did some restructuring, got multitasking almost working

This commit is contained in:
2026-06-26 20:05:01 -05:00
parent 57d7d34c6d
commit 43bc0df81a
35 changed files with 481 additions and 307 deletions

View File

@@ -9,11 +9,11 @@
"-Wextra", "-Wextra",
"-Ikernel", "-Ikernel",
"-o", "-o",
"obj/kernel/boot/boot.o", "obj/kernel/drivers/pit/pit.S.o",
"kernel/boot/boot.S" "kernel/drivers/pit/pit.S"
], ],
"directory": "/home/slinky/source/RockOS", "directory": "/home/slinky/source/RockOS",
"file": "/home/slinky/source/RockOS/kernel/boot/boot.S", "file": "/home/slinky/source/RockOS/kernel/drivers/pit/pit.S",
"output": "/home/slinky/source/RockOS/obj/kernel/boot/boot.o" "output": "/home/slinky/source/RockOS/obj/kernel/drivers/pit/pit.S.o"
} }
] ]

View File

@@ -116,3 +116,8 @@ outsw:
pop %esi pop %esi
leave leave
ret ret
.global fetch_cr3
fetch_cr3:
mov %cr3, %eax
ret

View File

@@ -1,7 +1,12 @@
#include "drivers/pic/pic.h" #define PIC1_ADDR 0x20 + 0xC0000000
#define PIC2_ADDR 0xA0 + 0xC0000000
#define PIC1_COMMAND PIC1_ADDR
#define PIC1_DATA (PIC1_ADDR+1)
#define PIC2_COMMAND PIC2_ADDR
#define PIC2_DATA (PIC2_ADDR+1)
#define PIC_EOI 0x20
.code32 .code32
.extern io_wait
.global init_pic .global init_pic
init_pic: init_pic:

View File

@@ -1,7 +1,9 @@
#define PIC1_ADDR 0x20 + 0xC0000000 #ifndef DPIC_H
#define PIC2_ADDR 0xA0 + 0xC0000000 #define DPIC_H
#define PIC1_COMMAND PIC1_ADDR
#define PIC1_DATA (PIC1_ADDR+1) void init_pic();
#define PIC2_COMMAND PIC2_ADDR
#define PIC2_DATA (PIC2_ADDR+1) void send_eoi_master();
#define PIC_EOI 0x20 void send_eoi_slave();
#endif

View File

@@ -1,7 +1,4 @@
#include "drivers/pit/pit.h"
.code32 .code32
.global init_pit .global init_pit
init_pit: # tickrate: 1193182/1000 = 0x04A9 (1000hz) (1ms) init_pit: # tickrate: 1193182/1000 = 0x04A9 (1000hz) (1ms)
movb $0x36, %al movb $0x36, %al

View File

@@ -0,0 +1,6 @@
#ifndef DPIT_H
#define DPIT_H
void init_pit();
#endif

View File

@@ -9,8 +9,6 @@
.global ps2_write_data .global ps2_write_data
.global ps2_flush_output_buffer .global ps2_flush_output_buffer
.extern io_wait
# helpers # helpers
ps2_wait_input_empty: #(void) -> void ps2_wait_input_empty: #(void) -> void
push %ebp push %ebp

View File

@@ -1,4 +1,5 @@
#include <stdint.h> #include <stdint.h>
#include <drivers/ps2/ps2.h> #include <drivers/ps2/ps2.h>
extern void ps2_wait_input_empty(void); extern void ps2_wait_input_empty(void);

View File

@@ -16,4 +16,10 @@
#define SELF_TEST_SUCCESS 0x55 #define SELF_TEST_SUCCESS 0x55
#define PORT_TEST_SUCCESS 0x00 #define PORT_TEST_SUCCESS 0x00
#ifndef __ASSEMBLER__
#include <stdint.h>
int init_ps2();
uint8_t ps2_read_data();
#endif
#endif #endif

View File

@@ -26,10 +26,10 @@ enum vga_color {
VGA_COLOR_WHITE = 15, VGA_COLOR_WHITE = 15,
}; };
size_t terminal_row; static size_t terminal_row;
size_t terminal_column; static size_t terminal_column;
uint8_t terminal_color; static uint8_t terminal_color;
uint16_t* terminal_buffer = (uint16_t*)VGA_MEMORY; static uint16_t* terminal_buffer = (uint16_t*)VGA_MEMORY;
static inline uint8_t vga_entry_color(enum vga_color fg, enum vga_color bg) static inline uint8_t vga_entry_color(enum vga_color fg, enum vga_color bg)
{ {
@@ -41,8 +41,7 @@ static inline uint16_t vga_entry(unsigned char uc, uint8_t color)
return (uint16_t) uc | (uint16_t) color << 8; return (uint16_t) uc | (uint16_t) color << 8;
} }
void vga_initialize() void vga_init() {
{
terminal_row = 0; terminal_row = 0;
terminal_column = 0; terminal_column = 0;
terminal_color = vga_entry_color(VGA_COLOR_LIGHT_GREY, VGA_COLOR_BLACK); terminal_color = vga_entry_color(VGA_COLOR_LIGHT_GREY, VGA_COLOR_BLACK);
@@ -55,8 +54,7 @@ void vga_initialize()
} }
} }
void vga_putchar(char c) void vga_putchar(char c) {
{
if (c == '\n') { if (c == '\n') {
terminal_row++; terminal_row++;
terminal_column = 0; terminal_column = 0;
@@ -78,8 +76,3 @@ void vga_putchar(char c)
terminal_row = 0; terminal_row = 0;
} }
} }
print_stream_t vga_print_stream = {
.putchar = vga_putchar,
.trunc = vga_initialize,
};

