windows-nt/Source/XPSP1/NT/base/boot/startrom/i386/exp.asm
2020-09-26 16:20:57 +08:00

2057 lines
42 KiB
NASM

;++
;
; 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