Merge pull request #416 from Jer6y/master

riscv : add riscv qemu virt support and fix fs bit error in mstatus
This commit is contained in:
Frédéric Desbiens
2025-02-13 09:58:54 -05:00
committed by GitHub
20 changed files with 1463 additions and 0 deletions
+29
View File
@@ -0,0 +1,29 @@
# Toolchain settings
set(CMAKE_C_COMPILER riscv64-unknown-elf-gcc)
set(CMAKE_CXX_COMPILER riscv64-unknown-elf-g++)
set(AS riscv64-unknown-elf-as)
set(AR riscv64-unknown-elf-ar)
set(OBJCOPY riscv64-unknown-elf-objcopy)
set(OBJDUMP riscv64-unknown-elf-objdump)
set(SIZE riscv64-unknown-elf-size)
set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER)
set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY)
set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY)
set(CMAKE_FIND_ROOT_PATH_MODE_PACKAGE ONLY)
# this makes the test compiles use static library option so that we don't need to pre-set linker flags and scripts
set(CMAKE_TRY_COMPILE_TARGET_TYPE STATIC_LIBRARY)
set(CMAKE_C_FLAGS "${CFLAGS}" CACHE INTERNAL "c compiler flags")
set(CMAKE_CXX_FLAGS "${CXXFLAGS}" CACHE INTERNAL "cxx compiler flags")
set(CMAKE_ASM_FLAGS "${ASFLAGS} -D__ASSEMBLER__" CACHE INTERNAL "asm compiler flags")
set(CMAKE_EXE_LINKER_FLAGS "${LDFLAGS}" CACHE INTERNAL "exe link flags")
SET(CMAKE_C_FLAGS_DEBUG "-Og -g -ggdb3" CACHE INTERNAL "c debug compiler flags")
SET(CMAKE_CXX_FLAGS_DEBUG "-Og -g -ggdb3" CACHE INTERNAL "cxx debug compiler flags")
SET(CMAKE_ASM_FLAGS_DEBUG "-g -ggdb3" CACHE INTERNAL "asm debug compiler flags")
SET(CMAKE_C_FLAGS_RELEASE "-O3" CACHE INTERNAL "c release compiler flags")
SET(CMAKE_CXX_FLAGS_RELEASE "-O3" CACHE INTERNAL "cxx release compiler flags")
SET(CMAKE_ASM_FLAGS_RELEASE "" CACHE INTERNAL "asm release compiler flags")
+12
View File
@@ -0,0 +1,12 @@
# Name of the target
set(CMAKE_SYSTEM_NAME Generic)
set(CMAKE_SYSTEM_PROCESSOR risc-v64)
set(THREADX_ARCH "risc-v64")
set(THREADX_TOOLCHAIN "gnu")
set(ARCH_FLAGS "-g -march=rv64gc -mabi=lp64d -mcmodel=medany")
set(CFLAGS "${ARCH_FLAGS}")
set(ASFLAGS "${ARCH_FLAGS}")
set(LDFLAGS "${ARCH_FLAGS}")
include(${CMAKE_CURRENT_LIST_DIR}/riscv64-unknown-elf.cmake)
+19
View File
@@ -0,0 +1,19 @@
target_sources(${PROJECT_NAME}
PRIVATE
# {{BEGIN_TARGET_SOURCES}}
${CMAKE_CURRENT_LIST_DIR}/src/tx_initialize_low_level.S
${CMAKE_CURRENT_LIST_DIR}/src/tx_thread_context_restore.S
${CMAKE_CURRENT_LIST_DIR}/src/tx_thread_context_save.S
${CMAKE_CURRENT_LIST_DIR}/src/tx_thread_interrupt_control.S
${CMAKE_CURRENT_LIST_DIR}/src/tx_thread_schedule.S
${CMAKE_CURRENT_LIST_DIR}/src/tx_thread_stack_build.S
${CMAKE_CURRENT_LIST_DIR}/src/tx_thread_system_return.S
${CMAKE_CURRENT_LIST_DIR}/src/tx_timer_interrupt.c
# {{END_TARGET_SOURCES}}
)
target_include_directories(${PROJECT_NAME}
PUBLIC
${CMAKE_CURRENT_LIST_DIR}/inc
)
@@ -0,0 +1,32 @@
#include "plic.h"
#include "hwtimer.h"
#include "uart.h"
#include <stdint.h>
#include <stddef.h>
void *memset(const void *des, int c,size_t n)
{
if((des == NULL) || n <=0)
return (void*)des;
char* t = (char*)des;
int i;
for(i=0;i<n;i++)
t[i]=c;
return t;
}
int board_init(void)
{
int ret;
ret = plic_init();
if(ret)
return ret;
ret = uart_init();
if(ret)
return ret;
ret = hwtimer_init();
if(ret)
return ret;
return 0;
}
@@ -0,0 +1,6 @@
#!/bin/bash
pushd ../../../../../
cmake -Bbuild -GNinja -DCMAKE_TOOLCHAIN_FILE=cmake/riscv64_gnu.cmake .
cmake --build ./build/
popd
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,58 @@
.section .text
.align 4
.global _start
.extern main
.extern _sysstack_start
.extern _bss_start
.extern _bss_end
_start:
csrr t0, mhartid
bne t0, zero, 1f
li x1, 0
li x2, 0
li x3, 0
li x4, 0
li x5, 0
li x6, 0
li x7, 0
li x8, 0
li x9, 0
li x10, 0
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
la t0, _sysstack_start
li t1, 0x1000
add sp, t0, t1
la t0, _bss_start
la t1, _bss_end
_bss_clean_start:
bgeu t0, t1, _bss_clean_end
sb zero, 0(t0)
addi t0, t0, 1
j _bss_clean_start
_bss_clean_end:
call main
1:
/* todo smp */
wfi
j 1b
@@ -0,0 +1,25 @@
#include "tx_port.h"
#include "csr.h"
#include "hwtimer.h"
#define CLINT (0x02000000L)
#define CLINT_TIME (CLINT+0xBFF8)
#define CLINT_TIMECMP(hart_id) (CLINT+0x4000+8*(hart_id))
int hwtimer_init(void)
{
int hart = riscv_get_core();
uint64_t time = *((uint64_t*)CLINT_TIME);
*((uint64_t*)CLINT_TIMECMP(hart)) = time + TICKNUM_PER_TIMER;
return 0;
}
int hwtimer_handler(void)
{
int hart = riscv_get_core();
uint64_t time = *((uint64_t*)CLINT_TIME);
*((uint64_t*)CLINT_TIMECMP(hart)) = time + TICKNUM_PER_TIMER;
return 0;
}
@@ -0,0 +1,24 @@
/***************************************************************************
* Copyright (c) 2024 Microsoft Corporation
*
* This program and the accompanying materials are made available under the
* terms of the MIT License which is available at
* https://opensource.org/licenses/MIT.
*
* SPDX-License-Identifier: MIT
**************************************************************************/
#ifndef RISCV_HWTIMER_H
#define RISCV_HWTIMER_H
#include <stdint.h>
#define TICKNUM_PER_SECOND 10000000
#define TICKNUM_PER_TIMER (TICKNUM_PER_SECOND / 10)
int hwtimer_init(void);
int hwtimer_handler(void);
#endif
@@ -0,0 +1,49 @@
OUTPUT_ARCH( "riscv" )
ENTRY( _start )
SECTIONS
{
/*
* ensure that entry.S / _entry is at 0x80000000,
* where qemu's -kernel jumps.
*/
. = 0x80000000;
.text : {
*(.text .text.*)
. = ALIGN(0x1000);
PROVIDE(etext = .);
}
.rodata : {
. = ALIGN(16);
*(.srodata .srodata.*) /* do not need to distinguish this from .rodata */
. = ALIGN(16);
*(.rodata .rodata.*)
}
.data : {
. = ALIGN(16);
*(.sdata .sdata.*) /* do not need to distinguish this from .data */
. = ALIGN(16);
*(.data .data.*)
}
.bss : {
. = ALIGN(16);
_bss_start = .;
*(.sbss .sbss.*) /* do not need to distinguish this from .bss */
. = ALIGN(16);
*(.bss .bss.*)
_bss_end = .;
}
.stack : {
. = ALIGN(4096);
_sysstack_start = .;
. += 0x1000;
_sysstack_end = .;
}
PROVIDE(_end = .);
}
@@ -0,0 +1,72 @@
#include "plic.h"
#include <stddef.h>
irq_callback callbacks[MAX_CALLBACK_NUM];
void plic_irq_enable(int irqno)
{
int hart = riscv_get_core();
*(uint32_t*)PLIC_MENABLE(hart) = (*(uint32_t*)PLIC_MENABLE(hart) | (1 << irqno));
return;
}
void plic_irq_disable(int irqno)
{
int hart = riscv_get_core();
*(uint32_t*)PLIC_MENABLE(hart) = (*(uint32_t*)PLIC_MENABLE(hart) & (~(1 << irqno)));
return;
}
void plic_prio_set(int irqno, int prio)
{
PLIC_SET_PRIO(irqno, prio);
}
int plic_prio_get(int irqno)
{
return PLIC_GET_PRIO(irqno);
}
int plic_register_callback(int irqno, irq_callback callback)
{
if(!(irqno >=0 && irqno < MAX_CALLBACK_NUM))
return -1;
callbacks[irqno] = callback;
return 0;
}
int plic_unregister_callback(int irqno)
{
return plic_register_callback(irqno, NULL);
}
int plic_init(void)
{
for(int i=0;i<MAX_CALLBACK_NUM;i++)
{
callbacks[i] = NULL;
}
return 0;
}
int plic_claim(void)
{
int hart = riscv_get_core();
return (*(uint32_t*)PLIC_MCLAIM(hart));
}
void plic_complete(int irqno)
{
int hart = riscv_get_core();
*(uint32_t*)(PLIC_MCOMPLETE(hart)) = (uint32_t)irqno;
return;
}
int plic_irq_intr(void)
{
int ret = -1;
int irqno = plic_claim();
if(callbacks[irqno] != NULL)
ret = (callbacks[irqno])(irqno);
plic_complete(irqno);
return ret;
}
@@ -0,0 +1,50 @@
/***************************************************************************
* Copyright (c) 2024 Microsoft Corporation
*
* This program and the accompanying materials are made available under the
* terms of the MIT License which is available at
* https://opensource.org/licenses/MIT.
*
* SPDX-License-Identifier: MIT
**************************************************************************/
#ifndef RISCV_PLIC_H
#define RISCV_PLIC_H
#include "csr.h"
#include <stdint.h>
#define PLIC 0x0c000000L
#define PLIC_PRIORITY (PLIC + 0x0)
#define PLIC_PENDING (PLIC + 0x1000)
#define PLIC_MENABLE(hart) (PLIC + 0x2000 + (hart)*0x100)
#define PLIC_SENABLE(hart) (PLIC + 0x2080 + (hart)*0x100)
#define PLIC_MPRIORITY(hart) (PLIC + 0x200000 + (hart)*0x2000)
#define PLIC_SPRIORITY(hart) (PLIC + 0x201000 + (hart)*0x2000)
#define PLIC_MCLAIM(hart) (PLIC + 0x200004 + (hart)*0x2000)
#define PLIC_SCLAIM(hart) (PLIC + 0x201004 + (hart)*0x2000)
#define PLIC_MCOMPLETE(hart) (PLIC + 0x200004 + (hart)*0x2000)
#define PLIC_SCOMPLETE(hart) (PLIC + 0x201004 + (hart)*0x2000)
#define PLIC_GET_PRIO(irqno) (*(uint32_t *)(PLIC_PRIORITY + (irqno)*4))
#define PLIC_SET_PRIO(irqno, prio) (*(uint32_t *)(PLIC_PRIORITY + (irqno)*4) = (prio))
#define MAX_CALLBACK_NUM 128
typedef int (*irq_callback)(int irqno);
void plic_irq_enable(int irqno);
void plic_irq_disable(int irqno);
int plic_prio_get(int irqno);
void plic_prio_set(int irqno, int prio);
int plic_register_callback(int irqno, irq_callback callback);
int plic_unregister_callback(int irqno);
int plic_init(void);
int plic_claim(void);
void plic_complete(int irqno);
int plic_irq_intr(void);
#endif
@@ -0,0 +1,46 @@
#include "csr.h"
#include <stdint.h>
#include "uart.h"
#include "hwtimer.h"
#include "plic.h"
#include <tx_port.h>
#include <tx_api.h>
#define OS_IS_INTERUPT(mcause) (mcause & 0x8000000000000000ull)
#define OS_IS_EXCEPTION(mcause) (~(OS_IS_INTERUPT))
#define OS_IS_TICK_INT(mcause) (mcause == 0x8000000000000007ull)
#define OS_IS_SOFT_INT(mcause) (mcause == 0x8000000000000003ull)
#define OS_IS_EXT_INT(mcause) (mcause == 0x800000000000000bull)
#define OS_IS_TRAP_USER(mcause) (mcause == 0x000000000000000bull)
extern void _tx_timer_interrupt(void);
void trap_handler(uintptr_t mcause, uintptr_t mepc, uintptr_t mtval)
{
if(OS_IS_INTERUPT(mcause))
{
if(OS_IS_TICK_INT(mcause))
{
hwtimer_handler();
_tx_timer_interrupt();
}
else if(OS_IS_EXT_INT(mcause))
{
int ret = plic_irq_intr();
if(ret)
{
puts("[INTERRUPT]: handler irq error!");
while(1) ;
}
}
else
{
puts("[INTERRUPT]: now can't deal with the interrupt!");
while(1) ;
}
}
else
{
puts("[EXCEPTION] : Unkown Error!!");
while(1) ;
}
}
@@ -0,0 +1,163 @@
/***************************************************************************
* Copyright (c) 2024 Microsoft Corporation
*
* This program and the accompanying materials are made available under the
* terms of the MIT License which is available at
* https://opensource.org/licenses/MIT.
*
* SPDX-License-Identifier: MIT
**************************************************************************/
#include "csr.h"
#include "tx_port.h"
.section .text
.align 4
/**************************************************************************/
/* */
/* FUNCTION RELEASE */
/* */
/* trap_entry RISC-V64/GNU */
/* 6.2.1 */
/* AUTHOR */
/* */
/* Jer6y , luojun@oerv.isrc.iscas.ac.cn */
/* */
/* DESCRIPTION */
/* */
/* This function is responsible for riscv processor trap handle */
/* It will do the contex save and call c trap_handler and do contex */
/* load */
/* */
/* INPUT */
/* */
/* None */
/* */
/* OUTPUT */
/* */
/* None */
/* */
/* CALLS */
/* */
/* trap_handler */
/* */
/* CALLED BY */
/* */
/* hardware exception */
/* RELEASE HISTORY */
/* */
/* DATE NAME DESCRIPTION */
/* */
/* 10-25-2024 Jerry Luo */
/* */
/**************************************************************************/
/**************************************************************************/
/**************************************************************************/
/** */
/** ThreadX Component */
/** */
/** Initialize */
/** */
/**************************************************************************/
/**************************************************************************/
.global trap_entry
.extern trap_handler
.extern _tx_thread_context_restore
trap_entry:
#if defined(__riscv_float_abi_single) || defined(__riscv_float_abi_double)
addi sp, sp, -65*REGBYTES // Allocate space for all registers - with floating point enabled
#else
addi sp, sp, -32*REGBYTES // Allocate space for all registers - without floating point enabled
#endif
STORE x1, 28*REGBYTES(sp) // Store RA, 28*REGBYTES(because call will override ra [ra is a calle register in riscv])
call _tx_thread_context_save
csrr a0, mcause
csrr a1, mepc
csrr a2, mtval
addi sp, sp, -8
sd ra, 0(sp)
call trap_handler
ld ra, 0(sp)
addi sp, sp, 8
call _tx_thread_context_restore
// it will nerver return
_err:
wfi
j _err
.section .text
/**************************************************************************/
/* */
/* FUNCTION RELEASE */
/* */
/* _tx_initialize_low_level RISC-V64/GNU */
/* 6.2.1 */
/* AUTHOR */
/* */
/* Scott Larson, Microsoft Corporation */
/* */
/* DESCRIPTION */
/* */
/* This function is responsible for any low-level processor */
/* initialization, including setting up interrupt vectors, setting */
/* up a periodic timer interrupt source, saving the system stack */
/* pointer for use in ISR processing later, and finding the first */
/* available RAM memory address for tx_application_define. */
/* */
/* INPUT */
/* */
/* None */
/* */
/* OUTPUT */
/* */
/* None */
/* */
/* CALLS */
/* */
/* None */
/* */
/* CALLED BY */
/* */
/* _tx_initialize_kernel_enter ThreadX entry function */
/* */
/* RELEASE HISTORY */
/* */
/* DATE NAME DESCRIPTION */
/* */
/* 03-08-2023 Scott Larson Initial Version 6.2.1 */
/* */
/**************************************************************************/
/* VOID _tx_initialize_low_level(VOID)
{ */
.global _tx_initialize_low_level
.weak _tx_initialize_low_level
.extern _end
.extern board_init
_tx_initialize_low_level:
sd sp, _tx_thread_system_stack_ptr, t0 // Save system stack pointer
la t0, _end // Pickup first free address
sd t0, _tx_initialize_unused_memory, t1 // Save unused memory address
li t0, MSTATUS_MIE
csrrc zero, mstatus, t0 // clear MSTATUS_MIE bit
li t0, (MSTATUS_MPP_M | MSTATUS_MPIE )
csrrs zero, mstatus, t0 // set MSTATUS_MPP, MPIE bit
li t0, (MIE_MTIE | MIE_MSIE | MIE_MEIE)
csrrs zero, mie, t0 // set mie
#ifdef __riscv_flen
li t0, MSTATUS_FS
csrrs zero, mstatus, t0 // set MSTATUS_FS bit to open f/d isa in riscv
fscsr x0
#endif
addi sp, sp, -8
sd ra, 0(sp)
call board_init
ld ra, 0(sp)
addi sp, sp, 8
la t0, trap_entry
csrw mtvec, t0
ret
@@ -0,0 +1,100 @@
#include "uart.h"
#include "csr.h"
#include "plic.h"
#include <stdint.h>
// the UART control registers are memory-mapped
// at address UART0. this macro returns the
// address of one of the registers.
#define Reg(reg) ((volatile unsigned char *)(UART0 + (reg)))
// the UART control registers.
// some have different meanings for
// read vs write.
// see http://byterunner.com/16550.html
#define RHR 0 // receive holding register (for input bytes)
#define THR 0 // transmit holding register (for output bytes)
#define IER 1 // interrupt enable register
#define IER_RX_ENABLE (1<<0)
#define IER_TX_ENABLE (1<<1)
#define FCR 2 // FIFO control register
#define FCR_FIFO_ENABLE (1<<0)
#define FCR_FIFO_CLEAR (3<<1) // clear the content of the two FIFOs
#define ISR 2 // interrupt status register
#define LCR 3 // line control register
#define LCR_EIGHT_BITS (3<<0)
#define LCR_BAUD_LATCH (1<<7) // special mode to set baud rate
#define LSR 5 // line status register
#define LSR_RX_READY (1<<0) // input is waiting to be read from RHR
#define LSR_TX_IDLE (1<<5) // THR can accept another character to send
#define ReadReg(reg) (*(Reg(reg)))
#define WriteReg(reg, v) (*(Reg(reg)) = (v))
int uart_init(void)
{
// disable interrupts.
WriteReg(IER, 0x00);
// special mode to set baud rate.
WriteReg(LCR, LCR_BAUD_LATCH);
// LSB for baud rate of 38.4K.
WriteReg(0, 0x03);
// MSB for baud rate of 38.4K.
WriteReg(1, 0x00);
// leave set-baud mode,
// and set word length to 8 bits, no parity.
WriteReg(LCR, LCR_EIGHT_BITS);
// reset and enable FIFOs.
WriteReg(FCR, FCR_FIFO_ENABLE | FCR_FIFO_CLEAR);
// enable transmit and receive interrupts.
// WriteReg(IER, IER_TX_ENABLE | IER_RX_ENABLE);
//enable UART0 in PLIC
plic_irq_enable(UART0_IRQ);
//set UART0 priority in PLIC
plic_prio_set(UART0_IRQ, 1);
//register callback for UART0
//plic_register_callback(UART0_IRQ, uart_intr);
puts("[UART0] : Uart Init Done, this is Test output!");
return 0;
}
static inline void uart_putc_nolock(int ch)
{
// wait for Transmit Holding Empty to be set in LSR.
while((ReadReg(LSR) & LSR_TX_IDLE) == 0)
;
WriteReg(THR, ch);
return;
}
int uart_putc(int ch)
{
int intr_enable = riscv_mintr_get();
riscv_mintr_off();
uart_putc_nolock(ch);
riscv_mintr_restore(intr_enable);
return 1;
}
int uart_puts(const char* str)
{
int i;
int intr_enable = riscv_mintr_get();
riscv_mintr_off();
for(i=0;str[i]!=0;i++)
{
uart_putc_nolock(str[i]);
}
uart_putc_nolock('\n');
riscv_mintr_restore(intr_enable);
return i;
}
@@ -0,0 +1,21 @@
/***************************************************************************
* Copyright (c) 2024 Microsoft Corporation
*
* This program and the accompanying materials are made available under the
* terms of the MIT License which is available at
* https://opensource.org/licenses/MIT.
*
* SPDX-License-Identifier: MIT
**************************************************************************/
#ifndef RISCV_UART_H
#define RISCV_UART_H
#define UART0 0x10000000L
#define UART0_IRQ 10
#define puts uart_puts
int uart_init(void);
int uart_putc(int ch);
int uart_puts(const char* str);
#endif
@@ -69,6 +69,7 @@ __tx_free_memory_start:
/* VOID _tx_initialize_low_level(VOID)
{ */
.global _tx_initialize_low_level
.weak _tx_initialize_low_level
_tx_initialize_low_level:
sd sp, _tx_thread_system_stack_ptr, t0 // Save system stack pointer
@@ -149,6 +149,10 @@ _tx_thread_context_restore:
LOAD t0, 30*REGBYTES(sp) // Recover mepc
csrw mepc, t0 // Setup mepc
li t0, 0x1880 // Prepare MPIP
#if defined(__riscv_float_abi_single) || defined(__riscv_float_abi_double)
li t1, 1<<13
or t0, t1, t0
#endif
csrw mstatus, t0 // Enable MPIP
LOAD x1, 28*REGBYTES(sp) // Recover RA
@@ -259,6 +263,10 @@ _tx_thread_no_preempt_restore:
LOAD t0, 240(sp) // Recover mepc
csrw mepc, t0 // Setup mepc
li t0, 0x1880 // Prepare MPIP
#if defined(__riscv_float_abi_single) || defined(__riscv_float_abi_double)
li t1, 1<<13
or t0, t1, t0
#endif
csrw mstatus, t0 // Enable MPIP
LOAD x1, 28*REGBYTES(sp) // Recover RA
@@ -201,6 +201,10 @@ _tx_thread_schedule_loop:
LOAD t0, 30*REGBYTES(sp) // Recover mepc
csrw mepc, t0 // Store mepc
li t0, 0x1880 // Prepare MPIP
#if defined(__riscv_float_abi_single) || defined(__riscv_float_abi_double)
li t1, 1<<13
or t0, t1, t0
#endif
csrw mstatus, t0 // Enable MPIP
LOAD x1, 28*REGBYTES(sp) // Recover RA