;++ ; ; 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 , ebx ; ; Go into real mode. We still have the same stack and sp ; but we'll be executing in realmode. ; ENTER_REALMODE_MACRO ; ; Get the requested sectors. Arguments on realmode stack ; Make (bp) point to the bottom of the argument frame. ; push bp mov bp,sp add bp,2 ; ; Put the buffer pointer into es:bx. Note that and buffer ; addresses passed to this routine MUST be in the lower one ; megabyte of memory to be addressable in real mode. ; mov eax,[bp].BufferPointer mov bx,ax and bx,0fh shr eax,4 mov es,ax ; ; Place the upper 2 bits of the 10bit track/cylinder number ; into the uppper 2 bits of the SectorNumber as reguired by ; the bios. ; mov cx,word ptr [bp].TrackNumber xchg ch,cl shl cl,6 add cl,byte ptr [bp].SectorNumber ; ; Get the rest of the arguments ; mov ah,byte ptr [bp].FunctionNumber mov al,byte ptr [bp].NumberOfSectors mov dh,byte ptr [bp].HeadNumber mov dl,byte ptr [bp].DriveNumber ; ; Check to see if we are trying to reset/read/write/verify off the second ; floppy drive. If so, we need to go change the disk-base vector. ; cmp dl,1 jne gs3 cmp ah,4 jg gs3 cmp ah,0 je gs1 cmp ah,2 jl gs3 gs1: ; ; We need to point the BIOS disk-table vector to our own table for this ; drive. ; push es push bx push di push 0 pop es mov di, offset DGROUP:_RomDiskBasePointer mov bx,es:[DISK_TABLE_VECTOR] mov [di],bx mov bx,es:[DISK_TABLE_VECTOR+2] mov [di+2],bx mov bx,offset DGROUP:_DiskBaseTable mov es:[DISK_TABLE_VECTOR],bx mov bx,ds mov es:[DISK_TABLE_VECTOR+2],bx pop di pop bx pop es int BIOS_DISK_INTERRUPT push es push bx push di push 0 pop es mov di, offset DGROUP:_RomDiskBasePointer mov bx, [di] mov es:[DISK_TABLE_VECTOR],bx mov bx, [di+2] mov es:[DISK_TABLE_VECTOR+2],bx pop di pop bx pop es jc gs5 xor eax,eax jmp short gs5 gs3: ; ; Call the bios to read the sector now ; if 0 push ax push dx push cx push bx push es extrn _DisplayArgs:near call _DisplayArgs pop es pop bx pop cx pop dx pop ax endif int BIOS_DISK_INTERRUPT jc gs5 ; ; Carry wasn't set so we have no error and need to "clean" eax of ; any garbage that may have been left in it. ; xor eax,eax gs5: if 0 push ax push dx push cx push bx push es extrn _DisplayArgs:near call _DisplayArgs pop es pop bx pop cx pop dx pop ax endif ; ; Mask-off any garbage that my have been left in the upper ; 16bits of eax. ; and eax,0000ffffh ; ; Restore bp and remove stack-frame from stack ; pop bp REMOVE_STACK_FRAME_MACRO ; ; Save return code on 16bit stack ; Re-enable protect-mode and paging. ; ; move cx into high 16-bits of ecx, and dx into cx. This is so the loader ; can get at interesting values in dx, even though edx gets munged by the ; random real-mode macros. shl ecx, 16 mov cx,dx push eax RE_ENABLE_PAGING_MACRO pop eax ; ; Return to caller and the 32bit universe. ; EXPORT_EXIT_MACRO ;++ ; ; Name: ; ; GetEddsSector ; ; Description: ; ; Reads the requested number of sectors from the specified drive into ; the specified buffer based on the Phoenix Enhanced Disk Drive Spec. ; ; Arguments: ; ; ULONG xint13 function number (42 = read, 43 = write) ; ULONG Virtual address into which to read data ; ULONG Number of logical blocks to read (word) ; ULONG Logical block number (High dword) ; ULONG Logical block number (Low dword) ; ULONG Drive Number (byte) ; TOS -> ULONG Flat return address (must be used with KeCodeSelector) ; ;-- EXPORT_ENTRY_MACRO GetEddsSector ; ; Move the arguments from the caller's 32bit stack to the SU module's ; 16bit stack. ; MAKE_STACK_FRAME_MACRO , ebx ; ; Go into real mode. We still have the same stack and sp ; but we'll be executing in realmode. ; ENTER_REALMODE_MACRO ; ; Get the requested sectors. Arguments on realmode stack ; Make (bp) point to the bottom of the argument frame. ; push bp mov bp,sp add bp,2 push ds push si push bx ; ; Set up DS:SI -> Disk Address Packet ; push 0 pop ds mov si, offset DGROUP:_EddsAddressPacket mov ds:[si],word ptr 10h ; Packet size = 10h, plus reserved byte mov ax,word ptr [bp].NumberOfBlocks mov ds:[si][2],ax ; Num blocks to transfer mov eax,[bp].BufPointer mov bx,ax and bx,0fh mov ds:[si][4],bx ; Transfer buffer address (low word=offset) shr eax,4 mov ds:[si][6],ax ; Transfer buffer address (high word=segment) mov eax,[bp].LBNLow mov ds:[si][8],eax ; Starting logical block number (low dword) mov eax,[bp].LBNHigh mov ds:[si][12],eax ; Starting logical block number (high dword) ; ; Call the bios to read the sector now (DS:SI -> Disk address packet) ; mov ah,byte ptr [bp].FunctionNum ; function xor al,al ; force verify on write off mov dl,byte ptr [bp].DriveNum ; DL = drive number int BIOS_DISK_INTERRUPT jc geserror1 ; ; Carry wasn't set so we have no error and need to "clean" eax of ; any garbage that may have been left in it. ; xor eax,eax geserror1: ; ; Mask-off any garbage that my have been left in the upper ; 16bits of eax. ; and eax,0000ffffh pop bx pop si pop ds ; ; Restore bp and remove stack-frame from stack ; pop bp REMOVE_STACK_FRAME_MACRO ; ; Save return code on 16bit stack ; Re-enable protect-mode and paging. ; ; move cx into high 16-bits of ecx, and dx into cx. This is so the loader ; can get at interesting values in dx, even though edx gets munged by the ; random real-mode macros. shl ecx, 16 mov cx,dx push eax RE_ENABLE_PAGING_MACRO pop eax ; ; Return to caller and the 32bit universe. ; EXPORT_EXIT_MACRO ;++ ; ; Routine Name: ; ; GetKey ; ; Description: ; ; Checks the keyboard to see if a key is available. ; ; Arguments: ; ; None. ; ; Returns: ; ; If no key is available, returns 0 ; ; If ASCII character is available, LSB 0 is ASCII code ; LSB 1 is keyboard scan code ; If extended character is available, LSB 0 is extended ASCII code ; LSB 1 is keyboard scan code ; ;-- EXPORT_ENTRY_MACRO GetKey ; ; Go into real mode. We still have the same stack and sp ; but we'll be executing in real mode. ; ENTER_REALMODE_MACRO ; ; Set up registers to call BIOS and check to see if a key is available ; mov ax,0100h int BIOS_KEYBOARD_INTERRUPT jnz GkKeyAvail mov eax, 0 jmp GkDone GkKeyAvail: ; ; Now we call BIOS again, this time to get the key from the keyboard buffer ; mov ax,0h int BIOS_KEYBOARD_INTERRUPT and eax,0000ffffh ; ; Save return code on 16bit stack ; Re-enable protect mode and paging ; GkDone: push eax RE_ENABLE_PAGING_MACRO pop eax ; ; Return to caller and the 32-bit universe ; EXPORT_EXIT_MACRO ;++ ; ; Routine Name: ; ; 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 , 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 EXPORT_EXIT_MACRO ;++ ; ; Name: ; ; HardwareCursor ; ; Description: ; ; Positions the hardware cursor and performs other display stuff. ; ; Arguments: ; ; ULONG Y coord (0 based) ; ULONG X coord (0 based) ; TOS -> ULONG Flat return address (must be used with KeCodeSelector) ; ; If X = 0x80000000, then Y contains values that get placed into ; ax (low word of Y) and bx (hi word of y). ; Otherwise X,Y = coors for cursor ; ; ;-- EXPORT_ENTRY_MACRO HardwareCursor ; ; Move the arguments from the caller's 32bit stack to the SU module's ; 16bit stack. ; MAKE_STACK_FRAME_MACRO , ebx ; ; Go into real mode. We still have the same stack and sp ; but we'll be executing in realmode. ; ENTER_REALMODE_MACRO ; ; Get the requested sectors. Arguments on realmode stack ; Make (bp) point to the bottom of the argument frame. ; push bp mov bp,sp add bp,2 ; ; Put the row (y coord) in dh and the column (x coord) in dl. ; mov eax,[bp].YCoord mov edx,[bp].XCoord cmp edx,80000000h jne gotxy mov ebx,eax shr ebx,16 jmp doint10 gotxy: mov dh,al mov ah,2 mov bh,0 doint10: int 10h ; ; Restore bp and remove stack-frame from stack ; pop bp REMOVE_STACK_FRAME_MACRO ; ; Re-enable protect-mode and paging. ; RE_ENABLE_PAGING_MACRO ; ; Return to caller and the 32bit universe. ; EXPORT_EXIT_MACRO ;++ ; ; Name: ; ; GetDateTime ; ; Description: ; ; Gets date and time ; ; Arguments: ; ; ULONG Virtual address of a dword in which to place time. ; ULONG Virtual address of a dword in which to place date. ; TOS -> ULONG Flat return address (must be used with KeCodeSelector) ; ;-- BCD_TO_BIN macro xor ah,ah rol ax,4 ror al,4 aad endm EXPORT_ENTRY_MACRO GetDateTime ; ; Move the arguments from the caller's 32bit stack to the SU module's ; 16bit stack. ; MAKE_STACK_FRAME_MACRO , ebx ; ; Go into real mode. We still have the same stack and sp ; but we'll be executing in realmode. ; ENTER_REALMODE_MACRO ; ; Make (bp) point to the bottom of the argument frame. ; push bp mov bp,sp add bp,2 ; ; Get the time ; mov ah,2 int 1ah ; ; Convert BIOS time format into our format and place in caller's dword ; bits 0-5 are the second ; bits 6-11 are the minute ; bits 12-16 are the hour ; xor eax,eax mov al,dh ; BCD seconds BCD_TO_BIN movzx edx,ax mov al,cl ; BCD minutes BCD_TO_BIN shl ax,6 or dx,ax mov al,ch ; BCD hours BCD_TO_BIN shl eax,12 or edx,eax mov eax,[bp].TimeDword mov bx,ax and bx,0fh shr eax,4 mov es,ax mov es:[bx],edx ; ; Get the date ; mov ah,4 int 1ah ; ; Convert BIOS date format into our format and place in caller's dword ; bits 0-4 are the day ; bits 5-8 are the month ; bits 9-31 are the year ; xor eax,eax mov al,dl ; BCD day BCD_TO_BIN mov bl,dh movzx edx,ax mov al,bl ; BCD month BCD_TO_BIN shl ax,5 or dx,ax mov al,cl ; BCD year BCD_TO_BIN mov cl,al mov al,ch ; BCD century BCD_TO_BIN mov ah,100 mul ah xor ch,ch add ax,cx shl eax,9 or edx,eax mov eax,[bp].DateDword mov bx,ax and bx,0fh shr eax,4 mov es,ax mov es:[bx],edx ; ; Restore bp and remove stack-frame from stack ; pop bp REMOVE_STACK_FRAME_MACRO ; ; Re-enable protect-mode and paging. ; RE_ENABLE_PAGING_MACRO ; ; Return to caller and the 32bit universe. ; EXPORT_EXIT_MACRO ;++ ; ; VOID ; DetectHardware ( ; IN PDETECTION_RECORD DetectionRecord ; ) ; ; Routine Description: ; ; This routine invokes x86 16 bit real mode detection code from ; osloader 32 bit flat mode. ; ; Arguments: ; ; DetectionRecord - Supplies a pointer to a detection record structure. ; ; Return Value: ; ; None. ; ;-- EXPORT_ENTRY_MACRO DetectHardware ; ; Move the arguments from the caller's 32bit stack to the SU module's ; 16bit stack. ; MAKE_STACK_FRAME_MACRO , ebx ; ; Go into real mode. We still have the same stack and sp ; but we'll be executing in realmode. ; ENTER_REALMODE_MACRO ; ; Call the Hardware Detection code ; push cs push offset _TEXT:DetectionDone ; push far return addr push DETECTION_ADDRESS_SEG push DETECTION_ADDRESS_OFFSET retf DetectionDone: ; ; Restore bp and remove stack-frame from stack ; REMOVE_STACK_FRAME_MACRO ; ; No return code, so we don't save return code around page enabling code ; Re-enable protect-mode and paging. ; RE_ENABLE_PAGING_MACRO ; ; Return to caller and the 32bit universe. ; EXPORT_EXIT_MACRO ;++ ; ; VOID ; ComPort ( ; IN LONG Port, ; IN ULONG Function, ; IN UCHAR Arg ; ) ; ; Routine Description: ; ; Invoke int14 on com1. ; ; Arguments: ; ; Port - port # (0 = com1, etc). ; ; Function - int 14 function (for ah) ; ; Arg - arg for function (for al) ; ; Return Value: ; ; None. ; ;-- EXPORT_ENTRY_MACRO ComPort ; ; Move the arguments from the caller's 32bit stack to the SU module's ; 16bit stack. ; MAKE_STACK_FRAME_MACRO , ebx ; ; Go into real mode. We still have the same stack and sp ; but we'll be executing in realmode. ; ENTER_REALMODE_MACRO ; ; Make (bp) point to the bottom of the argument frame. ; push bp mov bp,sp add bp,2 ; ; Get args and call int14 ; mov ah,byte ptr [bp].ComPortFunction mov al,byte ptr [bp].ComPortArg mov dx,word ptr [bp].ComPortPort int 14h ; ; Restore bp and remove stack-frame from stack ; pop bp REMOVE_STACK_FRAME_MACRO ; ; No return code, so we don't save return code around page enabling code ; Re-enable protect-mode and paging. ; RE_ENABLE_PAGING_MACRO ; ; Return to caller and the 32bit universe. ; EXPORT_EXIT_MACRO ;++ ; ; ULONG ; GetStallCount ( ; VOID ; ) ; ; Routine Description: ; ; Calculates how many increments are required to stall for one microsecond ; ; The way this routine works is to set up an ISR on the BIOS vector 1C. ; This routine will get called 18.2 times a second. The location where ; IP will be stored when the interrupt occurs is computed and stashed in ; the code segment. When the ISR fires, the IP on the stack is changed ; to point to the next chunk of code to execute. So we can spin in a ; very tight loop and automatically get blown out of the loop when the ; interrupt occurs. ; ; This is all pretty sleazy, but it allows us to calibrate accurately ; without relying on the 8259 or 8254 (just BIOS). It also does not ; depend on whether the ISR can affect the CPU registers or not. (some ; BIOSes, notably Olivetti, will preserve the registers for you) ; ; Arguments: ; ; None. ; ; Return Value: ; ; Number of increments required to stall for one microsecond ; ;-- EXPORT_ENTRY_MACRO GetStallCount ; ; Go into real mode. ; ENTER_REALMODE_MACRO cli push di push si push ds mov ax,0 mov ds,ax ; ; save previous vector ; mov di, 01ch*4 mov cx, [di] mov dx, [di+2] ; ; insert our vector ; mov ax, offset GscISR mov [di], ax push cs pop ax mov [di+2], ax mov eax,0 mov ebx,0 mov si,sp sub si,6 mov cs:savesp,si mov cs:newip,offset GscLoop2 sti ; ; wait for first tick. ; GscLoop1: cmp ebx,0 je GscLoop1 ; ; start counting ; ; ; We spin in this loop until the ISR fires. The ISR will munge the return ; address on the stack to blow us out of the loop and into GscLoop3 ; GscLoop2: mov cs:newip,offset GscLoop4 GscLoop3: add eax,1 jnz short GscLoop3 ; GscLoop4: ; ; stop counting ; ; ; replace old vector ; cli mov [di],cx mov [di+2],dx sti pop ds pop si pop di jmp GscDone newip dw ? savesp dw ? GscISR: ; ; blow out of loop ; push bp push ax mov bp,cs:savesp mov ax,cs:newip mov ss:[bp],ax pop ax pop bp GscISRdone: iret GscDone: mov edx, eax mov ecx,16 shr edx,cl ; (dx:ax) = dividend mov cx,0D6A6h ; (cx) = divisor div cx and eax,0ffffh inc eax ; round loopcount up (prevent 0) ; ; Re-enable protect-mode and paging. ; push eax RE_ENABLE_PAGING_MACRO pop eax ; ; Return to caller and the 32bit universe. ; EXPORT_EXIT_MACRO ;++ ; ; Routine Name: ; ; InitializeDisplayForNt ; ; Description: ; ; Puts the display into 50 line mode ; ; Arguments: ; ; None ; ; Returns: ; ; None ; ;-- EXPORT_ENTRY_MACRO InitializeDisplayForNt ; ; Go into real mode. ; ENTER_REALMODE_MACRO mov ax, 1112h ; Load 8x8 font mov bx, 0 int 10h RE_ENABLE_PAGING_MACRO EXPORT_EXIT_MACRO ;++ ; ; Routine Name: ; ; GetMemoryDescriptor ; ; Description: ; ; Returns a memory descriptor ; ; Arguments: ; ; pointer to MemoryDescriptorFrame ; ; Returns: ; ; None ; ;-- EXPORT_ENTRY_MACRO GetMemoryDescriptor ; ; Move the arguments from the caller's 32bit stack to the SU module's ; 16bit stack. ; MAKE_STACK_FRAME_MACRO , ebx ; ; Go into real mode. We still have the same stack and sp ; but we'll be executing in realmode. ; ENTER_REALMODE_MACRO ; ; Make (bp) point to the bottom of the argument frame. ; push bp mov bp,sp add bp,2 mov eax,[bp].E820FramePointer mov bp,ax and bp,0fh shr eax,4 mov es,ax ; (es:bp) = E820 Frame mov ebx, es:[bp].Key mov ecx, es:[bp].DescSize lea di, [bp].BaseAddrLow mov eax, 0E820h mov edx, 'SMAP' ; (edx) = signature INT 15h mov es:[bp].Key, ebx ; update callers ebx mov es:[bp].DescSize, ecx ; update callers size sbb ecx, ecx ; ecx = -1 if carry, else 0 sub eax, 'SMAP' ; eax = 0 if signature matched or ecx, eax mov es:[bp].ErrorFlag, ecx ; return 0 or non-zero ; ; Restore bp and remove stack-frame from stack ; pop bp REMOVE_STACK_FRAME_MACRO RE_ENABLE_PAGING_MACRO EXPORT_EXIT_MACRO ;++ ; ; Routine Name: ; ; GetElToritoStatus ; ; Description: ; ; Get El Torito Disk Emulation Status ; ; Arguments: ; ; None ; ; Returns: ; ; None ; ;-- EXPORT_ENTRY_MACRO GetElToritoStatus ; ; Move the arguments from the caller's 32bit stack to the SU module's ; 16bit stack. ; MAKE_STACK_FRAME_MACRO , ebx ; ; Go into real mode. We still have the same stack and sp ; but we'll be executing in realmode. ; ENTER_REALMODE_MACRO ; ; Make (bp) point to the bottom of the argument frame. ; push bp mov bp,sp add bp,2 push dx push bx push ds push si ; ; Put the Specification Packet pointer into DS:SI, and the Drive ; Number on DL. Note that and buffer ; addresses passed to this routine MUST be in the lower one ; megabyte of memory to be addressable in real mode. ; mov eax,[bp].SpecPacketPointer mov bx,ax and bx,0fh mov si,bx shr eax,4 mov ds,ax mov dl,byte ptr [bp].ETDriveNum mov ax,04B01h ; Function = Return Disk Emulation status int BIOS_DISK_INTERRUPT jc etstatuserr ; ; Carry wasn't set so we have no error and need to "clean" eax of ; any garbage that may have been left in it. ; xor eax,eax etstatuserr: ; ; Mask-off any garbage that my have been left in the upper ; 16bits of eax. ; and eax,0000ffffh pop si pop ds pop bx pop dx ; ; Restore bp and remove stack-frame from stack ; pop bp REMOVE_STACK_FRAME_MACRO ; ; Save return code on 16bit stack ; Re-enable protect-mode and paging. ; push eax RE_ENABLE_PAGING_MACRO pop eax ; ; Return to caller and the 32bit universe. ; EXPORT_EXIT_MACRO ;++ ; ; Routine Name: ; ; GetExtendedInt13Params ; ; Description: ; ; Determine if extended int13 services are available for a drive ; and if so retrieve extended disk parameters. ; ; Arguments: ; ; - 32-bit flat pointer to 26-byte param packet filled by this routine ; ; - int 13 unit number ; ; Returns: ; ; ax = 0 means extended int13 not supported on the given drive ; ax = 1 means extended int13 supported and param packet filled in ; ;-- EXPORT_ENTRY_MACRO GetExtendedInt13Params ; ; Move the arguments from the caller's 32bit stack to the SU module's ; 16bit stack. ; MAKE_STACK_FRAME_MACRO , ebx ; ; Go into real mode. We still have the same stack and sp ; but we'll be executing in realmode. ; ENTER_REALMODE_MACRO ; ; Make (bp) point to the bottom of the argument frame. ; push bp mov bp,sp add bp,2 push dx push bx push ds push si ; ; Check for support for this drive. ; mov ah,41h mov bx,55aah mov dl,byte ptr [bp].Int13UnitNumber int BIOS_DISK_INTERRUPT jc noxint13 ; carry set means no xint13 cmp bx,0aa55h ; check signature jnz noxint13 ; not present, no xint13 test cl,1 ; bit 0 clear means no xint13 jz noxint13 ; ; If we get here it looks like we have xint13 support. ; Some BIOSes are broken though so we do some validation while we're ; asking for the extended int13 drive parameters for the drive. ; Note that and buffer addresses passed to this routine ; MUST be in the lower one megabyte of memory to be addressable in real mode. ; mov eax,[bp].ParamPacketPointer mov bx,ax and bx,0fh mov si,bx shr eax,4 mov ds,ax ; DS:SI -> param packet mov word ptr [si],26 ; initialize packet with size ; some bioses helpfully zero out ; the whole buffer according to ; this size, so make SURE the ; entire word is initialized and ; there's no junk in the high byte. mov dl,byte ptr [bp].Int13UnitNumber mov ah,48h int BIOS_DISK_INTERRUPT jc noxint13 ; ; If we get here then everything's cool and we have xint13 parameters. ; We also know carry isn't set. ; mov al,1 jnc xint13done noxint13: xor al,al xint13done: movzx eax,al pop si pop ds pop bx pop dx ; ; Restore bp and remove stack-frame from stack ; pop bp REMOVE_STACK_FRAME_MACRO ; ; Save return code on 16bit stack ; Re-enable protect-mode and paging. ; push eax RE_ENABLE_PAGING_MACRO pop eax ; ; Return to caller and the 32bit universe. ; EXPORT_EXIT_MACRO ;++ ; ; 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