286 Commits
v1.1 ... v1.3

Author SHA1 Message Date
Anup Patel
2552799a1d 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 <apatel@ventanamicro.com>
2023-06-23 11:01:49 +05:30
Gianluca Guida
8bd666a25b 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 <gianluca@rivosinc.com>
Reviewed-by: Anup Patel <anup@brainfault.org>
2023-06-23 08:46:07 +05:30
Guo Ren
27c957a43b 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:
230278dcf1 ("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: 230278dcf1 ("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 <jrtc27@jrtc27.com>
Signed-off-by: Guo Ren <guoren@linux.alibaba.com>
Signed-off-by: Guo Ren <guoren@kernel.org>
Reviewed-by: Anup Patel <anup@brainfault.org>
2023-06-21 11:12:42 +05:30
Xiang W
d64942f0e4 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 <wxjstz@126.com>
Reviewed-by: Anup Patel <anup@brainfault.org>
2023-06-21 10:20:51 +05:30
Alexandre Ghiti
8153b2622b platform/lib: Set no-map attribute on all PMP regions
This reverts commit 6966ad0abe ("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 <alexghiti@rivosinc.com>
Reviewed-by: Atish Patra <atishp@rivosinc.com>
Reviewed-by: Xiang W <wxjstz@126.com>
2023-06-15 18:27:17 +05:30
Anup Patel
932be2cde1 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 <apatel@ventanamicro.com>
Reviewed-by: Andrew Jones <ajones@ventanamicro.com>
2023-06-14 11:26:06 +05:30
Anup Patel
524feec7b7 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 <apatel@ventanamicro.com>
Reviewed-by: Andrew Jones <ajones@ventanamicro.com>
2023-06-14 11:26:04 +05:30
Anup Patel
355796c5bc 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 <apatel@ventanamicro.com>
Reviewed-by: Andrew Jones <ajones@ventanamicro.com>
2023-06-06 16:01:14 +05:30
Anup Patel
1df52fa7e8 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 <apatel@ventanamicro.com>
Reviewed-by: Andrew Jones <ajones@ventanamicro.com>
2023-06-05 16:51:07 +05:30
Anup Patel
b3594ac1d1 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 <apatel@ventanamicro.com>
Reviewed-by: Andrew Jones <ajones@ventanamicro.com>
2023-06-05 16:50:56 +05:30
Anup Patel
f0516beae0 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 <apatel@ventanamicro.com>
Reviewed-by: Andrew Jones <ajones@ventanamicro.com>
2023-06-05 16:46:50 +05:30
Anup Patel
acbd8fce9e 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 <apatel@ventanamicro.com>
Reviewed-by: Andrew Jones <ajones@ventanamicro.com>
2023-06-05 16:02:59 +05:30
Anup Patel
3c1c972cb6 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 <apatel@ventanamicro.com>
Reviewed-by: Andrew Jones <ajones@ventanamicro.com>
2023-06-05 15:59:35 +05:30
Anup Patel
7e5636ac37 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 <apatel@ventanamicro.com>
Reviewed-by: Andrew Jones <ajones@ventanamicro.com>
2023-06-05 15:58:42 +05:30
Anup Patel
30137166c6 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 <apatel@ventanamicro.com>
Reviewed-by: Andrew Jones <ajones@ventanamicro.com>
2023-06-05 15:57:58 +05:30
Anup Patel
5a8cfcdf19 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 <apatel@ventanamicro.com>
Reviewed-by: Andrew Jones <ajones@ventanamicro.com>
2023-06-05 15:55:56 +05:30
Anup Patel
903e88caaf 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 <apatel@ventanamicro.com>
Reviewed-by: Andrew Jones <ajones@ventanamicro.com>
2023-06-05 15:55:45 +05:30
Anup Patel
fa5ad2e6f9 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 <apatel@ventanamicro.com>
Reviewed-by: Andrew Jones <ajones@ventanamicro.com>
2023-06-05 15:55:29 +05:30
Anup Patel
66daafe3ba 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 <apatel@ventanamicro.com>
Reviewed-by: Andrew Jones <ajones@ventanamicro.com>
2023-06-05 15:55:21 +05:30
Anup Patel
ef4542dc13 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 <apatel@ventanamicro.com>
Reviewed-by: Andrew Jones <ajones@ventanamicro.com>
2023-06-05 15:50:33 +05:30
Anup Patel
bbff53fe3b 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 <apatel@ventanamicro.com>
Reviewed-by: Andrew Jones <ajones@ventanamicro.com>
2023-06-05 15:48:43 +05:30
Anup Patel
2a04f70373 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 <apatel@ventanamicro.com>
Reviewed-by: Andrew Jones <ajones@ventanamicro.com>
2023-06-05 15:46:22 +05:30
Anup Patel
40d36a6673 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 <apatel@ventanamicro.com>
Reviewed-by: Andrew Jones <ajones@ventanamicro.com>
2023-06-05 15:46:09 +05:30
Anup Patel
5cf9a54016 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 <apatel@ventanamicro.com>
Reviewed-by: Andrew Jones <ajones@ventanamicro.com>
2023-06-05 15:45:33 +05:30
Anup Patel
aad7a37705 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 <apatel@ventanamicro.com>
2023-06-05 15:42:50 +05:30
Andrew Jones
bdde2ecd27 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 <ajones@ventanamicro.com>
Reviewed-by: Anup Patel <anup@brainfault.org>
2023-06-04 15:18:40 +05:30
Heinrich Schuchardt
df75e09956 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: 5a049fe1d6 ("lib: utils/ipi: Add ACLINT MSWI library")
Signed-off-by: Heinrich Schuchardt <heinrich.schuchardt@canonical.com>
Reviewed-by: Xiang W <wxjstz@126.com>
Reviewed-by: Anup Patel <anup@brainfault.org>
2023-06-04 15:13:50 +05:30
Xiang W
122f2260b3 lib: utils: Improve fdt_timer
Remove dummy driver. Optimize fdt_timer_cold_init to exit the
loop early.

Signed-off-by: Xiang W <wxjstz@126.com>
Reviewed-by: Anup Patel <anup@brainfault.org>
2023-05-26 12:47:22 +05:30
Xiang W
9a0bdd0c84 lib: utils: Improve fdt_ipi
Remove dummy driver. Optimize fdt_ipi_cold_init to exit the loop
early.

Signed-off-by: Xiang W <wxjstz@126.com>
Reviewed-by: Anup Patel <anup@brainfault.org>
2023-05-26 12:43:25 +05:30
Xiang W
264d0be1fd 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 <wxjstz@126.com>
Reviewed-by: Anup Patel <anup@brainfault.org>
2023-05-26 12:37:25 +05:30
Xiang W
8b99a7f7d8 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 <wxjstz@126.com>
Reviewed-by: Anup Patel <anup@brainfault.org>
2023-05-26 12:36:54 +05:30
Filip Filmar
d4c46e0ff1 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 <fmil@google.com>
Reviewed-by: Xiang W <wxjstz@126.com>
Reviewed-by: Anup Patel <anup@brainfault.org>
2023-05-22 08:52:57 +05:30
Andrew Jones
33f1722f2b 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 <ajones@ventanamicro.com>
Reviewed-by: Anup Patel <anup@brainfault.org>
2023-05-21 16:54:02 +05:30
Andrew Jones
c3e31cbf36 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 <ajones@ventanamicro.com>
Reviewed-by: Anup Patel <anup@brainfault.org>
2023-05-21 16:54:00 +05:30
Xiang W
767b5fc418 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 <wxjstz@126.com>
Signed-off-by: Andrew Jones <ajones@ventanamicro.com>
Reviewed-by: Anup Patel <anup@brainfault.org>
2023-05-21 16:53:38 +05:30
Andrew Jones
8b952d4fcd 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 <ajones@ventanamicro.com>
Reviewed-by: Anup Patel <anup@brainfault.org>
2023-05-21 16:53:02 +05:30
Andrew Jones
042f0c3ea2 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 <ajones@ventanamicro.com>
Reviewed-by: Anup Patel <anup@brainfault.org>
2023-05-21 16:30:29 +05:30
Andrew Jones
e307ba7d46 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 <ajones@ventanamicro.com>
Reviewed-by: Anup Patel <anup@brainfault.org>
2023-05-21 16:29:46 +05:30
Andrew Jones
f58c14090f 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 <ajones@ventanamicro.com>
Reviewed-by: Anup Patel <anup@brainfault.org>
2023-05-21 16:27:38 +05:30
Xiang W
dc1c7db05e lib: sbi: Simplify BITS_PER_LONG definition
No need to use #elif ladder when defining BITS_PER_LONG.

Signed-off-by: Xiang W <wxjstz@126.com>
Reviewed-by: Andrew Jones <ajones@ventanamicro.com>
Reviewed-by: Anup Patel <anup@brainfault.org>
2023-05-11 12:56:56 +05:30
Xiang W
6bc02dede8 lib: sbi: Simplify sbi_ipi_process remove goto
Simplify sbi_ipi_process() by removing goto statement.

Signed-off-by: Xiang W <wxjstz@126.com>
Reviewed-by: Anup Patel <anup@brainfault.org>
2023-05-11 12:46:42 +05:30
Xiang W
4e3353057a lib: sbi: Remove unnecessary semicolon
We have redundant semicolon at quite a few places so let's remove it.

Signed-off-by: Xiang W <wxjstz@126.com>
Reviewed-by: Anup Patel <anup@brainfault.org>
2023-05-11 12:31:34 +05:30
Tan En De
7919530308 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 <ende.tan@starfivetech.com>
Reviewed-by: Atish Patra <atishp@rivosinc.com>
2023-04-20 14:19:44 +05:30
Anup Patel
f5dfd99139 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: 67b2a40892 ("lib: sbi: sbi_ecall: Check the range of
SBI error")
Signed-off-by: Anup Patel <apatel@ventanamicro.com>
2023-04-17 09:48:13 +05:30
Alexandre Ghiti
674e0199b2 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 <atishp@atishpatra.org>
Signed-off-by: Alexandre Ghiti <alexghiti@rivosinc.com>
Reviewed-by: Atish Patra <atishp@rivosinc.com>
2023-04-17 09:26:28 +05:30
Alexandre Ghiti
bdb3c42bca 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 <alexghiti@rivosinc.com>
Reviewed-by: Atish Patra <atishp@rivosinc.com>
2023-04-17 09:26:26 +05:30
Bin Meng
e41dbb507c 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 <bmeng@tinylab.org>
Reviewed-by: Anup Patel <anup@brainfault.org>
Reviewed-by: Xiang W <wxjstz@126.com>
2023-04-17 08:55:55 +05:30
Bin Meng
f692289ed4 firmware: Optimize loading relocation type
't5' already contains relocation type so don't bother reloading it.

Signed-off-by: Bin Meng <bmeng@tinylab.org>
Reviewed-by: Anup Patel <anup@brainfault.org>
Reviewed-by: Xiang W <wxjstz@126.com>
2023-04-17 08:55:49 +05:30
Lad Prabhakar
eeab500a65 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 <prabhakar.mahadev-lad.rj@bp.renesas.com>
Reviewed-by: Anup Patel <anup@brainfault.org>
Reviewed-by: Conor Dooley <conor.dooley@microchip.com>
Reviewed-by: Yu Chien Peter Lin <peterlin@andestech.com>
2023-04-14 17:35:04 +05:30
Xiang W
bf40e07f6f 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 <wxjstz@126.com>
Reviewed-by: Anup Patel <anup@brainfault.org>
Tested-by: Anup Patel <anup@brainfault.org>
2023-04-14 13:45:30 +05:30
Xiang W
80078ab088 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 <wxjstz@126.com>
Reviewed-by: Anup Patel <anup@brainfault.org>
Tested-by: Anup Patel <anup@brainfault.org>
2023-04-13 13:49:57 +05:30
Xiang W
24dde46b8d 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 <wxjstz@126.com>
Reviewed-by: Anup Patel <anup@brainfault.org>
Tested-by: Anup Patel <anup@brainfault.org>
2023-04-13 12:44:50 +05:30
Xiang W
66fa925353 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 <wxjstz@126.com>
Reviewed-by: Anup Patel <anup@brainfault.org>
Tested-by: Anup Patel <anup@brainfault.org>
2023-04-13 12:37:55 +05:30
Heinrich Schuchardt
2868f26131 lib: utils: fdt_fixup: avoid buffer overrun
fdt_reserved_memory_fixup() uses filtered_order[PMP_COUNT]. The index
must not reach PMP_COUNT.

Fixes: 199189bd1c ("lib: utils: Mark only the largest region as reserved in FDT")
Addresses-Coverity-ID: 1536994 ("Out-of-bounds write")
Signed-off-by: Heinrich Schuchardt <heinrich.schuchardt@canonical.com>
Reviewed-by: Xiang W <wxjstz@126.com>
Reviewed-by: Anup Patel <anup@brainfault.org>
2023-04-07 11:22:25 +05:30
Gabriel Somlo
ee016a7bb0 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 <gsomlo@gmail.com>
Reviewed-by: Andrew Jones <ajones@ventanamicro.com>
Reviewed-by: Xiang W <wxjstz@126.com>
2023-04-07 11:16:05 +05:30
Yu Chien Peter Lin
edc9914392 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: 13d40f21d5 ("lib: sbi: Add PMU support")
Signed-off-by: Yu Chien Peter Lin <peterlin@andestech.com>
Reviewed-by: Andrew Jones <ajones@ventanamicro.com>
Reviewed-by: Xiang W <wxjstz@126.com>
2023-04-07 10:06:59 +05:30
Sunil V L
91767d093b lib: sbi: Print the CPPC device name
If CPPC device is registered by the platform, print its name.

Signed-off-by: Sunil V L <sunilvl@ventanamicro.com>
Reviewed-by: Andrew Jones <ajones@ventanamicro.com>
Reviewed-by: Anup Patel <anup@brainfault.org>
2023-04-07 09:36:42 +05:30
Sunil V L
33caae8069 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 <sunilvl@ventanamicro.com>
Reviewed-by: Andrew Jones <ajones@ventanamicro.com>
Reviewed-by: Anup Patel <anup@brainfault.org>
2023-04-07 09:36:01 +05:30
Sunil V L
45ba2b203c 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 <sunilvl@ventanamicro.com>
Reviewed-by: Andrew Jones <ajones@ventanamicro.com>
Reviewed-by: Anup Patel <anup@brainfault.org>
2023-04-07 09:35:06 +05:30
Mayuresh Chitale
8e90259da8 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 <mchitale@ventanamicro.com>
Reviewed-by: Anup Patel <anup@brainfault.org>
2023-04-06 18:52:03 +05:30
Anup Patel
30b9e7ee14 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 <apatel@ventanamicro.com>
2023-04-06 18:48:19 +05:30
Anup Patel
f64dfcd2b5 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 <apatel@ventanamicro.com>
2023-04-06 18:48:15 +05:30
Xiang W
73ab11dfb0 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 <wxjstz@126.com>
Reviewed-by: Himanshu Chauhan <hchauhan@ventanamicro.com>
Reviewed-by: Anup Patel <anup@brainfault.org>
2023-04-06 16:14:35 +05:30
Xiang W
ed88a63b90 lib: sbi_scratch: Optimize the alignment code for alloc size
Signed-off-by: Xiang W <wxjstz@126.com>
Reviewed-by: Anup Patel <anup@brainfault.org>
2023-04-06 16:00:45 +05:30
Evgenii Shatokhin
c6a092cd80 lib: sbi: Clear IPIs before init_warm_startup in non-boot harts
Since commit 50d4fde1c5 ("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 <e.shatokhin@yadro.com>
Reviewed-by: Anup Patel <anup@brainfault.org>
2023-03-10 14:13:40 +05:30
Evgenii Shatokhin
e8e9ed3790 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 <e.shatokhin@yadro.com>
Reviewed-by: Anup Patel <anup@brainfault.org>
2023-03-10 14:12:43 +05:30
Evgenii Shatokhin
d56049e299 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 <anup@brainfault.org>
Signed-off-by: Evgenii Shatokhin <e.shatokhin@yadro.com>
Reviewed-by: Anup Patel <anup@brainfault.org>
2023-03-10 14:00:36 +05:30
Mayuresh Chitale
c631a7da27 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 <mchitale@ventanamicro.com>
Reviewed-by: Atish Patra <atishp@rivosinc.com>
Reviewed-by: Anup Patel <anup@brainfault.org>
2023-03-10 14:00:33 +05:30
Mayuresh Chitale
57d3aa3b0d 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 <mchitale@ventanamicro.com>
Reviewed-by: Anup Patel <anup@brainfault.org>
2023-03-10 14:00:30 +05:30
Mayuresh Chitale
641d2e9f38 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 <mchitale@ventanamicro.com>
Reviewed-by: Anup Patel <anup@brainfault.org>
2023-03-10 14:00:28 +05:30
Mayuresh Chitale
b51ddffcc0 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 <mchitale@ventanamicro.com>
Reviewed-by: Anup Patel <anup@brainfault.org>
2023-03-10 14:00:26 +05:30
Mayuresh Chitale
548e4b4b28 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 <mchitale@ventanamicro.com>
Reviewed-by: Anup Patel <anup@brainfault.org>
Reviewed-by: Andrew Jones <ajones@ventanamicro.com>
2023-03-10 14:00:24 +05:30
Mayuresh Chitale
60c358e677 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 <mchitale@ventanamicro.com>
Reviewed-by: Atish Patra <atishp@rivosinc.com>
Reviewed-by: Anup Patel <anup@brainfault.org>
2023-03-10 14:00:22 +05:30
Mayuresh Chitale
51951d9e9a 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 <mchitale@ventanamicro.com>
Reviewed-by: Atish Patra <atishp@rivosinc.com>
Reviewed-by: Anup Patel <anup@brainfault.org>
2023-03-10 14:00:07 +05:30
Mayuresh Chitale
1fe8dc9955 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 <mchitale@ventanamicro.com>
Reviewed-by: Atish Patra <atishp@rivosinc.com>
Reviewed-by: Anup Patel <anup@brainfault.org>
2023-03-10 13:46:52 +05:30
Mayuresh Chitale
506144f398 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 <mchitale@ventanamicro.com>
Reviewed-by: Anup Patel <anup@brainfault.org>
2023-03-09 21:12:35 +05:30
Minda Chen
568ea49490 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 <minda.chen@starfivetech.com>
Reviewed-by: Anup Patel <anup@brainfault.org>
2023-03-09 21:11:20 +05:30
Minda Chen
e9d08bd99c 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 <minda.chen@starfivetech.com>
Reviewed-by: Anup Patel <anup@brainfault.org>
2023-03-09 21:00:57 +05:30
Bin Meng
4b28afc98b 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 <bmeng@tinylab.org>
Reviewed-by: Xiang W <wxjstz@126.com>
Reviewed-by: Anup Patel <anup@brainfault.org>
2023-03-01 09:23:17 +05:30
minda.chen
908be1b85c 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 <minda.chen@starfivetech.com>
Reviewed-by: Anup Patel <anup@brainfault.org>
2023-03-01 08:59:33 +05:30
Andrew Jones
5ccebf0a7e 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 <ajones@ventanamicro.com>
Reviewed-by: Anup Patel <anup@brainfault.org>
2023-02-27 19:50:51 +05:30
Andrew Jones
37558dccbe docs: Correct opensbi-domain property name
Replace the commas with dashes to correct the name.

Signed-off-by: Andrew Jones <ajones@ventanamicro.com>
Reviewed-by: Anup Patel <anup@brainfault.org>
2023-02-27 19:49:07 +05:30
Andrew Jones
7c964e279c 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 <ajones@ventanamicro.com>
Reviewed-by: Anup Patel <anup@brainfault.org>
2023-02-27 19:47:35 +05:30
Andrew Jones
c9917b6108 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 <ajones@ventanamicro.com>
Reviewed-by: Anup Patel <anup@brainfault.org>
2023-02-27 19:45:28 +05:30
Andrew Jones
73623a0aca 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 <ajones@ventanamicro.com>
Reviewed-by: Anup Patel <anup@brainfault.org>
2023-02-27 19:43:52 +05:30
Andrew Jones
8a40306371 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 <ajones@ventanamicro.com>
Reviewed-by: Anup Patel <anup@brainfault.org>
2023-02-27 19:40:21 +05:30
Andrew Jones
07673fc063 lib: sbi_hsm: Remove unnecessary include
Also remove a superfluous semicolon and add a blank line.

Signed-off-by: Andrew Jones <ajones@ventanamicro.com>
Reviewed-by: Anup Patel <anup@brainfault.org>
2023-02-27 19:38:55 +05:30
Andrew Jones
b1ae6ef33b 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 <ajones@ventanamicro.com>
Reviewed-by: Anup Patel <anup@brainfault.org>
2023-02-27 19:38:00 +05:30
Andrew Jones
c88e039ec2 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 <ajones@ventanamicro.com>
Reviewed-by: Anup Patel <anup@brainfault.org>
2023-02-27 19:36:58 +05:30
Andrew Jones
40f16a81d3 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 <ajones@ventanamicro.com>
Reviewed-by: Anup Patel <anup@brainfault.org>
2023-02-27 19:35:47 +05:30
Andrew Jones
1364d5adb2 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 <ajones@ventanamicro.com>
Reviewed-by: Anup Patel <anup@brainfault.org>
2023-02-27 19:34:41 +05:30
Bin Meng
17b3776c81 docs: domain_support: Update the DT example
commit 3e2f573e70 ("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 <bmeng@tinylab.org>
Reviewed-by: Anup Patel <anup@brainfault.org>
2023-02-27 13:50:27 +05:30
Bin Meng
bc06ff65bf 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 <bmeng@tinylab.org>
Reviewed-by: Anup Patel <anup@brainfault.org>
2023-02-27 13:49:21 +05:30
Bin Meng
5a75f5309c lib: sbi/sbi_domain: cosmetic style fixes
Minor updates to the comments for language and style fixes.

Signed-off-by: Bin Meng <bmeng@tinylab.org>
Reviewed-by: Anup Patel <anup@brainfault.org>
2023-02-27 12:26:26 +05:30
Yu Chien Peter Lin
67b2a40892 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 <peterlin@andestech.com>
Reviewed-by: Xiang W <wxjstz@126.com>
Reviewed-by: Andrew Jones <ajones@ventanamicro.com>
Reviewed-by: Anup Patel <anup@brainfault.org>
2023-02-27 11:46:08 +05:30
Lad Prabhakar
2491242282 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 <prabhakar.mahadev-lad.rj@bp.renesas.com>
Reviewed-by: Yu Chien Peter Lin <peterlin@andestech.com>
Reviewed-by: Anup Patel <anup@brainfault.org>
2023-02-27 11:36:06 +05:30
Lad Prabhakar
c10095132a 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 <prabhakar.mahadev-lad.rj@bp.renesas.com>
Reviewed-by: Yu Chien Peter Lin <peterlin@andestech.com>
Reviewed-by: Anup Patel <anup@brainfault.org>
2023-02-27 11:35:01 +05:30
Anup Patel
31b82e0d50 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 <apatel@ventanamicro.com>
2023-02-27 11:26:37 +05:30
Anup Patel
81adc62f45 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 <apatel@ventanamicro.com>
2023-02-27 11:26:35 +05:30
Nylon Chen
30ea8069f4 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: a28bfae443/content.adoc [0]

Signed-off-by: Nylon Chen <nylon.chen@sifive.com>
Reviewed-by: Zong Li <zong.li@sifive.com>
Reviewed-by: Anup Patel <anup@brainfault.org>
2023-02-27 11:22:11 +05:30
Shengyu Qu
4f2be40102 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 <wiagn233@outlook.com>
Reviewed-by: Xiang W <wxjstz@126.com>
Reviewed-by: Anup Patel <anup@brainfault.org>
2023-02-27 10:54:42 +05:30
Xiang W
6861ee996c 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 <peterlin@andestech.com>
Signed-off-by: Xiang W <wxjstz@126.com>
Reviewed-by: Anup Patel <anup@brainfault.org>
Reviewed-by: Bin Meng <bmeng@tinylab.org>
2023-02-27 10:49:09 +05:30
Bin Meng
99d09b601e 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: b1678af210 ("lib: sbi: Add initial domain support")
Reported-by: Marouene Boubakri <marouene.boubakri@nxp.com>
Signed-off-by: Bin Meng <bmeng@tinylab.org>
Reviewed-by: Anup Patel <anup@brainfault.org>
2023-02-27 10:04:03 +05:30
Bin Meng
745aaecc64 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 <bmeng@tinylab.org>
Reviewed-by: Anup Patel <anup@brainfault.org>
2023-02-27 10:02:29 +05:30
Bin Meng
aafcc90a87 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 <bmeng@tinylab.org>
Reviewed-by: Anup Patel <anup@brainfault.org>
2023-02-27 10:00:15 +05:30
Bin Meng
321293c644 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 <bmeng@tinylab.org>
Reviewed-by: Anup Patel <anup@brainfault.org>
2023-02-27 09:59:01 +05:30
Anup Patel
65c2190b47 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 <apatel@ventanamicro.com>
Reviewed-by: Andrew Jones <ajones@ventanamicro.com>
2023-02-10 10:30:18 +05:30
Anup Patel
29285aead0 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 <apatel@ventanamicro.com>
Reviewed-by: Atish Patra <atishp@rivosinc.com>
Reviewed-by: Xiang W <wxjstz@126.com>
Reviewed-by: Bin Meng <bmeng@tinylab.org>
Reviewed-by: Andrew Jones <ajones@ventanamicro.com>
2023-02-10 10:04:59 +05:30
Anup Patel
c43903c4ea 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 <apatel@ventanamicro.com>
Reviewed-by: Atish Patra <atishp@rivosinc.com>
Reviewed-by: Xiang W <wxjstz@126.com>
Reviewed-by: Bin Meng <bmeng@tinylab.org>
Reviewed-by: Andrew Jones <ajones@ventanamicro.com>
2023-02-10 10:04:41 +05:30
Anup Patel
5a41a3884f 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 <apatel@ventanamicro.com>
Reviewed-by: Atish Patra <atishp@rivosinc.com>
Reviewed-by: Xiang W <wxjstz@126.com>
Reviewed-by: Bin Meng <bmeng@tinylab.org>
2023-02-10 09:55:18 +05:30
Anup Patel
eab48c33a1 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 <apatel@ventanamicro.com>
Reviewed-by: Atish Patra <atishp@rivosinc.com>
Reviewed-by: Xiang W <wxjstz@126.com>
Reviewed-by: Bin Meng <bmeng@tinylab.org>
Reviewed-by: Andrew Jones <ajones@ventanamicro.com>
2023-02-10 09:14:58 +05:30
Anup Patel
4e0572f57b 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 <apatel@ventanamicro.com>
Reviewed-by: Atish Patra <atishp@rivosinc.com>
Reviewed-by: Andrew Jones <ajones@ventanamicro.com>
2023-02-09 22:30:06 +05:30
Anup Patel
0ee3a86fed 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 <apatel@ventanamicro.com>
Reviewed-by: Atish Patra <atishp@rivosinc.com>
Reviewed-by: Bin Meng <bmeng@tinylab.org>
Reviewed-by: Xiang W <wxjstz@126.com>
2023-02-09 22:29:24 +05:30
Anup Patel
e3bf1afcc5 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 <apatel@ventanamicro.com>
Reviewed-by: Andrew Jones <ajones@ventanamicro.com>
Reviewed-by: Atish Patra <atishp@rivosinc.com>
Reviewed-by: Bin Meng <bmeng@tinylab.org>
Reviewed-by: Xiang W <wxjstz@126.com>
2023-02-09 22:21:24 +05:30
Anup Patel
aa5dafcb5b 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: 09b34d8cca ("include: Add support for byteorder/endianness
conversion")
Reported-by: Samuel Holland <samuel@sholland.org>
Signed-off-by: Anup Patel <apatel@ventanamicro.com>
2023-02-09 09:31:10 +05:30
Rahul Pathak
b224ddb41f 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 <rpathak@ventanamicro.com>
Reviewed-by: Anup Patel <anup@brainfault.org>
2023-02-08 18:24:13 +05:30
Rahul Pathak
680bea02bf 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 <rpathak@ventanamicro.com>
Reviewed-by: Xiang W <wxjstz@126.com>
Reviewed-by: Anup Patel <anup@brainfault.org>
2023-02-08 18:17:42 +05:30
Rahul Pathak
09b34d8cca 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 <rpathak@ventanamicro.com>
Reviewed-by: Xiang W <wxjstz@126.com>
Reviewed-by: Sergey Matyukevich <sergey.matyukevich@syntacore.com>
Reviewed-by: Anup Patel <anup@brainfault.org>
2023-02-08 18:10:39 +05:30
Jessica Clarke
642f3de9b9 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 <ben.dooks@sifive.com>
Signed-off-by: Jessica Clarke <jrtc27@jrtc27.com>
Reviewed-by: Anup Patel <anup@brainfault.org>
2023-02-08 16:36:55 +05:30
Andrew Jones
66b0e23a0c 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 <ajones@ventanamicro.com>
Reviewed-by: Anup Patel <anup@brainfault.org>
2023-02-08 13:42:45 +05:30
Himanshu Chauhan
199189bd1c 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 <hchauhan@ventanamicro.com>
Reviewed-by: Anup Patel <anup@brainfault.org>
2023-02-08 11:13:19 +05:30
Nick Hu
84d15f4f52 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 <nick.hu@sifive.com>
Signed-off-by: Jim Shu <jim.shu@sifive.com>
Reviewed-by: Anup Patel <anup@brainfault.org>
2023-02-08 10:39:21 +05:30
Nick Hu
8050081f68 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 <nick.hu@sifive.com>
Signed-off-by: Jim Shu <jim.shu@sifive.com>
Reviewed-by: Anup Patel <anup@brainfault.org>
2023-02-08 10:39:20 +05:30
Jessica Clarke
c8ea836ee3 firmware: Fix fw_rw_offset computation in fw_base.S
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: c10e3fe5f9 ("firmware: Add RW section offset in scratch")
Signed-off-by: Jessica Clarke <jrtc27@jrtc27.com>
Reported-by: Lad Prabhakar <prabhakar.mahadev-lad.rj@bp.renesas.com>
Tested-by: Lad Prabhakar <prabhakar.mahadev-lad.rj@bp.renesas.com>
Tested-by: Anup Patel <apatel@ventanamicro.com>
Signed-off-by: Anup Patel <apatel@ventanamicro.com>
2023-01-27 08:39:49 +05:30
Samuel Holland
c45992cc2b 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 <anup@brainfault.org>
Signed-off-by: Samuel Holland <samuel@sholland.org>
2023-01-24 17:30:21 +05:30
Samuel Holland
33bf917460 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 <anup@brainfault.org>
Signed-off-by: Samuel Holland <samuel@sholland.org>
2023-01-24 17:30:21 +05:30
Lad Prabhakar
dea0922f86 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 <prabhakar.mahadev-lad.rj@bp.renesas.com>
Reviewed-by: Anup Patel <anup@brainfault.org>
2023-01-23 11:29:03 +05:30
Himanshu Chauhan
230278dcf1 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 <hchauhan@ventanamicro.com>
Reviewed-by: Anup Patel <anup@brainfault.org>
2023-01-23 10:34:18 +05:30
Himanshu Chauhan
b666760bfa 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 <hchauhan@ventanamicro.com>
Reviewed-by: Anup Patel <anup@brainfault.org>
2023-01-23 10:06:14 +05:30
Himanshu Chauhan
c10e3fe5f9 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 <hchauhan@ventanamicro.com>
Reviewed-by: Anup Patel <anup@brainfault.org>
2023-01-23 10:06:14 +05:30
Himanshu Chauhan
2f40a99c9e 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 <hchauhan@ventanamicro.com>
Reviewed-by: Anup Patel <anup@brainfault.org>
2023-01-23 10:06:14 +05:30
Himanshu Chauhan
fefa548803 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 <hchauhan@ventanamicro.com>
Reviewed-by: Anup Patel <anup@brainfault.org>
2023-01-23 10:06:14 +05:30
Mayuresh Chitale
a990309fa3 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 <mchitale@ventanamicro.com>
Reviewed-by: Anup Patel <anup@brainfault.org>
2023-01-22 17:49:10 +05:30
Yu Chien Peter Lin
7aaeeab9e7 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 <peterlin@andestech.com>
Reviewed-by: Anup Patel <anup@brainfault.org>
2023-01-22 17:33:13 +05:30
Yu Chien Peter Lin
787296ae92 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 <peterlin@andestech.com>
Reviewed-by: Anup Patel <anup@brainfault.org>
2023-01-22 17:33:03 +05:30
Yu Chien Peter Lin
9c4eb3521e 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 <peterlin@andestech.com>
Reviewed-by: Anup Patel <anup@brainfault.org>
2023-01-22 17:32:50 +05:30
Yu Chien Peter Lin
b1818ee244 include: types: add always inline compiler attribute
Provide __always_inline to sbi_types header.

Signed-off-by: Yu Chien Peter Lin <peterlin@andestech.com>
Reviewed-by: Anup Patel <anup@brainfault.org>
2023-01-22 17:32:35 +05:30
Yu Chien Peter Lin
8ecbe6d3fb 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 <peterlin@andestech.com>
Reviewed-by: Andrew Jones <ajones@ventanamicro.com>
Reviewed-by: Atish Patra <atishp@rivosinc.com>
Reviewed-by: Anup Patel <anup@brainfault.org>
2023-01-22 17:32:09 +05:30
Yu Chien Peter Lin
ce2a834c98 docs: generic.md: fix typo of andes-ae350
Fix hyperlink due to the typo.

Signed-off-by: Yu Chien Peter Lin <peterlin@andestech.com>
Reviewed-by: Anup Patel <anup@brainfault.org>
2023-01-22 17:31:54 +05:30
Samuel Holland
da5594bf85 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: 8509e46ca6 ("lib: utils/irqchip: plic: Ensure no out-of-bound access in priority save/restore helpers")
Fixes: 9a2eeb4aae ("lib: utils/irqchip: plic: Ensure no out-of-bound access in context save/restore helpers")
Signed-off-by: Samuel Holland <samuel@sholland.org>
Reviewed-by: Anup Patel <anup@brainfault.org>
2023-01-13 17:39:42 +05:30
Himanshu Chauhan
001106d19b 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 <hchauhan@ventanamicro.com>
Reviewed-by: Anup Patel <anup@brainfault.org>
Tested-by: Anup Patel <anup@brainfault.org>
2023-01-09 18:04:30 +05:30
Himanshu Chauhan
59a08cd7d6 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 <hchauhan@ventanamicro.com>
Reviewed-by: Anup Patel <anup@brainfault.org>
Tested-by: Anup Patel <anup@brainfault.org>
2023-01-09 18:04:28 +05:30
Himanshu Chauhan
3e2f573e70 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 <hchauhan@ventanamicro.com>
Reviewed-by: Anup Patel <anup@brainfault.org>
Tested-by: Anup Patel <anup@brainfault.org>
2023-01-09 18:04:25 +05:30
Himanshu Chauhan
20646e0184 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 <hchauhan@ventanamicro.com>
Reviewed-by: Anup Patel <anup@brainfault.org>
Tested-by: Anup Patel <anup@brainfault.org>
2023-01-09 18:04:23 +05:30
Himanshu Chauhan
44f736c96e 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 <hchauhan@ventanamicro.com>
Reviewed-by: Anup Patel <anup@brainfault.org>
Tested-by: Anup Patel <anup@brainfault.org>
2023-01-09 18:04:19 +05:30
Himanshu Chauhan
1ac14f10f6 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 <hchauhan@ventanamicro.com>
Reviewed-by: Anup Patel <anup@brainfault.org>
Tested-by: Anup Patel <anup@brainfault.org>
2023-01-09 18:04:17 +05:30
Himanshu Chauhan
22dbdb3d60 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 <hchauhan@ventanamicro.com>
Reviewed-by: Anup Patel <anup@brainfault.org>
Tested-by: Anup Patel <anup@brainfault.org>
2023-01-09 18:04:14 +05:30
Himanshu Chauhan
aace1e145d 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 <hchauhan@ventanamicro.com>
Reviewed-by: Anup Patel <anup@brainfault.org>
Tested-by: Anup Patel <anup@brainfault.org>
2023-01-09 18:04:12 +05:30
Himanshu Chauhan
9e0ba09076 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 <hchauhan@ventanamicro.com>
Reviewed-by: Anup Patel <anup@brainfault.org>
Tested-by: Anup Patel <anup@brainfault.org>
2023-01-09 18:04:10 +05:30
Bin Meng
9e397e3960 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 <bmeng@tinylab.org>
Reviewed-by: Atish Patra <atishp@rivosinc.com>
Reviewed-by: Anup Patel <anup@brainfault.org>
2023-01-09 16:54:29 +05:30
Bin Meng
6997552ea2 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 <bmeng@tinylab.org>
Reviewed-by: Samuel Holland <samuel@sholland.org>
Tested-by: Samuel Holland <samuel@sholland.org>
Reviewed-by: Atish Patra <atishp@rivosinc.com>
Reviewed-by: Anup Patel <anup@brainfault.org>
2023-01-09 16:52:34 +05:30
Wei Liang Lim
8020df8733 generic/starfive: Add Starfive JH7110 platform implementation
Add Starfive JH7110 platform implementation

Signed-off-by: Wei Liang Lim <weiliang.lim@starfivetech.com>
Reviewed-by: Chee Hong Ang <cheehong.ang@starfivetech.com>
Reviewed-by: Jun Liang Tan <junliang.tan@starfivetech.com>
Reviewed-by: Anup Patel <anup@brainfault.org>
2023-01-07 16:00:22 +05:30
Wei Liang Lim
cb7e7c3325 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 <weiliang.lim@starfivetech.com>
Reviewed-by: Chee Hong Ang <cheehong.ang@starfivetech.com>
Reviewed-by: Jun Liang Tan <junliang.tan@starfivetech.com>
Reviewed-by: Anup Patel <anup@brainfault.org>
2023-01-07 15:58:54 +05:30
Anup Patel
6957ae0e91 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 <apatel@ventanamicro.com>
2023-01-07 15:58:52 +05:30
Anup Patel
f14595a7cf 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 <apatel@ventanamicro.com>
2023-01-07 15:58:49 +05:30
Bin Meng
65638f8d6b lib: utils/sys: Allow custom HTIF base address for RV32
commit 6dde43584f ("lib: utils/sys: Extend HTIF library to allow custom base address")
forgot to update do_tohost_fromhost() codes for RV32, which still
accesses the HTIF registers using the ELF symbol address directly.

Fixes: 6dde43584f ("lib: utils/sys: Extend HTIF library to allow custom base address")
Signed-off-by: Bin Meng <bmeng@tinylab.org>
Tested-by: Daniel Henrique Barboza <dbarboza@ventanamicro.com>
Reviewed-by: Anup Patel <anup@brainfault.org>
2023-01-06 18:01:36 +05:30
Rahul Pathak
6509127ad6 Makefile: Remove -N ldflag to prevent linker RWX warning
-N option coalesce all sections into single LOAD segment which causes
data and other sections to have executable permission causing warning
with new binutils ld 2.39.
New ld emits warning when any segment have all three permissions RWX.

ld.bfd: warning: test.elf has a LOAD segment with RWX permissions
ld.bfd: warning: fw_dynamic.elf has a LOAD segment with RWX permissions
ld.bfd: warning: fw_jump.elf has a LOAD segment with RWX permissions
ld.bfd: warning: fw_payload.elf has a LOAD segment with RWX permissions

This option was added in below commit -
commit: eeab92f242 ("Makefile: Convert to a more standard format")

Removing -N option allows to have text and rodata into one LOAD
segment and other sections into separate LOAD segment which prevents
RWX permissions on single LOAD segment. Here X == E

Current
 LOAD           0x0000000000000120 0x0000000080000000 0x0000000080000000
                 0x000000000001d4d0 0x0000000000032ed8  RWE    0x10

-N removed
  LOAD           0x0000000000001000 0x0000000080000000 0x0000000080000000
                 0x00000000000198cc 0x00000000000198cc  R E    0x1000
  LOAD           0x000000000001b000 0x000000008001a000 0x000000008001a000
                 0x00000000000034d0 0x0000000000018ed8  RW     0x1000

Signed-off-by: Rahul Pathak <rpathak@ventanamicro.com>
Reviewed-by: Anup Patel <anup@brainfault.org>
Tested-by: Samuel Holland <samuel@sholland.org>
2023-01-06 17:51:15 +05:30
Bin Meng
440fa818fb treewide: Replace TRUE/FALSE with true/false
C language standard uses true/false for the boolean type.
Let's switch to that for better language compatibility.

Signed-off-by: Bin Meng <bmeng@tinylab.org>
Reviewed-by: Anup Patel <anup@brainfault.org>
Reviewed-by: Samuel Holland <samuel@sholland.org>
Tested-by: Samuel Holland <samuel@sholland.org>
2023-01-06 17:26:35 +05:30
Anup Patel
6b5188ca14 include: Bump-up version to 1.2
This patch updates OpenSBI version to 1.2 as part of
release preparation.

Signed-off-by: Anup Patel <apatel@ventanamicro.com>
2022-12-24 11:36:49 +05:30
Atish Patra
d5d12a91d1 docs: pmu: Update the pmu doc with removal of mcountinhbit restriction
Since commit b28f070, it is possible for platforms to run perf monitoring
even if mcountinhibit is not supported. Sampling still won't be possible
though as it requires sscofpmf extension.

Update the docs to remove the restriction.

Signed-off-by: Atish Patra <atishp@rivosinc.com>
Reviewed-by: Anup Patel <anup@brainfault.org>
2022-12-24 11:07:14 +05:30
Conor Dooley
0412460baf docs: pmu: update a reference to a deprecated property name
event-to-mhpmevent was deprecated and replaced by
riscv,event-to-mhpmevent, but a reference remains to the old name.
Replace it with the new one.

Signed-off-by: Conor Dooley <conor.dooley@microchip.com>
Reviewed-by: Atish Patra <atishp@rivosinc.com>
Reviewed-by: Anup Patel <anup@brainfault.org>
2022-12-24 11:06:04 +05:30
Conor Dooley
391ec85875 docs: pmu: fix binding example
The first PMU binding example does not terminate properties with a ;,
which is invalid. Noticed while converting the binding to yaml.

Signed-off-by: Conor Dooley <conor.dooley@microchip.com>
Reviewed-by: Bin Meng <bmeng@tinylab.org>
Reviewed-by: Anup Patel <anup@brainfault.org>
2022-12-24 11:05:09 +05:30
Icenowy Zheng
b848d8763a lib: utils/timer: mtimer: add T-Head C9xx CLINT compatible
As we already added the quirk for lacking mtime register to MTIMER
driver, add T-Head C9xx CLINT compatible to it and wire the quirk.

Signed-off-by: Icenowy Zheng <uwu@icenowy.me>
Reviewed-by: Anup Patel <anup@brainfault.org>
2022-12-17 11:01:06 +05:30
Icenowy Zheng
ca7810aecd lib: utils/timer: mtimer: add a quirk for lacking mtime register
T-Head developers surely have a different understanding of time CSR and
CLINT's mtime register with SiFive ones, that they did not implement
the mtime register at all -- as shown in openC906 source code, their
time CSR value is just exposed at the top of their processor IP block
and expects an external continous counter, which makes it not
overrideable, and thus mtime register is not implemented, even not for
reading. However, if CLINTEE is not enabled in T-Head's MXSTATUS
extended CSR, these systems still rely on the mtimecmp registers to
generate timer interrupts. This makes it necessary to implement T-Head
C9xx CLINT support in OpenSBI MTIMER driver, which skips implementing
reading mtime register and falls back to default code that reads time
CSR.

Add a quirk into MTIMER driver, which represents a mtime register is
lacking and time CSR value should be used instead.

Signed-off-by: Icenowy Zheng <uwu@icenowy.me>
Reviewed-by: Anup Patel <anup@brainfault.org>
2022-12-17 11:01:03 +05:30
Icenowy Zheng
a8ee82cd8c lib: utils/ipi: mswi: add T-Head C9xx CLINT compatible
Althoug the MTIMER part of a C9xx CLINT differs from a SiFive one, the
MSWI part is compliant.

Add T-Head C9xx CLINT compatible string to fdt_ipi_mswi code, sharing
the same codepath with SiFive CLINT.

Signed-off-by: Icenowy Zheng <uwu@icenowy.me>
Reviewed-by: Anup Patel <anup@brainfault.org>
2022-12-17 11:01:00 +05:30
Bin Meng
9a2eeb4aae lib: utils/irqchip: plic: Ensure no out-of-bound access in context save/restore helpers
Currently the context save/restore helpers writes/reads the provided
array using an index whose maximum value is determined by PLIC, which
potentially may disagree with the caller to these helpers.

Add a parameter to ask the caller to provide the size limit of the
array to ensure no out-of-bound access happens.

Signed-off-by: Bin Meng <bmeng@tinylab.org>
Reviewed-by: Anup Patel <anup@brainfault.org>
2022-12-17 09:03:30 +05:30
Bin Meng
fabbc00668 lib: utils/irqchip: plic: Fix the off-by-one error in context save/restore helpers
plic->num_src holds the number of interrupt sources without interrupt
source 0 but the interrupt enable register includes a bit for the
interrupt source 0 in the first word.

Fixes: 415ecf28f7 ("lib: irqchip/plic: Add context save/restore helpers")
Signed-off-by: Bin Meng <bmeng@tinylab.org>
Reviewed-by: Anup Patel <anup@brainfault.org>
Reviewed-by: Samuel Holland <samuel@sholland.org>
2022-12-17 09:02:40 +05:30
Bin Meng
91c8a7d5ce lib: utils/irqchip: plic: Fix the off-by-one error in plic_context_init()
The number of interrupt enable register in words was once correct,
but was wrongly changed to have an off-by-one error since
commit 8c362e7d06 ("lib: irqchip/plic: Factor out a context init function").

Fixes: 8c362e7d06 ("lib: irqchip/plic: Factor out a context init function")
Signed-off-by: Bin Meng <bmeng@tinylab.org>
Reviewed-by: Anup Patel <anup@brainfault.org>
Reviewed-by: Samuel Holland <samuel@sholland.org>
2022-12-17 09:00:35 +05:30
Bin Meng
8509e46ca6 lib: utils/irqchip: plic: Ensure no out-of-bound access in priority save/restore helpers
Currently the priority save/restore helpers writes/reads the provided
array using an index whose maximum value is determined by PLIC, which
potentially may disagree with the caller to these helpers.

Add a parameter to ask the caller to provide the size limit of the
array to ensure no out-of-bound access happens.

Signed-off-by: Bin Meng <bmeng@tinylab.org>
Reviewed-by: Anup Patel <anup@brainfault.org>
2022-12-17 09:00:29 +05:30
Bin Meng
34da6638ad lib: utils/irqchip: plic: Fix the off-by-one error in priority save/restore helpers
Interrupt source 0 is reserved. Hence the irq should start from 1.

Fixes: 2b79b694a8 ("lib: irqchip/plic: Add priority save/restore helpers")
Signed-off-by: Bin Meng <bmeng@tinylab.org>
Reviewed-by: Anup Patel <anup@brainfault.org>
2022-12-17 08:42:21 +05:30
Lad Prabhakar
7a3354ac15 docs: platform: Add documentation for Renesas RZ/Five SoC
This patch adds documentation to build Renesas RZ/Five (R9A07G043F) SoC.

Signed-off-by: Lad Prabhakar <prabhakar.mahadev-lad.rj@bp.renesas.com>
Reviewed-by: Anup Patel <anup@brainfault.org>
2022-12-12 18:51:10 +05:30
Lad Prabhakar
8b1617d13a platform: generic: Add Renesas RZ/Five initial support
This commit provides basic support for the Renesas RZ/Five
(R9A07G043F) SoC.

The RZ/Five microprocessor includes a single RISC-V CPU Core (Andes AX45MP)
1.0 GHz, 16-bit DDR3L/DDR4 interface. Supported interfaces include:
- Gigabit Ethernet 2ch
- CAN interface (CAN-FD) 2ch
- USB 2.0 interface 2ch
- SD interface 2ch
- AD converter 2ch

Useful links:
-------------
Links: https://www.renesas.com/us/en/products/microcontrollers-microprocessors/rz-mpus/rzfive-risc-v-general-purpose-microprocessors-risc-v-cpu-core-andes-ax45mp-single-10-ghz-2ch-gigabit-ethernet
Links: http://www.andestech.com/en/products-solutions/andescore-processors/riscv-ax45mp/

Signed-off-by: Lad Prabhakar <prabhakar.mahadev-lad.rj@bp.renesas.com>
Reviewed-by: Anup Patel <anup@brainfault.org>
2022-12-12 18:50:56 +05:30
Lad Prabhakar
684090272a lib: utils/irqchip: Add compatible string for Andestech NCEPLIC100
Add compatible string for Andestech NCEPLIC100 found on Renesas RZ/Five SoC
which is equipped with AX45MP AndesCore.

While at it drop the comma after the sentinel as it does not make sense to
have a comma after a sentinel, as any new elements must be added before the
sentinel.

dts example (Single-core AX45MP):

    soc: soc {
          ....
          plic: interrupt-controller@12c00000 {
              compatible = "renesas,r9a07g043-plic", "andestech,nceplic100";
              #interrupt-cells = <2>;
              #address-cells = <0>;
              riscv,ndev = <511>;
              interrupt-controller;
              reg = <0x0 0x12c00000 0 0x400000>;
              clocks = <&cpg CPG_MOD R9A07G043_NCEPLIC_ACLK>;
              power-domains = <&cpg>;
              resets = <&cpg R9A07G043_NCEPLIC_ARESETN>;
              interrupts-extended = <&cpu0_intc 11 &cpu0_intc 9>;
          };
          ....
    };

Signed-off-by: Lad Prabhakar <prabhakar.mahadev-lad.rj@bp.renesas.com>
Reviewed-by: Anup Patel <anup@brainfault.org>
Reviewed-by: Bin Meng <bmeng@tinylab.org>
2022-12-12 18:50:46 +05:30
Lad Prabhakar
0021b43737 lib: utils: serial: Add FDT driver for Renesas SCIF
Add FDT driver for Renesas SCIF.

    dts example:

    soc: soc {
          ....
            scif0: serial@1004b800 {
                    compatible = "renesas,scif-r9a07g043",
                                 "renesas,scif-r9a07g044";
                    reg = <0 0x1004b800 0 0x400>;
                    interrupts = <412 IRQ_TYPE_LEVEL_HIGH>,
                                 <414 IRQ_TYPE_LEVEL_HIGH>,
                                 <415 IRQ_TYPE_LEVEL_HIGH>,
                                 <413 IRQ_TYPE_LEVEL_HIGH>,
                                 <416 IRQ_TYPE_LEVEL_HIGH>,
                                 <416 IRQ_TYPE_LEVEL_HIGH>;
                    interrupt-names = "eri", "rxi", "txi",
                                      "bri", "dri", "tei";
                    clocks = <&cpg CPG_MOD R9A07G043_SCIF0_CLK_PCK>;
                    clock-names = "fck";
                    power-domains = <&cpg>;
                    resets = <&cpg R9A07G043_SCIF0_RST_SYSTEM_N>;
                    status = "disabled";
            };
          ....
    };

Signed-off-by: Lad Prabhakar <prabhakar.mahadev-lad.rj@bp.renesas.com>
Reviewed-by: Anup Patel <anup@brainfault.org>
2022-12-12 18:50:35 +05:30
Lad Prabhakar
64e8b9f72e lib: utils: serial: Add Renesas SCIF driver
Add Renesas SCIF driver.

Based on a patch in the BSP by Takeki Hamada
<takeki.hamada.ak@bp.renesas.com>
Link: https://github.com/renesas-rz/rz_opensbi/commits/work/OpenSBI-PMA

Signed-off-by: Lad Prabhakar <prabhakar.mahadev-lad.rj@bp.renesas.com>
Reviewed-by: Anup Patel <anup@brainfault.org>
2022-12-12 18:50:26 +05:30
Himanshu Chauhan
506928a1be scripts: use env to invoke bash
Not all systems have bash at a fixed location like /bin/bash.
FreeBSD, for example, would typically have it at /usr/local/bin/bash.
When building OpenSBI on freebsd system, the build breaks.

Its advisable to use: #!/usr/bin/env bash

Signed-off-by: Himanshu Chauhan <hchauhan@ventanamicro.com>
Reviewed-by: Xiang W <wxjstz@126.com>
Reviewed-by: Anup Patel <anup@brainfault.org>
2022-12-10 22:00:27 +05:30
Himanshu Chauhan
cb568b9b29 lib: sbi: Synchronize PMP settings with virtual memory system
As per section 3.7.2 of RISC-V Privileged Specification,
PMP settings must be synchronized with the virtual memory
system after PMP settings have been written.

Signed-off-by: Himanshu Chauhan <hchauhan@ventanamicro.com>
Reviewed-by: Anup Patel <anup@brainfault.org>
2022-12-09 14:17:56 +05:30
Heinrich Schuchardt
7b087781c2 lib: fix irqchip_plic_update_hartid_table
After determining cpu_offset we have to check this value.

Addresses-Coverity-ID: 1529706 ("Logically dead code")
Signed-off-by: Heinrich Schuchardt <heinrich.schuchardt@canonical.com>
Reviewed-by: Xiang W <wxjstz@126.com>
Reviewed-by: Atish Patra <atishp@rivosinc.com>
Reviewed-by: Anup Patel <anup@brainfault.org>
2022-12-09 11:27:28 +05:30
Heinrich Schuchardt
c2be21432c lib: fix __fdt_parse_region()
If fdt_getprop() returns NULL, this indicates an error. In this case lenp
is set to an error code. But even if lenp = 0 we should not continue.

If fdt_getprop() returns a wider value than we expect this is a separate
error condition.

In both cases the device-tree is invalid.

Addresses-Coverity-ID: 1529703 ("Dereference after null check")
Signed-off-by: Heinrich Schuchardt <heinrich.schuchardt@canonical.com>
Reviewed-by: Xiang W <wxjstz@126.com>
Reviewed-by: Anup Patel <anup@brainfault.org>
2022-12-09 11:26:39 +05:30
Heinrich Schuchardt
8b00be6927 lib: fix is_region_valid()
For 'reg->order == __riscv_xlen' the term 'BIT(reg->order)' is undefined.

Addresses-Coverity-ID: 1529706 ("Bad bit shift operation")
Signed-off-by: Heinrich Schuchardt <heinrich.schuchardt@canonical.com>
Reviewed-by: Xiang W <wxjstz@126.com>
Reviewed-by: Anup Patel <anup@brainfault.org>
2022-12-09 11:25:27 +05:30
Lad Prabhakar
ed8b8f5254 platform: generic: Make use of fdt_match_node()
It makes sense to use fdt_match_node() instead of fdt_find_match()
in fw_platform_lookup_special() as we already have the start offset
to search from.

Signed-off-by: Lad Prabhakar <prabhakar.mahadev-lad.rj@bp.renesas.com>
Reviewed-by: Anup Patel <anup@brainfault.org>
2022-12-09 11:13:00 +05:30
Sergey Matyukevich
e1a0cb062a gitignore: add vim swap files
Update .gitignore for vim swap files.

Signed-off-by: Sergey Matyukevich <sergey.matyukevich@syntacore.com>
Reviewed-by: Bin Meng <bmeng@tinylab.org>
Reviewed-by: Xiang W <wxjstz@126.com>
Reviewed-by: Anup Patel <anup@brainfault.org>
2022-12-05 17:57:30 +05:30
Lad Prabhakar
e9775120f5 lib: utils: Add fdt_fixup_node() helper function
Add a helper function fdt_fixup_node() based on the compatible string.
This will avoid code duplication for every new node fixup being added.

Signed-off-by: Lad Prabhakar <prabhakar.mahadev-lad.rj@bp.renesas.com>
Reviewed-by: Bin Meng <bmeng@tinylab.org>
Reviewed-by: Xiang W <wxjstz@126.com>
Reviewed-by: Anup Patel <anup@brainfault.org>
2022-12-05 17:54:45 +05:30
Yu Chien Peter Lin
4640d041d3 scripts/create-binary-archive.sh: remove andes/ae350 build directory
The andes-specific files have been moved to generic platform so we
can drop this line.

Signed-off-by: Yu Chien Peter Lin <peterlin@andestech.com>
Reviewed-by: Bin Meng <bmeng@tinylab.org>
Reviewed-by: Anup Patel <anup@brainfault.org>
2022-12-05 17:33:03 +05:30
Yu Chien Peter Lin
d3fcff77a1 docs: andes-ae350.md: fix watchdog nodename in dts example
The example should use watchdog as nodename instead of wdt.
This is defined in watchdog common schemas:
https://github.com/torvalds/linux/blob/v6.0/Documentation/devicetree/bindings/watchdog/watchdog.yaml#L19

Signed-off-by: Yu Chien Peter Lin <peterlin@andestech.com>
Reviewed-by: Bin Meng <bmeng@tinylab.org>
Reviewed-by: Anup Patel <anup@brainfault.org>
2022-12-05 17:32:16 +05:30
Yu Chien Peter Lin
6cd4b9b223 docs: platform: Update AE350 and generic platform documentation
Update compile option and platform compatible string for AE350 and
add it to the generic platform list.

Signed-off-by: Yu Chien Peter Lin <peterlin@andestech.com>
Reviewed-by: Bin Meng <bmeng@tinylab.org>
Reviewed-by: Anup Patel <anup@brainfault.org>
2022-12-05 17:30:55 +05:30
Yu Chien Peter Lin
a36d455182 platform: generic/andes: Enable generic platform support for AE350
We move andes directory to platform/generic as the necessary fdt
drivers are available, the users can enable the console, timer, ipi,
irqchip and reset devices by adding device tree nodes stated in the
docs/platform/andes-ae350.md.

Signed-off-by: Yu Chien Peter Lin <peterlin@andestech.com>
Reviewed-by: Bin Meng <bmeng@tinylab.org>
Reviewed-by: Anup Patel <anup@brainfault.org>
2022-12-05 17:24:32 +05:30
Dongdong Zhang
cfbabb9ec6 firmware: Minor optimization for relocate
The t3 register stores the address of _load_end. If relocation is not
required, it is unnecessary to calculate the address of _load_end.

This can reduce the operation time of two instructions.

Signed-off-by: Dongdong Zhang <zhangdongdong@eswincomputing.com>
Reviewed-by: Bin Meng <bmeng@tinylab.org>
Reviewed-by: Anup Patel <anup@brainfault.org>
2022-12-05 10:47:38 +05:30
Heinrich Schuchardt
ad2ac29263 lib: fix fdt_parse_aclint_node()
After determining cpu_offset we have to check this variable and not
cpu_intc_offset.

Signed-off-by: Heinrich Schuchardt <heinrich.schuchardt@canonical.com>
Reviewed-by: Xiang W <wxjstz@126.com>
Reviewed-by: Bin Meng <bmeng@tinylab.org>
2022-12-05 10:37:38 +05:30
Heinrich Schuchardt
1f6866e015 lib: simplify fdt_translate_address()
Don't assign a value to offset which is never used.

Signed-off-by: Heinrich Schuchardt <heinrich.schuchardt@canonical.com>
Reviewed-by: Xiang W <wxjstz@126.com>
Reviewed-by: Bin Meng <bmeng@tinylab.org>
2022-12-05 10:36:41 +05:30
Heinrich Schuchardt
5daa0ef087 lib: fix fdt_parse_plicsw_node()
cpu_offset and cpu_intc_offset must be int to detect failed invocations of
fdt_node_offset_by_phandle() or fdt_parent_offset().

After determining cpu_offset we have to check this value and not
cpu_intc_offset.

Signed-off-by: Heinrich Schuchardt <heinrich.schuchardt@canonical.com>
Reviewed-by: Xiang W <wxjstz@126.com>
Reviewed-by: Yu Chien Peter Lin <peterlin@andestech.com>
Reviewed-by: Bin Meng <bmeng@tinylab.org>
2022-12-05 10:35:36 +05:30
Heinrich Schuchardt
e9bc7f1757 lib: fix fdt_parse_plmt_node()
cpu_offset, cpu_intc_offset must be int to discover failed invocations of
fdt_node_offset_by_phandle() or fdt_parent_offset().

After determining cpu_offset we have to check this value and not
cpu_intc_offset.

Signed-off-by: Heinrich Schuchardt <heinrich.schuchardt@canonical.com>
Reviewed-by: Xiang W <wxjstz@126.com>
Reviewed-by: Yu Chien Peter Lin <peterlin@andestech.com>
Reviewed-by: Bin Meng <bmeng@tinylab.org>
2022-12-05 10:33:42 +05:30
Heinrich Schuchardt
cc54184619 lib: simplify fdt_parse_plicsw_node()
We should not check !plicsw_base || !size twice.

Signed-off-by: Heinrich Schuchardt <heinrich.schuchardt@canonical.com>
Reviewed-by: Xiang W <wxjstz@126.com>
Reviewed-by: Yu Chien Peter Lin <peterlin@andestech.com>
Reviewed-by: Bin Meng <bmeng@tinylab.org>
2022-12-05 10:31:01 +05:30
Heinrich Schuchardt
f8eec91de8 lib: simplify fdt_parse_plmt_node()
We should not check !plmt_base || !plmt_size twice.

Signed-off-by: Heinrich Schuchardt <heinrich.schuchardt@canonical.com>
Reviewed-by: Xiang W <wxjstz@126.com>
Reviewed-by: Yu Chien Peter Lin <peterlin@andestech.com>
Reviewed-by: Bin Meng <bmeng@tinylab.org>
2022-12-05 10:10:48 +05:30
Xiang W
fc82e84329 lib: sbi: Fix is_region_valid()
When order is equal to __riscv_xlen, the shift operation will not perform
any operation, which will cause reg->base & (BIT(reg->order) - 1) to always
be 0, and the condition has not been established.

This patch fixes this bug.

Signed-off-by: Xiang W <wxjstz@126.com>
Reviewed-by: Anup Patel <anup@brainfault.org>
2022-12-04 21:52:52 +05:30
Xiang W
74e20293c4 lib: sbi: Simplified mmio match checking
We simplify the mmio flag matching in sbi_domain_check_addr().

Signed-off-by: Xiang W <wxjstz@126.com>
Reviewed-by: Anup Patel <anup@brainfault.org>
2022-12-04 21:16:45 +05:30
Alejandro Cabrera Aldaya
49b0e355e6 Makefile: bugfix for handling platform paths
If the path where this repo is located contains the platform name on
it, the original Makefile replaced its occurrences from the path making
it an invalid path. This commit prevents this behavior replacing only
the last part of the path as intended.

Signed-off-by: Alejandro Cabrera Aldaya <aldaya@gmail.com>
Reviewed-by: Xiang W <wxjstz@126.com>
Reviewed-by: Andrew Jones <ajones@ventanamicro.com>
Reviewed-by: Anup Patel <anup@brainfault.org>
2022-12-04 21:02:33 +05:30
KaDiWa
ba32021683 Makefile: replace echo with printf for compatibility
I don't know why but `echo -n` didn't work for me. macOS supports
the `-n` option but it doesn't work in the makefile. What it does
instead is it literally writes `-n` to the file and then also
leaves a newline at the end.

I'm using GNU Make 4.4 (`gmake` from Homebrew).

Signed-off-by: KaDiWa <kalle.wachsmuth@gmail.com>
Reviewed-by: Andrew Jones <ajones@ventanamicro.com>
Reviewed-by: Anup Patel <anup@brainfault.org>
2022-12-04 20:41:30 +05:30
Xiang W
9a740f5c46 platform: generic/allwinner: Remove ghostly type cast
Corrected the same parameter of writel_relaxed in sun20i_d1_riscv_cfg_init
to be u32 for a while and u64 for a while.

Signed-off-by: Xiang W <wxjstz@126.com>
Reviewed-by: Anup Patel <anup@brainfault.org>
2022-12-04 20:38:46 +05:30
Leizheng Zhang
1b0d71bb9f platform: generic/allwinner: Remove unused header files
Remove "#include <sbi/sbi_console.h>"

Signed-off-by: Leizheng Zhang <zhangleizheng@eswincomputing.com>
Reviewed-by: Bin Meng <bmeng@tinylab.org>
Reviewed-by: Xiang W <wxjstz@126.com>
2022-11-22 11:46:19 +05:30
Leizheng Zhang
8e63716c1c firmware: payloads: Optimize usage of "ALIGN"
Delete the redundant "ALIGN" and adjust the position of "ALIGN"

Signed-off-by: Leizheng Zhang <zhangleizheng@eswincomputing.com>
Reviewed-by: Andrew Jones <ajones@ventanamicro.com>
Reviewed-by: Atish Patra <atishp@rivosinc.com>
Reviewed-by: Bin Meng <bmeng@tinylab.org>
2022-11-22 11:20:11 +05:30
Vivian Wang
14f5c4cb4d lib: sbi_ecall: Split up sbi_ecall_replace
Split up sbi_ecall_replace so that each extension is in its individual
file.

Also reorganize the corresponding section in lib/sbi/objects.mk so
that it is grouped by extension, now that the object file targets are
split up.

Signed-off-by: Vivian Wang <dramforever@live.com>
Reviewed-by: Anup Patel <anup@brainfault.org>
2022-11-15 16:44:03 +05:30
Anup Patel
7b29264f11 lib: utils/serial: Fix semihosting compile error using LLVM
We fix the following semihosting compile error observed using LLVM:
lib/utils/serial/semihosting.c:158:12: error: result of comparison of constant -1 with expression of type 'char' is always true [-Werror,-Wtautological-constant-out-of-range-compare]
                ret = ch > -1 ? ch : -1;
                      ~~ ^ ~~

Fixes: 7f09fba86e ("lib: utils/serial: add semihosting support")
Signed-off-by: Anup Patel <apatel@ventanamicro.com>
Reviewed-by: Xiang W <wxjstz@126.com>
Reviewed-by: Bin Meng <bmeng@tinylab.org>
2022-11-15 16:38:41 +05:30
zhangdongdong
8e9966c1a7 docs: fix some typos
Corrected the typos of some documents in the 'docs' folder.

Signed-off-by: zhangdongdong <zhangdongdong@eswincomputing.com>
Reviewed-by: Anup Patel <anup@brainfault.org>
2022-11-14 22:21:31 +05:30
Xiang W
21ba418f1a lib: utils/fdt: Simplified code
Simplified fdt_parse_xxx_uart_node which direct call
fdt_parse_uart_node_common.

Signed-off-by: Xiang W <wxjstz@126.com>
Reviewed-by: Atish Patra <atishp@rivosinc.com>
Reviewed-by: Anup Patel <anup@brainfault.org>
2022-11-14 22:07:36 +05:30
Xiang W
85cf56c159 lib: utils/fdt: Remove redundant code
uart->reg_offset and uart->reg_io_width are only used on uart8250 and
not required on other platforms. Remove for sifive and gaisler.

Signed-off-by: Xiang W <wxjstz@126.com>
Reviewed-by: Atish Patra <atishp@rivosinc.com>
Reviewed-by: Anup Patel <anup@brainfault.org>
2022-11-14 22:02:33 +05:30
Vivian Wang
22f38ee6c6 lib: sbi_ecall: Add Kconfig option for each extension
For each SBI extension, we:

- Add a Kconfig option for it
- Add the extension to sbi_ecall_exts only if the extension is enabled
- Add the corresponding sbi_ecall_* object file only if the extension is
  enabled

Special cases are as follows:

- The legacy extensions are lumped together as one 'big' extension, as
  has always been the case in OpenSBI code.
- The platform-defined vendor extensions are regarded as one extension.
- The Base extension cannot be disabled.
- sbi_ecall_replace implements multiple extensions, so it's not easy to
  avoid linking it in. Enable it always, and use #ifdef to
  disable/enable individual extensions.

Signed-off-by: Vivian Wang <dramforever@live.com>
Reviewed-by: Andrew Jones <ajones@ventanamicro.com>
Reviewed-by: Anup Patel <anup@brainfault.org>
2022-10-23 11:01:33 +05:30
Vivian Wang
56bed1a0fe lib: sbi_ecall: Generate extensions list with carray
Instead of hard-coding the list of extensions in C code, use carray to
generate the list of extensions.

Using carray makes adding and removing extensions slightly cleaner. This
also paves the way for using Kconfig to disable unneeded extensions.

Signed-off-by: Vivian Wang <dramforever@live.com>
Reviewed-by: Andrew Jones <ajones@ventanamicro.com>
Reviewed-by: Anup Patel <anup@brainfault.org>
2022-10-23 11:00:30 +05:30
Vivian Wang
9d54f431e8 Makefile: Add rules for carray sources in lib/sbi
Add back the missing rules needed to build carray files in lib/sbi. This
allows future usage of carray in lib/sbi.

Fixes: de80e9337d ("Makefile: Compile lib/utils sources separately for each platform")
Signed-off-by: Vivian Wang <dramforever@live.com>
Reviewed-by: Andrew Jones <ajones@ventanamicro.com>
Reviewed-by: Anup Patel <anup@brainfault.org>
2022-10-23 10:59:26 +05:30
Yangjie Zhang
51acd4956a docs/firmware: update the document
Since
commit 9c07c513aa ("firmware:Remove FW_PAYLOAD_FDT_PATH compile-time option"),
the section where FDT would be embedded in has changed from *.text* to *.rodata*,
but some places in fw_payload.md and fw.md are still *.text*.
This patch updates the document.

Signed-off-by: Yangjie Zhang <pyjmstr@gmail.com>
Reviewed-by: Bin Meng <bmeng.cn@gmail.com>
Reviewed-by: Anup Patel <anup@brainfault.org>
2022-10-23 10:49:39 +05:30
Tan En De
0fee0bf826 Makefile: Add cscope support
Add cscope support so that running `make cscope` will generate/update
cscope files used for source code browsing, while running `make
distclean` will remove the cscope files.

Also add entry in .gitignore to ignore generated cscope files.

Signed-off-by: Tan En De <ende.tan@linux.starfivetech.com>
Reviewed-by: Xiang W <wxjstz@126.com>
Reviewed-by: Anup Patel <anup@brainfault.org>
Reviewed-by: Andrew Jones <ajones@ventanamicro.com>
2022-10-23 10:47:40 +05:30
Yu Chien Peter Lin
d682a0afa1 docs: andes-ae350.md: Update ae350 documentation for fdt driver support
We update ae350 documentation to add details about platform device tree.
The nodes and their properties must be provided to properly initialize
data of underlying hardware and access their mmio registers.

Signed-off-by: Yu Chien Peter Lin <peterlin@andestech.com>
Reviewed-by: Anup Patel <anup@brainfault.org>
2022-10-23 10:35:45 +05:30
Yu Chien Peter Lin
c8683c57f6 platform: andes/ae350: Add AE350 domain support
Add domains_init platform hook for Andes AE350, users can add domain
description in device tree and select FDT domain support in Kconfig
to achieve system-level partitioning.

Signed-off-by: Yu Chien Peter Lin <peterlin@andestech.com>
Reviewed-by: Leo Yu-Chi Liang <ycliang@andestech.com>
Reviewed-by: Anup Patel <anup@brainfault.org>
2022-10-23 10:35:00 +05:30
Yu Chien Peter Lin
ce7c490719 lib: utils/ipi: Add Andes fdt ipi driver support
Move Andes PLICSW ipi device to fdt ipi framework, this patch is based
on Leo's modified IPI scheme on PLICSW.

Current IPI scheme uses bit 0 of pending reigster on PLICSW to send IPI
from hart 0 to hart 7, but bit 0 needs to be hardwired to 0 according
to spec. After some investigation, self-IPI seems to be seldom or never
used, so we re-order the IPI scheme to support 8 core platforms.

dts example (Quad-core AX45MP):

  plicsw: interrupt-controller@e6400000 {
          compatible = "andestech,plicsw";
          reg = <0x00000000 0xe6400000 0x00000000 0x00400000>;
          interrupts-extended = <&CPU0_intc 3
                                 &CPU1_intc 3
                                 &CPU2_intc 3
                                 &CPU3_intc 3>;
          interrupt-controller;
          #address-cells = <2>;
          #interrupt-cells = <2>;
  };

Signed-off-by: Yu Chien Peter Lin <peterlin@andestech.com>
Reviewed-by: Anup Patel <anup@brainfault.org>
2022-10-23 10:31:01 +05:30
Yu Chien Peter Lin
6f3258e671 platform: andes/ae350: Add fw_platform_init for platform initialization
This patch adds fw_platform_init() to initialize ae350 platform.name
and platform.hart_count by parsing device tree.

Signed-off-by: Yu Chien Peter Lin <peterlin@andestech.com>
Reviewed-by: Leo Yu-Chi Liang <ycliang@andestech.com>
Reviewed-by: Anup Patel <anup@brainfault.org>
2022-10-23 10:30:21 +05:30
Yu Chien Peter Lin
127a3f2ab4 platform: andes/ae350: Use fdt irqchip driver
Andes PLIC is compatible with plic driver. The PLIC base address and
number of source can be obtained by parsing the device tree.

Signed-off-by: Yu Chien Peter Lin <peterlin@andestech.com>
Reviewed-by: Leo Yu-Chi Liang <ycliang@andestech.com>
Reviewed-by: Anup Patel <anup@brainfault.org>
2022-10-23 10:29:58 +05:30
Yu Chien Peter Lin
8234fc1bdf lib: utils/reset: Add Andes fdt reset driver support
Add ATCWDT200 as reset device of AE350 platform, this driver requires
SMU to program the reset vector registers before triggering WDT software
restart signal.

dts example:

  smu@f0100000 {
    compatible = "andestech,atcsmu";
    reg = <0x00000000 0xf0100000 0x00000000 0x00001000>;
  };

  wdt: wdt@f0500000 {
    compatible = "andestech,atcwdt200";
    reg = <0x00000000 0xf0500000 0x00000000 0x00001000>;
    interrupts = <3 4>;
    interrupt-parent = <&plic0>;
    clock-frequency = <15000000>;
  };

Signed-off-by: Yu Chien Peter Lin <peterlin@andestech.com>
Reviewed-by: Leo Yu-Chi Liang <ycliang@andestech.com>
Reviewed-by: Anup Patel <anup@brainfault.org>
2022-10-23 10:29:23 +05:30
Yu Chien Peter Lin
ef9f02e7fb lib: utils/timer: Add Andes fdt timer support
Since we can get the PLMT base address and timer frequency from
device tree, move plmt timer device to fdt timer framework.

dts example (Quad-core AX45MP):

  cpus {
      ...
      timebase-frequency = <0x3938700>;
      ...
  }
  soc {
      ...
      plmt0@e6000000 {
          compatible = "andestech,plmt0";
          reg = <0x00 0xe6000000 0x00 0x100000>;
          interrupts-extended = <&cpu0_intc 0x07
                                 &cpu1_intc 0x07
                                 &cpu2_intc 0x07
                                 &cpu3_intc 0x07>;
      };
      ...
  }

Signed-off-by: Yu Chien Peter Lin <peterlin@andestech.com>
Reviewed-by: Anup Patel <anup@brainfault.org>
2022-10-23 10:26:39 +05:30
Yu Chien Peter Lin
88f58a3694 platform: andes/ae350: Use fdt serial driver
Andes UART is compatible with uart8250 driver. We can use
fdt_serial_init() as platform console init hook.

dts example:

  serial0: serial@f0300000 {
    compatible = "andestech,uart16550", "ns16550a";
    reg = <0x00000000 0xf0300000 0x00000000 0x00001000>;
    interrupts = <9 4>;
    interrupt-parent = <&plic0>;
    clock-frequency = <19660800>;
    current-speed = <38400>;
    reg-shift = <2>;
    reg-offset = <32>;
    reg-io-width = <4>;
    no-loopback-test = <1>;
  };

Signed-off-by: Yu Chien Peter Lin <peterlin@andestech.com>
Reviewed-by: Anup Patel <anup@brainfault.org>
2022-10-23 10:26:06 +05:30
Yu Chien Peter Lin
9899b59beb platform: andes/ae350: Use kconfig to set platform version and default name
This patch makes andes platform name and version can be set in
menuconfig interface.

Signed-off-by: Yu Chien Peter Lin <peterlin@andestech.com>
Reviewed-by: Leo Yu-Chi Liang <ycliang@andestech.com>
Reviewed-by: Anup Patel <anup@brainfault.org>
2022-10-23 10:25:13 +05:30
Yu Chien Peter Lin
bd7ef41398 platform: andes/ae350: Remove enabling cache from an350_final_init
The boot-time cache operations have been handled by U-boot SPL, so we
can drop duplicate code.

Signed-off-by: Yu Chien Peter Lin <peterlin@andestech.com>
Reviewed-by: Leo Yu-Chi Liang <ycliang@andestech.com>
Reviewed-by: Anup Patel <anup@brainfault.org>
2022-10-23 10:23:13 +05:30
Yu Chien Peter Lin
dcdaf30274 lib: sbi: Add sbi_domain_root_add_memrange() API
This patch generalizes the logic to add a memory range with desired
alignment and flags of consecutive regions to the root domain.

Signed-off-by: Yu Chien Peter Lin <peterlin@andestech.com>
Reviewed-by: Anup Patel <anup@brainfault.org>
2022-10-23 10:21:21 +05:30
Yu Chien Peter Lin
60b78fee92 include: sbi: Fix grammar in comment
Fix minor grammar issue in function description.

Signed-off-by: Yu Chien Peter Lin <peterlin@andestech.com>
Reviewed-by: Anup Patel <anup@brainfault.org>
2022-10-23 10:20:04 +05:30
Yu Chien Peter Lin
11d14ae7f2 lib: sbi: Fix typo in comment
%s/is is/is

Signed-off-by: Yu Chien Peter Lin <peterlin@andestech.com>
Reviewed-by: Anup Patel <anup@brainfault.org>
2022-10-23 10:19:28 +05:30
Yu Chien Peter Lin
98aa12738d include: sbi: Fix typo in comment
%s/Priviledge/Privilege

Signed-off-by: Yu Chien Peter Lin <peterlin@andestech.com>
Reviewed-by: Anup Patel <anup@brainfault.org>
2022-10-23 10:17:22 +05:30
Heiko Stuebner
b6e520b2a8 platform: generic: allwinner: add support for c9xx pmu
With the T-HEAD C9XX cores being designed before or during ratification
of the SSCOFPMF extension, they implement a PMU extension that behaves
very similar but not equal to it by providing overflow interrupts though
in a slightly different registers format.

The sun20i-d1 is using this core. So implement the necessary overrides
to allow its pmu to be used via the standard sbi-pmu extension.

For now it's also the only soc using this core, so keep the additional
code in the d1-space for now.

Reviewed-by: Andrew Jones <ajones@ventanamicro.com>
Reviewed-by: Guo Ren <guoren@kernel.org>
Reviewed-by: Anup Patel <anup@brainfault.org>
Signed-off-by: Heiko Stuebner <heiko@sntech.de>
2022-10-13 09:52:09 +05:30
Heiko Stuebner
2f63f2465c platform: generic: add extensions_init handler and platform-override
Init of non-standard extensions is a platform-specific thing,
so allow generic platforms to do this via a platform-override.

Reviewed-by: Andrew Jones <ajones@ventanamicro.com>
Reviewed-by: Guo Ren <guoren@kernel.org>
Reviewed-by: Anup Patel <anup@brainfault.org>
Signed-off-by: Heiko Stuebner <heiko@sntech.de>
2022-10-13 09:52:06 +05:30
Heiko Stuebner
4f2acb53e2 lib: sbi_platform: expose hart_features to extension_init callback
The platform-specific extension_init callback is supposed to
set specific things for the platform opensbi is running on.

So it's also the right place to override specific hart_features
if needed - when it's know that autodetection has provided
wrong results for example.

Suggested-by: Atish Patra <atishp@atishpatra.org>
Reviewed-by: Andrew Jones <ajones@ventanamicro.com>
Reviewed-by: Guo Ren <guoren@kernel.org>
Reviewed-by: Anup Patel <anup@brainfault.org>
Signed-off-by: Heiko Stuebner <heiko@sntech.de>
2022-10-13 09:52:05 +05:30
Heiko Stuebner
c316fa38c2 lib: sbi_hart: move hart_features struct to a public location
Platforms may need to override auto-detected hart features
in their override functions. So move the hart_features
struct to the sbi_hart.h header allowing us to pass it over
to platform-handlers.

Suggested-by: Atish Patra <atishp@atishpatra.org>
Reviewed-by: Andrew Jones <ajones@ventanamicro.com>
Reviewed-by: Guo Ren <guoren@kernel.org>
Reviewed-by: Anup Patel <anup@brainfault.org>
Signed-off-by: Heiko Stuebner <heiko@sntech.de>
2022-10-13 09:52:03 +05:30
Heiko Stuebner
e54cb3298b lib: sbi_pmu: move pmu irq information into pmu itself
Don't spread checking for pmu extensions through the code
but instead introduce a sbi-pmu function that other code can
call to get the correct information about the existence of the
pmu interrupt.

Add a sbi_pmu_device override function to allow overridung this
bit as well if needed.

Reviewed-by: Atish Patra <atishp@rivosinc.com>
Reviewed-by: Andrew Jones <ajones@ventanamicro.com>
Reviewed-by: Guo Ren <guoren@kernel.org>
Reviewed-by: Anup Patel <anup@brainfault.org>
Signed-off-by: Heiko Stuebner <heiko@sntech.de>
2022-10-13 09:52:01 +05:30
zhangdongdong
3f3d401d2d docs: Fix some typos
We fix few typos in documentation.

Signed-off-by: zhangdongdong <zhangdongdong@eswincomputing.com>
Reviewed-by: Andrew Jones <ajones@ventanamicro.com>
Reviewed-by: Xiang W <wxjstz@126.com>
Reviewed-by: Anup Patel <anup@brainfault.org>
2022-10-13 09:28:54 +05:30
Nylon.Chen
7105c189f6 docs/firmware: Update FW_JUMP documentation
Add a tip for OpenSBI's FW_JUMP which helps
users avoid overwriting the kernel.

Signed-off-by: Nylon Chen <nylon.chen@sifive.com>
Reviewed-by: Andrew Jones <ajones@ventanamicro.com>
Reviewed-by: Anup Patel <anup@brainfault.org>
2022-10-13 09:25:15 +05:30
Kautuk Consul
7f09fba86e lib: utils/serial: add semihosting support
We add RISC-V semihosting based serial console for JTAG based early
debugging.

The RISC-V semihosting specification is available at:
https://github.com/riscv/riscv-semihosting-spec/blob/main/riscv-semihosting-spec.adoc

Signed-off-by: Anup Patel <apatel@ventanamicro.com>
Signed-off-by: Kautuk Consul <kconsul@ventanamicro.com>
Reviewed-by: Anup Patel <anup@brainfault.org>
2022-09-13 18:24:42 +05:30
Rahul Pathak
49372f2691 lib: sbi: Fix sbi_strnlen wrong count decrement
count(maxlen) should not be decremented here

Fixes: 1901e8a287 ("platform: Add minimal libc support.")
Signed-off-by: Rahul Pathak <rpathak@ventanamicro.com>
Reviewed-by: Anup Patel <anup@brainfault.org>
2022-09-13 17:17:10 +05:30
Anup Patel
8ce486a781 lib: utils/fdt: Fix DT parsing in fdt_pmu_setup()
This patch does following fixes in fdt_pmu_setup():
1) If any of the event mapping DT property is absent or too small
   then don't skip parsing of other DT properties.
2) Return failure if sbi_pmu_add_hw_event_counter_map() fails.
3) Return failure if sbi_pmu_add_raw_event_counter_map() fails.

Signed-off-by: Anup Patel <apatel@ventanamicro.com>
Reviewed-by: Andrew Jones <ajones@ventanamicro.com>
Reviewed-by: Atish Patra <atishp@rivosinc.com>
2022-09-13 17:15:58 +05:30
Vivian Wang
46e744ab67 lib: sbi_misaligned_ldst: Set GVA if not emulating
If a particular misaligned load or store cannot be emulated at all, for
the redirected trap, trap.gva is set to 0, but it should be the same as
mstatus[h].GVA of the original trap. Fix this so that if the trap is
destined for HS-mode, hstatus.GVA is then set correctly.

Fixes: 1c4ce74f51 ("lib: sbi: Set gva when creating sbi_trap_info")
Signed-off-by: Vivian Wang <dramforever@live.com>
Reviewed-by: Andrew Jones <ajones@ventanamicro.com>
Reviewed-by: Anup Patel <anup@brainfault.org>
2022-09-13 16:43:07 +05:30
Vivian Wang
37a0d83b6d lib: sbi_trap: Add helper to get GVA in sbi_trap_regs
The GVA bit is in mstatus on RV64, and in mstatush in RV32. Refactor
code handling this in sbi_trap_handler into a helper function to extract
GVA from sbi_trap_regs, so that future code accessing GVA can be
XLEN-agnostic.

Signed-off-by: Vivian Wang <dramforever@live.com>
Reviewed-by: Andrew Jones <ajones@ventanamicro.com>
Reviewed-by: Anup Patel <anup@brainfault.org>
2022-09-13 16:42:59 +05:30
Nikita Shubin
19664f6757 docs: pmu: extend bindings example for Unmatched
Extend example for Unmatched board to provide SBI PMU bindings
for generalized and cache event's where they are applicable.

Signed-off-by: Nikita Shubin <n.shubin@yadro.com>
Reviewed-by: Anup Patel <anup@brainfault.org>
2022-09-13 16:42:10 +05:30
Nikita Shubin
d32b0a92db docs: pmu: fix Unmatched example typo
bitmap for MHPMCOUNTERx should be 0x18 and not 0x0c, we check
against SBI_PMU_FIXED_CTR_MASK which assumes than first 3 bits are
dedicated to mcycle, mtime and minstret, u74 has 2 hardware counters.

Reported-by: Zhang Xin <zhangxin.xa@gmail.com>
Signed-off-by: Nikita Shubin <n.shubin@yadro.com>
Reviewed-by: Anup Patel <anup@brainfault.org>
2022-09-13 16:42:03 +05:30
Anup Patel
5019fd124b include: sbi: Reduce includes in sbi_pmu.h
The sbi_pmu.h should only include minimal required headers whereas
sbi_pmu.c should include all required headers.

Signed-off-by: Anup Patel <apatel@ventanamicro.com>
Reviewed-by: Andrew Jones <ajones@ventanamicro.com>
Reviewed-by: Atish Patra <atishp@rivosinc.com>
2022-09-01 16:53:28 +05:30
Anup Patel
ee69f8eeb3 lib: sbi: Print platform PMU device at boot-time
Let us print the platform PMU device name at the boot-time so that users
know whether the underlying platform has custom per-HART PMU operations.

Signed-off-by: Anup Patel <apatel@ventanamicro.com>
Reviewed-by: Andrew Jones <ajones@ventanamicro.com>
Reviewed-by: Atish Patra <atishp@rivosinc.com>
2022-09-01 16:53:25 +05:30
Anup Patel
d10c1f4acd lib: sbi_pmu: Add custom PMU device operations
We extend SBI PMU implementation to allow custom PMU device operations
which a platform can use for platform specific quirks.

The custom PMU device operations added by this patch include:
1) Operations to allow a platform implement custom firmware events.
   These custom firmware events can be SBI vendor extension related
   events or platform specific per-HART events are not possible to
   count through HPM CSRs.
2) Operations to allow a platform implement custom way for enabling
   (or disabling) an overflow interrupt (e.g. T-Head C9xx).

Signed-off-by: Anup Patel <apatel@ventanamicro.com>
Reviewed-by: Andrew Jones <ajones@ventanamicro.com>
Reviewed-by: Atish Patra <atishp@rivosinc.com>
2022-09-01 16:53:22 +05:30
Anup Patel
c9b388d578 lib: sbi_pmu: Simplify FW counters to reduce memory usage
Currently, we have 32 elements (i.e. SBI_PMU_FW_EVENT_MAX) array of
"struct sbi_pmu_fw_event" for each of 128 possible HARTs
(i.e. SBI_HARTMASK_MAX_BITS).

To reduce memory usage of OpenSBI, we update FW counter implementation
as follows:
1) Remove SBI_PMU_FW_EVENT_MAX
2) Remove "struct sbi_pmu_fw_event"
3) Create per-HART bitmap of XLEN bits to track FW counters
   which are started on each HART
