Zitat
0x0000839b - Da musst du die größte Adresse suchen, die kleiner ist als diese (oder gleich).kernel.map:
Zitat
0x000083a0 _test1
0x0000836e _test
0x00008330 _surprise
Das wäre dann also test?
09. November 2026, 18:29
Gespeichert 0x0000839b - Da musst du die größte Adresse suchen, die kleiner ist als diese (oder gleich).kernel.map:
0x000083a0 _test1
0x0000836e _test
0x00008330 _surprise
Gespeichert void moo()
{
while(TRUE)
{
settextcolor(2,0);
printformat("MOO %d", getpid()); // <-- cow
settextcolor(15,0);
}
}Aber ich möchte nun auch das machen:void moo()
{
settextcolor(2,0);
printformat("MOO %d", getpid()); // <-- cow
settextcolor(15,0);
}
Als erstes passiert das:11111111111111111111111111111111111111111111111MOO 2Das hat noch nichts mit User Mode zu schaffen, sondern immer noch Multitasking. Das Problem ist wohl das ret von moo(), das offensichtlich das Tasking stört.
Page Fault (page not present) at 123890ABh - EIP: 123890ABh
err_code: 00000000h address(eip): 123890ABh
edi: 00000000h esi: 00000000h ebp: 00000000h eax: 0000000Fh ebx: 00000000h ecx: 000B8000h edx: 0000000Fh cs: 00000008h ds: 00000010h es: 00000010h fs: 00000010h gs 00000010h ss 123890ABh
int_no 14 eflags 00010206h useresp 40204FF4h
), CS unverändert. Das wäre dann also test?Wenn du beachtet hast, dass die Liste nicht sortiert ist, ja.
Rufe ich einen Syscall mit while(TRUE)-Schleife auf, dann bleibt er dabei hängen. kein Task-Switch mehr.Das ist nicht unerwartet: Im Kernel sind Interrupts deaktiviert -> kein präemptiver Task-Switch möglich. Lösung: Keine Endlosschleifen im Kernel. Du musst da auch nicht warten. Eine wartende Funktion sollte selbst den Task-Switch (Stack-Wechsel beim Verlassen des syscalls) initiieren können.
Taljeth meint, ich solle mit einem Syscall zurück springen. Ein syscall ist bei mir der Aufruf einer Kernel-Fkt. aus Ring 3. Dieser syscall_... müsste doch das ret von moo() "aufhalten", indem er in eine Schleife (Ersatz für die while-Schleife) geht, bis der Dispatcher/Scheduler zuschlägt. Später noch informieren, dass zur Umschaltung bereit. Sehe ich das richtig?Nein, der syscall kann den Task-Wechsel direkt vornehmen, und den esp-Wert vom neuen Task zurückgeben. Dann wird nach dem Syscall direkt zum nächsten Task gesprungen. Dazu braucht der Stub vom Syscall Handler die selbe Struktur wie der von den IRQs.
Was macht ret?Mit ret solltest du beim Taskwechsel nichts am Hut haben. Es sollte einfach kein ret ausgeführt werden, dass Probleme machen könnte.
Near Return: holt EIP vom Stack und springt dorthin (aber was ist das in diesem Fall? Was kommt nach einem einmaligen moo()in create_task?

int main() {
puts("Hallo Welt!");
return 0;
}void start() {
int result;
// Hier würde man normalerweise noch sowas machen wie Parameter vom Kernel holen und parsen, aber das lassen wir der Einfachheit halber mal weg.
result = main();
syscall_exit(result);
}
Gespeichert Danke an euch beide! Der Stub vom Syscall Handler u. Exceptions braucht also die gleiche Struktur wie der von den IRQs.Ich denke, dies ist der erste notwendige Schritt, ist mir inzwischen auch klar geworden, dass diese Unsymmetrie (Exception und SW-Interrupt über fault_handler und IRQ0...IRQ15 über irq_handler noch dazu mit unterschiedlichem stub - habe ich von Bran's Tutorial geerbt) Probleme macht, denn, wenn ich es richtig sehe, soll sowohl ein syscall als auch exceptions und die IRQ0...15 einen task_switch durchführen können.
Gespeichert (0) [0x000082a6] iretd <== wenn ich es richtig sehe, zweite Hälfte vom Software-Interrupt (fault_handler)
| STACK 0x4020d7f0 [0x0000d4fc]
| STACK 0x4020d7f4 [0x00000008]
| STACK 0x4020d7f8 [0x00000202]
| STACK 0x4020d7fc [0x00000000]
| STACK 0x4020d800 [0x123890ab]
| STACK 0x4020d804 [0x4020cff4]
| STACK 0x4020d808 [0x123890ab]
| STACK 0x4020d80c [0x00000001]
| STACK 0x4020d810 [0x000007f8]
(0) [0x0000d4fc] pop ebp
(0) [0x0000d4fd] ret
| STACK 0x4020d800 [0x123890ab]
| STACK 0x4020d804 [0x4020cff4]
| STACK 0x4020d808 [0x123890ab]
| STACK 0x4020d80c [0x00000001]
| STACK 0x4020d810 [0x000007f8]
(0).[41476341] ??? (physical address not available)
void f3()
{
while(TRUE)
{
settextcolor(4,0);
printformat("%d", getpid());
settextcolor(15,0);
}
}
void test5()
{
}
task_t* task2 = create_task (f2,0);
task_t* task3 = create_task (f3,0);
task_t* task5 = create_task (syscall_test5,0);
00000012 <_syscall_test5>:
12: 55 push %ebp
13: 89 e5 mov %esp,%ebp
15: b8 01 00 00 00 mov $0x1,%eax
1a: cd 7f int $0x7f
1c: 5d pop %ebp
1d: c3 ret ULONG fault_handler(ULONG esp)
{
ULONG retVal;
struct regs* r = (struct regs*)esp;
if(!pODA->ts_flag)
retVal = esp;
else
retVal = task_switch1(esp); //new task's esp
if (r->int_no < 32) //exception
{
settextcolor(4,0);
if (r->int_no == 6 || r->int_no == 1) //Invalid Opcode
{...}
if (r->int_no == 14) //Page Fault
{...}
printformat("\n");
printformat("%s >>> Exception. System Halted! <<<", exception_messages[r->int_no]);
for (;;);
}
if (r->int_no == 127) //sw-interrupt syscall
{
syscall_handler(r);
}
return retVal;
}
void syscall_handler(struct regs* r)
{
// Firstly, check if the requested syscall number is valid. The syscall number is found in EAX.
if( r->eax >= num_syscalls )
return;
void* addr = syscalls[r->eax]; // Get the required syscall location.
// We don't know how many parameters the function wants, so we just push them all onto the stack in the correct order.
// The function will use all the parameters it wants, and we can pop them all back off afterwards.
int ret;
asm volatile (" \
push %1; \
push %2; \
push %3; \
push %4; \
push %5; \
call *%6; \
pop %%ebx; \
pop %%ebx; \
pop %%ebx; \
pop %%ebx; \
pop %%ebx; \
" : "=a" (ret) : "r" (r->edi), "r" (r->esi), "r" (r->edx), "r" (r->ecx), "r" (r->ebx), "r" (addr));
r->eax = ret;
}Hier der objdump von _syscall_handler zur Sicherheit wegen inline-Assembler:00000032 <_syscall_handler>:
32: 55 push %ebp
33: 89 e5 mov %esp,%ebp
35: 57 push %edi
36: 56 push %esi
37: 53 push %ebx
38: 83 ec 1c sub $0x1c,%esp
3b: 8b 55 08 mov 0x8(%ebp),%edx
3e: 8b 42 28 mov 0x28(%edx),%eax
41: 3b 05 90 00 00 00 cmp 0x90,%eax
47: 73 31 jae 7a <_syscall_handler+0x48>
49: 8b 04 85 94 00 00 00 mov 0x94(,%eax,4),%eax
50: 89 45 f0 mov %eax,0xfffffff0(%ebp)
53: 8b 4a 10 mov 0x10(%edx),%ecx
56: 8b 5a 14 mov 0x14(%edx),%ebx
59: 8b 72 20 mov 0x20(%edx),%esi
5c: 8b 7a 24 mov 0x24(%edx),%edi
5f: 8b 42 1c mov 0x1c(%edx),%eax
62: 8b 55 f0 mov 0xfffffff0(%ebp),%edx
65: 51 push %ecx
66: 53 push %ebx
67: 56 push %esi
68: 57 push %edi
69: 50 push %eax
6a: ff d2 call *%edx
6c: 5b pop %ebx...1 - 2 - 3 - [5] - 1 - 2 - 3 ! [5]
22222222222222222222222222222222222222222222222222222222222222222222222222222222
22222222222222222222222222222222222222222222222222222222222222222222222222222222
22222222222222222233333333333333333333333333333333333333333333333333333333333333
33333333333333333333333333333333333333333333333333333333333333333333333333333333
33333333333333333333333333333333333333333333333333333333333333333333333333333333
33333333333333333333333333333333333333333333333333333333333333333333333333333333
33333333333333333333333333333333333333333333333333333333333333333333333333333333
33333111111111111111111111111111111111111111111111111111111111111111111111111111
11111111111111111111111111111111111111111111111111111111111111111111111111111111
11111111111111111111111111111111111111111111111111111111111111111111111111111111
11111111111111111111111111111111111111111111111111111111111111111111111111111111
11111111111111111111111111111111111111111111111111111111111111111111111111111111
11111111111111122222222222222222222222222222222222222222222222222222222222222222
22222222222222222222222222222222222222222222222222222222222222222222222222222222
22222222222222222222222222222222222222222222222222222222222222222222222222222222
22222222222222222222222222222222222222222222222222222222222222222222222222222222
22222222222222222222222222222222222222222222222222222222222222222222222222222222
22333333333333333333333333333333333333333333333333333333333333333333333333333333
33333333333333333333333333333333333333333333333333333333333333333333333333333333
33333333333333333333333333333333333333333333333333333333333333333333333333333333
33333333333333333333333333333333333333333333333333333333333333333333333333333333
333333333333333333333333333333333333333333333333333333333333333333333Page Fault
(page not present) at 123890ABh - EIP: 123890ABh
Page Fault >>> Exception. System Halted! <<<
Das d4fc muss doch falsch sein!Das ist die falsche Datei. Du musst den Kernel disassemblieren nicht die Objektdateien, wenn du Kerneladressen überprüfen willst.
0x0000d4f2 _syscall_test5 (kernel.map)
objdump -D syscall.o > syscall.txt
Dieser syscall_handler leitet ja nach syscall_puts weiter, wenn ich das richtig sehe.Nein.
ULONG num_syscalls = 3;
static void* syscalls[3] =
{
&puts, <---------- 0
&test5, <----------- 1
&test6 <-------------- 2
};
Gespeichert ULONG fault_handler(ULONG esp)
{
ULONG retVal;
//...
if (r->int_no == 127) //sw-interrupt syscall
{
syscall_handler(r);
}
nop();///TEST for debugger
return retVal;
}
Gespeichert Du musst den Kernel disassemblieren nicht die Objektdateien, wenn du Kerneladressen überprüfen willst.Die Adressen finde ich doch in kernel.map. Ich wollte nur in der Objektdatei nachschauen, wie wirklich in Assembler übersetzt wurde.



Gespeichert Also ss und esp werden auf dem Stack vor cs gepusht.Ja, das liegt sogar ausgedruckt neben mir unter einem Stapel von Büchern:
Gespeichert
Gespeichert typedef struct task
{
int id; // Process ID.
ULONG esp, ebp; // Stack and base pointers.
ULONG eip; // Instruction pointer.
ULONG ss;
page_directory_t* page_directory; // Page directory.
ULONG kernel_stack; // Kernel stack location.
struct task* next; // The next task in a linked list.
} task_t;
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;
*(--kernel_stack) = 0x0202; // eflags = interrupts activated and iopl = 0
ULONG code_segment=0x08, data_segment=0x10;
if(privilege == 0) code_segment = 0x08;
if(privilege == 3)
{
*(--kernel_stack) = new_task->ss = 0x23; // ss
*(--kernel_stack) = new_task->esp = new_task->kernel_stack; // esp
code_segment = 0x1B; // 0x18|0x3=0x1B
}
*(--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;
// data segment registers
if(privilege == 0) data_segment = 0x10;
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 task_t
new_task->ebp = 0xd00fc0de; // test value
new_task->kernel_stack = (ULONG)kernel_stack;
new_task->esp = (ULONG)kernel_stack;
new_task->eip = (ULONG)irq_tail;
new_task->ss = data_segment;
//setup TSS
tss_entry.ss0 = 0x10;
tss_entry.esp0 = new_task->kernel_stack;
tss_entry.ss = data_segment;
tss_entry.esp = new_task->esp;
tss_entry.cr3 = new_task->page_directory->physicalAddr;
sti();
return new_task;
}So o.k.? oder noch ein extra user-stack mit kmalloc?333333333333333333333333333333333333333333333333333333333333333333333Warum sollte sich auch etwas ändern?
Page Fault (page not present) at 123890ABh - EIP: 123890ABh
33333333333333333333333333333333333333333333333333333333333333333333333333333333
33333
General Protection Fault >>> Exception. System Halted! <<<
Also ss und esp werden auf dem Stack vor cs gepusht.Stimmt natürlich nicht. Vor eflags werden die auf den Stack gelegt.
Brauche ich hier schon einen user stack oder ist der hier identisch mit dem kernel-stack? Muss das in TSS->esp3 TSS->ss3 eingetragen werden?Sobald du Ring3-Prozesse hast, brauchst du einen zusätzlichen Stack. Dieser sollte dann auch mit User-Privilegien gemappt sein, sonst fliegen die Pagefaults frischfrölich.

Gespeichert eflags, cs, eip, error code ohne Privileg-WechselIch schreibe es richtig, und mache es dann doch so wie du es sagst.
ss, esp, eflags, cs, eip, error code mit Privileg-Wechsel

Gespeichert
Gespeichert Sobald du Ring3-Prozesse hast, brauchst du einen zusätzlichen Stack. Dieser sollte dann auch mit User-Privilegien gemappt seinDanke für den Hinweis.

When the processor performs a call to the exception- or interrupt-handler procedure:
•If the handler procedure is going to be executed at a numerically lower privilege level, a stack switch occurs.
When the stack switch occurs:
a.The segment selector and stack pointer for the stack to be used by the handler are obtained from the TSS for the currently executing task. On this new stack, the processor pushes the stack segment selector and stack pointer of the interrupted procedure.
b.The processor then saves the current state of the EFLAGS, CS, and EIP registers on the new stack (see Figures 5-4).
c.If an exception causes an error code to be saved, it is pushed on the new stack after the EIP value.
•If the handler procedure is going to be executed at the same privilege level as the interrupted procedure:
a.The processor saves the current state of the EFLAGS, CS, and EIP registers on the current stack (see Figures 5-4).
b.If an exception causes an error code to be saved, it is pushed on the current stack after the EIP value.