Ich bin zunächst zu einer funktionierenden Version mit Endlos-while-Schleife beim Aufruf der Funktion zurück gekehrt, um den user mode mit der neuen Erkenntnis mit ss und esp vor eflags zu testen, und es geht! Ich bin sogar etwas verblüfft.
void test5()
{
while(TRUE)
{
syscall_puts("5");
//puts("5");
}
}
task_t* task2 = create_task (f2,0); // function moo in kernel
task_t* task3 = create_task (f3,0); // function baa in kernel
task_t* task4 = create_task2(f4,0,4,2); // function ... in kernel
task_t* task5 = create_task (test5,3); // <=== user mode !!!
task_t* task6 = create_task2(test6,0,ramdisk_start+(ULONG)&prog_start-(ULONG)&file_data_start,0);
task_t* create_task(void* entry, UCHAR privilege)
{
cli();
page_directory_t* directory = clone_directory(current_directory);
task_t* new_task = (task_t*)k_malloc(sizeof(task_t),0,0);
new_task->id = next_pid++;
new_task->page_directory = directory;
new_task->kernel_stack = k_malloc(KERNEL_STACK_SIZE,1,0)+KERNEL_STACK_SIZE;
new_task->next = 0;
task_t* tmp_task = (task_t*)ready_queue;
while (tmp_task->next)
tmp_task = tmp_task->next;
tmp_task->next = new_task; // ... and extend it
ULONG* kernel_stack = (ULONG*) new_task->kernel_stack;
ULONG code_segment=0x08, data_segment=0x10;
if(privilege == 3)
{
//Intel 3A Chapter 5.12
*(--kernel_stack) = new_task->ss = 0x23; // ss
*(--kernel_stack) = new_task->kernel_stack; // esp0
code_segment = 0x1B; // 0x18|0x3=0x1B
}
*(--kernel_stack) = 0x0202; // eflags = interrupts activated and iopl = 0
*(--kernel_stack) = code_segment; // cs
*(--kernel_stack) = (ULONG)entry; // eip
*(--kernel_stack) = 0; // error code
*(--kernel_stack) = 0; // interrupt nummer
// general purpose registers w/o esp
*(--kernel_stack) = 0;
*(--kernel_stack) = 0;
*(--kernel_stack) = 0;
*(--kernel_stack) = 0;
*(--kernel_stack) = 0;
*(--kernel_stack) = 0;
*(--kernel_stack) = 0;
if(privilege == 3) data_segment = 0x23; // 0x20|0x3=0x23
*(--kernel_stack) = data_segment;
*(--kernel_stack) = data_segment;
*(--kernel_stack) = data_segment;
*(--kernel_stack) = data_segment;
//setup TSS
tss_entry.ss0 = 0x10;
tss_entry.esp0 = new_task->kernel_stack;
tss_entry.ss = data_segment;
//setup task_t
new_task->ebp = 0xd00fc0de; // test value
new_task->esp = (ULONG)kernel_stack;
new_task->eip = (ULONG)irq_tail;
new_task->ss = data_segment;
sti();
return new_task;
}
Das läuft, aber etwas seltsam. Die 5 wird immer nur einmal ausgegeben.
Offenbar passiert da etwas seltsames, muss ich im Debugger genau sehen. Denn dieses einmalige Ausführen einer Funktion möchte ich ja gerade erreichen.
EDIT: Habe mir das im Debugger angeschaut. Als Rücksprungadresse des syscalls im Interrupt ist test6 enthalten, weil ich ja beim syscall z.Z. automatisch einen direkten Taskwechsel habe. Streiche ich das while, dann klappt es mindestens ein Mal, dann kommt aber wieder PF mit dem magic code, wie bereits vorne mit dem Debugger intensiv untersucht, aber leider noch nicht gelöst.
44444444444444444444444444444444444444444444444444444444444444444444444444444444
45 666666666666666666666666666666666666666666666666666666666666666666666666666666
Dass es sich wirklich um User Mode handelt, sieht man, wenn man nicht syscall_puts, sondern puts verwendet:
44444444444444444444444444444444444444444444444444444444444444444444444444444444
4444444444444444444
Page Fault ( read-only - write operation user-mode) at 000B8C06h - EIP: 00008986h
Was mich verblüfft, ist, dass ich test5(...) im Kernel aufrufen kann. ich hatte extra syscall_test5 produziert. Aber offensichtlich erfolgt die Umschaltung auf Ring 3 etwas später in create_task, so dass man test5 als Einsprung-Adresse verwenden kann.
Endlich user mode!
Code:
http://www.henkessoft.de/OS_Dev/Downloads/20090522_43_user_mode.zipDas Umschalten des Tasks durch syscall kann man natürlich leicht unterbinden, was ich auch inzwischen gemacht habe:
ULONG fault_handler(ULONG esp)
{
ULONG retVal;
struct regs* r = (struct regs*)esp;
if(!pODA->ts_flag)
retVal = esp;
else
{
if(r->int_no == 127) //syscall
retVal = esp;
else
retVal = task_switch1(esp); //new task's esp
}
//...
if (r->int_no == 127) //sw-interrupt syscall
{
syscall_handler(r);
}
return retVal;
}
4444444444444444444444444444444444444444444444444444444444444444444444444444444
5555555555555555555555555555555555555555555555555555555555555555555555555555555
555555555555555555555555555555555555555555555555
66666666666666666666666666666666666666666666666666666666666666666666666666666666