;++ ; ; Module name ; ; exp.asm ; ; Author ; ; Thomas Parslow (tomp) Feb-26-91 ; ; Description ; ; Entry points exported to OS loader by SU module. Exported ; routines provide basic machine dependent i/o funtions needed ; by the OS loader. Providing these routines decouples the ; OS loader from the h/w. Note that the OS loader will ; refer to these exported routines as the "external services". ; ; ; Exported Procedures ; ; RebootProcessor - Reboots the machine ; GetSector - Read one or more sectors from the boot device. ; PutChar - Puts a character on the video display. ; GetKey - Gets a key from the keyboard ; GetKeyEx - Gets an extended key from the keyboard or the comport (headless) ; GetCounter - Reads the Tick Counter ; Reboot - Transfers control to a loaded boot sector. ; HardwareCursor - set position of hardware cursor ; GetDateTime - gets date and time ; ComPort - int14 functions ; GetStallCount - calculates processor stall count ; ; ; Notes ; ; When adding a new exported routine note that you must manually add the ; entry's name to the BootRecord in "sudata.asm". ; ;-- include su.inc include macro.inc DISK_TABLE_VECTOR equ 01Eh * 4 _TEXT segment para use16 public 'CODE' ASSUME CS: _TEXT, DS: DGROUP, SS: DGROUP .386p extrn _DiskBaseTable:near extrn _RomDiskBasePointer:near extrn _EddsAddressPacket:near extrn _NetPcRomEntry:near extrn _EnableA20:near ;++ ; ; Exported Name: ; ; RebootProcessor ; ; Arguments: ; ; None ; ; Description: ; ; Reboot the processor using INT 19h ; ; ; ;-- ; ; ExportEntry takes us from a 32bit cs to a 16bit cs, inits 16bit stack ; and ds segments and saves the callers esp and ebp. ; ;-- EXPORT_ENTRY_MACRO RebootProcessor ; ; Switch to real mode so we can take interrupts ; ENTER_REALMODE_MACRO ; ; int 19h doesn't do what you would expect on BIOS Boot Specification machines. ; It either goes on to the next boot device or goes back to the first boot ; device. In both cases, it does not properly reset the machine. So we write ; to the keyboard port instead (as does HalpReboot). ; mov ax, 040h mov ds, ax mov word ptr ds:[72h], 1234h ; set location 472 to 1234 to indicate warm reboot mov al, 0feh out 64h, al ; write to keyboard port to cause reboot ; ; Loop forever and wait to ctrl-alt-del (should never get here) ; WAIT_FOREVER_MACRO ;EXPORT_EXIT_MACRO ;++ ; ; Name: ; ; GetSector ; ; Description: ; ; Reads the requested number of sectors from the specified drive into ; the specified buffer. ; ; Arguments: ; ; ULONG Virtual address into which to read data ; ULONG Number of sectors to read ; ULONG Physical sector number ; ULONG Drive Number ; ULONG Function Number ; TOS -> ULONG Flat return address (must be used with KeCodeSelector) ; ;-- EXPORT_ENTRY_MACRO GetSector ; ; Move the arguments from the caller's 32bit stack to the SU module's ; 16bit stack. ; MAKE_STACK_FRAME_MACRO , ebx ; ; Go into real mode. We still have the same stack and sp ; but we'll be executing in realmode. ; ENTER_REALMODE_MACRO ; ; Get the requested sectors. Arguments on realmode stack ; Make (bp) point to the bottom of the argument frame. ; push bp mov bp,sp add bp,2 ; ; Put the buffer pointer into es:bx. Note that and buffer ; addresses passed to this routine MUST be in the lower one ; megabyte of memory to be addressable in real mode. ; mov eax,[bp].BufferPointer mov bx,ax and bx,0fh shr eax,4 mov es,ax ; ; Place the upper 2 bits of the 10bit track/cylinder number ; into the uppper 2 bits of the SectorNumber as reguired by ; the bios. ; mov cx,word ptr [bp].TrackNumber xchg ch,cl shl cl,6 add cl,byte ptr [bp].SectorNumber ; ; Get the rest of the arguments ; mov ah,byte ptr [bp].FunctionNumber mov al,byte ptr [bp].NumberOfSectors mov dh,byte ptr [bp].HeadNumber mov dl,byte ptr [bp].DriveNumber ; ; Check to see if we are trying to reset/read/write/verify off the second ; floppy drive. If so, we need to go change the disk-base vector. ; cmp dl,1 jne gs3 cmp ah,4 jg gs3 cmp ah,0 je gs1 cmp ah,2 jl gs3 gs1: ; ; We need to point the BIOS disk-table vector to our own table for this ; drive. ; push es push bx push di push 0 pop es mov di, offset DGROUP:_RomDiskBasePointer mov bx,es:[DISK_TABLE_VECTOR] mov [di],bx mov bx,es:[DISK_TABLE_VECTOR+2] mov [di+2],bx mov bx,offset DGROUP:_DiskBaseTable mov es:[DISK_TABLE_VECTOR],bx mov bx,ds mov es:[DISK_TABLE_VECTOR+2],bx pop di pop bx pop es int BIOS_DISK_INTERRUPT push es push bx push di push 0 pop es mov di, offset DGROUP:_RomDiskBasePointer mov bx, [di] mov es:[DISK_TABLE_VECTOR],bx mov bx, [di+2] mov es:[DISK_TABLE_VECTOR+2],bx pop di pop bx pop es jc gs5 xor eax,eax jmp short gs5 gs3: ; ; Call the bios to read the sector now ; if 0 push ax push dx push cx push bx push es extrn _DisplayArgs:near call _DisplayArgs pop es pop bx pop cx pop dx pop ax endif int BIOS_DISK_INTERRUPT jc gs5 ; ; Carry wasn't set so we have no error and need to "clean" eax of ; any garbage that may have been left in it. ; xor eax,eax gs5: if 0 push ax push dx push cx push bx push es extrn _DisplayArgs:near call _DisplayArgs pop es pop bx pop cx pop dx pop ax endif ; ; Mask-off any garbage that my have been left in the upper ; 16bits of eax. ; and eax,0000ffffh ; ; Restore bp and remove stack-frame from stack ; pop bp REMOVE_STACK_FRAME_MACRO ; ; Save return code on 16bit stack ; Re-enable protect-mode and paging. ; ; move cx into high 16-bits of ecx, and dx into cx. This is so the loader ; can get at interesting values in dx, even though edx gets munged by the ; random real-mode macros. shl ecx, 16 mov cx,dx push eax RE_ENABLE_PAGING_MACRO pop eax ; ; Return to caller and the 32bit universe. ; EXPORT_EXIT_MACRO ;++ ; ; Name: ; ; GetEddsSector ; ; Description: ; ; Reads the requested number of sectors from the specified drive into ; the specified buffer based on the Phoenix Enhanced Disk Drive Spec. ; ; Arguments: ; ; ULONG xint13 function number (42 = read, 43 = write) ; ULONG Virtual address into which to read data ; ULONG Number of logical blocks to read (word) ; ULONG Logical block number (High dword) ; ULONG Logical block number (Low dword) ; ULONG Drive Number (byte) ; TOS -> ULONG Flat return address (must be used with KeCodeSelector) ; ;-- EXPORT_ENTRY_MACRO GetEddsSector ; ; Move the arguments from the caller's 32bit stack to the SU module's ; 16bit stack. ; MAKE_STACK_FRAME_MACRO , ebx ; ; Go into real mode. We still have the same stack and sp ; but we'll be executing in realmode. ; ENTER_REALMODE_MACRO ; ; Get the requested sectors. Arguments on realmode stack ; Make (bp) point to the bottom of the argument frame. ; push bp mov bp,sp add bp,2 push ds push si push bx ; ; Set up DS:SI -> Disk Address Packet ; push 0 pop ds mov si, offset DGROUP:_EddsAddressPacket mov ds:[si],word ptr 10h ; Packet size = 10h, plus reserved byte mov ax,word ptr [bp].NumberOfBlocks mov ds:[si][2],ax ; Num blocks to transfer mov eax,[bp].BufPointer mov bx,ax and bx,0fh mov ds:[si][4],bx ; Transfer buffer address (low word=offset) shr eax,4 mov ds:[si][6],ax ; Transfer buffer address (high word=segment) mov eax,[bp].LBNLow mov ds:[si][8],eax ; Starting logical block number (low dword) mov eax,[bp].LBNHigh mov ds:[si][12],eax ; Starting logical block number (high dword) ; ; Call the bios to read the sector now (DS:SI -> Disk address packet) ; mov ah,byte ptr [bp].FunctionNum ; function xor al,al ; force verify on write off mov dl,byte ptr [bp].DriveNum ; DL = drive number int BIOS_DISK_INTERRUPT jc geserror1 ; ; Carry wasn't set so we have no error and need to "clean" eax of ; any garbage that may have been left in it. ; xor eax,eax geserror1: ; ; Mask-off any garbage that my have been left in the upper ; 16bits of eax. ; and eax,0000ffffh pop bx pop si pop ds ; ; Restore bp and remove stack-frame from stack ; pop bp REMOVE_STACK_FRAME_MACRO ; ; Save return code on 16bit stack ; Re-enable protect-mode and paging. ; ; move cx into high 16-bits of ecx, and dx into cx. This is so the loader ; can get at interesting values in dx, even though edx gets munged by the ; random real-mode macros. shl ecx, 16 mov cx,dx push eax RE_ENABLE_PAGING_MACRO pop eax ; ; Return to caller and the 32bit universe. ; EXPORT_EXIT_MACRO ;++ ; ; Routine Name: ; ; GetKey ; ; Description: ; ; Checks the keyboard to see if a key is available. ; ; Arguments: ; ; None. ; ; Returns: ; ; If no key is available, returns 0 ; ; If ASCII character is available, LSB 0 is ASCII code ; LSB 1 is keyboard scan code ; If extended character is available, LSB 0 is extended ASCII code ; LSB 1 is keyboard scan code ; ;-- EXPORT_ENTRY_MACRO GetKey ; ; Go into real mode. We still have the same stack and sp ; but we'll be executing in real mode. ; ENTER_REALMODE_MACRO ; ; Set up registers to call BIOS and check to see if a key is available ; mov ax,0100h int BIOS_KEYBOARD_INTERRUPT jnz GkKeyAvail mov eax, 0 jmp GkDone GkKeyAvail: ; ; Now we call BIOS again, this time to get the key from the keyboard buffer ; mov ax,0h int BIOS_KEYBOARD_INTERRUPT and eax,0000ffffh ; ; Save return code on 16bit stack ; Re-enable protect mode and paging ; GkDone: push eax RE_ENABLE_PAGING_MACRO pop eax ; ; Return to caller and the 32-bit universe ; EXPORT_EXIT_MACRO ;++ ; ; Routine Name: ; ; GetKeyEx ; ; Description: ; ; Checks the keyboard to see if a (possibly extended) key is available. ; ; Arguments: ; ; None. ; ; Returns: ; ; If no key is available, returns 0 ; ; If ASCII character is available, LSB 0 is ASCII code ; LSB 1 is keyboard scan code ; If extended character is available, LSB 0 is extended ASCII code ; LSB 1 is keyboard scan code ; ;-- public GetKeyEx GetKeyEx proc near IFDEF HEADLESS_SRV ; ; Give priority to Com I/O ; push edi call GetCounterReal ; get starting RTC value mov edi,eax ; calculate RTC value for now + 2 secs. add edi,37 ; (RTC clicks 18.2 times per second) TopComPortRead: mov ah, 03h ; Query status mov al, 0 mov dx, HEADLESS_COMPORT ; Com port int 14h mov bh, ah ; There seems to be a problem where the transmitter shift and ah, 40h ; register status bit gets stuck on. When this is jz XmitterOk1 ; the case, it blocks all other status bits. To resolve it ; we write out a NULL character mov ah, 01h ; Write character mov al, 0 ; NULL character mov dx, HEADLESS_COMPORT ; Com port int 14h call GetCounterReal ; get current RTC value cmp eax, edi ; is it higher than end value? jb TopComPortRead ; loop if current < end jmp NoComPortKey XmitterOk1: mov ah, bh and ah, 1 ; Data ready jz NoComPortKey mov ah, 02h ; Read character mov al, 0 mov dx, HEADLESS_COMPORT ; Com port int 14h cmp al, 1bh ; If this is the ESC character, process Function key (if any) jne ExitComPortRead call GetCounterReal ; get starting RTC value mov edi,eax ; calculate RTC value for now + 2 secs. add edi,37 ; (RTC clicks 18.2 times per second) EscLoop: mov ah, 03h ; Query status mov al, 0 mov dx, HEADLESS_COMPORT ; Com port int 14h mov bh, ah ; There seems to be a problem where the transmitter shift and ah, 40h ; register status bit gets stuck on. When this is jz XmitterOk2 ; the case, it blocks all other status bits. To resolve it ; we write out a NULL character mov ah, 01h ; Write character mov al, 0 ; NULL character mov dx, HEADLESS_COMPORT ; Com port int 14h jmp EscLoop XMitterOk2: mov ah, bh and ah, 1 ; Data ready jnz NextKeyPressed call GetCounterReal ; get current RTC value cmp eax, edi ; is it higher than end value? jb EscLoop ; loop if current < end jmp ComPortEscapeKey NextKeyPressed: mov ah, 02h ; Read character mov al, 0 mov dx, HEADLESS_COMPORT ; Com port int 14h cmp al, 40h ; '@' key jne CheckMinusSign mov eax, 0DA00h ; F12 key jmp GkxDone CheckMinusSign: cmp al, 21h ; '!' key jne CheckNumbers mov eax, 0D900h ; F11 key jmp GkxDone CheckNumbers: cmp al, 30h jl ComPortEscapeKey cmp al, 39h jg ComPortEscapeKey add al, 10 mov ah, 0 shl eax, 8 cmp eax, 3a00h ; Check for miscomputation on F10 key (aka Esc-0) jne GkxDone mov eax, 4400h jmp GkxDone ComPortEscapeKey: mov eax, 011bh ; ESCAPE key jmp GkxDone ExitComPortRead: movzx edx, al mov eax, edx jmp GkxDone NoComPortKey: endif ; ; Set up registers to call BIOS and check to see if a key is available ; mov ax,01100h int BIOS_KEYBOARD_INTERRUPT jnz GkxKeyAvail mov eax, 0 jmp GkxDone GkxKeyAvail: ; ; Now we call BIOS again, this time to get the key from the keyboard buffer ; mov ax,01000h int BIOS_KEYBOARD_INTERRUPT and eax,0000ffffh GkxDone: IFDEF HEADLESS_SRV pop edi endif ret GetKeyEx endp ;++ ; ; Routine Name: ; ; GetCounter ; ; Description: ; ; Reads the tick counter (incremented 18.2 times per second) ; ; Arguments: ; ; None ; ; Returns: ; ; The current value of the tick counter ; ;-- EXPORT_ENTRY_MACRO GetCounter ; ; Go into real mode. ; ENTER_REALMODE_MACRO call GetCounterReal push eax RE_ENABLE_PAGING_MACRO pop eax EXPORT_EXIT_MACRO public GetCounterReal GetCounterReal proc near mov ah,0 int 01ah mov ax,cx ; high word of count shl eax,16 mov ax,dx ; low word of count ret GetCounterReal endp ;++ ; ; Routine Name: ; ; Reboot ; ; Description: ; ; Switches to real-mode and transfers control to a loaded boot sector ; ; Arguments: ; ; unsigned BootType ; 0 = FAT. Just jump to 0:7c00. ; 1 = HPFS. Assumes boot code and super+spare areas (20 sectors) ; are already loaded at 0xd000; jumps to d00:200. ; 2 = NTFS. Assumes boot code is loaded (16 sectors) at 0xd000. ; Jumps to d00:256. ; 3 = SDI. Boot from downloaded SDI image. Assumes boot code ; (startrom.com) has been copied from the SDI image to ; 0x7c00. Changes low byte of argument from 0x03 to 0x41 ; to tell startrom that this is an SDI boot. The upper 3 ; bytes of the argument are the upper 3 bytes of the ; page-aligned address at which the SDI image was loaded. ; ; Returns: ; Does not return ; ; Environment: ; ; Boot sector has been loaded at 7C00 ;-- EXPORT_ENTRY_MACRO Reboot ; ; Move the arguments from the caller's 32bit stack to the SU module's ; 16bit stack. ; MAKE_STACK_FRAME_MACRO , ebx ; ; Go into real mode. ; ENTER_REALMODE_MACRO ; ; Get the BootType argument. Arguments on realmode stack ; Make (bp) point to the bottom of the argument frame. ; push bp mov bp,sp add bp,2 mov edx, [bp].BootType ; ; Zero out the firmware heaps, 3000:0000 - 4000:ffff. ; xor eax,eax ; prepare for stosd mov bx,3000h mov es,bx mov di,ax ; es:di = physical address 30000 mov cx,4000h ; cx = rep count, # dwords in 64K cld rep stosd mov cx,4000h ; rep count mov es,cx ; es:di = physical address 40000 rep stosd ; ; Disable the A20 line. Some things (like EMM386 and OS/2 on PS/2 machines) ; hiccup or die if we don't do this. ; extrn _DisableA20:near call _DisableA20 ; ; Put the video adapter back in 80x25 mode ; push edx mov ax, 0003h int 010h pop edx ; ; Reset all the segment registers and setup the original stack ; mov ax,0 mov ds,ax mov es,ax mov fs,ax mov gs,ax mov ax,30 mov ss,ax mov esp,0100h mov ebp,0 mov esi,0 mov edi,0 ; ; Check for FAT boot or SDI boot and jump as appropriate. ; test dx,-1 jz FatBoot cmp dl,3 je SdiBoot ; ; Setup the registers the way the second sector of the OS/2 HPFS boot code ; expects them. We skip the first sector entirely, as that just loads in ; the rest of the sectors. Since the rest of the sectors are ours and not ; OS/2's, this would cause great distress. ; mov ax,07c0h mov ds, ax mov ax, 0d00h mov es, ax cli xor ax,ax mov ss,ax mov sp, 07c00h sti push 0d00h push 0256h jmp RebootDoit ; ; SDI boot. Set up to jump to startrom at 0:7c00. Change the 0x03 in DL ; to 0x41 to indicate SDI boot. Leave the upper three bytes of EDX as is. ; SdiBoot: push 0 push 07c00h mov dl,041h jmp RebootDoit ; ; FAT boot. Set up to jump to startup at 0:7c00. Put 0x80 in DX to indicate ; the boot drive. ; FatBoot: push 0 ; set up for branch to boot sector push 07c00h mov dx,080h ; ; And away we go! ; RebootDoit: retf RE_ENABLE_PAGING_MACRO REMOVE_STACK_FRAME_MACRO EXPORT_EXIT_MACRO ;++ ; ; Name: ; ; HardwareCursor ; ; Description: ; ; Positions the hardware cursor and performs other display stuff. ; ; Arguments: ; ; ULONG Y coord (0 based) ; ULONG X coord (0 based) ; TOS -> ULONG Flat return address (must be used with KeCodeSelector) ; ; If X = 0x80000000, then Y contains values that get placed into ; ax (low word of Y) and bx (hi word of y). ; Otherwise X,Y = coors for cursor ; ; ;-- EXPORT_ENTRY_MACRO HardwareCursor ; ; Move the arguments from the caller's 32bit stack to the SU module's ; 16bit stack. ; MAKE_STACK_FRAME_MACRO , ebx ; ; Go into real mode. We still have the same stack and sp ; but we'll be executing in realmode. ; ENTER_REALMODE_MACRO ; ; Get the requested sectors. Arguments on realmode stack ; Make (bp) point to the bottom of the argument frame. ; push bp mov bp,sp add bp,2 ; ; Put the row (y coord) in dh and the column (x coord) in dl. ; mov eax,[bp].YCoord mov edx,[bp].XCoord cmp edx,80000000h jne gotxy mov ebx,eax shr ebx,16 jmp doint10 gotxy: mov dh,al mov ah,2 mov bh,0 doint10: int 10h ; ; Restore bp and remove stack-frame from stack ; pop bp REMOVE_STACK_FRAME_MACRO ; ; Re-enable protect-mode and paging. ; RE_ENABLE_PAGING_MACRO ; ; Return to caller and the 32bit universe. ; EXPORT_EXIT_MACRO ;++ ; ; Name: ; ; GetDateTime ; ; Description: ; ; Gets date and time ; ; Arguments: ; ; ULONG Virtual address of a dword in which to place time. ; ULONG Virtual address of a dword in which to place date. ; TOS -> ULONG Flat return address (must be used with KeCodeSelector) ; ;-- BCD_TO_BIN macro xor ah,ah rol ax,4 ror al,4 aad endm EXPORT_ENTRY_MACRO GetDateTime ; ; Move the arguments from the caller's 32bit stack to the SU module's ; 16bit stack. ; MAKE_STACK_FRAME_MACRO , ebx ; ; Go into real mode. We still have the same stack and sp ; but we'll be executing in realmode. ; ENTER_REALMODE_MACRO ; ; Make (bp) point to the bottom of the argument frame. ; push bp mov bp,sp add bp,2 ; ; Get the time ; mov ah,2 int 1ah ; ; Convert BIOS time format into our format and place in caller's dword ; bits 0-5 are the second ; bits 6-11 are the minute ; bits 12-16 are the hour ; xor eax,eax mov al,dh ; BCD seconds BCD_TO_BIN movzx edx,ax mov al,cl ; BCD minutes BCD_TO_BIN shl ax,6 or dx,ax mov al,ch ; BCD hours BCD_TO_BIN shl eax,12 or edx,eax mov eax,[bp].TimeDword mov bx,ax and bx,0fh shr eax,4 mov es,ax mov es:[bx],edx ; ; Get the date ; mov ah,4 int 1ah ; ; Convert BIOS date format into our format and place in caller's dword ; bits 0-4 are the day ; bits 5-8 are the month ; bits 9-31 are the year ; xor eax,eax mov al,dl ; BCD day BCD_TO_BIN mov bl,dh movzx edx,ax mov al,bl ; BCD month BCD_TO_BIN shl ax,5 or dx,ax mov al,cl ; BCD year BCD_TO_BIN mov cl,al mov al,ch ; BCD century BCD_TO_BIN mov ah,100 mul ah xor ch,ch add ax,cx shl eax,9 or edx,eax mov eax,[bp].DateDword mov bx,ax and bx,0fh shr eax,4 mov es,ax mov es:[bx],edx ; ; Restore bp and remove stack-frame from stack ; pop bp REMOVE_STACK_FRAME_MACRO ; ; Re-enable protect-mode and paging. ; RE_ENABLE_PAGING_MACRO ; ; Return to caller and the 32bit universe. ; EXPORT_EXIT_MACRO ;++ ; ; VOID ; DetectHardware ( ; IN PDETECTION_RECORD DetectionRecord ; ) ; ; Routine Description: ; ; This routine invokes x86 16 bit real mode detection code from ; osloader 32 bit flat mode. ; ; Arguments: ; ; DetectionRecord - Supplies a pointer to a detection record structure. ; ; Return Value: ; ; None. ; ;-- EXPORT_ENTRY_MACRO DetectHardware ; ; Move the arguments from the caller's 32bit stack to the SU module's ; 16bit stack. ; MAKE_STACK_FRAME_MACRO , ebx ; ; Go into real mode. We still have the same stack and sp ; but we'll be executing in realmode. ; ENTER_REALMODE_MACRO ; ; Call the Hardware Detection code ; push cs push offset _TEXT:DetectionDone ; push far return addr push DETECTION_ADDRESS_SEG push DETECTION_ADDRESS_OFFSET retf DetectionDone: ; ; Restore bp and remove stack-frame from stack ; REMOVE_STACK_FRAME_MACRO ; ; No return code, so we don't save return code around page enabling code ; Re-enable protect-mode and paging. ; RE_ENABLE_PAGING_MACRO ; ; Return to caller and the 32bit universe. ; EXPORT_EXIT_MACRO ;++ ; ; VOID ; ComPort ( ; IN LONG Port, ; IN ULONG Function, ; IN UCHAR Arg ; ) ; ; Routine Description: ; ; Invoke int14 on com1. ; ; Arguments: ; ; Port - port # (0 = com1, etc). ; ; Function - int 14 function (for ah) ; ; Arg - arg for function (for al) ; ; Return Value: ; ; None. ; ;-- EXPORT_ENTRY_MACRO ComPort ; ; Move the arguments from the caller's 32bit stack to the SU module's ; 16bit stack. ; MAKE_STACK_FRAME_MACRO , ebx ; ; Go into real mode. We still have the same stack and sp ; but we'll be executing in realmode. ; ENTER_REALMODE_MACRO ; ; Make (bp) point to the bottom of the argument frame. ; push bp mov bp,sp add bp,2 ; ; Get args and call int14 ; mov ah,byte ptr [bp].ComPortFunction mov al,byte ptr [bp].ComPortArg mov dx,word ptr [bp].ComPortPort int 14h ; ; Restore bp and remove stack-frame from stack ; pop bp REMOVE_STACK_FRAME_MACRO ; ; No return code, so we don't save return code around page enabling code ; Re-enable protect-mode and paging. ; RE_ENABLE_PAGING_MACRO ; ; Return to caller and the 32bit universe. ; EXPORT_EXIT_MACRO ;++ ; ; ULONG ; GetStallCount ( ; VOID ; ) ; ; Routine Description: ; ; Calculates how many increments are required to stall for one microsecond ; ; The way this routine works is to set up an ISR on the BIOS vector 1C. ; This routine will get called 18.2 times a second. The location where ; IP will be stored when the interrupt occurs is computed and stashed in ; the code segment. When the ISR fires, the IP on the stack is changed ; to point to the next chunk of code to execute. So we can spin in a ; very tight loop and automatically get blown out of the loop when the ; interrupt occurs. ; ; This is all pretty sleazy, but it allows us to calibrate accurately ; without relying on the 8259 or 8254 (just BIOS). It also does not ; depend on whether the ISR can affect the CPU registers or not. (some ; BIOSes, notably Olivetti, will preserve the registers for you) ; ; Arguments: ; ; None. ; ; Return Value: ; ; Number of increments required to stall for one microsecond ; ;-- EXPORT_ENTRY_MACRO GetStallCount ; ; Go into real mode. ; ENTER_REALMODE_MACRO cli push di push si push ds mov ax,0 mov ds,ax ; ; save previous vector ; mov di, 01ch*4 mov cx, [di] mov dx, [di+2] ; ; insert our vector ; mov ax, offset GscISR mov [di], ax push cs pop ax mov [di+2], ax mov eax,0 mov ebx,0 mov si,sp sub si,6 mov cs:savesp,si mov cs:newip,offset GscLoop2 sti ; ; wait for first tick. ; GscLoop1: cmp ebx,0 je GscLoop1 ; ; start counting ; ; ; We spin in this loop until the ISR fires. The ISR will munge the return ; address on the stack to blow us out of the loop and into GscLoop3 ; GscLoop2: mov cs:newip,offset GscLoop4 GscLoop3: add eax,1 jnz short GscLoop3 ; GscLoop4: ; ; stop counting ; ; ; replace old vector ; cli mov [di],cx mov [di+2],dx sti pop ds pop si pop di jmp GscDone newip dw ? savesp dw ? GscISR: ; ; blow out of loop ; push bp push ax mov bp,cs:savesp mov ax,cs:newip mov ss:[bp],ax pop ax pop bp GscISRdone: iret GscDone: mov edx, eax mov ecx,16 shr edx,cl ; (dx:ax) = dividend mov cx,0D6A6h ; (cx) = divisor div cx and eax,0ffffh inc eax ; round loopcount up (prevent 0) ; ; Re-enable protect-mode and paging. ; push eax RE_ENABLE_PAGING_MACRO pop eax ; ; Return to caller and the 32bit universe. ; EXPORT_EXIT_MACRO ;++ ; ; Routine Name: ; ; InitializeDisplayForNt ; ; Description: ; ; Puts the display into 50 line mode ; ; Arguments: ; ; None ; ; Returns: ; ; None ; ;-- EXPORT_ENTRY_MACRO InitializeDisplayForNt ; ; Go into real mode. ; ENTER_REALMODE_MACRO mov ax, 1112h ; Load 8x8 font mov bx, 0 int 10h RE_ENABLE_PAGING_MACRO EXPORT_EXIT_MACRO ;++ ; ; Routine Name: ; ; GetMemoryDescriptor ; ; Description: ; ; Returns a memory descriptor ; ; Arguments: ; ; pointer to MemoryDescriptorFrame ; ; Returns: ; ; None ; ;-- EXPORT_ENTRY_MACRO GetMemoryDescriptor ; ; Move the arguments from the caller's 32bit stack to the SU module's ; 16bit stack. ; MAKE_STACK_FRAME_MACRO , ebx ; ; Go into real mode. We still have the same stack and sp ; but we'll be executing in realmode. ; ENTER_REALMODE_MACRO ; ; Make (bp) point to the bottom of the argument frame. ; push bp mov bp,sp add bp,2 mov eax,[bp].E820FramePointer mov bp,ax and bp,0fh shr eax,4 mov es,ax ; (es:bp) = E820 Frame mov ebx, es:[bp].Key mov ecx, es:[bp].DescSize lea di, [bp].BaseAddrLow mov eax, 0E820h mov edx, 'SMAP' ; (edx) = signature INT 15h mov es:[bp].Key, ebx ; update callers ebx mov es:[bp].DescSize, ecx ; update callers size sbb ecx, ecx ; ecx = -1 if carry, else 0 sub eax, 'SMAP' ; eax = 0 if signature matched or ecx, eax mov es:[bp].ErrorFlag, ecx ; return 0 or non-zero ; ; Restore bp and remove stack-frame from stack ; pop bp REMOVE_STACK_FRAME_MACRO RE_ENABLE_PAGING_MACRO EXPORT_EXIT_MACRO ;++ ; ; Routine Name: ; ; GetElToritoStatus ; ; Description: ; ; Get El Torito Disk Emulation Status ; ; Arguments: ; ; None ; ; Returns: ; ; None ; ;-- EXPORT_ENTRY_MACRO GetElToritoStatus ; ; Move the arguments from the caller's 32bit stack to the SU module's ; 16bit stack. ; MAKE_STACK_FRAME_MACRO , ebx ; ; Go into real mode. We still have the same stack and sp ; but we'll be executing in realmode. ; ENTER_REALMODE_MACRO ; ; Make (bp) point to the bottom of the argument frame. ; push bp mov bp,sp add bp,2 push dx push bx push ds push si ; ; Put the Specification Packet pointer into DS:SI, and the Drive ; Number on DL. Note that and buffer ; addresses passed to this routine MUST be in the lower one ; megabyte of memory to be addressable in real mode. ; mov eax,[bp].SpecPacketPointer mov bx,ax and bx,0fh mov si,bx shr eax,4 mov ds,ax mov dl,byte ptr [bp].ETDriveNum mov ax,04B01h ; Function = Return Disk Emulation status int BIOS_DISK_INTERRUPT jc etstatuserr ; ; Carry wasn't set so we have no error and need to "clean" eax of ; any garbage that may have been left in it. ; xor eax,eax etstatuserr: ; ; Mask-off any garbage that my have been left in the upper ; 16bits of eax. ; and eax,0000ffffh pop si pop ds pop bx pop dx ; ; Restore bp and remove stack-frame from stack ; pop bp REMOVE_STACK_FRAME_MACRO ; ; Save return code on 16bit stack ; Re-enable protect-mode and paging. ; push eax RE_ENABLE_PAGING_MACRO pop eax ; ; Return to caller and the 32bit universe. ; EXPORT_EXIT_MACRO ;++ ; ; Routine Name: ; ; GetExtendedInt13Params ; ; Description: ; ; Determine if extended int13 services are available for a drive ; and if so retrieve extended disk parameters. ; ; Arguments: ; ; - 32-bit flat pointer to 26-byte param packet filled by this routine ; ; - int 13 unit number ; ; Returns: ; ; ax = 0 means extended int13 not supported on the given drive ; ax = 1 means extended int13 supported and param packet filled in ; ;-- EXPORT_ENTRY_MACRO GetExtendedInt13Params ; ; Move the arguments from the caller's 32bit stack to the SU module's ; 16bit stack. ; MAKE_STACK_FRAME_MACRO , ebx ; ; Go into real mode. We still have the same stack and sp ; but we'll be executing in realmode. ; ENTER_REALMODE_MACRO ; ; Make (bp) point to the bottom of the argument frame. ; push bp mov bp,sp add bp,2 push dx push bx push ds push si ; ; Check for support for this drive. ; mov ah,41h mov bx,55aah mov dl,byte ptr [bp].Int13UnitNumber int BIOS_DISK_INTERRUPT jc noxint13 ; carry set means no xint13 cmp bx,0aa55h ; check signature jnz noxint13 ; not present, no xint13 test cl,1 ; bit 0 clear means no xint13 jz noxint13 ; ; If we get here it looks like we have xint13 support. ; Some BIOSes are broken though so we do some validation while we're ; asking for the extended int13 drive parameters for the drive. ; Note that and buffer addresses passed to this routine ; MUST be in the lower one megabyte of memory to be addressable in real mode. ; mov eax,[bp].ParamPacketPointer mov bx,ax and bx,0fh mov si,bx shr eax,4 mov ds,ax ; DS:SI -> param packet mov word ptr [si],26 ; initialize packet with size ; some bioses helpfully zero out ; the whole buffer according to ; this size, so make SURE the ; entire word is initialized and ; there's no junk in the high byte. mov dl,byte ptr [bp].Int13UnitNumber mov ah,48h int BIOS_DISK_INTERRUPT jc noxint13 ; ; If we get here then everything's cool and we have xint13 parameters. ; We also know carry isn't set. ; mov al,1 jnc xint13done noxint13: xor al,al xint13done: movzx eax,al pop si pop ds pop bx pop dx ; ; Restore bp and remove stack-frame from stack ; pop bp REMOVE_STACK_FRAME_MACRO ; ; Save return code on 16bit stack ; Re-enable protect-mode and paging. ; push eax RE_ENABLE_PAGING_MACRO pop eax ; ; Return to caller and the 32bit universe. ; EXPORT_EXIT_MACRO ;++ ; ; ULONG ; NetPcRomServices ( ; ULONG FunctionNumber ; PVOID CommandPacket ; ) ; ; Routine Name: ; ; NetPcRomServices ; ; Description: ; ; Invoke a NetPC ROM service ; ; Arguments: ; ; FunctionNumber - NetPC ROM function number ; CommandPacket - 32-bit flat pointer to command packet (must be in ; low megabyte of physical memory) ; ; Returns: ; ; NetPC ROM status code ; ;-- EXPORT_ENTRY_MACRO NetPcRomServices ; ; Move the arguments from the caller's 32bit stack to the SU module's ; 16bit stack. ; MAKE_STACK_FRAME_MACRO , ebx ; ; Go into real mode. We still have the same stack and sp ; but we'll be executing in realmode. ; ENTER_REALMODE_MACRO ; ; Make (bp) point to the bottom of the argument frame. ; push bp mov bp,sp add bp,2 ; ; Put the CommandPacket pointer into ES:DI, and the Function Number into BX. ; mov eax,dword ptr [bp].NetPcRomCommandPacketPointer mov bx,ax and bx,0fh mov di,bx shr eax,4 mov es,ax mov bx,word ptr [bp].NetPcRomFunctionNumber push ds lds si,dword ptr _NetPcRomEntry mov ax,ds shl eax,16 mov ax,si push cs push offset _TEXT:RomServiceDone push ds push si if 0 push ds push si push 0b800h pop ds mov si, 20*(80*2)+(2*40) mov byte ptr ds:[si],02bh pop si pop ds endif retf RomServiceDone: if 0 push ds push si push 0b800h pop ds mov si, 20*(80*2)+(2*40) mov byte ptr ds:[si],02dh pop si pop ds endif pop ds ; ; Restore bp and remove stack-frame from stack ; pop bp REMOVE_STACK_FRAME_MACRO ; ; Save return code on 16bit stack. Turn the A20 gate back on, ; in case the BIOS turned it off in int 15h, op 87h. ; Re-enable protect-mode and paging. ; push eax cli call _EnableA20 sti RE_ENABLE_PAGING_MACRO pop eax ; ; Return to caller and the 32bit universe. ; EXPORT_EXIT_MACRO ;++ ; ; ULONG ; BiosRedirectService ( ; ULONG Command ; ) ; ; Routine Name: ; ; BiosRedirectService ; ; Description: ; ; Get parameters of bios redirection. ; ; Arguments: ; ; Command - 1: Get Com Port Number ; 2: Get Baud Rate ; 3: Get Parity ; 4: Get Stop Bits ; ; Returns: ; ; Value, or -1 if an error. ; ;-- EXPORT_ENTRY_MACRO BiosRedirectService ; ; Move the arguments from the caller's 32bit stack to the SU module's ; 16bit stack. ; MAKE_STACK_FRAME_MACRO , ebx ; ; Go into real mode. We still have the same stack and sp ; but we'll be executing in realmode. ; ENTER_REALMODE_MACRO ; ; Make (bp) point to the bottom of the argument frame. ; push bp mov bp,sp add bp,2 ; ; Get the Command and do it. ; mov eax,dword ptr [bp].Command cmp eax, 1 je GetComPort cmp eax, 2 je GetBaudRate cmp eax, 3 je GetParity cmp eax, 4 je GetStopBits mov eax, -1 jmp Done GetStopBits: mov eax, 1 jmp Done GetParity: mov eax, 0 jmp Done GetBaudRate: IFDEF HDLS_HISPEED mov eax, 115200 else mov eax, 9600 endif jmp Done GetComPort: IFDEF HEADLESS_SRV mov eax, HEADLESS_COMPORT add eax, 1 else mov eax, -1 endif Done: ; ; Restore bp and remove stack-frame from stack ; pop bp REMOVE_STACK_FRAME_MACRO ; ; Save return code on 16bit stack. Turn the A20 gate back on, ; in case the BIOS turned it off in int 15h, op 87h. ; Re-enable protect-mode and paging. ; push eax cli call _EnableA20 sti RE_ENABLE_PAGING_MACRO pop eax ; ; Return to caller and the 32bit universe. ; EXPORT_EXIT_MACRO _TEXT ends end