aboutsummaryrefslogtreecommitdiffstats
path: root/src/kernel
diff options
context:
space:
mode:
authorClyne Sullivan <tullivan99@gmail.com>2018-11-29 20:43:06 -0500
committerClyne Sullivan <tullivan99@gmail.com>2018-11-29 20:43:06 -0500
commit563c92e6d08c305cb9f7693818ecbe2a2dec527b (patch)
tree5b8a6dcdad1daa64dc3a73e3dc9385b85b2c9200 /src/kernel
parent22615096dee294f63c6940c17f2a448da51d9197 (diff)
hello world from initrd
Diffstat (limited to 'src/kernel')
-rw-r--r--src/kernel/Makefile22
-rw-r--r--src/kernel/clock.c30
-rw-r--r--src/kernel/clock.h12
-rw-r--r--src/kernel/elf.c136
-rw-r--r--src/kernel/elf.h124
-rw-r--r--src/kernel/fault.c21
-rw-r--r--src/kernel/init.c2
-rw-r--r--src/kernel/serial.c2
-rw-r--r--src/kernel/svc.c3
-rw-r--r--src/kernel/task.c20
-rw-r--r--src/kernel/vfs.c72
-rw-r--r--src/kernel/vfs.h111
12 files changed, 505 insertions, 50 deletions
diff --git a/src/kernel/Makefile b/src/kernel/Makefile
index d22fbf3..ce23a89 100644
--- a/src/kernel/Makefile
+++ b/src/kernel/Makefile
@@ -1,9 +1,29 @@
+##
+# @file Makefile
+# Script to build folder of source files
+#
+# 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/>.
+#
+
CFILES = $(wildcard *.c)
AFILES = $(wildcard *.s)
OFILES = $(patsubst %.c, %.o, $(CFILES)) \
$(patsubst %.s, %.asm.o, $(AFILES))
-CFLAGS += -I.. -I../arch/cmsis
+CFLAGS += -ffreestanding -nostdlib -I.. -I../arch/cmsis
all: $(OFILES)
diff --git a/src/kernel/clock.c b/src/kernel/clock.c
index 950f4ca..a49b4c1 100644
--- a/src/kernel/clock.c
+++ b/src/kernel/clock.c
@@ -23,20 +23,18 @@
#include <arch/stm/stm32l476xx.h>
// ticks since init
-volatile uint32_t ticks = 0;
+volatile uint32_t clock_ticks = 0;
volatile uint8_t tim2_finished = 1;
-extern task_t *current;
-
void clock_svc(uint32_t *args)
{
if (args[0] == 0)
task_sleep(args[1]);
else if (args[0] == 1)
- udelay(args[1]);
+ clock_udelay(args[1]);
else if (args[0] == 2)
- *((unsigned int *)args[1]) = ticks;
+ *((unsigned int *)args[1]) = clock_millis();
}
void clock_init(void)
@@ -79,18 +77,13 @@ void clock_init(void)
TIM2->CR1 |= TIM_CR1_OPM | TIM_CR1_CEN;
}
-uint32_t millis(void)
-{
- return ticks;
-}
-
-void delay(uint32_t count)
+void clock_delay(uint32_t count)
{
- uint32_t target = ticks + count;
- while (ticks < target);
+ uint32_t target = clock_ticks + count;
+ while (clock_ticks < target);
}
-void udelay(uint32_t count)
+void clock_udelay(uint32_t count)
{
tim2_finished = 0;
TIM2->ARR = count;
@@ -98,13 +91,18 @@ void udelay(uint32_t count)
while (tim2_finished == 0);
}
+uint32_t clock_millis(void)
+{
+ return clock_ticks;
+}
+
void SysTick_Handler(void)
{
// just keep counting
- ticks++;
+ clock_ticks++;
// task switch every four ticks (4ms)
- if (!(ticks & 3))
+ if (!(clock_ticks & 3))
SCB->ICSR |= SCB_ICSR_PENDSVSET_Msk;
}
diff --git a/src/kernel/clock.h b/src/kernel/clock.h
index 3ec7857..e5e46c4 100644
--- a/src/kernel/clock.h
+++ b/src/kernel/clock.h
@@ -28,18 +28,22 @@
*/
extern void clock_init(void);
-uint32_t millis(void);
-
/**
* Sleeps for given amount of milliseconds.
* @param ms Number of milliseconds to sleep for
*/
-void delay(uint32_t ms);
+void clock_delay(uint32_t ms);
/**
* Sleeps for the given amount of microseconds.
* @param count Number of microseconds to sleep for
*/
-void udelay(uint32_t count);
+void clock_udelay(uint32_t count);
+
+/**
+ * Returns the number of milliseconds since clock initialization.
+ * @return milliseconds since init
+ */
+uint32_t clock_millis(void);
#endif // CLOCK_H_
diff --git a/src/kernel/elf.c b/src/kernel/elf.c
new file mode 100644
index 0000000..77333a9
--- /dev/null
+++ b/src/kernel/elf.c
@@ -0,0 +1,136 @@
+/**
+ * @file elf.c
+ * Functionality to execute ELF files
+ *
+ * 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 "elf.h"
+#include "vfs.h"
+#include "heap.h"
+
+#include <string.h>
+
+Elf32_Shdr *elf_find_section(Elf32_Ehdr *ehdr, const char *name)
+{
+ Elf32_Shdr *shdr = (Elf32_Shdr *)((char *)ehdr + ehdr->e_shoff);
+ Elf32_Shdr *shdr_str = (Elf32_Shdr *)((char *)ehdr + ehdr->e_shoff +
+ ehdr->e_shstrndx * ehdr->e_shentsize);
+
+ for (Elf32_Half i = 0; i < ehdr->e_shnum; i++) {
+ char *section = ((char *)ehdr + shdr_str->sh_offset) +
+ shdr->sh_name;
+ if (!strcmp(section, name))
+ return shdr;
+
+ shdr = (Elf32_Shdr *)((char *)shdr + ehdr->e_shentsize);
+ }
+
+ return 0;
+}
+
+uint32_t elf_execve(const char *file, char * const argv[], char * const envp[])
+{
+ (void)argv;
+ (void)envp;
+
+ // Open the given file
+ int fd = vfs_open(file, VFS_FILE_READ);
+ if (fd == -1)
+ return -1;
+
+ // Get file size
+ vfs_seek(fd, 0, SEEK_END);
+ unsigned int fileLength = vfs_tell(fd);
+ vfs_seek(fd, 0, SEEK_SET);
+
+ // Read entire file
+ char *elfData = malloc(fileLength);
+ if (vfs_read(fd, fileLength, (uint8_t *)elfData) != fileLength) {
+ vfs_close(fd);
+ free(elfData);
+ return -1;
+ }
+
+ // ELF signature check
+ if (elfData[0] != '\177' || elfData[1] != 'E' || elfData[2] != 'L' ||
+ elfData[3] != 'F') {
+ vfs_close(fd);
+ free(elfData);
+ return -1;
+ }
+
+
+ uint32_t ELF_OFFSET = 0;
+
+ // Load program headers
+ Elf32_Ehdr *ehdr = (Elf32_Ehdr *)elfData;
+ Elf32_Phdr *phdr = (Elf32_Phdr *)(elfData + ehdr->e_phoff);
+
+ for (Elf32_Half i = 0; i < ehdr->e_phnum; i++) {
+ if (phdr->p_type == PT_LOAD) {
+ // There should only be one PT_LOAD section...
+ if (ELF_OFFSET != 0)
+ while (1);
+ ELF_OFFSET = (uint32_t)malloc(phdr->p_memsz + 8) & ~7;
+
+ 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++)
+ dst[j] = src[j];
+ }
+
+ phdr = (Elf32_Phdr *)((char *)phdr + ehdr->e_phentsize);
+ }
+
+ // Zero the .bss section
+ Elf32_Shdr *bssSection = elf_find_section(ehdr, ".bss");
+ if (bssSection != 0) {
+ uint32_t *bssArray = (Elf32_Addr *)(ELF_OFFSET + bssSection->sh_addr);
+ Elf32_Word bssSize = bssSection->sh_size / sizeof(void *);
+ for (Elf32_Word i = 0; i < bssSize; i++)
+ bssArray[i] = 0;
+ }
+
+ // Fix GOT entries if they exist
+ Elf32_Shdr *gotSection = elf_find_section(ehdr, ".got");
+ if (gotSection != 0) {
+ Elf32_Addr *gotArray = (Elf32_Addr *)(ELF_OFFSET + gotSection->sh_addr);
+ Elf32_Word gotSize = gotSection->sh_size / sizeof(void *);
+ for (Elf32_Word i = 0; i < gotSize; i++)
+ gotArray[i] += ELF_OFFSET;
+ }
+
+ // Run any constructors
+ Elf32_Shdr *initArraySection = elf_find_section(ehdr, ".init_array");
+ if (initArraySection != 0) {
+ Elf32_Addr *initArray = (Elf32_Addr *)(ELF_OFFSET +
+ initArraySection->sh_addr);
+
+ Elf32_Word initArraySize = initArraySection->sh_size / sizeof(void *);
+ for (Elf32_Word i = 0; i < initArraySize; i++) {
+ initArray[i] += ELF_OFFSET;
+ ((void (*)(void))(initArray[i]))();
+ }
+ }
+
+ vfs_close(fd);
+ free(elfData);
+
+ // Return entry point
+ return (ELF_OFFSET + ehdr->e_entry);
+}
+
diff --git a/src/kernel/elf.h b/src/kernel/elf.h
new file mode 100644
index 0000000..9143401
--- /dev/null
+++ b/src/kernel/elf.h
@@ -0,0 +1,124 @@
+/**
+ * @file elf.h
+ * Functionality to execute ELF files
+ *
+ * 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 ELF_H_
+#define ELF_H_
+
+#include <stdint.h>
+
+/**
+ * Attempts to open the given ELF file.
+ * @param file Path of the ELF file
+ * @param argv argv to be passed to the program
+ * @param envp envp to be passed to the program
+ * @return -1 on fail, otherwise returns address of ELF entry
+ */
+uint32_t elf_execve(const char *file, char * const argv[], char * const envp[]);
+
+//
+// ELF Standard macros and structures below
+
+#define EI_NIDENT 16
+
+#define PT_NULL 0
+#define PT_LOAD 1
+#define PT_DYNAMIC 2
+#define PT_INTERP 3
+#define PT_NOTE 4
+#define PT_SHLIB 5
+#define PT_PHDR 6
+#define PT_RESERVED 0x70000000
+
+#define ELF32_ST_BIND(i) ((i) >> 4)
+#define ELF32_ST_TYPE(i) ((i) & 0xF)
+#define ELF32_ST_INFO(b, t) (((b) << 4) + ((t) & 0xF))
+
+#define ELF32_R_SYM(i) ((i) >> 8)
+#define ELF32_R_TYPE(i) ((i) & 0xFF)
+#define ELF32_R_INFO(s, t) (((s) << 8) + ((t) & 0xFF))
+
+typedef uint32_t Elf32_Addr;
+typedef uint16_t Elf32_Half;
+typedef uint32_t Elf32_Off;
+typedef uint32_t Elf32_Sword;
+typedef uint32_t Elf32_Word;
+
+typedef struct {
+ unsigned char e_ident[EI_NIDENT];
+ Elf32_Half e_type;
+ Elf32_Half e_machine;
+ Elf32_Word e_version;
+ Elf32_Addr e_entry;
+ Elf32_Off e_phoff;
+ Elf32_Off e_shoff;
+ Elf32_Word e_flags;
+ Elf32_Half e_ehsize;
+ Elf32_Half e_phentsize;
+ Elf32_Half e_phnum;
+ Elf32_Half e_shentsize;
+ Elf32_Half e_shnum;
+ Elf32_Half e_shstrndx;
+} __attribute__((packed)) Elf32_Ehdr;
+
+typedef struct {
+ Elf32_Word sh_name;
+ Elf32_Word sh_type;
+ Elf32_Word sh_flags;
+ Elf32_Addr sh_addr;
+ Elf32_Off sh_offset;
+ Elf32_Word sh_size;
+ Elf32_Word sh_link;
+ Elf32_Word sh_info;
+ Elf32_Word sh_addralign;
+ Elf32_Word sh_entsize;
+} __attribute__((packed)) Elf32_Shdr;
+
+typedef struct {
+ Elf32_Word st_name;
+ Elf32_Addr st_value;
+ Elf32_Word st_size;
+ unsigned char st_info;
+ unsigned char st_other;
+ Elf32_Half st_shndx;
+} __attribute__((packed)) Elf32_Sym;
+
+typedef struct {
+ Elf32_Addr r_offset;
+ Elf32_Word r_info;
+} __attribute__((packed)) Elf32_Rel;
+
+typedef struct {
+ Elf32_Addr r_offset;
+ Elf32_Word r_info;
+ Elf32_Sword r_addend;
+} __attribute__((packed)) Elf32_Rela;
+
+typedef struct {
+ Elf32_Word p_type;
+ Elf32_Off p_offset;
+ Elf32_Addr p_vaddr;
+ Elf32_Addr p_paddr;
+ Elf32_Word p_filesz;
+ Elf32_Word p_memsz;
+ Elf32_Word p_flags;
+ Elf32_Word p_align;
+} __attribute__((packed)) Elf32_Phdr;
+
+#endif // ELF_H_
diff --git a/src/kernel/fault.c b/src/kernel/fault.c
index dd491c4..db81c1f 100644
--- a/src/kernel/fault.c
+++ b/src/kernel/fault.c
@@ -1,5 +1,26 @@
+/**
+ * @file fault.c
+ * Fault managing functions
+ *
+ * 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/>.
+ */
+
__attribute__ ((naked))
void HardFault_Handler(void)
{
+ // TODO have a real fault handler...
while (1);
}
diff --git a/src/kernel/init.c b/src/kernel/init.c
index 3bd6b39..48e1800 100644
--- a/src/kernel/init.c
+++ b/src/kernel/init.c
@@ -63,5 +63,5 @@ void init_idle(void)
task_start(user_main, 4096);
while (1)
- delay(10);
+ clock_delay(10);
}
diff --git a/src/kernel/serial.c b/src/kernel/serial.c
index 6f112a8..2737b7d 100644
--- a/src/kernel/serial.c
+++ b/src/kernel/serial.c
@@ -44,7 +44,7 @@ void serial_put(int c)
char serial_get(void)
{
while (!(USART2->ISR & USART_ISR_RXNE))
- delay(10);
+ clock_delay(10);
return USART2->RDR & 0xFF;
}
diff --git a/src/kernel/svc.c b/src/kernel/svc.c
index cf1fbe2..1455841 100644
--- a/src/kernel/svc.c
+++ b/src/kernel/svc.c
@@ -1,6 +1,6 @@
/**
* @file svc.c
- * An unused handler for SVC calls
+ * Handler code for SVC calls
*
* Copyright (C) 2018 Clyne Sullivan
*
@@ -48,6 +48,7 @@ void SVC_Handler(void) {
* 2 - getpid
* 3 - waitpid
* 4 - sbrk (TODO bad)
+ * 5 - execve
*/
task_svc(args);
break;
diff --git a/src/kernel/task.c b/src/kernel/task.c
index c5e5e96..c5d09d4 100644
--- a/src/kernel/task.c
+++ b/src/kernel/task.c
@@ -19,6 +19,7 @@
*/
#include "clock.h"
+#include "elf.h"
#include "heap.h"
#include "task.h"
#include <arch/stm/stm32l476xx.h>
@@ -49,6 +50,10 @@ void task_svc(uint32_t *args)
case 4:
*((void **)args[2]) = task_sbrk(args[1]);
break;
+ case 5:
+ *((uint32_t *)args[4]) = elf_execve((const char *)args[1],
+ (char * const *)args[2], (char * const *)args[3]);
+ break;
default:
break;
}
@@ -56,18 +61,19 @@ void task_svc(uint32_t *args)
void *task_sbrk(uint32_t bytes)
{
- if (task_current->heap == 0) {
+ return malloc(bytes);
+
+ /*if (task_current->heap == 0)
task_current->heap = malloc(1024 * 16);
- return (uint8_t *)task_current->heap + (1024 * 16);
- }
if (bytes == 0) {
alloc_t *alloc = (alloc_t *)((uint8_t *)task_current->heap -
sizeof(alloc_t));
- return (uint8_t *)task_current->heap + alloc->size;
+ return (uint8_t *)(((uint32_t)task_current->heap + alloc->size)
+ & ~0xFFF);
}
- return (void *)-1;
+ return (void *)-1;*/
}
void task_hold(uint8_t hold)
@@ -81,7 +87,7 @@ void task_hold(uint8_t hold)
void task_sleep(uint32_t ms)
{
task_current->status.state = TASK_SLEEPING;
- task_current->status.value = millis() + ms;
+ task_current->status.value = clock_millis() + ms;
YIELD;
}
@@ -312,7 +318,7 @@ void PendSV_Handler(void)
" : "=r" (task_current->sp));
// Load next task
- uint32_t ticks = millis();
+ uint32_t ticks = clock_millis();
do {
task_current = task_current->next;
if (task_current == 0)
diff --git a/src/kernel/vfs.c b/src/kernel/vfs.c
index 6236691..b9be9bc 100644
--- a/src/kernel/vfs.c
+++ b/src/kernel/vfs.c
@@ -1,3 +1,23 @@
+/**
+ * @file vfs.c
+ * An implementation of filesystem abstraction
+ *
+ * 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 "vfs.h"
#include <kernel/task.h>
@@ -10,6 +30,11 @@
static vfs_volume vfs_volumes[VFS_MAX_VOLS];
static vfs_file vfs_files[VFS_MAX_FILES];
+#define VFS_PID_CHECK(fpid) { \
+ uint32_t pid = task_getpid(); \
+ if (pid != fpid && fpid != 0) \
+ return 0; }
+
void vfs_svc(uint32_t *args)
{
switch (args[0]) {
@@ -114,7 +139,8 @@ int vfs_open(const char *path, uint32_t flags)
vfs_files[file].flags = VFS_FILE_OPEN | flags;
vfs_files[file].vol = drive;
vfs_files[file].pid = task_getpid();
- vfs_files[file].fsinfo = fsinfo;
+ vfs_files[file].info.pos = 0;
+ vfs_files[file].info.fsinfo = fsinfo;
return file;
}
@@ -125,14 +151,13 @@ int vfs_close(int fd)
return -1;
if (vfs_volumes[vfs_files[fd].vol].funcs->close == 0)
return -1;
- if (vfs_files[fd].pid != task_getpid())
- return -1;
+ VFS_PID_CHECK(vfs_files[fd].pid);
if (!(vfs_files[fd].flags & VFS_FILE_OPEN))
return 0;
// TODO care
/*int ret =*/ vfs_volumes[vfs_files[fd].vol].funcs->close(
- vfs_files[fd].fsinfo);
+ &vfs_files[fd].info);
vfs_files[fd].flags = 0;
vfs_files[fd].pid = 0;
@@ -143,16 +168,17 @@ uint32_t vfs_read(int fd, uint32_t count, uint8_t *buffer)
{
if (fd < 0 || fd > VFS_MAX_FILES || count == 0 || buffer == 0)
return 0;
+ if (!(vfs_files[fd].flags & VFS_FILE_OPEN))
+ return -1;
if (vfs_volumes[vfs_files[fd].vol].funcs->read == 0)
return -1;
- if (vfs_files[fd].pid != task_getpid())
- return 0;
+ VFS_PID_CHECK(vfs_files[fd].pid);
if ((!(vfs_files[fd].flags & VFS_FILE_READ)) || (vfs_files[fd].flags &
VFS_EOF))
return 0;
uint32_t ret = vfs_volumes[vfs_files[fd].vol].funcs->read(
- vfs_files[fd].fsinfo, count, buffer);
+ &vfs_files[fd].info, count, buffer);
if (ret < count)
vfs_files[fd].flags |= VFS_EOF;
@@ -164,17 +190,18 @@ uint32_t vfs_write(int fd, uint32_t count, const uint8_t *buffer)
{
if (fd < 0 || fd > VFS_MAX_FILES || count == 0 || buffer == 0)
return 0;
+ if (!(vfs_files[fd].flags & VFS_FILE_OPEN))
+ return -1;
if (vfs_volumes[vfs_files[fd].vol].funcs->write == 0)
return -1;
- if (vfs_files[fd].pid != task_getpid())
- return 0;
+ VFS_PID_CHECK(vfs_files[fd].pid);
// TODO append?
if ((!(vfs_files[fd].flags & VFS_FILE_WRITE)) || (vfs_files[fd].flags &
VFS_EOF))
return 0;
uint32_t ret = vfs_volumes[vfs_files[fd].vol].funcs->write(
- vfs_files[fd].fsinfo, count, buffer);
+ &vfs_files[fd].info, count, buffer);
if (ret < count)
vfs_files[fd].flags |= VFS_EOF;
@@ -182,3 +209,28 @@ uint32_t vfs_write(int fd, uint32_t count, const uint8_t *buffer)
return ret;
}
+int vfs_seek(int fd, int32_t offset, int whence)
+{
+ if (fd < 0 || fd > VFS_MAX_FILES)
+ return -1;
+ if (!(vfs_files[fd].flags & VFS_FILE_OPEN))
+ return -1;
+ if (vfs_volumes[vfs_files[fd].vol].funcs->seek == 0)
+ return -1;
+ VFS_PID_CHECK(vfs_files[fd].pid);
+
+ return vfs_volumes[vfs_files[fd].vol].funcs->seek(&vfs_files[fd].info,
+ offset, whence);
+}
+
+int32_t vfs_tell(int fd)
+{
+ if (fd < 0 || fd > VFS_MAX_FILES)
+ return -1;
+ if (!(vfs_files[fd].flags & VFS_FILE_OPEN))
+ return -1;
+ VFS_PID_CHECK(vfs_files[fd].pid);
+
+ return (int32_t)vfs_files[fd].info.pos;
+}
+
diff --git a/src/kernel/vfs.h b/src/kernel/vfs.h
index 89213f9..ccad67b 100644
--- a/src/kernel/vfs.h
+++ b/src/kernel/vfs.h
@@ -1,18 +1,95 @@
+/**
+ * @file vfs.h
+ * An implementation of filesystem abstraction
+ *
+ * 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 VFS_H_
#define VFS_H_
#include <stdint.h>
+/**
+ * Holds file info that can be used by filesystem drivers/modules.
+ */
+typedef struct {
+ uint32_t pos; /**< Position within the file */
+ void *fsinfo; /**< Filesystem-specific data, handled by fs driver */
+} vfs_file_info;
+
+/**
+ * Directory entry data, used by readdir.
+ */
typedef struct {
char name[32];
} vfs_dirent;
+/**
+ * Functions that a filesystem driver/module should implement.
+ */
typedef struct vfs_volume_funcs_t {
+ /**
+ * Opens the given file.
+ * @param file Path to the file
+ * @return 0 on fail, otherwise pointer to be stored in
+ * vfs_file_info.fsinfo
+ */
void *(*open)(const char *file);
- int (*close)(void *info);
- uint32_t (*read)(void *info, uint32_t count, uint8_t *buffer);
- uint32_t (*write)(void *info, uint32_t count, const uint8_t *buffer);
+
+ /**
+ * Closes the file, releasing given info however necessary.
+ * @param info File info
+ * @return 0 on success, non-zero on failure
+ */
+ int (*close)(vfs_file_info *info);
+
+ /**
+ * Reads bytes from the given file.
+ * @param info Info on the file
+ * @param count Number of bytes to read
+ * @param buffer Pre-allocated buffer to store data to
+ * @return Number of bytes read
+ */
+ uint32_t (*read)(vfs_file_info *info, uint32_t count, uint8_t *buffer);
+
+ /**
+ * Writes bytes from the given file.
+ * @param info Info on the file
+ * @param count Number of bytes to write
+ * @param buffer Data to write to file
+ * @return Number of bytes written
+ */
+ uint32_t (*write)(vfs_file_info *info, uint32_t count, const uint8_t *buffer);
+
+ /**
+ * Creates an array of vfs_dirent for the given directory.
+ * @param path Directory to read
+ * @return 0 on fail, an array of vfs_dirent otherwise
+ */
vfs_dirent *(*readdir)(const char *path);
+
+ /**
+ * Seeks file to the given position.
+ * @param info The file's info
+ * @param offset Offset to seek to
+ * @param whence Where to seek from (beginning, end, or current pos.)
+ * @return 0 on succes, non-zero otherwise
+ */
+ int (*seek)(vfs_file_info *info, uint32_t offset, int whence);
} vfs_volume_funcs;
// Indicates mounted volume
@@ -20,9 +97,12 @@ typedef struct vfs_volume_funcs_t {
// Set if filesystem is read-only
#define VFS_READONLY (1 << 1)
+/**
+ * Data defining a VFS volume.
+ */
typedef struct {
- uint32_t flags;
- const vfs_volume_funcs *funcs;
+ uint32_t flags; /**< Flags regarding volume state */
+ const vfs_volume_funcs *funcs; /**< Volume-managing functions */
} vfs_volume;
// Indicates an opened file
@@ -34,13 +114,19 @@ typedef struct {
// Set if EOF has been reached
#define VFS_EOF (1 << 3)
+/**
+ * Contains data to manage open files.
+ */
typedef struct {
- uint32_t flags; /**< File attribute flags */
- uint32_t vol; /**< Index of volume file is stored on */
- uint32_t pid; /**< PID of process handling this file */
- void *fsinfo; /**< Filesystem-specific data, handled by fs driver */
+ uint32_t flags; /**< File attribute flags */
+ uint32_t vol; /**< Index of volume file is stored on */
+ uint32_t pid; /**< PID of process handling this file */
+ vfs_file_info info; /**< File info used by file IO functions */
} vfs_file;
+/**
+ * Initializes the filesystem abstraction layer.
+ */
void vfs_init(void);
int vfs_mount(const vfs_volume_funcs *funcs, uint32_t flags);
@@ -49,4 +135,11 @@ int vfs_close(int fd);
uint32_t vfs_read(int fd, uint32_t count, uint8_t *buffer);
uint32_t vfs_write(int fd, uint32_t count, const uint8_t *buffer);
+#define SEEK_SET 0
+#define SEEK_CUR 1
+#define SEEK_END 2
+
+int vfs_seek(int fd, int32_t offset, int whence);
+int32_t vfs_tell(int fd);
+
#endif // VFS_H_