diff --git a/initrd/make_img.sh b/initrd/make_img.sh index 444456d..dd5dd03 100755 --- a/initrd/make_img.sh +++ b/initrd/make_img.sh @@ -2,4 +2,5 @@ mkdir -p output rm -rf output/* -find . -depth -print | cpio -o -H newc > output/initrd.img \ No newline at end of file +find . -depth -print | cpio -o -H newc > output/initrd.img +cp output/initrd.img ../isodir/boot \ No newline at end of file diff --git a/kernel/common.S b/kernel/common.S index 5a8dc6c..2b1b563 100644 --- a/kernel/common.S +++ b/kernel/common.S @@ -120,4 +120,6 @@ outsw: .global fetch_cr3 fetch_cr3: mov %cr3, %eax - ret \ No newline at end of file + ret + +.global set_cr3 diff --git a/kernel/drivers/cpio/cpio.c b/kernel/drivers/cpio/cpio.c index da39cd9..f5a15ba 100644 --- a/kernel/drivers/cpio/cpio.c +++ b/kernel/drivers/cpio/cpio.c @@ -34,7 +34,7 @@ static uint32_t cpio_read(struct vfs_node* node, uint32_t offset, uint32_t size, if (offset + size > node->size) { size = node->size - offset; } - memcpy(buffer, (uint8_t*)(node->ptr) + offset, size); + memcpy((uint8_t*)(node->data) + offset, buffer, size); return size; } @@ -80,7 +80,7 @@ vfs_node_t* cpio_read_fs(uint32_t _vaddr) { current->flags = VFS_FILE; current->read = cpio_read; - current->ptr = (vfs_node_t*)file_data; + current->data = file_data; } uint32_t next_header_offset = file_data_offset + filesize; diff --git a/kernel/gdt.c b/kernel/gdt.c index c6bff54..1b18673 100644 --- a/kernel/gdt.c +++ b/kernel/gdt.c @@ -1,4 +1,4 @@ -#include +#include #define SEG_DESCTYPE(x) ((x) << 0x04) // Descriptor type (0 for system, 1 for code/data) #define SEG_PRES(x) ((x) << 0x07) // Present @@ -45,41 +45,11 @@ typedef struct __attribute__((packed)) { uint16_t limit; uint32_t base; } gdt_ptr_t; - -typedef struct __attribute__((packed)) { - uint32_t prev_tss; - uint32_t esp0; - uint32_t ss0; - uint32_t esp1; - uint32_t ss1; - uint32_t esp2; - uint32_t ss2; - uint32_t cr3; - uint32_t eip; - uint32_t eflags; - uint32_t eax; - uint32_t ecx; - uint32_t edx; - uint32_t ebx; - uint32_t esp; - uint32_t ebp; - uint32_t esi; - uint32_t edi; - uint32_t es; - uint32_t cs; - uint32_t ss; - uint32_t ds; - uint32_t fs; - uint32_t gs; - uint32_t ldt; - uint16_t trap; - uint16_t iomap_base; -} tss_entry; uint64_t gdt[6]; gdt_ptr_t gdtr; -tss_entry tss; +tss_entry_t tss; extern void load_gdt(); extern void tss_flush(); @@ -126,14 +96,14 @@ void init_gdt() { gdt[3] = create_descriptor(0, 0x000FFFFF, (GDT_CODE_PL3)); gdt[4] = create_descriptor(0, 0x000FFFFF, (GDT_DATA_PL3)); - for (uint32_t i = 0; i < sizeof(tss_entry); i++) { + for (uint32_t i = 0; i < sizeof(tss_entry_t); i++) { ((char*)&tss)[i] = 0; } tss.ss0 = 0x10; - tss.iomap_base = sizeof(tss_entry); + tss.iomap_base = sizeof(tss_entry_t); - gdt[5] = create_tss_descriptor((uint32_t)&tss, sizeof(tss_entry) - 1); + gdt[5] = create_tss_descriptor((uint32_t)&tss, sizeof(tss_entry_t) - 1); gdtr.limit = 6 * sizeof(uint64_t) - 1; gdtr.base = (uint32_t)&gdt; diff --git a/kernel/gdt.h b/kernel/gdt.h index f90e54d..43104cf 100644 --- a/kernel/gdt.h +++ b/kernel/gdt.h @@ -1,6 +1,40 @@ #ifndef KGDT_H #define KGDT_H +#include + +typedef struct __attribute__((packed)) { + uint32_t prev_tss; + uint32_t esp0; + uint32_t ss0; + uint32_t esp1; + uint32_t ss1; + uint32_t esp2; + uint32_t ss2; + uint32_t cr3; + uint32_t eip; + uint32_t eflags; + uint32_t eax; + uint32_t ecx; + uint32_t edx; + uint32_t ebx; + uint32_t esp; + uint32_t ebp; + uint32_t esi; + uint32_t edi; + uint32_t es; + uint32_t cs; + uint32_t ss; + uint32_t ds; + uint32_t fs; + uint32_t gs; + uint32_t ldt; + uint16_t trap; + uint16_t iomap_base; +} tss_entry_t; + void init_gdt(); +extern tss_entry_t tss; + #endif \ No newline at end of file diff --git a/kernel/initrd.c b/kernel/initrd.c deleted file mode 100644 index 501723d..0000000 --- a/kernel/initrd.c +++ /dev/null @@ -1,34 +0,0 @@ -#include "initrd.h" - -#include - -#include -#include - -void parse_cpio(void *initrd_start) { - cpio_header_t *head = (cpio_header_t *)initrd_start; - - while (strncmp(head->c_magic, "070701", 6) == 0) { - // If we hit the trailer, we are done - char *filename = (char *)(head + 1); - if (strncmp(filename, "TRAILER!!!", 10) == 0) { - break; - } - - uint32_t filesize = parse_hex(head->c_filesize); - uint32_t namesize = parse_hex(head->c_namesize); - - kprintf("found file of size %d\n", filesize); - - // Calculate where the data begins (accounting for 4-byte padding) - uint32_t header_plus_name = 110 + namesize; - header_plus_name = (header_plus_name + 3) & ~3; // Align to 4 bytes - - char *file_data = (char *)head + header_plus_name; - - uint32_t total_record_size = header_plus_name + filesize; - total_record_size = (total_record_size + 3) & ~3; // Align to 4 bytes - - head = (cpio_header_t *)((char *)head + total_record_size); - } -} \ No newline at end of file diff --git a/kernel/initrd.h b/kernel/initrd.h deleted file mode 100644 index 58981f9..0000000 --- a/kernel/initrd.h +++ /dev/null @@ -1,36 +0,0 @@ -#ifndef KINITRD_H -#define KINITRD_H - -#include - -typedef struct { - char c_magic[6]; - char c_ino[8]; - char c_mode[8]; - char c_uid[8]; - char c_gid[8]; - char c_nlink[8]; - char c_mtime[8]; - char c_filesize[8]; - char c_devmajor[8]; - char c_devminor[8]; - char c_rdevmajor[8]; - char c_rdevminor[8]; - char c_namesize[8]; - char c_check[8]; -} cpio_header_t; - -static inline uint32_t parse_hex(const char *s) { - uint32_t val = 0; - for (int i = 0; i < 8; i++) { - val <<= 4; - if (s[i] >= '0' && s[i] <= '9') val += (s[i] - '0'); - else if (s[i] >= 'A' && s[i] <= 'F') val += (s[i] - 'A' + 10); - else if (s[i] >= 'a' && s[i] <= 'f') val += (s[i] - 'a' + 10); - } - return val; -} - -void parse_cpio(void *initrd_start); - -#endif \ No newline at end of file diff --git a/kernel/interrupts.S b/kernel/interrupts.S index 00e6d47..a73bcdd 100644 --- a/kernel/interrupts.S +++ b/kernel/interrupts.S @@ -44,8 +44,16 @@ ISR_ERRCODE 14 # Page Fault (Has Error Code!) .extern send_eoi_master # drivers/pic/pic.c isr32: cli - pushal + + movw %ds, %ax + pushl %eax + + movw $0x10, %ax # Load Kernel Data Segment descriptor + movw %ax, %ds + movw %ax, %es + movw %ax, %fs + movw %ax, %gs pushl %esp call switch_context @@ -53,6 +61,12 @@ isr32: call send_eoi_master + popl %eax + movw %ax, %ds + movw %ax, %es + movw %ax, %fs + movw %ax, %gs + popal sti iret diff --git a/kernel/kmain.c b/kernel/kmain.c index f0c43b4..1b714f7 100644 --- a/kernel/kmain.c +++ b/kernel/kmain.c @@ -4,6 +4,7 @@ #include "scheduler.h" #include "common.h" #include "vfs.h" +#include "elf.h" #include #include @@ -51,26 +52,73 @@ vfs_node_t* load_initrd() { return cpio_read_fs(initrd_module->mod_start); } -void load_origin_program() { - vfs_node_t* vfs_root = vfs_create_root(); - vfs_node_t* initrd_root = load_initrd(); - - if (initrd_root) { - mount(vfs_root, initrd_root); - kprintf("initrd read, mounted @ /\n"); +void load_program(const char* path) { + void* cr3 = create_task_pd(); + load_pd(cr3); + flush_tlb(); - int fd = open("/origin.elf", 0); - if (fd == -1) { - kprintf("failed to read origin program\n"); - } - - void* buf = kalloc(512); - int rd = read(fd, buf, 512); - if (rd > 0) { - kprintf("read %d bytes from origin.elf\n", rd); - } + int fd = open(path, 0); + if (fd == -1) { + kprintf("failed to open program: %s\n", path); + return;; } - exit(); + elf_header_t* e_hdr = kalloc(sizeof(elf_header_t)); + memset((void*)e_hdr, 0, sizeof(elf_header_t)); + + uint32_t bytes_rd = read(fd, e_hdr, sizeof(elf_header_t)); + if (bytes_rd <= 0) { + kprintf("failed to read program data for %s\n", path); + return; + } + + uint32_t ph_table_ptr = e_hdr->e_phoff; + elf_program_header_t* ph = kalloc(sizeof(elf_program_header_t)); + uint32_t heap_start = 0; + + for (uint32_t i = 0; i < e_hdr->e_phnum; i++) { + fseek(fd, ph_table_ptr); + memset((void*)ph, 0, sizeof(elf_program_header_t)); + read(fd, ph, sizeof(elf_program_header_t)); + + if (ph->p_type == PT_LOAD) { + uint32_t vstart = ph->p_vaddr; + uint32_t vend = vstart + ph->p_memsz; + + if (vend > heap_start) { + heap_start = vend; + } + + uint32_t page_start = vstart & ~(PAGE_SIZE - 1); + uint32_t page_end = (vend + PAGE_SIZE - 1) & ~(PAGE_SIZE - 1); + + for (uint32_t v = page_start; v < page_end; v += PAGE_SIZE) { + void* phys_frame = p_alloc_frame(); + map_page(v, (uint32_t)phys_frame, 0x07); + } + + uint32_t data_ptr = ph->p_offset; + fseek(fd, data_ptr); + read(fd, (void*)vstart, ph->p_memsz); + + // 0 out bss + if (ph->p_memsz > ph->p_filesz) { + size_t bss_size = ph->p_memsz - ph->p_filesz; + memset((void*)(vstart + ph->p_filesz), 0, bss_size); + } + } + + ph_table_ptr += sizeof(elf_program_header_t); + } + + uint32_t esp = 0xBFFF0000; + void* pesp = p_alloc_frame(); + map_page(esp - PAGE_SIZE, (uint32_t)pesp, 0x07); + + create_task(e_hdr->e_entry, fetch_cr3(), 1); +} + +void start_origin() { + load_program("/origin.elf"); } void kmain(uint32_t magic, multiboot_info* mbi) { @@ -96,9 +144,19 @@ void kmain(uint32_t magic, multiboot_info* mbi) { kprintf("basic initializations complete\n"); + vfs_node_t* vfs_root = vfs_create_root(); + + vfs_node_t* initrd_root = load_initrd(); + if (!initrd_root) { + kprintf("failed to load initrd\n"); + } + mount(vfs_root, initrd_root); + kprintf("initrd read, mounted @ /\n"); + disable_interrupts(); init_scheduler(); enable_interrupts(); - create_task((uint32_t)load_origin_program, fetch_cr3()); + kprintf("loading user program\n"); + start_origin(); } diff --git a/kernel/lib/string.h b/kernel/lib/string.h new file mode 100644 index 0000000..70dcf7d --- /dev/null +++ b/kernel/lib/string.h @@ -0,0 +1,6 @@ +#ifndef KSTRING_H +#define KSTRING_H + +char* strtok_r(char* str, const char* delim, char** saveptr); + +#endif \ No newline at end of file diff --git a/kernel/lib/strtok.c b/kernel/lib/strtok.c new file mode 100644 index 0000000..31aa210 --- /dev/null +++ b/kernel/lib/strtok.c @@ -0,0 +1,49 @@ +#include + +#include + +static int is_delim(char c, const char* delim) { + while (*delim) { + if (c == *delim) { + return 1; + } + delim++; + } + return 0; +} + +char* strtok_r(char* str, const char* delim, char** saveptr) { + if (saveptr == NULL) { + return NULL; + } + + char* next_token = (str != NULL) ? str : *saveptr; + + if (next_token == NULL || *next_token == '\0') { + *saveptr = NULL; + return NULL; + } + + while (*next_token && is_delim(*next_token, delim)) { + next_token++; + } + + if (*next_token == '\0') { + *saveptr = next_token; + return NULL; + } + + char* token_start = next_token; + + while (*next_token) { + if (is_delim(*next_token, delim)) { + *next_token = '\0'; // Destructively null-terminate the token + *saveptr = next_token + 1; // Save the position right after the null-terminator + return token_start; + } + next_token++; + } + + *saveptr = next_token; + return token_start; +} \ No newline at end of file diff --git a/kernel/memory/mm_stubs.S b/kernel/memory/mm.S similarity index 100% rename from kernel/memory/mm_stubs.S rename to kernel/memory/mm.S diff --git a/kernel/memory/mm.c b/kernel/memory/mm.c index 85118d9..2d3c175 100644 --- a/kernel/memory/mm.c +++ b/kernel/memory/mm.c @@ -8,8 +8,6 @@ extern uint8_t __kernel_start; extern uint8_t __kernel_end; extern uint32_t page_directory[1024]; -extern void flush_tlb(); -extern void disable_pae(); #define PAGE_SIZE 4096 #define MAX_RAM 0xFFFFFFFF // 4GB diff --git a/kernel/memory/mm.h b/kernel/memory/mm.h index 456d8c2..7d73dfc 100644 --- a/kernel/memory/mm.h +++ b/kernel/memory/mm.h @@ -24,4 +24,9 @@ void* create_task_pd(); void map_page(uint32_t vaddr, uint32_t paddr, uint32_t flags); +void load_pd(void* paddr); + +void flush_tlb(); +void disable_pae(); + #endif diff --git a/kernel/process.h b/kernel/process.h index 5962621..689f691 100644 --- a/kernel/process.h +++ b/kernel/process.h @@ -13,6 +13,7 @@ typedef enum { typedef struct { uint32_t pid; uint32_t esp; + uint32_t esp0; uint32_t cr3; process_state_t state; uint32_t sleep; diff --git a/kernel/scheduler.c b/kernel/scheduler.c index 0986a73..ef70e01 100644 --- a/kernel/scheduler.c +++ b/kernel/scheduler.c @@ -8,6 +8,7 @@ #include "common.h" #include "process.h" #include "scheduler.h" +#include "gdt.h" static process_t* process_table; @@ -68,9 +69,10 @@ uint32_t switch_context(uint32_t current_esp) { current_process = next_process; + tss.esp0 = process_table[current_process].esp0; + if (fetch_cr3() != process_table[current_process].cr3) { - extern void load_pd(uint32_t table); - load_pd(process_table[current_process].cr3); + load_pd((void*)process_table[current_process].cr3); } return process_table[current_process].esp; @@ -88,12 +90,12 @@ void init_scheduler() { process->sleep = 0; total_processes++; - create_task((uint32_t)idle_task, fetch_cr3()); + create_task((uint32_t)idle_task, fetch_cr3(), 0); current_process = 0; } -int create_task(uint32_t entry_point, uint32_t cr3) { +int create_task(uint32_t entry_point, uint32_t cr3, int user) { if (total_processes >= 16) { return 0; } @@ -117,10 +119,20 @@ int create_task(uint32_t entry_point, uint32_t cr3) { void* stack_bottom = kalloc(4096); uint32_t* esp = (uint32_t*)((uint32_t)stack_bottom + 4096); + process->esp0 = (uint32_t)esp; - *(--esp) = 0x0202; // EFLAGS - *(--esp) = 0x08; // CS - *(--esp) = entry_point; // EIP + if (user) { + *(--esp) = 0x23; // User Data Segment (SS) with RPL 3 (0x20 | 3) + *(--esp) = 0xBFFFF000; // User Stack Pointer (ESP) - location mapped in user space + *(--esp) = 0x0202; // EFLAGS (Interrupts enabled) + *(--esp) = 0x1B; // User Code Segment (CS) with RPL 3 (0x18 | 3) + *(--esp) = entry_point; // EIP + } else { + // IRET values for Ring 0 + *(--esp) = 0x0202; // EFLAGS + *(--esp) = 0x08; // Kernel Code Segment (CS) + *(--esp) = entry_point; // EIP + } *(--esp) = 0; // EAX *(--esp) = 0; // ECX diff --git a/kernel/scheduler.h b/kernel/scheduler.h index 437290b..20616d0 100644 --- a/kernel/scheduler.h +++ b/kernel/scheduler.h @@ -6,7 +6,7 @@ void init_scheduler(); -int create_task(uint32_t entry_point, uint32_t cr3); +int create_task(uint32_t entry_point, uint32_t cr3, int user); process_t* current_task(); void sleep(uint32_t ms); diff --git a/kernel/vfs.c b/kernel/vfs.c index 4fa7d37..704f1cd 100644 --- a/kernel/vfs.c +++ b/kernel/vfs.c @@ -22,22 +22,22 @@ vfs_node_t* vfs_create_root() { void mount(vfs_node_t* _mnt, vfs_node_t* _fs) { if (!_fs || !_mnt || !(_mnt->flags & VFS_DIRECTORY)) return; - _mnt->ptr = _fs; + _mnt->mnt = _fs; } static vfs_node_t* lookup(const char* path) { if (path[0] != '/') return NULL; vfs_node_t* current = root; - if (current->ptr) { - current = current->ptr; + if (current->mnt) { + current = current->mnt; } - const char* component = path + 1; - if (*component == '\0') return current; + const char* cmp = path + 1; + if (*cmp == '\0') return current; if (current->finddir) { - return current->finddir(current, component); + return current->finddir(current, cmp); } return NULL; @@ -72,6 +72,22 @@ int read(int fd, void* buf, size_t sz) { return bytes_read; } -int fseek(int fd) { - -} \ No newline at end of file +int fstat(int fd, file_t* dst) { + if (fd < 0 || fd >= MAX_PROCESS_FDS || !fd_table[fd].node) { + return 0; + } + + file_t* src = &fd_table[fd]; + memcpy(src, dst, sizeof(file_t)); + return 1; +} + +int fseek(int fd, size_t offset) { + if (fd < 0 || fd >= MAX_PROCESS_FDS || !fd_table[fd].node) { + return 0; + } + + file_t* file = &fd_table[fd]; + file->offset = offset; + return 1; +} \ No newline at end of file diff --git a/kernel/vfs.h b/kernel/vfs.h index d9059e1..4530658 100644 --- a/kernel/vfs.h +++ b/kernel/vfs.h @@ -25,7 +25,8 @@ typedef struct vfs_node { write_type_t write; finddir_type_t finddir; - struct vfs_node* ptr; + struct vfs_node* mnt; + void* data; } vfs_node_t; typedef struct { @@ -40,4 +41,7 @@ void mount(vfs_node_t* _mnt, vfs_node_t* _fs); int open(const char* path, int flags); int read(int fd, void* buf, size_t sz); +int fstat(int fd, file_t* _f); +int fseek(int fd, size_t offset); + #endif \ No newline at end of file diff --git a/programs/makefile b/programs/makefile index c88a74f..9d074de 100644 --- a/programs/makefile +++ b/programs/makefile @@ -1,8 +1,8 @@ CC = i686-elf-gcc LD = i686-elf-ld -CFLAGS = -ffreestanding -O2 -Wall -Wextra -I../rocklibc/include -LDFLAGS = -m elf_i386 -nostdlib +CFLAGS = -ffreestanding -O2 -Wall -Wextra -ffunction-sections -fdata-sections -I../rocklibc/include +LDFLAGS = -m elf_i386 -nostdlib --gc-sections TARGET = origin.elf @@ -16,6 +16,7 @@ main.o: main.c $(TARGET): crt0.o main.o ../rocklibc/rlibc.a $(LD) $(LDFLAGS) -T linker.ld crt0.o main.o ../rocklibc/rlibc.a $(shell $(CC) -print-libgcc-file-name) -o $(TARGET) + cp $(TARGET) ../initrd clean: rm -f *.o $(TARGET) diff --git a/rocklibc/makefile b/rocklibc/makefile index efc4608..f5a54fe 100644 --- a/rocklibc/makefile +++ b/rocklibc/makefile @@ -1,6 +1,7 @@ CC = i686-elf-gcc AR = i686-elf-ar CFLAGS = -ffreestanding -O2 -Wall -Wextra -Iinclude -DHAVE_MMAP=0 -DLACKS_SYS_MMAN_H=1 -DUSE_LOCKS=0 -DLACKS_SYS_PARAM_H=1 +CFLAGS += -ffunction-sections -fdata-sections TARGET = rlibc.a SRCS = $(shell find src -name "*.c")