[haiku-development] [PATCH 1/1] Add Multiboot Support to the Stage2 loader.

  • From: "Dustin Howett" <alaricx@xxxxxxxxx>
  • To: haiku-development@xxxxxxxxxxxxx
  • Date: Tue, 9 Sep 2008 07:02:41 -0400

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
 

Other related posts: