1 | /* $Id: HGSMIHostCmd.cpp 93115 2022-01-01 11:31:46Z vboxsync $ */
|
---|
2 | /** @file
|
---|
3 | * VirtualBox Video driver, common code - HGSMI host-to-guest communication.
|
---|
4 | */
|
---|
5 |
|
---|
6 | /*
|
---|
7 | * Copyright (C) 2006-2022 Oracle Corporation
|
---|
8 | *
|
---|
9 | * Permission is hereby granted, free of charge, to any person
|
---|
10 | * obtaining a copy of this software and associated documentation
|
---|
11 | * files (the "Software"), to deal in the Software without
|
---|
12 | * restriction, including without limitation the rights to use,
|
---|
13 | * copy, modify, merge, publish, distribute, sublicense, and/or sell
|
---|
14 | * copies of the Software, and to permit persons to whom the
|
---|
15 | * Software is furnished to do so, subject to the following
|
---|
16 | * conditions:
|
---|
17 | *
|
---|
18 | * The above copyright notice and this permission notice shall be
|
---|
19 | * included in all copies or substantial portions of the Software.
|
---|
20 | *
|
---|
21 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
---|
22 | * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
|
---|
23 | * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
---|
24 | * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
|
---|
25 | * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
---|
26 | * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
---|
27 | * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
|
---|
28 | * OTHER DEALINGS IN THE SOFTWARE.
|
---|
29 | */
|
---|
30 |
|
---|
31 | #include <VBoxVideoGuest.h>
|
---|
32 | #include <VBoxVideoVBE.h>
|
---|
33 | #include <VBoxVideoIPRT.h>
|
---|
34 | #include <HGSMIHostCmd.h>
|
---|
35 |
|
---|
36 | /**
|
---|
37 | * Initialise the host context structure.
|
---|
38 | *
|
---|
39 | * @param pCtx the context structure to initialise
|
---|
40 | * @param pvBaseMapping where the basic HGSMI structures are mapped at
|
---|
41 | * @param offHostFlags the offset of the host flags into the basic HGSMI
|
---|
42 | * structures
|
---|
43 | * @param pvHostAreaMapping where the area for the host heap is mapped at
|
---|
44 | * @param offVRAMHostArea offset of the host heap area into VRAM
|
---|
45 | * @param cbHostArea size in bytes of the host heap area
|
---|
46 | */
|
---|
47 | DECLHIDDEN(void) VBoxHGSMISetupHostContext(PHGSMIHOSTCOMMANDCONTEXT pCtx,
|
---|
48 | void *pvBaseMapping,
|
---|
49 | uint32_t offHostFlags,
|
---|
50 | void *pvHostAreaMapping,
|
---|
51 | uint32_t offVRAMHostArea,
|
---|
52 | uint32_t cbHostArea)
|
---|
53 | {
|
---|
54 | uint8_t *pu8HostFlags = ((uint8_t *)pvBaseMapping) + offHostFlags;
|
---|
55 | pCtx->pfHostFlags = (HGSMIHOSTFLAGS *)pu8HostFlags;
|
---|
56 | /** @todo should we really be using a fixed ISA port value here? */
|
---|
57 | pCtx->port = (RTIOPORT)VGA_PORT_HGSMI_HOST;
|
---|
58 | HGSMIAreaInitialize(&pCtx->areaCtx, pvHostAreaMapping, cbHostArea,
|
---|
59 | offVRAMHostArea);
|
---|
60 | }
|
---|
61 |
|
---|
62 |
|
---|
63 | /** Send completion notification to the host for the command located at offset
|
---|
64 | * @a offt into the host command buffer. */
|
---|
65 | static void HGSMINotifyHostCmdComplete(PHGSMIHOSTCOMMANDCONTEXT pCtx, HGSMIOFFSET offt)
|
---|
66 | {
|
---|
67 | VBVO_PORT_WRITE_U32(pCtx->port, offt);
|
---|
68 | }
|
---|
69 |
|
---|
70 |
|
---|
71 | /**
|
---|
72 | * Inform the host that a command has been handled.
|
---|
73 | *
|
---|
74 | * @param pCtx the context containing the heap to be used
|
---|
75 | * @param pvMem pointer into the heap as mapped in @a pCtx to the command to
|
---|
76 | * be completed
|
---|
77 | */
|
---|
78 | DECLHIDDEN(void) VBoxHGSMIHostCmdComplete(PHGSMIHOSTCOMMANDCONTEXT pCtx, void RT_UNTRUSTED_VOLATILE_HOST *pvMem)
|
---|
79 | {
|
---|
80 | HGSMIBUFFERHEADER RT_UNTRUSTED_VOLATILE_GUEST *pHdr = HGSMIBufferHeaderFromData(pvMem);
|
---|
81 | HGSMIOFFSET offMem = HGSMIPointerToOffset(&pCtx->areaCtx, pHdr);
|
---|
82 | Assert(offMem != HGSMIOFFSET_VOID);
|
---|
83 | if (offMem != HGSMIOFFSET_VOID)
|
---|
84 | HGSMINotifyHostCmdComplete(pCtx, offMem);
|
---|
85 | }
|
---|
86 |
|
---|
87 |
|
---|
88 | /** Submit an incoming host command to the appropriate handler. */
|
---|
89 | static void hgsmiHostCmdProcess(PHGSMIHOSTCOMMANDCONTEXT pCtx,
|
---|
90 | HGSMIOFFSET offBuffer)
|
---|
91 | {
|
---|
92 | int rc = HGSMIBufferProcess(&pCtx->areaCtx, &pCtx->channels, offBuffer);
|
---|
93 | Assert(!RT_FAILURE(rc));
|
---|
94 | if(RT_FAILURE(rc))
|
---|
95 | {
|
---|
96 | /* failure means the command was not submitted to the handler for some reason
|
---|
97 | * it's our responsibility to notify its completion in this case */
|
---|
98 | HGSMINotifyHostCmdComplete(pCtx, offBuffer);
|
---|
99 | }
|
---|
100 | /* if the cmd succeeded it's responsibility of the callback to complete it */
|
---|
101 | }
|
---|
102 |
|
---|
103 | /** Get the next command from the host. */
|
---|
104 | static HGSMIOFFSET hgsmiGetHostBuffer(PHGSMIHOSTCOMMANDCONTEXT pCtx)
|
---|
105 | {
|
---|
106 | return VBVO_PORT_READ_U32(pCtx->port);
|
---|
107 | }
|
---|
108 |
|
---|
109 |
|
---|
110 | /** Get and handle the next command from the host. */
|
---|
111 | static void hgsmiHostCommandQueryProcess(PHGSMIHOSTCOMMANDCONTEXT pCtx)
|
---|
112 | {
|
---|
113 | HGSMIOFFSET offset = hgsmiGetHostBuffer(pCtx);
|
---|
114 | AssertReturnVoid(offset != HGSMIOFFSET_VOID);
|
---|
115 | hgsmiHostCmdProcess(pCtx, offset);
|
---|
116 | }
|
---|
117 |
|
---|
118 |
|
---|
119 | /** Drain the host command queue. */
|
---|
120 | DECLHIDDEN(void) VBoxHGSMIProcessHostQueue(PHGSMIHOSTCOMMANDCONTEXT pCtx)
|
---|
121 | {
|
---|
122 | while (pCtx->pfHostFlags->u32HostFlags & HGSMIHOSTFLAGS_COMMANDS_PENDING)
|
---|
123 | {
|
---|
124 | if (!ASMAtomicCmpXchgBool(&pCtx->fHostCmdProcessing, true, false))
|
---|
125 | return;
|
---|
126 | hgsmiHostCommandQueryProcess(pCtx);
|
---|
127 | ASMAtomicWriteBool(&pCtx->fHostCmdProcessing, false);
|
---|
128 | }
|
---|
129 | }
|
---|
130 |
|
---|
131 |
|
---|
132 | /** Tell the host about the location of the area of VRAM set aside for the host
|
---|
133 | * heap. */
|
---|
134 | static int vboxHGSMIReportHostArea(PHGSMIGUESTCOMMANDCONTEXT pCtx,
|
---|
135 | uint32_t u32AreaOffset, uint32_t u32AreaSize)
|
---|
136 | {
|
---|
137 | VBVAINFOHEAP *p;
|
---|
138 | int rc = VINF_SUCCESS;
|
---|
139 |
|
---|
140 | /* Allocate the IO buffer. */
|
---|
141 | p = (VBVAINFOHEAP *)VBoxHGSMIBufferAlloc(pCtx,
|
---|
142 | sizeof (VBVAINFOHEAP), HGSMI_CH_VBVA,
|
---|
143 | VBVA_INFO_HEAP);
|
---|
144 | if (p)
|
---|
145 | {
|
---|
146 | /* Prepare data to be sent to the host. */
|
---|
147 | p->u32HeapOffset = u32AreaOffset;
|
---|
148 | p->u32HeapSize = u32AreaSize;
|
---|
149 | rc = VBoxHGSMIBufferSubmit(pCtx, p);
|
---|
150 | /* Free the IO buffer. */
|
---|
151 | VBoxHGSMIBufferFree(pCtx, p);
|
---|
152 | }
|
---|
153 | else
|
---|
154 | rc = VERR_NO_MEMORY;
|
---|
155 | return rc;
|
---|
156 | }
|
---|
157 |
|
---|
158 |
|
---|
159 | /**
|
---|
160 | * Get the information needed to map the area used by the host to send back
|
---|
161 | * requests.
|
---|
162 | *
|
---|
163 | * @param pCtx the context containing the heap to use
|
---|
164 | * @param cbVRAM how much video RAM is allocated to the device
|
---|
165 | * @param offVRAMBaseMapping the offset of the basic communication structures
|
---|
166 | * into the guest's VRAM
|
---|
167 | * @param poffVRAMHostArea where to store the offset into VRAM of the host
|
---|
168 | * heap area
|
---|
169 | * @param pcbHostArea where to store the size of the host heap area
|
---|
170 | */
|
---|
171 | DECLHIDDEN(void) VBoxHGSMIGetHostAreaMapping(PHGSMIGUESTCOMMANDCONTEXT pCtx,
|
---|
172 | uint32_t cbVRAM,
|
---|
173 | uint32_t offVRAMBaseMapping,
|
---|
174 | uint32_t *poffVRAMHostArea,
|
---|
175 | uint32_t *pcbHostArea)
|
---|
176 | {
|
---|
177 | uint32_t offVRAMHostArea = offVRAMBaseMapping, cbHostArea = 0;
|
---|
178 |
|
---|
179 | AssertPtrReturnVoid(poffVRAMHostArea);
|
---|
180 | AssertPtrReturnVoid(pcbHostArea);
|
---|
181 | VBoxQueryConfHGSMI(pCtx, VBOX_VBVA_CONF32_HOST_HEAP_SIZE, &cbHostArea);
|
---|
182 | if (cbHostArea != 0)
|
---|
183 | {
|
---|
184 | uint32_t cbHostAreaMaxSize = cbVRAM / 4;
|
---|
185 | /** @todo what is the idea of this? */
|
---|
186 | if (cbHostAreaMaxSize >= VBVA_ADAPTER_INFORMATION_SIZE)
|
---|
187 | {
|
---|
188 | cbHostAreaMaxSize -= VBVA_ADAPTER_INFORMATION_SIZE;
|
---|
189 | }
|
---|
190 | if (cbHostArea > cbHostAreaMaxSize)
|
---|
191 | {
|
---|
192 | cbHostArea = cbHostAreaMaxSize;
|
---|
193 | }
|
---|
194 | /* Round up to 4096 bytes. */
|
---|
195 | cbHostArea = (cbHostArea + 0xFFF) & ~0xFFF;
|
---|
196 | offVRAMHostArea = offVRAMBaseMapping - cbHostArea;
|
---|
197 | }
|
---|
198 |
|
---|
199 | *pcbHostArea = cbHostArea;
|
---|
200 | *poffVRAMHostArea = offVRAMHostArea;
|
---|
201 | // LogFunc(("offVRAMHostArea = 0x%08X, cbHostArea = 0x%08X\n",
|
---|
202 | // offVRAMHostArea, cbHostArea));
|
---|
203 | }
|
---|
204 |
|
---|
205 |
|
---|
206 | /**
|
---|
207 | * Tell the host about the ways it can use to communicate back to us via an
|
---|
208 | * HGSMI command
|
---|
209 | *
|
---|
210 | * @returns iprt status value
|
---|
211 | * @param pCtx the context containing the heap to use
|
---|
212 | * @param offVRAMFlagsLocation where we wish the host to place its flags
|
---|
213 | * relative to the start of the VRAM
|
---|
214 | * @param fCaps additions HGSMI capabilities the guest
|
---|
215 | * supports
|
---|
216 | * @param offVRAMHostArea offset into VRAM of the host heap area
|
---|
217 | * @param cbHostArea size in bytes of the host heap area
|
---|
218 | */
|
---|
219 | DECLHIDDEN(int) VBoxHGSMISendHostCtxInfo(PHGSMIGUESTCOMMANDCONTEXT pCtx,
|
---|
220 | HGSMIOFFSET offVRAMFlagsLocation,
|
---|
221 | uint32_t fCaps,
|
---|
222 | uint32_t offVRAMHostArea,
|
---|
223 | uint32_t cbHostArea)
|
---|
224 | {
|
---|
225 | // Log(("VBoxVideo::vboxSetupAdapterInfo\n"));
|
---|
226 |
|
---|
227 | /* setup the flags first to ensure they are initialized by the time the
|
---|
228 | * host heap is ready */
|
---|
229 | int rc = VBoxHGSMIReportFlagsLocation(pCtx, offVRAMFlagsLocation);
|
---|
230 | AssertRC(rc);
|
---|
231 | if (RT_SUCCESS(rc) && fCaps)
|
---|
232 | {
|
---|
233 | /* Inform about caps */
|
---|
234 | rc = VBoxHGSMISendCapsInfo(pCtx, fCaps);
|
---|
235 | AssertRC(rc);
|
---|
236 | }
|
---|
237 | if (RT_SUCCESS (rc))
|
---|
238 | {
|
---|
239 | /* Report the host heap location. */
|
---|
240 | rc = vboxHGSMIReportHostArea(pCtx, offVRAMHostArea, cbHostArea);
|
---|
241 | AssertRC(rc);
|
---|
242 | }
|
---|
243 | // Log(("VBoxVideo::vboxSetupAdapterInfo finished rc = %d\n", rc));
|
---|
244 | return rc;
|
---|
245 | }
|
---|