Skip to content

Add a builder to multiboot2 #133

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

Merged
merged 20 commits into from
Jun 19, 2023
Merged

Add a builder to multiboot2 #133

merged 20 commits into from
Jun 19, 2023

Conversation

YtvwlD
Copy link
Contributor

@YtvwlD YtvwlD commented Apr 17, 2023

Hey, I'm currently working on adding Multiboot 2 support to a bootloader (towboot) and while using the multiboot2 and multiboot2-header crates, I encountered some pieces that were missing.

I particular:

  • I added more getters to multiboot2-header (mostly inspired by the ones in multiboot2).
  • I added a builder to multiboot2 (inspired by multiboot2-header).
  • I added the SMBIOS tag.
  • I added a function to find a header in a given (file) slice.

This is mostly just boilerplate, but there were two bigger problems I had to work around:

  1. The memory map is only really accurate after exiting Boot Services, but then the bootloader can't allocate anymore.

I've solved this by prefilling the memory map tags with empty entries and overwriting them later on. It seems to work, but it's not pretty.

  1. Most tags are dynamically sized. The previous implementation had them fixed-size in Rust and let the content dangle behind them. I think this is a bit weird and it doesn't work when you try to allocate new structs.

I made them dynamically sized – which is worse to handle in Rust (you can't put them on the stack anymore).
In addition, since the ptr_metadata feature is currently unstable, I used the slice methods instead. (You can probably revert 800567f once it's stable).

I tried to adjust the tests and add some where appropriate. If that's not enough, I'll add more. :)

There's one test that fails for me on stable Rust (rustc 1.68.0 (2c8cc3432 2023-03-06)), though it works on nightly (rustc 1.70.0-nightly (900c35403 2023-03-08)).

I tried to keep the changes small. I think eg. that it would be nicer if Multiboot2Header::from_addr returned a Result, but I didn't change it

@phip1611
Copy link
Member

Hi @YtvwlD
Thanks very much for working on this. I'm in big favor of the new functionality. Can you please rebase your changes onto the latest main branch? I refrain from merging any other breaking stuff, until we get this thing merged - to keep things simple.

I will have a more detailed look in the upcoming days.

@phip1611 phip1611 self-assigned this Apr 17, 2023
@phip1611 phip1611 self-requested a review April 17, 2023 11:10
@YtvwlD
Copy link
Contributor Author

YtvwlD commented Apr 22, 2023

That's great to hear. :)

I've tried rebasing this on Monday, but it didn't compile afterwards, sadly. I hope to be able to do it this weekend.

@YtvwlD
Copy link
Contributor Author

YtvwlD commented Apr 24, 2023

So, this took a bit longer than expected. :)
The one test sadly still only works with some compilers (though it seems to work on stable and fail on nightly in the CI, interesting).

I've removed cast_tag after the rebase because rustc doesn't seem to support generic casts over dynamically sized types? Here's what I was getting:

error[E0606]: casting `*const Tag` as `*const T` is invalid
   --> multiboot2/src/tag_type.rs:307:20
    |
307 |         unsafe { &*(self as *const Tag as *const T) }
    |                    ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
    = note: vtable kinds may not match

