parent
c4b07e8a00
commit
6151bee3cd
@ -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
|
@ -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…
Reference in new issue