diff --git a/Makefile b/Makefile index 980e035..eaa1f8c 100644 --- a/Makefile +++ b/Makefile @@ -14,6 +14,7 @@ SRC_DIR := . OBJ_DIR := obj SPROJS_INCLUDE := -I. +HOSTFS_ROOT := hostfs_root ifneq (,) march := -march= is_32bit := $(findstring 32,$(march)) @@ -63,12 +64,41 @@ SPIKE_INF_LIB := $(OBJ_DIR)/spike_interface.a #--------------------- user ----------------------- -USER_CPPS := user/*.c +USER_CPPS := user/app_shell.c user/user_lib.c -USER_CPPS := $(wildcard $(USER_CPPS)) USER_OBJS := $(addprefix $(OBJ_DIR)/, $(patsubst %.c,%.o,$(USER_CPPS))) -USER_TARGET := $(OBJ_DIR)/app_hardlink +USER_TARGET := $(HOSTFS_ROOT)/bin/app_shell + +USER_E_CPPS := user/app_ls.c user/user_lib.c + +USER_E_OBJS := $(addprefix $(OBJ_DIR)/, $(patsubst %.c,%.o,$(USER_E_CPPS))) + +USER_E_TARGET := $(HOSTFS_ROOT)/bin/app_ls + +USER_M_CPPS := user/app_mkdir.c user/user_lib.c + +USER_M_OBJS := $(addprefix $(OBJ_DIR)/, $(patsubst %.c,%.o,$(USER_M_CPPS))) + +USER_M_TARGET := $(HOSTFS_ROOT)/bin/app_mkdir + +USER_T_CPPS := user/app_touch.c user/user_lib.c + +USER_T_OBJS := $(addprefix $(OBJ_DIR)/, $(patsubst %.c,%.o,$(USER_T_CPPS))) + +USER_T_TARGET := $(HOSTFS_ROOT)/bin/app_touch + +USER_C_CPPS := user/app_cat.c user/user_lib.c + +USER_C_OBJS := $(addprefix $(OBJ_DIR)/, $(patsubst %.c,%.o,$(USER_C_CPPS))) + +USER_C_TARGET := $(HOSTFS_ROOT)/bin/app_cat + +USER_O_CPPS := user/app_echo.c user/user_lib.c + +USER_O_OBJS := $(addprefix $(OBJ_DIR)/, $(patsubst %.c,%.o,$(USER_O_CPPS))) + +USER_O_TARGET := $(HOSTFS_ROOT)/bin/app_echo #------------------------targets------------------------ $(OBJ_DIR): @-mkdir -p $(OBJ_DIR) @@ -76,7 +106,12 @@ $(OBJ_DIR): @-mkdir -p $(dir $(SPIKE_INF_OBJS)) @-mkdir -p $(dir $(KERNEL_OBJS)) @-mkdir -p $(dir $(USER_OBJS)) - + @-mkdir -p $(dir $(USER_E_OBJS)) + @-mkdir -p $(dir $(USER_M_OBJS)) + @-mkdir -p $(dir $(USER_T_OBJS)) + @-mkdir -p $(dir $(USER_C_OBJS)) + @-mkdir -p $(dir $(USER_O_OBJS)) + $(OBJ_DIR)/%.o : %.c @echo "compiling" $< @$(COMPILE) -c $< -o $@ @@ -102,20 +137,52 @@ $(KERNEL_TARGET): $(OBJ_DIR) $(UTIL_LIB) $(SPIKE_INF_LIB) $(KERNEL_OBJS) $(KERNE $(USER_TARGET): $(OBJ_DIR) $(UTIL_LIB) $(USER_OBJS) @echo "linking" $@ ... + -@mkdir -p $(HOSTFS_ROOT)/bin @$(COMPILE) --entry=main $(USER_OBJS) $(UTIL_LIB) -o $@ @echo "User app has been built into" \"$@\" + @cp $@ $(OBJ_DIR) + +$(USER_E_TARGET): $(OBJ_DIR) $(UTIL_LIB) $(USER_E_OBJS) + @echo "linking" $@ ... + -@mkdir -p $(HOSTFS_ROOT)/bin + @$(COMPILE) --entry=main $(USER_E_OBJS) $(UTIL_LIB) -o $@ + @echo "User app has been built into" \"$@\" + +$(USER_M_TARGET): $(OBJ_DIR) $(UTIL_LIB) $(USER_M_OBJS) + @echo "linking" $@ ... + -@mkdir -p $(HOSTFS_ROOT)/bin + @$(COMPILE) --entry=main $(USER_M_OBJS) $(UTIL_LIB) -o $@ + @echo "User app has been built into" \"$@\" + +$(USER_T_TARGET): $(OBJ_DIR) $(UTIL_LIB) $(USER_T_OBJS) + @echo "linking" $@ ... + -@mkdir -p $(HOSTFS_ROOT)/bin + @$(COMPILE) --entry=main $(USER_T_OBJS) $(UTIL_LIB) -o $@ + @echo "User app has been built into" \"$@\" + +$(USER_C_TARGET): $(OBJ_DIR) $(UTIL_LIB) $(USER_C_OBJS) + @echo "linking" $@ ... + -@mkdir -p $(HOSTFS_ROOT)/bin + @$(COMPILE) --entry=main $(USER_C_OBJS) $(UTIL_LIB) -o $@ + @echo "User app has been built into" \"$@\" + +$(USER_O_TARGET): $(OBJ_DIR) $(UTIL_LIB) $(USER_O_OBJS) + @echo "linking" $@ ... + -@mkdir -p $(HOSTFS_ROOT)/bin + @$(COMPILE) --entry=main $(USER_O_OBJS) $(UTIL_LIB) -o $@ + @echo "User app has been built into" \"$@\" -include $(wildcard $(OBJ_DIR)/*/*.d) -include $(wildcard $(OBJ_DIR)/*/*/*.d) .DEFAULT_GOAL := $(all) -all: $(KERNEL_TARGET) $(USER_TARGET) +all: $(KERNEL_TARGET) $(USER_TARGET) $(USER_E_TARGET) $(USER_M_TARGET) $(USER_T_TARGET) $(USER_C_TARGET) $(USER_O_TARGET) .PHONY:all -run: $(KERNEL_TARGET) $(USER_TARGET) +run: $(KERNEL_TARGET) $(USER_TARGET) $(USER_E_TARGET) $(USER_M_TARGET) $(USER_T_TARGET) $(USER_C_TARGET) $(USER_O_TARGET) @echo "********************HUST PKE********************" - spike $(KERNEL_TARGET) $(USER_TARGET) + spike $(KERNEL_TARGET) /bin/app_shell # need openocd! gdb:$(KERNEL_TARGET) $(USER_TARGET) @@ -146,4 +213,4 @@ format: @python ./format.py ./ clean: - rm -fr ${OBJ_DIR} + rm -fr ${OBJ_DIR} ${HOSTFS_ROOT}/bin diff --git a/hostfs_root/hostfile.txt b/hostfs_root/hostfile.txt deleted file mode 100644 index cfbea73..0000000 --- a/hostfs_root/hostfile.txt +++ /dev/null @@ -1,2 +0,0 @@ -This is an apple. -Apples are good for our health. diff --git a/hostfs_root/shellrc b/hostfs_root/shellrc new file mode 100644 index 0000000..26ce3b9 --- /dev/null +++ b/hostfs_root/shellrc @@ -0,0 +1,8 @@ +/bin/app_mkdir /RAMDISK0/sub_dir +/bin/app_touch /RAMDISK0/sub_dir/ramfile1 +/bin/app_touch /RAMDISK0/sub_dir/ramfile2 +/bin/app_echo /RAMDISK0/sub_dir/ramfile1 +/bin/app_cat /RAMDISK0/sub_dir/ramfile1 +/bin/app_ls /RAMDISK0/sub_dir +/bin/app_ls /RAMDISK0 +END END diff --git a/kernel/elf.c b/kernel/elf.c index 5010a01..b354510 100644 --- a/kernel/elf.c +++ b/kernel/elf.c @@ -8,10 +8,11 @@ #include "riscv.h" #include "vmm.h" #include "pmm.h" +#include "vfs.h" #include "spike_interface/spike_utils.h" typedef struct elf_info_t { - spike_file_t *f; + struct file *f; process *p; } elf_info; @@ -34,14 +35,12 @@ static void *elf_alloc_mb(elf_ctx *ctx, uint64 elf_pa, uint64 elf_va, uint64 siz } // -// actual file reading, using the spike file interface. +// actual file reading, using the vfs file interface. // static uint64 elf_fpread(elf_ctx *ctx, void *dest, uint64 nb, uint64 offset) { elf_info *msg = (elf_info *)ctx->info; - // call spike file utility to load the content of elf file into memory. - // spike_file_pread will read the elf file (msg->f) from offset to memory (indicated by - // *dest) for nb bytes. - return spike_file_pread(msg->f, dest, nb, offset); + vfs_lseek(msg->f, offset, SEEK_SET); + return vfs_read(msg->f, dest, nb); } // @@ -107,50 +106,18 @@ elf_status elf_load(elf_ctx *ctx) { return EL_OK; } -typedef union { - uint64 buf[MAX_CMDLINE_ARGS]; - char *argv[MAX_CMDLINE_ARGS]; -} arg_buf; - -// -// returns the number (should be 1) of string(s) after PKE kernel in command line. -// and store the string(s) in arg_bug_msg. -// -static size_t parse_args(arg_buf *arg_bug_msg) { - // HTIFSYS_getmainvars frontend call reads command arguments to (input) *arg_bug_msg - long r = frontend_syscall(HTIFSYS_getmainvars, (uint64)arg_bug_msg, - sizeof(*arg_bug_msg), 0, 0, 0, 0, 0); - kassert(r == 0); - - size_t pk_argc = arg_bug_msg->buf[0]; - uint64 *pk_argv = &arg_bug_msg->buf[1]; - - int arg = 1; // skip the PKE OS kernel string, leave behind only the application name - for (size_t i = 0; arg + i < pk_argc; i++) - arg_bug_msg->argv[i] = (char *)(uintptr_t)pk_argv[arg + i]; - - //returns the number of strings after PKE kernel in command line - return pk_argc - arg; -} - // // load the elf of user application, by using the spike file interface. // -void load_bincode_from_host_elf(process *p) { - arg_buf arg_bug_msg; - - // retrieve command line arguements - size_t argc = parse_args(&arg_bug_msg); - if (!argc) panic("You need to specify the application program!\n"); - - sprint("Application: %s\n", arg_bug_msg.argv[0]); +void load_bincode_from_host_elf(process *p, char *filename) { + sprint("Application: %s\n", filename); //elf loading. elf_ctx is defined in kernel/elf.h, used to track the loading process. elf_ctx elfloader; // elf_info is defined above, used to tie the elf file and its corresponding process. elf_info info; - info.f = spike_file_open(arg_bug_msg.argv[0], O_RDONLY, 0); + info.f = vfs_open(filename, O_RDONLY); info.p = p; // IS_ERR_VALUE is a macro defined in spike_interface/spike_htif.h if (IS_ERR_VALUE(info.f)) panic("Fail on openning the input application program.\n"); @@ -165,8 +132,8 @@ void load_bincode_from_host_elf(process *p) { // entry (virtual, also physical in lab1_x) address p->trapframe->epc = elfloader.ehdr.entry; - // close the host spike file - spike_file_close( info.f ); + // close the vfs file + vfs_close( info.f ); sprint("Application program entry point (virtual address): 0x%lx\n", p->trapframe->epc); } diff --git a/kernel/elf.h b/kernel/elf.h index 3011dc5..7d06f19 100644 --- a/kernel/elf.h +++ b/kernel/elf.h @@ -63,6 +63,6 @@ typedef struct elf_ctx_t { elf_status elf_init(elf_ctx *ctx, void *info); elf_status elf_load(elf_ctx *ctx); -void load_bincode_from_host_elf(process *p); +void load_bincode_from_host_elf(process *p, char *filename); #endif diff --git a/kernel/kernel.c b/kernel/kernel.c index b30b793..5cf0301 100644 --- a/kernel/kernel.c +++ b/kernel/kernel.c @@ -33,6 +33,32 @@ void enable_paging() { flush_tlb(); } +typedef union { + uint64 buf[MAX_CMDLINE_ARGS]; + char *argv[MAX_CMDLINE_ARGS]; +} arg_buf; + +// +// returns the number (should be 1) of string(s) after PKE kernel in command line. +// and store the string(s) in arg_bug_msg. +// +static size_t parse_args(arg_buf *arg_bug_msg) { + // HTIFSYS_getmainvars frontend call reads command arguments to (input) *arg_bug_msg + long r = frontend_syscall(HTIFSYS_getmainvars, (uint64)arg_bug_msg, + sizeof(*arg_bug_msg), 0, 0, 0, 0, 0); + kassert(r == 0); + + size_t pk_argc = arg_bug_msg->buf[0]; + uint64 *pk_argv = &arg_bug_msg->buf[1]; + + int arg = 1; // skip the PKE OS kernel string, leave behind only the application name + for (size_t i = 0; arg + i < pk_argc; i++) + arg_bug_msg->argv[i] = (char *)(uintptr_t)pk_argv[arg + i]; + + //returns the number of strings after PKE kernel in command line + return pk_argc - arg; +} + // // load the elf, and construct a "process" (with only a trapframe). // load_bincode_from_host_elf is defined in elf.c @@ -43,7 +69,13 @@ process* load_user_program() { proc = alloc_process(); sprint("User application is loading.\n"); - load_bincode_from_host_elf(proc); + arg_buf arg_bug_msg; + + // retrieve command line arguements + size_t argc = parse_args(&arg_bug_msg); + if (!argc) panic("You need to specify the application program!\n"); + + load_bincode_from_host_elf(proc, arg_bug_msg.argv[0]); return proc; } diff --git a/user/app_cat.c b/user/app_cat.c new file mode 100644 index 0000000..6ffc1b6 --- /dev/null +++ b/user/app_cat.c @@ -0,0 +1,23 @@ +#include "user_lib.h" +#include "util/string.h" +#include "util/types.h" + +int main(int argc, char *argv[]) { + int fd; + int MAXBUF = 512; + char buf[MAXBUF]; + char *filename = argv[0]; + + printu("\n======== cat command ========\n"); + printu("cat: %s\n", filename); + + fd = open(filename, O_RDWR); + printu("file descriptor fd: %d\n", fd); + + read_u(fd, buf, MAXBUF); + printu("read content: \n%s\n", buf); + close(fd); + + exit(0); + return 0; +} diff --git a/user/app_echo.c b/user/app_echo.c new file mode 100644 index 0000000..f106728 --- /dev/null +++ b/user/app_echo.c @@ -0,0 +1,20 @@ +#include "user_lib.h" +#include "util/string.h" +#include "util/types.h" + +int main(int argc, char *argv[]) { + int fd; + char str[] = "hello world"; + char *filename = argv[0]; + printu("\n======== echo command ========\n"); + printu("echo: %s\n", filename); + + fd = open(filename, O_RDWR | O_CREAT); + printu("file descriptor fd: %d\n", fd); + + write_u(fd, str, strlen(str)); + printu("write content: \n%s\n", str); + close(fd); + exit(0); + return 0; +} diff --git a/user/app_hardlink.c b/user/app_hardlink.c deleted file mode 100644 index 7e209e5..0000000 --- a/user/app_hardlink.c +++ /dev/null @@ -1,94 +0,0 @@ -#include "user_lib.h" -#include "util/string.h" -#include "util/types.h" - -void ls(char *path) { - int dir_fd = opendir_u(path); - printu("------------------------------\n"); - printu("ls \"%s\":\n", path); - printu("[name] [inode_num]\n"); - struct dir dir; - int width = 20; - while(readdir_u(dir_fd, &dir) == 0) { - // we do not have %ms :( - char name[width + 1]; - memset(name, ' ', width + 1); - name[width] = '\0'; - if (strlen(dir.name) < width) { - strcpy(name, dir.name); - name[strlen(dir.name)] = ' '; - printu("%s %d\n", name, dir.inum); - } - else - printu("%s %d\n", dir.name, dir.inum); - } - printu("------------------------------\n"); - closedir_u(dir_fd); -} - -int main(int argc, char *argv[]) { - int MAXBUF = 512; - char str[] = "hello world"; - char buf[MAXBUF]; - int fd1, fd2; - - printu("\n======== establish the file ========\n"); - - fd1 = open("/RAMDISK0/ramfile", O_RDWR | O_CREAT); - printu("create file: /RAMDISK0/ramfile\n"); - close(fd1); - - printu("\n======== Test 1: hard link ========\n"); - - link_u("/RAMDISK0/ramfile", "/RAMDISK0/ramfile2"); - printu("create hard link: /RAMDISK0/ramfile2 -> /RAMDISK0/ramfile\n"); - - fd1 = open("/RAMDISK0/ramfile", O_RDWR); - fd2 = open("/RAMDISK0/ramfile2", O_RDWR); - - printu("file descriptor fd1 (ramfile): %d\n", fd1); - printu("file descriptor fd2 (ramfile2): %d\n", fd2); - - // check the number of hard links to ramfile on disk - struct istat st; - disk_stat_u(fd1, &st); - printu("ramfile hard links: %d\n", st.st_nlinks); - if (st.st_nlinks != 2) { - printu("ERROR: the number of hard links to ramfile should be 2, but it is %d\n", - st.st_nlinks); - exit(-1); - } - - write_u(fd1, str, strlen(str)); - printu("/RAMDISK0/ramfile write content: \n%s\n", str); - - read_u(fd2, buf, MAXBUF); - printu("/RAMDISK0/ramfile2 read content: \n%s\n", buf); - - close(fd1); - close(fd2); - - printu("\n======== Test 2: unlink ========\n"); - - ls("/RAMDISK0"); - - unlink_u("/RAMDISK0/ramfile"); - printu("unlink: /RAMDISK0/ramfile\n"); - - ls("/RAMDISK0"); - - // check the number of hard links to ramfile2 on disk - fd2 = open("/RAMDISK0/ramfile2", O_RDWR); - disk_stat_u(fd2, &st); - printu("ramfile2 hard links: %d\n", st.st_nlinks); - if (st.st_nlinks != 1) { - printu("ERROR: the number of hard links to ramfile should be 1, but it is %d\n", - st.st_nlinks); - exit(-1); - } - close(fd2); - - printu("\nAll tests passed!\n\n"); - exit(0); - return 0; -} diff --git a/user/app_ls.c b/user/app_ls.c new file mode 100644 index 0000000..f560038 --- /dev/null +++ b/user/app_ls.c @@ -0,0 +1,31 @@ +#include "user_lib.h" +#include "util/string.h" +#include "util/types.h" + +int main(int argc, char *argv[]) { + char *path = argv[0]; + int dir_fd = opendir_u(path); + printu("---------- ls command -----------\n"); + printu("ls \"%s\":\n", path); + printu("[name] [inode_num]\n"); + struct dir dir; + int width = 20; + while(readdir_u(dir_fd, &dir) == 0) { + // we do not have %ms :( + char name[width + 1]; + memset(name, ' ', width + 1); + name[width] = '\0'; + if (strlen(dir.name) < width) { + strcpy(name, dir.name); + name[strlen(dir.name)] = ' '; + printu("%s %d\n", name, dir.inum); + } + else + printu("%s %d\n", dir.name, dir.inum); + } + printu("------------------------------\n"); + closedir_u(dir_fd); + + exit(0); + return 0; +} \ No newline at end of file diff --git a/user/app_mkdir.c b/user/app_mkdir.c new file mode 100644 index 0000000..8428f8d --- /dev/null +++ b/user/app_mkdir.c @@ -0,0 +1,15 @@ +#include "user_lib.h" +#include "util/string.h" +#include "util/types.h" + + +int main(int argc, char *argv[]) { + char *new_dir = argv[0]; + printu("\n======== mkdir command ========\n"); + + mkdir_u(new_dir); + printu("mkdir: %s\n", new_dir); + + exit(0); + return 0; +} diff --git a/user/app_shell.c b/user/app_shell.c new file mode 100644 index 0000000..df83692 --- /dev/null +++ b/user/app_shell.c @@ -0,0 +1,53 @@ +/* + * This app starts a very simple shell and executes some simple commands. + * The commands are stored in the hostfs_root/shellrc + * The shell loads the file and executes the command line by line. + */ +#include "user_lib.h" +#include "string.h" +#include "util/types.h" + +int main(int argc, char *argv[]) { + printu("\n======== Shell Start ========\n\n"); + int fd; + int MAXBUF = 1024; + char buf[MAXBUF]; + char *token; + char delim[3] = " \n"; + fd = open("/shellrc", O_RDONLY); + + read_u(fd, buf, MAXBUF); + close(fd); + char *command = naive_malloc(); + char *para = naive_malloc(); + int start = 0; + while (1) + { + if(!start) { + token = strtok(buf, delim); + start = 1; + } + else + token = strtok(NULL, delim); + strcpy(command, token); + token = strtok(NULL, delim); + strcpy(para, token); + if(strcmp(command, "END") == 0 && strcmp(para, "END") == 0) + break; + printu("Next command: %s %s\n\n", command, para); + printu("==========Command Start============\n\n"); + int pid = fork(); + if(pid == 0) { + int ret = exec(command, para); + if (ret == -1) + printu("exec failed!\n"); + } + else + { + wait(pid); + printu("==========Command End============\n\n"); + } + } + exit(0); + return 0; +} diff --git a/user/app_touch.c b/user/app_touch.c new file mode 100644 index 0000000..f79d3ba --- /dev/null +++ b/user/app_touch.c @@ -0,0 +1,17 @@ +#include "user_lib.h" +#include "util/string.h" +#include "util/types.h" + +int main(int argc, char *argv[]) { + int fd; + char *filename = argv[0]; + printu("\n======== touch command ========\n"); + printu("touch: %s\n", filename); + + fd = open(filename, O_CREAT); + printu("file descriptor fd: %d\n", fd); + + close(fd); + exit(0); + return 0; +}