aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/kernel/init.c1
-rw-r--r--src/kernel/svc.c33
-rw-r--r--src/kernel/task.c116
-rw-r--r--src/kernel/task.h30
-rw-r--r--src/kernel/vfs.c15
-rw-r--r--src/kernel/vfs.h32
-rw-r--r--src/user/user.c9
7 files changed, 186 insertions, 50 deletions
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 <arch/stm/stm32l476xx.h>
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 <arch/stm/stm32l476xx.h>
+#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 <stdint.h>
+#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 <stdint.h>
+
+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;
}