@@ -14,5 +14,6 @@ void kpanic(const char* string);
void memdump(void* start, uint32_t size); void crit_enter(void); void crit_exit(void); +void hard_reset(void); #endif
@@ -23,6 +23,11 @@ */
typedef uint32_t PROCESS_ID; /*! + * Type for Process IDs. + */ +typedef uint32_t PROCESS_PRIO; + +/*! * Defines the prototype for process entry functions. */ typedef int PROCESS_MAIN(void);@@ -31,24 +36,45 @@ /*!
* Struct that saves context information for a process. */ typedef struct __PROCESS { - //! Points to the next process struct in the list. + //! Points to the next process struct in the process list. struct __PROCESS *next; + //! Points to the previous process struct in the process list. + struct __PROCESS *prev; + //! Points to the processes first child process. struct __PROCESS *child; - //! Points to one of the processes sibling processes. - struct __PROCESS *sibling; + //! Points to the processes parent process. + struct __PROCESS *parent; + + //! Points to the processes next sibling process. + struct __PROCESS *next_sibling; + + //! Points to the processes previous sibling process. + struct __PROCESS *prev_sibling; //! Unique number to identify the process with. PROCESS_ID id; - //! Address of the processes own page directory in physical memory. - PHYS_ADDR page_dir; + //! Name of the process. + const char *name; //! Current state of the process. PROCESS_STATE state; + //! Process priority. + PROCESS_PRIO priority; + + //! Stack checksum + STACK_CHECKSUM checksum; + + //! Points to the program that is to be executed by the scheduler. + PROCESS_MAIN *entry; + + //! Address of the processes own page directory in physical memory. + PHYS_ADDR page_dir; + //! Points to the processor instruction to be executed next. VIRT_ADDR eip;@@ -58,14 +84,8 @@
//! 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; - - //! Points to the program that is to be executed by the scheduler. - PROCESS_MAIN *entry; } PROCESS; /*!@@ -78,14 +98,33 @@
/*! * Adds a process struct to the list of all processes and assigns it a unique ID. * \param process Pointer to the process struct to add to the list. + * \param parent_pid PID of the parent process. * \return Process ID that was assigned to the process struct. */ -PROCESS_ID add_process(PROCESS* process); +PROCESS_ID add_process(PROCESS *process, PROCESS_ID parent_pid); /*! * Removes the process struct with ID \p pid from the list of all processes. * \param pid Process ID whose process struct is to be removed from the list. */ void remove_process(PROCESS_ID pid); + +/*! + * Returns the first element of the list. + * \return First list element. + */ +PROCESS* get_first_process(void); + +/*! + * Returns the last element of the list. + * \return Last list element. + */ +PROCESS* get_last_process(void); + +/*! + * Returns the number of running processes. + * \return Number of running processes. + */ +uint32_t get_process_count(void); #endif
@@ -30,13 +30,13 @@
/*! * Executes a task. */ -PROCESS_ID sched_exec(PHYS_ADDR page_dir, PROCESS_MAIN *entry); +PROCESS_ID sched_exec(PHYS_ADDR page_dir, PROCESS_MAIN *entry, const char *name); /*! * Return the ID of the current process. * \return ID of current process. */ -PROCESS_ID sched_get_current_process(void); +PROCESS_ID get_current_process(void); /*! * Initializes the scheduler.@@ -48,6 +48,12 @@ * Starts the scheduler.
* \return 1 on success, 0 on failure. */ int sched_start(void); + +/*! + * Stops the scheduler. + * \return 1 on success, 0 on failure. + */ +int sched_stop(void); /*! * Returns processing time to the scheduler prematurely and blocks the
@@ -0,0 +1,14 @@
+/*! \file + * Provides the used scheduling strategy. + */ +#ifndef SCHED_STRATS_H +#define SCHED_STRATS_H + +/*! + * Returns the process ID that is to be scheduled next. + * \param current Currently running process. + * \return Next scheduled process. + */ +PROCESS_ID next_schedule(PROCESS_ID current); + +#endif
@@ -4,8 +4,10 @@ #include "assembly.h"
CON_DRIVER *core_con; +char numeric[] = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9' }; +char hex[] = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' }; + void print_hex_char(uint8_t c) { - static char hex[] = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' }; core_con->write_c(hex[c >> 4]); core_con->write_c(hex[c & 0x0F]); }@@ -17,6 +19,35 @@ print_hex_char(mem[3-i]);
} } +void rek_print_uint(unsigned int value) { + if (value > 0) { + rek_print_uint(value / 10); + core_con->write_c(numeric[value % 10]); + } +} + +void print_uint(unsigned int value) { + if (value == 0) { + core_con->write_c('0'); + return; + } + + rek_print_uint(value); +} + +void print_int(int value) { + if (value < 0) { + core_con->write_c('-'); + print_int(-value); + return; + } else if (value == 0) { + core_con->write_c('0'); + return; + } + + rek_print_uint((unsigned int)value); +} + void memdump(void* start, uint32_t size) { uint8_t* _start = (uint8_t*)((uint32_t)start & 0xFFFFFFF0); uint8_t* _end = (uint8_t*)(((uint32_t)start + size + 0xF) & 0xFFFFFFF0);@@ -77,7 +108,7 @@ printk(" ESI=%i EDI=%i ESP=%i EBP=%i\n", esi, edi, esp, ebp);
} void printk(const char* fmt, ...) { - //crit_enter(); + crit_enter(); va_list args; va_start(args, fmt); uint32_t index = 0;@@ -88,9 +119,15 @@ STATE_ARGUMENT,
} state = STATE_DEFAULT; while (*fmt) { - if (state == STATE_ARGUMENT && *fmt == 'i') { + if (state == STATE_ARGUMENT && *fmt == 'X') { print_uint32(va_arg(args, uint32_t)); state = STATE_DEFAULT; + } else if (state == STATE_ARGUMENT && *fmt == 'i') { + print_int(va_arg(args, int)); + state = STATE_DEFAULT; + } else if (state == STATE_ARGUMENT && *fmt == 'u') { + print_uint(va_arg(args, unsigned int)); + state = STATE_DEFAULT; } else if (state == STATE_ARGUMENT && *fmt == 's') { const char* string = va_arg(args, const char*); while (*string) { core_con->write_c(*string++); }@@ -107,7 +144,7 @@
fmt++; } - //crit_exit(); + crit_exit(); } void kpanic(const char* string) {@@ -119,14 +156,21 @@ stackdump();
while (1) {} } -uint32_t volatile eflags = 0; +uint32_t eflags_stack[20]; +uint32_t eflags_stack_index = 0; void crit_enter(void) { - eflags = get_eflags(); + eflags_stack[eflags_stack_index++] = get_eflags(); cli(); } void crit_exit(void) { - set_eflags(eflags); + if (eflags_stack_index > 0) { + set_eflags(eflags_stack[--eflags_stack_index]); + } +} + +void hard_reset(void) { + outb(0xFE, 0x64); } int core_init(void) {
@@ -59,38 +59,74 @@ }
extern uint8_t* IDT; -int task1(void); -int task2(void); -int task3(void); +void tasktree_r(PROCESS *p, int n) { + if (p == NULL) { return; } -int task1(void) { - //outb(0xFE, 0x64); - sched_exec(create_empty_page_dir(), task2); - printk(" Somebody once told me\n"); - while (1) { hlt(); } + for (int i = 0; i < n - 1; i++) { + printk("| "); + } + + printk("|--%s\n", p->name); + + for (PROCESS *child = p->child; child != NULL; child = child->next_sibling) { + for (int i = 0; i < n; i++) { + printk("| "); + } + printk("|\n"); + tasktree_r(child, n + 1); + } } -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"); - +void tasktree(PROCESS_ID pid) { + PROCESS *process = get_process(pid); + if (process != NULL) { + crit_enter(); + printk("Current task tree:\n"); + tasktree_r(process, 1); + crit_exit(); + } +} + +int fibonacci(void) { + int a = 0, b = 1; + + while (1) { + int tmp = a + b; + b = a; + a = tmp; + printk("%i\n", a); + sched_yield(); + } +} + +int leaf(void) { while (1) { hlt(); } } -int task3(void) { - printk(" I ain't the sharpest tool in the shed.\n"); +int node(void) { + for (int i = 0; i < 8; i++) { + sched_yield(); + } + + sched_exec(create_empty_page_dir(), leaf, "leaf"); + while (1) { hlt(); } } +int sysinit(void) { + sched_exec(create_empty_page_dir(), fibonacci, "fibonacci"); + sched_exec(create_empty_page_dir(), node, "node"); + while (get_process_count() < 5) { sched_yield(); } + tasktree(1); + printk("Terminating.\n"); +} + int os_main(void) { - //pic_unmask_interrupt(0); infodump(); // create test tasks printk("Creating tasks.\n"); - sched_exec(create_empty_page_dir(), task1); + sched_exec(create_empty_page_dir(), sysinit, "sysinit"); printk("Starting scheduler.\n"); sched_start();
@@ -191,7 +191,7 @@
EXCEPTION(page_fault_isr, frame, error_code) { volatile VIRT_ADDR faulty_addr; __asm__ volatile ("mov %%cr2, %0" : "=a" (faulty_addr)); - printk("PAGE FAULT: %i\n", faulty_addr); + printk("PAGE FAULT: %X\n", faulty_addr); PHYS_ADDR new_page = get_free_page(); map_page_to_this(new_page, PAGE_DIR_INDEX(faulty_addr), PAGE_TABLE_INDEX(faulty_addr), PAGE_TABLE_FLAGS); // dump registers to stdout
@@ -1,6 +1,5 @@
#include "cedos/pic.h" #include "assembly.h" -#include "common.h" /*! * Moves irqs to appropriate addresses and enables all PIC interrupts
@@ -2,11 +2,19 @@ #include "cedos/sched/process.h"
#define NULL ((void*)0) -PROCESS* list_head; -//PROCESS* current_process; -//PROCESS_ID next_available = 0; +PROCESS* list_head = NULL; +PROCESS* list_tail = NULL; +PROCESS_ID next_available = 0; +uint32_t process_count = 0; +/*! + * Gets a process ID and returns the process struct in the list with the same ID. + * \param pid Process ID to get the process struct for. + * \return Process struct for process with ID \p pid. + */ PROCESS* get_process(PROCESS_ID pid) { + if (list_tail->id == pid) { return list_tail; } + for (PROCESS *p = list_head; p != NULL; p = p->next) { if (p->id == pid) { return p;@@ -18,32 +26,97 @@
return NULL; } -PROCESS_ID add_process(PROCESS* process) { - for (PROCESS **p = &list_head; *p != NULL; p = &((*p)->next)) { - if ((*p)->next == NULL) { - (*p)->next = process; - process->id = (*p)->id + 1; - process->next = NULL; - return process->id; - } else if ((*p)->next->id > (*p)->id + 1) { - (*p)->next = process; - process->id = (*p)->id + 1; - process->next = (*p); - return process->id; +/*! + * Adds a process struct to the list of all processes and assigns it a unique ID. + * \param process Pointer to the process struct to add to the list. + * \return Process ID that was assigned to the process struct. + */ +PROCESS_ID add_process(PROCESS *process, PROCESS_ID parent_pid) { + if (list_head == NULL) { + list_head = process; + list_tail = process; + process->prev = NULL; + } else { + list_tail->next = process; + process->prev = list_tail; + list_tail = process; + } + + process->next = NULL; + + PROCESS *parent = (parent_pid == 0) ? NULL : get_process(parent_pid); + + if (parent != NULL) { + process->next_sibling = parent->child; + + if (parent->child != NULL) { + parent->child->prev_sibling = process; } + + parent->child = process; + } else { + process->next_sibling = NULL; } - list_head = process; - process->next = NULL; - process->id = 0; - return 0; + process->prev_sibling = NULL; + process->parent = parent; + + process_count++; + + return (process->id = next_available++); } +/*! + * Removes the process struct with ID \p pid from the list of all processes. + * \param pid Process ID whose process struct is to be removed from the list. + */ void remove_process(PROCESS_ID pid) { - for (PROCESS **p = &list_head; (*p) != NULL; p = &((*p)->next)) { - if ((*p)->next != NULL && (*p)->next->id == pid) { - (*p)->next = (*p)->next->next; - return; - } + PROCESS *process = get_process(pid); + + if (process == NULL) { return; } + + if (process == list_head && process == list_tail) { + list_head = NULL; + list_tail = NULL; + } else if (process == list_head && process != list_tail) { + list_head = process->next; + list_head->prev = NULL; + } else if (process != list_head && process == list_tail) { + list_tail = process->prev; + list_tail->next = NULL; + } else { + PROCESS *prev = process->prev, *next = process->next; + prev->next = next; + next->prev = prev; } + + PROCESS *prev_sib = process->prev_sibling, *next_sib = process->next_sibling; + if (prev_sib != NULL) { prev_sib->next_sibling = next_sib; } + if (next_sib != NULL) { next_sib->prev_sibling = prev_sib; } + + process_count--; +} + +/*! + * Returns the first element of the list. + * \return First list element. + */ +PROCESS* get_first_process(void) { + return list_head; +} + +/*! + * Returns the last element of the list. + * \return Last list element. + */ +PROCESS* get_last_process(void) { + return list_tail; +} + +/*! + * Returns the number of running processes. + * \return Number of running processes. + */ +uint32_t get_process_count(void) { + return process_count; }
@@ -1,5 +1,6 @@
#include "cedos/sched/sched.h" #include "cedos/sched/process.h" +#include "cedos/sched/sched_strats.h" #include "cedos/mm/paging.h"@@ -12,26 +13,32 @@ #include "cedos/pit.h"
#include "cedos/pic.h" #include "assembly.h" -#include "common.h" #define KERNEL_PRIVATE_STACK (void*)(0xC0600000) #define PROCESS_STD_EFLAGS (0x00000286) +#define SCHED_INTERVAL (0xFFFF) + PROCESS* get_slot(void) { - static PROCESS free_slots[4]; + static PROCESS free_slots[8]; static uint32_t index = 0; return &(free_slots[index++]); } +PROCESS_ID current_pid; + int sched_dispatcher(void); /*! * Executes a task. */ -PROCESS_ID sched_exec(PHYS_ADDR page_dir, PROCESS_MAIN *entry) { +PROCESS_ID sched_exec(PHYS_ADDR page_dir, PROCESS_MAIN *entry, const char *name) { + crit_enter(); + // set process context PROCESS *p = get_slot(); + p->name = name; p->page_dir = page_dir; p->eip = sched_dispatcher; p->ebp = KERNEL_PRIVATE_STACK;@@ -56,12 +63,12 @@
// save stack checksum p->checksum = stack_check(&frame, &(&frame)[1]); - PROCESS_ID pid = add_process(p); - printk("Executing task %i...\n", pid); + PROCESS_ID pid = add_process(p, current_pid); + //printk("Executing task %i...\n", pid); + + crit_exit(); return pid; } - -PROCESS_ID current_pid; void sched_interrupt_c(SCHED_FRAME * volatile frame, uint32_t volatile ebp) { //kpanic("SCHEDULER STACK INFO");@@ -78,11 +85,9 @@ current->checksum = stack_check(current->esp, current->ebp);
} // select next process - static int pid = 0; - pid = pid % 3 + 1; - current_pid = pid; + current_pid = next_schedule(current_pid); - //printk("\n### SCHEDULER: SWITCH TO TASK %i\n", pid); + //printk("%i", current_pid); // prepare to return to process PROCESS* next = get_process(current_pid);@@ -90,7 +95,7 @@ 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); + printk("STACK DAMAGED: PROCESS %i (%s), ESP %X, EBP %X\n", current_pid, get_process(current_pid)->name, next->esp, next->ebp); memdump((void*)(next->esp), (void*)(next->ebp - next->esp)); kpanic("CRITICAL STACK DAMAGE"); }@@ -106,16 +111,13 @@ frame->ebp = next->ebp;
// reset the timer - pit_setup_channel(PIT_CHANNEL_0, PIT_MODE_0, 0xFFFF); + pit_setup_channel(PIT_CHANNEL_0, PIT_MODE_0, SCHED_INTERVAL); pic1_eoi(); - - //if (current_pid == 2) outb(0xFE, 0x64); } void idle(void) { - printk("."); - while (1) { } + while (1) { printk("."); hlt(); } } extern void* sched_interrupt;@@ -124,39 +126,64 @@ int sched_init(void) {
// install scheduler interrupt install_interrupt(0x20, &sched_interrupt, 0x08, INT_GATE); + current_pid = 0; + // create idle process - sched_exec(create_empty_page_dir(), idle); + sched_exec(create_empty_page_dir(), idle, "idle"); return 1; -} - -int sched_start(void) { - current_pid = 0; - - // perform the first timer interrupt manually - pic_unmask_interrupt(0); - INT(0x20); } void sched_yield(void) { + INT(0x20); } +/** + * IMPORTANT NOTE: + * This method has to be modified for processes to be able to kill themselves! + * Right now, this will lead to undefined behaviour! + */ int sched_kill(PROCESS_ID pid) { + int success = 1; crit_enter(); - if (pid == current_pid) { - //remove_process(pid); - sched_yield(); + + PROCESS *process = get_process(pid); + if (process != NULL) { + // kill all children + for (PROCESS *child = process->child; child != NULL; child = child->next_sibling) { + sched_kill(child->id); + } + + remove_process(process->id); } else { - //remove_process(pid); + success = 0; } + crit_exit(); - return 1; + return success; +} + +int sched_start(void) { + current_pid = 0; + + // perform the first timer interrupt manually + pic_unmask_interrupt(0); + INT(0x20); +} + +int sched_stop(void) { + // send signals to all processes and allow them to wrap up + + // kill all processes + + // disable interrupts + pic_mask_interrupt(0); } int sched_dispatcher(void) { - printk("Dispatching process %i...\n", current_pid); + //printk("Dispatching process %i...\n", current_pid); PROCESS* this = get_process(current_pid); PROCESS_MAIN* entry = this->entry;@@ -164,7 +191,10 @@
// enter the actual program entry(); - printk("Process %i terminated.\n", current_pid); + //printk("Process %i terminated.\n", current_pid); sched_kill(current_pid); + + // just for absolute safety + while (1); }
@@ -0,0 +1,20 @@
+#include "cedos/sched/process.h" + +#define NULL ((void*)0) + +PROCESS_ID next_schedule(PROCESS_ID current) { + PROCESS* process = get_process(current); + + if (process != NULL && process->next != NULL) { + return process->next->id; + } else { + PROCESS *first = get_first_process(); + if (first != NULL && first->id != 0) { + return first->id; + } else if (first != NULL && first->next != NULL) { + return first->next->id; + } else { + return 0; + } + } +}