From 105eb7c48276615543a90d94c8af4df5d2f90883 Mon Sep 17 00:00:00 2001 From: Yann MAGNIN Date: Wed, 5 Feb 2020 21:09:39 +0100 Subject: [PATCH] Add scheduler first release + fix process stack crash --- Makefile | 14 +- include/kernel/devices/timer.h | 18 -- include/kernel/hardware/cpg.h | 80 ++++++++ include/kernel/hardware/tmu.h | 30 +-- include/kernel/memory.h | 2 +- include/kernel/process.h | 3 +- include/kernel/scheduler.h | 6 +- include/kernel/syscall.h | 2 + include/kernel/unistd_32.h | 3 +- include/kernel/util.h | 20 +- include/lib/display.h | 3 +- include/lib/unistd.h | 1 + include/user/builtin.h | 12 +- src/kernel/bootstrap/start.c | 14 +- src/kernel/devices/tty/file_op/read.c | 3 +- src/kernel/fs/gladfs/filesystem/mount.c | 2 +- src/kernel/fs/vfs/dentry/resolve.c | 7 +- src/kernel/fs/vfs/inode/mknod.c | 4 +- src/kernel/fs/vfs/superblock/mount.c | 4 +- src/kernel/hardware/tmu/constructor.c | 16 -- src/kernel/hardware/tmu/handler.c | 19 +- src/kernel/hardware/vbr/interrupt.c | 1 - src/kernel/hardware/vbr/interrupt_pre.s | 52 ++++++ src/kernel/scheduler/context_switch.s | 6 +- src/kernel/scheduler/debug.c | 37 ++++ src/kernel/scheduler/handler.S | 204 +++++++++++++++++++++ src/kernel/scheduler/process/alloc.c | 4 +- src/kernel/scheduler/process/get.c | 16 +- src/kernel/scheduler/process/initialize.c | 2 +- src/kernel/scheduler/schedule.c | 46 ++--- src/kernel/scheduler/start.c | 108 ++++++++++- src/kernel/scheduler/syscall/sys_exit.c | 11 ++ src/kernel/scheduler/syscall/sys_fexecve.c | 77 ++++++++ src/kernel/scheduler/syscall/sys_fork.c | 45 +++-- src/kernel/syscall/handler.c | 35 ++-- src/kernel/syscall/syscall_pre.s | 1 + src/kernel/util/kvram.c | 57 +++--- src/kernel/util/timer.c | 72 +++++++- src/lib/display/dclr_str_area.S | 12 ++ src/lib/unistd/fexecve.S | 12 ++ src/user/{ => shell}/Makefile | 18 +- src/user/shell/builtin/proc.c | 43 +++++ src/user/{ => shell}/shell.ld | 5 - src/user/shell/util/check_builtin.c | 98 +++++++--- src/user/test/Makefile | 106 +++++++++++ src/user/test/test.c | 21 ++- src/user/test/test.ld | 65 +++++++ src/user/test/test_asm.s | 4 +- 48 files changed, 1168 insertions(+), 253 deletions(-) delete mode 100644 include/kernel/devices/timer.h create mode 100644 include/kernel/hardware/cpg.h delete mode 100644 src/kernel/hardware/tmu/constructor.c create mode 100644 src/kernel/hardware/vbr/interrupt_pre.s create mode 100644 src/kernel/scheduler/debug.c create mode 100644 src/kernel/scheduler/handler.S create mode 100644 src/kernel/scheduler/syscall/sys_exit.c create mode 100644 src/kernel/scheduler/syscall/sys_fexecve.c create mode 100644 src/lib/display/dclr_str_area.S create mode 100644 src/lib/unistd/fexecve.S rename src/user/{ => shell}/Makefile (77%) create mode 100644 src/user/shell/builtin/proc.c rename src/user/{ => shell}/shell.ld (89%) create mode 100644 src/user/test/Makefile create mode 100644 src/user/test/test.ld diff --git a/Makefile b/Makefile index dae1e50..c041356 100644 --- a/Makefile +++ b/Makefile @@ -7,6 +7,7 @@ KERNEL := output/vhex.g1a USER := output/shell.elf +TEST := output/test.elf ##--- @@ -15,11 +16,13 @@ USER := output/shell.elf all: @ make --no-print-directory -C src/lib @ make --no-print-directory -C src/kernel - @ make --no-print-directory -C src/user + @ make --no-print-directory -C src/user/shell + @ make --no-print-directory -C src/user/test install: all sudo p7 send --force --no-term $(KERNEL) - sudo p7 send --force --directory=VHEX $(USER) + sudo p7 send --force --no-term --directory=VHEX $(USER) + sudo p7 send --force --directory=VHEX $(TEST) @@ -30,12 +33,15 @@ install: all clean: make clean --no-print-directory -C src/lib make clean --no-print-directory -C src/kernel - make clean --no-print-directory -C src/user + make clean --no-print-directory -C src/user/shell + make clean --no-print-directory -C src/user/test fclean: clean make fclean --no-print-directory -C src/lib make fclean --no-print-directory -C src/kernel - make fclean --no-print-directory -C src/user + make fclean --no-print-directory -C src/user/shell + make fclean --no-print-directory -C src/user/test + rm -rf build re: fclean all diff --git a/include/kernel/devices/timer.h b/include/kernel/devices/timer.h deleted file mode 100644 index 01f0929..0000000 --- a/include/kernel/devices/timer.h +++ /dev/null @@ -1,18 +0,0 @@ -#ifndef __KERNEL_DEVICES_TIMER_H__ -# define __KERNEL_DEVICES_TIMER_H__ - -#include -#include - -// TODO: MOVE ME !!!!!!!! -#define TIMER_NUMBER 3 -#define TIMER_UNUSED 0xff - -struct timer_cache_s -{ - void *callback; - volatile void *arg; - uint8_t status; -}; - -#endif /*__KERNEL_DEVICES_TIMER_H__*/ diff --git a/include/kernel/hardware/cpg.h b/include/kernel/hardware/cpg.h new file mode 100644 index 0000000..13363e2 --- /dev/null +++ b/include/kernel/hardware/cpg.h @@ -0,0 +1,80 @@ +#ifndef __KERNEL_HARDWARE_CPG_H__ +# define __KERNEL_HARDWARE_CPG_H__ + +#include +#include +#include +#include + +struct SH7305_cpg_s +{ + volatile long_union(FRQCRA, /* Casio's configuration: 0x0f212213 */ + uint32_t KICK : 1; /* Kick bits */ + uint32_t const : 1; /* All 0 */ + uint32_t STC : 6; /* PLL circuit multiplication ratio */ + uint32_t IFC : 4; /* CPU clock frequency division ratio */ + uint32_t const : 4; /* All 0 */ + uint32_t SFC : 4; /* S clock frequency division ratio */ + uint32_t BFC : 4; /* Bus clock frequency division ration */ + uint32_t const : 4; /* All 0 */ + uint32_t PFC : 4; /* Peripheral clock frequency division ratio */ + ); + volatile uint32_t FRQCRB; /* Undocumented (0x00000000) */ + volatile long_union(FCLKACR, /* Casio's configuration: 0x00000157 */ + uint32_t const : 16; /* All 0 */ + uint32_t unknown : 16; /* Unknown (default 0x0157) */ + ); + volatile long_union(FCLKBCR, /* Casio's configuration: 0x0000003f */ + uint32_t const : 16; /* All 0 */ + uint32_t unknown : 16; /* Unknown (default 0x003f) */ + ); + + GAPS(0x08); + volatile long_union(IRDACLKCR, /* Casio's configuration: 0x0000003f */ + uint32_t const : 16; /* All 0 */ + uint32_t unknown : 16; /* Unknown (default 0x003f) */ + ); + + GAPS(0x08); + volatile long_union(PLLCR, /* Casio's configuration: 0x00005000 */ + uint32_t const : 16; /* All 0 */ + uint32_t unknown0 : 1; /* Unknown (default 0) */ + uint32_t PLLE : 1; /* PLL enable (?) */ + uint32_t const : 1; /* All 0 */ + uint32_t FLLE : 1; /* FLL enable (?) */ + uint32_t const : 8; /* All 0 */ + uint32_t unknown1 : 4; /* Unknown (default 0b0000) */ + ); + + GAPS(0x14); + volatile long_union(SPUCLKCR, /* Casio's configuration: 0x00000103 */ + uint32_t const : 16; /* All 0 */ + uint32_t unknown : 16; /* Unknown (default 0x0103) */ + ); + + GAPS(0x08); + volatile long_union(VCLKCR, /* Casio's configuration: 0x0000003f */ + uint32_t const : 16; /* All 0 */ + uint32_t unknown : 16; /* Unknown (default 0x003f) */ + ); + + + GAPS(0x04); + volatile long_union(FLLFRQ, /* Casio's configuration: 0x00004384 */ + uint32_t const : 16; /* All 0 */ + uint32_t SELXM : 2; /* FLL output division */ + uint32_t unknown : 3; /* Unknown */ + uint32_t FLF : 11; /* FLL Multiplication Ratio */ + + ); + + GAPS(0x0c); + volatile long_union(LSTATS, + uint32_t const : 31; /* All 0 */ + uint32_t const FQRF : 1; /* Frequency change status */ + ); +}; + + +#define SH7305_CPG (*(volatile struct SH7305_cpg_s *)0xa4150000) +#endif /*__KERNEL_HARDWARE_CPG_H__*/ diff --git a/include/kernel/hardware/tmu.h b/include/kernel/hardware/tmu.h index 895276a..7a36b6c 100644 --- a/include/kernel/hardware/tmu.h +++ b/include/kernel/hardware/tmu.h @@ -8,29 +8,29 @@ struct timer_s { - volatile uint32_t TCOR; /* Timer Constant register */ - volatile uint32_t TCNT; /* Timer Counter */ - volatile word_union(TCR, /* Timer Control Register */ - uint16_t const : 7; /* All 0 */ - uint16_t UNF : 1; /* Underflow flags */ - uint16_t const : 2; /* All 0 */ - uint16_t UNIE : 1; /* Underflow interrup control */ - uint16_t const : 2; /* All 0 */ - uint16_t TPSC : 3; /* Time prescaler */ + volatile uint32_t TCOR; /* Timer Constant register */ + volatile uint32_t TCNT; /* Timer Counter */ + volatile word_union(TCR, /* Timer Control Register */ + uint16_t const : 7; /* All 0 */ + uint16_t UNF : 1; /* Underflow flags */ + uint16_t const : 2; /* All 0 */ + uint16_t UNIE : 1; /* Underflow interrup control */ + uint16_t CKREG : 2; /* Input Clock edge */ + uint16_t TPSC : 3; /* Time prescaler */ ); GAPS(2); }; struct __sh7305_tmu_s { - volatile byte_union(TSTR, /* Timer Start Register */ - uint8_t const : 5; /* All 0 */ - uint8_t STR2 : 1; /* Counter start 2 */ - uint8_t STR1 : 1; /* Counter start 1 */ - uint8_t STR0 : 1; /* Counter start 0 */ + volatile byte_union(TSTR, /* Timer Start Register */ + uint8_t const : 5; /* All 0 */ + uint8_t STR2 : 1; /* Counter start 2 */ + uint8_t STR1 : 1; /* Counter start 1 */ + uint8_t STR0 : 1; /* Counter start 0 */ ); GAPS(3); - volatile struct timer_s TIMER[3]; + volatile struct timer_s TIMER[3]; /* Timers */ }; #define SH7305_TMU (*(volatile struct __sh7305_tmu_s *)0xa4490004) diff --git a/include/kernel/memory.h b/include/kernel/memory.h index 74eca5f..af34990 100644 --- a/include/kernel/memory.h +++ b/include/kernel/memory.h @@ -15,7 +15,7 @@ struct pm_block_cache_s } status; // Space informations. - uint16_t start; + uint32_t start; uint32_t end; // Linked list diff --git a/include/kernel/process.h b/include/kernel/process.h index bda9cf7..20c63ff 100644 --- a/include/kernel/process.h +++ b/include/kernel/process.h @@ -14,8 +14,6 @@ #define PROCESS_NAME_LENGHT (16) #define PROCESS_MAX (4) -#define PROC_IDLE (0) - // define process struct. //TODO: signal ! struct process @@ -93,6 +91,7 @@ struct process_stack // Functions. extern struct process *process_create(const char *name); extern struct process *process_get(pid_t pid); +extern pid_t process_get_pid(struct process *process); extern int process_switch(pid_t pid); // Internal function. diff --git a/include/kernel/scheduler.h b/include/kernel/scheduler.h index 14f3547..7165d81 100644 --- a/include/kernel/scheduler.h +++ b/include/kernel/scheduler.h @@ -59,10 +59,10 @@ extern int sched_add_task(struct process *process); extern void sched_start(void); /* -** Save current context of the current task and run the -** next one based on internal task priority. +** Get the current task context and the next one +** based on internal task priority / status. */ -extern void sched_schedule(void); +extern int sched_schedule(common_context_t **current, common_context_t **next); /* ** Internal function wich will switch current process diff --git a/include/kernel/syscall.h b/include/kernel/syscall.h index a63bd0e..78a861f 100644 --- a/include/kernel/syscall.h +++ b/include/kernel/syscall.h @@ -14,6 +14,8 @@ extern pid_t sys_fork(void); extern pid_t sys_getpid(void); extern pid_t sys_getppid(void); extern pid_t sys_waitpid(pid_t pid, int *wstatus, int options); +extern pid_t sys_fexecve(const char *pathname); +extern void sys_exit(int status); extern int sys_open(const char *pathname, int flags, ...); extern ssize_t sys_write(int fd, const void *buf, size_t count); diff --git a/include/kernel/unistd_32.h b/include/kernel/unistd_32.h index e066abd..d882e82 100644 --- a/include/kernel/unistd_32.h +++ b/include/kernel/unistd_32.h @@ -6,7 +6,7 @@ // Process #define __NR_exit 1 -#define __NR_exec 2 +#define __NR_fexecve 2 #define __NR_waitpid 3 // VFS @@ -27,6 +27,7 @@ #define __NR_kvram_ascii 12 #define __NR_kvram_reverse 13 #define __NR_kvram_scroll 14 +#define __NR_kvram_clr_str_area 15 //TODO: keyboard diff --git a/include/kernel/util.h b/include/kernel/util.h index 5d1dc27..33552b2 100644 --- a/include/kernel/util.h +++ b/include/kernel/util.h @@ -18,9 +18,9 @@ extern size_t strlen(char const *str); extern void kvram_clear(void); extern void kvram_display(void); extern void kvram_scroll(int lines); -extern void kvram_reverse(int x, int y, int width, int height); -extern void kvram_print(int x, int y, char const *str); extern void kvram_ascii(int x, int y, char const c); +extern void kvram_reverse(int x, int y, int width, int height); +extern void kvram_clr_str_area(int x, int y, int width, int height); // Kernel printf-wrapper extern void printk(int x, int y, char const *str, ...); @@ -28,9 +28,21 @@ extern void printk(int x, int y, char const *str, ...); // Hardware specific function (do not use !) extern void t6k11_display(void *vram); -// Timer functions. +//--- +// Timer functions. +//--- +#define TIMER_NUMBER 3 +#define TIMER_UNUSED 0xff + +struct timer_cache_s +{ + void *callback; + volatile void *arg; + uint8_t status; +}; extern int timer_uninstall(int timer_ID); -extern int timer_install(void *callback, void *arg, uint32_t delay_ms, uint8_t mode); +extern int timer_install(void *callback, void *arg, uint32_t ticks, uint8_t mode); +extern int timer_start(int timer_ID); // Debug wait #define DBG_WAIT for(int i = 0 ; i < 3000000 ; i++) diff --git a/include/lib/display.h b/include/lib/display.h index ec71229..e316599 100644 --- a/include/lib/display.h +++ b/include/lib/display.h @@ -6,7 +6,8 @@ // Draw primtives extern void dclear(void); -extern void dprint(int x, int y, char const *str); +extern void dclr_str_area(int x, int y, int with, int height); +extern void dprint(int x, int y, char const *str, ...); extern void dascii(int x, int y, char const c); extern void dreverse(int x, int y, int width, int height); extern void dscroll(int line); diff --git a/include/lib/unistd.h b/include/lib/unistd.h index ba72c8f..5bc4c7c 100644 --- a/include/lib/unistd.h +++ b/include/lib/unistd.h @@ -14,6 +14,7 @@ #define WUNTRACED 1 #define WCONTINUED 2 extern pid_t waitpid(pid_t pid, int *wstatus, int options); +extern pid_t fexecve(const char *pathname); // File syscall #define O_DIRECT 0 diff --git a/include/user/builtin.h b/include/user/builtin.h index b5fce45..c8a7516 100644 --- a/include/user/builtin.h +++ b/include/user/builtin.h @@ -4,14 +4,6 @@ #include #include -#define VHEX_BUILTIN(bname) \ - static int bname(int argc, char **argv); \ - __attribute__((section(".builtin"))) \ - struct builtin_s _##bname = { \ - .name = #bname, \ - .entry = &bname \ - }; \ - static int bname(int argc, char **argv) // Define builtin struct. struct builtin_s @@ -20,5 +12,9 @@ struct builtin_s int (*entry)(int argc, char **argv); }; +// Builtin list +extern int builtin_proc(void); +extern int builtin_ram(void); + #endif /*__USER_BUILTIN_H__*/ diff --git a/src/kernel/bootstrap/start.c b/src/kernel/bootstrap/start.c index 88d034c..2787c9a 100644 --- a/src/kernel/bootstrap/start.c +++ b/src/kernel/bootstrap/start.c @@ -174,9 +174,9 @@ int start(void) if (vhex_process == NULL) { kvram_clear(); - kvram_print(0, 0, "Vhex fatal error !"); - kvram_print(0, 1, "First process error !"); - kvram_print(0, 2, "Wait manual reset..."); + printk(0, 0, "Vhex fatal error !"); + printk(0, 1, "First process error !"); + printk(0, 2, "Wait manual reset..."); kvram_display(); while (1) { __asm__ volatile ("sleep"); } } @@ -188,9 +188,9 @@ int start(void) { // Display message. kvram_clear(); - kvram_print(0, 0, "Vhex fatal error !"); - kvram_print(0, 1, "File \"VHEX/shell.elf\" not found !"); - kvram_print(0, 2, "Press [MENU key]..."); + printk(0, 0, "Vhex fatal error !"); + printk(0, 1, "File \"VHEX/shell.elf\" not found !"); + printk(0, 2, "Press [MENU key]..."); kvram_display(); // Restore Casio context. @@ -225,7 +225,7 @@ int start(void) // normally the kernel SHOULD / CAN not arrive here. kvram_clear(); - kvram_print(0, 0, "Kernel job fini !"); + printk(0, 0, "Kernel job fini !"); kvram_display(); while (1) { diff --git a/src/kernel/devices/tty/file_op/read.c b/src/kernel/devices/tty/file_op/read.c index dfec176..5ebbfd9 100644 --- a/src/kernel/devices/tty/file_op/read.c +++ b/src/kernel/devices/tty/file_op/read.c @@ -42,7 +42,8 @@ ssize_t tty_read(void *inode, void *buffer, size_t count) keyboard.saved.tty.cursor.y = tty.cursor.y; // Initialize timer for cursor. - timer_fd = timer_install(&cursor_callback, &keyboard, 500, 1); + // FIXME: find real ticks value !! + timer_fd = timer_install(&cursor_callback, &keyboard, 500 * 500 * 2, 1); if (timer_fd == -1) return (0); diff --git a/src/kernel/fs/gladfs/filesystem/mount.c b/src/kernel/fs/gladfs/filesystem/mount.c index d2ed87d..2f425bc 100644 --- a/src/kernel/fs/gladfs/filesystem/mount.c +++ b/src/kernel/fs/gladfs/filesystem/mount.c @@ -19,7 +19,7 @@ void *gladfs_mount(void) if (gladfs_superblock.root_inode == NULL) { kvram_clear(); - kvram_print(0, 0, "GladFS: ROOT inode alloc error !"); + printk(0, 0, "GladFS: ROOT inode alloc error !"); kvram_display(); DBG_WAIT; } diff --git a/src/kernel/fs/vfs/dentry/resolve.c b/src/kernel/fs/vfs/dentry/resolve.c index 33b3b21..afb8fe2 100644 --- a/src/kernel/fs/vfs/dentry/resolve.c +++ b/src/kernel/fs/vfs/dentry/resolve.c @@ -24,7 +24,7 @@ static int get_name(int *name_lenght, const char *path, char *name) return (0); } -//TODO add '..' handling. +//TODO: update ? struct dentry *vfs_dentry_resolve(const char *path, int mode) { extern struct process *process_current; @@ -114,7 +114,6 @@ struct dentry *vfs_dentry_resolve(const char *path, int mode) printk(0, 3, "name: %s$", name); kvram_display(); DBG_WAIT; - while (1); return (NULL); } } @@ -138,7 +137,7 @@ struct dentry *vfs_dentry_resolve(const char *path, int mode) // Try to find first child next = vfs_dentry_find_first_child(next); - if (next != NULL) + /*if (next != NULL) { // Debug ! kvram_clear(); @@ -148,7 +147,7 @@ struct dentry *vfs_dentry_resolve(const char *path, int mode) printk(0, 3, "name: %s$", name); kvram_display(); DBG_WAIT; - } + }*/ // Update name lenght to skip '/' char name_lenght = name_lenght + 1; diff --git a/src/kernel/fs/vfs/inode/mknod.c b/src/kernel/fs/vfs/inode/mknod.c index f3c13bf..b1c3a64 100644 --- a/src/kernel/fs/vfs/inode/mknod.c +++ b/src/kernel/fs/vfs/inode/mknod.c @@ -62,7 +62,7 @@ int vfs_mknod(const char *pathname, mode_t mode, dev_t dev) // Debug ! - kvram_clear(); + /*kvram_clear(); printk(0, 0, "New mknod device !"); printk(0, 1, "dentry: %p$", file); printk(0, 2, "inode: %p$", file->inode); @@ -70,7 +70,7 @@ int vfs_mknod(const char *pathname, mode_t mode, dev_t dev) printk(0, 4, "dev->file_op: %p$", &device->file_op); kvram_display(); DBG_WAIT; - DBG_WAIT; + DBG_WAIT;*/ // Set file operations file->dentry_op.file_op = &device->file_op; diff --git a/src/kernel/fs/vfs/superblock/mount.c b/src/kernel/fs/vfs/superblock/mount.c index a51ec1a..1c1c2c6 100644 --- a/src/kernel/fs/vfs/superblock/mount.c +++ b/src/kernel/fs/vfs/superblock/mount.c @@ -67,13 +67,13 @@ int vfs_mount(const char *source, const char *target, vfs_root_node->dentry_op.inode_op = &filesystem->inode_operations; // Debug ! - kvram_clear(); + /*kvram_clear(); printk(0, 0, "vfs_root_node = %p", vfs_root_node); printk(0, 1, "vfs_root_node = %s$", vfs_root_node->name); printk(0, 2, "vfs_root_node = %p", vfs_root_node->child); printk(0, 3, "vfs_root_node = %p", vfs_root_node->next); kvram_display(); - DBG_WAIT; + DBG_WAIT;*/ return (0); } diff --git a/src/kernel/hardware/tmu/constructor.c b/src/kernel/hardware/tmu/constructor.c deleted file mode 100644 index 7bab556..0000000 --- a/src/kernel/hardware/tmu/constructor.c +++ /dev/null @@ -1,16 +0,0 @@ -#include -#include - -// Internal timer "cache". -struct timer_cache_s timercache[TIMER_NUMBER]; - -__attribute__((constructor)) -void timer_constructor(void) -{ - for (int i = 0 ; i < TIMER_NUMBER ; i = i + 1) - { - timercache[i].status = TIMER_UNUSED; - timercache[i].callback = NULL; - timercache[i].arg = NULL; - } -} diff --git a/src/kernel/hardware/tmu/handler.c b/src/kernel/hardware/tmu/handler.c index e8126a1..3eafc74 100644 --- a/src/kernel/hardware/tmu/handler.c +++ b/src/kernel/hardware/tmu/handler.c @@ -1,9 +1,10 @@ #include -#include +#include void timer_handler(void) { extern struct timer_cache_s timercache[TIMER_NUMBER]; + static uint32_t counter = 0; uint32_t intevt; int timer_ID; @@ -11,10 +12,18 @@ void timer_handler(void) // @note: tricky way to get timer ID // TODO: find better way ! intevt = *(uint32_t*)0xff000028; - timer_ID = (intevt - 0x400) >> 9; + timer_ID = (intevt - 0x400) / 0x20; - // Stop timer flag and clear interrupt flags. - SH7305_TMU.TSTR.BYTE &= ~(1 << timer_ID); + /*if (intevt != 0x400) + { + kvram_clear(); + printk(0, 0, "Timer ID: %d\n", timer_ID); + printk(0, 1, "Interrupt: %#x\n", intevt); + printk(0, 2, "counter: %d\n", counter++); + kvram_display(); + }*/ + + // Clear interrupt flags. SH7305_TMU.TIMER[timer_ID].TCR.UNF = 0; // Execute callback if possible. @@ -24,6 +33,4 @@ void timer_handler(void) ((void (*)(volatile void *))timercache[timer_ID].callback)(timercache[timer_ID].arg); } - // Re-start timer. - SH7305_TMU.TSTR.BYTE |= 1 << timer_ID; } diff --git a/src/kernel/hardware/vbr/interrupt.c b/src/kernel/hardware/vbr/interrupt.c index 8f6b50e..2b3e119 100644 --- a/src/kernel/hardware/vbr/interrupt.c +++ b/src/kernel/hardware/vbr/interrupt.c @@ -4,7 +4,6 @@ extern void keysc_handler(void); extern void timer_handler(void); -__attribute__((section(".vhex.interrupt"), interrupt_handler)) void interrupt_handler(void) { uint32_t intevt = *(uint32_t*)0xff000028; diff --git a/src/kernel/hardware/vbr/interrupt_pre.s b/src/kernel/hardware/vbr/interrupt_pre.s new file mode 100644 index 0000000..835b7e3 --- /dev/null +++ b/src/kernel/hardware/vbr/interrupt_pre.s @@ -0,0 +1,52 @@ +.section ".vhex.interrupt", "awx", @progbits + +.global _interrupt_handler_pre +.type _interrupt_handler_pre, @function + +.extern _sched_timer_intevt +.extern _sched_handler +.extern _interrupt_handler + +_interrupt_handler_pre: + ! Due to PR register used to switch process + ! context, we SHOULD catch scheduler timer + ! interrupt before the interrupt handler because + ! we need to save / restore pr register before + ! context swtich. + mov.l .sched_timer_intevt, r0 ! get the precalculate scheduler timer event + mov.l .intevt_register, r1 ! get INTEVT register address + mov.l @r0, r0 ! get the scheduler event code + mov.l @r1, r1 ! get the interrupt event + cmp/eq r0, r1 ! if scheduler timer event == INTEVT... + bf general_interrupt ! ...if not, jump at + +scheduler_interrupt: + mov.l .scheduler_handler, r0 ! get scheduler handler address + jmp @r0 ! jump into scheduler handler + nop ! (db) nop + +general_interrupt: + ! Save critical regsiter. + stc.l spc, @-r15 ! save SPC register. + stc.l ssr, @-r15 ! save SSR register. + sts.l pr, @-r15 ! save pr register. + + ! Call interrupt handler + mov.l .interrupt_handler, r0 ! get interrupt handler address + jsr @r0 ! call interurpt handler + nop ! (db) nop + + ! Restore critical regsiter + lds.l @r15+, pr ! restore PR register. + ldc.l @r15+, ssr ! restore SSR regsiter. + ldc.l @r15+, spc ! restore SPC regsiter. + + ! Return + rte ! exit + nop ! (db) nop + +.align 4 +.sched_timer_intevt: .long _sched_timer_intevt +.scheduler_handler: .long _sched_handler +.interrupt_handler: .long _interrupt_handler +.intevt_register: .long 0xff000028 diff --git a/src/kernel/scheduler/context_switch.s b/src/kernel/scheduler/context_switch.s index 13e9422..0108300 100644 --- a/src/kernel/scheduler/context_switch.s +++ b/src/kernel/scheduler/context_switch.s @@ -44,10 +44,10 @@ save_current_context: ! @note: current process can be NULL ! tst r4, r4 ! if current task == NULL... bt context_load ! ...if yes, jump at - add #88, r4 ! get &process->context (end) + add #84, r4 ! get &process->context (end) ! save current context - sts.l pr, @-r4 ! get pr regsiter + !sts.l pr, @-r4 ! get pr regsiter stc.l spc, @-r4 ! get spc regsiter stc.l ssr, @-r4 ! get ssr regsiter sts.l mach, @-r4 ! get mach regsiter @@ -95,7 +95,7 @@ context_load: lds.l @r5+, mach ! set mach regsiter ldc.l @r5+, ssr ! set ssr regsiter ldc.l @r5+, spc ! set spc regsiter - lds.l @r5+, pr ! set pr regsiter + !lds.l @r5+, pr ! set pr regsiter ! Process switch diff --git a/src/kernel/scheduler/debug.c b/src/kernel/scheduler/debug.c new file mode 100644 index 0000000..2a18839 --- /dev/null +++ b/src/kernel/scheduler/debug.c @@ -0,0 +1,37 @@ +#include +#include +#include + +// Test +uint32_t counter = 0; + +void sched_debug(common_context_t *context_current, common_context_t *context_next) +{ + extern uint32_t sched_timer_id; + extern uint32_t sched_timer_address; + + uint32_t tstr = SH7305_TMU.TSTR.BYTE; + uint32_t tcr = *(uint16_t*)sched_timer_address; + uint32_t tcor = *(uint32_t*)(sched_timer_address - 4); + uint32_t tcnt = *(uint32_t*)(sched_timer_address - 8); + + + //SH7305_TMU.TSTR.STR2 = 0; + //SH7305_TMU.TSTR.STR1 = 0; + //SH7305_TMU.TSTR.STR0 = 0; + + //SH7305_TMU.TIMER[0].TCR.UNF = 0; + //SH7305_TMU.TIMER[1].TCR.UNF = 0; + //SH7305_TMU.TIMER[2].TCR.UNF = 0; + + kvram_clear(); + printk(0, 0, "Scheduler_schudele !"); + printk(0, 1, "context current = %p", context_current); + printk(0, 2, "context next = %p", context_next); + printk(0, 3, "counter = %#x", counter++); + printk(0, 4, "TSTR: %#x", tstr); + printk(0, 5, "TCOR: %#x", tcor); + printk(0, 6, "TCNT: %#x", tcnt); + printk(0, 7, "TCR: %#x", tcr); + kvram_display(); +} diff --git a/src/kernel/scheduler/handler.S b/src/kernel/scheduler/handler.S new file mode 100644 index 0000000..d0910c0 --- /dev/null +++ b/src/kernel/scheduler/handler.S @@ -0,0 +1,204 @@ +.text + +.global _sched_handler +.type _sched_handler, @function + +.extern _sched_timer_id +.extern _sched_timer_address +.extern _sched_schedule + +.align 2 +/* +** @note +** We can use only r0 - r7 register because +** we SHOULD not modify the current process context. +*/ +_sched_handler: + + +/* +** Stop scheduler timer and clear interrupt flags +*/ +stop_clear_sched_timer: + ! Clear scheduler timer interrupt + mov.l .sched_timer_address, r0 ! get precalculated scheduler timer address + mov.l .timer_unf_field, r1 ! get TIMER.TCR.UNF byte field + mov.l @r0, r0 ! get scheduler timer TCR register + mov.w @r0, r2 ! get scheduler timer TCR register + not r1, r1 ! get interrupt flags bit mask (to remove) + and r1, r2 ! clear timer interrupt flags + mov.w r2, @r0 ! update timer TCR + + ! Stop scheduler timer + mov.l .sched_timer_tstr_bit, r0 ! get precalculated scheduler timer ID + mov.l .timer_tstr_register, r1 ! get TMU0.TSTR base address + mov.l @r0, r0 ! get scheduler timer ID + mov.b @r1, r2 ! get TMU0.TSTR data + not r0, r0 ! get TSTR scheduler timer ID mask (to remove) + and r0, r2 ! stop scheduler timer + mov.b r2, @r1 ! update TMU0.TSTR + +#ifdef __SCHED_DEBUG__ + sts.l pr, @-r15 ! save pr register + mov #0, r4 ! save r4 register (current context) + mov #0, r5 ! save r5 register (next context) + mov.l .sched_debug, r0 ! get sched_debug() absraction + jsr @r0 ! call abstraction + nop ! (db) nop + lds.l @r15+, pr ! restore pr register + + bra restart_sched_timer + nop +#endif + + +/* +** Get current and next context +*/ +get_contexts: + ! prologue + mov.l r9, @-r15 ! save r9 register + mov.l r8, @-r15 ! save r8 register + sts.l pr, @-r15 ! save pr register + + ! Create to context_common_t **ptr + add #-4, r15 ! create first context pointer + mov r15, r8 ! save first context pointer + add #-4, r15 ! create second context pointer + mov r15, r9 ! save second context pointer + add #-4, r15 ! create context pointer + mov.l r15, @r8 ! save context pointer + add #-4, r15 ! create context pointer + mov.l r15, @r9 ! save context pointer + + ! call high level abstraction + mov r8, r4 ! send current contexts pointer + mov r9, r5 ! send next context pointer + mov.l .sched_schedule, r0 ! get sched_scheduler() abstraction address + jsr @r0 ! call sched_schedule() abstract + nop ! (db) nop + + ! Restore stack and register (epilogue) + mov.l @r8, r4 ! save current context + mov.l @r9, r5 ! save next context + add #16, r15 ! restore stack + lds.l @r15+, pr ! restore pr register + mov.l @r15+, r8 ! restore r8 register + mov.l @r15+, r9 ! restore r9 register + + ! Check context error + tst r0, r0 ! check if returned value == 0... + bt debug ! if yes, jump at + bra restart_sched_timer ! jump at + nop ! (db) nop + + +/* +** Debug part, used to debug the contexts +*/ +debug: +#ifdef __SCHED_DEBUG__ + sts.l pr, @-r15 ! save pr register + mov.l r4, @-r15 ! save r4 register (current context) + mov.l r5, @-r15 ! save r5 register (next context) + mov.l .sched_debug, r0 ! get sched_debug() absraction + jsr @r0 ! call abstraction + nop ! (db) nop + mov.l @r15+, r5 ! restore r5 register + mov.l @r15+, r4 ! restore r4 register + lds.l @r15+, pr ! restore pr register +#endif + + + +/* +** Context switch +*/ +save_current_context: + ! Check current process + ! @note: current process can be NULL ! + tst r4, r4 ! if current task == NULL... + bt next_context_load ! ...if yes, jump at + add #88, r4 ! get &process->context (end) + + ! save current context + sts.l pr, @-r4 ! get pr regsiter + stc.l spc, @-r4 ! get spc regsiter + stc.l ssr, @-r4 ! get ssr regsiter + sts.l mach, @-r4 ! get mach regsiter + sts.l macl, @-r4 ! get macl regsiter + stc.l gbr, @-r4 ! get gbr regsiter + mov.l r15, @-r4 ! get r15 register + mov.l r14, @-r4 ! get r14 regsiter + mov.l r13, @-r4 ! get r13 regsiter + mov.l r12, @-r4 ! get r12 regsiter + mov.l r11, @-r4 ! get r11 regsiter + mov.l r10, @-r4 ! get r10 regsiter + mov.l r9, @-r4 ! get r9 regsiter + mov.l r8, @-r4 ! get r8 regsiter + stc.l R7_BANK, @-r4 ! get "process" r7 regsiter + stc.l R6_BANK, @-r4 ! get "process" r6 regsiter + stc.l R5_BANK, @-r4 ! get "process" r5 regsiter + stc.l R4_BANK, @-r4 ! get "process" r4 regsiter + stc.l R3_BANK, @-r4 ! get "process" r3 regsiter + stc.l R2_BANK, @-r4 ! get "process" r2 regsiter + stc.l R1_BANK, @-r4 ! get "process" r1 regsiter + stc.l R0_BANK, @-r4 ! get "process" r0 regsiter + +next_context_load: + ! Load next process + ! @note: next process can not be NULL ! + ldc.l @r5+, R0_BANK ! set "process" r0 regsiter + ldc.l @r5+, R1_BANK ! set "process" r1 regsiter + ldc.l @r5+, R2_BANK ! set "process" r2 regsiter + ldc.l @r5+, R3_BANK ! set "process" r3 regsiter + ldc.l @r5+, R4_BANK ! set "process" r4 regsiter + ldc.l @r5+, R5_BANK ! set "process" r5 regsiter + ldc.l @r5+, R6_BANK ! set "process" r6 regsiter + ldc.l @r5+, R7_BANK ! set "process" r7 regsiter + mov.l @r5+, r8 ! set r8 regsiter + mov.l @r5+, r9 ! set r9 regsiter + mov.l @r5+, r10 ! set r10 regsiter + mov.l @r5+, r11 ! set r11 regsiter + mov.l @r5+, r12 ! set r12 regsiter + mov.l @r5+, r13 ! set r13 regsiter + mov.l @r5+, r14 ! set r14 regsiter + mov.l @r5+, r15 ! set r15 register + ldc.l @r5+, gbr ! set gbr regsiter + lds.l @r5+, macl ! set macl regsiter + lds.l @r5+, mach ! set mach regsiter + ldc.l @r5+, ssr ! set ssr regsiter + ldc.l @r5+, spc ! set spc regsiter + lds.l @r5+, pr ! set pr regsiter + + +/* +** Restart timer +*/ +restart_sched_timer: + mov.l .sched_timer_tstr_bit, r0 ! get precalculated scheduler timer ID + mov.l .timer_tstr_register, r1 ! get TMU0.TSTR base address + mov.l @r0, r0 ! get scheduler timer ID + mov.b @r1, r2 ! get TMU0.TSTR data + or r0, r2 ! start scheduler timer + mov.b r2, @r1 ! update TMU0.TSTR + + +/* +** Process switch +*/ +process_switch: + rte ! use RTE to switch process + nop ! (db) nop + + +.align 4 +.sched_timer_tstr_bit: .long _sched_timer_tstr_bit +.sched_timer_address: .long _sched_timer_address +.sched_schedule: .long _sched_schedule +.timer_tstr_register: .long 0xa4490004 +.timer_unf_field: .long 0x00000100 +#ifndef __SCHED_DEBUG__ +.sched_debug: .long _sched_debug +#endif +.end diff --git a/src/kernel/scheduler/process/alloc.c b/src/kernel/scheduler/process/alloc.c index ea57666..9de6c68 100644 --- a/src/kernel/scheduler/process/alloc.c +++ b/src/kernel/scheduler/process/alloc.c @@ -2,14 +2,16 @@ // This function SHOULD NOT be called // without atomic operation !! +// TODO: dynamic allocation ? pid_t process_alloc(struct process **process) { extern struct process_stack process_stack[PROCESS_MAX]; for (int i = 0 ; i < PROCESS_MAX ; i = i + 1) { - if (process_stack[i].status == PROC_IDLE) + if (process_stack[i].status == PROC_UNUSED) { + process_stack[i].status = PROC_USED; *process = &process_stack[i].process; return (i); } diff --git a/src/kernel/scheduler/process/get.c b/src/kernel/scheduler/process/get.c index 03f441e..9f8e5ae 100644 --- a/src/kernel/scheduler/process/get.c +++ b/src/kernel/scheduler/process/get.c @@ -1,6 +1,6 @@ #include -struct process *process_get(pid_t pid) +struct process *process_get_proc(pid_t pid) { extern struct process_stack process_stack[PROCESS_MAX]; @@ -11,3 +11,17 @@ struct process *process_get(pid_t pid) // Return process. return (&process_stack[pid].process); } + +pid_t process_get_pid(struct process *target) +{ + extern struct process_stack process_stack[PROCESS_MAX]; + int i; + + i = -1; + while (++i < PROCESS_MAX) + { + if (&process_stack[i].process == target) + return (i); + } + return (-1); +} diff --git a/src/kernel/scheduler/process/initialize.c b/src/kernel/scheduler/process/initialize.c index 96d26e0..f36fa8f 100644 --- a/src/kernel/scheduler/process/initialize.c +++ b/src/kernel/scheduler/process/initialize.c @@ -10,6 +10,6 @@ void process_constructor(void) // Set all process to idle state. for (int i = 0 ; i < PROCESS_MAX ; i = i + 1) { - process_stack[i].status = PROC_IDLE; + process_stack[i].status = PROC_UNUSED; } } diff --git a/src/kernel/scheduler/schedule.c b/src/kernel/scheduler/schedule.c index 5da4f2d..fa618bf 100644 --- a/src/kernel/scheduler/schedule.c +++ b/src/kernel/scheduler/schedule.c @@ -3,26 +3,20 @@ #include //TODO: assembly ! -void sched_schedule(void) +// @note: This part *SHOULD* be exeption safe ! +int sched_schedule(common_context_t **context_current, common_context_t **context_next) { extern struct sched_task *sched_task_current; extern struct sched_task *sched_task_queue; struct sched_task *task_current; struct sched_task *task_next; - common_context_t *context_current; - common_context_t *context_next; - // Start atomic operation - atomic_start(); - // Check current task + // TODO: check process status !! if (sched_task_current == NULL) { task_current = NULL; - task_next = (sched_task_queue != NULL) - ? sched_task_queue - : NULL; - + task_next = (sched_task_queue != NULL) ? sched_task_queue : NULL; } else { task_current = sched_task_current; task_next = (sched_task_current->next != NULL) @@ -32,39 +26,23 @@ void sched_schedule(void) // Check potantial error if (task_next == NULL || task_next == sched_task_current) - { - atomic_stop(); - return; - } - - //TODO: check process status !!! + return (-1); // Update internal scheduler task cursor sched_task_current = task_next; - // Get context - context_current = - (task_current != NULL) - ? &task_current->process->context - : NULL; - context_next = - (task_next != NULL) - ? &task_next->process->context - : NULL; + *context_current = (task_current != NULL) ? &task_current->process->context : NULL; + *context_next = &task_next->process->context; // DEBUG ! - kvram_clear(); + /*kvram_clear(); printk(0, 0, "Scheduler_schudele !"); printk(0, 1, "task current = %p", task_current); printk(0, 2, "task next = %p", task_next); - printk(0, 3, "context current = %p", context_current); - printk(0, 4, "context next = %p", context_next); + printk(0, 3, "context current = %p", *context_current); + printk(0, 4, "context next = %p", *context_next); kvram_display(); - DBG_WAIT; - printk(0, 5, "context switch !"); - kvram_display(); - - // Context switch - sched_context_switch(context_current, context_next); + DBG_WAIT;*/ + return (0); } diff --git a/src/kernel/scheduler/start.c b/src/kernel/scheduler/start.c index b5171b9..c4d2be0 100644 --- a/src/kernel/scheduler/start.c +++ b/src/kernel/scheduler/start.c @@ -1,12 +1,114 @@ #include +#include +#include +#include + +// Internal data used by the scheduler handler +uint32_t sched_timer_id = 0; +uint32_t sched_timer_address = 0; +uint32_t sched_timer_intevt = 0; +uint32_t sched_timer_tstr_bit = 0; + +// Internal private function +//void sched_handler(void); + +//FIXME: remove me and wrap timer interrupt when occur !! +static void scheduler_timer_callback(void) +{ + common_context_t *context_current; + common_context_t *context_next; + + //TODO: quantum handling !! + //TODO: scheduler block / unblock options !! + //FIXME: Get SPC, SSR, ... !! + + // Get current context and + if (sched_schedule(&context_current, &context_next) != 0) + return; + + // Debug + //kvram_clear(); + //printk(0, 0, "Scheduler_schudele !"); + //printk(0, 1, "context current = %p", context_current); + //printk(0, 2, "context next = %p", context_next); + //kvram_display(); + //printk(0, 3, "context switch !"); + //kvram_display(); + //DBG_WAIT; + + // Context switch + sched_context_switch(context_current, context_next); +} void sched_start(void) { extern struct sched_task *sched_task_queue; extern struct process *process_current; + uint32_t fll_freq; + uint32_t pll_freq; + uint32_t cpu_freq; + uint32_t bus_freq; + uint32_t per_freq; - //TODO: get CPU frequency ! - //TODO: setup TMU0 interrupt ! + + // Calculate FLL frequency (Khz) + // @note: RCLK = 32 768 Hz + fll_freq = SH7305_CPG.FLLFRQ.FLF * 32768; // Hz + fll_freq = fll_freq / (1 << SH7305_CPG.FLLFRQ.SELXM); // Check FLL output division + + // Calculate PLL frequency (Khz) + pll_freq = fll_freq * (SH7305_CPG.FRQCRA.STC + 1); + + // Calculate CPU clock frequency ! + cpu_freq = pll_freq / (1 << (SH7305_CPG.FRQCRA.IFC + 1)); + + // Calculate BUS clock frequency ! + bus_freq = pll_freq / (1 << (SH7305_CPG.FRQCRA.BFC + 1)); + + // Calculate Peripheral clock frequency ! + per_freq = pll_freq / (1 << (SH7305_CPG.FRQCRA.PFC + 1)); + + + // Debug + kvram_clear(); + printk(0, 0, + "FLL freq: %d.%d Mhz\n" + "PLL freq: %d.%d Mhz\n" + "CPU freq: %d.%d Mhz\n" + "BUS freq: %d.%d Mhz\n" + "Per freq: %d.%d Mhz", + fll_freq / 1000000, (((fll_freq - ((fll_freq / 1000000)) * 1000000)) + 999) / 1000, + pll_freq / 1000000, (((pll_freq - ((pll_freq / 1000000)) * 1000000)) + 999) / 1000, + cpu_freq / 1000000, (((cpu_freq - ((cpu_freq / 1000000)) * 1000000)) + 999) / 1000, + bus_freq / 1000000, (((bus_freq - ((bus_freq / 1000000)) * 1000000)) + 999) / 1000, + per_freq / 1000000, (((per_freq - ((per_freq / 1000000)) * 1000000)) + 999) / 1000 + ); + kvram_display(); + DBG_WAIT; + + // Register first process ! process_current = sched_task_queue->process; - sched_schedule(); + + // Setup TMU0 (scheduler) interrupt ! + // @note: I use Po/4 on TMU prescaler + // TODO: generate quantum and quantum counter for preemption ! + uint32_t ticks = (per_freq / 4) / 16; + //sched_timer_id = timer_install(scheduler_timer_callback, NULL, ticks, 0); + sched_timer_id = timer_install(NULL, NULL, ticks, 0); + sched_timer_address = (uint32_t)&SH7305_TMU.TIMER[sched_timer_id].TCR; + sched_timer_intevt = 0x400 + (0x20 * sched_timer_id); + sched_timer_tstr_bit = 1 << sched_timer_id; + + // Debug + kvram_clear(); + printk(0, 0, "timer ID: %d", sched_timer_id); + printk(0, 1, "timer addr: %#x", sched_timer_address); + printk(0, 2, "timer event: %#x", sched_timer_intevt); + printk(0, 3, "timer TSTR: %#x", sched_timer_tstr_bit); + kvram_display(); + DBG_WAIT; + + + // Start scheduler timer + timer_start(sched_timer_id); } diff --git a/src/kernel/scheduler/syscall/sys_exit.c b/src/kernel/scheduler/syscall/sys_exit.c new file mode 100644 index 0000000..affe2a5 --- /dev/null +++ b/src/kernel/scheduler/syscall/sys_exit.c @@ -0,0 +1,11 @@ +#include +#include + +void sys_exit(int status) +{ + kvram_clear(); + printk(0, 0, "PROCESS EXIT SYSCALL !!!!"); + printk(0, 0, "Wait manual reset..."); + kvram_display(); + while (1); +} diff --git a/src/kernel/scheduler/syscall/sys_fexecve.c b/src/kernel/scheduler/syscall/sys_fexecve.c new file mode 100644 index 0000000..e79095a --- /dev/null +++ b/src/kernel/scheduler/syscall/sys_fexecve.c @@ -0,0 +1,77 @@ +#include +#include +#include +#include +#include + +pid_t sys_fexecve(const char *pathname) +{ + struct process *proc; + pid_t child_pid; + FILE *bin; + int error; + + // Start atomic operation + atomic_start(); + + // Try create new process + proc = process_create(pathname); + if (proc == NULL) + { + kvram_clear(); + printk(0, 0, "sys_fexecve: alloc error !"); + kvram_display(); + DBG_WAIT; + atomic_stop(); + return (-1); + } + + // Try to load binary into physical memory + proc->context.spc = (uint32_t)loader(pathname, proc); + if (proc->context.spc == 0x00000000) + { + kvram_clear(); + printk(0, 0, "sys_fexecve: loader error !"); + kvram_display(); + DBG_WAIT; + process_free(proc); + atomic_stop(); + return (-1); + } + + // Debug + kvram_clear(); + printk(0, 0, "New proc loaded !"); + kvram_display(); + DBG_WAIT; + + // Add new process into task queue + error = sched_add_task(proc); + if (error != 0) + { + kvram_clear(); + printk(0, 0, "sys_fexecve: scheduler error !"); + kvram_display(); + DBG_WAIT; + process_free(proc); + atomic_stop(); + return (-1); + } + + // Debug + printk(0, 1, "New proc sched added !"); + kvram_display(); + DBG_WAIT; + + // Get child process PID + child_pid = process_get_pid(proc); + + // Debug + printk(0, 2, "New proc PID = %#x !", child_pid); + kvram_display(); + DBG_WAIT; + + // Stop atomic operations + atomic_stop(); + return (child_pid); +} diff --git a/src/kernel/scheduler/syscall/sys_fork.c b/src/kernel/scheduler/syscall/sys_fork.c index 16ee9a3..16f9167 100644 --- a/src/kernel/scheduler/syscall/sys_fork.c +++ b/src/kernel/scheduler/syscall/sys_fork.c @@ -2,20 +2,41 @@ pid_t sys_fork(void) { - extern process_t *process_current; - process_t **process_new; - pid_t process_pid; + extern struct process *process_current; + struct process *process_new; + pid_t process_new_pid; + + // Check error + if (process_current == NULL) + return (-1); // Get the new process slot. - process_new = &process_current->child; - while (*process_new != NULL) - process_new = &(*process_new)->next; - - // Try to find new sheduler place. - process_pid = process_alloc(&(*process_new)); - if (*process_new == NULL) + new_pid = process_alloc(&process_new); + if (new_pid != 0) return (-1); - - // Initialize context. + + // Try to create user stack + process_new->memory.stack.size.user = process_current->; + process_new->memory.stack.user = (uint32_t)pm_alloc(process_new->memory.stack.size.user); + if (process_new->memory.stack.user == 0x00000000) + { + process_free(process_new); + return (-1); + } + + // Try to create kernel stack + process_new->memory.stack.size.kernel = process_current->memory.stack.size.kernel; + process_new->memory.stack.kernel = (uint32_t)pm_alloc(process_new->memory.stack.size.kernel); + if (process_new->memory.stack.kernel == 0x00000000) + { + pm_free(process_new->memory.stack.user); + process_free(process_new); + return (-1); + } + + + //TODO: dump stack data + //TODO: dump code data + //TODO: Initialize context. return (-1); }*/ diff --git a/src/kernel/syscall/handler.c b/src/kernel/syscall/handler.c index c5b7261..19651e5 100644 --- a/src/kernel/syscall/handler.c +++ b/src/kernel/syscall/handler.c @@ -12,35 +12,36 @@ static void sys_test(uint32_t a, uint32_t b, uint32_t c, uint32_t d) DBG_WAIT; } -static const void *sys_handler[15] = { +static const void *sys_handler[16] = { // Kernel Test - sys_test, //restart + sys_test, // test // Process - NULL, //exit - sys_waitpid, //waitpid - NULL, //exec + sys_exit, // exit + sys_fexecve, // fexecve + sys_waitpid, // waitpid // VFS - sys_read, //read - sys_write, //write - sys_open, //open - sys_close, //close - sys_lseek, //lseek + sys_read, // read + sys_write, // write + sys_open, // open + sys_close, // close + sys_lseek, // lseek // Display - kvram_display, //kvram_display - kvram_clear, //kvram_clear - kvram_print, //kvram_print - kvram_ascii, //kvram_ascii - kvram_reverse, //kvram_reverse - kvram_scroll //kvram_scroll + kvram_display, // kvram_display + kvram_clear, // kvram_clear + printk, // printk + kvram_ascii, // kvram_ascii + kvram_reverse, // kvram_reverse + kvram_scroll, // kvram_scroll + kvram_clr_str_area // kvram_clr_str_area }; void *sys_get_handler(int sysno) { // Check sysno validity - if (sysno < 0 || sysno >= 14) + if (sysno < 0 || sysno >= 16) return (0); // DEBUG diff --git a/src/kernel/syscall/syscall_pre.s b/src/kernel/syscall/syscall_pre.s index 5c04542..af4dfab 100644 --- a/src/kernel/syscall/syscall_pre.s +++ b/src/kernel/syscall/syscall_pre.s @@ -31,6 +31,7 @@ _syscall_pre: ! Switch register bank and allow interrupt ! @note: user context has been saved ! during the `exception_handler_pre` + ! TODO: do not allow interrupt ? mov.l .sr_mask, r1 ! get SR mask for BL and IMASK and r1, r0 ! set SR.BL = 0, SR.RB = 0 and SR.IMASK = 0b0000 ldc r0, sr ! update SR regsiter diff --git a/src/kernel/util/kvram.c b/src/kernel/util/kvram.c index f5db090..30b4c3a 100644 --- a/src/kernel/util/kvram.c +++ b/src/kernel/util/kvram.c @@ -133,42 +133,49 @@ void kvram_reverse(int x, int y, int width, int height) atomic_stop(); } -/* kvram_print() - Print string on Video RAM */ -void kvram_print(int x, int y, char const *str) +/* kvram_clr_str_area() - Clear area based on kernel font size on Video RAM */ +//FIXME: secure +void kvram_clr_str_area(int x, int y, int width, int height) { - int default_pos_x; - int starting_x; - int i; + uint32_t vram_offset_y; + int cur_x; + int cur_y; // Initialize part - i = -1; - starting_x = x; x = x * (KERNEL_FONT_REAL_WIDTH + 1); y = y * (KERNEL_FONT_REAL_HEIGHT + 1); - default_pos_x = x; + width = width * (KERNEL_FONT_REAL_WIDTH + 1); + height = height * (KERNEL_FONT_REAL_HEIGHT + 1); - // Walk into string and display character by character - while (str[++i] != '\0') + // Get VRAM offset + vram_offset_y = y << 2; + + //DEbug + /*kvram_clear(); + printk(0, 0, "kvram_clr_str_area debug !"); + printk(0, 1, "x = %d", x); + printk(0, 2, "y = %d", y); + printk(0, 3, "width = %d", width); + printk(0, 4, "height = %d", height); + kvram_display(); + DBG_WAIT;*/ + + // Clear area, pixel per pixel x____x + // TODO: update me !!!! + cur_y = -1; + while (++cur_y < height) { - // New line - if (str[i] == '\n') + cur_x = -1; + while (++cur_x < width) { - y = y + KERNEL_FONT_REAL_HEIGHT + 1; - x = default_pos_x; - continue; - } - // Horizontal tab - if (str[i] == '\t') - { - x = x / (KERNEL_FONT_REAL_WIDTH + 1); - x = (x + (4 - ((x - starting_x) & 3))) * (KERNEL_FONT_REAL_WIDTH + 1); - continue; + vram[((x + cur_x) >> 5) + vram_offset_y] &= + ~(0x80000000 >> ((x + cur_x) & 31)); } - // Default, display character - font_draw(x, y, str[i]); - x = x + KERNEL_FONT_REAL_WIDTH + 1; + // update internal counter + vram_offset_y = vram_offset_y + 4; } + } /* kvram_ascii() - Draw ASCII character into Video RAM */ diff --git a/src/kernel/util/timer.c b/src/kernel/util/timer.c index 4cb127f..15f0682 100644 --- a/src/kernel/util/timer.c +++ b/src/kernel/util/timer.c @@ -1,10 +1,39 @@ #include #include -#include #include -//TODO: update ! -int timer_install(void *callback, void *arg, uint32_t delay_ms, uint8_t mode) +// Internal timer "cache". +struct timer_cache_s timercache[TIMER_NUMBER]; + +__attribute__((constructor)) +void timer_constructor(void) +{ + // Initialise internal cache + for (int i = 0 ; i < TIMER_NUMBER ; i = i + 1) + { + timercache[i].status = TIMER_UNUSED; + timercache[i].callback = NULL; + timercache[i].arg = NULL; + } + + // Configure TMU + SH7305_TMU.TSTR.STR0 = 0; // Stop timer 0 + SH7305_TMU.TSTR.STR1 = 0; // Stop timer 1 + SH7305_TMU.TSTR.STR2 = 0; // Stop timer 2 + + // Configure TMU timers + for (int i = 0 ; i < 3 ; ++i) + { + SH7305_TMU.TIMER[i].TCOR = 0xffffffff; // Reset timer constant register + SH7305_TMU.TIMER[i].TCNT = 0xffffffff; // Reset timer counter + SH7305_TMU.TIMER[i].TCR.UNF = 0; // Clear interrupt flags + SH7305_TMU.TIMER[i].TCR.UNIE = 0; // Disable timerinterrupt + SH7305_TMU.TIMER[i].TCR.CKREG = 0b00; // Count on rising edge + SH7305_TMU.TIMER[i].TCR.TPSC = 0b000; // Select P/4 prescaler + } +} + +int timer_install(void *callback, void *arg, uint32_t ticks, uint8_t mode) { extern struct timer_cache_s timercache[TIMER_NUMBER]; int timer_ID; @@ -20,6 +49,12 @@ int timer_install(void *callback, void *arg, uint32_t delay_ms, uint8_t mode) if (timer_ID >= TIMER_NUMBER) return (-1); + // Debug !! + /*kvram_clear(); + printk(0, 0, "Timer find: %d\n", timer_ID); + printk(0, 1, "TMU = %p\n", &SH7305_TMU.TIMER[timer_ID]); + kvram_display(); + DBG_WAIT;*/ // Initialise internal timer data. timercache[timer_ID].callback = callback; @@ -29,12 +64,11 @@ int timer_install(void *callback, void *arg, uint32_t delay_ms, uint8_t mode) // Initialise hardware module. SH7305_TMU.TSTR.BYTE &= ~(1 << timer_ID); // Stop timer. - // Convert delay in millisecond into timer tick. - // TODO !! - SH7305_TMU.TIMER[timer_ID].TCOR = delay_ms * 2000; - SH7305_TMU.TIMER[timer_ID].TCNT = delay_ms * 2000; - SH7305_TMU.TIMER[timer_ID].TCR.TPSC = 0b000; // TODO use appropriate divisor ! + // Setup Timer + SH7305_TMU.TIMER[timer_ID].TCOR = ticks; + SH7305_TMU.TIMER[timer_ID].TCNT = ticks; + // Configure timer SH7305_TMU.TIMER[timer_ID].TCR.UNF = 0; // Clear interrupt flag. SH7305_TMU.TIMER[timer_ID].TCR.UNIE = 1; // Enable interrupt. @@ -48,7 +82,6 @@ int timer_install(void *callback, void *arg, uint32_t delay_ms, uint8_t mode) return (timer_ID); } -//TODO: update ! int timer_uninstall(int timer_ID) { extern struct timer_cache_s timercache[TIMER_NUMBER]; @@ -71,6 +104,27 @@ int timer_uninstall(int timer_ID) // Free'd timer cache. timercache[timer_ID].status = TIMER_UNUSED; + timercache[timer_ID].callback = NULL; + timercache[timer_ID].arg = NULL; + + // Stop atomic operation and return. + atomic_stop(); + return (0); +} + +int timer_start(int timer_ID) +{ + extern struct timer_cache_s timercache[TIMER_NUMBER]; + + // Check bad ID + if (timer_ID < 0 || timer_ID >= TIMER_NUMBER) + return (-1); + + // Start Atomic operation. + atomic_start(); + + // Start hardware timer. + SH7305_TMU.TSTR.BYTE |= 1 << timer_ID; // Stop atomic operation and return. atomic_stop(); diff --git a/src/lib/display/dclr_str_area.S b/src/lib/display/dclr_str_area.S new file mode 100644 index 0000000..b62c747 --- /dev/null +++ b/src/lib/display/dclr_str_area.S @@ -0,0 +1,12 @@ +.text +.global _dclr_str_area +.type _dclr_str_area, @function + +#include "kernel/unistd_32.h" + +.align 2 +_dclr_str_area: + trapa #__NR_kvram_clr_str_area + rts + nop +.end diff --git a/src/lib/unistd/fexecve.S b/src/lib/unistd/fexecve.S new file mode 100644 index 0000000..e70296d --- /dev/null +++ b/src/lib/unistd/fexecve.S @@ -0,0 +1,12 @@ +.text +.global _fexecve +.type _fexecve, @function + +#include "kernel/unistd_32.h" + +.align 2 +_fexecve: + trapa #__NR_fexecve + rts + nop +.end diff --git a/src/user/Makefile b/src/user/shell/Makefile similarity index 77% rename from src/user/Makefile rename to src/user/shell/Makefile index f0dd72b..6a4fdf8 100644 --- a/src/user/Makefile +++ b/src/user/shell/Makefile @@ -3,16 +3,16 @@ ## Project: Vhex - On-calc debugger ## Author: yann.magnin@epitech.eu ## --- -include ../../global.mk +include ../../../global.mk ##--- ## Static variables ##-- -HEADER := -I../../include -I../../include/user -LIBS := -L../lib/ -l_unistd -l_stdio -l_string -l_display -BUILD := ../../build/user -DEBUG := ../../debug -OUTPUT := ../../output +HEADER := -I../../../include -I../../../include/user +LIBS := -L../../lib/ -l_unistd -l_stdio -l_string -l_display +BUILD := ../../../build/user/shell +DEBUG := ../../../debug +OUTPUT := ../../../output NAME := shell EXEC := $(OUTPUT)/$(NAME).elf @@ -26,7 +26,7 @@ MEMORY_MAP := $(DEBUG)/$(NAME).map ## Automated variables ##--- SRC := -DIRECTORY := $(shell find shell -not -path "*/\.*" -type d) +DIRECTORY := $(shell find . -not -path "*/\.*" -type d) # Get all source files $(foreach path,$(DIRECTORY),$(eval \ SRC += $(wildcard $(path)/*.c) \ @@ -34,7 +34,7 @@ $(foreach path,$(DIRECTORY),$(eval \ $(wildcard $(path)/*.s) \ )) # Geneate all object files -OBJ := $(patsubst %,$(BUILD)/%.o,$(subst /,_,$(subst src/,,$(basename $(SRC))))) +OBJ := $(patsubst ._%,$(BUILD)/%.o,$(subst /,_,$(subst src/,,$(basename $(SRC))))) @@ -75,7 +75,7 @@ sec: ## Automated rules ##--- define rule-src -$(patsubst %,$(BUILD)/%.o,$(subst /,_,$(subst src/,,$(basename $1)))): $1 +$(patsubst ._%,$(BUILD)/%.o,$(subst /,_,$(subst src/,,$(basename $1)))): $1 @ printf "compiling $(white)$$<$(nocolor)..." @ $(CC) -fPIC $(CFLAGS) -o $$@ -c $$< $(HEADER) -lgcc @ printf "$(green)[ok]$(nocolor)\n" diff --git a/src/user/shell/builtin/proc.c b/src/user/shell/builtin/proc.c new file mode 100644 index 0000000..6f48ac4 --- /dev/null +++ b/src/user/shell/builtin/proc.c @@ -0,0 +1,43 @@ +#include +#include +#include + +int builtin_proc(void) +{ + pid_t child; + + // Debug + dclear(); + dprint(0, 0, "Proc builtin !"); + dupdate(); + for (int i = 0 ; i < 3000000 ; i++); + + // Try to create first child + /*child = fork(); + if (child == -1) + { + dprint(0, 1, "fork() fail !"); + dupdate(); + for (int i = 0 ; i < 3000000 ; i++); + return (0); + } + + // Check parent + if (child_pid != 0) + { + int counter = 0; + while (1) + { + dprint(0, 1, "parent: %d", counter++); + for (int i = 0 ; i < 3000000 ; i++); + } + } else { + int counter = 0; + while (1) + { + dprint(0, 2, "child: %d", counter++); + for (int i = 0 ; i < 9000000 ; i++); + } + }*/ + return (0); +} diff --git a/src/user/shell.ld b/src/user/shell/shell.ld similarity index 89% rename from src/user/shell.ld rename to src/user/shell/shell.ld index a605e6a..7729fdd 100644 --- a/src/user/shell.ld +++ b/src/user/shell/shell.ld @@ -27,11 +27,6 @@ SECTIONS .rodata : { *(.rodata); *(.rodata.*); - - /* Builtin */ - _bbuiltin_section = ALIGN(4) ; - *(.builtin); - _ebuiltin_section = . ; } .data ALIGN(4) : { diff --git a/src/user/shell/util/check_builtin.c b/src/user/shell/util/check_builtin.c index a5b51b5..b3cf2b9 100644 --- a/src/user/shell/util/check_builtin.c +++ b/src/user/shell/util/check_builtin.c @@ -1,48 +1,88 @@ #include "util.h" #include "builtin.h" #include +#include +#include + +// Internal builtin list +// FIXME: due to PIE binary format, we can not +// FIXME: use address of builtin_proc !! +/*struct builtin_s list[1] = { + { + .name = "proc", + .entry = (void*)&builtin_proc + }, + //{ + // .name = "ram", + // .entry = (void *)&builtin_ram + //} +};*/ + //TODO: use agc, argv. int check_builtin(char *cmd) { - extern uint32_t bbuiltin_section; - extern uint32_t ebuiltin_section; - struct builtin_s *list; - int wstatus; - //pid_t pid; - int i; - i = -1; - list = (void*)&bbuiltin_section; - while ((uint32_t)&list[++i] < (uint32_t)&ebuiltin_section) + // Process test + dclear(); + dprint(0, 0, "Process Load Test !"); + + // Load process test + pid_t pid = fexecve("/mnt/smemfs/VHEX/test.elf"); + if (pid < 0) + { + dprint(0, 1, "Process error !"); + dupdate(); + for(int i = 0 ; i < 3000000 ; ++i); + return (-1); + } + + int counter = 0; + dclear(); + dprint(0, 0, "Process Test !");; + while (1) + { + dclr_str_area(0, 1, 20, 1); + dprint(0, 1, "P process: %d", counter); + dupdate(); + counter = counter + 1; + for (int i = 0 ; i < 30000 ; ++i); + } + + //int wstatus; + //pid_t pid; + //int i; + + // Try to find builtin +/* for (int i = 0 ; i < 1 ; i++) { if (strcmp(list[i].name, cmd) != 0) continue; - + // Execute builtin list[i].entry(0, NULL); return (0); - } + }*/ return (-1); - // Create subprocess - //pid = fork(); - //if (pid < 0) - // return (1); - - // If we are the child execute - // the builtins. - //if (pid == 0) -// //{ -// dclear(); -// dprint(0, 0, "Child process !!"); -// dprint(0, 1, "PID = %d", getpid()); -// dprint(0, 2, "PPID = %d", getppid()); -// dupdate(); + // Create subprocess + //pid = fork(); + //if (pid < 0) + // return (1); + + // If we are the child execute + // the builtins. + //if (pid == 0) + // //{ + // dclear(); + // dprint(0, 0, "Child process !!"); + // dprint(0, 1, "PID = %d", getpid()); + // dprint(0, 2, "PPID = %d", getppid()); + // dupdate(); // } else { // waitpid(pid, &wstatus, WCONTINUED); - //TODO: signal handling. + //TODO: signal handling. // } -// } -// return (1); -} + // } + // return (1); + } diff --git a/src/user/test/Makefile b/src/user/test/Makefile new file mode 100644 index 0000000..9391e6f --- /dev/null +++ b/src/user/test/Makefile @@ -0,0 +1,106 @@ +#!/usr/bin/make -f +## --- +## Project: Vhex - On-calc debugger +## Author: yann.magnin@epitech.eu +## --- +include ../../../global.mk + +##--- +## Static variables +##-- +HEADER := -I../../../include -I../../../include/user +LIBS := -L../../lib/ -l_unistd -l_stdio -l_string -l_display +BUILD := ../../../build/user/test +DEBUG := ../../../debug +OUTPUT := ../../../output + +NAME := test +EXEC := $(OUTPUT)/$(NAME).elf +LDFLAG := -T $(NAME).ld +MEMORY_MAP := $(DEBUG)/$(NAME).map + + + + +##--- +## Automated variables +##--- +SRC := +DIRECTORY := $(shell find . -not -path "*/\.*" -type d) +# Get all source files +$(foreach path,$(DIRECTORY),$(eval \ + SRC += $(wildcard $(path)/*.c) \ + $(wildcard $(path)/*.S) \ + $(wildcard $(path)/*.s) \ +)) +# Geneate all object files +OBJ := $(patsubst ._%,$(BUILD)/%.o,$(subst /,_,$(subst src/,,$(basename $(SRC))))) + + + + +##--- +## General rules +##--- +all: | $(BUILD) $(DEBUG) $(EXEC) + +$(EXEC): $(OBJ) + $(CC) -fPIC -Wl,-M $(LDFLAG) $(CFLAGS) -o $(DEBUG)/$(NAME).elf.big $(OBJ) $(HEADER) $(LIBS) -lgcc > $(MEMORY_MAP) + $(OBJCOPY) -S $(DEBUG)/$(NAME).elf.big $@ + rm -f $(DEBUG)/$(NAME).elf.big + +$(BUILD) $(DEBUG): + @ printf "Create $(blue)$@$(nocolor) directory\n" + @ mkdir -p $@ + +install: $(EXEC) + sudo p7 send --force -d VHEX $^ + +check: + @ echo 'src: $(SRC)' + @ echo 'obj: $(OBJ)' + @ echo 'directory: $(DIRECTORY)' + +asm: + @ $(OBJDUMP) -D $(EXEC) | less + +map: + @ cat $(MEMORY_MAP) | less + +sec: + @ $(OBJDUMP) -h $(EXEC) + + +##--- +## Automated rules +##--- +define rule-src +$(patsubst ._%,$(BUILD)/%.o,$(subst /,_,$(subst src/,,$(basename $1)))): $1 + @ printf "compiling $(white)$$<$(nocolor)..." + @ $(CC) -fPIC $(CFLAGS) -o $$@ -c $$< $(HEADER) -lgcc + @ printf "$(green)[ok]$(nocolor)\n" +endef + +$(foreach source,$(SRC),$(eval \ + $(call rule-src,$(source))) \ +) + + + + +##--- +## Cleaning rules +##--- +clean: + rm -rf $(BUILD) + rm -rf $(DEBUG) + +fclean: clean + rm -f $(EXEC) + +re: fclean all + + + + +.PHONY: re fclean clean all install diff --git a/src/user/test/test.c b/src/user/test/test.c index b844fc8..7ba5a73 100644 --- a/src/user/test/test.c +++ b/src/user/test/test.c @@ -1,8 +1,19 @@ -/*#include +#include -void test(void) +int main(void) { - uint8_t *vram; + uint32_t counter = 0; + while (1) + { + // Display data + dclr_str_area(0, 2, 20, 1); + dprint(0, 2, "C process: %d", counter); + dupdate(); - vram = casio_Bdisp_GetVRAM(); -}*/ + // Update counter and "wait" + counter = counter + 1; + if (counter >= 100) + counter = 0; + for (int i = 0 ; i < 300000 ; ++i); + } +} diff --git a/src/user/test/test.ld b/src/user/test/test.ld new file mode 100644 index 0000000..7729fdd --- /dev/null +++ b/src/user/test/test.ld @@ -0,0 +1,65 @@ +OUTPUT_ARCH(sh3) +OUTPUT_FORMAT(elf32-sh) +ENTRY(_main) + +/* +** Linker script for user executables. +*/ +MEMORY +{ + /* virtual memory, read-write segment */ + userram (WX) : o = 0x00000000, l = 256k +} + +PHDRS +{ + text PT_LOAD ; + data PT_LOAD ; +} + +SECTIONS +{ + .text : { + *(.text); + *(.text.*); + } : text + + .rodata : { + *(.rodata); + *(.rodata.*); + } + + .data ALIGN(4) : { + *(.plt); + *(.data); + *(.data.*); + + /* bss section included to avoid missaligned segment */ + *(.bss); + *(.bss.*); + *(COMMON); + } : data + + + .relocgot : { + BRELOC_GOT = . ; + *(.got.plt) + *(.got) + ERELOC_GOT = . ; + } + + /* unwanted section */ + /DISCARD/ : { + *(.debug_info) + *(.debug_abbrev) + *(.debug_loc) + *(.debug_aranges) + *(.debug_ranges) + *(.debug_line) + *(.debug_str) + *(.jcr) + *(.eh_frame_hdr) + *(.eh_frame) + *(.comment) + } +} diff --git a/src/user/test/test_asm.s b/src/user/test/test_asm.s index c2e79e9..ee21ea3 100644 --- a/src/user/test/test_asm.s +++ b/src/user/test/test_asm.s @@ -1,4 +1,4 @@ -.global _test +/*.global _test .type _test, @function .align 2 @@ -20,4 +20,4 @@ _test: .align 4 .syscall_entry: .long 0xa0010070 .syscall_vram: .long 0x00000135 -.end +.end*/