mirror of
https://github.com/subhobhai943/SUB-OS.git
synced 2026-10-26 00:52:50 +00:00
Initial commit: SUB-OS 64-Bit Production Monolithic Operating System with LazyBox userland suite
This commit is contained in:
commit
cd9c786d14
88 files changed
+7132
No files matched your search
@@ -0,0 +1,37 @@
|
||||
[BITS 64]
|
||||
|
||||
extern kernel_main
|
||||
extern __bss_start
|
||||
extern __bss_end
|
||||
extern stack_top
|
||||
|
||||
global kernel_entry
|
||||
|
||||
section .text
|
||||
kernel_entry:
|
||||
; 1. Set up high-performance dedicated 64 KB kernel stack
|
||||
mov rsp, stack_top
|
||||
|
||||
; 2. Preserve bootloader arguments safely in callee-saved registers R12 & R13
|
||||
mov r12, rdi ; memory_map pointer
|
||||
mov r13, rsi ; memory_map count
|
||||
|
||||
; 3. Zero out the entire BSS section (.bss)
|
||||
mov rdi, __bss_start
|
||||
mov rcx, __bss_end
|
||||
sub rcx, rdi
|
||||
xor al, al
|
||||
cld
|
||||
rep stosb
|
||||
|
||||
; 4. Restore bootloader arguments into RDI and RSI per AMD64 System V ABI
|
||||
mov rdi, r12
|
||||
mov rsi, r13
|
||||
|
||||
; 5. Call kernel_main(memory_map, memory_map_count)
|
||||
call kernel_main
|
||||
|
||||
.hang:
|
||||
cli
|
||||
hlt
|
||||
jmp .hang
|
||||
@@ -0,0 +1,65 @@
|
||||
#include <arch/x86_64/cpuid.h>
|
||||
#include <lib/string.h>
|
||||
|
||||
static cpu_info_t global_cpu_info;
|
||||
static bool cpu_detected = false;
|
||||
|
||||
static inline void cpuid(uint32_t code, uint32_t* a, uint32_t* b, uint32_t* c, uint32_t* d) {
|
||||
__asm__ volatile("cpuid"
|
||||
: "=a"(*a), "=b"(*b), "=c"(*c), "=d"(*d)
|
||||
: "a"(code));
|
||||
}
|
||||
|
||||
void cpuid_detect(cpu_info_t* info) {
|
||||
uint32_t eax, ebx, ecx, edx;
|
||||
|
||||
memset(info, 0, sizeof(cpu_info_t));
|
||||
|
||||
// 1. Get Vendor String
|
||||
cpuid(0, &eax, &ebx, &ecx, &edx);
|
||||
((uint32_t*)info->vendor)[0] = ebx;
|
||||
((uint32_t*)info->vendor)[1] = edx;
|
||||
((uint32_t*)info->vendor)[2] = ecx;
|
||||
info->vendor[12] = '\0';
|
||||
|
||||
// 2. Get Features & Model Info
|
||||
cpuid(1, &eax, &ebx, &ecx, &edx);
|
||||
info->stepping = eax & 0x0F;
|
||||
info->model_id = (eax >> 4) & 0x0F;
|
||||
info->family = (eax >> 8) & 0x0F;
|
||||
|
||||
info->has_fpu = (edx & (1 << 0)) != 0;
|
||||
info->has_tsc = (edx & (1 << 4)) != 0;
|
||||
info->has_msr = (edx & (1 << 5)) != 0;
|
||||
info->has_pae = (edx & (1 << 6)) != 0;
|
||||
info->has_apic = (edx & (1 << 9)) != 0;
|
||||
info->has_sse = (edx & (1 << 25)) != 0;
|
||||
info->has_sse2 = (edx & (1 << 26)) != 0;
|
||||
info->has_sse3 = (ecx & (1 << 0)) != 0;
|
||||
info->has_sse4_1= (ecx & (1 << 19)) != 0;
|
||||
info->has_sse4_2= (ecx & (1 << 20)) != 0;
|
||||
info->has_avx = (ecx & (1 << 28)) != 0;
|
||||
info->has_rdrand= (ecx & (1 << 30)) != 0;
|
||||
|
||||
// 3. Get Brand String (Extended Functions)
|
||||
cpuid(0x80000000, &eax, &ebx, &ecx, &edx);
|
||||
if (eax >= 0x80000004) {
|
||||
uint32_t* brand = (uint32_t*)info->model;
|
||||
cpuid(0x80000002, &brand[0], &brand[1], &brand[2], &brand[3]);
|
||||
cpuid(0x80000003, &brand[4], &brand[5], &brand[6], &brand[7]);
|
||||
cpuid(0x80000004, &brand[8], &brand[9], &brand[10], &brand[11]);
|
||||
info->model[48] = '\0';
|
||||
} else {
|
||||
strcpy(info->model, "x86_64 Compatible Processor");
|
||||
}
|
||||
|
||||
global_cpu_info = *info;
|
||||
cpu_detected = true;
|
||||
}
|
||||
|
||||
const cpu_info_t* cpuid_get_info(void) {
|
||||
if (!cpu_detected) {
|
||||
cpuid_detect(&global_cpu_info);
|
||||
}
|
||||
return &global_cpu_info;
|
||||
}
|
||||
@@ -0,0 +1,65 @@
|
||||
#include <arch/x86_64/gdt.h>
|
||||
#include <lib/string.h>
|
||||
|
||||
extern void gdt_flush(uint64_t gdt_ptr);
|
||||
extern void tss_flush(void);
|
||||
|
||||
static gdt_entry_t gdt_entries[7];
|
||||
static gdt_ptr_t gdt_ptr;
|
||||
static tss_entry_t tss_entry;
|
||||
|
||||
static void gdt_set_gate(int num, uint32_t base, uint32_t limit, uint8_t access, uint8_t gran) {
|
||||
gdt_entries[num].base_low = (base & 0xFFFF);
|
||||
gdt_entries[num].base_middle = (base >> 16) & 0xFF;
|
||||
gdt_entries[num].base_high = (base >> 24) & 0xFF;
|
||||
|
||||
gdt_entries[num].limit_low = (limit & 0xFFFF);
|
||||
gdt_entries[num].granularity = (limit >> 16) & 0x0F;
|
||||
|
||||
gdt_entries[num].granularity |= gran & 0xF0;
|
||||
gdt_entries[num].access = access;
|
||||
}
|
||||
|
||||
static void write_tss(int num, uint64_t base, uint32_t limit) {
|
||||
gdt_set_gate(num, (uint32_t)base, limit, 0x89, 0x00);
|
||||
|
||||
// TSS descriptor takes 16 bytes in 64-bit mode (2 entries)
|
||||
uint32_t* high_part = (uint32_t*)&gdt_entries[num + 1];
|
||||
high_part[0] = (uint32_t)(base >> 32);
|
||||
high_part[1] = 0;
|
||||
}
|
||||
|
||||
void gdt_init(void) {
|
||||
gdt_ptr.limit = sizeof(gdt_entries) - 1;
|
||||
gdt_ptr.base = (uint64_t)&gdt_entries;
|
||||
|
||||
// 0x00: Null Descriptor
|
||||
gdt_set_gate(0, 0, 0, 0, 0);
|
||||
|
||||
// 0x08: Kernel 64-bit Code Segment (Access=0x9A, Gran=0x20 for Long Mode)
|
||||
gdt_set_gate(1, 0, 0xFFFFFFFF, 0x9A, 0x20);
|
||||
|
||||
// 0x10: Kernel 64-bit Data Segment (Access=0x92, Gran=0x00)
|
||||
gdt_set_gate(2, 0, 0xFFFFFFFF, 0x92, 0x00);
|
||||
|
||||
// 0x18: User 64-bit Code Segment (Access=0xFA, Gran=0x20)
|
||||
gdt_set_gate(3, 0, 0xFFFFFFFF, 0xFA, 0x20);
|
||||
|
||||
// 0x20: User 64-bit Data Segment (Access=0xF2, Gran=0x00)
|
||||
gdt_set_gate(4, 0, 0xFFFFFFFF, 0xF2, 0x00);
|
||||
|
||||
// 0x28: TSS (Task State Segment) - takes slots 5 & 6
|
||||
extern char stack_top[];
|
||||
memset(&tss_entry, 0, sizeof(tss_entry_t));
|
||||
tss_entry.rsp0 = (uint64_t)stack_top;
|
||||
tss_entry.ist1 = (uint64_t)stack_top;
|
||||
tss_entry.iomap_base = sizeof(tss_entry_t);
|
||||
write_tss(5, (uint64_t)&tss_entry, sizeof(tss_entry_t) - 1);
|
||||
|
||||
gdt_flush((uint64_t)&gdt_ptr);
|
||||
tss_flush();
|
||||
}
|
||||
|
||||
void gdt_set_kernel_stack(uint64_t stack) {
|
||||
tss_entry.rsp0 = stack;
|
||||
}
|
||||
@@ -0,0 +1,29 @@
|
||||
[BITS 64]
|
||||
|
||||
global gdt_flush
|
||||
global tss_flush
|
||||
|
||||
section .text
|
||||
gdt_flush:
|
||||
lgdt [rdi]
|
||||
; Reload data segments
|
||||
mov ax, 0x10
|
||||
mov ds, ax
|
||||
mov es, ax
|
||||
mov fs, ax
|
||||
mov gs, ax
|
||||
mov ss, ax
|
||||
|
||||
; Reload CS via far return
|
||||
push 0x08
|
||||
lea rax, [rel .reload_cs]
|
||||
push rax
|
||||
retfq
|
||||
|
||||
.reload_cs:
|
||||
ret
|
||||
|
||||
tss_flush:
|
||||
mov ax, 0x28
|
||||
ltr ax
|
||||
ret
|
||||
@@ -0,0 +1,34 @@
|
||||
#include <arch/x86_64/idt.h>
|
||||
#include <lib/string.h>
|
||||
|
||||
extern void idt_flush(uint64_t idt_ptr);
|
||||
|
||||
static idt_entry_t idt_entries[IDT_ENTRIES];
|
||||
static idt_ptr_t idt_ptr;
|
||||
|
||||
void idt_set_gate(uint8_t vector, void* isr, uint8_t flags) {
|
||||
uint64_t addr = (uint64_t)isr;
|
||||
idt_entries[vector].isr_low = (uint16_t)(addr & 0xFFFF);
|
||||
idt_entries[vector].kernel_cs = 0x08;
|
||||
idt_entries[vector].ist = 0;
|
||||
idt_entries[vector].attributes = flags;
|
||||
idt_entries[vector].isr_mid = (uint16_t)((addr >> 16) & 0xFFFF);
|
||||
idt_entries[vector].isr_high = (uint32_t)((addr >> 32) & 0xFFFFFFFF);
|
||||
idt_entries[vector].reserved = 0;
|
||||
}
|
||||
|
||||
void idt_enable_gate(uint8_t vector) {
|
||||
idt_entries[vector].attributes |= 0x80;
|
||||
}
|
||||
|
||||
void idt_disable_gate(uint8_t vector) {
|
||||
idt_entries[vector].attributes &= ~0x80;
|
||||
}
|
||||
|
||||
void idt_init(void) {
|
||||
idt_ptr.limit = sizeof(idt_entries) - 1;
|
||||
idt_ptr.base = (uint64_t)&idt_entries;
|
||||
|
||||
memset(&idt_entries, 0, sizeof(idt_entries));
|
||||
idt_flush((uint64_t)&idt_ptr);
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
[BITS 64]
|
||||
|
||||
global idt_flush
|
||||
|
||||
section .text
|
||||
idt_flush:
|
||||
lidt [rdi]
|
||||
ret
|
||||
@@ -0,0 +1,87 @@
|
||||
#include <arch/x86_64/isr.h>
|
||||
#include <arch/x86_64/idt.h>
|
||||
#include <arch/x86_64/pic.h>
|
||||
#include <kernel/printk.h>
|
||||
#include <kernel/panic.h>
|
||||
#include <lib/string.h>
|
||||
|
||||
extern void* isr_stub_table[48];
|
||||
|
||||
static isr_handler_t interrupt_handlers[256];
|
||||
|
||||
static const char* exception_messages[32] = {
|
||||
"Division By Zero",
|
||||
"Debug",
|
||||
"Non-Maskable Interrupt",
|
||||
"Breakpoint",
|
||||
"Into Detected Overflow",
|
||||
"Out of Bounds",
|
||||
"Invalid Opcode",
|
||||
"No Coprocessor",
|
||||
"Double Fault",
|
||||
"Coprocessor Segment Overrun",
|
||||
"Bad TSS",
|
||||
"Segment Not Present",
|
||||
"Stack Fault",
|
||||
"General Protection Fault",
|
||||
"Page Fault",
|
||||
"Unknown Interrupt",
|
||||
"Coprocessor Fault",
|
||||
"Alignment Check",
|
||||
"Machine Check",
|
||||
"SIMD Floating-Point Exception",
|
||||
"Virtualization Exception",
|
||||
"Control Protection Exception",
|
||||
"Reserved",
|
||||
"Reserved",
|
||||
"Reserved",
|
||||
"Reserved",
|
||||
"Reserved",
|
||||
"Reserved",
|
||||
"Hypervisor Injection Exception",
|
||||
"VMM Communication Exception",
|
||||
"Security Exception",
|
||||
"Reserved"
|
||||
};
|
||||
|
||||
void isr_register_handler(uint8_t int_no, isr_handler_t handler) {
|
||||
interrupt_handlers[int_no] = handler;
|
||||
}
|
||||
|
||||
void isr_unregister_handler(uint8_t int_no) {
|
||||
interrupt_handlers[int_no] = NULL;
|
||||
}
|
||||
|
||||
void isr_handler_common(registers_t* regs) {
|
||||
if (regs->int_no < 32) {
|
||||
// CPU Exception Fault
|
||||
printk(KERN_EMERG "\n[EXCEPTION] Vector %llu: %s (Error code: 0x%llx)\n",
|
||||
regs->int_no, exception_messages[regs->int_no], regs->error_code);
|
||||
panic_with_regs(exception_messages[regs->int_no], regs);
|
||||
}
|
||||
|
||||
if (interrupt_handlers[regs->int_no] != NULL) {
|
||||
interrupt_handlers[regs->int_no](regs);
|
||||
}
|
||||
|
||||
// Acknowledge Hardware PIC Interrupts (IRQs 32-47)
|
||||
if (regs->int_no >= 32 && regs->int_no < 48) {
|
||||
pic_send_eoi((uint8_t)(regs->int_no - 32));
|
||||
}
|
||||
}
|
||||
|
||||
extern void* isr_stub_default;
|
||||
|
||||
void isr_init(void) {
|
||||
memset(interrupt_handlers, 0, sizeof(interrupt_handlers));
|
||||
|
||||
// 1. Initialize all 256 gates to isr_stub_default
|
||||
for (int i = 0; i < 256; i++) {
|
||||
idt_set_gate(i, isr_stub_default, 0x8E);
|
||||
}
|
||||
|
||||
// 2. Install dedicated CPU exception gates (0-31) and hardware IRQ gates (32-47)
|
||||
for (uint8_t i = 0; i < 48; i++) {
|
||||
idt_set_gate(i, isr_stub_table[i], 0x8E);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,133 @@
|
||||
[BITS 64]
|
||||
|
||||
extern isr_handler_common
|
||||
global isr_stub_table
|
||||
global isr_stub_default
|
||||
|
||||
%macro ISR_NOERRCODE 1
|
||||
isr_stub_%1:
|
||||
push qword 0 ; Dummy error code
|
||||
push qword %1 ; Interrupt vector number
|
||||
jmp isr_common_stub
|
||||
%endmacro
|
||||
|
||||
%macro ISR_ERRCODE 1
|
||||
isr_stub_%1:
|
||||
push qword %1 ; Interrupt vector number (error code already on stack)
|
||||
jmp isr_common_stub
|
||||
%endmacro
|
||||
|
||||
section .text
|
||||
|
||||
; CPU Exceptions 0-31
|
||||
ISR_NOERRCODE 0
|
||||
ISR_NOERRCODE 1
|
||||
ISR_NOERRCODE 2
|
||||
ISR_NOERRCODE 3
|
||||
ISR_NOERRCODE 4
|
||||
ISR_NOERRCODE 5
|
||||
ISR_NOERRCODE 6
|
||||
ISR_NOERRCODE 7
|
||||
ISR_ERRCODE 8
|
||||
ISR_NOERRCODE 9
|
||||
ISR_ERRCODE 10
|
||||
ISR_ERRCODE 11
|
||||
ISR_ERRCODE 12
|
||||
ISR_ERRCODE 13
|
||||
ISR_ERRCODE 14
|
||||
ISR_NOERRCODE 15
|
||||
ISR_NOERRCODE 16
|
||||
ISR_ERRCODE 17
|
||||
ISR_NOERRCODE 18
|
||||
ISR_NOERRCODE 19
|
||||
ISR_NOERRCODE 20
|
||||
ISR_NOERRCODE 21
|
||||
ISR_NOERRCODE 22
|
||||
ISR_NOERRCODE 23
|
||||
ISR_NOERRCODE 24
|
||||
ISR_NOERRCODE 25
|
||||
ISR_NOERRCODE 26
|
||||
ISR_NOERRCODE 27
|
||||
ISR_NOERRCODE 28
|
||||
ISR_NOERRCODE 29
|
||||
ISR_ERRCODE 30
|
||||
ISR_NOERRCODE 31
|
||||
|
||||
; Hardware IRQs 32-47
|
||||
ISR_NOERRCODE 32
|
||||
ISR_NOERRCODE 33
|
||||
ISR_NOERRCODE 34
|
||||
ISR_NOERRCODE 35
|
||||
ISR_NOERRCODE 36
|
||||
ISR_NOERRCODE 37
|
||||
ISR_NOERRCODE 38
|
||||
ISR_NOERRCODE 39
|
||||
ISR_NOERRCODE 40
|
||||
ISR_NOERRCODE 41
|
||||
ISR_NOERRCODE 42
|
||||
ISR_NOERRCODE 43
|
||||
ISR_NOERRCODE 44
|
||||
ISR_NOERRCODE 45
|
||||
ISR_NOERRCODE 46
|
||||
ISR_NOERRCODE 47
|
||||
|
||||
isr_stub_default:
|
||||
push qword 0
|
||||
push qword 255
|
||||
jmp isr_common_stub
|
||||
|
||||
isr_common_stub:
|
||||
push rax
|
||||
push rbx
|
||||
push rcx
|
||||
push rdx
|
||||
push rsi
|
||||
push rdi
|
||||
push rbp
|
||||
push r8
|
||||
push r9
|
||||
push r10
|
||||
push r11
|
||||
push r12
|
||||
push r13
|
||||
push r14
|
||||
push r15
|
||||
|
||||
mov rdi, rsp
|
||||
cld
|
||||
call isr_handler_common
|
||||
|
||||
pop r15
|
||||
pop r14
|
||||
pop r13
|
||||
pop r12
|
||||
pop r11
|
||||
pop r10
|
||||
pop r9
|
||||
pop r8
|
||||
pop rbp
|
||||
pop rdi
|
||||
pop rsi
|
||||
pop rdx
|
||||
pop rcx
|
||||
pop rbx
|
||||
pop rax
|
||||
|
||||
add rsp, 16
|
||||
iretq
|
||||
|
||||
section .data
|
||||
align 8
|
||||
isr_stub_table:
|
||||
dq isr_stub_0, isr_stub_1, isr_stub_2, isr_stub_3
|
||||
dq isr_stub_4, isr_stub_5, isr_stub_6, isr_stub_7
|
||||
dq isr_stub_8, isr_stub_9, isr_stub_10, isr_stub_11
|
||||
dq isr_stub_12, isr_stub_13, isr_stub_14, isr_stub_15
|
||||
dq isr_stub_16, isr_stub_17, isr_stub_18, isr_stub_19
|
||||
dq isr_stub_20, isr_stub_21, isr_stub_22, isr_stub_23
|
||||
dq isr_stub_24, isr_stub_25, isr_stub_26, isr_stub_27
|
||||
dq isr_stub_28, isr_stub_29, isr_stub_30, isr_stub_31
|
||||
dq isr_stub_32, isr_stub_33, isr_stub_34, isr_stub_35
|
||||
dq isr_stub_36, isr_stub_37, isr_stub_38, isr_stub_39
|
||||
dq isr_stub_40, isr_stub_41, isr_stub_42, isr_stub_43
|
||||
dq isr_stub_44, isr_stub_45, isr_stub_46, isr_stub_47
|
||||
@@ -0,0 +1,78 @@
|
||||
#include <arch/x86_64/pic.h>
|
||||
#include <arch/x86_64/io.h>
|
||||
|
||||
#define PIC1_COMMAND 0x20
|
||||
#define PIC1_DATA 0x21
|
||||
#define PIC2_COMMAND 0xA0
|
||||
#define PIC2_DATA 0xA1
|
||||
|
||||
#define PIC_EOI 0x20
|
||||
|
||||
#define ICW1_INIT 0x10
|
||||
#define ICW1_ICW4 0x01
|
||||
#define ICW4_8086 0x01
|
||||
|
||||
void pic_send_eoi(uint8_t irq) {
|
||||
if (irq >= 8) {
|
||||
outb(PIC2_COMMAND, PIC_EOI);
|
||||
}
|
||||
outb(PIC1_COMMAND, PIC_EOI);
|
||||
}
|
||||
|
||||
void pic_init(void) {
|
||||
outb(PIC1_COMMAND, ICW1_INIT | ICW1_ICW4);
|
||||
io_wait();
|
||||
outb(PIC2_COMMAND, ICW1_INIT | ICW1_ICW4);
|
||||
io_wait();
|
||||
|
||||
// Remap Master PIC to 0x20 (32), Slave PIC to 0x28 (40)
|
||||
outb(PIC1_DATA, 0x20);
|
||||
io_wait();
|
||||
outb(PIC2_DATA, 0x28);
|
||||
io_wait();
|
||||
|
||||
outb(PIC1_DATA, 4); // Tell Master that Slave is at IRQ2
|
||||
io_wait();
|
||||
outb(PIC2_DATA, 2); // Tell Slave its cascade identity
|
||||
io_wait();
|
||||
|
||||
outb(PIC1_DATA, ICW4_8086);
|
||||
io_wait();
|
||||
outb(PIC2_DATA, ICW4_8086);
|
||||
io_wait();
|
||||
|
||||
// Mask all interrupts initially except Cascade (IRQ2)
|
||||
outb(PIC1_DATA, 0xFB);
|
||||
outb(PIC2_DATA, 0xFF);
|
||||
}
|
||||
|
||||
void pic_set_mask(uint8_t irq) {
|
||||
uint16_t port;
|
||||
if (irq < 8) {
|
||||
port = PIC1_DATA;
|
||||
} else {
|
||||
port = PIC2_DATA;
|
||||
irq -= 8;
|
||||
}
|
||||
uint8_t value = inb(port) | (1 << irq);
|
||||
outb(port, value);
|
||||
}
|
||||
|
||||
void pic_clear_mask(uint8_t irq) {
|
||||
uint16_t port;
|
||||
if (irq < 8) {
|
||||
port = PIC1_DATA;
|
||||
} else {
|
||||
port = PIC2_DATA;
|
||||
irq -= 8;
|
||||
uint8_t master_val = inb(PIC1_DATA) & ~(1 << 2);
|
||||
outb(PIC1_DATA, master_val);
|
||||
}
|
||||
uint8_t value = inb(port) & ~(1 << irq);
|
||||
outb(port, value);
|
||||
}
|
||||
|
||||
void pic_disable(void) {
|
||||
outb(PIC1_DATA, 0xFF);
|
||||
outb(PIC2_DATA, 0xFF);
|
||||
}
|
||||
@@ -0,0 +1,49 @@
|
||||
#include <arch/x86_64/pit.h>
|
||||
#include <arch/x86_64/isr.h>
|
||||
#include <arch/x86_64/pic.h>
|
||||
#include <arch/x86_64/io.h>
|
||||
#include <kernel/sched.h>
|
||||
|
||||
#define PIT_COMMAND_PORT 0x43
|
||||
#define PIT_CHANNEL0_PORT 0x40
|
||||
#define PIT_BASE_FREQUENCY 1193182
|
||||
|
||||
static volatile uint64_t pit_ticks = 0;
|
||||
static uint32_t pit_freq = 100;
|
||||
|
||||
static void pit_handler(registers_t* regs) {
|
||||
(void)regs;
|
||||
pit_ticks++;
|
||||
|
||||
// Notify preemptive scheduler
|
||||
sched_tick();
|
||||
}
|
||||
|
||||
void pit_init(uint32_t frequency) {
|
||||
pit_freq = frequency;
|
||||
uint32_t divisor = PIT_BASE_FREQUENCY / frequency;
|
||||
|
||||
// Channel 0, lobyte/hibyte, Rate generator (Mode 2)
|
||||
outb(PIT_COMMAND_PORT, 0x36);
|
||||
outb(PIT_CHANNEL0_PORT, (uint8_t)(divisor & 0xFF));
|
||||
outb(PIT_CHANNEL0_PORT, (uint8_t)((divisor >> 8) & 0xFF));
|
||||
|
||||
// Register IRQ0 handler
|
||||
isr_register_handler(32, pit_handler);
|
||||
pic_clear_mask(0);
|
||||
}
|
||||
|
||||
uint64_t pit_get_ticks(void) {
|
||||
return pit_ticks;
|
||||
}
|
||||
|
||||
uint64_t pit_get_uptime_ms(void) {
|
||||
return (pit_ticks * 1000) / pit_freq;
|
||||
}
|
||||
|
||||
void pit_sleep(uint32_t milliseconds) {
|
||||
uint64_t target = pit_ticks + (milliseconds * pit_freq) / 1000;
|
||||
while (pit_ticks < target) {
|
||||
hlt();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,92 @@
|
||||
#include <arch/x86_64/paging.h>
|
||||
#include <mm/pmm.h>
|
||||
#include <lib/string.h>
|
||||
|
||||
static pml4e_t* kernel_pml4 = (pml4e_t*)0x1000;
|
||||
|
||||
void paging_flush_tlb_single(uint64_t virt) {
|
||||
__asm__ volatile("invlpg (%0)" : : "r"(virt) : "memory");
|
||||
}
|
||||
|
||||
void paging_init(void) {
|
||||
// PML4 is already loaded at 0x1000 by Stage 2 bootloader with 4GB mapped
|
||||
kernel_pml4 = (pml4e_t*)0x1000;
|
||||
}
|
||||
|
||||
void paging_map_page(uint64_t virt, uint64_t phys, uint64_t flags) {
|
||||
size_t pml4_idx = (virt >> 39) & 0x1FF;
|
||||
size_t pdpt_idx = (virt >> 30) & 0x1FF;
|
||||
size_t pd_idx = (virt >> 21) & 0x1FF;
|
||||
size_t pt_idx = (virt >> 12) & 0x1FF;
|
||||
|
||||
if (!(kernel_pml4[pml4_idx] & PAGE_PRESENT)) {
|
||||
void* new_pdpt = pmm_alloc_page();
|
||||
if (!new_pdpt) return;
|
||||
memset(new_pdpt, 0, PAGE_SIZE);
|
||||
kernel_pml4[pml4_idx] = (uint64_t)new_pdpt | PAGE_PRESENT | PAGE_WRITABLE | (flags & PAGE_USER);
|
||||
}
|
||||
|
||||
pdpte_t* pdpt = (pdpte_t*)(kernel_pml4[pml4_idx] & ~0xFFFULL);
|
||||
if (!(pdpt[pdpt_idx] & PAGE_PRESENT)) {
|
||||
void* new_pd = pmm_alloc_page();
|
||||
if (!new_pd) return;
|
||||
memset(new_pd, 0, PAGE_SIZE);
|
||||
pdpt[pdpt_idx] = (uint64_t)new_pd | PAGE_PRESENT | PAGE_WRITABLE | (flags & PAGE_USER);
|
||||
}
|
||||
|
||||
pde_t* pd = (pde_t*)(pdpt[pdpt_idx] & ~0xFFFULL);
|
||||
if (!(pd[pd_idx] & PAGE_PRESENT)) {
|
||||
void* new_pt = pmm_alloc_page();
|
||||
if (!new_pt) return;
|
||||
memset(new_pt, 0, PAGE_SIZE);
|
||||
pd[pd_idx] = (uint64_t)new_pt | PAGE_PRESENT | PAGE_WRITABLE | (flags & PAGE_USER);
|
||||
}
|
||||
|
||||
pte_t* pt = (pte_t*)(pd[pd_idx] & ~0xFFFULL);
|
||||
pt[pt_idx] = (phys & ~0xFFFULL) | flags | PAGE_PRESENT;
|
||||
|
||||
paging_flush_tlb_single(virt);
|
||||
}
|
||||
|
||||
void paging_unmap_page(uint64_t virt) {
|
||||
size_t pml4_idx = (virt >> 39) & 0x1FF;
|
||||
size_t pdpt_idx = (virt >> 30) & 0x1FF;
|
||||
size_t pd_idx = (virt >> 21) & 0x1FF;
|
||||
size_t pt_idx = (virt >> 12) & 0x1FF;
|
||||
|
||||
if (!(kernel_pml4[pml4_idx] & PAGE_PRESENT)) return;
|
||||
pdpte_t* pdpt = (pdpte_t*)(kernel_pml4[pml4_idx] & ~0xFFFULL);
|
||||
|
||||
if (!(pdpt[pdpt_idx] & PAGE_PRESENT)) return;
|
||||
pde_t* pd = (pde_t*)(pdpt[pdpt_idx] & ~0xFFFULL);
|
||||
|
||||
if (!(pd[pd_idx] & PAGE_PRESENT)) return;
|
||||
pte_t* pt = (pte_t*)(pd[pd_idx] & ~0xFFFULL);
|
||||
|
||||
pt[pt_idx] = 0;
|
||||
paging_flush_tlb_single(virt);
|
||||
}
|
||||
|
||||
uint64_t paging_get_phys(uint64_t virt) {
|
||||
size_t pml4_idx = (virt >> 39) & 0x1FF;
|
||||
size_t pdpt_idx = (virt >> 30) & 0x1FF;
|
||||
size_t pd_idx = (virt >> 21) & 0x1FF;
|
||||
size_t pt_idx = (virt >> 12) & 0x1FF;
|
||||
|
||||
if (!(kernel_pml4[pml4_idx] & PAGE_PRESENT)) return 0;
|
||||
pdpte_t* pdpt = (pdpte_t*)(kernel_pml4[pml4_idx] & ~0xFFFULL);
|
||||
|
||||
if (!(pdpt[pdpt_idx] & PAGE_PRESENT)) return 0;
|
||||
pde_t* pd = (pde_t*)(pdpt[pdpt_idx] & ~0xFFFULL);
|
||||
|
||||
// Check for 2MB huge page
|
||||
if (pd[pd_idx] & PAGE_HUGE) {
|
||||
return (pd[pd_idx] & ~0x1FFFFFULL) | (virt & 0x1FFFFF);
|
||||
}
|
||||
|
||||
if (!(pd[pd_idx] & PAGE_PRESENT)) return 0;
|
||||
pte_t* pt = (pte_t*)(pd[pd_idx] & ~0xFFFULL);
|
||||
|
||||
if (!(pt[pt_idx] & PAGE_PRESENT)) return 0;
|
||||
return (pt[pt_idx] & ~0xFFFULL) | (virt & 0xFFF);
|
||||
}
|
||||
Reference in new issue
Block a user