diff --git a/payloads/libpayload/Kconfig b/payloads/libpayload/Kconfig index 44d656bcac..9ad454181f 100644 --- a/payloads/libpayload/Kconfig +++ b/payloads/libpayload/Kconfig @@ -127,6 +127,15 @@ config ARCH_ARM64 help Support the ARM64 architecture +config ARCH_RISCV_RV64 + bool "RISCV64" + depends on GPL + depends on EXPERIMENTAL + help + Support the RISC-V 64-bit architecture + Please note that support for riscv64 payload is experimental at this time, may have + fundamental change in the future. + config ARCH_MOCK bool "Mock architecture (for unit tests)" help @@ -523,3 +532,4 @@ source "arch/arm/Kconfig" source "arch/arm64/Kconfig" source "arch/x86/Kconfig" source "arch/mock/Kconfig" +source "arch/riscv/Kconfig" diff --git a/payloads/libpayload/Makefile b/payloads/libpayload/Makefile index a8c2641dc6..6ac1e90d26 100644 --- a/payloads/libpayload/Makefile +++ b/payloads/libpayload/Makefile @@ -111,6 +111,7 @@ ARCHDIR-$(CONFIG_LP_ARCH_ARM) := arm ARCHDIR-$(CONFIG_LP_ARCH_ARM64) := arm64 ARCHDIR-$(CONFIG_LP_ARCH_X86) := x86 ARCHDIR-$(CONFIG_LP_ARCH_MOCK) := mock +ARCHDIR-$(CONFIG_LP_ARCH_RISCV_RV64) := riscv ARCH-y := $(ARCHDIR-y) @@ -121,6 +122,7 @@ ARCH-$(CONFIG_LP_ARCH_ARM64) := arm64 ARCH-$(CONFIG_LP_ARCH_X86_32) := x86_32 ARCH-$(CONFIG_LP_ARCH_X86_64) := x86_64 ARCH-$(CONFIG_LP_ARCH_MOCK) := mock +ARCH-$(CONFIG_LP_ARCH_RISCV_RV64) := riscv # Five cases where we don't need fully populated $(obj) lists: # 1. when no .config exists diff --git a/payloads/libpayload/Makefile.mk b/payloads/libpayload/Makefile.mk index 08249c2648..f7c2c8bda0 100644 --- a/payloads/libpayload/Makefile.mk +++ b/payloads/libpayload/Makefile.mk @@ -41,6 +41,7 @@ ARCHDIR-$(CONFIG_LP_ARCH_ARM) := arm ARCHDIR-$(CONFIG_LP_ARCH_ARM64) := arm64 ARCHDIR-$(CONFIG_LP_ARCH_X86) := x86 ARCHDIR-$(CONFIG_LP_ARCH_MOCK) := mock +ARCHDIR-$(CONFIG_LP_ARCH_RISCV_RV64) := riscv DESTDIR ?= install real-target: lib diff --git a/payloads/libpayload/arch/riscv/Kconfig b/payloads/libpayload/arch/riscv/Kconfig new file mode 100644 index 0000000000..03960ab1da --- /dev/null +++ b/payloads/libpayload/arch/riscv/Kconfig @@ -0,0 +1,4 @@ +## SPDX-License-Identifier: GPL-2.0-only + +config ARCH_RISCV_RV64 + select LITTLE_ENDIAN diff --git a/payloads/libpayload/arch/riscv/Makefile.mk b/payloads/libpayload/arch/riscv/Makefile.mk new file mode 100644 index 0000000000..cb835bbfcb --- /dev/null +++ b/payloads/libpayload/arch/riscv/Makefile.mk @@ -0,0 +1,7 @@ +## SPDX-License-Identifier: GPL-2.0-only + +libc-y += head.S +libc-y += main.c sysinfo.c +libc-y += timer.c coreboot.c cache.c util.S virtual.c + +CFLAGS += -mcmodel=medany diff --git a/payloads/libpayload/arch/riscv/cache.c b/payloads/libpayload/arch/riscv/cache.c new file mode 100644 index 0000000000..d5dcb5e2a2 --- /dev/null +++ b/payloads/libpayload/arch/riscv/cache.c @@ -0,0 +1,13 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ + +#include + +void tlb_invalidate_all(void) +{ + asm volatile ("sfence.vma" : : : "memory"); +} + +void dcache_clean_invalidate_all(void) +{ + +} diff --git a/payloads/libpayload/arch/riscv/coreboot.c b/payloads/libpayload/arch/riscv/coreboot.c new file mode 100644 index 0000000000..acd3e85fb1 --- /dev/null +++ b/payloads/libpayload/arch/riscv/coreboot.c @@ -0,0 +1,34 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ + +#include +#include +#include + +/* + * This pointer is no longer set in head.S by default like in other arch, payloads should have + * their own ways to init it from any source before using it. + * e.g. If run after OpenSBI, this could be retrieved from fdt node. + * If run directly after Ramstage, could be from arg0. + */ +void *cb_header_ptr; + +/* == Architecture specific == */ + +int cb_parse_arch_specific(struct cb_record *rec, struct sysinfo_t *info) +{ + switch (rec->tag) { + default: + return 0; + } + return 1; +} + +int get_coreboot_info(struct sysinfo_t *info) +{ + return cb_parse_header(cb_header_ptr, 1, info); +} + +void *get_cb_header_ptr(void) +{ + return cb_header_ptr; +} diff --git a/payloads/libpayload/arch/riscv/head.S b/payloads/libpayload/arch/riscv/head.S new file mode 100644 index 0000000000..aebbff979d --- /dev/null +++ b/payloads/libpayload/arch/riscv/head.S @@ -0,0 +1,24 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ + +#include + +/* + * Our entry point + */ +ENTRY(_entry) + + /* Setup new stack */ + lla t0, 1f + ld sp, 0(t0) + //mov sp, x1 + + /* Let's rock. */ + j start_main + + ret +ENDPROC(_entry) + +.section .entry, "ax", %progbits +.align 4 +1: +.quad _stack diff --git a/payloads/libpayload/arch/riscv/libpayload.ldscript b/payloads/libpayload/arch/riscv/libpayload.ldscript new file mode 100644 index 0000000000..168f61397a --- /dev/null +++ b/payloads/libpayload/arch/riscv/libpayload.ldscript @@ -0,0 +1,65 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ + +OUTPUT_ARCH(riscv) + +ENTRY(_entry) + +SECTIONS +{ + . = CONFIG_LP_BASE_ADDRESS; + + . = ALIGN(16); + _start = .; + + .text : { + _text = .; + *(.text._entry) + *(.text) + *(.text.*) + _etext = .; + } + + .rodata : { + _rodata = .; + *(.rodata) + *(.rodata.*) + _erodata = .; + } + + .data : { + _data = .; + *(.data) + *(.data.*) + _edata = .; + } + + .bss : { + _bss = .; + *(.sbss) + *(.sbss.*) + *(.bss) + *(.bss.*) + *(COMMON) + _ebss = .; + + /* Stack and heap */ + + . = ALIGN(16); + _heap = .; + . += CONFIG_LP_HEAP_SIZE; + . = ALIGN(16); + _eheap = .; + + _estack = .; + . += CONFIG_LP_STACK_SIZE; + . = ALIGN(16); + _stack = .; + } + + _end = .; + + /DISCARD/ : { + *(.comment) + *(.note*) + } +} diff --git a/payloads/libpayload/arch/riscv/main.c b/payloads/libpayload/arch/riscv/main.c new file mode 100644 index 0000000000..d0b400c8f2 --- /dev/null +++ b/payloads/libpayload/arch/riscv/main.c @@ -0,0 +1,53 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ + +#include +#include +#include + +uint64_t boot_hartid; +/** + * This is our C entry function - set up the system and jump into the payload entry point. + * Unlike other archs, we do not save a0~a2 from previous stage as global variables in head.S, + * but pass them to start_main directly as arg0, arg1, arg2 instead. + * + * arg0 is the preferred boot hart id. + * arg1 is a pointer to the DTB. + * This interface is static no matter whether previous stage is OpenSBI or coreboot Ramstage. + * + * arg2 is reserved for possible future usage. + */ +void start_main(uint64_t arg0, uint64_t arg1, uint64_t arg2); +void start_main(uint64_t arg0, uint64_t arg1, uint64_t arg2) +{ + extern int main(int argc, char **argv); + extern void *cb_header_ptr; + + /* cbtable pointer is stored in the dtb passed by previous stage */ + boot_hartid = arg0; + const void *dtb = (const void *)arg1; + if (dtb && fdt_is_valid(dtb)) { + /* Look for the "coreboot-table" node in the DTB */ + u32 node_offset = fdt_find_node_by_path(dtb, "/chosen", NULL, NULL); + if (node_offset) { + struct fdt_property prop; + if (fdt_read_prop(dtb, node_offset, "coreboot-table", &prop)) { + /* Extract the coreboot table pointer from the property */ + cb_header_ptr = (void *)be64dec(prop.data); + } + } + } + + /* Gather system information. */ + lib_get_sysinfo(); + +#if !CONFIG(LP_SKIP_CONSOLE_INIT) + console_init(); +#endif + + /* + * Go to the entry point. + * In the future we may care about the return value. + */ + main(0, NULL); + printf("Unexpected return from payload\n"); +} diff --git a/payloads/libpayload/arch/riscv/sysinfo.c b/payloads/libpayload/arch/riscv/sysinfo.c new file mode 100644 index 0000000000..353ede174e --- /dev/null +++ b/payloads/libpayload/arch/riscv/sysinfo.c @@ -0,0 +1,70 @@ +/* + * + * Copyright (C) 2008 Advanced Micro Devices, Inc. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include +#include +#include + +/** + * This is a global structure that is used through the library - we set it + * up initially with some dummy values - hopefully they will be overridden. + */ +struct sysinfo_t lib_sysinfo = { + .cpu_khz = 200, +}; + +int lib_get_sysinfo(void) +{ + int ret; + + /* Get the CPU speed (for delays). */ + lib_sysinfo.cpu_khz = get_cpu_speed(); + + /* Get information from the coreboot tables, + * if they exist */ + + ret = get_coreboot_info(&lib_sysinfo); + + if (!lib_sysinfo.n_memranges) { + /* If we can't get a good memory range, use the default. */ + lib_sysinfo.n_memranges = 1; + + lib_sysinfo.memrange[0].base = 0; + lib_sysinfo.memrange[0].size = 1024 * 1024; + lib_sysinfo.memrange[0].type = CB_MEM_RAM; + } + + return ret; +} + +void lib_sysinfo_get_memranges(struct memrange **ranges, + uint64_t *nranges) +{ + *ranges = &lib_sysinfo.memrange[0]; + *nranges = lib_sysinfo.n_memranges; +} diff --git a/payloads/libpayload/arch/riscv/timer.c b/payloads/libpayload/arch/riscv/timer.c new file mode 100644 index 0000000000..1177e09802 --- /dev/null +++ b/payloads/libpayload/arch/riscv/timer.c @@ -0,0 +1,53 @@ +/* + * + * Copyright (C) 2008 Advanced Micro Devices, Inc. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/** + * @file riscv64/timer.c + * RISCV64 specific timer routines + */ + +#include + +/** + * @ingroup arch + * Global variable containing the speed of the processor in KHz. + */ +u32 cpu_khz; + +/** + * Calculate the speed of the processor for use in delays. + * + * @return The CPU speed in kHz. + */ +unsigned int get_cpu_speed(void) +{ + /* FIXME */ + cpu_khz = 1000000U; + + return cpu_khz; +} diff --git a/payloads/libpayload/arch/riscv/util.S b/payloads/libpayload/arch/riscv/util.S new file mode 100644 index 0000000000..3b15abc21d --- /dev/null +++ b/payloads/libpayload/arch/riscv/util.S @@ -0,0 +1,34 @@ +/* + * + * Copyright (C) 2012 Google, Inc. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include + +/* This function puts the system into a halt. */ +ENTRY(halt) + j halt +ENDPROC(halt) diff --git a/payloads/libpayload/arch/riscv/virtual.c b/payloads/libpayload/arch/riscv/virtual.c new file mode 100644 index 0000000000..9450ac0d86 --- /dev/null +++ b/payloads/libpayload/arch/riscv/virtual.c @@ -0,0 +1,36 @@ +/* + * + * Copyright (C) 2008 coresystems GmbH + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include + +unsigned long virtual_offset = 0; + +int getpagesize(void) +{ + return 4096; +} diff --git a/payloads/libpayload/drivers/Makefile.mk b/payloads/libpayload/drivers/Makefile.mk index 23471b83c4..63daf67cdb 100644 --- a/payloads/libpayload/drivers/Makefile.mk +++ b/payloads/libpayload/drivers/Makefile.mk @@ -64,6 +64,7 @@ libc-y += timer/generic.c endif libc-$(CONFIG_LP_TIMER_RDTSC) += timer/rdtsc.c libc-$(CONFIG_LP_TIMER_ARM64_ARCH) += timer/arm64_arch_timer.c +libc-$(CONFIG_LP_TIMER_RISCV64_ARCH) += timer/riscv64_arch_timer.c # Video console drivers libc-$(CONFIG_LP_VIDEO_CONSOLE) += video/video.c diff --git a/payloads/libpayload/drivers/timer/Kconfig b/payloads/libpayload/drivers/timer/Kconfig index 406457af8e..1932a136da 100644 --- a/payloads/libpayload/drivers/timer/Kconfig +++ b/payloads/libpayload/drivers/timer/Kconfig @@ -36,6 +36,12 @@ config TIMER_ARM64_ARCH help The cntfrq register needs to have been pre-initialized. +config TIMER_RISCV64_ARCH + bool "Architecture Timer for RISCV64 platforms" + depends on ARCH_RISCV_RV64 + help + Payloads usually run in S-Mode, which has a time CSR for timer implementation. + config TIMER_RK3288 bool "Timer for Rockchip RK3288" diff --git a/payloads/libpayload/drivers/timer/riscv64_arch_timer.c b/payloads/libpayload/drivers/timer/riscv64_arch_timer.c new file mode 100644 index 0000000000..515ae47658 --- /dev/null +++ b/payloads/libpayload/drivers/timer/riscv64_arch_timer.c @@ -0,0 +1,16 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ + +#include + +uint64_t timer_hz(void) +{ + /* FIXME */ + return 1000000; +} + +uint64_t timer_raw_value(void) +{ + uint64_t value; + asm volatile ("csrr %0, time" : "=r" (value)); + return value; +} diff --git a/payloads/libpayload/include/riscv/arch/asm.h b/payloads/libpayload/include/riscv/arch/asm.h new file mode 100644 index 0000000000..5d8eae20e2 --- /dev/null +++ b/payloads/libpayload/include/riscv/arch/asm.h @@ -0,0 +1,23 @@ +/* + * + * Copyright 2013 Google Inc. + * + */ + +#ifndef __RISCV64_ASM_H +#define __RISCV64_ASM_H + +#define ENDPROC(name) \ + .type name, %function; \ + END(name) + +#define ENTRY(name) \ + .section .text.name, "ax", %progbits; \ + .global name; \ + .align 2; \ + name: + +#define END(name) \ + .size name, .-name + +#endif /* __RISCV64_ASM_H */ diff --git a/payloads/libpayload/include/riscv/arch/cache.h b/payloads/libpayload/include/riscv/arch/cache.h new file mode 100644 index 0000000000..d47b05dd41 --- /dev/null +++ b/payloads/libpayload/include/riscv/arch/cache.h @@ -0,0 +1,21 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ + +#ifndef RISCV64_CACHE_H +#define RISCV64_CACHE_H + +#include +#include + +/* tlb invalidate all */ +void tlb_invalidate_all(void); + +void dcache_clean_invalidate_all(void); + +/* Invalidate all of the instruction cache for PE to PoU. */ +static inline void icache_invalidate_all(void) +{ + __asm__ __volatile__("fence.i\n\t"); +} + + +#endif /* RISCV64_CACHE_H */ diff --git a/payloads/libpayload/include/riscv/arch/io.h b/payloads/libpayload/include/riscv/arch/io.h new file mode 100644 index 0000000000..b586204bfe --- /dev/null +++ b/payloads/libpayload/include/riscv/arch/io.h @@ -0,0 +1,106 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ + +#ifndef _ARCH_IO_H +#define _ARCH_IO_H + +#include +#include + +#define fence_i_r() __asm__ __volatile__("fence i,r" : : : "memory") +#define fence_ow_ow() __asm__ __volatile__("fence ow,ow" : : : "memory") + +/* + * readb/w/l writeb/w/l are deprecated. use read8/16/32 and write8/16/32 + * instead for future development. + */ + +static inline uint8_t readb(volatile const void *_a) +{ + return *(volatile const uint8_t *)_a; + fence_i_r(); +} + +static inline uint16_t readw(volatile const void *_a) +{ + return *(volatile const uint16_t *)_a; + fence_i_r(); +} + +static inline uint32_t readl(volatile const void *_a) +{ + return *(volatile const uint32_t *)_a; + fence_i_r(); +} + +static inline void writeb(uint8_t _v, volatile void *_a) +{ + fence_ow_ow(); + *(volatile uint8_t *)_a = _v; +} + +static inline void writew(uint16_t _v, volatile void *_a) +{ + fence_ow_ow(); + *(volatile uint16_t *)_a = _v; +} + +static inline void writel(uint32_t _v, volatile void *_a) +{ + fence_ow_ow(); + *(volatile uint32_t *)_a = _v; +} + +/* + * TODO: make the existing code use read8/16/32 and write8/16/32 then remove + * readb/w/l and writeb/w/l. + */ + +static inline uint8_t read8(volatile const void *addr) +{ + return *(volatile uint8_t *)addr; + fence_i_r(); +} + +static inline uint16_t read16(volatile const void *addr) +{ + return *(volatile uint16_t *)addr; + fence_i_r(); +} + +static inline uint32_t read32(volatile const void *addr) +{ + return *(volatile uint32_t *)addr; + fence_i_r(); +} + +static inline uint64_t read64(volatile const void *addr) +{ + return *(volatile uint64_t *)addr; + fence_i_r(); +} + +static inline void write8(volatile void *addr, uint8_t val) +{ + fence_ow_ow(); + *(volatile uint8_t *)addr = val; +} + +static inline void write16(volatile void *addr, uint16_t val) +{ + fence_ow_ow(); + *(volatile uint16_t *)addr = val; +} + +static inline void write32(volatile void *addr, uint32_t val) +{ + fence_ow_ow(); + *(volatile uint32_t *)addr = val; +} + +static inline void write64(volatile void *addr, uint64_t val) +{ + fence_ow_ow(); + *(volatile uint64_t *)addr = val; +} + +#endif diff --git a/payloads/libpayload/include/riscv/arch/types.h b/payloads/libpayload/include/riscv/arch/types.h new file mode 100644 index 0000000000..044e047f37 --- /dev/null +++ b/payloads/libpayload/include/riscv/arch/types.h @@ -0,0 +1,33 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ + +#ifndef _ARCH_TYPES_H +#define _ARCH_TYPES_H + +typedef unsigned char uint8_t; +typedef unsigned char u8; +typedef signed char int8_t; +typedef signed char s8; + +typedef unsigned short uint16_t; +typedef unsigned short u16; +typedef signed short int16_t; +typedef signed short s16; + +typedef unsigned int uint32_t; +typedef unsigned int u32; +typedef signed int int32_t; +typedef signed int s32; + +typedef unsigned long long uint64_t; +typedef unsigned long long u64; +typedef signed long long int64_t; +typedef signed long long s64; + +typedef long time_t; +typedef long suseconds_t; + +#ifndef NULL +#define NULL ((void *)0) +#endif + +#endif diff --git a/payloads/libpayload/include/riscv/arch/virtual.h b/payloads/libpayload/include/riscv/arch/virtual.h new file mode 100644 index 0000000000..4b107787d2 --- /dev/null +++ b/payloads/libpayload/include/riscv/arch/virtual.h @@ -0,0 +1,14 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ + +#ifndef _ARCH_VIRTUAL_H +#define _ARCH_VIRTUAL_H + +extern unsigned long virtual_offset; + +#define virt_to_phys(virt) ((unsigned long) (virt) + virtual_offset) +#define phys_to_virt(phys) ((void *) ((unsigned long) (phys) - virtual_offset)) + +#define virt_to_bus(addr) virt_to_phys(addr) +#define bus_to_virt(addr) phys_to_virt(addr) + +#endif diff --git a/src/arch/riscv/boot.c b/src/arch/riscv/boot.c index 6f744d3211..7d1cb3e92d 100644 --- a/src/arch/riscv/boot.c +++ b/src/arch/riscv/boot.c @@ -8,12 +8,58 @@ #include #include #include +#include +#include struct arch_prog_run_args { struct prog *prog; struct prog *opensbi; }; +/* + * At the moment devicetree is the default handoff format to the payload instead of + * coreboot tables (on RISC-V only). That may change in the future, but for now we will put a + * reference to the coreboot tables inside the FDT (similar to what we do in ACPI). + */ +static void *add_coreboot_table_to_fdt(void *fdt) +{ + if (!fdt || !fdt_is_valid(fdt)) { + printk(BIOS_ERR, "Invalid FDT provided\n"); + return fdt; + } + + void *coreboot_table = cbmem_find(CBMEM_ID_CBTABLE); + if (!coreboot_table) { + printk(BIOS_ERR, "coreboot table not found in CBMEM\n"); + return fdt; + } + + struct device_tree *tree = fdt_unflatten(fdt); + if (!tree) { + printk(BIOS_ERR, "Failed to unflatten FDT\n"); + return fdt; + } + + struct device_tree_node *chosen_node = dt_find_node_by_path(tree, "/chosen", NULL, NULL, 1); + if (!chosen_node) { + printk(BIOS_ERR, "Failed to find or create /chosen node\n"); + return fdt; + } + + printk(BIOS_INFO, "Adding cbtable@%p to fdt\n", coreboot_table); + dt_add_u64_prop(chosen_node, "coreboot-table", (uint64_t)(uintptr_t)coreboot_table); + + size_t next_size = dt_flat_size(tree); + void *next_fdt = malloc(next_size); + if (!next_fdt) { + printk(BIOS_ERR, "Failed to allocate memory for next-stage FDT\n"); + return fdt; + } + + dt_flatten(tree, next_fdt); + return next_fdt; +} + /* * A pointer to the Flattened Device Tree passed to coreboot by the boot ROM. * Presumably this FDT is also in ROM. @@ -51,14 +97,29 @@ void arch_prog_run(struct prog *prog) args.prog = prog; - /* In case of OpenSBI we have to load it before resuming all HARTs */ - if (ENV_RAMSTAGE && CONFIG(RISCV_OPENSBI)) { - struct prog sbi = PROG_INIT(PROG_OPENSBI, CONFIG_CBFS_PREFIX"/opensbi"); + if (ENV_RAMSTAGE) { + int hart_count = CONFIG_MAX_CPUS; + if (CONFIG(RISCV_GET_HART_COUNT_AT_RUNTIME)) + hart_count = smp_get_hart_count(); - if (!selfload_check(&sbi, BM_MEM_OPENSBI)) - die("OpenSBI load failed"); + /* Embed coreboot table pointer into fdt, so that payload can find it. */ + void *fdt = HLS()->fdt; + void *next_fdt = add_coreboot_table_to_fdt(fdt); - args.opensbi = &sbi; + /* Update per hart's fdt with "coreboot-table" node embedded */ + for (int i = 0; i < hart_count; i++) { + OTHER_HLS(i)->fdt = next_fdt; + } + + /* In case of OpenSBI we have to load it before resuming all HARTs */ + if (CONFIG(RISCV_OPENSBI)) { + struct prog sbi = PROG_INIT(PROG_OPENSBI, CONFIG_CBFS_PREFIX"/opensbi"); + + if (!selfload_check(&sbi, BM_MEM_OPENSBI)) + die("OpenSBI load failed"); + + args.opensbi = &sbi; + } } smp_resume((void (*)(void *))do_arch_prog_run, &args);