diff --git a/.gitignore b/.gitignore index d42ab35..8bbd2c8 100644 --- a/.gitignore +++ b/.gitignore @@ -1 +1,3 @@ -out/* +*.o +*.swp +*.swo diff --git a/Makefile b/Makefile index 02fbad2..c131a32 100644 --- a/Makefile +++ b/Makefile @@ -24,7 +24,7 @@ AS = as MCUFLAGS = -mthumb -mcpu=cortex-m4 #-mfloat-abi=hard -mfpu=fpv4-sp-d16 AFLAGS = $(MCUFLAGS) -CFLAGS = $(MCUFLAGS) -ggdb \ +CFLAGS = $(MCUFLAGS) -ggdb --specs=nosys.specs \ -I.. \ -fno-builtin -fsigned-char -ffreestanding \ -Wall -Werror -Wextra -pedantic \ diff --git a/src/kernel/init.c b/src/kernel/init.c index 474ef8a..6bb7eb5 100644 --- a/src/kernel/init.c +++ b/src/kernel/init.c @@ -22,6 +22,7 @@ #include "gpio.h" #include "heap.h" #include "task.h" +#include "vfs.h" #include extern uint8_t __bss_end__; diff --git a/src/kernel/svc.c b/src/kernel/svc.c index 4aa156e..1e03262 100644 --- a/src/kernel/svc.c +++ b/src/kernel/svc.c @@ -41,24 +41,31 @@ void SVC_Handler(void) { switch (svc_number) { case -1: - case 0: - _exit(args[0]); + case 0: /* Task-related calls + * 0 - _exit + * 1 - fork + * 2 - getpid + * 3 - waitpid + */ + task_svc(args); break; - case 1: + + case 1: /* GPIO-related calls + * 0 - gpio_mode + * 1 - gpio_type + * 2 - gpio_pupd + * 3 - gpio_speed + * 4 - gpio_dout + */ gpio_svc(args); break; - case 2: + + case 2: /* Clock-related calls + * 0 - delay + * 1 - udelay + */ clock_svc(args); break; - case 3: - asm("\ - mrs r0, psp; \ - stmdb r0!, {r4-r11, r14}; \ - mov %0, r0; \ - " : "=r" (args[0])); - task_svc(args); - asm("mov r0, %0" :: "r" (args[0])); // TODO doesn't work, r0 overwritten on exc. return - break; default: break; } diff --git a/src/kernel/task.c b/src/kernel/task.c index 4f61e1d..e4531db 100644 --- a/src/kernel/task.c +++ b/src/kernel/task.c @@ -23,16 +23,37 @@ #include "task.h" #include +#define YIELD { SCB->ICSR |= SCB_ICSR_PENDSVSET_Msk; } + static task_t *task_current; static task_t *task_queue; static uint8_t task_disable = 0; -static uint32_t task_next_pid = 0; +static pid_t task_next_pid = 0; + +void task_exit(int code); +int task_fork(void); +pid_t task_getpid(void); +pid_t task_waitpid(pid_t pid, int *wstatus, int options); -int task_fork(uint32_t sp); void task_svc(uint32_t *args) { - int result = task_fork(args[0]); - args[0] = result; + switch (args[0]) { + case 0: + task_exit(args[1]); + break; + case 1: + *((int *)args[1]) = task_fork(); + break; + case 2: + *((int *)args[1]) = task_getpid(); + break; + case 3: + *((int *)args[4]) = task_waitpid(args[1], (int *)args[2], + args[3]); + break; + default: + break; + } } void task_hold(uint8_t hold) @@ -45,19 +66,54 @@ void task_hold(uint8_t hold) void task_sleep(uint32_t ms) { - task_current->sleep = millis() + ms; - SCB->ICSR |= SCB_ICSR_PENDSVSET_Msk; + task_current->status.state = TASK_SLEEPING; + task_current->status.value = millis() + ms; + YIELD; } -uint32_t task_getpid(void) +pid_t task_getpid(void) { return task_current->pid; } -void _exit(int code) +pid_t task_waitpid(pid_t pid, int *wstatus, int options) +{ + (void)options; + *wstatus = 0; + + // Find the process + task_t *task = task_queue; + while (task != 0 && task->pid != pid) + task = task->next; + + if (task == 0) + return (pid_t)-1; + + // Check process's state + if (task->status.state == TASK_EXITED) { + *wstatus = task->status.value | (1 << 8); + task->status.state = TASK_ZOMBIE; + } + + return pid; +} + +/*vfs_node *task_getcwd(void) { - (void)code; + return task_current->cwd; +}*/ +void task_exit(int code) +{ + task_current->status.state = TASK_EXITED; + task_current->status.value = code & 0xFF; + + YIELD; +} + +void task_purge(void) +{ + // Remove task from the chain if (task_queue == task_current) { task_queue = task_queue->next; } else { @@ -75,19 +131,17 @@ void _exit(int code) free(task_current->stack); free(task_current); - SCB->ICSR |= SCB_ICSR_PENDSVSET_Msk; - // TODO if child proc. set return code in parent task handle? - // or something like that + YIELD; + while (1); } - /** * Exits the task (userspace call). */ __attribute__ ((naked)) void task_doexit(void) { - asm("eor r0, r0; svc 0"); + asm("eor r0, r0; eor r1, r1; svc 0"); while (1); } @@ -109,8 +163,10 @@ task_t *task_create(void (*code)(void), uint16_t stackSize) { task_t *t = (task_t *)malloc(sizeof(task_t)); t->next = 0; - t->sleep = 0; t->pid = task_next_pid++; + t->pgid = t->pid; + t->status.state = TASK_RUNNING; + t->status.value = 0; t->stack = (uint32_t *)malloc(stackSize); void *sp = (uint8_t *)t->stack + stackSize - 68; // excep. stack + regs @@ -141,7 +197,8 @@ void task_init(void (*init)(void), uint16_t stackSize) task_current->next = 0; task_current->stack = 0; // free() is called on this task_current->sp = 0; - task_current->sleep = 1000; + task_current->status.state = TASK_SLEEPING; + task_current->status.value = 1000; task_queue = task_create(init, stackSize); @@ -177,10 +234,17 @@ int task_fork_ret(void) } // Return 0 for child, non-zero for parent -int task_fork(uint32_t sp) +int task_fork(void) { asm("cpsid i"); + uint32_t sp; + asm("\ + mrs r0, psp; \ + stmdb r0!, {r4-r11, r14}; \ + mov %0, r0; \ + " : "=r" (sp)); + //// 1. Prepare child task // Get parent task's stack info alloc_t *stackInfo = (alloc_t *)(((uint8_t *)task_current->stack) @@ -189,8 +253,10 @@ int task_fork(uint32_t sp) // Create child task data task_t *childTask = (task_t *)malloc(sizeof(task_t)); childTask->stack = (uint32_t *)malloc(stackInfo->size - sizeof(alloc_t)); - childTask->sleep = 0; childTask->pid = task_next_pid++; + childTask->pgid = task_current->pid; + childTask->status.state = TASK_RUNNING; + childTask->status.value = 0; // Copy parent's stack for (uint32_t i = 0; i < (stackInfo->size - sizeof(alloc_t)); i++) @@ -198,6 +264,7 @@ int task_fork(uint32_t sp) childTask->sp = (uint32_t *)((uint32_t)childTask->stack + (sp - (uint32_t)task_current->stack)); + childTask->sp[8] = 0xFFFFFFFD; childTask->sp[15] = (uint32_t)task_fork_ret; //childTask->sp[16] = 0x01000000; @@ -208,7 +275,7 @@ int task_fork(uint32_t sp) //// 3. Re-enable scheduler, make change happen asm("cpsie i"); - SCB->ICSR |= SCB_ICSR_PENDSVSET_Msk; + YIELD; return childTask->pid; } @@ -234,13 +301,14 @@ void PendSV_Handler(void) task_current = task_current->next; if (task_current == 0) task_current = task_queue; - } while (task_current->sleep > ticks); - task_current->sleep = 0; - /*task_current = task_current->next; - if (task_current == 0) - task_current = task_queue;*/ + if (task_current->status.state == TASK_SLEEPING && + task_current->status.value <= ticks) + task_current->status.state = TASK_RUNNING; + } while (task_current->status.state != TASK_RUNNING); + task_current->status.state = TASK_RUNNING; + task_current->status.value = 0; // Load stack pointer, return asm("\ diff --git a/src/kernel/task.h b/src/kernel/task.h index 0e2e07a..d78e1da 100644 --- a/src/kernel/task.h +++ b/src/kernel/task.h @@ -21,8 +21,14 @@ #ifndef TASK_H_ #define TASK_H_ +#include "vfs.h" #include +#define WIFEXITED(w) (w & (1 << 8)) +#define WEXITSTATUS(w) (w & 0xFF) + +typedef uint16_t pid_t; + /** * A structure to contain task data. */ @@ -30,10 +36,22 @@ typedef struct task_t { struct task_t *next; /**< pointer to the next task_t instance */ uint32_t *sp; /**< pointer to the task's last sp register value */ uint32_t *stack; /**< pointer to the task's stack */ - uint32_t sleep; /**< number of milliseconds task is sleeping for */ - uint32_t pid; + pid_t pid; /**< Task (Process) ID */ + pid_t pgid; /**< Process Group ID */ + struct { + uint32_t state : 8; + uint32_t value : 24; + } status; +// vfs_node *cwd; } task_t; +enum TASK_STATUS_FLAGS { + TASK_RUNNING, /**< Task is actively running */ + TASK_SLEEPING, /**< Task is sleeping for task_t.sleep ms */ + TASK_EXITED, /**< Task has exited, task_t.sleep has code */ + TASK_ZOMBIE /**< Task exited, accounted for, ready to go bye bye */ +}; + /** * Enters multitasking mode. The given function acts as the initial thread. * This task is given a 4kb stack. @@ -56,14 +74,8 @@ void task_start(void (*task)(void), uint16_t stackSize); */ void task_hold(uint8_t hold); -/** - * Frees the task's resources and removes it from the running task list. - * @param code An unused exit code - */ -void _exit(int code); - void task_sleep(uint32_t ms); -uint32_t task_getpid(void); +//vfs_node *task_getcwd(void); #endif // TASK_H_ diff --git a/src/kernel/vfs.c b/src/kernel/vfs.c new file mode 100644 index 0000000..a0d9bb4 --- /dev/null +++ b/src/kernel/vfs.c @@ -0,0 +1,15 @@ +#include "vfs.h" +#include "task.h" + +//static vfs_node vfs_root; + +int vfs_open(const char *path, int mode) +{ + (void)path; + (void)mode; +// vfs_node *cd = task_getcwd(); +// if (cd == 0) +// cd = &vfs_root; + + return 0; +} diff --git a/src/kernel/vfs.h b/src/kernel/vfs.h new file mode 100644 index 0000000..6874905 --- /dev/null +++ b/src/kernel/vfs.h @@ -0,0 +1,32 @@ +#ifndef VFS_H_ +#define VFS_H_ + +#include + +struct vfs_node; +struct dirent; + +typedef struct { + uint32_t (*read)(struct vfs_node *, uint32_t, uint32_t, uint8_t *); + uint32_t (*write)(struct vfs_node *, uint32_t, uint32_t, const uint8_t *); + void (*open)(struct vfs_node *); + void (*close)(struct vfs_node *); +} vfs_driver; + +typedef struct vfs_node { + char *name; + uint32_t flags; + + struct vfs_node *parent; + union { + struct vfs_node* children; + vfs_driver *access; + } data; +} vfs_node; + +struct dirent { + char *name; + vfs_node *node; +}; + +#endif // VFS_H_ diff --git a/src/user/user.c b/src/user/user.c index 87f4b49..620ffd0 100644 --- a/src/user/user.c +++ b/src/user/user.c @@ -15,11 +15,12 @@ void user_delay(uint32_t ms) int fork(void) { - int result; + int result = 0; asm("\ - svc 3; \ - mov %0, r0; \ - " : "=r" (result)); + mov r0, 1; \ + mov r1, %0; \ + svc 0; \ + " :: "r" (&result)); return result; }