I'm trying to write a system call that will demote the running task from ring 0 to ring 3.
I have one TSS descripter and have software task switching that works when just switching between ring 0 tasks.
I can fork() from my kernel proc, but i want to demote it to ring 3, so I do a system call, change the CS, DS ES... to the User mode ones, (my interrupt handlers pass these values as a structure, then I return (iret) from the system call.
However I get a GPF because the CS is wrong, the DS, ES and so on are correct, but the eip, cs & eflags are wrong (it appears that the system has inserted these 3 values, as after these three values are the correct values..
Am I missing something? Is there more I have to change in my demote syscall? I have read the Context Switching FAQ, but can't seem to figure this out.
my isr looks like this:
Code: Select all
syscall_irq:
cli
push byte 0
push byte 48
jmp irq_common_stub
extern irq_handler
extern current
extern morts_tss
irq_common_stub:
cld
pushad
push ds
push es
push fs
push gs
mov eax,[current]
mov [eax],esp
mov eax, 0x10
mov ds, eax
mov es, eax
mov fs, eax
mov gs, eax
push esp
call irq_handler
mov eax,[current] ;put adress of struct of current process in eax.
mov esp,[eax] ;restore adress of esp.
mov ebx,[eax+8];put content of the k-stack field into ebx.
mov [morts_tss+4],ebx ;update system tss. (esp)
mov ebx, [eax+4]
mov [morts_tss+8],ebx ; (ss)
mov ebx, [eax+20]
mov cr3, ebx
pop gs
pop fs
pop es
pop ds
popad
add esp, 8
iret
Code: Select all
struct regs {
unsigned int gs;
unsigned int fs;
unsigned int es;
unsigned int ds;
unsigned int edi;
unsigned int esi;
unsigned int ebp;
unsigned int esp;
unsigned int ebx;
unsigned int edx;
unsigned int ecx;
unsigned int eax;
unsigned int int_no;
unsigned int err_code; /* our 'push byte #' and ecodes do this */
unsigned int eip;
unsigned int cs;
unsigned int eflags;
unsigned int useresp;
unsigned int ss; /* pushed by the processor automatically */
};
Code: Select all
int sys_demote(struct regs *r) {
r->cs = 0x18;
current->ss = r->ss = r->es = r->gs = r->fs = r->ds = 0x20;
return 0;
}
any help would be really appreciated, i'm quite stuck
thanks.
andrew