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.
64 lines
1.5 KiB
C
64 lines
1.5 KiB
C
/**
|
|
* @file tss.h
|
|
* @brief Task State Segment (TSS) definitions.
|
|
*
|
|
* The TSS is required by x86 for ring transitions. When a user-mode process
|
|
* triggers an interrupt, the CPU loads the kernel stack pointer (SS0:ESP0)
|
|
* from the TSS before pushing the interrupt frame.
|
|
*/
|
|
|
|
#ifndef TSS_H
|
|
#define TSS_H
|
|
|
|
#include <stdint.h>
|
|
|
|
/**
|
|
* x86 Task State Segment structure.
|
|
* Only SS0 and ESP0 are actively used for ring 3 -> ring 0 transitions.
|
|
*/
|
|
typedef struct tss_entry {
|
|
uint32_t prev_tss;
|
|
uint32_t esp0; /**< Kernel stack pointer (loaded on ring transition). */
|
|
uint32_t ss0; /**< Kernel stack segment (loaded on ring transition). */
|
|
uint32_t esp1;
|
|
uint32_t ss1;
|
|
uint32_t esp2;
|
|
uint32_t ss2;
|
|
uint32_t cr3;
|
|
uint32_t eip;
|
|
uint32_t eflags;
|
|
uint32_t eax;
|
|
uint32_t ecx;
|
|
uint32_t edx;
|
|
uint32_t ebx;
|
|
uint32_t esp;
|
|
uint32_t ebp;
|
|
uint32_t esi;
|
|
uint32_t edi;
|
|
uint32_t es;
|
|
uint32_t cs;
|
|
uint32_t ss;
|
|
uint32_t ds;
|
|
uint32_t fs;
|
|
uint32_t gs;
|
|
uint32_t ldt;
|
|
uint16_t trap;
|
|
uint16_t iomap_base;
|
|
} __attribute__((packed)) tss_entry_t;
|
|
|
|
/**
|
|
* Initialize the TSS and install it as GDT entry 5 (selector 0x28).
|
|
* Must be called after init_gdt().
|
|
*/
|
|
void init_tss(void);
|
|
|
|
/**
|
|
* Update the kernel stack pointer in the TSS.
|
|
* Called during context switches to set the stack for the next process.
|
|
*
|
|
* @param esp0 The new kernel stack pointer.
|
|
*/
|
|
void tss_set_kernel_stack(uint32_t esp0);
|
|
|
|
#endif /* TSS_H */
|