Implement Ring 3 process subsystem with syscalls and context switching (AI)
Add complete user-mode process support: - TSS (tss.c/h): Task State Segment for Ring 3->0 transitions, installed as GDT entry 5 (selector 0x28). ESP0 updated per-process for kernel stack switching. - Process management (process.c/h): Process table with up to 64 processes. process_create() clones kernel page directory, maps user code at 0x08048000 and user stack at 0xBFFFF000, copies flat binary code. Round-robin scheduler via schedule_tick() modifies the interrupt frame in-place for zero-copy context switching. - System calls (syscall.c/h): INT 0x80 dispatcher with 8 syscalls: SYS_EXIT, SYS_WRITE (to debug port + VGA), SYS_READ, SYS_FORK, SYS_GETPID, SYS_YIELD, SYS_WAITPID, SYS_EXEC. IDT gate at 0x80 uses DPL=3 (flags 0xEE) so user code can invoke it. - Assembly stubs (interrupts.S): isr128 for INT 0x80, tss_flush for loading the Task Register, enter_usermode for initial iret to Ring 3. - Paging extensions (paging.c/h): paging_clone_directory() to create per-process page directories, paging_map_page_in() for mapping into non-active directories, paging_switch_directory() for CR3 switching. - GDT expanded from 5 to 6 entries to accommodate TSS descriptor. gdt_set_gate() exposed in header for TSS initialization. - ISR handler routes timer IRQ (32) to scheduler and INT 0x80 to syscall dispatcher. Exception handler now prints EIP/CS/ERR for debugging. - Kernel boots a test user program that writes 'Hello from Ring 3!' via SYS_WRITE and exits with code 42 via SYS_EXIT. Verified working in QEMU. Context switching approach: Timer/syscall interrupts save all registers via the ISR stub. schedule_tick() copies saved_regs between PCBs and overwrites the interrupt frame, so the existing iret restores the next process's state without separate switch assembly.
This commit is contained in:
28
src/isr.c
28
src/isr.c
@@ -1,5 +1,7 @@
|
||||
#include "isr.h"
|
||||
#include "pic.h"
|
||||
#include "process.h"
|
||||
#include "syscall.h"
|
||||
#include <stdint.h>
|
||||
|
||||
/* Forward declaration for kernel panic or similar */
|
||||
@@ -44,24 +46,28 @@ char *exception_messages[] = {
|
||||
|
||||
void isr_handler(registers_t *regs)
|
||||
{
|
||||
// If it's a hardware interrupt (IRQ), we must acknowledge it
|
||||
/* System call (INT 0x80) */
|
||||
if (regs->int_no == 0x80) {
|
||||
syscall_handler(regs);
|
||||
return;
|
||||
}
|
||||
|
||||
/* Hardware interrupts (IRQs 0-15, mapped to vectors 32-47) */
|
||||
if (regs->int_no >= 32 && regs->int_no < 48) {
|
||||
// Send EOI to PIC (IRQ number 0-15)
|
||||
/* Send EOI to PIC (IRQ number 0-15) */
|
||||
pic_send_eoi(regs->int_no - 32);
|
||||
|
||||
// Here we would call the registered handler for this IRQ
|
||||
// For now, just print something for the timer tick so we know it works,
|
||||
// but limit it to avoid flooding the log.
|
||||
if (regs->int_no == 32) {
|
||||
// Timer tick - do nothing verbose
|
||||
// offset_print(".");
|
||||
/* Timer tick - invoke scheduler */
|
||||
schedule_tick(regs);
|
||||
} else if (regs->int_no == 33) {
|
||||
// Keyboard
|
||||
/* Keyboard */
|
||||
offset_print("Keyboard IRQ!\n");
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
/* CPU exceptions (vectors 0-31) */
|
||||
offset_print("received interrupt: ");
|
||||
print_hex(regs->int_no);
|
||||
offset_print("\n");
|
||||
@@ -70,6 +76,12 @@ void isr_handler(registers_t *regs)
|
||||
{
|
||||
offset_print(exception_messages[regs->int_no]);
|
||||
offset_print(" Exception. System Halted!\n");
|
||||
offset_print(" EIP: ");
|
||||
print_hex(regs->eip);
|
||||
offset_print(" CS: ");
|
||||
print_hex(regs->cs);
|
||||
offset_print(" ERR: ");
|
||||
print_hex(regs->err_code);
|
||||
for (;;) ;
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user