diff --git a/src/apps/CMakeLists.txt b/src/apps/CMakeLists.txt index 4cf9f762..68ddbee1 100644 --- a/src/apps/CMakeLists.txt +++ b/src/apps/CMakeLists.txt @@ -1,23 +1,36 @@ -set(APPS_BASE_DIR ${CMAKE_BINARY_DIR}/apps) -execute_process(COMMAND mkdir -p ${APPS_BASE_DIR}) +set(DRIVE_BASE_DIR ${CMAKE_BINARY_DIR}/drive) +execute_process(COMMAND mkdir -p ${DRIVE_BASE_DIR}) macro(add_app target) cross_target(${target}) - target_link_libraries(${target} libc) + target_link_libraries(${target} cinit libc) cross_target_binary(${target}) - add_custom_command(OUTPUT ${APPS_BASE_DIR}/${target} - COMMAND ${CMAKE_COMMAND} -E copy ${CMAKE_CURRENT_BINARY_DIR}/${target}.bin ${APPS_BASE_DIR}/${target} - COMMAND ${CMAKE_COMMAND} -E copy ${CMAKE_CURRENT_BINARY_DIR}/${target}.elf ${APPS_BASE_DIR}/${target}.elf + # Build raw binary for execution in os + add_custom_command(OUTPUT ${DRIVE_BASE_DIR}/${target} + COMMAND ${CMAKE_COMMAND} -E copy ${CMAKE_CURRENT_BINARY_DIR}/${target}.bin ${DRIVE_BASE_DIR}/${target} + + # Output from cross_target_binary DEPENDS ${CMAKE_CURRENT_BINARY_DIR}/${target}.bin) + # Build elf executable for future use + add_custom_command(OUTPUT ${DRIVE_BASE_DIR}/${target}.elf + COMMAND ${CMAKE_COMMAND} -E copy ${CMAKE_CURRENT_BINARY_DIR}/${target}.elf ${DRIVE_BASE_DIR}/${target}.elf + + # Output from cross_target_binary + DEPENDS ${CMAKE_CURRENT_BINARY_DIR}/${target}.elf) + add_custom_target(${target}_app - DEPENDS ${APPS_BASE_DIR}/${target}) + DEPENDS ${DRIVE_BASE_DIR}/${target} ${DRIVE_BASE_DIR}/${target}.elf) list(APPEND APPS_TARGETS ${target} ${target}_app) set(APPS_TARGETS ${APPS_TARGETS} PARENT_SCOPE) endmacro() +# Code to run before calling app main (includes __start entrypoint) +add_subdirectory(cinit) + +# Programs loaded from disk add_subdirectory(foo) add_subdirectory(bar) add_subdirectory(init) @@ -30,20 +43,25 @@ add_subdirectory(getpid) message("App targets are ${APPS_TARGETS}") add_custom_command( - OUTPUT ${APPS_BASE_DIR}/data/ - COMMAND rm -rf ${APPS_BASE_DIR}/data/ - COMMAND mkdir -p ${APPS_BASE_DIR}/data/ - COMMAND cp -r ${CMAKE_SOURCE_DIR}/drive/* ${APPS_BASE_DIR}/data - DEPENDS ${CMAKE_SOURCE_DIR}/drive/ -) + OUTPUT ${DRIVE_BASE_DIR}/data/ + COMMAND rm -rf ${DRIVE_BASE_DIR}/data/ + COMMAND mkdir -p ${DRIVE_BASE_DIR}/data/ + COMMAND cp -r ${CMAKE_SOURCE_DIR}/drive/* ${DRIVE_BASE_DIR}/data + DEPENDS ${CMAKE_SOURCE_DIR}/drive/) add_custom_target(apps_data - DEPENDS ${APPS_BASE_DIR}/data/) + DEPENDS ${DRIVE_BASE_DIR}/data/) + +# Delete files in build/apps/data so it can be removed +set_property( + TARGET apps_data + APPEND + PROPERTY ADDITIONAL_CLEAN_FILES ${DRIVE_BASE_DIR}/data/) add_custom_command(OUTPUT ${CMAKE_BINARY_DIR}/apps.tar COMMAND tar -cf ${CMAKE_BINARY_DIR}/apps.tar * DEPENDS ${APPS_TARGETS} apps_data - WORKING_DIRECTORY ${APPS_BASE_DIR}) + WORKING_DIRECTORY ${DRIVE_BASE_DIR}) add_custom_target(apps_image ALL DEPENDS ${CMAKE_BINARY_DIR}/apps.tar) diff --git a/src/apps/bar/src/bar.c b/src/apps/bar/src/bar.c index 9235242b..6008f4e1 100644 --- a/src/apps/bar/src/bar.c +++ b/src/apps/bar/src/bar.c @@ -3,7 +3,7 @@ #include "libc/stdio.h" -int __start(size_t argc, char ** argv) { +int main(size_t argc, char ** argv) { printf("Bar got %u arguments\n", argc); for (size_t i = 0; i < argc; i++) { diff --git a/src/apps/cinit/CMakeLists.txt b/src/apps/cinit/CMakeLists.txt new file mode 100644 index 00000000..e2d18641 --- /dev/null +++ b/src/apps/cinit/CMakeLists.txt @@ -0,0 +1,4 @@ +set(TARGET cinit) + +cross_target(${TARGET}) +target_link_libraries(${TARGET} libc) diff --git a/src/apps/cinit/link.ld b/src/apps/cinit/link.ld new file mode 100644 index 00000000..28e2cfdc --- /dev/null +++ b/src/apps/cinit/link.ld @@ -0,0 +1,30 @@ +ENTRY(__start) + +SECTIONS { + . = 0x400000; + + .text : + { + *(.text.entry) + *(.text) + } + + /* Read-only data. */ + .rodata BLOCK(4K) : ALIGN(4K) + { + *(.rodata) + } + + /* Read-write data (initialized) */ + .data BLOCK(4K) : ALIGN(4K) + { + *(.data) + } + + /* Read-write data (uninitialized) and stack */ + .bss BLOCK(4K) : ALIGN(4K) + { + *(COMMON) + *(.bss) + } +} \ No newline at end of file diff --git a/src/apps/cinit/src/cinit.c b/src/apps/cinit/src/cinit.c new file mode 100644 index 00000000..2c601456 --- /dev/null +++ b/src/apps/cinit/src/cinit.c @@ -0,0 +1,14 @@ +#include "libc/proc.h" +#include "libc/stdio.h" + +extern int main(size_t argc, char ** argv); + +void __cinit(size_t argc, char ** argv) { + printf("c init\n"); + // TODO init malloc + // TODO is there anything in signals or system calls to setup? + // TODO do stdio handles setup here? + int res = main(argc, argv); + printf("Main returned %d\n", res); + proc_exit(res); +} diff --git a/src/apps/cinit/src/entry.asm b/src/apps/cinit/src/entry.asm new file mode 100644 index 00000000..f1c10222 --- /dev/null +++ b/src/apps/cinit/src/entry.asm @@ -0,0 +1,9 @@ +extern __cinit +extern main + +section .text.entry + +global __start +__start: + call __cinit + ; jmp main diff --git a/src/apps/demo/src/demo.c b/src/apps/demo/src/demo.c index 31803f0e..2b6d6429 100644 --- a/src/apps/demo/src/demo.c +++ b/src/apps/demo/src/demo.c @@ -2,7 +2,7 @@ #include "libc/proc.h" #include "libc/stdio.h" -int __start(size_t argc, char ** argv) { +int main(size_t argc, char ** argv) { printf("Lets demo some cool features of printf\n"); int len = printf("Like the percent sign %%, \na signed int %d, a signed int with width formatting %4d, \nleading zeros %04d, left align %-4d\n", 10, 10, 10, 10); len += printf("How about negative numbers: signed %d and unsigned %u\n", -10, -10); diff --git a/src/apps/foo/src/foo.c b/src/apps/foo/src/foo.c index 293b553a..765ee444 100644 --- a/src/apps/foo/src/foo.c +++ b/src/apps/foo/src/foo.c @@ -13,6 +13,6 @@ void foo() { proc_exit(0); } -void __start() { +void main() { foo(); } diff --git a/src/apps/getpid/src/getpid.c b/src/apps/getpid/src/getpid.c index 2c6f3679..e02eadc8 100644 --- a/src/apps/getpid/src/getpid.c +++ b/src/apps/getpid/src/getpid.c @@ -1,7 +1,7 @@ #include "libc/proc.h" #include "libc/stdio.h" -void __start() { +void main() { int pid = getpid(); printf("PID is %u\n"); } diff --git a/src/apps/ping/src/ping.c b/src/apps/ping/src/ping.c index 5495f2a4..3d3bf97f 100644 --- a/src/apps/ping/src/ping.c +++ b/src/apps/ping/src/ping.c @@ -7,7 +7,3 @@ void main() { yield(); } } - -void __start() { - main(); -} diff --git a/src/apps/pong/src/pong.c b/src/apps/pong/src/pong.c index 1bf4053c..d1c41aa1 100644 --- a/src/apps/pong/src/pong.c +++ b/src/apps/pong/src/pong.c @@ -7,7 +7,3 @@ void main() { yield(); } } - -void __start() { - main(); -} diff --git a/src/apps/shell/src/shell.c b/src/apps/shell/src/shell.c index 73cc24f6..8fb26547 100644 --- a/src/apps/shell/src/shell.c +++ b/src/apps/shell/src/shell.c @@ -48,7 +48,7 @@ static size_t buff_read(const cb_t * cb, uint8_t * data, size_t count); static size_t buff_remove(cb_t * cb, size_t count); static void exec_buff(); -int __start(size_t argc, char ** argv) { +int main(size_t argc, char ** argv) { term_command_add("help", help_cmd); init_commands(); diff --git a/src/kernel/include/kernel.h b/src/kernel/include/kernel.h index 5b74647e..67c0aa5e 100644 --- a/src/kernel/include/kernel.h +++ b/src/kernel/include/kernel.h @@ -48,8 +48,6 @@ void kernel_queue_event(ebus_event_t * event); typedef int (*_proc_call_t)(void * data); -int kernel_call_as_proc(int pid, _proc_call_t fn, void * data); - -int kernel_switch_task(); +void kernel_switch_task(); #endif // KERNEL_H diff --git a/src/kernel/src/kernel.c b/src/kernel/src/kernel.c index 4c2ff789..60b96401 100644 --- a/src/kernel/src/kernel.c +++ b/src/kernel/src/kernel.c @@ -154,8 +154,10 @@ int kernel_exec(const char * filename, size_t argc, char ** argv) { return pid; } -int kernel_switch_task() { - return scheduler_run(&__kernel.scheduler); +void kernel_switch_task() { + if (scheduler_run(&__kernel.scheduler)) { + KPANIC("Failed to switch tasks"); + } } process_t * get_current_process() { diff --git a/src/kernel/src/kernel/scheduler.c b/src/kernel/src/kernel/scheduler.c index a38e597a..b2348621 100644 --- a/src/kernel/src/kernel/scheduler.c +++ b/src/kernel/src/kernel/scheduler.c @@ -7,78 +7,44 @@ #include "kernel/logs.h" #include "libc/string.h" -static void idle(); - int scheduler_init(scheduler_t * scheduler, proc_man_t * pm) { - if (!scheduler || !pm) { + if (!scheduler) { + KLOG_ERROR("scheduler_init received a null pointer for the scheduler struct"); + return -1; + } + if (!pm) { + KLOG_ERROR("scheduler_init received a null pointer for the process manager struct"); return -1; } + KLOG_TRACE("Clearing scheduler struct"); kmemset(scheduler, 0, sizeof(scheduler_t)); + KLOG_TRACE("Useing process manager %p in scheduler %p", pm, scheduler); scheduler->pm = pm; + KLOG_TRACE("Finished init of scheduler %p", scheduler); + return 0; } -// TODO this is just a copy of the kernel / process manager current behavior int scheduler_run(scheduler_t * scheduler) { if (!scheduler) { + KLOG_ERROR("scheduler_run received a null pointer"); return -1; } - if (cb_len(&get_kernel()->event_queue.queue) > 0) { - KLOG_DEBUG("There are %u events ready", cb_len(&get_kernel()->event_queue.queue)); - ebus_event_t event; - - if (cb_pop(&get_kernel()->event_queue.queue, &event) < 0) { - KPANIC("Failed to pop from event queue"); - } - - switch (event.event_id) { - case EBUS_EVENT_EXEC: { - int pid = kernel_exec(event.exec.filename, event.exec.argc, event.exec.argv); - if (pid > 0) { - ebus_event_t proc_event = {0}; - proc_event.event_id = EBUS_EVENT_PROC_MADE; - proc_event.proc_made.pid = pid; - if (ebus_push(&get_kernel()->event_queue, &proc_event)) { - KPANIC("Ebus push failed"); - } - } - } break; - - case EBUS_EVENT_PROC_CLOSE: { - process_t * proc = kernel_find_pid(event.proc_close.pid); - if (!proc) { - KPANIC("Failed to find pid"); - } - if (pm_remove_proc(&get_kernel()->pm, proc->pid)) { - KPANIC("Failed to remove process from pm"); - } - process_free(proc); - } break; - - default: { - if (pm_push_event(&get_kernel()->pm, &event)) { - KPANIC("Failed to push event to process manager"); - } - } break; - } + process_t * proc = get_active_task(); + if (!proc) { + KPANIC("Failed to get active process"); } - process_t * next = pm_get_next(scheduler->pm); + process_t * next = pm_get_next(kernel_get_proc_man()); + KLOG_TRACE("Next after %u is %u in state %u", proc->pid, next->pid, next->state); - if (next) { - // TODO ebus events - process_resume(next, 0); - KPANIC("PROCESS SHOULD NOT RETURN TO SCHEDULER!"); + if (pm_resume_process(kernel_get_proc_man(), next->pid)) { + KPANIC("Failed to resume process"); } - else { - idle(); - } -} -static void idle() { - asm("hlt"); + KLOG_TRACE("Returned to process %u", proc->pid); } diff --git a/src/kernel/src/kernel/system_call_event.c b/src/kernel/src/kernel/system_call_event.c index 4a105dd1..b5695b8c 100644 --- a/src/kernel/src/kernel/system_call_event.c +++ b/src/kernel/src/kernel/system_call_event.c @@ -46,10 +46,7 @@ int sys_call_event_cb(uint32_t call_id, void * args_data, registers_t * regs) { proc->state = PROCESS_STATE_WAITING; enable_interrupts(); - process_t * next = pm_get_next(kernel_get_proc_man()); - if (pm_resume_process(kernel_get_proc_man(), next->pid)) { - KPANIC("Failed to resume process"); - } + kernel_switch_task(); // args->filter doesn't appear to be valid here, why not? if (!(proc->next_event.event_id == proc->filter_event.event_id)) { @@ -65,10 +62,7 @@ int sys_call_event_cb(uint32_t call_id, void * args_data, registers_t * regs) { case SYS_CALL_EVENT_TIME: { enable_interrupts(); - process_t * next = pm_get_next(kernel_get_proc_man()); - if (pm_resume_process(kernel_get_proc_man(), next->pid)) { - KPANIC("Failed to resume process"); - } + kernel_switch_task(); return time_s(); } break; @@ -103,10 +97,7 @@ int sys_call_event_cb(uint32_t call_id, void * args_data, registers_t * regs) { do { enable_interrupts(); - process_t * next = pm_get_next(kernel_get_proc_man()); - if (pm_resume_process(kernel_get_proc_man(), next->pid)) { - KPANIC("Failed to resume process"); - } + kernel_switch_task(); KLOG_TRACE("Back from timer %u", timer_id); } while (proc->next_event.timer.id != timer_id); } break; diff --git a/src/kernel/src/kernel/system_call_proc.c b/src/kernel/src/kernel/system_call_proc.c index a822da0a..7f64008e 100644 --- a/src/kernel/src/kernel/system_call_proc.c +++ b/src/kernel/src/kernel/system_call_proc.c @@ -10,6 +10,7 @@ #include "exec.h" #include "kernel.h" #include "kernel/logs.h" +#include "kernel/scheduler.h" #include "libc/proc.h" #include "libc/stdio.h" #include "libc/string.h" @@ -27,27 +28,15 @@ int sys_call_proc_cb(uint32_t call_id, void * args_data, registers_t * regs) { break; } - // TODO this isn't fully updated with task switching - case SYS_CALL_PROC_EXIT: { - KLOG_DEBUG("System call proc exit"); - struct _args { - uint8_t code; - } * args = (struct _args *)args_data; - printf("Proc exit with code %u\n", args->code); - enable_interrupts(); - - ebus_event_t event = {0}; - event.event_id = EBUS_EVENT_PROC_CLOSE; - event.proc_close.pid = get_active_task()->pid; - event.proc_close.status_code = args->code; + KLOG_DEBUG("Setting process %u state from %u to %u", proc->pid, proc->state, PROCESS_STATE_DEAD); + proc->state = PROCESS_STATE_DEAD; - queue_event(&event); + enable_interrupts(); kernel_switch_task(); - KPANIC("Unexpected return from kernel_switch_task"); - } break; - // TODO this isn't fully updated with task switching + KPANIC("Unexpected return from task switch in SYS_CALL_PROC_EXIT"); + } break; case SYS_CALL_PROC_ABORT: { KLOG_DEBUG("System call proc abort"); @@ -57,43 +46,41 @@ int sys_call_proc_cb(uint32_t call_id, void * args_data, registers_t * regs) { } * args = (struct _args *)args_data; printf("Proc abort with code %u\n", args->code); puts(args->msg); - process_t * proc = get_current_process(); - enable_interrupts(); + proc->state = PROCESS_STATE_DEAD; - ebus_event_t event = {0}; - event.event_id = EBUS_EVENT_PROC_CLOSE; - event.proc_close.pid = get_active_task()->pid; - event.proc_close.status_code = args->code; - - queue_event(&event); + enable_interrupts(); kernel_switch_task(); - KPANIC("Unexpected return from kernel_switch_task"); + + KPANIC("Unexpected return from task switch in SYS_CALL_PROC_ABORT"); } break; case SYS_CALL_PROC_PANIC: { - KLOG_DEBUG("System call proc panic"); struct _args { const char * msg; const char * file; unsigned int line; } * args = (struct _args *)args_data; - vga_color(VGA_FG_WHITE | VGA_BG_RED); - vga_puts("[PANIC]"); - if (args->file) { - vga_putc('['); - vga_puts(args->file); - vga_puts("]:"); - vga_putu(args->line); - } - if (args->msg) { - vga_putc(' '); - vga_puts(args->msg); + + // Default empty string if not provided by process + const char * file = ""; + if (!file) { + file = args->file; } - vga_cursor_hide(); - asm("cli"); - for (;;) { - asm("hlt"); + + // Default empty string if not provided by process + const char * msg = ""; + if (!msg) { + msg = args->msg; } + + KLOG_WARNING("Process %u panicked in %s at line %s: %s", proc->pid, file, args->line, msg); + + proc->state = PROCESS_STATE_DEAD; + + enable_interrupts(); + kernel_switch_task(); + + KPANIC("Unexpected return from task switch in SYS_CALL_PROC_PANIC"); } break; case SYS_CALL_PROC_REG_SIG: { @@ -135,10 +122,7 @@ int sys_call_proc_cb(uint32_t call_id, void * args_data, registers_t * regs) { proc->state = PROCESS_STATE_SUSPENDED; enable_interrupts(); - process_t * next = pm_get_next(kernel_get_proc_man()); - if (pm_resume_process(kernel_get_proc_man(), next->pid)) { - KPANIC("Failed to resume process"); - } + kernel_switch_task(); } break; case SYS_CALL_PROC_EXEC: { diff --git a/src/kernel/src/process_manager.c b/src/kernel/src/process_manager.c index 7f4bf13d..9e21fafb 100644 --- a/src/kernel/src/process_manager.c +++ b/src/kernel/src/process_manager.c @@ -173,6 +173,8 @@ int pm_resume_process(proc_man_t * pm, int pid) { return -1; } + pm->foreground_task = proc; + if (proc->filter_event.event_id) { // TODO assert next_event has an event of the correct type // TODO push to process next_event instead of event_queue @@ -191,14 +193,14 @@ process_t * pm_get_next(proc_man_t * pm) { process_t * proc = pm->foreground_task->next; - // KLOG_TRACE("Start looking for next process"); + KLOG_TRACE("Start looking for next process after %u", pm->foreground_task->pid); do { - // KLOG_TRACE("Looking at pid %u in state %u to see if it's ready", proc->pid, proc->state); + KLOG_TRACE("Looking at pid %u in state %u to see if it's ready", proc->pid, proc->state); - if (PROCESS_STATE_LOADED <= proc->state <= PROCESS_STATE_DEAD) { + if (proc->state > PROCESS_STATE_LOADED && proc->state < PROCESS_STATE_DEAD) { if (!proc->filter_event.event_id) { - // KLOG_TRACE("Process %u has no filter event, so it's ready", proc->pid); + KLOG_TRACE("Process %u has no filter event, so it's ready", proc->pid); return proc; } // This handles the above case but is split for trace log @@ -206,20 +208,20 @@ process_t * pm_get_next(proc_man_t * pm) { KLOG_TRACE("Process %u has ready event %u", proc->pid, proc->next_event.event_id); return proc; } - // KLOG_TRACE("Process %u is not ready, waiting for %u", proc->pid, proc->filter_event.event_id); + KLOG_TRACE("Process %u is not ready, waiting for %u", proc->pid, proc->filter_event.event_id); } else { - // KLOG_TRACE("Process with pid %u is not alive", proc->pid); + KLOG_TRACE("Process with pid %u is not alive", proc->pid); } - // KLOG_TRACE("Going to next process %u, fg is %u", proc->next->pid, pm->foreground_task->pid); + KLOG_TRACE("Going to next process %u, fg is %u", proc->next->pid, pm->foreground_task->pid); proc = proc->next; } while (proc != pm->foreground_task->next); - // KLOG_TRACE("Finish looking for next process"); + KLOG_TRACE("Finish looking for next process"); if (PROCESS_STATE_LOADED <= proc->state <= PROCESS_STATE_DEAD) { - // KLOG_TRACE("Next process is the foreground process with pid %u", proc->pid); + KLOG_TRACE("Next process is the foreground process with pid %u", proc->pid); return proc; }