aboutsummaryrefslogtreecommitdiffstats
path: root/src/kernel
diff options
context:
space:
mode:
Diffstat (limited to 'src/kernel')
-rw-r--r--src/kernel/clock.h1
-rw-r--r--src/kernel/elf.c10
-rw-r--r--src/kernel/elf.h1
-rw-r--r--src/kernel/fault.c1
-rw-r--r--src/kernel/gpio.c1
-rw-r--r--src/kernel/gpio.h1
-rw-r--r--src/kernel/heap.c35
-rw-r--r--src/kernel/heap.h9
-rw-r--r--src/kernel/init.c15
-rw-r--r--src/kernel/serial.c5
-rw-r--r--src/kernel/serial.h1
-rw-r--r--src/kernel/svc.c5
-rw-r--r--src/kernel/task.c19
-rw-r--r--src/kernel/task.h24
-rw-r--r--src/kernel/vfs.c3
-rw-r--r--src/kernel/vfs.h1
16 files changed, 102 insertions, 30 deletions
diff --git a/src/kernel/clock.h b/src/kernel/clock.h
index e5e46c4..325a080 100644
--- a/src/kernel/clock.h
+++ b/src/kernel/clock.h
@@ -47,3 +47,4 @@ void clock_udelay(uint32_t count);
uint32_t clock_millis(void);
#endif // CLOCK_H_
+
diff --git a/src/kernel/elf.c b/src/kernel/elf.c
index 77333a9..db268ce 100644
--- a/src/kernel/elf.c
+++ b/src/kernel/elf.c
@@ -24,6 +24,12 @@
#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 *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_Phdr *phdr = (Elf32_Phdr *)(elfData + ehdr->e_phoff);
+ // Search for the loadable program header
for (Elf32_Half i = 0; i < ehdr->e_phnum; i++) {
if (phdr->p_type == PT_LOAD) {
// 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);
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 *dst = (uint8_t *)(ELF_OFFSET + phdr->p_vaddr);
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;
}
- // Run any constructors
+ // Run any initial constructors
Elf32_Shdr *initArraySection = elf_find_section(ehdr, ".init_array");
if (initArraySection != 0) {
Elf32_Addr *initArray = (Elf32_Addr *)(ELF_OFFSET +
diff --git a/src/kernel/elf.h b/src/kernel/elf.h
index 9143401..dd7ffc1 100644
--- a/src/kernel/elf.h
+++ b/src/kernel/elf.h
@@ -122,3 +122,4 @@ typedef struct {
} __attribute__((packed)) Elf32_Phdr;
#endif // ELF_H_
+
diff --git a/src/kernel/fault.c b/src/kernel/fault.c
index db81c1f..f43353b 100644
--- a/src/kernel/fault.c
+++ b/src/kernel/fault.c
@@ -24,3 +24,4 @@ void HardFault_Handler(void)
// TODO have a real fault handler...
while (1);
}
+
diff --git a/src/kernel/gpio.c b/src/kernel/gpio.c
index 3bd67cb..7831bf5 100644
--- a/src/kernel/gpio.c
+++ b/src/kernel/gpio.c
@@ -91,3 +91,4 @@ uint32_t gpio_din(GPIO_TypeDef *port, uint32_t pin)
{
return port->IDR & (1 << pin);
}
+
diff --git a/src/kernel/gpio.h b/src/kernel/gpio.h
index ea7e837..ed9dfa6 100644
--- a/src/kernel/gpio.h
+++ b/src/kernel/gpio.h
@@ -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);
#endif // GPIO_H_
+
diff --git a/src/kernel/heap.c b/src/kernel/heap.c
index 123f7e6..b125d6e 100644
--- a/src/kernel/heap.c
+++ b/src/kernel/heap.c
@@ -20,8 +20,10 @@
#include "heap.h"
+// Defines size of alignment on memory allocations
#define HEAP_ALIGN 4
+// Linked list of free'd memory
static alloc_t *free_blocks;
static void *heap_end;
@@ -34,8 +36,10 @@ void heap_init(void *buf)
uint32_t heap_free(void)
{
uint32_t total = 0;
+ // Count free'd block sizes
for (alloc_t *node = free_blocks; node != 0; node = node->next)
total += node->size;
+ // Add remaining free memory to that total
return total + (0x20018000 - (uint32_t)heap_end);
}
@@ -44,26 +48,29 @@ void *malloc(uint32_t size)
if (size == 0)
return 0;
+ // Round size to an aligned value
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 *prev = 0;
while (node != 0) {
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)
prev->next = node->next;
else
free_blocks = node->next;
node->next = 0;
- // split alloc if too big
- if (node->size > size + 64) {
+ // If this chunk is really big, give back the extra space
+ if (node->size > size + 64) { // TODO why 64..?
alloc_t *leftover = (alloc_t *)((uint32_t)node
+ sizeof(alloc_t) + size);
leftover->size = node->size - size - sizeof(alloc_t);
leftover->next = 0;
free((uint8_t *)leftover + sizeof(alloc_t));
+
node->size = size;
return (void *)((uint8_t *)node + sizeof(alloc_t));
}
@@ -75,6 +82,7 @@ void *malloc(uint32_t size)
node = node->next;
}
+ // No reusable chunks, take from the end of the heap
node = (alloc_t *)heap_end;
node->size = size;
node->next = 0;
@@ -86,9 +94,10 @@ void *malloc(uint32_t size)
void *calloc(uint32_t count, uint32_t size)
{
+ // Simply malloc and zero
uint8_t *buf = malloc(count * size);
for (uint32_t i = 0; i < count * size; i++)
- buf[i] = 0;
+ buf[i] = 0; // TODO safe?
return buf;
}
@@ -97,24 +106,30 @@ void free(void *buf)
if (buf == 0)
return;
+ // Get the alloc_t structure of this chunk
alloc_t *alloc = (alloc_t *)((uint8_t *)buf - sizeof(alloc_t));
if (alloc->next != 0)
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;
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) {
- // block before
+ // Merge by adding our node's size to this one
merged |= 1;
node->size += sizeof(alloc_t) + alloc->size;
break;
- //alloc = node;
- } else if ((uint32_t)buf + alloc->size == (uint32_t)node) {
- // block after
+ }
+ // Or, if this current node is the one after ours
+ else if ((uint32_t)buf + alloc->size == (uint32_t)node) {
+ // Merge the current node into ours
merged |= 1;
alloc->size += sizeof(alloc_t) + node->size;
alloc->next = node->next;
+
+ // Take the current node's place in the free_blocks chain
if (prev != 0)
prev->next = alloc;
else
@@ -123,9 +138,11 @@ void free(void *buf)
}
}
+ // If we couldn't merge, simply append to the chain
if (merged == 0) {
alloc->next = free_blocks;
free_blocks = alloc;
}
}
+
diff --git a/src/kernel/heap.h b/src/kernel/heap.h
index 82d057e..054cb8a 100644
--- a/src/kernel/heap.h
+++ b/src/kernel/heap.h
@@ -23,6 +23,9 @@
#include <stdint.h>
+/**
+ * Internal structure place before memory allocations, to track allocation size.
+ */
typedef struct {
uint32_t size;
void *next;
@@ -30,13 +33,14 @@ typedef struct {
/**
* 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
*/
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
*/
uint32_t heap_free(void);
@@ -64,3 +68,4 @@ void *calloc(uint32_t count, uint32_t size);
void free(void *buf);
#endif // HEAP_H_
+
diff --git a/src/kernel/init.c b/src/kernel/init.c
index 48e1800..01bff42 100644
--- a/src/kernel/init.c
+++ b/src/kernel/init.c
@@ -27,6 +27,7 @@
#include <fs/initrd.h>
#include <arch/stm/stm32l476xx.h>
+// Heap goes after the end of the BSS section
extern uint8_t __bss_end__;
extern void user_main(void);
@@ -34,15 +35,17 @@ void init_idle(void);
int main(void)
{
+ // Disable interrupts while we get ready
asm("cpsid i");
- // disable cached writes for precise debug info
+
+ // Disabling cached writes can help give more precise debug info
//*((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_4WS;
- // init core components
+ // Initialize core components
clock_init();
heap_init(&__bss_end__);
gpio_init();
@@ -51,17 +54,21 @@ int main(void)
vfs_init();
initrd_init();
- // enable FPU
+ // Enable FPU (TODO why isn't it enabled?)
//SCB->CPACR |= (0xF << 20);
+ // Begin multi-tasking (enables interrupts)
task_init(init_idle, 512);
while (1);
}
void init_idle(void)
{
+ // Start the main userspace task with a 4kB stack
task_start(user_main, 4096);
+ // Idle
while (1)
clock_delay(10);
}
+
diff --git a/src/kernel/serial.c b/src/kernel/serial.c
index 2737b7d..2b5cb2d 100644
--- a/src/kernel/serial.c
+++ b/src/kernel/serial.c
@@ -28,9 +28,9 @@ void serial_init(uint32_t baud)
gpio_mode(GPIOA, 3, ALTERNATE);
GPIOA->AFR[0] &= ~(0x0000FF00);
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->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);
buf[index] = '\0';
}
+
diff --git a/src/kernel/serial.h b/src/kernel/serial.h
index e721d6c..9dd75e1 100644
--- a/src/kernel/serial.h
+++ b/src/kernel/serial.h
@@ -46,3 +46,4 @@ char serial_get(void);
void serial_gets(char *buf, int max);
#endif // SERIAL_H_
+
diff --git a/src/kernel/svc.c b/src/kernel/svc.c
index 7c81e5f..358fa3d 100644
--- a/src/kernel/svc.c
+++ b/src/kernel/svc.c
@@ -31,6 +31,7 @@ extern void vfs_svc(uint32_t, uint32_t *, uint32_t *args);
void SVC_Handler(void) {
uint32_t *stack;
+ // Get the appropriate stack (either kernel or process)
asm("\
tst lr, #4; \
ite eq; \
@@ -44,13 +45,13 @@ void SVC_Handler(void) {
uint32_t *args = (uint32_t *)stack[2];
switch (svc_number) {
- case -1:
+ case -1: // TODO why?
case 0: /* Task-related calls
* 0 - _exit
* 1 - fork
* 2 - getpid
* 3 - waitpid
- * 4 - sbrk (TODO bad)
+ * 4 - sbrk (TODO poor implementation)
* 5 - execve
*/
task_svc(min_number, ret, args);
diff --git a/src/kernel/task.c b/src/kernel/task.c
index 304e608..b6f4fc1 100644
--- a/src/kernel/task.c
+++ b/src/kernel/task.c
@@ -146,8 +146,9 @@ void task_purge(void)
}
// Free this thread's stack, and task data.
- // Since we're single core, no one else can claim this memory until
- // a task switch, after which we're done with this memory anyway.
+ // The scheduler still needs to use the data we're about to free; however,
+ // our single-core implementation keeps us safe from anyone else claiming
+ // this memory in the meantime.
free(task_current->stack);
free(task_current->heap);
free(task_current);
@@ -168,7 +169,8 @@ void task_doexit(void)
/**
* '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))
void task_crt0(void)
@@ -191,7 +193,7 @@ task_t *task_create(void (*code)(void), uint16_t stackSize)
t->heap = 0;
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;
/*
@@ -215,6 +217,7 @@ task_t *task_create(void (*code)(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->next = 0;
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.value = 1000;
+ // Place the init task in the queue to take the dummy task's place
task_queue = task_create(init, stackSize);
task_disable = 0;
+ // Enter userspace process mode
// bit 0 - priv, bit 1 - psp/msp
asm("\
isb; \
@@ -237,7 +242,7 @@ void task_init(void (*init)(void), uint16_t stackSize)
msr control, r0; \
");
- // exit the current (fake) task
+ // Exit the current (fake) task
task_doexit();
}
@@ -307,9 +312,9 @@ void PendSV_Handler(void)
if (task_disable != 0)
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("\
mrs r0, psp; \
isb; \
diff --git a/src/kernel/task.h b/src/kernel/task.h
index 5875e3c..b67147e 100644
--- a/src/kernel/task.h
+++ b/src/kernel/task.h
@@ -25,7 +25,6 @@
#define WIFEXITED(w) (w & (1 << 8))
#define WEXITSTATUS(w) (w & 0xFF)
-
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);
/**
- * 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
* switching.
* @param hold non-zero for hold, zero to remove 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);
+/**
+ * Called by the task when it's ready to exit.
+ * @param code Task's exit code
+ */
void task_exit(int code);
+/**
+ * Forks the task into two processes.
+ */
int task_fork(void);
+/**
+ * Gets the task's PID.
+ */
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);
+/**
+ * TODO
+ */
void *task_sbrk(uint32_t bytes);
#endif // TASK_H_
+
diff --git a/src/kernel/vfs.c b/src/kernel/vfs.c
index 8d4b975..b3af7fc 100644
--- a/src/kernel/vfs.c
+++ b/src/kernel/vfs.c
@@ -61,13 +61,14 @@ void vfs_svc(uint32_t n, uint32_t *ret, uint32_t *args)
void vfs_init(void)
{
+ // Mark all volumes and files as empty
for (int i = 0; i < VFS_MAX_VOLS; i++)
vfs_volumes[i].flags = 0;
for (int i = 0; i < VFS_MAX_FILES; i++)
vfs_files[i].flags = 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(" out", VFS_FILE_WRITE);
vfs_open(" err", VFS_FILE_WRITE);
diff --git a/src/kernel/vfs.h b/src/kernel/vfs.h
index ccad67b..be73941 100644
--- a/src/kernel/vfs.h
+++ b/src/kernel/vfs.h
@@ -143,3 +143,4 @@ int vfs_seek(int fd, int32_t offset, int whence);
int32_t vfs_tell(int fd);
#endif // VFS_H_
+