4) Create per-HART uint64_t array to track values of FW
   counters on each HART.

Signed-off-by: Anup Patel <apatel@ventanamicro.com>
Reviewed-by: Andrew Jones <ajones@ventanamicro.com>
Reviewed-by: Atish Patra <atishp@rivosinc.com>
2022-09-01 16:53:20 +05:30
Anup Patel
e238459fab lib: sbi_pmu: Firmware counters are always 64 bits wide
As-per SBI specification, all firmware counters are always 64 bits
wide so let us update the SBI PMU implementation to reflect this fact.

Signed-off-by: Anup Patel <apatel@ventanamicro.com>
Reviewed-by: Andrew Jones <ajones@ventanamicro.com>
Reviewed-by: Atish Patra <atishp@rivosinc.com>
2022-09-01 16:53:18 +05:30
Anup Patel
1664d0efce lib: sbi_pmu: Replace sbi_pmu_ctr_read() with sbi_pmu_ctr_fw_read()
The "read a firmware counter" SBI call should only work for firmware
counters so let us replace sbi_pmu_ctr_read() with sbi_pmu_ctr_fw_read()
which works only on firmware counters.

Signed-off-by: Anup Patel <apatel@ventanamicro.com>
Reviewed-by: Andrew Jones <ajones@ventanamicro.com>
Reviewed-by: Atish Patra <atishp@rivosinc.com>
2022-09-01 16:53:16 +05:30
Anup Patel
a90cf6b186 lib: sbi_pmu: Remove "event_idx" member from struct sbi_pmu_fw_event
The "event_idx" member of struct sbi_pmu_fw_event is not used
anywhere so let us remove it.

Signed-off-by: Anup Patel <apatel@ventanamicro.com>
Reviewed-by: Andrew Jones <ajones@ventanamicro.com>
Reviewed-by: Atish Patra <atishp@rivosinc.com>
2022-09-01 16:53:14 +05:30
Rahul Pathak
622cc5f014 include: Remove sideleg and sedeleg
sideleg and sedeleg csrs are not part of riscv isa spec
anymore, these csrs were part of N extension which
is removed from the riscv isa specification.

These commits removed all traces of these csrs from
riscv spec (https://github.com/riscv/riscv-isa-manual) -

commit f8d27f805b65 ("Remove or downgrade more references to N extension (#674)")
commit b6cade07034d ("Remove N extension chapter for now")

Signed-off-by: Rahul Pathak <rpathak@ventanamicro.com>
Reviewed-by: Andrew Jones <ajones@ventanamicro.com>
Reviewed-by: Anup Patel <anup@brainfault.org>
2022-09-01 15:37:22 +05:30
Jun Liang Tan
cbaa9b0333 lib: utils: serial: Add Cadence UART driver
Add Cadence UART driver

Signed-off-by: Jun Liang Tan <junliang.tan@linux.starfivetech.com>
Signed-off-by: Wei Liang Lim <weiliang.lim@linux.starfivetech.com>
Reviewed-by: Andrew Jones <ajones@ventanamicro.com>
Reviewed-by: Anup Patel <anup@brainfault.org>
2022-08-23 08:40:17 +05:30
Anup Patel
adf44b51ba lib: sbi: Use the official extension name for AIA M-mode CSRs
The arch review of AIA spec is completed and we now have official
extension names for AIA: Smaia (M-mode AIA CSRs) and Ssaia (S-mode
AIA CSRs).

Refer, section 1.6 of the latest AIA v0.3.1 stable specification at
https://github.com/riscv/riscv-aia/releases/download/0.3.1-draft.32/riscv-interrupts-032.pdf)

Based on above, we update generic library to use "Smaia" extension
name for AIA M-mode CSRs.

Signed-off-by: Anup Patel <apatel@ventanamicro.com>
Reviewed-by: Andrew Jones <ajones@ventanamicro.com>
Reviewed-by: Atish Patra <atishp@rivosinc.com>
2022-08-22 09:01:33 +05:30
Rahul Pathak
111afc1230 lib: sbi_illegal_insn: Fix FENCE.TSO emulation infinite trap loop
In case of missing "FENCE.TSO" instruction implementation,
opensbi can emulate the "FENCE.TSO" with "FENCE RW,RW", but
mepc was not incremented to continue from the next instruction
causing infinite trap.

Fixes: cb8271c8 ("lib: sbi_illegal_insn: Add emulation for fence.tso")
Signed-off-by: Rahul Pathak <rpathak@ventanamicro.com>
Reviewed-by: Andrew Jones <ajones@ventanamicro.com>
Reviewed-by: Xiang W <wxjstz@126.com>
Reviewed-by: Samuel Holland <samuel@sholland.org>
2022-08-22 08:57:23 +05:30
Vivian Wang
a69eb6cc65 lib: sbi_trap: Set hstatus.GVA when going to HS-mode
The privileged spec specifies that on a trap to HS-mode, hstatus.GVA
should be set to 1 if stval is written with a guest virtual address, and
to 0 otherwise. Implement this by setting hstatus.GVA to trap->gva when
redirecting traps to HS-mode.

Signed-off-by: Vivian Wang <dramforever@live.com>
Reviewed-by: Andrew Jones <ajones@ventanamicro.com>
Reviewed-by: Anup Patel <anup@brainfault.org>
2022-08-22 08:50:23 +05:30
Vivian Wang
5a0ca098f1 lib: sbi_trap: Set hypervisor CSRs for HS-mode
The hypervisor CSRs hstatus, htval, htinst should always be set if the
trap is to be taken in HS-mode, regardless of which mode it came from.

Signed-off-by: Vivian Wang <dramforever@live.com>
Reviewed-by: Andrew Jones <ajones@ventanamicro.com>
Reviewed-by: Anup Patel <anup@brainfault.org>
2022-08-22 08:50:04 +05:30
Vivian Wang
1c4ce74f51 lib: sbi: Set gva when creating sbi_trap_info
In some cases the sbi_trap_info argument passed to sbi_trap_redirect is
created from scratch by filling its fields. Since we previously added a
gva field to struct sbi_trap_info, initialize gva in these cases also.

Suggested-by: Andrew Jones <ajones@ventanamicro.com>
Signed-off-by: Vivian Wang <dramforever@live.com>
Reviewed-by: Andrew Jones <ajones@ventanamicro.com>
Reviewed-by: Anup Patel <anup@brainfault.org>
2022-08-22 08:49:49 +05:30
Vivian Wang
1fbe7778c9 lib: sbi_trap: Save mstatus[h].GVA in trap->gva
The machine mode GVA field is available if the hypervisor extension is
implemented, and indicates if mtval is a guest virtual address. Add a
gva field to sbi_trap_info for this, and in __sbi_expected_trap_hext,
save mstatus[h].GVA to it, so that gva indicates if tval is a guest
virtual address. If the hypervisor extension is not implemented, always
set gva to 0.

Signed-off-by: Vivian Wang <dramforever@live.com>
Reviewed-by: Andrew Jones <ajones@ventanamicro.com>
Reviewed-by: Anup Patel <anup@brainfault.org>
2022-08-22 08:49:39 +05:30
Vivian Wang
9529e360df include: Add mstatus[h].GVA encodings
The machine mode GVA field is in mstatus for RV64 and mstatush for RV32,
and is available if the hypervisor extension is available. If an
exception occurs, we may need to redirect the trap to HS-mode, in which
case, hstatus.GVA should be set to same as the machine mode GVA bit.

Add MSTATUS_GVA for RV64, MSTATUSH_GVA for RV32, and their SHIFT
encodings. The SHIFT index is helpful in assembly code, since field
extraction can be implemented in only one register. In pseudocode:

- For RV32: gva = (mstatus >> MSTATUS_GVA_SHIFT) & 1;
- For RV64: gva = (mstatush >> MSTATUSH_GVA_SHIFT) & 1;

Signed-off-by: Vivian Wang <dramforever@live.com>
Reviewed-by: Andrew Jones <ajones@ventanamicro.com>
Reviewed-by: Anup Patel <anup@brainfault.org>
2022-08-22 08:49:29 +05:30
Anup Patel
a6a85579b6 Makefile: Fix typo related to object.mk
The "object.mk" name referred in top-level makefile should be
"objects.mk".

Signed-off-by: Anup Patel <apatel@ventanamicro.com>
Reviewed-by: Andrew Jones <ajones@ventanamicro.com>
Tested-by: Andrew Jones <ajones@ventanamicro.com>
Acked-by: Atish Patra <atishp@rivosinc.com>
Tested-by: Atish Patra <atishp@rivosinc.com>
2022-08-08 09:34:43 +05:30
Anup Patel
0723bab8fe docs: Update documentation for kconfig support
We update all documentation files to:
1) Remove references to platform specific config.mk file since it is
   has been removed.
2) Add details about platform specific configs/defconfig and Kconfig
   files mandatory for each platform.
3) Add required packages in top-level README.md
4) Fix typo releated to object.mk in docs/platform/platform.md

Signed-off-by: Anup Patel <apatel@ventanamicro.com>
Reviewed-by: Andrew Jones <ajones@ventanamicro.com>
Tested-by: Andrew Jones <ajones@ventanamicro.com>
Acked-by: Atish Patra <atishp@rivosinc.com>
Tested-by: Atish Patra <atishp@rivosinc.com>
2022-08-08 09:34:31 +05:30
Anup Patel
eccb9df5cf platform: Remove redundant config.mk from all platforms
The options defined in config.mk can be specified in objects.mk of each
platform so let us remove config.mk from all platforms.

Signed-off-by: Anup Patel <apatel@ventanamicro.com>
Tested-by: Andrew Jones <ajones@ventanamicro.com>
Acked-by: Atish Patra <atishp@rivosinc.com>
Tested-by: Atish Patra <atishp@rivosinc.com>
2022-08-08 09:34:25 +05:30
Anup Patel
bc317a378f platform: generic: Use kconfig to set platform version and default name
The generic platform version and default name should be set based
on kconfig options so that users can override it.

Signed-off-by: Anup Patel <apatel@ventanamicro.com>
Reviewed-by: Andrew Jones <ajones@ventanamicro.com>
Tested-by: Andrew Jones <ajones@ventanamicro.com>
Acked-by: Atish Patra <atishp@rivosinc.com>
Tested-by: Atish Patra <atishp@rivosinc.com>
2022-08-08 09:34:20 +05:30
Anup Patel
d514a8f0dc platform: generic: Use kconfig for enabling/disabling overrides
We update generic platform to use kconfig for enabling/disabling
platform overrides. We also enable all platform overrides in generic
platform defconfig.

Signed-off-by: Anup Patel <apatel@ventanamicro.com>
Tested-by: Andrew Jones <ajones@ventanamicro.com>
Acked-by: Atish Patra <atishp@rivosinc.com>
Tested-by: Atish Patra <atishp@rivosinc.com>
2022-08-08 09:34:14 +05:30
Anup Patel
68d7b85ec7 lib: utils/fdt: Use kconfig for enabling/disabling
We update FDT support makefile to use kconfig for enabling/disabling.
To avoid compilation errors, we also enable FDT for each platform.

Signed-off-by: Anup Patel <apatel@ventanamicro.com>
Tested-by: Andrew Jones <ajones@ventanamicro.com>
Acked-by: Atish Patra <atishp@rivosinc.com>
Tested-by: Atish Patra <atishp@rivosinc.com>
2022-08-08 09:34:08 +05:30
Anup Patel
5616aa4f4a lib: utils/gpio: Use kconfig for enabling/disabling drivers
We update gpio drivers makefile to use kconfig for enabling/disabling
drivers. To avoid compile errors, we also enable appropriate gpio
drivers for each platform.

Signed-off-by: Anup Patel <apatel@ventanamicro.com>
Tested-by: Andrew Jones <ajones@ventanamicro.com>
Acked-by: Atish Patra <atishp@rivosinc.com>
Tested-by: Atish Patra <atishp@rivosinc.com>
2022-08-08 09:34:02 +05:30
Anup Patel
b126ce4a8f lib: utils/i2c: Use kconfig for enabling/disabling drivers
We update i2c drivers makefile to use kconfig for enabling/disabling
drivers. To avoid compile errors, we also enable appropriate i2c
drivers for each platform.

Signed-off-by: Anup Patel <apatel@ventanamicro.com>
Tested-by: Andrew Jones <ajones@ventanamicro.com>
Acked-by: Atish Patra <atishp@rivosinc.com>
Tested-by: Atish Patra <atishp@rivosinc.com>
2022-08-08 09:33:57 +05:30
Anup Patel
0b1cf2f645 lib: utils/irqchip: Use kconfig for enabling/disabling drivers
We update irqchip drivers makefile to use kconfig for enabling/disabling
drivers. To avoid compile errors, we also enable appropriate irqchip
drivers for each platform.

Signed-off-by: Anup Patel <apatel@ventanamicro.com>
Tested-by: Andrew Jones <ajones@ventanamicro.com>
Acked-by: Atish Patra <atishp@rivosinc.com>
Tested-by: Atish Patra <atishp@rivosinc.com>
2022-08-08 09:33:52 +05:30
Anup Patel
76af9d40da lib: utils/ipi: Use kconfig for enabling/disabling drivers
We update ipi drivers makefile to use kconfig for enabling/disabling
drivers. To avoid compile errors, we also enable appropriate ipi
drivers for each platform.

Signed-off-by: Anup Patel <apatel@ventanamicro.com>
Tested-by: Andrew Jones <ajones@ventanamicro.com>
Acked-by: Atish Patra <atishp@rivosinc.com>
Tested-by: Atish Patra <atishp@rivosinc.com>
2022-08-08 09:33:45 +05:30
Anup Patel
013dbb3a60 lib: utils/timer: Use kconfig for enabling/disabling drivers
We update timer drivers makefile to use kconfig for enabling/disabling
drivers. To avoid compile errors, we also enable appropriate timer
drivers for each platform.

Signed-off-by: Anup Patel <apatel@ventanamicro.com>
Tested-by: Andrew Jones <ajones@ventanamicro.com>
Acked-by: Atish Patra <atishp@rivosinc.com>
Tested-by: Atish Patra <atishp@rivosinc.com>
2022-08-08 09:33:37 +05:30
Anup Patel
3e76a607b5 lib: utils/sys: Use kconfig for enabling/disabling drivers
We update system drivers makefile to use kconfig for enabling/disabling
drivers. To avoid compile errors, we also enable appropriate system
drivers for each platform.

Signed-off-by: Anup Patel <apatel@ventanamicro.com>
Tested-by: Andrew Jones <ajones@ventanamicro.com>
Acked-by: Atish Patra <atishp@rivosinc.com>
Tested-by: Atish Patra <atishp@rivosinc.com>
2022-08-08 09:33:31 +05:30
Anup Patel
2adc94b466 lib: utils/reset: Use kconfig for enabling/disabling drivers
We update reset drivers makefile to use kconfig for enabling/disabling
drivers. To avoid compile errors, we also enable appropriate reset
drivers for each platform.

Signed-off-by: Anup Patel <apatel@ventanamicro.com>
Tested-by: Andrew Jones <ajones@ventanamicro.com>
Acked-by: Atish Patra <atishp@rivosinc.com>
Tested-by: Atish Patra <atishp@rivosinc.com>
2022-08-08 09:33:26 +05:30
Anup Patel
26bbff5f76 lib: utils/serial: Use kconfig for enabling/disabling drivers
We update serial drivers makefile to use kconfig for enabling/disabling
drivers. To avoid compile errors, we also enable appropriate serial
drivers for each platform.

Signed-off-by: Anup Patel <apatel@ventanamicro.com>
Tested-by: Andrew Jones <ajones@ventanamicro.com>
Acked-by: Atish Patra <atishp@rivosinc.com>
Tested-by: Atish Patra <atishp@rivosinc.com>
2022-08-08 09:33:21 +05:30
Anup Patel
de80e9337d Makefile: Compile lib/utils sources separately for each platform
Currently, if same build directory is used to compile two different
platforms then lib/utils objects are shared for these platforms.

We will be having platform specific configs to enable/disable drivers
in lib/utils and select compile time options for lib/utils sources.
This means lib/utils sources will now be compiled in a platform
specific way.

To tackle above, we update top-level Makefile as follows:
1) Don't create libsbiutils.a anymore because this can't be shared
   between platforms.
2) Compile lib/utils sources separately for each platform.
3) Add comments showing which make rules are for lib/sbi, lib/utils,
   firmware, and platform sources.

Signed-off-by: Anup Patel <apatel@ventanamicro.com>
Tested-by: Andrew Jones <ajones@ventanamicro.com>
Acked-by: Atish Patra <atishp@rivosinc.com>
Tested-by: Atish Patra <atishp@rivosinc.com>
2022-08-08 09:33:14 +05:30
Anup Patel
662e631cce Makefile: Add initial kconfig support for each platform
We extend the top-level makefile to allow kconfig based configuration
for each platform where each platform has it's own set of configs with
"defconfig" being the default config.

Signed-off-by: Anup Patel <apatel@ventanamicro.com>
Tested-by: Andrew Jones <ajones@ventanamicro.com>
Acked-by: Atish Patra <atishp@rivosinc.com>
Tested-by: Atish Patra <atishp@rivosinc.com>
2022-08-08 09:33:09 +05:30
Anup Patel
422f0e0486 scripts: Add Kconfiglib v14.1.0 under scripts directory
We adopt Kconfiglib v14.1.0 sources under scripts directory so that
top-level OpenSBI makefile can directly use Kconfiglib scripts without
expecting users to install a particular version of Kconfiglib on their
build system.

Signed-off-by: Anup Patel <apatel@ventanamicro.com>
Tested-by: Andrew Jones <ajones@ventanamicro.com>
Acked-by: Atish Patra <atishp@rivosinc.com>
Tested-by: Atish Patra <atishp@rivosinc.com>
2022-08-08 09:33:03 +05:30
dramforever
b9edf49b67 lib: sbi: Fix printf handling of long long
Read long long arguments directly using va_arg. Remove original hack for
RV32 that read a long long arg as two long args.

This un-breaks the case on RV64 where e.g. the long long is followed by
an odd number of ints:

    sbi_printf("%d %lld", (int) 1, (long long) 2LL);

Also remove the acnt variable, which is now unused.

Signed-off-by: dramforever <dramforever@live.com>
Reviewed-by: Andrew Jones <ajones@ventanamicro.com>
Reviewed-by: Anup Patel <anup@brainfault.org>
2022-07-30 11:55:51 +05:30
Andrew Jones
f27203525a lib: utils/serial: Ensure baudrate is non-zero before using
RISC-V doesn't generate exceptions on divide-by-zero, but the result,
all bits set, is not likely what people expect either. In all cases
where we divide by baudrate there's a chance it's zero (when the DT
it came from is "bad"). To avoid difficult to debug situations, leave
baudrate dependent registers alone when baudrate is zero, as, also in
all cases, it appears we can skip initialization of those registers
and still [hopefully] have a functioning UART.

Signed-off-by: Andrew Jones <ajones@ventanamicro.com>
Reviewed-by: Anup Patel <anup@brainfault.org>
2022-07-30 11:39:42 +05:30
Andrew Jones
7198e1d06f lib: serial: Clean up coding style in sifive-uart.c
Signed-off-by: Andrew Jones <ajones@ventanamicro.com>
Reviewed-by: Xiang W <wxjstz@126.com>
Reviewed-by: Anup Patel <anup@brainfault.org>
2022-07-30 11:39:19 +05:30
Andrew Jones
7d28d3be50 lib: utils/serial: Initialize platform_uart_data to zero
While it doesn't look like there are any current cases of using
uninitialized data, let's zero all the UART data members to be
safe. Zero may not actually be better than a random number in
some cases, so all structure members should still be validated
before use, but at least zero is usually easier to debug than
some random stack garbage...

Signed-off-by: Andrew Jones <ajones@ventanamicro.com>
Reviewed-by: Anup Patel <anup@brainfault.org>
2022-07-30 11:39:10 +05:30
Andrew Jones
8e86b23db9 lib: utils/fdt: Factor out common uart node code
Factor out the common code used by the fdt UART node parsers,
allowing us to drop duplicate code.

Signed-off-by: Andrew Jones <ajones@ventanamicro.com>
Reviewed-by: Anup Patel <anup@brainfault.org>
2022-07-30 11:39:01 +05:30
Atish Patra
11c0008862 lib: sbi: Fix fw_event_map initialization
fw_event_map represents array of firmware events. It should initialized
for maximum number of firmware events not counters.

Reviewed-by: Andrew Jones <ajones@ventanamicro.com>
Signed-off-by: Atish Patra <atishp@rivosinc.com>
Reviewed-by: Anup Patel <anup@brainfault.org>
2022-07-30 11:28:36 +05:30
Atish Patra
860a376817 lib: sbi: Fix possible buffer overrun in counter validation
The active_events array is accessed with counter ID passed from the supervisor
software before the counter ID bound check. This may cause a buffer overrun
if a supervisor passes an invalid counter ID.

Fix this by moving the access part after the bound check.

Reported-by: Andrew Jones <ajones@ventanamicro.com>
Reviewed-by: Andrew Jones <ajones@ventanamicro.com>
Signed-off-by: Atish Patra <atishp@rivosinc.com>
Reviewed-by: Anup Patel <anup@brainfault.org>
2022-07-30 11:25:48 +05:30
Atish Patra
83db3af5f9 lib: sbi: Add the bound check for events during config match
Currently, there is no sanity check for firmware event code. We don't see
any issue as Linux kernel driver does a bound check on firmware events
already. However, OpenSBI can't assume sane supervisor mode software
always. Thus, an invalid event idx can cause a buffer overflow error.
For hardware events, the match will fail for invalid event code anyways.
However, a search is unecessary if event code is invalid.

Add a event ID validation function to solve the issue.

Signed-off-by: Atish Patra <atishp@rivosinc.com>
Reviewed-by: Andrew Jones <ajones@ventanamicro.com>
Reviewed-by: Anup Patel <anup@brainfault.org>
2022-07-30 11:22:50 +05:30
Atish Patra
1545afd342 lib: sbi: Fix counter index sanity check
The current implementation computes the possible counter range
by doing a left shift of counter base. However, this may overflow depending
on the counter base value. In case of overflow, the highest counter id
may be computed incorrectly. As per the SBI specification, the respective
function should return an error if any of the counter is not valid.

Fix the counter index check by avoiding left shifting while doing the
sanity checks. Without the shift, the implementation just iterates
over the counter mask and computes the correct counter index by adding
the base to it.

Reviewed-by: Andrew Jones <ajones@ventanamicro.com>
Signed-off-by: Atish Patra <atishp@rivosinc.com>
Reviewed-by: Anup Patel <anup@brainfault.org>
2022-07-30 11:09:18 +05:30
Andrew Jones
88b790f129 lib: sbi: Fix sbi_snprintf
printc would happily write to 'out' even when 'out_len' was zero,
potentially overflowing buffers. Rework printc to not do that and
also ensure the null byte is written at the last position when
necessary, as stated in the snprintf man page. Also, panic if
sprintf or snprintf are called with NULL output strings (except
the special case of snprintf having a NULL output string and
a zero output size, allowing it to be used to get the number of
characters that would have been written). Finally, rename a
goto label which clashed with 'out'.

Fixes: 9e8ff05cb6 ("Initial commit.")
Signed-off-by: Andrew Jones <ajones@ventanamicro.com>
Reviewed-by: Anup Patel <anup@brainfault.org>
2022-07-30 11:02:07 +05:30
Prasanna T
4e21ccacd1 lib: utils/serial: Update Shakti UART based on latest implementation
The age old version of Shakti UART was upgraded long back, but we missed
updating the driver in OpenSBI. The old version of UART is not supported
anymore, hence removed the inline comment which is also outdated now.

Signed-off-by: Prasanna T <ptprasanna@gmail.com>
Signed-off-by: Anup Patel <apatel@ventanamicro.com>
Reviewed-by: Xiang W <wxjstz@126.com>
2022-07-20 10:06:25 +05:30
gagachang
0374ccf3f1 lib: sbi_hart: Shorten the code to set MPV bit
MPV bit is set when the value of next_virt boolean variable equals
true. Since the value of next_virt is either 0 or 1, we can set
MPV bit without if-else logic.

Signed-off-by: Che-Chia Chang <alvinga@andestech.com>
Reviewed-by: Andrew Jones <ajones@ventanamicro.com>
Reviewed-by: Anup Patel <anup@brainfault.org>
2022-07-20 10:05:33 +05:30
Ben Dooks
caa5eeacac lib: sbi: add check for ipi device for hsm start
If the ecall SBI_EXT_HSM_HART_START is called it might try to wake the
secondary hart using sbi_ipi_raw_send() to send an IPI to the hart.
This can fail if there is no IPI device but no error is returned from
sbi_ipi_raw_send() so the ecall returns as if the action completed and
the caller continues without noticing (in the case of Linux it just hangs
waiting for the secondary hart to become active)

Fix this by changing sbi_ipi_raw_send() to return and error, and if an
error is returned, then return it via SBI_EXT_HSM_HART_START call.

Signed-off-by: Ben Dooks <ben.dooks@sifive.com>
Reviewed-by: Anup Patel <anup@brainfault.org>
2022-07-11 15:46:59 +05:30
Adnan Rahman Chowdhury
994c8cfb29 lib: sbi_timer: Added a conditional wait function which can timeout
Motivation: Suppose a peripheral needs to be configured to transmit
data. There is an SFR bit which indicates that the peripheral is ready
to transmit. The firmware should check the bit and will only transmit
data when the peripheral is ready. When the firmware starts polling the
SFR, the peripheral could be busy transmitting/receiving other data so
the firmware must wait till that completes. Assuming that there is no
other way, the firmware shouldn't wait indefinitely.

The function sbi_timer_waitms_until() will constantly check whether a
certain condition is satisfied, or timeout occurs. It can be used for
the cases when a timeout is required.

Signed-off-by: Adnan Rahman Chowdhury <adnan.chowdhury@sifive.com>
Reviewed-by: Xiang W <wxjstz@126.com>
Reviewed-by: Anup Patel <anup@brainfault.org>
2022-07-08 14:51:24 +05:30
248 changed files with 19774 additions and 2767 deletions

2
.gitignore vendored
View File

@@ -9,3 +9,5 @@ install/
# Development friendly files
tags
cscope*
*.swp

25
Kconfig Normal file
View File

@@ -0,0 +1,25 @@
# SPDX-License-Identifier: BSD-2-Clause
mainmenu "OpenSBI $(OPENSBI_PLATFORM) Configuration"
config OPENSBI_SRC_DIR
string
option env="OPENSBI_SRC_DIR"
config OPENSBI_PLATFORM
string
option env="OPENSBI_PLATFORM"
config OPENSBI_PLATFORM_SRC_DIR
string
option env="OPENSBI_PLATFORM_SRC_DIR"
menu "Platform Options"
source "$(OPENSBI_PLATFORM_SRC_DIR)/Kconfig"
endmenu
source "$(OPENSBI_SRC_DIR)/lib/sbi/Kconfig"
source "$(OPENSBI_SRC_DIR)/lib/utils/Kconfig"
source "$(OPENSBI_SRC_DIR)/firmware/Kconfig"

168
Makefile
View File

@@ -47,11 +47,14 @@ ifdef PLATFORM_DIR
platform_parent_dir=$(platform_dir_path)
else
PLATFORM=$(shell basename $(platform_dir_path))
platform_parent_dir=$(subst $(PLATFORM),,$(platform_dir_path))
platform_parent_dir=$(shell realpath ${platform_dir_path}/..)
endif
else
platform_parent_dir=$(src_dir)/platform
endif
ifndef PLATFORM_DEFCONFIG
PLATFORM_DEFCONFIG=defconfig
endif
# Check if verbosity is ON for build process
CMD_PREFIX_DEFAULT := @
@@ -70,6 +73,20 @@ export libsbi_dir=$(CURDIR)/lib/sbi
export libsbiutils_dir=$(CURDIR)/lib/utils
export firmware_dir=$(CURDIR)/firmware
# Setup variables for kconfig
ifdef PLATFORM
export PYTHONDONTWRITEBYTECODE=1
export KCONFIG_DIR=$(platform_build_dir)/kconfig
export KCONFIG_AUTOLIST=$(KCONFIG_DIR)/auto.list
export KCONFIG_AUTOHEADER=$(KCONFIG_DIR)/autoconf.h
export KCONFIG_AUTOCMD=$(KCONFIG_DIR)/auto.conf.cmd
export KCONFIG_CONFIG=$(KCONFIG_DIR)/.config
# Additional exports for include paths in Kconfig files
export OPENSBI_SRC_DIR=$(src_dir)
export OPENSBI_PLATFORM=$(PLATFORM)
export OPENSBI_PLATFORM_SRC_DIR=$(platform_src_dir)
endif
# Find library version
OPENSBI_VERSION_MAJOR=`grep "define OPENSBI_VERSION_MAJOR" $(include_dir)/sbi/sbi_version.h | sed 's/.*MAJOR.*\([0-9][0-9]*\)/\1/'`
OPENSBI_VERSION_MINOR=`grep "define OPENSBI_VERSION_MINOR" $(include_dir)/sbi/sbi_version.h | sed 's/.*MINOR.*\([0-9][0-9]*\)/\1/'`
@@ -183,12 +200,38 @@ libsbi-object-mks=$(shell if [ -d $(libsbi_dir) ]; then find $(libsbi_dir) -inam
libsbiutils-object-mks=$(shell if [ -d $(libsbiutils_dir) ]; then find $(libsbiutils_dir) -iname "objects.mk" | sort -r; fi)
firmware-object-mks=$(shell if [ -d $(firmware_dir) ]; then find $(firmware_dir) -iname "objects.mk" | sort -r; fi)
# Include platform specifig config.mk
# The "make all" rule should always be first rule
.PHONY: all
all:
# Include platform specific .config
ifdef PLATFORM
include $(platform_src_dir)/config.mk
.PHONY: menuconfig
menuconfig: $(platform_src_dir)/Kconfig $(src_dir)/Kconfig
$(CMD_PREFIX)mkdir -p $(KCONFIG_DIR)
$(CMD_PREFIX)$(src_dir)/scripts/Kconfiglib/menuconfig.py $(src_dir)/Kconfig
$(CMD_PREFIX)$(src_dir)/scripts/Kconfiglib/genconfig.py --header-path $(KCONFIG_AUTOHEADER) --sync-deps $(KCONFIG_DIR) --file-list $(KCONFIG_AUTOLIST) $(src_dir)/Kconfig
.PHONY: savedefconfig
savedefconfig: $(platform_src_dir)/Kconfig $(src_dir)/Kconfig
$(CMD_PREFIX)mkdir -p $(KCONFIG_DIR)
$(CMD_PREFIX)$(src_dir)/scripts/Kconfiglib/savedefconfig.py --kconfig $(src_dir)/Kconfig --out $(KCONFIG_DIR)/defconfig
$(KCONFIG_CONFIG): $(platform_src_dir)/configs/$(PLATFORM_DEFCONFIG) $(platform_src_dir)/Kconfig $(src_dir)/Kconfig
$(CMD_PREFIX)mkdir -p $(KCONFIG_DIR)
$(CMD_PREFIX)$(src_dir)/scripts/Kconfiglib/defconfig.py --kconfig $(src_dir)/Kconfig $(platform_src_dir)/configs/$(PLATFORM_DEFCONFIG)
$(CMD_PREFIX)$(src_dir)/scripts/Kconfiglib/genconfig.py --header-path $(KCONFIG_AUTOHEADER) --sync-deps $(KCONFIG_DIR) --file-list $(KCONFIG_AUTOLIST) $(src_dir)/Kconfig
$(KCONFIG_AUTOCMD): $(KCONFIG_CONFIG)
$(CMD_PREFIX)mkdir -p $(KCONFIG_DIR)
$(CMD_PREFIX)printf "%s: " $(KCONFIG_CONFIG) > $(KCONFIG_AUTOCMD)
$(CMD_PREFIX)cat $(KCONFIG_AUTOLIST) | tr '\n' ' ' >> $(KCONFIG_AUTOCMD)
include $(KCONFIG_CONFIG)
include $(KCONFIG_AUTOCMD)
endif
# Include all object.mk files
# Include all objects.mk files
ifdef PLATFORM
include $(platform-object-mks)
endif
@@ -198,8 +241,8 @@ include $(firmware-object-mks)
# Setup list of objects
libsbi-objs-path-y=$(foreach obj,$(libsbi-objs-y),$(build_dir)/lib/sbi/$(obj))
libsbiutils-objs-path-y=$(foreach obj,$(libsbiutils-objs-y),$(build_dir)/lib/utils/$(obj))
ifdef PLATFORM
libsbiutils-objs-path-y=$(foreach obj,$(libsbiutils-objs-y),$(platform_build_dir)/lib/utils/$(obj))
platform-objs-path-y=$(foreach obj,$(platform-objs-y),$(platform_build_dir)/$(obj))
firmware-bins-path-y=$(foreach bin,$(firmware-bins-y),$(platform_build_dir)/firmware/$(bin))
endif
@@ -211,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
@@ -280,11 +324,19 @@ ifeq ($(BUILD_INFO),y)
GENFLAGS += -DOPENSBI_BUILD_TIME_STAMP="\"$(OPENSBI_BUILD_TIME_STAMP)\""
GENFLAGS += -DOPENSBI_BUILD_COMPILER_VERSION="\"$(OPENSBI_BUILD_COMPILER_VERSION)\""
endif
ifdef PLATFORM
GENFLAGS += -include $(KCONFIG_AUTOHEADER)
endif
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)
@@ -323,7 +375,7 @@ ASFLAGS += $(firmware-asflags-y)
ARFLAGS = rcs
ELFFLAGS += $(USE_LD_FLAG)
ELFFLAGS += -Wl,--build-id=none -Wl,-N
ELFFLAGS += -Wl,--build-id=none
ELFFLAGS += $(platform-ldflags-y)
ELFFLAGS += $(firmware-ldflags-y)
@@ -349,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 \
@@ -361,12 +413,17 @@ 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) && \
$(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)
@@ -413,29 +470,33 @@ compile_gen_dep = $(CMD_PREFIX)mkdir -p `dirname $(1)`; \
echo "$(1:.dep=$(2)): $(3)" >> $(1)
targets-y = $(build_dir)/lib/libsbi.a
targets-y += $(build_dir)/lib/libsbiutils.a
ifdef PLATFORM
targets-y += $(platform_build_dir)/lib/libplatsbi.a
endif
targets-y += $(firmware-bins-path-y)
# Default rule "make" should always be first rule
# The default "make all" rule
.PHONY: all
all: $(targets-y)
# Preserve all intermediate files
.SECONDARY:
# Rules for lib/sbi sources
$(build_dir)/lib/libsbi.a: $(libsbi-objs-path-y)
$(call compile_ar,$@,$^)
$(build_dir)/lib/libsbiutils.a: $(libsbi-objs-path-y) $(libsbiutils-objs-path-y)
$(call compile_ar,$@,$^)
$(platform_build_dir)/lib/libplatsbi.a: $(libsbi-objs-path-y) $(libsbiutils-objs-path-y) $(platform-objs-path-y)
$(call compile_ar,$@,$^)
$(build_dir)/%.dep: $(src_dir)/%.c
$(build_dir)/%.dep: $(src_dir)/%.carray $(KCONFIG_CONFIG)
$(call compile_gen_dep,$@,.c,$< $(KCONFIG_CONFIG))
$(call compile_gen_dep,$@,.o,$(@:.dep=.c))
$(build_dir)/%.c: $(src_dir)/%.carray
$(call compile_carray,$@,$<)
$(build_dir)/%.dep: $(src_dir)/%.c $(KCONFIG_CONFIG)
$(call compile_cc_dep,$@,$<)
$(build_dir)/%.o: $(src_dir)/%.c
@@ -449,32 +510,24 @@ $(build_dir)/lib/sbi/sbi_init.o: $(libsbi_dir)/sbi_init.c FORCE
$(call compile_cc,$@,$<)
endif
$(build_dir)/%.dep: $(src_dir)/%.S
$(build_dir)/%.dep: $(src_dir)/%.S $(KCONFIG_CONFIG)
$(call compile_as_dep,$@,$<)
$(build_dir)/%.o: $(src_dir)/%.S
$(call compile_as,$@,$<)
$(build_dir)/%.dep: $(src_dir)/%.carray
$(call compile_gen_dep,$@,.c,$<)
# Rules for platform sources
$(platform_build_dir)/%.dep: $(platform_src_dir)/%.carray $(KCONFIG_CONFIG)
$(call compile_gen_dep,$@,.c,$< $(KCONFIG_CONFIG))
$(call compile_gen_dep,$@,.o,$(@:.dep=.c))
$(build_dir)/%.c: $(src_dir)/%.carray
$(platform_build_dir)/%.c: $(platform_src_dir)/%.carray
$(call compile_carray,$@,$<)
$(platform_build_dir)/%.bin: $(platform_build_dir)/%.elf
$(call compile_objcopy,$@,$<)
$(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)/%.ld: $(src_dir)/%.ldS
$(call compile_cpp,$@,$<)
$(platform_build_dir)/%.dep: $(platform_src_dir)/%.c
$(platform_build_dir)/%.dep: $(platform_src_dir)/%.c $(KCONFIG_CONFIG)
$(call compile_cc_dep,$@,$<)
$(platform_build_dir)/%.o: $(platform_src_dir)/%.c
$(platform_build_dir)/%.o: $(platform_src_dir)/%.c $(KCONFIG_CONFIG)
$(call compile_cc,$@,$<)
$(platform_build_dir)/%.dep: $(platform_src_dir)/%.S
@@ -483,8 +536,8 @@ $(platform_build_dir)/%.dep: $(platform_src_dir)/%.S
$(platform_build_dir)/%.o: $(platform_src_dir)/%.S
$(call compile_as,$@,$<)
$(platform_build_dir)/%.dep: $(platform_src_dir)/%.dts
$(call compile_gen_dep,$@,.dtb,$<)
$(platform_build_dir)/%.dep: $(platform_src_dir)/%.dts $(KCONFIG_CONFIG)
$(call compile_gen_dep,$@,.dtb,$< $(KCONFIG_CONFIG))
$(call compile_gen_dep,$@,.c,$(@:.dep=.dtb))
$(call compile_gen_dep,$@,.o,$(@:.dep=.c))
@@ -494,13 +547,33 @@ $(platform_build_dir)/%.c: $(platform_build_dir)/%.dtb
$(platform_build_dir)/%.dtb: $(platform_src_dir)/%.dts
$(call compile_dts,$@,$<)
$(platform_build_dir)/%.dep: $(src_dir)/%.c
# Rules for lib/utils and firmware sources
$(platform_build_dir)/%.bin: $(platform_build_dir)/%.elf
$(call compile_objcopy,$@,$<)
$(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,$@,$<)
$(platform_build_dir)/%.dep: $(src_dir)/%.carray $(KCONFIG_CONFIG)
$(call compile_gen_dep,$@,.c,$< $(KCONFIG_CONFIG))
$(call compile_gen_dep,$@,.o,$(@:.dep=.c))
$(platform_build_dir)/%.c: $(src_dir)/%.carray
$(call compile_carray,$@,$<)
$(platform_build_dir)/%.dep: $(src_dir)/%.c $(KCONFIG_CONFIG)
$(call compile_cc_dep,$@,$<)
$(platform_build_dir)/%.o: $(src_dir)/%.c
$(call compile_cc,$@,$<)
$(platform_build_dir)/%.dep: $(src_dir)/%.S
$(platform_build_dir)/%.dep: $(src_dir)/%.S $(KCONFIG_CONFIG)
$(call compile_as_dep,$@,$<)
$(platform_build_dir)/%.o: $(src_dir)/%.S
@@ -544,7 +617,6 @@ endif
endif
install_targets-y = install_libsbi
install_targets-y += install_libsbiutils
ifdef PLATFORM
install_targets-y += install_libplatsbi
install_targets-y += install_firmwares
@@ -559,17 +631,12 @@ install_libsbi: $(build_dir)/lib/libsbi.a
$(call inst_header_dir,$(install_root_dir)/$(install_include_path),$(include_dir)/sbi)
$(call inst_file,$(install_root_dir)/$(install_lib_path)/libsbi.a,$(build_dir)/lib/libsbi.a)
.PHONY: install_libsbiutils
install_libsbiutils: $(build_dir)/lib/libsbiutils.a
$(call inst_header_dir,$(install_root_dir)/$(install_include_path),$(include_dir)/sbi_utils)
$(call inst_file,$(install_root_dir)/$(install_lib_path)/libsbiutils.a,$(build_dir)/lib/libsbiutils.a)
.PHONY: install_libplatsbi
install_libplatsbi: $(platform_build_dir)/lib/libplatsbi.a $(build_dir)/lib/libsbi.a $(build_dir)/lib/libsbiutils.a
install_libplatsbi: $(platform_build_dir)/lib/libplatsbi.a $(build_dir)/lib/libsbi.a
$(call inst_file,$(install_root_dir)/$(install_lib_path)/opensbi/$(platform_subdir)/lib/libplatsbi.a,$(platform_build_dir)/lib/libplatsbi.a)
.PHONY: install_firmwares
install_firmwares: $(platform_build_dir)/lib/libplatsbi.a $(build_dir)/lib/libsbi.a $(build_dir)/lib/libsbiutils.a $(firmware-bins-path-y)
install_firmwares: $(platform_build_dir)/lib/libplatsbi.a $(build_dir)/lib/libsbi.a $(firmware-bins-path-y)
$(call inst_file_list,$(install_root_dir),$(build_dir),$(install_firmware_path)/$(platform_subdir)/firmware,$(firmware-elfs-path-y))
$(call inst_file_list,$(install_root_dir),$(build_dir),$(install_firmware_path)/$(platform_subdir)/firmware,$(firmware-bins-path-y))
@@ -577,6 +644,17 @@ install_firmwares: $(platform_build_dir)/lib/libplatsbi.a $(build_dir)/lib/libsb
install_docs: $(build_dir)/docs/latex/refman.pdf
$(call inst_file,$(install_root_dir)/$(install_docs_path)/refman.pdf,$(build_dir)/docs/latex/refman.pdf)
.PHONY: cscope
cscope:
$(CMD_PREFIX)find \
"$(src_dir)/firmware" \
"$(src_dir)/include" \
"$(src_dir)/lib" \
"$(platform_src_dir)" \
-name "*.[chS]" -print > cscope.files
$(CMD_PREFIX)echo "$(KCONFIG_AUTOHEADER)" >> cscope.files
$(CMD_PREFIX)cscope -bkq -i cscope.files -f cscope.out
# Rule for "make clean"
.PHONY: clean
clean:
@@ -606,6 +684,8 @@ ifeq ($(install_root_dir),$(install_root_dir_default)/usr)
$(if $(V), @echo " RM $(install_root_dir_default)")
$(CMD_PREFIX)rm -rf $(install_root_dir_default)
endif
$(if $(V), @echo " RM $(src_dir)/cscope*")
$(CMD_PREFIX)rm -f $(src_dir)/cscope*
.PHONY: FORCE
FORCE:

View File

@@ -1,11 +1,15 @@
RISC-V Open Source Supervisor Binary Interface (OpenSBI)
========================================================
![RISC-V OpenSBI](docs/riscv_opensbi_logo_final_color.png)
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*).
@@ -92,8 +96,8 @@ N.B. Any S-mode boot loader (i.e. U-Boot) doesn't need to support HSM extension,
as it doesn't need to boot all the harts. The operating system should be
capable enough to bring up all other non-booting harts using HSM extension.
Required Toolchain
------------------
Required Toolchain and Packages
-------------------------------
OpenSBI can be compiled natively or cross-compiled on a x86 host. For
cross-compilation, you can build your own toolchain, download a prebuilt one
@@ -115,6 +119,14 @@ triple is used (e.g. *-target riscv64-unknown-elf*).
Please note that only a 64-bit version of the toolchain is available in
the Bootlin toolchain repository for now.
In addition to a toolchain, OpenSBI also requires the following packages on
the host:
1. device-tree-compiler: The device tree compiler for compiling device
tree sources (DTS files).
2. python3: The python 3.0 (or compatible) language support for various
scripts.
Building and Installing the OpenSBI Platform-Independent Library
----------------------------------------------------------------
@@ -196,6 +208,19 @@ top-level make command line. These options, such as *PLATFORM_<xyz>* or
*docs/platform/<platform_name>.md* files and
*docs/firmware/<firmware_name>.md* files.
All OpenSBI platforms support Kconfig style build-time configuration. Users
can change the build-time configuration of a platform using a graphical
interface as follows:
```
make PLATFORM=<platform_subdir> menuconfig
```
Alternately, an OpenSBI platform can have multiple default configurations
and users can select a custom default configuration as follows:
```
make PLATFORM=<platform_subdir> PLATFORM_DEFCONFIG=<platform_custom_defconfig>
```
Building 32-bit / 64-bit OpenSBI Images
---------------------------------------
By default, building OpenSBI generates 32-bit or 64-bit images based on the
@@ -277,6 +302,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
-----------------------

View File

@@ -29,7 +29,7 @@ and "top:".
5. Maintainers should use "Rebase and Merge" when using GitHub to merge pull
requests to avoid creating unnecessary merge commits.
6. Maintainers should avoid creating branches directly in the main
riscv/opensbi repository. Instead prefer using a fork of the riscv/opensbi main
riscv/opensbi repository. Instead, prefer using a fork of the riscv/opensbi main
repository and branches within that fork to create pull requests.
7. A maintainer cannot merge his own pull requests in the riscv/opensbi main
repository.

View File

@@ -2,7 +2,7 @@ OpenSBI Domain Support
======================
An OpenSBI domain is a system-level partition (subset) of underlying hardware
having it's own memory regions (RAM and MMIO devices) and HARTs. The OpenSBI
having its own memory regions (RAM and MMIO devices) and HARTs. The OpenSBI
will try to achieve secure isolation between domains using RISC-V platform
features such as PMP, ePMP, IOPMP, SiFive Shield, etc.
@@ -15,7 +15,7 @@ Important entities which help implement OpenSBI domain support are:
Each HART of a RISC-V platform must have an OpenSBI domain assigned to it.
The OpenSBI platform support is responsible for populating domains and
providing HART id to domain mapping. The OpenSBI domain support will by
default assign **the ROOT domain** to all HARTs of a RISC-V platform so
default assign **the ROOT domain** to all HARTs of a RISC-V platform, so
it is not mandatory for the OpenSBI platform support to populate domains.
Domain Memory Region
@@ -29,7 +29,7 @@ OpenSBI and has following details:
* **base** - The base address of a memory region is **2 ^ order**
aligned start address
* **flags** - The flags of a memory region represent memory type (i.e.
RAM or MMIO) and allowed accesses (i.e. READ, WRITE, EXECUTE, etc)
RAM or MMIO) and allowed accesses (i.e. READ, WRITE, EXECUTE, etc.)
Domain Instance
---------------
@@ -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
--------------
@@ -124,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
@@ -160,8 +165,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
@@ -180,13 +193,15 @@ 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
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
@@ -195,9 +210,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
@@ -222,6 +237,7 @@ be done:
chosen {
opensbi-domains {
compatible = "opensbi,domain,config";
system-suspend-test;
tmem: tmem {
compatible = "opensbi,domain,memregion";
@@ -246,18 +262,19 @@ 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>;
next-mode = <0x0>;
system-reset-allowed;
system-suspend-allowed;
};
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>;
};
};
};

View File

@@ -53,7 +53,7 @@ the booting stage to follow OpenSBI firmware.
A *FW_PAYLOAD* firmware is also useful for cases where the booting stage prior
to OpenSBI firmware does not pass a *flattened device tree (FDT file)*. In such
case, a *FW_PAYLOAD* firmware allows embedding a flattened device tree in the
.text section of the final firmware.
.rodata section of the final firmware.
Firmware Configuration and Compilation
--------------------------------------
@@ -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

View File

@@ -20,7 +20,7 @@ the booting stage binary to follow OpenSBI firmware.
A platform can enable *FW_DYNAMIC* firmware using any of the following methods.
1. Specifying `FW_DYNAMIC=y` on the top level `make` command line.
2. Specifying `FW_DYNAMIC=y` in the target platform *config.mk* configuration
2. Specifying `FW_DYNAMIC=y` in the target platform *objects.mk* configuration
file.
The compiled *FW_DYNAMIC* firmware ELF file is named *fw_dynamic.elf*. It's
@@ -31,6 +31,6 @@ directory.
*FW_DYNAMIC* Firmware Configuration Options
-------------------------------------------
The *FW_DYNAMIC* firmware does not requires any platform specific configuration
The *FW_DYNAMIC* firmware does not require any platform specific configuration
parameters because all required information is passed by previous booting stage
at runtime via *struct fw_dynamic_info*.

View File

@@ -15,7 +15,7 @@ and the booting stage binary to follow the OpenSBI firmware.
A platform *FW_JUMP* firmware can be enabled by any of the following methods:
1. Specifying `FW_JUMP=y` on the top level `make` command line.
2. Specifying `FW_JUMP=y` in the target platform *config.mk* configuration file.
2. Specifying `FW_JUMP=y` in the target platform *objects.mk* configuration file.
The compiled *FW_JUMP* firmware ELF file is named *fw_jump.elf*. Its expanded
image file is *fw_jump.bin*. Both files are created in the platform-specific
@@ -26,7 +26,7 @@ build directory under the *build/platform/<platform_subdir>/firmware* directory.
To operate correctly, a *FW_JUMP* firmware requires some configuration
parameters to be defined using either the top level `make` command line or the
target platform *config.mk* configuration file. The possible parameters are as
target platform *objects.mk* configuration file. The possible parameters are as
follows:
* **FW_JUMP_ADDR** - Address of the entry point of the booting stage to be
@@ -41,6 +41,22 @@ follows:
provided, then the OpenSBI firmware will pass the FDT address passed by the
previous booting stage to the next booting stage.
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 (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` > (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
-----------------

View File

@@ -12,7 +12,7 @@ firmware and the booting stage to follow OpenSBI firmware.
A *FW_PAYLOAD* firmware is also useful for cases where the booting stage prior
to the OpenSBI firmware does not pass a *flattened device tree (FDT file)*. In
such a case, a *FW_PAYLOAD* firmware allows embedding a flattened device tree
in the .text section of the final firmware.
in the .rodata section of the final firmware.
Enabling *FW_PAYLOAD* compilation
---------------------------------
@@ -20,7 +20,7 @@ Enabling *FW_PAYLOAD* compilation
The *FW_PAYLOAD* firmware can be enabled by any of the following methods:
1. Specifying `FW_PAYLOAD=y` on the top level `make` command line.
2. Specifying `FW_PAYLOAD=y` in the target platform *config.mk* configuration
2. Specifying `FW_PAYLOAD=y` in the target platform *objects.mk* configuration
file.
The compiled *FW_PAYLOAD* firmware ELF file is named *fw_jump.elf*. Its
@@ -33,7 +33,7 @@ Configuration Options
A *FW_PAYLOAD* firmware is built according to configuration parameters and
options. These configuration parameters can be defined using either the top
level `make` command line or the target platform *config.mk* configuration
level `make` command line or the target platform *objects.mk* configuration
file. The parameters currently defined are as follows:
* **FW_PAYLOAD_OFFSET** - Offset from *FW_TEXT_BASE* where the payload binary

View File

@@ -8,11 +8,7 @@ OpenSBI provides two types of static libraries:
hooks for the execution of this interface must be provided by the firmware or
bootloader linking with this library. This library is installed as
*<install_directory>/lib/libsbi.a*
2. *libsbiutils.a* - A static library that will contain all common code required
by any platform supported in OpenSBI. It will be built by default and included
in libplatsbi.a. This library is installed as
*<install_directory>/lib/libsbiutils.a*.
3. *libplatsbi.a* - An example platform-specific static library integrating
2. *libplatsbi.a* - An example platform-specific static library integrating
*libsbi.a* with platform-specific hooks. This library is available only for
the platforms supported by OpenSBI. This library is installed as
*<install_directory>/platform/<platform_subdir>/lib/libplatsbi.a*
@@ -77,7 +73,7 @@ firmware drivers based on the external firmware architecture.
**OPENSBI_EXTERNAL_SBI_TYPES** identifier is introduced to *sbi_types.h* for selecting
external header file during the build preprocess in order to define OpensSBI data types
based on external firmware data type binding.
For example, *bool* is declared as *int* in sbi_types.h. However in EDK2 build system,
For example, *bool* is declared as *int* in sbi_types.h. However, in EDK2 build system,
*bool* is declared as *BOOLEAN* which is defined as *unsigned char* data type.
External firmware can define **OPENSBI_EXTERNAL_SBI_TYPES** in CFLAGS and specify it to the

View File

@@ -8,7 +8,7 @@ AHB/APB IPs suites a majority embedded systems, and the verified platform serves
as a starting point to jump start SoC designs.
To build platform specific library and firmwares, provide the
*PLATFORM=andes/ae350* parameter to the top level make command.
*PLATFORM=generic* parameter to the top level `make` command.
Platform Options
----------------
@@ -18,13 +18,190 @@ The Andes AE350 platform does not have any platform-specific options.
Building Andes AE350 Platform
-----------------------------
To use Linux v5.2 should be used to build Andes AE350 OpenSBI binaries by using
the compile time option FW_FDT_PATH.
AE350's dts is included in https://github.com/andestech/linux/tree/ast-v3_2_0-release-public
AE350's dts is included in https://github.com/andestech/linux/tree/RISCV-Linux-5.4-ast-v5_1_0-branch
**Linux Kernel Payload**
```
make PLATFORM=andes/ae350 FW_PAYLOAD_PATH=<linux_build_directory>/arch/riscv/boot/Image FW_FDT_PATH=<ae350.dtb path>
make PLATFORM=generic FW_PAYLOAD_PATH=<linux_build_directory>/arch/riscv/boot/Image FW_FDT_PATH=<ae350.dtb path>
```
DTS Example: (Quad-core AX45MP)
-------------------------------
```
compatible = "andestech,ae350";
cpus {
#address-cells = <1>;
#size-cells = <0>;
timebase-frequency = <60000000>;
CPU0: cpu@0 {
device_type = "cpu";
reg = <0>;
status = "okay";
compatible = "riscv";
riscv,isa = "rv64imafdc";
riscv,priv-major = <1>;
riscv,priv-minor = <10>;
mmu-type = "riscv,sv48";
clock-frequency = <60000000>;
i-cache-size = <0x8000>;
i-cache-sets = <256>;
i-cache-line-size = <64>;
i-cache-block-size = <64>;
d-cache-size = <0x8000>;
d-cache-sets = <128>;
d-cache-line-size = <64>;
d-cache-block-size = <64>;
next-level-cache = <&L2>;
CPU0_intc: interrupt-controller {
#interrupt-cells = <1>;
interrupt-controller;
compatible = "riscv,cpu-intc";
};
};
CPU1: cpu@1 {
device_type = "cpu";
reg = <1>;
status = "okay";
compatible = "riscv";
riscv,isa = "rv64imafdc";
riscv,priv-major = <1>;
riscv,priv-minor = <10>;
mmu-type = "riscv,sv48";
clock-frequency = <60000000>;
i-cache-size = <0x8000>;
i-cache-sets = <256>;
i-cache-line-size = <64>;
i-cache-block-size = <64>;
d-cache-size = <0x8000>;
d-cache-sets = <128>;
d-cache-line-size = <64>;
d-cache-block-size = <64>;
next-level-cache = <&L2>;
CPU1_intc: interrupt-controller {
#interrupt-cells = <1>;
interrupt-controller;
compatible = "riscv,cpu-intc";
};
};
CPU2: cpu@2 {
device_type = "cpu";
reg = <2>;
status = "okay";
compatible = "riscv";
riscv,isa = "rv64imafdc";
riscv,priv-major = <1>;
riscv,priv-minor = <10>;
mmu-type = "riscv,sv48";
clock-frequency = <60000000>;
i-cache-size = <0x8000>;
i-cache-sets = <256>;
i-cache-line-size = <64>;
i-cache-block-size = <64>;
d-cache-size = <0x8000>;
d-cache-sets = <128>;
d-cache-line-size = <64>;
d-cache-block-size = <64>;
next-level-cache = <&L2>;
CPU2_intc: interrupt-controller {
#interrupt-cells = <1>;
interrupt-controller;
compatible = "riscv,cpu-intc";
};
};
CPU3: cpu@3 {
device_type = "cpu";
reg = <3>;
status = "okay";
compatible = "riscv";
riscv,isa = "rv64imafdc";
riscv,priv-major = <1>;
riscv,priv-minor = <10>;
mmu-type = "riscv,sv48";
clock-frequency = <60000000>;
i-cache-size = <0x8000>;
i-cache-sets = <256>;
i-cache-line-size = <64>;
i-cache-block-size = <64>;
d-cache-size = <0x8000>;
d-cache-sets = <128>;
d-cache-line-size = <64>;
d-cache-block-size = <64>;
next-level-cache = <&L2>;
CPU3_intc: interrupt-controller {
#interrupt-cells = <1>;
interrupt-controller;
compatible = "riscv,cpu-intc";
};
};
};
soc {
#address-cells = <2>;
#size-cells = <2>;
compatible = "andestech,riscv-ae350-soc", "simple-bus";
ranges;
plic0: interrupt-controller@e4000000 {
compatible = "riscv,plic0";
reg = <0x00000000 0xe4000000 0x00000000 0x02000000>;
interrupts-extended = < &CPU0_intc 11 &CPU0_intc 9
&CPU1_intc 11 &CPU1_intc 9
&CPU2_intc 11 &CPU2_intc 9
&CPU3_intc 11 &CPU3_intc 9 >;
interrupt-controller;
#address-cells = <2>;
#interrupt-cells = <2>;
riscv,ndev = <71>;
};
plicsw: interrupt-controller@e6400000 {
compatible = "andestech,plicsw";
reg = <0x00000000 0xe6400000 0x00000000 0x00400000>;
interrupts-extended = < &CPU0_intc 3
&CPU1_intc 3
&CPU2_intc 3
&CPU3_intc 3 >;
interrupt-controller;
#address-cells = <2>;
#interrupt-cells = <2>;
};
plmt0: plmt0@e6000000 {
compatible = "andestech,plmt0";
reg = <0x00000000 0xe6000000 0x00000000 0x00100000>;
interrupts-extended = < &CPU0_intc 7
&CPU1_intc 7
&CPU2_intc 7
&CPU3_intc 7 >;
};
wdt: watchdog@f0500000 {
compatible = "andestech,atcwdt200";
reg = <0x00000000 0xf0500000 0x00000000 0x00001000>;
interrupts = <3 4>;
interrupt-parent = <&plic0>;
clock-frequency = <15000000>;
};
serial0: serial@f0300000 {
compatible = "andestech,uart16550", "ns16550a";
reg = <0x00000000 0xf0300000 0x00000000 0x00001000>;
interrupts = <9 4>;
interrupt-parent = <&plic0>;
clock-frequency = <19660800>;
current-speed = <38400>;
reg-shift = <2>;
reg-offset = <32>;
reg-io-width = <4>;
no-loopback-test = <1>;
};
smu: smu@f0100000 {
compatible = "andestech,atcsmu";
reg = <0x00000000 0xf0100000 0x00000000 0x00001000>;
};
};
```

View File

@@ -7,7 +7,7 @@ Linux.
The FPGA SoC currently contains the following peripherals:
- DDR3 memory controller
- SPI controller to conncet to an SDCard
- SPI controller to connect to an SDCard
- Ethernet controller
- JTAG port (see debugging section below)
- Bootrom containing zero stage bootloader and device tree.

View File

@@ -45,13 +45,17 @@ The *Generic* platform does not have any platform-specific options.
RISC-V Platforms Using Generic Platform
---------------------------------------
* **Andes AE350 Platform** (*[andes-ae350.md]*)
* **QEMU RISC-V Virt Machine** (*[qemu_virt.md]*)
* **Renesas RZ/Five SoC** (*[renesas-rzfive.md]*)
* **Shakti C-class SoC Platform** (*[shakti_cclass.md]*)
* **SiFive HiFive Unleashed** (*[sifive_fu540.md]*)
* **Spike** (*[spike.md]*)
* **T-HEAD C9xx series Processors** (*[thead-c9xx.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
[sifive_fu540.md]: sifive_fu540.md
[spike.md]: spike.md

View File

@@ -39,11 +39,15 @@ OpenSBI currently supports the following virtual and hardware platforms:
processor based SOCs. More details on this platform can be found in the
file *[shakti_cclass.md]*.
* **Renesas RZ/Five SoC**: Platform support for Renesas RZ/Five (R9A07G043F) SoC
used on the Renesas RZ/Five SMARC EVK board. More details on this platform can
be found in the file *[renesas-rzfive.md]*.
The code for these supported platforms can be used as example to implement
support for other platforms. The *platform/template* directory also provides
template files for implementing support for a new platform. The *object.mk*,
*config.mk* and *platform.c* template files provides enough comments to
facilitate the implementation.
template files for implementing support for a new platform. The *objects.mk*,
*Kconfig*, *configs/defconfig* and *platform.c* template files provides enough
comments to facilitate the implementation.
[generic.md]: generic.md
[qemu_virt.md]: qemu_virt.md
@@ -54,3 +58,4 @@ facilitate the implementation.
[spike.md]: spike.md
[fpga-openpiton.md]: fpga-openpiton.md
[shakti_cclass.md]: shakti_cclass.md
[renesas-rzfive.md]: renesas-rzfive.md

View File

@@ -0,0 +1,160 @@
Renesas RZ/Five SoC (R9A07G043F) Platform
=========================================
The RZ/Five microprocessor includes a single RISC-V CPU Core (Andes AX45MP)
1.0 GHz, 16-bit DDR3L/DDR4 interface. Supported interfaces include:
- Memory controller for DDR4-1600 / DDR3L-1333 with 16 bits
- System RAM (RAM of 128 Kbytes (ECC))
- SPI Multi I/O Bus Controller 1ch
- SD Card Host Interface/Multimedia Card Interface (SD/MMC) 2ch
- Serial Sound Interface (SSI) 4ch
- Sampling Rate Converter (SRC) 1ch
- USB2.0 host/function interface 2ch (ch0: Host-Function ch1: Host only)
- Gigabit Ethernet Interface (GbE) 2ch
- Controller Area Network Interface (CAN) 2ch (CAN-FD ISO 11898-1 (CD2014) compliant)
- Multi-function Timer Pulse Unit 3 (MTU3a) 9 ch (16 bits × 8 channels, 32 bits × 1 channel)
- Port Output Enable 3 (POE3)
- Watchdog Timer (WDT) 1ch
- General Timer (GTM) 3ch (32bits)
- I2C Bus Interface (I2C) 4ch
- Serial Communication Interface with FIFO (SCIFA) 5ch
- Serial Communication Interface (SCI) 2ch
- Renesas Serial Peripheral Interface (RSPI) 3ch
- A/D Converter (ADC) 2ch
making it ideal for applications such as entry-class social infrastructure
gateway control and industrial gateway control. More details can be found at
below link [0].
[0] https://www.renesas.com/us/en/products/microcontrollers-microprocessors/rz-mpus/rzfive-general-purpose-microprocessors-risc-v-cpu-core-andes-ax45mp-single-10-ghz-2ch-gigabit-ethernet
To build platform specific library and firmwares, provide the
*PLATFORM=generic* parameter to the top level make command.
Platform Options
----------------
The Renesas RZ/Five platform does not have any platform-specific options.
Building Renesas RZ/Five Platform
---------------------------------
```
make PLATFORM=generic
```
DTS Example: (RZ/Five AX45MP)
-----------------------------
```
compatible = "renesas,r9a07g043f01", "renesas,r9a07g043";
cpus {
#address-cells = <1>;
#size-cells = <0>;
timebase-frequency = <12000000>;
cpu0: cpu@0 {
compatible = "andestech,ax45mp", "riscv";
device_type = "cpu";
reg = <0x0>;
status = "okay";
riscv,isa = "rv64imafdc";
mmu-type = "riscv,sv39";
i-cache-size = <0x8000>;
i-cache-line-size = <0x40>;
d-cache-size = <0x8000>;
d-cache-line-size = <0x40>;
clocks = <&cpg CPG_CORE R9A07G043_CLK_I>;
cpu0_intc: interrupt-controller {
#interrupt-cells = <1>;
compatible = "riscv,cpu-intc";
interrupt-controller;
};
};
};
soc {
compatible = "simple-bus";
#address-cells = <1>;
#size-cells = <0>;
ranges;
scif0: serial@1004b800 {
compatible = "renesas,scif-r9a07g043",
"renesas,scif-r9a07g044";
reg = <0 0x1004b800 0 0x400>;
interrupts = <412 IRQ_TYPE_LEVEL_HIGH>,
<414 IRQ_TYPE_LEVEL_HIGH>,
<415 IRQ_TYPE_LEVEL_HIGH>,
<413 IRQ_TYPE_LEVEL_HIGH>,
<416 IRQ_TYPE_LEVEL_HIGH>,
<416 IRQ_TYPE_LEVEL_HIGH>;
interrupt-names = "eri", "rxi", "txi",
"bri", "dri", "tei";
clocks = <&cpg CPG_MOD R9A07G043_SCIF0_CLK_PCK>;
clock-names = "fck";
power-domains = <&cpg>;
resets = <&cpg R9A07G043_SCIF0_RST_SYSTEM_N>;
status = "disabled";
};
cpg: clock-controller@11010000 {
compatible = "renesas,r9a07g043-cpg";
reg = <0 0x11010000 0 0x10000>;
clocks = <&extal_clk>;
clock-names = "extal";
#clock-cells = <2>;
#reset-cells = <1>;
#power-domain-cells = <0>;
};
sysc: system-controller@11020000 {
compatible = "renesas,r9a07g043-sysc";
reg = <0 0x11020000 0 0x10000>;
status = "disabled";
};
pinctrl: pinctrl@11030000 {
compatible = "renesas,r9a07g043-pinctrl";
reg = <0 0x11030000 0 0x10000>;
gpio-controller;
#gpio-cells = <2>;
#interrupt-cells = <2>;
interrupt-controller;
gpio-ranges = <&pinctrl 0 0 152>;
clocks = <&cpg CPG_MOD R9A07G043_GPIO_HCLK>;
power-domains = <&cpg>;
resets = <&cpg R9A07G043_GPIO_RSTN>,
<&cpg R9A07G043_GPIO_PORT_RESETN>,
<&cpg R9A07G043_GPIO_SPARE_RESETN>;
};
plmt0: plmt0@110c0000 {
compatible = "andestech,plmt0", "riscv,plmt0";
reg = <0x0 0x110c0000 0x0 0x10000>;
interrupts-extended = <&cpu0_intc 7>;
};
plic: interrupt-controller@12c00000 {
compatible = "renesas,r9a07g043-plic", "andestech,nceplic100";
#interrupt-cells = <2>;
#address-cells = <0>;
riscv,ndev = <511>;
interrupt-controller;
reg = <0x0 0x12c00000 0x0 0x400000>;
clocks = <&cpg CPG_MOD R9A07G043_NCEPLIC_ACLK>;
power-domains = <&cpg>;
resets = <&cpg R9A07G043_NCEPLIC_ARESETN>;
interrupts-extended = <&cpu0_intc 11 &cpu0_intc 9>;
};
plicsw: interrupt-controller@13000000 {
compatible = "andestech,plicsw";
reg = <0x0 0x13000000 0x0 0x400000>;
interrupts-extended = <&cpu0_intc 3>;
interrupt-controller;
#address-cells = <2>;
#interrupt-cells = <2>;
};
};
```

View File

@@ -150,7 +150,7 @@ If you want to test OpenSBI with QEMU 'sifive_u' machine, please follow the
same instructions above, with the exception of not passing FW_FDT_PATH.
This is because QEMU generates a device tree blob on the fly based on the
command line parameters and it's compatible with the one used in the upstream
command line parameters, and it's compatible with the one used in the upstream
Linux kernel.
When U-Boot v2021.07 (or higher) is used as the payload, as the SiFive FU540

View File

@@ -13,7 +13,7 @@ Platform Options
----------------
The *T-HEAD C9xx* does not have any platform-specific compile options
because it use generic platform.
because it uses generic platform.
```
CROSS_COMPILE=riscv64-linux-gnu- PLATFORM=generic /usr/bin/make

View File

@@ -28,11 +28,12 @@ Adding support for a new platform
Support for a new platform named *&lt;xyz&gt;* can be added as follows:
1. Create a directory named *&lt;xyz&gt;* under the *platform/* directory.
2. Create a platform configuration file named *config.mk* under the
*platform/&lt;xyz&gt;/* directory. This configuration file will provide
2. Create platform configuration files named *Kconfig* and *configs/defconfig*
under the *platform/&lt;xyz&gt;/* directory. These configuration files will
provide the build time configuration for the sources to be compiled.
3. Create a *platform/&lt;xyz&gt;/objects.mk* file for listing the platform
object files to be compiled. This file also provides platform-specific
compiler flags, and select firmware options.
3. Create a *platform/&lt;xyz&gt;/objects.mk* file for listing the
platform-specific object files to be compiled.
4. Create a *platform/&lt;xyz&gt;/platform.c* file providing a
*struct sbi_platform* instance.

View File

@@ -10,7 +10,7 @@ To handle this, we have two types of RISC-V platform requirements:
2. **Release specific platform requirements** which apply to a OpenSBI
release and later releases
Currently, we don't have any **Release specific platform requirements**
Currently, we don't have any **Release specific platform requirements**,
but such platform requirements will be added in future.
Base Platform Requirements

View File

@@ -1,14 +1,11 @@
OpenSBI SBI PMU extension support
==================================
SBI PMU extension supports allow supervisor software to configure/start/stop
any performance counter at anytime. Thus, an user can leverage full
any performance counter at anytime. Thus, a user can leverage full
capability of performance analysis tools such as perf if SBI PMU extension is
enabled. The OpenSBI implementation makes the following assumptions about the
hardware platform.
* MCOUNTINHIBIT CSR must be implemented in the hardware. Otherwise, SBI PMU
extension will not be enabled.
* The platform must provide information about PMU event to counter mapping
via device tree or platform specific hooks. Otherwise, SBI PMU extension will
not be enabled.
@@ -25,7 +22,7 @@ SBI PMU Device Tree Bindings
----------------------------
Platforms may choose to describe PMU event selector and event to counter mapping
values via device tree. The following sections describes the PMU DT node
values via device tree. The following sections describe the PMU DT node
bindings in details.
* **compatible** (Mandatory) - The compatible string of SBI PMU device tree node.
@@ -42,21 +39,21 @@ This property shouldn't encode any raw hardware event.
* **riscv,event-to-mhpmcounters**(Optional) - It represents a MANY-to-MANY
mapping between a range of events and all the MHPMCOUNTERx in a bitmap format
that can be used to monitor these range of events. The information is encoded in
a table format where each row represent a certain range of events and
a table format where each row represents a certain range of events and
corresponding counters. The first column represents starting of the pmu event id
and 2nd column represents the end of the pmu event id. The third column
represent a bitmap of all the MHPMCOUNTERx. This property is mandatory if
event-to-mhpmevent is present. Otherwise, it can be omitted. This property
riscv,event-to-mhpmevent is present. Otherwise, it can be omitted. This property
shouldn't encode any raw event.
* **riscv,raw-event-to-mhpmcounters**(Optional) - It represents an ONE-to-MANY
or MANY-to-MANY mapping between the raw event(s) and all the MHPMCOUNTERx in
a bitmap format that can be used to monitor that raw event. The encoding of the
raw events are platform specific. The information is encoded in a table format
where each row represent the specific raw event(s). The first column is a 64bit
where each row represents the specific raw event(s). The first column is a 64bit
match value where the invariant bits of range of events are set. The second
column is a 64 bit mask that will have all the variant bits of the range of
events cleared. Every other bits should be set in the mask.
events cleared. All other bits should be set in the mask.
The third column is a 32bit value to represent bitmap of all MHPMCOUNTERx that
can monitor these set of event(s).
If a platform directly encodes each raw PMU event as a unique ID, the value of
@@ -70,17 +67,17 @@ via platform hooks rather than the device tree.
```
pmu {
compatible = "riscv,pmu";
riscv,event-to-mhpmevent = <0x0000B 0x0000 0x0001>,
riscv,event-to-mhpmevent = <0x0000B 0x0000 0x0001>;
riscv,event-to-mhpmcounters = <0x00001 0x00001 0x00000001>,
<0x00002 0x00002 0x00000004>,
<0x00003 0x0000A 0x00000ff8>,
<0x10000 0x10033 0x000ff000>,
<0x10000 0x10033 0x000ff000>;
/* For event ID 0x0002 */
riscv,raw-event-to-mhpmcounters = <0x0000 0x0002 0xffffffff 0xffffffff 0x00000f8>,
/* For event ID 0-4 */
<0x0 0x0 0xffffffff 0xfffffff0 0x00000ff0>,
/* For event ID 0xffffffff0000000f - 0xffffffff000000ff */
<0xffffffff 0x0 0xffffffff 0xffffff0f 0x00000ff0>,
<0xffffffff 0x0 0xffffffff 0xffffff0f 0x00000ff0>;
};
```
@@ -90,11 +87,41 @@ pmu {
/*
* For HiFive Unmatched board. The encodings can be found here
* https://sifive.cdn.prismic.io/sifive/1a82e600-1f93-4f41-b2d8-86ed8b16acba_fu740-c000-manual-v1p6.pdf
* This example also binds standard SBI PMU hardware id's to U74 PMU event codes, U74 uses bitfield for
* events encoding, so several U74 events can be bound to single perf id.
* See SBI PMU hardware id's in include/sbi/sbi_ecall_interface.h
*/
pmu {
compatible = "riscv,pmu";
riscv,raw-event-to-mhpmcounters = <0x0 0x0 0xffffffff 0xfc0000ff 0xc>,
<0x0 0x1 0xffffffff 0xfff800ff 0xc>,
<0x0 0x2 0xffffffff 0xffffe0ff 0xc>;
riscv,event-to-mhpmevent =
/* SBI_PMU_HW_CACHE_REFERENCES -> Instruction cache/ITIM busy | Data cache/DTIM busy */
<0x00003 0x00000000 0x1801>,
/* SBI_PMU_HW_CACHE_MISSES -> Instruction cache miss | Data cache miss or memory-mapped I/O access */
<0x00004 0x00000000 0x0302>,
/* SBI_PMU_HW_BRANCH_INSTRUCTIONS -> Conditional branch retired */
<0x00005 0x00000000 0x4000>,
/* SBI_PMU_HW_BRANCH_MISSES -> Branch direction misprediction | Branch/jump target misprediction */
<0x00006 0x00000000 0x6001>,
/* L1D_READ_MISS -> Data cache miss or memory-mapped I/O access */
<0x10001 0x00000000 0x0202>,
/* L1D_WRITE_ACCESS -> Data cache write-back */
<0x10002 0x00000000 0x0402>,
/* L1I_READ_ACCESS -> Instruction cache miss */
<0x10009 0x00000000 0x0102>,
/* LL_READ_MISS -> UTLB miss */
<0x10011 0x00000000 0x2002>,
/* DTLB_READ_MISS -> Data TLB miss */
<0x10019 0x00000000 0x1002>,
/* ITLB_READ_MISS-> Instruction TLB miss */
<0x10021 0x00000000 0x0802>;
riscv,event-to-mhpmcounters = <0x00003 0x00006 0x18>,
<0x10001 0x10002 0x18>,
<0x10009 0x10009 0x18>,
<0x10011 0x10011 0x18>,
<0x10019 0x10019 0x18>,
<0x10021 0x10021 0x18>;
riscv,raw-event-to-mhpmcounters = <0x0 0x0 0xffffffff 0xfc0000ff 0x18>,
<0x0 0x1 0xffffffff 0xfff800ff 0x18>,
<0x0 0x2 0xffffffff 0xffffe0ff 0x18>;
};
```

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.9 KiB

1
firmware/Kconfig Normal file
View File

@@ -0,0 +1 @@
# SPDX-License-Identifier: BSD-2-Clause

View File

@@ -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 */
@@ -95,18 +94,17 @@ _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
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 */
@@ -114,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
@@ -128,9 +126,9 @@ _relocate:
REG_L t1, 0(t1)
lla t2, _load_start
REG_L t2, 0(t2)
beq t0, t2, _relocate_done
sub t3, t1, t0
add t3, t3, t2
beq t0, t2, _relocate_done
lla t4, _relocate_done
sub t4, t4, t2
add t4, t4, t0
@@ -257,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 */
@@ -285,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
@@ -298,6 +307,16 @@ _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 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
@@ -422,9 +441,8 @@ _start_warm:
li ra, 0
call _reset_regs
/* Disable and clear all interrupts */
/* Disable all interrupts */
csrw CSR_MIE, zero
csrw CSR_MIP, zero
/* Find HART count and HART stack size */
lla a4, platform
@@ -453,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
@@ -519,6 +536,8 @@ _link_start:
RISCV_PTR FW_TEXT_START
_link_end:
RISCV_PTR _fw_reloc_end
__fw_rw_offset:
RISCV_PTR _fw_rw_start - _fw_start
.section .entry, "ax", %progbits
.align 3

View File

@@ -24,27 +24,49 @@
PROVIDE(_text_end = .);
}
. = ALIGN(0x1000); /* Ensure next section is page aligned */
/* End of the code sections */
. = ALIGN(0x1000); /* Ensure next section is page aligned */
/* Beginning of the read-only data sections */
. = ALIGN(0x1000); /* Ensure next section is page aligned */
PROVIDE(_rodata_start = .);
.rodata :
{
PROVIDE(_rodata_start = .);
*(.rodata .rodata.*)
. = ALIGN(8);
PROVIDE(_rodata_end = .);
}
. = 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 */
/* Beginning of the read-write data sections */
/*
* 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)
+ SIZEOF(.dynsym) + SIZEOF(.rela.dyn))));
. = ALIGN(0x1000); /* Ensure next section is page aligned */
PROVIDE(_fw_rw_start = .);
/* Beginning of the read-write data sections */
.data :
{
@@ -61,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 :

View File

@@ -33,14 +33,12 @@ SECTIONS
PROVIDE(_text_end = .);
}
. = ALIGN(0x1000); /* Ensure next section is page aligned */
/* End of the code sections */
/* Beginning of the read-only data sections */
. = ALIGN(0x1000); /* Ensure next section is page aligned */
/* Beginning of the read-only data sections */
.rodata :
{
PROVIDE(_rodata_start = .);
@@ -51,10 +49,10 @@ SECTIONS
/* End of the read-only data sections */
/* Beginning of the read-write data sections */
. = ALIGN(0x1000); /* Ensure next section is page aligned */
/* Beginning of the read-write data sections */
.data :
{
PROVIDE(_data_start = .);

View File

@@ -38,10 +38,14 @@
#define MSTATUS_SXL _ULL(0x0000000C00000000)
#define MSTATUS_SBE _ULL(0x0000001000000000)
#define MSTATUS_MBE _ULL(0x0000002000000000)
#define MSTATUS_GVA _ULL(0x0000004000000000)
#define MSTATUS_GVA_SHIFT 38
#define MSTATUS_MPV _ULL(0x0000008000000000)
#else
#define MSTATUSH_SBE _UL(0x00000010)
#define MSTATUSH_MBE _UL(0x00000020)
#define MSTATUSH_GVA _UL(0x00000040)
#define MSTATUSH_GVA_SHIFT 6
#define MSTATUSH_MPV _UL(0x00000080)
#endif
#define MSTATUS32_SD _UL(0x80000000)
@@ -308,8 +312,6 @@
/* Supervisor Trap Setup */
#define CSR_SSTATUS 0x100
#define CSR_SEDELEG 0x102
#define CSR_SIDELEG 0x103
#define CSR_SIE 0x104
#define CSR_STVEC 0x105
#define CSR_SCOUNTEREN 0x106
@@ -734,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

View File

@@ -12,13 +12,7 @@
#include <sbi/sbi_types.h>
#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)))

View File

@@ -0,0 +1,61 @@
/*
* SPDX-License-Identifier: BSD-2-Clause
*
* Copyright (c) 2023 Ventana Micro Systems Inc.
*/
#ifndef __SBI_BYTEORDER_H__
#define __SBI_BYTEORDER_H__
#include <sbi/sbi_types.h>
#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))
#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__ */

View File

@@ -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);
};
@@ -33,8 +36,12 @@ 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);
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, ...);

35
include/sbi/sbi_cppc.h Normal file
View File

@@ -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 <sbi/sbi_types.h>
/** 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

View File

@@ -36,11 +36,53 @@ 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)
#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 | \
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;
@@ -78,17 +120,17 @@ 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;
/** Identifies whether to include the firmware region */
bool fw_region_inited;
};
/** 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() \
@@ -113,7 +155,7 @@ extern struct sbi_domain *domidx_to_domain_table[];
* Check whether given HART is assigned to specified domain
* @param dom pointer to domain
* @param hartid the HART ID
* @return TRUE if HART is assigned to domain otherwise FALSE
* @return true if HART is assigned to domain otherwise false
*/
bool sbi_domain_is_assigned_hart(const struct sbi_domain *dom, u32 hartid);
@@ -148,12 +190,27 @@ void sbi_domain_memregion_init(unsigned long addr,
* @param addr the address 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
* @return true if access allowed otherwise false
*/
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);
@@ -175,11 +232,25 @@ int sbi_domain_register(struct sbi_domain *dom,
* @param reg pointer to the memory region to be added
*
* @return 0 on success
* @return SBI_EALREADY if memory region conflicts with existing
* @return SBI_EALREADY if memory region conflicts with the existing one
* @return SBI_EINVAL otherwise
*/
int sbi_domain_root_add_memregion(const struct sbi_domain_memregion *reg);
/**
* Add a memory range with its flags to the root domain
* @param addr start physical address of memory range
* @param size physical size of memory range
* @param align alignment of memory region
* @param region_flags memory range flags
*
* @return 0 on success
* @return SBI_EALREADY if memory region conflicts with the existing one
* @return SBI_EINVAL otherwise
*/
int sbi_domain_root_add_memrange(unsigned long addr, unsigned long size,
unsigned long align, unsigned long region_flags);
/** Finalize domain tables and startup non-root domains */
int sbi_domain_finalize(struct sbi_scratch *scratch, u32 cold_hartid);

View File

@@ -21,26 +21,52 @@ 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,
struct sbi_trap_info *out_trap);
};
extern struct sbi_ecall_extension ecall_base;
extern struct sbi_ecall_extension ecall_legacy;
extern struct sbi_ecall_extension ecall_time;
extern struct sbi_ecall_extension ecall_rfence;
extern struct sbi_ecall_extension ecall_ipi;
extern struct sbi_ecall_extension ecall_vendor;
extern struct sbi_ecall_extension ecall_hsm;
extern struct sbi_ecall_extension ecall_srst;
extern struct sbi_ecall_extension ecall_pmu;
u16 sbi_ecall_version_major(void);
u16 sbi_ecall_version_minor(void);

View File

@@ -29,6 +29,9 @@
#define SBI_EXT_HSM 0x48534D
#define SBI_EXT_SRST 0x53525354
#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
@@ -99,6 +102,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 {
@@ -182,6 +186,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 */
@@ -200,14 +215,20 @@ 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
#define SBI_PMU_EVENT_HW_CACHE_OPS_RESULT 0x1
#define SBI_PMU_EVENT_HW_CACHE_OPS_ID_MASK 0x6
#define SBI_PMU_EVENT_HW_CACHE_OPS_ID_OFFSET 1
#define SBI_PMU_EVENT_HW_CACHE_ID_MASK 0xfff8
#define SBI_PMU_EVENT_HW_CACHE_ID_OFFSET 3
/* Flags defined for config matching function */
#define SBI_PMU_CFG_FLAG_SKIP_MATCH (1 << 0)
#define SBI_PMU_CFG_FLAG_CLEAR_VALUE (1 << 1)
@@ -224,6 +245,51 @@ 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 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 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

View File

@@ -30,8 +30,8 @@ enum sbi_hart_extensions {
SBI_HART_EXT_SSCOFPMF = 0,
/** HART has HW time CSR (extension name not available) */
SBI_HART_EXT_TIME,
/** HART has AIA CSRs (extension name not available) */
SBI_HART_EXT_AIA,
/** HART has AIA M-mode CSRs */
SBI_HART_EXT_SMAIA,
/** HART has Smstateen CSR **/
SBI_HART_EXT_SMSTATEEN,
/** HART has Sstc extension */
@@ -41,6 +41,17 @@ enum sbi_hart_extensions {
SBI_HART_EXT_MAX,
};
struct sbi_hart_features {
bool detected;
int priv_version;
unsigned long extensions;
unsigned int pmp_count;
unsigned int pmp_addr_bits;
unsigned long pmp_gran;
unsigned int mhpm_count;
unsigned int mhpm_bits;
};
struct sbi_scratch;
int sbi_hart_reinit(struct sbi_scratch *scratch);

44
include/sbi/sbi_heap.h Normal file
View File

@@ -0,0 +1,44 @@
/*
* SPDX-License-Identifier: BSD-2-Clause
*
* Copyright (c) 2023 Ventana Micro Systems Inc.
*
* Authors:
* Anup Patel<apatel@ventanamicro.com>
*/
#ifndef __SBI_HEAP_H__
#define __SBI_HEAP_H__
#include <sbi/sbi_types.h>
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

View File

@@ -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);
@@ -59,15 +63,21 @@ 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);
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 priv);
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_prepare_next_jump(struct sbi_scratch *scratch, u32 hartid);
void __sbi_hsm_suspend_non_ret_save(struct sbi_scratch *scratch);
void __noreturn sbi_hsm_hart_start_finish(struct sbi_scratch *scratch,
u32 hartid);
#endif

