diff -Naur v51_src/i386/boot0/Makefile boot-132_dfe_r146/i386/boot0/Makefile --- v51_src/i386/boot0/Makefile 2008-10-02 03:46:06.000000000 +0200 +++ boot-132_dfe_r146/i386/boot0/Makefile 2007-06-27 17:51:09.000000000 +0200 @@ -2,17 +2,16 @@ DIR = boot0 include ../MakePaths.dir -#NASM = $(SYMROOT)/nasm -NASM = nasm +NASM = $(SYMROOT)/nasm INSTALLDIR = $(DSTROOT)/usr/standalone/i386 DIRS_NEEDED = $(SYMROOT) all: $(DIRS_NEEDED) boot0 chain0 -boot0: boot0.s Makefile +boot0: boot0.s Makefile $(NASM) $(NASM) boot0.s -o $(SYMROOT)/$@ -chain0: chain0.s Makefile +chain0: chain0.s Makefile $(NASM) $(NASM) chain0.s -o $(SYMROOT)/$@ install_i386:: all $(INSTALLDIR) diff -Naur v51_src/i386/boot0/boot0.s boot-132_dfe_r146/i386/boot0/boot0.s --- v51_src/i386/boot0/boot0.s 2008-10-02 03:46:06.000000000 +0200 +++ boot-132_dfe_r146/i386/boot0/boot0.s 2007-06-27 17:51:09.000000000 +0200 @@ -39,11 +39,6 @@ ; This code is written for the NASM assembler. ; nasm boot0.s -o boot0 -; -; This version of boot0 implements hybrid GUID/MBR partition scheme support -; -; Written by Tams Kosrszky on 2008-03-10 -; ; ; Set to 1 to enable obscure debug messages. @@ -51,9 +46,12 @@ DEBUG EQU 0 ; -; Set to 1 to enable verbose mode +; Set to 1 to support loading the partition booter (boot1) from a +; logical partition. ; -VERBOSE EQU 1 +EXT_PART_SUPPORT EQU 1 + +CHS_SUPPORT EQU 1 ; ; Various constants. @@ -64,38 +62,22 @@ kBoot0RelocAddr EQU 0xE000 ; boot0 relocated address kMBRBuffer EQU 0x1000 ; MBR buffer address -kLBA1Buffer EQU 0x1200 ; LBA1 - GPT Partition Table Header buffer address -kGPTABuffer EQU 0x1400 ; GUID Partition Entry Array buffer address +kExtBuffer EQU 0x1200 ; EXT boot block buffer address kPartTableOffset EQU 0x1be kMBRPartTable EQU kMBRBuffer + kPartTableOffset +kExtPartTable EQU kExtBuffer + kPartTableOffset kSectorBytes EQU 512 ; sector size in bytes kBootSignature EQU 0xAA55 ; boot sector signature -kGPTSignatureLow EQU 'EFI ' ; GUID Partition Table Header Signature -kGPTSignatureHigh EQU 'PART' -kGUIDLastDwordOffs EQU 12 ; last 4 byte offset of a GUID kPartCount EQU 4 ; number of paritions per table -kPartTypeHFS EQU 0xaf ; HFS+ Filesystem type -kPartTypePMBR EQU 0xee ; On all GUID Partition Table disks a Protective MBR (PMBR) - ; in LBA 0 (that is, the first block) precedes the - ; GUID Partition Table Header to maintain compatibility - ; with existing tools that do not understand GPT partition structures. - ; The Protective MBR has the same format as a legacy MBR - ; and contains one partition entry with an OSType set to 0xEE - ; reserving the entire space used on the disk by the GPT partitions, - ; including all headers. - -kPartActive EQU 0x80 ; active flag enabled -kPartInactive EQU 0x00 ; active flag disabled -kHFSGUID EQU 0x48465300 ; first 4 bytes of Apple HFS Partition Type GUID. -kAppleGUID EQU 0xACEC4365 ; last 4 bytes of Apple type GUIDs. -kEFISYSGUID EQU 0xC93EC93B ; first 4 bytes of EFI System Partition Type GUID. - - -; efi system C12A7328-F81F-11D2-BA4B-00A0C93EC93B +kPartTypeBoot EQU 0xab ; boot2 partition type +kPartTypeExtDOS EQU 0x05 ; DOS extended partition type +kPartTypeExtWin EQU 0x0f ; Windows extended partition type +kPartTypeExtLinux EQU 0x85 ; Linux extended partition type +kPartActive EQU 0x80 %ifdef FLOPPY kDriveNumber EQU 0x00 @@ -110,51 +92,19 @@ ; giving the size of the structure. ; struc part -.bootid resb 1 ; bootable or not -.head resb 1 ; starting head, sector, cylinder -.sect resb 1 ; -.cyl resb 1 ; -.type resb 1 ; partition type +.bootid: resb 1 ; bootable or not +.head: resb 1 ; starting head, sector, cylinder +.sect: resb 1 ; +.cyl: resb 1 ; +.type: resb 1 ; partition type .endhead resb 1 ; ending head, sector, cylinder -.endsect resb 1 ; -.endcyl resb 1 ; -.lba resd 1 ; starting lba +.endsect: resb 1 ; +.endcyl: resb 1 ; +.lba: resd 1 ; starting lba .sectors resd 1 ; size in sectors endstruc ; -; Format of GPT Partition Table Header -; - struc gpth -.Signature resb 8 -.Revision resb 4 -.HeaderSize resb 4 -.HeaderCRC32 resb 4 -.Reserved resb 4 -.MyLBA resb 8 -.AlternateLBA resb 8 -.FirstUsableLBA resb 8 -.LastUsableLBA resb 8 -.DiskGUID resb 16 -.PartitionEntryLBA resb 8 -.NumberOfPartitionEntries resb 4 -.SizeOfPartitionEntry resb 4 -.PartitionEntryArrayCRC32 resb 4 - endstruc - -; -; Format of GUID Partition Entry Array -; - struc gpta -.PartitionTypeGUID resb 16 -.UniquePartitionGUID resb 16 -.StartingLBA resb 8 -.EndingLBA resb 8 -.Attributes resb 8 -.PartitionName resb 72 - endstruc - -; ; Macros. ; %macro DebugCharMacro 1 @@ -162,11 +112,6 @@ call print_char %endmacro -%macro LogString 1 - mov di, %1 - call log_string -%endmacro - %if DEBUG %define DebugChar(x) DebugCharMacro x %else @@ -178,12 +123,12 @@ SEGMENT .text - ORG kBoot0RelocAddr - + ORG 0xE000 ; must match kBoot0RelocAddr + ;-------------------------------------------------------------------------- ; Boot code is loaded at 0:7C00h. ; -start: +start ; ; Set up the stack to grow down from kBoot0Segment:kBoot0Stack. ; Interrupts should be off while the stack is being manipulated. @@ -202,14 +147,14 @@ ; mov si, kBoot0LoadAddr ; si <- source mov di, kBoot0RelocAddr ; di <- destination + ; cld ; auto-increment SI and/or DI registers mov cx, kSectorBytes/2 ; copy 256 words repnz movsw ; repeat string move (word) operation - ; ; Code relocated, jump to start_reloc in relocated location. ; - jmp kBoot0Segment:start_reloc + jmp 0:start_reloc ;-------------------------------------------------------------------------- ; Start execution from the relocated location. @@ -218,290 +163,265 @@ DebugChar('>') +.loop: + %if DEBUG mov al, dl call print_hex %endif ; - ; Since this code may not always reside in the MBR, always start by - ; loading the MBR to kMBRBuffer and LBA1 to kGPTBuffer. + ; Clear various flags in memory. ; - xor eax, eax - mov [my_lba], eax ; store LBA sector 0 for read_lba function - mov al, 2 ; load two sectors: MBR and LBA1 + mov [first_part], eax ; clear EBIOS LBA offset + mov [this_part], eax + +%if CHS_SUPPORT + mov [ebios_present], al ; clear EBIOS support flag + + ; + ; Check if EBIOS is supported for this hard drive. + ; + mov ah, 0x41 ; Function 0x41 + mov bx, 0x55AA ; check signature + int 0x13 + + ; + ; If successful, the return values are as follows: + ; + ; carry = 0 + ; ah = major version of EBIOS extensions (0x21 = version 1.1) + ; al = altered + ; bx = 0xAA55 + ; cx = support bits. bit 0 must be set for function 0x42. + ; + jc .ebios_check_done + cmp bx, 0xAA55 ; check BX = 0xAA55 + jnz .ebios_check_done + test cl, 0x01 ; check enhanced drive read support + setnz [ebios_present] ; EBIOS supported, set flag + DebugChar('E') ; EBIOS supported +.ebios_check_done: +%else + inc al + mov [ebios_present], al +%endif + + ; + ; Since this code may not always reside in the MBR, always start by + ; loading the MBR to kMBRBuffer. + ; + mov al, 1 ; load one sector + xor bx, bx + mov es, bx ; MBR load segment = 0 mov bx, kMBRBuffer ; MBR load address + mov si, bx ; pointer to fake partition entry +%if CHS_SUPPORT + mov WORD [si], 0x0000 ; CHS DX: head = 0 + mov WORD [si + 2], 0x0001 ; CHS CX: cylinder = 0, sector = 1 +%endif + mov DWORD [si + part.lba], 0x00000000 ; LBA sector 0 + call load - jc error ; MBR load error + jc .next_drive ; MBR load error ; ; Look for the booter partition in the MBR partition table, ; which is at offset kMBRPartTable. ; - mov si, kMBRPartTable ; pointer to partition table + mov di, kMBRPartTable ; pointer to partition table call find_boot ; will not return on success +.next_drive: + inc dl ; next drive number + test dl, 0x4 ; went through all 4 drives? + jz .loop ; not yet, loop again + error: - LogString(boot_error_str) + mov si, boot_error_str + call print_string hang: hlt - jmp hang - + jmp SHORT hang ;-------------------------------------------------------------------------- ; Find the active (boot) partition and load the booter from the partition. ; ; Arguments: ; DL = drive number (0x80 + unit number) -; SI = pointer to fdisk partition table. +; DI = pointer to fdisk partition table. ; ; Clobber list: ; EAX, BX, EBP ; find_boot: + push cx ; preserve CX and SI + push si ; ; Check for boot block signature 0xAA55 following the 4 partition ; entries. ; - cmp WORD [si + part_size * kPartCount], kBootSignature - jne .exit ; boot signature not found. - - xor bx, bx ; BL will be set to 1 later in case of - ; Protective MBR has been found + cmp WORD [di + part_size * kPartCount], kBootSignature + jne NEAR .exit ; boot signature not found - inc bh ; BH = 1. Giving a chance for a second pass - ; to boot an inactive but boot1h aware HFS+ partition - ; by scanning the MBR partition entries again. - -.start_scan: - mov cx, kPartCount ; number of partition entries per table + mov si, di ; make SI a pointer to partition table + mov cx, kPartCount ; number of partition entries per table .loop: - ; ; First scan through the partition table looking for the active - ; partition. + ; partition. Postpone walking the extended partition chain for + ; the second pass. Do not merge the two without changing the + ; buffering scheme used to store extended partition tables. ; %if DEBUG mov al, [si + part.type] ; print partition type call print_hex %endif - mov eax, [si + part.lba] ; save starting LBA of current - mov [my_lba], eax ; MBR partition entry for read_lba function - cmp BYTE [si + part.type], 0 ; unused partition? - je .continue ; skip to next entry - cmp BYTE [si + part.type], kPartTypePMBR ; check for Protective MBR - jne .testPass - - mov BYTE [si + part.bootid], kPartInactive ; found Protective MBR - ; clear active flag to make sure this protective - ; partition won't be used as a bootable partition. - mov bl, 1 ; Assume we can deal with GPT but try to scan - ; later if not found any other bootable partitions. - -.testPass: - cmp bh, 1 - jne .Pass2 - -.Pass1: - cmp BYTE [si + part.bootid], kPartActive ; In pass 1 we are walking on the standard path - jne .continue ; by trying to hop on the active partition. - jmp .tryToBoot - -.Pass2: - cmp BYTE [si + part.type], kPartTypeHFS ; In pass 2 we're going to find a HFS+ partition - jne .continue ; equipped with boot1h in its boot record - ; regardless if it's active or not. + cmp BYTE [si + part.type], 0 + je .continue + cmp BYTE [si + part.bootid], kPartActive + jne .continue DebugChar('*') + ; fix offset for load + mov eax, [this_part] + mov [first_part], eax + ; ; Found boot partition, read boot sector to memory. ; + mov al, 1 + mov bx, kBoot0Segment + mov es, bx + mov bx, kBoot0LoadAddr + call load ; will not return on success + jc error ; load error, keep looking? -.tryToBoot: - -%if VERBOSE - LogString(mbr_str) -%endif - - call loadBootSector - jne .continue - jmp initBootLoader - -.continue: - add si, part_size ; advance SI to next partition entry - loop .loop ; loop through all partition entries - - ; - ; Scanned all partitions but not found any with active flag enabled - ; Anyway if we found a protective MBR before we still have a chance - ; for a possible GPT Header at LBA 1 - ; - dec bl - jz checkGPT ; found Protective MBR before - - ; - ; Switching to Pass 2 - ; try to find a boot1h aware HFS+ MBR partition - ; - dec bh - mov si, kMBRPartTable ; set SI to first entry of MBR Partition table - jz .start_scan ; scan again - -.exit: - ret ; Giving up. - ; - ; Found Protective MBR Partition Type: 0xEE - ; Check for 'EFI PART' string at the beginning - ; of LBA1 for possible GPT Table Header - ; -checkGPT: - - mov di, kLBA1Buffer ; address of GUID Partition Table Header - cmp DWORD [di], kGPTSignatureLow ; looking for 'EFI ' - jne .exit ; not found. Giving up. - cmp DWORD [di + 4], kGPTSignatureHigh ; looking for 'PART' - jne .exit ; not found. Giving up indeed. - mov si, di - - ; - ; Loading GUID Partition Table Array + ; Fix up absolute block location in partition record. ; - mov eax, [si + gpth.PartitionEntryLBA] ; starting LBA of GPT Array - mov [my_lba], eax ; save starting LBA for read_lba function - mov cx, [si + gpth.NumberOfPartitionEntries] ; number of GUID Partition Array entries - mov bx, [si + gpth.SizeOfPartitionEntry] ; size of GUID Partition Array entry - push bx ; push size of GUID Partition entry - - ; - ; Calculating number of sectors we need to read for loading a GPT Array - ; - push dx ; preserve DX (DL = BIOS drive unit number) - mov ax, cx ; AX * BX = number of entries * size of one entry - mul bx ; AX = total byte size of GPT Array - pop dx ; restore DX - shr ax, 9 ; convert to sectors + mov eax, [si + part.lba] + add eax, [this_part] + mov [si + part.lba], eax + DebugChar('J') ; - ; ... or: - ; Current GPT Arrays uses 128 partition entries each 128 bytes long - ; 128 entries * 128 bytes long GPT Array entries / 512 bytes per sector = 32 sectors + ; Jump to partition booter. The drive number is already in register DL. + ; SI is pointing to the modified partition entry. ; -; mov al, 32 ; maximum sector size of GPT Array (hardcoded method) + jmp kBoot0Segment:kBoot0LoadAddr - mov bx, kGPTABuffer - push bx ; push address of GPT Array - call load ; read GPT Array - pop si ; SI = address of GPT Array - pop bx ; BX = size of GUID Partition Array entry - jc error +.continue: + add si, part_size ; advance SI to next partition entry + loop .loop ; loop through all partition entries +%if EXT_PART_SUPPORT ; - ; Walk through GUID Partition Table Array - ; and load boot record from first available HFS+ partition. - ; - ; If it has boot signature (0xAA55) then jump to it - ; otherwise skip to next partition. + ; No primary (or logical) boot partition found in the current + ; partition table. Restart and look for extended partitions. ; + mov si, di ; make SI a pointer to partition table + mov cx, kPartCount ; number of partition entries per table -%if VERBOSE - LogString(gpt_str) -%endif +.ext_loop: -.gpt_loop: + mov al, [si + part.type] ; AL <- partition type -; mov eax, [si + gpta.PartitionTypeGUID] -; cmp eax, kHFSGUID ; check current GUID Partition for HFS GUID - mov eax, [si + gpta.PartitionTypeGUID + kGUIDLastDwordOffs] + cmp al, kPartTypeExtDOS ; Extended DOS + je .ext_load -; turbo - also try efi system partition -; cmp eax,kEFISYSGUID -; je .gpt_ok + cmp al, kPartTypeExtWin ; Extended Windows(95) + je .ext_load -; cmp eax, kAppleGUID ; check current GUID Partition for Apple's GUID type -; jne .gpt_continue + cmp al, kPartTypeExtLinux ; Extended Linux + je .ext_load -;.gpt_ok +.ext_continue: ; - ; Found HFS Partition + ; Advance si to the next partition entry in the extended + ; partition table. ; + add si, part_size ; advance SI to next partition entry + loop .ext_loop ; loop through all partition entries + jmp .exit ; boot partition not found -%if VERBOSE - LogString(hfs_str) -%endif - - mov eax, [si + gpta.StartingLBA] ; load boot sector from StartingLBA - mov [my_lba], eax - call loadBootSector - jne .gpt_continue ; no boot loader signature - -%if VERBOSE - LogString(bootable_str) -%endif - - mov si, kMBRPartTable ; fake the current GUID Partition - mov [si + part.lba], eax ; as MBR style partition for boot1h - mov BYTE [si + part.type], kPartTypeHFS ; with HFS+ filesystem type (0xAF) - jmp SHORT initBootLoader - -.gpt_continue: - - add si, bx ; advance SI to next partition entry - loop .gpt_loop ; loop through all partition entries +.ext_load: + DebugChar('L') -.exit: - ret ; no more GUID partitions. Giving up. + ; Save current partition offset, since for extended + ; partitions we will overwrite it when loading the new + ; table. + ; + mov ebp, [si + part.lba] + + ; + ; Setup the arguments for the load function call to bring the + ; extended partition table into memory. + ; Remember that SI points to the extended partition entry. + ; + mov al, 1 ; read 1 sector + xor bx, bx + mov es, bx ; es = 0 + mov bx, kExtBuffer ; load extended boot sector + call load + jc .ext_continue ; load error - DebugChar('J') ; - ; Jump to partition booter. The drive number is already in register DL. - ; SI is pointing to the modified partition entry. + ; The LBA address of all extended partitions is relative based + ; on the LBA address of the extended partition in the MBR, or + ; the extended partition at the head of the chain. Thus it is + ; necessary to save the LBA address of the first extended partition. ; -initBootLoader: - -%if VERBOSE - LogString(done_str) -%endif + + DebugChar('+') - jmp kBoot0LoadAddr + add ebp, [first_part] + mov [this_part], ebp + mov eax,[first_part] + or eax, eax + jnz .ext_find_boot + mov [first_part], ebp + +%if DEBUG + DebugChar('=') + mov eax, ebp + call print_hex +%endif -;-------------------------------------------------------------------------- -; loadBS - Load boot sector -; -; Arguments: -; DL = drive number (0x80 + unit number) -; [my_lba] = starting LBA. -; -; Returns: -; ZF = 0 if boot sector hasn't kBootSignature -; 1 if boot sector has kBootSignature -; -loadBootSector: - pusha - - mov al, 1 - mov bx, kBoot0LoadAddr - call load ; will not return on success - jc error ; load error, keep looking? +.ext_find_boot: + + ; + ; Call find_boot recursively to scan through the extended partition + ; table. Load DI with a pointer to the extended table in memory. + ; + mov di, kExtPartTable ; partition table pointer + call find_boot ; recursion... ; - ; Check for boot block signature 0xAA55 + ; Since there is an "unwritten" rule that limits each partition table + ; to have 0 or 1 extended partitions, there is no point in looking for + ; any additional extended partition entries at this point. There is no + ; boot partition linked beyond the extended partition that was loaded + ; above. ; - mov di, bx - cmp WORD [di + kSectorBytes - 2], kBootSignature - popa +%endif ; EXT_PART_SUPPORT +.exit: + ; + ; Boot partition not found. Giving up. + ; + pop si + pop cx ret - ;-------------------------------------------------------------------------- ; load - Load one or more sectors from a partition. ; @@ -509,7 +429,7 @@ ; AL = number of 512-byte sectors to read. ; ES:BX = pointer to where the sectors should be stored. ; DL = drive number (0x80 + unit number) -; [my_lba] = starting LBA. +; SI = pointer to the partition entry. ; ; Returns: ; CF = 0 success @@ -517,6 +437,10 @@ ; load: push cx +%if CHS_SUPPORT + test BYTE [ebios_present], 1 + jz .chs +%endif .ebios: mov cx, 5 ; load retry count @@ -525,10 +449,80 @@ jnc .exit loop .ebios_loop -.exit: +%if CHS_SUPPORT +.chs: + mov cx, 5 ; load retry count +.chs_loop: + call read_chs ; use INT13/F2 + jnc .exit + loop .chs_loop +%endif + +.exit pop cx ret +%if CHS_SUPPORT +;-------------------------------------------------------------------------- +; read_chs - Read sectors from a partition using CHS addressing. +; +; Arguments: +; AL = number of 512-byte sectors to read. +; ES:BX = pointer to where the sectors should be stored. +; DL = drive number (0x80 + unit number) +; SI = pointer to the partition entry. +; +; Returns: +; CF = 0 success +; 1 error +; +read_chs: + pusha ; save all registers + + ; + ; Read the CHS start values from the partition entry. + ; + mov dh, [ si + part.head ] ; drive head + mov cx, [ si + part.sect ] ; drive sector + cylinder + + ; + ; INT13 Func 2 - Read Disk Sectors + ; + ; Arguments: + ; AH = 2 + ; AL = number of sectors to read + ; CH = lowest 8 bits of the 10-bit cylinder number + ; CL = bits 6 & 7: cylinder number bits 8 and 9 + ; bits 0 - 5: starting sector number (1-63) + ; DH = starting head number (0 to 255) + ; DL = drive number (80h + drive unit) + ; es:bx = pointer where to place sectors read from disk + ; + ; Returns: + ; AH = return status (sucess is 0) + ; AL = burst error length if ah=0x11 (ECC corrected) + ; carry = 0 success + ; 1 error + ; + mov ah, 0x02 ; Func 2 + int 0x13 ; INT 13 + jnc .exit + + DebugChar('r') ; indicate INT13/F2 error + + ; + ; Issue a disk reset on error. + ; Should this be changed to Func 0xD to skip the diskette controller + ; reset? + ; + xor ax, ax ; Func 0 + int 0x13 ; INT 13 + stc ; set carry to indicate error + +.exit: + popa + ret +%endif ;-------------------------------------------------------------------------- ; read_lba - Read sectors from a partition using LBA addressing. @@ -537,7 +531,7 @@ ; AL = number of 512-byte sectors to read (valid from 1-127). ; ES:BX = pointer to where the sectors should be stored. ; DL = drive number (0x80 + unit number) -; [my_lba] = starting LBA. +; SI = pointer to the partition entry. ; ; Returns: ; CF = 0 success @@ -552,13 +546,18 @@ ; INT13/F42 (Extended Read Sectors) on the stack. ; -; push DWORD 0 ; offset 12, upper 32-bit LBA + ; push DWORD 0 ; offset 12, upper 32-bit LBA push ds ; For sake of saving memory, push ds ; push DS register, which is 0. - mov ecx, [my_lba] ; offset 8, lower 32-bit LBA + + mov ecx, [first_part] ; offset 8, lower 32-bit LBA + add ecx, [si + part.lba] push ecx + push es ; offset 6, memory segment + push bx ; offset 4, memory offset + xor ah, ah ; offset 3, must be 0 push ax ; offset 2, number of sectors @@ -608,31 +607,6 @@ popa ret - -;-------------------------------------------------------------------------- -; Write a string with 'boot0: ' prefix to the console. -; -; Arguments: -; ES:DI pointer to a NULL terminated string. -; -; Clobber list: -; DI -; -log_string: - pusha - - push di - mov si, log_title_str - call print_string - - pop si - call print_string - - popa - - ret - - ;-------------------------------------------------------------------------- ; Write a string to the console. ; @@ -642,29 +616,27 @@ ; Clobber list: ; AX, BX, SI ; -print_string: +print_string mov bx, 1 ; BH=0, BL=1 (blue) cld ; increment SI after each lodsb call -.loop: +.loop lodsb ; load a byte from DS:SI into AL cmp al, 0 ; Is it a NULL? je .exit ; yes, all done mov ah, 0xE ; INT10 Func 0xE int 0x10 ; display byte in tty mode jmp short .loop -.exit: +.exit ret -%if DEBUG - ;-------------------------------------------------------------------------- ; Write a ASCII character to the console. ; ; Arguments: ; AL = ASCII character. ; -print_char: +print_char pusha mov bx, 1 ; BH=0, BL=1 (blue) mov ah, 0x0e ; bios INT 10, Function 0xE @@ -672,7 +644,8 @@ popa ret - +%if DEBUG + ;-------------------------------------------------------------------------- ; Write the 4-byte value to the console in hex. ; @@ -683,7 +656,7 @@ pushad mov cx, WORD 4 bswap eax -.loop: +.loop push ax ror al, 4 call print_nibble ; display upper nibble @@ -696,7 +669,6 @@ call print_char mov al, 13 call print_char - popad ret @@ -722,16 +694,7 @@ ;-------------------------------------------------------------------------- ; NULL terminated strings. ; -log_title_str db 10, 13, 'boot0: ', 0 -boot_error_str db 'error', 0 - -%if VERBOSE -gpt_str db 'GPT', 0 -mbr_str db 'MBR', 0 -hfs_str db 'HFS+', 0 -bootable_str db 'booting', 0 -done_str db 'done', 0 -%endif +boot_error_str db 10, 13, 'b0 error', 0 ;-------------------------------------------------------------------------- ; Pad the rest of the 512 byte sized booter with zeroes. The last @@ -740,12 +703,8 @@ ; If the booter code becomes too large, then nasm will complain ; that the 'times' argument is negative. -; -; According to EFI specification, maximum boot code size is 440 bytes -; - -pad_boot: - times 440-($-$$) db 0 +pad_boot + times 446-($-$$) db 0 %ifdef FLOPPY ;-------------------------------------------------------------------------- @@ -768,7 +727,7 @@ part2numsect dd 0x000015fe ; 2.88MB - 65K %endif -pad_table_and_sig: +pad_table_and_sig times 510-($-$$) db 0 dw kBootSignature @@ -778,6 +737,8 @@ ; ; In memory variables. ; -my_lba resd 1 ; Starting LBA for read_lba function - -; END +first_part resd 1 ; starting LBA of the intial extended partition. +this_part resd 1 ; starting LBA of the current extended partition. +ebios_present resb 1 ; 1 if EBIOS is supported, 0 otherwise. + + END diff -Naur v51_src/i386/boot2/boot.c boot-132_dfe_r146/i386/boot2/boot.c --- v51_src/i386/boot2/boot.c 2008-10-02 03:46:06.000000000 +0200 +++ boot-132_dfe_r146/i386/boot2/boot.c 2008-06-28 21:53:02.000000000 +0200 @@ -65,7 +65,6 @@ char gRootDevice[512]; char gMKextName[512]; BVRef gBootVolume; -extern BVRef gBIOSBootVolume; // turbo - original partition static void selectBiosDevice(void); @@ -224,29 +223,6 @@ // PCI_Bus_Init( &bootInfo->pciInfo ); } -#define BooterKextDir "/System/Booter/" - -static long turbo_preLoadDrivers(LoadDriverMKext_t LoadDriverMKext_p, FileLoadDrivers_t FileLoadDrivers_p) { - char dirspec[1024]; // nasty hack because FileLoadDrivers will overwrite our string!! - - verbose("turbo_LoadExtraDrivers active\n"); - - // Search for Extensions in BooterKextDir on our original BOOT volume - if (gBIOSBootVolume) { - //setRootVolume(gBIOSBootVolume); - sprintf(dirspec,"bt(0,0)%s",BooterKextDir); - verbose("%s: Scanning BIOS Boot (%s)\n",__FUNCTION__,dirspec); - if (FileLoadDrivers_p(dirspec,0)==0) verbose("%s: Loaded from BIOS Boot!\n", __FUNCTION__); - } - - // Search the same path on our chosen root - strcpy(dirspec,BooterKextDir); // required because it will overwrite our (const) string! - verbose("%s: Scanning selected Boot (%s)\n",__FUNCTION__,dirspec); - if (FileLoadDrivers_p(dirspec,0)==0) verbose("%s: Loaded from selected Boot!\n", __FUNCTION__); - - return(0); -} - /*! This is the entrypoint from real-mode which functions exactly as it did before. Multiboot does its own runtime initialization, does some of its own things, and then @@ -324,14 +300,8 @@ // Record default boot device. gBootVolume = selectBootVolume(bvChain); - - // turbo - Save the ORIGINAL boot volume too for loading our mkext - if (!gBIOSBootVolume) gBIOSBootVolume = gBootVolume; - // turbo - hook our driver preload routine - LoadExtraDrivers_p=&turbo_preLoadDrivers; - setRootVolume(gBootVolume); - + // Load default config file from boot device. status = loadSystemConfig(0, 0); diff -Naur v51_src/i386/boot2/boot.h boot-132_dfe_r146/i386/boot2/boot.h --- v51_src/i386/boot2/boot.h 2008-10-02 03:46:06.000000000 +0200 +++ boot-132_dfe_r146/i386/boot2/boot.h 2008-06-28 21:48:57.000000000 +0200 @@ -130,15 +130,11 @@ extern long DecodeKernel(void *binary, entry_t *rentry, char **raddr, int *rsize); typedef long (*FileLoadDrivers_t)(char *dirSpec, long plugin); -typedef long (*LoadDriverMKext_t)(char *fileSpec); - /*! Hookable function pointer called during the driver loading phase that allows other code to cause additional drivers to be loaded. */ -// turbo - allow extra mkext also -//extern long (*LoadExtraDrivers_p)(FileLoadDrivers_t FileLoadDrivers_p); -extern long (*LoadExtraDrivers_p)(LoadDriverMKext_t LoadDriverMKext_p, FileLoadDrivers_t FileLoadDrivers_p); +extern long (*LoadExtraDrivers_p)(FileLoadDrivers_t FileLoadDrivers_p); /* * options.c diff -Naur v51_src/i386/boot2/drivers.c boot-132_dfe_r146/i386/boot2/drivers.c --- v51_src/i386/boot2/drivers.c 2008-10-02 03:46:06.000000000 +0200 +++ boot-132_dfe_r146/i386/boot2/drivers.c 2008-06-27 06:20:27.000000000 +0200 @@ -76,7 +76,7 @@ kCFBundleType3 }; -long (*LoadExtraDrivers_p)(LoadDriverMKext_t LoadDriverMKext_p, FileLoadDrivers_t FileLoadDrivers_p); +long (*LoadExtraDrivers_p)(FileLoadDrivers_t FileLoadDrivers_p); static unsigned long Alder32( unsigned char * buffer, long length ); @@ -162,7 +162,7 @@ // Load extra drivers if a hook has been installed. if (LoadExtraDrivers_p != NULL) { - long ret = (*LoadExtraDrivers_p)(&LoadDriverMKext,&FileLoadDrivers); // turbo - support directly loading an mkext also + long ret = (*LoadExtraDrivers_p)(&FileLoadDrivers); if(ret != 0) return ret; } @@ -183,12 +183,10 @@ if ( LoadDriverMKext(gMKextName) != 0 ) { error("Could not load %s\n", gMKextName); - // turbo - not fatal - //return -1; + return -1; } } -// turbo - load both mkexts! -// else + else { strcpy(gExtensionsSpec, dirSpec); strcat(gExtensionsSpec, "System/Library/"); @@ -478,8 +476,8 @@ sprintf(gFileSpec, "%s%s", module->driverPath, fileName); length = LoadThinFatFile(gFileSpec, &driverModuleAddr); //length = LoadFile(gFileSpec); - driverModuleAddr = (void *)driverModuleAddr; - printf("%s length = %d addr = 0x%x\n", gFileSpec, length, driverModuleAddr); //getc(); + //driverModuleAddr = (void *)kLoadAddr; + //printf("%s length = %d addr = 0x%x\n", gFileSpec, length, driverModuleAddr); getc(); } else length = 0; diff -Naur v51_src/i386/boot2/mboot.c boot-132_dfe_r146/i386/boot2/mboot.c --- v51_src/i386/boot2/mboot.c 2008-10-02 03:46:06.000000000 +0200 +++ boot-132_dfe_r146/i386/boot2/mboot.c 2008-06-29 05:40:52.000000000 +0200 @@ -45,7 +45,7 @@ unsigned int byteoff, unsigned int byteCount, void * buffer ); static int multiboot_get_ramdisk_info(int biosdev, struct driveInfo *dip); -static long multiboot_LoadExtraDrivers(LoadDriverMKext_t LoadDriverMKext_p, FileLoadDrivers_t FileLoadDrivers_p); +static long multiboot_LoadExtraDrivers(FileLoadDrivers_t FileLoadDrivers_p); // Starts off in the multiboot context 1 MB high but eventually gets into low memory // and winds up with a bootdevice in eax which is all that boot() wants @@ -443,7 +443,7 @@ return 0; } -static long multiboot_LoadExtraDrivers(LoadDriverMKext_t LoadDriverMKext_p, FileLoadDrivers_t FileLoadDrivers_p) +static long multiboot_LoadExtraDrivers(FileLoadDrivers_t FileLoadDrivers_p) { char extensionsSpec[1024]; int ramdiskUnit; diff -Naur v51_src/i386/libsaio/biosfn.c boot-132_dfe_r146/i386/libsaio/biosfn.c --- v51_src/i386/libsaio/biosfn.c 2008-10-06 02:54:40.000000000 +0200 +++ boot-132_dfe_r146/i386/libsaio/biosfn.c 2008-06-29 05:51:25.000000000 +0200 @@ -327,42 +327,42 @@ return bb.eax.r.h; } -//int ebioswrite(int dev, long sec, int count) -//{ -// int i; -// static struct { -// unsigned char size; -// unsigned char reserved; -// unsigned char numblocks; -// unsigned char reserved2; -// unsigned short bufferOffset; -// unsigned short bufferSegment; -// unsigned long long startblock; -// } addrpacket __attribute__((aligned(16))) = {0}; -// addrpacket.size = sizeof(addrpacket); -// -// for (i=0;;) { -// bb.intno = 0x13; -// bb.eax.r.l = 0; /* Don't verify */ -// bb.eax.r.h = 0x43; -// bb.edx.r.l = dev; -// bb.esi.rr = NORMALIZED_OFFSET((unsigned)&addrpacket); -// bb.ds = NORMALIZED_SEGMENT((unsigned)&addrpacket); -// addrpacket.reserved = addrpacket.reserved2 = 0; -// addrpacket.numblocks = count; -// addrpacket.bufferOffset = OFFSET(ptov(BIOS_ADDR)); -// addrpacket.bufferSegment = SEGMENT(ptov(BIOS_ADDR)); -// addrpacket.startblock = sec; -// bios(&bb); -// if ((bb.eax.r.h == 0x00) || (i++ >= 5)) -// break; -// -// /* reset disk subsystem and try again */ -// bb.eax.r.h = 0x00; -// bios(&bb); -// } -// return bb.eax.r.h; -//} +int ebioswrite(int dev, long sec, int count) +{ + int i; + static struct { + unsigned char size; + unsigned char reserved; + unsigned char numblocks; + unsigned char reserved2; + unsigned short bufferOffset; + unsigned short bufferSegment; + unsigned long long startblock; + } addrpacket __attribute__((aligned(16))) = {0}; + addrpacket.size = sizeof(addrpacket); + + for (i=0;;) { + bb.intno = 0x13; + bb.eax.r.l = 0; /* Don't verify */ + bb.eax.r.h = 0x43; + bb.edx.r.l = dev; + bb.esi.rr = NORMALIZED_OFFSET((unsigned)&addrpacket); + bb.ds = NORMALIZED_SEGMENT((unsigned)&addrpacket); + addrpacket.reserved = addrpacket.reserved2 = 0; + addrpacket.numblocks = count; + addrpacket.bufferOffset = OFFSET(ptov(BIOS_ADDR)); + addrpacket.bufferSegment = SEGMENT(ptov(BIOS_ADDR)); + addrpacket.startblock = sec; + bios(&bb); + if ((bb.eax.r.h == 0x00) || (i++ >= 5)) + break; + + /* reset disk subsystem and try again */ + bb.eax.r.h = 0x00; + bios(&bb); + } + return bb.eax.r.h; +} void putc(int ch) { diff -Naur v51_src/i386/libsaio/disk.c boot-132_dfe_r146/i386/libsaio/disk.c --- v51_src/i386/libsaio/disk.c 2008-10-06 02:53:46.000000000 +0200 +++ boot-132_dfe_r146/i386/libsaio/disk.c 2008-06-26 07:38:02.000000000 +0200 @@ -114,9 +114,6 @@ static struct DiskBVMap * gDiskBVMap = NULL; static struct disk_blk0 * gBootSector = NULL; -// Turbo - save what we think is our original BIOS boot volume if we have one 0xab -BVRef gBIOSBootVolume = NULL; - // Function pointers to be filled in if ramdisks are available: int (*p_ramdiskReadBytes)( int biosdev, unsigned int blkno, unsigned int byteoff, @@ -779,27 +776,7 @@ kBIOSDevTypeHardDrive); break; - // turbo - we want the booter type scanned also - case FDISK_BOOTER: - if (part->bootid & FDISK_ACTIVE) - gBIOSBootVolume = newFDiskBVRef( - biosdev, partno, - part->relsect, - part, - HFSInitPartition, - HFSLoadFile, - HFSReadFile, - HFSGetDirEntry, - HFSGetFileBlock, - HFSGetUUID, - HFSGetDescription, - HFSFree, - 0, - kBIOSDevTypeHardDrive); - break; - -#if 0==1 -//#if UFS_SUPPORT +#if UFS_SUPPORT case FDISK_BOOTER: booterUFS = newFDiskBVRef( biosdev, partno, @@ -1019,13 +996,7 @@ // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // HFS+ GUID in LE form -EFI_GUID const GPT_HFS_GUID = { 0x48465300, 0x0000, 0x11AA, { 0xAA, 0x11, 0x00, 0x30, 0x65, 0x43, 0xEC, 0xAC } }; -// turbo - also our booter partition -EFI_GUID const GPT_BOOT_GUID = { 0x426F6F74, 0x0000, 0x11AA, { 0xAA, 0x11, 0x00, 0x30, 0x65, 0x43, 0xEC, 0xAC } }; -// turbo - or an efi system partition -EFI_GUID const GPT_EFISYS_GUID = { 0xC12A7328, 0xF81F, 0x11D2, { 0xBA, 0x4B, 0x00, 0xA0, 0xC9, 0x3E, 0xC9, 0x3B } }; - -//C12A7328-F81F-11D2-BA4B-00A0C93EC93B +EFI_GUID const GPT_HFS_GUID = { 0x48465300, 0x0000, 0x11AA, { 0xAA, 0x11, 0x00, 0x30, 0x65, 0x43, 0xEC, 0xAC } }; static BVRef diskScanGPTBootVolumes( int biosdev, int * countPtr ) { @@ -1173,25 +1144,7 @@ map->bvr = bvr; ++map->bvrcnt; } - - // turbo - save our booter partition - if ( (efi_guid_compare(&GPT_BOOT_GUID, (EFI_GUID const*)gptMap->ent_type) == 0) || - (efi_guid_compare(&GPT_EFISYS_GUID, (EFI_GUID const*)gptMap->ent_type) == 0) ) { - gBIOSBootVolume = newGPTBVRef( - biosdev, gptID, - gptMap->ent_lba_start, - gptMap, - HFSInitPartition, - HFSLoadFile, - HFSReadFile, - HFSGetDirEntry, - HFSGetFileBlock, - HFSGetUUID, - HFSGetDescription, - HFSFree, - 0, - kBIOSDevTypeHardDrive); - } + } } @@ -1487,41 +1440,41 @@ return 0; } -//int rawDiskWrite( BVRef bvr, unsigned int secno, void *buffer, unsigned int len ) -//{ -// int secs; -// unsigned char *cbuf = (unsigned char *)buffer; -// unsigned int copy_len; -// int rc; -// -// if ((len & (BPS-1)) != 0) { -// error("raw disk write not sector aligned"); -// return -1; -// } -// secno += bvr->part_boff; -// -// cache_valid = FALSE; -// -// while (len > 0) { -// secs = len / BPS; -// if (secs > N_CACHE_SECS) secs = N_CACHE_SECS; -// copy_len = secs * BPS; -// -// bcopy( cbuf, trackbuf, copy_len ); -// //printf("rdr: ebioswrite(%d, %d, %d)\n", bvr->biosdev, secno, secs); -// if ((rc = ebioswrite(bvr->biosdev, secno, secs)) != 0) { -// error(" EBIOS write error: %s\n", bios_error(rc), rc); -// error(" Block %d Sectors %d\n", secno, secs); -// return rc; -// } -// len -= copy_len; -// cbuf += copy_len; -// secno += secs; -// spinActivityIndicator(); -// } -// -// return 0; -//} +int rawDiskWrite( BVRef bvr, unsigned int secno, void *buffer, unsigned int len ) +{ + int secs; + unsigned char *cbuf = (unsigned char *)buffer; + unsigned int copy_len; + int rc; + + if ((len & (BPS-1)) != 0) { + error("raw disk write not sector aligned"); + return -1; + } + secno += bvr->part_boff; + + cache_valid = FALSE; + + while (len > 0) { + secs = len / BPS; + if (secs > N_CACHE_SECS) secs = N_CACHE_SECS; + copy_len = secs * BPS; + + bcopy( cbuf, trackbuf, copy_len ); + //printf("rdr: ebioswrite(%d, %d, %d)\n", bvr->biosdev, secno, secs); + if ((rc = ebioswrite(bvr->biosdev, secno, secs)) != 0) { + error(" EBIOS write error: %s\n", bios_error(rc), rc); + error(" Block %d Sectors %d\n", secno, secs); + return rc; + } + len -= copy_len; + cbuf += copy_len; + secno += secs; + spinActivityIndicator(); + } + + return 0; +} int diskIsCDROM(BVRef bvr) diff -Naur v51_src/i386/libsaio/fake_efi.c boot-132_dfe_r146/i386/libsaio/fake_efi.c --- v51_src/i386/libsaio/fake_efi.c 2008-10-09 02:07:46.000000000 +0200 +++ boot-132_dfe_r146/i386/libsaio/fake_efi.c 2008-05-25 06:52:31.000000000 +0200 @@ -251,54 +251,19 @@ #define Tera (kilo * Giga) #define Peta (kilo * Tera) -#define bit(n) (1UL << (n)) -#define bitmask(h,l) ((bit(h)|(bit(h)-1)) & ~(bit(l)-1)) -#define bitfield(x,h,l) (((x) & bitmask(h,l)) >> l) - -#define TICKS 59659 /* Program counter to 50 ms = 59659 clks */ -#define IA32_PERF_STATUS 0x198 -#define K8_FIDVID_STATUS 0xC0010042 -#define K10_COFVID_STATUS 0xC0010071 - -#define DEFAULT_FSB 100000 /* for now, hardcoding 100MHz for old CPUs */ - -#define DEBUG_FSB 0 -#if DEBUG_FSB -#define DBG(x...) printf(x) -#else -#define DBG(x...) -#endif - -uint64_t fsbFrequency; -uint16_t div = 0; // Non-Integer Bus Ratio -/* This should be const but DT__AddProperty takes char* */ -static char FSB_Frequency_prop[] = "FSBFrequency"; - - +/*========================================================================== + * FSB Frequency detection + */ +// DFE: rdtsc64 from xnu (obvious implementation) static inline uint64_t rdtsc64(void) { - uint64_t ret; - __asm__ volatile("rdtsc" : "=A" (ret)); - return ret; -} - -static inline uint64_t rdmsr64(uint32_t msr) -{ uint64_t ret; - __asm__ volatile("rdmsr" : "=A" (ret) : "c" (msr)); + __asm__ volatile("rdtsc" : "=A" (ret)); return ret; } -static inline void do_cpuid(uint32_t selector, uint32_t *data) -{ - asm volatile ("cpuid" - : "=a" (data[0]), - "=b" (data[1]), - "=c" (data[2]), - "=d" (data[3]) - : "a" (selector) - ); -} +// DFE: enable_PIT2 and disable_PIT2 come from older xnu + /* * Enable or disable timer 2. * Port 0x61 controls timer 2: @@ -308,72 +273,26 @@ inline static void enable_PIT2(void) { - asm volatile( - " inb $0x61,%%al \n\t" - " and $0xFC,%%al \n\t" - " or $1,%%al \n\t" - " outb %%al,$0x61 \n\t" + /* Enable gate, disable speaker */ + __asm__ volatile( + " inb $0x61,%%al \n\t" + " and $0xFC,%%al \n\t" /* & ~0x03 */ + " or $1,%%al \n\t" + " outb %%al,$0x61 \n\t" : : : "%al" ); } inline static void disable_PIT2(void) { - asm volatile( - " inb $0x61,%%al \n\t" - " and $0xFC,%%al \n\t" - " outb %%al,$0x61 \n\t" + /* Disable gate and output to speaker */ + __asm__ volatile( + " inb $0x61,%%al \n\t" + " and $0xFC,%%al \n\t" /* & ~0x03 */ + " outb %%al,$0x61 \n\t" : : : "%al" ); } -inline static void -set_PIT2(int value) -{ -/* - * First, tell the clock we are going to write 16 bits to the counter - * and enable one-shot mode (command 0xB8 to port 0x43) - * Then write the two bytes into the PIT2 clock register (port 0x42). - * Loop until the value is "realized" in the clock, - * this happens on the next tick. - */ - asm volatile( - " movb $0xB8,%%al \n\t" - " outb %%al,$0x43 \n\t" - " movb %%dl,%%al \n\t" - " outb %%al,$0x42 \n\t" - " movb %%dh,%%al \n\t" - " outb %%al,$0x42 \n" -"1: inb $0x42,%%al \n\t" - " inb $0x42,%%al \n\t" - " cmp %%al,%%dh \n\t" - " jne 1b" - : : "d"(value) : "%al"); -} - -inline static uint64_t -get_PIT2(unsigned int *value) -{ - register uint64_t result; -/* - * This routine first latches the time (command 0x80 to port 0x43), - * then gets the time stamp so we know how long the read will take later. - * Read (from port 0x42) and return the current value of the timer. - */ - asm volatile( - " xorl %%ecx,%%ecx \n\t" - " movb $0x80,%%al \n\t" - " outb %%al,$0x43 \n\t" - " rdtsc \n\t" - " pushl %%eax \n\t" - " inb $0x42,%%al \n\t" - " movb %%al,%%cl \n\t" - " inb $0x42,%%al \n\t" - " movb %%al,%%ch \n\t" - " popl %%eax " - : "=A"(result), "=c"(*value)); - return result; -} - // DFE: set_PIT2_mode0, poll_PIT2_gate, and measure_tsc_frequency are // roughly based on Linux code @@ -481,150 +400,96 @@ return retval; } -/* - * timeRDTSC() (from an old version of xnu) - * This routine sets up PIT counter 2 to count down 1/20 of a second. - * It pauses until the value is latched in the counter - * and then reads the time stamp counter to return to the caller. - */ -static uint64_t -timeRDTSC(void) +static inline uint64_t rdmsr64(uint32_t msr) { - int attempts = 0; - uint64_t latchTime; - uint64_t saveTime,intermediate; - unsigned int timerValue, lastValue; - - /* - * Table of correction factors to account for - * - timer counter quantization errors, and - * - undercounts 0..5 - */ -#define CLKNUM 1193182 /* formerly 1193167 */ -#define SAMPLE_CLKS_EXACT (((double) CLKNUM) / 20.0) -#define SAMPLE_CLKS_INT ((int) CLKNUM / 20) -#define SAMPLE_NSECS (2000000000LL) -#define SAMPLE_MULTIPLIER (((double)SAMPLE_NSECS)*SAMPLE_CLKS_EXACT) -#define ROUND64(x) ((uint64_t)((x) + 0.5)) - uint64_t scale[6] = { - ROUND64(SAMPLE_MULTIPLIER/(double)(SAMPLE_CLKS_INT-0)), - ROUND64(SAMPLE_MULTIPLIER/(double)(SAMPLE_CLKS_INT-1)), - ROUND64(SAMPLE_MULTIPLIER/(double)(SAMPLE_CLKS_INT-2)), - ROUND64(SAMPLE_MULTIPLIER/(double)(SAMPLE_CLKS_INT-3)), - ROUND64(SAMPLE_MULTIPLIER/(double)(SAMPLE_CLKS_INT-4)), - ROUND64(SAMPLE_MULTIPLIER/(double)(SAMPLE_CLKS_INT-5)) - }; - - -restart: - if (attempts >= 2) -// printf("calibration failed with %d attempts\n", attempts); - attempts++; - enable_PIT2(); // turn on PIT2 - set_PIT2(0); // reset timer 2 to be zero - latchTime = rdtsc64(); // get the time stamp to time - latchTime = get_PIT2(&timerValue) - latchTime; // time how long this takes - set_PIT2(SAMPLE_CLKS_INT); // set up the timer for (almost) 1/20th a second - saveTime = rdtsc64(); // now time how long a 20th a second is... - get_PIT2(&lastValue); - get_PIT2(&lastValue); // read twice, first value may be unreliable - do { - intermediate = get_PIT2(&timerValue); - if (timerValue > lastValue) { - set_PIT2(0); - disable_PIT2(); - goto restart; - } - lastValue = timerValue; - } while (timerValue > 5); - intermediate -= saveTime; // raw count for about 1/20 second - intermediate *= scale[timerValue]; // rescale measured time spent - intermediate /= SAMPLE_NSECS; // so its exactly 1/20 a second - intermediate += latchTime; // add on our save fudge - - set_PIT2(0); // reset timer 2 to be zero - disable_PIT2(); // turn off PIT 2 - - return intermediate; -} - -static uint64_t getCPUFrequency(void) -{ - uint64_t tsc_freq = 0; - tsc_freq = (timeRDTSC() * 20); -// printf("CPU Frequency = %dMHz \n", (tsc_freq / 1000000)); - return(tsc_freq); -} - -static int getCPUMultiplier(void) -{ - uint32_t cpuid_reg[4]; - uint32_t cpu_vendor; - uint8_t cpu_family; - uint8_t cpu_model; - uint8_t cpu_extfamily; - uint8_t cpu_extmodel; - uint64_t msr; - int coef = 0; - - do_cpuid(0, cpuid_reg); - cpu_vendor = cpuid_reg[1]; - - do_cpuid(1, cpuid_reg); - cpu_model = bitfield(cpuid_reg[0], 7, 4); - cpu_family = bitfield(cpuid_reg[0], 11, 8); - cpu_extmodel = bitfield(cpuid_reg[0], 19, 16); - cpu_extfamily = bitfield(cpuid_reg[0], 27, 20); - - /* Find multiplier (by MSR) */ - - if((cpu_vendor == 0x756E6547 /* Intel */) && ((cpu_family == 0x06) || (cpu_family == 0x0f))) - { - cpu_model += (cpu_extmodel << 4); - if ((cpu_model > 0x0d) || (cpu_model > 0x02)) - { - msr = rdmsr64(IA32_PERF_STATUS); - div = ((msr >> 46) & 1) * 2; - coef = (msr >> 40) & 0x1f; - } - } - else if((cpu_vendor == 0x68747541 /* AMD */) && (cpu_family == 0x0f)) - { - if(cpu_extfamily == 0x00 /* K8 */) - coef = (rdmsr64(K8_FIDVID_STATUS) & 0x3f) / 2 + 4; - else if(cpu_extfamily == 0x01 /* K10 */) - { - msr = rdmsr64(K10_COFVID_STATUS); - coef = (msr & 0x3f) + 0x10; - div = (2 << ((msr >> 6) & 0x07)); - } - } - - DBG("CPU Model: %d - CPU Family: %d - CPU Ext. Family: %d\n", cpu_model, cpu_family, cpu_extfamily); - return coef; -} - -static uint64_t getFSBFrequency(void) -{ - int coef = getCPUMultiplier(); - uint64_t cpu_freq = getCPUFrequency(); - - DBG("CPU Multiplier: %d", coef); - - if (coef && cpu_freq) - if(div) - { - DBG(".%d\n", 100 / div); - return ((cpu_freq * div) / ((coef * div) + 1)); - } - else - { - DBG("\n"); - return (cpu_freq / coef); - } + uint64_t ret; + __asm__ volatile("rdmsr" : "=A" (ret) : "c" (msr)); + return ret; +} + +#define MSR_IA32_PERF_STS 0x198 - return (DEFAULT_FSB * 1000); +#define bit(n) (1ULL << (n)) +#define bitmask(h,l) ((bit(h)|(bit(h)-1)) & ~(bit(l)-1)) +#define bitfield(x,h,l) (((x) & bitmask(h,l)) >> l) + +uint64_t fsbFrequency = 0; + +void determineFsbFrequency() +{ + const char *val; // value + int cnt; // length of value + + if(getValueForKey("fsbmhz", &val, &cnt)) + { + uint32_t fsbmhz; + char valcpy[10]; + bool gotvalue = (cnt < 10); + if(gotvalue) + { + // Force NUL-term by making a copy with strlcpy + strlcpy(valcpy, val, cnt+1); + char *endval; + fsbmhz = strtoul(valcpy, &endval, 10); + gotvalue = (valcpy != endval && *endval == '\0'); + } + if(gotvalue) + { + switch(fsbmhz) + { + case 33: + fsbFrequency = 33333333; + break; + case 66: + fsbFrequency = 66666667; + break; + case 133: + fsbFrequency = 133333333; + break; + case 166: + fsbFrequency = 166666667; + break; + default: + printf("Strange fsbmhz=%d specified.. assuming you mean it literally.\n", fsbmhz); + /* Fall through */ + case 100: + case 200: + fsbFrequency = fsbmhz * Mega; + } + } + else + fsbFrequency = 0; + } + else + fsbFrequency = 0; + if(fsbFrequency != 0) + { + printf("Using specified FSB Frequency %d.%06dMHz\n", (uint32_t)(fsbFrequency/Mega), (uint32_t)(fsbFrequency % Mega)); + sleep(1); + return; + } + printf("Attempting to determine CPU Multiplier. If system reboots, RDMSR 198h causes a fault.\n"); + sleep(1); + uint64_t prfsts = rdmsr64(MSR_IA32_PERF_STS); + uint32_t tscGranularity = bitfield(prfsts, 44, 40); + printf("Determined CPU:FSB multiplier to be %d\n", tscGranularity); + if(tscGranularity == 0) + { + printf("CPU says its multiplier is 0 which makes no sense. The kernel as shipped by\n"); + printf("Apple will not support this and will cause the machine to reboot immediately.\n"); + printf("Press 'y' to continue or use Ctrl+Alt+Delete to reboot\n"); + while(getc() != 'y') + ; + fsbFrequency = 0; + return; + } + printf("Measuring TSC frequency (e.g. CPU speed)\n"); + uint64_t measuredTscFrequency = measure_tsc_frequency(); + printf("CPU runs at %d.%06d MHz\n", (uint32_t)(measuredTscFrequency / Mega), (uint32_t)(measuredTscFrequency % Mega)); + fsbFrequency = measuredTscFrequency / tscGranularity; + printf("BUS must therefore run at %d.%06d MHz\n", (uint32_t)(fsbFrequency / Mega), (uint32_t)(fsbFrequency % Mega)); + sleep(1); } void printFrequencyInfo() @@ -637,6 +502,10 @@ getc(); } +/* This should be const but DT__AddProperty takes char* */ +static char FSB_Frequency_prop[] = "FSBFrequency"; + + /*========================================================================== * SMBIOS */ @@ -799,19 +668,10 @@ char const FIRMWARE_ABI_PROP[] = "firmware-abi"; char const FIRMWARE_VENDOR_PROP[] = "firmware-vendor"; char const FIRMWARE_ABI_PROP_VALUE[] = "EFI32"; -char const DEVICE_PROPERTIES_PROP[] = "device-properties"; void setupEfiDeviceTree(void) { - const char *val; - int cnt; - char hexNibble; - char hexByte[2]; - uint8_t binChar; - uint8_t *binStr; - int hexStrIdx, binStrIdx, hexNibbleIdx; - Node *node; node = DT__FindNode("/", false); if (node == 0) { @@ -827,47 +687,6 @@ DT__AddProperty(node, FIRMWARE_ABI_PROP, sizeof(FIRMWARE_ABI_PROP_VALUE), (char*)FIRMWARE_ABI_PROP_VALUE); DT__AddProperty(node, FIRMWARE_VENDOR_PROP, sizeof(FIRMWARE_VENDOR), (EFI_CHAR16*)FIRMWARE_VENDOR); - /* Add IODeviceTree:/efi/device-properties by decoding - * 'device-properties' value into binary data found in Boot.plist - */ - if (getValueForKey(DEVICE_PROPERTIES_PROP, &val, &cnt) && cnt > 1) - { - // the resulting binary will be the half size of the input hex string - binStr = malloc(cnt / 2); - binStrIdx = 0; - hexNibbleIdx = 0; - for (hexStrIdx = 0; hexStrIdx < cnt; hexStrIdx++) - { - hexNibble = val[hexStrIdx]; - - // ignore all chars except valid hex numbers - if (hexNibble >= '0' && hexNibble <= '9' || hexNibble >= 'A' && hexNibble <= 'F' || hexNibble >= 'a' && hexNibble <= 'f') - { - hexByte[hexNibbleIdx++] = hexNibble; - - // found both two nibbles, convert to binary - if (hexNibbleIdx == 2) - { - binChar = 0; - - for (hexNibbleIdx = 0; hexNibbleIdx < sizeof(hexByte); hexNibbleIdx++) - { - if (hexNibbleIdx > 0) binChar = binChar << 4; - - if (hexByte[hexNibbleIdx] <= '9') binChar += hexByte[hexNibbleIdx] - '0'; - else if (hexByte[hexNibbleIdx] <= 'F') binChar += hexByte[hexNibbleIdx] - ('A' - 10); - else if (hexByte[hexNibbleIdx] <= 'f') binChar += hexByte[hexNibbleIdx] - ('a' - 10); - } - - binStr[binStrIdx++] = binChar; - hexNibbleIdx = 0; - } - } - } - - if (binStrIdx > 0) DT__AddProperty(node, DEVICE_PROPERTIES_PROP, binStrIdx, binStr); - } - /* TODO: Fill in other efi properties if necessary */ /* Set up the /efi/runtime-services table node similar to the way a child node of configuration-table @@ -889,7 +708,6 @@ /* Now fill in the /efi/platform Node */ Node *efiPlatformNode = DT__AddChild(node, "platform"); - fsbFrequency = getFSBFrequency(); if(fsbFrequency != 0) DT__AddProperty(efiPlatformNode, FSB_Frequency_prop, sizeof(uint64_t), &fsbFrequency); /* NOTE WELL: If you do add FSB Frequency detection, make sure to store @@ -912,6 +730,7 @@ /* Entrypoint from boot.c */ void setupFakeEfi(void) { + determineFsbFrequency(); // Initialize the base table setupEfiTables(); // Initialize the device tree diff -Naur v51_src/i386/libsaio/fake_efi.c.OLD.c boot-132_dfe_r146/i386/libsaio/fake_efi.c.OLD.c --- v51_src/i386/libsaio/fake_efi.c.OLD.c 2008-10-02 04:35:34.000000000 +0200 +++ boot-132_dfe_r146/i386/libsaio/fake_efi.c.OLD.c 1970-01-01 01:00:00.000000000 +0100 @@ -1,791 +0,0 @@ -/* - * Copyright 2007 David F. Elliott. All rights reserved. - */ - -#include "libsaio.h" -#include "bootstruct.h" /* for bootArgs */ -#include -#include "fake_efi.h" -#include "efi_tables.h" -#include "SMBIOS.h" - -/* -Modern Darwin kernels require some amount of EFI because Apple machines all -have EFI. Modifying the kernel source to not require EFI is of course -possible but would have to be maintained as a separate patch because it is -unlikely that Apple wishes to add legacy support to their kernel. - -As you can see from the Apple-supplied code in bootstruct.c, it seems that -the intention was clearly to modify this booter to provide EFI-like structures -to the kernel rather than modifying the kernel to handle non-EFI stuff. This -makes a lot of sense from an engineering point of view as it means the kernel -for the as yet unreleased EFI-only Macs could still be booted by the non-EFI -DTK systems so long as the kernel checked to ensure the boot tables were -filled in appropriately. Modern xnu requires a system table and a runtime -services table and performs no checks whatsoever to ensure the pointers to -these tables are non-NULL. Therefore, any modern xnu kernel will page fault -early on in the boot process if the system table pointer is zero. - -Even before that happens, the tsc_init function in modern xnu requires the FSB -Frequency to be a property in the /efi/platform node of the device tree or else -it panics the bootstrap process very early on. - -As of this writing, the current implementation found here is good enough -to make the currently available xnu kernel boot without modification on a -system with an appropriate processor. With a minor source modification to -the tsc_init function to remove the explicit check for Core or Core 2 -processors the kernel can be made to boot on other processors so long as -the code can be executed by the processor and the machine contains the -necessary hardware. -*/ - - -/*========================================================================== - * Utility function to make a device tree string from an EFI_GUID - */ - -static inline char * mallocStringForGuid(EFI_GUID const *pGuid) -{ - char *string = malloc(37); - efi_guid_unparse_upper(pGuid, string); - return string; -} - - -/*========================================================================== - * Fake EFI implementation - */ - -/* Identify ourselves as the EFI firmware vendor */ -static EFI_CHAR16 const FIRMWARE_VENDOR[] = {'D','a','r','w','i','n','_','b','o','o','t', 0}; -static EFI_UINT32 const FIRMWARE_REVISION = 132; /* FIXME: Find a constant for this. */ - -/* Just a ret instruction */ -static uint8_t const VOIDRET_INSTRUCTIONS[] = {0xc3}; -/* movl $0x80000003,%eax; ret */ -static uint8_t const UNSUPPORTEDRET_INSTRUCTIONS[] = {0xb8, 0x03, 0x00, 0x00, 0x80, 0xc3}; - -/* Set up space for up to 10 configuration table entries */ -#define MAX_CONFIGURATION_TABLE_ENTRIES 10 - -/* We use the fake_efi_pages struct so that we only need to do one kernel - * memory allocation for all needed EFI data. Otherwise, small allocations - * like the FIRMWARE_VENDOR string would take up an entire page. - * NOTE WELL: Do NOT assume this struct has any particular layout within itself. - * It is absolutely not intended to be publicly exposed anywhere - * We say pages (plural) although right now we are well within the 1 page size - * and probably will stay that way. - */ -struct fake_efi_pages -{ - EFI_SYSTEM_TABLE efiSystemTable; - EFI_RUNTIME_SERVICES efiRuntimeServices; - EFI_CONFIGURATION_TABLE efiConfigurationTable[MAX_CONFIGURATION_TABLE_ENTRIES]; - EFI_CHAR16 firmwareVendor[sizeof(FIRMWARE_VENDOR)/sizeof(EFI_CHAR16)]; - uint8_t voidret_instructions[sizeof(VOIDRET_INSTRUCTIONS)/sizeof(uint8_t)]; - uint8_t unsupportedret_instructions[sizeof(UNSUPPORTEDRET_INSTRUCTIONS)/sizeof(uint8_t)]; -}; - -EFI_SYSTEM_TABLE *gST = NULL; -Node *gEfiConfigurationTableNode = NULL; - -static EFI_STATUS addConfigurationTable(EFI_GUID const *pGuid, void *table, char const *alias) -{ - EFI_UINTN i = gST->NumberOfTableEntries; - /* We only do adds, not modifications and deletes like InstallConfigurationTable */ - if(i >= MAX_CONFIGURATION_TABLE_ENTRIES) - stop("Ran out of space for configuration tables. Increase the reserved size in the code.\n"); - - if(pGuid == NULL) - return EFI_INVALID_PARAMETER; - - if(table != NULL) - { - gST->ConfigurationTable[i].VendorGuid = *pGuid; - gST->ConfigurationTable[i].VendorTable = table; - - ++gST->NumberOfTableEntries; - - Node *tableNode = DT__AddChild(gEfiConfigurationTableNode, mallocStringForGuid(pGuid)); - /* Use the pointer to the GUID we just stuffed into the system table */ - DT__AddProperty(tableNode, "guid", sizeof(EFI_GUID),&gST->ConfigurationTable[i].VendorGuid); - /* The "table" property is the 32-bit (in our implementation) physical address of the table */ - DT__AddProperty(tableNode, "table", sizeof(void*), &gST->ConfigurationTable[i].VendorTable); - /* Assume the alias pointer is a global or static piece of data */ - if(alias != NULL) - DT__AddProperty(tableNode, "alias", strlen(alias)+1, (char*)alias); - return EFI_SUCCESS; - } - return EFI_UNSUPPORTED; -} - -static inline void fixupEfiSystemTableCRC32(EFI_SYSTEM_TABLE *efiSystemTable) -{ - efiSystemTable->Hdr.CRC32 = 0; - efiSystemTable->Hdr.CRC32 = crc32(0L, efiSystemTable, efiSystemTable->Hdr.HeaderSize); -} - -/* -What we do here is simply allocate a fake EFI system table and a fake EFI -runtime services table. - -Because we build against modern headers with kBootArgsRevision 4 we -also take care to set efiMode = 32. -*/ -void -setupEfiTables(void) -{ - struct fake_efi_pages *fakeEfiPages= (struct fake_efi_pages*)AllocateKernelMemory(sizeof(struct fake_efi_pages)); - - /* Zero out all the tables in case fields are added later */ - bzero(fakeEfiPages, sizeof(struct fake_efi_pages)); - - /* -------------------------------------------------------------------- - * Initialize some machine code that will return EFI_UNSUPPORTED for - * functions returning int and simply return for void functions. - */ - memcpy(fakeEfiPages->voidret_instructions, VOIDRET_INSTRUCTIONS, sizeof(VOIDRET_INSTRUCTIONS)); - memcpy(fakeEfiPages->unsupportedret_instructions, UNSUPPORTEDRET_INSTRUCTIONS, sizeof(UNSUPPORTEDRET_INSTRUCTIONS)); - - /* -------------------------------------------------------------------- */ - /* System table */ - EFI_SYSTEM_TABLE *efiSystemTable = gST = &fakeEfiPages->efiSystemTable; - efiSystemTable->Hdr.Signature = EFI_SYSTEM_TABLE_SIGNATURE; - efiSystemTable->Hdr.Revision = EFI_SYSTEM_TABLE_REVISION; - efiSystemTable->Hdr.HeaderSize = sizeof(EFI_SYSTEM_TABLE); - efiSystemTable->Hdr.CRC32 = 0; /* Initialize to zero and then do CRC32 */ - efiSystemTable->Hdr.Reserved = 0; - - efiSystemTable->FirmwareVendor = fakeEfiPages->firmwareVendor; - memcpy(efiSystemTable->FirmwareVendor, FIRMWARE_VENDOR, sizeof(FIRMWARE_VENDOR)); - efiSystemTable->FirmwareRevision = FIRMWARE_REVISION; - - /* XXX: We may need to have basic implementations of ConIn/ConOut/StdErr */ - /* The EFI spec states that all handles are invalid after boot services have been - * exited so we can probably get by with leaving the handles as zero. */ - efiSystemTable->ConsoleInHandle = 0; - efiSystemTable->ConIn = 0; - - efiSystemTable->ConsoleOutHandle = 0; - efiSystemTable->ConOut = 0; - - efiSystemTable->StandardErrorHandle = 0; - efiSystemTable->StdErr = 0; - - efiSystemTable->RuntimeServices = &fakeEfiPages->efiRuntimeServices; - /* According to the EFI spec, BootServices aren't valid after the - * boot process is exited so we can probably do without it. - * Apple didn't provide a definition for it in pexpert/i386/efi.h - * so I'm guessing they don't use it. - */ - efiSystemTable->BootServices = 0; - - efiSystemTable->NumberOfTableEntries = 0; - efiSystemTable->ConfigurationTable = fakeEfiPages->efiConfigurationTable; - - - /* We're done. Now CRC32 the thing so the kernel will accept it */ - fixupEfiSystemTableCRC32(efiSystemTable); - - /* -------------------------------------------------------------------- */ - /* Runtime services */ - EFI_RUNTIME_SERVICES *efiRuntimeServices = &fakeEfiPages->efiRuntimeServices; - efiRuntimeServices->Hdr.Signature = EFI_RUNTIME_SERVICES_SIGNATURE; - efiRuntimeServices->Hdr.Revision = EFI_RUNTIME_SERVICES_REVISION; - efiRuntimeServices->Hdr.HeaderSize = sizeof(EFI_RUNTIME_SERVICES); - efiRuntimeServices->Hdr.CRC32 = 0; - efiRuntimeServices->Hdr.Reserved = 0; - - /* There are a number of function pointers in the efiRuntimeServices table. - * These are the Foundation (e.g. core) services and are expected to be present on - * all EFI-compliant machines. Some kernel extensions (notably AppleEFIRuntime) - * will call these without checking to see if they are null. - * - * We don't really feel like doing an EFI implementation in the bootloader - * but it is nice if we can at least prevent a complete crash by - * at least providing some sort of implementation until one can be provided - * nicely in a kext. - */ - void (*voidret_fp)() = (void*)fakeEfiPages->voidret_instructions; - void (*unsupportedret_fp)() = (void*)fakeEfiPages->unsupportedret_instructions; - efiRuntimeServices->GetTime = (void*)unsupportedret_fp; - efiRuntimeServices->SetTime = (void*)unsupportedret_fp; - efiRuntimeServices->GetWakeupTime = (void*)unsupportedret_fp; - efiRuntimeServices->SetWakeupTime = (void*)unsupportedret_fp; - efiRuntimeServices->SetVirtualAddressMap = (void*)unsupportedret_fp; - efiRuntimeServices->ConvertPointer = (void*)unsupportedret_fp; - efiRuntimeServices->GetVariable = (void*)unsupportedret_fp; - efiRuntimeServices->GetNextVariableName = (void*)unsupportedret_fp; - efiRuntimeServices->SetVariable = (void*)unsupportedret_fp; - efiRuntimeServices->GetNextHighMonotonicCount = (void*)unsupportedret_fp; - efiRuntimeServices->ResetSystem = (void*)voidret_fp; - - /* We're done. Now CRC32 the thing so the kernel will accept it */ - efiRuntimeServices->Hdr.CRC32 = crc32(0L, efiRuntimeServices, efiRuntimeServices->Hdr.HeaderSize); - - - /* -------------------------------------------------------------------- */ - /* Finish filling in the rest of the boot args that we need. */ - bootArgs->efiSystemTable = (uint32_t)efiSystemTable; - bootArgs->efiMode = kBootArgsEfiMode32; - - /* The bootArgs structure as a whole is bzero'd so we don't need to fill in - * things like efiRuntimeServices* and what not. - * - * In fact, the only code that seems to use that is the hibernate code so it - * knows not to save the pages. It even checks to make sure its nonzero. - */ -} - -/* -In addition to the EFI tables there is also the EFI device tree node. -In particular, we need /efi/platform to have an FSBFrequency key. Without it, -the tsc_init function will panic very early on in kernel startup, before -the console is available. -*/ - -/* Decimal powers: */ -#define kilo (1000ULL) -#define Mega (kilo * kilo) -#define Giga (kilo * Mega) -#define Tera (kilo * Giga) -#define Peta (kilo * Tera) - -/*========================================================================== - * FSB Frequency detection - */ -// DFE: rdtsc64 from xnu (obvious implementation) -static inline uint64_t rdtsc64(void) -{ - uint64_t ret; - __asm__ volatile("rdtsc" : "=A" (ret)); - return ret; -} - -// DFE: enable_PIT2 and disable_PIT2 come from older xnu - -/* - * Enable or disable timer 2. - * Port 0x61 controls timer 2: - * bit 0 gates the clock, - * bit 1 gates output to speaker. - */ -inline static void -enable_PIT2(void) -{ - /* Enable gate, disable speaker */ - __asm__ volatile( - " inb $0x61,%%al \n\t" - " and $0xFC,%%al \n\t" /* & ~0x03 */ - " or $1,%%al \n\t" - " outb %%al,$0x61 \n\t" - : : : "%al" ); -} - -inline static void -disable_PIT2(void) -{ - /* Disable gate and output to speaker */ - __asm__ volatile( - " inb $0x61,%%al \n\t" - " and $0xFC,%%al \n\t" /* & ~0x03 */ - " outb %%al,$0x61 \n\t" - : : : "%al" ); -} - -// DFE: set_PIT2_mode0, poll_PIT2_gate, and measure_tsc_frequency are -// roughly based on Linux code - -/* Set the 8254 channel 2 to mode 0 with the specified value. - In mode 0, the counter will initially set its gate low when the - timer expires. For this to be useful, you ought to set it high - before calling this function. The enable_PIT2 function does this. - */ -static inline void set_PIT2_mode0(uint16_t value) -{ - __asm__ volatile( - " movb $0xB0,%%al \n\t" - " outb %%al,$0x43 \n\t" - " movb %%dl,%%al \n\t" - " outb %%al,$0x42 \n\t" - " movb %%dh,%%al \n\t" - " outb %%al,$0x42" - : : "d"(value) /*: no clobber */ ); -} - -/* Returns the number of times the loop ran before the PIT2 signaled */ -static inline unsigned long poll_PIT2_gate(void) -{ - unsigned long count = 0; - unsigned char nmi_sc_val; - do { - ++count; - __asm__ volatile( - "inb $0x61,%0" - : "=q"(nmi_sc_val) /*:*/ /* no input */ /*:*/ /* no clobber */); - } while( (nmi_sc_val & 0x20) == 0); - return count; -} - -// DFE: This constant comes from older xnu: -#define CLKNUM 1193182 /* formerly 1193167 */ - -// DFE: These two constants come from Linux except CLOCK_TICK_RATE replaced with CLKNUM -#define CALIBRATE_TIME_MSEC 30 /* 30 msecs */ -#define CALIBRATE_LATCH \ - ((CLKNUM * CALIBRATE_TIME_MSEC + 1000/2)/1000) - -/* - * Measures the TSC frequency in Hz (64-bit) using the ACPI PM timer - */ -uint64_t measure_tsc_frequency(void); -uint64_t measure_tsc_frequency(void) -{ - uint64_t tscStart; - uint64_t tscEnd; - uint64_t tscDelta = 0xffffffffffffffffULL; - unsigned long pollCount; - uint64_t retval = 0; - int i; - - /* Time how many TSC ticks elapse in 30 msec using the 8254 PIT - * counter 2. We run this loop 3 times to make sure the cache - * is hot and we take the minimum delta from all of the runs. - * That is to say that we're biased towards measuring the minimum - * number of TSC ticks that occur while waiting for the timer to - * expire. That theoretically helps avoid inconsistencies when - * running under a VM if the TSC is not virtualized and the host - * steals time. The TSC is normally virtualized for VMware. - */ - for(i = 0; i < 3; ++i) - { - enable_PIT2(); - set_PIT2_mode0(CALIBRATE_LATCH); - tscStart = rdtsc64(); - pollCount = poll_PIT2_gate(); - tscEnd = rdtsc64(); - /* The poll loop must have run at least a few times for accuracy */ - if(pollCount <= 1) - continue; - /* The TSC must increment at LEAST once every millisecond. We - * should have waited exactly 30 msec so the TSC delta should - * be >= 30. Anything less and the processor is way too slow. - */ - if((tscEnd - tscStart) <= CALIBRATE_TIME_MSEC) - continue; - // tscDelta = min(tscDelta, (tscEnd - tscStart)) - if( (tscEnd - tscStart) < tscDelta ) - tscDelta = tscEnd - tscStart; - } - /* tscDelta is now the least number of TSC ticks the processor made in - * a timespan of 0.03 s (e.g. 30 milliseconds) - * Linux thus divides by 30 which gives the answer in kiloHertz because - * 1 / ms = kHz. But we're xnu and most of the rest of the code uses - * Hz so we need to convert our milliseconds to seconds. Since we're - * dividing by the milliseconds, we simply multiply by 1000. - */ - - /* Unlike linux, we're not limited to 32-bit, but we do need to take care - * that we're going to multiply by 1000 first so we do need at least some - * arithmetic headroom. For now, 32-bit should be enough. - * Also unlike Linux, our compiler can do 64-bit integer arithmetic. - */ - if(tscDelta > (1ULL<<32)) - retval = 0; - else - { - retval = tscDelta * 1000 / 30; - } - disable_PIT2(); - return retval; -} - -static inline uint64_t rdmsr64(uint32_t msr) -{ - uint64_t ret; - __asm__ volatile("rdmsr" : "=A" (ret) : "c" (msr)); - return ret; -} - -#define MSR_IA32_PERF_STS 0x198 - -#define bit(n) (1ULL << (n)) -#define bitmask(h,l) ((bit(h)|(bit(h)-1)) & ~(bit(l)-1)) -#define bitfield(x,h,l) (((x) & bitmask(h,l)) >> l) - -uint64_t fsbFrequency = 0; - -void determineFsbFrequency() -{ - const char *val; // value - int cnt; // length of value - - if(getValueForKey("fsbmhz", &val, &cnt)) - { - uint32_t fsbmhz; - char valcpy[10]; - bool gotvalue = (cnt < 10); - if(gotvalue) - { - // Force NUL-term by making a copy with strlcpy - strlcpy(valcpy, val, cnt+1); - char *endval; - fsbmhz = strtoul(valcpy, &endval, 10); - gotvalue = (valcpy != endval && *endval == '\0'); - } - if(gotvalue) - { - switch(fsbmhz) - { - case 33: - fsbFrequency = 33333333; - break; - case 66: - fsbFrequency = 66666667; - break; - case 133: - fsbFrequency = 133333333; - break; - case 166: - fsbFrequency = 166666667; - break; - default: - printf("Strange fsbmhz=%d specified.. assuming you mean it literally.\n", fsbmhz); - /* Fall through */ - case 100: - case 200: - fsbFrequency = fsbmhz * Mega; - } - } - else - fsbFrequency = 0; - } - else - fsbFrequency = 0; - - if(fsbFrequency != 0) - { - printf("Using specified FSB Frequency %d.%06dMHz\n", (uint32_t)(fsbFrequency/Mega), (uint32_t)(fsbFrequency % Mega)); - //sleep(1); - return; - } - printf("Attempting to determine CPU Multiplier. If system reboots, RDMSR 198h causes a fault.\n"); - //sleep(1); - uint64_t prfsts = rdmsr64(MSR_IA32_PERF_STS); - uint32_t tscGranularity = bitfield(prfsts, 44, 40); - printf("Determined CPU:FSB multiplier to be %d\n", tscGranularity); - if(tscGranularity == 0) - { - printf("CPU says its multiplier is 0 which makes no sense. The kernel as shipped by\n"); - printf("Apple will not support this and will cause the machine to reboot immediately.\n"); - printf("Press 'y' to continue or use Ctrl+Alt+Delete to reboot\n"); - while(getc() != 'y') - ; - fsbFrequency = 0; - return; - } - printf("Measuring TSC frequency (e.g. CPU speed)\n"); - uint64_t measuredTscFrequency = measure_tsc_frequency(); - printf("CPU runs at %d.%06d MHz\n", (uint32_t)(measuredTscFrequency / Mega), (uint32_t)(measuredTscFrequency % Mega)); - fsbFrequency = measuredTscFrequency / tscGranularity; - printf("BUS must therefore run at %d.%06d MHz\n", (uint32_t)(fsbFrequency / Mega), (uint32_t)(fsbFrequency % Mega)); - //sleep(1); -} - -void printFrequencyInfo() -{ - printf("\n"); - uint64_t measuredTscFrequency = measure_tsc_frequency(); - printf("CPU runs at %d.%06d MHz\n", (uint32_t)(measuredTscFrequency / Mega), (uint32_t)(measuredTscFrequency % Mega)); - printf("\n"); - printf("(Press a key to continue...)"); - getc(); -} - -/* This should be const but DT__AddProperty takes char* */ -static char FSB_Frequency_prop[] = "FSBFrequency"; - - -/*========================================================================== - * SMBIOS - */ - -/* From Foundation/Efi/Guid/Smbios/SmBios.h */ -/* Modified to wrap Data4 array init with {} */ -#define EFI_SMBIOS_TABLE_GUID \ - { \ - 0xeb9d2d31, 0x2d88, 0x11d3, {0x9a, 0x16, 0x0, 0x90, 0x27, 0x3f, 0xc1, 0x4d} \ - } - -/* From Foundation/Efi/Guid/Smbios/SmBios.c */ -EFI_GUID const gEfiSmbiosTableGuid = EFI_SMBIOS_TABLE_GUID; - -#define SMBIOS_RANGE_START 0x000F0000 -#define SMBIOS_RANGE_END 0x000FFFFF - -/* '_SM_' in little endian: */ -#define SMBIOS_ANCHOR_UINT32_LE 0x5f4d535f - -static inline void* getAddressOfSmbiosTable() -{ - /* First see if we can even find the damn SMBIOS table - * The logic here is to start at 0xf0000 and end at 0xfffff iterating 16 bytes at a time looking - * for the SMBIOS entry-point structure anchor (literal ASCII "_SM_"). - */ - void *smbios_addr = (void*)SMBIOS_RANGE_START; - for(; (smbios_addr <= (void*)SMBIOS_RANGE_END) && (*(uint32_t*)smbios_addr != SMBIOS_ANCHOR_UINT32_LE); smbios_addr += 16) - ; - if(smbios_addr <= (void*)SMBIOS_RANGE_END) - { - /* NOTE: The specification does not specifically state what to do in the event of finding an - * SMBIOS anchor on an invalid table. It might be better to move this code into the for loop - * so that searching can continue. - */ - uint8_t csum = checksum8(smbios_addr, sizeof(struct SMBEntryPoint)); - /* The table already contains the checksum so we merely need to see if its checksum is now zero. */ - if(csum != 0) - { - printf("Found SMBIOS anchor but bad table checksum. Assuming no SMBIOS.\n"); - sleep(5); - smbios_addr = 0; - } - } - else - { - /* If this happens, it's possible that a PnP BIOS call can be done to retrieve the address of the table. - * The latest versions of the spec state that modern programs should not even attempt to do this. */ - printf("Unable to find SMBIOS table.\n"); - sleep(5); - smbios_addr = 0; - } - return smbios_addr; -} - - -/*========================================================================== - * ACPI - */ - -#define EFI_ACPI_TABLE_GUID \ - { \ - 0xeb9d2d30, 0x2d88, 0x11d3, { 0x9a, 0x16, 0x0, 0x90, 0x27, 0x3f, 0xc1, 0x4d } \ - } - -#define EFI_ACPI_20_TABLE_GUID \ - { \ - 0x8868e871, 0xe4f1, 0x11d3, { 0xbc, 0x22, 0x0, 0x80, 0xc7, 0x3c, 0x88, 0x81 } \ - } - -// NOTE: ACPI 3.0 uses same GUID as ACPI 2.0 - -EFI_GUID gEfiAcpiTableGuid = EFI_ACPI_TABLE_GUID; - -EFI_GUID gEfiAcpi20TableGuid = EFI_ACPI_20_TABLE_GUID; - -#define ACPI_RANGE_START (0x0E0000) -#define ACPI_RANGE_END (0x0FFFFF) - -#define UINT64_LE_FROM_CHARS(a,b,c,d,e,f,g,h) \ - ( ((uint64_t)h << 56) \ - | ((uint64_t)g << 48) \ - | ((uint64_t)f << 40) \ - | ((uint64_t)e << 32) \ - | ((uint64_t)d << 24) \ - | ((uint64_t)c << 16) \ - | ((uint64_t)b << 8) \ - | ((uint64_t)a << 0) \ - ) - -#define ACPI_SIGNATURE_UINT64_LE UINT64_LE_FROM_CHARS('R','S','D',' ','P','T','R',' ') - -/* Per ACPI 3.0a spec */ -struct acpi_2_rsdp { - char Signature[8]; - uint8_t Checksum; - char OEMID[6]; - uint8_t Revision; - uint32_t RsdtAddress; - uint32_t Length; - uint64_t XsdtAddress; - uint8_t ExtendedChecksum; - char Reserved[3]; -} __attribute__((packed)); - -/* Gets the ACPI 1.0 RSDP address */ -static void* getAddressOfAcpiTable() -{ - /* TODO: Before searching the BIOS space we are supposed to search the first 1K of the EBDA */ - - void *acpi_addr = (void*)ACPI_RANGE_START; - for(; acpi_addr <= (void*)ACPI_RANGE_END; acpi_addr += 16) - { - if(*(uint64_t *)acpi_addr == ACPI_SIGNATURE_UINT64_LE) - { - uint8_t csum = checksum8(acpi_addr, 20); - if(csum == 0) - { - // Only return the table if it is a true version 1.0 table (Revision 0) - if(((struct acpi_2_rsdp*)acpi_addr)->Revision == 0) - return acpi_addr; - } - } - } - return NULL; -} - -/* Gets the ACPI 2.0 RSDP address */ -static void* getAddressOfAcpi20Table() -{ - /* TODO: Before searching the BIOS space we are supposed to search the first 1K of the EBDA */ - - void *acpi_addr = (void*)ACPI_RANGE_START; - for(; acpi_addr <= (void*)ACPI_RANGE_END; acpi_addr += 16) - { - if(*(uint64_t *)acpi_addr == ACPI_SIGNATURE_UINT64_LE) - { - uint8_t csum = checksum8(acpi_addr, 20); - /* Only assume this is a 2.0 or better table if the revision is greater than 0 - * NOTE: ACPI 3.0 spec only seems to say that 1.0 tables have revision 1 - * and that the current revision is 2.. I am going to assume that rev > 0 is 2.0. - */ - if(csum == 0 && (((struct acpi_2_rsdp*)acpi_addr)->Revision > 0)) - { - uint8_t csum2 = checksum8(acpi_addr, sizeof(struct acpi_2_rsdp)); - if(csum2 == 0) - return acpi_addr; - } - } - } - return NULL; -} - - -/*========================================================================== - * Fake EFI implementation - */ - -char const FIRMWARE_REVISION_PROP[] = "firmware-revision"; -char const FIRMWARE_ABI_PROP[] = "firmware-abi"; -char const FIRMWARE_VENDOR_PROP[] = "firmware-vendor"; -char const FIRMWARE_ABI_PROP_VALUE[] = "EFI32"; -char const DEVICE_PROPERTIES_PROP[] = "device-properties"; - -void -setupEfiDeviceTree(void) -{ - const char *val; - int cnt; - char hexNibble; - char hexByte[2]; - uint8_t binChar; - uint8_t *binStr; - int hexStrIdx, binStrIdx, hexNibbleIdx; - - Node *node; - node = DT__FindNode("/", false); - if (node == 0) { - stop("Couldn't get root node"); - } - /* We could also just do DT__FindNode("/efi/platform", true) - * But I think eventually we want to fill stuff in the efi node - * too so we might as well create it so we have a pointer for it too. - */ - node = DT__AddChild(node, "efi"); - - DT__AddProperty(node, FIRMWARE_REVISION_PROP, sizeof(FIRMWARE_REVISION), (EFI_UINT32*)&FIRMWARE_REVISION); - DT__AddProperty(node, FIRMWARE_ABI_PROP, sizeof(FIRMWARE_ABI_PROP_VALUE), (char*)FIRMWARE_ABI_PROP_VALUE); - DT__AddProperty(node, FIRMWARE_VENDOR_PROP, sizeof(FIRMWARE_VENDOR), (EFI_CHAR16*)FIRMWARE_VENDOR); - - /* Add IODeviceTree:/efi/device-properties by decoding - * 'device-properties' value into binary data found in Boot.plist - */ - if (getValueForKey(DEVICE_PROPERTIES_PROP, &val, &cnt) && cnt > 1) - { - // the resulting binary will be the half size of the input hex string - binStr = malloc(cnt / 2); - binStrIdx = 0; - hexNibbleIdx = 0; - for (hexStrIdx = 0; hexStrIdx < cnt; hexStrIdx++) - { - hexNibble = val[hexStrIdx]; - - // ignore all chars except valid hex numbers - if (hexNibble >= '0' && hexNibble <= '9' || hexNibble >= 'A' && hexNibble <= 'F' || hexNibble >= 'a' && hexNibble <= 'f') - { - hexByte[hexNibbleIdx++] = hexNibble; - - // found both two nibbles, convert to binary - if (hexNibbleIdx == 2) - { - binChar = 0; - - for (hexNibbleIdx = 0; hexNibbleIdx < sizeof(hexByte); hexNibbleIdx++) - { - if (hexNibbleIdx > 0) binChar = binChar << 4; - - if (hexByte[hexNibbleIdx] <= '9') binChar += hexByte[hexNibbleIdx] - '0'; - else if (hexByte[hexNibbleIdx] <= 'F') binChar += hexByte[hexNibbleIdx] - ('A' - 10); - else if (hexByte[hexNibbleIdx] <= 'f') binChar += hexByte[hexNibbleIdx] - ('a' - 10); - } - - binStr[binStrIdx++] = binChar; - hexNibbleIdx = 0; - } - } - } - - if (binStrIdx > 0) DT__AddProperty(node, DEVICE_PROPERTIES_PROP, binStrIdx, binStr); - } - - /* TODO: Fill in other efi properties if necessary */ - - /* Set up the /efi/runtime-services table node similar to the way a child node of configuration-table - * is set up. That is, name and table properties */ - Node *runtimeServicesNode = DT__AddChild(node, "runtime-services"); - - /* The value of the table property is the 32-bit physical address for the RuntimeServices table. - * Sice the EFI system table already has a pointer to it, we simply use the address of that pointer - * for the pointer to the property data. Warning.. DT finalization calls free on that but we're not - * the only thing to use a non-malloc'd pointer for something in the DT - */ - DT__AddProperty(runtimeServicesNode, "table", sizeof(void *), &gST->RuntimeServices); - - /* Set up the /efi/configuration-table node which will eventually have several child nodes for - * all of the configuration tables needed by various kernel extensions. - */ - gEfiConfigurationTableNode = DT__AddChild(node, "configuration-table"); - - /* Now fill in the /efi/platform Node */ - Node *efiPlatformNode = DT__AddChild(node, "platform"); - - if(fsbFrequency != 0) - DT__AddProperty(efiPlatformNode, FSB_Frequency_prop, sizeof(uint64_t), &fsbFrequency); - /* NOTE WELL: If you do add FSB Frequency detection, make sure to store - * the value in the fsbFrequency global and not an malloc'd pointer - * because the DT_AddProperty function does not copy its args. - */ -} - -/* Installs all the needed configuration table entries */ -void setupEfiConfigurationTable() -{ - addConfigurationTable(&gEfiSmbiosTableGuid, getAddressOfSmbiosTable(), NULL); - addConfigurationTable(&gEfiAcpiTableGuid, getAddressOfAcpiTable(), "ACPI"); - addConfigurationTable(&gEfiAcpi20TableGuid, getAddressOfAcpi20Table(), "ACPI_20"); - - // We've obviously changed the count.. so fix up the CRC32 - fixupEfiSystemTableCRC32(gST); -} - -/* Entrypoint from boot.c */ -void setupFakeEfi(void) -{ - determineFsbFrequency(); - // Initialize the base table - setupEfiTables(); - // Initialize the device tree - setupEfiDeviceTree(); - // Add configuration table entries to both the services table and the device tree - setupEfiConfigurationTable(); -} - diff -Naur v51_src/i386/libsaio/saio_internal.h boot-132_dfe_r146/i386/libsaio/saio_internal.h --- v51_src/i386/libsaio/saio_internal.h 2008-10-06 02:54:18.000000000 +0200 +++ boot-132_dfe_r146/i386/libsaio/saio_internal.h 2008-06-29 05:51:25.000000000 +0200 @@ -44,7 +44,7 @@ extern int bgetc(void); extern int biosread(int dev, int cyl, int head, int sec, int num); extern int ebiosread(int dev, long sec, int count); -//extern int ebioswrite(int dev, long sec, int count); +extern int ebioswrite(int dev, long sec, int count); extern int get_drive_info(int drive, struct driveInfo *dp); extern int ebiosEjectMedia(int biosdev); extern void putc(int ch); @@ -103,7 +103,7 @@ extern int diskRead(BVRef bvr, long addr, long length); extern int diskIsCDROM(BVRef bvr); extern int rawDiskRead(BVRef bvr, unsigned int secno, void *buffer, unsigned int len); -//extern int rawDiskWrite(BVRef bvr, unsigned int secno, void *buffer, unsigned int len); +extern int rawDiskWrite(BVRef bvr, unsigned int secno, void *buffer, unsigned int len); extern int readBootSector(int biosdev, unsigned int secno, void *buffer); extern void turnOffFloppy(void); diff -Naur v51_src/i386/libsaio/stringTable.c boot-132_dfe_r146/i386/libsaio/stringTable.c --- v51_src/i386/libsaio/stringTable.c 2008-10-02 04:24:42.000000000 +0200 +++ boot-132_dfe_r146/i386/libsaio/stringTable.c 2007-06-27 18:02:45.000000000 +0200 @@ -481,8 +481,6 @@ #define LP '(' #define RP ')' -#define EFI_PART_CONFIG_DIR1 "bt(0,0)/Library/Preferences/SystemConfiguration" -#define EFI_PART_CONFIG_DIR2 "bt(0,0)" #define SYSTEM_CONFIG_DIR "/Library/Preferences/SystemConfiguration" #define SYSTEM_CONFIG_FILE "/com.apple.Boot.plist" #define LRE_CONFIG_FILE "/com.apple.lre.Boot.plist" @@ -597,20 +595,6 @@ strcat(bp, LRE_CONFIG_FILE); ret = loadConfigFile(bp); - if (ret < 0) { - /* If not found, try to load from EFI partition in Library/Preferences/SystemConfiguration */ - strcpy(bp, EFI_PART_CONFIG_DIR1); - strcat(bp, SYSTEM_CONFIG_FILE); - ret = loadConfigFile(bp); - } - - if (ret < 0) { - /* If not found, try to load from EFI partition root */ - strcpy(bp, EFI_PART_CONFIG_DIR2); - strcat(bp, SYSTEM_CONFIG_FILE); - ret = loadConfigFile(bp); - } - if (ret < 0) { /* If not found, try default file */ strcpy(bp, systemConfigDir()); diff -Naur v51_src/i386/libsaio/sys.c boot-132_dfe_r146/i386/libsaio/sys.c --- v51_src/i386/libsaio/sys.c 2008-10-02 03:47:24.000000000 +0200 +++ boot-132_dfe_r146/i386/libsaio/sys.c 2008-06-28 22:48:39.000000000 +0200 @@ -89,7 +89,6 @@ { "fd", 0x00, kBIOSDevTypeFloppy }, /* DEV_FD */ { "en", 0xE0, kBIOSDevTypeNetwork }, /* DEV_EN */ { "rd", 0x100, kBIOSDevTypeHardDrive }, - { "bt", 0x101, kBIOSDevTypeHardDrive }, // turbo - type for booter partition { 0, 0 } }; @@ -102,8 +101,6 @@ void * gFSLoadAddress = 0; -extern BVRef gBIOSBootVolume; // turbo - original partition - //static BVRef getBootVolumeRef( const char * path, const char ** outPath ); static BVRef newBootVolumeRef( int biosdev, int partno ); @@ -781,8 +778,6 @@ if (*cp == RP) cp++; biosdev = dp->biosdev + unit; - // turbo - if (biosdev == 0x101) bvr = gBIOSBootVolume; else bvr = newBootVolumeRef(biosdev, part); if(bvr == NULL)