From c4b07e8a00f6ebc5e6029a5f49419d2c521db07a Mon Sep 17 00:00:00 2001 From: Zhiyuan Shao Date: Thu, 24 Aug 2023 10:14:38 +0800 Subject: [PATCH] init commit of lab5_1 --- Makefile | 2 +- kernel/config.h | 4 +- kernel/kernel.lds | 5 +- kernel/machine/mentry.S | 3 +- kernel/machine/minit.c | 32 ++++++++++++- kernel/machine/uart.c | 74 +++++++++++++++++++++++++++++ kernel/machine/uart.h | 27 +++++++++++ kernel/syscall.c | 39 +++++++++++++++ kernel/syscall.h | 5 +- kernel/vmm.c | 4 ++ spike_interface/dts_parse.c | 18 +++++++ spike_interface/dts_parse.h | 6 ++- user/app_hardlink.c | 94 ------------------------------------- user/app_polling.c | 20 ++++++++ user/user_lib.c | 41 ++++++++++++++++ user/user_lib.h | 5 ++ 16 files changed, 276 insertions(+), 103 deletions(-) create mode 100644 kernel/machine/uart.c create mode 100644 kernel/machine/uart.h delete mode 100644 user/app_hardlink.c create mode 100644 user/app_polling.c diff --git a/Makefile b/Makefile index 980e035..abf1899 100644 --- a/Makefile +++ b/Makefile @@ -68,7 +68,7 @@ USER_CPPS := user/*.c USER_CPPS := $(wildcard $(USER_CPPS)) USER_OBJS := $(addprefix $(OBJ_DIR)/, $(patsubst %.c,%.o,$(USER_CPPS))) -USER_TARGET := $(OBJ_DIR)/app_hardlink +USER_TARGET := $(OBJ_DIR)/app_polling #------------------------targets------------------------ $(OBJ_DIR): @-mkdir -p $(OBJ_DIR) diff --git a/kernel/config.h b/kernel/config.h index bdc8270..cfe9208 100644 --- a/kernel/config.h +++ b/kernel/config.h @@ -7,8 +7,8 @@ //interval of timer interrupt. added @lab1_3 #define TIMER_INTERVAL 1000000 -// the maximum memory space that PKE is allowed to manage. added @lab2_1 -#define PKE_MAX_ALLOWABLE_RAM 128 * 1024 * 1024 +// redefine the maximum memory space that PKE is allowed to manage @lab5_1 +#define PKE_MAX_ALLOWABLE_RAM 1 * 1024 * 1024 // the ending physical address that PKE observes. added @lab2_1 #define PHYS_TOP (DRAM_BASE + PKE_MAX_ALLOWABLE_RAM) diff --git a/kernel/kernel.lds b/kernel/kernel.lds index 90d730f..0814e66 100644 --- a/kernel/kernel.lds +++ b/kernel/kernel.lds @@ -14,7 +14,10 @@ SECTIONS /* Begining of code and text segment, starts from DRAM_BASE to be effective before enabling paging */ . = 0x80000000; _ftext = .; - + .text : + { + *(.text.init) + } /* text: Program code section */ .text : { diff --git a/kernel/machine/mentry.S b/kernel/machine/mentry.S index f3d3458..ba4b142 100644 --- a/kernel/machine/mentry.S +++ b/kernel/machine/mentry.S @@ -9,7 +9,8 @@ # [a1] = pointer to the DTS (i.e., Device Tree String), which is stored in the memory of # RISC-V guest computer emulated by spike. # - +.option norvc +.section .text.init,"ax",@progbits .globl _mentry _mentry: # [mscratch] = 0; mscratch points the stack bottom of machine mode computer diff --git a/kernel/machine/minit.c b/kernel/machine/minit.c index b258f71..350029b 100644 --- a/kernel/machine/minit.c +++ b/kernel/machine/minit.c @@ -6,7 +6,7 @@ #include "kernel/riscv.h" #include "kernel/config.h" #include "spike_interface/spike_utils.h" - +#include "uart.h" // // global variables are placed in the .data section. // stack0 is the privilege mode stack(s) of the proxy kernel on CPU(s) @@ -76,6 +76,26 @@ static void delegate_traps() { assert(read_csr(medeleg) == exceptions); } +// +// setup the Physical Memory Protection mechanism. the purpose is to make PKE runable on +// both Spike and Zedboard (especially Zedboard). the function is borrowed from PK. +// added @lab5_1. +// +void setup_pmp(void) { + // Set up a PMP to permit access to all of memory. + // Ignore the illegal-instruction trap if PMPs aren't supported. + uintptr_t pmpc = PMP_NAPOT | PMP_R | PMP_W | PMP_X; + asm volatile( + "la t0, 1f\n\t" + "csrrw t0, mtvec, t0\n\t" + "csrw pmpaddr0, %1\n\t" + "csrw pmpcfg0, %0\n\t" + ".align 2\n\t" + "1: csrw mtvec, t0" + : + : "r"(pmpc), "r"(-1UL) + : "t0"); +} // // enabling timer interrupt (irq) in Machine mode. added @lab1_3 // @@ -95,12 +115,22 @@ void m_start(uintptr_t hartid, uintptr_t dtb) { // functions with "spike_" prefix are all defined in codes under spike_interface/, // sprint is also defined in spike_interface/spike_utils.c spike_file_init(); + // query_uart is added @lab5_1 + query_uart(dtb); sprint("In m_start, hartid:%d\n", hartid); // init HTIF (Host-Target InterFace) and memory by using the Device Table Blob (DTB) // init_dtb() is defined above. init_dtb(dtb); + // following code block is added @lab5_1 + setup_pmp(); + extern char smode_trap_vector; + write_csr(stvec, (uint64)smode_trap_vector); + write_csr(sscratch, 0); + write_csr(sie, 0); + set_csr(sstatus, SSTATUS_SUM | SSTATUS_FS); + // save the address of trap frame for interrupt in M mode to "mscratch". added @lab1_2 write_csr(mscratch, &g_itrframe); diff --git a/kernel/machine/uart.c b/kernel/machine/uart.c new file mode 100644 index 0000000..983c667 --- /dev/null +++ b/kernel/machine/uart.c @@ -0,0 +1,74 @@ +// added @lab5_1. + +#include +#include "uart.h" +//add +#include "util/types.h" +#include "spike_interface/dts_parse.h" + +volatile uint32* uart; + + +void uart_putchar(uint8 ch) +{ + volatile uint32 *status = (void*)(uintptr_t)0x60000008; + volatile uint32 *tx = (void*)(uintptr_t)0x60000004; + while (*status & 0x00000008); + *tx = ch; +} + +int uart_getchar() +{ + volatile uint32 *rx = (void*)(uintptr_t)0x60000000; + volatile uint32 *status = (void*)(uintptr_t)0x60000008; + while (!(*status & 0x00000001)); + int32_t ch = *rx; + return ch; +} + +struct uart_scan +{ + int compat; + uint64 reg; +}; + +static void uart_open(const struct fdt_scan_node *node, void *extra) +{ + struct uart_scan *scan = (struct uart_scan *)extra; + memset(scan, 0, sizeof(*scan)); +} + +static void uart_prop(const struct fdt_scan_prop *prop, void *extra) +{ + struct uart_scan *scan = (struct uart_scan *)extra; + if (!strcmp(prop->name, "compatible") && fdt_string_list_index(prop, "sifive,uart0") >= 0) { + scan->compat = 1; + } else if (!strcmp(prop->name, "reg")) { + fdt_get_address(prop->node->parent, prop->value, &scan->reg); + } +} + +static void uart_done(const struct fdt_scan_node *node, void *extra) +{ + struct uart_scan *scan = (struct uart_scan *)extra; + if (!scan->compat || !scan->reg || uart) return; + + // Enable Rx/Tx channels + uart = (void*)(uintptr_t)scan->reg; + uart[UART_REG_TXCTRL] = UART_TXEN; + uart[UART_REG_RXCTRL] = UART_RXEN; +} + +void query_uart(uintptr_t fdt) +{ + struct fdt_cb cb; + struct uart_scan scan; + + memset(&cb, 0, sizeof(cb)); + cb.open = uart_open; + cb.prop = uart_prop; + cb.done = uart_done; + cb.extra = &scan; + + fdt_scan(fdt, &cb); +} diff --git a/kernel/machine/uart.h b/kernel/machine/uart.h new file mode 100644 index 0000000..8959903 --- /dev/null +++ b/kernel/machine/uart.h @@ -0,0 +1,27 @@ +// added @lab5_1. + +#ifndef _RISCV_UART_H +#define _RISCV_UART_H + +#include +//add +#include "util/types.h" + +extern volatile uint32* uart; + +#define UART_REG_TXFIFO 0 +#define UART_REG_RXFIFO 1 +#define UART_REG_TXCTRL 2 +#define UART_REG_RXCTRL 3 +#define UART_REG_IE 4 +#define UART_REG_IP 5 +#define UART_REG_DIV 6 + +#define UART_TXEN 0x1 +#define UART_RXEN 0x1 + +void uart_putchar(uint8_t ch); +int uart_getchar(); +void query_uart(uintptr_t dtb); + +#endif diff --git a/kernel/syscall.c b/kernel/syscall.c index 4ef7a33..088afe8 100644 --- a/kernel/syscall.c +++ b/kernel/syscall.c @@ -213,6 +213,38 @@ ssize_t sys_user_unlink(char * vfn){ return do_unlink(pfn); } +// +// implement the SYS_user_uart_putchar syscall. added @lab5_1 +// +void sys_user_uart_putchar(uint8 ch) { + volatile uint32 *status = (void*)(uintptr_t)0x60000008; + volatile uint32 *tx = (void*)(uintptr_t)0x60000004; + while (*status & 0x00000008); + *tx = ch; +} + +// added @lab5_1 +ssize_t sys_user_uart_getchar() { + // TODO (lab5_1 and lab5_2): implment the syscall of sys_user_uart_getchar and modify it in lab5_2. + // hint (lab5_1): the functionality of sys_user_uart_getchar is to get data from UART address. + // therefore, we should let a pointer point, insert it in + // the rear of ready queue, and finally, schedule a READY process to run. + // hint (lab5_2): the functionality of sys_user_uart_getchar is let process sleep + // and register a callback function to handle system call return value. + // therefore, we should call do_sleep to let process 0 sleep. + // Note that the do_sleep function will never return, and the function passed to do_sleep + // will be called in do_wake. + panic( "You have to implement sys_user_uart_getchar to get data from UART using uartgetchar in lab5_1 and modify it in lab5_2.\n" ); +} + +// used for car control. added @lab5_1 +void sys_user_uart2_putchar(uint8 ch) { + volatile uint32 *status = (void*)(uintptr_t)0x60001008; + volatile uint32 *tx = (void*)(uintptr_t)0x60001004; + while (*status & 0x00000008); + *tx = ch; +} + // // [a0]: the syscall number; [a1] ... [a7]: arguments to the syscalls. // returns the code of success, (e.g., 0 means success, fail for otherwise) @@ -261,6 +293,13 @@ long do_syscall(long a0, long a1, long a2, long a3, long a4, long a5, long a6, l return sys_user_link((char *)a1, (char *)a2); case SYS_user_unlink: return sys_user_unlink((char *)a1); + // following 3 cases are added @lab5_1 + case SYS_user_uart_putchar: + sys_user_uart_putchar(a1);return 1; + case SYS_user_uart_getchar: + return sys_user_uart_getchar(); + case SYS_user_uart2_putchar: + sys_user_uart2_putchar(a1);return 1; default: panic("Unknown syscall %ld \n", a0); } diff --git a/kernel/syscall.h b/kernel/syscall.h index 0486c81..f59fbce 100644 --- a/kernel/syscall.h +++ b/kernel/syscall.h @@ -30,7 +30,10 @@ // added @lab4_3 #define SYS_user_link (SYS_user_base + 28) #define SYS_user_unlink (SYS_user_base + 29) - +// added @lab5_1 +#define SYS_user_uart_putchar (SYS_user_base + 30) +#define SYS_user_uart_getchar (SYS_user_base + 31) +#define SYS_user_uart2_putchar (SYS_user_base + 32) long do_syscall(long a0, long a1, long a2, long a3, long a4, long a5, long a6, long a7); #endif diff --git a/kernel/vmm.c b/kernel/vmm.c index 3dd02be..97e71e3 100644 --- a/kernel/vmm.c +++ b/kernel/vmm.c @@ -133,6 +133,10 @@ void kern_vm_init(void) { sprint("KERN_BASE 0x%lx\n", lookup_pa(t_page_dir, KERN_BASE)); + // map IO space @lab5_1 + kern_vm_map(t_page_dir, (uint64)0x60000000, (uint64)0x60000000, (uint64)0x60020000 - (uint64)0x60000000, + prot_to_type(PROT_READ | PROT_WRITE, 0)); + // also (direct) map remaining address space, to make them accessable from kernel. // this is important when kernel needs to access the memory content of user's app // without copying pages between kernel and user spaces. diff --git a/spike_interface/dts_parse.c b/spike_interface/dts_parse.c index 2aec5c1..22ee94f 100644 --- a/spike_interface/dts_parse.c +++ b/spike_interface/dts_parse.c @@ -97,3 +97,21 @@ void fdt_scan(uint64 fdt, const struct fdt_cb *cb) { fdt_scan_helper(lex, strings, 0, cb); } + +// following two functions are added @lab5_1 +uint32 fdt_get_value(const struct fdt_scan_prop *prop, uint32 index) { + return bswap(prop->value[index]); +} + +int fdt_string_list_index(const struct fdt_scan_prop *prop, const char *str) +{ + const char *list = (const char *)prop->value; + const char *end = list + prop->len; + int index = 0; + while (end - list > 0) { + if (!strcmp(list, str)) return index; + ++index; + list += strlen(list) + 1; + } + return -1; +} diff --git a/spike_interface/dts_parse.h b/spike_interface/dts_parse.h index aea977f..bbfe534 100644 --- a/spike_interface/dts_parse.h +++ b/spike_interface/dts_parse.h @@ -56,6 +56,8 @@ uint32 fdt_size(uint64 fdt); // Extract fields const uint32 *fdt_get_address(const struct fdt_scan_node *node, const uint32 *base, uint64 *value); const uint32 *fdt_get_size(const struct fdt_scan_node *node, const uint32 *base, uint64 *value); -int fdt_string_list_index(const struct fdt_scan_prop *prop, - const char *str); // -1 if not found +int fdt_string_list_index(const struct fdt_scan_prop *prop, const char *str); // -1 if not found +//add +uint32 fdt_get_value(const struct fdt_scan_prop *prop, uint32 index); + #endif 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_polling.c b/user/app_polling.c new file mode 100644 index 0000000..4a05466 --- /dev/null +++ b/user/app_polling.c @@ -0,0 +1,20 @@ +/* + * Below is the given application for lab5_1. + * The goal of this app is to control the car via Bluetooth. + */ + +#include "user_lib.h" +#include "util/types.h" + +int main(void) { + printu("please input the instruction through bluetooth!\n"); + while(1) + { + char temp = (char)uartgetchar(); + if(temp == 'q') + break; + car_control(temp); + } + exit(0); + return 0; +} diff --git a/user/user_lib.c b/user/user_lib.c index 1c4f6d1..9e94a87 100644 --- a/user/user_lib.c +++ b/user/user_lib.c @@ -9,6 +9,7 @@ #include "util/types.h" #include "util/snprintf.h" #include "kernel/syscall.h" +#include "util/string.h" uint64 do_user_call(uint64 sysnum, uint64 a1, uint64 a2, uint64 a3, uint64 a4, uint64 a5, uint64 a6, uint64 a7) { @@ -167,3 +168,43 @@ int unlink_u(const char *fn){ int close(int fd) { return do_user_call(SYS_user_close, fd, 0, 0, 0, 0, 0, 0); } + +// +// add syscalls for uart IO @lab5_1 +// applications need to call uart_putchar to output a char to device +// +int uartputchar(char ch) { + return do_user_call(SYS_user_uart_putchar, ch, 0, 0, 0, 0, 0, 0); +} + +// +// applications need to call uart_getchar to get a char from device +// +int uartgetchar() { + return do_user_call(SYS_user_uart_getchar, 0, 0, 0, 0, 0, 0, 0); +} + +// car +int uart2putchar(char ch) { + return do_user_call(SYS_user_uart2_putchar, ch, 0, 0, 0, 0, 0, 0); +} + +void car_control(char val) { + char cmd[80]; + if(val == '1') //front + strcpy(cmd, "#006P2500T0000!#007P0500T0000!#008P2500T0000!#009P0500T0000!"); + else if(val == '2') //back + strcpy(cmd, "#006P0500T0000!#007P2500T0000!#008P0500T0000!#009P2500T0000!"); + else if(val == '3') //left + strcpy(cmd, "#006P0500T0000!#007P0500T0000!#008P0500T0000!#009P0500T0000!"); + else if(val == '4') //right + strcpy(cmd, "#006P2500T0000!#007P2500T0000!#008P2500T0000!#009P2500T0000!"); + else if(val == '0') //stop + strcpy(cmd, "#006P1500T0000!#007P1500T0000!#008P1500T0000!#009P1500T0000!"); + else + strcpy(cmd, ""); + + int i; + for(i = 0; i < strlen(cmd); i++) + uart2putchar(cmd[i]); +} diff --git a/user/user_lib.h b/user/user_lib.h index 95a686d..b1fd16c 100644 --- a/user/user_lib.h +++ b/user/user_lib.h @@ -33,5 +33,10 @@ int closedir_u(int fd); int link_u(const char *fn1, const char *fn2); int unlink_u(const char *fn); +// added @lab5_1 +int uartputchar(char ch); +int uartgetchar(); +int uart2putchar(char ch); +void car_control(char val); #endif