good tasks, svc cleaning

master
Clyne Sullivan 6 years ago
parent 3919219d9b
commit 3a798edb83

4
.gitignore vendored

@ -1 +1,3 @@
out/* *.o
*.swp
*.swo

@ -24,7 +24,7 @@ AS = as
MCUFLAGS = -mthumb -mcpu=cortex-m4 #-mfloat-abi=hard -mfpu=fpv4-sp-d16 MCUFLAGS = -mthumb -mcpu=cortex-m4 #-mfloat-abi=hard -mfpu=fpv4-sp-d16
AFLAGS = $(MCUFLAGS) AFLAGS = $(MCUFLAGS)
CFLAGS = $(MCUFLAGS) -ggdb \ CFLAGS = $(MCUFLAGS) -ggdb --specs=nosys.specs \
-I.. \ -I.. \
-fno-builtin -fsigned-char -ffreestanding \ -fno-builtin -fsigned-char -ffreestanding \
-Wall -Werror -Wextra -pedantic \ -Wall -Werror -Wextra -pedantic \

@ -22,6 +22,7 @@
#include "gpio.h" #include "gpio.h"
#include "heap.h" #include "heap.h"
#include "task.h" #include "task.h"
#include "vfs.h"
#include <arch/stm/stm32l476xx.h> #include <arch/stm/stm32l476xx.h>
extern uint8_t __bss_end__; extern uint8_t __bss_end__;

@ -41,24 +41,31 @@ void SVC_Handler(void) {
switch (svc_number) { switch (svc_number) {
case -1: case -1:
case 0: case 0: /* Task-related calls
_exit(args[0]); * 0 - _exit
* 1 - fork
* 2 - getpid
* 3 - waitpid
*/
task_svc(args);
break; 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); gpio_svc(args);
break; break;
case 2:
case 2: /* Clock-related calls
* 0 - delay
* 1 - udelay
*/
clock_svc(args); clock_svc(args);
break; 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: default:
break; break;
} }

