From 3ca7b6c9cc23e118968b49a79f2b64fe4a3b73b3 Mon Sep 17 00:00:00 2001 From: Javier Date: Sat, 2 Apr 2022 16:34:17 +0200 Subject: readd VDS support so that it works under emm386 and win386+swap --- dlog.h | 2 +- dosmain.c | 42 ++++++++++++++++---------------- dostsr.c | 2 +- dostsr.h | 1 + vbox.c | 82 +++++++++++++++++++++++++++++---------------------------------- vbox.h | 33 +++++++++++++------------ vboxlog.h | 12 ++++++++++ vds.h | 61 ++++++++++++++++++++++++++++++++++++++++------- 8 files changed, 146 insertions(+), 89 deletions(-) create mode 100644 vboxlog.h diff --git a/dlog.h b/dlog.h index 67f430a..6556089 100644 --- a/dlog.h +++ b/dlog.h @@ -25,7 +25,7 @@ #if ENABLE_DLOG #if 1 -#include "vbox.h" +#include "vboxlog.h" #define dlog_putc vbox_log_putc #endif diff --git a/dosmain.c b/dosmain.c index f1c2291..ee6389c 100644 --- a/dosmain.c +++ b/dosmain.c @@ -36,24 +36,34 @@ static int set_integration(LPTSRDATA data, bool enable) data->vbavail = false; // Reinitialize it even if already enabled - if ((err = vbox_init(&data->vb)) == 0) { - printf("Found VirtualBox device at IO 0x%x\n", data->vb.iobase); - printf("Physical address used for VBox communication: 0x%lx\n", data->vb.buf_physaddr); - - if ((err = vbox_report_guest_info(&data->vb, VBOXOSTYPE_DOS)) == 0) { - printf("VirtualBox integration enabled\n"); - data->vbavail = true; - } else { - fprintf(stderr, "VirtualBox communication is not working, err=%d\n", err); - return err; - } - } else { + err = vbox_init_device(&data->vb); + if (err) { fprintf(stderr, "Cannot find VirtualBox PCI device, err=%d\n", err); return err; } + + printf("Found VirtualBox device at IO 0x%x\n", data->vb.iobase); + + err = vbox_init_buffer(&data->vb); + if (err) { + fprintf(stderr, "Cannot lock buffer used for VirtualBox communication, err=%d\n", err); + return err; + } + + err = vbox_report_guest_info(&data->vb, VBOXOSTYPE_DOS); + if (err) { + fprintf(stderr, "VirtualBox communication is not working, err=%d\n", err); + return err; + } + + printf("VirtualBox integration enabled\n"); + data->vbavail = true; } else { if (data->vbavail) { vbox_set_mouse(&data->vb, false, false); + + vbox_release_buffer(&data->vb); + printf("Disabled VirtualBox integration\n"); data->vbavail = false; } else { @@ -208,12 +218,6 @@ static int driver_reset(void) return int33_call(0x0) == 0xFFFF; } -static int driver_test(void) -{ - int2f_call(0x1234); - return EXIT_FAILURE; -} - static int driver_not_found(void) { fprintf(stderr, "Driver data not found (driver not installed?)\n"); @@ -311,8 +315,6 @@ int main(int argc, const char *argv[]) #endif } else if (stricmp(argv[argi], "reset") == 0) { return driver_reset(); - } else if (stricmp(argv[argi], "test") == 0) { - return driver_test(); } print_help(); diff --git a/dostsr.c b/dostsr.c index aab2855..57ec089 100644 --- a/dostsr.c +++ b/dostsr.c @@ -366,7 +366,7 @@ static void load_cursor(void) dlog_puts("Loading cursor to VBox"); - vbox_send_request(data.vb.iobase, data.vb.buf_physaddr); + vbox_send_request(data.vb.iobase, data.vb.dds.physicalAddress); if (req->header.rc != 0) { dlog_puts("Could not send cursor to VirtualBox"); diff --git a/dostsr.h b/dostsr.h index 268b2aa..b9a5b73 100644 --- a/dostsr.h +++ b/dostsr.h @@ -161,6 +161,7 @@ extern void __declspec(naked) __far int2f_isr(void); extern LPTSRDATA __far get_tsr_data(bool installed); +/** This symbol is always at the end of the TSR segment */ extern int resident_end; /** This is not just data, but the entire segment. */ diff --git a/vbox.c b/vbox.c index 6d33659..28fb02d 100644 --- a/vbox.c +++ b/vbox.c @@ -38,9 +38,7 @@ enum { CFG_BAR1 = 0x14, /* DWord */ }; -/** Finds the VirtualBox PCI device and reads the current IO base. - * @returns 0 if the device was found. */ -static int vbox_find_iobase(uint16_t __far *iobase) +int vbox_init_device(LPVBOXCOMM vb) { int err; pcisel pcidev; @@ -73,65 +71,61 @@ static int vbox_find_iobase(uint16_t __far *iobase) return -2; } - *iobase = bar & 0xFFFC; + vb->iobase = bar & 0xFFFC; return 0; } -static int vbox_get_phys_addr(uint32_t __far *physaddr, void __far *buf) +int vbox_init_buffer(LPVBOXCOMM vb) { - int err = 0; -#if 0 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); - if (err == VDS_REGION_NOT_CONTIGUOUS) { - // This is why we made the allocation double the required size - // If the buffer happens to be on a page boundary, - // it may not be contiguous and cause the call to fail. - // So, we try to lock the 2nd half of the allocation, - // which should not be on a page boundary. - vbox_logs("VDS try again\n"); - pBuf = (char FAR*) pBuf + bufferSize; - bufdds.regionSize = bufferSize; - bufdds.offset += bufferSize; - err = vds_lock_dma_buffer_region(&bufdds, VDS_NO_AUTO_ALLOC); - } + int err; + + vb->dds.regionSize = sizeof(vb->buf); + vb->dds.segOrSelector = FP_SEG(&vb->buf); + vb->dds.offset = FP_OFF(&vb->buf); + vb->dds.bufferId = 0; + vb->dds.physicalAddress = 0; + + err = vds_lock_dma_buffer_region(&vb->dds, VDS_NO_AUTO_ALLOC); if (err) { - vbox_logs("VDS lock failure\n"); + // As far as I have seen, most VDS providers always keep low memory contiguous, + // so I'm not handling VDS_REGION_NOT_CONTIGUOUS here. + dlog_print("Error while VDS locking, err="); + dlog_printd(err); + dlog_endline(); + return err; } } else { - bufdds.regionSize = 0; // Indicates we don't have to unlock this later on + vb->dds.regionSize = 0; // So that we don't try to unlock it later + vb->dds.segOrSelector = FP_SEG(&vb->buf); + vb->dds.offset = FP_OFF(&vb->buf); + vb->dds.bufferId = 0; - // If VDS is not available, assume we are not paging - // Just use the linear address as physical - bufdds.physicalAddress = FP_SEG(pBuf + FP_OFF(pBuf); - err = 0; + vb->dds.physicalAddress = vds_ptr_to_linear(&vb->buf); } -#endif - *physaddr = ((uint32_t)(FP_SEG(buf)) << 4) + FP_OFF(buf); - - return err; + return 0; } -int vbox_init(LPVBOXCOMM vb) +int vbox_release_buffer(LPVBOXCOMM vb) { - int err; + if (vds_available() && vb->dds.regionSize) { - if ((err = vbox_find_iobase(&vb->iobase))) { - return err; - } - - if (err = vbox_get_phys_addr(&vb->buf_physaddr, vb->buf)) { - return err; + int err = vds_unlock_dma_buffer_region(&vb->dds, 0); + if (err) { + dlog_print("Error while VDS unlocking, err="); + dlog_printd(err); + dlog_endline(); + // Ignore the error, it's not like we can do anything + } } + vb->dds.regionSize = 0; + vb->dds.segOrSelector = 0; + vb->dds.offset = 0; + vb->dds.bufferId = 0; + vb->dds.physicalAddress = 0; return 0; } diff --git a/vbox.h b/vbox.h index dfa124b..69721aa 100644 --- a/vbox.h +++ b/vbox.h @@ -23,6 +23,8 @@ #include #include +#include "dlog.h" +#include "vds.h" #include "utils.h" #include "vboxdev.h" @@ -32,18 +34,10 @@ typedef struct vboxcomm { uint16_t iobase; char buf[VBOX_BUFFER_SIZE]; - uint32_t buf_physaddr; + VDSDDS dds; } vboxcomm_t; typedef vboxcomm_t __far * LPVBOXCOMM; -/** Logs a single character to the VBox debug message port. */ -static void vbox_log_putc(char c); -#pragma aux vbox_log_putc = \ - "mov dx, 0x504" \ - "out dx, al" \ - __parm [al] \ - __modify [dx] - /** Actually send a request to the VirtualBox VMM device. * @param addr 32-bit physical address containing the VMMDevRequest struct. */ @@ -58,7 +52,16 @@ static void vbox_send_request(uint16_t iobase, uint32_t addr); __parm [dx] [bx ax] \ __modify [dx] -extern int vbox_init(LPVBOXCOMM vb); +/** Finds the VirtualBox PCI device and reads the current IO base. + * @returns 0 if the device was found. */ +extern int vbox_init_device(LPVBOXCOMM vb); + +/** Prepares the buffer used for communicating with VBox and + * computes its physical address (using VDS if necessary). */ +extern int vbox_init_buffer(LPVBOXCOMM vb); + +/** Releases/unlocks buffer, no further use possible. */ +extern int vbox_release_buffer(LPVBOXCOMM vb); /** Lets VirtualBox know that there are VirtualBox Guest Additions on this guest. * @param osType os installed on this guest. */ @@ -75,7 +78,7 @@ static int vbox_report_guest_info(LPVBOXCOMM vb, uint32_t osType) req->guestInfo.interfaceVersion = VMMDEV_VERSION; req->guestInfo.osType = osType; - vbox_send_request(vb->iobase, vb->buf_physaddr); + vbox_send_request(vb->iobase, vb->dds.physicalAddress); return req->header.rc; } @@ -94,7 +97,7 @@ static int vbox_set_mouse(LPVBOXCOMM vb, bool absolute, bool pointer) if (absolute) req->mouseFeatures |= VMMDEV_MOUSE_GUEST_CAN_ABSOLUTE; if (pointer) req->mouseFeatures |= VMMDEV_MOUSE_GUEST_NEEDS_HOST_CURSOR; - vbox_send_request(vb->iobase, vb->buf_physaddr); + vbox_send_request(vb->iobase, vb->dds.physicalAddress); return req->header.rc; } @@ -114,7 +117,7 @@ static int vbox_get_mouse(LPVBOXCOMM vb, bool __far *abs, req->header.requestType = VMMDevReq_GetMouseStatus; req->header.rc = -1; - vbox_send_request(vb->iobase, vb->buf_physaddr); + vbox_send_request(vb->iobase, vb->dds.physicalAddress); *abs = req->mouseFeatures & VMMDEV_MOUSE_HOST_WANTS_ABSOLUTE; *xpos = req->pointerXPos; @@ -123,7 +126,7 @@ static int vbox_get_mouse(LPVBOXCOMM vb, bool __far *abs, return req->header.rc; } -/** @todo */ +/** Asks the host to render the mouse cursor for us. */ static int vbox_set_pointer_visible(LPVBOXCOMM vb, bool visible) { VMMDevReqMousePointer __far *req = (void __far *) vb->buf; @@ -137,7 +140,7 @@ static int vbox_set_pointer_visible(LPVBOXCOMM vb, bool visible) if (visible) req->fFlags |= VBOX_MOUSE_POINTER_VISIBLE; - vbox_send_request(vb->iobase, vb->buf_physaddr); + vbox_send_request(vb->iobase, vb->dds.physicalAddress); return req->header.rc; } diff --git a/vboxlog.h b/vboxlog.h new file mode 100644 index 0000000..11ecf68 --- /dev/null +++ b/vboxlog.h @@ -0,0 +1,12 @@ +#ifndef VBOXDLOG_H +#define VBOXDLOG_H + +/** Logs a single character to the VBox debug message port. */ +static void vbox_log_putc(char c); +#pragma aux vbox_log_putc = \ + "mov dx, 0x504" \ + "out dx, al" \ + __parm [al] \ + __modify [dx] + +#endif // VBOXDLOG_H diff --git a/vds.h b/vds.h index c006e1d..508a0ca 100644 --- a/vds.h +++ b/vds.h @@ -24,7 +24,7 @@ #include typedef unsigned char vdserr; -enum { +enum vds_errors { VDS_SUCCESSFUL = 0, VDS_REGION_NOT_CONTIGUOUS = 1, VDS_REGION_NOT_ALIGNED = 2, @@ -44,7 +44,7 @@ enum { VDS_FLAGS_NOT_SUPPORTED = 0x10, }; -enum { +enum vds_flags { /* Bit 1 = Automatically copy to/from buffer Bit 2 = Disable automatic buffer allocation @@ -62,7 +62,7 @@ enum { }; /** DMA Descriptor structure. Describes a potentially DMA-lockable buffer. */ -typedef _Packed struct VDS_DDS +typedef _Packed struct VDSDDS { /** Size of this buffer. */ uint32_t regionSize; @@ -74,7 +74,15 @@ typedef _Packed struct VDS_DDS uint16_t bufferId; /** Physical address of this buffer. */ uint32_t physicalAddress; -} VDS_DDS; +} VDSDDS; + +/** Converts a far pointer into equivalent linear address. + * Note that under protected mode linear != physical. + * That's what VDS is for. */ +static inline uint32_t vds_ptr_to_linear(const void __far * ptr) +{ + return ((uint32_t)(FP_SEG(ptr)) << 4) + FP_OFF(ptr); +} static bool vds_available(void); #pragma aux vds_available = \ @@ -89,9 +97,9 @@ static bool vds_available(void); /** Locks an already allocated buffer into a physical memory location. * regionSize, offset and segment must be valid in the DDS, * while the physical address is returned. */ -static vdserr vds_lock_dma_buffer_region(VDS_DDS __far * dds, unsigned char flags); +static vdserr vds_lock_dma_buffer_region(VDSDDS __far * dds, unsigned char flags); #pragma aux vds_lock_dma_buffer_region = \ - "stc" /* If nothing happens, assume failure. */ \ + "stc" \ "mov ax, 0x8103" \ "int 0x4B" \ "jc fail" \ @@ -99,14 +107,14 @@ static vdserr vds_lock_dma_buffer_region(VDS_DDS __far * dds, unsigned char flag "jmp end" \ "fail: test al, al" \ "jnz end" \ - "mov al, 0xFF" /* Force a error code if there was none. */ \ + "mov al, 0xFF" /* Force a error code if there was none. */ \ "end:" \ __parm [es di] [dx] \ __value [al] \ __modify [ax] /** Unlocks a locked buffer. */ -static vdserr vds_unlock_dma_buffer_region(VDS_DDS __far * dds, unsigned char flags); +static vdserr vds_unlock_dma_buffer_region(VDSDDS __far * dds, unsigned char flags); #pragma aux vds_unlock_dma_buffer_region = \ "stc" \ "mov ax, 0x8104" \ @@ -122,4 +130,41 @@ static vdserr vds_unlock_dma_buffer_region(VDS_DDS __far * dds, unsigned char fl __value [al] \ __modify [ax] +/** Allocates a DMA buffer. + * @param dds regionSize must be valid. + * @return dds Physical_Address, Buffer_ID, and Region_Size + */ +static vdserr vds_request_dma_buffer(VDSDDS __far * dds, unsigned char flags); +#pragma aux vds_request_dma_buffer = \ + "stc" \ + "mov ax, 0x8107" \ + "int 0x4B" \ + "jc fail" \ + "mov al, 0" \ + "jmp end" \ + "fail: test al, al" \ + "jnz end" \ + "mov al, 0xFF" \ + "end:" \ + __parm [es di] [dx] \ + __value [al] \ + __modify [ax] + +/** Frees a DMA buffer. */ +static vdserr vds_release_dma_buffer(VDSDDS __far * dds, unsigned char flags); +#pragma aux vds_release_dma_buffer = \ + "stc" \ + "mov ax, 0x8108" \ + "int 0x4B" \ + "jc fail" \ + "mov al, 0" \ + "jmp end" \ + "fail: test al, al" \ + "jnz end" \ + "mov al, 0xFF" \ + "end:" \ + __parm [es di] [dx] \ + __value [al] \ + __modify [ax] + #endif -- cgit v1.2.3