* arch/risc-v/src/common/riscv_internal.h
*
* 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.
*
****************************************************************************/
#ifndef __ARCH_RISCV_SRC_COMMON_RISCV_INTERNAL_H
#define __ARCH_RISCV_SRC_COMMON_RISCV_INTERNAL_H
* Included Files
****************************************************************************/
#include <nuttx/config.h>
#ifndef __ASSEMBLY__
# include <nuttx/compiler.h>
# include <nuttx/sched.h>
# include <sys/types.h>
# include <stdint.h>
# include <syscall.h>
#endif
#include <nuttx/irq.h>
#include "riscv_common_memorymap.h"
* Pre-processor Definitions
****************************************************************************/
#if defined(CONFIG_ARCH_QPFPU)
# define FLOAD __STR(flq)
# define FSTORE __STR(fsq)
#elif defined(CONFIG_ARCH_DPFPU)
# define FLOAD __STR(fld)
# define FSTORE __STR(fsd)
#else
# define FLOAD __STR(flw)
# define FSTORE __STR(fsw)
#endif
#ifdef CONFIG_ARCH_RV32
# define REGLOAD __STR(lw)
# define REGSTORE __STR(sw)
#else
# define REGLOAD __STR(ld)
# define REGSTORE __STR(sd)
#endif
* logic.
*/
#define STACK_COLOR 0xdeadbeef
#define HEAP_COLOR 'h'
#define STACK_FRAME_SIZE __XSTR(STACKFRAME_ALIGN)
#define INT_STACK_SIZE (STACKFRAME_ALIGN_DOWN(CONFIG_ARCH_INTERRUPTSTACK))
* and no other console device is specified, then a serial console is
* assumed.
*/
#ifndef CONFIG_DEV_CONSOLE
# undef USE_SERIALDRIVER
# undef USE_EARLYSERIALINIT
#else
# if defined(CONFIG_CONSOLE_SYSLOG)
# undef USE_SERIALDRIVER
# undef USE_EARLYSERIALINIT
# else
# define USE_SERIALDRIVER 1
# define USE_EARLYSERIALINIT 1
# endif
#endif
#define PMP_ACCESS_OFF (0)
#define PMP_ACCESS_DENIED (-1)
#define PMP_ACCESS_FULL (1)
#ifndef __ASSEMBLY__
static inline uint8_t getreg8(const volatile uintreg_t a)
{
uint8_t v;
__asm__ __volatile__("lb %0, 0(%1)" : "=r" (v) : "r" (a));
return v;
}
static inline void putreg8(uint8_t v, const volatile uintreg_t a)
{
__asm__ __volatile__("sb %0, 0(%1)" : : "r" (v), "r" (a));
}
static inline uint16_t getreg16(const volatile uintreg_t a)
{
uint16_t v;
__asm__ __volatile__("lh %0, 0(%1)" : "=r" (v) : "r" (a));
return v;
}
static inline void putreg16(uint16_t v, const volatile uintreg_t a)
{
__asm__ __volatile__("sh %0, 0(%1)" : : "r" (v), "r" (a));
}
static inline uint32_t getreg32(const volatile uintreg_t a)
{
uint32_t v;
__asm__ __volatile__("lw %0, 0(%1)" : "=r" (v) : "r" (a));
return v;
}
static inline void putreg32(uint32_t v, const volatile uintreg_t a)
{
__asm__ __volatile__("sw %0, 0(%1)" : : "r" (v), "r" (a));
}
static inline uint64_t getreg64(const volatile uintreg_t a)
{
uint64_t v;
__asm__ __volatile__("ld %0, 0(%1)" : "=r" (v) : "r" (a));
return v;
}
static inline void putreg64(uint64_t v, const volatile uintreg_t a)
{
__asm__ __volatile__("sd %0, 0(%1)" : : "r" (v), "r" (a));
}
#define riscv_append_pmp_region(a, b, s) \
riscv_config_pmp_region(riscv_next_free_pmp_region(), a, b, s)
#endif
* Public Types
****************************************************************************/
#undef EXTERN
#if defined(__cplusplus)
#define EXTERN extern "C"
extern "C"
{
#else
#define EXTERN extern
#endif
* Public Function Prototypes
***************************************************************************/
#ifndef __ASSEMBLY__
void modifyreg32(uintreg_t addr, uint32_t clearbits, uint32_t setbits);
#if CONFIG_MM_REGIONS > 1
void riscv_addregion(void);
#else
# define riscv_addregion()
#endif
void riscv_ack_irq(int irq);
void riscv_sigdeliver(void);
int riscv_swint(int irq, void *context, void *arg);
uintptr_t riscv_get_newintctx(void);
void riscv_set_idleintctx(void);
void riscv_exception_attach(void);
#ifdef CONFIG_ARCH_FPU
void riscv_fpuconfig(void);
void riscv_savefpu(uintreg_t *regs, uintreg_t *fregs);
void riscv_restorefpu(uintreg_t *regs, uintreg_t *fregs);
static inline uintreg_t *riscv_fpuregs(struct tcb_s *tcb)
{
#ifdef CONFIG_ARCH_LAZYFPU
return tcb->xcp.fregs;
#else
return (uintreg_t *)((uintptr_t)tcb->xcp.regs + INT_XCPT_SIZE);
#endif
}
#else
# define riscv_fpuconfig()
# define riscv_savefpu(regs, fregs)
# define riscv_restorefpu(regs, fregs)
# define riscv_fpuregs(tcb)
#endif
#ifdef CONFIG_ARCH_RV_ISA_V
void riscv_vpuconfig(void);
void riscv_savevpu(uintptr_t *regs, uintptr_t *vregs);
void riscv_restorevpu(uintptr_t *regs, uintptr_t *vregs);
static inline uintptr_t *riscv_vpuregs(struct tcb_s *tcb)
{
return tcb->xcp.vregs;
}
#else
# define riscv_vpuconfig()
# define riscv_savevpu(regs, vregs)
# define riscv_restorevpu(regs, vregs)
# define riscv_vpuregs(tcb)
#endif
static inline void riscv_savecontext(struct tcb_s *tcb)
{
#ifdef CONFIG_ARCH_FPU
riscv_savefpu(tcb->xcp.regs, riscv_fpuregs(tcb));
#endif
#ifdef CONFIG_ARCH_RV_ISA_V
riscv_savevpu(tcb->xcp.regs, riscv_vpuregs(tcb));
#endif
}
static inline void riscv_restorecontext(struct tcb_s *tcb)
{
#ifdef CONFIG_ARCH_FPU
riscv_restorefpu(tcb->xcp.regs, riscv_fpuregs(tcb));
#endif
#ifdef CONFIG_ARCH_RV_ISA_V
riscv_restorevpu(tcb->xcp.regs, riscv_vpuregs(tcb));
#endif
}
#ifdef CONFIG_ARCH_RISCV_INTXCPT_EXTENSIONS
void riscv_initial_extctx_state(struct tcb_s *tcb);
#endif
int riscv_config_pmp_region(uintptr_t region, uintptr_t attr,
uintptr_t base, uintptr_t size);
int riscv_check_pmp_access(uintptr_t attr, uintptr_t base, uintptr_t size);
int riscv_configured_pmp_regions(void);
int riscv_next_free_pmp_region(void);
#ifdef CONFIG_PM
void riscv_pminitialize(void);
#else
# define riscv_pminitialize()
#endif
#ifdef CONFIG_ARCH_DMA
void weak_function riscv_dma_initialize(void);
#endif
void riscv_lowputc(char ch);
void riscv_lowputs(const char *str);
#ifdef USE_SERIALDRIVER
void riscv_serialinit(void);
#endif
#ifdef USE_EARLYSERIALINIT
void riscv_earlyserialinit(void);
#endif
* implementations, or chip/xyx_ethernet.c for chip-specific Ethernet
* implementations.
*/
#if defined(CONFIG_NET) && !defined(CONFIG_NETDEV_LATEINIT)
void riscv_netinitialize(void);
#else
# define riscv_netinitialize()
#endif
uintreg_t *riscv_doirq(int irq, uintreg_t *regs);
int riscv_exception(int mcause, void *regs, void *args);
int riscv_fillpage(int mcause, void *regs, void *args);
int riscv_misaligned(int irq, void *context, void *arg);
#ifdef CONFIG_STACK_COLORATION
size_t riscv_stack_check(uintptr_t alloc, size_t size);
void riscv_stack_color(void *stackbase, size_t nbytes);
#endif
#if defined(CONFIG_STACK_COLORATION) && \
defined(CONFIG_ARCH_INTERRUPTSTACK) && CONFIG_ARCH_INTERRUPTSTACK > 15
void riscv_color_intstack(void);
#else
# define riscv_color_intstack()
#endif
#ifdef CONFIG_SMP
void riscv_cpu_boot(int cpu);
int riscv_smp_call_handler(int irq, void *c, void *arg);
#endif
* Name: riscv_mhartid
*
* Description:
* Context aware way to query hart id (physical core ID)
*
* The function riscv_mhartid is designed to retrieve the hardware thread
* ID (hartid) in different execution modes of RISC-V. Its behavior depends
* on the configuration and execution mode:
*
* - In machine mode, riscv_mhartid reads directly from the CSR mhartid.
* - In supervisor mode, the hartid is stored in the percpu structure
* during boot because supervisor mode does not have access to CSR
* `shartid`. The SBI (Supervisor Binary Interface) provides the hartid
* in the a0 register (as per SBI ABI requirements), and it is the
* responsibility of the payload OS to store this value internally.
* We use the percpu scratch register for this purpose, as it is the only
* location that is unique for each CPU and non-volatile.
*
* Note: In flat (machine) mode, you could still read the hartid from CSR
* mhartid even if CONFIG_RISCV_PERCPU_SCRATCH is enabled.
*
* Returned Value:
* Hart id
*
****************************************************************************/
uintptr_t riscv_mhartid(void);
#ifdef CONFIG_ARCH_RV_CPUID_MAP
* Name: riscv_hartid_to_cpuid / riscv_cpuid_to_hartid
*
* Description:
* CPU ID mapping functions for systems where physical hart IDs don't match
* logical CPU IDs.
*
****************************************************************************/
int riscv_hartid_to_cpuid(int hart);
int riscv_cpuid_to_hartid(int cpu);
#else
#define riscv_hartid_to_cpuid(hart) (hart)
#define riscv_cpuid_to_hartid(cpu) (cpu)
#endif
#ifdef CONFIG_ARCH_USE_S_MODE
void *riscv_perform_syscall(uintreg_t *regs);
#endif
void riscv_jump_to_user(uintptr_t entry, uintreg_t a0, uintreg_t a1,
uintreg_t a2, uintreg_t sp,
uintreg_t *regs) noreturn_function;
* Name: riscv_fullcontextrestore
*
* Description:
* Restores the full context.
*
* Returned Value:
* None
*
****************************************************************************/
#define riscv_fullcontextrestore() \
do \
{ \
sys_call0(SYS_restore_context); \
} \
while (1)
* Name: riscv_switchcontext
*
* Description:
* Switches the context.
*
* Returned Value:
* None
*
****************************************************************************/
#define riscv_switchcontext() \
do \
{ \
sys_call0(SYS_switch_context); \
} \
while (0)
#undef EXTERN
#ifdef __cplusplus
}
#endif
#endif
#endif