Compare commits
2 Commits
@@ -18,9 +18,11 @@ BOOT_OBJ = build/boot.o
|
|||||||
KERNEL_CPP = kernel/entry.cpp kernel/main.cpp kernel/serial.cpp kernel/fs.cpp \
|
KERNEL_CPP = kernel/entry.cpp kernel/main.cpp kernel/serial.cpp kernel/fs.cpp \
|
||||||
kernel/memory/heap.cpp kernel/memory/pmm.cpp \
|
kernel/memory/heap.cpp kernel/memory/pmm.cpp \
|
||||||
kernel/scheduler/scheduler.cpp \
|
kernel/scheduler/scheduler.cpp \
|
||||||
|
kernel/interrupt/gdt.cpp kernel/interrupt/idt.cpp \
|
||||||
|
kernel/interrupt/pic.cpp kernel/interrupt/pit.cpp \
|
||||||
graphics/context.cpp graphics/draw.cpp \
|
graphics/context.cpp graphics/draw.cpp \
|
||||||
fonts/pixel_font.cpp
|
fonts/pixel_font.cpp
|
||||||
KERNEL_ASM = kernel/scheduler/context_switch.S
|
KERNEL_ASM = kernel/scheduler/context_switch.S kernel/interrupt/isr.S kernel/interrupt/idt_helpers.S
|
||||||
KERNEL_OBJ = $(KERNEL_CPP:%.cpp=build/%.o) $(KERNEL_ASM:%.S=build/%.o)
|
KERNEL_OBJ = $(KERNEL_CPP:%.cpp=build/%.o) $(KERNEL_ASM:%.S=build/%.o)
|
||||||
|
|
||||||
EFI_TOP_C = $(wildcard efi/lib/*.c)
|
EFI_TOP_C = $(wildcard efi/lib/*.c)
|
||||||
@@ -46,7 +48,7 @@ all: _bd $(EFI_OBJ) $(BOOT_OBJ) $(KERNEL_OBJ)
|
|||||||
|
|
||||||
_bd:
|
_bd:
|
||||||
@mkdir -p build/graphics build/kernel build/fonts build/kernel/memory \
|
@mkdir -p build/graphics build/kernel build/fonts build/kernel/memory \
|
||||||
build/kernel/scheduler \
|
build/kernel/scheduler build/kernel/interrupt \
|
||||||
build/efi/lib build/efi/lib/x86_64 build/efi/lib/runtime build/efi/gnuefi
|
build/efi/lib build/efi/lib/x86_64 build/efi/lib/runtime build/efi/gnuefi
|
||||||
|
|
||||||
$(EFI_CRT0_OBJ): efi/gnuefi/crt0-efi-x86_64.S | _bd
|
$(EFI_CRT0_OBJ): efi/gnuefi/crt0-efi-x86_64.S | _bd
|
||||||
@@ -98,6 +100,15 @@ build/kernel/scheduler/%.o: kernel/scheduler/%.S | _bd
|
|||||||
@gcc -Iinclude -Iefi/inc -ffreestanding -fno-stack-protector -fno-stack-check \
|
@gcc -Iinclude -Iefi/inc -ffreestanding -fno-stack-protector -fno-stack-check \
|
||||||
-fshort-wchar -mno-red-zone -fcf-protection=none -c $< -o $@
|
-fshort-wchar -mno-red-zone -fcf-protection=none -c $< -o $@
|
||||||
|
|
||||||
|
build/kernel/interrupt/%.o: kernel/interrupt/%.cpp | _bd
|
||||||
|
@echo "Compile CPP $<"
|
||||||
|
@g++ $(KERNEL_CXXFLAGS) -c $< -o $@
|
||||||
|
|
||||||
|
build/kernel/interrupt/%.o: kernel/interrupt/%.S | _bd
|
||||||
|
@echo "Compile AS $<"
|
||||||
|
@gcc -Iinclude -Iefi/inc -ffreestanding -fno-stack-protector -fno-stack-check \
|
||||||
|
-fshort-wchar -mno-red-zone -fcf-protection=none -c $< -o $@
|
||||||
|
|
||||||
build/graphics/%.o: graphics/%.cpp | _bd
|
build/graphics/%.o: graphics/%.cpp | _bd
|
||||||
@echo "Compile CPP $<"
|
@echo "Compile CPP $<"
|
||||||
@g++ $(KERNEL_CXXFLAGS) -c $< -o $@
|
@g++ $(KERNEL_CXXFLAGS) -c $< -o $@
|
||||||
|
|||||||
@@ -0,0 +1,61 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <efi.h>
|
||||||
|
|
||||||
|
// GDT selectors
|
||||||
|
#define GDT_NULL 0x00
|
||||||
|
#define GDT_KERNEL_CODE 0x08
|
||||||
|
#define GDT_KERNEL_DATA 0x10
|
||||||
|
#define GDT_USER_CODE 0x18
|
||||||
|
#define GDT_USER_DATA 0x20
|
||||||
|
#define GDT_TSS 0x28
|
||||||
|
|
||||||
|
// GDT entry
|
||||||
|
struct gdt_entry {
|
||||||
|
UINT16 limit_low;
|
||||||
|
UINT16 base_low;
|
||||||
|
UINT8 base_mid;
|
||||||
|
UINT8 access;
|
||||||
|
UINT8 granularity;
|
||||||
|
UINT8 base_high;
|
||||||
|
} __attribute__((packed));
|
||||||
|
|
||||||
|
// GDT pointer
|
||||||
|
struct gdt_ptr {
|
||||||
|
UINT16 limit;
|
||||||
|
UINT64 base;
|
||||||
|
} __attribute__((packed));
|
||||||
|
|
||||||
|
// TSS (Task State Segment) — 64-bit mode uses only RSP0 and IST1-7
|
||||||
|
struct tss {
|
||||||
|
UINT32 reserved0;
|
||||||
|
UINT64 rsp0;
|
||||||
|
UINT64 rsp1;
|
||||||
|
UINT64 rsp2;
|
||||||
|
UINT64 reserved1;
|
||||||
|
UINT64 ist1;
|
||||||
|
UINT64 ist2;
|
||||||
|
UINT64 ist3;
|
||||||
|
UINT64 ist4;
|
||||||
|
UINT64 ist5;
|
||||||
|
UINT64 ist6;
|
||||||
|
UINT64 ist7;
|
||||||
|
UINT64 reserved2;
|
||||||
|
UINT16 reserved3;
|
||||||
|
UINT16 iopb_offset;
|
||||||
|
} __attribute__((packed));
|
||||||
|
|
||||||
|
// TSS descriptor in GDT (system segment, 16 bytes)
|
||||||
|
struct tss_descriptor {
|
||||||
|
UINT16 limit_low;
|
||||||
|
UINT16 base_low;
|
||||||
|
UINT8 base_mid;
|
||||||
|
UINT8 access;
|
||||||
|
UINT8 granularity;
|
||||||
|
UINT8 base_high;
|
||||||
|
UINT32 base_upper;
|
||||||
|
UINT32 reserved;
|
||||||
|
} __attribute__((packed));
|
||||||
|
|
||||||
|
void gdt_init(void);
|
||||||
|
void gdt_set_kernel_stack(UINT64 stack); // sets TSS.RSP0
|
||||||
@@ -0,0 +1,48 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <efi.h>
|
||||||
|
|
||||||
|
// IDT entry (64-bit gate descriptor)
|
||||||
|
struct idt_entry {
|
||||||
|
UINT16 offset_low;
|
||||||
|
UINT16 selector;
|
||||||
|
UINT8 ist; // IST index (bits 0-2), reserved (bits 3-6), type (bit 7)
|
||||||
|
UINT8 type_attr; // P (bit 7), DPL (bits 5-6), 0 (bit 4), type (bits 0-3)
|
||||||
|
UINT16 offset_mid;
|
||||||
|
UINT32 offset_high;
|
||||||
|
UINT32 reserved;
|
||||||
|
} __attribute__((packed));
|
||||||
|
|
||||||
|
struct idt_ptr {
|
||||||
|
UINT16 limit;
|
||||||
|
UINT64 base;
|
||||||
|
} __attribute__((packed));
|
||||||
|
|
||||||
|
// Interrupt frame saved by ISR stubs
|
||||||
|
struct trap_frame {
|
||||||
|
// Pushed by ISR stub (general-purpose registers)
|
||||||
|
UINT64 r11;
|
||||||
|
UINT64 r10;
|
||||||
|
UINT64 r9;
|
||||||
|
UINT64 r8;
|
||||||
|
UINT64 rdi;
|
||||||
|
UINT64 rsi;
|
||||||
|
UINT64 rdx;
|
||||||
|
UINT64 rcx;
|
||||||
|
UINT64 rax;
|
||||||
|
// Pushed by ISR stub (metadata)
|
||||||
|
UINT64 vector;
|
||||||
|
UINT64 error_code;
|
||||||
|
// Pushed by CPU (interrupt frame)
|
||||||
|
UINT64 rip;
|
||||||
|
UINT64 cs;
|
||||||
|
UINT64 rflags;
|
||||||
|
UINT64 rsp;
|
||||||
|
UINT64 ss;
|
||||||
|
} __attribute__((packed));
|
||||||
|
|
||||||
|
// Handler function type
|
||||||
|
typedef void (*isr_handler_t)(trap_frame*);
|
||||||
|
|
||||||
|
void idt_init(void);
|
||||||
|
void idt_set_handler(UINT8 vector, isr_handler_t handler);
|
||||||
@@ -0,0 +1,20 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <efi.h>
|
||||||
|
|
||||||
|
// 8259 PIC ports
|
||||||
|
#define PIC1_CMD 0x20
|
||||||
|
#define PIC1_DATA 0x21
|
||||||
|
#define PIC2_CMD 0xA0
|
||||||
|
#define PIC2_DATA 0xA1
|
||||||
|
|
||||||
|
// PIC vectors
|
||||||
|
#define PIC_IRQ_BASE 0x20 // IRQ 0 mapped to vector 0x20 (32)
|
||||||
|
|
||||||
|
// EOI signal
|
||||||
|
#define PIC_EOI 0x20
|
||||||
|
|
||||||
|
void pic_init(void);
|
||||||
|
void pic_send_eoi(UINT8 irq);
|
||||||
|
void pic_mask_irq(UINT8 irq);
|
||||||
|
void pic_unmask_irq(UINT8 irq);
|
||||||
@@ -0,0 +1,18 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <efi.h>
|
||||||
|
|
||||||
|
// PIT I/O ports
|
||||||
|
#define PIT_CHANNEL0_DATA 0x40
|
||||||
|
#define PIT_COMMAND_PORT 0x43
|
||||||
|
|
||||||
|
// PIT frequency
|
||||||
|
#define PIT_BASE_FREQ 1193182 // 1.193182 MHz
|
||||||
|
#define PIT_TICK_HZ 100 // 100 Hz tick (10ms per tick)
|
||||||
|
|
||||||
|
// Timer tick callback type
|
||||||
|
typedef void (*timer_callback_t)(void);
|
||||||
|
|
||||||
|
void pit_init(void);
|
||||||
|
void pit_set_tick_handler(timer_callback_t handler);
|
||||||
|
UINT64 pit_get_ticks(void);
|
||||||
@@ -7,6 +7,7 @@
|
|||||||
#define TASK_STACK_SIZE (PAGE_SIZE * 4) // 16 KB kernel stack per task
|
#define TASK_STACK_SIZE (PAGE_SIZE * 4) // 16 KB kernel stack per task
|
||||||
#define TASK_MAX 32
|
#define TASK_MAX 32
|
||||||
#define TASK_NAME_LEN 32
|
#define TASK_NAME_LEN 32
|
||||||
|
#define TIME_SLICE_DEFAULT 5 // 5 ticks = 50ms at 100 Hz
|
||||||
|
|
||||||
typedef enum {
|
typedef enum {
|
||||||
TASK_STATE_READY,
|
TASK_STATE_READY,
|
||||||
@@ -21,6 +22,7 @@ typedef struct task {
|
|||||||
char name[TASK_NAME_LEN];
|
char name[TASK_NAME_LEN];
|
||||||
void* stack_base; // base address of kernel stack
|
void* stack_base; // base address of kernel stack
|
||||||
struct task* next; // circular linked list
|
struct task* next; // circular linked list
|
||||||
|
UINT32 time_slice; // remaining ticks before preemption
|
||||||
} task_t;
|
} task_t;
|
||||||
|
|
||||||
// Create a new task. Returns task pointer or NULL on failure.
|
// Create a new task. Returns task pointer or NULL on failure.
|
||||||
@@ -37,3 +39,6 @@ void task_exit(void);
|
|||||||
|
|
||||||
// Get current running task
|
// Get current running task
|
||||||
task_t* scheduler_current(void);
|
task_t* scheduler_current(void);
|
||||||
|
|
||||||
|
// Timer tick handler — called by PIT IRQ 0, drives preemption
|
||||||
|
void scheduler_tick(void);
|
||||||
|
|||||||
@@ -8,6 +8,7 @@ extern "C" void kernel_main();
|
|||||||
extern "C" void _start(EFI_HANDLE ImageHandle, EFI_SYSTEM_TABLE *SystemTable) {
|
extern "C" void _start(EFI_HANDLE ImageHandle, EFI_SYSTEM_TABLE *SystemTable) {
|
||||||
(void)ImageHandle;
|
(void)ImageHandle;
|
||||||
ST = SystemTable;
|
ST = SystemTable;
|
||||||
|
ASM("cli"); // disable interrupts until IDT is ready
|
||||||
kernel_main();
|
kernel_main();
|
||||||
while (1) ASM ("hlt");
|
while (1) ASM ("hlt");
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,71 @@
|
|||||||
|
#include <gdt.h>
|
||||||
|
#include <common.h>
|
||||||
|
#include <serial.h>
|
||||||
|
|
||||||
|
static gdt_entry g_gdt[7]; // 5 segments + TSS (2 entries)
|
||||||
|
static gdt_ptr g_gdt_ptr;
|
||||||
|
static tss g_tss;
|
||||||
|
|
||||||
|
extern "C" void lgdt_and_reload(void* gdt_ptr);
|
||||||
|
extern "C" void tss_load(UINT16 selector);
|
||||||
|
|
||||||
|
static void gdt_set_entry(UINT32 index, UINT32 base, UINT32 limit,
|
||||||
|
UINT8 access, UINT8 granularity) {
|
||||||
|
g_gdt[index].limit_low = limit & 0xFFFF;
|
||||||
|
g_gdt[index].base_low = base & 0xFFFF;
|
||||||
|
g_gdt[index].base_mid = (base >> 16) & 0xFF;
|
||||||
|
g_gdt[index].access = access;
|
||||||
|
g_gdt[index].granularity = granularity | ((limit >> 16) & 0x0F);
|
||||||
|
g_gdt[index].base_high = (base >> 24) & 0xFF;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void tss_set_descriptor(UINT32 index) {
|
||||||
|
UINT64 base = (UINT64)&g_tss;
|
||||||
|
UINT32 limit = sizeof(tss) - 1;
|
||||||
|
|
||||||
|
g_gdt[index].limit_low = limit & 0xFFFF;
|
||||||
|
g_gdt[index].base_low = base & 0xFFFF;
|
||||||
|
g_gdt[index].base_mid = (base >> 16) & 0xFF;
|
||||||
|
g_gdt[index].access = 0x89;
|
||||||
|
g_gdt[index].granularity = 0x00;
|
||||||
|
g_gdt[index].base_high = (base >> 24) & 0xFF;
|
||||||
|
|
||||||
|
g_gdt[index + 1].limit_low = (limit >> 16) & 0xFFFF;
|
||||||
|
g_gdt[index + 1].base_low = (base >> 32) & 0xFFFF;
|
||||||
|
g_gdt[index + 1].base_mid = (base >> 48) & 0xFF;
|
||||||
|
g_gdt[index + 1].access = 0;
|
||||||
|
g_gdt[index + 1].granularity = 0;
|
||||||
|
g_gdt[index + 1].base_high = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void gdt_init(void) {
|
||||||
|
serial_write("GDT: initializing\n");
|
||||||
|
|
||||||
|
for (int i = 0; i < 7; i++) {
|
||||||
|
g_gdt[i] = {0};
|
||||||
|
}
|
||||||
|
|
||||||
|
gdt_set_entry(0, 0, 0, 0, 0);
|
||||||
|
gdt_set_entry(1, 0, 0xFFFFF, 0x9A, 0xA0);
|
||||||
|
gdt_set_entry(2, 0, 0xFFFFF, 0x92, 0xC0);
|
||||||
|
gdt_set_entry(3, 0, 0xFFFFF, 0xFA, 0xA0);
|
||||||
|
gdt_set_entry(4, 0, 0xFFFFF, 0xF2, 0xC0);
|
||||||
|
tss_set_descriptor(5);
|
||||||
|
|
||||||
|
g_tss = {};
|
||||||
|
g_tss.iopb_offset = sizeof(tss);
|
||||||
|
|
||||||
|
g_gdt_ptr.limit = sizeof(g_gdt) - 1;
|
||||||
|
g_gdt_ptr.base = (UINT64)&g_gdt[0];
|
||||||
|
|
||||||
|
serial_write("GDT: loading GDT + reloading segments\n");
|
||||||
|
lgdt_and_reload(&g_gdt_ptr);
|
||||||
|
serial_write("GDT: loading TSS\n");
|
||||||
|
tss_load(GDT_TSS);
|
||||||
|
|
||||||
|
serial_write("GDT: done\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
void gdt_set_kernel_stack(UINT64 stack) {
|
||||||
|
g_tss.rsp0 = stack;
|
||||||
|
}
|
||||||
@@ -0,0 +1,66 @@
|
|||||||
|
#include <idt.h>
|
||||||
|
#include <common.h>
|
||||||
|
#include <pic.h>
|
||||||
|
#include <serial.h>
|
||||||
|
|
||||||
|
// Defined in isr.S — 256 ISR stubs
|
||||||
|
extern "C" void* isr_stub_table[256];
|
||||||
|
|
||||||
|
static idt_entry g_idt[256];
|
||||||
|
static idt_ptr g_idt_ptr;
|
||||||
|
static isr_handler_t g_handlers[256] = {0};
|
||||||
|
|
||||||
|
void idt_set_handler(UINT8 vector, isr_handler_t handler) {
|
||||||
|
g_handlers[vector] = handler;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Called from isr.S common handler
|
||||||
|
extern "C" void isr_dispatch(trap_frame* frame) {
|
||||||
|
UINT8 vector = (UINT8)frame->vector;
|
||||||
|
|
||||||
|
if (g_handlers[vector]) {
|
||||||
|
g_handlers[vector](frame);
|
||||||
|
} else if (vector < 32) {
|
||||||
|
serial_write("IDT: unhandled exception #");
|
||||||
|
serial_write_hex(vector);
|
||||||
|
serial_write(" error=");
|
||||||
|
serial_write_hex(frame->error_code);
|
||||||
|
serial_write("\n");
|
||||||
|
while (1) ASM("hlt");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// IDT helpers (defined in idt_helpers.S)
|
||||||
|
extern "C" void idt_load(UINT64 base, UINT16 limit);
|
||||||
|
|
||||||
|
static void idt_set_entry(UINT8 vector, UINT64 handler_addr) {
|
||||||
|
g_idt[vector].offset_low = handler_addr & 0xFFFF;
|
||||||
|
g_idt[vector].selector = 0x08; // kernel code segment
|
||||||
|
g_idt[vector].ist = 0;
|
||||||
|
g_idt[vector].type_attr = 0x8E; // present, DPL=0, 64-bit interrupt gate
|
||||||
|
g_idt[vector].offset_mid = (handler_addr >> 16) & 0xFFFF;
|
||||||
|
g_idt[vector].offset_high = (handler_addr >> 32) & 0xFFFFFFFF;
|
||||||
|
g_idt[vector].reserved = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void idt_init(void) {
|
||||||
|
serial_write("IDT: initializing 256 entries\n");
|
||||||
|
|
||||||
|
// Clear IDT
|
||||||
|
for (int i = 0; i < 256; i++) {
|
||||||
|
g_idt[i] = {0};
|
||||||
|
g_handlers[i] = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Install all 256 ISR stubs
|
||||||
|
for (int i = 0; i < 256; i++) {
|
||||||
|
idt_set_entry(i, (UINT64)isr_stub_table[i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Load IDT
|
||||||
|
g_idt_ptr.limit = sizeof(g_idt) - 1;
|
||||||
|
g_idt_ptr.base = (UINT64)&g_idt[0];
|
||||||
|
idt_load(g_idt_ptr.base, g_idt_ptr.limit);
|
||||||
|
|
||||||
|
serial_write("IDT: loaded\n");
|
||||||
|
}
|
||||||
@@ -0,0 +1,33 @@
|
|||||||
|
.intel_syntax noprefix
|
||||||
|
|
||||||
|
.global idt_load
|
||||||
|
idt_load:
|
||||||
|
sub rsp, 10
|
||||||
|
mov [rsp], si
|
||||||
|
mov [rsp + 2], rdi
|
||||||
|
lidt [rsp]
|
||||||
|
add rsp, 10
|
||||||
|
ret
|
||||||
|
|
||||||
|
.global lgdt_and_reload
|
||||||
|
lgdt_and_reload:
|
||||||
|
lgdt [rdi]
|
||||||
|
push 0x08
|
||||||
|
mov rax, offset .reload_cs
|
||||||
|
push rax
|
||||||
|
retfq
|
||||||
|
.reload_cs:
|
||||||
|
mov ax, 0x10
|
||||||
|
mov ds, ax
|
||||||
|
mov es, ax
|
||||||
|
mov fs, ax
|
||||||
|
mov gs, ax
|
||||||
|
mov ss, ax
|
||||||
|
ret
|
||||||
|
|
||||||
|
.global tss_load
|
||||||
|
tss_load:
|
||||||
|
ltr di
|
||||||
|
ret
|
||||||
|
|
||||||
|
.section .note.GNU-stack,"",@progbits
|
||||||
@@ -0,0 +1,589 @@
|
|||||||
|
.intel_syntax noprefix
|
||||||
|
|
||||||
|
// ISR stub table — 256 entries
|
||||||
|
// For exceptions without error code, we push a dummy 0
|
||||||
|
// For exceptions with error code, the CPU already pushed it
|
||||||
|
|
||||||
|
// Macros for generating ISR stubs
|
||||||
|
.macro ISR_NOERR num
|
||||||
|
.global isr_stub_\num
|
||||||
|
isr_stub_\num:
|
||||||
|
push 0 // dummy error code
|
||||||
|
push \num // vector number
|
||||||
|
jmp isr_common
|
||||||
|
.endm
|
||||||
|
|
||||||
|
.macro ISR_ERR num
|
||||||
|
.global isr_stub_\num
|
||||||
|
isr_stub_\num:
|
||||||
|
// error code already on stack from CPU
|
||||||
|
push \num // vector number
|
||||||
|
jmp isr_common
|
||||||
|
.endm
|
||||||
|
|
||||||
|
// === Exceptions 0-31 ===
|
||||||
|
ISR_NOERR 0 // #DE Divide Error
|
||||||
|
ISR_NOERR 1 // #DB Debug
|
||||||
|
ISR_NOERR 2 // NMI
|
||||||
|
ISR_NOERR 3 // #BP Breakpoint
|
||||||
|
ISR_NOERR 4 // #OF Overflow
|
||||||
|
ISR_NOERR 5 // #BR Bound Range Exceeded
|
||||||
|
ISR_NOERR 6 // #UD Invalid Opcode
|
||||||
|
ISR_NOERR 7 // #NM Device Not Available
|
||||||
|
ISR_ERR 8 // #DF Double Fault
|
||||||
|
ISR_NOERR 9 // Coprocessor Segment Overrun (reserved)
|
||||||
|
ISR_ERR 10 // #TS Invalid TSS
|
||||||
|
ISR_ERR 11 // #NP Segment Not Present
|
||||||
|
ISR_ERR 12 // #SS Stack-Segment Fault
|
||||||
|
ISR_ERR 13 // #GP General Protection
|
||||||
|
ISR_ERR 14 // #PF Page Fault
|
||||||
|
ISR_NOERR 15 // Reserved
|
||||||
|
ISR_NOERR 16 // #MF x87 FPU Error
|
||||||
|
ISR_ERR 17 // #AC Alignment Check
|
||||||
|
ISR_NOERR 18 // #MC Machine Check
|
||||||
|
ISR_NOERR 19 // #XM SIMD Exception
|
||||||
|
ISR_NOERR 20 // Virtualization Exception
|
||||||
|
ISR_ERR 21 // #CP Control Protection
|
||||||
|
ISR_NOERR 22
|
||||||
|
ISR_NOERR 23
|
||||||
|
ISR_NOERR 24
|
||||||
|
ISR_NOERR 25
|
||||||
|
ISR_NOERR 26
|
||||||
|
ISR_NOERR 27
|
||||||
|
ISR_NOERR 28
|
||||||
|
ISR_ERR 29 // Hypervisor Injection
|
||||||
|
ISR_ERR 30 // #SX Security Exception
|
||||||
|
ISR_NOERR 31 // Reserved
|
||||||
|
|
||||||
|
// === Hardware IRQs 32-255 ===
|
||||||
|
ISR_NOERR 32 // PIT timer (IRQ 0)
|
||||||
|
ISR_NOERR 33 // Keyboard (IRQ 1)
|
||||||
|
ISR_NOERR 34 // Cascade (IRQ 2)
|
||||||
|
ISR_NOERR 35 // COM2 (IRQ 3)
|
||||||
|
ISR_NOERR 36 // COM1 (IRQ 4)
|
||||||
|
ISR_NOERR 37 // LPT2 (IRQ 5)
|
||||||
|
ISR_NOERR 38 // Floppy (IRQ 6)
|
||||||
|
ISR_NOERR 39 // LPT1 / Spurious (IRQ 7)
|
||||||
|
ISR_NOERR 40 // CMOS RTC (IRQ 8)
|
||||||
|
ISR_NOERR 41 // ACPI (IRQ 9)
|
||||||
|
ISR_NOERR 42 // Open (IRQ 10)
|
||||||
|
ISR_NOERR 43 // Open (IRQ 11)
|
||||||
|
ISR_NOERR 44 // PS/2 Mouse (IRQ 12)
|
||||||
|
ISR_NOERR 45 // FPU (IRQ 13)
|
||||||
|
ISR_NOERR 46 // Primary ATA (IRQ 14)
|
||||||
|
ISR_NOERR 47 // Secondary ATA (IRQ 15)
|
||||||
|
|
||||||
|
// Vectors 48-255: software / unused
|
||||||
|
ISR_NOERR 48
|
||||||
|
ISR_NOERR 49
|
||||||
|
ISR_NOERR 50
|
||||||
|
ISR_NOERR 51
|
||||||
|
ISR_NOERR 52
|
||||||
|
ISR_NOERR 53
|
||||||
|
ISR_NOERR 54
|
||||||
|
ISR_NOERR 55
|
||||||
|
ISR_NOERR 56
|
||||||
|
ISR_NOERR 57
|
||||||
|
ISR_NOERR 58
|
||||||
|
ISR_NOERR 59
|
||||||
|
ISR_NOERR 60
|
||||||
|
ISR_NOERR 61
|
||||||
|
ISR_NOERR 62
|
||||||
|
ISR_NOERR 63
|
||||||
|
ISR_NOERR 64
|
||||||
|
ISR_NOERR 65
|
||||||
|
ISR_NOERR 66
|
||||||
|
ISR_NOERR 67
|
||||||
|
ISR_NOERR 68
|
||||||
|
ISR_NOERR 69
|
||||||
|
ISR_NOERR 70
|
||||||
|
ISR_NOERR 71
|
||||||
|
ISR_NOERR 72
|
||||||
|
ISR_NOERR 73
|
||||||
|
ISR_NOERR 74
|
||||||
|
ISR_NOERR 75
|
||||||
|
ISR_NOERR 76
|
||||||
|
ISR_NOERR 77
|
||||||
|
ISR_NOERR 78
|
||||||
|
ISR_NOERR 79
|
||||||
|
ISR_NOERR 80
|
||||||
|
ISR_NOERR 81
|
||||||
|
ISR_NOERR 82
|
||||||
|
ISR_NOERR 83
|
||||||
|
ISR_NOERR 84
|
||||||
|
ISR_NOERR 85
|
||||||
|
ISR_NOERR 86
|
||||||
|
ISR_NOERR 87
|
||||||
|
ISR_NOERR 88
|
||||||
|
ISR_NOERR 89
|
||||||
|
ISR_NOERR 90
|
||||||
|
ISR_NOERR 91
|
||||||
|
ISR_NOERR 92
|
||||||
|
ISR_NOERR 93
|
||||||
|
ISR_NOERR 94
|
||||||
|
ISR_NOERR 95
|
||||||
|
ISR_NOERR 96
|
||||||
|
ISR_NOERR 97
|
||||||
|
ISR_NOERR 98
|
||||||
|
ISR_NOERR 99
|
||||||
|
ISR_NOERR 100
|
||||||
|
ISR_NOERR 101
|
||||||
|
ISR_NOERR 102
|
||||||
|
ISR_NOERR 103
|
||||||
|
ISR_NOERR 104
|
||||||
|
ISR_NOERR 105
|
||||||
|
ISR_NOERR 106
|
||||||
|
ISR_NOERR 107
|
||||||
|
ISR_NOERR 108
|
||||||
|
ISR_NOERR 109
|
||||||
|
ISR_NOERR 110
|
||||||
|
ISR_NOERR 111
|
||||||
|
ISR_NOERR 112
|
||||||
|
ISR_NOERR 113
|
||||||
|
ISR_NOERR 114
|
||||||
|
ISR_NOERR 115
|
||||||
|
ISR_NOERR 116
|
||||||
|
ISR_NOERR 117
|
||||||
|
ISR_NOERR 118
|
||||||
|
ISR_NOERR 119
|
||||||
|
ISR_NOERR 120
|
||||||
|
ISR_NOERR 121
|
||||||
|
ISR_NOERR 122
|
||||||
|
ISR_NOERR 123
|
||||||
|
ISR_NOERR 124
|
||||||
|
ISR_NOERR 125
|
||||||
|
ISR_NOERR 126
|
||||||
|
ISR_NOERR 127
|
||||||
|
ISR_NOERR 128
|
||||||
|
ISR_NOERR 129
|
||||||
|
ISR_NOERR 130
|
||||||
|
ISR_NOERR 131
|
||||||
|
ISR_NOERR 132
|
||||||
|
ISR_NOERR 133
|
||||||
|
ISR_NOERR 134
|
||||||
|
ISR_NOERR 135
|
||||||
|
ISR_NOERR 136
|
||||||
|
ISR_NOERR 137
|
||||||
|
ISR_NOERR 138
|
||||||
|
ISR_NOERR 139
|
||||||
|
ISR_NOERR 140
|
||||||
|
ISR_NOERR 141
|
||||||
|
ISR_NOERR 142
|
||||||
|
ISR_NOERR 143
|
||||||
|
ISR_NOERR 144
|
||||||
|
ISR_NOERR 145
|
||||||
|
ISR_NOERR 146
|
||||||
|
ISR_NOERR 147
|
||||||
|
ISR_NOERR 148
|
||||||
|
ISR_NOERR 149
|
||||||
|
ISR_NOERR 150
|
||||||
|
ISR_NOERR 151
|
||||||
|
ISR_NOERR 152
|
||||||
|
ISR_NOERR 153
|
||||||
|
ISR_NOERR 154
|
||||||
|
ISR_NOERR 155
|
||||||
|
ISR_NOERR 156
|
||||||
|
ISR_NOERR 157
|
||||||
|
ISR_NOERR 158
|
||||||
|
ISR_NOERR 159
|
||||||
|
ISR_NOERR 160
|
||||||
|
ISR_NOERR 161
|
||||||
|
ISR_NOERR 162
|
||||||
|
ISR_NOERR 163
|
||||||
|
ISR_NOERR 164
|
||||||
|
ISR_NOERR 165
|
||||||
|
ISR_NOERR 166
|
||||||
|
ISR_NOERR 167
|
||||||
|
ISR_NOERR 168
|
||||||
|
ISR_NOERR 169
|
||||||
|
ISR_NOERR 170
|
||||||
|
ISR_NOERR 171
|
||||||
|
ISR_NOERR 172
|
||||||
|
ISR_NOERR 173
|
||||||
|
ISR_NOERR 174
|
||||||
|
ISR_NOERR 175
|
||||||
|
ISR_NOERR 176
|
||||||
|
ISR_NOERR 177
|
||||||
|
ISR_NOERR 178
|
||||||
|
ISR_NOERR 179
|
||||||
|
ISR_NOERR 180
|
||||||
|
ISR_NOERR 181
|
||||||
|
ISR_NOERR 182
|
||||||
|
ISR_NOERR 183
|
||||||
|
ISR_NOERR 184
|
||||||
|
ISR_NOERR 185
|
||||||
|
ISR_NOERR 186
|
||||||
|
ISR_NOERR 187
|
||||||
|
ISR_NOERR 188
|
||||||
|
ISR_NOERR 189
|
||||||
|
ISR_NOERR 190
|
||||||
|
ISR_NOERR 191
|
||||||
|
ISR_NOERR 192
|
||||||
|
ISR_NOERR 193
|
||||||
|
ISR_NOERR 194
|
||||||
|
ISR_NOERR 195
|
||||||
|
ISR_NOERR 196
|
||||||
|
ISR_NOERR 197
|
||||||
|
ISR_NOERR 198
|
||||||
|
ISR_NOERR 199
|
||||||
|
ISR_NOERR 200
|
||||||
|
ISR_NOERR 201
|
||||||
|
ISR_NOERR 202
|
||||||
|
ISR_NOERR 203
|
||||||
|
ISR_NOERR 204
|
||||||
|
ISR_NOERR 205
|
||||||
|
ISR_NOERR 206
|
||||||
|
ISR_NOERR 207
|
||||||
|
ISR_NOERR 208
|
||||||
|
ISR_NOERR 209
|
||||||
|
ISR_NOERR 210
|
||||||
|
ISR_NOERR 211
|
||||||
|
ISR_NOERR 212
|
||||||
|
ISR_NOERR 213
|
||||||
|
ISR_NOERR 214
|
||||||
|
ISR_NOERR 215
|
||||||
|
ISR_NOERR 216
|
||||||
|
ISR_NOERR 217
|
||||||
|
ISR_NOERR 218
|
||||||
|
ISR_NOERR 219
|
||||||
|
ISR_NOERR 220
|
||||||
|
ISR_NOERR 221
|
||||||
|
ISR_NOERR 222
|
||||||
|
ISR_NOERR 223
|
||||||
|
ISR_NOERR 224
|
||||||
|
ISR_NOERR 225
|
||||||
|
ISR_NOERR 226
|
||||||
|
ISR_NOERR 227
|
||||||
|
ISR_NOERR 228
|
||||||
|
ISR_NOERR 229
|
||||||
|
ISR_NOERR 230
|
||||||
|
ISR_NOERR 231
|
||||||
|
ISR_NOERR 232
|
||||||
|
ISR_NOERR 233
|
||||||
|
ISR_NOERR 234
|
||||||
|
ISR_NOERR 235
|
||||||
|
ISR_NOERR 236
|
||||||
|
ISR_NOERR 237
|
||||||
|
ISR_NOERR 238
|
||||||
|
ISR_NOERR 239
|
||||||
|
ISR_NOERR 240
|
||||||
|
ISR_NOERR 241
|
||||||
|
ISR_NOERR 242
|
||||||
|
ISR_NOERR 243
|
||||||
|
ISR_NOERR 244
|
||||||
|
ISR_NOERR 245
|
||||||
|
ISR_NOERR 246
|
||||||
|
ISR_NOERR 247
|
||||||
|
ISR_NOERR 248
|
||||||
|
ISR_NOERR 249
|
||||||
|
ISR_NOERR 250
|
||||||
|
ISR_NOERR 251
|
||||||
|
ISR_NOERR 252
|
||||||
|
ISR_NOERR 253
|
||||||
|
ISR_NOERR 254
|
||||||
|
ISR_NOERR 255
|
||||||
|
|
||||||
|
// === Common ISR handler ===
|
||||||
|
// Stack layout on entry (from ISR stub):
|
||||||
|
// [rsp+0x00] vector (pushed by stub)
|
||||||
|
// [rsp+0x08] error_code (pushed by stub or CPU)
|
||||||
|
// [rsp+0x10] rip (pushed by CPU)
|
||||||
|
// [rsp+0x18] cs (pushed by CPU)
|
||||||
|
// [rsp+0x20] rflags (pushed by CPU)
|
||||||
|
// [rsp+0x28] rsp (pushed by CPU)
|
||||||
|
// [rsp+0x30] ss (pushed by CPU)
|
||||||
|
|
||||||
|
isr_common:
|
||||||
|
// Save all general-purpose registers to form trap_frame
|
||||||
|
push r11
|
||||||
|
push r10
|
||||||
|
push r9
|
||||||
|
push r8
|
||||||
|
push rdi
|
||||||
|
push rsi
|
||||||
|
push rdx
|
||||||
|
push rcx
|
||||||
|
push rax
|
||||||
|
|
||||||
|
// Now RSP points to trap_frame struct, pass as argument
|
||||||
|
mov rdi, rsp
|
||||||
|
call isr_dispatch
|
||||||
|
|
||||||
|
// Restore registers
|
||||||
|
pop rax
|
||||||
|
pop rcx
|
||||||
|
pop rdx
|
||||||
|
pop rsi
|
||||||
|
pop rdi
|
||||||
|
pop r8
|
||||||
|
pop r9
|
||||||
|
pop r10
|
||||||
|
pop r11
|
||||||
|
|
||||||
|
// Skip vector + error_code (16 bytes)
|
||||||
|
add rsp, 16
|
||||||
|
|
||||||
|
iretq
|
||||||
|
|
||||||
|
// === ISR stub table (array of pointers) ===
|
||||||
|
.section .data
|
||||||
|
.global isr_stub_table
|
||||||
|
isr_stub_table:
|
||||||
|
.quad isr_stub_0
|
||||||
|
.quad isr_stub_1
|
||||||
|
.quad isr_stub_2
|
||||||
|
.quad isr_stub_3
|
||||||
|
.quad isr_stub_4
|
||||||
|
.quad isr_stub_5
|
||||||
|
.quad isr_stub_6
|
||||||
|
.quad isr_stub_7
|
||||||
|
.quad isr_stub_8
|
||||||
|
.quad isr_stub_9
|
||||||
|
.quad isr_stub_10
|
||||||
|
.quad isr_stub_11
|
||||||
|
.quad isr_stub_12
|
||||||
|
.quad isr_stub_13
|
||||||
|
.quad isr_stub_14
|
||||||
|
.quad isr_stub_15
|
||||||
|
.quad isr_stub_16
|
||||||
|
.quad isr_stub_17
|
||||||
|
.quad isr_stub_18
|
||||||
|
.quad isr_stub_19
|
||||||
|
.quad isr_stub_20
|
||||||
|
.quad isr_stub_21
|
||||||
|
.quad isr_stub_22
|
||||||
|
.quad isr_stub_23
|
||||||
|
.quad isr_stub_24
|
||||||
|
.quad isr_stub_25
|
||||||
|
.quad isr_stub_26
|
||||||
|
.quad isr_stub_27
|
||||||
|
.quad isr_stub_28
|
||||||
|
.quad isr_stub_29
|
||||||
|
.quad isr_stub_30
|
||||||
|
.quad isr_stub_31
|
||||||
|
.quad isr_stub_32
|
||||||
|
.quad isr_stub_33
|
||||||
|
.quad isr_stub_34
|
||||||
|
.quad isr_stub_35
|
||||||
|
.quad isr_stub_36
|
||||||
|
.quad isr_stub_37
|
||||||
|
.quad isr_stub_38
|
||||||
|
.quad isr_stub_39
|
||||||
|
.quad isr_stub_40
|
||||||
|
.quad isr_stub_41
|
||||||
|
.quad isr_stub_42
|
||||||
|
.quad isr_stub_43
|
||||||
|
.quad isr_stub_44
|
||||||
|
.quad isr_stub_45
|
||||||
|
.quad isr_stub_46
|
||||||
|
.quad isr_stub_47
|
||||||
|
.quad isr_stub_48
|
||||||
|
.quad isr_stub_49
|
||||||
|
.quad isr_stub_50
|
||||||
|
.quad isr_stub_51
|
||||||
|
.quad isr_stub_52
|
||||||
|
.quad isr_stub_53
|
||||||
|
.quad isr_stub_54
|
||||||
|
.quad isr_stub_55
|
||||||
|
.quad isr_stub_56
|
||||||
|
.quad isr_stub_57
|
||||||
|
.quad isr_stub_58
|
||||||
|
.quad isr_stub_59
|
||||||
|
.quad isr_stub_60
|
||||||
|
.quad isr_stub_61
|
||||||
|
.quad isr_stub_62
|
||||||
|
.quad isr_stub_63
|
||||||
|
.quad isr_stub_64
|
||||||
|
.quad isr_stub_65
|
||||||
|
.quad isr_stub_66
|
||||||
|
.quad isr_stub_67
|
||||||
|
.quad isr_stub_68
|
||||||
|
.quad isr_stub_69
|
||||||
|
.quad isr_stub_70
|
||||||
|
.quad isr_stub_71
|
||||||
|
.quad isr_stub_72
|
||||||
|
.quad isr_stub_73
|
||||||
|
.quad isr_stub_74
|
||||||
|
.quad isr_stub_75
|
||||||
|
.quad isr_stub_76
|
||||||
|
.quad isr_stub_77
|
||||||
|
.quad isr_stub_78
|
||||||
|
.quad isr_stub_79
|
||||||
|
.quad isr_stub_80
|
||||||
|
.quad isr_stub_81
|
||||||
|
.quad isr_stub_82
|
||||||
|
.quad isr_stub_83
|
||||||
|
.quad isr_stub_84
|
||||||
|
.quad isr_stub_85
|
||||||
|
.quad isr_stub_86
|
||||||
|
.quad isr_stub_87
|
||||||
|
.quad isr_stub_88
|
||||||
|
.quad isr_stub_89
|
||||||
|
.quad isr_stub_90
|
||||||
|
.quad isr_stub_91
|
||||||
|
.quad isr_stub_92
|
||||||
|
.quad isr_stub_93
|
||||||
|
.quad isr_stub_94
|
||||||
|
.quad isr_stub_95
|
||||||
|
.quad isr_stub_96
|
||||||
|
.quad isr_stub_97
|
||||||
|
.quad isr_stub_98
|
||||||
|
.quad isr_stub_99
|
||||||
|
.quad isr_stub_100
|
||||||
|
.quad isr_stub_101
|
||||||
|
.quad isr_stub_102
|
||||||
|
.quad isr_stub_103
|
||||||
|
.quad isr_stub_104
|
||||||
|
.quad isr_stub_105
|
||||||
|
.quad isr_stub_106
|
||||||
|
.quad isr_stub_107
|
||||||
|
.quad isr_stub_108
|
||||||
|
.quad isr_stub_109
|
||||||
|
.quad isr_stub_110
|
||||||
|
.quad isr_stub_111
|
||||||
|
.quad isr_stub_112
|
||||||
|
.quad isr_stub_113
|
||||||
|
.quad isr_stub_114
|
||||||
|
.quad isr_stub_115
|
||||||
|
.quad isr_stub_116
|
||||||
|
.quad isr_stub_117
|
||||||
|
.quad isr_stub_118
|
||||||
|
.quad isr_stub_119
|
||||||
|
.quad isr_stub_120
|
||||||
|
.quad isr_stub_121
|
||||||
|
.quad isr_stub_122
|
||||||
|
.quad isr_stub_123
|
||||||
|
.quad isr_stub_124
|
||||||
|
.quad isr_stub_125
|
||||||
|
.quad isr_stub_126
|
||||||
|
.quad isr_stub_127
|
||||||
|
.quad isr_stub_128
|
||||||
|
.quad isr_stub_129
|
||||||
|
.quad isr_stub_130
|
||||||
|
.quad isr_stub_131
|
||||||
|
.quad isr_stub_132
|
||||||
|
.quad isr_stub_133
|
||||||
|
.quad isr_stub_134
|
||||||
|
.quad isr_stub_135
|
||||||
|
.quad isr_stub_136
|
||||||
|
.quad isr_stub_137
|
||||||
|
.quad isr_stub_138
|
||||||
|
.quad isr_stub_139
|
||||||
|
.quad isr_stub_140
|
||||||
|
.quad isr_stub_141
|
||||||
|
.quad isr_stub_142
|
||||||
|
.quad isr_stub_143
|
||||||
|
.quad isr_stub_144
|
||||||
|
.quad isr_stub_145
|
||||||
|
.quad isr_stub_146
|
||||||
|
.quad isr_stub_147
|
||||||
|
.quad isr_stub_148
|
||||||
|
.quad isr_stub_149
|
||||||
|
.quad isr_stub_150
|
||||||
|
.quad isr_stub_151
|
||||||
|
.quad isr_stub_152
|
||||||
|
.quad isr_stub_153
|
||||||
|
.quad isr_stub_154
|
||||||
|
.quad isr_stub_155
|
||||||
|
.quad isr_stub_156
|
||||||
|
.quad isr_stub_157
|
||||||
|
.quad isr_stub_158
|
||||||
|
.quad isr_stub_159
|
||||||
|
.quad isr_stub_160
|
||||||
|
.quad isr_stub_161
|
||||||
|
.quad isr_stub_162
|
||||||
|
.quad isr_stub_163
|
||||||
|
.quad isr_stub_164
|
||||||
|
.quad isr_stub_165
|
||||||
|
.quad isr_stub_166
|
||||||
|
.quad isr_stub_167
|
||||||
|
.quad isr_stub_168
|
||||||
|
.quad isr_stub_169
|
||||||
|
.quad isr_stub_170
|
||||||
|
.quad isr_stub_171
|
||||||
|
.quad isr_stub_172
|
||||||
|
.quad isr_stub_173
|
||||||
|
.quad isr_stub_174
|
||||||
|
.quad isr_stub_175
|
||||||
|
.quad isr_stub_176
|
||||||
|
.quad isr_stub_177
|
||||||
|
.quad isr_stub_178
|
||||||
|
.quad isr_stub_179
|
||||||
|
.quad isr_stub_180
|
||||||
|
.quad isr_stub_181
|
||||||
|
.quad isr_stub_182
|
||||||
|
.quad isr_stub_183
|
||||||
|
.quad isr_stub_184
|
||||||
|
.quad isr_stub_185
|
||||||
|
.quad isr_stub_186
|
||||||
|
.quad isr_stub_187
|
||||||
|
.quad isr_stub_188
|
||||||
|
.quad isr_stub_189
|
||||||
|
.quad isr_stub_190
|
||||||
|
.quad isr_stub_191
|
||||||
|
.quad isr_stub_192
|
||||||
|
.quad isr_stub_193
|
||||||
|
.quad isr_stub_194
|
||||||
|
.quad isr_stub_195
|
||||||
|
.quad isr_stub_196
|
||||||
|
.quad isr_stub_197
|
||||||
|
.quad isr_stub_198
|
||||||
|
.quad isr_stub_199
|
||||||
|
.quad isr_stub_200
|
||||||
|
.quad isr_stub_201
|
||||||
|
.quad isr_stub_202
|
||||||
|
.quad isr_stub_203
|
||||||
|
.quad isr_stub_204
|
||||||
|
.quad isr_stub_205
|
||||||
|
.quad isr_stub_206
|
||||||
|
.quad isr_stub_207
|
||||||
|
.quad isr_stub_208
|
||||||
|
.quad isr_stub_209
|
||||||
|
.quad isr_stub_210
|
||||||
|
.quad isr_stub_211
|
||||||
|
.quad isr_stub_212
|
||||||
|
.quad isr_stub_213
|
||||||
|
.quad isr_stub_214
|
||||||
|
.quad isr_stub_215
|
||||||
|
.quad isr_stub_216
|
||||||
|
.quad isr_stub_217
|
||||||
|
.quad isr_stub_218
|
||||||
|
.quad isr_stub_219
|
||||||
|
.quad isr_stub_220
|
||||||
|
.quad isr_stub_221
|
||||||
|
.quad isr_stub_222
|
||||||
|
.quad isr_stub_223
|
||||||
|
.quad isr_stub_224
|
||||||
|
.quad isr_stub_225
|
||||||
|
.quad isr_stub_226
|
||||||
|
.quad isr_stub_227
|
||||||
|
.quad isr_stub_228
|
||||||
|
.quad isr_stub_229
|
||||||
|
.quad isr_stub_230
|
||||||
|
.quad isr_stub_231
|
||||||
|
.quad isr_stub_232
|
||||||
|
.quad isr_stub_233
|
||||||
|
.quad isr_stub_234
|
||||||
|
.quad isr_stub_235
|
||||||
|
.quad isr_stub_236
|
||||||
|
.quad isr_stub_237
|
||||||
|
.quad isr_stub_238
|
||||||
|
.quad isr_stub_239
|
||||||
|
.quad isr_stub_240
|
||||||
|
.quad isr_stub_241
|
||||||
|
.quad isr_stub_242
|
||||||
|
.quad isr_stub_243
|
||||||
|
.quad isr_stub_244
|
||||||
|
.quad isr_stub_245
|
||||||
|
.quad isr_stub_246
|
||||||
|
.quad isr_stub_247
|
||||||
|
.quad isr_stub_248
|
||||||
|
.quad isr_stub_249
|
||||||
|
.quad isr_stub_250
|
||||||
|
.quad isr_stub_251
|
||||||
|
.quad isr_stub_252
|
||||||
|
.quad isr_stub_253
|
||||||
|
.quad isr_stub_254
|
||||||
|
.quad isr_stub_255
|
||||||
|
|
||||||
|
.section .note.GNU-stack,"",@progbits
|
||||||
@@ -0,0 +1,71 @@
|
|||||||
|
#include <pic.h>
|
||||||
|
#include <common.h>
|
||||||
|
#include <serial.h>
|
||||||
|
|
||||||
|
static inline void outb(UINT16 port, UINT8 val) {
|
||||||
|
ASM("outb %0, %1" : : "a"(val), "Nd"(port));
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline UINT8 inb(UINT16 port) {
|
||||||
|
UINT8 ret;
|
||||||
|
ASM("inb %1, %0" : "=a"(ret) : "Nd"(port));
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void pic_wait(void) {
|
||||||
|
// Small delay for slow PICs
|
||||||
|
ASM("jmp 1f\n\t1: jmp 1f\n\t1:");
|
||||||
|
}
|
||||||
|
|
||||||
|
void pic_init(void) {
|
||||||
|
serial_write("PIC: remapping 8259 PIC\n");
|
||||||
|
|
||||||
|
// Save masks
|
||||||
|
UINT8 mask1 = inb(PIC1_DATA);
|
||||||
|
UINT8 mask2 = inb(PIC2_DATA);
|
||||||
|
|
||||||
|
// ICW1: begin initialization, ICW4 needed
|
||||||
|
outb(PIC1_CMD, 0x11); pic_wait();
|
||||||
|
outb(PIC2_CMD, 0x11); pic_wait();
|
||||||
|
|
||||||
|
// ICW2: vector offset
|
||||||
|
outb(PIC1_DATA, PIC_IRQ_BASE); // IRQ 0-7 → vector 0x20-0x27
|
||||||
|
pic_wait();
|
||||||
|
outb(PIC2_DATA, PIC_IRQ_BASE + 8); // IRQ 8-15 → vector 0x28-0x2F
|
||||||
|
pic_wait();
|
||||||
|
|
||||||
|
// ICW3: cascading
|
||||||
|
outb(PIC1_DATA, 0x04); pic_wait(); // slave on IRQ 2
|
||||||
|
outb(PIC2_DATA, 0x02); pic_wait(); // cascade identity
|
||||||
|
|
||||||
|
// ICW4: 8086 mode
|
||||||
|
outb(PIC1_DATA, 0x01); pic_wait();
|
||||||
|
outb(PIC2_DATA, 0x01); pic_wait();
|
||||||
|
|
||||||
|
// Restore masks
|
||||||
|
outb(PIC1_DATA, mask1);
|
||||||
|
outb(PIC2_DATA, mask2);
|
||||||
|
|
||||||
|
serial_write("PIC: remapped IRQ 0-7 → 0x20-0x27\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
void pic_send_eoi(UINT8 irq) {
|
||||||
|
if (irq >= 8) {
|
||||||
|
outb(PIC2_CMD, PIC_EOI);
|
||||||
|
}
|
||||||
|
outb(PIC1_CMD, PIC_EOI);
|
||||||
|
}
|
||||||
|
|
||||||
|
void pic_mask_irq(UINT8 irq) {
|
||||||
|
UINT16 port = (irq < 8) ? PIC1_DATA : PIC2_DATA;
|
||||||
|
UINT8 shift = irq % 8;
|
||||||
|
UINT8 mask = inb(port) | (1 << shift);
|
||||||
|
outb(port, mask);
|
||||||
|
}
|
||||||
|
|
||||||
|
void pic_unmask_irq(UINT8 irq) {
|
||||||
|
UINT16 port = (irq < 8) ? PIC1_DATA : PIC2_DATA;
|
||||||
|
UINT8 shift = irq % 8;
|
||||||
|
UINT8 mask = inb(port) & ~(1 << shift);
|
||||||
|
outb(port, mask);
|
||||||
|
}
|
||||||
@@ -0,0 +1,48 @@
|
|||||||
|
#include <pit.h>
|
||||||
|
#include <common.h>
|
||||||
|
#include <pic.h>
|
||||||
|
#include <serial.h>
|
||||||
|
|
||||||
|
static inline void outb(UINT16 port, UINT8 val) {
|
||||||
|
ASM("outb %0, %1" : : "a"(val), "Nd"(port));
|
||||||
|
}
|
||||||
|
|
||||||
|
static volatile UINT64 g_ticks = 0;
|
||||||
|
static timer_callback_t g_tick_handler = NULL;
|
||||||
|
|
||||||
|
extern "C" void pit_irq_handler(void) {
|
||||||
|
g_ticks++;
|
||||||
|
if (g_tick_handler) {
|
||||||
|
g_tick_handler();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void pit_init(void) {
|
||||||
|
serial_write("PIT: initializing channel 0 at ");
|
||||||
|
serial_write_hex(PIT_TICK_HZ);
|
||||||
|
serial_write(" Hz\n");
|
||||||
|
|
||||||
|
UINT32 divisor = PIT_BASE_FREQ / PIT_TICK_HZ;
|
||||||
|
|
||||||
|
// Command byte: channel 0, lobyte/hibyte, rate generator, binary
|
||||||
|
outb(PIT_COMMAND_PORT, 0x36);
|
||||||
|
|
||||||
|
// Send divisor (low byte first, then high byte)
|
||||||
|
outb(PIT_CHANNEL0_DATA, (UINT8)(divisor & 0xFF));
|
||||||
|
outb(PIT_CHANNEL0_DATA, (UINT8)((divisor >> 8) & 0xFF));
|
||||||
|
|
||||||
|
// Unmask IRQ 0 (timer)
|
||||||
|
pic_unmask_irq(0);
|
||||||
|
|
||||||
|
serial_write("PIT: divisor = ");
|
||||||
|
serial_write_hex(divisor);
|
||||||
|
serial_write("\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
void pit_set_tick_handler(timer_callback_t handler) {
|
||||||
|
g_tick_handler = handler;
|
||||||
|
}
|
||||||
|
|
||||||
|
UINT64 pit_get_ticks(void) {
|
||||||
|
return g_ticks;
|
||||||
|
}
|
||||||
+55
-11
@@ -8,11 +8,14 @@
|
|||||||
#include <memory/heap.h>
|
#include <memory/heap.h>
|
||||||
#include <scheduler.h>
|
#include <scheduler.h>
|
||||||
#include <fs.h>
|
#include <fs.h>
|
||||||
|
#include <gdt.h>
|
||||||
|
#include <idt.h>
|
||||||
|
#include <pic.h>
|
||||||
|
#include <pit.h>
|
||||||
|
|
||||||
extern EFI_SYSTEM_TABLE *ST;
|
extern EFI_SYSTEM_TABLE *ST;
|
||||||
|
|
||||||
inline void init_gop() {
|
inline void init_gop() {
|
||||||
// 初始化 GOP
|
|
||||||
EFI_GUID gop_guid = EFI_GRAPHICS_OUTPUT_PROTOCOL_GUID;
|
EFI_GUID gop_guid = EFI_GRAPHICS_OUTPUT_PROTOCOL_GUID;
|
||||||
EFI_GRAPHICS_OUTPUT_PROTOCOL *GOP;
|
EFI_GRAPHICS_OUTPUT_PROTOCOL *GOP;
|
||||||
uefi_call_wrapper(ST->BootServices->SetWatchdogTimer, 4, 0, 0, 0, NULL);
|
uefi_call_wrapper(ST->BootServices->SetWatchdogTimer, 4, 0, 0, 0, NULL);
|
||||||
@@ -21,7 +24,6 @@ inline void init_gop() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
inline void init_serial() {
|
inline void init_serial() {
|
||||||
// 初始化串行驱动
|
|
||||||
EFI_SERIAL_IO_PROTOCOL *SerialIo = NULL;
|
EFI_SERIAL_IO_PROTOCOL *SerialIo = NULL;
|
||||||
EFI_GUID gEfiSerialIoProtocolGuid = EFI_SERIAL_IO_PROTOCOL_GUID;
|
EFI_GUID gEfiSerialIoProtocolGuid = EFI_SERIAL_IO_PROTOCOL_GUID;
|
||||||
EFI_HANDLE *SerialHandles = NULL;
|
EFI_HANDLE *SerialHandles = NULL;
|
||||||
@@ -45,6 +47,27 @@ inline void init_serial() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// External: PIT IRQ handler defined in pit.cpp
|
||||||
|
extern "C" void pit_irq_handler(void);
|
||||||
|
|
||||||
|
// PIC IRQ handler — dispatches IRQ 0 (timer)
|
||||||
|
static void irq_handler(trap_frame* frame) {
|
||||||
|
UINT8 vector = (UINT8)frame->vector;
|
||||||
|
UINT8 irq = vector - PIC_IRQ_BASE;
|
||||||
|
|
||||||
|
// Send EOI BEFORE handling, so PIC can deliver new interrupts
|
||||||
|
// immediately after a context switch inside the handler.
|
||||||
|
pic_send_eoi(irq);
|
||||||
|
|
||||||
|
switch (irq) {
|
||||||
|
case 0: // PIT timer
|
||||||
|
pit_irq_handler();
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
extern "C" void kernel_main() {
|
extern "C" void kernel_main() {
|
||||||
init_gop();
|
init_gop();
|
||||||
init_serial();
|
init_serial();
|
||||||
@@ -53,7 +76,7 @@ extern "C" void kernel_main() {
|
|||||||
uefi_call_wrapper(ST->ConOut->OutputString, 2, ST->ConOut, (CHAR16*)L"Kernel is running!\n");
|
uefi_call_wrapper(ST->ConOut->OutputString, 2, ST->ConOut, (CHAR16*)L"Kernel is running!\n");
|
||||||
|
|
||||||
uefi_call_wrapper(ST->ConOut->ClearScreen, 1, ST->ConOut);
|
uefi_call_wrapper(ST->ConOut->ClearScreen, 1, ST->ConOut);
|
||||||
serial_write("\n\n"); // 防止和前面串了serial.log看不清
|
serial_write("\n\n");
|
||||||
|
|
||||||
// init memory managers
|
// init memory managers
|
||||||
serial_write("Sylva: init PMM...\n");
|
serial_write("Sylva: init PMM...\n");
|
||||||
@@ -108,27 +131,48 @@ extern "C" void kernel_main() {
|
|||||||
pf_print("Welcome to Sylva OS!\n");
|
pf_print("Welcome to Sylva OS!\n");
|
||||||
serial_write(" Kernel prepared well.\n");
|
serial_write(" Kernel prepared well.\n");
|
||||||
|
|
||||||
|
// --- Interrupt infrastructure ---
|
||||||
|
serial_write("Sylva: init GDT...\n");
|
||||||
|
gdt_init();
|
||||||
|
|
||||||
|
serial_write("Sylva: init IDT...\n");
|
||||||
|
idt_init();
|
||||||
|
|
||||||
|
serial_write("Sylva: init PIC...\n");
|
||||||
|
pic_init();
|
||||||
|
|
||||||
|
// Register IRQ handler (vector 0x20 = PIC_IRQ_BASE + 0)
|
||||||
|
idt_set_handler(PIC_IRQ_BASE + 0, irq_handler);
|
||||||
|
|
||||||
|
serial_write("Sylva: init PIT...\n");
|
||||||
|
pit_init();
|
||||||
|
pit_set_tick_handler(scheduler_tick);
|
||||||
|
|
||||||
|
// Enable interrupts
|
||||||
|
ASM("sti");
|
||||||
|
serial_write("Sylva: interrupts enabled\n");
|
||||||
|
|
||||||
// --- Multitasking demo ---
|
// --- Multitasking demo ---
|
||||||
serial_write("Sylva: creating tasks...\n");
|
serial_write("Sylva: creating tasks...\n");
|
||||||
|
|
||||||
// Task A: prints a message 3 times, yielding between each
|
// Task A: prints messages — preemption handles time slicing
|
||||||
task_create("taskA", []() {
|
task_create("taskA", []() {
|
||||||
for (int i = 0; i < 3; i++) {
|
for (int i = 0; i < 10; i++) {
|
||||||
serial_write("[taskA] running iteration ");
|
serial_write("[taskA] running iteration ");
|
||||||
serial_write_hex(i);
|
serial_write_hex(i);
|
||||||
serial_write("\n");
|
serial_write("\n");
|
||||||
yield();
|
for (volatile int j = 0; j < 50000000; j++) {}
|
||||||
}
|
}
|
||||||
serial_write("[taskA] done\n");
|
serial_write("[taskA] done\n");
|
||||||
});
|
});
|
||||||
|
|
||||||
// Task B: prints a message 5 times
|
// Task B: prints messages
|
||||||
task_create("taskB", []() {
|
task_create("taskB", []() {
|
||||||
for (int i = 0; i < 5; i++) {
|
for (int i = 0; i < 5; i++) {
|
||||||
serial_write("[taskB] hello from taskB #");
|
serial_write("[taskB] hello from taskB #");
|
||||||
serial_write_hex(i);
|
serial_write_hex(i);
|
||||||
serial_write("\n");
|
serial_write("\n");
|
||||||
yield();
|
for (volatile int j = 0; j < 50000000; j++) {}
|
||||||
}
|
}
|
||||||
serial_write("[taskB] done\n");
|
serial_write("[taskB] done\n");
|
||||||
});
|
});
|
||||||
@@ -136,10 +180,10 @@ extern "C" void kernel_main() {
|
|||||||
// Task C: short task
|
// Task C: short task
|
||||||
task_create("taskC", []() {
|
task_create("taskC", []() {
|
||||||
serial_write("[taskC] quick task\n");
|
serial_write("[taskC] quick task\n");
|
||||||
yield();
|
for (volatile int j = 0; j < 50000000; j++) {}
|
||||||
serial_write("[taskC] finished\n");
|
serial_write("[taskC] finished\n");
|
||||||
});
|
});
|
||||||
|
|
||||||
serial_write("Sylva: starting scheduler\n");
|
serial_write("Sylva: starting preemptive scheduler\n");
|
||||||
scheduler_run(); // never returns
|
scheduler_run(); // never returns
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,7 +5,19 @@
|
|||||||
// rsi = new_rsp (value of new stack pointer)
|
// rsi = new_rsp (value of new stack pointer)
|
||||||
//
|
//
|
||||||
// Saves/restores callee-saved registers only.
|
// Saves/restores callee-saved registers only.
|
||||||
// On first switch into a new task, ret lands on task_entry_trampoline.
|
// The caller-saved registers are already saved on the task's stack
|
||||||
|
// by the ISR stub (for preemptive switching) or are not in use
|
||||||
|
// (for the initial switch).
|
||||||
|
//
|
||||||
|
// For preemptive switching:
|
||||||
|
// - Timer IRQ fires, ISR stub pushes rax-r11 + trap_frame
|
||||||
|
// - C code runs (isr_dispatch → timer handler → scheduler)
|
||||||
|
// - context_switch saves/restores callee-saved regs + switches RSP
|
||||||
|
// - On return, C code unwinds, isr_common pops rax-r11 + iretq
|
||||||
|
//
|
||||||
|
// For new tasks:
|
||||||
|
// - task_create sets up a fake trap_frame on the stack
|
||||||
|
// - context_switch pops callee-saved regs, returns into task_entry_trampoline
|
||||||
.global context_switch
|
.global context_switch
|
||||||
context_switch:
|
context_switch:
|
||||||
push rbx
|
push rbx
|
||||||
|
|||||||
@@ -1,4 +1,6 @@
|
|||||||
#include <scheduler.h>
|
#include <scheduler.h>
|
||||||
|
#include <idt.h>
|
||||||
|
#include <pic.h>
|
||||||
#include <memory/heap.h>
|
#include <memory/heap.h>
|
||||||
#include <memory/pmm.h>
|
#include <memory/pmm.h>
|
||||||
#include <common.h>
|
#include <common.h>
|
||||||
@@ -13,16 +15,15 @@ static task_t* g_current = NULL;
|
|||||||
static task_t* g_task_list = NULL; // circular linked list head
|
static task_t* g_task_list = NULL; // circular linked list head
|
||||||
|
|
||||||
// Trampoline: first thing a new task runs after context_switch.
|
// Trampoline: first thing a new task runs after context_switch.
|
||||||
// The entry function pointer is stored in the task's name field
|
|
||||||
// (we repurpose a slot — actually we store it in a simple global array).
|
|
||||||
static void (*g_task_entries[TASK_MAX])(void);
|
static void (*g_task_entries[TASK_MAX])(void);
|
||||||
|
|
||||||
extern "C" void task_entry_trampoline() {
|
extern "C" void task_entry_trampoline() {
|
||||||
|
ASM("sti");
|
||||||
task_t* cur = scheduler_current();
|
task_t* cur = scheduler_current();
|
||||||
if (cur && g_task_entries[cur->id]) {
|
if (cur && g_task_entries[cur->id]) {
|
||||||
g_task_entries[cur->id](); // call the user function
|
g_task_entries[cur->id]();
|
||||||
}
|
}
|
||||||
task_exit(); // clean up when done
|
task_exit();
|
||||||
}
|
}
|
||||||
|
|
||||||
task_t* task_create(const char* name, void (*entry)(void)) {
|
task_t* task_create(const char* name, void (*entry)(void)) {
|
||||||
@@ -34,7 +35,6 @@ task_t* task_create(const char* name, void (*entry)(void)) {
|
|||||||
UINT32 id = g_task_count++;
|
UINT32 id = g_task_count++;
|
||||||
task_t* task = &g_tasks[id];
|
task_t* task = &g_tasks[id];
|
||||||
|
|
||||||
// Store entry function for the trampoline
|
|
||||||
g_task_entries[id] = entry;
|
g_task_entries[id] = entry;
|
||||||
|
|
||||||
// Allocate kernel stack
|
// Allocate kernel stack
|
||||||
@@ -47,10 +47,10 @@ task_t* task_create(const char* name, void (*entry)(void)) {
|
|||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Fill task struct
|
|
||||||
task->id = id;
|
task->id = id;
|
||||||
task->state = TASK_STATE_READY;
|
task->state = TASK_STATE_READY;
|
||||||
task->stack_base = stack;
|
task->stack_base = stack;
|
||||||
|
task->time_slice = TIME_SLICE_DEFAULT;
|
||||||
|
|
||||||
// Copy name
|
// Copy name
|
||||||
const char* s = name;
|
const char* s = name;
|
||||||
@@ -73,12 +73,13 @@ task_t* task_create(const char* name, void (*entry)(void)) {
|
|||||||
// r14 = 0
|
// r14 = 0
|
||||||
// r15 = 0 <- RSP points here initially
|
// r15 = 0 <- RSP points here initially
|
||||||
//
|
//
|
||||||
|
// When preempted by timer IRQ, the ISR stub saves a full trap_frame
|
||||||
|
// on the task's stack — that layout is only created by hardware+ISR.
|
||||||
|
//
|
||||||
UINT64* sp = (UINT64*)((UINT8*)stack + TASK_STACK_SIZE);
|
UINT64* sp = (UINT64*)((UINT8*)stack + TASK_STACK_SIZE);
|
||||||
|
|
||||||
// Push return address (task_entry_trampoline)
|
|
||||||
*--sp = (UINT64)task_entry_trampoline;
|
*--sp = (UINT64)task_entry_trampoline;
|
||||||
|
|
||||||
// Push callee-saved registers (all zero)
|
|
||||||
*--sp = 0; // rbx
|
*--sp = 0; // rbx
|
||||||
*--sp = 0; // rbp
|
*--sp = 0; // rbp
|
||||||
*--sp = 0; // r12
|
*--sp = 0; // r12
|
||||||
@@ -90,13 +91,12 @@ task_t* task_create(const char* name, void (*entry)(void)) {
|
|||||||
|
|
||||||
// Insert into circular linked list
|
// Insert into circular linked list
|
||||||
if (g_task_list == NULL) {
|
if (g_task_list == NULL) {
|
||||||
task->next = task; // points to itself (single element circle)
|
task->next = task;
|
||||||
g_task_list = task;
|
g_task_list = task;
|
||||||
} else {
|
} else {
|
||||||
// Insert after current tail (g_task_list is the "last" in circle)
|
|
||||||
task->next = g_task_list->next;
|
task->next = g_task_list->next;
|
||||||
g_task_list->next = task;
|
g_task_list->next = task;
|
||||||
g_task_list = task; // new tail
|
g_task_list = task;
|
||||||
}
|
}
|
||||||
|
|
||||||
serial_write("SCHED: created task '");
|
serial_write("SCHED: created task '");
|
||||||
@@ -108,28 +108,71 @@ task_t* task_create(const char* name, void (*entry)(void)) {
|
|||||||
return task;
|
return task;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Find next READY task in the circular list, starting from g_current->next
|
||||||
|
static task_t* find_next_ready(void) {
|
||||||
|
if (g_current == NULL || g_task_list == NULL) return NULL;
|
||||||
|
|
||||||
|
task_t* next = g_current->next;
|
||||||
|
task_t* start = next;
|
||||||
|
|
||||||
|
do {
|
||||||
|
if (next->state == TASK_STATE_READY) {
|
||||||
|
return next;
|
||||||
|
}
|
||||||
|
next = next->next;
|
||||||
|
} while (next != start);
|
||||||
|
|
||||||
|
return NULL; // no READY tasks
|
||||||
|
}
|
||||||
|
|
||||||
void yield(void) {
|
void yield(void) {
|
||||||
if (g_current == NULL || g_task_list == NULL) return;
|
if (g_current == NULL || g_task_list == NULL) return;
|
||||||
|
|
||||||
task_t* cur = g_current;
|
task_t* cur = g_current;
|
||||||
task_t* next = cur->next;
|
task_t* next = find_next_ready();
|
||||||
|
|
||||||
// Skip terminated tasks
|
if (next == NULL || next == cur) return;
|
||||||
while (next->state == TASK_STATE_TERMINATED && next != cur) {
|
|
||||||
next = next->next;
|
|
||||||
}
|
|
||||||
if (next->state == TASK_STATE_TERMINATED) return; // all terminated
|
|
||||||
|
|
||||||
if (next == cur) return; // only one task, nothing to do
|
|
||||||
|
|
||||||
if (cur->state != TASK_STATE_TERMINATED)
|
if (cur->state != TASK_STATE_TERMINATED)
|
||||||
cur->state = TASK_STATE_READY;
|
cur->state = TASK_STATE_READY;
|
||||||
next->state = TASK_STATE_RUNNING;
|
next->state = TASK_STATE_RUNNING;
|
||||||
|
next->time_slice = TIME_SLICE_DEFAULT;
|
||||||
g_current = next;
|
g_current = next;
|
||||||
|
|
||||||
context_switch(&cur->rsp, next->rsp);
|
context_switch(&cur->rsp, next->rsp);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Timer tick handler — called from PIT IRQ 0
|
||||||
|
void scheduler_tick(void) {
|
||||||
|
if (g_current == NULL) return;
|
||||||
|
|
||||||
|
// Decrement time slice
|
||||||
|
if (g_current->time_slice > 0) {
|
||||||
|
g_current->time_slice--;
|
||||||
|
}
|
||||||
|
|
||||||
|
// If time slice expired, preempt
|
||||||
|
if (g_current->time_slice == 0) {
|
||||||
|
task_t* cur = g_current;
|
||||||
|
task_t* next = find_next_ready();
|
||||||
|
|
||||||
|
if (next == NULL || next == cur) {
|
||||||
|
// No other task ready, or only this task — reload time slice
|
||||||
|
cur->time_slice = TIME_SLICE_DEFAULT;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Preempt
|
||||||
|
cur->state = TASK_STATE_READY;
|
||||||
|
cur->time_slice = TIME_SLICE_DEFAULT;
|
||||||
|
next->state = TASK_STATE_RUNNING;
|
||||||
|
next->time_slice = TIME_SLICE_DEFAULT;
|
||||||
|
g_current = next;
|
||||||
|
|
||||||
|
context_switch(&cur->rsp, next->rsp);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void scheduler_run(void) {
|
void scheduler_run(void) {
|
||||||
if (g_task_list == NULL) {
|
if (g_task_list == NULL) {
|
||||||
serial_write("SCHED: no tasks to run\n");
|
serial_write("SCHED: no tasks to run\n");
|
||||||
@@ -137,7 +180,7 @@ void scheduler_run(void) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Find first READY task
|
// Find first READY task
|
||||||
task_t* start = g_task_list->next; // head of circle
|
task_t* start = g_task_list->next;
|
||||||
task_t* t = start;
|
task_t* t = start;
|
||||||
do {
|
do {
|
||||||
if (t->state == TASK_STATE_READY) {
|
if (t->state == TASK_STATE_READY) {
|
||||||
@@ -153,14 +196,14 @@ void scheduler_run(void) {
|
|||||||
|
|
||||||
g_current = t;
|
g_current = t;
|
||||||
t->state = TASK_STATE_RUNNING;
|
t->state = TASK_STATE_RUNNING;
|
||||||
|
t->time_slice = TIME_SLICE_DEFAULT;
|
||||||
|
|
||||||
serial_write("SCHED: starting task '");
|
serial_write("SCHED: starting task '");
|
||||||
serial_write(t->name);
|
serial_write(t->name);
|
||||||
serial_write("'\n");
|
serial_write("'\n");
|
||||||
|
|
||||||
// First context switch — no old RSP to save (we're still in scheduler_run)
|
// First context switch — switch to the task's stack
|
||||||
// Just switch to the task's stack directly.
|
// This will never return (until all tasks terminate)
|
||||||
// We need a dummy old_rsp to satisfy the API, but we never return here.
|
|
||||||
UINT64 dummy_rsp;
|
UINT64 dummy_rsp;
|
||||||
context_switch(&dummy_rsp, t->rsp);
|
context_switch(&dummy_rsp, t->rsp);
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user