From 352df42c1793ce29edd813b79ffcaef842360fbd Mon Sep 17 00:00:00 2001 From: Davide Mor <davide.mor@skywarder.eu> Date: Sun, 7 May 2023 01:56:57 +0200 Subject: [PATCH] [angel] Added support for mounting host filesystem --- miosix/CMakeLists.txt | 3 +- miosix/util/angel/angel.cpp | 186 ++++++++++++++++++++------- miosix/util/angel/angel.h | 61 +++++++-- miosix/util/angel/angel_fs.cpp | 194 +++++++++++++++++++++++++++++ miosix/util/angel/angel_fs.h | 39 ++++++ miosix/util/angel/angel_serial.cpp | 26 +++- miosix/util/angel/angel_serial.h | 8 +- 7 files changed, 460 insertions(+), 57 deletions(-) create mode 100644 miosix/util/angel/angel_fs.cpp create mode 100644 miosix/util/angel/angel_fs.h diff --git a/miosix/CMakeLists.txt b/miosix/CMakeLists.txt index 8c1c3865..afeb594d 100644 --- a/miosix/CMakeLists.txt +++ b/miosix/CMakeLists.txt @@ -91,8 +91,9 @@ foreach(OPT_BOARD ${BOARDS}) util/version.cpp util/crc16.cpp util/lcd44780.cpp - util/angel/angel_serial.cpp util/angel/angel.cpp + util/angel/angel_serial.cpp + util/angel/angel_fs.cpp ${ARCH_SRC} ) add_library(Miosix::Miosix::${OPT_BOARD} ALIAS ${MIOSIX_LIBRARY}) diff --git a/miosix/util/angel/angel.cpp b/miosix/util/angel/angel.cpp index 915f3899..f0a5784b 100644 --- a/miosix/util/angel/angel.cpp +++ b/miosix/util/angel/angel.cpp @@ -24,10 +24,10 @@ #include <cstring> -using namespace miosix::angel; +namespace miosix { __attribute__((target("thumb"))) -int miosix::angel::angelswi(int num2, int param2) { +int angel::angelswi(int num2, int param2) { register int num asm("r0") = num2; register int param asm("r1") = param2; register int ret asm("r0"); @@ -42,96 +42,123 @@ int miosix::angel::angelswi(int num2, int param2) { return ret; } -int miosix::angel::sys_clock() { - return angelswi(0x10, 0); +int angel::sys_open(const char *filename, Mode mode) { + struct { + const char *filename; + int mode; + int filename_len; + } params; + + params.filename = filename; + params.mode = mode; + params.filename_len = strlen(filename); + return angelswi(SYS_OPEN, reinterpret_cast<int>(¶ms)); } -int miosix::angel::sys_close(int handle) { +int angel::sys_close(int handle) { struct { int handle; } params; params.handle = handle; - return angelswi(0x02, reinterpret_cast<int>(¶ms)); + return angelswi(SYS_CLOSE, reinterpret_cast<int>(¶ms)); } -int miosix::angel::sys_errno() { - return angelswi(0x13, 0); +void angel::sys_writec(char c) { + angelswi(SYS_WRITEC, reinterpret_cast<int>(&c)); } -int miosix::angel::sys_flen(int handle) { +void angel::sys_write0(const char *str) { + angelswi(SYS_WRITE0, reinterpret_cast<int>(str)); +} + +int angel::sys_write(int handle, const void *buf, int len) { struct { int handle; + const void *buf; + int len; } params; params.handle = handle; - return angelswi(0x0c, reinterpret_cast<int>(¶ms)); + params.buf = buf; + params.len = len; + + return angelswi(SYS_WRITE, reinterpret_cast<int>(¶ms)); } -int miosix::angel::sys_istty(int handle) { +int angel::sys_read(int handle, void *buf, int len) { struct { int handle; + void *buf; + int len; } params; params.handle = handle; - return angelswi(0x09, reinterpret_cast<int>(¶ms)); + params.buf = buf; + params.len = len; + + return angelswi(SYS_READ, reinterpret_cast<int>(¶ms)); +} + +int angel::sys_readc() { + return angelswi(SYS_READC, 0); } -int miosix::angel::sys_open(const char *filename, Mode mode) { +int angel::sys_iserror(int code) { struct { - const char *filename; - int mode; - int filename_len; + int code; } params; - params.filename = filename; - params.mode = mode; - params.filename_len = strlen(filename); + params.code = code; - return angelswi(0x01, reinterpret_cast<int>(¶ms)); + return angelswi(SYS_ISERROR, reinterpret_cast<int>(¶ms)); } -int miosix::angel::sys_read(int handle, void *buf, int len) { +int angel::sys_istty(int handle) { struct { int handle; - void *buf; - int len; } params; params.handle = handle; - params.buf = buf; - params.len = len; - return angelswi(0x06, reinterpret_cast<int>(¶ms)); + return angelswi(SYS_ISTTY, reinterpret_cast<int>(¶ms)); } -int miosix::angel::sys_write(int handle, const void *buf, int len) { +int angel::sys_seek(int handle, int pos) { struct { int handle; - const void *buf; - int len; + int pos; } params; params.handle = handle; - params.buf = buf; - params.len = len; + params.pos = pos; - return angelswi(0x05, reinterpret_cast<int>(¶ms)); + return angelswi(SYS_SEEK, reinterpret_cast<int>(¶ms)); } -int miosix::angel::sys_seek(int handle, int pos) { +int angel::sys_flen(int handle) { struct { int handle; - int pos; } params; params.handle = handle; - params.pos = pos; + return angelswi(SYS_FLEN, reinterpret_cast<int>(¶ms)); +} - return angelswi(0x0a, reinterpret_cast<int>(¶ms)); +int angel::sys_tmpnam(char *buf, int id, int len) { + struct { + char *buf; + int id; + int len; + } params; + + params.buf = buf; + params.id = id; + params.len = len; + return angelswi(SYS_TMPNAM, reinterpret_cast<int>(¶ms)); } -int miosix::angel::sys_remove(const char *filename) { +int angel::sys_remove(const char *filename) { struct { const char *filename; int filename_len; @@ -139,11 +166,10 @@ int miosix::angel::sys_remove(const char *filename) { params.filename = filename; params.filename_len = strlen(filename); - - return angelswi(0x0e, reinterpret_cast<int>(¶ms)); + return angelswi(SYS_REMOVE, reinterpret_cast<int>(¶ms)); } -int miosix::angel::sys_rename(const char *old_filename, const char *new_filename) { +int angel::sys_rename(const char *old_filename, const char *new_filename) { struct { const char *old_filename; int old_filename_len; @@ -155,14 +181,88 @@ int miosix::angel::sys_rename(const char *old_filename, const char *new_filename params.old_filename_len = strlen(old_filename); params.new_filename = new_filename; params.new_filename_len = strlen(new_filename); + return angelswi(SYS_RENAME, reinterpret_cast<int>(¶ms)); +} + +int angel::sys_clock() { + return angelswi(SYS_CLOCK, 0); +} + +int angel::sys_time() { + return angelswi(SYS_TIME, 0); +} + +int angel::sys_system(const char *cmd) { + struct { + const char *cmd; + int cmd_len; + } params; + + params.cmd = cmd; + params.cmd_len = strlen(cmd); + return angelswi(SYS_SYSTEM, reinterpret_cast<int>(¶ms)); +} + +int angel::sys_errno() { + return angelswi(SYS_ERRNO, 0); +} + +int angel::sys_get_cmdline(char *buf, int *len) { + struct { + char *buf; + int len; + } params; + + params.buf = buf; + params.len = *len; - return angelswi(0x0f, reinterpret_cast<int>(¶ms)); + int ret = angelswi(SYS_GET_CMDLINE, reinterpret_cast<int>(¶ms)); + *len = params.len; + + return ret; +} + +void angel::sys_heapinfo(Heapinfo *heapinfo) { + angelswi(SYS_HEAPINFO, reinterpret_cast<int>(heapinfo)); +} + +void angel::sys_exit(int reason) { + angelswi(SYS_EXIT, reason); +} + +void angel::sys_exit_extended(int reason, int code) { + struct { + int reason; + int code; + } params; + + params.reason = reason; + params.code = code; + angelswi(SYS_EXIT_EXTENDED, reinterpret_cast<int>(¶ms)); } -int miosix::angel::sys_open_stdout() { +int angel::sys_elapsed(long long *ticks) { + struct { + int low; + int high; + } params; + + int ret = angelswi(SYS_ELAPSED, reinterpret_cast<int>(¶ms)); + *ticks = (long long)params.low | ((long long) params.high << 32); + + return ret; +} + +int angel::sys_tickfreq() { + return angelswi(SYS_TICKFREQ, 0); +} + +int angel::sys_open_stdout() { return sys_open(":tt", MODE_W); } -int miosix::angel::sys_open_stderr() { +int angel::sys_open_stderr() { return sys_open(":tt", MODE_A); +} + } \ No newline at end of file diff --git a/miosix/util/angel/angel.h b/miosix/util/angel/angel.h index 4e0988aa..c59ef73a 100644 --- a/miosix/util/angel/angel.h +++ b/miosix/util/angel/angel.h @@ -39,20 +39,67 @@ namespace miosix { MODE_APB = 11 }; + enum OpNum { + SYS_OPEN = 0x01, + SYS_CLOSE = 0x02, + SYS_WRITEC = 0x03, + SYS_WRITE0 = 0x04, + SYS_WRITE = 0x05, + SYS_READ = 0x06, + SYS_READC = 0x07, + SYS_ISERROR = 0x08, + SYS_ISTTY = 0x09, + SYS_SEEK = 0x0a, + SYS_FLEN = 0x0c, + SYS_TMPNAM = 0x0d, + SYS_REMOVE = 0x0e, + SYS_RENAME = 0x0f, + SYS_CLOCK = 0x10, + SYS_TIME = 0x11, + SYS_SYSTEM = 0x12, + SYS_ERRNO = 0x13, + SYS_GET_CMDLINE = 0x15, + SYS_HEAPINFO = 0x16, + SYS_EXIT = 0x18, + SYS_EXIT_EXTENDED = 0x20, + SYS_ELAPSED = 0x30, + SYS_TICKFREQ = 0x31, + }; + + struct Heapinfo { + void *heap_base; + void *heap_limit; + void *stack_base; + void *stack_limit; + }; + int angelswi(int num2, int param2); - int sys_clock(); - int sys_close(int handle); - int sys_errno(); - int sys_flen(int handle); - int sys_istty(int handle); int sys_open(const char *filename, Mode mode); - int sys_read(int handle, void *buf, int len); + int sys_close(int handle); + void sys_writec(char inc); + void sys_write0(const char *str); int sys_write(int handle, const void *buf, int len); + int sys_read(int handle, void *buf, int len); + int sys_readc(); + int sys_iserror(int code); + int sys_istty(int handle); int sys_seek(int handle, int pos); + int sys_flen(int handle); + int sys_tmpnam(char *buf, int id, int len); int sys_remove(const char *filename); int sys_rename(const char *old_filename, const char *new_filename); - + int sys_clock(); + int sys_time(); + int sys_system(const char *cmd); + int sys_errno(); + int sys_get_cmdline(char *buf, int *len); + void sys_heapinfo(Heapinfo *heapinfo); + void sys_exit(int reason); + void sys_exit_extended(int reason, int code); + int sys_elapsed(long long *ticks); + int sys_tickfreq(); + int sys_open_stdout(); int sys_open_stderr(); } diff --git a/miosix/util/angel/angel_fs.cpp b/miosix/util/angel/angel_fs.cpp new file mode 100644 index 00000000..693cd611 --- /dev/null +++ b/miosix/util/angel/angel_fs.cpp @@ -0,0 +1,194 @@ +/* Copyright (c) 2023 Skyward Experimental Rocketry + * Author: Davide Mor + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include "angel_fs.h" + +#include <sys/fcntl.h> +#include <errno.h> + +#include "filesystem/stringpart.h" +#include "angel.h" + +namespace miosix { + +angel::Mode flagsToMode(int flags) { + // Try to map from flags to angel mode + + // First, are we appending? This has high priority + if(flags & _FAPPEND) + // If yes, do we need to read? + return flags & _FREAD ? angel::MODE_APB : angel::MODE_AB; + + // Second, do we need to both read and write? + if(flags & _FREAD && flags & _FWRITE) + // If yes, do we need to truncate the file? + return flags & _FTRUNC ? angel::MODE_WPB : angel::MODE_RPB; + + // Finally, do we need to write? + return angel::MODE_WB; +} + +class AngelFile : public FileBase { +public: + AngelFile(intrusive_ref_ptr<FilesystemBase> parent, int handle); + ~AngelFile(); + + ssize_t write(const void *data, size_t len) override; + ssize_t read(void *data, size_t len) override; + off_t lseek(off_t pos, int whence) override; + int fstat(struct stat *pstat) const override; + int ioctl(int cmd, void *arg) override; + +private: + int offset; + int handle; +}; + +AngelFile::AngelFile(intrusive_ref_ptr<FilesystemBase> parent, int handle) : + FileBase(parent), + offset(0), + handle(handle) {} + +AngelFile::~AngelFile() { + angel::sys_close(handle); +} + +ssize_t AngelFile::write(const void *data, size_t len) { + // TODO: Any way to detect errors? + int count = len - angel::sys_write(handle, data, len); + offset += count; + + return count; +} + +ssize_t AngelFile::read(void *data, size_t len) { + // TODO: Any way to detect errors? + int count = len - angel::sys_read(handle, data, len); + offset += count; + + return count; +} + +off_t AngelFile::lseek(off_t pos, int whence) { + int size = angel::sys_flen(handle); + if(size < 0) + return -EIO; + + off_t new_offset; + switch(whence) + { + case SEEK_CUR: + new_offset = offset + pos; + break; + case SEEK_SET: + new_offset = pos; + break; + case SEEK_END: + new_offset = size - pos; + break; + default: + return -EINVAL; + } + + if(new_offset < 0 || new_offset > size) + return -EOVERFLOW; + + if(angel::sys_seek(handle, new_offset) < 0) { + return -angel::sys_errno(); + } else { + return offset = new_offset; + } +} + +int AngelFile::fstat(struct stat *pstat) const { + memset(pstat, 0, sizeof(struct stat)); + + // TODO: Maybe actually return this error? + int size = angel::sys_flen(handle); + if(size < 0) + return -EIO; + + pstat->st_dev = getParent()->getFsId(); + pstat->st_mode = S_IFREG | 0755; //-rwxr-xr-x + pstat->st_nlink = 1; + pstat->st_size = size; + pstat->st_blocks = (size + 511) / 512; + + // This number needs to be very high because angel writes are very inefficient + pstat->st_blksize = 512; + + return 0; +} + +int AngelFile::ioctl(int cmd, void *arg) { + return -EINVAL; +} + +AngelFs::AngelFs() {} + +int AngelFs::open(intrusive_ref_ptr<FileBase>& file, StringPart &name, int flags, int mode) { + int handle = angel::sys_open(name.c_str(), flagsToMode(flags)); + if(handle == -1) { + return -angel::sys_errno(); + } + + file = intrusive_ref_ptr<AngelFile>(new AngelFile(shared_from_this(), handle)); + return 0; +} + +int AngelFs::lstat(StringPart& name, struct stat *pstat) { + intrusive_ref_ptr<FileBase> file; + int ret = open(file, name, 0, 0); + if(ret != 0) + return ret; + + // We only really support files + return file.get()->fstat(pstat); +} + +int AngelFs::unlink(StringPart& name) { + if(angel::sys_remove(name.c_str()) == 0) { + return 0; + } else { + return -angel::sys_errno(); + } +} + +int AngelFs::rename(StringPart& oldName, StringPart& newName) { + if(angel::sys_rename(oldName.c_str(), newName.c_str()) == 0) { + return 0; + } else { + return -angel::sys_errno(); + } +} + +int AngelFs::mkdir(StringPart& name, int mode) { + // TODO: Maybe support these using angel::sys_system? + return -EACCES; +} + +int AngelFs::rmdir(StringPart& name) { + // TODO: Maybe support these using angel::sys_system? + return -EACCES; +} + +} \ No newline at end of file diff --git a/miosix/util/angel/angel_fs.h b/miosix/util/angel/angel_fs.h new file mode 100644 index 00000000..41f9d859 --- /dev/null +++ b/miosix/util/angel/angel_fs.h @@ -0,0 +1,39 @@ +/* Copyright (c) 2023 Skyward Experimental Rocketry + * Author: Davide Mor + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#pragma once + +#include "filesystem/file.h" + +namespace miosix { + class AngelFs : public FilesystemBase { + public: + AngelFs(); + + int open(intrusive_ref_ptr<FileBase>& file, StringPart &name, int flags, int mode) override; + int lstat(StringPart& name, struct stat *pstat) override; + int unlink(StringPart& name) override; + int rename(StringPart& oldName, StringPart& newName) override; + int mkdir(StringPart& name, int mode) override; + int rmdir(StringPart& name) override; + }; +} \ No newline at end of file diff --git a/miosix/util/angel/angel_serial.cpp b/miosix/util/angel/angel_serial.cpp index dcdcce77..797b3b02 100644 --- a/miosix/util/angel/angel_serial.cpp +++ b/miosix/util/angel/angel_serial.cpp @@ -27,19 +27,33 @@ #include "angel.h" #include "filesystem/ioctl.h" -using namespace miosix; +namespace miosix { -miosix::AngelSerial::AngelSerial() : Device(DeviceType::TTY), handle(angel::sys_open_stdout()) {} +AngelSerial::AngelSerial(Stream stream) : + Device(DeviceType::TTY), + handle(stream == Stream::Stdout ? angel::sys_open_stdout() : angel::sys_open_stderr()) {} + +AngelSerial::~AngelSerial() { + if(handle != -1) { + angel::sys_close(handle); + } +} + +ssize_t AngelSerial::readBlock(void *buffer, size_t size, off_t where) { + if(handle == -1) + return -EIO; -ssize_t miosix::AngelSerial::readBlock(void *buffer, size_t size, off_t where) { return size - angel::sys_read(handle, buffer, size); } -ssize_t miosix::AngelSerial::writeBlock(const void *buffer, size_t size, off_t where) { +ssize_t AngelSerial::writeBlock(const void *buffer, size_t size, off_t where) { + if(handle == -1) + return -EIO; + return size - angel::sys_write(handle, buffer, size); } -int miosix::AngelSerial::ioctl(int cmd, void *arg) { +int AngelSerial::ioctl(int cmd, void *arg) { if(reinterpret_cast<unsigned>(arg) & 0b11) return -EFAULT; // Unaligned @@ -65,3 +79,5 @@ int miosix::AngelSerial::ioctl(int cmd, void *arg) { return -ENOTTY; // Means the operation does not apply to this descriptor } } + +} \ No newline at end of file diff --git a/miosix/util/angel/angel_serial.h b/miosix/util/angel/angel_serial.h index 1f2cfa90..bfe80cbc 100644 --- a/miosix/util/angel/angel_serial.h +++ b/miosix/util/angel/angel_serial.h @@ -27,7 +27,13 @@ namespace miosix { class AngelSerial : public miosix::Device { public: - AngelSerial(); + enum class Stream { + Stdout, + Stderr, + }; + + AngelSerial(Stream stream); + ~AngelSerial(); ssize_t readBlock(void *buffer, size_t size, off_t where) override; ssize_t writeBlock(const void *buffer, size_t size, off_t where) override; -- GitLab