302 Commits
v0.9 ... v1.1

Author SHA1 Message Date
Anup Patel
4489876e93 include: Bump-up version to 1.1
This patch updates OpenSBI version to 1.1 as part of
release preparation.

Signed-off-by: Anup Patel <apatel@ventanamicro.com>
2022-06-25 09:12:10 +05:30
Sergey Matyukevich
3f66465fb6 lib: pmu: allow to use the highest available counter
OpenSBI explicitly assumes that there is no pmu hardware counter with
index 1: hardware uses that bit for TM control. So OpenSBI filters
out that index in sanity checks. However OpenSBI also excludes that
counter when reports total amount of hardware counters to Linux. As
a result, Linux uses incomplete counters mask excluding the highest
available counter.

Return accurate number of counters, update the firmware counter
starting index, fix range checks that include num_hw_ctrs.

The simple test is to make sure that there is no counter multiplexing
in the following command:

$ perf stat -e \
	r8000000000000000,r8000000000000001,r8000000000000002,r8000000000000003, \
	r8000000000000004,r8000000000000005,r8000000000000006,r8000000000000007, \
	r8000000000000008,r8000000000000009,r800000000000000a,r800000000000000b, \
	r800000000000000c,r800000000000000d,r800000000000000e,r800000000000000f  \
	ls

Note that 16 firmware events with 16 counters won't require multiplexing.

Signed-off-by: Sergey Matyukevich <geomatsi@gmail.com>
Signed-off-by: Atish Patra <atishp@rivosinc.com>
Reviewed-by: Atish Patra <atishp@rivosinc.com>
2022-06-25 08:44:20 +05:30
Anup Patel
c6fdbcf83f include: sbi: Change spec version to 1.0
Now that SBI v1.0 specification is ratified, we change spec verion
implemented by OpenSBI to v1.0.

Signed-off-by: Anup Patel <apatel@ventanamicro.com>
Reviewed-by: Atish Patra <atishp@rivosinc.com>
2022-06-24 08:54:59 +05:30
Samuel Holland
6f1fe98c2f lib: utils/timer: Remove Allwinner D1 CLINT compatibles
The allwinner,sun20i-d1-clint compatible string is not documented in any
official binding, so it should not be used by drivers.

The MSWI in the D1 CLINT is compatible with the ACLINT specification, so
it can take advantage of generic driver support. However, that is only
possible if the MSWI and MTIMER are split into separate DT nodes. This
means the final binding for this device is likely to be incompatible
with what is implemented here.

Remove this compatible string from the driver to prevent it from
appearing in a stable version and causing future issues.

Signed-off-by: Samuel Holland <samuel@sholland.org>
Reviewed-by: Anup Patel <anup@brainfault.org>
2022-06-22 10:55:37 +05:30
Jan Remes
d76a196bfc lib: irqchip/plic: fix typo in plic_warm_irqchip_init
The second invocation of plic_context_init() incorrectly calls the
function with m_cntx_id instead of s_cntx_id. This breaks systems which
only have 1 external interrupt per hart.

Fixes: 8c362e7 ("lib: irqchip/plic: Factor out a context init function")
Signed-off-by: Jan Remes <jan.remes@codasip.com>
Reviewed-by: Anup Patel <anup@brainfault.org>
Reviewed-by: Samuel Holland <samuel@sholland.org>
2022-06-22 10:55:27 +05:30
Samuel Holland
7738345396 lib: utils/timer: Add a separate compatible for the D1 CLINT
The CLINT in the Allwinner D1 SoC apparently does not support 64-bit
MMIO access. A property was added to support this quirk (and that
property was copied to the ACLINT MTIMER code). However, since this
difference in behavior makes the D1 CLINT incompatible with the SiFive
CLINT's programming interface, a better solution is to use a separate
compatible string.

Signed-off-by: Samuel Holland <samuel@sholland.org>
Reviewed-by: Anup Patel <anup@brainfault.org>
2022-06-21 09:20:59 +05:30
Anup Patel
c6530012d4 lib: utils: Remove CSRs that set/clear an IMSIC interrupt file bits
Based on architecture review committee feedback, the [m|s|vs]seteienum,
[m|s|vs]clreienum, [m|s|vs]seteipnum, and [m|s|vs]clreipnum CSRs are
removed in the latest AIA draft v0.3.0 specification.
(Refer, https://github.com/riscv/riscv-aia/releases/tag/0.3.0-draft.31)

These CSRs were mostly for software convenience and software can always
use [m|s|vs]iselect and [m|s|vs]ireg CSRs to update the IMSIC interrupt
file bits.

We update the IMSIC programming as-per above to match the latest AIA
draft specification.

Signed-off-by: Anup Patel <apatel@ventanamicro.com>
Reviewed-by: Atish Patra <atishp@rivosinc.com>
2022-06-21 08:44:45 +05:30
dramforever
a07402ac9c lib: sbi: Fix tval and tinst for sbi_get_insn()
We should not change trap->tval to mepc because mtval already points to
the faulting portion of the emulated instruction fetch, which is also
what stval is expected to be.

In addition, htinst is only allowed to be zero for instruction access
faults or page faults, and is only allowed to be zero or a
psuedoinstruction for instruction guest-page faults. Fix trap->tinst for
these cases.

Signed-off-by: dramforever <dramforever@live.com>
Reviewed-by: Anup Patel <anup@brainfault.org>
2022-06-21 08:31:56 +05:30
dramforever
187127fb89 lib: sbi: Fixup tinst for exceptions in sbi_misaligned_*()
If there is an exception while emulating a misaligned load/store, fixup
uptrap.tinst before redirecting. Otherwise, HS-mode software may receive
an htinst describing the lbu/sb instruction that faulted during
emulation[1].

[1]: https://github.com/riscv-software-src/opensbi/issues/258

Signed-off-by: dramforever <dramforever@live.com>
Reviewed-by: Anup Patel <anup@brainfault.org>
2022-06-21 08:31:14 +05:30
dramforever
551c70c040 include: sbi: Add mtinst/htinst psuedoinstructions
Add psuedoinstruction encodings written to mtinst/htinst for faults
caused by implicit memory access for VS-stage address translation

Signed-off-by: dramforever <dramforever@live.com>
Reviewed-by: Anup Patel <anup@brainfault.org>
2022-06-21 08:31:04 +05:30
Samuel Holland
9dc5ec5c51 platform: Add HSM implementation for Allwinner D1
Allwinner D1 contains a "PPU" power domain controller which can
automatically power down/up the CPU power domain. This power domain
includes the C906 core along with its CLINT and PLIC.

This HSM implementation supports non-retentive hart suspend by:
  1) Saving/restoring state that is lost during hart suspend,
  2) Performing cache maintenance before/after hart suspend,
  3) Configuring wakeup sources before hart suspend, and
  4) Asking the PPU to power down the hart when it enters WFI.

Since this HSM implementation is for a single-core SoC, it does not need
to worry about concurrency or saving multiple instances of state.

Reviewed-by: Anup Patel <anup@brainfault.org>
Signed-off-by: Samuel Holland <samuel@sholland.org>
2022-06-13 11:59:09 +05:30
Samuel Holland
5e5675874c lib: utils/irqchip: Add wrapper for T-HEAD PLIC delegation
The delegation bit is lost along with the rest of the PLIC state when
the CPU power domain in the Allwinner D1 is powered down, so the PLIC
needs to be re-delegated to S-mode during the hart resume path.

Reviewed-by: Anup Patel <anup@brainfault.org>
Signed-off-by: Samuel Holland <samuel@sholland.org>
2022-06-13 11:54:06 +05:30
Samuel Holland
69be3dff9d lib: utils/irqchip: Add FDT wrappers for PLIC save/restore functions
These functions save/restore the state of the PLIC associated with the
current hart. The context save/restore functions only manipulate a
single context, since most likely the M-mode context is unused and does
not need to be saved.

Signed-off-by: Samuel Holland <samuel@sholland.org>
Reviewed-by: Anup Patel <anup@brainfault.org>
2022-06-13 11:54:06 +05:30
Samuel Holland
2b79b694a8 lib: irqchip/plic: Add priority save/restore helpers
These can be used by platform code to save the PLIC priority state, if
it would otherwise be lost during non-retentive suspend. The platform
is responsible for allocating all necessary storage.

As a space optimization, store the saved priority values as 8-bit
integers, since that is large enough to hold any priority value on the
relevant platforms.

Reviewed-by: Anup Patel <anup@brainfault.org>
Signed-off-by: Samuel Holland <samuel@sholland.org>
2022-06-13 11:54:06 +05:30
Samuel Holland
415ecf28f7 lib: irqchip/plic: Add context save/restore helpers
These can be used by platform code to save the PLIC context state, if
it would otherwise be lost during non-retentive suspend. The platform
is responsible for allocating all necessary storage.

Reviewed-by: Anup Patel <anup@brainfault.org>
Signed-off-by: Samuel Holland <samuel@sholland.org>
2022-06-13 11:54:06 +05:30
Samuel Holland
8c362e7d06 lib: irqchip/plic: Factor out a context init function
This simplifies both the callers and the callees by removing duplicated
code and consolidating the error handling. It also fixes two bugs in the
process:
  1) ie_words was one too large when plic->num_src was a multiple of 32.
  2) plic_set_ie takes a 32-bit mask, not a Boolean value, so the FPGA
     platforms previously only enabled one out of every 32 interrupts.

Reviewed-by: Anup Patel <anup@brainfault.org>
Signed-off-by: Samuel Holland <samuel@sholland.org>
2022-06-13 11:54:06 +05:30
Samuel Holland
2ea7799d56 lib: irqchip/plic: Constify plic_data pointers
None of the functions modify the passed-in plic_data, so mark it const.

Reviewed-by: Anup Patel <anup@brainfault.org>
Signed-off-by: Samuel Holland <samuel@sholland.org>
2022-06-13 11:54:06 +05:30
Samuel Holland
79e42eb2d6 lib: sbi_hsm: Assume a consistent resume address
The suspend code needs to know the resume address for two reasons:
  1) Programming some hardware register or management firmware. Here we
     assume the hardware/firmware maintains its state between suspends,
     so it only needs to be programmed once at startup.
  2) When a non-retentive suspend request ends up being retentive, due
     to lack of hardware support, pending interrupt, or for some other
     reason. However, the behavior here is not platform-dependent, and
     this can be handled in the generic hart suspend function.

Since neither situation requires the platform-level suspend function to
know the resume address, stop passing it to that function. Instead,
handle the non-retentive to retentive situation generically.

Reviewed-by: Anup Patel <anup@brainfault.org>
Signed-off-by: Samuel Holland <samuel@sholland.org>
2022-06-13 11:54:06 +05:30
Samuel Holland
b20ed9febe lib: sbi_hsm: Call a device hook during hart resume
Non-retentive suspend states may require platform-specific actions
during resume. For example, firmware may need to save and restore the
values of custom CSRs. Add a hook to support this.

Reviewed-by: Anup Patel <anup@brainfault.org>
Signed-off-by: Samuel Holland <samuel@sholland.org>
2022-06-13 11:54:06 +05:30
Mayuresh Chitale
ce1d6188a2 platform: generic: add overrides for vendor extensions
Allow the vendor_ext_check and vendor_ext_provider APIs of the
generic platform to be overridden by other platforms

Signed-off-by: Mayuresh Chitale <mchitale@ventanamicro.com>
Reviewed-by: Anup Patel <anup@brainfault.org>
2022-06-13 11:17:38 +05:30
dramforever
adc3388d76 lib: sbi_trap: Redirect exception based on hedeleg
HS-mode software can choose what exceptions to delegate to VS-mode using
the hedeleg CSR. Synthetic VS/VU-mode exceptions should also honor
hedeleg. They should be redirected to VS-mode if and only if delegated
by HS-mode.

Signed-off-by: dramforever <dramforever@live.com>
Reviewed-by: Xiang W <wxjstz@126.com>
Reviewed-by: Anup Patel <anup@brainfault.org>
2022-06-13 11:02:49 +05:30
Samuel Holland
cb8271c8e4 lib: sbi_illegal_insn: Add emulation for fence.tso
While OpenC906 appears to properly decode `fence.tso` as a fence
instruction[1], the version of the C906 taped out in the Allwinner D1
does not, and raises illegal instruction.

Handle this errata by emulating `fence.tso` as `fence rw, rw`.

[1]: https://github.com/T-head-Semi/openc906/blob/30827e7f/C906_RTL_FACTORY/gen_rtl/idu/rtl/aq_idu_id_decd.v#L2097

Signed-off-by: Samuel Holland <samuel@sholland.org>
Reviewed-by: Anup Patel <anup@brainfault.org>
2022-06-01 17:20:20 +05:30
Samuel Holland
ff65bfec4e lib: sbi_illegal_insn: Constify illegal_insn_table
This table does not need to be modified at runtime.

Signed-off-by: Samuel Holland <samuel@sholland.org>
Reviewed-by: Anup Patel <anup@brainfault.org>
2022-05-30 10:54:31 +05:30
Samuel Holland
295e5f3c69 lib: sbi_timer: Drop unnecessary get_platform_ticks wrapper
The device's timer_value callback is already the right prototype to use
for the get_time_val function pointer.

Signed-off-by: Samuel Holland <samuel@sholland.org>
Reviewed-by: Anup Patel <anup@brainfault.org>
2022-05-30 10:43:03 +05:30
Samuel Holland
fab0379bb6 lib: utils/fdt: Require match data to be const
Match data stores hardware attributes which do not change at runtime, so
it does not need to be mutable. Make it const.

Reviewed-by: Guo Ren <guoren@kernel.org>
Reviewed-by: Xiang W <wxjstz@126.com>
Reviewed-by: Anup Patel <anup@brainfault.org>
Signed-off-by: Samuel Holland <samuel@sholland.org>
2022-05-30 10:32:35 +05:30
Xiang W
f067bb84cf lib: sbi: fix system_opcode_insn
If the csr's operation comes from M mode, it should not be forwarded
to low-privilege processing, this patch fixes this problem.

Signed-off-by: Xiang W <wxjstz@126.com>
Reviewed-by: Anup Patel <anup@brainfault.org>
2022-05-30 10:22:13 +05:30
Jan Remes
1bc67db80c lib: utils/fdt: rename fdt_parse_max_hart_id
The function returns the highest hart-id of the harts actually used in
the system (enabled). Change the name to reflect this fact.

Signed-off-by: Jan Remes <jan.remes@codasip.com>
Reviewed-by: Anup Patel <anup@brainfault.org>
2022-05-14 10:18:12 +05:30
Jan Remes
575bb4e8ca platform: generic: check if CPU node is enabled
Ignore CPU nodes in FDT which are not enabled.

Signed-off-by: Jan Remes <jan.remes@codasip.com>
Reviewed-by: Xiang W <wxjstz@126.com>
Reviewed-by: Anup Patel <anup@brainfault.org>
2022-05-14 10:17:33 +05:30
Jan Remes
616da52e18 lib: utils: check if CPU node is enabled
Ignore CPU nodes in FDT that are not enabled.

Signed-off-by: Jan Remes <jan.remes@codasip.com>
Reviewed-by: Anup Patel <anup@brainfault.org>
2022-05-14 10:16:50 +05:30
Jan Remes
90a9dd2b22 lib: utils/fdt: introduce fdt_node_is_enabled()
If an FDT node contains a "status" property and this property is not
"ok" or "okay", this node should be ignored. Introduce a function that
checks this.

Signed-off-by: Jan Remes <jan.remes@codasip.com>
Reviewed-by: Xiang W <wxjstz@126.com>
Reviewed-by: Anup Patel <anup@brainfault.org>
2022-05-14 10:16:24 +05:30
Jan Remes
851c14d455 lib: utils/irqchip: fix typo when checking for CPU node
Fix typo in irqchip_imsic_update_hartid_table() when checking for CPU
node.

Signed-off-by: Jan Remes <jan.remes@codasip.com>
Reviewed-by: Anup Patel <anup@brainfault.org>
Reviewed-by: Bin Meng <bmeng.cn@gmail.com>
2022-05-13 09:58:54 +05:30
Anup Patel
9a7a677d5f platform: generic: Move Sifive platform overrides into own directory
Let us move SiFive platform overrides for FU540 and FU740 into a separate
directory so better maintainability. Other SoC vendors can also create
their own directory under platform/generic.

Signed-off-by: Anup Patel <apatel@ventanamicro.com>
Reviewed-by: Atish Patra <atishp@rivosinc.com>
2022-05-13 09:27:23 +05:30
Anup Patel
a3a3c60b66 platform: generic: Generate platform override module list at compile-time
Instead of having platform override module list hard-coded in the C source,
we generate it using carray.sh at compile-time.

Signed-off-by: Anup Patel <apatel@ventanamicro.com>
Reviewed-by: Atish Patra <atishp@rivosinc.com>
2022-05-13 09:27:18 +05:30
Anup Patel
4eacd8229b lib: utils/gpio: Generate FDT gpio driver list at compile-time
Instead of having FDT gpio driver list hard-coded in the C source,
we generate it using carray.sh at compile-time.

Signed-off-by: Anup Patel <apatel@ventanamicro.com>
Reviewed-by: Atish Patra <atishp@rivosinc.com>
2022-05-13 09:27:12 +05:30
Anup Patel
998ed43fde lib: utils/i2c: Generate FDT i2c adapter driver list at compile-time
Instead of having FDT i2c adapter driver list hard-coded in the C source,
we generate it using carray.sh at compile-time.

Signed-off-by: Anup Patel <apatel@ventanamicro.com>
Reviewed-by: Atish Patra <atishp@rivosinc.com>
2022-05-13 09:26:45 +05:30
Anup Patel
4ee0c57969 lib: utils/ipi: Generate FDT ipi driver list at compile-time
Instead of having FDT ipi driver list hard-coded in the C source,
we generate it using carray.sh at compile-time.

Signed-off-by: Anup Patel <apatel@ventanamicro.com>
Reviewed-by: Atish Patra <atishp@rivosinc.com>
2022-05-13 09:26:35 +05:30
Anup Patel
3a69d12fc3 lib: utils/irqchip: Generate FDT irqchip driver list at compile-time
Instead of having FDT irqchip driver list hard-coded in the C source,
we generate it using carray.sh at compile-time.

Signed-off-by: Anup Patel <apatel@ventanamicro.com>
Reviewed-by: Atish Patra <atishp@rivosinc.com>
2022-05-13 09:26:27 +05:30
Anup Patel
bfeb305e0f lib: utils/timer: Generate FDT timer driver list at compile-time
Instead of having FDT timer driver list hard-coded in the C source,
we generate it using carray.sh at compile-time.

Signed-off-by: Anup Patel <apatel@ventanamicro.com>
Reviewed-by: Atish Patra <atishp@rivosinc.com>
2022-05-13 09:26:20 +05:30
Anup Patel
1e62705adc lib: utils/serial: Generate FDT serial driver list at compile-time
Instead of having FDT serial driver list hard-coded in the C source,
we generate it using carray.sh at compile-time.

Signed-off-by: Anup Patel <apatel@ventanamicro.com>
Reviewed-by: Atish Patra <atishp@rivosinc.com>
2022-05-13 09:26:13 +05:30
Anup Patel
73cf511914 lib: utils/reset: Generate FDT reset driver list at compile-time
Instead of having FDT reset driver list hard-coded in the C source,
we generate it using carray.sh at compile-time.

Signed-off-by: Anup Patel <apatel@ventanamicro.com>
Reviewed-by: Atish Patra <atishp@rivosinc.com>
2022-05-13 09:26:06 +05:30
Anup Patel
7fb474b9dd Makefile: Add support for generating C array at compile time
Generating C array at compile time based on details provided by
objects.mk is a very useful feature which will help us compile
only a subset of drivers or modules.

We add a bash script (carray.sh) which takes array details and
object/variable list from command-line to generate a C source
containing array of object/variable pointers. We also extend
top-level makefile to use carray.sh whenever specified through
objects.mk.

Signed-off-by: Anup Patel <apatel@ventanamicro.com>
Reviewed-by: Atish Patra <atishp@rivosinc.com>
2022-05-13 09:26:00 +05:30
Anup Patel
f726f2dc01 Makefile: Allow generated C source to be anywhere in build directory
The generated C source could be anywhere within build directory so
let us update the make rule to comple generated C source accordingly.

Signed-off-by: Anup Patel <apatel@ventanamicro.com>
Reviewed-by: Atish Patra <atishp@rivosinc.com>
2022-05-13 09:25:50 +05:30
Anup Patel
023f0ad2d9 lib: sbi_platform: Add callback to populate HART extensions
We add platform specific extensions_init() callback which allows
platforms to populate HART extensions for each HART. For example,
the generic platform can populate HART extensions from HART ISA
string described in DeviceTree.

Signed-off-by: Anup Patel <apatel@ventanamicro.com>
Reviewed-by: Atish Patra <atishp@rivosinc.com>
2022-05-07 10:17:28 +05:30
Anup Patel
994ace30f7 lib: sbi: Add sbi_hart_update_extension() function
We add sbi_hart_update_extension() function which allow platforms
to enable/disable hart extensions.

Signed-off-by: Anup Patel <anup@brainfault.org>
Reviewed-by: Atish Patra <atishp@rivosinc.com>
2022-05-07 10:17:25 +05:30
Anup Patel
be4903ae00 lib: sbi: Detect hart features only once for each hart
Currently, the hart_detect_features() is called everytime a hart
is stopped and started again which is unnecessary work.

We update hart_detect_features() to detect hart features only
once for each hart.

Signed-off-by: Anup Patel <apatel@ventanamicro.com>
Reviewed-by: Atish Patra <atishp@rivosinc.com>
2022-05-07 10:17:22 +05:30
Anup Patel
cad6c91045 lib: sbi: Convert hart features into hart extensions
Since past few years, we have been using "hart features" in OpenSBI
to represent all optionalities and multi-letter extensions defined
by the RISC-V specifications.

The RISC-V profiles specification has taken a different approach and
started assigning extension names for all optionalities which did not
have any extension name previously.
(Refer, https://github.com/riscv/riscv-profiles/blob/main/profiles.adoc)

Inspired from the RISC-V profiles specification, we convert OpenSBI
hart features into hart extensions. Going forward, we align the
extension naming with RISC-V profiles specification. Currently, only
"time CSR" and "AIA CSR" have not been assigned extension name but
for everything else we have a name.

Signed-off-by: Anup Patel <apatel@ventanamicro.com>
Reviewed-by: Atish Patra <atishp@rivosinc.com>
2022-05-07 10:16:30 +05:30
Anup Patel
a6ab94fdbf lib: sbi: Fix AIA feature detection
The AIA feature detection uses unnecessary goto which is not need
and AIA case in sbi_hart_feature_id2string() does not break. This
patch fixes both issues in AIA feature detection.

Signed-off-by: Anup Patel <apatel@ventanamicro.com>
Reviewed-by: Atish Patra <atishp@rivosinc.com>
2022-05-07 10:06:57 +05:30
Anup Patel
97a17c2e5c lib: sbi: Remove MENVCFG hart feature
If a hart implements privileged spec v1.12 (or higher) then we can
safely assume that menvcfg CSR is present and we don't need MENVCFG
as a hart feature.

Signed-off-by: Anup Patel <apatel@ventanamicro.com>
Reviewed-by: Atish Patra <atishp@rivosinc.com>
2022-05-07 10:06:19 +05:30
Anup Patel
dbc3d8f0ef lib: sbi: Remove MCOUNTINHIBT hart feature
If a hart implements privileged spec v1.11 (or higher) then we can
safely assume that mcountinhibit CSR is present and we don't need
MCOUNTINHIBT as a hart feature.

Signed-off-by: Anup Patel <apatel@ventanamicro.com>
Reviewed-by: Atish Patra <atishp@rivosinc.com>
2022-05-07 10:05:37 +05:30
Anup Patel
d4b563c881 lib: sbi: Remove MCOUNTEREN and SCOUNTEREN hart features
If a hart implements privileged spec v1.10 (or higher) then we can
safely assume that [m|s]counteren CSR are present and we don't need
MCOUNTEREN and SCOUNTEREN as hart features.

Signed-off-by: Anup Patel <apatel@ventanamicro.com>
Reviewed-by: Atish Patra <atishp@rivosinc.com>
2022-05-07 10:04:54 +05:30
Anup Patel
5b8b377178 lib: sbi: Update the name of ISA string printed at boot time
The ISA string printed at boot time is not the complete ISA string
representing all single letter and multi-letter extensions rather
it is base ISA string derived from misa CSR so let us update the
boot print accordingly.

Signed-off-by: Anup Patel <apatel@ventanamicro.com>
Reviewed-by: Atish Patra <atishp@rivosinc.com>
2022-05-07 10:03:24 +05:30
Anup Patel
5a6be99cc5 lib: sbi: Remove 's' and 'u' from misa_string() output
Both 's' and 'u' are not treated as ISA extensions since these are
privilege modes so let's remove it from misa_string() output.

Signed-off-by: Anup Patel <apatel@ventanamicro.com>
Reviewed-by: Atish Patra <atishp@rivosinc.com>
2022-05-07 10:02:28 +05:30
Anup Patel
1a754bb365 lib: sbi: Detect and print privileged spec version
It is possible to guess privileged spec versions based on the CSRs
that where introduced in different privileged spec versions. In
future, if we are not able guess privileged spec version then we
can have platform provide it.

We add privileged spec version as per-hart feature and try to guess
it based on presence of mcounteren, mcountinhibit, and menvcfg CSRs.

Signed-off-by: Anup Patel <apatel@ventanamicro.com>
Reviewed-by: Atish Patra <atishp@rivosinc.com>
2022-05-07 09:49:54 +05:30
Atish Patra
b0c9df514b lib: sbi: Fix mhpmeventh access for rv32 in absence of sscofpmf
MHPMEVENT3H-31H are defined in sscofpmf extension. Thus, they should be
accessed only if sscofpmf is present.

Signed-off-by: Atish Patra <atishp@rivosinc.com>
Reviewed-by: Anup Patel <anup@brainfault.org>
2022-05-07 09:40:59 +05:30
Jun Liang Tan
e576b3e620 include: sbi: Define SBI_PMU_HW_EVENT_MAX to 256
Increase maximum number of PMU hardware events that can be mapped
by OpenSBI to 256

Signed-off-by: Jun Liang Tan <junliang.tan@linux.starfivetech.com>
Signed-off-by: Wei Liang Lim <weiliang.lim@linux.starfivetech.com>
Reviewed-by: Anup Patel <anup@brainfault.org>
2022-05-07 09:37:42 +05:30
Anup Patel
474a9d4555 lib: sbi: Fix mstatus_init() for RV32 when Sscofpmf is not available
The mhpmevent3h to mhpmevent31h CSRs are available on RV32 only when
Sscofpmf extension is available so mstatus_init() should set this
CSRs only when Sscofpmf extension is available.

Signed-off-by: Anup Patel <apatel@ventanamicro.com>
Reviewed-by: Atish Patra <atishp@rivosinc.com>
2022-04-28 19:39:01 +05:30
Atish Patra
d62f6da062 lib: sbi: Implement Sstc extension
Recently, Sstc extension was ratified. It defines stimecmp which allows
the supervisor mode to directly update the timecmp value without the
need of the SBI call. The hardware also can inject the S-mode timer
interrupt direclty to the supervisor without going through the M-mode.
To maintain backward compatibility with the older software, SBI call
now uses stimecmp directly if the hardware supports.

Implement the Sstc extension.

Signed-off-by: Atish Patra <atishp@rivosinc.com>
Reviewed-by: Anup Patel <anup@brainfault.org>
2022-04-28 11:45:21 +05:30
Atish Patra
4035ae94be docs: pmu: Improve the PMU DT bindings
The current DT binding description is misleading and confusing. Clarify
the text and provide more examples.

Signed-off-by: Atish Patra <atishp@rivosinc.com>
Reviewed-by: Anup Patel <anup@brainfault.org>
2022-04-28 11:40:15 +05:30
Dmitry Dunaev
9cd95e13bb lib: sbi/hart: preserve csr validation value
The OpenSBI hart init function hart_detect_features() try to read
important CSRs but reasign the last read value to the variable that
initially contains write probe value. So for series of CSRs (like
PMPADDRx) the second CSR probe value will became the initial value of
first probing CSR. To avoid of this issue the CSR read value should be
saved in different variable. In this configuration the count of PMP
will detect rightly if any PMPADDR is hardwired to zero.

Signed-off-by: Dmitry Dunaev <dunaich@mail.ru>
Signed-off-by: Anup Patel <anup@brainfault.org>
2022-04-17 14:43:08 +05:30
Vincent Chen
c1e47d0c3f include: correct the definition of MSTATUS_VS
Accordind to the RISC-V privileged specification, the VS filed is
mstatus[10:9] instead of mstatus[24:23]. Modify the MSTATUS_VS
to the correct value.

Reported-by: I-Cheng Cheng <i-cheng.cheng@sifive.com>
Signed-off-by: Vincent Chen <vincent.chen@sifive.com>
Reviewed-by: Xiang W <wxjstz@126.com>
Reviewed-by: Anup Patel <anup@brainfault.org>
2022-04-17 14:30:19 +05:30
Zong Li
5c5cbb53a4 lib: utils/serial: support 'reg-offset' property
reg-offset property is used for offset to apply to the mapbase
from the start of the registers in 8250 UART. In Linux kernel,
it has been handled in 8250 UART driver.

dt-bindings:
<linux>/Documentation/devicetree/bindings/serial/8250.yaml

Signed-off-by: Zong Li <zong.li@sifive.com>
Reviewed-by: Anup Patel <anup@brainfault.org>
2022-04-17 13:57:48 +05:30
Mayuresh Chitale
3383d6a4d1 lib: irqchip/imsic: configure mstateen
When mstateen registers are implemented, the AIA related
configurations need to be done in mstateen for the IMSIC
initialization to succeed.

Signed-off-by: Mayuresh Chitale <mchitale@ventanamicro.com>
Reviewed-by: Xiang W <wxjstz@126.com>
Reviewed-by: Anup Patel <anup@brainfault.org>
2022-04-11 08:34:17 +05:30
Mayuresh Chitale
d44568a0f2 lib: sbi: Detect Smstateen CSRs at boot-time
Extend HART feature detection to discover Smstateen CSRs at boot-time
and configure mstateen envcfg bit depending on availability of
menvcfg CSR.

Signed-off-by: Mayuresh Chitale <mchitale@ventanamicro.com>
Reviewed-by: Xiang W <wxjstz@126.com>
Reviewed-by: Anup Patel <anup@brainfault.org>
2022-04-11 08:34:10 +05:30
Mayuresh Chitale
499601a4ff lib: sbi: Add Smstateen extension defines
Smstateen extension provides a mechanism to plug potential
covert channels which are opened by extensions that add to
processor state that may not get context-switched.

Signed-off-by: Mayuresh Chitale <mchitale@ventanamicro.com>
Reviewed-by: Xiang W <wxjstz@126.com>
Reviewed-by: Anup Patel <anup@brainfault.org>
2022-04-11 08:34:02 +05:30
Anup Patel
794986f87f lib: sbi: Enable Svpbmt extension in the menvcfg CSR
The menvcfg.PBMTE bit is read-only zero when Svpbmt extension is not
available so we try to enable menvcfg.PBMTE bit irrespective whether
Svpbmt is available or not.

Signed-off-by: Anup Patel <apatel@ventanamicro.com>
Reviewed-by: Atish Patra <atishp@rivosinc.com>
Reviewed-by: Xiang W <wxjstz@126.com>
2022-04-05 08:53:11 +05:30
Anup Patel
47d676570d lib: sbi: Enable Zicbo[m|z] extensions in the menvcfg CSR
The bits to configure/enable Zicbo[m|z] extensions in the menvcfg
CSR are WARL. We try to enable these bits irrespective whether
these extensions are available or not because writes to these
bits will be ignored if these extensions are not available.

Signed-off-by: Anup Patel <apatel@ventanamicro.com>
Reviewed-by: Atish Patra <atishp@rivosinc.com>
Reviewed-by: Xiang W <wxjstz@126.com>
2022-04-05 08:51:40 +05:30
Atish Patra
31fecad46d lib: sbi: Detect menvcfg CSR at boot time
We add the menvcfg CSR as a HART feature and detect it at boot time
using traping mechanism.

Signed-off-by: Atish Patra <atishp@rivosinc.com>
Signed-off-by: Anup Patel <apatel@ventanamicro.com>
Reviewed-by: Xiang W <wxjstz@126.com>
2022-04-05 08:50:48 +05:30
Anup Patel
722f80d8e9 include: Add defines for [m|h|s]envcfg CSRs
The latest RISC-V privileged specification introduces xenvcfg CSRs
to enable/disable certain features/extensions for lower privilege
modes. This patch adds defines for these new [m|h|s]envcfg CSRs.

Signed-off-by: Anup Patel <apatel@ventanamicro.com>
Reviewed-by: Atish Patra <atishp@rivosinc.com>
Reviewed-by: Xiang W <wxjstz@126.com>
2022-04-05 08:50:17 +05:30
Xiang W
7924a0b220 include: Use static asserts for FW_DYNAMIC_INFO_xxx_OFFSET defines
Add static detection to prevent the modification of struct fw_dynamic_info
from forgetting the modification of FW_DYNAMIC_INFO_xxx_OFFSET

Signed-off-by: Xiang W <wxjstz@126.com>
Reviewed-by: Anup Patel <anup@brainfault.org>
2022-03-27 09:44:58 +05:30
Xiang W
1b42d3ace3 include: Use static asserts for SBI_SCRATCH_xxx_OFFSET defines
Add static detection to prevent the modification of struct sbi_scratch
from forgetting the modification of SBI_SCRATCH_xxx_OFFSET

Signed-off-by: Xiang W <wxjstz@126.com>
Reviewed-by: Anup Patel <anup@brainfault.org>
2022-03-27 09:44:54 +05:30
Xiang W
555bdb1cf3 include: Use static asserts for SBI_PLATFORM_xxx_OFFSET defines
Add static detection to prevent the modification of struct sbi_platform
from forgetting the modification of SBI_PLATFORM_xxx_OFFSET

Signed-off-by: Xiang W <wxjstz@126.com>
Reviewed-by: Anup Patel <anup@brainfault.org>
2022-03-27 09:07:44 +05:30
Xiang W
d552fc8d36 lib: Add error messages via conditional compilation for the future
On 128-bit machines, sbi_load_xx/sbi_store_xx needs to be improved.
Through this conditional compile, the corresponding implementation
can be prompted to be added.

Signed-off-by: Xiang W <wxjstz@126.com>
Reviewed-by: Anup Patel <anup@brainfault.org>
2022-03-27 08:54:12 +05:30
Xiang W
b6b7220a47 firmware: Fix code for accessing hart_count and stack_size
lwu exists under the current rv64 and should also exist under the rv128
in the future, so I modified the conditions of conditional compilation
so that it can adapt to the future situation

Signed-off-by: Xiang W <wxjstz@126.com>
Reviewed-by: Anup Patel <anup@brainfault.org>
2022-03-27 08:53:27 +05:30
Xiang W
2dfbd3c0e2 lib: pmp_set/pmp_get moved errors from runtime to compile time
pmp_set/pmp_get calculates the location of the CSR register separately
through conditional compilation. In the case of non-32-bit and 64-bit,
we can report an error directly through #error without putting it at
runtime

Signed-off-by: Xiang W <wxjstz@126.com>
Reviewed-by: Anup Patel <anup@brainfault.org>
2022-03-27 08:52:19 +05:30
Alistair Francis
4998a712b2 lib: utils: serial: Initial commit of xlnx-uartlite
Initial commit of the xlnx-uartlite device and FDT support. This was
tested by running OpenSBI on a modified QEMU virt machine using the
xlnx-uartlite for serial.

Signed-off-by: Alistair Francis <alistair.francis@wdc.com>
Reviewed-by: Xiang W <wxjstz@126.com>
Reviewed-by: Anup Patel <anup@brainfault.org>
2022-02-28 09:50:09 +05:30
Anup Patel
f3f4604c19 lib: sbi: Add a simple external interrupt handling framework
Currently, the external interrupt handling is scattered between
sbi_init and sbi_trap. This patch moves all external interrupt
handling into a simple framework called sbi_irqchip.

Signed-off-by: Anup Patel <apatel@ventanamicro.com>
Reviewed-by: Xiang W <wxjstz@126.com>
Reviewed-by: Atish Patra <atishp@rivosinc.com>
2022-02-28 09:43:12 +05:30
Nikita Shubin
f2ccf2f783 lib: sbi: verbose sbi_domain_root_add_memregion
Be more verbose on region confict, print addresses in conflict.

Signed-off-by: Nikita Shubin <n.shubin@yadro.com>
Reviewed-by: Xiang W <wxjstz@126.com>
Reviewed-by: Anup Patel <anup@brainfault.org>
2022-02-15 20:59:38 +05:30
Nikita Shubin
3a69cc1487 lib: sbi: fix typo in is_region_subset
Fix typo in is_region_subset, regB_end should be calculated from regB.

Signed-off-by: Nikita Shubin <n.shubin@yadro.com>
Reviewed-by: Dong Du <Dd_nirvana@sjtu.edu.cn>
Reviewed-by: Xiang W <wxjstz@126.com>
Reviewed-by: Anup Patel <anup@brainfault.org>
2022-02-15 20:58:04 +05:30
Anup Patel
8e2ef4f7af lib: utils: Disable appropriate APLIC DT nodes in fdt_fixups()
We should disable APLIC DT nodes in fdt_fixups() which are not
accessible to the next booting stage based on currently assigned
domain.

Signed-off-by: Anup Patel <anup.patel@wdc.com>
Signed-off-by: Anup Patel <apatel@ventanamicro.com>
Reviewed-by: Atish Patra <atishp@rivosinc.com>
2022-02-15 20:39:15 +05:30
Anup Patel
34612193af lib: utils/irqchip: Add FDT based driver for APLIC
We add simple FDT irqchip driver for APLIC so that generic platform (and
other FDT based platforms) can utilize common APLIC initialization library.

Signed-off-by: Anup Patel <anup.patel@wdc.com>
Signed-off-by: Anup Patel <apatel@ventanamicro.com>
Reviewed-by: Atish Patra <atishp@rivosinc.com>
2022-02-15 20:39:01 +05:30
Anup Patel
99792653de lib: utils/irqchip: Add APLIC initialization library
We add simple APLIC initialization library which is independent of
hardware description format (FDT or ACPI). This APLIC initialization
library can be used by custom OpenSBI platform support to setup
APLIC domains.

Signed-off-by: Anup Patel <anup.patel@wdc.com>
Signed-off-by: Anup Patel <apatel@ventanamicro.com>
Reviewed-by: Atish Patra <atishp@rivosinc.com>
2022-02-15 20:37:55 +05:30
Anup Patel
7127aaaaf7 lib: utils: Disable appropriate IMSIC DT nodes in fdt_fixups()
We should disable IMSIC DT nodes in fdt_fixups() which are not
accessible to the next booting stage based on currently assigned
domain.

Signed-off-by: Anup Patel <anup.patel@wdc.com>
Signed-off-by: Anup Patel <apatel@ventanamicro.com>
Reviewed-by: Atish Patra <atishp@rivosinc.com>
2022-02-15 20:37:27 +05:30
Anup Patel
811da5c541 lib: utils/irqchip: Add FDT based driver for IMSIC
We add simple FDT irqchip driver for IMSIC so that generic platform
(and other FDT based platforms) can utilize common IMIC library.

Signed-off-by: Anup Patel <anup.patel@wdc.com>
Signed-off-by: Anup Patel <apatel@ventanamicro.com>
Reviewed-by: Atish Patra <atishp@rivosinc.com>
2022-02-15 20:37:05 +05:30
Anup Patel
9f73669959 lib: utils/irqchip: Add IMSIC library
We add simple IMSIC library which is independent of hardware description
format (FDT or ACPI). This IMSIC library can be used by custom OpenSBI
platform support to setup IMSIC for external interrupts.

Signed-off-by: Anup Patel <anup.patel@wdc.com>
Signed-off-by: Anup Patel <apatel@ventanamicro.com>
Reviewed-by: Atish Patra <atishp@rivosinc.com>
2022-02-15 20:36:24 +05:30
Anup Patel
55e79f823d lib: sbi: Enable mie.MEIE bit for IPIs based on external interrupts.
We can have IPIs based on external interrupts provided by devices
such as AIA IMSIC so we should enable mie.MEIE bit at appropriate
places in generic library.

Signed-off-by: Anup Patel <anup@brainfault.org>
Signed-off-by: Anup Patel <apatel@ventanamicro.com>
Reviewed-by: Atish Patra <atishp@rivosinc.com>
2022-02-15 20:35:45 +05:30
Anup Patel
10509405b2 include: sbi: Introduce nascent_init() platform callback
We introduce nascent_init() platform callback which will allow
platforms to do very early initialization of platform specific
per-HART CSRs and per-HART devices.

Signed-off-by: Anup Patel <anup.patel@wdc.com>
Signed-off-by: Anup Patel <apatel@ventanamicro.com>
Reviewed-by: Atish Patra <atishp@rivosinc.com>
2022-02-15 20:34:24 +05:30
Anup Patel
5f56314618 lib: utils/irqchip: Allow multiple FDT irqchip drivers
We can have multiple FDT irqchip drivers to be probed when a RISC-V
system has different types of interrupt controller in a hierarchy.

This will be certainly the case when a RISC-V system has both
RISC-V AIA IMSIC and RISC-V AIA APLIC implemented.

We extend simple FDT irqchip framework to allow multiple FDT
irqchip drivers to be used for same RISC-V platform.

Signed-off-by: Anup Patel <anup.patel@wdc.com>
Signed-off-by: Anup Patel <apatel@ventanamicro.com>
Reviewed-by: Atish Patra <atishp@rivosinc.com>
2022-02-15 20:34:08 +05:30
Anup Patel
222132f48c lib: sbi: Add sbi_trap_set_external_irqfn() API
This patch adds sbi_trap_set_external_irqfn() API which can be used by
OpenSBI platform code to set a callback function for external interrupts.
The RISC-V AIA IMSIC driver will use this API to implement inter-processor
interrupts on-top-of MSIs.

Signed-off-by: Anup Patel <anup.patel@wdc.com>
Signed-off-by: Anup Patel <apatel@ventanamicro.com>
Reviewed-by: Atish Patra <atishp@rivosinc.com>
2022-02-15 20:33:55 +05:30
Anup Patel
65b4c7c01e lib: sbi: Use AIA CSRs for local interrupts when available
We should use AIA CSRs to process local interrupts whenever AIA
is available.

Signed-off-by: Anup Patel <anup.patel@wdc.com>
Signed-off-by: Anup Patel <apatel@ventanamicro.com>
Reviewed-by: Atish Patra <atishp@rivosinc.com>
2022-02-15 20:33:31 +05:30
Anup Patel
8f96070067 lib: sbi: Detect AIA CSRs at boot-time
We extend HART feature detection to discover AIA CSRs at boot-time.

Signed-off-by: Anup Patel <anup.patel@wdc.com>
Signed-off-by: Anup Patel <apatel@ventanamicro.com>
Reviewed-by: Atish Patra <atishp@rivosinc.com>
2022-02-15 20:32:42 +05:30
Anup Patel
01250d0044 include: sbi: Add AIA related CSR defines
The RISC-V AIA specification improves handling of per-HART local
interrupts in a backward compatible manner. This patch adds defines
for the new RISC-V AIA CSRs.

Signed-off-by: Anup Patel <anup.patel@wdc.com>
Signed-off-by: Anup Patel <apatel@ventanamicro.com>
Reviewed-by: Atish Patra <atishp@rivosinc.com>
2022-02-15 20:32:07 +05:30
Jakub Luzny
ce4c0188d9 lib: utils/serial: Round UART8250 baud rate divisor to nearest integer
Previously, it was rounded down and that gives suboptimal results when
non-standard clock sources or baud rates are used.

Signed-off-by: Jakub Luzny <jakub.luzny@codasip.com>
Reviewed-by: Anup Patel <anup@brainfault.org>
2022-02-04 11:16:29 +05:30
Petro Karashchenko
6ad8917b7e lib: fix compilation when strings.h is included
In a systems that provide strings.h and it is included
together with sbi_bitops.h the compilation error appears.
The ffs() and fls() are provided by strings.h

Signed-off-by: Petro Karashchenko <petro.karashchenko@gmail.com>
Reviewed-by: Anup Patel <anup@brainfault.org>
2022-02-04 11:04:19 +05:30
Aurelien Jarno
5d53b55aa7 Makefile: fix build with binutils 2.38
From version 2.38, binutils default to ISA spec version 20191213. This
means that the csr read/write (csrr*/csrw*) instructions and fence.i
instruction has separated from the `I` extension, become two standalone
extensions: Zicsr and Zifencei. As the kernel uses those instruction,
this causes the following build failure:

 CC        lib/sbi/sbi_tlb.o
<<BUILDDIR>>/lib/sbi/sbi_tlb.c: Assembler messages:
<<BUILDDIR>>/lib/sbi/sbi_tlb.c:190: Error: unrecognized opcode `fence.i'
make: *** [Makefile:431: <<BUILDDIR>>/build/lib/sbi/sbi_tlb.o] Error 1

The fix is to specify those extensions explicitly in -march. However as
older binutils version do not support this, we first need to detect
that.

Signed-off-by: Aurelien Jarno <aurelien@aurel32.net>
Reviewed-by: Bin Meng <bmeng.cn@gmail.com>
Tested-by: Alexandre Ghiti <alexandre.ghiti@canonical.com>
Reviewed-by: Anup Patel <anup@brainfault.org>
2022-02-04 10:47:24 +05:30
Atish Patra
a26dc609df lib: sbi: Disable interrupt and inhibit counting in M-mode during init
Currently, the mhpmevent CSRs are untouched during hart init during
cold/warm boot. Ideally, we should clear out all the bits except
overflow and MINH bit. That is required to disable overflow
interrupt and inhibit counting in M-mode to avoid any spurious
interrupts before perf start.

Signed-off-by: Atish Patra <atishp@rivosinc.com>
Reviewed-by: Anup Patel <anup@brainfault.org>
2022-02-04 10:10:28 +05:30
Atish Patra
3b7c204dca lib: sbi: Disable interrupt during config matching
PMU overflow interrupt should be disabled durinig initial configuration of
counters. They should be enabled while starting counters.

Fixes: 730f01bb41 ("lib: sbi: Support sscofpmf extension in OpenSBI")
Signed-off-by: Atish Patra <atishp@rivosinc.com>
Reviewed-by: Anup Patel <anup@brainfault.org>
2022-02-04 10:08:57 +05:30
Atish Patra
632f59392b lib: sbi: Map only the counters enabled in hardware
The counter mapping in DT may be incorrect if all the counters specified
in the mapping are actually not physically present in the hardware.
OpenSBI should only keep a mapping of counters enabled in hardware and
defined in DT. This assume that all the programmable hpmcounters are
consecutive as it doesn't make sense to build a system with sparse
hpmcounters.

Signed-off-by: Atish Patra <atishp@rivosinc.com>
Reviewed-by: Anup Patel <anup@brainfault.org>
2022-02-04 10:07:07 +05:30
Jukka Laitinen
5d025eb235 lib: fix pointer of type 'void *' used in arithmetic
Using "void *" in arithmetic causes errors with strict compiler settings:
"error: pointer of type 'void *' used in arithmetic [-Werror=pointer-arith]"

Avoid these by calculating on "char *" where 1-byte data size is assumed.

Signed-off-by: Jukka Laitinen <jukkax@ssrc.tii.ae>
Reviewed-by: Dong Du <Dd_nirvana@sjtu.edu.cn>
Reviewed-by: Xiang W <wxjstz@126.com>
Reviewed-by: Anup Patel <anup@brainfault.org>
2022-01-21 21:58:12 +05:30
Aurelien Jarno
fb688d9e9d platform: sifive_fu740: fix reset when watchdog is running
When the watchdog is running the HiFive Unmatched board does not reboot
properly and shuts down itself a few seconds after reboot, in the early
stages of the u-boot loading. On a Linux kernel this happens when the
da9063_wdt module is loaded. This does not happen if the module is
unloaded before reboot or if the watchdog module is loaded with
"stop_on_reboot=1".

Fix that by stopping the watchdog before attempting to reset the board.
This is done by zeroing the TWDSCALE field of CONTROL_D register, unless
it was already set to 0.

Reported-by: Tianon Gravi <tianon@debian.org>
Signed-off-by: Aurelien Jarno <aurelien@aurel32.net>
Reviewed-by: Nikita Shubin <n.shubin@yadro.com>
Tested-by: Nikita Shubin <n.shubin@yadro.com>
Reviewed-by: Anup Patel <anup@brainfault.org>
2022-01-21 21:44:57 +05:30
Aurelien Jarno
8257262dbf platform: sifive_fu740: do not use a global in da9063_reset/shutdown
da9063_reset() and da9063_shutdown() take the chip address in argument
(like similar functions), but in practice use the da9063 global struct
instead. Fix that.

Signed-off-by: Aurelien Jarno <aurelien@aurel32.net>
Reviewed-by: Nikita Shubin <n.shubin@yadro.com>
Reviewed-by: Anup Patel <anup@brainfault.org>
Reviewed-by: Xiang W <wxjstz@126.com>
2022-01-21 21:41:33 +05:30
Anup Patel
6dde43584f lib: utils/sys: Extend HTIF library to allow custom base address
Some of RISC-V emulators provide HTIF at fixed base address so for
such emulators users have to hard-code HTIF base address in the
linker script.

To address this problem, we let users optionally provide fixed HTIF
base address via platform support (or device tree).

Signed-off-by: Anup Patel <apatel@ventanamicro.com>
Reviewed-by: Dong Du <Dd_nirvana@sjtu.edu.cn>
Reviewed-by: Atish Patra <atishp@rivosinc.com>
2022-01-11 18:17:49 +05:30
Anup Patel
5b9960379f lib: utils/ipi: Fix size check in aclint_mswi_cold_init()
Currently, the ACLINT MSWI size check is forcing size to be at least
0x4000. This is inappropriate check because most systems will never
utilize full 16KB for a single ACLINT MSWI device so instead we should
check that ACLINT MSWI size is enough for on the associated HARTs.

Signed-off-by: Anup Patel <apatel@ventanamicro.com>
Reviewed-by: Dong Du <Dd_nirvana@sjtu.edu.cn>
Reviewed-by: Alistair Francis <alistair.francis@wdc.com>
2022-01-11 18:17:07 +05:30
Anup Patel
48f91ee9c9 include: Bump-up version to 1.0
This patch updates OpenSBI version to 1.0 as part of
release preparation.

Signed-off-by: Anup Patel <anup.patel@wdc.com>
2021-12-24 17:27:44 +05:30
Anup Patel
d30bde36d5 firmware: Move memcpy/memset mapping to fw_base.S
Some of the external firmwares using OpenSBI as library are facing
issues with the weak memcpy() and memset() aliases in libsbi.a so
we move these to fw_base.S. This way mapping of implicit memcpy()
or memset() calls to sbi_memcpy() or sbi_memset() will only be done
for OpenSBI firmwares.
(Refer, https://github.com/riscv-software-src/opensbi/issues/234)

In addition, we also add memmove() and memcmp() mappings in fw_base.S
because as-per the GCC documentation the freestanding environment must
provide memcpy(), memmove(), memset(), and memcmp().

Signed-off-by: Anup Patel <anup.patel@wdc.com>
Reviewed-by: Atish Patra <atishp@rivosinc.com>
2021-12-23 17:46:09 +05:30
Heinrich Schuchardt
2082153fc9 lib: sbi: simplify pmp_set(), pmp_get()
pmpcfg_csr and pmpcfg_shift are only negative for an unexpected value of
__riscv_xlen. We can immediately return in this case.

Signed-off-by: Heinrich Schuchardt <heinrich.schuchardt@canonical.com>
Reviewed-by: Dong Du <Dd_nirvana@sjtu.edu.cn>
Reviewed-by: Anup Patel <anup.patel@wdc.com>
2021-12-22 09:05:05 +05:30
Xiang W
f270359810 Makefile: Improve the method to disable -m(no-)save-restore option
The commit 69d7e53 disables the -m(no-)save-restore option for
clang, but clang11 supports this option. This patch uses the
output information of the compiler to check whether the compiler
supports this option.

Signed-off-by: Xiang W <wxjstz@126.com>
Reviewed-by: Anup Patel <anup.patel@wdc.com>
2021-12-16 09:27:22 +05:30
Anup Patel
d249d6544c lib: sbi: Fix compile errors using -Os option
When compiling with -Os option along with -ffreestanding, both GCC
and clang will add implicit calls to memcpy() and memset() for stack
variables initialized in declaration.

The C standard as per Clause 4, the compiler cannot necessarily
assume that anything beyond:

 * float.h
 * iso646.h
 * limits.h
 * stdalign.h
 * stdarg.h
 * stdbool.h
 * stddef.h
 * stdint.h
 * stdnoreturn.h
 * fenv.h
 * math.h
 * and the numeric conversion functions of stdlib.h.

This patch maps memcpy() and memset() as weak-alias of sbi_memcpy()
and sbi_memset() respectively so that implicit calls to memcpy()
and memset() will compile properly.

Signed-off-by: Anup Patel <anup.patel@wdc.com>
Reviewed-by: Dong Du <Dd_nirvana@sjtu.edu.cn>
Reviewed-by: Xiang W <wxjstz@126.com>
2021-12-11 17:37:29 +05:30
Anup Patel
69d7e53613 Makefile: Fix -msave-restore compile warning with CLANG-10 (or lower)
The riscv target of CLANG-10 (or lower) does not support the
-m(no-)save-restore option so we get compile warnings. This patch
fixes compile warning by using -m(no-)save-restore option only
for GCC.

Signed-off-by: Anup Patel <anup.patel@wdc.com>
Reviewed-by: Dong Du <Dd_nirvana@sjtu.edu.cn>
2021-12-11 17:37:26 +05:30
Nikita Shubin
460041c816 lib: pmu: check SSCOF before masking
We should check if SSCOF extension is present,
before applying inhibit mask and clearing overflow,
otherwise undesirable value can be written
in MHPMEVENT_N CSR.

Signed-off-by: Nikita Shubin <n.shubin@yadro.com>
Reviewed-by: Anup Patel <anup.patel@wdc.com>
Reviewed-by: Xiang W <wxjstz@126.com>
2021-12-11 16:26:15 +05:30
Tsukasa OI
66fbcc03df docs/platform: spike: Enhance Spike examples
This commit makes Spike usable as QEMU (in fact, those are based on
QEMU examples).

Signed-off-by: Tsukasa OI <research_trasio@irq.a4lg.com>
Reviewed-by: Anup Patel <anup.patel@wdc.com>
2021-12-11 16:24:39 +05:30
Vincent Chen
2428987cc0 lib: pmu: support the event ID encoded by a bitmap.
RISC-V privilege specification does not specify how to encode the event ID.
Therefore, each platform is allowed to customize its own encoding rule.
The common encoding methods are as follow, directly assigning a number to an
event, or every bit in the mphmevent CSR controls one specified event or
mixes the above two methods.

To enable OpenSBI to support the above three encoding methods simultaneously,
this patch repurpose the dt property "riscv,raw-event-to-mhpmcounters". The
"riscv,raw-event-to-mhpmcounters" will describes the one or multiple raw
events that could be counted by a set of counters. But, the column number
of "riscv,raw-event-to-mhpmcounters" is extended from 2 to 3. The 1st column
(64bit) is the ID of the raw events. The 2nd column (64bit) represents a
select_mask now to represent the bits used for event ID encoding.
If a platform directly encodes each raw PMU event as a unique ID,
the value of select_mask will be 0xffffffff_ffffffff.

Signed-off-by: Vincent Chen <vincent.chen@sifive.com>
Signed-off-by: Atish Patra<atishp@rivosinc.com>
Reviewed-by: Anup Patel <anup.patel@wdc.com>
2021-12-03 09:37:03 +05:30
Jessica Clarke
14faee6916 lib: sbi: Improve fatal error handling
BUG and BUG_ON are not informative and are rather lazy interfaces, only
telling the user that something went wrong in a given function, but not
what, requiring the user to find the sources corresponding to their
firmware (which may not be available) and figure out how that BUG(_ON)
was hit. Even SBI_ASSERT in its current form, which does include the
condition that triggered it in the output, isn't necessarily very
informative. In some cases, the error may be fixable by the user, but
they need to know the problem in order to have any hope of fixing it.
It's also a nuisance for developers, whose development trees may have
changed significantly since the release in question being used, and so
line numbers can make it harder for them to understand which error case
a user has hit.

This patch introduces a new sbi_panic function which is printf-like,
allowing detailed error messages to be printed to the console. BUG and
BUG_ON are removed, since the former is just a worse form of sbi_panic
and the latter is a worse version of SBI_ASSERT. Finally, SBI_ASSERT is
augmented to take a set of arguments to pass to sbi_panic on failure,
used like so (sbi_boot_print_hart's current error case, which currently
manually calls sbi_printf and sbi_hart_hang):

  SBI_ASSERT(xlen >= 1, ("Error %d getting MISA XLEN\n", xlen));

The existing users of BUG are replaced with calls to sbi_panic along
with informative error messages. BUG_ON and SBI_ASSERT were unused (and,
in the case of SBI_ASSERT, remain unused).

Many existing users of sbi_hart_hang should be converted to use either
sbi_panic or SBI_ASSERT after this commit.

Signed-off-by: Jessica Clarke <jrtc27@jrtc27.com>
Reviewed-by: Anup Patel <anup.patel@wdc.com>
Reviewed-by: Xiang W <wxjstz@126.com>
Reviewed-by: Atish Patra <atishp@rivosinc.com>
2021-12-02 08:50:36 +05:30
Dong Du
7e77706966 lib: sbi: Resolve the uninitialized complaint in sbi_pmu
A recent commit (b28f0700) turns to read from CSR_MCOUNTINHIBIT after
checking the SBI_HART_HAS_MCOUNTINHIBIT HART feature, which leaves the
mctr_inhbt uninitialized in pmu_ctr_find_hw().
As a result, compiler will complain:
error: 'mctr_inhbt' may be used uninitialized in this function.

This commit resolves the issue by assigning an initial value to mctr_inhbt.

Signed-off-by: Dong Du <Dd_nirvana@sjtu.edu.cn>
Reviewed-by: Xiang W <wxjstz@126.com>
Reviewed-by: Anup Patel <anup.patel@wdc.com>
2021-11-30 10:40:35 +05:30
Nikita Shubin
7a22c780df lib: sbi: Fix missing space
Fix missing space in sbi_hart_pmp_configure
error printing.

Signed-off-by: Nikita Shubin <n.shubin@yadro.com>
Reviewed-by: Dong Du <Dd_nirvana@sjtu.edu.cn>
Reviewed-by: Xiang w <wxjstz@126.com>
2021-11-30 10:35:34 +05:30
Vagrant Cascadian
22d556d268 lib: sbi: Fix spelling of "address" in sbi_domain.c
Fix a spelling typo in error print.

Signed-off-by: Vagrant Cascadian <vagrant@debian.org>
Signed-off-by: Anup Patel <anup.patel@wdc.com>
Reviewed-by: Xiang W <wxjstz@126.com>
2021-11-23 17:52:13 +05:30
Gabriel Somlo
52af6e4b52 lib: utils: Add LiteX UART support
Add support for the UART provided by the LiteX SoC
framework (https://github.com/enjoy-digital/litex),
based on its FDT info (described in the Linux tree at
Documentation/devicetree/bindings/serial/litex,liteuart.yaml).

Signed-off-by: Gabriel Somlo <gsomlo@gmail.com>
Reviewed-by: Xiang W <wxjstz@126.com>
Reviewed-by: Anup Patel <anup.patel@wdc.com>
2021-11-18 13:22:02 +05:30
Xiang W
d335a178d8 lib: sbi: clear pmpcfg.A before setting in pmp_set()
We should clear A bits in prot variable before enabling A_NA4 or A_NAPOT.

Signed-off-by: Xiang W <wxjstz@126.com>
Reviewed-by: Anup Patel <anup.patel@wdc.com>
2021-11-12 12:19:00 +05:30
Nikita Shubin
f3744967c6 platform: sifive_fu740: add platform reset driver
da9063 PMIC can be used to reset/shutdown the
Sifive Unmatched board.

shutdown is done simply by writing SHUTDOWN bit to
DA9063_REG_CONTROL_F register.

reset via setting WAKEUP bit in DA9063_REG_CONTROL_F
register followed by masking POWER and POWER1 domains
and setting STANDBY bit in DA9063_REG_CONTROL_A,
originally discovered by Alexandre Ghiti on linux-riscv
maillists.

Tested-by: Heinrich Schuchardt <heinrich.schuchardt@canonical.com>
Reviewed-by: Alexandre Ghiti <alexandre.ghiti@canonical.com>
Tested-by: Alexandre Ghiti <alexandre.ghiti@canonical.com>
Signed-off-by: Nikita Shubin <n.shubin@yadro.com>
2021-11-12 10:29:20 +05:30
Nikita Shubin
13a1158d24 lib: utils/i2c: Add minimal SiFive I2C driver
Minimum SiFive 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.

Tested-by: Heinrich Schuchardt <heinrich.schuchardt@canonical.com>
Reviewed-by: Alexandre Ghiti <alexandre.ghiti@canonical.com>
Tested-by: Alexandre Ghiti <alexandre.ghiti@canonical.com>
Signed-off-by: Nikita Shubin <n.shubin@yadro.com>
2021-11-12 10:29:08 +05:30
Nikita Shubin
6ca6bcafb7 lib: utils/i2c: Add simple FDT based I2C framework
FDT based I2C framework on the top of I2C library.

The drivers are probed on demand by fdt_i2c_adapter_get
function.

Tested-by: Heinrich Schuchardt <heinrich.schuchardt@canonical.com>
Reviewed-by: Alexandre Ghiti <alexandre.ghiti@canonical.com>
Tested-by: Alexandre Ghiti <alexandre.ghiti@canonical.com>
Signed-off-by: Nikita Shubin <n.shubin@yadro.com>
2021-11-12 10:19:45 +05:30
Nikita Shubin
2c964a2e15 lib: utils/i2c: Add generic I2C configuration library
Helper library to keep track of registered I2C adapters,
identified by dts offset, basic send/read functions and
adapter configuration (enable, set dividers, etc...).

Tested-by: Heinrich Schuchardt <heinrich.schuchardt@canonical.com>
Reviewed-by: Alexandre Ghiti <alexandre.ghiti@canonical.com>
Tested-by: Alexandre Ghiti <alexandre.ghiti@canonical.com>
Signed-off-by: Nikita Shubin <n.shubin@yadro.com>
2021-11-12 10:17:50 +05:30
Nikita Shubin
1d462e0397 lib: utils/reset: separate driver init func
Move driver init code to separate function, so it can be reused
elsewhere.

Tested-by: Heinrich Schuchardt <heinrich.schuchardt@canonical.com>
Reviewed-by: Alexandre Ghiti <alexandre.ghiti@canonical.com>
Tested-by: Alexandre Ghiti <alexandre.ghiti@canonical.com>
Signed-off-by: Nikita Shubin <n.shubin@yadro.com>
2021-11-12 10:16:23 +05:30
Nikita Shubin
94eba23376 lib: utils/reset: add priority to gpio reset
Make gpio_system_reset_check return priority instead of just true/false.

Make default 128 priority for reset/shutdown.

Tested-by: Heinrich Schuchardt <heinrich.schuchardt@canonical.com>
Reviewed-by: Alexandre Ghiti <alexandre.ghiti@canonical.com>
Tested-by: Alexandre Ghiti <alexandre.ghiti@canonical.com>
Signed-off-by: Nikita Shubin <n.shubin@yadro.com>
2021-11-12 10:15:54 +05:30
Vasan VS
31fe5a7a3d lib: sbi: Fix PMP address bits detection
We should ensure that pmpcfg0.pmp0cfg is set to zero before using
pmpaddr0 CSR for detecting implemented PMP address bits.

Fixes: bf21632860 ("lib: sbi: Detect PMP granularity and number
of address bits")
Signed-off-by: Vasan VS <vasan.vs@gmail.com>
Signed-off-by: Anup Patel <anup.patel@wdc.com>
Reviewed-by: Atish Patra <atish.patra@wdc.com>
Reviewed-by: Dong Du <Dd_nirvana@sjtu.edu.cn>
2021-11-11 18:27:53 +05:30
Atish Patra
b8845e4204 lib: sbi: Fix initial value mask while updating the counters
The first 32 bits of the initial value for the counter should be
preserved while updating the mhpmcounter for 32bit.

Fixes: 13d40f21d5 ("lib: sbi: Add PMU support")
Signed-off-by: Atish Patra <atish.patra@wdc.com>
Reviewed-by: Bin Meng <bmeng.cn@gmail.com>
Reviewed-by: Dong Du <Dd_nirvana@sjtu.edu.cn>
Reviewed-by: Anup Patel <anup.patel@wdc.com>
2021-11-11 17:57:17 +05:30
Atish Patra
15906a3984 lib: utils: Rename the prefix in PMU DT properties
As per the DT schema rules, the prefix should be vendor. As the PMU
properties are generic for all vendors, change the prefix to riscv
instead of pmu.

Reviewed-by: Anup Patel <anup.patel@wdc.com>
Reviewed-by: Bin Meng <bmeng.cn@gmail.com>
Signed-off-by: Atish Patra <atish.patra@wdc.com>
2021-11-11 17:54:46 +05:30
Atish Patra
b28f07005c lib: sbi: Enable PMU extension for platforms without mcountinhibit
Some platforms such as hifive unmatched doesn't implement mcountinhibit
csr. However, it has hardware events that can be monitored using 2
hpmcounter it has (i.e. mhpmcounter3 & mhpmcounter4).

Currently, PMU extension disabled if mcountinhibit is absent. That's not
really necessary as long as the supervisor OS keeps track of the delta
value of the counters. Without mcountinhibit, the delta value won't be
entirely accurate because the counters are freely running. However, that
should be fine to produce an approximate counter value which can help
performance analysis. Perf sampling won't work though as sscof extension
is not present in hifive unmatched.

Reviewed-by: Anup Patel <anup.patel@wdc.com>
Reviewed-by: Bin Meng <bmeng.cn@gmail.com>
Signed-off-by: Atish Patra <atish.patra@wdc.com>
2021-11-11 17:54:01 +05:30
Atish Patra
b628cfd6a0 lib: sbi: Counter info width should be zero indexed
The mhpm bits represent the number of bits available in mhpmcounter
while counter width describes a zero indexed value. Fix the counter width
calculation.

Fixes: 13d40f21d5 ("lib: sbi: Add PMU support")
Reviewed-by: Bin Meng <bmeng.cn@gmail.com>
Reviewed-by: Anup Patel <anup.patel@wdc.com>
Signed-off-by: Atish Patra <atish.patra@wdc.com>
2021-11-11 17:52:19 +05:30
Atish Patra
1e147324f0 lib: sbi: Reset the mhpmevent value upon counter reset
The hardware solely relies on the event selector value in mhpmevent
to figure out what event to monitor using that counter. It should be
reset when counter reset happens.

Reviewed-by: Anup Patel <anup.patel@wdc.com>
Reviewed-by: Bin Meng <bmeng.cn@gmail.com>
Signed-off-by: Atish Patra <atish.patra@wdc.com>
2021-11-11 17:50:32 +05:30
Atish Patra
0c304b6619 lib: sbi: Allow programmable counters to monitor cycle/instret events
A platform may use programmable counters for cycle/instret events.
The priv spec allows that provided that cycle/instret also report those
events in addition to the programmable counters. We should allow that
functionality in OpenSBI.

Reviewed-by: Anup Patel <anup.patel@wdc.com>
Reviewed-by: Bin Meng <bmeng.cn@gmail.com>
Signed-off-by: Atish Patra <atish.patra@wdc.com>
2021-11-11 17:48:45 +05:30
Atish Patra
2363f950bc lib: sbi: Always enable access for all counters
OpenSBI doesn't use any counters for its own usage. Thus, all the counters
can be made accessible for lower privilege mode always. However, the
mcountinhibit must be set so that the counter doesn't increment.
As a result, we don't have to enable/disable mcounteren at every start/stop.

Reviewed-by: Bin Meng <bmeng.cn@gmail.com>
Reviewed-by: Anup Patel <anup.patel@wdc.com>
Signed-off-by: Atish Patra <atish.patra@wdc.com>
2021-11-11 17:47:52 +05:30
Atish Patra
730f01bb41 lib: sbi: Support sscofpmf extension in OpenSBI
This patch adds sscofpmf extension in pmu module which includes
following things.

1. Enable overflow irq when starting a counter.
2. Setting the correct event filters passed from supervisor.
3. Delegating the overflow interrupt to the supervisor.
4. Add RV32 support for sscofpmf.

Reviewed-by: Anup Patel <anup.patel@wdc.com>
Reviewed-by: Bin Meng <bmeng.cn@gmail.com>
Signed-off-by: Atish Patra <atish.patra@wdc.com>
2021-11-11 17:46:57 +05:30
Atish Patra
9134c3643e lib: sbi: Delegate PMU counter overflow interrupt to S mode
OpenSBI doesn't handle PMU counters for now.

Delegate the overflow counter to S-mode always.

Reviewed-by: Bin Meng <bmeng.cn@gmail.com>
Reviewed-by: Anup Patel <anup.patel@wdc.com>
Signed-off-by: Atish Patra <atish.patra@wdc.com>
2021-11-11 17:45:12 +05:30
Atish Patra
867c65360d lib: sbi: Detect Sscofpmf extension at run time
Sscofpmf ISA extension introduces PMU counter overflow and filtering support.
It introduces a read only `scountovf` csr that can be used to detect if
a hart supports this extension at runtime. However, this feature is only
useful if the hart already supports mcounteren and mcountinhibit.

Add a dynamic detection mechanism and boot time print message if sscofpmf
is present.

Reviewed-by: Anup Patel <anup.patel@wdc.com>
Reviewed-by: Bin Meng <bmeng.cn@gmail.com>
Signed-off-by: Atish Patra <atish.patra@wdc.com>
2021-11-11 17:42:59 +05:30
Atish Patra
7084ad9f42 lib: sbi: Update csr_read/write_num for PMU
The Sscofpmf extension introduces mhpmevent[h] csrs to handle filtering
/overflow bits in RV32. There is no way to read/write mcountinhibit
using mcountinhibit csr using a variable.

Updated the support to read/write mhpmevent[h] and mcountinhibit csr.

Reviewed-by: Anup Patel <anup.patel@wdc.com>
Reviewed-by: Bin Meng <bmeng.cn@gmail.com>
Signed-off-by: Atish Patra <atish.patra@wdc.com>
2021-11-11 17:39:38 +05:30
Atish Patra
a74daf2cb9 riscv: Add new CSRs introduced by Sscofpmf[1] extension
[1] https://drive.google.com/file/d/1KcjgbLM5L1ZKY8934aJl8aQwGlMz6Cbo/view

Reviewed-by: Xiang W <wxjstz@126.com>
Reviewed-by: Bin Meng <bmeng.cn@gmail.com>
Reviewed-by: Anup Patel <anup.patel@wdc.com>
Signed-off-by: Atish Patra <atish.patra@wdc.com>
2021-11-11 17:37:34 +05:30
Heinrich Schuchardt
be245acfff lib: sbi: error handling in fdt_reset_init()
The initialization of a reset driver may fail for various reasons, like
a PMIC based reset driver not finding the required I2C driver. The return
code of the init routine may take other error values than -ENODEV.

If the initialization of a reset driver fails, this should not lead to the
board hanging. It is enough that the reset driver does not call
sbi_system_reset_add_device() to avoid invoking the driver for a device
that could not be initialized.

Change the return type of fdt_reset_init() to void.
Print a message if an error occurs.

Signed-off-by: Heinrich Schuchardt <heinrich.schuchardt@canonical.com>
Reviewed-by: Dong Du <Dd_nirvana@sjtu.edu.cn>
Reviewed-by: Anup Patel <anup.patel@wdc.com>
2021-11-08 10:50:48 +05:30
Heinrich Schuchardt
57f094e67e platform: generic: move fdt_reset_init to final_init
Move the fdt_reset_init() invocation from generic_early_init() to
generic_final_init(). This allows to print error messages.

Ignore the return value of fdt_reset_init() as we should not stop booting
due to failure to initialize reset drivers.

Signed-off-by: Heinrich Schuchardt <heinrich.schuchardt@canonical.com>
Reviewed-by: Dong Du <Dd_nirvana@sjtu.edu.cn>
Reviewed-by: Anup Patel <anup.patel@wdc.com>
2021-11-08 10:42:05 +05:30
Heinrich Schuchardt
2fe2f55d50 lib: sbi: move sbi_boot_print_general()
Moving the sbi_boot_print_general() call after the
sbi_platform_final_init() call allows to print devices initialized in the
latter.

To keep the overall print sequence the same also move
sbi_boot_print_domains().

Signed-off-by: Heinrich Schuchardt <heinrich.schuchardt@canonical.com>
Reviewed-by: Anup Patel <anup.patel@wdc.com>
2021-11-08 10:39:31 +05:30
Nikita Shubin
0979ffda12 lib: utils/gpio: use list for drivers
Convert static array to sbi_list.

This removes size limitation, makes add/remove more efficient and
saves space.

Signed-off-by: Nikita Shubin <n.shubin@yadro.com>
Reviewed-by: Anup Patel <anup.patel@wdc.com>
2021-11-03 15:57:56 +05:30
Anup Patel
013ba4ef3d lib: sbi: Fix GPA passed to __sbi_hfence_gvma_xyz() functions
The parameter passed to HFENCE.GVMA instruction in rs1 register
is guest physical address right shifted by 2 (i.e. divided by 4).

Unfortunately, we overlooked the semantics of rs1 registers for
HFENCE.GVMA instruction and never right shifted guest physical
address by 2. This issue did not manifest for hypervisors till
now because all H-extension implementations (such as QEMU, Spike,
Rocket Core FPGA, etc) we tried till now were conservatively
flushing everything upon any HFENCE.GVMA instruction.

This patch fixes GPA passed to __sbi_hfence_gvma_vmid_gpa()
and __sbi_hfence_gvma_gpa() functions.

Fixes: 331ff6a162 ("lib: Support stage1 and stage2 tlb flushing")
Reported-by: Ian Huang <ihuang@ventanamicro.com>
Signed-off-by: Anup Patel <anup.patel@wdc.com>
Reviewed-by: Xiang W <wxjstz@126.com>
Reviewed-by: Dong Du <Dd_nirvana@sjtu.edu.cn>
2021-11-02 16:02:08 +05:30
Alexandre Ghiti
c891acca17 include: sbi_utils: Introduce an helper to get fdt base address
This simply adds an helper to get fdt address which is more explicit than
sbi_scratch_thishart_arg1_ptr.

Signed-off-by: Alexandre Ghiti <alexandre.ghiti@canonical.com>
Reviewed-by: Xiang W <wxjstz@126.com>
Reviewed-by: Anup Patel <anup.patel@wdc.com>
2021-11-02 11:23:16 +05:30
Dong Du
723aa88ff4 lib: sbi: Refine addr format in sbi_printf
Although we have PRILX to help us print unsigned long without
considering the 32bit/64bit differences, there are still some
places using 08lx and 016lx manually --- leading to redundant code.

This commit fixes the issue by using PRILX all the time.

Signed-off-by: Dong Du <Dd_nirvana@sjtu.edu.cn>
Reviewed-by: Anup Patel <anup.patel@wdc.com>
2021-11-02 10:42:01 +05:30
Anup Patel
309e8bdf85 lib: utils/reset: Register separate GPIO system reset devices
Now that sbi_system support multiple system reset devices, we should
register separate devices for GPIO restart and GPIO poweroff because
DT describes these as separate devices with different compatible
strings.

Signed-off-by: Anup Patel <anup.patel@wdc.com>
Reviewed-by: Dong Du <Dd_nirvana@sjtu.edu.cn>
2021-11-02 09:14:11 +05:30
Samuel Holland
78c2b19218 lib: utils/irqchip: Automatically delegate T-HEAD PLIC access
The T-HEAD PLIC implementation requires setting a delegation bit
to allow access from S-mode. Now that the T-HEAD PLIC has its own
compatible string, set this bit automatically from the PLIC driver,
instead of reaching into the PLIC's MMIO space from another driver.

Signed-off-by: Samuel Holland <samuel@sholland.org>
Reviewed-by: Bin Meng <bmeng.cn@gmail.com>
Reviewed-by: Anup Patel <anup.patel@wdc.com>
2021-10-21 10:06:00 +05:30
Wei Fu
422eda499c Makefile: Add build time and compiler info string
When we are doing opensbi development, we want to know the build time
and compiler info for debug purpose.

To enable this message, please add "BUILD_INFO=y", like:

```
make BUILD_INFO=y
```

NOTE: Using `BUILD_INFO=y` without specifying SOURCE_DATE_EPOCH will
violate "reproducible builds". So it's ONLY for development and debug
purpose, and should NOT be used in a product which follows "reproducible
builds".

Signed-off-by: Wei Fu <wefu@redhat.com>
Reviewed-by: Anup Patel <anup.patel@wdc.com>
Reviewed-by: Alistair Francis <alistair.francis@wdc.com>
2021-10-20 15:10:52 +05:30
Heinrich Schuchardt
67cbbcb100 lib: sbi: system reset with invalid parameters
The SBI specification requires that sbi_system_reset() returns
SBI_ERR_INVALID_PARAM if reset_type or reset_reason are not valid.

Signed-off-by: Heinrich Schuchardt <heinrich.schuchardt@canonical.com>
Reviewed-by: Atish Patra <atish.patra@wdc.com>
Reviewed-by: Xiang W <wxjstz@126.com>
2021-10-18 16:07:21 +05:30
Anup Patel
c38973e087 lib: sbi: Save context for all non-retentive suspend types
Instead of saving context only for default non-retentive suspend,
we should save context for all non-retentive suspend types.

Fixes: 74756891cc ("lib: sbi: Implement SBI HSM suspend function")
Signed-off-by: Anup Patel <anup.patel@wdc.com>
Reviewed-by: Dong Du <Dd_nirvana@sjtu.edu.cn>
Reviewed-by: Xiang W <wxjstz@126.com>
2021-10-18 16:07:16 +05:30
Nikita Shubin
9283d503bd lib: sbi: add priority for reset handler
Let's make system_reset_check returning priority instead of only
true/false. In that case 0 - means not supported, and anything above
means priority that makes existing reset handlers being used in first
place, unless it is decided to lower their priority.

The handler with the most priority wins.

Signed-off-by: Nikita Shubin <n.shubin@yadro.com>
Reviewed-by: Anup Patel <anup.patel@wdc.com>
2021-10-11 10:32:26 +05:30
Nikita Shubin
516161c46f lib: sbi: convert reset to list
To support different handlers for different types of resets, we are
adding a sbi_list of restart handlers.

Instead of sbi_system_reset_set_device we use
sbi_system_reset_add_device to reflect the actual meaning.

Signed-off-by: Nikita Shubin <n.shubin@yadro.com>
Reviewed-by: Anup Patel <anup.patel@wdc.com>
2021-10-11 09:59:29 +05:30
Heinrich Schuchardt
754d51192b lib: utils: identify supported GPIO reset methods
The GPIO reset driver supports reset and poweroff. But not all boards
support both. gpio_system_reset_check() must detect this situation.

Signed-off-by: Heinrich Schuchardt <heinrich.schuchardt@canonical.com>
Reviewed-by: Anup Patel <anup.patel@wdc.com>
2021-10-01 10:24:43 +05:30
Anup Patel
fa59dd317a lib: utils/reset: use sbi_timer_mdelay() in gpio reset driver
We should use sbi_timer_mdelay() instead of custom gpio_mdelay() in
the gpio reset driver.

Signed-off-by: Anup Patel <anup.patel@wdc.com>
Reviewed-by: Bin Meng <bmeng.cn@gmail.com>
Reviewed-by: Xiang W <wxjstz@126.com>
2021-09-26 19:52:18 +05:30
Anup Patel
9d0ab35ab4 lib: sbi: Add generic timer delay loop function
We now have frequency of the timer device provided by the platform
support so we can emulate desired delay using a loop where the number
loop iterations are based on timer frequency.

This patch provides sbi_timer_delay_loop() for above purpose.

Signed-off-by: Anup Patel <anup.patel@wdc.com>
Reviewed-by: Bin Meng <bmeng.cn@gmail.com>
Reviewed-by: Xiang W <wxjstz@126.com>
2021-09-26 19:52:15 +05:30
Anup Patel
6355155f51 lib: sbi: Print timer frequency at boot time
We now have frequency in timer device instance provided by platform
so let's print timer frequency as part of the boot prints.

Signed-off-by: Anup Patel <anup.patel@wdc.com>
Reviewed-by: Bin Meng <bmeng.cn@gmail.com>
Reviewed-by: Xiang W <wxjstz@126.com>
2021-09-26 19:52:12 +05:30
Anup Patel
12e7af9ab7 lib: sbi: Add timer frequency to struct sbi_timer_device
Generic mdelay() and udelay() functions can be provided by the
sbi_timer framework if timer frequency is available in the timer
instance provided by the platform support or timer driver.

This patch adds timer frequency (timer_freq) member in the
struct sbi_timer_device for above purpose.

Signed-off-by: Anup Patel <anup.patel@wdc.com>
Reviewed-by: Bin Meng <bmeng.cn@gmail.com>
Reviewed-by: Xiang W <wxjstz@126.com>
2021-09-26 19:52:10 +05:30
Anup Patel
72154f4708 lib: utils/fdt: Add fdt_parse_timebase_frequency() function
We add fdt_parse_timebase_frequency() function which can be used
by ACLINT mtimer driver and platform code to get timebase frequency.

Signed-off-by: Anup Patel <anup.patel@wdc.com>
Reviewed-by: Bin Meng <bmeng.cn@gmail.com>
Reviewed-by: Xiang W <wxjstz@126.com>
2021-09-26 19:52:07 +05:30
Xiang W
51113fe2a5 lib: sbi: Add BUG() macro for csr_read/write_num() and misa_string()
We use BUG() macro in csr_read_num(), csr_write_num(), and
misa_string() functions for unhandled cases.

Signed-off-by: Xiang W <wxjstz@126.com>
Reviewed-by: Anup Patel <anup.patel@wdc.com>
2021-09-22 13:38:39 +05:30
Xiang W
12753d2256 lib: sbi: add some macros to detect BUG at runtime
Three macros are added. One is called BUG, which is used to put in an
unreachable branch. One is called BUG_ON, which is used to check bugs
and assert conditions are opposite. One is called SBI_ASSERT, used for
assertion checking.

Signed-off-by: Xiang W <wxjstz@126.com>
Reviewed-by: Anup Patel <anup.patel@wdc.com>
2021-09-22 13:35:30 +05:30
Xiang W
3477f08b08 lib: sbi: fix ctz bug
The original version of ctz will cause an endless loop, if the parameter
passed in is 0. This commit fixes this bug.

Signed-off-by: Xiang W <wxjstz@126.com>
Reviewed-by: Bin Meng <bmeng.cn@gmail.com>
Reviewed-by: Anup Patel <anup.patel@wdc.com>
2021-09-22 13:26:23 +05:30
Samuel Holland
395ff7eede lib: utils/reset: Add a sunxi watchdog reset driver
One of the watchdogs in the D1 SoC provides a "soft reset" function,
which allows software to immediately reset the entire SoC. Add a driver
so it can implement the SBI system reset function.

Signed-off-by: Samuel Holland <samuel@sholland.org>
Reviewed-by: Anup Patel <anup.patel@wdc.com>
2021-09-14 13:24:53 +05:30
Samuel Holland
0274a96004 lib: utils/reset: Sort fdt_reset driver list
In preparation for adding a new fdt_reset driver, ensure the existing
lists are sorted alphabetically.

Signed-off-by: Samuel Holland <samuel@sholland.org>
Reviewed-by: Anup Patel <anup.patel@wdc.com>
2021-09-14 12:13:55 +05:30
Dong Du
bd355213bf lib: sbi: Refine the way to construct platform features
sbi_platform_get_features_str() uses sbi_snprintf() to construct the
features_str. However, it passes the wrong length value (i.e., the nfstr),
which should be (nfstr-offset) as the starting point of str (i.e.,
features_str + offset) changes.

This commit also checks the return value of snprintf, and handles the
corner case that the string buffer is full.

Signed-off-by: Dong Du <Dd_nirvana@sjtu.edu.cn>
Reviewed-by: Atish Patra <atish.patra@wdc.com>
2021-09-03 12:16:01 +05:30
Dong Du
1718b1642e lib: sbi: Checking fifo validness in sbi_fifo_is_empty and is_full
As other exported fifo functions, we should check whether the fifo is
valid in sbi_fifo_is_empty and sbi_fifo_is_full. To this end, this patch
changes the retval from bool to int, and the two functions will return
SBI_EINVAL in the case the fifo is invalid.

Signed-off-by: Dong Du <Dd_nirvana@sjtu.edu.cn>
Reviewed-by: Atish Patra <atish.patra@wdc.com>
2021-09-03 11:59:35 +05:30
Dong Du
c262306533 lib: sbi: protect dprintf output with spinlock
Avoid getting messages from multiple harts (using dprintf and printf)
concurrently with a spinlock serializaing calls to sbi_dprintf(),
sbi_printf() and sbi_puts()

Signed-off-by: Dong Du <Dd_nirvana@sjtu.edu.cn>
Reviewed-by: Xiang W <wxjstz@126.com>
Reviewed-by: Anup Patel <anup.patel@wdc.com>
2021-08-30 09:12:37 +05:30
Rahul Pathak
bd316e2c9b lib: sbi: Correct typo in faults delegation CSR name
Correcting the name of faults delegation CSR
%s/mfdeleg/medeleg

Signed-off-by: Rahul Pathak <rpathak@ventanamicro.com>
Reviewed-by: Anup Patel <anup.patel@wdc.com>
2021-08-30 09:07:47 +05:30
Samuel Holland
b1d3e91e9a payloads/test: Add support for SBI v0.2 ecalls
It can be useful to make SBI v0.2 or newer ecalls from this payload
for testing purposes. To support this, convert the macros to use the
extension/function parameter convention.

Signed-off-by: Samuel Holland <samuel@sholland.org>
Reviewed-by: Atish Patra <atish.patra@wdc.com>
2021-08-20 09:48:45 +05:30
Samuel Holland
ee274377b2 lib: sbi_trap: Restore redirect for access faults
commit 764a17d852 ("lib: sbi: Implement firmware counters") added
switch cases for CAUSE_LOAD_ACCESS and CAUSE_STORE_ACCESS. This caused
them to stop being redirected to U or S mode, as that is handled in the
default switch case. As a result, an error in userspace could cause the
system to hang. Fix this by allowing the acces fault case to fall
through to the default case.

Fixes: 764a17d852 ("lib: sbi: Implement firmware counters")
Signed-off-by: Samuel Holland <samuel@sholland.org>
Reviewed-by: Atish Patra <atish.patra@wdc.com>
Reviewed-by: Bin Meng <bmeng.cn@gmail.com>
2021-08-20 09:47:40 +05:30
Dong Du
33eac764f2 lib: sbi: Fix bug in sbi_ecall_rfence that misses checking
In sbi_ecall_rfence_handler, it will compare the funcid with
REMOTE_HFENCE_GVMA and REMOTE_HFENCE_VVMA_ASID. Later it check
whether the misa includes H-extension. This checking is incomplete
which misses REMOTE_HFENCE_GVMA_VMID and REMOTE_HFENCE_VVMA.

Fix the issue by updating the checking range.

Signed-off-by: Dong Du <Dd_nirvana@sjtu.edu.cn>
Reviewed-by: Atish Patra <atish.patra@wdc.com>
2021-08-20 09:42:39 +05:30
Anup Patel
7aa6c9aa96 lib: utils/timer: Simplify MTIMER synchronization
We simplify MTIMER synchronization as follows:

1) Detect MTIMER devices with unique (or non-shared) MTIME
   register at boot-time
2) Select first MTIMER device with no associated HART as our
   reference MTIMER device
3) Only synchronize MTIMER devices with unique (or non-shared)
   MTIME register using reference MTIMER device
4) Directly update the MTIME register at time of synchronization
   because MTIME is a read/write register.

Signed-off-by: Anup Patel <anup.patel@wdc.com>
Reviewed-by: Atish Patra <atish.patra@wdc.com>
2021-08-14 09:07:42 +05:30
Anup Patel
b35f7826b0 lib: utils/timer: Allow ACLINT MTIMER supporting only 32-bit MMIO
We can have ACLINT MTIMER devices which only support 32-bit MMIO
accesses on RV64 system so this patch adds a boolean DT property
"mtimer,no-64bit-mmio" to detect this from MTIMER DT node.

Signed-off-by: Anup Patel <anup.patel@wdc.com>
Reviewed-by: Atish Patra <atish.patra@wdc.com>
2021-08-14 09:02:44 +05:30
Anup Patel
f3a0eb8583 lib: utils/fdt: Extend fdt_parse_aclint_node() function
The fdt_parse_aclint_node() is used to parse DT node for SiFive
CLINT, ACLINT MTIMER, and ACLINT MSWI devices.

The ACLINT MTIMER has undergone following changes:
1) MTIMER DT node now requires separate addresses in for MTIME
   register and MTIMECMPx registers in the reg DT property.
2) MTIMER DT node might have no interrupts-extended DT property
   when the MTIMER device has no associated HARTs (i.e. the
   MTIMER device has no MTIMECMPx registers)

This patch extends fdt_parse_aclint_node() to handle above
mentioned changes in ACLINT MTIMER DT bindings.

Signed-off-by: Anup Patel <anup.patel@wdc.com>
Reviewed-by: Atish Patra <atish.patra@wdc.com>
2021-08-14 09:02:39 +05:30
Anup Patel
7a3a0cce4d lib: utils: Extend fdt_get_node_addr_size() for multiple register sets
We add "index" parameter to fdt_get_node_addr_size() API so that
calling function can specify index of desired register set. This
will allow fdt_get_node_addr_size() to handle DT nodes with
multiple register sets.

Signed-off-by: Anup Patel <anup.patel@wdc.com>
Reviewed-by: Atish Patra <atish.patra@wdc.com>
2021-08-14 09:02:36 +05:30
Anup Patel
e0d1b9db8a lib: utils/timer: Allow separate base addresses for MTIME and MTIMECMP
We extend the ACLINT library to support separate base addresses
for MTIME and MTIMECMP registers.

Signed-off-by: Anup Patel <anup.patel@wdc.com>
Reviewed-by: Atish Patra <atish.patra@wdc.com>
2021-08-14 09:02:33 +05:30
Bin Meng
47a47654e8 lib: utils/fdt: Change addr and size to uint64_t
The maximum address and size encoded in DT are 64-bit numbers, so we
should use uint64_t for 'addr' and 'size' in fdt_get_node_addr_size().

Signed-off-by: Bin Meng <bmeng.cn@gmail.com>
Reviewed-by: Anup Patel <anup.patel@wdc.com>
2021-08-07 17:26:51 +05:30
Dong Du
d244f3dbd6 lib: sbi: Fix bug in strncmp function when count is 0
No need to compare characters when the count turns to 0.
Fix the issue in sbi_strncmp.

Signed-off-by: Dong Du <Dd_nirvana@sjtu.edu.cn>
Reviewed-by: Bin Meng <bmeng.cn@gmail.com>
Reviewed-by: Anup Patel <anup.patel@wdc.com>
2021-08-07 15:40:40 +05:30
Heinrich Schuchardt
e928472e67 lib: utils: support both of gpio-poweroff, gpio-reset
The generic GPIO reset driver has two entries in the match table:
"gpio-poweroff", "gpio-reset". Only the first entry is considered by
fdt_reset_init().

Define "gpio-poweroff" and "gpio-reset" as compatibility strings of two
separate reset drivers. They still can share code.

Fixes: e3d6919d10 ("lib: utils/reset: Add generic GPIO reset driver")
Signed-off-by: Heinrich Schuchardt <heinrich.schuchardt@canonical.com>
Reviewed-by: Atish Patra <atish.patra@wdc.com>
2021-07-27 17:26:54 +05:30
Heinrich Schuchardt
ce03c88ee1 lib: utils: remove unused variable in fdt_reset_init
The value of variable current_driver is unused. Remove the variable.

Signed-off-by: Heinrich Schuchardt <heinrich.schuchardt@canonical.com>
Reviewed-by: Atish Patra <atish.patra@wdc.com>
2021-07-27 17:16:02 +05:30
David Abdurachmanov
217d5e4880 generic: fu740: add workaround for CIP-1200 errata
Instruction TLB can fail to respect a non-global SFENCE thus we need to
flush the TLB using SFENCE.VMA x0, x0

See full description of CIP-1200 in Errata_FU740-C000_20210205 from
https://www.sifive.com/boards/hifive-unmatched

Signed-off-by: David Abdurachmanov <david.abdurachmanov@sifive.com>
Signed-off-by: Heinrich Schuchardt <heinrich.schuchardt@canonical.com>
2021-07-27 15:29:59 +05:30
Xiang W
74db0acbe5 firmware: use _fw_start for load address
The previous code uses _start as the load address, this default .entry is
the first segment, using _fw_start does not need to make this assumption.

Signed-off-by: Xiang W <wxjstz@126.com>
Reviewed-by: Anup Patel <anup.patel@wdc.com>
2021-07-27 15:20:49 +05:30
Bin Meng
989039117f Makefile: Manually forward RELAX_FLAG to the assembler when linking with LLD
When generating code with -mno-relax, GCC puts .option norelax in
the generated assembly, and so doesn’t bother passing on -mno-relax
to the assembler. This has the unfortunate effect that, when using
GCC to assemble hand-written assembly, -mno-relax does nothing,
and we have to pass -Wa,-mno-relax to manually forward it to the
assembler.

This is an old GCC bug that was fixed [1] recently. For the time
being, let's pass "-Wa,-mno-relax" to ASFLAGS for the GCC + LLD
combination to work, e.g.:

  $ make CC=riscv64-unknown-elf-gcc LLVM=1 PLATFORM=generic

[1] 3b0a7d624e

Signed-off-by: Bin Meng <bmeng.cn@gmail.com>
Reviewed-by: Anup Patel <anup.patel@wdc.com>
2021-07-27 14:29:31 +05:30
Bin Meng
81eb7088b6 README: Update toolchain information
Recent FW_PIC=y changes actually require toolchains with PIE support
and it is on by default. Existing doc uses a GNU bare-metal toolchain
as examples but it does not support PIE.

Replace references of bare-metal toolchain prefix with Linux toolchain
prefix everywhere in documentation.

Also indicate that "riscv64-unknown-freebsd-" as an alternative to
"riscv64-linux-" GNU toolchain.

Signed-off-by: Bin Meng <bmeng.cn@gmail.com>
Reviewed-by: Anup Patel <anup.patel@wdc.com>
2021-07-17 18:32:20 +05:30
Bin Meng
2c74dc3c47 docs: Document FW_PIC compile time option
FW_PIC=y is on by default, but the doc is missing when this was
introduced. Add some description for it.

Signed-off-by: Bin Meng <bmeng.cn@gmail.com>
Reviewed-by: Anup Patel <anup.patel@wdc.com>
2021-07-17 17:43:37 +05:30
Bin Meng
a4555e5698 docs: Document parameters passed to firmware and alignment requirement
This updates documentation to describe parameters passed to firmware
from previous booting stage, and corresponding address alignment
requirement.

This also fixes a typo in fw_dynamic.md (it's => its).

Signed-off-by: Bin Meng <bmeng.cn@gmail.com>
Reviewed-by: Anup Patel <anup.patel@wdc.com>
2021-07-17 17:30:48 +05:30
Bin Meng
8a1475b5a1 firmware: Remove the unhelpful alignment codes before fdt relocation
If the device tree is at an address that is not __SIZEOF_POINTER__
aligned, the fdt relocation code tries to align both source and
destination address to __SIZEOF_POINTER__ before the memory copy.
But such alignment can lead to unexpected results if either source
or destination address is not aligned.

In fact libfdt requires that the device tree must be at an 8-byte
aligned address. Hence remove the unhelpful alignment codes.

Signed-off-by: Bin Meng <bmeng.cn@gmail.com>
Reviewed-by: Anup Patel <anup.patel@wdc.com>
2021-07-17 17:13:43 +05:30
Alex Richardson
f3a8f603a7 include: types: Use __builtin_offsetof when supported
Clang provides a __builtin_offsetof which can be detected using
__has_builtin().

Signed-off-by: Alex Richardson <Alexander.Richardson@cl.cam.ac.uk>
Reviewed-by: Anup Patel <anup.patel@wdc.com>
2021-07-17 16:40:07 +05:30
Alex Richardson
7210e90785 firmware: use __SIZEOF_LONG__ for field offsets in fw_dynamic.h
The fields are of type unsigned long and are not pointers. While this
happens to be the same for RV32/RV64, it is not correct when compiling
for a CHERI-RISC-V system where pointers are twice the size of long.

Signed-off-by: Alex Richardson <Alexander.Richardson@cl.cam.ac.uk>
Reviewed-by: Bin Meng <bmeng.cn@gmail.com>
Reviewed-by: Anup Patel <anup.patel@wdc.com>
2021-07-17 16:35:23 +05:30
Green Wan
e3d6919d10 lib: utils/reset: Add generic GPIO reset driver
We add generic GPIO reset driver inspired from gpio-restart
and gpio-poweroff drivers of Linux kernel.

Signed-off-by: Green Wan <green.wan@sifive.com>
Signed-off-by: Anup Patel <anup.patel@wdc.com>
Reviewed-by: Atish Patra <atish.patra@wdc.com>
2021-07-17 14:12:07 +05:30
Green Wan
4c3df2ab96 lib: utils/gpio: Add minimal SiFive GPIO driver
We add a minimal SiFive GPIO driver so that we can do GPIO based
system power-off and reset.

Signed-off-by: Green Wan <green.wan@sifive.com>
Signed-off-by: Anup Patel <anup.patel@wdc.com>
Reviewed-by: Atish Patra <atish.patra@wdc.com>
2021-07-17 13:56:42 +05:30
Anup Patel
c14f1fe0df lib: utils/gpio: Add simple FDT based GPIO framework
We add a simple FDT based GPIO framework which is built on top
of generic GPIO library. The phandle of FDT GPIO chip DT node
is treated as unique GPIO chip ID required by the generic GPIO
library. The FDT based GPIO chip drivers will be probed on-demand
from fdt_gpio_pin_get() called by the GPIO client drivers.

Signed-off-by: Anup Patel <anup.patel@wdc.com>
Reviewed-by: Atish Patra <atish.patra@wdc.com>
2021-07-17 13:41:17 +05:30
Anup Patel
36b8effe4a lib: utils/gpio: Add generic GPIO configuration library
We add generic GPIO configuration library which is independent of
hardware description format (FDT or ACPI). The OpenSBI platform
support or GPIO drivers can register GPIO chip instances which
can be discovered and used by different GPIO clients. Each GPIO
chip instance has a unique ID which can be used by GPIO clients
to lookup GPIO chip instance.

Signed-off-by: Anup Patel <anup.patel@wdc.com>
Reviewed-by: Atish Patra <atish.patra@wdc.com>
2021-07-17 11:42:51 +05:30
Anup Patel
e931f387b2 lib: utils/fdt: Add fdt_parse_phandle_with_args() API
The libfdt project does not have a generic API to parse phandle
with args from a DT node so we add fdt_parse_phandle_with_args()
for this purpose. This new API will be useful to FDT based drivers.

Signed-off-by: Anup Patel <anup.patel@wdc.com>
Reviewed-by: Atish Patra <atish.patra@wdc.com>
2021-07-17 11:40:49 +05:30
Jessica Clarke
17729d44da lib: utils: Drop dependency on libgcc by importing part of FreeBSD's libquad
We only need libgcc for 64-bit division on RV32. Whilst GCC toolchains
bundle libgcc, Clang toolchains tend not to ship libclang_rt.builtins
given every compiler is a cross-compiler for every target and so you
would need a silly number of builds of it, with only the native library
available; only vendor-provided Clang toolchains specifically for bare
metal cross-compiling are likely to provide it.

Thus, import part of FreeBSD's implementation of the division support
functions needed and stop linking against libgcc.

Signed-off-by: Jessica Clarke <jrtc27@jrtc27.com>
Reviewed-by: Anup Patel <anup.patel@wdc.com>
Tested-by: Anup Patel <anup.patel@wdc.com>
2021-07-11 21:01:44 +05:30
Jessica Clarke
2942777425 Makefile: Support building with Clang and LLVM binutils
This is intended to mirror the Linux kernel. Building with CC=clang will
use Clang as the compiler but default to using the existing binutils.
Building with LLVM=1 will default to using Clang and LLVM binutils.

Whilst GCC will accept the -N linker option and forward it on to the
linker, Clang will not, and so in order to support both compilers we
must use -Wl, to forward it to the linker as is required for most other
linker options.

Note that there is currently a bug when using Clang as the compiler and
riscv64-linux-gnu-ld as the linker for FW_PIC=y. At first glance this
appears to be a bug in GNU binutils, but this could also be Clang or
OpenSBI at fault in some subtle way. Thus, for now, advise that this
combination be avoided.

Signed-off-by: Jessica Clarke <jrtc27@jrtc27.com>
Reviewed-by: Anup Patel <anup.patel@wdc.com>
Tested-by: Anup Patel <anup.patel@wdc.com>
2021-07-11 20:22:55 +05:30
Jessica Clarke
09ad811ec4 firmware: Only default FW_PIC to y if supported
Bare-metal GNU ld does not support PIE, so if using it this will result
in a failure to build. Instead, default to FW_PIC=n if not supported.
Note that an explicit FW_PIC=y is not overridden, to ensure the build
fails rather than silently producing a position-dependent binary.

Signed-off-by: Jessica Clarke <jrtc27@jrtc27.com>
Reviewed-by: Bin Meng <bmeng.cn@gmail.com>
Tested-by: Bin Meng <bmeng.cn@gmail.com>
Reviewed-by: Anup Patel <anup.patel@wdc.com>
2021-07-11 20:03:06 +05:30
Jessica Clarke
a3d328ae33 firmware: Explicitly pass -pie to the linker, not just the driver
When using Clang with a bare-metal triple, -pie does not get passed to
the linker as it's not normally a thing that makes sense, unlike GCC
which will unconditionally forward it on and potentially result in a
linker error. However, LLD does support it, and manually forwarding it
on works as desired, so do so to fully support FW_PIC with Clang and
LLD.

Signed-off-by: Jessica Clarke <jrtc27@jrtc27.com>
Reviewed-by: Bin Meng <bmeng.cn@gmail.com>
Tested-by: Bin Meng <bmeng.cn@gmail.com>
Reviewed-by: Anup Patel <anup.patel@wdc.com>
2021-07-11 20:01:56 +05:30
Jessica Clarke
397afe5ba1 fw_base: Put data in .data rather than .text
The -N linker option is supposed to make .text writable, but GNU ld and
LLD differ in interpreting what that means. GNU ld will happily let you
have relocations in it, but LLD will see that the input section is
read-only (even though the output section is writable) and give an
error. It's unclear if either of them intend to have that behaviour in
this edge case, but regardless there's no reason not to just put the
data in a writable .data section.

Signed-off-by: Jessica Clarke <jrtc27@jrtc27.com>
Reviewed-by: Bin Meng <bmeng.cn@gmail.com>
Tested-by: Bin Meng <bmeng.cn@gmail.com>
Reviewed-by: Anup Patel <anup.patel@wdc.com>
2021-07-11 17:33:30 +05:30
Jessica Clarke
7f1be8a624 fw_base: Don't mark fw_platform_init as both global and weak
These are mutually exclusive. GNU as and LLVM both let later binding
directives override earlier ones so this works as intended, but LLVM 12
turned this into a warning as there's no good reason to do such a thing
and could be a potential bug. Thus, remove the redundant and incorrect
.globl directive for fw_platform_init.

Signed-off-by: Jessica Clarke <jrtc27@jrtc27.com>
Reviewed-by: Bin Meng <bmeng.cn@gmail.com>
Tested-by: Bin Meng <bmeng.cn@gmail.com>
Reviewed-by: Anup Patel <anup.patel@wdc.com>
2021-07-11 17:20:42 +05:30
Anup Patel
a76ac4449b lib: sbi: Fix sbi_pmu_exit() for systems not having MCOUNTINHIBIT csr
The sbi_pmu_exit() crashes on systems not having MCOUNTINHIBIT csr
so to fix this we check SBI_HART_HAS_MCOUNTINHIBIT feature in
sbi_pmu_exit() and do nothing if it is not available.

Fixes: 13d40f21d5 ("lib: sbi: Add PMU support")
Signed-off-by: Anup Patel <anup.patel@wdc.com>
2021-07-11 14:31:21 +05:30
Bin Meng
b88b3661d4 firmware: Define a macro for version of struct fw_dynamic_info
Avoid using a magic number, instead use a macro for the version of
struct fw_dynamic_info.

Signed-off-by: Bin Meng <bmeng.cn@gmail.com>
Reviewed-by: Xiang W <wxjstz@126.com>
Reviewed-by: Anup Patel <anup.patel@wdc.com>
2021-07-11 14:13:32 +05:30
Bin Meng
dcb756b01a firmware: Remove the sanity checks in fw_save_info()
The sanity checks on the magic and version was already done in
fw_boot_hart(), which happens before fw_save_info() is called.

Signed-off-by: Bin Meng <bmeng.cn@gmail.com>
Reviewed-by: Xiang W <wxjstz@126.com>
Reviewed-by: Anup Patel <anup.patel@wdc.com>
2021-07-11 14:09:10 +05:30
Bin Meng
abfce9b25c docs: Make <xyz> visible in the rendered platform guide
At present in the rendered platform guide, all instances of <xyz>
are missing. Use &lt; and &gt; to replace <> to make them visible.

Signed-off-by: Bin Meng <bmeng.cn@gmail.com>
Reviewed-by: Xiang W <wxjstz@126.com>
Reviewed-by: Anup Patel <anup.patel@wdc.com>
2021-07-11 11:58:31 +05:30
Bin Meng
dafaa0f54b docs: Correct a typo in platform_guide.md
It's riscv-pk, not riskv-pk.

Signed-off-by: Bin Meng <bmeng.cn@gmail.com>
Reviewed-by: Xiang W <wxjstz@126.com>
Reviewed-by: Anup Patel <anup.patel@wdc.com>
2021-07-11 11:55:55 +05:30
Bin Meng
14c7f71c0d firmware: Minor optimization in _scratch_init()
Before entering _scratch_init(), register t3 already holds a copy
of the firmware end address, hence there is no need to calculate
it again. This reduces 3 instructions in each _scratch_init() loop.

Signed-off-by: Bin Meng <bmeng.cn@gmail.com>
Reviewed-by: Xiang W <wxjstz@126.com>
Reviewed-by: Atish Patra <atish.patra@wdc.com>
2021-07-11 11:41:50 +05:30
Atish Patra
0e12aa8dee platform: generic: Add PMU support
Add PMU support for generic platform. Generic platform solely relies on
the device tree to parse all pmu related information. If any event is
not described in device tree, generic platform will not support it.

Reviewed-by: Anup Patel <anup.patel@wdc.com>
Signed-off-by: Atish Patra <atish.patra@wdc.com>
2021-07-11 10:39:42 +05:30
Atish Patra
ec1b8bb763 lib: sbi: Improve TLB function naming
Follow the standard conventon for static function names:

	All global functions should be start with sbi_<module name>_
	All static functions should be start with <module name>_

Reviewed-by: Anup Patel <anup.patel@wdc.com>
Signed-off-by: Atish Patra <atish.patra@wdc.com>
2021-07-11 10:38:26 +05:30
Atish Patra
764a17d852 lib: sbi: Implement firmware counters
RISC-V SBI v0.3 specification defines a set of firmware events that can
provide additional information about the current firmware context. All
of the firmware event monitoring are enabled now. The firmware
events must be defined as raw perf event with MSB set as specified in the
specification.

Reviewed-by: Anup Patel <anup.patel@wdc.com>
Signed-off-by: Atish Patra <atish.patra@wdc.com>
2021-07-11 10:38:23 +05:30
Atish Patra
37f9b0f2f2 lib: sbi: Implement SBI PMU extension
RISC-V SBI specfication 0.3 defines a PMU extension that allows supervisor
mode to start/stop/configure pmu related events. This patch implements
all of the functionality defined in the specification.

Reviewed-by: Anup Patel <anup.patel@wdc.com>
Signed-off-by: Atish Patra <atish.patra@wdc.com>
2021-07-11 10:38:02 +05:30
Atish Patra
ae72ec0915 utils: fdt: Add fdt helper functions to parse PMU DT nodes
The PMU DT node bindings are defined in docs/pmu_support.md
Add few fdt helper functions to parse the DT node and update the
event-counter mapping tables.

Reviewed-by: Anup Patel <anup.patel@wdc.com>
Signed-off-by: Atish Patra <atish.patra@wdc.com>
2021-07-11 10:27:57 +05:30
Atish Patra
13d40f21d5 lib: sbi: Add PMU support
RISC-V SBI v0.3 specification defined a PMU extension to configure/start/stop
the hardware/firmware pmu events.

Implement PMU support in OpenSBI library. The implementation is agnostic of
event to counter mapping & mhpmevent value configuration. That means, it
expects platform hooks will be used to set up the mapping and provide
the mhpmevent value at runtime.

Reviewed-by: Anup Patel <anup.patel@wdc.com>
Signed-off-by: Atish Patra <atish.patra@wdc.com>
2021-07-11 10:23:18 +05:30
Atish Patra
e7cc7a3ab2 lib: sbi: Add PMU specific platform hooks
A platform hook to initialize PMU allows platform vendors to provide
their own mechanism to define pmu event-counter mappings in addition
to the DT based approach.

Another platform hook that allows platform vendors customize the
final mhpmevent value configuration.

Reviewed-by: Anup Patel <anup.patel@wdc.com>
Signed-off-by: Atish Patra <atish.patra@wdc.com>
2021-07-11 10:21:38 +05:30
Atish Patra
49966db306 lib: sbi: Use csr_read/write_num to read/update PMU counters
Currently, csr_read/write_num functions are used to read/write PMP related
CSRs where CSR value is decided at runtime. Expand this function to include
PMU related CSRs as well.

Reviewed-by: Anup Patel <anup.patel@wdc.com>
Reviewed-by: Xiang W <wxjstz@126.com>
Signed-off-by: Atish Patra <atish.patra@wdc.com>
2021-07-11 10:20:44 +05:30
Atish Patra
fd9116bd46 lib: sbi: Remove redundant boot time print statement
This patch removes redundant print from sbi_boot_print_hart().

Reviewed-by: Anup Patel <anup.patel@wdc.com>
Signed-off-by: Atish Patra <atish.patra@wdc.com>
2021-07-11 10:19:48 +05:30
Atish Patra
41ae63cd0a include: Add a list empty check function
Implement a list helper function that checks for empty lists.

Reviewed-by: Anup Patel <anup.patel@wdc.com>
Reviewed-by: Xiang W <wxjstz@126.com>
Signed-off-by: Atish Patra <atish.patra@wdc.com>
2021-07-11 10:15:29 +05:30
Atish Patra
9c9b4ad24b lib: sbi: Disable m/scounteren & enable mcountinhibit
Currently, all bits in mcountern are enabled unconditionally at boot time.
With SBI PMU extension, all the programmable counters should enabled only
during performance monitoring for a particular event. However, this is done
only if mcountinhibit is implemented because the supervisor mode can not
start/stop any event without mcountinhibit.

Similarly, supervisor should take care enabling scounteren which allows
U-mode to access programmable pmu counters. All the non-programmable ones
(CY, TM, IR) should be enabled in M-mode because some userspace may rely on
builtins such as __builtin_readcyclecounter. Supervisor OS can still disable
them during initial configuration.

Reviewed-by: Anup Patel <anup.patel@wdc.com>
Signed-off-by: Atish Patra <atish.patra@wdc.com>
2021-07-11 10:14:26 +05:30
Atish Patra
0829f2bc28 lib: sbi: Detect number of bits implemented in mhpmcounter
RISC-V privilege specification allows the implementation to have less
than 64 bits.

Add a function to detect the number of implemented bits in mhpmcounter
dynamically at runtime.

Reviewed-by: Xiang W <wxjstz@126.com>
Reviewed-by: Anup Patel <anup.patel@wdc.com>
Signed-off-by: Atish Patra <atish.patra@wdc.com>
2021-07-11 10:13:04 +05:30
Atish Patra
d3a96cc469 lib: sbi: Remove stray '\' character
Reviewed-by: Xiang W <wxjstz@126.com>
Reviewed-by: Anup Patel <anup.patel@wdc.com>
Signed-off-by: Atish Patra <atish.patra@wdc.com>
2021-07-11 10:12:06 +05:30
Atish Patra
fde28fadc2 lib: sbi: Detect mcountinihibit support at runtime
RISC-V ISA specification v1.11 defined mcountinhibit CSR that allows
software to stop any counter from incrementing. The SBI PMU extension
depends on this CSR support in hardware.

Define mcountinhibit as a hart specific feature and detect it at runtime.

Reviewed-by: Anup Patel <anup.patel@wdc.com>
Signed-off-by: Atish Patra <atish.patra@wdc.com>
2021-07-11 10:11:10 +05:30
Atish Patra
3e8b31aca9 docs: Add device tree bindings for SBI PMU extension
SBI PMU extension requires a firmware to be aware of the event to
counter/mhpmevent mappings supported by the hardware. One approach
is to encode that information in the device tree.

Define a device tree binding that allows a hardware to describe
all the PMU mappings required in concise format.

Reviewed-by: Anup Patel <anup.patel@wdc.com>
Signed-off-by: Atish Patra <atish.patra@wdc.com>
2021-07-11 10:10:16 +05:30
Bin Meng
17e23b678d platform: generic: Terminate platform.name with null
fw_platform_init() fills platform.name without considering the
ending null character. Fix it.

Signed-off-by: Bin Meng <bmeng.cn@gmail.com>
Reviewed-by: Anup Patel <anup.patel@wdc.com>
2021-07-06 14:21:53 +05:30
Bin Meng
197e08941b docs/platform: thead-c9xx: Remove FW_PIC=y
FW_PIC is on by default. Hence no need to explicitly require it.

Signed-off-by: Bin Meng <bmeng.cn@gmail.com>
Reviewed-by: Anup Patel <anup.patel@wdc.com>
2021-07-06 10:50:44 +05:30
Green Wan
b7f2cd268b lib: utils: reset: unify naming of 'sifive_test' device
Unify all the file and function names of 'sifive_test' device, to use
the same prefix. This is also a preparatory patch for upcoming sifive
reset device.

Signed-off-by: Green Wan <green.wan@sifive.com>
Reviewed-by: Bin Meng <bmeng.cn@gmail.com>
Reviewed-by: Anup Patel <anup.patel@wdc.com>
2021-07-05 21:36:40 +05:30
Anup Patel
a731c7e369 platform: Replace CLINT library usage with ACLINT library
The ACLINT devices are backward compatible with SiFive CLINT
so we replace all CLINT library usage in various platforms
with ACLINT library. As a result of this replacement, the
CLINT library is not used by any part of OpenSBI hence we
remove it.

Signed-off-by: Anup Patel <anup.patel@wdc.com>
Reviewed-by: Bin Meng <bmeng.cn@gmail.com>
Reviewed-by: Xiang W <wxjstz@126.com>
2021-06-24 09:39:55 +05:30
Anup Patel
03d6bb51ba lib: utils/timer: Add FDT based ACLINT MTIMER driver
We add a new FDT based ACLINT MTIMER driver which works for
both CLINT device and standalone ACLINT MTIMER device.

Signed-off-by: Anup Patel <anup.patel@wdc.com>
Reviewed-by: Bin Meng <bmeng.cn@gmail.com>
Reviewed-by: Xiang W <wxjstz@126.com>
2021-06-24 09:39:53 +05:30
Anup Patel
56fc5f7618 lib: utils/ipi: Add FDT based ACLINT MSWI IPI driver
We add a new FDT based ACLINT MSWI IPI driver which works for both
CLINT device and standalone ACLINT MSWI device.

Signed-off-by: Anup Patel <anup.patel@wdc.com>
Reviewed-by: Bin Meng <bmeng.cn@gmail.com>
Reviewed-by: Xiang W <wxjstz@126.com>
2021-06-24 09:39:51 +05:30
Anup Patel
bd5d2089b8 lib: utils: Add FDT parsing API common for both ACLINT and CLINT
We add fdt_parse_aclint_node() which can parse both ACLINT and
CLINT DT nodes. This means fdt_parse_clint_node() is not required
anymore so we remove it as well.

Signed-off-by: Anup Patel <anup.patel@wdc.com>
Reviewed-by: Bin Meng <bmeng.cn@gmail.com>
Reviewed-by: Xiang W <wxjstz@126.com>
2021-06-24 09:39:48 +05:30
Anup Patel
5a049fe1d6 lib: utils/ipi: Add ACLINT MSWI library
We add common ACLINT MSWI library similar to the CLINT library
so that OpenSBI platforms can use it.

Signed-off-by: Anup Patel <anup.patel@wdc.com>
Reviewed-by: Bin Meng <bmeng.cn@gmail.com>
Reviewed-by: Xiang W <wxjstz@126.com>
2021-06-24 09:39:44 +05:30
Anup Patel
4519e29c51 lib: utils/timer: Add ACLINT MTIMER library
We add common ACLINT MTIMER library similar to the CLINT library
so that OpenSBI platforms can use it.

Signed-off-by: Anup Patel <anup.patel@wdc.com>
Reviewed-by: Bin Meng <bmeng.cn@gmail.com>
Reviewed-by: Xiang W <wxjstz@126.com>
2021-06-24 09:38:47 +05:30
Heinrich Schuchardt
11c345f14a lib: simplify sbi_fifo_inplace_update()
Don't assign an unused value to variable index.

Use operator '-=' where applicable.

Signed-off-by: Heinrich Schuchardt <xypron.glpk@gmx.de>
Reviewed-by: Atish Patra <atish.patra@wdc.com>
Reviewed-by: Xiang W <wxjstz@126.com>
2021-06-22 19:16:52 +05:30
Heinrich Schuchardt
99017946f3 lib: sign conflict in wake_coldboot_harts()
Compiling wake_coldboot_harts() with GCC 11 and -Wextra yields:

lib/sbi/sbi_init.c:208:27:
error: comparison of integer expressions of different signedness:
‘int’ and ‘u32’ {aka ‘unsigned int’} [-Werror=sign-compare]
  208 |         for (int i = 0; i <= sbi_scratch_last_hartid(); i++) {
      |                           ^~

Signed-off-by: Heinrich Schuchardt <xypron.glpk@gmx.de>
Reviewed-by: Atish Patra <atish.patra@wdc.com>
Reviewed-by: Xiang W <wxjstz@126.com>
2021-06-22 19:14:30 +05:30
Heinrich Schuchardt
cdcf907b19 lib: sign conflict in sbi_tlb_entry_process()
Compiling sbi_tlb_entry_process() with GCC 11 and -Wextra yields:

lib/sbi/sbi_tlb.c: In function ‘sbi_tlb_process_count’:
lib/sbi/sbi_tlb.c:206:31:
error: comparison of integer expressions of different signedness:
‘u32’ {aka ‘unsigned int’} and ‘int’ [-Werror=sign-compare]
  206 |                 if (deq_count > count)

Signed-off-by: Heinrich Schuchardt <xypron.glpk@gmx.de>
Reviewed-by: Atish Patra <atish.patra@wdc.com>
Reviewed-by: Xiang W <wxjstz@126.com>
2021-06-22 19:12:22 +05:30
Bin Meng
eb90e0a16c lib: utils/libfdt: Upgrade to v1.6.1 release
Sync with libfdt v1.6.1 release source codes.

Signed-off-by: Bin Meng <bmeng.cn@gmail.com>
Reviewed-by: Anup Patel <anup.patel@wdc.com>
2021-06-22 17:42:29 +05:30
Charles Papon
79f9b4220f lib: sbi: Fix GET_F64_REG inline assembly
Current, GET_F64_REG() macro does not generate correct inline
assembly for the RV32 systems. This patch provides separate
definitions of GET_F64_REG() macro for RV32 and RV64 systems.

Signed-off-by: Charles Papon <charles.papon.90@gmail.com>
Signed-off-by: Anup Patel <anup.patel@wdc.com>
2021-06-12 09:53:33 +05:30
Heinrich Schuchardt
360ab88569 lib: utils: missing initialization in thead_reset_init
If property csr-copy does not exist, fdt_getprop() will return NULL and cnt
will have a random value from the stack.

Call clone_csrs() only if cnt is initialized to a non-zero value.

Fixes: 49e422c5ad ("lib: utils: reset: Add T-HEAD sample platform reset driver")
Signed-off-by: Heinrich Schuchardt <xypron.glpk@gmx.de>
Reviewed-by: Anup Patel <anup.patel@wdc.com>
2021-06-11 19:20:16 +05:30
Heinrich Schuchardt
1da3d80b5b lib: sbi_scratch: zero out scratch memory on all harts
In sbi_scratch_init() we determine the last hart. The index of the last
hart cannot exceed SBI_HARTMASK_MAX_BITS - 1. We should not initialize
last_hartid_having_scratch to a higher number to avoid buffer overflows
when using this value before calling sbi_scratch_init().

When allocating scratch memory in sbi_scratch_alloc_offset() we zero out
the allocated memory for all harts except for the last one. We should not
skip the last hart.

Signed-off-by: Heinrich Schuchardt <xypron.glpk@gmx.de>
Reviewed-by: Anup Patel <anup.patel@wdc.com>
2021-06-11 13:59:48 +05:30
Bin Meng
434198e3be platform: andes/ae350: Drop plicsw_ipi_sync()
plicsw_ipi_sync() is a forward declaration but without the actual
implementation. Drop it.

Signed-off-by: Bin Meng <bmeng.cn@gmail.com>
Reviewed-by: Anup Patel <anup.patel@wdc.com>
2021-06-11 11:21:14 +05:30
Bin Meng
de446ccf18 platform: andes/ae350: Drop plicsw_get_pending()
This is not used anywhere. Drop it.

Signed-off-by: Bin Meng <bmeng.cn@gmail.com>
Reviewed-by: Anup Patel <anup.patel@wdc.com>
2021-06-11 11:20:18 +05:30
Bin Meng
b32fac4b65 docs/platform: andes-ae350: Fix missing spaces
Fix several places in the docmentation that are missing spaces.

Signed-off-by: Bin Meng <bmeng.cn@gmail.com>
Reviewed-by: Anup Patel <anup.patel@wdc.com>
2021-06-11 11:18:07 +05:30
Bin Meng
a03ea2e2b1 platform: andes/ae350: Cosmetic fixes in plicsw.c
- %s/CLINT/PLICSW
- replace '.' with a space
- add a space around * in plicsw_cold_ipi_init()

Signed-off-by: Bin Meng <bmeng.cn@gmail.com>
Reviewed-by: Anup Patel <anup.patel@wdc.com>
2021-06-11 11:16:46 +05:30
Heinrich Schuchardt
f30b18944e lib: sbi_scratch: remove owner from sbi_scratch_alloc_offset
The parameter owner of function sbi_scratch_alloc_offset() is never used.
The scratch memory is small. We should not use it for debug information in
future. Hence eliminate the parameter.

Signed-off-by: Heinrich Schuchardt <xypron.glpk@gmx.de>
Reviewed-by: Xiang W <wxjstz@126.com>
Reviewed-by: Anup Patel <anup.patel@wdc.com>
2021-06-02 17:07:26 +05:30
Heinrich Schuchardt
66c4fca532 lib: utils: consider ':' in stdout-path
The value of the /chosen/stdout-path devicetree property is used to
determine the UART used by openSBI. According to the devicetree
specification the value may contain a hyphen, e.g.

	chosen {
                stdout-path = "/serial@f00:115200";
        };

If the character ':' is present, it terminates the path of the device.

Signed-off-by: Heinrich Schuchardt <xypron.glpk@gmx.de>
Reviewed-by: Atish Patra <atish.patra@wdc.com>
2021-06-02 17:06:17 +05:30
Heinrich Schuchardt
d9ba6536d3 docs: debugging OpenSBI
Describe how to debug OpenSBI on QEMU with GDB.

Signed-off-by: Heinrich Schuchardt <xypron.glpk@gmx.de>
Reviewed-by: Atish Patra <atish.patra@wdc.com>
2021-06-02 17:04:07 +05:30
Anup Patel
54d7def6c2 lib: utils: Try other FDT drivers when we see SBI_ENODEV
We should try other FDT drivers when we see SBI_ENODEV returned
by cold_init() of FDT driver.

Signed-off-by: Anup Patel <anup.patel@wdc.com>
Reviewed-by: Atish Patra <atish.patra@wdc.com>
Reviewed-by: Xiang W <wxjstz@126.com>
2021-05-24 15:49:21 +05:30
Anup Patel
b2dbbc0577 lib: Check region base for merging in sbi_domain_root_add_memregion()
We can merge region B onto region A only if base of region A is
aligned to region A order + 1.

Signed-off-by: Anup Patel <anup.patel@wdc.com>
Reviewed-by: Atish Patra <atish.patra@wdc.com>
Reviewed-by: Xiang W <wxjstz@126.com>
2021-05-24 15:47:41 +05:30
Daniel Schaefer
fe92347b9f lib: utils/fdt: Replace strcmp with strncmp
Use strncmp() instead of strcmp() in __fixup_find_domain_offset()
so that it compiles fine when linking with external firmware (such
as EDK2).

Signed-off-by: Daniel Schaefer <daniel.schaefer@hpe.com>
Reviewed-by: Xiang W <wxjstz@126.com>
Reviewed-by: Abner Chang <abner.chang@hpe.com>
Reviewed-by: Anup Patel <anup.patel@wdc.com>
2021-05-19 17:35:38 +05:30
Daniel Schaefer
ee7c2b27ea lib: utils/fdt: Don't use sbi_string functions
When SBI is built by external firmware, we need to use their functions,
defined in libfdt_env.h.

Just like 2cfd2fc904

Signed-off-by: Daniel Schaefer <daniel.schaefer@hpe.com>
Reviewed-by: Abner Chang <abner.chang@hpe.com>
Reviewed-by: Xiang W <wxjstz@126.com>
Reviewed-by: Anup Patel <anup.patel@wdc.com>
2021-05-19 17:34:06 +05:30
Daniel Schaefer
c9ef2bc7e4 lib: utils: Add strncpy macro to libfdt_env.h
we want to use sbi_strncpy as strncpy in the OpenSBI implementation for
libfdt.

Just like 2845d2d2cf

Signed-off-by: Daniel Schaefer <daniel.schaefer@hpe.com>
Reviewed-by: Abner Chang <abner.chang@hpe.com>
Reviewed-by: Xiang W <wxjstz@126.com>
Reviewed-by: Anup Patel <anup.patel@wdc.com>
2021-05-19 17:33:33 +05:30
Fabrice Fontaine
6139ab272b Makefile: unconditionally disable SSP
Though -nostdlib is passed in CFLAGS, -fno-stack-protector must also be
passed to avoid linking errors related to undefined references to
'__stack_chk_guard' and '__stack_chk_fail' if toolchain enforces
-fstack-protector.

Fixes:
 - https://gitlab.com/kubu93/buildroot/-/jobs/1247043359

Signed-off-by: Fabrice Fontaine <fontaine.fabrice@gmail.com>
Reviewed-by: Bin Meng <bmeng.cn@gmail.com>
Reviewed-by: Xiang W <wxjstz@126.com>
2021-05-19 16:37:50 +05:30
Bin Meng
e822b7504d lib: utils/serial: Support Synopsys DesignWare APB UART
Synopsys DesignWare APB UART is seen on the StarFive JH7100 SoC.
Its programming interface is compatible with the existing 8250
UART driver. Simply add its compatible string to the driver makes
it work with the StarFive JH7100 SoC on a BeagleV board.

With this patch, the generic platform firmware can be used out of
the box on the BeagleV board.

Signed-off-by: Bin Meng <bmeng.cn@gmail.com>
Reviewed-by: Anup Patel <anup.patel@wdc.com>
2021-05-19 13:03:19 +05:30
Daniel Schaefer
f90c4c2e02 lib: sbi: Have spinlock checks return bool
spin_lock_check already returned bool in the source file but not in the
header. With some toolchains that causes an error, as it should.

Because it and related functions all essentially return a bool, we can
use this opportunity to change them.

Signed-off-by: Daniel Schaefer <git@danielschaefer.me>
Reviewed-by: Anup Patel <anup.patel@wdc.com>
2021-05-14 17:05:20 +05:30
Bin Meng
26998f3d11 platform: Remove sifive/fu540 platform
Now that SiFive HiFive Unleashed board is using the generic platform
support in OpenSBI, let's remove the old non-generic one.

Signed-off-by: Bin Meng <bmeng.cn@gmail.com>
Reviewed-by: Anup Patel <anup.patel@wdc.com>
2021-05-06 14:24:45 +05:30
Bin Meng
d4177e7217 docs: platform: Describe sifive_fu540 as supported generic platform
The upstream U-Boot/QEMU have been using generic platform for SiFive
HiFive Unleashed board for some time. Let's document sifive_fu540 as
one of the supported targets for "generic" platform.

Signed-off-by: Bin Meng <bmeng.cn@gmail.com>
Reviewed-by: Anup Patel <anup.patel@wdc.com>
2021-05-06 14:23:38 +05:30
Bin Meng
552f53f360 docs: platform: Sort platform names
Let's sort the platform names in alphabetical order.

Signed-off-by: Bin Meng <bmeng.cn@gmail.com>
Reviewed-by: Anup Patel <anup.patel@wdc.com>
2021-05-06 14:22:34 +05:30
Daniel Cederman
117fb6dcb1 lib: utils/serial: Add support for Gaisler APBUART
This patch adds support for the UART used by the NOEL-V processor.

Cobham Gaisler's NOEL-V RISC-V processor IP is available under GPL
and commercial license and is described in more detail at
https://www.gaisler.com/noelv.

Signed-off-by: Daniel Cederman <cederman@gaisler.com>
Reviewed-by: Anup Patel <anup.patel@wdc.com>
Reviewed-by: Bin Meng <bmeng.cn@gmail.com>
2021-05-06 14:21:07 +05:30
Bin Meng
632e27bb91 docs/platform: sifive_fu540: Update U-Boot defconfig name
With latest U-Boot upstream (v2021.07 in development), the defconfig
name has been changed to sifive_unleashed_defconfig. Update the doc.

Signed-off-by: Bin Meng <bmeng.cn@gmail.com>
Reviewed-by: Anup Patel <anup.patel@wdc.com>
2021-04-29 15:11:24 +05:30
Anup Patel
e9a27ab8ea lib: sbi: Show devices provided by platform in boot prints
We extend the boot-time prints to show various devices provided
(or registered) by the platform support. This will help users
verify hardware devices available for OpenSBI firmwares.

Signed-off-by: Anup Patel <anup.patel@wdc.com>
Reviewed-by: Alistair Francis <alistair.francis@wdc.com>
2021-04-28 17:33:37 +05:30
Anup Patel
a84a1ddbba lib: sbi: Simplify HSM platform operations
Instead of having hsm_start(), hsm_stop() and hsm_suspend()
callbacks in platform operations, it will be much simpler for
HSM driver to directly register these operations as a device
to the sbi_hsm implementation.

Signed-off-by: Anup Patel <anup.patel@wdc.com>
Reviewed-by: Alistair Francis <alistair.francis@wdc.com>
2021-04-28 17:31:07 +05:30
Anup Patel
043d088e39 lib: sbi: Simplify system reset platform operations
Instead of having system_reset_check() and system_reset() callbacks
in platform operations, it will be much simpler for reset driver to
directly register these operations as a device to the sbi_system
implementation.

Signed-off-by: Anup Patel <anup.patel@wdc.com>
Reviewed-by: Alistair Francis <alistair.francis@wdc.com>
2021-04-28 17:25:00 +05:30
Anup Patel
dc39c7b630 lib: sbi: Simplify ipi platform operations
Instead of having ipi_send() and ipi_clear() callbacks in
platform operations, it will be much simpler for ipi driver
to directly register these operations as a device to sbi_ipi
implementation.

Signed-off-by: Anup Patel <anup.patel@wdc.com>
Reviewed-by: Alistair Francis <alistair.francis@wdc.com>
2021-04-28 17:03:31 +05:30
Anup Patel
559a8f1d3b lib: sbi: Simplify timer platform operations
Instead of having timer_value(), timer_event_start(), and
timer_event_stop() callbacks in platform operations, it will
be much simpler for timer driver to directly register these
operations as device to the sbi_timer implementation.

Signed-off-by: Anup Patel <anup.patel@wdc.com>
Reviewed-by: Alistair Francis <alistair.francis@wdc.com>
2021-04-28 17:00:49 +05:30
Anup Patel
068ca086af lib: sbi: Simplify console platform operations
Instead of having console_putc() and console_getc() callbacks in
platform operations, it will be much simpler for console driver to
directly register these operations as device to the sbi_console
implementation.

Signed-off-by: Anup Patel <anup.patel@wdc.com>
Reviewed-by: Alistair Francis <alistair.francis@wdc.com>
Reviewed-by: Xiang W <wxjstz@126.com>
2021-04-28 16:58:23 +05:30
Anup Patel
a3689db92a lib: sbi: Remove domains_root_regions() platform callback
We now have sbi_domain_root_add_memregion() which allows platform
support to add root domain regions at boot-time so let's remove
the domains_root_regions() platform callback which was added
for this purpose.

Signed-off-by: Anup Patel <anup.patel@wdc.com>
Reviewed-by: Alistair Francis <alistair.francis@wdc.com>
Reviewed-by: Xiang W <wxjstz@126.com>
2021-04-28 16:56:58 +05:30
Guo Ren
6d1642f856 docs: generic: Add T-HEAD C9xx series processors
Add description and dts examples for T-HEAD C9xx platforms.

Signed-off-by: Guo Ren <guoren@linux.alibaba.com>
Reviewed-by: Anup Patel <anup.patel@wdc.com>
2021-04-28 16:12:02 +05:30
Guo Ren
1db843622a platform: Remove platform/thead
We could use platform/generic instead, and won't use
platform/thead/c910 again.

Signed-off-by: Guo Ren <guoren@linux.alibaba.com>
Reviewed-by: Anup Patel <anup.patel@wdc.com>
2021-04-28 15:43:04 +05:30
Guo Ren
bf3ef53bb7 firmware: Enable FW_PIC by default
Let's have FW_PIC enabled by default so that OpenSBI firmware
can by default run from any physical address.

Tested with qemu_rv32 & rv64, T-HEAD all hardwares.

Suggested-by: Anup Patel <anup.patel@wdc.com>
Signed-off-by: Guo Ren <guoren@linux.alibaba.com>
Tested-by: Guo Ren <guoren@linux.alibaba.com>
Reviewed-by: Anup Patel <anup.patel@wdc.com>
2021-04-28 15:38:22 +05:30
Anup Patel
0d56293817 lib: sbi: Fix sbi_domain_root_add_memregion() for merging memregions
We should decrement root_memregs_count by one after merging two
memregions otherwise new memregion added after a merge will be
appended after last sentinel memregion of zero order.

Signed-off-by: Anup Patel <anup.patel@wdc.com>
Reviewed-by: Xiang W <wxjstz@126.com>
2021-04-24 13:05:09 +05:30
Guo Ren
49e422c5ad lib: utils: reset: Add T-HEAD sample platform reset driver
This driver is for T-HEAD test chip, fpga. It could work with
all T-HEAD riscv processors: C9xx series.

example1: (Using io-regs for reset)
reset: reset-sample {
	compatible = "thead,reset-sample";
	plic-delegate = <0xff 0xd81ffffc>;
	entry-reg = <0xff 0xff019050>;
	entry-cnt = <4>;
	control-reg = <0xff 0xff015004>;
	control-val = <0x1c>;
	csr-copy = <0x7f3 0x7c0 0x7c1 0x7c2 0x7c3 0x7c5 0x7cc>;
};

example2: (Using csr-regs for reset)
reset: reset-sample {
	compatible = "thead,reset-sample";
	plic-delegate = <0xff 0xd81ffffc>;
	using-csr-reset;
	csr-copy = <0x7c0 0x7c1 0x7c2 0x7c3 0x7c5 0x7cc
		    0x3b0 0x3b1 0x3b2 0x3b3
		    0x3b4 0x3b5 0x3b6 0x3b7
		    0x3a0>;
};

example3: (Only delegate plic enable to S-mode)
reset: reset-sample {
	compatible = "thead,reset-sample";
	plic-delegate = <0xff 0xd81ffffc>;
};

After this patch, all T-HEAD c9xx would use platform/generic with fw_dynamic
as default:

CROSS_COMPILE=riscv64-linux-gnu- PLATFORM=generic FW_PIC=y /usr/bin/make

The platform/thead will be deprecated.

Signed-off-by: Guo Ren <guoren@linux.alibaba.com>
Reviewed-by: Anup Patel <anup.patel@wdc.com>
2021-04-22 15:13:53 +05:30
Guo Ren
c5d0645052 lib: utils: Implement "64bit-mmio" property parsing
Figure out CLINT has_64bit_mmio from DT node and using antonym for
compatibility.

Signed-off-by: Guo Ren <guoren@linux.alibaba.com>
Reviewed-by: Anup Patel <anup.patel@wdc.com>
2021-04-22 15:00:58 +05:30
Anup Patel
f41196a9d2 lib: sbi: Make sbi_domain_memregion_initfw() a local function
The sbi_domain_memregion_initfw() is no longer used outside
sbi_domain.c so let's make it a local function.

Signed-off-by: Anup Patel <anup.patel@wdc.com>
Reviewed-by: Xiang W <wxjstz@126.com>
Reviewed-by: Alistair Francis <alistair.francis@wdc.com>
2021-04-13 10:56:51 +05:30
Anup Patel
e7e4bcd5b9 lib: utils: Copy over restricted root domain memregions to FDT domains
We should copy over all restricted memregions from the root domain
to the domains populated from FDT. These restricted root memregions
are typically firmware memregion and M-mode only mmio memregions.

Signed-off-by: Anup Patel <anup.patel@wdc.com>
Reviewed-by: Xiang W <wxjstz@126.com>
Reviewed-by: Alistair Francis <alistair.francis@wdc.com>
2021-04-13 10:56:48 +05:30
Anup Patel
fc37c9712d lib: sbi: Make the root domain instance global variable
We make the the root domain instance global variable so that
platform support and drivers can iterate over the root domain
regions.

Signed-off-by: Anup Patel <anup.patel@wdc.com>
Reviewed-by: Xiang W <wxjstz@126.com>
Reviewed-by: Alistair Francis <alistair.francis@wdc.com>
2021-04-13 10:56:45 +05:30
Anup Patel
8b56980347 lib: utils/sys: Add CLINT memregion in the root domain
The CLINT memory should not be accessed by the supervisor-mode
software so let's protect it by adding CLINT memregion to the
root domain.

Signed-off-by: Anup Patel <anup.patel@wdc.com>
Reviewed-by: Xiang W <wxjstz@126.com>
Reviewed-by: Alistair Francis <alistair.francis@wdc.com>
2021-04-13 10:56:42 +05:30
Anup Patel
4dc0001b09 lib: sbi: Add sbi_domain_root_add_memregion() API
We should allow platform support to add more root memory regions
before domains are finalized. This will help platform support to
protect critical M-mode only resources.

This patch adds sbi_domain_root_add_memregion() API for above
described purpose.

Signed-off-by: Anup Patel <anup.patel@wdc.com>
Reviewed-by: Xiang W <wxjstz@126.com>
Reviewed-by: Alistair Francis <alistair.francis@wdc.com>
2021-04-13 10:56:37 +05:30
Anup Patel
7495bce6f9 lib: sbi: Add sbi_domain_memregion_init() API
This patch adds sbi_domain_memregion_init() helper API which can
be used by platform support to initialize a domain memory region
before adding it to the root domain.

Signed-off-by: Anup Patel <anup.patel@wdc.com>
Reviewed-by: Xiang W <wxjstz@126.com>
Reviewed-by: Alistair Francis <alistair.francis@wdc.com>
2021-04-13 10:56:35 +05:30
Anup Patel
b1df1acd20 lib: sbi: Domains can be registered only before finalizing domains
The domains are boot-time system-level partitions so we should
allow platform support to register domains only before hart
domain assignments are finalized.

Signed-off-by: Anup Patel <anup.patel@wdc.com>
Reviewed-by: Xiang W <wxjstz@126.com>
Reviewed-by: Alistair Francis <alistair.francis@wdc.com>
2021-04-13 10:56:32 +05:30
hasheddan
27a16b1545 docs: fix link to OpenPiton documentation
Updates link in platforms documentation to point to the correct
OpenPiton document.

Signed-off-by: hasheddan <georgedanielmangum@gmail.com>
Reviewed-by: Anup Patel <anup.patel@wdc.com>
2021-04-12 13:36:08 +05:30
Xiang W
70ffc3e2e6 lib: sbi: fix atomic_add_return
The unsigned length may be 4 bytes or 8 bytes, amoadd.w only applies
to 4 bytes hence this patch.

Signed-off-by: Xiang W <wxjstz@126.com>
Reviewed-by: Anup Patel <anup.patel@wdc.com>
2021-04-09 18:51:02 +05:30
Christoph Muellner
4d8e2f135d lib: sbi: Replace test-and-set locks by ticket locks
Replace the test-and-set spinlock implementation with ticket locks
in order to get fairness (in form of FIFO order).

The implementation uses a 32-bit wide struct, which consists of
two 16-bit counters (owner and next). This is inspired by similar
spinlock implementations on other architectures.
This allows that the code works for both, RV32 and RV64.

Signed-off-by: Christoph Muellner <cmuellner@linux.com>
Reviewed-by: Anup Patel <anup.patel@wdc.com>
Reviewed-by: Xiang W <wxjstz@126.com>
2021-04-09 18:48:50 +05:30
Christoph Muellner
d0e406fa44 include: sbi: Allow direct initialization via SPIN_LOCK_INIT()
The current implementation of SPIN_LOCK_INIT() provides the spinlock
to be initialized as reference. This does not allow a direct
initialization of the spinlock object at the creation site.

Let's pass the spinlock directly instead (like Linux does as well)
and adjust all users of the macro (in fact there is only one user).

Signed-off-by: Christoph Muellner <cmuellner@linux.com>
Reviewed-by: Anup Patel <anup.patel@wdc.com>
2021-04-09 18:39:50 +05:30
Christoph Muellner
d4a94ea471 include: types: Add __aligned(x) to define the minimum alignement
The __aligned(x) macro is a common wrapper around compiler's
aligned attribute, which allow to define the minimum alignement
of a data type. Let's add this macro.

Signed-off-by: Christoph Muellner <cmuellner@linux.com>
Reviewed-by: Anup Patel <anup.patel@wdc.com>
2021-04-09 18:37:06 +05:30
Anup Patel
e71a7c10a9 firmware: Remove redundant add instruction from trap restore path
The "add sp, a0, zero" instruction in the trap restore path is redundant
and can be avoided if TRAP_RESTORE_xyz() assembly macros use a0 as the
base register instead of sp.

Signed-off-by: Anup Patel <anup.patel@wdc.com>
Reviewed-by: Xiang W <wxjstz@126.com>
2021-04-05 15:39:28 +05:30
Xiang W
3d8a952737 lib: fix csr detect support
csr_read_allowed/csr_read_allowed requires trap.case to detect the results,
but if no exception occurs, the value of trap.case will remain unchanged,
which makes the detection results unreliable. Add code to initialize
trap.case to 0.

Signed-off-by: Xiang W <wxjstz@126.com>
Reviewed-by: Anup Patel <anup.patel@wdc.com>
2021-04-05 13:43:08 +05:30
Xiang W
4ef2f5d3e6 firware: optimize the exception exit code
There are two copies of the same abnormal exit code, this patch deletes one

Signed-off-by: Xiang W <wxjstz@126.com>
Reviewed-by: Anup Patel <anup.patel@wdc.com>
2021-04-01 10:48:35 +05:30
Bin Meng
4edc822407 lib/utils: Support fixing up the official DT bindings of PLIC
Current fdt_plic_fixup() only does necessary fix-up against the legacy
"riscv,plic0" node. The upstream Linux kernel defines its official DT
bindings which uses "sifive,plic-1.0.0" as the compatible string and
we should check that first, and if not present fall back to legacy.

Signed-off-by: Bin Meng <bmeng.cn@gmail.com>
Reviewed-by: Anup Patel <anup.patel@wdc.com>
2021-04-01 10:31:11 +05:30
Bin Meng
ca3f35821b lib/utils: Drop the 'compat' parameter of fdt_plic_fixup()
At present fdt_plic_fixup() accepts a 'compat' parameter for PLIC
compatible string. In preparation to support the new DT bindings,
drop this and use "riscv,plic0" directly in fdt_plic_fixup().

Signed-off-by: Bin Meng <bmeng.cn@gmail.com>
Reviewed-by: Anup Patel <anup.patel@wdc.com>
2021-04-01 10:27:28 +05:30
Bin Meng
9190ad12f7 lib/utils: Support the official clint DT bindings
Linux kernel commit a2770b57d083 ("dt-bindings: timer: Add CLINT bindings")
adds the official DT bindings for CLINT, which uses "sifive,clint0"
as the compatible string. "riscv,clint0" is now legacy and has to
be kept for backward compatibility of legacy systems.

Signed-off-by: Bin Meng <bmeng.cn@gmail.com>
Reviewed-by: Anup Patel <anup.patel@wdc.com>
2021-04-01 10:26:41 +05:30
Marouene Boubakri
bfc85c70e7 include: headers: Replace __ASSEMBLY__ with __ASSEMBLER__
GCC has already a predefined macro __ASSEMBLER__ therefore, it can be
used without the need to define a new flag with -D__ASSEMBLY__.
This is useful when adding the library to projects having a build
system such one can build without the need to make changes.
THe build system does not use the Makefile in the sources tree.

Signed-off-by: Marouene Boubakri <marouene.boubakri@nxp.com>
Signed-off-by: Anup Patel <anup.patel@wdc.com>
2021-03-22 16:02:48 +05:30
Heinrich Schuchardt
ddad02d625 lib: sbi: illegal CSR 0x306 access in hpm_allowed()
The trap handler sbi_emulate_csr_read() invokes hpm_allowed() which reads
CSR 0x306 (mcounteren). The K210 does not support CSR 0x306. While trying
to handle a trap occurring in S-mode code this creates an additional trap
in M-mode. This results in failure to redirect to S-mode and the system
hanging in sbi_hart_hang().

In hart_detect_features() we have already determined if CSR 0x306 is
available and stored that information in the scratch area. We can use this
information to decide if CSR 0x306 shall be accessed in hpm_allowed() and
thus avoid the M-mode trap.

Likewise if CSR scounteren is not available we have to avoid reading CSR
0x106.

Signed-off-by: Heinrich Schuchardt <xypron.glpk@gmx.de>
Reviewed-by: Anup Patel <anup.patel@wdc.com>
2021-03-22 09:18:56 +05:30
Vincent Chen
0f20e8adcf firmware: Support position independent execution
Enable OpenSBI to support position independent execution. Because the
position independent code will cause an additional GOT reference when
accessing the global variables, it will reduce performance a bit. Therefore,
the position independent execution is disabled by default. Users can
through specifying "FW_PIC=y" on the make command to enable this feature.

In theory, after enabling position-independent execution, the OpenSBI
can run at arbitrary address with appropriate alignment. Therefore, the
original relocation mechanism will be skipped. In other words, OpenSBI will
directly run at the load address without any code movement.

Signed-off-by: Vincent Chen <vincent.chen@sifive.com>
Reviewed-by: Anup Patel <anup.patel@wdc.com>
2021-03-19 15:00:50 +05:30
Vincent Chen
22d8ee9758 firmware: Use lla to access all global symbols
When OpenSBI is compiled as fPIE mode, the assembler will translate "la"
to GOT reference pattern. It will cause to cost an additional load
instruction when obtaining the symbol address. However, if the symbol
locates within the positive or negative 2GB region, we can use "lla"
instead of "la" to avoid unneeded GOT references. This patch assumes that
the OpenSBI image excluding the payload does not exceed 2GB. Based on
this assumption, all "la" instructions are replaced by "lla" to avoid
performance degradation when compiling as fPIE mode.

Signed-off-by: Vincent Chen <vincent.chen@sifive.com>
Reviewed-by: Anup Patel <anup.patel@wdc.com>
2021-03-19 14:57:45 +05:30
Heinrich Schuchardt
ff5bd949d5 include: sbi: SBI function IDs for RFENCE extension
The SBI function IDs for RFENCE extension must match the SBI specification.

Signed-off-by: Heinrich Schuchardt <xypron.glpk@gmx.de>
Reviewed-by: Atish Patra <atish.patra@wdc.com>
2021-03-12 09:32:53 +05:30
Anup Patel
50d4fde1c5 lib: Remove redundant sbi_platform_ipi_clear() calls
The sbi_platform_ipi_clear() called from wait_for_coldboot() and
sbi_hsm_hart_wait() is redundant because IPI will be automatically
cleared by sbi_platform_ipi_init() called from sbi_ipi_init().

Further, wait_for_coldboot() is common for warm startup and warm
resume path so the sbi_platform_ipi_clear() called in warm resume
path cause resuming HART to miss an IPI injected other HART to
wakeup the HART.

Signed-off-by: Anup Patel <anup.patel@wdc.com>
Reviewed-by: Atish Patra <atish.patra@wdc.com>
2021-03-03 13:54:50 +05:30
Anup Patel
b9cf617a9f include: sbi: Upgrade SBI implementation version to v0.3
The OpenSBI SBI implementation is now compliant with latest draft
SBI v0.3 specification so let's upgrade SBI implementation version.

This will also help HSM suspend function detection in S-mode because
HSM suspend function is only present when HSM extension is present
and SBI implementation version is 0.3 (or higher).

Signed-off-by: Anup Patel <anup.patel@wdc.com>
Reviewed-by: Atish Patra <atish.patra@wdc.com>
2021-03-03 13:54:44 +05:30
Anup Patel
74756891cc lib: sbi: Implement SBI HSM suspend function
This patch implements the SBI HSM suspend function. Using this
new SBI call, the S-mode software can put calling HART in platform
specific suspend (i.e. low-power) state. For a successful retentive
suspend, the SBI call will return without errors upon resuming
whereas for a successful non-retentive suspend, the SBI call will
resume from a user provided resume address.

Signed-off-by: Anup Patel <anup.patel@wdc.com>
Reviewed-by: Atish Patra <atish.patra@wdc.com>
2021-03-03 13:51:15 +05:30
Anup Patel
807d71c4ff include: sbi: Add hart_suspend() platform callback
We add hart_suspend() callback in platform operations which will
be used by HSM implementation to enter retentive or non-retentive
suspend state.

Signed-off-by: Anup Patel <anup.patel@wdc.com>
Reviewed-by: Atish Patra <atish.patra@wdc.com>
2021-03-03 10:19:24 +05:30
Anup Patel
4b05df6700 lib: sbi: Add sbi_hart_reinit() function
We add sbi_hart_reinit() function which will re-initialize HART CSRs
assuming HART features are already detected. This new function will
be useful in re-initializing HART after it resumes from HSM SUSPENDED
state.

Signed-off-by: Anup Patel <anup.patel@wdc.com>
Reviewed-by: Atish Patra <atish.patra@wdc.com>
2021-03-03 10:19:18 +05:30
Anup Patel
6290a22e34 include: sbi: Add HSM suspend related defines
This patch adds SBI HSM suspend related defines to ecall interface
header.

Signed-off-by: Anup Patel <anup.patel@wdc.com>
Reviewed-by: Atish Patra <atish.patra@wdc.com>
2021-03-03 10:19:13 +05:30
Anup Patel
ca864a978d lib: sbi: Fix error codes returned by HSM start() and stop() functions
The sbi_hsm_hart_start() and sbi_hsm_hart_stop() functions should
only return error codes as defined by the SBI specification.

Signed-off-by: Anup Patel <anup.patel@wdc.com>
Reviewed-by: Atish Patra <atish.patra@wdc.com>
2021-03-03 10:19:01 +05:30
Anup Patel
638c948ab9 lib: sbi: Remove redundant sbi_hsm_hart_started() function
The sbi_hsm_hart_started() function is only used by sbi_hsm_hart_stop()
for checking state of calling HART and current domain assignment.

The atomic_cmpxchg() called by sbi_hsm_hart_stop() will check state of
calling hart anyway and domain assignment can be checked by other domain
function such as sbi_domain_is_assigned_hart().

This means sbi_hsm_hart_started() is redundant and can be removed.

Signed-off-by: Anup Patel <anup.patel@wdc.com>
Reviewed-by: Atish Patra <atish.patra@wdc.com>
2021-03-03 10:18:23 +05:30
Anup Patel
7c867fd19f lib: sbi: Rename sbi_hsm_hart_started_mask() function
A hart can take interrupt in the new HSM states introduced by the
SBI HSM suspend function (such as SUSPENDED state) so we rename
sbi_hsm_hart_started_mask() to something more generic such as
sbi_hsm_hart_interruptible_mask().

Signed-off-by: Anup Patel <anup.patel@wdc.com>
Reviewed-by: Atish Patra <atish.patra@wdc.com>
2021-03-03 10:17:45 +05:30
Anup Patel
8df1f9a0d3 lib: sbi: Use SBI_HSM_STATE_xyz defines instead of SBI_STATE_xyz defines
We replace the use of SBI_STATE_xyz defines with SBI_HSM_STATE_xyz
defines because the HSM state defines are complete enough to implement
HSM state machine in OpenSBI. As a result of this, we can now remove
sbi_hsm_hart_state_to_status() function because it is now redundant
and sbi_hsm_hart_get_state() can directly return HSM state or error.

Signed-off-by: Anup Patel <anup.patel@wdc.com>
Reviewed-by: Atish Patra <atish.patra@wdc.com>
2021-03-03 10:17:41 +05:30
Anup Patel
5487cf095d include: sbi: Simplify HSM state define names
We simplify HSM state define names so that these defines can directly
replace SBI_HART_xyz defines used by SBI HSM implementation.

Signed-off-by: Anup Patel <anup.patel@wdc.com>
Reviewed-by: Atish Patra <atish.patra@wdc.com>
2021-03-03 10:17:35 +05:30
Heinrich Schuchardt
ec5274b04c platform: implement K210 system reset
Implement rebooting the K210 via the system reset extension.

All reset types are treated in the same way.
A request for shutdown results in a reboot.

Signed-off-by: Heinrich Schuchardt <xypron.glpk@gmx.de>
Reviewed-by: Damien Le Moal <damien.lemoal@wdc.com>
Reviewed-by: Anup Patel <anup.patel@wdc.com>
2021-03-03 08:39:10 +05:30
226 changed files with 10887 additions and 2616 deletions

150
Makefile
View File

@@ -76,26 +76,54 @@ OPENSBI_VERSION_MINOR=`grep "define OPENSBI_VERSION_MINOR" $(include_dir)/sbi/sb
OPENSBI_VERSION_GIT=$(shell if [ -d $(src_dir)/.git ]; then git describe 2> /dev/null; fi)
# Setup compilation commands
ifneq ($(LLVM),)
CC = clang
AR = llvm-ar
LD = ld.lld
OBJCOPY = llvm-objcopy
else
ifdef CROSS_COMPILE
CC = $(CROSS_COMPILE)gcc
CPP = $(CROSS_COMPILE)cpp
AR = $(CROSS_COMPILE)ar
LD = $(CROSS_COMPILE)ld
OBJCOPY = $(CROSS_COMPILE)objcopy
else
CC ?= gcc
CPP ?= cpp
AR ?= ar
LD ?= ld
OBJCOPY ?= objcopy
endif
endif
CPP = $(CC) -E
AS = $(CC)
DTC = dtc
# Guess the compillers xlen
OPENSBI_CC_XLEN := $(shell TMP=`$(CC) -dumpmachine | sed 's/riscv\([0-9][0-9]\).*/\1/'`; echo $${TMP})
ifneq ($(shell $(CC) --version 2>&1 | head -n 1 | grep clang),)
CC_IS_CLANG = y
else
CC_IS_CLANG = n
endif
ifneq ($(shell $(LD) --version 2>&1 | head -n 1 | grep LLD),)
LD_IS_LLD = y
else
LD_IS_LLD = n
endif
ifeq ($(CC_IS_CLANG),y)
ifneq ($(CROSS_COMPILE),)
CLANG_TARGET = --target=$(notdir $(CROSS_COMPILE:%-=%))
endif
endif
# Guess the compiler's XLEN
OPENSBI_CC_XLEN := $(shell TMP=`$(CC) $(CLANG_TARGET) -dumpmachine | sed 's/riscv\([0-9][0-9]\).*/\1/'`; echo $${TMP})
# Guess the compiler's ABI and ISA
ifneq ($(CC_IS_CLANG),y)
OPENSBI_CC_ABI := $(shell TMP=`$(CC) -v 2>&1 | sed -n 's/.*\(with\-abi=\([a-zA-Z0-9]*\)\).*/\2/p'`; echo $${TMP})
OPENSBI_CC_ISA := $(shell TMP=`$(CC) -v 2>&1 | sed -n 's/.*\(with\-arch=\([a-zA-Z0-9]*\)\).*/\2/p'`; echo $${TMP})
endif
# Setup platform XLEN
ifndef PLATFORM_RISCV_XLEN
@@ -106,6 +134,47 @@ ifndef PLATFORM_RISCV_XLEN
endif
endif
ifeq ($(CC_IS_CLANG),y)
ifeq ($(CROSS_COMPILE),)
CLANG_TARGET = --target=riscv$(PLATFORM_RISCV_XLEN)-unknown-elf
endif
endif
ifeq ($(LD_IS_LLD),y)
RELAX_FLAG = -mno-relax
USE_LD_FLAG = -fuse-ld=lld
else
USE_LD_FLAG = -fuse-ld=bfd
endif
# Check whether the linker supports creating PIEs
OPENSBI_LD_PIE := $(shell $(CC) $(CLANG_TARGET) $(RELAX_FLAG) $(USE_LD_FLAG) -fPIE -nostdlib -Wl,-pie -x c /dev/null -o /dev/null >/dev/null 2>&1 && echo y || echo n)
# Check whether the compiler supports -m(no-)save-restore
CC_SUPPORT_SAVE_RESTORE := $(shell $(CC) $(CLANG_TARGET) $(RELAX_FLAG) -nostdlib -mno-save-restore -x c /dev/null -o /dev/null 2>&1 | grep "\-save\-restore" >/dev/null && echo n || echo y)
# Check whether the assembler and the compiler support the Zicsr and Zifencei extensions
CC_SUPPORT_ZICSR_ZIFENCEI := $(shell $(CC) $(CLANG_TARGET) $(RELAX_FLAG) -nostdlib -march=rv$(OPENSBI_CC_XLEN)imafd_zicsr_zifencei -x c /dev/null -o /dev/null 2>&1 | grep "zicsr\|zifencei" > /dev/null && echo n || echo y)
# Build Info:
# OPENSBI_BUILD_TIME_STAMP -- the compilation time stamp
# OPENSBI_BUILD_COMPILER_VERSION -- the compiler version info
BUILD_INFO ?= n
ifeq ($(BUILD_INFO),y)
OPENSBI_BUILD_DATE_FMT = +%Y-%m-%d %H:%M:%S %z
ifdef SOURCE_DATE_EPOCH
OPENSBI_BUILD_TIME_STAMP ?= $(shell date -u -d "@$(SOURCE_DATE_EPOCH)" \
"$(OPENSBI_BUILD_DATE_FMT)" 2>/dev/null || \
date -u -r "$(SOURCE_DATE_EPOCH)" \
"$(OPENSBI_BUILD_DATE_FMT)" 2>/dev/null || \
date -u "$(OPENSBI_BUILD_DATE_FMT)")
else
OPENSBI_BUILD_TIME_STAMP ?= $(shell date "$(OPENSBI_BUILD_DATE_FMT)")
endif
OPENSBI_BUILD_COMPILER_VERSION=$(shell $(CC) -v 2>&1 | grep ' version ' | \
sed 's/[[:space:]]*$$//')
endif
# Setup list of objects.mk files
ifdef PLATFORM
platform-object-mks=$(shell if [ -d $(platform_src_dir)/ ]; then find $(platform_src_dir) -iname "objects.mk" | sort -r; fi)
@@ -157,7 +226,11 @@ ifndef PLATFORM_RISCV_ABI
endif
ifndef PLATFORM_RISCV_ISA
ifneq ($(PLATFORM_RISCV_TOOLCHAIN_DEFAULT), 1)
ifeq ($(CC_SUPPORT_ZICSR_ZIFENCEI), y)
PLATFORM_RISCV_ISA = rv$(PLATFORM_RISCV_XLEN)imafdc_zicsr_zifencei
else
PLATFORM_RISCV_ISA = rv$(PLATFORM_RISCV_XLEN)imafdc
endif
else
PLATFORM_RISCV_ISA = $(OPENSBI_CC_ISA)
endif
@@ -194,46 +267,72 @@ else
endif
# Setup compilation commands flags
GENFLAGS = -I$(platform_src_dir)/include
ifeq ($(CC_IS_CLANG),y)
GENFLAGS += $(CLANG_TARGET)
GENFLAGS += -Wno-unused-command-line-argument
endif
GENFLAGS += -I$(platform_src_dir)/include
GENFLAGS += -I$(include_dir)
ifneq ($(OPENSBI_VERSION_GIT),)
GENFLAGS += -DOPENSBI_VERSION_GIT="\"$(OPENSBI_VERSION_GIT)\""
endif
ifeq ($(BUILD_INFO),y)
GENFLAGS += -DOPENSBI_BUILD_TIME_STAMP="\"$(OPENSBI_BUILD_TIME_STAMP)\""
GENFLAGS += -DOPENSBI_BUILD_COMPILER_VERSION="\"$(OPENSBI_BUILD_COMPILER_VERSION)\""
endif
GENFLAGS += $(libsbiutils-genflags-y)
GENFLAGS += $(platform-genflags-y)
GENFLAGS += $(firmware-genflags-y)
CFLAGS = -g -Wall -Werror -ffreestanding -nostdlib -fno-strict-aliasing -O2
CFLAGS += -fno-omit-frame-pointer -fno-optimize-sibling-calls
CFLAGS += -mno-save-restore -mstrict-align
CFLAGS = -g -Wall -Werror -ffreestanding -nostdlib -fno-stack-protector -fno-strict-aliasing -O2
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)
CFLAGS += -mno-save-restore
endif
CFLAGS += -mabi=$(PLATFORM_RISCV_ABI) -march=$(PLATFORM_RISCV_ISA)
CFLAGS += -mcmodel=$(PLATFORM_RISCV_CODE_MODEL)
CFLAGS += $(RELAX_FLAG)
CFLAGS += $(GENFLAGS)
CFLAGS += $(platform-cflags-y)
CFLAGS += $(firmware-cflags-y)
CFLAGS += -fno-pie -no-pie
CFLAGS += $(firmware-cflags-y)
CPPFLAGS += $(GENFLAGS)
CPPFLAGS += $(platform-cppflags-y)
CPPFLAGS += $(firmware-cppflags-y)
ASFLAGS = -g -Wall -nostdlib -D__ASSEMBLY__
ASFLAGS += -fno-omit-frame-pointer -fno-optimize-sibling-calls
ASFLAGS += -mno-save-restore -mstrict-align
ASFLAGS = -g -Wall -nostdlib
ASFLAGS += -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)
ASFLAGS += -mno-save-restore
endif
ASFLAGS += -mabi=$(PLATFORM_RISCV_ABI) -march=$(PLATFORM_RISCV_ISA)
ASFLAGS += -mcmodel=$(PLATFORM_RISCV_CODE_MODEL)
ASFLAGS += $(RELAX_FLAG)
ifneq ($(CC_IS_CLANG),y)
ifneq ($(RELAX_FLAG),)
ASFLAGS += -Wa,$(RELAX_FLAG)
endif
endif
ASFLAGS += $(GENFLAGS)
ASFLAGS += $(platform-asflags-y)
ASFLAGS += $(firmware-asflags-y)
ARFLAGS = rcs
ELFFLAGS += -Wl,--build-id=none -N -static-libgcc -lgcc
ELFFLAGS += $(USE_LD_FLAG)
ELFFLAGS += -Wl,--build-id=none -Wl,-N
ELFFLAGS += $(platform-ldflags-y)
ELFFLAGS += $(firmware-ldflags-y)
MERGEFLAGS += -r
ifeq ($(LD_IS_LLD),y)
MERGEFLAGS += -b elf
else
MERGEFLAGS += -b elf$(PLATFORM_RISCV_XLEN)-littleriscv
endif
MERGEFLAGS += -m elf$(PLATFORM_RISCV_XLEN)lriscv
DTSCPPFLAGS = $(CPPFLAGS) -nostdinc -nostdlib -fno-builtin -D__DTS__ -x assembler-with-cpp
@@ -305,6 +404,10 @@ compile_d2c = $(CMD_PREFIX)mkdir -p `dirname $(1)`; \
$(if $($(2)-varprefix-$(3)),$(eval D2C_NAME_PREFIX := $($(2)-varprefix-$(3))),$(eval D2C_NAME_PREFIX := $(5))) \
$(if $($(2)-padding-$(3)),$(eval D2C_PADDING_BYTES := $($(2)-padding-$(3))),$(eval D2C_PADDING_BYTES := 0)) \
$(src_dir)/scripts/d2c.sh -i $(6) -a $(D2C_ALIGN_BYTES) -p $(D2C_NAME_PREFIX) -t $(D2C_PADDING_BYTES) > $(1)
compile_carray = $(CMD_PREFIX)mkdir -p `dirname $(1)`; \
echo " CARRAY $(subst $(build_dir)/,,$(1))"; \
$(eval CARRAY_VAR_LIST := $(carray-$(subst .c,,$(shell basename $(1)))-y)) \
$(src_dir)/scripts/carray.sh -i $(2) -l "$(CARRAY_VAR_LIST)" > $(1)
compile_gen_dep = $(CMD_PREFIX)mkdir -p `dirname $(1)`; \
echo " GEN-DEP $(subst $(build_dir)/,,$(1))"; \
echo "$(1:.dep=$(2)): $(3)" >> $(1)
@@ -338,12 +441,27 @@ $(build_dir)/%.dep: $(src_dir)/%.c
$(build_dir)/%.o: $(src_dir)/%.c
$(call compile_cc,$@,$<)
$(build_dir)/%.o: $(build_dir)/%.c
$(call compile_cc,$@,$<)
ifeq ($(BUILD_INFO),y)
$(build_dir)/lib/sbi/sbi_init.o: $(libsbi_dir)/sbi_init.c FORCE
$(call compile_cc,$@,$<)
endif
$(build_dir)/%.dep: $(src_dir)/%.S
$(call compile_as_dep,$@,$<)
$(build_dir)/%.o: $(src_dir)/%.S
$(call compile_as,$@,$<)
$(build_dir)/%.dep: $(src_dir)/%.carray
$(call compile_gen_dep,$@,.c,$<)
$(call compile_gen_dep,$@,.o,$(@:.dep=.c))
$(build_dir)/%.c: $(src_dir)/%.carray
$(call compile_carray,$@,$<)
$(platform_build_dir)/%.bin: $(platform_build_dir)/%.elf
$(call compile_objcopy,$@,$<)
@@ -359,9 +477,6 @@ $(platform_build_dir)/%.dep: $(platform_src_dir)/%.c
$(platform_build_dir)/%.o: $(platform_src_dir)/%.c
$(call compile_cc,$@,$<)
$(platform_build_dir)/%.o: $(platform_build_dir)/%.c
$(call compile_cc,$@,$<)
$(platform_build_dir)/%.dep: $(platform_src_dir)/%.S
$(call compile_as_dep,$@,$<)
@@ -491,3 +606,6 @@ 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
.PHONY: FORCE
FORCE:

View File

@@ -96,8 +96,21 @@ Required Toolchain
------------------
OpenSBI can be compiled natively or cross-compiled on a x86 host. For
cross-compilation, you can build your own toolchain or just download
a prebuilt one from the [Bootlin toolchain repository].
cross-compilation, you can build your own toolchain, download a prebuilt one
from the [Bootlin toolchain repository] or install a distribution-provided
toolchain; if you opt to use LLVM/Clang, most distribution toolchains will
support cross-compiling for RISC-V using the same toolchain as your native
LLVM/Clang toolchain due to LLVM's ability to support multiple backends in the
same binary, so is often an easy way to obtain a working cross-compilation
toolchain.
Basically, we prefer toolchains with Position Independent Executable (PIE)
support like *riscv64-linux-gnu-gcc*, *riscv64-unknown-freebsd-gcc*, or
*Clang/LLVM* as they generate PIE firmware images that can run at arbitrary
address with appropriate alignment. If a bare-metal GNU toolchain (e.g.
*riscv64-unknown-elf-gcc*) is used, static linked firmware images are
generated instead. *Clang/LLVM* can still generate PIE images if a bare-metal
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.
@@ -111,7 +124,7 @@ architecture than RISC-V.
For cross-compiling, the environment variable *CROSS_COMPILE* must be defined
to specify the name prefix of the RISC-V compiler toolchain executables, e.g.
*riscv64-unknown-elf-* if the gcc executable used is *riscv64-unknown-elf-gcc*.
*riscv64-linux-gnu-* if the gcc executable used is *riscv64-linux-gnu-gcc*.
To build *libsbi.a* simply execute:
```
@@ -187,21 +200,83 @@ Building 32-bit / 64-bit OpenSBI Images
---------------------------------------
By default, building OpenSBI generates 32-bit or 64-bit images based on the
supplied RISC-V cross-compile toolchain. For example if *CROSS_COMPILE* is set
to *riscv64-unknown-elf-*, 64-bit OpenSBI images will be generated. If building
to *riscv64-linux-gnu-*, 64-bit OpenSBI images will be generated. If building
32-bit OpenSBI images, *CROSS_COMPILE* should be set to a toolchain that is
pre-configured to generate 32-bit RISC-V codes, like *riscv32-unknown-elf-*.
pre-configured to generate 32-bit RISC-V codes, like *riscv32-linux-gnu-*.
However it's possible to explicitly specify the image bits we want to build with
a given RISC-V toolchain. This can be done by setting the environment variable
*PLATFORM_RISCV_XLEN* to the desired width, for example:
```
export CROSS_COMPILE=riscv64-unknown-elf-
export CROSS_COMPILE=riscv64-linux-gnu-
export PLATFORM_RISCV_XLEN=32
```
will generate 32-bit OpenSBI images. And vice vesa.
Building with Clang/LLVM
------------------------
OpenSBI can also be built with Clang/LLVM. To build with just Clang but keep
the default binutils (which will still use the *CROSS_COMPILE* prefix if
defined), override the *CC* make variable with:
```
make CC=clang
```
To build with a full LLVM-based toolchain, not just Clang, enable the *LLVM*
option with:
```
make LLVM=1
```
When using Clang, *CROSS_COMPILE* often does not need to be defined unless
using GNU binutils with prefixed binary names. *PLATFORM_RISCV_XLEN* will be
used to infer a default triple to pass to Clang, so if *PLATFORM_RISCV_XLEN*
itself defaults to an undesired value then prefer setting that rather than the
full triple via *CROSS_COMPILE*. If *CROSS_COMPILE* is nonetheless defined,
rather than being used as a prefix for the executable name, it will instead be
passed via the `--target` option with the trailing `-` removed, so must be a
valid triple.
These can also be mixed; for example using a GCC cross-compiler but LLVM
binutils would be:
```
make CC=riscv64-linux-gnu-gcc LLVM=1
```
These variables must be passed for all the make invocations described in this
document.
NOTE: Using Clang with a `riscv*-linux-gnu` GNU binutils linker has been seen
to produce broken binaries with missing relocations; it is therefore currently
recommended that this combination be avoided or *FW_PIC=n* be used to disable
building OpenSBI as a position-independent binary.
Building with timestamp and compiler info
-----------------------------------------
When doing development, we may want to know the build time and compiler info
for debug purpose. OpenSBI can also be built with timestamp and compiler info.
To build with those info and print it out at boot time, we can just simply add
`BUILD_INFO=y`, like:
```
make BUILD_INFO=y
```
But if you have used `BUILD_INFO=y`, and want to switch back to `BUILD_INFO=n`,
you must do
```
make clean
```
before the next build.
NOTE: Using `BUILD_INFO=y` without specifying SOURCE_DATE_EPOCH will violate
[reproducible builds]. This definition is ONLY for development and debug
purpose, and should NOT be used in a product which follows "reproducible
builds".
Contributing to OpenSBI
-----------------------
@@ -284,3 +359,4 @@ make I=<install_directory> install_docs
[Doxygen manual]: http://www.doxygen.nl/manual/index.html
[Kendryte standalone SDK]: https://github.com/kendryte/kendryte-standalone-sdk
[third party notices]: ThirdPartyNotices.md
[reproducible builds]: https://reproducible-builds.org

View File

@@ -9,6 +9,13 @@ OpenSBI generic library code. The supported firmwares type will differ in how
the arguments passed by the platform early boot stage are handled, as well as
how the boot stage following the firmware will be handled and executed.
The previous booting stage will pass information via the following registers
of RISC-V CPU:
* hartid via *a0* register
* device tree blob address in memory via *a1* register. The address must
be aligned to 8 bytes.
OpenSBI currently supports three different types of firmwares.
Firmware with Dynamic Information (*FW_DYNAMIC*)
@@ -62,6 +69,12 @@ parameters:
argument by the prior booting stage.
* **FW_FDT_PADDING** - Optional zero bytes padding to the embedded flattened
device tree binary file specified by **FW_FDT_PATH** option.
* **FW_PIC** - "FW_PIC=y" generates position independent executable firmware
images. OpenSBI can run at arbitrary address with appropriate alignment.
Therefore, the original relocation mechanism ("FW_PIC=n") will be skipped.
In other words, OpenSBI will directly run at the load address without any
code movement. This option requires a toolchain with PIE support, and it
is on by default.
Additionally, each firmware type as a set of type specific configuration
parameters. Detailed information for each firmware type can be found in the

View File

@@ -6,8 +6,9 @@ information about next booting stage (e.g. a bootloader or an OS) and runtime
OpenSBI library options from previous booting stage.
The previous booting stage will pass information to *FW_DYNAMIC* by creating
*struct fw_dynamic_info* in memory and passing it's address to *FW_DYNAMIC*
via *a2* register of RISC-V CPU.
*struct fw_dynamic_info* in memory and passing its address to *FW_DYNAMIC*
via *a2* register of RISC-V CPU. The address must be aligned to 8 bytes on
RV64 and 4 bytes on RV32.
A *FW_DYNAMIC* firmware is particularly useful when the booting stage executed
prior to OpenSBI firmware is capable of loading both the OpenSBI firmware and

View File

@@ -46,9 +46,13 @@ RISC-V Platforms Using Generic Platform
---------------------------------------
* **QEMU RISC-V Virt Machine** (*[qemu_virt.md]*)
* **Spike** (*[spike.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]*)
[qemu_virt.md]: qemu_virt.md
[spike.md]: spike.md
[shakti_cclass.md]: shakti_cclass.md
[sifive_fu540.md]: sifive_fu540.md
[spike.md]: spike.md
[thead-c9xx.md]: thead-c9xx.md

View File

@@ -28,15 +28,12 @@ OpenSBI currently supports the following virtual and hardware platforms:
* **Andes AE350 SoC**: Platform support for the Andes's SoC (AE350). More
details on this platform can be found in the file *[andes-ae350.md]*.
* **T-HEAD C910**: Platform support for the T-HEAD C910 Processor. More
details on this platform can be found in the file *[thead-c910.md]*.
* **Spike**: Platform support for the Spike emulator. More
details on this platform can be found in the file *[spike.md]*.
* **OpenPiton FPGA SoC**: Platform support OpenPiton research platform based
on ariane core. More details on this platform can be found in the file
*[fpga_openpiton.md]*.
*[fpga-openpiton.md]*.
* **Shakti C-class SoC Platform**: Platform support for Shakti C-class
processor based SOCs. More details on this platform can be found in the
@@ -55,5 +52,5 @@ facilitate the implementation.
[andes-ae350.md]: andes-ae350.md
[thead-c910.md]: thead-c910.md
[spike.md]: spike.md
[fpga_openpiton.md]: fpga_openpiton.md
[fpga-openpiton.md]: fpga-openpiton.md
[shakti_cclass.md]: shakti_cclass.md

View File

@@ -147,3 +147,27 @@ qemu-system-riscv32 -M virt -m 256M -nographic \
-device virtio-blk-device,drive=hd0 \
-append "root=/dev/vda rw console=ttyS0"
```
Debugging with GDB
------------------
In a first console start OpenSBI with QEMU:
```
qemu-system-riscv64 -M virt -m 256M -nographic \
-bios build/platform/generic/firmware/fw_payload.bin \
-gdb tcp::1234 \
-S
```
Parameter *-gdb tcp::1234* specifies 1234 as the debug port.
Parameter *-S* lets QEMU wait at the first instruction.
In a second console start GDB:
```
gdb build/platform/generic/firmware/fw_payload.elf \
-ex 'target remote localhost:1234'
```

View File

@@ -8,7 +8,7 @@ With QEMU v4.2 or above release, the 'sifive_u' machine can be used to test
OpenSBI image built for the real hardware as well.
To build platform specific library and firmwares, provide the
*PLATFORM=sifive/fu540* parameter to the top level `make` command.
*PLATFORM=generic* parameter to the top level `make` command.
Platform Options
----------------
@@ -32,20 +32,20 @@ To use Linux v5.2 (or higher), the pre-built DTB (DT binary) from Linux v5.2
the compile time option *FW_FDT_PATH*.
```
make PLATFORM=sifive/fu540 FW_PAYLOAD_PATH=<linux_build_directory>/arch/riscv/boot/Image
make PLATFORM=generic FW_PAYLOAD_PATH=<linux_build_directory>/arch/riscv/boot/Image
or
(For Linux v5.2 or higher)
make PLATFORM=sifive/fu540 FW_PAYLOAD_PATH=<linux_build_directory>/arch/riscv/boot/Image FW_FDT_PATH=<hifive-unleashed-a00.dtb path from Linux kernel>
make PLATFORM=generic FW_PAYLOAD_PATH=<linux_build_directory>/arch/riscv/boot/Image FW_FDT_PATH=<hifive-unleashed-a00.dtb path from Linux kernel>
```
**U-Boot Payload**
The command-line example here assumes that U-Boot was compiled using the
sifive_fu540_defconfig configuration and with U-Boot v2020.01, and up to
v2020.07-rc3.
v2021.04. sifive_unleashed_defconfig shall be used with v2021.07 or above.
```
make PLATFORM=sifive/fu540 FW_PAYLOAD_PATH=<u-boot_build_dir>/u-boot-dtb.bin
make PLATFORM=generic FW_PAYLOAD_PATH=<u-boot_build_dir>/u-boot-dtb.bin
```
For U-Boot v2020.07-rc4 or later releases, SPL support was added in U-Boot.
Please refer to the detailed U-Boot booting guide available at [U-Boot].
@@ -64,7 +64,7 @@ That's why the generated firmware binary in above steps should be copied to
the partition of the sdcard with above GUID.
```
dd if=build/platform/sifive/fu540/firmware/fw_payload.bin of=/dev/disk2s1 bs=1024
dd if=build/platform/generic/firmware/fw_payload.bin of=/dev/disk2s1 bs=1024
```
In my case, it is the first partition is **disk2s1** that has been formatted
@@ -153,14 +153,15 @@ 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
Linux kernel.
When U-Boot v2020.01 (or higher) is used as the payload, as the SiFive FU540
When U-Boot v2021.07 (or higher) is used as the payload, as the SiFive FU540
DTB for the real hardware is embedded in U-Boot binary itself, due to the same
reason above, we need to switch the U-Boot sifive_fu540_defconfig configuration
from **CONFIG_OF_SEPARATE** to **CONFIG_OF_PRIOR_STAGE** so that U-Boot uses the
DTB generated by QEMU, and u-boot.bin should be used as the payload image, like:
reason above, we need to switch the U-Boot sifive_unleashed_defconfig
configuration from **CONFIG_OF_SEPARATE** to **CONFIG_OF_PRIOR_STAGE** so that
U-Boot uses the DTB generated by QEMU, and u-boot.bin should be used as the
payload image, like:
```
make PLATFORM=sifive/fu540 FW_PAYLOAD_PATH=<u-boot_build_dir>/u-boot.bin
make PLATFORM=generic FW_PAYLOAD_PATH=<u-boot_build_dir>/u-boot.bin
```
U-Boot v2020.07 release added SPL support to SiFive HiFive Unleashed board,
@@ -178,12 +179,12 @@ The above errors can be safely ignored as we don't run U-Boot SPL under QEMU.
Run:
```
qemu-system-riscv64 -M sifive_u -m 256M -nographic \
-bios build/platform/sifive/fu540/firmware/fw_payload.bin
-bios build/platform/generic/firmware/fw_payload.bin
```
or
```
qemu-system-riscv64 -M sifive_u -m 256M -nographic \
-bios build/platform/sifive/fu540/firmware/fw_jump.bin \
-bios build/platform/generic/firmware/fw_jump.bin \
-kernel <uboot_build_dir>/u-boot.bin
```

View File

@@ -43,7 +43,18 @@ make PLATFORM=generic FW_PAYLOAD_PATH=<linux_build_directory>/arch/riscv/boot/Im
Run:
```
spike --initrd <path_to_cpio_ramdisk> build/platform/generic/firmware/fw_payload.elf
spike -m256 \
--initrd <path_to_cpio_ramdisk> \
--bootargs 'root=/dev/ram rw console=hvc0 earlycon=sbi' \
build/platform/generic/firmware/fw_payload.elf
```
or
```
spike -m256 \
--kernel <linux_build_directory>/arch/riscv/boot/Image \
--initrd <path_to_cpio_ramdisk> \
--bootargs 'root=/dev/ram rw console=hvc0 earlycon=sbi' \
build/platform/generic/firmware/fw_jump.elf
```
Execution on QEMU RISC-V 64-bit

View File

@@ -1,34 +0,0 @@
T-HEAD C910 Processor
=====================
C910 is a 12-stage, 3 issues, 8 executions, out-of-order 64-bit RISC-V CPU which
supports 16 cores, runs with 2.5GHz, and is capable of running Linux.
To build platform specific library and firmwares, provide the
*PLATFORM=thead/c910* parameter to the top level make command.
Platform Options
----------------
The *T-HEAD C910* platform does not have any platform-specific options.
Building T-HEAD C910 Platform
-----------------------------
```
make PLATFORM=thead/c910
```
Booting T-HEAD C910 Platform
----------------------------
**No Payload**
As there's no payload, you may download vmlinux or u-boot to FW_JUMP_ADDR which
specified in config.mk or compile commands with GDB. And the execution flow will
turn to vmlinux or u-boot when opensbi ends.
**Linux Kernel Payload**
You can also choose to use Linux kernel as payload by enabling FW_PAYLOAD=y
along with specifying FW_PAYLOAD_OFFSET. The kernel image will be embedded in
the OPENSBI firmware binary, T-head will directly boot into Linux after OpenSBI.

196
docs/platform/thead-c9xx.md Normal file
View File

@@ -0,0 +1,196 @@
T-HEAD C9xx Series Processors
=============================
The **C9xx** series processors are high-performance RISC-V architecture
multi-core processors with AI vector acceleration engine.
For more details, refer [T-HEAD.CN](https://www.t-head.cn/)
To build the platform-specific library and firmware images, provide the
*PLATFORM=generic* parameter to the top level `make` command.
Platform Options
----------------
The *T-HEAD C9xx* does not have any platform-specific compile options
because it use generic platform.
```
CROSS_COMPILE=riscv64-linux-gnu- PLATFORM=generic /usr/bin/make
```
The *T-HEAD C9xx* DTB provided to OpenSBI generic firmwares will usually have
"riscv,clint0", "riscv,plic0", "thead,reset-sample" compatible strings.
DTS Example1: (Single core, eg: Allwinner D1 - c906)
----------------------------------------------------
```
cpus {
#address-cells = <1>;
#size-cells = <0>;
timebase-frequency = <3000000>;
cpu@0 {
device_type = "cpu";
reg = <0>;
status = "okay";
compatible = "riscv";
riscv,isa = "rv64imafdcv";
mmu-type = "riscv,sv39";
cpu0_intc: interrupt-controller {
#interrupt-cells = <1>;
compatible = "riscv,cpu-intc";
interrupt-controller;
};
};
};
soc {
#address-cells = <2>;
#size-cells = <2>;
compatible = "simple-bus";
ranges;
clint0: clint@14000000 {
compatible = "allwinner,sun20i-d1-clint";
interrupts-extended = <
&cpu0_intc 3 &cpu0_intc 7
>;
reg = <0x0 0x14000000 0x0 0x04000000>;
};
intc: interrupt-controller@10000000 {
#interrupt-cells = <1>;
compatible = "allwinner,sun20i-d1-plic",
"thead,c900-plic";
interrupt-controller;
interrupts-extended = <
&cpu0_intc 0xffffffff &cpu0_intc 9
>;
reg = <0x0 0x10000000 0x0 0x04000000>;
reg-names = "control";
riscv,max-priority = <7>;
riscv,ndev = <200>;
};
}
```
DTS Example2: (Multi cores with soc reset-regs)
-----------------------------------------------
```
cpus {
#address-cells = <1>;
#size-cells = <0>;
timebase-frequency = <3000000>;
cpu@0 {
device_type = "cpu";
reg = <0>;
status = "okay";
compatible = "riscv";
riscv,isa = "rv64imafdc";
mmu-type = "riscv,sv39";
cpu0_intc: interrupt-controller {
#interrupt-cells = <1>;
compatible = "riscv,cpu-intc";
interrupt-controller;
};
};
cpu@1 {
device_type = "cpu";
reg = <1>;
status = "fail";
compatible = "riscv";
riscv,isa = "rv64imafdc";
mmu-type = "riscv,sv39";
cpu1_intc: interrupt-controller {
#interrupt-cells = <1>;
compatible = "riscv,cpu-intc";
interrupt-controller;
};
};
cpu@2 {
device_type = "cpu";
reg = <2>;
status = "fail";
compatible = "riscv";
riscv,isa = "rv64imafdc";
mmu-type = "riscv,sv39";
cpu2_intc: interrupt-controller {
#interrupt-cells = <1>;
compatible = "riscv,cpu-intc";
interrupt-controller;
};
};
cpu@3 {
device_type = "cpu";
reg = <3>;
status = "fail";
compatible = "riscv";
riscv,isa = "rv64imafdc";
mmu-type = "riscv,sv39";
cpu3_intc: interrupt-controller {
#interrupt-cells = <1>;
compatible = "riscv,cpu-intc";
interrupt-controller;
};
};
};
soc {
#address-cells = <2>;
#size-cells = <2>;
compatible = "simple-bus";
ranges;
reset: reset-sample {
compatible = "thead,reset-sample";
entry-reg = <0xff 0xff019050>;
entry-cnt = <4>;
control-reg = <0xff 0xff015004>;
control-val = <0x1c>;
csr-copy = <0x7f3 0x7c0 0x7c1 0x7c2 0x7c3 0x7c5 0x7cc>;
};
clint0: clint@ffdc000000 {
compatible = "riscv,clint0";
interrupts-extended = <
&cpu0_intc 3 &cpu0_intc 7
&cpu1_intc 3 &cpu1_intc 7
&cpu2_intc 3 &cpu2_intc 7
&cpu3_intc 3 &cpu3_intc 7
&cpu4_intc 3 &cpu4_intc 7
>;
reg = <0xff 0xdc000000 0x0 0x04000000>;
};
intc: interrupt-controller@ffd8000000 {
#interrupt-cells = <1>;
compatible = "thead,c900-plic";
interrupt-controller;
interrupts-extended = <
&cpu0_intc 0xffffffff &cpu0_intc 9
&cpu1_intc 0xffffffff &cpu1_intc 9
&cpu2_intc 0xffffffff &cpu2_intc 9
&cpu3_intc 0xffffffff &cpu3_intc 9
>;
reg = <0xff 0xd8000000 0x0 0x04000000>;
reg-names = "control";
riscv,max-priority = <7>;
riscv,ndev = <80>;
};
}
```
DTS Example2: (Multi cores with old reset csrs)
-----------------------------------------------
```
reset: reset-sample {
compatible = "thead,reset-sample";
using-csr-reset;
csr-copy = <0x7c0 0x7c1 0x7c2 0x7c3 0x7c5 0x7cc
0x3b0 0x3b1 0x3b2 0x3b3
0x3b4 0x3b5 0x3b6 0x3b7
0x3a0>;
};
```

View File

@@ -17,7 +17,7 @@ the supported platforms. These firmwares are linked against *libplatsbi.a*.
Firmware binaries are installed in
*<install_directory>/platform/<platform_subdir>/bin*. These firmwares can be
used as executable runtime firmwares on the supported platforms as a replacement
for the legacy *riskv-pk* boot loader (BBL).
for the legacy *riscv-pk* boot loader (BBL).
A complete doxygen-style documentation of *struct sbi_platform* and related
APIs is available in the file *include/sbi/sbi_platform.h*.
@@ -25,18 +25,18 @@ APIs is available in the file *include/sbi/sbi_platform.h*.
Adding support for a new platform
---------------------------------
Support for a new platform named *<xyz>* can be added as follows:
Support for a new platform named *&lt;xyz&gt;* can be added as follows:
1. Create a directory named *<xyz>* under the *platform/* directory.
1. Create a directory named *&lt;xyz&gt;* under the *platform/* directory.
2. Create a platform configuration file named *config.mk* under the
*platform/<xyz>/* directory. This configuration file will provide
*platform/&lt;xyz&gt;/* directory. This configuration file will provide
compiler flags, and select firmware options.
3. Create a *platform/<xyz>/objects.mk* file for listing the
3. Create a *platform/&lt;xyz&gt;/objects.mk* file for listing the
platform-specific object files to be compiled.
4. Create a *platform/<xyz>/platform.c* file providing a *struct sbi_platform*
instance.
4. Create a *platform/&lt;xyz&gt;/platform.c* file providing a
*struct sbi_platform* instance.
A platform support code template is available under the *platform/template*
directory. Copying this directory and its content as a new directory named
*<xyz>* under the *platform/* directory will create all the files mentioned
above.
*&lt;xyz&gt;* under the *platform/* directory will create all the files
mentioned above.

100
docs/pmu_support.md Normal file
View File

@@ -0,0 +1,100 @@
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
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.
* The platforms should provide information about the PMU event selector values
that should be encoded in the expected value of MHPMEVENTx while configuring
MHPMCOUNTERx for that specific event. This can be done via a device tree or
platform specific hooks. The exact value to be written to he MHPMEVENTx is
completely depends on platform. Generic platform writes the zero-extended event_idx
as the expected value for hardware cache/generic events as suggested by the SBI
specification.
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
bindings in details.
* **compatible** (Mandatory) - The compatible string of SBI PMU device tree node.
This DT property must have the value **riscv,pmu**.
* **riscv,event-to-mhpmevent**(Optional) - It represents an ONE-to-ONE mapping
between a PMU event and the event selector value that platform expects to be
written to the MHPMEVENTx CSR for that event. The mapping is encoded in a
table format where each row represents an event. The first column represent the
event idx where the 2nd & 3rd column represent the event selector value that
should be encoded in the expected value to be written in MHPMEVENTx.
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
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
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
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.
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
select_mask must be 0xffffffff_ffffffff.
*Note:* A platform may choose to provide the mapping between event & counters
via platform hooks rather than the device tree.
### Example 1
```
pmu {
compatible = "riscv,pmu";
riscv,event-to-mhpmevent = <0x0000B 0x0000 0x0001>,
riscv,event-to-mhpmcounters = <0x00001 0x00001 0x00000001>,
<0x00002 0x00002 0x00000004>,
<0x00003 0x0000A 0x00000ff8>,
<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>,
};
```
### Example 2
```
/*
* 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
*/
pmu {
compatible = "riscv,pmu";
riscv,raw-event-to-mhpmcounters = <0x0 0x0 0xffffffff 0xfc0000ff 0xc>,
<0x0 0x1 0xffffffff 0xfff800ff 0xc>,
<0x0 0x2 0xffffffff 0xffffe0ff 0xc>;
};
```

View File

@@ -9,6 +9,7 @@
#include <sbi/riscv_asm.h>
#include <sbi/riscv_encoding.h>
#include <sbi/riscv_elf.h>
#include <sbi/sbi_platform.h>
#include <sbi/sbi_scratch.h>
#include <sbi/sbi_trap.h>
@@ -57,39 +58,91 @@ _start:
bne a0, a6, _wait_relocate_copy_done
_try_lottery:
/* Jump to relocation wait loop if we don't get relocation lottery */
la a6, _relocate_lottery
lla a6, _relocate_lottery
li a7, 1
amoadd.w a6, a7, (a6)
bnez a6, _wait_relocate_copy_done
/* Save load address */
la t0, _load_start
la t1, _start
lla t0, _load_start
lla t1, _fw_start
REG_S t1, 0(t0)
#ifdef FW_PIC
/* relocate the global table content */
lla t0, _link_start
REG_L t0, 0(t0)
/* t1 shall has the address of _fw_start */
sub t2, t1, t0
lla t3, _runtime_offset
REG_S t2, (t3)
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 */
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 */
add t5, t5, t2
add t3, t3, t2
REG_S t5, 0(t3) /* store runtime address to the GOT entry */
j 5f
3:
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)
li t5, SYM_SIZE
mul t6, t6, t5
add s5, t4, t6
REG_L t6, -(REGBYTES)(t0) /* t0 <-- addend */
REG_L t5, REGBYTES(s5)
add t5, t5, t6
add t5, t5, t2 /* t5 <-- location to fix up in RAM */
add t3, t3, t2 /* t3 <-- location to fix up in RAM */
REG_S t5, 0(t3) /* store runtime address to the variable */
5:
addi t0, t0, (REGBYTES*3)
ble t0, t1, 2b
j _relocate_done
_wait_relocate_copy_done:
j _wait_for_boot_hart
#else
/* Relocate if load address != link address */
_relocate:
la t0, _link_start
lla t0, _link_start
REG_L t0, 0(t0)
la t1, _link_end
lla t1, _link_end
REG_L t1, 0(t1)
la t2, _load_start
lla t2, _load_start
REG_L t2, 0(t2)
sub t3, t1, t0
add t3, t3, t2
beq t0, t2, _relocate_done
la t4, _relocate_done
lla t4, _relocate_done
sub t4, t4, t2
add t4, t4, t0
blt t2, t0, _relocate_copy_to_upper
_relocate_copy_to_lower:
ble t1, t2, _relocate_copy_to_lower_loop
la t3, _relocate_lottery
lla t3, _relocate_lottery
BRANGE t2, t1, t3, _start_hang
la t3, _boot_status
lla t3, _boot_status
BRANGE t2, t1, t3, _start_hang
la t3, _relocate
la t5, _relocate_done
lla t3, _relocate
lla t5, _relocate_done
BRANGE t2, t1, t3, _start_hang
BRANGE t2, t1, t5, _start_hang
BRANGE t3, t5, t2, _start_hang
@@ -102,12 +155,12 @@ _relocate_copy_to_lower_loop:
jr t4
_relocate_copy_to_upper:
ble t3, t0, _relocate_copy_to_upper_loop
la t2, _relocate_lottery
lla t2, _relocate_lottery
BRANGE t0, t3, t2, _start_hang
la t2, _boot_status
lla t2, _boot_status
BRANGE t0, t3, t2, _start_hang
la t2, _relocate
la t5, _relocate_done
lla t2, _relocate
lla t5, _relocate_done
BRANGE t0, t3, t2, _start_hang
BRANGE t0, t3, t5, _start_hang
BRANGE t2, t5, t0, _start_hang
@@ -119,12 +172,12 @@ _relocate_copy_to_upper_loop:
blt t0, t1, _relocate_copy_to_upper_loop
jr t4
_wait_relocate_copy_done:
la t0, _start
la t1, _link_start
lla t0, _fw_start
lla t1, _link_start
REG_L t1, 0(t1)
beq t0, t1, _wait_for_boot_hart
la t2, _boot_status
la t3, _wait_for_boot_hart
lla t2, _boot_status
lla t3, _wait_for_boot_hart
sub t3, t3, t0
add t3, t3, t1
1:
@@ -137,19 +190,22 @@ _wait_relocate_copy_done:
nop
bgt t4, t5, 1b
jr t3
#endif
_relocate_done:
/*
* Mark relocate copy done
* Use _boot_status copy relative to the load address
*/
la t0, _boot_status
la t1, _link_start
lla t0, _boot_status
#ifndef FW_PIC
lla t1, _link_start
REG_L t1, 0(t1)
la t2, _load_start
lla t2, _load_start
REG_L t2, 0(t2)
sub t0, t0, t1
add t0, t0, t2
#endif
li t1, BOOT_STATUS_RELOCATE_DONE
REG_S t1, 0(t0)
fence rw, rw
@@ -161,19 +217,19 @@ _relocate_done:
call _reset_regs
/* Zero-out BSS */
la s4, _bss_start
la s5, _bss_end
lla s4, _bss_start
lla s5, _bss_end
_bss_zero:
REG_S zero, (s4)
add s4, s4, __SIZEOF_POINTER__
blt s4, s5, _bss_zero
/* Setup temporary trap handler */
la s4, _start_hang
lla s4, _start_hang
csrw CSR_MTVEC, s4
/* Setup temporary stack */
la s4, _fw_end
lla s4, _fw_end
li s5, (SBI_SCRATCH_SIZE * 2)
add sp, s4, s5
@@ -184,7 +240,7 @@ _bss_zero:
#ifdef FW_FDT_PATH
/* Override previous arg1 */
la a1, fw_fdt_bin
lla a1, fw_fdt_bin
#endif
/*
@@ -202,8 +258,8 @@ _bss_zero:
* s7 -> HART Count
* s8 -> HART Stack Size
*/
la a4, platform
#if __riscv_xlen == 64
lla a4, platform
#if __riscv_xlen > 32
lwu s7, SBI_PLATFORM_HART_COUNT_OFFSET(a4)
lwu s8, SBI_PLATFORM_HART_STACK_SIZE_OFFSET(a4)
#else
@@ -212,7 +268,7 @@ _bss_zero:
#endif
/* Setup scratch space for all the HARTs*/
la tp, _fw_end
lla tp, _fw_end
mul a5, s7, s8
add tp, tp, a5
/* Keep a copy of tp */
@@ -222,6 +278,14 @@ _bss_zero:
/* hartid 0 is mandated by ISA */
li t1, 0
_scratch_init:
/*
* The following registers hold values that are computed before
* entering this block, and should remain unchanged.
*
* t3 -> the firmware end address
* s7 -> HART count
* s8 -> HART stack size
*/
add tp, t3, zero
mul a5, s8, t1
sub tp, tp, a5
@@ -230,11 +294,8 @@ _scratch_init:
/* Initialize scratch space */
/* Store fw_start and fw_size in scratch space */
la a4, _fw_start
la a5, _fw_end
mul t0, s7, s8
add a5, a5, t0
sub a5, a5, a4
lla a4, _fw_start
sub a5, t3, a4
REG_S a4, SBI_SCRATCH_FW_START_OFFSET(tp)
REG_S a5, SBI_SCRATCH_FW_SIZE_OFFSET(tp)
/* Store next arg1 in scratch space */
@@ -253,16 +314,16 @@ _scratch_init:
REG_S a0, SBI_SCRATCH_NEXT_MODE_OFFSET(tp)
MOV_3R a0, s0, a1, s1, a2, s2
/* Store warm_boot address in scratch space */
la a4, _start_warm
lla a4, _start_warm
REG_S a4, SBI_SCRATCH_WARMBOOT_ADDR_OFFSET(tp)
/* Store platform address in scratch space */
la a4, platform
lla a4, platform
REG_S a4, SBI_SCRATCH_PLATFORM_ADDR_OFFSET(tp)
/* Store hartid-to-scratch function address in scratch space */
la a4, _hartid_to_scratch
lla a4, _hartid_to_scratch
REG_S a4, SBI_SCRATCH_HARTID_TO_SCRATCH_OFFSET(tp)
/* Store trap-exit function address in scratch space */
la a4, _trap_exit
lla a4, _trap_exit
REG_S a4, SBI_SCRATCH_TRAP_EXIT_OFFSET(tp)
/* Clear tmp0 in scratch space */
REG_S zero, SBI_SCRATCH_TMP0_OFFSET(tp)
@@ -288,8 +349,7 @@ _scratch_init:
* previous booting stage.
*/
beqz a1, _fdt_reloc_done
/* Mask values in a3 and a4 */
li a3, ~(__SIZEOF_POINTER__ - 1)
/* Mask values in a4 */
li a4, 0xff
/* t1 = destination FDT start address */
MOV_3R s0, a0, s1, a1, s2, a2
@@ -298,10 +358,8 @@ _scratch_init:
MOV_3R a0, s0, a1, s1, a2, s2
beqz t1, _fdt_reloc_done
beq t1, a1, _fdt_reloc_done
and t1, t1, a3
/* t0 = source FDT start address */
add t0, a1, zero
and t0, t0, a3
/* t2 = source FDT size in big-endian */
#if __riscv_xlen == 64
lwu t2, 4(t0)
@@ -343,7 +401,7 @@ _fdt_reloc_done:
/* mark boot hart done */
li t0, BOOT_STATUS_BOOT_HART_DONE
la t1, _boot_status
lla t1, _boot_status
REG_S t0, 0(t1)
fence rw, rw
j _start_warm
@@ -351,7 +409,7 @@ _fdt_reloc_done:
/* waiting for boot hart to be done (_boot_status == 2) */
_wait_for_boot_hart:
li t0, BOOT_STATUS_BOOT_HART_DONE
la t1, _boot_status
lla t1, _boot_status
REG_L t1, 0(t1)
/* Reduce the bus traffic so that boot hart may proceed faster */
nop
@@ -369,7 +427,7 @@ _start_warm:
csrw CSR_MIP, zero
/* Find HART count and HART stack size */
la a4, platform
lla a4, platform
#if __riscv_xlen == 64
lwu s7, SBI_PLATFORM_HART_COUNT_OFFSET(a4)
lwu s8, SBI_PLATFORM_HART_STACK_SIZE_OFFSET(a4)
@@ -400,7 +458,7 @@ _start_warm:
3: bge s6, s7, _start_hang
/* Find the scratch space based on HART index */
la tp, _fw_end
lla tp, _fw_end
mul a5, s7, s8
add tp, tp, a5
mul a5, s8, s6
@@ -415,13 +473,13 @@ _start_warm:
add sp, tp, zero
/* Setup trap handler */
la a4, _trap_handler
lla a4, _trap_handler
#if __riscv_xlen == 32
csrr a5, CSR_MISA
srli a5, a5, ('H' - 'A')
andi a5, a5, 0x1
beq a5, zero, _skip_trap_handler_rv32_hyp
la a4, _trap_handler_rv32_hyp
lla a4, _trap_handler_rv32_hyp
_skip_trap_handler_rv32_hyp:
#endif
csrw CSR_MTVEC, a4
@@ -432,7 +490,7 @@ _skip_trap_handler_rv32_hyp:
srli a5, a5, ('H' - 'A')
andi a5, a5, 0x1
beq a5, zero, _skip_trap_exit_rv32_hyp
la a4, _trap_exit_rv32_hyp
lla a4, _trap_exit_rv32_hyp
csrr a5, CSR_MSCRATCH
REG_S a4, SBI_SCRATCH_TRAP_EXIT_OFFSET(a5)
_skip_trap_exit_rv32_hyp:
@@ -445,7 +503,12 @@ _skip_trap_exit_rv32_hyp:
/* We don't expect to reach here hence just hang */
j _start_hang
.data
.align 3
#ifdef FW_PIC
_runtime_offset:
RISCV_PTR 0
#endif
_relocate_lottery:
RISCV_PTR 0
_boot_status:
@@ -453,7 +516,7 @@ _boot_status:
_load_start:
RISCV_PTR _fw_start
_link_start:
RISCV_PTR _fw_start
RISCV_PTR FW_TEXT_START
_link_end:
RISCV_PTR _fw_reloc_end
@@ -468,7 +531,7 @@ _hartid_to_scratch:
* t1 -> HART Stack End
* t2 -> Temporary
*/
la t2, platform
lla t2, platform
#if __riscv_xlen == 64
lwu t0, SBI_PLATFORM_HART_STACK_SIZE_OFFSET(t2)
lwu t2, SBI_PLATFORM_HART_COUNT_OFFSET(t2)
@@ -478,7 +541,7 @@ _hartid_to_scratch:
#endif
sub t2, t2, a1
mul t2, t2, t0
la t1, _fw_end
lla t1, _fw_end
add t1, t1, t2
li t2, SBI_SCRATCH_SIZE
sub a0, t1, t2
@@ -493,12 +556,39 @@ _start_hang:
.section .entry, "ax", %progbits
.align 3
.globl fw_platform_init
.weak fw_platform_init
fw_platform_init:
add a0, a1, zero
ret
/* Map implicit memcpy() added by compiler to sbi_memcpy() */
.section .text
.align 3
.globl memcpy
memcpy:
tail sbi_memcpy
/* Map implicit memset() added by compiler to sbi_memset() */
.section .text
.align 3
.globl memset
memset:
tail sbi_memset
/* Map implicit memmove() added by compiler to sbi_memmove() */
.section .text
.align 3
.globl memmove
memmove:
tail sbi_memmove
/* Map implicit memcmp() added by compiler to sbi_memcmp() */
.section .text
.align 3
.globl memcmp
memcmp:
tail sbi_memcmp
.macro TRAP_SAVE_AND_SETUP_SP_T0
/* Swap TP and MSCRATCH */
csrrw tp, CSR_MSCRATCH, tp
@@ -595,62 +685,63 @@ fw_platform_init:
call sbi_trap_handler
.endm
.macro TRAP_RESTORE_GENERAL_REGS_EXCEPT_SP_T0
/* Restore all general regisers except SP and T0 */
REG_L ra, SBI_TRAP_REGS_OFFSET(ra)(sp)
REG_L gp, SBI_TRAP_REGS_OFFSET(gp)(sp)
REG_L tp, SBI_TRAP_REGS_OFFSET(tp)(sp)
REG_L t1, SBI_TRAP_REGS_OFFSET(t1)(sp)
REG_L t2, SBI_TRAP_REGS_OFFSET(t2)(sp)
REG_L s0, SBI_TRAP_REGS_OFFSET(s0)(sp)
REG_L s1, SBI_TRAP_REGS_OFFSET(s1)(sp)
REG_L a0, SBI_TRAP_REGS_OFFSET(a0)(sp)
REG_L a1, SBI_TRAP_REGS_OFFSET(a1)(sp)
REG_L a2, SBI_TRAP_REGS_OFFSET(a2)(sp)
REG_L a3, SBI_TRAP_REGS_OFFSET(a3)(sp)
REG_L a4, SBI_TRAP_REGS_OFFSET(a4)(sp)
REG_L a5, SBI_TRAP_REGS_OFFSET(a5)(sp)
REG_L a6, SBI_TRAP_REGS_OFFSET(a6)(sp)
REG_L a7, SBI_TRAP_REGS_OFFSET(a7)(sp)
REG_L s2, SBI_TRAP_REGS_OFFSET(s2)(sp)
REG_L s3, SBI_TRAP_REGS_OFFSET(s3)(sp)
REG_L s4, SBI_TRAP_REGS_OFFSET(s4)(sp)
REG_L s5, SBI_TRAP_REGS_OFFSET(s5)(sp)
REG_L s6, SBI_TRAP_REGS_OFFSET(s6)(sp)
REG_L s7, SBI_TRAP_REGS_OFFSET(s7)(sp)
REG_L s8, SBI_TRAP_REGS_OFFSET(s8)(sp)
REG_L s9, SBI_TRAP_REGS_OFFSET(s9)(sp)
REG_L s10, SBI_TRAP_REGS_OFFSET(s10)(sp)
REG_L s11, SBI_TRAP_REGS_OFFSET(s11)(sp)
REG_L t3, SBI_TRAP_REGS_OFFSET(t3)(sp)
REG_L t4, SBI_TRAP_REGS_OFFSET(t4)(sp)
REG_L t5, SBI_TRAP_REGS_OFFSET(t5)(sp)
REG_L t6, SBI_TRAP_REGS_OFFSET(t6)(sp)
.macro TRAP_RESTORE_GENERAL_REGS_EXCEPT_A0_T0
/* Restore all general regisers except A0 and T0 */
REG_L ra, SBI_TRAP_REGS_OFFSET(ra)(a0)
REG_L sp, SBI_TRAP_REGS_OFFSET(sp)(a0)
REG_L gp, SBI_TRAP_REGS_OFFSET(gp)(a0)
REG_L tp, SBI_TRAP_REGS_OFFSET(tp)(a0)
REG_L t1, SBI_TRAP_REGS_OFFSET(t1)(a0)
REG_L t2, SBI_TRAP_REGS_OFFSET(t2)(a0)
REG_L s0, SBI_TRAP_REGS_OFFSET(s0)(a0)
REG_L s1, SBI_TRAP_REGS_OFFSET(s1)(a0)
REG_L a1, SBI_TRAP_REGS_OFFSET(a1)(a0)
REG_L a2, SBI_TRAP_REGS_OFFSET(a2)(a0)
REG_L a3, SBI_TRAP_REGS_OFFSET(a3)(a0)
REG_L a4, SBI_TRAP_REGS_OFFSET(a4)(a0)
REG_L a5, SBI_TRAP_REGS_OFFSET(a5)(a0)
REG_L a6, SBI_TRAP_REGS_OFFSET(a6)(a0)
REG_L a7, SBI_TRAP_REGS_OFFSET(a7)(a0)
REG_L s2, SBI_TRAP_REGS_OFFSET(s2)(a0)
REG_L s3, SBI_TRAP_REGS_OFFSET(s3)(a0)
REG_L s4, SBI_TRAP_REGS_OFFSET(s4)(a0)
REG_L s5, SBI_TRAP_REGS_OFFSET(s5)(a0)
REG_L s6, SBI_TRAP_REGS_OFFSET(s6)(a0)
REG_L s7, SBI_TRAP_REGS_OFFSET(s7)(a0)
REG_L s8, SBI_TRAP_REGS_OFFSET(s8)(a0)
REG_L s9, SBI_TRAP_REGS_OFFSET(s9)(a0)
REG_L s10, SBI_TRAP_REGS_OFFSET(s10)(a0)
REG_L s11, SBI_TRAP_REGS_OFFSET(s11)(a0)
REG_L t3, SBI_TRAP_REGS_OFFSET(t3)(a0)
REG_L t4, SBI_TRAP_REGS_OFFSET(t4)(a0)
REG_L t5, SBI_TRAP_REGS_OFFSET(t5)(a0)
REG_L t6, SBI_TRAP_REGS_OFFSET(t6)(a0)
.endm
.macro TRAP_RESTORE_MEPC_MSTATUS have_mstatush
/* Restore MEPC and MSTATUS CSRs */
REG_L t0, SBI_TRAP_REGS_OFFSET(mepc)(sp)
REG_L t0, SBI_TRAP_REGS_OFFSET(mepc)(a0)
csrw CSR_MEPC, t0
REG_L t0, SBI_TRAP_REGS_OFFSET(mstatus)(sp)
REG_L t0, SBI_TRAP_REGS_OFFSET(mstatus)(a0)
csrw CSR_MSTATUS, t0
.if \have_mstatush
REG_L t0, SBI_TRAP_REGS_OFFSET(mstatusH)(sp)
REG_L t0, SBI_TRAP_REGS_OFFSET(mstatusH)(a0)
csrw CSR_MSTATUSH, t0
.endif
.endm
.macro TRAP_RESTORE_SP_T0
.macro TRAP_RESTORE_A0_T0
/* Restore T0 */
REG_L t0, SBI_TRAP_REGS_OFFSET(t0)(sp)
REG_L t0, SBI_TRAP_REGS_OFFSET(t0)(a0)
/* Restore SP */
REG_L sp, SBI_TRAP_REGS_OFFSET(sp)(sp)
/* Restore A0 */
REG_L a0, SBI_TRAP_REGS_OFFSET(a0)(a0)
.endm
.section .entry, "ax", %progbits
.align 3
.globl _trap_handler
.globl _trap_exit
_trap_handler:
TRAP_SAVE_AND_SETUP_SP_T0
@@ -660,25 +751,12 @@ _trap_handler:
TRAP_CALL_C_ROUTINE
TRAP_RESTORE_GENERAL_REGS_EXCEPT_SP_T0
TRAP_RESTORE_MEPC_MSTATUS 0
TRAP_RESTORE_SP_T0
mret
.section .entry, "ax", %progbits
.align 3
.globl _trap_exit
_trap_exit:
add sp, a0, zero
TRAP_RESTORE_GENERAL_REGS_EXCEPT_SP_T0
TRAP_RESTORE_GENERAL_REGS_EXCEPT_A0_T0
TRAP_RESTORE_MEPC_MSTATUS 0
TRAP_RESTORE_SP_T0
TRAP_RESTORE_A0_T0
mret
@@ -686,6 +764,7 @@ _trap_exit:
.section .entry, "ax", %progbits
.align 3
.globl _trap_handler_rv32_hyp
.globl _trap_exit_rv32_hyp
_trap_handler_rv32_hyp:
TRAP_SAVE_AND_SETUP_SP_T0
@@ -695,25 +774,12 @@ _trap_handler_rv32_hyp:
TRAP_CALL_C_ROUTINE
TRAP_RESTORE_GENERAL_REGS_EXCEPT_SP_T0
TRAP_RESTORE_MEPC_MSTATUS 1
TRAP_RESTORE_SP_T0
mret
.section .entry, "ax", %progbits
.align 3
.globl _trap_exit_rv32_hyp
_trap_exit_rv32_hyp:
add sp, a0, zero
TRAP_RESTORE_GENERAL_REGS_EXCEPT_SP_T0
TRAP_RESTORE_GENERAL_REGS_EXCEPT_A0_T0
TRAP_RESTORE_MEPC_MSTATUS 1
TRAP_RESTORE_SP_T0
TRAP_RESTORE_A0_T0
mret
#endif

View File

@@ -8,7 +8,7 @@
*/
. = FW_TEXT_START;
/* Don't add any section between FW_TEXT_START and _fw_start */
PROVIDE(_fw_start = .);
. = ALIGN(0x1000); /* Need this to create proper sections */
@@ -61,6 +61,19 @@
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

@@ -36,7 +36,7 @@ fw_boot_hart:
bgt a0, a1, _bad_dynamic_info
/* Read boot HART id */
li a1, 0x2
li a1, FW_DYNAMIC_INFO_VERSION_2
blt a0, a1, 2f
REG_L a0, FW_DYNAMIC_INFO_BOOT_HART_OFFSET(a2)
ret
@@ -54,33 +54,25 @@ fw_boot_hart:
*/
fw_save_info:
/* Save next arg1 in 'a1' */
la a4, _dynamic_next_arg1
lla a4, _dynamic_next_arg1
REG_S a1, (a4)
/* Sanity checks */
li a4, FW_DYNAMIC_INFO_MAGIC_VALUE
REG_L a3, FW_DYNAMIC_INFO_MAGIC_OFFSET(a2)
bne a3, a4, _bad_dynamic_info
li a4, FW_DYNAMIC_INFO_VERSION_MAX
REG_L a3, FW_DYNAMIC_INFO_VERSION_OFFSET(a2)
bgt a3, a4, _bad_dynamic_info
/* Save version == 0x1 fields */
la a4, _dynamic_next_addr
lla a4, _dynamic_next_addr
REG_L a3, FW_DYNAMIC_INFO_NEXT_ADDR_OFFSET(a2)
REG_S a3, (a4)
la a4, _dynamic_next_mode
lla a4, _dynamic_next_mode
REG_L a3, FW_DYNAMIC_INFO_NEXT_MODE_OFFSET(a2)
REG_S a3, (a4)
la a4, _dynamic_options
lla a4, _dynamic_options
REG_L a3, FW_DYNAMIC_INFO_OPTIONS_OFFSET(a2)
REG_S a3, (a4)
/* Save version == 0x2 fields */
li a4, 0x2
li a4, FW_DYNAMIC_INFO_VERSION_2
REG_L a3, FW_DYNAMIC_INFO_VERSION_OFFSET(a2)
blt a3, a4, 2f
la a4, _dynamic_boot_hart
lla a4, _dynamic_boot_hart
REG_L a3, FW_DYNAMIC_INFO_BOOT_HART_OFFSET(a2)
REG_S a3, (a4)
2:
@@ -96,7 +88,7 @@ fw_save_info:
* The next arg1 should be returned in 'a0'.
*/
fw_next_arg1:
la a0, _dynamic_next_arg1
lla a0, _dynamic_next_arg1
REG_L a0, (a0)
ret
@@ -108,7 +100,7 @@ fw_next_arg1:
* The next address should be returned in 'a0'.
*/
fw_next_addr:
la a0, _dynamic_next_addr
lla a0, _dynamic_next_addr
REG_L a0, (a0)
ret
@@ -120,7 +112,7 @@ fw_next_addr:
* The next address should be returned in 'a0'
*/
fw_next_mode:
la a0, _dynamic_next_mode
lla a0, _dynamic_next_mode
REG_L a0, (a0)
ret
@@ -133,7 +125,7 @@ fw_next_mode:
* The next address should be returned in 'a0'.
*/
fw_options:
la a0, _dynamic_options
lla a0, _dynamic_options
REG_L a0, (a0)
ret

View File

@@ -59,7 +59,7 @@ fw_next_arg1:
* The next address should be returned in 'a0'.
*/
fw_next_addr:
la a0, _jump_addr
lla a0, _jump_addr
REG_L a0, (a0)
ret

View File

@@ -59,7 +59,7 @@ fw_next_arg1:
* The next address should be returned in 'a0'.
*/
fw_next_addr:
la a0, payload_bin
lla a0, payload_bin
ret
.section .entry, "ax", %progbits

View File

@@ -13,6 +13,17 @@ firmware-cflags-y +=
firmware-asflags-y +=
firmware-ldflags-y +=
ifndef FW_PIC
FW_PIC := $(OPENSBI_LD_PIE)
endif
ifeq ($(FW_PIC),y)
firmware-genflags-y += -DFW_PIC
firmware-asflags-y += -fpic
firmware-cflags-y += -fPIE -pie
firmware-ldflags-y += -Wl,--no-dynamic-linker -Wl,-pie
endif
ifdef FW_TEXT_START
firmware-genflags-y += -DFW_TEXT_START=$(FW_TEXT_START)
endif

View File

@@ -28,20 +28,20 @@
.globl _start
_start:
/* Pick one hart to run the main boot sequence */
la a3, _hart_lottery
lla a3, _hart_lottery
li a2, 1
amoadd.w a3, a2, (a3)
bnez a3, _start_hang
/* Save a0 and a1 */
la a3, _boot_a0
lla a3, _boot_a0
REG_S a0, 0(a3)
la a3, _boot_a1
lla a3, _boot_a1
REG_S a1, 0(a3)
/* Zero-out BSS */
la a4, _bss_start
la a5, _bss_end
lla a4, _bss_start
lla a5, _bss_end
_bss_zero:
REG_S zero, (a4)
add a4, a4, __SIZEOF_POINTER__
@@ -53,18 +53,18 @@ _start_warm:
csrw CSR_SIP, zero
/* Setup exception vectors */
la a3, _start_hang
lla a3, _start_hang
csrw CSR_STVEC, a3
/* Setup stack */
la a3, _payload_end
lla a3, _payload_end
li a4, 0x2000
add sp, a3, a4
/* Jump to C main */
la a3, _boot_a0
lla a3, _boot_a0
REG_L a0, 0(a3)
la a3, _boot_a1
lla a3, _boot_a1
REG_L a1, 0(a3)
call test_main

View File

@@ -9,24 +9,25 @@
#include <sbi/sbi_ecall_interface.h>
#define SBI_ECALL(__num, __a0, __a1, __a2) \
#define SBI_ECALL(__eid, __fid, __a0, __a1, __a2) \
({ \
register unsigned long a0 asm("a0") = (unsigned long)(__a0); \
register unsigned long a1 asm("a1") = (unsigned long)(__a1); \
register unsigned long a2 asm("a2") = (unsigned long)(__a2); \
register unsigned long a7 asm("a7") = (unsigned long)(__num); \
register unsigned long a6 asm("a6") = (unsigned long)(__fid); \
register unsigned long a7 asm("a7") = (unsigned long)(__eid); \
asm volatile("ecall" \
: "+r"(a0) \
: "r"(a1), "r"(a2), "r"(a7) \
: "r"(a1), "r"(a2), "r"(a6), "r"(a7) \
: "memory"); \
a0; \
})
#define SBI_ECALL_0(__num) SBI_ECALL(__num, 0, 0, 0)
#define SBI_ECALL_1(__num, __a0) SBI_ECALL(__num, __a0, 0, 0)
#define SBI_ECALL_2(__num, __a0, __a1) SBI_ECALL(__num, __a0, __a1, 0)
#define SBI_ECALL_0(__eid, __fid) SBI_ECALL(__eid, __fid, 0, 0, 0)
#define SBI_ECALL_1(__eid, __fid, __a0) SBI_ECALL(__eid, __fid, __a0, 0, 0)
#define SBI_ECALL_2(__eid, __fid, __a0, __a1) SBI_ECALL(__eid, __fid, __a0, __a1, 0)
#define sbi_ecall_console_putc(c) SBI_ECALL_1(SBI_EXT_0_1_CONSOLE_PUTCHAR, (c))
#define sbi_ecall_console_putc(c) SBI_ECALL_1(SBI_EXT_0_1_CONSOLE_PUTCHAR, 0, (c))
static inline void sbi_ecall_console_puts(const char *str)
{

View File

@@ -15,23 +15,24 @@
/* clang-format off */
/** Offset of magic member in fw_dynamic_info */
#define FW_DYNAMIC_INFO_MAGIC_OFFSET (0 * __SIZEOF_POINTER__)
#define FW_DYNAMIC_INFO_MAGIC_OFFSET (0 * __SIZEOF_LONG__)
/** Offset of version member in fw_dynamic_info */
#define FW_DYNAMIC_INFO_VERSION_OFFSET (1 * __SIZEOF_POINTER__)
#define FW_DYNAMIC_INFO_VERSION_OFFSET (1 * __SIZEOF_LONG__)
/** Offset of next_addr member in fw_dynamic_info (version >= 1) */
#define FW_DYNAMIC_INFO_NEXT_ADDR_OFFSET (2 * __SIZEOF_POINTER__)
#define FW_DYNAMIC_INFO_NEXT_ADDR_OFFSET (2 * __SIZEOF_LONG__)
/** Offset of next_mode member in fw_dynamic_info (version >= 1) */
#define FW_DYNAMIC_INFO_NEXT_MODE_OFFSET (3 * __SIZEOF_POINTER__)
#define FW_DYNAMIC_INFO_NEXT_MODE_OFFSET (3 * __SIZEOF_LONG__)
/** Offset of options member in fw_dynamic_info (version >= 1) */
#define FW_DYNAMIC_INFO_OPTIONS_OFFSET (4 * __SIZEOF_POINTER__)
#define FW_DYNAMIC_INFO_OPTIONS_OFFSET (4 * __SIZEOF_LONG__)
/** Offset of boot_hart member in fw_dynamic_info (version >= 2) */
#define FW_DYNAMIC_INFO_BOOT_HART_OFFSET (5 * __SIZEOF_POINTER__)
#define FW_DYNAMIC_INFO_BOOT_HART_OFFSET (5 * __SIZEOF_LONG__)
/** Expected value of info magic ('OSBI' ascii string in hex) */
#define FW_DYNAMIC_INFO_MAGIC_VALUE 0x4942534f
/** Maximum supported info version */
#define FW_DYNAMIC_INFO_VERSION_MAX 0x2
#define FW_DYNAMIC_INFO_VERSION_2 0x2
#define FW_DYNAMIC_INFO_VERSION_MAX FW_DYNAMIC_INFO_VERSION_2
/** Possible next mode values */
#define FW_DYNAMIC_INFO_NEXT_MODE_U 0x0
@@ -40,7 +41,7 @@
/* clang-format on */
#ifndef __ASSEMBLY__
#ifndef __ASSEMBLER__
#include <sbi/sbi_types.h>
@@ -74,6 +75,41 @@ struct fw_dynamic_info {
unsigned long boot_hart;
} __packed;
/**
* Prevent modification of struct fw_dynamic_info from affecting
* FW_DYNAMIC_INFO_xxx_OFFSET
*/
_Static_assert(
offsetof(struct fw_dynamic_info, magic)
== FW_DYNAMIC_INFO_MAGIC_OFFSET,
"struct fw_dynamic_info definition has changed, please redefine "
"FW_DYNAMIC_INFO_MAGIC_OFFSET");
_Static_assert(
offsetof(struct fw_dynamic_info, version)
== FW_DYNAMIC_INFO_VERSION_OFFSET,
"struct fw_dynamic_info definition has changed, please redefine "
"FW_DYNAMIC_INFO_VERSION_OFFSET");
_Static_assert(
offsetof(struct fw_dynamic_info, next_addr)
== FW_DYNAMIC_INFO_NEXT_ADDR_OFFSET,
"struct fw_dynamic_info definition has changed, please redefine "
"FW_DYNAMIC_INFO_NEXT_ADDR_OFFSET");
_Static_assert(
offsetof(struct fw_dynamic_info, next_mode)
== FW_DYNAMIC_INFO_NEXT_MODE_OFFSET,
"struct fw_dynamic_info definition has changed, please redefine "
"FW_DYNAMIC_INFO_NEXT_MODE_OFFSET");
_Static_assert(
offsetof(struct fw_dynamic_info, options)
== FW_DYNAMIC_INFO_OPTIONS_OFFSET,
"struct fw_dynamic_info definition has changed, please redefine "
"FW_DYNAMIC_INFO_OPTIONS_OFFSET");
_Static_assert(
offsetof(struct fw_dynamic_info, boot_hart)
== FW_DYNAMIC_INFO_BOOT_HART_OFFSET,
"struct fw_dynamic_info definition has changed, please redefine "
"FW_DYNAMIC_INFO_BOOT_HART_OFFSET");
#endif
#endif

View File

@@ -14,7 +14,7 @@
/* clang-format off */
#ifdef __ASSEMBLY__
#ifdef __ASSEMBLER__
#define __ASM_STR(x) x
#else
#define __ASM_STR(x) #x
@@ -38,7 +38,7 @@
#define LGREG __REG_SEL(3, 2)
#if __SIZEOF_POINTER__ == 8
#ifdef __ASSEMBLY__
#ifdef __ASSEMBLER__
#define RISCV_PTR .dword
#define RISCV_SZPTR 8
#define RISCV_LGPTR 3
@@ -48,7 +48,7 @@
#define RISCV_LGPTR "3"
#endif
#elif __SIZEOF_POINTER__ == 4
#ifdef __ASSEMBLY__
#ifdef __ASSEMBLER__
#define RISCV_PTR .word
#define RISCV_SZPTR 4
#define RISCV_LGPTR 2
@@ -79,7 +79,7 @@
/* clang-format on */
#ifndef __ASSEMBLY__
#ifndef __ASSEMBLER__
#define csr_swap(csr, val) \
({ \
@@ -157,6 +157,11 @@ void csr_write_num(int csr_num, unsigned long val);
__asm__ __volatile__("wfi" ::: "memory"); \
} while (0)
#define ebreak() \
do { \
__asm__ __volatile__("ebreak" ::: "memory"); \
} while (0)
/* Get current HART id */
#define current_hartid() ((unsigned int)csr_read(CSR_MHARTID))
@@ -182,6 +187,6 @@ int pmp_set(unsigned int n, unsigned long prot, unsigned long addr,
int pmp_get(unsigned int n, unsigned long *prot_out, unsigned long *addr_out,
unsigned long *log2len);
#endif /* !__ASSEMBLY__ */
#endif /* !__ASSEMBLER__ */
#endif

View File

@@ -18,6 +18,9 @@
#define RISCV_FENCE(p, s) \
__asm__ __volatile__ ("fence " #p "," #s : : : "memory")
#define RISCV_FENCE_I \
__asm__ __volatile__ ("fence.i" : : : "memory")
/* Read & Write Memory barrier */
#define mb() RISCV_FENCE(iorw,iorw)

14
include/sbi/riscv_elf.h Normal file
View File

@@ -0,0 +1,14 @@
#ifndef __RISCV_ELF_H__
#define __RISCV_ELF_H__
#include <sbi/riscv_asm.h>
#define R_RISCV_32 1
#define R_RISCV_64 2
#define R_RISCV_RELATIVE 3
#define RELOC_TYPE __REG_SEL(R_RISCV_64, R_RISCV_32)
#define SYM_INDEX __REG_SEL(0x20, 0x8)
#define SYM_SIZE __REG_SEL(0x18,0x10)
#endif

View File

@@ -25,7 +25,7 @@
#define MSTATUS_MPP (_UL(3) << MSTATUS_MPP_SHIFT)
#define MSTATUS_FS _UL(0x00006000)
#define MSTATUS_XS _UL(0x00018000)
#define MSTATUS_VS _UL(0x01800000)
#define MSTATUS_VS _UL(0x00000600)
#define MSTATUS_MPRV _UL(0x00020000)
#define MSTATUS_SUM _UL(0x00040000)
#define MSTATUS_MXR _UL(0x00080000)
@@ -86,6 +86,7 @@
#define IRQ_VS_EXT 10
#define IRQ_M_EXT 11
#define IRQ_S_GEXT 12
#define IRQ_PMU_OVF 13
#define MIP_SSIP (_UL(1) << IRQ_S_SOFT)
#define MIP_VSSIP (_UL(1) << IRQ_VS_SOFT)
@@ -97,6 +98,7 @@
#define MIP_VSEIP (_UL(1) << IRQ_VS_EXT)
#define MIP_MEIP (_UL(1) << IRQ_M_EXT)
#define MIP_SGEIP (_UL(1) << IRQ_S_GEXT)
#define MIP_LCOFIP (_UL(1) << IRQ_PMU_OVF)
#define SIP_SSIP MIP_SSIP
#define SIP_STIP MIP_STIP
@@ -171,6 +173,52 @@
#define HGATP_MODE_SHIFT HGATP32_MODE_SHIFT
#endif
#define TOPI_IID_SHIFT 16
#define TOPI_IID_MASK 0xfff
#define TOPI_IPRIO_MASK 0xff
#if __riscv_xlen == 64
#define MHPMEVENT_OF (_UL(1) << 63)
#define MHPMEVENT_MINH (_UL(1) << 62)
#define MHPMEVENT_SINH (_UL(1) << 61)
#define MHPMEVENT_UINH (_UL(1) << 60)
#define MHPMEVENT_VSINH (_UL(1) << 59)
#define MHPMEVENT_VUINH (_UL(1) << 58)
#else
#define MHPMEVENTH_OF (_ULL(1) << 31)
#define MHPMEVENTH_MINH (_ULL(1) << 30)
#define MHPMEVENTH_SINH (_ULL(1) << 29)
#define MHPMEVENTH_UINH (_ULL(1) << 28)
#define MHPMEVENTH_VSINH (_ULL(1) << 27)
#define MHPMEVENTH_VUINH (_ULL(1) << 26)
#define MHPMEVENT_OF (MHPMEVENTH_OF << 32)
#define MHPMEVENT_MINH (MHPMEVENTH_MINH << 32)
#define MHPMEVENT_SINH (MHPMEVENTH_SINH << 32)
#define MHPMEVENT_UINH (MHPMEVENTH_UINH << 32)
#define MHPMEVENT_VSINH (MHPMEVENTH_VSINH << 32)
#define MHPMEVENT_VUINH (MHPMEVENTH_VUINH << 32)
#endif
#define MHPMEVENT_SSCOF_MASK _ULL(0xFFFF000000000000)
#if __riscv_xlen > 32
#define ENVCFG_STCE (_ULL(1) << 63)
#define ENVCFG_PBMTE (_ULL(1) << 62)
#else
#define ENVCFGH_STCE (_UL(1) << 31)
#define ENVCFGH_PBMTE (_UL(1) << 30)
#endif
#define ENVCFG_CBZE (_UL(1) << 7)
#define ENVCFG_CBCFE (_UL(1) << 6)
#define ENVCFG_CBIE_SHIFT 4
#define ENVCFG_CBIE (_UL(0x3) << ENVCFG_CBIE_SHIFT)
#define ENVCFG_CBIE_ILL _UL(0x0)
#define ENVCFG_CBIE_FLUSH _UL(0x1)
#define ENVCFG_CBIE_INV _UL(0x3)
#define ENVCFG_FIOM _UL(0x1)
/* ===== User-level CSRs ===== */
/* User Trap Setup (N-extension) */
@@ -266,6 +314,9 @@
#define CSR_STVEC 0x105
#define CSR_SCOUNTEREN 0x106
/* Supervisor Configuration */
#define CSR_SENVCFG 0x10a
/* Supervisor Trap Handling */
#define CSR_SSCRATCH 0x140
#define CSR_SEPC 0x141
@@ -273,9 +324,31 @@
#define CSR_STVAL 0x143
#define CSR_SIP 0x144
/* Sstc extension */
#define CSR_STIMECMP 0x14D
#define CSR_STIMECMPH 0x15D
/* Supervisor Protection and Translation */
#define CSR_SATP 0x180
/* Supervisor-Level Window to Indirectly Accessed Registers (AIA) */
#define CSR_SISELECT 0x150
#define CSR_SIREG 0x151
/* Supervisor-Level Interrupts (AIA) */
#define CSR_STOPEI 0x15c
#define CSR_STOPI 0xdb0
/* Supervisor-Level High-Half CSRs (AIA) */
#define CSR_SIEH 0x114
#define CSR_SIPH 0x154
/* Supervisor stateen CSRs */
#define CSR_SSTATEEN0 0x10C
#define CSR_SSTATEEN1 0x10D
#define CSR_SSTATEEN2 0x10E
#define CSR_SSTATEEN3 0x10F
/* ===== Hypervisor-level CSRs ===== */
/* Hypervisor Trap Setup (H-extension) */
@@ -286,6 +359,10 @@
#define CSR_HCOUNTEREN 0x606
#define CSR_HGEIE 0x607
/* Hypervisor Configuration */
#define CSR_HENVCFG 0x60a
#define CSR_HENVCFGH 0x61a
/* Hypervisor Trap Handling (H-extension) */
#define CSR_HTVAL 0x643
#define CSR_HIP 0x644
@@ -311,6 +388,39 @@
#define CSR_VSIP 0x244
#define CSR_VSATP 0x280
/* Virtual Interrupts and Interrupt Priorities (H-extension with AIA) */
#define CSR_HVIEN 0x608
#define CSR_HVICTL 0x609
#define CSR_HVIPRIO1 0x646
#define CSR_HVIPRIO2 0x647
/* VS-Level Window to Indirectly Accessed Registers (H-extension with AIA) */
#define CSR_VSISELECT 0x250
#define CSR_VSIREG 0x251
/* VS-Level Interrupts (H-extension with AIA) */
#define CSR_VSTOPEI 0x25c
#define CSR_VSTOPI 0xeb0
/* Hypervisor and VS-Level High-Half CSRs (H-extension with AIA) */
#define CSR_HIDELEGH 0x613
#define CSR_HVIENH 0x618
#define CSR_HVIPH 0x655
#define CSR_HVIPRIO1H 0x656
#define CSR_HVIPRIO2H 0x657
#define CSR_VSIEH 0x214
#define CSR_VSIPH 0x254
/* Hypervisor stateen CSRs */
#define CSR_HSTATEEN0 0x60C
#define CSR_HSTATEEN0H 0x61C
#define CSR_HSTATEEN1 0x60D
#define CSR_HSTATEEN1H 0x61D
#define CSR_HSTATEEN2 0x60E
#define CSR_HSTATEEN2H 0x61E
#define CSR_HSTATEEN3 0x60F
#define CSR_HSTATEEN3H 0x61F
/* ===== Machine-level CSRs ===== */
/* Machine Information Registers */
@@ -329,6 +439,10 @@
#define CSR_MCOUNTEREN 0x306
#define CSR_MSTATUSH 0x310
/* Machine Configuration */
#define CSR_MENVCFG 0x30a
#define CSR_MENVCFGH 0x31a
/* Machine Trap Handling */
#define CSR_MSCRATCH 0x340
#define CSR_MEPC 0x341
@@ -516,6 +630,40 @@
#define CSR_MHPMEVENT30 0x33e
#define CSR_MHPMEVENT31 0x33f
/* For RV32 */
#define CSR_MHPMEVENT3H 0x723
#define CSR_MHPMEVENT4H 0x724
#define CSR_MHPMEVENT5H 0x725
#define CSR_MHPMEVENT6H 0x726
#define CSR_MHPMEVENT7H 0x727
#define CSR_MHPMEVENT8H 0x728
#define CSR_MHPMEVENT9H 0x729
#define CSR_MHPMEVENT10H 0x72a
#define CSR_MHPMEVENT11H 0x72b
#define CSR_MHPMEVENT12H 0x72c
#define CSR_MHPMEVENT13H 0x72d
#define CSR_MHPMEVENT14H 0x72e
#define CSR_MHPMEVENT15H 0x72f
#define CSR_MHPMEVENT16H 0x730
#define CSR_MHPMEVENT17H 0x731
#define CSR_MHPMEVENT18H 0x732
#define CSR_MHPMEVENT19H 0x733
#define CSR_MHPMEVENT20H 0x734
#define CSR_MHPMEVENT21H 0x735
#define CSR_MHPMEVENT22H 0x736
#define CSR_MHPMEVENT23H 0x737
#define CSR_MHPMEVENT24H 0x738
#define CSR_MHPMEVENT25H 0x739
#define CSR_MHPMEVENT26H 0x73a
#define CSR_MHPMEVENT27H 0x73b
#define CSR_MHPMEVENT28H 0x73c
#define CSR_MHPMEVENT29H 0x73d
#define CSR_MHPMEVENT30H 0x73e
#define CSR_MHPMEVENT31H 0x73f
/* Counter Overflow CSR */
#define CSR_SCOUNTOVF 0xda0
/* Debug/Trace Registers */
#define CSR_TSELECT 0x7a0
#define CSR_TDATA1 0x7a1
@@ -528,6 +676,36 @@
#define CSR_DSCRATCH0 0x7b2
#define CSR_DSCRATCH1 0x7b3
/* Machine-Level Window to Indirectly Accessed Registers (AIA) */
#define CSR_MISELECT 0x350
#define CSR_MIREG 0x351
/* Machine-Level Interrupts (AIA) */
#define CSR_MTOPEI 0x35c
#define CSR_MTOPI 0xfb0
/* Virtual Interrupts for Supervisor Level (AIA) */
#define CSR_MVIEN 0x308
#define CSR_MVIP 0x309
/* Smstateen extension registers */
/* Machine stateen CSRs */
#define CSR_MSTATEEN0 0x30C
#define CSR_MSTATEEN0H 0x31C
#define CSR_MSTATEEN1 0x30D
#define CSR_MSTATEEN1H 0x31D
#define CSR_MSTATEEN2 0x30E
#define CSR_MSTATEEN2H 0x31E
#define CSR_MSTATEEN3 0x30F
#define CSR_MSTATEEN3H 0x31F
/* Machine-Level High-Half CSRs (AIA) */
#define CSR_MIDELEGH 0x313
#define CSR_MIEH 0x314
#define CSR_MVIENH 0x318
#define CSR_MVIPH 0x319
#define CSR_MIPH 0x354
/* ===== Trap/Exception Causes ===== */
#define CAUSE_MISALIGNED_FETCH 0x0
@@ -550,6 +728,23 @@
#define CAUSE_VIRTUAL_INST_FAULT 0x16
#define CAUSE_STORE_GUEST_PAGE_FAULT 0x17
/* Common defines for all smstateen */
#define SMSTATEEN_MAX_COUNT 4
#define SMSTATEEN0_CS_SHIFT 0
#define SMSTATEEN0_CS (_ULL(1) << SMSTATEEN0_CS_SHIFT)
#define SMSTATEEN0_FCSR_SHIFT 1
#define SMSTATEEN0_FCSR (_ULL(1) << SMSTATEEN0_FCSR_SHIFT)
#define SMSTATEEN0_IMSIC_SHIFT 58
#define SMSTATEEN0_IMSIC (_ULL(1) << SMSTATEEN0_IMSIC_SHIFT)
#define SMSTATEEN0_AIA_SHIFT 59
#define SMSTATEEN0_AIA (_ULL(1) << SMSTATEEN0_AIA_SHIFT)
#define SMSTATEEN0_SVSLCT_SHIFT 60
#define SMSTATEEN0_SVSLCT (_ULL(1) << SMSTATEEN0_SVSLCT_SHIFT)
#define SMSTATEEN0_HSENVCFG_SHIFT 62
#define SMSTATEEN0_HSENVCFG (_ULL(1) << SMSTATEEN0_HSENVCFG_SHIFT)
#define SMSTATEEN_STATEN_SHIFT 63
#define SMSTATEEN_STATEN (_ULL(1) << SMSTATEEN_STATEN_SHIFT)
/* ===== Instruction Encodings ===== */
#define INSN_MATCH_LB 0x3
@@ -625,6 +820,29 @@
#define INSN_MASK_WFI 0xffffff00
#define INSN_MATCH_WFI 0x10500000
#define INSN_MASK_FENCE_TSO 0xffffffff
#define INSN_MATCH_FENCE_TSO 0x8330000f
#if __riscv_xlen == 64
/* 64-bit read for VS-stage address translation (RV64) */
#define INSN_PSEUDO_VS_LOAD 0x00003000
/* 64-bit write for VS-stage address translation (RV64) */
#define INSN_PSEUDO_VS_STORE 0x00003020
#elif __riscv_xlen == 32
/* 32-bit read for VS-stage address translation (RV32) */
#define INSN_PSEUDO_VS_LOAD 0x00002000
/* 32-bit write for VS-stage address translation (RV32) */
#define INSN_PSEUDO_VS_STORE 0x00002020
#else
#error "Unexpected __riscv_xlen"
#endif
#define INSN_16BIT_MASK 0x3
#define INSN_32BIT_MASK 0x1c

View File

@@ -42,15 +42,28 @@
: "t0"); \
})
#define init_fp_reg(i) SET_F32_REG((i) << 3, 3, 0, 0)
#if __riscv_xlen == 64
#define GET_F64_REG(insn, pos, regs) \
({ \
register ulong value asm("a0") = \
SHIFT_RIGHT(insn, (pos)-3) & 0xf8; \
register ulong value asm("a0") = SHIFT_RIGHT(insn, (pos)-3) & 0xf8; \
ulong tmp; \
asm("1: auipc %0, %%pcrel_hi(get_f64_reg); add %0, %0, %1; jalr t0, %0, %%pcrel_lo(1b)" \
: "=&r"(tmp), "+&r"(value)::"t0"); \
sizeof(ulong) == 4 ? *(int64_t *)value : (int64_t)value; \
value; \
})
#else
#define GET_F64_REG(insn, pos, regs) \
({ \
u64 value; \
ulong offset = SHIFT_RIGHT(insn, (pos)-3) & 0xf8; \
register ulong ptr asm("a0") = (ulong)&value; \
asm ("1: auipc t1, %%pcrel_hi(get_f64_reg); add t1, t1, %2; jalr t0, t1, %%pcrel_lo(1b)" \
: "=m"(value) : "r"(ptr), "r"(offset) : "t0", "t1"); \
value; \
})
#endif
#define SET_F64_REG(insn, pos, regs, val) \
({ \
uint64_t __val = (val); \

View File

@@ -2,30 +2,41 @@
* SPDX-License-Identifier: BSD-2-Clause
*
* Copyright (c) 2019 Western Digital Corporation or its affiliates.
*
* Authors:
* Anup Patel <anup.patel@wdc.com>
* Copyright (c) 2021 Christoph Müllner <cmuellner@linux.com>
*/
#ifndef __RISCV_LOCKS_H__
#define __RISCV_LOCKS_H__
#include <sbi/sbi_types.h>
#define TICKET_SHIFT 16
typedef struct {
volatile long lock;
} spinlock_t;
#if __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__
u16 next;
u16 owner;
#else
u16 owner;
u16 next;
#endif
} __aligned(4) spinlock_t;
#define __RISCV_SPIN_UNLOCKED 0
#define __SPIN_LOCK_UNLOCKED \
(spinlock_t) { 0, 0 }
#define SPIN_LOCK_INIT(_lptr) (_lptr)->lock = __RISCV_SPIN_UNLOCKED
#define SPIN_LOCK_INIT(x) \
x = __SPIN_LOCK_UNLOCKED
#define SPIN_LOCK_INITIALIZER \
{ \
.lock = __RISCV_SPIN_UNLOCKED, \
}
__SPIN_LOCK_UNLOCKED
int spin_lock_check(spinlock_t *lock);
#define DEFINE_SPIN_LOCK(x) \
spinlock_t SPIN_LOCK_INIT(x)
int spin_trylock(spinlock_t *lock);
bool spin_lock_check(spinlock_t *lock);
bool spin_trylock(spinlock_t *lock);
void spin_lock(spinlock_t *lock);

View File

@@ -37,47 +37,12 @@
(((~0UL) - (1UL << (l)) + 1) & (~0UL >> (BITS_PER_LONG - 1 - (h))))
/**
* ffs - Find first bit set
* @x: the word to search
*
* This is defined the same way as
* the libc and compiler builtin ffs routines, therefore
* differs in spirit from the above ffz (man ffs).
*/
static inline int ffs(int x)
{
int r = 1;
if (!x)
return 0;
if (!(x & 0xffff)) {
x >>= 16;
r += 16;
}
if (!(x & 0xff)) {
x >>= 8;
r += 8;
}
if (!(x & 0xf)) {
x >>= 4;
r += 4;
}
if (!(x & 3)) {
x >>= 2;
r += 2;
}
if (!(x & 1))
r += 1;
return r;
}
/**
* __ffs - find first bit in word.
* sbi_ffs - find first (less-significant) set bit in a long word.
* @word: The word to search
*
* Undefined if no bit exists, so code should check against 0 first.
*/
static inline int __ffs(unsigned long word)
static inline int sbi_ffs(unsigned long word)
{
int num = 0;
@@ -109,55 +74,20 @@ static inline int __ffs(unsigned long word)
}
/*
* ffz - find first zero in word.
* sbi_ffz - find first zero in word.
* @word: The word to search
*
* Undefined if no zero exists, so code should check against ~0UL first.
*/
#define ffz(x) __ffs(~(x))
#define sbi_ffz(x) sbi_ffs(~(x))
/**
* fls - find last (most-significant) bit set
* @x: the word to search
*
* This is defined the same way as ffs.
* Note fls(0) = 0, fls(1) = 1, fls(0x80000000) = 32.
*/
static inline int fls(int x)
{
int r = 32;
if (!x)
return 0;
if (!(x & 0xffff0000u)) {
x <<= 16;
r -= 16;
}
if (!(x & 0xff000000u)) {
x <<= 8;
r -= 8;
}
if (!(x & 0xf0000000u)) {
x <<= 4;
r -= 4;
}
if (!(x & 0xc0000000u)) {
x <<= 2;
r -= 2;
}
if (!(x & 0x80000000u))
r -= 1;
return r;
}
/**
* __fls - find last (most-significant) set bit in a long word
* sbi_fls - find last (most-significant) set bit in a long word
* @word: the word to search
*
* Undefined if no set bit exists, so code should check against 0 first.
*/
static inline unsigned long __fls(unsigned long word)
static inline unsigned long sbi_fls(unsigned long word)
{
int num = BITS_PER_LONG - 1;

View File

@@ -12,6 +12,17 @@
#include <sbi/sbi_types.h>
struct sbi_console_device {
/** Name of the console device */
char name[32];
/** Write a character to the console output */
void (*console_putc)(char ch);
/** Read a character from the console input */
int (*console_getc)(void);
};
#define __printf(a, b) __attribute__((format(printf, a, b)))
bool sbi_isprintable(char ch);
@@ -32,8 +43,19 @@ int __printf(1, 2) sbi_printf(const char *format, ...);
int __printf(1, 2) sbi_dprintf(const char *format, ...);
void __printf(1, 2) __attribute__((noreturn)) sbi_panic(const char *format, ...);
const struct sbi_console_device *sbi_console_get_device(void);
void sbi_console_set_device(const struct sbi_console_device *dev);
struct sbi_scratch;
int sbi_console_init(struct sbi_scratch *scratch);
#define SBI_ASSERT(cond, args) do { \
if (unlikely(!(cond))) \
sbi_panic args; \
} while (0)
#endif

View File

@@ -22,7 +22,7 @@
/* clang-format off */
#ifdef __ASSEMBLY__
#ifdef __ASSEMBLER__
#define _AC(X,Y) X
#define _AT(T,X) X
#else

View File

@@ -12,6 +12,7 @@
#include <sbi/riscv_encoding.h>
#include <sbi/sbi_hart.h>
#include <sbi/sbi_trap.h>
#define csr_read_allowed(csr_num, trap) \
({ \
@@ -19,6 +20,7 @@
register ulong ttmp asm("a4"); \
register ulong mtvec = sbi_hart_expected_trap_addr(); \
register ulong ret = 0; \
((struct sbi_trap_info *)(trap))->cause = 0; \
asm volatile( \
"add %[ttmp], %[tinfo], zero\n" \
"csrrw %[mtvec], " STR(CSR_MTVEC) ", %[mtvec]\n" \
@@ -36,6 +38,7 @@
register ulong tinfo asm("a3") = (ulong)trap; \
register ulong ttmp asm("a4"); \
register ulong mtvec = sbi_hart_expected_trap_addr(); \
((struct sbi_trap_info *)(trap))->cause = 0; \
asm volatile( \
"add %[ttmp], %[tinfo], zero\n" \
"csrrw %[mtvec], " STR(CSR_MTVEC) ", %[mtvec]\n" \

View File

@@ -80,6 +80,9 @@ struct sbi_domain {
bool system_reset_allowed;
};
/** The root domain instance */
extern struct sbi_domain root;
/** HART id to domain table */
extern struct sbi_domain *hartid_to_domain_table[];
@@ -124,8 +127,19 @@ bool sbi_domain_is_assigned_hart(const struct sbi_domain *dom, u32 hartid);
ulong sbi_domain_get_assigned_hartmask(const struct sbi_domain *dom,
ulong hbase);
/** Initialize a domain memory region as firmware region */
void sbi_domain_memregion_initfw(struct sbi_domain_memregion *reg);
/**
* Initialize a domain memory region based on it's physical
* address and size.
*
* @param addr start physical address of memory region
* @param size physical size of memory region
* @param flags memory region flags
* @param reg pointer to memory region being initialized
*/
void sbi_domain_memregion_init(unsigned long addr,
unsigned long size,
unsigned long flags,
struct sbi_domain_memregion *reg);
/**
* Check whether we can access specified address for given mode and
@@ -156,6 +170,16 @@ void sbi_domain_dump_all(const char *suffix);
int sbi_domain_register(struct sbi_domain *dom,
const struct sbi_hartmask *assign_mask);
/**
* Add a memory region to the root domain
* @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_EINVAL otherwise
*/
int sbi_domain_root_add_memregion(const struct sbi_domain_memregion *reg);
/** Finalize domain tables and startup non-root domains */
int sbi_domain_finalize(struct sbi_scratch *scratch, u32 cold_hartid);

View File

@@ -13,8 +13,8 @@
#include <sbi/sbi_types.h>
#include <sbi/sbi_list.h>
#define SBI_ECALL_VERSION_MAJOR 0
#define SBI_ECALL_VERSION_MINOR 2
#define SBI_ECALL_VERSION_MAJOR 1
#define SBI_ECALL_VERSION_MINOR 0
#define SBI_OPENSBI_IMPID 1
struct sbi_trap_regs;
@@ -39,6 +39,7 @@ 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);

View File

@@ -28,6 +28,7 @@
#define SBI_EXT_RFENCE 0x52464E43
#define SBI_EXT_HSM 0x48534D
#define SBI_EXT_SRST 0x53525354
#define SBI_EXT_PMU 0x504D55
/* SBI function IDs for BASE extension*/
#define SBI_EXT_BASE_GET_SPEC_VERSION 0x0
@@ -48,20 +49,37 @@
#define SBI_EXT_RFENCE_REMOTE_FENCE_I 0x0
#define SBI_EXT_RFENCE_REMOTE_SFENCE_VMA 0x1
#define SBI_EXT_RFENCE_REMOTE_SFENCE_VMA_ASID 0x2
#define SBI_EXT_RFENCE_REMOTE_HFENCE_GVMA 0x3
#define SBI_EXT_RFENCE_REMOTE_HFENCE_GVMA_VMID 0x4
#define SBI_EXT_RFENCE_REMOTE_HFENCE_VVMA 0x5
#define SBI_EXT_RFENCE_REMOTE_HFENCE_VVMA_ASID 0x6
#define SBI_EXT_RFENCE_REMOTE_HFENCE_GVMA_VMID 0x3
#define SBI_EXT_RFENCE_REMOTE_HFENCE_GVMA 0x4
#define SBI_EXT_RFENCE_REMOTE_HFENCE_VVMA_ASID 0x5
#define SBI_EXT_RFENCE_REMOTE_HFENCE_VVMA 0x6
/* SBI function IDs for HSM extension */
#define SBI_EXT_HSM_HART_START 0x0
#define SBI_EXT_HSM_HART_STOP 0x1
#define SBI_EXT_HSM_HART_GET_STATUS 0x2
#define SBI_EXT_HSM_HART_SUSPEND 0x3
#define SBI_HSM_HART_STATUS_STARTED 0x0
#define SBI_HSM_HART_STATUS_STOPPED 0x1
#define SBI_HSM_HART_STATUS_START_PENDING 0x2
#define SBI_HSM_HART_STATUS_STOP_PENDING 0x3
#define SBI_HSM_STATE_STARTED 0x0
#define SBI_HSM_STATE_STOPPED 0x1
#define SBI_HSM_STATE_START_PENDING 0x2
#define SBI_HSM_STATE_STOP_PENDING 0x3
#define SBI_HSM_STATE_SUSPENDED 0x4
#define SBI_HSM_STATE_SUSPEND_PENDING 0x5
#define SBI_HSM_STATE_RESUME_PENDING 0x6
#define SBI_HSM_SUSP_BASE_MASK 0x7fffffff
#define SBI_HSM_SUSP_NON_RET_BIT 0x80000000
#define SBI_HSM_SUSP_PLAT_BASE 0x10000000
#define SBI_HSM_SUSPEND_RET_DEFAULT 0x00000000
#define SBI_HSM_SUSPEND_RET_PLATFORM SBI_HSM_SUSP_PLAT_BASE
#define SBI_HSM_SUSPEND_RET_LAST SBI_HSM_SUSP_BASE_MASK
#define SBI_HSM_SUSPEND_NON_RET_DEFAULT SBI_HSM_SUSP_NON_RET_BIT
#define SBI_HSM_SUSPEND_NON_RET_PLATFORM (SBI_HSM_SUSP_NON_RET_BIT | \
SBI_HSM_SUSP_PLAT_BASE)
#define SBI_HSM_SUSPEND_NON_RET_LAST (SBI_HSM_SUSP_NON_RET_BIT | \
SBI_HSM_SUSP_BASE_MASK)
/* SBI function IDs for SRST extension */
#define SBI_EXT_SRST_RESET 0x0
@@ -74,6 +92,139 @@
#define SBI_SRST_RESET_REASON_NONE 0x0
#define SBI_SRST_RESET_REASON_SYSFAIL 0x1
/* SBI function IDs for PMU extension */
#define SBI_EXT_PMU_NUM_COUNTERS 0x0
#define SBI_EXT_PMU_COUNTER_GET_INFO 0x1
#define SBI_EXT_PMU_COUNTER_CFG_MATCH 0x2
#define SBI_EXT_PMU_COUNTER_START 0x3
#define SBI_EXT_PMU_COUNTER_STOP 0x4
#define SBI_EXT_PMU_COUNTER_FW_READ 0x5
/** General pmu event codes specified in SBI PMU extension */
enum sbi_pmu_hw_generic_events_t {
SBI_PMU_HW_NO_EVENT = 0,
SBI_PMU_HW_CPU_CYCLES = 1,
SBI_PMU_HW_INSTRUCTIONS = 2,
SBI_PMU_HW_CACHE_REFERENCES = 3,
SBI_PMU_HW_CACHE_MISSES = 4,
SBI_PMU_HW_BRANCH_INSTRUCTIONS = 5,
SBI_PMU_HW_BRANCH_MISSES = 6,
SBI_PMU_HW_BUS_CYCLES = 7,
SBI_PMU_HW_STALLED_CYCLES_FRONTEND = 8,
SBI_PMU_HW_STALLED_CYCLES_BACKEND = 9,
SBI_PMU_HW_REF_CPU_CYCLES = 10,
SBI_PMU_HW_GENERAL_MAX,
};
/**
* Generalized hardware cache events:
*
* { L1-D, L1-I, LLC, ITLB, DTLB, BPU, NODE } x
* { read, write, prefetch } x
* { accesses, misses }
*/
enum sbi_pmu_hw_cache_id {
SBI_PMU_HW_CACHE_L1D = 0,
SBI_PMU_HW_CACHE_L1I = 1,
SBI_PMU_HW_CACHE_LL = 2,
SBI_PMU_HW_CACHE_DTLB = 3,
SBI_PMU_HW_CACHE_ITLB = 4,
SBI_PMU_HW_CACHE_BPU = 5,
SBI_PMU_HW_CACHE_NODE = 6,
SBI_PMU_HW_CACHE_MAX,
};
enum sbi_pmu_hw_cache_op_id {
SBI_PMU_HW_CACHE_OP_READ = 0,
SBI_PMU_HW_CACHE_OP_WRITE = 1,
SBI_PMU_HW_CACHE_OP_PREFETCH = 2,
SBI_PMU_HW_CACHE_OP_MAX,
};
enum sbi_pmu_hw_cache_op_result_id {
SBI_PMU_HW_CACHE_RESULT_ACCESS = 0,
SBI_PMU_HW_CACHE_RESULT_MISS = 1,
SBI_PMU_HW_CACHE_RESULT_MAX,
};
/**
* Special "firmware" events provided by the OpenSBI, even if the hardware
* does not support performance events. These events are encoded as a raw
* event type in Linux kernel perf framework.
*/
enum sbi_pmu_fw_event_code_id {
SBI_PMU_FW_MISALIGNED_LOAD = 0,
SBI_PMU_FW_MISALIGNED_STORE = 1,
SBI_PMU_FW_ACCESS_LOAD = 2,
SBI_PMU_FW_ACCESS_STORE = 3,
SBI_PMU_FW_ILLEGAL_INSN = 4,
SBI_PMU_FW_SET_TIMER = 5,
SBI_PMU_FW_IPI_SENT = 6,
SBI_PMU_FW_IPI_RECVD = 7,
SBI_PMU_FW_FENCE_I_SENT = 8,
SBI_PMU_FW_FENCE_I_RECVD = 9,
SBI_PMU_FW_SFENCE_VMA_SENT = 10,
SBI_PMU_FW_SFENCE_VMA_RCVD = 11,
SBI_PMU_FW_SFENCE_VMA_ASID_SENT = 12,
SBI_PMU_FW_SFENCE_VMA_ASID_RCVD = 13,
SBI_PMU_FW_HFENCE_GVMA_SENT = 14,
SBI_PMU_FW_HFENCE_GVMA_RCVD = 15,
SBI_PMU_FW_HFENCE_GVMA_VMID_SENT = 16,
SBI_PMU_FW_HFENCE_GVMA_VMID_RCVD = 17,
SBI_PMU_FW_HFENCE_VVMA_SENT = 18,
SBI_PMU_FW_HFENCE_VVMA_RCVD = 19,
SBI_PMU_FW_HFENCE_VVMA_ASID_SENT = 20,
SBI_PMU_FW_HFENCE_VVMA_ASID_RCVD = 21,
SBI_PMU_FW_MAX,
};
/** SBI PMU event idx type */
enum sbi_pmu_event_type_id {
SBI_PMU_EVENT_TYPE_HW = 0x0,
SBI_PMU_EVENT_TYPE_HW_CACHE = 0x1,
SBI_PMU_EVENT_TYPE_HW_RAW = 0x2,
SBI_PMU_EVENT_TYPE_FW = 0xf,
SBI_PMU_EVENT_TYPE_MAX,
};
/** SBI PMU counter type */
enum sbi_pmu_ctr_type {
SBI_PMU_CTR_TYPE_HW = 0,
SBI_PMU_CTR_TYPE_FW,
};
/* 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_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
/* Flags defined for config matching function */
#define SBI_PMU_CFG_FLAG_SKIP_MATCH (1 << 0)
#define SBI_PMU_CFG_FLAG_CLEAR_VALUE (1 << 1)
#define SBI_PMU_CFG_FLAG_AUTO_START (1 << 2)
#define SBI_PMU_CFG_FLAG_SET_VUINH (1 << 3)
#define SBI_PMU_CFG_FLAG_SET_VSINH (1 << 4)
#define SBI_PMU_CFG_FLAG_SET_UINH (1 << 5)
#define SBI_PMU_CFG_FLAG_SET_SINH (1 << 6)
#define SBI_PMU_CFG_FLAG_SET_MINH (1 << 7)
/* Flags defined for counter start function */
#define SBI_PMU_START_FLAG_SET_INIT_VALUE (1 << 0)
/* Flags defined for counter stop function */
#define SBI_PMU_STOP_FLAG_RESET (1 << 0)
/* SBI base specification related macros */
#define SBI_SPEC_VERSION_MAJOR_OFFSET 24
#define SBI_SPEC_VERSION_MAJOR_MASK 0x7f
#define SBI_SPEC_VERSION_MINOR_MASK 0xffffff
@@ -90,8 +241,10 @@
#define SBI_ERR_DENIED -4
#define SBI_ERR_INVALID_ADDRESS -5
#define SBI_ERR_ALREADY_AVAILABLE -6
#define SBI_ERR_ALREADY_STARTED -7
#define SBI_ERR_ALREADY_STOPPED -8
#define SBI_LAST_ERR SBI_ERR_ALREADY_AVAILABLE
#define SBI_LAST_ERR SBI_ERR_ALREADY_STOPPED
/* clang-format on */

View File

@@ -21,6 +21,8 @@
#define SBI_EDENIED SBI_ERR_DENIED
#define SBI_EINVALID_ADDR SBI_ERR_INVALID_ADDRESS
#define SBI_EALREADY SBI_ERR_ALREADY_AVAILABLE
#define SBI_EALREADY_STARTED SBI_ERR_ALREADY_STARTED
#define SBI_EALREADY_STOPPED SBI_ERR_ALREADY_STOPPED
#define SBI_ENODEV -1000
#define SBI_ENOSYS -1001

View File

@@ -33,8 +33,8 @@ int sbi_fifo_dequeue(struct sbi_fifo *fifo, void *data);
int sbi_fifo_enqueue(struct sbi_fifo *fifo, void *data);
void sbi_fifo_init(struct sbi_fifo *fifo, void *queue_mem, u16 entries,
u16 entry_size);
bool sbi_fifo_is_empty(struct sbi_fifo *fifo);
bool sbi_fifo_is_full(struct sbi_fifo *fifo);
int sbi_fifo_is_empty(struct sbi_fifo *fifo);
int sbi_fifo_is_full(struct sbi_fifo *fifo);
int sbi_fifo_inplace_update(struct sbi_fifo *fifo, void *in,
int (*fptr)(void *in, void *data));
u16 sbi_fifo_avail(struct sbi_fifo *fifo);

View File

@@ -12,21 +12,38 @@
#include <sbi/sbi_types.h>
/** Possible feature flags of a hart */
enum sbi_hart_features {
/** Hart has S-mode counter enable */
SBI_HART_HAS_SCOUNTEREN = (1 << 0),
/** Hart has M-mode counter enable */
SBI_HART_HAS_MCOUNTEREN = (1 << 1),
/** HART has timer csr implementation in hardware */
SBI_HART_HAS_TIME = (1 << 2),
/** Possible privileged specification versions of a hart */
enum sbi_hart_priv_versions {
/** Unknown privileged specification */
SBI_HART_PRIV_VER_UNKNOWN = 0,
/** Privileged specification v1.10 */
SBI_HART_PRIV_VER_1_10 = 1,
/** Privileged specification v1.11 */
SBI_HART_PRIV_VER_1_11 = 2,
/** Privileged specification v1.12 */
SBI_HART_PRIV_VER_1_12 = 3,
};
/** Last index of Hart features*/
SBI_HART_HAS_LAST_FEATURE = SBI_HART_HAS_TIME,
/** Possible ISA extensions of a hart */
enum sbi_hart_extensions {
/** Hart has Sscofpmt extension */
SBI_HART_EXT_SSCOFPMF = 0,
/** HART has HW time CSR (extension name not available) */
SBI_HART_EXT_TIME,
/** HART has AIA CSRs (extension name not available) */
SBI_HART_EXT_AIA,
/** HART has Smstateen CSR **/
SBI_HART_EXT_SMSTATEEN,
/** HART has Sstc extension */
SBI_HART_EXT_SSTC,
/** Maximum index of Hart extension */
SBI_HART_EXT_MAX,
};
struct sbi_scratch;
int sbi_hart_reinit(struct sbi_scratch *scratch);
int sbi_hart_init(struct sbi_scratch *scratch, bool cold_boot);
extern void (*sbi_hart_expected_trap)(void);
@@ -41,10 +58,18 @@ void sbi_hart_delegation_dump(struct sbi_scratch *scratch,
unsigned int sbi_hart_pmp_count(struct sbi_scratch *scratch);
unsigned long sbi_hart_pmp_granularity(struct sbi_scratch *scratch);
unsigned int sbi_hart_pmp_addrbits(struct sbi_scratch *scratch);
unsigned int sbi_hart_mhpm_bits(struct sbi_scratch *scratch);
int sbi_hart_pmp_configure(struct sbi_scratch *scratch);
bool sbi_hart_has_feature(struct sbi_scratch *scratch, unsigned long feature);
void sbi_hart_get_features_str(struct sbi_scratch *scratch,
char *features_str, int nfstr);
int sbi_hart_priv_version(struct sbi_scratch *scratch);
void sbi_hart_get_priv_version_str(struct sbi_scratch *scratch,
char *version_str, int nvstr);
void sbi_hart_update_extension(struct sbi_scratch *scratch,
enum sbi_hart_extensions ext,
bool enable);
bool sbi_hart_has_extension(struct sbi_scratch *scratch,
enum sbi_hart_extensions ext);
void sbi_hart_get_extensions_str(struct sbi_scratch *scratch,
char *extension_str, int nestr);
void __attribute__((noreturn)) sbi_hart_hang(void);

View File

@@ -12,13 +12,14 @@
#define __SBI_FENCE_H__
/** Invalidate Stage2 TLBs for given VMID and guest physical address */
void __sbi_hfence_gvma_vmid_gpa(unsigned long gpa, unsigned long vmid);
void __sbi_hfence_gvma_vmid_gpa(unsigned long gpa_divby_4,
unsigned long vmid);
/** Invalidate Stage2 TLBs for given VMID */
void __sbi_hfence_gvma_vmid(unsigned long vmid);
/** Invalidate Stage2 TLBs for given guest physical address */
void __sbi_hfence_gvma_gpa(unsigned long gpa);
void __sbi_hfence_gvma_gpa(unsigned long gpa_divby_4);
/** Invalidate all possible Stage2 TLBs */
void __sbi_hfence_gvma_all(void);

View File

@@ -12,16 +12,48 @@
#include <sbi/sbi_types.h>
/** Hart state values **/
#define SBI_HART_STOPPED 0
#define SBI_HART_STOPPING 1
#define SBI_HART_STARTING 2
#define SBI_HART_STARTED 3
#define SBI_HART_UNKNOWN 4
/** Hart state managment device */
struct sbi_hsm_device {
/** Name of the hart state managment device */
char name[32];
/** Start (or power-up) the given hart */
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.
*/
int (*hart_stop)(void);
/**
* Put the current hart in platform specific suspend (or low-power)
* state.
*
* For successful retentive suspend, the call will return 0 when
* the hart resumes normal execution.
*
* For successful non-retentive suspend, the hart will resume from
* the warm boot entry point.
*/
int (*hart_suspend)(u32 suspend_type);
/**
* Perform platform-specific actions to resume from a suspended state.
*
* This includes restoring any platform state that was lost during
* non-retentive suspend.
*/
void (*hart_resume)(void);
};
struct sbi_domain;
struct sbi_scratch;
const struct sbi_hsm_device *sbi_hsm_get_device(void);
void sbi_hsm_set_device(const struct sbi_hsm_device *dev);
int sbi_hsm_init(struct sbi_scratch *scratch, u32 hartid, bool cold_boot);
void __noreturn sbi_hsm_exit(struct sbi_scratch *scratch);
@@ -29,9 +61,12 @@ int sbi_hsm_hart_start(struct sbi_scratch *scratch,
const struct sbi_domain *dom,
u32 hartid, ulong saddr, ulong smode, ulong priv);
int sbi_hsm_hart_stop(struct sbi_scratch *scratch, bool exitnow);
void sbi_hsm_hart_resume_start(struct sbi_scratch *scratch);
void sbi_hsm_hart_resume_finish(struct sbi_scratch *scratch);
int sbi_hsm_hart_suspend(struct sbi_scratch *scratch, u32 suspend_type,
ulong raddr, ulong rmode, ulong priv);
int sbi_hsm_hart_get_state(const struct sbi_domain *dom, u32 hartid);
int sbi_hsm_hart_state_to_status(int state);
int sbi_hsm_hart_started_mask(const struct sbi_domain *dom,
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);

View File

@@ -18,6 +18,18 @@
/* clang-format on */
/** IPI hardware device */
struct sbi_ipi_device {
/** Name of the IPI device */
char name[32];
/** Send IPI to a target HART */
void (*ipi_send)(u32 target_hart);
/** Clear IPI for a target HART */
void (*ipi_clear)(u32 target_hart);
};
struct sbi_scratch;
/** IPI event operations or callbacks */
@@ -63,6 +75,12 @@ int sbi_ipi_send_halt(ulong hmask, ulong hbase);
void sbi_ipi_process(void);
void sbi_ipi_raw_send(u32 target_hart);
const struct sbi_ipi_device *sbi_ipi_get_device(void);
void sbi_ipi_set_device(const struct sbi_ipi_device *dev);
int sbi_ipi_init(struct sbi_scratch *scratch, bool cold_boot);
void sbi_ipi_exit(struct sbi_scratch *scratch);

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

@@ -0,0 +1,44 @@
/*
* SPDX-License-Identifier: BSD-2-Clause
*
* Copyright (c) 2022 Ventana Micro Systems Inc.
*
* Authors:
* Anup Patel <apatel@ventanamicro.com>
*/
#ifndef __SBI_IRQCHIP_H__
#define __SBI_IRQCHIP_H__
#include <sbi/sbi_types.h>
struct sbi_scratch;
struct sbi_trap_regs;
/**
* Set external interrupt handling function
*
* This function is called by OpenSBI platform code to set a handler for
* external interrupts
*
* @param fn function pointer for handling external irqs
*/
void sbi_irqchip_set_irqfn(int (*fn)(struct sbi_trap_regs *regs));
/**
* Process external interrupts
*
* This function is called by sbi_trap_handler() to handle external
* interrupts.
*
* @param regs pointer for trap registers
*/
int sbi_irqchip_process(struct sbi_trap_regs *regs);
/** Initialize interrupt controllers */
int sbi_irqchip_init(struct sbi_scratch *scratch, bool cold_boot);
/** Exit interrupt controllers */
void sbi_irqchip_exit(struct sbi_scratch *scratch);
#endif

View File

@@ -43,6 +43,17 @@ static inline void __sbi_list_add(struct sbi_dlist *new,
next->prev = new;
}
/**
* Checks if the list is empty or not.
* @param head List head
*
* Retruns TRUE if list is empty, FALSE otherwise.
*/
static inline bool sbi_list_empty(struct sbi_dlist *head)
{
return head->next == head;
}
/**
* Adds the new node after the given head.
* @param new New node that needs to be added to list.

View File

@@ -38,7 +38,7 @@
#define SBI_PLATFORM_TLB_RANGE_FLUSH_LIMIT_DEFAULT (1UL << 12)
#ifndef __ASSEMBLY__
#ifndef __ASSEMBLER__
#include <sbi/sbi_ecall_interface.h>
#include <sbi/sbi_error.h>
@@ -51,25 +51,22 @@ struct sbi_trap_regs;
/** Possible feature flags of a platform */
enum sbi_platform_features {
/** Platform has timer value */
SBI_PLATFORM_HAS_TIMER_VALUE = (1 << 0),
/** Platform has HART hotplug support */
SBI_PLATFORM_HAS_HART_HOTPLUG = (1 << 1),
/** Platform has fault delegation support */
SBI_PLATFORM_HAS_MFAULTS_DELEGATION = (1 << 2),
/** Platform has custom secondary hart booting support */
SBI_PLATFORM_HAS_HART_SECONDARY_BOOT = (1 << 3),
SBI_PLATFORM_HAS_MFAULTS_DELEGATION = (1 << 1),
/** Last index of Platform features*/
SBI_PLATFORM_HAS_LAST_FEATURE = SBI_PLATFORM_HAS_HART_SECONDARY_BOOT,
SBI_PLATFORM_HAS_LAST_FEATURE = SBI_PLATFORM_HAS_MFAULTS_DELEGATION,
};
/** Default feature set for a platform */
#define SBI_PLATFORM_DEFAULT_FEATURES \
(SBI_PLATFORM_HAS_TIMER_VALUE | SBI_PLATFORM_HAS_MFAULTS_DELEGATION)
(SBI_PLATFORM_HAS_MFAULTS_DELEGATION)
/** Platform functions */
struct sbi_platform_operations {
/* Platform nascent initialization */
int (*nascent_init)(void);
/** Platform early initialization */
int (*early_init)(bool cold_boot);
/** Platform final initialization */
@@ -92,15 +89,18 @@ struct sbi_platform_operations {
*/
int (*misa_get_xlen)(void);
/** Get platform specific root domain memory regions */
struct sbi_domain_memregion *(*domains_root_regions)(void);
/** Initialize (or populate) HART extensions for the platform */
int (*extensions_init)(void);
/** Initialize (or populate) domains for the platform */
int (*domains_init)(void);
/** Write a character to the platform console output */
void (*console_putc)(char ch);
/** Read a character from the platform console input */
int (*console_getc)(void);
/** Initialize hw performance counters */
int (*pmu_init)(void);
/** Get platform specific mhpmevent value */
uint64_t (*pmu_xlate_to_mhpmevent)(uint32_t event_idx, uint64_t data);
/** Initialize the platform console */
int (*console_init)(void);
@@ -109,10 +109,6 @@ struct sbi_platform_operations {
/** Exit the platform interrupt controller for current HART */
void (*irqchip_exit)(void);
/** Send IPI to a target HART */
void (*ipi_send)(u32 target_hart);
/** Clear IPI for a target HART */
void (*ipi_clear)(u32 target_hart);
/** Initialize IPI for current HART */
int (*ipi_init)(bool cold_boot);
/** Exit IPI for current HART */
@@ -121,30 +117,11 @@ struct sbi_platform_operations {
/** Get tlb flush limit value **/
u64 (*get_tlbr_flush_limit)(void);
/** Get platform timer value */
u64 (*timer_value)(void);
/** Start platform timer event for current HART */
void (*timer_event_start)(u64 next_event);
/** Stop platform timer event for current HART */
void (*timer_event_stop)(void);
/** Initialize platform timer for current HART */
int (*timer_init)(bool cold_boot);
/** Exit platform timer for current HART */
void (*timer_exit)(void);
/** Bringup the given hart */
int (*hart_start)(u32 hartid, ulong saddr);
/**
* Stop the current hart from running. This call doesn't expect to
* return if success.
*/
int (*hart_stop)(void);
/* Check whether reset type and reason supported by the platform */
int (*system_reset_check)(u32 reset_type, u32 reset_reason);
/** Reset the platform */
void (*system_reset)(u32 reset_type, u32 reset_reason);
/** platform specific SBI extension implementation probe function */
int (*vendor_ext_check)(long extid);
/** platform specific SBI extension implementation provider */
@@ -201,6 +178,56 @@ struct sbi_platform {
const u32 *hart_index2id;
};
/**
* Prevent modification of struct sbi_platform from affecting
* SBI_PLATFORM_xxx_OFFSET
*/
_Static_assert(
offsetof(struct sbi_platform, opensbi_version)
== SBI_PLATFORM_OPENSBI_VERSION_OFFSET,
"struct sbi_platform definition has changed, please redefine "
"SBI_PLATFORM_OPENSBI_VERSION_OFFSET");
_Static_assert(
offsetof(struct sbi_platform, platform_version)
== SBI_PLATFORM_VERSION_OFFSET,
"struct sbi_platform definition has changed, please redefine "
"SBI_PLATFORM_VERSION_OFFSET");
_Static_assert(
offsetof(struct sbi_platform, name)
== SBI_PLATFORM_NAME_OFFSET,
"struct sbi_platform definition has changed, please redefine "
"SBI_PLATFORM_NAME_OFFSET");
_Static_assert(
offsetof(struct sbi_platform, features)
== SBI_PLATFORM_FEATURES_OFFSET,
"struct sbi_platform definition has changed, please redefine "
"SBI_PLATFORM_FEATURES_OFFSET");
_Static_assert(
offsetof(struct sbi_platform, hart_count)
== SBI_PLATFORM_HART_COUNT_OFFSET,
"struct sbi_platform definition has changed, please redefine "
"SBI_PLATFORM_HART_COUNT_OFFSET");
_Static_assert(
offsetof(struct sbi_platform, hart_stack_size)
== SBI_PLATFORM_HART_STACK_SIZE_OFFSET,
"struct sbi_platform definition has changed, please redefine "
"SBI_PLATFORM_HART_STACK_SIZE_OFFSET");
_Static_assert(
offsetof(struct sbi_platform, platform_ops_addr)
== SBI_PLATFORM_OPS_OFFSET,
"struct sbi_platform definition has changed, please redefine "
"SBI_PLATFORM_OPS_OFFSET");
_Static_assert(
offsetof(struct sbi_platform, firmware_context)
== SBI_PLATFORM_FIRMWARE_CONTEXT_OFFSET,
"struct sbi_platform definition has changed, please redefine "
"SBI_PLATFORM_FIRMWARE_CONTEXT_OFFSET");
_Static_assert(
offsetof(struct sbi_platform, hart_index2id)
== SBI_PLATFORM_HART_INDEX2ID_OFFSET,
"struct sbi_platform definition has changed, please redefine "
"SBI_PLATFORM_HART_INDEX2ID_OFFSET");
/** Get pointer to sbi_platform for sbi_scratch pointer */
#define sbi_platform_ptr(__s) \
((const struct sbi_platform *)((__s)->platform_addr))
@@ -211,18 +238,9 @@ struct sbi_platform {
#define sbi_platform_ops(__p) \
((const struct sbi_platform_operations *)(__p)->platform_ops_addr)
/** Check whether the platform supports timer value */
#define sbi_platform_has_timer_value(__p) \
((__p)->features & SBI_PLATFORM_HAS_TIMER_VALUE)
/** Check whether the platform supports HART hotplug */
#define sbi_platform_has_hart_hotplug(__p) \
((__p)->features & SBI_PLATFORM_HAS_HART_HOTPLUG)
/** Check whether the platform supports fault delegation */
#define sbi_platform_has_mfaults_delegation(__p) \
((__p)->features & SBI_PLATFORM_HAS_MFAULTS_DELEGATION)
/** Check whether the platform supports custom secondary hart booting support */
#define sbi_platform_has_hart_secondary_boot(__p) \
((__p)->features & SBI_PLATFORM_HAS_HART_SECONDARY_BOOT)
/**
* Get HART index for the given HART
@@ -338,36 +356,20 @@ static inline bool sbi_platform_hart_invalid(const struct sbi_platform *plat,
}
/**
* Bringup a given hart from previous stage. Platform should implement this
* operation if they support a custom mechanism to start a hart. Otherwise,
* a generic WFI based approach will be used to start/stop a hart in OpenSBI.
* Nascent (very early) initialization for current HART
*
* @param plat pointer to struct sbi_platform
* @param hartid HART id
* @param saddr M-mode start physical address for the HART
*
* @return 0 if sucessful and negative error code on failure
*/
static inline int sbi_platform_hart_start(const struct sbi_platform *plat,
u32 hartid, ulong saddr)
{
if (plat && sbi_platform_ops(plat)->hart_start)
return sbi_platform_ops(plat)->hart_start(hartid, saddr);
return SBI_ENOTSUPP;
}
/**
* Stop the current hart in OpenSBI.
* NOTE: This function can be used to do very early initialization of
* platform specific per-HART CSRs and devices.
*
* @param plat pointer to struct sbi_platform
*
* @return Negative error code on failure. It doesn't return on success.
* @return 0 on success and negative error code on failure
*/
static inline int sbi_platform_hart_stop(const struct sbi_platform *plat)
static inline int sbi_platform_nascent_init(const struct sbi_platform *plat)
{
if (plat && sbi_platform_ops(plat)->hart_stop)
return sbi_platform_ops(plat)->hart_stop();
return SBI_ENOTSUPP;
if (plat && sbi_platform_ops(plat)->nascent_init)
return sbi_platform_ops(plat)->nascent_init();
return 0;
}
/**
@@ -455,19 +457,18 @@ static inline int sbi_platform_misa_xlen(const struct sbi_platform *plat)
}
/**
* Get platform specific root domain memory regions
* Initialize (or populate) HART extensions for the platform
*
* @param plat pointer to struct sbi_platform
*
* @return an array of memory regions terminated by a region with order zero
* or NULL for no memory regions
* @return 0 on success and negative error code on failure
*/
static inline struct sbi_domain_memregion *
sbi_platform_domains_root_regions(const struct sbi_platform *plat)
static inline int sbi_platform_extensions_init(
const struct sbi_platform *plat)
{
if (plat && sbi_platform_ops(plat)->domains_root_regions)
return sbi_platform_ops(plat)->domains_root_regions();
return NULL;
if (plat && sbi_platform_ops(plat)->extensions_init)
return sbi_platform_ops(plat)->extensions_init();
return 0;
}
/**
@@ -485,30 +486,36 @@ static inline int sbi_platform_domains_init(const struct sbi_platform *plat)
}
/**
* Write a character to the platform console output
* Setup hw PMU events for the platform
*
* @param plat pointer to struct sbi_platform
* @param ch character to write
*
* @return 0 on success and negative error code on failure
*/
static inline void sbi_platform_console_putc(const struct sbi_platform *plat,
char ch)
static inline int sbi_platform_pmu_init(const struct sbi_platform *plat)
{
if (plat && sbi_platform_ops(plat)->console_putc)
sbi_platform_ops(plat)->console_putc(ch);
if (plat && sbi_platform_ops(plat)->pmu_init)
return sbi_platform_ops(plat)->pmu_init();
return 0;
}
/**
* Read a character from the platform console input
* Get the value to be written in mhpmeventx for event_idx
*
* @param plat pointer to struct sbi_platform
* @param event_idx ID of the PMU event
* @param data Additional configuration data passed from supervisor software
*
* @return character read from console input
* @return expected value by the platform or 0 if platform doesn't know about
* the event
*/
static inline int sbi_platform_console_getc(const struct sbi_platform *plat)
static inline uint64_t sbi_platform_pmu_xlate_to_mhpmevent(const struct sbi_platform *plat,
uint32_t event_idx, uint64_t data)
{
if (plat && sbi_platform_ops(plat)->console_getc)
return sbi_platform_ops(plat)->console_getc();
return -1;
if (plat && sbi_platform_ops(plat)->pmu_xlate_to_mhpmevent)
return sbi_platform_ops(plat)->pmu_xlate_to_mhpmevent(event_idx,
data);
return 0;
}
/**
@@ -552,32 +559,6 @@ static inline void sbi_platform_irqchip_exit(const struct sbi_platform *plat)
sbi_platform_ops(plat)->irqchip_exit();
}
/**
* Send IPI to a target HART
*
* @param plat pointer to struct sbi_platform
* @param target_hart HART ID of IPI target
*/
static inline void sbi_platform_ipi_send(const struct sbi_platform *plat,
u32 target_hart)
{
if (plat && sbi_platform_ops(plat)->ipi_send)
sbi_platform_ops(plat)->ipi_send(target_hart);
}
/**
* Clear IPI for a target HART
*
* @param plat pointer to struct sbi_platform
* @param target_hart HART ID of IPI target
*/
static inline void sbi_platform_ipi_clear(const struct sbi_platform *plat,
u32 target_hart)
{
if (plat && sbi_platform_ops(plat)->ipi_clear)
sbi_platform_ops(plat)->ipi_clear(target_hart);
}
/**
* Initialize the platform IPI support for current HART
*
@@ -605,45 +586,6 @@ static inline void sbi_platform_ipi_exit(const struct sbi_platform *plat)
sbi_platform_ops(plat)->ipi_exit();
}
/**
* Get platform timer value
*
* @param plat pointer to struct sbi_platform
*
* @return 64-bit timer value
*/
static inline u64 sbi_platform_timer_value(const struct sbi_platform *plat)
{
if (plat && sbi_platform_ops(plat)->timer_value)
return sbi_platform_ops(plat)->timer_value();
return 0;
}
/**
* Start platform timer event for current HART
*
* @param plat pointer to struct struct sbi_platform
* @param next_event timer value when timer event will happen
*/
static inline void
sbi_platform_timer_event_start(const struct sbi_platform *plat, u64 next_event)
{
if (plat && sbi_platform_ops(plat)->timer_event_start)
sbi_platform_ops(plat)->timer_event_start(next_event);
}
/**
* Stop platform timer event for current HART
*
* @param plat pointer to struct sbi_platform
*/
static inline void
sbi_platform_timer_event_stop(const struct sbi_platform *plat)
{
if (plat && sbi_platform_ops(plat)->timer_event_stop)
sbi_platform_ops(plat)->timer_event_stop();
}
/**
* Initialize the platform timer for current HART
*
@@ -671,41 +613,6 @@ static inline void sbi_platform_timer_exit(const struct sbi_platform *plat)
sbi_platform_ops(plat)->timer_exit();
}
/**
* Check whether reset type and reason supported by the platform
*
* @param plat pointer to struct sbi_platform
* @param reset_type type of reset
* @param reset_reason reason for reset
*
* @return 0 if reset type and reason not supported and 1 if supported
*/
static inline int sbi_platform_system_reset_check(
const struct sbi_platform *plat,
u32 reset_type, u32 reset_reason)
{
if (plat && sbi_platform_ops(plat)->system_reset_check)
return sbi_platform_ops(plat)->system_reset_check(reset_type,
reset_reason);
return 0;
}
/**
* Reset the platform
*
* This function will not return for supported reset type and reset reason
*
* @param plat pointer to struct sbi_platform
* @param reset_type type of reset
* @param reset_reason reason for reset
*/
static inline void sbi_platform_system_reset(const struct sbi_platform *plat,
u32 reset_type, u32 reset_reason)
{
if (plat && sbi_platform_ops(plat)->system_reset)
sbi_platform_ops(plat)->system_reset(reset_type, reset_reason);
}
/**
* Check if a vendor extension is implemented or not.
*

74
include/sbi/sbi_pmu.h Normal file
View File

@@ -0,0 +1,74 @@
/*
* SPDX-License-Identifier: BSD-2-Clause
*
* Copyright (c) 2021 Western Digital Corporation or its affiliates.
*
* Authors:
* Atish Patra <atish.patra@wdc.com>
*/
#ifndef __SBI_PMU_H__
#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>
/* 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
/** 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);
/**
* Add the hardware event to counter mapping information. This should be called
* from the platform code to update the mapping table.
* @param eidx_start Start of the event idx range for supported counters
* @param eidx_end End of the event idx range for supported counters
* @param cmap A bitmap representing counters supporting the event range
* @return 0 on success, error otherwise.
*/
int sbi_pmu_add_hw_event_counter_map(u32 eidx_start, u32 eidx_end, u32 cmap);
/**
* Add the raw hardware event selector and supported counter information. This
* should be called from the platform code to update the mapping table.
* @param info a pointer to the hardware event info
* @return 0 on success, error otherwise.
*/
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_stop(unsigned long cidx_base, unsigned long cidx_mask,
unsigned long flag);
int sbi_pmu_ctr_start(unsigned long cidx_base, unsigned long cidx_mask,
unsigned long flags, uint64_t ival);
int sbi_pmu_ctr_get_info(uint32_t cidx, unsigned long *ctr_info);
unsigned long sbi_pmu_num_ctr(void);
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 sbi_pmu_ctr_incr_fw(enum sbi_pmu_fw_event_code_id fw_id);
#endif

View File

@@ -43,7 +43,7 @@
/* clang-format on */
#ifndef __ASSEMBLY__
#ifndef __ASSEMBLER__
#include <sbi/sbi_types.h>
@@ -73,6 +73,66 @@ struct sbi_scratch {
unsigned long options;
};
/**
* Prevent modification of struct sbi_scratch from affecting
* SBI_SCRATCH_xxx_OFFSET
*/
_Static_assert(
offsetof(struct sbi_scratch, fw_start)
== SBI_SCRATCH_FW_START_OFFSET,
"struct sbi_scratch definition has changed, please redefine "
"SBI_SCRATCH_FW_START_OFFSET");
_Static_assert(
offsetof(struct sbi_scratch, fw_size)
== SBI_SCRATCH_FW_SIZE_OFFSET,
"struct sbi_scratch definition has changed, please redefine "
"SBI_SCRATCH_FW_SIZE_OFFSET");
_Static_assert(
offsetof(struct sbi_scratch, next_arg1)
== SBI_SCRATCH_NEXT_ARG1_OFFSET,
"struct sbi_scratch definition has changed, please redefine "
"SBI_SCRATCH_NEXT_ARG1_OFFSET");
_Static_assert(
offsetof(struct sbi_scratch, next_addr)
== SBI_SCRATCH_NEXT_ADDR_OFFSET,
"struct sbi_scratch definition has changed, please redefine "
"SBI_SCRATCH_NEXT_ADDR_OFFSET");
_Static_assert(
offsetof(struct sbi_scratch, next_mode)
== SBI_SCRATCH_NEXT_MODE_OFFSET,
"struct sbi_scratch definition has changed, please redefine "
"SBI_SCRATCH_NEXT_MODE_OFFSET");
_Static_assert(
offsetof(struct sbi_scratch, warmboot_addr)
== SBI_SCRATCH_WARMBOOT_ADDR_OFFSET,
"struct sbi_scratch definition has changed, please redefine "
"SBI_SCRATCH_WARMBOOT_ADDR_OFFSET");
_Static_assert(
offsetof(struct sbi_scratch, platform_addr)
== SBI_SCRATCH_PLATFORM_ADDR_OFFSET,
"struct sbi_scratch definition has changed, please redefine "
"SBI_SCRATCH_PLATFORM_ADDR_OFFSET");
_Static_assert(
offsetof(struct sbi_scratch, hartid_to_scratch)
== SBI_SCRATCH_HARTID_TO_SCRATCH_OFFSET,
"struct sbi_scratch definition has changed, please redefine "
"SBI_SCRATCH_HARTID_TO_SCRATCH_OFFSET");
_Static_assert(
offsetof(struct sbi_scratch, trap_exit)
== SBI_SCRATCH_TRAP_EXIT_OFFSET,
"struct sbi_scratch definition has changed, please redefine "
"SBI_SCRATCH_TRAP_EXIT_OFFSET");
_Static_assert(
offsetof(struct sbi_scratch, tmp0)
== SBI_SCRATCH_TMP0_OFFSET,
"struct sbi_scratch definition has changed, please redefine "
"SBI_SCRATCH_TMP0_OFFSET");
_Static_assert(
offsetof(struct sbi_scratch, options)
== SBI_SCRATCH_OPTIONS_OFFSET,
"struct sbi_scratch definition has changed, please redefine "
"SBI_SCRATCH_OPTIONS_OFFSET");
/** Possible options for OpenSBI library */
enum sbi_scratch_options {
/** Disable prints during boot */
@@ -98,17 +158,17 @@ int sbi_scratch_init(struct sbi_scratch *scratch);
* @return zero on failure and non-zero (>= SBI_SCRATCH_EXTRA_SPACE_OFFSET)
* on success
*/
unsigned long sbi_scratch_alloc_offset(unsigned long size, const char *owner);
unsigned long sbi_scratch_alloc_offset(unsigned long size);
/** Free-up extra space in sbi_scratch */
void sbi_scratch_free_offset(unsigned long offset);
/** Get pointer from offset in sbi_scratch */
#define sbi_scratch_offset_ptr(scratch, offset) ((void *)scratch + (offset))
#define sbi_scratch_offset_ptr(scratch, offset) (void *)((char *)(scratch) + (offset))
/** Get pointer from offset in sbi_scratch for current HART */
#define sbi_scratch_thishart_offset_ptr(offset) \
((void *)sbi_scratch_thishart_ptr() + (offset))
(void *)((char *)sbi_scratch_thishart_ptr() + (offset))
/** HART id to scratch table */
extern struct sbi_scratch *hartid_to_scratch_table[];

View File

@@ -11,6 +11,33 @@
#define __SBI_SYSTEM_H__
#include <sbi/sbi_types.h>
#include <sbi/sbi_list.h>
/** System reset hardware device */
struct sbi_system_reset_device {
/** Name of the system reset device */
char name[32];
/* Check whether reset type and reason supported by the device */
int (*system_reset_check)(u32 reset_type, u32 reset_reason);
/** Reset the system */
void (*system_reset)(u32 reset_type, u32 reset_reason);
/** List */
struct sbi_dlist node;
};
static inline struct sbi_system_reset_device *to_system_reset_device(
struct sbi_dlist *node)
{
return container_of(node, struct sbi_system_reset_device, node);
}
const struct sbi_system_reset_device *sbi_system_reset_get_device(
u32 reset_type, u32 reset_reason);
void sbi_system_reset_add_device(struct sbi_system_reset_device *dev);
bool sbi_system_reset_supported(u32 reset_type, u32 reset_reason);

View File

@@ -12,8 +12,42 @@
#include <sbi/sbi_types.h>
/** Timer hardware device */
struct sbi_timer_device {
/** Name of the timer operations */
char name[32];
/** Frequency of timer in HZ */
unsigned long timer_freq;
/** Get free-running timer value */
u64 (*timer_value)(void);
/** Start timer event for current HART */
void (*timer_event_start)(u64 next_event);
/** Stop timer event for current HART */
void (*timer_event_stop)(void);
};
struct sbi_scratch;
/** Generic delay loop of desired granularity */
void sbi_timer_delay_loop(ulong units, u64 unit_freq,
void (*delay_fn)(void *), void *opaque);
/** Provide delay in terms of milliseconds */
static inline void sbi_timer_mdelay(ulong msecs)
{
sbi_timer_delay_loop(msecs, 1000, NULL, NULL);
}
/** Provide delay in terms of microseconds */
static inline void sbi_timer_udelay(ulong usecs)
{
sbi_timer_delay_loop(usecs, 1000000, NULL, NULL);
}
/** Get timer value for current HART */
u64 sbi_timer_value(void);
@@ -35,6 +69,12 @@ void sbi_timer_event_start(u64 next_event);
/** Process timer event for current HART */
void sbi_timer_process(void);
/** Get current timer device */
const struct sbi_timer_device *sbi_timer_get_device(void);
/** Register timer device */
void sbi_timer_set_device(const struct sbi_timer_device *dev);
/* Initialize timer */
int sbi_timer_init(struct sbi_scratch *scratch, bool cold_boot);

View File

@@ -110,7 +110,7 @@
/** Size (in bytes) of sbi_trap_info */
#define SBI_TRAP_INFO_SIZE SBI_TRAP_INFO_OFFSET(last)
#ifndef __ASSEMBLY__
#ifndef __ASSEMBLER__
#include <sbi/sbi_types.h>
@@ -205,7 +205,7 @@ struct sbi_trap_info {
int sbi_trap_redirect(struct sbi_trap_regs *regs,
struct sbi_trap_info *trap);
void sbi_trap_handler(struct sbi_trap_regs *regs);
struct sbi_trap_regs *sbi_trap_handler(struct sbi_trap_regs *regs);
void __noreturn sbi_trap_exit(const struct sbi_trap_regs *regs);

View File

@@ -63,12 +63,19 @@ typedef unsigned long physical_size_t;
#define __packed __attribute__((packed))
#define __noreturn __attribute__((noreturn))
#define __aligned(x) __attribute__((aligned(x)))
#define likely(x) __builtin_expect((x), 1)
#define unlikely(x) __builtin_expect((x), 0)
#ifndef __has_builtin
#define __has_builtin(...) 0
#endif
#undef offsetof
#ifdef __compiler_offsetof
#if __has_builtin(__builtin_offsetof)
#define offsetof(TYPE, MEMBER) __builtin_offsetof(TYPE,MEMBER)
#elif defined(__compiler_offsetof)
#define offsetof(TYPE, MEMBER) __compiler_offsetof(TYPE,MEMBER)
#else
#define offsetof(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER)

View File

@@ -10,8 +10,8 @@
#ifndef __SBI_VERSION_H__
#define __SBI_VERSION_H__
#define OPENSBI_VERSION_MAJOR 0
#define OPENSBI_VERSION_MINOR 9
#define OPENSBI_VERSION_MAJOR 1
#define OPENSBI_VERSION_MINOR 1
/**
* OpenSBI 32-bit version with:

View File

@@ -21,6 +21,30 @@
*/
void fdt_cpu_fixup(void *fdt);
/**
* Fix up the APLIC nodes in the device tree
*
* This routine disables APLIC nodes which are not accessible to the next
* booting stage based on currently assigned domain.
*
* It is recommended that platform codes call this helper in their final_init()
*
* @param fdt: device tree blob
*/
void fdt_aplic_fixup(void *fdt);
/**
* Fix up the IMSIC nodes in the device tree
*
* This routine disables IMSIC nodes which are not accessible to the next
* booting stage based on currently assigned domain.
*
* It is recommended that platform codes call this helper in their final_init()
*
* @param fdt: device tree blob
*/
void fdt_imsic_fixup(void *fdt);
/**
* Fix up the PLIC node in the device tree
*
@@ -30,9 +54,8 @@ void fdt_cpu_fixup(void *fdt);
* It is recommended that platform codes call this helper in their final_init()
*
* @param fdt: device tree blob
* @param compat: PLIC node compatible string
*/
void fdt_plic_fixup(void *fdt, const char *compat);
void fdt_plic_fixup(void *fdt);
/**
* Fix up the reserved memory node in the device tree
@@ -65,8 +88,9 @@ int fdt_reserved_memory_nomap_fixup(void *fdt);
* General device tree fix-up
*
* This routine do all required device tree fix-ups for a typical platform.
* It fixes up the PLIC node and the reserved memory node in the device tree
* by calling the corresponding helper routines to accomplish the task.
* It fixes up the PLIC node, IMSIC nodes, APLIC nodes, and the reserved
* memory node in the device tree by calling the corresponding helper
* routines to accomplish the task.
*
* It is recommended that platform codes call this helper in their final_init()
*

View File

@@ -11,10 +11,18 @@
#define __FDT_HELPER_H__
#include <sbi/sbi_types.h>
#include <sbi/sbi_scratch.h>
struct fdt_match {
const char *compatible;
void *data;
const void *data;
};
#define FDT_MAX_PHANDLE_ARGS 16
struct fdt_phandle_args {
int node_offset;
int args_count;
u32 args[FDT_MAX_PHANDLE_ARGS];
};
struct platform_uart_data {
@@ -23,6 +31,7 @@ struct platform_uart_data {
unsigned long baud;
unsigned long reg_shift;
unsigned long reg_io_width;
unsigned long reg_offset;
};
const struct fdt_match *fdt_match_node(void *fdt, int nodeoff,
@@ -32,12 +41,23 @@ int fdt_find_match(void *fdt, int startoff,
const struct fdt_match *match_table,
const struct fdt_match **out_match);
int fdt_get_node_addr_size(void *fdt, int node, unsigned long *addr,
unsigned long *size);
int fdt_parse_phandle_with_args(void *fdt, int nodeoff,
const char *prop, const char *cells_prop,
int index, struct fdt_phandle_args *out_args);
int fdt_get_node_addr_size(void *fdt, int node, int index,
uint64_t *addr, uint64_t *size);
bool fdt_node_is_enabled(void *fdt, int nodeoff);
int fdt_parse_hart_id(void *fdt, int cpu_offset, u32 *hartid);
int fdt_parse_max_hart_id(void *fdt, u32 *max_hartid);
int fdt_parse_max_enabled_hart_id(void *fdt, u32 *max_hartid);
int fdt_parse_timebase_frequency(void *fdt, unsigned long *freq);
int fdt_parse_gaisler_uart_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);
@@ -51,18 +71,36 @@ int fdt_parse_uart8250_node(void *fdt, int nodeoffset,
int fdt_parse_uart8250(void *fdt, struct platform_uart_data *uart,
const char *compatible);
int fdt_parse_xlnx_uartlite_node(void *fdt, int nodeoffset,
struct platform_uart_data *uart);
struct aplic_data;
int fdt_parse_aplic_node(void *fdt, int nodeoff, struct aplic_data *aplic);
struct imsic_data;
bool fdt_check_imsic_mlevel(void *fdt);
int fdt_parse_imsic_node(void *fdt, int nodeoff, struct imsic_data *imsic);
struct plic_data;
int fdt_parse_plic_node(void *fdt, int nodeoffset, struct plic_data *plic);
int fdt_parse_plic(void *fdt, struct plic_data *plic, const char *compat);
struct clint_data;
int fdt_parse_aclint_node(void *fdt, int nodeoffset, bool for_timer,
unsigned long *out_addr1, unsigned long *out_size1,
unsigned long *out_addr2, unsigned long *out_size2,
u32 *out_first_hartid, u32 *out_hart_count);
int fdt_parse_clint_node(void *fdt, int nodeoffset, bool for_timer,
struct clint_data *clint);
int fdt_parse_compat_addr(void *fdt, unsigned long *addr,
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();
}
#endif /* __FDT_HELPER_H__ */

View File

@@ -0,0 +1,46 @@
// SPDX-License-Identifier: BSD-2-Clause
/*
* fdt_pmu.c - Flat Device Tree PMU helper routines
*
* Copyright (c) 2021 Western Digital Corporation or its affiliates.
*
* Authors:
* Atish Patra <atish.patra@wdc.com>
*/
#ifndef __FDT_PMU_H__
#define __FDT_PMU_H__
#include <sbi/sbi_types.h>
/**
* Fix up the PMU node in the device tree
*
* This routine:
* 1. Disables opensbi specific properties from the DT
*
* It is recommended that platform support call this function in
* their final_init() platform operation.
*
* @param fdt device tree blob
*/
void fdt_pmu_fixup(void *fdt);
/**
* Setup PMU data from device tree
*
* @param fdt device tree blob
*
* @return 0 on success and negative error code on failure
*/
int fdt_pmu_setup(void *fdt);
/**
* Get the mhpmevent select value read from DT for a given event
* @param event_idx Event ID of the given event
*
* @return The select value read from DT or 0 if given index was not found
*/
uint64_t fdt_pmu_get_select_value(uint32_t event_idx);
#endif

View File

@@ -0,0 +1,36 @@
/*
* SPDX-License-Identifier: BSD-2-Clause
*
* Copyright (c) 2021 Western Digital Corporation or its affiliates.
*
* Authors:
* Anup Patel <anup.patel@wdc.com>
*/
#ifndef __FDT_GPIO_H__
#define __FDT_GPIO_H__
#include <sbi_utils/gpio/gpio.h>
struct fdt_phandle_args;
/** FDT based GPIO driver */
struct fdt_gpio {
const struct fdt_match *match_table;
int (*xlate)(struct gpio_chip *chip,
const struct fdt_phandle_args *pargs,
struct gpio_pin *out_pin);
int (*init)(void *fdt, int nodeoff, u32 phandle,
const struct fdt_match *match);
};
/** Get a GPIO pin using "gpios" DT property of client DT node */
int fdt_gpio_pin_get(void *fdt, int nodeoff, int index,
struct gpio_pin *out_pin);
/** Simple xlate function to convert two GPIO FDT cells into GPIO pin */
int fdt_gpio_simple_xlate(struct gpio_chip *chip,
const struct fdt_phandle_args *pargs,
struct gpio_pin *out_pin);
#endif

View File

@@ -0,0 +1,107 @@
/*
* SPDX-License-Identifier: BSD-2-Clause
*
* Copyright (c) 2021 Western Digital Corporation or its affiliates.
*
* Authors:
* Anup Patel <anup.patel@wdc.com>
*/
#ifndef __GPIO_H__
#define __GPIO_H__
#include <sbi/sbi_types.h>
#include <sbi/sbi_list.h>
#define GPIO_LINE_DIRECTION_IN 1
#define GPIO_LINE_DIRECTION_OUT 0
/** Representation of a GPIO pin */
struct gpio_pin {
/** Pointer to the GPIO chip */
struct gpio_chip *chip;
/** Identification of GPIO pin within GPIO chip */
unsigned int offset;
/**
* Additional configuration flags of the GPIO pin desired
* by GPIO clients.
*
* NOTE: GPIO chip can have custom configuration flags.
*/
unsigned int flags;
#define GPIO_FLAG_ACTIVE_LOW 0x1
#define GPIO_FLAG_SINGLE_ENDED 0x2
#define GPIO_FLAG_OPEN_DRAIN 0x4
#define GPIO_FLAG_TRANSITORY 0x8
#define GPIO_FLAG_PULL_UP 0x10
#define GPIO_FLAG_PULL_DOWN 0x20
};
/** Representation of a GPIO chip */
struct gpio_chip {
/** Pointer to GPIO driver owning this GPIO chip */
void *driver;
/** Uniquie ID of the GPIO chip assigned by the driver */
unsigned int id;
/** Number of GPIOs supported by the GPIO chip */
unsigned int ngpio;
/**
* Get current direction of GPIO pin
*
* @return 0=output, 1=input, or negative error
*/
int (*get_direction)(struct gpio_pin *gp);
/**
* Set input direction of GPIO pin
*
* @return 0 on success and negative error code on failure
*/
int (*direction_input)(struct gpio_pin *gp);
/**
* Set output direction of GPIO pin with given output value
*
* @return 0 on success and negative error code on failure
*/
int (*direction_output)(struct gpio_pin *gp, int value);
/**
* Get current value of GPIO pin
*
* @return 0=low, 1=high, or negative error
*/
int (*get)(struct gpio_pin *gp);
/** Set output value for GPIO pin */
void (*set)(struct gpio_pin *gp, int value);
/** List */
struct sbi_dlist node;
};
static inline struct gpio_chip *to_gpio_chip(struct sbi_dlist *node)
{
return container_of(node, struct gpio_chip, node);
}
/** Find a registered GPIO chip */
struct gpio_chip *gpio_chip_find(unsigned int id);
/** Register GPIO chip */
int gpio_chip_add(struct gpio_chip *gc);
/** Un-register GPIO chip */
void gpio_chip_remove(struct gpio_chip *gc);
/** Get current direction of GPIO pin */
int gpio_get_direction(struct gpio_pin *gp);
/** Set input direction of GPIO pin */
int gpio_direction_input(struct gpio_pin *gp);
/** Set output direction of GPIO pin */
int gpio_direction_output(struct gpio_pin *gp, int value);
/** Get current value of GPIO pin */
int gpio_get(struct gpio_pin *gp);
/** Set output value of GPIO pin */
int gpio_set(struct gpio_pin *gp, int value);
#endif

View File

@@ -0,0 +1,26 @@
/*
* SPDX-License-Identifier: BSD-2-Clause
*
* Copyright (c) 2021 YADRO
*
* Authors:
* Nikita Shubin <n.shubin@yadro.com>
*/
#ifndef __FDT_I2C_H__
#define __FDT_I2C_H__
#include <sbi_utils/i2c/i2c.h>
/** FDT based I2C adapter driver */
struct fdt_i2c_adapter {
const struct fdt_match *match_table;
int (*init)(void *fdt, int nodeoff,
const struct fdt_match *match);
};
/** Get I2C adapter identified by nodeoff */
int fdt_i2c_adapter_get(void *fdt, int nodeoff,
struct i2c_adapter **out_adapter);
#endif

View File

@@ -0,0 +1,85 @@
/*
* SPDX-License-Identifier: BSD-2-Clause
*
* Copyright (c) 2021 YADRO
*
* Authors:
* Nikita Shubin <n.shubin@yadro.com>
*/
#ifndef __I2C_H__
#define __I2C_H__
#include <sbi/sbi_types.h>
#include <sbi/sbi_list.h>
/** Representation of a I2C adapter */
struct i2c_adapter {
/** Pointer to I2C driver owning this I2C adapter */
void *driver;
/** Unique ID of the I2C adapter assigned by the driver */
int id;
/**
* Send buffer to given address, register
*
* @return 0 on success and negative error code on failure
*/
int (*write)(struct i2c_adapter *ia, uint8_t addr, uint8_t reg,
uint8_t *buffer, int len);
/**
* Read buffer from given address, register
*
* @return 0 on success and negative error code on failure
*/
int (*read)(struct i2c_adapter *ia, uint8_t addr, uint8_t reg,
uint8_t *buffer, int len);
/** List */
struct sbi_dlist node;
};
static inline struct i2c_adapter *to_i2c_adapter(struct sbi_dlist *node)
{
return container_of(node, struct i2c_adapter, node);
}
/** Find a registered I2C adapter */
struct i2c_adapter *i2c_adapter_find(int id);
/** Register I2C adapter */
int i2c_adapter_add(struct i2c_adapter *ia);
/** Un-register I2C adapter */
void i2c_adapter_remove(struct i2c_adapter *ia);
/** Send to device on I2C adapter bus */
int i2c_adapter_write(struct i2c_adapter *ia, uint8_t addr, uint8_t reg,
uint8_t *buffer, int len);
/** Read from device on I2C adapter bus */
int i2c_adapter_read(struct i2c_adapter *ia, uint8_t addr, uint8_t reg,
uint8_t *buffer, int len);
static inline int i2c_adapter_reg_write(struct i2c_adapter *ia, uint8_t addr,
uint8_t reg, uint8_t val)
{
return i2c_adapter_write(ia, addr, reg, &val, 1);
}
static inline int i2c_adapter_reg_read(struct i2c_adapter *ia, uint8_t addr,
uint8_t reg, uint8_t *val)
{
uint8_t buf;
int ret = i2c_adapter_read(ia, addr, reg, &buf, 1);
if (ret)
return ret;
*val = buf;
return 0;
}
#endif

View File

@@ -0,0 +1,33 @@
/*
* SPDX-License-Identifier: BSD-2-Clause
*
* Copyright (c) 2021 Western Digital Corporation or its affiliates.
*
* Authors:
* Anup Patel <anup.patel@wdc.com>
*/
#ifndef __IPI_ACLINT_MSWI_H__
#define __IPI_ACLINT_MSWI_H__
#include <sbi/sbi_types.h>
#define ACLINT_MSWI_ALIGN 0x1000
#define ACLINT_MSWI_SIZE 0x4000
#define ACLINT_MSWI_MAX_HARTS 4095
#define CLINT_MSWI_OFFSET 0x0000
struct aclint_mswi_data {
/* Public details */
unsigned long addr;
unsigned long size;
u32 first_hartid;
u32 hart_count;
};
int aclint_mswi_warm_init(void);
int aclint_mswi_cold_init(struct aclint_mswi_data *mswi);
#endif

View File

@@ -17,14 +17,8 @@ struct fdt_ipi {
int (*cold_init)(void *fdt, int nodeoff, const struct fdt_match *match);
int (*warm_init)(void);
void (*exit)(void);
void (*send)(u32 target_hart);
void (*clear)(u32 target_hart);
};
void fdt_ipi_send(u32 target_hart);
void fdt_ipi_clear(u32 target_hart);
void fdt_ipi_exit(void);
int fdt_ipi_init(bool cold_boot);

View File

@@ -0,0 +1,47 @@
/*
* SPDX-License-Identifier: BSD-2-Clause
*
* Copyright (c) 2021 Western Digital Corporation or its affiliates.
* Copyright (c) 2022 Ventana Micro Systems Inc.
*
* Authors:
* Anup Patel <anup.patel@wdc.com>
*/
#ifndef __IRQCHIP_APLIC_H__
#define __IRQCHIP_APLIC_H__
#include <sbi/sbi_types.h>
#define APLIC_MAX_DELEGATE 16
struct aplic_msicfg_data {
unsigned long lhxs;
unsigned long lhxw;
unsigned long hhxs;
unsigned long hhxw;
unsigned long base_addr;
};
struct aplic_delegate_data {
u32 first_irq;
u32 last_irq;
u32 child_index;
};
struct aplic_data {
unsigned long addr;
unsigned long size;
unsigned long num_idc;
unsigned long num_source;
bool targets_mmode;
bool has_msicfg_mmode;
struct aplic_msicfg_data msicfg_mmode;
bool has_msicfg_smode;
struct aplic_msicfg_data msicfg_smode;
struct aplic_delegate_data delegate[APLIC_MAX_DELEGATE];
};
int aplic_cold_irqchip_init(struct aplic_data *aplic);
#endif

View File

@@ -0,0 +1,22 @@
/*
* SPDX-License-Identifier: BSD-2-Clause
*
* Copyright (c) 2022 Samuel Holland <samuel@sholland.org>
*/
#ifndef __IRQCHIP_FDT_IRQCHIP_PLIC_H__
#define __IRQCHIP_FDT_IRQCHIP_PLIC_H__
#include <sbi/sbi_types.h>
void fdt_plic_priority_save(u8 *priority);
void fdt_plic_priority_restore(const u8 *priority);
void fdt_plic_context_save(bool smode, u32 *enable, u32 *threshold);
void fdt_plic_context_restore(bool smode, const u32 *enable, u32 threshold);
void thead_plic_restore(void);
#endif

View File

@@ -0,0 +1,50 @@
/*
* SPDX-License-Identifier: BSD-2-Clause
*
* Copyright (c) 2021 Western Digital Corporation or its affiliates.
* Copyright (c) 2022 Ventana Micro Systems Inc.
*
* Authors:
* Anup Patel <anup.patel@wdc.com>
*/
#ifndef __IRQCHIP_IMSIC_H__
#define __IRQCHIP_IMSIC_H__
#include <sbi/sbi_types.h>
#define IMSIC_MMIO_PAGE_SHIFT 12
#define IMSIC_MMIO_PAGE_SZ (1UL << IMSIC_MMIO_PAGE_SHIFT)
#define IMSIC_MAX_REGS 16
struct imsic_regs {
unsigned long addr;
unsigned long size;
};
struct imsic_data {
bool targets_mmode;
u32 guest_index_bits;
u32 hart_index_bits;
u32 group_index_bits;
u32 group_index_shift;
unsigned long num_ids;
struct imsic_regs regs[IMSIC_MAX_REGS];
};
int imsic_map_hartid_to_data(u32 hartid, struct imsic_data *imsic, int file);
struct imsic_data *imsic_get_data(u32 hartid);
int imsic_get_target_file(u32 hartid);
void imsic_local_irqchip_init(void);
int imsic_warm_irqchip_init(void);
int imsic_data_check(struct imsic_data *imsic);
int imsic_cold_irqchip_init(struct imsic_data *imsic);
#endif

View File

@@ -17,13 +17,23 @@ struct plic_data {
unsigned long num_src;
};
int plic_warm_irqchip_init(struct plic_data *plic,
/* 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_restore(const struct plic_data *plic, const u8 *priority);
void plic_context_save(const struct plic_data *plic, int context_id,
u32 *enable, u32 *threshold);
void plic_context_restore(const struct plic_data *plic, int context_id,
const u32 *enable, u32 threshold);
int plic_context_init(const struct plic_data *plic, int context_id,
bool enable, u32 threshold);
int plic_warm_irqchip_init(const struct plic_data *plic,
int m_cntx_id, int s_cntx_id);
int plic_cold_irqchip_init(struct plic_data *plic);
void plic_set_thresh(struct plic_data *plic, u32 cntxid, u32 val);
void plic_set_ie(struct plic_data *plic, u32 cntxid, u32 word_index, u32 val);
int plic_cold_irqchip_init(const struct plic_data *plic);
#endif

View File

@@ -15,14 +15,18 @@
struct fdt_reset {
const struct fdt_match *match_table;
int (*init)(void *fdt, int nodeoff, const struct fdt_match *match);
int (*system_reset_check)(u32 reset_type, u32 reset_reason);
void (*system_reset)(u32 reset_type, u32 reset_reason);
};
int fdt_system_reset_check(u32 reset_type, u32 reset_reason);
/**
* fdt_reset_driver_init() - initialize reset driver based on the device-tree
*/
int fdt_reset_driver_init(void *fdt, struct fdt_reset *drv);
void fdt_system_reset(u32 reset_type, u32 reset_reason);
int fdt_reset_init(void);
/**
* fdt_reset_init() - initialize reset drivers based on the device-tree
*
* This function shall be invoked in final init.
*/
void fdt_reset_init(void);
#endif

View File

@@ -15,14 +15,8 @@
struct fdt_serial {
const struct fdt_match *match_table;
int (*init)(void *fdt, int nodeoff, const struct fdt_match *match);
void (*putc)(char ch);
int (*getc)(void);
};
void fdt_serial_putc(char ch);
int fdt_serial_getc(void);
int fdt_serial_init(void);
#endif

View File

@@ -0,0 +1,17 @@
/*
* SPDX-License-Identifier: BSD-2-Clause
*
* Copyright (c) 2021 Cobham Gaisler AB.
*
* Authors:
* Daniel Cederman <cederman@gaisler.com>
*/
#ifndef __SERIAL_GAISLER_APBUART_H__
#define __SERIAL_GAISLER_APBUART_H__
#include <sbi/sbi_types.h>
int gaisler_uart_init(unsigned long base, u32 in_freq, u32 baudrate);
#endif

View File

@@ -0,0 +1,17 @@
/*
* SPDX-License-Identifier: BSD-2-Clause
*
* Copyright (c) 2021 Gabriel Somlo
*
* Authors:
* Gabriel Somlo <gsomlo@gmail.com>
*/
#ifndef __SERIAL_LITEX_UART_H__
#define __SERIAL_LITEX_UART_H__
#include <sbi/sbi_types.h>
int litex_uart_init(unsigned long base);
#endif

View File

@@ -9,10 +9,6 @@
#include <sbi/sbi_types.h>
void shakti_uart_putc(char ch);
int shakti_uart_getc(void);
int shakti_uart_init(unsigned long base, u32 in_freq, u32 baudrate);
#endif

View File

@@ -12,10 +12,6 @@
#include <sbi/sbi_types.h>
void sifive_uart_putc(char ch);
int sifive_uart_getc(void);
int sifive_uart_init(unsigned long base, u32 in_freq, u32 baudrate);
#endif

View File

@@ -12,11 +12,7 @@
#include <sbi/sbi_types.h>
void uart8250_putc(char ch);
int uart8250_getc(void);
int uart8250_init(unsigned long base, u32 in_freq, u32 baudrate, u32 reg_shift,
u32 reg_width);
u32 reg_width, u32 reg_offset);
#endif

View File

@@ -0,0 +1,16 @@
/*
* SPDX-License-Identifier: BSD-2-Clause
*
* Copyright (c) 2022 Western Digital Corporation or its affiliates.
*
* Authors:
* Alistair Francis <alistair.francis@wdc.com>
*/
#ifndef __SERIAL_XLNX_UARTLITE_H__
#define __SERIAL_XLNX_UARTLITE_H__
#include <sbi/sbi_types.h>
int xlnx_uartlite_init(unsigned long base);
#endif

View File

@@ -1,51 +0,0 @@
/*
* SPDX-License-Identifier: BSD-2-Clause
*
* Copyright (c) 2019 Western Digital Corporation or its affiliates.
*
* Authors:
* Anup Patel <anup.patel@wdc.com>
*/
#ifndef __SYS_CLINT_H__
#define __SYS_CLINT_H__
#include <sbi/sbi_types.h>
struct clint_data {
/* Public details */
unsigned long addr;
u32 first_hartid;
u32 hart_count;
bool has_64bit_mmio;
/* Private details (initialized and used by CLINT library)*/
u32 *ipi;
struct clint_data *time_delta_reference;
unsigned long time_delta_computed;
u64 time_delta;
u64 *time_val;
u64 *time_cmp;
u64 (*time_rd)(volatile u64 *addr);
void (*time_wr)(u64 value, volatile u64 *addr);
};
void clint_ipi_send(u32 target_hart);
void clint_ipi_clear(u32 target_hart);
int clint_warm_ipi_init(void);
int clint_cold_ipi_init(struct clint_data *clint);
u64 clint_timer_value(void);
void clint_timer_event_stop(void);
void clint_timer_event_start(u64 next_event);
int clint_warm_timer_init(void);
int clint_cold_timer_init(struct clint_data *clint,
struct clint_data *reference);
#endif

View File

@@ -10,12 +10,12 @@
#include <sbi/sbi_types.h>
void htif_putc(char ch);
int htif_serial_init(bool custom_addr,
unsigned long custom_fromhost_addr,
unsigned long custom_tohost_addr);
int htif_getc(void);
int htif_system_reset_check(u32 type, u32 reason);
void htif_system_reset(u32 type, u32 reason);
int htif_system_reset_init(bool custom_addr,
unsigned long custom_fromhost_addr,
unsigned long custom_tohost_addr);
#endif

View File

@@ -12,10 +12,6 @@
#include <sbi/sbi_types.h>
int sifive_test_system_reset_check(u32 type, u32 reason);
void sifive_test_system_reset(u32 type, u32 reason);
int sifive_test_init(unsigned long base);
#endif

View File

@@ -0,0 +1,53 @@
/*
* SPDX-License-Identifier: BSD-2-Clause
*
* Copyright (c) 2021 Western Digital Corporation or its affiliates.
*
* Authors:
* Anup Patel <anup.patel@wdc.com>
*/
#ifndef __TIMER_ACLINT_MTIMER_H__
#define __TIMER_ACLINT_MTIMER_H__
#include <sbi/sbi_types.h>
#define ACLINT_MTIMER_ALIGN 0x8
#define ACLINT_MTIMER_MAX_HARTS 4095
#define ACLINT_DEFAULT_MTIME_OFFSET 0x7ff8
#define ACLINT_DEFAULT_MTIME_SIZE 0x8
#define ACLINT_DEFAULT_MTIMECMP_OFFSET 0x0000
#define ACLINT_DEFAULT_MTIMECMP_SIZE 0x7ff8
#define CLINT_MTIMER_OFFSET 0x4000
struct aclint_mtimer_data {
/* Public details */
unsigned long mtime_freq;
unsigned long mtime_addr;
unsigned long mtime_size;
unsigned long mtimecmp_addr;
unsigned long mtimecmp_size;
u32 first_hartid;
u32 hart_count;
bool has_64bit_mmio;
bool has_shared_mtime;
/* Private details (initialized and used by ACLINT MTIMER library) */
struct aclint_mtimer_data *time_delta_reference;
unsigned long time_delta_computed;
u64 (*time_rd)(volatile u64 *addr);
void (*time_wr)(bool timecmp, u64 value, volatile u64 *addr);
};
void aclint_mtimer_sync(struct aclint_mtimer_data *mt);
void aclint_mtimer_set_reference(struct aclint_mtimer_data *mt,
struct aclint_mtimer_data *ref);
int aclint_mtimer_warm_init(void);
int aclint_mtimer_cold_init(struct aclint_mtimer_data *mt,
struct aclint_mtimer_data *reference);
#endif

View File

@@ -17,17 +17,8 @@ struct fdt_timer {
int (*cold_init)(void *fdt, int nodeoff, const struct fdt_match *match);
int (*warm_init)(void);
void (*exit)(void);
u64 (*value)(void);
void (*event_stop)(void);
void (*event_start)(u64 next_event);
};
u64 fdt_timer_value(void);
void fdt_timer_event_stop(void);
void fdt_timer_event_start(u64 next_event);
void fdt_timer_exit(void);
int fdt_timer_init(bool cold_boot);

View File

@@ -20,6 +20,7 @@ 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
@@ -31,8 +32,10 @@ libsbi-objs-y += sbi_hsm.o
libsbi-objs-y += sbi_illegal_insn.o
libsbi-objs-y += sbi_init.o
libsbi-objs-y += sbi_ipi.o
libsbi-objs-y += sbi_irqchip.o
libsbi-objs-y += sbi_misaligned_ldst.o
libsbi-objs-y += sbi_platform.o
libsbi-objs-y += sbi_pmu.o
libsbi-objs-y += sbi_scratch.o
libsbi-objs-y += sbi_string.o
libsbi-objs-y += sbi_system.o

View File

@@ -11,6 +11,7 @@
#include <sbi/riscv_encoding.h>
#include <sbi/sbi_error.h>
#include <sbi/sbi_platform.h>
#include <sbi/sbi_console.h>
/* determine CPU extension, return non-zero support */
int misa_extension_imp(char ext)
@@ -52,7 +53,7 @@ int misa_xlen(void)
void misa_string(int xlen, char *out, unsigned int out_sz)
{
unsigned int i, pos = 0;
const char valid_isa_order[] = "iemafdqclbjtpvnsuhkorwxyzg";
const char valid_isa_order[] = "iemafdqclbjtpvnhkorwxyzg";
if (!out)
return;
@@ -75,6 +76,8 @@ void misa_string(int xlen, char *out, unsigned int out_sz)
out[pos++] = '8';
break;
default:
sbi_panic("%s: Unknown misa.MXL encoding %d",
__func__, xlen);
return;
}
}
@@ -118,7 +121,36 @@ unsigned long csr_read_num(int csr_num)
switch (csr_num) {
switchcase_csr_read_16(CSR_PMPCFG0, ret)
switchcase_csr_read_64(CSR_PMPADDR0, ret)
switchcase_csr_read(CSR_MCYCLE, ret)
switchcase_csr_read(CSR_MINSTRET, ret)
switchcase_csr_read(CSR_MHPMCOUNTER3, ret)
switchcase_csr_read_4(CSR_MHPMCOUNTER4, ret)
switchcase_csr_read_8(CSR_MHPMCOUNTER8, ret)
switchcase_csr_read_16(CSR_MHPMCOUNTER16, ret)
switchcase_csr_read(CSR_MCOUNTINHIBIT, ret)
switchcase_csr_read(CSR_MHPMEVENT3, ret)
switchcase_csr_read_4(CSR_MHPMEVENT4, ret)
switchcase_csr_read_8(CSR_MHPMEVENT8, ret)
switchcase_csr_read_16(CSR_MHPMEVENT16, ret)
#if __riscv_xlen == 32
switchcase_csr_read(CSR_MCYCLEH, ret)
switchcase_csr_read(CSR_MINSTRETH, ret)
switchcase_csr_read(CSR_MHPMCOUNTER3H, ret)
switchcase_csr_read_4(CSR_MHPMCOUNTER4H, ret)
switchcase_csr_read_8(CSR_MHPMCOUNTER8H, ret)
switchcase_csr_read_16(CSR_MHPMCOUNTER16H, ret)
/**
* The CSR range MHPMEVENT[3-16]H are available only if sscofpmf
* extension is present. The caller must ensure that.
*/
switchcase_csr_read(CSR_MHPMEVENT3H, ret)
switchcase_csr_read_4(CSR_MHPMEVENT4H, ret)
switchcase_csr_read_8(CSR_MHPMEVENT8H, ret)
switchcase_csr_read_16(CSR_MHPMEVENT16H, ret)
#endif
default:
sbi_panic("%s: Unknown CSR %#x", __func__, csr_num);
break;
};
@@ -161,7 +193,32 @@ void csr_write_num(int csr_num, unsigned long val)
switch (csr_num) {
switchcase_csr_write_16(CSR_PMPCFG0, val)
switchcase_csr_write_64(CSR_PMPADDR0, val)
switchcase_csr_write(CSR_MCYCLE, val)
switchcase_csr_write(CSR_MINSTRET, val)
switchcase_csr_write(CSR_MHPMCOUNTER3, val)
switchcase_csr_write_4(CSR_MHPMCOUNTER4, val)
switchcase_csr_write_8(CSR_MHPMCOUNTER8, val)
switchcase_csr_write_16(CSR_MHPMCOUNTER16, val)
#if __riscv_xlen == 32
switchcase_csr_write(CSR_MCYCLEH, val)
switchcase_csr_write(CSR_MINSTRETH, val)
switchcase_csr_write(CSR_MHPMCOUNTER3H, val)
switchcase_csr_write_4(CSR_MHPMCOUNTER4H, val)
switchcase_csr_write_8(CSR_MHPMCOUNTER8H, val)
switchcase_csr_write_16(CSR_MHPMCOUNTER16H, val)
switchcase_csr_write(CSR_MHPMEVENT3H, val)
switchcase_csr_write_4(CSR_MHPMEVENT4H, val)
switchcase_csr_write_8(CSR_MHPMEVENT8H, val)
switchcase_csr_write_16(CSR_MHPMEVENT16H, val)
#endif
switchcase_csr_write(CSR_MCOUNTINHIBIT, val)
switchcase_csr_write(CSR_MHPMEVENT3, val)
switchcase_csr_write_4(CSR_MHPMEVENT4, val)
switchcase_csr_write_8(CSR_MHPMEVENT8, val)
switchcase_csr_write_16(CSR_MHPMEVENT16, val)
default:
sbi_panic("%s: Unknown CSR %#x", __func__, csr_num);
break;
};
@@ -178,6 +235,9 @@ static unsigned long ctz(unsigned long x)
{
unsigned long ret = 0;
if (x == 0)
return 8 * sizeof(x);
while (!(x & 1UL)) {
ret++;
x = x >> 1;
@@ -205,14 +265,12 @@ int pmp_set(unsigned int n, unsigned long prot, unsigned long addr,
pmpcfg_csr = (CSR_PMPCFG0 + (n >> 2)) & ~1;
pmpcfg_shift = (n & 7) << 3;
#else
pmpcfg_csr = -1;
pmpcfg_shift = -1;
# error "Unexpected __riscv_xlen"
#endif
pmpaddr_csr = CSR_PMPADDR0 + n;
if (pmpcfg_csr < 0 || pmpcfg_shift < 0)
return SBI_ENOTSUPP;
/* encode PMP config */
prot &= ~PMP_A;
prot |= (log2len == PMP_SHIFT) ? PMP_A_NA4 : PMP_A_NAPOT;
cfgmask = ~(0xffUL << pmpcfg_shift);
pmpcfg = (csr_read_num(pmpcfg_csr) & cfgmask);
@@ -258,12 +316,9 @@ int pmp_get(unsigned int n, unsigned long *prot_out, unsigned long *addr_out,
pmpcfg_csr = (CSR_PMPCFG0 + (n >> 2)) & ~1;
pmpcfg_shift = (n & 7) << 3;
#else
pmpcfg_csr = -1;
pmpcfg_shift = -1;
# error "Unexpected __riscv_xlen"
#endif
pmpaddr_csr = CSR_PMPADDR0 + n;
if (pmpcfg_csr < 0 || pmpcfg_shift < 0)
return SBI_ENOTSUPP;
/* decode PMP config */
cfgmask = (0xffUL << pmpcfg_shift);

View File

@@ -28,25 +28,23 @@ void atomic_write(atomic_t *atom, long value)
long atomic_add_return(atomic_t *atom, long value)
{
long ret;
#if __SIZEOF_LONG__ == 4
__asm__ __volatile__(" amoadd.w.aqrl %1, %2, %0"
: "+A"(atom->counter), "=r"(ret)
: "r"(value)
: "memory");
#elif __SIZEOF_LONG__ == 8
__asm__ __volatile__(" amoadd.d.aqrl %1, %2, %0"
: "+A"(atom->counter), "=r"(ret)
: "r"(value)
: "memory");
#endif
return ret + value;
}
long atomic_sub_return(atomic_t *atom, long value)
{
long ret;
__asm__ __volatile__(" amoadd.w.aqrl %1, %2, %0"
: "+A"(atom->counter), "=r"(ret)
: "r"(-value)
: "memory");
return ret - value;
return atomic_add_return(atom, -value);
}
#define __axchg(ptr, new, size) \

View File

@@ -2,44 +2,76 @@
* SPDX-License-Identifier: BSD-2-Clause
*
* Copyright (c) 2019 Western Digital Corporation or its affiliates.
*
* Authors:
* Anup Patel <anup.patel@wdc.com>
* Copyright (c) 2021 Christoph Müllner <cmuellner@linux.com>
*/
#include <sbi/riscv_barrier.h>
#include <sbi/riscv_locks.h>
int spin_lock_check(spinlock_t *lock)
static inline bool spin_lock_unlocked(spinlock_t lock)
{
return (lock->lock == __RISCV_SPIN_UNLOCKED) ? 0 : 1;
return lock.owner == lock.next;
}
int spin_trylock(spinlock_t *lock)
bool spin_lock_check(spinlock_t *lock)
{
int tmp = 1, busy;
RISCV_FENCE(r, rw);
return !spin_lock_unlocked(*lock);
}
bool spin_trylock(spinlock_t *lock)
{
unsigned long inc = 1u << TICKET_SHIFT;
unsigned long mask = 0xffffu << TICKET_SHIFT;
u32 l0, tmp1, tmp2;
__asm__ __volatile__(
" amoswap.w %0, %2, %1\n" RISCV_ACQUIRE_BARRIER
: "=r"(busy), "+A"(lock->lock)
: "r"(tmp)
/* Get the current lock counters. */
"1: lr.w.aq %0, %3\n"
" slli %2, %0, %6\n"
" and %2, %2, %5\n"
" and %1, %0, %5\n"
/* Is the lock free right now? */
" bne %1, %2, 2f\n"
" add %0, %0, %4\n"
/* Acquire the lock. */
" sc.w.rl %0, %0, %3\n"
" bnez %0, 1b\n"
"2:"
: "=&r"(l0), "=&r"(tmp1), "=&r"(tmp2), "+A"(*lock)
: "r"(inc), "r"(mask), "I"(TICKET_SHIFT)
: "memory");
return !busy;
return l0 == 0;
}
void spin_lock(spinlock_t *lock)
{
while (1) {
if (spin_lock_check(lock))
continue;
unsigned long inc = 1u << TICKET_SHIFT;
unsigned long mask = 0xffffu;
u32 l0, tmp1, tmp2;
if (spin_trylock(lock))
break;
}
__asm__ __volatile__(
/* Atomically increment the next ticket. */
" amoadd.w.aqrl %0, %4, %3\n"
/* Did we get the lock? */
" srli %1, %0, %6\n"
" and %1, %1, %5\n"
"1: and %2, %0, %5\n"
" beq %1, %2, 2f\n"
/* If not, then spin on the lock. */
" lw %0, %3\n"
RISCV_ACQUIRE_BARRIER
" j 1b\n"
"2:"
: "=&r"(l0), "=&r"(tmp1), "=&r"(tmp2), "+A"(*lock)
: "r"(inc), "r"(mask), "I"(TICKET_SHIFT)
: "memory");
}
void spin_unlock(spinlock_t *lock)
{
__smp_store_release(&lock->lock, __RISCV_SPIN_UNLOCKED);
__smp_store_release(&lock->owner, lock->owner + 1);
}

View File

@@ -39,7 +39,7 @@ unsigned long find_first_bit(const unsigned long *addr,
if (tmp == 0UL) /* Are any bits set? */
return result + size; /* Nope. */
found:
return result + __ffs(tmp);
return result + sbi_ffs(tmp);
}
/**
@@ -69,7 +69,7 @@ unsigned long find_first_zero_bit(const unsigned long *addr,
if (tmp == ~0UL) /* Are any bits zero? */
return result + size; /* Nope. */
found:
return result + ffz(tmp);
return result + sbi_ffz(tmp);
}
/**
@@ -100,7 +100,7 @@ unsigned long find_last_bit(const unsigned long *addr,
tmp = addr[--words];
if (tmp) {
found:
return words * BITS_PER_LONG + __fls(tmp);
return words * BITS_PER_LONG + sbi_fls(tmp);
}
}
@@ -150,7 +150,7 @@ found_first:
if (tmp == 0UL) /* Are any bits set? */
return result + size; /* Nope. */
found_middle:
return result + __ffs(tmp);
return result + sbi_ffs(tmp);
}
/**
@@ -196,5 +196,5 @@ found_first:
if (tmp == ~0UL) /* Are any bits zero? */
return result + size; /* Nope. */
found_middle:
return result + ffz(tmp);
return result + sbi_ffz(tmp);
}

View File

@@ -9,10 +9,11 @@
#include <sbi/riscv_locks.h>
#include <sbi/sbi_console.h>
#include <sbi/sbi_hart.h>
#include <sbi/sbi_platform.h>
#include <sbi/sbi_scratch.h>
static const struct sbi_platform *console_plat = NULL;
static const struct sbi_console_device *console_dev = NULL;
static spinlock_t console_out_lock = SPIN_LOCK_INITIALIZER;
bool sbi_isprintable(char c)
@@ -26,14 +27,18 @@ bool sbi_isprintable(char c)
int sbi_getc(void)
{
return sbi_platform_console_getc(console_plat);
if (console_dev && console_dev->console_getc)
return console_dev->console_getc();
return -1;
}
void sbi_putc(char ch)
{
if (console_dev && console_dev->console_putc) {
if (ch == '\n')
sbi_platform_console_putc(console_plat, '\r');
sbi_platform_console_putc(console_plat, ch);
console_dev->console_putc('\r');
console_dev->console_putc(ch);
}
}
void sbi_puts(const char *str)
@@ -383,16 +388,43 @@ int sbi_dprintf(const char *format, ...)
struct sbi_scratch *scratch = sbi_scratch_thishart_ptr();
va_start(args, format);
if (scratch->options & SBI_SCRATCH_DEBUG_PRINTS)
if (scratch->options & SBI_SCRATCH_DEBUG_PRINTS) {
spin_lock(&console_out_lock);
retval = print(NULL, NULL, format, args);
spin_unlock(&console_out_lock);
}
va_end(args);
return retval;
}
void sbi_panic(const char *format, ...)
{
va_list args;
spin_lock(&console_out_lock);
va_start(args, format);
print(NULL, NULL, format, args);
va_end(args);
spin_unlock(&console_out_lock);
sbi_hart_hang();
}
const struct sbi_console_device *sbi_console_get_device(void)
{
return console_dev;
}
void sbi_console_set_device(const struct sbi_console_device *dev)
{
if (!dev || console_dev)
return;
console_dev = dev;
}
int sbi_console_init(struct sbi_scratch *scratch)
{
console_plat = sbi_platform_ptr(scratch);
return sbi_platform_console_init(console_plat);
return sbi_platform_console_init(sbi_platform_ptr(scratch));
}

View File

@@ -19,17 +19,17 @@
struct sbi_domain *hartid_to_domain_table[SBI_HARTMASK_MAX_BITS] = { 0 };
struct sbi_domain *domidx_to_domain_table[SBI_DOMAIN_MAX_INDEX] = { 0 };
static u32 domain_count = 0;
static bool domain_finalized = false;
static struct sbi_hartmask root_hmask = { 0 };
#define ROOT_FW_REGION 0
#define ROOT_ALL_REGION 1
#define ROOT_END_REGION 2
static struct sbi_domain_memregion root_memregs[ROOT_END_REGION + 1] = { 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 };
static struct sbi_domain root = {
struct sbi_domain root = {
.name = "root",
.possible_harts = &root_hmask,
.regions = root_memregs,
@@ -64,12 +64,41 @@ ulong sbi_domain_get_assigned_hartmask(const struct sbi_domain *dom,
return ret;
}
void sbi_domain_memregion_initfw(struct sbi_domain_memregion *reg)
static void domain_memregion_initfw(struct sbi_domain_memregion *reg)
{
if (!reg)
return;
sbi_memcpy(reg, &root_memregs[ROOT_FW_REGION], sizeof(*reg));
sbi_memcpy(reg, &root_fw_region, sizeof(*reg));
}
void sbi_domain_memregion_init(unsigned long addr,
unsigned long size,
unsigned long flags,
struct sbi_domain_memregion *reg)
{
unsigned long base = 0, order;
for (order = log2roundup(size) ; order <= __riscv_xlen; order++) {
if (order < __riscv_xlen) {
base = addr & ~((1UL << order) - 1UL);
if ((base <= addr) &&
(addr < (base + (1UL << order))) &&
(base <= (addr + size - 1UL)) &&
((addr + size - 1UL) < (base + (1UL << order))))
break;
} else {
base = 0;
break;
}
}
if (reg) {
reg->base = base;
reg->order = order;
reg->flags = flags;
}
}
bool sbi_domain_check_addr(const struct sbi_domain *dom,
@@ -130,7 +159,7 @@ static bool is_region_subset(const struct sbi_domain_memregion *regA,
ulong regA_start = regA->base;
ulong regA_end = regA->base + (BIT(regA->order) - 1);
ulong regB_start = regB->base;
ulong regB_end = regB->base + (BIT(regA->order) - 1);
ulong regB_end = regB->base + (BIT(regB->order) - 1);
if ((regB_start <= regA_start) &&
(regA_start < regB_end) &&
@@ -207,9 +236,9 @@ static int sanitize_domain(const struct sbi_platform *plat,
count = 0;
have_fw_reg = FALSE;
sbi_domain_for_each_memregion(dom, reg) {
if (reg->order == root_memregs[ROOT_FW_REGION].order &&
reg->base == root_memregs[ROOT_FW_REGION].base &&
reg->flags == root_memregs[ROOT_FW_REGION].flags)
if (reg->order == root_fw_region.order &&
reg->base == root_fw_region.base &&
reg->flags == root_fw_region.flags)
have_fw_reg = TRUE;
count++;
}
@@ -266,7 +295,7 @@ static int sanitize_domain(const struct sbi_platform *plat,
/* 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 addres 0x%lx can't "
sbi_printf("%s: %s next booting stage address 0x%lx can't "
"execute\n", __func__, dom->name, dom->next_addr);
return SBI_EINVAL;
}
@@ -299,11 +328,7 @@ void sbi_domain_dump(const struct sbi_domain *dom, const char *suffix)
rend = (reg->order < __riscv_xlen) ?
rstart + ((1UL << reg->order) - 1) : -1UL;
#if __riscv_xlen == 32
sbi_printf("Domain%d Region%02d %s: 0x%08lx-0x%08lx ",
#else
sbi_printf("Domain%d Region%02d %s: 0x%016lx-0x%016lx ",
#endif
sbi_printf("Domain%d Region%02d %s: 0x%" PRILX "-0x%" PRILX " ",
dom->index, i, suffix, rstart, rend);
k = 0;
@@ -322,18 +347,10 @@ void sbi_domain_dump(const struct sbi_domain *dom, const char *suffix)
i++;
}
#if __riscv_xlen == 32
sbi_printf("Domain%d Next Address%s: 0x%08lx\n",
#else
sbi_printf("Domain%d Next Address%s: 0x%016lx\n",
#endif
sbi_printf("Domain%d Next Address%s: 0x%" PRILX "\n",
dom->index, suffix, dom->next_addr);
#if __riscv_xlen == 32
sbi_printf("Domain%d Next Arg1 %s: 0x%08lx\n",
#else
sbi_printf("Domain%d Next Arg1 %s: 0x%016lx\n",
#endif
sbi_printf("Domain%d Next Arg1 %s: 0x%" PRILX "\n",
dom->index, suffix, dom->next_arg1);
sbi_printf("Domain%d Next Mode %s: ", dom->index, suffix);
@@ -376,7 +393,8 @@ int sbi_domain_register(struct sbi_domain *dom,
u32 cold_hartid = current_hartid();
const struct sbi_platform *plat = sbi_platform_thishart_ptr();
if (!dom || !assign_mask)
/* Sanity checks */
if (!dom || !assign_mask || domain_finalized)
return SBI_EINVAL;
/* Check if domain already discovered */
@@ -438,6 +456,72 @@ int sbi_domain_register(struct sbi_domain *dom,
return 0;
}
int sbi_domain_root_add_memregion(const struct sbi_domain_memregion *reg)
{
int rc;
bool reg_merged;
struct sbi_domain_memregion *nreg, *nreg1, *nreg2;
const struct sbi_platform *plat = sbi_platform_thishart_ptr();
/* Sanity checks */
if (!reg || domain_finalized ||
(root.regions != root_memregs) ||
(ROOT_REGION_MAX <= root_memregs_count))
return SBI_EINVAL;
/* Check for conflicts */
sbi_domain_for_each_memregion(&root, nreg) {
if (is_region_conflict(reg, nreg)) {
sbi_printf("%s: is_region_conflict check failed"
" 0x%lx conflicts existing 0x%lx\n", __func__,
reg->base, nreg->base);
return SBI_EALREADY;
}
}
/* Append the memregion to root memregions */
nreg = &root_memregs[root_memregs_count];
sbi_memcpy(nreg, reg, sizeof(*reg));
root_memregs_count++;
root_memregs[root_memregs_count].order = 0;
/* Sort and optimize root regions */
do {
/* Sanitize the root domain so that memregions are sorted */
rc = sanitize_domain(plat, &root);
if (rc) {
sbi_printf("%s: sanity checks failed for"
" %s (error %d)\n", __func__,
root.name, rc);
return rc;
}
/* Merge consecutive memregions with same order and flags */
reg_merged = false;
sbi_domain_for_each_memregion(&root, nreg) {
nreg1 = nreg + 1;
if (!nreg1->order)
continue;
if (!(nreg->base & (BIT(nreg->order + 1) - 1)) &&
(nreg->base + BIT(nreg->order)) == nreg1->base &&
nreg->order == nreg1->order &&
nreg->flags == nreg1->flags) {
nreg->order++;
while (nreg1->order) {
nreg2 = nreg1 + 1;
sbi_memcpy(nreg1, nreg2, sizeof(*nreg1));
nreg1++;
}
reg_merged = true;
root_memregs_count--;
}
}
} while (reg_merged);
return 0;
}
int sbi_domain_finalize(struct sbi_scratch *scratch, u32 cold_hartid)
{
int rc;
@@ -490,35 +574,34 @@ int sbi_domain_finalize(struct sbi_scratch *scratch, u32 cold_hartid)
}
}
/*
* Set the finalized flag so that the root domain
* regions can't be changed.
*/
domain_finalized = true;
return 0;
}
int sbi_domain_init(struct sbi_scratch *scratch, u32 cold_hartid)
{
u32 i;
struct sbi_domain_memregion *memregs;
const struct sbi_platform *plat = sbi_platform_ptr(scratch);
/* Root domain firmware memory region */
root_memregs[ROOT_FW_REGION].order = log2roundup(scratch->fw_size);
root_memregs[ROOT_FW_REGION].base = scratch->fw_start &
~((1UL << root_memregs[0].order) - 1UL);
root_memregs[ROOT_FW_REGION].flags = 0;
sbi_domain_memregion_init(scratch->fw_start, scratch->fw_size, 0,
&root_fw_region);
domain_memregion_initfw(&root_memregs[root_memregs_count++]);
/* Root domain allow everything memory region */
root_memregs[ROOT_ALL_REGION].order = __riscv_xlen;
root_memregs[ROOT_ALL_REGION].base = 0;
root_memregs[ROOT_ALL_REGION].flags = (SBI_DOMAIN_MEMREGION_READABLE |
sbi_domain_memregion_init(0, ~0UL,
(SBI_DOMAIN_MEMREGION_READABLE |
SBI_DOMAIN_MEMREGION_WRITEABLE |
SBI_DOMAIN_MEMREGION_EXECUTABLE);
SBI_DOMAIN_MEMREGION_EXECUTABLE),
&root_memregs[root_memregs_count++]);
/* Root domain memory region end */
root_memregs[ROOT_END_REGION].order = 0;
/* Use platform specific root memory regions when available */
memregs = sbi_platform_domains_root_regions(plat);
if (memregs)
root.regions = memregs;
root_memregs[root_memregs_count].order = 0;
/* Root domain boot HART id is same as coldboot HART id */
root.boot_hartid = cold_hartid;

View File

@@ -162,6 +162,9 @@ int sbi_ecall_init(void)
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);

View File

@@ -22,14 +22,13 @@ static int sbi_ecall_hsm_handler(unsigned long extid, unsigned long funcid,
unsigned long *out_val,
struct sbi_trap_info *out_trap)
{
ulong smode;
int ret = 0, hstate;
int ret = 0;
struct sbi_scratch *scratch = sbi_scratch_thishart_ptr();
ulong smode = (csr_read(CSR_MSTATUS) & MSTATUS_MPP) >>
MSTATUS_MPP_SHIFT;
switch (funcid) {
case SBI_EXT_HSM_HART_START:
smode = csr_read(CSR_MSTATUS);
smode = (smode & MSTATUS_MPP) >> MSTATUS_MPP_SHIFT;
ret = sbi_hsm_hart_start(scratch, sbi_domain_thishart_ptr(),
regs->a0, regs->a1, smode, regs->a2);
break;
@@ -37,9 +36,12 @@ static int sbi_ecall_hsm_handler(unsigned long extid, unsigned long funcid,
ret = sbi_hsm_hart_stop(scratch, TRUE);
break;
case SBI_EXT_HSM_HART_GET_STATUS:
hstate = sbi_hsm_hart_get_state(sbi_domain_thishart_ptr(),
ret = sbi_hsm_hart_get_state(sbi_domain_thishart_ptr(),
regs->a0);
ret = sbi_hsm_hart_state_to_status(hstate);
break;
case SBI_EXT_HSM_HART_SUSPEND:
ret = sbi_hsm_hart_suspend(scratch, regs->a0, regs->a1,
smode, regs->a2);
break;
default:
ret = SBI_ENOTSUPP;

View File

@@ -34,7 +34,7 @@ static int sbi_load_hart_mask_unpriv(ulong *pmask, ulong *hmask,
if (uptrap->cause)
return SBI_ETRAP;
} else {
sbi_hsm_hart_started_mask(sbi_domain_thishart_ptr(),
sbi_hsm_hart_interruptible_mask(sbi_domain_thishart_ptr(),
0, &mask);
}
*hmask = mask;

87
lib/sbi/sbi_ecall_pmu.c Normal file
View File

@@ -0,0 +1,87 @@
/*
* SPDX-License-Identifier: BSD-2-Clause
*
* Copyright (c) 2021 Western Digital Corporation or its affiliates.
*
* Authors:
* Atish Patra <atish.patra@wdc.com>
*/
#include <sbi/sbi_ecall.h>
#include <sbi/sbi_ecall_interface.h>
#include <sbi/sbi_error.h>
#include <sbi/sbi_hart.h>
#include <sbi/sbi_trap.h>
#include <sbi/sbi_version.h>
#include <sbi/sbi_pmu.h>
#include <sbi/sbi_scratch.h>
#include <sbi/riscv_asm.h>
static int sbi_ecall_pmu_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_PMU_NUM_COUNTERS:
ret = sbi_pmu_num_ctr();
if (ret >= 0) {
*out_val = ret;
ret = 0;
}
break;
case SBI_EXT_PMU_COUNTER_GET_INFO:
ret = sbi_pmu_ctr_get_info(regs->a0, out_val);
break;
case SBI_EXT_PMU_COUNTER_CFG_MATCH:
#if __riscv_xlen == 32
temp = ((uint64_t)regs->a5 << 32) | regs->a4;
#else
temp = regs->a4;
#endif
ret = sbi_pmu_ctr_cfg_match(regs->a0, regs->a1, regs->a2,
regs->a3, temp);
if (ret >= 0) {
*out_val = ret;
ret = 0;
}
break;
case SBI_EXT_PMU_COUNTER_FW_READ:
ret = sbi_pmu_ctr_read(regs->a0, out_val);
break;
case SBI_EXT_PMU_COUNTER_START:
#if __riscv_xlen == 32
temp = ((uint64_t)regs->a4 << 32) | regs->a3;
#else
temp = regs->a3;
#endif
ret = sbi_pmu_ctr_start(regs->a0, regs->a1, regs->a2, temp);
break;
case SBI_EXT_PMU_COUNTER_STOP:
ret = sbi_pmu_ctr_stop(regs->a0, regs->a1, regs->a2);
break;
default:
ret = SBI_ENOTSUPP;
};
return ret;
}
static int sbi_ecall_pmu_probe(unsigned long extid, unsigned long *out_val)
{
/* PMU extension is always enabled */
*out_val = 1;
return 0;
}
struct sbi_ecall_extension ecall_pmu = {
.extid_start = SBI_EXT_PMU,
.extid_end = SBI_EXT_PMU,
.handle = sbi_ecall_pmu_handler,
.probe = sbi_ecall_pmu_probe,
};

View File

@@ -54,8 +54,8 @@ static int sbi_ecall_rfence_handler(unsigned long extid, unsigned long funcid,
struct sbi_tlb_info tlb_info;
u32 source_hart = current_hartid();
if (funcid >= SBI_EXT_RFENCE_REMOTE_HFENCE_GVMA &&
funcid <= SBI_EXT_RFENCE_REMOTE_HFENCE_VVMA_ASID)
if (funcid >= SBI_EXT_RFENCE_REMOTE_HFENCE_GVMA_VMID &&
funcid <= SBI_EXT_RFENCE_REMOTE_HFENCE_VVMA)
if (!misa_extension('H'))
return SBI_ENOTSUPP;
@@ -151,7 +151,7 @@ static int sbi_ecall_srst_handler(unsigned long extid, unsigned long funcid,
case SBI_SRST_RESET_TYPE_WARM_REBOOT:
break;
default:
return SBI_ENOTSUPP;
return SBI_EINVAL;
}
switch (regs->a1) {
@@ -159,7 +159,7 @@ static int sbi_ecall_srst_handler(unsigned long extid, unsigned long funcid,
case SBI_SRST_RESET_REASON_SYSFAIL:
break;
default:
return SBI_ENOTSUPP;
return SBI_EINVAL;
}
if (sbi_system_reset_supported(regs->a0, regs->a1))

View File

@@ -21,14 +21,23 @@
static bool hpm_allowed(int hpm_num, ulong prev_mode, bool virt)
{
ulong cen = -1UL;
struct sbi_scratch *scratch = sbi_scratch_thishart_ptr();
if (prev_mode <= PRV_S) {
if (sbi_hart_priv_version(scratch) >= SBI_HART_PRIV_VER_1_10) {
cen &= csr_read(CSR_MCOUNTEREN);
if (virt)
cen &= csr_read(CSR_HCOUNTEREN);
} else {
cen = 0;
}
if (prev_mode == PRV_U)
}
if (prev_mode == PRV_U) {
if (sbi_hart_priv_version(scratch) >= SBI_HART_PRIV_VER_1_10)
cen &= csr_read(CSR_SCOUNTEREN);
else
cen = 0;
}
return ((cen >> hpm_num) & 1) ? TRUE : FALSE;
}

View File

@@ -18,7 +18,7 @@ void sbi_fifo_init(struct sbi_fifo *fifo, void *queue_mem, u16 entries,
fifo->queue = queue_mem;
fifo->num_entries = entries;
fifo->entry_size = entry_size;
SPIN_LOCK_INIT(&fifo->qlock);
SPIN_LOCK_INIT(fifo->qlock);
fifo->avail = fifo->tail = 0;
sbi_memset(fifo->queue, 0, (size_t)entries * entry_size);
}
@@ -43,10 +43,13 @@ u16 sbi_fifo_avail(struct sbi_fifo *fifo)
return ret;
}
bool sbi_fifo_is_full(struct sbi_fifo *fifo)
int sbi_fifo_is_full(struct sbi_fifo *fifo)
{
bool ret;
if (!fifo)
return SBI_EINVAL;
spin_lock(&fifo->qlock);
ret = __sbi_fifo_is_full(fifo);
spin_unlock(&fifo->qlock);
@@ -63,7 +66,7 @@ static inline void __sbi_fifo_enqueue(struct sbi_fifo *fifo, void *data)
if (head >= fifo->num_entries)
head = head - fifo->num_entries;
sbi_memcpy(fifo->queue + head * fifo->entry_size, data, fifo->entry_size);
sbi_memcpy((char *)fifo->queue + head * fifo->entry_size, data, fifo->entry_size);
fifo->avail++;
}
@@ -75,10 +78,13 @@ static inline bool __sbi_fifo_is_empty(struct sbi_fifo *fifo)
return (fifo->avail == 0) ? TRUE : FALSE;
}
bool sbi_fifo_is_empty(struct sbi_fifo *fifo)
int sbi_fifo_is_empty(struct sbi_fifo *fifo)
{
bool ret;
if (!fifo)
return SBI_EINVAL;
spin_lock(&fifo->qlock);
ret = __sbi_fifo_is_empty(fifo);
spin_unlock(&fifo->qlock);
@@ -118,7 +124,7 @@ bool sbi_fifo_reset(struct sbi_fifo *fifo)
int sbi_fifo_inplace_update(struct sbi_fifo *fifo, void *in,
int (*fptr)(void *in, void *data))
{
int i, index = 0;
int i, index;
int ret = SBI_FIFO_UNCHANGED;
void *entry;
@@ -135,8 +141,8 @@ int sbi_fifo_inplace_update(struct sbi_fifo *fifo, void *in,
for (i = 0; i < fifo->avail; i++) {
index = fifo->tail + i;
if (index >= fifo->num_entries)
index = index - fifo->num_entries;
entry = (void *)fifo->queue + (u32)index * fifo->entry_size;
index -= fifo->num_entries;
entry = (char *)fifo->queue + (u32)index * fifo->entry_size;
ret = fptr(in, entry);
if (ret == SBI_FIFO_SKIP || ret == SBI_FIFO_UPDATED) {
@@ -178,7 +184,7 @@ int sbi_fifo_dequeue(struct sbi_fifo *fifo, void *data)
return SBI_ENOENT;
}
sbi_memcpy(data, fifo->queue + (u32)fifo->tail * fifo->entry_size,
sbi_memcpy(data, (char *)fifo->queue + (u32)fifo->tail * fifo->entry_size,
fifo->entry_size);
fifo->avail--;

View File

@@ -28,17 +28,24 @@ extern void __sbi_expected_trap_hext(void);
void (*sbi_hart_expected_trap)(void) = &__sbi_expected_trap;
struct hart_features {
unsigned long 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)
{
unsigned long mstatus_val = 0;
unsigned long menvcfg_val, mstatus_val = 0;
int cidx;
unsigned int num_mhpm = sbi_hart_mhpm_count(scratch);
uint64_t mhpmevent_init_val = 0;
uint64_t mstateen_val;
/* Enable FPU */
if (misa_extension('D') || misa_extension('F'))
@@ -50,13 +57,117 @@ static void mstatus_init(struct sbi_scratch *scratch)
csr_write(CSR_MSTATUS, mstatus_val);
/* Enable user/supervisor use of perf counters */
/* Disable user mode usage of all perf counters except default ones (CY, TM, IR) */
if (misa_extension('S') &&
sbi_hart_has_feature(scratch, SBI_HART_HAS_SCOUNTEREN))
csr_write(CSR_SCOUNTEREN, -1);
if (sbi_hart_has_feature(scratch, SBI_HART_HAS_MCOUNTEREN))
sbi_hart_priv_version(scratch) >= SBI_HART_PRIV_VER_1_10)
csr_write(CSR_SCOUNTEREN, 7);
/**
* OpenSBI doesn't use any PMU counters in M-mode.
* Supervisor mode usage for all counters are enabled by default
* But counters will not run until mcountinhibit is set.
*/
if (sbi_hart_priv_version(scratch) >= SBI_HART_PRIV_VER_1_10)
csr_write(CSR_MCOUNTEREN, -1);
/* All programmable counters will start running at runtime after S-mode request */
if (sbi_hart_priv_version(scratch) >= SBI_HART_PRIV_VER_1_11)
csr_write(CSR_MCOUNTINHIBIT, 0xFFFFFFF8);
/**
* The mhpmeventn[h] CSR should be initialized with interrupt disabled
* and inhibited running in M-mode during init.
* To keep it simple, only contiguous mhpmcounters are supported as a
* platform with discontiguous mhpmcounters may not make much sense.
*/
mhpmevent_init_val |= (MHPMEVENT_OF | MHPMEVENT_MINH);
for (cidx = 0; cidx < num_mhpm; cidx++) {
#if __riscv_xlen == 32
csr_write_num(CSR_MHPMEVENT3 + cidx, mhpmevent_init_val & 0xFFFFFFFF);
if (sbi_hart_has_extension(scratch, SBI_HART_EXT_SSCOFPMF))
csr_write_num(CSR_MHPMEVENT3H + cidx,
mhpmevent_init_val >> BITS_PER_LONG);
#else
csr_write_num(CSR_MHPMEVENT3 + cidx, mhpmevent_init_val);
#endif
}
if (sbi_hart_has_extension(scratch, SBI_HART_EXT_SMSTATEEN)) {
mstateen_val = csr_read(CSR_MSTATEEN0);
#if __riscv_xlen == 32
mstateen_val |= ((uint64_t)csr_read(CSR_MSTATEEN0H)) << 32;
#endif
mstateen_val |= SMSTATEEN_STATEN;
mstateen_val |= SMSTATEEN0_HSENVCFG;
if (sbi_hart_has_extension(scratch, SBI_HART_EXT_AIA))
mstateen_val |= (SMSTATEEN0_AIA | SMSTATEEN0_SVSLCT |
SMSTATEEN0_IMSIC);
else
mstateen_val &= ~(SMSTATEEN0_AIA | SMSTATEEN0_SVSLCT |
SMSTATEEN0_IMSIC);
csr_write(CSR_MSTATEEN0, mstateen_val);
#if __riscv_xlen == 32
csr_write(CSR_MSTATEEN0H, mstateen_val >> 32);
#endif
}
if (sbi_hart_priv_version(scratch) >= SBI_HART_PRIV_VER_1_12) {
menvcfg_val = csr_read(CSR_MENVCFG);
/*
* Set menvcfg.CBZE == 1
*
* If Zicboz extension is not available then writes to
* menvcfg.CBZE will be ignored because it is a WARL field.
*/
menvcfg_val |= ENVCFG_CBZE;
/*
* Set menvcfg.CBCFE == 1
*
* If Zicbom extension is not available then writes to
* menvcfg.CBCFE will be ignored because it is a WARL field.
*/
menvcfg_val |= ENVCFG_CBCFE;
/*
* Set menvcfg.CBIE == 3
*
* If Zicbom extension is not available then writes to
* menvcfg.CBIE will be ignored because it is a WARL field.
*/
menvcfg_val |= ENVCFG_CBIE_INV << ENVCFG_CBIE_SHIFT;
/*
* Set menvcfg.PBMTE == 1 for RV64 or RV128
*
* If Svpbmt extension is not available then menvcfg.PBMTE
* will be read-only zero.
*/
#if __riscv_xlen > 32
menvcfg_val |= ENVCFG_PBMTE;
#endif
/*
* The spec doesn't explicitly describe the reset value of menvcfg.
* Enable access to stimecmp if sstc extension is present in the
* hardware.
*/
if (sbi_hart_has_extension(scratch, SBI_HART_EXT_SSTC)) {
#if __riscv_xlen == 32
unsigned long menvcfgh_val;
menvcfgh_val = csr_read(CSR_MENVCFGH);
menvcfgh_val |= ENVCFGH_STCE;
csr_write(CSR_MENVCFGH, menvcfgh_val);
#else
menvcfg_val |= ENVCFG_STCE;
#endif
}
csr_write(CSR_MENVCFG, menvcfg_val);
}
/* Disable all interrupts */
csr_write(CSR_MIE, 0);
@@ -97,6 +208,9 @@ 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;
exceptions = (1U << CAUSE_MISALIGNED_FETCH) | (1U << CAUSE_BREAKPOINT) |
(1U << CAUSE_USER_ECALL);
if (sbi_platform_has_mfaults_delegation(plat))
@@ -132,17 +246,10 @@ void sbi_hart_delegation_dump(struct sbi_scratch *scratch,
/* No delegation possible as mideleg does not exist*/
return;
#if __riscv_xlen == 32
sbi_printf("%sMIDELEG%s: 0x%08lx\n",
sbi_printf("%sMIDELEG%s: 0x%" PRILX "\n",
prefix, suffix, csr_read(CSR_MIDELEG));
sbi_printf("%sMEDELEG%s: 0x%08lx\n",
sbi_printf("%sMEDELEG%s: 0x%" PRILX "\n",
prefix, suffix, csr_read(CSR_MEDELEG));
#else
sbi_printf("%sMIDELEG%s: 0x%016lx\n",
prefix, suffix, csr_read(CSR_MIDELEG));
sbi_printf("%sMEDELEG%s: 0x%016lx\n",
prefix, suffix, csr_read(CSR_MEDELEG));
#endif
}
unsigned int sbi_hart_mhpm_count(struct sbi_scratch *scratch)
@@ -177,6 +284,14 @@ unsigned int sbi_hart_pmp_addrbits(struct sbi_scratch *scratch)
return hfeatures->pmp_addr_bits;
}
unsigned int sbi_hart_mhpm_bits(struct sbi_scratch *scratch)
{
struct hart_features *hfeatures =
sbi_scratch_offset_ptr(scratch, hart_features_offset);
return hfeatures->mhpm_bits;
}
int sbi_hart_pmp_configure(struct sbi_scratch *scratch)
{
struct sbi_domain_memregion *reg;
@@ -219,97 +334,156 @@ int sbi_hart_pmp_configure(struct sbi_scratch *scratch)
return 0;
}
/**
* Check whether a particular hart feature is available
*
* @param scratch pointer to the HART scratch space
* @param feature the feature to check
* @returns true (feature available) or false (feature not available)
*/
bool sbi_hart_has_feature(struct sbi_scratch *scratch, unsigned long feature)
int sbi_hart_priv_version(struct sbi_scratch *scratch)
{
struct hart_features *hfeatures =
sbi_scratch_offset_ptr(scratch, hart_features_offset);
if (hfeatures->features & feature)
return hfeatures->priv_version;
}
void sbi_hart_get_priv_version_str(struct sbi_scratch *scratch,
char *version_str, int nvstr)
{
char *temp;
struct hart_features *hfeatures =
sbi_scratch_offset_ptr(scratch, hart_features_offset);
switch (hfeatures->priv_version) {
case SBI_HART_PRIV_VER_1_10:
temp = "v1.10";
break;
case SBI_HART_PRIV_VER_1_11:
temp = "v1.11";
break;
case SBI_HART_PRIV_VER_1_12:
temp = "v1.12";
break;
default:
temp = "unknown";
break;
}
sbi_snprintf(version_str, nvstr, "%s", temp);
}
static inline void __sbi_hart_update_extension(
struct hart_features *hfeatures,
enum sbi_hart_extensions ext,
bool enable)
{
if (enable)
hfeatures->extensions |= BIT(ext);
else
hfeatures->extensions &= ~BIT(ext);
}
/**
* Enable/Disable a particular hart extension
*
* @param scratch pointer to the HART scratch space
* @param ext the extension number to check
* @param enable new state of hart extension
*/
void sbi_hart_update_extension(struct sbi_scratch *scratch,
enum sbi_hart_extensions ext,
bool enable)
{
struct hart_features *hfeatures =
sbi_scratch_offset_ptr(scratch, hart_features_offset);
__sbi_hart_update_extension(hfeatures, ext, enable);
}
/**
* Check whether a particular hart extension is available
*
* @param scratch pointer to the HART scratch space
* @param ext the extension number to check
* @returns true (available) or false (not available)
*/
bool sbi_hart_has_extension(struct sbi_scratch *scratch,
enum sbi_hart_extensions ext)
{
struct hart_features *hfeatures =
sbi_scratch_offset_ptr(scratch, hart_features_offset);
if (hfeatures->extensions & BIT(ext))
return true;
else
return false;
}
static unsigned long hart_get_features(struct sbi_scratch *scratch)
static inline char *sbi_hart_extension_id2string(int ext)
{
struct hart_features *hfeatures =
sbi_scratch_offset_ptr(scratch, hart_features_offset);
char *estr = NULL;
return hfeatures->features;
}
static inline char *sbi_hart_feature_id2string(unsigned long feature)
{
char *fstr = NULL;
if (!feature)
return NULL;
switch (feature) {
case SBI_HART_HAS_SCOUNTEREN:
fstr = "scounteren";
switch (ext) {
case SBI_HART_EXT_SSCOFPMF:
estr = "sscofpmf";
break;
case SBI_HART_HAS_MCOUNTEREN:
fstr = "mcounteren";
case SBI_HART_EXT_TIME:
estr = "time";
break;
case SBI_HART_HAS_TIME:
fstr = "time";
case SBI_HART_EXT_AIA:
estr = "aia";
break;
case SBI_HART_EXT_SSTC:
estr = "sstc";
break;
case SBI_HART_EXT_SMSTATEEN:
estr = "smstateen";
break;
default:
break;
}
return fstr;
return estr;
}
/**
* Get the hart features in string format
* Get the hart extensions in string format
*
* @param scratch pointer to the HART scratch space
* @param features_str pointer to a char array where the features string will be
* updated
* @param nfstr length of the features_str. The feature string will be truncated
* if nfstr is not long enough.
* @param extensions_str pointer to a char array where the extensions string
* will be updated
* @param nestr length of the features_str. The feature string will be
* truncated if nestr is not long enough.
*/
void sbi_hart_get_features_str(struct sbi_scratch *scratch,
char *features_str, int nfstr)
void sbi_hart_get_extensions_str(struct sbi_scratch *scratch,
char *extensions_str, int nestr)
{
unsigned long features, feat = 1UL;
struct hart_features *hfeatures =
sbi_scratch_offset_ptr(scratch, hart_features_offset);
int offset = 0, ext = 0;
char *temp;
int offset = 0;
if (!features_str || nfstr <= 0)
if (!extensions_str || nestr <= 0)
return;
sbi_memset(features_str, 0, nfstr);
sbi_memset(extensions_str, 0, nestr);
features = hart_get_features(scratch);
if (!features)
if (!hfeatures->extensions)
goto done;
do {
if (features & feat) {
temp = sbi_hart_feature_id2string(feat);
if (hfeatures->extensions & BIT(ext)) {
temp = sbi_hart_extension_id2string(ext);
if (temp) {
sbi_snprintf(features_str + offset, nfstr,
sbi_snprintf(extensions_str + offset,
nestr - offset,
"%s,", temp);
offset = offset + sbi_strlen(temp) + 1;
}
}
feat = feat << 1;
} while (feat <= SBI_HART_HAS_LAST_FEATURE);
ext++;
} while (ext < SBI_HART_EXT_MAX);
done:
if (offset)
features_str[offset - 1] = '\0';
extensions_str[offset - 1] = '\0';
else
sbi_strncpy(features_str, "none", nfstr);
sbi_strncpy(extensions_str, "none", nestr);
}
static unsigned long hart_pmp_get_allowed_addr(void)
@@ -317,7 +491,11 @@ static unsigned long hart_pmp_get_allowed_addr(void)
unsigned long val = 0;
struct sbi_trap_info trap = {0};
csr_write_allowed(CSR_PMPADDR0, (ulong)&trap, PMP_ADDR_MASK); \
csr_write_allowed(CSR_PMPCFG0, (ulong)&trap, 0);
if (trap.cause)
return 0;
csr_write_allowed(CSR_PMPADDR0, (ulong)&trap, PMP_ADDR_MASK);
if (!trap.cause) {
val = csr_read_allowed(CSR_PMPADDR0, (ulong)&trap);
if (trap.cause)
@@ -327,27 +505,63 @@ static unsigned long hart_pmp_get_allowed_addr(void)
return val;
}
static void hart_detect_features(struct sbi_scratch *scratch)
static int hart_pmu_get_allowed_bits(void)
{
unsigned long val = ~(0UL);
struct sbi_trap_info trap = {0};
int num_bits = 0;
/**
* It is assumed that platforms will implement same number of bits for
* all the performance counters including mcycle/minstret.
*/
csr_write_allowed(CSR_MHPMCOUNTER3, (ulong)&trap, val);
if (!trap.cause) {
val = csr_read_allowed(CSR_MHPMCOUNTER3, (ulong)&trap);
if (trap.cause)
return 0;
}
num_bits = sbi_fls(val) + 1;
#if __riscv_xlen == 32
csr_write_allowed(CSR_MHPMCOUNTER3H, (ulong)&trap, val);
if (!trap.cause) {
val = csr_read_allowed(CSR_MHPMCOUNTER3H, (ulong)&trap);
if (trap.cause)
return num_bits;
}
num_bits += sbi_fls(val) + 1;
#endif
return num_bits;
}
static int hart_detect_features(struct sbi_scratch *scratch)
{
struct sbi_trap_info trap = {0};
struct hart_features *hfeatures;
unsigned long val;
struct hart_features *hfeatures =
sbi_scratch_offset_ptr(scratch, hart_features_offset);
unsigned long val, oldval;
int rc;
/* Reset hart features */
hfeatures = sbi_scratch_offset_ptr(scratch, hart_features_offset);
hfeatures->features = 0;
/* If hart features already detected then do nothing */
if (hfeatures->detected)
return 0;
/* Clear hart features */
hfeatures->extensions = 0;
hfeatures->pmp_count = 0;
hfeatures->mhpm_count = 0;
#define __check_csr(__csr, __rdonly, __wrval, __field, __skip) \
val = csr_read_allowed(__csr, (ulong)&trap); \
oldval = csr_read_allowed(__csr, (ulong)&trap); \
if (!trap.cause) { \
if (__rdonly) { \
(hfeatures->__field)++; \
} else { \
csr_write_allowed(__csr, (ulong)&trap, __wrval);\
if (!trap.cause) { \
if (csr_swap(__csr, val) == __wrval) \
if (csr_swap(__csr, oldval) == __wrval) \
(hfeatures->__field)++; \
else \
goto __skip; \
@@ -383,8 +597,8 @@ static void hart_detect_features(struct sbi_scratch *scratch)
*/
val = hart_pmp_get_allowed_addr();
if (val) {
hfeatures->pmp_gran = 1 << (__ffs(val) + 2);
hfeatures->pmp_addr_bits = __fls(val) + 1;
hfeatures->pmp_gran = 1 << (sbi_ffs(val) + 2);
hfeatures->pmp_addr_bits = sbi_fls(val) + 1;
/* Detect number of PMP regions. At least PMPADDR0 should be implemented*/
__check_csr_64(CSR_PMPADDR0, 0, val, pmp_count, __pmp_skip);
}
@@ -392,9 +606,17 @@ __pmp_skip:
/* Detect number of MHPM counters */
__check_csr(CSR_MHPMCOUNTER3, 0, 1UL, mhpm_count, __mhpm_skip);
hfeatures->mhpm_bits = hart_pmu_get_allowed_bits();
__check_csr_4(CSR_MHPMCOUNTER4, 0, 1UL, mhpm_count, __mhpm_skip);
__check_csr_8(CSR_MHPMCOUNTER8, 0, 1UL, mhpm_count, __mhpm_skip);
__check_csr_16(CSR_MHPMCOUNTER16, 0, 1UL, mhpm_count, __mhpm_skip);
/**
* No need to check for MHPMCOUNTERH for RV32 as they are expected to be
* implemented if MHPMCOUNTER is implemented.
*/
__mhpm_skip:
#undef __check_csr_64
@@ -405,48 +627,75 @@ __mhpm_skip:
#undef __check_csr_2
#undef __check_csr
/* Detect if hart supports SCOUNTEREN feature */
trap.cause = 0;
val = csr_read_allowed(CSR_SCOUNTEREN, (unsigned long)&trap);
if (!trap.cause) {
csr_write_allowed(CSR_SCOUNTEREN, (unsigned long)&trap, val);
if (!trap.cause)
hfeatures->features |= SBI_HART_HAS_SCOUNTEREN;
}
/* Detect if hart supports MCOUNTEREN feature */
trap.cause = 0;
/* Detect if hart supports Priv v1.10 */
val = csr_read_allowed(CSR_MCOUNTEREN, (unsigned long)&trap);
if (!trap.cause) {
csr_write_allowed(CSR_MCOUNTEREN, (unsigned long)&trap, val);
if (!trap.cause)
hfeatures->features |= SBI_HART_HAS_MCOUNTEREN;
hfeatures->priv_version = SBI_HART_PRIV_VER_1_10;
/* Detect if hart supports Priv v1.11 */
val = csr_read_allowed(CSR_MCOUNTINHIBIT, (unsigned long)&trap);
if (!trap.cause &&
(hfeatures->priv_version >= SBI_HART_PRIV_VER_1_10))
hfeatures->priv_version = SBI_HART_PRIV_VER_1_11;
/* Detect if hart supports Priv v1.12 */
csr_read_allowed(CSR_MENVCFG, (unsigned long)&trap);
if (!trap.cause &&
(hfeatures->priv_version >= SBI_HART_PRIV_VER_1_11))
hfeatures->priv_version = SBI_HART_PRIV_VER_1_12;
/* Counter overflow/filtering is not useful without mcounter/inhibit */
if (hfeatures->priv_version >= SBI_HART_PRIV_VER_1_12) {
/* Detect if hart supports sscofpmf */
csr_read_allowed(CSR_SCOUNTOVF, (unsigned long)&trap);
if (!trap.cause)
__sbi_hart_update_extension(hfeatures,
SBI_HART_EXT_SSCOFPMF, true);
}
/* Detect if hart supports time CSR */
trap.cause = 0;
csr_read_allowed(CSR_TIME, (unsigned long)&trap);
if (!trap.cause)
hfeatures->features |= SBI_HART_HAS_TIME;
__sbi_hart_update_extension(hfeatures,
SBI_HART_EXT_TIME, true);
/* Detect if hart has AIA local interrupt CSRs */
csr_read_allowed(CSR_MTOPI, (unsigned long)&trap);
if (!trap.cause)
__sbi_hart_update_extension(hfeatures,
SBI_HART_EXT_AIA, true);
/* Detect if hart supports stimecmp CSR(Sstc extension) */
if (hfeatures->priv_version >= SBI_HART_PRIV_VER_1_12) {
csr_read_allowed(CSR_STIMECMP, (unsigned long)&trap);
if (!trap.cause)
__sbi_hart_update_extension(hfeatures,
SBI_HART_EXT_SSTC, true);
}
int sbi_hart_init(struct sbi_scratch *scratch, bool cold_boot)
/* Detect if hart supports mstateen CSRs */
if (hfeatures->priv_version >= SBI_HART_PRIV_VER_1_12) {
val = csr_read_allowed(CSR_MSTATEEN0, (unsigned long)&trap);
if (!trap.cause)
__sbi_hart_update_extension(hfeatures,
SBI_HART_EXT_SMSTATEEN, true);
}
/* Let platform populate extensions */
rc = sbi_platform_extensions_init(sbi_platform_thishart_ptr());
if (rc)
return rc;
/* Mark hart feature detection done */
hfeatures->detected = true;
return 0;
}
int sbi_hart_reinit(struct sbi_scratch *scratch)
{
int rc;
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),
"HART_FEATURES");
if (!hart_features_offset)
return SBI_ENOMEM;
}
hart_detect_features(scratch);
mstatus_init(scratch);
rc = fp_init(scratch);
@@ -460,6 +709,27 @@ int sbi_hart_init(struct sbi_scratch *scratch, bool cold_boot)
return 0;
}
int sbi_hart_init(struct sbi_scratch *scratch, bool cold_boot)
{
int rc;
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));
if (!hart_features_offset)
return SBI_ENOMEM;
}
rc = hart_detect_features(scratch);
if (rc)
return rc;
return sbi_hart_reinit(scratch);
}
void __attribute__((noreturn)) sbi_hart_hang(void)
{
while (1)

View File

@@ -27,7 +27,7 @@
.global __sbi_hfence_gvma_vmid_gpa
__sbi_hfence_gvma_vmid_gpa:
/*
* rs1 = a0 (GPA)
* rs1 = a0 (GPA >> 2)
* rs2 = a1 (VMID)
* HFENCE.GVMA a0, a1
* 0110001 01011 01010 000 00000 1110011
@@ -51,7 +51,7 @@ __sbi_hfence_gvma_vmid:
.global __sbi_hfence_gvma_gpa
__sbi_hfence_gvma_gpa:
/*
* rs1 = a0 (GPA)
* rs1 = a0 (GPA >> 2)
* rs2 = zero
* HFENCE.GVMA a0
* 0110001 00000 01010 000 00000 1110011

View File

@@ -21,42 +21,22 @@
#include <sbi/sbi_hsm.h>
#include <sbi/sbi_init.h>
#include <sbi/sbi_ipi.h>
#include <sbi/sbi_platform.h>
#include <sbi/sbi_scratch.h>
#include <sbi/sbi_system.h>
#include <sbi/sbi_timer.h>
#include <sbi/sbi_console.h>
static const struct sbi_hsm_device *hsm_dev = NULL;
static unsigned long hart_data_offset;
/** Per hart specific data to manage state transition **/
struct sbi_hsm_data {
atomic_t state;
unsigned long suspend_type;
unsigned long saved_mie;
unsigned long saved_mip;
};
int sbi_hsm_hart_state_to_status(int state)
{
int ret;
switch (state) {
case SBI_HART_STOPPED:
ret = SBI_HSM_HART_STATUS_STOPPED;
break;
case SBI_HART_STOPPING:
ret = SBI_HSM_HART_STATUS_STOP_PENDING;
break;
case SBI_HART_STARTING:
ret = SBI_HSM_HART_STATUS_START_PENDING;
break;
case SBI_HART_STARTED:
ret = SBI_HSM_HART_STATUS_STARTED;
break;
default:
ret = SBI_EINVAL;
}
return ret;
}
static inline int __sbi_hsm_hart_get_state(u32 hartid)
{
struct sbi_hsm_data *hdata;
@@ -64,7 +44,7 @@ static inline int __sbi_hsm_hart_get_state(u32 hartid)
scratch = sbi_hartid_to_scratch(hartid);
if (!scratch)
return SBI_HART_UNKNOWN;
return SBI_EINVAL;
hdata = sbi_scratch_offset_ptr(scratch, hart_data_offset);
return atomic_read(&hdata->state);
@@ -73,19 +53,11 @@ static inline int __sbi_hsm_hart_get_state(u32 hartid)
int sbi_hsm_hart_get_state(const struct sbi_domain *dom, u32 hartid)
{
if (!sbi_domain_is_assigned_hart(dom, hartid))
return SBI_HART_UNKNOWN;
return SBI_EINVAL;
return __sbi_hsm_hart_get_state(hartid);
}
static bool sbi_hsm_hart_started(const struct sbi_domain *dom, u32 hartid)
{
if (sbi_hsm_hart_get_state(dom, hartid) == SBI_HART_STARTED)
return TRUE;
else
return FALSE;
}
/**
* Get ulong HART mask for given HART base ID
* @param dom the domain to be used for output HART mask
@@ -94,9 +66,10 @@ static bool sbi_hsm_hart_started(const struct sbi_domain *dom, u32 hartid)
* @return 0 on success and SBI_Exxx (< 0) on failure
* Note: the output HART mask will be set to zero on failure as well.
*/
int sbi_hsm_hart_started_mask(const struct sbi_domain *dom,
int sbi_hsm_hart_interruptible_mask(const struct sbi_domain *dom,
ulong hbase, ulong *out_hmask)
{
int hstate;
ulong i, hmask, dmask;
ulong hend = sbi_scratch_last_hartid() + 1;
@@ -109,10 +82,13 @@ int sbi_hsm_hart_started_mask(const struct sbi_domain *dom,
dmask = sbi_domain_get_assigned_hartmask(dom, hbase);
for (i = hbase; i < hend; i++) {
hmask = 1UL << (i - hbase);
if ((dmask & hmask) &&
(__sbi_hsm_hart_get_state(i) == SBI_HART_STARTED))
if (dmask & hmask) {
hstate = __sbi_hsm_hart_get_state(i);
if (hstate == SBI_HSM_STATE_STARTED ||
hstate == SBI_HSM_STATE_SUSPENDED)
*out_hmask |= hmask;
}
}
return 0;
}
@@ -123,34 +99,89 @@ void sbi_hsm_prepare_next_jump(struct sbi_scratch *scratch, u32 hartid)
struct sbi_hsm_data *hdata = sbi_scratch_offset_ptr(scratch,
hart_data_offset);
oldstate = atomic_cmpxchg(&hdata->state, SBI_HART_STARTING,
SBI_HART_STARTED);
if (oldstate != SBI_HART_STARTING)
oldstate = atomic_cmpxchg(&hdata->state, SBI_HSM_STATE_START_PENDING,
SBI_HSM_STATE_STARTED);
if (oldstate != SBI_HSM_STATE_START_PENDING)
sbi_hart_hang();
}
static void sbi_hsm_hart_wait(struct sbi_scratch *scratch, u32 hartid)
{
unsigned long saved_mie;
const struct sbi_platform *plat = sbi_platform_ptr(scratch);
struct sbi_hsm_data *hdata = sbi_scratch_offset_ptr(scratch,
hart_data_offset);
/* Save MIE CSR */
saved_mie = csr_read(CSR_MIE);
/* Set MSIE bit to receive IPI */
csr_set(CSR_MIE, MIP_MSIP);
/* Set MSIE and MEIE bits to receive IPI */
csr_set(CSR_MIE, MIP_MSIP | MIP_MEIP);
/* Wait for hart_add call*/
while (atomic_read(&hdata->state) != SBI_HART_STARTING) {
while (atomic_read(&hdata->state) != SBI_HSM_STATE_START_PENDING) {
wfi();
};
/* Restore MIE CSR */
csr_write(CSR_MIE, saved_mie);
/* Clear current HART IPI */
sbi_platform_ipi_clear(plat, hartid);
/*
* No need to clear IPI here because the sbi_ipi_init() will
* clear it for current HART via sbi_platform_ipi_init().
*/
}
const struct sbi_hsm_device *sbi_hsm_get_device(void)
{
return hsm_dev;
}
void sbi_hsm_set_device(const struct sbi_hsm_device *dev)
{
if (!dev || hsm_dev)
return;
hsm_dev = dev;
}
static bool hsm_device_has_hart_hotplug(void)
{
if (hsm_dev && hsm_dev->hart_start && hsm_dev->hart_stop)
return true;
return false;
}
static bool hsm_device_has_hart_secondary_boot(void)
{
if (hsm_dev && hsm_dev->hart_start && !hsm_dev->hart_stop)
return true;
return false;
}
static int hsm_device_hart_start(u32 hartid, ulong saddr)
{
if (hsm_dev && hsm_dev->hart_start)
return hsm_dev->hart_start(hartid, saddr);
return SBI_ENOTSUPP;
}
static int hsm_device_hart_stop(void)
{
if (hsm_dev && hsm_dev->hart_stop)
return hsm_dev->hart_stop();
return SBI_ENOTSUPP;
}
static int hsm_device_hart_suspend(u32 suspend_type)
{
if (hsm_dev && hsm_dev->hart_suspend)
return hsm_dev->hart_suspend(suspend_type);
return SBI_ENOTSUPP;
}
static void hsm_device_hart_resume(void)
{
if (hsm_dev && hsm_dev->hart_resume)
hsm_dev->hart_resume();
}
int sbi_hsm_init(struct sbi_scratch *scratch, u32 hartid, bool cold_boot)
@@ -160,8 +191,7 @@ int sbi_hsm_init(struct sbi_scratch *scratch, u32 hartid, bool cold_boot)
struct sbi_hsm_data *hdata;
if (cold_boot) {
hart_data_offset = sbi_scratch_alloc_offset(sizeof(*hdata),
"HART_DATA");
hart_data_offset = sbi_scratch_alloc_offset(sizeof(*hdata));
if (!hart_data_offset)
return SBI_ENOMEM;
@@ -174,7 +204,9 @@ int sbi_hsm_init(struct sbi_scratch *scratch, u32 hartid, bool cold_boot)
hdata = sbi_scratch_offset_ptr(rscratch,
hart_data_offset);
ATOMIC_INIT(&hdata->state,
(i == hartid) ? SBI_HART_STARTING : SBI_HART_STOPPED);
(i == hartid) ?
SBI_HSM_STATE_START_PENDING :
SBI_HSM_STATE_STOPPED);
}
} else {
sbi_hsm_hart_wait(scratch, hartid);
@@ -186,18 +218,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;
const struct sbi_platform *plat = sbi_platform_ptr(scratch);
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_HART_STOPPING,
SBI_HART_STOPPED);
if (hstate != SBI_HART_STOPPING)
hstate = atomic_cmpxchg(&hdata->state, SBI_HSM_STATE_STOP_PENDING,
SBI_HSM_STATE_STOPPED);
if (hstate != SBI_HSM_STATE_STOP_PENDING)
goto fail_exit;
if (sbi_platform_has_hart_hotplug(plat)) {
sbi_platform_hart_stop(plat);
if (hsm_device_has_hart_hotplug()) {
hsm_device_hart_stop();
/* It should never reach here */
goto fail_exit;
}
@@ -223,7 +254,6 @@ int sbi_hsm_hart_start(struct sbi_scratch *scratch,
unsigned int hstate;
struct sbi_scratch *rscratch;
struct sbi_hsm_data *hdata;
const struct sbi_platform *plat = sbi_platform_ptr(scratch);
/* For now, we only allow start mode to be S-mode or U-mode. */
if (smode != PRV_S && smode != PRV_U)
@@ -232,22 +262,22 @@ int sbi_hsm_hart_start(struct sbi_scratch *scratch,
return SBI_EINVAL;
if (dom && !sbi_domain_check_addr(dom, saddr, smode,
SBI_DOMAIN_EXECUTE))
return SBI_EINVAL;
return SBI_EINVALID_ADDR;
rscratch = sbi_hartid_to_scratch(hartid);
if (!rscratch)
return SBI_EINVAL;
hdata = sbi_scratch_offset_ptr(rscratch, hart_data_offset);
hstate = atomic_cmpxchg(&hdata->state, SBI_HART_STOPPED,
SBI_HART_STARTING);
if (hstate == SBI_HART_STARTED)
hstate = atomic_cmpxchg(&hdata->state, SBI_HSM_STATE_STOPPED,
SBI_HSM_STATE_START_PENDING);
if (hstate == SBI_HSM_STATE_STARTED)
return SBI_EALREADY;
/**
* if a hart is already transition to start or stop, another start call
* is considered as invalid request.
*/
if (hstate != SBI_HART_STOPPED)
if (hstate != SBI_HSM_STATE_STOPPED)
return SBI_EINVAL;
init_count = sbi_init_count(hartid);
@@ -255,12 +285,11 @@ int sbi_hsm_hart_start(struct sbi_scratch *scratch,
rscratch->next_addr = saddr;
rscratch->next_mode = smode;
if (sbi_platform_has_hart_hotplug(plat) ||
(sbi_platform_has_hart_secondary_boot(plat) && !init_count)) {
return sbi_platform_hart_start(plat, hartid,
scratch->warmboot_addr);
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_platform_ipi_send(plat, hartid);
sbi_ipi_raw_send(hartid);
}
return 0;
@@ -269,19 +298,19 @@ int sbi_hsm_hart_start(struct sbi_scratch *scratch,
int sbi_hsm_hart_stop(struct sbi_scratch *scratch, bool exitnow)
{
int oldstate;
u32 hartid = current_hartid();
const struct sbi_domain *dom = sbi_domain_thishart_ptr();
struct sbi_hsm_data *hdata = sbi_scratch_offset_ptr(scratch,
hart_data_offset);
if (!sbi_hsm_hart_started(sbi_domain_thishart_ptr(), hartid))
return SBI_EINVAL;
if (!dom)
return SBI_EFAIL;
oldstate = atomic_cmpxchg(&hdata->state, SBI_HART_STARTED,
SBI_HART_STOPPING);
if (oldstate != SBI_HART_STARTED) {
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);
return SBI_EDENIED;
return SBI_EFAIL;
}
if (exitnow)
@@ -289,3 +318,178 @@ int sbi_hsm_hart_stop(struct sbi_scratch *scratch, bool exitnow)
return 0;
}
static int __sbi_hsm_suspend_default(struct sbi_scratch *scratch)
{
/* Wait for interrupt */
wfi();
return 0;
}
static void __sbi_hsm_suspend_non_ret_save(struct sbi_scratch *scratch)
{
struct sbi_hsm_data *hdata = sbi_scratch_offset_ptr(scratch,
hart_data_offset);
/*
* We will be resuming in warm-boot path so the MIE and MIP CSRs
* will be back to initial state. It is possible that HART has
* configured timer event before going to suspend state so we
* should save MIE and MIP CSRs and restore it after resuming.
*
* Further, the M-mode bits in MIP CSR are read-only and set by
* external devices (such as interrupt controller) whereas all
* VS-mode bits in MIP are read-only alias of bits in HVIP CSR.
*
* This means we should only save/restore S-mode bits of MIP CSR
* such as MIP.SSIP and MIP.STIP.
*/
hdata->saved_mie = csr_read(CSR_MIE);
hdata->saved_mip = csr_read(CSR_MIP) & (MIP_SSIP | MIP_STIP);
}
static void __sbi_hsm_suspend_non_ret_restore(struct sbi_scratch *scratch)
{
struct sbi_hsm_data *hdata = sbi_scratch_offset_ptr(scratch,
hart_data_offset);
csr_write(CSR_MIE, hdata->saved_mie);
csr_write(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);
sbi_hart_hang();
}
hsm_device_hart_resume();
}
void sbi_hsm_hart_resume_finish(struct sbi_scratch *scratch)
{
u32 oldstate;
struct sbi_hsm_data *hdata = sbi_scratch_offset_ptr(scratch,
hart_data_offset);
/* If current HART was RESUME_PENDING then set STARTED state */
oldstate = atomic_cmpxchg(&hdata->state, SBI_HSM_STATE_RESUME_PENDING,
SBI_HSM_STATE_STARTED);
if (oldstate != SBI_HSM_STATE_RESUME_PENDING) {
sbi_printf("%s: ERR: The hart is in invalid state [%u]\n",
__func__, oldstate);
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);
}
int sbi_hsm_hart_suspend(struct sbi_scratch *scratch, u32 suspend_type,
ulong raddr, ulong rmode, ulong priv)
{
int oldstate, 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;
/* Sanity check on suspend type */
if (SBI_HSM_SUSPEND_RET_DEFAULT < suspend_type &&
suspend_type < SBI_HSM_SUSPEND_RET_PLATFORM)
return SBI_EINVAL;
if (SBI_HSM_SUSPEND_NON_RET_DEFAULT < suspend_type &&
suspend_type < SBI_HSM_SUSPEND_NON_RET_PLATFORM)
return SBI_EINVAL;
/* Additional sanity check for non-retentive suspend */
if (suspend_type & SBI_HSM_SUSP_NON_RET_BIT) {
if (rmode != PRV_S && rmode != PRV_U)
return SBI_EINVAL;
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_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;
}
/* Save the suspend type */
hdata->suspend_type = suspend_type;
/*
* Save context which will be restored after resuming from
* non-retentive suspend.
*/
if (suspend_type & SBI_HSM_SUSP_NON_RET_BIT)
__sbi_hsm_suspend_non_ret_save(scratch);
/* Try platform specific suspend */
ret = hsm_device_hart_suspend(suspend_type);
if (ret == SBI_ENOTSUPP) {
/* Try generic implementation of default suspend types */
if (suspend_type == SBI_HSM_SUSPEND_RET_DEFAULT ||
suspend_type == SBI_HSM_SUSPEND_NON_RET_DEFAULT) {
ret = __sbi_hsm_suspend_default(scratch);
}
}
/*
* The platform may have coordinated a retentive suspend, or it may
* have exited early from a non-retentive suspend. Either way, the
* caller is not expecting a successful return, so jump to the warm
* boot entry point to simulate resume from a non-retentive suspend.
*/
if (ret == 0 && (suspend_type & SBI_HSM_SUSP_NON_RET_BIT)) {
void (*jump_warmboot)(void) =
(void (*)(void))scratch->warmboot_addr;
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);
sbi_hart_hang();
}
return ret;
}

View File

@@ -8,13 +8,16 @@
*/
#include <sbi/riscv_asm.h>
#include <sbi/riscv_barrier.h>
#include <sbi/riscv_encoding.h>
#include <sbi/sbi_bitops.h>
#include <sbi/sbi_emulate_csr.h>
#include <sbi/sbi_error.h>
#include <sbi/sbi_illegal_insn.h>
#include <sbi/sbi_pmu.h>
#include <sbi/sbi_trap.h>
#include <sbi/sbi_unpriv.h>
#include <sbi/sbi_console.h>
typedef int (*illegal_insn_func)(ulong insn, struct sbi_trap_regs *regs);
@@ -31,13 +34,31 @@ static int truly_illegal_insn(ulong insn, struct sbi_trap_regs *regs)
return sbi_trap_redirect(regs, &trap);
}
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();
return 0;
}
return truly_illegal_insn(insn, regs);
}
static int system_opcode_insn(ulong insn, struct sbi_trap_regs *regs)
{
int do_write, rs1_num = (insn >> 15) & 0x1f;
ulong rs1_val = GET_RS1(insn, regs);
int csr_num = (u32)insn >> 20;
ulong prev_mode = (regs->mstatus & MSTATUS_MPP) >> MSTATUS_MPP_SHIFT;
ulong csr_val, new_csr_val;
if (prev_mode == PRV_M) {
sbi_printf("%s: Failed to access CSR %#x from M-mode",
__func__, csr_num);
return SBI_EFAIL;
}
/* TODO: Ensure that we got CSR read/write instruction */
if (sbi_emulate_csr_read(csr_num, regs, &csr_val))
@@ -79,11 +100,11 @@ static int system_opcode_insn(ulong insn, struct sbi_trap_regs *regs)
return 0;
}
static illegal_insn_func illegal_insn_table[32] = {
static const illegal_insn_func illegal_insn_table[32] = {
truly_illegal_insn, /* 0 */
truly_illegal_insn, /* 1 */
truly_illegal_insn, /* 2 */
truly_illegal_insn, /* 3 */
misc_mem_opcode_insn, /* 3 */
truly_illegal_insn, /* 4 */
truly_illegal_insn, /* 5 */
truly_illegal_insn, /* 6 */
@@ -129,6 +150,7 @@ int sbi_illegal_insn_handler(ulong insn, struct sbi_trap_regs *regs)
* instruction trap.
*/
sbi_pmu_ctr_incr_fw(SBI_PMU_FW_ILLEGAL_INSN);
if (unlikely((insn & 3) != 3)) {
insn = sbi_get_insn(regs->mepc, &uptrap);
if (uptrap.cause) {

View File

@@ -18,7 +18,9 @@
#include <sbi/sbi_hartmask.h>
#include <sbi/sbi_hsm.h>
#include <sbi/sbi_ipi.h>
#include <sbi/sbi_irqchip.h>
#include <sbi/sbi_platform.h>
#include <sbi/sbi_pmu.h>
#include <sbi/sbi_system.h>
#include <sbi/sbi_string.h>
#include <sbi/sbi_timer.h>
@@ -47,12 +49,25 @@ static void sbi_boot_print_banner(struct sbi_scratch *scratch)
OPENSBI_VERSION_MINOR);
#endif
#ifdef OPENSBI_BUILD_TIME_STAMP
sbi_printf("Build time: %s\n", OPENSBI_BUILD_TIME_STAMP);
#endif
#ifdef OPENSBI_BUILD_COMPILER_VERSION
sbi_printf("Build compiler: %s\n", OPENSBI_BUILD_COMPILER_VERSION);
#endif
sbi_printf(BANNER);
}
static void sbi_boot_print_general(struct sbi_scratch *scratch)
{
char str[128];
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_platform *plat = sbi_platform_ptr(scratch);
if (scratch->options & SBI_SCRATCH_NO_BOOT_PRINTS)
@@ -65,6 +80,25 @@ static void sbi_boot_print_general(struct sbi_scratch *scratch)
sbi_printf("Platform Features : %s\n", str);
sbi_printf("Platform HART Count : %u\n",
sbi_platform_hart_count(plat));
idev = sbi_ipi_get_device();
sbi_printf("Platform IPI Device : %s\n",
(idev) ? idev->name : "---");
tdev = sbi_timer_get_device();
sbi_printf("Platform Timer Device : %s @ %luHz\n",
(tdev) ? tdev->name : "---",
(tdev) ? tdev->timer_freq : 0);
cdev = sbi_console_get_device();
sbi_printf("Platform Console Device : %s\n",
(cdev) ? cdev->name : "---");
hdev = sbi_hsm_get_device();
sbi_printf("Platform HSM Device : %s\n",
(hdev) ? hdev->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 : "---");
/* Firmware details */
sbi_printf("Firmware Base : 0x%lx\n", scratch->fw_start);
@@ -105,10 +139,12 @@ static void sbi_boot_print_hart(struct sbi_scratch *scratch, u32 hartid)
/* Boot HART details */
sbi_printf("Boot HART ID : %u\n", hartid);
sbi_printf("Boot HART Domain : %s\n", dom->name);
sbi_hart_get_priv_version_str(scratch, str, sizeof(str));
sbi_printf("Boot HART Priv Version : %s\n", str);
misa_string(xlen, str, sizeof(str));
sbi_printf("Boot HART ISA : %s\n", str);
sbi_hart_get_features_str(scratch, str, sizeof(str));
sbi_printf("Boot HART Features : %s\n", str);
sbi_printf("Boot HART Base ISA : %s\n", str);
sbi_hart_get_extensions_str(scratch, str, sizeof(str));
sbi_printf("Boot HART ISA Extensions : %s\n", str);
sbi_printf("Boot HART PMP Count : %d\n",
sbi_hart_pmp_count(scratch));
sbi_printf("Boot HART PMP Granularity : %lu\n",
@@ -117,8 +153,6 @@ static void sbi_boot_print_hart(struct sbi_scratch *scratch, u32 hartid)
sbi_hart_pmp_addrbits(scratch));
sbi_printf("Boot HART MHPM Count : %d\n",
sbi_hart_mhpm_count(scratch));
sbi_printf("Boot HART MHPM Count : %d\n",
sbi_hart_mhpm_count(scratch));
sbi_hart_delegation_dump(scratch, "Boot HART ", " ");
}
@@ -130,13 +164,12 @@ static unsigned long coldboot_done;
static void wait_for_coldboot(struct sbi_scratch *scratch, u32 hartid)
{
unsigned long saved_mie, cmip;
const struct sbi_platform *plat = sbi_platform_ptr(scratch);
/* Save MIE CSR */
saved_mie = csr_read(CSR_MIE);
/* Set MSIE bit to receive IPI */
csr_set(CSR_MIE, MIP_MSIP);
/* Set MSIE and MEIE bits to receive IPI */
csr_set(CSR_MIE, MIP_MSIP | MIP_MEIP);
/* Acquire coldboot lock */
spin_lock(&coldboot_lock);
@@ -152,7 +185,7 @@ static void wait_for_coldboot(struct sbi_scratch *scratch, u32 hartid)
do {
wfi();
cmip = csr_read(CSR_MIP);
} while (!(cmip & MIP_MSIP));
} while (!(cmip & (MIP_MSIP | MIP_MEIP)));
};
/* Acquire coldboot lock */
@@ -167,14 +200,18 @@ static void wait_for_coldboot(struct sbi_scratch *scratch, u32 hartid)
/* Restore MIE CSR */
csr_write(CSR_MIE, saved_mie);
/* Clear current HART IPI */
sbi_platform_ipi_clear(plat, hartid);
/*
* The wait for coldboot is common for both warm startup and
* warm resume path so clearing IPI here would result in losing
* an IPI in warm resume path.
*
* Also, the sbi_platform_ipi_init() called from sbi_ipi_init()
* will automatically clear IPI for current HART.
*/
}
static void wake_coldboot_harts(struct sbi_scratch *scratch, u32 hartid)
{
const struct sbi_platform *plat = sbi_platform_ptr(scratch);
/* Mark coldboot done */
__smp_store_release(&coldboot_done, 1);
@@ -182,10 +219,10 @@ static void wake_coldboot_harts(struct sbi_scratch *scratch, u32 hartid)
spin_lock(&coldboot_lock);
/* Send an IPI to all HARTs waiting for coldboot */
for (int i = 0; i <= sbi_scratch_last_hartid(); i++) {
for (u32 i = 0; i <= sbi_scratch_last_hartid(); i++) {
if ((i != hartid) &&
sbi_hartmask_test_hart(i, &coldboot_wait_hmask))
sbi_platform_ipi_send(plat, i);
sbi_ipi_raw_send(i);
}
/* Release coldboot lock */
@@ -210,8 +247,7 @@ static void __noreturn init_coldboot(struct sbi_scratch *scratch, u32 hartid)
if (rc)
sbi_hart_hang();
init_count_offset = sbi_scratch_alloc_offset(__SIZEOF_POINTER__,
"INIT_COUNT");
init_count_offset = sbi_scratch_alloc_offset(__SIZEOF_POINTER__);
if (!init_count_offset)
sbi_hart_hang();
@@ -231,11 +267,15 @@ static void __noreturn init_coldboot(struct sbi_scratch *scratch, u32 hartid)
if (rc)
sbi_hart_hang();
rc = sbi_pmu_init(scratch, TRUE);
if (rc)
sbi_hart_hang();
sbi_boot_print_banner(scratch);
rc = sbi_platform_irqchip_init(plat, TRUE);
rc = sbi_irqchip_init(scratch, TRUE);
if (rc) {
sbi_printf("%s: platform irqchip init failed (error %d)\n",
sbi_printf("%s: irqchip init failed (error %d)\n",
__func__, rc);
sbi_hart_hang();
}
@@ -264,8 +304,6 @@ static void __noreturn init_coldboot(struct sbi_scratch *scratch, u32 hartid)
sbi_hart_hang();
}
sbi_boot_print_general(scratch);
/*
* Note: Finalize domains after HSM initialization so that we
* can startup non-root domains.
@@ -279,8 +317,6 @@ static void __noreturn init_coldboot(struct sbi_scratch *scratch, u32 hartid)
sbi_hart_hang();
}
sbi_boot_print_domains(scratch);
rc = sbi_hart_pmp_configure(scratch);
if (rc) {
sbi_printf("%s: PMP configure failed (error %d)\n",
@@ -299,6 +335,10 @@ static void __noreturn init_coldboot(struct sbi_scratch *scratch, u32 hartid)
sbi_hart_hang();
}
sbi_boot_print_general(scratch);
sbi_boot_print_domains(scratch);
sbi_boot_print_hart(scratch, hartid);
wake_coldboot_harts(scratch, hartid);
@@ -311,14 +351,12 @@ static void __noreturn init_coldboot(struct sbi_scratch *scratch, u32 hartid)
scratch->next_mode, FALSE);
}
static void __noreturn init_warmboot(struct sbi_scratch *scratch, u32 hartid)
static void init_warm_startup(struct sbi_scratch *scratch, u32 hartid)
{
int rc;
unsigned long *init_count;
const struct sbi_platform *plat = sbi_platform_ptr(scratch);
wait_for_coldboot(scratch, hartid);
if (!init_count_offset)
sbi_hart_hang();
@@ -334,7 +372,11 @@ static void __noreturn init_warmboot(struct sbi_scratch *scratch, u32 hartid)
if (rc)
sbi_hart_hang();
rc = sbi_platform_irqchip_init(plat, FALSE);
rc = sbi_pmu_init(scratch, FALSE);
if (rc)
sbi_hart_hang();
rc = sbi_irqchip_init(scratch, FALSE);
if (rc)
sbi_hart_hang();
@@ -362,6 +404,40 @@ static void __noreturn init_warmboot(struct sbi_scratch *scratch, u32 hartid)
(*init_count)++;
sbi_hsm_prepare_next_jump(scratch, hartid);
}
static void init_warm_resume(struct sbi_scratch *scratch)
{
int rc;
sbi_hsm_hart_resume_start(scratch);
rc = sbi_hart_reinit(scratch);
if (rc)
sbi_hart_hang();
rc = sbi_hart_pmp_configure(scratch);
if (rc)
sbi_hart_hang();
sbi_hsm_hart_resume_finish(scratch);
}
static void __noreturn init_warmboot(struct sbi_scratch *scratch, u32 hartid)
{
int hstate;
wait_for_coldboot(scratch, hartid);
hstate = sbi_hsm_hart_get_state(sbi_domain_thishart_ptr(), hartid);
if (hstate < 0)
sbi_hart_hang();
if (hstate == SBI_HSM_STATE_SUSPENDED)
init_warm_resume(scratch);
else
init_warm_startup(scratch, hartid);
sbi_hart_switch_mode(hartid, scratch->next_arg1,
scratch->next_addr,
scratch->next_mode, FALSE);
@@ -421,6 +497,14 @@ void __noreturn sbi_init(struct sbi_scratch *scratch)
if (next_mode_supported && atomic_xchg(&coldboot_lottery, 1) == 0)
coldboot = TRUE;
/*
* Do platform specific nascent (very early) initialization so
* that platform can initialize platform specific per-HART CSRs
* or per-HART devices.
*/
if (sbi_platform_nascent_init(plat))
sbi_hart_hang();
if (coldboot)
init_coldboot(scratch, hartid);
else
@@ -463,11 +547,13 @@ void __noreturn sbi_exit(struct sbi_scratch *scratch)
sbi_platform_early_exit(plat);
sbi_pmu_exit(scratch);
sbi_timer_exit(scratch);
sbi_ipi_exit(scratch);
sbi_platform_irqchip_exit(plat);
sbi_irqchip_exit(scratch);
sbi_platform_final_exit(plat);

View File

@@ -19,13 +19,16 @@
#include <sbi/sbi_init.h>
#include <sbi/sbi_ipi.h>
#include <sbi/sbi_platform.h>
#include <sbi/sbi_pmu.h>
#include <sbi/sbi_string.h>
#include <sbi/sbi_tlb.h>
struct sbi_ipi_data {
unsigned long ipi_type;
};
static unsigned long ipi_data_off;
static const struct sbi_ipi_device *ipi_dev = NULL;
static const struct sbi_ipi_event_ops *ipi_ops_array[SBI_IPI_EVENT_MAX];
static int sbi_ipi_send(struct sbi_scratch *scratch, u32 remote_hartid,
@@ -33,7 +36,6 @@ static int sbi_ipi_send(struct sbi_scratch *scratch, u32 remote_hartid,
{
int ret;
struct sbi_scratch *remote_scratch = NULL;
const struct sbi_platform *plat = sbi_platform_ptr(scratch);
struct sbi_ipi_data *ipi_data;
const struct sbi_ipi_event_ops *ipi_ops;
@@ -61,7 +63,11 @@ static int sbi_ipi_send(struct sbi_scratch *scratch, u32 remote_hartid,
*/
atomic_raw_set_bit(event, &ipi_data->ipi_type);
smp_wmb();
sbi_platform_ipi_send(plat, remote_hartid);
if (ipi_dev && ipi_dev->ipi_send)
ipi_dev->ipi_send(remote_hartid);
sbi_pmu_ctr_incr_fw(SBI_PMU_FW_IPI_SENT);
if (ipi_ops->sync)
ipi_ops->sync(scratch);
@@ -82,7 +88,7 @@ int sbi_ipi_send_many(ulong hmask, ulong hbase, u32 event, void *data)
struct sbi_scratch *scratch = sbi_scratch_thishart_ptr();
if (hbase != -1UL) {
rc = sbi_hsm_hart_started_mask(dom, hbase, &m);
rc = sbi_hsm_hart_interruptible_mask(dom, hbase, &m);
if (rc)
return rc;
m &= hmask;
@@ -94,7 +100,7 @@ int sbi_ipi_send_many(ulong hmask, ulong hbase, u32 event, void *data)
}
} else {
hbase = 0;
while (!sbi_hsm_hart_started_mask(dom, hbase, &m)) {
while (!sbi_hsm_hart_interruptible_mask(dom, hbase, &m)) {
/* Send IPIs */
for (i = hbase; m; i++, m >>= 1) {
if (m & 1UL)
@@ -178,12 +184,13 @@ void sbi_ipi_process(void)
unsigned int ipi_event;
const struct sbi_ipi_event_ops *ipi_ops;
struct sbi_scratch *scratch = sbi_scratch_thishart_ptr();
const struct sbi_platform *plat = sbi_platform_ptr(scratch);
struct sbi_ipi_data *ipi_data =
sbi_scratch_offset_ptr(scratch, ipi_data_off);
u32 hartid = current_hartid();
sbi_platform_ipi_clear(plat, hartid);
sbi_pmu_ctr_incr_fw(SBI_PMU_FW_IPI_RECVD);
if (ipi_dev && ipi_dev->ipi_clear)
ipi_dev->ipi_clear(hartid);
ipi_type = atomic_raw_xchg_ulong(&ipi_data->ipi_type, 0);
ipi_event = 0;
@@ -201,14 +208,32 @@ skip:
};
}
void sbi_ipi_raw_send(u32 target_hart)
{
if (ipi_dev && ipi_dev->ipi_send)
ipi_dev->ipi_send(target_hart);
}
const struct sbi_ipi_device *sbi_ipi_get_device(void)
{
return ipi_dev;
}
void sbi_ipi_set_device(const struct sbi_ipi_device *dev)
{
if (!dev || ipi_dev)
return;
ipi_dev = dev;
}
int sbi_ipi_init(struct sbi_scratch *scratch, bool cold_boot)
{
int ret;
struct sbi_ipi_data *ipi_data;
if (cold_boot) {
ipi_data_off = sbi_scratch_alloc_offset(sizeof(*ipi_data),
"IPI_DATA");
ipi_data_off = sbi_scratch_alloc_offset(sizeof(*ipi_data));
if (!ipi_data_off)
return SBI_ENOMEM;
ret = sbi_ipi_event_create(&ipi_smode_ops);
@@ -230,7 +255,10 @@ int sbi_ipi_init(struct sbi_scratch *scratch, bool cold_boot)
ipi_data = sbi_scratch_offset_ptr(scratch, ipi_data_off);
ipi_data->ipi_type = 0x00;
/* Platform init */
/*
* Initialize platform IPI support. This will also clear any
* pending IPIs for current/calling HART.
*/
ret = sbi_platform_ipi_init(sbi_platform_ptr(scratch), cold_boot);
if (ret)
return ret;

54
lib/sbi/sbi_irqchip.c Normal file
View File

@@ -0,0 +1,54 @@
/*
* SPDX-License-Identifier: BSD-2-Clause
*
* Copyright (c) 2022 Ventana Micro Systems Inc.
*
* Authors:
* Anup Patel <apatel@ventanamicro.com>
*/
#include <sbi/sbi_irqchip.h>
#include <sbi/sbi_platform.h>
static int default_irqfn(struct sbi_trap_regs *regs)
{
return SBI_ENODEV;
}
static int (*ext_irqfn)(struct sbi_trap_regs *regs) = default_irqfn;
void sbi_irqchip_set_irqfn(int (*fn)(struct sbi_trap_regs *regs))
{
if (fn)
ext_irqfn = fn;
}
int sbi_irqchip_process(struct sbi_trap_regs *regs)
{
return ext_irqfn(regs);
}
int sbi_irqchip_init(struct sbi_scratch *scratch, bool cold_boot)
{
int rc;
const struct sbi_platform *plat = sbi_platform_ptr(scratch);
rc = sbi_platform_irqchip_init(plat, cold_boot);
if (rc)
return rc;
if (ext_irqfn != default_irqfn)
csr_set(CSR_MIE, MIP_MEIP);
return 0;
}
void sbi_irqchip_exit(struct sbi_scratch *scratch)
{
const struct sbi_platform *plat = sbi_platform_ptr(scratch);
if (ext_irqfn != default_irqfn)
csr_clear(CSR_MIE, MIP_MEIP);
sbi_platform_irqchip_exit(plat);
}

View File

@@ -12,6 +12,7 @@
#include <sbi/riscv_fp.h>
#include <sbi/sbi_error.h>
#include <sbi/sbi_misaligned_ldst.h>
#include <sbi/sbi_pmu.h>
#include <sbi/sbi_trap.h>
#include <sbi/sbi_unpriv.h>
@@ -21,6 +22,18 @@ union reg_data {
u64 data_u64;
};
static ulong sbi_misaligned_tinst_fixup(ulong orig_tinst, ulong new_tinst,
ulong addr_offset)
{
if (new_tinst == INSN_PSEUDO_VS_LOAD ||
new_tinst == INSN_PSEUDO_VS_STORE)
return new_tinst;
else if (orig_tinst == 0)
return 0UL;
else
return orig_tinst | (addr_offset << SH_RS1);
}
int sbi_misaligned_load_handler(ulong addr, ulong tval2, ulong tinst,
struct sbi_trap_regs *regs)
{
@@ -29,6 +42,8 @@ int sbi_misaligned_load_handler(ulong addr, ulong tval2, ulong tinst,
struct sbi_trap_info uptrap;
int i, fp = 0, shift = 0, len = 0;
sbi_pmu_ctr_incr_fw(SBI_PMU_FW_MISALIGNED_LOAD);
if (tinst & 0x1) {
/*
* Bit[0] == 1 implies trapped instruction value is
@@ -123,6 +138,8 @@ int sbi_misaligned_load_handler(ulong addr, ulong tval2, ulong tinst,
&uptrap);
if (uptrap.cause) {
uptrap.epc = regs->mepc;
uptrap.tinst = sbi_misaligned_tinst_fixup(
tinst, uptrap.tinst, i);
return sbi_trap_redirect(regs, &uptrap);
}
}
@@ -149,6 +166,8 @@ int sbi_misaligned_store_handler(ulong addr, ulong tval2, ulong tinst,
struct sbi_trap_info uptrap;
int i, len = 0;
sbi_pmu_ctr_incr_fw(SBI_PMU_FW_MISALIGNED_STORE);
if (tinst & 0x1) {
/*
* Bit[0] == 1 implies trapped instruction value is
@@ -233,6 +252,8 @@ int sbi_misaligned_store_handler(ulong addr, ulong tval2, ulong tinst,
&uptrap);
if (uptrap.cause) {
uptrap.epc = regs->mepc;
uptrap.tinst = sbi_misaligned_tinst_fixup(
tinst, uptrap.tinst, i);
return sbi_trap_redirect(regs, &uptrap);
}
}

View File

@@ -19,17 +19,8 @@ static inline char *sbi_platform_feature_id2string(unsigned long feature)
return NULL;
switch (feature) {
case SBI_PLATFORM_HAS_TIMER_VALUE:
fstr = "timer";
break;
case SBI_PLATFORM_HAS_HART_HOTPLUG:
fstr = "hotplug";
break;
case SBI_PLATFORM_HAS_MFAULTS_DELEGATION:
fstr = "mfdeleg";
break;
case SBI_PLATFORM_HAS_HART_SECONDARY_BOOT:
fstr = "sec_boot";
fstr = "medeleg";
break;
default:
break;
@@ -57,9 +48,18 @@ void sbi_platform_get_features_str(const struct sbi_platform *plat,
if (features & feat) {
temp = sbi_platform_feature_id2string(feat);
if (temp) {
sbi_snprintf(features_str + offset, nfstr,
int len = sbi_snprintf(features_str + offset,
nfstr - offset,
"%s,", temp);
offset = offset + sbi_strlen(temp) + 1;
if (len < 0)
break;
if (offset + len >= nfstr) {
/* No more space for features */
offset = nfstr;
break;
} else
offset = offset + len;
}
}
feat = feat << 1;

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