aboutsummaryrefslogtreecommitdiff
path: root/vbox.c
diff options
context:
space:
mode:
Diffstat (limited to 'vbox.c')
-rw-r--r--vbox.c219
1 files changed, 130 insertions, 89 deletions
diff --git a/vbox.c b/vbox.c
index 042a470..456877b 100644
--- a/vbox.c
+++ b/vbox.c
@@ -19,11 +19,14 @@
#include <windows.h>
#include <i86.h>
+#include <string.h>
#include "pci.h"
+#include "vds.h"
#include "vboxdev.h"
#include "vbox.h"
+// PCI device information
/** VBox's PCI bus, device number, etc. */
static pcisel vbpci;
/** IO base of VBox's PCI device. */
@@ -31,14 +34,16 @@ static uint16_t vbiobase;
/** IRQ number of VBox's PCI device. Unused. */
static uint8_t vbirq;
-/** Keep a pre-allocated VBox VMMDevRequest struct for the benefit of the callbacks,
- which may be called in a IRQ handler where I'd prefer to avoid making API calls. */
-static VMMDevReqMouseStatus __far * reqMouse;
-static HANDLE reqMouseH;
-static uint32_t reqMouseAddr;
+/** Handle to fixed buffer used for communication with VBox device.
+ * We also use Virtual DMA Service to obtain the physical address of this buffer,
+ * so it must remain fixed in memory. */
+static HANDLE hBuf;
+static LPVOID pBuf;
+/** The DMA descriptor used by VDS corresponding to the above buffer. */
+static VDS_DDS bufdds;
/** Actually send a request to the VirtualBox VMM device.
- * @param addr 32-bit linear address containing the VMMDevRequest struct.
+ * @param addr 32-bit physical address containing the VMMDevRequest struct.
*/
static void vbox_send_request(uint32_t addr);
#pragma aux vbox_send_request = \
@@ -61,7 +66,7 @@ static uint32_t vbox_irq_ack();
"in eax, dx" \
"mov edx, eax" \
"shr edx, 16" \
- __value [dx ax] \
+ __value [dx ax]
// Classic PCI defines
#define VBOX_PCI_VEND_ID 0x80ee
@@ -73,21 +78,6 @@ enum {
CFG_BAR1 = 0x14, /* DWord */
};
-/** Gets the 32-bit linear address of a 16:16 far pointer.
- Uses GetSelectorBase() since we are supposed to work under protected mode. */
-static inline uint32_t get_physical_addr(void far *obj)
-{
- return GetSelectorBase(FP_SEG(obj)) + FP_OFF(obj);
-}
-
-/** Send a request to the VirtualBox VMM device at vbiobase.
- * @param request must be a VMMDevRequest (e.g. VMMDevReqMouseStatus). */
-static inline void vbox_request(void far *request)
-{
- uint32_t addr = get_physical_addr(request);
- vbox_send_request(addr);
-}
-
/** Finds the VirtualBox PCI device and reads the current IO base.
* @returns 0 if the device was found. */
int vbox_init(void)
@@ -126,56 +116,118 @@ int vbox_init(void)
return 0;
}
+/** Allocates the buffers that will be used to communicate with the VirtualBox device. */
+int vbox_alloc_buffers(void)
+{
+ const unsigned int bufferSize = 48; // This should be the largest of all VMMDevRequest* structs that we can send
+ int err;
+
+ // Allocate the buffer
+ hBuf = GlobalAlloc(GMEM_FIXED|GMEM_SHARE, bufferSize);
+ if (!hBuf) return -1;
+
+ // Keep it in memory at a fixed location
+ GlobalFix(hBuf);
+ GlobalPageLock(hBuf);
+
+ // Get the usable pointer / logical address of the buffer
+ pBuf = (LPVOID) GlobalLock(hBuf);
+
+ if (vds_available()) {
+ // Use the Virtual DMA Service to get the physical address of this buffer
+ bufdds.regionSize = bufferSize;
+ bufdds.segOrSelector = FP_SEG(pBuf);
+ bufdds.offset = FP_OFF(pBuf);
+ bufdds.bufferId = 0;
+ bufdds.physicalAddress = 0;
+
+ err = vds_lock_dma_buffer_region(&bufdds, VDS_NO_AUTO_ALLOC | VDS_NO_AUTO_REMAP);
+ } else {
+ bufdds.regionSize = 0; // Indicates we don't have to unlock this later on
+
+ // If VDS is not available, assume we are not paging
+ // Just use the linear address as physical
+ bufdds.physicalAddress = GetSelectorBase(FP_SEG(pBuf)) + FP_OFF(pBuf);
+ err = 0;
+ }
+
+ return err;
+}
+
+/** Frees the buffers allocated by vbox_alloc_buffers(). */
+int vbox_free_buffers(void)
+{
+ if (bufdds.regionSize > 0) {
+ vds_unlock_dma_buffer_region(&bufdds, 0);
+ }
+ bufdds.regionSize = 0;
+ bufdds.segOrSelector = 0;
+ bufdds.offset = 0;
+ bufdds.bufferId = 0;
+ bufdds.physicalAddress = 0;
+ GlobalFree(hBuf);
+ hBuf = NULL;
+ pBuf = NULL;
+
+ return 0;
+}
+
/** Lets VirtualBox know that there are VirtualBox Guest Additions on this guest.
* @param osType os installed on this guest. */
int vbox_report_guest_info(uint32_t osType)
{
- VMMDevReportGuestInfo req = {0};
+ VMMDevReportGuestInfo *req = pBuf;
+
+ memset(req, 0, sizeof(VMMDevReportGuestInfo));
- req.header.size = sizeof(req);
- req.header.version = VMMDEV_REQUEST_HEADER_VERSION;
- req.header.requestType = VMMDevReq_ReportGuestInfo;
- req.header.rc = -1;
- req.guestInfo.interfaceVersion = VMMDEV_VERSION;
- req.guestInfo.osType = osType;
+ req->header.size = sizeof(VMMDevReportGuestInfo);
+ req->header.version = VMMDEV_REQUEST_HEADER_VERSION;
+ req->header.requestType = VMMDevReq_ReportGuestInfo;
+ req->header.rc = -1;
+ req->guestInfo.interfaceVersion = VMMDEV_VERSION;
+ req->guestInfo.osType = osType;
- vbox_request(&req);
+ vbox_send_request(bufdds.physicalAddress);
- return req.header.rc;
+ return req->header.rc;
}
/** Tells VirtualBox about the events we are interested in receiving.
These events are notified via the PCI IRQ which we are not using, so this is not used either. */
int vbox_set_filter_mask(uint32_t add, uint32_t remove)
{
- VMMDevCtlGuestFilterMask req = {0};
+ VMMDevCtlGuestFilterMask *req = pBuf;
- req.header.size = sizeof(req);
- req.header.version = VMMDEV_REQUEST_HEADER_VERSION;
- req.header.requestType = VMMDevReq_CtlGuestFilterMask;
- req.header.rc = -1;
- req.u32OrMask = add;
- req.u32NotMask = remove;
+ memset(req, 0, sizeof(VMMDevCtlGuestFilterMask));
- vbox_request(&req);
+ req->header.size = sizeof(VMMDevCtlGuestFilterMask);
+ req->header.version = VMMDEV_REQUEST_HEADER_VERSION;
+ req->header.requestType = VMMDevReq_CtlGuestFilterMask;
+ req->header.rc = -1;
+ req->u32OrMask = add;
+ req->u32NotMask = remove;
- return req.header.rc;
+ vbox_send_request(bufdds.physicalAddress);
+
+ return req->header.rc;
}
/** Tells VirtualBox whether we want absolute mouse information or not. */
int vbox_set_mouse(bool enable)
{
- VMMDevReqMouseStatus req = {0};
+ VMMDevReqMouseStatus *req = pBuf;
+
+ memset(req, 0, sizeof(VMMDevReqMouseStatus));
- req.header.size = sizeof(req);
- req.header.version = VMMDEV_REQUEST_HEADER_VERSION;
- req.header.requestType = VMMDevReq_SetMouseStatus;
- req.header.rc = -1;
- req.mouseFeatures = enable ? VMMDEV_MOUSE_GUEST_CAN_ABSOLUTE : 0;
+ req->header.size = sizeof(VMMDevReqMouseStatus);
+ req->header.version = VMMDEV_REQUEST_HEADER_VERSION;
+ req->header.requestType = VMMDevReq_SetMouseStatus;
+ req->header.rc = -1;
+ req->mouseFeatures = enable ? VMMDEV_MOUSE_GUEST_CAN_ABSOLUTE : 0;
- vbox_request(&req);
+ vbox_send_request(bufdds.physicalAddress);
- return req.header.rc;
+ return req->header.rc;
}
/** Gets the current absolute mouse position from VirtualBox.
@@ -183,57 +235,46 @@ int vbox_set_mouse(bool enable)
* in which case we should fallback to PS/2 relative events. */
int vbox_get_mouse(bool *abs, uint16_t *xpos, uint16_t *ypos)
{
- VMMDevReqMouseStatus req = {0};
+ VMMDevReqMouseStatus *req = pBuf;
- req.header.size = sizeof(req);
- req.header.version = VMMDEV_REQUEST_HEADER_VERSION;
- req.header.requestType = VMMDevReq_GetMouseStatus;
- req.header.rc = -1;
+ memset(req, 0, sizeof(VMMDevReqMouseStatus));
- vbox_request(&req);
+ req->header.size = sizeof(VMMDevReqMouseStatus);
+ req->header.version = VMMDEV_REQUEST_HEADER_VERSION;
+ req->header.requestType = VMMDevReq_GetMouseStatus;
+ req->header.rc = -1;
- *abs = req.mouseFeatures & VMMDEV_MOUSE_HOST_WANTS_ABSOLUTE;
- *xpos = req.pointerXPos;
- *ypos = req.pointerYPos;
+ vbox_send_request(bufdds.physicalAddress);
- return req.header.rc;
-}
+ *abs = req->mouseFeatures & VMMDEV_MOUSE_HOST_WANTS_ABSOLUTE;
+ *xpos = req->pointerXPos;
+ *ypos = req->pointerYPos;
-/** Just allocates the memory used by vbox_get_mouse_locked below. */
-void vbox_init_callbacks(void)
-{
- reqMouseH = GlobalAlloc(GMEM_FIXED|GMEM_SHARE, sizeof(VMMDevReqMouseStatus));
- reqMouse = (LPVOID) GlobalLock(reqMouseH);
- reqMouseAddr = get_physical_addr(reqMouse);
-}
-
-void vbox_deinit_callbacks(void)
-{
- GlobalFree(reqMouseH);
- reqMouse = NULL;
- reqMouseAddr = 0;
+ return req->header.rc;
}
#pragma code_seg ( "CALLBACKS" )
-/** This is a version of vbox_get_mouse() that does not call any other functions. */
+/** This is a version of vbox_get_mouse() that does not call any other functions,
+ * and may be called inside an interrupt handler. */
int vbox_get_mouse_locked(bool *abs, uint16_t *xpos, uint16_t *ypos)
{
- // Note that this may be called with interrupts disabled
- reqMouse->header.size = sizeof(VMMDevReqMouseStatus);
- reqMouse->header.version = VMMDEV_REQUEST_HEADER_VERSION;
- reqMouse->header.requestType = VMMDevReq_GetMouseStatus;
- reqMouse->header.rc = -1;
- reqMouse->mouseFeatures = 0;
- reqMouse->pointerXPos = 0;
- reqMouse->pointerYPos = 0;
-
- vbox_send_request(reqMouseAddr);
-
- *abs = reqMouse->mouseFeatures & VMMDEV_MOUSE_HOST_WANTS_ABSOLUTE;
- *xpos = reqMouse->pointerXPos;
- *ypos = reqMouse->pointerYPos;
-
- return reqMouse->header.rc;
+ VMMDevReqMouseStatus *req = pBuf;
+
+ req->header.size = sizeof(VMMDevReqMouseStatus);
+ req->header.version = VMMDEV_REQUEST_HEADER_VERSION;
+ req->header.requestType = VMMDevReq_GetMouseStatus;
+ req->header.rc = -1;
+ req->mouseFeatures = 0;
+ req->pointerXPos = 0;
+ req->pointerYPos = 0;
+
+ vbox_send_request(bufdds.physicalAddress);
+
+ *abs = req->mouseFeatures & VMMDEV_MOUSE_HOST_WANTS_ABSOLUTE;
+ *xpos = req->pointerXPos;
+ *ypos = req->pointerYPos;
+
+ return req->header.rc;
}