CeDOS - Commit 38e3efda

Fixed sched_exec issue, and other things - Implemented stack integrity check - Implemented syscalls The paging subsystem could REALLY need some rework, it's getting REALLY messy
Celina Sophie Kalus
Wed, 17 Jan 2018 15:45:24 +0100
14 files changed, 182 insertions(+), 58 deletions(-)
M include/assembly.hinclude/assembly.h

@@ -114,6 +114,20 @@ __asm__ volatile ("hlt");

} /*! + * Performs a syscall. + */ +__attribute__((always_inline)) inline int syscall(int eax, int ebx, int ecx, int edx) { + int res; + __asm__ volatile ( "mov %1, %%eax;" + "mov %2, %%ebx;" + "mov %3, %%ecx;" + "mov %4, %%edx;" + "int $0x30;" + "mov %%eax, %0;" : "=m" (res) : "" (eax), "" (ebx), "" (ecx), "" (edx) : "eax", "ebx", "ecx", "edx"); + return res; +} + +/*! * Causes an interrupt */ #define INT(n) __asm__ volatile ("int $" #n)
M include/cedos/mm/paging.hinclude/cedos/mm/paging.h

@@ -6,6 +6,7 @@ #ifndef PAGING_H

#define PAGING_H #include <stdint.h> +#include "string.h" //! Number of entries within a page table/directory. #define PAGE_ENTRY_COUNT (uint32_t)(1 << 10)

@@ -43,6 +44,8 @@ __attribute__((always_inline)) inline void inv_all_pages(void) {

__asm__ volatile ( "mov %cr3, %eax\n" "mov %eax, %cr3"); } + +size_t copy_to_pdir(VIRT_ADDR src, size_t length, PHYS_ADDR pdir, VIRT_ADDR dest); /*! * Maps the specified range of physical addresses to the specified virtual address.
M include/cedos/pit.hinclude/cedos/pit.h

@@ -36,6 +36,6 @@ * \param freq_div Desired frequency divider.

*/ void pit_setup_channel(PIT_CHANNEL channel, PIT_MODE mode, uint16_t freq_div); -void pit_init(void); +int pit_init(void); #endif
M include/cedos/sched/process.hinclude/cedos/sched/process.h

@@ -5,6 +5,7 @@ #ifndef PROCESS_H

#define PROCESS_H #include "cedos/mm/paging.h" +#include "cedos/sched/stack_check.h" /*! * Defines all possible states for processes.

@@ -24,7 +25,7 @@

/*! * Defines the prototype for process entry functions. */ -typedef int PROCESS_MAIN(int argc, char** argv); +typedef int PROCESS_MAIN(void); /*! * Struct that saves context information for a process.

@@ -56,6 +57,9 @@ VIRT_ADDR esp;

//! Points to the base of the process stack. VIRT_ADDR ebp; + + //! Stack checksum + STACK_CHECKSUM checksum; //! Current value of the EFLAGS register. uint32_t eflags;
A include/cedos/sched/stack_check.h

@@ -0,0 +1,10 @@

+#ifndef STACK_CHECK_H +#define STACK_CHECK_H + +#include <stdint.h> + +typedef uint32_t STACK_CHECKSUM; + +STACK_CHECKSUM stack_check(const void *esp, const void *ebp); + +#endif
A include/cedos/syscall.h

@@ -0,0 +1,13 @@

+/*! \file + * Provides the syscall interface for user processes + */ +#ifndef SYSCALL_H +#define SYSCALL_H + +/*! + * Installs the syscall interrupt to INT 0x30 + * \return 1 on success, 0 on failure + */ +int syscall_init(void); + +#endif
M kernel/interrupts.ckernel/interrupts.c

@@ -62,8 +62,6 @@ sizeof(IDT),

