; memory.
;
; Copyright 2001-2009 H. Peter Anvin - All Rights Reserved
+; Copyright 2009 Intel Corporation; author: H. Peter Anvin
+; Portions copyright 2009 Shao Miller [El Torito code, mBFT, safe hook]
;
; This program is free software; you can redistribute it and/or modify
; it under the terms of the GNU General Public License as published by
;
; ****************************************************************************
-%ifndef DEPEND
-%include "../version.gen"
-%endif
+%include "../version.gen"
; %define DEBUG_TRACERS ; Uncomment to get debugging tracers
call debug_tracer
db %1
%endmacro
+%macro WRITEHEX2 0-1 al
+%ifnidni %1,al
+ push ax
+ mov al,%1
+ call writehex2
+ pop ax
+%else
+ call writehex2
+%endif
+%endmacro
+%macro WRITEHEX4 0-1 ax
+%ifnidni %1,ax
+ push ax
+ mov ax,%1
+ call writehex4
+ pop ax
+%else
+ call writehex4
+%endif
+%endmacro
+%macro WRITEHEX8 0-1 eax
+%ifnidni %1,eax
+ push eax
+ mov eax,%1
+ call writehex8
+ pop eax
+%else
+ call writehex8
+%endif
+%endmacro
%else ; DEBUG_TRACERS
%macro TRACER 1
%endmacro
+%macro WRITEHEX2 0-1
+%endmacro
+%macro WRITEHEX4 0-1
+%endmacro
+%macro WRITEHEX8 0-1
+%endmacro
%endif ; DEBUG_TRACERS
org 0h
-%define SECTORSIZE_LG2 9 ; log2(sector size)
%define SECTORSIZE (1 << SECTORSIZE_LG2)
; Parameter registers definition; this is the definition
; must be first in the binary
Pointers: dw Int13Start
dw Int15Start
- dw PatchArea
+ dw MemDisk_Info ; Portions are patched by installer
dw TotalSize
dw IretPtr
IretPtr equ Int13Start.iret
Int13Start:
+ jmp strict near .SafeHookEnd ; 3-byte jump
+ db '$INT13SF' ; Signature for "safe hook"
+ db 'MEMDISK ' ; Vendor ID
+ dd 0 ; SEG:OFF of previous INT 13h hook
+ ; Must be filled in by installer
+ dd 0 ; "Safe hook" flags
+; ---- "Safe hook" structure ends here ---
+
+; This next field should be guaranteed at this position after the
+; "safe hook" structure. This allows for a MEMDISK OS driver to
+; immediately find out the particular parameters using the mBFT
+; and MDI structures. This binary will have the offset to the mBFT
+; in this field to begin with, so the installer knows where the mBFT
+; is. This is akin to the "Pointers" section above. The installer
+; will refill this field with the physical address of the mBFT for
+; future consumers, such as OS drivers.
+ dd mBFT ; Offset from hook to the mBFT
+
+.SafeHookEnd:
+ cmp word [cs:Recursive],0
+ jne recursive
+
; Swap stack
mov [cs:Stack],esp
+ mov [cs:Stack+4],ss
mov [cs:SavedAX],ax
- mov ax,ss
- mov [cs:Stack+4],ax
mov ax,cs
mov ss,ax
mov sp,[cs:MyStack]
+%if ELTORITO
+ cmp word [cs:SavedAX],4a00h ; El Torito function?
+ jae our_drive ; We grab it
+%endif
; See if DL points to our class of device (FD, HD)
push dx
push dx
js .nomatch ; If SF=0, we have a class match here
; 0x00 the sign bit for FD
; 0x80 the sign bit for HD
- jz .our_drive ; If ZF=1, we have an exact match
+ jz our_drive ; If ZF=1, we have an exact match
cmp dl,[cs:DriveNo]
jb .nomatch ; Drive < Our drive
+ cmp dl,[cs:DriveShiftLimit]
+ jae .nomatch ; Drive > The maximum drive
+ ; number that we will shift for.
+ ; This leaves any higher-up BIOS
+ ; drives alone, such as an optical
+ ; disc drive 0xA0 or 0xE0
dec dl ; Drive > Our drive, adjust drive #
.nomatch:
+ TRACER '!'
+ WRITEHEX2 dl
+ TRACER ','
mov ax,[cs:SavedAX]
+ WRITEHEX4
+ inc word [cs:Recursive]
pushf
call far [cs:OldInt13]
pushf
+ dec word [cs:Recursive]
push bp
mov bp,sp
cmp byte [cs:SavedAX+1],08h ; Get drive params function?
- je .norestoredl
+ je .norestoredl ; DL = number of drives
cmp byte [cs:SavedAX+1],15h ; Get disk type function?
jne .restoredl
- test byte [bp+4],80h ; Hard disk?
- jnz .norestoredl
-.restoredl: ; DL should have number of drives
+ test byte [bp+4],80h ; Hard disk?
+ jnz .norestoredl ; CX:DX = size of device
+.restoredl:
mov dl,[bp+4]
.norestoredl:
push ax
lss esp,[cs:Stack]
.iret: iret
-.our_drive:
+recursive:
+ TRACER '@'
+jmp_oldint13:
+ jmp far [cs:OldInt13]
+
+our_drive:
; Set up standard entry frame
push ds
push es
pushad
mov bp,sp ; Point BP to the entry stack frame
TRACER 'F'
- ; Note: AH == P_AH here
+ WRITEHEX4
+ ; Note: AX == P_AX here
cmp ah,Int13FuncsCnt-1
ja Invalid_jump
+%if ELTORITO
+ mov al,[CD_PKT.type] ; Check if we are in
+ cmp al,0 ; El Torito no emulation mode
+ ja .emulation ; No. We support the function
+ cmp ah,3fh ; Yes. We must not support functions
+ jbe Invalid_jump ; 0 through 3Fh. Check and decide
+.emulation:
+%endif
xor al,al ; AL = 0 is standard entry condition
mov di,ax
shr di,7 ; Convert AH to an offset in DI
pop ds
lss esp,[cs:Stack] ; Restore the stack
and dl,80h ; Clear all but the type bit
- jmp far [cs:OldInt13]
+ jmp jmp_oldint13
Invalid:
test byte [DriveNo],80h
mov bl,02h ; Type 02h = floppy with changeline
jz .floppy
- ; Hard disks only...
+ ; Hard disks only! DO NOT set CX:DX for floppies...
+ ; it apparently causes Win98SE DOS to go into an loop
+ ; resetting the drive over and over. Sigh.
inc bx ; Type = 03h
mov dx,[DiskSize] ; Return the disk size in sectors
mov P_DX,dx
jne Invalid
mov P_BX,0AA55h ; EDD signature
mov P_AX,03000h ; EDD 3.0
- mov P_CX,0003h ; Bit 0 - Fixed disk access subset
+ mov P_CX,0007h ; Bit 0 - Fixed disk access subset
; Bit 1 - Locking and ejecting subset
+ ; Bit 2 - EDD subset
pop ax ; Drop return address
xor ax,ax ; Success
jmp DoneWeird ; Success, but AH != 0, sigh...
EDDEject:
mov ax,0B200h ; Volume Not Removable
ret
-
+%if ELTORITO
+ElToritoTerminate:
+ TRACER 'T'
+ mov ax,[cs:SavedAX]
+ cmp al,1 ; We only support query, not terminate
+ jne ElToritoErr ; Fail
+ cmp dl,7fh ; Terminate all?
+ je .doit
+ cmp dl,[cs:DriveNo] ; Terminate our drive?
+ je .doit
+ jmp ElToritoErr ; Fail
+.doit: mov es,P_DS ; Caller's DS:SI pointed to packet
+ mov di,P_SI ; We'll use ES:DI
+ mov si,CD_PKT.size ; First byte is packet size
+ xor cx,0 ; Empty our count
+ ;mov cl,[ds:si] ; We'll copy that many bytes
+ mov cl,13h
+ rep movsb ; Copy until CX is zero
+ mov ax,0 ; Success
+ ret
+ElToritoEmulate:
+ElToritoBoot:
+ElToritoCatalog:
+ElToritoErr:
+ TRACER '!'
+ mov ax,100h ; Invalid parameter
+ ret
+%endif ; ELTORITO
%endif ; EDD
-
;
; INT 15h intercept routines
;
jne .renew
mov ebx,E820Table
.renew:
- add bx,16 ; Advance to next
- mov eax,[bx-8] ; Type
+ add bx,12 ; Advance to next
+ mov eax,[bx-4] ; Type
and eax,eax ; Null type?
jz .renew ; If so advance to next
mov [es:di+16],eax
- and cl,~3
- cmp ecx,24
- jb .no_extattr
- mov eax,[bx-4] ; Extended attributes
- mov [es:di+20],eax
- mov ecx,24 ; Bytes loaded
-.no_extattr:
- mov eax,[bx-16] ; Start addr (low)
- mov edx,[bx-12] ; Start addr (high)
+ mov eax,[bx-12] ; Start addr (low)
+ mov edx,[bx-8] ; Start addr (high)
mov [es:di],eax
mov [es:di+4],edx
mov eax,[bx] ; End addr (low)
mov edx,[bx+4] ; End addr (high)
- sub eax,[bx-16] ; Derive the length
- sbb edx,[bx-12]
+ sub eax,[bx-12] ; Derive the length
+ sbb edx,[bx-8]
mov [es:di+8],eax ; Length (low)
mov [es:di+12],edx ; Length (high)
cmp dword [bx+8],-1 ; Type of next = end?
.notdone:
pop eax ; "SMAP"
mov edx,eax ; Some systems expect eax = edx = SMAP
+ mov ecx,20 ; Bytes loaded
pop ds
int15_success:
mov byte [bp+6], 02h ; Clear CF
popfd
popad
ret
+
+writehex2: pushad
+ pushfd
+ mov cx,2
+ ror eax,4
+ jmp writehex_common
+writehex4: pushad
+ pushfd
+ mov cx,4
+ ror eax,12
+ jmp writehex_common
+writehex8: pushad
+ pushfd
+ mov cx,8
+ ror eax,28
+writehex_common:
+.loop: push cx
+ push eax
+ and al,0Fh
+ cmp al,10
+ jb .isdec
+ add al,'a'-'0'-10
+.isdec: add al,'0'
+ mov ah,0Eh
+ mov bx,7
+ int 10h
+ pop eax
+ rol eax,4
+ pop cx
+ loop .loop
+ popfd
+ popad
+ ret
%endif
- section .data
+ section .data align=16
alignb 2
Int13Funcs dw Reset ; 00h - RESET
dw GetStatus ; 01h - GET STATUS
dw EDDSeek ; 47h - EDD SEEK
dw EDDGetParms ; 48h - EDD GET PARAMETERS
dw EDDDetectChange ; 49h - EDD MEDIA CHANGE STATUS
-%endif
+%if ELTORITO ; EDD El Torito Functions
+ ; ELTORITO _must_ also have EDD
+ dw ElToritoEmulate ; 4Ah - Initiate Disk Emulation
+ dw ElToritoTerminate ; 4Bh - Terminate Disk Emulation
+ dw ElToritoBoot ; 4Ch - Initiate Disk Emu. and Reboot
+ dw ElToritoCatalog ; 4Dh - Return Boot Catalog
+%endif ; ELTORITO
+%endif ; EDD
Int13FuncsEnd equ $
Int13FuncsCnt equ (Int13FuncsEnd-Int13Funcs) >> 1
Mover_dst2: db 0 ; High 8 bits of source addy
Mover_dummy2: dd 0, 0, 0, 0 ; More space for the BIOS
- alignb 4, db 0
+ alignb 16, db 0
+mBFT:
+; Fields common to all ACPI tables
+ dd ' ' ; ACPI signature ("mBFT")
+ ; This is filled-in by the installer
+ ; to avoid an accidentally valid mBFT
+ dd mBFT_Len ; ACPI table length
+ db 1 ; ACPI revision
+ db 0 ; ACPI table checksum
+ db 'MEMDSK' ; ACPI OEM ID
+ db 'Syslinux' ; ACPI OEM table ID
+ dd 0 ; ACPI OEM revision
+ dd 0 ; ACPI ASL compiler vendor ID
+ dd 0 ; ACPI ASL compiler revision
+; The next field is mBFT-specific and filled-in by the installer
+ dd 0 ; "Safe hook" physical address
+
+; Note that the above ends on a DWORD boundary.
+; The MDI has always started at such a boundary.
+; Portions of the MDI are patched by the installer
MemDisk_Info equ $ ; Pointed to by installation check
MDI_Bytes dw MDI_Len ; Total bytes in MDI structure
MDI_Version db VERSION_MINOR, VERSION_MAJOR ; MEMDISK version
-PatchArea equ $ ; This gets filled in by the installer
-
DiskBuf dd 0 ; Linear address of high memory disk
DiskSize dd 0 ; Size of disk in blocks
CommandLine dw 0, 0 ; Far pointer to saved command line
; Original DPT pointer follows
MDI_Len equ $-MemDisk_Info
+mBFT_Len equ $-mBFT ; mBFT includes the MDI
; ---- MDI structure ends here ---
+DriveShiftLimit db 0ffh ; Installer will probe for
+ ; a range of contiguous drives.
+ ; Any BIOS drives above this region
+ ; shall not be impacted by our
+ ; shifting behaviour
+ db 0 ; pad to a DWORD
+ dw 0 ; pad to a QWORD
MemInt1588 dw 0 ; 1MB-65MB memory amount (1K)
Cylinders dw 0 ; Cylinder count
.totalsize dd 0, 0 ; Filled in by installer
.bytespersec dw SECTORSIZE
.eddtable dw -1, -1 ; Invalid DPTE pointer
+.dpikey dw 0BEDDh ; Device Path Info magic
+.dpilen db 2ch ; DPI len
+.res1 db 0 ; Reserved
+.res2 dw 0 ; Reserved
+.bustype dd 'MEM ' ; Host bus type (4 bytes, space padded)
+.inttype dd 'MEMORY ' ; Interface type (8 bytes, spc. padded)
+.intpath dd 0, 0 ; Interface path
+.devpath dd 0, 0, 0, 0 ; Device path
+.res3 db 0 ; Reserved
+.chksum db 0 ; DPI checksum
+
+%if ELTORITO
+; El Torito CD Specification Packet - mostly filled in by installer
+CD_PKT:
+.size db 13h ; Packet size (19 bytes)
+.type db 0 ; Boot media type (flags)
+.driveno db 0E0h ; INT 13h drive number
+.controller db 0 ; Controller index
+.start dd 0 ; Starting LBA of image
+.devno dw 0 ; Device number
+.user_buf dw 0 ; User buffer segment
+.load_seg dw 0 ; Load segment
+.sect_count dw 0 ; Emulated sectors to load
+.geom1 db 0 ; Cylinders bits 0 thru 7
+.geom2 db 0 ; Sects/track 0 thru 5, cyls 8, 9
+.geom3 db 0 ; Heads
+%endif ; ELTORITO
-%endif
+%endif ; EDD
- ; End patch area
+; End patch area
+
+ alignb 4, db 0
Stack dd 0 ; Saved SS:ESP on invocation
dw 0
SavedAX dw 0 ; AX saved on invocation
+Recursive dw 0 ; Recursion counter
alignb 4, db 0 ; We *MUST* end on a dword boundary