diff options
author | Clyne Sullivan <tullivan99@gmail.com> | 2018-11-29 20:43:06 -0500 |
---|---|---|
committer | Clyne Sullivan <tullivan99@gmail.com> | 2018-11-29 20:43:06 -0500 |
commit | 563c92e6d08c305cb9f7693818ecbe2a2dec527b (patch) | |
tree | 5b8a6dcdad1daa64dc3a73e3dc9385b85b2c9200 /src/kernel | |
parent | 22615096dee294f63c6940c17f2a448da51d9197 (diff) |
hello world from initrd
Diffstat (limited to 'src/kernel')
-rw-r--r-- | src/kernel/Makefile | 22 | ||||
-rw-r--r-- | src/kernel/clock.c | 30 | ||||
-rw-r--r-- | src/kernel/clock.h | 12 | ||||
-rw-r--r-- | src/kernel/elf.c | 136 | ||||
-rw-r--r-- | src/kernel/elf.h | 124 | ||||
-rw-r--r-- | src/kernel/fault.c | 21 | ||||
-rw-r--r-- | src/kernel/init.c | 2 | ||||
-rw-r--r-- | src/kernel/serial.c | 2 | ||||
-rw-r--r-- | src/kernel/svc.c | 3 | ||||
-rw-r--r-- | src/kernel/task.c | 20 | ||||
-rw-r--r-- | src/kernel/vfs.c | 72 | ||||
-rw-r--r-- | src/kernel/vfs.h | 111 |
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_ |