IDT }; -extern void* sched_interrupt; - int interrupts_init(void) { for (uint32_t i = 0; i < INTERRUPT_COUNT; i++) { if (i == 0x03) {

@@ -72,8 +70,6 @@ } else if (i == 0x08) {

install_interrupt(i, double_fault_isr, 0x08, INT_GATE); } else if (i == 0x0d) { install_interrupt(i, gpf_isr, 0x08, INT_GATE); - } else if (i == 0x20) { - install_interrupt(i, &sched_interrupt, 0x08, INT_GATE); } else if (i >= 0x21 || i < 0x28) { install_interrupt(i, pic1_handler, 0x08, INT_GATE); } else if (i >= 0x28 || i < 0x30) {
M kernel/main.ckernel/main.c

@@ -1,10 +1,12 @@

#include "cedos/drivers/console.h" #include "cedos/sched/sched.h" +#include "cedos/sched/process.h" #include "cedos/mm/paging.h" #include "cedos/interrupts.h" +#include "cedos/syscall.h" #include "cedos/pic.h" #include "cedos/pit.h" #include "cedos/core.h"

@@ -35,6 +37,10 @@ printk("Activating interrupts...");

sti(); printk("done.\n"); + printk("Installing syscalls..."); + syscall_init(); + printk("done.\n"); + printk("Initializing scheduler..."); sched_init(); printk("done.\n");

@@ -53,21 +59,29 @@ }

extern uint8_t* IDT; -void task1(void); -void task2(void); -void task3(void); +int task1(void); +int task2(void); +int task3(void); -void task1(void) { +int task1(void) { //outb(0xFE, 0x64); - while (1) { printk("Somebody once told me\n"); hlt(); } + sched_exec(create_empty_page_dir(), task2); + printk(" Somebody once told me\n"); + while (1) { hlt(); } } -void task2(void) { - while (1) { printk("The world is gonna roll me\n"); hlt(); } +int task2(void) { + //sched_yield(); + syscall(0, 0, 0, 0); + sched_exec(create_empty_page_dir(), task3); + printk(" The world is gonna roll me\n"); + + while (1) { hlt(); } } -void task3(void) { - while (1) { printk("I ain't the sharpest tool in the shed.\n"); hlt(); } +int task3(void) { + printk(" I ain't the sharpest tool in the shed.\n"); + while (1) { hlt(); } } int os_main(void) {

@@ -77,8 +91,6 @@

// create test tasks printk("Creating tasks.\n"); sched_exec(create_empty_page_dir(), task1); - sched_exec(create_empty_page_dir(), task2); - sched_exec(create_empty_page_dir(), task3); printk("Starting scheduler.\n"); sched_start();
M kernel/mm/paging.ckernel/mm/paging.c

@@ -3,6 +3,7 @@ #include "cedos/mm/page_allocator.h"

#include "linker.h" #include "string.h" #include "cedos/interrupts.h" +#include "cedos/core.h" #define MAKE_PAGE_ENTRY(addr, flags) (uint32_t)(((uint32_t)(addr) & 0xFFFFF000) | (flags))

@@ -45,6 +46,11 @@ return 1;

} else { return 0; } +} + +void mount_page_dir(PHYS_ADDR page_dir) { + PAGE_DIR_ENTRY *cur_page_dir = PAGE_DIR_MAPPED_ADDR; + cur_page_dir[PAGE_ENTRY_COUNT - 2] = MAKE_PAGE_ENTRY(page_dir, PAGE_TABLE_FLAGS); } /*!

@@ -59,7 +65,7 @@ int tmp = 0;

if (!is_present(page_dir[dir_index])) { // acquire new page table - void *new_page_table = get_free_page(); + PHYS_ADDR new_page_table = get_free_page(); page_dir[dir_index] = MAKE_PAGE_ENTRY(new_page_table, PAGE_TABLE_FLAGS); }

@@ -76,8 +82,6 @@

int map_page_to_this(PHYS_ADDR page_addr, uint32_t dir_index, uint32_t table_index, uint32_t flags) { PAGE_DIR_ENTRY* page_dir = PAGE_DIR_MAPPED_ADDR; PAGE_TABLE_ENTRY* page_table = PAGE_TABLE_MAPPED_ADDR(dir_index); - - int tmp = 0; if (!is_present(page_dir[dir_index])) { // acquire new page table

@@ -95,9 +99,33 @@ return 0;

} } -void mount_page_dir(PHYS_ADDR page_dir) { - PAGE_DIR_ENTRY *cur_page_dir = PAGE_DIR_MAPPED_ADDR; - cur_page_dir[PAGE_ENTRY_COUNT - 2] = MAKE_PAGE_ENTRY(page_dir, PAGE_TABLE_FLAGS); +int force_map_page_to_this(PHYS_ADDR page_addr, uint32_t dir_index, uint32_t table_index, uint32_t flags) { + PAGE_DIR_ENTRY* page_dir = PAGE_DIR_MAPPED_ADDR; + PAGE_TABLE_ENTRY* page_table = PAGE_TABLE_MAPPED_ADDR(dir_index); + + if (!is_present(page_dir[dir_index])) { + // acquire new page table + void *new_page_table = get_free_page(); + page_dir[dir_index] = MAKE_PAGE_ENTRY(new_page_table, PAGE_TABLE_FLAGS); + } + + // map page + page_table[table_index] = MAKE_PAGE_ENTRY(page_addr, flags); + return 1; +} + +size_t copy_to_pdir(VIRT_ADDR src, size_t length, PHYS_ADDR pdir, VIRT_ADDR dest) { + PHYS_ADDR page = get_free_page(); + VIRT_ADDR mount_dest = 0xe0000000; + force_map_page_to_this(page, PAGE_DIR_INDEX(mount_dest), PAGE_TABLE_INDEX(mount_dest), PAGE_TABLE_FLAGS); + uint32_t offset = ((uint32_t)dest) & 0xFFF; + + for (uint32_t i = 0; i < length; i++) { + ((uint8_t*)mount_dest)[offset + i] = ((uint8_t*)src)[i]; + } + + mount_page_dir(pdir); + map_page_to(page, PAGE_DIR_INDEX(dest), PAGE_TABLE_INDEX(dest), PAGE_TABLE_FLAGS); } int map_range_to(PHYS_ADDR page_dir, VIRT_ADDR dest, PHYS_ADDR src, uint32_t page_count, uint32_t flags) {

@@ -170,5 +198,5 @@ // dump registers to stdout

} int paging_init(void) { - install_interrupt(0x0e, page_fault_isr, 0x08, INT_GATE); + install_interrupt(0x0e, page_fault_isr, 0x08, TRAP_GATE); }
M kernel/pit.ckernel/pit.c

@@ -18,6 +18,6 @@ outb((uint8_t)(freq_div >> 8), 0x40 + (uint16_t)channel);

popf(); } -void pit_init(void) { +int pit_init(void) { return 1; }
M kernel/sched/sched.ckernel/sched/sched.c

@@ -30,65 +30,80 @@ /*!

* Executes a task. */ PROCESS_ID sched_exec(PHYS_ADDR page_dir, PROCESS_MAIN *entry) { - crit_enter(); - PHYS_ADDR tmp_page_dir = switch_page_dir(page_dir); - PROCESS* p = get_slot(); - // set process context + PROCESS *p = get_slot(); p->page_dir = page_dir; p->eip = sched_dispatcher; p->ebp = KERNEL_PRIVATE_STACK; p->esp = KERNEL_PRIVATE_STACK - sizeof(SCHED_FRAME); p->eflags = PROCESS_STD_EFLAGS; p->entry = entry; + p->state = PSTATE_READY; // setup stack - SCHED_FRAME* frame = (SCHED_FRAME*)(p->esp); - frame->eax = frame->ebx = frame->ecx = frame->edx = 0; - frame->esi = frame->edi = 0; - frame->ebp = p->ebp; - frame->esp = p->esp; - frame->eflags = p->eflags; - frame->eip = sched_dispatcher; - frame->cs = 0x8; - - // TODO: add file descriptors for stdin, stdout and stderr + static SCHED_FRAME frame; + frame.eax = frame.ebx = frame.ecx = frame.edx = 0; + frame.esi = frame.edi = 0; + frame.ebp = p->ebp; + frame.esp = p->esp; + frame.eflags = p->eflags; + frame.eip = sched_dispatcher; + frame.cs = 0x8; - p->state = PSTATE_READY; + // load stack + copy_to_pdir(&frame, sizeof(frame), p->page_dir, p->esp); - switch_page_dir(tmp_page_dir); + // save stack checksum + p->checksum = stack_check(&frame, &(&frame)[1]); - crit_exit(); - return add_process(p); + PROCESS_ID pid = add_process(p); + printk("Executing task %i...\n", pid); + return pid; } PROCESS_ID current_pid; void sched_interrupt_c(SCHED_FRAME * volatile frame, uint32_t volatile ebp) { //kpanic("SCHEDULER STACK INFO"); - PROCESS* process = get_process(current_pid); + PROCESS* current = get_process(current_pid); if (current_pid != 0) { - process->esp = (uint32_t)frame; - process->ebp = ebp; - process->eip = frame->eip; - process->eflags = frame->eflags; + current->esp = (uint32_t)frame; + current->ebp = ebp; + current->eip = frame->eip; + current->eflags = frame->eflags; + + // save stack checksum + current->checksum = stack_check(current->esp, current->ebp); } // select next process static int pid = 0; - pid = pid % 2 + 1; + pid = pid % 3 + 1; current_pid = pid; - printk("\n### SCHEDULER: SWITCH TO TASK %i\n", pid); + //printk("\n### SCHEDULER: SWITCH TO TASK %i\n", pid); // prepare to return to process - process = get_process(current_pid); - switch_page_dir(process->page_dir); - frame = (volatile SCHED_FRAME*)(process->esp); - ebp = process->ebp; - frame->eip = process->eip; - frame->eflags = process->eflags; + PROCESS* next = get_process(current_pid); + switch_page_dir(next->page_dir); + + // check stack + if (current_pid != 0 && next->checksum != stack_check(next->esp, next->ebp)) { + printk("STACK DAMAGED: PROCESS %i, ESP %i, EBP %i\n", current_pid, next->esp, next->ebp); + memdump((void*)(next->esp), (void*)(next->ebp - next->esp)); + kpanic("CRITICAL STACK DAMAGE"); + } + + // prepare stack + frame = (volatile SCHED_FRAME*)(next->esp); + ebp = next->ebp; + //frame->cs = 0x08; + //frame->eip = next->eip; + //frame->eflags = next->eflags; + frame->esp = next->esp; + frame->ebp = next->ebp; + // reset the timer pit_setup_channel(PIT_CHANNEL_0, PIT_MODE_0, 0xFFFF);

@@ -103,7 +118,12 @@ printk(".");

while (1) { } } +extern void* sched_interrupt; + int sched_init(void) { + // install scheduler interrupt + install_interrupt(0x20, &sched_interrupt, 0x08, INT_GATE); + // create idle process sched_exec(create_empty_page_dir(), idle);

@@ -142,7 +162,7 @@ PROCESS* this = get_process(current_pid);

PROCESS_MAIN* entry = this->entry; // enter the actual program - entry(0, (void*)0); + entry(); printk("Process %i terminated.\n", current_pid);
A kernel/sched/stack_check.c

@@ -0,0 +1,11 @@

+#include "cedos/sched/stack_check.h" + +STACK_CHECKSUM stack_check(const void *esp, const void *ebp) { + STACK_CHECKSUM sum = 0; + + for (uint32_t *p = esp; p < ebp; p = &p[1]) { + sum ^= *p; + } + + return sum; +}
A kernel/syscall.c

@@ -0,0 +1,13 @@

+#include "cedos/interrupts.h" + +INTERRUPT(syscall_interrupt, frame) { + printk("SYSCALL\n"); +} + +/*! + * Installs the syscall interrupt to INT 0x30 + */ +int syscall_init(void) { + install_interrupt(0x30, syscall_interrupt, 0x08, INT_GATE); + return 1; +}
M run.shrun.sh

@@ -1,1 +1,1 @@

-qemu -drive index=0,if=floppy,format=raw,file=build/base.img -m 64 -monitor stdio -no-reboot -d int,cpu_reset,exec,in_asm 2> /dev/null+qemu -drive index=0,if=floppy,format=raw,file=build/base.img -m 64 -monitor stdio -no-reboot -d int,cpu_reset,exec,in_asm 2> debug/err.log