commit 8299f1f50b3197849fdc756af9ce50045e916720
parent 211e202c9e1348e82a7ddaa229bb5fb1e501ee8f
Author: Virgil Dupras <hsoft@hardcoded.net>
Date: Thu, 4 Aug 2022 09:05:12 -0400
cvm: add FS support
Diffstat:
2 files changed, 113 insertions(+), 11 deletions(-)
diff --git a/posix/tmpboot.fs b/posix/tmpboot.fs
@@ -125,5 +125,4 @@ alias noop [then]
\ doc comment placeholder
alias \ \\
-: foo S" Bootlo compiles!" stype ;
-foo bye
+0 S" lib" fchild S" nfmt.fs" fchild fopen 20 over _freadbuf rtype _fclose bye
diff --git a/posix/vm.c b/posix/vm.c
@@ -11,6 +11,8 @@ The VM is little endian.
#include <stdio.h>
#include <unistd.h>
#include <string.h>
+#include <sys/stat.h>
+#include <fcntl.h>
#define MEMSZ 0x100000 // 1MB
#define STACKSZ 0x800
@@ -25,7 +27,8 @@ The VM is little endian.
#define EMIT (INRD+4)
#define ABORT (EMIT+4)
#define CURWORD (ABORT+4)
-#define HEREMAX SYSVARS
+#define IOBUF (SYSVARS-0x400)
+#define HEREMAX IOBUF
typedef uint8_t byte;
@@ -115,9 +118,9 @@ static void toexec(dword a) {
}
// Operations
-/* The VM works in a simple manner. PC starts at 0. The VM reads the byte
-where PC points to in memory, increases PC by 1 and executes the corresponding
-function in the function list below. As simple as this. */
+/* The VM works in a simple manner. The VM reads the byte where PC points to in
+memory, increases PC by 1 and executes the corresponding function in the
+function list below. As simple as this. */
static void JUMP() { // op: 00
vm.PC = gpc();
@@ -697,7 +700,106 @@ static void EXIT() { // op: 5c
rpop();
}
-#define OPCNT 0x5d
+/* Filesystem
+
+At POSIX level, we don't have access to the underlying FS structure such as
+inodes, making Dusk's 32-bit "ID" system a bit awkward. What we're going to do
+here is have a buffer of all requested paths, and the index in that buffer will
+be our ID.
+*/
+#define MAXPATHSZ 0x100
+#define FSIDCNT 0x200
+static char fsids[FSIDCNT][MAXPATHSZ] = {0};
+
+static dword findpath(char *path) {
+ for (dword i=0; i<FSIDCNT; i++) {
+ if (strcmp(path, fsids[i]) == 0) return i;
+ }
+ return 0;
+}
+
+static int getfiledesc(dword hdl) {
+ return (int)(gd(hdl+20)|(((int64_t)gd(hdl+24))<<32));
+}
+
+static void FCHILD () { // op: 5d
+ dword s = ppop();
+ byte len = gb(s++);
+ dword parent = ppop();
+ char path[MAXPATHSZ] = {0};
+ dword res;
+ if ((parent >= FSIDCNT) || !fsids[parent][0]) {
+ printf("Out of bounds FSID\n");
+ vm.PC = gd(ABORT);
+ return;
+ }
+ strcpy(path, fsids[parent]);
+ strcat(path, "/");
+ strncat(path, (char*)&vm.mem[s], len);
+ res = findpath(path);
+ if (!res) {
+ // Verify if path actually exists in FS, then create a new ID
+ struct stat sb;
+ if (stat(path, &sb) != 0) { // does not exist
+ ppush(0);
+ return;
+ }
+ while (fsids[++res][0]);
+ strcpy(fsids[res], path);
+ }
+ ppush(res);
+}
+
+// Our handles are simply the regular IO/File preludes followed by the POSIX
+// file descriptor, a 64bit int.
+static void FOPEN () { // op: 5e
+ dword fsid = ppop();
+ char *path;
+ int fd;
+ if ((fsid >= FSIDCNT) || !fsids[fsid][0]) {
+ printf("Out of bounds FSID\n");
+ vm.PC = gd(ABORT);
+ return;
+ }
+ path = fsids[fsid];
+ fd = open(path, 0);
+ if (fd == -1) {
+ printf("Can't open %s\n", path);
+ vm.PC = gd(ABORT);
+ return;
+ }
+ ppush(here()); // File cursor we're about to create
+ dwrite(find("_freadbuf"));
+ dwrite(find("abort")); // writebuf
+ dwrite(find("drop")); // flush
+ dwrite(find("2drop")); // seek
+ dwrite(find("_fclose")); // close
+ dwrite(fd);
+ dwrite((int64_t)fd>>32);
+}
+
+static void FREADBUF () { // op: 5f
+ dword hdl = ppop();
+ dword n = ppop();
+ int res;
+ int fd = getfiledesc(hdl);
+ res = read(fd, &vm.mem[IOBUF], n);
+ if (res < 0) {
+ printf("I/O readbuf error\n");
+ vm.PC = gd(ABORT);
+ return;
+ }
+ if (n) ppush(IOBUF);
+ ppush((dword)n);
+}
+
+static void FCLOSE () { // op: 60
+ dword hdl = ppop();
+ int fd = getfiledesc(hdl);
+ close(fd);
+}
+
+#define OPCNT 0x61
static void (*ops[OPCNT])() = {
JUMP, CALL, RET, LIT, BYE, BYEFAIL, QUIT, ABORT_,
EXECUTE, CELL, VAL, ALIAS, DOES, SLIT, BR, CBR,
@@ -710,7 +812,8 @@ static void (*ops[OPCNT])() = {
OR, XOR, BOOL, NOT, LT, SHLC, SHRC, LSHIFT,
RSHIFT, LITN, EXECUTEWR, EXITWR, MOVE, MOVEWR, RTYPE, WNF,
STACKCHK, MAYBEWORD, WORD, PARSE, REQ, FIND, APOS, ENTRY,
- XTCOMP, DOCOL, STOPCOL, RUNWORD, EXIT};
+ XTCOMP, DOCOL, STOPCOL, RUNWORD, EXIT, FCHILD, FOPEN, FREADBUF,
+ FCLOSE};
static char *opnames[OPCNT] = {
NULL, NULL, NULL, NULL, "bye", "bytefail", "quit", "(abort)",
@@ -724,7 +827,8 @@ static char *opnames[OPCNT] = {
"or", "xor", "bool", "not", "<", "<<c", ">>c", "lshift",
"rshift", "litn", "execute,", "exit,", "move", "move,", "rtype", "(wnf)",
"stack?", "maybeword", "word", "parse", "[]=", "find", "'", "entry",
- "xtcomp", ":", ";", "runword", "exit"};
+ "xtcomp", ":", ";", "runword", "exit", "fchild", "fopen", "_freadbuf",
+ "_fclose"};
static void oprun1() { // run next op
byte opcode = vm.mem[vm.PC++];
@@ -798,8 +902,7 @@ static void buildsysdict() {
// Interpret loop
int main() {
- vm.PSP = PSTOP;
- vm.RSP = RSTOP;
+ strcpy(fsids[0], "fs"); // Set FS root path
bootfp = fopen("posix/tmpboot.fs", "r");
if (!bootfp) {
printf("Can't open boot file.\n");