Support for running with M-Mode

This commit is contained in:
bigmagic 2021-05-21 17:03:30 +08:00
parent 0dc972bee6
commit b7c7c7f4de
26 changed files with 1162 additions and 462 deletions

View File

@ -213,6 +213,7 @@ CONFIG_RT_LIBC_FIXED_TIMEZONE=8
# CONFIG_RT_USING_RYM is not set # CONFIG_RT_USING_RYM is not set
# CONFIG_RT_USING_ULOG is not set # CONFIG_RT_USING_ULOG is not set
# CONFIG_RT_USING_UTEST is not set # CONFIG_RT_USING_UTEST is not set
# CONFIG_RT_USING_RT_LINK is not set
# #
# RT-Thread Utestcases # RT-Thread Utestcases
@ -335,6 +336,7 @@ CONFIG_RT_LIBC_FIXED_TIMEZONE=8
# CONFIG_PKG_USING_HELIX is not set # CONFIG_PKG_USING_HELIX is not set
# CONFIG_PKG_USING_AZUREGUIX is not set # CONFIG_PKG_USING_AZUREGUIX is not set
# CONFIG_PKG_USING_TOUCHGFX2RTT is not set # CONFIG_PKG_USING_TOUCHGFX2RTT is not set
# CONFIG_PKG_USING_NUEMWIN is not set
# #
# tools packages # tools packages
@ -492,6 +494,7 @@ CONFIG_RT_LIBC_FIXED_TIMEZONE=8
# CONFIG_PKG_USING_LIBNFC is not set # CONFIG_PKG_USING_LIBNFC is not set
# CONFIG_PKG_USING_MFOC is not set # CONFIG_PKG_USING_MFOC is not set
# CONFIG_PKG_USING_TMC51XX is not set # CONFIG_PKG_USING_TMC51XX is not set
# CONFIG_PKG_USING_TCA9534 is not set
# #
# AI packages # AI packages
@ -519,6 +522,7 @@ CONFIG_RT_LIBC_FIXED_TIMEZONE=8
# CONFIG_PKG_USING_FLEXIBLE_BUTTON is not set # CONFIG_PKG_USING_FLEXIBLE_BUTTON is not set
# CONFIG_PKG_USING_CANFESTIVAL is not set # CONFIG_PKG_USING_CANFESTIVAL is not set
# CONFIG_PKG_USING_ZLIB is not set # CONFIG_PKG_USING_ZLIB is not set
# CONFIG_PKG_USING_MINIZIP is not set
# CONFIG_PKG_USING_DSTR is not set # CONFIG_PKG_USING_DSTR is not set
# CONFIG_PKG_USING_TINYFRAME is not set # CONFIG_PKG_USING_TINYFRAME is not set
# CONFIG_PKG_USING_KENDRYTE_DEMO is not set # CONFIG_PKG_USING_KENDRYTE_DEMO is not set
@ -558,7 +562,8 @@ CONFIG_BOARD_virt=y
CONFIG_RT_USING_USERSPACE=y CONFIG_RT_USING_USERSPACE=y
# #
# General Purpose UARTs # RISCV qemu virt64 configs
# #
# CONFIG_BSP_USING_UART1 is not set # CONFIG_BSP_USING_UART1 is not set
# CONFIG_RISCV_S_MODE is not set
CONFIG___STACKSIZE__=16384 CONFIG___STACKSIZE__=16384

View File

@ -31,7 +31,11 @@ stack_size = 4096
stack_lds = open('link_stacksize.lds', 'w') stack_lds = open('link_stacksize.lds', 'w')
if GetDepend('__STACKSIZE__'): stack_size = GetDepend('__STACKSIZE__') if GetDepend('__STACKSIZE__'): stack_size = GetDepend('__STACKSIZE__')
stack_lds.write('__STACKSIZE__ = %d;' % stack_size) stack_lds.write('__STACKSIZE__ = %d;\r\n' % stack_size)
if GetDepend('RISCV_S_MODE'): start_addr = int(0x80200000)
else: start_addr = int(0x80000000)
stack_lds.write('__START_ADDR__ = 0x%x;' % start_addr)
stack_lds.close() stack_lds.close()
# make a building # make a building

View File

@ -1,10 +1,11 @@
/* /*
* Copyright (c) 2006-2018, RT-Thread Development Team * Copyright (c) 2006-2021, RT-Thread Development Team
* *
* SPDX-License-Identifier: Apache-2.0 * SPDX-License-Identifier: Apache-2.0
* *
* Change Logs: * Change Logs:
* Date Author Notes * Date Author Notes
* 2021-05-20 bigmagic first version
*/ */
#include <rtthread.h> #include <rtthread.h>
@ -14,9 +15,7 @@
int main(void) int main(void)
{ {
void rt_hw_uart_start_rx_thread(); printf("Hello RISC-V!\n");
rt_hw_uart_start_rx_thread();
printf("Hello RISC-V\n");
return 0; return 0;
} }

View File

@ -1,6 +1,6 @@
menu "General Purpose UARTs" menu "RISCV qemu virt64 configs"
menuconfig BSP_USING_UART1 menuconfig BSP_USING_UART1
bool "Enable UART1" bool "Enable UART1"
@ -14,5 +14,8 @@ menuconfig BSP_USING_UART1
default 21 default 21
endif endif
endmenu config RISCV_S_MODE
bool "RT-Thread run in riscv smode"
default y
endmenu

View File

