I was having trouble booting Haiku from a partition on my Acer Aspire One, so I added multiboot support to zbeos. It uses the a.out kludge to load at 0x100000 (1mb) and then relocates itself down to 0x10000, its expected location. Loading boot_loader_bios_ia32 as ELF also works, but grub refuses to load it below 1MB, despite what the multiboot header says (ELF header has priority). There is one downside to loading zbeos directly with GRUB: It won't find its boot volume, so the menu needs to be used to select it - I worked around this with a small shell script (meant to be run from a trunk checkout post build, passed the BIOS Drive ID in hex (80, 81, etc.) and the partition offset in sectors (the one makebootable outputs)) that manually patches zbeos. The reason it needs to be run from a checkout/built copy is that it runs objdump on the built bootloader to find the address to write gBootDriveID and gBootPartitionOffset. I tried adding a partition ID field, based on the multiboot info struct, but- 1) GRUB passes the ID/Drive of the partition the multiboot image was loaded from, so this would only be feasible with a GRUB bfs driver. 2) The bootloader's partition IDs are not equivalent to grub partition numbers. Note that GRUB2 will not load a.out kludge multiboot files, only GRUB Legacy will. This appears to be a defect or limitation. Attached: Patch and Script. Script comes with no error/bounds checking. Script requires bc, tr, dd, and bash (probably >=3.0) This would all be more useful if: GRUB could read bfs partitions and makebootable touched zbeos so this script didn't need to exist. Currently, zbeos needs to be copied to a grub-bootable partition, obviously. Report: Success on the Aspire One and in QEMU.
Index: src/system/boot/platform/bios_ia32/shell.S =================================================================== --- src/system/boot/platform/bios_ia32/shell.S (revision 27385) +++ src/system/boot/platform/bios_ia32/shell.S (working copy) @@ -25,6 +25,10 @@ // when the drive reading fails for some reason, it will // retry this many times until it will report a failure +.equ LOAD_ADDRESS, 0x10000 +.equ INITIAL_LOAD_ADDRESS, 0x100000 +.equ INITIAL_LOAD_OFFSET, INITIAL_LOAD_ADDRESS - LOAD_ADDRESS + .text .code16 @@ -281,6 +285,49 @@ call _start +multiboot_start: + + // The boot device is 15 bytes into the multiboot info struct. + movl (%ebx), %ecx + andl $0x2, %ecx + jz done_boot_drive_info + addl $15, %ebx + + movb (%ebx), %cl + movb %cl, gBootDriveID + INITIAL_LOAD_OFFSET + + //subl $1, %ebx + //movb (%ebx), %cl + //movb %cl, gBootPartitionID + INITIAL_LOAD_OFFSET + +done_boot_drive_info: + // Load the GDT from 1M + lgdt gdt_descriptor + INITIAL_LOAD_OFFSET + + // relocate boot loader code to expected start address + movl $_end, %ecx // desired end address + addl $3, %ecx // long word align + andb $0xfc, %cl // (should be page aligned anyway, though) + movl %ecx, %edi + subl $LOAD_ADDRESS, %ecx // number of bytes to copy + movl $INITIAL_LOAD_ADDRESS, %esi + addl %ecx, %esi // current end address + shrl $2, %ecx // number of long words +_copy: + subl $4, %esi + subl $4, %edi + movl (%esi), %eax + movl %eax, (%edi) + decl %ecx + jnz _copy + + ljmp $0x8, $relocated_start + +relocated_start: + // Just for good measure, Load the GDT when we're relocated + lgdt gdt_descriptor + ljmp $0x8, $_protected_code_segment + //-------------------------------------------------------------- /** Enables the a20 gate. It will first try to enable it through @@ -331,7 +378,7 @@ //-------------------------------------------------------------- -.org 896 +.org 864 // since we don't need the above space when the boot loader is // running, it is used as a real mode scratch buffer (as our // boot loader spans over the whole real mode 0x1000 segment) @@ -364,6 +411,17 @@ .word 0x2f // 6 entries in the GDT (8 bytes each) .long gdt +.align 4 +multiboot: + .long 0x1BADB002 + .long 0x00010003 + .long 0xE4514FFB + .long multiboot + INITIAL_LOAD_OFFSET + .long .text + INITIAL_LOAD_OFFSET + .long .bss + (INITIAL_LOAD_OFFSET - 24) + .long _end + (INITIAL_LOAD_OFFSET - 24) + .long multiboot_start + INITIAL_LOAD_OFFSET + GLOBAL(gBootedFromImage): .byte 0