View File

@@ -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);

View File

@@ -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,
@@ -75,7 +85,9 @@ int sbi_ipi_send_halt(ulong hmask, ulong hbase);
void sbi_ipi_process(void);
void sbi_ipi_raw_send(u32 target_hart);
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);

View File

@@ -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,
@@ -47,7 +47,7 @@ static inline void __sbi_list_add(struct sbi_dlist *new,
* Checks if the list is empty or not.
* @param head List head
*
* Retruns TRUE if list is empty, FALSE otherwise.
* Returns true if list is empty, false otherwise.
*/
static inline bool sbi_list_empty(struct sbi_dlist *head)
{

View File

@@ -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)
@@ -48,6 +52,7 @@
struct sbi_domain_memregion;
struct sbi_trap_info;
struct sbi_trap_regs;
struct sbi_hart_features;
/** Possible feature flags of a platform */
enum sbi_platform_features {
@@ -64,6 +69,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);
@@ -90,7 +98,7 @@ struct sbi_platform_operations {
int (*misa_get_xlen)(void);
/** Initialize (or populate) HART extensions for the platform */
int (*extensions_init)(void);
int (*extensions_init)(struct sbi_hart_features *hfeatures);
/** Initialize (or populate) domains for the platform */
int (*domains_init)(void);
@@ -122,10 +130,10 @@ 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,
int (*vendor_ext_provider)(long funcid,
const struct sbi_trap_regs *regs,
unsigned long *out_value,
struct sbi_trap_info *out_trap);
@@ -134,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 {
/**
@@ -156,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 */
@@ -343,16 +359,33 @@ static inline u32 sbi_platform_hart_stack_size(const struct sbi_platform *plat)
* @param plat pointer to struct sbi_platform
* @param hartid HART ID
*
* @return TRUE if HART is invalid and FALSE otherwise
* @return true if HART is invalid and false otherwise
*/
static inline bool sbi_platform_hart_invalid(const struct sbi_platform *plat,
u32 hartid)
{
if (!plat)
return TRUE;
return true;
if (plat->hart_count <= sbi_platform_hart_index(plat, hartid))
return TRUE;
return FALSE;
return true;
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;
}
/**
@@ -376,7 +409,7 @@ static inline int sbi_platform_nascent_init(const struct sbi_platform *plat)
* Early initialization for current HART
*
* @param plat pointer to struct sbi_platform
* @param cold_boot whether cold boot (TRUE) or warm_boot (FALSE)
* @param cold_boot whether cold boot (true) or warm_boot (false)
*
* @return 0 on success and negative error code on failure
*/
@@ -392,7 +425,7 @@ static inline int sbi_platform_early_init(const struct sbi_platform *plat,
* Final initialization for current HART
*
* @param plat pointer to struct sbi_platform
* @param cold_boot whether cold boot (TRUE) or warm_boot (FALSE)
* @param cold_boot whether cold boot (true) or warm_boot (false)
*
* @return 0 on success and negative error code on failure
*/
@@ -464,10 +497,11 @@ static inline int sbi_platform_misa_xlen(const struct sbi_platform *plat)
* @return 0 on success and negative error code on failure
*/
static inline int sbi_platform_extensions_init(
const struct sbi_platform *plat)
const struct sbi_platform *plat,
struct sbi_hart_features *hfeatures)
{
if (plat && sbi_platform_ops(plat)->extensions_init)
return sbi_platform_ops(plat)->extensions_init();
return sbi_platform_ops(plat)->extensions_init(hfeatures);
return 0;
}
@@ -536,7 +570,7 @@ static inline int sbi_platform_console_init(const struct sbi_platform *plat)
* Initialize the platform interrupt controller for current HART
*
* @param plat pointer to struct sbi_platform
* @param cold_boot whether cold boot (TRUE) or warm_boot (FALSE)
* @param cold_boot whether cold boot (true) or warm_boot (false)
*
* @return 0 on success and negative error code on failure
*/
@@ -563,7 +597,7 @@ static inline void sbi_platform_irqchip_exit(const struct sbi_platform *plat)
* Initialize the platform IPI support for current HART
*
* @param plat pointer to struct sbi_platform
* @param cold_boot whether cold boot (TRUE) or warm_boot (FALSE)
* @param cold_boot whether cold boot (true) or warm_boot (false)
*
* @return 0 on success and negative error code on failure
*/
@@ -590,7 +624,7 @@ static inline void sbi_platform_ipi_exit(const struct sbi_platform *plat)
* Initialize the platform timer for current HART
*
* @param plat pointer to struct sbi_platform
* @param cold_boot whether cold boot (TRUE) or warm_boot (FALSE)
* @param cold_boot whether cold boot (true) or warm_boot (false)
*
* @return 0 on success and negative error code on failure
*/
@@ -614,27 +648,25 @@ 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;
}
/**
* 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
@@ -644,14 +676,14 @@ static inline int sbi_platform_vendor_ext_check(const struct sbi_platform *plat,
*/
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);
}

View File

@@ -11,29 +11,101 @@
#define __SBI_PMU_H__
#include <sbi/sbi_types.h>
#include <sbi/sbi_hartmask.h>
#include <sbi/sbi_scratch.h>
#include <sbi/sbi_ecall_interface.h>
struct sbi_scratch;
/* Event related macros */
/* Maximum number of hardware events that can mapped by OpenSBI */
#define SBI_PMU_HW_EVENT_MAX 256
/* Maximum number of firmware events that can mapped by OpenSBI */
#define SBI_PMU_FW_EVENT_MAX 32
/* Counter related macros */
#define SBI_PMU_FW_CTR_MAX 16
#define SBI_PMU_HW_CTR_MAX 32
#define SBI_PMU_CTR_MAX (SBI_PMU_HW_CTR_MAX + SBI_PMU_FW_CTR_MAX)
#define SBI_PMU_FIXED_CTR_MASK 0x07
struct sbi_pmu_device {
/** Name of the PMU platform device */
char name[32];
/**
* Validate event code of custom firmware event
*/
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 hartid,
uint32_t counter_index,
uint64_t event_data);
/**
* 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
*/
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 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 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 hartid, uint32_t counter_index);
/**
* Custom enable irq for hardware counter
* Note: 0 <= counter_index < SBI_PMU_HW_CTR_MAX
*/
void (*hw_counter_enable_irq)(uint32_t counter_index);
/**
* Custom disable irq for hardware counter
* Note: 0 <= counter_index < SBI_PMU_HW_CTR_MAX
*/
void (*hw_counter_disable_irq)(uint32_t counter_index);
/**
* Custom function returning the machine-specific irq-bit.
*/
int (*hw_counter_irq_bit)(void);
};
/** Get the PMU platform device */
const struct sbi_pmu_device *sbi_pmu_get_device(void);
/** Set the PMU platform device */
void sbi_pmu_set_device(const struct sbi_pmu_device *dev);
/** Initialize PMU */
int sbi_pmu_init(struct sbi_scratch *scratch, bool cold_boot);
/** Reset PMU during hart exit */
void sbi_pmu_exit(struct sbi_scratch *scratch);
/** Return the pmu irq bit depending on extension existence */
int sbi_pmu_irq_bit(void);
/**
* Add the hardware event to counter mapping information. This should be called
* from the platform code to update the mapping table.
@@ -53,7 +125,7 @@ int sbi_pmu_add_hw_event_counter_map(u32 eidx_start, u32 eidx_end, u32 cmap);
int sbi_pmu_add_raw_event_counter_map(uint64_t select, uint64_t select_mask, u32 cmap);
int sbi_pmu_ctr_read(uint32_t cidx, unsigned long *cval);
int sbi_pmu_ctr_fw_read(uint32_t cidx, uint64_t *cval);
int sbi_pmu_ctr_stop(unsigned long cidx_base, unsigned long cidx_mask,
unsigned long flag);

View File

@@ -18,26 +18,32 @@
#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 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 (2 * __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 (3 * __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 (4 * __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 (5 * __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 (6 * __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 (7 * __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 (8 * __SIZEOF_POINTER__)
#define SBI_SCRATCH_TRAP_EXIT_OFFSET (11 * __SIZEOF_POINTER__)
/** Offset of tmp0 member in sbi_scratch */
#define SBI_SCRATCH_TMP0_OFFSET (9 * __SIZEOF_POINTER__)
#define SBI_SCRATCH_TMP0_OFFSET (12 * __SIZEOF_POINTER__)
/** Offset of options member in sbi_scratch */
#define SBI_SCRATCH_OPTIONS_OFFSET (10 * __SIZEOF_POINTER__)
#define SBI_SCRATCH_OPTIONS_OFFSET (13 * __SIZEOF_POINTER__)
/** Offset of extra space in sbi_scratch */
#define SBI_SCRATCH_EXTRA_SPACE_OFFSET (11 * __SIZEOF_POINTER__)
#define SBI_SCRATCH_EXTRA_SPACE_OFFSET (14 * __SIZEOF_POINTER__)
/** Maximum size of sbi_scratch (4KB) */
#define SBI_SCRATCH_SIZE (0x1000)
@@ -53,11 +59,17 @@ 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;
/** 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 */
unsigned long next_addr;
/** Priviledge mode of next booting stage for this HART */
/** Privilege mode of next booting stage for this HART */
unsigned long next_mode;
/** Warm boot entry point address for this HART */
unsigned long warmboot_addr;
@@ -163,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))
@@ -170,6 +185,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[];

View File

@@ -43,4 +43,38 @@ 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
*
* 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);
/**
* 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);
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);
#endif

View File

@@ -48,6 +48,24 @@ static inline void sbi_timer_udelay(ulong usecs)
sbi_timer_delay_loop(usecs, 1000000, NULL, NULL);
}
/**
* A blocking function that will wait until @p predicate returns true or
* @p timeout_ms milliseconds elapsed. @p arg will be passed as argument to
* @p predicate function.
*
* @param predicate Pointer to a function that returns true if certain
* condition is met. It shouldn't block the code execution.
* @param arg Argument to pass to @p predicate.
* @param timeout_ms Timeout value in milliseconds. The function will return
* false if @p timeout_ms time period elapsed but still @p predicate doesn't
* return true.
*
* @return true if @p predicate returns true within @p timeout_ms, false
* otherwise.
*/
bool sbi_timer_waitms_until(bool (*predicate)(void *), void *arg,
uint64_t timeout_ms);
/** Get timer value for current HART */
u64 sbi_timer_value(void);

View File

@@ -10,6 +10,8 @@
#ifndef __SBI_TRAP_H__
#define __SBI_TRAP_H__
#include <sbi/riscv_encoding.h>
/* clang-format off */
/** Index of zero member in sbi_trap_regs */
@@ -95,8 +97,10 @@
#define SBI_TRAP_INFO_tval2 3
/** Index of tinst member in sbi_trap_info */
#define SBI_TRAP_INFO_tinst 4
/** Index of gva member in sbi_trap_info */
#define SBI_TRAP_INFO_gva 5
/** Last member index in sbi_trap_info */
#define SBI_TRAP_INFO_last 5
#define SBI_TRAP_INFO_last 6
/* clang-format on */
@@ -200,8 +204,26 @@ struct sbi_trap_info {
unsigned long tval2;
/** tinst Trap instruction */
unsigned long tinst;
/** gva Guest virtual address in tval flag */
unsigned long gva;
};
static inline unsigned long sbi_regs_gva(const struct sbi_trap_regs *regs)
{
/*
* If the hypervisor extension is not implemented, mstatus[h].GVA is a
* WPRI field, which is guaranteed to read as zero. In addition, in this
* case we don't read mstatush and instead pretend it is zero, which
* handles privileged spec version < 1.12.
*/
#if __riscv_xlen == 32
return (regs->mstatusH & MSTATUSH_GVA) ? 1 : 0;
#else
return (regs->mstatus & MSTATUS_GVA) ? 1 : 0;
#endif
}
int sbi_trap_redirect(struct sbi_trap_regs *regs,
struct sbi_trap_info *trap);

View File

@@ -54,16 +54,22 @@ typedef unsigned long virtual_size_t;
typedef unsigned long physical_addr_t;
typedef unsigned long physical_size_t;
#define TRUE 1
#define FALSE 0
#define true TRUE
#define false FALSE
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
#define NULL ((void *)0)
#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)

View File

@@ -11,7 +11,7 @@
#define __SBI_VERSION_H__
#define OPENSBI_VERSION_MAJOR 1
#define OPENSBI_VERSION_MINOR 1
#define OPENSBI_VERSION_MINOR 3
/**
* OpenSBI 32-bit version with:

View File

@@ -13,6 +13,8 @@
#include <sbi/sbi_types.h>
#ifdef CONFIG_FDT_DOMAIN
struct sbi_domain;
/**
@@ -70,4 +72,11 @@ void fdt_domain_fixup(void *fdt);
*/
int fdt_domains_populate(void *fdt);
#else
static inline void fdt_domain_fixup(void *fdt) { }
static inline int fdt_domains_populate(void *fdt) { return 0; }
#endif
#endif /* __FDT_DOMAIN_H__ */

View File

@@ -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
*
@@ -70,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
*

View File

@@ -11,7 +11,7 @@
#define __FDT_HELPER_H__
#include <sbi/sbi_types.h>
#include <sbi/sbi_scratch.h>
#include <sbi/sbi_domain.h>
struct fdt_match {
const char *compatible;
@@ -59,14 +59,17 @@ int fdt_parse_timebase_frequency(void *fdt, unsigned long *freq);
int fdt_parse_gaisler_uart_node(void *fdt, int nodeoffset,
struct platform_uart_data *uart);
int fdt_parse_renesas_scif_node(void *fdt, int nodeoffset,
struct platform_uart_data *uart);
int fdt_parse_shakti_uart_node(void *fdt, int nodeoffset,
struct platform_uart_data *uart);
int fdt_parse_sifive_uart_node(void *fdt, int nodeoffset,
struct platform_uart_data *uart);
int fdt_parse_uart8250_node(void *fdt, int nodeoffset,
struct platform_uart_data *uart);
int fdt_parse_uart_node(void *fdt, int nodeoffset,
struct platform_uart_data *uart);
int fdt_parse_uart8250(void *fdt, struct platform_uart_data *uart,
const char *compatible);
@@ -95,12 +98,18 @@ int fdt_parse_aclint_node(void *fdt, int nodeoffset, bool for_timer,
unsigned long *out_addr2, unsigned long *out_size2,
u32 *out_first_hartid, u32 *out_hart_count);
int fdt_parse_plmt_node(void *fdt, int nodeoffset, unsigned long *plmt_base,
unsigned long *plmt_size, u32 *hart_count);
int fdt_parse_plicsw_node(void *fdt, int nodeoffset, unsigned long *plicsw_base,
unsigned long *size, u32 *hart_count);
int fdt_parse_compat_addr(void *fdt, uint64_t *addr,
const char *compatible);
static inline void *fdt_get_address(void)
{
return sbi_scratch_thishart_arg1_ptr();
return (void *)root.next_arg1;
}
#endif /* __FDT_HELPER_H__ */

View File

@@ -13,6 +13,8 @@
#include <sbi/sbi_types.h>
#ifdef CONFIG_FDT_PMU
/**
* Fix up the PMU node in the device tree
*
@@ -43,4 +45,12 @@ int fdt_pmu_setup(void *fdt);
*/
uint64_t fdt_pmu_get_select_value(uint32_t event_idx);
#else
static inline void fdt_pmu_fixup(void *fdt) { }
static inline int fdt_pmu_setup(void *fdt) { return 0; }
static inline uint64_t fdt_pmu_get_select_value(uint32_t event_idx) { return 0; }
#endif
#endif

View File

@@ -0,0 +1,21 @@
/*
* SPDX-License-Identifier: BSD-2-Clause
*
* Copyright (c) 2022 StarFive Technology Co., Ltd.
*
* Author: Minda Chen <minda.chen@starfivetech.com>
*/
#ifndef __DW_I2C_H__
#define __DW_I2C_H__
#include <sbi_utils/i2c/i2c.h>
int dw_i2c_init(struct i2c_adapter *, int nodeoff);
struct dw_i2c_adapter {
unsigned long addr;
struct i2c_adapter adapter;
};
#endif

View File

@@ -0,0 +1,46 @@
/*
* SPDX-License-Identifier: BSD-2-Clause
*
* Copyright (c) 2022 Andes Technology Corporation
*
* Authors:
* Zong Li <zong@andestech.com>
* Nylon Chen <nylon7@andestech.com>
* Leo Yu-Chi Liang <ycliang@andestech.com>
* Yu Chien Peter Lin <peterlin@andestech.com>
*/
#ifndef _IPI_ANDES_PLICSW_H_
#define _IPI_ANDES_PLICSW_H_
#define PLICSW_PRIORITY_BASE 0x4
#define PLICSW_PENDING_BASE 0x1000
#define PLICSW_PENDING_STRIDE 0x8
#define PLICSW_ENABLE_BASE 0x2000
#define PLICSW_ENABLE_STRIDE 0x80
#define PLICSW_CONTEXT_BASE 0x200000
#define PLICSW_CONTEXT_STRIDE 0x1000
#define PLICSW_CONTEXT_CLAIM 0x4
#define PLICSW_HART_MASK 0x01010101
#define PLICSW_HART_MAX_NR 8
#define PLICSW_REGION_ALIGN 0x1000
struct plicsw_data {
unsigned long addr;
unsigned long size;
uint32_t hart_count;
/* hart id to source id table */
uint32_t source_id[PLICSW_HART_MAX_NR];
};
int plicsw_warm_ipi_init(void);
int plicsw_cold_ipi_init(struct plicsw_data *plicsw);
#endif /* _IPI_ANDES_PLICSW_H_ */

View File

@@ -12,6 +12,8 @@
#include <sbi/sbi_types.h>
#ifdef CONFIG_FDT_IPI
struct fdt_ipi {
const struct fdt_match *match_table;
int (*cold_init)(void *fdt, int nodeoff, const struct fdt_match *match);
@@ -23,4 +25,11 @@ void fdt_ipi_exit(void);
int fdt_ipi_init(bool cold_boot);
#else
static inline void fdt_ipi_exit(void) { }
static inline int fdt_ipi_init(bool cold_boot) { return 0; }
#endif
#endif

View File

@@ -12,6 +12,8 @@
#include <sbi/sbi_types.h>
#ifdef CONFIG_FDT_IRQCHIP
struct fdt_irqchip {
const struct fdt_match *match_table;
int (*cold_init)(void *fdt, int nodeoff, const struct fdt_match *match);
@@ -23,4 +25,12 @@ void fdt_irqchip_exit(void);
int fdt_irqchip_init(bool cold_boot);
#else
static inline void fdt_irqchip_exit(void) { }
static inline int fdt_irqchip_init(bool cold_boot) { return 0; }
#endif
#endif

View File

@@ -9,13 +9,24 @@
#include <sbi/sbi_types.h>
void fdt_plic_priority_save(u8 *priority);
/**
* Save the PLIC priority state
* @param priority pointer to the memory region for the saved priority
* @param num size of the memory region including interrupt source 0
*/
void fdt_plic_priority_save(u8 *priority, u32 num);
void fdt_plic_priority_restore(const u8 *priority);
/**
* Restore the PLIC priority state
* @param priority pointer to the memory region for the saved priority
* @param num size of the memory region including interrupt source 0
*/
void fdt_plic_priority_restore(const u8 *priority, u32 num);
void fdt_plic_context_save(bool smode, u32 *enable, u32 *threshold);
void fdt_plic_context_save(bool smode, u32 *enable, u32 *threshold, u32 num);
void fdt_plic_context_restore(bool smode, const u32 *enable, u32 threshold);
void fdt_plic_context_restore(bool smode, const u32 *enable, u32 threshold,
u32 num);
void thead_plic_restore(void);

View File

@@ -33,6 +33,8 @@ struct imsic_data {
struct imsic_regs regs[IMSIC_MAX_REGS];
};
#ifdef CONFIG_IRQCHIP_IMSIC
int imsic_map_hartid_to_data(u32 hartid, struct imsic_data *imsic, int file);
struct imsic_data *imsic_get_data(u32 hartid);
@@ -47,4 +49,12 @@ int imsic_data_check(struct imsic_data *imsic);
int imsic_cold_irqchip_init(struct imsic_data *imsic);
#else
static inline void imsic_local_irqchip_init(void) { }
static inline int imsic_data_check(struct imsic_data *imsic) { return 0; }
#endif
#endif

View File

@@ -18,15 +18,16 @@ struct plic_data {
};
/* So far, priorities on all consumers of these functions fit in 8 bits. */
void plic_priority_save(const struct plic_data *plic, u8 *priority);
void plic_priority_save(const struct plic_data *plic, u8 *priority, u32 num);
void plic_priority_restore(const struct plic_data *plic, const u8 *priority);
void plic_priority_restore(const struct plic_data *plic, const u8 *priority,
u32 num);
void plic_context_save(const struct plic_data *plic, int context_id,
u32 *enable, u32 *threshold);
u32 *enable, u32 *threshold, u32 num);
void plic_context_restore(const struct plic_data *plic, int context_id,
const u32 *enable, u32 threshold);
const u32 *enable, u32 threshold, u32 num);
int plic_context_init(const struct plic_data *plic, int context_id,
bool enable, u32 threshold);

View File

@@ -17,6 +17,8 @@ struct fdt_reset {
int (*init)(void *fdt, int nodeoff, const struct fdt_match *match);
};
#ifdef CONFIG_FDT_RESET
/**
* fdt_reset_driver_init() - initialize reset driver based on the device-tree
*/
@@ -29,4 +31,14 @@ int fdt_reset_driver_init(void *fdt, struct fdt_reset *drv);
*/
void fdt_reset_init(void);
#else
static inline int fdt_reset_driver_init(void *fdt, struct fdt_reset *drv)
{
return 0;
}
static inline void fdt_reset_init(void) { }
#endif
#endif

View File

@@ -0,0 +1,16 @@
/*
* SPDX-License-Identifier: BSD-2-Clause
*
* Copyright (c) 2022 StarFive Technology Co., Ltd.
*
* Author: Jun Liang Tan <junliang.tan@linux.starfivetech.com>
*/
#ifndef __SERIAL_CADENCE_UART_H__
#define __SERIAL_CADENCE_UART_H__
#include <sbi/sbi_types.h>
int cadence_uart_init(unsigned long base, u32 in_freq, u32 baudrate);
#endif

View File

@@ -12,6 +12,8 @@
#include <sbi/sbi_types.h>
#ifdef CONFIG_FDT_SERIAL
struct fdt_serial {
const struct fdt_match *match_table;
int (*init)(void *fdt, int nodeoff, const struct fdt_match *match);
@@ -19,4 +21,10 @@ struct fdt_serial {
int fdt_serial_init(void);
#else
static inline int fdt_serial_init(void) { return 0; }
#endif
#endif

View File

@@ -0,0 +1,11 @@
/* SPDX-License-Identifier: BSD-2-Clause */
/*
* Copyright (C) 2022 Renesas Electronics Corporation
*/
#ifndef __SERIAL_RENESAS_SCIF_H__
#define __SERIAL_RENESAS_SCIF_H__
int renesas_scif_init(unsigned long base, u32 in_freq, u32 baudrate);
#endif /* __SERIAL_RENESAS_SCIF_H__ */

View File

@@ -0,0 +1,47 @@
/*
* SPDX-License-Identifier: BSD-2-Clause
*
* Copyright (c) 2022 Ventana Micro Systems Inc.
*
* Authors:
* Anup Patel <apatel@ventanamicro.com>
* Kautuk Consul <kconsul@ventanamicro.com>
*/
#ifndef __SERIAL_SEMIHOSTING_H__
#define __SERIAL_SEMIHOSTING_H__
#include <sbi/sbi_types.h>
/**
* enum semihosting_open_mode - Numeric file modes for use with semihosting_open()
* MODE_READ: 'r'
* MODE_BINARY: 'b'
* MODE_PLUS: '+'
* MODE_WRITE: 'w'
* MODE_APPEND: 'a'
*
* These modes represent the mode string used by fopen(3) in a form which can
* be passed to semihosting_open(). These do NOT correspond directly to %O_RDONLY,
* %O_CREAT, etc; see fopen(3) for details. In particular, @MODE_PLUS
* effectively results in adding %O_RDWR, and @MODE_WRITE will add %O_TRUNC.
* For compatibility, @MODE_BINARY should be added when opening non-text files
* (such as images).
*/
enum semihosting_open_mode {
MODE_READ = 0x0,
MODE_BINARY = 0x1,
MODE_PLUS = 0x2,
MODE_WRITE = 0x4,
MODE_APPEND = 0x8,
};
#ifdef CONFIG_SERIAL_SEMIHOSTING
int semihosting_init(void);
int semihosting_enabled(void);
#else
static inline int semihosting_init(void) { return SBI_ENODEV; }
static inline int semihosting_enabled(void) { return 0; }
#endif
#endif

View File

@@ -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 <sbi/sbi_types.h>
/* 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 */

View File

@@ -22,6 +22,8 @@
#define CLINT_MTIMER_OFFSET 0x4000
#define MTIMER_REGION_ALIGN 0x1000
struct aclint_mtimer_data {
/* Public details */
unsigned long mtime_freq;

View File

@@ -0,0 +1,29 @@
/*
* SPDX-License-Identifier: BSD-2-Clause
*
* Copyright (c) 2022 Andes Technology Corporation
*
* Authors:
* Zong Li <zong@andestech.com>
* Nylon Chen <nylon7@andestech.com>
* Yu Chien Peter Lin <peterlin@andestech.com>
*/
#ifndef __TIMER_ANDES_PLMT_H__
#define __TIMER_ANDES_PLMT_H__
#define DEFAULT_AE350_PLMT_FREQ 60000000
#define PLMT_REGION_ALIGN 0x1000
struct plmt_data {
u32 hart_count;
unsigned long size;
unsigned long timer_freq;
volatile u64 *time_val;
volatile u64 *time_cmp;
};
int plmt_cold_timer_init(struct plmt_data *plmt);
int plmt_warm_timer_init(void);
#endif /* __TIMER_ANDES_PLMT_H__ */

View File

@@ -12,6 +12,8 @@
#include <sbi/sbi_types.h>
#ifdef CONFIG_FDT_TIMER
struct fdt_timer {
const struct fdt_match *match_table;
int (*cold_init)(void *fdt, int nodeoff, const struct fdt_match *match);
@@ -23,4 +25,11 @@ void fdt_timer_exit(void);
int fdt_timer_init(bool cold_boot);
#else
static inline void fdt_timer_exit(void) { }
static inline int fdt_timer_init(bool cold_boot) { return 0; }
#endif
#endif

49
lib/sbi/Kconfig Normal file
View File

@@ -0,0 +1,49 @@
# SPDX-License-Identifier: BSD-2-Clause
menu "SBI Extension Support"
config SBI_ECALL_TIME
bool "Timer extension"
default y
config SBI_ECALL_RFENCE
bool "RFENCE extension"
default y
config SBI_ECALL_IPI
bool "IPI extension"
default y
config SBI_ECALL_HSM
bool "Hart State Management extension"
default y
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
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
config SBI_ECALL_VENDOR
bool "Platform-defined vendor extensions"
default y
endmenu

View File

@@ -12,20 +12,54 @@ libsbi-objs-y += riscv_atomic.o
libsbi-objs-y += riscv_hardfp.o
libsbi-objs-y += riscv_locks.o
libsbi-objs-y += sbi_ecall.o
libsbi-objs-y += sbi_ecall_exts.o
# The order of below extensions is performance optimized
carray-sbi_ecall_exts-$(CONFIG_SBI_ECALL_TIME) += ecall_time
libsbi-objs-$(CONFIG_SBI_ECALL_TIME) += sbi_ecall_time.o
carray-sbi_ecall_exts-$(CONFIG_SBI_ECALL_RFENCE) += ecall_rfence
libsbi-objs-$(CONFIG_SBI_ECALL_RFENCE) += sbi_ecall_rfence.o
carray-sbi_ecall_exts-$(CONFIG_SBI_ECALL_IPI) += ecall_ipi
libsbi-objs-$(CONFIG_SBI_ECALL_IPI) += sbi_ecall_ipi.o
carray-sbi_ecall_exts-y += ecall_base
libsbi-objs-y += sbi_ecall_base.o
carray-sbi_ecall_exts-$(CONFIG_SBI_ECALL_HSM) += ecall_hsm
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
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
carray-sbi_ecall_exts-$(CONFIG_SBI_ECALL_VENDOR) += ecall_vendor
libsbi-objs-$(CONFIG_SBI_ECALL_VENDOR) += sbi_ecall_vendor.o
libsbi-objs-y += sbi_bitmap.o
libsbi-objs-y += sbi_bitops.o
libsbi-objs-y += sbi_console.o
libsbi-objs-y += sbi_domain.o
libsbi-objs-y += sbi_ecall.o
libsbi-objs-y += sbi_ecall_base.o
libsbi-objs-y += sbi_ecall_hsm.o
libsbi-objs-y += sbi_ecall_legacy.o
libsbi-objs-y += sbi_ecall_pmu.o
libsbi-objs-y += sbi_ecall_replace.o
libsbi-objs-y += sbi_ecall_vendor.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
@@ -44,3 +78,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

View File

@@ -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

View File

@@ -12,17 +12,22 @@
#include <sbi/sbi_hart.h>
#include <sbi/sbi_platform.h>
#include <sbi/sbi_scratch.h>
#include <sbi/sbi_string.h>
#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)
{
if (((31 < c) && (c < 127)) || (c == '\f') || (c == '\r') ||
(c == '\n') || (c == '\t')) {
return TRUE;
return true;
}
return FALSE;
return false;
}
int sbi_getc(void)
@@ -41,16 +46,49 @@ void sbi_putc(char ch)
}
}
static unsigned long nputs(const char *str, unsigned long len)
{
unsigned long i, ret;
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;
}
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);
while (*str) {
sbi_putc(*str);
str++;
}
nputs_all(str, len);
spin_unlock(&console_out_lock);
}
unsigned long sbi_nputs(const char *str, unsigned long len)
{
unsigned long ret;
spin_lock(&console_out_lock);
ret = nputs(str, len);
spin_unlock(&console_out_lock);
return ret;
}
void sbi_gets(char *s, int maxwidth, char endchar)
{
int ch;
@@ -64,6 +102,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
@@ -76,20 +129,22 @@ typedef __builtin_va_list va_list;
static void printc(char **out, u32 *out_len, char ch)
{
if (out) {
if (*out) {
if (out_len && (0 < *out_len)) {
**out = ch;
++(*out);
(*out_len)--;
} else {
**out = ch;
++(*out);
}
}
} else {
if (!out) {
sbi_putc(ch);
return;
}
/*
* The *printf entry point functions have enforced that (*out) can
* only be null when out_len is non-null and its value is zero.
*/
if (!out_len || *out_len > 1) {
*(*out)++ = ch;
**out = '\0';
}
if (out_len && *out_len > 0)
--(*out_len);
}
static int prints(char **out, u32 *out_len, const char *string, int width,
@@ -181,19 +236,37 @@ 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, acnt = 0;
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;
if (*format == '\0')
break;
if (*format == '%')
goto out;
goto literal;
/* Get flags */
if (*format == '-') {
++format;
@@ -214,7 +287,6 @@ static int print(char **out, u32 *out_len, const char *format, va_list args)
}
if (*format == 's') {
char *s = va_arg(args, char *);
acnt += sizeof(char *);
pc += prints(out, out_len, s ? s : "(null)",
width, flags);
continue;
@@ -222,61 +294,40 @@ 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');
acnt += sizeof(int);
continue;
}
if (*format == 'x') {
pc += printi(out, out_len,
va_arg(args, unsigned int), 16, 0,
width, flags, 'a');
acnt += sizeof(unsigned int);
continue;
}
if (*format == 'X') {
pc += printi(out, out_len,
va_arg(args, unsigned int), 16, 0,
width, flags, 'A');
acnt += sizeof(unsigned int);
continue;
}
if (*format == 'u') {
pc += printi(out, out_len,
va_arg(args, unsigned int), 10, 0,
width, flags, 'a');
acnt += sizeof(unsigned int);
continue;
}
if (*format == 'p') {
pc += printi(out, out_len,
va_arg(args, unsigned long), 16, 0,
width, flags, 'a');
acnt += sizeof(unsigned long);
continue;
}
if (*format == 'P') {
pc += printi(out, out_len,
va_arg(args, unsigned long), 16, 0,
width, flags, 'A');
acnt += sizeof(unsigned long);
continue;
}
if (*format == 'l' && *(format + 1) == 'l') {
while (acnt &
(sizeof(unsigned long long) - 1)) {
va_arg(args, int);
acnt += sizeof(int);
}
if (sizeof(unsigned long long) ==
sizeof(unsigned long)) {
tmp = va_arg(args, unsigned long long);
acnt += sizeof(unsigned long long);
} else {
((unsigned long *)&tmp)[0] =
va_arg(args, unsigned long);
((unsigned long *)&tmp)[1] =
va_arg(args, unsigned long);
acnt += 2 * sizeof(unsigned long);
}
tmp = va_arg(args, unsigned long long);
if (*(format + 2) == 'u') {
format += 2;
pc += printi(out, out_len, tmp, 10, 0,
@@ -308,19 +359,16 @@ static int print(char **out, u32 *out_len, const char *format, va_list args)
out, out_len,
va_arg(args, unsigned long), 16,
0, width, flags, 'a');
acnt += sizeof(unsigned long);
} else if (*(format + 1) == 'X') {
format += 1;
pc += printi(
out, out_len,
va_arg(args, unsigned long), 16,
0, width, flags, 'A');
acnt += sizeof(unsigned long);
} else {
pc += printi(out, out_len,
va_arg(args, long), 10, 1,
width, flags, '0');
acnt += sizeof(long);
}
}
if (*format == 'c') {
@@ -328,17 +376,17 @@ static int print(char **out, u32 *out_len, const char *format, va_list args)
scr[0] = va_arg(args, int);
scr[1] = '\0';
pc += prints(out, out_len, scr, width, flags);
acnt += sizeof(int);
continue;
}
} else {
out:
literal:
printc(out, out_len, *format);
++pc;
}
}
if (out)
**out = '\0';
if (use_tbuf && console_tbuf_len < CONSOLE_TBUF_MAX)
nputs_all(console_tbuf, CONSOLE_TBUF_MAX - console_tbuf_len);
return pc;
}
@@ -348,6 +396,9 @@ int sbi_sprintf(char *out, const char *format, ...)
va_list args;
int retval;
if (unlikely(!out))
sbi_panic("sbi_sprintf called with NULL output string\n");
va_start(args, format);
retval = print(&out, NULL, format, args);
va_end(args);
@@ -360,6 +411,10 @@ int sbi_snprintf(char *out, u32 out_sz, const char *format, ...)
va_list args;
int retval;
if (unlikely(!out && out_sz != 0))
sbi_panic("sbi_snprintf called with NULL output string and "
"output size is not zero\n");
va_start(args, format);
retval = print(&out, &out_sz, format, args);
va_end(args);
@@ -426,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;
}

