157 Commits

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

Signed-off-by: Anup Patel <apatel@ventanamicro.com>
Signed-off-by: Anup Patel <anup@brainfault.org>
2023-12-27 12:32:58 +05:30
Anup Patel
bbd065d903 lib: sbi: Detect Zicntr extension only based on traps
OpenSBI uses time CSR if Zicntr extension present which causes
it to crash on an older QEMU because QEMU generates Zicntr in
the ISA string for unleashed machine which only has CYCLE and
INSTRET counters.

Fixes: 776770d2ad ("lib: sbi: Using one array to define the
name of extensions")
Signed-off-by: Anup Patel <apatel@ventanamicro.com>
Signed-off-by: Anup Patel <anup@brainfault.org>
2023-12-27 12:25:09 +05:30
Inochi Amaoto
ba29293dc9 lib: utils/timer: mtimer: only use regname for aclint
The parser will fail if the timer is clint timer and has regname
property. As the regname is only meaningful for aclint, it is more
robust to only check regname for aclint timer.

Fixes: 6112d58 ("lib: utils/fdt: Allow to use reg-names when parsing ACLINT")
Signed-off-by: Inochi Amaoto <inochiama@outlook.com>
Reviewed-by: Anup Patel <anup@brainfault.org>
2023-12-27 11:57:33 +05:30
Xiang W
63e09ad3f7 lib: sbi: Fix shift bug in sbi_system_reset
There is a problem with judging whether the current hart belongs to
hmask. If cur_hartid minus hbase is greater than BITS_PER_LONG, the
previous hmask will also have a bit cleared incorrectly, which will
cause some harts to lose ipi.

Signed-off-by: Xiang W <wxjstz@126.com>
Reviewed-by: Anup Patel <anup@brainfault.org>
2023-12-26 21:28:34 +05:30
Anup Patel
2b80b92f02 lib: sbi: Do not enter OpenSBI with mseccfg.MML == 1
On platforms with Smepmp, the previous booting stage must enter
OpenSBI with mseccfg.MML == 0. This allows OpenSBI to configure
it's own M-mode only regions without depending on the previous
booting stage.

Signed-off-by: Anup Patel <apatel@ventanamicro.com>
2023-12-19 15:56:37 +05:30
Anup Patel
5a57e8cd41 lib: sbi: Remove the SBI_ETRAP error code
The SBI_ETRAP error code was introduced only for doing trap
redirection in generic sbi_ecall_handler(). Now the trap
redirection is moved into sbi_ecall_legacy.c and SBI_ETRAP
error code is only used in this source file so let us remove
it.

Signed-off-by: Anup Patel <apatel@ventanamicro.com>
2023-12-19 15:56:37 +05:30
Anup Patel
3284bea833 lib: sbi: Allow ecall handlers to directly update register state
Some of the upcoming SBI extensions (such as SSE) will directly
update register state so improve the prototype of ecall handler
to accommodate this. Further, this flexibility allows us to
push the trap redirection from sbi_ecall_handler() to the
sbi_ecall_legacy_handler().

Signed-off-by: Anup Patel <apatel@ventanamicro.com>
2023-12-19 15:56:37 +05:30
Anup Patel
cdebae2cc9 lib: utils/irqchip: Add shared MMIO region for PLIC in root domain
On platforms with Smepmp, the MMIO regions accessed by M-mode need
to be explicitly marked with M-mode only read/write or shared (both
(M-mode and S-mode) read/write permission.

If the above is not done then runtime PLIC access from M-mode on
platforms with Smepmp will result in access fault when further
results in CPU hotplug not working.

Signed-off-by: Anup Patel <apatel@ventanamicro.com>
2023-12-19 15:56:37 +05:30
Anup Patel
80169b25f8 platform: generic: Fine tune fw_platform_calculate_heap_size()
Let's use SBI_TLB_INFO_SIZE instead of hard-coded 0x40 in
fw_platform_calculate_heap_size() to fine tune the heap size
required for per-hart TLB fifos.

Signed-off-by: Anup Patel <apatel@ventanamicro.com>
2023-12-19 15:56:37 +05:30
Anup Patel
416ceb3cd7 lib: sbi_tlb: Reduce size of struct sbi_tlb_info
Let us reduce the size of struct sbi_tlb_info by doing the
following:
1) Change the data type of asid and vmid fields to uint16_t
2) Replace local_fn() function pointer with an enum

Based on the above, the size of struct sbi_tlb_info is reduced
by 16 bytes on RV64 and 4 bytes on RV32.

Signed-off-by: Anup Patel <apatel@ventanamicro.com>
2023-12-19 15:56:37 +05:30
Yong-Xuan Wang
3daac8fb87 lib: sbi: Detect extensions from the ISA string in DT
Enable access to some extensions through menvcfg and show them in "Boot
HART ISA Extensions" if they are present in the device tree.

Signed-off-by: Yong-Xuan Wang <yongxuan.wang@sifive.com>
Reviewed-by: Anup Patel <anup@brainfault.org>
2023-12-19 15:39:17 +05:30
Yong-Xuan Wang
776770d2ad lib: sbi: Using one array to define the name of extensions
Define an array sbi_hart_ext to map extension ID and name , and use it
for ISA parsing and printing out the supported extensions.

Signed-off-by: Yong-Xuan Wang <yongxuan.wang@sifive.com>
Reviewed-by: Anup Patel <anup@brainfault.org>
2023-12-19 14:14:22 +05:30
Yong-Xuan Wang
056fe6f85d lib: sbi: Refactor the code for enable extensions in menvfg CSR
Use 1 variable to store the value of menvcfg.

Signed-off-by: Yong-Xuan Wang <yongxuan.wang@sifive.com>
Reviewed-by: Anup Patel <anup@brainfault.org>
2023-12-19 13:54:33 +05:30
Yong-Xuan Wang
2c8be566f3 lib: sbi: Improve the code of privilege mode and extensions detection
We can enhance the code by creating 2 unified interface with macro  for
privilege mode and extensions detection, which relies on supported
privilege modes and CSRs.

Signed-off-by: Yong-Xuan Wang <yongxuan.wang@sifive.com>
Reviewed-by: Anup Patel <anup@brainfault.org>
2023-12-19 13:46:02 +05:30
Xiang W
925ce14622 lib: sbi: Simplify the initialization of root_hmask in sbi_domain_init
The original code has multiple conversions between hartid and
hartindex. Can call sbi_hartmask_set_hartindex directly to
avoid conversion.

Signed-off-by: Xiang W <wxjstz@126.com>
Reviewed-by: Anup Patel <anup@brainfault.org>
2023-12-18 19:51:45 +05:30
Samuel Holland
2707250495 lib: sbi_ipi: Drop unnecessary ipi_process check
sbi_ipi_event_create() disallows registering an IPI event with a NULL
.process callback, so the function pointer will never be NULL here.

Signed-off-by: Samuel Holland <samuel.holland@sifive.com>
Reviewed-by: Anup Patel <anup@brainfault.org>
Reviewed-by: Xiang W <wxjstz@126.com>
2023-12-18 19:26:35 +05:30
Samuel Holland
446fa65eb5 lib: sbi_ipi: Process self-IPIs in sbi_ipi_send()
An IPI sent to the local hart can be processed directly instead of
triggering the IPI device. This is more efficient, and it avoids a
deadlock when the .sync callback is defined. Since interrupts are
disabled while handling an ecall, the IPI would not get delivered
until the next mret, but sbi_ipi_sync() is called before then.

Signed-off-by: Samuel Holland <samuel.holland@sifive.com>
Reviewed-by: Anup Patel <anup@brainfault.org>
Reviewed-by: Xiang W <wxjstz@126.com>
2023-12-18 19:26:33 +05:30
Samuel Holland
a894187e28 lib: sbi_ipi: Do not ignore errors from sbi_ipi_send()
Currently, failures in sbi_ipi_send() are silently ignored, which makes
them difficult to debug. Instead, abort sending the IPI and pass back
the error, but still synchronize any IPIs already sent.

Signed-off-by: Samuel Holland <samuel.holland@sifive.com>
Signed-off-by: Anup Patel <anup@brainfault.org>
2023-12-18 19:26:11 +05:30
Samuel Holland
35cba92655 lib: sbi_tlb: Check tlb_range_flush_limit only once per request
The tlb_update() callback is called for each destination hart.
Move the size check earlier, so it is executed only once.

Signed-off-by: Samuel Holland <samuel.holland@sifive.com>
Reviewed-by: Anup Patel <anup@brainfault.org>
2023-12-11 10:41:48 +05:30
Inochi Amaoto
6112d584d4 lib: utils/fdt: Allow to use reg-names when parsing ACLINT
Currently, the fdt_parse_aclint_node() follows a fixed order to parse
ACLINT timer. This may cause the undesirable result when the ACLINT
device does not support mtime without adding an empty entry for it in
the DT.

To be robust, make fdt_parse_aclint_node() support "reg-names" property,
so it can parse the DT in an order independent way. For compatibility,
fdt_parse_aclint_node() only use "reg-names" when parsing ACLINT timer,
and will fallback to the old way if "reg-names" property is not found.

Link: https://lore.kernel.org/all/20231114-skedaddle-precinct-66c8897227bb@squawk/
Signed-off-by: Inochi Amaoto <inochiama@outlook.com>
Reviewed-by: Anup patel <anup@brainfault.org>
2023-12-11 10:35:32 +05:30
Xiang W
a2e254e881 lib: sbi: skip wait_for_coldboot when coolboot done
When warmboot via HSM, coolboot has been completed and
wait_for_coldboot can be skipped to speed up.

Signed-off-by: Xiang W <wxjstz@126.com>
Reviewed-by: Anup Patel <anup@brainfault.org>
2023-12-11 09:36:57 +05:30
Inochi Amaoto
87aa3069d1 platform: recalculate heap size to support new tlb entry number
Previous patch introduced a change that using hart count as the default
number of tlb entries in the fifo. This makes the default tlb fifo size
grow in square with the number of harts. So the default heap size is
not enough to allocate tlb fifo when the hart count is big.

Fixes: 52fd64b ("platform: Uses hart count as the default size of tlb info")
Signed-off-by: Inochi Amaoto <inochiama@outlook.com>
Reviewed-by: Anup Patel <anup@brainfault.org>
2023-12-11 09:23:24 +05:30
Nick Hu
a25fc74699 lib: sbi_hsm: Put the resume_pending hart in the interruptible hart mask
Current interruptible hart mask doesn't include the hart which HSM state
is SBI_HSM_STATE_RESUME_PENDING. So when there is a request to send an
IPI to the hart which is in the resume process, this hart would miss the
IPI forever. Put the SBI_HSM_STATE_RESUME_PENDING hart in the
interruptible hart mask to fix the issue.

Signed-off-by: Nick Hu <nick.hu@sifive.com>
Reviewed-by: Xiang W <wxjstz@126.com>
Reviewed-by: Anup Patel <anup@brainfault.org>
2023-12-10 13:24:13 +05:30
Matt Waltz
06968103dc firmware: fix section types
These sections are only intended to hold data, and should not be executable.

Signed-off-by: Matt Waltz <matthewwaltzis@gmail.com>
Reviewed-by: Xiang W <wxjstz@126.com>
Reviewed-by: Anup Patel <anup@brainfault.org>
2023-12-09 14:26:58 +05:30
Atish Patra
11a0ba5d4b lib: sbi_pmu: Fix the counter info function
The counter info should only return valid hardware counters for the ones
set in the counter mask. Otherwise, it will report incorrect number of
hardware counters to the supervisor if the platform has discontiguous
counters.

Fixes: c744ed77b1 ("lib: sbi_pmu: Enable noncontigous hpm event and counters")
Signed-off-by: Atish Patra <atishp@rivosinc.com>
Reviewed-by: Xiang W <wxjstz@126.com>
Reviewed-by: Anup Patel <anup@brainfault.org>
2023-12-08 22:50:23 +05:30
Atish Patra
ee725174ba lib: sbi_pmu: Add PMU snapshot definitions
OpenSBI doesn't support SBI PMU snapshot yet as there is not much benefit
unless the multiple counters overflow at the same time.

Just add the definition and return not supported error at this moment. The
default returned error is also not supported. Thus, no functional change
intended.

Reviewed-by: Anup Patel <anup@brainfault.org>
Signed-off-by: Atish Patra <atishp@rivosinc.com>
2023-12-08 22:50:21 +05:30
Samuel Holland
93da66b7d4 lib: sbi_hart: Store PMP granularity as log base 2
This minimizes the need to call log2roundup() to recover the log value.

Signed-off-by: Samuel Holland <samuel.holland@sifive.com>
Reviewed-by: Anup Patel <anup@brainfault.org>
2023-12-08 22:43:12 +05:30
Xiang W
07419ec84b lib: sbi: Prevent redundant sbi_ipi_process
Multiple harts may try to send IPI to a particular target hart A
in which case the send_ipi() should be called only when the old
value of the hart A ipi_type is zero.

Signed-off-by: Xiang W <wxjstz@126.com>
Reviewed-by: Anup Patel <anup@brainfault.org>
2023-12-08 17:07:03 +05:30
Anup Patel
88398696c8 lib: sbi: Replace __atomic_op_bit_ord with __atomic intrinsics
Simplify atomic-related bit operations through __atomic intrinsics.

Signed-off-by: Xiang W <wxjstz@126.com>
Reviewed-by: Anup Patel <anup@brainfault.org>
2023-12-08 14:06:40 +05:30
Xiang W
11bf49b444 lib: sbi: Fix __atomic_op_bit_ord and comments
The original code returns the value of the word before modification.
When modifying the upper 32 bits under RV64, the value returned via
int return will have no meaning. Corrected to return the value of the
bit. And modify the function description.

Signed-off-by: Xiang W <wxjstz@126.com>
Reviewed-by: Anup Patel <anup@brainfault.org>
2023-12-08 13:47:31 +05:30
Xiang W
6b9a849482 lib: sbi: Remove xchg/cmpxchg implemented via lr/sc
lr/sc is part of the A extension. If the A extension is not supported,
lr/sc cannot be used. So remove xchg/cmpxchg.

Signed-off-by: Xiang W <wxjstz@126.com>
Reviewed-by: Anup Patel <anup@brainfault.org>
2023-12-08 10:54:35 +05:30
Yu Chien Peter Lin
d162009612 docs: pmu: Add Andes PMU node example
Add PMU node example for event index to counter index mapping
and selector value translation of Andes' CPUs.

Currently, there are 4 HPM counters that can be used to monitor
all of the events for each hart.

Signed-off-by: Yu Chien Peter Lin <peterlin@andestech.com>
Reviewed-by: Locus Wei-Han Chen <locus84@andestech.com>
Reviewed-by: Leo Yu-Chi Liang <ycliang@andestech.com>
Reviewed-by: Anup Patel <anup@brainfault.org>
Reviewed-by: Lad Prabhakar <prabhakar.mahadev-lad.rj@bp.renesas.com>
2023-12-06 18:21:25 +05:30
Yu Chien Peter Lin
e19d419f15 lib: utils: fdt_pmu: Do not iterate over the fdt_pmu_evt_select table
The valid entry count is tracking by hw_event_count so there
is no need to check the whole table.

Signed-off-by: Yu Chien Peter Lin <peterlin@andestech.com>
Reviewed-by: Atish Patra <atishp@rivosinc.com>
Reviewed-by: Anup Patel <anup@brainfault.org>
2023-12-06 18:17:08 +05:30
Yu Chien Peter Lin
0308f93dc4 lib: utils: fdt_pmu: Make the fdt_pmu_evt_select table global variable
To allow platform override pmu_init() filling the translation table
fdt_pmu_evt_select[] when PMU node doesn't provide such information,
we need to share the table and its entry counter with other .c file.

We also define the structures of PMU property in fdt_helper.h, so we
can initialize the mappings in arrays.

Signed-off-by: Yu Chien Peter Lin <peterlin@andestech.com>
Reviewed-by: Atish Patra <atishp@rivosinc.com>
Reviewed-by: Anup Patel <anup@brainfault.org>
2023-12-06 18:15:41 +05:30
Yu Chien Peter Lin
009ae4e602 platform: andes: Factor out is_andes() helper
We will need is_andes(45) in the following patch,
so factor out the code that parses marchid to make
it reusable for checking any Andes CPU variants.

Also improves the comment in ae350_hart_start().

Signed-off-by: Yu Chien Peter Lin <peterlin@andestech.com>
Reviewed-by: Anup Patel <anup@brainfault.org>
2023-12-06 18:03:12 +05:30
Yu Chien Peter Lin
0b3262efc6 lib: utils: fdt_fixup: Allow preserving PMU properties
Add a Kconfig option to control PMU fixup, so the next
stage software can dump the PMU node including event
mapping information for debugging purposes.

Signed-off-by: Yu Chien Peter Lin <peterlin@andestech.com>
Reviewed-by: Atish Patra <atishp@rivosinc.com>
Reviewed-by: Anup Patel <anup@brainfault.org>
2023-12-06 17:59:44 +05:30
Yu Chien Peter Lin
535c661d87 platform: rzfive: Enable Andes PMU for RZ/Five
Enable Andes PMU extension support for RZ/Five.
We also staticize renesas_rzfive_early_init() as
it is not used outside of this unit.

Signed-off-by: Yu Chien Peter Lin <peterlin@andestech.com>
Reviewed-by: Leo Yu-Chi Liang <ycliang@andestech.com>
Reviewed-by: Atish Patra <atishp@rivosinc.com>
Reviewed-by: Lad Prabhakar <prabhakar.mahadev-lad.rj@bp.renesas.com>
Tested-by: Lad Prabhakar <prabhakar.mahadev-lad.rj@bp.renesas.com>
Reviewed-by: Anup Patel <anup@brainfault.org>
2023-12-06 17:57:28 +05:30
Yu Chien Peter Lin
2e50c24399 platform: andes: Enable Andes PMU for AE350
Enable Andes PMU extension support for AE350 platforms.

Signed-off-by: Yu Chien Peter Lin <peterlin@andestech.com>
Reviewed-by: Leo Yu-Chi Liang <ycliang@andestech.com>
Reviewed-by: Atish Patra <atishp@rivosinc.com>
Reviewed-by: Lad Prabhakar <prabhakar.mahadev-lad.rj@bp.renesas.com>
Tested-by: Lad Prabhakar <prabhakar.mahadev-lad.rj@bp.renesas.com>
Reviewed-by: Anup Patel <anup@brainfault.org>
2023-12-06 17:55:55 +05:30
Yu Chien Peter Lin
1b9e743c3d platform: andes: Add Andes custom PMU support
Before the ratification of Sscofpmf, the Andes PMU extension
was designed to support the sampling and filtering with hardware
performance counters (zihpm), it works with the current SBI PMU
extension and Linux SBI PMU driver.

We implement 1) the PMU device callbacks that update the
corresponding bits on custom CSRs, 2) extentions_init() to detect
the hardware support of Andes PMU and initialize the per-hart
PMU related CSR, and 3) pmu_init() to register PMU device and
populate event mappings.

Also define a andes_pmu_setup() function which is in preparation
for adding default PMU mappings in andes_hpm.h

Signed-off-by: Yu Chien Peter Lin <peterlin@andestech.com>
Reviewed-by: Leo Yu-Chi Liang <ycliang@andestech.com>
Reviewed-by: Anup Patel <anup@brainfault.org>
2023-12-06 17:53:45 +05:30
Yu Chien Peter Lin
effd89aa05 platform: generic: Introduce pmu_init() platform override
Add pmu_init() platform override, which will be used to register
PMU device and populate event mappings.

Signed-off-by: Yu Chien Peter Lin <peterlin@andestech.com>
Reviewed-by: Atish Patra <atishp@rivosinc.com>
Reviewed-by: Lad Prabhakar <prabhakar.mahadev-lad.rj@bp.renesas.com>
Reviewed-by: Anup Patel <anup@brainfault.org>
2023-12-06 17:49:59 +05:30
Yu Chien Peter Lin
51ec60c9ea platform: include: andes45: Add PMU related CSR defines
Add CSR definitions for Andes PMU extension.

Signed-off-by: Yu Chien Peter Lin <peterlin@andestech.com>
Reviewed-by: Leo Yu-Chi Liang <ycliang@andestech.com>
Reviewed-by: Anup Patel <anup@brainfault.org>
Reviewed-by: Atish Patra <atishp@rivosinc.com>
Reviewed-by: Lad Prabhakar <prabhakar.mahadev-lad.rj@bp.renesas.com>
Tested-by: Lad Prabhakar <prabhakar.mahadev-lad.rj@bp.renesas.com>
2023-12-06 17:31:36 +05:30
Yu Chien Peter Lin
a48f2cfd94 sbi: sbi_pmu: Add hw_counter_filter_mode() to pmu device
Add support for custom PMU extensions to set inhibit bits
on custom CSRs by introducing the PMU device callback
hw_counter_filter_mode(). This allows the perf tool to
restrict event counting under a specified privileged
mode by appending a modifier, e.g. perf record -e event:k
to count events only happening in kernel mode.

Signed-off-by: Yu Chien Peter Lin <peterlin@andestech.com>
Reviewed-by: Leo Yu-Chi Liang <ycliang@andestech.com>
Reviewed-by: Atish Patra <atishp@rivosinc.com>
Reviewed-by: Anup Patel <anup@brainfault.org>
2023-12-06 17:30:01 +05:30
Yu Chien Peter Lin
090fa99d7c lib: sbi: Add XAndesPMU in hart extensions
Add the custom extension to hart extension list.

Signed-off-by: Yu Chien Peter Lin <peterlin@andestech.com>
Reviewed-by: Atish Patra <atishp@rivosinc.com>
Reviewed-by: Lad Prabhakar <prabhakar.mahadev-lad.rj@bp.renesas.com>
Tested-by: Lad Prabhakar <prabhakar.mahadev-lad.rj@bp.renesas.com>
Reviewed-by: Anup Patel <anup@brainfault.org>
2023-12-06 17:27:22 +05:30
Yu Chien Peter Lin
291403f6f2 sbi: sbi_pmu: Improve sbi_pmu_init() error handling
This patch makes the following changes:

- As sbi_platform_pmu_init() returns a negative error code on
  failure, let sbi_pmu_init() print out the error code with
  sbi_dprintf().

- In order to distinguish the SBI_EFAIL error returned by
  sbi_pmu_add_*_counter_map(), return SBI_ENOENT to indicate
  that fdt_pmu_setup() failed to locate "riscv,pmu" node, and
  generic_pmu_init() ignores such case.

Signed-off-by: Yu Chien Peter Lin <peterlin@andestech.com>
Reviewed-by: Anup Patel <anup@brainfault.org>
Reviewed-by: Lad Prabhakar <prabhakar.mahadev-lad.rj@bp.renesas.com>
Reviewed-by: Atish Patra <atishp@rivosinc.com>
2023-12-06 17:24:38 +05:30
Leo Yu-Chi Liang
bd74931d79 lib: ipi: Adjust Andes PLICSW to single-bit-per-hart scheme
The old scheme doesn't allow sending hart0 self-IPI as the
corresponding bit on pending register is hardwired to 0, this
could lead to unhandle IPIs on SMP systems, esp. on single-core.

Furthermore, the limitation of old scheme is 8-core, instead of
reserving source hart information, we assign bit (x + 1) as the
enable and pending bit of hartx, this also expands the bootable
hart number.

The following diagram shows the enable bits of the new scheme
on 32-core Andes platform.

   Pending regs: 0x1000  x---0---0---0---0------0---0
Pending hart ID:             0   1   2   3 ... 30  31
   Interrupt ID:         0   1   2   3   4 ... 31  32
                         |   |   |   |   |      |   |
    Enable regs: 0x2000  x---1---0---0---0-...--0---0---> hart0
                         |   |   |   |   |      |   |
                 0x2080  x---0---1---0---0-...--0---0---> hart1
                         |   |   |   |   |      |   |
                 0x2100  x---0---0---1---0-...--0---0---> hart2
                         |   |   |   |   |      |   |
                 0x2180  x---0---0---0---1-...--0---0---> hart3
                         .   .   .   .   .      .   .
                         .   .   .   .   .      .   .
                         .   .   .   .   .      .   .
                 0x2f00  x---0---0---0---0-...--1---0---> hart30
                         |   |   |   |   |      |   |
                 0x2f80  x---0---0---0---0-...--0---1---> hart31
                         <-------- word 0 -------><--- word 1 --->

To send IPI to hart0, for example, another hart (including hart0
itself) will set bit 1 of first word on the pending register.

We also fix indentation in andes_plicsw.h along with this patch.

Fixes: ce7c490719 ("lib: utils/ipi: Add Andes fdt ipi driver support")
Signed-off-by: Leo Yu-Chi Liang <ycliang@andestech.com>
Reviewed-by: Yu Chien Peter Lin <peterlin@andestech.com>
Reviewed-by: Randolph <randolph@andestech.com>
Reported-by: Lad Prabhakar <prabhakar.mahadev-lad.rj@bp.renesas.com>
Link: https://lists.infradead.org/pipermail/opensbi/2023-October/005665.html
Reviewed-by: Lad Prabhakar <prabhakar.mahadev-lad.rj@bp.renesas.com>
Tested-by: Lad Prabhakar <prabhakar.mahadev-lad.rj@bp.renesas.com>
Reviewed-by: Anup Patel <anup@brainfault.org>
2023-12-06 17:23:27 +05:30
Anup Patel
b70d6285f0 lib: sbi: Allow relaxed MMIO writes in device ipi_clear() callback
Currently, there are no barriers before or after the ipi_clear()
device callback which forces ipi_clear() device callback to always
use non-relaxed MMIO writes.

Instead of above, we use wmb() in after the ipi_clear() device
callback which pairs with the wmb() done before the ipi_send()
device callback. This also allows device ipi_clear() callback
to use relaxed MMIO writes.

Signed-off-by: Anup Patel <apatel@ventanamicro.com>
Reported-by: Bo Gan <ganboing@gmail.com>
2023-11-26 18:45:08 +05:30
Anup Patel
f520256d03 lib: sbi: Allow relaxed MMIO writes in device ipi_send() callback
Currently, we have a smp_wmb() between atomic_raw_set_bit() and
ipi_send() device callback whereas the MMIO writes done by the
device ipi_send() callback will also include a barrier.

We can avoid unnecessary/redundant barriers described above by
allowing relaxed MMIO writes in device ipi_send() callback. To
achieve this, we simply use  wmb() instead of smp_wmb() before
calling device ipi_send().

Signed-off-by: Anup Patel <apatel@ventanamicro.com>
Reported-by: Bo Gan <ganboing@gmail.com>
2023-11-26 18:45:06 +05:30
Anup Patel
791704cd09 lib: utils/irqchip: Avoid redundant writes to APLIC CLRIE register
Each APLIC CLRIE register allows disabling 32 interrupt sources at
a time by writing -1 so no need to write CLRIE register separately
for each interrupt source.

Fixes: 99792653de ("lib: utils/irqchip: Add APLIC initialization library")
Signed-off-by: Anup Patel <apatel@ventanamicro.com>
Reviewed-by: Atish Patra <atishp@rivosinc.com>
2023-11-24 12:48:41 +05:30
Heinrich Schuchardt
574b9c8ec2 lib: sbi_pmu: avoid buffer overflow
total_ctrs is bounded by

    SBI_PMU_FW_CTR_MAX + SBI_PMU_HW_CTR_MAX) == 48

which exceeds BITS_PER_LONG on 32 bit systems.

Iterating over the bits of &cmask results in a buffer overflow when looking
for a bit >= BITS_PER_LONG.

Adjust the iterators in sbi_pmu_ctr_start() and sbi_pmu_ctr_stop()
accordingly.

Signed-off-by: Heinrich Schuchardt <heinrich.schuchardt@canonical.com>
Reviewed-by: Anup Patel <anup@brainfault.org>
2023-11-22 20:55:22 +05:30
Anup Patel
16bb930533 lib: sbi: Fix PMP granularity handling in sbi_hart_map_saddr()
The sbi_hart_map_saddr() must create PMP mapping of size greater
than or equal to PMP granularity otherwise PMP mapping does not
work when size parameter less than sbi_hart_pmp_granularity(scratch).

Fixes: 6e44ef686a ("lib: sbi: Add functions to map/unmap shared memory")
Signed-off-by: Anup Patel <apatel@ventanamicro.com>
Reviewed-by: Samuel Holland <samuel.holland@sifive.com>
2023-11-22 20:42:24 +05:30
Xiang W
dc0bb19bd2 lib: utils/serial: remove semihosting_putc
For some debuggers that do not implement SYSWRITEC and SYSREADC
operations, we have to use SYSWRITE and SYSREAD.

Instead of implementing semihosting_putc() using SYSWRITE, let us
simply remove semihosting_putc() because console_putc/console_puts
are now interchangeable.

Signed-off-by: Chen Pei <cp0613@linux.alibaba.com>
Signed-off-by: Xiang W <wxjstz@126.com>
Reviewed-by: Guo Ren <guoren@kernel.org>
Reviewed-by: Anup Patel <anup@brainfault.org>
2023-11-17 16:03:24 +05:30
Xiang W
3aaed4fadf lib: sbi: Make console_puts/console_putc interchangeable
console_puts/console_putc should replace each other, but the previous
sbi_putc can only use console_putc. This patch addresses this problem.

Signed-off-by: Xiang W <wxjstz@126.com>
Reviewed-by: Guo Ren <guoren@kernel.org>
Reviewed-by: Anup Patel <anup@brainfault.org>
2023-11-17 16:03:21 +05:30
Xiang W
6602e11de3 lib: sbi: change sbi_hart_features.extensions as an array
In the future there may be a lot of ISA extensions, a 'long' may not
be able to accommodate, changed to an array for the future.

