Reviewed stmos, made small format/doc fixes

master
Clyne 5 years ago
parent 998b3ac86e
commit a5892b3523

@ -25,12 +25,20 @@ extern int main(int, char **);
static void stdio_init(void); static void stdio_init(void);
/**
* Entry point for userland programs.
* Sets up stdio, then enters the program's main() before exiting with main()'s
* return code.
*/
void _start(void) void _start(void)
{ {
stdio_init(); stdio_init();
exit(main(0, 0)); exit(main(0, 0));
} }
/**
* Initializes file handles for stdout, stdin, and stderr.
*/
void stdio_init(void) void stdio_init(void)
{ {
stderr = calloc(1, sizeof(FILE)); stderr = calloc(1, sizeof(FILE));

@ -28,6 +28,7 @@ typedef struct {
uint32_t size; uint32_t size;
} initrd_info; } initrd_info;
// Defined by linker script
extern uint8_t _binary_initrd_img_start[]; extern uint8_t _binary_initrd_img_start[];
extern uint8_t _binary_initrd_img_size[]; extern uint8_t _binary_initrd_img_size[];
@ -39,6 +40,10 @@ uint32_t initrd_read(vfs_file_info *info, uint32_t count, uint8_t *buffer);
int initrd_close(vfs_file_info *info); int initrd_close(vfs_file_info *info);
int initrd_seek(vfs_file_info *info, uint32_t offset, int whence); int initrd_seek(vfs_file_info *info, uint32_t offset, int whence);
/**
* Gets the start of the offset-th file in the initrd.
* @return Pointer to the file, NULL otherwise
*/
char *initrd_getfile(uint32_t offset); char *initrd_getfile(uint32_t offset);
static const vfs_volume_funcs initrd_funcs = { static const vfs_volume_funcs initrd_funcs = {
@ -50,6 +55,9 @@ static const vfs_volume_funcs initrd_funcs = {
initrd_seek initrd_seek
}; };
/**
* Custom strncmp() implementation used by this driver.
*/
int initrd_strncmp(const char *a, const char *b, unsigned int n) int initrd_strncmp(const char *a, const char *b, unsigned int n)
{ {
for (unsigned int i = 0; i < n; i++) { for (unsigned int i = 0; i < n; i++) {
@ -67,10 +75,12 @@ void initrd_init(void)
void *initrd_open(const char *file) void *initrd_open(const char *file)
{ {
// Iterate through all files in the initrd
char *ptr; char *ptr;
for (uint32_t i = 0; ptr = initrd_getfile(i), ptr != 0; i++) { for (uint32_t i = 0; ptr = initrd_getfile(i), ptr != 0; i++) {
uint32_t len = *((uint32_t *)ptr); uint32_t len = *((uint32_t *)ptr);
if (!initrd_strncmp(file, ptr + 4, len)) { if (!initrd_strncmp(file, ptr + 4, len)) {
// If we found our file, create an info structure and return it
initrd_info *file = (initrd_info *)malloc( initrd_info *file = (initrd_info *)malloc(
sizeof(initrd_info)); sizeof(initrd_info));
file->address = ptr + len + 8; file->address = ptr + len + 8;
@ -84,17 +94,18 @@ void *initrd_open(const char *file)
int initrd_close(vfs_file_info *info) int initrd_close(vfs_file_info *info)
{ {
// Nothing to do
free(info->fsinfo); free(info->fsinfo);
return 0; return 0;
} }
uint32_t initrd_read(vfs_file_info *info, uint32_t count, uint8_t *buffer) uint32_t initrd_read(vfs_file_info *info, uint32_t count, uint8_t *buffer)
{ {
// Confirm this is a valid file
initrd_info *iinfo = (initrd_info *)info->fsinfo; initrd_info *iinfo = (initrd_info *)info->fsinfo;
if (iinfo == 0 || iinfo->address == 0) if (iinfo == 0 || iinfo->address == 0)
return 0; return 0;
// Attempt to read 'count' bytes, breaking if we reach the end of the file
uint32_t i; uint32_t i;
for (i = 0; i < count; i++) { for (i = 0; i < count; i++) {
if (info->pos >= iinfo->size) if (info->pos >= iinfo->size)
@ -129,9 +140,11 @@ char *initrd_getfile(uint32_t offset)
{ {
char *ptr = (char *)initrd_start; char *ptr = (char *)initrd_start;
for (uint32_t i = 0; i < offset; i++) { for (uint32_t i = 0; i < offset; i++) {
// Move to the next file
uint32_t len = *((uint32_t *)ptr); uint32_t len = *((uint32_t *)ptr);
uint32_t datalen = *((uint32_t *)(ptr + 4 + len)); uint32_t datalen = *((uint32_t *)(ptr + 4 + len));
ptr += len + datalen + 8; ptr += len + datalen + 8;
if (ptr >= (char *)(initrd_start + initrd_size)) if (ptr >= (char *)(initrd_start + initrd_size))
return 0; return 0;
} }

@ -27,3 +27,4 @@
void initrd_init(void); void initrd_init(void);
#endif // INITRD_H_ #endif // INITRD_H_

@ -39,6 +39,9 @@ const vfs_volume_funcs stdio_funcs = {
void *stdio_open(const char *path) void *stdio_open(const char *path)
{ {
/**
* All we need is the correct file handle number.
*/
int *id = malloc(sizeof(uint32_t)); int *id = malloc(sizeof(uint32_t));
if (path[0] == 'o' && path[1] == 'u' && path[2] == 't') if (path[0] == 'o' && path[1] == 'u' && path[2] == 't')
@ -53,13 +56,13 @@ void *stdio_open(const char *path)
int stdio_close(vfs_file_info *info) int stdio_close(vfs_file_info *info)
{ {
// Nothing to do
free(info->fsinfo); free(info->fsinfo);
return 0; return 0;
} }
uint32_t stdio_read(vfs_file_info *info, uint32_t count, uint8_t *buffer) uint32_t stdio_read(vfs_file_info *info, uint32_t count, uint8_t *buffer)
{ {
// TODO?
(void)info; (void)info;
(void)count; (void)count;
(void)buffer; (void)buffer;
@ -68,6 +71,7 @@ uint32_t stdio_read(vfs_file_info *info, uint32_t count, uint8_t *buffer)
uint32_t stdio_write(vfs_file_info *info, uint32_t count, const uint8_t *buffer) uint32_t stdio_write(vfs_file_info *info, uint32_t count, const uint8_t *buffer)
{ {
// For now, output to serial
(void)info; (void)info;
for (uint32_t i = 0; i < count; i++) for (uint32_t i = 0; i < count; i++)
serial_put(buffer[i]); serial_put(buffer[i]);

@ -29,3 +29,4 @@
extern const vfs_volume_funcs stdio_funcs; extern const vfs_volume_funcs stdio_funcs;
#endif // INITRD_H_ #endif // INITRD_H_

@ -47,3 +47,4 @@ void clock_udelay(uint32_t count);
uint32_t clock_millis(void); uint32_t clock_millis(void);
#endif // CLOCK_H_ #endif // CLOCK_H_

@ -24,6 +24,12 @@
#include <string.h> #include <string.h>
/**
* Finds the section with the given name in the ELF data, e.g. ".bss".
* @param ehdr ELF file header
* @param name Name of the section
* @return Section header of the section, NULL if not found
*/
Elf32_Shdr *elf_find_section(Elf32_Ehdr *ehdr, const char *name) Elf32_Shdr *elf_find_section(Elf32_Ehdr *ehdr, const char *name)
{ {
Elf32_Shdr *shdr = (Elf32_Shdr *)((char *)ehdr + ehdr->e_shoff); Elf32_Shdr *shdr = (Elf32_Shdr *)((char *)ehdr + ehdr->e_shoff);
@ -80,6 +86,7 @@ uint32_t elf_execve(const char *file, char * const argv[], char * const envp[])
Elf32_Ehdr *ehdr = (Elf32_Ehdr *)elfData; Elf32_Ehdr *ehdr = (Elf32_Ehdr *)elfData;
Elf32_Phdr *phdr = (Elf32_Phdr *)(elfData + ehdr->e_phoff); Elf32_Phdr *phdr = (Elf32_Phdr *)(elfData + ehdr->e_phoff);
// Search for the loadable program header
for (Elf32_Half i = 0; i < ehdr->e_phnum; i++) { for (Elf32_Half i = 0; i < ehdr->e_phnum; i++) {
if (phdr->p_type == PT_LOAD) { if (phdr->p_type == PT_LOAD) {
// There should only be one PT_LOAD section... // There should only be one PT_LOAD section...
@ -87,6 +94,7 @@ uint32_t elf_execve(const char *file, char * const argv[], char * const envp[])
while (1); while (1);
ELF_OFFSET = (uint32_t)malloc(phdr->p_memsz + 8) & ~7; ELF_OFFSET = (uint32_t)malloc(phdr->p_memsz + 8) & ~7;
// Copy the program data into RAM for execution
uint8_t *src = (uint8_t *)elfData + phdr->p_offset; uint8_t *src = (uint8_t *)elfData + phdr->p_offset;
uint8_t *dst = (uint8_t *)(ELF_OFFSET + phdr->p_vaddr); uint8_t *dst = (uint8_t *)(ELF_OFFSET + phdr->p_vaddr);
for (uint32_t j = 0; j < phdr->p_filesz; j++) for (uint32_t j = 0; j < phdr->p_filesz; j++)
@ -114,7 +122,7 @@ uint32_t elf_execve(const char *file, char * const argv[], char * const envp[])
gotArray[i] += ELF_OFFSET; gotArray[i] += ELF_OFFSET;
} }
// Run any constructors // Run any initial constructors
Elf32_Shdr *initArraySection = elf_find_section(ehdr, ".init_array"); Elf32_Shdr *initArraySection = elf_find_section(ehdr, ".init_array");
if (initArraySection != 0) { if (initArraySection != 0) {
Elf32_Addr *initArray = (Elf32_Addr *)(ELF_OFFSET + Elf32_Addr *initArray = (Elf32_Addr *)(ELF_OFFSET +

@ -122,3 +122,4 @@ typedef struct {
} __attribute__((packed)) Elf32_Phdr; } __attribute__((packed)) Elf32_Phdr;
#endif // ELF_H_ #endif // ELF_H_

@ -24,3 +24,4 @@ void HardFault_Handler(void)
// TODO have a real fault handler... // TODO have a real fault handler...
while (1); while (1);
} }

@ -91,3 +91,4 @@ uint32_t gpio_din(GPIO_TypeDef *port, uint32_t pin)
{ {
return port->IDR & (1 << pin); return port->IDR & (1 << pin);
} }

@ -129,3 +129,4 @@ void gpio_dout(GPIO_TypeDef *port, uint32_t pin, uint32_t val);
uint32_t gpio_din(GPIO_TypeDef *port, uint32_t pin); uint32_t gpio_din(GPIO_TypeDef *port, uint32_t pin);
#endif // GPIO_H_ #endif // GPIO_H_

@ -20,8 +20,10 @@
#include "heap.h" #include "heap.h"
// Defines size of alignment on memory allocations
#define HEAP_ALIGN 4 #define HEAP_ALIGN 4
// Linked list of free'd memory
static alloc_t *free_blocks; static alloc_t *free_blocks;
static void *heap_end; static void *heap_end;
@ -34,8 +36,10 @@ void heap_init(void *buf)
uint32_t heap_free(void) uint32_t heap_free(void)
{ {
uint32_t total = 0; uint32_t total = 0;
// Count free'd block sizes
for (alloc_t *node = free_blocks; node != 0; node = node->next) for (alloc_t *node = free_blocks; node != 0; node = node->next)
total += node->size; total += node->size;
// Add remaining free memory to that total
return total + (0x20018000 - (uint32_t)heap_end); return total + (0x20018000 - (uint32_t)heap_end);
} }
@ -44,26 +48,29 @@ void *malloc(uint32_t size)
if (size == 0) if (size == 0)
return 0; return 0;
// Round size to an aligned value
size = (size + sizeof(alloc_t) + HEAP_ALIGN) & ~(HEAP_ALIGN - 1); size = (size + sizeof(alloc_t) + HEAP_ALIGN) & ~(HEAP_ALIGN - 1);
// Begin searching through free'd blocks to see if we can reuse some memory.
alloc_t *node = free_blocks; alloc_t *node = free_blocks;
alloc_t *prev = 0; alloc_t *prev = 0;
while (node != 0) { while (node != 0) {
if (node->size >= size) { if (node->size >= size) {
// get out of the free chain // If we can use this chunk, remove it from the free_blocks chain
if (prev != 0) if (prev != 0)
prev->next = node->next; prev->next = node->next;
else else
free_blocks = node->next; free_blocks = node->next;
node->next = 0; node->next = 0;
// split alloc if too big // If this chunk is really big, give back the extra space
if (node->size > size + 64) { if (node->size > size + 64) { // TODO why 64..?
alloc_t *leftover = (alloc_t *)((uint32_t)node alloc_t *leftover = (alloc_t *)((uint32_t)node
+ sizeof(alloc_t) + size); + sizeof(alloc_t) + size);
leftover->size = node->size - size - sizeof(alloc_t); leftover->size = node->size - size - sizeof(alloc_t);
leftover->next = 0; leftover->next = 0;
free((uint8_t *)leftover + sizeof(alloc_t)); free((uint8_t *)leftover + sizeof(alloc_t));
node->size = size; node->size = size;
return (void *)((uint8_t *)node + sizeof(alloc_t)); return (void *)((uint8_t *)node + sizeof(alloc_t));
} }
@ -75,6 +82,7 @@ void *malloc(uint32_t size)
node = node->next; node = node->next;
} }
// No reusable chunks, take from the end of the heap
node = (alloc_t *)heap_end; node = (alloc_t *)heap_end;
node->size = size; node->size = size;
node->next = 0; node->next = 0;
@ -86,9 +94,10 @@ void *malloc(uint32_t size)
void *calloc(uint32_t count, uint32_t size) void *calloc(uint32_t count, uint32_t size)
{ {
// Simply malloc and zero
uint8_t *buf = malloc(count * size); uint8_t *buf = malloc(count * size);
for (uint32_t i = 0; i < count * size; i++) for (uint32_t i = 0; i < count * size; i++)
buf[i] = 0; buf[i] = 0; // TODO safe?
return buf; return buf;
} }
@ -97,24 +106,30 @@ void free(void *buf)
if (buf == 0) if (buf == 0)
return; return;
// Get the alloc_t structure of this chunk
alloc_t *alloc = (alloc_t *)((uint8_t *)buf - sizeof(alloc_t)); alloc_t *alloc = (alloc_t *)((uint8_t *)buf - sizeof(alloc_t));
if (alloc->next != 0) if (alloc->next != 0)
return; return;
// check for adjacent free'd blocks // Search through the free_blocks list to see if this free chunk can merge
// into an adjacent free chunk.
int merged = 0; int merged = 0;
for (alloc_t *prev = 0, *node = free_blocks; node != 0; prev = node, node = node->next) { for (alloc_t *prev = 0, *node = free_blocks; node != 0; prev = node, node = node->next) {
// If the node after the current one is ours
if ((uint32_t)node + sizeof(alloc_t) + node->size == (uint32_t)alloc) { if ((uint32_t)node + sizeof(alloc_t) + node->size == (uint32_t)alloc) {
// block before // Merge by adding our node's size to this one
merged |= 1; merged |= 1;
node->size += sizeof(alloc_t) + alloc->size; node->size += sizeof(alloc_t) + alloc->size;
break; break;
//alloc = node; }
} else if ((uint32_t)buf + alloc->size == (uint32_t)node) { // Or, if this current node is the one after ours
// block after else if ((uint32_t)buf + alloc->size == (uint32_t)node) {
// Merge the current node into ours
merged |= 1; merged |= 1;
alloc->size += sizeof(alloc_t) + node->size; alloc->size += sizeof(alloc_t) + node->size;
alloc->next = node->next; alloc->next = node->next;
// Take the current node's place in the free_blocks chain
if (prev != 0) if (prev != 0)
prev->next = alloc; prev->next = alloc;
else else
@ -123,9 +138,11 @@ void free(void *buf)
} }
} }
// If we couldn't merge, simply append to the chain
if (merged == 0) { if (merged == 0) {
alloc->next = free_blocks; alloc->next = free_blocks;
free_blocks = alloc; free_blocks = alloc;
} }
} }

@ -23,6 +23,9 @@
#include <stdint.h> #include <stdint.h>
/**
* Internal structure place before memory allocations, to track allocation size.
*/
typedef struct { typedef struct {
uint32_t size; uint32_t size;
void *next; void *next;
@ -30,13 +33,14 @@ typedef struct {
/** /**
* Initializes memory management of the given heap. * Initializes memory management of the given heap.
* No overflow stuff is done, so... be careful. * Note: Heap size is not accounted for.
* @param buf The heap to use for allocations * @param buf The heap to use for allocations
*/ */
void heap_init(void *buf); void heap_init(void *buf);
/** /**
* Returns the amount of free, allocatable memory, in bytes. * Returns the amount of free, allocatable memory, in bytes, assuming that the
* heap has from its initial location to the end of SRAM.
* @return Amount of free memory in bytes * @return Amount of free memory in bytes
*/ */
uint32_t heap_free(void); uint32_t heap_free(void);
@ -64,3 +68,4 @@ void *calloc(uint32_t count, uint32_t size);
void free(void *buf); void free(void *buf);
#endif // HEAP_H_ #endif // HEAP_H_

@ -27,6 +27,7 @@
#include <fs/initrd.h> #include <fs/initrd.h>
#include <arch/stm/stm32l476xx.h> #include <arch/stm/stm32l476xx.h>
// Heap goes after the end of the BSS section
extern uint8_t __bss_end__; extern uint8_t __bss_end__;
extern void user_main(void); extern void user_main(void);
@ -34,15 +35,17 @@ void init_idle(void);
int main(void) int main(void)
{ {
// Disable interrupts while we get ready
asm("cpsid i"); asm("cpsid i");
// disable cached writes for precise debug info
// Disabling cached writes can help give more precise debug info
//*((uint32_t *)0xE000E008) |= 2; //*((uint32_t *)0xE000E008) |= 2;
// prepare flash latency for 80MHz operation // Prepare flash latency for 80MHz operation
FLASH->ACR &= ~(FLASH_ACR_LATENCY); FLASH->ACR &= ~(FLASH_ACR_LATENCY);
FLASH->ACR |= FLASH_ACR_LATENCY_4WS; FLASH->ACR |= FLASH_ACR_LATENCY_4WS;
// init core components // Initialize core components
clock_init(); clock_init();
heap_init(&__bss_end__); heap_init(&__bss_end__);
gpio_init(); gpio_init();
@ -51,17 +54,21 @@ int main(void)
vfs_init(); vfs_init();
initrd_init(); initrd_init();
// enable FPU // Enable FPU (TODO why isn't it enabled?)
//SCB->CPACR |= (0xF << 20); //SCB->CPACR |= (0xF << 20);
// Begin multi-tasking (enables interrupts)
task_init(init_idle, 512); task_init(init_idle, 512);
while (1); while (1);
} }
void init_idle(void) void init_idle(void)
{ {
// Start the main userspace task with a 4kB stack
task_start(user_main, 4096); task_start(user_main, 4096);
// Idle
while (1) while (1)
clock_delay(10); clock_delay(10);
} }

@ -28,9 +28,9 @@ void serial_init(uint32_t baud)
gpio_mode(GPIOA, 3, ALTERNATE); gpio_mode(GPIOA, 3, ALTERNATE);
GPIOA->AFR[0] &= ~(0x0000FF00); GPIOA->AFR[0] &= ~(0x0000FF00);
GPIOA->AFR[0] |= 0x00007700; GPIOA->AFR[0] |= 0x00007700;
RCC->APB1ENR1 |= RCC_APB1ENR1_USART2EN;
// start usart device // Start usart device
RCC->APB1ENR1 |= RCC_APB1ENR1_USART2EN;
USART2->BRR = 80000000L / baud; USART2->BRR = 80000000L / baud;
USART2->CR1 |= USART_CR1_TE | USART_CR1_RE | USART_CR1_UE; USART2->CR1 |= USART_CR1_TE | USART_CR1_RE | USART_CR1_UE;
} }
@ -58,3 +58,4 @@ void serial_gets(char *buf, int max)
} while (buf[index] != '\r' && index++ < max); } while (buf[index] != '\r' && index++ < max);
buf[index] = '\0'; buf[index] = '\0';
} }

@ -46,3 +46,4 @@ char serial_get(void);
void serial_gets(char *buf, int max); void serial_gets(char *buf, int max);
#endif // SERIAL_H_ #endif // SERIAL_H_

@ -31,6 +31,7 @@ extern void vfs_svc(uint32_t, uint32_t *, uint32_t *args);
void SVC_Handler(void) { void SVC_Handler(void) {
uint32_t *stack; uint32_t *stack;
// Get the appropriate stack (either kernel or process)
asm("\ asm("\
tst lr, #4; \ tst lr, #4; \
ite eq; \ ite eq; \
@ -44,13 +45,13 @@ void SVC_Handler(void) {
uint32_t *args = (uint32_t *)stack[2]; uint32_t *args = (uint32_t *)stack[2];
switch (svc_number) { switch (svc_number) {
case -1: case -1: // TODO why?
case 0: /* Task-related calls case 0: /* Task-related calls
* 0 - _exit * 0 - _exit
* 1 - fork * 1 - fork
* 2 - getpid * 2 - getpid
* 3 - waitpid * 3 - waitpid
* 4 - sbrk (TODO bad) * 4 - sbrk (TODO poor implementation)
* 5 - execve * 5 - execve
*/ */
task_svc(min_number, ret, args); task_svc(min_number, ret, args);

@ -146,8 +146,9 @@ void task_purge(void)
} }
// Free this thread's stack, and task data. // Free this thread's stack, and task data.
// Since we're single core, no one else can claim this memory until // The scheduler still needs to use the data we're about to free; however,
// a task switch, after which we're done with this memory anyway. // our single-core implementation keeps us safe from anyone else claiming
// this memory in the meantime.
free(task_current->stack); free(task_current->stack);
free(task_current->heap); free(task_current->heap);
free(task_current); free(task_current);
@ -168,7 +169,8 @@ void task_doexit(void)
/** /**
* 'Prepares' task for running. * 'Prepares' task for running.
* Calls the task's main code, setting task_doexit() (_exit) as the return point. * Calls the task's main code after making task_doexit() (_exit) main's return
* point.
*/ */
__attribute__ ((naked)) __attribute__ ((naked))
void task_crt0(void) void task_crt0(void)
@ -191,7 +193,7 @@ task_t *task_create(void (*code)(void), uint16_t stackSize)
t->heap = 0; t->heap = 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; // exception stack + regs
t->sp = sp; t->sp = sp;
/* /*
@ -215,6 +217,7 @@ task_t *task_create(void (*code)(void), uint16_t stackSize)
void task_init(void (*init)(void), uint16_t stackSize) void task_init(void (*init)(void), uint16_t stackSize)
{ {
// Create a dummy current task that we'll "exit" from
task_current = (task_t *)malloc(sizeof(task_t)); task_current = (task_t *)malloc(sizeof(task_t));
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
@ -222,10 +225,12 @@ void task_init(void (*init)(void), uint16_t stackSize)
task_current->status.state = TASK_SLEEPING; task_current->status.state = TASK_SLEEPING;
task_current->status.value = 1000; task_current->status.value = 1000;
// Place the init task in the queue to take the dummy task's place
task_queue = task_create(init, stackSize); task_queue = task_create(init, stackSize);
task_disable = 0; task_disable = 0;
// Enter userspace process mode
// bit 0 - priv, bit 1 - psp/msp // bit 0 - priv, bit 1 - psp/msp
asm("\ asm("\
isb; \ isb; \
@ -237,7 +242,7 @@ void task_init(void (*init)(void), uint16_t stackSize)
msr control, r0; \ msr control, r0; \
"); ");
// exit the current (fake) task // Exit the current (fake) task
task_doexit(); task_doexit();
} }
@ -307,9 +312,9 @@ void PendSV_Handler(void)
if (task_disable != 0) if (task_disable != 0)
asm("bx lr"); asm("bx lr");
// TODO get back to c, implement task sleeping // TODO get back to c, implement task sleeping TODO did we do this?
// Save current stack pointer // Finish saving current state
asm("\ asm("\
mrs r0, psp; \ mrs r0, psp; \
isb; \ isb; \

@ -25,7 +25,6 @@
#define WIFEXITED(w) (w & (1 << 8)) #define WIFEXITED(w) (w & (1 << 8))
#define WEXITSTATUS(w) (w & 0xFF) #define WEXITSTATUS(w) (w & 0xFF)
typedef uint16_t pid_t; typedef uint16_t pid_t;
/** /**
@ -66,23 +65,44 @@ void task_init(void (*init)(void), uint16_t stackSize);
void task_start(void (*task)(void), uint16_t stackSize); void task_start(void (*task)(void), uint16_t stackSize);
/** /**
* Allows task switching to be disabled, for low-level actions. * Allows task switching to be disabled, for low-level/time-critical operations.
* Multiple holds can be placed, and all must be removed to continue task * Multiple holds can be placed, and all must be removed to continue task
* switching. * switching.
* @param hold non-zero for hold, zero to remove hold * @param hold non-zero for hold, zero to remove hold
*/ */
void task_hold(uint8_t hold); void task_hold(uint8_t hold);
/**
* Puts the task to sleep for the given duration.
* @param ms Milliseconds to sleep for
*/
void task_sleep(uint32_t ms); void task_sleep(uint32_t ms);
/**
* Called by the task when it's ready to exit.
* @param code Task's exit code
*/
void task_exit(int code); void task_exit(int code);
/**
* Forks the task into two processes.
*/
int task_fork(void); int task_fork(void);
/**
* Gets the task's PID.
*/
pid_t task_getpid(void); pid_t task_getpid(void);
/**
* Waits for a task to change state (TODO confirm).
*/
pid_t task_waitpid(pid_t pid, int *wstatus, int options); pid_t task_waitpid(pid_t pid, int *wstatus, int options);
/**
* TODO
*/
void *task_sbrk(uint32_t bytes); void *task_sbrk(uint32_t bytes);
#endif // TASK_H_ #endif // TASK_H_

@ -61,13 +61,14 @@ void vfs_svc(uint32_t n, uint32_t *ret, uint32_t *args)
void vfs_init(void) void vfs_init(void)
{ {
// Mark all volumes and files as empty
for (int i = 0; i < VFS_MAX_VOLS; i++) for (int i = 0; i < VFS_MAX_VOLS; i++)
vfs_volumes[i].flags = 0; vfs_volumes[i].flags = 0;
for (int i = 0; i < VFS_MAX_FILES; i++) for (int i = 0; i < VFS_MAX_FILES; i++)
vfs_files[i].flags = 0; vfs_files[i].flags = 0;
vfs_mount(&stdio_funcs, 0); vfs_mount(&stdio_funcs, 0);
// order is crucial // Order of opening here may be important TODO confirm
vfs_open(" in", VFS_FILE_READ); vfs_open(" in", VFS_FILE_READ);
vfs_open(" out", VFS_FILE_WRITE); vfs_open(" out", VFS_FILE_WRITE);
vfs_open(" err", VFS_FILE_WRITE); vfs_open(" err", VFS_FILE_WRITE);

@ -143,3 +143,4 @@ int vfs_seek(int fd, int32_t offset, int whence);
int32_t vfs_tell(int fd); int32_t vfs_tell(int fd);
#endif // VFS_H_ #endif // VFS_H_

@ -1,7 +1,28 @@
/**
* @file gpio.c
* Userspace library for GPIO access
*
* Copyright (C) 2018 Clyne Sullivan
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
#include "gpio.h" #include "gpio.h"
#include <stdint.h> #include <stdint.h>
// SVC calls get messed up by GCC's optimization...
#define NOOPTIMIZE __attribute__((optimize(0))) #define NOOPTIMIZE __attribute__((optimize(0)))
NOOPTIMIZE NOOPTIMIZE

@ -1,3 +1,23 @@
/**
* @file gpio.h
* Userspace library for GPIO access
*
* Copyright (C) 2018 Clyne Sullivan
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
#ifndef STMOS_GPIO_H_ #ifndef STMOS_GPIO_H_
#define STMOS_GPIO_H_ #define STMOS_GPIO_H_
@ -55,3 +75,4 @@ void gpioWrite(gpio_pin_t pin, int value);
int gpioRead(gpio_pin_t pin); int gpioRead(gpio_pin_t pin);
#endif // STMOS_GPIO_H_ #endif // STMOS_GPIO_H_

@ -23,7 +23,8 @@
void user_main(void) void user_main(void)
{ {
//gpio(GPIO_MODE, 5, OUTPUT); // Just load the init program from the initrd.
// (A:/ is stdio, B:/ is initrd)
execve("B:/init", 0, 0); execve("B:/init", 0, 0);
} }

Loading…
Cancel
Save