Last active
February 26, 2023 07:35
-
-
Save CodingKoopa/b07ab0797ff24a7dfb924c65e749e887 to your computer and use it in GitHub Desktop.
Revisions
-
CodingKoopa revised this gist
Feb 26, 2023 . 1 changed file with 149 additions and 0 deletions.There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal 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 -
CodingKoopa revised this gist
Feb 24, 2023 . 1 changed file with 48 additions and 35 deletions.There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal 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: - 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! ``` -
CodingKoopa created this gist
Feb 24, 2023 .There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal 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\"" ```