Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

change multiboot to boot as an option rom, add initrd, cmdline #971

Merged
merged 7 commits into from
Jan 22, 2024

Conversation

russor
Copy link
Contributor

@russor russor commented Jan 2, 2024

This fleshes out the multiboot support a bit more. My hobby os relies on multiboot, but also needs some ACPI tables set. Using the existing multiboot support means seabios doesn't run at all, and the tables are missing.

The multiboot content is loaded in an i/o write hook rather than before booting, because otherwise seabios may overwrite the loaded data (happens with the kvm-test).

load_multiboot still works, although the mechanism changed, because nasmtests uses it directly and doesn't load seabios anyway. Now it generates the option rom, loads it at address 0 (seemed like a convenient place) and adjusts execution to start at address 3 (where an option rom is jumped to in a BIOS context).

There's a not entirely related log fix in elf section header debug info (log said program headers, but was reporting about section headers); happy to put that separate, but it came up while I was working on this.

Copy link
Owner

@copy copy left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks!

Testing-wise, I would like to add your OS to the testsuite (in tests/full/run.js). Could you upload a (preferably small) multiboot image? Also, I assume this could also be used to boot Linux kernels. Have you tested that?

Overall the code looks good. My main bigger suggestion would be to remove the assembly and implement it directly in the io port hook.

src/cpu.js Outdated Show resolved Hide resolved
src/cpu.js Outdated
// It sets up the multiboot environment.
const SIZE = 0x200;

const data8 = new Uint8Array(0x100);
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I believe this should be new Uint8Array(SIZE); (also in kernel.js)

src/cpu.js Outdated
if(option_rom)
{
dbg_log("loaded multiboot", LOG_CPU);
this.write_blob(new Uint8Array(option_rom.data), 0);
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I believe the new Uint8Array makes an unnecessary copy of the option rom and can be removed.

src/cpu.js Show resolved Hide resolved
src/cpu.js Outdated Show resolved Hide resolved
src/cpu.js Outdated Show resolved Hide resolved
src/cpu.js Outdated
// does not exclude traditional bios exclusions
let start = 0;
let was_memory = false;
for (let addr = 0; addr < MMAP_MAX; addr += MMAP_BLOCK_SIZE) {
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this loop could stop at this.memory_size[0].

@russor
Copy link
Contributor Author

russor commented Jan 17, 2024

Thanks!

Testing-wise, I would like to add your OS to the testsuite (in tests/full/run.js). Could you upload a (preferably small) multiboot image?

I hadn't released it yet, but there's a time for everything. The multiboot image is < 1M; it's more interesting if it has the ~20M initrd though... but that's then a bit big. Either way, I'll need to do some cleanup beforehand.

Also, I assume this could also be used to boot Linux kernels. Have you tested that?

I have not. So far, I only tested my OS and the tests in the repo. I'll see what's out there that I can get to boot with this after I address the code comments and remove the bulk of the assembly.

Overall the code looks good. My main bigger suggestion would be to remove the assembly and implement it directly in the io port hook.

This allows the acpi bios support to be used by a multiboot os image.  The
image loading must be done either in the option rom, or triggered by the
option rom, in case the multiboot image needs to be loaded into addresses
that the bios writes to.
@russor
Copy link
Contributor Author

russor commented Jan 17, 2024

I think this addresses most of the comments, but I have some more work to do now; which I'll try to get done over the next few days.

FreeBSD and Linux don't appear to have multiboot kernels (at least the ones I tried)... but NetBSD does.

When attempting to load an image that isn't a multiboot image, at least a proper console message would be appropriate, instead of a TypeError.

When attempting to load NetBSD, it's hitting an assert in this multiboot loader; and I'm going to dig into why, and see if I can fix it. :D (and same for GNU Hurd)

@russor
Copy link
Contributor Author

russor commented Jan 18, 2024

Ok, so NetBSD and GNU Hurd kernels both have virtual address != physical address. I looked around, and it seems like the thing to do is load at the physical address, adjust the entry point address from a virtual address to the physical address and jump to that. I didn't see that in the specification (my kernel, and the v86 unit tests have physical == virtual), but it's what grub does.

With that change, Hurd does something --- lots of debug output from cpuid and friends, but no output on screen or com1 (probably needs some config or command line). Behavior seems similar with or without bios.

NetBSD does start and outputs some boot logs to VGA; then it hits an unexpected overlapped read in ne2k. Excitingly, NetBSD only works if run with SeaBIOS... without a bios, it crashes the emulator with a bad instruction; so that's a good case for me. NetBSD does throw a warning about the memory map, so there's probably improvements to be made there at some point; but I think this is OK for now.

I also tweaked things so multiboot and linux kernel loading don't crash if they fail to load. With seabios, that means it'll try to load something else, which doesn't work, but I think that's reasonable... better than just getting stuck on a error?

Let me know if you want me to squash this into fewer commits, or feel free to adjust as you like.

@russor
Copy link
Contributor Author

russor commented Jan 19, 2024

Testing-wise, I would like to add your OS to the testsuite (in tests/full/run.js). Could you upload a (preferably small) multiboot image?

I've put up https://crazierl.org/crazierl.elf and https://crazierl.org/initrd -- using the initrd, a command line of "kernel /libexec/ld-elf32.so.1" is required, works in my demo page https://crazierl.org/demo.html in case any other parameters are important. Expectation if you boot without initrd is it will start and eventually print "end of kernel!" on vga and com1, and halt. If you boot with the initrd, it should end up with a prompt like "1>" where you can type "5 + 5." and hit enter, and get back 10 and a new prompt.

VGA output is wonky; my demo page uses com1 only. I may provide a future PR to make vga work better; I set the CRTC Offset Register http://www.osdever.net/FreeVGA/vga/crtcreg.htm#13 so text lines are 128 characters in memory (but still 80 on screen), which makes scrolling with wrap around much simpler.

@copy copy merged commit 483a188 into copy:master Jan 22, 2024
3 checks passed
@copy
Copy link
Owner

copy commented Jan 22, 2024

Thanks, merged!

I'll add NetBSD (even though it doesn't fully boot, I believe unrelated to multiboot) and crazierl as tests soon. I'll also add crazierl to the website, as it's pretty cool :-)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants