init commit of lab4_1
This commit is contained in:
parent
f287fda5a6
commit
f6d24eed96
|
@ -4,8 +4,10 @@ Copyright License
|
|||
The PKE software is:
|
||||
|
||||
Copyright (c) 2021, Zhiyuan Shao (zyshao@hust.edu.cn),
|
||||
Yi Gui (gy163email@163.com),
|
||||
Yan Jiao (773709579@qq.com),
|
||||
Ziming Yuan (1223962053@qq.com),
|
||||
Yixin Song (474309045@qq.com),
|
||||
Boyang Li (liboyang_hust@163.com),
|
||||
Zhenfei Huo(393900861@qq.com)
|
||||
Huazhong University of Science and Technology
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining
|
||||
|
|
2
Makefile
2
Makefile
|
@ -70,7 +70,7 @@ USER_OBJS := $(addprefix $(OBJ_DIR)/, $(patsubst %.c,%.o,$(USER_CPPS)))
|
|||
|
||||
|
||||
|
||||
USER_TARGET := $(OBJ_DIR)/app_two_long_loops
|
||||
USER_TARGET := $(OBJ_DIR)/app_polling
|
||||
#------------------------targets------------------------
|
||||
$(OBJ_DIR):
|
||||
@-mkdir -p $(OBJ_DIR)
|
||||
|
|
|
@ -8,7 +8,7 @@
|
|||
#define TIMER_INTERVAL 1000000
|
||||
|
||||
// the maximum memory space that PKE is allowed to manage
|
||||
#define PKE_MAX_ALLOWABLE_RAM 128 * 1024 * 1024
|
||||
#define PKE_MAX_ALLOWABLE_RAM 1 * 1024 * 1024
|
||||
|
||||
// the ending physical address that PKE observes
|
||||
#define PHYS_TOP (DRAM_BASE + PKE_MAX_ALLOWABLE_RAM)
|
||||
|
|
|
@ -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 :
|
||||
{
|
||||
|
|
|
@ -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.
|
||||
#
|
||||
|
||||
.option norvc
|
||||
.section .text.init,"ax",@progbits
|
||||
.globl _mentry
|
||||
_mentry:
|
||||
# [mscratch] = 0; mscratch points the stack bottom of machine mode computer
|
||||
|
|
|
@ -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)
|
||||
|
@ -66,6 +66,25 @@ 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.
|
||||
//
|
||||
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
|
||||
//
|
||||
|
@ -83,11 +102,18 @@ void timerinit(uintptr_t hartid) {
|
|||
void m_start(uintptr_t hartid, uintptr_t dtb) {
|
||||
// init the spike file interface (stdin,stdout,stderr)
|
||||
spike_file_init();
|
||||
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(dtb);
|
||||
|
||||
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 frame for interrupt in M mode to csr "mscratch".
|
||||
write_csr(mscratch, &g_itrframe);
|
||||
|
||||
|
|
|
@ -0,0 +1,74 @@
|
|||
// See LICENSE for license details.
|
||||
|
||||
#include <string.h>
|
||||
#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);
|
||||
}
|
|
@ -0,0 +1,27 @@
|
|||
// See LICENSE for license details.
|
||||
|
||||
#ifndef _RISCV_UART_H
|
||||
#define _RISCV_UART_H
|
||||
|
||||
#include <stdint.h>
|
||||
//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
|
|
@ -81,6 +81,40 @@ ssize_t sys_user_yield() {
|
|||
return 0;
|
||||
}
|
||||
|
||||
//add uart putchar getchar syscall
|
||||
//
|
||||
// implement the SYS_user_uart_putchar syscall
|
||||
//
|
||||
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;
|
||||
}
|
||||
|
||||
ssize_t sys_user_uart_getchar() {
|
||||
// TODO (lab4_1 and lab4_2): implment the syscall of sys_user_uart_getchar and modify it in lab4_2.
|
||||
// hint (lab4_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 (lab4_2): the functionality of sys_user_uart_getchar is let process sleep and wait for value. therefore,
|
||||
// we should call do_sleep to let process 0 sleep.
|
||||
// then we should get uartvalue and return.
|
||||
panic( "You have to implement sys_user_uart_getchar to get data from UART using uartgetchar in lab4_1 and modify it in lab4_2.\n" );
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
//car control
|
||||
ssize_t sys_user_gpio_reg_write(uint8 val) {
|
||||
volatile uint32_t *control_reg = (void*)(uintptr_t)0x60001004;
|
||||
volatile uint32_t *data_reg = (void*)(uintptr_t)0x60001000;
|
||||
//*control_reg = 0;
|
||||
*data_reg = (uint32_t)val;
|
||||
return 1;
|
||||
}
|
||||
|
||||
//
|
||||
// [a0]: the syscall number; [a1] ... [a7]: arguments to the syscalls.
|
||||
// returns the code of success, (e.g., 0 means success, fail for otherwise)
|
||||
|
@ -99,6 +133,12 @@ long do_syscall(long a0, long a1, long a2, long a3, long a4, long a5, long a6, l
|
|||
return sys_user_fork();
|
||||
case SYS_user_yield:
|
||||
return sys_user_yield();
|
||||
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_gpio_reg_write:
|
||||
return sys_user_gpio_reg_write(a1);
|
||||
default:
|
||||
panic("Unknown syscall %ld \n", a0);
|
||||
}
|
||||
|
|
|
@ -12,7 +12,10 @@
|
|||
#define SYS_user_free_page (SYS_user_base + 3)
|
||||
#define SYS_user_fork (SYS_user_base + 4)
|
||||
#define SYS_user_yield (SYS_user_base + 5)
|
||||
|
||||
// add syscall uart putchar getchar
|
||||
#define SYS_user_uart_putchar (SYS_user_base + 6)
|
||||
#define SYS_user_uart_getchar (SYS_user_base + 7)
|
||||
#define SYS_user_gpio_reg_write (SYS_user_base + 8)
|
||||
long do_syscall(long a0, long a1, long a2, long a3, long a4, long a5, long a6, long a7);
|
||||
|
||||
#endif
|
||||
|
|
|
@ -133,6 +133,8 @@ void kern_vm_init(void) {
|
|||
// 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.
|
||||
kern_vm_map(t_page_dir, (uint64)0x60000000, (uint64)0x60000000, (uint64)0x60020000 - (uint64)0x60000000,
|
||||
prot_to_type(PROT_READ | PROT_WRITE, 0));
|
||||
kern_vm_map(t_page_dir, (uint64)_etext, (uint64)_etext, PHYS_TOP - (uint64)_etext,
|
||||
prot_to_type(PROT_READ | PROT_WRITE, 0));
|
||||
|
||||
|
|
|
@ -97,3 +97,21 @@ void fdt_scan(uint64 fdt, const struct fdt_cb *cb) {
|
|||
|
||||
fdt_scan_helper(lex, strings, 0, cb);
|
||||
}
|
||||
|
||||
//add
|
||||
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;
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -0,0 +1,27 @@
|
|||
/*
|
||||
* Below is the given application for lab4_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();
|
||||
uartputchar(temp);
|
||||
switch (temp)
|
||||
{
|
||||
case '1' : gpio_reg_write(0x2e); break; //前进
|
||||
case '2' : gpio_reg_write(0xd1); break; //后退
|
||||
case '3' : gpio_reg_write(0x63); break; //左转
|
||||
case '4' : gpio_reg_write(0x9c); break; //右转
|
||||
case 'q' : exit(0); break;
|
||||
default : gpio_reg_write(0x00); break; //停止
|
||||
}
|
||||
}
|
||||
exit(0);
|
||||
return 0;
|
||||
}
|
|
@ -1,28 +0,0 @@
|
|||
/*
|
||||
* The application of lab3_3.
|
||||
* parent and child processes never give up their processor during execution.
|
||||
*/
|
||||
|
||||
#include "user/user_lib.h"
|
||||
#include "util/types.h"
|
||||
|
||||
int main(void) {
|
||||
uint64 pid = fork();
|
||||
uint64 rounds = 100000000;
|
||||
uint64 interval = 10000000;
|
||||
uint64 a = 0;
|
||||
if (pid == 0) {
|
||||
printu("Child: Hello world! \n");
|
||||
for (uint64 i = 0; i < rounds; ++i) {
|
||||
if (i % interval == 0) printu("Child running %ld \n", i);
|
||||
}
|
||||
} else {
|
||||
printu("Parent: Hello world! \n");
|
||||
for (uint64 i = 0; i < rounds; ++i) {
|
||||
if (i % interval == 0) printu("Parent running %ld \n", i);
|
||||
}
|
||||
}
|
||||
|
||||
exit(0);
|
||||
return 0;
|
||||
}
|
|
@ -76,3 +76,25 @@ int fork() {
|
|||
void yield() {
|
||||
do_user_call(SYS_user_yield, 0, 0, 0, 0, 0, 0, 0);
|
||||
}
|
||||
// add
|
||||
// add syscall uart getchar putchar
|
||||
//
|
||||
// applications need to call uart_putchar to put a char by 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 by device
|
||||
//
|
||||
int uartgetchar() {
|
||||
return do_user_call(SYS_user_uart_getchar, 0, 0, 0, 0, 0, 0, 0);
|
||||
}
|
||||
|
||||
|
||||
|
||||
// car
|
||||
int gpio_reg_write(char val) {
|
||||
return do_user_call(SYS_user_gpio_reg_write, val, 0, 0, 0, 0, 0, 0);
|
||||
}
|
|
@ -8,3 +8,8 @@ void* naive_malloc();
|
|||
void naive_free(void* va);
|
||||
int fork();
|
||||
void yield();
|
||||
//add
|
||||
int uartputchar(char ch);
|
||||
int uartgetchar();
|
||||
|
||||
int gpio_reg_write(char val);
|
||||
|
|
Loading…
Reference in New Issue