110
lib/sbi/sbi_cppc.c Normal file
View File

@@ -0,0 +1,110 @@
/*
* SPDX-License-Identifier: BSD-2-Clause
*
* Copyright (c) 2023 Ventana Micro Systems Inc.
*
*/
#include <sbi/sbi_error.h>
#include <sbi/sbi_cppc.h>
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);
}

View File

@@ -11,37 +11,63 @@
#include <sbi/sbi_console.h>
#include <sbi/sbi_domain.h>
#include <sbi/sbi_hartmask.h>
#include <sbi/sbi_heap.h>
#include <sbi/sbi_hsm.h>
#include <sbi/sbi_math.h>
#include <sbi/sbi_platform.h>
#include <sbi/sbi_scratch.h>
#include <sbi/sbi_string.h>
struct sbi_domain *hartid_to_domain_table[SBI_HARTMASK_MAX_BITS] = { 0 };
struct sbi_domain *domidx_to_domain_table[SBI_DOMAIN_MAX_INDEX] = { 0 };
/*
* 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 };
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_fw_region;
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,
.system_reset_allowed = TRUE,
.possible_harts = NULL,
.regions = NULL,
.system_reset_allowed = true,
.system_suspend_allowed = true,
.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)
return sbi_hartmask_test_hart(hartid, &dom->assigned_harts);
return FALSE;
return false;
}
ulong sbi_domain_get_assigned_hartmask(const struct sbi_domain *dom,
@@ -64,14 +90,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,
@@ -105,51 +123,64 @@ bool sbi_domain_check_addr(const struct sbi_domain *dom,
unsigned long addr, unsigned long mode,
unsigned long access_flags)
{
bool mmio = FALSE;
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;
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;
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) ?
rstart + ((1UL << reg->order) - 1) : -1UL;
if (rstart <= addr && addr <= rend) {
if ((mmio && !(rflags & SBI_DOMAIN_MEMREGION_MMIO)) ||
(!mmio && (rflags & SBI_DOMAIN_MEMREGION_MMIO)))
return FALSE;
return ((rflags & rwx) == rwx) ? TRUE : FALSE;
rmmio = (rflags & SBI_DOMAIN_MEMREGION_MMIO) ? true : false;
if (mmio != rmmio)
return false;
return ((rrwx & rwx) == rwx) ? true : false;
}
}
return (mode == PRV_M) ? TRUE : FALSE;
return (mode == PRV_M) ? true : false;
}
/* Check if region complies with constraints */
static bool is_region_valid(const struct sbi_domain_memregion *reg)
{
if (reg->order < 3 || __riscv_xlen < reg->order)
return FALSE;
return false;
if (reg->base & (BIT(reg->order) - 1))
return FALSE;
if (reg->order == __riscv_xlen && reg->base != 0)
return false;
return TRUE;
if (reg->order < __riscv_xlen && (reg->base & (BIT(reg->order) - 1)))
return false;
return true;
}
/** Check if regionA is sub-region of regionB */
@@ -165,9 +196,9 @@ static bool is_region_subset(const struct sbi_domain_memregion *regA,
(regA_start < regB_end) &&
(regB_start < regA_end) &&
(regA_end <= regB_end))
return TRUE;
return true;
return FALSE;
return false;
}
/** Check if regionA conflicts regionB */
@@ -176,9 +207,9 @@ static bool is_region_conflict(const struct sbi_domain_memregion *regA,
{
if ((is_region_subset(regA, regB) || is_region_subset(regB, regA)) &&
regA->flags == regB->flags)
return TRUE;
return true;
return FALSE;
return false;
}
/** Check if regionA should be placed before regionB */
@@ -186,20 +217,57 @@ static bool is_region_before(const struct sbi_domain_memregion *regA,
const struct sbi_domain_memregion *regB)
{
if (regA->order < regB->order)
return TRUE;
return true;
if ((regA->order == regB->order) &&
(regA->base < regB->base))
return TRUE;
return true;
return FALSE;
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)
{
u32 i, j, count;
bool have_fw_reg;
struct sbi_domain_memregion treg, *reg, *reg1;
/* Check possible HARTs */
@@ -214,7 +282,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) {
@@ -232,17 +300,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;
@@ -282,7 +346,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 &&
@@ -292,7 +356,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 "
@@ -303,6 +367,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;
@@ -332,15 +427,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_WRITEABLE)
if (reg->flags & SBI_DOMAIN_MEMREGION_M_WRITABLE)
sbi_printf("%cW", (k++) ? ',' : '(');
if (reg->flags & SBI_DOMAIN_MEMREGION_EXECUTABLE)
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_SU_WRITABLE)
sbi_printf("%cW", (k++) ? ',' : '(');
if (reg->flags & SBI_DOMAIN_MEMREGION_SU_EXECUTABLE)
sbi_printf("%cX", (k++) ? ',' : '(');
sbi_printf("%s\n", (k++) ? ")" : "()");
@@ -367,10 +472,13 @@ 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");
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)
@@ -434,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);
/*
@@ -464,8 +572,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;
@@ -480,10 +587,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 {
@@ -522,6 +629,33 @@ int sbi_domain_root_add_memregion(const struct sbi_domain_memregion *reg)
return 0;
}
int sbi_domain_root_add_memrange(unsigned long addr, unsigned long size,
unsigned long align, unsigned long region_flags)
{
int rc;
unsigned long pos, end, rsize;
struct sbi_domain_memregion reg;
pos = addr;
end = addr + size;
while (pos < end) {
rsize = pos & (align - 1);
if (rsize)
rsize = 1UL << sbi_ffs(pos);
else
rsize = ((end - pos) < align) ?
(end - pos) : align;
sbi_domain_memregion_init(pos, rsize, region_flags, &reg);
rc = sbi_domain_root_add_memregion(&reg);
if (rc)
return rc;
pos += rsize;
}
return 0;
}
int sbi_domain_finalize(struct sbi_scratch *scratch, u32 cold_hartid)
{
int rc;
@@ -586,12 +720,57 @@ 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 ||
(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;
}
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__);
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__);
rc = SBI_ENOMEM;
goto fail_free_root_memregs;
}
root.possible_harts = root_hmask;
/* Root domain firmware memory region */
sbi_domain_memregion_init(scratch->fw_start, scratch->fw_size, 0,
&root_fw_region);
domain_memregion_initfw(&root_memregs[root_memregs_count++]);
sbi_domain_memregion_init(scratch->fw_start, scratch->fw_rw_offset,
(SBI_DOMAIN_MEMREGION_M_READABLE |
SBI_DOMAIN_MEMREGION_M_EXECUTABLE),
&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.fw_region_inited = true;
/* Root domain allow everything memory region */
sbi_domain_memregion_init(0, ~0UL,
@@ -615,8 +794,21 @@ 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);
}
return sbi_domain_register(&root, &root_hmask);
/* Finally register the root domain */
rc = sbi_domain_register(&root, root_hmask);
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;
}

View File

@@ -13,6 +13,9 @@
#include <sbi/sbi_error.h>
#include <sbi/sbi_trap.h>
extern struct sbi_ecall_extension *sbi_ecall_exts[];
extern unsigned long sbi_ecall_exts_size;
u16 sbi_ecall_version_major(void)
{
return SBI_ECALL_VERSION_MAJOR;
@@ -75,7 +78,7 @@ int sbi_ecall_register_extension(struct sbi_ecall_extension *ext)
void sbi_ecall_unregister_extension(struct sbi_ecall_extension *ext)
{
bool found = FALSE;
bool found = false;
struct sbi_ecall_extension *t;
if (!ext)
@@ -83,7 +86,7 @@ void sbi_ecall_unregister_extension(struct sbi_ecall_extension *ext)
sbi_list_for_each_entry(t, &ecall_exts_list, head) {
if (t == ext) {
found = TRUE;
found = true;
break;
}
}
@@ -117,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) {
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);
@@ -144,35 +149,18 @@ int sbi_ecall_handler(struct sbi_trap_regs *regs)
int sbi_ecall_init(void)
{
int ret;
struct sbi_ecall_extension *ext;
unsigned long i;
/* The order of below registrations is performance optimized */
ret = sbi_ecall_register_extension(&ecall_time);
if (ret)
return ret;
ret = sbi_ecall_register_extension(&ecall_rfence);
if (ret)
return ret;
ret = sbi_ecall_register_extension(&ecall_ipi);
if (ret)
return ret;
ret = sbi_ecall_register_extension(&ecall_base);
if (ret)
return ret;
ret = sbi_ecall_register_extension(&ecall_hsm);
if (ret)
return ret;
ret = sbi_ecall_register_extension(&ecall_srst);
if (ret)
return ret;
ret = sbi_ecall_register_extension(&ecall_pmu);
if (ret)
return ret;
ret = sbi_ecall_register_extension(&ecall_legacy);
if (ret)
return ret;
ret = sbi_ecall_register_extension(&ecall_vendor);
if (ret)
return ret;
for (i = 0; i < sbi_ecall_exts_size; i++) {
ext = sbi_ecall_exts[i];
ret = SBI_ENODEV;
if (ext->register_extensions)
ret = ext->register_extensions();
if (ret)
return ret;
}
return 0;
}

View File

@@ -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,
};

67
lib/sbi/sbi_ecall_cppc.c Normal file
View File

@@ -0,0 +1,67 @@
/*
* SPDX-License-Identifier: BSD-2-Clause
*
* Copyright (c) 2023 Ventana Micro Systems Inc.
*
*/
#include <sbi/sbi_ecall.h>
#include <sbi/sbi_ecall_interface.h>
#include <sbi/sbi_error.h>
#include <sbi/sbi_trap.h>
#include <sbi/sbi_cppc.h>
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;
}
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);
}
struct sbi_ecall_extension ecall_cppc = {
.extid_start = SBI_EXT_CPPC,
.extid_end = SBI_EXT_CPPC,
.register_extensions = sbi_ecall_cppc_register_extensions,
.handle = sbi_ecall_cppc_handler,
};

79
lib/sbi/sbi_ecall_dbcn.c Normal file
View File

@@ -0,0 +1,79 @@
/*
* SPDX-License-Identifier: BSD-2-Clause
*
* Copyright (c) 2022 Ventana Micro Systems Inc.
*
* Authors:
* Anup Patel <apatel@ventanamicro.com>
*/
#include <sbi/sbi_console.h>
#include <sbi/sbi_domain.h>
#include <sbi/sbi_error.h>
#include <sbi/sbi_ecall.h>
#include <sbi/sbi_ecall_interface.h>
#include <sbi/sbi_trap.h>
#include <sbi/riscv_asm.h>
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.
*
* 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;
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;
}
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);
}
struct sbi_ecall_extension ecall_dbcn = {
.extid_start = SBI_EXT_DBCN,
.extid_end = SBI_EXT_DBCN,
.register_extensions = sbi_ecall_dbcn_register_extensions,
.handle = sbi_ecall_dbcn_handler,
};

View File

@@ -0,0 +1,3 @@
HEADER: sbi/sbi_ecall.h
TYPE: struct sbi_ecall_extension
NAME: sbi_ecall_exts

View File

@@ -12,7 +12,6 @@
#include <sbi/sbi_ecall_interface.h>
#include <sbi/sbi_error.h>
#include <sbi/sbi_trap.h>
#include <sbi/sbi_version.h>
#include <sbi/sbi_hsm.h>
#include <sbi/sbi_scratch.h>
#include <sbi/riscv_asm.h>
@@ -33,7 +32,7 @@ static int sbi_ecall_hsm_handler(unsigned long extid, unsigned long funcid,
regs->a0, regs->a1, smode, regs->a2);
break;
case SBI_EXT_HSM_HART_STOP:
ret = sbi_hsm_hart_stop(scratch, TRUE);
ret = sbi_hsm_hart_stop(scratch, true);
break;
case SBI_EXT_HSM_HART_GET_STATUS:
ret = sbi_hsm_hart_get_state(sbi_domain_thishart_ptr(),
@@ -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;
@@ -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,
};

44
lib/sbi/sbi_ecall_ipi.c Normal file
View File

@@ -0,0 +1,44 @@
/*
* SPDX-License-Identifier: BSD-2-Clause
*
* Copyright (c) 2020 Western Digital Corporation or its affiliates.
*
* Authors:
* Anup Patel <anup.patel@wdc.com>
* Atish Patra <atish.patra@wdc.com>
*/
#include <sbi/sbi_error.h>
#include <sbi/sbi_ecall.h>
#include <sbi/sbi_ecall_interface.h>
#include <sbi/sbi_trap.h>
#include <sbi/sbi_ipi.h>
static int sbi_ecall_ipi_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;
if (funcid == SBI_EXT_IPI_SEND_IPI)
ret = sbi_ipi_send_smode(regs->a0, regs->a1);
else
ret = SBI_ENOTSUPP;
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,
.register_extensions = sbi_ecall_ipi_register_extensions,
.handle = sbi_ecall_ipi_handler,
};

View File

@@ -112,13 +112,21 @@ static int sbi_ecall_legacy_handler(unsigned long extid, unsigned long funcid,
break;
default:
ret = SBI_ENOTSUPP;
};
}
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,
};

View File

@@ -51,7 +51,16 @@ static int sbi_ecall_pmu_handler(unsigned long extid, unsigned long funcid,
break;
case SBI_EXT_PMU_COUNTER_FW_READ:
ret = sbi_pmu_ctr_read(regs->a0, out_val);
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:
@@ -67,21 +76,21 @@ static int sbi_ecall_pmu_handler(unsigned long extid, unsigned long funcid,
break;
default:
ret = SBI_ENOTSUPP;
};
}
return ret;
}
static int sbi_ecall_pmu_probe(unsigned long extid, unsigned long *out_val)
struct sbi_ecall_extension ecall_pmu;
static int sbi_ecall_pmu_register_extensions(void)
{
/* PMU extension is always enabled */
*out_val = 1;
return 0;
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,
.handle = sbi_ecall_pmu_handler,
};

View File

