From 4bcb62ee96db4dcb5a18fb66d9ab2b055dea6aeb Mon Sep 17 00:00:00 2001 From: anevilyak Date: Sat, 11 Jun 2011 19:14:49 +0000 Subject: [PATCH] =?UTF-8?q?Applied=20patch=20by=20Jean-Lo=C3=AFc=20Charrou?= =?UTF-8?q?d=20that=20reworks=20the=20anyboot=20MBR=20to=20fix=20boot=20pr?= =?UTF-8?q?oblems=20on=20various=20systems.=20Resolves=20#3441.=20Thanks!?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit +alpha3 git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@42104 a95241bf-73f2-0310-859d-f6bbb57e9c96 --- build/jam/AnybootImage | 2 +- .../intel/PartitionMapWriter.cpp | 64 +-- src/apps/aboutsystem/AboutSystem.cpp | 1 + src/bin/writembr/mbr.S | 539 +++++++++++++----- 4 files changed, 416 insertions(+), 190 deletions(-) diff --git a/build/jam/AnybootImage b/build/jam/AnybootImage index d2793fa0f7..4bc00b05a1 100644 --- a/build/jam/AnybootImage +++ b/build/jam/AnybootImage @@ -14,7 +14,7 @@ rule BuildAnybootMBR binary : source { actions BuildAnybootMBR1 { $(RM) $(1) - $(TARGET_CC) $(MBR_SOURCE) -o $(1) -nostdlib -Xlinker --oformat=binary -Xlinker -S -Xlinker -N -Xlinker "-e start" -Xlinker "-Ttext=0x600" + $(HAIKU_YASM) -f bin $(MBR_SOURCE) -O5 -o $(1) } rule BuildAnybootImage anybootImage : mbrPart : isoPart : imageFile { diff --git a/src/add-ons/kernel/partitioning_systems/intel/PartitionMapWriter.cpp b/src/add-ons/kernel/partitioning_systems/intel/PartitionMapWriter.cpp index 3f9be03b3c..66cd6b7aa9 100644 --- a/src/add-ons/kernel/partitioning_systems/intel/PartitionMapWriter.cpp +++ b/src/add-ons/kernel/partitioning_systems/intel/PartitionMapWriter.cpp @@ -37,44 +37,34 @@ using std::nothrow; #endif -// compiled form of hybrid FreeBSD pmbr and mbr loader done by André Braga +// compiled mbr boot loader code static const uint8 kBootCode[] = { - 0xfc, 0xe8, 0x05, 0x01, 0xbc, 0x00, 0x0e, 0xbe, 0x15, 0x7c, 0xbf, 0x15, - 0x06, 0xb9, 0xeb, 0x01, 0xf3, 0xa4, 0xe9, 0x00, 0x8a, 0xe8, 0xfc, 0x00, - 0xbb, 0x00, 0x0e, 0xbe, 0xb0, 0x07, 0xb9, 0x01, 0x00, 0xe8, 0x03, 0x01, - 0x66, 0x81, 0x3e, 0x00, 0x0e, 0x45, 0x46, 0x49, 0x20, 0x75, 0x5c, 0x66, - 0x81, 0x3e, 0x04, 0x0e, 0x50, 0x41, 0x52, 0x54, 0x75, 0x51, 0xbe, 0x48, - 0x0e, 0xbb, 0x00, 0x10, 0xb9, 0x01, 0x00, 0xe8, 0xe1, 0x00, 0x89, 0xde, - 0xbf, 0xa0, 0x07, 0xb1, 0x10, 0xf3, 0xa6, 0x75, 0x1b, 0x89, 0xdf, 0x8d, - 0x75, 0x20, 0xbb, 0xc0, 0x07, 0x8e, 0xc3, 0x31, 0xdb, 0x56, 0x8a, 0x0e, - 0x9f, 0x07, 0xe8, 0xc2, 0x00, 0x31, 0xc0, 0x8e, 0xc0, 0xe9, 0x94, 0x75, - 0x66, 0xff, 0x0e, 0x50, 0x0e, 0x74, 0x18, 0xa1, 0x54, 0x0e, 0x01, 0xc3, - 0x81, 0xfb, 0x00, 0x12, 0x72, 0xc8, 0x66, 0xff, 0x06, 0x48, 0x0e, 0x66, - 0x83, 0x16, 0x4c, 0x0e, 0x00, 0xeb, 0xaf, 0xe8, 0x7b, 0x00, 0xbc, 0x00, - 0x7c, 0x31, 0xf6, 0xbb, 0xbe, 0x07, 0xb1, 0x04, 0x38, 0x2f, 0x74, 0x0c, - 0x0f, 0x8f, 0xa2, 0x00, 0x85, 0xf6, 0x0f, 0x85, 0x9c, 0x00, 0x89, 0xde, - 0x80, 0xc3, 0x10, 0xe2, 0xeb, 0x85, 0xf6, 0x75, 0x02, 0xcd, 0x18, 0xe8, - 0x5e, 0x00, 0x89, 0xe7, 0x8a, 0x74, 0x01, 0x8b, 0x4c, 0x02, 0xbb, 0x00, - 0x7c, 0xf6, 0x06, 0x9e, 0x07, 0x80, 0x74, 0x2d, 0x51, 0x53, 0xbb, 0xaa, - 0x55, 0xb4, 0x41, 0xcd, 0x13, 0x72, 0x20, 0x81, 0xfb, 0x55, 0xaa, 0x75, - 0x1a, 0xf6, 0xc1, 0x01, 0x74, 0x15, 0x5b, 0x66, 0x6a, 0x00, 0x66, 0xff, - 0x74, 0x08, 0x06, 0x53, 0x6a, 0x01, 0x6a, 0x10, 0x89, 0xe6, 0xb8, 0x00, - 0x42, 0xeb, 0x05, 0x5b, 0x59, 0xb8, 0x01, 0x02, 0xcd, 0x13, 0x89, 0xfc, - 0x72, 0x49, 0x81, 0xbf, 0xfe, 0x01, 0x55, 0xaa, 0x75, 0x46, 0xe9, 0x5c, - 0xff, 0x31, 0xc9, 0x31, 0xc0, 0x8e, 0xc0, 0x8e, 0xd8, 0x8e, 0xd0, 0xc3, - 0x80, 0xfa, 0x80, 0x72, 0x0b, 0x8a, 0x36, 0x75, 0x04, 0x80, 0xc6, 0x80, - 0x38, 0xf2, 0x72, 0x02, 0xb2, 0x80, 0xc3, 0x66, 0xff, 0x74, 0x04, 0x66, - 0xff, 0x34, 0x06, 0x53, 0x51, 0x6a, 0x10, 0x89, 0xe6, 0xb8, 0x00, 0x42, - 0xcd, 0x13, 0x83, 0xc4, 0x10, 0x0f, 0x82, 0x4a, 0xff, 0xc3, 0xbe, 0x60, - 0x07, 0xeb, 0x11, 0xbe, 0x74, 0x07, 0xeb, 0x0c, 0xbe, 0x7d, 0x07, 0xeb, - 0x07, 0xbb, 0x07, 0x00, 0xb4, 0x0e, 0xcd, 0x10, 0xac, 0x84, 0xc0, 0x75, - 0xf4, 0xf4, 0xeb, 0xfd, 0x42, 0x61, 0x64, 0x20, 0x50, 0x61, 0x72, 0x74, - 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x54, 0x61, 0x62, 0x6c, 0x65, 0x00, - 0x49, 0x4f, 0x20, 0x45, 0x72, 0x72, 0x6f, 0x72, 0x00, 0x4d, 0x69, 0x73, - 0x73, 0x69, 0x6e, 0x67, 0x20, 0x53, 0x79, 0x73, 0x74, 0x65, 0x6d, 0x20, - 0x42, 0x6f, 0x6f, 0x74, 0x6c, 0x6f, 0x61, 0x64, 0x65, 0x72, 0x00, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x80, 0x02, 0x31, 0x53, 0x46, 0x42, - 0xa3, 0x3b, 0xf1, 0x10, 0x80, 0x2a, 0x48, 0x61, 0x69, 0x6b, 0x75, 0x21 + // compiled form of //haiku/trunk/src/bin/writembr/mbr.S + // yasm -f bin -O5 -o mbrcode.bin mbr.S -dMBR_CODE_ONLY=1 + // bin2h al - sectors read + %assign READ_DRV_PARAMETERS 0x08; dl - drive + ; -> cl - max cylinder 9:8 + ; - sectors per track + ; ch - max cylinder 7:0 + ; dh - max head + ; dl - number of drives (?) + %assign CHK_DISK_EXTENTIONS 0x41; bx - 0x55aa + ; dl - drive + ; -> success: carry clear + ; ah - extension version + ; bx - 0xaa55 + ; cx - support bit mask + ; 1 - Device Access using the + ; packet structure + ; 2 - Drive Locking and + ; Ejecting + ; 4 - Enhanced Disk Drive + ; Support (EDD) + ; -> error: carry set + %assign EXTENDED_READ 0x42; dl - drive + ; ds:si - address packet + ; -> success: carry clear + ; -> error: carry set -err_missing_os: - movw $msg_missing_os, %si // "Missing operating system" - jmp putString // -/* - * Output an ASCIZ string to the console via the BIOS. - */ -putString.0: - movw $0x7, %bx // Page:attribute - movb $0xe, %ah // BIOS: Display character - int $0x10 // -putString: - lodsb // Get character - testb %al,%al // End of string? - jnz putString.0 // No -putString.1: - jmp putString.1 // Await reset + %assign FIXED_DSK_SUPPORT 0x1 ; flag indicating fixed disk + ; extension command subset -msg_partition_table: .asciz "Invalid partition table" -msg_loading_os: .asciz "Error loading operating system" -msg_missing_os: .asciz "Missing operating system" + ; keyboard services + %assign READ_CHAR 0x00; -> al - ASCII char - .org PT_OFF +;MACRO + ; nicer way to get the size of a structure + %define sizeof(s) s %+ _size -partition_table: - .fill 0x10,0x4,0x0 // Partition table - .word MAGIC // Magic number + ; using a structure in a another structure definition + %macro nstruc 1-2 1 + resb sizeof(%1) * %2 + %endmacro + + ; nicer way to access GlobalVariables + %macro declare_var 1 + %define %1 HEAP + GlobalVariables. %+ %1 + %endmacro + + %macro puts 1 + mov si, %1 + call _puts + %endmacro + + %macro error 1 + mov si, %1 + jmp _error + %endmacro + +;TYPEDEFS + ; 64 bit value + struc quadword + .lower resd 1 + .upper resd 1 + endstruc + + struc CHS_addr + .head resb 1 + .sector resb 1 + .cylindre resb 1 + endstruc + + struc PartitionEntry + .status resb 1 + .CHS_first nstruc CHS_addr + .type resb 1 + .CHS_last nstruc CHS_addr + .LBA_start resd 1 + .LBA_size resd 1 + endstruc + + ; address packet as required by the EXTENDED_READ BIOS call + struc AddressPacket + .packet_size resb 1 + .reserved resb 1 + .block_count resw 1 + .buffer resd 1 + .sector nstruc quadword + ;.long_buffer nstruc quadword + ; We don't need the 64 bit buffer pointer. The 32 bit .buffer is more + ; than sufficient. + endstruc + + ; Structure containing the variables that don't need pre-initialization. + ; this structure will be allocated onto our "heap". + struc GlobalVariables + .boot_drive_id resd 1 + .boot_partition resd 1 + .address_packet nstruc AddressPacket + endstruc + +;alias for easy access to our global variables + declare_var boot_drive_id + declare_var boot_partition + declare_var address_packet + +;///////////////////////////////////////////////////////////////////////// +;// A 512 byte MBR boot manager that simply boots the active partition. // +;///////////////////////////////////////////////////////////////////////// +; 16 bit code +SECTION .text +BITS 16 +ORG EXEC ; MBR is loaded at 0x7c00 but relocated at 0x600 +start: ; we run the LOADed code + cli ; disable interrupts + cld ; clear direction flag (for string operations) + init: + xor ax, ax ; Zero + mov es, ax ; Set up extra segment + mov ds, ax ; Set up data segment + mov ss, ax ; Set up stack segment + mov sp, LOAD ; Set up stack pointer + + ;init our heap allocated variables with zeros + mov di, HEAP ;start adress + mov cx, sizeof(GlobalVariables) ;size + rep ; while(cx--) + stosb ; es[di++]:=al; + + ; Relocate ourself to a lower address so that we are out of the way + ; when we load in the bootstrap from the partition to boot. + reloc: + mov si, LOAD ; Source + ; init AddressPacket.buffer now since LOAD is in 'si' + mov [address_packet+AddressPacket.buffer],si + mov byte[address_packet+AddressPacket.packet_size],sizeof(AddressPacket) + mov byte[address_packet+AddressPacket.block_count],SECTOR_COUNT + + mov di, EXEC ; Destination + mov ch, 1 ; count cx:=256 (cl cleared by precedent rep call) + rep ; while(cx--) + movsw ; es[di++]:=ds[si++] + ; //di and si are incremented by sizeof(word) + jmp word 0x0000:continue; FAR jump to the relocated "continue" (some + ; BIOSes initialise CS to 0x07c0 so we must set + ; CS correctly) + +continue: ; Now we run EXEC_based relocated code + sti ; enable interrupts + %ifdef DEBUG + puts kMsgStart + %endif + +search_active_partition: + mov si,EXEC+PT_OFF ; point to first table entry + mov al,04 ; there are 4 table entries + .loop: ; SEARCH FOR AN ACTIVE ENTRY + cmp byte[si],FLG_ACTIVE ; is this the active entry? + je found_active ; yes + add si, sizeof(PartitionEntry) ; next PartitionEntry + dec al ; decrease remaining entry count + jnz .loop ; loop if entry count > 0 + jmp no_bootable_active_partition; last partition reached + +found_active: ; active partition (pointed by si) + mov [boot_partition],si ; Save active partition pointer + + .get_read_sector: ; initialise address_packet: + mov eax,[si + PartitionEntry.LBA_start] + mov [address_packet+AddressPacket.sector],eax + + ; if LBA_adress equals 0 then it's not a valid PBR (it is the MBR) + ; this can append when we only have a CHS adress in the partition entry + test eax, eax ;if ( LBA_adress == 0 ) + jz no_disk_extentions ;then no_disk_extentions() + +check_disk_extensions: + ; Note: this test may be unnecessary since EXTENDED_READ also + ; set the carry flag when extended calls are not supported + %ifdef DEBUG + puts kMsgCheckEx + %endif + + mov ah, CHK_DISK_EXTENTIONS ; set command + mov bx, 0x55aa ; set parameter : hton(MAGIC) + ; dl has not changed yet, still contains the drive ID + int BIOS_DISK_SERVICES ; if( do_command() <> OK ) + jc no_disk_extentions ; then use simple read operation + ; else use extended read +disk_extentions: + %ifdef DEBUG + puts kMsgRead_Ex + %endif + + ; load first bloc active partition + ; dl has not changed yet, still contains the drive ID + mov si, address_packet ; set command parameters + mov ah, EXTENDED_READ ; set command + .read_PBR: + int BIOS_DISK_SERVICES ; if ( do_command() <> OK ) + jc no_disk_extentions ; then try CHS_read(); + +check_for_bootable_partition: + cmp word[LOAD+MAGIC_OFF],MAGIC ; if ( ! volume.isBootable() ) + jne no_bootable_active_partition; then error(); + +jump_PBR: + %ifdef DEBUG + puts kMsgBootPBR + call _pause + %else + puts kMsgStart + %endif + + ; jump to 0x7c00 with : + ; - CS=0 + ; - DL=drive number + ; - DS:SI=pointer to the selected partition table + ; entry (required by some PBR) + + ; dl has not changed yet, still contains the drive ID + mov si, [boot_partition] + jmp LOAD ; jump into partition boot loader + +no_disk_extentions: + %ifdef DEBUG + puts kMsgNoExtentions + %endif + + mov si, [boot_partition] ; Restore active partition pointer + + ;load CHS PBR sector info + mov dh, [si+1] ; dh 7:0 = head 7:0 (0 - 255) + mov cx, [si+2] ; cl 5:0 = sector 7:0 (1 - 63) + ; cl 7:6 = cylinder 9:8 (0 - 1023) + ; ch 7:0 = cylinder 7:0 + .check_Sector: + mov al, cl + and al, 0x3F ; extract sector + test al, al; ; if (sector==0) + jz no_bootable_active_partition; then error("invalid sector"); + cmp al, 0x3F ; if( (Sector == 63) + jne .CHS_valid ; + .check_Cylinder: + mov ax, cx + shr ah, 6 + cmp ax, 0x03FF ; and (Cylinder == 1023) + jne .CHS_valid + .check_Head: + cmp dh, 0xFF ; and ( (Head == 255) + jne .CHS_valid + cmp dh, 0xFE ; or (Head == 254) ) ) + je no_bootable_active_partition; then error("invalid CHS_adress"); + + .CHS_valid: + ; dl has not changed yet, still contains the drive ID + mov bx, LOAD ; set buffer + mov al, SECTOR_COUNT ; set Size + mov ah, READ_DISK_SECTORS ; set read command + int BIOS_DISK_SERVICES ; if ( do_command() == OK ) + jnc check_for_bootable_partition; then resume(normal boot sequence) + ; else continue; + +no_bootable_active_partition: + mov si, kMsgNoBootable + ;jmp _error ; _error is the next line ! + +_error: + ; display a non-empty null-terminated string on the screen, + ; wait for a key pressed and go back to the bios + ; IN : + ; - si = address of string to display + ; OUT : + ; DIRTY : + ; - ax + ; - si + call _puts + call _pause + puts kMsgROMBASIC + int BIOS_BASIC ; BIOS_BASIC give the control back + ; to the BIOS. Doing so, let some + ; BIOSes try to boot an alternate + ; device (PXE/CD/HDD : see your + ; BIOS' boot device order ) +_pause: + ; wait for a key pressed + ; IN : + ; OUT : + ; DIRTY : + ; - ax + mov ah, READ_CHAR + int BIOS_KEYBOARD_SERVICES + ret + +_puts: + ; display a non-empty null-terminated string on the screen + ; IN : + ; - si = address of string to display + ; OUT : + ; DIRTY : + ; - ax + ; - bx + ; - si + xor bx, bx ; bx:=0 + .loop: ; do { + lodsb ; al=[si++]; + mov ah, WRITE_CHAR ; + int BIOS_VIDEO_SERVICES ; WRITE_CHAR(al) + or al, al ; } while (al<>0); + jnz .loop + ret + +data: + kMsgROMBASIC db 'ROM BASIC',0 + kMsgNoBootable db 'No bootable active volume',13,10,0 + kMsgStart db 'Loading system',10,13,0 + + %ifdef DEBUG + kMsgBootPBR db 'JMP PBR',13,10,0 + kMsgRead_Ex db 'Read_ex block',13,10,0 + kMsgCheckEx db 'CheckEx',13,10,0 + kMsgNoExtentions db 'Read block',13,10,0 + kMsgReloc db 'reloc MBR',13,10,0 + %endif + +; check whether the code is small enough to fit in the boot code area +end: + ;use nasm instead of yasm to check the code size + ;%if end - start > DISKSIG + ; %error "Code exceeds master boot code area!" + ;%endif + +%ifdef MBR_CODE_ONLY + ;just build the code. + ;Do not generate the datas +%else + ;use nasm instead of yasm => use %rep instead of times + ;%rep start + DISKSIG - end + ; db 0 ;fill the rest of the code area + ;%endrep + times start + DISKSIG - end db 0 + kMbrDiskID dd 0 ;Disk signature + dw 0 ;reserved + PartitionTable times PartitionEntry_size * 4 db 0 +DiskSignature: + ;use nasm instead of yasm to check the MAGIC offset + ;%if DiskSignature - start <> MAGIC_OFF + ; %error "incorrect Disk Signature offset" + ;%endif + kMbrSignature db 0x55, 0xAA +%endif