Addresses-Coverity-ID: 1568357 Out-of-bounds access
Fixes: 6259b2ec2d ("lib: utils/fdt: Fix fdt_parse_isa_extensions()
implementation")
Signed-off-by: Xiang W <wxjstz@126.com>
Reviewed-by: Heinrich Schuchardt <heinrich.schuchardt@canonical.com>
Reviewed-by: Anup Patel <anup@brainfault.org>
2023-11-17 13:23:49 +05:30
Heinrich Schuchardt
6e5b0cfb45 lib: sbi: enable seed access in S-mode
If ISA extension Zkr is available, set

    mseccfg.sseed=1
    mseccfg.useed=0

This enables access to the seed CSR in S-mode but not in U-mode.

Signed-off-by: Heinrich Schuchardt <heinrich.schuchardt@canonical.com>
Reviewed-by: Anup Patel <anup@brainfault.org>
2023-11-17 12:26:22 +05:30
Heinrich Schuchardt
efcac338bd lib: sbi: Add Zkr in hart extensions
- Add Zkr as extension in sbi_hart_extensions enum
- Return "zkr" string for Zkr extension from sbi_hart_extension_id2string

Signed-off-by: Heinrich Schuchardt <heinrich.schuchardt@canonical.com>
Reviewed-by: Anup Patel <anup@brainfault.org>
2023-11-17 12:04:18 +05:30
Heinrich Schuchardt
280f7ae627 include: sbi: macros for mseccfg.sseed and .useed
Define macros to access the sseed and the useed bit in the machine
security configuration register (mseccfg).

Signed-off-by: Heinrich Schuchardt <heinrich.schuchardt@canonical.com>
Reviewed-by: Xiang W <wxjstz@126.com>
Reviewed-by: Anup Patel <anup@brainfault.org>
2023-11-17 12:03:59 +05:30
Inochi Amaoto
2bfdb9e5c2 platform: generic: Add Sophgo sg2042 platform support
Add Sophgo sg2042 soc support

Signed-off-by: Inochi Amaoto <inochiama@outlook.com>
Reviewed-by: Guo Ren <guoren@kernel.org>
Reviewed-by: Anup Patel <anup@brainfault.org>
2023-11-16 21:22:27 +05:30
Inochi Amaoto
3b03cdd60c lib: sbi: Add regions merging when sanitizing domain region
As the domain will reject a new memory region which has a sub-regions
already in the domain, even the new region is bigger and has the same
flags. This problem can be solved by relaxing region restriction and
rechecking when adding and sanitizing domains.

Signed-off-by: Inochi Amaoto <inochiama@outlook.com>
Reviewed-by: Anup Patel <anup@brainfault.org>
2023-11-16 21:03:26 +05:30
Inochi Amaoto
5b2f55d65a lib: sbi: separate the swap operation of domain region
Swapping domain region is a common operation when sorting domain region,
so separate it as a function to make code clean.

Signed-off-by: Inochi Amaoto <inochiama@outlook.com>
Reviewed-by: Anup Patel <anup@brainfault.org>
2023-11-16 20:58:56 +05:30
Inochi Amaoto
98bc25f181 lib: utils/ipi: mswi: add separate T-Head C9xx CLINT mswi compatible
Like the mtimer of T-HEAD C9xx clint, the mswi also needs new compatible
string to avoid misuse.

Signed-off-by: Inochi Amaoto <inochiama@outlook.com>
Link: https://lore.kernel.org/linux-riscv/1f6b82a1864477a51db33d3f295889ff985b497b.1696433229.git.unicorn_wang@outlook.com/
Reviewed-by: Guo Ren <guoren@kernel.org>
Reviewed-by: Anup Patel <anup@brainfault.org>
2023-11-16 16:55:28 +05:30
Inochi Amaoto
accafb13d4 lib: utils/timer: mtimer: add separate T-Head C9xx CLINT mtimer compatible
T-HEAD allows soc vendor to map the mtimer and mswi of C9xx clint on
different address, which may cause a misuse if use the same compatible
string, add a new timer compatible string to avoid this.

Signed-off-by: Inochi Amaoto <inochiama@outlook.com>
Link: https://lore.kernel.org/linux-riscv/6e48cbe5e60f9ada2fd1fe58e803e127f1a678e5.1696433229.git.unicorn_wang@outlook.com/
Reviewed-by: Guo Ren <guoren@kernel.org>
Reviewed-by: Anup Patel <anup@brainfault.org>
2023-11-16 16:53:48 +05:30
Inochi Amaoto
896d2c99e2 lib: utils/timer: Allow ACLINT MTIMER driver to setup quirks
The quirks checking will cause ACLINT step into a CLINT code path, this
is not expected when ACLINT needs custom quirks.

Add a new quirk to identify custom ACLINT, and apply the general quirks
after applying CLINT specific quirks.

Signed-off-by: Inochi Amaoto <inochiama@outlook.com>
Reviewed-by: Anup Patel <anup@brainfault.org>
2023-11-16 16:50:42 +05:30
Guo Ren
d1e0f7f25b utils/reset: Remove fdt_reset_thead
In the past, we used fdt_reset_thead to help customers with prototype
verification. However, with the emergence of the Big-little SoC system,
it can no longer meet the demand. Therefore, we use zero_stage_boot
instead of fdt_reset_thead. It cleans up the opensbi code and ends the
disputation of reset_sample's dts.

This patch removes the fdt_reset_thead component and updates the related
doc.

Signed-off-by: Guo Ren <guoren@linux.alibaba.com>
Signed-off-by: Guo Ren <guoren@kernel.org>
Reviewed-by: Anup Patel <anup@brainfault.org>
2023-11-16 16:25:23 +05:30
Guo Ren
fccdf41d32 firmware: fw_base.S: Fix boot hart status synchronization
It's wrong to put the fence after setting the boot status flag because
all relocation operations must be finished before setting the status
flag. So, this fence must be put before the setting status flag, and
there is no use in putting a fence between _start_warm and setting
status flag.

Also, nop can't delay other harts too much, so use div instead, just
like Linux cpu_relax. Current opensbi force enables “M” Standard
Extension, and mul instructions have been used in the fw_base.S.

After the above two fixes, the boot hart index param of the
fw_dynamic_info could be guaranteed properly for all platforms.

Signed-off-by: Guo Ren <guoren@linux.alibaba.com>
Signed-off-by: Guo Ren <guoren@kernel.org>
Reviewed-by: Anup Patel <anup@brainfault.org>
2023-11-16 16:19:42 +05:30
Chen Pei
07f2ccd990 lib: utils/serial: Optimize semihosting_putc implementation
For some debuggers that do not implement SYSWRITEC and SYSREADC
operations, we can use SYSWRITE and SYSREAD instead like the
implementation of semihosting_getc().

Signed-off-by: Chen Pei <cp0613@linux.alibaba.com>
Reviewed-by: Xiang W <wxjstz@126.com>
Reviewed-by: Anup Patel <anup@brainfault.org>
2023-11-16 11:36:44 +05:30
Inochi Amaoto
52fd64b82c platform: Uses hart count as the default size of tlb info
For platform with high number of harts, it is better to auto detect a
suitable number of entries in tlb fifo. Since allocating tlb entry for
all online harts can reduce the wait time significantly, using the
number of the online harts can make most platforms happy. This auto
detection can avoid most duplicate code for setting tlb fifo size.

Signed-off-by: Inochi Amaoto <inochiama@outlook.com>
Acked-by: Guo Ren <guoren@kernel.org>
Reviewed-by: Xiang W <wxjstz@126.com>
Reviewed-by: Anup Patel <anup@brainfault.org>
2023-11-16 09:53:45 +05:30
Inochi Amaoto
88ae718d36 platform: generic: thead: improve tlb flush errata
Flushing the tlb entries can solve the thead tlb problem, but flushing
it by address will miss something and lead to a exception in some rare
cases, and this is more common for sg2042.

To solve this problem, flush the tlb entries by asid in the custom trap
handler to ensure it is refreshed.

Signed-off-by: Inochi Amaoto <inochiama@outlook.com>
Reviewed-by: Guo Ren <guoren@kernel.org>
Reviewed-by: Anup Patel <anup@brainfault.org>
2023-11-16 09:42:12 +05:30
Samuel Holland
a140a4e862 lib: sbi: Correctly limit flushes to a single ASID/VMID
Per the SBI specification, the effects of these functions are limited to
a specific ASID and/or VMID. This applies even when flushing the entire
address space.

Signed-off-by: Samuel Holland <samuel.holland@sifive.com>
Reviewed-by: Anup Patel <anup@brainfault.org>
2023-11-16 09:21:47 +05:30
Inochi Amaoto
3e21b96003 platform: generic: thead: initialize PMU by default in thead generic platform
Since all the SoC with thead c9xx cores need this initialization at now,
initialize the c9xx pmu in the thead generic platform by default.

Signed-off-by: Inochi Amaoto <inochiama@outlook.com>
Reviewed-by: Anup Patel <anup@brainfault.org>
2023-11-14 21:53:52 +05:30
Inochi Amaoto
492d9b153d platform: generic: thead: separate implement of T-HEAD c9xx errata
Separate the implement of T-HEAD c9xx errata to allow any platform
with bug related to c9xx cores can use it.

Signed-off-by: Inochi Amaoto <inochiama@outlook.com>
Reviewed-by: Anup Patel <anup@brainfault.org>
2023-11-14 21:53:50 +05:30
Inochi Amaoto
8e941e7fe3 platform: generic: thead: separate implement of T-HEAD c9xx pmu
Separate the implement of T-HEAD c9xx pmu to allow any platform with
c9xx cores can use it.

Signed-off-by: Inochi Amaoto <inochiama@outlook.com>
Reviewed-by: Anup Patel <anup@brainfault.org>
2023-11-14 21:53:45 +05:30
Inochi Amaoto
c1a6987447 platform: generic: thead: move to thead c9xx header to vendor specific postion
The CSR encoding for t-head c9xx cores is shared across all the
platforms with these cores. So move header thead_c9xx.h to the
thead subdir.

Signed-off-by: Inochi Amaoto <inochiama@outlook.com>
Acked-by: Guo Ren <guoren@kernel.org>
Reviewed-by: Anup Patel <anup@brainfault.org>
2023-11-14 21:53:42 +05:30
Heinrich Schuchardt
5d0ed1bfb8 lib: sbi: simplify sanitize_domain()
Since commit 112daa2e64 ("lib: sbi: Maximize the use of HART index in
sbi_domain") the platform parameter is unused.

Fixes: 112daa2e64 ("lib: sbi: Maximize the use of HART index in sbi_domain")
Signed-off-by: Heinrich Schuchardt <heinrich.schuchardt@canonical.com>
Reviewed-by: Anup Patel <anup@brainfault.org>
2023-11-14 17:57:54 +05:30
Anup Patel
cbdd869739 include: sbi: Change spec version to 2.0
Now that SBI v2.0 specification is frozen, we change spec version
implemented by OpenSBI to v2.0.

Signed-off-by: Anup Patel <apatel@ventanamicro.com>
Reviewed-by: Andrew Jones <ajones@ventanamicro.com>
2023-10-19 17:21:17 +05:30
Amanieu d'Antras
ec0559eb31 lib: sbi_misaligned_ldst: Fix handling of C.SWSP and C.SDSP
Unlike C.LWSP/C.LDSP, these encodings can be used with the zero
register, so checking that the rs2 field is non-zero is unnecessary.

Additionally, the previous check was incorrect since it was checking
the immediate field of the instruction instead of the rs2 field.

Signed-off-by: Amanieu d'Antras <amanieu@gmail.com>
Reviewed-by: Anup Patel <anup@brainfault.org>
2023-10-09 13:53:20 +05:30
Yangjie Zhang
3632f2b5c4 lib: sbi: Add support for mconfigptr
RISC-V privileged specification v1.12 introduced the mconfigptr CSR
which will hold the physical address of a configuration data
structure.

Signed-off-by: Yangjie Zhang <jay1273062855@outlook.com>
Reviewed-by: Anup Patel <anup@brainfault.org>
2023-10-06 17:58:42 +05:30
Yangjie Zhang
e8114c6ae2 docs: platform: update platform_requirements.md
"Zicsr" isa extension has been separated from "I" extension.
This patch add the isa requirement of "Zicsr" extension in
platform requirements documentation.

Signed-off-by: Yangjie Zhang <jay1273062855@outlook.com>
Reviewed-by: Anup Patel <anup@brainfault.org>
2023-10-06 17:58:09 +05:30
Heinrich Schuchardt
d891caeae9 gpio/starfive: redundant readl() call
In starfive_gpio_direction_output() readl() is called twice to read the
gpio direction register. The result of the first read is discarded.

Remove the redundant read.

Fixes: 908be1b85c ("gpio/starfive: add gpio driver and support gpio reset")
Signed-off-by: Heinrich Schuchardt <heinrich.schuchardt@canonical.com>
Reviewed-by: Anup Patel <anup@brainfault.org>
2023-10-06 17:29:09 +05:30
Heinrich Schuchardt
f831b93357 lib: sbi_pmu: check for index overflows
sbi_pmu_ctr_cfg_match() receives data from a lower privilege level mode.
We must catch maliciously wrong values.

We already check against total_ctrs. But we do not check that total_ctrs is
less than SBI_PMU_HW_CTR_MAX + SBI_PMU_FW_CTR_MAX.

Check that the number of hardware counters is in the valid range.

Addresses-Coverity-ID: 1566114 Out-of-bounds write
Signed-off-by: Heinrich Schuchardt <heinrich.schuchardt@canonical.com>
Reviewed-by: Atish Patra <atishp@rivosinc.com>
2023-10-06 17:29:07 +05:30
Heinrich Schuchardt
942aca232e lib: utils: Simplify SET_ISA_EXT_MAP()
The define is hard to read. The continue statement does not do what was
intended.

* Remove do {} while (false);
* Change the name to set_multi_letter_ext
  - Other local macros are lower case too.
  - Refer to the fact that this is only used for multi-letter extensions.

Addresses-Coverity-ID: 1568359 Unexpected control flow
Fixes: d72f5f1747 ("lib: utils: Add detection of Smepmp from ISA string in FDT")
Signed-off-by: Heinrich Schuchardt <heinrich.schuchardt@canonical.com>
Reviewed-by: Xiang W <wxjstz@126.com>
Reviewed-by: Anup Patel <anup@brainfault.org>
2023-10-06 17:28:52 +05:30
Heinrich Schuchardt
9da30f6105 lib: utils/fdt: simplify dt_parse_isa_extensions
hart_exts == NULL can only occur if offset and node address lead to an
overflow resulting in exactly NULL. As we don't catch other values of
overflow it does not make sense to treat this one as special.

Addresses-Coverity-ID: 1568355 Logically dead code
Addresses-Coverity-ID: 1568358 Logically dead code
Fixes: 6259b2ec2d ("lib: utils/fdt: Fix fdt_parse_isa_extensions() implementation")
Signed-off-by: Heinrich Schuchardt <heinrich.schuchardt@canonical.com>
Reviewed-by: Xiang W <wxjstz@126.com>
Reviewed-by: Anup Patel <anup@brainfault.org>
2023-10-06 17:06:13 +05:30
Heinrich Schuchardt
8197c2f1ec lib: sbi: fix sbi_domain_get_assigned_hartmask()
'1' is a 32 bit integer. When shifting it by more than 31 bits it becomes
zero and we get an incorrect return value.

Addresses-Coverity-ID: 1568356 Bad bit shift operation
Fixes: 296e70d69d ("lib: sbi: Extend sbi_hartmask to support both hartid and hartindex")
Signed-off-by: Heinrich Schuchardt <heinrich.schuchardt@canonical.com>
Reviewed-by: Xiang W <wxjstz@126.com>
Reviewed-by: Anup Patel <anup@brainfault.org>
2023-10-06 17:06:09 +05:30
Yu Chien Peter Lin
d36709fcaf lib: utils: timer/ipi: Update memregion flags for PLMT and PLICSW
This patch adds unspecified permission flags for the PLICSW region
and updates the permission of the PLMT region.

With this update, both regions will become M-mode only read/write
regions in the root domain.

  Domain0 Region00: 0x00000000f0300000-0x00000000f0300fff M: (I,R,W) S/U: (R,W)
  Domain0 Region01: 0x0000000000040000-0x000000000005ffff M: (R,W) S/U: ()
  Domain0 Region02: 0x0000000000000000-0x000000000003ffff M: (R,X) S/U: ()
> Domain0 Region03: 0x00000000e6000000-0x00000000e60fffff M: (I,R,W) S/U: ()
> Domain0 Region04: 0x00000000e6400000-0x00000000e67fffff M: (I,R,W) S/U: ()
  Domain0 Region05: 0x0000000000000000-0xffffffffffffffff M: () S/U: (R,W,X)

The PMP rules of AE350-AX65 (single-core) w/ Smepmp:

  p/x $pmpcfg0
  $1 = {0x1f9b9b9d9b1e00,
  pmp0cfg = {0x0},
                    L--AAXWR
  pmp1cfg = {0x1e} (00011110), pmpaddr1: 0xf0300000 ~   0xf0300fff  (UART1)
  pmp2cfg = {0x9b} (10011011), pmpaddr2:    0x40000 ~      0x5ffff
  pmp3cfg = {0x9d} (10011101), pmpaddr3:        0x0 ~      0x3ffff
  pmp4cfg = {0x9b} (10011011), pmpaddr4: 0xe6000000 ~   0xe60fffff  (PLMT)
  pmp5cfg = {0x9b} (10011011), pmpaddr5: 0xe6400000 ~   0xe67fffff  (PLICSW)
  pmp6cfg = {0x1f} (00011111), pmpaddr6:        0x0 ~ 0xffffffffff
  pmp7cfg = {0x0 }}

The PMP rules of AE350-AX45MP (qual-core) w/o Smepmp:

  p/x $pmpcfg0
  $1 = {0x1f181818181b,
                     L--AAXWR
  pmp0cfg = {0x1b}, (00011011), pmpaddr0: 0xf0300000 ~  0xf0300fff  (UART1)
  pmp1cfg = {0x18}, (00011000), pmpaddr1:    0x40000 ~     0x5ffff
  pmp2cfg = {0x18}, (00011000), pmpaddr2:        0x0 ~     0x3ffff
  pmp3cfg = {0x18}, (00011000), pmpaddr3: 0xe6000000 ~  0xe60fffff  (PLMT)
  pmp4cfg = {0x18}, (00011000), pmpaddr4: 0xe6400000 ~  0xe67fffff  (PLICSW)
  pmp5cfg = {0x1f}, (00011111), pmpaddr5:        0x0 ~ 0x1ffffffff
  pmp6cfg = {0x0 }}

Note that starting from this patch, we restrict the S/U-mode read
permission to the PLMT region, since we should read the TIME CSR
in a lower privilege mode.

Signed-off-by: Yu Chien Peter Lin <peterlin@andestech.com>
Reviewed-by: Anup Patel <anup@brainfault.org>
2023-10-06 16:53:26 +05:30
Yu Chien Peter Lin
a12542316c lib: utils/serial: Ensure proper allocation of PMP entries for uart8250
The added memory region should start from the base address.
Otherwise, the range will be shifted by reg_offset and not
able to merge consecutive NAPOT regions in the root domain,
resulting in wasted PMP entries.

Fixes: e8bc1621 ("lib: utils/serial: Add shared regions for
serial drivers")

Signed-off-by: Yu Chien Peter Lin <peterlin@andestech.com>
Reviewed-by: Anup Patel <anup@brainfault.org>
2023-10-06 16:53:25 +05:30
Hoa Nguyen
e21901d317 doc: Fix fw_payload.md
The base of .text is defined by `FW_TEXT_START`, not `FW_TEXT_BASE`.

Signed-off-by: Hoa Nguyen <hn@hnpl.org>
Reviewed-by: Xiang W <wxjstz@126.com>
Reviewed-by: Anup Patel <anup@brainfault.org>
2023-10-06 10:07:48 +05:30
Vivian Wang
6ed125a602 Makefile: Add --exclude-libs ALL to avoid .dynsym
Since everything is statically linked, we don't need to expose symbols
for dynamic linking.

For a default build this saves about 2 KiB of useless read only data in
.dynsym, .dynstr, .hash, .gnu.hash sections.

Signed-off-by: Vivian Wang <dramforever@live.com>
Reviewed-by: Anup Patel <anup@brainfault.org>
2023-10-06 09:21:24 +05:30
Vivian Wang
2a6d72534d firmware: Remove handling of R_RISCV_{32,64}
Since everything is statically linked, we won't actually have
R_RISCV_{32,64} relocations. No need to handle these.

Fixes: 0f20e8adcf ("firmware: Support position independent execution")
Signed-off-by: Vivian Wang <dramforever@live.com>
Reviewed-by: Anup Patel <anup@brainfault.org>
2023-10-06 09:21:23 +05:30
Vivian Wang
de525ac18d firmware: Remove ALIGN in .rela.dyn in linker script
The .rela.dyn section should be exactly the size of the relocations,
without padding. On RV64, .rela* sections are already aligned and
there's no need for padding. On RV32, this adds padding up to 4 bytes,
which, if present, confuses the relocation loop into processing an extra
entry past the end of .rela*, and it crashes with an invalid memory
access.

Fixes: 0f20e8adcf ("firmware: Support position independent execution")
Signed-off-by: Vivian Wang <dramforever@live.com>
Reviewed-by: Anup Patel <anup@brainfault.org>
2023-10-06 09:21:21 +05:30
Inochi Amaoto
3669153e06 platform: generic: thead: fix stale TLB entries for th1520/sg2042
The TLB entries remain functional all the time once added in T-HEAD th1520
and Sophgo sg2042 (even if the MMU is then disabled afterwards). If there
are some stale TLB entries that contains the address of SBI, it will cause
unexpected memory access and issue a illegal instruction error. To avoid
this, a TLB flush is needed to drop these TLB entries before any memory
access in the trap handler.

To handle this workaroud, add a custom trap handler with executing TLB flush
first in the T-HEAD platform to fix affected socs.

Signed-off-by: Inochi Amaoto <inochiama@outlook.com>
Reviewed-by: Anup Patel <anup@brainfault.org>
2023-10-04 18:59:54 +05:30
Anup Patel
b7e9d34edf lib: utils/regmap: Mark syscon region as shared read-write
The syscon region used by OpenSBI should be marked as a shared
read-write region between M-mode and SU-mode.

Signed-off-by: Anup Patel <apatel@ventanamicro.com>
Signed-off-by: Mayuresh Chitale <mchitale@ventanamicro.com>
2023-09-24 17:14:26 +05:30
Mayuresh Chitale
e8bc1621c6 lib: utils/serial: Add shared regions for serial drivers
The serial driver regions used by OpenSBI should be marked as a shared
read-write regions between M-mode and SU-mode as those are accessed
by earlycon and the corresponding tty serial drivers running in 'S' mode.
When the smepmp extension is enabled, PMP entries for these shared regions
will get programmed.

Signed-off-by: Mayuresh Chitale <mchitale@ventanamicro.com>
Signed-off-by: Anup Patel <apatel@ventanamicro.com>
2023-09-24 17:04:41 +05:30
Anup Patel
73aea28264 lib: sbi: Populate M-only Smepmp entries before setting mseccfg.MML
Based on sections 4.c and 4.d in Ch.2 of the Smepmp spec the PMP entries
must be programmed as below:
1. Program M-only entries
2. Enable mseccfg.MML
3. Program shared-region entries
4. Program SU-only entries

Co-developed-by: Mayuresh Chitale <mchitale@ventanamicro.com>
Signed-off-by: Mayuresh Chitale <mchitale@ventanamicro.com>
Signed-off-by: Anup Patel <apatel@ventanamicro.com>
2023-09-24 16:45:15 +05:30
Anup Patel
2b51a9dd9c lib: sbi: Fix pmp_flags for Smepmp read-only shared region
The Smepmp read-only shared region must have pmpcfg.L, pmpcfg.R,
pmpcfg.W, and pmpcfg.X bits set so sbi_hart_get_smepmp_flags()
must return pmp_flags accordingly.

Signed-off-by: Anup Patel <apatel@ventanamicro.com>
Signed-off-by: Mayuresh Chitale <mchitale@ventanamicro.com>
2023-09-24 16:40:52 +05:30
Anup Patel
5240d312d3 lib: sbi: Don't clear mseccfg.MML bit in sbi_hart_smepmp_configure()
The mseccfg.MML bit is a sticky bit which remains unchanged once set
so no need to clear it in sbi_hart_smepmp_configure().

Signed-off-by: Anup Patel <apatel@ventanamicro.com>
Signed-off-by: Mayuresh Chitale <mchitale@ventanamicro.com>
2023-09-24 16:28:16 +05:30
Anup Patel
bff27c1fb4 lib: sbi: Factor-out Smepmp configuration as separate function
Let us factor-out Smepmp configuaration as separate function so
that code is more readable.

Signed-off-by: Anup Patel <apatel@ventanamicro.com>
Signed-off-by: Mayuresh Chitale <mchitale@ventanamicro.com>
2023-09-24 16:27:40 +05:30
Mayuresh Chitale
b8fb96eceb include: sbi_domain: Fix permission test macros
The macros to test permissions must perform an exact match of all the
bits in the input with the desired permission bits. Otherwise, the check
returns false positives in those cases where only some of the desired
permissions are set in the input.

Fixes: 6c202c5 ("include: sbi: Add Smepmp specific access flags for PMP
entries")
Signed-off-by: Mayuresh Chitale <mchitale@ventanamicro.com>
Reviewed-by: Anup Patel <anup@brainfault.org>
2023-09-24 16:27:02 +05:30
Anup Patel
9560fb38fe include: sbi: Remove sbi_hartmask_for_each_hart() macro
The sbi_hartmask_for_each_hart() macro is slow and has only one user
so let us completely remove the sbi_hartmask_for_each_hart() macro.

Signed-off-by: Anup Patel <apatel@ventanamicro.com>
2023-09-24 11:48:21 +05:30
Anup Patel
112daa2e64 lib: sbi: Maximize the use of HART index in sbi_domain
Let us maximize the use of HART index in sbi_domain because hartindex
based hartmask access and sbi_scratch lookup is faster.

Signed-off-by: Anup Patel <apatel@ventanamicro.com>
2023-09-24 11:48:17 +05:30
Anup Patel
22d6ff8675 lib: sbi: Remove sbi_scratch_last_hartid() macro
The sbi_scratch_last_hartid() macro is not of much use on platforms
with really sparse hartids so let us replace use of this macro with
other approaches.

Signed-off-by: Anup Patel <apatel@ventanamicro.com>
2023-09-24 11:41:54 +05:30
Anup Patel
78c667b6fc lib: sbi: Prefer hartindex over hartid in IPI framework
Let us prefer hartindex over hartid in IPI framework which in-turn
forces IPI users to also prefer hartindex.

Signed-off-by: Anup Patel <apatel@ventanamicro.com>
2023-09-24 11:39:38 +05:30
Anup Patel
e632cd7c81 lib: sbi: Use sbi_scratch_last_hartindex() in remote TLB managment
The sbi_hartid_to_scratch() involves translating hartid to hartindex
which is expensive so let's use sbi_hartindex_to_scratch() instead.

Signed-off-by: Anup Patel <apatel@ventanamicro.com>
2023-09-24 11:39:35 +05:30
Xiang W
296e70d69d lib: sbi: Extend sbi_hartmask to support both hartid and hartindex
Currently, the sbi_hartmask is indexed by hartid which puts a
limit on hartid to be less than SBI_HARTMASK_MAX_BITS.

We extend the sbi_hartmask implementation to use hartindex and
support updating sbi_hartmask using hartid. This removes the
limit on hartid and existing code works largely unmodified.

Signed-off-by: Xiang W <wxjstz@126.com>
Signed-off-by: Anup Patel <apatel@ventanamicro.com>
2023-09-24 11:39:32 +05:30
Anup Patel
e6125c3c4f lib: sbi: Remove sbi_platform_hart_index/invalid() functions
The hartid to hartindex mapping is now tracked in sbi_scratch so we
don't need sbi_platform_hart_index() and sbi_platform_hart_invalid()
functions hence let us remove them.

Signed-off-by: Anup Patel <apatel@ventanamicro.com>
2023-09-24 11:39:30 +05:30
Anup Patel
d1e4dff45b lib: sbi: Introduce HART index in sbi_scratch
We introduce HART index and related helper functions in sbi_scratch
where HART index is contiguous and each HART index maps to a physical
HART id such that 0 <= HART index and HART index < SBI_HARTMASK_MAX_BITS.

The HART index to HART id mapping follows the index2id mapping provided
by the platform. If the platform does not provide index2id mapping then
identity mapping is assumed.

Signed-off-by: Anup Patel <apatel@ventanamicro.com>
2023-09-24 11:39:21 +05:30
Greentime Hu
130e65dd9d lib: sbi: Implement SET_FS_DIRTY() to make sure the mstatus FS dirty is set
We found the mstatus.FS status is not set correctly after the SET_F64_REG()
and SET_F32_REG(). We should set mstatus.FS dirty after we emulate the FPU
instructions.

Co-developed-by: Roy Lin <roy.lin@sifive.com>
Signed-off-by: Roy Lin <roy.lin@sifive.com>
Signed-off-by: Greentime Hu <greentime.hu@sifive.com>
Reviewed-by: Anup Patel <anup@brainfault.org>
2023-09-22 11:17:26 +05:30
Xiang W
5bd969477f lib: sbi: alloc tlb fifo by sbi_malloc
If the system is defined from tlb_fifo_num_entries, the scratch may be
too small to hold the fifo, so it is alloc through the heap.

Signed-off-by: Xiang W <wxjstz@126.com>
Signed-off-by: Xing Xiaoguang <xiaoguang.xing@sophgo.com>
Reviewed-by: Anup Patel <anup@brainfault.org>
2023-09-10 11:46:44 +05:30
Xiang W
cacfba32cc platform: Allow platforms to specify the size of tlb fifo
For some platforms with a particularly high number of harts, if the
tlb fifo is too small, it case harts to wait. Platforms should be
allowed to specify the size of the tlb fifo.

Signed-off-by: Xiang W <wxjstz@126.com>
Signed-off-by: Xing Xiaoguang <xiaoguang.xing@sophgo.com>
Reviewed-by: Anup Patel <anup@brainfault.org>
2023-09-10 11:21:05 +05:30
Inochi Amaoto
901d3d7bff lib: sbi_pmu: keep overflow interrupt of stopped hpm counter disabled
After the hardware hpm counter is stopped, it should not raise any new
interrupt as it is already stopped. So add the hw_counter_disable_irq
callback to allow the custom pmu device to control this behavior.

Signed-off-by: Inochi Amaoto <inochiama@outlook.com>
Reviewed-by: Guo Ren <guoren@kernel.org>
Reviewed-by: Anup Patel <anup@brainfault.org>
Tested-by: Samuel Holland <samuel@sholland.org>
2023-09-10 11:05:01 +05:30
Inochi Amaoto
c9a296d0ed platform: generic: allwinner: fix OF process for T-HEAD c9xx pmu
T-HEAD c9xx pmu needs to clear OV bits of MCOUNTEROF in any condition
to avoid unnecessary OF interrupts.

In addition, the S-mode SCOUNTEROF only have OF bit set when the related
bits of MCOUNTERWEN is set, so also configure MCOUNTERWEN to allow kernel
to access valid SCOUNTEROF.

Signed-off-by: Haijiao Liu <haijiao.liu@sophgo.com>
Co-authored-by: Inochi Amaoto <inochiama@outlook.com>
Signed-off-by: Inochi Amaoto <inochiama@outlook.com>
Reviewed-by: Anup Patel <anup@brainfault.org>
Tested-by: Samuel Holland <samuel@sholland.org>
2023-09-10 11:04:59 +05:30
Inochi Amaoto
664692f507 lib: sbi_pmu: ensure update hpm counter before starting counting
When detecting features of PMU, the hpm counter may be written to some
value, this will cause some unexpected behavior in some cases. So ensure
the hpm counter is updated before starting the counter and the related
interrupt.

Signed-off-by: Haijiao Liu <haijiao.liu@sophgo.com>
Co-authored-by: Inochi Amaoto <inochiama@outlook.com>
Signed-off-by: Inochi Amaoto <inochiama@outlook.com>
Reviewed-by: Anup Patel <anup@brainfault.org>
Tested-by: Samuel Holland <samuel@sholland.org>
2023-09-10 11:04:57 +05:30
Xiang W
b20bd479ef lib: sbi: improve the definition of SBI_IPI_EVENT_MAX
The previous definition had the assumption that the machine word length
is equal to the word length of LONG. Remove this assumption and add a
static check to prevent errors in subsequent modifications.

Signed-off-by: Xiang W <wxjstz@126.com>
Reviewed-by: Anup Patel <anup@brainfault.org>
2023-09-06 17:06:12 +05:30
Inochi Amaoto
a9cffd6532 firmware: payload: test: Change to SBI v2.0 DBCN ecalls
As the the "Console Putchar" extension is already legacy and may
be removed in the furture. So replace it with the SBI v2.0 "DBCN"
extension.

Signed-off-by: Inochi Amaoto <inochiama@outlook.com>
Reviewed-by: Anup Patel <anup@brainfault.org>
2023-09-06 16:50:50 +05:30
Inochi Amaoto
ee1f83ca84 lib: sbi_pmu: remove mhpm_count field in hart feature
After supporting noncontigous hpm event and counters in opensbi, the
number of hpm counters can be calculated by the mhpm_mask. So this field
is unnecessary and can be removed to save some space.

Signed-off-by: Inochi Amaoto <inochiama@outlook.com>
Reviewed-by: Anup Patel  <anup@brainfault.org>
2023-08-22 13:26:09 +05:30
Inochi Amaoto
e7e73aa532 platform: generic: allwinner: correct mhpmevent count
Only the CSR mhpmevent 3-9,13-17 of D1 have valid function, so change
the mhpm_mask to a valid value to avoid invalid usage.

Due to the openc906 pmu code
https://github.com/T-head-Semi/openc906/blob/main/C906_RTL_FACTORY/gen_rtl/pmu/rtl/aq_hpcp_top.v

Signed-off-by: Inochi Amaoto <inochiama@outlook.com>
Reviewed-by: Anup Patel  <anup@brainfault.org>
2023-08-22 13:26:05 +05:30
Andrew Jones
7aabeee93e Makefile: Fix grep warning
grep (at least my version, grep-3.8-3.fc38.x86_64) warns with
"grep: warning: stray \ before -". Fix the warning by making
the command line input to grep less ambiguous.

Signed-off-by: Andrew Jones <ajones@ventanamicro.com>
Reviewed-by: Anup Patel  <anup@brainfault.org>
2023-08-22 13:26:03 +05:30
Kaiwen Xue
c104c60912 lib: sbi: Add support for smcntrpmf
This adds the support for ISA extension smcntrpmf. When some inhibit flags
are set by a lower privilege mode for new CSRs added by smcntrpmf, OpenSBI
sets the appropriate values correspondingly.

Signed-off-by: Kaiwen Xue <kaiwenx@andrew.cmu.edu>
Signed-off-by: Kaiwen Xue <kaiwenx@rivosinc.com>
Reviewed-by: Anup Patel <anup@brainfault.org>
Reviewed-by: Atish Patra <atishp@rivosinc.com>
2023-08-18 14:50:38 +05:30
Mitchell Horne
94197a8c49 fw_base.S: Fix assembler error with clang 16+
Attempting to build OpenSBI with clang 16 and the following command:

   $ make LLVM=1 PLATFORM=generic

Results in the following error:

    AS        platform/generic/firmware/fw_dynamic.o
   /tmp/fw_dynamic-d000a6.s:429:9: error: symbol '_fw_start' can not be undefined in a subtraction expression
    .dword _fw_rw_start - _fw_start

Work around this issue by eliminating the __fw_rw_offset variable and
performing the offset calculation at run-time instead. This takes
advantage of the fact that the a4 register contains the value of
_fw_start.

Signed-off-by: Mitchell Horne <mhorne@FreeBSD.org>
Reviewed-by: Anup Patel <anup@brainfault.org>
2023-08-06 11:06:02 +05:30
Kaiwen Xue
f46a5643bc lib: sbi: Fix typo for finding fixed event counter
Cycle and instructions are hardware events instead of firmware ones. Fix
the typo in the name of this function.

Signed-off-by: Kaiwen Xue <kaiwenx@andrew.cmu.edu>
Signed-off-by: Kaiwen Xue <kaiwenx@rivosinc.com>
Reviewed-by: Anup patel <anup@brainfault.org>
2023-08-06 10:22:58 +05:30
Anup Patel
6259b2ec2d lib: utils/fdt: Fix fdt_parse_isa_extensions() implementation
Currently, the fdt_parse_isa_extensions() tries to parse the ISA
string once for each HART. This ISA string parsing can fail for
secondary HARTs if the FDT memory is already overwritten by the
supervisor OS.

To tackle this issue, we improve the fdt_parse_isa_extensions()
implementation to pre-parse ISA string for all HARTs during
cold boot.

Fixes: d72f5f1747 ("lib: utils: Add detection of Smepmp from ISA
string in FDT")
Signed-off-by: Anup Patel <apatel@ventanamicro.com>
Tested-By: Mayuresh Chitale<mchitale@ventanamicro.com>
2023-08-06 10:18:51 +05:30
Mayuresh Chitale
c744ed77b1 lib: sbi_pmu: Enable noncontigous hpm event and counters
Platforms may implement hpm events/counters non contiguously but the current
implementation assumes them to be always contigous. Add a bitmap that
captures the hpm events/counters as implemented in the hardware and use
it to set the max limit of hardware counters visible to the OS. Counters
not implemented in the hardware can't be used by the OS because those
wont be described in the DT.

Signed-off-by: Mayuresh Chitale <mchitale@ventanamicro.com>
Reviewed-by: Anup Patel <anup@brainfault.org>
2023-08-06 10:09:25 +05:30
Inochi Amaoto
f536e0b02e gitignore: allow gitignore to ignore most dot file
Nowadays, most of the editor use files or directories begin with dot to
store some settings. So let git ignore these files and directories to
reduce potential mistakes.

Add dot match to ignore any editor file and there are two exceptions:
- .gitignore
- .clang-format

Signed-off-by: Inochi Amaoto <inochiama@outlook.com>
Reviewed-by: Bin Meng <bmeng.cn@gmail.com>
Reviewed-by: Anup Patel <anup@brainfault.org>
2023-08-06 10:07:57 +05:30
Anup Patel
c2e602707d lib: utils/reset: Remove SiFive Test reset driver
The functionality of SiFive Test reset driver is easily available
through Syscon reset driver so let us remove the SiFive Test driver.

Signed-off-by: Anup Patel <apatel@ventanamicro.com>
2023-07-31 14:09:24 +05:30
Anup Patel
4a344a9b4c lib: utils/reset: Add syscon based reboot and poweroff
Let us have common FDT based reset driver for syscon reboot and
poweroff. The device tree bindings for syscon reboot and poweroff
are already available in the Linux kernel sources.

Signed-off-by: Anup Patel <apatel@ventanamicro.com>
Reviewed-by: Xiang W <wxjstz@126.com>
2023-07-31 14:09:21 +05:30
Anup Patel
f21d8f7d59 lib: utils/regmap: Add simple FDT based syscon regmap driver
Let us add a simple FDT based system regmap driver which follows the
device tree bindings already defined in the Linux kernel.

Signed-off-by: Anup Patel <apatel@ventanamicro.com>
Reviewed-by: Xiang W <wxjstz@126.com>
2023-07-31 14:09:13 +05:30
Anup Patel
8e97275d97 lib: utils/regmap: Add simple FDT based regmap framework
We add a simple FDT based regmap framework which is built on top of
generic regmap library. The phandle of FDT regmap DT node is treated
as unique regmap ID. The FDT based regmap drivers will be probed
on-demand from fdt_regmap_get_by_phandle() and fdt_regmap_get()
called by the regmap client drivers.

Signed-off-by: Anup Patel <apatel@ventanamicro.com>
Reviewed-by: Xiang W <wxjstz@126.com>
2023-07-31 14:09:10 +05:30
Anup Patel
14a35b0e0e lib: utils/regmap: Add generic regmap access library
We add generic regmap access library which is independent of
hardware description format (FDT or ACPI). The OpenSBI platform
support or regmap drivers can register regmap instances which
can be discovered by different regmap clients based on the
unique ID of regmap instances.

Signed-off-by: Anup Patel <apatel@ventanamicro.com>
Reviewed-by: Xiang W <wxjstz@126.com>
2023-07-31 14:09:08 +05:30
Anup Patel
44c5151293 include: sbi_utils: Remove driver pointer from struct i2c_adapter
The "driver" pointer in struct i2c_adapter is not used anywhere
so let us remove it.

Signed-off-by: Anup Patel <apatel@ventanamicro.com>
Reviewed-by: Xiang W <wxjstz@126.com>
2023-07-31 14:09:06 +05:30
Xiang W
5e20d25f19 include: sbi: fix CSR define of mseccfg
Because the CSR names in the spec are mseccfg and mseccfgh. Remove
CSR_MSECCFG_LOWER and CSR_MSECCFG_UPPER and directly define
CSR_MSECCFG and CSR_MSECCFGH.

Signed-off-by: Xiang W <wxjstz@126.com>
Reviewed-by: Anup Patel <anup@brainfault.org>
2023-07-31 11:51:49 +05:30
Andrew Jones
e05a9cfefc lib: sbi: Update system suspend to spec
commit 68e66106120f ("SUSP: Add SBI_ERR_DENIED") of the SBI spec adds
a new error code, SBI_ERR_DENIED, which is returned when entry criteria
has not be meant. Update the system suspend implementation to return
this error when it has detected that not all harts are in the STOPPED
state.

Signed-off-by: Andrew Jones <ajones@ventanamicro.com>
Reviewed-by: Anup Patel <anup@brainfault.org>
2023-07-31 11:45:11 +05:30
Heinrich Schuchardt
0e2111e12c libfdt: fix SPDX license identifiers
License identifiers should be machine readable.

According to the SPDX v2.3.0 specification annex E parentheses are not
used in the SPDX identifier field when specifying multiple licenses [1].

[1] https://spdx.github.io/spdx-spec/v2.3/using-SPDX-short-identifiers-in-source-files/

Signed-off-by: Heinrich Schuchardt <heinrich.schuchardt@canonical.com>
Reviewed-by: Anup Patel <anup@brainfault.org>
2023-07-31 11:40:49 +05:30
Himanshu Chauhan
0ad866067d lib: sbi: Map/Unmap debug console shared memory buffers
With Smepmp enabled, it is necessary for shared memory from
S/U mode to be mapped/unmapped before and after read/write
of the memory region. This patch maps the debug console
shared memory before accessing it.

Signed-off-by: Himanshu Chauhan <hchauhan@ventanamicro.com>
Reviewed-by: Anup Patel <anup@brainfault.org>
2023-07-13 12:44:22 +05:30
Himanshu Chauhan
6e44ef686a lib: sbi: Add functions to map/unmap shared memory
When Smepmp is enabled, M-mode will need to map/unmap the
shared memory before it can read/write to it. This patch
adds functions to create dynamic short-lived mappings.

Signed-off-by: Himanshu Chauhan <hchauhan@ventanamicro.com>
Reviewed-by: Anup Patel <anup@brainfault.org>
2023-07-13 12:44:02 +05:30
Himanshu Chauhan
5dd8db5b10 lib: sbi: Add support for Smepmp
- If Smepmp is enabled, the access flags of an entry are determined based on
  truth table defined in Smepmp.
- First PMP entry (index 0) is reserved.
- Existing boot PMP entries start from index 1.
- Since enabling Smepmp revokes the access privileges of the M-mode software
  on S/U-mode region, first PMP entry is used to map/unmap the shared memory
  between M and S/U-mode. This allows a temporary access window for the M-mode
  software to read/write to S/U-mode memory region.

Signed-off-by: Himanshu Chauhan <hchauhan@ventanamicro.com>
Reviewed-by: Anup Patel <anup@brainfault.org>
2023-07-13 12:42:09 +05:30
Himanshu Chauhan
f3fdd041ac lib: sbi: Change the order of PMP initialization
Configure PMP at last when all other initializations have been done.
Because if SMEPMP is detected, M-mode access to the S/U space will be
rescinded.

Signed-off-by: Himanshu Chauhan <hchauhan@ventanamicro.com>
Reviewed-by: Anup Patel <anup@brainfault.org>
2023-07-13 12:42:06 +05:30
Himanshu Chauhan
4a42a2347c lib: sbi: Grant SU R/W/X permissions to whole memory
Since pmp entries have implicit priority on index, previous entries will
deny access to SU on M-mode region. Also, M-mode will not have access to
SU region while previous entries will allow access to M-mode regions.

Signed-off-by: Himanshu Chauhan <hchauhan@ventanamicro.com>
Reviewed-by: Anup Patel <anup@brainfault.org>
2023-07-13 12:27:50 +05:30
Himanshu Chauhan
d72f5f1747 lib: utils: Add detection of Smepmp from ISA string in FDT
- Add function to parse ISA string in FDT.
- Set Smepmp feature bit in extensions if "smepmp" string is found in ISA string.

Signed-off-by: Himanshu Chauhan <hchauhan@ventanamicro.com>
Reviewed-by: Anup Patel <anup@brainfault.org>
2023-07-13 12:12:58 +05:30
Himanshu Chauhan
cbcfc7b10c lib: sbi: Add smepmp in hart extensions
- Add Smepmp as extension in sbi_hart_extensions enum
- Return "smepmp" string for Smepmp extension from sbi_hart_extension_id2string

Signed-off-by: Himanshu Chauhan <hchauhan@ventanamicro.com>
Reviewed-by: Anup Patel <anup@brainfault.org>
2023-07-13 12:12:16 +05:30
Himanshu Chauhan
6c202c5efd include: sbi: Add Smepmp specific access flags for PMP entries
Smepmp specification defines a truth table based on which the access is allowed to
different modes. This patch adds different flags based on this truth table.

Signed-off-by: Himanshu Chauhan <hchauhan@ventanamicro.com>
Reviewed-by: Anup Patel <anup@brainfault.org>
2023-07-13 12:11:10 +05:30
Himanshu Chauhan
1c099c4f36 lib: sbi: Add functions to manipulate PMP entries
- Add a function to disable a given PMP entry.
- Add a function to check if a given entry is disabled.

Signed-off-by: Himanshu Chauhan <hchauhan@ventanamicro.com>
Reviewed-by: Anup Patel <anup@brainfault.org>
2023-07-13 12:10:39 +05:30
Himanshu Chauhan
c3b98c610b include: sbi: Add macro definitions for mseccfg CSR
- Add macros for Machine Security Configuration (mseccfg) CSR
- Add macros to access/manipulate bits in msecfg CSR

Signed-off-by: Himanshu Chauhan <hchauhan@ventanamicro.com>
Reviewed-by: Anup Patel <anup@brainfault.org>
2023-07-13 12:09:34 +05:30
Anup Patel
ea6533ada8 lib: utils/gpio: Fix RV32 compile error for designware GPIO driver
Currently, we see following compile error in the designeware GPIO driver
for RV32 systems:

lib/utils/gpio/fdt_gpio_designware.c:115:20: error: cast to pointer from integer of different size [-Werror=int-to-pointer-cast]
  115 |         chip->dr = (void *)addr + (bank * 0xc);
      |                    ^
lib/utils/gpio/fdt_gpio_designware.c:116:21: error: cast to pointer from integer of different size [-Werror=int-to-pointer-cast]
  116 |         chip->ext = (void *)addr + (bank * 4) + 0x50;

We fix the above error using an explicit type-cast to 'unsigned long'.

Fixes: 7828eebaaa ("gpio/desginware: add Synopsys DesignWare APB GPIO support")
Signed-off-by: Anup Patel <apatel@ventanamicro.com>
Reviewed-by: Xiang W <wxjstz@126.com>
2023-07-12 11:22:03 +05:30
Xiang W
a73982d737 lib: sbi: Fix missing '\0' when buffer szie equal 1
Fix special case: sbi_snprintf(out, out_len, ...) when out_len equal
1, The previous code will not fill the buffer with any char.

Signed-off-by: Xiang W <wxjstz@126.com>
Reviewed-by: Anup Patel <anup@brainfault.org>
2023-07-12 10:37:43 +05:30
Xiang W
ff43168137 lib: sbi: Fix timing of clearing tbuf
A single scan of the format char may add multiple characters to the
tbuf, causing a buffer overflow. You should check if tbuf is full in
printc so that it does not cause a buffer overflow.

Signed-off-by: Xiang W <wxjstz@126.com>
Reviewed-by: Anup Patel <anup@brainfault.org>
2023-07-12 10:37:16 +05:30
Xiang W
cc89fa7b54 lib: sbi: Fix printc
Because *out needs to reserve a byte to hold '\0', no more characters
should be added to the buffer when *out has one byte left, and the
buffer size *out_len should not be modified. this patch prevents
the correction of *out_len when *out_len is 1.

Signed-off-by: Xiang W <wxjstz@126.com>
Reviewed-by: Anup Patel <anup@brainfault.org>
2023-07-12 10:02:27 +05:30
Xiang W
3b6fcddceb lib: sbi: Simplify prints
When doing width = width - strlen(string) in prints there is no need
to consider the case that witdh may be less than 0. This is because
the code to do filling needs to be executed under the condition that
width > 0.

Signed-off-by: Xiang W <wxjstz@126.com>
Reviewed-by: Anup Patel <anup@brainfault.org>
2023-07-12 10:02:06 +05:30
Xiang W
c6ee5ae5a4 lib: sbi: Fix printi
Fix two bug:
> printf("%#08x", 0x123); /* print 0000x123 */
> printf("%#x", 0); /* print 0x0 */

Signed-off-by: Xiang W <wxjstz@126.com>
Reviewed-by: Anup Patel <anup@brainfault.org>
2023-07-12 10:01:43 +05:30
Xiang W
fe0828142f lib: sbi: print add 'o' type
Add o type for print to print octal numbers

Signed-off-by: Xiang W <wxjstz@126.com>
Reviewed-by: Anup Patel <anup@brainfault.org>
2023-07-12 09:59:22 +05:30
Xiang W
05cbb6e908 lib: sbi: implifying the parameters of printi
The information of sg/b/letbase can be obtained by the type character,
simplifying the parameter by passing the type directly.

Signed-off-by: Xiang W <wxjstz@126.com>
Reviewed-by: Anup Patel <anup@brainfault.org>
2023-07-12 09:58:52 +05:30
Xiang W
458fa74266 lib: sbi: Add ' ' '\'' flags for print
The space flag is used to add a space before positive numbers, and
apostrophe is used to print the thousand separator. Add code to
ignore these two flags

Signed-off-by: Xiang W <wxjstz@126.com>
Reviewed-by: Anup Patel <anup@brainfault.org>
2023-07-12 09:58:00 +05:30
Xiang W
40dac06e3c lib: sbi: Add '+' flags for print
Adds + flags for print, prefixing positive numbers with + when this
flags is present

Signed-off-by: Xiang W <wxjstz@126.com>
Reviewed-by: Anup Patel <anup@brainfault.org>
2023-07-12 09:57:48 +05:30
Xiang W
35ef182690 lib: sbi: print not fill '0' when left-aligned
Left alignment and padding '0' should not exist at the same time,
this patch skips padding.

Signed-off-by: Xiang W <wxjstz@126.com>
Reviewed-by: Anup Patel <anup@brainfault.org>
2023-07-12 09:48:49 +05:30
Xiang W
6053917626 lib: sbi: Fix how print gets flags
The flags for print should be able to appear in any order. The
previous code required the order to be fixed.

Signed-off-by: Xiang W <wxjstz@126.com>
Reviewed-by: Anup Patel <anup@brainfault.org>
2023-07-12 09:39:38 +05:30
Ley Foon Tan
976895c57e lib: sbi: Fix Priv spec version for [m|s]counteren and mcountinhibit CSRs
Fix Priv spec version typo in commit d4b563c881 ("lib: sbi: Remove MCOUNTEREN
and SCOUNTEREN hart features").

At least Priv spec v1.11 is required for [m|s]counteren and mcountinhibit CSRs.

Fixes: d4b563c881 ("lib: sbi: Remove MCOUNTEREN and SCOUNTEREN hart features")
Signed-off-by: Ley Foon Tan <leyfoon.tan@starfivetech.com>
Reviewed-by: Anup Patel <anup@brainfault.org>
2023-07-09 11:08:35 +05:30
Anup Patel
5359fc6955 lib: sbi: Rename hart_pmu_get_allowed_bits() function
The hart_pmu_get_allowed_bits() function detects implemented bits
of mhpm counters so let us rename this function accordingly.

Signed-off-by: Anup Patel <apatel@ventanamicro.com>
Reviewed-by: Xiang W <wxjstz@126.com>
2023-07-09 11:06:30 +05:30
Anup Patel
72b9c8ff89 lib: sbi: Alphabetically sort HART ISA extensions
Let us follow alphabetical order for HART ISA extension so that
it is simpler to maintain.

Signed-off-by: Anup Patel <apatel@ventanamicro.com>
Reviewed-by: Xiang W <wxjstz@126.com>
2023-07-09 11:06:28 +05:30
Anup Patel
669089c5f2 lib: sbi: Add Zihpm as a HART ISA extension
Recently ratified Zihpm ISA extension covers all [m]hpm* CSRs
so we add Zihpm as a HART ISA extension in OpenSBI.

Signed-off-by: Anup Patel <apatel@ventanamicro.com>
Reviewed-by: Xiang W <wxjstz@126.com>
2023-07-09 11:06:26 +05:30
Anup Patel
1a398d9faa lib: sbi: Add Zicntr as a HART ISA extension
Recently ratified Zicntr ISA extension covers cycle, time and
instret CSRs so we replace the "time" ISA extension with "zicntr"
ISA extension in OpenSBI.

Signed-off-by: Anup Patel <apatel@ventanamicro.com>
Reviewed-by: Xiang W <wxjstz@126.com>
2023-07-09 11:06:24 +05:30
155 changed files with 3442 additions and 1816 deletions

8
.gitignore vendored
View File

@@ -1,3 +1,10 @@
# ignore anything begin with dot
.*
# exceptions we need even begin with dot
!.clang-format
!.gitignore
# Object files
*.o
*.a
@@ -10,4 +17,3 @@ install/
# Development friendly files
tags
cscope*
*.swp

View File

@@ -168,7 +168,7 @@ endif
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)
CC_SUPPORT_SAVE_RESTORE := $(shell $(CC) $(CLANG_TARGET) $(RELAX_FLAG) -nostdlib -mno-save-restore -x c /dev/null -o /dev/null 2>&1 | grep -e "-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)
@@ -375,6 +375,7 @@ ASFLAGS += $(firmware-asflags-y)
ARFLAGS = rcs
ELFFLAGS += $(USE_LD_FLAG)
ELFFLAGS += -Wl,--exclude-libs,ALL
ELFFLAGS += -Wl,--build-id=none
ELFFLAGS += $(platform-ldflags-y)
ELFFLAGS += $(firmware-ldflags-y)

View File

@@ -36,7 +36,7 @@ options. These configuration parameters can be defined using either the top
level `make` command line or the target platform *objects.mk* configuration
file. The parameters currently defined are as follows:
* **FW_PAYLOAD_OFFSET** - Offset from *FW_TEXT_BASE* where the payload binary
* **FW_PAYLOAD_OFFSET** - Offset from *FW_TEXT_START* where the payload binary
will be linked in the final *FW_PAYLOAD* firmware binary image. This
configuration parameter is mandatory if *FW_PAYLOAD_ALIGN* is not defined.
Compilation errors will result from an incorrect definition of

View File

@@ -1,7 +1,7 @@
T-HEAD C9xx Series Processors
=============================
The **C9xx** series processors are high-performance RISC-V architecture
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/)
@@ -12,185 +12,16 @@ To build the platform-specific library and firmware images, provide the
Platform Options
----------------
The *T-HEAD C9xx* does not have any platform-specific compile options
The T-HEAD C9xx does not have any platform-specific compile options
because it uses generic platform.
```
CROSS_COMPILE=riscv64-linux-gnu- PLATFORM=generic /usr/bin/make
CROSS_COMPILE=riscv64-linux-gnu- PLATFORM=generic make
```
The *T-HEAD C9xx* DTB provided to OpenSBI generic firmwares will usually have
"riscv,clint0", "riscv,plic0", "thead,reset-sample" compatible strings.
Here is the simplest boot flow for a fpga prototype:
DTS Example1: (Single core, eg: Allwinner D1 - c906)
----------------------------------------------------
(Jtag gdbinit) -> (zsb) -> (opensbi) -> (linux)
```
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>;
};
```
For more details, refer:
[zero stage boot](https://github.com/c-sky/zero_stage_boot)

View File

@@ -18,7 +18,7 @@ Base Platform Requirements
The base RISC-V platform requirements for OpenSBI are as follows:
1. At least rv32ima or rv64ima required on all HARTs
1. At least rv32ima_zicsr or rv64ima_zicsr required on all HARTs
2. At least one HART should have S-mode support because:
* SBI calls are meant for RISC-V S-mode (Supervisor mode)
@@ -33,7 +33,7 @@ The base RISC-V platform requirements for OpenSBI are as follows:
6. Hardware support for injecting M-mode software interrupts on
a multi-HART platform
The RISC-V extensions not covered by rv32ima or rv64ima are optional
The RISC-V extensions not covered by rv32ima_zicsr or rv64ima_zicsr are optional
for OpenSBI. Although, OpenSBI will detect and handle some of these
optional RISC-V extensions at runtime.

View File

@@ -125,3 +125,85 @@ pmu {
<0x0 0x2 0xffffffff 0xffffe0ff 0x18>;
};
```
### Example 3
```
/*
* For Andes 45-series platforms. The encodings can be found in the
* "Machine Performance Monitoring Event Selector" section
* http://www.andestech.com/wp-content/uploads/AX45MP-1C-Rev.-5.0.0-Datasheet.pdf
*/
pmu {
compatible = "riscv,pmu";
riscv,event-to-mhpmevent =
<0x1 0x0000 0x10>, /* CPU_CYCLES -> Cycle count */
<0x2 0x0000 0x20>, /* INSTRUCTIONS -> Retired instruction count */
<0x3 0x0000 0x41>, /* CACHE_REFERENCES -> D-Cache access */
<0x4 0x0000 0x51>, /* CACHE_MISSES -> D-Cache miss */
<0x5 0x0000 0x80>, /* BRANCH_INSTRUCTIONS -> Conditional branch instruction count */
<0x6 0x0000 0x02>, /* BRANCH_MISSES -> Misprediction of conditional branches */
<0x10000 0x0000 0x61>, /* L1D_READ_ACCESS -> D-Cache load access */
<0x10001 0x0000 0x71>, /* L1D_READ_MISS -> D-Cache load miss */
<0x10002 0x0000 0x81>, /* L1D_WRITE_ACCESS -> D-Cache store access */
<0x10003 0x0000 0x91>, /* L1D_WRITE_MISS -> D-Cache store miss */
<0x10008 0x0000 0x21>, /* L1I_READ_ACCESS -> I-Cache access */
<0x10009 0x0000 0x31>; /* L1I_READ_MISS -> I-Cache miss */
riscv,event-to-mhpmcounters = <0x1 0x6 0x78>,
<0x10000 0x10003 0x78>,
<0x10008 0x10009 0x78>;
riscv,raw-event-to-mhpmcounters =
<0x0 0x10 0xffffffff 0xffffffff 0x78>, /* Cycle count */
<0x0 0x20 0xffffffff 0xffffffff 0x78>, /* Retired instruction count */
<0x0 0x30 0xffffffff 0xffffffff 0x78>, /* Integer load instruction count */
<0x0 0x40 0xffffffff 0xffffffff 0x78>, /* Integer store instruction count */
<0x0 0x50 0xffffffff 0xffffffff 0x78>, /* Atomic instruction count */
<0x0 0x60 0xffffffff 0xffffffff 0x78>, /* System instruction count */
<0x0 0x70 0xffffffff 0xffffffff 0x78>, /* Integer computational instruction count */
<0x0 0x80 0xffffffff 0xffffffff 0x78>, /* Conditional branch instruction count */
<0x0 0x90 0xffffffff 0xffffffff 0x78>, /* Taken conditional branch instruction count */
<0x0 0xA0 0xffffffff 0xffffffff 0x78>, /* JAL instruction count */
<0x0 0xB0 0xffffffff 0xffffffff 0x78>, /* JALR instruction count */
<0x0 0xC0 0xffffffff 0xffffffff 0x78>, /* Return instruction count */
<0x0 0xD0 0xffffffff 0xffffffff 0x78>, /* Control transfer instruction count */
<0x0 0xE0 0xffffffff 0xffffffff 0x78>, /* EXEC.IT instruction count */
<0x0 0xF0 0xffffffff 0xffffffff 0x78>, /* Integer multiplication instruction count */
<0x0 0x100 0xffffffff 0xffffffff 0x78>, /* Integer division instruction count */
<0x0 0x110 0xffffffff 0xffffffff 0x78>, /* Floating-point load instruction count */
<0x0 0x120 0xffffffff 0xffffffff 0x78>, /* Floating-point store instruction count */
<0x0 0x130 0xffffffff 0xffffffff 0x78>, /* Floating-point addition/subtraction instruction count */
<0x0 0x140 0xffffffff 0xffffffff 0x78>, /* Floating-point multiplication instruction count */
<0x0 0x150 0xffffffff 0xffffffff 0x78>, /* Floating-point fused multiply-add instruction count */
<0x0 0x160 0xffffffff 0xffffffff 0x78>, /* Floating-point division or square-root instruction count */
<0x0 0x170 0xffffffff 0xffffffff 0x78>, /* Other floating-point instruction count */
<0x0 0x180 0xffffffff 0xffffffff 0x78>, /* Integer multiplication and add/sub instruction count */
<0x0 0x190 0xffffffff 0xffffffff 0x78>, /* Retired operation count */
<0x0 0x01 0xffffffff 0xffffffff 0x78>, /* ILM access */
<0x0 0x11 0xffffffff 0xffffffff 0x78>, /* DLM access */
<0x0 0x21 0xffffffff 0xffffffff 0x78>, /* I-Cache access */
<0x0 0x31 0xffffffff 0xffffffff 0x78>, /* I-Cache miss */
<0x0 0x41 0xffffffff 0xffffffff 0x78>, /* D-Cache access */
<0x0 0x51 0xffffffff 0xffffffff 0x78>, /* D-Cache miss */
<0x0 0x61 0xffffffff 0xffffffff 0x78>, /* D-Cache load access */
<0x0 0x71 0xffffffff 0xffffffff 0x78>, /* D-Cache load miss */
<0x0 0x81 0xffffffff 0xffffffff 0x78>, /* D-Cache store access */
<0x0 0x91 0xffffffff 0xffffffff 0x78>, /* D-Cache store miss */
<0x0 0xA1 0xffffffff 0xffffffff 0x78>, /* D-Cache writeback */
<0x0 0xB1 0xffffffff 0xffffffff 0x78>, /* Cycles waiting for I-Cache fill data */
<0x0 0xC1 0xffffffff 0xffffffff 0x78>, /* Cycles waiting for D-Cache fill data */
<0x0 0xD1 0xffffffff 0xffffffff 0x78>, /* Uncached fetch data access from bus */
<0x0 0xE1 0xffffffff 0xffffffff 0x78>, /* Uncached load data access from bus */
<0x0 0xF1 0xffffffff 0xffffffff 0x78>, /* Cycles waiting for uncached fetch data from bus */
<0x0 0x101 0xffffffff 0xffffffff 0x78>, /* Cycles waiting for uncached load data from bus */
<0x0 0x111 0xffffffff 0xffffffff 0x78>, /* Main ITLB access */
<0x0 0x121 0xffffffff 0xffffffff 0x78>, /* Main ITLB miss */
<0x0 0x131 0xffffffff 0xffffffff 0x78>, /* Main DTLB access */
<0x0 0x141 0xffffffff 0xffffffff 0x78>, /* Main DTLB miss */
<0x0 0x151 0xffffffff 0xffffffff 0x78>, /* Cycles waiting for Main ITLB fill data */
<0x0 0x161 0xffffffff 0xffffffff 0x78>, /* Pipeline stall cycles caused by Main DTLB miss */
<0x0 0x171 0xffffffff 0xffffffff 0x78>, /* Hardware prefetch bus access */
<0x0 0x02 0xffffffff 0xffffffff 0x78>, /* Misprediction of conditional branches */
<0x0 0x12 0xffffffff 0xffffffff 0x78>, /* Misprediction of taken conditional branches */
<0x0 0x22 0xffffffff 0xffffffff 0x78>; /* Misprediction of targets of Return instructions */
};
```

View File

@@ -88,30 +88,8 @@ _try_lottery:
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:
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, 0(t0)
li t5, SYM_SIZE
mul t6, t6, t5
add s5, t4, t6
REG_L t6, (REGBYTES * 2)(t0) /* t0 <-- addend */
REG_L t5, REGBYTES(s5)
add t5, t5, t6
add t5, t5, t2 /* t5 <-- location to fix up in RAM */
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)
blt t0, t1, 2b
j _relocate_done
@@ -309,8 +287,8 @@ _scratch_init:
REG_S a5, SBI_SCRATCH_FW_SIZE_OFFSET(tp)
/* Store R/W section's offset in scratch space */
lla a4, __fw_rw_offset
REG_L a5, 0(a4)
lla a5, _fw_rw_start
sub a5, a5, a4
REG_S a5, SBI_SCRATCH_FW_RW_OFFSET(tp)
/* Store fw_heap_offset and fw_heap_size in scratch space */
@@ -421,8 +399,8 @@ _fdt_reloc_done:
/* mark boot hart done */
li t0, BOOT_STATUS_BOOT_HART_DONE
lla t1, _boot_status
REG_S t0, 0(t1)
fence rw, rw
REG_S t0, 0(t1)
j _start_warm
/* waiting for boot hart to be done (_boot_status == 2) */
@@ -431,9 +409,9 @@ _wait_for_boot_hart:
lla t1, _boot_status
REG_L t1, 0(t1)
/* Reduce the bus traffic so that boot hart may proceed faster */
nop
nop
nop
div t2, t2, zero
div t2, t2, zero
div t2, t2, zero
bne t0, t1, _wait_for_boot_hart
_start_warm:
@@ -536,8 +514,6 @@ _link_start:
RISCV_PTR FW_TEXT_START
_link_end:
RISCV_PTR _fw_reloc_end
__fw_rw_offset:
RISCV_PTR _fw_rw_start - _fw_start
.section .entry, "ax", %progbits
.align 3

View File

@@ -40,16 +40,9 @@
. = ALIGN(0x1000); /* Ensure next section is page aligned */
.dynsym : {
PROVIDE(__dyn_sym_start = .);
*(.dynsym)
PROVIDE(__dyn_sym_end = .);
}
.rela.dyn : {
PROVIDE(__rel_dyn_start = .);
*(.rela*)
. = ALIGN(8);
PROVIDE(__rel_dyn_end = .);
}

View File

@@ -129,7 +129,7 @@ fw_options:
REG_L a0, (a0)
ret
.section .entry, "ax", %progbits
.section .data
.align 3
_dynamic_next_arg1:
RISCV_PTR 0x0

View File

@@ -90,7 +90,7 @@ fw_options:
#error "Must define FW_JUMP_ADDR"
#endif
.section .entry, "ax", %progbits
.section .rodata
.align 3
_jump_addr:
RISCV_PTR FW_JUMP_ADDR

View File

@@ -78,7 +78,7 @@ _start_hang:
wfi
j _start_hang
.section .entry, "ax", %progbits
.section .data
.align 3
_hart_lottery:
RISCV_PTR 0

View File

@@ -8,31 +8,42 @@
*/
#include <sbi/sbi_ecall_interface.h>
#include <sbi/sbi_string.h>
#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 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"(a6), "r"(a7) \
: "memory"); \
a0; \
})
struct sbiret {
unsigned long error;
unsigned long value;
};
#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)
struct sbiret sbi_ecall(int ext, int fid, unsigned long arg0,
unsigned long arg1, unsigned long arg2,
unsigned long arg3, unsigned long arg4,
unsigned long arg5)
{
struct sbiret ret;
#define sbi_ecall_console_putc(c) SBI_ECALL_1(SBI_EXT_0_1_CONSOLE_PUTCHAR, 0, (c))
register unsigned long a0 asm ("a0") = (unsigned long)(arg0);
register unsigned long a1 asm ("a1") = (unsigned long)(arg1);
register unsigned long a2 asm ("a2") = (unsigned long)(arg2);
register unsigned long a3 asm ("a3") = (unsigned long)(arg3);
register unsigned long a4 asm ("a4") = (unsigned long)(arg4);
register unsigned long a5 asm ("a5") = (unsigned long)(arg5);
register unsigned long a6 asm ("a6") = (unsigned long)(fid);
register unsigned long a7 asm ("a7") = (unsigned long)(ext);
asm volatile ("ecall"
: "+r" (a0), "+r" (a1)
: "r" (a2), "r" (a3), "r" (a4), "r" (a5), "r" (a6), "r" (a7)
: "memory");
ret.error = a0;
ret.value = a1;
return ret;
}
static inline void sbi_ecall_console_puts(const char *str)
{
while (str && *str)
sbi_ecall_console_putc(*str++);
sbi_ecall(SBI_EXT_DBCN, SBI_EXT_DBCN_CONSOLE_WRITE,
sbi_strlen(str), (unsigned long)str, 0, 0, 0, 0);
}
#define wfi() \

View File

@@ -181,6 +181,12 @@ int misa_xlen(void);
/* Get RISC-V ISA string representation */
void misa_string(int xlen, char *out, unsigned int out_sz);
/* Disable pmp entry at a given index */
int pmp_disable(unsigned int n);
/* Check if the matching field is set */
int is_pmp_entry_mapped(unsigned long entry);
int pmp_set(unsigned int n, unsigned long prot, unsigned long addr,
unsigned long log2len);

View File

@@ -39,14 +39,14 @@ unsigned int atomic_raw_xchg_uint(volatile unsigned int *ptr,
unsigned long atomic_raw_xchg_ulong(volatile unsigned long *ptr,
unsigned long newval);
/**
* Set a bit in an atomic variable and return the new value.
* Set a bit in an atomic variable and return the value of bit before modify.
* @nr : Bit to set.
* @atom: atomic variable to modify
*/
int atomic_set_bit(int nr, atomic_t *atom);
/**
* Clear a bit in an atomic variable and return the new value.
* Clear a bit in an atomic variable and return the value of bit before modify.
* @nr : Bit to set.
* @atom: atomic variable to modify
*/
@@ -54,14 +54,14 @@ int atomic_set_bit(int nr, atomic_t *atom);
int atomic_clear_bit(int nr, atomic_t *atom);
/**
* Set a bit in any address and return the new value .
* Set a bit in any address and return the value of bit before modify.
* @nr : Bit to set.
* @addr: Address to modify
*/
int atomic_raw_set_bit(int nr, volatile unsigned long *addr);
/**
* Clear a bit in any address and return the new value .
* Clear a bit in any address and return the value of bit before modify.
* @nr : Bit to set.
* @addr: Address to modify
*/

View File

@@ -1,14 +1,6 @@
#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

@@ -207,13 +207,8 @@
#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
@@ -430,6 +425,7 @@
#define CSR_MARCHID 0xf12
#define CSR_MIMPID 0xf13
#define CSR_MHARTID 0xf14
#define CSR_MCONFIGPTR 0xf15
/* Machine Trap Setup */
#define CSR_MSTATUS 0x300
@@ -602,6 +598,8 @@
/* Machine Counter Setup */
#define CSR_MCOUNTINHIBIT 0x320
#define CSR_MCYCLECFG 0x321
#define CSR_MINSTRETCFG 0x322
#define CSR_MHPMEVENT3 0x323
#define CSR_MHPMEVENT4 0x324
#define CSR_MHPMEVENT5 0x325
@@ -633,6 +631,8 @@
#define CSR_MHPMEVENT31 0x33f
/* For RV32 */
#define CSR_MCYCLECFGH 0x721
#define CSR_MINSTRETCFGH 0x722
#define CSR_MHPMEVENT3H 0x723
#define CSR_MHPMEVENT4H 0x724
#define CSR_MHPMEVENT5H 0x725
@@ -663,6 +663,21 @@
#define CSR_MHPMEVENT30H 0x73e
#define CSR_MHPMEVENT31H 0x73f
/* Machine Security Configuration CSR (mseccfg) */
#define CSR_MSECCFG 0x747
#define CSR_MSECCFGH 0x757
#define MSECCFG_MML_SHIFT (0)
#define MSECCFG_MML (_UL(1) << MSECCFG_MML_SHIFT)
#define MSECCFG_MMWP_SHIFT (1)
#define MSECCFG_MMWP (_UL(1) << MSECCFG_MMWP_SHIFT)
#define MSECCFG_RLB_SHIFT (2)
#define MSECCFG_RLB (_UL(1) << MSECCFG_RLB_SHIFT)
#define MSECCFG_USEED_SHIFT (8)
#define MSECCFG_USEED (_UL(1) << MSECCFG_USEED_SHIFT)
#define MSECCFG_SSEED_SHIFT (9)
#define MSECCFG_SSEED (_UL(1) << MSECCFG_SSEED_SHIFT)
/* Counter Overflow CSR */
#define CSR_SCOUNTOVF 0xda0

View File

@@ -84,7 +84,7 @@
#define GET_FFLAGS() csr_read(CSR_FFLAGS)
#define SET_FFLAGS(value) csr_write(CSR_FFLAGS, (value))
#define SET_FS_DIRTY() ((void)0)
#define SET_FS_DIRTY(regs) (regs->mstatus |= MSTATUS_FS)
#define GET_F32_RS1(insn, regs) (GET_F32_REG(insn, 15, regs))
#define GET_F32_RS2(insn, regs) (GET_F32_REG(insn, 20, regs))
@@ -93,9 +93,9 @@
#define GET_F64_RS2(insn, regs) (GET_F64_REG(insn, 20, regs))
#define GET_F64_RS3(insn, regs) (GET_F64_REG(insn, 27, regs))
#define SET_F32_RD(insn, regs, val) \
(SET_F32_REG(insn, 7, regs, val), SET_FS_DIRTY())
(SET_F32_REG(insn, 7, regs, val), SET_FS_DIRTY(regs))
#define SET_F64_RD(insn, regs, val) \
(SET_F64_REG(insn, 7, regs, val), SET_FS_DIRTY())
(SET_F64_REG(insn, 7, regs, val), SET_FS_DIRTY(regs))
#define GET_F32_RS2C(insn, regs) (GET_F32_REG(insn, 2, regs))
#define GET_F32_RS2S(insn, regs) (GET_F32_REG(RVC_RS2S(insn), 0, regs))

View File

@@ -26,6 +26,7 @@
#define BIT_MASK(nr) (1UL << ((nr) % BITS_PER_LONG))
#define BIT_WORD(bit) ((bit) / BITS_PER_LONG)
#define BIT_WORD_OFFSET(bit) ((bit) & (BITS_PER_LONG - 1))
#define BIT_ALIGN(bit, align) (((bit) + ((align) - 1)) & ~((align) - 1))
#define GENMASK(h, l) \
(((~0UL) - (1UL << (l)) + 1) & (~0UL >> (BITS_PER_LONG - 1 - (h))))
@@ -112,6 +113,22 @@ static inline unsigned long sbi_fls(unsigned long word)
return num;
}
/**
* sbi_popcount - find the number of set bit in a long word
* @word: the word to search
*/
static inline unsigned long sbi_popcount(unsigned long word)
{
unsigned long count = 0;
while (word) {
word &= word - 1;
count++;
}
return count;
}
#define for_each_set_bit(bit, addr, size) \
for ((bit) = find_first_bit((addr), (size)); \
(bit) < (size); \

View File

@@ -43,6 +43,80 @@ struct sbi_domain_memregion {
#define SBI_DOMAIN_MEMREGION_SU_WRITABLE (1UL << 4)
#define SBI_DOMAIN_MEMREGION_SU_EXECUTABLE (1UL << 5)
#define SBI_DOMAIN_MEMREGION_ACCESS_MASK (0x3fUL)
#define SBI_DOMAIN_MEMREGION_M_ACCESS_MASK (0x7UL)
#define SBI_DOMAIN_MEMREGION_SU_ACCESS_MASK (0x38UL)
#define SBI_DOMAIN_MEMREGION_SU_ACCESS_SHIFT (3)
#define SBI_DOMAIN_MEMREGION_SHARED_RDONLY \
(SBI_DOMAIN_MEMREGION_M_READABLE | \
SBI_DOMAIN_MEMREGION_SU_READABLE)
#define SBI_DOMAIN_MEMREGION_SHARED_SUX_MRX \
(SBI_DOMAIN_MEMREGION_M_READABLE | \
SBI_DOMAIN_MEMREGION_M_EXECUTABLE | \
SBI_DOMAIN_MEMREGION_SU_EXECUTABLE)
#define SBI_DOMAIN_MEMREGION_SHARED_SUX_MX \
(SBI_DOMAIN_MEMREGION_M_EXECUTABLE | \
SBI_DOMAIN_MEMREGION_SU_EXECUTABLE)
#define SBI_DOMAIN_MEMREGION_SHARED_SURW_MRW \
(SBI_DOMAIN_MEMREGION_M_READABLE | \
SBI_DOMAIN_MEMREGION_M_WRITABLE | \
SBI_DOMAIN_MEMREGION_SU_READABLE| \
SBI_DOMAIN_MEMREGION_SU_WRITABLE)
#define SBI_DOMAIN_MEMREGION_SHARED_SUR_MRW \
(SBI_DOMAIN_MEMREGION_M_READABLE | \
SBI_DOMAIN_MEMREGION_M_WRITABLE | \
SBI_DOMAIN_MEMREGION_SU_READABLE)
/* Shared read-only region between M and SU mode */
#define SBI_DOMAIN_MEMREGION_IS_SUR_MR(__flags) \
((__flags & SBI_DOMAIN_MEMREGION_ACCESS_MASK) == \
SBI_DOMAIN_MEMREGION_SHARED_RDONLY)
/* Shared region: SU execute-only and M read/execute */
#define SBI_DOMAIN_MEMREGION_IS_SUX_MRX(__flags) \
((__flags & SBI_DOMAIN_MEMREGION_ACCESS_MASK) == \
SBI_DOMAIN_MEMREGION_SHARED_SUX_MRX)
/* Shared region: SU and M execute-only */
#define SBI_DOMAIN_MEMREGION_IS_SUX_MX(__flags) \
((__flags & SBI_DOMAIN_MEMREGION_ACCESS_MASK) == \
SBI_DOMAIN_MEMREGION_SHARED_SUX_MX)
/* Shared region: SU and M read/write */
#define SBI_DOMAIN_MEMREGION_IS_SURW_MRW(__flags) \
((__flags & SBI_DOMAIN_MEMREGION_ACCESS_MASK) == \
SBI_DOMAIN_MEMREGION_SHARED_SURW_MRW)
/* Shared region: SU read-only and M read/write */
#define SBI_DOMAIN_MEMREGION_IS_SUR_MRW(__flags) \
((__flags & SBI_DOMAIN_MEMREGION_ACCESS_MASK) == \
SBI_DOMAIN_MEMREGION_SHARED_SUR_MRW)
/*
* Check if region flags match with any of the above
* mentioned shared region type
*/
#define SBI_DOMAIN_MEMREGION_IS_SHARED(_flags) \
(SBI_DOMAIN_MEMREGION_IS_SUR_MR(_flags) || \
SBI_DOMAIN_MEMREGION_IS_SUX_MRX(_flags) || \
SBI_DOMAIN_MEMREGION_IS_SUX_MX(_flags) || \
SBI_DOMAIN_MEMREGION_IS_SURW_MRW(_flags)|| \
SBI_DOMAIN_MEMREGION_IS_SUR_MRW(_flags))
#define SBI_DOMAIN_MEMREGION_M_ONLY_ACCESS(__flags) \
((__flags & SBI_DOMAIN_MEMREGION_M_ACCESS_MASK) && \
!(__flags & SBI_DOMAIN_MEMREGION_SU_ACCESS_MASK))
#define SBI_DOMAIN_MEMREGION_SU_ONLY_ACCESS(__flags) \
((__flags & SBI_DOMAIN_MEMREGION_SU_ACCESS_MASK) && \
!(__flags & SBI_DOMAIN_MEMREGION_M_ACCESS_MASK))
/** Bit to control if permissions are enforced on all modes */
#define SBI_DOMAIN_MEMREGION_ENF_PERMISSIONS (1UL << 6)
@@ -78,12 +152,6 @@ struct sbi_domain_memregion {
(SBI_DOMAIN_MEMREGION_SU_EXECUTABLE | \
SBI_DOMAIN_MEMREGION_M_EXECUTABLE)
#define SBI_DOMAIN_MEMREGION_ACCESS_MASK (0x3fUL)
#define SBI_DOMAIN_MEMREGION_M_ACCESS_MASK (0x7UL)
#define SBI_DOMAIN_MEMREGION_SU_ACCESS_MASK (0x38UL)
#define SBI_DOMAIN_MEMREGION_SU_ACCESS_SHIFT (3)
#define SBI_DOMAIN_MEMREGION_MMIO (1UL << 31)
unsigned long flags;
};
@@ -129,12 +197,12 @@ struct sbi_domain {
/** The root domain instance */
extern struct sbi_domain root;
/** Get pointer to sbi_domain from HART id */
struct sbi_domain *sbi_hartid_to_domain(u32 hartid);
/** Get pointer to sbi_domain from HART index */
struct sbi_domain *sbi_hartindex_to_domain(u32 hartindex);
/** Get pointer to sbi_domain for current HART */
#define sbi_domain_thishart_ptr() \
sbi_hartid_to_domain(current_hartid())
sbi_hartindex_to_domain(sbi_hartid_to_hartindex(current_hartid()))
/** Index to domain table */
extern struct sbi_domain *domidx_to_domain_table[];

View File

@@ -13,13 +13,20 @@
#include <sbi/sbi_types.h>
#include <sbi/sbi_list.h>
#define SBI_ECALL_VERSION_MAJOR 1
#define SBI_ECALL_VERSION_MAJOR 2
#define SBI_ECALL_VERSION_MINOR 0
#define SBI_OPENSBI_IMPID 1
struct sbi_trap_regs;
struct sbi_trap_info;
struct sbi_ecall_return {
/* Return flag to skip register update */
bool skip_regs_update;
/* Return value */
unsigned long value;
};
struct sbi_ecall_extension {
/* head is used by the extension list */
struct sbi_dlist head;
@@ -62,9 +69,8 @@ struct sbi_ecall_extension {
* never invoked with an invalid or unavailable extension ID.
*/
int (* handle)(unsigned long extid, unsigned long funcid,
const struct sbi_trap_regs *regs,
unsigned long *out_val,
struct sbi_trap_info *out_trap);
struct sbi_trap_regs *regs,
struct sbi_ecall_return *out);
};
u16 sbi_ecall_version_major(void);

View File

@@ -103,6 +103,7 @@
#define SBI_EXT_PMU_COUNTER_STOP 0x4
#define SBI_EXT_PMU_COUNTER_FW_READ 0x5
#define SBI_EXT_PMU_COUNTER_FW_READ_HI 0x6
#define SBI_EXT_PMU_SNAPSHOT_SET_SHMEM 0x7
/** General pmu event codes specified in SBI PMU extension */
enum sbi_pmu_hw_generic_events_t {
@@ -241,9 +242,11 @@ enum sbi_pmu_ctr_type {
/* Flags defined for counter start function */
#define SBI_PMU_START_FLAG_SET_INIT_VALUE (1 << 0)
#define SBI_PMU_START_FLAG_INIT_FROM_SNAPSHOT (1 << 1)
/* Flags defined for counter stop function */
#define SBI_PMU_STOP_FLAG_RESET (1 << 0)
#define SBI_PMU_STOP_FLAG_TAKE_SNAPSHOT (1 << 1)
/* SBI function IDs for DBCN extension */
#define SBI_EXT_DBCN_CONSOLE_WRITE 0x0
@@ -309,8 +312,9 @@ enum sbi_cppc_reg_id {
#define SBI_ERR_ALREADY_AVAILABLE -6
#define SBI_ERR_ALREADY_STARTED -7
#define SBI_ERR_ALREADY_STOPPED -8
#define SBI_ERR_NO_SHMEM -9
#define SBI_LAST_ERR SBI_ERR_ALREADY_STOPPED
#define SBI_LAST_ERR SBI_ERR_NO_SHMEM
/* clang-format on */

View File

@@ -23,6 +23,7 @@
#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_ENO_SHMEM SBI_ERR_NO_SHMEM
#define SBI_ENODEV -1000
#define SBI_ENOSYS -1001
@@ -31,9 +32,8 @@
#define SBI_EILL -1004
#define SBI_ENOSPC -1005
#define SBI_ENOMEM -1006
#define SBI_ETRAP -1007
#define SBI_EUNKNOWN -1008
#define SBI_ENOENT -1009
#define SBI_EUNKNOWN -1007
#define SBI_ENOENT -1008
/* clang-format on */

View File

@@ -11,6 +11,7 @@
#define __SBI_HART_H__
#include <sbi/sbi_types.h>
#include <sbi/sbi_bitops.h>
/** Possible privileged specification versions of a hart */
enum sbi_hart_priv_versions {
@@ -26,29 +27,67 @@ enum sbi_hart_priv_versions {
/** Possible ISA extensions of a hart */
enum sbi_hart_extensions {
/** Hart has Sscofpmt extension */
SBI_HART_EXT_SSCOFPMF = 0,
/** HART has HW time CSR (extension name not available) */
SBI_HART_EXT_TIME,
/** HART has AIA M-mode CSRs */
SBI_HART_EXT_SMAIA,
SBI_HART_EXT_SMAIA = 0,
/** HART has Smepmp */
SBI_HART_EXT_SMEPMP,
/** HART has Smstateen CSR **/
SBI_HART_EXT_SMSTATEEN,
/** Hart has Sscofpmt extension */
SBI_HART_EXT_SSCOFPMF,
/** HART has Sstc extension */
SBI_HART_EXT_SSTC,
/** HART has Zicntr extension (i.e. HW cycle, time & instret CSRs) */
SBI_HART_EXT_ZICNTR,
/** HART has Zihpm extension */
SBI_HART_EXT_ZIHPM,
/** HART has Zkr extension */
SBI_HART_EXT_ZKR,
/** Hart has Smcntrpmf extension */
SBI_HART_EXT_SMCNTRPMF,
/** Hart has Xandespmu extension */
SBI_HART_EXT_XANDESPMU,
/** Hart has Zicboz extension */
SBI_HART_EXT_ZICBOZ,
/** Hart has Zicbom extension */
SBI_HART_EXT_ZICBOM,
/** Hart has Svpbmt extension */
SBI_HART_EXT_SVPBMT,
/** Maximum index of Hart extension */
SBI_HART_EXT_MAX,
};
struct sbi_hart_ext_data {
const unsigned int id;
const char *name;
};
extern const struct sbi_hart_ext_data sbi_hart_ext[];
/*
* Smepmp enforces access boundaries between M-mode and
* S/U-mode. When it is enabled, the PMPs are programmed
* such that M-mode doesn't have access to S/U-mode memory.
*
* To give M-mode R/W access to the shared memory between M and
* S/U-mode, first entry is reserved. It is disabled at boot.
* When shared memory access is required, the physical address
* should be programmed into the first PMP entry with R/W
* permissions to the M-mode. Once the work is done, it should be
* unmapped. sbi_hart_map_saddr/sbi_hart_unmap_saddr function
* pair should be used to map/unmap the shared memory.
*/
#define SBI_SMEPMP_RESV_ENTRY 0
struct sbi_hart_features {
bool detected;
int priv_version;
unsigned long extensions;
unsigned long extensions[BITS_TO_LONGS(SBI_HART_EXT_MAX)];
unsigned int pmp_count;
unsigned int pmp_addr_bits;
unsigned long pmp_gran;
unsigned int mhpm_count;
unsigned int pmp_log2gran;
unsigned int mhpm_mask;
unsigned int mhpm_bits;
};
@@ -63,14 +102,16 @@ static inline ulong sbi_hart_expected_trap_addr(void)
return (ulong)sbi_hart_expected_trap;
}
unsigned int sbi_hart_mhpm_count(struct sbi_scratch *scratch);
unsigned int sbi_hart_mhpm_mask(struct sbi_scratch *scratch);
void sbi_hart_delegation_dump(struct sbi_scratch *scratch,
const char *prefix, const char *suffix);
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_log2gran(struct sbi_scratch *scratch);
unsigned int sbi_hart_pmp_addrbits(struct sbi_scratch *scratch);
unsigned int sbi_hart_mhpm_bits(struct sbi_scratch *scratch);
int sbi_hart_pmp_configure(struct sbi_scratch *scratch);
int sbi_hart_map_saddr(unsigned long base, unsigned long size);
int sbi_hart_unmap_saddr(void);
int sbi_hart_priv_version(struct sbi_scratch *scratch);
void sbi_hart_get_priv_version_str(struct sbi_scratch *scratch,
char *version_str, int nvstr);

View File

@@ -11,6 +11,7 @@
#define __SBI_HARTMASK_H__
#include <sbi/sbi_bitmap.h>
#include <sbi/sbi_scratch.h>
/**
* Maximum number of bits in a hartmask
@@ -32,7 +33,10 @@ struct sbi_hartmask {
/** Initialize hartmask to zero except a particular HART id */
#define SBI_HARTMASK_INIT_EXCEPT(__m, __h) \
bitmap_zero_except(((__m)->bits), (__h), SBI_HARTMASK_MAX_BITS)
do { \
u32 __i = sbi_hartid_to_hartindex(__h); \
bitmap_zero_except(((__m)->bits), __i, SBI_HARTMASK_MAX_BITS); \
} while(0)
/**
* Get underlying bitmap of hartmask
@@ -41,37 +45,68 @@ struct sbi_hartmask {
#define sbi_hartmask_bits(__m) ((__m)->bits)
/**
* Set a HART in hartmask
* Set a HART index in hartmask
* @param i HART index to set
* @param m the hartmask pointer
*/
static inline void sbi_hartmask_set_hartindex(u32 i, struct sbi_hartmask *m)
{
if (i < SBI_HARTMASK_MAX_BITS)
__set_bit(i, m->bits);
}
/**
* Set a HART id in hartmask
* @param h HART id to set
* @param m the hartmask pointer
*/
static inline void sbi_hartmask_set_hart(u32 h, struct sbi_hartmask *m)
static inline void sbi_hartmask_set_hartid(u32 h, struct sbi_hartmask *m)
{
if (h < SBI_HARTMASK_MAX_BITS)
__set_bit(h, m->bits);
sbi_hartmask_set_hartindex(sbi_hartid_to_hartindex(h), m);
}
/**
* Clear a HART in hartmask
* Clear a HART index in hartmask
* @param i HART index to clear
* @param m the hartmask pointer
*/
static inline void sbi_hartmask_clear_hartindex(u32 i, struct sbi_hartmask *m)
{
if (i < SBI_HARTMASK_MAX_BITS)
__clear_bit(i, m->bits);
}
/**
* Clear a HART id in hartmask
* @param h HART id to clear
* @param m the hartmask pointer
*/
static inline void sbi_hartmask_clear_hart(u32 h, struct sbi_hartmask *m)
static inline void sbi_hartmask_clear_hartid(u32 h, struct sbi_hartmask *m)
{
if (h < SBI_HARTMASK_MAX_BITS)
__clear_bit(h, m->bits);
sbi_hartmask_clear_hartindex(sbi_hartid_to_hartindex(h), m);
}
/**
* Test a HART in hartmask
* Test a HART index in hartmask
* @param i HART index to test
* @param m the hartmask pointer
*/
static inline int sbi_hartmask_test_hartindex(u32 i,
const struct sbi_hartmask *m)
{
if (i < SBI_HARTMASK_MAX_BITS)
return __test_bit(i, m->bits);
return 0;
}
/**
* Test a HART id in hartmask
* @param h HART id to test
* @param m the hartmask pointer
*/
static inline int sbi_hartmask_test_hart(u32 h, const struct sbi_hartmask *m)
static inline int sbi_hartmask_test_hartid(u32 h, const struct sbi_hartmask *m)
{
if (h < SBI_HARTMASK_MAX_BITS)
return __test_bit(h, m->bits);
return 0;
return sbi_hartmask_test_hartindex(sbi_hartid_to_hartindex(h), m);
}
/**
@@ -134,8 +169,14 @@ static inline void sbi_hartmask_xor(struct sbi_hartmask *dstp,
sbi_hartmask_bits(src2p), SBI_HARTMASK_MAX_BITS);
}
/** Iterate over each HART in hartmask */
#define sbi_hartmask_for_each_hart(__h, __m) \
for_each_set_bit(__h, (__m)->bits, SBI_HARTMASK_MAX_BITS)
/**
* Iterate over each HART index in hartmask
* __i hart index
* __m hartmask
*/
#define sbi_hartmask_for_each_hartindex(__i, __m) \
for((__i) = find_first_bit((__m)->bits, SBI_HARTMASK_MAX_BITS); \
(__i) < SBI_HARTMASK_MAX_BITS; \
(__i) = find_next_bit((__m)->bits, SBI_HARTMASK_MAX_BITS, (__i) + 1))
#endif

View File

@@ -12,6 +12,9 @@
#include <sbi/sbi_types.h>
/* Alignment of heap base address and size */
#define HEAP_BASE_ALIGN 1024
struct sbi_scratch;
/** Allocate from heap area */

View File

@@ -14,7 +14,7 @@
/* clang-format off */
#define SBI_IPI_EVENT_MAX __riscv_xlen
#define SBI_IPI_EVENT_MAX (8 * __SIZEOF_LONG__)
/* clang-format on */
@@ -23,11 +23,11 @@ struct sbi_ipi_device {
/** Name of the IPI device */
char name[32];
/** Send IPI to a target HART */
void (*ipi_send)(u32 target_hart);
/** Send IPI to a target HART index */
void (*ipi_send)(u32 hart_index);
/** Clear IPI for a target HART */
void (*ipi_clear)(u32 target_hart);
/** Clear IPI for a target HART index */
void (*ipi_clear)(u32 hart_index);
};
enum sbi_ipi_update_type {
@@ -54,7 +54,7 @@ struct sbi_ipi_event_ops {
*/
int (* update)(struct sbi_scratch *scratch,
struct sbi_scratch *remote_scratch,
u32 remote_hartid, void *data);
u32 remote_hartindex, void *data);
/**
* Sync callback to wait for remote HART
@@ -85,9 +85,9 @@ int sbi_ipi_send_halt(ulong hmask, ulong hbase);
void sbi_ipi_process(void);
int sbi_ipi_raw_send(u32 target_hart);
int sbi_ipi_raw_send(u32 hartindex);
void sbi_ipi_raw_clear(u32 target_hart);
void sbi_ipi_raw_clear(u32 hartindex);
const struct sbi_ipi_device *sbi_ipi_get_device(void);

View File

@@ -50,7 +50,7 @@
#include <sbi/sbi_version.h>
struct sbi_domain_memregion;
struct sbi_trap_info;
struct sbi_ecall_return;
struct sbi_trap_regs;
struct sbi_hart_features;
@@ -125,6 +125,9 @@ struct sbi_platform_operations {
/** Get tlb flush limit value **/
u64 (*get_tlbr_flush_limit)(void);
/** Get tlb fifo num entries*/
u32 (*get_tlb_num_entries)(void);
/** Initialize platform timer for current HART */
int (*timer_init)(bool cold_boot);
/** Exit platform timer for current HART */
@@ -134,9 +137,8 @@ struct sbi_platform_operations {
bool (*vendor_ext_check)(void);
/** platform specific SBI extension implementation provider */
int (*vendor_ext_provider)(long funcid,
const struct sbi_trap_regs *regs,
unsigned long *out_value,
struct sbi_trap_info *out_trap);
struct sbi_trap_regs *regs,
struct sbi_ecall_return *out);
};
/** Platform default per-HART stack size for exception/interrupt handling */
@@ -258,16 +260,6 @@ _Static_assert(
#define sbi_platform_has_mfaults_delegation(__p) \
((__p)->features & SBI_PLATFORM_HAS_MFAULTS_DELEGATION)
/**
* Get HART index for the given HART
*
* @param plat pointer to struct sbi_platform
* @param hartid HART ID
*
* @return 0 <= value < hart_count for valid HART otherwise -1U
*/
u32 sbi_platform_hart_index(const struct sbi_platform *plat, u32 hartid);
/**
* Get the platform features in string format
*
@@ -325,6 +317,20 @@ static inline u64 sbi_platform_tlbr_flush_limit(const struct sbi_platform *plat)
return SBI_PLATFORM_TLB_RANGE_FLUSH_LIMIT_DEFAULT;
}
/**
* Get platform specific tlb fifo num entries.
*
* @param plat pointer to struct sbi_platform
*
* @return number of tlb fifo entries
*/
static inline u32 sbi_platform_tlb_fifo_num_entries(const struct sbi_platform *plat)
{
if (plat && sbi_platform_ops(plat)->get_tlb_num_entries)
return sbi_platform_ops(plat)->get_tlb_num_entries();
return sbi_scratch_last_hartindex() + 1;
}
/**
* Get total number of HARTs supported by the platform
*
@@ -353,24 +359,6 @@ static inline u32 sbi_platform_hart_stack_size(const struct sbi_platform *plat)
return 0;
}
/**
* Check whether given HART is invalid
*
* @param plat pointer to struct sbi_platform
* @param hartid HART ID
*
* @return true if HART is invalid and false otherwise
*/
static inline bool sbi_platform_hart_invalid(const struct sbi_platform *plat,
u32 hartid)
{
if (!plat)
return true;
if (plat->hart_count <= sbi_platform_hart_index(plat, hartid))
return true;
return false;
}
/**
* Check whether given HART is allowed to do cold boot
*
@@ -677,16 +665,12 @@ static inline bool sbi_platform_vendor_ext_check(
static inline int sbi_platform_vendor_ext_provider(
const struct sbi_platform *plat,
long funcid,
const struct sbi_trap_regs *regs,
unsigned long *out_value,
struct sbi_trap_info *out_trap)
struct sbi_trap_regs *regs,
struct sbi_ecall_return *out)
{
if (plat && sbi_platform_ops(plat)->vendor_ext_provider) {
if (plat && sbi_platform_ops(plat)->vendor_ext_provider)
return sbi_platform_ops(plat)->vendor_ext_provider(funcid,
regs,
out_value,
out_trap);
}
regs, out);
return SBI_ENOTSUPP;
}

View File

@@ -23,6 +23,7 @@ struct sbi_scratch;
#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
#define SBI_PMU_CY_IR_MASK 0x05
struct sbi_pmu_device {
/** Name of the PMU platform device */
@@ -89,6 +90,12 @@ struct sbi_pmu_device {
* Custom function returning the machine-specific irq-bit.
*/
int (*hw_counter_irq_bit)(void);
/**
* Custom function to inhibit counting of events while in
* specified mode.
*/
void (*hw_counter_filter_mode)(unsigned long flags, int counter_index);
};
/** Get the PMU platform device */

View File

@@ -202,18 +202,51 @@ do { \
= (__type)(__ptr); \
} while (0)
/** HART id to scratch table */
extern struct sbi_scratch *hartid_to_scratch_table[];
/** Last HART index having a sbi_scratch pointer */
extern u32 last_hartindex_having_scratch;
/** Get last HART index having a sbi_scratch pointer */
#define sbi_scratch_last_hartindex() last_hartindex_having_scratch
/** Check whether a particular HART index is valid or not */
#define sbi_hartindex_valid(__hartindex) \
(((__hartindex) <= sbi_scratch_last_hartindex()) ? true : false)
/** HART index to HART id table */
extern u32 hartindex_to_hartid_table[];
/** Get sbi_scratch from HART index */
#define sbi_hartindex_to_hartid(__hartindex) \
({ \
((__hartindex) <= sbi_scratch_last_hartindex()) ?\
hartindex_to_hartid_table[__hartindex] : -1U; \
})
/** HART index to scratch table */
extern struct sbi_scratch *hartindex_to_scratch_table[];
/** Get sbi_scratch from HART index */
#define sbi_hartindex_to_scratch(__hartindex) \
({ \
((__hartindex) <= sbi_scratch_last_hartindex()) ?\
hartindex_to_scratch_table[__hartindex] : NULL;\
})
/**
* Get logical index for given HART id
* @param hartid physical HART id
* @returns value between 0 to SBI_HARTMASK_MAX_BITS upon success and
* SBI_HARTMASK_MAX_BITS upon failure.
*/
u32 sbi_hartid_to_hartindex(u32 hartid);
/** Get sbi_scratch from HART id */
#define sbi_hartid_to_scratch(__hartid) \
hartid_to_scratch_table[__hartid]
sbi_hartindex_to_scratch(sbi_hartid_to_hartindex(__hartid))
/** Last HART id having a sbi_scratch pointer */
extern u32 last_hartid_having_scratch;
/** Get last HART id having a sbi_scratch pointer */
#define sbi_scratch_last_hartid() last_hartid_having_scratch
/** Check whether particular HART id is valid or not */
#define sbi_hartid_valid(__hartid) \
sbi_hartindex_valid(sbi_hartid_to_hartindex(__hartid))
#endif

View File

@@ -20,34 +20,35 @@
/* clang-format on */
#define SBI_TLB_FIFO_NUM_ENTRIES 8
struct sbi_scratch;
enum sbi_tlb_type {
SBI_TLB_FENCE_I = 0,
SBI_TLB_SFENCE_VMA,
SBI_TLB_SFENCE_VMA_ASID,
SBI_TLB_HFENCE_GVMA_VMID,
SBI_TLB_HFENCE_GVMA,
SBI_TLB_HFENCE_VVMA_ASID,
SBI_TLB_HFENCE_VVMA,
SBI_TLB_TYPE_MAX,
};
struct sbi_tlb_info {
unsigned long start;
unsigned long size;
unsigned long asid;
unsigned long vmid;
void (*local_fn)(struct sbi_tlb_info *tinfo);
uint16_t asid;
uint16_t vmid;
enum sbi_tlb_type type;
struct sbi_hartmask smask;
};
void sbi_tlb_local_hfence_vvma(struct sbi_tlb_info *tinfo);
void sbi_tlb_local_hfence_gvma(struct sbi_tlb_info *tinfo);
void sbi_tlb_local_sfence_vma(struct sbi_tlb_info *tinfo);
void sbi_tlb_local_hfence_vvma_asid(struct sbi_tlb_info *tinfo);
void sbi_tlb_local_hfence_gvma_vmid(struct sbi_tlb_info *tinfo);
void sbi_tlb_local_sfence_vma_asid(struct sbi_tlb_info *tinfo);
void sbi_tlb_local_fence_i(struct sbi_tlb_info *tinfo);
#define SBI_TLB_INFO_INIT(__p, __start, __size, __asid, __vmid, __lfn, __src) \
#define SBI_TLB_INFO_INIT(__p, __start, __size, __asid, __vmid, __type, __src) \
do { \
(__p)->start = (__start); \
(__p)->size = (__size); \
(__p)->asid = (__asid); \
(__p)->vmid = (__vmid); \
(__p)->local_fn = (__lfn); \
(__p)->type = (__type); \
SBI_HARTMASK_INIT_EXCEPT(&(__p)->smask, (__src)); \
} while (0)

View File

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

View File

@@ -48,6 +48,9 @@ int fdt_parse_phandle_with_args(void *fdt, int nodeoff,
int fdt_get_node_addr_size(void *fdt, int node, int index,
uint64_t *addr, uint64_t *size);
int fdt_get_node_addr_size_by_name(void *fdt, int node, const char *name,
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);
@@ -56,6 +59,9 @@ int fdt_parse_max_enabled_hart_id(void *fdt, u32 *max_hartid);
int fdt_parse_timebase_frequency(void *fdt, unsigned long *freq);
int fdt_parse_isa_extensions(void *fdt, unsigned int hard_id,
unsigned long *extensions);
int fdt_parse_gaisler_uart_node(void *fdt, int nodeoffset,
struct platform_uart_data *uart);
@@ -93,7 +99,8 @@ 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);
int fdt_parse_aclint_node(void *fdt, int nodeoffset, bool for_timer,
int fdt_parse_aclint_node(void *fdt, int nodeoffset,
bool for_timer, bool allow_regname,
unsigned long *out_addr1, unsigned long *out_size1,
unsigned long *out_addr2, unsigned long *out_size2,
u32 *out_first_hartid, u32 *out_hart_count);

View File

@@ -13,6 +13,23 @@
#include <sbi/sbi_types.h>
struct fdt_pmu_hw_event_select_map {
uint32_t eidx;
uint64_t select;
};
struct fdt_pmu_hw_event_counter_map {
uint32_t eidx_start;
uint32_t eidx_end;
uint32_t ctr_map;
};
struct fdt_pmu_raw_event_counter_map {
uint64_t select;
uint64_t select_mask;
uint32_t ctr_map;
};
#ifdef CONFIG_FDT_PMU
/**
@@ -26,7 +43,7 @@
*
* @param fdt device tree blob
*/
void fdt_pmu_fixup(void *fdt);
int fdt_pmu_fixup(void *fdt);
/**
* Setup PMU data from device tree
@@ -45,6 +62,11 @@ int fdt_pmu_setup(void *fdt);
*/
uint64_t fdt_pmu_get_select_value(uint32_t event_idx);
/** The event index to selector value table instance */
extern struct fdt_pmu_hw_event_select_map fdt_pmu_evt_select[];
/** The number of valid entries in fdt_pmu_evt_select[] */
extern uint32_t hw_event_count;
#else
static inline void fdt_pmu_fixup(void *fdt) { }

View File

@@ -15,9 +15,6 @@
/** 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;

View File

@@ -13,30 +13,23 @@
#ifndef _IPI_ANDES_PLICSW_H_
#define _IPI_ANDES_PLICSW_H_
#define PLICSW_PRIORITY_BASE 0x4
#define PLICSW_PRIORITY_BASE 0x4
#define PLICSW_PENDING_BASE 0x1000
#define PLICSW_PENDING_STRIDE 0x8
#define PLICSW_PENDING_BASE 0x1000
#define PLICSW_ENABLE_BASE 0x2000
#define PLICSW_ENABLE_STRIDE 0x80
#define PLICSW_ENABLE_BASE 0x2000
#define PLICSW_ENABLE_STRIDE 0x80
#define PLICSW_CONTEXT_BASE 0x200000
#define PLICSW_CONTEXT_STRIDE 0x1000
#define PLICSW_CONTEXT_CLAIM 0x4
#define PLICSW_CONTEXT_BASE 0x200000
#define PLICSW_CONTEXT_STRIDE 0x1000
#define PLICSW_CONTEXT_CLAIM 0x4
#define PLICSW_HART_MASK 0x01010101
#define PLICSW_HART_MAX_NR 8
#define PLICSW_REGION_ALIGN 0x1000
#define PLICSW_REGION_ALIGN 0x1000
struct plicsw_data {
unsigned long addr;
unsigned long size;
uint32_t hart_count;
/* hart id to source id table */
uint32_t source_id[PLICSW_HART_MAX_NR];
};
int plicsw_warm_ipi_init(void);

View File

@@ -14,6 +14,7 @@
struct plic_data {
unsigned long addr;
unsigned long size;
unsigned long num_src;
};

View File

@@ -0,0 +1,31 @@
/*
* SPDX-License-Identifier: BSD-2-Clause
*
* Copyright (c) 2023 Ventana Micro Systems Inc.
*
* Authors:
* Anup Patel <apatel@ventanamicro.com>
*/
#ifndef __FDT_REGMAP_H__
#define __FDT_REGMAP_H__
#include <sbi_utils/regmap/regmap.h>
struct fdt_phandle_args;
/** FDT based regmap driver */
struct fdt_regmap {
const struct fdt_match *match_table;
int (*init)(void *fdt, int nodeoff, u32 phandle,
const struct fdt_match *match);
};
/** Get regmap instance based on phandle */
int fdt_regmap_get_by_phandle(void *fdt, u32 phandle,
struct regmap **out_rmap);
/** Get regmap instance based on "regmap' property of the specified DT node */
int fdt_regmap_get(void *fdt, int nodeoff, struct regmap **out_rmap);
#endif

View File

@@ -0,0 +1,67 @@
/*
* SPDX-License-Identifier: BSD-2-Clause
*
* Copyright (c) 2023 Ventana Micro Systems Inc.
*
* Authors:
* Anup Patel <apatel@ventanamicro.com>
*/
#ifndef __REGMAP_H__
#define __REGMAP_H__
#include <sbi/sbi_types.h>
#include <sbi/sbi_list.h>
/** Representation of a regmap instance */
struct regmap {
/** Uniquie ID of the regmap instance assigned by the driver */
unsigned int id;
/** Configuration of regmap registers */
int reg_shift;
int reg_stride;
unsigned int reg_base;
unsigned int reg_max;
/** Read a regmap register */
int (*reg_read)(struct regmap *rmap, unsigned int reg,
unsigned int *val);
/** Write a regmap register */
int (*reg_write)(struct regmap *rmap, unsigned int reg,
unsigned int val);
/** Read-modify-write a regmap register */
int (*reg_update_bits)(struct regmap *rmap, unsigned int reg,
unsigned int mask, unsigned int val);
/** List */
struct sbi_dlist node;
};
static inline struct regmap *to_regmap(struct sbi_dlist *node)
{
return container_of(node, struct regmap, node);
}
/** Find a registered regmap instance */
struct regmap *regmap_find(unsigned int id);
/** Register a regmap instance */
int regmap_add(struct regmap *rmap);
/** Un-register a regmap instance */
void regmap_remove(struct regmap *rmap);
/** Read a register in a regmap instance */
int regmap_read(struct regmap *rmap, unsigned int reg, unsigned int *val);
/** Write a register in a regmap instance */
int regmap_write(struct regmap *rmap, unsigned int reg, unsigned int val);
/** Read-modify-write a register in a regmap instance */
int regmap_update_bits(struct regmap *rmap, unsigned int reg,
unsigned int mask, unsigned int val);
#endif

View File

@@ -1,17 +0,0 @@
/*
* SPDX-License-Identifier: BSD-3-Clause
*
* Copyright (c) 2020 Western Digital Corporation or its affiliates.
*
* Authors:
* Anup Patel <anup.patel@wdc.com>
*/
#ifndef __SYS_SIFIVE_TEST_H__
#define __SYS_SIFIVE_TEST_H__
#include <sbi/sbi_types.h>
int sifive_test_init(unsigned long base);
#endif

View File

@@ -128,6 +128,8 @@ unsigned long csr_read_num(int csr_num)
switchcase_csr_read_8(CSR_MHPMCOUNTER8, ret)
switchcase_csr_read_16(CSR_MHPMCOUNTER16, ret)
switchcase_csr_read(CSR_MCOUNTINHIBIT, ret)
switchcase_csr_read(CSR_MCYCLECFG, ret)
switchcase_csr_read(CSR_MINSTRETCFG, ret)
switchcase_csr_read(CSR_MHPMEVENT3, ret)
switchcase_csr_read_4(CSR_MHPMEVENT4, ret)
switchcase_csr_read_8(CSR_MHPMEVENT8, ret)
@@ -139,6 +141,12 @@ unsigned long csr_read_num(int csr_num)
switchcase_csr_read_4(CSR_MHPMCOUNTER4H, ret)
switchcase_csr_read_8(CSR_MHPMCOUNTER8H, ret)
switchcase_csr_read_16(CSR_MHPMCOUNTER16H, ret)
/**
* The CSR range M[CYCLE, INSTRET]CFGH are available only if smcntrpmf
* extension is present. The caller must ensure that.
*/
switchcase_csr_read(CSR_MCYCLECFGH, ret)
switchcase_csr_read(CSR_MINSTRETCFGH, ret)
/**
* The CSR range MHPMEVENT[3-16]H are available only if sscofpmf
* extension is present. The caller must ensure that.
@@ -206,12 +214,16 @@ void csr_write_num(int csr_num, unsigned long val)
switchcase_csr_write_4(CSR_MHPMCOUNTER4H, val)
switchcase_csr_write_8(CSR_MHPMCOUNTER8H, val)
switchcase_csr_write_16(CSR_MHPMCOUNTER16H, val)
switchcase_csr_write(CSR_MCYCLECFGH, val)
switchcase_csr_write(CSR_MINSTRETCFGH, val)
switchcase_csr_write(CSR_MHPMEVENT3H, val)
switchcase_csr_write_4(CSR_MHPMEVENT4H, val)
switchcase_csr_write_8(CSR_MHPMEVENT8H, val)
switchcase_csr_write_16(CSR_MHPMEVENT16H, val)
#endif
switchcase_csr_write(CSR_MCOUNTINHIBIT, val)
switchcase_csr_write(CSR_MCYCLECFG, val)
switchcase_csr_write(CSR_MINSTRETCFG, val)
switchcase_csr_write(CSR_MHPMEVENT3, val)
switchcase_csr_write_4(CSR_MHPMEVENT4, val)
switchcase_csr_write_8(CSR_MHPMEVENT8, val)
@@ -246,6 +258,48 @@ static unsigned long ctz(unsigned long x)
return ret;
}
int pmp_disable(unsigned int n)
{
int pmpcfg_csr, pmpcfg_shift;
unsigned long cfgmask, pmpcfg;
if (n >= PMP_COUNT)
return SBI_EINVAL;
#if __riscv_xlen == 32
pmpcfg_csr = CSR_PMPCFG0 + (n >> 2);
pmpcfg_shift = (n & 3) << 3;
#elif __riscv_xlen == 64
pmpcfg_csr = (CSR_PMPCFG0 + (n >> 2)) & ~1;
pmpcfg_shift = (n & 7) << 3;
#else
# error "Unexpected __riscv_xlen"
#endif
/* Clear the address matching bits to disable the pmp entry */
cfgmask = ~(0xffUL << pmpcfg_shift);
pmpcfg = (csr_read_num(pmpcfg_csr) & cfgmask);
csr_write_num(pmpcfg_csr, pmpcfg);
return SBI_OK;
}
int is_pmp_entry_mapped(unsigned long entry)
{
unsigned long prot;
unsigned long addr;
unsigned long log2len;
pmp_get(entry, &prot, &addr, &log2len);
/* If address matching bits are non-zero, the entry is enable */
if (prot & PMP_A)
return true;
return false;
}
int pmp_set(unsigned int n, unsigned long prot, unsigned long addr,
unsigned long log2len)
{

View File

@@ -12,6 +12,10 @@
#include <sbi/riscv_atomic.h>
#include <sbi/riscv_barrier.h>
#ifndef __riscv_atomic
#error "opensbi strongly relies on the A extension of RISC-V"
#endif
long atomic_read(atomic_t *atom)
{
long ret = atom->counter;
@@ -79,175 +83,51 @@ long atomic_sub_return(atomic_t *atom, long value)
(__typeof__(*(ptr))) __axchg((ptr), _x_, sizeof(*(ptr))); \
})
#define __xchg(ptr, new, size) \
({ \
__typeof__(ptr) __ptr = (ptr); \
__typeof__(*(ptr)) __new = (new); \
__typeof__(*(ptr)) __ret; \
register unsigned int __rc; \
switch (size) { \
case 4: \
__asm__ __volatile__("0: lr.w %0, %2\n" \
" sc.w.rl %1, %z3, %2\n" \
" bnez %1, 0b\n" \
" fence rw, rw\n" \
: "=&r"(__ret), "=&r"(__rc), \
"+A"(*__ptr) \
: "rJ"(__new) \
: "memory"); \
break; \
case 8: \
__asm__ __volatile__("0: lr.d %0, %2\n" \
" sc.d.rl %1, %z3, %2\n" \
" bnez %1, 0b\n" \
" fence rw, rw\n" \
: "=&r"(__ret), "=&r"(__rc), \
"+A"(*__ptr) \
: "rJ"(__new) \
: "memory"); \
break; \
default: \
break; \
} \
__ret; \
})
#define xchg(ptr, n) \
({ \
__typeof__(*(ptr)) _n_ = (n); \
(__typeof__(*(ptr))) __xchg((ptr), _n_, sizeof(*(ptr))); \
})
#define __cmpxchg(ptr, old, new, size) \
({ \
__typeof__(ptr) __ptr = (ptr); \
__typeof__(*(ptr)) __old = (old); \
__typeof__(*(ptr)) __new = (new); \
__typeof__(*(ptr)) __ret; \
register unsigned int __rc; \
switch (size) { \
case 4: \
__asm__ __volatile__("0: lr.w %0, %2\n" \
" bne %0, %z3, 1f\n" \
" sc.w.rl %1, %z4, %2\n" \
" bnez %1, 0b\n" \
" fence rw, rw\n" \
"1:\n" \
: "=&r"(__ret), "=&r"(__rc), \
"+A"(*__ptr) \
: "rJ"(__old), "rJ"(__new) \
: "memory"); \
break; \
case 8: \
__asm__ __volatile__("0: lr.d %0, %2\n" \
" bne %0, %z3, 1f\n" \
" sc.d.rl %1, %z4, %2\n" \
" bnez %1, 0b\n" \
" fence rw, rw\n" \
"1:\n" \
: "=&r"(__ret), "=&r"(__rc), \
"+A"(*__ptr) \
: "rJ"(__old), "rJ"(__new) \
: "memory"); \
break; \
default: \
break; \
} \
__ret; \
})
#define cmpxchg(ptr, o, n) \
({ \
__typeof__(*(ptr)) _o_ = (o); \
__typeof__(*(ptr)) _n_ = (n); \
(__typeof__(*(ptr))) \
__cmpxchg((ptr), _o_, _n_, sizeof(*(ptr))); \
})
long atomic_cmpxchg(atomic_t *atom, long oldval, long newval)
{
#ifdef __riscv_atomic
return __sync_val_compare_and_swap(&atom->counter, oldval, newval);
#else
return cmpxchg(&atom->counter, oldval, newval);
#endif
}
long atomic_xchg(atomic_t *atom, long newval)
{
/* Atomically set new value and return old value. */
#ifdef __riscv_atomic
return axchg(&atom->counter, newval);
#else
return xchg(&atom->counter, newval);
#endif
}
unsigned int atomic_raw_xchg_uint(volatile unsigned int *ptr,
unsigned int newval)
{
/* Atomically set new value and return old value. */
#ifdef __riscv_atomic
return axchg(ptr, newval);
#else
return xchg(ptr, newval);
#endif
}
unsigned long atomic_raw_xchg_ulong(volatile unsigned long *ptr,
unsigned long newval)
{
/* Atomically set new value and return old value. */
#ifdef __riscv_atomic
return axchg(ptr, newval);
#else
return xchg(ptr, newval);
#endif
}
#if (__SIZEOF_POINTER__ == 8)
#define __AMO(op) "amo" #op ".d"
#elif (__SIZEOF_POINTER__ == 4)
#define __AMO(op) "amo" #op ".w"
#else
#error "Unexpected __SIZEOF_POINTER__"
#endif
#define __atomic_op_bit_ord(op, mod, nr, addr, ord) \
({ \
unsigned long __res, __mask; \
__mask = BIT_MASK(nr); \
__asm__ __volatile__(__AMO(op) #ord " %0, %2, %1" \
: "=r"(__res), "+A"(addr[BIT_WORD(nr)]) \
: "r"(mod(__mask)) \
: "memory"); \
__res; \
})
#define __atomic_op_bit(op, mod, nr, addr) \
__atomic_op_bit_ord(op, mod, nr, addr, .aqrl)
/* Bitmask modifiers */
#define __NOP(x) (x)
#define __NOT(x) (~(x))
inline int atomic_raw_set_bit(int nr, volatile unsigned long *addr)
int atomic_raw_set_bit(int nr, volatile unsigned long *addr)
{
return __atomic_op_bit(or, __NOP, nr, addr);
unsigned long res, mask = BIT_MASK(nr);
res = __atomic_fetch_or(&addr[BIT_WORD(nr)], mask, __ATOMIC_RELAXED);
return res & mask ? 1 : 0;
}
inline int atomic_raw_clear_bit(int nr, volatile unsigned long *addr)
int atomic_raw_clear_bit(int nr, volatile unsigned long *addr)
{
return __atomic_op_bit(and, __NOT, nr, addr);
unsigned long res, mask = BIT_MASK(nr);
res = __atomic_fetch_and(&addr[BIT_WORD(nr)], ~mask, __ATOMIC_RELAXED);
return res & mask ? 1 : 0;
}
inline int atomic_set_bit(int nr, atomic_t *atom)
int atomic_set_bit(int nr, atomic_t *atom)
{
return atomic_raw_set_bit(nr, (unsigned long *)&atom->counter);
}
inline int atomic_clear_bit(int nr, atomic_t *atom)
int atomic_clear_bit(int nr, atomic_t *atom)
{
return atomic_raw_clear_bit(nr, (unsigned long *)&atom->counter);
}

View File

@@ -37,28 +37,22 @@ int sbi_getc(void)
return -1;
}
void sbi_putc(char ch)
{
if (console_dev && console_dev->console_putc) {
if (ch == '\n')
console_dev->console_putc('\r');
console_dev->console_putc(ch);
}
}
static unsigned long nputs(const char *str, unsigned long len)
{
unsigned long i, ret;
unsigned long i;
if (console_dev && console_dev->console_puts) {
ret = console_dev->console_puts(str, len);
} else {
for (i = 0; i < len; i++)
sbi_putc(str[i]);
ret = len;
if (console_dev) {
if (console_dev->console_puts)
return console_dev->console_puts(str, len);
else if (console_dev->console_putc) {
for (i = 0; i < len; i++) {
if (str[i] == '\n')
console_dev->console_putc('\r');
console_dev->console_putc(str[i]);
}
}
}
return ret;
return len;
}
static void nputs_all(const char *str, unsigned long len)
@@ -69,6 +63,11 @@ static void nputs_all(const char *str, unsigned long len)
p += nputs(&str[p], len - p);
}
void sbi_putc(char ch)
{
nputs_all(&ch, 1);
}
void sbi_puts(const char *str)
{
unsigned long len = sbi_strlen(str);
@@ -120,6 +119,8 @@ unsigned long sbi_ngets(char *str, unsigned long len)
#define PAD_RIGHT 1
#define PAD_ZERO 2
#define PAD_ALTERNATE 4
#define PAD_SIGN 8
#define USE_TBUF 16
#define PRINT_BUF_LEN 64
#define va_start(v, l) __builtin_va_start((v), l)
@@ -127,7 +128,7 @@ unsigned long sbi_ngets(char *str, unsigned long len)
#define va_arg __builtin_va_arg
typedef __builtin_va_list va_list;
static void printc(char **out, u32 *out_len, char ch)
static void printc(char **out, u32 *out_len, char ch, int flags)
{
if (!out) {
sbi_putc(ch);
@@ -141,60 +142,66 @@ static void printc(char **out, u32 *out_len, char ch)
if (!out_len || *out_len > 1) {
*(*out)++ = ch;
**out = '\0';
if (out_len) {
--(*out_len);
if ((flags & USE_TBUF) && *out_len == 1) {
nputs_all(console_tbuf, CONSOLE_TBUF_MAX - *out_len);
*out = console_tbuf;
*out_len = CONSOLE_TBUF_MAX;
}
}
}
if (out_len && *out_len > 0)
--(*out_len);
}
static int prints(char **out, u32 *out_len, const char *string, int width,
int flags)
{
int pc = 0;
char padchar = ' ';
if (width > 0) {
int len = 0;
const char *ptr;
for (ptr = string; *ptr; ++ptr)
++len;
if (len >= width)
width = 0;
else
width -= len;
if (flags & PAD_ZERO)
padchar = '0';
}
int pc = 0;
width -= sbi_strlen(string);
if (!(flags & PAD_RIGHT)) {
for (; width > 0; --width) {
printc(out, out_len, padchar);
printc(out, out_len, flags & PAD_ZERO ? '0' : ' ', flags);
++pc;
}
}
for (; *string; ++string) {
printc(out, out_len, *string);
printc(out, out_len, *string, flags);
++pc;
}
for (; width > 0; --width) {
printc(out, out_len, padchar);
printc(out, out_len, ' ', flags);
++pc;
}
return pc;
}
static int printi(char **out, u32 *out_len, long long i, int b, int sg,
int width, int flags, int letbase)
static int printi(char **out, u32 *out_len, long long i,
int width, int flags, int type)
{
char print_buf[PRINT_BUF_LEN];
char *s;
int neg = 0, pc = 0;
u64 t;
unsigned long long u = i;
int pc = 0;
char *s, sign = 0, letbase, print_buf[PRINT_BUF_LEN];
unsigned long long u, b, t;
if (sg && b == 10 && i < 0) {
neg = 1;
u = -i;
b = 10;
letbase = 'a';
if (type == 'o')
b = 8;
else if (type == 'x' || type == 'X' || type == 'p' || type == 'P') {
b = 16;
letbase &= ~0x20;
letbase |= type & 0x20;
}
u = i;
sign = 0;
if (type == 'i' || type == 'd') {
if ((flags & PAD_SIGN) && i > 0)
sign = '+';
if (i < 0) {
sign = '-';
u = -i;
}
}
s = print_buf + PRINT_BUF_LEN - 1;
@@ -212,23 +219,33 @@ static int printi(char **out, u32 *out_len, long long i, int b, int sg,
}
}
if (flags & PAD_ALTERNATE) {
if ((b == 16) && (letbase == 'A')) {
*--s = 'X';
} else if ((b == 16) && (letbase == 'a')) {
*--s = 'x';
}
*--s = '0';
}
if (neg) {
if (width && (flags & PAD_ZERO)) {
printc(out, out_len, '-');
if (flags & PAD_ZERO) {
if (sign) {
printc(out, out_len, sign, flags);
++pc;
--width;
} else {
*--s = '-';
}
if (i && (flags & PAD_ALTERNATE)) {
if (b == 16 || b == 8) {
printc(out, out_len, '0', flags);
++pc;
--width;
}
if (b == 16) {
printc(out, out_len, 'x' - 'a' + letbase, flags);
++pc;
--width;
}
}
} else {
if (i && (flags & PAD_ALTERNATE)) {
if (b == 16)
*--s = 'x' - 'a' + letbase;
if (b == 16 || b == 8)
*--s = '0';
}
if (sign)
*--s = sign;
}
return pc + prints(out, out_len, s, width, flags);
@@ -236,10 +253,10 @@ static int printi(char **out, u32 *out_len, long long i, int b, int sg,
static int print(char **out, u32 *out_len, const char *format, va_list args)
{
bool flags_done;
int width, flags, pc = 0;
char scr[2], *tout;
char type, scr[2], *tout;
bool use_tbuf = (!out) ? true : false;
unsigned long long tmp;
/*
* The console_tbuf is protected by console_out_lock and
@@ -253,33 +270,51 @@ static int print(char **out, u32 *out_len, const char *format, va_list args)
out_len = &console_tbuf_len;
}
for (; *format != 0; ++format) {
if (use_tbuf && !console_tbuf_len) {
nputs_all(console_tbuf, CONSOLE_TBUF_MAX);
console_tbuf_len = CONSOLE_TBUF_MAX;
tout = console_tbuf;
}
/* handle special case: *out_len == 1*/
if (out) {
if(!out_len || *out_len)
**out = '\0';
}
for (; *format != 0; ++format) {
width = flags = 0;
if (use_tbuf)
flags |= USE_TBUF;
if (*format == '%') {
++format;
width = flags = 0;
if (*format == '\0')
break;
if (*format == '%')
goto literal;
/* Get flags */
if (*format == '-') {
++format;
flags = PAD_RIGHT;
}
if (*format == '#') {
++format;
flags |= PAD_ALTERNATE;
}
while (*format == '0') {
++format;
flags |= PAD_ZERO;
flags_done = false;
while (!flags_done) {
switch (*format) {
case '-':
flags |= PAD_RIGHT;
break;
case '+':
flags |= PAD_SIGN;
break;
case '#':
flags |= PAD_ALTERNATE;
break;
case '0':
flags |= PAD_ZERO;
break;
case ' ':
case '\'':
/* Ignored flags, do nothing */
break;
default:
flags_done = true;
break;
}
if (!flags_done)
++format;
}
if (flags & PAD_RIGHT)
flags &= ~PAD_ZERO;
/* Get width */
for (; *format >= '0' && *format <= '9'; ++format) {
width *= 10;
@@ -293,83 +328,47 @@ static int print(char **out, u32 *out_len, const char *format, va_list args)
}
if ((*format == 'd') || (*format == 'i')) {
pc += printi(out, out_len, va_arg(args, int),
10, 1, width, flags, '0');
width, flags, *format);
continue;
}
if (*format == 'x') {
pc += printi(out, out_len,
va_arg(args, unsigned int), 16, 0,
width, flags, 'a');
if ((*format == 'u') || (*format == 'o')
|| (*format == 'x') || (*format == 'X')) {
pc += printi(out, out_len, va_arg(args, unsigned int),
width, flags, *format);
continue;
}
if (*format == 'X') {
pc += printi(out, out_len,
va_arg(args, unsigned int), 16, 0,
width, flags, 'A');
if ((*format == 'p') || (*format == 'P')) {
pc += printi(out, out_len, (uintptr_t)va_arg(args, void*),
width, flags, *format);
continue;
}
if (*format == 'u') {
pc += printi(out, out_len,
va_arg(args, unsigned int), 10, 0,
width, flags, 'a');
continue;
}
if (*format == 'p') {
pc += printi(out, out_len,
va_arg(args, unsigned long), 16, 0,
width, flags, 'a');
continue;
}
if (*format == 'P') {
pc += printi(out, out_len,
va_arg(args, unsigned long), 16, 0,
width, flags, 'A');
continue;
}
if (*format == 'l' && *(format + 1) == 'l') {
tmp = va_arg(args, unsigned long long);
if (*(format + 2) == 'u') {
format += 2;
pc += printi(out, out_len, tmp, 10, 0,
width, flags, 'a');
} else if (*(format + 2) == 'x') {
format += 2;
pc += printi(out, out_len, tmp, 16, 0,
width, flags, 'a');
} else if (*(format + 2) == 'X') {
format += 2;
pc += printi(out, out_len, tmp, 16, 0,
width, flags, 'A');
} else {
format += 1;
pc += printi(out, out_len, tmp, 10, 1,
width, flags, '0');
if (*format == 'l') {
type = 'i';
if (format[1] == 'l') {
++format;
if ((format[1] == 'u') || (format[1] == 'o')
|| (format[1] == 'd') || (format[1] == 'i')
|| (format[1] == 'x') || (format[1] == 'X')) {
++format;
type = *format;
}
pc += printi(out, out_len, va_arg(args, long long),
width, flags, type);
continue;
}
continue;
} else if (*format == 'l') {
if (*(format + 1) == 'u') {
format += 1;
pc += printi(
out, out_len,
va_arg(args, unsigned long), 10,
0, width, flags, 'a');
} else if (*(format + 1) == 'x') {
format += 1;
pc += printi(
out, out_len,
va_arg(args, unsigned long), 16,
0, width, flags, 'a');
} else if (*(format + 1) == 'X') {
format += 1;
pc += printi(
out, out_len,
va_arg(args, unsigned long), 16,
0, width, flags, 'A');
} else {
pc += printi(out, out_len,
va_arg(args, long), 10, 1,
width, flags, '0');
if ((format[1] == 'u') || (format[1] == 'o')
|| (format[1] == 'd') || (format[1] == 'i')
|| (format[1] == 'x') || (format[1] == 'X')) {
++format;
type = *format;
}
if ((type == 'd') || (type == 'i'))
pc += printi(out, out_len, va_arg(args, long),
width, flags, type);
else
pc += printi(out, out_len, va_arg(args, unsigned long),
width, flags, type);
continue;
}
if (*format == 'c') {
/* char are converted to int then pushed on the stack */
@@ -380,7 +379,7 @@ static int print(char **out, u32 *out_len, const char *format, va_list args)
}
} else {
literal:
printc(out, out_len, *format);
printc(out, out_len, *format, flags);
++pc;
}
}

View File

@@ -40,22 +40,22 @@ struct sbi_domain root = {
static unsigned long domain_hart_ptr_offset;
struct sbi_domain *sbi_hartid_to_domain(u32 hartid)
struct sbi_domain *sbi_hartindex_to_domain(u32 hartindex)
{
struct sbi_scratch *scratch;
scratch = sbi_hartid_to_scratch(hartid);
scratch = sbi_hartindex_to_scratch(hartindex);
if (!scratch || !domain_hart_ptr_offset)
return NULL;
return sbi_scratch_read_type(scratch, void *, domain_hart_ptr_offset);
}
static void update_hartid_to_domain(u32 hartid, struct sbi_domain *dom)
static void update_hartindex_to_domain(u32 hartindex, struct sbi_domain *dom)
{
struct sbi_scratch *scratch;
scratch = sbi_hartid_to_scratch(hartid);
scratch = sbi_hartindex_to_scratch(hartindex);
if (!scratch)
return;
@@ -65,7 +65,7 @@ static void update_hartid_to_domain(u32 hartid, struct sbi_domain *dom)
bool sbi_domain_is_assigned_hart(const struct sbi_domain *dom, u32 hartid)
{
if (dom)
return sbi_hartmask_test_hart(hartid, &dom->assigned_harts);
return sbi_hartmask_test_hartid(hartid, &dom->assigned_harts);
return false;
}
@@ -73,18 +73,10 @@ 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)
{
ulong ret, bword, boff;
if (!dom)
return 0;
bword = BIT_WORD(hbase);
boff = BIT_WORD_OFFSET(hbase);
ret = sbi_hartmask_bits(&dom->assigned_harts)[bword++] >> boff;
if (boff && bword < BIT_WORD(SBI_HARTMASK_MAX_BITS)) {
ret |= (sbi_hartmask_bits(&dom->assigned_harts)[bword] &
(BIT(boff) - 1UL)) << (BITS_PER_LONG - boff);
ulong ret = 0;
for (int i = 0; i < 8 * sizeof(ret); i++) {
if (sbi_domain_is_assigned_hart(dom, hbase + i))
ret |= 1UL << i;
}
return ret;
@@ -201,12 +193,11 @@ static bool is_region_subset(const struct sbi_domain_memregion *regA,
return false;
}
/** Check if regionA conflicts regionB */
static bool is_region_conflict(const struct sbi_domain_memregion *regA,
const struct sbi_domain_memregion *regB)
/** Check if regionA can be replaced by regionB */
static bool is_region_compatible(const struct sbi_domain_memregion *regA,
const struct sbi_domain_memregion *regB)
{
if ((is_region_subset(regA, regB) || is_region_subset(regB, regA)) &&
regA->flags == regB->flags)
if (is_region_subset(regA, regB) && regA->flags == regB->flags)
return true;
return false;
@@ -264,11 +255,26 @@ static const struct sbi_domain_memregion *find_next_subset_region(
return ret;
}
static int sanitize_domain(const struct sbi_platform *plat,
struct sbi_domain *dom)
static void swap_region(struct sbi_domain_memregion* reg1,
struct sbi_domain_memregion* reg2)
{
struct sbi_domain_memregion treg;
sbi_memcpy(&treg, reg1, sizeof(treg));
sbi_memcpy(reg1, reg2, sizeof(treg));
sbi_memcpy(reg2, &treg, sizeof(treg));
}
static void clear_region(struct sbi_domain_memregion* reg)
{
sbi_memset(reg, 0x0, sizeof(*reg));
}
static int sanitize_domain(struct sbi_domain *dom)
{
u32 i, j, count;
struct sbi_domain_memregion treg, *reg, *reg1;
bool is_covered;
struct sbi_domain_memregion *reg, *reg1;
/* Check possible HARTs */
if (!dom->possible_harts) {
@@ -276,10 +282,11 @@ static int sanitize_domain(const struct sbi_platform *plat,
__func__, dom->name);
return SBI_EINVAL;
}
sbi_hartmask_for_each_hart(i, dom->possible_harts) {
if (sbi_platform_hart_invalid(plat, i)) {
sbi_hartmask_for_each_hartindex(i, dom->possible_harts) {
if (!sbi_hartindex_valid(i)) {
sbi_printf("%s: %s possible HART mask has invalid "
"hart %d\n", __func__, dom->name, i);
"hart %d\n", __func__,
dom->name, sbi_hartindex_to_hartid(i));
return SBI_EINVAL;
}
}
@@ -318,25 +325,38 @@ static int sanitize_domain(const struct sbi_platform *plat,
for (j = i + 1; j < count; j++) {
reg1 = &dom->regions[j];
if (is_region_conflict(reg1, reg)) {
sbi_printf("%s: %s conflict between regions "
"(base=0x%lx order=%lu flags=0x%lx) and "
"(base=0x%lx order=%lu flags=0x%lx)\n",
__func__, dom->name,
reg->base, reg->order, reg->flags,
reg1->base, reg1->order, reg1->flags);
return SBI_EINVAL;
}
if (!is_region_before(reg1, reg))
continue;
sbi_memcpy(&treg, reg1, sizeof(treg));
sbi_memcpy(reg1, reg, sizeof(treg));
sbi_memcpy(reg, &treg, sizeof(treg));
swap_region(reg, reg1);
}
}
/* Remove covered regions */
while(i < (count - 1)) {
is_covered = false;
reg = &dom->regions[i];
for (j = i + 1; j < count; j++) {
reg1 = &dom->regions[j];
if (is_region_compatible(reg, reg1)) {
is_covered = true;
break;
}
}
/* find a region is superset of reg, remove reg */
if (is_covered) {
for (j = i; j < (count - 1); j++)
swap_region(&dom->regions[j],
&dom->regions[j + 1]);
clear_region(&dom->regions[count - 1]);
count--;
} else
i++;
}
/*
* We don't need to check boot HART id of domain because if boot
* HART id is not possible/assigned to this domain then it won't
@@ -400,7 +420,7 @@ bool sbi_domain_check_addr_range(const struct sbi_domain *dom,
void sbi_domain_dump(const struct sbi_domain *dom, const char *suffix)
{
u32 i, k;
u32 i, j, k;
unsigned long rstart, rend;
struct sbi_domain_memregion *reg;
@@ -412,9 +432,11 @@ void sbi_domain_dump(const struct sbi_domain *dom, const char *suffix)
k = 0;
sbi_printf("Domain%d HARTs %s: ", dom->index, suffix);
sbi_hartmask_for_each_hart(i, dom->possible_harts)
sbi_hartmask_for_each_hartindex(i, dom->possible_harts) {
j = sbi_hartindex_to_hartid(i);
sbi_printf("%s%d%s", (k++) ? "," : "",
i, sbi_domain_is_assigned_hart(dom, i) ? "*" : "");
j, sbi_domain_is_assigned_hart(dom, j) ? "*" : "");
}
sbi_printf("\n");
i = 0;
@@ -499,7 +521,6 @@ int sbi_domain_register(struct sbi_domain *dom,
int rc;
struct sbi_domain *tdom;
u32 cold_hartid = current_hartid();
const struct sbi_platform *plat = sbi_platform_thishart_ptr();
/* Sanity checks */
if (!dom || !assign_mask || domain_finalized)
@@ -522,7 +543,7 @@ int sbi_domain_register(struct sbi_domain *dom,
}
/* Sanitize discovered domain */
rc = sanitize_domain(plat, dom);
rc = sanitize_domain(dom);
if (rc) {
sbi_printf("%s: sanity checks failed for"
" %s (error %d)\n", __func__,
@@ -538,22 +559,22 @@ int sbi_domain_register(struct sbi_domain *dom,
sbi_hartmask_clear_all(&dom->assigned_harts);
/* Assign domain to HART if HART is a possible HART */
sbi_hartmask_for_each_hart(i, assign_mask) {
if (!sbi_hartmask_test_hart(i, dom->possible_harts))
sbi_hartmask_for_each_hartindex(i, assign_mask) {
if (!sbi_hartmask_test_hartindex(i, dom->possible_harts))
continue;
tdom = sbi_hartid_to_domain(i);
tdom = sbi_hartindex_to_domain(i);
if (tdom)
sbi_hartmask_clear_hart(i,
sbi_hartmask_clear_hartindex(i,
&tdom->assigned_harts);
update_hartid_to_domain(i, dom);
sbi_hartmask_set_hart(i, &dom->assigned_harts);
update_hartindex_to_domain(i, dom);
sbi_hartmask_set_hartindex(i, &dom->assigned_harts);
/*
* If cold boot HART is assigned to this domain then
* override boot HART of this domain.
*/
if (i == cold_hartid &&
if (sbi_hartindex_to_hartid(i) == cold_hartid &&
dom->boot_hartid != cold_hartid) {
sbi_printf("Domain%d Boot HARTID forced to"
" %d\n", dom->index, cold_hartid);
@@ -569,21 +590,16 @@ 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_REGION_MAX <= root_memregs_count))
return SBI_EINVAL;
/* Check for conflicts */
/* Check whether compatible region exists for the new one */
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;
}
if (is_region_compatible(reg, nreg))
return 0;
}
/* Append the memregion to root memregions */
@@ -595,7 +611,7 @@ int sbi_domain_root_add_memregion(const struct sbi_domain_memregion *reg)
/* Sort and optimize root regions */
do {
/* Sanitize the root domain so that memregions are sorted */
rc = sanitize_domain(plat, &root);
rc = sanitize_domain(&root);
if (rc) {
sbi_printf("%s: sanity checks failed for"
" %s (error %d)\n", __func__,
@@ -673,36 +689,37 @@ int sbi_domain_finalize(struct sbi_scratch *scratch, u32 cold_hartid)
/* Startup boot HART of domains */
sbi_domain_for_each(i, dom) {
/* Domain boot HART */
dhart = dom->boot_hartid;
/* Domain boot HART index */
dhart = sbi_hartid_to_hartindex(dom->boot_hartid);
/* Ignore of boot HART is off limits */
if (SBI_HARTMASK_MAX_BITS <= dhart)
if (!sbi_hartindex_valid(dhart))
continue;
/* Ignore if boot HART not possible for this domain */
if (!sbi_hartmask_test_hart(dhart, dom->possible_harts))
if (!sbi_hartmask_test_hartindex(dhart, dom->possible_harts))
continue;
/* Ignore if boot HART assigned different domain */
if (sbi_hartid_to_domain(dhart) != dom ||
!sbi_hartmask_test_hart(dhart, &dom->assigned_harts))
if (sbi_hartindex_to_domain(dhart) != dom ||
!sbi_hartmask_test_hartindex(dhart, &dom->assigned_harts))
continue;
/* Startup boot HART of domain */
if (dhart == cold_hartid) {
if (dom->boot_hartid == cold_hartid) {
scratch->next_addr = dom->next_addr;
scratch->next_mode = dom->next_mode;
scratch->next_arg1 = dom->next_arg1;
} else {
rc = sbi_hsm_hart_start(scratch, NULL, dhart,
rc = sbi_hsm_hart_start(scratch, NULL,
dom->boot_hartid,
dom->next_addr,
dom->next_mode,
dom->next_arg1);
if (rc) {
sbi_printf("%s: failed to start boot HART %d"
" for %s (error %d)\n", __func__,
dhart, dom->name, rc);
dom->boot_hartid, dom->name, rc);
return rc;
}
}
@@ -772,11 +789,17 @@ int sbi_domain_init(struct sbi_scratch *scratch, u32 cold_hartid)
root.fw_region_inited = true;
/* Root domain allow everything memory region */
/*
* Allow SU RWX on rest of the memory region. Since pmp entries
* have implicit priority on index, previous entries will
* deny access to SU on M-mode region. Also, M-mode will not
* have access to SU region while previous entries will allow
* access to M-mode regions.
*/
sbi_domain_memregion_init(0, ~0UL,
(SBI_DOMAIN_MEMREGION_READABLE |
SBI_DOMAIN_MEMREGION_WRITEABLE |
SBI_DOMAIN_MEMREGION_EXECUTABLE),
(SBI_DOMAIN_MEMREGION_SU_READABLE |
SBI_DOMAIN_MEMREGION_SU_WRITABLE |
SBI_DOMAIN_MEMREGION_SU_EXECUTABLE),
&root_memregs[root_memregs_count++]);
/* Root domain memory region end */
@@ -791,11 +814,8 @@ int sbi_domain_init(struct sbi_scratch *scratch, u32 cold_hartid)
root.next_mode = scratch->next_mode;
/* Root domain possible and assigned HARTs */
for (i = 0; i < SBI_HARTMASK_MAX_BITS; i++) {
if (sbi_platform_hart_invalid(plat, i))
continue;
sbi_hartmask_set_hart(i, root_hmask);
}
for (i = 0; i < plat->hart_count; i++)
sbi_hartmask_set_hartindex(i, root_hmask);
/* Finally register the root domain */
rc = sbi_domain_register(&root, root_hmask);

View File

@@ -101,14 +101,12 @@ int sbi_ecall_handler(struct sbi_trap_regs *regs)
struct sbi_ecall_extension *ext;
unsigned long extension_id = regs->a7;
unsigned long func_id = regs->a6;
struct sbi_trap_info trap = {0};
unsigned long out_val = 0;
struct sbi_ecall_return out = {0};
bool is_0_1_spec = 0;
ext = sbi_ecall_find_extension(extension_id);
if (ext && ext->handle) {
ret = ext->handle(extension_id, func_id,
regs, &out_val, &trap);
ret = ext->handle(extension_id, func_id, regs, &out);
if (extension_id >= SBI_EXT_0_1_SET_TIMER &&
extension_id <= SBI_EXT_0_1_SHUTDOWN)
is_0_1_spec = 1;
@@ -116,10 +114,7 @@ int sbi_ecall_handler(struct sbi_trap_regs *regs)
ret = SBI_ENOTSUPP;
}
if (ret == SBI_ETRAP) {
trap.epc = regs->mepc;
sbi_trap_redirect(regs, &trap);
} else {
if (!out.skip_regs_update) {
if (ret < SBI_LAST_ERR ||
(extension_id != SBI_EXT_0_1_CONSOLE_GETCHAR &&
SBI_SUCCESS < ret)) {
@@ -140,7 +135,7 @@ int sbi_ecall_handler(struct sbi_trap_regs *regs)
regs->mepc += 4;
regs->a0 = ret;
if (!is_0_1_spec)
regs->a1 = out_val;
regs->a1 = out.value;
}
return 0;

View File

@@ -33,37 +33,36 @@ static int sbi_ecall_base_probe(unsigned long extid, unsigned long *out_val)
}
static int sbi_ecall_base_handler(unsigned long extid, unsigned long funcid,
const struct sbi_trap_regs *regs,
unsigned long *out_val,
struct sbi_trap_info *out_trap)
struct sbi_trap_regs *regs,
struct sbi_ecall_return *out)
{
int ret = 0;
switch (funcid) {
case SBI_EXT_BASE_GET_SPEC_VERSION:
*out_val = (SBI_ECALL_VERSION_MAJOR <<
SBI_SPEC_VERSION_MAJOR_OFFSET) &
(SBI_SPEC_VERSION_MAJOR_MASK <<
SBI_SPEC_VERSION_MAJOR_OFFSET);
*out_val = *out_val | SBI_ECALL_VERSION_MINOR;
out->value = (SBI_ECALL_VERSION_MAJOR <<
SBI_SPEC_VERSION_MAJOR_OFFSET) &
(SBI_SPEC_VERSION_MAJOR_MASK <<
SBI_SPEC_VERSION_MAJOR_OFFSET);
out->value = out->value | SBI_ECALL_VERSION_MINOR;
break;
case SBI_EXT_BASE_GET_IMP_ID:
*out_val = sbi_ecall_get_impid();
out->value = sbi_ecall_get_impid();
break;
case SBI_EXT_BASE_GET_IMP_VERSION:
*out_val = OPENSBI_VERSION;
out->value = OPENSBI_VERSION;
break;
case SBI_EXT_BASE_GET_MVENDORID:
*out_val = csr_read(CSR_MVENDORID);
out->value = csr_read(CSR_MVENDORID);
break;
case SBI_EXT_BASE_GET_MARCHID:
*out_val = csr_read(CSR_MARCHID);
out->value = csr_read(CSR_MARCHID);
break;
case SBI_EXT_BASE_GET_MIMPID:
*out_val = csr_read(CSR_MIMPID);
out->value = csr_read(CSR_MIMPID);
break;
case SBI_EXT_BASE_PROBE_EXT:
ret = sbi_ecall_base_probe(regs->a0, out_val);
ret = sbi_ecall_base_probe(regs->a0, &out->value);
break;
default:
ret = SBI_ENOTSUPP;

View File

@@ -12,9 +12,8 @@
#include <sbi/sbi_cppc.h>
static int sbi_ecall_cppc_handler(unsigned long extid, unsigned long funcid,
const struct sbi_trap_regs *regs,
unsigned long *out_val,
struct sbi_trap_info *out_trap)
struct sbi_trap_regs *regs,
struct sbi_ecall_return *out)
{
int ret = 0;
uint64_t temp;
@@ -22,14 +21,14 @@ static int sbi_ecall_cppc_handler(unsigned long extid, unsigned long funcid,
switch (funcid) {
case SBI_EXT_CPPC_READ:
ret = sbi_cppc_read(regs->a0, &temp);
*out_val = temp;
out->value = temp;
break;
case SBI_EXT_CPPC_READ_HI:
#if __riscv_xlen == 32
ret = sbi_cppc_read(regs->a0, &temp);
*out_val = temp >> 32;
out->value = temp >> 32;
#else
*out_val = 0;
out->value = 0;
#endif
break;
case SBI_EXT_CPPC_WRITE:
@@ -38,7 +37,7 @@ static int sbi_ecall_cppc_handler(unsigned long extid, unsigned long funcid,
case SBI_EXT_CPPC_PROBE:
ret = sbi_cppc_probe(regs->a0);
if (ret >= 0) {
*out_val = ret;
out->value = ret;
ret = 0;
}
break;

View File

@@ -14,11 +14,11 @@
#include <sbi/sbi_ecall_interface.h>
#include <sbi/sbi_trap.h>
#include <sbi/riscv_asm.h>
#include <sbi/sbi_hart.h>
static int sbi_ecall_dbcn_handler(unsigned long extid, unsigned long funcid,
const struct sbi_trap_regs *regs,
unsigned long *out_val,
struct sbi_trap_info *out_trap)
struct sbi_trap_regs *regs,
struct sbi_ecall_return *out)
{
ulong smode = (csr_read(CSR_MSTATUS) & MSTATUS_MPP) >>
MSTATUS_MPP_SHIFT;
@@ -46,10 +46,12 @@ static int sbi_ecall_dbcn_handler(unsigned long extid, unsigned long funcid,
regs->a1, regs->a0, smode,
SBI_DOMAIN_READ|SBI_DOMAIN_WRITE))
return SBI_ERR_INVALID_PARAM;
sbi_hart_map_saddr(regs->a1, regs->a0);
if (funcid == SBI_EXT_DBCN_CONSOLE_WRITE)
*out_val = sbi_nputs((const char *)regs->a1, regs->a0);
out->value = sbi_nputs((const char *)regs->a1, regs->a0);
else
*out_val = sbi_ngets((char *)regs->a1, regs->a0);
out->value = sbi_ngets((char *)regs->a1, regs->a0);
sbi_hart_unmap_saddr();
return 0;
case SBI_EXT_DBCN_CONSOLE_WRITE_BYTE:
sbi_putc(regs->a0);

View File

@@ -17,9 +17,8 @@
#include <sbi/riscv_asm.h>
static int sbi_ecall_hsm_handler(unsigned long extid, unsigned long funcid,
const struct sbi_trap_regs *regs,
unsigned long *out_val,
struct sbi_trap_info *out_trap)
struct sbi_trap_regs *regs,
struct sbi_ecall_return *out)
{
int ret = 0;
struct sbi_scratch *scratch = sbi_scratch_thishart_ptr();
@@ -47,7 +46,7 @@ static int sbi_ecall_hsm_handler(unsigned long extid, unsigned long funcid,
}
if (ret >= 0) {
*out_val = ret;
out->value = ret;
ret = 0;
}

View File

@@ -15,9 +15,8 @@
#include <sbi/sbi_ipi.h>
static int sbi_ecall_ipi_handler(unsigned long extid, unsigned long funcid,
const struct sbi_trap_regs *regs,
unsigned long *out_val,
struct sbi_trap_info *out_trap)
struct sbi_trap_regs *regs,
struct sbi_ecall_return *out)
{
int ret = 0;

View File

@@ -24,32 +24,32 @@
#include <sbi/sbi_unpriv.h>
#include <sbi/sbi_hart.h>
static int sbi_load_hart_mask_unpriv(ulong *pmask, ulong *hmask,
struct sbi_trap_info *uptrap)
static bool sbi_load_hart_mask_unpriv(ulong *pmask, ulong *hmask,
struct sbi_trap_info *uptrap)
{
ulong mask = 0;
if (pmask) {
mask = sbi_load_ulong(pmask, uptrap);
if (uptrap->cause)
return SBI_ETRAP;
return false;
} else {
sbi_hsm_hart_interruptible_mask(sbi_domain_thishart_ptr(),
0, &mask);
}
*hmask = mask;
return 0;
return true;
}
static int sbi_ecall_legacy_handler(unsigned long extid, unsigned long funcid,
const struct sbi_trap_regs *regs,
unsigned long *out_val,
struct sbi_trap_info *out_trap)
struct sbi_trap_regs *regs,
struct sbi_ecall_return *out)
{
int ret = 0;
struct sbi_tlb_info tlb_info;
u32 source_hart = current_hartid();
struct sbi_trap_info trap = {0};
ulong hmask = 0;
switch (extid) {
@@ -70,40 +70,51 @@ static int sbi_ecall_legacy_handler(unsigned long extid, unsigned long funcid,
sbi_ipi_clear_smode();
break;
case SBI_EXT_0_1_SEND_IPI:
ret = sbi_load_hart_mask_unpriv((ulong *)regs->a0,
&hmask, out_trap);
if (ret != SBI_ETRAP)
if (sbi_load_hart_mask_unpriv((ulong *)regs->a0,
&hmask, &trap)) {
ret = sbi_ipi_send_smode(hmask, 0);
} else {
trap.epc = regs->mepc;
sbi_trap_redirect(regs, &trap);
out->skip_regs_update = true;
}
break;
case SBI_EXT_0_1_REMOTE_FENCE_I:
ret = sbi_load_hart_mask_unpriv((ulong *)regs->a0,
&hmask, out_trap);
if (ret != SBI_ETRAP) {
if (sbi_load_hart_mask_unpriv((ulong *)regs->a0,
&hmask, &trap)) {
SBI_TLB_INFO_INIT(&tlb_info, 0, 0, 0, 0,
sbi_tlb_local_fence_i,
source_hart);
SBI_TLB_FENCE_I, source_hart);
ret = sbi_tlb_request(hmask, 0, &tlb_info);
} else {
trap.epc = regs->mepc;
sbi_trap_redirect(regs, &trap);
out->skip_regs_update = true;
}
break;
case SBI_EXT_0_1_REMOTE_SFENCE_VMA:
ret = sbi_load_hart_mask_unpriv((ulong *)regs->a0,
&hmask, out_trap);
if (ret != SBI_ETRAP) {
if (sbi_load_hart_mask_unpriv((ulong *)regs->a0,
&hmask, &trap)) {
SBI_TLB_INFO_INIT(&tlb_info, regs->a1, regs->a2, 0, 0,
sbi_tlb_local_sfence_vma,
source_hart);
SBI_TLB_SFENCE_VMA, source_hart);
ret = sbi_tlb_request(hmask, 0, &tlb_info);
} else {
trap.epc = regs->mepc;
sbi_trap_redirect(regs, &trap);
out->skip_regs_update = true;
}
break;
case SBI_EXT_0_1_REMOTE_SFENCE_VMA_ASID:
ret = sbi_load_hart_mask_unpriv((ulong *)regs->a0,
&hmask, out_trap);
if (ret != SBI_ETRAP) {
if (sbi_load_hart_mask_unpriv((ulong *)regs->a0,
&hmask, &trap)) {
SBI_TLB_INFO_INIT(&tlb_info, regs->a1,
regs->a2, regs->a3, 0,
sbi_tlb_local_sfence_vma_asid,
SBI_TLB_SFENCE_VMA_ASID,
source_hart);
ret = sbi_tlb_request(hmask, 0, &tlb_info);
} else {
trap.epc = regs->mepc;
sbi_trap_redirect(regs, &trap);
out->skip_regs_update = true;
}
break;
case SBI_EXT_0_1_SHUTDOWN:

View File

@@ -18,9 +18,8 @@
#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)
struct sbi_trap_regs *regs,
struct sbi_ecall_return *out)
{
int ret = 0;
uint64_t temp;
@@ -29,12 +28,12 @@ static int sbi_ecall_pmu_handler(unsigned long extid, unsigned long funcid,
case SBI_EXT_PMU_NUM_COUNTERS:
ret = sbi_pmu_num_ctr();
if (ret >= 0) {
*out_val = ret;
out->value = ret;
ret = 0;
}
break;
case SBI_EXT_PMU_COUNTER_GET_INFO:
ret = sbi_pmu_ctr_get_info(regs->a0, out_val);
ret = sbi_pmu_ctr_get_info(regs->a0, &out->value);
break;
case SBI_EXT_PMU_COUNTER_CFG_MATCH:
#if __riscv_xlen == 32
@@ -45,21 +44,21 @@ static int sbi_ecall_pmu_handler(unsigned long extid, unsigned long funcid,
ret = sbi_pmu_ctr_cfg_match(regs->a0, regs->a1, regs->a2,
regs->a3, temp);
if (ret >= 0) {
*out_val = ret;
out->value = ret;
ret = 0;
}
break;
case SBI_EXT_PMU_COUNTER_FW_READ:
ret = sbi_pmu_ctr_fw_read(regs->a0, &temp);
*out_val = temp;
out->value = temp;
break;
case SBI_EXT_PMU_COUNTER_FW_READ_HI:
#if __riscv_xlen == 32
ret = sbi_pmu_ctr_fw_read(regs->a0, &temp);
*out_val = temp >> 32;
out->value = temp >> 32;
#else
*out_val = 0;
out->value = 0;
#endif
break;
case SBI_EXT_PMU_COUNTER_START:
@@ -74,6 +73,8 @@ static int sbi_ecall_pmu_handler(unsigned long extid, unsigned long funcid,
case SBI_EXT_PMU_COUNTER_STOP:
ret = sbi_pmu_ctr_stop(regs->a0, regs->a1, regs->a2);
break;
case SBI_EXT_PMU_SNAPSHOT_SET_SHMEM:
/* fallthrough as OpenSBI doesn't support snapshot yet */
default:
ret = SBI_ENOTSUPP;
}

View File

@@ -16,9 +16,8 @@
#include <sbi/sbi_tlb.h>
static int sbi_ecall_rfence_handler(unsigned long extid, unsigned long funcid,
const struct sbi_trap_regs *regs,
unsigned long *out_val,
struct sbi_trap_info *out_trap)
struct sbi_trap_regs *regs,
struct sbi_ecall_return *out)
{
int ret = 0;
unsigned long vmid;
@@ -33,43 +32,41 @@ static int sbi_ecall_rfence_handler(unsigned long extid, unsigned long funcid,
switch (funcid) {
case SBI_EXT_RFENCE_REMOTE_FENCE_I:
SBI_TLB_INFO_INIT(&tlb_info, 0, 0, 0, 0,
sbi_tlb_local_fence_i, source_hart);
SBI_TLB_FENCE_I, source_hart);
ret = sbi_tlb_request(regs->a0, regs->a1, &tlb_info);
break;
case SBI_EXT_RFENCE_REMOTE_HFENCE_GVMA:
SBI_TLB_INFO_INIT(&tlb_info, regs->a2, regs->a3, 0, 0,
sbi_tlb_local_hfence_gvma, source_hart);
SBI_TLB_HFENCE_GVMA, source_hart);
ret = sbi_tlb_request(regs->a0, regs->a1, &tlb_info);
break;
case SBI_EXT_RFENCE_REMOTE_HFENCE_GVMA_VMID:
SBI_TLB_INFO_INIT(&tlb_info, regs->a2, regs->a3, 0, regs->a4,
sbi_tlb_local_hfence_gvma_vmid,
source_hart);
SBI_TLB_HFENCE_GVMA_VMID, source_hart);
ret = sbi_tlb_request(regs->a0, regs->a1, &tlb_info);
break;
case SBI_EXT_RFENCE_REMOTE_HFENCE_VVMA:
vmid = (csr_read(CSR_HGATP) & HGATP_VMID_MASK);
vmid = vmid >> HGATP_VMID_SHIFT;
SBI_TLB_INFO_INIT(&tlb_info, regs->a2, regs->a3, 0, vmid,
sbi_tlb_local_hfence_vvma, source_hart);
SBI_TLB_HFENCE_VVMA, source_hart);
ret = sbi_tlb_request(regs->a0, regs->a1, &tlb_info);
break;
case SBI_EXT_RFENCE_REMOTE_HFENCE_VVMA_ASID:
vmid = (csr_read(CSR_HGATP) & HGATP_VMID_MASK);
vmid = vmid >> HGATP_VMID_SHIFT;
SBI_TLB_INFO_INIT(&tlb_info, regs->a2, regs->a3, regs->a4,
vmid, sbi_tlb_local_hfence_vvma_asid,
source_hart);
vmid, SBI_TLB_HFENCE_VVMA_ASID, source_hart);
ret = sbi_tlb_request(regs->a0, regs->a1, &tlb_info);
break;
case SBI_EXT_RFENCE_REMOTE_SFENCE_VMA:
SBI_TLB_INFO_INIT(&tlb_info, regs->a2, regs->a3, 0, 0,
sbi_tlb_local_sfence_vma, source_hart);
SBI_TLB_SFENCE_VMA, source_hart);
ret = sbi_tlb_request(regs->a0, regs->a1, &tlb_info);
break;
case SBI_EXT_RFENCE_REMOTE_SFENCE_VMA_ASID:
SBI_TLB_INFO_INIT(&tlb_info, regs->a2, regs->a3, regs->a4, 0,
sbi_tlb_local_sfence_vma_asid, source_hart);
SBI_TLB_SFENCE_VMA_ASID, source_hart);
ret = sbi_tlb_request(regs->a0, regs->a1, &tlb_info);
break;
default:

View File

@@ -15,9 +15,8 @@
#include <sbi/sbi_system.h>
static int sbi_ecall_srst_handler(unsigned long extid, unsigned long funcid,
const struct sbi_trap_regs *regs,
unsigned long *out_val,
struct sbi_trap_info *out_trap)
struct sbi_trap_regs *regs,
struct sbi_ecall_return *out)
{
if (funcid == SBI_EXT_SRST_RESET) {
if ((((u32)-1U) <= ((u64)regs->a0)) ||

View File

@@ -6,9 +6,8 @@
#include <sbi/sbi_system.h>
static int sbi_ecall_susp_handler(unsigned long extid, unsigned long funcid,
const struct sbi_trap_regs *regs,
unsigned long *out_val,
struct sbi_trap_info *out_trap)
struct sbi_trap_regs *regs,
struct sbi_ecall_return *out)
{
int ret = SBI_ENOTSUPP;
@@ -16,7 +15,7 @@ static int sbi_ecall_susp_handler(unsigned long extid, unsigned long funcid,
ret = sbi_system_suspend(regs->a0, regs->a1, regs->a2);
if (ret >= 0) {
*out_val = ret;
out->value = ret;
ret = 0;
}

View File

@@ -15,9 +15,8 @@
#include <sbi/sbi_timer.h>
static int sbi_ecall_time_handler(unsigned long extid, unsigned long funcid,
const struct sbi_trap_regs *regs,
unsigned long *out_val,
struct sbi_trap_info *out_trap)
struct sbi_trap_regs *regs,
struct sbi_ecall_return *out)
{
int ret = 0;

View File

@@ -23,13 +23,11 @@ static inline unsigned long sbi_ecall_vendor_id(void)
}
static int sbi_ecall_vendor_handler(unsigned long extid, unsigned long funcid,
const struct sbi_trap_regs *regs,
unsigned long *out_val,
struct sbi_trap_info *out_trap)
struct sbi_trap_regs *regs,
struct sbi_ecall_return *out)
{
return sbi_platform_vendor_ext_provider(sbi_platform_thishart_ptr(),
funcid, regs,
out_val, out_trap);
funcid, regs, out);
}
struct sbi_ecall_extension ecall_vendor;

View File

@@ -109,7 +109,7 @@ int sbi_emulate_csr_read(int csr_num, struct sbi_trap_regs *regs,
#define switchcase_hpm(__uref, __mref, __csr) \
case __csr: \
if ((sbi_hart_mhpm_count(scratch) + 3) <= (__csr - __uref))\
if (sbi_hart_mhpm_mask(scratch) & (1 << (__csr - __uref)))\
return SBI_ENOTSUPP; \
if (!hpm_allowed(__csr - __uref, prev_mode, virt)) \
return SBI_ENOTSUPP; \

View File

@@ -33,11 +33,11 @@ static unsigned long hart_features_offset;
static void mstatus_init(struct sbi_scratch *scratch)
{
unsigned long menvcfg_val, mstatus_val = 0;
int cidx;
unsigned int num_mhpm = sbi_hart_mhpm_count(scratch);
unsigned long mstatus_val = 0;
unsigned int mhpm_mask = sbi_hart_mhpm_mask(scratch);
uint64_t mhpmevent_init_val = 0;
uint64_t mstateen_val;
uint64_t menvcfg_val, mstateen_val;
/* Enable FPU */
if (misa_extension('D') || misa_extension('F'))
@@ -69,13 +69,14 @@ static void mstatus_init(struct sbi_scratch *scratch)
/**
* 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++) {
for (cidx = 0; cidx <= 28; cidx++) {
if (!(mhpm_mask & 1 << (cidx + 3)))
continue;
#if __riscv_xlen == 32
csr_write_num(CSR_MHPMEVENT3 + cidx, mhpmevent_init_val & 0xFFFFFFFF);
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);
@@ -107,58 +108,40 @@ static void mstatus_init(struct sbi_scratch *scratch)
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;
menvcfg_val |= ((uint64_t)csr_read(CSR_MENVCFGH)) << 32;
#endif
}
#define __set_menvcfg_ext(__ext, __bits) \
if (sbi_hart_has_extension(scratch, __ext)) \
menvcfg_val |= __bits;
/*
* Enable access to extensions if they are present in the
* hardware or in the device tree.
*/
__set_menvcfg_ext(SBI_HART_EXT_ZICBOZ, ENVCFG_CBZE)
__set_menvcfg_ext(SBI_HART_EXT_ZICBOM, ENVCFG_CBCFE)
__set_menvcfg_ext(SBI_HART_EXT_ZICBOM,
ENVCFG_CBIE_INV << ENVCFG_CBIE_SHIFT)
#if __riscv_xlen > 32
__set_menvcfg_ext(SBI_HART_EXT_SVPBMT, ENVCFG_PBMTE)
#endif
__set_menvcfg_ext(SBI_HART_EXT_SSTC, ENVCFG_STCE)
#undef __set_menvcfg_ext
csr_write(CSR_MENVCFG, menvcfg_val);
#if __riscv_xlen == 32
csr_write(CSR_MENVCFGH, menvcfg_val >> 32);
#endif
/* Enable S-mode access to seed CSR */
if (sbi_hart_has_extension(scratch, SBI_HART_EXT_ZKR)) {
csr_set(CSR_MSECCFG, MSECCFG_SSEED);
csr_clear(CSR_MSECCFG, MSECCFG_USEED);
}
}
/* Disable all interrupts */
@@ -244,12 +227,12 @@ void sbi_hart_delegation_dump(struct sbi_scratch *scratch,
prefix, suffix, csr_read(CSR_MEDELEG));
}
unsigned int sbi_hart_mhpm_count(struct sbi_scratch *scratch)
unsigned int sbi_hart_mhpm_mask(struct sbi_scratch *scratch)
{
struct sbi_hart_features *hfeatures =
sbi_scratch_offset_ptr(scratch, hart_features_offset);
return hfeatures->mhpm_count;
return hfeatures->mhpm_mask;
}
unsigned int sbi_hart_pmp_count(struct sbi_scratch *scratch)
@@ -260,12 +243,12 @@ unsigned int sbi_hart_pmp_count(struct sbi_scratch *scratch)
return hfeatures->pmp_count;
}
unsigned long sbi_hart_pmp_granularity(struct sbi_scratch *scratch)
unsigned int sbi_hart_pmp_log2gran(struct sbi_scratch *scratch)
{
struct sbi_hart_features *hfeatures =
sbi_scratch_offset_ptr(scratch, hart_features_offset);
return hfeatures->pmp_gran;
return hfeatures->pmp_log2gran;
}
unsigned int sbi_hart_pmp_addrbits(struct sbi_scratch *scratch)
@@ -284,20 +267,174 @@ unsigned int sbi_hart_mhpm_bits(struct sbi_scratch *scratch)
return hfeatures->mhpm_bits;
}
int sbi_hart_pmp_configure(struct sbi_scratch *scratch)
/*
* Returns Smepmp flags for a given domain and region based on permissions.
*/
static unsigned int sbi_hart_get_smepmp_flags(struct sbi_scratch *scratch,
struct sbi_domain *dom,
struct sbi_domain_memregion *reg)
{
unsigned int pmp_flags = 0;
if (SBI_DOMAIN_MEMREGION_IS_SHARED(reg->flags)) {
/* Read only for both M and SU modes */
if (SBI_DOMAIN_MEMREGION_IS_SUR_MR(reg->flags))
pmp_flags = (PMP_L | PMP_R | PMP_W | PMP_X);
/* Execute for SU but Read/Execute for M mode */
else if (SBI_DOMAIN_MEMREGION_IS_SUX_MRX(reg->flags))
/* locked region */
pmp_flags = (PMP_L | PMP_W | PMP_X);
/* Execute only for both M and SU modes */
else if (SBI_DOMAIN_MEMREGION_IS_SUX_MX(reg->flags))
pmp_flags = (PMP_L | PMP_W);
/* Read/Write for both M and SU modes */
else if (SBI_DOMAIN_MEMREGION_IS_SURW_MRW(reg->flags))
pmp_flags = (PMP_W | PMP_X);
/* Read only for SU mode but Read/Write for M mode */
else if (SBI_DOMAIN_MEMREGION_IS_SUR_MRW(reg->flags))
pmp_flags = (PMP_W);
} else if (SBI_DOMAIN_MEMREGION_M_ONLY_ACCESS(reg->flags)) {
/*
* When smepmp is supported and used, M region cannot have RWX
* permissions on any region.
*/
if ((reg->flags & SBI_DOMAIN_MEMREGION_M_ACCESS_MASK)
== SBI_DOMAIN_MEMREGION_M_RWX) {
sbi_printf("%s: M-mode only regions cannot have"
"RWX permissions\n", __func__);
return 0;
}
/* M-mode only access regions are always locked */
pmp_flags |= PMP_L;
if (reg->flags & SBI_DOMAIN_MEMREGION_M_READABLE)
pmp_flags |= PMP_R;
if (reg->flags & SBI_DOMAIN_MEMREGION_M_WRITABLE)
pmp_flags |= PMP_W;
if (reg->flags & SBI_DOMAIN_MEMREGION_M_EXECUTABLE)
pmp_flags |= PMP_X;
} else if (SBI_DOMAIN_MEMREGION_SU_ONLY_ACCESS(reg->flags)) {
if (reg->flags & SBI_DOMAIN_MEMREGION_SU_READABLE)
pmp_flags |= PMP_R;
if (reg->flags & SBI_DOMAIN_MEMREGION_SU_WRITABLE)
pmp_flags |= PMP_W;
if (reg->flags & SBI_DOMAIN_MEMREGION_SU_EXECUTABLE)
pmp_flags |= PMP_X;
}
return pmp_flags;
}
static void sbi_hart_smepmp_set(struct sbi_scratch *scratch,
struct sbi_domain *dom,
struct sbi_domain_memregion *reg,
unsigned int pmp_idx,
unsigned int pmp_flags,
unsigned int pmp_log2gran,
unsigned long pmp_addr_max)
{
unsigned long pmp_addr = reg->base >> PMP_SHIFT;
if (pmp_log2gran <= reg->order && pmp_addr < pmp_addr_max) {
pmp_set(pmp_idx, pmp_flags, reg->base, reg->order);
} else {
sbi_printf("Can not configure pmp for domain %s because"
" memory region address 0x%lx or size 0x%lx "
"is not in range.\n", dom->name, reg->base,
reg->order);
}
}
static int sbi_hart_smepmp_configure(struct sbi_scratch *scratch,
unsigned int pmp_count,
unsigned int pmp_log2gran,
unsigned long pmp_addr_max)
{
struct sbi_domain_memregion *reg;
struct sbi_domain *dom = sbi_domain_thishart_ptr();
unsigned int pmp_idx = 0, pmp_flags, pmp_bits, pmp_gran_log2;
unsigned int pmp_count = sbi_hart_pmp_count(scratch);
unsigned long pmp_addr = 0, pmp_addr_max = 0;
unsigned int pmp_idx, pmp_flags;
if (!pmp_count)
return 0;
/*
* Set the RLB so that, we can write to PMP entries without
* enforcement even if some entries are locked.
*/
csr_set(CSR_MSECCFG, MSECCFG_RLB);
pmp_gran_log2 = log2roundup(sbi_hart_pmp_granularity(scratch));
pmp_bits = sbi_hart_pmp_addrbits(scratch) - 1;
pmp_addr_max = (1UL << pmp_bits) | ((1UL << pmp_bits) - 1);
/* Disable the reserved entry */
pmp_disable(SBI_SMEPMP_RESV_ENTRY);
/* Program M-only regions when MML is not set. */
pmp_idx = 0;
sbi_domain_for_each_memregion(dom, reg) {
/* Skip reserved entry */
if (pmp_idx == SBI_SMEPMP_RESV_ENTRY)
pmp_idx++;
if (pmp_count <= pmp_idx)
break;
/* Skip shared and SU-only regions */
if (!SBI_DOMAIN_MEMREGION_M_ONLY_ACCESS(reg->flags)) {
pmp_idx++;
continue;
}
pmp_flags = sbi_hart_get_smepmp_flags(scratch, dom, reg);
if (!pmp_flags)
return 0;
sbi_hart_smepmp_set(scratch, dom, reg, pmp_idx++, pmp_flags,
pmp_log2gran, pmp_addr_max);
}
/* Set the MML to enforce new encoding */
csr_set(CSR_MSECCFG, MSECCFG_MML);
/* Program shared and SU-only regions */
pmp_idx = 0;
sbi_domain_for_each_memregion(dom, reg) {
/* Skip reserved entry */
if (pmp_idx == SBI_SMEPMP_RESV_ENTRY)
pmp_idx++;
if (pmp_count <= pmp_idx)
break;
/* Skip M-only regions */
if (SBI_DOMAIN_MEMREGION_M_ONLY_ACCESS(reg->flags)) {
pmp_idx++;
continue;
}
pmp_flags = sbi_hart_get_smepmp_flags(scratch, dom, reg);
if (!pmp_flags)
return 0;
sbi_hart_smepmp_set(scratch, dom, reg, pmp_idx++, pmp_flags,
pmp_log2gran, pmp_addr_max);
}
/*
* All entries are programmed.
* Keep the RLB bit so that dynamic mappings can be done.
*/
return 0;
}
static int sbi_hart_oldpmp_configure(struct sbi_scratch *scratch,
unsigned int pmp_count,
unsigned int pmp_log2gran,
unsigned long pmp_addr_max)
{
struct sbi_domain_memregion *reg;
struct sbi_domain *dom = sbi_domain_thishart_ptr();
unsigned int pmp_idx = 0;
unsigned int pmp_flags;
unsigned long pmp_addr;
sbi_domain_for_each_memregion(dom, reg) {
if (pmp_count <= pmp_idx)
@@ -306,8 +443,8 @@ int sbi_hart_pmp_configure(struct sbi_scratch *scratch)
pmp_flags = 0;
/*
* If permissions are to be enforced for all modes on this
* region, the lock bit should be set.
* If permissions are to be enforced for all modes on
* this region, the lock bit should be set.
*/
if (reg->flags & SBI_DOMAIN_MEMREGION_ENF_PERMISSIONS)
pmp_flags |= PMP_L;
@@ -319,16 +456,84 @@ int sbi_hart_pmp_configure(struct sbi_scratch *scratch)
if (reg->flags & SBI_DOMAIN_MEMREGION_SU_EXECUTABLE)
pmp_flags |= PMP_X;
pmp_addr = reg->base >> PMP_SHIFT;
if (pmp_gran_log2 <= reg->order && pmp_addr < pmp_addr_max)
pmp_addr = reg->base >> PMP_SHIFT;
if (pmp_log2gran <= reg->order && pmp_addr < pmp_addr_max) {
pmp_set(pmp_idx++, pmp_flags, reg->base, reg->order);
else {
sbi_printf("Can not configure pmp for domain %s", dom->name);
sbi_printf(" because memory region address %lx or size %lx is not in range\n",
reg->base, reg->order);
} else {
sbi_printf("Can not configure pmp for domain %s because"
" memory region address 0x%lx or size 0x%lx "
"is not in range.\n", dom->name, reg->base,
reg->order);
}
}
return 0;
}
int sbi_hart_map_saddr(unsigned long addr, unsigned long size)
{
/* shared R/W access for M and S/U mode */
unsigned int pmp_flags = (PMP_W | PMP_X);
unsigned long order, base = 0;
struct sbi_scratch *scratch = sbi_scratch_thishart_ptr();
/* If Smepmp is not supported no special mapping is required */
if (!sbi_hart_has_extension(scratch, SBI_HART_EXT_SMEPMP))
return SBI_OK;
if (is_pmp_entry_mapped(SBI_SMEPMP_RESV_ENTRY))
return SBI_ENOSPC;
for (order = MAX(sbi_hart_pmp_log2gran(scratch), log2roundup(size));
order <= __riscv_xlen; order++) {
if (order < __riscv_xlen) {
base = addr & ~((1UL << order) - 1UL);
if ((base <= addr) &&
(addr < (base + (1UL << order))) &&
(base <= (addr + size - 1UL)) &&
((addr + size - 1UL) < (base + (1UL << order))))
break;
} else {
return SBI_EFAIL;
}
}
pmp_set(SBI_SMEPMP_RESV_ENTRY, pmp_flags, base, order);
return SBI_OK;
}
int sbi_hart_unmap_saddr(void)
{
struct sbi_scratch *scratch = sbi_scratch_thishart_ptr();
if (!sbi_hart_has_extension(scratch, SBI_HART_EXT_SMEPMP))
return SBI_OK;
return pmp_disable(SBI_SMEPMP_RESV_ENTRY);
}
int sbi_hart_pmp_configure(struct sbi_scratch *scratch)
{
int rc;
unsigned int pmp_bits, pmp_log2gran;
unsigned int pmp_count = sbi_hart_pmp_count(scratch);
unsigned long pmp_addr_max;
if (!pmp_count)
return 0;
pmp_log2gran = sbi_hart_pmp_log2gran(scratch);
pmp_bits = sbi_hart_pmp_addrbits(scratch) - 1;
pmp_addr_max = (1UL << pmp_bits) | ((1UL << pmp_bits) - 1);
if (sbi_hart_has_extension(scratch, SBI_HART_EXT_SMEPMP))
rc = sbi_hart_smepmp_configure(scratch, pmp_count,
pmp_log2gran, pmp_addr_max);
else
rc = sbi_hart_oldpmp_configure(scratch, pmp_count,
pmp_log2gran, pmp_addr_max);
/*
* As per section 3.7.2 of privileged specification v1.12,
* virtual address translations can be speculatively performed
@@ -350,7 +555,7 @@ int sbi_hart_pmp_configure(struct sbi_scratch *scratch)
__sbi_hfence_gvma_all();
}
return 0;
return rc;
}
int sbi_hart_priv_version(struct sbi_scratch *scratch)
@@ -392,9 +597,9 @@ static inline void __sbi_hart_update_extension(
bool enable)
{
if (enable)
hfeatures->extensions |= BIT(ext);
__set_bit(ext, hfeatures->extensions);
else
hfeatures->extensions &= ~BIT(ext);
__clear_bit(ext, hfeatures->extensions);
}
/**
@@ -427,39 +632,33 @@ bool sbi_hart_has_extension(struct sbi_scratch *scratch,
struct sbi_hart_features *hfeatures =
sbi_scratch_offset_ptr(scratch, hart_features_offset);
if (hfeatures->extensions & BIT(ext))
if (__test_bit(ext, hfeatures->extensions))
return true;
else
return false;
}
static inline char *sbi_hart_extension_id2string(int ext)
{
char *estr = NULL;
switch (ext) {
case SBI_HART_EXT_SSCOFPMF:
estr = "sscofpmf";
break;
case SBI_HART_EXT_TIME:
estr = "time";
break;
case SBI_HART_EXT_SMAIA:
estr = "smaia";
break;
case SBI_HART_EXT_SSTC:
estr = "sstc";
break;
case SBI_HART_EXT_SMSTATEEN:
estr = "smstateen";
break;
default:
break;
}
return estr;
#define __SBI_HART_EXT_DATA(_name, _id) { \
.name = #_name, \
.id = _id, \
}
const struct sbi_hart_ext_data sbi_hart_ext[] = {
__SBI_HART_EXT_DATA(smaia, SBI_HART_EXT_SMAIA),
__SBI_HART_EXT_DATA(smepmp, SBI_HART_EXT_SMEPMP),
__SBI_HART_EXT_DATA(smstateen, SBI_HART_EXT_SMSTATEEN),
__SBI_HART_EXT_DATA(sscofpmf, SBI_HART_EXT_SSCOFPMF),
__SBI_HART_EXT_DATA(sstc, SBI_HART_EXT_SSTC),
__SBI_HART_EXT_DATA(zicntr, SBI_HART_EXT_ZICNTR),
__SBI_HART_EXT_DATA(zihpm, SBI_HART_EXT_ZIHPM),
__SBI_HART_EXT_DATA(zkr, SBI_HART_EXT_ZKR),
__SBI_HART_EXT_DATA(smcntrpmf, SBI_HART_EXT_SMCNTRPMF),
__SBI_HART_EXT_DATA(xandespmu, SBI_HART_EXT_XANDESPMU),
__SBI_HART_EXT_DATA(zicboz, SBI_HART_EXT_ZICBOZ),
__SBI_HART_EXT_DATA(zicbom, SBI_HART_EXT_ZICBOM),
__SBI_HART_EXT_DATA(svpbmt, SBI_HART_EXT_SVPBMT),
};
/**
* Get the hart extensions in string format
*
@@ -475,30 +674,18 @@ void sbi_hart_get_extensions_str(struct sbi_scratch *scratch,
struct sbi_hart_features *hfeatures =
sbi_scratch_offset_ptr(scratch, hart_features_offset);
int offset = 0, ext = 0;
char *temp;
if (!extensions_str || nestr <= 0)
return;
sbi_memset(extensions_str, 0, nestr);
if (!hfeatures->extensions)
goto done;
for_each_set_bit(ext, hfeatures->extensions, SBI_HART_EXT_MAX) {
sbi_snprintf(extensions_str + offset,
nestr - offset,
"%s,", sbi_hart_ext[ext].name);
offset = offset + sbi_strlen(sbi_hart_ext[ext].name) + 1;
}
do {
if (hfeatures->extensions & BIT(ext)) {
temp = sbi_hart_extension_id2string(ext);
if (temp) {
sbi_snprintf(extensions_str + offset,
nestr - offset,
"%s,", temp);
offset = offset + sbi_strlen(temp) + 1;
}
}
ext++;
} while (ext < SBI_HART_EXT_MAX);
done:
if (offset)
extensions_str[offset - 1] = '\0';
else
@@ -524,7 +711,7 @@ static unsigned long hart_pmp_get_allowed_addr(void)
return val;
}
static int hart_pmu_get_allowed_bits(void)
static int hart_mhpm_get_allowed_bits(void)
{
unsigned long val = ~(0UL);
struct sbi_trap_info trap = {0};
@@ -561,6 +748,7 @@ static int hart_detect_features(struct sbi_scratch *scratch)
struct sbi_hart_features *hfeatures =
sbi_scratch_offset_ptr(scratch, hart_features_offset);
unsigned long val, oldval;
bool has_zicntr = false;
int rc;
/* If hart features already detected then do nothing */
@@ -568,9 +756,32 @@ static int hart_detect_features(struct sbi_scratch *scratch)
return 0;
/* Clear hart features */
hfeatures->extensions = 0;
sbi_memset(hfeatures->extensions, 0, sizeof(hfeatures->extensions));
hfeatures->pmp_count = 0;
hfeatures->mhpm_count = 0;
hfeatures->mhpm_mask = 0;
hfeatures->priv_version = SBI_HART_PRIV_VER_UNKNOWN;
#define __check_hpm_csr(__csr, __mask) \
oldval = csr_read_allowed(__csr, (ulong)&trap); \
if (!trap.cause) { \
csr_write_allowed(__csr, (ulong)&trap, 1UL); \
if (!trap.cause && csr_swap(__csr, oldval) == 1UL) { \
(hfeatures->__mask) |= 1 << (__csr - CSR_MCYCLE); \
} \
}
#define __check_hpm_csr_2(__csr, __mask) \
__check_hpm_csr(__csr + 0, __mask) \
__check_hpm_csr(__csr + 1, __mask)
#define __check_hpm_csr_4(__csr, __mask) \
__check_hpm_csr_2(__csr + 0, __mask) \
__check_hpm_csr_2(__csr + 2, __mask)
#define __check_hpm_csr_8(__csr, __mask) \
__check_hpm_csr_4(__csr + 0, __mask) \
__check_hpm_csr_4(__csr + 4, __mask)
#define __check_hpm_csr_16(__csr, __mask) \
__check_hpm_csr_8(__csr + 0, __mask) \
__check_hpm_csr_8(__csr + 8, __mask)
#define __check_csr(__csr, __rdonly, __wrval, __field, __skip) \
oldval = csr_read_allowed(__csr, (ulong)&trap); \
@@ -616,28 +827,23 @@ static int hart_detect_features(struct sbi_scratch *scratch)
*/
val = hart_pmp_get_allowed_addr();
if (val) {
hfeatures->pmp_gran = 1 << (sbi_ffs(val) + 2);
hfeatures->pmp_log2gran = 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);
}
__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);
__check_hpm_csr(CSR_MHPMCOUNTER3, mhpm_mask);
hfeatures->mhpm_bits = hart_mhpm_get_allowed_bits();
__check_hpm_csr_4(CSR_MHPMCOUNTER4, mhpm_mask);
__check_hpm_csr_8(CSR_MHPMCOUNTER8, mhpm_mask);
__check_hpm_csr_16(CSR_MHPMCOUNTER16, mhpm_mask);
/**
* 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
#undef __check_csr_32
#undef __check_csr_16
@@ -646,59 +852,57 @@ __mhpm_skip:
#undef __check_csr_2
#undef __check_csr
#define __check_priv(__csr, __base_priv, __priv) \
val = csr_read_allowed(__csr, (ulong)&trap); \
if (!trap.cause && (hfeatures->priv_version >= __base_priv)) { \
hfeatures->priv_version = __priv; \
}
/* Detect if hart supports Priv v1.10 */
val = csr_read_allowed(CSR_MCOUNTEREN, (unsigned long)&trap);
if (!trap.cause)
hfeatures->priv_version = SBI_HART_PRIV_VER_1_10;
__check_priv(CSR_MCOUNTEREN,
SBI_HART_PRIV_VER_UNKNOWN, 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;
__check_priv(CSR_MCOUNTINHIBIT,
SBI_HART_PRIV_VER_1_10, 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;
__check_priv(CSR_MENVCFG,
SBI_HART_PRIV_VER_1_11, SBI_HART_PRIV_VER_1_12);
#undef __check_priv_csr
#define __check_ext_csr(__base_priv, __csr, __ext) \
if (hfeatures->priv_version >= __base_priv) { \
csr_read_allowed(__csr, (ulong)&trap); \
if (!trap.cause) \
__sbi_hart_update_extension(hfeatures, \
__ext, true); \
}
/* 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 sscofpmf */
__check_ext_csr(SBI_HART_PRIV_VER_1_11,
CSR_SCOUNTOVF, SBI_HART_EXT_SSCOFPMF);
/* Detect if hart supports time CSR */
csr_read_allowed(CSR_TIME, (unsigned long)&trap);
if (!trap.cause)
__sbi_hart_update_extension(hfeatures,
SBI_HART_EXT_TIME, true);
__check_ext_csr(SBI_HART_PRIV_VER_UNKNOWN,
CSR_TIME, SBI_HART_EXT_ZICNTR);
/* 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_SMAIA, true);
__check_ext_csr(SBI_HART_PRIV_VER_UNKNOWN,
CSR_MTOPI, SBI_HART_EXT_SMAIA);
/* 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);
}
__check_ext_csr(SBI_HART_PRIV_VER_1_12,
CSR_STIMECMP, SBI_HART_EXT_SSTC);
/* 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);
}
__check_ext_csr(SBI_HART_PRIV_VER_1_12,
CSR_MSTATEEN0, SBI_HART_EXT_SMSTATEEN);
/* Detect if hart supports smcntrpmf */
__check_ext_csr(SBI_HART_PRIV_VER_1_12,
CSR_MCYCLECFG, SBI_HART_EXT_SMCNTRPMF);
#undef __check_ext_csr
/* Save trap based detection of Zicntr */
has_zicntr = sbi_hart_has_extension(scratch, SBI_HART_EXT_ZICNTR);
/* Let platform populate extensions */
rc = sbi_platform_extensions_init(sbi_platform_thishart_ptr(),
@@ -706,9 +910,28 @@ __mhpm_skip:
if (rc)
return rc;
/* Zicntr should only be detected using traps */
__sbi_hart_update_extension(hfeatures, SBI_HART_EXT_ZICNTR,
has_zicntr);
/* Extensions implied by other extensions and features */
if (hfeatures->mhpm_mask)
__sbi_hart_update_extension(hfeatures,
SBI_HART_EXT_ZIHPM, true);
/* Mark hart feature detection done */
hfeatures->detected = true;
/*
* On platforms with Smepmp, the previous booting stage must
* enter OpenSBI with mseccfg.MML == 0. This allows OpenSBI
* to configure it's own M-mode only regions without depending
* on the previous booting stage.
*/
if (sbi_hart_has_extension(scratch, SBI_HART_EXT_SMEPMP) &&
(csr_read(CSR_MSECCFG) & MSECCFG_MML))
return SBI_EILL;
return 0;
}

View File

@@ -14,8 +14,6 @@
#include <sbi/sbi_scratch.h>
#include <sbi/sbi_string.h>
/* Alignment of heap base address and size */
#define HEAP_BASE_ALIGN 1024
/* Minimum size and alignment of heap allocations */
#define HEAP_ALLOC_ALIGN 64
#define HEAP_HOUSEKEEPING_FACTOR 16

View File

@@ -115,23 +115,22 @@ int sbi_hsm_hart_interruptible_mask(const struct sbi_domain *dom,
{
int hstate;
ulong i, hmask, dmask;
ulong hend = sbi_scratch_last_hartid() + 1;
*out_hmask = 0;
if (hend <= hbase)
if (!sbi_hartid_valid(hbase))
return SBI_EINVAL;
if (BITS_PER_LONG < (hend - hbase))
hend = hbase + BITS_PER_LONG;
dmask = sbi_domain_get_assigned_hartmask(dom, hbase);
for (i = hbase; i < hend; i++) {
hmask = 1UL << (i - hbase);
if (dmask & hmask) {
hstate = __sbi_hsm_hart_get_state(i);
if (hstate == SBI_HSM_STATE_STARTED ||
hstate == SBI_HSM_STATE_SUSPENDED)
*out_hmask |= hmask;
}
for (i = 0; i < BITS_PER_LONG; i++) {
hmask = 1UL << i;
if (!(dmask & hmask))
continue;
hstate = __sbi_hsm_hart_get_state(hbase + i);
if (hstate == SBI_HSM_STATE_STARTED ||
hstate == SBI_HSM_STATE_SUSPENDED ||
hstate == SBI_HSM_STATE_RESUME_PENDING)
*out_hmask |= hmask;
}
return 0;
@@ -249,15 +248,15 @@ int sbi_hsm_init(struct sbi_scratch *scratch, u32 hartid, bool cold_boot)
return SBI_ENOMEM;
/* Initialize hart state data for every hart */
for (i = 0; i <= sbi_scratch_last_hartid(); i++) {
rscratch = sbi_hartid_to_scratch(i);
for (i = 0; i <= sbi_scratch_last_hartindex(); i++) {
rscratch = sbi_hartindex_to_scratch(i);
if (!rscratch)
continue;
hdata = sbi_scratch_offset_ptr(rscratch,
hart_data_offset);
ATOMIC_INIT(&hdata->state,
(i == hartid) ?
(sbi_hartindex_to_hartid(i) == hartid) ?
SBI_HSM_STATE_START_PENDING :
SBI_HSM_STATE_STOPPED);
ATOMIC_INIT(&hdata->start_ticket, 0);
@@ -356,7 +355,7 @@ int sbi_hsm_hart_start(struct sbi_scratch *scratch,
(hsm_device_has_hart_secondary_boot() && !init_count)) {
rc = hsm_device_hart_start(hartid, scratch->warmboot_addr);
} else {
rc = sbi_ipi_raw_send(hartid);
rc = sbi_ipi_raw_send(sbi_hartid_to_hartindex(hartid));
}
if (!rc)

View File

@@ -176,12 +176,13 @@ static void sbi_boot_print_hart(struct sbi_scratch *scratch, u32 hartid)
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",
sbi_hart_pmp_granularity(scratch));
sbi_printf("Boot HART PMP Granularity : %u bits\n",
sbi_hart_pmp_log2gran(scratch));
sbi_printf("Boot HART PMP Address Bits: %d\n",
sbi_hart_pmp_addrbits(scratch));
sbi_printf("Boot HART MHPM Count : %d\n",
sbi_hart_mhpm_count(scratch));
sbi_printf("Boot HART MHPM Info : %lu (0x%08x)\n",
sbi_popcount(sbi_hart_mhpm_mask(scratch)),
sbi_hart_mhpm_mask(scratch));
sbi_hart_delegation_dump(scratch, "Boot HART ", " ");
}
@@ -194,6 +195,9 @@ static void wait_for_coldboot(struct sbi_scratch *scratch, u32 hartid)
{
unsigned long saved_mie, cmip;
if (__smp_load_acquire(&coldboot_done))
return;
/* Save MIE CSR */
saved_mie = csr_read(CSR_MIE);
@@ -204,7 +208,7 @@ static void wait_for_coldboot(struct sbi_scratch *scratch, u32 hartid)
spin_lock(&coldboot_lock);
/* Mark current HART as waiting */
sbi_hartmask_set_hart(hartid, &coldboot_wait_hmask);
sbi_hartmask_set_hartid(hartid, &coldboot_wait_hmask);
/* Release coldboot lock */
spin_unlock(&coldboot_lock);
@@ -221,7 +225,7 @@ static void wait_for_coldboot(struct sbi_scratch *scratch, u32 hartid)
spin_lock(&coldboot_lock);
/* Unmark current HART as waiting */
sbi_hartmask_clear_hart(hartid, &coldboot_wait_hmask);
sbi_hartmask_clear_hartid(hartid, &coldboot_wait_hmask);
/* Release coldboot lock */
spin_unlock(&coldboot_lock);
@@ -241,6 +245,8 @@ static void wait_for_coldboot(struct sbi_scratch *scratch, u32 hartid)
static void wake_coldboot_harts(struct sbi_scratch *scratch, u32 hartid)
{
u32 i, hartindex = sbi_hartid_to_hartindex(hartid);
/* Mark coldboot done */
__smp_store_release(&coldboot_done, 1);
@@ -248,10 +254,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 (u32 i = 0; i <= sbi_scratch_last_hartid(); i++) {
if ((i != hartid) &&
sbi_hartmask_test_hart(i, &coldboot_wait_hmask))
sbi_ipi_raw_send(i);
sbi_hartmask_for_each_hartindex(i, &coldboot_wait_hmask) {
if (i == hartindex)
continue;
sbi_ipi_raw_send(i);
}
/* Release coldboot lock */
@@ -356,13 +362,6 @@ static void __noreturn init_coldboot(struct sbi_scratch *scratch, u32 hartid)
sbi_hart_hang();
}
rc = sbi_hart_pmp_configure(scratch);
if (rc) {
sbi_printf("%s: PMP configure failed (error %d)\n",
__func__, rc);
sbi_hart_hang();
}
/*
* Note: Platform final initialization should be after finalizing
* domains so that it sees correct domain assignment and PMP
@@ -392,6 +391,17 @@ static void __noreturn init_coldboot(struct sbi_scratch *scratch, u32 hartid)
sbi_boot_print_hart(scratch, hartid);
/*
* Configure PMP at last because if SMEPMP is detected,
* M-mode access to the S/U space will be rescinded.
*/
rc = sbi_hart_pmp_configure(scratch);
if (rc) {
sbi_printf("%s: PMP configure failed (error %d)\n",
__func__, rc);
sbi_hart_hang();
}
wake_coldboot_harts(scratch, hartid);
count = sbi_scratch_offset_ptr(scratch, init_count_offset);
@@ -445,11 +455,15 @@ static void __noreturn init_warm_startup(struct sbi_scratch *scratch,
if (rc)
sbi_hart_hang();
rc = sbi_hart_pmp_configure(scratch);
rc = sbi_platform_final_init(plat, false);
if (rc)
sbi_hart_hang();
rc = sbi_platform_final_init(plat, false);
/*
* Configure PMP at last because if SMEPMP is detected,
* M-mode access to the S/U space will be rescinded.
*/
rc = sbi_hart_pmp_configure(scratch);
if (rc)
sbi_hart_hang();
@@ -490,7 +504,7 @@ static void __noreturn init_warmboot(struct sbi_scratch *scratch, u32 hartid)
if (hstate == SBI_HSM_STATE_SUSPENDED) {
init_warm_resume(scratch, hartid);
} else {
sbi_ipi_raw_clear(hartid);
sbi_ipi_raw_clear(sbi_hartid_to_hartindex(hartid));
init_warm_startup(scratch, hartid);
}
}
@@ -511,13 +525,19 @@ static atomic_t coldboot_lottery = ATOMIC_INITIALIZER(0);
*/
void __noreturn sbi_init(struct sbi_scratch *scratch)
{
u32 i, h;
bool hartid_valid = false;
bool next_mode_supported = false;
bool coldboot = false;
u32 hartid = current_hartid();
const struct sbi_platform *plat = sbi_platform_ptr(scratch);
if ((SBI_HARTMASK_MAX_BITS <= hartid) ||
sbi_platform_hart_invalid(plat, hartid))
for (i = 0; i < plat->hart_count; i++) {
h = (plat->hart_index2id) ? plat->hart_index2id[i] : i;
if (h == hartid)
hartid_valid = true;
}
if (!hartid_valid)
sbi_hart_hang();
switch (scratch->next_mode) {
@@ -614,7 +634,7 @@ void __noreturn sbi_exit(struct sbi_scratch *scratch)
u32 hartid = current_hartid();
const struct sbi_platform *plat = sbi_platform_ptr(scratch);
if (sbi_platform_hart_invalid(plat, hartid))
if (!sbi_hartid_valid(hartid))
sbi_hart_hang();
sbi_platform_early_exit(plat);

View File

@@ -27,14 +27,19 @@ struct sbi_ipi_data {
unsigned long ipi_type;
};
_Static_assert(
8 * sizeof(((struct sbi_ipi_data*)0)->ipi_type) == SBI_IPI_EVENT_MAX,
"type of sbi_ipi_data.ipi_type has changed, please redefine SBI_IPI_EVENT_MAX"
);
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,
static int sbi_ipi_send(struct sbi_scratch *scratch, u32 remote_hartindex,
u32 event, void *data)
{
int ret;
int ret = 0;
struct sbi_scratch *remote_scratch = NULL;
struct sbi_ipi_data *ipi_data;
const struct sbi_ipi_event_ops *ipi_ops;
@@ -44,7 +49,7 @@ static int sbi_ipi_send(struct sbi_scratch *scratch, u32 remote_hartid,
return SBI_EINVAL;
ipi_ops = ipi_ops_array[event];
remote_scratch = sbi_hartid_to_scratch(remote_hartid);
remote_scratch = sbi_hartindex_to_scratch(remote_hartindex);
if (!remote_scratch)
return SBI_EINVAL;
@@ -52,24 +57,34 @@ static int sbi_ipi_send(struct sbi_scratch *scratch, u32 remote_hartid,
if (ipi_ops->update) {
ret = ipi_ops->update(scratch, remote_scratch,
remote_hartid, data);
remote_hartindex, data);
if (ret != SBI_IPI_UPDATE_SUCCESS)
return ret;
} else if (scratch == remote_scratch) {
/*
* IPI events with an update() callback are expected to return
* SBI_IPI_UPDATE_BREAK for self-IPIs. For other events, check
* for self-IPI and execute the callback directly here.
*/
ipi_ops->process(scratch);
return 0;
}
/*
* Set IPI type on remote hart's scratch area and
* trigger the interrupt
* trigger the interrupt.
*
* Multiple harts may be trying to send IPI to the
* remote hart so call sbi_ipi_raw_send() only when
* the ipi_type was previously zero.
*/
atomic_raw_set_bit(event, &ipi_data->ipi_type);
smp_wmb();
if (ipi_dev && ipi_dev->ipi_send)
ipi_dev->ipi_send(remote_hartid);
if (!__atomic_fetch_or(&ipi_data->ipi_type,
BIT(event), __ATOMIC_RELAXED))
ret = sbi_ipi_raw_send(remote_hartindex);
sbi_pmu_ctr_incr_fw(SBI_PMU_FW_IPI_SENT);
return 0;
return ret;
}
static int sbi_ipi_sync(struct sbi_scratch *scratch, u32 event)
@@ -94,7 +109,7 @@ static int sbi_ipi_sync(struct sbi_scratch *scratch, u32 event)
*/
int sbi_ipi_send_many(ulong hmask, ulong hbase, u32 event, void *data)
{
int rc;
int rc = 0;
bool retry_needed;
ulong i, m;
struct sbi_hartmask target_mask = {0};
@@ -110,14 +125,14 @@ int sbi_ipi_send_many(ulong hmask, ulong hbase, u32 event, void *data)
for (i = hbase; m; i++, m >>= 1) {
if (m & 1UL)
sbi_hartmask_set_hart(i, &target_mask);
sbi_hartmask_set_hartid(i, &target_mask);
}
} else {
hbase = 0;
while (!sbi_hsm_hart_interruptible_mask(dom, hbase, &m)) {
for (i = hbase; m; i++, m >>= 1) {
if (m & 1UL)
sbi_hartmask_set_hart(i, &target_mask);
sbi_hartmask_set_hartid(i, &target_mask);
}
hbase += BITS_PER_LONG;
}
@@ -126,19 +141,23 @@ int sbi_ipi_send_many(ulong hmask, ulong hbase, u32 event, void *data)
/* Send IPIs */
do {
retry_needed = false;
sbi_hartmask_for_each_hart(i, &target_mask) {
sbi_hartmask_for_each_hartindex(i, &target_mask) {
rc = sbi_ipi_send(scratch, i, event, data);
if (rc < 0)
goto done;
if (rc == SBI_IPI_UPDATE_RETRY)
retry_needed = true;
else
sbi_hartmask_clear_hart(i, &target_mask);
sbi_hartmask_clear_hartindex(i, &target_mask);
rc = 0;
}
} while (retry_needed);
done:
/* Sync IPIs */
sbi_ipi_sync(scratch, event);
return 0;
return rc;
}
int sbi_ipi_event_create(const struct sbi_ipi_event_ops *ops)
@@ -214,18 +233,17 @@ void sbi_ipi_process(void)
struct sbi_scratch *scratch = sbi_scratch_thishart_ptr();
struct sbi_ipi_data *ipi_data =
sbi_scratch_offset_ptr(scratch, ipi_data_off);
u32 hartid = current_hartid();
u32 hartindex = sbi_hartid_to_hartindex(current_hartid());
sbi_pmu_ctr_incr_fw(SBI_PMU_FW_IPI_RECVD);
if (ipi_dev && ipi_dev->ipi_clear)
ipi_dev->ipi_clear(hartid);
sbi_ipi_raw_clear(hartindex);
ipi_type = atomic_raw_xchg_ulong(&ipi_data->ipi_type, 0);
ipi_event = 0;
while (ipi_type) {
if (ipi_type & 1UL) {
ipi_ops = ipi_ops_array[ipi_event];
if (ipi_ops && ipi_ops->process)
if (ipi_ops)
ipi_ops->process(scratch);
}
ipi_type = ipi_type >> 1;
@@ -233,19 +251,41 @@ void sbi_ipi_process(void)
}
}
int sbi_ipi_raw_send(u32 target_hart)
int sbi_ipi_raw_send(u32 hartindex)
{
if (!ipi_dev || !ipi_dev->ipi_send)
return SBI_EINVAL;
ipi_dev->ipi_send(target_hart);
/*
* Ensure that memory or MMIO writes done before
* this function are not observed after the memory
* or MMIO writes done by the ipi_send() device
* callback. This also allows the ipi_send() device
* callback to use relaxed MMIO writes.
*
* This pairs with the wmb() in sbi_ipi_raw_clear().
*/
wmb();
ipi_dev->ipi_send(hartindex);
return 0;
}
void sbi_ipi_raw_clear(u32 target_hart)
void sbi_ipi_raw_clear(u32 hartindex)
{
if (ipi_dev && ipi_dev->ipi_clear)
ipi_dev->ipi_clear(target_hart);
ipi_dev->ipi_clear(hartindex);
/*
* Ensure that memory or MMIO writes after this
* function returns are not observed before the
* memory or MMIO writes done by the ipi_clear()
* device callback. This also allows ipi_clear()
* device callback to use relaxed MMIO writes.
*
* This pairs with the wmb() in sbi_ipi_raw_send().
*/
wmb();
}
const struct sbi_ipi_device *sbi_ipi_get_device(void)

View File

@@ -211,16 +211,14 @@ int sbi_misaligned_store_handler(ulong addr, ulong tval2, ulong tinst,
} else if ((insn & INSN_MASK_C_SD) == INSN_MATCH_C_SD) {
len = 8;
val.data_ulong = GET_RS2S(insn, regs);
} else if ((insn & INSN_MASK_C_SDSP) == INSN_MATCH_C_SDSP &&
((insn >> SH_RD) & 0x1f)) {
} else if ((insn & INSN_MASK_C_SDSP) == INSN_MATCH_C_SDSP) {
len = 8;
val.data_ulong = GET_RS2C(insn, regs);
#endif
} else if ((insn & INSN_MASK_C_SW) == INSN_MATCH_C_SW) {
len = 4;
val.data_ulong = GET_RS2S(insn, regs);
} else if ((insn & INSN_MASK_C_SWSP) == INSN_MATCH_C_SWSP &&
((insn >> SH_RD) & 0x1f)) {
} else if ((insn & INSN_MASK_C_SWSP) == INSN_MATCH_C_SWSP) {
len = 4;
val.data_ulong = GET_RS2C(insn, regs);
#ifdef __riscv_flen

View File

@@ -71,20 +71,3 @@ done:
else
sbi_strncpy(features_str, "none", nfstr);
}
u32 sbi_platform_hart_index(const struct sbi_platform *plat, u32 hartid)
{
u32 i;
if (!plat)
return -1U;
if (plat->hart_index2id) {
for (i = 0; i < plat->hart_count; i++) {
if (plat->hart_index2id[i] == hartid)
return i;
}
return -1U;
}
return hartid;
}

View File

@@ -236,8 +236,7 @@ static int pmu_add_hw_event_map(u32 eidx_start, u32 eidx_end, u32 cmap,
bool is_overlap;
struct sbi_pmu_hw_event *event = &hw_event_map[num_hw_events];
struct sbi_scratch *scratch = sbi_scratch_thishart_ptr();
int hw_ctr_avail = sbi_hart_mhpm_count(scratch);
uint32_t ctr_avail_mask = ((uint32_t)(~0) >> (32 - (hw_ctr_avail + 3)));
uint32_t ctr_avail_mask = sbi_hart_mhpm_mask(scratch) | 0x7;
/* The first two counters are reserved by priv spec */
if (eidx_start > SBI_PMU_HW_INSTRUCTIONS && (cmap & SBI_PMU_FIXED_CTR_MASK))
@@ -354,8 +353,11 @@ static int pmu_ctr_start_hw(uint32_t cidx, uint64_t ival, bool ival_update)
if (cidx >= num_hw_ctrs || cidx == 1)
return SBI_EINVAL;
if (sbi_hart_priv_version(scratch) < SBI_HART_PRIV_VER_1_11)
goto skip_inhibit_update;
if (sbi_hart_priv_version(scratch) < SBI_HART_PRIV_VER_1_11) {
if (ival_update)
pmu_ctr_write_hw(cidx, ival);
return 0;
}
/*
* Some of the hardware may not support mcountinhibit but perf stat
@@ -369,13 +371,12 @@ static int pmu_ctr_start_hw(uint32_t cidx, uint64_t ival, bool ival_update)
if (sbi_hart_has_extension(scratch, SBI_HART_EXT_SSCOFPMF))
pmu_ctr_enable_irq_hw(cidx);
if (pmu_dev && pmu_dev->hw_counter_enable_irq)
pmu_dev->hw_counter_enable_irq(cidx);
csr_write(CSR_MCOUNTINHIBIT, mctr_inhbt);
skip_inhibit_update:
if (ival_update)
pmu_ctr_write_hw(cidx, ival);
if (pmu_dev && pmu_dev->hw_counter_enable_irq)
pmu_dev->hw_counter_enable_irq(cidx);
csr_write(CSR_MCOUNTINHIBIT, mctr_inhbt);
return 0;
}
@@ -441,10 +442,13 @@ int sbi_pmu_ctr_start(unsigned long cbase, unsigned long cmask,
if ((cbase + sbi_fls(cmask)) >= total_ctrs)
return ret;
if (flags & SBI_PMU_STOP_FLAG_TAKE_SNAPSHOT)
return SBI_ENO_SHMEM;
if (flags & SBI_PMU_START_FLAG_SET_INIT_VALUE)
bUpdate = true;
for_each_set_bit(i, &cmask, total_ctrs) {
for_each_set_bit(i, &cmask, BITS_PER_LONG) {
cidx = i + cbase;
event_idx_type = pmu_ctr_validate(phs, cidx, &event_code);
if (event_idx_type < 0)
@@ -481,6 +485,9 @@ static int pmu_ctr_stop_hw(uint32_t cidx)
if (!__test_bit(cidx, &mctr_inhbt)) {
__set_bit(cidx, &mctr_inhbt);
csr_write(CSR_MCOUNTINHIBIT, mctr_inhbt);
if (pmu_dev && pmu_dev->hw_counter_disable_irq) {
pmu_dev->hw_counter_disable_irq(cidx);
}
return 0;
} else
return SBI_EALREADY_STOPPED;
@@ -536,7 +543,10 @@ int sbi_pmu_ctr_stop(unsigned long cbase, unsigned long cmask,
if ((cbase + sbi_fls(cmask)) >= total_ctrs)
return SBI_EINVAL;
for_each_set_bit(i, &cmask, total_ctrs) {
if (flag & SBI_PMU_STOP_FLAG_TAKE_SNAPSHOT)
return SBI_ENO_SHMEM;
for_each_set_bit(i, &cmask, BITS_PER_LONG) {
cidx = i + cbase;
event_idx_type = pmu_ctr_validate(phs, cidx, &event_code);
if (event_idx_type < 0)
@@ -595,7 +605,10 @@ static int pmu_update_hw_mhpmevent(struct sbi_pmu_hw_event *hw_evt, int ctr_idx,
pmu_dev->hw_counter_disable_irq(ctr_idx);
/* Update the inhibit flags based on inhibit flags received from supervisor */
pmu_update_inhibit_flags(flags, &mhpmevent_val);
if (sbi_hart_has_extension(scratch, SBI_HART_EXT_SSCOFPMF))
pmu_update_inhibit_flags(flags, &mhpmevent_val);
if (pmu_dev && pmu_dev->hw_counter_filter_mode)
pmu_dev->hw_counter_filter_mode(flags, ctr_idx);
#if __riscv_xlen == 32
csr_write_num(CSR_MHPMEVENT3 + ctr_idx - 3, mhpmevent_val & 0xFFFFFFFF);
@@ -609,7 +622,50 @@ static int pmu_update_hw_mhpmevent(struct sbi_pmu_hw_event *hw_evt, int ctr_idx,
return 0;
}
static int pmu_ctr_find_fixed_fw(unsigned long evt_idx_code)
static int pmu_fixed_ctr_update_inhibit_bits(int fixed_ctr, unsigned long flags)
{
struct sbi_scratch *scratch = sbi_scratch_thishart_ptr();
uint64_t cfg_val = 0, cfg_csr_no;
#if __riscv_xlen == 32
uint64_t cfgh_csr_no;
#endif
if (!sbi_hart_has_extension(scratch, SBI_HART_EXT_SMCNTRPMF) &&
!(pmu_dev && pmu_dev->hw_counter_filter_mode))
return fixed_ctr;
switch (fixed_ctr) {
case 0:
cfg_csr_no = CSR_MCYCLECFG;
#if __riscv_xlen == 32
cfgh_csr_no = CSR_MCYCLECFGH;
#endif
break;
case 2:
cfg_csr_no = CSR_MINSTRETCFG;
#if __riscv_xlen == 32
cfgh_csr_no = CSR_MINSTRETCFGH;
#endif
break;
default:
return SBI_EFAIL;
}
cfg_val |= MHPMEVENT_MINH;
if (sbi_hart_has_extension(scratch, SBI_HART_EXT_SMCNTRPMF)) {
pmu_update_inhibit_flags(flags, &cfg_val);
#if __riscv_xlen == 32
csr_write_num(cfg_csr_no, cfg_val & 0xFFFFFFFF);
csr_write_num(cfgh_csr_no, cfg_val >> BITS_PER_LONG);
#else
csr_write_num(cfg_csr_no, cfg_val);
#endif
}
if (pmu_dev && pmu_dev->hw_counter_filter_mode)
pmu_dev->hw_counter_filter_mode(flags, fixed_ctr);
return fixed_ctr;
}
static int pmu_ctr_find_fixed_hw(unsigned long evt_idx_code)
{
/* Non-programmables counters are enabled always. No need to do lookup */
if (evt_idx_code == SBI_PMU_HW_CPU_CYCLES)
@@ -638,10 +694,10 @@ static int pmu_ctr_find_hw(struct sbi_pmu_hart_state *phs,
* If Sscof is present try to find the programmable counter for
* cycle/instret as well.
*/
fixed_ctr = pmu_ctr_find_fixed_fw(event_idx);
fixed_ctr = pmu_ctr_find_fixed_hw(event_idx);
if (fixed_ctr >= 0 &&
!sbi_hart_has_extension(scratch, SBI_HART_EXT_SSCOFPMF))
return fixed_ctr;
return pmu_fixed_ctr_update_inhibit_bits(fixed_ctr, flags);
if (sbi_hart_priv_version(scratch) >= SBI_HART_PRIV_VER_1_11)
mctr_inhbt = csr_read(CSR_MCOUNTINHIBIT);
@@ -684,7 +740,7 @@ static int pmu_ctr_find_hw(struct sbi_pmu_hart_state *phs,
* Return the fixed counter as they are mandatory anyways.
*/
if (fixed_ctr >= 0)
return fixed_ctr;
return pmu_fixed_ctr_update_inhibit_bits(fixed_ctr, flags);
else
return SBI_EFAIL;
}
@@ -843,13 +899,17 @@ int sbi_pmu_ctr_get_info(uint32_t cidx, unsigned long *ctr_info)
int width;
union sbi_pmu_ctr_info cinfo = {0};
struct sbi_scratch *scratch = sbi_scratch_thishart_ptr();
unsigned long counter_mask = (unsigned long)sbi_hart_mhpm_mask(scratch) |
SBI_PMU_CY_IR_MASK;
/* Sanity check. Counter1 is not mapped at all */
if (cidx >= total_ctrs || cidx == 1)
/* Sanity check */
if (cidx >= total_ctrs)
return SBI_EINVAL;
/* We have 31 HW counters with 31 being the last index(MHPMCOUNTER31) */
if (cidx < num_hw_ctrs) {
if (!(__test_bit(cidx, &counter_mask)))
return SBI_EINVAL;
cinfo.type = SBI_PMU_CTR_TYPE_HW;
cinfo.csr = CSR_CYCLE + cidx;
/* mcycle & minstret are always 64 bit */
@@ -912,8 +972,10 @@ void sbi_pmu_exit(struct sbi_scratch *scratch)
int sbi_pmu_init(struct sbi_scratch *scratch, bool cold_boot)
{
int hpm_count = sbi_fls(sbi_hart_mhpm_mask(scratch));
struct sbi_pmu_hart_state *phs;
const struct sbi_platform *plat;
int rc;
if (cold_boot) {
hw_event_map = sbi_calloc(sizeof(*hw_event_map),
@@ -929,12 +991,21 @@ int sbi_pmu_init(struct sbi_scratch *scratch, bool cold_boot)
plat = sbi_platform_ptr(scratch);
/* Initialize hw pmu events */
sbi_platform_pmu_init(plat);
rc = sbi_platform_pmu_init(plat);
if (rc)
sbi_dprintf("%s: platform pmu init failed "
"(error %d)\n", __func__, rc);
/* mcycle & minstret is available always */
num_hw_ctrs = sbi_hart_mhpm_count(scratch) + 3;
if (!hpm_count)
/* Only CY, TM & IR are implemented in the hw */
num_hw_ctrs = 3;
else
num_hw_ctrs = hpm_count + 1;
if (num_hw_ctrs > SBI_PMU_HW_CTR_MAX)
return SBI_EINVAL;
total_ctrs = num_hw_ctrs + SBI_PMU_FW_CTR_MAX;
}

View File

@@ -14,29 +14,40 @@
#include <sbi/sbi_scratch.h>
#include <sbi/sbi_string.h>
u32 last_hartid_having_scratch = SBI_HARTMASK_MAX_BITS - 1;
struct sbi_scratch *hartid_to_scratch_table[SBI_HARTMASK_MAX_BITS] = { 0 };
u32 last_hartindex_having_scratch = 0;
u32 hartindex_to_hartid_table[SBI_HARTMASK_MAX_BITS + 1] = { -1U };
struct sbi_scratch *hartindex_to_scratch_table[SBI_HARTMASK_MAX_BITS + 1] = { 0 };
static spinlock_t extra_lock = SPIN_LOCK_INITIALIZER;
static unsigned long extra_offset = SBI_SCRATCH_EXTRA_SPACE_OFFSET;
u32 sbi_hartid_to_hartindex(u32 hartid)
{
u32 i;
for (i = 0; i <= last_hartindex_having_scratch; i++)
if (hartindex_to_hartid_table[i] == hartid)
return i;
return -1U;
}
typedef struct sbi_scratch *(*hartid2scratch)(ulong hartid, ulong hartindex);
int sbi_scratch_init(struct sbi_scratch *scratch)
{
u32 i;
u32 i, h;
const struct sbi_platform *plat = sbi_platform_ptr(scratch);
for (i = 0; i < SBI_HARTMASK_MAX_BITS; i++) {
if (sbi_platform_hart_invalid(plat, i))
continue;
hartid_to_scratch_table[i] =
((hartid2scratch)scratch->hartid_to_scratch)(i,
sbi_platform_hart_index(plat, i));
if (hartid_to_scratch_table[i])
last_hartid_having_scratch = i;
for (i = 0; i < plat->hart_count; i++) {
h = (plat->hart_index2id) ? plat->hart_index2id[i] : i;
hartindex_to_hartid_table[i] = h;
hartindex_to_scratch_table[i] =
((hartid2scratch)scratch->hartid_to_scratch)(h, i);
}
last_hartindex_having_scratch = plat->hart_count - 1;
return 0;
}
@@ -74,8 +85,8 @@ done:
spin_unlock(&extra_lock);
if (ret) {
for (i = 0; i <= sbi_scratch_last_hartid(); i++) {
rscratch = sbi_hartid_to_scratch(i);
for (i = 0; i <= sbi_scratch_last_hartindex(); i++) {
rscratch = sbi_hartindex_to_scratch(i);
if (!rscratch)
continue;
ptr = sbi_scratch_offset_ptr(rscratch, ret);

View File

@@ -72,7 +72,8 @@ void __noreturn sbi_system_reset(u32 reset_type, u32 reset_reason)
/* Send HALT IPI to every hart other than the current hart */
while (!sbi_hsm_hart_interruptible_mask(dom, hbase, &hmask)) {
if (hbase <= cur_hartid)
if ((hbase <= cur_hartid)
&& (cur_hartid < hbase + BITS_PER_LONG))
hmask &= ~(1UL << (cur_hartid - hbase));
if (hmask)
sbi_ipi_send_halt(hmask, hbase);
@@ -152,7 +153,7 @@ int sbi_system_suspend(u32 sleep_type, ulong resume_addr, ulong opaque)
void (*jump_warmboot)(void) = (void (*)(void))scratch->warmboot_addr;
unsigned int hartid = current_hartid();
unsigned long prev_mode;
unsigned long i;
unsigned long i, j;
int ret;
if (!dom || !dom->system_suspend_allowed)
@@ -170,11 +171,12 @@ int sbi_system_suspend(u32 sleep_type, ulong resume_addr, ulong opaque)
if (prev_mode != PRV_S && prev_mode != PRV_U)
return SBI_EFAIL;
sbi_hartmask_for_each_hart(i, &dom->assigned_harts) {
sbi_hartmask_for_each_hartindex(j, &dom->assigned_harts) {
i = sbi_hartindex_to_hartid(j);
if (i == hartid)
continue;
if (__sbi_hsm_hart_get_state(i) != SBI_HSM_STATE_STOPPED)
return SBI_EFAIL;
return SBI_ERR_DENIED;
}
if (!sbi_domain_check_addr(dom, resume_addr, prev_mode,

View File

@@ -188,7 +188,7 @@ int sbi_timer_init(struct sbi_scratch *scratch, bool cold_boot)
if (!time_delta_off)
return SBI_ENOMEM;
if (sbi_hart_has_extension(scratch, SBI_HART_EXT_TIME))
if (sbi_hart_has_extension(scratch, SBI_HART_EXT_ZICNTR))
get_time_val = get_ticks;
} else {
if (!time_delta_off)

View File

@@ -14,6 +14,7 @@
#include <sbi/sbi_error.h>
#include <sbi/sbi_fifo.h>
#include <sbi/sbi_hart.h>
#include <sbi/sbi_heap.h>
#include <sbi/sbi_ipi.h>
#include <sbi/sbi_scratch.h>
#include <sbi/sbi_tlb.h>
@@ -33,7 +34,7 @@ static void tlb_flush_all(void)
__asm__ __volatile("sfence.vma");
}
void sbi_tlb_local_hfence_vvma(struct sbi_tlb_info *tinfo)
static void sbi_tlb_local_hfence_vvma(struct sbi_tlb_info *tinfo)
{
unsigned long start = tinfo->start;
unsigned long size = tinfo->size;
@@ -58,7 +59,7 @@ done:
csr_write(CSR_HGATP, hgatp);
}
void sbi_tlb_local_hfence_gvma(struct sbi_tlb_info *tinfo)
static void sbi_tlb_local_hfence_gvma(struct sbi_tlb_info *tinfo)
{
unsigned long start = tinfo->start;
unsigned long size = tinfo->size;
@@ -76,7 +77,7 @@ void sbi_tlb_local_hfence_gvma(struct sbi_tlb_info *tinfo)
}
}
void sbi_tlb_local_sfence_vma(struct sbi_tlb_info *tinfo)
static void sbi_tlb_local_sfence_vma(struct sbi_tlb_info *tinfo)
{
unsigned long start = tinfo->start;
unsigned long size = tinfo->size;
@@ -97,7 +98,7 @@ void sbi_tlb_local_sfence_vma(struct sbi_tlb_info *tinfo)
}
}
void sbi_tlb_local_hfence_vvma_asid(struct sbi_tlb_info *tinfo)
static void sbi_tlb_local_hfence_vvma_asid(struct sbi_tlb_info *tinfo)
{
unsigned long start = tinfo->start;
unsigned long size = tinfo->size;
@@ -110,12 +111,7 @@ void sbi_tlb_local_hfence_vvma_asid(struct sbi_tlb_info *tinfo)
hgatp = csr_swap(CSR_HGATP,
(vmid << HGATP_VMID_SHIFT) & HGATP_VMID_MASK);
if (start == 0 && size == 0) {
__sbi_hfence_vvma_all();
goto done;
}
if (size == SBI_TLB_FLUSH_ALL) {
if ((start == 0 && size == 0) || (size == SBI_TLB_FLUSH_ALL)) {
__sbi_hfence_vvma_asid(asid);
goto done;
}
@@ -128,7 +124,7 @@ done:
csr_write(CSR_HGATP, hgatp);
}
void sbi_tlb_local_hfence_gvma_vmid(struct sbi_tlb_info *tinfo)
static void sbi_tlb_local_hfence_gvma_vmid(struct sbi_tlb_info *tinfo)
{
unsigned long start = tinfo->start;
unsigned long size = tinfo->size;
@@ -137,12 +133,7 @@ void sbi_tlb_local_hfence_gvma_vmid(struct sbi_tlb_info *tinfo)
sbi_pmu_ctr_incr_fw(SBI_PMU_FW_HFENCE_GVMA_VMID_RCVD);
if (start == 0 && size == 0) {
__sbi_hfence_gvma_all();
return;
}
if (size == SBI_TLB_FLUSH_ALL) {
if ((start == 0 && size == 0) || (size == SBI_TLB_FLUSH_ALL)) {
__sbi_hfence_gvma_vmid(vmid);
return;
}
@@ -152,7 +143,7 @@ void sbi_tlb_local_hfence_gvma_vmid(struct sbi_tlb_info *tinfo)
}
}
void sbi_tlb_local_sfence_vma_asid(struct sbi_tlb_info *tinfo)
static void sbi_tlb_local_sfence_vma_asid(struct sbi_tlb_info *tinfo)
{
unsigned long start = tinfo->start;
unsigned long size = tinfo->size;
@@ -161,13 +152,8 @@ void sbi_tlb_local_sfence_vma_asid(struct sbi_tlb_info *tinfo)
sbi_pmu_ctr_incr_fw(SBI_PMU_FW_SFENCE_VMA_ASID_RCVD);
if (start == 0 && size == 0) {
tlb_flush_all();
return;
}
/* Flush entire MM context for a given ASID */
if (size == SBI_TLB_FLUSH_ALL) {
if ((start == 0 && size == 0) || (size == SBI_TLB_FLUSH_ALL)) {
__asm__ __volatile__("sfence.vma x0, %0"
:
: "r"(asid)
@@ -183,44 +169,55 @@ void sbi_tlb_local_sfence_vma_asid(struct sbi_tlb_info *tinfo)
}
}
void sbi_tlb_local_fence_i(struct sbi_tlb_info *tinfo)
static void sbi_tlb_local_fence_i(struct sbi_tlb_info *tinfo)
{
sbi_pmu_ctr_incr_fw(SBI_PMU_FW_FENCE_I_RECVD);
__asm__ __volatile("fence.i");
}
static void tlb_pmu_incr_fw_ctr(struct sbi_tlb_info *data)
static void tlb_entry_local_process(struct sbi_tlb_info *data)
{
if (unlikely(!data))
return;
if (data->local_fn == sbi_tlb_local_fence_i)
sbi_pmu_ctr_incr_fw(SBI_PMU_FW_FENCE_I_SENT);
else if (data->local_fn == sbi_tlb_local_sfence_vma)
sbi_pmu_ctr_incr_fw(SBI_PMU_FW_SFENCE_VMA_SENT);
else if (data->local_fn == sbi_tlb_local_sfence_vma_asid)
sbi_pmu_ctr_incr_fw(SBI_PMU_FW_SFENCE_VMA_ASID_SENT);
else if (data->local_fn == sbi_tlb_local_hfence_gvma)
sbi_pmu_ctr_incr_fw(SBI_PMU_FW_HFENCE_GVMA_SENT);
else if (data->local_fn == sbi_tlb_local_hfence_gvma_vmid)
sbi_pmu_ctr_incr_fw(SBI_PMU_FW_HFENCE_GVMA_VMID_SENT);
else if (data->local_fn == sbi_tlb_local_hfence_vvma)
sbi_pmu_ctr_incr_fw(SBI_PMU_FW_HFENCE_VVMA_SENT);
else if (data->local_fn == sbi_tlb_local_hfence_vvma_asid)
sbi_pmu_ctr_incr_fw(SBI_PMU_FW_HFENCE_VVMA_ASID_SENT);
switch (data->type) {
case SBI_TLB_FENCE_I:
sbi_tlb_local_fence_i(data);
break;
case SBI_TLB_SFENCE_VMA:
sbi_tlb_local_sfence_vma(data);
break;
case SBI_TLB_SFENCE_VMA_ASID:
sbi_tlb_local_sfence_vma_asid(data);
break;
case SBI_TLB_HFENCE_GVMA_VMID:
sbi_tlb_local_hfence_gvma_vmid(data);
break;
case SBI_TLB_HFENCE_GVMA:
sbi_tlb_local_hfence_gvma(data);
break;
case SBI_TLB_HFENCE_VVMA_ASID:
sbi_tlb_local_hfence_vvma_asid(data);
break;
case SBI_TLB_HFENCE_VVMA:
sbi_tlb_local_hfence_vvma(data);
break;
default:
break;
};
}
static void tlb_entry_process(struct sbi_tlb_info *tinfo)
{
u32 rhartid;
u32 rindex;
struct sbi_scratch *rscratch = NULL;
atomic_t *rtlb_sync = NULL;
tinfo->local_fn(tinfo);
tlb_entry_local_process(tinfo);
sbi_hartmask_for_each_hart(rhartid, &tinfo->smask) {
rscratch = sbi_hartid_to_scratch(rhartid);
sbi_hartmask_for_each_hartindex(rindex, &tinfo->smask) {
rscratch = sbi_hartindex_to_scratch(rindex);
if (!rscratch)
continue;
@@ -319,12 +316,12 @@ static int tlb_update_cb(void *in, void *data)
curr = (struct sbi_tlb_info *)data;
next = (struct sbi_tlb_info *)in;
if (next->local_fn == sbi_tlb_local_sfence_vma_asid &&
curr->local_fn == sbi_tlb_local_sfence_vma_asid) {
if (next->type == SBI_TLB_SFENCE_VMA_ASID &&
curr->type == SBI_TLB_SFENCE_VMA_ASID) {
if (next->asid == curr->asid)
ret = tlb_range_check(curr, next);
} else if (next->local_fn == sbi_tlb_local_sfence_vma &&
curr->local_fn == sbi_tlb_local_sfence_vma) {
} else if (next->type == SBI_TLB_SFENCE_VMA &&
curr->type == SBI_TLB_SFENCE_VMA) {
ret = tlb_range_check(curr, next);
}
@@ -333,7 +330,7 @@ static int tlb_update_cb(void *in, void *data)
static int tlb_update(struct sbi_scratch *scratch,
struct sbi_scratch *remote_scratch,
u32 remote_hartid, void *data)
u32 remote_hartindex, void *data)
{
int ret;
atomic_t *tlb_sync;
@@ -341,22 +338,12 @@ static int tlb_update(struct sbi_scratch *scratch,
struct sbi_tlb_info *tinfo = data;
u32 curr_hartid = current_hartid();
/*
* If address range to flush is too big then simply
* upgrade it to flush all because we can only flush
* 4KB at a time.
*/
if (tinfo->size > tlb_range_flush_limit) {
tinfo->start = 0;
tinfo->size = SBI_TLB_FLUSH_ALL;
}
/*
* If the request is to queue a tlb flush entry for itself
* then just do a local flush and return;
*/
if (remote_hartid == curr_hartid) {
tinfo->local_fn(tinfo);
if (sbi_hartindex_to_hartid(remote_hartindex) == curr_hartid) {
tlb_entry_local_process(tinfo);
return SBI_IPI_UPDATE_BREAK;
}
@@ -374,8 +361,8 @@ static int tlb_update(struct sbi_scratch *scratch,
* this properly.
*/
tlb_process_once(scratch);
sbi_dprintf("hart%d: hart%d tlb fifo full\n",
curr_hartid, remote_hartid);
sbi_dprintf("hart%d: hart%d tlb fifo full\n", curr_hartid,
sbi_hartindex_to_hartid(remote_hartindex));
return SBI_IPI_UPDATE_RETRY;
}
@@ -394,12 +381,32 @@ static struct sbi_ipi_event_ops tlb_ops = {
static u32 tlb_event = SBI_IPI_EVENT_MAX;
static const u32 tlb_type_to_pmu_fw_event[SBI_TLB_TYPE_MAX] = {
[SBI_TLB_FENCE_I] = SBI_PMU_FW_FENCE_I_SENT,
[SBI_TLB_SFENCE_VMA] = SBI_PMU_FW_SFENCE_VMA_SENT,
[SBI_TLB_SFENCE_VMA_ASID] = SBI_PMU_FW_SFENCE_VMA_ASID_SENT,
[SBI_TLB_HFENCE_GVMA_VMID] = SBI_PMU_FW_HFENCE_GVMA_VMID_SENT,
[SBI_TLB_HFENCE_GVMA] = SBI_PMU_FW_HFENCE_GVMA_SENT,
[SBI_TLB_HFENCE_VVMA_ASID] = SBI_PMU_FW_HFENCE_VVMA_ASID_SENT,
[SBI_TLB_HFENCE_VVMA] = SBI_PMU_FW_HFENCE_VVMA_SENT,
};
int sbi_tlb_request(ulong hmask, ulong hbase, struct sbi_tlb_info *tinfo)
{
if (!tinfo->local_fn)
if (tinfo->type < 0 || tinfo->type >= SBI_TLB_TYPE_MAX)
return SBI_EINVAL;
tlb_pmu_incr_fw_ctr(tinfo);
/*
* If address range to flush is too big then simply
* upgrade it to flush all because we can only flush
* 4KB at a time.
*/
if (tinfo->size > tlb_range_flush_limit) {
tinfo->start = 0;
tinfo->size = SBI_TLB_FLUSH_ALL;
}
sbi_pmu_ctr_incr_fw(tlb_type_to_pmu_fw_event[tinfo->type]);
return sbi_ipi_send_many(hmask, hbase, tlb_event, tinfo);
}
@@ -421,8 +428,7 @@ int sbi_tlb_init(struct sbi_scratch *scratch, bool cold_boot)
sbi_scratch_free_offset(tlb_sync_off);
return SBI_ENOMEM;
}
tlb_fifo_mem_off = sbi_scratch_alloc_offset(
SBI_TLB_FIFO_NUM_ENTRIES * SBI_TLB_INFO_SIZE);
tlb_fifo_mem_off = sbi_scratch_alloc_offset(sizeof(tlb_mem));
if (!tlb_fifo_mem_off) {
sbi_scratch_free_offset(tlb_fifo_off);
sbi_scratch_free_offset(tlb_sync_off);
@@ -448,12 +454,19 @@ int sbi_tlb_init(struct sbi_scratch *scratch, bool cold_boot)
tlb_sync = sbi_scratch_offset_ptr(scratch, tlb_sync_off);
tlb_q = sbi_scratch_offset_ptr(scratch, tlb_fifo_off);
tlb_mem = sbi_scratch_offset_ptr(scratch, tlb_fifo_mem_off);
tlb_mem = sbi_scratch_read_type(scratch, void *, tlb_fifo_mem_off);
if (!tlb_mem) {
tlb_mem = sbi_malloc(
sbi_platform_tlb_fifo_num_entries(plat) * SBI_TLB_INFO_SIZE);
if (!tlb_mem)
return SBI_ENOMEM;
sbi_scratch_write_type(scratch, void *, tlb_fifo_mem_off, tlb_mem);
}
ATOMIC_INIT(tlb_sync, 0);
sbi_fifo_init(tlb_q, tlb_mem,
SBI_TLB_FIFO_NUM_ENTRIES, SBI_TLB_INFO_SIZE);
sbi_platform_tlb_fifo_num_entries(plat), SBI_TLB_INFO_SIZE);
return 0;
}

View File

@@ -14,6 +14,8 @@ source "$(OPENSBI_SRC_DIR)/lib/utils/irqchip/Kconfig"
source "$(OPENSBI_SRC_DIR)/lib/utils/libfdt/Kconfig"
source "$(OPENSBI_SRC_DIR)/lib/utils/regmap/Kconfig"
source "$(OPENSBI_SRC_DIR)/lib/utils/reset/Kconfig"
source "$(OPENSBI_SRC_DIR)/lib/utils/serial/Kconfig"

View File

@@ -15,4 +15,11 @@ config FDT_PMU
bool "FDT performance monitoring unit (PMU) support"
default n
config FDT_FIXUPS_PRESERVE_PMU_NODE
bool "Preserve PMU node in device-tree"
depends on FDT_PMU
default n
help
Preserve PMU node properties for debugging purposes.
endif

View File

@@ -342,7 +342,7 @@ static int __fdt_parse_domain(void *fdt, int domain_offset, void *opaque)
if (!fdt_node_is_enabled(fdt, cpu_offset))
continue;
sbi_hartmask_set_hart(val32, mask);
sbi_hartmask_set_hartid(val32, mask);
}
}
@@ -472,7 +472,7 @@ static int __fdt_parse_domain(void *fdt, int domain_offset, void *opaque)
}
if (doffset == domain_offset)
sbi_hartmask_set_hart(val32, &assign_mask);
sbi_hartmask_set_hartid(val32, &assign_mask);
}
/* Register the domain */

View File

@@ -394,5 +394,8 @@ void fdt_fixups(void *fdt)
fdt_plic_fixup(fdt);
fdt_reserved_memory_fixup(fdt);
#ifndef CONFIG_FDT_FIXUPS_PRESERVE_PMU_NODE
fdt_pmu_fixup(fdt);
#endif
}

View File

@@ -12,6 +12,7 @@
#include <sbi/sbi_hartmask.h>
#include <sbi/sbi_platform.h>
#include <sbi/sbi_scratch.h>
#include <sbi/sbi_hart.h>
#include <sbi_utils/fdt/fdt_helper.h>
#include <sbi_utils/irqchip/aplic.h>
#include <sbi_utils/irqchip/imsic.h>
@@ -215,6 +216,32 @@ int fdt_get_node_addr_size(void *fdt, int node, int index,
return 0;
}
int fdt_get_node_addr_size_by_name(void *fdt, int node, const char *name,
uint64_t *addr, uint64_t *size)
{
int i, j, count;
const char *val;
const char *regname;
if (!fdt || node < 0 || !name)
return SBI_EINVAL;
val = fdt_getprop(fdt, node, "reg-names", &count);
if (!val)
return SBI_ENODEV;
for (i = 0, j = 0; i < count; i++, j++) {
regname = val + i;
if (strcmp(name, regname) == 0)
return fdt_get_node_addr_size(fdt, node, j, addr, size);
i += strlen(regname);
}
return SBI_ENODEV;
}
bool fdt_node_is_enabled(void *fdt, int nodeoff)
{
int len;
@@ -313,6 +340,149 @@ int fdt_parse_timebase_frequency(void *fdt, unsigned long *freq)
return 0;
}
#define RISCV_ISA_EXT_NAME_LEN_MAX 32
static unsigned long fdt_isa_bitmap_offset;
static int fdt_parse_isa_one_hart(const char *isa, unsigned long *extensions)
{
size_t i, j, isa_len;
char mstr[RISCV_ISA_EXT_NAME_LEN_MAX];
i = 0;
isa_len = strlen(isa);
if (isa[i] == 'r' || isa[i] == 'R')
i++;
else
return SBI_EINVAL;
if (isa[i] == 'v' || isa[i] == 'V')
i++;
else
return SBI_EINVAL;
if (isa[i] == '3' || isa[i+1] == '2')
i += 2;
else if (isa[i] == '6' || isa[i+1] == '4')
i += 2;
else
return SBI_EINVAL;
/* Skip base ISA extensions */
for (; i < isa_len; i++) {
if (isa[i] == '_')
break;
}
while (i < isa_len) {
if (isa[i] != '_') {
i++;
continue;
}
/* Skip the '_' character */
i++;
/* Extract the multi-letter extension name */
j = 0;
while ((i < isa_len) && (isa[i] != '_') &&
(j < (sizeof(mstr) - 1)))
mstr[j++] = isa[i++];
mstr[j] = '\0';
/* Skip empty multi-letter extension name */
if (!j)
continue;
#define set_multi_letter_ext(name, bit) \
if (!strcmp(mstr, name)) { \
__set_bit(bit, extensions); \
continue; \
}
for (j = 0; j < SBI_HART_EXT_MAX; j++) {
set_multi_letter_ext(sbi_hart_ext[j].name,
sbi_hart_ext[j].id);
}
#undef set_multi_letter_ext
}
return 0;
}
static int fdt_parse_isa_all_harts(void *fdt)
{
u32 hartid;
const fdt32_t *val;
unsigned long *hart_exts;
struct sbi_scratch *scratch;
int err, cpu_offset, cpus_offset, len;
if (!fdt || !fdt_isa_bitmap_offset)
return SBI_EINVAL;
cpus_offset = fdt_path_offset(fdt, "/cpus");
if (cpus_offset < 0)
return cpus_offset;
fdt_for_each_subnode(cpu_offset, fdt, cpus_offset) {
err = fdt_parse_hart_id(fdt, cpu_offset, &hartid);
if (err)
continue;
if (!fdt_node_is_enabled(fdt, cpu_offset))
continue;
val = fdt_getprop(fdt, cpu_offset, "riscv,isa", &len);
if (!val || len <= 0)
return SBI_ENOENT;
scratch = sbi_hartid_to_scratch(hartid);
if (!scratch)
return SBI_ENOENT;
hart_exts = sbi_scratch_offset_ptr(scratch,
fdt_isa_bitmap_offset);
err = fdt_parse_isa_one_hart((const char *)val, hart_exts);
if (err)
return err;
}
return 0;
}
int fdt_parse_isa_extensions(void *fdt, unsigned int hartid,
unsigned long *extensions)
{
int rc, i;
unsigned long *hart_exts;
struct sbi_scratch *scratch;
if (!fdt_isa_bitmap_offset) {
fdt_isa_bitmap_offset = sbi_scratch_alloc_offset(
sizeof(*hart_exts) *
BITS_TO_LONGS(SBI_HART_EXT_MAX));
if (!fdt_isa_bitmap_offset)
return SBI_ENOMEM;
rc = fdt_parse_isa_all_harts(fdt);
if (rc)
return rc;
}
scratch = sbi_hartid_to_scratch(hartid);
if (!scratch)
return SBI_ENOENT;
hart_exts = sbi_scratch_offset_ptr(scratch, fdt_isa_bitmap_offset);
for (i = 0; i < BITS_TO_LONGS(SBI_HART_EXT_MAX); i++)
extensions[i] |= hart_exts[i];
return 0;
}
static int fdt_parse_uart_node_common(void *fdt, int nodeoffset,
struct platform_uart_data *uart,
unsigned long default_freq,
@@ -710,6 +880,7 @@ int fdt_parse_plic_node(void *fdt, int nodeoffset, struct plic_data *plic)
if (rc < 0 || !reg_addr || !reg_size)
return SBI_ENODEV;
plic->addr = reg_addr;
plic->size = reg_size;
val = fdt_getprop(fdt, nodeoffset, "riscv,ndev", &len);
if (len > 0)
@@ -732,21 +903,40 @@ int fdt_parse_plic(void *fdt, struct plic_data *plic, const char *compat)
return fdt_parse_plic_node(fdt, nodeoffset, plic);
}
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)
static int fdt_get_aclint_addr_size_by_name(void *fdt, int nodeoffset,
unsigned long *out_addr1,
unsigned long *out_size1,
unsigned long *out_addr2,
unsigned long *out_size2)
{
const fdt32_t *val;
int rc;
uint64_t reg_addr, reg_size;
int i, rc, count, cpu_offset, cpu_intc_offset;
u32 phandle, hwirq, hartid, first_hartid, last_hartid, hart_count;
u32 match_hwirq = (for_timer) ? IRQ_M_TIMER : IRQ_M_SOFT;
if (nodeoffset < 0 || !fdt ||
!out_addr1 || !out_size1 ||
!out_first_hartid || !out_hart_count)
return SBI_EINVAL;
rc = fdt_get_node_addr_size_by_name(fdt, nodeoffset, "mtime",
&reg_addr, &reg_size);
if (rc < 0 || !reg_size)
reg_addr = reg_size = 0;
*out_addr1 = reg_addr;
*out_size1 = reg_size;
rc = fdt_get_node_addr_size_by_name(fdt, nodeoffset, "mtimecmp",
&reg_addr, &reg_size);
if (rc < 0 || !reg_size)
return SBI_ENODEV;
*out_addr2 = reg_addr;
*out_size2 = reg_size;
return 0;
}
static int fdt_get_aclint_addr_size(void *fdt, int nodeoffset,
unsigned long *out_addr1,
unsigned long *out_size1,
unsigned long *out_addr2,
unsigned long *out_size2)
{
int rc;
uint64_t reg_addr, reg_size;
rc = fdt_get_node_addr_size(fdt, nodeoffset, 0,
&reg_addr, &reg_size);
@@ -764,6 +954,37 @@ int fdt_parse_aclint_node(void *fdt, int nodeoffset, bool for_timer,
if (out_size2)
*out_size2 = reg_size;
return 0;
}
int fdt_parse_aclint_node(void *fdt, int nodeoffset,
bool for_timer, bool allow_regname,
unsigned long *out_addr1, unsigned long *out_size1,
unsigned long *out_addr2, unsigned long *out_size2,
u32 *out_first_hartid, u32 *out_hart_count)
{
const fdt32_t *val;
int i, rc, count, cpu_offset, cpu_intc_offset;
u32 phandle, hwirq, hartid, first_hartid, last_hartid, hart_count;
u32 match_hwirq = (for_timer) ? IRQ_M_TIMER : IRQ_M_SOFT;
if (nodeoffset < 0 || !fdt ||
!out_addr1 || !out_size1 ||
!out_first_hartid || !out_hart_count)
return SBI_EINVAL;
if (for_timer && allow_regname && out_addr2 && out_size2 &&
fdt_getprop(fdt, nodeoffset, "reg-names", NULL))
rc = fdt_get_aclint_addr_size_by_name(fdt, nodeoffset,
out_addr1, out_size1,
out_addr2, out_size2);
else
rc = fdt_get_aclint_addr_size(fdt, nodeoffset,
out_addr1, out_size1,
out_addr2, out_size2);
if (rc)
return rc;
*out_first_hartid = 0;
*out_hart_count = 0;

View File

@@ -14,23 +14,19 @@
#include <sbi/sbi_pmu.h>
#include <sbi/sbi_scratch.h>
#include <sbi_utils/fdt/fdt_helper.h>
#include <sbi_utils/fdt/fdt_pmu.h>
#define FDT_PMU_HW_EVENT_MAX (SBI_PMU_HW_EVENT_MAX * 2)
struct fdt_pmu_hw_event_select {
uint32_t eidx;
uint64_t select;
};
static struct fdt_pmu_hw_event_select fdt_pmu_evt_select[FDT_PMU_HW_EVENT_MAX] = {0};
static uint32_t hw_event_count;
struct fdt_pmu_hw_event_select_map fdt_pmu_evt_select[FDT_PMU_HW_EVENT_MAX] = {0};
uint32_t hw_event_count;
uint64_t fdt_pmu_get_select_value(uint32_t event_idx)
{
int i;
struct fdt_pmu_hw_event_select *event;
struct fdt_pmu_hw_event_select_map *event;
for (i = 0; i < SBI_PMU_HW_EVENT_MAX; i++) {
for (i = 0; i < hw_event_count; i++) {
event = &fdt_pmu_evt_select[i];
if (event->eidx == event_idx)
return event->select;
@@ -65,7 +61,7 @@ int fdt_pmu_setup(void *fdt)
int i, pmu_offset, len, result;
const u32 *event_val;
const u32 *event_ctr_map;
struct fdt_pmu_hw_event_select *event;
struct fdt_pmu_hw_event_select_map *event;
uint64_t raw_selector, select_mask;
u32 event_idx_start, event_idx_end, ctr_map;
@@ -74,7 +70,7 @@ int fdt_pmu_setup(void *fdt)
pmu_offset = fdt_node_offset_by_compatible(fdt, -1, "riscv,pmu");
if (pmu_offset < 0)
return SBI_EFAIL;
return SBI_ENOENT;
event_ctr_map = fdt_getprop(fdt, pmu_offset,
"riscv,event-to-mhpmcounters", &len);

View File

@@ -112,8 +112,8 @@ static int dw_gpio_init_bank(void *fdt, int nodeoff, u32 phandle,
chip = &dw_gpio_chip_array[dw_gpio_chip_count];
chip->dr = (void *)addr + (bank * 0xc);
chip->ext = (void *)addr + (bank * 4) + 0x50;
chip->dr = (void *)(uintptr_t)addr + (bank * 0xc);
chip->ext = (void *)(uintptr_t)addr + (bank * 4) + 0x50;
chip->chip.driver = &fdt_gpio_designware;
chip->chip.id = phandle;
chip->chip.ngpio = nr_pins;

View File

@@ -37,7 +37,6 @@ static int starfive_gpio_direction_output(struct gpio_pin *gp, int value)
reg_addr = chip->addr + gp->offset;
reg_addr &= ~(STARFIVE_GPIO_REG_SHIFT_MASK);
val = readl((void *)(reg_addr));
shift_bits = (gp->offset & STARFIVE_GPIO_REG_SHIFT_MASK)
<< STARFIVE_GPIO_SHIFT_BITS;
bit_mask = STARFIVE_GPIO_MASK << shift_bits;

View File

@@ -15,8 +15,6 @@
#include <sbi_utils/i2c/dw_i2c.h>
#include <sbi_utils/i2c/fdt_i2c.h>
extern struct fdt_i2c_adapter fdt_i2c_adapter_dw;
static int fdt_dw_i2c_init(void *fdt, int nodeoff,
const struct fdt_match *match)
{
@@ -35,7 +33,6 @@ static int fdt_dw_i2c_init(void *fdt, int nodeoff,
}
adapter->addr = addr;
adapter->adapter.driver = &fdt_i2c_adapter_dw;
rc = dw_i2c_init(&adapter->adapter, nodeoff);
if (rc) {

View File

@@ -46,8 +46,6 @@ struct sifive_i2c_adapter {
struct i2c_adapter adapter;
};
extern struct fdt_i2c_adapter fdt_i2c_adapter_sifive;
static inline void sifive_i2c_setreg(struct sifive_i2c_adapter *adap,
uint8_t reg, uint8_t value)
{
@@ -250,7 +248,6 @@ static int sifive_i2c_init(void *fdt, int nodeoff,
}
adapter->addr = addr;
adapter->adapter.driver = &fdt_i2c_adapter_sifive;
adapter->adapter.id = nodeoff;
adapter->adapter.write = sifive_i2c_adapter_write;
adapter->adapter.read = sifive_i2c_adapter_read;

View File

@@ -25,13 +25,13 @@ static unsigned long mswi_ptr_offset;
#define mswi_set_hart_data_ptr(__scratch, __mswi) \
sbi_scratch_write_type((__scratch), void *, mswi_ptr_offset, (__mswi))
static void mswi_ipi_send(u32 target_hart)
static void mswi_ipi_send(u32 hart_index)
{
u32 *msip;
struct sbi_scratch *scratch;
struct aclint_mswi_data *mswi;
scratch = sbi_hartid_to_scratch(target_hart);
scratch = sbi_hartindex_to_scratch(hart_index);
if (!scratch)
return;
@@ -41,16 +41,17 @@ static void mswi_ipi_send(u32 target_hart)
/* Set ACLINT IPI */
msip = (void *)mswi->addr;
writel(1, &msip[target_hart - mswi->first_hartid]);
writel_relaxed(1, &msip[sbi_hartindex_to_hartid(hart_index) -
mswi->first_hartid]);
}
static void mswi_ipi_clear(u32 target_hart)
static void mswi_ipi_clear(u32 hart_index)
{
u32 *msip;
struct sbi_scratch *scratch;
struct aclint_mswi_data *mswi;
scratch = sbi_hartid_to_scratch(target_hart);
scratch = sbi_hartindex_to_scratch(hart_index);
if (!scratch)
return;
@@ -60,7 +61,8 @@ static void mswi_ipi_clear(u32 target_hart)
/* Clear ACLINT IPI */
msip = (void *)mswi->addr;
writel(0, &msip[target_hart - mswi->first_hartid]);
writel_relaxed(0, &msip[sbi_hartindex_to_hartid(hart_index) -
mswi->first_hartid]);
}
static struct sbi_ipi_device aclint_mswi = {

View File

@@ -18,73 +18,45 @@
struct plicsw_data plicsw;
static inline void plicsw_claim(void)
static void plicsw_ipi_send(u32 hart_index)
{
u32 hartid = current_hartid();
ulong pending_reg;
u32 interrupt_id, word_index, pending_bit;
u32 target_hart = sbi_hartindex_to_hartid(hart_index);
if (plicsw.hart_count <= hartid)
if (plicsw.hart_count <= target_hart)
ebreak();
plicsw.source_id[hartid] =
readl((void *)plicsw.addr + PLICSW_CONTEXT_BASE +
PLICSW_CONTEXT_CLAIM + PLICSW_CONTEXT_STRIDE * hartid);
}
static inline void plicsw_complete(void)
{
u32 hartid = current_hartid();
u32 source = plicsw.source_id[hartid];
writel(source, (void *)plicsw.addr + PLICSW_CONTEXT_BASE +
PLICSW_CONTEXT_CLAIM +
PLICSW_CONTEXT_STRIDE * hartid);
}
static inline void plic_sw_pending(u32 target_hart)
{
/*
* The pending array registers are w1s type.
* IPI pending array mapping as following:
*
* Pending array start address: base + 0x1000
* ---------------------------------
* | hart3 | hart2 | hart1 | hart0 |
* ---------------------------------
* Each hartX can send IPI to another hart by setting the
* bitY to its own region (see the below).
*
* In each hartX region:
* <---------- PICSW_PENDING_STRIDE -------->
* | bit7 | ... | bit3 | bit2 | bit1 | bit0 |
* ------------------------------------------
* The bitY of hartX region indicates that hartX sends an
* IPI to hartY.
* We assign a single bit for each hart.
* Bit 0 is hardwired to 0, thus unavailable.
* Bit(X+1) indicates that IPI is sent to hartX.
*/
u32 hartid = current_hartid();
u32 word_index = hartid / 4;
u32 per_hart_offset = PLICSW_PENDING_STRIDE * hartid;
u32 val = 1 << target_hart << per_hart_offset;
interrupt_id = target_hart + 1;
word_index = interrupt_id / 32;
pending_bit = interrupt_id % 32;
pending_reg = plicsw.addr + PLICSW_PENDING_BASE + word_index * 4;
writel(val, (void *)plicsw.addr + PLICSW_PENDING_BASE + word_index * 4);
/* Set target hart's mip.MSIP */
writel_relaxed(BIT(pending_bit), (void *)pending_reg);
}
static void plicsw_ipi_send(u32 target_hart)
static void plicsw_ipi_clear(u32 hart_index)
{
u32 target_hart = sbi_hartindex_to_hartid(hart_index);
ulong reg = plicsw.addr + PLICSW_CONTEXT_BASE + PLICSW_CONTEXT_CLAIM +
PLICSW_CONTEXT_STRIDE * target_hart;
if (plicsw.hart_count <= target_hart)
ebreak();
/* Set PLICSW IPI */
plic_sw_pending(target_hart);
}
/* Claim */
u32 source = readl((void *)reg);
static void plicsw_ipi_clear(u32 target_hart)
{
if (plicsw.hart_count <= target_hart)
ebreak();
/* A successful claim will clear mip.MSIP */
/* Clear PLICSW IPI */
plicsw_claim();
plicsw_complete();
/* Complete */
writel(source, (void *)reg);
}
static struct sbi_ipi_device plicsw_ipi = {
@@ -106,28 +78,34 @@ int plicsw_warm_ipi_init(void)
int plicsw_cold_ipi_init(struct plicsw_data *plicsw)
{
int rc;
u32 interrupt_id, word_index, enable_bit;
ulong enable_reg, priority_reg;
/* Setup source priority */
uint32_t *priority = (void *)plicsw->addr + PLICSW_PRIORITY_BASE;
for (int i = 0; i < plicsw->hart_count; i++)
writel(1, &priority[i]);
/* Setup target enable */
uint32_t enable_mask = PLICSW_HART_MASK;
for (int i = 0; i < plicsw->hart_count; i++) {
uint32_t *enable = (void *)plicsw->addr + PLICSW_ENABLE_BASE +
PLICSW_ENABLE_STRIDE * i;
writel(enable_mask, enable);
writel(enable_mask, enable + 1);
enable_mask <<= 1;
priority_reg = plicsw->addr + PLICSW_PRIORITY_BASE + i * 4;
writel(1, (void *)priority_reg);
}
/*
* Setup enable for each hart, skip non-existent interrupt ID 0
* which is hardwired to 0.
*/
for (int i = 0; i < plicsw->hart_count; i++) {
interrupt_id = i + 1;
word_index = interrupt_id / 32;
enable_bit = interrupt_id % 32;
enable_reg = plicsw->addr + PLICSW_ENABLE_BASE +
PLICSW_ENABLE_STRIDE * i + 4 * word_index;
writel(BIT(enable_bit), (void *)enable_reg);
}
/* Add PLICSW region to the root domain */
rc = sbi_domain_root_add_memrange(plicsw->addr, plicsw->size,
PLICSW_REGION_ALIGN,
SBI_DOMAIN_MEMREGION_MMIO);
SBI_DOMAIN_MEMREGION_MMIO |
SBI_DOMAIN_MEMREGION_M_READABLE |
SBI_DOMAIN_MEMREGION_M_WRITABLE);
if (rc)
return rc;

View File

@@ -24,7 +24,7 @@ static int ipi_mswi_cold_init(void *fdt, int nodeoff,
if (!ms)
return SBI_ENOMEM;
rc = fdt_parse_aclint_node(fdt, nodeoff, false,
rc = fdt_parse_aclint_node(fdt, nodeoff, false, false,
&ms->addr, &ms->size, NULL, NULL,
&ms->first_hartid, &ms->hart_count);
if (rc) {
@@ -56,6 +56,7 @@ static const struct fdt_match ipi_mswi_match[] = {
{ .compatible = "riscv,clint0", .data = &clint_offset },
{ .compatible = "sifive,clint0", .data = &clint_offset },
{ .compatible = "thead,c900-clint", .data = &clint_offset },
{ .compatible = "thead,c900-aclint-mswi" },
{ .compatible = "riscv,aclint-mswi" },
{ },
};

View File

@@ -193,7 +193,7 @@ int aplic_cold_irqchip_init(struct aplic_data *aplic)
writel(0, (void *)(aplic->addr + APLIC_DOMAINCFG));
/* Disable all interrupts */
for (i = 0; i <= aplic->num_source; i++)
for (i = 0; i <= aplic->num_source; i += 32)
writel(-1U, (void *)(aplic->addr + APLIC_CLRIE_BASE +
(i / 32) * sizeof(u32)));

View File

@@ -161,7 +161,7 @@ static int imsic_external_irqfn(struct sbi_trap_regs *regs)
return 0;
}
static void imsic_ipi_send(u32 target_hart)
static void imsic_ipi_send(u32 hart_index)
{
unsigned long reloff;
struct imsic_regs *regs;
@@ -169,7 +169,7 @@ static void imsic_ipi_send(u32 target_hart)
struct sbi_scratch *scratch;
int file;
scratch = sbi_hartid_to_scratch(target_hart);
scratch = sbi_hartindex_to_scratch(hart_index);
if (!scratch)
return;
@@ -186,8 +186,8 @@ static void imsic_ipi_send(u32 target_hart)
}
if (regs->size && (reloff < regs->size))
writel(IMSIC_IPI_ID,
(void *)(regs->addr + reloff + IMSIC_MMIO_PAGE_LE));
writel_relaxed(IMSIC_IPI_ID,
(void *)(regs->addr + reloff + IMSIC_MMIO_PAGE_LE));
}
static struct sbi_ipi_device imsic_ipi_device = {

View File

@@ -10,7 +10,9 @@
#include <sbi/riscv_io.h>
#include <sbi/riscv_encoding.h>
#include <sbi/sbi_bitops.h>
#include <sbi/sbi_console.h>
#include <sbi/sbi_domain.h>
#include <sbi/sbi_error.h>
#include <sbi/sbi_string.h>
#include <sbi_utils/irqchip/plic.h>
@@ -171,5 +173,7 @@ int plic_cold_irqchip_init(const struct plic_data *plic)
for (i = 1; i <= plic->num_src; i++)
plic_set_priority(plic, i, 0);
return 0;
return sbi_domain_root_add_memrange(plic->addr, plic->size, BIT(20),
(SBI_DOMAIN_MEMREGION_MMIO |
SBI_DOMAIN_MEMREGION_SHARED_SURW_MRW));
}

View File

@@ -1,4 +1,4 @@
# SPDX-License-Identifier: (GPL-2.0-or-later OR BSD-2-Clause)
# SPDX-License-Identifier: GPL-2.0-or-later OR BSD-2-Clause
# Makefile.libfdt
#
# This is not a complete Makefile of itself. Instead, it is designed to

View File

@@ -1,4 +1,4 @@
// SPDX-License-Identifier: (GPL-2.0-or-later OR BSD-2-Clause)
// SPDX-License-Identifier: GPL-2.0-or-later OR BSD-2-Clause
/*
* libfdt - Flat Device Tree manipulation
* Copyright (C) 2006 David Gibson, IBM Corporation.

View File

@@ -1,4 +1,4 @@
/* SPDX-License-Identifier: (GPL-2.0-or-later OR BSD-2-Clause) */
/* SPDX-License-Identifier: GPL-2.0-or-later OR BSD-2-Clause */
#ifndef FDT_H
#define FDT_H
/*

View File

@@ -1,4 +1,4 @@
// SPDX-License-Identifier: (GPL-2.0-or-later OR BSD-2-Clause)
// SPDX-License-Identifier: GPL-2.0-or-later OR BSD-2-Clause
/*
* libfdt - Flat Device Tree manipulation
* Copyright (C) 2014 David Gibson <david@gibson.dropbear.id.au>

View File

@@ -1,4 +1,4 @@
// SPDX-License-Identifier: (GPL-2.0-or-later OR BSD-2-Clause)
// SPDX-License-Identifier: GPL-2.0-or-later OR BSD-2-Clause
/*
* libfdt - Flat Device Tree manipulation
* Copyright (C) 2006 David Gibson, IBM Corporation.

View File

@@ -1,4 +1,4 @@
// SPDX-License-Identifier: (GPL-2.0-or-later OR BSD-2-Clause)
// SPDX-License-Identifier: GPL-2.0-or-later OR BSD-2-Clause
/*
* libfdt - Flat Device Tree manipulation
* Copyright (C) 2012 David Gibson, IBM Corporation.

View File

@@ -1,4 +1,4 @@
// SPDX-License-Identifier: (GPL-2.0-or-later OR BSD-2-Clause)
// SPDX-License-Identifier: GPL-2.0-or-later OR BSD-2-Clause
/*
* libfdt - Flat Device Tree manipulation
* Copyright (C) 2016 Free Electrons

View File

@@ -1,4 +1,4 @@
// SPDX-License-Identifier: (GPL-2.0-or-later OR BSD-2-Clause)
// SPDX-License-Identifier: GPL-2.0-or-later OR BSD-2-Clause
/*
* libfdt - Flat Device Tree manipulation
* Copyright (C) 2006 David Gibson, IBM Corporation.

View File

@@ -1,4 +1,4 @@
// SPDX-License-Identifier: (GPL-2.0-or-later OR BSD-2-Clause)
// SPDX-License-Identifier: GPL-2.0-or-later OR BSD-2-Clause
/*
* libfdt - Flat Device Tree manipulation
* Copyright (C) 2006 David Gibson, IBM Corporation.

View File

@@ -1,4 +1,4 @@
// SPDX-License-Identifier: (GPL-2.0-or-later OR BSD-2-Clause)
// SPDX-License-Identifier: GPL-2.0-or-later OR BSD-2-Clause
/*
* libfdt - Flat Device Tree manipulation
* Copyright (C) 2006 David Gibson, IBM Corporation.

View File

@@ -1,4 +1,4 @@
// SPDX-License-Identifier: (GPL-2.0-or-later OR BSD-2-Clause)
// SPDX-License-Identifier: GPL-2.0-or-later OR BSD-2-Clause
/*
* libfdt - Flat Device Tree manipulation
* Copyright (C) 2006 David Gibson, IBM Corporation.

View File

@@ -1,4 +1,4 @@
// SPDX-License-Identifier: (GPL-2.0-or-later OR BSD-2-Clause)
// SPDX-License-Identifier: GPL-2.0-or-later OR BSD-2-Clause
/*
* libfdt - Flat Device Tree manipulation
* Copyright (C) 2006 David Gibson, IBM Corporation.

View File

@@ -1,4 +1,4 @@
/* SPDX-License-Identifier: (GPL-2.0-or-later OR BSD-2-Clause) */
/* SPDX-License-Identifier: GPL-2.0-or-later OR BSD-2-Clause */
#ifndef LIBFDT_H
#define LIBFDT_H
/*

View File

@@ -1,4 +1,4 @@
/* SPDX-License-Identifier: (GPL-2.0-or-later OR BSD-2-Clause) */
/* SPDX-License-Identifier: GPL-2.0-or-later OR BSD-2-Clause */
#ifndef LIBFDT_ENV_H
#define LIBFDT_ENV_H
/*

View File

@@ -1,4 +1,4 @@
/* SPDX-License-Identifier: (GPL-2.0-or-later OR BSD-2-Clause) */
/* SPDX-License-Identifier: GPL-2.0-or-later OR BSD-2-Clause */
#ifndef LIBFDT_INTERNAL_H
#define LIBFDT_INTERNAL_H
/*

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