From 6151bee3cd929a6abac83e9d4fefa78c67d17fe5 Mon Sep 17 00:00:00 2001 From: Zhiyuan Shao Date: Thu, 24 Aug 2023 10:16:08 +0800 Subject: [PATCH] init commit of lab5_2 --- Makefile | 2 +- kernel/machine/fdt.c | 204 +++++++++++++++++++++++++++++++++++++++++ kernel/machine/fdt.h | 76 +++++++++++++++ kernel/machine/minit.c | 26 ++++++ kernel/process.c | 28 ++++++ kernel/process.h | 19 ++++ kernel/riscv.h | 8 ++ kernel/strap.c | 18 ++++ kernel/syscall.c | 12 +++ kernel/vmm.c | 4 + user/app_PLIC.c | 43 +++++++++ user/app_polling.c | 20 ---- 12 files changed, 439 insertions(+), 21 deletions(-) create mode 100644 kernel/machine/fdt.c create mode 100644 kernel/machine/fdt.h create mode 100644 user/app_PLIC.c delete mode 100644 user/app_polling.c diff --git a/Makefile b/Makefile index abf1899..dbffb15 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_polling +USER_TARGET := $(OBJ_DIR)/app_PLIC #------------------------targets------------------------ $(OBJ_DIR): @-mkdir -p $(OBJ_DIR) diff --git a/kernel/machine/fdt.c b/kernel/machine/fdt.c new file mode 100644 index 0000000..ff07bc1 --- /dev/null +++ b/kernel/machine/fdt.c @@ -0,0 +1,204 @@ +#include "fdt.h" +#include "spike_interface/spike_utils.h" +#include "util/string.h" +//#include "mtrap.h" +#include "spike_interface/dts_parse.h" +#include "util/types.h" + +static inline uint32 bswap(uint32 x) +{ +#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__ + uint32 y = (x & 0x00FF00FF) << 8 | (x & 0xFF00FF00) >> 8; + uint32 z = (y & 0x0000FFFF) << 16 | (y & 0xFFFF0000) >> 16; + return z; +#else + /* No need to swap on big endian */ + return x; +#endif +} + +static inline int isstring(char c) +{ + if (c >= 'A' && c <= 'Z') + return 1; + if (c >= 'a' && c <= 'z') + return 1; + if (c >= '0' && c <= '9') + return 1; + if (c == '\0' || c == ' ' || c == ',' || c == '-') + return 1; + return 0; +} + +static uint32 *fdt_scan_helper( + uint32 *lex, + const char *strings, + struct fdt_scan_node *node, + const struct fdt_cb *cb) +{ + struct fdt_scan_node child; + struct fdt_scan_prop prop; + int last = 0; + + child.parent = node; + // these are the default cell counts, as per the FDT spec + child.address_cells = 2; + child.size_cells = 1; + prop.node = node; + + while (1) { + switch (bswap(lex[0])) { + case FDT_NOP: { + lex += 1; + break; + } + case FDT_PROP: { + assert (!last); + prop.name = strings + bswap(lex[2]); + prop.len = bswap(lex[1]); + prop.value = lex + 3; + if (node && !strcmp(prop.name, "#address-cells")) { node->address_cells = bswap(lex[3]); } + if (node && !strcmp(prop.name, "#size-cells")) { node->size_cells = bswap(lex[3]); } + lex += 3 + (prop.len+3)/4; + cb->prop(&prop, cb->extra); + break; + } + case FDT_BEGIN_NODE: { + uint32 *lex_next; + if (!last && node && cb->done) cb->done(node, cb->extra); + last = 1; + child.name = (const char *)(lex+1); + if (cb->open) cb->open(&child, cb->extra); + lex_next = fdt_scan_helper( + lex + 2 + strlen(child.name)/4, + strings, &child, cb); + if (cb->close && cb->close(&child, cb->extra) == -1) + while (lex != lex_next) *lex++ = bswap(FDT_NOP); + lex = lex_next; + break; + } + case FDT_END_NODE: { + if (!last && node && cb->done) cb->done(node, cb->extra); + return lex + 1; + } + default: { // FDT_END + if (!last && node && cb->done) cb->done(node, cb->extra); + return lex; + } + } + } +} + + +struct plic_scan +{ + int compat; + uint64 reg; + uint32 *int_value; + int int_len; + int done; + int ndev; +}; +static void plic_open(const struct fdt_scan_node *node, void *extra) +{ + struct plic_scan *scan = (struct plic_scan *)extra; + scan->compat = 0; + scan->reg = 0; + scan->int_value = 0; +} + +static void plic_prop(const struct fdt_scan_prop *prop, void *extra) +{ + struct plic_scan *scan = (struct plic_scan *)extra; + if (!strcmp(prop->name, "compatible") && fdt_string_list_index(prop, "riscv,plic0") >= 0) { + scan->compat = 1; + } else if (!strcmp(prop->name, "reg")) { + fdt_get_address(prop->node->parent, prop->value, &scan->reg); + } else if (!strcmp(prop->name, "interrupts-extended")) { + scan->int_value = prop->value; + scan->int_len = prop->len; + } else if (!strcmp(prop->name, "riscv,ndev")) { + scan->ndev = bswap(prop->value[0]); + } +} +#define HART_BASE 0x200000 +#define HART_SIZE 0x1000 +#define ENABLE_BASE 0x2000 +#define ENABLE_SIZE 0x80 +extern volatile uint32* plic_priorities; +extern ssize_t plic_ndevs; +static void plic_done(const struct fdt_scan_node *node, void *extra) +{ + struct plic_scan *scan = (struct plic_scan *)extra; + const uint32 *value = scan->int_value; + const uint32 *end = value + scan->int_len/4; + + if (!scan->compat) return; + assert (scan->reg != 0); + assert (scan->int_value && scan->int_len % 8 == 0); + assert (scan->ndev >= 0 && scan->ndev < 1024); + assert (!scan->done); // only one plic + + scan->done = 1; + plic_priorities = (uint32*)(uintptr_t)scan->reg; + plic_ndevs = scan->ndev; + + for (int index = 0; end - value > 0; ++index) { + uint32 phandle = bswap(value[0]); + uint32 cpu_int = bswap(value[1]); + int hart = 0; + + hls_t *hls = OTHER_HLS(hart); + if (cpu_int == IRQ_M_EXT) { + hls->plic_m_ie = (uint32*)((uintptr_t)scan->reg + ENABLE_BASE + ENABLE_SIZE * index); + hls->plic_m_thresh = (uint32*) ((uintptr_t)scan->reg + HART_BASE + HART_SIZE * index); + } else if (cpu_int == IRQ_S_EXT) { + hls->plic_s_ie = (uint32*)((uintptr_t)scan->reg + ENABLE_BASE + ENABLE_SIZE * index); + hls->plic_s_thresh = (uint32*) ((uintptr_t)scan->reg + HART_BASE + HART_SIZE * index); + } else { + sprint("PLIC wired hart %d to wrong interrupt %d", hart, cpu_int); + } + + value += 2; + } +} +void query_plic(uintptr_t fdt) +{ + struct fdt_cb cb; + struct plic_scan scan; + + memset(&cb, 0, sizeof(cb)); + cb.open = plic_open; + cb.prop = plic_prop; + cb.done = plic_done; + cb.extra = &scan; + + scan.done = 0; + fdt_scan(fdt, &cb); +} +void hart_plic_init() +{ + // clear pending interrupts + // *HLS()->ipi = 0; + // *HLS()->timecmp = -1ULL; + write_csr(mip, 0); + + if (!plic_ndevs) + return; + + size_t ie_words = (plic_ndevs + 8 * sizeof(*HLS()->plic_s_ie) - 1) / + (8 * sizeof(*HLS()->plic_s_ie)); + for (size_t i = 0; i < ie_words; i++) { + if (HLS()->plic_s_ie) { + // Supervisor not always present + HLS()->plic_s_ie[i] = __UINT32_MAX__; + } + ////////////////////////////// + HLS()->plic_m_ie[i] = __UINT32_MAX__; + } + *HLS()->plic_m_thresh = 1; + if (HLS()->plic_s_thresh) { + // Supervisor not always present + *HLS()->plic_s_thresh = 0; + } +} \ No newline at end of file diff --git a/kernel/machine/fdt.h b/kernel/machine/fdt.h new file mode 100644 index 0000000..b289778 --- /dev/null +++ b/kernel/machine/fdt.h @@ -0,0 +1,76 @@ +// See LICENSE for license details. + +#ifndef FDT_H +#define FDT_H +#include "util/types.h" +#include "kernel/riscv.h" +typedef struct { + volatile uint32* ipi; + volatile int mipi_pending; + + volatile uint64* timecmp; + + volatile uint32* plic_m_thresh; + volatile uint32* plic_m_ie; + volatile uint32* plic_s_thresh; + volatile uint32* plic_s_ie; +} hls_t; +#define STACK_POINTER() ({ \ + uintptr_t __sp; \ + __asm__("mv %0, sp" : "=r"(__sp)); \ + __sp; \ +}) +#define RISCV_PGSHIFT 12 +#define RISCV_PGSIZE (1 << RISCV_PGSHIFT) +#define HLS_SIZE 64 +#define MACHINE_STACK_TOP() \ + ({ (void*)((STACK_POINTER() + RISCV_PGSIZE) & -RISCV_PGSIZE); }) + +// hart-local storage, at top of stack +#define HLS() ((hls_t*)(MACHINE_STACK_TOP() - HLS_SIZE)) +#define OTHER_HLS(id) ((hls_t*)((void*)HLS() + RISCV_PGSIZE * ((id) - read_const_csr(mhartid)))) +#define FDT_MAGIC 0xd00dfeed +#define FDT_VERSION 17 + +#define IRQ_U_SOFT 0 +#define IRQ_S_SOFT 1 +#define IRQ_VS_SOFT 2 +#define IRQ_M_SOFT 3 +#define IRQ_U_TIMER 4 +#define IRQ_S_TIMER 5 +#define IRQ_VS_TIMER 6 +#define IRQ_M_TIMER 7 +#define IRQ_U_EXT 8 +#define IRQ_S_EXT 9 +#define IRQ_VS_EXT 10 +#define IRQ_M_EXT 11 +#define IRQ_S_GEXT 12 +#define IRQ_COP 12 +#define IRQ_HOST 13 + + +#define FDT_BEGIN_NODE 1 +#define FDT_END_NODE 2 +#define FDT_PROP 3 +#define FDT_NOP 4 +#define FDT_END 9 + + + + +// Setup memory+clint+plic +void query_plic(size_t fdt); +void hart_plic_init(); + + + +// Optional FDT preloaded external payload +extern void* kernel_start; +extern void* kernel_end; + +#ifdef PK_PRINT_DEVICE_TREE +// Prints the device tree to the console as a DTS +void fdt_print(size_t fdt); +#endif + +#endif diff --git a/kernel/machine/minit.c b/kernel/machine/minit.c index 350029b..d9955bb 100644 --- a/kernel/machine/minit.c +++ b/kernel/machine/minit.c @@ -7,6 +7,9 @@ #include "kernel/config.h" #include "spike_interface/spike_utils.h" #include "uart.h" +#include "util/string.h" +#include "fdt.h" + // // global variables are placed in the .data section. // stack0 is the privilege mode stack(s) of the proxy kernel on CPU(s) @@ -30,6 +33,10 @@ extern uint64 g_mem_size; // registers when interrupt hapens in M mode. added @lab1_2 riscv_regs g_itrframe; +// following two variables are added @lab5_2 +volatile uint32* plic_priorities; +ssize_t plic_ndevs; + // // get the information of HTIF (calling interface) and the emulated memory by // parsing the Device Tree Blog (DTB, actually DTS) stored in memory. @@ -107,6 +114,14 @@ void timerinit(uintptr_t hartid) { write_csr(mie, read_csr(mie) | MIE_MTIE); } +// +// set plic priority to the highest. added @lab5_2 +// +void plic_init() { + for (size_t i = 1; i <= plic_ndevs; i++) + plic_priorities[i] = 6; +} + // // m_start: machine mode C entry point. // @@ -119,12 +134,23 @@ void m_start(uintptr_t hartid, uintptr_t dtb) { query_uart(dtb); sprint("In m_start, hartid:%d\n", hartid); + // init plic. added @lab5_2 + query_plic(dtb); + plic_init(); + hart_plic_init(); + // 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(); + + // init bluetooth external interrupt. added @lab5_2 + volatile int *ctrl_reg = (void *)(uintptr_t)0x6000000c; + int k = *ctrl_reg; + *ctrl_reg = k | (1 << 4); + extern char smode_trap_vector; write_csr(stvec, (uint64)smode_trap_vector); write_csr(sscratch, 0); diff --git a/kernel/process.c b/kernel/process.c index ddbbc35..b56e240 100644 --- a/kernel/process.c +++ b/kernel/process.c @@ -254,3 +254,31 @@ int do_fork( process* parent) return child->pid; } + +// following 3 functions are added @lab5_2 +void do_sleep(void wake_cb(void*), void* wake_cb_arg){ + current->status = BLOCKED; + set_wake_callback(current->pid, wake_cb, wake_cb_arg); + schedule(); +} + +extern process* ready_queue_head; + +void do_wake(uint64 pid){ + procs[pid].status = READY; + current->status = READY; + insert_to_ready_queue(&procs[pid]); + insert_to_ready_queue( current ); + + if (procs[pid].wake_callback) + procs[pid].wake_callback(procs[pid].wake_callback_arg); + + schedule(); +} + +void set_wake_callback(uint64 pid, void (*wake_cb)(void *), void *wake_cb_arg) { + if (wake_cb != NULL) + procs[pid].wake_callback = wake_cb; + if (wake_cb_arg != NULL) + procs[pid].wake_callback_arg = wake_cb_arg; +} diff --git a/kernel/process.h b/kernel/process.h index 5f4c63b..2ce80cb 100644 --- a/kernel/process.h +++ b/kernel/process.h @@ -93,6 +93,11 @@ typedef struct process_t { // file system. added @lab4_1 proc_file_management *pfiles; + + // wake up callback, registered by do_sleep(). added @lab5_2 + // it will be called when process is waken up. + void (*wake_callback)(void *); + void *wake_callback_arg; }process; // switch to run user app @@ -110,4 +115,18 @@ int do_fork(process* parent); // current running process extern process* current; +// prototype declarations added @lab5_2 +// sleep current process +void do_sleep(void (*wake_cb)(void *), void *wake_cb_arg); +// awake process with pid +void do_wake(uint64 pid); +// set wake callback for process with pid +void set_wake_callback(uint64 pid, void (*wake_cb)(void *), void *wake_cb_arg); + +extern process procs[NPROC]; + +struct update_uartvalue_ctx { + char uartvalue; + uint64 pid; +}; #endif diff --git a/kernel/riscv.h b/kernel/riscv.h index 9668580..59bda48 100644 --- a/kernel/riscv.h +++ b/kernel/riscv.h @@ -24,6 +24,10 @@ #define MIP_STIP (1 << IRQ_S_TIMER) // s-mode timer interrupt pending #define MIP_MSIP (1 << IRQ_M_SOFT) // m-mode software interrupt pending +// plic handling. added @lab5_2 +#define IRQ_M_EXT 11 // m-mode external interrupt +#define MIP_MEIP (1 << IRQ_M_EXT) // m-mode external interrupt pending + // pysical memory protection choices #define PMP_R 0x01 #define PMP_W 0x02 @@ -56,6 +60,10 @@ #define CAUSE_MTIMER 0x8000000000000007 #define CAUSE_MTIMER_S_TRAP 0x8000000000000001 +// plics. added @lab5_2 +#define CAUSE_MEXTERNAL 0x800000000000000b +#define CAUSE_MEXTERNEL_S_TRAP 0x8000000000000009 + //Supervisor interrupt-pending register #define SIP_SSIP (1L << 1) diff --git a/kernel/strap.c b/kernel/strap.c index c6ac60c..32108e3 100644 --- a/kernel/strap.c +++ b/kernel/strap.c @@ -106,6 +106,24 @@ void smode_trap_handler(void) { // invoke round-robin scheduler. added @lab3_3 rrsched(); break; + // added @lab5_2 + case CAUSE_MEXTERNEL_S_TRAP: + { + //reset the PLIC so that we can get the next external interrupt. + volatile int irq = *(uint32 *)0xc201004L; + *(uint32 *)0xc201004L = irq; + volatile int *ctrl_reg = (void *)(uintptr_t)0x6000000c; + *ctrl_reg = *ctrl_reg | (1 << 4); + // TODO (lab5_2): implment the case of CAUSE_MEXTERNEL_S_TRAP. + // hint: the case of CAUSE_MEXTERNEL_S_TRAP is to get data from UART address and wake + // the process. therefore, you need to construct an update_uartvalue_ctx structure + // then store the interrupt processing process pid and the uart value in it + // and use this structure to update the wake callback context of the process + // finally call do_wake to wake up the process. + panic( "You have to implement CAUSE_MEXTERNEL_S_TRAP to get data from UART and wake the process 0 in lab5_2.\n" ); + + break; + } case CAUSE_STORE_PAGE_FAULT: case CAUSE_LOAD_PAGE_FAULT: // the address of missing page is stored in stval diff --git a/kernel/syscall.c b/kernel/syscall.c index 088afe8..3118141 100644 --- a/kernel/syscall.c +++ b/kernel/syscall.c @@ -223,6 +223,18 @@ void sys_user_uart_putchar(uint8 ch) { *tx = ch; } +// added @lab5_1. Sets the return value of the uart_getchar system call, which should be called +// when waking up the process. For ctx, there needs to be the process number that initiates +// the system call and the data obtained from the uart device. +void update_uartvalue(void *ctx) { + struct update_uartvalue_ctx *uart_ctx = (struct update_uartvalue_ctx *)ctx; + char value = uart_ctx->uartvalue; + process *proc = &procs[uart_ctx->pid]; + + // set system call return value + proc->trapframe->regs.a0 = (uint64)value; +} + // 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. diff --git a/kernel/vmm.c b/kernel/vmm.c index 97e71e3..d9a40ad 100644 --- a/kernel/vmm.c +++ b/kernel/vmm.c @@ -143,6 +143,10 @@ void kern_vm_init(void) { kern_vm_map(t_page_dir, (uint64)_etext, (uint64)_etext, PHYS_TOP - (uint64)_etext, prot_to_type(PROT_READ | PROT_WRITE, 0)); + // plic IO space maping. @lab5_2 + kern_vm_map(t_page_dir, (uint64)0xc201000, (uint64)0xc201000, (uint64)0x100, + prot_to_type(PROT_READ | PROT_WRITE, 0)); + sprint("physical address of _etext is: 0x%lx\n", lookup_pa(t_page_dir, (uint64)_etext)); g_kernel_pagetable = t_page_dir; diff --git a/user/app_PLIC.c b/user/app_PLIC.c new file mode 100644 index 0000000..643d904 --- /dev/null +++ b/user/app_PLIC.c @@ -0,0 +1,43 @@ +/* + * Below is the given application for lab5_2. + * The goal of this app is to control the car via Bluetooth. + */ + +#include "user_lib.h" +#include "util/types.h" +void delay(unsigned int time){ + unsigned int a = 0xfffff ,b = time; + volatile unsigned int i,j; + for(i = 0; i < a; ++i){ + for(j = 0; j < b; ++j){ + ; + } + } +} +int main(void) { + printu("Hello world!\n"); + int i; + int pid = fork(); + if(pid == 0) + { + while (1) + { + delay(3); + printu("waiting for you!\n"); + } + } + else + { + while(1) + { + char temp = (char)uartgetchar(); + if(temp == 'q') + break; + car_control(temp); + } + } + + exit(0); + + return 0; +} diff --git a/user/app_polling.c b/user/app_polling.c deleted file mode 100644 index 4a05466..0000000 --- a/user/app_polling.c +++ /dev/null @@ -1,20 +0,0 @@ -/* - * 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; -}