summaryrefslogtreecommitdiff
path: root/src/user
diff options
context:
space:
mode:
Diffstat (limited to 'src/user')
-rw-r--r--src/user/init.cc237
-rw-r--r--src/user/sh.cc409
-rw-r--r--src/user/usys.S13
3 files changed, 457 insertions, 202 deletions
diff --git a/src/user/init.cc b/src/user/init.cc
index 27c1e2f..827a21e 100644
--- a/src/user/init.cc
+++ b/src/user/init.cc
@@ -1,221 +1,58 @@
+#include "ulib/stdio.h"
+#include "ulib/stdlib.h"
+#include "ulib/string.h"
#include "user/user.h"
-#include "common/fcntl.h"
-int strlen(const char *s)
-{
- int n = 0;
- while (s[n])
- n++;
- return n;
-}
-
-void print(const char *s)
-{
- write(1, s, strlen(s));
-}
-
-void print_int(int n)
-{
- char buf[16];
- int i = 0;
- int neg = 0;
- if (n == 0)
- {
- write(1, "0", 1);
- return;
- }
- if (n < 0)
- {
- neg = 1;
- n = -n;
- }
- while (n > 0)
- {
- buf[i++] = (n % 10) + '0';
- n /= 10;
- }
- if (neg)
- buf[i++] = '-';
- while (i > 0)
- write(1, &buf[--i], 1);
-}
-
-void print_hex(uint64 n)
-{
- char buf[16];
- char digits[] = "0123456789ABCDEF";
- write(1, "0x", 2);
- if (n == 0)
- {
- write(1, "0", 1);
- return;
- }
- int i = 0;
- while (n > 0)
- {
- buf[i++] = digits[n % 16];
- n /= 16;
- }
- while (i > 0)
- write(1, &buf[--i], 1);
-}
-
-void test_syscalls()
+int main()
{
- print("\n=== [Test] Starting System Call Check ===\n");
-
- print("[1/4] Checking getpid()... ");
- int my_pid = getpid();
- if (my_pid > 0)
- {
- print("PASS (PID=");
- print_int(my_pid);
- print(")\n");
- }
- else
- {
- print("FAIL (Invalid PID)\n");
- }
-
- print("[2/4] Checking sbrk() heap allocation... ");
- char *p = sbrk(4096);
- if (p == (char *)-1)
- {
- print("FAIL (sbrk returned error)\n");
- }
- else
- {
- p[0] = 'A';
- p[4095] = 'Z';
- if (p[0] == 'A' && p[4095] == 'Z')
- {
- print("PASS (Allocated at ");
- print_hex((uint64)p);
- print(")\n");
- }
- else
- {
- print("FAIL (Memory read/write check failed)\n");
- }
- }
+ char *argv[] = {(char *)"sh", 0};
- print("[3/4] Checking fork() and wait()...\n");
- int pid = fork();
+ printf("[Init] Starting Lume OS Shell...\n");
- if (pid < 0)
- {
- print(" FAIL: fork error\n");
- }
- else if (pid == 0)
+ while (1)
{
- int child_pid = getpid();
- if (child_pid == my_pid)
+ // printf("fork start\n");
+ int pid = fork();
+ // printf("fork suceess, pid=%i\n", pid);
+
+ if (pid < 0)
{
- print(" FAIL: Child has same PID as parent\n");
+ printf("[Init] fork failed!\n");
exit(1);
}
- print(" [Child] I am alive. PID=");
- print_int(child_pid);
- print("\n");
- print(" [Child] Exiting now.\n");
- exit(0);
- }
- else
- {
- print(" [Parent] Forked child PID=");
- print_int(pid);
- print("\n");
- print(" [Parent] Waiting for child...\n");
- int waited_pid = wait(0);
-
- if (waited_pid == pid)
+ if (pid == 0)
{
- print(" [Parent] Wait returned correct PID.\n");
- print("PASS (Fork/Wait cycle)\n");
- }
- else
- {
- print("FAIL (Wait returned ");
- print_int(waited_pid);
- print(")\n");
- }
- }
-
- print("[4/4] Checking write()... PASS (Self-evident)\n");
-
- print("=== [Test] All Tests Finished ===\n");
-}
-
-
-int main()
-{
- print("\n[Lume Shell] Init process started.\n");
- print("[Test] Opening test.txt...\n");
- int fd = open("test.txt", O_RDONLY);
- if (fd < 0)
- {
- print("[Test] Open failed (Is test.txt in fs.img?)\n");
- }
- else
- {
- print("[Test] Open success! fd=");
- print_int(fd);
- print("\n");
+
+ char sh_path[] = "/sh";
+ exec(sh_path, argv);
- char buf[64];
- int n = read(fd, buf, 63);
- if (n > 0)
- {
- buf[n] = 0;
- print("[Test] Read content:\n---\n");
- print(buf);
- print("\n---\n");
+ printf("[Init] exec sh failed\n");
+ return 0;
+ exit(1);
}
else
{
- print("[Test] Read returned ");
- print_int(n);
- print("\n");
- }
- close(fd);
- print("[Test] File closed.\n");
- }
-
-
-
- print("Commands:\n");
- print(" s: Run System Call Tests (fork, wait, mm)\n");
- print(" t: Run Disk Driver Test (VirtIO)\n");
-
- while (1)
- {
- char buf[16];
- write(1, "$ ", 2);
-
- int n = read(0, buf, sizeof(buf));
- if (n <= 0)
- continue;
-
- if (buf[0] == 's')
- {
- test_syscalls();
- }
- else if (buf[0] == 't')
- {
- if (fork() == 0)
+ // break;
+ int status;
+ int wpid;
+ while (1)
{
- disk_test();
- exit(0);
+ wpid = wait((uint64)&status);
+
+ if (wpid == pid)
+ {
+ printf("Shell Exit");
+ break;
+ }
+ if (wpid < 0)
+ {
+ printf("[Init] wait error or no child\n");
+
+ break;
+ }
}
- wait(0);
- }
- else if (buf[0] != '\n')
- {
- print("Unknown command.\n");
}
}
-
- exit(0);
return 0;
} \ No newline at end of file
diff --git a/src/user/sh.cc b/src/user/sh.cc
new file mode 100644
index 0000000..287d2be
--- /dev/null
+++ b/src/user/sh.cc
@@ -0,0 +1,409 @@
+#include "ulib/stdio.h"
+#include "ulib/stdlib.h"
+#include "ulib/string.h"
+#include "user/user.h"
+#include "common/fcntl.h"
+
+constexpr int MAX_ARGS = 10;
+const char *WHITESPACE = " \t\r\n\v";
+const char *SYMBOLS = "<|>&;()";
+
+void panic(const char *s)
+{
+ printf("shell panic: %s\n", s);
+ exit(1);
+}
+
+int fork_or_panic()
+{
+ int pid = fork();
+ if (pid == -1)
+ panic("fork");
+ return pid;
+}
+
+struct Command
+{
+ virtual ~Command() = default;
+
+ virtual void run() = 0;
+};
+
+struct ExecCommand : public Command
+{
+ char *argv[MAX_ARGS];
+
+ ExecCommand()
+ {
+ memset(argv, 0, sizeof(argv));
+ }
+
+ void run() override
+ {
+ if (argv[0] == nullptr)
+ exit(1);
+
+ exec(argv[0], argv);
+
+ printf("exec %s failed\n", argv[0]);
+ exit(1);
+ }
+};
+
+struct RedirCommand : public Command
+{
+ Command *sub_cmd;
+ char *file;
+ char *efile; // file name end pointer (used by parser)
+ int mode;
+ int fd;
+
+ RedirCommand(Command *c, char *f, char *ef, int m, int fd_in)
+ : sub_cmd(c), file(f), efile(ef), mode(m), fd(fd_in) {}
+
+ ~RedirCommand() { delete sub_cmd; }
+
+ void run() override
+ {
+ close(fd);
+ if (open(file, mode) < 0)
+ {
+ printf("open %s failed\n", file);
+ exit(1);
+ }
+ sub_cmd->run();
+ }
+};
+
+struct PipeCommand : public Command
+{
+ Command *left;
+ Command *right;
+
+ PipeCommand(Command *l, Command *r) : left(l), right(r) {}
+ ~PipeCommand()
+ {
+ delete left;
+ delete right;
+ }
+
+ void run() override
+ {
+ int p[2];
+ if (pipe(p) < 0)
+ panic("pipe");
+
+ if (fork_or_panic() == 0)
+ {
+ // Left child: write to pipe
+ close(1); // close stdout
+ dup(p[1]); // dup write-end to stdout
+ close(p[0]);
+ close(p[1]);
+ left->run();
+ }
+
+ if (fork_or_panic() == 0)
+ {
+ // Right child: read from pipe
+ close(0); // close stdin
+ dup(p[0]); // dup read-end to stdin
+ close(p[0]);
+ close(p[1]);
+ right->run();
+ }
+
+ close(p[0]);
+ close(p[1]);
+ wait(0);
+ wait(0);
+ exit(0);
+ }
+};
+
+struct ListCommand : public Command
+{
+ Command *left;
+ Command *right;
+
+ ListCommand(Command *l, Command *r) : left(l), right(r) {}
+ ~ListCommand()
+ {
+ delete left;
+ delete right;
+ }
+
+ void run() override
+ {
+ if (fork_or_panic() == 0)
+ {
+ left->run();
+ }
+ wait(0);
+ right->run();
+ }
+};
+
+struct BackCommand : public Command
+{
+ Command *sub_cmd;
+
+ BackCommand(Command *c) : sub_cmd(c) {}
+ ~BackCommand() { delete sub_cmd; }
+
+ void run() override
+ {
+ if (fork_or_panic() == 0)
+ {
+ sub_cmd->run();
+ }
+ // Parent doesn't wait
+ exit(0);
+ }
+};
+
+class Parser
+{
+public:
+ static Command *parse(char *s)
+ {
+ char *es = s + strlen(s);
+ Command *cmd = parse_line(&s, es);
+ peek(&s, es, "");
+ if (s != es)
+ {
+ printf("leftovers: %s\n", s);
+ // panic("syntax"); // strict syntax check
+ }
+ terminate_strings(cmd);
+ return cmd;
+ }
+
+private:
+ // Helper: NUL-terminate strings found during parsing
+ static void terminate_strings(Command *cmd)
+ {
+ if (!cmd)
+ return;
+ }
+
+ static char get_token(char **ps, char *es, char **q, char **eq)
+ {
+ char *s;
+ int ret;
+
+ s = *ps;
+ while (s < es && strchr(WHITESPACE, *s))
+ s++;
+ if (q)
+ *q = s;
+ ret = *s;
+ switch (*s)
+ {
+ case 0:
+ break;
+ case '|':
+ case '(':
+ case ')':
+ case ';':
+ case '&':
+ case '<':
+ s++;
+ break;
+ case '>':
+ s++;
+ if (*s == '>')
+ {
+ ret = '+';
+ s++;
+ }
+ break;
+ default:
+ ret = 'a';
+ while (s < es && !strchr(WHITESPACE, *s) && !strchr(SYMBOLS, *s))
+ s++;
+ break;
+ }
+ if (eq)
+ *eq = s;
+
+ while (s < es && strchr(WHITESPACE, *s))
+ s++;
+ *ps = s;
+ return ret;
+ }
+
+ static int peek(char **ps, char *es, const char *toks)
+ {
+ char *s = *ps;
+ while (s < es && strchr(WHITESPACE, *s))
+ s++;
+ *ps = s;
+ return *s && strchr(toks, *s);
+ }
+
+ // Recursive Descent Parsers
+
+ static Command *parse_line(char **ps, char *es)
+ {
+ Command *cmd = parse_pipe(ps, es);
+ while (peek(ps, es, "&"))
+ {
+ get_token(ps, es, 0, 0);
+ cmd = new BackCommand(cmd);
+ }
+ if (peek(ps, es, ";"))
+ {
+ get_token(ps, es, 0, 0);
+ cmd = new ListCommand(cmd, parse_line(ps, es));
+ }
+ return cmd;
+ }
+
+ static Command *parse_pipe(char **ps, char *es)
+ {
+ Command *cmd = parse_exec(ps, es);
+ if (peek(ps, es, "|"))
+ {
+ get_token(ps, es, 0, 0);
+ cmd = new PipeCommand(cmd, parse_pipe(ps, es));
+ }
+ return cmd;
+ }
+
+ static Command *parse_exec(char **ps, char *es)
+ {
+ char *q, *eq;
+ int tok, argc;
+ ExecCommand *cmd = new ExecCommand();
+ Command *ret = cmd;
+
+ argc = 0;
+ ret = parse_redirs(ret, ps, es);
+ while (!peek(ps, es, "|)&;"))
+ {
+ if ((tok = get_token(ps, es, &q, &eq)) == 0)
+ break;
+ if (tok != 'a')
+ panic("syntax");
+
+ cmd->argv[argc] = q;
+ *eq = 0; // Temp
+
+ argc++;
+ if (argc >= MAX_ARGS)
+ panic("too many args");
+ ret = parse_redirs(ret, ps, es);
+ }
+ cmd->argv[argc] = 0;
+ return ret;
+ }
+
+ static Command *parse_redirs(Command *cmd, char **ps, char *es)
+ {
+ int tok;
+ char *q, *eq;
+
+ while (peek(ps, es, "<>"))
+ {
+ tok = get_token(ps, es, 0, 0);
+ if (get_token(ps, es, &q, &eq) != 'a')
+ panic("missing file for redirection");
+
+ *eq = 0; // Null terminate filename immediately
+
+ switch (tok)
+ {
+ case '<':
+ cmd = new RedirCommand(cmd, q, eq, O_RDONLY, 0);
+ break;
+ case '>':
+ cmd = new RedirCommand(cmd, q, eq, O_WRONLY | O_CREATE | O_TRUNC, 1);
+ break;
+ case '+': // >>
+ cmd = new RedirCommand(cmd, q, eq, O_WRONLY | O_CREATE, 1); // Append not fully supported in simple OS yet?
+ break;
+ }
+ }
+ return cmd;
+ }
+};
+
+int getcmd(char *buf, int nbuf)
+{
+ write(1, "$ ", 2);
+ memset(buf, 0, nbuf);
+
+ int i = 0;
+ while (i < nbuf - 1)
+ {
+ char c;
+ int n = read(0, &c, 1);
+ if (n <= 0)
+ return -1;
+
+ if (c == '\b' || c == 127)
+ {
+ if (i > 0)
+ {
+ write(1, "\b \b", 3);
+ i--;
+ }
+ }
+ else if (c == '\n' || c == '\r')
+ {
+ write(1, "\n", 1);
+ buf[i] = 0;
+ return 0;
+ }
+ else
+ {
+ write(1, &c, 1);
+ buf[i++] = c;
+ }
+ }
+ return -1;
+}
+
+int main()
+{
+ static char buf[100];
+
+ // int fd;
+ // while ((fd = open("console", O_RDWR)) >= 0)
+ // {
+ // if (fd >= 3)
+ // {
+ // close(fd);
+ // break;
+ // }
+ // }
+
+ printf("\n[Lume Shell] Initialized! \n");
+
+ while (getcmd(buf, sizeof(buf)) >= 0)
+ {
+ if (buf[0] == 'c' && buf[1] == 'd' && buf[2] == ' ')
+ {
+ buf[strlen(buf) - 1] = 0; // chop \n
+ if (chdir(buf + 3) < 0)
+ {
+ printf("cannot cd %s\n", buf + 3);
+ }
+ continue;
+ }
+
+ if (fork_or_panic() == 0)
+ {
+ Command *cmd = Parser::parse(buf);
+ if (cmd)
+ {
+ cmd->run();
+ delete cmd;
+ }
+ exit(0);
+ }
+ wait(0);
+ }
+ return 0;
+} \ No newline at end of file
diff --git a/src/user/usys.S b/src/user/usys.S
index 65937cc..f85917e 100644
--- a/src/user/usys.S
+++ b/src/user/usys.S
@@ -7,8 +7,16 @@
ecall; \
ret
+#define SYSCALL_NAME(name, sysname) \
+ .global name; \
+ name: \
+ li a7, SYS_ ## sysname; \
+ ecall; \
+ ret
+
+SYSCALL_NAME(sys_exit, exit)
+
SYSCALL(fork)
-SYSCALL(exit)
SYSCALL(wait)
SYSCALL(pipe)
SYSCALL(read)
@@ -29,4 +37,5 @@ SYSCALL(sbrk)
SYSCALL(sleep)
SYSCALL(uptime)
SYSCALL(putc)
-SYSCALL(disk_test) \ No newline at end of file
+SYSCALL(disk_test)
+SYSCALL(lseek) \ No newline at end of file