Question about CPL/IOPL not working [SOLVED]

Question about which tools to use, bugs, the best way to implement a function, etc should go here. Don't forget to see if your question is answered in the wiki first! When in doubt post here.
Post Reply
User avatar
TyrelHaveman
Member
Member
Posts: 40
Joined: Thu Sep 20, 2007 11:20 pm
Location: Bellingham, WA
Contact:

Question about CPL/IOPL not working [SOLVED]

Post by TyrelHaveman »

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
Last edited by TyrelHaveman on Mon Nov 24, 2008 11:34 am, edited 1 time in total.
User avatar
TyrelHaveman
Member
Member
Posts: 40
Joined: Thu Sep 20, 2007 11:20 pm
Location: Bellingham, WA
Contact:

Re: Question about CPL/IOPL not working

Post by TyrelHaveman »

(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
User avatar
Combuster
Member
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

Post by Combuster »

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
"Certainly avoid yourself. He is a newbie and might not realize it. You'll hate his code deeply a few years down the road." - Sortie
[ My OS ] [ VDisk/SFS ]
User avatar
TyrelHaveman
Member
Member
Posts: 40
Joined: Thu Sep 20, 2007 11:20 pm
Location: Bellingham, WA
Contact:

Re: Question about CPL/IOPL not working

Post by TyrelHaveman »

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
User avatar
TyrelHaveman
Member
Member
Posts: 40
Joined: Thu Sep 20, 2007 11:20 pm
Location: Bellingham, WA
Contact:

Re: Question about CPL/IOPL not working

Post by TyrelHaveman »

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
User avatar
Brendan
Member
Member
Posts: 8561
Joined: Sat Jan 15, 2005 12:00 am
Location: At his keyboard!
Contact:

Re: Question about CPL/IOPL not working

Post by Brendan »

Hi,
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?
To let CPL=3 code access I/O ports there's 4 options:
  • 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.
These methods can be mixed. For example, a kernel's general protection fault handler could emulate the I/O port accesses for a while, and then when you're confident the code is safe (or when the end user is happy?) you could set IOPL to 3 for that task. Also, I wouldn't worry too much about the overhead added to each I/O port access, as I/O port accesses are typically very slow anyway (especially for old ISA devices). Most devices that are designed for speed (e.g. all modern video cards) use memory mapped I/O anyway (e.g. where the device driver accesses the device's registers via. an area in physical memory that's mapped into it's address space with paging, so that I/O ports are entirely avoided).


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.
User avatar
TyrelHaveman
Member
Member
Posts: 40
Joined: Thu Sep 20, 2007 11:20 pm
Location: Bellingham, WA
Contact:

Re: Question about CPL/IOPL not working

Post by TyrelHaveman »

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
User avatar
TyrelHaveman
Member
Member
Posts: 40
Joined: Thu Sep 20, 2007 11:20 pm
Location: Bellingham, WA
Contact:

Re: Question about CPL/IOPL not working

Post by TyrelHaveman »

Sorry again about the double post. :oops: 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!
Post Reply