Alrighty, to prefix I've got a mostly working multitasking kernel with floppy driver, ATA driver, serial driver, and some other things. For now I've been running everything as part of the kernel... sort of...
I have 4 segment descriptors in the GDT, in this order: kernel code (0x08), kernel data/stack (0x10), user code (0x18), user data/stack (0x20) (and they're all base 0 limit 4 gig). For now I have a single page directory & table that just identity maps the first 2 MB of the physical address space.
So far, in all of my threads (there are exactly 3, init, gui thread (I'm in a VESA mode), and an idle thread), I've been setting (in my stack image at thread creation) CS to 0x1B, and SS, DS, etc to 0x23. That is, the "user" segments with CPL=3, I believe. I'm also setting IOPL=3, thus these threads can use IO. And everything is great.
The problem is, I don't want IOPL=3, I'd like IOPL=0 and for the three threads (especially init, since it accesses hardware directly as it sets up drivers and things) and for them to run as CPL 0.... in other words, I want these to be ring 0 threads, not ring 3 threads (which happen to be able to do IO, sti and cli) as they are now.
So I changed my initial stack image for these threads to use CS 0x08, SS, DS etc 0x10. For now I left the IOPL at 3 in EFLAGS. For some reason these threads don't run. I also tried CS 0x18 and SS, DS etc 0x20 (the user mode segments, but with CPL=0). They still don't run. Specifically, I'm getting a GPF with error code 3. And I haven't changed the IOPL.
The kernel code itself runs in CS 0x08, SS, DS etc 0x10 just fine. So I don't understand why I can't set that for this stuff...
Let me know if I can provide any additional details.
Any ideas?
Thanks,
Tyrel
Question about CPL/IOPL not working [SOLVED]
- TyrelHaveman
- Member
- Posts: 40
- Joined: Thu Sep 20, 2007 11:20 pm
- Location: Bellingham, WA
- Contact:
Question about CPL/IOPL not working [SOLVED]
Last edited by TyrelHaveman on Mon Nov 24, 2008 11:34 am, edited 1 time in total.
- TyrelHaveman
- Member
- Posts: 40
- Joined: Thu Sep 20, 2007 11:20 pm
- Location: Bellingham, WA
- Contact:
Re: Question about CPL/IOPL not working
(Sorry, double post)
Here's a little bit more info:
If I use the user-mode segments but specify CPL 0 in CS, it blows up because the CPL in the segment selector and the segment descriptor to not match (according to Bochs). That makes sense. I won't do that.
So, if I use the kernel-mode segments, 0x08 and 0x10, I get this:
00078718608e[CPU0 ] fetch_raw_descriptor: GDT: index (3207)640 > limit (2f)
Any idea where that might be coming from? Should I be doing something "different" with ring 0 threads than ring 3 threads somewhere?
Thanks again!
Tyrel
Here's a little bit more info:
If I use the user-mode segments but specify CPL 0 in CS, it blows up because the CPL in the segment selector and the segment descriptor to not match (according to Bochs). That makes sense. I won't do that.
So, if I use the kernel-mode segments, 0x08 and 0x10, I get this:
00078718608e[CPU0 ] fetch_raw_descriptor: GDT: index (3207)640 > limit (2f)
Any idea where that might be coming from? Should I be doing something "different" with ring 0 threads than ring 3 threads somewhere?
Thanks again!
Tyrel
- Combuster
- Member
- Posts: 9301
- Joined: Wed Oct 18, 2006 3:45 am
- Libera.chat IRC: [com]buster
- Location: On the balcony, where I can actually keep 1½m distance
- Contact:
Re: Question about CPL/IOPL not working
If you do stack switching then there is a big difference between ring 0 state frames and ring 3 state frames - most notably, SS and ESP do *not* get popped on an IRET when there's no change in privilege level. (and in reverse, the kernel uses the same stack as the thread itself)
Also, the only "feature" of ring 0 is that you can modify control registers, and you don't need those to access hardware (which goes via port I/O and memory mapped devices) for which any other ring will do as well, so I'm missing part of the story there on what you actually want to do with the ring 0 privileges
Also, the only "feature" of ring 0 is that you can modify control registers, and you don't need those to access hardware (which goes via port I/O and memory mapped devices) for which any other ring will do as well, so I'm missing part of the story there on what you actually want to do with the ring 0 privileges
- TyrelHaveman
- Member
- Posts: 40
- Joined: Thu Sep 20, 2007 11:20 pm
- Location: Bellingham, WA
- Contact:
Re: Question about CPL/IOPL not working
Thanks Combuster.
First of all, thanks for the info regarding IRET when there's no change in privilege level. I figured it had to be something like that, but wasn't sure.
As far as why I want ring 0 code... now that I think about it, I guess all I really wanted was some code to be able to do port I/O and access specific parts of physical memory, while other code (user mode programs) cannot do that. I guess that could be accomplished in ways other than using ring 0 for the I/O code, like changing the I/O map in the single TSS to allow/disallow ports on task switch, but that seems expensive. Or I could use ring 1 for the I/O code. Or something. I think I've just confused myself a bit. If there's a page on the wiki or post in the forums that explains this well, that I somehow missed, please let me know.
I don't think you're missing part of the story, Combuster, I think I am.
Thanks,
Tyrel
First of all, thanks for the info regarding IRET when there's no change in privilege level. I figured it had to be something like that, but wasn't sure.
As far as why I want ring 0 code... now that I think about it, I guess all I really wanted was some code to be able to do port I/O and access specific parts of physical memory, while other code (user mode programs) cannot do that. I guess that could be accomplished in ways other than using ring 0 for the I/O code, like changing the I/O map in the single TSS to allow/disallow ports on task switch, but that seems expensive. Or I could use ring 1 for the I/O code. Or something. I think I've just confused myself a bit. If there's a page on the wiki or post in the forums that explains this well, that I somehow missed, please let me know.
I don't think you're missing part of the story, Combuster, I think I am.
Thanks,
Tyrel
- TyrelHaveman
- Member
- Posts: 40
- Joined: Thu Sep 20, 2007 11:20 pm
- Location: Bellingham, WA
- Contact:
Re: Question about CPL/IOPL not working
Oh wait... (sorry about double post again!)
I guess all I need to do is have all threads ring 3, and those that I want to access I/O, set IOPL in EFLAGS to 3... Those that I do not want to access I/O, just set IOPL in EFLAGS to 0. Is that it?
Tyrel
I guess all I need to do is have all threads ring 3, and those that I want to access I/O, set IOPL in EFLAGS to 3... Those that I do not want to access I/O, just set IOPL in EFLAGS to 0. Is that it?
Tyrel
Re: Question about CPL/IOPL not working
Hi,
Cheers,
Brendan
To let CPL=3 code access I/O ports there's 4 options:TyrelHaveman wrote:I guess all I need to do is have all threads ring 3, and those that I want to access I/O, set IOPL in EFLAGS to 3... Those that I do not want to access I/O, just set IOPL in EFLAGS to 0. Is that it?
- Provide kernel API functions for I/O port access (so CPL=3 calls kernel, kernel checks permissions and does the I/O port access and returns the info). This doesn't add any overhead to the task switch code and can provide complete protection (e.g. a task can be given access to some I/O ports but not others), but it does add overhead to each I/O port access.
- Kernel uses I/O permission bitmap in the TSS to give the task access to some I/O ports. This method also provides complete I/O port protection and doesn't add any overhead to each I/O port access, but it does add overhead to the task switch code.
- Kernel changes the IOPL during task switches to give tasks access to none or all I/O ports. This method doesn't add any overhead to each I/O port access and only adds a tiny bit of overhead to the task switch code, but it doesn't provides complete I/O port protection (e.g. an untrusted floppy disk driver needs access to a few I/O ports, therefore you need to give it access to all I/O ports and it can completely trash everything).
- Kernel has code in it's general protection fault handler that emulates I/O port accesses; so that CPL=3 code tries to do an I/O port access and causes an exception, and the kernel's exception handler checks permissions and either refuses or emulates the I/O port access (does the I/O port access on behalf of the CPL=3 code). This method doesn't add any overhead to the task switch code and provides complete I/O port protection, but it adds the most overhead to each I/O port access.
Cheers,
Brendan
For all things; perfection is, and will always remain, impossible to achieve in practice. However; by striving for perfection we create things that are as perfect as practically possible. Let the pursuit of perfection be our guide.
- TyrelHaveman
- Member
- Posts: 40
- Joined: Thu Sep 20, 2007 11:20 pm
- Location: Bellingham, WA
- Contact:
Re: Question about CPL/IOPL not working
Thanks very much Brendan! That is extremely helpful. I think for now to keep it easy I'll stick with setting IOPL = 3 in the processes that need it.
By the way, is this info already in the wiki somewhere and I perhaps missed it? If it isn't, I think it would be valuable to add.
Thanks again Brendan and Combuster.
Tyrel
By the way, is this info already in the wiki somewhere and I perhaps missed it? If it isn't, I think it would be valuable to add.
Thanks again Brendan and Combuster.
Tyrel
- TyrelHaveman
- Member
- Posts: 40
- Joined: Thu Sep 20, 2007 11:20 pm
- Location: Bellingham, WA
- Contact:
Re: Question about CPL/IOPL not working
Sorry again about the double post. I just wanted to mention that thanks to your help with this (plus other forum threads, the wiki, and my wonderful hard-copies of the Intel manuals) I also made another leap this evening and got paging working on my OS.
Thanks!
Thanks!