arch: qemu-rv: Add M-timer handling for BUILD_KERNEL
Summary: - In RISC-V, BUILD_KERNEL uses S-mode and to use M-mode timer we need to handle it by using OpenSBI or self-implementation. - This commit adds M-timer self-implementation for BUILD_KERNEL. Impact: - qemu-rv only Testing: - Tested with rv-virt:knsh64 on qemu-6.2 Signed-off-by: Masayuki Ishikawa <Masayuki.Ishikawa@jp.sony.com>
This commit is contained in:
parent
34b05804b0
commit
2fa872e304
@ -30,6 +30,7 @@ CHIP_CSRCS += qemu_rv_timerisr.c qemu_rv_allocateheap.c
|
|||||||
|
|
||||||
ifeq ($(CONFIG_BUILD_KERNEL),y)
|
ifeq ($(CONFIG_BUILD_KERNEL),y)
|
||||||
CHIP_CSRCS += qemu_rv_mm_init.c
|
CHIP_CSRCS += qemu_rv_mm_init.c
|
||||||
|
CMN_ASRCS += qemu_rv_exception_m.S
|
||||||
endif
|
endif
|
||||||
|
|
||||||
ifeq ($(CONFIG_MM_PGALLOC),y)
|
ifeq ($(CONFIG_MM_PGALLOC),y)
|
||||||
|
105
arch/risc-v/src/qemu-rv/qemu_rv_exception_m.S
Normal file
105
arch/risc-v/src/qemu-rv/qemu_rv_exception_m.S
Normal file
@ -0,0 +1,105 @@
|
|||||||
|
/****************************************************************************
|
||||||
|
* arch/risc-v/src/qemu-rv/qemu_rv_exception_m.S
|
||||||
|
*
|
||||||
|
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||||
|
* contributor license agreements. See the NOTICE file distributed with
|
||||||
|
* this work for additional information regarding copyright ownership. The
|
||||||
|
* ASF licenses this file to you under the Apache License, Version 2.0 (the
|
||||||
|
* "License"); you may not use this file except in compliance with the
|
||||||
|
* License. You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||||
|
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||||
|
* License for the specific language governing permissions and limitations
|
||||||
|
* under the License.
|
||||||
|
*
|
||||||
|
****************************************************************************/
|
||||||
|
|
||||||
|
/****************************************************************************
|
||||||
|
* Included Files
|
||||||
|
****************************************************************************/
|
||||||
|
|
||||||
|
#include <nuttx/config.h>
|
||||||
|
|
||||||
|
#include <arch/arch.h>
|
||||||
|
#include <arch/irq.h>
|
||||||
|
#include <arch/mode.h>
|
||||||
|
|
||||||
|
#include <sys/types.h>
|
||||||
|
|
||||||
|
#include "chip.h"
|
||||||
|
|
||||||
|
#include "riscv_macros.S"
|
||||||
|
|
||||||
|
/****************************************************************************
|
||||||
|
* Pre-processor Definitions
|
||||||
|
****************************************************************************/
|
||||||
|
|
||||||
|
/* Provide a default section for the exeception handler. */
|
||||||
|
|
||||||
|
#ifndef EXCEPTION_SECTION
|
||||||
|
# define EXCEPTION_SECTION .text
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/****************************************************************************
|
||||||
|
* Public Symbols
|
||||||
|
****************************************************************************/
|
||||||
|
|
||||||
|
.section .text
|
||||||
|
.balign 8
|
||||||
|
.global __trap_vec_m
|
||||||
|
|
||||||
|
/****************************************************************************
|
||||||
|
* Name: __trap_vec_m
|
||||||
|
*
|
||||||
|
* Description:
|
||||||
|
* All M-mode exceptions and interrupts will be handled from here. If
|
||||||
|
* kernel is in S-mode delegated exceptions and interrupts are handled.
|
||||||
|
*
|
||||||
|
****************************************************************************/
|
||||||
|
|
||||||
|
__trap_vec_m:
|
||||||
|
j exception_m
|
||||||
|
|
||||||
|
/****************************************************************************
|
||||||
|
* Name: exception_m
|
||||||
|
*
|
||||||
|
* Description:
|
||||||
|
* Handles interrupts for m-mode
|
||||||
|
*
|
||||||
|
****************************************************************************/
|
||||||
|
|
||||||
|
.section EXCEPTION_SECTION
|
||||||
|
.global exception_m
|
||||||
|
.align 8
|
||||||
|
|
||||||
|
exception_m:
|
||||||
|
|
||||||
|
/* Swap mscratch with sp */
|
||||||
|
/* NOTE: mscratch has been set in up_mtimer_initialize() */
|
||||||
|
|
||||||
|
csrrw sp, mscratch, sp
|
||||||
|
|
||||||
|
/* Save the context */
|
||||||
|
|
||||||
|
save_ctx sp
|
||||||
|
|
||||||
|
/* Handle the mtimer interrupt */
|
||||||
|
/* NOTE: we assume exception/interrupt only happens for mtimer */
|
||||||
|
|
||||||
|
jal ra, qemu_rv_mtimer_interrupt
|
||||||
|
|
||||||
|
/* Restore the context */
|
||||||
|
|
||||||
|
load_ctx sp
|
||||||
|
|
||||||
|
/* Swap mscratch with sp */
|
||||||
|
|
||||||
|
csrrw sp, mscratch, sp
|
||||||
|
|
||||||
|
/* Return from exception */
|
||||||
|
|
||||||
|
mret
|
@ -163,6 +163,14 @@ void up_enable_irq(int irq)
|
|||||||
|
|
||||||
SET_CSR(CSR_IE, IE_TIE);
|
SET_CSR(CSR_IE, IE_TIE);
|
||||||
}
|
}
|
||||||
|
#ifdef CONFIG_BUILD_KERNEL
|
||||||
|
else if (irq == RISCV_IRQ_MTIMER)
|
||||||
|
{
|
||||||
|
/* Read m/sstatus & set timer interrupt enable in m/sie */
|
||||||
|
|
||||||
|
SET_CSR(mie, MIE_MTIE);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
else if (irq > RISCV_IRQ_EXT)
|
else if (irq > RISCV_IRQ_EXT)
|
||||||
{
|
{
|
||||||
extirq = irq - RISCV_IRQ_EXT;
|
extirq = irq - RISCV_IRQ_EXT;
|
||||||
|
@ -49,6 +49,34 @@
|
|||||||
# error "Target requires kernel in S-mode, enable CONFIG_ARCH_USE_S_MODE"
|
# error "Target requires kernel in S-mode, enable CONFIG_ARCH_USE_S_MODE"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
/****************************************************************************
|
||||||
|
* Extern Function Declarations
|
||||||
|
****************************************************************************/
|
||||||
|
|
||||||
|
#ifdef CONFIG_BUILD_KERNEL
|
||||||
|
extern void __trap_vec(void);
|
||||||
|
extern void __trap_vec_m(void);
|
||||||
|
extern void up_mtimer_initialize(void);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/****************************************************************************
|
||||||
|
* Name: qemu_rv_clear_bss
|
||||||
|
****************************************************************************/
|
||||||
|
|
||||||
|
void qemu_rv_clear_bss(void)
|
||||||
|
{
|
||||||
|
uint32_t *dest;
|
||||||
|
|
||||||
|
/* Clear .bss. We'll do this inline (vs. calling memset) just to be
|
||||||
|
* certain that there are no issues with the state of global variables.
|
||||||
|
*/
|
||||||
|
|
||||||
|
for (dest = (uint32_t *)_sbss; dest < (uint32_t *)_ebss; )
|
||||||
|
{
|
||||||
|
*dest++ = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/****************************************************************************
|
/****************************************************************************
|
||||||
* Public Data
|
* Public Data
|
||||||
****************************************************************************/
|
****************************************************************************/
|
||||||
@ -69,8 +97,6 @@ uintptr_t g_idle_topstack = QEMU_RV_IDLESTACK_TOP;
|
|||||||
|
|
||||||
void qemu_rv_start(int mhartid)
|
void qemu_rv_start(int mhartid)
|
||||||
{
|
{
|
||||||
uint32_t *dest;
|
|
||||||
|
|
||||||
/* Configure FPU */
|
/* Configure FPU */
|
||||||
|
|
||||||
riscv_fpuconfig();
|
riscv_fpuconfig();
|
||||||
@ -80,14 +106,9 @@ void qemu_rv_start(int mhartid)
|
|||||||
goto cpux;
|
goto cpux;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Clear .bss. We'll do this inline (vs. calling memset) just to be
|
#ifndef CONFIG_BUILD_KERNEL
|
||||||
* certain that there are no issues with the state of global variables.
|
qemu_rv_clear_bss();
|
||||||
*/
|
#endif
|
||||||
|
|
||||||
for (dest = (uint32_t *)_sbss; dest < (uint32_t *)_ebss; )
|
|
||||||
{
|
|
||||||
*dest++ = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
showprogress('A');
|
showprogress('A');
|
||||||
|
|
||||||
@ -99,12 +120,6 @@ void qemu_rv_start(int mhartid)
|
|||||||
|
|
||||||
/* Do board initialization */
|
/* Do board initialization */
|
||||||
|
|
||||||
#ifdef CONFIG_ARCH_USE_S_MODE
|
|
||||||
/* Initialize the per CPU areas */
|
|
||||||
|
|
||||||
riscv_percpu_add_hart(mhartid);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
showprogress('C');
|
showprogress('C');
|
||||||
|
|
||||||
#ifdef CONFIG_BUILD_KERNEL
|
#ifdef CONFIG_BUILD_KERNEL
|
||||||
@ -116,6 +131,7 @@ void qemu_rv_start(int mhartid)
|
|||||||
nx_start();
|
nx_start();
|
||||||
|
|
||||||
cpux:
|
cpux:
|
||||||
|
|
||||||
#ifdef CONFIG_SMP
|
#ifdef CONFIG_SMP
|
||||||
riscv_cpu_boot(mhartid);
|
riscv_cpu_boot(mhartid);
|
||||||
#endif
|
#endif
|
||||||
@ -126,9 +142,16 @@ cpux:
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef CONFIG_ARCH_USE_S_MODE
|
#ifdef CONFIG_BUILD_KERNEL
|
||||||
|
|
||||||
void qemu_rv_start_s(int mhartid)
|
void qemu_rv_start_s(int mhartid)
|
||||||
{
|
{
|
||||||
|
qemu_rv_clear_bss();
|
||||||
|
|
||||||
|
/* Initialize the per CPU areas */
|
||||||
|
|
||||||
|
riscv_percpu_add_hart(mhartid);
|
||||||
|
|
||||||
/* Disable MMU and enable PMP */
|
/* Disable MMU and enable PMP */
|
||||||
|
|
||||||
WRITE_CSR(satp, 0x0);
|
WRITE_CSR(satp, 0x0);
|
||||||
@ -151,13 +174,27 @@ void qemu_rv_start_s(int mhartid)
|
|||||||
|
|
||||||
/* Set the trap vector for S-mode */
|
/* Set the trap vector for S-mode */
|
||||||
|
|
||||||
extern void __trap_vec(void);
|
|
||||||
WRITE_CSR(stvec, (uintptr_t)__trap_vec);
|
WRITE_CSR(stvec, (uintptr_t)__trap_vec);
|
||||||
|
|
||||||
|
/* Set the trap vector for M-mode */
|
||||||
|
|
||||||
|
WRITE_CSR(mtvec, (uintptr_t)__trap_vec_m);
|
||||||
|
|
||||||
|
/* Initialize mtimer before entering to S-mode */
|
||||||
|
|
||||||
|
up_mtimer_initialize();
|
||||||
|
|
||||||
/* Set mepc to the entry */
|
/* Set mepc to the entry */
|
||||||
|
|
||||||
WRITE_CSR(mepc, (uintptr_t)qemu_rv_start);
|
WRITE_CSR(mepc, (uintptr_t)qemu_rv_start);
|
||||||
asm volatile("mret");
|
|
||||||
|
/* Set a0 to mhartid explicitly and enter to S-mode */
|
||||||
|
|
||||||
|
asm volatile (
|
||||||
|
"mv a0, %0 \n"
|
||||||
|
"mret \n"
|
||||||
|
:: "r" (mhartid)
|
||||||
|
);
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
@ -37,6 +37,7 @@
|
|||||||
|
|
||||||
#include "riscv_internal.h"
|
#include "riscv_internal.h"
|
||||||
#include "riscv_mtimer.h"
|
#include "riscv_mtimer.h"
|
||||||
|
#include "riscv_percpu.h"
|
||||||
#include "hardware/qemu_rv_memorymap.h"
|
#include "hardware/qemu_rv_memorymap.h"
|
||||||
#include "hardware/qemu_rv_clint.h"
|
#include "hardware/qemu_rv_clint.h"
|
||||||
|
|
||||||
@ -45,6 +46,55 @@
|
|||||||
****************************************************************************/
|
****************************************************************************/
|
||||||
|
|
||||||
#define MTIMER_FREQ 10000000
|
#define MTIMER_FREQ 10000000
|
||||||
|
#define TICK_COUNT (10000000 / TICK_PER_SEC)
|
||||||
|
|
||||||
|
/****************************************************************************
|
||||||
|
* Private Functions
|
||||||
|
****************************************************************************/
|
||||||
|
|
||||||
|
#ifdef CONFIG_BUILD_KERNEL
|
||||||
|
|
||||||
|
/****************************************************************************
|
||||||
|
* Name: qemu_rv_ssoft_interrupt
|
||||||
|
*
|
||||||
|
* Description:
|
||||||
|
* This function is S-mode software interrupt handler to proceed
|
||||||
|
* the OS timer
|
||||||
|
*
|
||||||
|
****************************************************************************/
|
||||||
|
|
||||||
|
static int qemu_rv_ssoft_interrupt(int irq, void *context, void *arg)
|
||||||
|
{
|
||||||
|
/* Cleaer Supervisor Software Interrupt */
|
||||||
|
|
||||||
|
CLEAR_CSR(sip, SIP_SSIP);
|
||||||
|
|
||||||
|
/* Proceed the OS timer */
|
||||||
|
|
||||||
|
nxsched_process_timer();
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/****************************************************************************
|
||||||
|
* Name: qemu_rv_reload_mtimecmp
|
||||||
|
*
|
||||||
|
* Description:
|
||||||
|
* This function is called during start-up to initialize mtimecmp
|
||||||
|
* for CONFIG_BUILD_KERNEL=y
|
||||||
|
*
|
||||||
|
****************************************************************************/
|
||||||
|
|
||||||
|
static void qemu_rv_reload_mtimecmp(void)
|
||||||
|
{
|
||||||
|
uint64_t current;
|
||||||
|
uint64_t next;
|
||||||
|
|
||||||
|
current = READ_CSR(time);
|
||||||
|
next = current + TICK_COUNT;
|
||||||
|
putreg64(next, QEMU_RV_CLINT_MTIMECMP);
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif /* CONFIG_BUILD_KERNEL */
|
||||||
|
|
||||||
/****************************************************************************
|
/****************************************************************************
|
||||||
* Public Functions
|
* Public Functions
|
||||||
@ -69,5 +119,64 @@ void up_timer_initialize(void)
|
|||||||
DEBUGASSERT(lower);
|
DEBUGASSERT(lower);
|
||||||
|
|
||||||
up_alarm_set_lowerhalf(lower);
|
up_alarm_set_lowerhalf(lower);
|
||||||
|
#else
|
||||||
|
/* NOTE: This function is called in S-mode */
|
||||||
|
|
||||||
|
irq_attach(RISCV_IRQ_SSOFT, qemu_rv_ssoft_interrupt, NULL);
|
||||||
|
up_enable_irq(RISCV_IRQ_SSOFT);
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef CONFIG_BUILD_KERNEL
|
||||||
|
|
||||||
|
/****************************************************************************
|
||||||
|
* Name: up_mtimer_initialize
|
||||||
|
*
|
||||||
|
* Description:
|
||||||
|
* This function is called during start-up to initialize the M-mode timer
|
||||||
|
*
|
||||||
|
****************************************************************************/
|
||||||
|
|
||||||
|
void up_mtimer_initialize(void)
|
||||||
|
{
|
||||||
|
uintptr_t irqstacktop = riscv_percpu_get_irqstack();
|
||||||
|
|
||||||
|
/* Set the irq stack base to mscratch */
|
||||||
|
|
||||||
|
WRITE_CSR(mscratch,
|
||||||
|
irqstacktop - STACK_ALIGN_DOWN(CONFIG_ARCH_INTERRUPTSTACK));
|
||||||
|
|
||||||
|
/* NOTE: we do not attach a handler for mtimer,
|
||||||
|
* because it is handled in the exception_m directly
|
||||||
|
*/
|
||||||
|
|
||||||
|
up_enable_irq(RISCV_IRQ_MTIMER);
|
||||||
|
qemu_rv_reload_mtimecmp();
|
||||||
|
}
|
||||||
|
|
||||||
|
/****************************************************************************
|
||||||
|
* Name: qemu_rv_mtimer_interrupt
|
||||||
|
*
|
||||||
|
* Description:
|
||||||
|
* In RISC-V with S-mode, M-mode timer must be handled in M-mode
|
||||||
|
* This function is called from exception_m in M-mode directly
|
||||||
|
*
|
||||||
|
****************************************************************************/
|
||||||
|
|
||||||
|
void qemu_rv_mtimer_interrupt(void)
|
||||||
|
{
|
||||||
|
uint64_t current;
|
||||||
|
uint64_t next;
|
||||||
|
|
||||||
|
/* Update mtimercmp */
|
||||||
|
|
||||||
|
current = getreg64(QEMU_RV_CLINT_MTIMECMP);
|
||||||
|
next = current + TICK_COUNT;
|
||||||
|
putreg64(next, QEMU_RV_CLINT_MTIMECMP);
|
||||||
|
|
||||||
|
/* Post Supervisor Software Interrupt */
|
||||||
|
|
||||||
|
SET_CSR(sip, SIP_SSIP);
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif /* CONFIG_BUILD_KERNEL */
|
||||||
|
Loading…
Reference in New Issue
Block a user