@ -21,6 +21,9 @@
#include "sbi.h" #include "sbi.h"
#include "riscv.h" #include "riscv.h"
#include "stack.h" #include "stack.h"
#include "riscv_io.h"
#include "plic.h"
#include "interrupt.h"
void primary_cpu_entry(void) void primary_cpu_entry(void)
{ {
@ -33,11 +36,6 @@ void primary_cpu_entry(void)
entry(); entry();
} }
void rt_hw_interrupt_init()
{
/* Enable machine external interrupts. */
set_csr(sie, SIP_SEIP);
}
void rt_hw_board_init(void) void rt_hw_board_init(void)
{ {
@ -46,10 +44,7 @@ void rt_hw_board_init(void)
/* initialize hardware interrupt */ /* initialize hardware interrupt */
rt_hw_uart_init(); rt_hw_uart_init();
rt_hw_tick_init();
#ifdef RT_USING_HEAP #ifdef RT_USING_HEAP
rt_kprintf("heap: [0x%08x - 0x%08x]\n", (rt_ubase_t) RT_HW_HEAP_BEGIN, (rt_ubase_t) RT_HW_HEAP_END);
/* initialize memory system */ /* initialize memory system */
rt_system_heap_init(RT_HW_HEAP_BEGIN, RT_HW_HEAP_END); rt_system_heap_init(RT_HW_HEAP_BEGIN, RT_HW_HEAP_END);
#endif #endif
@ -58,6 +53,8 @@ void rt_hw_board_init(void)
/* set console device */ /* set console device */
rt_console_set_device("uart"); rt_console_set_device("uart");
#endif /* RT_USING_CONSOLE */ #endif /* RT_USING_CONSOLE */
rt_hw_tick_init();
rt_kprintf("heap: [0x%08x - 0x%08x]\n", (rt_ubase_t) RT_HW_HEAP_BEGIN, (rt_ubase_t) RT_HW_HEAP_END);
#ifdef RT_USING_COMPONENTS_INIT #ifdef RT_USING_COMPONENTS_INIT
rt_components_board_init(); rt_components_board_init();
@ -71,137 +68,3 @@ void rt_hw_cpu_reset(void)
} }
MSH_CMD_EXPORT_ALIAS(rt_hw_cpu_reset, reboot, reset machine); MSH_CMD_EXPORT_ALIAS(rt_hw_cpu_reset, reboot, reset machine);
void dump_regs(struct rt_hw_stack_frame *regs)
{
rt_kprintf("--------------Dump Registers-----------------\n");
rt_kprintf("Function Registers:\n");
rt_kprintf("\tra(x1) = 0x%p\tuser_sp = 0x%p\n",regs -> ra,regs -> user_sp_exc_stack);
rt_kprintf("\tgp(x3) = 0x%p\ttp(x4) = 0x%p\n",regs -> gp,regs -> tp);
rt_kprintf("Temporary Registers:\n");
rt_kprintf("\tt0(x5) = 0x%p\tt1(x6) = 0x%p\n",regs -> t0,regs -> t1);
rt_kprintf("\tt2(x7) = 0x%p\n",regs -> t2);
rt_kprintf("\tt3(x28) = 0x%p\tt4(x29) = 0x%p\n",regs -> t3,regs -> t4);
rt_kprintf("\tt5(x30) = 0x%p\tt6(x31) = 0x%p\n",regs -> t5,regs -> t6);
rt_kprintf("Saved Registers:\n");
rt_kprintf("\ts0/fp(x8) = 0x%p\ts1(x9) = 0x%p\n",regs -> s0_fp,regs -> s1);
rt_kprintf("\ts2(x18) = 0x%p\ts3(x19) = 0x%p\n",regs -> s2,regs -> s3);
rt_kprintf("\ts4(x20) = 0x%p\ts5(x21) = 0x%p\n",regs -> s4,regs -> s5);
rt_kprintf("\ts6(x22) = 0x%p\ts7(x23) = 0x%p\n",regs -> s6,regs -> s7);
rt_kprintf("\ts8(x24) = 0x%p\ts9(x25) = 0x%p\n",regs -> s8,regs -> s9);
rt_kprintf("\ts10(x26) = 0x%p\ts11(x27) = 0x%p\n",regs -> s10,regs -> s11);
rt_kprintf("Function Arguments Registers:\n");
rt_kprintf("\ta0(x10) = 0x%p\ta1(x11) = 0x%p\n",regs -> a0,regs -> a1);
rt_kprintf("\ta2(x12) = 0x%p\ta3(x13) = 0x%p\n",regs -> a2,regs -> a3);
rt_kprintf("\ta4(x14) = 0x%p\ta5(x15) = 0x%p\n",regs -> a4,regs -> a5);
rt_kprintf("\ta6(x16) = 0x%p\ta7(x17) = 0x%p\n",regs -> a6,regs -> a7);
rt_kprintf("sstatus = 0x%p\n",regs -> sstatus);
rt_kprintf("\t%s\n",(regs -> sstatus & SSTATUS_SIE) ? "Supervisor Interrupt Enabled" : "Supervisor Interrupt Disabled");
rt_kprintf("\t%s\n",(regs -> sstatus & SSTATUS_SPIE) ? "Last Time Supervisor Interrupt Enabled" : "Last Time Supervisor Interrupt Disabled");
rt_kprintf("\t%s\n",(regs -> sstatus & SSTATUS_SPP) ? "Last Privilege is Supervisor Mode" : "Last Privilege is User Mode");
rt_kprintf("\t%s\n",(regs -> sstatus & SSTATUS_PUM) ? "Permit to Access User Page" : "Not Permit to Access User Page");
rt_kprintf("\t%s\n",(regs -> sstatus & (1 << 19)) ? "Permit to Read Executable-only Page" : "Not Permit to Read Executable-only Page");
rt_size_t satp_v = read_csr(satp);
rt_kprintf("satp = 0x%p\n",satp_v);
const char *mode_str = "Unknown Address Translation/Protection Mode";
switch(__MASKVALUE(satp_v >> 60,__MASK(4)))
{
case 0:
mode_str = "No Address Translation/Protection Mode";
break;
case 8:
mode_str = "Page-based 39-bit Virtual Addressing Mode";
break;
case 9:
mode_str = "Page-based 48-bit Virtual Addressing Mode";
break;
}
rt_kprintf("\tMode = %s\n",mode_str);
rt_kprintf("-----------------Dump OK---------------------\n");
}
static const char *Exception_Name[] =
{
"Instruction Address Misaligned",
"Instruction Access Fault",
"Illegal Instruction",
"Breakpoint",
"Load Address Misaligned",
"Load Access Fault",
"Store/AMO Address Misaligned",
"Store/AMO Access Fault",
"Environment call from U-mode",
"Environment call from S-mode",
"Reserved-10",
"Reserved-11",
"Instruction Page Fault",
"Load Page Fault",
"Reserved-14",
"Store/AMO Page Fault"
};
static const char *Interrupt_Name[] =
{
"User Software Interrupt",
"Supervisor Software Interrupt",
"Reversed-2",
"Reversed-3",
"User Timer Interrupt",
"Supervisor Timer Interrupt",
"Reversed-6",
"Reversed-7",
"User External Interrupt",
"Supervisor External Interrupt",
"Reserved-10",
"Reserved-11",
};
void handle_trap(rt_size_t scause,rt_size_t stval,rt_size_t sepc,struct rt_hw_stack_frame *sp)
{
if(scause == (uint64_t)(0x8000000000000005))
{
rt_interrupt_enter();
tick_isr();
rt_interrupt_leave();
}
else
{
rt_size_t id = __MASKVALUE(scause,__MASK(63UL));
const char *msg;
if(scause >> 63)
{
if(id < sizeof(Interrupt_Name) / sizeof(const char *))
{
msg = Interrupt_Name[id];
}
else
{
msg = "Unknown Interrupt";
}
rt_kprintf("Unhandled Interrupt %ld:%s\n",id,msg);
}
else
{
if(id < sizeof(Exception_Name) / sizeof(const char *))
{
msg = Exception_Name[id];
}
else
{
msg = "Unknown Exception";
}
rt_kprintf("Unhandled Exception %ld:%s\n",id,msg);
}
rt_kprintf("scause:0x%p,stval:0x%p,sepc:0x%p\n",scause,stval,sepc);
dump_regs(sp);
while(1);
}
}

View File