7
kernel/drivers/vga/vga.h Normal file
View File

@@ -0,0 +1,7 @@
#ifndef DVGA_H
#define DVGA_H
void vga_init();
void vga_putchar(char c);
#endif

View File

@@ -1,4 +1,5 @@
.code32 .code32
.extern gdtr .extern gdtr
.global load_gdt .global load_gdt
load_gdt: load_gdt:

View File

@@ -84,7 +84,7 @@ tss_entry tss;
extern void load_gdt(); extern void load_gdt();
extern void tss_flush(); extern void tss_flush();
uint64_t create_descriptor(uint32_t base, uint32_t limit, uint16_t flag) static uint64_t create_descriptor(uint32_t base, uint32_t limit, uint16_t flag)
{ {
uint64_t descriptor; uint64_t descriptor;
@@ -101,7 +101,7 @@ uint64_t create_descriptor(uint32_t base, uint32_t limit, uint16_t flag)
return descriptor; return descriptor;
} }
uint64_t create_tss_descriptor(uint32_t base, uint32_t limit) static uint64_t create_tss_descriptor(uint32_t base, uint32_t limit)
{ {
uint64_t descriptor; uint64_t descriptor;
uint16_t tss_flags = SEG_PRES(1) | SEG_PRIV(0) | SEG_DESCTYPE(0) | 0x09; uint16_t tss_flags = SEG_PRES(1) | SEG_PRIV(0) | SEG_DESCTYPE(0) | 0x09;

6
kernel/gdt.h Normal file
View File

@@ -0,0 +1,6 @@
#ifndef KGDT_H
#define KGDT_H
void init_gdt();
#endif

View File

@@ -1,8 +1,7 @@
#include <lib/stream.h>
#include <stddef.h> #include <stddef.h>
#include "multiboot.h" #include "multiboot.h"
print_stream_t* kout;
multiboot_info* grub_boot_struct_ptr = NULL; multiboot_info* grub_boot_struct_ptr = NULL;
extern char __kernel_start; extern char __kernel_start;

View File

@@ -1,61 +0,0 @@
#include <stdint.h>
#include <idt.h>
#define IDT_MAX_DESCRIPTORS 256
#define ATTR_KERN_32 0x8E // active(1), ring 0 (00), interrupt gate(0), 32 bit (1110)
#define ATTR_USER_32 0xEE // active, ring 3, 32bit
#define SEGMENT_KERN 0x08
extern void load_idt(void);
extern void enable_int(void);
extern void isr0();
extern void isr1();
extern void isr8();
extern void isr13();
extern void isr14();
extern void isr32();
extern void isr33();
void* isr_stub_table[256] = {
[0] = isr0,
[1] = isr1,
[8] = isr8,
[13] = isr13,
[14] = isr14,
[32] = isr32,
[33] = isr33,
};
idt_entry idt[IDT_MAX_DESCRIPTORS];
idt_ptr idtr;
void set_idtr(uint8_t vector, void* isr, uint16_t sel, uint8_t attributes) {
idt_entry* desc = &idt[vector];
desc->isr_low = (uint32_t)isr & 0xFFFF;
desc->selector = SEGMENT_KERN;
desc->reserved = 0;
desc->attributes = attributes;
desc->isr_high = ((uint32_t)isr >> 16) & 0xFFFF;
}
void init_idt() {
idtr.limit = (sizeof(idt_entry) * IDT_MAX_DESCRIPTORS) - 1;
idtr.base = (uint32_t)&idt;
for (int i = 0; i < IDT_MAX_DESCRIPTORS; i++) {
if (isr_stub_table[i] != 0) {
set_idtr(i, isr_stub_table[i], SEGMENT_KERN, ATTR_KERN_32);
} else {
set_idtr(i, 0, SEGMENT_KERN, 0);
}
}
extern void syscall_handler();
set_idtr(0x80, syscall_handler, SEGMENT_KERN, ATTR_USER_32);
load_idt();
}

View File

@@ -1,19 +0,0 @@
#ifndef KIDT_H
#define KIDT_H
#include <stdint.h>
typedef struct __attribute__((packed)){
uint16_t isr_low;
uint16_t selector;
uint8_t reserved;
uint8_t attributes;
uint16_t isr_high;
} idt_entry;
typedef struct __attribute__((packed)){
uint16_t limit;
uint32_t base;
} idt_ptr;
#endif

View File

@@ -1,5 +1,4 @@
.code32 .code32
.macro ISR_NOERRCODE num .macro ISR_NOERRCODE num
.global isr\num .global isr\num
isr\num: isr\num:
@@ -33,18 +32,29 @@ load_idt:
lidt idtr lidt idtr
ret ret
.global enable_int
enable_int:
sti
ret
ISR_NOERRCODE 0 # Divide by Zero ISR_NOERRCODE 0 # Divide by Zero
ISR_NOERRCODE 1 # Debug ISR_NOERRCODE 1 # Debug
ISR_ERRCODE 8 # Double Fault (Has Error Code!) ISR_ERRCODE 8 # Double Fault (Has Error Code!)
ISR_ERRCODE 13 # General Protection Fault (Has Error Code!) ISR_ERRCODE 13 # General Protection Fault (Has Error Code!)
ISR_ERRCODE 14 # Page Fault (Has Error Code!) ISR_ERRCODE 14 # Page Fault (Has Error Code!)
ISR_NOERRCODE 32 # IRQ0 - Timer // This is a special case so we need to handle it for task switching
.global isr32
isr32:
cli
pushal
pushl %esp
call schedule_next_task
movl %eax, %esp
call send_eoi_master
popal
sti
iret
ISR_NOERRCODE 33 # IRQ1 - Keyboard ISR_NOERRCODE 33 # IRQ1 - Keyboard
ISR_NOERRCODE 46 # IRQ14 ISR_NOERRCODE 46 # IRQ14

View File

@@ -1,23 +1,61 @@
#include "lib/print.h"
#include <stdint.h> #include <stdint.h>
extern void send_eoi_master(void); #include <lib/print.h>
extern void send_eoi_slave(void);
extern uint8_t read_isr_master(void);
extern uint8_t read_isr_slave(void);
extern uint8_t ps2_read_data(); #include "syscall.h"
struct registers { #include <drivers/pic/pic.h>
#include <drivers/ps2/ps2.h>
#define IDT_MAX_DESCRIPTORS 256
#define ATTR_KERN_32 0x8E // active(1), ring 0 (00), interrupt gate(0), 32 bit (1110)
#define ATTR_USER_32 0xEE // active, ring 3, 32bit
#define SEGMENT_KERN 0x08
typedef struct __attribute__((packed)) {
uint16_t isr_low;
uint16_t selector;
uint8_t reserved;
uint8_t attributes;
uint16_t isr_high;
} idt_entry;
typedef struct __attribute__((packed)) {
uint16_t limit;
uint32_t base;
} idt_ptr;
typedef struct __attribute__((packed)) {
uint32_t edi, esi, ebp, esp_dummy, ebx, edx, ecx, eax; uint32_t edi, esi, ebp, esp_dummy, ebx, edx, ecx, eax;
uint32_t int_no; uint32_t int_no;
uint32_t error_code; uint32_t error_code;
uint32_t eip, cs, eflags, useresp, ss; uint32_t eip, cs, eflags, useresp, ss;
} registers;
extern void load_idt(void);
// isr stubs
extern void isr0();
extern void isr1();
extern void isr8();
extern void isr13();
extern void isr14();
extern void isr32();
extern void isr33();
static void* isr_stub_table[256] = {
[0] = isr0,
[1] = isr1,
[8] = isr8,
[13] = isr13,
[14] = isr14,
[32] = isr32,
[33] = isr33,
}; };
const char* err_messages[32] = { static const char* err_messages[32] = {
[0] = "Divide by 0", [0] = "Divide by 0",
[1] = "", [1] = "",
[8] = "", [8] = "",
@@ -25,7 +63,37 @@ const char* err_messages[32] = {
[14] = "Page Fault", [14] = "Page Fault",
}; };
void common_interrupt_handler(struct registers *args) { idt_entry idt[IDT_MAX_DESCRIPTORS];
idt_ptr idtr;
static void set_idtr(uint8_t vector, void* isr, uint16_t sel, uint8_t attributes) {
idt_entry* desc = &idt[vector];
desc->isr_low = (uint32_t)isr & 0xFFFF;
desc->selector = SEGMENT_KERN;
desc->reserved = 0;
desc->attributes = attributes;
desc->isr_high = ((uint32_t)isr >> 16) & 0xFFFF;
}
void init_idt() {
idtr.limit = (sizeof(idt_entry) * IDT_MAX_DESCRIPTORS) - 1;
idtr.base = (uint32_t)&idt;
for (int i = 0; i < IDT_MAX_DESCRIPTORS; i++) {
if (isr_stub_table[i] != 0) {
set_idtr(i, isr_stub_table[i], SEGMENT_KERN, ATTR_KERN_32);
} else {
set_idtr(i, 0, SEGMENT_KERN, 0);
}
}
set_idtr(0x80, syscall_handler, SEGMENT_KERN, ATTR_USER_32);
load_idt();
}
void common_interrupt_handler(registers *args) {
switch (args->int_no) { switch (args->int_no) {
case 0: case 0:
case 1: case 1:

6
kernel/interrupts.h Normal file
View File

@@ -0,0 +1,6 @@
#ifndef KIDT_H
#define KIDT_H
void init_idt();
#endif

View File

@@ -1,150 +1,62 @@
#include "multiboot.h" #include "multiboot.h"
#include "idt.h" #include "interrupts.h"
#include "elf.h" #include "elf.h"
#include "gdt.h"
#include "scheduler.h"
#include <lib/print.h> #include <lib/print.h>
#include <lib/stream.h> #include <lib/stream.h>
#include <lib/memory.h> #include <lib/memory.h>
#include "memory/mm.h" #include <memory/mm.h>
#include "drivers/iso/iso.h" #include <drivers/iso/iso.h>
#include "drivers/ide/ide.h" #include <drivers/ide/ide.h>
#include <drivers/pic/pic.h>
#include <drivers/ps2/ps2.h>
#include <drivers/pit/pit.h>
#include <drivers/vga/vga.h>
#include <stddef.h> #include <stddef.h>
#include <stdint.h> #include <stdint.h>
extern void init_idt();
extern void init_gdt();
extern void init_pic();
extern void init_pit();
extern int init_ps2();
extern void enable_interrupts(); extern void enable_interrupts();
extern void disable_interrupts();
void* page = NULL; extern uint32_t fetch_cr3();
extern char __kernel_start; extern char __kernel_start;
extern char __kernel_end; extern char __kernel_end;
void* user_page_directories[10]; void kernel_test_task() {
while (1) {
void load_origin_program(multiboot_info* mbi) { kprintf("task sleeping...\n");
user_page_directories[0] = create_user_pd(); sleep(10000000);
kprintf("Created origin process page directory @ [phys] 0x%x\n", user_page_directories[0]);
extern void load_pd(void* pd);
extern void flush_tlb();
load_pd(user_page_directories[0]);
flush_tlb();
kprintf("switched to user address space\n");
uint32_t mods_virtual_addr = mbi->mods_addr + 0xC0000000;
kprintf("parsing mutliboot modules @ 0x%x\n", mods_virtual_addr);
if (mbi->mods_count == 0) {
return;
} }
multiboot_module_entry* modules = (multiboot_module_entry*)mods_virtual_addr;
uint32_t elf_vbase = 0xE0000000;
uint32_t elf_pbase = modules[0].mod_start;
uint32_t elf_limit = modules[0].mod_end - modules[0].mod_start;
uint32_t elf_pages_needed = (elf_limit / 4096) + 1;
for (uint32_t i = 0; i < elf_pages_needed; i++) {
const uint32_t vaddr = elf_vbase + (i * 4096);
const uint32_t paddr = elf_pbase + (i * 4096);
map_page(vaddr, paddr, PAGE_PRESENT | PAGE_WRITABLE);
}
elf_header_t* elf = (elf_header_t*)elf_vbase;
elf_program_header_t* ph = (elf_program_header_t*)(elf_vbase + elf->e_phoff);
kprintf("elf header @ 0x%x\n", elf);
kprintf("program headers @ 0x%x\n", ph);
// load program sections into physical memory and map the pages
for (int i = 0; i < elf->e_phnum; i++) {
if (ph[i].p_type == PT_LOAD) {
uint32_t v_start = ph[i].p_vaddr & 0xFFFFF000;
uint32_t v_end = (ph[i].p_vaddr + ph[i].p_memsz + 4095) & 0xFFFFF000;
for (uint32_t page = v_start; page < v_end; page += 4096) {
uint32_t frame_paddr = (uint32_t)p_alloc_frame();
map_page(page, frame_paddr, PAGE_PRESENT | PAGE_WRITABLE | PAGE_USER);
}
for (uint32_t j = 0; j < ph[i].p_memsz; j++) {
((char*)ph[i].p_vaddr)[j] = 0;
}
for (uint32_t j = 0; j < ph[i].p_filesz; j++) {
((char*)ph[i].p_vaddr)[j] = ((char*)(elf_vbase + ph[i].p_offset))[j];
}
}
}
// allocate the user stack
uint32_t stack_paddr = (uint32_t)p_alloc_frame();
map_page(0xBFFFF000, stack_paddr, PAGE_PRESENT | PAGE_WRITABLE | PAGE_USER);
kprintf("program loaded into memory @ [virt] 0x%x\n", elf->e_entry);
extern void liftoff(uint32_t entry, uint32_t stack_top);
kprintf("launching origin process\n");
uint32_t stack_top = 0xBFFFF000 + 4095;
liftoff(elf->e_entry, stack_top);
} }
void kmain(uint32_t magic, multiboot_info* mbi) { void kmain(uint32_t magic, multiboot_info* mbi) {
extern print_stream_t vga_print_stream;
extern print_stream_t* kout;
kout = &vga_print_stream;
kout->trunc();
kprintf("kernel start: 0x%x\n", &__kernel_start);
kprintf("kernel end: 0x%x\n", &__kernel_end);
uint32_t size = (&__kernel_end - &__kernel_start) / 1024;
kprintf("kernel size: %dKB\n", size);
if (!(mbi->flags & (1 << 6))) { if (!(mbi->flags & (1 << 6))) {
return; return;
} }
kprintf("multiboot virtual address: 0x%x\n", mbi); vga_init();
kprintf("parsing multiboot memory map\n");
uint32_t mmap_virtual_addr = mbi->mmap_addr + 0xC0000000; uint32_t mmap_virtual_addr = mbi->mmap_addr + 0xC0000000;
kprintf("mmap virtual address: 0x%x\n", mmap_virtual_addr);
init_pmm((void*)mmap_virtual_addr, mbi->mmap_length); init_pmm((void*)mmap_virtual_addr, mbi->mmap_length);
kprintf("memory detection complete. total free memory: %dMB\n", total_free_memory() / 1024 / 1024);
kprintf("RockOS booting...\n");
init_gdt(); init_gdt();
extern uint64_t gdt[5];
kprintf("GDT set @ 0x%x\n", &gdt);
init_idt(); init_idt();
extern idt_entry idt[256];
kprintf("IDT set @ 0x%x\n", &idt);
init_pic(); init_pic();
kprintf("PIC initialized\n");
init_pit(); init_pit();
kprintf("PIT initialized\n");
init_page_tables(); init_page_tables();
kprintf("Page tables initialized\n");
kgrow(1); kprintf("basic initializations complete\n");
kprintf("Allocated 4kb for kernel heap\n");
kprintf("scanning for drives\n"); disable_interrupts();
extern void scan_drives(); init_scheduler();
scan_drives(); enable_interrupts();
ide_device_t* boot_cd_rom = get_ide_device(0); while(1) yield();
read_iso(boot_cd_rom);
while(1);
} }

View File

@@ -4,8 +4,9 @@
#define KHEAP_START 0xE0000000 #define KHEAP_START 0xE0000000
typedef struct __attribute__((packed)) { typedef struct __attribute__((packed)) {
size_t size;
uint8_t free; uint8_t free;
uint32_t next_blk; void* next_blk;
} alloc_header_t; } alloc_header_t;
void memcpy(const void* src, void* dst, size_t sz) { void memcpy(const void* src, void* dst, size_t sz) {
@@ -42,18 +43,6 @@ static void* kernel_heap_end = (void*)KHEAP_START;
alloc_header_t* blk_list = NULL; alloc_header_t* blk_list = NULL;
void kgrow(size_t pages) { void kgrow(size_t pages) {
if (kernel_heap_end == kernel_heap_start) {
// probaably not great, but if we don't have a heap yet, allocate the first (or only) frame requested.
// Then initialize the first block header for the allocator
void* frame = p_alloc_frame();
map_page((uint32_t)kernel_heap_end, (uint32_t)frame, PAGE_PRESENT | PAGE_WRITABLE);
kernel_heap_end = (void*)((uint32_t)kernel_heap_end + PAGE_SIZE);
pages--;
blk_list = kernel_heap_start;
blk_list->free = 1;
blk_list->next_blk = 0;
}
for (size_t p = 0; p < pages; p++) { for (size_t p = 0; p < pages; p++) {
void* frame = p_alloc_frame(); void* frame = p_alloc_frame();
map_page((uint32_t)kernel_heap_end, (uint32_t)frame, PAGE_PRESENT | PAGE_WRITABLE); map_page((uint32_t)kernel_heap_end, (uint32_t)frame, PAGE_PRESENT | PAGE_WRITABLE);
@@ -61,34 +50,60 @@ void kgrow(size_t pages) {
} }
} }
#define ALIGNMENT 4
#define ALIGN(size) (((size) + (ALIGNMENT - 1)) & ~(ALIGNMENT - 1))
void* kalloc(size_t sz) { void* kalloc(size_t sz) {
if (sz == 0) { sz = ALIGN(sz);
return NULL;
if (kernel_heap_end == kernel_heap_start) {
// probaably not great, but if we don't have a heap yet, allocate the first (or only) frame requested.
// Then initialize the first block header for the allocator
kgrow(4);
blk_list = (alloc_header_t*)kernel_heap_start;
blk_list->size = ((uint32_t)kernel_heap_end - (uint32_t)kernel_heap_start) - sizeof(alloc_header_t);
blk_list->free = 1;
blk_list->next_blk = NULL;
} }
alloc_header_t* header = blk_list; alloc_header_t* curr = blk_list;
while (!header->free) { alloc_header_t* prev = NULL;
if (header->next_blk == 0) {
return NULL; while (curr != NULL) {
if (curr->free && curr->size >= sz) {
if (curr->size >= sz + sizeof(alloc_header_t) + ALIGNMENT) {
alloc_header_t* new_blk = (alloc_header_t*)((uint32_t)curr + sizeof(alloc_header_t) + sz);
new_blk->size = curr->size - sz - sizeof(alloc_header_t);
new_blk->free = 1;
new_blk->next_blk = curr->next_blk;
curr->size = sz;
curr->next_blk = new_blk;
}
curr->free = 0;
return (void*)((uint32_t)curr + sizeof(alloc_header_t));
} }
header = (alloc_header_t*)header->next_blk; prev = curr;
curr = curr->next_blk;
} }
uint32_t data_ptr = (uint32_t)header + sizeof(alloc_header_t); // no more space, grow!!
if (data_ptr >= (uint32_t)kernel_heap_end) { size_t required_space = sz + sizeof(alloc_header_t);
return NULL; size_t pages_to_grow = (required_space + PAGE_SIZE - 1) / PAGE_SIZE;
} // if the start of the data is already at the end, we don't have room
uint32_t end_of_blk = data_ptr + sz; alloc_header_t* new_heap_blk = (alloc_header_t*)kernel_heap_end;
if (end_of_blk > (uint32_t)kernel_heap_end) {
return NULL;
} // if the end of the data is past the end, we don't have room
if (end_of_blk != header->next_blk && end_of_blk < ((uint32_t)kernel_heap_end - sizeof(alloc_header_t))) { kgrow(pages_to_grow);
header->next_blk = end_of_blk;
alloc_header_t* next_header = (alloc_header_t*)header->next_blk;
next_header->f
} // see if we have room to place the next header and at least 1 byte of data
return (void*)data_ptr; new_heap_blk->size = (pages_to_grow * PAGE_SIZE) - sizeof(alloc_header_t);
new_heap_blk->free = 1;
new_heap_blk->next_blk = NULL;
if (prev != NULL) {
prev->next_blk = new_heap_blk;
}
return kalloc(sz);
} }

View File

@@ -11,7 +11,7 @@ int strcmp(const char *s1, const char *s2);
int strlen(const char* str); int strlen(const char* str);
void kgrow(size_t pages); void kgrow(size_t pages);
void* alloc(size_t sz); void* kalloc(size_t sz);
#endif #endif

View File

@@ -1,20 +1,25 @@
#include "print.h" #include "print.h"
#include "stream.h" #include "stream.h"
#include "tasks.h"
#include <stdarg.h> #include <stdarg.h>
extern print_stream_t* kout; #include <drivers/vga/vga.h>
spinlock_t kwrite_lock = {0};
static char* hex_chars = "0123456789abcdef"; static char* hex_chars = "0123456789abcdef";
static void kprint(const char *str) { static void kprint(const char *str) {
while (*str) { while (*str) {
kout->putchar(*str); vga_putchar(*str);
str++; str++;
} }
} }
static void kputd(int d) { static void kputd(int d) {
if (d == 0) { if (d == 0) {
kout->putchar('0'); vga_putchar('0');
return; return;
} }
char buffer[12]; char buffer[12];
@@ -24,13 +29,13 @@ static void kputd(int d) {
d /= 10; d /= 10;
} }
for (int j = i - 1; j >= 0; j--) { for (int j = i - 1; j >= 0; j--) {
kout->putchar(buffer[j]); vga_putchar(buffer[j]);
} }
} }
static void kputx(unsigned int x) { static void kputx(unsigned int x) {
if (x == 0) { if (x == 0) {
kout->putchar('0'); vga_putchar('0');
return; return;
} }
char buffer[8]; char buffer[8];
@@ -41,15 +46,18 @@ static void kputx(unsigned int x) {
x >>= 4; x >>= 4;
} }
for (int j = i - 1; j >= 0; j--) { for (int j = i - 1; j >= 0; j--) {
kout->putchar(buffer[j]); vga_putchar(buffer[j]);
} }
} }
void kputc(const char c) { void kputc(const char c) {
kout->putchar(c); spin_lock(&kwrite_lock);
vga_putchar(c);
spin_unlock(&kwrite_lock);
} }
void kprintf(const char* fmt, ...) { void kprintf(const char* fmt, ...) {
spin_lock(&kwrite_lock);
va_list args; va_list args;
va_start(args, fmt); va_start(args, fmt);
@@ -73,19 +81,20 @@ void kprintf(const char* fmt, ...) {
break; break;
} }
case '%': case '%':
kout->putchar('%'); vga_putchar('%');
break; break;
default: default:
kout->putchar('%'); vga_putchar('%');
kout->putchar(*fmt); vga_putchar(*fmt);
break; break;
} }
fmt++; fmt++;
} else { } else {
kout->putchar(*fmt); vga_putchar(*fmt);
fmt++; fmt++;
} }
} }
va_end(args); va_end(args);
spin_unlock(&kwrite_lock);
} }

11
kernel/lib/tasks.c Normal file
View File

@@ -0,0 +1,11 @@
#include <lib/tasks.h>
void spin_lock(spinlock_t *lock) {
while (__sync_lock_test_and_set(&lock->locked, 1)) {
asm volatile("pause");
}
}
void spin_unlock(spinlock_t *lock) {
__sync_lock_release(&lock->locked);
}

13
kernel/lib/tasks.h Normal file
View File

@@ -0,0 +1,13 @@
#ifndef KTASKS_H
#define KTASKS_H
#include <stdint.h>
typedef struct {
volatile uint32_t locked;
} spinlock_t;
void spin_lock(spinlock_t *lock);
void spin_unlock(spinlock_t *lock);
#endif

View File

@@ -18,7 +18,7 @@ extern void disable_pae();
#define PAGE_TABLES 0xFFC00000 #define PAGE_TABLES 0xFFC00000
#define PAGE_DIRECTORY 0xFFFFF000 #define PAGE_DIRECTORY 0xFFFFF000
#define TEMP_MAPPING_VADDR 0xE0000000 #define TEMP_MAPPING_VADDR 0xDFFF0000
static uint32_t max_address = 0; static uint32_t max_address = 0;
static uint32_t total_available_memory = 0; static uint32_t total_available_memory = 0;
@@ -141,8 +141,6 @@ void init_pmm(void* mmap_base, uint32_t mmap_limit) {
if (mmap_base != NULL && mmap_limit > 0) { if (mmap_base != NULL && mmap_limit > 0) {
parse_multiboot_mmap(mmap_base, mmap_limit); parse_multiboot_mmap(mmap_base, mmap_limit);
} }
kprintf("total free memory: %dMB\n", total_available_memory / 1024 / 1024);
} }
void init_page_tables() { void init_page_tables() {
@@ -165,7 +163,7 @@ uint32_t total_free_memory() {
return total_available_memory; return total_available_memory;
} }
void* create_user_pd() { void* create_task_pd() {
uint32_t pd_address = (uint32_t)p_alloc_frame(); uint32_t pd_address = (uint32_t)p_alloc_frame();
if (pd_address == 0) { if (pd_address == 0) {
return 0; return 0;
@@ -173,18 +171,18 @@ void* create_user_pd() {
map_page(TEMP_MAPPING_VADDR, pd_address, PAGE_PRESENT | PAGE_WRITABLE); map_page(TEMP_MAPPING_VADDR, pd_address, PAGE_PRESENT | PAGE_WRITABLE);
uint32_t* user_pd = (uint32_t*)TEMP_MAPPING_VADDR; uint32_t* task_pd = (uint32_t*)TEMP_MAPPING_VADDR;
uint32_t* kernel_pd = (uint32_t*)PAGE_DIRECTORY; uint32_t* kernel_pd = (uint32_t*)PAGE_DIRECTORY;
for(int i = 0; i < 768; i++) { for(int i = 0; i < 768; i++) {
user_pd[i] = 0; task_pd[i] = 0;
} }
for(int i = 768; i < 1023; i++) { for(int i = 768; i < 1023; i++) {
user_pd[i] = kernel_pd[i]; task_pd[i] = kernel_pd[i];
} }
user_pd[1023] = (uint32_t)pd_address | PAGE_PRESENT | PAGE_WRITABLE; task_pd[1023] = (uint32_t)pd_address | PAGE_PRESENT | PAGE_WRITABLE;
uint32_t pde = TEMP_MAPPING_VADDR >> 22; uint32_t pde = TEMP_MAPPING_VADDR >> 22;
uint32_t pte = (TEMP_MAPPING_VADDR >> 12) & 0x3FF; uint32_t pte = (TEMP_MAPPING_VADDR >> 12) & 0x3FF;

View File

@@ -20,7 +20,7 @@ void* p_alloc_frame();
uint32_t total_free_memory(); uint32_t total_free_memory();
void* create_user_pd(); void* create_task_pd();
void map_page(uint32_t vaddr, uint32_t paddr, uint32_t flags); void map_page(uint32_t vaddr, uint32_t paddr, uint32_t flags);

20
kernel/process.h Normal file
View File

@@ -0,0 +1,20 @@
#ifndef KPROCESS_H
#define KPROCESS_H
#include <stdint.h>
typedef enum {
STATE_READY,
STATE_SLEEPING,
STATE_DEAD
} process_state_t;
typedef struct {
uint32_t pid;
uint32_t esp;
uint32_t cr3;
process_state_t state;
uint32_t sleep;
} __attribute__((packed)) process_t;
#endif

12
kernel/scheduler.S Normal file
View File

@@ -0,0 +1,12 @@
.code32
.extern schedule_next_task
.global yield
yield:
cli
pushal
push %esp
call schedule_next_task
movl %eax, %esp
popal
sti
ret

136
kernel/scheduler.c Normal file
View File

@@ -0,0 +1,136 @@
#include <lib/tasks.h>
#include <lib/memory.h>
#include <memory/mm.h>
#include <stddef.h>
#include "process.h"
#include "scheduler.h"
static process_t* process_table;
static spinlock_t process_table_lock = {0};
static int current_process = 0;
static int total_processes = 0;
extern uint32_t fetch_cr3();
#define IDLE_TASK_PID 1
static void idle_task() {
while (1) asm volatile("hlt");
}
uint32_t schedule_next_task(uint32_t current_esp) {
spin_lock(&process_table_lock);
process_table[current_process].esp = current_esp;
for (int i = 0; i < total_processes; i++) {
if (process_table[i].state == STATE_SLEEPING) {
if (process_table[i].sleep > 0) {
process_table[i].sleep--;
}
if (process_table[i].sleep == 0) {
process_table[i].state = STATE_READY;
}
}
}
int next_process = current_process;
int found_ready = 0;
while (1) {
next_process = (next_process + 1) % total_processes;
if (next_process != IDLE_TASK_PID && process_table[next_process].state == STATE_READY) {
found_ready = 1;
break;
}
if (next_process == current_process) {
break;
}
}
if (!found_ready) {
if (process_table[current_process].state == STATE_READY) {
next_process = current_process;
} else {
next_process = IDLE_TASK_PID;
}
}
current_process = next_process;
if (fetch_cr3() != process_table[current_process].cr3) {
extern void load_pd(uint32_t table);
load_pd(process_table[current_process].cr3);
}
uint32_t rtn = process_table[current_process].esp;
spin_unlock(&process_table_lock);
return rtn;
}
void init_scheduler() {
process_table = kalloc(16 * sizeof(process_t));
total_processes = 0;
process_t* process = &process_table[total_processes];
process->pid = total_processes;
process->esp = 0;
process->cr3 = fetch_cr3();
process->state = STATE_READY;
process->sleep = 0;
total_processes++;
create_task((uint32_t)idle_task, fetch_cr3());
current_process = 0;
}
int create_task(uint32_t entry_point, uint32_t cr3) {
if (total_processes >= 16) {
return 0;
}
spin_lock(&process_table_lock);
process_t* process = &process_table[total_processes];
process->pid = total_processes;
process->cr3 = cr3;
process->state = STATE_READY;
process->sleep = 0;
void* stack_bottom = kalloc(4096);
uint32_t* esp = (uint32_t*)((uint32_t)stack_bottom + 4096);
*(--esp) = 0x0202; // EFLAGS
*(--esp) = 0x08; // CS
*(--esp) = entry_point; // EIP
*(--esp) = 0; // EAX
*(--esp) = 0; // ECX
*(--esp) = 0; // EDX
*(--esp) = 0; // EBX
*(--esp) = 0; // ESP
*(--esp) = 0; // EBP
*(--esp) = 0; // ESI
*(--esp) = 0; // EDI
process->esp = (uint32_t)esp;
spin_unlock(&process_table_lock);
total_processes++;
return 1;
}
void sleep(uint32_t ticks) {
if (ticks == 0) return;
spin_lock(&process_table_lock);
process_table[current_process].sleep = ticks;
process_table[current_process].state = STATE_SLEEPING;
spin_unlock(&process_table_lock);
yield();
}

13
kernel/scheduler.h Normal file
View File

@@ -0,0 +1,13 @@
#ifndef KSCHEDULER_H
#define KSCHEDULER_H
#include <stdint.h>
void init_scheduler();
int create_task(uint32_t entry_point, uint32_t cr3);
void sleep(uint32_t ticks);
void yield();
#endif

6
kernel/syscall.h Normal file
View File

@@ -0,0 +1,6 @@
#ifndef KSYSCALL_H
#define KSYSCALL_H
void syscall_handler();
#endif

View File

@@ -6,8 +6,7 @@ OSNAME := rockos
C_SOURCES := $(shell find kernel -type f -name '*.c') C_SOURCES := $(shell find kernel -type f -name '*.c')
S_SOURCES := $(shell find kernel -type f -name '*.S') S_SOURCES := $(shell find kernel -type f -name '*.S')
# This correctly generates paths like obj/kernel/main.o OBJECTS := $(patsubst %, obj/%.o, $(C_SOURCES) $(S_SOURCES))
OBJECTS := $(patsubst %.c, obj/%.o, $(C_SOURCES)) $(patsubst %.S, obj/%.o, $(S_SOURCES))
CFLAGS := -ffreestanding -O2 -Wall -Wextra -Ikernel CFLAGS := -ffreestanding -O2 -Wall -Wextra -Ikernel
LDFLAGS := -T kernel/linker.ld LDFLAGS := -T kernel/linker.ld
@@ -25,11 +24,11 @@ $(OSNAME).iso: $(OSNAME).bin grub.cfg
cp grub.cfg isodir/boot/grub/grub.cfg cp grub.cfg isodir/boot/grub/grub.cfg
grub-mkrescue -o $(OSNAME).iso isodir grub-mkrescue -o $(OSNAME).iso isodir
obj/kernel/%.o: kernel/%.c obj/%.c.o: %.c
@mkdir -p $(dir $@) @mkdir -p $(dir $@)
$(CC) -c $< -o $@ $(CFLAGS) $(CC) -c $< -o $@ $(CFLAGS)
obj/kernel/%.o: kernel/%.S obj/%.S.o: %.S
@mkdir -p $(dir $@) @mkdir -p $(dir $@)
$(CC) -c $< -o $@ $(CFLAGS) $(CC) -c $< -o $@ $(CFLAGS)