init commit of lab5_2

lab5_2_PLIC
Zhiyuan Shao 1 year ago
parent c4b07e8a00
commit 6151bee3cd

@ -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)

@ -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;
}
}

@ -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

@ -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);

@ -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;
}

@ -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

@ -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)

@ -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

@ -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.

@ -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;

@ -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;
}

@ -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;
}
Loading…
Cancel
Save