@ -23,16 +23,37 @@
#include "task.h" #include "task.h"
#include <arch/stm/stm32l476xx.h> #include <arch/stm/stm32l476xx.h>
#define YIELD { SCB->ICSR |= SCB_ICSR_PENDSVSET_Msk; }
static task_t *task_current; static task_t *task_current;
static task_t *task_queue; static task_t *task_queue;
static uint8_t task_disable = 0; 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) void task_svc(uint32_t *args)
{ {
int result = task_fork(args[0]); switch (args[0]) {
args[0] = result; 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) void task_hold(uint8_t hold)
@ -45,19 +66,54 @@ void task_hold(uint8_t hold)
void task_sleep(uint32_t ms) void task_sleep(uint32_t ms)
{ {
task_current->sleep = millis() + ms; task_current->status.state = TASK_SLEEPING;
SCB->ICSR |= SCB_ICSR_PENDSVSET_Msk; task_current->status.value = millis() + ms;
YIELD;
} }
uint32_t task_getpid(void) pid_t task_getpid(void)
{ {
return task_current->pid; 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) { if (task_queue == task_current) {
task_queue = task_queue->next; task_queue = task_queue->next;
} else { } else {
@ -75,19 +131,17 @@ void _exit(int code)
free(task_current->stack); free(task_current->stack);
free(task_current); free(task_current);
SCB->ICSR |= SCB_ICSR_PENDSVSET_Msk; YIELD;
// TODO if child proc. set return code in parent task handle? while (1);
// or something like that
} }
/** /**
* Exits the task (userspace call). * Exits the task (userspace call).
*/ */
__attribute__ ((naked)) __attribute__ ((naked))
void task_doexit(void) void task_doexit(void)
{ {
asm("eor r0, r0; svc 0"); asm("eor r0, r0; eor r1, r1; svc 0");
while (1); 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)); task_t *t = (task_t *)malloc(sizeof(task_t));
t->next = 0; t->next = 0;
t->sleep = 0;
t->pid = task_next_pid++; t->pid = task_next_pid++;
t->pgid = t->pid;
t->status.state = TASK_RUNNING;
t->status.value = 0;
t->stack = (uint32_t *)malloc(stackSize); t->stack = (uint32_t *)malloc(stackSize);
void *sp = (uint8_t *)t->stack + stackSize - 68; // excep. stack + regs 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->next = 0;
task_current->stack = 0; // free() is called on this task_current->stack = 0; // free() is called on this
task_current->sp = 0; 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); task_queue = task_create(init, stackSize);
@ -177,10 +234,17 @@ int task_fork_ret(void)
} }
// Return 0 for child, non-zero for parent // Return 0 for child, non-zero for parent
int task_fork(uint32_t sp) int task_fork(void)
{ {
asm("cpsid i"); asm("cpsid i");
uint32_t sp;
asm("\
mrs r0, psp; \
stmdb r0!, {r4-r11, r14}; \
mov %0, r0; \
" : "=r" (sp));
//// 1. Prepare child task //// 1. Prepare child task
// Get parent task's stack info // Get parent task's stack info
alloc_t *stackInfo = (alloc_t *)(((uint8_t *)task_current->stack) alloc_t *stackInfo = (alloc_t *)(((uint8_t *)task_current->stack)
@ -189,8 +253,10 @@ int task_fork(uint32_t sp)
// Create child task data // Create child task data
task_t *childTask = (task_t *)malloc(sizeof(task_t)); task_t *childTask = (task_t *)malloc(sizeof(task_t));
childTask->stack = (uint32_t *)malloc(stackInfo->size - sizeof(alloc_t)); childTask->stack = (uint32_t *)malloc(stackInfo->size - sizeof(alloc_t));
childTask->sleep = 0;
childTask->pid = task_next_pid++; childTask->pid = task_next_pid++;
childTask->pgid = task_current->pid;
childTask->status.state = TASK_RUNNING;
childTask->status.value = 0;
// Copy parent's stack // Copy parent's stack
for (uint32_t i = 0; i < (stackInfo->size - sizeof(alloc_t)); i++) 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 childTask->sp = (uint32_t *)((uint32_t)childTask->stack + (sp
- (uint32_t)task_current->stack)); - (uint32_t)task_current->stack));
childTask->sp[8] = 0xFFFFFFFD;
childTask->sp[15] = (uint32_t)task_fork_ret; childTask->sp[15] = (uint32_t)task_fork_ret;
//childTask->sp[16] = 0x01000000; //childTask->sp[16] = 0x01000000;
@ -208,7 +275,7 @@ int task_fork(uint32_t sp)
//// 3. Re-enable scheduler, make change happen //// 3. Re-enable scheduler, make change happen
asm("cpsie i"); asm("cpsie i");
SCB->ICSR |= SCB_ICSR_PENDSVSET_Msk; YIELD;
return childTask->pid; return childTask->pid;
} }
@ -234,13 +301,14 @@ void PendSV_Handler(void)
task_current = task_current->next; task_current = task_current->next;
if (task_current == 0) if (task_current == 0)
task_current = task_queue; task_current = task_queue;
} while (task_current->sleep > ticks);
task_current->sleep = 0;
/*task_current = task_current->next; if (task_current->status.state == TASK_SLEEPING &&
if (task_current == 0) task_current->status.value <= ticks)
task_current = task_queue;*/ 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 // Load stack pointer, return
asm("\ asm("\

@ -21,8 +21,14 @@
#ifndef TASK_H_ #ifndef TASK_H_
#define TASK_H_ #define TASK_H_
#include "vfs.h"
#include <stdint.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. * 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 */ 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 *sp; /**< pointer to the task's last sp register value */
uint32_t *stack; /**< pointer to the task's stack */ uint32_t *stack; /**< pointer to the task's stack */
uint32_t sleep; /**< number of milliseconds task is sleeping for */ pid_t pid; /**< Task (Process) ID */
uint32_t pid; pid_t pgid; /**< Process Group ID */
struct {
uint32_t state : 8;
uint32_t value : 24;
} status;
// vfs_node *cwd;
} task_t; } 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. * Enters multitasking mode. The given function acts as the initial thread.
* This task is given a 4kb stack. * 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); 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); void task_sleep(uint32_t ms);
uint32_t task_getpid(void); //vfs_node *task_getcwd(void);
#endif // TASK_H_ #endif // TASK_H_

@ -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;
}

@ -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_

@ -15,11 +15,12 @@ void user_delay(uint32_t ms)
int fork(void) int fork(void)
{ {
int result; int result = 0;
asm("\ asm("\
svc 3; \ mov r0, 1; \
mov %0, r0; \ mov r1, %0; \
" : "=r" (result)); svc 0; \
" :: "r" (&result));
return result; return result;
} }

Loading…
Cancel
Save