From 2f719330b8afee5075b48d428c836e2c0a3bb14e Mon Sep 17 00:00:00 2001 From: Clyne Sullivan Date: Sun, 4 Nov 2018 23:46:12 -0500 Subject: [PATCH] vfs, initrd --- .gitignore | 2 + Makefile | 8 ++- initrd/hello | 1 + src/fs/Makefile | 22 ++++++++ src/fs/initrd.c | 97 ++++++++++++++++++++++++++++++++++++ src/fs/initrd.h | 6 +++ src/kernel/init.c | 4 ++ src/kernel/svc.c | 7 +++ src/kernel/task.c | 5 -- src/kernel/task.h | 11 ++-- src/kernel/vfs.c | 124 ++++++++++++++++++++++++++++++++++++++++++---- src/kernel/vfs.h | 56 +++++++++++++-------- src/user/user.c | 11 +++- tools/rba | Bin 0 -> 14664 bytes tools/rba.cpp | 72 +++++++++++++++++++++++++++ 15 files changed, 385 insertions(+), 41 deletions(-) create mode 100644 initrd/hello create mode 100644 src/fs/Makefile create mode 100644 src/fs/initrd.c create mode 100644 src/fs/initrd.h create mode 100755 tools/rba create mode 100644 tools/rba.cpp diff --git a/.gitignore b/.gitignore index 8bbd2c8..56b48db 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,5 @@ *.o *.swp *.swo +initrd.img +main.elf diff --git a/Makefile b/Makefile index c131a32..0d4d85c 100644 --- a/Makefile +++ b/Makefile @@ -21,6 +21,7 @@ CROSS = arm-none-eabi- CC = gcc AS = as +OBJCOPY = objcopy MCUFLAGS = -mthumb -mcpu=cortex-m4 #-mfloat-abi=hard -mfpu=fpv4-sp-d16 AFLAGS = $(MCUFLAGS) @@ -37,14 +38,19 @@ export all: @$(MAKE) -C src/kernel + @$(MAKE) -C src/fs @$(MAKE) -C src/user + @echo " INITRD" + @tools/rba initrd.img $$(find initrd/*) + @$(CROSS)$(OBJCOPY) -B arm -I binary -O elf32-littlearm initrd.img initrd.img.o @echo " LINK " $(OUT) - @$(CROSS)$(CC) $(CFLAGS) $(LFLAGS) -o $(OUT) $$(find src/ -name "*.o") + @$(CROSS)$(CC) $(CFLAGS) $(LFLAGS) -o $(OUT) $$(find src/ -name "*.o") initrd.img.o clean: @echo " CLEAN" @$(MAKE) -C src/kernel clean + @$(MAKE) -C src/fs clean @$(MAKE) -C src/user clean @rm -f $(OUT) diff --git a/initrd/hello b/initrd/hello new file mode 100644 index 0000000..5d437a5 --- /dev/null +++ b/initrd/hello @@ -0,0 +1 @@ +Hello, world!! diff --git a/src/fs/Makefile b/src/fs/Makefile new file mode 100644 index 0000000..d22fbf3 --- /dev/null +++ b/src/fs/Makefile @@ -0,0 +1,22 @@ +CFILES = $(wildcard *.c) +AFILES = $(wildcard *.s) +OFILES = $(patsubst %.c, %.o, $(CFILES)) \ + $(patsubst %.s, %.asm.o, $(AFILES)) + +CFLAGS += -I.. -I../arch/cmsis + +all: $(OFILES) + +%.o: %.c + @echo " CC " $< + @$(CROSS)$(CC) $(CFLAGS) -c $< -o $@ + +%.asm.o: %.s + @echo " AS " $< + @$(CROSS)$(AS) $(AFLAGS) -c $< -o $@ + +clean: + @echo " CLEAN" + @rm -f $(OFILES) + + diff --git a/src/fs/initrd.c b/src/fs/initrd.c new file mode 100644 index 0000000..efa430c --- /dev/null +++ b/src/fs/initrd.c @@ -0,0 +1,97 @@ +#include +#include + +#include +#include + +typedef struct { + char *address; + uint32_t pos; + uint32_t size; +} initrd_info; + +extern uint8_t _binary_initrd_img_start[]; +extern uint8_t _binary_initrd_img_size[]; + +static const uint8_t *initrd_start = (uint8_t *)_binary_initrd_img_start; +static const uint32_t initrd_size = (uint32_t)_binary_initrd_img_size; + +void *initrd_open(const char *file); +uint32_t initrd_read(void *info, uint32_t count, uint8_t *buffer); + +char *initrd_getfile(uint32_t offset); + +static const vfs_volume_funcs initrd_funcs = { + initrd_open, + 0, // close + initrd_read, + 0, // write + 0 // readdir +}; + +void initrd_init(void) +{ + vfs_mount(&initrd_funcs, VFS_READONLY); +} + +void *initrd_open(const char *file) +{ + char *ptr; + for (uint32_t i = 0; ptr = initrd_getfile(i), ptr != 0; i++) { + uint32_t len = *((uint32_t *)ptr); + if (!strncmp(file, ptr + 4, len)) { + initrd_info *file = (initrd_info *)malloc( + sizeof(initrd_info)); + file->address = ptr + len + 8; + file->pos = 0; + file->size = *(uint32_t *)(ptr + len + 4); + return file; + } + } + + return 0; +} + +uint32_t initrd_read(void *info, uint32_t count, uint8_t *buffer) +{ + initrd_info *iinfo = (initrd_info *)info; + if (iinfo == 0 || iinfo->address == 0) + return 0; + + uint32_t i; + for (i = 0; i < count; i++) { + if (iinfo->pos >= iinfo->size) + break; + + buffer[iinfo->pos] = iinfo->address[iinfo->pos]; + iinfo->pos++; + } + + return i; +} + +/*char *readfile(const char *name) +{ + char *ptr; + for (uint32_t i = 0; ptr = getfile(i), ptr != 0; i++) { + uint32_t len = *((uint32_t *)ptr); + if (!strncmp(name, ptr + 4, len)) + return ptr + len + 8; + } + return 0; +}*/ + +char *initrd_getfile(uint32_t offset) +{ + char *ptr = (char *)initrd_start; + for (uint32_t i = 0; i < offset; i++) { + uint32_t len = *((uint32_t *)ptr); + uint32_t datalen = *((uint32_t *)(ptr + 4 + len)); + ptr += len + datalen + 8; + if (ptr >= (char *)(initrd_start + initrd_size)) + return 0; + } + + return ptr; +} + diff --git a/src/fs/initrd.h b/src/fs/initrd.h new file mode 100644 index 0000000..dbc0079 --- /dev/null +++ b/src/fs/initrd.h @@ -0,0 +1,6 @@ +#ifndef INTIRD_H_ +#define INITRD_H_ + +void initrd_init(void); + +#endif // INITRD_H_ diff --git a/src/kernel/init.c b/src/kernel/init.c index 6bb7eb5..2ba607d 100644 --- a/src/kernel/init.c +++ b/src/kernel/init.c @@ -23,6 +23,7 @@ #include "heap.h" #include "task.h" #include "vfs.h" +#include #include extern uint8_t __bss_end__; @@ -45,6 +46,9 @@ int main(void) heap_init(&__bss_end__); gpio_init(); + vfs_init(); + initrd_init(); + // enable FPU //SCB->CPACR |= (0xF << 20); diff --git a/src/kernel/svc.c b/src/kernel/svc.c index 1e03262..f448ee0 100644 --- a/src/kernel/svc.c +++ b/src/kernel/svc.c @@ -26,6 +26,7 @@ extern void gpio_svc(uint32_t *); extern void clock_svc(uint32_t *); extern void task_svc(uint32_t *); +extern void vfs_svc(uint32_t *args); void SVC_Handler(void) { uint32_t *args; @@ -66,6 +67,12 @@ void SVC_Handler(void) { */ clock_svc(args); break; + case 3: /* Filesystem-related calls + * 0 - mount + * 1 - open + */ + vfs_svc(args); + break; default: break; } diff --git a/src/kernel/task.c b/src/kernel/task.c index e4531db..2550e4b 100644 --- a/src/kernel/task.c +++ b/src/kernel/task.c @@ -30,11 +30,6 @@ static task_t *task_queue; static uint8_t task_disable = 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); - void task_svc(uint32_t *args) { switch (args[0]) { diff --git a/src/kernel/task.h b/src/kernel/task.h index d78e1da..30e3e66 100644 --- a/src/kernel/task.h +++ b/src/kernel/task.h @@ -21,7 +21,6 @@ #ifndef TASK_H_ #define TASK_H_ -#include "vfs.h" #include #define WIFEXITED(w) (w & (1 << 8)) @@ -42,7 +41,6 @@ typedef struct task_t { uint32_t state : 8; uint32_t value : 24; } status; -// vfs_node *cwd; } task_t; enum TASK_STATUS_FLAGS { @@ -76,6 +74,13 @@ void task_hold(uint8_t hold); void task_sleep(uint32_t ms); -//vfs_node *task_getcwd(void); +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); + #endif // TASK_H_ diff --git a/src/kernel/vfs.c b/src/kernel/vfs.c index a0d9bb4..1720a6b 100644 --- a/src/kernel/vfs.c +++ b/src/kernel/vfs.c @@ -1,15 +1,121 @@ #include "vfs.h" -#include "task.h" -//static vfs_node vfs_root; +#include -int vfs_open(const char *path, int mode) +#define VFS_MAX_VOLS 8 +#define VFS_MAX_FILES 10 + +static vfs_volume vfs_volumes[VFS_MAX_VOLS]; +static vfs_file vfs_files[VFS_MAX_FILES]; + +void vfs_svc(uint32_t *args) +{ + switch (args[0]) { + case 0: + *((int *)args[3]) = vfs_mount((vfs_volume_funcs *)args[1], + args[2]); + break; + case 1: + *((int *)args[3]) = vfs_open((const char *)args[1], args[2]); + break; + case 2: + *((int *)args[4]) = vfs_read(args[1], args[2], (uint8_t *)args[3]); + break; + default: + break; + } +} + +void vfs_init(void) +{ + 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; +} + +int vfs_mount(vfs_volume_funcs *funcs, uint32_t flags) +{ + for (int i = 0; i < VFS_MAX_VOLS; i++) { + if (!(vfs_volumes[i].flags && VFS_MOUNTED)) { + vfs_volumes[i].flags = VFS_MOUNTED | flags; + vfs_volumes[i].funcs = funcs; + return i; + } + } + + return -1; +} + +int vfs_get_drive(const char *path) +{ + // Validate parameters + if (path[0] == '\0' || path[1] == '\0' || path[1] != ':' || + path[2] == '\0' || path[2] != '/') + return -1; + + // Find chosen drive + int drive = -1; + for (int i = 0; i < VFS_MAX_VOLS; i++) { + if (path[0] == ('a' + i) || path[0] == ('A' + i)) { + drive = i; + break; + } + } + + if (drive == -1 || !(vfs_volumes[drive].flags && VFS_MOUNTED)) + return -1; + + return drive; +} + +int vfs_open(const char *path, uint32_t flags) +{ + int drive = vfs_get_drive(path); + if (drive == -1) + return -1; + if (vfs_volumes[drive].funcs->open == 0) + return -1; + + // Find available file handle + int file = -1; + for (int i = 0; i < VFS_MAX_FILES; i++) { + if (!(vfs_files[i].flags & VFS_FILE_OPEN)) { + file = i; + break; + } + } + + if (file == -1) + return -1; + + vfs_files[file].flags = VFS_FILE_OPEN | flags; + vfs_files[file].vol = drive; + vfs_files[file].pid = task_getpid(); + vfs_files[file].fsinfo = + vfs_volumes[drive].funcs->open(path + 3); + + return file; +} + +uint32_t vfs_read(int fd, uint32_t count, uint8_t *buffer) { - (void)path; - (void)mode; -// vfs_node *cd = task_getcwd(); -// if (cd == 0) -// cd = &vfs_root; + if (fd < 0 || fd > VFS_MAX_FILES || count == 0 || buffer == 0) + return 0; + if (vfs_volumes[vfs_files[fd].vol].funcs->read == 0) + return -1; + if (vfs_files[fd].pid != task_getpid()) + return 0; + if ((!(vfs_files[fd].flags & VFS_FILE_READ)) || (vfs_files[fd].flags & + VFS_EOF)) + return 0; - return 0; + uint32_t ret = vfs_volumes[vfs_files[fd].vol].funcs->read(vfs_files[fd].fsinfo, + count, buffer); + + if (ret < count) + vfs_files[fd].flags |= VFS_EOF; + + return ret; } + diff --git a/src/kernel/vfs.h b/src/kernel/vfs.h index 6874905..a6de690 100644 --- a/src/kernel/vfs.h +++ b/src/kernel/vfs.h @@ -3,30 +3,44 @@ #include -struct vfs_node; -struct dirent; +typedef struct { + char name[32]; +} vfs_dirent; + +typedef struct { + void *(*open)(const char *file); + void (*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); + vfs_dirent *(*readdir)(const char *path); +} vfs_volume_funcs; + +#define VFS_MOUNTED (1 << 0) +#define VFS_READONLY (1 << 1) 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; + vfs_volume_funcs *funcs; +} vfs_volume; + +#define VFS_FILE_OPEN (1 << 0) +#define VFS_FILE_READ (1 << 1) +#define VFS_FILE_WRITE (1 << 2) +#define VFS_FILE_MODF (1 << 3) +#define VFS_TEMPORARY (1 << 4) +#define VFS_EOF (1 << 5) + +typedef struct { + uint32_t flags; + uint32_t vol; + uint32_t pid; + void *fsinfo; +} vfs_file; + +void vfs_init(void); - struct vfs_node *parent; - union { - struct vfs_node* children; - vfs_driver *access; - } data; -} vfs_node; - -struct dirent { - char *name; - vfs_node *node; -}; +int vfs_mount(vfs_volume_funcs *funcs, uint32_t flags); +int vfs_open(const char *path, uint32_t flags); +uint32_t vfs_read(int fd, uint32_t count, uint8_t *buffer); #endif // VFS_H_ diff --git a/src/user/user.c b/src/user/user.c index 620ffd0..eb2d662 100644 --- a/src/user/user.c +++ b/src/user/user.c @@ -1,6 +1,8 @@ -#include #include "priv_gpio.h" -#include + +#include +#include +#include void user_delay(uint32_t ms) { @@ -28,6 +30,11 @@ void user_main(void) { gpio(GPIO_MODE, 5, OUTPUT); + int test = vfs_open("A:/hello", VFS_FILE_READ); + char *buf = malloc(20); + int count = vfs_read(test, 20, (uint8_t *)buf); + (void)count; + if (fork() == 0) { while (1) { gpio(GPIO_OUT, 5, 1); diff --git a/tools/rba b/tools/rba new file mode 100755 index 0000000000000000000000000000000000000000..52f37cb59cac5d5e55e8bb84700b1e522d162270 GIT binary patch literal 14664 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. + */ + +#include +#include +#include +#include + +int main(int argc, char *argv[]) +{ + // check args + if (argc < 3) { + std::cout << "Usage: " << argv[0] << " archive files...\n"; + return 0; + } + + std::ofstream archive (argv[1], std::ios::out); + for (int i = 2; i < argc; i++) { + // attempt to read file contents + std::string fileName (argv[i]); + std::ifstream contents (fileName, std::ios::in | std::ios::ate); + std::string shortName; + if (auto pos = fileName.rfind('/'); pos != std::string::npos) + shortName = fileName.substr(pos + 1); + else + shortName = fileName; + + if (contents.good()) { + uint32_t size = contents.tellg(); + contents.seekg(0); + std::cout << "Adding file " << fileName <<" (" + << size << " bytes)...\n"; + + // read in file + char *buffer = new char[size]; + contents.read(buffer, size); + + // write name size/text + uint32_t nameSize = shortName.size(); + archive.write((char *)&nameSize, sizeof(uint32_t)); + archive.write(shortName.data(), nameSize); + // write data size/content + archive.write((char *)&size, sizeof(uint32_t)); + archive.write(buffer, size); + + delete[] buffer; + } else { + std::cout << "Failed to add file " << fileName + << ", continuing...\n"; + } + } + + std::cout << "Created archive " << argv[1] << '\n'; + return 0; +}