static VOID WINAPI XmsBopProcedure(LPWORD Stack) { switch (getAH()) { /* Get XMS Version */ case 0x00: { setAX(0x0300); /* XMS version 3.00 */ setBX(0x0301); /* Driver version 3.01 */ setDX(0x0001); /* HMA present */ break; } /* Request HMA */ case 0x01: { /* Check whether HMA is already reserved */ if (IsHmaReserved) { /* It is, bail out */ setAX(0x0000); setBL(XMS_STATUS_HMA_IN_USE); break; } // NOTE: We implicitely suppose that we always have HMA. // If not, we should fail there with the XMS_STATUS_HMA_DOES_NOT_EXIST // error code. /* Check whether the requested size is above the minimal allowed one */ if (getDX() < HmaMinSize) { /* It is not, bail out */ setAX(0x0000); setBL(XMS_STATUS_HMA_MIN_SIZE); break; } /* Reserve it */ IsHmaReserved = TRUE; setAX(0x0001); setBL(XMS_STATUS_SUCCESS); break; } /* Release HMA */ case 0x02: { /* Check whether HMA was reserved */ if (!IsHmaReserved) { /* It was not, bail out */ setAX(0x0000); setBL(XMS_STATUS_HMA_NOT_ALLOCATED); break; } /* Release it */ IsHmaReserved = FALSE; setAX(0x0001); setBL(XMS_STATUS_SUCCESS); break; } /* Global Enable A20 */ case 0x03: { /* Enable A20 if needed */ if (!IsA20Enabled) { XmsLocalEnableA20(); if (getAX() != 0x0001) { /* XmsLocalEnableA20 failed and already set AX and BL to their correct values */ break; } IsA20Enabled = TRUE; } setAX(0x0001); /* Line successfully enabled */ setBL(XMS_STATUS_SUCCESS); break; } /* Global Disable A20 */ case 0x04: { UCHAR Result = XMS_STATUS_SUCCESS; /* Disable A20 if needed */ if (IsA20Enabled) { XmsLocalDisableA20(); if (getAX() != 0x0001) { /* XmsLocalDisableA20 failed and already set AX and BL to their correct values */ break; } IsA20Enabled = FALSE; Result = getBL(); } setAX(0x0001); /* Line successfully disabled */ setBL(Result); break; } /* Local Enable A20 */ case 0x05: { /* This call sets AX and BL to their correct values */ XmsLocalEnableA20(); break; } /* Local Disable A20 */ case 0x06: { /* This call sets AX and BL to their correct values */ XmsLocalDisableA20(); break; } /* Query A20 State */ case 0x07: { setAX(EmulatorGetA20()); setBL(XMS_STATUS_SUCCESS); break; } /* Query Free Extended Memory */ case 0x08: { setAX(XmsGetLargestFreeBlock()); setDX(FreeBlocks); if (FreeBlocks > 0) setBL(XMS_STATUS_SUCCESS); else setBL(XMS_STATUS_OUT_OF_MEMORY); break; } /* Allocate Extended Memory Block */ case 0x09: { WORD Handle; UCHAR Result = XmsAlloc(getDX(), &Handle); if (Result == XMS_STATUS_SUCCESS) { setAX(1); setDX(Handle); } else { setAX(0); setBL(Result); } break; } /* Free Extended Memory Block */ case 0x0A: { UCHAR Result = XmsFree(getDX()); setAX(Result == XMS_STATUS_SUCCESS); setBL(Result); break; } /* Move Extended Memory Block */ case 0x0B: { PVOID SourceAddress, DestAddress; PXMS_COPY_DATA CopyData = (PXMS_COPY_DATA)SEG_OFF_TO_PTR(getDS(), getSI()); PXMS_HANDLE HandleEntry; if (CopyData->SourceHandle) { HandleEntry = GetHandleRecord(CopyData->SourceHandle); if (!ValidateHandle(HandleEntry)) { setAX(0); setBL(XMS_STATUS_BAD_SRC_HANDLE); break; } if (CopyData->SourceOffset >= HandleEntry->Size * XMS_BLOCK_SIZE) { setAX(0); setBL(XMS_STATUS_BAD_SRC_OFFSET); } SourceAddress = (PVOID)REAL_TO_PHYS(HandleEntry->Address + CopyData->SourceOffset); } else { /* The offset is actually a 16-bit segment:offset pointer */ SourceAddress = FAR_POINTER(CopyData->SourceOffset); } if (CopyData->DestHandle) { HandleEntry = GetHandleRecord(CopyData->DestHandle); if (!ValidateHandle(HandleEntry)) { setAX(0); setBL(XMS_STATUS_BAD_DEST_HANDLE); break; } if (CopyData->DestOffset >= HandleEntry->Size * XMS_BLOCK_SIZE) { setAX(0); setBL(XMS_STATUS_BAD_DEST_OFFSET); } DestAddress = (PVOID)REAL_TO_PHYS(HandleEntry->Address + CopyData->DestOffset); } else { /* The offset is actually a 16-bit segment:offset pointer */ DestAddress = FAR_POINTER(CopyData->DestOffset); } /* Perform the move */ RtlMoveMemory(DestAddress, SourceAddress, CopyData->Count); setAX(1); setBL(XMS_STATUS_SUCCESS); break; } /* Lock Extended Memory Block */ case 0x0C: { DWORD Address; UCHAR Result = XmsLock(getDX(), &Address); if (Result == XMS_STATUS_SUCCESS) { setAX(1); /* Store the LINEAR address in DX:BX */ setDX(HIWORD(Address)); setBX(LOWORD(Address)); } else { setAX(0); setBL(Result); } break; } /* Unlock Extended Memory Block */ case 0x0D: { UCHAR Result = XmsUnlock(getDX()); setAX(Result == XMS_STATUS_SUCCESS); setBL(Result); break; } /* Get Handle Information */ case 0x0E: { PXMS_HANDLE HandleEntry = GetHandleRecord(getDX()); UINT i; UCHAR Handles = 0; if (!ValidateHandle(HandleEntry)) { setAX(0); setBL(XMS_STATUS_INVALID_HANDLE); break; } for (i = 0; i < XMS_MAX_HANDLES; i++) { if (HandleTable[i].Handle == 0) Handles++; } setAX(1); setBH(HandleEntry->LockCount); setBL(Handles); setDX(HandleEntry->Size); break; } /* Reallocate Extended Memory Block */ case 0x0F: { UCHAR Result = XmsRealloc(getDX(), getBX()); setAX(Result == XMS_STATUS_SUCCESS); setBL(Result); break; } /* Request UMB */ case 0x10: { BOOLEAN Result; USHORT Segment = 0x0000; /* No preferred segment */ USHORT Size = getDX(); /* Size is in paragraphs */ Result = UmaDescReserve(&Segment, &Size); if (Result) setBX(Segment); else setBL(Size > 0 ? XMS_STATUS_SMALLER_UMB : XMS_STATUS_OUT_OF_UMBS); setDX(Size); setAX(Result); break; } /* Release UMB */ case 0x11: { BOOLEAN Result; USHORT Segment = getDX(); Result = UmaDescRelease(Segment); if (!Result) setBL(XMS_STATUS_INVALID_UMB); setAX(Result); break; } /* Reallocate UMB */ case 0x12: { BOOLEAN Result; USHORT Segment = getDX(); USHORT Size = getBX(); /* Size is in paragraphs */ Result = UmaDescReallocate(Segment, &Size); if (!Result) { if (Size > 0) { setBL(XMS_STATUS_SMALLER_UMB); setDX(Size); } else { setBL(XMS_STATUS_INVALID_UMB); } } setAX(Result); break; } default: { DPRINT1("XMS command AH = 0x%02X NOT IMPLEMENTED\n", getAH()); setBL(XMS_STATUS_NOT_IMPLEMENTED); } } }
__declspec(dllexport) void __cdecl VDDDispatch(void) { char str[512]; DWORD count; DWORD msgs; int retval; int node_num; BYTE* p; vdd_status_t* status; static DWORD writes; static DWORD bytes_written; static DWORD reads; static DWORD bytes_read; static DWORD inbuf_poll; static DWORD online_poll; static DWORD status_poll; static DWORD vdd_yields; static DWORD vdd_calls; VDD_IO_HANDLERS IOHandlers = { NULL }; static VDD_IO_PORTRANGE PortRange; retval=0; node_num=getBH(); lprintf(LOG_DEBUG,"VDD_OP: (handle=%d) %d (arg=%X)", getAX(),getBL(),getCX()); vdd_calls++; switch(getBL()) { case VDD_OPEN: sscanf("$Revision: 1.40 $", "%*s %s", revision); lprintf(LOG_INFO,"Synchronet Virtual Device Driver, rev %s %s %s" ,revision, __DATE__, __TIME__); #if 0 sprintf(str,"sbbsexec%d.log",node_num); fp=fopen(str,"wb"); #endif sprintf(str,"\\\\.\\mailslot\\sbbsexec\\wr%d",node_num); rdslot=CreateMailslot(str ,0 //LINEAR_RX_BUFLEN /* Max message size (0=any) */ ,MAILSLOT_WAIT_FOREVER /* Read timeout */ ,NULL); if(rdslot==INVALID_HANDLE_VALUE) { lprintf(LOG_ERR,"!VDD_OPEN: Error %d opening %s" ,GetLastError(),str); retval=1; break; } sprintf(str,"\\\\.\\mailslot\\sbbsexec\\rd%d",node_num); wrslot=CreateFile(str ,GENERIC_WRITE ,FILE_SHARE_READ ,NULL ,OPEN_EXISTING ,FILE_ATTRIBUTE_NORMAL ,(HANDLE) NULL); if(wrslot==INVALID_HANDLE_VALUE) { lprintf(LOG_ERR,"!VDD_OPEN: Error %d opening %s" ,GetLastError(),str); retval=2; break; } if(RingBufInit(&rdbuf, RINGBUF_SIZE_IN)!=0) { retval=3; break; } sprintf(str,"sbbsexec_hungup%d",node_num); hungup_event=OpenEvent( EVENT_ALL_ACCESS, /* access flag */ FALSE, /* inherit flag */ str); /* pointer to event-object name */ if(hungup_event==NULL) { lprintf(LOG_ERR,"!VDD_OPEN: Error %d opening %s" ,GetLastError(),str); retval=4; break; } sprintf(str,"sbbsexec_hangup%d",node_num); hangup_event=OpenEvent( EVENT_ALL_ACCESS, /* access flag */ FALSE, /* inherit flag */ str); /* pointer to event-object name */ if(hangup_event==NULL) { lprintf(LOG_WARNING,"!VDD_OPEN: Error %d opening %s" ,GetLastError(),str); } status_poll=0; inbuf_poll=0; online_poll=0; yields=0; lprintf(LOG_INFO,"Yield interval: %f milliseconds", yield_interval); if(virtualize_uart) { lprintf(LOG_INFO,"Virtualizing UART (0x%x, IRQ %u)" ,uart_io_base, uart_irq); IOHandlers.inb_handler = uart_rdport; IOHandlers.outb_handler = uart_wrport; PortRange.First=uart_io_base; PortRange.Last=uart_io_base + UART_IO_RANGE; VDDInstallIOHook((HANDLE)getAX(), 1, &PortRange, &IOHandlers); interrupt_event=CreateEvent(NULL,FALSE,FALSE,NULL); InitializeCriticalSection(&interrupt_mutex); _beginthread(interrupt_thread, 0, NULL); } lprintf(LOG_DEBUG,"VDD_OPEN: Opened successfully (wrslot=%p)", wrslot); _beginthread(input_thread, 0, NULL); retval=0; break; case VDD_CLOSE: lprintf(LOG_INFO,"VDD_CLOSE: rdbuf=%u " "status_poll=%u inbuf_poll=%u online_poll=%u yields=%u vdd_yields=%u vdd_calls=%u" ,RingBufFull(&rdbuf),status_poll,inbuf_poll,online_poll ,yields,vdd_yields,vdd_calls); lprintf(LOG_INFO," read=%u bytes (in %u calls)",bytes_read,reads); lprintf(LOG_INFO," wrote=%u bytes (in %u calls)",bytes_written,writes); if(virtualize_uart) { lprintf(LOG_INFO,"Uninstalling Virtualizaed UART IO Hook"); VDDDeInstallIOHook((HANDLE)getAX(), 1, &PortRange); } CloseHandle(rdslot); CloseHandle(wrslot); if(hungup_event!=NULL) CloseHandle(hungup_event); if(hangup_event!=NULL) CloseHandle(hangup_event); #if 0 /* This isn't strictly necessary... and possibly the cause of a NULL dereference in the input_thread */ RingBufDispose(&rdbuf); #endif status_poll=0; retval=0; break; case VDD_READ: count = getCX(); if(count != 1) lprintf(LOG_DEBUG,"VDD_READ of %d",count); p = (BYTE*) GetVDMPointer((ULONG)((getES() << 16)|getDI()) ,count,FALSE); retval=vdd_read(p, count); reads++; bytes_read+=retval; reset_yield(); break; case VDD_PEEK: count = getCX(); if(count != 1) lprintf(LOG_DEBUG,"VDD_PEEK of %d",count); p = (BYTE*) GetVDMPointer((ULONG)((getES() << 16)|getDI()) ,count,FALSE); retval=RingBufPeek(&rdbuf,p,count); reset_yield(); break; case VDD_WRITE: count = getCX(); if(count != 1) lprintf(LOG_DEBUG,"VDD_WRITE of %d",count); p = (BYTE*) GetVDMPointer((ULONG)((getES() << 16)|getDI()) ,count,FALSE); if(!WriteFile(wrslot,p,count,&retval,NULL)) { lprintf(LOG_ERR,"!VDD_WRITE: WriteFile Error %d (size=%d)" ,GetLastError(),retval); retval=0; } else { writes++; bytes_written+=retval; reset_yield(); } break; case VDD_STATUS: status_poll++; count = getCX(); if(count != sizeof(vdd_status_t)) { lprintf(LOG_DEBUG,"!VDD_STATUS: wrong size (%d!=%d)",count,sizeof(vdd_status_t)); retval=sizeof(vdd_status_t); break; } status = (vdd_status_t*) GetVDMPointer((ULONG)((getES() << 16)|getDI()) ,count,FALSE); status->inbuf_size=RINGBUF_SIZE_IN; status->inbuf_full=RingBufFull(&rdbuf); msgs=0; /* OUTBUF FULL/SIZE */ if(!GetMailslotInfo( wrslot, /* mailslot handle */ &status->outbuf_size, /* address of maximum message size */ &status->outbuf_full, /* address of size of next message */ &msgs, /* address of number of messages */ NULL /* address of read time-out */ )) { lprintf(LOG_ERR,"!VDD_STATUS: GetMailSlotInfo(%p) failed, error %u (msgs=%u, inbuf_full=%u, inbuf_size=%u)" ,wrslot ,GetLastError(), msgs, status->inbuf_full, status->inbuf_size); status->outbuf_full=0; status->outbuf_size=DEFAULT_MAX_MSG_SIZE; } else lprintf(LOG_DEBUG,"VDD_STATUS: MailSlot maxmsgsize=%u, nextmsgsize=%u, msgs=%u" ,status->outbuf_size ,status->outbuf_full ,msgs); if(status->outbuf_full==MAILSLOT_NO_MESSAGE) status->outbuf_full=0; status->outbuf_full*=msgs; /* ONLINE */ if(WaitForSingleObject(hungup_event,0)==WAIT_OBJECT_0) status->online=0; else status->online=1; retval=0; /* success */ break; case VDD_INBUF_PURGE: RingBufReInit(&rdbuf); retval=0; break; case VDD_OUTBUF_PURGE: lprintf(LOG_WARNING,"!VDD_OUTBUF_PURGE: NOT IMPLEMENTED"); retval=0; break; case VDD_INBUF_FULL: retval=RingBufFull(&rdbuf); inbuf_poll++; break; case VDD_INBUF_SIZE: retval=RINGBUF_SIZE_IN; break; case VDD_OUTBUF_FULL: if(!GetMailslotInfo( wrslot, /* mailslot handle */ NULL, /* address of maximum message size */ &retval, /* address of size of next message */ &msgs, /* address of number of messages */ NULL /* address of read time-out */ )) retval=0; if(retval==MAILSLOT_NO_MESSAGE) retval=0; retval*=msgs; break; case VDD_OUTBUF_SIZE: if(!GetMailslotInfo( wrslot, /* mailslot handle */ &retval, /* address of maximum message size */ NULL, /* address of size of next message */ NULL, /* address of number of messages */ NULL /* address of read time-out */ )) retval=DEFAULT_MAX_MSG_SIZE; break; case VDD_ONLINE: if(WaitForSingleObject(hungup_event,0)==WAIT_OBJECT_0) retval=0; else retval=1; online_poll++; break; case VDD_YIELD: /* forced yield */ vdd_yields++; yield(); break; case VDD_MAYBE_YIELD: /* yield if YieldInterval is enabled and expired */ maybe_yield(); break; case VDD_LOAD_INI_FILE: /* Load and parse settings file */ { FILE* fp; char cwd[MAX_PATH+1]; /* Load exec/sbbsexec.ini first (setting default values) */ count = getCX(); p = (BYTE*)GetVDMPointer((ULONG)((getES() << 16)|getDI()) ,count,FALSE); iniFileName(ini_fname, sizeof(ini_fname), p, INI_FILENAME); if((fp=fopen(ini_fname,"r"))!=NULL) { ini=iniReadFile(fp); fclose(fp); parse_ini(ROOT_SECTION); } /* Load cwd/sbbsexec.ini second (over-riding default values) */ GetCurrentDirectory(sizeof(cwd),cwd); iniFileName(ini_fname, sizeof(ini_fname), cwd, INI_FILENAME); if((fp=fopen(ini_fname,"r"))!=NULL) { ini=iniReadFile(fp); fclose(fp); parse_ini(ROOT_SECTION); } } break; case VDD_LOAD_INI_SECTION: /* Parse (program-specific) sub-section of settings file */ count = getCX(); p = (BYTE*)GetVDMPointer((ULONG)((getES() << 16)|getDI()) ,count,FALSE); parse_ini(p); break; case VDD_DEBUG_OUTPUT: /* Send string to debug output */ count = getCX(); p = (BYTE*)GetVDMPointer((ULONG)((getES() << 16)|getDI()) ,count,FALSE); lputs(LOG_INFO, p); break; case VDD_HANGUP: hangup(); break; default: lprintf(LOG_ERR,"!UNKNOWN VDD_OP: %d",getBL()); break; } setAX((WORD)retval); }
void rs232_io() { #ifdef BIT_ORDER2 union { half_word all; struct { HALF_WORD_BIT_FIELD word_length:2; HALF_WORD_BIT_FIELD stop_bit:1; HALF_WORD_BIT_FIELD parity:2; HALF_WORD_BIT_FIELD baud_rate:3; } bit; } parameters; #endif #ifdef BIT_ORDER1 union { half_word all; struct { HALF_WORD_BIT_FIELD baud_rate:3; HALF_WORD_BIT_FIELD parity:2; HALF_WORD_BIT_FIELD stop_bit:1; HALF_WORD_BIT_FIELD word_length:2; } bit; } parameters; #endif DIVISOR_LATCH divisor_latch; int j; half_word timeout; sys_addr timeout_location; /* clear com/lpt idle flag */ IDLE_comlpt (); setIF(1); /* * Which adapter? */ switch (getDX ()) { case 0: port = RS232_COM1_PORT_START; timeout_location = RS232_COM1_TIMEOUT; break; case 1: port = RS232_COM2_PORT_START; timeout_location = RS232_COM2_TIMEOUT; break; case 2: port = RS232_COM3_PORT_START; timeout_location = RS232_COM3_TIMEOUT; break; case 3: port = RS232_COM4_PORT_START; timeout_location = RS232_COM4_TIMEOUT; break; default: break; } /* * Determine function */ switch (getAH ()) { case 0: /* * Initialise the communication port */ value = 0x80; /* set DLAB */ outb(port + (io_addr) RS232_LCR, value); /* * Set baud rate */ parameters.all = getAL(); divisor_latch.all = divisors[parameters.bit.baud_rate]; outb(port + (io_addr) RS232_IER, divisor_latch.byte.MSByte); outb(port + (io_addr) RS232_TX_RX, divisor_latch.byte.LSByte); /* * Set word length, stop bits and parity */ parameters.bit.baud_rate = 0; outb(port + (io_addr) RS232_LCR, parameters.all); /* * Disable interrupts */ value = 0; outb(port + (io_addr) RS232_IER, value); return_status(); break; case 1: /* * Send char over the comms line */ /* * Set DTR and RTS */ outb(port + (io_addr) RS232_MCR, 3); /* * Real BIOS checks CTS and DSR - we know DSR ok. * Real BIOS check THRE - we know it's ok. * We only check CTS - this is supported on a few ports, eg. Macintosh. */ /* * Wait for CTS to go high, or timeout */ sas_load(timeout_location, &timeout); for ( j = 0; j < timeout; j++) { inb(port + (io_addr) RS232_MSR, &value); if(value & 0x10)break; /* CTS High, all is well */ } if(j < timeout) { outb(port + (io_addr) RS232_TX_RX, getAL()); /* Send byte */ inb(port + (io_addr) RS232_LSR, &value); setAH(value); /* Return Line Status Reg in AH */ } else { setAH(value | 0x80); /* Indicate time out */ } break; case 2: /* * Receive char over the comms line */ /* * Set DTR */ value = 1; outb(port + (io_addr) RS232_MCR, value); /* * Real BIOS checks DSR - we know it's ok. */ /* * Wait for data to appear, or timeout(just an empirical guess) */ sas_load(timeout_location, &timeout); for ( j = 0; j < timeout; j++) { inb(port + (io_addr) RS232_LSR, &value); if ( (value & 1) == 1 ) { /* * Data ready go read it */ value &= 0x1e; /* keep error bits only */ setAH(value); inb(port + (io_addr) RS232_TX_RX, &value); setAL(value); return; } } /* * Set timeout */ value |= 0x80; setAH(value); break; case 3: /* * Return the communication port status */ return_status(); break; case 4: /* * EXTENDED (PS/2) Initialise the communication port */ value = 0x80; /* set DLAB */ outb(port + (io_addr) RS232_LCR, value); parameters.bit.word_length = getCH(); parameters.bit.stop_bit = getBL(); parameters.bit.parity = getBH(); parameters.bit.baud_rate = getCL(); /* Set baud rate */ divisor_latch.all = divisors[parameters.bit.baud_rate]; outb(port + (io_addr) RS232_IER, divisor_latch.byte.MSByte); outb(port + (io_addr) RS232_TX_RX, divisor_latch.byte.LSByte); /* * Set word length, stop bits and parity */ parameters.bit.baud_rate = 0; outb(port + (io_addr) RS232_LCR, parameters.all); /* * Disable interrupts */ value = 0; outb(port + (io_addr) RS232_IER, value); return_status(); break; case 5: /* EXTENDED Comms Port Control */ switch( getAL() ) { case 0: /* Read modem control register */ inb( port + (io_addr) RS232_MCR, &value); setBL(value); break; case 1: /* Write modem control register */ outb( port + (io_addr) RS232_MCR, getBL()); break; } /* Return the communication port status */ return_status(); break; default: /* ** Yes both XT and AT BIOS's really do this. */ setAH( getAH()-3 ); break; } }