OK, ich habe zu kompliziert gedacht. Syscalls sollten nicht auf User Pages stehen, da man diese ja via Interrupt im Kernelmodus aufrufen kann.
Ich habe nun vereinfacht und die User-Funktion
direkt aufgerufen und den Kontext mittels Interrupt gewechselt. Hat bestens geklappt!
Multitasking im Wechsel zwischen Supervisor- und User-Segment/-Page läuft hervorragend.
Die Herausforderung besteht aber noch darin, das der "User"-Task nur Funktionen starten kann, die in User Pages stehen. Dazu muss die Startadresse in einem solchen Bereich stehen. Daher habe ich per Linkerskript versucht, nur ein bestimmtes Objektmodul in einer Page zu haben, damit man diese gezielt auf User-Page setzen kann. Das habe ich sinnloserweise mit syscall.o gemacht, wollte das Linkerskript hier mal zeigen, da es nicht völlig trivial ist, falls das mal jemand braucht:
OUTPUT_FORMAT("binary")
ENTRY(KernelStart)
SECTIONS
{
. = 0x8000;
.text : { *(EXCLUDE_FILE(syscall.o).text) }
. = 0xe000;
.text1 : { syscall.o(.text) }
. = 0xf000;
.data : { *(.data) }
.rodata : { *(.rodata) }
.bss : { *(.bss) }
}
.text1 0x0000e000 0xd8
syscall.o(.text)
.text 0x0000e000 0xd8 syscall.o
0x0000e091 _syscall_handler
0x0000e015 _syscall_putch
0x0000e081 _syscall_switch_context
0x0000e061 _syscall_f4
0x0000e051 _syscall_getpid
0x0000e02f _syscall_settextcolor
0x0000e071 _syscall_nop
0x0000e000 _syscall_puts
0x0000f000 . = 0xf000
.data 0x0000f000 0xb8
*(.data)
.data 0x0000f000 0x0 syscall.o
.data 0x0000f000 0x8 ckernel.o
0x0000f004 _address_user
0x0000f000 _ramdisk_start
In diesem Fall eben syscall.o (besser ein user.o) wurde hier sauber zwischen 0xe000 und 0xf000 eingelinkt.
Alles bestens. Nun kann die User-Programm-Welt starten.