|
|
;++ ; ; 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 <GetSectorFrame>, 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 <GetSectorFrame>
; ; 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 <GetEddsSectorFrame>, 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 <GetEddsSectorFrame>
; ; 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 <RebootFrame>, 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 <RebootFrame>
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 <HardwareCursorFrame>, 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 <HardwareCursorFrame>
; ; 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 <GetDateTimeFrame>, 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 <GetDateTimeFrame>
; ; 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 <DetectionFrame>, 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 <DetectionFrame>
; ; 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 <ComPortFrame>, 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 <ComPortFrame>
; ; 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 <MemoryDescriptorFramePointer>, 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 <MemoryDescriptorFramePointer> 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 <GetElToritoStatusFrame>, 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 <GetElToritoStatusFrame>
; ; 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 <GetExtendedInt13ParamsFrame>, 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 <GetExtendedInt13ParamsFrame>
; ; 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 <NetPcRomServicesFrame>, 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 <NetPcRomServicesFrame>
; ; 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 <BiosRedirectServiceFrame>, 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 <BiosRedirectServiceFrame>
; ; 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
|