From f14595a7cfc8de16a06335c6ecdf9ae23a0adf53 Mon Sep 17 00:00:00 2001 From: Anup Patel Date: Thu, 29 Dec 2022 10:56:15 +0800 Subject: [PATCH 001/187] lib: sbi: Allow platform to influence cold boot HART selection We add an optional cold_boot_allowed() platform callback which allows platform support to decide which HARTs can do cold boot initialization. If this platform callback is not available then any HART can do cold boot initialization. Signed-off-by: Anup Patel --- include/sbi/sbi_platform.h | 20 ++++++++++++++++++++ lib/sbi/sbi_init.c | 7 +++++-- 2 files changed, 25 insertions(+), 2 deletions(-) diff --git a/include/sbi/sbi_platform.h b/include/sbi/sbi_platform.h index 010e9cebdd7..43d1c031ed7 100644 --- a/include/sbi/sbi_platform.h +++ b/include/sbi/sbi_platform.h @@ -65,6 +65,9 @@ enum sbi_platform_features { /** Platform functions */ struct sbi_platform_operations { + /* Check if specified HART is allowed to do cold boot */ + bool (*cold_boot_allowed)(u32 hartid); + /* Platform nascent initialization */ int (*nascent_init)(void); @@ -356,6 +359,23 @@ static inline bool sbi_platform_hart_invalid(const struct sbi_platform *plat, return false; } +/** + * Check whether given HART is allowed to do cold boot + * + * @param plat pointer to struct sbi_platform + * @param hartid HART ID + * + * @return true if HART is allowed to do cold boot and false otherwise + */ +static inline bool sbi_platform_cold_boot_allowed( + const struct sbi_platform *plat, + u32 hartid) +{ + if (plat && sbi_platform_ops(plat)->cold_boot_allowed) + return sbi_platform_ops(plat)->cold_boot_allowed(hartid); + return true; +} + /** * Nascent (very early) initialization for current HART * diff --git a/lib/sbi/sbi_init.c b/lib/sbi/sbi_init.c index ded3da00a93..259a191051a 100644 --- a/lib/sbi/sbi_init.c +++ b/lib/sbi/sbi_init.c @@ -498,8 +498,11 @@ void __noreturn sbi_init(struct sbi_scratch *scratch) * HARTs which satisfy above condition. */ - if (next_mode_supported && atomic_xchg(&coldboot_lottery, 1) == 0) - coldboot = true; + if (sbi_platform_cold_boot_allowed(plat, hartid)) { + if (next_mode_supported && + atomic_xchg(&coldboot_lottery, 1) == 0) + coldboot = true; + } /* * Do platform specific nascent (very early) initialization so From 6957ae0e91ebd9f17411b56f3e9100d31bc48b56 Mon Sep 17 00:00:00 2001 From: Anup Patel Date: Thu, 29 Dec 2022 10:56:16 +0800 Subject: [PATCH 002/187] platform: generic: Allow platform_override to select cold boot HART We add a generic platform override callback to allow platform specific selection of cold boot HART. Signed-off-by: Anup Patel --- platform/generic/include/platform_override.h | 1 + platform/generic/platform.c | 9 +++++++++ 2 files changed, 10 insertions(+) diff --git a/platform/generic/include/platform_override.h b/platform/generic/include/platform_override.h index 7f1558dde1a..21354e96bf6 100644 --- a/platform/generic/include/platform_override.h +++ b/platform/generic/include/platform_override.h @@ -18,6 +18,7 @@ struct platform_override { const struct fdt_match *match_table; u64 (*features)(const struct fdt_match *match); u64 (*tlbr_flush_limit)(const struct fdt_match *match); + bool (*cold_boot_allowed)(u32 hartid, const struct fdt_match *match); int (*early_init)(bool cold_boot, const struct fdt_match *match); int (*final_init)(bool cold_boot, const struct fdt_match *match); void (*early_exit)(const struct fdt_match *match); diff --git a/platform/generic/platform.c b/platform/generic/platform.c index bfe15f0d6b8..5fb0dc6565b 100644 --- a/platform/generic/platform.c +++ b/platform/generic/platform.c @@ -122,6 +122,14 @@ unsigned long fw_platform_init(unsigned long arg0, unsigned long arg1, wfi(); } +static bool generic_cold_boot_allowed(u32 hartid) +{ + if (generic_plat && generic_plat->cold_boot_allowed) + return generic_plat->cold_boot_allowed( + hartid, generic_plat_match); + return true; +} + static int generic_nascent_init(void) { if (platform_has_mlevel_imsic) @@ -261,6 +269,7 @@ static int generic_console_init(void) } const struct sbi_platform_operations platform_ops = { + .cold_boot_allowed = generic_cold_boot_allowed, .nascent_init = generic_nascent_init, .early_init = generic_early_init, .final_init = generic_final_init, From cb7e7c3325e68a9b4d5ea210b97cac693cf5814f Mon Sep 17 00:00:00 2001 From: Wei Liang Lim Date: Thu, 29 Dec 2022 10:56:17 +0800 Subject: [PATCH 003/187] platform: generic: Allow platform_override to perform firmware init We add a generic platform override callback to allow platform specific firmware init. Signed-off-by: Wei Liang Lim Reviewed-by: Chee Hong Ang Reviewed-by: Jun Liang Tan Reviewed-by: Anup Patel --- platform/generic/include/platform_override.h | 1 + platform/generic/platform.c | 3 +++ 2 files changed, 4 insertions(+) diff --git a/platform/generic/include/platform_override.h b/platform/generic/include/platform_override.h index 21354e96bf6..a59b06a11d8 100644 --- a/platform/generic/include/platform_override.h +++ b/platform/generic/include/platform_override.h @@ -26,6 +26,7 @@ struct platform_override { int (*fdt_fixup)(void *fdt, const struct fdt_match *match); int (*extensions_init)(const struct fdt_match *match, struct sbi_hart_features *hfeatures); + void (*fw_init)(void *fdt, const struct fdt_match *match); int (*vendor_ext_check)(long extid, const struct fdt_match *match); int (*vendor_ext_provider)(long extid, long funcid, const struct sbi_trap_regs *regs, diff --git a/platform/generic/platform.c b/platform/generic/platform.c index 5fb0dc6565b..a34d3b01933 100644 --- a/platform/generic/platform.c +++ b/platform/generic/platform.c @@ -85,6 +85,9 @@ unsigned long fw_platform_init(unsigned long arg0, unsigned long arg1, fw_platform_lookup_special(fdt, root_offset); + if (generic_plat && generic_plat->fw_init) + generic_plat->fw_init(fdt, generic_plat_match); + model = fdt_getprop(fdt, root_offset, "model", &len); if (model) sbi_strncpy(platform.name, model, sizeof(platform.name) - 1); From 8020df8733b060f01e35b0b2bcb2b41e6b992e9b Mon Sep 17 00:00:00 2001 From: Wei Liang Lim Date: Thu, 29 Dec 2022 10:56:18 +0800 Subject: [PATCH 004/187] generic/starfive: Add Starfive JH7110 platform implementation Add Starfive JH7110 platform implementation Signed-off-by: Wei Liang Lim Reviewed-by: Chee Hong Ang Reviewed-by: Jun Liang Tan Reviewed-by: Anup Patel --- platform/generic/Kconfig | 4 +++ platform/generic/configs/defconfig | 1 + platform/generic/starfive/jh7110.c | 47 ++++++++++++++++++++++++++++ platform/generic/starfive/objects.mk | 6 ++++ 4 files changed, 58 insertions(+) create mode 100644 platform/generic/starfive/jh7110.c create mode 100644 platform/generic/starfive/objects.mk diff --git a/platform/generic/Kconfig b/platform/generic/Kconfig index 62c7a2d8051..47c10e53a32 100644 --- a/platform/generic/Kconfig +++ b/platform/generic/Kconfig @@ -45,4 +45,8 @@ config PLATFORM_SIFIVE_FU740 depends on FDT_RESET && FDT_I2C default n +config PLATFORM_STARFIVE_JH7110 + bool "StarFive JH7110 support" + default n + endif diff --git a/platform/generic/configs/defconfig b/platform/generic/configs/defconfig index 47fca950c24..4b0842e03ed 100644 --- a/platform/generic/configs/defconfig +++ b/platform/generic/configs/defconfig @@ -3,6 +3,7 @@ CONFIG_PLATFORM_ANDES_AE350=y CONFIG_PLATFORM_RENESAS_RZFIVE=y CONFIG_PLATFORM_SIFIVE_FU540=y CONFIG_PLATFORM_SIFIVE_FU740=y +CONFIG_PLATFORM_STARFIVE_JH7110=y CONFIG_FDT_GPIO=y CONFIG_FDT_GPIO_SIFIVE=y CONFIG_FDT_I2C=y diff --git a/platform/generic/starfive/jh7110.c b/platform/generic/starfive/jh7110.c new file mode 100644 index 00000000000..c665658ac9b --- /dev/null +++ b/platform/generic/starfive/jh7110.c @@ -0,0 +1,47 @@ +/* + * SPDX-License-Identifier: BSD-2-Clause + * + * Copyright (c) 2022 StarFive + * + * Authors: + * Wei Liang Lim + */ + +#include +#include +#include + +static u32 selected_hartid = -1; + +static bool starfive_jh7110_cold_boot_allowed(u32 hartid, + const struct fdt_match *match) +{ + if (selected_hartid != -1) + return (selected_hartid == hartid); + + return true; +} + +static void starfive_jh7110_fw_init(void *fdt, const struct fdt_match *match) +{ + const fdt32_t *val; + int len, coff; + + coff = fdt_path_offset(fdt, "/chosen"); + if (-1 < coff) { + val = fdt_getprop(fdt, coff, "starfive,boot-hart-id", &len); + if (val && len >= sizeof(fdt32_t)) + selected_hartid = (u32) fdt32_to_cpu(*val); + } +} + +static const struct fdt_match starfive_jh7110_match[] = { + { .compatible = "starfive,jh7110" }, + { }, +}; + +const struct platform_override starfive_jh7110 = { + .match_table = starfive_jh7110_match, + .cold_boot_allowed = starfive_jh7110_cold_boot_allowed, + .fw_init = starfive_jh7110_fw_init, +}; diff --git a/platform/generic/starfive/objects.mk b/platform/generic/starfive/objects.mk new file mode 100644 index 00000000000..0b900fb6fe6 --- /dev/null +++ b/platform/generic/starfive/objects.mk @@ -0,0 +1,6 @@ +# +# SPDX-License-Identifier: BSD-2-Clause +# + +carray-platform_override_modules-$(CONFIG_PLATFORM_STARFIVE_JH7110) += starfive_jh7110 +platform-objs-$(CONFIG_PLATFORM_STARFIVE_JH7110) += starfive/jh7110.o From 6997552ea2236b2a0fe1269e71e3588a58e100e7 Mon Sep 17 00:00:00 2001 From: Bin Meng Date: Fri, 30 Dec 2022 13:07:23 +0800 Subject: [PATCH 005/187] lib: sbi_hsm: Rename 'priv' argument to 'arg1' 'priv' argument of sbi_hsm_hart_start() and sbi_hsm_hart_suspend() may mislead people to think it stands for 'privilege mode', but it is not. Change it to 'arg1' to clearly indicate the a1 register. Signed-off-by: Bin Meng Reviewed-by: Samuel Holland Tested-by: Samuel Holland Reviewed-by: Atish Patra Reviewed-by: Anup Patel --- include/sbi/sbi_hsm.h | 4 ++-- lib/sbi/sbi_hsm.c | 8 ++++---- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/include/sbi/sbi_hsm.h b/include/sbi/sbi_hsm.h index d6cc468d052..c2a728a4aca 100644 --- a/include/sbi/sbi_hsm.h +++ b/include/sbi/sbi_hsm.h @@ -59,12 +59,12 @@ void __noreturn sbi_hsm_exit(struct sbi_scratch *scratch); int sbi_hsm_hart_start(struct sbi_scratch *scratch, const struct sbi_domain *dom, - u32 hartid, ulong saddr, ulong smode, ulong priv); + u32 hartid, ulong saddr, ulong smode, ulong arg1); int sbi_hsm_hart_stop(struct sbi_scratch *scratch, bool exitnow); void sbi_hsm_hart_resume_start(struct sbi_scratch *scratch); void sbi_hsm_hart_resume_finish(struct sbi_scratch *scratch); int sbi_hsm_hart_suspend(struct sbi_scratch *scratch, u32 suspend_type, - ulong raddr, ulong rmode, ulong priv); + ulong raddr, ulong rmode, ulong arg1); int sbi_hsm_hart_get_state(const struct sbi_domain *dom, u32 hartid); int sbi_hsm_hart_interruptible_mask(const struct sbi_domain *dom, ulong hbase, ulong *out_hmask); diff --git a/lib/sbi/sbi_hsm.c b/lib/sbi/sbi_hsm.c index 836008fc92d..c0a5505423b 100644 --- a/lib/sbi/sbi_hsm.c +++ b/lib/sbi/sbi_hsm.c @@ -248,7 +248,7 @@ void __noreturn sbi_hsm_exit(struct sbi_scratch *scratch) int sbi_hsm_hart_start(struct sbi_scratch *scratch, const struct sbi_domain *dom, - u32 hartid, ulong saddr, ulong smode, ulong priv) + u32 hartid, ulong saddr, ulong smode, ulong arg1) { unsigned long init_count; unsigned int hstate; @@ -281,7 +281,7 @@ int sbi_hsm_hart_start(struct sbi_scratch *scratch, return SBI_EINVAL; init_count = sbi_init_count(hartid); - rscratch->next_arg1 = priv; + rscratch->next_arg1 = arg1; rscratch->next_addr = saddr; rscratch->next_mode = smode; @@ -402,7 +402,7 @@ void sbi_hsm_hart_resume_finish(struct sbi_scratch *scratch) } int sbi_hsm_hart_suspend(struct sbi_scratch *scratch, u32 suspend_type, - ulong raddr, ulong rmode, ulong priv) + ulong raddr, ulong rmode, ulong arg1) { int oldstate, ret; const struct sbi_domain *dom = sbi_domain_thishart_ptr(); @@ -433,7 +433,7 @@ int sbi_hsm_hart_suspend(struct sbi_scratch *scratch, u32 suspend_type, } /* Save the resume address and resume mode */ - scratch->next_arg1 = priv; + scratch->next_arg1 = arg1; scratch->next_addr = raddr; scratch->next_mode = rmode; From 9e397e3960413360aa8972da5320adf744996e69 Mon Sep 17 00:00:00 2001 From: Bin Meng Date: Fri, 30 Dec 2022 13:07:51 +0800 Subject: [PATCH 006/187] docs: domain_support: Use capital letter for privilege modes The RISC-V convention for the privilege mode is capital letter, like 'M-mode', instead of 'm-mode'. Signed-off-by: Bin Meng Reviewed-by: Atish Patra Reviewed-by: Anup Patel --- docs/domain_support.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/domain_support.md b/docs/domain_support.md index 8963b57e378..c909d4a6878 100644 --- a/docs/domain_support.md +++ b/docs/domain_support.md @@ -161,7 +161,7 @@ The DT properties of a domain instance DT node are as follows: and access permissions for the domain instance. Each list entry is a pair of DT node phandle and access permissions. The access permissions are represented as a 32bit bitmask having bits: **readable** (BIT[0]), - **writeable** (BIT[1]), **executable** (BIT[2]), and **m-mode** (BIT[3]). + **writeable** (BIT[1]), **executable** (BIT[2]), and **M-mode** (BIT[3]). * **boot-hart** (Optional) - The DT node phandle of the HART booting the domain instance. If coldboot HART is assigned to the domain instance then this DT property is ignored and the coldboot HART is assumed to be the @@ -180,7 +180,7 @@ The DT properties of a domain instance DT node are as follows: is used as default value. * **next-mode** (Optional) - The 32 bit next booting stage mode for the domain instance. The possible values of this DT property are: **0x1** - (s-mode), and **0x0** (u-mode). If this DT property is not available + (S-mode), and **0x0** (U-mode). If this DT property is not available and coldboot HART is not assigned to the domain instance then **0x1** is used as default value. If this DT property is not available and coldboot HART is assigned to the domain instance then **next booting From 9e0ba090763a7d31d63ba67421b09647f2f2adc4 Mon Sep 17 00:00:00 2001 From: Himanshu Chauhan Date: Mon, 9 Jan 2023 05:20:35 +0000 Subject: [PATCH 007/187] include: sbi: Fine grain the permissions for M and SU modes Split the permissions for M-mode and SU-mode. This would help if different sections of OpenSBI need to be given different permissions and if M-mode has different permisssions than the SU-mode over a region. Signed-off-by: Himanshu Chauhan Reviewed-by: Anup Patel Tested-by: Anup Patel --- include/sbi/sbi_domain.h | 47 +++++++++++++++++++++++++++++++++++----- 1 file changed, 42 insertions(+), 5 deletions(-) diff --git a/include/sbi/sbi_domain.h b/include/sbi/sbi_domain.h index f0d9289ec7c..a42c20ddf38 100644 --- a/include/sbi/sbi_domain.h +++ b/include/sbi/sbi_domain.h @@ -36,11 +36,48 @@ struct sbi_domain_memregion { */ unsigned long base; /** Flags representing memory region attributes */ -#define SBI_DOMAIN_MEMREGION_READABLE (1UL << 0) -#define SBI_DOMAIN_MEMREGION_WRITEABLE (1UL << 1) -#define SBI_DOMAIN_MEMREGION_EXECUTABLE (1UL << 2) -#define SBI_DOMAIN_MEMREGION_MMODE (1UL << 3) -#define SBI_DOMAIN_MEMREGION_ACCESS_MASK (0xfUL) +#define SBI_DOMAIN_MEMREGION_M_READABLE (1UL << 0) +#define SBI_DOMAIN_MEMREGION_M_WRITABLE (1UL << 1) +#define SBI_DOMAIN_MEMREGION_M_EXECUTABLE (1UL << 2) +#define SBI_DOMAIN_MEMREGION_SU_READABLE (1UL << 3) +#define SBI_DOMAIN_MEMREGION_SU_WRITABLE (1UL << 4) +#define SBI_DOMAIN_MEMREGION_SU_EXECUTABLE (1UL << 5) + +/** Bit to control if permissions are enforced on all modes */ +#define SBI_DOMAIN_MEMREGION_ENF_PERMISSIONS (1UL << 6) + +#define SBI_DOMAIN_MEMREGION_M_RWX \ + (SBI_DOMAIN_MEMREGION_M_READABLE | \ + SBI_DOMAIN_MEMREGION_M_WRITABLE | \ + SBI_DOMAIN_MEMREGION_M_EXECUTABLE) + +/* Unrestricted M-mode accesses but enfoced on SU-mode */ +#define SBI_DOMAIN_MEMREGION_READABLE \ + (SBI_DOMAIN_MEMREGION_SU_READABLE | \ + SBI_DOMAIN_MEMREGION_M_RWX) +#define SBI_DOMAIN_MEMREGION_WRITEABLE \ + (SBI_DOMAIN_MEMREGION_SU_WRITABLE | \ + SBI_DOMAIN_MEMREGION_M_RWX) +#define SBI_DOMAIN_MEMREGION_EXECUTABLE \ + (SBI_DOMAIN_MEMREGION_SU_EXECUTABLE | \ + SBI_DOMAIN_MEMREGION_M_RWX) + +/* Enforced accesses across all modes */ +#define SBI_DOMAIN_MEMREGION_ENF_READABLE \ + (SBI_DOMAIN_MEMREGION_SU_READABLE | \ + SBI_DOMAIN_MEMREGION_M_READABLE) +#define SBI_DOMAIN_MEMREGION_ENF_WRITABLE \ + (SBI_DOMAIN_MEMREGION_SU_WRITABLE | \ + SBI_DOMAIN_MEMREGION_M_WRITABLE) +#define SBI_DOMAIN_MEMREGION_ENF_EXECUTABLE \ + (SBI_DOMAIN_MEMREGION_SU_EXECUTABLE | \ + SBI_DOMAIN_MEMREGION_M_EXECUTABLE) + +#define SBI_DOMAIN_MEMREGION_ACCESS_MASK (0x3fUL) +#define SBI_DOMAIN_MEMREGION_M_ACCESS_MASK (0x7UL) +#define SBI_DOMAIN_MEMREGION_SU_ACCESS_MASK (0x38UL) + +#define SBI_DOMAIN_MEMREGION_SU_ACCESS_SHIFT (3) #define SBI_DOMAIN_MEMREGION_MMIO (1UL << 31) unsigned long flags; From aace1e145dbd987e6bd5a8b4583faafde7d33c43 Mon Sep 17 00:00:00 2001 From: Himanshu Chauhan Date: Mon, 9 Jan 2023 05:20:36 +0000 Subject: [PATCH 008/187] lib: sbi: Use finer permission semantics for address validation Use the fine grained permisssion semantics for address validation of a given region. Signed-off-by: Himanshu Chauhan Reviewed-by: Anup Patel Tested-by: Anup Patel --- lib/sbi/sbi_domain.c | 24 +++++++++++++++++------- 1 file changed, 17 insertions(+), 7 deletions(-) diff --git a/lib/sbi/sbi_domain.c b/lib/sbi/sbi_domain.c index 19e2029e6c4..97eec25c857 100644 --- a/lib/sbi/sbi_domain.c +++ b/lib/sbi/sbi_domain.c @@ -107,24 +107,34 @@ bool sbi_domain_check_addr(const struct sbi_domain *dom, { bool rmmio, mmio = false; struct sbi_domain_memregion *reg; - unsigned long rstart, rend, rflags, rwx = 0; + unsigned long rstart, rend, rflags, rwx = 0, rrwx = 0; if (!dom) return false; + /* + * Use M_{R/W/X} bits because the SU-bits are at the + * same relative offsets. If the mode is not M, the SU + * bits will fall at same offsets after the shift. + */ if (access_flags & SBI_DOMAIN_READ) - rwx |= SBI_DOMAIN_MEMREGION_READABLE; + rwx |= SBI_DOMAIN_MEMREGION_M_READABLE; + if (access_flags & SBI_DOMAIN_WRITE) - rwx |= SBI_DOMAIN_MEMREGION_WRITEABLE; + rwx |= SBI_DOMAIN_MEMREGION_M_WRITABLE; + if (access_flags & SBI_DOMAIN_EXECUTE) - rwx |= SBI_DOMAIN_MEMREGION_EXECUTABLE; + rwx |= SBI_DOMAIN_MEMREGION_M_EXECUTABLE; + if (access_flags & SBI_DOMAIN_MMIO) mmio = true; sbi_domain_for_each_memregion(dom, reg) { rflags = reg->flags; - if (mode == PRV_M && !(rflags & SBI_DOMAIN_MEMREGION_MMODE)) - continue; + rrwx = (mode == PRV_M ? + (rflags & SBI_DOMAIN_MEMREGION_M_ACCESS_MASK) : + (rflags & SBI_DOMAIN_MEMREGION_SU_ACCESS_MASK) + >> SBI_DOMAIN_MEMREGION_SU_ACCESS_SHIFT); rstart = reg->base; rend = (reg->order < __riscv_xlen) ? @@ -133,7 +143,7 @@ bool sbi_domain_check_addr(const struct sbi_domain *dom, rmmio = (rflags & SBI_DOMAIN_MEMREGION_MMIO) ? true : false; if (mmio != rmmio) return false; - return ((rflags & rwx) == rwx) ? true : false; + return ((rrwx & rwx) == rwx) ? true : false; } } From 22dbdb3d60c64975d7e5704a6bd64f7b73bee157 Mon Sep 17 00:00:00 2001 From: Himanshu Chauhan Date: Mon, 9 Jan 2023 05:20:37 +0000 Subject: [PATCH 009/187] lib: sbi: Add permissions for the firmware start till end Change the zero flag to M-mode R/W/X flag for the firmware region. Signed-off-by: Himanshu Chauhan Reviewed-by: Anup Patel Tested-by: Anup Patel --- lib/sbi/sbi_domain.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/lib/sbi/sbi_domain.c b/lib/sbi/sbi_domain.c index 97eec25c857..b08d6e35a69 100644 --- a/lib/sbi/sbi_domain.c +++ b/lib/sbi/sbi_domain.c @@ -629,7 +629,8 @@ int sbi_domain_init(struct sbi_scratch *scratch, u32 cold_hartid) const struct sbi_platform *plat = sbi_platform_ptr(scratch); /* Root domain firmware memory region */ - sbi_domain_memregion_init(scratch->fw_start, scratch->fw_size, 0, + sbi_domain_memregion_init(scratch->fw_start, scratch->fw_size, + SBI_DOMAIN_MEMREGION_M_RWX, &root_fw_region); domain_memregion_initfw(&root_memregs[root_memregs_count++]); From 1ac14f10f6f27f1078d684b7931718db0e6822c4 Mon Sep 17 00:00:00 2001 From: Himanshu Chauhan Date: Mon, 9 Jan 2023 05:20:38 +0000 Subject: [PATCH 010/187] lib: sbi: Use finer permission sematics to decide on PMP bits Use the fine grained permission bits to decide if the region permissions are to be enforced on all modes. Also use the new permission bits for deciding on R/W/X bits in pmpcfg register. Signed-off-by: Himanshu Chauhan Reviewed-by: Anup Patel Tested-by: Anup Patel --- lib/sbi/sbi_hart.c | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) diff --git a/lib/sbi/sbi_hart.c b/lib/sbi/sbi_hart.c index 5447c523987..02ce99191cd 100644 --- a/lib/sbi/sbi_hart.c +++ b/lib/sbi/sbi_hart.c @@ -303,14 +303,20 @@ int sbi_hart_pmp_configure(struct sbi_scratch *scratch) break; pmp_flags = 0; - if (reg->flags & SBI_DOMAIN_MEMREGION_READABLE) + + /* + * If permissions are to be enforced for all modes on this + * region, the lock bit should be set. + */ + if (reg->flags & SBI_DOMAIN_MEMREGION_ENF_PERMISSIONS) + pmp_flags |= PMP_L; + + if (reg->flags & SBI_DOMAIN_MEMREGION_SU_READABLE) pmp_flags |= PMP_R; - if (reg->flags & SBI_DOMAIN_MEMREGION_WRITEABLE) + if (reg->flags & SBI_DOMAIN_MEMREGION_SU_WRITABLE) pmp_flags |= PMP_W; - if (reg->flags & SBI_DOMAIN_MEMREGION_EXECUTABLE) + if (reg->flags & SBI_DOMAIN_MEMREGION_SU_EXECUTABLE) pmp_flags |= PMP_X; - if (reg->flags & SBI_DOMAIN_MEMREGION_MMODE) - pmp_flags |= PMP_L; pmp_addr = reg->base >> PMP_SHIFT; if (pmp_gran_log2 <= reg->order && pmp_addr < pmp_addr_max) From 44f736c96ed997df6e40d90acdd1cdd3342a8ff4 Mon Sep 17 00:00:00 2001 From: Himanshu Chauhan Date: Mon, 9 Jan 2023 05:20:39 +0000 Subject: [PATCH 011/187] lib: sbi: Modify the boot time region flag prints With the finer permission semantics, the region access permissions must be displayed separately for M and SU mode. Signed-off-by: Himanshu Chauhan Reviewed-by: Anup Patel Tested-by: Anup Patel --- lib/sbi/sbi_domain.c | 20 +++++++++++++++----- 1 file changed, 15 insertions(+), 5 deletions(-) diff --git a/lib/sbi/sbi_domain.c b/lib/sbi/sbi_domain.c index b08d6e35a69..60fda012d7b 100644 --- a/lib/sbi/sbi_domain.c +++ b/lib/sbi/sbi_domain.c @@ -345,15 +345,25 @@ void sbi_domain_dump(const struct sbi_domain *dom, const char *suffix) dom->index, i, suffix, rstart, rend); k = 0; - if (reg->flags & SBI_DOMAIN_MEMREGION_MMODE) - sbi_printf("%cM", (k++) ? ',' : '('); + + sbi_printf("M: "); if (reg->flags & SBI_DOMAIN_MEMREGION_MMIO) sbi_printf("%cI", (k++) ? ',' : '('); - if (reg->flags & SBI_DOMAIN_MEMREGION_READABLE) + if (reg->flags & SBI_DOMAIN_MEMREGION_M_READABLE) + sbi_printf("%cR", (k++) ? ',' : '('); + if (reg->flags & SBI_DOMAIN_MEMREGION_M_WRITABLE) + sbi_printf("%cW", (k++) ? ',' : '('); + if (reg->flags & SBI_DOMAIN_MEMREGION_M_EXECUTABLE) + sbi_printf("%cX", (k++) ? ',' : '('); + sbi_printf("%s ", (k++) ? ")" : "()"); + + k = 0; + sbi_printf("S/U: "); + if (reg->flags & SBI_DOMAIN_MEMREGION_SU_READABLE) sbi_printf("%cR", (k++) ? ',' : '('); - if (reg->flags & SBI_DOMAIN_MEMREGION_WRITEABLE) + if (reg->flags & SBI_DOMAIN_MEMREGION_SU_WRITABLE) sbi_printf("%cW", (k++) ? ',' : '('); - if (reg->flags & SBI_DOMAIN_MEMREGION_EXECUTABLE) + if (reg->flags & SBI_DOMAIN_MEMREGION_SU_EXECUTABLE) sbi_printf("%cX", (k++) ? ',' : '('); sbi_printf("%s\n", (k++) ? ")" : "()"); From 20646e0184e23cacfeb951060d33881453d14772 Mon Sep 17 00:00:00 2001 From: Himanshu Chauhan Date: Mon, 9 Jan 2023 05:20:40 +0000 Subject: [PATCH 012/187] lib: utils: Use SU-{R/W/X} flags for region permissions during parsing Use the newer SU-{R/W/X} flags for checking and assigning region permissions. Signed-off-by: Himanshu Chauhan Reviewed-by: Anup Patel Tested-by: Anup Patel --- lib/utils/fdt/fdt_domain.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/lib/utils/fdt/fdt_domain.c b/lib/utils/fdt/fdt_domain.c index 35462a2008a..45612ef6924 100644 --- a/lib/utils/fdt/fdt_domain.c +++ b/lib/utils/fdt/fdt_domain.c @@ -338,9 +338,9 @@ static int __fdt_parse_domain(void *fdt, int domain_offset, void *opaque) * 2) mmio regions protecting M-mode only mmio devices */ sbi_domain_for_each_memregion(&root, reg) { - if ((reg->flags & SBI_DOMAIN_MEMREGION_READABLE) || - (reg->flags & SBI_DOMAIN_MEMREGION_WRITEABLE) || - (reg->flags & SBI_DOMAIN_MEMREGION_EXECUTABLE)) + if ((reg->flags & SBI_DOMAIN_MEMREGION_SU_READABLE) || + (reg->flags & SBI_DOMAIN_MEMREGION_SU_WRITABLE) || + (reg->flags & SBI_DOMAIN_MEMREGION_SU_EXECUTABLE)) continue; if (FDT_DOMAIN_REGION_MAX_COUNT <= val32) return SBI_EINVAL; From 3e2f573e707e78c7e00a977b28ce917ff051e69d Mon Sep 17 00:00:00 2001 From: Himanshu Chauhan Date: Mon, 9 Jan 2023 05:20:41 +0000 Subject: [PATCH 013/187] lib: utils: Disallow non-root domains from adding M-mode regions The M-mode regions can only be added to the root domain. The non-root domains shouldn't be able to add them from FDT. Signed-off-by: Himanshu Chauhan Reviewed-by: Anup Patel Tested-by: Anup Patel --- include/sbi/sbi_domain.h | 5 +++++ lib/utils/fdt/fdt_domain.c | 14 ++++++++++++++ 2 files changed, 19 insertions(+) diff --git a/include/sbi/sbi_domain.h b/include/sbi/sbi_domain.h index a42c20ddf38..bbb3effa244 100644 --- a/include/sbi/sbi_domain.h +++ b/include/sbi/sbi_domain.h @@ -51,6 +51,11 @@ struct sbi_domain_memregion { SBI_DOMAIN_MEMREGION_M_WRITABLE | \ SBI_DOMAIN_MEMREGION_M_EXECUTABLE) +#define SBI_DOMAIN_MEMREGION_SU_RWX \ + (SBI_DOMAIN_MEMREGION_SU_READABLE | \ + SBI_DOMAIN_MEMREGION_SU_WRITABLE | \ + SBI_DOMAIN_MEMREGION_SU_EXECUTABLE) + /* Unrestricted M-mode accesses but enfoced on SU-mode */ #define SBI_DOMAIN_MEMREGION_READABLE \ (SBI_DOMAIN_MEMREGION_SU_READABLE | \ diff --git a/lib/utils/fdt/fdt_domain.c b/lib/utils/fdt/fdt_domain.c index 45612ef6924..2b51a8ebe13 100644 --- a/lib/utils/fdt/fdt_domain.c +++ b/lib/utils/fdt/fdt_domain.c @@ -239,6 +239,20 @@ static int __fdt_parse_region(void *fdt, int domain_offset, u32 *region_count = opaque; struct sbi_domain_memregion *region; + /* + * Non-root domains cannot add a region with only M-mode + * access permissions. M-mode regions can only be part of + * root domain. + * + * SU permission bits can't be all zeroes and M-mode permission + * bits must be all set. + */ + if (!((region_access & SBI_DOMAIN_MEMREGION_SU_ACCESS_MASK) + & SBI_DOMAIN_MEMREGION_SU_RWX) + && ((region_access & SBI_DOMAIN_MEMREGION_M_ACCESS_MASK) + & SBI_DOMAIN_MEMREGION_M_RWX)) + return SBI_EINVAL; + /* Find next region of the domain */ if (FDT_DOMAIN_REGION_MAX_COUNT <= *region_count) return SBI_EINVAL; From 59a08cd7d632bb2394a29956497dfe7829099997 Mon Sep 17 00:00:00 2001 From: Himanshu Chauhan Date: Mon, 9 Jan 2023 05:20:42 +0000 Subject: [PATCH 014/187] lib: utils: Add M-mode {R/W} flags to the MMIO regions Add the M-mode readable/writable flags to mmio regions of various drivers. Signed-off-by: Himanshu Chauhan Reviewed-by: Anup Patel Tested-by: Anup Patel --- lib/utils/ipi/aclint_mswi.c | 5 ++++- lib/utils/irqchip/aplic.c | 5 ++++- lib/utils/irqchip/imsic.c | 5 ++++- lib/utils/timer/aclint_mtimer.c | 16 ++++++++++++---- 4 files changed, 24 insertions(+), 7 deletions(-) diff --git a/lib/utils/ipi/aclint_mswi.c b/lib/utils/ipi/aclint_mswi.c index 832e223f08d..6b004cb9efb 100644 --- a/lib/utils/ipi/aclint_mswi.c +++ b/lib/utils/ipi/aclint_mswi.c @@ -88,7 +88,10 @@ int aclint_mswi_cold_init(struct aclint_mswi_data *mswi) region_size = ((mswi->size - pos) < ACLINT_MSWI_ALIGN) ? (mswi->size - pos) : ACLINT_MSWI_ALIGN; sbi_domain_memregion_init(mswi->addr + pos, region_size, - SBI_DOMAIN_MEMREGION_MMIO, ®); + (SBI_DOMAIN_MEMREGION_MMIO | + SBI_DOMAIN_MEMREGION_M_READABLE | + SBI_DOMAIN_MEMREGION_M_WRITABLE), + ®); rc = sbi_domain_root_add_memregion(®); if (rc) return rc; diff --git a/lib/utils/irqchip/aplic.c b/lib/utils/irqchip/aplic.c index 0a8469b618b..d7fd9928044 100644 --- a/lib/utils/irqchip/aplic.c +++ b/lib/utils/irqchip/aplic.c @@ -269,7 +269,10 @@ int aplic_cold_irqchip_init(struct aplic_data *aplic) (last_deleg_irq == aplic->num_source) && (first_deleg_irq == 1))) { sbi_domain_memregion_init(aplic->addr, aplic->size, - SBI_DOMAIN_MEMREGION_MMIO, ®); + (SBI_DOMAIN_MEMREGION_MMIO | + SBI_DOMAIN_MEMREGION_M_READABLE | + SBI_DOMAIN_MEMREGION_M_WRITABLE), + ®); rc = sbi_domain_root_add_memregion(®); if (rc) return rc; diff --git a/lib/utils/irqchip/imsic.c b/lib/utils/irqchip/imsic.c index 98f2cb63eeb..11667cd90df 100644 --- a/lib/utils/irqchip/imsic.c +++ b/lib/utils/irqchip/imsic.c @@ -313,7 +313,10 @@ int imsic_cold_irqchip_init(struct imsic_data *imsic) for (i = 0; i < IMSIC_MAX_REGS && imsic->regs[i].size; i++) { sbi_domain_memregion_init(imsic->regs[i].addr, imsic->regs[i].size, - SBI_DOMAIN_MEMREGION_MMIO, ®); + (SBI_DOMAIN_MEMREGION_MMIO | + SBI_DOMAIN_MEMREGION_M_READABLE | + SBI_DOMAIN_MEMREGION_M_WRITABLE), + ®); rc = sbi_domain_root_add_memregion(®); if (rc) return rc; diff --git a/lib/utils/timer/aclint_mtimer.c b/lib/utils/timer/aclint_mtimer.c index 1846a9a7cc9..84ded4ed44e 100644 --- a/lib/utils/timer/aclint_mtimer.c +++ b/lib/utils/timer/aclint_mtimer.c @@ -188,26 +188,34 @@ int aclint_mtimer_cold_init(struct aclint_mtimer_data *mt, rc = sbi_domain_root_add_memrange(mt->mtimecmp_addr, mt->mtime_size + mt->mtimecmp_size, MTIMER_REGION_ALIGN, - SBI_DOMAIN_MEMREGION_MMIO); + (SBI_DOMAIN_MEMREGION_MMIO | + SBI_DOMAIN_MEMREGION_M_READABLE | + SBI_DOMAIN_MEMREGION_M_WRITABLE)); if (rc) return rc; } else if (mt->mtimecmp_addr == (mt->mtime_addr + mt->mtime_size)) { rc = sbi_domain_root_add_memrange(mt->mtime_addr, mt->mtime_size + mt->mtimecmp_size, MTIMER_REGION_ALIGN, - SBI_DOMAIN_MEMREGION_MMIO); + (SBI_DOMAIN_MEMREGION_MMIO | + SBI_DOMAIN_MEMREGION_M_READABLE | + SBI_DOMAIN_MEMREGION_M_WRITABLE)); if (rc) return rc; } else { rc = sbi_domain_root_add_memrange(mt->mtime_addr, mt->mtime_size, MTIMER_REGION_ALIGN, - SBI_DOMAIN_MEMREGION_MMIO); + (SBI_DOMAIN_MEMREGION_MMIO | + SBI_DOMAIN_MEMREGION_M_READABLE | + SBI_DOMAIN_MEMREGION_M_WRITABLE)); if (rc) return rc; rc = sbi_domain_root_add_memrange(mt->mtimecmp_addr, mt->mtimecmp_size, MTIMER_REGION_ALIGN, - SBI_DOMAIN_MEMREGION_MMIO); + (SBI_DOMAIN_MEMREGION_MMIO | + SBI_DOMAIN_MEMREGION_M_READABLE | + SBI_DOMAIN_MEMREGION_M_WRITABLE)); if (rc) return rc; } From 001106d19b21cd6443ae7f7f6d4d048d80e9ecac Mon Sep 17 00:00:00 2001 From: Himanshu Chauhan Date: Mon, 9 Jan 2023 05:20:43 +0000 Subject: [PATCH 015/187] docs: Update domain's region permissions and requirements Updated the various permissions bits available for domains defined in DT node and restrictions on them. Signed-off-by: Himanshu Chauhan Reviewed-by: Anup Patel Tested-by: Anup Patel --- docs/domain_support.md | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/docs/domain_support.md b/docs/domain_support.md index c909d4a6878..4ccbcff8719 100644 --- a/docs/domain_support.md +++ b/docs/domain_support.md @@ -160,8 +160,16 @@ The DT properties of a domain instance DT node are as follows: * **regions** (Optional) - The list of domain memory region DT node phandle and access permissions for the domain instance. Each list entry is a pair of DT node phandle and access permissions. The access permissions are - represented as a 32bit bitmask having bits: **readable** (BIT[0]), - **writeable** (BIT[1]), **executable** (BIT[2]), and **M-mode** (BIT[3]). + represented as a 32bit bitmask having bits: **M readable** (BIT[0]), + **M writeable** (BIT[1]), **M executable** (BIT[2]), **SU readable** + (BIT[3]), **SU writable** (BIT[4]), and **SU executable** (BIT[5]). + The enforce permission bit (BIT[6]), if set, will lock the permissions + in the PMP. This will enforce the permissions on M-mode as well which + otherwise will have unrestricted access. This bit must be used with + caution because no changes can be made to a PMP entry once its locked + until the hart is reset. + Any region of a domain defined in DT node cannot have only M-bits set + in access permissions i.e. it cannot be an m-mode only accessible region. * **boot-hart** (Optional) - The DT node phandle of the HART booting the domain instance. If coldboot HART is assigned to the domain instance then this DT property is ignored and the coldboot HART is assumed to be the From da5594bf853d9c635aee14bce3abc1076641e395 Mon Sep 17 00:00:00 2001 From: Samuel Holland Date: Tue, 27 Dec 2022 12:44:44 -0600 Subject: [PATCH 016/187] platform: generic: allwinner: Fix PLIC array bounds The two referenced commits passed incorrect bounds to the PLIC save/ restore functions, causing out-of-bounds memory access. The functions expect "num" to be the 1-based number of interrupt sources, equivalent to the "riscv,ndev" devicetree property. Thus, "num" must be strictly smaller than the 0-based size of the array storing the register values. However, the referenced commits incorrectly passed in the unmodified size of the array as "num". Fix this by reducing PLIC_SOURCES (matching "riscv,ndev" on this platform), while keeping the same array sizes. Addresses-Coverity-ID: 1530251 ("Out-of-bounds access") Addresses-Coverity-ID: 1530252 ("Out-of-bounds access") Fixes: 8509e46ca63a ("lib: utils/irqchip: plic: Ensure no out-of-bound access in priority save/restore helpers") Fixes: 9a2eeb4aaeac ("lib: utils/irqchip: plic: Ensure no out-of-bound access in context save/restore helpers") Signed-off-by: Samuel Holland Reviewed-by: Anup Patel --- platform/generic/allwinner/sun20i-d1.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/platform/generic/allwinner/sun20i-d1.c b/platform/generic/allwinner/sun20i-d1.c index 1da9e5b5914..e2b76a33d95 100644 --- a/platform/generic/allwinner/sun20i-d1.c +++ b/platform/generic/allwinner/sun20i-d1.c @@ -69,10 +69,10 @@ static void sun20i_d1_csr_restore(void) * PLIC */ -#define PLIC_SOURCES 176 -#define PLIC_IE_WORDS ((PLIC_SOURCES + 31) / 32) +#define PLIC_SOURCES 175 +#define PLIC_IE_WORDS (PLIC_SOURCES / 32 + 1) -static u8 plic_priority[PLIC_SOURCES]; +static u8 plic_priority[1 + PLIC_SOURCES]; static u32 plic_sie[PLIC_IE_WORDS]; static u32 plic_threshold; From ce2a834c989043895d339df4d61221eca2b428e9 Mon Sep 17 00:00:00 2001 From: Yu Chien Peter Lin Date: Fri, 20 Jan 2023 11:05:07 +0800 Subject: [PATCH 017/187] docs: generic.md: fix typo of andes-ae350 Fix hyperlink due to the typo. Signed-off-by: Yu Chien Peter Lin Reviewed-by: Anup Patel --- docs/platform/generic.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/platform/generic.md b/docs/platform/generic.md index 8e4cf2d090c..c29eb047607 100644 --- a/docs/platform/generic.md +++ b/docs/platform/generic.md @@ -53,7 +53,7 @@ RISC-V Platforms Using Generic Platform * **Spike** (*[spike.md]*) * **T-HEAD C9xx series Processors** (*[thead-c9xx.md]*) -[andes-ae350.md]: andse-ae350.md +[andes-ae350.md]: andes-ae350.md [qemu_virt.md]: qemu_virt.md [renesas-rzfive.md]: renesas-rzfive.md [shakti_cclass.md]: shakti_cclass.md From 8ecbe6d3fba6a655b5b5d8e39381187826ac750f Mon Sep 17 00:00:00 2001 From: Yu Chien Peter Lin Date: Fri, 20 Jan 2023 11:05:08 +0800 Subject: [PATCH 018/187] lib: sbi_hsm: handle failure when hart_stop returns SBI_ENOTSUPP Make use of generic warm-boot path when platform hart_stop callback returns SBI_ENOTSUPP, in case certain hart can not turn off its power domain, or it detects some error occured in power management unit, it can fall through warm-boot flow and wait for interrupt in sbi_hsm_hart_wait(). Also improves comment in sbi_hsm_hart_wait(). Signed-off-by: Yu Chien Peter Lin Reviewed-by: Andrew Jones Reviewed-by: Atish Patra Reviewed-by: Anup Patel --- include/sbi/sbi_hsm.h | 8 ++++++-- lib/sbi/sbi_hsm.c | 7 +++---- 2 files changed, 9 insertions(+), 6 deletions(-) diff --git a/include/sbi/sbi_hsm.h b/include/sbi/sbi_hsm.h index c2a728a4aca..1170127baa8 100644 --- a/include/sbi/sbi_hsm.h +++ b/include/sbi/sbi_hsm.h @@ -21,8 +21,12 @@ struct sbi_hsm_device { int (*hart_start)(u32 hartid, ulong saddr); /** - * Stop (or power-down) the current hart from running. This call - * doesn't expect to return if success. + * Stop (or power-down) the current hart from running. + * + * Return SBI_ENOTSUPP if the hart does not support platform-specific + * stop actions. + * + * For successful stop, the call won't return. */ int (*hart_stop)(void); diff --git a/lib/sbi/sbi_hsm.c b/lib/sbi/sbi_hsm.c index c0a5505423b..d4cce4ac914 100644 --- a/lib/sbi/sbi_hsm.c +++ b/lib/sbi/sbi_hsm.c @@ -116,7 +116,7 @@ static void sbi_hsm_hart_wait(struct sbi_scratch *scratch, u32 hartid) /* Set MSIE and MEIE bits to receive IPI */ csr_set(CSR_MIE, MIP_MSIP | MIP_MEIP); - /* Wait for hart_add call*/ + /* Wait for state transition requested by sbi_hsm_hart_start() */ while (atomic_read(&hdata->state) != SBI_HSM_STATE_START_PENDING) { wfi(); }; @@ -228,9 +228,8 @@ void __noreturn sbi_hsm_exit(struct sbi_scratch *scratch) goto fail_exit; if (hsm_device_has_hart_hotplug()) { - hsm_device_hart_stop(); - /* It should never reach here */ - goto fail_exit; + if (hsm_device_hart_stop() != SBI_ENOTSUPP) + goto fail_exit; } /** From b1818ee244adae3c07fcd4494873a74f7aaeb21a Mon Sep 17 00:00:00 2001 From: Yu Chien Peter Lin Date: Fri, 20 Jan 2023 11:05:09 +0800 Subject: [PATCH 019/187] include: types: add always inline compiler attribute Provide __always_inline to sbi_types header. Signed-off-by: Yu Chien Peter Lin Reviewed-by: Anup Patel --- include/sbi/sbi_types.h | 1 + 1 file changed, 1 insertion(+) diff --git a/include/sbi/sbi_types.h b/include/sbi/sbi_types.h index 75cddddfe0d..9c1fef3b8dc 100644 --- a/include/sbi/sbi_types.h +++ b/include/sbi/sbi_types.h @@ -62,6 +62,7 @@ typedef unsigned long physical_size_t; #define __packed __attribute__((packed)) #define __noreturn __attribute__((noreturn)) #define __aligned(x) __attribute__((aligned(x))) +#define __always_inline inline __attribute__((always_inline)) #define likely(x) __builtin_expect((x), 1) #define unlikely(x) __builtin_expect((x), 0) From 9c4eb3521e515603671198295f2c7d5114e4c601 Mon Sep 17 00:00:00 2001 From: Yu Chien Peter Lin Date: Fri, 20 Jan 2023 11:05:10 +0800 Subject: [PATCH 020/187] lib: utils: atcsmu: Add Andes System Management Unit support This patch adds atcsmu support for Andes AE350 platforms. The SMU provides system management capabilities, including clock, reset and power control based on power domain partitions. Signed-off-by: Yu Chien Peter Lin Reviewed-by: Anup Patel --- include/sbi_utils/sys/atcsmu.h | 59 ++++++++++++++++++++++ lib/utils/sys/Kconfig | 4 ++ lib/utils/sys/atcsmu.c | 92 ++++++++++++++++++++++++++++++++++ lib/utils/sys/objects.mk | 1 + platform/generic/Kconfig | 1 + 5 files changed, 157 insertions(+) create mode 100644 include/sbi_utils/sys/atcsmu.h create mode 100644 lib/utils/sys/atcsmu.c diff --git a/include/sbi_utils/sys/atcsmu.h b/include/sbi_utils/sys/atcsmu.h new file mode 100644 index 00000000000..07be22eef62 --- /dev/null +++ b/include/sbi_utils/sys/atcsmu.h @@ -0,0 +1,59 @@ +/* + * SPDX-License-Identifier: BSD-3-Clause + * + * Copyright (c) 2023 Andes Technology Corporation + */ + +#ifndef _SYS_ATCSMU_H +#define _SYS_ATCSMU_H + +#include + +/* clang-format off */ + +#define PCS0_WE_OFFSET 0x90 +#define PCSm_WE_OFFSET(i) ((i + 3) * 0x20 + PCS0_WE_OFFSET) + +#define PCS0_CTL_OFFSET 0x94 +#define PCSm_CTL_OFFSET(i) ((i + 3) * 0x20 + PCS0_CTL_OFFSET) +#define PCS_CTL_CMD_SHIFT 0 +#define PCS_CTL_PARAM_SHIFT 3 +#define SLEEP_CMD 0x3 +#define WAKEUP_CMD (0x0 | (1 << PCS_CTL_PARAM_SHIFT)) +#define LIGHTSLEEP_MODE 0 +#define DEEPSLEEP_MODE 1 +#define LIGHT_SLEEP_CMD (SLEEP_CMD | (LIGHTSLEEP_MODE << PCS_CTL_PARAM_SHIFT)) +#define DEEP_SLEEP_CMD (SLEEP_CMD | (DEEPSLEEP_MODE << PCS_CTL_PARAM_SHIFT)) + +#define PCS0_CFG_OFFSET 0x80 +#define PCSm_CFG_OFFSET(i) ((i + 3) * 0x20 + PCS0_CFG_OFFSET) +#define PCS_CFG_LIGHT_SLEEP_SHIFT 2 +#define PCS_CFG_LIGHT_SLEEP (1 << PCS_CFG_LIGHT_SLEEP_SHIFT) +#define PCS_CFG_DEEP_SLEEP_SHIFT 3 +#define PCS_CFG_DEEP_SLEEP (1 << PCS_CFG_DEEP_SLEEP_SHIFT) + +#define RESET_VEC_LO_OFFSET 0x50 +#define RESET_VEC_HI_OFFSET 0x60 +#define RESET_VEC_8CORE_OFFSET 0x1a0 +#define HARTn_RESET_VEC_LO(n) (RESET_VEC_LO_OFFSET + \ + ((n) < 4 ? 0 : RESET_VEC_8CORE_OFFSET) + \ + ((n) * 0x4)) +#define HARTn_RESET_VEC_HI(n) (RESET_VEC_HI_OFFSET + \ + ((n) < 4 ? 0 : RESET_VEC_8CORE_OFFSET) + \ + ((n) * 0x4)) + +#define PCS_MAX_NR 8 +#define FLASH_BASE 0x80000000ULL + +/* clang-format on */ + +struct smu_data { + unsigned long addr; +}; + +int smu_set_wakeup_events(struct smu_data *smu, u32 events, u32 hartid); +bool smu_support_sleep_mode(struct smu_data *smu, u32 sleep_mode, u32 hartid); +int smu_set_command(struct smu_data *smu, u32 pcs_ctl, u32 hartid); +int smu_set_reset_vector(struct smu_data *smu, ulong wakeup_addr, u32 hartid); + +#endif /* _SYS_ATCSMU_H */ diff --git a/lib/utils/sys/Kconfig b/lib/utils/sys/Kconfig index ee85b1a3106..76190f8c52a 100644 --- a/lib/utils/sys/Kconfig +++ b/lib/utils/sys/Kconfig @@ -2,6 +2,10 @@ menu "System Device Support" +config SYS_ATCSMU + bool "Andes System Management Unit (SMU) support" + default n + config SYS_HTIF bool "Host transfere interface (HTIF) support" default n diff --git a/lib/utils/sys/atcsmu.c b/lib/utils/sys/atcsmu.c new file mode 100644 index 00000000000..8ddd88d5f52 --- /dev/null +++ b/lib/utils/sys/atcsmu.c @@ -0,0 +1,92 @@ +/* + * SPDX-License-Identifier: BSD-3-Clause + * + * Copyright (c) 2023 Andes Technology Corporation + * + * Authors: + * Yu Chien Peter Lin + */ + +#include +#include +#include +#include +#include + +inline int smu_set_wakeup_events(struct smu_data *smu, u32 events, u32 hartid) +{ + if (smu) { + writel(events, (void *)(smu->addr + PCSm_WE_OFFSET(hartid))); + return 0; + } else + return SBI_EINVAL; +} + +inline bool smu_support_sleep_mode(struct smu_data *smu, u32 sleep_mode, + u32 hartid) +{ + u32 pcs_cfg; + + if (!smu) { + sbi_printf("%s(): Failed to access smu_data\n", __func__); + return false; + } + + pcs_cfg = readl((void *)(smu->addr + PCSm_CFG_OFFSET(hartid))); + + switch (sleep_mode) { + case LIGHTSLEEP_MODE: + if (EXTRACT_FIELD(pcs_cfg, PCS_CFG_LIGHT_SLEEP) == 0) { + sbi_printf( + "SMU: hart%d (PCS%d) does not support light sleep mode\n", + hartid, hartid + 3); + return false; + } + break; + case DEEPSLEEP_MODE: + if (EXTRACT_FIELD(pcs_cfg, PCS_CFG_DEEP_SLEEP) == 0) { + sbi_printf( + "SMU: hart%d (PCS%d) does not support deep sleep mode\n", + hartid, hartid + 3); + return false; + } + break; + } + + return true; +} + +inline int smu_set_command(struct smu_data *smu, u32 pcs_ctl, u32 hartid) +{ + if (smu) { + writel(pcs_ctl, (void *)(smu->addr + PCSm_CTL_OFFSET(hartid))); + return 0; + } else + return SBI_EINVAL; +} + +inline int smu_set_reset_vector(struct smu_data *smu, ulong wakeup_addr, + u32 hartid) +{ + u32 vec_lo, vec_hi; + u64 reset_vector; + + if (!smu) + return SBI_EINVAL; + + writel(wakeup_addr, (void *)(smu->addr + HARTn_RESET_VEC_LO(hartid))); + writel((u64)wakeup_addr >> 32, + (void *)(smu->addr + HARTn_RESET_VEC_HI(hartid))); + + vec_lo = readl((void *)(smu->addr + HARTn_RESET_VEC_LO(hartid))); + vec_hi = readl((void *)(smu->addr + HARTn_RESET_VEC_HI(hartid))); + reset_vector = ((u64)vec_hi << 32) | vec_lo; + + if (reset_vector != (u64)wakeup_addr) { + sbi_printf( + "hard%d (PCS%d): Failed to program the reset vector.\n", + hartid, hartid + 3); + return SBI_EFAIL; + } else + return 0; +} diff --git a/lib/utils/sys/objects.mk b/lib/utils/sys/objects.mk index 9f67aee2777..03d6740b142 100644 --- a/lib/utils/sys/objects.mk +++ b/lib/utils/sys/objects.mk @@ -9,3 +9,4 @@ libsbiutils-objs-$(CONFIG_SYS_HTIF) += sys/htif.o libsbiutils-objs-$(CONFIG_SYS_SIFIVE_TEST) += sys/sifive_test.o +libsbiutils-objs-$(CONFIG_SYS_ATCSMU) += sys/atcsmu.o diff --git a/platform/generic/Kconfig b/platform/generic/Kconfig index 47c10e53a32..c7f198aee84 100644 --- a/platform/generic/Kconfig +++ b/platform/generic/Kconfig @@ -30,6 +30,7 @@ config PLATFORM_ALLWINNER_D1 config PLATFORM_ANDES_AE350 bool "Andes AE350 support" + select SYS_ATCSMU default n config PLATFORM_RENESAS_RZFIVE From 787296ae92b7ec5363dab71b6d036e8def31c6f7 Mon Sep 17 00:00:00 2001 From: Yu Chien Peter Lin Date: Fri, 20 Jan 2023 11:05:11 +0800 Subject: [PATCH 021/187] platform: andes/ae350: Implement hart hotplug using HSM extension Add hart_start() and hart_stop() callbacks for the multi-core ae350 platform, it utilizes the ATCSMU to put the harts into power-gated deep sleep mode. The programming sequence is stated as below: 1. Set the wakeup events to PCSm_WE 2. Set the sleep command to PCSm_CTL 3. Set the reset vector to HARTm_RESET_VECTOR_{LO|HI} 4. Write back and invalidate D-cache by executing the CCTL command L1D_WBINVAL_ALL 5. Disable I/D-cache by clearing mcache_ctl.{I|D}C_EN 6. Disable D-cache coherency by clearing mcache_ctl_.DC_COHEN 7. Wait for mcache_ctl.DC_COHSTA to be cleared to ensure the previous step is completed 8. Execute WFI Signed-off-by: Yu Chien Peter Lin Reviewed-by: Anup Patel --- platform/generic/andes/ae350.c | 99 ++++++++++++++++++++++++ platform/generic/andes/objects.mk | 2 +- platform/generic/andes/sleep.S | 70 +++++++++++++++++ platform/generic/include/andes/andes45.h | 10 +++ 4 files changed, 180 insertions(+), 1 deletion(-) create mode 100644 platform/generic/andes/sleep.S create mode 100644 platform/generic/include/andes/andes45.h diff --git a/platform/generic/andes/ae350.c b/platform/generic/andes/ae350.c index cf7f6f2a0f5..89f5b74af71 100644 --- a/platform/generic/andes/ae350.c +++ b/platform/generic/andes/ae350.c @@ -10,6 +10,104 @@ #include #include #include +#include +#include +#include +#include +#include +#include +#include + +static struct smu_data smu = { 0 }; +extern void __ae350_enable_coherency_warmboot(void); +extern void __ae350_disable_coherency(void); + +static __always_inline bool is_andes25(void) +{ + ulong marchid = csr_read(CSR_MARCHID); + return !!(EXTRACT_FIELD(marchid, CSR_MARCHID_MICROID) == 0xa25); +} + +static int ae350_hart_start(u32 hartid, ulong saddr) +{ + /* Don't send wakeup command at boot-time */ + if (!sbi_init_count(hartid) || (is_andes25() && hartid == 0)) + return sbi_ipi_raw_send(hartid); + + /* Write wakeup command to the sleep hart */ + smu_set_command(&smu, WAKEUP_CMD, hartid); + + return 0; +} + +static int ae350_hart_stop(void) +{ + int rc; + u32 hartid = current_hartid(); + + /** + * For Andes AX25MP, the hart0 shares power domain with + * L2-cache, instead of turning it off, it should fall + * through and jump to warmboot_addr. + */ + if (is_andes25() && hartid == 0) + return SBI_ENOTSUPP; + + if (!smu_support_sleep_mode(&smu, DEEPSLEEP_MODE, hartid)) + return SBI_ENOTSUPP; + + /** + * disable all events, the current hart will be + * woken up from reset vector when other hart + * writes its PCS (power control slot) control + * register + */ + smu_set_wakeup_events(&smu, 0x0, hartid); + smu_set_command(&smu, DEEP_SLEEP_CMD, hartid); + + rc = smu_set_reset_vector(&smu, (ulong)__ae350_enable_coherency_warmboot, + hartid); + if (rc) + goto fail; + + __ae350_disable_coherency(); + + wfi(); + +fail: + /* It should never reach here */ + sbi_hart_hang(); + return 0; +} + +static const struct sbi_hsm_device andes_smu = { + .name = "andes_smu", + .hart_start = ae350_hart_start, + .hart_stop = ae350_hart_stop, +}; + +static void ae350_hsm_device_init(void) +{ + int rc; + void *fdt; + + fdt = fdt_get_address(); + + rc = fdt_parse_compat_addr(fdt, (uint64_t *)&smu.addr, + "andestech,atcsmu"); + + if (!rc) { + sbi_hsm_set_device(&andes_smu); + } +} + +static int ae350_final_init(bool cold_boot, const struct fdt_match *match) +{ + if (cold_boot) + ae350_hsm_device_init(); + + return 0; +} static const struct fdt_match andes_ae350_match[] = { { .compatible = "andestech,ae350" }, @@ -18,4 +116,5 @@ static const struct fdt_match andes_ae350_match[] = { const struct platform_override andes_ae350 = { .match_table = andes_ae350_match, + .final_init = ae350_final_init, }; diff --git a/platform/generic/andes/objects.mk b/platform/generic/andes/objects.mk index dd6408de01f..28275efbccf 100644 --- a/platform/generic/andes/objects.mk +++ b/platform/generic/andes/objects.mk @@ -3,4 +3,4 @@ # carray-platform_override_modules-$(CONFIG_PLATFORM_ANDES_AE350) += andes_ae350 -platform-objs-$(CONFIG_PLATFORM_ANDES_AE350) += andes/ae350.o +platform-objs-$(CONFIG_PLATFORM_ANDES_AE350) += andes/ae350.o andes/sleep.o diff --git a/platform/generic/andes/sleep.S b/platform/generic/andes/sleep.S new file mode 100644 index 00000000000..59a5597d6d8 --- /dev/null +++ b/platform/generic/andes/sleep.S @@ -0,0 +1,70 @@ +/* + * SPDX-License-Identifier: BSD-2-Clause + * + * Copyright (c) 2023 Andes Technology Corporation + * + * Authors: + * Yu Chien Peter Lin + */ + +#include +#include +#include + + .section .text, "ax", %progbits + .align 3 + .global __ae350_disable_coherency +__ae350_disable_coherency: + /* flush d-cache */ + csrw CSR_MCCTLCOMMAND, 0x6 + /* disable i/d-cache */ + csrc CSR_MCACHE_CTL, 0x3 + /* disable d-cache coherency */ + lui t1, 0x80 + csrc CSR_MCACHE_CTL, t1 + /* + * wait for mcache_ctl.DC_COHSTA to be cleared, + * the bit is hard-wired 0 on platforms w/o CM + * (Coherence Manager) + */ +check_cm_disabled: + csrr t1, CSR_MCACHE_CTL + srli t1, t1, 20 + andi t1, t1, 0x1 + bnez t1, check_cm_disabled + + ret + + .section .text, "ax", %progbits + .align 3 + .global __ae350_enable_coherency +__ae350_enable_coherency: + /* enable d-cache coherency */ + lui t1, 0x80 + csrs CSR_MCACHE_CTL, t1 + /* + * mcache_ctl.DC_COHEN is hard-wired 0 on platforms + * w/o CM support + */ + csrr t1, CSR_MCACHE_CTL + srli t1, t1, 19 + andi t1, t1, 0x1 + beqz t1, enable_L1_cache + /* wait for mcache_ctl.DC_COHSTA to be set */ +check_cm_enabled: + csrr t1, CSR_MCACHE_CTL + srli t1, t1, 20 + andi t1, t1, 0x1 + beqz t1, check_cm_enabled +enable_L1_cache: + /* enable i/d-cache */ + csrs CSR_MCACHE_CTL, 0x3 + + ret + + .section .text, "ax", %progbits + .align 3 + .global __ae350_enable_coherency_warmboot +__ae350_enable_coherency_warmboot: + call ra, __ae350_enable_coherency + j _start_warm diff --git a/platform/generic/include/andes/andes45.h b/platform/generic/include/andes/andes45.h new file mode 100644 index 00000000000..08b3d18876e --- /dev/null +++ b/platform/generic/include/andes/andes45.h @@ -0,0 +1,10 @@ +#ifndef _RISCV_ANDES45_H +#define _RISCV_ANDES45_H + +#define CSR_MARCHID_MICROID 0xfff + +/* Memory and Miscellaneous Registers */ +#define CSR_MCACHE_CTL 0x7ca +#define CSR_MCCTLCOMMAND 0x7cc + +#endif /* _RISCV_ANDES45_H */ From 7aaeeab9e794e5a15a0253ef3c3453496f74117a Mon Sep 17 00:00:00 2001 From: Yu Chien Peter Lin Date: Fri, 20 Jan 2023 11:05:12 +0800 Subject: [PATCH 022/187] lib: reset/fdt_reset_atcwdt200: Use defined macros and function in atcsmu.h Reuse the smu related macros and function in atcsmu.h. Signed-off-by: Yu Chien Peter Lin Reviewed-by: Anup Patel --- lib/utils/reset/Kconfig | 1 + lib/utils/reset/fdt_reset_atcwdt200.c | 21 ++++++++------------- 2 files changed, 9 insertions(+), 13 deletions(-) diff --git a/lib/utils/reset/Kconfig b/lib/utils/reset/Kconfig index 0e0c2c1d7c4..4748cc8504a 100644 --- a/lib/utils/reset/Kconfig +++ b/lib/utils/reset/Kconfig @@ -11,6 +11,7 @@ if FDT_RESET config FDT_RESET_ATCWDT200 bool "Andes WDT FDT reset driver" + depends on SYS_ATCSMU default n config FDT_RESET_GPIO diff --git a/lib/utils/reset/fdt_reset_atcwdt200.c b/lib/utils/reset/fdt_reset_atcwdt200.c index 91acc9f7f11..03d547b9dd7 100644 --- a/lib/utils/reset/fdt_reset_atcwdt200.c +++ b/lib/utils/reset/fdt_reset_atcwdt200.c @@ -16,6 +16,7 @@ #include #include #include +#include #define ATCWDT200_WP_NUM 0x5aa5 #define WREN_REG 0x18 @@ -41,14 +42,8 @@ #define CLK_PCLK (1 << 1) #define WDT_EN (1 << 0) -#define FLASH_BASE 0x80000000ULL -#define SMU_RESET_VEC_LO_OFF 0x50 -#define SMU_RESET_VEC_HI_OFF 0x60 -#define SMU_HARTn_RESET_VEC_LO(n) (SMU_RESET_VEC_LO_OFF + (n * 0x4)) -#define SMU_HARTn_RESET_VEC_HI(n) (SMU_RESET_VEC_HI_OFF + (n * 0x4)) - -static volatile char *wdt_addr; -static volatile char *smu_addr; +static volatile char *wdt_addr = NULL; +static struct smu_data smu = { 0 }; static int ae350_system_reset_check(u32 type, u32 reason) { @@ -66,16 +61,16 @@ static void ae350_system_reset(u32 type, u32 reason) { const struct sbi_platform *plat = sbi_platform_thishart_ptr(); - for (int i = 0; i < sbi_platform_hart_count(plat); i++) { - writel(FLASH_BASE, smu_addr + SMU_HARTn_RESET_VEC_LO(i)); - writel(FLASH_BASE >> 32, smu_addr + SMU_HARTn_RESET_VEC_HI(i)); - } + for (int i = 0; i < sbi_platform_hart_count(plat); i++) + if (smu_set_reset_vector(&smu, FLASH_BASE, i)) + goto fail; /* Program WDT control register */ writew(ATCWDT200_WP_NUM, wdt_addr + WREN_REG); writel(INT_CLK_32768 | INT_EN | RST_CLK_128 | RST_EN | WDT_EN, wdt_addr + CTRL_REG); +fail: sbi_hart_hang(); } @@ -104,7 +99,7 @@ static int atcwdt200_reset_init(void *fdt, int nodeoff, if (fdt_parse_compat_addr(fdt, ®_addr, "andestech,atcsmu")) return SBI_ENODEV; - smu_addr = (volatile char *)(unsigned long)reg_addr; + smu.addr = (unsigned long)reg_addr; sbi_system_reset_add_device(&atcwdt200_reset); From a990309fa362aa050caf7fb175f35c7bfa486ccc Mon Sep 17 00:00:00 2001 From: Mayuresh Chitale Date: Sat, 21 Jan 2023 12:15:59 +0530 Subject: [PATCH 023/187] lib: utils: Fix reserved memory node for firmware memory The commit 9e0ba090 introduced more fine grained permissions for memory regions and did not update the fdt_reserved_memory_fixup() function. As a result, the fdt_reserved_memory_fixup continued to use the older coarse permissions which causes the reserved memory node to be not inserted into the DT. To fix the above issue, we correct the flags used for memory region permission checks in the fdt_reserved_memory_fixup() function. Fixes: 9e0ba090 ("include: sbi: Fine grain the permissions for M and SU modes") Signed-off-by: Mayuresh Chitale Reviewed-by: Anup Patel --- lib/utils/fdt/fdt_fixup.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/lib/utils/fdt/fdt_fixup.c b/lib/utils/fdt/fdt_fixup.c index 41f6cbb7023..42692cc4e25 100644 --- a/lib/utils/fdt/fdt_fixup.c +++ b/lib/utils/fdt/fdt_fixup.c @@ -259,11 +259,11 @@ int fdt_reserved_memory_fixup(void *fdt) /* Ignore MMIO or READABLE or WRITABLE or EXECUTABLE regions */ if (reg->flags & SBI_DOMAIN_MEMREGION_MMIO) continue; - if (reg->flags & SBI_DOMAIN_MEMREGION_READABLE) + if (reg->flags & SBI_DOMAIN_MEMREGION_SU_READABLE) continue; - if (reg->flags & SBI_DOMAIN_MEMREGION_WRITEABLE) + if (reg->flags & SBI_DOMAIN_MEMREGION_SU_WRITABLE) continue; - if (reg->flags & SBI_DOMAIN_MEMREGION_EXECUTABLE) + if (reg->flags & SBI_DOMAIN_MEMREGION_SU_EXECUTABLE) continue; addr = reg->base; From fefa5488038584a6376a8f361e74ccc2183dd50b Mon Sep 17 00:00:00 2001 From: Himanshu Chauhan Date: Thu, 19 Jan 2023 20:48:22 +0530 Subject: [PATCH 024/187] firmware: Split RO/RX and RW sections Split the RO/RX and RW sections so that they can have independent pmp entries with required permissions. The split size is ensured to be a power-of-2 as required by pmp. _fw_rw_offset symbol marks the beginning of the data section. Signed-off-by: Himanshu Chauhan Reviewed-by: Anup Patel --- firmware/fw_base.ldS | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/firmware/fw_base.ldS b/firmware/fw_base.ldS index 563ae252a3d..5411bbdc092 100644 --- a/firmware/fw_base.ldS +++ b/firmware/fw_base.ldS @@ -42,6 +42,14 @@ . = ALIGN(0x1000); /* Ensure next section is page aligned */ + /* + * PMP regions must be to be power-of-2. RO/RW will have separate + * regions, so ensure that the split is power-of-2. + */ + . = ALIGN(1 << LOG2CEIL(SIZEOF(.rodata) + SIZEOF(.text))); + + PROVIDE(_fw_rw_offset = (. - _fw_start)); + /* Beginning of the read-write data sections */ .data : From 2f40a99c9e0876ac543e918191b2e06ab8a0fdc5 Mon Sep 17 00:00:00 2001 From: Himanshu Chauhan Date: Thu, 19 Jan 2023 20:48:23 +0530 Subject: [PATCH 025/187] firmware: Move dynsym and reladyn sections to RX section Currently, the dynsym and reladyn sections are under RW data. They are moved to the Read-only/Executable region. Signed-off-by: Himanshu Chauhan Reviewed-by: Anup Patel --- firmware/fw_base.ldS | 41 ++++++++++++++++++++++------------------- 1 file changed, 22 insertions(+), 19 deletions(-) diff --git a/firmware/fw_base.ldS b/firmware/fw_base.ldS index 5411bbdc092..9a1304e98ec 100644 --- a/firmware/fw_base.ldS +++ b/firmware/fw_base.ldS @@ -30,23 +30,39 @@ /* Beginning of the read-only data sections */ + PROVIDE(_rodata_start = .); + .rodata : { - PROVIDE(_rodata_start = .); *(.rodata .rodata.*) . = ALIGN(8); - PROVIDE(_rodata_end = .); } - /* End of the read-only data sections */ - . = ALIGN(0x1000); /* Ensure next section is page aligned */ + .dynsym : { + PROVIDE(__dyn_sym_start = .); + *(.dynsym) + PROVIDE(__dyn_sym_end = .); + } + + .rela.dyn : { + PROVIDE(__rel_dyn_start = .); + *(.rela*) + . = ALIGN(8); + PROVIDE(__rel_dyn_end = .); + } + + PROVIDE(_rodata_end = .); + + /* End of the read-only data sections */ + /* - * PMP regions must be to be power-of-2. RO/RW will have separate + * PMP regions must be to be power-of-2. RX/RW will have separate * regions, so ensure that the split is power-of-2. */ - . = ALIGN(1 << LOG2CEIL(SIZEOF(.rodata) + SIZEOF(.text))); + . = ALIGN(1 << LOG2CEIL((SIZEOF(.rodata) + SIZEOF(.text) + + SIZEOF(.dynsym) + SIZEOF(.rela.dyn)))); PROVIDE(_fw_rw_offset = (. - _fw_start)); @@ -67,19 +83,6 @@ PROVIDE(_data_end = .); } - .dynsym : { - PROVIDE(__dyn_sym_start = .); - *(.dynsym) - PROVIDE(__dyn_sym_end = .); - } - - .rela.dyn : { - PROVIDE(__rel_dyn_start = .); - *(.rela*) - . = ALIGN(8); - PROVIDE(__rel_dyn_end = .); - } - . = ALIGN(0x1000); /* Ensure next section is page aligned */ .bss : From c10e3fe5f9a14de3f001a6b007b7d9f117858dff Mon Sep 17 00:00:00 2001 From: Himanshu Chauhan Date: Thu, 19 Jan 2023 20:48:24 +0530 Subject: [PATCH 026/187] firmware: Add RW section offset in scratch Add the RW section offset, provided by _fw_rw_offset symbol, to the scratch structure. This will be used to program separate pmp entry for RW section. Signed-off-by: Himanshu Chauhan Reviewed-by: Anup Patel --- firmware/fw_base.S | 8 ++++++++ include/sbi/sbi_scratch.h | 24 ++++++++++++++---------- 2 files changed, 22 insertions(+), 10 deletions(-) diff --git a/firmware/fw_base.S b/firmware/fw_base.S index 3f622b3b39a..e04b683331d 100644 --- a/firmware/fw_base.S +++ b/firmware/fw_base.S @@ -298,6 +298,12 @@ _scratch_init: sub a5, t3, a4 REG_S a4, SBI_SCRATCH_FW_START_OFFSET(tp) REG_S a5, SBI_SCRATCH_FW_SIZE_OFFSET(tp) + + /* Store R/W section's offset in scratch space */ + lla a4, __fw_rw_offset + REG_L a5, 0(a4) + REG_S a5, SBI_SCRATCH_FW_RW_OFFSET(tp) + /* Store next arg1 in scratch space */ MOV_3R s0, a0, s1, a1, s2, a2 call fw_next_arg1 @@ -519,6 +525,8 @@ _link_start: RISCV_PTR FW_TEXT_START _link_end: RISCV_PTR _fw_reloc_end +__fw_rw_offset: + RISCV_PTR _fw_rw_offset .section .entry, "ax", %progbits .align 3 diff --git a/include/sbi/sbi_scratch.h b/include/sbi/sbi_scratch.h index 40a3bc93c6d..2966188d699 100644 --- a/include/sbi/sbi_scratch.h +++ b/include/sbi/sbi_scratch.h @@ -18,26 +18,28 @@ #define SBI_SCRATCH_FW_START_OFFSET (0 * __SIZEOF_POINTER__) /** Offset of fw_size member in sbi_scratch */ #define SBI_SCRATCH_FW_SIZE_OFFSET (1 * __SIZEOF_POINTER__) +/** Offset (in sbi_scratch) of the R/W Offset */ +#define SBI_SCRATCH_FW_RW_OFFSET (2 * __SIZEOF_POINTER__) /** Offset of next_arg1 member in sbi_scratch */ -#define SBI_SCRATCH_NEXT_ARG1_OFFSET (2 * __SIZEOF_POINTER__) +#define SBI_SCRATCH_NEXT_ARG1_OFFSET (3 * __SIZEOF_POINTER__) /** Offset of next_addr member in sbi_scratch */ -#define SBI_SCRATCH_NEXT_ADDR_OFFSET (3 * __SIZEOF_POINTER__) +#define SBI_SCRATCH_NEXT_ADDR_OFFSET (4 * __SIZEOF_POINTER__) /** Offset of next_mode member in sbi_scratch */ -#define SBI_SCRATCH_NEXT_MODE_OFFSET (4 * __SIZEOF_POINTER__) +#define SBI_SCRATCH_NEXT_MODE_OFFSET (5 * __SIZEOF_POINTER__) /** Offset of warmboot_addr member in sbi_scratch */ -#define SBI_SCRATCH_WARMBOOT_ADDR_OFFSET (5 * __SIZEOF_POINTER__) +#define SBI_SCRATCH_WARMBOOT_ADDR_OFFSET (6 * __SIZEOF_POINTER__) /** Offset of platform_addr member in sbi_scratch */ -#define SBI_SCRATCH_PLATFORM_ADDR_OFFSET (6 * __SIZEOF_POINTER__) +#define SBI_SCRATCH_PLATFORM_ADDR_OFFSET (7 * __SIZEOF_POINTER__) /** Offset of hartid_to_scratch member in sbi_scratch */ -#define SBI_SCRATCH_HARTID_TO_SCRATCH_OFFSET (7 * __SIZEOF_POINTER__) +#define SBI_SCRATCH_HARTID_TO_SCRATCH_OFFSET (8 * __SIZEOF_POINTER__) /** Offset of trap_exit member in sbi_scratch */ -#define SBI_SCRATCH_TRAP_EXIT_OFFSET (8 * __SIZEOF_POINTER__) +#define SBI_SCRATCH_TRAP_EXIT_OFFSET (9 * __SIZEOF_POINTER__) /** Offset of tmp0 member in sbi_scratch */ -#define SBI_SCRATCH_TMP0_OFFSET (9 * __SIZEOF_POINTER__) +#define SBI_SCRATCH_TMP0_OFFSET (10 * __SIZEOF_POINTER__) /** Offset of options member in sbi_scratch */ -#define SBI_SCRATCH_OPTIONS_OFFSET (10 * __SIZEOF_POINTER__) +#define SBI_SCRATCH_OPTIONS_OFFSET (11 * __SIZEOF_POINTER__) /** Offset of extra space in sbi_scratch */ -#define SBI_SCRATCH_EXTRA_SPACE_OFFSET (11 * __SIZEOF_POINTER__) +#define SBI_SCRATCH_EXTRA_SPACE_OFFSET (12 * __SIZEOF_POINTER__) /** Maximum size of sbi_scratch (4KB) */ #define SBI_SCRATCH_SIZE (0x1000) @@ -53,6 +55,8 @@ struct sbi_scratch { unsigned long fw_start; /** Size (in bytes) of firmware linked to OpenSBI library */ unsigned long fw_size; + /** Offset (in bytes) of the R/W section */ + unsigned long fw_rw_offset; /** Arg1 (or 'a1' register) of next booting stage for this HART */ unsigned long next_arg1; /** Address of next booting stage for this HART */ From b666760bfafda75b6d31d6f9f01bcc60bc673aa4 Mon Sep 17 00:00:00 2001 From: Himanshu Chauhan Date: Thu, 19 Jan 2023 20:48:25 +0530 Subject: [PATCH 027/187] lib: sbi: Print the RW section offset Print the RW section offset when firmware base and size is being printed. Signed-off-by: Himanshu Chauhan Reviewed-by: Anup Patel --- lib/sbi/sbi_init.c | 1 + 1 file changed, 1 insertion(+) diff --git a/lib/sbi/sbi_init.c b/lib/sbi/sbi_init.c index 259a191051a..e353c334830 100644 --- a/lib/sbi/sbi_init.c +++ b/lib/sbi/sbi_init.c @@ -108,6 +108,7 @@ static void sbi_boot_print_general(struct sbi_scratch *scratch) sbi_printf("Firmware Base : 0x%lx\n", scratch->fw_start); sbi_printf("Firmware Size : %d KB\n", (u32)(scratch->fw_size / 1024)); + sbi_printf("Firmware RW Offset : 0x%lx\n", scratch->fw_rw_offset); /* SBI details */ sbi_printf("Runtime SBI Version : %d.%d\n", From 230278dcf127e2a336d54748f03b5bc280656498 Mon Sep 17 00:00:00 2001 From: Himanshu Chauhan Date: Thu, 19 Jan 2023 20:48:26 +0530 Subject: [PATCH 028/187] lib: sbi: Add separate entries for firmware RX and RW regions Add two entries for firmware in the root domain: 1. TEXT: fw_start to _fw_rw_offset with RX permissions 2. DATA: _fw_rw_offset to fw_size with RW permissions These permissions are still not enforced from M-mode but lay the ground work for enforcing them for M-mode. SU-mode don't have any access to these regions. Sample output: Domain0 Region01 : 0x0000000080000000-0x000000008001ffff M: (R,X) S/U: () Domain0 Region02 : 0x0000000080020000-0x000000008003ffff M: (R,W) S/U: () Signed-off-by: Himanshu Chauhan Reviewed-by: Anup Patel --- lib/sbi/sbi_domain.c | 24 ++++++++++++++++++++++-- 1 file changed, 22 insertions(+), 2 deletions(-) diff --git a/lib/sbi/sbi_domain.c b/lib/sbi/sbi_domain.c index 60fda012d7b..3ab1fbe0b7d 100644 --- a/lib/sbi/sbi_domain.c +++ b/lib/sbi/sbi_domain.c @@ -638,12 +638,32 @@ int sbi_domain_init(struct sbi_scratch *scratch, u32 cold_hartid) u32 i; const struct sbi_platform *plat = sbi_platform_ptr(scratch); + if (scratch->fw_rw_offset == 0 || + (scratch->fw_rw_offset & (scratch->fw_rw_offset - 1)) != 0) { + sbi_printf("%s: fw_rw_offset is not a power of 2 (0x%lx)\n", + __func__, scratch->fw_rw_offset); + return SBI_EINVAL; + } + + if ((scratch->fw_start & (scratch->fw_rw_offset - 1)) != 0) { + sbi_printf("%s: fw_start and fw_rw_offset not aligned\n", + __func__); + return SBI_EINVAL; + } + /* Root domain firmware memory region */ - sbi_domain_memregion_init(scratch->fw_start, scratch->fw_size, - SBI_DOMAIN_MEMREGION_M_RWX, + sbi_domain_memregion_init(scratch->fw_start, scratch->fw_rw_offset, + (SBI_DOMAIN_MEMREGION_M_READABLE | + SBI_DOMAIN_MEMREGION_M_EXECUTABLE), &root_fw_region); domain_memregion_initfw(&root_memregs[root_memregs_count++]); + sbi_domain_memregion_init((scratch->fw_start + scratch->fw_rw_offset), + (scratch->fw_size - scratch->fw_rw_offset), + (SBI_DOMAIN_MEMREGION_M_READABLE | + SBI_DOMAIN_MEMREGION_M_WRITABLE), + &root_memregs[root_memregs_count++]); + /* Root domain allow everything memory region */ sbi_domain_memregion_init(0, ~0UL, (SBI_DOMAIN_MEMREGION_READABLE | From dea0922f867f3d681ad3191fb562a082ea4a339f Mon Sep 17 00:00:00 2001 From: Lad Prabhakar Date: Fri, 13 Jan 2023 16:47:19 +0000 Subject: [PATCH 029/187] platform: renesas/rzfive: Configure Local memory regions as part of root domain Renesas RZ/Five RISC-V SoC has Instruction local memory and Data local memory (ILM & DLM) mapped between region 0x30000 - 0x4FFFF. When a virtual address falls within this range, the MMU doesn't trigger a page fault; it assumes the virtual address is a physical address which can cause undesired behaviours for statically linked applications/libraries. To avoid this, add the ILM/DLM memory regions to the root domain region of the PMPU with permissions set to 0x0 for S/U modes so that any access to these regions gets blocked and for M-mode we grant full access (R/W/X). Signed-off-by: Lad Prabhakar Reviewed-by: Anup Patel --- platform/generic/renesas/rzfive/rzfive.c | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/platform/generic/renesas/rzfive/rzfive.c b/platform/generic/renesas/rzfive/rzfive.c index ca182e3136f..ee9c9c4eba9 100644 --- a/platform/generic/renesas/rzfive/rzfive.c +++ b/platform/generic/renesas/rzfive/rzfive.c @@ -5,8 +5,27 @@ */ #include +#include #include +int renesas_rzfive_early_init(bool cold_boot, const struct fdt_match *match) +{ + /* + * Renesas RZ/Five RISC-V SoC has Instruction local memory and + * Data local memory (ILM & DLM) mapped between region 0x30000 + * to 0x4FFFF. When a virtual address falls within this range, + * the MMU doesn't trigger a page fault; it assumes the virtual + * address is a physical address which can cause undesired + * behaviours for statically linked applications/libraries. To + * avoid this, add the ILM/DLM memory regions to the root domain + * region of the PMPU with permissions set to 0x0 for S/U modes + * so that any access to these regions gets blocked and for M-mode + * we grant full access. + */ + return sbi_domain_root_add_memrange(0x30000, 0x20000, 0x1000, + SBI_DOMAIN_MEMREGION_M_RWX); +} + static const struct fdt_match renesas_rzfive_match[] = { { .compatible = "renesas,r9a07g043f01" }, { /* sentinel */ } @@ -14,4 +33,5 @@ static const struct fdt_match renesas_rzfive_match[] = { const struct platform_override renesas_rzfive = { .match_table = renesas_rzfive_match, + .early_init = renesas_rzfive_early_init, }; From 33bf9174602c900201481241e9ade31cf37fccd8 Mon Sep 17 00:00:00 2001 From: Samuel Holland Date: Mon, 23 Jan 2023 00:32:06 -0600 Subject: [PATCH 030/187] lib: utils: Add fdt_add_cpu_idle_states() helper function Since the availability and latency properties of CPU idle states depend on the specific SBI HSM implementation, it is appropriate that the idle states are added to the devicetree at runtime by that implementation. This helper function adds a platform-provided array of idle states to the devicetree, following the SBI idle state binding. Reviewed-by: Anup Patel Signed-off-by: Samuel Holland --- include/sbi_utils/fdt/fdt_fixup.h | 23 +++++++++ lib/utils/fdt/fdt_fixup.c | 85 +++++++++++++++++++++++++++++++ 2 files changed, 108 insertions(+) diff --git a/include/sbi_utils/fdt/fdt_fixup.h b/include/sbi_utils/fdt/fdt_fixup.h index fb076bad76c..cab3f0f2a99 100644 --- a/include/sbi_utils/fdt/fdt_fixup.h +++ b/include/sbi_utils/fdt/fdt_fixup.h @@ -9,6 +9,29 @@ #ifndef __FDT_FIXUP_H__ #define __FDT_FIXUP_H__ +struct sbi_cpu_idle_state { + const char *name; + uint32_t suspend_param; + bool local_timer_stop; + uint32_t entry_latency_us; + uint32_t exit_latency_us; + uint32_t min_residency_us; + uint32_t wakeup_latency_us; +}; + +/** + * Add CPU idle states to cpu nodes in the DT + * + * Add information about CPU idle states to the devicetree. This function + * assumes that CPU idle states are not already present in the devicetree, and + * that all CPU states are equally applicable to all CPUs. + * + * @param fdt: device tree blob + * @param states: array of idle state descriptions, ending with empty element + * @return zero on success and -ve on failure + */ +int fdt_add_cpu_idle_states(void *dtb, const struct sbi_cpu_idle_state *state); + /** * Fix up the CPU node in the device tree * diff --git a/lib/utils/fdt/fdt_fixup.c b/lib/utils/fdt/fdt_fixup.c index 42692cc4e25..e57a4e1da27 100644 --- a/lib/utils/fdt/fdt_fixup.c +++ b/lib/utils/fdt/fdt_fixup.c @@ -18,6 +18,91 @@ #include #include +int fdt_add_cpu_idle_states(void *fdt, const struct sbi_cpu_idle_state *state) +{ + int cpu_node, cpus_node, err, idle_states_node; + uint32_t count, phandle; + + err = fdt_open_into(fdt, fdt, fdt_totalsize(fdt) + 1024); + if (err < 0) + return err; + + err = fdt_find_max_phandle(fdt, &phandle); + phandle++; + if (err < 0) + return err; + + cpus_node = fdt_path_offset(fdt, "/cpus"); + if (cpus_node < 0) + return cpus_node; + + /* Do nothing if the idle-states node already exists. */ + idle_states_node = fdt_subnode_offset(fdt, cpus_node, "idle-states"); + if (idle_states_node >= 0) + return 0; + + /* Create the idle-states node and its child nodes. */ + idle_states_node = fdt_add_subnode(fdt, cpus_node, "idle-states"); + if (idle_states_node < 0) + return idle_states_node; + + for (count = 0; state->name; count++, phandle++, state++) { + int idle_state_node; + + idle_state_node = fdt_add_subnode(fdt, idle_states_node, + state->name); + if (idle_state_node < 0) + return idle_state_node; + + fdt_setprop_string(fdt, idle_state_node, "compatible", + "riscv,idle-state"); + fdt_setprop_u32(fdt, idle_state_node, + "riscv,sbi-suspend-param", + state->suspend_param); + if (state->local_timer_stop) + fdt_setprop_empty(fdt, idle_state_node, + "local-timer-stop"); + fdt_setprop_u32(fdt, idle_state_node, "entry-latency-us", + state->entry_latency_us); + fdt_setprop_u32(fdt, idle_state_node, "exit-latency-us", + state->exit_latency_us); + fdt_setprop_u32(fdt, idle_state_node, "min-residency-us", + state->min_residency_us); + if (state->wakeup_latency_us) + fdt_setprop_u32(fdt, idle_state_node, + "wakeup-latency-us", + state->wakeup_latency_us); + fdt_setprop_u32(fdt, idle_state_node, "phandle", phandle); + } + + if (count == 0) + return 0; + + /* Link each cpu node to the idle state nodes. */ + fdt_for_each_subnode(cpu_node, fdt, cpus_node) { + const char *device_type; + fdt32_t *value; + + /* Only process child nodes with device_type = "cpu". */ + device_type = fdt_getprop(fdt, cpu_node, "device_type", NULL); + if (!device_type || strcmp(device_type, "cpu")) + continue; + + /* Allocate space for the list of phandles. */ + err = fdt_setprop_placeholder(fdt, cpu_node, "cpu-idle-states", + count * sizeof(phandle), + (void **)&value); + if (err < 0) + return err; + + /* Fill in the phandles of the idle state nodes. */ + for (uint32_t i = 0; i < count; ++i) + value[i] = cpu_to_fdt32(phandle - count + i); + } + + return 0; +} + void fdt_cpu_fixup(void *fdt) { struct sbi_domain *dom = sbi_domain_thishart_ptr(); From c45992cc2b121e05c74b438462b8066de3e7d999 Mon Sep 17 00:00:00 2001 From: Samuel Holland Date: Mon, 23 Jan 2023 00:32:07 -0600 Subject: [PATCH 031/187] platform: generic: allwinner: Advertise nonretentive suspend Add D1's nonretentive suspend state to the devicetree so S-mode software knows about it and can use it. Latency and power measurements were taken on an Allwinner Nezha board: - Entry latency was measured from the beginning of sbi_ecall_handler() to before the call to wfi() in sun20i_d1_hart_suspend(). - Exit latency was measured from the beginning of sbi_init() to before the call to sbi_hart_switch_mode() in init_warmboot(). - There was a 17.5 mW benefit from non-retentive suspend compared to WFI, with a 170 mW cost during the 107 us entry/exit period. This provides a break-even point around 1040 us. Residency includes entry latency, so round this up to 1100 us. - The hardware power sequence latency (after the WFI) is assumed to be negligible, so set the wakeup latency to the exit latency. Reviewed-by: Anup Patel Signed-off-by: Samuel Holland --- platform/generic/allwinner/sun20i-d1.c | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/platform/generic/allwinner/sun20i-d1.c b/platform/generic/allwinner/sun20i-d1.c index e2b76a33d95..295c1593db1 100644 --- a/platform/generic/allwinner/sun20i-d1.c +++ b/platform/generic/allwinner/sun20i-d1.c @@ -12,6 +12,7 @@ #include #include #include +#include #include #include @@ -202,6 +203,24 @@ static int sun20i_d1_final_init(bool cold_boot, const struct fdt_match *match) return 0; } +static const struct sbi_cpu_idle_state sun20i_d1_cpu_idle_states[] = { + { + .name = "cpu-nonretentive", + .suspend_param = SBI_HSM_SUSPEND_NON_RET_DEFAULT, + .local_timer_stop = true, + .entry_latency_us = 40, + .exit_latency_us = 67, + .min_residency_us = 1100, + .wakeup_latency_us = 67, + }, + { } +}; + +static int sun20i_d1_fdt_fixup(void *fdt, const struct fdt_match *match) +{ + return fdt_add_cpu_idle_states(fdt, sun20i_d1_cpu_idle_states); +} + static void thead_c9xx_pmu_ctr_enable_irq(uint32_t ctr_idx) { unsigned long mip_val; @@ -265,5 +284,6 @@ static const struct fdt_match sun20i_d1_match[] = { const struct platform_override sun20i_d1 = { .match_table = sun20i_d1_match, .final_init = sun20i_d1_final_init, + .fdt_fixup = sun20i_d1_fdt_fixup, .extensions_init = sun20i_d1_extensions_init, }; From c8ea836ee33eb778f48f780412e147386dac5301 Mon Sep 17 00:00:00 2001 From: Jessica Clarke Date: Thu, 26 Jan 2023 21:10:03 +0530 Subject: [PATCH 032/187] firmware: Fix fw_rw_offset computation in fw_base.S MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit It seems BFD just does totally nonsensical things for SHN_ABS symbols when producing position-independent outputs (both -pie and -shared) for various historical reasons, and so SHN_ABS symbols are still subject to relocation as far as BFD is concerned (except AArch64, which fixes it in limited cases that don’t apply here...). The above affects the _fw_rw_offset provided through fw_base.ldS linker script which results in OpenSBI firmware failing to boot when loaded at an address different from FW_TEXT_START. Fixes: c10e3fe5f9a1 ("firmware: Add RW section offset in scratch") Signed-off-by: Jessica Clarke Reported-by: Lad Prabhakar Tested-by: Lad Prabhakar Tested-by: Anup Patel Signed-off-by: Anup Patel --- firmware/fw_base.S | 2 +- firmware/fw_base.ldS | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/firmware/fw_base.S b/firmware/fw_base.S index e04b683331d..fb6ac926978 100644 --- a/firmware/fw_base.S +++ b/firmware/fw_base.S @@ -526,7 +526,7 @@ _link_start: _link_end: RISCV_PTR _fw_reloc_end __fw_rw_offset: - RISCV_PTR _fw_rw_offset + RISCV_PTR _fw_rw_start - _fw_start .section .entry, "ax", %progbits .align 3 diff --git a/firmware/fw_base.ldS b/firmware/fw_base.ldS index 9a1304e98ec..3d68484ba5e 100644 --- a/firmware/fw_base.ldS +++ b/firmware/fw_base.ldS @@ -64,7 +64,7 @@ . = ALIGN(1 << LOG2CEIL((SIZEOF(.rodata) + SIZEOF(.text) + SIZEOF(.dynsym) + SIZEOF(.rela.dyn)))); - PROVIDE(_fw_rw_offset = (. - _fw_start)); + PROVIDE(_fw_rw_start = .); /* Beginning of the read-write data sections */ From 8050081f68b2b66f8937b15a6753ec6408c2fdee Mon Sep 17 00:00:00 2001 From: Nick Hu Date: Tue, 17 Jan 2023 16:14:27 +0800 Subject: [PATCH 033/187] firmware: Not to clear all the MIP In generic behavior of QEMU, if the pending bits of PLIC are still set and we clear the SEIP, the QEMU may not set the SEIP back immediately and the interrupt may not be handled anymore until the new interrupts arrived and QEMU set the SEIP back which is a generic behavior in QEMU. Signed-off-by: Nick Hu Signed-off-by: Jim Shu Reviewed-by: Anup Patel --- firmware/fw_base.S | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/firmware/fw_base.S b/firmware/fw_base.S index fb6ac926978..ceef44f26b1 100644 --- a/firmware/fw_base.S +++ b/firmware/fw_base.S @@ -428,9 +428,15 @@ _start_warm: li ra, 0 call _reset_regs - /* Disable and clear all interrupts */ + /* Disable all interrupts */ csrw CSR_MIE, zero - csrw CSR_MIP, zero + /* + * Only clear the MIP_SSIP and MIP_STIP. For the platform like QEMU, + * If we clear other interrupts like MIP_SEIP and the pendings of + * PLIC still exist, the QEMU may not set it back immediately. + */ + li t0, (MIP_SSIP | MIP_STIP) + csrc CSR_MIP, t0 /* Find HART count and HART stack size */ lla a4, platform From 84d15f4f529c92d3f32fbc570c02f7d40e9e70cb Mon Sep 17 00:00:00 2001 From: Nick Hu Date: Tue, 17 Jan 2023 16:14:28 +0800 Subject: [PATCH 034/187] lib: sbi_hsm: Use csr_set to restore the MIP If we use the csr_write to restore the MIP, we may clear the SEIP. In generic behavior of QEMU, if the pending bits of PLIC are set and we clear the SEIP, the QEMU may not set it back immediately. It may cause the interrupts won't be handled anymore until the new interrupts arrived and QEMU set the bits back. Signed-off-by: Nick Hu Signed-off-by: Jim Shu Reviewed-by: Anup Patel --- lib/sbi/sbi_hsm.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/sbi/sbi_hsm.c b/lib/sbi/sbi_hsm.c index d4cce4ac914..8499bb1ddea 100644 --- a/lib/sbi/sbi_hsm.c +++ b/lib/sbi/sbi_hsm.c @@ -357,7 +357,7 @@ static void __sbi_hsm_suspend_non_ret_restore(struct sbi_scratch *scratch) hart_data_offset); csr_write(CSR_MIE, hdata->saved_mie); - csr_write(CSR_MIP, (hdata->saved_mip & (MIP_SSIP | MIP_STIP))); + csr_set(CSR_MIP, (hdata->saved_mip & (MIP_SSIP | MIP_STIP))); } void sbi_hsm_hart_resume_start(struct sbi_scratch *scratch) From 199189bd1c172aab5a9733c0ffaaa14bbebb3323 Mon Sep 17 00:00:00 2001 From: Himanshu Chauhan Date: Fri, 27 Jan 2023 09:49:23 +0530 Subject: [PATCH 035/187] lib: utils: Mark only the largest region as reserved in FDT In commit 230278dcf, RX and RW regions were marked separately. When the RW region grows (e.g. with more harts) and it isn't a power-of-two, sbi_domain_memregion_init will upgrade the region to the next power-of-two. This will make RX and RW both start at the same base address, like so (with 64 harts): Domain0 Region01 : 0x0000000080000000-0x000000008001ffff M: (R,X) S/U: () Domain0 Region02 : 0x0000000080000000-0x00000000800fffff M: (R,W) S/U: () This doesn't break the permission enforcement because of static priorities in PMP but makes the kernel complain about the regions overlapping each other. Like so: [ 0.000000] OF: reserved mem: OVERLAP DETECTED! [ 0.000000] mmode_resv0@80000000 (0x0000000080000000--0x0000000080020000) \ overlaps with mmode_resv1@80000000 (0x0000000080000000--0x0000000080100000) To fix this warning, among the multiple regions having same base address but different sizes, add only the largest region as reserved region during fdt fixup. Fixes: 230278dcf (lib: sbi: Add separate entries for firmware RX and RW regions) Signed-off-by: Himanshu Chauhan Reviewed-by: Anup Patel --- lib/utils/fdt/fdt_fixup.c | 34 ++++++++++++++++++++++++++++++---- 1 file changed, 30 insertions(+), 4 deletions(-) diff --git a/lib/utils/fdt/fdt_fixup.c b/lib/utils/fdt/fdt_fixup.c index e57a4e1da27..619e4f5cbaf 100644 --- a/lib/utils/fdt/fdt_fixup.c +++ b/lib/utils/fdt/fdt_fixup.c @@ -1,3 +1,4 @@ + // SPDX-License-Identifier: BSD-2-Clause /* * fdt_fixup.c - Flat Device Tree parsing helper routines @@ -14,6 +15,7 @@ #include #include #include +#include #include #include #include @@ -285,8 +287,10 @@ int fdt_reserved_memory_fixup(void *fdt) struct sbi_domain_memregion *reg; struct sbi_domain *dom = sbi_domain_thishart_ptr(); struct sbi_scratch *scratch = sbi_scratch_thishart_ptr(); + unsigned long filtered_base[PMP_COUNT] = { 0 }; + unsigned char filtered_order[PMP_COUNT] = { 0 }; unsigned long addr, size; - int err, parent, i; + int err, parent, i, j; int na = fdt_address_cells(fdt, 0); int ns = fdt_size_cells(fdt, 0); @@ -351,11 +355,33 @@ int fdt_reserved_memory_fixup(void *fdt) if (reg->flags & SBI_DOMAIN_MEMREGION_SU_EXECUTABLE) continue; + if (i > PMP_COUNT) { + sbi_printf("%s: Too many memory regions to fixup.\n", + __func__); + return SBI_ENOSPC; + } + addr = reg->base; - size = 1UL << reg->order; - fdt_resv_memory_update_node(fdt, addr, size, i, parent, - (sbi_hart_pmp_count(scratch)) ? false : true); + for (j = 0; j < i; j++) { + if (addr == filtered_base[j] + && filtered_order[j] < reg->order) { + filtered_order[j] = reg->order; + goto next_entry; + } + } + + filtered_base[i] = reg->base; + filtered_order[i] = reg->order; i++; + next_entry: + } + + for (j = 0; j < i; j++) { + addr = filtered_base[j]; + size = 1UL << filtered_order[j]; + fdt_resv_memory_update_node(fdt, addr, size, j, parent, + (sbi_hart_pmp_count(scratch)) + ? false : true); } return 0; From 66b0e23a0cecb863b8fbb24c337be5710f31da62 Mon Sep 17 00:00:00 2001 From: Andrew Jones Date: Mon, 30 Jan 2023 17:42:24 +0100 Subject: [PATCH 036/187] lib: sbi: Ensure domidx_to_domain_table is null-terminated sbi_domain_for_each() requires domidx_to_domain_table[] to be null-terminated. Allocate one extra element which will always be null. Signed-off-by: Andrew Jones Reviewed-by: Anup Patel --- lib/sbi/sbi_domain.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/lib/sbi/sbi_domain.c b/lib/sbi/sbi_domain.c index 3ab1fbe0b7d..3813f1b2e97 100644 --- a/lib/sbi/sbi_domain.c +++ b/lib/sbi/sbi_domain.c @@ -17,8 +17,12 @@ #include #include +/* + * We allocate an extra element because sbi_domain_for_each() expects + * the array to be null-terminated. + */ +struct sbi_domain *domidx_to_domain_table[SBI_DOMAIN_MAX_INDEX + 1] = { 0 }; struct sbi_domain *hartid_to_domain_table[SBI_HARTMASK_MAX_BITS] = { 0 }; -struct sbi_domain *domidx_to_domain_table[SBI_DOMAIN_MAX_INDEX] = { 0 }; static u32 domain_count = 0; static bool domain_finalized = false; From 642f3de9b947b747a4fe0eaae348f1c55f1ac409 Mon Sep 17 00:00:00 2001 From: Jessica Clarke Date: Wed, 1 Feb 2023 16:49:16 +0000 Subject: [PATCH 037/187] Makefile: Add missing .dep files for fw_*.elf.ld Since we don't currently create these, changes to fw_base.ldS do not cause the preprocessed fw_*.elf.ld files to be rebuilt, and thus incremental builds can end up failing with missing symbols if crossing the recent commits that introduced _fw_rw_offset and then replaced it with _fw_rw_start. Reported-by: Ben Dooks Signed-off-by: Jessica Clarke Reviewed-by: Anup Patel --- Makefile | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/Makefile b/Makefile index b742d6dbc5e..b20404f94aa 100644 --- a/Makefile +++ b/Makefile @@ -254,6 +254,7 @@ deps-y=$(platform-objs-path-y:.o=.dep) deps-y+=$(libsbi-objs-path-y:.o=.dep) deps-y+=$(libsbiutils-objs-path-y:.o=.dep) deps-y+=$(firmware-objs-path-y:.o=.dep) +deps-y+=$(firmware-elfs-path-y:=.dep) # Setup platform ABI, ISA and Code Model ifndef PLATFORM_RISCV_ABI @@ -413,6 +414,11 @@ inst_file_list = $(CMD_PREFIX)if [ ! -z "$(4)" ]; then \ inst_header_dir = $(CMD_PREFIX)mkdir -p $(1); \ echo " INSTALL $(subst $(install_root_dir)/,,$(1))"; \ cp -rf $(2) $(1) +compile_cpp_dep = $(CMD_PREFIX)mkdir -p `dirname $(1)`; \ + echo " CPP-DEP $(subst $(build_dir)/,,$(1))"; \ + printf %s `dirname $(1)`/ > $(1) && \ + $(CC) $(CPPFLAGS) -x c -MM $(3) \ + -MT `basename $(1:.dep=$(2))` >> $(1) || rm -f $(1) compile_cpp = $(CMD_PREFIX)mkdir -p `dirname $(1)`; \ echo " CPP $(subst $(build_dir)/,,$(1))"; \ $(CPP) $(CPPFLAGS) -x c $(2) | grep -v "\#" > $(1) @@ -543,6 +549,9 @@ $(platform_build_dir)/%.bin: $(platform_build_dir)/%.elf $(platform_build_dir)/%.elf: $(platform_build_dir)/%.o $(platform_build_dir)/%.elf.ld $(platform_build_dir)/lib/libplatsbi.a $(call compile_elf,$@,$@.ld,$< $(platform_build_dir)/lib/libplatsbi.a) +$(platform_build_dir)/%.dep: $(src_dir)/%.ldS $(KCONFIG_CONFIG) + $(call compile_cpp_dep,$@,.ld,$<) + $(platform_build_dir)/%.ld: $(src_dir)/%.ldS $(call compile_cpp,$@,$<) From 09b34d8cca513dbd4d52ffd6d3d5b6dedeea516b Mon Sep 17 00:00:00 2001 From: Rahul Pathak Date: Thu, 2 Feb 2023 10:14:25 +0530 Subject: [PATCH 038/187] include: Add support for byteorder/endianness conversion Define macros general byteorder conversion Define functions for endianness conversion from general byteorder conversion macros Signed-off-by: Rahul Pathak Reviewed-by: Xiang W Reviewed-by: Sergey Matyukevich Reviewed-by: Anup Patel --- include/sbi/sbi_byteorder.h | 57 +++++++++++++++++++++++++++++++++++++ 1 file changed, 57 insertions(+) create mode 100644 include/sbi/sbi_byteorder.h diff --git a/include/sbi/sbi_byteorder.h b/include/sbi/sbi_byteorder.h new file mode 100644 index 00000000000..680710fe6d9 --- /dev/null +++ b/include/sbi/sbi_byteorder.h @@ -0,0 +1,57 @@ +/* + * SPDX-License-Identifier: BSD-2-Clause + * + * Copyright (c) 2023 Ventana Micro Systems Inc. + */ + +#ifndef __SBI_BYTEORDER_H__ +#define __SBI_BYTEORDER_H__ + +#include + +#define EXTRACT_BYTE(x, n) ((unsigned long long)((uint8_t *)&x)[n]) + +#define BSWAP16(x) ((EXTRACT_BYTE(x, 0) << 8) | EXTRACT_BYTE(x, 1)) +#define BSWAP32(x) ((EXTRACT_BYTE(x, 0) << 24) | (EXTRACT_BYTE(x, 1) << 16) | \ + (EXTRACT_BYTE(x, 2) << 8) | EXTRACT_BYTE(x, 3)) +#define BSWAP64(x) ((EXTRACT_BYTE(x, 0) << 56) | (EXTRACT_BYTE(x, 1) << 48) | \ + (EXTRACT_BYTE(x, 2) << 40) | (EXTRACT_BYTE(x, 3) << 32) | \ + (EXTRACT_BYTE(x, 4) << 24) | (EXTRACT_BYTE(x, 5) << 16) | \ + (EXTRACT_BYTE(x, 6) << 8) | EXTRACT_BYTE(x, 7)) + + +#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__ /* CPU(little-endian) */ +#define cpu_to_be16(x) ((uint16_t)BSWAP16(x)) +#define cpu_to_be32(x) ((uint32_t)BSWAP32(x)) +#define cpu_to_be64(x) ((uint64_t)BSWAP64(x)) + +#define be16_to_cpu(x) ((uint16_t)BSWAP16(x)) +#define be32_to_cpu(x) ((uint32_t)BSWAP32(x)) +#define be64_to_cpu(x) ((uint64_t)BSWAP64(x)) + +#define cpu_to_le16(x) ((uint16_t)(x)) +#define cpu_to_le32(x) ((uint32_t)(x)) +#define cpu_to_le64(x) ((uint64_t)(x)) + +#define le16_to_cpu(x) ((uint16_t)(x)) +#define le32_to_cpu(x) ((uint32_t)(x)) +#define le64_to_cpu(x) ((uint64_t)(x)) +#else /* CPU(big-endian) */ +#define cpu_to_be16(x) ((uint16_t)(x)) +#define cpu_to_be32(x) ((uint32_t)(x)) +#define cpu_to_be64(x) ((uint64_t)(x)) + +#define be16_to_cpu(x) ((uint16_t)(x)) +#define be32_to_cpu(x) ((uint32_t)(x)) +#define be64_to_cpu(x) ((uint64_t)(x)) + +#define cpu_to_le16(x) ((uint16_t)BSWAP16(x)) +#define cpu_to_le32(x) ((uint32_t)BSWAP32(x)) +#define cpu_to_le64(x) ((uint64_t)BSWAP64(x)) + +#define le16_to_cpu(x) ((uint16_t)BSWAP16(x)) +#define le32_to_cpu(x) ((uint32_t)BSWAP32(x)) +#define le64_to_cpu(x) ((uint64_t)BSWAP64(x)) +#endif + +#endif /* __SBI_BYTEORDER_H__ */ From 680bea02bf47e04594ed8810bfee7e9088cd1ca7 Mon Sep 17 00:00:00 2001 From: Rahul Pathak Date: Thu, 2 Feb 2023 10:14:26 +0530 Subject: [PATCH 039/187] lib: utils/fdt: Use byteorder conversion functions in libfdt_env.h FDT follows big-endian and CPU can be little or big endian as per the implementation. libfdt_env.h defines function for conversion between fdt and cpu byteorder according to the endianness. Currently, libfdt_env.h defines custom byte swapping macros and then undefines them. Instead, use the generic endianness conversion functions Signed-off-by: Rahul Pathak Reviewed-by: Xiang W Reviewed-by: Anup Patel --- lib/utils/libfdt/libfdt_env.h | 29 ++++++++++------------------- 1 file changed, 10 insertions(+), 19 deletions(-) diff --git a/lib/utils/libfdt/libfdt_env.h b/lib/utils/libfdt/libfdt_env.h index f9d9c6783c5..e5ad7698efc 100644 --- a/lib/utils/libfdt/libfdt_env.h +++ b/lib/utils/libfdt/libfdt_env.h @@ -9,6 +9,7 @@ #include #include +#include #define INT_MAX ((int)(~0U >> 1)) #define UINT_MAX ((unsigned int)~0U) @@ -41,45 +42,35 @@ typedef uint16_t FDT_BITWISE fdt16_t; typedef uint32_t FDT_BITWISE fdt32_t; typedef uint64_t FDT_BITWISE fdt64_t; -#define EXTRACT_BYTE(x, n) ((unsigned long long)((uint8_t *)&x)[n]) -#define CPU_TO_FDT16(x) ((EXTRACT_BYTE(x, 0) << 8) | EXTRACT_BYTE(x, 1)) -#define CPU_TO_FDT32(x) ((EXTRACT_BYTE(x, 0) << 24) | (EXTRACT_BYTE(x, 1) << 16) | \ - (EXTRACT_BYTE(x, 2) << 8) | EXTRACT_BYTE(x, 3)) -#define CPU_TO_FDT64(x) ((EXTRACT_BYTE(x, 0) << 56) | (EXTRACT_BYTE(x, 1) << 48) | \ - (EXTRACT_BYTE(x, 2) << 40) | (EXTRACT_BYTE(x, 3) << 32) | \ - (EXTRACT_BYTE(x, 4) << 24) | (EXTRACT_BYTE(x, 5) << 16) | \ - (EXTRACT_BYTE(x, 6) << 8) | EXTRACT_BYTE(x, 7)) - static inline uint16_t fdt16_to_cpu(fdt16_t x) { - return (FDT_FORCE uint16_t)CPU_TO_FDT16(x); + return (FDT_FORCE uint16_t)be16_to_cpu(x); } + static inline fdt16_t cpu_to_fdt16(uint16_t x) { - return (FDT_FORCE fdt16_t)CPU_TO_FDT16(x); + return (FDT_FORCE fdt16_t)cpu_to_be16(x); } static inline uint32_t fdt32_to_cpu(fdt32_t x) { - return (FDT_FORCE uint32_t)CPU_TO_FDT32(x); + return (FDT_FORCE uint32_t)be32_to_cpu(x); } + static inline fdt32_t cpu_to_fdt32(uint32_t x) { - return (FDT_FORCE fdt32_t)CPU_TO_FDT32(x); + return (FDT_FORCE fdt32_t)cpu_to_be32(x); } static inline uint64_t fdt64_to_cpu(fdt64_t x) { - return (FDT_FORCE uint64_t)CPU_TO_FDT64(x); + return (FDT_FORCE uint64_t)be64_to_cpu(x); } + static inline fdt64_t cpu_to_fdt64(uint64_t x) { - return (FDT_FORCE fdt64_t)CPU_TO_FDT64(x); + return (FDT_FORCE fdt64_t)cpu_to_be64(x); } -#undef CPU_TO_FDT64 -#undef CPU_TO_FDT32 -#undef CPU_TO_FDT16 -#undef EXTRACT_BYTE #ifdef __APPLE__ #include From b224ddb41fe1f9cbdfb246ebf22036ae1fe3f40f Mon Sep 17 00:00:00 2001 From: Rahul Pathak Date: Thu, 2 Feb 2023 10:14:27 +0530 Subject: [PATCH 040/187] include: types: Add typedefs for endianness If any variable/memory-location follows certain endianness then its important to annotate it properly so that proper conversion can be done before read/write from that variable/memory. Also, use these new typedefs in libfdt_env.h for deriving its own custom fdtX_t types Signed-off-by: Rahul Pathak Reviewed-by: Anup Patel --- include/sbi/sbi_types.h | 7 +++++++ lib/utils/libfdt/libfdt_env.h | 6 +++--- 2 files changed, 10 insertions(+), 3 deletions(-) diff --git a/include/sbi/sbi_types.h b/include/sbi/sbi_types.h index 9c1fef3b8dc..def88bbad2c 100644 --- a/include/sbi/sbi_types.h +++ b/include/sbi/sbi_types.h @@ -54,6 +54,13 @@ typedef unsigned long virtual_size_t; typedef unsigned long physical_addr_t; typedef unsigned long physical_size_t; +typedef uint16_t le16_t; +typedef uint16_t be16_t; +typedef uint32_t le32_t; +typedef uint32_t be32_t; +typedef uint64_t le64_t; +typedef uint64_t be64_t; + #define true 1 #define false 0 diff --git a/lib/utils/libfdt/libfdt_env.h b/lib/utils/libfdt/libfdt_env.h index e5ad7698efc..6ebbae01b51 100644 --- a/lib/utils/libfdt/libfdt_env.h +++ b/lib/utils/libfdt/libfdt_env.h @@ -38,9 +38,9 @@ #define strlen sbi_strlen #define strnlen sbi_strnlen -typedef uint16_t FDT_BITWISE fdt16_t; -typedef uint32_t FDT_BITWISE fdt32_t; -typedef uint64_t FDT_BITWISE fdt64_t; +typedef be16_t FDT_BITWISE fdt16_t; +typedef be32_t FDT_BITWISE fdt32_t; +typedef be64_t FDT_BITWISE fdt64_t; static inline uint16_t fdt16_to_cpu(fdt16_t x) { From aa5dafcb5bfc04f8509a04291402d86d6b5c36d5 Mon Sep 17 00:00:00 2001 From: Anup Patel Date: Thu, 9 Feb 2023 09:15:19 +0530 Subject: [PATCH 041/187] include: sbi: Fix BSWAPx() macros for big-endian host The BSWAPx() macros won't do any swapping for big-endian host because the EXTRACT_BYTE() macro will pickup bytes in reverse order. Also, the EXTRACT_BYTE() will generate compile error for constants. To fix this, we get remove the EXTRACT_BYTE() macro and re-write BSWAPx() using simple mask and shift operations. Fixes: 09b34d8cca51 ("include: Add support for byteorder/endianness conversion") Reported-by: Samuel Holland Signed-off-by: Anup Patel --- include/sbi/sbi_byteorder.h | 24 ++++++++++++++---------- 1 file changed, 14 insertions(+), 10 deletions(-) diff --git a/include/sbi/sbi_byteorder.h b/include/sbi/sbi_byteorder.h index 680710fe6d9..15107e1ea3d 100644 --- a/include/sbi/sbi_byteorder.h +++ b/include/sbi/sbi_byteorder.h @@ -9,16 +9,20 @@ #include -#define EXTRACT_BYTE(x, n) ((unsigned long long)((uint8_t *)&x)[n]) - -#define BSWAP16(x) ((EXTRACT_BYTE(x, 0) << 8) | EXTRACT_BYTE(x, 1)) -#define BSWAP32(x) ((EXTRACT_BYTE(x, 0) << 24) | (EXTRACT_BYTE(x, 1) << 16) | \ - (EXTRACT_BYTE(x, 2) << 8) | EXTRACT_BYTE(x, 3)) -#define BSWAP64(x) ((EXTRACT_BYTE(x, 0) << 56) | (EXTRACT_BYTE(x, 1) << 48) | \ - (EXTRACT_BYTE(x, 2) << 40) | (EXTRACT_BYTE(x, 3) << 32) | \ - (EXTRACT_BYTE(x, 4) << 24) | (EXTRACT_BYTE(x, 5) << 16) | \ - (EXTRACT_BYTE(x, 6) << 8) | EXTRACT_BYTE(x, 7)) - +#define BSWAP16(x) ((((x) & 0x00ff) << 8) | \ + (((x) & 0xff00) >> 8)) +#define BSWAP32(x) ((((x) & 0x000000ff) << 24) | \ + (((x) & 0x0000ff00) << 8) | \ + (((x) & 0x00ff0000) >> 8) | \ + (((x) & 0xff000000) >> 24)) +#define BSWAP64(x) ((((x) & 0x00000000000000ffULL) << 56) | \ + (((x) & 0x000000000000ff00ULL) << 40) | \ + (((x) & 0x0000000000ff0000ULL) << 24) | \ + (((x) & 0x00000000ff000000ULL) << 8) | \ + (((x) & 0x000000ff00000000ULL) >> 8) | \ + (((x) & 0x0000ff0000000000ULL) >> 24) | \ + (((x) & 0x00ff000000000000ULL) >> 40) | \ + (((x) & 0xff00000000000000ULL) >> 56)) #if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__ /* CPU(little-endian) */ #define cpu_to_be16(x) ((uint16_t)BSWAP16(x)) From e3bf1afcc568fece971d67395f63461fddb4c0fa Mon Sep 17 00:00:00 2001 From: Anup Patel Date: Fri, 22 Jul 2022 16:25:51 +0530 Subject: [PATCH 042/187] include: Add defines for SBI debug console extension We add SBI debug console extension related defines to the SBI ecall interface header. Signed-off-by: Anup Patel Reviewed-by: Andrew Jones Reviewed-by: Atish Patra Reviewed-by: Bin Meng Reviewed-by: Xiang W --- include/sbi/sbi_ecall_interface.h | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/include/sbi/sbi_ecall_interface.h b/include/sbi/sbi_ecall_interface.h index a3f2bf4bdf6..9d6f4743651 100644 --- a/include/sbi/sbi_ecall_interface.h +++ b/include/sbi/sbi_ecall_interface.h @@ -29,6 +29,7 @@ #define SBI_EXT_HSM 0x48534D #define SBI_EXT_SRST 0x53525354 #define SBI_EXT_PMU 0x504D55 +#define SBI_EXT_DBCN 0x4442434E /* SBI function IDs for BASE extension*/ #define SBI_EXT_BASE_GET_SPEC_VERSION 0x0 @@ -230,6 +231,11 @@ enum sbi_pmu_ctr_type { /* Flags defined for counter stop function */ #define SBI_PMU_STOP_FLAG_RESET (1 << 0) +/* SBI function IDs for DBCN extension */ +#define SBI_EXT_DBCN_CONSOLE_WRITE 0x0 +#define SBI_EXT_DBCN_CONSOLE_READ 0x1 +#define SBI_EXT_DBCN_CONSOLE_WRITE_BYTE 0x2 + /* SBI base specification related macros */ #define SBI_SPEC_VERSION_MAJOR_OFFSET 24 #define SBI_SPEC_VERSION_MAJOR_MASK 0x7f From 0ee3a86fedafccaa5f57df86b07547747920972e Mon Sep 17 00:00:00 2001 From: Anup Patel Date: Fri, 22 Jul 2022 16:28:21 +0530 Subject: [PATCH 043/187] lib: sbi: Add sbi_nputs() function We add new sbi_nputs() which help us print a fixed number of characters from a physical memory location. Signed-off-by: Anup Patel Reviewed-by: Atish Patra Reviewed-by: Bin Meng Reviewed-by: Xiang W --- include/sbi/sbi_console.h | 2 ++ lib/sbi/sbi_console.c | 12 ++++++++++++ 2 files changed, 14 insertions(+) diff --git a/include/sbi/sbi_console.h b/include/sbi/sbi_console.h index e15b55dcb54..dd6a905d116 100644 --- a/include/sbi/sbi_console.h +++ b/include/sbi/sbi_console.h @@ -33,6 +33,8 @@ void sbi_putc(char ch); void sbi_puts(const char *str); +unsigned long sbi_nputs(const char *str, unsigned long len); + void sbi_gets(char *s, int maxwidth, char endchar); int __printf(2, 3) sbi_sprintf(char *out, const char *format, ...); diff --git a/lib/sbi/sbi_console.c b/lib/sbi/sbi_console.c index bb6e1ef159a..2f83a26c734 100644 --- a/lib/sbi/sbi_console.c +++ b/lib/sbi/sbi_console.c @@ -51,6 +51,18 @@ void sbi_puts(const char *str) spin_unlock(&console_out_lock); } +unsigned long sbi_nputs(const char *str, unsigned long len) +{ + unsigned long i; + + spin_lock(&console_out_lock); + for (i = 0; i < len; i++) + sbi_putc(str[i]); + spin_unlock(&console_out_lock); + + return i; +} + void sbi_gets(char *s, int maxwidth, char endchar) { int ch; From 4e0572f57bc832b13f6e813dcdaebb1bf4d1172a Mon Sep 17 00:00:00 2001 From: Anup Patel Date: Wed, 4 Jan 2023 17:36:29 +0530 Subject: [PATCH 044/187] lib: sbi: Add sbi_ngets() function We add new sbi_ngets() which help us read characters into a physical memory location. Signed-off-by: Anup Patel Reviewed-by: Atish Patra Reviewed-by: Andrew Jones --- include/sbi/sbi_console.h | 2 ++ lib/sbi/sbi_console.c | 15 +++++++++++++++ 2 files changed, 17 insertions(+) diff --git a/include/sbi/sbi_console.h b/include/sbi/sbi_console.h index dd6a905d116..3c1f5e595a6 100644 --- a/include/sbi/sbi_console.h +++ b/include/sbi/sbi_console.h @@ -37,6 +37,8 @@ unsigned long sbi_nputs(const char *str, unsigned long len); void sbi_gets(char *s, int maxwidth, char endchar); +unsigned long sbi_ngets(char *str, unsigned long len); + int __printf(2, 3) sbi_sprintf(char *out, const char *format, ...); int __printf(3, 4) sbi_snprintf(char *out, u32 out_sz, const char *format, ...); diff --git a/lib/sbi/sbi_console.c b/lib/sbi/sbi_console.c index 2f83a26c734..c734bc0a04f 100644 --- a/lib/sbi/sbi_console.c +++ b/lib/sbi/sbi_console.c @@ -76,6 +76,21 @@ void sbi_gets(char *s, int maxwidth, char endchar) *retval = '\0'; } +unsigned long sbi_ngets(char *str, unsigned long len) +{ + int ch; + unsigned long i; + + for (i = 0; i < len; i++) { + ch = sbi_getc(); + if (ch < 0) + break; + str[i] = ch; + } + + return i; +} + #define PAD_RIGHT 1 #define PAD_ZERO 2 #define PAD_ALTERNATE 4 From eab48c33a12d5cdb01e36d0078c9f79764055952 Mon Sep 17 00:00:00 2001 From: Anup Patel Date: Wed, 23 Nov 2022 11:46:16 +0530 Subject: [PATCH 045/187] lib: sbi: Add sbi_domain_check_addr_range() function We add sbi_domain_check_addr_range() helper function to check whether a given address range is accessible under a particular domain. Signed-off-by: Anup Patel Reviewed-by: Atish Patra Reviewed-by: Xiang W Reviewed-by: Bin Meng Reviewed-by: Andrew Jones --- include/sbi/sbi_domain.h | 15 +++++++++ lib/sbi/sbi_domain.c | 69 ++++++++++++++++++++++++++++++++++++++++ 2 files changed, 84 insertions(+) diff --git a/include/sbi/sbi_domain.h b/include/sbi/sbi_domain.h index bbb3effa244..ab1a944b474 100644 --- a/include/sbi/sbi_domain.h +++ b/include/sbi/sbi_domain.h @@ -196,6 +196,21 @@ bool sbi_domain_check_addr(const struct sbi_domain *dom, unsigned long addr, unsigned long mode, unsigned long access_flags); +/** + * Check whether we can access specified address range for given mode and + * memory region flags under a domain + * @param dom pointer to domain + * @param addr the start of the address range to be checked + * @param size the size of the address range to be checked + * @param mode the privilege mode of access + * @param access_flags bitmask of domain access types (enum sbi_domain_access) + * @return TRUE if access allowed otherwise FALSE + */ +bool sbi_domain_check_addr_range(const struct sbi_domain *dom, + unsigned long addr, unsigned long size, + unsigned long mode, + unsigned long access_flags); + /** Dump domain details on the console */ void sbi_domain_dump(const struct sbi_domain *dom, const char *suffix); diff --git a/lib/sbi/sbi_domain.c b/lib/sbi/sbi_domain.c index 3813f1b2e97..dc825b0d95f 100644 --- a/lib/sbi/sbi_domain.c +++ b/lib/sbi/sbi_domain.c @@ -212,6 +212,44 @@ static bool is_region_before(const struct sbi_domain_memregion *regA, return false; } +static const struct sbi_domain_memregion *find_region( + const struct sbi_domain *dom, + unsigned long addr) +{ + unsigned long rstart, rend; + struct sbi_domain_memregion *reg; + + sbi_domain_for_each_memregion(dom, reg) { + rstart = reg->base; + rend = (reg->order < __riscv_xlen) ? + rstart + ((1UL << reg->order) - 1) : -1UL; + if (rstart <= addr && addr <= rend) + return reg; + } + + return NULL; +} + +static const struct sbi_domain_memregion *find_next_subset_region( + const struct sbi_domain *dom, + const struct sbi_domain_memregion *reg, + unsigned long addr) +{ + struct sbi_domain_memregion *sreg, *ret = NULL; + + sbi_domain_for_each_memregion(dom, sreg) { + if (sreg == reg || (sreg->base <= addr) || + !is_region_subset(sreg, reg)) + continue; + + if (!ret || (sreg->base < ret->base) || + ((sreg->base == ret->base) && (sreg->order < ret->order))) + ret = sreg; + } + + return ret; +} + static int sanitize_domain(const struct sbi_platform *plat, struct sbi_domain *dom) { @@ -320,6 +358,37 @@ static int sanitize_domain(const struct sbi_platform *plat, return 0; } +bool sbi_domain_check_addr_range(const struct sbi_domain *dom, + unsigned long addr, unsigned long size, + unsigned long mode, + unsigned long access_flags) +{ + unsigned long max = addr + size; + const struct sbi_domain_memregion *reg, *sreg; + + if (!dom) + return false; + + while (addr < max) { + reg = find_region(dom, addr); + if (!reg) + return false; + + if (!sbi_domain_check_addr(dom, addr, mode, access_flags)) + return false; + + sreg = find_next_subset_region(dom, reg, addr); + if (sreg) + addr = sreg->base; + else if (reg->order < __riscv_xlen) + addr = reg->base + (1UL << reg->order); + else + break; + } + + return true; +} + void sbi_domain_dump(const struct sbi_domain *dom, const char *suffix) { u32 i, k; From 5a41a3884fe2a639698aaa67a9c1ecc33573eb78 Mon Sep 17 00:00:00 2001 From: Anup Patel Date: Wed, 23 Nov 2022 11:11:43 +0530 Subject: [PATCH 046/187] lib: sbi: Implement SBI debug console extension We implement SBI debug console extension as one of the replacement SBI extensions. This extension is only available when OpenSBI platform provides a console device to generic library. Signed-off-by: Anup Patel Reviewed-by: Atish Patra Reviewed-by: Xiang W Reviewed-by: Bin Meng --- lib/sbi/Kconfig | 4 +++ lib/sbi/objects.mk | 3 ++ lib/sbi/sbi_ecall_dbcn.c | 72 ++++++++++++++++++++++++++++++++++++++++ 3 files changed, 79 insertions(+) create mode 100644 lib/sbi/sbi_ecall_dbcn.c diff --git a/lib/sbi/Kconfig b/lib/sbi/Kconfig index df74bba3854..ef6728bab3e 100644 --- a/lib/sbi/Kconfig +++ b/lib/sbi/Kconfig @@ -26,6 +26,10 @@ config SBI_ECALL_PMU bool "Performance Monitoring Unit extension" default y +config SBI_ECALL_DBCN + bool "Debug Console extension" + default y + config SBI_ECALL_LEGACY bool "SBI v0.1 legacy extensions" default y diff --git a/lib/sbi/objects.mk b/lib/sbi/objects.mk index c774ebbcd14..319f38dce70 100644 --- a/lib/sbi/objects.mk +++ b/lib/sbi/objects.mk @@ -37,6 +37,9 @@ libsbi-objs-$(CONFIG_SBI_ECALL_SRST) += sbi_ecall_srst.o carray-sbi_ecall_exts-$(CONFIG_SBI_ECALL_PMU) += ecall_pmu libsbi-objs-$(CONFIG_SBI_ECALL_PMU) += sbi_ecall_pmu.o +carray-sbi_ecall_exts-$(CONFIG_SBI_ECALL_DBCN) += ecall_dbcn +libsbi-objs-$(CONFIG_SBI_ECALL_DBCN) += sbi_ecall_dbcn.o + carray-sbi_ecall_exts-$(CONFIG_SBI_ECALL_LEGACY) += ecall_legacy libsbi-objs-$(CONFIG_SBI_ECALL_LEGACY) += sbi_ecall_legacy.o diff --git a/lib/sbi/sbi_ecall_dbcn.c b/lib/sbi/sbi_ecall_dbcn.c new file mode 100644 index 00000000000..fe7e175a64c --- /dev/null +++ b/lib/sbi/sbi_ecall_dbcn.c @@ -0,0 +1,72 @@ +/* + * SPDX-License-Identifier: BSD-2-Clause + * + * Copyright (c) 2022 Ventana Micro Systems Inc. + * + * Authors: + * Anup Patel + */ + +#include +#include +#include +#include +#include +#include +#include + +static int sbi_ecall_dbcn_handler(unsigned long extid, unsigned long funcid, + const struct sbi_trap_regs *regs, + unsigned long *out_val, + struct sbi_trap_info *out_trap) +{ + ulong smode = (csr_read(CSR_MSTATUS) & MSTATUS_MPP) >> + MSTATUS_MPP_SHIFT; + + switch (funcid) { + case SBI_EXT_DBCN_CONSOLE_WRITE: + case SBI_EXT_DBCN_CONSOLE_READ: + /* + * On RV32, the M-mode can only access the first 4GB of + * the physical address space because M-mode does not have + * MMU to access full 34-bit physical address space. + * + * Based on above, we simply fail if the upper 32bits of + * the physical address (i.e. a2 register) is non-zero on + * RV32. + */ +#if __riscv_xlen == 32 + if (regs->a2) + return SBI_ERR_FAILED; +#endif + if (!sbi_domain_check_addr_range(sbi_domain_thishart_ptr(), + regs->a1, regs->a0, smode, + SBI_DOMAIN_READ|SBI_DOMAIN_WRITE)) + return SBI_ERR_INVALID_PARAM; + if (funcid == SBI_EXT_DBCN_CONSOLE_WRITE) + *out_val = sbi_nputs((const char *)regs->a1, regs->a0); + else + *out_val = sbi_ngets((char *)regs->a1, regs->a0); + return 0; + case SBI_EXT_DBCN_CONSOLE_WRITE_BYTE: + sbi_putc(regs->a0); + return 0; + default: + break; + } + + return SBI_ENOTSUPP; +} + +static int sbi_ecall_dbcn_probe(unsigned long extid, unsigned long *out_val) +{ + *out_val = sbi_console_get_device() ? 1 : 0; + return 0; +} + +struct sbi_ecall_extension ecall_dbcn = { + .extid_start = SBI_EXT_DBCN, + .extid_end = SBI_EXT_DBCN, + .handle = sbi_ecall_dbcn_handler, + .probe = sbi_ecall_dbcn_probe, +}; From c43903c4eae41be9917b0623f3625d96ca25fbc3 Mon Sep 17 00:00:00 2001 From: Anup Patel Date: Wed, 23 Nov 2022 12:32:06 +0530 Subject: [PATCH 047/187] lib: sbi: Add console_puts() callback in the console device We add console_puts() callback in the console device which allows console drivers (such as semihosting) to implement a specialized way to output character string. Signed-off-by: Anup Patel Reviewed-by: Atish Patra Reviewed-by: Xiang W Reviewed-by: Bin Meng Reviewed-by: Andrew Jones --- include/sbi/sbi_console.h | 3 +++ lib/sbi/sbi_console.c | 29 ++++++++++++++++++++++------- 2 files changed, 25 insertions(+), 7 deletions(-) diff --git a/include/sbi/sbi_console.h b/include/sbi/sbi_console.h index 3c1f5e595a6..0979765240c 100644 --- a/include/sbi/sbi_console.h +++ b/include/sbi/sbi_console.h @@ -19,6 +19,9 @@ struct sbi_console_device { /** Write a character to the console output */ void (*console_putc)(char ch); + /** Write a character string to the console output */ + unsigned long (*console_puts)(const char *str, unsigned long len); + /** Read a character from the console input */ int (*console_getc)(void); }; diff --git a/lib/sbi/sbi_console.c b/lib/sbi/sbi_console.c index c734bc0a04f..8a5d9de0485 100644 --- a/lib/sbi/sbi_console.c +++ b/lib/sbi/sbi_console.c @@ -12,6 +12,7 @@ #include #include #include +#include static const struct sbi_console_device *console_dev = NULL; static spinlock_t console_out_lock = SPIN_LOCK_INITIALIZER; @@ -43,24 +44,38 @@ void sbi_putc(char ch) void sbi_puts(const char *str) { + unsigned long p, len; + spin_lock(&console_out_lock); - while (*str) { - sbi_putc(*str); - str++; + if (console_dev && console_dev->console_puts) { + p = 0; + len = sbi_strlen(str); + while (p < len) + p += console_dev->console_puts(&str[p], len - p); + } else { + while (*str) { + sbi_putc(*str); + str++; + } } spin_unlock(&console_out_lock); } unsigned long sbi_nputs(const char *str, unsigned long len) { - unsigned long i; + unsigned long i, ret; spin_lock(&console_out_lock); - for (i = 0; i < len; i++) - sbi_putc(str[i]); + if (console_dev && console_dev->console_puts) { + ret = console_dev->console_puts(str, len); + } else { + for (i = 0; i < len; i++) + sbi_putc(str[i]); + ret = len; + } spin_unlock(&console_out_lock); - return i; + return ret; } void sbi_gets(char *s, int maxwidth, char endchar) From 29285aead07d2778855e1e67ba9c08b4fa4a2c7a Mon Sep 17 00:00:00 2001 From: Anup Patel Date: Wed, 23 Nov 2022 15:40:17 +0530 Subject: [PATCH 048/187] lib: utils/serial: Implement console_puts() for semihosting We implement console_puts() for semihosting serial driver to speed-up semihosting based prints. Signed-off-by: Anup Patel Reviewed-by: Atish Patra Reviewed-by: Xiang W Reviewed-by: Bin Meng Reviewed-by: Andrew Jones --- lib/utils/serial/semihosting.c | 37 ++++++++++++++++++++++++++++++++++ 1 file changed, 37 insertions(+) diff --git a/lib/utils/serial/semihosting.c b/lib/utils/serial/semihosting.c index 86fa296ce17..ce65887dd72 100644 --- a/lib/utils/serial/semihosting.c +++ b/lib/utils/serial/semihosting.c @@ -15,6 +15,7 @@ #define SYSOPEN 0x01 #define SYSWRITEC 0x03 +#define SYSWRITE 0x05 #define SYSREAD 0x06 #define SYSREADC 0x07 #define SYSERRNO 0x13 @@ -93,6 +94,7 @@ static int semihosting_errno(void) } static int semihosting_infd = SBI_ENODEV; +static int semihosting_outfd = SBI_ENODEV; static long semihosting_open(const char *fname, enum semihosting_open_mode mode) { @@ -141,6 +143,21 @@ static long semihosting_read(long fd, void *memp, size_t len) return len - ret; } +static long semihosting_write(long fd, const void *memp, size_t len) +{ + long ret; + struct semihosting_rdwr_s write; + + write.fd = fd; + write.memp = (void *)memp; + write.len = len; + + ret = semihosting_trap(SYSWRITE, &write); + if (ret < 0) + return semihosting_errno(); + return len - ret; +} + /* clang-format on */ static void semihosting_putc(char ch) @@ -148,6 +165,24 @@ static void semihosting_putc(char ch) semihosting_trap(SYSWRITEC, &ch); } +static unsigned long semihosting_puts(const char *str, unsigned long len) +{ + char ch; + long ret; + unsigned long i; + + if (semihosting_outfd < 0) { + for (i = 0; i < len; i++) { + ch = str[i]; + semihosting_trap(SYSWRITEC, &ch); + } + ret = len; + } else + ret = semihosting_write(semihosting_outfd, str, len); + + return (ret < 0) ? 0 : ret; +} + static int semihosting_getc(void) { char ch = 0; @@ -165,12 +200,14 @@ static int semihosting_getc(void) static struct sbi_console_device semihosting_console = { .name = "semihosting", .console_putc = semihosting_putc, + .console_puts = semihosting_puts, .console_getc = semihosting_getc }; int semihosting_init(void) { semihosting_infd = semihosting_open(":tt", MODE_READ); + semihosting_outfd = semihosting_open(":tt", MODE_WRITE); sbi_console_set_device(&semihosting_console); From 65c2190b47b14341dac9f763fed2d4ecbbff2a69 Mon Sep 17 00:00:00 2001 From: Anup Patel Date: Fri, 13 Jan 2023 14:53:53 +0530 Subject: [PATCH 049/187] lib: sbi: Speed-up sbi_printf() and friends using nputs() The sbi_printf() is slow for semihosting because it prints one character at a time. To speed-up sbi_printf() for semihosting, we use a temporary buffer and nputs(). Signed-off-by: Anup Patel Reviewed-by: Andrew Jones --- lib/sbi/sbi_console.c | 76 ++++++++++++++++++++++++++++++------------- 1 file changed, 54 insertions(+), 22 deletions(-) diff --git a/lib/sbi/sbi_console.c b/lib/sbi/sbi_console.c index 8a5d9de0485..f3ac0033460 100644 --- a/lib/sbi/sbi_console.c +++ b/lib/sbi/sbi_console.c @@ -14,7 +14,11 @@ #include #include +#define CONSOLE_TBUF_MAX 256 + static const struct sbi_console_device *console_dev = NULL; +static char console_tbuf[CONSOLE_TBUF_MAX]; +static u32 console_tbuf_len; static spinlock_t console_out_lock = SPIN_LOCK_INITIALIZER; bool sbi_isprintable(char c) @@ -42,37 +46,44 @@ void sbi_putc(char ch) } } -void sbi_puts(const char *str) +static unsigned long nputs(const char *str, unsigned long len) { - unsigned long p, len; + unsigned long i, ret; - spin_lock(&console_out_lock); if (console_dev && console_dev->console_puts) { - p = 0; - len = sbi_strlen(str); - while (p < len) - p += console_dev->console_puts(&str[p], len - p); + ret = console_dev->console_puts(str, len); } else { - while (*str) { - sbi_putc(*str); - str++; - } + for (i = 0; i < len; i++) + sbi_putc(str[i]); + ret = len; } + + return ret; +} + +static void nputs_all(const char *str, unsigned long len) +{ + unsigned long p = 0; + + while (p < len) + p += nputs(&str[p], len - p); +} + +void sbi_puts(const char *str) +{ + unsigned long len = sbi_strlen(str); + + spin_lock(&console_out_lock); + nputs_all(str, len); spin_unlock(&console_out_lock); } unsigned long sbi_nputs(const char *str, unsigned long len) { - unsigned long i, ret; + unsigned long ret; spin_lock(&console_out_lock); - if (console_dev && console_dev->console_puts) { - ret = console_dev->console_puts(str, len); - } else { - for (i = 0; i < len; i++) - sbi_putc(str[i]); - ret = len; - } + ret = nputs(str, len); spin_unlock(&console_out_lock); return ret; @@ -225,12 +236,30 @@ static int printi(char **out, u32 *out_len, long long i, int b, int sg, static int print(char **out, u32 *out_len, const char *format, va_list args) { - int width, flags; - int pc = 0; - char scr[2]; + int width, flags, pc = 0; + char scr[2], *tout; + bool use_tbuf = (!out) ? true : false; unsigned long long tmp; + /* + * The console_tbuf is protected by console_out_lock and + * print() is always called with console_out_lock held + * when out == NULL. + */ + if (use_tbuf) { + console_tbuf_len = CONSOLE_TBUF_MAX; + tout = console_tbuf; + out = &tout; + out_len = &console_tbuf_len; + } + for (; *format != 0; ++format) { + if (use_tbuf && !console_tbuf_len) { + nputs_all(console_tbuf, CONSOLE_TBUF_MAX); + console_tbuf_len = CONSOLE_TBUF_MAX; + tout = console_tbuf; + } + if (*format == '%') { ++format; width = flags = 0; @@ -356,6 +385,9 @@ static int print(char **out, u32 *out_len, const char *format, va_list args) } } + if (use_tbuf && console_tbuf_len < CONSOLE_TBUF_MAX) + nputs_all(console_tbuf, CONSOLE_TBUF_MAX - console_tbuf_len); + return pc; } From 321293c6443ea55e2fcb17975ebc498dcbcb7290 Mon Sep 17 00:00:00 2001 From: Bin Meng Date: Thu, 23 Feb 2023 18:40:06 +0800 Subject: [PATCH 050/187] lib: utils/fdt: Fix fdt_pmu.c header dependency The code calls sbi_scratch_thishart_ptr() from sbi_scratch.h which is not directly included. Fix such dependency. Signed-off-by: Bin Meng Reviewed-by: Anup Patel --- lib/utils/fdt/fdt_pmu.c | 1 + 1 file changed, 1 insertion(+) diff --git a/lib/utils/fdt/fdt_pmu.c b/lib/utils/fdt/fdt_pmu.c index 4829f2127ac..83301bb5c1a 100644 --- a/lib/utils/fdt/fdt_pmu.c +++ b/lib/utils/fdt/fdt_pmu.c @@ -12,6 +12,7 @@ #include #include #include +#include #include #define FDT_PMU_HW_EVENT_MAX (SBI_PMU_HW_EVENT_MAX * 2) From aafcc90a875b58b883275522fb63d9b19964c851 Mon Sep 17 00:00:00 2001 From: Bin Meng Date: Thu, 23 Feb 2023 18:40:07 +0800 Subject: [PATCH 051/187] platform: generic/allwinner: Fix sun20i-d1.c header dependency The code calls various macros from riscv_asm.h and sbi_scratch.h which are not directly included. Fix such dependency. Signed-off-by: Bin Meng Reviewed-by: Anup Patel --- platform/generic/allwinner/sun20i-d1.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/platform/generic/allwinner/sun20i-d1.c b/platform/generic/allwinner/sun20i-d1.c index 295c1593db1..0f0a9f347a6 100644 --- a/platform/generic/allwinner/sun20i-d1.c +++ b/platform/generic/allwinner/sun20i-d1.c @@ -6,12 +6,14 @@ #include #include +#include #include #include #include #include #include #include +#include #include #include #include From 745aaecc64dcae0cfb7e40702a173100af94d582 Mon Sep 17 00:00:00 2001 From: Bin Meng Date: Thu, 23 Feb 2023 18:40:08 +0800 Subject: [PATCH 052/187] platform: generic/andes: Fix ae350.c header dependency The code calls various macros from riscv_asm.h which is not directly included. Fix such dependency. Signed-off-by: Bin Meng Reviewed-by: Anup Patel --- platform/generic/andes/ae350.c | 1 + 1 file changed, 1 insertion(+) diff --git a/platform/generic/andes/ae350.c b/platform/generic/andes/ae350.c index 89f5b74af71..01bd02d5b96 100644 --- a/platform/generic/andes/ae350.c +++ b/platform/generic/andes/ae350.c @@ -11,6 +11,7 @@ #include #include #include +#include #include #include #include From 99d09b601eb3809a4cc2aa409da34bc4fe32f67f Mon Sep 17 00:00:00 2001 From: Bin Meng Date: Thu, 23 Feb 2023 18:40:09 +0800 Subject: [PATCH 053/187] include: fdt/fdt_helper: Change fdt_get_address() to return root.next_arg1 In sbi_domain_finalize(), when locating the coldboot hart's domain, the coldboot hart's scratch->arg1 will be overwritten by the domain configuration. However scratch->arg1 holds the FDT address of the coldboot hart, and is still being accessed by fdt_get_address() in later boot process. scratch->arg1 could then contain completely garbage and lead to a crash. To fix this, we change fdt_get_address() to return root domain's next_arg1 as the FDT pointer. Resolves: https://github.com/riscv-software-src/opensbi/issues/281 Fixes: b1678af210dc ("lib: sbi: Add initial domain support") Reported-by: Marouene Boubakri Signed-off-by: Bin Meng Reviewed-by: Anup Patel --- include/sbi_utils/fdt/fdt_helper.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/include/sbi_utils/fdt/fdt_helper.h b/include/sbi_utils/fdt/fdt_helper.h index 09f3095d0d9..39d7f3a01d8 100644 --- a/include/sbi_utils/fdt/fdt_helper.h +++ b/include/sbi_utils/fdt/fdt_helper.h @@ -11,7 +11,7 @@ #define __FDT_HELPER_H__ #include -#include +#include struct fdt_match { const char *compatible; @@ -109,7 +109,7 @@ int fdt_parse_compat_addr(void *fdt, uint64_t *addr, static inline void *fdt_get_address(void) { - return sbi_scratch_thishart_arg1_ptr(); + return (void *)root.next_arg1; } #endif /* __FDT_HELPER_H__ */ From 6861ee996ce5b1f2017ca7a9b0342f9cd9462917 Mon Sep 17 00:00:00 2001 From: Xiang W Date: Tue, 21 Feb 2023 13:07:07 +0800 Subject: [PATCH 054/187] lib: utils: fdt_fixup: Fix compile error When building with GCC-10 or older versions, it throws the following error: CC-DEP platform/generic/lib/utils/fdt/fdt_fixup.dep CC platform/generic/lib/utils/fdt/fdt_fixup.o lib/utils/fdt/fdt_fixup.c: In function 'fdt_reserved_memory_fixup': lib/utils/fdt/fdt_fixup.c:376:2: error: label at end of compound statement 376 | next_entry: | ^~~~~~~~~~ Remove the goto statement. Resolves: https://github.com/riscv-software-src/opensbi/issues/288 Signed-off-by: Yu Chien Peter Lin Signed-off-by: Xiang W Reviewed-by: Anup Patel Reviewed-by: Bin Meng --- lib/utils/fdt/fdt_fixup.c | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/lib/utils/fdt/fdt_fixup.c b/lib/utils/fdt/fdt_fixup.c index 619e4f5cbaf..c10179b900c 100644 --- a/lib/utils/fdt/fdt_fixup.c +++ b/lib/utils/fdt/fdt_fixup.c @@ -361,19 +361,22 @@ int fdt_reserved_memory_fixup(void *fdt) return SBI_ENOSPC; } + bool overlap = false; addr = reg->base; for (j = 0; j < i; j++) { if (addr == filtered_base[j] && filtered_order[j] < reg->order) { + overlap = true; filtered_order[j] = reg->order; - goto next_entry; + break; } } - filtered_base[i] = reg->base; - filtered_order[i] = reg->order; - i++; - next_entry: + if (!overlap) { + filtered_base[i] = reg->base; + filtered_order[i] = reg->order; + i++; + } } for (j = 0; j < i; j++) { From 4f2be401025d7f5095dd2a4d2acad0fa60ef15e0 Mon Sep 17 00:00:00 2001 From: Shengyu Qu Date: Thu, 16 Feb 2023 02:26:28 +0800 Subject: [PATCH 055/187] docs: fix typo in fw.md In docs/firmware/fw.md, there's a configuration parameter called FW_TEXT_ADDR, which actually should be FW_TEXT_START, so fix it. Signed-off-by: Shengyu Qu Reviewed-by: Xiang W Reviewed-by: Anup Patel --- docs/firmware/fw.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/firmware/fw.md b/docs/firmware/fw.md index 18faaa9e27e..38351c84a54 100644 --- a/docs/firmware/fw.md +++ b/docs/firmware/fw.md @@ -61,7 +61,7 @@ Firmware Configuration and Compilation All firmware types support the following common compile time configuration parameters: -* **FW_TEXT_ADDR** - Defines the execution address of the OpenSBI firmware. +* **FW_TEXT_START** - Defines the execution address of the OpenSBI firmware. This configuration parameter is mandatory. * **FW_FDT_PATH** - Path to an external flattened device tree binary file to be embedded in the *.rodata* section of the final firmware. If this option From 30ea8069f4c704e67017215f90f74b8588ee9bdf Mon Sep 17 00:00:00 2001 From: Nylon Chen Date: Fri, 10 Feb 2023 16:52:38 +0800 Subject: [PATCH 056/187] lib: sbi_hart: Enable hcontext and scontext According to the description in "riscv-state-enable[0]", to access h/scontext in S-Mode, we need to enable the 57th bit. If it is not enabled, an "illegal instruction" error will occur. Link: https://github.com/riscv/riscv-state-enable/blob/a28bfae443f350d5b4c42874f428367d5b322ffe/content.adoc [0] Signed-off-by: Nylon Chen Reviewed-by: Zong Li Reviewed-by: Anup Patel --- include/sbi/riscv_encoding.h | 2 ++ lib/sbi/sbi_hart.c | 1 + 2 files changed, 3 insertions(+) diff --git a/include/sbi/riscv_encoding.h b/include/sbi/riscv_encoding.h index b0f08c87676..4ebed97ab0a 100644 --- a/include/sbi/riscv_encoding.h +++ b/include/sbi/riscv_encoding.h @@ -736,6 +736,8 @@ #define SMSTATEEN0_CS (_ULL(1) << SMSTATEEN0_CS_SHIFT) #define SMSTATEEN0_FCSR_SHIFT 1 #define SMSTATEEN0_FCSR (_ULL(1) << SMSTATEEN0_FCSR_SHIFT) +#define SMSTATEEN0_CONTEXT_SHIFT 57 +#define SMSTATEEN0_CONTEXT (_ULL(1) << SMSTATEEN0_CONTEXT_SHIFT) #define SMSTATEEN0_IMSIC_SHIFT 58 #define SMSTATEEN0_IMSIC (_ULL(1) << SMSTATEEN0_IMSIC_SHIFT) #define SMSTATEEN0_AIA_SHIFT 59 diff --git a/lib/sbi/sbi_hart.c b/lib/sbi/sbi_hart.c index 02ce99191cd..5e06918c7a4 100644 --- a/lib/sbi/sbi_hart.c +++ b/lib/sbi/sbi_hart.c @@ -90,6 +90,7 @@ static void mstatus_init(struct sbi_scratch *scratch) mstateen_val |= ((uint64_t)csr_read(CSR_MSTATEEN0H)) << 32; #endif mstateen_val |= SMSTATEEN_STATEN; + mstateen_val |= SMSTATEEN0_CONTEXT; mstateen_val |= SMSTATEEN0_HSENVCFG; if (sbi_hart_has_extension(scratch, SBI_HART_EXT_SMAIA)) From 81adc62f45c0baf13112358164a327197e70a7af Mon Sep 17 00:00:00 2001 From: Anup Patel Date: Mon, 13 Feb 2023 10:20:30 +0530 Subject: [PATCH 057/187] lib: sbi: Align SBI vendor extension id with mvendorid CSR As-per the SBI specification, the lower 24bits of the SBI vendor extension id is same as lower 24bits of the mvendorid CSR. We update the SBI vendor extension id checking based on above. Signed-off-by: Anup Patel --- include/sbi/sbi_platform.h | 17 ++++++++--------- lib/sbi/sbi_ecall_vendor.c | 19 +++++++++++++++++-- platform/generic/include/platform_override.h | 1 - platform/generic/platform.c | 19 ++++++------------- 4 files changed, 31 insertions(+), 25 deletions(-) diff --git a/include/sbi/sbi_platform.h b/include/sbi/sbi_platform.h index 43d1c031ed7..3a629a69038 100644 --- a/include/sbi/sbi_platform.h +++ b/include/sbi/sbi_platform.h @@ -126,8 +126,8 @@ struct sbi_platform_operations { /** Exit platform timer for current HART */ void (*timer_exit)(void); - /** platform specific SBI extension implementation probe function */ - int (*vendor_ext_check)(long extid); + /** Check if SBI vendor extension is implemented or not */ + bool (*vendor_ext_check)(void); /** platform specific SBI extension implementation provider */ int (*vendor_ext_provider)(long extid, long funcid, const struct sbi_trap_regs *regs, @@ -636,20 +636,19 @@ static inline void sbi_platform_timer_exit(const struct sbi_platform *plat) } /** - * Check if a vendor extension is implemented or not. + * Check if SBI vendor extension is implemented or not. * * @param plat pointer to struct sbi_platform - * @param extid vendor SBI extension id * - * @return 0 if extid is not implemented and 1 if implemented + * @return false if not implemented and true if implemented */ -static inline int sbi_platform_vendor_ext_check(const struct sbi_platform *plat, - long extid) +static inline bool sbi_platform_vendor_ext_check( + const struct sbi_platform *plat) { if (plat && sbi_platform_ops(plat)->vendor_ext_check) - return sbi_platform_ops(plat)->vendor_ext_check(extid); + return sbi_platform_ops(plat)->vendor_ext_check(); - return 0; + return false; } /** diff --git a/lib/sbi/sbi_ecall_vendor.c b/lib/sbi/sbi_ecall_vendor.c index 9252829633a..9ea5156ba10 100644 --- a/lib/sbi/sbi_ecall_vendor.c +++ b/lib/sbi/sbi_ecall_vendor.c @@ -13,12 +13,23 @@ #include #include #include +#include + +static inline unsigned long sbi_ecall_vendor_id(void) +{ + return SBI_EXT_VENDOR_START + + (csr_read(CSR_MVENDORID) & + (SBI_EXT_VENDOR_END - SBI_EXT_VENDOR_START)); +} static int sbi_ecall_vendor_probe(unsigned long extid, unsigned long *out_val) { - *out_val = sbi_platform_vendor_ext_check(sbi_platform_thishart_ptr(), - extid); + if (!sbi_platform_vendor_ext_check(sbi_platform_thishart_ptr()) || + extid != sbi_ecall_vendor_id()) + *out_val = 0; + else + *out_val = 1; return 0; } @@ -27,6 +38,10 @@ static int sbi_ecall_vendor_handler(unsigned long extid, unsigned long funcid, unsigned long *out_val, struct sbi_trap_info *out_trap) { + if (!sbi_platform_vendor_ext_check(sbi_platform_thishart_ptr()) || + extid != sbi_ecall_vendor_id()) + return SBI_ERR_NOT_SUPPORTED; + return sbi_platform_vendor_ext_provider(sbi_platform_thishart_ptr(), extid, funcid, regs, out_val, out_trap); diff --git a/platform/generic/include/platform_override.h b/platform/generic/include/platform_override.h index a59b06a11d8..350c3811fae 100644 --- a/platform/generic/include/platform_override.h +++ b/platform/generic/include/platform_override.h @@ -27,7 +27,6 @@ struct platform_override { int (*extensions_init)(const struct fdt_match *match, struct sbi_hart_features *hfeatures); void (*fw_init)(void *fdt, const struct fdt_match *match); - int (*vendor_ext_check)(long extid, const struct fdt_match *match); int (*vendor_ext_provider)(long extid, long funcid, const struct sbi_trap_regs *regs, unsigned long *out_value, diff --git a/platform/generic/platform.c b/platform/generic/platform.c index a34d3b01933..88c3ec7e3ab 100644 --- a/platform/generic/platform.c +++ b/platform/generic/platform.c @@ -180,13 +180,10 @@ static int generic_final_init(bool cold_boot) return 0; } -static int generic_vendor_ext_check(long extid) +static bool generic_vendor_ext_check(void) { - if (generic_plat && generic_plat->vendor_ext_check) - return generic_plat->vendor_ext_check(extid, - generic_plat_match); - - return 0; + return (generic_plat && generic_plat->vendor_ext_provider) ? + true : false; } static int generic_vendor_ext_provider(long extid, long funcid, @@ -194,13 +191,9 @@ static int generic_vendor_ext_provider(long extid, long funcid, unsigned long *out_value, struct sbi_trap_info *out_trap) { - if (generic_plat && generic_plat->vendor_ext_provider) { - return generic_plat->vendor_ext_provider(extid, funcid, regs, - out_value, out_trap, - generic_plat_match); - } - - return SBI_ENOTSUPP; + return generic_plat->vendor_ext_provider(extid, funcid, regs, + out_value, out_trap, + generic_plat_match); } static void generic_early_exit(void) From 31b82e0d5046dda92d5d393d66455545763b99c9 Mon Sep 17 00:00:00 2001 From: Anup Patel Date: Mon, 13 Feb 2023 10:39:06 +0530 Subject: [PATCH 058/187] include: sbi: Remove extid parameter from vendor_ext_provider() callback The extid parameter of vendor_ext_provider() is redundant so let us remove it. Signed-off-by: Anup Patel --- include/sbi/sbi_platform.h | 9 ++++----- lib/sbi/sbi_ecall_vendor.c | 2 +- platform/generic/include/platform_override.h | 2 +- platform/generic/platform.c | 4 ++-- 4 files changed, 8 insertions(+), 9 deletions(-) diff --git a/include/sbi/sbi_platform.h b/include/sbi/sbi_platform.h index 3a629a69038..546c0a61acb 100644 --- a/include/sbi/sbi_platform.h +++ b/include/sbi/sbi_platform.h @@ -129,7 +129,7 @@ struct sbi_platform_operations { /** Check if SBI vendor extension is implemented or not */ bool (*vendor_ext_check)(void); /** platform specific SBI extension implementation provider */ - int (*vendor_ext_provider)(long extid, long funcid, + int (*vendor_ext_provider)(long funcid, const struct sbi_trap_regs *regs, unsigned long *out_value, struct sbi_trap_info *out_trap); @@ -655,7 +655,6 @@ static inline bool sbi_platform_vendor_ext_check( * Invoke platform specific vendor SBI extension implementation. * * @param plat pointer to struct sbi_platform - * @param extid vendor SBI extension id * @param funcid SBI function id within the extension id * @param regs pointer to trap registers passed by the caller * @param out_value output value that can be filled by the callee @@ -665,14 +664,14 @@ static inline bool sbi_platform_vendor_ext_check( */ static inline int sbi_platform_vendor_ext_provider( const struct sbi_platform *plat, - long extid, long funcid, + long funcid, const struct sbi_trap_regs *regs, unsigned long *out_value, struct sbi_trap_info *out_trap) { if (plat && sbi_platform_ops(plat)->vendor_ext_provider) { - return sbi_platform_ops(plat)->vendor_ext_provider(extid, - funcid, regs, + return sbi_platform_ops(plat)->vendor_ext_provider(funcid, + regs, out_value, out_trap); } diff --git a/lib/sbi/sbi_ecall_vendor.c b/lib/sbi/sbi_ecall_vendor.c index 9ea5156ba10..8b8dab00c92 100644 --- a/lib/sbi/sbi_ecall_vendor.c +++ b/lib/sbi/sbi_ecall_vendor.c @@ -43,7 +43,7 @@ static int sbi_ecall_vendor_handler(unsigned long extid, unsigned long funcid, return SBI_ERR_NOT_SUPPORTED; return sbi_platform_vendor_ext_provider(sbi_platform_thishart_ptr(), - extid, funcid, regs, + funcid, regs, out_val, out_trap); } diff --git a/platform/generic/include/platform_override.h b/platform/generic/include/platform_override.h index 350c3811fae..0d9e5ee6b40 100644 --- a/platform/generic/include/platform_override.h +++ b/platform/generic/include/platform_override.h @@ -27,7 +27,7 @@ struct platform_override { int (*extensions_init)(const struct fdt_match *match, struct sbi_hart_features *hfeatures); void (*fw_init)(void *fdt, const struct fdt_match *match); - int (*vendor_ext_provider)(long extid, long funcid, + int (*vendor_ext_provider)(long funcid, const struct sbi_trap_regs *regs, unsigned long *out_value, struct sbi_trap_info *out_trap, diff --git a/platform/generic/platform.c b/platform/generic/platform.c index 88c3ec7e3ab..0b90fd7c144 100644 --- a/platform/generic/platform.c +++ b/platform/generic/platform.c @@ -186,12 +186,12 @@ static bool generic_vendor_ext_check(void) true : false; } -static int generic_vendor_ext_provider(long extid, long funcid, +static int generic_vendor_ext_provider(long funcid, const struct sbi_trap_regs *regs, unsigned long *out_value, struct sbi_trap_info *out_trap) { - return generic_plat->vendor_ext_provider(extid, funcid, regs, + return generic_plat->vendor_ext_provider(funcid, regs, out_value, out_trap, generic_plat_match); } From c10095132aca1711a485fb25865237e0e768341c Mon Sep 17 00:00:00 2001 From: Lad Prabhakar Date: Mon, 13 Feb 2023 21:51:09 +0000 Subject: [PATCH 059/187] platform: generic: renesas: rzfive: Add support to configure the PMA I/O Coherence Port (IOCP) provides an AXI interface for connecting external non-caching masters, such as DMA controllers. The accesses from IOCP are coherent with D-Caches and L2 Cache. IOCP is a specification option and is disabled on the Renesas RZ/Five SoC due to this reason IP blocks using DMA will fail. The Andes AX45MP core has a Programmable Physical Memory Attributes (PMA) block that allows dynamic adjustment of memory attributes in the runtime. It contains a configurable amount of PMA entries implemented as CSR registers to control the attributes of memory locations in interest. Below are the memory attributes supported: * Device, Non-bufferable * Device, bufferable * Memory, Non-cacheable, Non-bufferable * Memory, Non-cacheable, Bufferable * Memory, Write-back, No-allocate * Memory, Write-back, Read-allocate * Memory, Write-back, Write-allocate * Memory, Write-back, Read and Write-allocate More info about PMA (section 10.3): Link: http://www.andestech.com/wp-content/uploads/AX45MP-1C-Rev.-5.0.0-Datasheet.pdf As a workaround for SoCs with IOCP disabled CMO needs to be handled by software. Firstly OpenSBI configures the memory region as "Memory, Non-cacheable, Bufferable" and passes this region as a global shared dma pool as a DT node. With DMA_GLOBAL_POOL enabled all DMA allocations happen from this region and synchronization callbacks are implemented to synchronize when doing DMA transactions. Example PMA region passed as a DT node from OpenSBI: reserved-memory { #address-cells = <2>; #size-cells = <2>; ranges; pma_resv0@58000000 { compatible = "shared-dma-pool"; reg = <0x0 0x58000000 0x0 0x08000000>; no-map; linux,dma-default; }; }; Signed-off-by: Lad Prabhakar Reviewed-by: Yu Chien Peter Lin Reviewed-by: Anup Patel --- platform/generic/Kconfig | 2 + platform/generic/andes/Kconfig | 5 + platform/generic/andes/andes45-pma.c | 350 +++++++++++++++++++ platform/generic/andes/objects.mk | 2 + platform/generic/include/andes/andes45_pma.h | 48 +++ 5 files changed, 407 insertions(+) create mode 100644 platform/generic/andes/Kconfig create mode 100644 platform/generic/andes/andes45-pma.c create mode 100644 platform/generic/include/andes/andes45_pma.h diff --git a/platform/generic/Kconfig b/platform/generic/Kconfig index c7f198aee84..39fb4e90d7f 100644 --- a/platform/generic/Kconfig +++ b/platform/generic/Kconfig @@ -50,4 +50,6 @@ config PLATFORM_STARFIVE_JH7110 bool "StarFive JH7110 support" default n +source "$(OPENSBI_SRC_DIR)/platform/generic/andes/Kconfig" + endif diff --git a/platform/generic/andes/Kconfig b/platform/generic/andes/Kconfig new file mode 100644 index 00000000000..3ad4e4ca56f --- /dev/null +++ b/platform/generic/andes/Kconfig @@ -0,0 +1,5 @@ +# SPDX-License-Identifier: BSD-2-Clause + +config ANDES45_PMA + bool "Andes PMA support" + default n diff --git a/platform/generic/andes/andes45-pma.c b/platform/generic/andes/andes45-pma.c new file mode 100644 index 00000000000..2745bc3a998 --- /dev/null +++ b/platform/generic/andes/andes45-pma.c @@ -0,0 +1,350 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (C) 2023 Renesas Electronics Corp. + * + * Copyright (c) 2020 Andes Technology Corporation + * + * Authors: + * Nick Hu + * Nylon Chen + * Lad Prabhakar + */ + +#include +#include +#include +#include +#include +#include +#include + +/* Configuration Registers */ +#define ANDES45_CSR_MMSC_CFG 0xFC2 +#define ANDES45_CSR_MMSC_PPMA_OFFSET (1 << 30) + +#define ANDES45_PMAADDR_0 0xBD0 + +#define ANDES45_PMACFG_0 0xBC0 + +static inline unsigned long andes45_pma_read_cfg(unsigned int pma_cfg_off) +{ +#define switchcase_pma_cfg_read(__pma_cfg_off, __val) \ + case __pma_cfg_off: \ + __val = csr_read(__pma_cfg_off); \ + break; +#define switchcase_pma_cfg_read_2(__pma_cfg_off, __val) \ + switchcase_pma_cfg_read(__pma_cfg_off + 0, __val) \ + switchcase_pma_cfg_read(__pma_cfg_off + 2, __val) + + unsigned long ret = 0; + + switch (pma_cfg_off) { + switchcase_pma_cfg_read_2(ANDES45_PMACFG_0, ret) + + default: + sbi_panic("%s: Unknown PMA CFG offset %#x", __func__, pma_cfg_off); + break; + } + + return ret; + +#undef switchcase_pma_cfg_read_2 +#undef switchcase_pma_cfg_read +} + +static inline void andes45_pma_write_cfg(unsigned int pma_cfg_off, unsigned long val) +{ +#define switchcase_pma_cfg_write(__pma_cfg_off, __val) \ + case __pma_cfg_off: \ + csr_write(__pma_cfg_off, __val); \ + break; +#define switchcase_pma_cfg_write_2(__pma_cfg_off, __val) \ + switchcase_pma_cfg_write(__pma_cfg_off + 0, __val) \ + switchcase_pma_cfg_write(__pma_cfg_off + 2, __val) + + switch (pma_cfg_off) { + switchcase_pma_cfg_write_2(ANDES45_PMACFG_0, val) + + default: + sbi_panic("%s: Unknown PMA CFG offset %#x", __func__, pma_cfg_off); + break; + } + +#undef switchcase_pma_cfg_write_2 +#undef switchcase_pma_cfg_write +} + +static inline void andes45_pma_write_addr(unsigned int pma_addr_off, unsigned long val) +{ +#define switchcase_pma_write(__pma_addr_off, __val) \ + case __pma_addr_off: \ + csr_write(__pma_addr_off, __val); \ + break; +#define switchcase_pma_write_2(__pma_addr_off, __val) \ + switchcase_pma_write(__pma_addr_off + 0, __val) \ + switchcase_pma_write(__pma_addr_off + 1, __val) +#define switchcase_pma_write_4(__pma_addr_off, __val) \ + switchcase_pma_write_2(__pma_addr_off + 0, __val) \ + switchcase_pma_write_2(__pma_addr_off + 2, __val) +#define switchcase_pma_write_8(__pma_addr_off, __val) \ + switchcase_pma_write_4(__pma_addr_off + 0, __val) \ + switchcase_pma_write_4(__pma_addr_off + 4, __val) +#define switchcase_pma_write_16(__pma_addr_off, __val) \ + switchcase_pma_write_8(__pma_addr_off + 0, __val) \ + switchcase_pma_write_8(__pma_addr_off + 8, __val) + + switch (pma_addr_off) { + switchcase_pma_write_16(ANDES45_PMAADDR_0, val) + + default: + sbi_panic("%s: Unknown PMA ADDR offset %#x", __func__, pma_addr_off); + break; + } + +#undef switchcase_pma_write_16 +#undef switchcase_pma_write_8 +#undef switchcase_pma_write_4 +#undef switchcase_pma_write_2 +#undef switchcase_pma_write +} + +static inline unsigned long andes45_pma_read_addr(unsigned int pma_addr_off) +{ +#define switchcase_pma_read(__pma_addr_off, __val) \ + case __pma_addr_off: \ + __val = csr_read(__pma_addr_off); \ + break; +#define switchcase_pma_read_2(__pma_addr_off, __val) \ + switchcase_pma_read(__pma_addr_off + 0, __val) \ + switchcase_pma_read(__pma_addr_off + 1, __val) +#define switchcase_pma_read_4(__pma_addr_off, __val) \ + switchcase_pma_read_2(__pma_addr_off + 0, __val) \ + switchcase_pma_read_2(__pma_addr_off + 2, __val) +#define switchcase_pma_read_8(__pma_addr_off, __val) \ + switchcase_pma_read_4(__pma_addr_off + 0, __val) \ + switchcase_pma_read_4(__pma_addr_off + 4, __val) +#define switchcase_pma_read_16(__pma_addr_off, __val) \ + switchcase_pma_read_8(__pma_addr_off + 0, __val) \ + switchcase_pma_read_8(__pma_addr_off + 8, __val) + + unsigned long ret = 0; + + switch (pma_addr_off) { + switchcase_pma_read_16(ANDES45_PMAADDR_0, ret) + + default: + sbi_panic("%s: Unknown PMA ADDR offset %#x", __func__, pma_addr_off); + break; + } + + return ret; + +#undef switchcase_pma_read_16 +#undef switchcase_pma_read_8 +#undef switchcase_pma_read_4 +#undef switchcase_pma_read_2 +#undef switchcase_pma_read +} + +static unsigned long +andes45_pma_setup(const struct andes45_pma_region *pma_region, + unsigned int entry_id) +{ + unsigned long size = pma_region->size; + unsigned long addr = pma_region->pa; + unsigned int pma_cfg_addr; + unsigned long pmacfg_val; + unsigned long pmaaddr; + char *pmaxcfg; + + /* Check for 4KiB granularity */ + if (size < (1 << 12)) + return SBI_EINVAL; + + /* Check size is power of 2 */ + if (size & (size - 1)) + return SBI_EINVAL; + + if (entry_id > 15) + return SBI_EINVAL; + + if (!(pma_region->flags & ANDES45_PMACFG_ETYP_NAPOT)) + return SBI_EINVAL; + + if ((addr & (size - 1)) != 0) + return SBI_EINVAL; + + pma_cfg_addr = entry_id / 8 ? ANDES45_PMACFG_0 + 2 : ANDES45_PMACFG_0; + pmacfg_val = andes45_pma_read_cfg(pma_cfg_addr); + pmaxcfg = (char *)&pmacfg_val + (entry_id % 8); + *pmaxcfg = 0; + *pmaxcfg = pma_region->flags; + + andes45_pma_write_cfg(pma_cfg_addr, pmacfg_val); + + pmaaddr = (addr >> 2) + (size >> 3) - 1; + + andes45_pma_write_addr(ANDES45_PMAADDR_0 + entry_id, pmaaddr); + + return andes45_pma_read_addr(ANDES45_PMAADDR_0 + entry_id) == pmaaddr ? + pmaaddr : SBI_EINVAL; +} + +static int andes45_fdt_pma_resv(void *fdt, const struct andes45_pma_region *pma, + unsigned int index, int parent) +{ + int na = fdt_address_cells(fdt, 0); + int ns = fdt_size_cells(fdt, 0); + static bool dma_default = false; + fdt32_t addr_high, addr_low; + fdt32_t size_high, size_low; + int subnode, err; + fdt32_t reg[4]; + fdt32_t *val; + char name[32]; + + addr_high = (u64)pma->pa >> 32; + addr_low = pma->pa; + size_high = (u64)pma->size >> 32; + size_low = pma->size; + + if (na > 1 && addr_high) + sbi_snprintf(name, sizeof(name), + "pma_resv%d@%x,%x", index, + addr_high, addr_low); + else + sbi_snprintf(name, sizeof(name), + "pma_resv%d@%x", index, + addr_low); + + subnode = fdt_add_subnode(fdt, parent, name); + if (subnode < 0) + return subnode; + + if (pma->shared_dma) { + err = fdt_setprop_string(fdt, subnode, "compatible", "shared-dma-pool"); + if (err < 0) + return err; + } + + if (pma->no_map) { + err = fdt_setprop_empty(fdt, subnode, "no-map"); + if (err < 0) + return err; + } + + /* Linux allows single linux,dma-default region. */ + if (pma->dma_default) { + if (dma_default) + return SBI_EINVAL; + + err = fdt_setprop_empty(fdt, subnode, "linux,dma-default"); + if (err < 0) + return err; + dma_default = true; + } + + /* encode the property value */ + val = reg; + if (na > 1) + *val++ = cpu_to_fdt32(addr_high); + *val++ = cpu_to_fdt32(addr_low); + if (ns > 1) + *val++ = cpu_to_fdt32(size_high); + *val++ = cpu_to_fdt32(size_low); + + err = fdt_setprop(fdt, subnode, "reg", reg, + (na + ns) * sizeof(fdt32_t)); + if (err < 0) + return err; + + return 0; +} + +static int andes45_fdt_reserved_memory_fixup(void *fdt, + const struct andes45_pma_region *pma, + unsigned int entry) +{ + int parent; + + /* try to locate the reserved memory node */ + parent = fdt_path_offset(fdt, "/reserved-memory"); + if (parent < 0) { + int na = fdt_address_cells(fdt, 0); + int ns = fdt_size_cells(fdt, 0); + int err; + + /* if such node does not exist, create one */ + parent = fdt_add_subnode(fdt, 0, "reserved-memory"); + if (parent < 0) + return parent; + + err = fdt_setprop_empty(fdt, parent, "ranges"); + if (err < 0) + return err; + + err = fdt_setprop_u32(fdt, parent, "#size-cells", ns); + if (err < 0) + return err; + + err = fdt_setprop_u32(fdt, parent, "#address-cells", na); + if (err < 0) + return err; + } + + return andes45_fdt_pma_resv(fdt, pma, entry, parent); +} + +int andes45_pma_setup_regions(const struct andes45_pma_region *pma_regions, + unsigned int pma_regions_count) +{ + unsigned long mmsc = csr_read(ANDES45_CSR_MMSC_CFG); + unsigned int dt_populate_cnt; + unsigned int i, j; + unsigned long pa; + void *fdt; + int ret; + + if (!pma_regions || !pma_regions_count) + return 0; + + if (pma_regions_count > ANDES45_MAX_PMA_REGIONS) + return SBI_EINVAL; + + if ((mmsc & ANDES45_CSR_MMSC_PPMA_OFFSET) == 0) + return SBI_ENOTSUPP; + + /* Configure the PMA regions */ + for (i = 0; i < pma_regions_count; i++) { + pa = andes45_pma_setup(&pma_regions[i], i); + if (pa == SBI_EINVAL) + return SBI_EINVAL; + } + + dt_populate_cnt = 0; + for (i = 0; i < pma_regions_count; i++) { + if (!pma_regions[i].dt_populate) + continue; + dt_populate_cnt++; + } + + if (!dt_populate_cnt) + return 0; + + fdt = fdt_get_address(); + + ret = fdt_open_into(fdt, fdt, fdt_totalsize(fdt) + (64 * dt_populate_cnt)); + if (ret < 0) + return ret; + + for (i = 0, j = 0; i < pma_regions_count; i++) { + if (!pma_regions[i].dt_populate) + continue; + + ret = andes45_fdt_reserved_memory_fixup(fdt, &pma_regions[i], j++); + if (ret) + return ret; + } + + return 0; +} diff --git a/platform/generic/andes/objects.mk b/platform/generic/andes/objects.mk index 28275efbccf..ea6b561953e 100644 --- a/platform/generic/andes/objects.mk +++ b/platform/generic/andes/objects.mk @@ -4,3 +4,5 @@ carray-platform_override_modules-$(CONFIG_PLATFORM_ANDES_AE350) += andes_ae350 platform-objs-$(CONFIG_PLATFORM_ANDES_AE350) += andes/ae350.o andes/sleep.o + +platform-objs-$(CONFIG_ANDES45_PMA) += andes/andes45-pma.o diff --git a/platform/generic/include/andes/andes45_pma.h b/platform/generic/include/andes/andes45_pma.h new file mode 100644 index 00000000000..37ec77cf670 --- /dev/null +++ b/platform/generic/include/andes/andes45_pma.h @@ -0,0 +1,48 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright (C) 2023 Renesas Electronics Corp. + */ + +#ifndef _ANDES45_PMA_H_ +#define _ANDES45_PMA_H_ + +#include + +#define ANDES45_MAX_PMA_REGIONS 16 + +/* Naturally aligned power of 2 region */ +#define ANDES45_PMACFG_ETYP_NAPOT 3 + +/* Memory, Non-cacheable, Bufferable */ +#define ANDES45_PMACFG_MTYP_MEM_NON_CACHE_BUF (3 << 2) + +/** + * struct andes45_pma_region - Describes PMA regions + * + * @pa: Address to be configured in the PMA + * @size: Size of the region + * @flags: Flags to be set for the PMA region + * @dt_populate: Boolean flag indicating if the DT entry should be + * populated for the given PMA region + * @shared_dma: Boolean flag if set "shared-dma-pool" property will + * be set in the DT node + * @no_map: Boolean flag if set "no-map" property will be set in the + * DT node + * @dma_default: Boolean flag if set "linux,dma-default" property will + * be set in the DT node. Note Linux expects single node + * with this property set. + */ +struct andes45_pma_region { + unsigned long pa; + unsigned long size; + u8 flags:7; + bool dt_populate; + bool shared_dma; + bool no_map; + bool dma_default; +}; + +int andes45_pma_setup_regions(const struct andes45_pma_region *pma_regions, + unsigned int pma_regions_count); + +#endif /* _ANDES45_PMA_H_ */ From 2491242282b4e3bb0617f41dfb667ca9a8241c0a Mon Sep 17 00:00:00 2001 From: Lad Prabhakar Date: Mon, 13 Feb 2023 21:51:10 +0000 Subject: [PATCH 060/187] platform: generic: renesas: rzfive: Configure the PMA region On the Renesas RZ/Five SoC by default we want to configure 128MiB of memory ranging from 0x58000000 as a non-cacheable + bufferable region in the PMA and populate this region as PMA reserve DT node with shared DMA pool and no-map flags set so that Linux drivers requesting any DMA'able memory go through this region. PMA node passed to the above stack: reserved-memory { #address-cells = <2>; #size-cells = <2>; ranges; pma_resv0@58000000 { compatible = "shared-dma-pool"; reg = <0x0 0x58000000 0x0 0x08000000>; no-map; linux,dma-default; }; }; Signed-off-by: Lad Prabhakar Reviewed-by: Yu Chien Peter Lin Reviewed-by: Anup Patel --- platform/generic/Kconfig | 1 + platform/generic/renesas/rzfive/rzfive.c | 21 +++++++++++++++++++++ 2 files changed, 22 insertions(+) diff --git a/platform/generic/Kconfig b/platform/generic/Kconfig index 39fb4e90d7f..1f4f8e1f340 100644 --- a/platform/generic/Kconfig +++ b/platform/generic/Kconfig @@ -35,6 +35,7 @@ config PLATFORM_ANDES_AE350 config PLATFORM_RENESAS_RZFIVE bool "Renesas RZ/Five support" + select ANDES45_PMA default n config PLATFORM_SIFIVE_FU540 diff --git a/platform/generic/renesas/rzfive/rzfive.c b/platform/generic/renesas/rzfive/rzfive.c index ee9c9c4eba9..4d71d0d6c22 100644 --- a/platform/generic/renesas/rzfive/rzfive.c +++ b/platform/generic/renesas/rzfive/rzfive.c @@ -4,10 +4,30 @@ * */ +#include #include #include #include +static const struct andes45_pma_region renesas_rzfive_pma_regions[] = { + { + .pa = 0x58000000, + .size = 0x8000000, + .flags = ANDES45_PMACFG_ETYP_NAPOT | + ANDES45_PMACFG_MTYP_MEM_NON_CACHE_BUF, + .dt_populate = true, + .shared_dma = true, + .no_map = true, + .dma_default = true, + }, +}; + +static int renesas_rzfive_final_init(bool cold_boot, const struct fdt_match *match) +{ + return andes45_pma_setup_regions(renesas_rzfive_pma_regions, + array_size(renesas_rzfive_pma_regions)); +} + int renesas_rzfive_early_init(bool cold_boot, const struct fdt_match *match) { /* @@ -34,4 +54,5 @@ static const struct fdt_match renesas_rzfive_match[] = { const struct platform_override renesas_rzfive = { .match_table = renesas_rzfive_match, .early_init = renesas_rzfive_early_init, + .final_init = renesas_rzfive_final_init, }; From 67b2a408924b466dcd659c70348043987401f0b1 Mon Sep 17 00:00:00 2001 From: Yu Chien Peter Lin Date: Wed, 22 Feb 2023 10:48:54 +0800 Subject: [PATCH 061/187] lib: sbi: sbi_ecall: Check the range of SBI error We should also check if the return error code is greater than 0 (SBI_SUCCESS), as this is an invalid error. Signed-off-by: Yu Chien Peter Lin Reviewed-by: Xiang W Reviewed-by: Andrew Jones Reviewed-by: Anup Patel --- lib/sbi/sbi_ecall.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/sbi/sbi_ecall.c b/lib/sbi/sbi_ecall.c index 27ce5d49342..d0f01665368 100644 --- a/lib/sbi/sbi_ecall.c +++ b/lib/sbi/sbi_ecall.c @@ -120,7 +120,7 @@ int sbi_ecall_handler(struct sbi_trap_regs *regs) trap.epc = regs->mepc; sbi_trap_redirect(regs, &trap); } else { - if (ret < SBI_LAST_ERR) { + if (ret < SBI_LAST_ERR || SBI_SUCCESS < ret) { sbi_printf("%s: Invalid error %d for ext=0x%lx " "func=0x%lx\n", __func__, ret, extension_id, func_id); From 5a75f5309c7544bbf7ef021bdeee0b0455af6d9b Mon Sep 17 00:00:00 2001 From: Bin Meng Date: Fri, 24 Feb 2023 12:28:25 +0800 Subject: [PATCH 062/187] lib: sbi/sbi_domain: cosmetic style fixes Minor updates to the comments for language and style fixes. Signed-off-by: Bin Meng Reviewed-by: Anup Patel --- lib/sbi/sbi_domain.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/sbi/sbi_domain.c b/lib/sbi/sbi_domain.c index dc825b0d95f..d2f58a28cbd 100644 --- a/lib/sbi/sbi_domain.c +++ b/lib/sbi/sbi_domain.c @@ -337,7 +337,7 @@ static int sanitize_domain(const struct sbi_platform *plat, /* * Check next mode * - * We only allow next mode to be S-mode or U-mode.so that we can + * We only allow next mode to be S-mode or U-mode, so that we can * protect M-mode context and enforce checks on memory accesses. */ if (dom->next_mode != PRV_S && @@ -347,7 +347,7 @@ static int sanitize_domain(const struct sbi_platform *plat, return SBI_EINVAL; } - /* Check next address and next mode*/ + /* Check next address and next mode */ if (!sbi_domain_check_addr(dom, dom->next_addr, dom->next_mode, SBI_DOMAIN_EXECUTE)) { sbi_printf("%s: %s next booting stage address 0x%lx can't " From bc06ff65bf97172d11d6c898291fe1b98e177715 Mon Sep 17 00:00:00 2001 From: Bin Meng Date: Fri, 24 Feb 2023 12:28:26 +0800 Subject: [PATCH 063/187] lib: utils/fdt/fdt_domain: Simplify region access permission check The region access permission check in __fdt_parse_region() can be simplified as masking SBI_DOMAIN_MEMREGION_{M,SU}_ACCESS_MASK is enough. While we are here, update the confusing comments to match the codes. Signed-off-by: Bin Meng Reviewed-by: Anup Patel --- lib/utils/fdt/fdt_domain.c | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/lib/utils/fdt/fdt_domain.c b/lib/utils/fdt/fdt_domain.c index 2b51a8ebe13..bc30010a888 100644 --- a/lib/utils/fdt/fdt_domain.c +++ b/lib/utils/fdt/fdt_domain.c @@ -244,13 +244,11 @@ static int __fdt_parse_region(void *fdt, int domain_offset, * access permissions. M-mode regions can only be part of * root domain. * - * SU permission bits can't be all zeroes and M-mode permission - * bits must be all set. + * SU permission bits can't be all zeroes when M-mode permission + * bits have at least one bit set. */ - if (!((region_access & SBI_DOMAIN_MEMREGION_SU_ACCESS_MASK) - & SBI_DOMAIN_MEMREGION_SU_RWX) - && ((region_access & SBI_DOMAIN_MEMREGION_M_ACCESS_MASK) - & SBI_DOMAIN_MEMREGION_M_RWX)) + if (!(region_access & SBI_DOMAIN_MEMREGION_SU_ACCESS_MASK) + && (region_access & SBI_DOMAIN_MEMREGION_M_ACCESS_MASK)) return SBI_EINVAL; /* Find next region of the domain */ From 17b3776c812921adcc527d542331b439b53c7b71 Mon Sep 17 00:00:00 2001 From: Bin Meng Date: Fri, 24 Feb 2023 12:28:27 +0800 Subject: [PATCH 064/187] docs: domain_support: Update the DT example commit 3e2f573e707e ("lib: utils: Disallow non-root domains from adding M-mode regions") added access permission check in __fdt_parse_region(). With the existing DT example in the doc OpenSBI won't boot anymore. Let's update the DT example so that it can work out of the box. Signed-off-by: Bin Meng Reviewed-by: Anup Patel --- docs/domain_support.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/domain_support.md b/docs/domain_support.md index 4ccbcff8719..2a9ca3d70ea 100644 --- a/docs/domain_support.md +++ b/docs/domain_support.md @@ -254,7 +254,7 @@ be done: tdomain: trusted-domain { compatible = "opensbi,domain,instance"; possible-harts = <&cpu0>; - regions = <&tmem 0x7>, <&tuart 0x7>; + regions = <&tmem 0x3f>, <&tuart 0x3f>; boot-hart = <&cpu0>; next-arg1 = <0x0 0x0>; next-addr = <0x0 0x80100000>; @@ -265,7 +265,7 @@ be done: udomain: untrusted-domain { compatible = "opensbi,domain,instance"; possible-harts = <&cpu1 &cpu2 &cpu3 &cpu4>; - regions = <&tmem 0x0>, <&tuart 0x0>, <&allmem 0x7>; + regions = <&tmem 0x0>, <&tuart 0x0>, <&allmem 0x3f>; }; }; }; From 1364d5adb291ecf7471db571956545f592a5a615 Mon Sep 17 00:00:00 2001 From: Andrew Jones Date: Mon, 27 Feb 2023 11:30:56 +0100 Subject: [PATCH 065/187] lib: sbi_hsm: Factor out invalid state detection Remove some redundant code by creating an invalid state detection macro. No functional change intended. Signed-off-by: Andrew Jones Reviewed-by: Anup Patel --- lib/sbi/sbi_hsm.c | 65 +++++++++++++++++------------------------------ 1 file changed, 24 insertions(+), 41 deletions(-) diff --git a/lib/sbi/sbi_hsm.c b/lib/sbi/sbi_hsm.c index 8499bb1ddea..b71ee6ba4e8 100644 --- a/lib/sbi/sbi_hsm.c +++ b/lib/sbi/sbi_hsm.c @@ -26,6 +26,15 @@ #include #include +#define __sbi_hsm_hart_change_state(hdata, oldstate, newstate) \ +({ \ + long state = atomic_cmpxchg(&(hdata)->state, oldstate, newstate); \ + if (state != (oldstate)) \ + sbi_printf("%s: ERR: The hart is in invalid state [%lu]\n", \ + __func__, state); \ + state == (oldstate); \ +}) + static const struct sbi_hsm_device *hsm_dev = NULL; static unsigned long hart_data_offset; @@ -95,13 +104,11 @@ int sbi_hsm_hart_interruptible_mask(const struct sbi_domain *dom, void sbi_hsm_prepare_next_jump(struct sbi_scratch *scratch, u32 hartid) { - u32 oldstate; struct sbi_hsm_data *hdata = sbi_scratch_offset_ptr(scratch, hart_data_offset); - oldstate = atomic_cmpxchg(&hdata->state, SBI_HSM_STATE_START_PENDING, - SBI_HSM_STATE_STARTED); - if (oldstate != SBI_HSM_STATE_START_PENDING) + if (!__sbi_hsm_hart_change_state(hdata, SBI_HSM_STATE_START_PENDING, + SBI_HSM_STATE_STARTED)) sbi_hart_hang(); } @@ -217,14 +224,12 @@ int sbi_hsm_init(struct sbi_scratch *scratch, u32 hartid, bool cold_boot) void __noreturn sbi_hsm_exit(struct sbi_scratch *scratch) { - u32 hstate; struct sbi_hsm_data *hdata = sbi_scratch_offset_ptr(scratch, hart_data_offset); void (*jump_warmboot)(void) = (void (*)(void))scratch->warmboot_addr; - hstate = atomic_cmpxchg(&hdata->state, SBI_HSM_STATE_STOP_PENDING, - SBI_HSM_STATE_STOPPED); - if (hstate != SBI_HSM_STATE_STOP_PENDING) + if (!__sbi_hsm_hart_change_state(hdata, SBI_HSM_STATE_STOP_PENDING, + SBI_HSM_STATE_STOPPED)) goto fail_exit; if (hsm_device_has_hart_hotplug()) { @@ -298,7 +303,6 @@ int sbi_hsm_hart_start(struct sbi_scratch *scratch, int sbi_hsm_hart_stop(struct sbi_scratch *scratch, bool exitnow) { - int oldstate; const struct sbi_domain *dom = sbi_domain_thishart_ptr(); struct sbi_hsm_data *hdata = sbi_scratch_offset_ptr(scratch, hart_data_offset); @@ -306,13 +310,9 @@ int sbi_hsm_hart_stop(struct sbi_scratch *scratch, bool exitnow) if (!dom) return SBI_EFAIL; - oldstate = atomic_cmpxchg(&hdata->state, SBI_HSM_STATE_STARTED, - SBI_HSM_STATE_STOP_PENDING); - if (oldstate != SBI_HSM_STATE_STARTED) { - sbi_printf("%s: ERR: The hart is in invalid state [%u]\n", - __func__, oldstate); + if (!__sbi_hsm_hart_change_state(hdata, SBI_HSM_STATE_STARTED, + SBI_HSM_STATE_STOP_PENDING)) return SBI_EFAIL; - } if (exitnow) sbi_exit(scratch); @@ -362,36 +362,26 @@ static void __sbi_hsm_suspend_non_ret_restore(struct sbi_scratch *scratch) void sbi_hsm_hart_resume_start(struct sbi_scratch *scratch) { - int oldstate; struct sbi_hsm_data *hdata = sbi_scratch_offset_ptr(scratch, hart_data_offset); /* If current HART was SUSPENDED then set RESUME_PENDING state */ - oldstate = atomic_cmpxchg(&hdata->state, SBI_HSM_STATE_SUSPENDED, - SBI_HSM_STATE_RESUME_PENDING); - if (oldstate != SBI_HSM_STATE_SUSPENDED) { - sbi_printf("%s: ERR: The hart is in invalid state [%u]\n", - __func__, oldstate); + if (!__sbi_hsm_hart_change_state(hdata, SBI_HSM_STATE_SUSPENDED, + SBI_HSM_STATE_RESUME_PENDING)) sbi_hart_hang(); - } hsm_device_hart_resume(); } void sbi_hsm_hart_resume_finish(struct sbi_scratch *scratch) { - u32 oldstate; struct sbi_hsm_data *hdata = sbi_scratch_offset_ptr(scratch, hart_data_offset); /* If current HART was RESUME_PENDING then set STARTED state */ - oldstate = atomic_cmpxchg(&hdata->state, SBI_HSM_STATE_RESUME_PENDING, - SBI_HSM_STATE_STARTED); - if (oldstate != SBI_HSM_STATE_RESUME_PENDING) { - sbi_printf("%s: ERR: The hart is in invalid state [%u]\n", - __func__, oldstate); + if (!__sbi_hsm_hart_change_state(hdata, SBI_HSM_STATE_RESUME_PENDING, + SBI_HSM_STATE_STARTED)) sbi_hart_hang(); - } /* * Restore some of the M-mode CSRs which we are re-configured by @@ -403,7 +393,7 @@ void sbi_hsm_hart_resume_finish(struct sbi_scratch *scratch) int sbi_hsm_hart_suspend(struct sbi_scratch *scratch, u32 suspend_type, ulong raddr, ulong rmode, ulong arg1) { - int oldstate, ret; + int ret; const struct sbi_domain *dom = sbi_domain_thishart_ptr(); struct sbi_hsm_data *hdata = sbi_scratch_offset_ptr(scratch, hart_data_offset); @@ -437,11 +427,8 @@ int sbi_hsm_hart_suspend(struct sbi_scratch *scratch, u32 suspend_type, scratch->next_mode = rmode; /* Directly move from STARTED to SUSPENDED state */ - oldstate = atomic_cmpxchg(&hdata->state, SBI_HSM_STATE_STARTED, - SBI_HSM_STATE_SUSPENDED); - if (oldstate != SBI_HSM_STATE_STARTED) { - sbi_printf("%s: ERR: The hart is in invalid state [%u]\n", - __func__, oldstate); + if (!__sbi_hsm_hart_change_state(hdata, SBI_HSM_STATE_STARTED, + SBI_HSM_STATE_SUSPENDED)) { ret = SBI_EDENIED; goto fail_restore_state; } @@ -484,13 +471,9 @@ int sbi_hsm_hart_suspend(struct sbi_scratch *scratch, u32 suspend_type, * We might have successfully resumed from retentive suspend * or suspend failed. In both cases, we restore state of hart. */ - oldstate = atomic_cmpxchg(&hdata->state, SBI_HSM_STATE_SUSPENDED, - SBI_HSM_STATE_STARTED); - if (oldstate != SBI_HSM_STATE_SUSPENDED) { - sbi_printf("%s: ERR: The hart is in invalid state [%u]\n", - __func__, oldstate); + if (!__sbi_hsm_hart_change_state(hdata, SBI_HSM_STATE_SUSPENDED, + SBI_HSM_STATE_STARTED)) sbi_hart_hang(); - } return ret; } From 40f16a81d33d70b113645fc9dc5071a74267e613 Mon Sep 17 00:00:00 2001 From: Andrew Jones Date: Mon, 27 Feb 2023 11:30:57 +0100 Subject: [PATCH 066/187] lib: sbi_hsm: Don't try to restore state on failed change When a state change fails there's no need to restore the original state as it remains the same. Signed-off-by: Andrew Jones Reviewed-by: Anup Patel --- lib/sbi/sbi_hsm.c | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/lib/sbi/sbi_hsm.c b/lib/sbi/sbi_hsm.c index b71ee6ba4e8..7ee4159256b 100644 --- a/lib/sbi/sbi_hsm.c +++ b/lib/sbi/sbi_hsm.c @@ -428,10 +428,8 @@ int sbi_hsm_hart_suspend(struct sbi_scratch *scratch, u32 suspend_type, /* Directly move from STARTED to SUSPENDED state */ if (!__sbi_hsm_hart_change_state(hdata, SBI_HSM_STATE_STARTED, - SBI_HSM_STATE_SUSPENDED)) { - ret = SBI_EDENIED; - goto fail_restore_state; - } + SBI_HSM_STATE_SUSPENDED)) + return SBI_EDENIED; /* Save the suspend type */ hdata->suspend_type = suspend_type; @@ -466,7 +464,6 @@ int sbi_hsm_hart_suspend(struct sbi_scratch *scratch, u32 suspend_type, jump_warmboot(); } -fail_restore_state: /* * We might have successfully resumed from retentive suspend * or suspend failed. In both cases, we restore state of hart. From c88e039ec23c41ad0769c6714f60904f89fa3a5d Mon Sep 17 00:00:00 2001 From: Andrew Jones Date: Mon, 27 Feb 2023 11:30:58 +0100 Subject: [PATCH 067/187] lib: sbi_hsm: Ensure errors are consistent with spec HSM functions define when SBI_ERR_INVALID_PARAM should be returned. Ensure it's not used for reasons that don't meet the definitions by using the catch-all code, SBI_ERR_FAILED, for those reasons instead. Also, in one case sbi_hart_suspend() may have returned SBI_ERR_DENIED, which isn't defined for that function at all. Use SBI_ERR_FAILED for that case too. Signed-off-by: Andrew Jones Reviewed-by: Anup Patel --- lib/sbi/sbi_hsm.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/lib/sbi/sbi_hsm.c b/lib/sbi/sbi_hsm.c index 7ee4159256b..3455520b8a9 100644 --- a/lib/sbi/sbi_hsm.c +++ b/lib/sbi/sbi_hsm.c @@ -402,7 +402,7 @@ int sbi_hsm_hart_suspend(struct sbi_scratch *scratch, u32 suspend_type, /* Sanity check on domain assigned to current HART */ if (!dom) - return SBI_EINVAL; + return SBI_EFAIL; /* Sanity check on suspend type */ if (SBI_HSM_SUSPEND_RET_DEFAULT < suspend_type && @@ -415,7 +415,7 @@ int sbi_hsm_hart_suspend(struct sbi_scratch *scratch, u32 suspend_type, /* Additional sanity check for non-retentive suspend */ if (suspend_type & SBI_HSM_SUSP_NON_RET_BIT) { if (rmode != PRV_S && rmode != PRV_U) - return SBI_EINVAL; + return SBI_EFAIL; if (dom && !sbi_domain_check_addr(dom, raddr, rmode, SBI_DOMAIN_EXECUTE)) return SBI_EINVALID_ADDR; @@ -429,7 +429,7 @@ int sbi_hsm_hart_suspend(struct sbi_scratch *scratch, u32 suspend_type, /* Directly move from STARTED to SUSPENDED state */ if (!__sbi_hsm_hart_change_state(hdata, SBI_HSM_STATE_STARTED, SBI_HSM_STATE_SUSPENDED)) - return SBI_EDENIED; + return SBI_EFAIL; /* Save the suspend type */ hdata->suspend_type = suspend_type; From b1ae6ef33ba92fe7d85edd87656998330637ed7e Mon Sep 17 00:00:00 2001 From: Andrew Jones Date: Mon, 27 Feb 2023 11:30:59 +0100 Subject: [PATCH 068/187] lib: sbi_hsm: Move misplaced comment While non-retentive suspend is not allowed for M-mode, the comment at the top of sbi_hsm_hart_suspend() implied suspend wasn't allowed for M-mode at all. Move the comment above the mode check which is inside a suspend type is non-retentive check. Signed-off-by: Andrew Jones Reviewed-by: Anup Patel --- lib/sbi/sbi_hsm.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/lib/sbi/sbi_hsm.c b/lib/sbi/sbi_hsm.c index 3455520b8a9..294156a9a7b 100644 --- a/lib/sbi/sbi_hsm.c +++ b/lib/sbi/sbi_hsm.c @@ -398,8 +398,6 @@ int sbi_hsm_hart_suspend(struct sbi_scratch *scratch, u32 suspend_type, struct sbi_hsm_data *hdata = sbi_scratch_offset_ptr(scratch, hart_data_offset); - /* For now, we only allow suspend from S-mode or U-mode. */ - /* Sanity check on domain assigned to current HART */ if (!dom) return SBI_EFAIL; @@ -414,6 +412,10 @@ int sbi_hsm_hart_suspend(struct sbi_scratch *scratch, u32 suspend_type, /* Additional sanity check for non-retentive suspend */ if (suspend_type & SBI_HSM_SUSP_NON_RET_BIT) { + /* + * For now, we only allow non-retentive suspend from + * S-mode or U-mode. + */ if (rmode != PRV_S && rmode != PRV_U) return SBI_EFAIL; if (dom && !sbi_domain_check_addr(dom, raddr, rmode, From 07673fc0633db82db939c0cf896c19ef0a7c548e Mon Sep 17 00:00:00 2001 From: Andrew Jones Date: Mon, 27 Feb 2023 11:31:00 +0100 Subject: [PATCH 069/187] lib: sbi_hsm: Remove unnecessary include Also remove a superfluous semicolon and add a blank line. Signed-off-by: Andrew Jones Reviewed-by: Anup Patel --- lib/sbi/sbi_ecall_hsm.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/sbi/sbi_ecall_hsm.c b/lib/sbi/sbi_ecall_hsm.c index 703a824493b..f1b41d073b2 100644 --- a/lib/sbi/sbi_ecall_hsm.c +++ b/lib/sbi/sbi_ecall_hsm.c @@ -12,7 +12,6 @@ #include #include #include -#include #include #include #include @@ -45,7 +44,8 @@ static int sbi_ecall_hsm_handler(unsigned long extid, unsigned long funcid, break; default: ret = SBI_ENOTSUPP; - }; + } + if (ret >= 0) { *out_val = ret; ret = 0; From 8a40306371b7e5dbe20da946edd0ddd9693bfa85 Mon Sep 17 00:00:00 2001 From: Andrew Jones Date: Mon, 27 Feb 2023 11:31:01 +0100 Subject: [PATCH 070/187] lib: sbi_hsm: Export some functions A coming patch can make use of a few internal hsm functions if we export them. Signed-off-by: Andrew Jones Reviewed-by: Anup Patel --- include/sbi/sbi_hsm.h | 4 ++++ lib/sbi/sbi_hsm.c | 12 ++++++++++-- 2 files changed, 14 insertions(+), 2 deletions(-) diff --git a/include/sbi/sbi_hsm.h b/include/sbi/sbi_hsm.h index 1170127baa8..c0b483030de 100644 --- a/include/sbi/sbi_hsm.h +++ b/include/sbi/sbi_hsm.h @@ -69,9 +69,13 @@ void sbi_hsm_hart_resume_start(struct sbi_scratch *scratch); void sbi_hsm_hart_resume_finish(struct sbi_scratch *scratch); int sbi_hsm_hart_suspend(struct sbi_scratch *scratch, u32 suspend_type, ulong raddr, ulong rmode, ulong arg1); +bool sbi_hsm_hart_change_state(struct sbi_scratch *scratch, long oldstate, + long newstate); +int __sbi_hsm_hart_get_state(u32 hartid); int sbi_hsm_hart_get_state(const struct sbi_domain *dom, u32 hartid); int sbi_hsm_hart_interruptible_mask(const struct sbi_domain *dom, ulong hbase, ulong *out_hmask); +void __sbi_hsm_suspend_non_ret_save(struct sbi_scratch *scratch); void sbi_hsm_prepare_next_jump(struct sbi_scratch *scratch, u32 hartid); #endif diff --git a/lib/sbi/sbi_hsm.c b/lib/sbi/sbi_hsm.c index 294156a9a7b..3eeeb586cbb 100644 --- a/lib/sbi/sbi_hsm.c +++ b/lib/sbi/sbi_hsm.c @@ -46,7 +46,15 @@ struct sbi_hsm_data { unsigned long saved_mip; }; -static inline int __sbi_hsm_hart_get_state(u32 hartid) +bool sbi_hsm_hart_change_state(struct sbi_scratch *scratch, long oldstate, + long newstate) +{ + struct sbi_hsm_data *hdata = sbi_scratch_offset_ptr(scratch, + hart_data_offset); + return __sbi_hsm_hart_change_state(hdata, oldstate, newstate); +} + +int __sbi_hsm_hart_get_state(u32 hartid) { struct sbi_hsm_data *hdata; struct sbi_scratch *scratch; @@ -328,7 +336,7 @@ static int __sbi_hsm_suspend_default(struct sbi_scratch *scratch) return 0; } -static void __sbi_hsm_suspend_non_ret_save(struct sbi_scratch *scratch) +void __sbi_hsm_suspend_non_ret_save(struct sbi_scratch *scratch) { struct sbi_hsm_data *hdata = sbi_scratch_offset_ptr(scratch, hart_data_offset); From 73623a0acac7f62646757cdd5a03b325eba3e0c9 Mon Sep 17 00:00:00 2001 From: Andrew Jones Date: Mon, 27 Feb 2023 11:31:02 +0100 Subject: [PATCH 071/187] lib: sbi: Add system suspend skeleton Add the SUSP extension probe and ecall support, but for now the system suspend function is just a stub. Signed-off-by: Andrew Jones Reviewed-by: Anup Patel --- include/sbi/sbi_ecall_interface.h | 8 ++++++ include/sbi/sbi_system.h | 26 +++++++++++++++++ lib/sbi/Kconfig | 4 +++ lib/sbi/objects.mk | 3 ++ lib/sbi/sbi_ecall_susp.c | 48 +++++++++++++++++++++++++++++++ lib/sbi/sbi_init.c | 4 +++ lib/sbi/sbi_system.c | 26 +++++++++++++++++ 7 files changed, 119 insertions(+) create mode 100644 lib/sbi/sbi_ecall_susp.c diff --git a/include/sbi/sbi_ecall_interface.h b/include/sbi/sbi_ecall_interface.h index 9d6f4743651..4c378c3e7c3 100644 --- a/include/sbi/sbi_ecall_interface.h +++ b/include/sbi/sbi_ecall_interface.h @@ -30,6 +30,7 @@ #define SBI_EXT_SRST 0x53525354 #define SBI_EXT_PMU 0x504D55 #define SBI_EXT_DBCN 0x4442434E +#define SBI_EXT_SUSP 0x53555350 /* SBI function IDs for BASE extension*/ #define SBI_EXT_BASE_GET_SPEC_VERSION 0x0 @@ -236,6 +237,13 @@ enum sbi_pmu_ctr_type { #define SBI_EXT_DBCN_CONSOLE_READ 0x1 #define SBI_EXT_DBCN_CONSOLE_WRITE_BYTE 0x2 +/* SBI function IDs for SUSP extension */ +#define SBI_EXT_SUSP_SUSPEND 0x0 + +#define SBI_SUSP_SLEEP_TYPE_SUSPEND 0x0 +#define SBI_SUSP_SLEEP_TYPE_LAST SBI_SUSP_SLEEP_TYPE_SUSPEND +#define SBI_SUSP_PLATFORM_SLEEP_START 0x80000000 + /* SBI base specification related macros */ #define SBI_SPEC_VERSION_MAJOR_OFFSET 24 #define SBI_SPEC_VERSION_MAJOR_MASK 0x7f diff --git a/include/sbi/sbi_system.h b/include/sbi/sbi_system.h index 84c281383d8..11d3d6fd9a6 100644 --- a/include/sbi/sbi_system.h +++ b/include/sbi/sbi_system.h @@ -43,4 +43,30 @@ bool sbi_system_reset_supported(u32 reset_type, u32 reset_reason); void __noreturn sbi_system_reset(u32 reset_type, u32 reset_reason); +/** System suspend device */ +struct sbi_system_suspend_device { + /** Name of the system suspend device */ + char name[32]; + + /* Check whether sleep type is supported by the device */ + int (*system_suspend_check)(u32 sleep_type); + + /** + * Suspend the system + * + * @sleep_type: The sleep type identifier passed to the SBI call. + * @mmode_resume_addr: + * This is the same as sbi_scratch.warmboot_addr. Some platforms + * may not be able to return from system_suspend(), so they will + * jump directly to this address instead. Platforms which can + * return from system_suspend() may ignore this parameter. + */ + int (*system_suspend)(u32 sleep_type, unsigned long mmode_resume_addr); +}; + +const struct sbi_system_suspend_device *sbi_system_suspend_get_device(void); +void sbi_system_suspend_set_device(struct sbi_system_suspend_device *dev); +bool sbi_system_suspend_supported(u32 sleep_type); +int sbi_system_suspend(u32 sleep_type, ulong resume_addr, ulong opaque); + #endif diff --git a/lib/sbi/Kconfig b/lib/sbi/Kconfig index ef6728bab3e..7eb3273d546 100644 --- a/lib/sbi/Kconfig +++ b/lib/sbi/Kconfig @@ -22,6 +22,10 @@ config SBI_ECALL_SRST bool "System Reset extension" default y +config SBI_ECALL_SUSP + bool "System Suspend extension" + default y + config SBI_ECALL_PMU bool "Performance Monitoring Unit extension" default y diff --git a/lib/sbi/objects.mk b/lib/sbi/objects.mk index 319f38dce70..770238b25fa 100644 --- a/lib/sbi/objects.mk +++ b/lib/sbi/objects.mk @@ -34,6 +34,9 @@ libsbi-objs-$(CONFIG_SBI_ECALL_HSM) += sbi_ecall_hsm.o carray-sbi_ecall_exts-$(CONFIG_SBI_ECALL_SRST) += ecall_srst libsbi-objs-$(CONFIG_SBI_ECALL_SRST) += sbi_ecall_srst.o +carray-sbi_ecall_exts-$(CONFIG_SBI_ECALL_SUSP) += ecall_susp +libsbi-objs-$(CONFIG_SBI_ECALL_SUSP) += sbi_ecall_susp.o + carray-sbi_ecall_exts-$(CONFIG_SBI_ECALL_PMU) += ecall_pmu libsbi-objs-$(CONFIG_SBI_ECALL_PMU) += sbi_ecall_pmu.o diff --git a/lib/sbi/sbi_ecall_susp.c b/lib/sbi/sbi_ecall_susp.c new file mode 100644 index 00000000000..f20126c49a6 --- /dev/null +++ b/lib/sbi/sbi_ecall_susp.c @@ -0,0 +1,48 @@ +// SPDX-License-Identifier: BSD-2-Clause +#include +#include +#include +#include +#include + +static int sbi_ecall_susp_handler(unsigned long extid, unsigned long funcid, + const struct sbi_trap_regs *regs, + unsigned long *out_val, + struct sbi_trap_info *out_trap) +{ + int ret = SBI_ENOTSUPP; + + if (funcid == SBI_EXT_SUSP_SUSPEND) + ret = sbi_system_suspend(regs->a0, regs->a1, regs->a2); + + if (ret >= 0) { + *out_val = ret; + ret = 0; + } + + return ret; +} + +static int sbi_ecall_susp_probe(unsigned long extid, unsigned long *out_val) +{ + u32 type, count = 0; + + /* + * At least one suspend type should be supported by the + * platform for the SBI SUSP extension to be usable. + */ + for (type = 0; type <= SBI_SUSP_SLEEP_TYPE_LAST; type++) { + if (sbi_system_suspend_supported(type)) + count++; + } + + *out_val = count ? 1 : 0; + return 0; +} + +struct sbi_ecall_extension ecall_susp = { + .extid_start = SBI_EXT_SUSP, + .extid_end = SBI_EXT_SUSP, + .handle = sbi_ecall_susp_handler, + .probe = sbi_ecall_susp_probe, +}; diff --git a/lib/sbi/sbi_init.c b/lib/sbi/sbi_init.c index e353c334830..bc60a427935 100644 --- a/lib/sbi/sbi_init.c +++ b/lib/sbi/sbi_init.c @@ -69,6 +69,7 @@ static void sbi_boot_print_general(struct sbi_scratch *scratch) const struct sbi_timer_device *tdev; const struct sbi_console_device *cdev; const struct sbi_system_reset_device *srdev; + const struct sbi_system_suspend_device *susp_dev; const struct sbi_platform *plat = sbi_platform_ptr(scratch); if (scratch->options & SBI_SCRATCH_NO_BOOT_PRINTS) @@ -103,6 +104,9 @@ static void sbi_boot_print_general(struct sbi_scratch *scratch) srdev = sbi_system_reset_get_device(SBI_SRST_RESET_TYPE_SHUTDOWN, 0); sbi_printf("Platform Shutdown Device : %s\n", (srdev) ? srdev->name : "---"); + susp_dev = sbi_system_suspend_get_device(); + sbi_printf("Platform Suspend Device : %s\n", + (susp_dev) ? susp_dev->name : "---"); /* Firmware details */ sbi_printf("Firmware Base : 0x%lx\n", scratch->fw_start); diff --git a/lib/sbi/sbi_system.c b/lib/sbi/sbi_system.c index f37c811d0bf..5c123a6c9d8 100644 --- a/lib/sbi/sbi_system.c +++ b/lib/sbi/sbi_system.c @@ -92,3 +92,29 @@ void __noreturn sbi_system_reset(u32 reset_type, u32 reset_reason) /* If platform specific reset did not work then do sbi_exit() */ sbi_exit(scratch); } + +static const struct sbi_system_suspend_device *suspend_dev = NULL; + +const struct sbi_system_suspend_device *sbi_system_suspend_get_device(void) +{ + return suspend_dev; +} + +void sbi_system_suspend_set_device(struct sbi_system_suspend_device *dev) +{ + if (!dev || suspend_dev) + return; + + suspend_dev = dev; +} + +bool sbi_system_suspend_supported(u32 sleep_type) +{ + return suspend_dev && suspend_dev->system_suspend_check && + suspend_dev->system_suspend_check(sleep_type); +} + +int sbi_system_suspend(u32 sleep_type, ulong resume_addr, ulong opaque) +{ + return 0; +} From c9917b610871e4f9a0142e5c37c2b698177c3291 Mon Sep 17 00:00:00 2001 From: Andrew Jones Date: Mon, 27 Feb 2023 11:31:03 +0100 Subject: [PATCH 072/187] lib: sbi: Add system_suspend_allowed domain property Only privileged domains should be allowed to suspend the entire system. Give the root domain this property by default and allow other domains to be given the property by specifying it in the DT. Signed-off-by: Andrew Jones Reviewed-by: Anup Patel --- docs/domain_support.md | 5 +++++ include/sbi/sbi_domain.h | 2 ++ lib/sbi/sbi_domain.c | 4 ++++ lib/utils/fdt/fdt_domain.c | 7 +++++++ 4 files changed, 18 insertions(+) diff --git a/docs/domain_support.md b/docs/domain_support.md index 2a9ca3d70ea..039f262bfec 100644 --- a/docs/domain_support.md +++ b/docs/domain_support.md @@ -52,6 +52,7 @@ has following details: * **next_mode** - Privilege mode of the next booting stage for this domain. This can be either S-mode or U-mode. * **system_reset_allowed** - Is domain allowed to reset the system? +* **system_suspend_allowed** - Is domain allowed to suspend the system? The memory regions represented by **regions** in **struct sbi_domain** have following additional constraints to align with RISC-V PMP requirements: @@ -91,6 +92,7 @@ following manner: * **next_mode** - Next booting stage mode in coldboot HART scratch space is the next mode for the ROOT domain * **system_reset_allowed** - The ROOT domain is allowed to reset the system +* **system_suspend_allowed** - The ROOT domain is allowed to suspend the system Domain Effects -------------- @@ -195,6 +197,8 @@ The DT properties of a domain instance DT node are as follows: stage mode of coldboot HART** is used as default value. * **system-reset-allowed** (Optional) - A boolean flag representing whether the domain instance is allowed to do system reset. +* **system-suspend-allowed** (Optional) - A boolean flag representing + whether the domain instance is allowed to do system suspend. ### Assigning HART To Domain Instance @@ -260,6 +264,7 @@ be done: next-addr = <0x0 0x80100000>; next-mode = <0x0>; system-reset-allowed; + system-suspend-allowed; }; udomain: untrusted-domain { diff --git a/include/sbi/sbi_domain.h b/include/sbi/sbi_domain.h index ab1a944b474..eaca7f09327 100644 --- a/include/sbi/sbi_domain.h +++ b/include/sbi/sbi_domain.h @@ -120,6 +120,8 @@ struct sbi_domain { unsigned long next_mode; /** Is domain allowed to reset the system */ bool system_reset_allowed; + /** Is domain allowed to suspend the system */ + bool system_suspend_allowed; }; /** The root domain instance */ diff --git a/lib/sbi/sbi_domain.c b/lib/sbi/sbi_domain.c index d2f58a28cbd..4d7b80a3ddd 100644 --- a/lib/sbi/sbi_domain.c +++ b/lib/sbi/sbi_domain.c @@ -38,6 +38,7 @@ struct sbi_domain root = { .possible_harts = &root_hmask, .regions = root_memregs, .system_reset_allowed = true, + .system_suspend_allowed = true, }; bool sbi_domain_is_assigned_hart(const struct sbi_domain *dom, u32 hartid) @@ -467,6 +468,9 @@ void sbi_domain_dump(const struct sbi_domain *dom, const char *suffix) sbi_printf("Domain%d SysReset %s: %s\n", dom->index, suffix, (dom->system_reset_allowed) ? "yes" : "no"); + + sbi_printf("Domain%d SysSuspend %s: %s\n", + dom->index, suffix, (dom->system_suspend_allowed) ? "yes" : "no"); } void sbi_domain_dump_all(const char *suffix) diff --git a/lib/utils/fdt/fdt_domain.c b/lib/utils/fdt/fdt_domain.c index bc30010a888..adcb94b6413 100644 --- a/lib/utils/fdt/fdt_domain.c +++ b/lib/utils/fdt/fdt_domain.c @@ -417,6 +417,13 @@ static int __fdt_parse_domain(void *fdt, int domain_offset, void *opaque) else dom->system_reset_allowed = false; + /* Read "system-suspend-allowed" DT property */ + if (fdt_get_property(fdt, domain_offset, + "system-suspend-allowed", NULL)) + dom->system_suspend_allowed = true; + else + dom->system_suspend_allowed = false; + /* Find /cpus DT node */ cpus_offset = fdt_path_offset(fdt, "/cpus"); if (cpus_offset < 0) From 7c964e279cbca3bad88b2fe35217e44a73862151 Mon Sep 17 00:00:00 2001 From: Andrew Jones Date: Mon, 27 Feb 2023 11:31:04 +0100 Subject: [PATCH 073/187] lib: sbi: Implement system suspend Fill the implementation of the system suspend ecall. A platform implementation of the suspend callbacks is still required for this to do anything. Signed-off-by: Andrew Jones Reviewed-by: Anup Patel --- lib/sbi/sbi_system.c | 57 +++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 56 insertions(+), 1 deletion(-) diff --git a/lib/sbi/sbi_system.c b/lib/sbi/sbi_system.c index 5c123a6c9d8..7fa5ea82b7a 100644 --- a/lib/sbi/sbi_system.c +++ b/lib/sbi/sbi_system.c @@ -116,5 +116,60 @@ bool sbi_system_suspend_supported(u32 sleep_type) int sbi_system_suspend(u32 sleep_type, ulong resume_addr, ulong opaque) { - return 0; + int ret = SBI_ENOTSUPP; + const struct sbi_domain *dom = sbi_domain_thishart_ptr(); + struct sbi_scratch *scratch = sbi_scratch_thishart_ptr(); + void (*jump_warmboot)(void) = (void (*)(void))scratch->warmboot_addr; + unsigned int hartid = current_hartid(); + unsigned long prev_mode; + unsigned long i; + + if (!dom || !dom->system_suspend_allowed) + return SBI_EFAIL; + + if (!suspend_dev || !suspend_dev->system_suspend) + return SBI_EFAIL; + + if (!sbi_system_suspend_supported(sleep_type)) + return SBI_ENOTSUPP; + + prev_mode = (csr_read(CSR_MSTATUS) & MSTATUS_MPP) >> MSTATUS_MPP_SHIFT; + if (prev_mode != PRV_S && prev_mode != PRV_U) + return SBI_EFAIL; + + sbi_hartmask_for_each_hart(i, &dom->assigned_harts) { + if (i == hartid) + continue; + if (__sbi_hsm_hart_get_state(i) != SBI_HSM_STATE_STOPPED) + return SBI_EFAIL; + } + + if (!sbi_domain_check_addr(dom, resume_addr, prev_mode, + SBI_DOMAIN_EXECUTE)) + return SBI_EINVALID_ADDR; + + if (!sbi_hsm_hart_change_state(scratch, SBI_HSM_STATE_STARTED, + SBI_HSM_STATE_SUSPENDED)) + return SBI_EFAIL; + + /* Prepare for resume */ + scratch->next_mode = prev_mode; + scratch->next_addr = resume_addr; + scratch->next_arg1 = opaque; + + __sbi_hsm_suspend_non_ret_save(scratch); + + /* Suspend */ + ret = suspend_dev->system_suspend(sleep_type, scratch->warmboot_addr); + if (ret != SBI_OK) { + if (!sbi_hsm_hart_change_state(scratch, SBI_HSM_STATE_SUSPENDED, + SBI_HSM_STATE_STARTED)) + sbi_hart_hang(); + return ret; + } + + /* Resume */ + jump_warmboot(); + + __builtin_unreachable(); } From 37558dccbedbb571150630a910547a93d7ec8822 Mon Sep 17 00:00:00 2001 From: Andrew Jones Date: Mon, 27 Feb 2023 11:31:05 +0100 Subject: [PATCH 074/187] docs: Correct opensbi-domain property name Replace the commas with dashes to correct the name. Signed-off-by: Andrew Jones Reviewed-by: Anup Patel --- docs/domain_support.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/docs/domain_support.md b/docs/domain_support.md index 039f262bfec..65b61427166 100644 --- a/docs/domain_support.md +++ b/docs/domain_support.md @@ -207,9 +207,9 @@ platform support can provide the HART to domain instance assignment using platform specific callback. The HART to domain instance assignment can be parsed from the device tree -using optional DT property **opensbi,domain** in each CPU DT node. The -value of DT property **opensbi,domain** is the DT phandle of the domain -instance DT node. If **opensbi,domain** DT property is not specified then +using optional DT property **opensbi-domain** in each CPU DT node. The +value of DT property **opensbi-domain** is the DT phandle of the domain +instance DT node. If **opensbi-domain** DT property is not specified then corresponding HART is assigned to **the ROOT domain**. ### Domain Configuration Only Accessible to OpenSBI From 5ccebf0a7ec79d0bbef36d6dcdc2717f25d40767 Mon Sep 17 00:00:00 2001 From: Andrew Jones Date: Mon, 27 Feb 2023 11:31:06 +0100 Subject: [PATCH 075/187] platform: generic: Add system suspend test When the system-suspend-test property is present in the domain config node as shown below, implement system suspend with a simple 5 second delay followed by a WFI. This allows testing system suspend when the low-level firmware doesn't support it. / { chosen { opensbi-domains { compatible = "opensbi,domain,config"; system-suspend-test; }; Signed-off-by: Andrew Jones Reviewed-by: Anup Patel --- docs/domain_support.md | 4 ++++ include/sbi/sbi_system.h | 1 + lib/sbi/sbi_system.c | 31 +++++++++++++++++++++++++++++++ platform/generic/platform.c | 20 +++++++++++++++++++- 4 files changed, 55 insertions(+), 1 deletion(-) diff --git a/docs/domain_support.md b/docs/domain_support.md index 65b61427166..b285d65aec0 100644 --- a/docs/domain_support.md +++ b/docs/domain_support.md @@ -126,6 +126,9 @@ The DT properties of a domain configuration DT node are as follows: * **compatible** (Mandatory) - The compatible string of the domain configuration. This DT property should have value *"opensbi,domain,config"* +* **system-suspend-test** (Optional) - When present, enable a system + suspend test implementation which simply waits five seconds and issues a WFI. + ### Domain Memory Region Node The domain memory region DT node describes details of a memory region and @@ -234,6 +237,7 @@ be done: chosen { opensbi-domains { compatible = "opensbi,domain,config"; + system-suspend-test; tmem: tmem { compatible = "opensbi,domain,memregion"; diff --git a/include/sbi/sbi_system.h b/include/sbi/sbi_system.h index 11d3d6fd9a6..33ff7f1a44a 100644 --- a/include/sbi/sbi_system.h +++ b/include/sbi/sbi_system.h @@ -66,6 +66,7 @@ struct sbi_system_suspend_device { const struct sbi_system_suspend_device *sbi_system_suspend_get_device(void); void sbi_system_suspend_set_device(struct sbi_system_suspend_device *dev); +void sbi_system_suspend_test_enable(void); bool sbi_system_suspend_supported(u32 sleep_type); int sbi_system_suspend(u32 sleep_type, ulong resume_addr, ulong opaque); diff --git a/lib/sbi/sbi_system.c b/lib/sbi/sbi_system.c index 7fa5ea82b7a..6933915a12e 100644 --- a/lib/sbi/sbi_system.c +++ b/lib/sbi/sbi_system.c @@ -17,6 +17,7 @@ #include #include #include +#include static SBI_LIST_HEAD(reset_devices_list); @@ -108,6 +109,36 @@ void sbi_system_suspend_set_device(struct sbi_system_suspend_device *dev) suspend_dev = dev; } +static int sbi_system_suspend_test_check(u32 sleep_type) +{ + return sleep_type == SBI_SUSP_SLEEP_TYPE_SUSPEND; +} + +static int sbi_system_suspend_test_suspend(u32 sleep_type, + unsigned long mmode_resume_addr) +{ + if (sleep_type != SBI_SUSP_SLEEP_TYPE_SUSPEND) + return SBI_EINVAL; + + sbi_timer_mdelay(5000); + + /* Wait for interrupt */ + wfi(); + + return SBI_OK; +} + +static struct sbi_system_suspend_device sbi_system_suspend_test = { + .name = "system-suspend-test", + .system_suspend_check = sbi_system_suspend_test_check, + .system_suspend = sbi_system_suspend_test_suspend, +}; + +void sbi_system_suspend_test_enable(void) +{ + sbi_system_suspend_set_device(&sbi_system_suspend_test); +} + bool sbi_system_suspend_supported(u32 sleep_type) { return suspend_dev && suspend_dev->system_suspend_check && diff --git a/platform/generic/platform.c b/platform/generic/platform.c index 0b90fd7c144..eeefef4c953 100644 --- a/platform/generic/platform.c +++ b/platform/generic/platform.c @@ -13,6 +13,7 @@ #include #include #include +#include #include #include #include @@ -219,7 +220,24 @@ static int generic_extensions_init(struct sbi_hart_features *hfeatures) static int generic_domains_init(void) { - return fdt_domains_populate(fdt_get_address()); + void *fdt = fdt_get_address(); + int offset, ret; + + ret = fdt_domains_populate(fdt); + if (ret < 0) + return ret; + + offset = fdt_path_offset(fdt, "/chosen"); + + if (offset >= 0) { + offset = fdt_node_offset_by_compatible(fdt, offset, + "opensbi,domain,config"); + if (offset >= 0 && + fdt_get_property(fdt, offset, "system-suspend-test", NULL)) + sbi_system_suspend_test_enable(); + } + + return 0; } static u64 generic_tlbr_flush_limit(void) From 908be1b85c8ff0695ea226fbbf0ff24a779cdece Mon Sep 17 00:00:00 2001 From: "minda.chen" Date: Thu, 16 Feb 2023 17:21:26 +0800 Subject: [PATCH 076/187] gpio/starfive: add gpio driver and support gpio reset Add gpio driver and gpio reset function in Starfive JH7110 SOC platform. Signed-off-by: minda.chen Reviewed-by: Anup Patel --- lib/utils/gpio/Kconfig | 3 + lib/utils/gpio/fdt_gpio_starfive.c | 117 +++++++++++++++++++++++++++++ lib/utils/gpio/objects.mk | 3 + platform/generic/configs/defconfig | 1 + 4 files changed, 124 insertions(+) create mode 100644 lib/utils/gpio/fdt_gpio_starfive.c diff --git a/lib/utils/gpio/Kconfig b/lib/utils/gpio/Kconfig index 38a9d75c829..1b338a6fd94 100644 --- a/lib/utils/gpio/Kconfig +++ b/lib/utils/gpio/Kconfig @@ -14,6 +14,9 @@ config FDT_GPIO_SIFIVE bool "SiFive GPIO FDT driver" default n +config FDT_GPIO_STARFIVE + bool "StarFive GPIO FDT driver" + default n endif config GPIO diff --git a/lib/utils/gpio/fdt_gpio_starfive.c b/lib/utils/gpio/fdt_gpio_starfive.c new file mode 100644 index 00000000000..18cca72aa89 --- /dev/null +++ b/lib/utils/gpio/fdt_gpio_starfive.c @@ -0,0 +1,117 @@ +/* + * SPDX-License-Identifier: BSD-2-Clause + * + * Copyright (c) 2022 Starfive + * + * Authors: + * Minda.chen + */ + +#include +#include +#include +#include +#include + +#define STARFIVE_GPIO_CHIP_MAX 2 +#define STARFIVE_GPIO_PINS_DEF 64 +#define STARFIVE_GPIO_OUTVAL 0x40 +#define STARFIVE_GPIO_MASK 0xff +#define STARFIVE_GPIO_REG_SHIFT_MASK 0x3 +#define STARFIVE_GPIO_SHIFT_BITS 0x3 + +struct starfive_gpio_chip { + unsigned long addr; + struct gpio_chip chip; +}; + +static unsigned int starfive_gpio_chip_count; +static struct starfive_gpio_chip starfive_gpio_chip_array[STARFIVE_GPIO_CHIP_MAX]; + +static int starfive_gpio_direction_output(struct gpio_pin *gp, int value) +{ + u32 val; + unsigned long reg_addr; + u32 bit_mask, shift_bits; + struct starfive_gpio_chip *chip = + container_of(gp->chip, struct starfive_gpio_chip, chip); + + /* set out en*/ + reg_addr = chip->addr + gp->offset; + reg_addr &= ~(STARFIVE_GPIO_REG_SHIFT_MASK); + + val = readl((void *)(reg_addr)); + shift_bits = (gp->offset & STARFIVE_GPIO_REG_SHIFT_MASK) + << STARFIVE_GPIO_SHIFT_BITS; + bit_mask = STARFIVE_GPIO_MASK << shift_bits; + + val = readl((void *)reg_addr); + val &= ~bit_mask; + writel(val, (void *)reg_addr); + + return 0; +} + +static void starfive_gpio_set(struct gpio_pin *gp, int value) +{ + u32 val; + unsigned long reg_addr; + u32 bit_mask, shift_bits; + struct starfive_gpio_chip *chip = + container_of(gp->chip, struct starfive_gpio_chip, chip); + + reg_addr = chip->addr + gp->offset; + reg_addr &= ~(STARFIVE_GPIO_REG_SHIFT_MASK); + + shift_bits = (gp->offset & STARFIVE_GPIO_REG_SHIFT_MASK) + << STARFIVE_GPIO_SHIFT_BITS; + bit_mask = STARFIVE_GPIO_MASK << shift_bits; + /* set output value */ + val = readl((void *)(reg_addr + STARFIVE_GPIO_OUTVAL)); + val &= ~bit_mask; + val |= value << shift_bits; + writel(val, (void *)(reg_addr + STARFIVE_GPIO_OUTVAL)); +} + +extern struct fdt_gpio fdt_gpio_starfive; + +static int starfive_gpio_init(void *fdt, int nodeoff, u32 phandle, + const struct fdt_match *match) +{ + int rc; + struct starfive_gpio_chip *chip; + u64 addr; + + if (starfive_gpio_chip_count >= STARFIVE_GPIO_CHIP_MAX) + return SBI_ENOSPC; + chip = &starfive_gpio_chip_array[starfive_gpio_chip_count]; + + rc = fdt_get_node_addr_size(fdt, nodeoff, 0, &addr, NULL); + if (rc) + return rc; + + chip->addr = addr; + chip->chip.driver = &fdt_gpio_starfive; + chip->chip.id = phandle; + chip->chip.ngpio = STARFIVE_GPIO_PINS_DEF; + chip->chip.direction_output = starfive_gpio_direction_output; + chip->chip.set = starfive_gpio_set; + rc = gpio_chip_add(&chip->chip); + if (rc) + return rc; + + starfive_gpio_chip_count++; + return 0; +} + +static const struct fdt_match starfive_gpio_match[] = { + { .compatible = "starfive,jh7110-sys-pinctrl" }, + { .compatible = "starfive,iomux-pinctrl" }, + { }, +}; + +struct fdt_gpio fdt_gpio_starfive = { + .match_table = starfive_gpio_match, + .xlate = fdt_gpio_simple_xlate, + .init = starfive_gpio_init, +}; diff --git a/lib/utils/gpio/objects.mk b/lib/utils/gpio/objects.mk index eedd699d85f..8f4a6a84fb1 100644 --- a/lib/utils/gpio/objects.mk +++ b/lib/utils/gpio/objects.mk @@ -13,4 +13,7 @@ libsbiutils-objs-$(CONFIG_FDT_GPIO) += gpio/fdt_gpio_drivers.o carray-fdt_gpio_drivers-$(CONFIG_FDT_GPIO_SIFIVE) += fdt_gpio_sifive libsbiutils-objs-$(CONFIG_FDT_GPIO_SIFIVE) += gpio/fdt_gpio_sifive.o +carray-fdt_gpio_drivers-$(CONFIG_FDT_GPIO_STARFIVE) += fdt_gpio_starfive +libsbiutils-objs-$(CONFIG_FDT_GPIO_STARFIVE) += gpio/fdt_gpio_starfive.o + libsbiutils-objs-$(CONFIG_GPIO) += gpio/gpio.o diff --git a/platform/generic/configs/defconfig b/platform/generic/configs/defconfig index 4b0842e03ed..2ad953d3ab0 100644 --- a/platform/generic/configs/defconfig +++ b/platform/generic/configs/defconfig @@ -6,6 +6,7 @@ CONFIG_PLATFORM_SIFIVE_FU740=y CONFIG_PLATFORM_STARFIVE_JH7110=y CONFIG_FDT_GPIO=y CONFIG_FDT_GPIO_SIFIVE=y +CONFIG_FDT_GPIO_STARFIVE=y CONFIG_FDT_I2C=y CONFIG_FDT_I2C_SIFIVE=y CONFIG_FDT_IPI=y From 4b28afc98bbe406e3ad6f4a97d0fe96a882e83a1 Mon Sep 17 00:00:00 2001 From: Bin Meng Date: Mon, 27 Feb 2023 10:35:06 +0800 Subject: [PATCH 077/187] make: Add a command line option for debugging OpenSBI Add a new make command line option "make DEBUG=1" to prevent compiler optimizations using -O2. Signed-off-by: Bin Meng Reviewed-by: Xiang W Reviewed-by: Anup Patel --- Makefile | 7 ++++++- README.md | 13 +++++++++++++ 2 files changed, 19 insertions(+), 1 deletion(-) diff --git a/Makefile b/Makefile index b20404f94aa..a26a39baf12 100644 --- a/Makefile +++ b/Makefile @@ -331,7 +331,12 @@ GENFLAGS += $(libsbiutils-genflags-y) GENFLAGS += $(platform-genflags-y) GENFLAGS += $(firmware-genflags-y) -CFLAGS = -g -Wall -Werror -ffreestanding -nostdlib -fno-stack-protector -fno-strict-aliasing -O2 +CFLAGS = -g -Wall -Werror -ffreestanding -nostdlib -fno-stack-protector -fno-strict-aliasing +ifneq ($(DEBUG),) +CFLAGS += -O0 +else +CFLAGS += -O2 +endif CFLAGS += -fno-omit-frame-pointer -fno-optimize-sibling-calls -mstrict-align # enable -m(no-)save-restore option by CC_SUPPORT_SAVE_RESTORE ifeq ($(CC_SUPPORT_SAVE_RESTORE),y) diff --git a/README.md b/README.md index 895bbf27a37..a6bcb0c1c3a 100644 --- a/README.md +++ b/README.md @@ -298,6 +298,19 @@ NOTE: Using `BUILD_INFO=y` without specifying SOURCE_DATE_EPOCH will violate purpose, and should NOT be used in a product which follows "reproducible builds". +Building with optimization off for debugging +-------------------------------------------- + +When debugging OpenSBI, we may want to turn off the compiler optimization and +make debugging produce the expected results for a better debugging experience. +To build with optimization off we can just simply add `DEBUG=1`, like: +``` +make DEBUG=1 +``` + +This definition is ONLY for development and debug purpose, and should NOT be +used in a product build. + Contributing to OpenSBI ----------------------- From e9d08bd99cc702fcec1c5b59b593781da668e2bc Mon Sep 17 00:00:00 2001 From: Minda Chen Date: Thu, 9 Mar 2023 14:19:58 +0800 Subject: [PATCH 078/187] lib: utils/i2c: Add minimal StarFive jh7110 I2C driver Starfive JH7110 I2C IP is synopsys designware. Minimum StarFIve I2C driver to read/send bytes over I2C bus. This allows querying information and perform operation of onboard PMIC, as well as power-off and reset. Signed-off-by: Minda Chen Reviewed-by: Anup Patel --- include/sbi_utils/i2c/dw_i2c.h | 21 ++++ lib/utils/i2c/Kconfig | 8 ++ lib/utils/i2c/dw_i2c.c | 190 +++++++++++++++++++++++++++++++++ lib/utils/i2c/fdt_i2c_dw.c | 62 +++++++++++ lib/utils/i2c/objects.mk | 5 + 5 files changed, 286 insertions(+) create mode 100644 include/sbi_utils/i2c/dw_i2c.h create mode 100644 lib/utils/i2c/dw_i2c.c create mode 100644 lib/utils/i2c/fdt_i2c_dw.c diff --git a/include/sbi_utils/i2c/dw_i2c.h b/include/sbi_utils/i2c/dw_i2c.h new file mode 100644 index 00000000000..88703e057ff --- /dev/null +++ b/include/sbi_utils/i2c/dw_i2c.h @@ -0,0 +1,21 @@ +/* + * SPDX-License-Identifier: BSD-2-Clause + * + * Copyright (c) 2022 StarFive Technology Co., Ltd. + * + * Author: Minda Chen + */ + +#ifndef __DW_I2C_H__ +#define __DW_I2C_H__ + +#include + +int dw_i2c_init(struct i2c_adapter *, int nodeoff); + +struct dw_i2c_adapter { + unsigned long addr; + struct i2c_adapter adapter; +}; + +#endif diff --git a/lib/utils/i2c/Kconfig b/lib/utils/i2c/Kconfig index 46a3454c034..7fa32fcf967 100644 --- a/lib/utils/i2c/Kconfig +++ b/lib/utils/i2c/Kconfig @@ -14,8 +14,16 @@ config FDT_I2C_SIFIVE bool "SiFive I2C FDT driver" default n +config FDT_I2C_DW + bool "Synopsys Designware I2C FDT driver" + select I2C_DW + default n endif +config I2C_DW + bool "Synopsys Designware I2C support" + default n + config I2C bool "I2C support" default n diff --git a/lib/utils/i2c/dw_i2c.c b/lib/utils/i2c/dw_i2c.c new file mode 100644 index 00000000000..e2ffc71259a --- /dev/null +++ b/lib/utils/i2c/dw_i2c.c @@ -0,0 +1,190 @@ +/* + * SPDX-License-Identifier: BSD-2-Clause + * + * Copyright (c) 2022 starfivetech.com + * + * Authors: + * Minda Chen + */ + +#include +#include +#include +#include +#include +#include +#include + +#define DW_IC_CON 0x00 +#define DW_IC_TAR 0x04 +#define DW_IC_SAR 0x08 +#define DW_IC_DATA_CMD 0x10 +#define DW_IC_SS_SCL_HCNT 0x14 +#define DW_IC_SS_SCL_LCNT 0x18 +#define DW_IC_FS_SCL_HCNT 0x1c +#define DW_IC_FS_SCL_LCNT 0x20 +#define DW_IC_HS_SCL_HCNT 0x24 +#define DW_IC_HS_SCL_LCNT 0x28 +#define DW_IC_INTR_STAT 0x2c +#define DW_IC_INTR_MASK 0x30 +#define DW_IC_RAW_INTR_STAT 0x34 +#define DW_IC_RX_TL 0x38 +#define DW_IC_TX_TL 0x3c +#define DW_IC_CLR_INTR 0x40 +#define DW_IC_CLR_RX_UNDER 0x44 +#define DW_IC_CLR_RX_OVER 0x48 +#define DW_IC_CLR_TX_OVER 0x4c +#define DW_IC_CLR_RD_REQ 0x50 +#define DW_IC_CLR_TX_ABRT 0x54 +#define DW_IC_CLR_RX_DONE 0x58 +#define DW_IC_CLR_ACTIVITY 0x5c +#define DW_IC_CLR_STOP_DET 0x60 +#define DW_IC_CLR_START_DET 0x64 +#define DW_IC_CLR_GEN_CALL 0x68 +#define DW_IC_ENABLE 0x6c +#define DW_IC_STATUS 0x70 +#define DW_IC_TXFLR 0x74 +#define DW_IC_RXFLR 0x78 +#define DW_IC_SDA_HOLD 0x7c +#define DW_IC_TX_ABRT_SOURCE 0x80 +#define DW_IC_ENABLE_STATUS 0x9c +#define DW_IC_CLR_RESTART_DET 0xa8 +#define DW_IC_COMP_PARAM_1 0xf4 +#define DW_IC_COMP_VERSION 0xf8 + +#define DW_I2C_STATUS_TXFIFO_EMPTY BIT(2) +#define DW_I2C_STATUS_RXFIFO_NOT_EMPTY BIT(3) + +#define IC_DATA_CMD_READ BIT(8) +#define IC_DATA_CMD_STOP BIT(9) +#define IC_DATA_CMD_RESTART BIT(10) +#define IC_INT_STATUS_STOPDET BIT(9) + +static inline void dw_i2c_setreg(struct dw_i2c_adapter *adap, + u8 reg, u32 value) +{ + writel(value, (void *)adap->addr + reg); +} + +static inline u32 dw_i2c_getreg(struct dw_i2c_adapter *adap, + u32 reg) +{ + return readl((void *)adap->addr + reg); +} + +static int dw_i2c_adapter_poll(struct dw_i2c_adapter *adap, + u32 mask, u32 addr, + bool inverted) +{ + unsigned int timeout = 10; /* msec */ + int count = 0; + u32 val; + + do { + val = dw_i2c_getreg(adap, addr); + if (inverted) { + if (!(val & mask)) + return 0; + } else { + if (val & mask) + return 0; + } + sbi_timer_udelay(2); + count += 1; + if (count == (timeout * 1000)) + return SBI_ETIMEDOUT; + } while (1); +} + +#define dw_i2c_adapter_poll_rxrdy(adap) \ + dw_i2c_adapter_poll(adap, DW_I2C_STATUS_RXFIFO_NOT_EMPTY, DW_IC_STATUS, 0) +#define dw_i2c_adapter_poll_txfifo_ready(adap) \ + dw_i2c_adapter_poll(adap, DW_I2C_STATUS_TXFIFO_EMPTY, DW_IC_STATUS, 0) + +static int dw_i2c_write_addr(struct dw_i2c_adapter *adap, u8 addr) +{ + dw_i2c_setreg(adap, DW_IC_ENABLE, 0); + dw_i2c_setreg(adap, DW_IC_TAR, addr); + dw_i2c_setreg(adap, DW_IC_ENABLE, 1); + + return 0; +} + +static int dw_i2c_adapter_read(struct i2c_adapter *ia, u8 addr, + u8 reg, u8 *buffer, int len) +{ + struct dw_i2c_adapter *adap = + container_of(ia, struct dw_i2c_adapter, adapter); + int rc; + + dw_i2c_write_addr(adap, addr); + + rc = dw_i2c_adapter_poll_txfifo_ready(adap); + if (rc) + return rc; + + /* set register address */ + dw_i2c_setreg(adap, DW_IC_DATA_CMD, reg); + + /* set value */ + while (len) { + if (len == 1) + dw_i2c_setreg(adap, DW_IC_DATA_CMD, + IC_DATA_CMD_READ | IC_DATA_CMD_STOP); + else + dw_i2c_setreg(adap, DW_IC_DATA_CMD, IC_DATA_CMD_READ); + + rc = dw_i2c_adapter_poll_rxrdy(adap); + if (rc) + return rc; + + *buffer = dw_i2c_getreg(adap, DW_IC_DATA_CMD) & 0xff; + buffer++; + len--; + } + + return 0; +} + +static int dw_i2c_adapter_write(struct i2c_adapter *ia, u8 addr, + u8 reg, u8 *buffer, int len) +{ + struct dw_i2c_adapter *adap = + container_of(ia, struct dw_i2c_adapter, adapter); + int rc; + + dw_i2c_write_addr(adap, addr); + + rc = dw_i2c_adapter_poll_txfifo_ready(adap); + if (rc) + return rc; + + /* set register address */ + dw_i2c_setreg(adap, DW_IC_DATA_CMD, reg); + + while (len) { + rc = dw_i2c_adapter_poll_txfifo_ready(adap); + if (rc) + return rc; + + if (len == 1) + dw_i2c_setreg(adap, DW_IC_DATA_CMD, *buffer | IC_DATA_CMD_STOP); + else + dw_i2c_setreg(adap, DW_IC_DATA_CMD, *buffer); + + buffer++; + len--; + } + rc = dw_i2c_adapter_poll_txfifo_ready(adap); + + return rc; +} + +int dw_i2c_init(struct i2c_adapter *adapter, int nodeoff) +{ + adapter->id = nodeoff; + adapter->write = dw_i2c_adapter_write; + adapter->read = dw_i2c_adapter_read; + + return i2c_adapter_add(adapter); +} diff --git a/lib/utils/i2c/fdt_i2c_dw.c b/lib/utils/i2c/fdt_i2c_dw.c new file mode 100644 index 00000000000..71062f4b403 --- /dev/null +++ b/lib/utils/i2c/fdt_i2c_dw.c @@ -0,0 +1,62 @@ +/* + * SPDX-License-Identifier: BSD-2-Clause + * + * Copyright (c) 2022 starfivetech.com + * + * Authors: + * Minda Chen + */ + +#include +#include +#include +#include +#include +#include + +#define FDT_DW_I2C_ADAPTER_MAX 7 + +static unsigned int fdt_dw_i2c_adapter_count; +static struct dw_i2c_adapter + fdt_dw_i2c_adapter_array[FDT_DW_I2C_ADAPTER_MAX]; + +extern struct fdt_i2c_adapter fdt_i2c_adapter_dw; + +static int fdt_dw_i2c_init(void *fdt, int nodeoff, + const struct fdt_match *match) +{ + int rc; + struct dw_i2c_adapter *adapter; + u64 addr; + + if (fdt_dw_i2c_adapter_count >= FDT_DW_I2C_ADAPTER_MAX) + return SBI_ENOSPC; + + adapter = &fdt_dw_i2c_adapter_array[fdt_dw_i2c_adapter_count]; + + rc = fdt_get_node_addr_size(fdt, nodeoff, 0, &addr, NULL); + if (rc) + return rc; + + adapter->addr = addr; + adapter->adapter.driver = &fdt_i2c_adapter_dw; + + rc = dw_i2c_init(&adapter->adapter, nodeoff); + if (rc) + return rc; + + fdt_dw_i2c_adapter_count++; + + return 0; +} + +static const struct fdt_match fdt_dw_i2c_match[] = { + { .compatible = "snps,designware-i2c" }, + { .compatible = "starfive,jh7110-i2c" }, + { }, +}; + +struct fdt_i2c_adapter fdt_i2c_adapter_dw = { + .match_table = fdt_dw_i2c_match, + .init = fdt_dw_i2c_init, +}; diff --git a/lib/utils/i2c/objects.mk b/lib/utils/i2c/objects.mk index a0fbbb5de32..5f7a79ff3d3 100644 --- a/lib/utils/i2c/objects.mk +++ b/lib/utils/i2c/objects.mk @@ -14,3 +14,8 @@ libsbiutils-objs-$(CONFIG_FDT_I2C) += i2c/fdt_i2c_adapter_drivers.o carray-fdt_i2c_adapter_drivers-$(CONFIG_FDT_I2C_SIFIVE) += fdt_i2c_adapter_sifive libsbiutils-objs-$(CONFIG_FDT_I2C_SIFIVE) += i2c/fdt_i2c_sifive.o + +carray-fdt_i2c_adapter_drivers-$(CONFIG_FDT_I2C_DW) += fdt_i2c_adapter_dw +libsbiutils-objs-$(CONFIG_FDT_I2C_DW) += i2c/fdt_i2c_dw.o + +libsbiutils-objs-$(CONFIG_I2C_DW) += i2c/dw_i2c.o From 568ea49490d935e01b9a41ef8bb5daf9cb0ef201 Mon Sep 17 00:00:00 2001 From: Minda Chen Date: Thu, 9 Mar 2023 14:19:59 +0800 Subject: [PATCH 079/187] platform: starfive: add PMIC power ops in JH7110 visionfive2 board add reboot and poweroff support. The whole reboot and shutdown pm op includes shutdown jh7110 pmu device power domain and access on board pmic register through I2C. Signed-off-by: Minda Chen Reviewed-by: Anup Patel --- platform/generic/configs/defconfig | 1 + platform/generic/starfive/jh7110.c | 272 +++++++++++++++++++++++++++++ 2 files changed, 273 insertions(+) diff --git a/platform/generic/configs/defconfig b/platform/generic/configs/defconfig index 2ad953d3ab0..ee0df38a22e 100644 --- a/platform/generic/configs/defconfig +++ b/platform/generic/configs/defconfig @@ -9,6 +9,7 @@ CONFIG_FDT_GPIO_SIFIVE=y CONFIG_FDT_GPIO_STARFIVE=y CONFIG_FDT_I2C=y CONFIG_FDT_I2C_SIFIVE=y +CONFIG_FDT_I2C_DW=y CONFIG_FDT_IPI=y CONFIG_FDT_IPI_MSWI=y CONFIG_FDT_IPI_PLICSW=y diff --git a/platform/generic/starfive/jh7110.c b/platform/generic/starfive/jh7110.c index c665658ac9b..dcd6306be5f 100644 --- a/platform/generic/starfive/jh7110.c +++ b/platform/generic/starfive/jh7110.c @@ -5,14 +5,285 @@ * * Authors: * Wei Liang Lim + * Minda Chen */ #include #include +#include +#include +#include +#include +#include +#include #include +#include +#include +struct pmic { + struct i2c_adapter *adapter; + u32 dev_addr; + const char *compatible; +}; + +struct jh7110 { + u64 pmu_reg_base; + u64 clk_reg_base; + u32 i2c_index; +}; + +static struct pmic pmic_inst; +static struct jh7110 jh7110_inst; static u32 selected_hartid = -1; +/* PMU register define */ +#define HW_EVENT_TURN_ON_MASK 0x04 +#define HW_EVENT_TURN_OFF_MASK 0x08 +#define SW_TURN_ON_POWER_MODE 0x0C +#define SW_TURN_OFF_POWER_MODE 0x10 +#define SW_ENCOURAGE 0x44 +#define PMU_INT_MASK 0x48 +#define PCH_BYPASS 0x4C +#define PCH_PSTATE 0x50 +#define PCH_TIMEOUT 0x54 +#define LP_TIMEOUT 0x58 +#define HW_TURN_ON_MODE 0x5C +#define CURR_POWER_MODE 0x80 +#define PMU_EVENT_STATUS 0x88 +#define PMU_INT_STATUS 0x8C + +/* sw encourage cfg */ +#define SW_MODE_ENCOURAGE_EN_LO 0x05 +#define SW_MODE_ENCOURAGE_EN_HI 0x50 +#define SW_MODE_ENCOURAGE_DIS_LO 0x0A +#define SW_MODE_ENCOURAGE_DIS_HI 0xA0 +#define SW_MODE_ENCOURAGE_ON 0xFF + +#define DEVICE_PD_MASK 0xfc +#define SYSTOP_CPU_PD_MASK 0x3 + +#define TIMEOUT_COUNT 100000 +#define AXP15060_POWER_REG 0x32 +#define AXP15060_POWER_OFF_BIT BIT(7) +#define AXP15060_RESET_BIT BIT(6) + +#define I2C_APB_CLK_OFFSET 0x228 +#define I2C_APB_CLK_ENABLE_BIT BIT(31) + +static int pm_system_reset_check(u32 type, u32 reason) +{ + switch (type) { + case SBI_SRST_RESET_TYPE_SHUTDOWN: + return 1; + case SBI_SRST_RESET_TYPE_COLD_REBOOT: + return 255; + default: + break; + } + + return 0; +} + +static int wait_pmu_pd_state(u32 mask) +{ + int count = 0; + unsigned long addr = jh7110_inst.pmu_reg_base; + u32 val; + + do { + val = readl((void *)(addr + CURR_POWER_MODE)); + if (val == mask) + return 0; + + sbi_timer_udelay(2); + count += 1; + if (count == TIMEOUT_COUNT) + return SBI_ETIMEDOUT; + } while (1); +} + +static int shutdown_device_power_domain(void) +{ + unsigned long addr = jh7110_inst.pmu_reg_base; + u32 curr_mode; + int ret = 0; + + curr_mode = readl((void *)(addr + CURR_POWER_MODE)); + curr_mode &= DEVICE_PD_MASK; + + if (curr_mode) { + writel(curr_mode, (void *)(addr + SW_TURN_OFF_POWER_MODE)); + writel(SW_MODE_ENCOURAGE_ON, (void *)(addr + SW_ENCOURAGE)); + writel(SW_MODE_ENCOURAGE_DIS_LO, (void *)(addr + SW_ENCOURAGE)); + writel(SW_MODE_ENCOURAGE_DIS_HI, (void *)(addr + SW_ENCOURAGE)); + ret = wait_pmu_pd_state(SYSTOP_CPU_PD_MASK); + if (ret) + sbi_printf("%s shutdown device power %x error\n", + __func__, curr_mode); + } + return ret; +} + +static void pmic_ops(struct pmic *pmic, int type) +{ + int ret = 0; + u8 val; + + ret = shutdown_device_power_domain(); + + if (ret) + return; + + if (!sbi_strcmp("stf,axp15060-regulator", pmic->compatible)) { + ret = i2c_adapter_reg_read(pmic->adapter, pmic->dev_addr, + AXP15060_POWER_REG, &val); + + if (ret) { + sbi_printf("%s: cannot read pmic power register\n", + __func__); + return; + } + + val |= AXP15060_POWER_OFF_BIT; + if (type == SBI_SRST_RESET_TYPE_SHUTDOWN) + val |= AXP15060_POWER_OFF_BIT; + else + val |= AXP15060_RESET_BIT; + + ret = i2c_adapter_reg_write(pmic->adapter, pmic->dev_addr, + AXP15060_POWER_REG, val); + if (ret) + sbi_printf("%s: cannot write pmic power register\n", + __func__); + } +} + +static void pmic_i2c_clk_enable(void) +{ + unsigned long clock_base; + unsigned int val; + + clock_base = jh7110_inst.clk_reg_base + + I2C_APB_CLK_OFFSET + + (jh7110_inst.i2c_index << 2); + + val = readl((void *)clock_base); + + if (!val) + writel(I2C_APB_CLK_ENABLE_BIT, (void *)clock_base); +} + +static void pm_system_reset(u32 type, u32 reason) +{ + if (pmic_inst.adapter) { + switch (type) { + case SBI_SRST_RESET_TYPE_SHUTDOWN: + case SBI_SRST_RESET_TYPE_COLD_REBOOT: + /* i2c clk may be disabled by kernel driver */ + pmic_i2c_clk_enable(); + pmic_ops(&pmic_inst, type); + break; + default: + break; + } + } + + sbi_hart_hang(); +} + +static struct sbi_system_reset_device pm_reset = { + .name = "pm-reset", + .system_reset_check = pm_system_reset_check, + .system_reset = pm_system_reset +}; + +static int pm_reset_init(void *fdt, int nodeoff, + const struct fdt_match *match) +{ + int rc; + int i2c_bus; + struct i2c_adapter *adapter; + u64 addr; + + rc = fdt_get_node_addr_size(fdt, nodeoff, 0, &addr, NULL); + if (rc) + return rc; + + pmic_inst.dev_addr = addr; + pmic_inst.compatible = match->compatible; + + i2c_bus = fdt_parent_offset(fdt, nodeoff); + if (i2c_bus < 0) + return i2c_bus; + + /* i2c adapter get */ + rc = fdt_i2c_adapter_get(fdt, i2c_bus, &adapter); + if (rc) + return rc; + + pmic_inst.adapter = adapter; + + sbi_system_reset_add_device(&pm_reset); + + return 0; +} + +static const struct fdt_match pm_reset_match[] = { + { .compatible = "stf,axp15060-regulator", .data = (void *)true }, + { }, +}; + +static struct fdt_reset fdt_reset_pmic = { + .match_table = pm_reset_match, + .init = pm_reset_init, +}; + +static int starfive_jh7110_inst_init(void *fdt) +{ + int noff, rc = 0; + const char *name; + u64 addr; + + noff = fdt_node_offset_by_compatible(fdt, -1, "starfive,jh7110-pmu"); + if (-1 < noff) { + rc = fdt_get_node_addr_size(fdt, noff, 0, &addr, NULL); + if (rc) + goto err; + jh7110_inst.pmu_reg_base = addr; + } + + noff = fdt_node_offset_by_compatible(fdt, -1, "starfive,jh7110-clkgen"); + if (-1 < noff) { + rc = fdt_get_node_addr_size(fdt, noff, 0, &addr, NULL); + if (rc) + goto err; + jh7110_inst.clk_reg_base = addr; + } + + if (pmic_inst.adapter) { + name = fdt_get_name(fdt, pmic_inst.adapter->id, NULL); + if (!sbi_strncmp(name, "i2c", 3)) + jh7110_inst.i2c_index = name[3] - '0'; + else + rc = SBI_EINVAL; + } +err: + return rc; +} + +static int starfive_jh7110_final_init(bool cold_boot, + const struct fdt_match *match) +{ + void *fdt = fdt_get_address(); + + if (cold_boot) { + fdt_reset_driver_init(fdt, &fdt_reset_pmic); + return starfive_jh7110_inst_init(fdt); + } + + return 0; +} + static bool starfive_jh7110_cold_boot_allowed(u32 hartid, const struct fdt_match *match) { @@ -44,4 +315,5 @@ const struct platform_override starfive_jh7110 = { .match_table = starfive_jh7110_match, .cold_boot_allowed = starfive_jh7110_cold_boot_allowed, .fw_init = starfive_jh7110_fw_init, + .final_init = starfive_jh7110_final_init, }; From 506144f398b7911a2395d127fb6a64082a4a79cc Mon Sep 17 00:00:00 2001 From: Mayuresh Chitale Date: Wed, 1 Mar 2023 20:08:00 +0530 Subject: [PATCH 080/187] lib: serial: Cadence: Enable compatibility for cdns,uart-r1p8 The Cadence driver does not use the RX byte status feature and hence can be advertised to be compatible with cdns,uart-r1p8 as well. Signed-off-by: Mayuresh Chitale Reviewed-by: Anup Patel --- lib/utils/serial/fdt_serial_cadence.c | 1 + 1 file changed, 1 insertion(+) diff --git a/lib/utils/serial/fdt_serial_cadence.c b/lib/utils/serial/fdt_serial_cadence.c index 946e5336547..ae59e4c1e9c 100644 --- a/lib/utils/serial/fdt_serial_cadence.c +++ b/lib/utils/serial/fdt_serial_cadence.c @@ -24,6 +24,7 @@ static int serial_cadence_init(void *fdt, int nodeoff, } static const struct fdt_match serial_cadence_match[] = { + { .compatible = "cdns,uart-r1p8", }, { .compatible = "cdns,uart-r1p12" }, { .compatible = "starfive,jh8100-uart" }, { }, From 1fe8dc995566d869836d3caf37e427c28536f453 Mon Sep 17 00:00:00 2001 From: Mayuresh Chitale Date: Thu, 9 Mar 2023 18:43:51 +0530 Subject: [PATCH 081/187] lib: sbi_pmu: add callback for counter width This patch adds a callback to fetch the number of bits implemented for a custom firmware counter. If the callback fails or is not implemented then width defaults to 63. Signed-off-by: Mayuresh Chitale Reviewed-by: Atish Patra Reviewed-by: Anup Patel --- include/sbi/sbi_pmu.h | 5 +++++ lib/sbi/sbi_pmu.c | 6 ++++++ 2 files changed, 11 insertions(+) diff --git a/include/sbi/sbi_pmu.h b/include/sbi/sbi_pmu.h index c36524393bc..b3b75c1bad0 100644 --- a/include/sbi/sbi_pmu.h +++ b/include/sbi/sbi_pmu.h @@ -41,6 +41,11 @@ struct sbi_pmu_device { bool (*fw_counter_match_code)(uint32_t counter_index, uint32_t event_idx_code); + /** + * Fetch the max width of this counter in number of bits. + */ + int (*fw_counter_width)(void); + /** * Read value of custom firmware counter * Note: 0 <= counter_index < SBI_PMU_FW_CTR_MAX diff --git a/lib/sbi/sbi_pmu.c b/lib/sbi/sbi_pmu.c index 154dbdac549..a99c04506f3 100644 --- a/lib/sbi/sbi_pmu.c +++ b/lib/sbi/sbi_pmu.c @@ -761,6 +761,7 @@ unsigned long sbi_pmu_num_ctr(void) int sbi_pmu_ctr_get_info(uint32_t cidx, unsigned long *ctr_info) { + int width; union sbi_pmu_ctr_info cinfo = {0}; struct sbi_scratch *scratch = sbi_scratch_thishart_ptr(); @@ -782,6 +783,11 @@ int sbi_pmu_ctr_get_info(uint32_t cidx, unsigned long *ctr_info) cinfo.type = SBI_PMU_CTR_TYPE_FW; /* Firmware counters are always 64 bits wide */ cinfo.width = 63; + if (pmu_dev && pmu_dev->fw_counter_width) { + width = pmu_dev->fw_counter_width(); + if (width) + cinfo.width = width - 1; + } } *ctr_info = cinfo.value; From 51951d9e9af86c885cf5564bba7dd83a9a59a3b3 Mon Sep 17 00:00:00 2001 From: Mayuresh Chitale Date: Thu, 9 Mar 2023 18:43:52 +0530 Subject: [PATCH 082/187] lib: sbi_pmu: Implement sbi_pmu_counter_fw_read_hi To support 64 bit firmware counters on RV32 systems, we implement sbi_pmu_counter_fw_read_hi() which returns the upper 32 bits of the firmware counter value. On RV64 (or higher) systems, this function will always return zero. Signed-off-by: Mayuresh Chitale Reviewed-by: Atish Patra Reviewed-by: Anup Patel --- include/sbi/sbi_ecall_interface.h | 1 + lib/sbi/sbi_ecall_pmu.c | 8 ++++++++ 2 files changed, 9 insertions(+) diff --git a/include/sbi/sbi_ecall_interface.h b/include/sbi/sbi_ecall_interface.h index 4c378c3e7c3..d4482129f89 100644 --- a/include/sbi/sbi_ecall_interface.h +++ b/include/sbi/sbi_ecall_interface.h @@ -101,6 +101,7 @@ #define SBI_EXT_PMU_COUNTER_START 0x3 #define SBI_EXT_PMU_COUNTER_STOP 0x4 #define SBI_EXT_PMU_COUNTER_FW_READ 0x5 +#define SBI_EXT_PMU_COUNTER_FW_READ_HI 0x6 /** General pmu event codes specified in SBI PMU extension */ enum sbi_pmu_hw_generic_events_t { diff --git a/lib/sbi/sbi_ecall_pmu.c b/lib/sbi/sbi_ecall_pmu.c index 826c8a89bf0..8f91f9cec01 100644 --- a/lib/sbi/sbi_ecall_pmu.c +++ b/lib/sbi/sbi_ecall_pmu.c @@ -54,6 +54,14 @@ static int sbi_ecall_pmu_handler(unsigned long extid, unsigned long funcid, ret = sbi_pmu_ctr_fw_read(regs->a0, &temp); *out_val = temp; break; + case SBI_EXT_PMU_COUNTER_FW_READ_HI: +#if __riscv_xlen == 32 + ret = sbi_pmu_ctr_fw_read(regs->a0, &temp); + *out_val = temp >> 32; +#else + *out_val = 0; +#endif + break; case SBI_EXT_PMU_COUNTER_START: #if __riscv_xlen == 32 From 60c358e6774847629cd608a8841c4e7752b4949a Mon Sep 17 00:00:00 2001 From: Mayuresh Chitale Date: Thu, 9 Mar 2023 18:43:53 +0530 Subject: [PATCH 083/187] lib: sbi_pmu: Reserve space for implementation specific firmware events We reserve space for SBI implementation specific custom firmware events which can be used by M-mode firmwares and HS-mode hypervisors for their own use. This reserved space is intentionally large to ensure that SBI implementation has enough space to accommodate platform specific firmware events as well. Signed-off-by: Mayuresh Chitale Reviewed-by: Atish Patra Reviewed-by: Anup Patel --- include/sbi/sbi_ecall_interface.h | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/include/sbi/sbi_ecall_interface.h b/include/sbi/sbi_ecall_interface.h index d4482129f89..459735807f1 100644 --- a/include/sbi/sbi_ecall_interface.h +++ b/include/sbi/sbi_ecall_interface.h @@ -185,6 +185,17 @@ enum sbi_pmu_fw_event_code_id { SBI_PMU_FW_HFENCE_VVMA_ASID_SENT = 20, SBI_PMU_FW_HFENCE_VVMA_ASID_RCVD = 21, SBI_PMU_FW_MAX, + /* + * Event codes 22 to 255 are reserved for future use. + * Event codes 256 to 65534 are reserved for SBI implementation + * specific custom firmware events. + */ + SBI_PMU_FW_RESERVED_MAX = 0xFFFE, + /* + * Event code 0xFFFF is used for platform specific firmware + * events where the event data contains any event specific information. + */ + SBI_PMU_FW_PLATFORM = 0xFFFF, }; /** SBI PMU event idx type */ From 548e4b4b28b96aa771c2f49a5b255ba6cc26777f Mon Sep 17 00:00:00 2001 From: Mayuresh Chitale Date: Thu, 9 Mar 2023 18:43:54 +0530 Subject: [PATCH 084/187] lib: sbi_pmu: Rename fw_counter_value Rename and reuse fw_counter_value array to save both the counter values for the SBI firmware events and event data for the SBI platform specific firmware events. Signed-off-by: Mayuresh Chitale Reviewed-by: Anup Patel Reviewed-by: Andrew Jones --- lib/sbi/sbi_pmu.c | 22 +++++++++++++--------- 1 file changed, 13 insertions(+), 9 deletions(-) diff --git a/lib/sbi/sbi_pmu.c b/lib/sbi/sbi_pmu.c index a99c04506f3..1a3c44d182e 100644 --- a/lib/sbi/sbi_pmu.c +++ b/lib/sbi/sbi_pmu.c @@ -65,8 +65,12 @@ static uint32_t active_events[SBI_HARTMASK_MAX_BITS][SBI_PMU_HW_CTR_MAX + SBI_PM #endif static unsigned long fw_counters_started[SBI_HARTMASK_MAX_BITS]; -/* Values of firmwares counters on each HART */ -static uint64_t fw_counters_value[SBI_HARTMASK_MAX_BITS][SBI_PMU_FW_CTR_MAX] = {0}; +/* + * Counter values for SBI firmware events and event codes for platform + * firmware events. Both are mutually exclusive and hence can optimally share + * the same memory. + */ +static uint64_t fw_counters_data[SBI_HARTMASK_MAX_BITS][SBI_PMU_FW_CTR_MAX] = {0}; /* Maximum number of hardware events available */ static uint32_t num_hw_events; @@ -185,10 +189,10 @@ int sbi_pmu_ctr_fw_read(uint32_t cidx, uint64_t *cval) if (SBI_PMU_FW_MAX <= event_code && pmu_dev && pmu_dev->fw_counter_read_value) - fw_counters_value[hartid][cidx - num_hw_ctrs] = + fw_counters_data[hartid][cidx - num_hw_ctrs] = pmu_dev->fw_counter_read_value(cidx - num_hw_ctrs); - *cval = fw_counters_value[hartid][cidx - num_hw_ctrs]; + *cval = fw_counters_data[hartid][cidx - num_hw_ctrs]; return 0; } @@ -372,7 +376,7 @@ static int pmu_ctr_start_fw(uint32_t cidx, uint32_t event_code, } if (ival_update) - fw_counters_value[hartid][cidx - num_hw_ctrs] = ival; + fw_counters_data[hartid][cidx - num_hw_ctrs] = ival; fw_counters_started[hartid] |= BIT(cidx - num_hw_ctrs); return 0; @@ -711,13 +715,13 @@ int sbi_pmu_ctr_cfg_match(unsigned long cidx_base, unsigned long cidx_mask, pmu_ctr_start_hw(ctr_idx, 0, false); } else if (event_type == SBI_PMU_EVENT_TYPE_FW) { if (flags & SBI_PMU_CFG_FLAG_CLEAR_VALUE) - fw_counters_value[hartid][ctr_idx - num_hw_ctrs] = 0; + fw_counters_data[hartid][ctr_idx - num_hw_ctrs] = 0; if (flags & SBI_PMU_CFG_FLAG_AUTO_START) { if (SBI_PMU_FW_MAX <= event_code && pmu_dev && pmu_dev->fw_counter_start) { ret = pmu_dev->fw_counter_start( ctr_idx - num_hw_ctrs, event_code, - fw_counters_value[hartid][ctr_idx - num_hw_ctrs], + fw_counters_data[hartid][ctr_idx - num_hw_ctrs], true); if (ret) return ret; @@ -743,7 +747,7 @@ int sbi_pmu_ctr_incr_fw(enum sbi_pmu_fw_event_code_id fw_id) for (cidx = num_hw_ctrs; cidx < total_ctrs; cidx++) { if (get_cidx_code(active_events[hartid][cidx]) == fw_id && (fw_counters_started[hartid] & BIT(cidx - num_hw_ctrs))) { - fcounter = &fw_counters_value[hartid][cidx - num_hw_ctrs]; + fcounter = &fw_counters_data[hartid][cidx - num_hw_ctrs]; break; } } @@ -803,7 +807,7 @@ static void pmu_reset_event_map(u32 hartid) for (j = 3; j < total_ctrs; j++) active_events[hartid][j] = SBI_PMU_EVENT_IDX_INVALID; for (j = 0; j < SBI_PMU_FW_CTR_MAX; j++) - fw_counters_value[hartid][j] = 0; + fw_counters_data[hartid][j] = 0; fw_counters_started[hartid] = 0; } From b51ddffcc043fb94ebcbffce7682b2d0deef5afd Mon Sep 17 00:00:00 2001 From: Mayuresh Chitale Date: Thu, 9 Mar 2023 18:43:55 +0530 Subject: [PATCH 085/187] lib: sbi_pmu: Update sbi_pmu dev ops Update fw_event_validate_code, fw_counter_match_code and fw_counter_start ops which used a 32 bit event code to use the 64 bit event data instead. Signed-off-by: Mayuresh Chitale Reviewed-by: Anup Patel --- include/sbi/sbi_pmu.h | 9 ++++----- lib/sbi/sbi_pmu.c | 30 +++++++++++++++++------------- 2 files changed, 21 insertions(+), 18 deletions(-) diff --git a/include/sbi/sbi_pmu.h b/include/sbi/sbi_pmu.h index b3b75c1bad0..3232e140ad7 100644 --- a/include/sbi/sbi_pmu.h +++ b/include/sbi/sbi_pmu.h @@ -30,16 +30,15 @@ struct sbi_pmu_device { /** * Validate event code of custom firmware event - * Note: SBI_PMU_FW_MAX <= event_idx_code */ - int (*fw_event_validate_code)(uint32_t event_idx_code); + int (*fw_event_validate_encoding)(uint64_t event_data); /** * Match custom firmware counter with custom firmware event * Note: 0 <= counter_index < SBI_PMU_FW_CTR_MAX */ - bool (*fw_counter_match_code)(uint32_t counter_index, - uint32_t event_idx_code); + bool (*fw_counter_match_encoding)(uint32_t counter_index, + uint64_t event_data); /** * Fetch the max width of this counter in number of bits. @@ -58,7 +57,7 @@ struct sbi_pmu_device { * Note: 0 <= counter_index < SBI_PMU_FW_CTR_MAX */ int (*fw_counter_start)(uint32_t counter_index, - uint32_t event_idx_code, + uint64_t event_data, uint64_t init_val, bool init_val_update); /** diff --git a/lib/sbi/sbi_pmu.c b/lib/sbi/sbi_pmu.c index 1a3c44d182e..1169ef29bde 100644 --- a/lib/sbi/sbi_pmu.c +++ b/lib/sbi/sbi_pmu.c @@ -110,7 +110,7 @@ static bool pmu_event_select_overlap(struct sbi_pmu_hw_event *evt, return false; } -static int pmu_event_validate(unsigned long event_idx) +static int pmu_event_validate(unsigned long event_idx, uint64_t edata) { uint32_t event_idx_type = get_cidx_type(event_idx); uint32_t event_idx_code = get_cidx_code(event_idx); @@ -123,8 +123,8 @@ static int pmu_event_validate(unsigned long event_idx) break; case SBI_PMU_EVENT_TYPE_FW: if (SBI_PMU_FW_MAX <= event_idx_code && - pmu_dev && pmu_dev->fw_event_validate_code) - return pmu_dev->fw_event_validate_code(event_idx_code); + pmu_dev && pmu_dev->fw_event_validate_encoding) + return pmu_dev->fw_event_validate_encoding(edata); else event_idx_code_max = SBI_PMU_FW_MAX; break; @@ -361,7 +361,8 @@ int sbi_pmu_irq_bit(void) } static int pmu_ctr_start_fw(uint32_t cidx, uint32_t event_code, - uint64_t ival, bool ival_update) + uint64_t event_data, uint64_t ival, + bool ival_update) { int ret; u32 hartid = current_hartid(); @@ -369,7 +370,7 @@ static int pmu_ctr_start_fw(uint32_t cidx, uint32_t event_code, if (SBI_PMU_FW_MAX <= event_code && pmu_dev && pmu_dev->fw_counter_start) { ret = pmu_dev->fw_counter_start(cidx - num_hw_ctrs, - event_code, + event_data, ival, ival_update); if (ret) return ret; @@ -390,6 +391,7 @@ int sbi_pmu_ctr_start(unsigned long cbase, unsigned long cmask, int ret = SBI_EINVAL; bool bUpdate = false; int i, cidx; + uint64_t edata = 0; if ((cbase + sbi_fls(cmask)) >= total_ctrs) return ret; @@ -404,7 +406,8 @@ int sbi_pmu_ctr_start(unsigned long cbase, unsigned long cmask, /* Continue the start operation for other counters */ continue; else if (event_idx_type == SBI_PMU_EVENT_TYPE_FW) - ret = pmu_ctr_start_fw(cidx, event_code, ival, bUpdate); + ret = pmu_ctr_start_fw(cidx, event_code, edata, ival, + bUpdate); else ret = pmu_ctr_start_hw(cidx, ival, bUpdate); } @@ -644,7 +647,7 @@ static int pmu_ctr_find_hw(unsigned long cbase, unsigned long cmask, unsigned lo * check. */ static int pmu_ctr_find_fw(unsigned long cbase, unsigned long cmask, - uint32_t event_code, u32 hartid) + uint32_t event_code, u32 hartid, uint64_t edata) { int i, cidx; @@ -655,9 +658,9 @@ static int pmu_ctr_find_fw(unsigned long cbase, unsigned long cmask, if (active_events[hartid][i] != SBI_PMU_EVENT_IDX_INVALID) continue; if (SBI_PMU_FW_MAX <= event_code && - pmu_dev && pmu_dev->fw_counter_match_code) { - if (!pmu_dev->fw_counter_match_code(cidx - num_hw_ctrs, - event_code)) + pmu_dev && pmu_dev->fw_counter_match_encoding) { + if (!pmu_dev->fw_counter_match_encoding(cidx - num_hw_ctrs, + edata)) continue; } @@ -679,7 +682,7 @@ int sbi_pmu_ctr_cfg_match(unsigned long cidx_base, unsigned long cidx_mask, if ((cidx_base + sbi_fls(cidx_mask)) >= total_ctrs) return SBI_EINVAL; - event_type = pmu_event_validate(event_idx); + event_type = pmu_event_validate(event_idx, event_data); if (event_type < 0) return SBI_EINVAL; event_code = get_cidx_code(event_idx); @@ -697,7 +700,8 @@ int sbi_pmu_ctr_cfg_match(unsigned long cidx_base, unsigned long cidx_mask, if (event_type == SBI_PMU_EVENT_TYPE_FW) { /* Any firmware counter can be used track any firmware event */ - ctr_idx = pmu_ctr_find_fw(cidx_base, cidx_mask, event_code, hartid); + ctr_idx = pmu_ctr_find_fw(cidx_base, cidx_mask, event_code, + hartid, event_data); } else { ctr_idx = pmu_ctr_find_hw(cidx_base, cidx_mask, flags, event_idx, event_data); @@ -720,7 +724,7 @@ int sbi_pmu_ctr_cfg_match(unsigned long cidx_base, unsigned long cidx_mask, if (SBI_PMU_FW_MAX <= event_code && pmu_dev && pmu_dev->fw_counter_start) { ret = pmu_dev->fw_counter_start( - ctr_idx - num_hw_ctrs, event_code, + ctr_idx - num_hw_ctrs, event_data, fw_counters_data[hartid][ctr_idx - num_hw_ctrs], true); if (ret) From 641d2e9f38e085ccee77cfd866cae5c7222830fc Mon Sep 17 00:00:00 2001 From: Mayuresh Chitale Date: Thu, 9 Mar 2023 18:43:56 +0530 Subject: [PATCH 086/187] lib: sbi_pmu: Use dedicated event code for platform firmware events For all platform specific firmware event operations use the dedicated event code (0xFFFF) when matching against the input firmware event. Furthermore save the real platform specific firmware event code received as the event data for future use. Signed-off-by: Mayuresh Chitale Reviewed-by: Anup Patel --- lib/sbi/sbi_pmu.c | 65 +++++++++++++++++++++++++++++++++++++---------- 1 file changed, 52 insertions(+), 13 deletions(-) diff --git a/lib/sbi/sbi_pmu.c b/lib/sbi/sbi_pmu.c index 1169ef29bde..d0831985bb0 100644 --- a/lib/sbi/sbi_pmu.c +++ b/lib/sbi/sbi_pmu.c @@ -122,7 +122,12 @@ static int pmu_event_validate(unsigned long event_idx, uint64_t edata) event_idx_code_max = SBI_PMU_HW_GENERAL_MAX; break; case SBI_PMU_EVENT_TYPE_FW: - if (SBI_PMU_FW_MAX <= event_idx_code && + if ((event_idx_code >= SBI_PMU_FW_MAX && + event_idx_code <= SBI_PMU_FW_RESERVED_MAX) || + event_idx_code > SBI_PMU_FW_PLATFORM) + return SBI_EINVAL; + + if (SBI_PMU_FW_PLATFORM == event_idx_code && pmu_dev && pmu_dev->fw_event_validate_encoding) return pmu_dev->fw_event_validate_encoding(edata); else @@ -187,12 +192,19 @@ int sbi_pmu_ctr_fw_read(uint32_t cidx, uint64_t *cval) if (event_idx_type != SBI_PMU_EVENT_TYPE_FW) return SBI_EINVAL; - if (SBI_PMU_FW_MAX <= event_code && - pmu_dev && pmu_dev->fw_counter_read_value) - fw_counters_data[hartid][cidx - num_hw_ctrs] = - pmu_dev->fw_counter_read_value(cidx - num_hw_ctrs); + if ((event_code >= SBI_PMU_FW_MAX && + event_code <= SBI_PMU_FW_RESERVED_MAX) || + event_code > SBI_PMU_FW_PLATFORM) + return SBI_EINVAL; - *cval = fw_counters_data[hartid][cidx - num_hw_ctrs]; + if (SBI_PMU_FW_PLATFORM == event_code) { + if (pmu_dev && pmu_dev->fw_counter_read_value) + *cval = pmu_dev->fw_counter_read_value(cidx - + num_hw_ctrs); + else + *cval = 0; + } else + *cval = fw_counters_data[hartid][cidx - num_hw_ctrs]; return 0; } @@ -367,8 +379,17 @@ static int pmu_ctr_start_fw(uint32_t cidx, uint32_t event_code, int ret; u32 hartid = current_hartid(); - if (SBI_PMU_FW_MAX <= event_code && - pmu_dev && pmu_dev->fw_counter_start) { + if ((event_code >= SBI_PMU_FW_MAX && + event_code <= SBI_PMU_FW_RESERVED_MAX) || + event_code > SBI_PMU_FW_PLATFORM) + return SBI_EINVAL; + + if (SBI_PMU_FW_PLATFORM == event_code) { + if (!pmu_dev || + !pmu_dev->fw_counter_start) { + return SBI_EINVAL; + } + ret = pmu_dev->fw_counter_start(cidx - num_hw_ctrs, event_data, ival, ival_update); @@ -386,12 +407,13 @@ static int pmu_ctr_start_fw(uint32_t cidx, uint32_t event_code, int sbi_pmu_ctr_start(unsigned long cbase, unsigned long cmask, unsigned long flags, uint64_t ival) { + u32 hartid = current_hartid(); int event_idx_type; uint32_t event_code; int ret = SBI_EINVAL; bool bUpdate = false; int i, cidx; - uint64_t edata = 0; + uint64_t edata; if ((cbase + sbi_fls(cmask)) >= total_ctrs) return ret; @@ -405,9 +427,13 @@ int sbi_pmu_ctr_start(unsigned long cbase, unsigned long cmask, if (event_idx_type < 0) /* Continue the start operation for other counters */ continue; - else if (event_idx_type == SBI_PMU_EVENT_TYPE_FW) + else if (event_idx_type == SBI_PMU_EVENT_TYPE_FW) { + edata = (event_code == SBI_PMU_FW_PLATFORM) ? + fw_counters_data[hartid][cidx - num_hw_ctrs] + : 0x0; ret = pmu_ctr_start_fw(cidx, event_code, edata, ival, bUpdate); + } else ret = pmu_ctr_start_hw(cidx, ival, bUpdate); } @@ -441,7 +467,12 @@ static int pmu_ctr_stop_fw(uint32_t cidx, uint32_t event_code) { int ret; - if (SBI_PMU_FW_MAX <= event_code && + if ((event_code >= SBI_PMU_FW_MAX && + event_code <= SBI_PMU_FW_RESERVED_MAX) || + event_code > SBI_PMU_FW_PLATFORM) + return SBI_EINVAL; + + if (SBI_PMU_FW_PLATFORM == event_code && pmu_dev && pmu_dev->fw_counter_stop) { ret = pmu_dev->fw_counter_stop(cidx - num_hw_ctrs); if (ret) @@ -651,13 +682,18 @@ static int pmu_ctr_find_fw(unsigned long cbase, unsigned long cmask, { int i, cidx; + if ((event_code >= SBI_PMU_FW_MAX && + event_code <= SBI_PMU_FW_RESERVED_MAX) || + event_code > SBI_PMU_FW_PLATFORM) + return SBI_EINVAL; + for_each_set_bit(i, &cmask, BITS_PER_LONG) { cidx = i + cbase; if (cidx < num_hw_ctrs || total_ctrs <= cidx) continue; if (active_events[hartid][i] != SBI_PMU_EVENT_IDX_INVALID) continue; - if (SBI_PMU_FW_MAX <= event_code && + if (SBI_PMU_FW_PLATFORM == event_code && pmu_dev && pmu_dev->fw_counter_match_encoding) { if (!pmu_dev->fw_counter_match_encoding(cidx - num_hw_ctrs, edata)) @@ -702,6 +738,9 @@ int sbi_pmu_ctr_cfg_match(unsigned long cidx_base, unsigned long cidx_mask, /* Any firmware counter can be used track any firmware event */ ctr_idx = pmu_ctr_find_fw(cidx_base, cidx_mask, event_code, hartid, event_data); + if (event_code == SBI_PMU_FW_PLATFORM) + fw_counters_data[hartid][ctr_idx - num_hw_ctrs] = + event_data; } else { ctr_idx = pmu_ctr_find_hw(cidx_base, cidx_mask, flags, event_idx, event_data); @@ -721,7 +760,7 @@ int sbi_pmu_ctr_cfg_match(unsigned long cidx_base, unsigned long cidx_mask, if (flags & SBI_PMU_CFG_FLAG_CLEAR_VALUE) fw_counters_data[hartid][ctr_idx - num_hw_ctrs] = 0; if (flags & SBI_PMU_CFG_FLAG_AUTO_START) { - if (SBI_PMU_FW_MAX <= event_code && + if (SBI_PMU_FW_PLATFORM == event_code && pmu_dev && pmu_dev->fw_counter_start) { ret = pmu_dev->fw_counter_start( ctr_idx - num_hw_ctrs, event_data, From 57d3aa3b0dbd534ab702dce61767df0e9dc7577f Mon Sep 17 00:00:00 2001 From: Mayuresh Chitale Date: Thu, 9 Mar 2023 18:43:57 +0530 Subject: [PATCH 087/187] lib: sbi_pmu: Introduce fw_counter_write_value API Add fw_counter_write_value API for platform specific firmware events which separates setting the counter's initial value from starting the counter. This is required so that the fw_event_data array can be reused to save the event data received. Signed-off-by: Mayuresh Chitale Reviewed-by: Anup Patel --- include/sbi/sbi_pmu.h | 11 ++++++++--- lib/sbi/sbi_pmu.c | 25 +++++++++++++------------ 2 files changed, 21 insertions(+), 15 deletions(-) diff --git a/include/sbi/sbi_pmu.h b/include/sbi/sbi_pmu.h index 3232e140ad7..53f27003a9e 100644 --- a/include/sbi/sbi_pmu.h +++ b/include/sbi/sbi_pmu.h @@ -51,14 +51,19 @@ struct sbi_pmu_device { */ uint64_t (*fw_counter_read_value)(uint32_t counter_index); + /** + * Write value to custom firmware counter + * Note: 0 <= counter_index < SBI_PMU_FW_CTR_MAX + */ + void (*fw_counter_write_value)(uint32_t counter_index, + uint64_t value); + /** * Start custom firmware counter - * Note: SBI_PMU_FW_MAX <= event_idx_code * Note: 0 <= counter_index < SBI_PMU_FW_CTR_MAX */ int (*fw_counter_start)(uint32_t counter_index, - uint64_t event_data, - uint64_t init_val, bool init_val_update); + uint64_t event_data); /** * Stop custom firmware counter diff --git a/lib/sbi/sbi_pmu.c b/lib/sbi/sbi_pmu.c index d0831985bb0..00a2c3e9244 100644 --- a/lib/sbi/sbi_pmu.c +++ b/lib/sbi/sbi_pmu.c @@ -376,7 +376,6 @@ static int pmu_ctr_start_fw(uint32_t cidx, uint32_t event_code, uint64_t event_data, uint64_t ival, bool ival_update) { - int ret; u32 hartid = current_hartid(); if ((event_code >= SBI_PMU_FW_MAX && @@ -386,19 +385,22 @@ static int pmu_ctr_start_fw(uint32_t cidx, uint32_t event_code, if (SBI_PMU_FW_PLATFORM == event_code) { if (!pmu_dev || + !pmu_dev->fw_counter_write_value || !pmu_dev->fw_counter_start) { return SBI_EINVAL; } - ret = pmu_dev->fw_counter_start(cidx - num_hw_ctrs, - event_data, - ival, ival_update); - if (ret) - return ret; + if (ival_update) + pmu_dev->fw_counter_write_value(cidx - num_hw_ctrs, + ival); + + return pmu_dev->fw_counter_start(cidx - num_hw_ctrs, + event_data); + } else { + if (ival_update) + fw_counters_data[hartid][cidx - num_hw_ctrs] = ival; } - if (ival_update) - fw_counters_data[hartid][cidx - num_hw_ctrs] = ival; fw_counters_started[hartid] |= BIT(cidx - num_hw_ctrs); return 0; @@ -762,10 +764,9 @@ int sbi_pmu_ctr_cfg_match(unsigned long cidx_base, unsigned long cidx_mask, if (flags & SBI_PMU_CFG_FLAG_AUTO_START) { if (SBI_PMU_FW_PLATFORM == event_code && pmu_dev && pmu_dev->fw_counter_start) { - ret = pmu_dev->fw_counter_start( - ctr_idx - num_hw_ctrs, event_data, - fw_counters_data[hartid][ctr_idx - num_hw_ctrs], - true); + ret = pmu_dev->fw_counter_start(ctr_idx - + num_hw_ctrs, + event_data); if (ret) return ret; } From c631a7da279e735590231d2ae432fbc05743aa9e Mon Sep 17 00:00:00 2001 From: Mayuresh Chitale Date: Thu, 9 Mar 2023 18:43:58 +0530 Subject: [PATCH 088/187] lib: sbi_pmu: Add hartid parameter PMU device ops Platform specific firmware event handler may leverage the hartid to program per hart specific registers for a given counter. Signed-off-by: Mayuresh Chitale Reviewed-by: Atish Patra Reviewed-by: Anup Patel --- include/sbi/sbi_pmu.h | 14 ++++++++------ lib/sbi/sbi_pmu.c | 25 +++++++++++++++---------- 2 files changed, 23 insertions(+), 16 deletions(-) diff --git a/include/sbi/sbi_pmu.h b/include/sbi/sbi_pmu.h index 53f27003a9e..16f687733ba 100644 --- a/include/sbi/sbi_pmu.h +++ b/include/sbi/sbi_pmu.h @@ -31,13 +31,14 @@ struct sbi_pmu_device { /** * Validate event code of custom firmware event */ - int (*fw_event_validate_encoding)(uint64_t event_data); + int (*fw_event_validate_encoding)(uint32_t hartid, uint64_t event_data); /** * Match custom firmware counter with custom firmware event * Note: 0 <= counter_index < SBI_PMU_FW_CTR_MAX */ - bool (*fw_counter_match_encoding)(uint32_t counter_index, + bool (*fw_counter_match_encoding)(uint32_t hartid, + uint32_t counter_index, uint64_t event_data); /** @@ -49,27 +50,28 @@ struct sbi_pmu_device { * Read value of custom firmware counter * Note: 0 <= counter_index < SBI_PMU_FW_CTR_MAX */ - uint64_t (*fw_counter_read_value)(uint32_t counter_index); + uint64_t (*fw_counter_read_value)(uint32_t hartid, + uint32_t counter_index); /** * Write value to custom firmware counter * Note: 0 <= counter_index < SBI_PMU_FW_CTR_MAX */ - void (*fw_counter_write_value)(uint32_t counter_index, + void (*fw_counter_write_value)(uint32_t hartid, uint32_t counter_index, uint64_t value); /** * Start custom firmware counter * Note: 0 <= counter_index < SBI_PMU_FW_CTR_MAX */ - int (*fw_counter_start)(uint32_t counter_index, + int (*fw_counter_start)(uint32_t hartid, uint32_t counter_index, uint64_t event_data); /** * Stop custom firmware counter * Note: 0 <= counter_index < SBI_PMU_FW_CTR_MAX */ - int (*fw_counter_stop)(uint32_t counter_index); + int (*fw_counter_stop)(uint32_t hartid, uint32_t counter_index); /** * Custom enable irq for hardware counter diff --git a/lib/sbi/sbi_pmu.c b/lib/sbi/sbi_pmu.c index 00a2c3e9244..74d69122efb 100644 --- a/lib/sbi/sbi_pmu.c +++ b/lib/sbi/sbi_pmu.c @@ -116,6 +116,7 @@ static int pmu_event_validate(unsigned long event_idx, uint64_t edata) uint32_t event_idx_code = get_cidx_code(event_idx); uint32_t event_idx_code_max = -1; uint32_t cache_ops_result, cache_ops_id, cache_id; + u32 hartid = current_hartid(); switch(event_idx_type) { case SBI_PMU_EVENT_TYPE_HW: @@ -129,7 +130,8 @@ static int pmu_event_validate(unsigned long event_idx, uint64_t edata) if (SBI_PMU_FW_PLATFORM == event_idx_code && pmu_dev && pmu_dev->fw_event_validate_encoding) - return pmu_dev->fw_event_validate_encoding(edata); + return pmu_dev->fw_event_validate_encoding(hartid, + edata); else event_idx_code_max = SBI_PMU_FW_MAX; break; @@ -199,7 +201,8 @@ int sbi_pmu_ctr_fw_read(uint32_t cidx, uint64_t *cval) if (SBI_PMU_FW_PLATFORM == event_code) { if (pmu_dev && pmu_dev->fw_counter_read_value) - *cval = pmu_dev->fw_counter_read_value(cidx - + *cval = pmu_dev->fw_counter_read_value(hartid, + cidx - num_hw_ctrs); else *cval = 0; @@ -391,10 +394,11 @@ static int pmu_ctr_start_fw(uint32_t cidx, uint32_t event_code, } if (ival_update) - pmu_dev->fw_counter_write_value(cidx - num_hw_ctrs, + pmu_dev->fw_counter_write_value(hartid, + cidx - num_hw_ctrs, ival); - return pmu_dev->fw_counter_start(cidx - num_hw_ctrs, + return pmu_dev->fw_counter_start(hartid, cidx - num_hw_ctrs, event_data); } else { if (ival_update) @@ -467,6 +471,7 @@ static int pmu_ctr_stop_hw(uint32_t cidx) static int pmu_ctr_stop_fw(uint32_t cidx, uint32_t event_code) { + u32 hartid = current_hartid(); int ret; if ((event_code >= SBI_PMU_FW_MAX && @@ -476,7 +481,7 @@ static int pmu_ctr_stop_fw(uint32_t cidx, uint32_t event_code) if (SBI_PMU_FW_PLATFORM == event_code && pmu_dev && pmu_dev->fw_counter_stop) { - ret = pmu_dev->fw_counter_stop(cidx - num_hw_ctrs); + ret = pmu_dev->fw_counter_stop(hartid, cidx - num_hw_ctrs); if (ret) return ret; } @@ -697,8 +702,9 @@ static int pmu_ctr_find_fw(unsigned long cbase, unsigned long cmask, continue; if (SBI_PMU_FW_PLATFORM == event_code && pmu_dev && pmu_dev->fw_counter_match_encoding) { - if (!pmu_dev->fw_counter_match_encoding(cidx - num_hw_ctrs, - edata)) + if (!pmu_dev->fw_counter_match_encoding(hartid, + cidx - num_hw_ctrs, + edata)) continue; } @@ -764,9 +770,8 @@ int sbi_pmu_ctr_cfg_match(unsigned long cidx_base, unsigned long cidx_mask, if (flags & SBI_PMU_CFG_FLAG_AUTO_START) { if (SBI_PMU_FW_PLATFORM == event_code && pmu_dev && pmu_dev->fw_counter_start) { - ret = pmu_dev->fw_counter_start(ctr_idx - - num_hw_ctrs, - event_data); + ret = pmu_dev->fw_counter_start(hartid, + ctr_idx - num_hw_ctrs, event_data); if (ret) return ret; } From d56049e299cce3bca2022903a5550acdc323d8a4 Mon Sep 17 00:00:00 2001 From: Evgenii Shatokhin Date: Mon, 6 Mar 2023 00:22:45 +0300 Subject: [PATCH 089/187] lib: sbi: Refactor the calls to sbi_hart_switch_mode() Move them into sbi_hsm_hart_start_finish() and sbi_hsm_hart_resume_finish() to make them easier to manage. This will be used by subsequent patches. Suggested-by: Anup Patel Signed-off-by: Evgenii Shatokhin Reviewed-by: Anup Patel --- include/sbi/sbi_hsm.h | 6 ++++-- lib/sbi/sbi_hsm.c | 13 +++++++++++-- lib/sbi/sbi_init.c | 20 ++++++++------------ 3 files changed, 23 insertions(+), 16 deletions(-) diff --git a/include/sbi/sbi_hsm.h b/include/sbi/sbi_hsm.h index c0b483030de..4b5601ba40c 100644 --- a/include/sbi/sbi_hsm.h +++ b/include/sbi/sbi_hsm.h @@ -66,7 +66,8 @@ int sbi_hsm_hart_start(struct sbi_scratch *scratch, u32 hartid, ulong saddr, ulong smode, ulong arg1); int sbi_hsm_hart_stop(struct sbi_scratch *scratch, bool exitnow); void sbi_hsm_hart_resume_start(struct sbi_scratch *scratch); -void sbi_hsm_hart_resume_finish(struct sbi_scratch *scratch); +void __noreturn sbi_hsm_hart_resume_finish(struct sbi_scratch *scratch, + u32 hartid); int sbi_hsm_hart_suspend(struct sbi_scratch *scratch, u32 suspend_type, ulong raddr, ulong rmode, ulong arg1); bool sbi_hsm_hart_change_state(struct sbi_scratch *scratch, long oldstate, @@ -76,6 +77,7 @@ int sbi_hsm_hart_get_state(const struct sbi_domain *dom, u32 hartid); int sbi_hsm_hart_interruptible_mask(const struct sbi_domain *dom, ulong hbase, ulong *out_hmask); void __sbi_hsm_suspend_non_ret_save(struct sbi_scratch *scratch); -void sbi_hsm_prepare_next_jump(struct sbi_scratch *scratch, u32 hartid); +void __noreturn sbi_hsm_hart_start_finish(struct sbi_scratch *scratch, + u32 hartid); #endif diff --git a/lib/sbi/sbi_hsm.c b/lib/sbi/sbi_hsm.c index 3eeeb586cbb..100b8c0a669 100644 --- a/lib/sbi/sbi_hsm.c +++ b/lib/sbi/sbi_hsm.c @@ -110,7 +110,8 @@ int sbi_hsm_hart_interruptible_mask(const struct sbi_domain *dom, return 0; } -void sbi_hsm_prepare_next_jump(struct sbi_scratch *scratch, u32 hartid) +void __noreturn sbi_hsm_hart_start_finish(struct sbi_scratch *scratch, + u32 hartid) { struct sbi_hsm_data *hdata = sbi_scratch_offset_ptr(scratch, hart_data_offset); @@ -118,6 +119,9 @@ void sbi_hsm_prepare_next_jump(struct sbi_scratch *scratch, u32 hartid) if (!__sbi_hsm_hart_change_state(hdata, SBI_HSM_STATE_START_PENDING, SBI_HSM_STATE_STARTED)) sbi_hart_hang(); + + sbi_hart_switch_mode(hartid, scratch->next_arg1, scratch->next_addr, + scratch->next_mode, false); } static void sbi_hsm_hart_wait(struct sbi_scratch *scratch, u32 hartid) @@ -381,7 +385,8 @@ void sbi_hsm_hart_resume_start(struct sbi_scratch *scratch) hsm_device_hart_resume(); } -void sbi_hsm_hart_resume_finish(struct sbi_scratch *scratch) +void __noreturn sbi_hsm_hart_resume_finish(struct sbi_scratch *scratch, + u32 hartid) { struct sbi_hsm_data *hdata = sbi_scratch_offset_ptr(scratch, hart_data_offset); @@ -396,6 +401,10 @@ void sbi_hsm_hart_resume_finish(struct sbi_scratch *scratch) * the warm-boot sequence. */ __sbi_hsm_suspend_non_ret_restore(scratch); + + sbi_hart_switch_mode(hartid, scratch->next_arg1, + scratch->next_addr, + scratch->next_mode, false); } int sbi_hsm_hart_suspend(struct sbi_scratch *scratch, u32 suspend_type, diff --git a/lib/sbi/sbi_init.c b/lib/sbi/sbi_init.c index bc60a427935..dcca2c811e1 100644 --- a/lib/sbi/sbi_init.c +++ b/lib/sbi/sbi_init.c @@ -355,12 +355,11 @@ static void __noreturn init_coldboot(struct sbi_scratch *scratch, u32 hartid) init_count = sbi_scratch_offset_ptr(scratch, init_count_offset); (*init_count)++; - sbi_hsm_prepare_next_jump(scratch, hartid); - sbi_hart_switch_mode(hartid, scratch->next_arg1, scratch->next_addr, - scratch->next_mode, false); + sbi_hsm_hart_start_finish(scratch, hartid); } -static void init_warm_startup(struct sbi_scratch *scratch, u32 hartid) +static void __noreturn init_warm_startup(struct sbi_scratch *scratch, + u32 hartid) { int rc; unsigned long *init_count; @@ -412,10 +411,11 @@ static void init_warm_startup(struct sbi_scratch *scratch, u32 hartid) init_count = sbi_scratch_offset_ptr(scratch, init_count_offset); (*init_count)++; - sbi_hsm_prepare_next_jump(scratch, hartid); + sbi_hsm_hart_start_finish(scratch, hartid); } -static void init_warm_resume(struct sbi_scratch *scratch) +static void __noreturn init_warm_resume(struct sbi_scratch *scratch, + u32 hartid) { int rc; @@ -429,7 +429,7 @@ static void init_warm_resume(struct sbi_scratch *scratch) if (rc) sbi_hart_hang(); - sbi_hsm_hart_resume_finish(scratch); + sbi_hsm_hart_resume_finish(scratch, hartid); } static void __noreturn init_warmboot(struct sbi_scratch *scratch, u32 hartid) @@ -443,13 +443,9 @@ static void __noreturn init_warmboot(struct sbi_scratch *scratch, u32 hartid) sbi_hart_hang(); if (hstate == SBI_HSM_STATE_SUSPENDED) - init_warm_resume(scratch); + init_warm_resume(scratch, hartid); else init_warm_startup(scratch, hartid); - - sbi_hart_switch_mode(hartid, scratch->next_arg1, - scratch->next_addr, - scratch->next_mode, false); } static atomic_t coldboot_lottery = ATOMIC_INITIALIZER(0); From e8e9ed3790feac05ec6fd5c279ec80b05293d67b Mon Sep 17 00:00:00 2001 From: Evgenii Shatokhin Date: Mon, 6 Mar 2023 00:22:46 +0300 Subject: [PATCH 090/187] lib: sbi: Set the state of a hart to START_PENDING after the hart is ready When a boot hart executes sbi_hsm_hart_start() to start a secondary hart, next_arg1, next_addr and next_mode for the latter are stored in the scratch area after the state has been set to SBI_HSM_STATE_START_PENDING. The secondary hart waits in the loop with wfi() in sbi_hsm_hart_wait() at that time. However, "wfi" instruction is not guaranteed to wait for an interrupt to be received by the hart, it is just a hint for the CPU. According to RISC-V Privileged Architectures spec. v20211203, even an implementation of "wfi" as "nop" is legal. So, the secondary might leave the loop in sbi_hsm_hart_wait() as soon as its state has been set to SBI_HSM_STATE_START_PENDING, even if it got no IPI or it got an IPI unrelated to sbi_hsm_hart_start(). This could lead to the following race condition when booting Linux, for example: Boot hart (#0) Secondary hart (#1) runs Linux startup code waits in sbi_hsm_hart_wait() sbi_ecall(SBI_EXT_HSM, SBI_EXT_HSM_HART_START, ...) enters sbi_hsm_hart_start() sets state of hart #1 to START_PENDING leaves sbi_hsm_hart_wait() runs to the end of init_warmboot() returns to scratch->next_addr (next_addr can be garbage here) sets next_addr, etc. for hart #1 (no good: hart #1 has already left) sends IPI to hart #1 (no good either) If this happens, the secondary hart jumps to a wrong next_addr at the end of init_warmboot(), which leads to a system hang or crash. To reproduce the issue more reliably, one could add a delay in sbi_hsm_hart_start() after setting the hart's state but before sending IPI to that hart: hstate = atomic_cmpxchg(&hdata->state, SBI_HSM_STATE_STOPPED, SBI_HSM_STATE_START_PENDING); ... + sbi_timer_mdelay(10); init_count = sbi_init_count(hartid); rscratch->next_arg1 = arg1; rscratch->next_addr = saddr; The issue can be reproduced, for example, in a QEMU VM with '-machine virt' and 2 or more CPUs, with Linux as the guest OS. This patch moves writing of next_arg1, next_addr and next_mode for the secondary hart before setting its state to SBI_HSM_STATE_START_PENDING. In theory, it is possible that two or more harts enter sbi_hsm_hart_start() for the same target hart simultaneously. To make sure the current hart has exclusive access to the scratch area of the target hart at that point, a per-hart 'start_ticket' is used. It is initially 0. The current hart tries to acquire the ticket first (set it to 1) at the beginning of sbi_hsm_hart_start() and only proceeds if it has successfully acquired it. The target hart reads next_addr, etc., and then the releases the ticket (sets it to 0) before calling sbi_hart_switch_mode(). This way, even if some other hart manages to enter sbi_hsm_hart_start() after the ticket has been released but before the target hart jumps to next_addr, it will not cause problems. atomic_cmpxchg() already has "acquire" semantics, among other things, so no additional barriers are needed in hsm_start_ticket_acquire(). No hart can perform or observe the update of *rscratch before setting of 'start_ticket' to 1. atomic_write() only imposes ordering of writes, so an explicit barrier is needed in hsm_start_ticket_release() to ensure its "release" semantics. This guarantees that reads of scratch->next_addr, etc., in sbi_hsm_hart_start_finish() cannot happen after 'start_ticket' has been released. Signed-off-by: Evgenii Shatokhin Reviewed-by: Anup Patel --- lib/sbi/sbi_hsm.c | 83 ++++++++++++++++++++++++++++++++++++++--------- 1 file changed, 67 insertions(+), 16 deletions(-) diff --git a/lib/sbi/sbi_hsm.c b/lib/sbi/sbi_hsm.c index 100b8c0a669..16e3846faef 100644 --- a/lib/sbi/sbi_hsm.c +++ b/lib/sbi/sbi_hsm.c @@ -44,6 +44,7 @@ struct sbi_hsm_data { unsigned long suspend_type; unsigned long saved_mie; unsigned long saved_mip; + atomic_t start_ticket; }; bool sbi_hsm_hart_change_state(struct sbi_scratch *scratch, long oldstate, @@ -75,6 +76,32 @@ int sbi_hsm_hart_get_state(const struct sbi_domain *dom, u32 hartid) return __sbi_hsm_hart_get_state(hartid); } +/* + * Try to acquire the ticket for the given target hart to make sure only + * one hart prepares the start of the target hart. + * Returns true if the ticket has been acquired, false otherwise. + * + * The function has "acquire" semantics: no memory operations following it + * in the current hart can be seen before it by other harts. + * atomic_cmpxchg() provides the memory barriers needed for that. + */ +static bool hsm_start_ticket_acquire(struct sbi_hsm_data *hdata) +{ + return (atomic_cmpxchg(&hdata->start_ticket, 0, 1) == 0); +} + +/* + * Release the ticket for the given target hart. + * + * The function has "release" semantics: no memory operations preceding it + * in the current hart can be seen after it by other harts. + */ +static void hsm_start_ticket_release(struct sbi_hsm_data *hdata) +{ + RISCV_FENCE(rw, w); + atomic_write(&hdata->start_ticket, 0); +} + /** * Get ulong HART mask for given HART base ID * @param dom the domain to be used for output HART mask @@ -113,6 +140,9 @@ int sbi_hsm_hart_interruptible_mask(const struct sbi_domain *dom, void __noreturn sbi_hsm_hart_start_finish(struct sbi_scratch *scratch, u32 hartid) { + unsigned long next_arg1; + unsigned long next_addr; + unsigned long next_mode; struct sbi_hsm_data *hdata = sbi_scratch_offset_ptr(scratch, hart_data_offset); @@ -120,8 +150,12 @@ void __noreturn sbi_hsm_hart_start_finish(struct sbi_scratch *scratch, SBI_HSM_STATE_STARTED)) sbi_hart_hang(); - sbi_hart_switch_mode(hartid, scratch->next_arg1, scratch->next_addr, - scratch->next_mode, false); + next_arg1 = scratch->next_arg1; + next_addr = scratch->next_addr; + next_mode = scratch->next_mode; + hsm_start_ticket_release(hdata); + + sbi_hart_switch_mode(hartid, next_arg1, next_addr, next_mode, false); } static void sbi_hsm_hart_wait(struct sbi_scratch *scratch, u32 hartid) @@ -226,6 +260,7 @@ int sbi_hsm_init(struct sbi_scratch *scratch, u32 hartid, bool cold_boot) (i == hartid) ? SBI_HSM_STATE_START_PENDING : SBI_HSM_STATE_STOPPED); + ATOMIC_INIT(&hdata->start_ticket, 0); } } else { sbi_hsm_hart_wait(scratch, hartid); @@ -270,6 +305,7 @@ int sbi_hsm_hart_start(struct sbi_scratch *scratch, unsigned int hstate; struct sbi_scratch *rscratch; struct sbi_hsm_data *hdata; + int rc; /* For now, we only allow start mode to be S-mode or U-mode. */ if (smode != PRV_S && smode != PRV_U) @@ -283,34 +319,49 @@ int sbi_hsm_hart_start(struct sbi_scratch *scratch, rscratch = sbi_hartid_to_scratch(hartid); if (!rscratch) return SBI_EINVAL; + hdata = sbi_scratch_offset_ptr(rscratch, hart_data_offset); + if (!hsm_start_ticket_acquire(hdata)) + return SBI_EINVAL; + + init_count = sbi_init_count(hartid); + rscratch->next_arg1 = arg1; + rscratch->next_addr = saddr; + rscratch->next_mode = smode; + + /* + * atomic_cmpxchg() is an implicit barrier. It makes sure that + * other harts see reading of init_count and writing to *rscratch + * before hdata->state is set to SBI_HSM_STATE_START_PENDING. + */ hstate = atomic_cmpxchg(&hdata->state, SBI_HSM_STATE_STOPPED, SBI_HSM_STATE_START_PENDING); - if (hstate == SBI_HSM_STATE_STARTED) - return SBI_EALREADY; + if (hstate == SBI_HSM_STATE_STARTED) { + rc = SBI_EALREADY; + goto err; + } /** * if a hart is already transition to start or stop, another start call * is considered as invalid request. */ - if (hstate != SBI_HSM_STATE_STOPPED) - return SBI_EINVAL; - - init_count = sbi_init_count(hartid); - rscratch->next_arg1 = arg1; - rscratch->next_addr = saddr; - rscratch->next_mode = smode; + if (hstate != SBI_HSM_STATE_STOPPED) { + rc = SBI_EINVAL; + goto err; + } if (hsm_device_has_hart_hotplug() || (hsm_device_has_hart_secondary_boot() && !init_count)) { - return hsm_device_hart_start(hartid, scratch->warmboot_addr); + rc = hsm_device_hart_start(hartid, scratch->warmboot_addr); } else { - int rc = sbi_ipi_raw_send(hartid); - if (rc) - return rc; + rc = sbi_ipi_raw_send(hartid); } - return 0; + if (!rc) + return 0; +err: + hsm_start_ticket_release(hdata); + return rc; } int sbi_hsm_hart_stop(struct sbi_scratch *scratch, bool exitnow) From c6a092cd80112529cb2e92e180767ff5341b22a3 Mon Sep 17 00:00:00 2001 From: Evgenii Shatokhin Date: Mon, 6 Mar 2023 00:22:47 +0300 Subject: [PATCH 091/187] lib: sbi: Clear IPIs before init_warm_startup in non-boot harts Since commit 50d4fde1c5a4 ("lib: Remove redundant sbi_platform_ipi_clear() calls"), the IPI sent from the boot hart in wake_coldboot_harts() is not cleared in the secondary harts until they reach sbi_ipi_init(). However, sbi_hsm_init() and sbi_hsm_hart_wait() are called earlier, so a secondary hart might enter sbi_hsm_hart_wait() with an already pending IPI. sbi_hsm_hart_wait() makes sure the hart leaves the loop only when it is actually ready, so a pending unrelated IPI should not cause safety issues. However, it might be inefficient on certain hardware, because it prevents "wfi" from stalling the hart even if the hardware supports this, making the hart needlessly spin in a "busy-wait" loop. This behaviour can be observed, for example, in a QEMU VM (QEMU 7.2.0) with "-machine virt" running a Linux guest. Inserting delays in sbi_hsm_hart_start() allows reproducing the issue more reliably. The comment in wait_for_coldboot() suggests that the initial IPI is needed in the warm resume path, so let us clear it before init_warm_startup() only. To do this, sbi_ipi_raw_clear() was created similar to sbi_ipi_raw_send(). Signed-off-by: Evgenii Shatokhin Reviewed-by: Anup Patel --- include/sbi/sbi_ipi.h | 2 ++ lib/sbi/sbi_init.c | 6 ++++-- lib/sbi/sbi_ipi.c | 6 ++++++ 3 files changed, 12 insertions(+), 2 deletions(-) diff --git a/include/sbi/sbi_ipi.h b/include/sbi/sbi_ipi.h index f6ac8072f68..f384e748672 100644 --- a/include/sbi/sbi_ipi.h +++ b/include/sbi/sbi_ipi.h @@ -77,6 +77,8 @@ void sbi_ipi_process(void); int sbi_ipi_raw_send(u32 target_hart); +void sbi_ipi_raw_clear(u32 target_hart); + const struct sbi_ipi_device *sbi_ipi_get_device(void); void sbi_ipi_set_device(const struct sbi_ipi_device *dev); diff --git a/lib/sbi/sbi_init.c b/lib/sbi/sbi_init.c index dcca2c811e1..ffa214ca7ee 100644 --- a/lib/sbi/sbi_init.c +++ b/lib/sbi/sbi_init.c @@ -442,10 +442,12 @@ static void __noreturn init_warmboot(struct sbi_scratch *scratch, u32 hartid) if (hstate < 0) sbi_hart_hang(); - if (hstate == SBI_HSM_STATE_SUSPENDED) + if (hstate == SBI_HSM_STATE_SUSPENDED) { init_warm_resume(scratch, hartid); - else + } else { + sbi_ipi_raw_clear(hartid); init_warm_startup(scratch, hartid); + } } static atomic_t coldboot_lottery = ATOMIC_INITIALIZER(0); diff --git a/lib/sbi/sbi_ipi.c b/lib/sbi/sbi_ipi.c index 1bcc2e40c90..b9f62056cb6 100644 --- a/lib/sbi/sbi_ipi.c +++ b/lib/sbi/sbi_ipi.c @@ -217,6 +217,12 @@ int sbi_ipi_raw_send(u32 target_hart) return 0; } +void sbi_ipi_raw_clear(u32 target_hart) +{ + if (ipi_dev && ipi_dev->ipi_clear) + ipi_dev->ipi_clear(target_hart); +} + const struct sbi_ipi_device *sbi_ipi_get_device(void) { return ipi_dev; From ed88a63b90249c570c7f1f123e979f6f5faf657a Mon Sep 17 00:00:00 2001 From: Xiang W Date: Thu, 9 Mar 2023 18:35:28 +0800 Subject: [PATCH 092/187] lib: sbi_scratch: Optimize the alignment code for alloc size Signed-off-by: Xiang W Reviewed-by: Anup Patel --- lib/sbi/sbi_scratch.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/sbi/sbi_scratch.c b/lib/sbi/sbi_scratch.c index 87b34c6d4de..55ebdbb76a8 100644 --- a/lib/sbi/sbi_scratch.c +++ b/lib/sbi/sbi_scratch.c @@ -59,8 +59,8 @@ unsigned long sbi_scratch_alloc_offset(unsigned long size) if (!size) return 0; - if (size & (__SIZEOF_POINTER__ - 1)) - size = (size & ~(__SIZEOF_POINTER__ - 1)) + __SIZEOF_POINTER__; + size += __SIZEOF_POINTER__ - 1; + size &= ~((unsigned long)__SIZEOF_POINTER__ - 1); spin_lock(&extra_lock); From 73ab11dfb0bfaa2f7792cf10804c04c157dc2291 Mon Sep 17 00:00:00 2001 From: Xiang W Date: Thu, 16 Mar 2023 20:11:11 +0800 Subject: [PATCH 093/187] lib: sbi: Fix how to check whether the domain contains fw_region Because firmware is split into rw/rx segments, it cannot be recorded by a root_fw_region. This problem is solved by adding a flag fw_region_inited to sbi_domain. Signed-off-by: Xiang W Reviewed-by: Himanshu Chauhan Reviewed-by: Anup Patel --- include/sbi/sbi_domain.h | 2 ++ lib/sbi/sbi_domain.c | 30 +++++++++--------------------- lib/utils/fdt/fdt_domain.c | 1 + 3 files changed, 12 insertions(+), 21 deletions(-) diff --git a/include/sbi/sbi_domain.h b/include/sbi/sbi_domain.h index eaca7f09327..124ea90b9db 100644 --- a/include/sbi/sbi_domain.h +++ b/include/sbi/sbi_domain.h @@ -122,6 +122,8 @@ struct sbi_domain { bool system_reset_allowed; /** Is domain allowed to suspend the system */ bool system_suspend_allowed; + /** Identifies whether to include the firmware region */ + bool fw_region_inited; }; /** The root domain instance */ diff --git a/lib/sbi/sbi_domain.c b/lib/sbi/sbi_domain.c index 4d7b80a3ddd..67b87f3043c 100644 --- a/lib/sbi/sbi_domain.c +++ b/lib/sbi/sbi_domain.c @@ -30,7 +30,6 @@ static struct sbi_hartmask root_hmask = { 0 }; #define ROOT_REGION_MAX 16 static u32 root_memregs_count = 0; -static struct sbi_domain_memregion root_fw_region; static struct sbi_domain_memregion root_memregs[ROOT_REGION_MAX + 1] = { 0 }; struct sbi_domain root = { @@ -39,6 +38,7 @@ struct sbi_domain root = { .regions = root_memregs, .system_reset_allowed = true, .system_suspend_allowed = true, + .fw_region_inited = false, }; bool sbi_domain_is_assigned_hart(const struct sbi_domain *dom, u32 hartid) @@ -69,14 +69,6 @@ ulong sbi_domain_get_assigned_hartmask(const struct sbi_domain *dom, return ret; } -static void domain_memregion_initfw(struct sbi_domain_memregion *reg) -{ - if (!reg) - return; - - sbi_memcpy(reg, &root_fw_region, sizeof(*reg)); -} - void sbi_domain_memregion_init(unsigned long addr, unsigned long size, unsigned long flags, @@ -255,7 +247,6 @@ static int sanitize_domain(const struct sbi_platform *plat, struct sbi_domain *dom) { u32 i, j, count; - bool have_fw_reg; struct sbi_domain_memregion treg, *reg, *reg1; /* Check possible HARTs */ @@ -288,17 +279,13 @@ static int sanitize_domain(const struct sbi_platform *plat, } } - /* Count memory regions and check presence of firmware region */ + /* Count memory regions */ count = 0; - have_fw_reg = false; - sbi_domain_for_each_memregion(dom, reg) { - if (reg->order == root_fw_region.order && - reg->base == root_fw_region.base && - reg->flags == root_fw_region.flags) - have_fw_reg = true; + sbi_domain_for_each_memregion(dom, reg) count++; - } - if (!have_fw_reg) { + + /* Check presence of firmware regions */ + if (!dom->fw_region_inited) { sbi_printf("%s: %s does not have firmware region\n", __func__, dom->name); return SBI_EINVAL; @@ -732,8 +719,7 @@ int sbi_domain_init(struct sbi_scratch *scratch, u32 cold_hartid) sbi_domain_memregion_init(scratch->fw_start, scratch->fw_rw_offset, (SBI_DOMAIN_MEMREGION_M_READABLE | SBI_DOMAIN_MEMREGION_M_EXECUTABLE), - &root_fw_region); - domain_memregion_initfw(&root_memregs[root_memregs_count++]); + &root_memregs[root_memregs_count++]); sbi_domain_memregion_init((scratch->fw_start + scratch->fw_rw_offset), (scratch->fw_size - scratch->fw_rw_offset), @@ -741,6 +727,8 @@ int sbi_domain_init(struct sbi_scratch *scratch, u32 cold_hartid) SBI_DOMAIN_MEMREGION_M_WRITABLE), &root_memregs[root_memregs_count++]); + root.fw_region_inited = true; + /* Root domain allow everything memory region */ sbi_domain_memregion_init(0, ~0UL, (SBI_DOMAIN_MEMREGION_READABLE | diff --git a/lib/utils/fdt/fdt_domain.c b/lib/utils/fdt/fdt_domain.c index adcb94b6413..bb6d17d29fd 100644 --- a/lib/utils/fdt/fdt_domain.c +++ b/lib/utils/fdt/fdt_domain.c @@ -358,6 +358,7 @@ static int __fdt_parse_domain(void *fdt, int domain_offset, void *opaque) return SBI_EINVAL; memcpy(®ions[val32++], reg, sizeof(*reg)); } + dom->fw_region_inited = root.fw_region_inited; /* Read "boot-hart" DT property */ val32 = -1U; From f64dfcd2b5e78e9eea3fe3fee58e0632b5f81b99 Mon Sep 17 00:00:00 2001 From: Anup Patel Date: Mon, 20 Mar 2023 18:52:02 +0530 Subject: [PATCH 094/187] lib: sbi: Introduce sbi_entry_count() function We introduce sbi_entry_count() function which counts the number of times a HART enters OpenSBI via cold-boot or warm-boot path. Signed-off-by: Anup Patel --- include/sbi/sbi_init.h | 2 ++ lib/sbi/sbi_init.c | 42 +++++++++++++++++++++++++++++++++++------- 2 files changed, 37 insertions(+), 7 deletions(-) diff --git a/include/sbi/sbi_init.h b/include/sbi/sbi_init.h index 74eb1c07599..9640fee9143 100644 --- a/include/sbi/sbi_init.h +++ b/include/sbi/sbi_init.h @@ -16,6 +16,8 @@ struct sbi_scratch; void __noreturn sbi_init(struct sbi_scratch *scratch); +unsigned long sbi_entry_count(u32 hartid); + unsigned long sbi_init_count(u32 hartid); void __noreturn sbi_exit(struct sbi_scratch *scratch); diff --git a/lib/sbi/sbi_init.c b/lib/sbi/sbi_init.c index ffa214ca7ee..f184248d0a9 100644 --- a/lib/sbi/sbi_init.c +++ b/lib/sbi/sbi_init.c @@ -238,12 +238,13 @@ static void wake_coldboot_harts(struct sbi_scratch *scratch, u32 hartid) spin_unlock(&coldboot_lock); } +static unsigned long entry_count_offset; static unsigned long init_count_offset; static void __noreturn init_coldboot(struct sbi_scratch *scratch, u32 hartid) { int rc; - unsigned long *init_count; + unsigned long *count; const struct sbi_platform *plat = sbi_platform_ptr(scratch); /* Note: This has to be first thing in coldboot init sequence */ @@ -256,10 +257,17 @@ static void __noreturn init_coldboot(struct sbi_scratch *scratch, u32 hartid) if (rc) sbi_hart_hang(); + entry_count_offset = sbi_scratch_alloc_offset(__SIZEOF_POINTER__); + if (!entry_count_offset) + sbi_hart_hang(); + init_count_offset = sbi_scratch_alloc_offset(__SIZEOF_POINTER__); if (!init_count_offset) sbi_hart_hang(); + count = sbi_scratch_offset_ptr(scratch, entry_count_offset); + (*count)++; + rc = sbi_hsm_init(scratch, hartid, true); if (rc) sbi_hart_hang(); @@ -352,8 +360,8 @@ static void __noreturn init_coldboot(struct sbi_scratch *scratch, u32 hartid) wake_coldboot_harts(scratch, hartid); - init_count = sbi_scratch_offset_ptr(scratch, init_count_offset); - (*init_count)++; + count = sbi_scratch_offset_ptr(scratch, init_count_offset); + (*count)++; sbi_hsm_hart_start_finish(scratch, hartid); } @@ -362,12 +370,15 @@ static void __noreturn init_warm_startup(struct sbi_scratch *scratch, u32 hartid) { int rc; - unsigned long *init_count; + unsigned long *count; const struct sbi_platform *plat = sbi_platform_ptr(scratch); - if (!init_count_offset) + if (!entry_count_offset || !init_count_offset) sbi_hart_hang(); + count = sbi_scratch_offset_ptr(scratch, entry_count_offset); + (*count)++; + rc = sbi_hsm_init(scratch, hartid, false); if (rc) sbi_hart_hang(); @@ -408,8 +419,8 @@ static void __noreturn init_warm_startup(struct sbi_scratch *scratch, if (rc) sbi_hart_hang(); - init_count = sbi_scratch_offset_ptr(scratch, init_count_offset); - (*init_count)++; + count = sbi_scratch_offset_ptr(scratch, init_count_offset); + (*count)++; sbi_hsm_hart_start_finish(scratch, hartid); } @@ -521,6 +532,23 @@ void __noreturn sbi_init(struct sbi_scratch *scratch) init_warmboot(scratch, hartid); } +unsigned long sbi_entry_count(u32 hartid) +{ + struct sbi_scratch *scratch; + unsigned long *entry_count; + + if (!entry_count_offset) + return 0; + + scratch = sbi_hartid_to_scratch(hartid); + if (!scratch) + return 0; + + entry_count = sbi_scratch_offset_ptr(scratch, entry_count_offset); + + return *entry_count; +} + unsigned long sbi_init_count(u32 hartid) { struct sbi_scratch *scratch; From 30b9e7ee14498e5db805f471dbb23ea67c7a3b32 Mon Sep 17 00:00:00 2001 From: Anup Patel Date: Mon, 20 Mar 2023 18:58:54 +0530 Subject: [PATCH 095/187] lib: sbi_hsm: Fix sbi_hsm_hart_start() for platform with hart hotplug It possible that a platform supports hart hotplug (i.e. both hart_start and hart_stop callbacks available) and all harts are start simultaneously at platform boot-time. In this situation, the sbi_hsm_hart_start() will call hsm_device_hart_start() for secondary harts at platform boot-time which will fail because secondary harts were already started. To fix above, we call hsm_device_hart_start() from sbi_hsm_hart_start() only when entry_count is same as init_count for the secondary hart. Signed-off-by: Anup Patel --- lib/sbi/sbi_hsm.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/lib/sbi/sbi_hsm.c b/lib/sbi/sbi_hsm.c index 16e3846faef..b2614105096 100644 --- a/lib/sbi/sbi_hsm.c +++ b/lib/sbi/sbi_hsm.c @@ -301,7 +301,7 @@ int sbi_hsm_hart_start(struct sbi_scratch *scratch, const struct sbi_domain *dom, u32 hartid, ulong saddr, ulong smode, ulong arg1) { - unsigned long init_count; + unsigned long init_count, entry_count; unsigned int hstate; struct sbi_scratch *rscratch; struct sbi_hsm_data *hdata; @@ -325,6 +325,8 @@ int sbi_hsm_hart_start(struct sbi_scratch *scratch, return SBI_EINVAL; init_count = sbi_init_count(hartid); + entry_count = sbi_entry_count(hartid); + rscratch->next_arg1 = arg1; rscratch->next_addr = saddr; rscratch->next_mode = smode; @@ -350,7 +352,7 @@ int sbi_hsm_hart_start(struct sbi_scratch *scratch, goto err; } - if (hsm_device_has_hart_hotplug() || + if ((hsm_device_has_hart_hotplug() && (entry_count == init_count)) || (hsm_device_has_hart_secondary_boot() && !init_count)) { rc = hsm_device_hart_start(hartid, scratch->warmboot_addr); } else { From 8e90259da8b4b5bc6c934506cc4302578d44dbc2 Mon Sep 17 00:00:00 2001 From: Mayuresh Chitale Date: Sat, 25 Mar 2023 22:20:47 +0530 Subject: [PATCH 096/187] lib: sbi_hart: clear mip csr during hart init If mip.SEIP bit is not cleared then on HiFive Unmatched board it causes spurious external interrupts. This breaks the boot up of HiFive Unmatched board. Hence it is required to bring the mip CSR to a known state during hart init and avoid spurious interrupts. Fixes: d9e7368 ("firmware: Not to clear all the MIP") Signed-off-by: Mayuresh Chitale Reviewed-by: Anup Patel --- firmware/fw_base.S | 7 ------- lib/sbi/sbi_hart.c | 6 ++++++ 2 files changed, 6 insertions(+), 7 deletions(-) diff --git a/firmware/fw_base.S b/firmware/fw_base.S index ceef44f26b1..5a3e89485a8 100644 --- a/firmware/fw_base.S +++ b/firmware/fw_base.S @@ -430,13 +430,6 @@ _start_warm: /* Disable all interrupts */ csrw CSR_MIE, zero - /* - * Only clear the MIP_SSIP and MIP_STIP. For the platform like QEMU, - * If we clear other interrupts like MIP_SEIP and the pendings of - * PLIC still exist, the QEMU may not set it back immediately. - */ - li t0, (MIP_SSIP | MIP_STIP) - csrc CSR_MIP, t0 /* Find HART count and HART stack size */ lla a4, platform diff --git a/lib/sbi/sbi_hart.c b/lib/sbi/sbi_hart.c index 5e06918c7a4..6e52cbd76d8 100644 --- a/lib/sbi/sbi_hart.c +++ b/lib/sbi/sbi_hart.c @@ -733,6 +733,12 @@ int sbi_hart_init(struct sbi_scratch *scratch, bool cold_boot) { int rc; + /* + * Clear mip CSR before proceeding with init to avoid any spurious + * external interrupts in S-mode. + */ + csr_write(CSR_MIP, 0); + if (cold_boot) { if (misa_extension('H')) sbi_hart_expected_trap = &__sbi_expected_trap_hext; From 45ba2b203cc38ebfd634dc42c1dd3a2d380a8899 Mon Sep 17 00:00:00 2001 From: Sunil V L Date: Wed, 29 Mar 2023 14:27:25 +0530 Subject: [PATCH 097/187] include: Add defines for SBI CPPC extension Add SBI CPPC extension related defines to the SBI ecall interface header. Signed-off-by: Sunil V L Reviewed-by: Andrew Jones Reviewed-by: Anup Patel --- include/sbi/sbi_ecall_interface.h | 34 +++++++++++++++++++++++++++++++ 1 file changed, 34 insertions(+) diff --git a/include/sbi/sbi_ecall_interface.h b/include/sbi/sbi_ecall_interface.h index 459735807f1..dee2dd9681c 100644 --- a/include/sbi/sbi_ecall_interface.h +++ b/include/sbi/sbi_ecall_interface.h @@ -31,6 +31,7 @@ #define SBI_EXT_PMU 0x504D55 #define SBI_EXT_DBCN 0x4442434E #define SBI_EXT_SUSP 0x53555350 +#define SBI_EXT_CPPC 0x43505043 /* SBI function IDs for BASE extension*/ #define SBI_EXT_BASE_GET_SPEC_VERSION 0x0 @@ -256,6 +257,39 @@ enum sbi_pmu_ctr_type { #define SBI_SUSP_SLEEP_TYPE_LAST SBI_SUSP_SLEEP_TYPE_SUSPEND #define SBI_SUSP_PLATFORM_SLEEP_START 0x80000000 +/* SBI function IDs for CPPC extension */ +#define SBI_EXT_CPPC_PROBE 0x0 +#define SBI_EXT_CPPC_READ 0x1 +#define SBI_EXT_CPPC_READ_HI 0x2 +#define SBI_EXT_CPPC_WRITE 0x3 + +enum sbi_cppc_reg_id { + SBI_CPPC_HIGHEST_PERF = 0x00000000, + SBI_CPPC_NOMINAL_PERF = 0x00000001, + SBI_CPPC_LOW_NON_LINEAR_PERF = 0x00000002, + SBI_CPPC_LOWEST_PERF = 0x00000003, + SBI_CPPC_GUARANTEED_PERF = 0x00000004, + SBI_CPPC_DESIRED_PERF = 0x00000005, + SBI_CPPC_MIN_PERF = 0x00000006, + SBI_CPPC_MAX_PERF = 0x00000007, + SBI_CPPC_PERF_REDUC_TOLERANCE = 0x00000008, + SBI_CPPC_TIME_WINDOW = 0x00000009, + SBI_CPPC_CTR_WRAP_TIME = 0x0000000A, + SBI_CPPC_REFERENCE_CTR = 0x0000000B, + SBI_CPPC_DELIVERED_CTR = 0x0000000C, + SBI_CPPC_PERF_LIMITED = 0x0000000D, + SBI_CPPC_ENABLE = 0x0000000E, + SBI_CPPC_AUTO_SEL_ENABLE = 0x0000000F, + SBI_CPPC_AUTO_ACT_WINDOW = 0x00000010, + SBI_CPPC_ENERGY_PERF_PREFERENCE = 0x00000011, + SBI_CPPC_REFERENCE_PERF = 0x00000012, + SBI_CPPC_LOWEST_FREQ = 0x00000013, + SBI_CPPC_NOMINAL_FREQ = 0x00000014, + SBI_CPPC_ACPI_LAST = SBI_CPPC_NOMINAL_FREQ, + SBI_CPPC_TRANSITION_LATENCY = 0x80000000, + SBI_CPPC_NON_ACPI_LAST = SBI_CPPC_TRANSITION_LATENCY, +}; + /* SBI base specification related macros */ #define SBI_SPEC_VERSION_MAJOR_OFFSET 24 #define SBI_SPEC_VERSION_MAJOR_MASK 0x7f From 33caae8069f4205861445f58095bcecb814be881 Mon Sep 17 00:00:00 2001 From: Sunil V L Date: Wed, 29 Mar 2023 14:27:26 +0530 Subject: [PATCH 098/187] lib: sbi: Implement SBI CPPC extension Implement SBI CPPC extension. This extension is only available when OpenSBI platform provides a CPPC device to generic library. Signed-off-by: Sunil V L Reviewed-by: Andrew Jones Reviewed-by: Anup Patel --- include/sbi/sbi_cppc.h | 35 +++++++++++++ lib/sbi/Kconfig | 4 ++ lib/sbi/objects.mk | 4 ++ lib/sbi/sbi_cppc.c | 110 +++++++++++++++++++++++++++++++++++++++ lib/sbi/sbi_ecall_cppc.c | 63 ++++++++++++++++++++++ 5 files changed, 216 insertions(+) create mode 100644 include/sbi/sbi_cppc.h create mode 100644 lib/sbi/sbi_cppc.c create mode 100644 lib/sbi/sbi_ecall_cppc.c diff --git a/include/sbi/sbi_cppc.h b/include/sbi/sbi_cppc.h new file mode 100644 index 00000000000..edf73f52ac0 --- /dev/null +++ b/include/sbi/sbi_cppc.h @@ -0,0 +1,35 @@ +/* + * SPDX-License-Identifier: BSD-2-Clause + * + * Copyright (c) 2023 Ventana Micro Systems Inc. + * + */ + +#ifndef __SBI_CPPC_H__ +#define __SBI_CPPC_H__ + +#include + +/** CPPC device */ +struct sbi_cppc_device { + /** Name of the CPPC device */ + char name[32]; + + /** probe - returns register width if implemented, 0 otherwise */ + int (*cppc_probe)(unsigned long reg); + + /** read the cppc register*/ + int (*cppc_read)(unsigned long reg, uint64_t *val); + + /** write to the cppc register*/ + int (*cppc_write)(unsigned long reg, uint64_t val); +}; + +int sbi_cppc_probe(unsigned long reg); +int sbi_cppc_read(unsigned long reg, uint64_t *val); +int sbi_cppc_write(unsigned long reg, uint64_t val); + +const struct sbi_cppc_device *sbi_cppc_get_device(void); +void sbi_cppc_set_device(const struct sbi_cppc_device *dev); + +#endif diff --git a/lib/sbi/Kconfig b/lib/sbi/Kconfig index 7eb3273d546..477775e21ea 100644 --- a/lib/sbi/Kconfig +++ b/lib/sbi/Kconfig @@ -34,6 +34,10 @@ config SBI_ECALL_DBCN bool "Debug Console extension" default y +config SBI_ECALL_CPPC + bool "CPPC extension" + default y + config SBI_ECALL_LEGACY bool "SBI v0.1 legacy extensions" default y diff --git a/lib/sbi/objects.mk b/lib/sbi/objects.mk index 770238b25fa..7d691c61f0e 100644 --- a/lib/sbi/objects.mk +++ b/lib/sbi/objects.mk @@ -43,6 +43,9 @@ libsbi-objs-$(CONFIG_SBI_ECALL_PMU) += sbi_ecall_pmu.o carray-sbi_ecall_exts-$(CONFIG_SBI_ECALL_DBCN) += ecall_dbcn libsbi-objs-$(CONFIG_SBI_ECALL_DBCN) += sbi_ecall_dbcn.o +carray-sbi_ecall_exts-$(CONFIG_SBI_ECALL_CPPC) += ecall_cppc +libsbi-objs-$(CONFIG_SBI_ECALL_CPPC) += sbi_ecall_cppc.o + carray-sbi_ecall_exts-$(CONFIG_SBI_ECALL_LEGACY) += ecall_legacy libsbi-objs-$(CONFIG_SBI_ECALL_LEGACY) += sbi_ecall_legacy.o @@ -74,3 +77,4 @@ libsbi-objs-y += sbi_tlb.o libsbi-objs-y += sbi_trap.o libsbi-objs-y += sbi_unpriv.o libsbi-objs-y += sbi_expected_trap.o +libsbi-objs-y += sbi_cppc.o diff --git a/lib/sbi/sbi_cppc.c b/lib/sbi/sbi_cppc.c new file mode 100644 index 00000000000..afb60b332c2 --- /dev/null +++ b/lib/sbi/sbi_cppc.c @@ -0,0 +1,110 @@ +/* + * SPDX-License-Identifier: BSD-2-Clause + * + * Copyright (c) 2023 Ventana Micro Systems Inc. + * + */ + +#include +#include + +static const struct sbi_cppc_device *cppc_dev = NULL; + +const struct sbi_cppc_device *sbi_cppc_get_device(void) +{ + return cppc_dev; +} + +void sbi_cppc_set_device(const struct sbi_cppc_device *dev) +{ + if (!dev || cppc_dev) + return; + + cppc_dev = dev; +} + +static bool sbi_cppc_is_reserved(unsigned long reg) +{ + if ((reg > SBI_CPPC_ACPI_LAST && reg < SBI_CPPC_TRANSITION_LATENCY) || + reg > SBI_CPPC_NON_ACPI_LAST) + return true; + + return false; +} + +static bool sbi_cppc_readable(unsigned long reg) +{ + /* there are no write-only cppc registers currently */ + return true; +} + +static bool sbi_cppc_writable(unsigned long reg) +{ + switch (reg) { + case SBI_CPPC_HIGHEST_PERF: + case SBI_CPPC_NOMINAL_PERF: + case SBI_CPPC_LOW_NON_LINEAR_PERF: + case SBI_CPPC_LOWEST_PERF: + case SBI_CPPC_GUARANTEED_PERF: + case SBI_CPPC_CTR_WRAP_TIME: + case SBI_CPPC_REFERENCE_CTR: + case SBI_CPPC_DELIVERED_CTR: + case SBI_CPPC_REFERENCE_PERF: + case SBI_CPPC_LOWEST_FREQ: + case SBI_CPPC_NOMINAL_FREQ: + case SBI_CPPC_TRANSITION_LATENCY: + return false; + } + + return true; +} + +int sbi_cppc_probe(unsigned long reg) +{ + if (!cppc_dev || !cppc_dev->cppc_probe) + return SBI_EFAIL; + + /* Check whether register is reserved */ + if (sbi_cppc_is_reserved(reg)) + return SBI_ERR_INVALID_PARAM; + + return cppc_dev->cppc_probe(reg); +} + +int sbi_cppc_read(unsigned long reg, uint64_t *val) +{ + int ret; + + if (!cppc_dev || !cppc_dev->cppc_read) + return SBI_EFAIL; + + /* Check whether register is implemented */ + ret = sbi_cppc_probe(reg); + if (ret <= 0) + return SBI_ERR_NOT_SUPPORTED; + + /* Check whether the register is write-only */ + if (!sbi_cppc_readable(reg)) + return SBI_ERR_DENIED; + + return cppc_dev->cppc_read(reg, val); +} + +int sbi_cppc_write(unsigned long reg, uint64_t val) +{ + int ret; + + if (!cppc_dev || !cppc_dev->cppc_write) + return SBI_EFAIL; + + /* Check whether register is implemented */ + ret = sbi_cppc_probe(reg); + if (ret <= 0) + return SBI_ERR_NOT_SUPPORTED; + + /* Check whether the register is read-only */ + if (!sbi_cppc_writable(reg)) + return SBI_ERR_DENIED; + + return cppc_dev->cppc_write(reg, val); +} diff --git a/lib/sbi/sbi_ecall_cppc.c b/lib/sbi/sbi_ecall_cppc.c new file mode 100644 index 00000000000..91585f3b74e --- /dev/null +++ b/lib/sbi/sbi_ecall_cppc.c @@ -0,0 +1,63 @@ +/* + * SPDX-License-Identifier: BSD-2-Clause + * + * Copyright (c) 2023 Ventana Micro Systems Inc. + * + */ + +#include +#include +#include +#include +#include + +static int sbi_ecall_cppc_handler(unsigned long extid, unsigned long funcid, + const struct sbi_trap_regs *regs, + unsigned long *out_val, + struct sbi_trap_info *out_trap) +{ + int ret = 0; + uint64_t temp; + + switch (funcid) { + case SBI_EXT_CPPC_READ: + ret = sbi_cppc_read(regs->a0, &temp); + *out_val = temp; + break; + case SBI_EXT_CPPC_READ_HI: +#if __riscv_xlen == 32 + ret = sbi_cppc_read(regs->a0, &temp); + *out_val = temp >> 32; +#else + *out_val = 0; +#endif + break; + case SBI_EXT_CPPC_WRITE: + ret = sbi_cppc_write(regs->a0, regs->a1); + break; + case SBI_EXT_CPPC_PROBE: + ret = sbi_cppc_probe(regs->a0); + if (ret >= 0) { + *out_val = ret; + ret = 0; + } + break; + default: + ret = SBI_ENOTSUPP; + } + + return ret; +} + +static int sbi_ecall_cppc_probe(unsigned long extid, unsigned long *out_val) +{ + *out_val = sbi_cppc_get_device() ? 1 : 0; + return 0; +} + +struct sbi_ecall_extension ecall_cppc = { + .extid_start = SBI_EXT_CPPC, + .extid_end = SBI_EXT_CPPC, + .handle = sbi_ecall_cppc_handler, + .probe = sbi_ecall_cppc_probe, +}; From 91767d093bf76c169c61194dd3ea7bbec1fc13f6 Mon Sep 17 00:00:00 2001 From: Sunil V L Date: Wed, 29 Mar 2023 14:27:27 +0530 Subject: [PATCH 099/187] lib: sbi: Print the CPPC device name If CPPC device is registered by the platform, print its name. Signed-off-by: Sunil V L Reviewed-by: Andrew Jones Reviewed-by: Anup Patel --- lib/sbi/sbi_init.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/lib/sbi/sbi_init.c b/lib/sbi/sbi_init.c index f184248d0a9..a0313367117 100644 --- a/lib/sbi/sbi_init.c +++ b/lib/sbi/sbi_init.c @@ -12,6 +12,7 @@ #include #include #include +#include #include #include #include @@ -70,6 +71,7 @@ static void sbi_boot_print_general(struct sbi_scratch *scratch) const struct sbi_console_device *cdev; const struct sbi_system_reset_device *srdev; const struct sbi_system_suspend_device *susp_dev; + const struct sbi_cppc_device *cppc_dev; const struct sbi_platform *plat = sbi_platform_ptr(scratch); if (scratch->options & SBI_SCRATCH_NO_BOOT_PRINTS) @@ -107,6 +109,9 @@ static void sbi_boot_print_general(struct sbi_scratch *scratch) susp_dev = sbi_system_suspend_get_device(); sbi_printf("Platform Suspend Device : %s\n", (susp_dev) ? susp_dev->name : "---"); + cppc_dev = sbi_cppc_get_device(); + sbi_printf("Platform CPPC Device : %s\n", + (cppc_dev) ? cppc_dev->name : "---"); /* Firmware details */ sbi_printf("Firmware Base : 0x%lx\n", scratch->fw_start); From edc9914392791031df624a7c79d1706f83199666 Mon Sep 17 00:00:00 2001 From: Yu Chien Peter Lin Date: Thu, 30 Mar 2023 16:41:14 +0800 Subject: [PATCH 100/187] lib: sbi_pmu: Align the event type offset as per SBI specification The bits encoded in event_idx[19:16] indicate the event type, with an offset of 16 instead of 20. Fixes: 13d40f21d588 ("lib: sbi: Add PMU support") Signed-off-by: Yu Chien Peter Lin Reviewed-by: Andrew Jones Reviewed-by: Xiang W --- include/sbi/sbi_ecall_interface.h | 4 ++-- lib/sbi/sbi_pmu.c | 7 ++++--- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/include/sbi/sbi_ecall_interface.h b/include/sbi/sbi_ecall_interface.h index dee2dd9681c..1fe469e3707 100644 --- a/include/sbi/sbi_ecall_interface.h +++ b/include/sbi/sbi_ecall_interface.h @@ -215,10 +215,10 @@ enum sbi_pmu_ctr_type { }; /* Helper macros to decode event idx */ -#define SBI_PMU_EVENT_IDX_OFFSET 20 #define SBI_PMU_EVENT_IDX_MASK 0xFFFFF +#define SBI_PMU_EVENT_IDX_TYPE_OFFSET 16 +#define SBI_PMU_EVENT_IDX_TYPE_MASK (0xF << SBI_PMU_EVENT_IDX_TYPE_OFFSET) #define SBI_PMU_EVENT_IDX_CODE_MASK 0xFFFF -#define SBI_PMU_EVENT_IDX_TYPE_MASK 0xF0000 #define SBI_PMU_EVENT_RAW_IDX 0x20000 #define SBI_PMU_EVENT_IDX_INVALID 0xFFFFFFFF diff --git a/lib/sbi/sbi_pmu.c b/lib/sbi/sbi_pmu.c index 74d69122efb..04259aeb24e 100644 --- a/lib/sbi/sbi_pmu.c +++ b/lib/sbi/sbi_pmu.c @@ -81,7 +81,8 @@ static uint32_t num_hw_ctrs; static uint32_t total_ctrs; /* Helper macros to retrieve event idx and code type */ -#define get_cidx_type(x) ((x & SBI_PMU_EVENT_IDX_TYPE_MASK) >> 16) +#define get_cidx_type(x) \ + (((x) & SBI_PMU_EVENT_IDX_TYPE_MASK) >> SBI_PMU_EVENT_IDX_TYPE_OFFSET) #define get_cidx_code(x) (x & SBI_PMU_EVENT_IDX_CODE_MASK) /** @@ -903,10 +904,10 @@ int sbi_pmu_init(struct sbi_scratch *scratch, bool cold_boot) pmu_reset_event_map(hartid); /* First three counters are fixed by the priv spec and we enable it by default */ - active_events[hartid][0] = SBI_PMU_EVENT_TYPE_HW << SBI_PMU_EVENT_IDX_OFFSET | + active_events[hartid][0] = SBI_PMU_EVENT_TYPE_HW << SBI_PMU_EVENT_IDX_TYPE_OFFSET | SBI_PMU_HW_CPU_CYCLES; active_events[hartid][1] = SBI_PMU_EVENT_IDX_INVALID; - active_events[hartid][2] = SBI_PMU_EVENT_TYPE_HW << SBI_PMU_EVENT_IDX_OFFSET | + active_events[hartid][2] = SBI_PMU_EVENT_TYPE_HW << SBI_PMU_EVENT_IDX_TYPE_OFFSET | SBI_PMU_HW_INSTRUCTIONS; return 0; From ee016a7bb098578a5d0d4bde01259fe3cd57b02f Mon Sep 17 00:00:00 2001 From: Gabriel Somlo Date: Thu, 30 Mar 2023 16:25:30 -0400 Subject: [PATCH 101/187] docs: Correct FW_JUMP_FDT_ADDR calculation example When using `PLATFORM=generic` defaults, the kernel is loaded at `FW_JUMP_ADDR`, and the FDT is loaded at `FW_JUMP_FDT_ADDR. Therefore, the maximum kernel size before `FW_JUMP_FDT_ADDR` must be increased is `$(( FW_JUMP_FDT_ADDR - FW_JUMP_ADDR ))`. The example calculation assumes `rv64`, and is wrong to boot (off by 0x200000). Fix it and update it for the general case. Signed-off-by: Gabriel Somlo Reviewed-by: Andrew Jones Reviewed-by: Xiang W --- docs/firmware/fw_jump.md | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/docs/firmware/fw_jump.md b/docs/firmware/fw_jump.md index 956897e7e7c..3e883fa814f 100644 --- a/docs/firmware/fw_jump.md +++ b/docs/firmware/fw_jump.md @@ -43,18 +43,18 @@ follows: When using the default *FW_JUMP_FDT_ADDR* with *PLATFORM=generic*, you must ensure *FW_JUMP_FDT_ADDR* is set high enough to avoid overwriting the kernel. - You can use the following method. + You can use the following method (e.g., using bash or zsh): ``` - ${CROSS_COMPILE}objdump -h $KERNEL_ELF | sort -k 5,5 | awk -n '/^ +[0-9]+ /\ - {addr="0x"$3; size="0x"$5; printf "0x""%x\n",addr+size}' \ - | (( `tail -1` > 0x2200000 )) && echo fdt overlaps kernel,\ - increase FW_JUMP_FDT_ADDR - - ${LLVM}objdump -h --show-lma $KERNEL_ELF | sort -k 5,5 | \ - awk -n '/^ +[0-9]+ / {addr="0x"$3; size="0x"$5; printf "0x""%x\n",addr+size}'\ - | (( `tail -1` > 0x2200000 )) && echo fdt overlaps kernel,\ - increase FW_JUMP_FDT_ADDR + ${CROSS_COMPILE}objdump -h $KERNEL_ELF | sort -k 5,5 | awk -n ' + /^ +[0-9]+ / {addr="0x"$3; size="0x"$5; printf "0x""%x\n",addr+size}' | + (( `tail -1` > (FW_JUMP_FDT_ADDR - FW_JUMP_ADDR) )) && + echo fdt overlaps kernel, increase FW_JUMP_FDT_ADDR + + ${LLVM}objdump -h --show-lma $KERNEL_ELF | sort -k 5,5 | awk -n ' + /^ +[0-9]+ / {addr="0x"$3; size="0x"$5; printf "0x""%x\n",addr+size}' | + (( `tail -1` > (FW_JUMP_FDT_ADDR - FW_JUMP_ADDR) )) && + echo fdt overlaps kernel, increase FW_JUMP_FDT_ADDR ``` *FW_JUMP* Example From 2868f26131308ff345382084681ea89c5b0159f1 Mon Sep 17 00:00:00 2001 From: Heinrich Schuchardt Date: Fri, 31 Mar 2023 15:15:15 +0200 Subject: [PATCH 102/187] lib: utils: fdt_fixup: avoid buffer overrun fdt_reserved_memory_fixup() uses filtered_order[PMP_COUNT]. The index must not reach PMP_COUNT. Fixes: 199189bd1c17 ("lib: utils: Mark only the largest region as reserved in FDT") Addresses-Coverity-ID: 1536994 ("Out-of-bounds write") Signed-off-by: Heinrich Schuchardt Reviewed-by: Xiang W Reviewed-by: Anup Patel --- lib/utils/fdt/fdt_fixup.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/utils/fdt/fdt_fixup.c b/lib/utils/fdt/fdt_fixup.c index c10179b900c..ae6be008579 100644 --- a/lib/utils/fdt/fdt_fixup.c +++ b/lib/utils/fdt/fdt_fixup.c @@ -355,7 +355,7 @@ int fdt_reserved_memory_fixup(void *fdt) if (reg->flags & SBI_DOMAIN_MEMREGION_SU_EXECUTABLE) continue; - if (i > PMP_COUNT) { + if (i >= PMP_COUNT) { sbi_printf("%s: Too many memory regions to fixup.\n", __func__); return SBI_ENOSPC; From 66fa925353a133173e4f51a5ba247ee3e1a5943c Mon Sep 17 00:00:00 2001 From: Xiang W Date: Tue, 11 Apr 2023 12:56:18 +0800 Subject: [PATCH 103/187] lib: sbi: Optimize sbi_tlb Originally, the process and sync of sbi_tlb need to wait for each other. Evasion by atomic addition and subtraction. Signed-off-by: Xiang W Reviewed-by: Anup Patel Tested-by: Anup Patel --- lib/sbi/sbi_tlb.c | 21 +++++++++++---------- 1 file changed, 11 insertions(+), 10 deletions(-) diff --git a/lib/sbi/sbi_tlb.c b/lib/sbi/sbi_tlb.c index 4c142ea3e66..d950c4520ae 100644 --- a/lib/sbi/sbi_tlb.c +++ b/lib/sbi/sbi_tlb.c @@ -215,7 +215,7 @@ static void tlb_entry_process(struct sbi_tlb_info *tinfo) { u32 rhartid; struct sbi_scratch *rscratch = NULL; - unsigned long *rtlb_sync = NULL; + atomic_t *rtlb_sync = NULL; tinfo->local_fn(tinfo); @@ -225,7 +225,7 @@ static void tlb_entry_process(struct sbi_tlb_info *tinfo) continue; rtlb_sync = sbi_scratch_offset_ptr(rscratch, tlb_sync_off); - while (atomic_raw_xchg_ulong(rtlb_sync, 1)) ; + atomic_sub_return(rtlb_sync, 1); } } @@ -257,10 +257,10 @@ static void tlb_process(struct sbi_scratch *scratch) static void tlb_sync(struct sbi_scratch *scratch) { - unsigned long *tlb_sync = + atomic_t *tlb_sync = sbi_scratch_offset_ptr(scratch, tlb_sync_off); - while (!atomic_raw_xchg_ulong(tlb_sync, 0)) { + while (atomic_read(tlb_sync) > 0) { /* * While we are waiting for remote hart to set the sync, * consume fifo requests to avoid deadlock. @@ -343,6 +343,7 @@ static int tlb_update(struct sbi_scratch *scratch, u32 remote_hartid, void *data) { int ret; + atomic_t *tlb_sync; struct sbi_fifo *tlb_fifo_r; struct sbi_tlb_info *tinfo = data; u32 curr_hartid = current_hartid(); @@ -369,11 +370,8 @@ static int tlb_update(struct sbi_scratch *scratch, tlb_fifo_r = sbi_scratch_offset_ptr(remote_scratch, tlb_fifo_off); ret = sbi_fifo_inplace_update(tlb_fifo_r, data, tlb_update_cb); - if (ret != SBI_FIFO_UNCHANGED) { - return 1; - } - while (sbi_fifo_enqueue(tlb_fifo_r, data) < 0) { + while (ret == SBI_FIFO_UNCHANGED && sbi_fifo_enqueue(tlb_fifo_r, data) < 0) { /** * For now, Busy loop until there is space in the fifo. * There may be case where target hart is also @@ -387,6 +385,9 @@ static int tlb_update(struct sbi_scratch *scratch, curr_hartid, remote_hartid); } + tlb_sync = sbi_scratch_offset_ptr(scratch, tlb_sync_off); + atomic_add_return(tlb_sync, 1); + return 0; } @@ -413,7 +414,7 @@ int sbi_tlb_init(struct sbi_scratch *scratch, bool cold_boot) { int ret; void *tlb_mem; - unsigned long *tlb_sync; + atomic_t *tlb_sync; struct sbi_fifo *tlb_q; const struct sbi_platform *plat = sbi_platform_ptr(scratch); @@ -455,7 +456,7 @@ int sbi_tlb_init(struct sbi_scratch *scratch, bool cold_boot) tlb_q = sbi_scratch_offset_ptr(scratch, tlb_fifo_off); tlb_mem = sbi_scratch_offset_ptr(scratch, tlb_fifo_mem_off); - *tlb_sync = 0; + ATOMIC_INIT(tlb_sync, 0); sbi_fifo_init(tlb_q, tlb_mem, SBI_TLB_FIFO_NUM_ENTRIES, SBI_TLB_INFO_SIZE); From 24dde46b8df0830174580919d49c21160d7d9fce Mon Sep 17 00:00:00 2001 From: Xiang W Date: Tue, 11 Apr 2023 12:56:19 +0800 Subject: [PATCH 104/187] lib: sbi: Optimize sbi_ipi The original sbi_ipi will be processed by hart by hart, after optimization, send ipi first and finally wait together. Signed-off-by: Xiang W Reviewed-by: Anup Patel Tested-by: Anup Patel --- lib/sbi/sbi_ipi.c | 34 ++++++++++++++++++++++++++++++++-- 1 file changed, 32 insertions(+), 2 deletions(-) diff --git a/lib/sbi/sbi_ipi.c b/lib/sbi/sbi_ipi.c index b9f62056cb6..24d8a93a0b9 100644 --- a/lib/sbi/sbi_ipi.c +++ b/lib/sbi/sbi_ipi.c @@ -69,6 +69,18 @@ static int sbi_ipi_send(struct sbi_scratch *scratch, u32 remote_hartid, sbi_pmu_ctr_incr_fw(SBI_PMU_FW_IPI_SENT); + return 0; +} + +static int sbi_ipi_sync(struct sbi_scratch *scratch, u32 event) +{ + const struct sbi_ipi_event_ops *ipi_ops; + + if ((SBI_IPI_EVENT_MAX <= event) || + !ipi_ops_array[event]) + return SBI_EINVAL; + ipi_ops = ipi_ops_array[event]; + if (ipi_ops->sync) ipi_ops->sync(scratch); @@ -83,7 +95,7 @@ static int sbi_ipi_send(struct sbi_scratch *scratch, u32 remote_hartid, int sbi_ipi_send_many(ulong hmask, ulong hbase, u32 event, void *data) { int rc; - ulong i, m; + ulong i, m, n; struct sbi_domain *dom = sbi_domain_thishart_ptr(); struct sbi_scratch *scratch = sbi_scratch_thishart_ptr(); @@ -92,22 +104,40 @@ int sbi_ipi_send_many(ulong hmask, ulong hbase, u32 event, void *data) if (rc) return rc; m &= hmask; + n = m; /* Send IPIs */ for (i = hbase; m; i++, m >>= 1) { if (m & 1UL) sbi_ipi_send(scratch, i, event, data); } + + /* Sync IPIs */ + m = n; + for (i = hbase; m; i++, m >>= 1) { + if (m & 1UL) + sbi_ipi_sync(scratch, event); + } } else { + /* Send IPIs */ hbase = 0; while (!sbi_hsm_hart_interruptible_mask(dom, hbase, &m)) { - /* Send IPIs */ for (i = hbase; m; i++, m >>= 1) { if (m & 1UL) sbi_ipi_send(scratch, i, event, data); } hbase += BITS_PER_LONG; } + + /* Sync IPIs */ + hbase = 0; + while (!sbi_hsm_hart_interruptible_mask(dom, hbase, &m)) { + for (i = hbase; m; i++, m >>= 1) { + if (m & 1UL) + sbi_ipi_sync(scratch, event); + } + hbase += BITS_PER_LONG; + } } return 0; From 80078ab088c34aafce52f0c0d4d1e367da146b9c Mon Sep 17 00:00:00 2001 From: Xiang W Date: Tue, 11 Apr 2023 12:56:20 +0800 Subject: [PATCH 105/187] sbi: tlb: Simplify to tlb_process_count/tlb_process function tlb_process_count is only used when count=1, so refactor to tlb_process_once and add the return value to be reused in tlb_process Signed-off-by: Xiang W Reviewed-by: Anup Patel Tested-by: Anup Patel --- lib/sbi/sbi_tlb.c | 23 ++++++++--------------- 1 file changed, 8 insertions(+), 15 deletions(-) diff --git a/lib/sbi/sbi_tlb.c b/lib/sbi/sbi_tlb.c index d950c4520ae..60ca8c6f089 100644 --- a/lib/sbi/sbi_tlb.c +++ b/lib/sbi/sbi_tlb.c @@ -229,30 +229,23 @@ static void tlb_entry_process(struct sbi_tlb_info *tinfo) } } -static void tlb_process_count(struct sbi_scratch *scratch, int count) +static bool tlb_process_once(struct sbi_scratch *scratch) { struct sbi_tlb_info tinfo; - unsigned int deq_count = 0; struct sbi_fifo *tlb_fifo = sbi_scratch_offset_ptr(scratch, tlb_fifo_off); - while (!sbi_fifo_dequeue(tlb_fifo, &tinfo)) { + if (!sbi_fifo_dequeue(tlb_fifo, &tinfo)) { tlb_entry_process(&tinfo); - deq_count++; - if (deq_count > count) - break; - + return true; } + + return false; } static void tlb_process(struct sbi_scratch *scratch) { - struct sbi_tlb_info tinfo; - struct sbi_fifo *tlb_fifo = - sbi_scratch_offset_ptr(scratch, tlb_fifo_off); - - while (!sbi_fifo_dequeue(tlb_fifo, &tinfo)) - tlb_entry_process(&tinfo); + while (tlb_process_once(scratch)); } static void tlb_sync(struct sbi_scratch *scratch) @@ -265,7 +258,7 @@ static void tlb_sync(struct sbi_scratch *scratch) * While we are waiting for remote hart to set the sync, * consume fifo requests to avoid deadlock. */ - tlb_process_count(scratch, 1); + tlb_process_once(scratch); } return; @@ -380,7 +373,7 @@ static int tlb_update(struct sbi_scratch *scratch, * TODO: Introduce a wait/wakeup event mechanism to handle * this properly. */ - tlb_process_count(scratch, 1); + tlb_process_once(scratch); sbi_dprintf("hart%d: hart%d tlb fifo full\n", curr_hartid, remote_hartid); } From bf40e07f6f24a9c3ed08cfeb730d4e62ba3e215b Mon Sep 17 00:00:00 2001 From: Xiang W Date: Fri, 14 Apr 2023 09:32:47 +0800 Subject: [PATCH 106/187] lib: sbi: Optimize sbi_tlb queue waiting When tlb_fifo is full, it will wait and affect the ipi update to other harts. This patch is optimized. Signed-off-by: Xiang W Reviewed-by: Anup Patel Tested-by: Anup Patel --- include/sbi/sbi_ipi.h | 10 ++++++++++ lib/sbi/sbi_ipi.c | 44 +++++++++++++++++++++---------------------- lib/sbi/sbi_tlb.c | 7 ++++--- 3 files changed, 35 insertions(+), 26 deletions(-) diff --git a/include/sbi/sbi_ipi.h b/include/sbi/sbi_ipi.h index f384e748672..c64f422c030 100644 --- a/include/sbi/sbi_ipi.h +++ b/include/sbi/sbi_ipi.h @@ -30,6 +30,12 @@ struct sbi_ipi_device { void (*ipi_clear)(u32 target_hart); }; +enum sbi_ipi_update_type { + SBI_IPI_UPDATE_SUCCESS, + SBI_IPI_UPDATE_BREAK, + SBI_IPI_UPDATE_RETRY, +}; + struct sbi_scratch; /** IPI event operations or callbacks */ @@ -41,6 +47,10 @@ struct sbi_ipi_event_ops { * Update callback to save/enqueue data for remote HART * Note: This is an optional callback and it is called just before * triggering IPI to remote HART. + * @return < 0, error or failure + * @return SBI_IPI_UPDATE_SUCCESS, success + * @return SBI_IPI_UPDATE_BREAK, break IPI, done on local hart + * @return SBI_IPI_UPDATE_RETRY, need retry */ int (* update)(struct sbi_scratch *scratch, struct sbi_scratch *remote_scratch, diff --git a/lib/sbi/sbi_ipi.c b/lib/sbi/sbi_ipi.c index 24d8a93a0b9..4f94bcee6db 100644 --- a/lib/sbi/sbi_ipi.c +++ b/lib/sbi/sbi_ipi.c @@ -53,7 +53,7 @@ static int sbi_ipi_send(struct sbi_scratch *scratch, u32 remote_hartid, if (ipi_ops->update) { ret = ipi_ops->update(scratch, remote_scratch, remote_hartid, data); - if (ret < 0) + if (ret != SBI_IPI_UPDATE_SUCCESS) return ret; } @@ -95,50 +95,48 @@ static int sbi_ipi_sync(struct sbi_scratch *scratch, u32 event) int sbi_ipi_send_many(ulong hmask, ulong hbase, u32 event, void *data) { int rc; - ulong i, m, n; + bool retry_needed; + ulong i, m; + struct sbi_hartmask target_mask = {0}; struct sbi_domain *dom = sbi_domain_thishart_ptr(); struct sbi_scratch *scratch = sbi_scratch_thishart_ptr(); + /* Find the target harts */ if (hbase != -1UL) { rc = sbi_hsm_hart_interruptible_mask(dom, hbase, &m); if (rc) return rc; m &= hmask; - n = m; - /* Send IPIs */ for (i = hbase; m; i++, m >>= 1) { if (m & 1UL) - sbi_ipi_send(scratch, i, event, data); - } - - /* Sync IPIs */ - m = n; - for (i = hbase; m; i++, m >>= 1) { - if (m & 1UL) - sbi_ipi_sync(scratch, event); + sbi_hartmask_set_hart(i, &target_mask); } } else { - /* Send IPIs */ hbase = 0; while (!sbi_hsm_hart_interruptible_mask(dom, hbase, &m)) { for (i = hbase; m; i++, m >>= 1) { if (m & 1UL) - sbi_ipi_send(scratch, i, event, data); + sbi_hartmask_set_hart(i, &target_mask); } hbase += BITS_PER_LONG; } + } - /* Sync IPIs */ - hbase = 0; - while (!sbi_hsm_hart_interruptible_mask(dom, hbase, &m)) { - for (i = hbase; m; i++, m >>= 1) { - if (m & 1UL) - sbi_ipi_sync(scratch, event); - } - hbase += BITS_PER_LONG; + /* Send IPIs */ + do { + retry_needed = false; + sbi_hartmask_for_each_hart(i, &target_mask) { + rc = sbi_ipi_send(scratch, i, event, data); + if (rc == SBI_IPI_UPDATE_RETRY) + retry_needed = true; + else + sbi_hartmask_clear_hart(i, &target_mask); } - } + } while (retry_needed); + + /* Sync IPIs */ + sbi_ipi_sync(scratch, event); return 0; } diff --git a/lib/sbi/sbi_tlb.c b/lib/sbi/sbi_tlb.c index 60ca8c6f089..26a87f32930 100644 --- a/lib/sbi/sbi_tlb.c +++ b/lib/sbi/sbi_tlb.c @@ -357,14 +357,14 @@ static int tlb_update(struct sbi_scratch *scratch, */ if (remote_hartid == curr_hartid) { tinfo->local_fn(tinfo); - return -1; + return SBI_IPI_UPDATE_BREAK; } tlb_fifo_r = sbi_scratch_offset_ptr(remote_scratch, tlb_fifo_off); ret = sbi_fifo_inplace_update(tlb_fifo_r, data, tlb_update_cb); - while (ret == SBI_FIFO_UNCHANGED && sbi_fifo_enqueue(tlb_fifo_r, data) < 0) { + if (ret == SBI_FIFO_UNCHANGED && sbi_fifo_enqueue(tlb_fifo_r, data) < 0) { /** * For now, Busy loop until there is space in the fifo. * There may be case where target hart is also @@ -376,12 +376,13 @@ static int tlb_update(struct sbi_scratch *scratch, tlb_process_once(scratch); sbi_dprintf("hart%d: hart%d tlb fifo full\n", curr_hartid, remote_hartid); + return SBI_IPI_UPDATE_RETRY; } tlb_sync = sbi_scratch_offset_ptr(scratch, tlb_sync_off); atomic_add_return(tlb_sync, 1); - return 0; + return SBI_IPI_UPDATE_SUCCESS; } static struct sbi_ipi_event_ops tlb_ops = { From eeab500a65d8a576874b36653a02c864e515b5e2 Mon Sep 17 00:00:00 2001 From: Lad Prabhakar Date: Tue, 11 Apr 2023 17:36:33 +0100 Subject: [PATCH 107/187] platform: generic: andes/renesas: Add SBI EXT to check for enabling IOCP errata I/O Coherence Port (IOCP) provides an AXI interface for connecting external non-caching masters, such as DMA controllers. The accesses from IOCP are coherent with D-Caches and L2 Cache. IOCP is a specification option and is disabled on the Renesas RZ/Five SoC (which is based on Andes AX45MP core) due to this reason IP blocks using DMA will fail. As a workaround for SoCs with IOCP disabled CMO needs to be handled by software. Firstly OpenSBI configures the memory region as "Memory, Non-cacheable, Bufferable" and passes this region as a global shared dma pool as a DT node. With DMA_GLOBAL_POOL enabled all DMA allocations happen from this region and synchronization callbacks are implemented to synchronize when doing DMA transactions. SBI_EXT_ANDES_IOCP_SW_WORKAROUND checks if the IOCP errata should be applied to handle cache management. Signed-off-by: Lad Prabhakar Reviewed-by: Anup Patel Reviewed-by: Conor Dooley Reviewed-by: Yu Chien Peter Lin --- platform/generic/Kconfig | 1 + platform/generic/andes/Kconfig | 4 ++ platform/generic/andes/andes_sbi.c | 51 ++++++++++++++++++++++ platform/generic/andes/objects.mk | 1 + platform/generic/include/andes/andes45.h | 23 +++++++++- platform/generic/include/andes/andes_sbi.h | 15 +++++++ platform/generic/renesas/rzfive/rzfive.c | 2 + 7 files changed, 95 insertions(+), 2 deletions(-) create mode 100644 platform/generic/andes/andes_sbi.c create mode 100644 platform/generic/include/andes/andes_sbi.h diff --git a/platform/generic/Kconfig b/platform/generic/Kconfig index 1f4f8e1f340..72768edeb92 100644 --- a/platform/generic/Kconfig +++ b/platform/generic/Kconfig @@ -36,6 +36,7 @@ config PLATFORM_ANDES_AE350 config PLATFORM_RENESAS_RZFIVE bool "Renesas RZ/Five support" select ANDES45_PMA + select ANDES_SBI default n config PLATFORM_SIFIVE_FU540 diff --git a/platform/generic/andes/Kconfig b/platform/generic/andes/Kconfig index 3ad4e4ca56f..a91fb9c95dc 100644 --- a/platform/generic/andes/Kconfig +++ b/platform/generic/andes/Kconfig @@ -3,3 +3,7 @@ config ANDES45_PMA bool "Andes PMA support" default n + +config ANDES_SBI + bool "Andes SBI support" + default n diff --git a/platform/generic/andes/andes_sbi.c b/platform/generic/andes/andes_sbi.c new file mode 100644 index 00000000000..3e89fb9c696 --- /dev/null +++ b/platform/generic/andes/andes_sbi.c @@ -0,0 +1,51 @@ +// SPDX-License-Identifier: BSD-2-Clause +/* + * Copyright (C) 2023 Renesas Electronics Corp. + * + */ +#include +#include +#include +#include + +enum sbi_ext_andes_fid { + SBI_EXT_ANDES_FID0 = 0, /* Reserved for future use */ + SBI_EXT_ANDES_IOCP_SW_WORKAROUND, +}; + +static bool andes45_cache_controllable(void) +{ + return (((csr_read(CSR_MICM_CFG) & MICM_CFG_ISZ_MASK) || + (csr_read(CSR_MDCM_CFG) & MDCM_CFG_DSZ_MASK)) && + (csr_read(CSR_MMSC_CFG) & MMSC_CFG_CCTLCSR_MASK) && + (csr_read(CSR_MCACHE_CTL) & MCACHE_CTL_CCTL_SUEN_MASK) && + misa_extension('U')); +} + +static bool andes45_iocp_disabled(void) +{ + return (csr_read(CSR_MMSC_CFG) & MMSC_IOCP_MASK) ? false : true; +} + +static bool andes45_apply_iocp_sw_workaround(void) +{ + return andes45_cache_controllable() & andes45_iocp_disabled(); +} + +int andes_sbi_vendor_ext_provider(long funcid, + const struct sbi_trap_regs *regs, + unsigned long *out_value, + struct sbi_trap_info *out_trap, + const struct fdt_match *match) +{ + switch (funcid) { + case SBI_EXT_ANDES_IOCP_SW_WORKAROUND: + *out_value = andes45_apply_iocp_sw_workaround(); + break; + + default: + return SBI_EINVAL; + } + + return 0; +} diff --git a/platform/generic/andes/objects.mk b/platform/generic/andes/objects.mk index ea6b561953e..e8f86ea0815 100644 --- a/platform/generic/andes/objects.mk +++ b/platform/generic/andes/objects.mk @@ -6,3 +6,4 @@ carray-platform_override_modules-$(CONFIG_PLATFORM_ANDES_AE350) += andes_ae350 platform-objs-$(CONFIG_PLATFORM_ANDES_AE350) += andes/ae350.o andes/sleep.o platform-objs-$(CONFIG_ANDES45_PMA) += andes/andes45-pma.o +platform-objs-$(CONFIG_ANDES_SBI) += andes/andes_sbi.o diff --git a/platform/generic/include/andes/andes45.h b/platform/generic/include/andes/andes45.h index 08b3d18876e..f5709943538 100644 --- a/platform/generic/include/andes/andes45.h +++ b/platform/generic/include/andes/andes45.h @@ -4,7 +4,26 @@ #define CSR_MARCHID_MICROID 0xfff /* Memory and Miscellaneous Registers */ -#define CSR_MCACHE_CTL 0x7ca -#define CSR_MCCTLCOMMAND 0x7cc +#define CSR_MCACHE_CTL 0x7ca +#define CSR_MCCTLCOMMAND 0x7cc + +/* Configuration Control & Status Registers */ +#define CSR_MICM_CFG 0xfc0 +#define CSR_MDCM_CFG 0xfc1 +#define CSR_MMSC_CFG 0xfc2 + +#define MICM_CFG_ISZ_OFFSET 6 +#define MICM_CFG_ISZ_MASK (0x7 << MICM_CFG_ISZ_OFFSET) + +#define MDCM_CFG_DSZ_OFFSET 6 +#define MDCM_CFG_DSZ_MASK (0x7 << MDCM_CFG_DSZ_OFFSET) + +#define MMSC_CFG_CCTLCSR_OFFSET 16 +#define MMSC_CFG_CCTLCSR_MASK (0x1 << MMSC_CFG_CCTLCSR_OFFSET) +#define MMSC_IOCP_OFFSET 47 +#define MMSC_IOCP_MASK (0x1ULL << MMSC_IOCP_OFFSET) + +#define MCACHE_CTL_CCTL_SUEN_OFFSET 8 +#define MCACHE_CTL_CCTL_SUEN_MASK (0x1 << MCACHE_CTL_CCTL_SUEN_OFFSET) #endif /* _RISCV_ANDES45_H */ diff --git a/platform/generic/include/andes/andes_sbi.h b/platform/generic/include/andes/andes_sbi.h new file mode 100644 index 00000000000..e5dc250707b --- /dev/null +++ b/platform/generic/include/andes/andes_sbi.h @@ -0,0 +1,15 @@ +// SPDX-License-Identifier: BSD-2-Clause + +#ifndef _RISCV_ANDES_SBI_H +#define _RISCV_ANDES_SBI_H + +#include +#include + +int andes_sbi_vendor_ext_provider(long funcid, + const struct sbi_trap_regs *regs, + unsigned long *out_value, + struct sbi_trap_info *out_trap, + const struct fdt_match *match); + +#endif /* _RISCV_ANDES_SBI_H */ diff --git a/platform/generic/renesas/rzfive/rzfive.c b/platform/generic/renesas/rzfive/rzfive.c index 4d71d0d6c22..a69797b18df 100644 --- a/platform/generic/renesas/rzfive/rzfive.c +++ b/platform/generic/renesas/rzfive/rzfive.c @@ -5,6 +5,7 @@ */ #include +#include #include #include #include @@ -55,4 +56,5 @@ const struct platform_override renesas_rzfive = { .match_table = renesas_rzfive_match, .early_init = renesas_rzfive_early_init, .final_init = renesas_rzfive_final_init, + .vendor_ext_provider = andes_sbi_vendor_ext_provider, }; From f692289ed42882567491c35700a1feb64ba540b5 Mon Sep 17 00:00:00 2001 From: Bin Meng Date: Tue, 4 Apr 2023 12:46:00 +0800 Subject: [PATCH 108/187] firmware: Optimize loading relocation type 't5' already contains relocation type so don't bother reloading it. Signed-off-by: Bin Meng Reviewed-by: Anup Patel Reviewed-by: Xiang W --- firmware/fw_base.S | 1 - 1 file changed, 1 deletion(-) diff --git a/firmware/fw_base.S b/firmware/fw_base.S index 5a3e89485a8..2d6be70e9d4 100644 --- a/firmware/fw_base.S +++ b/firmware/fw_base.S @@ -95,7 +95,6 @@ _try_lottery: lla t4, __dyn_sym_start 4: - REG_L t5, -(REGBYTES*2)(t0) /* t5 <-- relocation info:type */ srli t6, t5, SYM_INDEX /* t6 <--- sym table index */ andi t5, t5, 0xFF /* t5 <--- relocation type */ li t3, RELOC_TYPE From e41dbb507c422c52cf93228ca7157394d49ca9fe Mon Sep 17 00:00:00 2001 From: Bin Meng Date: Tue, 4 Apr 2023 12:46:01 +0800 Subject: [PATCH 109/187] firmware: Change to use positive offset to access relocation entries The codes currently skip the very first relocation entry, but later reference the elements in the relocation entry using minus offsets. Change to use positive offsets so that there is no need to skip the first relocation entry. Signed-off-by: Bin Meng Reviewed-by: Anup Patel Reviewed-by: Xiang W --- firmware/fw_base.S | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/firmware/fw_base.S b/firmware/fw_base.S index 2d6be70e9d4..e37df095845 100644 --- a/firmware/fw_base.S +++ b/firmware/fw_base.S @@ -79,13 +79,12 @@ _try_lottery: lla t0, __rel_dyn_start lla t1, __rel_dyn_end beq t0, t1, _relocate_done - j 5f 2: - REG_L t5, -(REGBYTES*2)(t0) /* t5 <-- relocation info:type */ + REG_L t5, REGBYTES(t0) /* t5 <-- relocation info:type */ li t3, R_RISCV_RELATIVE /* reloc type R_RISCV_RELATIVE */ bne t5, t3, 3f - REG_L t3, -(REGBYTES*3)(t0) - REG_L t5, -(REGBYTES)(t0) /* t5 <-- addend */ + REG_L t3, 0(t0) + REG_L t5, (REGBYTES * 2)(t0) /* t5 <-- addend */ add t5, t5, t2 add t3, t3, t2 REG_S t5, 0(t3) /* store runtime address to the GOT entry */ @@ -101,11 +100,11 @@ _try_lottery: bne t5, t3, 5f /* address R_RISCV_64 or R_RISCV_32 cases*/ - REG_L t3, -(REGBYTES*3)(t0) + REG_L t3, 0(t0) li t5, SYM_SIZE mul t6, t6, t5 add s5, t4, t6 - REG_L t6, -(REGBYTES)(t0) /* t0 <-- addend */ + REG_L t6, (REGBYTES * 2)(t0) /* t0 <-- addend */ REG_L t5, REGBYTES(s5) add t5, t5, t6 add t5, t5, t2 /* t5 <-- location to fix up in RAM */ @@ -113,8 +112,8 @@ _try_lottery: REG_S t5, 0(t3) /* store runtime address to the variable */ 5: - addi t0, t0, (REGBYTES*3) - ble t0, t1, 2b + addi t0, t0, (REGBYTES * 3) + blt t0, t1, 2b j _relocate_done _wait_relocate_copy_done: j _wait_for_boot_hart From bdb3c42bca1c7fddd0c43f0be24c3a1590f02e50 Mon Sep 17 00:00:00 2001 From: Alexandre Ghiti Date: Thu, 13 Apr 2023 16:02:18 +0200 Subject: [PATCH 110/187] lib: sbi: Do not clear active_events for cycle/instret when stopping Those events are enabled by default and should not be reset afterwards since when using SBI_PMU_CFG_FLAG_SKIP_MATCH, it leads to unaccessible counters after the first use. Signed-off-by: Alexandre Ghiti Reviewed-by: Atish Patra --- lib/sbi/sbi_pmu.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/sbi/sbi_pmu.c b/lib/sbi/sbi_pmu.c index 04259aeb24e..f28c9f5e80a 100644 --- a/lib/sbi/sbi_pmu.c +++ b/lib/sbi/sbi_pmu.c @@ -532,7 +532,7 @@ int sbi_pmu_ctr_stop(unsigned long cbase, unsigned long cmask, else ret = pmu_ctr_stop_hw(cidx); - if (flag & SBI_PMU_STOP_FLAG_RESET) { + if (cidx > (CSR_INSTRET - CSR_CYCLE) && flag & SBI_PMU_STOP_FLAG_RESET) { active_events[hartid][cidx] = SBI_PMU_EVENT_IDX_INVALID; pmu_reset_hw_mhpmevent(cidx); } From 674e0199b23effebfc5311d09b636ca9b46cde7e Mon Sep 17 00:00:00 2001 From: Alexandre Ghiti Date: Thu, 13 Apr 2023 16:02:19 +0200 Subject: [PATCH 111/187] lib: sbi: Fix counter index calculation for SBI_PMU_CFG_FLAG_SKIP_MATCH As per the SBI specification, we should "unconditionally select the first counter from the set of counters specified by the counter_idx_base and counter_idx_mask", so implement this behaviour. Suggested-by: Atish Patra Signed-off-by: Alexandre Ghiti Reviewed-by: Atish Patra --- lib/sbi/sbi_pmu.c | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/lib/sbi/sbi_pmu.c b/lib/sbi/sbi_pmu.c index f28c9f5e80a..939f29d841e 100644 --- a/lib/sbi/sbi_pmu.c +++ b/lib/sbi/sbi_pmu.c @@ -736,10 +736,15 @@ int sbi_pmu_ctr_cfg_match(unsigned long cidx_base, unsigned long cidx_mask, /* The caller wants to skip the match because it already knows the * counter idx for the given event. Verify that the counter idx * is still valid. + * As per the specification, we should "unconditionally select + * the first counter from the set of counters specified by the + * counter_idx_base and counter_idx_mask". */ - if (active_events[hartid][cidx_base] == SBI_PMU_EVENT_IDX_INVALID) + unsigned long cidx_first = cidx_base + sbi_ffs(cidx_mask); + + if (active_events[hartid][cidx_first] == SBI_PMU_EVENT_IDX_INVALID) return SBI_EINVAL; - ctr_idx = cidx_base; + ctr_idx = cidx_first; goto skip_match; } From f5dfd991396891d87d7780be45f887bc9ed13099 Mon Sep 17 00:00:00 2001 From: Anup Patel Date: Mon, 17 Apr 2023 09:48:13 +0530 Subject: [PATCH 112/187] lib: sbi: Don't check SBI error range for legacy console getchar The legacy console getchar SBI call returns character value in the sbiret.error field so the "SBI_SUCCESS < ret" check in sbi_ecall_handler() results in unwanted error prints for the legacy console getchar SBI call. Let's suppress these unwanted error prints. Fixes: 67b2a408924b ("lib: sbi: sbi_ecall: Check the range of SBI error") Signed-off-by: Anup Patel --- lib/sbi/sbi_ecall.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/lib/sbi/sbi_ecall.c b/lib/sbi/sbi_ecall.c index d0f01665368..76a1ae9ab73 100644 --- a/lib/sbi/sbi_ecall.c +++ b/lib/sbi/sbi_ecall.c @@ -120,7 +120,9 @@ int sbi_ecall_handler(struct sbi_trap_regs *regs) trap.epc = regs->mepc; sbi_trap_redirect(regs, &trap); } else { - if (ret < SBI_LAST_ERR || SBI_SUCCESS < ret) { + if (ret < SBI_LAST_ERR || + (extension_id != SBI_EXT_0_1_CONSOLE_GETCHAR && + SBI_SUCCESS < ret)) { sbi_printf("%s: Invalid error %d for ext=0x%lx " "func=0x%lx\n", __func__, ret, extension_id, func_id); From 791953030836d39687688a8e7f1a3e708892cfa1 Mon Sep 17 00:00:00 2001 From: Tan En De Date: Fri, 14 Apr 2023 13:13:11 +0800 Subject: [PATCH 113/187] lib: sbi: Add debug print when sbi_pmu_init fails Since sbi_pmu_init is called after sbi_console_init, the sbi_printf can be called when sbi_pmu_init fails. Signed-off-by: Tan En De Reviewed-by: Atish Patra --- lib/sbi/sbi_init.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/lib/sbi/sbi_init.c b/lib/sbi/sbi_init.c index a0313367117..5db8e7f68c8 100644 --- a/lib/sbi/sbi_init.c +++ b/lib/sbi/sbi_init.c @@ -290,8 +290,11 @@ static void __noreturn init_coldboot(struct sbi_scratch *scratch, u32 hartid) sbi_hart_hang(); rc = sbi_pmu_init(scratch, true); - if (rc) + if (rc) { + sbi_printf("%s: pmu init failed (error %d)\n", + __func__, rc); sbi_hart_hang(); + } sbi_boot_print_banner(scratch); From 4e3353057a3b975ca58c9b831749e2760f7812c0 Mon Sep 17 00:00:00 2001 From: Xiang W Date: Tue, 25 Apr 2023 16:56:23 +0800 Subject: [PATCH 114/187] lib: sbi: Remove unnecessary semicolon We have redundant semicolon at quite a few places so let's remove it. Signed-off-by: Xiang W Reviewed-by: Anup Patel --- include/sbi/sbi_list.h | 2 +- lib/sbi/riscv_asm.c | 4 ++-- lib/sbi/sbi_domain.c | 4 ++-- lib/sbi/sbi_ecall_legacy.c | 2 +- lib/sbi/sbi_ecall_pmu.c | 2 +- lib/sbi/sbi_ecall_rfence.c | 2 +- lib/sbi/sbi_emulate_csr.c | 4 ++-- lib/sbi/sbi_hsm.c | 2 +- lib/sbi/sbi_illegal_insn.c | 2 +- lib/sbi/sbi_init.c | 2 +- lib/sbi/sbi_ipi.c | 2 +- lib/sbi/sbi_trap.c | 4 ++-- lib/sbi/sbi_unpriv.c | 2 +- lib/utils/fdt/fdt_helper.c | 2 +- lib/utils/libfdt/fdt_overlay.c | 2 +- 15 files changed, 19 insertions(+), 19 deletions(-) diff --git a/include/sbi/sbi_list.h b/include/sbi/sbi_list.h index fe735dff054..9e56c526faf 100644 --- a/include/sbi/sbi_list.h +++ b/include/sbi/sbi_list.h @@ -31,7 +31,7 @@ struct sbi_dlist _lname = SBI_LIST_HEAD_INIT(_lname) #define SBI_INIT_LIST_HEAD(ptr) \ do { \ (ptr)->next = ptr; (ptr)->prev = ptr; \ -} while (0); +} while (0) static inline void __sbi_list_add(struct sbi_dlist *new, struct sbi_dlist *prev, diff --git a/lib/sbi/riscv_asm.c b/lib/sbi/riscv_asm.c index a09cf78e9c1..cd565534ca1 100644 --- a/lib/sbi/riscv_asm.c +++ b/lib/sbi/riscv_asm.c @@ -152,7 +152,7 @@ unsigned long csr_read_num(int csr_num) default: sbi_panic("%s: Unknown CSR %#x", __func__, csr_num); break; - }; + } return ret; @@ -220,7 +220,7 @@ void csr_write_num(int csr_num, unsigned long val) default: sbi_panic("%s: Unknown CSR %#x", __func__, csr_num); break; - }; + } #undef switchcase_csr_write_64 #undef switchcase_csr_write_32 diff --git a/lib/sbi/sbi_domain.c b/lib/sbi/sbi_domain.c index 67b87f3043c..c55e192207d 100644 --- a/lib/sbi/sbi_domain.c +++ b/lib/sbi/sbi_domain.c @@ -261,7 +261,7 @@ static int sanitize_domain(const struct sbi_platform *plat, "hart %d\n", __func__, dom->name, i); return SBI_EINVAL; } - }; + } /* Check memory regions */ if (!dom->regions) { @@ -451,7 +451,7 @@ void sbi_domain_dump(const struct sbi_domain *dom, const char *suffix) default: sbi_printf("Unknown\n"); break; - }; + } sbi_printf("Domain%d SysReset %s: %s\n", dom->index, suffix, (dom->system_reset_allowed) ? "yes" : "no"); diff --git a/lib/sbi/sbi_ecall_legacy.c b/lib/sbi/sbi_ecall_legacy.c index e20de766d27..8237498b538 100644 --- a/lib/sbi/sbi_ecall_legacy.c +++ b/lib/sbi/sbi_ecall_legacy.c @@ -112,7 +112,7 @@ static int sbi_ecall_legacy_handler(unsigned long extid, unsigned long funcid, break; default: ret = SBI_ENOTSUPP; - }; + } return ret; } diff --git a/lib/sbi/sbi_ecall_pmu.c b/lib/sbi/sbi_ecall_pmu.c index 8f91f9cec01..367e9277426 100644 --- a/lib/sbi/sbi_ecall_pmu.c +++ b/lib/sbi/sbi_ecall_pmu.c @@ -76,7 +76,7 @@ static int sbi_ecall_pmu_handler(unsigned long extid, unsigned long funcid, break; default: ret = SBI_ENOTSUPP; - }; + } return ret; } diff --git a/lib/sbi/sbi_ecall_rfence.c b/lib/sbi/sbi_ecall_rfence.c index 8f0e3d7bacf..6334c001d45 100644 --- a/lib/sbi/sbi_ecall_rfence.c +++ b/lib/sbi/sbi_ecall_rfence.c @@ -74,7 +74,7 @@ static int sbi_ecall_rfence_handler(unsigned long extid, unsigned long funcid, break; default: ret = SBI_ENOTSUPP; - }; + } return ret; } diff --git a/lib/sbi/sbi_emulate_csr.c b/lib/sbi/sbi_emulate_csr.c index 64bebd8da7a..da811653661 100644 --- a/lib/sbi/sbi_emulate_csr.c +++ b/lib/sbi/sbi_emulate_csr.c @@ -149,7 +149,7 @@ int sbi_emulate_csr_read(int csr_num, struct sbi_trap_regs *regs, default: ret = SBI_ENOTSUPP; break; - }; + } if (ret) sbi_dprintf("%s: hartid%d: invalid csr_num=0x%x\n", @@ -187,7 +187,7 @@ int sbi_emulate_csr_write(int csr_num, struct sbi_trap_regs *regs, default: ret = SBI_ENOTSUPP; break; - }; + } if (ret) sbi_dprintf("%s: hartid%d: invalid csr_num=0x%x\n", diff --git a/lib/sbi/sbi_hsm.c b/lib/sbi/sbi_hsm.c index b2614105096..f870ca72baf 100644 --- a/lib/sbi/sbi_hsm.c +++ b/lib/sbi/sbi_hsm.c @@ -172,7 +172,7 @@ static void sbi_hsm_hart_wait(struct sbi_scratch *scratch, u32 hartid) /* Wait for state transition requested by sbi_hsm_hart_start() */ while (atomic_read(&hdata->state) != SBI_HSM_STATE_START_PENDING) { wfi(); - }; + } /* Restore MIE CSR */ csr_write(CSR_MIE, saved_mie); diff --git a/lib/sbi/sbi_illegal_insn.c b/lib/sbi/sbi_illegal_insn.c index 9691bce930f..2be47575a36 100644 --- a/lib/sbi/sbi_illegal_insn.c +++ b/lib/sbi/sbi_illegal_insn.c @@ -90,7 +90,7 @@ static int system_opcode_insn(ulong insn, struct sbi_trap_regs *regs) break; default: return truly_illegal_insn(insn, regs); - }; + } if (do_write && sbi_emulate_csr_write(csr_num, regs, new_csr_val)) return truly_illegal_insn(insn, regs); diff --git a/lib/sbi/sbi_init.c b/lib/sbi/sbi_init.c index 5db8e7f68c8..539f8245c44 100644 --- a/lib/sbi/sbi_init.c +++ b/lib/sbi/sbi_init.c @@ -200,7 +200,7 @@ static void wait_for_coldboot(struct sbi_scratch *scratch, u32 hartid) wfi(); cmip = csr_read(CSR_MIP); } while (!(cmip & (MIP_MSIP | MIP_MEIP))); - }; + } /* Acquire coldboot lock */ spin_lock(&coldboot_lock); diff --git a/lib/sbi/sbi_ipi.c b/lib/sbi/sbi_ipi.c index 4f94bcee6db..ba83f245c14 100644 --- a/lib/sbi/sbi_ipi.c +++ b/lib/sbi/sbi_ipi.c @@ -233,7 +233,7 @@ void sbi_ipi_process(void) skip: ipi_type = ipi_type >> 1; ipi_event++; - }; + } } int sbi_ipi_raw_send(u32 target_hart) diff --git a/lib/sbi/sbi_trap.c b/lib/sbi/sbi_trap.c index 025cf614c27..dbf307c6894 100644 --- a/lib/sbi/sbi_trap.c +++ b/lib/sbi/sbi_trap.c @@ -212,7 +212,7 @@ static int sbi_trap_nonaia_irq(struct sbi_trap_regs *regs, ulong mcause) return sbi_irqchip_process(regs); default: return SBI_ENOENT; - }; + } return 0; } @@ -320,7 +320,7 @@ struct sbi_trap_regs *sbi_trap_handler(struct sbi_trap_regs *regs) rc = sbi_trap_redirect(regs, &trap); break; - }; + } trap_error: if (rc) diff --git a/lib/sbi/sbi_unpriv.c b/lib/sbi/sbi_unpriv.c index 9a34a717b00..2a55d9dbf11 100644 --- a/lib/sbi/sbi_unpriv.c +++ b/lib/sbi/sbi_unpriv.c @@ -163,7 +163,7 @@ ulong sbi_get_insn(ulong mepc, struct sbi_trap_info *trap) break; default: break; - }; + } return insn; } diff --git a/lib/utils/fdt/fdt_helper.c b/lib/utils/fdt/fdt_helper.c index 48bc2fe4c28..a88a4ba83fa 100644 --- a/lib/utils/fdt/fdt_helper.c +++ b/lib/utils/fdt/fdt_helper.c @@ -689,7 +689,7 @@ int fdt_parse_imsic_node(void *fdt, int nodeoff, struct imsic_data *imsic) break; regs->addr = reg_addr; regs->size = reg_size; - }; + } if (!imsic->regs[0].size) return SBI_EINVAL; diff --git a/lib/utils/libfdt/fdt_overlay.c b/lib/utils/libfdt/fdt_overlay.c index d217e79b672..0871e260ff4 100644 --- a/lib/utils/libfdt/fdt_overlay.c +++ b/lib/utils/libfdt/fdt_overlay.c @@ -404,7 +404,7 @@ static int overlay_fixup_one_phandle(void *fdt, void *fdto, name, name_len, poffset, &phandle_prop, sizeof(phandle_prop)); -}; +} /** * overlay_fixup_phandle - Set an overlay phandle to the base one From 6bc02dede86c47f87e65293b7099e9caf3b22c29 Mon Sep 17 00:00:00 2001 From: Xiang W Date: Tue, 25 Apr 2023 16:56:24 +0800 Subject: [PATCH 115/187] lib: sbi: Simplify sbi_ipi_process remove goto Simplify sbi_ipi_process() by removing goto statement. Signed-off-by: Xiang W Reviewed-by: Anup Patel --- lib/sbi/sbi_ipi.c | 13 +++++-------- 1 file changed, 5 insertions(+), 8 deletions(-) diff --git a/lib/sbi/sbi_ipi.c b/lib/sbi/sbi_ipi.c index ba83f245c14..ad09154521f 100644 --- a/lib/sbi/sbi_ipi.c +++ b/lib/sbi/sbi_ipi.c @@ -223,14 +223,11 @@ void sbi_ipi_process(void) ipi_type = atomic_raw_xchg_ulong(&ipi_data->ipi_type, 0); ipi_event = 0; while (ipi_type) { - if (!(ipi_type & 1UL)) - goto skip; - - ipi_ops = ipi_ops_array[ipi_event]; - if (ipi_ops && ipi_ops->process) - ipi_ops->process(scratch); - -skip: + if (ipi_type & 1UL) { + ipi_ops = ipi_ops_array[ipi_event]; + if (ipi_ops && ipi_ops->process) + ipi_ops->process(scratch); + } ipi_type = ipi_type >> 1; ipi_event++; } From dc1c7db05e075e0910b93504370b50d064a51402 Mon Sep 17 00:00:00 2001 From: Xiang W Date: Tue, 25 Apr 2023 19:32:21 +0800 Subject: [PATCH 116/187] lib: sbi: Simplify BITS_PER_LONG definition No need to use #elif ladder when defining BITS_PER_LONG. Signed-off-by: Xiang W Reviewed-by: Andrew Jones Reviewed-by: Anup Patel --- include/sbi/sbi_bitops.h | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/include/sbi/sbi_bitops.h b/include/sbi/sbi_bitops.h index 251e4d89d59..2e08947beed 100644 --- a/include/sbi/sbi_bitops.h +++ b/include/sbi/sbi_bitops.h @@ -12,13 +12,7 @@ #include -#if __SIZEOF_POINTER__ == 8 -#define BITS_PER_LONG 64 -#elif __SIZEOF_POINTER__ == 4 -#define BITS_PER_LONG 32 -#else -#error "Unexpected __SIZEOF_POINTER__" -#endif +#define BITS_PER_LONG (8 * __SIZEOF_LONG__) #define EXTRACT_FIELD(val, which) \ (((val) & (which)) / ((which) & ~((which)-1))) From f58c14090f79b5d3bde86573c979a019bbd7421d Mon Sep 17 00:00:00 2001 From: Andrew Jones Date: Mon, 15 May 2023 13:12:34 +0200 Subject: [PATCH 117/187] lib: sbi: Introduce register_extensions extension callback Rather than registering all extensions on their behalf in sbi_ecall_init(), introduce another extension callback and invoke that instead. For now, implement each callback by simply registering the extension, which means this patch has no intended functional change. In later patches, extension callbacks will be modified to choose when to register and to possibly narrow the extension ID range prior to registering. When an extension range needs to remove IDs, leaving gaps, then multiple invocations of sbi_ecall_register_extension() may be used. In summary, later patches for current extensions and the introductions of future extensions will use the new callback to ensure that only valid extension IDs from the initial range, which are also available, will be registered. Signed-off-by: Andrew Jones Reviewed-by: Anup Patel --- include/sbi/sbi_ecall.h | 1 + lib/sbi/sbi_ecall.c | 5 ++++- lib/sbi/sbi_ecall_base.c | 14 +++++++++++--- lib/sbi/sbi_ecall_cppc.c | 16 ++++++++++++---- lib/sbi/sbi_ecall_dbcn.c | 16 ++++++++++++---- lib/sbi/sbi_ecall_hsm.c | 14 +++++++++++--- lib/sbi/sbi_ecall_ipi.c | 14 +++++++++++--- lib/sbi/sbi_ecall_legacy.c | 14 +++++++++++--- lib/sbi/sbi_ecall_pmu.c | 16 ++++++++++++---- lib/sbi/sbi_ecall_rfence.c | 14 +++++++++++--- lib/sbi/sbi_ecall_srst.c | 16 ++++++++++++---- lib/sbi/sbi_ecall_susp.c | 16 ++++++++++++---- lib/sbi/sbi_ecall_time.c | 14 +++++++++++--- lib/sbi/sbi_ecall_vendor.c | 16 ++++++++++++---- 14 files changed, 143 insertions(+), 43 deletions(-) diff --git a/include/sbi/sbi_ecall.h b/include/sbi/sbi_ecall.h index ff9bf8e2b43..fac26429cf5 100644 --- a/include/sbi/sbi_ecall.h +++ b/include/sbi/sbi_ecall.h @@ -24,6 +24,7 @@ struct sbi_ecall_extension { struct sbi_dlist head; unsigned long extid_start; unsigned long extid_end; + int (* register_extensions)(void); int (* probe)(unsigned long extid, unsigned long *out_val); int (* handle)(unsigned long extid, unsigned long funcid, const struct sbi_trap_regs *regs, diff --git a/lib/sbi/sbi_ecall.c b/lib/sbi/sbi_ecall.c index 76a1ae9ab73..3eb4f0addb0 100644 --- a/lib/sbi/sbi_ecall.c +++ b/lib/sbi/sbi_ecall.c @@ -154,7 +154,10 @@ int sbi_ecall_init(void) for (i = 0; i < sbi_ecall_exts_size; i++) { ext = sbi_ecall_exts[i]; - ret = sbi_ecall_register_extension(ext); + ret = SBI_ENODEV; + + if (ext->register_extensions) + ret = ext->register_extensions(); if (ret) return ret; } diff --git a/lib/sbi/sbi_ecall_base.c b/lib/sbi/sbi_ecall_base.c index 786d2ac6792..74f05eb26a3 100644 --- a/lib/sbi/sbi_ecall_base.c +++ b/lib/sbi/sbi_ecall_base.c @@ -72,8 +72,16 @@ static int sbi_ecall_base_handler(unsigned long extid, unsigned long funcid, return ret; } +struct sbi_ecall_extension ecall_base; + +static int sbi_ecall_base_register_extensions(void) +{ + return sbi_ecall_register_extension(&ecall_base); +} + struct sbi_ecall_extension ecall_base = { - .extid_start = SBI_EXT_BASE, - .extid_end = SBI_EXT_BASE, - .handle = sbi_ecall_base_handler, + .extid_start = SBI_EXT_BASE, + .extid_end = SBI_EXT_BASE, + .register_extensions = sbi_ecall_base_register_extensions, + .handle = sbi_ecall_base_handler, }; diff --git a/lib/sbi/sbi_ecall_cppc.c b/lib/sbi/sbi_ecall_cppc.c index 91585f3b74e..42ec744c22b 100644 --- a/lib/sbi/sbi_ecall_cppc.c +++ b/lib/sbi/sbi_ecall_cppc.c @@ -55,9 +55,17 @@ static int sbi_ecall_cppc_probe(unsigned long extid, unsigned long *out_val) return 0; } +struct sbi_ecall_extension ecall_cppc; + +static int sbi_ecall_cppc_register_extensions(void) +{ + return sbi_ecall_register_extension(&ecall_cppc); +} + struct sbi_ecall_extension ecall_cppc = { - .extid_start = SBI_EXT_CPPC, - .extid_end = SBI_EXT_CPPC, - .handle = sbi_ecall_cppc_handler, - .probe = sbi_ecall_cppc_probe, + .extid_start = SBI_EXT_CPPC, + .extid_end = SBI_EXT_CPPC, + .register_extensions = sbi_ecall_cppc_register_extensions, + .probe = sbi_ecall_cppc_probe, + .handle = sbi_ecall_cppc_handler, }; diff --git a/lib/sbi/sbi_ecall_dbcn.c b/lib/sbi/sbi_ecall_dbcn.c index fe7e175a64c..58b19e4468e 100644 --- a/lib/sbi/sbi_ecall_dbcn.c +++ b/lib/sbi/sbi_ecall_dbcn.c @@ -64,9 +64,17 @@ static int sbi_ecall_dbcn_probe(unsigned long extid, unsigned long *out_val) return 0; } +struct sbi_ecall_extension ecall_dbcn; + +static int sbi_ecall_dbcn_register_extensions(void) +{ + return sbi_ecall_register_extension(&ecall_dbcn); +} + struct sbi_ecall_extension ecall_dbcn = { - .extid_start = SBI_EXT_DBCN, - .extid_end = SBI_EXT_DBCN, - .handle = sbi_ecall_dbcn_handler, - .probe = sbi_ecall_dbcn_probe, + .extid_start = SBI_EXT_DBCN, + .extid_end = SBI_EXT_DBCN, + .register_extensions = sbi_ecall_dbcn_register_extensions, + .probe = sbi_ecall_dbcn_probe, + .handle = sbi_ecall_dbcn_handler, }; diff --git a/lib/sbi/sbi_ecall_hsm.c b/lib/sbi/sbi_ecall_hsm.c index f1b41d073b2..20705c39513 100644 --- a/lib/sbi/sbi_ecall_hsm.c +++ b/lib/sbi/sbi_ecall_hsm.c @@ -54,8 +54,16 @@ static int sbi_ecall_hsm_handler(unsigned long extid, unsigned long funcid, return ret; } +struct sbi_ecall_extension ecall_hsm; + +static int sbi_ecall_hsm_register_extensions(void) +{ + return sbi_ecall_register_extension(&ecall_hsm); +} + struct sbi_ecall_extension ecall_hsm = { - .extid_start = SBI_EXT_HSM, - .extid_end = SBI_EXT_HSM, - .handle = sbi_ecall_hsm_handler, + .extid_start = SBI_EXT_HSM, + .extid_end = SBI_EXT_HSM, + .register_extensions = sbi_ecall_hsm_register_extensions, + .handle = sbi_ecall_hsm_handler, }; diff --git a/lib/sbi/sbi_ecall_ipi.c b/lib/sbi/sbi_ecall_ipi.c index f4797e117a3..a40d6b8cc8a 100644 --- a/lib/sbi/sbi_ecall_ipi.c +++ b/lib/sbi/sbi_ecall_ipi.c @@ -29,8 +29,16 @@ static int sbi_ecall_ipi_handler(unsigned long extid, unsigned long funcid, return ret; } +struct sbi_ecall_extension ecall_ipi; + +static int sbi_ecall_ipi_register_extensions(void) +{ + return sbi_ecall_register_extension(&ecall_ipi); +} + struct sbi_ecall_extension ecall_ipi = { - .extid_start = SBI_EXT_IPI, - .extid_end = SBI_EXT_IPI, - .handle = sbi_ecall_ipi_handler, + .extid_start = SBI_EXT_IPI, + .extid_end = SBI_EXT_IPI, + .register_extensions = sbi_ecall_ipi_register_extensions, + .handle = sbi_ecall_ipi_handler, }; diff --git a/lib/sbi/sbi_ecall_legacy.c b/lib/sbi/sbi_ecall_legacy.c index 8237498b538..99e862e0f19 100644 --- a/lib/sbi/sbi_ecall_legacy.c +++ b/lib/sbi/sbi_ecall_legacy.c @@ -117,8 +117,16 @@ static int sbi_ecall_legacy_handler(unsigned long extid, unsigned long funcid, return ret; } +struct sbi_ecall_extension ecall_legacy; + +static int sbi_ecall_legacy_register_extensions(void) +{ + return sbi_ecall_register_extension(&ecall_legacy); +} + struct sbi_ecall_extension ecall_legacy = { - .extid_start = SBI_EXT_0_1_SET_TIMER, - .extid_end = SBI_EXT_0_1_SHUTDOWN, - .handle = sbi_ecall_legacy_handler, + .extid_start = SBI_EXT_0_1_SET_TIMER, + .extid_end = SBI_EXT_0_1_SHUTDOWN, + .register_extensions = sbi_ecall_legacy_register_extensions, + .handle = sbi_ecall_legacy_handler, }; diff --git a/lib/sbi/sbi_ecall_pmu.c b/lib/sbi/sbi_ecall_pmu.c index 367e9277426..b0589d0ecfa 100644 --- a/lib/sbi/sbi_ecall_pmu.c +++ b/lib/sbi/sbi_ecall_pmu.c @@ -88,9 +88,17 @@ static int sbi_ecall_pmu_probe(unsigned long extid, unsigned long *out_val) return 0; } +struct sbi_ecall_extension ecall_pmu; + +static int sbi_ecall_pmu_register_extensions(void) +{ + return sbi_ecall_register_extension(&ecall_pmu); +} + struct sbi_ecall_extension ecall_pmu = { - .extid_start = SBI_EXT_PMU, - .extid_end = SBI_EXT_PMU, - .handle = sbi_ecall_pmu_handler, - .probe = sbi_ecall_pmu_probe, + .extid_start = SBI_EXT_PMU, + .extid_end = SBI_EXT_PMU, + .register_extensions = sbi_ecall_pmu_register_extensions, + .probe = sbi_ecall_pmu_probe, + .handle = sbi_ecall_pmu_handler, }; diff --git a/lib/sbi/sbi_ecall_rfence.c b/lib/sbi/sbi_ecall_rfence.c index 6334c001d45..22c66522782 100644 --- a/lib/sbi/sbi_ecall_rfence.c +++ b/lib/sbi/sbi_ecall_rfence.c @@ -79,8 +79,16 @@ static int sbi_ecall_rfence_handler(unsigned long extid, unsigned long funcid, return ret; } +struct sbi_ecall_extension ecall_rfence; + +static int sbi_ecall_rfence_register_extensions(void) +{ + return sbi_ecall_register_extension(&ecall_rfence); +} + struct sbi_ecall_extension ecall_rfence = { - .extid_start = SBI_EXT_RFENCE, - .extid_end = SBI_EXT_RFENCE, - .handle = sbi_ecall_rfence_handler, + .extid_start = SBI_EXT_RFENCE, + .extid_end = SBI_EXT_RFENCE, + .register_extensions = sbi_ecall_rfence_register_extensions, + .handle = sbi_ecall_rfence_handler, }; diff --git a/lib/sbi/sbi_ecall_srst.c b/lib/sbi/sbi_ecall_srst.c index 93b012ce024..ad31537604a 100644 --- a/lib/sbi/sbi_ecall_srst.c +++ b/lib/sbi/sbi_ecall_srst.c @@ -67,9 +67,17 @@ static int sbi_ecall_srst_probe(unsigned long extid, unsigned long *out_val) return 0; } +struct sbi_ecall_extension ecall_srst; + +static int sbi_ecall_srst_register_extensions(void) +{ + return sbi_ecall_register_extension(&ecall_srst); +} + struct sbi_ecall_extension ecall_srst = { - .extid_start = SBI_EXT_SRST, - .extid_end = SBI_EXT_SRST, - .handle = sbi_ecall_srst_handler, - .probe = sbi_ecall_srst_probe, + .extid_start = SBI_EXT_SRST, + .extid_end = SBI_EXT_SRST, + .register_extensions = sbi_ecall_srst_register_extensions, + .probe = sbi_ecall_srst_probe, + .handle = sbi_ecall_srst_handler, }; diff --git a/lib/sbi/sbi_ecall_susp.c b/lib/sbi/sbi_ecall_susp.c index f20126c49a6..bfbdbe64862 100644 --- a/lib/sbi/sbi_ecall_susp.c +++ b/lib/sbi/sbi_ecall_susp.c @@ -40,9 +40,17 @@ static int sbi_ecall_susp_probe(unsigned long extid, unsigned long *out_val) return 0; } +struct sbi_ecall_extension ecall_susp; + +static int sbi_ecall_susp_register_extensions(void) +{ + return sbi_ecall_register_extension(&ecall_susp); +} + struct sbi_ecall_extension ecall_susp = { - .extid_start = SBI_EXT_SUSP, - .extid_end = SBI_EXT_SUSP, - .handle = sbi_ecall_susp_handler, - .probe = sbi_ecall_susp_probe, + .extid_start = SBI_EXT_SUSP, + .extid_end = SBI_EXT_SUSP, + .register_extensions = sbi_ecall_susp_register_extensions, + .probe = sbi_ecall_susp_probe, + .handle = sbi_ecall_susp_handler, }; diff --git a/lib/sbi/sbi_ecall_time.c b/lib/sbi/sbi_ecall_time.c index 668cb17680c..e79196f77ad 100644 --- a/lib/sbi/sbi_ecall_time.c +++ b/lib/sbi/sbi_ecall_time.c @@ -33,8 +33,16 @@ static int sbi_ecall_time_handler(unsigned long extid, unsigned long funcid, return ret; } +struct sbi_ecall_extension ecall_time; + +static int sbi_ecall_time_register_extensions(void) +{ + return sbi_ecall_register_extension(&ecall_time); +} + struct sbi_ecall_extension ecall_time = { - .extid_start = SBI_EXT_TIME, - .extid_end = SBI_EXT_TIME, - .handle = sbi_ecall_time_handler, + .extid_start = SBI_EXT_TIME, + .extid_end = SBI_EXT_TIME, + .register_extensions = sbi_ecall_time_register_extensions, + .handle = sbi_ecall_time_handler, }; diff --git a/lib/sbi/sbi_ecall_vendor.c b/lib/sbi/sbi_ecall_vendor.c index 8b8dab00c92..126156f79a1 100644 --- a/lib/sbi/sbi_ecall_vendor.c +++ b/lib/sbi/sbi_ecall_vendor.c @@ -47,9 +47,17 @@ static int sbi_ecall_vendor_handler(unsigned long extid, unsigned long funcid, out_val, out_trap); } +struct sbi_ecall_extension ecall_vendor; + +static int sbi_ecall_vendor_register_extensions(void) +{ + return sbi_ecall_register_extension(&ecall_vendor); +} + struct sbi_ecall_extension ecall_vendor = { - .extid_start = SBI_EXT_VENDOR_START, - .extid_end = SBI_EXT_VENDOR_END, - .probe = sbi_ecall_vendor_probe, - .handle = sbi_ecall_vendor_handler, + .extid_start = SBI_EXT_VENDOR_START, + .extid_end = SBI_EXT_VENDOR_END, + .register_extensions = sbi_ecall_vendor_register_extensions, + .probe = sbi_ecall_vendor_probe, + .handle = sbi_ecall_vendor_handler, }; From e307ba7d464a8280e71195d79cc497e86d59b7fd Mon Sep 17 00:00:00 2001 From: Andrew Jones Date: Mon, 15 May 2023 13:12:35 +0200 Subject: [PATCH 118/187] lib: sbi: Narrow vendor extension range The vendor extension ID range is large, but at runtime at most a single ID will be available. Narrow the range in the register_extensions callback. After narrowing, we no longer need to check that the extension ID is correct in the other callbacks, as those callbacks will never be invoked with anything other than the single ID. Signed-off-by: Andrew Jones Reviewed-by: Anup Patel --- lib/sbi/sbi_ecall_vendor.c | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/lib/sbi/sbi_ecall_vendor.c b/lib/sbi/sbi_ecall_vendor.c index 126156f79a1..39c58c8b6fd 100644 --- a/lib/sbi/sbi_ecall_vendor.c +++ b/lib/sbi/sbi_ecall_vendor.c @@ -25,8 +25,7 @@ static inline unsigned long sbi_ecall_vendor_id(void) static int sbi_ecall_vendor_probe(unsigned long extid, unsigned long *out_val) { - if (!sbi_platform_vendor_ext_check(sbi_platform_thishart_ptr()) || - extid != sbi_ecall_vendor_id()) + if (!sbi_platform_vendor_ext_check(sbi_platform_thishart_ptr())) *out_val = 0; else *out_val = 1; @@ -38,8 +37,7 @@ static int sbi_ecall_vendor_handler(unsigned long extid, unsigned long funcid, unsigned long *out_val, struct sbi_trap_info *out_trap) { - if (!sbi_platform_vendor_ext_check(sbi_platform_thishart_ptr()) || - extid != sbi_ecall_vendor_id()) + if (!sbi_platform_vendor_ext_check(sbi_platform_thishart_ptr())) return SBI_ERR_NOT_SUPPORTED; return sbi_platform_vendor_ext_provider(sbi_platform_thishart_ptr(), @@ -51,6 +49,11 @@ struct sbi_ecall_extension ecall_vendor; static int sbi_ecall_vendor_register_extensions(void) { + unsigned long extid = sbi_ecall_vendor_id(); + + ecall_vendor.extid_start = extid; + ecall_vendor.extid_end = extid; + return sbi_ecall_register_extension(&ecall_vendor); } From 042f0c3ea25e995a6db93cd64964b816cb8ffba4 Mon Sep 17 00:00:00 2001 From: Andrew Jones Date: Mon, 15 May 2023 13:12:36 +0200 Subject: [PATCH 119/187] lib: sbi: pmu: Remove unnecessary probe function The absence of a probe implementation means that the extension is always available. Remove the implementation for the PMU extension, which does no checking, and indeed even has a comment saying it's always available. Signed-off-by: Andrew Jones Reviewed-by: Anup Patel --- lib/sbi/sbi_ecall_pmu.c | 8 -------- 1 file changed, 8 deletions(-) diff --git a/lib/sbi/sbi_ecall_pmu.c b/lib/sbi/sbi_ecall_pmu.c index b0589d0ecfa..1d5d512eeed 100644 --- a/lib/sbi/sbi_ecall_pmu.c +++ b/lib/sbi/sbi_ecall_pmu.c @@ -81,13 +81,6 @@ static int sbi_ecall_pmu_handler(unsigned long extid, unsigned long funcid, return ret; } -static int sbi_ecall_pmu_probe(unsigned long extid, unsigned long *out_val) -{ - /* PMU extension is always enabled */ - *out_val = 1; - return 0; -} - struct sbi_ecall_extension ecall_pmu; static int sbi_ecall_pmu_register_extensions(void) @@ -99,6 +92,5 @@ struct sbi_ecall_extension ecall_pmu = { .extid_start = SBI_EXT_PMU, .extid_end = SBI_EXT_PMU, .register_extensions = sbi_ecall_pmu_register_extensions, - .probe = sbi_ecall_pmu_probe, .handle = sbi_ecall_pmu_handler, }; From 8b952d4fcd4e1341ed7061bd01b8b12802031ea1 Mon Sep 17 00:00:00 2001 From: Andrew Jones Date: Mon, 15 May 2023 13:12:37 +0200 Subject: [PATCH 120/187] lib: sbi: Only register available extensions When an extension implements a probe function it means there's a chance that the extension is not available. Use this function in the register_extensions callback to determine if the extension should be registered at all. Where the probe implementation is simple, just open code the check. Signed-off-by: Andrew Jones Reviewed-by: Anup Patel --- lib/sbi/sbi_ecall_cppc.c | 3 +++ lib/sbi/sbi_ecall_dbcn.c | 3 +++ lib/sbi/sbi_ecall_srst.c | 6 ++++++ lib/sbi/sbi_ecall_susp.c | 6 ++++++ lib/sbi/sbi_ecall_vendor.c | 17 +++-------------- lib/sbi/sbi_init.c | 22 ++++++++++++++-------- 6 files changed, 35 insertions(+), 22 deletions(-) diff --git a/lib/sbi/sbi_ecall_cppc.c b/lib/sbi/sbi_ecall_cppc.c index 42ec744c22b..a6398ac7822 100644 --- a/lib/sbi/sbi_ecall_cppc.c +++ b/lib/sbi/sbi_ecall_cppc.c @@ -59,6 +59,9 @@ struct sbi_ecall_extension ecall_cppc; static int sbi_ecall_cppc_register_extensions(void) { + if (!sbi_cppc_get_device()) + return 0; + return sbi_ecall_register_extension(&ecall_cppc); } diff --git a/lib/sbi/sbi_ecall_dbcn.c b/lib/sbi/sbi_ecall_dbcn.c index 58b19e4468e..cbb2e802e61 100644 --- a/lib/sbi/sbi_ecall_dbcn.c +++ b/lib/sbi/sbi_ecall_dbcn.c @@ -68,6 +68,9 @@ struct sbi_ecall_extension ecall_dbcn; static int sbi_ecall_dbcn_register_extensions(void) { + if (!sbi_console_get_device()) + return 0; + return sbi_ecall_register_extension(&ecall_dbcn); } diff --git a/lib/sbi/sbi_ecall_srst.c b/lib/sbi/sbi_ecall_srst.c index ad31537604a..ea0dc73f010 100644 --- a/lib/sbi/sbi_ecall_srst.c +++ b/lib/sbi/sbi_ecall_srst.c @@ -71,6 +71,12 @@ struct sbi_ecall_extension ecall_srst; static int sbi_ecall_srst_register_extensions(void) { + unsigned long out_val; + + sbi_ecall_srst_probe(SBI_EXT_SRST, &out_val); + if (!out_val) + return 0; + return sbi_ecall_register_extension(&ecall_srst); } diff --git a/lib/sbi/sbi_ecall_susp.c b/lib/sbi/sbi_ecall_susp.c index bfbdbe64862..c4124046b92 100644 --- a/lib/sbi/sbi_ecall_susp.c +++ b/lib/sbi/sbi_ecall_susp.c @@ -44,6 +44,12 @@ struct sbi_ecall_extension ecall_susp; static int sbi_ecall_susp_register_extensions(void) { + unsigned long out_val; + + sbi_ecall_susp_probe(SBI_EXT_SUSP, &out_val); + if (!out_val) + return 0; + return sbi_ecall_register_extension(&ecall_susp); } diff --git a/lib/sbi/sbi_ecall_vendor.c b/lib/sbi/sbi_ecall_vendor.c index 39c58c8b6fd..700f475f0a8 100644 --- a/lib/sbi/sbi_ecall_vendor.c +++ b/lib/sbi/sbi_ecall_vendor.c @@ -22,24 +22,11 @@ static inline unsigned long sbi_ecall_vendor_id(void) (SBI_EXT_VENDOR_END - SBI_EXT_VENDOR_START)); } -static int sbi_ecall_vendor_probe(unsigned long extid, - unsigned long *out_val) -{ - if (!sbi_platform_vendor_ext_check(sbi_platform_thishart_ptr())) - *out_val = 0; - else - *out_val = 1; - return 0; -} - static int sbi_ecall_vendor_handler(unsigned long extid, unsigned long funcid, const struct sbi_trap_regs *regs, unsigned long *out_val, struct sbi_trap_info *out_trap) { - if (!sbi_platform_vendor_ext_check(sbi_platform_thishart_ptr())) - return SBI_ERR_NOT_SUPPORTED; - return sbi_platform_vendor_ext_provider(sbi_platform_thishart_ptr(), funcid, regs, out_val, out_trap); @@ -51,6 +38,9 @@ static int sbi_ecall_vendor_register_extensions(void) { unsigned long extid = sbi_ecall_vendor_id(); + if (!sbi_platform_vendor_ext_check(sbi_platform_thishart_ptr())) + return 0; + ecall_vendor.extid_start = extid; ecall_vendor.extid_end = extid; @@ -61,6 +51,5 @@ struct sbi_ecall_extension ecall_vendor = { .extid_start = SBI_EXT_VENDOR_START, .extid_end = SBI_EXT_VENDOR_END, .register_extensions = sbi_ecall_vendor_register_extensions, - .probe = sbi_ecall_vendor_probe, .handle = sbi_ecall_vendor_handler, }; diff --git a/lib/sbi/sbi_init.c b/lib/sbi/sbi_init.c index 539f8245c44..7c78d9bf706 100644 --- a/lib/sbi/sbi_init.c +++ b/lib/sbi/sbi_init.c @@ -323,12 +323,6 @@ static void __noreturn init_coldboot(struct sbi_scratch *scratch, u32 hartid) sbi_hart_hang(); } - rc = sbi_ecall_init(); - if (rc) { - sbi_printf("%s: ecall init failed (error %d)\n", __func__, rc); - sbi_hart_hang(); - } - /* * Note: Finalize domains after HSM initialization so that we * can startup non-root domains. @@ -350,8 +344,9 @@ static void __noreturn init_coldboot(struct sbi_scratch *scratch, u32 hartid) } /* - * Note: Platform final initialization should be last so that - * it sees correct domain assignment and PMP configuration. + * Note: Platform final initialization should be after finalizing + * domains so that it sees correct domain assignment and PMP + * configuration for FDT fixups. */ rc = sbi_platform_final_init(plat, true); if (rc) { @@ -360,6 +355,17 @@ static void __noreturn init_coldboot(struct sbi_scratch *scratch, u32 hartid) sbi_hart_hang(); } + /* + * Note: Ecall initialization should be after platform final + * initialization so that all available platform devices are + * already registered. + */ + rc = sbi_ecall_init(); + if (rc) { + sbi_printf("%s: ecall init failed (error %d)\n", __func__, rc); + sbi_hart_hang(); + } + sbi_boot_print_general(scratch); sbi_boot_print_domains(scratch); From 767b5fc4180a883497c081a95bb861a68651e9a6 Mon Sep 17 00:00:00 2001 From: Xiang W Date: Mon, 15 May 2023 13:12:38 +0200 Subject: [PATCH 121/187] lib: sbi: Optimize probe of srst/susp No need to do a fully comprehensive count, just find a supported reset or suspend type Signed-off-by: Xiang W Signed-off-by: Andrew Jones Reviewed-by: Anup Patel --- lib/sbi/sbi_ecall_srst.c | 10 ++++++---- lib/sbi/sbi_ecall_susp.c | 10 ++++++---- 2 files changed, 12 insertions(+), 8 deletions(-) diff --git a/lib/sbi/sbi_ecall_srst.c b/lib/sbi/sbi_ecall_srst.c index ea0dc73f010..fd2dc0d251f 100644 --- a/lib/sbi/sbi_ecall_srst.c +++ b/lib/sbi/sbi_ecall_srst.c @@ -50,7 +50,7 @@ static int sbi_ecall_srst_handler(unsigned long extid, unsigned long funcid, static int sbi_ecall_srst_probe(unsigned long extid, unsigned long *out_val) { - u32 type, count = 0; + u32 type; /* * At least one standard reset types should be supported by @@ -59,11 +59,13 @@ static int sbi_ecall_srst_probe(unsigned long extid, unsigned long *out_val) for (type = 0; type <= SBI_SRST_RESET_TYPE_LAST; type++) { if (sbi_system_reset_supported(type, - SBI_SRST_RESET_REASON_NONE)) - count++; + SBI_SRST_RESET_REASON_NONE)) { + *out_val = 1; + return 0; + } } - *out_val = (count) ? 1 : 0; + *out_val = 0; return 0; } diff --git a/lib/sbi/sbi_ecall_susp.c b/lib/sbi/sbi_ecall_susp.c index c4124046b92..716a6d585af 100644 --- a/lib/sbi/sbi_ecall_susp.c +++ b/lib/sbi/sbi_ecall_susp.c @@ -25,18 +25,20 @@ static int sbi_ecall_susp_handler(unsigned long extid, unsigned long funcid, static int sbi_ecall_susp_probe(unsigned long extid, unsigned long *out_val) { - u32 type, count = 0; + u32 type; /* * At least one suspend type should be supported by the * platform for the SBI SUSP extension to be usable. */ for (type = 0; type <= SBI_SUSP_SLEEP_TYPE_LAST; type++) { - if (sbi_system_suspend_supported(type)) - count++; + if (sbi_system_suspend_supported(type)) { + *out_val = 1; + return 0; + } } - *out_val = count ? 1 : 0; + *out_val = 0; return 0; } From c3e31cbf364e1c47392e57d31d055193946e866e Mon Sep 17 00:00:00 2001 From: Andrew Jones Date: Mon, 15 May 2023 13:12:39 +0200 Subject: [PATCH 122/187] lib: sbi: Remove 0/1 probe implementations When a probe implementation just returns zero for not available and one for available then we don't need it, as the extension won't be registered at all if it would return zero and the Base extension probe function will already set out_val to 1 if not probe function is implemented. Currently all probe functions only return zero or one, so remove them all. Signed-off-by: Andrew Jones Reviewed-by: Anup Patel --- lib/sbi/sbi_ecall_cppc.c | 7 ------- lib/sbi/sbi_ecall_dbcn.c | 7 ------- lib/sbi/sbi_ecall_srst.c | 18 +++++------------- lib/sbi/sbi_ecall_susp.c | 17 +++++------------ 4 files changed, 10 insertions(+), 39 deletions(-) diff --git a/lib/sbi/sbi_ecall_cppc.c b/lib/sbi/sbi_ecall_cppc.c index a6398ac7822..b54d54ec684 100644 --- a/lib/sbi/sbi_ecall_cppc.c +++ b/lib/sbi/sbi_ecall_cppc.c @@ -49,12 +49,6 @@ static int sbi_ecall_cppc_handler(unsigned long extid, unsigned long funcid, return ret; } -static int sbi_ecall_cppc_probe(unsigned long extid, unsigned long *out_val) -{ - *out_val = sbi_cppc_get_device() ? 1 : 0; - return 0; -} - struct sbi_ecall_extension ecall_cppc; static int sbi_ecall_cppc_register_extensions(void) @@ -69,6 +63,5 @@ struct sbi_ecall_extension ecall_cppc = { .extid_start = SBI_EXT_CPPC, .extid_end = SBI_EXT_CPPC, .register_extensions = sbi_ecall_cppc_register_extensions, - .probe = sbi_ecall_cppc_probe, .handle = sbi_ecall_cppc_handler, }; diff --git a/lib/sbi/sbi_ecall_dbcn.c b/lib/sbi/sbi_ecall_dbcn.c index cbb2e802e61..e0b892c2ed6 100644 --- a/lib/sbi/sbi_ecall_dbcn.c +++ b/lib/sbi/sbi_ecall_dbcn.c @@ -58,12 +58,6 @@ static int sbi_ecall_dbcn_handler(unsigned long extid, unsigned long funcid, return SBI_ENOTSUPP; } -static int sbi_ecall_dbcn_probe(unsigned long extid, unsigned long *out_val) -{ - *out_val = sbi_console_get_device() ? 1 : 0; - return 0; -} - struct sbi_ecall_extension ecall_dbcn; static int sbi_ecall_dbcn_register_extensions(void) @@ -78,6 +72,5 @@ struct sbi_ecall_extension ecall_dbcn = { .extid_start = SBI_EXT_DBCN, .extid_end = SBI_EXT_DBCN, .register_extensions = sbi_ecall_dbcn_register_extensions, - .probe = sbi_ecall_dbcn_probe, .handle = sbi_ecall_dbcn_handler, }; diff --git a/lib/sbi/sbi_ecall_srst.c b/lib/sbi/sbi_ecall_srst.c index fd2dc0d251f..dcd560d22f9 100644 --- a/lib/sbi/sbi_ecall_srst.c +++ b/lib/sbi/sbi_ecall_srst.c @@ -48,7 +48,7 @@ static int sbi_ecall_srst_handler(unsigned long extid, unsigned long funcid, return SBI_ENOTSUPP; } -static int sbi_ecall_srst_probe(unsigned long extid, unsigned long *out_val) +static bool srst_available(void) { u32 type; @@ -56,27 +56,20 @@ static int sbi_ecall_srst_probe(unsigned long extid, unsigned long *out_val) * At least one standard reset types should be supported by * the platform for SBI SRST extension to be usable. */ - for (type = 0; type <= SBI_SRST_RESET_TYPE_LAST; type++) { if (sbi_system_reset_supported(type, - SBI_SRST_RESET_REASON_NONE)) { - *out_val = 1; - return 0; - } + SBI_SRST_RESET_REASON_NONE)) + return true; } - *out_val = 0; - return 0; + return false; } struct sbi_ecall_extension ecall_srst; static int sbi_ecall_srst_register_extensions(void) { - unsigned long out_val; - - sbi_ecall_srst_probe(SBI_EXT_SRST, &out_val); - if (!out_val) + if (!srst_available()) return 0; return sbi_ecall_register_extension(&ecall_srst); @@ -86,6 +79,5 @@ struct sbi_ecall_extension ecall_srst = { .extid_start = SBI_EXT_SRST, .extid_end = SBI_EXT_SRST, .register_extensions = sbi_ecall_srst_register_extensions, - .probe = sbi_ecall_srst_probe, .handle = sbi_ecall_srst_handler, }; diff --git a/lib/sbi/sbi_ecall_susp.c b/lib/sbi/sbi_ecall_susp.c index 716a6d585af..2bfd99ae872 100644 --- a/lib/sbi/sbi_ecall_susp.c +++ b/lib/sbi/sbi_ecall_susp.c @@ -23,7 +23,7 @@ static int sbi_ecall_susp_handler(unsigned long extid, unsigned long funcid, return ret; } -static int sbi_ecall_susp_probe(unsigned long extid, unsigned long *out_val) +static bool susp_available(void) { u32 type; @@ -32,24 +32,18 @@ static int sbi_ecall_susp_probe(unsigned long extid, unsigned long *out_val) * platform for the SBI SUSP extension to be usable. */ for (type = 0; type <= SBI_SUSP_SLEEP_TYPE_LAST; type++) { - if (sbi_system_suspend_supported(type)) { - *out_val = 1; - return 0; - } + if (sbi_system_suspend_supported(type)) + return true; } - *out_val = 0; - return 0; + return false; } struct sbi_ecall_extension ecall_susp; static int sbi_ecall_susp_register_extensions(void) { - unsigned long out_val; - - sbi_ecall_susp_probe(SBI_EXT_SUSP, &out_val); - if (!out_val) + if (!susp_available()) return 0; return sbi_ecall_register_extension(&ecall_susp); @@ -59,6 +53,5 @@ struct sbi_ecall_extension ecall_susp = { .extid_start = SBI_EXT_SUSP, .extid_end = SBI_EXT_SUSP, .register_extensions = sbi_ecall_susp_register_extensions, - .probe = sbi_ecall_susp_probe, .handle = sbi_ecall_susp_handler, }; From 33f1722f2b6e1ad8f8bd0675271e3c7998d448c2 Mon Sep 17 00:00:00 2001 From: Andrew Jones Date: Mon, 15 May 2023 13:12:40 +0200 Subject: [PATCH 123/187] lib: sbi: Document sbi_ecall_extension members With the introduction of the register_extensions callback the range members (extid_start and extid_end) may now change and it has become a bit subtle as to when a probe function should be implemented. Document all the members and their relationship to the register_extensions callback. Signed-off-by: Andrew Jones Reviewed-by: Anup Patel --- include/sbi/sbi_ecall.h | 35 +++++++++++++++++++++++++++++++++++ 1 file changed, 35 insertions(+) diff --git a/include/sbi/sbi_ecall.h b/include/sbi/sbi_ecall.h index fac26429cf5..90f33bac0bc 100644 --- a/include/sbi/sbi_ecall.h +++ b/include/sbi/sbi_ecall.h @@ -21,11 +21,46 @@ struct sbi_trap_regs; struct sbi_trap_info; struct sbi_ecall_extension { + /* head is used by the extension list */ struct sbi_dlist head; + /* + * extid_start and extid_end specify the range for this extension. As + * the initial range may be wider than the valid runtime range, the + * register_extensions callback is responsible for narrowing the range + * before other callbacks may be invoked. + */ unsigned long extid_start; unsigned long extid_end; + /* + * register_extensions + * + * Calls sbi_ecall_register_extension() one or more times to register + * extension ID range(s) which should be handled by this extension. + * More than one sbi_ecall_extension struct and + * sbi_ecall_register_extension() call is necessary when the supported + * extension ID ranges have gaps. Additionally, extension availability + * must be checked before registering, which means, when this callback + * returns, only valid extension IDs from the initial range, which are + * also available, have been registered. + */ int (* register_extensions)(void); + /* + * probe + * + * Implements the Base extension's probe function for the extension. As + * the register_extensions callback ensures that no other extension + * callbacks will be invoked when the extension is not available, then + * probe can never fail. However, an extension may choose to set + * out_val to a nonzero value other than one. In those cases, it should + * implement this callback. + */ int (* probe)(unsigned long extid, unsigned long *out_val); + /* + * handle + * + * This is the extension handler. register_extensions ensures it is + * never invoked with an invalid or unavailable extension ID. + */ int (* handle)(unsigned long extid, unsigned long funcid, const struct sbi_trap_regs *regs, unsigned long *out_val, From d4c46e0ff1b0ead9d5a586e1a19a00a92160206d Mon Sep 17 00:00:00 2001 From: Filip Filmar Date: Tue, 16 May 2023 02:38:45 +0000 Subject: [PATCH 124/187] Makefile: Dereference symlinks on install Adds the `-L` flag (follow symlinks) to the `cp` commands used to install `libsbi.a` and `include/sbi/*`. This should make no difference in regular compilation. However, it does make a difference when compiling with bazel. Namely, bazel's sandboxing will turn all the source files into symlinks. After installation with `cp` the destination files will be symlinks pointing to the sandbox symlinks. As the sandbox files are removed when compilation ends, the just-copied symlinks become dangling symlinks. The resulting include files will be unusable due to the dangling symlink issues. Adding `-L` when copying ensures that the files obtained by executing the `install` targets are always dereferenced to files, rather than symlinks, eliminating this issue. Signed-off-by: Filip Filmar Reviewed-by: Xiang W Reviewed-by: Anup Patel --- Makefile | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/Makefile b/Makefile index a26a39baf12..730dbd910e5 100644 --- a/Makefile +++ b/Makefile @@ -401,10 +401,10 @@ merge_deps = $(CMD_PREFIX)mkdir -p `dirname $(1)`; \ cat $(2) > $(1) copy_file = $(CMD_PREFIX)mkdir -p `dirname $(1)`; \ echo " COPY $(subst $(build_dir)/,,$(1))"; \ - cp -f $(2) $(1) + cp -L -f $(2) $(1) inst_file = $(CMD_PREFIX)mkdir -p `dirname $(1)`; \ echo " INSTALL $(subst $(install_root_dir)/,,$(1))"; \ - cp -f $(2) $(1) + cp -L -f $(2) $(1) inst_file_list = $(CMD_PREFIX)if [ ! -z "$(4)" ]; then \ mkdir -p $(1)/$(3); \ for file in $(4) ; do \ @@ -413,12 +413,12 @@ inst_file_list = $(CMD_PREFIX)if [ ! -z "$(4)" ]; then \ dest_dir=`dirname $$dest_file`; \ echo " INSTALL "$(3)"/"`echo $$rel_file`; \ mkdir -p $$dest_dir; \ - cp -f $$file $$dest_file; \ + cp -L -f $$file $$dest_file; \ done \ fi inst_header_dir = $(CMD_PREFIX)mkdir -p $(1); \ echo " INSTALL $(subst $(install_root_dir)/,,$(1))"; \ - cp -rf $(2) $(1) + cp -L -rf $(2) $(1) compile_cpp_dep = $(CMD_PREFIX)mkdir -p `dirname $(1)`; \ echo " CPP-DEP $(subst $(build_dir)/,,$(1))"; \ printf %s `dirname $(1)`/ > $(1) && \ From 8b99a7f7d8294be29e18a667d51e13755ed2c0e0 Mon Sep 17 00:00:00 2001 From: Xiang W Date: Mon, 22 May 2023 13:18:06 +0800 Subject: [PATCH 125/187] lib: sbi: Fix return of sbi_console_init console is not a required peripheral. So it should return success when the console does not exist. Signed-off-by: Xiang W Reviewed-by: Anup Patel --- lib/sbi/sbi_console.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/lib/sbi/sbi_console.c b/lib/sbi/sbi_console.c index f3ac0033460..168dffd0642 100644 --- a/lib/sbi/sbi_console.c +++ b/lib/sbi/sbi_console.c @@ -481,5 +481,11 @@ void sbi_console_set_device(const struct sbi_console_device *dev) int sbi_console_init(struct sbi_scratch *scratch) { - return sbi_platform_console_init(sbi_platform_ptr(scratch)); + int rc = sbi_platform_console_init(sbi_platform_ptr(scratch)); + + /* console is not a necessary device */ + if (rc == SBI_ENODEV) + return 0; + + return rc; } From 264d0be1fdd93874bc8f4a365c911e15ec330ce5 Mon Sep 17 00:00:00 2001 From: Xiang W Date: Mon, 22 May 2023 13:18:07 +0800 Subject: [PATCH 126/187] lib: utils: Improve fdt_serial_init A final check of all DT nodes does not necessarily find a match, so SBI_ENODEV needs to be returned. Optimize removal of current_driver. Signed-off-by: Xiang W Reviewed-by: Anup Patel --- lib/utils/serial/fdt_serial.c | 48 +++++++++++++---------------------- 1 file changed, 17 insertions(+), 31 deletions(-) diff --git a/lib/utils/serial/fdt_serial.c b/lib/utils/serial/fdt_serial.c index 1a4bf9e87b6..0baa7228117 100644 --- a/lib/utils/serial/fdt_serial.c +++ b/lib/utils/serial/fdt_serial.c @@ -17,13 +17,6 @@ extern struct fdt_serial *fdt_serial_drivers[]; extern unsigned long fdt_serial_drivers_size; -static struct fdt_serial dummy = { - .match_table = NULL, - .init = NULL, -}; - -static struct fdt_serial *current_driver = &dummy; - int fdt_serial_init(void) { const void *prop; @@ -57,20 +50,15 @@ int fdt_serial_init(void) if (!match) continue; - if (drv->init) { - rc = drv->init(fdt, noff, match); - if (rc == SBI_ENODEV) - continue; - if (rc) - return rc; - } - current_driver = drv; - break; - } + /* drv->init must not be NULL */ + if (drv->init == NULL) + return SBI_EFAIL; - /* Check if we found desired driver */ - if (current_driver != &dummy) - goto done; + rc = drv->init(fdt, noff, match); + if (rc == SBI_ENODEV) + continue; + return rc; + } /* Lastly check all DT nodes */ for (pos = 0; pos < fdt_serial_drivers_size; pos++) { @@ -80,17 +68,15 @@ int fdt_serial_init(void) if (noff < 0) continue; - if (drv->init) { - rc = drv->init(fdt, noff, match); - if (rc == SBI_ENODEV) - continue; - if (rc) - return rc; - } - current_driver = drv; - break; + /* drv->init must not be NULL */ + if (drv->init == NULL) + return SBI_EFAIL; + + rc = drv->init(fdt, noff, match); + if (rc == SBI_ENODEV) + continue; + return rc; } -done: - return 0; + return SBI_ENODEV; } From 9a0bdd0c844ea87a7b83c313e1dd8e8152d508e7 Mon Sep 17 00:00:00 2001 From: Xiang W Date: Mon, 22 May 2023 13:18:08 +0800 Subject: [PATCH 127/187] lib: utils: Improve fdt_ipi Remove dummy driver. Optimize fdt_ipi_cold_init to exit the loop early. Signed-off-by: Xiang W Reviewed-by: Anup Patel --- lib/utils/ipi/fdt_ipi.c | 41 +++++++++++++++++++++-------------------- 1 file changed, 21 insertions(+), 20 deletions(-) diff --git a/lib/utils/ipi/fdt_ipi.c b/lib/utils/ipi/fdt_ipi.c index 66dc51082ed..7762ababe59 100644 --- a/lib/utils/ipi/fdt_ipi.c +++ b/lib/utils/ipi/fdt_ipi.c @@ -16,24 +16,17 @@ extern struct fdt_ipi *fdt_ipi_drivers[]; extern unsigned long fdt_ipi_drivers_size; -static struct fdt_ipi dummy = { - .match_table = NULL, - .cold_init = NULL, - .warm_init = NULL, - .exit = NULL, -}; - -static struct fdt_ipi *current_driver = &dummy; +static struct fdt_ipi *current_driver = NULL; void fdt_ipi_exit(void) { - if (current_driver->exit) + if (current_driver && current_driver->exit) current_driver->exit(); } static int fdt_ipi_warm_init(void) { - if (current_driver->warm_init) + if (current_driver && current_driver->warm_init) return current_driver->warm_init(); return 0; } @@ -51,20 +44,28 @@ static int fdt_ipi_cold_init(void) noff = -1; while ((noff = fdt_find_match(fdt, noff, drv->match_table, &match)) >= 0) { - if (drv->cold_init) { - rc = drv->cold_init(fdt, noff, match); - if (rc == SBI_ENODEV) - continue; - if (rc) - return rc; - } + /* drv->cold_init must not be NULL */ + if (drv->cold_init == NULL) + return SBI_EFAIL; + + rc = drv->cold_init(fdt, noff, match); + if (rc == SBI_ENODEV) + continue; + if (rc) + return rc; current_driver = drv; - } - if (current_driver != &dummy) - break; + /* + * We will have multiple IPI devices on multi-die or + * multi-socket systems so we cannot break here. + */ + } } + /* + * On some single-hart system there is no need for ipi, + * so we cannot return a failure here + */ return 0; } From 122f2260b350e94e4e79439ea289f08a329eb14a Mon Sep 17 00:00:00 2001 From: Xiang W Date: Mon, 22 May 2023 13:18:09 +0800 Subject: [PATCH 128/187] lib: utils: Improve fdt_timer Remove dummy driver. Optimize fdt_timer_cold_init to exit the loop early. Signed-off-by: Xiang W Reviewed-by: Anup Patel --- lib/utils/timer/fdt_timer.c | 41 +++++++++++++++++++------------------ 1 file changed, 21 insertions(+), 20 deletions(-) diff --git a/lib/utils/timer/fdt_timer.c b/lib/utils/timer/fdt_timer.c index 4695c0f02aa..62426a70fb0 100644 --- a/lib/utils/timer/fdt_timer.c +++ b/lib/utils/timer/fdt_timer.c @@ -16,24 +16,17 @@ extern struct fdt_timer *fdt_timer_drivers[]; extern unsigned long fdt_timer_drivers_size; -static struct fdt_timer dummy = { - .match_table = NULL, - .cold_init = NULL, - .warm_init = NULL, - .exit = NULL, -}; - -static struct fdt_timer *current_driver = &dummy; +static struct fdt_timer *current_driver = NULL; void fdt_timer_exit(void) { - if (current_driver->exit) + if (current_driver && current_driver->exit) current_driver->exit(); } static int fdt_timer_warm_init(void) { - if (current_driver->warm_init) + if (current_driver && current_driver->warm_init) return current_driver->warm_init(); return 0; } @@ -51,20 +44,28 @@ static int fdt_timer_cold_init(void) noff = -1; while ((noff = fdt_find_match(fdt, noff, drv->match_table, &match)) >= 0) { - if (drv->cold_init) { - rc = drv->cold_init(fdt, noff, match); - if (rc == SBI_ENODEV) - continue; - if (rc) - return rc; - } + /* drv->cold_init must not be NULL */ + if (drv->cold_init == NULL) + return SBI_EFAIL; + + rc = drv->cold_init(fdt, noff, match); + if (rc == SBI_ENODEV) + continue; + if (rc) + return rc; current_driver = drv; - } - if (current_driver != &dummy) - break; + /* + * We will have multiple timer devices on multi-die or + * multi-socket systems so we cannot break here. + */ + } } + /* + * We can't fail here since systems with Sstc might not provide + * mtimer/clint DT node in the device tree. + */ return 0; } From df75e0995689842b3022a4a8d4d69e980430c129 Mon Sep 17 00:00:00 2001 From: Heinrich Schuchardt Date: Mon, 29 May 2023 11:27:20 +0200 Subject: [PATCH 129/187] lib: utils/ipi: buffer overrun aclint_mswi_cold_init The parameter checks in aclint_mswi_cold_init() don't guard against a buffer overrun. mswi_hartid2data is defined as an array of SBI_HARTMASK_MAX_BITS entries. The current check allows mswi->hart_count = ACLINT_MSWI_MAX_HARTS mswi->first_hartid = SBI_HARTMASK_MAX_BITS - 1. With these values mswi_hartid2data will be accessed at index SBI_HARTMASK_MAX_BITS + SBI_HARTMASK_MAX_BITS - 2. We have to check the sum of mswi->first_hartid and mswi->hart_count. Furthermore mswi->hart_count = 0 would not make much sense. Addresses-Coverity-ID: 1529705 ("Out-of-bounds write") Fixes: 5a049fe1d6a5 ("lib: utils/ipi: Add ACLINT MSWI library") Signed-off-by: Heinrich Schuchardt Reviewed-by: Xiang W Reviewed-by: Anup Patel --- lib/utils/ipi/aclint_mswi.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/utils/ipi/aclint_mswi.c b/lib/utils/ipi/aclint_mswi.c index 6b004cb9efb..ac8570bc5fa 100644 --- a/lib/utils/ipi/aclint_mswi.c +++ b/lib/utils/ipi/aclint_mswi.c @@ -75,8 +75,8 @@ int aclint_mswi_cold_init(struct aclint_mswi_data *mswi) /* Sanity checks */ if (!mswi || (mswi->addr & (ACLINT_MSWI_ALIGN - 1)) || (mswi->size < (mswi->hart_count * sizeof(u32))) || - (mswi->first_hartid >= SBI_HARTMASK_MAX_BITS) || - (mswi->hart_count > ACLINT_MSWI_MAX_HARTS)) + (mswi->first_hartid + mswi->hart_count > SBI_HARTMASK_MAX_BITS) || + (!mswi->hart_count || mswi->hart_count > ACLINT_MSWI_MAX_HARTS)) return SBI_EINVAL; /* Update MSWI hartid table */ From bdde2ecd27af1ac158669809f6658376fb5137ab Mon Sep 17 00:00:00 2001 From: Andrew Jones Date: Thu, 1 Jun 2023 09:48:10 +0200 Subject: [PATCH 130/187] lib: sbi: Align system suspend errors with spec The spec says sbi_system_suspend() will return SBI_ERR_INVALID_PARAM when "sleep_type is reserved or is platform-specific and unimplemented" and SBI_ERR_NOT_SUPPORTED when sleep_type "is not reserved and is implemented, but the platform does not support it due to one or more missing dependencies." Ensure SBI_ERR_INVALID_PARAM is returned for reserved sleep types and that the system suspend driver can choose which of the two error types to return itself by returning an error from its check function rather than a boolean. Signed-off-by: Andrew Jones Reviewed-by: Anup Patel --- include/sbi/sbi_system.h | 9 ++++++++- lib/sbi/sbi_system.c | 14 ++++++++------ 2 files changed, 16 insertions(+), 7 deletions(-) diff --git a/include/sbi/sbi_system.h b/include/sbi/sbi_system.h index 33ff7f1a44a..0fdcc98cce5 100644 --- a/include/sbi/sbi_system.h +++ b/include/sbi/sbi_system.h @@ -48,7 +48,14 @@ struct sbi_system_suspend_device { /** Name of the system suspend device */ char name[32]; - /* Check whether sleep type is supported by the device */ + /** + * Check whether sleep type is supported by the device + * + * Returns 0 when @sleep_type supported, SBI_ERR_INVALID_PARAM + * when @sleep_type is reserved, or SBI_ERR_NOT_SUPPORTED when + * @sleep_type is not reserved and is implemented, but the + * platform doesn't support it due to missing dependencies. + */ int (*system_suspend_check)(u32 sleep_type); /** diff --git a/lib/sbi/sbi_system.c b/lib/sbi/sbi_system.c index 6933915a12e..d803ffa8418 100644 --- a/lib/sbi/sbi_system.c +++ b/lib/sbi/sbi_system.c @@ -111,7 +111,7 @@ void sbi_system_suspend_set_device(struct sbi_system_suspend_device *dev) static int sbi_system_suspend_test_check(u32 sleep_type) { - return sleep_type == SBI_SUSP_SLEEP_TYPE_SUSPEND; + return sleep_type == SBI_SUSP_SLEEP_TYPE_SUSPEND ? 0 : SBI_EINVAL; } static int sbi_system_suspend_test_suspend(u32 sleep_type, @@ -142,27 +142,29 @@ void sbi_system_suspend_test_enable(void) bool sbi_system_suspend_supported(u32 sleep_type) { return suspend_dev && suspend_dev->system_suspend_check && - suspend_dev->system_suspend_check(sleep_type); + suspend_dev->system_suspend_check(sleep_type) == 0; } int sbi_system_suspend(u32 sleep_type, ulong resume_addr, ulong opaque) { - int ret = SBI_ENOTSUPP; const struct sbi_domain *dom = sbi_domain_thishart_ptr(); struct sbi_scratch *scratch = sbi_scratch_thishart_ptr(); void (*jump_warmboot)(void) = (void (*)(void))scratch->warmboot_addr; unsigned int hartid = current_hartid(); unsigned long prev_mode; unsigned long i; + int ret; if (!dom || !dom->system_suspend_allowed) return SBI_EFAIL; - if (!suspend_dev || !suspend_dev->system_suspend) + if (!suspend_dev || !suspend_dev->system_suspend || + !suspend_dev->system_suspend_check) return SBI_EFAIL; - if (!sbi_system_suspend_supported(sleep_type)) - return SBI_ENOTSUPP; + ret = suspend_dev->system_suspend_check(sleep_type); + if (ret != SBI_OK) + return ret; prev_mode = (csr_read(CSR_MSTATUS) & MSTATUS_MPP) >> MSTATUS_MPP_SHIFT; if (prev_mode != PRV_S && prev_mode != PRV_U) From aad7a377051136c2e0f4adeea2689167a294d2b4 Mon Sep 17 00:00:00 2001 From: Anup Patel Date: Mon, 5 Jun 2023 12:22:37 +0530 Subject: [PATCH 131/187] include: sbi_scratch: Add helper macros to access data type Reading and writing a data type in scratch space is a very common use-case so let us add related helper macros in sbi_scratch.h. Signed-off-by: Anup Patel --- include/sbi/sbi_scratch.h | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/include/sbi/sbi_scratch.h b/include/sbi/sbi_scratch.h index 2966188d699..58f2d06b2d9 100644 --- a/include/sbi/sbi_scratch.h +++ b/include/sbi/sbi_scratch.h @@ -174,6 +174,23 @@ void sbi_scratch_free_offset(unsigned long offset); #define sbi_scratch_thishart_offset_ptr(offset) \ (void *)((char *)sbi_scratch_thishart_ptr() + (offset)) +/** Allocate offset for a data type in sbi_scratch */ +#define sbi_scratch_alloc_type_offset(__type) \ + sbi_scratch_alloc_offset(sizeof(__type)) + +/** Read a data type from sbi_scratch at given offset */ +#define sbi_scratch_read_type(__scratch, __type, __offset) \ +({ \ + *((__type *)sbi_scratch_offset_ptr((__scratch), (__offset))); \ +}) + +/** Write a data type to sbi_scratch at given offset */ +#define sbi_scratch_write_type(__scratch, __type, __offset, __ptr) \ +do { \ + *((__type *)sbi_scratch_offset_ptr((__scratch), (__offset))) \ + = (__type)(__ptr); \ +} while (0) + /** HART id to scratch table */ extern struct sbi_scratch *hartid_to_scratch_table[]; From 5cf9a540164a018a31a679578a27eb964af0340d Mon Sep 17 00:00:00 2001 From: Anup Patel Date: Mon, 17 Apr 2023 11:28:03 +0530 Subject: [PATCH 132/187] platform: Allow platforms to specify heap size We extend struct sbi_platform and struct sbi_scratch to allow platforms specify the heap size to the OpenSBI firmwares. The OpenSBI firmwares will use this information to determine the location of heap and provide heap base address in per-HART scratch space. Signed-off-by: Anup Patel Reviewed-by: Andrew Jones --- firmware/fw_base.S | 15 +++++++++++++++ include/sbi/sbi_platform.h | 18 +++++++++++++++--- include/sbi/sbi_scratch.h | 28 ++++++++++++++++++---------- platform/fpga/ariane/platform.c | 1 + platform/fpga/openpiton/platform.c | 2 ++ platform/generic/platform.c | 3 ++- platform/kendryte/k210/platform.c | 2 ++ platform/nuclei/ux600/platform.c | 2 ++ platform/template/platform.c | 1 + 9 files changed, 58 insertions(+), 14 deletions(-) diff --git a/firmware/fw_base.S b/firmware/fw_base.S index e37df095845..fff09e1365c 100644 --- a/firmware/fw_base.S +++ b/firmware/fw_base.S @@ -255,20 +255,28 @@ _bss_zero: /* Preload HART details * s7 -> HART Count * s8 -> HART Stack Size + * s9 -> Heap Size + * s10 -> Heap Offset */ lla a4, platform #if __riscv_xlen > 32 lwu s7, SBI_PLATFORM_HART_COUNT_OFFSET(a4) lwu s8, SBI_PLATFORM_HART_STACK_SIZE_OFFSET(a4) + lwu s9, SBI_PLATFORM_HEAP_SIZE_OFFSET(a4) #else lw s7, SBI_PLATFORM_HART_COUNT_OFFSET(a4) lw s8, SBI_PLATFORM_HART_STACK_SIZE_OFFSET(a4) + lw s9, SBI_PLATFORM_HEAP_SIZE_OFFSET(a4) #endif /* Setup scratch space for all the HARTs*/ lla tp, _fw_end mul a5, s7, s8 add tp, tp, a5 + /* Setup heap base address */ + lla s10, _fw_start + sub s10, tp, s10 + add tp, tp, s9 /* Keep a copy of tp */ add t3, tp, zero /* Counter */ @@ -283,8 +291,11 @@ _scratch_init: * t3 -> the firmware end address * s7 -> HART count * s8 -> HART stack size + * s9 -> Heap Size + * s10 -> Heap Offset */ add tp, t3, zero + sub tp, tp, s9 mul a5, s8, t1 sub tp, tp, a5 li a5, SBI_SCRATCH_SIZE @@ -302,6 +313,10 @@ _scratch_init: REG_L a5, 0(a4) REG_S a5, SBI_SCRATCH_FW_RW_OFFSET(tp) + /* Store fw_heap_offset and fw_heap_size in scratch space */ + REG_S s10, SBI_SCRATCH_FW_HEAP_OFFSET(tp) + REG_S s9, SBI_SCRATCH_FW_HEAP_SIZE_OFFSET(tp) + /* Store next arg1 in scratch space */ MOV_3R s0, a0, s1, a1, s2, a2 call fw_next_arg1 diff --git a/include/sbi/sbi_platform.h b/include/sbi/sbi_platform.h index 546c0a61acb..3e9616f6daf 100644 --- a/include/sbi/sbi_platform.h +++ b/include/sbi/sbi_platform.h @@ -29,12 +29,16 @@ #define SBI_PLATFORM_HART_COUNT_OFFSET (0x50) /** Offset of hart_stack_size in struct sbi_platform */ #define SBI_PLATFORM_HART_STACK_SIZE_OFFSET (0x54) +/** Offset of heap_size in struct sbi_platform */ +#define SBI_PLATFORM_HEAP_SIZE_OFFSET (0x58) +/** Offset of reserved in struct sbi_platform */ +#define SBI_PLATFORM_RESERVED_OFFSET (0x5c) /** Offset of platform_ops_addr in struct sbi_platform */ -#define SBI_PLATFORM_OPS_OFFSET (0x58) +#define SBI_PLATFORM_OPS_OFFSET (0x60) /** Offset of firmware_context in struct sbi_platform */ -#define SBI_PLATFORM_FIRMWARE_CONTEXT_OFFSET (0x58 + __SIZEOF_POINTER__) +#define SBI_PLATFORM_FIRMWARE_CONTEXT_OFFSET (0x60 + __SIZEOF_POINTER__) /** Offset of hart_index2id in struct sbi_platform */ -#define SBI_PLATFORM_HART_INDEX2ID_OFFSET (0x58 + (__SIZEOF_POINTER__ * 2)) +#define SBI_PLATFORM_HART_INDEX2ID_OFFSET (0x60 + (__SIZEOF_POINTER__ * 2)) #define SBI_PLATFORM_TLB_RANGE_FLUSH_LIMIT_DEFAULT (1UL << 12) @@ -138,6 +142,10 @@ struct sbi_platform_operations { /** Platform default per-HART stack size for exception/interrupt handling */ #define SBI_PLATFORM_DEFAULT_HART_STACK_SIZE 8192 +/** Platform default heap size */ +#define SBI_PLATFORM_DEFAULT_HEAP_SIZE(__num_hart) \ + (0x8000 + 0x800 * (__num_hart)) + /** Representation of a platform */ struct sbi_platform { /** @@ -160,6 +168,10 @@ struct sbi_platform { u32 hart_count; /** Per-HART stack size for exception/interrupt handling */ u32 hart_stack_size; + /** Size of heap shared by all HARTs */ + u32 heap_size; + /** Reserved for future use */ + u32 reserved; /** Pointer to sbi platform operations */ unsigned long platform_ops_addr; /** Pointer to system firmware specific context */ diff --git a/include/sbi/sbi_scratch.h b/include/sbi/sbi_scratch.h index 58f2d06b2d9..9894c704757 100644 --- a/include/sbi/sbi_scratch.h +++ b/include/sbi/sbi_scratch.h @@ -20,26 +20,30 @@ #define SBI_SCRATCH_FW_SIZE_OFFSET (1 * __SIZEOF_POINTER__) /** Offset (in sbi_scratch) of the R/W Offset */ #define SBI_SCRATCH_FW_RW_OFFSET (2 * __SIZEOF_POINTER__) +/** Offset of fw_heap_offset member in sbi_scratch */ +#define SBI_SCRATCH_FW_HEAP_OFFSET (3 * __SIZEOF_POINTER__) +/** Offset of fw_heap_size_offset member in sbi_scratch */ +#define SBI_SCRATCH_FW_HEAP_SIZE_OFFSET (4 * __SIZEOF_POINTER__) /** Offset of next_arg1 member in sbi_scratch */ -#define SBI_SCRATCH_NEXT_ARG1_OFFSET (3 * __SIZEOF_POINTER__) +#define SBI_SCRATCH_NEXT_ARG1_OFFSET (5 * __SIZEOF_POINTER__) /** Offset of next_addr member in sbi_scratch */ -#define SBI_SCRATCH_NEXT_ADDR_OFFSET (4 * __SIZEOF_POINTER__) +#define SBI_SCRATCH_NEXT_ADDR_OFFSET (6 * __SIZEOF_POINTER__) /** Offset of next_mode member in sbi_scratch */ -#define SBI_SCRATCH_NEXT_MODE_OFFSET (5 * __SIZEOF_POINTER__) +#define SBI_SCRATCH_NEXT_MODE_OFFSET (7 * __SIZEOF_POINTER__) /** Offset of warmboot_addr member in sbi_scratch */ -#define SBI_SCRATCH_WARMBOOT_ADDR_OFFSET (6 * __SIZEOF_POINTER__) +#define SBI_SCRATCH_WARMBOOT_ADDR_OFFSET (8 * __SIZEOF_POINTER__) /** Offset of platform_addr member in sbi_scratch */ -#define SBI_SCRATCH_PLATFORM_ADDR_OFFSET (7 * __SIZEOF_POINTER__) +#define SBI_SCRATCH_PLATFORM_ADDR_OFFSET (9 * __SIZEOF_POINTER__) /** Offset of hartid_to_scratch member in sbi_scratch */ -#define SBI_SCRATCH_HARTID_TO_SCRATCH_OFFSET (8 * __SIZEOF_POINTER__) +#define SBI_SCRATCH_HARTID_TO_SCRATCH_OFFSET (10 * __SIZEOF_POINTER__) /** Offset of trap_exit member in sbi_scratch */ -#define SBI_SCRATCH_TRAP_EXIT_OFFSET (9 * __SIZEOF_POINTER__) +#define SBI_SCRATCH_TRAP_EXIT_OFFSET (11 * __SIZEOF_POINTER__) /** Offset of tmp0 member in sbi_scratch */ -#define SBI_SCRATCH_TMP0_OFFSET (10 * __SIZEOF_POINTER__) +#define SBI_SCRATCH_TMP0_OFFSET (12 * __SIZEOF_POINTER__) /** Offset of options member in sbi_scratch */ -#define SBI_SCRATCH_OPTIONS_OFFSET (11 * __SIZEOF_POINTER__) +#define SBI_SCRATCH_OPTIONS_OFFSET (13 * __SIZEOF_POINTER__) /** Offset of extra space in sbi_scratch */ -#define SBI_SCRATCH_EXTRA_SPACE_OFFSET (12 * __SIZEOF_POINTER__) +#define SBI_SCRATCH_EXTRA_SPACE_OFFSET (14 * __SIZEOF_POINTER__) /** Maximum size of sbi_scratch (4KB) */ #define SBI_SCRATCH_SIZE (0x1000) @@ -57,6 +61,10 @@ struct sbi_scratch { unsigned long fw_size; /** Offset (in bytes) of the R/W section */ unsigned long fw_rw_offset; + /** Offset (in bytes) of the heap area */ + unsigned long fw_heap_offset; + /** Size (in bytes) of the heap area */ + unsigned long fw_heap_size; /** Arg1 (or 'a1' register) of next booting stage for this HART */ unsigned long next_arg1; /** Address of next booting stage for this HART */ diff --git a/platform/fpga/ariane/platform.c b/platform/fpga/ariane/platform.c index 1e341c2049f..975528f1372 100644 --- a/platform/fpga/ariane/platform.c +++ b/platform/fpga/ariane/platform.c @@ -185,5 +185,6 @@ const struct sbi_platform platform = { .features = SBI_PLATFORM_DEFAULT_FEATURES, .hart_count = ARIANE_HART_COUNT, .hart_stack_size = SBI_PLATFORM_DEFAULT_HART_STACK_SIZE, + .heap_size = SBI_PLATFORM_DEFAULT_HEAP_SIZE(ARIANE_HART_COUNT), .platform_ops_addr = (unsigned long)&platform_ops }; diff --git a/platform/fpga/openpiton/platform.c b/platform/fpga/openpiton/platform.c index 57ae6980924..e59dc992fe3 100644 --- a/platform/fpga/openpiton/platform.c +++ b/platform/fpga/openpiton/platform.c @@ -220,5 +220,7 @@ const struct sbi_platform platform = { .features = SBI_PLATFORM_DEFAULT_FEATURES, .hart_count = OPENPITON_DEFAULT_HART_COUNT, .hart_stack_size = SBI_PLATFORM_DEFAULT_HART_STACK_SIZE, + .heap_size = + SBI_PLATFORM_DEFAULT_HEAP_SIZE(OPENPITON_DEFAULT_HART_COUNT), .platform_ops_addr = (unsigned long)&platform_ops }; diff --git a/platform/generic/platform.c b/platform/generic/platform.c index eeefef4c953..0c9cd951817 100644 --- a/platform/generic/platform.c +++ b/platform/generic/platform.c @@ -115,7 +115,7 @@ unsigned long fw_platform_init(unsigned long arg0, unsigned long arg1, } platform.hart_count = hart_count; - + platform.heap_size = SBI_PLATFORM_DEFAULT_HEAP_SIZE(hart_count); platform_has_mlevel_imsic = fdt_check_imsic_mlevel(fdt); /* Return original FDT pointer */ @@ -315,5 +315,6 @@ struct sbi_platform platform = { .hart_count = SBI_HARTMASK_MAX_BITS, .hart_index2id = generic_hart_index2id, .hart_stack_size = SBI_PLATFORM_DEFAULT_HART_STACK_SIZE, + .heap_size = SBI_PLATFORM_DEFAULT_HEAP_SIZE(0), .platform_ops_addr = (unsigned long)&platform_ops }; diff --git a/platform/kendryte/k210/platform.c b/platform/kendryte/k210/platform.c index 7eb9015bb85..637a217fcd7 100644 --- a/platform/kendryte/k210/platform.c +++ b/platform/kendryte/k210/platform.c @@ -196,5 +196,7 @@ const struct sbi_platform platform = { .features = 0, .hart_count = K210_HART_COUNT, .hart_stack_size = SBI_PLATFORM_DEFAULT_HART_STACK_SIZE, + .heap_size = + SBI_PLATFORM_DEFAULT_HEAP_SIZE(K210_HART_COUNT), .platform_ops_addr = (unsigned long)&platform_ops }; diff --git a/platform/nuclei/ux600/platform.c b/platform/nuclei/ux600/platform.c index 4eccff15ee2..6fd6cd7082f 100644 --- a/platform/nuclei/ux600/platform.c +++ b/platform/nuclei/ux600/platform.c @@ -244,5 +244,7 @@ const struct sbi_platform platform = { .features = SBI_PLATFORM_DEFAULT_FEATURES, .hart_count = UX600_HART_COUNT, .hart_stack_size = SBI_PLATFORM_DEFAULT_HART_STACK_SIZE, + .heap_size = + SBI_PLATFORM_DEFAULT_HEAP_SIZE(UX600_HART_COUNT), .platform_ops_addr = (unsigned long)&platform_ops }; diff --git a/platform/template/platform.c b/platform/template/platform.c index 8adc431f1ce..86381ca2b70 100644 --- a/platform/template/platform.c +++ b/platform/template/platform.c @@ -152,5 +152,6 @@ const struct sbi_platform platform = { .features = SBI_PLATFORM_DEFAULT_FEATURES, .hart_count = 1, .hart_stack_size = SBI_PLATFORM_DEFAULT_HART_STACK_SIZE, + .heap_size = SBI_PLATFORM_DEFAULT_HEAP_SIZE(1), .platform_ops_addr = (unsigned long)&platform_ops }; From 40d36a6673131e36075b1df78af4d7ab92e8cc01 Mon Sep 17 00:00:00 2001 From: Anup Patel Date: Tue, 18 Apr 2023 18:38:21 +0530 Subject: [PATCH 133/187] lib: sbi: Introduce simple heap allocator We provide simple heap allocator to manage the heap space provided by OpenSBI firmware and platform. Signed-off-by: Anup Patel Reviewed-by: Andrew Jones --- include/sbi/sbi_heap.h | 44 +++++++++ lib/sbi/objects.mk | 1 + lib/sbi/sbi_heap.c | 206 +++++++++++++++++++++++++++++++++++++++++ lib/sbi/sbi_init.c | 15 +++ 4 files changed, 266 insertions(+) create mode 100644 include/sbi/sbi_heap.h create mode 100644 lib/sbi/sbi_heap.c diff --git a/include/sbi/sbi_heap.h b/include/sbi/sbi_heap.h new file mode 100644 index 00000000000..88d176ef0ed --- /dev/null +++ b/include/sbi/sbi_heap.h @@ -0,0 +1,44 @@ +/* + * SPDX-License-Identifier: BSD-2-Clause + * + * Copyright (c) 2023 Ventana Micro Systems Inc. + * + * Authors: + * Anup Patel + */ + +#ifndef __SBI_HEAP_H__ +#define __SBI_HEAP_H__ + +#include + +struct sbi_scratch; + +/** Allocate from heap area */ +void *sbi_malloc(size_t size); + +/** Zero allocate from heap area */ +void *sbi_zalloc(size_t size); + +/** Allocate array from heap area */ +static inline void *sbi_calloc(size_t nitems, size_t size) +{ + return sbi_zalloc(nitems * size); +} + +/** Free-up to heap area */ +void sbi_free(void *ptr); + +/** Amount (in bytes) of free space in the heap area */ +unsigned long sbi_heap_free_space(void); + +/** Amount (in bytes) of used space in the heap area */ +unsigned long sbi_heap_used_space(void); + +/** Amount (in bytes) of reserved space in the heap area */ +unsigned long sbi_heap_reserved_space(void); + +/** Initialize heap area */ +int sbi_heap_init(struct sbi_scratch *scratch); + +#endif diff --git a/lib/sbi/objects.mk b/lib/sbi/objects.mk index 7d691c61f0e..c6991870191 100644 --- a/lib/sbi/objects.mk +++ b/lib/sbi/objects.mk @@ -59,6 +59,7 @@ libsbi-objs-y += sbi_domain.o libsbi-objs-y += sbi_emulate_csr.o libsbi-objs-y += sbi_fifo.o libsbi-objs-y += sbi_hart.o +libsbi-objs-y += sbi_heap.o libsbi-objs-y += sbi_math.o libsbi-objs-y += sbi_hfence.o libsbi-objs-y += sbi_hsm.o diff --git a/lib/sbi/sbi_heap.c b/lib/sbi/sbi_heap.c new file mode 100644 index 00000000000..698c3775d99 --- /dev/null +++ b/lib/sbi/sbi_heap.c @@ -0,0 +1,206 @@ +/* + * SPDX-License-Identifier: BSD-2-Clause + * + * Copyright (c) 2023 Ventana Micro Systems Inc. + * + * Authors: + * Anup Patel + */ + +#include +#include +#include +#include +#include +#include + +/* Alignment of heap base address and size */ +#define HEAP_BASE_ALIGN 1024 +/* Minimum size and alignment of heap allocations */ +#define HEAP_ALLOC_ALIGN 64 +#define HEAP_HOUSEKEEPING_FACTOR 16 + +struct heap_node { + struct sbi_dlist head; + unsigned long addr; + unsigned long size; +}; + +struct heap_control { + spinlock_t lock; + unsigned long base; + unsigned long size; + unsigned long hkbase; + unsigned long hksize; + struct sbi_dlist free_node_list; + struct sbi_dlist free_space_list; + struct sbi_dlist used_space_list; +}; + +static struct heap_control hpctrl; + +void *sbi_malloc(size_t size) +{ + void *ret = NULL; + struct heap_node *n, *np; + + if (!size) + return NULL; + + size += HEAP_ALLOC_ALIGN - 1; + size &= ~((unsigned long)HEAP_ALLOC_ALIGN - 1); + + spin_lock(&hpctrl.lock); + + np = NULL; + sbi_list_for_each_entry(n, &hpctrl.free_space_list, head) { + if (size <= n->size) { + np = n; + break; + } + } + if (np) { + if ((size < np->size) && + !sbi_list_empty(&hpctrl.free_node_list)) { + n = sbi_list_first_entry(&hpctrl.free_node_list, + struct heap_node, head); + sbi_list_del(&n->head); + n->addr = np->addr + np->size - size; + n->size = size; + np->size -= size; + sbi_list_add_tail(&n->head, &hpctrl.used_space_list); + ret = (void *)n->addr; + } else if (size == np->size) { + sbi_list_del(&np->head); + sbi_list_add_tail(&np->head, &hpctrl.used_space_list); + ret = (void *)np->addr; + } + } + + spin_unlock(&hpctrl.lock); + + return ret; +} + +void *sbi_zalloc(size_t size) +{ + void *ret = sbi_malloc(size); + + if (ret) + sbi_memset(ret, 0, size); + return ret; +} + +void sbi_free(void *ptr) +{ + struct heap_node *n, *np; + + if (!ptr) + return; + + spin_lock(&hpctrl.lock); + + np = NULL; + sbi_list_for_each_entry(n, &hpctrl.used_space_list, head) { + if ((n->addr <= (unsigned long)ptr) && + ((unsigned long)ptr < (n->addr + n->size))) { + np = n; + break; + } + } + if (!np) { + spin_unlock(&hpctrl.lock); + return; + } + + sbi_list_del(&np->head); + + sbi_list_for_each_entry(n, &hpctrl.free_space_list, head) { + if ((np->addr + np->size) == n->addr) { + n->addr = np->addr; + n->size += np->size; + sbi_list_add_tail(&np->head, &hpctrl.free_node_list); + np = NULL; + break; + } else if (np->addr == (n->addr + n->size)) { + n->size += np->size; + sbi_list_add_tail(&np->head, &hpctrl.free_node_list); + np = NULL; + break; + } else if ((n->addr + n->size) < np->addr) { + sbi_list_add(&np->head, &n->head); + np = NULL; + break; + } + } + if (np) + sbi_list_add_tail(&np->head, &hpctrl.free_space_list); + + spin_unlock(&hpctrl.lock); +} + +unsigned long sbi_heap_free_space(void) +{ + struct heap_node *n; + unsigned long ret = 0; + + spin_lock(&hpctrl.lock); + sbi_list_for_each_entry(n, &hpctrl.free_space_list, head) + ret += n->size; + spin_unlock(&hpctrl.lock); + + return ret; +} + +unsigned long sbi_heap_used_space(void) +{ + return hpctrl.size - hpctrl.hksize - sbi_heap_free_space(); +} + +unsigned long sbi_heap_reserved_space(void) +{ + return hpctrl.hksize; +} + +int sbi_heap_init(struct sbi_scratch *scratch) +{ + unsigned long i; + struct heap_node *n; + + /* Sanity checks on heap offset and size */ + if (!scratch->fw_heap_size || + (scratch->fw_heap_size & (HEAP_BASE_ALIGN - 1)) || + (scratch->fw_heap_offset < scratch->fw_rw_offset) || + (scratch->fw_size < (scratch->fw_heap_offset + scratch->fw_heap_size)) || + (scratch->fw_heap_offset & (HEAP_BASE_ALIGN - 1))) + return SBI_EINVAL; + + /* Initialize heap control */ + SPIN_LOCK_INIT(hpctrl.lock); + hpctrl.base = scratch->fw_start + scratch->fw_heap_offset; + hpctrl.size = scratch->fw_heap_size; + hpctrl.hkbase = hpctrl.base; + hpctrl.hksize = hpctrl.size / HEAP_HOUSEKEEPING_FACTOR; + hpctrl.hksize &= ~((unsigned long)HEAP_BASE_ALIGN - 1); + SBI_INIT_LIST_HEAD(&hpctrl.free_node_list); + SBI_INIT_LIST_HEAD(&hpctrl.free_space_list); + SBI_INIT_LIST_HEAD(&hpctrl.used_space_list); + + /* Prepare free node list */ + for (i = 0; i < (hpctrl.hksize / sizeof(*n)); i++) { + n = (struct heap_node *)(hpctrl.hkbase + (sizeof(*n) * i)); + SBI_INIT_LIST_HEAD(&n->head); + n->addr = n->size = 0; + sbi_list_add_tail(&n->head, &hpctrl.free_node_list); + } + + /* Prepare free space list */ + n = sbi_list_first_entry(&hpctrl.free_node_list, + struct heap_node, head); + sbi_list_del(&n->head); + n->addr = hpctrl.hkbase + hpctrl.hksize; + n->size = hpctrl.size - hpctrl.hksize; + sbi_list_add_tail(&n->head, &hpctrl.free_space_list); + + return 0; +} diff --git a/lib/sbi/sbi_init.c b/lib/sbi/sbi_init.c index 7c78d9bf706..a1705254d9d 100644 --- a/lib/sbi/sbi_init.c +++ b/lib/sbi/sbi_init.c @@ -17,6 +17,7 @@ #include #include #include +#include #include #include #include @@ -118,6 +119,15 @@ static void sbi_boot_print_general(struct sbi_scratch *scratch) sbi_printf("Firmware Size : %d KB\n", (u32)(scratch->fw_size / 1024)); sbi_printf("Firmware RW Offset : 0x%lx\n", scratch->fw_rw_offset); + sbi_printf("Firmware RW Size : %d KB\n", + (u32)((scratch->fw_size - scratch->fw_rw_offset) / 1024)); + sbi_printf("Firmware Heap Offset : 0x%lx\n", scratch->fw_heap_offset); + sbi_printf("Firmware Heap Size : " + "%d KB (total), %d KB (reserved), %d KB (used), %d KB (free)\n", + (u32)(scratch->fw_heap_size / 1024), + (u32)(sbi_heap_reserved_space() / 1024), + (u32)(sbi_heap_used_space() / 1024), + (u32)(sbi_heap_free_space() / 1024)); /* SBI details */ sbi_printf("Runtime SBI Version : %d.%d\n", @@ -258,6 +268,11 @@ static void __noreturn init_coldboot(struct sbi_scratch *scratch, u32 hartid) sbi_hart_hang(); /* Note: This has to be second thing in coldboot init sequence */ + rc = sbi_heap_init(scratch); + if (rc) + sbi_hart_hang(); + + /* Note: This has to be the third thing in coldboot init sequence */ rc = sbi_domain_init(scratch, hartid); if (rc) sbi_hart_hang(); From 2a04f7037317c6c5b591b160a074c700de9b3378 Mon Sep 17 00:00:00 2001 From: Anup Patel Date: Thu, 20 Apr 2023 14:02:37 +0530 Subject: [PATCH 134/187] lib: sbi: Print scratch size and usage at boot time The scratch space being a scarce resource so let us print it's size and usage at boot time. Signed-off-by: Anup Patel Reviewed-by: Andrew Jones --- include/sbi/sbi_scratch.h | 3 +++ lib/sbi/sbi_init.c | 5 +++++ lib/sbi/sbi_scratch.c | 11 +++++++++++ 3 files changed, 19 insertions(+) diff --git a/include/sbi/sbi_scratch.h b/include/sbi/sbi_scratch.h index 9894c704757..48014923e36 100644 --- a/include/sbi/sbi_scratch.h +++ b/include/sbi/sbi_scratch.h @@ -175,6 +175,9 @@ unsigned long sbi_scratch_alloc_offset(unsigned long size); /** Free-up extra space in sbi_scratch */ void sbi_scratch_free_offset(unsigned long offset); +/** Amount (in bytes) of used space in in sbi_scratch */ +unsigned long sbi_scratch_used_space(void); + /** Get pointer from offset in sbi_scratch */ #define sbi_scratch_offset_ptr(scratch, offset) (void *)((char *)(scratch) + (offset)) diff --git a/lib/sbi/sbi_init.c b/lib/sbi/sbi_init.c index a1705254d9d..423e6d83650 100644 --- a/lib/sbi/sbi_init.c +++ b/lib/sbi/sbi_init.c @@ -128,6 +128,11 @@ static void sbi_boot_print_general(struct sbi_scratch *scratch) (u32)(sbi_heap_reserved_space() / 1024), (u32)(sbi_heap_used_space() / 1024), (u32)(sbi_heap_free_space() / 1024)); + sbi_printf("Firmware Scratch Size : " + "%d B (total), %d B (used), %d B (free)\n", + SBI_SCRATCH_SIZE, + (u32)sbi_scratch_used_space(), + (u32)(SBI_SCRATCH_SIZE - sbi_scratch_used_space())); /* SBI details */ sbi_printf("Runtime SBI Version : %d.%d\n", diff --git a/lib/sbi/sbi_scratch.c b/lib/sbi/sbi_scratch.c index 55ebdbb76a8..87ef84cafd3 100644 --- a/lib/sbi/sbi_scratch.c +++ b/lib/sbi/sbi_scratch.c @@ -97,3 +97,14 @@ void sbi_scratch_free_offset(unsigned long offset) * brain-dead allocator. */ } + +unsigned long sbi_scratch_used_space(void) +{ + unsigned long ret = 0; + + spin_lock(&extra_lock); + ret = extra_offset; + spin_unlock(&extra_lock); + + return ret; +} From bbff53fe3b6cdd3c9bc084d489640d7ee2a3f831 Mon Sep 17 00:00:00 2001 From: Anup Patel Date: Wed, 19 Apr 2023 13:40:19 +0530 Subject: [PATCH 135/187] lib: sbi_pmu: Use heap for per-HART PMU state Instead of using a global array for per-HART PMU state, we should use heap to on-demand allocate per-HART PMU state when the HART is initialized in cold boot or warm boot path. Signed-off-by: Anup Patel Reviewed-by: Andrew Jones --- lib/sbi/sbi_pmu.c | 215 +++++++++++++++++++++++++++------------------- 1 file changed, 127 insertions(+), 88 deletions(-) diff --git a/lib/sbi/sbi_pmu.c b/lib/sbi/sbi_pmu.c index 939f29d841e..c73e6ef3ff2 100644 --- a/lib/sbi/sbi_pmu.c +++ b/lib/sbi/sbi_pmu.c @@ -12,7 +12,7 @@ #include #include #include -#include +#include #include #include #include @@ -50,27 +50,43 @@ union sbi_pmu_ctr_info { }; }; -/* Platform specific PMU device */ -static const struct sbi_pmu_device *pmu_dev = NULL; - -/* Mapping between event range and possible counters */ -static struct sbi_pmu_hw_event hw_event_map[SBI_PMU_HW_EVENT_MAX] = {0}; - -/* counter to enabled event mapping */ -static uint32_t active_events[SBI_HARTMASK_MAX_BITS][SBI_PMU_HW_CTR_MAX + SBI_PMU_FW_CTR_MAX]; - -/* Bitmap of firmware counters started on each HART */ #if SBI_PMU_FW_CTR_MAX >= BITS_PER_LONG #error "Can't handle firmware counters beyond BITS_PER_LONG" #endif -static unsigned long fw_counters_started[SBI_HARTMASK_MAX_BITS]; -/* - * Counter values for SBI firmware events and event codes for platform - * firmware events. Both are mutually exclusive and hence can optimally share - * the same memory. - */ -static uint64_t fw_counters_data[SBI_HARTMASK_MAX_BITS][SBI_PMU_FW_CTR_MAX] = {0}; +/** Per-HART state of the PMU counters */ +struct sbi_pmu_hart_state { + /* HART to which this state belongs */ + uint32_t hartid; + /* Counter to enabled event mapping */ + uint32_t active_events[SBI_PMU_HW_CTR_MAX + SBI_PMU_FW_CTR_MAX]; + /* Bitmap of firmware counters started */ + unsigned long fw_counters_started; + /* + * Counter values for SBI firmware events and event codes + * for platform firmware events. Both are mutually exclusive + * and hence can optimally share the same memory. + */ + uint64_t fw_counters_data[SBI_PMU_FW_CTR_MAX]; +}; + +/** Offset of pointer to PMU HART state in scratch space */ +static unsigned long phs_ptr_offset; + +#define pmu_get_hart_state_ptr(__scratch) \ + sbi_scratch_read_type((__scratch), void *, phs_ptr_offset) + +#define pmu_thishart_state_ptr() \ + pmu_get_hart_state_ptr(sbi_scratch_thishart_ptr()) + +#define pmu_set_hart_state_ptr(__scratch, __phs) \ + sbi_scratch_write_type((__scratch), void *, phs_ptr_offset, (__phs)) + +/* Platform specific PMU device */ +static const struct sbi_pmu_device *pmu_dev = NULL; + +/* Mapping between event range and possible counters */ +static struct sbi_pmu_hw_event *hw_event_map; /* Maximum number of hardware events available */ static uint32_t num_hw_events; @@ -111,13 +127,13 @@ static bool pmu_event_select_overlap(struct sbi_pmu_hw_event *evt, return false; } -static int pmu_event_validate(unsigned long event_idx, uint64_t edata) +static int pmu_event_validate(struct sbi_pmu_hart_state *phs, + unsigned long event_idx, uint64_t edata) { uint32_t event_idx_type = get_cidx_type(event_idx); uint32_t event_idx_code = get_cidx_code(event_idx); uint32_t event_idx_code_max = -1; uint32_t cache_ops_result, cache_ops_id, cache_id; - u32 hartid = current_hartid(); switch(event_idx_type) { case SBI_PMU_EVENT_TYPE_HW: @@ -131,7 +147,7 @@ static int pmu_event_validate(unsigned long event_idx, uint64_t edata) if (SBI_PMU_FW_PLATFORM == event_idx_code && pmu_dev && pmu_dev->fw_event_validate_encoding) - return pmu_dev->fw_event_validate_encoding(hartid, + return pmu_dev->fw_event_validate_encoding(phs->hartid, edata); else event_idx_code_max = SBI_PMU_FW_MAX; @@ -165,16 +181,16 @@ static int pmu_event_validate(unsigned long event_idx, uint64_t edata) return SBI_EINVAL; } -static int pmu_ctr_validate(uint32_t cidx, uint32_t *event_idx_code) +static int pmu_ctr_validate(struct sbi_pmu_hart_state *phs, + uint32_t cidx, uint32_t *event_idx_code) { uint32_t event_idx_val; uint32_t event_idx_type; - u32 hartid = current_hartid(); if (cidx >= total_ctrs) return SBI_EINVAL; - event_idx_val = active_events[hartid][cidx]; + event_idx_val = phs->active_events[cidx]; event_idx_type = get_cidx_type(event_idx_val); if (event_idx_val == SBI_PMU_EVENT_IDX_INVALID || event_idx_type >= SBI_PMU_EVENT_TYPE_MAX) @@ -189,9 +205,9 @@ int sbi_pmu_ctr_fw_read(uint32_t cidx, uint64_t *cval) { int event_idx_type; uint32_t event_code; - u32 hartid = current_hartid(); + struct sbi_pmu_hart_state *phs = pmu_thishart_state_ptr(); - event_idx_type = pmu_ctr_validate(cidx, &event_code); + event_idx_type = pmu_ctr_validate(phs, cidx, &event_code); if (event_idx_type != SBI_PMU_EVENT_TYPE_FW) return SBI_EINVAL; @@ -202,13 +218,13 @@ int sbi_pmu_ctr_fw_read(uint32_t cidx, uint64_t *cval) if (SBI_PMU_FW_PLATFORM == event_code) { if (pmu_dev && pmu_dev->fw_counter_read_value) - *cval = pmu_dev->fw_counter_read_value(hartid, + *cval = pmu_dev->fw_counter_read_value(phs->hartid, cidx - num_hw_ctrs); else *cval = 0; } else - *cval = fw_counters_data[hartid][cidx - num_hw_ctrs]; + *cval = phs->fw_counters_data[cidx - num_hw_ctrs]; return 0; } @@ -376,12 +392,11 @@ int sbi_pmu_irq_bit(void) return 0; } -static int pmu_ctr_start_fw(uint32_t cidx, uint32_t event_code, +static int pmu_ctr_start_fw(struct sbi_pmu_hart_state *phs, + uint32_t cidx, uint32_t event_code, uint64_t event_data, uint64_t ival, bool ival_update) { - u32 hartid = current_hartid(); - if ((event_code >= SBI_PMU_FW_MAX && event_code <= SBI_PMU_FW_RESERVED_MAX) || event_code > SBI_PMU_FW_PLATFORM) @@ -395,18 +410,19 @@ static int pmu_ctr_start_fw(uint32_t cidx, uint32_t event_code, } if (ival_update) - pmu_dev->fw_counter_write_value(hartid, + pmu_dev->fw_counter_write_value(phs->hartid, cidx - num_hw_ctrs, ival); - return pmu_dev->fw_counter_start(hartid, cidx - num_hw_ctrs, + return pmu_dev->fw_counter_start(phs->hartid, + cidx - num_hw_ctrs, event_data); } else { if (ival_update) - fw_counters_data[hartid][cidx - num_hw_ctrs] = ival; + phs->fw_counters_data[cidx - num_hw_ctrs] = ival; } - fw_counters_started[hartid] |= BIT(cidx - num_hw_ctrs); + phs->fw_counters_started |= BIT(cidx - num_hw_ctrs); return 0; } @@ -414,7 +430,7 @@ static int pmu_ctr_start_fw(uint32_t cidx, uint32_t event_code, int sbi_pmu_ctr_start(unsigned long cbase, unsigned long cmask, unsigned long flags, uint64_t ival) { - u32 hartid = current_hartid(); + struct sbi_pmu_hart_state *phs = pmu_thishart_state_ptr(); int event_idx_type; uint32_t event_code; int ret = SBI_EINVAL; @@ -430,16 +446,16 @@ int sbi_pmu_ctr_start(unsigned long cbase, unsigned long cmask, for_each_set_bit(i, &cmask, total_ctrs) { cidx = i + cbase; - event_idx_type = pmu_ctr_validate(cidx, &event_code); + event_idx_type = pmu_ctr_validate(phs, cidx, &event_code); if (event_idx_type < 0) /* Continue the start operation for other counters */ continue; else if (event_idx_type == SBI_PMU_EVENT_TYPE_FW) { edata = (event_code == SBI_PMU_FW_PLATFORM) ? - fw_counters_data[hartid][cidx - num_hw_ctrs] + phs->fw_counters_data[cidx - num_hw_ctrs] : 0x0; - ret = pmu_ctr_start_fw(cidx, event_code, edata, ival, - bUpdate); + ret = pmu_ctr_start_fw(phs, cidx, event_code, edata, + ival, bUpdate); } else ret = pmu_ctr_start_hw(cidx, ival, bUpdate); @@ -470,9 +486,9 @@ static int pmu_ctr_stop_hw(uint32_t cidx) return SBI_EALREADY_STOPPED; } -static int pmu_ctr_stop_fw(uint32_t cidx, uint32_t event_code) +static int pmu_ctr_stop_fw(struct sbi_pmu_hart_state *phs, + uint32_t cidx, uint32_t event_code) { - u32 hartid = current_hartid(); int ret; if ((event_code >= SBI_PMU_FW_MAX && @@ -482,12 +498,12 @@ static int pmu_ctr_stop_fw(uint32_t cidx, uint32_t event_code) if (SBI_PMU_FW_PLATFORM == event_code && pmu_dev && pmu_dev->fw_counter_stop) { - ret = pmu_dev->fw_counter_stop(hartid, cidx - num_hw_ctrs); + ret = pmu_dev->fw_counter_stop(phs->hartid, cidx - num_hw_ctrs); if (ret) return ret; } - fw_counters_started[current_hartid()] &= ~BIT(cidx - num_hw_ctrs); + phs->fw_counters_started &= ~BIT(cidx - num_hw_ctrs); return 0; } @@ -511,7 +527,7 @@ static int pmu_reset_hw_mhpmevent(int ctr_idx) int sbi_pmu_ctr_stop(unsigned long cbase, unsigned long cmask, unsigned long flag) { - u32 hartid = current_hartid(); + struct sbi_pmu_hart_state *phs = pmu_thishart_state_ptr(); int ret = SBI_EINVAL; int event_idx_type; uint32_t event_code; @@ -522,18 +538,18 @@ int sbi_pmu_ctr_stop(unsigned long cbase, unsigned long cmask, for_each_set_bit(i, &cmask, total_ctrs) { cidx = i + cbase; - event_idx_type = pmu_ctr_validate(cidx, &event_code); + event_idx_type = pmu_ctr_validate(phs, cidx, &event_code); if (event_idx_type < 0) /* Continue the stop operation for other counters */ continue; else if (event_idx_type == SBI_PMU_EVENT_TYPE_FW) - ret = pmu_ctr_stop_fw(cidx, event_code); + ret = pmu_ctr_stop_fw(phs, cidx, event_code); else ret = pmu_ctr_stop_hw(cidx); if (cidx > (CSR_INSTRET - CSR_CYCLE) && flag & SBI_PMU_STOP_FLAG_RESET) { - active_events[hartid][cidx] = SBI_PMU_EVENT_IDX_INVALID; + phs->active_events[cidx] = SBI_PMU_EVENT_IDX_INVALID; pmu_reset_hw_mhpmevent(cidx); } } @@ -604,14 +620,15 @@ static int pmu_ctr_find_fixed_fw(unsigned long evt_idx_code) return SBI_EINVAL; } -static int pmu_ctr_find_hw(unsigned long cbase, unsigned long cmask, unsigned long flags, +static int pmu_ctr_find_hw(struct sbi_pmu_hart_state *phs, + unsigned long cbase, unsigned long cmask, + unsigned long flags, unsigned long event_idx, uint64_t data) { unsigned long ctr_mask; int i, ret = 0, fixed_ctr, ctr_idx = SBI_ENOTSUPP; struct sbi_pmu_hw_event *temp; unsigned long mctr_inhbt = 0; - u32 hartid = current_hartid(); struct sbi_scratch *scratch = sbi_scratch_thishart_ptr(); if (cbase >= num_hw_ctrs) @@ -650,7 +667,7 @@ static int pmu_ctr_find_hw(unsigned long cbase, unsigned long cmask, unsigned lo * Some of the platform may not support mcountinhibit. * Checking the active_events is enough for them */ - if (active_events[hartid][cbase] != SBI_PMU_EVENT_IDX_INVALID) + if (phs->active_events[cbase] != SBI_PMU_EVENT_IDX_INVALID) continue; /* If mcountinhibit is supported, the bit must be enabled */ if ((sbi_hart_priv_version(scratch) >= SBI_HART_PRIV_VER_1_11) && @@ -685,8 +702,9 @@ static int pmu_ctr_find_hw(unsigned long cbase, unsigned long cmask, unsigned lo * Thus, select the first available fw counter after sanity * check. */ -static int pmu_ctr_find_fw(unsigned long cbase, unsigned long cmask, - uint32_t event_code, u32 hartid, uint64_t edata) +static int pmu_ctr_find_fw(struct sbi_pmu_hart_state *phs, + unsigned long cbase, unsigned long cmask, + uint32_t event_code, uint64_t edata) { int i, cidx; @@ -699,11 +717,11 @@ static int pmu_ctr_find_fw(unsigned long cbase, unsigned long cmask, cidx = i + cbase; if (cidx < num_hw_ctrs || total_ctrs <= cidx) continue; - if (active_events[hartid][i] != SBI_PMU_EVENT_IDX_INVALID) + if (phs->active_events[i] != SBI_PMU_EVENT_IDX_INVALID) continue; if (SBI_PMU_FW_PLATFORM == event_code && pmu_dev && pmu_dev->fw_counter_match_encoding) { - if (!pmu_dev->fw_counter_match_encoding(hartid, + if (!pmu_dev->fw_counter_match_encoding(phs->hartid, cidx - num_hw_ctrs, edata)) continue; @@ -719,15 +737,15 @@ int sbi_pmu_ctr_cfg_match(unsigned long cidx_base, unsigned long cidx_mask, unsigned long flags, unsigned long event_idx, uint64_t event_data) { - int ret, ctr_idx = SBI_ENOTSUPP; - u32 event_code, hartid = current_hartid(); - int event_type; + struct sbi_pmu_hart_state *phs = pmu_thishart_state_ptr(); + int ret, event_type, ctr_idx = SBI_ENOTSUPP; + u32 event_code; /* Do a basic sanity check of counter base & mask */ if ((cidx_base + sbi_fls(cidx_mask)) >= total_ctrs) return SBI_EINVAL; - event_type = pmu_event_validate(event_idx, event_data); + event_type = pmu_event_validate(phs, event_idx, event_data); if (event_type < 0) return SBI_EINVAL; event_code = get_cidx_code(event_idx); @@ -742,7 +760,7 @@ int sbi_pmu_ctr_cfg_match(unsigned long cidx_base, unsigned long cidx_mask, */ unsigned long cidx_first = cidx_base + sbi_ffs(cidx_mask); - if (active_events[hartid][cidx_first] == SBI_PMU_EVENT_IDX_INVALID) + if (phs->active_events[cidx_first] == SBI_PMU_EVENT_IDX_INVALID) return SBI_EINVAL; ctr_idx = cidx_first; goto skip_match; @@ -750,20 +768,20 @@ int sbi_pmu_ctr_cfg_match(unsigned long cidx_base, unsigned long cidx_mask, if (event_type == SBI_PMU_EVENT_TYPE_FW) { /* Any firmware counter can be used track any firmware event */ - ctr_idx = pmu_ctr_find_fw(cidx_base, cidx_mask, event_code, - hartid, event_data); + ctr_idx = pmu_ctr_find_fw(phs, cidx_base, cidx_mask, + event_code, event_data); if (event_code == SBI_PMU_FW_PLATFORM) - fw_counters_data[hartid][ctr_idx - num_hw_ctrs] = + phs->fw_counters_data[ctr_idx - num_hw_ctrs] = event_data; } else { - ctr_idx = pmu_ctr_find_hw(cidx_base, cidx_mask, flags, event_idx, - event_data); + ctr_idx = pmu_ctr_find_hw(phs, cidx_base, cidx_mask, flags, + event_idx, event_data); } if (ctr_idx < 0) return SBI_ENOTSUPP; - active_events[hartid][ctr_idx] = event_idx; + phs->active_events[ctr_idx] = event_idx; skip_match: if (event_type == SBI_PMU_EVENT_TYPE_HW) { if (flags & SBI_PMU_CFG_FLAG_CLEAR_VALUE) @@ -772,16 +790,17 @@ int sbi_pmu_ctr_cfg_match(unsigned long cidx_base, unsigned long cidx_mask, pmu_ctr_start_hw(ctr_idx, 0, false); } else if (event_type == SBI_PMU_EVENT_TYPE_FW) { if (flags & SBI_PMU_CFG_FLAG_CLEAR_VALUE) - fw_counters_data[hartid][ctr_idx - num_hw_ctrs] = 0; + phs->fw_counters_data[ctr_idx - num_hw_ctrs] = 0; if (flags & SBI_PMU_CFG_FLAG_AUTO_START) { if (SBI_PMU_FW_PLATFORM == event_code && pmu_dev && pmu_dev->fw_counter_start) { - ret = pmu_dev->fw_counter_start(hartid, + ret = pmu_dev->fw_counter_start( + phs->hartid, ctr_idx - num_hw_ctrs, event_data); if (ret) return ret; } - fw_counters_started[hartid] |= BIT(ctr_idx - num_hw_ctrs); + phs->fw_counters_started |= BIT(ctr_idx - num_hw_ctrs); } } @@ -790,19 +809,20 @@ int sbi_pmu_ctr_cfg_match(unsigned long cidx_base, unsigned long cidx_mask, int sbi_pmu_ctr_incr_fw(enum sbi_pmu_fw_event_code_id fw_id) { - u32 cidx, hartid = current_hartid(); + u32 cidx; uint64_t *fcounter = NULL; + struct sbi_pmu_hart_state *phs = pmu_thishart_state_ptr(); - if (likely(!fw_counters_started[hartid])) + if (likely(!phs->fw_counters_started)) return 0; if (unlikely(fw_id >= SBI_PMU_FW_MAX)) return SBI_EINVAL; for (cidx = num_hw_ctrs; cidx < total_ctrs; cidx++) { - if (get_cidx_code(active_events[hartid][cidx]) == fw_id && - (fw_counters_started[hartid] & BIT(cidx - num_hw_ctrs))) { - fcounter = &fw_counters_data[hartid][cidx - num_hw_ctrs]; + if (get_cidx_code(phs->active_events[cidx]) == fw_id && + (phs->fw_counters_started & BIT(cidx - num_hw_ctrs))) { + fcounter = &phs->fw_counters_data[cidx - num_hw_ctrs]; break; } } @@ -854,16 +874,16 @@ int sbi_pmu_ctr_get_info(uint32_t cidx, unsigned long *ctr_info) return 0; } -static void pmu_reset_event_map(u32 hartid) +static void pmu_reset_event_map(struct sbi_pmu_hart_state *phs) { int j; /* Initialize the counter to event mapping table */ for (j = 3; j < total_ctrs; j++) - active_events[hartid][j] = SBI_PMU_EVENT_IDX_INVALID; + phs->active_events[j] = SBI_PMU_EVENT_IDX_INVALID; for (j = 0; j < SBI_PMU_FW_CTR_MAX; j++) - fw_counters_data[hartid][j] = 0; - fw_counters_started[hartid] = 0; + phs->fw_counters_data[j] = 0; + phs->fw_counters_started = 0; } const struct sbi_pmu_device *sbi_pmu_get_device(void) @@ -881,22 +901,32 @@ void sbi_pmu_set_device(const struct sbi_pmu_device *dev) void sbi_pmu_exit(struct sbi_scratch *scratch) { - u32 hartid = current_hartid(); - if (sbi_hart_priv_version(scratch) >= SBI_HART_PRIV_VER_1_11) csr_write(CSR_MCOUNTINHIBIT, 0xFFFFFFF8); if (sbi_hart_priv_version(scratch) >= SBI_HART_PRIV_VER_1_10) csr_write(CSR_MCOUNTEREN, -1); - pmu_reset_event_map(hartid); + + pmu_reset_event_map(pmu_get_hart_state_ptr(scratch)); } int sbi_pmu_init(struct sbi_scratch *scratch, bool cold_boot) { + struct sbi_pmu_hart_state *phs; const struct sbi_platform *plat; - u32 hartid = current_hartid(); if (cold_boot) { + hw_event_map = sbi_calloc(sizeof(*hw_event_map), + SBI_PMU_HW_EVENT_MAX); + if (!hw_event_map) + return SBI_ENOMEM; + + phs_ptr_offset = sbi_scratch_alloc_type_offset(void *); + if (!phs_ptr_offset) { + sbi_free(hw_event_map); + return SBI_ENOMEM; + } + plat = sbi_platform_ptr(scratch); /* Initialize hw pmu events */ sbi_platform_pmu_init(plat); @@ -906,14 +936,23 @@ int sbi_pmu_init(struct sbi_scratch *scratch, bool cold_boot) total_ctrs = num_hw_ctrs + SBI_PMU_FW_CTR_MAX; } - pmu_reset_event_map(hartid); + phs = pmu_get_hart_state_ptr(scratch); + if (!phs) { + phs = sbi_zalloc(sizeof(*phs)); + if (!phs) + return SBI_ENOMEM; + phs->hartid = current_hartid(); + pmu_set_hart_state_ptr(scratch, phs); + } + + pmu_reset_event_map(phs); /* First three counters are fixed by the priv spec and we enable it by default */ - active_events[hartid][0] = SBI_PMU_EVENT_TYPE_HW << SBI_PMU_EVENT_IDX_TYPE_OFFSET | - SBI_PMU_HW_CPU_CYCLES; - active_events[hartid][1] = SBI_PMU_EVENT_IDX_INVALID; - active_events[hartid][2] = SBI_PMU_EVENT_TYPE_HW << SBI_PMU_EVENT_IDX_TYPE_OFFSET | - SBI_PMU_HW_INSTRUCTIONS; + phs->active_events[0] = (SBI_PMU_EVENT_TYPE_HW << SBI_PMU_EVENT_IDX_TYPE_OFFSET) | + SBI_PMU_HW_CPU_CYCLES; + phs->active_events[1] = SBI_PMU_EVENT_IDX_INVALID; + phs->active_events[2] = (SBI_PMU_EVENT_TYPE_HW << SBI_PMU_EVENT_IDX_TYPE_OFFSET) | + SBI_PMU_HW_INSTRUCTIONS; return 0; } From ef4542dc1363038676e688cf3cb5edd174f65d76 Mon Sep 17 00:00:00 2001 From: Anup Patel Date: Fri, 21 Apr 2023 13:48:37 +0530 Subject: [PATCH 136/187] lib: sbi: Use heap for root domain creation Let's use heap allocation in root domain creation instead of using a fixed size global array. Signed-off-by: Anup Patel Reviewed-by: Andrew Jones --- lib/sbi/sbi_domain.c | 45 +++++++++++++++++++++++++++++++++----------- 1 file changed, 34 insertions(+), 11 deletions(-) diff --git a/lib/sbi/sbi_domain.c b/lib/sbi/sbi_domain.c index c55e192207d..5800870ae65 100644 --- a/lib/sbi/sbi_domain.c +++ b/lib/sbi/sbi_domain.c @@ -11,6 +11,7 @@ #include #include #include +#include #include #include #include @@ -26,16 +27,13 @@ struct sbi_domain *hartid_to_domain_table[SBI_HARTMASK_MAX_BITS] = { 0 }; static u32 domain_count = 0; static bool domain_finalized = false; -static struct sbi_hartmask root_hmask = { 0 }; - #define ROOT_REGION_MAX 16 static u32 root_memregs_count = 0; -static struct sbi_domain_memregion root_memregs[ROOT_REGION_MAX + 1] = { 0 }; struct sbi_domain root = { .name = "root", - .possible_harts = &root_hmask, - .regions = root_memregs, + .possible_harts = NULL, + .regions = NULL, .system_reset_allowed = true, .system_suspend_allowed = true, .fw_region_inited = false, @@ -551,8 +549,7 @@ int sbi_domain_root_add_memregion(const struct sbi_domain_memregion *reg) const struct sbi_platform *plat = sbi_platform_thishart_ptr(); /* Sanity checks */ - if (!reg || domain_finalized || - (root.regions != root_memregs) || + if (!reg || domain_finalized || !root.regions || (ROOT_REGION_MAX <= root_memregs_count)) return SBI_EINVAL; @@ -567,10 +564,10 @@ int sbi_domain_root_add_memregion(const struct sbi_domain_memregion *reg) } /* Append the memregion to root memregions */ - nreg = &root_memregs[root_memregs_count]; + nreg = &root.regions[root_memregs_count]; sbi_memcpy(nreg, reg, sizeof(*reg)); root_memregs_count++; - root_memregs[root_memregs_count].order = 0; + root.regions[root_memregs_count].order = 0; /* Sort and optimize root regions */ do { @@ -700,6 +697,9 @@ int sbi_domain_finalize(struct sbi_scratch *scratch, u32 cold_hartid) int sbi_domain_init(struct sbi_scratch *scratch, u32 cold_hartid) { u32 i; + int rc; + struct sbi_hartmask *root_hmask; + struct sbi_domain_memregion *root_memregs; const struct sbi_platform *plat = sbi_platform_ptr(scratch); if (scratch->fw_rw_offset == 0 || @@ -715,6 +715,21 @@ int sbi_domain_init(struct sbi_scratch *scratch, u32 cold_hartid) return SBI_EINVAL; } + root_memregs = sbi_calloc(sizeof(*root_memregs), ROOT_REGION_MAX + 1); + if (!root_memregs) { + sbi_printf("%s: no memory for root regions\n", __func__); + return SBI_ENOMEM; + } + root.regions = root_memregs; + + root_hmask = sbi_zalloc(sizeof(*root_hmask)); + if (!root_hmask) { + sbi_printf("%s: no memory for root hartmask\n", __func__); + sbi_free(root_memregs); + return SBI_ENOMEM; + } + root.possible_harts = root_hmask; + /* Root domain firmware memory region */ sbi_domain_memregion_init(scratch->fw_start, scratch->fw_rw_offset, (SBI_DOMAIN_MEMREGION_M_READABLE | @@ -751,8 +766,16 @@ int sbi_domain_init(struct sbi_scratch *scratch, u32 cold_hartid) for (i = 0; i < SBI_HARTMASK_MAX_BITS; i++) { if (sbi_platform_hart_invalid(plat, i)) continue; - sbi_hartmask_set_hart(i, &root_hmask); + sbi_hartmask_set_hart(i, root_hmask); + } + + /* Finally register the root domain */ + rc = sbi_domain_register(&root, root_hmask); + if (rc) { + sbi_free(root_hmask); + sbi_free(root_memregs); + return rc; } - return sbi_domain_register(&root, &root_hmask); + return 0; } From 66daafe3ba210eec78900269817ee504ffa9c212 Mon Sep 17 00:00:00 2001 From: Anup Patel Date: Tue, 25 Apr 2023 09:12:36 +0530 Subject: [PATCH 137/187] lib: sbi: Use scratch space to save per-HART domain pointer Instead of using a global array indexed by hartid, we should use scratch space to save per-HART domain pointer. Signed-off-by: Anup Patel Reviewed-by: Andrew Jones --- include/sbi/sbi_domain.h | 6 +---- lib/sbi/sbi_domain.c | 55 ++++++++++++++++++++++++++++++++-------- 2 files changed, 45 insertions(+), 16 deletions(-) diff --git a/include/sbi/sbi_domain.h b/include/sbi/sbi_domain.h index 124ea90b9db..b05bcf4d1c9 100644 --- a/include/sbi/sbi_domain.h +++ b/include/sbi/sbi_domain.h @@ -129,12 +129,8 @@ struct sbi_domain { /** The root domain instance */ extern struct sbi_domain root; -/** HART id to domain table */ -extern struct sbi_domain *hartid_to_domain_table[]; - /** Get pointer to sbi_domain from HART id */ -#define sbi_hartid_to_domain(__hartid) \ - hartid_to_domain_table[__hartid] +struct sbi_domain *sbi_hartid_to_domain(u32 hartid); /** Get pointer to sbi_domain for current HART */ #define sbi_domain_thishart_ptr() \ diff --git a/lib/sbi/sbi_domain.c b/lib/sbi/sbi_domain.c index 5800870ae65..38a5902ff47 100644 --- a/lib/sbi/sbi_domain.c +++ b/lib/sbi/sbi_domain.c @@ -23,7 +23,6 @@ * the array to be null-terminated. */ struct sbi_domain *domidx_to_domain_table[SBI_DOMAIN_MAX_INDEX + 1] = { 0 }; -struct sbi_domain *hartid_to_domain_table[SBI_HARTMASK_MAX_BITS] = { 0 }; static u32 domain_count = 0; static bool domain_finalized = false; @@ -39,6 +38,30 @@ struct sbi_domain root = { .fw_region_inited = false, }; +static unsigned long domain_hart_ptr_offset; + +struct sbi_domain *sbi_hartid_to_domain(u32 hartid) +{ + struct sbi_scratch *scratch; + + scratch = sbi_hartid_to_scratch(hartid); + if (!scratch || !domain_hart_ptr_offset) + return NULL; + + return sbi_scratch_read_type(scratch, void *, domain_hart_ptr_offset); +} + +static void update_hartid_to_domain(u32 hartid, struct sbi_domain *dom) +{ + struct sbi_scratch *scratch; + + scratch = sbi_hartid_to_scratch(hartid); + if (!scratch) + return; + + sbi_scratch_write_type(scratch, void *, domain_hart_ptr_offset, dom); +} + bool sbi_domain_is_assigned_hart(const struct sbi_domain *dom, u32 hartid) { if (dom) @@ -519,11 +542,11 @@ int sbi_domain_register(struct sbi_domain *dom, if (!sbi_hartmask_test_hart(i, dom->possible_harts)) continue; - tdom = hartid_to_domain_table[i]; + tdom = sbi_hartid_to_domain(i); if (tdom) sbi_hartmask_clear_hart(i, &tdom->assigned_harts); - hartid_to_domain_table[i] = dom; + update_hartid_to_domain(i, dom); sbi_hartmask_set_hart(i, &dom->assigned_harts); /* @@ -715,18 +738,23 @@ int sbi_domain_init(struct sbi_scratch *scratch, u32 cold_hartid) return SBI_EINVAL; } + domain_hart_ptr_offset = sbi_scratch_alloc_type_offset(void *); + if (!domain_hart_ptr_offset) + return SBI_ENOMEM; + root_memregs = sbi_calloc(sizeof(*root_memregs), ROOT_REGION_MAX + 1); if (!root_memregs) { sbi_printf("%s: no memory for root regions\n", __func__); - return SBI_ENOMEM; + rc = SBI_ENOMEM; + goto fail_free_domain_hart_ptr_offset; } root.regions = root_memregs; root_hmask = sbi_zalloc(sizeof(*root_hmask)); if (!root_hmask) { sbi_printf("%s: no memory for root hartmask\n", __func__); - sbi_free(root_memregs); - return SBI_ENOMEM; + rc = SBI_ENOMEM; + goto fail_free_root_memregs; } root.possible_harts = root_hmask; @@ -771,11 +799,16 @@ int sbi_domain_init(struct sbi_scratch *scratch, u32 cold_hartid) /* Finally register the root domain */ rc = sbi_domain_register(&root, root_hmask); - if (rc) { - sbi_free(root_hmask); - sbi_free(root_memregs); - return rc; - } + if (rc) + goto fail_free_root_hmask; return 0; + +fail_free_root_hmask: + sbi_free(root_hmask); +fail_free_root_memregs: + sbi_free(root_memregs); +fail_free_domain_hart_ptr_offset: + sbi_scratch_free_offset(domain_hart_ptr_offset); + return rc; } From fa5ad2e6f9e9c77b69cdf2506da753c8bad9509d Mon Sep 17 00:00:00 2001 From: Anup Patel Date: Wed, 19 Apr 2023 16:49:19 +0530 Subject: [PATCH 138/187] lib: utils/gpio: Use heap in SiFive and StartFive GPIO drivers Let's use heap allocation in SiFive and Starfive GPIO drivers instead of using a fixed size global array. Signed-off-by: Anup Patel Reviewed-by: Andrew Jones --- lib/utils/gpio/fdt_gpio_sifive.c | 21 ++++++++++----------- lib/utils/gpio/fdt_gpio_starfive.c | 20 ++++++++++---------- 2 files changed, 20 insertions(+), 21 deletions(-) diff --git a/lib/utils/gpio/fdt_gpio_sifive.c b/lib/utils/gpio/fdt_gpio_sifive.c index 677f0fa78b6..5e3f39d77b9 100644 --- a/lib/utils/gpio/fdt_gpio_sifive.c +++ b/lib/utils/gpio/fdt_gpio_sifive.c @@ -9,11 +9,10 @@ #include #include +#include #include #include -#define SIFIVE_GPIO_CHIP_MAX 2 - #define SIFIVE_GPIO_PINS_MIN 1 #define SIFIVE_GPIO_PINS_MAX 32 #define SIFIVE_GPIO_PINS_DEF 16 @@ -27,9 +26,6 @@ struct sifive_gpio_chip { struct gpio_chip chip; }; -static unsigned int sifive_gpio_chip_count; -static struct sifive_gpio_chip sifive_gpio_chip_array[SIFIVE_GPIO_CHIP_MAX]; - static int sifive_gpio_direction_output(struct gpio_pin *gp, int value) { unsigned int v; @@ -73,13 +69,15 @@ static int sifive_gpio_init(void *fdt, int nodeoff, u32 phandle, struct sifive_gpio_chip *chip; uint64_t addr; - if (SIFIVE_GPIO_CHIP_MAX <= sifive_gpio_chip_count) - return SBI_ENOSPC; - chip = &sifive_gpio_chip_array[sifive_gpio_chip_count]; + chip = sbi_zalloc(sizeof(*chip)); + if (!chip) + return SBI_ENOMEM; rc = fdt_get_node_addr_size(fdt, nodeoff, 0, &addr, NULL); - if (rc) + if (rc) { + sbi_free(chip); return rc; + } chip->addr = addr; chip->chip.driver = &fdt_gpio_sifive; @@ -88,10 +86,11 @@ static int sifive_gpio_init(void *fdt, int nodeoff, u32 phandle, chip->chip.direction_output = sifive_gpio_direction_output; chip->chip.set = sifive_gpio_set; rc = gpio_chip_add(&chip->chip); - if (rc) + if (rc) { + sbi_free(chip); return rc; + } - sifive_gpio_chip_count++; return 0; } diff --git a/lib/utils/gpio/fdt_gpio_starfive.c b/lib/utils/gpio/fdt_gpio_starfive.c index 18cca72aa89..f430b1352c9 100644 --- a/lib/utils/gpio/fdt_gpio_starfive.c +++ b/lib/utils/gpio/fdt_gpio_starfive.c @@ -9,11 +9,11 @@ #include #include +#include #include #include #include -#define STARFIVE_GPIO_CHIP_MAX 2 #define STARFIVE_GPIO_PINS_DEF 64 #define STARFIVE_GPIO_OUTVAL 0x40 #define STARFIVE_GPIO_MASK 0xff @@ -25,9 +25,6 @@ struct starfive_gpio_chip { struct gpio_chip chip; }; -static unsigned int starfive_gpio_chip_count; -static struct starfive_gpio_chip starfive_gpio_chip_array[STARFIVE_GPIO_CHIP_MAX]; - static int starfive_gpio_direction_output(struct gpio_pin *gp, int value) { u32 val; @@ -82,13 +79,15 @@ static int starfive_gpio_init(void *fdt, int nodeoff, u32 phandle, struct starfive_gpio_chip *chip; u64 addr; - if (starfive_gpio_chip_count >= STARFIVE_GPIO_CHIP_MAX) - return SBI_ENOSPC; - chip = &starfive_gpio_chip_array[starfive_gpio_chip_count]; + chip = sbi_zalloc(sizeof(*chip)); + if (!chip) + return SBI_ENOMEM; rc = fdt_get_node_addr_size(fdt, nodeoff, 0, &addr, NULL); - if (rc) + if (rc) { + sbi_free(chip); return rc; + } chip->addr = addr; chip->chip.driver = &fdt_gpio_starfive; @@ -97,10 +96,11 @@ static int starfive_gpio_init(void *fdt, int nodeoff, u32 phandle, chip->chip.direction_output = starfive_gpio_direction_output; chip->chip.set = starfive_gpio_set; rc = gpio_chip_add(&chip->chip); - if (rc) + if (rc) { + sbi_free(chip); return rc; + } - starfive_gpio_chip_count++; return 0; } From 903e88caaf9404a52ed90fcf1e594eb2f8ff1a0c Mon Sep 17 00:00:00 2001 From: Anup Patel Date: Wed, 19 Apr 2023 16:52:44 +0530 Subject: [PATCH 139/187] lib: utils/i2c: Use heap in DesignWare and SiFive I2C drivers Let's use heap allocation in DesignWare and SiFive I2C drivers instead of using a fixed size global array. Signed-off-by: Anup Patel Reviewed-by: Andrew Jones --- lib/utils/i2c/fdt_i2c_dw.c | 24 ++++++++++-------------- lib/utils/i2c/fdt_i2c_sifive.c | 23 ++++++++++------------- 2 files changed, 20 insertions(+), 27 deletions(-) diff --git a/lib/utils/i2c/fdt_i2c_dw.c b/lib/utils/i2c/fdt_i2c_dw.c index 71062f4b403..99b2ddb8411 100644 --- a/lib/utils/i2c/fdt_i2c_dw.c +++ b/lib/utils/i2c/fdt_i2c_dw.c @@ -9,17 +9,12 @@ #include #include +#include #include #include #include #include -#define FDT_DW_I2C_ADAPTER_MAX 7 - -static unsigned int fdt_dw_i2c_adapter_count; -static struct dw_i2c_adapter - fdt_dw_i2c_adapter_array[FDT_DW_I2C_ADAPTER_MAX]; - extern struct fdt_i2c_adapter fdt_i2c_adapter_dw; static int fdt_dw_i2c_init(void *fdt, int nodeoff, @@ -29,23 +24,24 @@ static int fdt_dw_i2c_init(void *fdt, int nodeoff, struct dw_i2c_adapter *adapter; u64 addr; - if (fdt_dw_i2c_adapter_count >= FDT_DW_I2C_ADAPTER_MAX) - return SBI_ENOSPC; - - adapter = &fdt_dw_i2c_adapter_array[fdt_dw_i2c_adapter_count]; + adapter = sbi_zalloc(sizeof(*adapter)); + if (!adapter) + return SBI_ENOMEM; rc = fdt_get_node_addr_size(fdt, nodeoff, 0, &addr, NULL); - if (rc) + if (rc) { + sbi_free(adapter); return rc; + } adapter->addr = addr; adapter->adapter.driver = &fdt_i2c_adapter_dw; rc = dw_i2c_init(&adapter->adapter, nodeoff); - if (rc) + if (rc) { + sbi_free(adapter); return rc; - - fdt_dw_i2c_adapter_count++; + } return 0; } diff --git a/lib/utils/i2c/fdt_i2c_sifive.c b/lib/utils/i2c/fdt_i2c_sifive.c index 195541cf2f0..b85b245c75f 100644 --- a/lib/utils/i2c/fdt_i2c_sifive.c +++ b/lib/utils/i2c/fdt_i2c_sifive.c @@ -9,12 +9,11 @@ #include #include +#include #include #include #include -#define SIFIVE_I2C_ADAPTER_MAX 2 - #define SIFIVE_I2C_PRELO 0x00 #define SIFIVE_I2C_PREHI 0x04 #define SIFIVE_I2C_CTR 0x08 @@ -47,10 +46,6 @@ struct sifive_i2c_adapter { struct i2c_adapter adapter; }; -static unsigned int sifive_i2c_adapter_count; -static struct sifive_i2c_adapter - sifive_i2c_adapter_array[SIFIVE_I2C_ADAPTER_MAX]; - extern struct fdt_i2c_adapter fdt_i2c_adapter_sifive; static inline void sifive_i2c_setreg(struct sifive_i2c_adapter *adap, @@ -244,14 +239,15 @@ static int sifive_i2c_init(void *fdt, int nodeoff, struct sifive_i2c_adapter *adapter; uint64_t addr; - if (sifive_i2c_adapter_count >= SIFIVE_I2C_ADAPTER_MAX) - return SBI_ENOSPC; - - adapter = &sifive_i2c_adapter_array[sifive_i2c_adapter_count]; + adapter = sbi_zalloc(sizeof(*adapter)); + if (!adapter) + return SBI_ENOMEM; rc = fdt_get_node_addr_size(fdt, nodeoff, 0, &addr, NULL); - if (rc) + if (rc) { + sbi_free(adapter); return rc; + } adapter->addr = addr; adapter->adapter.driver = &fdt_i2c_adapter_sifive; @@ -259,10 +255,11 @@ static int sifive_i2c_init(void *fdt, int nodeoff, adapter->adapter.write = sifive_i2c_adapter_write; adapter->adapter.read = sifive_i2c_adapter_read; rc = i2c_adapter_add(&adapter->adapter); - if (rc) + if (rc) { + sbi_free(adapter); return rc; + } - sifive_i2c_adapter_count++; return 0; } From 5a8cfcdf19d98b8dc5dd5a087a2eceb7f5b185fb Mon Sep 17 00:00:00 2001 From: Anup Patel Date: Wed, 19 Apr 2023 16:54:13 +0530 Subject: [PATCH 140/187] lib: utils/ipi: Use heap in ACLINT MSWI driver Let's use heap allocation in ACLINT MSWI driver instead of using a fixed size global array. Signed-off-by: Anup Patel Reviewed-by: Andrew Jones --- lib/utils/ipi/fdt_ipi_mswi.c | 21 ++++++++++----------- 1 file changed, 10 insertions(+), 11 deletions(-) diff --git a/lib/utils/ipi/fdt_ipi_mswi.c b/lib/utils/ipi/fdt_ipi_mswi.c index 4dc91f2cb96..e3a63782465 100644 --- a/lib/utils/ipi/fdt_ipi_mswi.c +++ b/lib/utils/ipi/fdt_ipi_mswi.c @@ -8,15 +8,11 @@ */ #include +#include #include #include #include -#define MSWI_MAX_NR 16 - -static unsigned long mswi_count = 0; -static struct aclint_mswi_data mswi[MSWI_MAX_NR]; - static int ipi_mswi_cold_init(void *fdt, int nodeoff, const struct fdt_match *match) { @@ -24,15 +20,17 @@ static int ipi_mswi_cold_init(void *fdt, int nodeoff, unsigned long offset; struct aclint_mswi_data *ms; - if (MSWI_MAX_NR <= mswi_count) - return SBI_ENOSPC; - ms = &mswi[mswi_count]; + ms = sbi_zalloc(sizeof(*ms)); + if (!ms) + return SBI_ENOMEM; rc = fdt_parse_aclint_node(fdt, nodeoff, false, &ms->addr, &ms->size, NULL, NULL, &ms->first_hartid, &ms->hart_count); - if (rc) + if (rc) { + sbi_free(ms); return rc; + } if (match->data) { /* Adjust MSWI address and size for CLINT device */ @@ -44,10 +42,11 @@ static int ipi_mswi_cold_init(void *fdt, int nodeoff, } rc = aclint_mswi_cold_init(ms); - if (rc) + if (rc) { + sbi_free(ms); return rc; + } - mswi_count++; return 0; } From 30137166c67753299a7b4a4ac5e1f92269090423 Mon Sep 17 00:00:00 2001 From: Anup Patel Date: Wed, 19 Apr 2023 16:55:59 +0530 Subject: [PATCH 141/187] lib: utils/irqchip: Use heap in PLIC, APLIC and IMSIC drivers Let's use heap allocation in PLIC, APLIC, and IMSIC irqchip drivers instead of using a fixed size global array. Signed-off-by: Anup Patel Reviewed-by: Andrew Jones --- lib/utils/irqchip/fdt_irqchip_aplic.c | 24 ++++++++++-------- lib/utils/irqchip/fdt_irqchip_imsic.c | 28 +++++++++------------ lib/utils/irqchip/fdt_irqchip_plic.c | 36 ++++++++++++--------------- 3 files changed, 42 insertions(+), 46 deletions(-) diff --git a/lib/utils/irqchip/fdt_irqchip_aplic.c b/lib/utils/irqchip/fdt_irqchip_aplic.c index 965f02394c4..583a3e30fa5 100644 --- a/lib/utils/irqchip/fdt_irqchip_aplic.c +++ b/lib/utils/irqchip/fdt_irqchip_aplic.c @@ -11,15 +11,11 @@ #include #include #include +#include #include #include #include -#define APLIC_MAX_NR 16 - -static unsigned long aplic_count = 0; -static struct aplic_data aplic[APLIC_MAX_NR]; - static int irqchip_aplic_warm_init(void) { /* Nothing to do here. */ @@ -32,15 +28,23 @@ static int irqchip_aplic_cold_init(void *fdt, int nodeoff, int rc; struct aplic_data *pd; - if (APLIC_MAX_NR <= aplic_count) - return SBI_ENOSPC; - pd = &aplic[aplic_count++]; + pd = sbi_zalloc(sizeof(*pd)); + if (!pd) + return SBI_ENOMEM; rc = fdt_parse_aplic_node(fdt, nodeoff, pd); if (rc) - return rc; + goto fail_free_data; + + rc = aplic_cold_irqchip_init(pd); + if (rc) + goto fail_free_data; + + return 0; - return aplic_cold_irqchip_init(pd); +fail_free_data: + sbi_free(pd); + return rc; } static const struct fdt_match irqchip_aplic_match[] = { diff --git a/lib/utils/irqchip/fdt_irqchip_imsic.c b/lib/utils/irqchip/fdt_irqchip_imsic.c index 6020ac0b992..590b2022b0a 100644 --- a/lib/utils/irqchip/fdt_irqchip_imsic.c +++ b/lib/utils/irqchip/fdt_irqchip_imsic.c @@ -11,16 +11,12 @@ #include #include #include +#include #include #include #include #include -#define IMSIC_MAX_NR 16 - -static unsigned long imsic_count = 0; -static struct imsic_data imsic[IMSIC_MAX_NR]; - static int irqchip_imsic_update_hartid_table(void *fdt, int nodeoff, struct imsic_data *id) { @@ -71,27 +67,27 @@ static int irqchip_imsic_cold_init(void *fdt, int nodeoff, int rc; struct imsic_data *id; - if (IMSIC_MAX_NR <= imsic_count) - return SBI_ENOSPC; - id = &imsic[imsic_count]; + id = sbi_zalloc(sizeof(*id)); + if (!id) + return SBI_ENOMEM; rc = fdt_parse_imsic_node(fdt, nodeoff, id); - if (rc) - return rc; - if (!id->targets_mmode) - return 0; + if (rc || !id->targets_mmode) + goto fail_free_data; rc = irqchip_imsic_update_hartid_table(fdt, nodeoff, id); if (rc) - return rc; + goto fail_free_data; rc = imsic_cold_irqchip_init(id); if (rc) - return rc; - - imsic_count++; + goto fail_free_data; return 0; + +fail_free_data: + sbi_free(id); + return rc; } static const struct fdt_match irqchip_imsic_match[] = { diff --git a/lib/utils/irqchip/fdt_irqchip_plic.c b/lib/utils/irqchip/fdt_irqchip_plic.c index 1aadf9190ca..d7332848eff 100644 --- a/lib/utils/irqchip/fdt_irqchip_plic.c +++ b/lib/utils/irqchip/fdt_irqchip_plic.c @@ -11,18 +11,14 @@ #include #include #include +#include #include #include #include #include -#define PLIC_MAX_NR 16 - -static unsigned long plic_count = 0; -static struct plic_data plic[PLIC_MAX_NR]; - static struct plic_data *plic_hartid2data[SBI_HARTMASK_MAX_BITS]; -static int plic_hartid2context[SBI_HARTMASK_MAX_BITS][2]; +static int plic_hartid2context[SBI_HARTMASK_MAX_BITS][2] = { { -1 } }; void fdt_plic_priority_save(u8 *priority, u32 num) { @@ -114,16 +110,16 @@ static int irqchip_plic_update_hartid_table(void *fdt, int nodeoff, static int irqchip_plic_cold_init(void *fdt, int nodeoff, const struct fdt_match *match) { - int i, rc; + int rc; struct plic_data *pd; - if (PLIC_MAX_NR <= plic_count) - return SBI_ENOSPC; - pd = &plic[plic_count++]; + pd = sbi_zalloc(sizeof(*pd)); + if (!pd) + return SBI_ENOMEM; rc = fdt_parse_plic_node(fdt, nodeoff, pd); if (rc) - return rc; + goto fail_free_data; if (match->data) { void (*plic_plat_init)(struct plic_data *) = match->data; @@ -132,17 +128,17 @@ static int irqchip_plic_cold_init(void *fdt, int nodeoff, rc = plic_cold_irqchip_init(pd); if (rc) - return rc; + goto fail_free_data; - if (plic_count == 1) { - for (i = 0; i < SBI_HARTMASK_MAX_BITS; i++) { - plic_hartid2data[i] = NULL; - plic_hartid2context[i][0] = -1; - plic_hartid2context[i][1] = -1; - } - } + rc = irqchip_plic_update_hartid_table(fdt, nodeoff, pd); + if (rc) + goto fail_free_data; + + return 0; - return irqchip_plic_update_hartid_table(fdt, nodeoff, pd); +fail_free_data: + sbi_free(pd); + return rc; } #define THEAD_PLIC_CTRL_REG 0x1ffffc From 7e5636ac3788451991a65791c5adcc7798dcc22a Mon Sep 17 00:00:00 2001 From: Anup Patel Date: Wed, 19 Apr 2023 17:13:22 +0530 Subject: [PATCH 142/187] lib: utils/timer: Use heap in ACLINT MTIMER driver Let's use heap allocation in ACLINT MTIMER driver instead of using a fixed size global array. Signed-off-by: Anup Patel Reviewed-by: Andrew Jones --- lib/utils/timer/fdt_timer_mtimer.c | 47 +++++++++++++++++++----------- 1 file changed, 30 insertions(+), 17 deletions(-) diff --git a/lib/utils/timer/fdt_timer_mtimer.c b/lib/utils/timer/fdt_timer_mtimer.c index 5244f98f5e7..9eaa11d855c 100644 --- a/lib/utils/timer/fdt_timer_mtimer.c +++ b/lib/utils/timer/fdt_timer_mtimer.c @@ -9,44 +9,54 @@ #include #include +#include +#include #include #include #include -#define MTIMER_MAX_NR 16 - struct timer_mtimer_quirks { unsigned int mtime_offset; bool has_64bit_mmio; bool without_mtime; }; -static unsigned long mtimer_count = 0; -static struct aclint_mtimer_data mtimer[MTIMER_MAX_NR]; +struct timer_mtimer_node { + struct sbi_dlist head; + struct aclint_mtimer_data data; +}; +static SBI_LIST_HEAD(mtn_list); + static struct aclint_mtimer_data *mt_reference = NULL; static int timer_mtimer_cold_init(void *fdt, int nodeoff, const struct fdt_match *match) { - int i, rc; + int rc; unsigned long addr[2], size[2]; + struct timer_mtimer_node *mtn, *n; struct aclint_mtimer_data *mt; - if (MTIMER_MAX_NR <= mtimer_count) - return SBI_ENOSPC; - mt = &mtimer[mtimer_count]; + mtn = sbi_zalloc(sizeof(*mtn)); + if (!mtn) + return SBI_ENOMEM; + mt = &mtn->data; rc = fdt_parse_aclint_node(fdt, nodeoff, true, &addr[0], &size[0], &addr[1], &size[1], &mt->first_hartid, &mt->hart_count); - if (rc) + if (rc) { + sbi_free(mtn); return rc; + } mt->has_64bit_mmio = true; mt->has_shared_mtime = false; rc = fdt_parse_timebase_frequency(fdt, &mt->mtime_freq); - if (rc) + if (rc) { + sbi_free(mtn); return rc; + } if (match->data) { /* SiFive CLINT */ const struct timer_mtimer_quirks *quirks = match->data; @@ -77,8 +87,8 @@ static int timer_mtimer_cold_init(void *fdt, int nodeoff, /* Check if MTIMER device has shared MTIME address */ if (mt->mtime_size) { mt->has_shared_mtime = false; - for (i = 0; i < mtimer_count; i++) { - if (mtimer[i].mtime_addr == mt->mtime_addr) { + sbi_list_for_each_entry(n, &mtn_list, head) { + if (n->data.mtime_addr == mt->mtime_addr) { mt->has_shared_mtime = true; break; } @@ -90,8 +100,10 @@ static int timer_mtimer_cold_init(void *fdt, int nodeoff, /* Initialize the MTIMER device */ rc = aclint_mtimer_cold_init(mt, mt_reference); - if (rc) + if (rc) { + sbi_free(mtn); return rc; + } /* * Select first MTIMER device with no associated HARTs as our @@ -106,16 +118,17 @@ static int timer_mtimer_cold_init(void *fdt, int nodeoff, * Set reference for already propbed MTIMER devices * with non-shared MTIME */ - for (i = 0; i < mtimer_count; i++) - if (!mtimer[i].has_shared_mtime) - aclint_mtimer_set_reference(&mtimer[i], mt); + sbi_list_for_each_entry(n, &mtn_list, head) { + if (!n->data.has_shared_mtime) + aclint_mtimer_set_reference(&n->data, mt); + } } /* Explicitly sync-up MTIMER devices not associated with any HARTs */ if (!mt->hart_count) aclint_mtimer_sync(mt); - mtimer_count++; + sbi_list_add_tail(&mtn->head, &mtn_list); return 0; } From 3c1c972cb69d670ddc309391c4db76f1f19fd77e Mon Sep 17 00:00:00 2001 From: Anup Patel Date: Thu, 20 Apr 2023 18:09:55 +0530 Subject: [PATCH 143/187] lib: utils/fdt: Use heap in FDT domain parsing Let's use heap allocation in FDT domain parsing instead of using a fixed size global array. Signed-off-by: Anup Patel Reviewed-by: Andrew Jones --- lib/utils/fdt/fdt_domain.c | 113 +++++++++++++++++++++++-------------- 1 file changed, 71 insertions(+), 42 deletions(-) diff --git a/lib/utils/fdt/fdt_domain.c b/lib/utils/fdt/fdt_domain.c index bb6d17d29fd..788683d27c1 100644 --- a/lib/utils/fdt/fdt_domain.c +++ b/lib/utils/fdt/fdt_domain.c @@ -13,6 +13,7 @@ #include #include #include +#include #include #include #include @@ -219,14 +220,13 @@ void fdt_domain_fixup(void *fdt) fdt_nop_node(fdt, poffset); } -#define FDT_DOMAIN_MAX_COUNT 8 #define FDT_DOMAIN_REGION_MAX_COUNT 16 -static u32 fdt_domains_count; -static struct sbi_domain fdt_domains[FDT_DOMAIN_MAX_COUNT]; -static struct sbi_hartmask fdt_masks[FDT_DOMAIN_MAX_COUNT]; -static struct sbi_domain_memregion - fdt_regions[FDT_DOMAIN_MAX_COUNT][FDT_DOMAIN_REGION_MAX_COUNT + 1]; +struct parse_region_data { + struct sbi_domain *dom; + u32 region_count; + u32 max_regions; +}; static int __fdt_parse_region(void *fdt, int domain_offset, int region_offset, u32 region_access, @@ -236,7 +236,7 @@ static int __fdt_parse_region(void *fdt, int domain_offset, u32 val32; u64 val64; const u32 *val; - u32 *region_count = opaque; + struct parse_region_data *preg = opaque; struct sbi_domain_memregion *region; /* @@ -252,9 +252,9 @@ static int __fdt_parse_region(void *fdt, int domain_offset, return SBI_EINVAL; /* Find next region of the domain */ - if (FDT_DOMAIN_REGION_MAX_COUNT <= *region_count) - return SBI_EINVAL; - region = &fdt_regions[fdt_domains_count][*region_count]; + if (preg->max_regions <= preg->region_count) + return SBI_ENOSPC; + region = &preg->dom->regions[preg->region_count]; /* Read "base" DT property */ val = fdt_getprop(fdt, region_offset, "base", &len); @@ -278,7 +278,7 @@ static int __fdt_parse_region(void *fdt, int domain_offset, if (fdt_get_property(fdt, region_offset, "mmio", NULL)) region->flags |= SBI_DOMAIN_MEMREGION_MMIO; - (*region_count)++; + preg->region_count++; return 0; } @@ -291,16 +291,30 @@ static int __fdt_parse_domain(void *fdt, int domain_offset, void *opaque) struct sbi_domain *dom; struct sbi_hartmask *mask; struct sbi_hartmask assign_mask; + struct parse_region_data preg; int *cold_domain_offset = opaque; - struct sbi_domain_memregion *reg, *regions; - int i, err, len, cpus_offset, cpu_offset, doffset; - - /* Sanity check on maximum domains we can handle */ - if (FDT_DOMAIN_MAX_COUNT <= fdt_domains_count) - return SBI_EINVAL; - dom = &fdt_domains[fdt_domains_count]; - mask = &fdt_masks[fdt_domains_count]; - regions = &fdt_regions[fdt_domains_count][0]; + struct sbi_domain_memregion *reg; + int i, err = 0, len, cpus_offset, cpu_offset, doffset; + + dom = sbi_zalloc(sizeof(*dom)); + if (!dom) + return SBI_ENOMEM; + + dom->regions = sbi_calloc(sizeof(*dom->regions), + FDT_DOMAIN_REGION_MAX_COUNT + 1); + if (!dom->regions) { + err = SBI_ENOMEM; + goto fail_free_domain; + } + preg.dom = dom; + preg.region_count = 0; + preg.max_regions = FDT_DOMAIN_REGION_MAX_COUNT; + + mask = sbi_zalloc(sizeof(*mask)); + if (!mask) { + err = SBI_ENOMEM; + goto fail_free_regions; + } /* Read DT node name */ strncpy(dom->name, fdt_get_name(fdt, domain_offset, NULL), @@ -316,12 +330,14 @@ static int __fdt_parse_domain(void *fdt, int domain_offset, void *opaque) for (i = 0; i < len; i++) { cpu_offset = fdt_node_offset_by_phandle(fdt, fdt32_to_cpu(val[i])); - if (cpu_offset < 0) - return cpu_offset; + if (cpu_offset < 0) { + err = cpu_offset; + goto fail_free_all; + } err = fdt_parse_hart_id(fdt, cpu_offset, &val32); if (err) - return err; + goto fail_free_all; if (!fdt_node_is_enabled(fdt, cpu_offset)) continue; @@ -331,14 +347,10 @@ static int __fdt_parse_domain(void *fdt, int domain_offset, void *opaque) } /* Setup memregions from DT */ - val32 = 0; - memset(regions, 0, - sizeof(*regions) * (FDT_DOMAIN_REGION_MAX_COUNT + 1)); - dom->regions = regions; - err = fdt_iterate_each_memregion(fdt, domain_offset, &val32, + err = fdt_iterate_each_memregion(fdt, domain_offset, &preg, __fdt_parse_region); if (err) - return err; + goto fail_free_all; /* * Copy over root domain memregions which don't allow @@ -354,9 +366,11 @@ static int __fdt_parse_domain(void *fdt, int domain_offset, void *opaque) (reg->flags & SBI_DOMAIN_MEMREGION_SU_WRITABLE) || (reg->flags & SBI_DOMAIN_MEMREGION_SU_EXECUTABLE)) continue; - if (FDT_DOMAIN_REGION_MAX_COUNT <= val32) - return SBI_EINVAL; - memcpy(®ions[val32++], reg, sizeof(*reg)); + if (preg.max_regions <= preg.region_count) { + err = SBI_EINVAL; + goto fail_free_all; + } + memcpy(&dom->regions[preg.region_count++], reg, sizeof(*reg)); } dom->fw_region_inited = root.fw_region_inited; @@ -427,8 +441,10 @@ static int __fdt_parse_domain(void *fdt, int domain_offset, void *opaque) /* Find /cpus DT node */ cpus_offset = fdt_path_offset(fdt, "/cpus"); - if (cpus_offset < 0) - return cpus_offset; + if (cpus_offset < 0) { + err = cpus_offset; + goto fail_free_all; + } /* HART to domain assignment mask based on CPU DT nodes */ sbi_hartmask_clear_all(&assign_mask); @@ -444,22 +460,35 @@ static int __fdt_parse_domain(void *fdt, int domain_offset, void *opaque) continue; val = fdt_getprop(fdt, cpu_offset, "opensbi-domain", &len); - if (!val || len < 4) - return SBI_EINVAL; + if (!val || len < 4) { + err = SBI_EINVAL; + goto fail_free_all; + } doffset = fdt_node_offset_by_phandle(fdt, fdt32_to_cpu(*val)); - if (doffset < 0) - return doffset; + if (doffset < 0) { + err = doffset; + goto fail_free_all; + } if (doffset == domain_offset) sbi_hartmask_set_hart(val32, &assign_mask); } - /* Increment domains count */ - fdt_domains_count++; - /* Register the domain */ - return sbi_domain_register(dom, &assign_mask); + err = sbi_domain_register(dom, &assign_mask); + if (err) + goto fail_free_all; + + return 0; + +fail_free_all: + sbi_free(mask); +fail_free_regions: + sbi_free(dom->regions); +fail_free_domain: + sbi_free(dom); + return err; } int fdt_domains_populate(void *fdt) From acbd8fce9e5d92f07d344388a3b046f1722ce072 Mon Sep 17 00:00:00 2001 From: Anup Patel Date: Wed, 19 Apr 2023 21:23:53 +0530 Subject: [PATCH 144/187] lib: utils/ipi: Use scratch space to save per-HART MSWI pointer Instead of using a global array indexed by hartid, we should use scratch space to save per-HART MSWI pointer. Signed-off-by: Anup Patel Reviewed-by: Andrew Jones --- lib/utils/ipi/aclint_mswi.c | 43 ++++++++++++++++++++++++++++--------- 1 file changed, 33 insertions(+), 10 deletions(-) diff --git a/lib/utils/ipi/aclint_mswi.c b/lib/utils/ipi/aclint_mswi.c index ac8570bc5fa..f47b3bcbbb4 100644 --- a/lib/utils/ipi/aclint_mswi.c +++ b/lib/utils/ipi/aclint_mswi.c @@ -12,21 +12,30 @@ #include #include #include -#include #include +#include #include #include -static struct aclint_mswi_data *mswi_hartid2data[SBI_HARTMASK_MAX_BITS]; +static unsigned long mswi_ptr_offset; + +#define mswi_get_hart_data_ptr(__scratch) \ + sbi_scratch_read_type((__scratch), void *, mswi_ptr_offset) + +#define mswi_set_hart_data_ptr(__scratch, __mswi) \ + sbi_scratch_write_type((__scratch), void *, mswi_ptr_offset, (__mswi)) static void mswi_ipi_send(u32 target_hart) { u32 *msip; + struct sbi_scratch *scratch; struct aclint_mswi_data *mswi; - if (SBI_HARTMASK_MAX_BITS <= target_hart) + scratch = sbi_hartid_to_scratch(target_hart); + if (!scratch) return; - mswi = mswi_hartid2data[target_hart]; + + mswi = mswi_get_hart_data_ptr(scratch); if (!mswi) return; @@ -38,11 +47,14 @@ static void mswi_ipi_send(u32 target_hart) static void mswi_ipi_clear(u32 target_hart) { u32 *msip; + struct sbi_scratch *scratch; struct aclint_mswi_data *mswi; - if (SBI_HARTMASK_MAX_BITS <= target_hart) + scratch = sbi_hartid_to_scratch(target_hart); + if (!scratch) return; - mswi = mswi_hartid2data[target_hart]; + + mswi = mswi_get_hart_data_ptr(scratch); if (!mswi) return; @@ -69,19 +81,30 @@ int aclint_mswi_cold_init(struct aclint_mswi_data *mswi) { u32 i; int rc; + struct sbi_scratch *scratch; unsigned long pos, region_size; struct sbi_domain_memregion reg; /* Sanity checks */ if (!mswi || (mswi->addr & (ACLINT_MSWI_ALIGN - 1)) || (mswi->size < (mswi->hart_count * sizeof(u32))) || - (mswi->first_hartid + mswi->hart_count > SBI_HARTMASK_MAX_BITS) || (!mswi->hart_count || mswi->hart_count > ACLINT_MSWI_MAX_HARTS)) return SBI_EINVAL; - /* Update MSWI hartid table */ - for (i = 0; i < mswi->hart_count; i++) - mswi_hartid2data[mswi->first_hartid + i] = mswi; + /* Allocate scratch space pointer */ + if (!mswi_ptr_offset) { + mswi_ptr_offset = sbi_scratch_alloc_type_offset(void *); + if (!mswi_ptr_offset) + return SBI_ENOMEM; + } + + /* Update MSWI pointer in scratch space */ + for (i = 0; i < mswi->hart_count; i++) { + scratch = sbi_hartid_to_scratch(mswi->first_hartid + i); + if (!scratch) + return SBI_ENOENT; + mswi_set_hart_data_ptr(scratch, mswi); + } /* Add MSWI regions to the root domain */ for (pos = 0; pos < mswi->size; pos += ACLINT_MSWI_ALIGN) { From f0516beae068ffce0d5a79f09a96904a661a25ba Mon Sep 17 00:00:00 2001 From: Anup Patel Date: Wed, 19 Apr 2023 21:27:27 +0530 Subject: [PATCH 145/187] lib: utils/timer: Use scratch space to save per-HART MTIMER pointer Instead of using a global array indexed by hartid, we should use scratch space to save per-HART MTIMER pointer. Signed-off-by: Anup Patel Reviewed-by: Andrew Jones --- lib/utils/timer/aclint_mtimer.c | 76 ++++++++++++++++++++++++++------- 1 file changed, 61 insertions(+), 15 deletions(-) diff --git a/lib/utils/timer/aclint_mtimer.c b/lib/utils/timer/aclint_mtimer.c index 84ded4ed44e..13af5d8232d 100644 --- a/lib/utils/timer/aclint_mtimer.c +++ b/lib/utils/timer/aclint_mtimer.c @@ -13,12 +13,17 @@ #include #include #include -#include -#include +#include #include #include -static struct aclint_mtimer_data *mtimer_hartid2data[SBI_HARTMASK_MAX_BITS]; +static unsigned long mtimer_ptr_offset; + +#define mtimer_get_hart_data_ptr(__scratch) \ + sbi_scratch_read_type((__scratch), void *, mtimer_ptr_offset) + +#define mtimer_set_hart_data_ptr(__scratch, __mtimer) \ + sbi_scratch_write_type((__scratch), void *, mtimer_ptr_offset, (__mtimer)) #if __riscv_xlen != 32 static u64 mtimer_time_rd64(volatile u64 *addr) @@ -53,30 +58,54 @@ static void mtimer_time_wr32(bool timecmp, u64 value, volatile u64 *addr) static u64 mtimer_value(void) { - struct aclint_mtimer_data *mt = mtimer_hartid2data[current_hartid()]; - u64 *time_val = (void *)mt->mtime_addr; + struct sbi_scratch *scratch = sbi_scratch_thishart_ptr(); + struct aclint_mtimer_data *mt; + + mt = mtimer_get_hart_data_ptr(scratch); + if (!mt) + return 0; /* Read MTIMER Time Value */ - return mt->time_rd(time_val); + return mt->time_rd((void *)mt->mtime_addr); } static void mtimer_event_stop(void) { u32 target_hart = current_hartid(); - struct aclint_mtimer_data *mt = mtimer_hartid2data[target_hart]; - u64 *time_cmp = (void *)mt->mtimecmp_addr; + struct sbi_scratch *scratch; + struct aclint_mtimer_data *mt; + u64 *time_cmp; + + scratch = sbi_hartid_to_scratch(target_hart); + if (!scratch) + return; + + mt = mtimer_get_hart_data_ptr(scratch); + if (!mt) + return; /* Clear MTIMER Time Compare */ + time_cmp = (void *)mt->mtimecmp_addr; mt->time_wr(true, -1ULL, &time_cmp[target_hart - mt->first_hartid]); } static void mtimer_event_start(u64 next_event) { u32 target_hart = current_hartid(); - struct aclint_mtimer_data *mt = mtimer_hartid2data[target_hart]; - u64 *time_cmp = (void *)mt->mtimecmp_addr; + struct sbi_scratch *scratch; + struct aclint_mtimer_data *mt; + u64 *time_cmp; + + scratch = sbi_hartid_to_scratch(target_hart); + if (!scratch) + return; + + mt = mtimer_get_hart_data_ptr(scratch); + if (!mt) + return; /* Program MTIMER Time Compare */ + time_cmp = (void *)mt->mtimecmp_addr; mt->time_wr(true, next_event, &time_cmp[target_hart - mt->first_hartid]); } @@ -126,8 +155,14 @@ int aclint_mtimer_warm_init(void) { u64 *mt_time_cmp; u32 target_hart = current_hartid(); - struct aclint_mtimer_data *mt = mtimer_hartid2data[target_hart]; + struct sbi_scratch *scratch; + struct aclint_mtimer_data *mt; + scratch = sbi_hartid_to_scratch(target_hart); + if (!scratch) + return SBI_ENOENT; + + mt = mtimer_get_hart_data_ptr(scratch); if (!mt) return SBI_ENODEV; @@ -147,6 +182,7 @@ int aclint_mtimer_cold_init(struct aclint_mtimer_data *mt, { u32 i; int rc; + struct sbi_scratch *scratch; /* Sanity checks */ if (!mt || @@ -155,12 +191,18 @@ int aclint_mtimer_cold_init(struct aclint_mtimer_data *mt, (mt->mtime_size && (mt->mtime_size & (ACLINT_MTIMER_ALIGN - 1))) || (mt->mtimecmp_addr & (ACLINT_MTIMER_ALIGN - 1)) || (mt->mtimecmp_size & (ACLINT_MTIMER_ALIGN - 1)) || - (mt->first_hartid >= SBI_HARTMASK_MAX_BITS) || (mt->hart_count > ACLINT_MTIMER_MAX_HARTS)) return SBI_EINVAL; if (reference && mt->mtime_freq != reference->mtime_freq) return SBI_EINVAL; + /* Allocate scratch space pointer */ + if (!mtimer_ptr_offset) { + mtimer_ptr_offset = sbi_scratch_alloc_type_offset(void *); + if (!mtimer_ptr_offset) + return SBI_ENOMEM; + } + /* Initialize private data */ aclint_mtimer_set_reference(mt, reference); mt->time_rd = mtimer_time_rd32; @@ -174,9 +216,13 @@ int aclint_mtimer_cold_init(struct aclint_mtimer_data *mt, } #endif - /* Update MTIMER hartid table */ - for (i = 0; i < mt->hart_count; i++) - mtimer_hartid2data[mt->first_hartid + i] = mt; + /* Update MTIMER pointer in scratch space */ + for (i = 0; i < mt->hart_count; i++) { + scratch = sbi_hartid_to_scratch(mt->first_hartid + i); + if (!scratch) + return SBI_ENOENT; + mtimer_set_hart_data_ptr(scratch, mt); + } if (!mt->mtime_size) { /* Disable reading mtime when mtime is not available */ From b3594ac1d10ef6c7269c6381a1e826b73b06aca0 Mon Sep 17 00:00:00 2001 From: Anup Patel Date: Wed, 19 Apr 2023 21:29:50 +0530 Subject: [PATCH 146/187] lib: utils/irqchip: Use scratch space to save per-HART PLIC pointer Instead of using a global array indexed by hartid, we should use scratch space to save per-HART PLIC pointer and PLIC context numbers. Signed-off-by: Anup Patel Reviewed-by: Andrew Jones --- lib/utils/irqchip/fdt_irqchip_plic.c | 88 +++++++++++++++++++++------- 1 file changed, 66 insertions(+), 22 deletions(-) diff --git a/lib/utils/irqchip/fdt_irqchip_plic.c b/lib/utils/irqchip/fdt_irqchip_plic.c index d7332848eff..829c5ee2034 100644 --- a/lib/utils/irqchip/fdt_irqchip_plic.c +++ b/lib/utils/irqchip/fdt_irqchip_plic.c @@ -12,54 +12,77 @@ #include #include #include -#include +#include #include #include #include -static struct plic_data *plic_hartid2data[SBI_HARTMASK_MAX_BITS]; -static int plic_hartid2context[SBI_HARTMASK_MAX_BITS][2] = { { -1 } }; +static unsigned long plic_ptr_offset; + +#define plic_get_hart_data_ptr(__scratch) \ + sbi_scratch_read_type((__scratch), void *, plic_ptr_offset) + +#define plic_set_hart_data_ptr(__scratch, __plic) \ + sbi_scratch_write_type((__scratch), void *, plic_ptr_offset, (__plic)) + +static unsigned long plic_mcontext_offset; + +#define plic_get_hart_mcontext(__scratch) \ + (sbi_scratch_read_type((__scratch), long, plic_mcontext_offset) - 1) + +#define plic_set_hart_mcontext(__scratch, __mctx) \ + sbi_scratch_write_type((__scratch), long, plic_mcontext_offset, (__mctx) + 1) + +static unsigned long plic_scontext_offset; + +#define plic_get_hart_scontext(__scratch) \ + (sbi_scratch_read_type((__scratch), long, plic_scontext_offset) - 1) + +#define plic_set_hart_scontext(__scratch, __sctx) \ + sbi_scratch_write_type((__scratch), long, plic_scontext_offset, (__sctx) + 1) void fdt_plic_priority_save(u8 *priority, u32 num) { - struct plic_data *plic = plic_hartid2data[current_hartid()]; + struct sbi_scratch *scratch = sbi_scratch_thishart_ptr(); - plic_priority_save(plic, priority, num); + plic_priority_save(plic_get_hart_data_ptr(scratch), priority, num); } void fdt_plic_priority_restore(const u8 *priority, u32 num) { - struct plic_data *plic = plic_hartid2data[current_hartid()]; + struct sbi_scratch *scratch = sbi_scratch_thishart_ptr(); - plic_priority_restore(plic, priority, num); + plic_priority_restore(plic_get_hart_data_ptr(scratch), priority, num); } void fdt_plic_context_save(bool smode, u32 *enable, u32 *threshold, u32 num) { - u32 hartid = current_hartid(); + struct sbi_scratch *scratch = sbi_scratch_thishart_ptr(); - plic_context_save(plic_hartid2data[hartid], - plic_hartid2context[hartid][smode], + plic_context_save(plic_get_hart_data_ptr(scratch), + smode ? plic_get_hart_scontext(scratch) : + plic_get_hart_mcontext(scratch), enable, threshold, num); } void fdt_plic_context_restore(bool smode, const u32 *enable, u32 threshold, u32 num) { - u32 hartid = current_hartid(); + struct sbi_scratch *scratch = sbi_scratch_thishart_ptr(); - plic_context_restore(plic_hartid2data[hartid], - plic_hartid2context[hartid][smode], + plic_context_restore(plic_get_hart_data_ptr(scratch), + smode ? plic_get_hart_scontext(scratch) : + plic_get_hart_mcontext(scratch), enable, threshold, num); } static int irqchip_plic_warm_init(void) { - u32 hartid = current_hartid(); + struct sbi_scratch *scratch = sbi_scratch_thishart_ptr(); - return plic_warm_irqchip_init(plic_hartid2data[hartid], - plic_hartid2context[hartid][0], - plic_hartid2context[hartid][1]); + return plic_warm_irqchip_init(plic_get_hart_data_ptr(scratch), + plic_get_hart_mcontext(scratch), + plic_get_hart_scontext(scratch)); } static int irqchip_plic_update_hartid_table(void *fdt, int nodeoff, @@ -67,6 +90,7 @@ static int irqchip_plic_update_hartid_table(void *fdt, int nodeoff, { const fdt32_t *val; u32 phandle, hwirq, hartid; + struct sbi_scratch *scratch; int i, err, count, cpu_offset, cpu_intc_offset; val = fdt_getprop(fdt, nodeoff, "interrupts-extended", &count); @@ -90,16 +114,17 @@ static int irqchip_plic_update_hartid_table(void *fdt, int nodeoff, if (err) continue; - if (SBI_HARTMASK_MAX_BITS <= hartid) + scratch = sbi_hartid_to_scratch(hartid); + if (!scratch) continue; - plic_hartid2data[hartid] = pd; + plic_set_hart_data_ptr(scratch, pd); switch (hwirq) { case IRQ_M_EXT: - plic_hartid2context[hartid][0] = i / 2; + plic_set_hart_mcontext(scratch, i / 2); break; case IRQ_S_EXT: - plic_hartid2context[hartid][1] = i / 2; + plic_set_hart_scontext(scratch, i / 2); break; } } @@ -113,6 +138,24 @@ static int irqchip_plic_cold_init(void *fdt, int nodeoff, int rc; struct plic_data *pd; + if (!plic_ptr_offset) { + plic_ptr_offset = sbi_scratch_alloc_type_offset(void *); + if (!plic_ptr_offset) + return SBI_ENOMEM; + } + + if (!plic_mcontext_offset) { + plic_mcontext_offset = sbi_scratch_alloc_type_offset(long); + if (!plic_mcontext_offset) + return SBI_ENOMEM; + } + + if (!plic_scontext_offset) { + plic_scontext_offset = sbi_scratch_alloc_type_offset(long); + if (!plic_scontext_offset) + return SBI_ENOMEM; + } + pd = sbi_zalloc(sizeof(*pd)); if (!pd) return SBI_ENOMEM; @@ -150,7 +193,8 @@ static void thead_plic_plat_init(struct plic_data *pd) void thead_plic_restore(void) { - struct plic_data *plic = plic_hartid2data[current_hartid()]; + struct sbi_scratch *scratch = sbi_scratch_thishart_ptr(); + struct plic_data *plic = plic_get_hart_data_ptr(scratch); thead_plic_plat_init(plic); } From 1df52fa7e8db2c23a921014404bd472d20ca42e8 Mon Sep 17 00:00:00 2001 From: Anup Patel Date: Thu, 20 Apr 2023 10:14:43 +0530 Subject: [PATCH 147/187] lib: utils/irqchip: Don't check hartid in imsic_update_hartid_table() The imsic_map_hartid_to_data() already checks hartid before using so we don't need to check in imsic_update_hartid_table(). Signed-off-by: Anup Patel Reviewed-by: Andrew Jones --- lib/utils/irqchip/fdt_irqchip_imsic.c | 3 --- 1 file changed, 3 deletions(-) diff --git a/lib/utils/irqchip/fdt_irqchip_imsic.c b/lib/utils/irqchip/fdt_irqchip_imsic.c index 590b2022b0a..d032ac8f540 100644 --- a/lib/utils/irqchip/fdt_irqchip_imsic.c +++ b/lib/utils/irqchip/fdt_irqchip_imsic.c @@ -12,7 +12,6 @@ #include #include #include -#include #include #include #include @@ -44,8 +43,6 @@ static int irqchip_imsic_update_hartid_table(void *fdt, int nodeoff, err = fdt_parse_hart_id(fdt, cpu_offset, &hartid); if (err) return SBI_EINVAL; - if (SBI_HARTMASK_MAX_BITS <= hartid) - return SBI_EINVAL; switch (hwirq) { case IRQ_M_EXT: From 355796c5bc1906d749850e4215e0f7f53802ba5b Mon Sep 17 00:00:00 2001 From: Anup Patel Date: Thu, 20 Apr 2023 10:18:08 +0530 Subject: [PATCH 148/187] lib: utils/irqchip: Use scratch space to save per-HART IMSIC pointer Instead of using a global array indexed by hartid, we should use scratch space to save per-HART IMSIC pointer and IMSIC file number. Signed-off-by: Anup Patel Reviewed-by: Andrew Jones --- lib/utils/irqchip/fdt_irqchip_imsic.c | 4 +- lib/utils/irqchip/imsic.c | 83 ++++++++++++++++++++++----- 2 files changed, 70 insertions(+), 17 deletions(-) diff --git a/lib/utils/irqchip/fdt_irqchip_imsic.c b/lib/utils/irqchip/fdt_irqchip_imsic.c index d032ac8f540..4eb1854556b 100644 --- a/lib/utils/irqchip/fdt_irqchip_imsic.c +++ b/lib/utils/irqchip/fdt_irqchip_imsic.c @@ -72,11 +72,11 @@ static int irqchip_imsic_cold_init(void *fdt, int nodeoff, if (rc || !id->targets_mmode) goto fail_free_data; - rc = irqchip_imsic_update_hartid_table(fdt, nodeoff, id); + rc = imsic_cold_irqchip_init(id); if (rc) goto fail_free_data; - rc = imsic_cold_irqchip_init(id); + rc = irqchip_imsic_update_hartid_table(fdt, nodeoff, id); if (rc) goto fail_free_data; diff --git a/lib/utils/irqchip/imsic.c b/lib/utils/irqchip/imsic.c index 11667cd90df..7fc61d9e8a2 100644 --- a/lib/utils/irqchip/imsic.c +++ b/lib/utils/irqchip/imsic.c @@ -13,10 +13,10 @@ #include #include #include -#include #include #include #include +#include #include #define IMSIC_MMIO_PAGE_LE 0x00 @@ -79,33 +79,65 @@ do { \ csr_clear(CSR_MIREG, __v); \ } while (0) -static struct imsic_data *imsic_hartid2data[SBI_HARTMASK_MAX_BITS]; -static int imsic_hartid2file[SBI_HARTMASK_MAX_BITS]; +static unsigned long imsic_ptr_offset; + +#define imsic_get_hart_data_ptr(__scratch) \ + sbi_scratch_read_type((__scratch), void *, imsic_ptr_offset) + +#define imsic_set_hart_data_ptr(__scratch, __imsic) \ + sbi_scratch_write_type((__scratch), void *, imsic_ptr_offset, (__imsic)) + +static unsigned long imsic_file_offset; + +#define imsic_get_hart_file(__scratch) \ + sbi_scratch_read_type((__scratch), long, imsic_file_offset) + +#define imsic_set_hart_file(__scratch, __file) \ + sbi_scratch_write_type((__scratch), long, imsic_file_offset, (__file)) int imsic_map_hartid_to_data(u32 hartid, struct imsic_data *imsic, int file) { - if (!imsic || !imsic->targets_mmode || - (SBI_HARTMASK_MAX_BITS <= hartid)) + struct sbi_scratch *scratch; + + if (!imsic || !imsic->targets_mmode) return SBI_EINVAL; - imsic_hartid2data[hartid] = imsic; - imsic_hartid2file[hartid] = file; + /* + * We don't need to fail if scratch pointer is not available + * because we might be dealing with hartid of a HART disabled + * in device tree. For HARTs disabled in device tree, the + * imsic_get_data() and imsic_get_target_file() will anyway + * fail. + */ + scratch = sbi_hartid_to_scratch(hartid); + if (!scratch) + return 0; + + imsic_set_hart_data_ptr(scratch, imsic); + imsic_set_hart_file(scratch, file); return 0; } struct imsic_data *imsic_get_data(u32 hartid) { - if (SBI_HARTMASK_MAX_BITS <= hartid) + struct sbi_scratch *scratch; + + scratch = sbi_hartid_to_scratch(hartid); + if (!scratch) return NULL; - return imsic_hartid2data[hartid]; + + return imsic_get_hart_data_ptr(scratch); } int imsic_get_target_file(u32 hartid) { - if ((SBI_HARTMASK_MAX_BITS <= hartid) || - !imsic_hartid2data[hartid]) + struct sbi_scratch *scratch; + + scratch = sbi_hartid_to_scratch(hartid); + if (!scratch) return SBI_ENOENT; - return imsic_hartid2file[hartid]; + + return imsic_get_hart_file(scratch); } static int imsic_external_irqfn(struct sbi_trap_regs *regs) @@ -133,9 +165,16 @@ static void imsic_ipi_send(u32 target_hart) { unsigned long reloff; struct imsic_regs *regs; - struct imsic_data *data = imsic_hartid2data[target_hart]; - int file = imsic_hartid2file[target_hart]; + struct imsic_data *data; + struct sbi_scratch *scratch; + int file; + + scratch = sbi_hartid_to_scratch(target_hart); + if (!scratch) + return; + data = imsic_get_hart_data_ptr(scratch); + file = imsic_get_hart_file(scratch); if (!data || !data->targets_mmode) return; @@ -204,7 +243,7 @@ void imsic_local_irqchip_init(void) int imsic_warm_irqchip_init(void) { - struct imsic_data *imsic = imsic_hartid2data[current_hartid()]; + struct imsic_data *imsic = imsic_get_data(current_hartid()); /* Sanity checks */ if (!imsic || !imsic->targets_mmode) @@ -306,6 +345,20 @@ int imsic_cold_irqchip_init(struct imsic_data *imsic) if (!imsic->targets_mmode) return SBI_EINVAL; + /* Allocate scratch space pointer */ + if (!imsic_ptr_offset) { + imsic_ptr_offset = sbi_scratch_alloc_type_offset(void *); + if (!imsic_ptr_offset) + return SBI_ENOMEM; + } + + /* Allocate scratch space file */ + if (!imsic_file_offset) { + imsic_file_offset = sbi_scratch_alloc_type_offset(long); + if (!imsic_file_offset) + return SBI_ENOMEM; + } + /* Setup external interrupt function for IMSIC */ sbi_irqchip_set_irqfn(imsic_external_irqfn); From 524feec7b74aa4079999af13ba4daf73b423f28a Mon Sep 17 00:00:00 2001 From: Anup Patel Date: Fri, 9 Jun 2023 17:21:08 +0530 Subject: [PATCH 149/187] docs: Add OpenSBI logo and use it in the top-level README.md We do have an official OpenSBI logo which was designed few months ago and was also approved by RISC-V International. Lets add this logo under docs and also use it in the top-level README.md Signed-off-by: Anup Patel Reviewed-by: Andrew Jones --- README.md | 2 ++ docs/riscv_opensbi_logo_final_color.png | Bin 0 -> 7758 bytes docs/riscv_opensbi_logo_final_grey.png | Bin 0 -> 9159 bytes 3 files changed, 2 insertions(+) create mode 100644 docs/riscv_opensbi_logo_final_color.png create mode 100644 docs/riscv_opensbi_logo_final_grey.png diff --git a/README.md b/README.md index a6bcb0c1c3a..bb09fdfeeb0 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,8 @@ RISC-V Open Source Supervisor Binary Interface (OpenSBI) ======================================================== +![RISC-V OpenSBI](docs/riscv_opensbi_logo_final_color.png) + Copyright and License --------------------- diff --git a/docs/riscv_opensbi_logo_final_color.png b/docs/riscv_opensbi_logo_final_color.png new file mode 100644 index 0000000000000000000000000000000000000000..111478119b5cdda1e9beddd5d779e54e7cb78d0d GIT binary patch literal 7758 zcma)>Wl$W=yY|tbfdvAKvp57x&>%sU#U;4A246x5?zW3tupkNU0fGj1hlda#1mDHo zUCuuL^H#l8r_P7-VS1)(T59I*zWT1~2iH(nc#cnvkA{Z!TuBk4g@%R>Ks^uPK0}ot zKnD_aL-){90Hak;(C(lrSoSh%GH7VE2?Y0+*r+-lRMF4_4UMSx-wS=vt<(k$jSi^< zkgDI|m1G9>#DbV(Kw$*1XML<-7&YqvhkTqUEqZ{DE!URY-Ha$OP0d#bX?5>VrvSh$V-8*-2AwhOm`i_Y-Aakhx$)h3;&p!8tdy{eAIsm z+8WFBtJqR^(|x+_I0{^84+Vg68N>fy0TYeBr+YKO_hjiFXx3{&60P$dr$<@$pu9!I z$pr^0F(|Ti?aY{np(XrLK0*VmVk;6Kd3(IACUjPAGY5#@y56MCQwv`|vamee2x&`0 zu+9rcAw`$N>tiRGFxWvwz4l8iUm`h@G-_v7P@|0&GX^G13ZvdA8~h0r{iaxGAWXLE z9iOhIeNUU`f;AbTx!>6Z)7TubW1^ir5xy3a9L2RG3AHm$6Ui1po|l`cFd}f6<`tr#t;TGcZ~Hz!-8YT0x~JAD4c@m>OXk%L~yQ{`S*Zc}JL@fEQ`&huNNJC*$h~z7(p+H zz$O3^K9MVa_&6`fz(fvDM3ObN&Gl3RV}muSZxs=S*bNbfG+lcBt#yrHZ&(S(iVIL6 z=*u$AksFVnu(5ZMJs24=tVy5(UFlrnymp-0v>h zZFMm^l#DbihpJZn0r`ak1k5z#Yz~td>wqy@x~-?fQ*}sjpHr{DiD`pa^E1ISC#MfF za{V`c8zf*DIgCK>e1WT6#0zMi;bFDSU+t6LGR% z-(-^jK%|Lpndbn2N`w2Ve;qB)5$G{U`xU{ZpeR5xR&(09UK=TVOg8@W{w>&u8&E(6 zG@!4MKCfIhV@a!gtM4rS$LvLYIS_a?&*w^Y)3SRrBn4uL@_sDfKe-YL=-b3RkTbsU zrJVQ56P~j8cmN7o|2sls^A2$~7JHOllxCZ?0uW($5?(m{ZM=bKA?8bL|8aisK~>^) zk#g!MDW(Jfsekd)34ZNIZQ}VD`^$A(#BEID$g*Lqojo=6smi^w-_=sYl-6(S;1AUB z!Jb|8NCbLg>F(W79v6g#i5Nf%-Q=csd`WL{nV)1em+oSF#NFI@ULE^LeNOsh4HBE% z5KfUu*wWD+kFF|LIYXSH*C{AMMRoH^a`zr=Co`ZBlJ8Z!Tz)4Y5&@zM>T@m%L`Cqn z2ub9HWvZo7Ye~Ty@3w~h%(D{;y~~ua@L!ck>~O3#xE37rEZkFBn=@b$lIMUPcd8l63mfwZPijOmZv(2X?~~k(eaLNUS&OA z#i_q$8OJ6e(cDG1Wicz7{R%5|SR+Cf0Rtw)got6S}bTwOoOyZjT#>9NW6Bk$ip1S1g1{%z?2|wGy9StEW=%PW#vC;o(FDt3CsILk-Bg;b}3#b;-Q{bdOUXk1`VDR(R z4G&nQ9Y73LOe+Xaqb5gY;=>x_IT^zhWA%guJT1@5w#&dkwjXZ-%Oea7bYGg8FDdLx z{*tG6q4##Zj+IDgiP(iS z(NJ=*_2*~v#SWeoGMA`si&#SBURH_#GfZ0eZ3sqke<8nIRM(CynI3#C;Bu6CU|%wu z&-Hra#rzpgF3sawQ!tcTL?J}iebPfenjJ{|Ss`|3zD&kM+qL6XWY~oRBsvkgi;k#$ zYK2_JW(pSSHR8gfFu;B0QU}%!@Ypv;l=e0-#`t^2v@?6Q++xlO5Hoo#2{XNqZJ~jd zbz7!K`SId$Lh1ww&c=Nj1@6d=O4Q_^Z;(EfG8oP<5d}95$QYhFOhub4%Yk4sxyt}> z(unm!wO^{BTZ#s`p4>Wm5Fi&PCYm-BBZ;bV4q{ZZsM5~J*t4(o3FeiFiPd6Po%l@WHJq0JIlm|0fd4fKVGrKf7;4U;|Y>kqbHqL{AA4w z;@+B6+UM79N7L>}Sgu+8I1pvS!M(+ zbza%#4BZWX_m(1nlOEyAY=}L21LuL7x>8!1oz;D^-^IX~+gRHx&z#9(t;v>J_5KVm zuY!CUjVgW(pZr7~eRO|FJ?}xRCx-l6u@f=V+^4_ahk1_}x2)U99lbp&^u_|5l?kVa2Sk}$(0kFn)73oQnZ{($W1`mAoQ?aw z=LRMmx+mLzZo{t=_Vf&+2d9so|DuRwqrxA(@rc5nDdPN|+hOIT??V2`fT3*QEnC{r zEP}^wwIx?mF4_iKGtc?ibw(uzYA+N^iL0ad140o-s)gV z#pJ%u7I{jfYt5K&#LVkKI|l0HZdCNVypP|d8~(%tB$=-~#&2*d@vlC0-PT~d&e93{ zQFvn^8blOAaN#$ZFiqMpw*9-J0%?e= zpKsfSDTC|SgMM}DTdzgW8>7*F7~pIF?^naT1``a>Y&$BmpeeoAey9BN0?!1P73ozd zROj=n2MDno82qRH<{(nR@nItypup6bMJFZT5(PG=UW3G3#k?PX*EqEO;B-}ujgne}{*I1eP$~z`Q zV$mNDVnF9=!jx>PA^jm%G$zX6neGC4czs6X%(-j&Cv&(0H~z-)6UkMLFFh$C>WliD zd1fNN)E!GYC0%=a__?ndft|%u zMPtPq!f~wVO9|P~gHekq_R7%@&i-WiRsd54b7x1>qU9c%e^WW?K4U9WE@qmJ*7G4S z-@dyJ-RLBT{K*ID=rT#!EDlHw)!Q`VEBE81?~d5GXF*SWT7VA;tOV$fJ-EE3x zvauNwq4p+84ekEOZB-v8Mtx%0t|+`E7!_FiU~h?zZBi0Amn8I=3B}mYKX?EOS+I>z>yxdsohI1q+~iIN%>z@WER0N?x%oStsZg;i_aiK913s(3M9Uh#1gvp!FW zz*UkeV@dv&Emg@OUPU@=F!4??7^N4CEY|-srysq+!+RB&erAl1(!n#M==8SIp`u_w za-bGzq5;#|)Sn`m%L$8}9@Jk0Gzav9ARdmTkW}fz`;a@FU4B66T@WMiQrP)JShs{rEM2sZ%#T7 znvngG?R2($LSju1>E5fm@91*K%*?U@qY7@t%At1dhFF^2F@X-sf^=9*yj;JEr!Jma)6>2u#beilM_d36+E z^IBuVt|y?~eD{x}lRN~>$M@cJ%^|2sfj#MaSdH0FQ~EFKTXndH7ll^0dUWEj(+Jc} zvj6eEzeyNTwSFm;TdzvcxE9}HG<+L67kPcF2r-Jx=n)L}A|A{xeZ|n)bdk zW^O^LOU^BAR09D>?^RW>#;!Gi=CSFT=+phlO;&#+61pIeCv*O`+fmVO0L-u*z7Y~L zOXS}u032vdpPF2Xwc$zR2r^z$hzaVmx-zlD>c+tPC@Q6XOcUhZzAqG#a(6Yoth@^r zy3H?O&t8fm=6VLqn5IIzH^2U=Zf;)pLmAC$-&j7-)yJL2l%uw*$&3Fjd@HNU%%Wz0 z{~rQH{zJsIsK`J|_N^i1TUTtXYC?>*S}Zkbg9*NFI>X6vW`vq0`)Xh4ao_3VGy94U zYea`S5@_nBJ3+M8G})NVLv9b_ST3>JCulY5P!f2jII ztS-`M^?{I9UUM%t1GogBL{E=@wLx0&qM0PYgvkjTYtx?_fZivv2zBwfR|;*V^EbcV zHiOJtcgsb6{XWx=Ifq99=I{B2gDwO6Ow!B|YbEX4<#d10dbwa=_F>s<-VpvlCszd^iN63$HyssT8Tb#<%#3R=F+z*S;#GNo)c{4zoqO|~*Ov9GXiyNE5` zFSM~RVITv*>yv+M`KHh_?6B!-8N0lNbM1#~`c$oeG}HfRx07?xA32+-xoO8OUn~rp zu!=iuVn4jG*z9a>3j)uUkZA{ih3-2A(DH%P zSAvwa?Gnq@`ihjQ_19u2Qga*B1|hAY7)>?7R@msp!n|hLu-kd8wntI1AQ}rjC1QW? zG1_s;ybMOF9K)V7B-5<1DlG4fCwV@oiz=u8mlQ)~NJ+;-V9#0QvL=i1CdkanZffl; z7!8phMi9YizQ|%hCtd$*JT;~h%0u50jx@|r<=XP1;SlIOe9ANgspkPV`K_pZRn`q> z@Zq_o@-h-IvhZF`d5YN2o|~8IWyH~9IS)NsuZ$mPFGPW#y1+8reZyl3KnmQNAIp_P zIs`17&ElP%tA(Fl8r7&CHVeK!M4Mw)9-ruIeS^{P1~2=OvPH_wCde0C5=V8#iVYjc zAt}q=1rBLO^r!-BmOqHeiVn4&?Y(Qm95f!)JEhFLmQ^MiNfXVuP5-lO5XHKPHjicKV@L?37|Jap=uW6-C`l7 zZI@l<4Ti6p<$X1V_gGh|`@V&;+(<7(bAw9BYGHjk; zI}up~JIoJchXEw$%vmq#nt?xyx&R7w?Ac)Us&{!X=@kNbBp9^+>W0>fOKJ69d{vwn z9;PDjcgzOW#&RyP8qc=1@VYu+8AC~TON?rpHB+k($n29XmT5AVh93plJAF#-$L$J3 z&^^+oGB@wRrP(>h7J4#oK%m$6>n!6oFqynxRhD7FJ!^-?)`L`g*X*C_&rQQ&A&l=^ z&w_#$v%I6iS(98G=F*BZ`-iTs9^{PWaXo@^@#thKURwb-cvpA=T-Vw3C zoPkLOpz~{q>}Kq18gBj4L8aIc9(hse1EajOszp|4>lqRpWTosG3WGQaYE;qeaUpH` z`s1-!3zT)P{|>L4Ktf<$O$zmrm*7Et}_tSgJLrJB$X)=i_%spi{!3dl&<7SqMa1Le1c|%pGsdr zqw*41LSI5PKAayER~hjdot=F12;(?)R$wJcdfH*dh_rbSYwdsr4XQ89%bY9aBMz~CiP(l;TvCd5b}G=D|@u>WgAdDWAtWy~eSt~!xD$WL7}A$rhO8@XJY zH=Gt!?-qyuYsu<9VnJ>&RGWzw4?Z2|lYe+VZ^L79%zR6)Q57s?H7iunAAG2=&OGbi z(G=$0BrHjCq^FDfh`c37gwmVi%V|Q)I4X^#?FFpX#F4cXI0pcM!S57aCVCa^@+BX+ zDyQwTUfv$)4(3qYe1pADVxUmiGaBxEkHLQDV;T=}cMNmaFD@XjXxF|*+0*ZM zelj3P3$5yvY0fndrL^rUA%{P9 zCpEY2@tyzpDy@Pq8or|(#oZYX)Cm!PRiWp=zZI#S>%$jV77^xGZZ}%Yjx`W*Lcu9LF=I1S<|8yeZh`ytYcP!F5Tg811NBIlOs5MzpgCJ3qm?5G-s28dfi2!i`$5 z`8fUpU=@|FJ^uXp4XaV817R_RVsZLe2_}mNYf4lI?F)7SLbBvIta4P6n`{@VGm%G> zyfll>ODOEi#-jf!F62G0Dt-f>Z(RUIWTJB)$|kY1JtuELjUt?SMh5<+usU*s$M}fK z!`-Mb%S?s7~Bj(x%q_p95y_JjOdXKufh{!BmRf4 z{)h)7g>(I!_o|m}#ATETp}=LNnwSkc=#Q>4ZCDvjgig;c{ci7)LWhSVC{h=_#vTrD z!q=Jpe6rr1M)s$gtG&3A@G82zTbPV(T8w8-6KefP<8@QBP?$iW*lZ*$xU6i&FdtO8 z!*dw;DVy>lj6Bp~Mzi&?#bSqbuG{xfw4@#$w?$gyM z6d`c^)~p=4I@|F@R@uG;GrFQGgefXVFQEbdm6uQG;2(j;$bv)V!+e(~4JC9gV|}y& z+Fm>7kTsfb^=yAv;yYH8rrtY4nsGOp*Ao=>oO*vN*SRFULH^R3A+6On1J`9X%>iS2 zg=q>cPs*EIDsM$R6ZZbQU%iz?&T#5#%8qw`ceVZZ>Nn;nbCgZJX}kVbyxse2np!9A zH{dlTX2>Xcv@u4Nmgl=lgVyQ5rpty_v0;=WTKLsA%-K-;pArAs3T!bI`ihFt;*#r^ zpo`}|?tIj|s-gU(UHGa*Nbf~l6Jy`K-pLv4fCUrrk+lE@I<8%_*NPlgi4rX39oxKY z&zG3~=8_%t=Byl)Hpca2(G6&KthChYEeK{MekIci&v@nCx{Y#)>&J*=h_Flg<+kWw zO!Jz5cj>F599spyp${}{f@U}dINyJq@Si`UU7>gpy>WlaK(VzoSCL$nt@LeA&s$5v zZ*JkQ+uMxterFXy3;ZVRw83zKCZ_2Lq#~lecj=#We0T zSr#$x;5JOp*vI2F(J9vL>0lK9Pu{A-ixtxhj;KqWDz4qvo6FjjJh>O!=Ygyj$z}_^IOJ{qQ>!zmcA=$@G{> zf2I8i`85&n3#$*q)26uR8%bHEsbS_NimB;J2T$$C(!&(zdQz-vUcTID2XHB6-?Fmc zLa;Fipq9_+xWketL2*Uy=8)kphgZ%qR45Xq*|t3P1r;Ye5ne~armRDS&sEy|^3rIe z6Q|&kTrIFq$~q$$7Ox73=b&N*)pj-D&CRKej=H^-p=V;TheN0@6{vg9dh%C^GeNYP z{Cd*)T`%FV0wkpQg({_s^=)fxi_J=&bJ zkjQIirbLt%{bHeqxnew0G#6<*{X%Ncp3KmE%vyfum`XfVvDDxbSq+yB!aLq=;$$9d zVGW8aiMT=3CDk01&!DhlU8W-SfIUHoh74DI5vlA40(gy9L|kNwp>YUOv_o`|>^}fC z*|c!is+bz-cz9Cg+Mcz0?SHetQx?zuAG9hKejT*C;jX2%%Md*J4 D0r2r2 literal 0 HcmV?d00001 diff --git a/docs/riscv_opensbi_logo_final_grey.png b/docs/riscv_opensbi_logo_final_grey.png new file mode 100644 index 0000000000000000000000000000000000000000..a370f4119d6b4b1b766df3ddf539a4b6c5853577 GIT binary patch literal 9159 zcmZ8{byOTb)Hbrf;)}a1u0_k@EU>^*pcH7aQnXkpR-m}sV#Qrbf#U9z;tq=yE5*II zYmsk%?|Z&~-Z^J7lT2>rCgZJ-H9xWak8XBQ09Hxzih7Ll#4+61KDKn^j z1NA_6(NMP&fi@*47JXf?6;_hwkAJgyVmzy%GBsOP^MeZaB!JsKLTkt$67 zwTJOxwrUc6U-|%My+B(@gR7mrTUi71L>NGUI+~FBU?*I2`*w8!Y3q>Ff<*S!$&6oF z`OtptFFNh=lT8erw zwB}!_hfuhD(~*4X(wF_X!gA_cWvbBM^(4r@@yd6`(b9L){K}jC#clAGXI1aFyGgeo zrOS+V&KmtqR(dpnc#C|X+*!Hx z=Oww8ozV>6Q_*qs-Nwp3d&(h@c2N6c00rTs$kcrj;$loA}T~ZSwxk zFOtzv7EsORRi_8X2@imC!8kX1dmendc+=KRYH-n=Ti8a@ge<~#kB@jYky@0=*b9%KQuhg#-iYUqW9n)9=q#)UAVI zML}r?ORaN@&CaYZ)IlK9=N8GL*}C|^%Hi0b+9~TA-QZpiP=ftJ1XT4%I$kw&-=+LPqTg5nTqKrqHSI34>&}B0L5WT`CuS~xC%{tK*MA!98plF#M~N1IlhU$J_b%sWBLbOZoG;VHW&a`D zullG=^!L{X<5>%vn&w>HRjT;=V!#~TDbZ;xhfH_RE=1+l;;O|gznHwGT8Cry*-r9LD5DG6)( zCNk1%PvlvL455M)!+?TccPZ{GzL5KkfiCY5E?O!9;|nJCo=;C~HWtmof#Pe;p`|e_ zcIaKc+*_BXo8L*leJh41s7r%;o4?SW=JJbWm17lrOt#OMX=vt7cIsjWN5V`@zCLlK z8`N3d#;zOGm@EBG5U`8-uMutorf1x**nj-^aj$YJn8gm8>^!8Vr9JzqBw{(7^g2=C zwmgn5Q4O6tU88_WU6B@IJ(R%y$O?|^>yM$c&@o`fzFu-S*_+w>CYGv3Rro%zfFf?D zOpkLLW6kBLWry)89n@#O-W&1RnfqFNiULGfPQ;hUnd8yTr(d1B&Kw;4ncTzithbDI z$V<|CcR|FHF9sh|y>PzG`??v-&ll@`+%~74BR%i01SG-1%`oxWWq(Syk0OLnXK*lU z%3LO04wVKvJ45RG2&C7!6cDZxemS1oG*9W@*A8Xus0v{X>*&*6@AKi(AvSU-5e3Ay zwp!6Uew4G5#8JSTNqR6g%WwKkk|m0vU@2TIcbr@t%tir*`I(U?hgKJ;z~KEF;hLnN zWp#F*rzX8&Z4x}NBzFC(KwA)4OF1Fn#EQqV7N`P@=bb>es!M4RamMJ*^r-7q1g=4; zhQ-=q>8Px5WslV6GxyhU0iJ1&@>1H>*Ky{nQMC#Jd7!%zEC-P6<{9GRg};iEq;>5!Oj8`B8sW;2(M zDp$LC!Fi?wQm_J8R=`PNp?xf82C;e9kErEk**aH`Ug^8v8&(@_`=iq(Z0D5b^r>y# z0WZ>@_2L2@*GFHIGISOUC5}$~BB}FRlAJm;U{wG>aeix^?OYiIuu+9UbW~Y>f#ZtZ zhbFXJPio54B=kZ&yLdNsETN&l2gLc||2sS)=>^DZlD_XnMRVnb4ZqaW^WKbO1vBeC z-%_nIh4+Suc<7`gS>^NmS=OhPX>s0AE?op|COXZRAiPiR$D|TBb`F%zmc4P1j}JK7 zJ70^jmZ;`QX+v#2yi)@Q_QG6E5ggEBVFfdf4&F`IUsafswR;BGj z`W zStu)qjfUXOM*cN&wRYudmIDr+Zg7$+y&qfjwEA;#^PsO}&5FKjTK#g_%dSeoiP>*h zGuArvqUg6WbQ1$*K;-;8R6}w8DH=#sf2zJ-)kO7`a@T*!i0*G&_j$qqi}_ob;bbt{ z!rVgYkf^&x_Bf$UV9I%v$M0%-J2rwCpMGR|PMm0ajk_E7xcwI>PJNaMEEt~*!YA$A z4X6?oGn!p`K2`p%Zq}dUQ+M;$y|X)(VyW`+r$}``T167*}o^GXw3dnqC;YH)1mRf z`(yDD6_wFECAG~T331y8`opn&=J}c}MirLcZxJzyT{hh%L`0QSkDT?$)U23>t>&>^jMW2(8{^1bc zRlOd+*quW55X-#x5;jz0<;jnJ&qB({43Mv3Ls%4m?G z`9^Q4LGmiC$ziE>#pJz8Hl3P~Q#Xfp(jfE$EtT@f?E*cm%^z)C-AzA_yQKL#cgNB7 zF6XeYl(g?XJv9St-zFCvQL8AKeI&||_HIt5RnNzyjy(u}UP%{E6=^&lN#PgKDeAWt zW^Gg;X+h(k`1HsULh>y9MzrjFL+hmRh;YemNQuu+sc4&QZS z;UhacbDus+Bl^E7h96vb#7os@bri>GeY`$en$3W3mI;h*sZq5l-?z^{Zf9f(>vS?>#rE6z8@~4qopFbMYbSp<<5Z5I@Zl(GfhDW!jA{&vr{>=g z;OSMoI$GL~7_@y#K3(+Ofr*Iz?B+|8lbb14r@hId7)j0Sy2ZcO>sMS1KBi2qhu6!f ztIU3S%u~daaav`dqlyTgY2wwZ6s@zG=@7#@O%o|v;iI9A%$^FobYAbpZLLWjWH&-h zoMV7ZIU9Vr#l<=gaWT3FxnAj*=eQ{ee|(g!`+WEVrJgRyg7Pa5zE7bk=k7es1jrqD zWVoxF+X6sNr)V~XfneXF#M+asqV{1kQS(2z#*5>wB+_YJQD`IKU!>ru*?E@jPQ-R~ zuc+8#HB}h%Mw5GhkoKLJd6TJwd;Sa|8E}xDTTYiT{BNlzfX)~Kx38$n}cXGUs zgzBs=|5ZhYw=k+ZBzln3;lgn`zqlZPvrzi?swVB`p}YJ0s`SfBA5#eUh3a;YF}_T7 z8n_uB1{-hSP)R`VMn%)|i;vS&g&GjzkA9s5$f%VQ+qIxuD_7T+m_S%yUyl!QP;;&9 zAEIaQ=Sr>TQ9?FI1WSN(R(J9z&DDEtRKStwSW`oC-cDUsGqs2FIrtTyi(_@amR}W{Nqe z8(Df^9T?b6+9ccW#BX*ZFcf>ND+pK;>aDQX{vJh)m%cPjiMDBA6CrI0HrO>B6L1K= zbUIlDKN+~0I>)_>2EWzv5PZ{+Ws;=$>hfewaeK*qrGf`-*gKX%%Ial~H22*1n_Ntk zTwYhU8341^@BELUCqMb2zSu}~fbtwBF#fANO(2OHIt4_AJk>BqV!y_f`7HO5+Ng+T zkEja=kEg_thI~7Ip;0S=0iWhq8Sh3EVT1fffP8&@uiPememh0l^?op}jDI^S<$LEk zwXk4UHNLuI`Ujy@$DaO`^adT$rjx`c2TkhWBvCd1;0!dtQjZMod-fTNUD0R=PD9fkF8kj z8ky-A)ulckRJTr>w0Sjr)M0-n>M7Xlxs=1cSZ(l5S||slq5iTV-tju7S@c4r@K-{0Yfx8N+AWMTb7k zk`szO zTxg0VBlar(kJd&8;y0g4Li!>pc#-by=L{}$@3s>6ZwMUNJ||GcV8s(VR>w3?L0gE7 zsHj|WzX`l;L`t6xvZCCMsN1VLU4+b{|I@=&JJ1l_$3!wKXiEyWGD%a1=V)v^v$lXd z$DtmpJCq&or8XVTHiyGt53$@q2Pv_v`0mXh?w%7%&*+GSY-SGIut|~ipP!y}hq$|a zz&o>FKf)A(nODODNY;u{E4~YzNVUZ8f+dJ#M7wbT_kwG;L@3BpH=s%eDzqM`-xBGm zE+IeSaA2sx`!aOubXooDW{EyLr>#{g+sx}^Rerx+ye!t`=jTJie-f%EZ{3fV?Pc%& zvOZB*V1DWL+Ffubz zva4SiGiEQnX9Bcq*X5msHR%P%q*jwwt=?h>?$3|WgUKK7*1Dsn*f=~R~@mVQFxsac7*CsPr z3q?1pxh9=xSPG2EMQKAKk7+_SMl+s|5DA(0xAtplYAgb;+5c8LA4$ASP+JG^5AUtg zH+zr_YzZ9M@N@W!V{79ZX|BJ$zxuF5#Wlf2fXNx%{i>8P)VY4^lOHEz0G9TC-?y6o z$b-Kawl16<(i8amqRhpk`bWTnAX*{Td@RlZ5oTB0bg|JCHEqZsn#Q zQogm?i)mx(&`sEqM zG+zf7d^=r`U_ywJVfg=BSTUp`nk>1Pj|n^8TP!3}8M(DX*AW{k|IBO{jkj7fAg`zh zpRF=6*(M@^$PWSlo2iz^har;kuOZaX8b1-(Qt7Pm6sbH z#LfeN4ne<;G_}kK+Ksj(3t0(E4v}CCvtW59j~}}7+E)45EXIH{OVmssTxCKsGRQ@F z{0n=KW$@bp)O_W07LSTKj(AH63Bg};(dX57^dVY-{Ix3l7NcUe7swbaq)JpIe%R%jg8S`qE zoEc41mfTCIhtBQmQL!M#?3}^CfZV$Vr~t|GLNZ;6wtDC_+hvHB`1wkp$Bg7JZNkbT z$LCrd$u5Y?pas~^zeAi~>(Nz|jX+7&yh^Vm`ED+uDqYcfU#OlF22iV4Wb1IoEpTZG zoZnP+Qc!@fu?~ITtUwG zun>HWPN6XXQIE!8R@AB>2ZXdTBFY~PqA8BOzD|3QW1Bk(auolxiFg{;KaP53o^=ZRJnOhh*IcBLx25)N@tyfYU_?OqP9iG+B%_Hb z!y1$BNl3)0uA0w-a`|nx83tw0D%CgGVBnfPx;NUaF16qWUED1l`|07qmD6)X;j~sxV1|j@)9|S=Xu*zE znvg0?TvmoQsvAUt6KLqAvJ(kLT-WND%mvg3(bA-l z<_)rm(CSpLol>U;S*-C0l0=ovk4v9NXNSTU(Y5S3n~9M3mU-0X-7eNg=iY)(BpQ`q zO7n^A&IeW6k`jta;<`_}prCWPYJwKst_T+iY>M(ia(9UiOta48@8MO``F&lZ2r2SZ zb)ZluDI#;&n7^5yK8jj}x}28w%|t^fm67l|mnb$ZkNHL~7alGC3Spp2&wLi%C6AVvpLMKs<~wG?m~p^YBH+Hyj|qJVOc%8+}TP*i9C>>Z9B{JJ@o~F zf|oyjP1unyA{LWI2Vwp0>}Z3uX^J5jB5bo$r^Wdj6Gm-QE_tzYIPC*J!c#HJsDEH*zSd>{;^sG2OoXbOwm4!_Tk4Ro65K+yz6^O%Fe6uVLB5J48 z8IW+u*LbWyX?=&enKhMvo?WU+F(~0==MuCYPm#rY6oCqT2#Ad2a=kzNZJF|l3ooRn zBGN6Y^VMf6@_a345#i}5)!5$!E%JF`&e_bSwH9wC#Q(-DMr-Cw!Ea>gapX-0Q|6{R z-TT;ATYs$bR5?eRI*!;y)2~qqMJm#Vi{lNrtnhO&`Vj5l>T!=%tV*4|qZ#|G%Wy=j z5Q9Y;tqNHC_iK>ErJc&jPvYrfR{xz3WZUqhb@4#ck8ExT>*uXZFN5H5%S-i>^}2kF z^q;9KUB?l4X+@zcI~>W*>g^`lD!mPTkx^1qwrdbEp^{HMWO!S$*uMz!%$XOV>aKXi zZFrL}|A#WY`TxY}a7-Yin8r0g!pt%;b={o#C+<|JMkAfVvNs3;hR#;?|c zdxJYkghIQxis~UyJ|PmdEUaI%Be$98`P|4bbymhsAez?gDux_5@?{2dDM+F7zwJNN ztTEr|aK}L67hAo>F{0ik5hPYXV08Zx$9_HR3bthg(%F&W*di3a?szgQY$jv(K^H$g ze!YuTV`~w#Z_6?P#!K`W|ED3I^p_7W`nK+EgNk1(!}XD*ZgB-HAzXsAp{VGe`V;`x z>VvB#{XP(=^(tf1)|#LBdvOIH2%MoNPV7i2ssa7=nC7L^i>u}Ot1pWdV zfI#}jk7=R~CaGSi5D4RGG?F-??3dq~;^0I{c3h$flrA7oA$;!>Z*z+ij-Oy0DJ z)Il@#MS<^EkZ0h7)34P=`k0`1=L$z^+*oG$wqXGuuU~NI#`oi`v2kQGt7Mp&fzJSR zmNi0#q#qS1nsBAAl%O*tfABwlF{%z-ModNHj~QGe;bo?LvOg{qsV_rf3;v!LQB*7(-^z>Ee}6s*@y@2#)=d;sT~ zVX~AQ{_9)N{m>FPFcN2LH(+eEG>_5B) zu`w$o>3FKawDP8~3K)W&6gII9P;tVH_yB|;!}Cbyz5HT~1dbLwUb+pVwED{p_*=Q7 zd&vHc7Bh2&w5+Sw!{V#g=&E(;M8^?^2rS$Ef%rzhtbiF8A3$#MwWZCBDcyP!*K%iVTvESQy|+^* z8$-S)A^TO!&X=#*Yi}n~oU9#g%JU-$0jMn1fR^2rt_ Date: Fri, 9 Jun 2023 17:29:10 +0530 Subject: [PATCH 150/187] README.md: Improve project copyright information Over-time a lot of organizations and individuals have contributed to the OpenSBI project so let us add copyright RISC-V International to respect the contributions from all RISC-V members. Signed-off-by: Anup Patel Reviewed-by: Andrew Jones --- README.md | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index bb09fdfeeb0..73de8eaf84f 100644 --- a/README.md +++ b/README.md @@ -6,8 +6,10 @@ RISC-V Open Source Supervisor Binary Interface (OpenSBI) Copyright and License --------------------- -The OpenSBI project is copyright (c) 2019 Western Digital Corporation -or its affiliates and other contributors. +The OpenSBI project is: + +* Copyright (c) 2019 Western Digital Corporation or its affiliates +* Copyright (c) 2023 RISC-V International It is distributed under the terms of the BSD 2-clause license ("Simplified BSD License" or "FreeBSD License", SPDX: *BSD-2-Clause*). From 8153b2622b08802cc542f30a1fcba407a5667ab9 Mon Sep 17 00:00:00 2001 From: Alexandre Ghiti Date: Wed, 14 Jun 2023 10:20:39 +0200 Subject: [PATCH 151/187] platform/lib: Set no-map attribute on all PMP regions This reverts commit 6966ad0abe70 ("platform/lib: Allow the OS to map the regions that are protected by PMP"). It was thought at the time of this commit that allowing the kernel to map PMP protected regions was safe but it is actually not: for example, the hibernation process will try to access any linear mapping page and then will fault on such mapped PMP regions [1]. Another issue is that the device tree specification [2] states that a !no-map region must be declared as EfiBootServicesData/Code in the EFI memory map which would make the PMP protected regions reclaimable by the kernel. And to circumvent this, RISC-V edk2 diverges from the DT specification to declare those regions as EfiReserved. The no-map attribute was removed to allow the kernel to use hugepages larger than 2MB to map the linear mapping to improve the performance but actually a recent talk from Mike Rapoport [3] stated that the performance benefit was marginal. For all those reasons, let's mark all the PMP protected regions as "no-map". [1] https://lore.kernel.org/linux-riscv/CAAYs2=gQvkhTeioMmqRDVGjdtNF_vhB+vm_1dHJxPNi75YDQ_Q@mail.gmail.com/ [2] "3.5.4 /reserved-memory and UEFI" https://github.com/devicetree-org/devicetree-specification/releases/download/v0.4-rc1/devicetree-specification-v0.4-rc1.pdf [3] https://lwn.net/Articles/931406/ Signed-off-by: Alexandre Ghiti Reviewed-by: Atish Patra Reviewed-by: Xiang W --- include/sbi_utils/fdt/fdt_fixup.h | 14 --------- lib/utils/fdt/fdt_fixup.c | 49 +++++++------------------------ platform/generic/sifive/fu540.c | 13 -------- 3 files changed, 10 insertions(+), 66 deletions(-) diff --git a/include/sbi_utils/fdt/fdt_fixup.h b/include/sbi_utils/fdt/fdt_fixup.h index cab3f0f2a99..ecd55a724a8 100644 --- a/include/sbi_utils/fdt/fdt_fixup.h +++ b/include/sbi_utils/fdt/fdt_fixup.h @@ -93,20 +93,6 @@ void fdt_plic_fixup(void *fdt); */ int fdt_reserved_memory_fixup(void *fdt); -/** - * Fix up the reserved memory subnodes in the device tree - * - * This routine adds the no-map property to the reserved memory subnodes so - * that the OS does not map those PMP protected memory regions. - * - * Platform codes must call this helper in their final_init() after fdt_fixups() - * if the OS should not map the PMP protected reserved regions. - * - * @param fdt: device tree blob - * @return zero on success and -ve on failure - */ -int fdt_reserved_memory_nomap_fixup(void *fdt); - /** * General device tree fix-up * diff --git a/lib/utils/fdt/fdt_fixup.c b/lib/utils/fdt/fdt_fixup.c index ae6be008579..e213dedba61 100644 --- a/lib/utils/fdt/fdt_fixup.c +++ b/lib/utils/fdt/fdt_fixup.c @@ -210,7 +210,7 @@ void fdt_plic_fixup(void *fdt) static int fdt_resv_memory_update_node(void *fdt, unsigned long addr, unsigned long size, int index, - int parent, bool no_map) + int parent) { int na = fdt_address_cells(fdt, 0); int ns = fdt_size_cells(fdt, 0); @@ -239,16 +239,14 @@ static int fdt_resv_memory_update_node(void *fdt, unsigned long addr, if (subnode < 0) return subnode; - if (no_map) { - /* - * Tell operating system not to create a virtual - * mapping of the region as part of its standard - * mapping of system memory. - */ - err = fdt_setprop_empty(fdt, subnode, "no-map"); - if (err < 0) - return err; - } + /* + * Tell operating system not to create a virtual + * mapping of the region as part of its standard + * mapping of system memory. + */ + err = fdt_setprop_empty(fdt, subnode, "no-map"); + if (err < 0) + return err; /* encode the property value */ val = reg; @@ -286,7 +284,6 @@ int fdt_reserved_memory_fixup(void *fdt) { struct sbi_domain_memregion *reg; struct sbi_domain *dom = sbi_domain_thishart_ptr(); - struct sbi_scratch *scratch = sbi_scratch_thishart_ptr(); unsigned long filtered_base[PMP_COUNT] = { 0 }; unsigned char filtered_order[PMP_COUNT] = { 0 }; unsigned long addr, size; @@ -382,33 +379,7 @@ int fdt_reserved_memory_fixup(void *fdt) for (j = 0; j < i; j++) { addr = filtered_base[j]; size = 1UL << filtered_order[j]; - fdt_resv_memory_update_node(fdt, addr, size, j, parent, - (sbi_hart_pmp_count(scratch)) - ? false : true); - } - - return 0; -} - -int fdt_reserved_memory_nomap_fixup(void *fdt) -{ - int parent, subnode; - int err; - - /* Locate the reserved memory node */ - parent = fdt_path_offset(fdt, "/reserved-memory"); - if (parent < 0) - return parent; - - fdt_for_each_subnode(subnode, fdt, parent) { - /* - * Tell operating system not to create a virtual - * mapping of the region as part of its standard - * mapping of system memory. - */ - err = fdt_setprop_empty(fdt, subnode, "no-map"); - if (err < 0) - return err; + fdt_resv_memory_update_node(fdt, addr, size, j, parent); } return 0; diff --git a/platform/generic/sifive/fu540.c b/platform/generic/sifive/fu540.c index 08f7bfc401e..b980f44371b 100644 --- a/platform/generic/sifive/fu540.c +++ b/platform/generic/sifive/fu540.c @@ -20,18 +20,6 @@ static u64 sifive_fu540_tlbr_flush_limit(const struct fdt_match *match) return 0; } -static int sifive_fu540_fdt_fixup(void *fdt, const struct fdt_match *match) -{ - /* - * SiFive Freedom U540 has an erratum that prevents S-mode software - * to access a PMP protected region using 1GB page table mapping, so - * always add the no-map attribute on this platform. - */ - fdt_reserved_memory_nomap_fixup(fdt); - - return 0; -} - static const struct fdt_match sifive_fu540_match[] = { { .compatible = "sifive,fu540" }, { .compatible = "sifive,fu540g" }, @@ -43,5 +31,4 @@ static const struct fdt_match sifive_fu540_match[] = { const struct platform_override sifive_fu540 = { .match_table = sifive_fu540_match, .tlbr_flush_limit = sifive_fu540_tlbr_flush_limit, - .fdt_fixup = sifive_fu540_fdt_fixup, }; From d64942f0e4fe63a248e7ba3dd7ff4dec02954134 Mon Sep 17 00:00:00 2001 From: Xiang W Date: Fri, 16 Jun 2023 15:03:51 +0800 Subject: [PATCH 152/187] firmware: Fix find hart index After the loop to find the hartid is launched, assigning -1 to index will fail in the subsequent compare instruction bge. Fix This. Signed-off-by: Xiang W Reviewed-by: Anup Patel --- firmware/fw_base.S | 1 - 1 file changed, 1 deletion(-) diff --git a/firmware/fw_base.S b/firmware/fw_base.S index fff09e1365c..b94742395c9 100644 --- a/firmware/fw_base.S +++ b/firmware/fw_base.S @@ -471,7 +471,6 @@ _start_warm: add s9, s9, 4 add a4, a4, 1 blt a4, s7, 1b - li a4, -1 2: add s6, a4, zero 3: bge s6, s7, _start_hang From 27c957a43b030523baf931a3b8ef002418fb27ad Mon Sep 17 00:00:00 2001 From: Guo Ren Date: Sun, 18 Jun 2023 11:07:16 -0400 Subject: [PATCH 153/187] lib: reset: Move fdt_reset_init into generic_early_init The fdt_reset_thead driver needs to modify the __reset_thead_csr_stub text region for the secondary harts booting. After that, the sbi_hart_pmp_configure may lock down the text region with M_READABLE & M_EXECUTABLE attributes in the future. Currently, the M_READABLE & M_EXECUtABLE have no effect on m-mode, the L-bit in pmpcfg csr is useless for the current opensbi scenario. See: Priv-isa-spec 3.7.1.2. Locking and Privilege Mode When the L bit is clear, any M-mode access matching the PMP entry will succeed; the R/W/X permissions apply only to S and U modes. That's why current fdt_reset_thead could still work well after commit: 230278dcf127 ("lib: sbi: Add separate entries for firmware RX and RW regions"). So this patch fixes up a fake bug for the M-mode permission setting of the future. Fixes: 230278dcf127 ("lib: sbi: Add separate entries for firmware RX and RW regions") Link: http://lists.infradead.org/pipermail/opensbi/2023-June/005176.html Reported-by: Jessica Clarke Signed-off-by: Guo Ren Signed-off-by: Guo Ren Reviewed-by: Anup Patel --- platform/generic/platform.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/platform/generic/platform.c b/platform/generic/platform.c index 0c9cd951817..86811e6b02c 100644 --- a/platform/generic/platform.c +++ b/platform/generic/platform.c @@ -143,6 +143,9 @@ static int generic_nascent_init(void) static int generic_early_init(bool cold_boot) { + if (cold_boot) + fdt_reset_init(); + if (!generic_plat || !generic_plat->early_init) return 0; @@ -154,9 +157,6 @@ static int generic_final_init(bool cold_boot) void *fdt; int rc; - if (cold_boot) - fdt_reset_init(); - if (generic_plat && generic_plat->final_init) { rc = generic_plat->final_init(cold_boot, generic_plat_match); if (rc) From 8bd666a25b543ba391ae6ee81c1a2469e95c4a05 Mon Sep 17 00:00:00 2001 From: Gianluca Guida Date: Thu, 22 Jun 2023 18:38:59 +0100 Subject: [PATCH 154/187] lib: sbi: check A2 register in ecall_dbcn_handler. Do not ignore register A2 (high bits of physical address) in the dbcn handler (RV64). Signed-off-by: Gianluca Guida Reviewed-by: Anup Patel --- lib/sbi/sbi_ecall_dbcn.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/lib/sbi/sbi_ecall_dbcn.c b/lib/sbi/sbi_ecall_dbcn.c index e0b892c2ed6..ecec027a0e1 100644 --- a/lib/sbi/sbi_ecall_dbcn.c +++ b/lib/sbi/sbi_ecall_dbcn.c @@ -34,11 +34,14 @@ static int sbi_ecall_dbcn_handler(unsigned long extid, unsigned long funcid, * Based on above, we simply fail if the upper 32bits of * the physical address (i.e. a2 register) is non-zero on * RV32. + * + * Analogously, we fail if the upper 64bit of the + * physical address (i.e. a2 register) is non-zero on + * RV64. */ -#if __riscv_xlen == 32 if (regs->a2) return SBI_ERR_FAILED; -#endif + if (!sbi_domain_check_addr_range(sbi_domain_thishart_ptr(), regs->a1, regs->a0, smode, SBI_DOMAIN_READ|SBI_DOMAIN_WRITE)) From 2552799a1df30a3dcd2321a8b75d61d06f5fb9fc Mon Sep 17 00:00:00 2001 From: Anup Patel Date: Fri, 23 Jun 2023 11:01:49 +0530 Subject: [PATCH 155/187] include: Bump-up version to 1.3 This patch updates OpenSBI version to 1.3 as part of release preparation. Signed-off-by: Anup Patel --- include/sbi/sbi_version.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/sbi/sbi_version.h b/include/sbi/sbi_version.h index dd75deae814..641cf8814b2 100644 --- a/include/sbi/sbi_version.h +++ b/include/sbi/sbi_version.h @@ -11,7 +11,7 @@ #define __SBI_VERSION_H__ #define OPENSBI_VERSION_MAJOR 1 -#define OPENSBI_VERSION_MINOR 2 +#define OPENSBI_VERSION_MINOR 3 /** * OpenSBI 32-bit version with: From 0907de38dbcd121d2f8b4bafaf7f9fe76092d5f1 Mon Sep 17 00:00:00 2001 From: Gianluca Guida Date: Thu, 29 Jun 2023 15:24:08 +0100 Subject: [PATCH 156/187] lib: sbi: fix comment indent Use tabs rather than spaces. Signed-off-by: Gianluca Guida Reviewed-by: Anup Patel --- lib/sbi/sbi_ecall_dbcn.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/lib/sbi/sbi_ecall_dbcn.c b/lib/sbi/sbi_ecall_dbcn.c index ecec027a0e1..8e687298a39 100644 --- a/lib/sbi/sbi_ecall_dbcn.c +++ b/lib/sbi/sbi_ecall_dbcn.c @@ -34,10 +34,10 @@ static int sbi_ecall_dbcn_handler(unsigned long extid, unsigned long funcid, * Based on above, we simply fail if the upper 32bits of * the physical address (i.e. a2 register) is non-zero on * RV32. - * - * Analogously, we fail if the upper 64bit of the - * physical address (i.e. a2 register) is non-zero on - * RV64. + * + * Analogously, we fail if the upper 64bit of the + * physical address (i.e. a2 register) is non-zero on + * RV64. */ if (regs->a2) return SBI_ERR_FAILED; From eb736a5118b8d271bd649d713b6a058882c8fb7b Mon Sep 17 00:00:00 2001 From: Heinrich Schuchardt Date: Mon, 3 Jul 2023 15:43:18 +0200 Subject: [PATCH 157/187] lib: sbi_pmu: Avoid out of bounds access On a misconfigured system we could access phs->active_events[] out of bounds. Check that num_hw_ctrs is less or equal SBI_PMU_HW_CTR_MAX. Addresses-Coverity-ID: 1566113 ("Out-of-bounds read") Addresses-Coverity-ID: 1566114 ("Out-of-bounds write") Signed-off-by: Heinrich Schuchardt Reviewed-by: Andrew Jones Reviewed-by: Anup Patel --- lib/sbi/sbi_pmu.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/lib/sbi/sbi_pmu.c b/lib/sbi/sbi_pmu.c index c73e6ef3ff2..7213a53b0b5 100644 --- a/lib/sbi/sbi_pmu.c +++ b/lib/sbi/sbi_pmu.c @@ -933,6 +933,8 @@ int sbi_pmu_init(struct sbi_scratch *scratch, bool cold_boot) /* mcycle & minstret is available always */ num_hw_ctrs = sbi_hart_mhpm_count(scratch) + 3; + if (num_hw_ctrs > SBI_PMU_HW_CTR_MAX) + return SBI_EINVAL; total_ctrs = num_hw_ctrs + SBI_PMU_FW_CTR_MAX; } From 7828eebaaa773fd83e63471ca27be3f30a0694f6 Mon Sep 17 00:00:00 2001 From: Ben Dooks Date: Wed, 1 Mar 2023 12:25:25 +0000 Subject: [PATCH 158/187] gpio/desginware: add Synopsys DesignWare APB GPIO support Add a driver for the Synopsys DesignWare APB GPIO IP block found in many SoCs. Signed-off-by: Ben Dooks Reviewed-by: Anup Patel --- lib/utils/gpio/Kconfig | 4 + lib/utils/gpio/fdt_gpio_designware.c | 140 +++++++++++++++++++++++++++ lib/utils/gpio/objects.mk | 3 + platform/generic/configs/defconfig | 1 + 4 files changed, 148 insertions(+) create mode 100644 lib/utils/gpio/fdt_gpio_designware.c diff --git a/lib/utils/gpio/Kconfig b/lib/utils/gpio/Kconfig index 1b338a6fd94..1a437e67d97 100644 --- a/lib/utils/gpio/Kconfig +++ b/lib/utils/gpio/Kconfig @@ -10,6 +10,10 @@ config FDT_GPIO if FDT_GPIO +config FDT_GPIO_DESIGNWARE + bool "DesignWare GPIO driver" + default n + config FDT_GPIO_SIFIVE bool "SiFive GPIO FDT driver" default n diff --git a/lib/utils/gpio/fdt_gpio_designware.c b/lib/utils/gpio/fdt_gpio_designware.c new file mode 100644 index 00000000000..6223d7e7c41 --- /dev/null +++ b/lib/utils/gpio/fdt_gpio_designware.c @@ -0,0 +1,140 @@ +/* + * SPDX-License-Identifier: BSD-2-Clause + * + * Copyright (c) 2022 SiFive + * + * GPIO driver for Synopsys DesignWare APB GPIO + * + * Authors: + * Ben Dooks + */ + +#include + +#include +#include + +#include +#include + +#define DW_GPIO_CHIP_MAX 4 /* need 1 per bank in use */ +#define DW_GPIO_PINS_MAX 32 + +#define DW_GPIO_DDR 0x4 +#define DW_GPIO_DR 0x0 +#define DW_GPIO_BIT(_b) (1UL << (_b)) + +struct dw_gpio_chip { + void *dr; + void *ext; + struct gpio_chip chip; +}; + +extern struct fdt_gpio fdt_gpio_designware; + +static unsigned int dw_gpio_chip_count; +static struct dw_gpio_chip dw_gpio_chip_array[DW_GPIO_CHIP_MAX]; + +#define pin_to_chip(__p) container_of((__p)->chip, struct dw_gpio_chip, chip); + +static int dw_gpio_direction_output(struct gpio_pin *gp, int value) +{ + struct dw_gpio_chip *chip = pin_to_chip(gp); + unsigned long v; + + v = readl(chip->dr + DW_GPIO_DR); + if (!value) + v &= ~DW_GPIO_BIT(gp->offset); + else + v |= DW_GPIO_BIT(gp->offset); + writel(v, chip->dr + DW_GPIO_DR); + + /* the DR is output only so we can set it then the DDR to set + * the data direction, to avoid glitches. + */ + v = readl(chip->dr + DW_GPIO_DDR); + v |= DW_GPIO_BIT(gp->offset); + writel(v, chip->dr + DW_GPIO_DDR); + + return 0; +} + +static void dw_gpio_set(struct gpio_pin *gp, int value) +{ + struct dw_gpio_chip *chip = pin_to_chip(gp); + unsigned long v; + + v = readl(chip->dr + DW_GPIO_DR); + if (!value) + v &= ~DW_GPIO_BIT(gp->offset); + else + v |= DW_GPIO_BIT(gp->offset); + writel(v, chip->dr + DW_GPIO_DR); +} + +/* notes: + * each sub node is a bank and has ngpios or snpns,nr-gpios and a reg property + * with the compatible `snps,dw-apb-gpio-port`. + * bank A is the only one with irq support but we're not using it here +*/ + +static int dw_gpio_init_bank(void *fdt, int nodeoff, u32 phandle, + const struct fdt_match *match) +{ + struct dw_gpio_chip *chip; + const fdt32_t *val; + uint64_t addr; + int rc, poff, nr_pins, bank, len; + + if (dw_gpio_chip_count >= DW_GPIO_CHIP_MAX) + return SBI_ENOSPC; + + /* need to get parent for the address property */ + poff = fdt_parent_offset(fdt, nodeoff); + if (poff < 0) + return SBI_EINVAL; + + rc = fdt_get_node_addr_size(fdt, poff, 0, &addr, NULL); + if (rc) + return rc; + + val = fdt_getprop(fdt, nodeoff, "reg", &len); + if (!val || len <= 0) + return SBI_EINVAL; + bank = fdt32_to_cpu(*val); + + val = fdt_getprop(fdt, nodeoff, "snps,nr-gpios", &len); + if (!val) + val = fdt_getprop(fdt, nodeoff, "ngpios", &len); + if (!val || len <= 0) + return SBI_EINVAL; + nr_pins = fdt32_to_cpu(*val); + + chip = &dw_gpio_chip_array[dw_gpio_chip_count]; + + chip->dr = (void *)addr + (bank * 0xc); + chip->ext = (void *)addr + (bank * 4) + 0x50; + chip->chip.driver = &fdt_gpio_designware; + chip->chip.id = phandle; + chip->chip.ngpio = nr_pins; + chip->chip.set = dw_gpio_set; + chip->chip.direction_output = dw_gpio_direction_output; + rc = gpio_chip_add(&chip->chip); + if (rc) + return rc; + + dw_gpio_chip_count++; + return 0; +} + +/* since we're only probed when used, match on port not main controller node */ +static const struct fdt_match dw_gpio_match[] = { + { .compatible = "snps,dw-apb-gpio-port" }, + { }, +}; + +struct fdt_gpio fdt_gpio_designware = { + .match_table = dw_gpio_match, + .xlate = fdt_gpio_simple_xlate, + .init = dw_gpio_init_bank, +}; diff --git a/lib/utils/gpio/objects.mk b/lib/utils/gpio/objects.mk index 8f4a6a84fb1..76647a591d5 100644 --- a/lib/utils/gpio/objects.mk +++ b/lib/utils/gpio/objects.mk @@ -10,6 +10,9 @@ libsbiutils-objs-$(CONFIG_FDT_GPIO) += gpio/fdt_gpio.o libsbiutils-objs-$(CONFIG_FDT_GPIO) += gpio/fdt_gpio_drivers.o +carray-fdt_gpio_drivers-$(CONFIG_FDT_GPIO_DESIGNWARE) += fdt_gpio_designware +libsbiutils-objs-$(CONFIG_FDT_GPIO_DESIGNWARE) += gpio/fdt_gpio_designware.o + carray-fdt_gpio_drivers-$(CONFIG_FDT_GPIO_SIFIVE) += fdt_gpio_sifive libsbiutils-objs-$(CONFIG_FDT_GPIO_SIFIVE) += gpio/fdt_gpio_sifive.o diff --git a/platform/generic/configs/defconfig b/platform/generic/configs/defconfig index ee0df38a22e..671281bb6cb 100644 --- a/platform/generic/configs/defconfig +++ b/platform/generic/configs/defconfig @@ -5,6 +5,7 @@ CONFIG_PLATFORM_SIFIVE_FU540=y CONFIG_PLATFORM_SIFIVE_FU740=y CONFIG_PLATFORM_STARFIVE_JH7110=y CONFIG_FDT_GPIO=y +CONFIG_FDT_GPIO_DESIGNWARE=y CONFIG_FDT_GPIO_SIFIVE=y CONFIG_FDT_GPIO_STARFIVE=y CONFIG_FDT_I2C=y From c6a35733b74aeff612398f274ed19a74f81d1f37 Mon Sep 17 00:00:00 2001 From: Anup Patel Date: Wed, 5 Jul 2023 12:15:15 +0530 Subject: [PATCH 159/187] lib: utils: Fix sbi_hartid_to_scratch() usage in ACLINT drivers The cold_init() functions of ACLINT drivers should skip the HART if sbi_hartid_to_scratch() returns NULL because we might be dealing with a HART that is disabled in the device tree. Signed-off-by: Anup Patel Reviewed-by: Xiang W --- lib/utils/ipi/aclint_mswi.c | 7 ++++++- lib/utils/timer/aclint_mtimer.c | 7 ++++++- 2 files changed, 12 insertions(+), 2 deletions(-) diff --git a/lib/utils/ipi/aclint_mswi.c b/lib/utils/ipi/aclint_mswi.c index f47b3bcbbb4..140a49b5f52 100644 --- a/lib/utils/ipi/aclint_mswi.c +++ b/lib/utils/ipi/aclint_mswi.c @@ -101,8 +101,13 @@ int aclint_mswi_cold_init(struct aclint_mswi_data *mswi) /* Update MSWI pointer in scratch space */ for (i = 0; i < mswi->hart_count; i++) { scratch = sbi_hartid_to_scratch(mswi->first_hartid + i); + /* + * We don't need to fail if scratch pointer is not available + * because we might be dealing with hartid of a HART disabled + * in the device tree. + */ if (!scratch) - return SBI_ENOENT; + continue; mswi_set_hart_data_ptr(scratch, mswi); } diff --git a/lib/utils/timer/aclint_mtimer.c b/lib/utils/timer/aclint_mtimer.c index 13af5d8232d..271e6252fef 100644 --- a/lib/utils/timer/aclint_mtimer.c +++ b/lib/utils/timer/aclint_mtimer.c @@ -219,8 +219,13 @@ int aclint_mtimer_cold_init(struct aclint_mtimer_data *mt, /* Update MTIMER pointer in scratch space */ for (i = 0; i < mt->hart_count; i++) { scratch = sbi_hartid_to_scratch(mt->first_hartid + i); + /* + * We don't need to fail if scratch pointer is not available + * because we might be dealing with hartid of a HART disabled + * in the device tree. + */ if (!scratch) - return SBI_ENOENT; + continue; mtimer_set_hart_data_ptr(scratch, mt); } From 1a398d9faa60ac0341614f59b864340fc5e49a35 Mon Sep 17 00:00:00 2001 From: Anup Patel Date: Wed, 5 Jul 2023 11:57:17 +0530 Subject: [PATCH 160/187] lib: sbi: Add Zicntr as a HART ISA extension Recently ratified Zicntr ISA extension covers cycle, time and instret CSRs so we replace the "time" ISA extension with "zicntr" ISA extension in OpenSBI. Signed-off-by: Anup Patel Reviewed-by: Xiang W --- include/sbi/sbi_hart.h | 4 ++-- lib/sbi/sbi_hart.c | 6 +++--- lib/sbi/sbi_timer.c | 2 +- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/include/sbi/sbi_hart.h b/include/sbi/sbi_hart.h index 95b40e75933..d48940d235f 100644 --- a/include/sbi/sbi_hart.h +++ b/include/sbi/sbi_hart.h @@ -28,8 +28,8 @@ enum sbi_hart_priv_versions { enum sbi_hart_extensions { /** Hart has Sscofpmt extension */ SBI_HART_EXT_SSCOFPMF = 0, - /** HART has HW time CSR (extension name not available) */ - SBI_HART_EXT_TIME, + /** HART has Zicntr extension (i.e. HW cycle, time & instret CSRs) */ + SBI_HART_EXT_ZICNTR, /** HART has AIA M-mode CSRs */ SBI_HART_EXT_SMAIA, /** HART has Smstateen CSR **/ diff --git a/lib/sbi/sbi_hart.c b/lib/sbi/sbi_hart.c index 6e52cbd76d8..c47048285fd 100644 --- a/lib/sbi/sbi_hart.c +++ b/lib/sbi/sbi_hart.c @@ -441,8 +441,8 @@ static inline char *sbi_hart_extension_id2string(int ext) case SBI_HART_EXT_SSCOFPMF: estr = "sscofpmf"; break; - case SBI_HART_EXT_TIME: - estr = "time"; + case SBI_HART_EXT_ZICNTR: + estr = "zicntr"; break; case SBI_HART_EXT_SMAIA: estr = "smaia"; @@ -676,7 +676,7 @@ static int hart_detect_features(struct sbi_scratch *scratch) csr_read_allowed(CSR_TIME, (unsigned long)&trap); if (!trap.cause) __sbi_hart_update_extension(hfeatures, - SBI_HART_EXT_TIME, true); + SBI_HART_EXT_ZICNTR, true); /* Detect if hart has AIA local interrupt CSRs */ csr_read_allowed(CSR_MTOPI, (unsigned long)&trap); diff --git a/lib/sbi/sbi_timer.c b/lib/sbi/sbi_timer.c index 4b24cbeb7c2..7b618de1e7f 100644 --- a/lib/sbi/sbi_timer.c +++ b/lib/sbi/sbi_timer.c @@ -188,7 +188,7 @@ int sbi_timer_init(struct sbi_scratch *scratch, bool cold_boot) if (!time_delta_off) return SBI_ENOMEM; - if (sbi_hart_has_extension(scratch, SBI_HART_EXT_TIME)) + if (sbi_hart_has_extension(scratch, SBI_HART_EXT_ZICNTR)) get_time_val = get_ticks; } else { if (!time_delta_off) From 669089c5f291f5543db1c46e8d6b04ffe49e9576 Mon Sep 17 00:00:00 2001 From: Anup Patel Date: Wed, 5 Jul 2023 12:15:56 +0530 Subject: [PATCH 161/187] lib: sbi: Add Zihpm as a HART ISA extension Recently ratified Zihpm ISA extension covers all [m]hpm* CSRs so we add Zihpm as a HART ISA extension in OpenSBI. Signed-off-by: Anup Patel Reviewed-by: Xiang W --- include/sbi/sbi_hart.h | 2 ++ lib/sbi/sbi_hart.c | 8 ++++++++ 2 files changed, 10 insertions(+) diff --git a/include/sbi/sbi_hart.h b/include/sbi/sbi_hart.h index d48940d235f..938248f36c4 100644 --- a/include/sbi/sbi_hart.h +++ b/include/sbi/sbi_hart.h @@ -36,6 +36,8 @@ enum sbi_hart_extensions { SBI_HART_EXT_SMSTATEEN, /** HART has Sstc extension */ SBI_HART_EXT_SSTC, + /** HART has Zihpm extension */ + SBI_HART_EXT_ZIHPM, /** Maximum index of Hart extension */ SBI_HART_EXT_MAX, diff --git a/lib/sbi/sbi_hart.c b/lib/sbi/sbi_hart.c index c47048285fd..ff6f5826c62 100644 --- a/lib/sbi/sbi_hart.c +++ b/lib/sbi/sbi_hart.c @@ -453,6 +453,9 @@ static inline char *sbi_hart_extension_id2string(int ext) case SBI_HART_EXT_SMSTATEEN: estr = "smstateen"; break; + case SBI_HART_EXT_ZIHPM: + estr = "zihpm"; + break; default: break; } @@ -706,6 +709,11 @@ static int hart_detect_features(struct sbi_scratch *scratch) if (rc) return rc; + /* Extensions implied by other extensions and features */ + if (hfeatures->mhpm_count) + __sbi_hart_update_extension(hfeatures, + SBI_HART_EXT_ZIHPM, true); + /* Mark hart feature detection done */ hfeatures->detected = true; From 72b9c8ff89a963bcec0a7f41fc679ee5246efd01 Mon Sep 17 00:00:00 2001 From: Anup Patel Date: Wed, 5 Jul 2023 12:23:57 +0530 Subject: [PATCH 162/187] lib: sbi: Alphabetically sort HART ISA extensions Let us follow alphabetical order for HART ISA extension so that it is simpler to maintain. Signed-off-by: Anup Patel Reviewed-by: Xiang W --- include/sbi/sbi_hart.h | 10 +++++----- lib/sbi/sbi_hart.c | 16 ++++++++-------- 2 files changed, 13 insertions(+), 13 deletions(-) diff --git a/include/sbi/sbi_hart.h b/include/sbi/sbi_hart.h index 938248f36c4..b97f78cd11e 100644 --- a/include/sbi/sbi_hart.h +++ b/include/sbi/sbi_hart.h @@ -26,16 +26,16 @@ enum sbi_hart_priv_versions { /** Possible ISA extensions of a hart */ enum sbi_hart_extensions { - /** Hart has Sscofpmt extension */ - SBI_HART_EXT_SSCOFPMF = 0, - /** HART has Zicntr extension (i.e. HW cycle, time & instret CSRs) */ - SBI_HART_EXT_ZICNTR, /** HART has AIA M-mode CSRs */ - SBI_HART_EXT_SMAIA, + SBI_HART_EXT_SMAIA = 0, /** HART has Smstateen CSR **/ SBI_HART_EXT_SMSTATEEN, + /** Hart has Sscofpmt extension */ + SBI_HART_EXT_SSCOFPMF, /** HART has Sstc extension */ SBI_HART_EXT_SSTC, + /** HART has Zicntr extension (i.e. HW cycle, time & instret CSRs) */ + SBI_HART_EXT_ZICNTR, /** HART has Zihpm extension */ SBI_HART_EXT_ZIHPM, diff --git a/lib/sbi/sbi_hart.c b/lib/sbi/sbi_hart.c index ff6f5826c62..2eacefb17c2 100644 --- a/lib/sbi/sbi_hart.c +++ b/lib/sbi/sbi_hart.c @@ -438,20 +438,20 @@ static inline char *sbi_hart_extension_id2string(int ext) char *estr = NULL; switch (ext) { - case SBI_HART_EXT_SSCOFPMF: - estr = "sscofpmf"; - break; - case SBI_HART_EXT_ZICNTR: - estr = "zicntr"; - break; case SBI_HART_EXT_SMAIA: estr = "smaia"; break; + case SBI_HART_EXT_SMSTATEEN: + estr = "smstateen"; + break; + case SBI_HART_EXT_SSCOFPMF: + estr = "sscofpmf"; + break; case SBI_HART_EXT_SSTC: estr = "sstc"; break; - case SBI_HART_EXT_SMSTATEEN: - estr = "smstateen"; + case SBI_HART_EXT_ZICNTR: + estr = "zicntr"; break; case SBI_HART_EXT_ZIHPM: estr = "zihpm"; From 5359fc69552ffa270b95c2935ef4407b050c43cb Mon Sep 17 00:00:00 2001 From: Anup Patel Date: Wed, 5 Jul 2023 12:34:31 +0530 Subject: [PATCH 163/187] lib: sbi: Rename hart_pmu_get_allowed_bits() function The hart_pmu_get_allowed_bits() function detects implemented bits of mhpm counters so let us rename this function accordingly. Signed-off-by: Anup Patel Reviewed-by: Xiang W --- lib/sbi/sbi_hart.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/sbi/sbi_hart.c b/lib/sbi/sbi_hart.c index 2eacefb17c2..e9b2b271b8a 100644 --- a/lib/sbi/sbi_hart.c +++ b/lib/sbi/sbi_hart.c @@ -527,7 +527,7 @@ static unsigned long hart_pmp_get_allowed_addr(void) return val; } -static int hart_pmu_get_allowed_bits(void) +static int hart_mhpm_get_allowed_bits(void) { unsigned long val = ~(0UL); struct sbi_trap_info trap = {0}; @@ -628,7 +628,7 @@ static int hart_detect_features(struct sbi_scratch *scratch) /* Detect number of MHPM counters */ __check_csr(CSR_MHPMCOUNTER3, 0, 1UL, mhpm_count, __mhpm_skip); - hfeatures->mhpm_bits = hart_pmu_get_allowed_bits(); + hfeatures->mhpm_bits = hart_mhpm_get_allowed_bits(); __check_csr_4(CSR_MHPMCOUNTER4, 0, 1UL, mhpm_count, __mhpm_skip); __check_csr_8(CSR_MHPMCOUNTER8, 0, 1UL, mhpm_count, __mhpm_skip); From 976895c57e3b0655466e20c6eb0d7c670b9e8452 Mon Sep 17 00:00:00 2001 From: Ley Foon Tan Date: Thu, 6 Jul 2023 14:30:28 +0800 Subject: [PATCH 164/187] lib: sbi: Fix Priv spec version for [m|s]counteren and mcountinhibit CSRs Fix Priv spec version typo in commit d4b563c881d6 ("lib: sbi: Remove MCOUNTEREN and SCOUNTEREN hart features"). At least Priv spec v1.11 is required for [m|s]counteren and mcountinhibit CSRs. Fixes: d4b563c881d6 ("lib: sbi: Remove MCOUNTEREN and SCOUNTEREN hart features") Signed-off-by: Ley Foon Tan Reviewed-by: Anup Patel --- lib/sbi/sbi_hart.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/sbi/sbi_hart.c b/lib/sbi/sbi_hart.c index e9b2b271b8a..0c27fd7ba01 100644 --- a/lib/sbi/sbi_hart.c +++ b/lib/sbi/sbi_hart.c @@ -667,7 +667,7 @@ static int hart_detect_features(struct sbi_scratch *scratch) hfeatures->priv_version = SBI_HART_PRIV_VER_1_12; /* Counter overflow/filtering is not useful without mcounter/inhibit */ - if (hfeatures->priv_version >= SBI_HART_PRIV_VER_1_12) { + if (hfeatures->priv_version >= SBI_HART_PRIV_VER_1_11) { /* Detect if hart supports sscofpmf */ csr_read_allowed(CSR_SCOUNTOVF, (unsigned long)&trap); if (!trap.cause) From 60539176266fa37b4bc20054128bebec5bbe7055 Mon Sep 17 00:00:00 2001 From: Xiang W Date: Mon, 10 Jul 2023 00:02:21 +0800 Subject: [PATCH 165/187] lib: sbi: Fix how print gets flags The flags for print should be able to appear in any order. The previous code required the order to be fixed. Signed-off-by: Xiang W Reviewed-by: Anup Patel --- lib/sbi/sbi_console.c | 30 +++++++++++++++++++----------- 1 file changed, 19 insertions(+), 11 deletions(-) diff --git a/lib/sbi/sbi_console.c b/lib/sbi/sbi_console.c index 168dffd0642..d87b5c20efc 100644 --- a/lib/sbi/sbi_console.c +++ b/lib/sbi/sbi_console.c @@ -236,6 +236,7 @@ static int printi(char **out, u32 *out_len, long long i, int b, int sg, static int print(char **out, u32 *out_len, const char *format, va_list args) { + bool flags_done; int width, flags, pc = 0; char scr[2], *tout; bool use_tbuf = (!out) ? true : false; @@ -268,17 +269,24 @@ static int print(char **out, u32 *out_len, const char *format, va_list args) if (*format == '%') goto literal; /* Get flags */ - if (*format == '-') { - ++format; - flags = PAD_RIGHT; - } - if (*format == '#') { - ++format; - flags |= PAD_ALTERNATE; - } - while (*format == '0') { - ++format; - flags |= PAD_ZERO; + flags_done = false; + while (!flags_done) { + switch (*format) { + case '-': + flags |= PAD_RIGHT; + break; + case '#': + flags |= PAD_ALTERNATE; + break; + case '0': + flags |= PAD_ZERO; + break; + default: + flags_done = true; + break; + } + if (!flags_done) + ++format; } /* Get width */ for (; *format >= '0' && *format <= '9'; ++format) { From 35ef1826906b5abfa0fc0c969ad29662fa83106d Mon Sep 17 00:00:00 2001 From: Xiang W Date: Mon, 10 Jul 2023 00:02:22 +0800 Subject: [PATCH 166/187] lib: sbi: print not fill '0' when left-aligned Left alignment and padding '0' should not exist at the same time, this patch skips padding. Signed-off-by: Xiang W Reviewed-by: Anup Patel --- lib/sbi/sbi_console.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/lib/sbi/sbi_console.c b/lib/sbi/sbi_console.c index d87b5c20efc..03ee05a11cb 100644 --- a/lib/sbi/sbi_console.c +++ b/lib/sbi/sbi_console.c @@ -288,6 +288,8 @@ static int print(char **out, u32 *out_len, const char *format, va_list args) if (!flags_done) ++format; } + if (flags & PAD_RIGHT) + flags &= ~PAD_ZERO; /* Get width */ for (; *format >= '0' && *format <= '9'; ++format) { width *= 10; From 40dac06e3c3c4056bf47d295c6fd85856556d998 Mon Sep 17 00:00:00 2001 From: Xiang W Date: Mon, 10 Jul 2023 00:02:23 +0800 Subject: [PATCH 167/187] lib: sbi: Add '+' flags for print Adds + flags for print, prefixing positive numbers with + when this flags is present Signed-off-by: Xiang W Reviewed-by: Anup Patel --- lib/sbi/sbi_console.c | 25 ++++++++++++++++--------- 1 file changed, 16 insertions(+), 9 deletions(-) diff --git a/lib/sbi/sbi_console.c b/lib/sbi/sbi_console.c index 03ee05a11cb..20fe65a3030 100644 --- a/lib/sbi/sbi_console.c +++ b/lib/sbi/sbi_console.c @@ -120,6 +120,7 @@ unsigned long sbi_ngets(char *str, unsigned long len) #define PAD_RIGHT 1 #define PAD_ZERO 2 #define PAD_ALTERNATE 4 +#define PAD_SIGN 8 #define PRINT_BUF_LEN 64 #define va_start(v, l) __builtin_va_start((v), l) @@ -186,15 +187,18 @@ static int prints(char **out, u32 *out_len, const char *string, int width, static int printi(char **out, u32 *out_len, long long i, int b, int sg, int width, int flags, int letbase) { - char print_buf[PRINT_BUF_LEN]; - char *s; - int neg = 0, pc = 0; + char *s, sign = 0, print_buf[PRINT_BUF_LEN]; + int pc = 0; u64 t; unsigned long long u = i; - if (sg && b == 10 && i < 0) { - neg = 1; - u = -i; + if (sg && b == 10) { + if ((flags & PAD_SIGN) && i > 0) + sign = '+'; + if (i < 0) { + sign = '-'; + u = -i; + } } s = print_buf + PRINT_BUF_LEN - 1; @@ -221,13 +225,13 @@ static int printi(char **out, u32 *out_len, long long i, int b, int sg, *--s = '0'; } - if (neg) { + if (sign) { if (width && (flags & PAD_ZERO)) { - printc(out, out_len, '-'); + printc(out, out_len, sign); ++pc; --width; } else { - *--s = '-'; + *--s = sign; } } @@ -275,6 +279,9 @@ static int print(char **out, u32 *out_len, const char *format, va_list args) case '-': flags |= PAD_RIGHT; break; + case '+': + flags |= PAD_SIGN; + break; case '#': flags |= PAD_ALTERNATE; break; From 458fa742663f889033b87b6d866f68fbc1c22eb4 Mon Sep 17 00:00:00 2001 From: Xiang W Date: Mon, 10 Jul 2023 00:02:24 +0800 Subject: [PATCH 168/187] lib: sbi: Add ' ' '\'' flags for print The space flag is used to add a space before positive numbers, and apostrophe is used to print the thousand separator. Add code to ignore these two flags Signed-off-by: Xiang W Reviewed-by: Anup Patel --- lib/sbi/sbi_console.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/lib/sbi/sbi_console.c b/lib/sbi/sbi_console.c index 20fe65a3030..4229e7e3be3 100644 --- a/lib/sbi/sbi_console.c +++ b/lib/sbi/sbi_console.c @@ -288,6 +288,10 @@ static int print(char **out, u32 *out_len, const char *format, va_list args) case '0': flags |= PAD_ZERO; break; + case ' ': + case '\'': + /* Ignored flags, do nothing */ + break; default: flags_done = true; break; From 05cbb6e908a469f152d0253cfdf7c1aa2bda820d Mon Sep 17 00:00:00 2001 From: Xiang W Date: Mon, 10 Jul 2023 00:02:25 +0800 Subject: [PATCH 169/187] lib: sbi: implifying the parameters of printi The information of sg/b/letbase can be obtained by the type character, simplifying the parameter by passing the type directly. Signed-off-by: Xiang W Reviewed-by: Anup Patel --- lib/sbi/sbi_console.c | 127 +++++++++++++++++------------------------- 1 file changed, 50 insertions(+), 77 deletions(-) diff --git a/lib/sbi/sbi_console.c b/lib/sbi/sbi_console.c index 4229e7e3be3..51380cffc7d 100644 --- a/lib/sbi/sbi_console.c +++ b/lib/sbi/sbi_console.c @@ -184,15 +184,26 @@ static int prints(char **out, u32 *out_len, const char *string, int width, return pc; } -static int printi(char **out, u32 *out_len, long long i, int b, int sg, - int width, int flags, int letbase) +static int printi(char **out, u32 *out_len, long long i, + int width, int flags, int type) { - char *s, sign = 0, print_buf[PRINT_BUF_LEN]; int pc = 0; - u64 t; - unsigned long long u = i; + char *s, sign = 0, letbase, print_buf[PRINT_BUF_LEN]; + unsigned long long u, b, t; + + b = 10; + letbase = 'a'; + if (type == 'o') + b = 8; + else if (type == 'x' || type == 'X' || type == 'p' || type == 'P') { + b = 16; + letbase &= ~0x20; + letbase |= type & 0x20; + } - if (sg && b == 10) { + u = i; + sign = 0; + if (type == 'i' || type == 'd') { if ((flags & PAD_SIGN) && i > 0) sign = '+'; if (i < 0) { @@ -242,9 +253,8 @@ static int print(char **out, u32 *out_len, const char *format, va_list args) { bool flags_done; int width, flags, pc = 0; - char scr[2], *tout; + char type, scr[2], *tout; bool use_tbuf = (!out) ? true : false; - unsigned long long tmp; /* * The console_tbuf is protected by console_out_lock and @@ -314,83 +324,46 @@ static int print(char **out, u32 *out_len, const char *format, va_list args) } if ((*format == 'd') || (*format == 'i')) { pc += printi(out, out_len, va_arg(args, int), - 10, 1, width, flags, '0'); - continue; - } - if (*format == 'x') { - pc += printi(out, out_len, - va_arg(args, unsigned int), 16, 0, - width, flags, 'a'); + width, flags, *format); continue; } - if (*format == 'X') { - pc += printi(out, out_len, - va_arg(args, unsigned int), 16, 0, - width, flags, 'A'); + if ((*format == 'u') || (*format == 'x') || (*format == 'X')) { + pc += printi(out, out_len, va_arg(args, unsigned int), + width, flags, *format); continue; } - if (*format == 'u') { - pc += printi(out, out_len, - va_arg(args, unsigned int), 10, 0, - width, flags, 'a'); + if ((*format == 'p') || (*format == 'P')) { + pc += printi(out, out_len, (uintptr_t)va_arg(args, void*), + width, flags, *format); continue; } - if (*format == 'p') { - pc += printi(out, out_len, - va_arg(args, unsigned long), 16, 0, - width, flags, 'a'); - continue; - } - if (*format == 'P') { - pc += printi(out, out_len, - va_arg(args, unsigned long), 16, 0, - width, flags, 'A'); - continue; - } - if (*format == 'l' && *(format + 1) == 'l') { - tmp = va_arg(args, unsigned long long); - if (*(format + 2) == 'u') { - format += 2; - pc += printi(out, out_len, tmp, 10, 0, - width, flags, 'a'); - } else if (*(format + 2) == 'x') { - format += 2; - pc += printi(out, out_len, tmp, 16, 0, - width, flags, 'a'); - } else if (*(format + 2) == 'X') { - format += 2; - pc += printi(out, out_len, tmp, 16, 0, - width, flags, 'A'); - } else { - format += 1; - pc += printi(out, out_len, tmp, 10, 1, - width, flags, '0'); + if (*format == 'l') { + type = 'i'; + if (format[1] == 'l') { + ++format; + if ((format[1] == 'u') + || (format[1] == 'd') || (format[1] == 'i') + || (format[1] == 'x') || (format[1] == 'X')) { + ++format; + type = *format; + } + pc += printi(out, out_len, va_arg(args, long long), + width, flags, type); + continue; } - continue; - } else if (*format == 'l') { - if (*(format + 1) == 'u') { - format += 1; - pc += printi( - out, out_len, - va_arg(args, unsigned long), 10, - 0, width, flags, 'a'); - } else if (*(format + 1) == 'x') { - format += 1; - pc += printi( - out, out_len, - va_arg(args, unsigned long), 16, - 0, width, flags, 'a'); - } else if (*(format + 1) == 'X') { - format += 1; - pc += printi( - out, out_len, - va_arg(args, unsigned long), 16, - 0, width, flags, 'A'); - } else { - pc += printi(out, out_len, - va_arg(args, long), 10, 1, - width, flags, '0'); + if ((format[1] == 'u') + || (format[1] == 'd') || (format[1] == 'i') + || (format[1] == 'x') || (format[1] == 'X')) { + ++format; + type = *format; } + if ((type == 'd') || (type == 'i')) + pc += printi(out, out_len, va_arg(args, long), + width, flags, type); + else + pc += printi(out, out_len, va_arg(args, unsigned long), + width, flags, type); + continue; } if (*format == 'c') { /* char are converted to int then pushed on the stack */ From fe0828142fa34a95b6933dd94e68ed528d4c5778 Mon Sep 17 00:00:00 2001 From: Xiang W Date: Mon, 10 Jul 2023 00:02:26 +0800 Subject: [PATCH 170/187] lib: sbi: print add 'o' type Add o type for print to print octal numbers Signed-off-by: Xiang W Reviewed-by: Anup Patel --- lib/sbi/sbi_console.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/lib/sbi/sbi_console.c b/lib/sbi/sbi_console.c index 51380cffc7d..10b27c621c4 100644 --- a/lib/sbi/sbi_console.c +++ b/lib/sbi/sbi_console.c @@ -327,7 +327,8 @@ static int print(char **out, u32 *out_len, const char *format, va_list args) width, flags, *format); continue; } - if ((*format == 'u') || (*format == 'x') || (*format == 'X')) { + if ((*format == 'u') || (*format == 'o') + || (*format == 'x') || (*format == 'X')) { pc += printi(out, out_len, va_arg(args, unsigned int), width, flags, *format); continue; @@ -341,7 +342,7 @@ static int print(char **out, u32 *out_len, const char *format, va_list args) type = 'i'; if (format[1] == 'l') { ++format; - if ((format[1] == 'u') + if ((format[1] == 'u') || (format[1] == 'o') || (format[1] == 'd') || (format[1] == 'i') || (format[1] == 'x') || (format[1] == 'X')) { ++format; @@ -351,7 +352,7 @@ static int print(char **out, u32 *out_len, const char *format, va_list args) width, flags, type); continue; } - if ((format[1] == 'u') + if ((format[1] == 'u') || (format[1] == 'o') || (format[1] == 'd') || (format[1] == 'i') || (format[1] == 'x') || (format[1] == 'X')) { ++format; From c6ee5ae5a485335fa28a5f74811f900d8da9f87d Mon Sep 17 00:00:00 2001 From: Xiang W Date: Mon, 10 Jul 2023 00:02:27 +0800 Subject: [PATCH 171/187] lib: sbi: Fix printi Fix two bug: > printf("%#08x", 0x123); /* print 0000x123 */ > printf("%#x", 0); /* print 0x0 */ Signed-off-by: Xiang W Reviewed-by: Anup Patel --- lib/sbi/sbi_console.c | 36 +++++++++++++++++++++++------------- 1 file changed, 23 insertions(+), 13 deletions(-) diff --git a/lib/sbi/sbi_console.c b/lib/sbi/sbi_console.c index 10b27c621c4..9e9f273f54d 100644 --- a/lib/sbi/sbi_console.c +++ b/lib/sbi/sbi_console.c @@ -227,23 +227,33 @@ static int printi(char **out, u32 *out_len, long long i, } } - if (flags & PAD_ALTERNATE) { - if ((b == 16) && (letbase == 'A')) { - *--s = 'X'; - } else if ((b == 16) && (letbase == 'a')) { - *--s = 'x'; - } - *--s = '0'; - } - - if (sign) { - if (width && (flags & PAD_ZERO)) { + if (flags & PAD_ZERO) { + if (sign) { printc(out, out_len, sign); ++pc; --width; - } else { - *--s = sign; } + if (i && (flags & PAD_ALTERNATE)) { + if (b == 16 || b == 8) { + printc(out, out_len, '0'); + ++pc; + --width; + } + if (b == 16) { + printc(out, out_len, 'x' - 'a' + letbase); + ++pc; + --width; + } + } + } else { + if (i && (flags & PAD_ALTERNATE)) { + if (b == 16) + *--s = 'x' - 'a' + letbase; + if (b == 16 || b == 8) + *--s = '0'; + } + if (sign) + *--s = sign; } return pc + prints(out, out_len, s, width, flags); From 3b6fcddcebf82bb58ac750a2ab4d6e22d7549ac9 Mon Sep 17 00:00:00 2001 From: Xiang W Date: Mon, 10 Jul 2023 00:02:28 +0800 Subject: [PATCH 172/187] lib: sbi: Simplify prints When doing width = width - strlen(string) in prints there is no need to consider the case that witdh may be less than 0. This is because the code to do filling needs to be executed under the condition that width > 0. Signed-off-by: Xiang W Reviewed-by: Anup Patel --- lib/sbi/sbi_console.c | 21 ++++----------------- 1 file changed, 4 insertions(+), 17 deletions(-) diff --git a/lib/sbi/sbi_console.c b/lib/sbi/sbi_console.c index 9e9f273f54d..adbe2e6b5db 100644 --- a/lib/sbi/sbi_console.c +++ b/lib/sbi/sbi_console.c @@ -151,24 +151,11 @@ static void printc(char **out, u32 *out_len, char ch) static int prints(char **out, u32 *out_len, const char *string, int width, int flags) { - int pc = 0; - char padchar = ' '; - - if (width > 0) { - int len = 0; - const char *ptr; - for (ptr = string; *ptr; ++ptr) - ++len; - if (len >= width) - width = 0; - else - width -= len; - if (flags & PAD_ZERO) - padchar = '0'; - } + int pc = 0; + width -= sbi_strlen(string); if (!(flags & PAD_RIGHT)) { for (; width > 0; --width) { - printc(out, out_len, padchar); + printc(out, out_len, flags & PAD_ZERO ? '0' : ' '); ++pc; } } @@ -177,7 +164,7 @@ static int prints(char **out, u32 *out_len, const char *string, int width, ++pc; } for (; width > 0; --width) { - printc(out, out_len, padchar); + printc(out, out_len, ' '); ++pc; } From cc89fa7b5481b3279f1628f71debf795d5618044 Mon Sep 17 00:00:00 2001 From: Xiang W Date: Mon, 10 Jul 2023 00:02:29 +0800 Subject: [PATCH 173/187] lib: sbi: Fix printc Because *out needs to reserve a byte to hold '\0', no more characters should be added to the buffer when *out has one byte left, and the buffer size *out_len should not be modified. this patch prevents the correction of *out_len when *out_len is 1. Signed-off-by: Xiang W Reviewed-by: Anup Patel --- lib/sbi/sbi_console.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/lib/sbi/sbi_console.c b/lib/sbi/sbi_console.c index adbe2e6b5db..6915148b175 100644 --- a/lib/sbi/sbi_console.c +++ b/lib/sbi/sbi_console.c @@ -142,10 +142,9 @@ static void printc(char **out, u32 *out_len, char ch) if (!out_len || *out_len > 1) { *(*out)++ = ch; **out = '\0'; + if (out_len) + --(*out_len); } - - if (out_len && *out_len > 0) - --(*out_len); } static int prints(char **out, u32 *out_len, const char *string, int width, From ff43168137a4890fe65460c1506fdf08c26bebad Mon Sep 17 00:00:00 2001 From: Xiang W Date: Mon, 10 Jul 2023 00:02:30 +0800 Subject: [PATCH 174/187] lib: sbi: Fix timing of clearing tbuf A single scan of the format char may add multiple characters to the tbuf, causing a buffer overflow. You should check if tbuf is full in printc so that it does not cause a buffer overflow. Signed-off-by: Xiang W Reviewed-by: Anup Patel --- lib/sbi/sbi_console.c | 35 +++++++++++++++++++---------------- 1 file changed, 19 insertions(+), 16 deletions(-) diff --git a/lib/sbi/sbi_console.c b/lib/sbi/sbi_console.c index 6915148b175..07a90452141 100644 --- a/lib/sbi/sbi_console.c +++ b/lib/sbi/sbi_console.c @@ -121,6 +121,7 @@ unsigned long sbi_ngets(char *str, unsigned long len) #define PAD_ZERO 2 #define PAD_ALTERNATE 4 #define PAD_SIGN 8 +#define USE_TBUF 16 #define PRINT_BUF_LEN 64 #define va_start(v, l) __builtin_va_start((v), l) @@ -128,7 +129,7 @@ unsigned long sbi_ngets(char *str, unsigned long len) #define va_arg __builtin_va_arg typedef __builtin_va_list va_list; -static void printc(char **out, u32 *out_len, char ch) +static void printc(char **out, u32 *out_len, char ch, int flags) { if (!out) { sbi_putc(ch); @@ -142,8 +143,14 @@ static void printc(char **out, u32 *out_len, char ch) if (!out_len || *out_len > 1) { *(*out)++ = ch; **out = '\0'; - if (out_len) + if (out_len) { --(*out_len); + if ((flags & USE_TBUF) && *out_len == 1) { + nputs_all(console_tbuf, CONSOLE_TBUF_MAX - *out_len); + *out = console_tbuf; + *out_len = CONSOLE_TBUF_MAX; + } + } } } @@ -154,16 +161,16 @@ static int prints(char **out, u32 *out_len, const char *string, int width, width -= sbi_strlen(string); if (!(flags & PAD_RIGHT)) { for (; width > 0; --width) { - printc(out, out_len, flags & PAD_ZERO ? '0' : ' '); + printc(out, out_len, flags & PAD_ZERO ? '0' : ' ', flags); ++pc; } } for (; *string; ++string) { - printc(out, out_len, *string); + printc(out, out_len, *string, flags); ++pc; } for (; width > 0; --width) { - printc(out, out_len, ' '); + printc(out, out_len, ' ', flags); ++pc; } @@ -215,18 +222,18 @@ static int printi(char **out, u32 *out_len, long long i, if (flags & PAD_ZERO) { if (sign) { - printc(out, out_len, sign); + printc(out, out_len, sign, flags); ++pc; --width; } if (i && (flags & PAD_ALTERNATE)) { if (b == 16 || b == 8) { - printc(out, out_len, '0'); + printc(out, out_len, '0', flags); ++pc; --width; } if (b == 16) { - printc(out, out_len, 'x' - 'a' + letbase); + printc(out, out_len, 'x' - 'a' + letbase, flags); ++pc; --width; } @@ -265,15 +272,11 @@ static int print(char **out, u32 *out_len, const char *format, va_list args) } for (; *format != 0; ++format) { - if (use_tbuf && !console_tbuf_len) { - nputs_all(console_tbuf, CONSOLE_TBUF_MAX); - console_tbuf_len = CONSOLE_TBUF_MAX; - tout = console_tbuf; - } - + width = flags = 0; + if (use_tbuf) + flags |= USE_TBUF; if (*format == '%') { ++format; - width = flags = 0; if (*format == '\0') break; if (*format == '%') @@ -371,7 +374,7 @@ static int print(char **out, u32 *out_len, const char *format, va_list args) } } else { literal: - printc(out, out_len, *format); + printc(out, out_len, *format, flags); ++pc; } } From a73982d7376a71cf6e230b255069da46fe2becc9 Mon Sep 17 00:00:00 2001 From: Xiang W Date: Mon, 10 Jul 2023 00:03:26 +0800 Subject: [PATCH 175/187] lib: sbi: Fix missing '\0' when buffer szie equal 1 Fix special case: sbi_snprintf(out, out_len, ...) when out_len equal 1, The previous code will not fill the buffer with any char. Signed-off-by: Xiang W Reviewed-by: Anup Patel --- lib/sbi/sbi_console.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/lib/sbi/sbi_console.c b/lib/sbi/sbi_console.c index 07a90452141..2b3b0a3fe80 100644 --- a/lib/sbi/sbi_console.c +++ b/lib/sbi/sbi_console.c @@ -271,6 +271,12 @@ static int print(char **out, u32 *out_len, const char *format, va_list args) out_len = &console_tbuf_len; } + /* handle special case: *out_len == 1*/ + if (out) { + if(!out_len || *out_len) + **out = '\0'; + } + for (; *format != 0; ++format) { width = flags = 0; if (use_tbuf) From ea6533ada828cf71b9359f566be0f9c640022543 Mon Sep 17 00:00:00 2001 From: Anup Patel Date: Tue, 11 Jul 2023 09:00:31 +0530 Subject: [PATCH 176/187] lib: utils/gpio: Fix RV32 compile error for designware GPIO driver Currently, we see following compile error in the designeware GPIO driver for RV32 systems: lib/utils/gpio/fdt_gpio_designware.c:115:20: error: cast to pointer from integer of different size [-Werror=int-to-pointer-cast] 115 | chip->dr = (void *)addr + (bank * 0xc); | ^ lib/utils/gpio/fdt_gpio_designware.c:116:21: error: cast to pointer from integer of different size [-Werror=int-to-pointer-cast] 116 | chip->ext = (void *)addr + (bank * 4) + 0x50; We fix the above error using an explicit type-cast to 'unsigned long'. Fixes: 7828eebaaa77 ("gpio/desginware: add Synopsys DesignWare APB GPIO support") Signed-off-by: Anup Patel Reviewed-by: Xiang W --- lib/utils/gpio/fdt_gpio_designware.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/utils/gpio/fdt_gpio_designware.c b/lib/utils/gpio/fdt_gpio_designware.c index 6223d7e7c41..018e2d54035 100644 --- a/lib/utils/gpio/fdt_gpio_designware.c +++ b/lib/utils/gpio/fdt_gpio_designware.c @@ -112,8 +112,8 @@ static int dw_gpio_init_bank(void *fdt, int nodeoff, u32 phandle, chip = &dw_gpio_chip_array[dw_gpio_chip_count]; - chip->dr = (void *)addr + (bank * 0xc); - chip->ext = (void *)addr + (bank * 4) + 0x50; + chip->dr = (void *)(uintptr_t)addr + (bank * 0xc); + chip->ext = (void *)(uintptr_t)addr + (bank * 4) + 0x50; chip->chip.driver = &fdt_gpio_designware; chip->chip.id = phandle; chip->chip.ngpio = nr_pins; From c3b98c610b63ebb75b023135e392b4f48080f380 Mon Sep 17 00:00:00 2001 From: Himanshu Chauhan Date: Wed, 12 Jul 2023 10:04:27 +0530 Subject: [PATCH 177/187] include: sbi: Add macro definitions for mseccfg CSR - Add macros for Machine Security Configuration (mseccfg) CSR - Add macros to access/manipulate bits in msecfg CSR Signed-off-by: Himanshu Chauhan Reviewed-by: Anup Patel --- include/sbi/riscv_encoding.h | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/include/sbi/riscv_encoding.h b/include/sbi/riscv_encoding.h index 4ebed97ab0a..50071ad3e12 100644 --- a/include/sbi/riscv_encoding.h +++ b/include/sbi/riscv_encoding.h @@ -663,6 +663,18 @@ #define CSR_MHPMEVENT30H 0x73e #define CSR_MHPMEVENT31H 0x73f +/* Machine Security Configuration CSR (mseccfg) */ +#define CSR_MSECCFG_LOWER 0x747 +#define CSR_MSECCFG_UPPER 0x757 +#define CSR_MSECCFG (CSR_MSECCFG_LOWER) + +#define MSECCFG_MML_SHIFT (0) +#define MSECCFG_MML (_UL(1) << MSECCFG_MML_SHIFT) +#define MSECCFG_MMWP_SHIFT (1) +#define MSECCFG_MMWP (_UL(1) << MSECCFG_MMWP_SHIFT) +#define MSECCFG_RLB_SHIFT (2) +#define MSECCFG_RLB (_UL(1) << MSECCFG_RLB_SHIFT) + /* Counter Overflow CSR */ #define CSR_SCOUNTOVF 0xda0 From 1c099c4f36528e00388a77309a4887640888e35a Mon Sep 17 00:00:00 2001 From: Himanshu Chauhan Date: Wed, 12 Jul 2023 10:04:28 +0530 Subject: [PATCH 178/187] lib: sbi: Add functions to manipulate PMP entries - Add a function to disable a given PMP entry. - Add a function to check if a given entry is disabled. Signed-off-by: Himanshu Chauhan Reviewed-by: Anup Patel --- include/sbi/riscv_asm.h | 6 ++++++ lib/sbi/riscv_asm.c | 42 +++++++++++++++++++++++++++++++++++++++++ 2 files changed, 48 insertions(+) diff --git a/include/sbi/riscv_asm.h b/include/sbi/riscv_asm.h index 1ff36de76e3..2c34635a393 100644 --- a/include/sbi/riscv_asm.h +++ b/include/sbi/riscv_asm.h @@ -181,6 +181,12 @@ int misa_xlen(void); /* Get RISC-V ISA string representation */ void misa_string(int xlen, char *out, unsigned int out_sz); +/* Disable pmp entry at a given index */ +int pmp_disable(unsigned int n); + +/* Check if the matching field is set */ +int is_pmp_entry_mapped(unsigned long entry); + int pmp_set(unsigned int n, unsigned long prot, unsigned long addr, unsigned long log2len); diff --git a/lib/sbi/riscv_asm.c b/lib/sbi/riscv_asm.c index cd565534ca1..881dea3e54a 100644 --- a/lib/sbi/riscv_asm.c +++ b/lib/sbi/riscv_asm.c @@ -246,6 +246,48 @@ static unsigned long ctz(unsigned long x) return ret; } +int pmp_disable(unsigned int n) +{ + int pmpcfg_csr, pmpcfg_shift; + unsigned long cfgmask, pmpcfg; + + if (n >= PMP_COUNT) + return SBI_EINVAL; + +#if __riscv_xlen == 32 + pmpcfg_csr = CSR_PMPCFG0 + (n >> 2); + pmpcfg_shift = (n & 3) << 3; +#elif __riscv_xlen == 64 + pmpcfg_csr = (CSR_PMPCFG0 + (n >> 2)) & ~1; + pmpcfg_shift = (n & 7) << 3; +#else +# error "Unexpected __riscv_xlen" +#endif + + /* Clear the address matching bits to disable the pmp entry */ + cfgmask = ~(0xffUL << pmpcfg_shift); + pmpcfg = (csr_read_num(pmpcfg_csr) & cfgmask); + + csr_write_num(pmpcfg_csr, pmpcfg); + + return SBI_OK; +} + +int is_pmp_entry_mapped(unsigned long entry) +{ + unsigned long prot; + unsigned long addr; + unsigned long log2len; + + pmp_get(entry, &prot, &addr, &log2len); + + /* If address matching bits are non-zero, the entry is enable */ + if (prot & PMP_A) + return true; + + return false; +} + int pmp_set(unsigned int n, unsigned long prot, unsigned long addr, unsigned long log2len) { From 6c202c5efda59d9bbc00b52f3664ebdc2e442f9a Mon Sep 17 00:00:00 2001 From: Himanshu Chauhan Date: Wed, 12 Jul 2023 10:04:29 +0530 Subject: [PATCH 179/187] include: sbi: Add Smepmp specific access flags for PMP entries Smepmp specification defines a truth table based on which the access is allowed to different modes. This patch adds different flags based on this truth table. Signed-off-by: Himanshu Chauhan Reviewed-by: Anup Patel --- include/sbi/sbi_domain.h | 84 +++++++++++++++++++++++++++++++++++++--- 1 file changed, 78 insertions(+), 6 deletions(-) diff --git a/include/sbi/sbi_domain.h b/include/sbi/sbi_domain.h index b05bcf4d1c9..da2a65a4d44 100644 --- a/include/sbi/sbi_domain.h +++ b/include/sbi/sbi_domain.h @@ -43,6 +43,84 @@ struct sbi_domain_memregion { #define SBI_DOMAIN_MEMREGION_SU_WRITABLE (1UL << 4) #define SBI_DOMAIN_MEMREGION_SU_EXECUTABLE (1UL << 5) +#define SBI_DOMAIN_MEMREGION_ACCESS_MASK (0x3fUL) +#define SBI_DOMAIN_MEMREGION_M_ACCESS_MASK (0x7UL) +#define SBI_DOMAIN_MEMREGION_SU_ACCESS_MASK (0x38UL) + +#define SBI_DOMAIN_MEMREGION_SU_ACCESS_SHIFT (3) + +#define SBI_DOMAIN_MEMREGION_SHARED_RDONLY \ + (SBI_DOMAIN_MEMREGION_M_READABLE | \ + SBI_DOMAIN_MEMREGION_SU_READABLE) + +#define SBI_DOMAIN_MEMREGION_SHARED_SUX_MRX \ + (SBI_DOMAIN_MEMREGION_M_READABLE | \ + SBI_DOMAIN_MEMREGION_M_EXECUTABLE | \ + SBI_DOMAIN_MEMREGION_SU_EXECUTABLE) + +#define SBI_DOMAIN_MEMREGION_SHARED_SUX_MX \ + (SBI_DOMAIN_MEMREGION_M_EXECUTABLE | \ + SBI_DOMAIN_MEMREGION_SU_EXECUTABLE) + +#define SBI_DOMAIN_MEMREGION_SHARED_SURW_MRW \ + (SBI_DOMAIN_MEMREGION_M_READABLE | \ + SBI_DOMAIN_MEMREGION_M_WRITABLE | \ + SBI_DOMAIN_MEMREGION_SU_READABLE| \ + SBI_DOMAIN_MEMREGION_SU_WRITABLE) + +#define SBI_DOMAIN_MEMREGION_SHARED_SUR_MRW \ + (SBI_DOMAIN_MEMREGION_M_READABLE | \ + SBI_DOMAIN_MEMREGION_M_WRITABLE | \ + SBI_DOMAIN_MEMREGION_SU_READABLE) + + /* Shared read-only region between M and SU mode */ +#define SBI_DOMAIN_MEMREGION_IS_SUR_MR(__flags) \ + ((__flags & SBI_DOMAIN_MEMREGION_M_READABLE) && \ + (__flags & SBI_DOMAIN_MEMREGION_SU_READABLE)) + + /* Shared region: SU execute-only and M read/execute */ +#define SBI_DOMAIN_MEMREGION_IS_SUX_MRX(__flags) \ + ((__flags & SBI_DOMAIN_MEMREGION_M_READABLE) && \ + (__flags & SBI_DOMAIN_MEMREGION_M_EXECUTABLE) && \ + (__flags & SBI_DOMAIN_MEMREGION_SU_EXECUTABLE)) + + /* Shared region: SU and M execute-only */ +#define SBI_DOMAIN_MEMREGION_IS_SUX_MX(__flags) \ + ((__flags & SBI_DOMAIN_MEMREGION_M_EXECUTABLE) && \ + (__flags & SBI_DOMAIN_MEMREGION_SU_EXECUTABLE)) + + /* Shared region: SU and M read/write */ +#define SBI_DOMAIN_MEMREGION_IS_SURW_MRW(__flags) \ + ((__flags & SBI_DOMAIN_MEMREGION_M_READABLE) && \ + (__flags & SBI_DOMAIN_MEMREGION_M_WRITABLE) && \ + (__flags & SBI_DOMAIN_MEMREGION_SU_READABLE) & \ + (__flags & SBI_DOMAIN_MEMREGION_SU_WRITABLE)) + + /* Shared region: SU read-only and M read/write */ +#define SBI_DOMAIN_MEMREGION_IS_SUR_MRW(__flags) \ + ((__flags & SBI_DOMAIN_MEMREGION_M_READABLE) && \ + (__flags & SBI_DOMAIN_MEMREGION_M_WRITABLE) && \ + (__flags & SBI_DOMAIN_MEMREGION_SU_READABLE)) + + /* + * Check if region flags match with any of the above + * mentioned shared region type + */ +#define SBI_DOMAIN_MEMREGION_IS_SHARED(_flags) \ + (SBI_DOMAIN_MEMREGION_IS_SUR_MR(_flags) || \ + SBI_DOMAIN_MEMREGION_IS_SUX_MRX(_flags) || \ + SBI_DOMAIN_MEMREGION_IS_SUX_MX(_flags) || \ + SBI_DOMAIN_MEMREGION_IS_SURW_MRW(_flags)|| \ + SBI_DOMAIN_MEMREGION_IS_SUR_MRW(_flags)) + +#define SBI_DOMAIN_MEMREGION_M_ONLY_ACCESS(__flags) \ + ((__flags & SBI_DOMAIN_MEMREGION_M_ACCESS_MASK) && \ + !(__flags & SBI_DOMAIN_MEMREGION_SU_ACCESS_MASK)) + +#define SBI_DOMAIN_MEMREGION_SU_ONLY_ACCESS(__flags) \ + ((__flags & SBI_DOMAIN_MEMREGION_SU_ACCESS_MASK) && \ + !(__flags & SBI_DOMAIN_MEMREGION_M_ACCESS_MASK)) + /** Bit to control if permissions are enforced on all modes */ #define SBI_DOMAIN_MEMREGION_ENF_PERMISSIONS (1UL << 6) @@ -78,12 +156,6 @@ struct sbi_domain_memregion { (SBI_DOMAIN_MEMREGION_SU_EXECUTABLE | \ SBI_DOMAIN_MEMREGION_M_EXECUTABLE) -#define SBI_DOMAIN_MEMREGION_ACCESS_MASK (0x3fUL) -#define SBI_DOMAIN_MEMREGION_M_ACCESS_MASK (0x7UL) -#define SBI_DOMAIN_MEMREGION_SU_ACCESS_MASK (0x38UL) - -#define SBI_DOMAIN_MEMREGION_SU_ACCESS_SHIFT (3) - #define SBI_DOMAIN_MEMREGION_MMIO (1UL << 31) unsigned long flags; }; From cbcfc7b10c3a99349f184647c73448b0cb8482df Mon Sep 17 00:00:00 2001 From: Himanshu Chauhan Date: Wed, 12 Jul 2023 10:04:30 +0530 Subject: [PATCH 180/187] lib: sbi: Add smepmp in hart extensions - Add Smepmp as extension in sbi_hart_extensions enum - Return "smepmp" string for Smepmp extension from sbi_hart_extension_id2string Signed-off-by: Himanshu Chauhan Reviewed-by: Anup Patel --- include/sbi/sbi_hart.h | 2 ++ lib/sbi/sbi_hart.c | 3 +++ 2 files changed, 5 insertions(+) diff --git a/include/sbi/sbi_hart.h b/include/sbi/sbi_hart.h index b97f78cd11e..8b0e896894e 100644 --- a/include/sbi/sbi_hart.h +++ b/include/sbi/sbi_hart.h @@ -28,6 +28,8 @@ enum sbi_hart_priv_versions { enum sbi_hart_extensions { /** HART has AIA M-mode CSRs */ SBI_HART_EXT_SMAIA = 0, + /** HART has Smepmp */ + SBI_HART_EXT_SMEPMP, /** HART has Smstateen CSR **/ SBI_HART_EXT_SMSTATEEN, /** Hart has Sscofpmt extension */ diff --git a/lib/sbi/sbi_hart.c b/lib/sbi/sbi_hart.c index 0c27fd7ba01..4dfa1704210 100644 --- a/lib/sbi/sbi_hart.c +++ b/lib/sbi/sbi_hart.c @@ -456,6 +456,9 @@ static inline char *sbi_hart_extension_id2string(int ext) case SBI_HART_EXT_ZIHPM: estr = "zihpm"; break; + case SBI_HART_EXT_SMEPMP: + estr = "smepmp"; + break; default: break; } From d72f5f17478dfef3df817339a0f02cfdb77a1dc1 Mon Sep 17 00:00:00 2001 From: Himanshu Chauhan Date: Wed, 12 Jul 2023 10:04:31 +0530 Subject: [PATCH 181/187] lib: utils: Add detection of Smepmp from ISA string in FDT - Add function to parse ISA string in FDT. - Set Smepmp feature bit in extensions if "smepmp" string is found in ISA string. Signed-off-by: Himanshu Chauhan Reviewed-by: Anup Patel --- include/sbi_utils/fdt/fdt_helper.h | 3 + lib/utils/fdt/fdt_helper.c | 111 +++++++++++++++++++++++++++++ platform/generic/platform.c | 9 +++ 3 files changed, 123 insertions(+) diff --git a/include/sbi_utils/fdt/fdt_helper.h b/include/sbi_utils/fdt/fdt_helper.h index 39d7f3a01d8..5c928ffd72c 100644 --- a/include/sbi_utils/fdt/fdt_helper.h +++ b/include/sbi_utils/fdt/fdt_helper.h @@ -56,6 +56,9 @@ int fdt_parse_max_enabled_hart_id(void *fdt, u32 *max_hartid); int fdt_parse_timebase_frequency(void *fdt, unsigned long *freq); +int fdt_parse_isa_extensions(void *fdt, unsigned int hard_id, + unsigned long *extensions); + int fdt_parse_gaisler_uart_node(void *fdt, int nodeoffset, struct platform_uart_data *uart); diff --git a/lib/utils/fdt/fdt_helper.c b/lib/utils/fdt/fdt_helper.c index a88a4ba83fa..61a41003ae6 100644 --- a/lib/utils/fdt/fdt_helper.c +++ b/lib/utils/fdt/fdt_helper.c @@ -12,6 +12,7 @@ #include #include #include +#include #include #include #include @@ -313,6 +314,116 @@ int fdt_parse_timebase_frequency(void *fdt, unsigned long *freq) return 0; } +static int fdt_get_isa_string(void *fdt, unsigned int hartid, + const char **isa_string) +{ + int err, cpu_offset, cpus_offset, len; + u32 c_hartid; + const fdt32_t *val; + + if (!fdt) + return SBI_EINVAL; + + cpus_offset = fdt_path_offset(fdt, "/cpus"); + if (cpus_offset < 0) + return cpus_offset; + + fdt_for_each_subnode(cpu_offset, fdt, cpus_offset) { + err = fdt_parse_hart_id(fdt, cpu_offset, &c_hartid); + if (err) + continue; + + if (!fdt_node_is_enabled(fdt, cpu_offset)) + continue; + + if (c_hartid == hartid) { + val = fdt_getprop(fdt, cpu_offset, "riscv,isa", &len); + if (val && len > 0) { + *isa_string = (const char *)val; + return 0; + } + } + } + + return SBI_EINVAL; +} + +#define RISCV_ISA_EXT_NAME_LEN_MAX 32 + +int fdt_parse_isa_extensions(void *fdt, unsigned int hartid, + unsigned long *extensions) +{ + size_t i, j, isa_len; + char mstr[RISCV_ISA_EXT_NAME_LEN_MAX]; + const char *isa = NULL; + + if (fdt_get_isa_string(fdt, hartid, &isa)) + return SBI_EINVAL; + + if (!isa) + return SBI_EINVAL; + + i = 0; + isa_len = strlen(isa); + + if (isa[i] == 'r' || isa[i] == 'R') + i++; + else + return SBI_EINVAL; + + if (isa[i] == 'v' || isa[i] == 'V') + i++; + else + return SBI_EINVAL; + + if (isa[i] == '3' || isa[i+1] == '2') + i += 2; + else if (isa[i] == '6' || isa[i+1] == '4') + i += 2; + else + return SBI_EINVAL; + + /* Skip base ISA extensions */ + for (; i < isa_len; i++) { + if (isa[i] == '_') + break; + } + + while (i < isa_len) { + if (isa[i] != '_') { + i++; + continue; + } + + /* Skip the '_' character */ + i++; + + /* Extract the multi-letter extension name */ + j = 0; + while ((i < isa_len) && (isa[i] != '_') && + (j < (sizeof(mstr) - 1))) + mstr[j++] = isa[i++]; + mstr[j] = '\0'; + + /* Skip empty multi-letter extension name */ + if (!j) + continue; + +#define SET_ISA_EXT_MAP(name, bit) \ + do { \ + if (!strcmp(mstr, name)) { \ + __set_bit(bit, extensions); \ + continue; \ + } \ + } while (false) \ + + SET_ISA_EXT_MAP("smepmp", SBI_HART_EXT_SMEPMP); +#undef SET_ISA_EXT_MAP + } + + return 0; +} + static int fdt_parse_uart_node_common(void *fdt, int nodeoffset, struct platform_uart_data *uart, unsigned long default_freq, diff --git a/platform/generic/platform.c b/platform/generic/platform.c index 86811e6b02c..34b87f74d37 100644 --- a/platform/generic/platform.c +++ b/platform/generic/platform.c @@ -211,6 +211,15 @@ static void generic_final_exit(void) static int generic_extensions_init(struct sbi_hart_features *hfeatures) { + int rc; + + /* Parse the ISA string from FDT and enable the listed extensions */ + rc = fdt_parse_isa_extensions(fdt_get_address(), current_hartid(), + &hfeatures->extensions); + + if (rc) + return rc; + if (generic_plat && generic_plat->extensions_init) return generic_plat->extensions_init(generic_plat_match, hfeatures); From 4a42a2347c757457f455d9293812a32a7552e4d5 Mon Sep 17 00:00:00 2001 From: Himanshu Chauhan Date: Wed, 12 Jul 2023 10:04:32 +0530 Subject: [PATCH 182/187] lib: sbi: Grant SU R/W/X permissions to whole memory Since pmp entries have implicit priority on index, previous entries will deny access to SU on M-mode region. Also, M-mode will not have access to SU region while previous entries will allow access to M-mode regions. Signed-off-by: Himanshu Chauhan Reviewed-by: Anup Patel --- lib/sbi/sbi_domain.c | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/lib/sbi/sbi_domain.c b/lib/sbi/sbi_domain.c index 38a5902ff47..acd0f74c301 100644 --- a/lib/sbi/sbi_domain.c +++ b/lib/sbi/sbi_domain.c @@ -772,11 +772,17 @@ int sbi_domain_init(struct sbi_scratch *scratch, u32 cold_hartid) root.fw_region_inited = true; - /* Root domain allow everything memory region */ + /* + * Allow SU RWX on rest of the memory region. Since pmp entries + * have implicit priority on index, previous entries will + * deny access to SU on M-mode region. Also, M-mode will not + * have access to SU region while previous entries will allow + * access to M-mode regions. + */ sbi_domain_memregion_init(0, ~0UL, - (SBI_DOMAIN_MEMREGION_READABLE | - SBI_DOMAIN_MEMREGION_WRITEABLE | - SBI_DOMAIN_MEMREGION_EXECUTABLE), + (SBI_DOMAIN_MEMREGION_SU_READABLE | + SBI_DOMAIN_MEMREGION_SU_WRITABLE | + SBI_DOMAIN_MEMREGION_SU_EXECUTABLE), &root_memregs[root_memregs_count++]); /* Root domain memory region end */ From f3fdd041acf5bfb9c261c1e8a909e9b0d78c03e8 Mon Sep 17 00:00:00 2001 From: Himanshu Chauhan Date: Wed, 12 Jul 2023 10:04:34 +0530 Subject: [PATCH 183/187] lib: sbi: Change the order of PMP initialization Configure PMP at last when all other initializations have been done. Because if SMEPMP is detected, M-mode access to the S/U space will be rescinded. Signed-off-by: Himanshu Chauhan Reviewed-by: Anup Patel --- lib/sbi/sbi_init.c | 26 +++++++++++++++++--------- 1 file changed, 17 insertions(+), 9 deletions(-) diff --git a/lib/sbi/sbi_init.c b/lib/sbi/sbi_init.c index 423e6d83650..35e66333501 100644 --- a/lib/sbi/sbi_init.c +++ b/lib/sbi/sbi_init.c @@ -356,13 +356,6 @@ static void __noreturn init_coldboot(struct sbi_scratch *scratch, u32 hartid) sbi_hart_hang(); } - rc = sbi_hart_pmp_configure(scratch); - if (rc) { - sbi_printf("%s: PMP configure failed (error %d)\n", - __func__, rc); - sbi_hart_hang(); - } - /* * Note: Platform final initialization should be after finalizing * domains so that it sees correct domain assignment and PMP @@ -392,6 +385,17 @@ static void __noreturn init_coldboot(struct sbi_scratch *scratch, u32 hartid) sbi_boot_print_hart(scratch, hartid); + /* + * Configure PMP at last because if SMEPMP is detected, + * M-mode access to the S/U space will be rescinded. + */ + rc = sbi_hart_pmp_configure(scratch); + if (rc) { + sbi_printf("%s: PMP configure failed (error %d)\n", + __func__, rc); + sbi_hart_hang(); + } + wake_coldboot_harts(scratch, hartid); count = sbi_scratch_offset_ptr(scratch, init_count_offset); @@ -445,11 +449,15 @@ static void __noreturn init_warm_startup(struct sbi_scratch *scratch, if (rc) sbi_hart_hang(); - rc = sbi_hart_pmp_configure(scratch); + rc = sbi_platform_final_init(plat, false); if (rc) sbi_hart_hang(); - rc = sbi_platform_final_init(plat, false); + /* + * Configure PMP at last because if SMEPMP is detected, + * M-mode access to the S/U space will be rescinded. + */ + rc = sbi_hart_pmp_configure(scratch); if (rc) sbi_hart_hang(); From 5dd8db5b10fc03aeded76407aecb731a8a9f1cfa Mon Sep 17 00:00:00 2001 From: Himanshu Chauhan Date: Wed, 12 Jul 2023 10:04:33 +0530 Subject: [PATCH 184/187] lib: sbi: Add support for Smepmp - If Smepmp is enabled, the access flags of an entry are determined based on truth table defined in Smepmp. - First PMP entry (index 0) is reserved. - Existing boot PMP entries start from index 1. - Since enabling Smepmp revokes the access privileges of the M-mode software on S/U-mode region, first PMP entry is used to map/unmap the shared memory between M and S/U-mode. This allows a temporary access window for the M-mode software to read/write to S/U-mode memory region. Signed-off-by: Himanshu Chauhan Reviewed-by: Anup Patel --- include/sbi/sbi_hart.h | 15 +++++ lib/sbi/sbi_hart.c | 134 +++++++++++++++++++++++++++++++++++------ 2 files changed, 130 insertions(+), 19 deletions(-) diff --git a/include/sbi/sbi_hart.h b/include/sbi/sbi_hart.h index 8b0e896894e..1b78343652d 100644 --- a/include/sbi/sbi_hart.h +++ b/include/sbi/sbi_hart.h @@ -45,6 +45,21 @@ enum sbi_hart_extensions { SBI_HART_EXT_MAX, }; +/* + * Smepmp enforces access boundaries between M-mode and + * S/U-mode. When it is enabled, the PMPs are programmed + * such that M-mode doesn't have access to S/U-mode memory. + * + * To give M-mode R/W access to the shared memory between M and + * S/U-mode, first entry is reserved. It is disabled at boot. + * When shared memory access is required, the physical address + * should be programmed into the first PMP entry with R/W + * permissions to the M-mode. Once the work is done, it should be + * unmapped. sbi_hart_map_saddr/sbi_hart_unmap_saddr function + * pair should be used to map/unmap the shared memory. + */ +#define SBI_SMEPMP_RESV_ENTRY 0 + struct sbi_hart_features { bool detected; int priv_version; diff --git a/lib/sbi/sbi_hart.c b/lib/sbi/sbi_hart.c index 4dfa1704210..12f9c7eadd1 100644 --- a/lib/sbi/sbi_hart.c +++ b/lib/sbi/sbi_hart.c @@ -284,11 +284,75 @@ unsigned int sbi_hart_mhpm_bits(struct sbi_scratch *scratch) return hfeatures->mhpm_bits; } +/* + * Returns Smepmp flags for a given domain and region based on permissions. + */ +unsigned int sbi_hart_get_smepmp_flags(struct sbi_scratch *scratch, + struct sbi_domain *dom, + struct sbi_domain_memregion *reg) +{ + unsigned int pmp_flags = 0; + + if (SBI_DOMAIN_MEMREGION_IS_SHARED(reg->flags)) { + /* Read only for both M and SU modes */ + if (SBI_DOMAIN_MEMREGION_IS_SUR_MR(reg->flags)) + pmp_flags = (PMP_R | PMP_W | PMP_X); + + /* Execute for SU but Read/Execute for M mode */ + else if (SBI_DOMAIN_MEMREGION_IS_SUX_MRX(reg->flags)) + /* locked region */ + pmp_flags = (PMP_L | PMP_W | PMP_X); + + /* Execute only for both M and SU modes */ + else if (SBI_DOMAIN_MEMREGION_IS_SUX_MX(reg->flags)) + pmp_flags = (PMP_L | PMP_W); + + /* Read/Write for both M and SU modes */ + else if (SBI_DOMAIN_MEMREGION_IS_SURW_MRW(reg->flags)) + pmp_flags = (PMP_W | PMP_X); + + /* Read only for SU mode but Read/Write for M mode */ + else if (SBI_DOMAIN_MEMREGION_IS_SUR_MRW(reg->flags)) + pmp_flags = (PMP_W); + } else if (SBI_DOMAIN_MEMREGION_M_ONLY_ACCESS(reg->flags)) { + /* + * When smepmp is supported and used, M region cannot have RWX + * permissions on any region. + */ + if ((reg->flags & SBI_DOMAIN_MEMREGION_M_ACCESS_MASK) + == SBI_DOMAIN_MEMREGION_M_RWX) { + sbi_printf("%s: M-mode only regions cannot have" + "RWX permissions\n", __func__); + return 0; + } + + /* M-mode only access regions are always locked */ + pmp_flags |= PMP_L; + + if (reg->flags & SBI_DOMAIN_MEMREGION_M_READABLE) + pmp_flags |= PMP_R; + if (reg->flags & SBI_DOMAIN_MEMREGION_M_WRITABLE) + pmp_flags |= PMP_W; + if (reg->flags & SBI_DOMAIN_MEMREGION_M_EXECUTABLE) + pmp_flags |= PMP_X; + } else if (SBI_DOMAIN_MEMREGION_SU_ONLY_ACCESS(reg->flags)) { + if (reg->flags & SBI_DOMAIN_MEMREGION_SU_READABLE) + pmp_flags |= PMP_R; + if (reg->flags & SBI_DOMAIN_MEMREGION_SU_WRITABLE) + pmp_flags |= PMP_W; + if (reg->flags & SBI_DOMAIN_MEMREGION_SU_EXECUTABLE) + pmp_flags |= PMP_X; + } + + return pmp_flags; +} + int sbi_hart_pmp_configure(struct sbi_scratch *scratch) { struct sbi_domain_memregion *reg; struct sbi_domain *dom = sbi_domain_thishart_ptr(); - unsigned int pmp_idx = 0, pmp_flags, pmp_bits, pmp_gran_log2; + unsigned int pmp_idx = 0; + unsigned int pmp_flags, pmp_bits, pmp_gran_log2; unsigned int pmp_count = sbi_hart_pmp_count(scratch); unsigned long pmp_addr = 0, pmp_addr_max = 0; @@ -299,36 +363,68 @@ int sbi_hart_pmp_configure(struct sbi_scratch *scratch) pmp_bits = sbi_hart_pmp_addrbits(scratch) - 1; pmp_addr_max = (1UL << pmp_bits) | ((1UL << pmp_bits) - 1); + if (sbi_hart_has_extension(scratch, SBI_HART_EXT_SMEPMP)) { + /* Reserve first entry for dynamic shared mappings */ + pmp_idx = SBI_SMEPMP_RESV_ENTRY + 1; + + /* + * Set the RLB and clear MML so that, we can write to + * entries without enforcement even if some entries + * are locked. + */ + csr_set(CSR_MSECCFG, MSECCFG_RLB); + csr_clear(CSR_MSECCFG, MSECCFG_MML); + + /* Disable the reserved entry */ + pmp_disable(SBI_SMEPMP_RESV_ENTRY); + } + sbi_domain_for_each_memregion(dom, reg) { if (pmp_count <= pmp_idx) break; pmp_flags = 0; - /* - * If permissions are to be enforced for all modes on this - * region, the lock bit should be set. - */ - if (reg->flags & SBI_DOMAIN_MEMREGION_ENF_PERMISSIONS) - pmp_flags |= PMP_L; - - if (reg->flags & SBI_DOMAIN_MEMREGION_SU_READABLE) - pmp_flags |= PMP_R; - if (reg->flags & SBI_DOMAIN_MEMREGION_SU_WRITABLE) - pmp_flags |= PMP_W; - if (reg->flags & SBI_DOMAIN_MEMREGION_SU_EXECUTABLE) - pmp_flags |= PMP_X; + if (sbi_hart_has_extension(scratch, SBI_HART_EXT_SMEPMP)) { + pmp_flags = sbi_hart_get_smepmp_flags(scratch, dom, reg); + + if (pmp_flags == 0) + return 0; + } else { + /* + * If permissions are to be enforced for all modes on + * this region, the lock bit should be set. + */ + if (reg->flags & SBI_DOMAIN_MEMREGION_ENF_PERMISSIONS) + pmp_flags |= PMP_L; + + if (reg->flags & SBI_DOMAIN_MEMREGION_SU_READABLE) + pmp_flags |= PMP_R; + if (reg->flags & SBI_DOMAIN_MEMREGION_SU_WRITABLE) + pmp_flags |= PMP_W; + if (reg->flags & SBI_DOMAIN_MEMREGION_SU_EXECUTABLE) + pmp_flags |= PMP_X; + } pmp_addr = reg->base >> PMP_SHIFT; - if (pmp_gran_log2 <= reg->order && pmp_addr < pmp_addr_max) + if (pmp_gran_log2 <= reg->order && pmp_addr < pmp_addr_max) { pmp_set(pmp_idx++, pmp_flags, reg->base, reg->order); - else { - sbi_printf("Can not configure pmp for domain %s", dom->name); - sbi_printf(" because memory region address %lx or size %lx is not in range\n", - reg->base, reg->order); + } else { + sbi_printf("Can not configure pmp for domain %s because" + " memory region address 0x%lx or size 0x%lx " + "is not in range.\n", dom->name, reg->base, + reg->order); } } + if (sbi_hart_has_extension(scratch, SBI_HART_EXT_SMEPMP)) { + /* + * All entries are programmed. Enable MML bit. + * Keep the RLB bit so that dynamic mappings can be done. + */ + csr_set(CSR_MSECCFG, (MSECCFG_RLB | MSECCFG_MML)); + } + /* * As per section 3.7.2 of privileged specification v1.12, * virtual address translations can be speculatively performed From 6e44ef686a9b329d837c61d7f121541abfcfed90 Mon Sep 17 00:00:00 2001 From: Himanshu Chauhan Date: Wed, 12 Jul 2023 10:04:35 +0530 Subject: [PATCH 185/187] lib: sbi: Add functions to map/unmap shared memory When Smepmp is enabled, M-mode will need to map/unmap the shared memory before it can read/write to it. This patch adds functions to create dynamic short-lived mappings. Signed-off-by: Himanshu Chauhan Reviewed-by: Anup Patel --- include/sbi/sbi_hart.h | 2 ++ lib/sbi/sbi_hart.c | 42 ++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 44 insertions(+) diff --git a/include/sbi/sbi_hart.h b/include/sbi/sbi_hart.h index 1b78343652d..c150b7e40db 100644 --- a/include/sbi/sbi_hart.h +++ b/include/sbi/sbi_hart.h @@ -90,6 +90,8 @@ unsigned long sbi_hart_pmp_granularity(struct sbi_scratch *scratch); unsigned int sbi_hart_pmp_addrbits(struct sbi_scratch *scratch); unsigned int sbi_hart_mhpm_bits(struct sbi_scratch *scratch); int sbi_hart_pmp_configure(struct sbi_scratch *scratch); +int sbi_hart_map_saddr(unsigned long base, unsigned long size); +int sbi_hart_unmap_saddr(void); int sbi_hart_priv_version(struct sbi_scratch *scratch); void sbi_hart_get_priv_version_str(struct sbi_scratch *scratch, char *version_str, int nvstr); diff --git a/lib/sbi/sbi_hart.c b/lib/sbi/sbi_hart.c index 12f9c7eadd1..7b5f38012a6 100644 --- a/lib/sbi/sbi_hart.c +++ b/lib/sbi/sbi_hart.c @@ -347,6 +347,48 @@ unsigned int sbi_hart_get_smepmp_flags(struct sbi_scratch *scratch, return pmp_flags; } +int sbi_hart_map_saddr(unsigned long addr, unsigned long size) +{ + /* shared R/W access for M and S/U mode */ + unsigned int pmp_flags = (PMP_W | PMP_X); + unsigned long order, base = 0; + struct sbi_scratch *scratch = sbi_scratch_thishart_ptr(); + + /* If Smepmp is not supported no special mapping is required */ + if (!sbi_hart_has_extension(scratch, SBI_HART_EXT_SMEPMP)) + return SBI_OK; + + if (is_pmp_entry_mapped(SBI_SMEPMP_RESV_ENTRY)) + return SBI_ENOSPC; + + for (order = log2roundup(size) ; order <= __riscv_xlen; order++) { + if (order < __riscv_xlen) { + base = addr & ~((1UL << order) - 1UL); + if ((base <= addr) && + (addr < (base + (1UL << order))) && + (base <= (addr + size - 1UL)) && + ((addr + size - 1UL) < (base + (1UL << order)))) + break; + } else { + return SBI_EFAIL; + } + } + + pmp_set(SBI_SMEPMP_RESV_ENTRY, pmp_flags, base, order); + + return SBI_OK; +} + +int sbi_hart_unmap_saddr(void) +{ + struct sbi_scratch *scratch = sbi_scratch_thishart_ptr(); + + if (!sbi_hart_has_extension(scratch, SBI_HART_EXT_SMEPMP)) + return SBI_OK; + + return pmp_disable(SBI_SMEPMP_RESV_ENTRY); +} + int sbi_hart_pmp_configure(struct sbi_scratch *scratch) { struct sbi_domain_memregion *reg; From 0ad866067d7853683d88c10ea9269ae6001bcf6f Mon Sep 17 00:00:00 2001 From: Himanshu Chauhan Date: Wed, 12 Jul 2023 10:04:36 +0530 Subject: [PATCH 186/187] lib: sbi: Map/Unmap debug console shared memory buffers With Smepmp enabled, it is necessary for shared memory from S/U mode to be mapped/unmapped before and after read/write of the memory region. This patch maps the debug console shared memory before accessing it. Signed-off-by: Himanshu Chauhan Reviewed-by: Anup Patel --- lib/sbi/sbi_ecall_dbcn.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/lib/sbi/sbi_ecall_dbcn.c b/lib/sbi/sbi_ecall_dbcn.c index 8e687298a39..18cd6c8b5cc 100644 --- a/lib/sbi/sbi_ecall_dbcn.c +++ b/lib/sbi/sbi_ecall_dbcn.c @@ -14,6 +14,7 @@ #include #include #include +#include static int sbi_ecall_dbcn_handler(unsigned long extid, unsigned long funcid, const struct sbi_trap_regs *regs, @@ -46,10 +47,12 @@ static int sbi_ecall_dbcn_handler(unsigned long extid, unsigned long funcid, regs->a1, regs->a0, smode, SBI_DOMAIN_READ|SBI_DOMAIN_WRITE)) return SBI_ERR_INVALID_PARAM; + sbi_hart_map_saddr(regs->a1, regs->a0); if (funcid == SBI_EXT_DBCN_CONSOLE_WRITE) *out_val = sbi_nputs((const char *)regs->a1, regs->a0); else *out_val = sbi_ngets((char *)regs->a1, regs->a0); + sbi_hart_unmap_saddr(); return 0; case SBI_EXT_DBCN_CONSOLE_WRITE_BYTE: sbi_putc(regs->a0); From de7cdbbee757929a84a11b86a00eb0aa82eaaf19 Mon Sep 17 00:00:00 2001 From: Kaiwen Xue Date: Mon, 17 Jul 2023 15:20:36 -0700 Subject: [PATCH 187/187] lib: sbi: Add support for smcntrpmf This adds the support for ISA extension smcntrpmf. Signed-off-by: Kaiwen Xue --- include/sbi/riscv_encoding.h | 4 ++++ include/sbi/sbi_hart.h | 2 ++ lib/sbi/riscv_asm.c | 12 +++++++++++ lib/sbi/sbi_hart.c | 11 ++++++++++ lib/sbi/sbi_pmu.c | 42 ++++++++++++++++++++++++++++++++++-- 5 files changed, 69 insertions(+), 2 deletions(-) diff --git a/include/sbi/riscv_encoding.h b/include/sbi/riscv_encoding.h index 50071ad3e12..f09a89afe82 100644 --- a/include/sbi/riscv_encoding.h +++ b/include/sbi/riscv_encoding.h @@ -602,6 +602,8 @@ /* Machine Counter Setup */ #define CSR_MCOUNTINHIBIT 0x320 +#define CSR_MCYCLECFG 0x321 +#define CSR_MINSTRETCFG 0x322 #define CSR_MHPMEVENT3 0x323 #define CSR_MHPMEVENT4 0x324 #define CSR_MHPMEVENT5 0x325 @@ -633,6 +635,8 @@ #define CSR_MHPMEVENT31 0x33f /* For RV32 */ +#define CSR_MCYCLECFGH 0x721 +#define CSR_MINSTRETCFGH 0x722 #define CSR_MHPMEVENT3H 0x723 #define CSR_MHPMEVENT4H 0x724 #define CSR_MHPMEVENT5H 0x725 diff --git a/include/sbi/sbi_hart.h b/include/sbi/sbi_hart.h index c150b7e40db..4f9e14608f4 100644 --- a/include/sbi/sbi_hart.h +++ b/include/sbi/sbi_hart.h @@ -40,6 +40,8 @@ enum sbi_hart_extensions { SBI_HART_EXT_ZICNTR, /** HART has Zihpm extension */ SBI_HART_EXT_ZIHPM, + /** Hart has Smcntrpmf extension */ + SBI_HART_EXT_SMCNTRPMF, /** Maximum index of Hart extension */ SBI_HART_EXT_MAX, diff --git a/lib/sbi/riscv_asm.c b/lib/sbi/riscv_asm.c index 881dea3e54a..05b8c7ce6e3 100644 --- a/lib/sbi/riscv_asm.c +++ b/lib/sbi/riscv_asm.c @@ -128,6 +128,8 @@ unsigned long csr_read_num(int csr_num) switchcase_csr_read_8(CSR_MHPMCOUNTER8, ret) switchcase_csr_read_16(CSR_MHPMCOUNTER16, ret) switchcase_csr_read(CSR_MCOUNTINHIBIT, ret) + switchcase_csr_read(CSR_MCYCLECFG, ret) + switchcase_csr_read(CSR_MINSTRETCFG, ret) switchcase_csr_read(CSR_MHPMEVENT3, ret) switchcase_csr_read_4(CSR_MHPMEVENT4, ret) switchcase_csr_read_8(CSR_MHPMEVENT8, ret) @@ -139,6 +141,12 @@ unsigned long csr_read_num(int csr_num) switchcase_csr_read_4(CSR_MHPMCOUNTER4H, ret) switchcase_csr_read_8(CSR_MHPMCOUNTER8H, ret) switchcase_csr_read_16(CSR_MHPMCOUNTER16H, ret) + /** + * The CSR range M[CYCLE, INSTRET]CFGH are available only if smcntrpmf + * extension is present. The caller must ensure that. + */ + switchcase_csr_read(CSR_MCYCLECFGH, ret) + switchcase_csr_read(CSR_MINSTRETCFGH, ret) /** * The CSR range MHPMEVENT[3-16]H are available only if sscofpmf * extension is present. The caller must ensure that. @@ -206,12 +214,16 @@ void csr_write_num(int csr_num, unsigned long val) switchcase_csr_write_4(CSR_MHPMCOUNTER4H, val) switchcase_csr_write_8(CSR_MHPMCOUNTER8H, val) switchcase_csr_write_16(CSR_MHPMCOUNTER16H, val) + switchcase_csr_write(CSR_MCYCLECFGH, val) + switchcase_csr_write(CSR_MINSTRETCFGH, val) switchcase_csr_write(CSR_MHPMEVENT3H, val) switchcase_csr_write_4(CSR_MHPMEVENT4H, val) switchcase_csr_write_8(CSR_MHPMEVENT8H, val) switchcase_csr_write_16(CSR_MHPMEVENT16H, val) #endif switchcase_csr_write(CSR_MCOUNTINHIBIT, val) + switchcase_csr_write(CSR_MCYCLECFG, val) + switchcase_csr_write(CSR_MINSTRETCFG, val) switchcase_csr_write(CSR_MHPMEVENT3, val) switchcase_csr_write_4(CSR_MHPMEVENT4, val) switchcase_csr_write_8(CSR_MHPMEVENT8, val) diff --git a/lib/sbi/sbi_hart.c b/lib/sbi/sbi_hart.c index 7b5f38012a6..aadb53c1dd3 100644 --- a/lib/sbi/sbi_hart.c +++ b/lib/sbi/sbi_hart.c @@ -597,6 +597,9 @@ static inline char *sbi_hart_extension_id2string(int ext) case SBI_HART_EXT_SMEPMP: estr = "smepmp"; break; + case SBI_HART_EXT_SMCNTRPMF: + estr = "smcntrpmf"; + break; default: break; } @@ -844,6 +847,14 @@ static int hart_detect_features(struct sbi_scratch *scratch) SBI_HART_EXT_SMSTATEEN, true); } + /* Detect if hart supports smcntrpmf */ + if (hfeatures->priv_version >= SBI_HART_PRIV_VER_1_12) { + csr_read_allowed(CSR_MCYCLECFG, (unsigned long)&trap); + if (!trap.cause) + __sbi_hart_update_extension(hfeatures, + SBI_HART_EXT_SMCNTRPMF, true); + } + /* Let platform populate extensions */ rc = sbi_platform_extensions_init(sbi_platform_thishart_ptr(), hfeatures); diff --git a/lib/sbi/sbi_pmu.c b/lib/sbi/sbi_pmu.c index 7213a53b0b5..a82f6941e4c 100644 --- a/lib/sbi/sbi_pmu.c +++ b/lib/sbi/sbi_pmu.c @@ -609,6 +609,44 @@ static int pmu_update_hw_mhpmevent(struct sbi_pmu_hw_event *hw_evt, int ctr_idx, return 0; } +static int pmu_fixed_ctr_update_inhibit_bits(int fixed_ctr, unsigned long flags) +{ + struct sbi_scratch *scratch = sbi_scratch_thishart_ptr(); + uint64_t cfg_val = 0, cfg_csr_no; +#if __riscv_xlen == 32 + uint64_t cfgh_csr_no; +#endif + if (!sbi_hart_has_extension(scratch, SBI_HART_EXT_SMCNTRPMF)) + return fixed_ctr; + + switch (fixed_ctr) { + case 0: + cfg_csr_no = CSR_MCYCLECFG; +#if __riscv_xlen == 32 + cfgh_csr_no = CSR_MCYCLECFGH; +#endif + break; + case 2: + cfg_csr_no = CSR_MINSTRETCFG; +#if __riscv_xlen == 32 + cfgh_csr_no = CSR_MINSTRETCFGH; +#endif + break; + default: + return SBI_EFAIL; + } + + cfg_val |= MHPMEVENT_MINH; + pmu_update_inhibit_flags(flags, &cfg_val); +#if __riscv_xlen == 32 + csr_write_num(cfg_csr_no, cfg_val & 0xFFFFFFFF); + csr_write_num(cfgh_csr_no, cfg_val >> BITS_PER_LONG); +#else + csr_write_num(cfg_csr_no, cfg_val); +#endif + return fixed_ctr; +} + static int pmu_ctr_find_fixed_fw(unsigned long evt_idx_code) { /* Non-programmables counters are enabled always. No need to do lookup */ @@ -641,7 +679,7 @@ static int pmu_ctr_find_hw(struct sbi_pmu_hart_state *phs, fixed_ctr = pmu_ctr_find_fixed_fw(event_idx); if (fixed_ctr >= 0 && !sbi_hart_has_extension(scratch, SBI_HART_EXT_SSCOFPMF)) - return fixed_ctr; + return pmu_fixed_ctr_update_inhibit_bits(fixed_ctr, flags); if (sbi_hart_priv_version(scratch) >= SBI_HART_PRIV_VER_1_11) mctr_inhbt = csr_read(CSR_MCOUNTINHIBIT); @@ -684,7 +722,7 @@ static int pmu_ctr_find_hw(struct sbi_pmu_hart_state *phs, * Return the fixed counter as they are mandatory anyways. */ if (fixed_ctr >= 0) - return fixed_ctr; + return pmu_fixed_ctr_update_inhibit_bits(fixed_ctr, flags); else return SBI_EFAIL; }