From 145e75088c81a774928c594e8724568790d2eca6 Mon Sep 17 00:00:00 2001 From: Yann MAGNIN Date: Sun, 29 Dec 2019 16:39:30 +0100 Subject: [PATCH] Add RAM memory managment --- include/kernel/context.h | 10 +++ include/kernel/memory.h | 40 +++++++++++ include/kernel/process.h | 49 ++++++++++++++ include/kernel/syscall.h | 20 ++++++ include/kernel/types.h | 2 + include/kernel/unistd_32.h | 13 ++++ include/lib/unistd.h | 19 ++++++ src/kernel/bootstrap/kernel_switch.s | 56 ++++++++++++++++ src/kernel/bootstrap/start.c | 29 ++++---- src/kernel/hardware/vbr/exception.c | 1 - src/kernel/hardware/vbr/exception_pre.s | 52 +++++++++++++++ src/kernel/memory/initialize.c | 59 ++++++++++++++++ src/kernel/memory/pm_alloc.c | 85 ++++++++++++++++++++++++ src/kernel/memory/pm_free.c | 53 +++++++++++++++ src/kernel/process/alloc.c | 19 ++++++ src/kernel/process/constructor.c | 19 ++++++ src/kernel/process/create.c | 36 ++++++++++ src/kernel/process/get.c | 13 ++++ src/kernel/process/switch.c | 27 ++++++++ src/kernel/process/syscall/sys_fork.c | 21 ++++++ src/kernel/process/syscall/sys_waitpid.c | 6 ++ src/kernel/syscall/handler.c | 19 ++++++ src/kernel/syscall/syscall_pre.s | 57 ++++++++++++++++ src/lib/unistd/fork.S | 12 ++++ src/lib/unistd/waitpid.S | 12 ++++ src/user/shell/builtin/fxdb.c | 9 +++ src/user/shell/builtin/ram.c | 60 +++++++++++++++++ src/user/shell/util/check_builtin.c | 32 ++++++--- vhex.ld | 2 +- 29 files changed, 809 insertions(+), 23 deletions(-) create mode 100644 include/kernel/memory.h create mode 100644 include/kernel/process.h create mode 100644 include/kernel/unistd_32.h create mode 100644 include/lib/unistd.h create mode 100644 src/kernel/bootstrap/kernel_switch.s create mode 100644 src/kernel/hardware/vbr/exception_pre.s create mode 100644 src/kernel/memory/initialize.c create mode 100644 src/kernel/memory/pm_alloc.c create mode 100644 src/kernel/memory/pm_free.c create mode 100644 src/kernel/process/alloc.c create mode 100644 src/kernel/process/constructor.c create mode 100644 src/kernel/process/create.c create mode 100644 src/kernel/process/get.c create mode 100644 src/kernel/process/switch.c create mode 100644 src/kernel/process/syscall/sys_fork.c create mode 100644 src/kernel/process/syscall/sys_waitpid.c create mode 100644 src/kernel/syscall/handler.c create mode 100644 src/kernel/syscall/syscall_pre.s create mode 100644 src/lib/unistd/fork.S create mode 100644 src/lib/unistd/waitpid.S create mode 100644 src/user/shell/builtin/ram.c diff --git a/include/kernel/context.h b/include/kernel/context.h index 9d40a69..ebf74a2 100644 --- a/include/kernel/context.h +++ b/include/kernel/context.h @@ -48,6 +48,16 @@ typedef struct fx9860_context_s uint32_t vbr; } fx9860_context_t; +typedef struct common_context_s +{ + uint32_t reg[16]; + uint32_t gbr; + uint32_t macl; + uint32_t mach; + uint32_t ssr; + uint32_t spc; +} common_context_t; + // Context primitive. extern void fx9860_context_save(fx9860_context_t *context); extern void fx9860_context_restore(fx9860_context_t *context); diff --git a/include/kernel/memory.h b/include/kernel/memory.h new file mode 100644 index 0000000..74eca5f --- /dev/null +++ b/include/kernel/memory.h @@ -0,0 +1,40 @@ +#ifndef __KERNEL_MEMORY_H__ +# define __KERNEL_MEMORY_H__ + +#include +#include + +#define PM_BLOCK_SIZE (64) + +struct pm_block_cache_s +{ + // Block status + enum { + UNUSED, + USED + } status; + + // Space informations. + uint16_t start; + uint32_t end; + + // Linked list + struct pm_block_cache_s *next; +}; + +struct memory_info_s +{ + // Cache informations. + struct pm_block_cache_s *cache; + struct pm_block_cache_s *head; + + // RAM informations. + uint32_t start; + uint32_t blocks; +}; + +// Function +extern void *pm_alloc(size_t size); +extern void pm_free(void *ptr); + +#endif /*__KERNEL_MEMORY_H__*/ diff --git a/include/kernel/process.h b/include/kernel/process.h new file mode 100644 index 0000000..0ad9f10 --- /dev/null +++ b/include/kernel/process.h @@ -0,0 +1,49 @@ +#ifndef __KERNEL_PROCESS_H__ +# define __KERNEL_PROCESS_H__ + +#include +#include +#include +#include + +#define PROCESS_NAME_LENGHT (16) +#define PROCESS_MAX (3) + +#define PROC_IDLE (0) + +// define process struct. +//TODO: signal ! +typedef struct process_s +{ + // Process name. + char name[PROCESS_NAME_LENGHT]; + + // Context management + common_context_t context; + + // Signals management. + //sighandler_t signal[NSIG]; + + // Other process management. + struct process_s *parent; + struct process_s *child; + struct process_s *next; +} process_t; + +// Internal struct used by the +// static process stack +struct process_stack_s +{ + struct process_s process; + int status; +}; + +// Functions. +extern pid_t process_create(const char *name); +extern process_t *process_get(pid_t pid); +extern int process_switch(pid_t pid); + +// Internal function. +extern pid_t process_alloc(process_t **process); + +#endif /*__KERNEL_PROCESS_H__*/ diff --git a/include/kernel/syscall.h b/include/kernel/syscall.h index 72cb167..f06889e 100644 --- a/include/kernel/syscall.h +++ b/include/kernel/syscall.h @@ -3,6 +3,26 @@ #include #include +#include + +//--- +// +// Vhex part !! +// +//--- +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); + + +//--- +// +// CASIO PART !! +// TODO: remove me ? +// +//---- + // Internal Casio datat structure struct rect diff --git a/include/kernel/types.h b/include/kernel/types.h index 6c30e36..aa8e77e 100644 --- a/include/kernel/types.h +++ b/include/kernel/types.h @@ -26,6 +26,8 @@ typedef enum mpu_e MPU_UNKNOWN, } mpu_t; +typedef int pid_t; + // Force inline function. #define INLINE __attribute__((always_inline)) inline diff --git a/include/kernel/unistd_32.h b/include/kernel/unistd_32.h new file mode 100644 index 0000000..809f283 --- /dev/null +++ b/include/kernel/unistd_32.h @@ -0,0 +1,13 @@ +#ifndef __KERNEL_UNISTD_32_H__ +# define __KERNEL_UNISTD_32_H__ + +#define __NR_restart_syscall 0 +#define __NR_exit 1 +#define __NR_fork 2 +#define __NR_read 3 +#define __NR_write 4 +#define __NR_open 5 +#define __NR_close 6 +#define __NR_waitpid 7 + +#endif /*__KERNEL_UNISTD_32_H__*/ diff --git a/include/lib/unistd.h b/include/lib/unistd.h new file mode 100644 index 0000000..2a9ceb1 --- /dev/null +++ b/include/lib/unistd.h @@ -0,0 +1,19 @@ +#ifndef __LIB_UNISTD_H__ +# define __LIB_UNISTD_H__ + +#include +#include +#include + +// Define syscall LIST +#include + +extern pid_t fork(void); + +//TODO: move me +#define WNOHANG 0 +#define WUNTRACED 1 +#define WCONTINUED 2 +extern pid_t waitpid(pid_t pid, int *wstatus, int options); + +#endif /*__LIB_UNISTD_H__*/ diff --git a/src/kernel/bootstrap/kernel_switch.s b/src/kernel/bootstrap/kernel_switch.s new file mode 100644 index 0000000..297ef40 --- /dev/null +++ b/src/kernel/bootstrap/kernel_switch.s @@ -0,0 +1,56 @@ +.text + +.global _kernel_switch +.type _kernel_switch, @function + +.align 2 +_kernel_switch: + ! Save process context into unbakable register + ! @note: + ! I do not save r8 ~ r14 because we will + ! never return into the bootstrap part. + mov r4, r8 + + ! Update SR register to block + ! interrupt / exception and + ! switch register bank to simalate + ! system call. + mov.l .sr_msk, r1 ! get mask for SR.BL = 1, SR.RB = 1 and SR.IMASK = 0b1111 + stc sr, r0 ! get SR register + or r1, r0 ! set mask for BL and IMASK + ldc r0, sr ! update SR regsiter + + ! set process context into bankable register + ! because unbankable register will be over-written. + mov r8, r0 + + ! Load first process + ldc.l @r0+, R0_BANK ! set "process" r0 regsiter + ldc.l @r0+, R1_BANK ! set "process" r1 regsiter + ldc.l @r0+, R2_BANK ! set "process" r2 regsiter + ldc.l @r0+, R3_BANK ! set "process" r3 regsiter + ldc.l @r0+, R4_BANK ! set "process" r4 regsiter + ldc.l @r0+, R5_BANK ! set "process" r5 regsiter + ldc.l @r0+, R6_BANK ! set "process" r6 regsiter + ldc.l @r0+, R7_BANK ! set "process" r7 regsiter + mov.l @r0+, r8 ! set r8 regsiter + mov.l @r0+, r9 ! set r9 regsiter + mov.l @r0+, r10 ! set r10 regsiter + mov.l @r0+, r11 ! set r11 regsiter + mov.l @r0+, r12 ! set r12 regsiter + mov.l @r0+, r13 ! set r13 regsiter + mov.l @r0+, r14 ! set r14 regsiter + mov.l @r0+, r2 ! Stack not handled for now + ldc.l @r0+, gbr ! set gbr regsiter + lds.l @r0+, macl ! set macl regsiter + lds.l @r0+, mach ! set mach regsiter + ldc.l @r0+, ssr ! set ssr regsiter + ldc.l @r0+, spc ! set spc regsiter + + ! Process switch + rte + nop + +.align 4 +.sr_msk: .long 0x300000f0 +.end diff --git a/src/kernel/bootstrap/start.c b/src/kernel/bootstrap/start.c index 52d1afe..402b26b 100644 --- a/src/kernel/bootstrap/start.c +++ b/src/kernel/bootstrap/start.c @@ -3,8 +3,8 @@ #include #include #include +#include #include -#include #include // Internal symbols @@ -35,6 +35,7 @@ extern uint32_t edtors; // Internal functions. extern void vhex_context_set(void); +extern void kernel_switch(common_context_t *context); extern mpu_t mpu_get(void); extern int main(void); @@ -116,18 +117,20 @@ int start(void) vhex_context_set(); atomic_end(); - // Call high level abstraction - error = main(); + // Create first process: Vhex. + uint32_t ssr = atomic_start(); + pid_t vhex_pid = process_create("Vhex"); + process_t *vhex_process = process_get(vhex_pid); + vhex_process->context.spc = (uint32_t)&main; + vhex_process->context.ssr = ssr; - // Restore Casio's context. - atomic_start(); - fx9860_context_restore(&casio_context); - atomic_end(); + // Switch to first process. + kernel_switch(&vhex_process->context); - // Execute destructor. - section_execute(&bdtors, &edtors); - - // Return properly - // TODO: involve main menu ? - return (error); + // normally the kernel SHOULD not + // arrive here. + while (1) + { + __asm__ volatile ("sleep"); + } } diff --git a/src/kernel/hardware/vbr/exception.c b/src/kernel/hardware/vbr/exception.c index 6fe5a78..000e5a2 100644 --- a/src/kernel/hardware/vbr/exception.c +++ b/src/kernel/hardware/vbr/exception.c @@ -1,6 +1,5 @@ #include -__attribute__((section(".vhex.exception"), interrupt_handler)) void exception_handler(void) { uint32_t spc; diff --git a/src/kernel/hardware/vbr/exception_pre.s b/src/kernel/hardware/vbr/exception_pre.s new file mode 100644 index 0000000..860065e --- /dev/null +++ b/src/kernel/hardware/vbr/exception_pre.s @@ -0,0 +1,52 @@ +.section ".vhex.exception", "awx", @progbits + +.global _exception_handler_pre +.type _exception_handler_pre, @function + +.extern _exception_handler +.extern _syscall_pre + +.align 2 +_exception_handler_pre: + ! Save critical regsiter. + stc.l spc, @-r15 ! save SPC register. + stc.l ssr, @-r15 ! save SSR register. + sts.l pr, @-r15 ! save pr register. + + ! Check syscall (trapa) + mov.l .expevt, r0 ! r0 = EXPEVT address. + mov.l .trapa_code, r1 ! r1 = trapa exception code + mov.l @r0, r0 ! r0 = excecption code + cmp/eq r1, r0 ! if exception code == TRAPA CODE... + bt _trapa_entry ! ...if yes, jump at + + ! Call high-level abstraction + mov.l .exception_handler, r0 ! get high-level aception abstraction + jsr @r0 ! call abstraction + nop ! (db) nop + bra _exception_handler_exit ! jump at <_exception_handler_exit> + nop ! (db) nop. + +_trapa_entry: + ! Call syscall pre handler + mov.l .syscall_pre, r0 ! get syscall pre handler address + jsr @r0 ! call pre handler + nop ! (db) nop + + +_exception_handler_exit: + ! Restore critical regsiter + lds.l @r15+, pr ! restore PR register. + ldc.l @r15+, ssr ! restore SSR regsiter. + ldc.l @r15+, spc ! restore SPC regsiter. + + ! Exit properly + rte ! exit + nop ! (db) nop + +.align 4 +.expevt: .long 0xff000024 +.trapa_code: .long 0x00000160 +.exception_handler: .long _exception_handler +.syscall_pre: .long _syscall_pre +.end diff --git a/src/kernel/memory/initialize.c b/src/kernel/memory/initialize.c new file mode 100644 index 0000000..f6d7d15 --- /dev/null +++ b/src/kernel/memory/initialize.c @@ -0,0 +1,59 @@ +#include +#include + +// Internal data. +struct memory_info_s pmemory; + +__attribute__((constructor(101))) +void memory_init(void) +{ + extern uint32_t ram_start; + uint32_t ram_end; + uint32_t ram_size; + + // TODO: determine RAM's end. + ram_end = 0x88080000; + ram_size = ram_end - (uint32_t)&ram_start; + + // DEBUG + /*dclear(); + dprint(0, 0, "RAM diagnostic"); + dprint(0, 1, "start = %p", &ram_start); + dprint(0, 2, "end = %p", ram_end); + dprint(0, 3, "size = %dko", ram_size / 1024); + dupdate();*/ + //for (int i = 0 ; i < 9000000 ; i = i + 1); + + // Get the number of block available + // and calculate the real numer of block with + // the cache. + // TODO: check if RAM can be used ? (block == 0) + // @note: try to avoid too long search part. + pmemory.cache = (void*)&ram_start; + pmemory.blocks = (ram_size / PM_BLOCK_SIZE) >> 1; + ram_end = ram_end - (PM_BLOCK_SIZE * pmemory.blocks); + while ((uint32_t)&pmemory.cache[pmemory.blocks] < ram_end - PM_BLOCK_SIZE) + { + pmemory.blocks = pmemory.blocks + 1; + ram_end = ram_end - PM_BLOCK_SIZE; + } + + // Get "real" physical memory start + pmemory.start = ram_end; + + // DEBUG + /*dclear(); + dprint(0, 0, "Cache diagnostic"); + dprint(0, 1, "Bloks = %d (%do)", pmemory.blocks, PM_BLOCK_SIZE); + dprint(0, 2, "Start = %p", pmemory.cache); + dprint(0, 3, "PRAM = %p", pmemory.start); + dupdate(); + for (int i = 0 ; i < 9000000 ; i = i + 1);*/ + + // Initialize cache + for (uint32_t i = 0 ; i < pmemory.blocks ; i = i + 1) + { + pmemory.cache[i].status = UNUSED; + pmemory.cache[i].next = NULL; + } +} diff --git a/src/kernel/memory/pm_alloc.c b/src/kernel/memory/pm_alloc.c new file mode 100644 index 0000000..718db32 --- /dev/null +++ b/src/kernel/memory/pm_alloc.c @@ -0,0 +1,85 @@ +#include + +static struct pm_block_cache_s *block_alloc(void) +{ + extern struct memory_info_s pmemory; + uint32_t i; + + i = -1; + while (++i < pmemory.blocks) + { + // Check if the block are used + if (pmemory.cache[i].status == USED) + continue; + + // Initialize block and return address + pmemory.cache[i].status = USED; + pmemory.cache[i].next = NULL; + return (&pmemory.cache[i]); + } + return (NULL); +} + +void *pm_alloc(size_t size) +{ + extern struct memory_info_s pmemory; + struct pm_block_cache_s **head; + struct pm_block_cache_s *block; + uint32_t block_entry; + uint32_t nb_blocks; + + // Check obvious error. + if (size == 0) + return (NULL); + + // Get the number of blocks we need. + nb_blocks = (size + PM_BLOCK_SIZE - 1) / PM_BLOCK_SIZE; + + // Find block entry. + block_entry = 0; + head = &pmemory.head; + while (*head != NULL) + { + // Check is it is the last allocated + // object. + if ((*head)->next == NULL) + { + // Check memory space. + if ((*head)->end + 1 + nb_blocks >= pmemory.blocks) + return (NULL); + + // Get cache entry. + block_entry = (*head)->end + 1; + head = &(*head)->next; + break; + } + + // Calculate the gap between current + // allocated object and the next object. + if (((*head)->next->start) - ((*head)->end + 1) >= nb_blocks) + { + block_entry = (*head)->end + 1; + head = &(*head)->next; + break; + } + + // Get next allocated block. + head = &(*head)->next; + } + + // Setup new allocated block + block = block_alloc(); + if (block == NULL) + return (NULL); + + // Initialize new block + block->start = block_entry; + block->end = block_entry + nb_blocks - 1; + + // Insert new block. + block->next = *head; + *head = block; + + // Generate physical memory address + return ((void*)((block_entry * PM_BLOCK_SIZE) + pmemory.start)); +} diff --git a/src/kernel/memory/pm_free.c b/src/kernel/memory/pm_free.c new file mode 100644 index 0000000..5694e4c --- /dev/null +++ b/src/kernel/memory/pm_free.c @@ -0,0 +1,53 @@ +#include +#include + +void pm_free(void *ptr) +{ + extern struct memory_info_s pmemory; + struct pm_block_cache_s **head; + uint32_t block_entry; + uint32_t sptr; + + // Save address for error message. + sptr = (uint32_t)ptr; + + // Get the "real" physical space. + ptr = (void*)(ptr - pmemory.start); + + // Check misaligned pointer. + if (((uint32_t)ptr % PM_BLOCK_SIZE) != 0) + { + tty_write( + "pm_free: Warning, you try to free misaligned" + "pointer address (%p)\n", sptr + ); + return; + } + + // Get block entry. + block_entry = (uint32_t)ptr / PM_BLOCK_SIZE; + + // Walk into "head" cache and try to find + // the allocated block. + head = &pmemory.head; + while (*head != NULL) + { + // Check the allocated block. + if ((*head)->start != block_entry) + { + head = &(*head)->next; + continue; + } + + // Free the block and return + (*head)->status = UNUSED; + *head = (*head)->next; + return; + } + + // No block found, display error. + tty_write( + "pm_free: Warning, you try to free unused" + "allocated memory (%p)", sptr + ); +} diff --git a/src/kernel/process/alloc.c b/src/kernel/process/alloc.c new file mode 100644 index 0000000..d58c6b9 --- /dev/null +++ b/src/kernel/process/alloc.c @@ -0,0 +1,19 @@ +#include +#include + +// This function SHOULD not be called +// without atomic operation !! +pid_t process_alloc(process_t **process) +{ + extern struct process_stack_s process_stack[PROCESS_MAX]; + + for (int i = 0 ; i < PROCESS_MAX ; i = i + 1) + { + if (process_stack[i].status == PROC_IDLE) + { + *process = &process_stack[i].process; + return (i); + } + } + return (-1); +} diff --git a/src/kernel/process/constructor.c b/src/kernel/process/constructor.c new file mode 100644 index 0000000..9b32479 --- /dev/null +++ b/src/kernel/process/constructor.c @@ -0,0 +1,19 @@ +#include + +// Create all internal global +// used to handle process. +struct process_stack_s process_stack[PROCESS_MAX]; +process_t *process_current; + +__attribute__((constructor)) +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; + } + + // No process is currently running. + process_current = NULL; +} diff --git a/src/kernel/process/create.c b/src/kernel/process/create.c new file mode 100644 index 0000000..a6bb3b0 --- /dev/null +++ b/src/kernel/process/create.c @@ -0,0 +1,36 @@ +#include +#include + +pid_t process_create(const char *name) +{ + extern process_t *process_current; + process_t *process; + pid_t process_pid; + + // Check error + if (name == NULL) + return (-1); + + // Try to find free slot. + process_pid = process_alloc(&process); + if (process == NULL) + return (-1); + + // Set process name. + strncpy(process->name, name, PROCESS_NAME_LENGHT); + + // Initialize context. + for (int i = 0 ; i < 16 ; i = i + 1) + process->context.reg[i] = 0x00000000; + process->context.gbr = 0x00000000; + process->context.macl = 0x00000000; + process->context.mach = 0x00000000; + process->context.ssr = 0x00000000; + process->context.spc = 0x00000000; + + // Initialize processes. + process->parent = process_current; + process->child = NULL; + process->next = NULL; + return (process_pid); +} diff --git a/src/kernel/process/get.c b/src/kernel/process/get.c new file mode 100644 index 0000000..c15577d --- /dev/null +++ b/src/kernel/process/get.c @@ -0,0 +1,13 @@ +#include + +process_t *process_get(pid_t pid) +{ + extern struct process_stack_s process_stack[PROCESS_MAX]; + + // Check error + if (pid < 0 || pid >= PROCESS_MAX) + return (NULL); + + // Return process. + return (&process_stack[pid].process); +} diff --git a/src/kernel/process/switch.c b/src/kernel/process/switch.c new file mode 100644 index 0000000..13f6128 --- /dev/null +++ b/src/kernel/process/switch.c @@ -0,0 +1,27 @@ +#include + +//FIXME: atomic operation !! +int process_switch(pid_t pid) +{ + extern process_t *process_current; + common_context_t *context_current; + common_context_t *context_next; + process_t *process; + + // Get current context + context_current = + (process_current != NULL) + ? &process_current->context + : NULL; + + // Get next context. + process = process_get(pid); + if (process == NULL) + return (-1); + context_next = &process->context; + + // Context switch + // TODO: SYSCALL !!!!! + //context_switch(context_current, context_next); + return (0); +} diff --git a/src/kernel/process/syscall/sys_fork.c b/src/kernel/process/syscall/sys_fork.c new file mode 100644 index 0000000..1f42686 --- /dev/null +++ b/src/kernel/process/syscall/sys_fork.c @@ -0,0 +1,21 @@ +#include + +pid_t sys_fork(void) +{ + extern process_t *process_current; + process_t **process_new; + pid_t process_pid; + + // 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) + return (-1); + + // Initialize context. + return (-1); +} diff --git a/src/kernel/process/syscall/sys_waitpid.c b/src/kernel/process/syscall/sys_waitpid.c new file mode 100644 index 0000000..78df952 --- /dev/null +++ b/src/kernel/process/syscall/sys_waitpid.c @@ -0,0 +1,6 @@ +#include + +pid_t sys_waitpid(pid_t pid, int *wstatus, int options) +{ + return (-1); +} diff --git a/src/kernel/syscall/handler.c b/src/kernel/syscall/handler.c new file mode 100644 index 0000000..1bced07 --- /dev/null +++ b/src/kernel/syscall/handler.c @@ -0,0 +1,19 @@ +#include +#include + +static const void *sys_handler[] = { + NULL, //restart + NULL, //exit + sys_fork, //fork + NULL, //read + NULL, //write + NULL, //open + NULL, //close + sys_waitpid, //waitpid +}; + +void *sys_get_handler(int sysno) +{ + //FIXME: Check sysno validity + return ((void *)sys_handler[sysno]); +} diff --git a/src/kernel/syscall/syscall_pre.s b/src/kernel/syscall/syscall_pre.s new file mode 100644 index 0000000..d3272d5 --- /dev/null +++ b/src/kernel/syscall/syscall_pre.s @@ -0,0 +1,57 @@ +.text +.global _syscall_pre +.type _syscall_pre, @function + +.extern _sys_get_handler + +.align 2 +_syscall_pre: + ! save some used register. + mov.l r8, @-r15 ! save r8 register + mov.l r9, @-r15 ! save r9 register + sts.l pr, @-r15 ! save PR register + + ! Call syscall high-level abstraction + ! to get appropriate system handler + mov.l .tra, r4 ! r4 = TRA regsiter address (trapa exception code) + mov.l .sys_get_handler, r0 ! r0 = high-level abstration handler + mov.l @r4, r4 ! r4 = trapa exception code + jsr @r0 ! call abstraction + shlr2 r4 ! (db) r4 = syscall number + cmp/eq #0, r0 ! if r0 == NULL... + bt.s syscall_pre_exit ! ...if yes, jump at + mov r0, r9 ! save kernel handler into unbankable register + + ! Get and save SR register + stc sr, r0 ! get SR register + mov r0, r8 ! save SR register + + ! Switch register bank and allow interrupt + ! @note: user context has been saved + ! during the `exception_handler_pre` + 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 + + ! Call kernel abstraction + jsr @r9 ! call system handler + nop ! (db) nop. + + ! Restore SR regsiter + ldc r8, sr ! SR.BL = 1, SR.RB = 1 and SR.IMASK = old mask. + +syscall_pre_exit: + ! Restore used regsiter. + lds.l @r15+, pr ! restore PR register + mov.l @r15+, r9 ! restore r9 register + mov.l @r15+, r8 ! restore r8 register + + ! Exit properly + rts ! exit + nop ! (db) nop + +.align 4 +.tra: .long 0xff000020 +.sr_mask: .long ~(0x300000f0) +.sys_get_handler: .long _sys_get_handler +.end diff --git a/src/lib/unistd/fork.S b/src/lib/unistd/fork.S new file mode 100644 index 0000000..2ab82f9 --- /dev/null +++ b/src/lib/unistd/fork.S @@ -0,0 +1,12 @@ +.text +.global _fork +.type _fork, @function + +#include "kernel/unistd_32.h" + +.align 2 +_fork: + trapa #__NR_fork + rts + nop +.end diff --git a/src/lib/unistd/waitpid.S b/src/lib/unistd/waitpid.S new file mode 100644 index 0000000..dd4c3e7 --- /dev/null +++ b/src/lib/unistd/waitpid.S @@ -0,0 +1,12 @@ +.text +.global _waitpid +.type _waitpid, @function + +#include "kernel/unistd_32.h" + +.align 2 +_waitpid: + trapa #__NR_waitpid + rts + nop +.end diff --git a/src/user/shell/builtin/fxdb.c b/src/user/shell/builtin/fxdb.c index eb48de7..bdd1d66 100644 --- a/src/user/shell/builtin/fxdb.c +++ b/src/user/shell/builtin/fxdb.c @@ -1,6 +1,7 @@ #include "builtin.h" #include #include +#include // TODO: remove me !! extern void test(void); @@ -15,6 +16,14 @@ VHEX_BUILTIN(fxdb) dprint(0, 0, "FXDB - entry !!"); dupdate(); for (int i = 0 ; i < 9000000 ; i = i + 1); + + int fion = fork(); + dclear(); + dprint(0, 0, "FXDB - entry !!"); + dprint(0, 1, "fork test = %d", fion); + dupdate(); + for (int i = 0 ; i < 9000000 ; i = i + 1); + return (0); // Open User Break Controller. diff --git a/src/user/shell/builtin/ram.c b/src/user/shell/builtin/ram.c new file mode 100644 index 0000000..f8a825b --- /dev/null +++ b/src/user/shell/builtin/ram.c @@ -0,0 +1,60 @@ +#include "builtin.h" +#include +#include + +VHEX_BUILTIN(ram) +{ + extern struct memory_info_s pmemory; + extern uint32_t ram_start; + uint32_t ram_end; + uint32_t ram_size; + + // TODO: determine RAM's end. + ram_end = 0x88080000; + ram_size = ram_end - (uint32_t)&ram_start; + + //dprint(0, 0, "RAM diagnostic"); + //dprint(0, 1, "start = %p", &ram_start); + //dprint(0, 2, "end = %p", 0x88080000); + //dprint(0, 3, "size = %dko", ram_size / 1024); + + //dprint(0, 5, "Cache diagnostic"); + //dprint(0, 0, "Bloks = %d (%do)", pmemory.blocks, PM_BLOCK_SIZE); + //dprint(0, 1, "Start = %p", pmemory.cache); + //dprint(0, 2, "PRAM = %p", pmemory.start); + //dupdate(); + + //TODO: GetKey + //for (int i = 0 ; i < 9000000 ; i = i + 1); + + // Try to alloc. + void *test0 = pm_alloc(129); + void *test1 = pm_alloc(1024); + void *test2 = pm_alloc(129); + + // Display address + dclear(); + dprint(0, 0, "test0 = %p (129o)", test0); + dprint(0, 1, "test1 = %p (1024o)", test1); + dprint(0, 2, "test2 = %p (129o)", test2); + + // Try to free allocated space. + pm_free(test1); + + // Try to alloc again. + test1 = pm_alloc(64); + + // Display RAM abstract cache + int i = 0; + struct pm_block_cache_s *head = pmemory.head; + while (head != NULL && i < 7) + { + dprint(0, 3 + i, "s:%d-e:%d-n:%p", head->start, head->end, head->next); + head = head->next; + i = i + 1; + } + dupdate(); + for (int i = 0 ; i < 9000000 ; i = i + 1); + + return (0); +} diff --git a/src/user/shell/util/check_builtin.c b/src/user/shell/util/check_builtin.c index c904451..2d2dc4b 100644 --- a/src/user/shell/util/check_builtin.c +++ b/src/user/shell/util/check_builtin.c @@ -2,6 +2,7 @@ #include "builtin.h" #include #include +#include //TODO: use agc, argv. int check_builtin(char *cmd) @@ -9,23 +10,38 @@ 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) { - dclear(); - dprint(0, 0, "builtin - %s", list[i].name); - dupdate(); - for (int i = 0 ; i < 9000000 ; i = i + 1); + if (strcmp(list[i].name, cmd) != 0) + continue; + + // 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();*/ - - if (strcmp(list[i].name, cmd) == 0) - { list[i].entry(0, NULL); return (0); - } + // } else { + // waitpid(pid, &wstatus, WCONTINUED); + //TODO: signal handling. + // } } return (1); } diff --git a/vhex.ld b/vhex.ld index 93cbf36..00f208a 100644 --- a/vhex.ld +++ b/vhex.ld @@ -88,7 +88,7 @@ SECTIONS *(.data) - . = ALIGN(4); + _ram_start = ALIGN(1024); } > ram AT> rom : data _sdata = SIZEOF(.data);