@ -1,10 +1,12 @@
/* /*
* Copyright (c) 2019-2020, Xim * Copyright (c) 2006-2021, RT-Thread Development Team
* *
* SPDX-License-Identifier: Apache-2.0 * SPDX-License-Identifier: Apache-2.0
* *
* Change Logs:
* Date Author Notes
* 2021-05-20 bigmagic first version
*/ */
#include <rthw.h> #include <rthw.h>
#include <rtdevice.h> #include <rtdevice.h>
@ -13,8 +15,7 @@
#include <stdio.h> #include <stdio.h>
#include "sbi.h" #include "sbi.h"
#include "interrupt.h"
#define UART_DEFAULT_BAUDRATE 115200
struct device_uart struct device_uart
{ {
@ -27,24 +28,26 @@ static rt_err_t uart_control(struct rt_serial_device *serial, int cmd, void *arg
static int drv_uart_putc(struct rt_serial_device *serial, char c); static int drv_uart_putc(struct rt_serial_device *serial, char c);
static int drv_uart_getc(struct rt_serial_device *serial); static int drv_uart_getc(struct rt_serial_device *serial);
const struct rt_uart_ops _uart_ops = void virt_uart_init(void)
{ {
rt_uart_configure, //http://byterunner.com/16550.html
uart_control, uart_write_reg(IER, 0x00);
drv_uart_putc,
drv_uart_getc,
//TODO: add DMA support
RT_NULL
};
void uart_init(void) uint8_t lcr = uart_read_reg(LCR);
{ uart_write_reg(LCR, lcr | (1 << 7));
return ; uart_write_reg(DLL, 0x03);
uart_write_reg(DLM, 0x00);
lcr = 0;
uart_write_reg(LCR, lcr | (3 << 0));
/*
* enable receive interrupts.
*/
uint8_t ier = uart_read_reg(IER);
uart_write_reg(IER, ier | (1 << 0));
} }
struct rt_serial_device serial1;
struct device_uart uart1;
/* /*
* UART interface * UART interface
*/ */
@ -58,22 +61,6 @@ static rt_err_t rt_uart_configure(struct rt_serial_device *serial, struct serial
return (RT_EOK); return (RT_EOK);
} }
#define UART_LSR_DR 0x01 /* Data ready */
#define UART_LSR_THRE 0x20 /* Xmit holding register empty */
#define UART_RBR(hw) HWREG32(hw + 0x00)
#define UART_IER(hw) HWREG32(hw + 0x04)
#define UART_LSR(hw) HWREG32(hw + 0x14)
static volatile uint64_t uart_hwbase = 0x10000000;
void uart_putc(char c)
{
while ((UART_LSR(uart_hwbase) & UART_LSR_THRE) == 0);
UART_RBR(uart_hwbase) = c;
}
static rt_err_t uart_control(struct rt_serial_device *serial, int cmd, void *arg) static rt_err_t uart_control(struct rt_serial_device *serial, int cmd, void *arg)
{ {
struct device_uart *uart; struct device_uart *uart;
@ -98,37 +85,37 @@ static rt_err_t uart_control(struct rt_serial_device *serial, int cmd, void *arg
static int drv_uart_putc(struct rt_serial_device *serial, char c) static int drv_uart_putc(struct rt_serial_device *serial, char c)
{ {
sbi_console_putchar(c); while ((uart_read_reg(LSR) & LSR_TX_IDLE) == 0);
return (1); return uart_write_reg(THR, c);
} }
static int drv_uart_getc(struct rt_serial_device *serial) static int drv_uart_getc(struct rt_serial_device *serial)
{ {
return sbi_console_getchar(); if (uart_read_reg(LSR) & LSR_RX_READY){
return uart_read_reg(RHR);
} else {
return -1;
}
//return sbi_console_getchar();
} }
char rt_hw_console_getchar(void) static void rt_hw_uart_isr(int irqno, void *param)
{
return sbi_console_getchar();
}
static void uart_rx(void *param)
{ {
struct rt_serial_device *serial = (struct rt_serial_device*)param; struct rt_serial_device *serial = (struct rt_serial_device*)param;
rt_hw_serial_isr(serial, RT_SERIAL_EVENT_RX_IND);
while(1)
{
rt_hw_serial_isr((struct rt_serial_device *)serial,RT_SERIAL_EVENT_RX_IND);
rt_thread_mdelay(10);
}
} }
void rt_hw_uart_start_rx_thread() struct rt_serial_device serial1;
struct device_uart uart1;
const struct rt_uart_ops _uart_ops =
{ {
rt_thread_t th; rt_uart_configure,
RT_ASSERT((th = rt_thread_create("uartrx",uart_rx,(void *)&serial1,8192,8,20)) != RT_NULL); uart_control,
RT_ASSERT(rt_thread_startup(th) == RT_EOK); drv_uart_putc,
} drv_uart_getc,
RT_NULL
};
/* /*
* UART Initiation * UART Initiation
@ -138,7 +125,6 @@ int rt_hw_uart_init(void)
struct rt_serial_device *serial; struct rt_serial_device *serial;
struct device_uart *uart; struct device_uart *uart;
struct serial_configure config = RT_SERIAL_CONFIG_DEFAULT; struct serial_configure config = RT_SERIAL_CONFIG_DEFAULT;
{ {
serial = &serial1; serial = &serial1;
uart = &uart1; uart = &uart1;
@ -147,19 +133,19 @@ int rt_hw_uart_init(void)
serial->config = config; serial->config = config;
serial->config.baud_rate = UART_DEFAULT_BAUDRATE; serial->config.baud_rate = UART_DEFAULT_BAUDRATE;
uart->hw_base = 0x10000000; uart->hw_base = UART_BASE;
uart->irqno = 0xa; uart->irqno = UART0_IRQ;
virt_uart_init();
rt_hw_serial_register(serial, rt_hw_serial_register(serial,
"uart", "uart",
RT_DEVICE_FLAG_STREAM | RT_DEVICE_FLAG_RDWR | RT_DEVICE_FLAG_INT_RX, RT_DEVICE_FLAG_STREAM | RT_DEVICE_FLAG_RDWR | RT_DEVICE_FLAG_INT_RX,
uart); uart);
rt_hw_interrupt_install(uart->irqno, rt_hw_uart_isr, serial, "uart");
rt_hw_interrupt_umask(uart->irqno);
} }
return 0; return 0;
} }
/* WEAK for SDK 0.5.6 */
RT_WEAK void uart_debug_init(int uart_channel)
{
}

View File

@ -1,15 +1,43 @@
/* /*
* Copyright (c) 2019-2020, Xim * Copyright (c) 2006-2021, RT-Thread Development Team
* *
* SPDX-License-Identifier: Apache-2.0 * SPDX-License-Identifier: Apache-2.0
* *
* Change Logs:
* Date Author Notes
* 2021-05-20 bigmagic first version
*/ */
#ifndef __DRV_UART_H__ #ifndef __DRV_UART_H__
#define __DRV_UART_H__ #define __DRV_UART_H__
void rt_hw_uart_start_rx_thread(); #define UART0_IRQ (10)
#define UART_DEFAULT_BAUDRATE 115200
#define UART_BASE (0x10000000L)
#define RHR 0 // Receive Holding Register (read mode)
#define THR 0 // Transmit Holding Register (write mode)
#define DLL 0 // LSB of Divisor Latch (write mode)
#define IER 1 // Interrupt Enable Register (write mode)
#define DLM 1 // MSB of Divisor Latch (write mode)
#define FCR 2 // FIFO Control Register (write mode)
#define ISR 2 // Interrupt Status Register (read mode)
#define LCR 3 // Line Control Register
#define MCR 4 // Modem Control Register
#define LSR 5 // Line Status Register
#define MSR 6 // Modem Status Register
#define SPR 7 // ScratchPad Register
#define UART_REG(reg) ((volatile uint8_t *)(UART_BASE + reg))
#define LSR_RX_READY (1 << 0)
#define LSR_TX_IDLE (1 << 5)
#define uart_read_reg(reg) (*(UART_REG(reg)))
#define uart_write_reg(reg, v) (*(UART_REG(reg)) = (v))
int rt_hw_uart_init(void); int rt_hw_uart_init(void);
void drv_uart_puts(char *str); // for syscall
#endif /* __DRV_UART_H__ */ #endif /* __DRV_UART_H__ */

View File

@ -0,0 +1,98 @@
/*
* Copyright (c) 2006-2021, RT-Thread Development Team
*
* SPDX-License-Identifier: Apache-2.0
*
* Change Logs:
* Date Author Notes
* 2021-05-20 bigmagic first version
*/
#include "rtthread.h"
#include "plic.h"
#include <riscv_io.h>
#include "encoding.h"
/*
* Each PLIC interrupt source can be assigned a priority by writing
* to its 32-bit memory-mapped priority register.
* The QEMU-virt (the same as FU540-C000) supports 7 levels of priority.
* A priority value of 0 is reserved to mean "never interrupt" and
* effectively disables the interrupt.
* Priority 1 is the lowest active priority, and priority 7 is the highest.
* Ties between global interrupts of the same priority are broken by
* the Interrupt ID; interrupts with the lowest ID have the highest
* effective priority.
*/
void plic_set_priority(int irq, int priority)
{
*(uint32_t*)PLIC_PRIORITY(irq) = priority;
}
/*
* Each global interrupt can be enabled by setting the corresponding
* bit in the enables registers.
*/
void plic_irq_enable(int irq)
{
int hart = r_mhartid();
*(uint32_t*)PLIC_ENABLE(hart) = ((*(uint32_t*)PLIC_ENABLE(hart)) | (1 << irq));
#ifdef RISCV_S_MODE
set_csr(sie, read_csr(sie) | MIP_SEIP);
#else
set_csr(mie, read_csr(mie) | MIP_MEIP);
#endif
}
void plic_irq_disable(int irq)
{
int hart = r_mhartid();
*(uint32_t*)PLIC_ENABLE(hart) = (((*(uint32_t*)PLIC_ENABLE(hart)) & (~(1 << irq))));
}
/*
* PLIC will mask all interrupts of a priority less than or equal to threshold.
* Maximum threshold is 7.
* For example, a threshold value of zero permits all interrupts with
* non-zero priority, whereas a value of 7 masks all interrupts.
* Notice, the threshold is global for PLIC, not for each interrupt source.
*/
void plic_set_threshold(int threshold)
{
int hart = r_mhartid();
*(uint32_t*)PLIC_THRESHOLD(hart) = threshold;
}
/*
* DESCRIPTION:
* Query the PLIC what interrupt we should serve.
* Perform an interrupt claim by reading the claim register, which
* returns the ID of the highest-priority pending interrupt or zero if there
* is no pending interrupt.
* A successful claim also atomically clears the corresponding pending bit
* on the interrupt source.
* RETURN VALUE:
* the ID of the highest-priority pending interrupt or zero if there
* is no pending interrupt.
*/
int plic_claim(void)
{
int hart = r_mhartid();
int irq = *(uint32_t*)PLIC_CLAIM(hart);
return irq;
}
/*
* DESCRIPTION:
* Writing the interrupt ID it received from the claim (irq) to the
* complete register would signal the PLIC we've served this IRQ.
* The PLIC does not check whether the completion ID is the same as the
* last claim ID for that target. If the completion ID does not match an
* interrupt source that is currently enabled for the target, the completion
* is silently ignored.
* RETURN VALUE: none
*/
void plic_complete(int irq)
{
int hart = r_mhartid();
*(uint32_t*)PLIC_COMPLETE(hart) = irq;
}

View File

@ -0,0 +1,61 @@
/*
* Copyright (c) 2006-2021, RT-Thread Development Team
*
* SPDX-License-Identifier: Apache-2.0
*
* Change Logs:
* Date Author Notes
* 2021-05-20 bigmagic first version
*/
#ifndef PLIC_H
#define PLIC_H
#include <rtconfig.h>
/*
* This machine puts platform-level interrupt controller (PLIC) here.
* Here only list PLIC registers in Machine mode.
*
*/
#define VIRT_PLIC_BASE 0x0c000000L
#define PLIC_PRIORITY_OFFSET (0x0)
#define PLIC_PENDING_OFFSET (0x1000)
#ifndef RISCV_S_MODE
#define PLIC_MENABLE_OFFSET (0x2000)
#define PLIC_MTHRESHOLD_OFFSET (0x200000)
#define PLIC_MCLAIM_OFFSET (0x200004)
#define PLIC_MCOMPLETE_OFFSET (0x200004)
#define PLIC_ENABLE(hart) (VIRT_PLIC_BASE + PLIC_MENABLE_OFFSET + (hart) * 0x80)
#define PLIC_THRESHOLD(hart) (VIRT_PLIC_BASE + PLIC_MTHRESHOLD_OFFSET + (hart) * 0x1000)
#define PLIC_CLAIM(hart) (VIRT_PLIC_BASE + PLIC_MCLAIM_OFFSET + (hart) * 0x1000)
#define PLIC_COMPLETE(hart) (VIRT_PLIC_BASE + PLIC_MCOMPLETE_OFFSET + (hart) * 0x1000)
#else
#define PLIC_SENABLE_OFFSET (0x2080)
#define PLIC_STHRESHOLD_OFFSET (0x201000)
#define PLIC_SCLAIM_OFFSET (0x201004)
#define PLIC_SCOMPLETE_OFFSET (0x201004)
#define PLIC_ENABLE(hart) (VIRT_PLIC_BASE + PLIC_SENABLE_OFFSET + (hart) * 0x80)
#define PLIC_THRESHOLD(hart) (VIRT_PLIC_BASE + PLIC_STHRESHOLD_OFFSET + (hart) * 0x1000)
#define PLIC_CLAIM(hart) (VIRT_PLIC_BASE + PLIC_SCLAIM_OFFSET + (hart) * 0x1000)
#define PLIC_COMPLETE(hart) (VIRT_PLIC_BASE + PLIC_SCOMPLETE_OFFSET + (hart) * 0x1000)
#endif
#define PLIC_PRIORITY(id) (VIRT_PLIC_BASE + PLIC_PRIORITY_OFFSET + (id) * 4)
#define PLIC_PENDING(id) (VIRT_PLIC_BASE + PLIC_PENDING_OFFSET + ((id) / 32))
void plic_set_priority(int irq, int priority);
void plic_irq_enable(int irq);
void plic_irq_disable(int irq);
void plic_set_threshold(int mthreshold);
int plic_claim(void);
void plic_complete(int irq);
#endif

View File

@ -21,13 +21,13 @@ OUTPUT_ARCH( "riscv" )
MEMORY MEMORY
{ {
SRAM : ORIGIN = 0x80200000, LENGTH = 0x7FF000 SRAM : ORIGIN = __START_ADDR__, LENGTH = 0x7FF000
} }
ENTRY(_start) ENTRY(_start)
SECTIONS SECTIONS
{ {
. = 0x80200000 ; . = __START_ADDR__ ;
/* __STACKSIZE__ = 4096; */ /* __STACKSIZE__ = 4096; */

View File

@ -1 +1,2 @@
__STACKSIZE__ = 16384; __STACKSIZE__ = 16384;
__START_ADDR__ = 0x80000000;

View File

@ -0,0 +1 @@
qemu-system-riscv64 -nographic -machine virt -m 256M -kernel rtthread.bin

2
bsp/qemu-riscv-virt64/qemu-nographic.sh Normal file → Executable file
View File

@ -1 +1 @@
qemu-system-riscv64 -nographic -machine virt -m 256M -kernel rtthread.bin qemu-system-riscv64 -nographic -machine virt -m 256M -bios rtthread.bin

View File

@ -177,7 +177,7 @@
#define BOARD_virt #define BOARD_virt
#define RT_USING_USERSPACE #define RT_USING_USERSPACE
/* General Purpose UARTs */ /* RISCV qemu virt64 configs */
#define __STACKSIZE__ 16384 #define __STACKSIZE__ 16384

View File

@ -9,44 +9,300 @@
* 2018/12/27 Jesven Add SMP support * 2018/12/27 Jesven Add SMP support
* 2021/02/02 lizhirui Add userspace support * 2021/02/02 lizhirui Add userspace support
*/ */
#include "cpuport.h" #include "cpuport.h"
#include "stackframe.h"
#ifdef RT_USING_SMP
#define rt_hw_interrupt_disable rt_hw_local_irq_disable
#define rt_hw_interrupt_enable rt_hw_local_irq_enable
#endif
/*
* rt_base_t rt_hw_interrupt_disable(void);
*/
.globl rt_hw_interrupt_disable
rt_hw_interrupt_disable:
#ifdef RISCV_S_MODE
csrrci a0, sstatus, 2
#else
csrrci a0, mstatus, 8
#endif
ret
/*
* void rt_hw_interrupt_enable(rt_base_t level);
*/
.globl rt_hw_interrupt_enable
rt_hw_interrupt_enable:
csrw SRC_XSTATUS, a0
ret
/*
* #ifdef RT_USING_SMP
* void rt_hw_context_switch_to(rt_ubase_t to, stuct rt_thread *to_thread);
* #else
* void rt_hw_context_switch_to(rt_ubase_t to);
* #endif
* a0 --> to
* a1 --> to_thread
*/
.globl rt_hw_context_switch_to .globl rt_hw_context_switch_to
rt_hw_context_switch_to: rt_hw_context_switch_to:
LOAD sp, (a0) LOAD sp, (a0)
la s0, rt_current_thread #ifdef RT_USING_SMP
LOAD s1, (s0) mv a0, a1
call rt_cpus_lock_status_restore
RESTORE_ALL #endif
sret LOAD a0, 2 * REGBYTES(sp)
csrw SRC_XSTATUS, a0
j rt_hw_context_switch_exit
/* /*
* #ifdef RT_USING_SMP
* void rt_hw_context_switch(rt_ubase_t from, rt_ubase_t to, struct rt_thread *to_thread);
* #else
* void rt_hw_context_switch(rt_ubase_t from, rt_ubase_t to); * void rt_hw_context_switch(rt_ubase_t from, rt_ubase_t to);
* #endif
* *
* a0 --> from * a0 --> from
* a1 --> to * a1 --> to
* a2 --> to_thread
*/ */
.globl rt_hw_context_switch .globl rt_hw_context_switch
rt_hw_context_switch: rt_hw_context_switch:
mv t2, sp /* saved from thread context
li t0, 0x120//set SPIE and SPP = 1 * x1/ra -> sp(0)
csrs sstatus, t0//if enter here,caller must be in system thread * x1/ra -> sp(1)
csrw sepc, ra//return address * mstatus.mie -> sp(2)
//saved from thread context * x(i) -> sp(i-4)
SAVE_ALL */
#ifdef ARCH_RISCV_FPU
addi sp, sp, -32 * FREGBYTES
STORE t2, 32 * REGBYTES(sp)//save user_sp FSTORE f0, 0 * FREGBYTES(sp)
FSTORE f1, 1 * FREGBYTES(sp)
FSTORE f2, 2 * FREGBYTES(sp)
FSTORE f3, 3 * FREGBYTES(sp)
FSTORE f4, 4 * FREGBYTES(sp)
FSTORE f5, 5 * FREGBYTES(sp)
FSTORE f6, 6 * FREGBYTES(sp)
FSTORE f7, 7 * FREGBYTES(sp)
FSTORE f8, 8 * FREGBYTES(sp)
FSTORE f9, 9 * FREGBYTES(sp)
FSTORE f10, 10 * FREGBYTES(sp)
FSTORE f11, 11 * FREGBYTES(sp)
FSTORE f12, 12 * FREGBYTES(sp)
FSTORE f13, 13 * FREGBYTES(sp)
FSTORE f14, 14 * FREGBYTES(sp)
FSTORE f15, 15 * FREGBYTES(sp)
FSTORE f16, 16 * FREGBYTES(sp)
FSTORE f17, 17 * FREGBYTES(sp)
FSTORE f18, 18 * FREGBYTES(sp)
FSTORE f19, 19 * FREGBYTES(sp)
FSTORE f20, 20 * FREGBYTES(sp)
FSTORE f21, 21 * FREGBYTES(sp)
FSTORE f22, 22 * FREGBYTES(sp)
FSTORE f23, 23 * FREGBYTES(sp)
FSTORE f24, 24 * FREGBYTES(sp)
FSTORE f25, 25 * FREGBYTES(sp)
FSTORE f26, 26 * FREGBYTES(sp)
FSTORE f27, 27 * FREGBYTES(sp)
FSTORE f28, 28 * FREGBYTES(sp)
FSTORE f29, 29 * FREGBYTES(sp)
FSTORE f30, 30 * FREGBYTES(sp)
FSTORE f31, 31 * FREGBYTES(sp)
#endif
addi sp, sp, -32 * REGBYTES
STORE sp, (a0) STORE sp, (a0)
//restore to thread context STORE x1, 0 * REGBYTES(sp)
STORE x1, 1 * REGBYTES(sp)
csrr a0, SRC_XSTATUS
#ifdef RISCV_S_MODE
andi a0, a0, 2
beqz a0, save_spie
li a0, 0x20
save_spie:
STORE a0, 2 * REGBYTES(sp)
#else
andi a0, a0, 8
beqz a0, save_mpie
li a0, 0x80
save_mpie:
STORE a0, 2 * REGBYTES(sp)
#endif
STORE x4, 4 * REGBYTES(sp)
STORE x5, 5 * REGBYTES(sp)
STORE x6, 6 * REGBYTES(sp)
STORE x7, 7 * REGBYTES(sp)
STORE x8, 8 * REGBYTES(sp)
STORE x9, 9 * REGBYTES(sp)
STORE x10, 10 * REGBYTES(sp)
STORE x11, 11 * REGBYTES(sp)
STORE x12, 12 * REGBYTES(sp)
STORE x13, 13 * REGBYTES(sp)
STORE x14, 14 * REGBYTES(sp)
STORE x15, 15 * REGBYTES(sp)
STORE x16, 16 * REGBYTES(sp)
STORE x17, 17 * REGBYTES(sp)
STORE x18, 18 * REGBYTES(sp)
STORE x19, 19 * REGBYTES(sp)
STORE x20, 20 * REGBYTES(sp)
STORE x21, 21 * REGBYTES(sp)
STORE x22, 22 * REGBYTES(sp)
STORE x23, 23 * REGBYTES(sp)
STORE x24, 24 * REGBYTES(sp)
STORE x25, 25 * REGBYTES(sp)
STORE x26, 26 * REGBYTES(sp)
STORE x27, 27 * REGBYTES(sp)
STORE x28, 28 * REGBYTES(sp)
STORE x29, 29 * REGBYTES(sp)
STORE x30, 30 * REGBYTES(sp)
STORE x31, 31 * REGBYTES(sp)
/* restore to thread context
* sp(0) -> epc;
* sp(1) -> ra;
* sp(i) -> x(i+2)
*/
LOAD sp, (a1) LOAD sp, (a1)
la s0, rt_current_thread #ifdef RT_USING_SMP
LOAD s1, (s0) mv a0, a2
call rt_cpus_lock_status_restore
#endif /*RT_USING_SMP*/
RESTORE_ALL j rt_hw_context_switch_exit
sret
#ifdef RT_USING_SMP
/*
* void rt_hw_context_switch_interrupt(void *context, rt_ubase_t from, rt_ubase_t to, struct rt_thread *to_thread);
*
* a0 --> context
* a1 --> from
* a2 --> to
* a3 --> to_thread
*/
.globl rt_hw_context_switch_interrupt
rt_hw_context_switch_interrupt:
STORE a0, 0(a1)
LOAD sp, 0(a2)
move a0, a3
call rt_cpus_lock_status_restore
j rt_hw_context_switch_exit
#endif
.global rt_hw_context_switch_exit
rt_hw_context_switch_exit:
#ifdef RT_USING_SMP
#ifdef RT_USING_SIGNALS
mv a0, sp
csrr t0, mhartid
/* switch interrupt stack of current cpu */
la sp, __stack_start__
addi t1, t0, 1
li t2, __STACKSIZE__
mul t1, t1, t2
add sp, sp, t1 /* sp = (cpuid + 1) * __STACKSIZE__ + __stack_start__ */
call rt_signal_check
mv sp, a0
#endif
#endif
/* resw ra to mepc */
LOAD a0, 0 * REGBYTES(sp)
csrw SRC_XEPC, a0
LOAD x1, 1 * REGBYTES(sp)
#ifdef RISCV_S_MODE
li t0, 0x00000120
csrw sstatus, t0
LOAD a0, 2 * REGBYTES(sp)
csrs sstatus, a0
#else
li t0, 0x00007800
csrw mstatus, t0
LOAD a0, 2 * REGBYTES(sp)
csrs mstatus, a0
#endif
LOAD x4, 4 * REGBYTES(sp)
LOAD x5, 5 * REGBYTES(sp)
LOAD x6, 6 * REGBYTES(sp)
LOAD x7, 7 * REGBYTES(sp)
LOAD x8, 8 * REGBYTES(sp)
LOAD x9, 9 * REGBYTES(sp)
LOAD x10, 10 * REGBYTES(sp)
LOAD x11, 11 * REGBYTES(sp)
LOAD x12, 12 * REGBYTES(sp)
LOAD x13, 13 * REGBYTES(sp)
LOAD x14, 14 * REGBYTES(sp)
LOAD x15, 15 * REGBYTES(sp)
LOAD x16, 16 * REGBYTES(sp)
LOAD x17, 17 * REGBYTES(sp)
LOAD x18, 18 * REGBYTES(sp)
LOAD x19, 19 * REGBYTES(sp)
LOAD x20, 20 * REGBYTES(sp)
LOAD x21, 21 * REGBYTES(sp)
LOAD x22, 22 * REGBYTES(sp)
LOAD x23, 23 * REGBYTES(sp)
LOAD x24, 24 * REGBYTES(sp)
LOAD x25, 25 * REGBYTES(sp)
LOAD x26, 26 * REGBYTES(sp)
LOAD x27, 27 * REGBYTES(sp)
LOAD x28, 28 * REGBYTES(sp)
LOAD x29, 29 * REGBYTES(sp)
LOAD x30, 30 * REGBYTES(sp)
LOAD x31, 31 * REGBYTES(sp)
addi sp, sp, 32 * REGBYTES
#ifdef ARCH_RISCV_FPU
FLOAD f0, 0 * FREGBYTES(sp)
FLOAD f1, 1 * FREGBYTES(sp)
FLOAD f2, 2 * FREGBYTES(sp)
FLOAD f3, 3 * FREGBYTES(sp)
FLOAD f4, 4 * FREGBYTES(sp)
FLOAD f5, 5 * FREGBYTES(sp)
FLOAD f6, 6 * FREGBYTES(sp)
FLOAD f7, 7 * FREGBYTES(sp)
FLOAD f8, 8 * FREGBYTES(sp)
FLOAD f9, 9 * FREGBYTES(sp)
FLOAD f10, 10 * FREGBYTES(sp)
FLOAD f11, 11 * FREGBYTES(sp)
FLOAD f12, 12 * FREGBYTES(sp)
FLOAD f13, 13 * FREGBYTES(sp)
FLOAD f14, 14 * FREGBYTES(sp)
FLOAD f15, 15 * FREGBYTES(sp)
FLOAD f16, 16 * FREGBYTES(sp)
FLOAD f17, 17 * FREGBYTES(sp)
FLOAD f18, 18 * FREGBYTES(sp)
FLOAD f19, 19 * FREGBYTES(sp)
FLOAD f20, 20 * FREGBYTES(sp)
FLOAD f21, 21 * FREGBYTES(sp)
FLOAD f22, 22 * FREGBYTES(sp)
FLOAD f23, 23 * FREGBYTES(sp)
FLOAD f24, 24 * FREGBYTES(sp)
FLOAD f25, 25 * FREGBYTES(sp)
FLOAD f26, 26 * FREGBYTES(sp)
FLOAD f27, 27 * FREGBYTES(sp)
FLOAD f28, 28 * FREGBYTES(sp)
FLOAD f29, 29 * FREGBYTES(sp)
FLOAD f30, 30 * FREGBYTES(sp)
FLOAD f31, 31 * FREGBYTES(sp)
addi sp, sp, 32 * FREGBYTES
#endif
XRET

View File

@ -70,8 +70,11 @@ rt_uint8_t *rt_hw_stack_init(void *tentry,
frame->epc = (rt_ubase_t)tentry; frame->epc = (rt_ubase_t)tentry;
frame->user_sp_exc_stack = (rt_ubase_t)(((rt_ubase_t)stk) + sizeof(struct rt_hw_stack_frame)); frame->user_sp_exc_stack = (rt_ubase_t)(((rt_ubase_t)stk) + sizeof(struct rt_hw_stack_frame));
/* force to supervisor mode(SPP=1) and set SPIE and SUM to 1 */ #ifndef RISCV_S_MODE
frame->sstatus = 0x00040120; frame->xstatus = 0x00007880;
#else
frame->xstatus = 0x00040120;
#endif
return stk; return stk;
} }

View File

@ -22,7 +22,34 @@
// error here, not portable // error here, not portable
#endif #endif
#endif
#ifdef RISCV_U_MODE #ifdef RISCV_U_MODE
#define RISCV_USER_ENTRY 0xFFFFFFE000000000ULL #define RISCV_USER_ENTRY 0xFFFFFFE000000000ULL
#endif #endif
#ifdef RISCV_S_MODE
//csr in s-mode
// M/U/S Interrupt Registers
#define SRC_XIE sie
#define SRC_XIP sip
#define SRC_XTVEC stvec
#define SRC_XSTATUS sstatus
#define SRC_XSCRATCH sscratch
#define SRC_XEPC sepc
#define SRC_XCAUSE scause
#define SRC_XTVAL stval
#define XRET sret
#else
//csr in m-mode
// M/U/S Interrupt Registers
#define SRC_XIE mie
#define SRC_XIP mip
#define SRC_XTVEC mtvec
#define SRC_XSTATUS mstatus
#define SRC_XSCRATCH mscratch
#define SRC_XEPC mepc
#define SRC_XCAUSE mcause
#define SRC_XTVAL mtval
#define XRET mret
#endif
#endif

View File

@ -0,0 +1,274 @@
/*
* Copyright (c) 2006-2021, RT-Thread Development Team
*
* SPDX-License-Identifier: Apache-2.0
*
* Change Logs:
* Date Author Notes
* 2018/10/01 Bernard The first version
* 2018/12/27 Jesven Change irq enable/disable to cpu0
*/
#include "tick.h"
#include <plic.h>
#include "encoding.h"
#include "riscv.h"
#include "interrupt.h"
#define CPU_NUM 2
#define MAX_HANDLERS 128
static struct rt_irq_desc irq_desc[MAX_HANDLERS];
static rt_isr_handler_t rt_hw_interrupt_handle(rt_uint32_t vector, void *param)
{
rt_kprintf("UN-handled interrupt %d occurred!!!\n", vector);
return RT_NULL;
}
int rt_hw_clint_ipi_enable(void)
{
/* Set the Machine-Software bit in MIE */
set_csr(mie, MIP_MSIP);
return 0;
}
int rt_hw_clint_ipi_disable(void)
{
/* Clear the Machine-Software bit in MIE */
clear_csr(mie, MIP_MSIP);
return 0;
}
int rt_hw_plic_irq_enable(int irq_number)
{
plic_irq_enable(irq_number);
return 0;
}
int rt_hw_plic_irq_disable(int irq_number)
{
plic_irq_disable(irq_number);
return 0;
}
/**
* This function will initialize hardware interrupt
*/
void rt_hw_interrupt_init(void)
{
int idx = 0;
/* init exceptions table */
for (idx = 0; idx < MAX_HANDLERS; idx++)
{
//rt_hw_interrupt_mask(idx);
irq_desc[idx].handler = (rt_isr_handler_t)rt_hw_interrupt_handle;
irq_desc[idx].param = RT_NULL;
#ifdef RT_USING_INTERRUPT_INFO
rt_snprintf(irq_desc[idx].name, RT_NAME_MAX - 1, "default");
irq_desc[idx].counter = 0;
#endif
}
}
/**
* This function will mask a interrupt.
* @param vector the interrupt number
*/
void rt_hw_interrupt_mask(int vector)
{
rt_hw_plic_irq_disable(vector);
}
/**
* This function will un-mask a interrupt.
* @param vector the interrupt number
*/
void rt_hw_interrupt_umask(int vector)
{
plic_set_priority(vector, 1);
plic_set_threshold(0);
rt_hw_plic_irq_enable(vector);
}
/**
* This function will install a interrupt service routine to a interrupt.
* @param vector the interrupt number
* @param new_handler the interrupt service routine to be installed
* @param old_handler the old interrupt service routine
*/
rt_isr_handler_t rt_hw_interrupt_install(int vector, rt_isr_handler_t handler,
void *param, const char *name)
{
rt_isr_handler_t old_handler = RT_NULL;
if(vector < MAX_HANDLERS)
{
old_handler = irq_desc[vector].handler;
if (handler != RT_NULL)
{
irq_desc[vector].handler = (rt_isr_handler_t)handler;
irq_desc[vector].param = param;
#ifdef RT_USING_INTERRUPT_INFO
rt_snprintf(irq_desc[vector].name, RT_NAME_MAX - 1, "%s", name);
irq_desc[vector].counter = 0;
#endif
}
}
return old_handler;
}
RT_WEAK
void plic_irq_handle(int irq)
{
rt_kprintf("UN-handled interrupt %d occurred!!!\n", irq);
return ;
}
void dump_regs(struct rt_hw_stack_frame *regs)
{
rt_kprintf("--------------Dump Registers-----------------\n");
rt_kprintf("Function Registers:\n");
rt_kprintf("\tra(x1) = 0x%p\tuser_sp = 0x%p\n",regs -> ra,regs -> user_sp_exc_stack);
rt_kprintf("\tgp(x3) = 0x%p\ttp(x4) = 0x%p\n",regs -> gp,regs -> tp);
rt_kprintf("Temporary Registers:\n");
rt_kprintf("\tt0(x5) = 0x%p\tt1(x6) = 0x%p\n",regs -> t0,regs -> t1);
rt_kprintf("\tt2(x7) = 0x%p\n",regs -> t2);
rt_kprintf("\tt3(x28) = 0x%p\tt4(x29) = 0x%p\n",regs -> t3,regs -> t4);
rt_kprintf("\tt5(x30) = 0x%p\tt6(x31) = 0x%p\n",regs -> t5,regs -> t6);
rt_kprintf("Saved Registers:\n");
rt_kprintf("\ts0/fp(x8) = 0x%p\ts1(x9) = 0x%p\n",regs -> s0_fp,regs -> s1);
rt_kprintf("\ts2(x18) = 0x%p\ts3(x19) = 0x%p\n",regs -> s2,regs -> s3);
rt_kprintf("\ts4(x20) = 0x%p\ts5(x21) = 0x%p\n",regs -> s4,regs -> s5);
rt_kprintf("\ts6(x22) = 0x%p\ts7(x23) = 0x%p\n",regs -> s6,regs -> s7);
rt_kprintf("\ts8(x24) = 0x%p\ts9(x25) = 0x%p\n",regs -> s8,regs -> s9);
rt_kprintf("\ts10(x26) = 0x%p\ts11(x27) = 0x%p\n",regs -> s10,regs -> s11);
rt_kprintf("Function Arguments Registers:\n");
rt_kprintf("\ta0(x10) = 0x%p\ta1(x11) = 0x%p\n",regs -> a0,regs -> a1);
rt_kprintf("\ta2(x12) = 0x%p\ta3(x13) = 0x%p\n",regs -> a2,regs -> a3);
rt_kprintf("\ta4(x14) = 0x%p\ta5(x15) = 0x%p\n",regs -> a4,regs -> a5);
rt_kprintf("\ta6(x16) = 0x%p\ta7(x17) = 0x%p\n",regs -> a6,regs -> a7);
rt_kprintf("xstatus = 0x%p\n",regs -> xstatus);
rt_kprintf("\t%s\n",(regs -> xstatus & SSTATUS_SIE) ? "Supervisor Interrupt Enabled" : "Supervisor Interrupt Disabled");
rt_kprintf("\t%s\n",(regs -> xstatus & SSTATUS_SPIE) ? "Last Time Supervisor Interrupt Enabled" : "Last Time Supervisor Interrupt Disabled");
rt_kprintf("\t%s\n",(regs -> xstatus & SSTATUS_SPP) ? "Last Privilege is Supervisor Mode" : "Last Privilege is User Mode");
rt_kprintf("\t%s\n",(regs -> xstatus & SSTATUS_PUM) ? "Permit to Access User Page" : "Not Permit to Access User Page");
rt_kprintf("\t%s\n",(regs -> xstatus & (1 << 19)) ? "Permit to Read Executable-only Page" : "Not Permit to Read Executable-only Page");
rt_size_t satp_v = read_csr(satp);
rt_kprintf("satp = 0x%p\n",satp_v);
const char *mode_str = "Unknown Address Translation/Protection Mode";
switch(__MASKVALUE(satp_v >> 60,__MASK(4)))
{
case 0:
mode_str = "No Address Translation/Protection Mode";
break;
case 8:
mode_str = "Page-based 39-bit Virtual Addressing Mode";
break;
case 9:
mode_str = "Page-based 48-bit Virtual Addressing Mode";
break;
}
rt_kprintf("\tMode = %s\n",mode_str);
rt_kprintf("-----------------Dump OK---------------------\n");
}
void handle_trap(rt_size_t xcause,rt_size_t xtval,rt_size_t xepc,struct rt_hw_stack_frame *sp)
{
int cause = (xcause & 0xFFFFFFFF);
int plic_irq = 0;
if (xcause & (1UL << 63))
{
switch (cause)
{
case IRQ_M_SOFT:
{
}
break;
case IRQ_M_TIMER:
tick_isr();
break;
case IRQ_S_TIMER:
tick_isr();
break;
case IRQ_S_EXT:
plic_irq = plic_claim();
plic_complete(plic_irq);
irq_desc[plic_irq].handler(plic_irq, irq_desc[plic_irq].param);
break;
case IRQ_M_EXT:
plic_irq = plic_claim();
plic_complete(plic_irq);
irq_desc[plic_irq].handler(plic_irq, irq_desc[plic_irq].param);
break;
}
}
else
{
rt_thread_t tid;
extern long list_thread();
rt_hw_interrupt_disable();
rt_kprintf("xcause = %08x,xtval = %08x,xepc = %08x\n", xcause, xtval, xepc);
tid = rt_thread_self();
rt_kprintf("\nException:\n");
switch (cause)
{
case CAUSE_MISALIGNED_FETCH:
rt_kprintf("Instruction address misaligned");
break;
case CAUSE_FAULT_FETCH:
rt_kprintf("Instruction access fault");
break;
case CAUSE_ILLEGAL_INSTRUCTION:
rt_kprintf("Illegal instruction");
break;
case CAUSE_BREAKPOINT:
rt_kprintf("Breakpoint");
break;
case CAUSE_MISALIGNED_LOAD:
rt_kprintf("Load address misaligned");
break;
case CAUSE_FAULT_LOAD:
rt_kprintf("Load access fault");
break;
case CAUSE_MISALIGNED_STORE:
rt_kprintf("Store address misaligned");
break;
case CAUSE_FAULT_STORE:
rt_kprintf("Store access fault");
break;
case CAUSE_USER_ECALL:
rt_kprintf("Environment call from U-mode");
break;
case CAUSE_SUPERVISOR_ECALL:
rt_kprintf("Environment call from S-mode");
break;
case CAUSE_HYPERVISOR_ECALL:
rt_kprintf("Environment call from H-mode");
break;
case CAUSE_MACHINE_ECALL:
rt_kprintf("Environment call from M-mode");
break;
default:
rt_kprintf("Uknown exception : %08lX", cause);
break;
}
rt_kprintf("\n");
dump_regs(sp);
rt_kprintf("exception pc => 0x%08x\n", xepc);
rt_kprintf("current thread: %.*s\n", RT_NAME_MAX, tid->name);
#ifdef RT_USING_FINSH
list_thread();
#endif
while(1);
}
rt_hw_interrupt_enable(0);
}

View File

@ -0,0 +1,27 @@
/*
* Copyright (c) 2006-2021, RT-Thread Development Team
*
* SPDX-License-Identifier: Apache-2.0
*
* Change Logs:
* Date Author Notes
* 2021-05-20 bigmagic The first version
*/
#ifndef INTERRUPT_H__
#define INTERRUPT_H__
#include <rthw.h>
#include "stack.h"
int rt_hw_clint_ipi_enable(void);
int rt_hw_clint_ipi_disable(void);
int rt_hw_plic_irq_enable(int irq_number);
int rt_hw_plic_irq_disable(int irq_number);
void rt_hw_interrupt_init(void);
void rt_hw_interrupt_mask(int vector);
rt_isr_handler_t rt_hw_interrupt_install(int vector, rt_isr_handler_t handler,
void *param, const char *name);
void handle_trap(rt_size_t xcause,rt_size_t xtval,rt_size_t xepc,struct rt_hw_stack_frame *sp);
#endif

View File

@ -11,31 +11,125 @@
*/ */
#include "cpuport.h" #include "cpuport.h"
#include "encoding.h"
#include "stackframe.h"
.section .text.entry .section .text.entry
.align 2 .align 2
.global trap_entry .global trap_entry
.extern __stack_cpu0
.extern get_current_thread_kernel_stack_top
trap_entry: trap_entry:
//backup sp #ifdef ARCH_RISCV_FPU
csrrw sp, sscratch, sp addi sp, sp, -32 * FREGBYTES
//load interrupt stack
la sp, __stack_cpu0
//backup context
SAVE_ALL
RESTORE_SYS_GP FSTORE f0, 0 * FREGBYTES(sp)
FSTORE f1, 1 * FREGBYTES(sp)
FSTORE f2, 2 * FREGBYTES(sp)
FSTORE f3, 3 * FREGBYTES(sp)
FSTORE f4, 4 * FREGBYTES(sp)
FSTORE f5, 5 * FREGBYTES(sp)
FSTORE f6, 6 * FREGBYTES(sp)
FSTORE f7, 7 * FREGBYTES(sp)
FSTORE f8, 8 * FREGBYTES(sp)
FSTORE f9, 9 * FREGBYTES(sp)
FSTORE f10, 10 * FREGBYTES(sp)
FSTORE f11, 11 * FREGBYTES(sp)
FSTORE f12, 12 * FREGBYTES(sp)
FSTORE f13, 13 * FREGBYTES(sp)
FSTORE f14, 14 * FREGBYTES(sp)
FSTORE f15, 15 * FREGBYTES(sp)
FSTORE f16, 16 * FREGBYTES(sp)
FSTORE f17, 17 * FREGBYTES(sp)
FSTORE f18, 18 * FREGBYTES(sp)
FSTORE f19, 19 * FREGBYTES(sp)
FSTORE f20, 20 * FREGBYTES(sp)
FSTORE f21, 21 * FREGBYTES(sp)
FSTORE f22, 22 * FREGBYTES(sp)
FSTORE f23, 23 * FREGBYTES(sp)
FSTORE f24, 24 * FREGBYTES(sp)
FSTORE f25, 25 * FREGBYTES(sp)
FSTORE f26, 26 * FREGBYTES(sp)
FSTORE f27, 27 * FREGBYTES(sp)
FSTORE f28, 28 * FREGBYTES(sp)
FSTORE f29, 29 * FREGBYTES(sp)
FSTORE f30, 30 * FREGBYTES(sp)
FSTORE f31, 31 * FREGBYTES(sp)
csrr a0, scause #endif
csrrc a1, stval, zero
csrr a2, sepc
mv a3, sp
/* scause, stval, sepc, sp */ /* save thread context to thread stack */
addi sp, sp, -32 * REGBYTES
STORE x1, 1 * REGBYTES(sp)
csrr x1, SRC_XSTATUS
STORE x1, 2 * REGBYTES(sp)
csrr x1, SRC_XEPC
STORE x1, 0 * REGBYTES(sp)
STORE x4, 4 * REGBYTES(sp)
STORE x5, 5 * REGBYTES(sp)
STORE x6, 6 * REGBYTES(sp)
STORE x7, 7 * REGBYTES(sp)
STORE x8, 8 * REGBYTES(sp)
STORE x9, 9 * REGBYTES(sp)
STORE x10, 10 * REGBYTES(sp)
STORE x11, 11 * REGBYTES(sp)
STORE x12, 12 * REGBYTES(sp)
STORE x13, 13 * REGBYTES(sp)
STORE x14, 14 * REGBYTES(sp)
STORE x15, 15 * REGBYTES(sp)
STORE x16, 16 * REGBYTES(sp)
STORE x17, 17 * REGBYTES(sp)
STORE x18, 18 * REGBYTES(sp)
STORE x19, 19 * REGBYTES(sp)
STORE x20, 20 * REGBYTES(sp)
STORE x21, 21 * REGBYTES(sp)
STORE x22, 22 * REGBYTES(sp)
STORE x23, 23 * REGBYTES(sp)
STORE x24, 24 * REGBYTES(sp)
STORE x25, 25 * REGBYTES(sp)
STORE x26, 26 * REGBYTES(sp)
STORE x27, 27 * REGBYTES(sp)
STORE x28, 28 * REGBYTES(sp)
STORE x29, 29 * REGBYTES(sp)
STORE x30, 30 * REGBYTES(sp)
STORE x31, 31 * REGBYTES(sp)
/* switch to interrupt stack */
move s0, sp
#ifndef RISCV_S_MODE
/* get cpu id */
csrr t0, mhartid
#else
li t0, 0
#endif
/* switch interrupt stack of current cpu */
la sp, __stack_start__
addi t1, t0, 1
li t2, __STACKSIZE__
mul t1, t1, t2
add sp, sp, t1 /* sp = (cpuid + 1) * __STACKSIZE__ + __stack_start__ */
/* handle interrupt */
call rt_interrupt_enter
csrr a0, SRC_XCAUSE
csrr a1, SRC_XEPC
mv a2, s0
call handle_trap call handle_trap
call rt_interrupt_leave
#ifdef RT_USING_SMP
/* s0 --> sp */
mv sp, s0
mv a0, s0
call rt_scheduler_do_irq_switch
tail rt_hw_context_switch_exit
#else
/* switch to from_thread stack */
move sp, s0
/* need to switch new thread */ /* need to switch new thread */
la s0, rt_thread_switch_interrupt_flag la s0, rt_thread_switch_interrupt_flag
@ -43,41 +137,6 @@ trap_entry:
beqz s2, spurious_interrupt beqz s2, spurious_interrupt
sw zero, 0(s0) sw zero, 0(s0)
.global rt_hw_context_switch_interrupt_do
rt_hw_context_switch_interrupt_do:
//switch to thread kernel stack
csrr t0, sstatus
andi t0, t0, 0x100
beqz t0, __restore_sp_from_tcb_interrupt
__restore_sp_from_sscratch_interrupt:
csrr t0, sscratch
j __move_stack_context_interrupt
__restore_sp_from_tcb_interrupt:
la s0, rt_interrupt_from_thread
LOAD a0, 0(s0)
jal rt_thread_sp_to_thread
jal get_thread_kernel_stack_top
mv t0, a0
__move_stack_context_interrupt:
mv t1, sp//src
mv sp, t0//switch stack
addi sp, sp, -33 * REGBYTES
//copy context
li s0, 33//cnt
mv t2, sp//dst
copy_context_loop_interrupt:
LOAD t0, 0(t1)
STORE t0, 0(t2)
addi s0, s0, -1
addi t1, t1, 8
addi t2, t2, 8
bnez s0, copy_context_loop_interrupt
la s0, rt_interrupt_from_thread la s0, rt_interrupt_from_thread
LOAD s1, 0(s0) LOAD s1, 0(s0)
STORE sp, 0(s1) STORE sp, 0(s1)
@ -86,16 +145,7 @@ copy_context_loop_interrupt:
LOAD s1, 0(s0) LOAD s1, 0(s0)
LOAD sp, 0(s1) LOAD sp, 0(s1)
#endif
spurious_interrupt: spurious_interrupt:
RESTORE_ALL tail rt_hw_context_switch_exit
sret
.global rt_hw_interrupt_enable
rt_hw_interrupt_enable:
csrs sstatus, a0
jr ra
.global rt_hw_interrupt_disable
rt_hw_interrupt_disable:
csrrci a0, sstatus, 2
jr ra

View File

@ -10,25 +10,45 @@
#ifndef __RISCV_IO_H__ #ifndef __RISCV_IO_H__
#define __RISCV_IO_H__ #define __RISCV_IO_H__
// which hart (core) is this?
static inline uint32_t r_mhartid()
{
#ifndef RISCV_S_MODE
uint32_t x;
asm volatile("csrr %0, mhartid" : "=r" (x) );
return x;
#else
return 0;
#endif
}
static inline void __raw_writeb(rt_uint8_t val, volatile void *addr) static inline void __raw_writeb(rt_uint8_t val, volatile void *addr)
{ {
asm volatile("sb %0, 0(%1)" : : "r"(val), "r"(addr)); asm volatile("sb %0, 0(%1)"
:
: "r"(val), "r"(addr));
} }
static inline void __raw_writew(rt_uint16_t val, volatile void *addr) static inline void __raw_writew(rt_uint16_t val, volatile void *addr)
{ {
asm volatile("sh %0, 0(%1)" : : "r"(val), "r"(addr)); asm volatile("sh %0, 0(%1)"
:
: "r"(val), "r"(addr));
} }
static inline void __raw_writel(rt_uint32_t val, volatile void *addr) static inline void __raw_writel(rt_uint32_t val, volatile void *addr)
{ {
asm volatile("sw %0, 0(%1)" : : "r"(val), "r"(addr)); asm volatile("sw %0, 0(%1)"
:
: "r"(val), "r"(addr));
} }
#if __riscv_xlen != 32 #if __riscv_xlen != 32
static inline void __raw_writeq(rt_uint64_t val, volatile void *addr) static inline void __raw_writeq(rt_uint64_t val, volatile void *addr)
{ {
asm volatile("sd %0, 0(%1)" : : "r"(val), "r"(addr)); asm volatile("sd %0, 0(%1)"
:
: "r"(val), "r"(addr));
} }
#endif #endif
@ -36,7 +56,9 @@
{ {
rt_uint8_t val; rt_uint8_t val;
asm volatile("lb %0, 0(%1)" : "=r"(val) : "r"(addr)); asm volatile("lb %0, 0(%1)"
: "=r"(val)
: "r"(addr));
return val; return val;
} }
@ -44,7 +66,9 @@
{ {
rt_uint16_t val; rt_uint16_t val;
asm volatile("lh %0, 0(%1)" : "=r"(val) : "r"(addr)); asm volatile("lh %0, 0(%1)"
: "=r"(val)
: "r"(addr));
return val; return val;
} }
@ -52,7 +76,9 @@
{ {
rt_uint32_t val; rt_uint32_t val;
asm volatile("lw %0, 0(%1)" : "=r"(val) : "r"(addr)); asm volatile("lw %0, 0(%1)"
: "=r"(val)
: "r"(addr));
return val; return val;
} }
@ -61,7 +87,9 @@
{ {
rt_uint64_t val; rt_uint64_t val;
asm volatile("ld %0, 0(%1)" : "=r"(val) : "r"(addr)); asm volatile("ld %0, 0(%1)"
: "=r"(val)
: "r"(addr));
return val; return val;
} }
#endif #endif

View File

@ -16,7 +16,7 @@ struct rt_hw_stack_frame
{ {
rt_ubase_t epc; /* epc - epc - program counter */ rt_ubase_t epc; /* epc - epc - program counter */
rt_ubase_t ra; /* x1 - ra - return address for jumps */ rt_ubase_t ra; /* x1 - ra - return address for jumps */
rt_ubase_t sstatus; /* - supervisor status register */ rt_ubase_t xstatus; /* - supervisor/machine/user status register */
rt_ubase_t gp; /* x3 - gp - global pointer */ rt_ubase_t gp; /* x3 - gp - global pointer */
rt_ubase_t tp; /* x4 - tp - thread pointer */ rt_ubase_t tp; /* x4 - tp - thread pointer */
rt_ubase_t t0; /* x5 - t0 - temporary register 0 */ rt_ubase_t t0; /* x5 - t0 - temporary register 0 */

View File

@ -19,10 +19,10 @@
STORE x1, 1 * REGBYTES(sp) STORE x1, 1 * REGBYTES(sp)
csrr x1, sstatus csrr x1, SRC_XSTATUS
STORE x1, 2 * REGBYTES(sp) STORE x1, 2 * REGBYTES(sp)
csrr x1, sepc csrr x1, SRC_XEPC
STORE x1, 0 * REGBYTES(sp) STORE x1, 0 * REGBYTES(sp)
STORE x3, 3 * REGBYTES(sp) STORE x3, 3 * REGBYTES(sp)
@ -54,17 +54,17 @@
STORE x29, 29 * REGBYTES(sp) STORE x29, 29 * REGBYTES(sp)
STORE x30, 30 * REGBYTES(sp) STORE x30, 30 * REGBYTES(sp)
STORE x31, 31 * REGBYTES(sp) STORE x31, 31 * REGBYTES(sp)
csrr t0, sscratch csrr t0, SRC_XSCRATCH
STORE t0, 32 * REGBYTES(sp) STORE t0, 32 * REGBYTES(sp)
.endm .endm
.macro RESTORE_ALL_ONLY .macro RESTORE_ALL_ONLY
/* resw ra to sepc */ /* resw ra to sepc */
LOAD x1, 0 * REGBYTES(sp) LOAD x1, 0 * REGBYTES(sp)
csrw sepc, x1 csrw SRC_XEPC, x1
LOAD x1, 2 * REGBYTES(sp) LOAD x1, 2 * REGBYTES(sp)
csrw sstatus, x1 csrw SRC_XSTATUS, x1
LOAD x1, 1 * REGBYTES(sp) LOAD x1, 1 * REGBYTES(sp)
@ -104,10 +104,10 @@
.macro RESTORE_ALL .macro RESTORE_ALL
/* resw ra to sepc */ /* resw ra to sepc */
LOAD x1, 0 * REGBYTES(sp) LOAD x1, 0 * REGBYTES(sp)
csrw sepc, x1 csrw SRC_XEPC, x1
LOAD x1, 2 * REGBYTES(sp) LOAD x1, 2 * REGBYTES(sp)
csrw sstatus, x1 csrw SRC_XSTATUS, x1
LOAD x1, 1 * REGBYTES(sp) LOAD x1, 1 * REGBYTES(sp)
@ -152,12 +152,4 @@
.option pop .option pop
.endm .endm
.macro OPEN_INTERRUPT
csrsi sstatus, 2
.endm
.macro CLOSE_INTERRUPT
csrci sstatus, 2
.endm
#endif #endif

View File

@ -10,71 +10,48 @@
* 2020/6/12 Xim Port to QEMU and remove SMP support * 2020/6/12 Xim Port to QEMU and remove SMP support
*/ */
#define SSTATUS_FS 0x00006000U /* initial state of FPU, clear to disable */ #define XSTATUS_FS (3 << 13) /* initial state of FPU, clear to disable */
#define XSTATUS_PUM (1 << 18)
#include <cpuport.h> #include <cpuport.h>
.global _start .global _start
.section ".start", "ax" .section ".start", "ax"
_start: _start:
j 1f #ifndef RISCV_S_MODE
.word 0xdeadbeef # setup stacks per hart
.align 3 csrr t0, mhartid # read current hart id
.global g_wake_up slli t0, t0, 10 # shift left the hart id by 1024
g_wake_up:
.dword 1
.dword 0
1:
csrw sie, 0
csrw sip, 0
la t0, trap_entry
csrw stvec, t0
li x1, 0 # park harts with id != 0
li x2, 0 csrr a0, mhartid # read current hart id
li x3, 0 bnez a0, park # if we're not on the hart 0
li x4, 0 #endif
li x5, 0
li x6, 0 csrw SRC_XIE, 0 # clear Interrupt Registers
li x7, 0 csrw SRC_XIP, 0
li x8, 0
li x9, 0 la t0, trap_entry
li x10,0 csrw SRC_XTVEC, t0 # set Trap Vector Base Address Register
li x11,0
li x12,0
li x13,0
li x14,0
li x15,0
li x16,0
li x17,0
li x18,0
li x19,0
li x20,0
li x21,0
li x22,0
li x23,0
li x24,0
li x25,0
li x26,0
li x27,0
li x28,0
li x29,0
li x30,0
li x31,0
/* set to disable FPU */ /* set to disable FPU */
li t0, SSTATUS_FS li t0, XSTATUS_FS # close fpu
csrc sstatus, t0 csrc SRC_XSTATUS, t0
li t0, 0x40000 // SUM in sstatus #ifdef RISCV_S_MODE
csrs sstatus, t0 li t0, XSTATUS_PUM # PUM has no effect
csrs SRC_XSTATUS, t0
#endif
.option push .option push
.option norelax .option norelax
la gp, __global_pointer$ la gp, __global_pointer$
.option pop .option pop
// removed SMP support here
la sp, __stack_start__ la sp, __stack_start__
li t0, __STACKSIZE__ li t0, __STACKSIZE__
add sp, sp, t0 add sp, sp, t0
csrw sscratch, sp csrw SRC_XSCRATCH, sp
j primary_cpu_entry j primary_cpu_entry
park:
wfi
j park

View File

@ -11,8 +11,12 @@
#include <rthw.h> #include <rthw.h>
#include <rtthread.h> #include <rtthread.h>
#include <encoding.h>
#include "sbi.h" #include "sbi.h"
#include "tick.h"
#include <riscv_io.h>
#include <encoding.h>
#define VIRT_CLINT_TIMEBASE_FREQ (10000000)
static volatile uint64_t time_elapsed = 0; static volatile uint64_t time_elapsed = 0;
static volatile unsigned long tick_cycles = 0; static volatile unsigned long tick_cycles = 0;
@ -27,11 +31,14 @@ static uint64_t get_ticks()
int tick_isr(void) int tick_isr(void)
{ {
// uint64_t core_id = current_coreid(); int tick_cycles = VIRT_CLINT_TIMEBASE_FREQ / RT_TICK_PER_SECOND;
int tick_cycles = 40000;
// clint->mtimecmp[core_id] += tick_cycles;
rt_tick_increase(); rt_tick_increase();
#ifdef RISCV_S_MODE
sbi_set_timer(get_ticks() + tick_cycles); sbi_set_timer(get_ticks() + tick_cycles);
#else
int id = r_mhartid();
*(uint64_t*)CLINT_MTIMECMP(id) = *(uint64_t*)CLINT_MTIME + tick_cycles;
#endif
return 0; return 0;
} }
@ -39,10 +46,9 @@ int tick_isr(void)
/* Sets and enable the timer interrupt */ /* Sets and enable the timer interrupt */
int rt_hw_tick_init(void) int rt_hw_tick_init(void)
{ {
/* Read core id */ unsigned long interval = VIRT_CLINT_TIMEBASE_FREQ / RT_TICK_PER_SECOND;
// unsigned long core_id = current_coreid();
unsigned long interval = 1000/RT_TICK_PER_SECOND;
#ifdef RISCV_S_MODE
/* Clear the Supervisor-Timer bit in SIE */ /* Clear the Supervisor-Timer bit in SIE */
clear_csr(sie, SIP_STIP); clear_csr(sie, SIP_STIP);
@ -54,6 +60,12 @@ int rt_hw_tick_init(void)
/* Enable the Supervisor-Timer bit in SIE */ /* Enable the Supervisor-Timer bit in SIE */
set_csr(sie, SIP_STIP); set_csr(sie, SIP_STIP);
#else
clear_csr(mie, MIP_MTIP);
clear_csr(mip, MIP_MTIP);
int id = r_mhartid();
*(uint64_t*)CLINT_MTIMECMP(id) = *(uint64_t*)CLINT_MTIME + interval;
set_csr(mie, MIP_MTIP);
#endif
return 0; return 0;
} }

View File

@ -11,6 +11,11 @@
#ifndef TICK_H__ #ifndef TICK_H__
#define TICK_H__ #define TICK_H__
//ask the CLINT for a timer interrupt.
#define CLINT (0x2000000L)
#define CLINT_MTIMECMP(hartid) (CLINT + 0x4000 + 4*(hartid))
#define CLINT_MTIME (CLINT + 0xBFF8) // cycles since boot.
int tick_isr(void); int tick_isr(void);
int rt_hw_tick_init(void); int rt_hw_tick_init(void);