diff --git a/Documentation/platforms/risc-v/litex/cores/vexriscv/index.rst b/Documentation/platforms/risc-v/litex/cores/vexriscv/index.rst new file mode 100644 index 00000000000..ec6306c2c20 --- /dev/null +++ b/Documentation/platforms/risc-v/litex/cores/vexriscv/index.rst @@ -0,0 +1,35 @@ +============= +Vexriscv Core +============= + +The vexriscv core only supports standard "Flat builds", consisting of a single binary. + +Building +-------- + +Build the minimal NSH application:: + + # Configure for NSH + $ ./tools/configure.sh arty_a7:nsh + + # Build Nuttx + $ make + + +Booting +-------- + +Create a file, 'boot.json' in the Nuttx root directory, with the following content:: + + { + "nuttx.bin": "0x40000000" + } + +Load the application over serial with:: + + $ litex_term --images=boot.json --speed=1e6 /dev/ttyUSB0 + +Update the baud rate and serial port to suit your configuration. + + + diff --git a/Documentation/platforms/risc-v/litex/cores/vexriscv_smp/index.rst b/Documentation/platforms/risc-v/litex/cores/vexriscv_smp/index.rst new file mode 100644 index 00000000000..aa515c9781e --- /dev/null +++ b/Documentation/platforms/risc-v/litex/cores/vexriscv_smp/index.rst @@ -0,0 +1,55 @@ +================== +VexRISCV_SMP Core +================== + +The vexrisc_smp core supports a two-pass build, producing the kernel (nuttx.bin), and a number of applications, +compiled into the apps/bin directory. In the standard configuration, the applications are loaded to the FPGA in a RAMdisk. +Although, for custom boards this could be extended to loading from SDCards, flash, or other mediums. + +Building +-------- + +Nuttx uses openSBI to configure and prepare the vexriscv_smp core. With this configuration, +the Nuttx kernel is a binary payload for OpenSBI. The configuration used is +identical to that used for Linux on Litex project (https://github.com/litex-hub/linux-on-litex-vexriscv). + +To build OpenSBI:: + + $ git clone https://github.com/litex-hub/opensbi --branch 0.8-linux-on-litex-vexriscv + $ cd opensbi + $ make CROSS_COMPILE=riscv64-unknown-elf- PLATFORM=litex/vexriscv + $ cp build/platform/litex/vexriscv/firmware/fw_jump.bin ../opensbi.bin" + +Build the Nuttx kernel:: + + $ ./tools/configure.sh arty_a7:knsh + $ make + +Build the loadable applications:: + + $ make export -j16 + $ cd ../apps + $ make ./tools/mkimport.sh -z -x ../nuttx/nuttx-export-*.tar.gz + $ make import + +Generate a romfs to be loaded to the FPGA as a ramdisk:: + + $ cd nuttx + $ genromfs -f romfs.img -d ../apps/bin -V "NuttXBootVol" + +Booting +-------- + +Create a file, 'boot.json' in the Nuttx root directory, with the following content:: + + { + "romfs.img": "0x40C00000", + "nuttx.bin": "0x40000000", + "opensbi.bin": "0x40f00000" + } + +Load the application over serial with:: + + litex_term --images=boot.json --speed=1e6 /dev/ttyUSB0 + +Update the baud rate and serial port to suit your configuration. \ No newline at end of file diff --git a/Documentation/platforms/risc-v/litex/index.rst b/Documentation/platforms/risc-v/litex/index.rst new file mode 100644 index 00000000000..f5dc565a561 --- /dev/null +++ b/Documentation/platforms/risc-v/litex/index.rst @@ -0,0 +1,70 @@ +====================================== +Enjoy Digital LiteX FPGA's +====================================== + +The LiteX framework provides a convenient and efficient infrastructure to create FPGA Cores/SoCs, to explore various digital design architectures and create full FPGA based systems. + +Information specific to Litex and supported boards can be found on the project's homepage: https://github.com/enjoy-digital/litex + +Nuttx has basic support for two softcores + + - vexriscv: FPGA friendly RISC-V ISA CPU implementation + - vexriscv_smp: A more fully featured, Linux compatible core. + +Currently, the only configured development board in the Arty A7 https://digilent.com/reference/programmable-logic/arty-a7/start. However, many Litex supported boards +should work with either core, requiring minimal adjustment to the configuration. + + +Toolchain +============== + +Litex projects can be built with a generic RISC-V GCC toolchain. There are currently two options. + +Prebuilt toolchain +------------------ + +A prebuilt RISC-V toolchain from SiFive can be used to build Litex projects:: + + # Download the prebuilt toolchain + $ curl https://static.dev.sifive.com/dev-tools/riscv64-unknown-elf-gcc-8.3.0-2019.08.0-x86_64-linux-ubuntu14.tar.gz \ + > riscv64-unknown-elf-gcc.tar.gz + + # Unpack the archive + $ tar -xf riscv64-unknown-elf-gcc.tar.gz + + # Add to path + $ export PATH="$HOME/path/to/riscv64-unknown-elf-gcc-8.3.0-2019.08.0-x86_64-linux-ubuntu14/bin:$PATH + +Custom built toolchain +---------------------- + +The toolchain needs to be compiled locally in order to use a more modern version. At the time of writing, +the source can be obtained from https://github.com/riscv-collab/riscv-gnu-toolchain and built with the following configuration:: + + $ CFLAGS="-g0 -Os" + $ CXXFLAGS="-g0 -Os" + $ LDFLAGS="-s" + + $ ./configure \ + CFLAGS_FOR_TARGET='-O2 -mcmodel=medany' \ + CXXFLAGS_FOR_TARGET='-O2 -mcmodel=medany' \ + --prefix=path/to/install/to \ + --with-system-zlib \ + --with-arch=rv32ima \ + --with-abi=ilp32 + + $ make + +.. important:: The vexriscv_smp core requires `with-arch=rv32imac`. + +Check the linked github repository for other options, including building with multilib enabled. + +Core specific information +========================= + +.. toctree:: + :glob: + :maxdepth: 1 + + cores/*/* + diff --git a/arch/risc-v/Kconfig b/arch/risc-v/Kconfig index f11df414bb6..422c61f88a9 100644 --- a/arch/risc-v/Kconfig +++ b/arch/risc-v/Kconfig @@ -354,6 +354,29 @@ config RISCV_SEMIHOSTING_HOSTFS_CACHE_COHERENCE endif +if ARCH_CHIP_LITEX + +choice + prompt "LITEX Core Selection" + default LITEX_CORE_VEXRISCV + +config LITEX_CORE_VEXRISCV + bool "vexriscv core" + +config LITEX_CORE_VEXRISCV_SMP + bool "vexriscv_smp core" + select ARCH_HAVE_MPU + select ARCH_HAVE_MMU + select ARCH_RV_ISA_C + select ARCH_MMU_TYPE_SV32 + select ARCH_HAVE_ADDRENV + select ARCH_NEED_ADDRENV_MAPPING + select ARCH_HAVE_S_MODE + +endchoice + +endif + source "arch/risc-v/src/opensbi/Kconfig" if ARCH_CHIP_FE310 diff --git a/arch/risc-v/include/litex/irq.h b/arch/risc-v/include/litex/irq.h index 652d9e870cc..27910562d39 100644 --- a/arch/risc-v/include/litex/irq.h +++ b/arch/risc-v/include/litex/irq.h @@ -29,17 +29,19 @@ #include CONFIG_LITEX_CUSTOM_IRQ_DEFINITIONS_PATH #else +#include + /**************************************************************************** * Pre-processor Definitions ****************************************************************************/ /* Map RISC-V exception code to NuttX IRQ */ -#define LITEX_IRQ_UART0 (RISCV_IRQ_MEXT + 1) -#define LITEX_IRQ_TIMER0 (RISCV_IRQ_MEXT + 2) -#define LITEX_IRQ_ETHMAC (RISCV_IRQ_MEXT + 3) -#define LITEX_IRQ_SDCARD (RISCV_IRQ_MEXT + 4) -#define LITEX_IRQ_GPIO (RISCV_IRQ_MEXT + 5) +#define LITEX_IRQ_UART0 (RISCV_IRQ_EXT + 1) +#define LITEX_IRQ_TIMER0 (RISCV_IRQ_EXT + 2) +#define LITEX_IRQ_ETHMAC (RISCV_IRQ_EXT + 3) +#define LITEX_IRQ_SDCARD (RISCV_IRQ_EXT + 4) +#define LITEX_IRQ_GPIO (RISCV_IRQ_EXT + 5) /* The last hardware IRQ number */ diff --git a/arch/risc-v/src/litex/Kconfig b/arch/risc-v/src/litex/Kconfig index a388a8cec11..09c4526edfb 100644 --- a/arch/risc-v/src/litex/Kconfig +++ b/arch/risc-v/src/litex/Kconfig @@ -148,3 +148,32 @@ config LITEX_EMAC_PHYADDR The 5-bit address of the PHY on the board. Default: 1 endmenu # PHY interface + +menu "LITEX MMU options" + depends on ARCH_USE_MMU + +config LITEX_MMU_IO_BASE + hex "IO base address." + default 0x80000000 + ---help--- + The base address for the IO MMU mapping. + +config LITEX_MMU_IO_SIZE + hex "IO base address." + default 0x7F000000 + ---help--- + The size for the IO MMU mapping. + +config LITEX_MMU_L1_SIZE + int "L1 page table size." + default 1024 + ---help--- + The size of the L1 page table. Each entry in the page table represents a 4MB L1 page. + +config LITEX_MMU_L2_SIZE + int "L2 page table size." + default 4096 + ---help--- + The size of the L2 page table. Each entry in the page table represents a 4kB L1 page. + +endmenu # LITEX MMU options diff --git a/arch/risc-v/src/litex/Make.defs b/arch/risc-v/src/litex/Make.defs index f6b5c3ac035..2760dffa3ec 100644 --- a/arch/risc-v/src/litex/Make.defs +++ b/arch/risc-v/src/litex/Make.defs @@ -22,7 +22,11 @@ include common/Make.defs # Specify our HEAD assembly file. This will be linked as # the first object file, so it will appear at address 0 +ifeq ($(CONFIG_LITEX_CORE_VEXRISCV_SMP),y) +HEAD_ASRC = litex_shead.S +else HEAD_ASRC = litex_head.S +endif # Specify our C code within this directory to be included CHIP_CSRCS = litex_allocateheap.c litex_clockconfig.c @@ -31,6 +35,9 @@ CHIP_CSRCS += litex_lowputc.c litex_serial.c CHIP_CSRCS += litex_start.c litex_timerisr.c CHIP_ASRCS += litex_cache.S +ifeq ($(CONFIG_BUILD_KERNEL),y) +CHIP_CSRCS += litex_mm_init.c litex_pgalloc.c +endif ifeq ($(CONFIG_LITEX_GPIO),y) CHIP_CSRCS += litex_gpio.c diff --git a/arch/risc-v/src/litex/chip.h b/arch/risc-v/src/litex/chip.h index 228cda581a3..9799e31e570 100644 --- a/arch/risc-v/src/litex/chip.h +++ b/arch/risc-v/src/litex/chip.h @@ -29,4 +29,28 @@ #include "litex_memorymap.h" +#include "riscv_internal.h" +#include "riscv_percpu.h" + +#ifdef __ASSEMBLY__ + +/**************************************************************************** + * Name: setintstack + * + * Description: + * Set the current stack pointer to the "top" the correct interrupt stack. + * + ****************************************************************************/ + +#if CONFIG_ARCH_INTERRUPTSTACK > 15 +#if !defined(CONFIG_SMP) && defined(CONFIG_ARCH_USE_S_MODE) +.macro setintstack tmp0, tmp1 + csrr \tmp0, CSR_SCRATCH + REGLOAD sp, RISCV_PERCPU_IRQSTACK(\tmp0) +.endm +#endif /* !defined(CONFIG_SMP) && defined(CONFIG_ARCH_USE_S_MODE) */ +#endif /* CONFIG_ARCH_INTERRUPTSTACK > 15 */ + +#endif /* __ASSEMBLY__ */ + #endif /* __ARCH_RISCV_SRC_LITEX_CHIP_H */ diff --git a/arch/risc-v/src/litex/hardware/litex_clint.h b/arch/risc-v/src/litex/hardware/litex_clint.h index 79a95c8afc2..a141ff1a400 100644 --- a/arch/risc-v/src/litex/hardware/litex_clint.h +++ b/arch/risc-v/src/litex/hardware/litex_clint.h @@ -24,9 +24,18 @@ /**************************************************************************** * Pre-processor Definitions ****************************************************************************/ +#ifdef CONFIG_LITEX_CORE_VEXRISCV_SMP + +#define LITEX_CLINT_MSIP (LITEX_CLINT_BASE + 0x0000) +#define LITEX_CLINT_MTIMECMP (LITEX_CLINT_BASE + 0x4000) +#define LITEX_CLINT_MTIME (LITEX_CLINT_BASE + 0xbff8) + +#else #define LITEX_CLINT_LATCH (LITEX_CPUTIMER_BASE) #define LITEX_CLINT_MTIME (LITEX_CPUTIMER_BASE + 0x04) #define LITEX_CLINT_MTIMECMP (LITEX_CPUTIMER_BASE + 0x0C) +#endif /* CONFIG_LITEX_CORE_VEXRISCV_SMP */ + #endif /* __ARCH_RISCV_SRC_LITEX_HARDWARE_LITEX_CLINT_H */ diff --git a/arch/risc-v/src/litex/hardware/litex_memorymap.h b/arch/risc-v/src/litex/hardware/litex_memorymap.h index ce56347952b..fc9423e199b 100644 --- a/arch/risc-v/src/litex/hardware/litex_memorymap.h +++ b/arch/risc-v/src/litex/hardware/litex_memorymap.h @@ -35,20 +35,30 @@ /* Register Base Address ****************************************************/ -/* litex vexRiscv does not follow RISC-V privileged specification and - * uses two additional CSRs: mask and pending. - */ - -#define LITEX_CPUTIMER_BASE 0xf0000800 -#define LITEX_ETHMAC_BASE 0xf0001000 -#define LITEX_ETHPHY_BASE 0xf0001800 -#define LITEX_SDBLOCK2MEM_BASE 0xf0003000 -#define LITEX_SDCORE_BASE 0xf0003800 -#define LITEX_SDIRQ_BASE 0xf0004000 -#define LITEX_SDMEM2BLOCK_BASE 0xf0004800 -#define LITEX_SDPHY_BASE 0xf0005000 -#define LITEX_TIMER0_BASE 0xf0006000 -#define LITEX_UART0_BASE 0xf0006800 +#ifdef CONFIG_LITEX_CORE_VEXRISCV_SMP + #define LITEX_CLINT_BASE 0xf0010000 + #define LITEX_PLIC_BASE 0xf0c00000 + #define LITEX_ETHMAC_BASE 0xf0002000 + #define LITEX_ETHPHY_BASE 0xf0002800 + #define LITEX_TIMER0_BASE 0xf0001800 + #define LITEX_UART0_BASE 0xf0001000 + #define LITEX_SDBLOCK2MEM_BASE 0xf0004000 + #define LITEX_SDCORE_BASE 0xf0004800 + #define LITEX_SDIRQ_BASE 0xf0005000 + #define LITEX_SDMEM2BLOCK_BASE 0xf0005800 + #define LITEX_SDPHY_BASE 0xf0006000 +#else + #define LITEX_CPUTIMER_BASE 0xf0000800 + #define LITEX_ETHMAC_BASE 0xf0001000 + #define LITEX_ETHPHY_BASE 0xf0001800 + #define LITEX_TIMER0_BASE 0xf0006000 + #define LITEX_UART0_BASE 0xf0006800 + #define LITEX_SDBLOCK2MEM_BASE 0xf0003000 + #define LITEX_SDCORE_BASE 0xf0003800 + #define LITEX_SDIRQ_BASE 0xf0004000 + #define LITEX_SDMEM2BLOCK_BASE 0xf0004800 + #define LITEX_SDPHY_BASE 0xf0005000 +#endif /* GPIO peripheral definitions. * - LITEX_GPIO_BASE is the first 32-bit address which contains a block diff --git a/arch/risc-v/src/litex/hardware/litex_plic.h b/arch/risc-v/src/litex/hardware/litex_plic.h index bd9e1002091..f57a6e8fb57 100644 --- a/arch/risc-v/src/litex/hardware/litex_plic.h +++ b/arch/risc-v/src/litex/hardware/litex_plic.h @@ -21,14 +21,32 @@ #ifndef __ARCH_RISCV_SRC_LITEX_HARDWARE_LITEX_PLIC_H #define __ARCH_RISCV_SRC_LITEX_HARDWARE_LITEX_PLIC_H +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include "litex_memorymap.h" + /**************************************************************************** * Pre-processor Definitions ****************************************************************************/ +#ifdef CONFIG_LITEX_CORE_VEXRISCV_SMP +# define LITEX_PLIC_PRIORITY (LITEX_PLIC_BASE + 0x000000) +# define LITEX_PLIC_PENDING1 (LITEX_PLIC_BASE + 0x001000) + +# define LITEX_PLIC_ENABLE1 (LITEX_PLIC_BASE + 0x002080) +# define LITEX_PLIC_ENABLE2 (LITEX_PLIC_BASE + 0x002084) +# define LITEX_PLIC_THRESHOLD (LITEX_PLIC_BASE + 0x201000) +# define LITEX_PLIC_CLAIM (LITEX_PLIC_BASE + 0x201004) +#else + /* litex vexRiscv does not follow RISC-V privileged specification and * uses two additional CSRs: mask and pending. */ #define LITEX_MMASK_CSR 0xBC0 #define LITEX_MPENDING_CSR 0xFC0 +#endif + #endif /* __ARCH_RISCV_SRC_LITEX_HARDWARE_LITEX_PLIC_H */ diff --git a/arch/risc-v/src/litex/hardware/litex_timer.h b/arch/risc-v/src/litex/hardware/litex_timer.h new file mode 100644 index 00000000000..619311199f2 --- /dev/null +++ b/arch/risc-v/src/litex/hardware/litex_timer.h @@ -0,0 +1,58 @@ +/**************************************************************************** + * arch/risc-v/src/litex/hardware/litex_timer.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_LITEX_HARDWARE_LITEX_TIMER_H +#define __ARCH_RISCV_SRC_LITEX_HARDWARE_LITEX_TIMER_H + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include "hardware/litex_memorymap.h" + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +/* LITEX_TIMER register offsets *********************************************/ + +#define LITEX_TIMER_LOAD_OFFSET 0x0000 +#define LITEX_TIMER_RELOAD_OFFSET 0x0004 +#define LITEX_TIMER_EN_OFFSET 0x0008 +#define LITEX_TIMER_UPDATE_VALUE_OFFSET 0x000C +#define LITEX_TIMER_VALUE_OFFSET 0x0010 +#define LITEX_TIMER_EV_STATUS_OFFSET 0x0014 +#define LITEX_TIMER_EV_PENDING_OFFSET 0x0018 +#define LITEX_TIMER_EV_ENABLE_OFFSET 0x001C + +/* LITEX_TIMER register addresses *******************************************/ + +#define LITEX_TIMER0_LOAD (LITEX_TIMER0_BASE+LITEX_TIMER_LOAD_OFFSET) +#define LITEX_TIMER0_RELOAD (LITEX_TIMER0_BASE+LITEX_TIMER_RELOAD_OFFSET) +#define LITEX_TIMER0_EN (LITEX_TIMER0_BASE+LITEX_TIMER_EN_OFFSET) +#define LITEX_TIMER0_UPDATE_VALUE (LITEX_TIMER0_BASE+LITEX_TIMER_UPDATE_VALUE_OFFSET) +#define LITEX_TIMER0_VALUE (LITEX_TIMER0_BASE+LITEX_TIMER_VALUE_OFFSET) +#define LITEX_TIMER0_EV_STATUS (LITEX_TIMER0_BASE+LITEX_TIMER_EV_STATUS_OFFSET) +#define LITEX_TIMER0_EV_PENDING (LITEX_TIMER0_BASE+LITEX_TIMER_EV_PENDING_OFFSET) +#define LITEX_TIMER0_EV_ENABLE (LITEX_TIMER0_BASE+LITEX_TIMER_EV_ENABLE_OFFSET) + +/* LITEX_TIMER register bit definitions *************************************/ + +#endif /* __ARCH_RISCV_SRC_LITEX_HARDWARE_LITEX_TIMER_H */ diff --git a/arch/risc-v/src/litex/litex_allocateheap.c b/arch/risc-v/src/litex/litex_allocateheap.c index a97728e3b06..c6783d6141c 100644 --- a/arch/risc-v/src/litex/litex_allocateheap.c +++ b/arch/risc-v/src/litex/litex_allocateheap.c @@ -29,10 +29,45 @@ #include "litex.h" +#ifdef CONFIG_MM_KERNEL_HEAP +#include +#endif + +#include "riscv_internal.h" + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +#ifdef CONFIG_MM_KERNEL_HEAP +#define KRAM_END KSRAM_END +#else +#define KRAM_END CONFIG_RAM_END +#endif + /**************************************************************************** * Public Functions ****************************************************************************/ +/**************************************************************************** + * Name: up_allocate_heap + * + * Description: + * This function will be called to dynamically set aside the heap region + * based on kernel or flat builds. + * + ****************************************************************************/ + +#ifdef CONFIG_BUILD_KERNEL +void up_allocate_kheap(void **heap_start, size_t *heap_size) +#else +void up_allocate_heap(void **heap_start, size_t *heap_size) +#endif /* CONFIG_BUILD_KERNEL */ +{ + *heap_start = (void *)g_idle_topstack; + *heap_size = KRAM_END - g_idle_topstack; +} + /**************************************************************************** * Name: riscv_addregion * diff --git a/arch/risc-v/src/litex/litex_irq.c b/arch/risc-v/src/litex/litex_irq.c index d792161ea42..af59cdd1571 100644 --- a/arch/risc-v/src/litex/litex_irq.c +++ b/arch/risc-v/src/litex/litex_irq.c @@ -51,7 +51,11 @@ void up_irqinitialize(void) /* Disable all global interrupts */ +#ifdef CONFIG_ARCH_USE_S_MODE + putreg32(0x0, LITEX_PLIC_ENABLE1); +#else asm volatile ("csrw %0, %1" :: "i"(LITEX_MMASK_CSR), "r"(0)); +#endif /* Colorize the interrupt stack for debug purposes */ @@ -62,6 +66,23 @@ void up_irqinitialize(void) /* litex vexriscv dont have priority and threshold control */ +#ifdef CONFIG_LITEX_CORE_VEXRISCV_SMP + /* litex vexriscv_smp does. */ + + /* Set priority for all global interrupts to 1 (lowest) */ + + int id; + + for (id = 1; id <= 31; id++) + { + putreg32(1, (uintptr_t)(LITEX_PLIC_PRIORITY + 4 * id)); + } + + /* Set irq threshold to 0 (permits all global interrupts) */ + + putreg32(0, LITEX_PLIC_THRESHOLD); +#endif + /* Attach the common interrupt handler */ riscv_exception_attach(); @@ -82,6 +103,41 @@ void up_irqinitialize(void) * ****************************************************************************/ +#ifdef CONFIG_LITEX_CORE_VEXRISCV_SMP +void up_disable_irq(int irq) +{ + int extirq; + + if (irq == RISCV_IRQ_SOFT) + { + /* Read m/sstatus & clear machine software interrupt enable in m/sie */ + + CLEAR_CSR(CSR_IE, IE_SIE); + } + else if (irq == RISCV_IRQ_TIMER) + { + /* Read m/sstatus & clear timer interrupt enable in m/sie */ + + CLEAR_CSR(CSR_IE, IE_TIE); + } + else if (irq > RISCV_IRQ_EXT) + { + extirq = irq - RISCV_IRQ_EXT; + + /* Clear enable bit for the irq */ + + if (1 <= extirq && extirq <= 31) + { + modifyreg32(LITEX_PLIC_ENABLE1 + (4 * (extirq / 32)), + 1 << (extirq % 32), 0); + } + else + { + PANIC(); + } + } +} +#else void up_disable_irq(int irq) { int extirq; @@ -118,6 +174,7 @@ void up_disable_irq(int irq) } } } +#endif /**************************************************************************** * Name: up_enable_irq @@ -127,6 +184,41 @@ void up_disable_irq(int irq) * ****************************************************************************/ +#ifdef CONFIG_LITEX_CORE_VEXRISCV_SMP +void up_enable_irq(int irq) +{ + int extirq; + + if (irq == RISCV_IRQ_SOFT) + { + /* Read sstatus and set supervisor software interrupt enable in sie */ + + SET_CSR(CSR_IE, IE_SIE); + } + else if (irq == RISCV_IRQ_TIMER) + { + /* Read sstatus & set timer interrupt enable in sie */ + + SET_CSR(CSR_IE, IE_TIE); + } + else if (irq >= RISCV_IRQ_EXT) + { + extirq = irq - RISCV_IRQ_EXT; + + /* Set enable bit for the irq in plic */ + + if (0 <= extirq && extirq <= 31) + { + modifyreg32(LITEX_PLIC_ENABLE1 + (4 * (extirq / 32)), + 0, 1 << (extirq % 32)); + } + else + { + PANIC(); + } + } +} +#else void up_enable_irq(int irq) { int extirq; @@ -163,6 +255,7 @@ void up_enable_irq(int irq) } } } +#endif /**************************************************************************** * Name: riscv_ack_irq @@ -189,15 +282,15 @@ irqstate_t up_irq_enable(void) irqstate_t oldstat; #if 1 - /* Enable MEIE (machine external interrupt enable) */ + /* Enable EIE (machine/supervisor external interrupt enable) */ /* TODO: should move to up_enable_irq() */ - SET_CSR(mie, MIE_MEIE); + SET_CSR(CSR_IE, IE_EIE); #endif - /* Read mstatus & set machine interrupt enable (MIE) in mstatus */ + /* Read s/mstatus & set interrupt enable (S/MIE) in s/mstatus */ - oldstat = READ_AND_SET_CSR(mstatus, MSTATUS_MIE); + oldstat = READ_AND_SET_CSR(CSR_STATUS, STATUS_IE); return oldstat; } diff --git a/arch/risc-v/src/litex/litex_irq_dispatch.c b/arch/risc-v/src/litex/litex_irq_dispatch.c index 825a4f137a7..90950eecc3d 100644 --- a/arch/risc-v/src/litex/litex_irq_dispatch.c +++ b/arch/risc-v/src/litex/litex_irq_dispatch.c @@ -49,8 +49,48 @@ void *riscv_dispatch_irq(uintptr_t vector, uintptr_t *regs) { - int irq = (vector >> RV_IRQ_MASK) | (vector & 0xf); +#ifdef CONFIG_LITEX_CORE_VEXRISCV_SMP + int irq = (vector & 0x3f); + + if ((vector & RISCV_IRQ_BIT) != 0) + { + irq += RISCV_IRQ_ASYNC; + } + + /* Firstly, check if the irq is machine external interrupt */ + + if (irq == RISCV_IRQ_EXT) + { + uint32_t ext = getreg32(LITEX_PLIC_CLAIM); + + /* Add the value to nuttx irq which is offset to the ext */ + + irq = RISCV_IRQ_EXT + ext; + } + + /* Acknowledge the interrupt */ + + riscv_ack_irq(irq); + + /* EXT means no interrupt */ + + if (irq != RISCV_IRQ_EXT) + { + /* Deliver the IRQ */ + + regs = riscv_doirq(irq, regs); + } + + if (irq > RISCV_IRQ_EXT) + { + /* Then write PLIC_CLAIM to clear pending in PLIC */ + + putreg32(irq - RISCV_IRQ_EXT, LITEX_PLIC_CLAIM); + } + +#else int i; + int irq = (vector >> RV_IRQ_MASK) | (vector & 0xf); /* Firstly, check if the irq is machine external interrupt */ @@ -87,5 +127,6 @@ void *riscv_dispatch_irq(uintptr_t vector, uintptr_t *regs) regs = riscv_doirq(irq, regs); +#endif /* CONFIG_LITEX_CORE_VEXRISCV_SMP */ return regs; } diff --git a/arch/risc-v/src/litex/litex_mm_init.c b/arch/risc-v/src/litex/litex_mm_init.c new file mode 100644 index 00000000000..657aaabfda3 --- /dev/null +++ b/arch/risc-v/src/litex/litex_mm_init.c @@ -0,0 +1,263 @@ +/**************************************************************************** + * arch/risc-v/src/litex/litex_mm_init.c + * + * 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 +#include + +#include +#include +#include + +#include + +#include "litex_memorymap.h" + +#include "riscv_internal.h" +#include "riscv_mmu.h" + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +/* Map the whole I/O memory with vaddr = paddr mappings */ + +#define MMU_IO_BASE CONFIG_LITEX_MMU_IO_BASE +#define MMU_IO_SIZE CONFIG_LITEX_MMU_IO_SIZE + +#ifdef CONFIG_ARCH_MMU_TYPE_SV32 + +/* Physical and virtual addresses to page tables (vaddr = paddr mapping) */ + +#define PGT_L1_PBASE (uintptr_t)&m_l1_pgtable +#define PGT_L2_PBASE (uintptr_t)&m_l2_pgtable +#define PGT_L1_VBASE PGT_L1_PBASE +#define PGT_L2_VBASE PGT_L2_PBASE + +#define PGT_L1_SIZE (CONFIG_LITEX_MMU_L1_SIZE) +#define PGT_L2_SIZE (CONFIG_LITEX_MMU_L2_SIZE) + +#define SLAB_COUNT (sizeof(m_l2_pgtable) / RV_MMU_PAGE_SIZE) + +#define KMM_PAGE_SIZE RV_MMU_L2_PAGE_SIZE +#define KMM_PBASE PGT_L2_PBASE +#define KMM_PBASE_IDX 2 +#define KMM_SPBASE PGT_L1_PBASE +#define KMM_SPBASE_IDX 1 + +#else +#error No valid MMU defined. +#endif + +/**************************************************************************** + * Private Types + ****************************************************************************/ + +struct pgalloc_slab_s +{ + sq_entry_t *next; + void *memory; +}; +typedef struct pgalloc_slab_s pgalloc_slab_t; + +/**************************************************************************** + * Private Data + ****************************************************************************/ + +/* Kernel mappings simply here, mapping is vaddr=paddr */ + +static size_t m_l1_pgtable[PGT_L1_SIZE] locate_data(".pgtables"); +static size_t m_l2_pgtable[PGT_L2_SIZE] locate_data(".pgtables"); + +/* Kernel mappings (L1 base) */ + +uintptr_t g_kernel_mappings = PGT_L1_VBASE; +uintptr_t g_kernel_pgt_pbase = PGT_L1_PBASE; + +/* L2 page table allocator */ + +static sq_queue_t g_free_slabs; +static pgalloc_slab_t g_slabs[SLAB_COUNT]; + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: slab_init + * + * Description: + * Initialize slab allocator for L2 page table entries + * + * Input Parameters: + * start - Beginning of the L2 page table pool + * + ****************************************************************************/ + +static void slab_init(uintptr_t start) +{ + int i; + + sq_init(&g_free_slabs); + + for (i = 0; i < SLAB_COUNT; i++) + { + g_slabs[i].memory = (void *)start; + sq_addlast((sq_entry_t *)&g_slabs[i], (sq_queue_t *)&g_free_slabs); + start += RV_MMU_PAGE_SIZE; + } +} + +/**************************************************************************** + * Name: slab_alloc + * + * Description: + * Allocate single slab for L2 page table entry + * + ****************************************************************************/ + +static uintptr_t slab_alloc(void) +{ + pgalloc_slab_t *slab = (pgalloc_slab_t *)sq_remfirst(&g_free_slabs); + return slab ? (uintptr_t)slab->memory : 0; +} + +/**************************************************************************** + * Name: map_region + * + * Description: + * Map a region of physical memory to the L2 page table + * + * Input Parameters: + * paddr - Beginning of the physical address mapping + * vaddr - Beginning of the virtual address mapping + * size - Size of the region in bytes + * mmuflags - The MMU flags to use in the mapping + * + ****************************************************************************/ + +static void map_region(uintptr_t paddr, uintptr_t vaddr, size_t size, + uint32_t mmuflags) +{ + uintptr_t endaddr; + uintptr_t pbase; + int npages; + int i; + int j; + + /* How many pages */ + + npages = (size + RV_MMU_PAGE_MASK) >> RV_MMU_PAGE_SHIFT; + endaddr = vaddr + size; + + for (i = 0; i < npages; i += RV_MMU_PAGE_ENTRIES) + { + /* See if a L2 mapping exists ? */ + + pbase = mmu_pte_to_paddr(mmu_ln_getentry( + KMM_SPBASE_IDX, KMM_SPBASE, vaddr)); + if (!pbase) + { + /* No, allocate 1 page, this must not fail */ + + pbase = slab_alloc(); + DEBUGASSERT(pbase); + + /* Map it to the L2 table */ + + mmu_ln_setentry( + KMM_SPBASE_IDX, KMM_SPBASE, pbase, vaddr, MMU_UPGT_FLAGS); + } + + /* Then add the L2 mappings */ + + for (j = 0; j < RV_MMU_PAGE_ENTRIES && vaddr < endaddr; j++) + { + mmu_ln_setentry(KMM_PBASE_IDX, pbase, paddr, vaddr, mmuflags); + paddr += KMM_PAGE_SIZE; + vaddr += KMM_PAGE_SIZE; + } + } +} + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: litex_kernel_mappings + * + * Description: + * Setup kernel mappings when usinc CONFIG_BUILD_KERNEL. Sets up the kernel + * MMU mappings. + * + ****************************************************************************/ + +void litex_kernel_mappings(void) +{ + /* Initialize slab allocator for L2 page tables */ + + slab_init(KMM_PBASE); + + /* Begin mapping memory to MMU; note that at this point the MMU is not yet + * active, so the page table virtual addresses are actually physical + * addresses and so forth. M-mode does not perform translations anyhow, so + * this mapping is quite simple to do + */ + + binfo("map I/O regions\n"); + mmu_ln_map_region(1, PGT_L1_VBASE, MMU_IO_BASE, MMU_IO_BASE, + MMU_IO_SIZE, MMU_IO_FLAGS); + + /* Map the kernel text and data for L2 */ + + binfo("map kernel text\n"); + map_region(KFLASH_START, KFLASH_START, KFLASH_SIZE, MMU_KTEXT_FLAGS); + + binfo("map kernel data\n"); + map_region(KSRAM_START, KSRAM_START, KSRAM_SIZE, MMU_KDATA_FLAGS); + + binfo("map the page pool\n"); + map_region(PGPOOL_START, PGPOOL_START, PGPOOL_SIZE, MMU_KDATA_FLAGS); +} + +/**************************************************************************** + * Name: litex_mm_init + * + * Description: + * Setup kernel mappings when using CONFIG_BUILD_KERNEL. Sets up kernel MMU + * mappings. Function also sets the first address environment (satp value). + * + ****************************************************************************/ + +void litex_mm_init(void) +{ + /* Setup the kernel mappings */ + + litex_kernel_mappings(); + + /* Enable MMU (note: system is still in M-mode) */ + + binfo("mmu_enable: satp=%" PRIuPTR "\n", g_kernel_pgt_pbase); + mmu_enable(g_kernel_pgt_pbase, 0); +} diff --git a/arch/risc-v/src/litex/litex_mm_init.h b/arch/risc-v/src/litex/litex_mm_init.h new file mode 100644 index 00000000000..216a2993d3c --- /dev/null +++ b/arch/risc-v/src/litex/litex_mm_init.h @@ -0,0 +1,58 @@ +/**************************************************************************** + * arch/risc-v/src/litex/litex_mm_init.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_RISC_V_SRC_LITEX_LITEX_MM_INIT_H +#define __ARCH_RISC_V_SRC_LITEX_LITEX_MM_INIT_H + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include + +#include "riscv_mmu.h" + +/**************************************************************************** + * Public Functions Prototypes + ****************************************************************************/ + +/**************************************************************************** + * Name: litex_kernel_mappings + * + * Description: + * Setup kernel mappings when using CONFIG_BUILD_KERNEL. Sets up the kernel + * MMU mappings. + * + ****************************************************************************/ + +void litex_kernel_mappings(void); + +/**************************************************************************** + * Name: litex_mm_init + * + * Description: + * Setup kernel mappings when using CONFIG_BUILD_KERNEL. Sets up kernel MMU + * mappings. Function also sets the first address environment (satp value). + * + ****************************************************************************/ + +void litex_mm_init(void); + +#endif /* __ARCH_RISC_V_SRC_LITEX_LITEX_MM_INIT_H */ diff --git a/arch/risc-v/src/litex/litex_pgalloc.c b/arch/risc-v/src/litex/litex_pgalloc.c new file mode 100644 index 00000000000..02dd5d8eade --- /dev/null +++ b/arch/risc-v/src/litex/litex_pgalloc.c @@ -0,0 +1,67 @@ +/**************************************************************************** + * arch/risc-v/src/litex/litex_pgalloc.c + * + * 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 +#include +#include + +#include +#include + +#include + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +/**************************************************************************** + * Private Data + ****************************************************************************/ + +/**************************************************************************** + * Public Data + ****************************************************************************/ + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: up_allocate_pgheap + * + * Description: + * If there is a page allocator in the configuration, then this function + * must be provided by the platform-specific code. The OS initialization + * logic will call this function early in the initialization sequence to + * get the page heap information needed to configure the page allocator. + * + ****************************************************************************/ + +void up_allocate_pgheap(void **heap_start, size_t *heap_size) +{ + DEBUGASSERT(heap_start && heap_size); + + *heap_start = (void *)PGPOOL_START; + *heap_size = (size_t)PGPOOL_SIZE; +} diff --git a/arch/risc-v/src/litex/litex_shead.S b/arch/risc-v/src/litex/litex_shead.S new file mode 100644 index 00000000000..03b4809d0f7 --- /dev/null +++ b/arch/risc-v/src/litex/litex_shead.S @@ -0,0 +1,94 @@ +/**************************************************************************** + * arch/risc-v/src/litex/litex_shead.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 + +#include + +#include "chip.h" +#include "litex_memorymap.h" +#include "riscv_internal.h" + + +/**************************************************************************** + * Public Symbols + ****************************************************************************/ + + /* Imported symbols */ + + .extern __trap_vec + + .section .text + .global __start + +/**************************************************************************** + * Name: __start + * + * Description: + * Supervisor mode start function. + * + * Input Parameters: + * a0 - hartid + * + ****************************************************************************/ + +__start: + /* Disable all interrupts in sie */ + + + csrw sie, zero + csrw sip, zero + + + /* Set the S-mode trap vector */ + + la t0, __trap_vec + csrw stvec, t0 + + /* Clear sscratch */ + + csrw sscratch, zero + csrw scause, zero + csrw sepc, zero + + /* initialize global pointer, global data */ + + +.option push +.option norelax + la gp, __global_pointer$ + +.option pop + + lui sp, %hi(LITEX_IDLESTACK_TOP) + addi sp, sp, %lo(LITEX_IDLESTACK_TOP) + + /* Make sure the writes to CSR stick before continuing */ + + fence + + /* Set stack pointer and jump to start */ + + /*la sp, LITEX_IDLESTACK_TOP*/ + j __litex_start diff --git a/arch/risc-v/src/litex/litex_start.c b/arch/risc-v/src/litex/litex_start.c index f237a0f9878..751111caf51 100644 --- a/arch/risc-v/src/litex/litex_start.c +++ b/arch/risc-v/src/litex/litex_start.c @@ -33,6 +33,10 @@ #include "litex.h" #include "chip.h" +#ifdef CONFIG_BUILD_KERNEL +# include "litex_mm_init.h" +#endif + /**************************************************************************** * Pre-processor Definitions ****************************************************************************/ @@ -43,6 +47,10 @@ # define showprogress(c) #endif +#if defined (CONFIG_BUILD_KERNEL) && !defined (CONFIG_ARCH_USE_S_MODE) +# error "Target requires kernel in S-mode, enable CONFIG_ARCH_USE_S_MODE" +#endif + /**************************************************************************** * Public Data ****************************************************************************/ @@ -96,6 +104,10 @@ void __litex_start(void) *dest++ = *src++; } +#ifdef CONFIG_LITEX_CORE_VEXRISCV_SMP + riscv_percpu_add_hart(0); +#endif + /* Setup PLL */ litex_clockconfig(); @@ -114,7 +126,11 @@ void __litex_start(void) /* Do board initialization */ - litex_boardinitialize(); +#ifdef CONFIG_BUILD_KERNEL + /* Setup page tables for kernel and enable MMU */ + + litex_mm_init(); +#endif showprogress('C'); diff --git a/arch/risc-v/src/litex/litex_timerisr.c b/arch/risc-v/src/litex/litex_timerisr.c index 643b04f66b1..8d55f175fa9 100644 --- a/arch/risc-v/src/litex/litex_timerisr.c +++ b/arch/risc-v/src/litex/litex_timerisr.c @@ -23,19 +23,17 @@ ****************************************************************************/ #include - -#include -#include -#include - -#include #include -#include -#include +#include +#include +#include #include "riscv_internal.h" + #include "litex.h" #include "litex_clockconfig.h" +#include "hardware/litex_timer.h" +#include "riscv_mtimer.h" /**************************************************************************** * Pre-processor Definitions @@ -47,95 +45,33 @@ * Private Data ****************************************************************************/ -static bool _b_tick_started = false; - /**************************************************************************** * Private Functions ****************************************************************************/ -/* litex mmio registers are a bit odd, by default they are byte-wide - * registers that are on 32-bit word boundaries. So a "32-bit" registers - * is actually broken into four bytes spanning a total address space of - * 16 bytes. - */ - -static inline uint64_t litex_clint_time_read(void) -{ - uint64_t r = getreg32(LITEX_CLINT_MTIME); - r <<= 32; - r |= getreg32(LITEX_CLINT_MTIME + 0x04); - return r; -} - -static inline uint64_t litex_clint_time_cmp_read(void) -{ - uint64_t r = getreg32(LITEX_CLINT_MTIMECMP); - r <<= 32; - r |= getreg32(LITEX_CLINT_MTIMECMP + 0x04); - return r; -} - -static inline void litex_clint_time_cmp_write(uint64_t v) -{ - putreg32(v >> 32, LITEX_CLINT_MTIMECMP); - putreg32(v, LITEX_CLINT_MTIMECMP + 0x04); -} - -/* helper function to set/clear csr */ - -#define csr_clear(csr, val) \ -({ \ - unsigned long __v = (unsigned long)(val); \ - __asm__ __volatile__ ("csrc " #csr ", %0" \ - : : "rK" (__v)); \ -}) - -#define csr_set(csr, val) \ -({ \ - unsigned long __v = (unsigned long)(val); \ - __asm__ __volatile__ ("csrs " #csr ", %0" \ - : : "rK" (__v)); \ -}) - -/**************************************************************************** - * Name: litex_reload_mtimecmp - ****************************************************************************/ - -static void litex_reload_mtimecmp(void) -{ - irqstate_t flags = spin_lock_irqsave(NULL); - - uint64_t current; - uint64_t next; - - if (!_b_tick_started) - { - _b_tick_started = true; - putreg32(1, LITEX_CLINT_LATCH); - current = litex_clint_time_read(); - } - else - { - current = litex_clint_time_cmp_read(); - } - - next = current + TICK_COUNT; - - litex_clint_time_cmp_write(next); - putreg32(1, LITEX_CLINT_LATCH); - csr_set(mie, MIE_MTIE); - csr_clear(mip, MIP_MTIP); - - spin_unlock_irqrestore(NULL, flags); -} - /**************************************************************************** * Name: litex_timerisr ****************************************************************************/ +#ifdef CONFIG_LITEX_CORE_VEXRISCV_SMP +static void litex_mtimer_initialise(void) +{ + struct oneshot_lowerhalf_s *lower = riscv_mtimer_initialize( + LITEX_CLINT_MTIME, LITEX_CLINT_MTIMECMP, + RISCV_IRQ_TIMER, litex_get_hfclk()); + + DEBUGASSERT(lower); + + up_alarm_set_lowerhalf(lower); +} + +#else + static int litex_timerisr(int irq, void *context, void *arg) { - litex_reload_mtimecmp(); + /* Clear timer interrupt */ + + putreg32(0xffffffff, LITEX_TIMER0_EV_PENDING); /* Process timer interrupt */ @@ -143,6 +79,33 @@ static int litex_timerisr(int irq, void *context, void *arg) return 0; } +static void litex_timer0_initialize(void) +{ + /* Disable the timer and clear any pending interrupt */ + + putreg32(0, LITEX_TIMER0_EN); + putreg32(getreg32(LITEX_TIMER0_EV_PENDING), LITEX_TIMER0_EV_PENDING); + + /* Set the timer period */ + + putreg32(TICK_COUNT, LITEX_TIMER0_RELOAD); + putreg32(getreg32(LITEX_TIMER0_RELOAD), LITEX_TIMER0_LOAD); + + /* Attach timer interrupt handler */ + + irq_attach(LITEX_IRQ_TIMER0, litex_timerisr, NULL); + + /* Enable the timer */ + + putreg32(1, LITEX_TIMER0_EN); + + /* And enable the timer interrupt */ + + putreg32(1, LITEX_TIMER0_EV_ENABLE); + up_enable_irq(LITEX_IRQ_TIMER0); +} +#endif + /**************************************************************************** * Public Functions ****************************************************************************/ @@ -158,15 +121,9 @@ static int litex_timerisr(int irq, void *context, void *arg) void up_timer_initialize(void) { - /* Attach timer interrupt handler */ - - irq_attach(RISCV_IRQ_MTIMER, litex_timerisr, NULL); - - /* Reload CLINT mtimecmp */ - - litex_reload_mtimecmp(); - - /* And enable the timer interrupt */ - - up_enable_irq(RISCV_IRQ_MTIMER); +#ifdef CONFIG_LITEX_CORE_VEXRISCV_SMP + litex_mtimer_initialise(); +#else + litex_timer0_initialize(); +#endif } diff --git a/boards/risc-v/litex/arty_a7/Kconfig b/boards/risc-v/litex/arty_a7/Kconfig index 61584068d37..92df0ad54c7 100644 --- a/boards/risc-v/litex/arty_a7/Kconfig +++ b/boards/risc-v/litex/arty_a7/Kconfig @@ -25,4 +25,12 @@ config LITEX_SDIO_MOUNT_FSTYPE default "vfat" depends on LITEX_SDIO +config LITEX_APPLICATION_RAMDISK + bool "Use application ramdisk" + depends on BUILD_KERNEL + ---help--- + The application ramdisk is currently only intended only to hold + application elfs in the romfs format. These applications must loaded + externally into ram through litex_term, or similar method. + endif diff --git a/boards/risc-v/litex/arty_a7/configs/knsh/defconfig b/boards/risc-v/litex/arty_a7/configs/knsh/defconfig new file mode 100644 index 00000000000..cfd80f2b0eb --- /dev/null +++ b/boards/risc-v/litex/arty_a7/configs/knsh/defconfig @@ -0,0 +1,84 @@ +# +# This file is autogenerated: PLEASE DO NOT EDIT IT. +# +# You can use "make menuconfig" to make any modifications to the installed .config file. +# You can then do "make savedefconfig" to generate a new defconfig file that includes your +# modifications. +# +# CONFIG_DEBUG_OPT_UNUSED_SECTIONS is not set +# CONFIG_NSH_DISABLE_LOSMART is not set +# CONFIG_STANDARD_SERIAL is not set +CONFIG_ALARM_ARCH=y +CONFIG_ARCH="risc-v" +CONFIG_ARCH_ADDRENV=y +CONFIG_ARCH_BOARD="arty_a7" +CONFIG_ARCH_BOARD_ARTY_A7=y +CONFIG_ARCH_CHIP="litex" +CONFIG_ARCH_CHIP_LITEX=y +CONFIG_ARCH_DATA_NPAGES=128 +CONFIG_ARCH_DATA_VBASE=0x10400000 +CONFIG_ARCH_HEAP_NPAGES=128 +CONFIG_ARCH_HEAP_VBASE=0x10800000 +CONFIG_ARCH_INTERRUPTSTACK=8192 +CONFIG_ARCH_KERNEL_STACKSIZE=3072 +CONFIG_ARCH_PGPOOL_MAPPING=y +CONFIG_ARCH_PGPOOL_PBASE=0x40800000 +CONFIG_ARCH_PGPOOL_SIZE=4194304 +CONFIG_ARCH_PGPOOL_VBASE=0x40800000 +CONFIG_ARCH_RISCV=y +CONFIG_ARCH_STACKDUMP=y +CONFIG_ARCH_TEXT_NPAGES=128 +CONFIG_ARCH_TEXT_VBASE=0x10000000 +CONFIG_ARCH_USE_MMU=y +CONFIG_ARCH_USE_MPU=y +CONFIG_ARCH_USE_S_MODE=y +CONFIG_BOARDCTL_ROMDISK=y +CONFIG_BOARD_LATE_INITIALIZE=y +CONFIG_BOARD_LOOPSPERMSEC=10000 +CONFIG_BUILD_KERNEL=y +CONFIG_DEV_ZERO=y +CONFIG_ELF=y +CONFIG_EXAMPLES_HELLO=y +CONFIG_FS_PROCFS=y +CONFIG_FS_PROCFS_EXCLUDE_ENVIRON=y +CONFIG_FS_ROMFS=y +CONFIG_IDLETHREAD_STACKSIZE=2048 +CONFIG_INIT_FILEPATH="/system/bin/init" +CONFIG_INIT_MOUNT=y +CONFIG_INIT_MOUNT_FLAGS=0x1 +CONFIG_INIT_MOUNT_TARGET="/system/bin" +CONFIG_INIT_STACKSIZE=3072 +CONFIG_INTELHEX_BINARY=y +CONFIG_LIBC_ENVPATH=y +CONFIG_LIBC_EXECFUNCS=y +CONFIG_LIBC_PERROR_STDOUT=y +CONFIG_LIBC_STRERROR=y +CONFIG_LITEX_APPLICATION_RAMDISK=y +CONFIG_LITEX_CORE_VEXRISCV_SMP=y +CONFIG_LITEX_SYS_CORE_FREQ_HZ=300000000 +CONFIG_MM_PGALLOC=y +CONFIG_NFILE_DESCRIPTORS_PER_BLOCK=6 +CONFIG_NSH_FILEIOSIZE=512 +CONFIG_NSH_FILE_APPS=y +CONFIG_NSH_READLINE=y +CONFIG_ONESHOT=y +CONFIG_PATH_INITIAL="/system/bin" +CONFIG_RAM_SIZE=4194304 +CONFIG_RAM_START=0x40400000 +CONFIG_RAW_BINARY=y +CONFIG_READLINE_CMD_HISTORY=y +CONFIG_RR_INTERVAL=200 +CONFIG_SCHED_LPWORK=y +CONFIG_SCHED_WAITPID=y +CONFIG_START_MONTH=12 +CONFIG_START_YEAR=2021 +CONFIG_SYMTAB_ORDEREDBYNAME=y +CONFIG_SYSLOG_PROCESS_NAME=y +CONFIG_SYSLOG_TIMESTAMP=y +CONFIG_SYSTEM_CLE=y +CONFIG_SYSTEM_NSH=y +CONFIG_SYSTEM_NSH_PROGNAME="init" +CONFIG_TESTING_GETPRIME=y +CONFIG_UART0_RXBUFSIZE=128 +CONFIG_UART0_SERIAL_CONSOLE=y +CONFIG_UART0_TXBUFSIZE=128 diff --git a/boards/risc-v/litex/arty_a7/include/board_memorymap.h b/boards/risc-v/litex/arty_a7/include/board_memorymap.h new file mode 100644 index 00000000000..73e2d644978 --- /dev/null +++ b/boards/risc-v/litex/arty_a7/include/board_memorymap.h @@ -0,0 +1,93 @@ +/**************************************************************************** + * boards/risc-v/litex/arty_a7/include/board_memorymap.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 __BOARDS_RISCV_LITEX_ARTY_A7_INCLUDE_BOARD_MEMORYMAP_H +#define __BOARDS_RISCV_LITEX_ARTY_A7_INCLUDE_BOARD_MEMORYMAP_H + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +/* Kernel code memory (RX) */ + +#define KFLASH_START (uintptr_t)__kflash_start +#define KFLASH_SIZE (uintptr_t)__kflash_size +#define KSRAM_START (uintptr_t)__ksram_start +#define KSRAM_SIZE (uintptr_t)__ksram_size +#define KSRAM_END (uintptr_t)__ksram_end + +/* Kernel RAM (RW) */ + +#define PGPOOL_START (uintptr_t)__pgheap_start +#define PGPOOL_SIZE (uintptr_t)__pgheap_size + +/* Page pool (RWX) */ + +#define PGPOOL_START (uintptr_t)__pgheap_start +#define PGPOOL_SIZE (uintptr_t)__pgheap_size +#define PGPOOL_END (PGPOOL_START + PGPOOL_SIZE) + +/* User flash */ + +#define UFLASH_START (uintptr_t)__uflash_start +#define UFLASH_SIZE (uintptr_t)__uflash_size + +/* RAMDisk */ + +#define RAMDISK_START (uintptr_t)__ramdisk_start +#define RAMDISK_SIZE (uintptr_t)__ramdisk_size + +/**************************************************************************** + * Public Data + ****************************************************************************/ + +/* Kernel code memory (RX) */ + +extern uint8_t __kflash_start[]; +extern uint8_t __kflash_size[]; + +/* Kernel RAM (RW) */ + +extern uint8_t __ksram_start[]; +extern uint8_t __ksram_size[]; +extern uint8_t __ksram_end[]; + +/* Page pool (RWX) */ + +extern uint8_t __pgheap_start[]; +extern uint8_t __pgheap_size[]; + +/* User code memory (RX) */ + +extern uint8_t __uflash_start[]; +extern uint8_t __uflash_size[]; + +/* ramdisk (RW) */ + +extern uint8_t __ramdisk_start[]; +extern uint8_t __ramdisk_size[]; + +#endif /* __BOARDS_RISC_V_LITEX_ARTY_A7_INCLUDE_BOARD_MEMORYMAP_H */ diff --git a/boards/risc-v/litex/arty_a7/scripts/Make.defs b/boards/risc-v/litex/arty_a7/scripts/Make.defs index a1e83f5acd3..2f3535d6541 100644 --- a/boards/risc-v/litex/arty_a7/scripts/Make.defs +++ b/boards/risc-v/litex/arty_a7/scripts/Make.defs @@ -22,7 +22,12 @@ include $(TOPDIR)/.config include $(TOPDIR)/tools/Config.mk include $(TOPDIR)/arch/risc-v/src/common/Toolchain.defs +ifeq ($(CONFIG_BUILD_KERNEL),y) +LDSCRIPT = ld-kernel.script +else LDSCRIPT = ld.script +endif + ARCHSCRIPT += $(BOARD_DIR)$(DELIM)scripts$(DELIM)$(LDSCRIPT) ARCHPICFLAGS = -fpic -msingle-pic-base -mpic-register=r10 @@ -33,3 +38,11 @@ CXXFLAGS := $(ARCHCXXFLAGS) $(ARCHOPTIMIZATION) $(ARCHCPUFLAGS) $(ARCHXXINCLUDES CXXPICFLAGS = $(ARCHPICFLAGS) $(CXXFLAGS) CPPFLAGS := $(ARCHINCLUDES) $(ARCHDEFINES) $(EXTRAFLAGS) AFLAGS += $(CFLAGS) -D__ASSEMBLY__ + +CELFFLAGS = $(CFLAGS) +CXXELFFLAGS = $(CXXFLAGS) + +LDELFFLAGS = --oformat elf32-littleriscv + +LDELFFLAGS += -r -e main +LDELFFLAGS += -T $(call CONVERT_PATH,$(TOPDIR)/binfmt/libelf/gnu-elf.ld) \ No newline at end of file diff --git a/boards/risc-v/litex/arty_a7/scripts/ld-kernel.script b/boards/risc-v/litex/arty_a7/scripts/ld-kernel.script new file mode 100644 index 00000000000..fae0d03fba8 --- /dev/null +++ b/boards/risc-v/litex/arty_a7/scripts/ld-kernel.script @@ -0,0 +1,135 @@ +/**************************************************************************** + * boards/risc-v/litex/arty_a7/scripts/ld-kernel.script + * + * 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. + * + ****************************************************************************/ + +MEMORY +{ + kflash (rx) : ORIGIN = 0x40000000, LENGTH = 4096K /* w/ cache */ + ksram (rwx) : ORIGIN = 0x40400000, LENGTH = 4096K /* w/ cache */ + pgram (rwx) : ORIGIN = 0x40800000, LENGTH = 4096K /* w/ cache */ + ramdisk (rwx) : ORIGIN = 0x40C00000, LENGTH = 4096K /* w/ cache */ +} + +OUTPUT_ARCH("riscv") + +/* Provide the kernel boundaries */ + +__kflash_start = ORIGIN(kflash); +__kflash_size = LENGTH(kflash); +__ksram_start = ORIGIN(ksram); +__ksram_size = LENGTH(ksram); +__ksram_end = ORIGIN(ksram) + LENGTH(ksram); + +/* Page heap */ + +__pgheap_start = ORIGIN(pgram); +__pgheap_size = LENGTH(pgram) + LENGTH(ramdisk); + +/* Application ramdisk */ + +__ramdisk_start = ORIGIN(ramdisk); +__ramdisk_size = LENGTH(ramdisk); +__ramdisk_end = ORIGIN(ramdisk) + LENGTH(ramdisk); + +ENTRY(_stext) +EXTERN(__start) +SECTIONS +{ + . = 0x40000000; + .text : { + _stext = ABSOLUTE(.); + *(.start .start.*) + *(.text .text.*) + *(.fixup) + *(.gnu.warning) + *(.rodata .rodata.* .srodata .srodata.*) + *(.gnu.linkonce.t.*) + *(.glue_7) + *(.glue_7t) + *(.got) + *(.gcc_except_table) + *(.gnu.linkonce.r.*) + _etext = ABSOLUTE(.); + } > kflash + + .init_section : ALIGN(4) { + _sinit = ABSOLUTE(.); + KEEP(*(.init_array .init_array.*)) + _einit = ABSOLUTE(.); + } > kflash + + _eronly = ABSOLUTE(.); + + /* No init section */ + + .noinit (NOLOAD) : ALIGN(4) { + *(.noinit) + *(.noinit.*) + } > ksram + + .data : ALIGN(4) { + _sdata = ABSOLUTE(.); + *(.data .data.*) + *(.sdata .sdata.* .sdata2.*) + *(.gnu.linkonce.d.*) + *(.gnu.linkonce.s.*) + CONSTRUCTORS + . = ALIGN(4); + _edata = ABSOLUTE(.); + } > ksram AT > kflash + + PROVIDE(__global_pointer$ = _sdata + ((_edata - _sdata) / 2)); + + .bss : ALIGN(4) { + _sbss = ABSOLUTE(.); + *(.bss .bss.*) + *(.sbss .sbss.*) + *(.gnu.linkonce.b.*) + *(.gnu.linkonce.sb.*) + *(COMMON) + } > ksram + /* Page tables here, align to 4K boundary */ + + .pgtables (NOLOAD) : ALIGN(0x1000) { + *(.pgtables) + . = ALIGN(4); + } > ksram + + /* Stack top */ + + .stack_top : { + . = ALIGN(32); + _ebss = ABSOLUTE(.); + } > ksram + + /* Stabs debugging sections. */ + + .stab 0 : { *(.stab) } + .stabstr 0 : { *(.stabstr) } + .stab.excl 0 : { *(.stab.excl) } + .stab.exclstr 0 : { *(.stab.exclstr) } + .stab.index 0 : { *(.stab.index) } + .stab.indexstr 0 : { *(.stab.indexstr) } + .comment 0 : { *(.comment) } + .debug_abbrev 0 : { *(.debug_abbrev) } + .debug_info 0 : { *(.debug_info) } + .debug_line 0 : { *(.debug_line) } + .debug_pubnames 0 : { *(.debug_pubnames) } + .debug_aranges 0 : { *(.debug_aranges) } +} diff --git a/boards/risc-v/litex/arty_a7/src/Makefile b/boards/risc-v/litex/arty_a7/src/Makefile index 497c7ab275e..ae8f0e74561 100644 --- a/boards/risc-v/litex/arty_a7/src/Makefile +++ b/boards/risc-v/litex/arty_a7/src/Makefile @@ -38,4 +38,8 @@ ifeq ($(CONFIG_LITEX_PWM),y) CSRCS += litex_pwm.c endif +ifeq ($(CONFIG_LITEX_APPLICATION_RAMDISK),y) +CSRCS += litex_ramdisk.c +endif + include $(TOPDIR)/boards/Board.mk diff --git a/boards/risc-v/litex/arty_a7/src/arty_a7.h b/boards/risc-v/litex/arty_a7/src/arty_a7.h index e224c18f757..cb0ee0795ea 100644 --- a/boards/risc-v/litex/arty_a7/src/arty_a7.h +++ b/boards/risc-v/litex/arty_a7/src/arty_a7.h @@ -161,4 +161,22 @@ bool litex_cardinserted(int slotno); int litex_pwm_setup(void); #endif +/**************************************************************************** + * Name: litex_mount_ramdisk + * + * Description: + * Mount a ramdisk defined in the ld-kernel.script to /dev/ramX. + * The ramdisk is intended to contain a romfs with applications which can + * be spawned at runtime. + * + * Returned Value: + * OK is returned on success. + * -ERRORNO is returned on failure. + * + ****************************************************************************/ + +#ifdef CONFIG_LITEX_APPLICATION_RAMDISK +int litex_mount_ramdisk(void); +#endif + #endif /* __BOARDS_RISCV_LITEX_ARTY_A7_SRC_ARTY_A7_H */ diff --git a/boards/risc-v/litex/arty_a7/src/litex_appinit.c b/boards/risc-v/litex/arty_a7/src/litex_appinit.c index e82f793cbe5..7371433f468 100644 --- a/boards/risc-v/litex/arty_a7/src/litex_appinit.c +++ b/boards/risc-v/litex/arty_a7/src/litex_appinit.c @@ -73,3 +73,31 @@ int board_app_initialize(uintptr_t arg) return litex_bringup(); #endif } + +/**************************************************************************** + * Name: board_late_initialize + * + * Description: + * If CONFIG_BOARD_LATE_INITIALIZE is selected, then an additional + * initialization call will be performed in the boot-up sequence to a + * function called board_late_initialize(). board_late_initialize() will + * be called after up_initialize() and board_early_initialize() and just + * before the initial application is started. This additional + * initialization phase may be used, for example, to initialize board- + * specific device drivers for which board_early_initialize() is not + * suitable. + * + * Waiting for events, use of I2C, SPI, etc are permissible in the context + * of board_late_initialize(). That is because board_late_initialize() + * will run on a temporary, internal kernel thread. + * + ****************************************************************************/ + +void board_late_initialize(void) +{ + #ifdef CONFIG_LITEX_APPLICATION_RAMDISK + litex_mount_ramdisk(); + #endif + + litex_bringup(); +} diff --git a/boards/risc-v/litex/arty_a7/src/litex_ramdisk.c b/boards/risc-v/litex/arty_a7/src/litex_ramdisk.c new file mode 100644 index 00000000000..6f413cd663f --- /dev/null +++ b/boards/risc-v/litex/arty_a7/src/litex_ramdisk.c @@ -0,0 +1,98 @@ +/**************************************************************************** + * boards/risc-v/litex/arty_a7/src/litex_ramdisk.c + * + * 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 + +#include +#include +#include +#include + +#include + +#include +#include +#include +#include + +#include "litex.h" +#include "arty_a7.h" + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +#ifndef CONFIG_BUILD_KERNEL +#error "Ramdisk usage is intended to be used with kernel build only" +#endif + +#define SECTORSIZE 512 +#define NSECTORS(b) (((b) + SECTORSIZE - 1) / SECTORSIZE) +#define RAMDISK_DEVICE_MINOR 0 + +/**************************************************************************** + * Private Types + ****************************************************************************/ + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: litex_mount_ramdisk + * + * Description: + * Mount a ramdisk defined in the ld-kernel.script to /dev/ramX. + * The ramdisk is intended to contain a romfs with applications which can + * be spawned at runtime. + * + * Returned Value: + * OK is returned on success. + * -ERRORNO is returned on failure. + * + ****************************************************************************/ + +int litex_mount_ramdisk(void) +{ + int ret; + struct boardioc_romdisk_s desc; + + desc.minor = RAMDISK_DEVICE_MINOR; + desc.nsectors = NSECTORS((ssize_t)__ramdisk_size); + desc.sectsize = SECTORSIZE; + desc.image = __ramdisk_start; + + ret = boardctl(BOARDIOC_ROMDISK, (uintptr_t)&desc); + if (ret < 0) + { + syslog(LOG_ERR, "Ramdisk register failed: %s\n", strerror(errno)); + syslog(LOG_ERR, "Ramdisk mountpoint /dev/ram%d\n", + RAMDISK_DEVICE_MINOR); + syslog(LOG_ERR, "Ramdisk length %u, origin %x\n", + (ssize_t)__ramdisk_size, + (uintptr_t)__ramdisk_start); + } + + return ret; +} diff --git a/libs/libc/machine/risc-v/arch_elf.c b/libs/libc/machine/risc-v/arch_elf.c index 50a20fb5cc7..9efa4837228 100644 --- a/libs/libc/machine/risc-v/arch_elf.c +++ b/libs/libc/machine/risc-v/arch_elf.c @@ -564,6 +564,11 @@ int up_relocateadd(const Elf_Rela *rel, const Elf_Sym *sym, *(uint64_t *)addr += (uint64_t)(sym->st_value + rel->r_addend); } break; + case R_RISCV_SUB16: + { + *(uint16_t *)addr -= (uint16_t)(sym->st_value + rel->r_addend); + } + break; case R_RISCV_SUB32: { *(uint32_t *)addr -= (uint32_t)(sym->st_value + rel->r_addend); @@ -574,6 +579,11 @@ int up_relocateadd(const Elf_Rela *rel, const Elf_Sym *sym, *(uint64_t *)addr -= (uint64_t)(sym->st_value + rel->r_addend); } break; + case R_RISCV_SET16: + { + *(uint16_t *)addr = (uint16_t)(sym->st_value + rel->r_addend); + } + break; default: berr("ERROR: Unsupported relocation: %ld\n", ARCH_ELF_RELTYPE(rel->r_info));