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

add set_general_handler macro #285

Merged
merged 9 commits into from
Nov 7, 2021

Conversation

Freax13
Copy link
Member

@Freax13 Freax13 commented Jul 26, 2021

This pr adds the set_general_handler! macro to set a general handler in an idt using only macro_rules. It's an alternative to #168 and all of the tests are taken from it.

As already mentioned in #167 (comment) there are no loops in macro_rules macros, so I used recursion instead:
https://github.com/Freax13/x86_64/blob/8252697d6ef5b567ff6a8110656f9a50e00df051/src/structures/idt.rs#L936-L956

I believe this to be a relatively short and concise solution. The only major drawback with this approach is that we can't do the range checks a compile time, so the macro always has to expand to setting all 256 interrupts even if some of those will be skipped at runtime. The upside of this approach is that the range doesn't necessarily need to be known at compile time (set_general_handler! takes $range as an expression).

Closes #167

@Freax13
Copy link
Member Author

Freax13 commented Jul 26, 2021

I'm not sure why ci is failing as I can't reproduce the error (running in a windows vm).

I think I managed to track down where the error is reported though:
Line 872 in https://llvm.org/doxygen/MCStreamer_8cpp_source.html

@josephlr
Copy link
Contributor

I'm not sure why ci is failing as I can't reproduce the error (running in a windows vm).

If you change the generic handler function to be extern "C" does that fix the error?

Copy link
Contributor

@josephlr josephlr left a comment

Choose a reason for hiding this comment

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

This is a cool idea, I'm wondering if we can make the macros less complex.

($idt:expr, $handler:ident, $range:expr) => {{
fn set_general_handler(
idt: &mut $crate::structures::idt::InterruptDescriptorTable,
range: impl core::ops::RangeBounds<usize>,
Copy link
Contributor

Choose a reason for hiding this comment

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

Why not a range of u8? This removes the concerns about out of bounds indexing.

Copy link
Member Author

Choose a reason for hiding this comment

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

Currently InterruptDescriptorTable only uses usize for indexing operations and doesn't allow indexing with u8, so I tried to mirror that api. I agree that using u8 would make more sense. Perhaps we should also implement Index<u8> and IndexMut<u8> for InterruptDescriptorTable in a seperate pr.

Copy link
Member

Choose a reason for hiding this comment

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

The problem with implementing both Index<u8> and Index<usize> might be that type annotations are required in more cases. For example, idt[20] leads to the non-helpful error message "idt::InterruptDescriptorTable cannot be indexed by i32" because integer literals default to i32 in these cases.

However, I'm happy to change the Index impl from usize to u8 in the next breaking release. We should do this separately though, since this PR is a non-breaking change otherwise. We can of course already use u8 for the macro if we want.

src/structures/idt.rs Show resolved Hide resolved
/// use x86_64::structures::idt::{InterruptDescriptorTable, InterruptStackFrame};
///
/// let mut idt = InterruptDescriptorTable::new();
/// fn my_general_handler(
Copy link
Contributor

Choose a reason for hiding this comment

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

If we are going to impose such a constraint, we should define the relevant function pointer type, and have the macro check that the function passed is actually of the correct type.

Copy link
Member Author

Choose a reason for hiding this comment

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

I agree, I'll add that next

src/structures/idt.rs Show resolved Hide resolved
@Freax13
Copy link
Member Author

Freax13 commented Jul 27, 2021

I'm not sure why ci is failing as I can't reproduce the error (running in a windows vm).

If you change the generic handler function to be extern "C" does that fix the error?

No, it's still failing with the same error

@phil-opp phil-opp added the waiting-for-review Waiting for a review from the maintainers. label Nov 6, 2021
Copy link
Member

@phil-opp phil-opp left a comment

Choose a reason for hiding this comment

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

Sorry for the long delay since the last review iteration. This adds quite a bit of macro trickery, which makes it less readable than #168, but keeping the proc macro dependencies out is worth it in my opinion. The only concern I had are the error messages, but they don't seem much worse than the proc macro errors.

Was https://github.com/rust-osdev/x86_64/pull/285/files#r677279319 resolved? It doesn't seem to point to the right part of the source code anymore (or I don't understand what it is about).

From my side this is ready to be merged. Thanks a lot for your work!

@phil-opp phil-opp added waiting-on-author Waiting for the author to act on review feedback. and removed waiting-for-review Waiting for a review from the maintainers. labels Nov 6, 2021
@Freax13 Freax13 changed the base branch from next to master November 7, 2021 12:42
@Freax13
Copy link
Member Author

Freax13 commented Nov 7, 2021

I finally figured out how to do a proper rebase from next to master 🥳:

git rebase --onto upstream/master upstream/next

Let's hope that in the future I will know ahead of time whether something is breaking the api and never have to use this git command again.

@Freax13
Copy link
Member Author

Freax13 commented Nov 7, 2021

The only concern I had are the error messages, but they don't seem much worse than the proc macro errors.

8695b39 makes the errors pretty well behaved. For example adding an invalid parameter to a general handlers only results in this single error message:

error[E0308]: mismatched types
  --> src/structures/idt.rs:1144:1
   |
19 | set_general_handler!(&mut idt, my_general_handler, 14);
   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ incorrect number of function parameters
   |
   = note: expected fn pointer `fn(InterruptStackFrame, u8, Option<u64>)`
                 found fn item `fn(InterruptStackFrame, u8, Option<u64>, u16) {my_general_handler}`
   = note: this error originates in the macro `$crate::set_general_handler` (in Nightly builds, run with -Z macro-backtrace for more info)

Was https://github.com/rust-osdev/x86_64/pull/285/files#r677279319 resolved? It doesn't seem to point to the right part of the source code anymore (or I don't understand what it is about).

I completely forgot about that thanks for reminding me! It's now fixed.

@Freax13
Copy link
Member Author

Freax13 commented Nov 7, 2021

I'm not sure why ci is failing as I can't reproduce the error (running in a windows vm).

If you change the generic handler function to be extern "C" does that fix the error?

No, it's still failing with the same error

This time the compiler on windows just straight up segfaulted: https://github.com/rust-osdev/x86_64/runs/4130900835?check_suite_focus=true#step:16:23

@phil-opp
Copy link
Member

phil-opp commented Nov 7, 2021

Oh wow, sounds like a bug in rustc. I'll try to look into it.

@phil-opp
Copy link
Member

phil-opp commented Nov 7, 2021

Ok, I think this is a bug in the x86-interrupt calling convention in LLVM. I'm not sure where the error occurs exactly, but my guess is at https://github.com/llvm/llvm-project/blob/e356027016c6365b3d8924f54c33e2c63d931492/llvm/lib/MC/MCStreamer.cpp#L874. The "error: offset is not a multiple of 16" message is interpreted as a warning by rustc in the CI run you linked, that's why I didn't notice it at first.

Since the x86-interrupt calling convention isn't typically used on Windows-based systems (or systems with an underlying OS in general), it's probably not worth the effort to try to fix this in LLVM. So let's just annotate the default_handlers test with a #[cfg(not(windows))] and add a comment that explains why (including a link to this thread/comment).

@phil-opp
Copy link
Member

phil-opp commented Nov 7, 2021

Thanks again for all your work on this!

@phil-opp phil-opp mentioned this pull request Dec 18, 2021
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
waiting-on-author Waiting for the author to act on review feedback.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Allow user provided function for Missing Entries in IDT
3 participants