-
Notifications
You must be signed in to change notification settings - Fork 132
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
Update GDT docs, add user_data_segment function and WRITABLE flag #78
Conversation
Thanks for the pull request! The doc changes look good to me. I'm not sure about the code changes though. According to the AMD64 manual (https://www.amd.com/system/files/TechDocs/24593.pdf), the content of the
And according to section 4.8, the read/write flag is ignored as well:
So adding these flags does not make much sense in my opinion. I'm less sure about the method to create a kernel data segment: data segments still exist in long mode (even if the present field is the only non-ignored part), but the segment registers that reference this data segment are ignored anyway. Or am I missing something? |
For AMD systems, you might be right. However the Intel manual doesn't say anything of the sort. It's hard to know when it's talking about protected mode or long mode sometimes:
I don't see any overriding text for IA-32e mode. Additionally, in my OS, if I don't set the |
As further evidence, without the
|
I've changed the doc comment to mention |
@64 I suggest adding a function for user_data_segment along the kernel_data_segment already added here. Since there is also a user_code_segment already. |
Sorry for taking so long to respond! I looked through the intel manual and found the following relevant sections:
So I'm not quite user what this means for us. The documentation for AMD64 is relatively clear due to the figures, but the Intel documentation leaves much room for interpretation. The bochs error you posted doesn't make things much clearer, as it might also be an implementation detail of bochs (e.g. by simply reusing the 32-bit check function for 64-bit mode). As an experiment, I removed all read/write bits from the 64-bit GDT we set up in the The blog_os project still works for me with this modified bootloader, at least in QEMU. (I don't have access to a pre-UEFI machine right now to test it on real hardware). If you want to try it yourself, simply replace the bootloader dependency with the following: bootloader = { git = "https://github.com/rust-osdev/bootloader.git", branch = "zero-segment-registers", features = ["map_physical_memory"]} |
That's odd... bochs doesn't even complain when I run your version. Will investigate further. |
Actually I guess it makes some sense. It was only complaining when loading an invalid but non-null descriptor. Still, I don't think it should be doing that per the Intel or AMD docs. Do you by any chance know how compatability mode works in long mode? I have a feeling that it involves the GDT and might be relevant to this discussion. |
Yeah, that could be. So segment selector I just tried to load
AFAIK, compatibility mode allows to run 32 bit applications in long mode by switching to a 32-bit GDT segment. |
This seems to suggest that null SS is only valid when not in ring 3. The plot thickens... |
Same is indicated here: https://www.felixcloutier.com/x86/mov#64-bit-mode-exceptions |
Interesting! So it seems like we definitely need a data segment for userspace, as @Darksecond suggested. Are there any differences between a kernel data segment and a userspace data segment or should we just add a general Also, is the read/write flag required for a kernel/user data segment? The links you provided indicate yes. Does it have any effect on code segments (i.e. makes them (non-)readable)? Either way, we should probably add some documentation that explains
|
…nt register usage
Not sure exactly what you'd like me to say for this. |
Thanks for the update! Looks very good!
I just thought of how the AMD manual, the Intel manual and the bochs implementation somewhat disagree whether the |
@@ -125,6 +158,8 @@ pub enum Descriptor { | |||
bitflags! { | |||
/// Flags for a GDT descriptor. Not all flags are valid for all descriptor types. | |||
pub struct DescriptorFlags: u64 { | |||
/// For data segments, this flag sets the segment as writable. Ignored for code segments. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Are we sure that the flag is ignored for code segments? The AMD manual says so, but it also says that the flag is ignored for data segments, which seems to be wrong on some platforms. I think we should at least cite the manual as source.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think part of the confusion is that the CPU doesn't check certain fields when the segment is used during a memory reference, but does check those fields when loading in a new value to a segment register. See the wording from the AMD manual, 4.8.1:
In Figure 4-20, gray shading indicates the code-segment descriptor fields that are ignored in 64-bit mode when the descriptor is used during a memory reference.
I'm going to read a bit further and get back to you on this, because I doubt there's any straight up mistakes here - just manual ambiguity and bad writing.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ah, that seems to be a reasonable explanation. Thanks!
Looks good to me. Let's get this finally merged! bors r+ |
Build succeeded
|
Released as version 0.7.2 |
Diff should be fairly self-explanatory.