BOOTBOOT Multi-platform Micro-kernel Loader
BOOTBOOT Multi-platform Micro-kernel Loader
BOOTBOOT Protocol
Unlike any existing boot loaders, this loader is not one big bloated system. Quite the contrary, it's a set of several independent, very thin implementations, all providing the same C/C++ compatible, higher-half 64 bit environment on their corresponding platforms. By very thin I mean really lightweight, no more than a few kilobytes each:
boot.bin (512 bytes), bootboot.bin (11k), bootboot.img (30k), bootboot.efi (93k)
It is ideal for hobby OS developers, as it's easy to use and it's very flexible. It's much easier to dealt with than GRUB, and also unlike with Multiboot you won't need any long mode Assembly trampoline code with dirty GDT and paging tricks in your kernel.
BOOTBOOT can load your higher half, 64 bit-only C/C++ kernel just as-is without any hacks. The repository also contains full documentation in MD and PDF formats, as well as small ANSI C mkboot utilities to help you with the installation. It's a Free and Open Source Sotfware, licensed under the terms of MIT license. If you want to use it as a reference for your own boot loader, the PDF documentation has a detailed description on which firmware interfaces have been used, and also the sources are well commented.
The BOOTBOOT Protocol is very easy to integrate, as it has a totally architecture agnostic interface. You just specify some object addresses in your linker script, and you're done. The information structure is defined in a C/C++ header file and can be used on all platforms. It contains information such as boot date and time, timezone, frame buffer dimension, platform independent memory map, initrd size, pointers to detected system tables (efi, acpi, mp, smbios etc.). Unlike other protocols, BOOTBOOT was written with forward-compatibility in mind. That is, current implementations support static addresses for those variables (Protocol Level 1), but it states that future versions (Level 2) should read the symbol table of the kernel to find those addresses. Kernels written for the Level 1 loaders will be able to boot with the upcoming Level 2 loaders just out-of-the-box.
The loader is capable of loading monolithic kernels, but mainly focuses on micro-kernels with an initrd. It can load the OS from several different sources: from ROM, over serial line, from a GPT partition, or from a file on a FAT16/32 GPT partition (usually ESP. To avoid licensing issues with M$, it's limited to upper case 8+3 filenames). The protocol also allows booting over network with TFTP, although the reference implementations do not use that (not yet ).
Current implementations support kernels in ELF64 and PE32+ formats for the AArch64 and x86_64 architectures. As for the initrd, they support
- statically linked executables (for monolithic kernels and statically linked micro-kernels like Minix)
- cpio (all variants: old hp, newc, and crc too. The latter is used by the Linux kernel btw.)
- tar (POSIX ustar, a very beginner friendly format)
- SFS (both Brendan's and BenLunt's versions)
- James Molloy's initrd (I assume you're already familiar with his tutorial)
- FS/Z (my operating system's native file system format)
- any archive or file system format, provided your kernel file is contiguous and is the first executable in the initrd.
The initrd can be gzip compressed, or optionally encrypted (FS/Z only feature).
The repository contains an example hello world kernel that demonstrates how to write strings and boxes on the frame buffer in an architecture independent way using PSF2 fonts. You are free to use that example kernel as a skeleton for starting your own kernel. Kernels written in C++ are also supported, but you have to provide a small code block at _start that calls your constructors (easiest way is to use a linker script to create .text.init or .text.ctors sections or .init_array table).
How to install
Please note BOOTBOOT is very flexible. What I describe here is just one way, which I believe to be the most common use case for hobby OS developers.
1. create a disk image with GPT partitioning table ("dd if=/dev/zero of=myimage.dd bs=1M count=256" and "fdisk myimage.dd")
2. set the first partition's type to ESP, and format it with FAT16 or FAT32 (fdisk's type 1, and use "mkfs.vfat -F x")
3. mount that partition with a loop device ("sudo mount -o loop,user myimage.dd somedir" or use "losetup"+"mount /dev/loop0")
4. create a BOOTBOOT directory there ("mkdir somedir/BOOTBOOT")
5. create an INITRD with your kernel in it (for example use "find . | cpio -H hpodc -o | gzip >somedir/BOOTBOOT/INITRD", for monolithic kernels, simply copy your kernel executable as INITRD).
6. optionally create a text file named BOOTBOOT/CONFIG (will be parsed by your kernel)
7. copy bootboot.bin into that directory as BOOTBOOT/LOADER (I strongly suggest to set the SYSTEM attribute for this file)
8. unmount the disk image
9. use the x86_64-bios/mkboot.c utility to install a (P)MBR sector on your disk image ("./mkboot myimage.dd")
If you want more control, do the steps 1-6, and choose a loader implementation for your platform and desired configuration (you can also use multiple loaders in the same image to create multiplatform bootable images). The documentation has detailed description of all of these scenarios:
- Raspberry Pi 3 (AArch64)
- UEFI (x86_64)
- UEFI for embedded systems (x86_64, in ROM)
- GRUB Multiboot (x86_64)
- ISOLINUX / LILO / BOOTLIN / etc. (x86_64)
- Legacy BIOS boot with any arbitrary boot manager (x86_64, chainloaded from VBR)
- Legacy BIOS boot with a single OS on a forward-compatible GPT disk (x86_64, booted from MBR)
- Legacy BIOS for embedded systems (x86_64, in ROM)
- CDROM, in El Torito "no emulation" mode (x86_64, hybrid GPT/ISO9660 image)
For more information, read the documentation. Before you comment any critism about this loader, please read the documentation. It's very likely it can do what you think it can't do, as most features and options are not mentioned in this brief introductory post.
Cheers,
bzt
Unlike any existing boot loaders, this loader is not one big bloated system. Quite the contrary, it's a set of several independent, very thin implementations, all providing the same C/C++ compatible, higher-half 64 bit environment on their corresponding platforms. By very thin I mean really lightweight, no more than a few kilobytes each:
boot.bin (512 bytes), bootboot.bin (11k), bootboot.img (30k), bootboot.efi (93k)
It is ideal for hobby OS developers, as it's easy to use and it's very flexible. It's much easier to dealt with than GRUB, and also unlike with Multiboot you won't need any long mode Assembly trampoline code with dirty GDT and paging tricks in your kernel.
BOOTBOOT can load your higher half, 64 bit-only C/C++ kernel just as-is without any hacks. The repository also contains full documentation in MD and PDF formats, as well as small ANSI C mkboot utilities to help you with the installation. It's a Free and Open Source Sotfware, licensed under the terms of MIT license. If you want to use it as a reference for your own boot loader, the PDF documentation has a detailed description on which firmware interfaces have been used, and also the sources are well commented.
The BOOTBOOT Protocol is very easy to integrate, as it has a totally architecture agnostic interface. You just specify some object addresses in your linker script, and you're done. The information structure is defined in a C/C++ header file and can be used on all platforms. It contains information such as boot date and time, timezone, frame buffer dimension, platform independent memory map, initrd size, pointers to detected system tables (efi, acpi, mp, smbios etc.). Unlike other protocols, BOOTBOOT was written with forward-compatibility in mind. That is, current implementations support static addresses for those variables (Protocol Level 1), but it states that future versions (Level 2) should read the symbol table of the kernel to find those addresses. Kernels written for the Level 1 loaders will be able to boot with the upcoming Level 2 loaders just out-of-the-box.
The loader is capable of loading monolithic kernels, but mainly focuses on micro-kernels with an initrd. It can load the OS from several different sources: from ROM, over serial line, from a GPT partition, or from a file on a FAT16/32 GPT partition (usually ESP. To avoid licensing issues with M$, it's limited to upper case 8+3 filenames). The protocol also allows booting over network with TFTP, although the reference implementations do not use that (not yet ).
Current implementations support kernels in ELF64 and PE32+ formats for the AArch64 and x86_64 architectures. As for the initrd, they support
- statically linked executables (for monolithic kernels and statically linked micro-kernels like Minix)
- cpio (all variants: old hp, newc, and crc too. The latter is used by the Linux kernel btw.)
- tar (POSIX ustar, a very beginner friendly format)
- SFS (both Brendan's and BenLunt's versions)
- James Molloy's initrd (I assume you're already familiar with his tutorial)
- FS/Z (my operating system's native file system format)
- any archive or file system format, provided your kernel file is contiguous and is the first executable in the initrd.
The initrd can be gzip compressed, or optionally encrypted (FS/Z only feature).
The repository contains an example hello world kernel that demonstrates how to write strings and boxes on the frame buffer in an architecture independent way using PSF2 fonts. You are free to use that example kernel as a skeleton for starting your own kernel. Kernels written in C++ are also supported, but you have to provide a small code block at _start that calls your constructors (easiest way is to use a linker script to create .text.init or .text.ctors sections or .init_array table).
How to install
Please note BOOTBOOT is very flexible. What I describe here is just one way, which I believe to be the most common use case for hobby OS developers.
1. create a disk image with GPT partitioning table ("dd if=/dev/zero of=myimage.dd bs=1M count=256" and "fdisk myimage.dd")
2. set the first partition's type to ESP, and format it with FAT16 or FAT32 (fdisk's type 1, and use "mkfs.vfat -F x")
3. mount that partition with a loop device ("sudo mount -o loop,user myimage.dd somedir" or use "losetup"+"mount /dev/loop0")
4. create a BOOTBOOT directory there ("mkdir somedir/BOOTBOOT")
5. create an INITRD with your kernel in it (for example use "find . | cpio -H hpodc -o | gzip >somedir/BOOTBOOT/INITRD", for monolithic kernels, simply copy your kernel executable as INITRD).
6. optionally create a text file named BOOTBOOT/CONFIG (will be parsed by your kernel)
7. copy bootboot.bin into that directory as BOOTBOOT/LOADER (I strongly suggest to set the SYSTEM attribute for this file)
8. unmount the disk image
9. use the x86_64-bios/mkboot.c utility to install a (P)MBR sector on your disk image ("./mkboot myimage.dd")
If you want more control, do the steps 1-6, and choose a loader implementation for your platform and desired configuration (you can also use multiple loaders in the same image to create multiplatform bootable images). The documentation has detailed description of all of these scenarios:
- Raspberry Pi 3 (AArch64)
- UEFI (x86_64)
- UEFI for embedded systems (x86_64, in ROM)
- GRUB Multiboot (x86_64)
- ISOLINUX / LILO / BOOTLIN / etc. (x86_64)
- Legacy BIOS boot with any arbitrary boot manager (x86_64, chainloaded from VBR)
- Legacy BIOS boot with a single OS on a forward-compatible GPT disk (x86_64, booted from MBR)
- Legacy BIOS for embedded systems (x86_64, in ROM)
- CDROM, in El Torito "no emulation" mode (x86_64, hybrid GPT/ISO9660 image)
For more information, read the documentation. Before you comment any critism about this loader, please read the documentation. It's very likely it can do what you think it can't do, as most features and options are not mentioned in this brief introductory post.
Cheers,
bzt
Re: BOOTBOOT Multi-platform Micro-kernel Loader
It looks very interesting, especially because I think I can find some guidance for my project in some points where I a a bit stuck, or not skilled enough to move forward comfortably, and you seem to cover.
Thanks for sharing this !
Thanks for sharing this !
Re: BOOTBOOT Multi-platform Micro-kernel Loader
Hi All,
I proudly present to you the final release of BOOTBOOT Protocol.
I've finished co-processor (SSE, Neon) initialization and SMP support on all platforms. With those the feature set is now complete, meaning from now on I'll only commit bugfixes (if any) and ports for new platforms. Specification is now frozen, no further modification on the specification will take place.
Multi Processing was tricky to achive without an interface, but finally I have decided to use the simplest method: the same kernel is started on all cores, only with different stacks. BIOS platform uses LAPIC IPI + SIPI (up to 256 cores) and PIT for sleeping. UEFI utilizes the newer PI EFI_MP_SERVICES_PROTOCOL (up to 1024 cores). If there's a need, I was thinking about implementing a fallback to the older FirmwareMPService Protocol (but I couldn't test it, so I skipped). And last but not least, on RPi, well SMP is just working out-of-the-box (with fixed 4 cores)
The bootboot structure had to be changed a bit, few fields were rearranged and bootboot.numcores came in (up to 65535 cores). Otherwise the structure is the same, 64 bytes architecture independent info, 64 bytes platform specific pointers (which already included ACPI and MP pointers), and the rest is the platform independent memory map.
Naturally I have updated the PDF documentation as well, and I've created an OSDev wiki page for BOOTBOOT. Happy OS development and I hope my loader will be useful to you too!
Cheers,
bzt
I proudly present to you the final release of BOOTBOOT Protocol.
I've finished co-processor (SSE, Neon) initialization and SMP support on all platforms. With those the feature set is now complete, meaning from now on I'll only commit bugfixes (if any) and ports for new platforms. Specification is now frozen, no further modification on the specification will take place.
Multi Processing was tricky to achive without an interface, but finally I have decided to use the simplest method: the same kernel is started on all cores, only with different stacks. BIOS platform uses LAPIC IPI + SIPI (up to 256 cores) and PIT for sleeping. UEFI utilizes the newer PI EFI_MP_SERVICES_PROTOCOL (up to 1024 cores). If there's a need, I was thinking about implementing a fallback to the older FirmwareMPService Protocol (but I couldn't test it, so I skipped). And last but not least, on RPi, well SMP is just working out-of-the-box (with fixed 4 cores)
The bootboot structure had to be changed a bit, few fields were rearranged and bootboot.numcores came in (up to 65535 cores). Otherwise the structure is the same, 64 bytes architecture independent info, 64 bytes platform specific pointers (which already included ACPI and MP pointers), and the rest is the platform independent memory map.
Naturally I have updated the PDF documentation as well, and I've created an OSDev wiki page for BOOTBOOT. Happy OS development and I hope my loader will be useful to you too!
Cheers,
bzt
Re: BOOTBOOT Multi-platform Micro-kernel Loader
Hi All,
Lots and lots (and lots) of testing on real hardware. I'd like to say thanks to all the testers! Testing the multicore support under UEFI was extremely helpful.
Some minor modifications had to be made: instead of PIT, the BIOS version now uses the PS/2 port oscillator for delays. Also minor fixes in Multiboot and Linux boot protocol support, they both work perfectly now.
On Raspberry Pi, model 3 was working already, but now model 4 support has been added too. Since the firmware code changed, multicore support had to be changed a bit too, but now SMP works with the latest firmware as well.
Furthermore, I've added sample bootable images and a very simple image creator tool, that can generate hybrid GPT/ISO9660 images with your inird. I've also provided a Makefile with several rules for testing (booting the images from ROM, via BIOS, via GRUB, from UEFI CDROM etc. etc. etc.)
Cheers,
bzt
Lots and lots (and lots) of testing on real hardware. I'd like to say thanks to all the testers! Testing the multicore support under UEFI was extremely helpful.
Some minor modifications had to be made: instead of PIT, the BIOS version now uses the PS/2 port oscillator for delays. Also minor fixes in Multiboot and Linux boot protocol support, they both work perfectly now.
On Raspberry Pi, model 3 was working already, but now model 4 support has been added too. Since the firmware code changed, multicore support had to be changed a bit too, but now SMP works with the latest firmware as well.
Furthermore, I've added sample bootable images and a very simple image creator tool, that can generate hybrid GPT/ISO9660 images with your inird. I've also provided a Makefile with several rules for testing (booting the images from ROM, via BIOS, via GRUB, from UEFI CDROM etc. etc. etc.)
Cheers,
bzt
Re: BOOTBOOT Multi-platform Micro-kernel Loader
Hi All,
New features (sort of). Protocol level 2 is now implemented in the reference implementations (UEFI and Raspberry Pi, BIOS remained at level 1). This means you are no longer tied to static link addresses, you are free to move them around (in the higher half -1G to 0 range). The loader will parse your ELF or PE kernel's symbols to find the addresses where to map the data. The affected labels:
The repo contains a simple, dependency-free image creator tool, mkimg. With that now you can create ESP FAT partition images and hybrid, bootable GPT disk / CDROM / DVD images. This means all disk generation related issues can be solved using this single file utility, no third party tools needed. Just like the loaders, you are free to use this tool with your project.
And last but not least, besides of the C example kernel, now there's a Rust example kernel that you can use as a skeleton for your own kernel.
Cheers,
bzt
New features (sort of). Protocol level 2 is now implemented in the reference implementations (UEFI and Raspberry Pi, BIOS remained at level 1). This means you are no longer tied to static link addresses, you are free to move them around (in the higher half -1G to 0 range). The loader will parse your ELF or PE kernel's symbols to find the addresses where to map the data. The affected labels:
- mmio - virtual address of the MMIO area (on platforms that supports that),
- fb - virtual address of the linear framebuffer,
- bootboot - the main information structure,
- environment - the arguments to your kernel in an UTF-8 string
- your kernel's segment (using Elf_Phdr->p_vaddr and PE_hdr->code_base).
The repo contains a simple, dependency-free image creator tool, mkimg. With that now you can create ESP FAT partition images and hybrid, bootable GPT disk / CDROM / DVD images. This means all disk generation related issues can be solved using this single file utility, no third party tools needed. Just like the loaders, you are free to use this tool with your project.
And last but not least, besides of the C example kernel, now there's a Rust example kernel that you can use as a skeleton for your own kernel.
Cheers,
bzt
Re: BOOTBOOT Multi-platform Micro-kernel Loader
Hi All,
I've replaced the quick and dirty mkimg tool with a proper, fully featured mkbootimg. This one is also dependency-free, with precompiled single portable executables available for Windows, MacOSX and Linux.
It receives a JSON configuration file as input, describing the disk you wish to create, and then it saves the resulting disk image. For example:Numbers are in Megabytes, except "align", which is in Kilobytes (align 0 means sector alignment for partitions). This tool can create:
Creating multiarch images also possible simply by using an array:This will create two initrds, one for each arch and it will put both loaders for them into the boot partition (the code is written in a way that it can support many architectures, however there's only loader for x86_64 and AArch64, so right now it is limited to two).
The generated images were tested with: FAT16/32: fsck.vfat, TianoCore UEFI; GPT: fdisk and gdisk's verify function. All green.
Hope this will be useful to some of you,
bzt
I've replaced the quick and dirty mkimg tool with a proper, fully featured mkbootimg. This one is also dependency-free, with precompiled single portable executables available for Windows, MacOSX and Linux.
It receives a JSON configuration file as input, describing the disk you wish to create, and then it saves the resulting disk image. For example:
Code: Select all
{
"diskguid": "00000000-0000-0000-0000-000000000000",
"disksize": 128,
"align": 1024,
"config": "initrd.dir/sys/config",
"initrd": { "type": "tar", "gzip": true, "directory": "initrd.dir" },
"iso9660": 1,
"partitions": [
{ "type": "boot", "size": 16 },
{ "type": "ntfs", "size": 16, "name": "Win Exchange" },
{ "type": "ext4", "size": 16, "name": "Linux Exchange" },
{ "type": "00000000-0000-0000-0000-000000000000", "size": 32, "name": "MyOS usr", "file": "usrpart.bin" },
{ "type": "00000000-0000-0000-0000-000000000000", "size": 32, "name": "MyOS var", "file": "varpart.bin" }
]
}
- A compressed initrd image from a directory (currently supports cpio and tar, but easily expandable)
- An ESP FAT boot partition with all the necessary files (including the newly created initrd) and boot code in VBR
- An MBR / GPT / ISO9660 hybrid partitioning table with the boot partition on it
- When creating a hybrid image, it also ensures that the root directory, the fat table, and the clusters on the boot partition are all 2048 bytes aligned
- Optionally it can add any number of partitions (well, up to 248), and it can fill them up using partition images
Creating multiarch images also possible simply by using an array:
Code: Select all
"initrd": { "type": "tar", "gzip": true, "directory": [ "initrd.x86", "initrd.arm" ] },
The generated images were tested with: FAT16/32: fsck.vfat, TianoCore UEFI; GPT: fdisk and gdisk's verify function. All green.
Hope this will be useful to some of you,
bzt
Re: BOOTBOOT Multi-platform Micro-kernel Loader
Out of curiosity, why did you pick this design? Do you map that segment as RWX? That prevents many useful sanity checking ("security") features from working, in particular WP and NX. WP and NX have probably caught more memory bugs in Managarm than any other measures combined. (I mean sure, one can enable it retroactively by some linker script hacks but that seems unnecessarily clunky for something that just amounts to setting two bits in the bootloader).bzt wrote:There can be one loadable segment (concatenated code, data and bss sections) in the kernel. With level 2, the size limit for this is raised to 16M (in comparition level 1 has a limit of 2M for info, environment, code, data, bss and stack). That must be enough for monolithic kernels too. You must be careful where you put these, because these might overlap, and there's absolutely no checks (it is perfectly valid for a kernel to request mapping of bootboot struct and the environment string into the middle of its bss section for example.)
managarm: Microkernel-based OS capable of running a Wayland desktop (Discord: https://discord.gg/7WB6Ur3). My OS-dev projects: [mlibc: Portable C library for managarm, qword, Linux, Sigma, ...] [LAI: AML interpreter] [xbstrap: Build system for OS distributions].
Re: BOOTBOOT Multi-platform Micro-kernel Loader
Hi,
Thanks for checking out! The answer is in the documentation, but thanks for asking!
First, for simplicity. This is also required by many other boot loaders (all that works with raw binaries this is actually a must otherwise you can't convert ELFs to raws).
Second, BOOTBOOT can load PE32+ kernels too, and PE doesn't have the concept of multiple, configurable load segments (there's a segment pointer for code and one for the data in the header, that's it).
Third, there's no point in overcomplicating because your kernel will switch away from identity mapping and will use its paging tables as soon as possible anyway.
Fourth, BOOTBOOT is a multiplatform loader, and it provides the same environment on all platforms. It cannot and should not rely on specific CPU features, it tries to keep it as minimal as possible so that it can support more platforms. (For example AArch64 has WNX bit too, but x86 doesn't. If BOOTBOOT were about to utilize that, then it couldn't load kernels on x86; not with the same environment that is).
The Multiboot specification is way too x86 related, and you simply can't use that on other platforms. As a result, loaders on other platforms create their own, unofficial and incompatible versions of the Multiboot spec (read this for example). I put a lot of effort in the BOOTBOOT Specification so this can never happen to it. As it focuses on the smallest common denominator among platforms, it's environment should be available on all platforms, no need for tweaking the spec.
In short, the bootloader's job is not to provide full functionality, rather to provide the bare minimum to get the system going. For example, BOOTBOOT allocates only 1k stack for your kernel per core, because it doesn't want to tell you how you should organize your memory. 1k is not enough for your kernel that's for sure, but it is surely enough to set up paging and stacks the way your kernel wants them, and that's about it.
Cheers,
bzt
Thanks for checking out! The answer is in the documentation, but thanks for asking!
It uses one boot segment for several reasons:Korona wrote:Out of curiosity, why did you pick this design? Do you map that segment as RWX?
First, for simplicity. This is also required by many other boot loaders (all that works with raw binaries this is actually a must otherwise you can't convert ELFs to raws).
Second, BOOTBOOT can load PE32+ kernels too, and PE doesn't have the concept of multiple, configurable load segments (there's a segment pointer for code and one for the data in the header, that's it).
Third, there's no point in overcomplicating because your kernel will switch away from identity mapping and will use its paging tables as soon as possible anyway.
Fourth, BOOTBOOT is a multiplatform loader, and it provides the same environment on all platforms. It cannot and should not rely on specific CPU features, it tries to keep it as minimal as possible so that it can support more platforms. (For example AArch64 has WNX bit too, but x86 doesn't. If BOOTBOOT were about to utilize that, then it couldn't load kernels on x86; not with the same environment that is).
The Multiboot specification is way too x86 related, and you simply can't use that on other platforms. As a result, loaders on other platforms create their own, unofficial and incompatible versions of the Multiboot spec (read this for example). I put a lot of effort in the BOOTBOOT Specification so this can never happen to it. As it focuses on the smallest common denominator among platforms, it's environment should be available on all platforms, no need for tweaking the spec.
No, not really. My kernel, which is loaded using BOOTBOOT does take advantage of both WP and NX security bits (and on AArch64 WNX too), so it is doable just fine. From the BOOTBOOT User's Manual, in section "Machine State":Korona wrote:That prevents many useful sanity checking ("security") features from working, in particular WP and NX.
Providing memory security is not a job for a bootloader. Your kernel will drop identity paging and will use it's own tables anyway. It will drop them for sure by the time it creates its first process. So why should the loader complicate things? I like simple. This is similar how GDT works (with Grub too). It is set up because it's needed, but your kernel should set a known GDT according its needs as soon as possible anyway.If a kernel wants to separate it's code on a read-only segment and data on a non-executable segment for security, it
can override the page translation tables as soon as it gains control. BOOTBOOT Protocol does only
handle one loadable segment for simplicity (called boot in the example linker script, see Appendix).
In short, the bootloader's job is not to provide full functionality, rather to provide the bare minimum to get the system going. For example, BOOTBOOT allocates only 1k stack for your kernel per core, because it doesn't want to tell you how you should organize your memory. 1k is not enough for your kernel that's for sure, but it is surely enough to set up paging and stacks the way your kernel wants them, and that's about it.
Cheers,
bzt
Re: BOOTBOOT Multi-platform Micro-kernel Loader
Great job!
But why do you call it "micro-kernel" loader? It's seems like unnecessary modesty to me. You could load nearly any kernel, don't you?
And what platforms is it available for so far? If I understood it correctly: Legacy-BIOS PCs, UEFI PCs, RaspPi 3 and 4. Correct?
Greetings
Peter
But why do you call it "micro-kernel" loader? It's seems like unnecessary modesty to me. You could load nearly any kernel, don't you?
And what platforms is it available for so far? If I understood it correctly: Legacy-BIOS PCs, UEFI PCs, RaspPi 3 and 4. Correct?
Greetings
Peter
Re: BOOTBOOT Multi-platform Micro-kernel Loader
Thanks!PeterX wrote:Great job!
Well, yes, it can load statically linked images, so it can load monolithic kernels too. I call it micro-kernel loader because it has a neat feature that no other boot loader: it loads an initrd into the memory with a bunch of files, then it locates the kernel amongst them (so the kernel is not a separate file as with GRUB, just a regular file inside the initrd). This suits primarily the needs of a micro-kernel, which requires to load several files on boot before it could access the disks.PeterX wrote:But why do you call it "micro-kernel" loader? It's seems like unnecessary modesty to me. You could load nearly any kernel, don't you?
Yes, for disks, USB storages and SD cards. Plus it can also boot from a CDROM via El Torito (both legacy BIOS and UEFI), and from ROM (via BIOS Boot Specification and under UEFI as Option ROM, this is useful for embedded systems); you can load it as a Linux kernel (using the Linux/x86 boot protocol, e.g. qemu -kernel), and last but not least, via GRUB, because it supports Multiboot too. Check out https://gitlab.com/bztsrc/bootboot/tree/master/images, along with the example images there's a Makefile with lots of qemu commands, one for each boot option.PeterX wrote:And what platforms is it available for so far? If I understood it correctly: Legacy-BIOS PCs, UEFI PCs, RaspPi 3 and 4. Correct?
In the future if I could get decent documentation and my hands on a board to test with, then I would like to support more. Beageboard is definitely on the bucket list, for example. I was also thinking about UltraSparc64, but as it's market is shrinking rapidly I don't think it worth the effort any more. Making it to work with Macs also a possibility (so far I had only one roadblock, I don't know how to get the frame buffer address using UGA, but that's the only one thing. Everything else works).
Greetings
Peter[/quote]
Re: BOOTBOOT Multi-platform Micro-kernel Loader
Hi All,
Just a little heads-up. I've upgraded the image creator:
bzt
Just a little heads-up. I've upgraded the image creator:
- It's multilingual now and autodetects OS' language
- If initrd is given as an image file which is compressed, now that's transparently uncompressed to look up the kernel inside
- New initrd formats has been added, it supports hpodc cpio, POSIX ustar, James Molloy's initrd and FS/Z (in lack of an up-to-date specification and with no available image creator I had to abandon SFS. But if you somehow manage to create an image, you can include it with the "file" directive and you should still be able to boot from it.)
- Many JSON tags made optional, the tool now calculates as much properties as it can. For example on a partition it's enough to specify "type" and "file".
- You can also use the "directory" directive for partitions, meaning you can create partition images from directories on-the-fly. Currently supported: tar and FS/Z (easy to add new file system drivers, see documentation). Could have added cpio and jamesm too, but those play not well with 512 byte sectors.
- I've updated the FS API to inform it if the image is generated for initrd or partition (this is needed for FS/Z, because it supports gaps in files, which must be avoided in initrds)
- On platforms that supports it (that's basically all save Windows) symlinks are also parsed and generated into initrds and partition images. This depends on S_ISLNK macro and readlink() libc function.
bzt
-
- Posts: 13
- Joined: Sat Jun 27, 2020 8:00 am
- Libera.chat IRC: heemogoblin
Re: BOOTBOOT Multi-platform Micro-kernel Loader
Dear All,
I am somewhat new to OS development and programming but am quite competent with the theory and also the implementation of an OS. Since I want my OS to make use of modern features I have decided to build it for UEFI firmware and x86_64 architecture. Despite being able to write a UEFI bootloader, I could not find any way to compile it and get it to call my kernel_main. Then I decided to use a premade bootloader, and have settled on your BOOTBOOT as it directly takes me to 64 bit mode and wrks with UEFI. I have looked at the example kernel and have compiled it to get myself an elf kernel.
Now here is the problem: I don't know how to boot it in virtualbox. To be more specific here are some details:
- I have my kernel elf (the0s.x86_64.elf) in my Documents/OS/The \OS/ folder.
- I have downloaded all of the bootboot code and have it ready.
- I am interested in using the bootboot.efi loader for UEFI systems.
- I have tried straight-up creating a .img with disk utility and partitioning it but that has problems:
- Whenever I make one, I can only edit one of its partitions.
- I can only place the bootboot efi code to the system partition and unfortunately the other partition for my kernel is blocked. I have tried many workarounds, none work.
- .imgs to virtualbox are floppy controllers and it is 2020.
- I compiled the mkbootimg and have checked my kernel. It is OK. However I have no clue how to use that to create a .iso with uefi compatibility and my kernel .elf at Documents/OS/The \OS/.
- I am quite confused about the config file. It says that the kernel=sys/config - does that mean the kernel is at sys/config/<name> or is the kernel called config and is at sys/ direcotry? Also it is in a specially named partition?
I would ideally like please some instructions to create a .iso ideally or .vmdk with UEFI booting and my kernel on it so I can test out my OS. Any way will do, as long as it can run on ubuntu and will give me a vmdk or .iso virtualbox will boot.
Also could you tell me if I can pass an EFI_SystemTable or a pointer to one to my kernel entry point? I'd prefer to get my time via the Runtime services GetTime function.
Apologies for being so naive, but I shall be incredibly grateful if you could help me. Thanks in advance!
I am somewhat new to OS development and programming but am quite competent with the theory and also the implementation of an OS. Since I want my OS to make use of modern features I have decided to build it for UEFI firmware and x86_64 architecture. Despite being able to write a UEFI bootloader, I could not find any way to compile it and get it to call my kernel_main. Then I decided to use a premade bootloader, and have settled on your BOOTBOOT as it directly takes me to 64 bit mode and wrks with UEFI. I have looked at the example kernel and have compiled it to get myself an elf kernel.
Now here is the problem: I don't know how to boot it in virtualbox. To be more specific here are some details:
- I have my kernel elf (the0s.x86_64.elf) in my Documents/OS/The \OS/ folder.
- I have downloaded all of the bootboot code and have it ready.
- I am interested in using the bootboot.efi loader for UEFI systems.
- I have tried straight-up creating a .img with disk utility and partitioning it but that has problems:
- Whenever I make one, I can only edit one of its partitions.
- I can only place the bootboot efi code to the system partition and unfortunately the other partition for my kernel is blocked. I have tried many workarounds, none work.
- .imgs to virtualbox are floppy controllers and it is 2020.
- I compiled the mkbootimg and have checked my kernel. It is OK. However I have no clue how to use that to create a .iso with uefi compatibility and my kernel .elf at Documents/OS/The \OS/.
- I am quite confused about the config file. It says that the kernel=sys/config - does that mean the kernel is at sys/config/<name> or is the kernel called config and is at sys/ direcotry? Also it is in a specially named partition?
I would ideally like please some instructions to create a .iso ideally or .vmdk with UEFI booting and my kernel on it so I can test out my OS. Any way will do, as long as it can run on ubuntu and will give me a vmdk or .iso virtualbox will boot.
Also could you tell me if I can pass an EFI_SystemTable or a pointer to one to my kernel entry point? I'd prefer to get my time via the Runtime services GetTime function.
Apologies for being so naive, but I shall be incredibly grateful if you could help me. Thanks in advance!
-
- Member
- Posts: 5568
- Joined: Mon Mar 25, 2013 7:01 pm
Re: BOOTBOOT Multi-platform Micro-kernel Loader
You can use VBoxManage to convert raw disk images to a format VirtualBox supports. Here is the documentation.
I don't see why you're not able to access more than one partition on your disk image, though.
I don't see why you're not able to access more than one partition on your disk image, though.
Re: BOOTBOOT Multi-platform Micro-kernel Loader
Hi,
Yes, @Octoronstabass is right, you can access more partitions.
I'd recommend to use mkbootimg, that's what it is for. But if you want to make it by hand, here are my answers.
EFI/BOOT/BOOTX64.EFI - move bootboot.efi here
BOOTBOOT/INITRD - the initrd image with your kernel in it, can be a tar or cpio archive, optionally gzip compressed.
BOOTBOOT/CONFIG - optional, a configuration that will be passed to your kernel. The loader uses only two keys if given, "screen=WxH" and "kernel=elf_filename_inside_the_initrd" all the others are for your kernel.The configuration is described in detail in the README (there's an example json in it), there's an example json in the source directory, and in the images directory you can find the actual json I've used to create the example disk images, as well as a Makefile on how to invoke it. If you want it to generate a hybrid ISO9660 image, that can be used on CDROMs, then in the mkbootimg json configuration, use "iso9660=true". Here's my mkbootimg.json:
This instructs mkbootimg that load the BOOTBOOT configuration from the file "./config", create an initrd in gzipped cpio format from the contents of the directory "initrd" (copy the0s.x86_64.elf there). Make the image 128M in size and CDROM compatible, and generate one ESP partition only (if you need it to generate more GPT records, just add more elements to the "partitions" array, and you can specify a partition image too with "file").
There's no need to create a filesystem on the boot partition, nor to copy files there, the mkbootimg will take care all of that for you.Because this will generate a random UUID for the vdi, and VirtualBox is extremely picky about UUIDs matching its configuration, I'd also recommend to use the following:
Cheers,
bzt
Yes, @Octoronstabass is right, you can access more partitions.
You create an image, then you configure your VB machine to boot with UEFI: "Detials" > "System" > "Motherboard" click "Enable EFI (special OSes only)".heemogoblin wrote:Dear All,
I am somewhat new to OS development and programming but am quite competent with the theory and also the implementation of an OS. Since I want my OS to make use of modern features I have decided to build it for UEFI firmware and x86_64 architecture. Despite being able to write a UEFI bootloader, I could not find any way to compile it and get it to call my kernel_main. Then I decided to use a premade bootloader, and have settled on your BOOTBOOT as it directly takes me to 64 bit mode and wrks with UEFI. I have looked at the example kernel and have compiled it to get myself an elf kernel.
Now here is the problem: I don't know how to boot it in virtualbox. To be more specific here are some details:
I'd recommend to use mkbootimg, that's what it is for. But if you want to make it by hand, here are my answers.
Move it into an initrd folder. Your kernel will be loaded as part of the initrd along with other files you want/need on boot.heemogoblin wrote:- I have my kernel elf (the0s.x86_64.elf) in my Documents/OS/The \OS/ folder.
Good.heemogoblin wrote:- I have downloaded all of the bootboot code and have it ready.
For that, you'll need the following files:heemogoblin wrote:- I am interested in using the bootboot.efi loader for UEFI systems.
EFI/BOOT/BOOTX64.EFI - move bootboot.efi here
BOOTBOOT/INITRD - the initrd image with your kernel in it, can be a tar or cpio archive, optionally gzip compressed.
BOOTBOOT/CONFIG - optional, a configuration that will be passed to your kernel. The loader uses only two keys if given, "screen=WxH" and "kernel=elf_filename_inside_the_initrd" all the others are for your kernel.
Not sure what disk utility you're using, but you should create a GPT disk, with a partition that is FAT formatted and copy the three files above to that system partition. Change the type to EFI System Partition (this is important, otherwise EFI won't recognize it). The BOOTBOOT User's Manual Appendix has an example how to use fdisk and mkfs.vfat for this.heemogoblin wrote:- I have tried straight-up creating a .img with disk utility and partitioning it but that has problems:
- Whenever I make one, I can only edit one of its partitions.
- I can only place the bootboot efi code to the system partition and unfortunately the other partition for my kernel is blocked. I have tried many workarounds, none work.
I don't know where you get that, .img files are just images. For example Raspberry OS contains an SD card image. My mkbootimg tool creates a hybrid CDROM / disk image by that extension.heemogoblin wrote: - .imgs to virtualbox are floppy controllers and it is 2020.
If you have compiled mkbootimg, then you don't need the boot loader files, as it has them already (data.c). It is well documented, and example configurations are provided. Basically you give it two arguments:heemogoblin wrote:- I compiled the mkbootimg and have checked my kernel. It is OK. However I have no clue how to use that to create a .iso with uefi compatibility and my kernel .elf at Documents/OS/The \OS/.
Code: Select all
./mkbootimg config.json output.img
Code: Select all
{
"disksize": 128,
"config": "./config",
"initrd": { "type": "cpio", "gzip": true, "directory": "initrd" },
"iso9660": true,
"partitions": [
{ "type": "boot", "size": 16 }
]
}
There's no need to create a filesystem on the boot partition, nor to copy files there, the mkbootimg will take care all of that for you.
I don't know where you get "kernel=sys/config". The "kernel" is the name of your kernel inside the initrd image (under the specified initrd directory). If you use mkbootimg, you'll have two config files:heemogoblin wrote:- I am quite confused about the config file. It says that the kernel=sys/config - does that mean the kernel is at sys/config/<name> or is the kernel called config and is at sys/ direcotry?
- the json - describes the disk image you want to create
- BOOTBOOT config - this will be copied to the ESP partition, and it is going to be parsed by the loader and your kernel during boot
Yes, the ESP is given a fixed name, "EFI System Partition".heemogoblin wrote:Also it is in a specially named partition?
The mkbootimg generates a disk image file. With "iso9660=true" it is going to be a hybrid image, which you can simply rename to ".iso" and it will work. For vmdk I'm not sure, I use vdi for VirtualBox. For that, use the following command:heemogoblin wrote:I would ideally like please some instructions to create a .iso ideally or .vmdk with UEFI booting and my kernel on it so I can test out my OS. Any way will do, as long as it can run on ubuntu and will give me a vmdk or .iso virtualbox will boot.
Code: Select all
VBoxManage convertfromraw yourimage.img yourimage.vdi
Code: Select all
BoxManage internalcommands sethduuid yourimage.vdi (some fix UUID)
Again, described in great detail in the BOOTBOOT User's Manual. The protocol maps an informational structure for your kernel, which contains both the EFI_SystemTable pointer and both the time (which is queried by the EFI GetTime service under UEFI).heemogoblin wrote:Also could you tell me if I can pass an EFI_SystemTable or a pointer to one to my kernel entry point? I'd prefer to get my time via the Runtime services GetTime function.
You should read the documentation first Both the READMEs and pdf have all the answers for your questions. But sure, ask and I'll try to answer.heemogoblin wrote:Apologies for being so naive, but I shall be incredibly grateful if you could help me. Thanks in advance!
Cheers,
bzt
Re: BOOTBOOT Multi-platform Micro-kernel Loader
does your religion allow you to use MSVC? if so, that's so easy to compile your OS Loader with it as compiling "hello world". if it doesn't, then *shrugs.Despite being able to write a UEFI bootloader, I could not find any way to compile it and get it to call my kernel_main. Then I decided to use a premade bootloader, and have settled on your BOOTBOOT as it directly takes me to 64 bit mode and wrks with UEFI. I have looked at the example kernel and have compiled it to get myself an elf kernel.
just for the note, despite bzt scares you, that you are required to mark a FAT partition as ESP and use only GPT, it's not true. you can create MBR with an ordinary FAT partition and be sure - it will be recognized by UEFI. since you are only at the start, I'd go this way (it's easier and maybe you'd have less troubles), actually, I do exactly this way - I created a small .vhd with VBox - thanks god its vhds are liked by diskpart (unlike qemu's). and created there a FAT partition. UEFI recognizes the disk, FAT formatted volume, and, of course, lets me start my OSL. either from the shell or from the Boot Manager menu or, finally, by creating a Load Option with the latter, - this way. Just don't forget to follow the guidelines and put your OSL in \efi\<YourNameAsAnOsVendor> directory, each OSL in its own directory (for the same architecture, I don't know why, but UEFI whimsically demands this, despite it distinguishes images well by their paths, which, of course, are different for two OSLs even lying in the same directory).
Of course, when you create such a disk, vhd in my case, for an easy access with diskpart, you can create 2 partitions or more. and then your OSL may access your OS boot volume (where your OS resides) either by using UEFI simple file system protocol and friends, if this is a FAT volume (because, see, bzt, FAT is a required part by the standard, for easening interoperability and osdevers lives and not for what you fantasize) or using block I/O protocols given to you by UEFI for reading disk sectors and then making FS related parsing in the OSL by your own.
and at the end, again and again - on this stubborn placement in \efi\boot\bootx64.efi. this is not a normal way of putting one's OSL. it's just a last resort in an attempt to start something by the Boot Manager on non-removable storages. if there is something else on the same disk, this thing won't be even touched. I have no idea why people don't look farther than this resort point. it is only somewhat and questionably good for removable storages, when you are going to install something and flash this storage for a one shot. even then, it's not necessary, and could mess up with something else, also blindly demanding itself to be placed there (and then when you put that other thing there, it overwrites the previous one and you find yoursefl in a mess). every UEFI has a "load from file" option - you better place your stuff in a personalized place and direct Boot Manager to it. it's more to bzt with his bootboot. the first time user directs the Boot Manager to load your bootboot, then, at the start, bootboot checks how it was started (by analyzing BootCurrent variable) and if it's not from its own Load Option, which is the case for the first start, asks a user if they want to install bootboot to this machine. on "yes", you just create a Load Option for bootboot by using SetVariable(), and that's it! this is how it should have been done.