init commit of lab5_1

lab5_1_poll
Zhiyuan Shao 1 year ago
parent 38183534a3
commit c4b07e8a00

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

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

@ -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 emulated by spike.
#
.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)
@ -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);

@ -0,0 +1,74 @@
// added @lab5_1.
#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 @@
// added @lab5_1.
#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

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

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

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

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

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

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

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

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

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

Loading…
Cancel
Save