(I've tried to put a minimal example in the playground.)

@phip1611
Copy link
Member

I've removed cast_tag after the rebase because rustc doesn't seem to support generic casts over dynamically sized types?

Yes, because DSTs uses fat pointers. This is also an existing problem in the multiboot2 crate. I plan to refactor this eventually - If I find some time.. One can fix this with https://crates.io/crates/ptr_meta for example.

@phip1611
Copy link
Member

But I', not sure how you can encounter this issue after you rebased your code. I think I didn't change anything in that regard

@YtvwlD
Copy link
Contributor Author

YtvwlD commented Apr 27, 2023

cast_tag didn't exist before the rebase. Each getter had its own cast.

@phip1611
Copy link
Member

Ah yes, totally right. I broke the API with that change... the right solution would be to remove cast_tag() and properly support DSTs... a quick fix for you might be to add something like find_tag next to get_tag that has the right semantics. This way, you could make your code compile.

@YtvwlD
Copy link
Contributor Author

YtvwlD commented Apr 27, 2023

ah, I've just reverted the two commits that added it (the last two commits in this PR).

@YtvwlD
Copy link
Contributor Author

YtvwlD commented Apr 28, 2023

The msrv fail is because alloc::ffi is only available since Rust 1.64. Any ideas on what to do about that?

@YtvwlD YtvwlD mentioned this pull request Apr 28, 2023
@phip1611
Copy link
Member

phip1611 commented Apr 28, 2023

I started working on DSTs which should fix your

error[E0606]: casting `*const Tag` as `*const T` is invalid
   --> multiboot2/src/tag_type.rs:307:20
    |
307 |         unsafe { &*(self as *const Tag as *const T) }
    |                    ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
    = note: vtable kinds may not match

problem. What do you think about my changes in #132 ? We could also merge your PR first and I adapt it then to my changes. But I'd like to hear if the new API would work in your case. I still hadn't much time to look into your code, unfortunately

The msrv fail is because alloc::ffi is only available since Rust 1.64. Any ideas on what to do about that?

I don't have anything against a MSVR bump, but I do not see a benefit in using this abstraction here. Multiboot2 strings and Rust strings are guaranteed to be valid UTF-8, CStrings are not. So I think it would be better to use regular Rust strings and push a final \0 byte onto the rust string. When the data is serialized (with .as_bytes()), the terminating null will be included.

PS: I don't quite understand at this point why your DST additions compile and why you do not have the fat pointer cast problem.

@phip1611 phip1611 closed this Apr 28, 2023
@phip1611 phip1611 reopened this Apr 28, 2023
@YtvwlD
Copy link
Contributor Author

YtvwlD commented Apr 28, 2023

I don't have any problems with fat pointers (anymore), because here, Tag is unsized, too. Casting Tag to eg. BootLoaderNameTag works out of the box. (Unless that cast is generic, then the vtable compiler error occurs.)

Casting raw bytes to a struct still requires explicit fat pointers, though (as can be seen in the tests for BootLoaderNameTag).

Having a from_base_tag method in a trait might be better than me just removing cast_tag, though.

I'd rebase this PR to keep using [u8] for strings then, but it'll probably make more sense for you to look into it, first?

@phip1611
Copy link
Member

phip1611 commented Apr 29, 2023

I'm on vacation right now, so I won't have much capacity for more review in the next 7 days.

But overall, the changes look good and I'm looking forward to merging them soon!

@YtvwlD
Copy link
Contributor Author

YtvwlD commented Apr 29, 2023

Have fun. :)

@phip1611 phip1611 marked this pull request as draft May 6, 2023 13:37
@phip1611
Copy link
Member

phip1611 commented May 6, 2023

I've had time to review everything. I converted this MR as draft, as there are several points to address before getting this merged. I hope I do not make the contribution process for you too frustrating or so, but this PR is in its current state to big to pass the review process.

I'd prefer to have dedicated PRs for the following things:

  • add missing functionality in multiboot2-header
    • find the header
    • add getter for the tags
    • that module align thingy
  • add missing tags in multiboot2
    • add smbios tag
    • add basic memory info tag
  • add multiboot2 MBI builder
  • mutable references to the mbi (this one is controversial to me, so a dedicated MR where we can discuss)

I think, and as you already said, that the DST approach I took in #132 is more mature. Maybe you can have a look there and tell me if it would work with your contribution. Then we merge it and you can rebase your code onto those changes.

I'd highly appreciate if you can address (at least some of) my concerns and improvement suggestions. Otherwise, I'd assist you and do (some) of the work myself.

Don't get me wrong, U'm are very happy of merging the changes. But this PR is just to big.

PS: You live/are from germany? Wir können auch gerne in nem Video Call oder so bequatschen, wie wir hier am besten weiter machen :D

@YtvwlD
Copy link
Contributor Author

YtvwlD commented Jun 4, 2023

Do we want a EFIMemoryDesc::new? I'm currently just transmuting the ones from the firmware into it (well, and checking the size), but I'm not sure if that's the right way.

Copy link
Member

@phip1611 phip1611 left a comment

Choose a reason for hiding this comment

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

LGTM. Thanks! Please address that one single remark regarding the sections(n) method.

Copy link
Member

@phip1611 phip1611 left a comment

Choose a reason for hiding this comment

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

Thanks for working on this. I'm glad we finally can merge it.

I address some open issues and then going to release it in a couple of days.

@phip1611 phip1611 merged commit 714905b into rust-osdev:main Jun 19, 2023
@YtvwlD
Copy link
Contributor Author

YtvwlD commented Jun 19, 2023

Thanks, but I'd still like to talk about modifying the memory map. 🙃

@YtvwlD YtvwlD deleted the bootloader branch June 19, 2023 11:17
@YtvwlD YtvwlD restored the bootloader branch June 19, 2023 11:17
@YtvwlD YtvwlD deleted the bootloader branch June 19, 2023 11:17
@phip1611
Copy link
Member

Via git bisecting, I could find that you might have broke something with commit d198dce

Since then, the debug print of the MBI doesn't work anymore and operates on wrong memory. I guess, some pointer magic is now wrong. I try to trace it down and create a unit test for it :)

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