Hi,
Pype.Clicker wrote:(hm. i know if one wants to use segment 0x20 from ring3, it actually *must* use selector 0x23. I'm unsure about whether ring0 will be happy with 0x23 or if it wants 0x20)
The rules for accessing data segments are:
A) the CPL (the lowest 2 bits of both CS and SS) and the RPL (the data segment's lowest 3 bits) must both be numerically lower or equal to the descriptors DPL.
B) the CPL (the lowest 2 bits of both CS and SS) must be numerically lower or equal to the RPL (the data segment's lowest 3 bits)
If either of these aren't satisfied, then you'll get a GPF.
For data segments (DS, ES, FS and GS) all CPL=0 code will be happy with RPL = 3 segments, so for a "flat paging" OS it's possible to load the data segment registers with something like 0x23 and never change them for any reason (forget they exist completely). This works fine for compiler generated code, but things like protected mode BIOS interfaces (VBE, APM, etc) and virtual 8086 make a mess of it (it forces you to save and load the data segment registers for IRQ handlers at least, although this is automatic for virtual 8086 IIRC).
The stack segment (SS) is entirely different - the lowest 2 bits of SS must always be equal to the lowest 2 bits of CS.
There are minor things I'd change with the code posted, but nothing I can find that would prevent it from working.
For e.g.:
There is absolutely no reason for the "cli" at the start of the stub. If you actually do want to prevent the kernel from being interrupted then use an interrupt gate (but be very careful that nothing in your kernel stuffs up interrupt latency too badly). IMHO it's better to leave interrupts enabled and then disable them if necessary where necessary.
I'd also change:
Code: Select all
mov eax, esp
push eax
mov eax, fault_handler
call eax
pop eax
To the functionally equivelent:
Code: Select all
push esp
call fault_handler
add esp,4
To be honest, I'm not sure why you'd want to call a routine called "fault_handler" when the kernel API isn't a fault (perhaps "call common_isr" might be a better name).
Then I'd be concerned with how common the "isr_common_stub" actually is, but I've always disliked this approach. To me (the kernel API and exception handlers), ignoring the CPU's call table (better known as the IDT) and then implementing your own call table just after it is just a waste of CPU time. It's good for IRQ handlers, but not much else (but I haven't slept for over 20 hours, so I should probably be quite). Anyway, I'd do something like:
Code: Select all
; 48 : 30h System Call
isr48:
pusha
; push ds
; push es
; push fs
; push gs
push esp
call kernel_API
add esp,4
; pop gs
; pop fs
; pop es
; pop ds
popa
add esp, 8
iret
Despite all of this, I still see nothing wrong with the code originally posted (nothing that would cause a GPF). I expect the problem is in the GDT, the IDT, or the "fault_handler" code.
Cheers,
Brendan