Skip to content

Instantly share code, notes, and snippets.

@CodingKoopa
Last active February 26, 2023 07:35
Show Gist options
  • Select an option

  • Save CodingKoopa/b07ab0797ff24a7dfb924c65e749e887 to your computer and use it in GitHub Desktop.

Select an option

Save CodingKoopa/b07ab0797ff24a7dfb924c65e749e887 to your computer and use it in GitHub Desktop.

Revisions

  1. CodingKoopa revised this gist Feb 26, 2023. 1 changed file with 149 additions and 0 deletions.
    149 changes: 149 additions & 0 deletions xv6-boot.md
    Original file line number Diff line number Diff line change
    @@ -1,3 +1,7 @@
    # xv6 boot

    ## boot process

    mainly just considering PATA/IDE (QEMU's default interface of choice)

    glosses over memory model
    @@ -54,3 +58,148 @@ Execution starts in the **BIOS**. **QEMU**'s default BIOS image is [SeaBIOS](htt
    ```
    QEMUEXTRA="--fw_cfg \"etc/show-boot-menu,string=1\""
    ```

    modified SeaBIOS cfg
    modified SeaBIOS makefile
    gdbinit

    ## troubleshooting boot

    `hexdump kernel` lines up with `x/120hx 0x10000` in GDB


    $1 = {magic = 1179403647, elf = "\001\001\001\000\000\000\000\000\000\000\000", type = 2, machine = 3, version = 1, entry = 1048588, phoff = 52, shoff = 201436, flags = 0, ehsize = 52,
    phentsize = 32, phnum = 3, shentsize = 40, shnum = 17, shstrndx = 16}

    ~~however, if we `x/10i 0x1000c`, the instructions are obviously not the assembly `entry` we have in our source - the ELF is bad

    wait no
    that address is *in the ELF header*

    maybe the linker script is wrong?~~ maybe just misread? looks fine to me


    okay, i hardcoded it to jump to the right place, but now it fails when jumping to a high addr

    ```
    segfault simulator <3  None 
    => 0x100032: jmp *%eax
    0x00100032 in ?? ()
    segfault simulator <3  None  x/16i 0x801030d0
    0x801030d0 <main>: lea 0x4(%esp),%ecx
    0x801030d4 <main+4>: and $0xfffffff0,%esp
    0x801030d7 <main+7>: push -0x4(%ecx)
    0x801030da <main+10>: push %ebp
    0x801030db <main+11>: mov %esp,%ebp
    0x801030dd <main+13>: push %ebx
    0x801030de <main+14>: push %ecx
    0x801030df <main+15>: sub $0x8,%esp
    0x801030e2 <main+18>: push $0x80400000
    0x801030e7 <main+23>: push $0x801154d0
    0x801030ec <main+28>: call 0x80102690 <kinit1>
    0x801030f1 <main+33>: call 0x80106fb0 <kvmalloc>
    0x801030f6 <main+38>: call 0x801032d0 <mpinit>
    0x801030fb <main+43>: call 0x80102880 <lapicinit>
    0x80103100 <main+48>: call 0x80106a70 <seginit>
    0x80103105 <main+53>: call 0x80103520 <picinit>
    segfault simulator <3  None  ni
    ```

    looking at page directories:
    ```
    x/16i entry
    0x10000c: mov %cr4,%eax
    0x10000f: or $0x10,%eax
    0x100012: mov %eax,%cr4
    0x100015: mov $0x109000,%eax
    0x10001a: mov %eax,%cr3
    0x10001d: mov %cr0,%eax
    0x100020: or $0x80010000,%eax
    0x100025: mov %eax,%cr0
    0x100028: mov $0x801154d0,%esp
    0x10002d: mov $0x801030d0,%eax
    0x100032: jmp *%eax
    0x100034: xchg %ax,%ax
    0x100036: xchg %ax,%ax
    0x100038: xchg %ax,%ax
    0x10003a: xchg %ax,%ax
    0x10003c: xchg %ax,%ax
    segfault simulator <3  bootmain  x/16x 0x109000
    0x109000: 0x00000083 0x00000000 0x00000000 0x00000000
    0x109010: 0x00000000 0x00000000 0x00000000 0x00000000
    0x109020: 0x00000000 0x00000000 0x00000000 0x00000000
    ```

    finding the high vt page directory entry:
    ```
    x/x 0x109000 + (0x80000000 >> 22) * 4
    0x109800: 0x00000083
    ```

    # nicer soln to the NOTE issue

    According to [this pull request](https://github.com/mit-pdos/xv6-public/pull/155), xv6 fails to boot on binutils 2.36. The author is correct; the informative `.note.gnu.property` section causes the ELF loader to hang. [https://lists.llvm.org/pipermail/llvm-dev/2018-March/121951.html]

    ## getting there

    so, the problem occurs when linking the initcode. first, look at the compiled initcode object:

    ```
    $ readelf -S initcode.o
    There are 18 section headers, starting at offset 0x380:
    Section Headers:
    [Nr] Name Type Addr Off Size ES Flg Lk Inf Al
    [ 0] NULL 00000000 000000 000000 00 0 0 0
    [ 1] .text PROGBITS 00000000 000034 00002c 00 AX 0 0 4
    [ 2] .rel.text REL 00000000 000268 000018 08 I 15 1 4
    [ 3] .data PROGBITS 00000000 000060 000000 00 WA 0 0 1
    [ 4] .bss NOBITS 00000000 000060 000000 00 WA 0 0 1
    [ 5] .note.gnu.pr[...] NOTE 00000000 000060 000028 00 A 0 0 4
    [ 6] .debug_line PROGBITS 00000000 000088 00004b 00 C 0 0 4
    [ 7] .rel.debug_line REL 00000000 000280 000020 08 I 15 6 4
    [ 8] .debug_line_str PROGBITS 00000000 0000d3 000033 01 MS 0 0 1
    [ 9] .debug_info PROGBITS 00000000 000106 000024 00 0 0 1
    [10] .rel.debug_info REL 00000000 0002a0 000030 08 I 15 9 4
    [11] .debug_abbrev PROGBITS 00000000 00012a 000014 00 0 0 1
    [12] .debug_aranges PROGBITS 00000000 000140 000020 00 0 0 8
    [13] .rel.debug_a[...] REL 00000000 0002d0 000010 08 I 15 12 4
    [14] .debug_str PROGBITS 00000000 000160 00003f 01 MS 0 0 1
    [15] .symtab SYMTAB 00000000 0001a0 0000b0 10 16 10 4
    [16] .strtab STRTAB 00000000 000250 000016 00 0 0 1
    [17] .shstrtab STRTAB 00000000 0002e0 00009f 00 0 0 1
    Key to Flags:
    W (write), A (alloc), X (execute), M (merge), S (strings), I (info),
    L (link order), O (extra OS processing required), G (group), T (TLS),
    C (compressed), x (unknown), o (OS specific), E (exclude),
    D (mbind), p (processor specific)
    ```

    the Note sections exist, but they are not doing any harm. but then, look at what happens when perform linking on it (not with other objects, yet):

    ```
    readelf -S initcode.out
    There are 12 section headers, starting at offset 0x368:
    Section Headers:
    [Nr] Name Type Addr Off Size ES Flg Lk Inf Al
    [ 0] NULL 00000000 000000 000000 00 0 0 0
    [ 1] .note.gnu.pr[...] NOTE 080480b4 0000e0 000028 00 A 0 0 4
    [ 2] .text PROGBITS 00000000 0000b4 00002c 00 WAX 0 0 4
    [ 3] .debug_aranges PROGBITS 00000000 000108 000020 00 0 0 8
    [ 4] .debug_info PROGBITS 00000000 000128 000024 00 0 0 1
    [ 5] .debug_abbrev PROGBITS 00000000 00014c 000014 00 0 0 1
    [ 6] .debug_line PROGBITS 00000000 000160 00004c 00 0 0 1
    [ 7] .debug_str PROGBITS 00000000 0001ac 00003f 01 MS 0 0 1
    [ 8] .debug_line_str PROGBITS 00000000 0001eb 000033 01 MS 0 0 1
    [ 9] .symtab SYMTAB 00000000 000220 000090 10 10 5 4
    [10] .strtab STRTAB 00000000 0002b0 000033 00 0 0 1
    [11] .shstrtab STRTAB 00000000 0002e3 000084 00 0 0 1
    Key to Flags:
    W (write), A (alloc), X (execute), M (merge), S (strings), I (info),
    L (link order), O (extra OS processing required), G (group), T (TLS),
    C (compressed), x (unknown), o (OS specific), E (exclude),
    D (mbind), p (processor specific)
    ```

    the note has been placed at a super high address
  2. CodingKoopa revised this gist Feb 24, 2023. 1 changed file with 48 additions and 35 deletions.
    83 changes: 48 additions & 35 deletions xv6-boot.md
    Original file line number Diff line number Diff line change
    @@ -1,41 +1,54 @@
    mainly just considering PATA/IDE (QEMU's default interface of choice)

    glosses over memory model

    Boot process:
    - Execution starts in the **BIOS**. **QEMU**'s default BIOS image is [SeaBIOS](https://www.seabios.org/SeaBIOS); **Bochs** can also use SeaBIOS but provides its own BIOS ROM by default (https://bochs.sourceforge.io/doc/docbook/user/bochsrc.html). We will use the SeaBIOS process as a reference: [https://www.seabios.org/Execution_and_code_flow]
    - POST is conducted.
    - Hardware initialization is performed by `device_hardware_setup` in `post.c`. [https://github.com/coreboot/seabios/blob/b0d61ecef66eb05bd7a4eb7ada88ec5dab06dfee/src/post.c#L125-L135]
    - `device_hardware_setup` calls `block_setup` in `block.c` (among setup functions for other hardware devices) for setting up all kinds of block devices. [https://github.com/coreboot/seabios/blob/b0d61ecef66eb05bd7a4eb7ada88ec5dab06dfee/src/block.c#L508-L523]
    - `block_setup` calls `ata_setup` in `ata.c` (among setup functions for other block storage types) to setup all **ATA** devices.
    - `ata_setup` "Scan[s the] PCI bus for ATA adapters". [https://github.com/coreboot/seabios/blob/b0d61ecef66eb05bd7a4eb7ada88ec5dab06dfee/src/hw/ata.c#L1018-L1037]
    - Control is handed over to the PCI subsystem, which calls `init_drive_ata` in `ata.c` [https://github.com/coreboot/seabios/blob/b0d61ecef66eb05bd7a4eb7ada88ec5dab06dfee/src/hw/ata.c#L768-L820] for each ATA controller.
    - These are processed in sequential order by PCI bus. [https://github.com/coreboot/seabios/blob/b0d61ecef66eb05bd7a4eb7ada88ec5dab06dfee/src/hw/pcidevice.c#L19-L84]
    - `init_drive_ata` detects any drives attached to the controller, including slave drives which have been daisy-chained.
    - `init_drive_ata` determines the priority of the drive, for boot order purposes.
    - Priorities can be assigned by configuring a boot order in the `bootorder` file. [https://github.com/coreboot/seabios/blob/b0d61ecef66eb05bd7a4eb7ada88ec5dab06dfee/docs/Runtime_config.md#configuring-boot-order]. The 1-based index within the file is used as the priority [https://github.com/coreboot/seabios/blob/b0d61ecef66eb05bd7a4eb7ada88ec5dab06dfee/src/boot.c#L245-L296].
    - If a boot order has not been configured, the default boot priority is assigned based on the type of media (e.g. Floppy, HD, CD). [https://github.com/coreboot/seabios/blob/b0d61ecef66eb05bd7a4eb7ada88ec5dab06dfee/src/boot.c#L460-L496] On QEMU, the order is provided by the emulator (e.g. configured from the command line).
    - `init_drive_ata` calls `boot_add_hd` in `boot.c` [https://github.com/coreboot/seabios/blob/b0d61ecef66eb05bd7a4eb7ada88ec5dab06dfee/src/boot.c#L593-L598], which adds a boot entry to a global list `BootList`. The `BootList` is sorted as follows:
    - Boot entries with lower priorities are listed above those with higher priorities. [https://github.com/coreboot/seabios/blob/b0d61ecef66eb05bd7a4eb7ada88ec5dab06dfee/src/boot.c#L524-L560]
    - Boot entries with the same priorities are sorted based on their media type (like with the default boot priority).
    - If tied here, I believe the order is sequential by ATA controller, then order of master, slave 1, slave 2, etc.
    - The bootmenu is (optionally, depending on runtime configuration) shown by `interactive_bootmenu` in `boot.c`. [https://github.com/coreboot/seabios/blob/ea1b7a0733906b8425d948ae94fba63c32b1d425/src/boot.c#L693-L791]
    - When the user selects an entry, it's moved to the top of the `BootList`.
    - Preparation is done for the boot phase by `prepareboot` in `post.c`. [https://github.com/coreboot/seabios/blob/b0d61ecef66eb05bd7a4eb7ada88ec5dab06dfee/src/post.c#L160-L179]
    - `prepareboot` calls `bcv_prepboot`, which, for each boot entry in the `BootList`: [https://github.com/coreboot/seabios/blob/b0d61ecef66eb05bd7a4eb7ada88ec5dab06dfee/src/boot.c#L817-L855]
    - Runs the [Boot Connection Vector](https://en.wikipedia.org/wiki/Option_ROM#BIOS_Boot_Specification) if applicable, though I don't think it is for ATA.
    - Assigns the drive a mapping in the internal two-dimensional `IDMap` array for all external drives being used. Implementation details: [https://github.com/coreboot/seabios/blob/b0d61ecef66eb05bd7a4eb7ada88ec5dab06dfee/src/block.h#L95-L100]
    - The first dimension is floppy disks, the second dimension is hard drives, and the third dimension is CDs.
    - Floppy IDs start at `0x00`, HD IDs start at `0x80`, and CD IDs start at `0xE0`.
    - Adds a Boot Execution Vector to `BEV`. The number of HDs and floppy disks is each limited to one.
    - The BEV seems to only be used for Plug-and-Play devices [https://etherboot.sourceforge.net/doc50/html/devman-3.html], though an entry is added regardless, with the vector being optional.
    - The **boot phase** (in SeaBIOS terms) loads the bootloader into memory (presumably from the first disk?).
    - POST fires software interrupt 0x19.
    - `entry_19` in `romlayout.s` handles the software interrupt; it is executing in 16-bit mode. [https://github.com/coreboot/seabios/blob/ea1b7a0733906b8425d948ae94fba63c32b1d425/src/romlayout.S#L576-L579]
    - `entry_19` transitions to 32-bit mode and executes `handle_19` and then `do_boot`, both in `boot.c`.
    - `do_boot` attempts to boot first boot entry in `BEV`. [https://github.com/coreboot/seabios/blob/ea1b7a0733906b8425d948ae94fba63c32b1d425/src/boot.c#L982-L1043]
    - If the boot entry is a HDD, `do_boot` invokes HDD `0x80` (the first HDD) using `boot_disk`. Now, remember:
    - We reordered the boot entries to our liking, back in `interactive_bootmenu`. Regardless of the inital priorities the devices were given, our chosen boot HDD (or other media) has been moved to the top of the `BootList`, and accordingly is at the top of `BEV`.
    - `BEV` is restricted to just one HDD, so hardcoding the device ID to the first one is sufficient.
    -

    Execution starts in the **BIOS**. **QEMU**'s default BIOS image is [SeaBIOS](https://www.seabios.org/SeaBIOS); **Bochs** can also use SeaBIOS but provides its own BIOS ROM by default (https://bochs.sourceforge.io/doc/docbook/user/bochsrc.html). We will use the SeaBIOS process as a reference: [https://www.seabios.org/Execution_and_code_flow]
    - POST is conducted.
    - Hardware initialization is performed by `device_hardware_setup` in `post.c`. [https://github.com/coreboot/seabios/blob/b0d61ecef66eb05bd7a4eb7ada88ec5dab06dfee/src/post.c#L125-L135]
    - `device_hardware_setup` calls `block_setup` in `block.c` (among setup functions for other hardware devices) for setting up all kinds of block devices. [https://github.com/coreboot/seabios/blob/b0d61ecef66eb05bd7a4eb7ada88ec5dab06dfee/src/block.c#L508-L523]
    - `block_setup` calls `ata_setup` in `ata.c` (among setup functions for other block storage types) to setup all **ATA** devices.
    - `ata_setup` "Scan[s the] PCI bus for ATA adapters". [https://github.com/coreboot/seabios/blob/b0d61ecef66eb05bd7a4eb7ada88ec5dab06dfee/src/hw/ata.c#L1018-L1037]
    - Control is handed over to the PCI subsystem, which calls `init_drive_ata` in `ata.c` [https://github.com/coreboot/seabios/blob/b0d61ecef66eb05bd7a4eb7ada88ec5dab06dfee/src/hw/ata.c#L768-L820] for each ATA controller.
    - These are processed in sequential order by PCI bus. [https://github.com/coreboot/seabios/blob/b0d61ecef66eb05bd7a4eb7ada88ec5dab06dfee/src/hw/pcidevice.c#L19-L84]
    - `init_drive_ata` detects any drives attached to the controller, including slave drives which have been daisy-chained.
    - `init_drive_ata` determines the priority of the drive, for boot order purposes.
    - Priorities can be assigned by configuring a boot order in the `bootorder` file. [https://github.com/coreboot/seabios/blob/b0d61ecef66eb05bd7a4eb7ada88ec5dab06dfee/docs/Runtime_config.md#configuring-boot-order]. The 1-based index within the file is used as the priority [https://github.com/coreboot/seabios/blob/b0d61ecef66eb05bd7a4eb7ada88ec5dab06dfee/src/boot.c#L245-L296].
    - If a boot order has not been configured, the default boot priority is assigned based on the type of media (e.g. Floppy, HD, CD). [https://github.com/coreboot/seabios/blob/b0d61ecef66eb05bd7a4eb7ada88ec5dab06dfee/src/boot.c#L460-L496] On QEMU, the order is provided by the emulator (e.g. configured from the command line).
    - `init_drive_ata` calls `boot_add_hd` in `boot.c` [https://github.com/coreboot/seabios/blob/b0d61ecef66eb05bd7a4eb7ada88ec5dab06dfee/src/boot.c#L593-L598], which adds a boot entry to a global list `BootList`. The `BootList` is sorted as follows:
    - Boot entries with lower priorities are listed above those with higher priorities. [https://github.com/coreboot/seabios/blob/b0d61ecef66eb05bd7a4eb7ada88ec5dab06dfee/src/boot.c#L524-L560]
    - Boot entries with the same priorities are sorted based on their media type (like with the default boot priority).
    - If tied here, I believe the order is sequential by ATA controller, then order of master, slave 1, slave 2, etc.
    - The bootmenu is (optionally, depending on runtime configuration) shown by `interactive_bootmenu` in `boot.c`. [https://github.com/coreboot/seabios/blob/ea1b7a0733906b8425d948ae94fba63c32b1d425/src/boot.c#L693-L791]
    - When the user selects an entry, it's moved to the top of the `BootList`.
    - Preparation is done for the boot phase by `prepareboot` in `post.c`. [https://github.com/coreboot/seabios/blob/b0d61ecef66eb05bd7a4eb7ada88ec5dab06dfee/src/post.c#L160-L179]
    - `prepareboot` calls `bcv_prepboot`, which, for each boot entry in the `BootList`: [https://github.com/coreboot/seabios/blob/b0d61ecef66eb05bd7a4eb7ada88ec5dab06dfee/src/boot.c#L817-L855]
    - Runs the [Boot Connection Vector](https://en.wikipedia.org/wiki/Option_ROM#BIOS_Boot_Specification) if applicable, though I don't think it is for ATA.
    - Assigns the drive a mapping in the internal two-dimensional `IDMap` array for all external drives being used. Implementation details: [https://github.com/coreboot/seabios/blob/b0d61ecef66eb05bd7a4eb7ada88ec5dab06dfee/src/block.h#L95-L100]
    - The first dimension is floppy disks, the second dimension is hard drives, and the third dimension is CDs.
    - Floppy IDs start at `0x00`, HD IDs start at `0x80`, and CD IDs start at `0xE0`.
    - Adds a Boot Execution Vector to `BEV`. The number of HDs and floppy disks is each limited to one.
    - The BEV seems to only be used for Plug-and-Play devices [https://etherboot.sourceforge.net/doc50/html/devman-3.html], though an entry is added regardless, with the vector being optional.
    - The **boot phase** (in SeaBIOS terms) loads the bootloader into memory:
    - POST fires software interrupt 0x19 once done.
    - The software interrupt is handled by `entry_19` in `romlayout.s`; it is executing in 16-bit mode. [https://github.com/coreboot/seabios/blob/ea1b7a0733906b8425d948ae94fba63c32b1d425/src/romlayout.S#L576-L579]
    - `entry_19` transitions to 32-bit mode and executes `handle_19` and then `do_boot`, both in `boot.c`.
    - `do_boot` attempts to boot first boot entry in `BEV`. [https://github.com/coreboot/seabios/blob/ea1b7a0733906b8425d948ae94fba63c32b1d425/src/boot.c#L982-L1043]
    - If the boot entry is a HDD, `do_boot` invokes `boot_disk` with HDD `0x80` (the first HDD). Now, remember:
    - We reordered the boot entries to our liking, back in `interactive_bootmenu`. Regardless of the inital priorities the devices were given, our chosen boot HDD (or other media) has been moved to the top of the `BootList`, and accordingly is at the top of `BEV`.
    - `BEV` is restricted to just one HDD, so hardcoding the device ID to the first one is sufficient.
    - `boot_disk` reads the first sector of the HDD by firing software interrupt 0x13, "Fixed Disk Services Entry Point". Detour time!
    - This is the [boot sector](https://en.wikipedia.org/wiki/Boot_sector), which is comprised of the [Master Boot Record](https://en.wikipedia.org/wiki/Master_boot_record).
    - As is convention, the destination buffer is located at `0x0000:0x7C00`. [https://wiki.osdev.org/Boot_Sequence] [https://en.wikipedia.org/wiki/Master_boot_record#BIOS_to_MBR_interface]
    - The software interrupt is handled by `handle_13` in `disk.c`. [https://github.com/coreboot/seabios/blob/b0d61ecef66eb05bd7a4eb7ada88ec5dab06dfee/src/disk.c#L739-L770]
    - `handle_13` eventually dispatches the command using `disk_13` in `disk.c`. [https://github.com/coreboot/seabios/blob/b0d61ecef66eb05bd7a4eb7ada88ec5dab06dfee/src/disk.c#L620-L656]
    - `disk_13` issues the command to the device. `boot_disk` specifies command `0x20` (`ah=0x2` -> `eax=0x20`), not that this is necessarily the exact command issued.
    - Eventually we arrive at `ata_process_op` in `ata.c`, which defers to `ata_readwrite` in `ata.c`. [https://github.com/coreboot/seabios/blob/b0d61ecef66eb05bd7a4eb7ada88ec5dab06dfee/src/hw/ata.c#L554-L576]
    - `ata_readwrite` reads the data into a buffer, either with Direct Memory Access or Programmed Input/Output.
    - `boot_disk` checks the MBR signature, and bails if it is not the magic number.
    - `boot_disk` calls `call_boot_entry`, which jumps to the beginning of the MBR!



    ```
  3. CodingKoopa created this gist Feb 24, 2023.
    43 changes: 43 additions & 0 deletions xv6-boot.md
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,43 @@
    mainly just considering PATA/IDE (QEMU's default interface of choice)

    Boot process:
    - Execution starts in the **BIOS**. **QEMU**'s default BIOS image is [SeaBIOS](https://www.seabios.org/SeaBIOS); **Bochs** can also use SeaBIOS but provides its own BIOS ROM by default (https://bochs.sourceforge.io/doc/docbook/user/bochsrc.html). We will use the SeaBIOS process as a reference: [https://www.seabios.org/Execution_and_code_flow]
    - POST is conducted.
    - Hardware initialization is performed by `device_hardware_setup` in `post.c`. [https://github.com/coreboot/seabios/blob/b0d61ecef66eb05bd7a4eb7ada88ec5dab06dfee/src/post.c#L125-L135]
    - `device_hardware_setup` calls `block_setup` in `block.c` (among setup functions for other hardware devices) for setting up all kinds of block devices. [https://github.com/coreboot/seabios/blob/b0d61ecef66eb05bd7a4eb7ada88ec5dab06dfee/src/block.c#L508-L523]
    - `block_setup` calls `ata_setup` in `ata.c` (among setup functions for other block storage types) to setup all **ATA** devices.
    - `ata_setup` "Scan[s the] PCI bus for ATA adapters". [https://github.com/coreboot/seabios/blob/b0d61ecef66eb05bd7a4eb7ada88ec5dab06dfee/src/hw/ata.c#L1018-L1037]
    - Control is handed over to the PCI subsystem, which calls `init_drive_ata` in `ata.c` [https://github.com/coreboot/seabios/blob/b0d61ecef66eb05bd7a4eb7ada88ec5dab06dfee/src/hw/ata.c#L768-L820] for each ATA controller.
    - These are processed in sequential order by PCI bus. [https://github.com/coreboot/seabios/blob/b0d61ecef66eb05bd7a4eb7ada88ec5dab06dfee/src/hw/pcidevice.c#L19-L84]
    - `init_drive_ata` detects any drives attached to the controller, including slave drives which have been daisy-chained.
    - `init_drive_ata` determines the priority of the drive, for boot order purposes.
    - Priorities can be assigned by configuring a boot order in the `bootorder` file. [https://github.com/coreboot/seabios/blob/b0d61ecef66eb05bd7a4eb7ada88ec5dab06dfee/docs/Runtime_config.md#configuring-boot-order]. The 1-based index within the file is used as the priority [https://github.com/coreboot/seabios/blob/b0d61ecef66eb05bd7a4eb7ada88ec5dab06dfee/src/boot.c#L245-L296].
    - If a boot order has not been configured, the default boot priority is assigned based on the type of media (e.g. Floppy, HD, CD). [https://github.com/coreboot/seabios/blob/b0d61ecef66eb05bd7a4eb7ada88ec5dab06dfee/src/boot.c#L460-L496] On QEMU, the order is provided by the emulator (e.g. configured from the command line).
    - `init_drive_ata` calls `boot_add_hd` in `boot.c` [https://github.com/coreboot/seabios/blob/b0d61ecef66eb05bd7a4eb7ada88ec5dab06dfee/src/boot.c#L593-L598], which adds a boot entry to a global list `BootList`. The `BootList` is sorted as follows:
    - Boot entries with lower priorities are listed above those with higher priorities. [https://github.com/coreboot/seabios/blob/b0d61ecef66eb05bd7a4eb7ada88ec5dab06dfee/src/boot.c#L524-L560]
    - Boot entries with the same priorities are sorted based on their media type (like with the default boot priority).
    - If tied here, I believe the order is sequential by ATA controller, then order of master, slave 1, slave 2, etc.
    - The bootmenu is (optionally, depending on runtime configuration) shown by `interactive_bootmenu` in `boot.c`. [https://github.com/coreboot/seabios/blob/ea1b7a0733906b8425d948ae94fba63c32b1d425/src/boot.c#L693-L791]
    - When the user selects an entry, it's moved to the top of the `BootList`.
    - Preparation is done for the boot phase by `prepareboot` in `post.c`. [https://github.com/coreboot/seabios/blob/b0d61ecef66eb05bd7a4eb7ada88ec5dab06dfee/src/post.c#L160-L179]
    - `prepareboot` calls `bcv_prepboot`, which, for each boot entry in the `BootList`: [https://github.com/coreboot/seabios/blob/b0d61ecef66eb05bd7a4eb7ada88ec5dab06dfee/src/boot.c#L817-L855]
    - Runs the [Boot Connection Vector](https://en.wikipedia.org/wiki/Option_ROM#BIOS_Boot_Specification) if applicable, though I don't think it is for ATA.
    - Assigns the drive a mapping in the internal two-dimensional `IDMap` array for all external drives being used. Implementation details: [https://github.com/coreboot/seabios/blob/b0d61ecef66eb05bd7a4eb7ada88ec5dab06dfee/src/block.h#L95-L100]
    - The first dimension is floppy disks, the second dimension is hard drives, and the third dimension is CDs.
    - Floppy IDs start at `0x00`, HD IDs start at `0x80`, and CD IDs start at `0xE0`.
    - Adds a Boot Execution Vector to `BEV`. The number of HDs and floppy disks is each limited to one.
    - The BEV seems to only be used for Plug-and-Play devices [https://etherboot.sourceforge.net/doc50/html/devman-3.html], though an entry is added regardless, with the vector being optional.
    - The **boot phase** (in SeaBIOS terms) loads the bootloader into memory (presumably from the first disk?).
    - POST fires software interrupt 0x19.
    - `entry_19` in `romlayout.s` handles the software interrupt; it is executing in 16-bit mode. [https://github.com/coreboot/seabios/blob/ea1b7a0733906b8425d948ae94fba63c32b1d425/src/romlayout.S#L576-L579]
    - `entry_19` transitions to 32-bit mode and executes `handle_19` and then `do_boot`, both in `boot.c`.
    - `do_boot` attempts to boot first boot entry in `BEV`. [https://github.com/coreboot/seabios/blob/ea1b7a0733906b8425d948ae94fba63c32b1d425/src/boot.c#L982-L1043]
    - If the boot entry is a HDD, `do_boot` invokes HDD `0x80` (the first HDD) using `boot_disk`. Now, remember:
    - We reordered the boot entries to our liking, back in `interactive_bootmenu`. Regardless of the inital priorities the devices were given, our chosen boot HDD (or other media) has been moved to the top of the `BootList`, and accordingly is at the top of `BEV`.
    - `BEV` is restricted to just one HDD, so hardcoding the device ID to the first one is sufficient.
    -


    ```
    QEMUEXTRA="--fw_cfg \"etc/show-boot-menu,string=1\""
    ```