aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorClyne Sullivan <tullivan99@gmail.com>2018-11-04 23:46:12 -0500
committerClyne Sullivan <tullivan99@gmail.com>2018-11-04 23:46:12 -0500
commit2f719330b8afee5075b48d428c836e2c0a3bb14e (patch)
treeda51902d1659383016cec9cbfbab34f2ec9a7826
parent3a798edb836a30f612b6dd40334b69a2dbeeca22 (diff)
vfs, initrd
-rw-r--r--.gitignore2
-rw-r--r--Makefile8
-rw-r--r--initrd/hello1
-rw-r--r--src/fs/Makefile22
-rw-r--r--src/fs/initrd.c97
-rw-r--r--src/fs/initrd.h6
-rw-r--r--src/kernel/init.c4
-rw-r--r--src/kernel/svc.c7
-rw-r--r--src/kernel/task.c5
-rw-r--r--src/kernel/task.h11
-rw-r--r--src/kernel/vfs.c124
-rw-r--r--src/kernel/vfs.h56
-rw-r--r--src/user/user.c11
-rwxr-xr-xtools/rbabin0 -> 14664 bytes
-rw-r--r--tools/rba.cpp72
15 files changed, 385 insertions, 41 deletions
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 <stdint.h>
+#include <string.h>
+
+#include <kernel/heap.h>
+#include <kernel/vfs.h>
+
+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 <fs/initrd.h>
#include <arch/stm/stm32l476xx.h>
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 <stdint.h>
#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 <kernel/task.h>
-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 <stdint.h>
-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 <kernel/clock.h>
#include "priv_gpio.h"
-#include <kernel/task.h>
+
+#include <kernel/clock.h>
+#include <kernel/heap.h>
+#include <kernel/vfs.h>
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 0000000..52f37cb
--- /dev/null
+++ b/tools/rba
Binary files differ
diff --git a/tools/rba.cpp b/tools/rba.cpp
new file mode 100644
index 0000000..03ae1d9
--- /dev/null
+++ b/tools/rba.cpp
@@ -0,0 +1,72 @@
+/**
+ * @file rba.cpp
+ * A "really basic archiver"
+ *
+ * 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 <iostream>
+#include <fstream>
+#include <string>
+#include <cstdint>
+
+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;
+}