@@ -9,40 +9,11 @@
*/
#include <sbi/riscv_asm.h>
#include <sbi/sbi_error.h>
#include <sbi/sbi_ecall.h>
#include <sbi/sbi_ecall_interface.h>
#include <sbi/sbi_error.h>
#include <sbi/sbi_hart.h>
#include <sbi/sbi_ipi.h>
#include <sbi/sbi_system.h>
#include <sbi/sbi_timer.h>
#include <sbi/sbi_tlb.h>
#include <sbi/sbi_trap.h>
static int sbi_ecall_time_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;
if (funcid == SBI_EXT_TIME_SET_TIMER) {
#if __riscv_xlen == 32
sbi_timer_event_start((((u64)regs->a1 << 32) | (u64)regs->a0));
#else
sbi_timer_event_start((u64)regs->a0);
#endif
} else
ret = SBI_ENOTSUPP;
return ret;
}
struct sbi_ecall_extension ecall_time = {
.extid_start = SBI_EXT_TIME,
.extid_end = SBI_EXT_TIME,
.handle = sbi_ecall_time_handler,
};
#include <sbi/sbi_tlb.h>
static int sbi_ecall_rfence_handler(unsigned long extid, unsigned long funcid,
const struct sbi_trap_regs *regs,
@@ -103,94 +74,21 @@ static int sbi_ecall_rfence_handler(unsigned long extid, unsigned long funcid,
break;
default:
ret = SBI_ENOTSUPP;
};
}
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,
};
static int sbi_ecall_ipi_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;
if (funcid == SBI_EXT_IPI_SEND_IPI)
ret = sbi_ipi_send_smode(regs->a0, regs->a1);
else
ret = SBI_ENOTSUPP;
return ret;
}
struct sbi_ecall_extension ecall_ipi = {
.extid_start = SBI_EXT_IPI,
.extid_end = SBI_EXT_IPI,
.handle = sbi_ecall_ipi_handler,
};
static int sbi_ecall_srst_handler(unsigned long extid, unsigned long funcid,
const struct sbi_trap_regs *regs,
unsigned long *out_val,
struct sbi_trap_info *out_trap)
{
if (funcid == SBI_EXT_SRST_RESET) {
if ((((u32)-1U) <= ((u64)regs->a0)) ||
(((u32)-1U) <= ((u64)regs->a1)))
return SBI_EINVAL;
switch (regs->a0) {
case SBI_SRST_RESET_TYPE_SHUTDOWN:
case SBI_SRST_RESET_TYPE_COLD_REBOOT:
case SBI_SRST_RESET_TYPE_WARM_REBOOT:
break;
default:
return SBI_EINVAL;
}
switch (regs->a1) {
case SBI_SRST_RESET_REASON_NONE:
case SBI_SRST_RESET_REASON_SYSFAIL:
break;
default:
return SBI_EINVAL;
}
if (sbi_system_reset_supported(regs->a0, regs->a1))
sbi_system_reset(regs->a0, regs->a1);
}
return SBI_ENOTSUPP;
}
static int sbi_ecall_srst_probe(unsigned long extid, unsigned long *out_val)
{
u32 type, count = 0;
/*
* 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))
count++;
}
*out_val = (count) ? 1 : 0;
return 0;
}
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_RFENCE,
.extid_end = SBI_EXT_RFENCE,
.register_extensions = sbi_ecall_rfence_register_extensions,
.handle = sbi_ecall_rfence_handler,
};

83
lib/sbi/sbi_ecall_srst.c Normal file
View File

@@ -0,0 +1,83 @@
/*
* SPDX-License-Identifier: BSD-2-Clause
*
* Copyright (c) 2020 Western Digital Corporation or its affiliates.
*
* Authors:
* Anup Patel <anup.patel@wdc.com>
* Atish Patra <atish.patra@wdc.com>
*/
#include <sbi/sbi_error.h>
#include <sbi/sbi_ecall.h>
#include <sbi/sbi_ecall_interface.h>
#include <sbi/sbi_trap.h>
#include <sbi/sbi_system.h>
static int sbi_ecall_srst_handler(unsigned long extid, unsigned long funcid,
const struct sbi_trap_regs *regs,
unsigned long *out_val,
struct sbi_trap_info *out_trap)
{
if (funcid == SBI_EXT_SRST_RESET) {
if ((((u32)-1U) <= ((u64)regs->a0)) ||
(((u32)-1U) <= ((u64)regs->a1)))
return SBI_EINVAL;
switch (regs->a0) {
case SBI_SRST_RESET_TYPE_SHUTDOWN:
case SBI_SRST_RESET_TYPE_COLD_REBOOT:
case SBI_SRST_RESET_TYPE_WARM_REBOOT:
break;
default:
return SBI_EINVAL;
}
switch (regs->a1) {
case SBI_SRST_RESET_REASON_NONE:
case SBI_SRST_RESET_REASON_SYSFAIL:
break;
default:
return SBI_EINVAL;
}
if (sbi_system_reset_supported(regs->a0, regs->a1))
sbi_system_reset(regs->a0, regs->a1);
}
return SBI_ENOTSUPP;
}
static bool srst_available(void)
{
u32 type;
/*
* 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))
return true;
}
return false;
}
struct sbi_ecall_extension ecall_srst;
static int sbi_ecall_srst_register_extensions(void)
{
if (!srst_available())
return 0;
return sbi_ecall_register_extension(&ecall_srst);
}
struct sbi_ecall_extension ecall_srst = {
.extid_start = SBI_EXT_SRST,
.extid_end = SBI_EXT_SRST,
.register_extensions = sbi_ecall_srst_register_extensions,
.handle = sbi_ecall_srst_handler,
};

57
lib/sbi/sbi_ecall_susp.c Normal file
View File

@@ -0,0 +1,57 @@
// SPDX-License-Identifier: BSD-2-Clause
#include <sbi/sbi_ecall.h>
#include <sbi/sbi_ecall_interface.h>
#include <sbi/sbi_error.h>
#include <sbi/sbi_trap.h>
#include <sbi/sbi_system.h>
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 bool susp_available(void)
{
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))
return true;
}
return false;
}
struct sbi_ecall_extension ecall_susp;
static int sbi_ecall_susp_register_extensions(void)
{
if (!susp_available())
return 0;
return sbi_ecall_register_extension(&ecall_susp);
}
struct sbi_ecall_extension ecall_susp = {
.extid_start = SBI_EXT_SUSP,
.extid_end = SBI_EXT_SUSP,
.register_extensions = sbi_ecall_susp_register_extensions,
.handle = sbi_ecall_susp_handler,
};

48
lib/sbi/sbi_ecall_time.c Normal file
View File

@@ -0,0 +1,48 @@
/*
* SPDX-License-Identifier: BSD-2-Clause
*
* Copyright (c) 2020 Western Digital Corporation or its affiliates.
*
* Authors:
* Anup Patel <anup.patel@wdc.com>
* Atish Patra <atish.patra@wdc.com>
*/
#include <sbi/sbi_error.h>
#include <sbi/sbi_ecall.h>
#include <sbi/sbi_ecall_interface.h>
#include <sbi/sbi_trap.h>
#include <sbi/sbi_timer.h>
static int sbi_ecall_time_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;
if (funcid == SBI_EXT_TIME_SET_TIMER) {
#if __riscv_xlen == 32
sbi_timer_event_start((((u64)regs->a1 << 32) | (u64)regs->a0));
#else
sbi_timer_event_start((u64)regs->a0);
#endif
} else
ret = SBI_ENOTSUPP;
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,
.register_extensions = sbi_ecall_time_register_extensions,
.handle = sbi_ecall_time_handler,
};

View File

@@ -13,13 +13,13 @@
#include <sbi/sbi_error.h>
#include <sbi/sbi_platform.h>
#include <sbi/sbi_trap.h>
#include <sbi/riscv_asm.h>
static int sbi_ecall_vendor_probe(unsigned long extid,
unsigned long *out_val)
static inline unsigned long sbi_ecall_vendor_id(void)
{
*out_val = sbi_platform_vendor_ext_check(sbi_platform_thishart_ptr(),
extid);
return 0;
return SBI_EXT_VENDOR_START +
(csr_read(CSR_MVENDORID) &
(SBI_EXT_VENDOR_END - SBI_EXT_VENDOR_START));
}
static int sbi_ecall_vendor_handler(unsigned long extid, unsigned long funcid,
@@ -28,13 +28,28 @@ static int sbi_ecall_vendor_handler(unsigned long extid, unsigned long funcid,
struct sbi_trap_info *out_trap)
{
return sbi_platform_vendor_ext_provider(sbi_platform_thishart_ptr(),
extid, funcid, regs,
funcid, regs,
out_val, out_trap);
}
struct sbi_ecall_extension ecall_vendor;
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;
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,
.handle = sbi_ecall_vendor_handler,
};

View File

@@ -39,7 +39,7 @@ static bool hpm_allowed(int hpm_num, ulong prev_mode, bool virt)
cen = 0;
}
return ((cen >> hpm_num) & 1) ? TRUE : FALSE;
return ((cen >> hpm_num) & 1) ? true : false;
}
int sbi_emulate_csr_read(int csr_num, struct sbi_trap_regs *regs,
@@ -49,9 +49,9 @@ int sbi_emulate_csr_read(int csr_num, struct sbi_trap_regs *regs,
struct sbi_scratch *scratch = sbi_scratch_thishart_ptr();
ulong prev_mode = (regs->mstatus & MSTATUS_MPP) >> MSTATUS_MPP_SHIFT;
#if __riscv_xlen == 32
bool virt = (regs->mstatusH & MSTATUSH_MPV) ? TRUE : FALSE;
bool virt = (regs->mstatusH & MSTATUSH_MPV) ? true : false;
#else
bool virt = (regs->mstatus & MSTATUS_MPV) ? TRUE : FALSE;
bool virt = (regs->mstatus & MSTATUS_MPV) ? true : false;
#endif
switch (csr_num) {
@@ -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",
@@ -164,9 +164,9 @@ int sbi_emulate_csr_write(int csr_num, struct sbi_trap_regs *regs,
int ret = 0;
ulong prev_mode = (regs->mstatus & MSTATUS_MPP) >> MSTATUS_MPP_SHIFT;
#if __riscv_xlen == 32
bool virt = (regs->mstatusH & MSTATUSH_MPV) ? TRUE : FALSE;
bool virt = (regs->mstatusH & MSTATUSH_MPV) ? true : false;
#else
bool virt = (regs->mstatus & MSTATUS_MPV) ? TRUE : FALSE;
bool virt = (regs->mstatus & MSTATUS_MPV) ? true : false;
#endif
switch (csr_num) {
@@ -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",

View File

@@ -11,7 +11,7 @@
#include <sbi/sbi_trap.h>
/*
* We assume that faulting instruction is is 4-byte long and blindly
* We assume that faulting instruction is 4-byte long and blindly
* increment SEPC by 4.
*
* The trap info will be saved as follows:
@@ -22,7 +22,7 @@
.align 3
.global __sbi_expected_trap
__sbi_expected_trap:
/* Without H-extension so, MTVAL2 and MTINST CSRs not available */
/* Without H-extension so, MTVAL2 and MTINST CSRs and GVA not available */
csrr a4, CSR_MEPC
REG_S a4, SBI_TRAP_INFO_OFFSET(epc)(a3)
csrr a4, CSR_MCAUSE
@@ -31,6 +31,7 @@ __sbi_expected_trap:
REG_S a4, SBI_TRAP_INFO_OFFSET(tval)(a3)
REG_S zero, SBI_TRAP_INFO_OFFSET(tval2)(a3)
REG_S zero, SBI_TRAP_INFO_OFFSET(tinst)(a3)
REG_S zero, SBI_TRAP_INFO_OFFSET(gva)(a3)
csrr a4, CSR_MEPC
addi a4, a4, 4
csrw CSR_MEPC, a4
@@ -39,7 +40,7 @@ __sbi_expected_trap:
.align 3
.global __sbi_expected_trap_hext
__sbi_expected_trap_hext:
/* With H-extension so, MTVAL2 and MTINST CSRs available */
/* With H-extension so, MTVAL2 and MTINST CSRs and GVA available */
csrr a4, CSR_MEPC
REG_S a4, SBI_TRAP_INFO_OFFSET(epc)(a3)
csrr a4, CSR_MCAUSE
@@ -50,6 +51,18 @@ __sbi_expected_trap_hext:
REG_S a4, SBI_TRAP_INFO_OFFSET(tval2)(a3)
csrr a4, CSR_MTINST
REG_S a4, SBI_TRAP_INFO_OFFSET(tinst)(a3)
/* Extract GVA bit from MSTATUS or MSTATUSH */
#if __riscv_xlen == 32
csrr a4, CSR_MSTATUSH
srli a4, a4, MSTATUSH_GVA_SHIFT
#else
csrr a4, CSR_MSTATUS
srli a4, a4, MSTATUS_GVA_SHIFT
#endif
andi a4, a4, 1
REG_S a4, SBI_TRAP_INFO_OFFSET(gva)(a3)
csrr a4, CSR_MEPC
addi a4, a4, 4
csrw CSR_MEPC, a4

View File

@@ -26,7 +26,7 @@ void sbi_fifo_init(struct sbi_fifo *fifo, void *queue_mem, u16 entries,
/* Note: must be called with fifo->qlock held */
static inline bool __sbi_fifo_is_full(struct sbi_fifo *fifo)
{
return (fifo->avail == fifo->num_entries) ? TRUE : FALSE;
return (fifo->avail == fifo->num_entries) ? true : false;
}
u16 sbi_fifo_avail(struct sbi_fifo *fifo)
@@ -75,7 +75,7 @@ static inline void __sbi_fifo_enqueue(struct sbi_fifo *fifo, void *data)
/* Note: must be called with fifo->qlock held */
static inline bool __sbi_fifo_is_empty(struct sbi_fifo *fifo)
{
return (fifo->avail == 0) ? TRUE : FALSE;
return (fifo->avail == 0) ? true : false;
}
int sbi_fifo_is_empty(struct sbi_fifo *fifo)
@@ -105,13 +105,13 @@ static inline void __sbi_fifo_reset(struct sbi_fifo *fifo)
bool sbi_fifo_reset(struct sbi_fifo *fifo)
{
if (!fifo)
return FALSE;
return false;
spin_lock(&fifo->qlock);
__sbi_fifo_reset(fifo);
spin_unlock(&fifo->qlock);
return TRUE;
return true;
}
/**

View File

@@ -19,24 +19,16 @@
#include <sbi/sbi_hart.h>
#include <sbi/sbi_math.h>
#include <sbi/sbi_platform.h>
#include <sbi/sbi_pmu.h>
#include <sbi/sbi_string.h>
#include <sbi/sbi_trap.h>
#include <sbi/sbi_hfence.h>
extern void __sbi_expected_trap(void);
extern void __sbi_expected_trap_hext(void);
void (*sbi_hart_expected_trap)(void) = &__sbi_expected_trap;
struct hart_features {
bool detected;
int priv_version;
unsigned long extensions;
unsigned int pmp_count;
unsigned int pmp_addr_bits;
unsigned long pmp_gran;
unsigned int mhpm_count;
unsigned int mhpm_bits;
};
static unsigned long hart_features_offset;
static void mstatus_init(struct sbi_scratch *scratch)
@@ -98,9 +90,10 @@ 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_AIA))
if (sbi_hart_has_extension(scratch, SBI_HART_EXT_SMAIA))
mstateen_val |= (SMSTATEEN0_AIA | SMSTATEEN0_SVSLCT |
SMSTATEEN0_IMSIC);
else
@@ -208,8 +201,7 @@ static int delegate_traps(struct sbi_scratch *scratch)
/* Send M-mode interrupts and most exceptions to S-mode */
interrupts = MIP_SSIP | MIP_STIP | MIP_SEIP;
if (sbi_hart_has_extension(scratch, SBI_HART_EXT_SSCOFPMF))
interrupts |= MIP_LCOFIP;
interrupts |= sbi_pmu_irq_bit();
exceptions = (1U << CAUSE_MISALIGNED_FETCH) | (1U << CAUSE_BREAKPOINT) |
(1U << CAUSE_USER_ECALL);
@@ -254,7 +246,7 @@ void sbi_hart_delegation_dump(struct sbi_scratch *scratch,
unsigned int sbi_hart_mhpm_count(struct sbi_scratch *scratch)
{
struct hart_features *hfeatures =
struct sbi_hart_features *hfeatures =
sbi_scratch_offset_ptr(scratch, hart_features_offset);
return hfeatures->mhpm_count;
@@ -262,7 +254,7 @@ unsigned int sbi_hart_mhpm_count(struct sbi_scratch *scratch)
unsigned int sbi_hart_pmp_count(struct sbi_scratch *scratch)
{
struct hart_features *hfeatures =
struct sbi_hart_features *hfeatures =
sbi_scratch_offset_ptr(scratch, hart_features_offset);
return hfeatures->pmp_count;
@@ -270,7 +262,7 @@ unsigned int sbi_hart_pmp_count(struct sbi_scratch *scratch)
unsigned long sbi_hart_pmp_granularity(struct sbi_scratch *scratch)
{
struct hart_features *hfeatures =
struct sbi_hart_features *hfeatures =
sbi_scratch_offset_ptr(scratch, hart_features_offset);
return hfeatures->pmp_gran;
@@ -278,7 +270,7 @@ unsigned long sbi_hart_pmp_granularity(struct sbi_scratch *scratch)
unsigned int sbi_hart_pmp_addrbits(struct sbi_scratch *scratch)
{
struct hart_features *hfeatures =
struct sbi_hart_features *hfeatures =
sbi_scratch_offset_ptr(scratch, hart_features_offset);
return hfeatures->pmp_addr_bits;
@@ -286,7 +278,7 @@ unsigned int sbi_hart_pmp_addrbits(struct sbi_scratch *scratch)
unsigned int sbi_hart_mhpm_bits(struct sbi_scratch *scratch)
{
struct hart_features *hfeatures =
struct sbi_hart_features *hfeatures =
sbi_scratch_offset_ptr(scratch, hart_features_offset);
return hfeatures->mhpm_bits;
@@ -312,15 +304,21 @@ int sbi_hart_pmp_configure(struct sbi_scratch *scratch)
break;
pmp_flags = 0;
if (reg->flags & SBI_DOMAIN_MEMREGION_READABLE)
pmp_flags |= PMP_R;
if (reg->flags & SBI_DOMAIN_MEMREGION_WRITEABLE)
pmp_flags |= PMP_W;
if (reg->flags & SBI_DOMAIN_MEMREGION_EXECUTABLE)
pmp_flags |= PMP_X;
if (reg->flags & SBI_DOMAIN_MEMREGION_MMODE)
/*
* 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)
pmp_set(pmp_idx++, pmp_flags, reg->base, reg->order);
@@ -331,12 +329,33 @@ int sbi_hart_pmp_configure(struct sbi_scratch *scratch)
}
}
/*
* As per section 3.7.2 of privileged specification v1.12,
* virtual address translations can be speculatively performed
* (even before actual access). These, along with PMP traslations,
* can be cached. This can pose a problem with CPU hotplug
* and non-retentive suspend scenario because PMP states are
* not preserved.
* It is advisable to flush the caching structures under such
* conditions.
*/
if (misa_extension('S')) {
__asm__ __volatile__("sfence.vma");
/*
* If hypervisor mode is supported, flush caching
* structures in guest mode too.
*/
if (misa_extension('H'))
__sbi_hfence_gvma_all();
}
return 0;
}
int sbi_hart_priv_version(struct sbi_scratch *scratch)
{
struct hart_features *hfeatures =
struct sbi_hart_features *hfeatures =
sbi_scratch_offset_ptr(scratch, hart_features_offset);
return hfeatures->priv_version;
@@ -346,7 +365,7 @@ void sbi_hart_get_priv_version_str(struct sbi_scratch *scratch,
char *version_str, int nvstr)
{
char *temp;
struct hart_features *hfeatures =
struct sbi_hart_features *hfeatures =
sbi_scratch_offset_ptr(scratch, hart_features_offset);
switch (hfeatures->priv_version) {
@@ -368,7 +387,7 @@ void sbi_hart_get_priv_version_str(struct sbi_scratch *scratch,
}
static inline void __sbi_hart_update_extension(
struct hart_features *hfeatures,
struct sbi_hart_features *hfeatures,
enum sbi_hart_extensions ext,
bool enable)
{
@@ -389,7 +408,7 @@ void sbi_hart_update_extension(struct sbi_scratch *scratch,
enum sbi_hart_extensions ext,
bool enable)
{
struct hart_features *hfeatures =
struct sbi_hart_features *hfeatures =
sbi_scratch_offset_ptr(scratch, hart_features_offset);
__sbi_hart_update_extension(hfeatures, ext, enable);
@@ -405,7 +424,7 @@ void sbi_hart_update_extension(struct sbi_scratch *scratch,
bool sbi_hart_has_extension(struct sbi_scratch *scratch,
enum sbi_hart_extensions ext)
{
struct hart_features *hfeatures =
struct sbi_hart_features *hfeatures =
sbi_scratch_offset_ptr(scratch, hart_features_offset);
if (hfeatures->extensions & BIT(ext))
@@ -425,8 +444,8 @@ static inline char *sbi_hart_extension_id2string(int ext)
case SBI_HART_EXT_TIME:
estr = "time";
break;
case SBI_HART_EXT_AIA:
estr = "aia";
case SBI_HART_EXT_SMAIA:
estr = "smaia";
break;
case SBI_HART_EXT_SSTC:
estr = "sstc";
@@ -453,7 +472,7 @@ static inline char *sbi_hart_extension_id2string(int ext)
void sbi_hart_get_extensions_str(struct sbi_scratch *scratch,
char *extensions_str, int nestr)
{
struct hart_features *hfeatures =
struct sbi_hart_features *hfeatures =
sbi_scratch_offset_ptr(scratch, hart_features_offset);
int offset = 0, ext = 0;
char *temp;
@@ -539,7 +558,7 @@ static int hart_pmu_get_allowed_bits(void)
static int hart_detect_features(struct sbi_scratch *scratch)
{
struct sbi_trap_info trap = {0};
struct hart_features *hfeatures =
struct sbi_hart_features *hfeatures =
sbi_scratch_offset_ptr(scratch, hart_features_offset);
unsigned long val, oldval;
int rc;
@@ -663,7 +682,7 @@ __mhpm_skip:
csr_read_allowed(CSR_MTOPI, (unsigned long)&trap);
if (!trap.cause)
__sbi_hart_update_extension(hfeatures,
SBI_HART_EXT_AIA, true);
SBI_HART_EXT_SMAIA, true);
/* Detect if hart supports stimecmp CSR(Sstc extension) */
if (hfeatures->priv_version >= SBI_HART_PRIV_VER_1_12) {
@@ -682,7 +701,8 @@ __mhpm_skip:
}
/* Let platform populate extensions */
rc = sbi_platform_extensions_init(sbi_platform_thishart_ptr());
rc = sbi_platform_extensions_init(sbi_platform_thishart_ptr(),
hfeatures);
if (rc)
return rc;
@@ -713,12 +733,18 @@ 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;
hart_features_offset = sbi_scratch_alloc_offset(
sizeof(struct hart_features));
sizeof(struct sbi_hart_features));
if (!hart_features_offset)
return SBI_ENOMEM;
}
@@ -769,19 +795,12 @@ sbi_hart_switch_mode(unsigned long arg0, unsigned long arg1,
#if __riscv_xlen == 32
if (misa_extension('H')) {
valH = csr_read(CSR_MSTATUSH);
if (next_virt)
valH = INSERT_FIELD(valH, MSTATUSH_MPV, 1);
else
valH = INSERT_FIELD(valH, MSTATUSH_MPV, 0);
valH = INSERT_FIELD(valH, MSTATUSH_MPV, next_virt);
csr_write(CSR_MSTATUSH, valH);
}
#else
if (misa_extension('H')) {
if (next_virt)
val = INSERT_FIELD(val, MSTATUS_MPV, 1);
else
val = INSERT_FIELD(val, MSTATUS_MPV, 0);
}
if (misa_extension('H'))
val = INSERT_FIELD(val, MSTATUS_MPV, next_virt);
#endif
csr_write(CSR_MSTATUS, val);
csr_write(CSR_MEPC, next_addr);

206
lib/sbi/sbi_heap.c Normal file
View File

@@ -0,0 +1,206 @@
/*
* SPDX-License-Identifier: BSD-2-Clause
*
* Copyright (c) 2023 Ventana Micro Systems Inc.
*
* Authors:
* Anup Patel<apatel@ventanamicro.com>
*/
#include <sbi/riscv_locks.h>
#include <sbi/sbi_error.h>
#include <sbi/sbi_heap.h>
#include <sbi/sbi_list.h>
#include <sbi/sbi_scratch.h>
#include <sbi/sbi_string.h>
/* 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;
}

View File

@@ -26,6 +26,15 @@
#include <sbi/sbi_timer.h>
#include <sbi/sbi_console.h>
#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;
@@ -35,9 +44,18 @@ struct sbi_hsm_data {
unsigned long suspend_type;
unsigned long saved_mie;
unsigned long saved_mip;
atomic_t start_ticket;
};
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;
@@ -58,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
@@ -93,16 +137,25 @@ 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)
{
u32 oldstate;
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);
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();
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)
@@ -116,10 +169,10 @@ 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();
};
}
/* Restore MIE CSR */
csr_write(CSR_MIE, saved_mie);
@@ -207,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);
@@ -217,20 +271,17 @@ 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()) {
hsm_device_hart_stop();
/* It should never reach here */
goto fail_exit;
if (hsm_device_hart_stop() != SBI_ENOTSUPP)
goto fail_exit;
}
/**
@@ -248,12 +299,13 @@ fail_exit:
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 long init_count, entry_count;
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)
@@ -267,37 +319,55 @@ 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);
entry_count = sbi_entry_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 = priv;
rscratch->next_addr = saddr;
rscratch->next_mode = smode;
if (hsm_device_has_hart_hotplug() ||
(hsm_device_has_hart_secondary_boot() && !init_count)) {
return hsm_device_hart_start(hartid, scratch->warmboot_addr);
} else {
sbi_ipi_raw_send(hartid);
if (hstate != SBI_HSM_STATE_STOPPED) {
rc = SBI_EINVAL;
goto err;
}
return 0;
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 {
rc = sbi_ipi_raw_send(hartid);
}
if (!rc)
return 0;
err:
hsm_start_ticket_release(hdata);
return rc;
}
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);
@@ -305,13 +375,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);
@@ -327,7 +393,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);
@@ -356,62 +422,55 @@ 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)
{
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)
void __noreturn sbi_hsm_hart_resume_finish(struct sbi_scratch *scratch,
u32 hartid)
{
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
* 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,
ulong raddr, ulong rmode, ulong priv)
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);
/* For now, we only allow suspend from S-mode or U-mode. */
/* 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 &&
@@ -423,27 +482,26 @@ 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_EINVAL;
return SBI_EFAIL;
if (dom && !sbi_domain_check_addr(dom, raddr, rmode,
SBI_DOMAIN_EXECUTE))
return SBI_EINVALID_ADDR;
}
/* Save the resume address and resume mode */
scratch->next_arg1 = priv;
scratch->next_arg1 = arg1;
scratch->next_addr = raddr;
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);
ret = SBI_EDENIED;
goto fail_restore_state;
}
if (!__sbi_hsm_hart_change_state(hdata, SBI_HSM_STATE_STARTED,
SBI_HSM_STATE_SUSPENDED))
return SBI_EFAIL;
/* Save the suspend type */
hdata->suspend_type = suspend_type;
@@ -478,18 +536,13 @@ 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.
*/
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;
}

View File

@@ -30,6 +30,7 @@ static int truly_illegal_insn(ulong insn, struct sbi_trap_regs *regs)
trap.tval = insn;
trap.tval2 = 0;
trap.tinst = 0;
trap.gva = 0;
return sbi_trap_redirect(regs, &trap);
}
@@ -39,6 +40,7 @@ static int misc_mem_opcode_insn(ulong insn, struct sbi_trap_regs *regs)
/* Errata workaround: emulate `fence.tso` as `fence rw, rw`. */
if ((insn & INSN_MASK_FENCE_TSO) == INSN_MATCH_FENCE_TSO) {
smp_mb();
regs->mepc += 4;
return 0;
}
@@ -88,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);

View File

@@ -12,10 +12,12 @@
#include <sbi/riscv_barrier.h>
#include <sbi/riscv_locks.h>
#include <sbi/sbi_console.h>
#include <sbi/sbi_cppc.h>
#include <sbi/sbi_domain.h>
#include <sbi/sbi_ecall.h>
#include <sbi/sbi_hart.h>
#include <sbi/sbi_hartmask.h>
#include <sbi/sbi_heap.h>
#include <sbi/sbi_hsm.h>
#include <sbi/sbi_ipi.h>
#include <sbi/sbi_irqchip.h>
@@ -63,11 +65,14 @@ static void sbi_boot_print_banner(struct sbi_scratch *scratch)
static void sbi_boot_print_general(struct sbi_scratch *scratch)
{
char str[128];
const struct sbi_pmu_device *pdev;
const struct sbi_hsm_device *hdev;
const struct sbi_ipi_device *idev;
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_cppc_device *cppc_dev;
const struct sbi_platform *plat = sbi_platform_ptr(scratch);
if (scratch->options & SBI_SCRATCH_NO_BOOT_PRINTS)
@@ -93,17 +98,41 @@ static void sbi_boot_print_general(struct sbi_scratch *scratch)
hdev = sbi_hsm_get_device();
sbi_printf("Platform HSM Device : %s\n",
(hdev) ? hdev->name : "---");
pdev = sbi_pmu_get_device();
sbi_printf("Platform PMU Device : %s\n",
(pdev) ? pdev->name : "---");
srdev = sbi_system_reset_get_device(SBI_SRST_RESET_TYPE_COLD_REBOOT, 0);
sbi_printf("Platform Reboot Device : %s\n",
(srdev) ? srdev->name : "---");
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 : "---");
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);
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_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",
@@ -186,7 +215,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);
@@ -229,12 +258,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 */
@@ -243,23 +273,35 @@ 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();
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();
rc = sbi_hsm_init(scratch, hartid, TRUE);
count = sbi_scratch_offset_ptr(scratch, entry_count_offset);
(*count)++;
rc = sbi_hsm_init(scratch, hartid, true);
if (rc)
sbi_hart_hang();
rc = sbi_platform_early_init(plat, TRUE);
rc = sbi_platform_early_init(plat, true);
if (rc)
sbi_hart_hang();
rc = sbi_hart_init(scratch, TRUE);
rc = sbi_hart_init(scratch, true);
if (rc)
sbi_hart_hang();
@@ -267,43 +309,40 @@ static void __noreturn init_coldboot(struct sbi_scratch *scratch, u32 hartid)
if (rc)
sbi_hart_hang();
rc = sbi_pmu_init(scratch, TRUE);
if (rc)
rc = sbi_pmu_init(scratch, true);
if (rc) {
sbi_printf("%s: pmu init failed (error %d)\n",
__func__, rc);
sbi_hart_hang();
}
sbi_boot_print_banner(scratch);
rc = sbi_irqchip_init(scratch, TRUE);
rc = sbi_irqchip_init(scratch, true);
if (rc) {
sbi_printf("%s: irqchip init failed (error %d)\n",
__func__, rc);
sbi_hart_hang();
}
rc = sbi_ipi_init(scratch, TRUE);
rc = sbi_ipi_init(scratch, true);
if (rc) {
sbi_printf("%s: ipi init failed (error %d)\n", __func__, rc);
sbi_hart_hang();
}
rc = sbi_tlb_init(scratch, TRUE);
rc = sbi_tlb_init(scratch, true);
if (rc) {
sbi_printf("%s: tlb init failed (error %d)\n", __func__, rc);
sbi_hart_hang();
}
rc = sbi_timer_init(scratch, TRUE);
rc = sbi_timer_init(scratch, true);
if (rc) {
sbi_printf("%s: timer init failed (error %d)\n", __func__, rc);
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.
@@ -325,16 +364,28 @@ 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);
rc = sbi_platform_final_init(plat, true);
if (rc) {
sbi_printf("%s: platform final init failed (error %d)\n",
__func__, rc);
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);
@@ -343,52 +394,54 @@ 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_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;
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();
rc = sbi_hsm_init(scratch, hartid, FALSE);
count = sbi_scratch_offset_ptr(scratch, entry_count_offset);
(*count)++;
rc = sbi_hsm_init(scratch, hartid, false);
if (rc)
sbi_hart_hang();
rc = sbi_platform_early_init(plat, FALSE);
rc = sbi_platform_early_init(plat, false);
if (rc)
sbi_hart_hang();
rc = sbi_hart_init(scratch, FALSE);
rc = sbi_hart_init(scratch, false);
if (rc)
sbi_hart_hang();
rc = sbi_pmu_init(scratch, FALSE);
rc = sbi_pmu_init(scratch, false);
if (rc)
sbi_hart_hang();
rc = sbi_irqchip_init(scratch, FALSE);
rc = sbi_irqchip_init(scratch, false);
if (rc)
sbi_hart_hang();
rc = sbi_ipi_init(scratch, FALSE);
rc = sbi_ipi_init(scratch, false);
if (rc)
sbi_hart_hang();
rc = sbi_tlb_init(scratch, FALSE);
rc = sbi_tlb_init(scratch, false);
if (rc)
sbi_hart_hang();
rc = sbi_timer_init(scratch, FALSE);
rc = sbi_timer_init(scratch, false);
if (rc)
sbi_hart_hang();
@@ -396,17 +449,18 @@ static void init_warm_startup(struct sbi_scratch *scratch, u32 hartid)
if (rc)
sbi_hart_hang();
rc = sbi_platform_final_init(plat, FALSE);
rc = sbi_platform_final_init(plat, false);
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_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;
@@ -420,7 +474,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)
@@ -433,14 +487,12 @@ static void __noreturn init_warmboot(struct sbi_scratch *scratch, u32 hartid)
if (hstate < 0)
sbi_hart_hang();
if (hstate == SBI_HSM_STATE_SUSPENDED)
init_warm_resume(scratch);
else
if (hstate == SBI_HSM_STATE_SUSPENDED) {
init_warm_resume(scratch, hartid);
} else {
sbi_ipi_raw_clear(hartid);
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);
@@ -459,8 +511,8 @@ static atomic_t coldboot_lottery = ATOMIC_INITIALIZER(0);
*/
void __noreturn sbi_init(struct sbi_scratch *scratch)
{
bool next_mode_supported = FALSE;
bool coldboot = FALSE;
bool next_mode_supported = false;
bool coldboot = false;
u32 hartid = current_hartid();
const struct sbi_platform *plat = sbi_platform_ptr(scratch);
@@ -470,15 +522,15 @@ void __noreturn sbi_init(struct sbi_scratch *scratch)
switch (scratch->next_mode) {
case PRV_M:
next_mode_supported = TRUE;
next_mode_supported = true;
break;
case PRV_S:
if (misa_extension('S'))
next_mode_supported = TRUE;
next_mode_supported = true;
break;
case PRV_U:
if (misa_extension('U'))
next_mode_supported = TRUE;
next_mode_supported = true;
break;
default:
sbi_hart_hang();
@@ -494,8 +546,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
@@ -511,6 +566,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;

View File

@@ -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;
}
@@ -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,33 +95,49 @@ 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;
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;
/* Send IPIs */
for (i = hbase; m; i++, m >>= 1) {
if (m & 1UL)
sbi_ipi_send(scratch, i, event, data);
sbi_hartmask_set_hart(i, &target_mask);
}
} else {
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);
sbi_hartmask_set_hart(i, &target_mask);
}
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;
}
@@ -163,7 +191,7 @@ void sbi_ipi_clear_smode(void)
static void sbi_ipi_process_halt(struct sbi_scratch *scratch)
{
sbi_hsm_hart_stop(scratch, TRUE);
sbi_hsm_hart_stop(scratch, true);
}
static struct sbi_ipi_event_ops ipi_halt_ops = {
@@ -195,23 +223,29 @@ 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++;
};
}
}
void sbi_ipi_raw_send(u32 target_hart)
int sbi_ipi_raw_send(u32 target_hart)
{
if (ipi_dev && ipi_dev->ipi_send)
ipi_dev->ipi_send(target_hart);
if (!ipi_dev || !ipi_dev->ipi_send)
return SBI_EINVAL;
ipi_dev->ipi_send(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)

View File

@@ -129,6 +129,7 @@ int sbi_misaligned_load_handler(ulong addr, ulong tval2, ulong tinst,
uptrap.tval = addr;
uptrap.tval2 = tval2;
uptrap.tinst = tinst;
uptrap.gva = sbi_regs_gva(regs);
return sbi_trap_redirect(regs, &uptrap);
}
@@ -244,6 +245,7 @@ int sbi_misaligned_store_handler(ulong addr, ulong tval2, ulong tinst,
uptrap.tval = addr;
uptrap.tval2 = tval2;
uptrap.tinst = tinst;
uptrap.gva = sbi_regs_gva(regs);
return sbi_trap_redirect(regs, &uptrap);
}

View File

@@ -10,7 +10,9 @@
#include <sbi/riscv_asm.h>
#include <sbi/sbi_bitops.h>
#include <sbi/sbi_console.h>
#include <sbi/sbi_ecall_interface.h>
#include <sbi/sbi_hart.h>
#include <sbi/sbi_heap.h>
#include <sbi/sbi_platform.h>
#include <sbi/sbi_pmu.h>
#include <sbi/sbi_scratch.h>
@@ -33,18 +35,6 @@ struct sbi_pmu_hw_event {
uint64_t select_mask;
};
/** Representation of a firmware event */
struct sbi_pmu_fw_event {
/* Event associated with the particular counter */
uint32_t event_idx;
/* Current value of the counter */
unsigned long curr_count;
/* A flag indicating pmu event monitoring is started */
bool bStarted;
};
/* Information about PMU counters as per SBI specification */
union sbi_pmu_ctr_info {
unsigned long value;
@@ -60,14 +50,43 @@ union sbi_pmu_ctr_info {
};
};
#if SBI_PMU_FW_CTR_MAX >= BITS_PER_LONG
#error "Can't handle firmware counters beyond BITS_PER_LONG"
#endif
/** 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[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];
/* Contains all the information about firmwares events */
static struct sbi_pmu_fw_event fw_event_map[SBI_HARTMASK_MAX_BITS][SBI_PMU_FW_EVENT_MAX] = {0};
static struct sbi_pmu_hw_event *hw_event_map;
/* Maximum number of hardware events available */
static uint32_t num_hw_events;
@@ -78,7 +97,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)
/**
@@ -86,7 +106,7 @@ static uint32_t total_ctrs;
* @param evtA Pointer to the existing hw event structure
* @param evtB Pointer to the new hw event structure
*
* Return FALSE if the range doesn't overlap, TRUE otherwise
* Return false if the range doesn't overlap, true otherwise
*/
static bool pmu_event_range_overlap(struct sbi_pmu_hw_event *evtA,
struct sbi_pmu_hw_event *evtB)
@@ -94,32 +114,86 @@ static bool pmu_event_range_overlap(struct sbi_pmu_hw_event *evtA,
/* check if the range of events overlap with a previous entry */
if (((evtA->end_idx < evtB->start_idx) && (evtA->end_idx < evtB->end_idx)) ||
((evtA->start_idx > evtB->start_idx) && (evtA->start_idx > evtB->end_idx)))
return FALSE;
return TRUE;
return false;
return true;
}
static bool pmu_event_select_overlap(struct sbi_pmu_hw_event *evt,
uint64_t select_val, uint64_t select_mask)
{
if ((evt->select == select_val) && (evt->select_mask == select_mask))
return TRUE;
return true;
return FALSE;
return false;
}
static int pmu_ctr_validate(uint32_t cidx, uint32_t *event_idx_code)
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;
switch(event_idx_type) {
case SBI_PMU_EVENT_TYPE_HW:
event_idx_code_max = SBI_PMU_HW_GENERAL_MAX;
break;
case SBI_PMU_EVENT_TYPE_FW:
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(phs->hartid,
edata);
else
event_idx_code_max = SBI_PMU_FW_MAX;
break;
case SBI_PMU_EVENT_TYPE_HW_CACHE:
cache_ops_result = event_idx_code &
SBI_PMU_EVENT_HW_CACHE_OPS_RESULT;
cache_ops_id = (event_idx_code &
SBI_PMU_EVENT_HW_CACHE_OPS_ID_MASK) >>
SBI_PMU_EVENT_HW_CACHE_OPS_ID_OFFSET;
cache_id = (event_idx_code &
SBI_PMU_EVENT_HW_CACHE_ID_MASK) >>
SBI_PMU_EVENT_HW_CACHE_ID_OFFSET;
if ((cache_ops_result < SBI_PMU_HW_CACHE_RESULT_MAX) &&
(cache_ops_id < SBI_PMU_HW_CACHE_OP_MAX) &&
(cache_id < SBI_PMU_HW_CACHE_MAX))
return event_idx_type;
else
return SBI_EINVAL;
break;
case SBI_PMU_EVENT_TYPE_HW_RAW:
event_idx_code_max = 1; // event_idx.code should be zero
break;
default:
return SBI_EINVAL;
}
if (event_idx_code < event_idx_code_max)
return event_idx_type;
return SBI_EINVAL;
}
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();
event_idx_val = active_events[hartid][cidx];
if (cidx >= total_ctrs || (event_idx_val == SBI_PMU_EVENT_IDX_INVALID))
if (cidx >= total_ctrs)
return SBI_EINVAL;
event_idx_val = phs->active_events[cidx];
event_idx_type = get_cidx_type(event_idx_val);
if (event_idx_type >= SBI_PMU_EVENT_TYPE_MAX)
if (event_idx_val == SBI_PMU_EVENT_IDX_INVALID ||
event_idx_type >= SBI_PMU_EVENT_TYPE_MAX)
return SBI_EINVAL;
*event_idx_code = get_cidx_code(event_idx_val);
@@ -127,50 +201,30 @@ static int pmu_ctr_validate(uint32_t cidx, uint32_t *event_idx_code)
return event_idx_type;
}
static int pmu_ctr_read_fw(uint32_t cidx, unsigned long *cval,
uint32_t fw_evt_code)
{
u32 hartid = current_hartid();
struct sbi_pmu_fw_event fevent;
fevent = fw_event_map[hartid][fw_evt_code];
*cval = fevent.curr_count;
return 0;
}
/* Add a hardware counter read for completeness for future purpose */
static int pmu_ctr_read_hw(uint32_t cidx, uint64_t *cval)
{
/* Check for invalid hw counter read requests */
if (unlikely(cidx == 1))
return SBI_EINVAL;
#if __riscv_xlen == 32
uint32_t temp, temph = 0;
temp = csr_read_num(CSR_MCYCLE + cidx);
temph = csr_read_num(CSR_MCYCLEH + cidx);
*cval = ((uint64_t)temph << 32) | temp;
#else
*cval = csr_read_num(CSR_MCYCLE + cidx);
#endif
return 0;
}
int sbi_pmu_ctr_read(uint32_t cidx, unsigned long *cval)
int sbi_pmu_ctr_fw_read(uint32_t cidx, uint64_t *cval)
{
int event_idx_type;
uint32_t event_code;
uint64_t cval64;
struct sbi_pmu_hart_state *phs = pmu_thishart_state_ptr();
event_idx_type = pmu_ctr_validate(cidx, &event_code);
if (event_idx_type < 0)
event_idx_type = pmu_ctr_validate(phs, cidx, &event_code);
if (event_idx_type != SBI_PMU_EVENT_TYPE_FW)
return SBI_EINVAL;
else if (event_idx_type == SBI_PMU_EVENT_TYPE_FW)
pmu_ctr_read_fw(cidx, cval, event_code);
else
pmu_ctr_read_hw(cidx, &cval64);
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_read_value)
*cval = pmu_dev->fw_counter_read_value(phs->hartid,
cidx -
num_hw_ctrs);
else
*cval = 0;
} else
*cval = phs->fw_counters_data[cidx - num_hw_ctrs];
return 0;
}
@@ -315,6 +369,8 @@ static int pmu_ctr_start_hw(uint32_t cidx, uint64_t ival, bool ival_update)
if (sbi_hart_has_extension(scratch, SBI_HART_EXT_SSCOFPMF))
pmu_ctr_enable_irq_hw(cidx);
if (pmu_dev && pmu_dev->hw_counter_enable_irq)
pmu_dev->hw_counter_enable_irq(cidx);
csr_write(CSR_MCOUNTINHIBIT, mctr_inhbt);
skip_inhibit_update:
@@ -324,16 +380,49 @@ skip_inhibit_update:
return 0;
}
static int pmu_ctr_start_fw(uint32_t cidx, uint32_t fw_evt_code,
uint64_t ival, bool ival_update)
int sbi_pmu_irq_bit(void)
{
u32 hartid = current_hartid();
struct sbi_pmu_fw_event *fevent;
struct sbi_scratch *scratch = sbi_scratch_thishart_ptr();
fevent = &fw_event_map[hartid][fw_evt_code];
if (ival_update)
fevent->curr_count = ival;
fevent->bStarted = TRUE;
if (sbi_hart_has_extension(scratch, SBI_HART_EXT_SSCOFPMF))
return MIP_LCOFIP;
if (pmu_dev && pmu_dev->hw_counter_irq_bit)
return pmu_dev->hw_counter_irq_bit();
return 0;
}
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)
{
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_write_value ||
!pmu_dev->fw_counter_start) {
return SBI_EINVAL;
}
if (ival_update)
pmu_dev->fw_counter_write_value(phs->hartid,
cidx - num_hw_ctrs,
ival);
return pmu_dev->fw_counter_start(phs->hartid,
cidx - num_hw_ctrs,
event_data);
} else {
if (ival_update)
phs->fw_counters_data[cidx - num_hw_ctrs] = ival;
}
phs->fw_counters_started |= BIT(cidx - num_hw_ctrs);
return 0;
}
@@ -341,27 +430,35 @@ static int pmu_ctr_start_fw(uint32_t cidx, uint32_t fw_evt_code,
int sbi_pmu_ctr_start(unsigned long cbase, unsigned long cmask,
unsigned long flags, uint64_t ival)
{
struct sbi_pmu_hart_state *phs = pmu_thishart_state_ptr();
int event_idx_type;
uint32_t event_code;
unsigned long ctr_mask = cmask << cbase;
int ret = SBI_EINVAL;
bool bUpdate = FALSE;
bool bUpdate = false;
int i, cidx;
uint64_t edata;
if (sbi_fls(ctr_mask) >= total_ctrs)
if ((cbase + sbi_fls(cmask)) >= total_ctrs)
return ret;
if (flags & SBI_PMU_START_FLAG_SET_INIT_VALUE)
bUpdate = TRUE;
bUpdate = true;
for_each_set_bit_from(cbase, &ctr_mask, total_ctrs) {
event_idx_type = pmu_ctr_validate(cbase, &event_code);
for_each_set_bit(i, &cmask, total_ctrs) {
cidx = i + cbase;
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)
ret = pmu_ctr_start_fw(cbase, event_code, ival, bUpdate);
else if (event_idx_type == SBI_PMU_EVENT_TYPE_FW) {
edata = (event_code == SBI_PMU_FW_PLATFORM) ?
phs->fw_counters_data[cidx - num_hw_ctrs]
: 0x0;
ret = pmu_ctr_start_fw(phs, cidx, event_code, edata,
ival, bUpdate);
}
else
ret = pmu_ctr_start_hw(cbase, ival, bUpdate);
ret = pmu_ctr_start_hw(cidx, ival, bUpdate);
}
return ret;
@@ -389,11 +486,24 @@ static int pmu_ctr_stop_hw(uint32_t cidx)
return SBI_EALREADY_STOPPED;
}
static int pmu_ctr_stop_fw(uint32_t cidx, uint32_t fw_evt_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;
fw_event_map[hartid][fw_evt_code].bStarted = FALSE;
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(phs->hartid, cidx - num_hw_ctrs);
if (ret)
return ret;
}
phs->fw_counters_started &= ~BIT(cidx - num_hw_ctrs);
return 0;
}
@@ -417,29 +527,30 @@ 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;
unsigned long ctr_mask = cmask << cbase;
int i, cidx;
if (sbi_fls(ctr_mask) >= total_ctrs)
if ((cbase + sbi_fls(cmask)) >= total_ctrs)
return SBI_EINVAL;
for_each_set_bit_from(cbase, &ctr_mask, total_ctrs) {
event_idx_type = pmu_ctr_validate(cbase, &event_code);
for_each_set_bit(i, &cmask, total_ctrs) {
cidx = i + cbase;
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(cbase, event_code);
ret = pmu_ctr_stop_fw(phs, cidx, event_code);
else
ret = pmu_ctr_stop_hw(cbase);
ret = pmu_ctr_stop_hw(cidx);
if (flag & SBI_PMU_STOP_FLAG_RESET) {
active_events[hartid][cbase] = SBI_PMU_EVENT_IDX_INVALID;
pmu_reset_hw_mhpmevent(cbase);
if (cidx > (CSR_INSTRET - CSR_CYCLE) && flag & SBI_PMU_STOP_FLAG_RESET) {
phs->active_events[cidx] = SBI_PMU_EVENT_IDX_INVALID;
pmu_reset_hw_mhpmevent(cidx);
}
}
@@ -480,6 +591,9 @@ static int pmu_update_hw_mhpmevent(struct sbi_pmu_hw_event *hw_evt, int ctr_idx,
mhpmevent_val = (mhpmevent_val & ~MHPMEVENT_SSCOF_MASK) |
MHPMEVENT_MINH | MHPMEVENT_OF;
if (pmu_dev && pmu_dev->hw_counter_disable_irq)
pmu_dev->hw_counter_disable_irq(ctr_idx);
/* Update the inhibit flags based on inhibit flags received from supervisor */
pmu_update_inhibit_flags(flags, &mhpmevent_val);
@@ -506,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)
@@ -552,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) &&
@@ -587,21 +702,33 @@ 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, u32 hartid)
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 = 0;
int fw_base;
unsigned long ctr_mask = cmask << cbase;
int i, cidx;
if (cbase < num_hw_ctrs)
fw_base = num_hw_ctrs;
else
fw_base = cbase;
if ((event_code >= SBI_PMU_FW_MAX &&
event_code <= SBI_PMU_FW_RESERVED_MAX) ||
event_code > SBI_PMU_FW_PLATFORM)
return SBI_EINVAL;
for (i = fw_base; i < total_ctrs; i++)
if ((active_events[hartid][i] == SBI_PMU_EVENT_IDX_INVALID) &&
((1UL << i) & ctr_mask))
return i;
for_each_set_bit(i, &cmask, BITS_PER_LONG) {
cidx = i + cbase;
if (cidx < num_hw_ctrs || total_ctrs <= cidx)
continue;
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(phs->hartid,
cidx - num_hw_ctrs,
edata))
continue;
}
return i;
}
return SBI_ENOTSUPP;
}
@@ -610,40 +737,51 @@ 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 ctr_idx = SBI_ENOTSUPP;
u32 hartid = current_hartid();
int event_type = get_cidx_type(event_idx);
struct sbi_pmu_fw_event *fevent;
uint32_t fw_evt_code;
unsigned long tmp = cidx_mask << cidx_base;
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 (sbi_fls(tmp) >= total_ctrs || event_type >= SBI_PMU_EVENT_TYPE_MAX)
if ((cidx_base + sbi_fls(cidx_mask)) >= total_ctrs)
return SBI_EINVAL;
event_type = pmu_event_validate(phs, event_idx, event_data);
if (event_type < 0)
return SBI_EINVAL;
event_code = get_cidx_code(event_idx);
if (flags & SBI_PMU_CFG_FLAG_SKIP_MATCH) {
/* 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 (phs->active_events[cidx_first] == SBI_PMU_EVENT_IDX_INVALID)
return SBI_EINVAL;
ctr_idx = cidx_base;
ctr_idx = cidx_first;
goto skip_match;
}
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, hartid);
ctr_idx = pmu_ctr_find_fw(phs, cidx_base, cidx_mask,
event_code, event_data);
if (event_code == SBI_PMU_FW_PLATFORM)
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)
@@ -651,30 +789,46 @@ skip_match:
if (flags & SBI_PMU_CFG_FLAG_AUTO_START)
pmu_ctr_start_hw(ctr_idx, 0, false);
} else if (event_type == SBI_PMU_EVENT_TYPE_FW) {
fw_evt_code = get_cidx_code(event_idx);
fevent = &fw_event_map[hartid][fw_evt_code];
if (flags & SBI_PMU_CFG_FLAG_CLEAR_VALUE)
fevent->curr_count = 0;
if (flags & SBI_PMU_CFG_FLAG_AUTO_START)
fevent->bStarted = TRUE;
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(
phs->hartid,
ctr_idx - num_hw_ctrs, event_data);
if (ret)
return ret;
}
phs->fw_counters_started |= BIT(ctr_idx - num_hw_ctrs);
}
}
return ctr_idx;
}
inline int sbi_pmu_ctr_incr_fw(enum sbi_pmu_fw_event_code_id fw_id)
int sbi_pmu_ctr_incr_fw(enum sbi_pmu_fw_event_code_id fw_id)
{
u32 hartid = current_hartid();
struct sbi_pmu_fw_event *fevent;
u32 cidx;
uint64_t *fcounter = NULL;
struct sbi_pmu_hart_state *phs = pmu_thishart_state_ptr();
if (likely(!phs->fw_counters_started))
return 0;
if (unlikely(fw_id >= SBI_PMU_FW_MAX))
return SBI_EINVAL;
fevent = &fw_event_map[hartid][fw_id];
for (cidx = num_hw_ctrs; cidx < total_ctrs; cidx++) {
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;
}
}
/* PMU counters will be only enabled during performance debugging */
if (unlikely(fevent->bStarted))
fevent->curr_count++;
if (fcounter)
(*fcounter)++;
return 0;
}
@@ -686,6 +840,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();
@@ -705,8 +860,13 @@ int sbi_pmu_ctr_get_info(uint32_t cidx, unsigned long *ctr_info)
} else {
/* it's a firmware counter */
cinfo.type = SBI_PMU_CTR_TYPE_FW;
/* Firmware counters are XLEN bits wide */
cinfo.width = BITS_PER_LONG - 1;
/* 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;
@@ -714,36 +874,59 @@ 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++)
sbi_memset(&fw_event_map[hartid][j], 0,
sizeof(struct sbi_pmu_fw_event));
phs->fw_counters_data[j] = 0;
phs->fw_counters_started = 0;
}
const struct sbi_pmu_device *sbi_pmu_get_device(void)
{
return pmu_dev;
}
void sbi_pmu_set_device(const struct sbi_pmu_device *dev)
{
if (!dev || pmu_dev)
return;
pmu_dev = 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);
@@ -753,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_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 |
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;
}

Some files were not shown because too many files have changed in this diff Show More