windows-nt/Source/XPSP1/NT/base/boot/startup/i386/exp.asm

1774 lines
36 KiB
NASM
Raw Permalink Normal View History

2020-09-26 03:20:57 -05:00
;++
;
; 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
; 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
;++
;
; 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).
;
; int 19h
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:
;
; 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
mov ah,0
int 01ah
mov ax,cx ; high word of count
shl eax,16
mov ax,dx ; low word of count
push eax
RE_ENABLE_PAGING_MACRO
pop eax
EXPORT_EXIT_MACRO
;++
;
; 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.
;
; 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 dx
mov ax, 0003h
int 010h
pop dx
;
; 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
test dx,-1
jz FatBoot
;
; 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
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
;++
;
; Routine Name:
;
; ApmAttemptReconnect
;
; Description:
;
; Called only during x86 resume from hiberate operation. Attempts
; to connect to APM bios in same way ntdetect.com did on first try,
; so that if APM is present on the machine, it will be reinited to
; the same working state it was in before hibernate.
;
; APM version, addresses, selector mappings, etc, are assumed
; not to have changed while the machine is hibernated.
;
;
; Arguments:
;
; None.
;
; Returns:
;
; None. (It either works or it doesn't.)
;
;--
;
; Yet another set of cheater APM include values
;
APM_INSTALLATION_CHECK equ 5300h
APM_REAL_MODE_CONNECT equ 5301h
APM_PROTECT_MODE_16bit_CONNECT equ 5302h
APM_DRIVER_VERSION equ 530Eh
APM_DISCONNECT equ 5304h
APM_DEVICE_BIOS equ 0h
APM_MODE_16BIT equ 1h
EXPORT_ENTRY_MACRO ApmAttemptReconnect
;
; Go into real mode. We still have the same stack and sp
; but we'll be executing in realmode.
;
ENTER_REALMODE_MACRO
;
; APM installation check
;
mov eax,APM_INSTALLATION_CHECK
mov ebx,APM_DEVICE_BIOS
int 15h
jc aar_punt
cmp bl,'M'
jnz aar_punt
cmp bh,'P'
jnz aar_punt
;
; If we get here, we have an APM bios. If we just call it,
; we may get grief. So we will connect in real mode, then
; set our version to the whatever the driver says it is, or 1.2,
; whichever is LESS. Then query options again.
;
cmp ah,1
jle aar10
mov ah,1 ; ah = min(old ah, 1)
aar10:
cmp al,2
jle aar20
mov al,2 ; al = min(old al, 2)
aar20:
;
; ax = min(apm version, 1.2)
;
push ax
;
; connect to the real mode interface
;
mov ax,APM_REAL_MODE_CONNECT
mov bx,APM_DEVICE_BIOS
int 15h
pop ax
jc aar_punt
push ax
;
; set the version of the real mode interface
;
mov cx,ax ; ax = major.minor
mov bx,APM_DEVICE_BIOS
mov ax,APM_DRIVER_VERSION
int 15h
pop ax
jc aar_punt
;
; do the install check again, now that we've connected and
; set the version to min(apm ver, 1.2) some apm bios code
; will give us different install parameters now.
;
mov ax,APM_INSTALLATION_CHECK
mov bx,APM_DEVICE_BIOS
int 15h
jc aar_punt
;
; If we are here:
; AH = revised Major version
; AL = revised Minor version
; CX = APM Flags
;
push cx
push ax
;
; Now disconnect from the real mode interface
;
mov ax,APM_DISCONNECT
mov bx,APM_DEVICE_BIOS
int 15h
pop ax
pop cx
jc aar_punt
;
; Since we are here:
; AH = revised Major version
; AL = revised Minor version
; CX = apm parameters
;
; APM is present, and seems to work, and we've set it to the
; version number that we think it and we both like.
;
; So, things should just work, if APM has proper support
; for the modes and features that we need.
;
cmp cx,APM_MODE_16BIT
jz aar_punt
;
; 16bit protected mode is available
;
push ax
push cx
;
; do 16 bit protected mode connect
;
mov ax,APM_PROTECT_MODE_16bit_CONNECT
mov bx,APM_DEVICE_BIOS
int 15h
pop cx
pop ax
jc aar_punt
;
; do 16 bit protected mode set version
;
mov cx,ax
mov ax,APM_DRIVER_VERSION
mov bx,APM_DEVICE_BIOS
int 15h
;
; if NC, then we have connect to 16bit proected mode interface,
; AND set the version. since ntdetect.com presumably did this
; exact same thing at first boot, we already have GDT entries pointing
; to the 16bit code, hooks set, etc. So, in theory, it just works.
;
; if CY here, or anywhere above, APM doesn't work for us. Too bad.
;
aar_punt:
;
; return to paged mode
;
RE_ENABLE_PAGING_MACRO
;
; Return to caller and the 32bit universe.
;
EXPORT_EXIT_MACRO
_TEXT ends
end