100 Commits
v0.5 ... v0.6

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

Signed-off-by: Anup Patel <anup.patel@wdc.com>
2020-02-24 11:27:57 +05:30
Anup Patel
f8b3bb826d lib: Simplify the for-loop in sbi_ipi_send_many()
We don't need to separately call sbi_ipi_send() for current HART
in sbi_ipi_send_many(). Instead, we can simplify the for-loop in
sbi_ipi_send_many() and call sbi_ipi_send() for all HARTs in the
for-loop itself.

Signed-off-by: Anup Patel <anup.patel@wdc.com>
Reviewed-by: Bin Meng <bmeng.cn@gmail.com>
2020-02-24 09:10:04 +05:30
Atish Patra
393624377a lib: Use available hart mask for correct hbase value
As per the latest SBI specification, all online harts should receive
IPI if hbase is set to -1.

Set the target mask to all available hart mask if hbase is -1.

Signed-off-by: Atish Patra <atish.patra@wdc.com>
Reviewed-by: Anup Patel <anup.patel@wdc.com>
2020-02-22 10:06:51 +05:30
Atish Patra
c3b3b8f43b lib: Fix typo in atomic exchange functions
There is a typo in atomic operations code which prevents the
usage of riscv atomic instructions even if it is supported.

Fix the typo.

Signed-off-by: Atish Patra <atish.patra@wdc.com>
Reviewed-by: Anup Patel <anup.patel@wdc.com>
2020-02-22 10:04:38 +05:30
Bin Meng
3e7d666d7c platform: qemu: virt: Correct the typo in config.mk
It should be "aligned".

Signed-off-by: Bin Meng <bmeng.cn@gmail.com>
Reviewed-by: Anup Patel <anup.patel@wdc.com>
2020-02-19 16:53:42 +05:30
Bin Meng
66fb729a1e platform: sifive: fu540: Add 32-bit specific fdt/payload addresses
For testing 32-bit SiFive specific drivers with QEMU riscv32, add
32-bit specific FW_JUMP_FDT_ADDR and FW_PAYLOAD_OFFSET.

Signed-off-by: Bin Meng <bmeng.cn@gmail.com>
Reviewed-by: Anup Patel <anup.patel@wdc.com>
2020-02-19 16:52:07 +05:30
Anup Patel
24c3082ea4 lib: Print interrupt and exception delegation in boot prints
We print MIDELEG and MEDELEG CSRs as part of boot prints so that
boot log shows the interrupts and exceptions delegated to S-mode.

Signed-off-by: Anup Patel <anup.patel@wdc.com>
Reviewed-by: Bin Meng <bmeng.cn@gmail.com>
Reviewed-by: Atish Patra <atish.patra@wdc.com>
2020-02-19 09:58:48 +05:30
Anup Patel
bc874e34ce lib: Don't check MIDELEG and MEDELEG at end of delegate_traps()
The MIDELEG and MEDELEG CSR checks at end of delegate_traps() were
added for initial bring-up on SiFive Unleashed and QEMU. These
checks are not required any more and in-future these checks can
cause failures because some of the MIDELEG/MEDELEG bits will be
hard-wired to 0 or 1.

For related discussion, refer github issue:
https://github.com/riscv/opensbi/issues/157

Signed-off-by: Anup Patel <anup.patel@wdc.com>
Reviewed-by: Bin Meng <bmeng.cn@gmail.com>
Reviewed-by: Atish Patra <atish.patra@wdc.com>
2020-02-19 09:58:45 +05:30
Bin Meng
c66543d049 lib: utils: htif: Fix 32-bit build
When building 32-bit OpenSBI images, we get:

  lib/utils/sys/htif.c: In function '__check_fromhost':
  lib/utils/sys/htif.c:12:31: error: left shift count >= width of type
                                     [-Werror=shift-count-overflow]
   #define HTIF_DATA_MASK  ((1UL << HTIF_DATA_BITS) - 1)
                                 ^~

Fixes: c2f23cc6ed ("platform: Add Spike initial support")
Signed-off-by: Bin Meng <bmeng.cn@gmail.com>
Reviewed-by: Anup Patel <anup.patel@wdc.com>
2020-02-18 10:30:16 +05:30
Anup Patel
0b414532c4 Revert "lib: Use __builtin_ctzl() in pmp_get()"
This reverts commit 897b8fbdd9.

We are seeing compile errors using newlib based GCC cross-toolchain
so we restore back old ctz() implementation.

Signed-off-by: Anup Patel <anup.patel@wdc.com>
2020-02-18 09:28:33 +05:30
Bin Meng
27a5c7f3c8 doc: thead-c910: Fix doc styles
- make title underline the same length as the title itself
- satisfy the 80 character per line rule as much as possible

Signed-off-by: Bin Meng <bmeng.cn@gmail.com>
Reviewed-by: Anup Patel <anup.patel@wdc.com>
2020-02-18 09:10:41 +05:30
Bin Meng
f8ce996d90 doc: sifive_fu540: Fix doc styles
- make title underline the same length as the title itself
- put all URLs at the end of the doc

Signed-off-by: Bin Meng <bmeng.cn@gmail.com>
Reviewed-by: Anup Patel <anup.patel@wdc.com>
2020-02-18 09:09:49 +05:30
Bin Meng
82fd42fcce doc: qemu_virt: Fix doc styles
Remove the unnecessary blank line at the end of the doc.

Signed-off-by: Bin Meng <bmeng.cn@gmail.com>
Reviewed-by: Anup Patel <anup.patel@wdc.com>
2020-02-18 09:08:44 +05:30
Bin Meng
a8ef0b5d53 doc: ariane-fpga: Fix doc styles
Various styles fixes including:

- satisfy the 80 character per line rule as much as possible
- make title underline the same length as the title itself
- remove the redundant FPGA (was FPGA FPGA SoC)

Signed-off-by: Bin Meng <bmeng.cn@gmail.com>
Reviewed-by: Anup Patel <anup.patel@wdc.com>
2020-02-18 09:07:37 +05:30
Bin Meng
44d1296018 doc: andes-ae350: Fix doc styles
Various styles fixes including:

- satisfy the 80 character per line rule as much as possible
- remove unnecessary spaces between words

Signed-off-by: Bin Meng <bmeng.cn@gmail.com>
Reviewed-by: Anup Patel <anup.patel@wdc.com>
2020-02-18 09:06:27 +05:30
Bin Meng
fdfb5332f3 doc: payload_linux: Fix doc styles
Remove the unnecessary blank line at the end of the doc.

Signed-off-by: Bin Meng <bmeng.cn@gmail.com>
Reviewed-by: Anup Patel <anup.patel@wdc.com>
2020-02-18 09:05:11 +05:30
Bin Meng
892e87998c doc: coreboot: Fix doc styles
- put all URLs at the end of the doc
- satisfy the 80 character per line rule as much as possible

Signed-off-by: Bin Meng <bmeng.cn@gmail.com>
Reviewed-by: Anup Patel <anup.patel@wdc.com>
2020-02-18 09:03:52 +05:30
Bin Meng
48b06ad16e ThirdPartyNotices: Fix doc styles
Remove the unnecessary blank line at the end of the doc.

Signed-off-by: Bin Meng <bmeng.cn@gmail.com>
Reviewed-by: Anup Patel <anup.patel@wdc.com>
2020-02-18 09:02:23 +05:30
Anup Patel
29bb2a6835 docs: platform: Add documentation for Spike platform
This patch adds documentation to build and run OpenSBI on
Spike simulator and QEMU Spike machine.

Signed-off-by: Anup Patel <anup.patel@wdc.com>
Reviewed-by: Bin Meng <bmeng.cn@gmail.com>
2020-02-17 17:43:01 +05:30
Anup Patel
c03c8a1e2c scripts: Add Spike to platform list of binary archive script
The Spike platform support works perfectly fine on QEMU RV64 Spike
machine and Spike emulator.

Signed-off-by: Anup Patel <anup.patel@wdc.com>
Reviewed-by: Bin Meng <bmeng.cn@gmail.com>
2020-02-17 17:42:58 +05:30
Anup Patel
a062200b89 platform: Remove stale options from config.mk files
This patch removes stale options from config.mk files of
Ariane FPGA and QEMU virt platform support.

Signed-off-by: Anup Patel <anup.patel@wdc.com>
Reviewed-by: Bin Meng <bmeng.cn@gmail.com>
Reviewed-by: Atish Patra <atish.patra@wdc.com>
2020-02-17 17:42:55 +05:30
James Clarke
c2f23cc6ed platform: Add Spike initial support
This patch adds initial platform support Spike emulator.

Signed-off-by: James Clarke <jrtc27@jrtc27.com>
Signed-off-by: Anup Patel <anup.patel@wdc.com>
Reviewed-by: Bin Meng <bmeng.cn@gmail.com>
Reviewed-by: Atish Patra <atish.patra@wdc.com>
2020-02-17 17:42:52 +05:30
Atish Patra
c2bfa2bff3 lib: irqchip/plic: Disable all contexts and IRQs
To initialize PLIC in sane state, we should:
1. set maximum threshold value of M-mode PLIC contexts
2. set maximum threshold value of S-mode PLIC contexts
3. set irq priorities to miniumum

Fix the comment and initialize the threshold/priorities correctly.

Signed-off-by: Anup Patel <anup.patel@wdc.com>
Signed-off-by: Atish Patra <atish.patra@wdc.com>
2020-02-13 09:58:27 +05:30
Atish Patra
1a8ca08cc0 lib: Initialize out value in SBI calls
As per the SBI specification, the return value in sbiret is undefined
if not explicitly described in the function. However, supervisor may
check this value by mistake and get a garbage value.

Initialize it to zero to avoid nasty supervisor bugs.

Signed-off-by: Atish Patra <atish.patra@wdc.com>
Reviewed-by: Anup Patel <anup.patel@wdc.com>
2020-02-13 09:57:22 +05:30
Li Jinpei
897b8fbdd9 lib: Use __builtin_ctzl() in pmp_get()
We should should __builtin_ctzl() in pmp_get() instead of
custom ctz() function.

Signed-off-by: Li Jinpei <leekingp1994@163.com>
Signed-off-by: Anup Patel <anup.patel@wdc.com>
Reviewed-by: Atish Patra <atish.patra@wdc.com>
2020-02-13 09:10:57 +05:30
Li Jinpei
179eddeb9c lib: sbi_scratch: use bitwise ops in sbi_scratch_alloc_offset()
Instead of using loop to make "size" machine word aligned, we should
use bitwise ops.

Signed-off-by: Li Jinpei <leekingp1994@163.com>
Signed-off-by: Anup Patel <anup.patel@wdc.com>
Reviewed-by: Atish Patra <atish.patra@wdc.com>
2020-02-13 09:10:55 +05:30
Bin Meng
d6fa7f95bb doc: sifive: fu540: Update QEMU instruction when using U-Boot as the payload
Document that when U-Boot v2020.01 (or higher) is used as the payload,
we need adjust the instructions a little bit when testing OpenSBI with
QEMU 'sifive_u' machine.

Signed-off-by: Bin Meng <bmeng.cn@gmail.com>
Reviewed-by: Atish Patra <atish.patra@wdc.com>
2020-02-11 15:09:08 +05:30
Bin Meng
9a717ec12e platform: sifive: fu540: Add platform specific 'make run' cmd
This adds sifive/fu540 specific QEMU run command.

Signed-off-by: Bin Meng <bmeng.cn@gmail.com>
Reviewed-by: Anup Patel <anup.patel@wdc.com>
2020-02-07 16:20:34 +05:30
Bin Meng
6d0b4c520d platform: Drop qemu/sifive_u support
With QEMU v4.2 RISC-V changes to improve the emulation fidelity
of 'sifive_u' machine, OpenSBI v0.4 / U-Boot v2019.10 / Linux
kernel v5.3 images built for the SiFive HiFive Unleashed board
can be used out of the box without any special hack. Hence there
is no need for us to continue supporting such a special target in
OpenSBI. Going forward, sifive/fu540 platform can be used on both
real hardware and QEMU 'sifive_u' machine.

Signed-off-by: Bin Meng <bmeng.cn@gmail.com>
Reviewed-by: Anup Patel <anup.patel@wdc.com>
2020-02-07 11:01:01 +05:30
Alex Richardson
5ff1ab0ed8 makefile: add support for building on macOS
On macOS the readlink command does not include a -f flag. Instead default
to using GNU readlink (which is often installed as greadlink).

Signed-off-by: Alex Richardson <Alexander.Richardson@cl.cam.ac.uk>
Signed-off-by: Anup Patel <anup.patel@wdc.com>
2020-02-06 15:42:47 +05:30
Atish Patra
2c2bbe7374 platform: sifive/fu540: Set tlb range flush limit to zero
It was reported that tlb range flush is not working on fu540.
Only tlb full flush seems to work on fu540 probably due to some
hardware errata.

Set the tlb flush limit to zero so that all tlb flush requests
are converted to full flush.

Signed-off-by: Atish Patra <atish.patra@wdc.com>
Reviewed-by: Anup Patel <anup.patel@wdc.com>
2020-02-05 10:46:29 +05:30
Atish Patra
d79173b4b7 platform: Add an platform ops to return platform specific tlb flush limit
If a platform requires to perform a tlb full flush, they should set
the tlb_range_flush_limit value to zero. However, corresponding platform
API ignore the value and continue to return the default value.

Add a platform ops to retrieve platform specific tlb range flush limit.
The platform variable becomes redundant in presence of the platform ops.
Take this opportunity to remove the variable as well.

The default is still set to smallest page size in RISC-V (4KB), as there
is no way to figure out a best value for all platforms. Individual platform
should set it to the optimal value for their platform.

Signed-off-by: Atish Patra <atish.patra@wdc.com>
Reviewed-by: Anup Patel <anup.patel@wdc.com>
2020-02-05 10:37:11 +05:30
Nikita Ermakov
ac1c229b61 platform: Update UART base addresses for qemu/sifve_u
In the QEMU [1] there was a change of the UART base addresses for
sifive_u machine to match the hardware. Make corresponding changes in
the opensbi for qemu/sifive_u platform.

[1] https://git.qemu.org/?p=qemu.git;a=commitdiff;h=4b55bc2b5f7ff065da5d2b813ee5153c598d3764

Signed-off-by: Nikita Ermakov <coffe92@gmail.com>
Reviewed-by: Anup Patel <anup.patel@wdc.com>
2020-01-25 10:54:21 +05:30
Jiuyang Liu (Sequencer)
85647a1a76 platform: template: typo fix in system reboot/shutdown names
This patch does minor typo fix in system reboot/shutdown names
in platform operations.

Signed-off-by: Jiuyang Liu (Sequencer) <liujiuyang1994@gmail.com>
Reviewed-by: Alistair Francis <alistair.francis@wdc.com>
Signed-off-by: Anup Patel <anup.patel@wdc.com>
2020-01-24 07:34:10 +05:30
Anup Patel
021b9e7c76 lib: Factor-out SBI base extension
This patch factor-out SBI base extension into its own source
for better modularity of SBI implementation.

Signed-off-by: Anup Patel <anup.patel@wdc.com>
Reviewed-by: Atish Patra <atish.patra@wdc.com>
2020-01-22 12:13:47 +05:30
Anup Patel
43ac621ecb lib: Factor-out SBI vendor extension
This patch factor-out SBI vendor extension into its own source
for better modularity of SBI implementation.

Signed-off-by: Anup Patel <anup.patel@wdc.com>
Reviewed-by: Atish Patra <atish.patra@wdc.com>
2020-01-22 12:13:44 +05:30
Anup Patel
161b348e7e lib: Factor-out SBI replacement extensions
This patch factor-out SBI replacement extensions (such as RFENCE,
IPI, and TIME) into its own source for better modularity of SBI
implementation.

Signed-off-by: Anup Patel <anup.patel@wdc.com>
Reviewed-by: Atish Patra <atish.patra@wdc.com>
2020-01-22 12:13:42 +05:30
Anup Patel
766850222a lib: Factor-out SBI legacy extension
This patch factor-out SBI legacy extension into its own source
for better modularity of SBI implementation.

Signed-off-by: Anup Patel <anup.patel@wdc.com>
Reviewed-by: Atish Patra <atish.patra@wdc.com>
2020-01-22 12:13:40 +05:30
Anup Patel
37923c4a66 lib: Add dynamic registration of SBI extensions
This patch extends our SBI ecall implementation to allow
dynamic registration of various SBI extensions. Using this
dynamic registration we can break-up SBI ecall implementation
into multiple files and even register experimental/custom
SBI extensions from platform code.

Signed-off-by: Anup Patel <anup.patel@wdc.com>
Reviewed-by: Atish Patra <atish.patra@wdc.com>
2020-01-22 12:13:34 +05:30
Anup Patel
0a411bf717 include: Add generic and simple list handling APIs
This patch adds generic and simple list handling APIs adapted
from Xvisor sources.

Signed-off-by: Anup Patel <anup.patel@wdc.com>
Reviewed-by: Atish Patra <atish.patra@wdc.com>
2020-01-22 12:13:30 +05:30
Anup Patel
84cd4fc913 lib: Initialize TLB management directly from coldboot/warmboot path
Currently, the remote TLB management is initialized via IPI init
which is counter intuitive. This patch initializes remote TLB
management directly from init_coldboot() and init_warmboot()
after IPI init is done.

Signed-off-by: Anup Patel <anup.patel@wdc.com>
Reviewed-by: Atish Patra <atish.patra@wdc.com>
2020-01-22 12:10:49 +05:30
Anup Patel
817d50d0d4 lib: Drop _fifo from the name of various sbi_tlb_fifo_xyz() functions
This patch drops _fifo from the name of various sbi_tlb_fifo_xyz()
functions because all these functions deal with remote TLB managment
and FIFO is the per-HART data structure used internally by remote
TLB implementation.

Signed-off-by: Anup Patel <anup.patel@wdc.com>
Reviewed-by: Atish Patra <atish.patra@wdc.com>
2020-01-22 12:10:47 +05:30
Anup Patel
5f762d14f0 lib: Introduce sbi_ipi_event_create/destroy() APIs
This patch introduces sbi_ipi_event_create/destroy() APIs and
struct sbi_ipi_event_ops for creating/destroying IPI events
at runtime based of event operations.

This new APIs will help platform code and utils code to create
custom IPI events which are not part of generic OpenSBI library.

Signed-off-by: Anup Patel <anup.patel@wdc.com>
Reviewed-by: Atish Patra <atish.patra@wdc.com>
2020-01-22 12:10:44 +05:30
Anup Patel
a8b4b83b7f lib: Introduce sbi_tlb_fifo_request() API
Instead of directly calling sbi_ipi_send_many(), we introduce
sbi_tlb_fifo_request() for halting a set of HARTs.

This way in future we can assign any IPI event number for remote
FENCE within sbi_tlb.c only.

Signed-off-by: Anup Patel <anup.patel@wdc.com>
Reviewed-by: Atish Patra <atish.patra@wdc.com>
2020-01-22 12:10:40 +05:30
Anup Patel
da9b76b957 lib: Introduce sbi_ipi_send_halt() API
Instead of directly calling sbi_ipi_send_many(), we introduce
sbi_ipi_send_halt() for halting a set of HARTs.

This way in future we can assign any IPI event number for HART
halting within sbi_ipi.c only.

Signed-off-by: Anup Patel <anup.patel@wdc.com>
Reviewed-by: Atish Patra <atish.patra@wdc.com>
2020-01-22 12:10:37 +05:30
Anup Patel
3d2aaac69a lib: Introduce sbi_ipi_send_smode() API
Instead of directly calling sbi_ipi_send_many(), we introduce
sbi_ipi_send_smode() for injecting S-mode software interrupts.

This way in future we can assign any IPI event number for S-mode
IPIs within sbi_ipi.c only.

Signed-off-by: Anup Patel <anup.patel@wdc.com>
Reviewed-by: Atish Patra <atish.patra@wdc.com>
2020-01-22 12:10:35 +05:30
Anup Patel
046cc16e8b lib: Move struct sbi_ipi_data definition to sbi_ipi.c
The struct sbi_ipi_data is only used in sbi_ipi.c so move it
to sbi_ipi.c from sbi_ipi.h.

Signed-off-by: Anup Patel <anup.patel@wdc.com>
Reviewed-by: Atish Patra <atish.patra@wdc.com>
2020-01-22 12:10:33 +05:30
Anup Patel
0492c5d92b include: Typo fix in comment for SBI_SCRATCH_SIZE define
This patch fixes a minor typo in comment for SBI_SCRATCH_SIZE define.

Signed-off-by: Anup Patel <anup.patel@wdc.com>
Reviewed-by: Atish Patra <atish.patra@wdc.com>
2020-01-22 12:10:31 +05:30
Liu Yibin
30cdf00655 scripts: Add C910 to platform list in the binary archive script
This patch adds T-HEAD C910 to RV64 platform list in the binary
archive script.

Signed-off-by: Liu Yibin <yibin_liu@c-sky.com>
Reviewed-by: Anup Patel <anup.patel@wdc.com>
2020-01-20 10:05:55 +05:30
Liu Yibin
a73d45ccac platform: thead/c910: Don't set plic/clint address in warm boot
Since all harts share the same plic/clint address now, setting
them during cold boot is just fine.

Signed-off-by: Liu Yibin <yibin_liu@c-sky.com>
Reviewed-by: Anup Patel <anup.patel@wdc.com>
2020-01-15 05:48:44 +05:30
Liu Yibin
7daccaeebd platform: thead/c910: Don't enable L2 cache in warm boot
Since all harts share the same L2 cache now, there's
no need to Enable L2 cache in warm boot.

Signed-off-by: Liu Yibin <yibin_liu@c-sky.com>
Reviewed-by: Anup Patel <anup.patel@wdc.com>
2020-01-15 05:46:38 +05:30
Andreas Schwab
6ffe1bed09 firmware: Fix placement of .align directives
Move the .align directives after switching the section.  We want to align
the start of the current section, not the end of the previous section.
This also obsoletes the misguided workaround of disabling relaxation.

Signed-off-by: Andreas Schwab <schwab@suse.de>
Reviewed-by: Anup Patel <anup.patel@wdc.com>
2020-01-10 09:30:27 +05:30
Anup Patel
f95dd39ab6 docs: platform: Update SiFive FU540 doc as-per U-Boot v2020.01
With U-Boot v2020.01, the SiFive FU540 DTB required by U-Boot is
embedded in U-Boot binary itself so we don't need to do anything
special for U-Boot v2020.01 as payload to OpenSBI firmware.

This patch updates SiFive FU540 documenation assuming we use
latest U-Boot v2020.01 release.

Signed-off-by: Anup Patel <anup.patel@wdc.com>
Reviewed-by: Bin Meng <bmeng.cn@gmail.com>
2020-01-10 09:13:19 +05:30
Liu Yibin
adf8b73675 platform: thead/c910: Remove SBI_PLATFORM_HAS_PMP
T-head c910 is a generic FPGA platform so we cannot
define PMP configuration for it in OpenSBI because
PMP configuration tend to be SOC specific.

Signed-off-by: Liu Yibin <yibin_liu@c-sky.com>
Reviewed-by: Atish Patra <atish.patra@wdc.com>
2020-01-09 10:23:11 +05:30
Abner Chang
b28b8ac0d2 docs: Add description of using OPENSBI_EXTERNAL_SBI_TYPES
Add description of using OPENSBI_EXTERNAL_SBI_TYPES in external
firmware code base.

Signed-off-by: Abner Chang <abner.chang@hpe.com>
Cc: Leif Lindholm <leif.lindholm@linaro.org>
Reviewed-by: Anup Patel <anup.patel@wdc.com>
2020-01-09 10:09:44 +05:30
Abner Chang
e340bbf7b5 include: Add OPENSBI_EXTERNAL_SBI_TYPES in sbi_types.h
Add OPENSBI_EXTERNAL_SBI_TYPES macro to allow external definitions of data
types and common macros. Also move some common definitions from sbi_bits.h to sbi_types.h.

Signed-off-by: Abner Chang <abner.chang@hpe.com>
Cc: Leif Lindholm <leif.lindholm@linaro.org>
Reviewed-by: Anup Patel <anup.patel@wdc.com>
2020-01-09 10:08:11 +05:30
Khem Raj
049ad0b387 build: Use -ffreestanding
this is a stand-alone/baremetal application, therefore demanding
-ffreestanding would help it compile with hosted toolchains e.g. ( linux
toolchains ), it also ensures that it won't be using platform
optimizations like inlining mem* str* functions which gcc might decide
especially with wrapper string functions in opensbi code

Signed-off-by: Khem Raj <raj.khem@gmail.com>
Reviewed-by: Anup Patel <anup.patel@wdc.com>
2020-01-08 09:10:24 +05:30
Anup Patel
a67fd68cbf lib: Add sbi_init_count() API
We add sbi_init_count() API which provides number of times a
given HART completed init sequence (warmboot/coldboot).

This will be very useful in debugging. With upcoming SBI HSM
extension, it will also help in implementing one-time init
code for each HART.

Signed-off-by: Anup Patel <anup@brainfault.org>
Reviewed-by: Atish Patra <atish.patra@wdc.com>
2020-01-07 12:11:48 +05:30
Anup Patel
73c19e69f3 lib: zero-out memory allocated using sbi_scratch_alloc_offset()
We should zero-out memory allocated from extra scratch space using
sbi_scratch_alloc_offset() API hence this patch. This will not
impact performance because we mostly allocate from extra scratch
space only at cold boot time.

Signed-off-by: Anup Patel <anup@brainfault.org>
Reviewed-by: Atish Patra <atish.patra@wdc.com>
2020-01-07 12:11:41 +05:30
Anup Patel
15ed1e7452 lib: improve system reboot and shutdown implementation
We improve sbi_system_reboot() an sbi_system_shutdown() by:

1. Calling halt IPI to all harts (except current HART) before
   calling platform reboot/shutdown hook.
2. Calling sbi_exit() instead of sbi_hang() in-case platform
   reboot/shutdown hook failed.

Signed-off-by: Anup Patel <anup.patel@wdc.com>
Reviewed-by: Atish Patra <atish.patra@wdc.com>
2020-01-07 12:11:36 +05:30
Anup Patel
b0c9787435 lib: do sbi_exit() upon halt IPI
Instead of doing sbi_hang() we should do sbi_exit() upon
halt IPI.

Signed-off-by: Anup Patel <anup.patel@wdc.com>
Reviewed-by: Atish Patra <atish.patra@wdc.com>
2020-01-07 12:11:31 +05:30
Anup Patel
2aa43a13cd lib: save/restore MIE CSR in sbi_hart_wait_for_coldboot()
Currently, sbi_hart_wait_for_coldboot() leaves MIE.MSIP bit
set when it returns which is not correct because MIE.MSIP
should be left enabled only by sbi_ipi_init().

This patch does save/restore of MIE CSR to ensure that MIE
CSR is in original state after sbi_hart_wait_for_coldboot()
returns.

Signed-off-by: Anup Patel <anup.patel@wdc.com>
Reviewed-by: Atish Patra <atish.patra@wdc.com>
2020-01-07 12:11:25 +05:30
Anup Patel
1993182f03 lib: Add irqchip exit API
We add an optional platform irqchip exit hook for exit path handling
in sbi_exit() implementation.

Signed-off-by: Anup Patel <anup.patel@wdc.com>
Reviewed-by: Atish Patra <atish.patra@wdc.com>
2020-01-07 12:11:19 +05:30
Anup Patel
b325f6baef lib: Add ipi exit API
We add sbi_ipi_exit() API for exit path handling in sbi_exit()
implementation.

Signed-off-by: Anup Patel <anup.patel@wdc.com>
Reviewed-by: Atish Patra <atish.patra@wdc.com>
2020-01-07 12:11:02 +05:30
Anup Patel
6469ed101c lib: Add timer exit API
We add sbi_timer_exit() API for OpenSBI exit path handling in
sbi_exit() implementation.

Signed-off-by: Anup Patel <anup.patel@wdc.com>
Reviewed-by: Atish Patra <atish.patra@wdc.com>
2020-01-07 12:10:55 +05:30
Anup Patel
55e191e3b0 lib: Add system early_exit and final_exit APIs
This patch adds system-level early_exit and final_exit APIs
with corresponding platform hooks. These new APIs will be
primarily used by sbi_exit() in OpenSBI exit path.

Signed-off-by: Anup Patel <anup.patel@wdc.com>
Reviewed-by: Atish Patra <atish.patra@wdc.com>
2020-01-07 12:10:48 +05:30
Anup Patel
c3e406f160 lib: Add initial sbi_exit() API
This patch adds initial implementation of sbi_exit() API which
can be used to perform OpenSBI exit sequence for current HART.

The sbi_exit() implementation will be further extended by
subsequent patches.

Signed-off-by: Anup Patel <anup.patel@wdc.com>
Reviewed-by: Atish Patra <atish.patra@wdc.com>
2020-01-07 12:10:35 +05:30
Anup Patel
e746673a79 lib: Remove unnecessary checks from init_coldboot() and init_warmboot()
We remove unnecessary checks related to hart hotplug and disabled
hart in coldboot and warmboot init path.

Signed-off-by: Anup Patel <anup.patel@wdc.com>
Reviewed-by: Atish Patra <atish.patra@wdc.com>
2020-01-07 10:22:24 +05:30
Liu Yibin
c0849cd731 platform: Add T-head C910 initial support
This commit provides basic support for the Thead/C910 platform.

Signed-off-by: Liu Yibin <yibin_liu@c-sky.com>
Reviewed-by: Atish Patra <atish.patra@wdc.com>
Reviewed-by: Anup Patel <anup.patel@wdc.com>
2020-01-02 10:03:23 +05:30
Anup Patel
46a90d90e7 lib: utils: Support CLINT with 32bit MMIO access on RV64 system
It is possible to have a CLINT implementation which supports
only 32bit MMIO accesses on RV64 system so this patch extends
our CLINT driver such that platform code can specify whether
CLINT supports 64bit MMIO access.

Signed-off-by: Anup Patel <anup.patel@wdc.com>
Reviewed-by: Atish Patra<atish.patra@wdc.com>
Reviewed-by: Zong Li <zong.li@sifive.com>
2020-01-02 09:14:36 +05:30
Liu Yibin
fc6bd90457 docs: Improve docs for FDT address passing
This patch updates FW_JUMP and FW_PAYLOAD documentation for the
case where FW_xyz_FDT_ADDR is not specified.

Signed-off-by: Liu Yibin <yibin_liu@c-sky.com>
Reviewed-by: Anup Patel <anup.patel@wdc.com>
2019-12-30 09:05:51 +05:30
Anup Patel
9beb57362f firmware: Improve comments for fw_prev_arg1() and fw_next_arg1()
The state of a0, a1, and a2 registers in fw_prev_arg1() and
fw_next_arg1() is same as passed by previous booting stage
so we add this info in comments for both these functions.

Signed-off-by: Anup Patel <anup.patel@wdc.com>
2019-12-27 08:54:24 +05:30
Liu Yibin
c7d1b12199 firmware: Return real DTB address when FW_xyz_FDT_ADDR is not defined
Function fw_next_arg1 in firmware/fw_jump.S:59 and
firmware/fw_payload.S:63 should return real dtb
address(if specified in a1) in a0, in case we don't
want to specify FW_xyz_FDT_ADDR when compiling.

Signed-off-by: Liu Yibin <yibin_liu@c-sky.com>
Reviewed-by: Anup Patel <anup.patel@wdc.com>
2019-12-27 08:48:17 +05:30
Atish Patra
86a31f5437 lib: Implement RFENCE extension
This patch adds RFENCE extension support in OpenSBI.

Signed-off-by: Atish Patra <atish.patra@wdc.com>
Reviewed-by: Anup Patel <anup.patel@wdc.com>
2019-12-23 09:12:23 +05:30
Atish Patra
331ff6a162 lib: Support stage1 and stage2 tlb flushing
The hypervisor specification support hfence calls which can be used
issue tlb flush requests at both level of address translation. Currently,
these requests are issued only via SBI which are defined in v0.2.

Signed-off-by: Atish Patra <atish.patra@wdc.com>
Reviewed-by: Anup Patel <anup.patel@wdc.com>
2019-12-23 09:12:19 +05:30
Atish Patra
9407202532 lib: Add hfence instruction encoding
Currently, the toolchains do not have support for hfence instruction.
Hence, the instruction are hardcode until we have toolchain support.

Signed-off-by: Atish Patra <atish.patra@wdc.com>
Reviewed-by: Anup Patel <anup.patel@wdc.com>
2019-12-23 09:12:16 +05:30
Atish Patra
9777aeef41 lib: Add IPI extension in SBI
This patch adds new IPI extension which replaces ipi related
v0.1 extensions. This also adds a new API for ipi sending as trap
handling is not necessary in v0.2 SBI IPI related extensions.

It also modifies the IPI sending code which now accepts hart mask as a value
instead of S-mode virtual address. Thus, the caller should set it to exact hart
mask value everytime.

Signed-off-by: Atish Patra <atish.patra@wdc.com>
Reviewed-by: Anup Patel <anup.patel@wdc.com>
2019-12-23 09:12:13 +05:30
Atish Patra
109266397a lib: Add TIME extension in SBI
This patch adds support for TIME extension which replaces v0.1
timer extension.

Signed-off-by: Atish Patra <atish.patra@wdc.com>
Reviewed-by: Anup Patel <anup.patel@wdc.com>
2019-12-23 09:12:11 +05:30
Atish Patra
aa0ed1d733 lib: Remove redundant IPI types
We just need to distinguish only between FENCE and non FENCE related
IPIs as all of the fence related requests are handled via fifo now.

Remove the unnecessary IPI types related to individual fence types.

Signed-off-by: Atish Patra <atish.patra@wdc.com>
Reviewed-by: Anup Patel <anup.patel@wdc.com>
2019-12-23 09:12:08 +05:30
Atish Patra
b8732feaf7 lib: Add replacement extension and function ids
Take this opportunity to move the enums to macros as enums make
sbi_ecall_interface.h unusable in assembly files.

Signed-off-by: Atish Patra <atish.patra@wdc.com>
Reviewed-by: Anup Patel <anup.patel@wdc.com>
2019-12-23 09:12:04 +05:30
Anup Patel
7219477f7b lib: Use MTINST CSR in misaligned load/store emulation
We should use MTINST CSR in misaligned load/store emulation whenever
possible to avoid unpriv read in getting trapped instruction. This will
improve preformance on HW having proper implementation of MTINST CSR.

Signed-off-by: Anup Patel <anup.patel@wdc.com>
Reviewed-by: Alistair Francis <alistair.francis@wdc.com>
2019-12-16 14:48:31 +05:30
Anup Patel
2be424bd28 lib: Extend trap redirection for hypervisor v0.5 spec
The hypervisor v0.5 spec introduces two new CSRs for both M-mode
and HS-mode which need to be considered when redirecting traps
hence this patch.

Signed-off-by: Anup Patel <anup.patel@wdc.com>
2019-12-16 14:48:26 +05:30
Anup Patel
086dbdfc92 lib: Fix sbi_get_insn() for load guest page fault
We should treat load guest page fault in sbi_get_insn() as
fetch guest patch fault.

Signed-off-by: Anup Patel <anup.patel@wdc.com>
Reviewed-by: Alistair Francis <alistair.francis@wdc.com>
2019-12-16 14:48:23 +05:30
Anup Patel
4370f18f34 include: Extend struct sbi_trap_info for mtval2 and mtinst
We have two new trap CSRs namely mtval2 and mtinst when
RISC-V hypervisor extension is available hence we extend
struct sbi_trap_info accordingly.

Signed-off-by: Anup Patel <anup.patel@wdc.com>
Reviewed-by: Alistair Francis <alistair.francis@wdc.com>
2019-12-16 14:48:19 +05:30
Anup Patel
6590a7dab9 lib: Delegate guest page faults to HS-mode
As-per RISC-V hypervisor v0.5 spec, we have new guest page faults
which need to be delegated to HS-mode.

Also, we can have bits in in MIDELEG and MEDELEG hardwired to 1
which means we need to fix the sainty check on these CSRs at the
end of delegate_traps() function.

Signed-off-by: Anup Patel <anup.patel@wdc.com>
Reviewed-by: Alistair Francis <alistair.francis@wdc.com>
2019-12-16 14:48:16 +05:30
Anup Patel
bd732ae612 include: Add guest external interrupt related defines
With RISC-V H-extension v0.5 draft, we have special support for guest
external interrupts so this patch adds related defines which were
missed-out previously.

Signed-off-by: Anup Patel <anup.patel@wdc.com>
Reviewed-by: Alistair Francis <alistair.francis@wdc.com>
2019-12-16 14:48:12 +05:30
Martin Pietryka
dc40042322 include: sbi_platform: fix compilation for GCC-9
GCC-9 will throw a warning when using the %s format specifier with a
possible NULL parameter and since -Werror is used, the compilation breaks
for GCC-9.

In function 'sbi_boot_prints',
    inlined from 'init_coldboot' at <redacted>/opensbi/lib/sbi/sbi_init.c:107:3,
    inlined from 'sbi_init' at <redacted>/opensbi/lib/sbi/sbi_init.c:189:3:
<redacted>/opensbi/lib/sbi/sbi_init.c:56:2: error: '%s' directive argument is null [-Werror=format-overflow=]
   56 |  sbi_printf("Platform Name          : %s\n", sbi_platform_name(plat));
      |  ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
cc1: all warnings being treated as errors

This is one way to fix this, currently there is nothing in the tree
checking for `sbi_platfrom_name() == NULL` so we can just return "Unknown"
instead of NULL on failure.

Signed-off-by: Martin Pietryka <martin@pietryka.at>
Reviewed-by: Anup Patel <anup.patel@wdc.com>
Tested-by: David Abdurachmanov <david.abdurachmanov@sifive.com>
2019-12-06 03:15:50 +05:30
Xiang W
813f7f4c25 lib: Add error detection for misa_extension
Add assertions for misa_extension to prevent incoming illegal
characters.

Signed-off-by: Xiang Wang <merle@hardenedlinux.org>
Reviewed-by: Anup Patel <anup.patel@wdc.com>
2019-11-27 12:10:33 +05:30
Atish Patra
ab14f94a8c lib: Fix probe extension
The break statement is missing in base extension function handling.

Fix the typo.

Signed-off-by: Atish Patra <atish.patra@wdc.com>
Reviewed-by: Xiang Wang <merle@hardenedlinux.org>
Reviewed-by: Anup Patel <anup.patel@wdc.com>
2019-11-26 16:17:52 +05:30
Xiang Wang
c96cc03fcc lib: Fix CPU capabilities detection function
On some platforms, misa may not be implemented. On such a platform,
reading misa will get 0. At this time, platform is required to
implement a non-standard function to detect the CPU's capabilities.
Therefore, this modification add interfaces for non-standard function.

The MXL field of misa is always at the highest two bits, whether it
is a 32-bit 64-bit or a 128-bit machine. Therefore, this modification
fixes the use of a fixed offset to detect the machine length.

Signed-off-by: Xiang Wang <merle@hardenedlinux.org>
Signed-off-by: Anup Patel <anup.patel@wdc.com>
2019-11-26 16:06:29 +05:30
Anup Patel
75f903dd78 lib: Simplify trap parameters in sbi_ecall functions
The out_tcause and out_tval parameters are not sufficient for most
sbi_ecall functions because this will grow in-future when we support
RISC-V hypervisor v0.5 draft. We replace these parameters with out_trap
which is a pointer to struct sbi_trap_info.

Signed-off-by: Anup Patel <anup.patel@wdc.com>
Reviewed-by: Atish Patra <atish.patra@wdc.com>
2019-11-21 13:58:14 +05:30
Anup Patel
0e1322bacb lib: Better naming of unpriv APIs for wider use
The unpriv APIs can be useful to external firmware and out-of-tree
platform support code.

This patch adds "sbi_" prefix to unpriv load/store APIs and rename
struct riscv_unpriv to struct sbi_trap_info everywhere. We also
place struct sbi_trap_info in sbi/sbi_trap.h so that we can use
it for sbi_trap_redirect() as well.

Overall, this patch will make naming of unpriv APIs consistent
with other OpenSBI APIs.

Signed-off-by: Anup Patel <anup.patel@wdc.com>
Reviewed-by: Atish Patra <atish.patra@wdc.com>
2019-11-21 13:57:33 +05:30
Anup Patel
b1d8c988bc lib: No need to set VSSTATUS.MXR bit in get_insn()
We don't need to set VSSTATUS.MXR bit in get_insn() for
unpriv instruction read because MSTATUS.MXR bit applies
to both "Stage1" and "Stage2" page tables.

This also allows us to remove the "virt" parameter of
get_insn() function.

Signed-off-by: Anup Patel <anup.patel@wdc.com>
Reviewed-by: Atish Patra <atish.patra@wdc.com>
2019-11-21 13:56:03 +05:30
Anup Patel
838657c052 include: Remove ilen member of struct unpriv_trap
We simplify struct unpriv_trap by removing ilen member. This
can be achieved by ensuring that at all unpriv load/store
instructions are 4 bytes long using GCC assembler option.

Additionally, this also reduces few instructions from unpriv
load/store functions.

Signed-off-by: Anup Patel <anup.patel@wdc.com>
Reviewed-by: Atish Patra <atish.patra@wdc.com>
2019-11-21 13:54:13 +05:30
Alistair Francis
215421ca61 lib: Remove date and time from init message
Building the date and time into the binary means the OpenSBI isn't
reproducible. We don't really need the time so let's remove it.

Signed-off-by: Alistair Francis <alistair.francis@wdc.com>
Reviewed-by: Anup Patel <anup.patel@wdc.com>
2019-11-15 17:42:55 +05:30
Anup Patel
7a13beb213 firmware: Add preferred boot HART field in struct fw_dynamic_info
It has been reported that link address range of previous booting stage
(such as U-Boot SPL) can overlap the link address rage of FW_DYNAMIC.

This means self-relocation in FW_DYNAMIC can potentially corrupt
previous booting stage if any of the secondary HART enter FW_DYNAMIC
before primary HART.

To tackle this, we add preferred boot HART field (i.e boot_hart) in
struct fw_dyanmic_info. We use this field to force secondary HARTs
into relocation wait loop till preferred/primary boot HART enters
FW_DYNAMIC completes self-relocation. If preferred boot HART is not
available then we fall back to relocation lottery approach.

Signed-off-by: Anup Patel <anup.patel@wdc.com>
Reviewed-by: Atish Patra <atish.patra@wdc.com>
2019-11-15 17:41:18 +05:30
Anup Patel
18897aaf5d include: Use _UL() and _ULL() for defines in riscv_encoding.h
The riscv_encoding.h is shared with assembly sources so we use
_UL() and _ULL() for register fields related defines.

Signed-off-by: Anup Patel <anup.patel@wdc.com>
Reviewed-by: Atish Patra <atish.patra@wdc.com>
2019-11-06 10:37:24 +05:30
Anup Patel
f728a0be42 include: Sync-up encoding with priv v1.12-draft and hypervisor v0.5-draft
This patch sync-up encoding header with the latest privilege
specifications draft v1.12 and hypervisor specifications draft v0.5.

The MSTATUS.MTL and HSTATUS.STL bits are not present anymore and
will be removed by another patch series for hypervisor v0.5-draft.

Signed-off-by: Anup Patel <anup.patel@wdc.com>
Reviewed-by: Atish Patra <atish.patra@wdc.com>
2019-11-06 10:35:41 +05:30
Anup Patel
98f4a20899 firmware: Introduce relocation lottery
Instead of forcing HART0 to do the relocation and scratch init
work, we should have an atomic lottery to decide which HART does
the relocation and scratch init.

This way any HART can be boot/main HART.

Signed-off-by: Anup Patel <anup.patel@wdc.com>
Reviewed-by: Atish Patra <atish.patra@wdc.com>
2019-11-05 08:50:04 +05:30
Anup Patel
dd8ef28b27 firmware: Fix compile error for FW_PAYLOAD with latest GCC binutils
We get following compile error for FW_PAYLOAD with latest GCC
binutils:
fw_payload.o(.text+0x1961): 15 bytes required for alignment to 16-byte
boundary, but only 14 present

Further investigating, it turn-out to be a known issue with RISC-V
GCC binutils.
(Refer, https://github.com/riscv/riscv-gnu-toolchain/issues/298)

As a work-around, we disable relaxation when including DTB and
PAYLOAD binary in fw_payload.S.

Reported-by: David Abdurachmanov <david.abdurachmanov@sifive.com>
Signed-off-by: Anup Patel <anup.patel@wdc.com>
Tested-by: David Abdurachmanov <david.abdurachmanov@sifive.com>
Reviewed-by: Atish Patra <atish.patra@wdc.com>
2019-10-28 20:11:42 +05:30
87 changed files with 3028 additions and 1178 deletions

View File

@@ -12,10 +12,17 @@
# o Do not print "Entering directory ...";
MAKEFLAGS += -r --no-print-directory
# Readlink -f requires GNU readlink
ifeq ($(shell uname -s),Darwin)
READLINK ?= greadlink
else
READLINK ?= readlink
endif
# Find out source, build, and install directories
src_dir=$(CURDIR)
ifdef O
build_dir=$(shell readlink -f $(O))
build_dir=$(shell $(READLINK) -f $(O))
else
build_dir=$(CURDIR)/build
endif
@@ -23,7 +30,7 @@ ifeq ($(build_dir),$(CURDIR))
$(error Build directory is same as source directory.)
endif
ifdef I
install_dir=$(shell readlink -f $(I))
install_dir=$(shell $(READLINK) -f $(I))
else
install_dir=$(CURDIR)/install
endif
@@ -34,7 +41,7 @@ ifeq ($(install_dir),$(build_dir))
$(error Install directory is same as build directory.)
endif
ifdef PLATFORM_DIR
platform_dir_path=$(shell readlink -f $(PLATFORM_DIR))
platform_dir_path=$(shell $(READLINK) -f $(PLATFORM_DIR))
ifdef PLATFORM
platform_parent_dir=$(platform_dir_path)
else
@@ -159,7 +166,7 @@ GENFLAGS += $(libsbiutils-genflags-y)
GENFLAGS += $(platform-genflags-y)
GENFLAGS += $(firmware-genflags-y)
CFLAGS = -g -Wall -Werror -nostdlib -fno-strict-aliasing -O2
CFLAGS = -g -Wall -Werror -ffreestanding -nostdlib -fno-strict-aliasing -O2
CFLAGS += -fno-omit-frame-pointer -fno-optimize-sibling-calls
CFLAGS += -mno-save-restore -mstrict-align
CFLAGS += -mabi=$(PLATFORM_RISCV_ABI) -march=$(PLATFORM_RISCV_ISA)

View File

@@ -16,4 +16,3 @@ The libfdt source code is disjunctively dual licensed (GPL-2.0+ or
BSD-2-Clause). Some of this project code is used in OpenSBI under the terms of
the BSD 2-Clause license. The full text of this license can be found in the
file [COPYING.BSD](COPYING.BSD).

View File

@@ -1,7 +1,10 @@
OpenSBI as coreboot payload
==============================
===========================
[coreboot](https://www.coreboot.org/) is a free/libre and open source firmware platform support multiple hardware architectures( x86, ARMv7, arm64, PowerPC64, MIPS and RISC-V) and diverse hardware models. In RISC-V world, coreboot currently support HiFive Unleashed with OpenSBI as a payload to boot GNU/Linux:
[coreboot] is a free/libre and open source firmware platform support multiple
hardware architectures(x86, ARMv7, arm64, PowerPC64, MIPS and RISC-V) and
diverse hardware models. In RISC-V world, coreboot currently support HiFive
Unleashed with OpenSBI as a payload to boot GNU/Linux:
```
SiFive HiFive unleashed's original firmware boot process:
@@ -21,4 +24,9 @@ coreboot boot process:
+---------------------------------------------+-------------+-------+-+
```
The upstreaming work is still in progress. There's a [documentation](https://github.com/hardenedlinux/embedded-iot_profile/blob/master/docs/riscv/hifiveunleashed_coreboot_notes-en.md) about how to build [out-of-tree code](https://github.com/hardenedlinux/coreboot-HiFiveUnleashed) to load OpenSBI.
The upstreaming work is still in progress. There's a [documentation] about how
to build [out-of-tree code] to load OpenSBI.
[coreboot]: https://www.coreboot.org/
[documentation]: https://github.com/hardenedlinux/embedded-iot_profile/blob/master/docs/riscv/hifiveunleashed_coreboot_notes-en.md
[out-of-tree code]: https://github.com/hardenedlinux/coreboot-HiFiveUnleashed

View File

@@ -38,15 +38,14 @@ follows:
* **FW_JUMP_FDT_ADDR** - Address where the *flattened device tree (FDT file)*
passed by the prior booting stage will be placed in memory before executing
the booting stage following the OpenSBI firmware. If this option is not
provided, then the OpenSBI firmware will pass zero as the FDT address to the
following booting stage.
provided, then the OpenSBI firmware will pass the FDT address passed by the
previous booting stage to the next booting stage.
*FW_JUMP* Example
-----------------
The *[qemu/virt]* and *[qemu/sifive_u]* platforms illustrate how to configure
and use a *FW_JUMP* firmware. Detailed information regarding these platforms
can be found in the platform documentation files.
The *[qemu/virt]* platform illustrates how to configure and use a *FW_JUMP*
firmware. Detailed information regarding these platforms can be found in the
platform documentation files.
[qemu/virt]: ../platform/qemu_virt.md
[qemu/sifive_u]: ../platform/qemu_sifive_u.md

View File

@@ -73,17 +73,17 @@ file. The parameters currently defined are as follows:
stage or specified by the *FW_PAYLOAD_FDT_PATH* parameter and embedded in
the *.text* section will be placed before executing the next booting stage,
that is, the payload firmware. If this option is not provided, then the
firmware will pass zero as the FDT address to the next booting stage.
firmware will pass the FDT address passed by the previous booting stage
to the next booting stage.
*FW_PAYLOAD* Example
--------------------
The *[qemu/virt]* and *[qemu/sifive_u]* platforms illustrate how to configure
and use a *FW_PAYLOAD* firmware. Detailed information regarding these platforms
can be found in the platform documentation files.
The *[qemu/virt]* platforms illustrate how to configure and use a *FW_PAYLOAD*
firmware. Detailed information regarding these platforms can be found in the
platform documentation files.
The *kendryte/k210* platform also enables a build of a *FW_PAYLOAD* using an
internally defined device tree file (*FW_PAYLOAD_FDT*).
[qemu/virt]: ../platform/qemu_virt.md
[qemu/sifive_u]: ../platform/qemu_sifive_u.md

View File

@@ -7,4 +7,3 @@ provided as a payload to OpenSBI.
Detailed examples can be found in both the [QEMU](../platform/qemu_virt.md)
and the [HiFive Unleashed](../platform/sifive_fu540.md) platform guides.

View File

@@ -66,3 +66,24 @@ bootloader to service the following interrupts and traps:
**Note:** external firmwares or bootloaders can be more conservative by
forwarding all traps and interrupts to *sbi_trap_handler()*.
Definitions of OpenSBI Data Types for the External Firmware
-----------------------------------------------------------
OpenSBI can be built as library using external firmware build system such as EDK2
code base (The open source of UEFI firmware implementation) and linked with external
firmware drivers based on the external firmware architecture.
**OPENSBI_EXTERNAL_SBI_TYPES** identifier is introduced to *sbi_types.h* for selecting
external header file during the build preprocess in order to define OpensSBI data types
based on external firmware data type binding.
For example, *bool* is declared as *int* in sbi_types.h. However in EDK2 build system,
*bool* is declared as *BOOLEAN* which is defined as *unsigned char* data type.
External firmware can define **OPENSBI_EXTERNAL_SBI_TYPES** in CFLAGS and specify it to the
header file maintained in its code tree. However, the external build system has to address
the additional include directory for the external header file based on its own build system.
For example,
*-D***OPENSBI_EXTERNAL_SBI_TYPES***=OpensbiTypes.h*
Above tells *sbi_types.h* to refer to *OpensbiTypes.h* instead of using original definitions of
data types.

View File

@@ -1,13 +1,14 @@
Andes AE350 SoC Platform
========================
The AE350 AXI/AHB-based platform N25(F)/NX25(F)/D25F/A25/AX25 CPU with
level-one memories,interrupt controller, debug module, AXI and AHB Bus
Matrix Controller, AXI-to-AHB Bridge and a collection of fundamentalAHB/APB
bus IP components pre-integrated together as a system design.The high-quality
and configurable AHB/APB IPs suites a majority embedded systems,
and the verified platform serves as a starting point to jump start SoC designs.
The AE350 AXI/AHB-based platform N25(F)/NX25(F)/D25F/A25/AX25 CPU with level-one
memories,interrupt controller, debug module, AXI and AHB Bus Matrix Controller,
AXI-to-AHB Bridge and a collection of fundamentalAHB/APB bus IP components
pre-integrated together as a system design.The high-quality and configurable
AHB/APB IPs suites a majority embedded systems, and the verified platform serves
as a starting point to jump start SoC designs.
To build platform specific library and firmwares, provide the *PLATFORM=andes/ae350* parameter to the top level make command.
To build platform specific library and firmwares, provide the
*PLATFORM=andes/ae350* parameter to the top level make command.
Platform Options
----------------
@@ -17,7 +18,8 @@ The Andes AE350 platform does not have any platform-specific options.
Building Andes AE350 Platform
-----------------------------
To use Linux v5.2 should be used to build Andes AE350 OpenSBI binaries by using the compile time option FW_PAYLOAD_FDT_PATH.
To use Linux v5.2 should be used to build Andes AE350 OpenSBI binaries by using
the compile time option FW_PAYLOAD_FDT_PATH.
AE350's dts is included in https://github.com/andestech/linux/tree/ast-v3_2_0-release-public

View File

@@ -1,9 +1,11 @@
Ariane FPGA SoC Platform
==========================
Ariane is a 6-stage, single issue, in-order CPU which implements the 64-bit RISC-V instruction set.
The Ariane FPGA development platform is based on FPGA FPGA SoC(which currently supports only Genesys 2 board) and is capable
of running Linux.
The FPGA SoC currently contains the following peripherals:
========================
Ariane is a 6-stage, single issue, in-order CPU which implements the 64-bit
RISC-V instruction set. The Ariane FPGA development platform is based on FPGA
SoC (which currently supports only Genesys 2 board) and is capable of running
Linux.
The FPGA SoC currently contains the following peripherals:
- DDR3 memory controller
- SPI controller to conncet to an SDCard
- Ethernet controller
@@ -16,22 +18,21 @@ To build platform specific library and firmwares, provide the
Platform Options
----------------
The *Ariane FPGA* platform does not have any platform-specific
options.
The *Ariane FPGA* platform does not have any platform-specific options.
Building Ariane FPGA Platform
-----------------------------
**Linux Kernel Payload**
**Linux Kernel Payload**
```
make PLATFORM=ariane-fpga FW_PAYLOAD_PATH=<linux_build_directory>/arch/riscv/boot/Image
```
Booting Ariane FPGA Platform
-----------------------------
----------------------------
**Linux Kernel Payload**
As Linux kernel image is embedded in the OpenSBI firmware binary, Ariane will directly
boot into Linux directly after powered on.
As Linux kernel image is embedded in the OpenSBI firmware binary, Ariane will
directly boot into Linux directly after powered on.

View File

@@ -8,14 +8,9 @@ OpenSBI currently supports the following virtual and hardware platforms:
development and tests. More details on this platform can be found in the
file *[qemu_virt.md]*.
* **QEMU SiFive Unleashed Machine**: Platform support for the *sifive_u* QEMU
virtual RISC-V machine. This is an emulation machine of the HiFive Unleashed
board by SiFive. More details on this platform can be found in the file
*[qemu_sifive_u.md]*.
* **SiFive FU540 SoC**: Platform support for SiFive FU540 SoC used on the
HiFive Unleashed board. This platform is very similar to the *QEMU sifive_u*
platform. More details on this platform can be found in the file
HiFive Unleashed board, as well as the *sifive_u* QEMU virtual RISC-V
machine. More details on this platform can be found in the file
*[sifive_fu540.md]*.
* **Kendryte K210 SoC**: Platform support for the Kendryte K210 SoC used on
@@ -26,6 +21,10 @@ OpenSBI currently supports the following virtual and hardware platforms:
* **Andes AE350 SoC**: Platform support for the Andes's SoC (AE350).
* **T-HEAD C910**: Platform support for the T-HEAD C910 Processor.
* **Spike**: Platform support for the Spike emulator.
The code for these supported platforms can be used as example to implement
support for other platforms. The *platform/template* directory also provides
template files for implementing support for a new platform. The *object.mk*,
@@ -33,7 +32,8 @@ template files for implementing support for a new platform. The *object.mk*,
facilitate the implementation.
[qemu_virt.md]: qemu_virt.md
[qemu_sifive_u.md]: qemu_sifive_u.md
[sifive_fu540.md]: sifive_fu540.md
[ariane-fpga.md]: ariane-fpga.md
[andes_ae350.md]: andes-ae350.md
[thead-c910.md]: thead-c910.md
[spike.md]: spike.md

View File

@@ -1,60 +0,0 @@
QEMU SiFive Unleashed Machine Platform
======================================
The **QEMU SiFive Unleashed Machine** is an emulation of the SiFive Unleashed
platform.
To build this platform specific library and firmwares, provide the
*PLATFORM=qemu/sifive_u* parameter to the top level `make` command line.
Note with QEMU v4.2 release, the QEMU *sifive_u* machine has been updated to
closely match the SiFive HiFive Unleashed hardware and can therefore run the
same firmware as what gets loaded onto the board, and OpenSBI's *qemu/sifive_u*
platform should only be used with QEMU v4.1 release or before.
The special *qemu/sifive_u* platform support will be dropped in the future
OpenSBI release.
Platform Options
----------------
The *QEMU SiFive Unleashed Machine* platform does not have any platform specific
options.
Executing on QEMU RISC-V 64-bit
-------------------------------
**No Payload Case**
Build:
```
make PLATFORM=qemu/sifive_u
```
Run:
```
qemu-system-riscv64 -M sifive_u -m 256M -display none -serial stdio \
-kernel build/platform/qemu/sifive_u/firmware/fw_payload.elf
```
**U-Boot as a Payload**
Note: the command line examples here assume that U-Boot was compiled using
the `sifive_fu540_defconfig` configuration.
Build:
```
make PLATFORM=qemu/sifive_u FW_PAYLOAD_PATH=<uboot_build_directory>/u-boot.bin
```
Run:
```
qemu-system-riscv64 -M sifive_u -m 256M -display none -serial stdio \
-kernel build/platform/qemu/sifive_u/firmware/fw_payload.elf
```
or
```
qemu-system-riscv64 -M sifive_u -m 256M -display none -serial stdio \
-kernel build/platform/qemu/sifive_u/firmware/fw_jump.elf \
-device loader,file=<uboot_build_directory>/u-boot.bin,addr=0x80200000
```

View File

@@ -149,4 +149,3 @@ qemu-system-riscv32 -M virt -m 256M -nographic \
-device virtio-blk-device,drive=hd0 \
-append "root=/dev/vda rw console=ttyS0"
```

View File

@@ -1,5 +1,5 @@
SiFive FU540 SoC Platform
==========================
=========================
The FU540-C000 is the worlds first 4+1 64-bit RISC-V SoC from SiFive.
The HiFive Unleashed development platform is based on FU540-C000 and capable
of running Linux.
@@ -25,10 +25,10 @@ make PLATFORM=sifive/fu540 FW_PAYLOAD_PATH=Image FU540_ENABLED_HART_MASK=0x02
This will let the board boot only hart1 instead of default 1-4.
Building SiFive Fu540 Platform
-----------------------------
------------------------------
In order to boot SMP Linux in U-Boot, Linux v5.1 (or higher) and latest
U-Boot v2019.04 (or higher) should be used.
U-Boot v2020.01 (or higher) should be used.
**Linux Kernel Payload**
@@ -49,24 +49,12 @@ make PLATFORM=sifive/fu540 FW_PAYLOAD_PATH=<linux_build_directory>/arch/riscv/bo
**U-Boot Payload**
The command-line example here assumes that U-Boot was compiled using the
sifive_fu540_defconfig configuration and with U-Boot v2019.04 (or higher)
having SMP support. From, Linux v5.2 (or higher) device tree is hosted in
Linux kernel and compiled as a part of Linux kernel build process.
sifive_fu540_defconfig configuration and with U-Boot v2020.01 (or higher).
The detailed U-Boot booting guide is avaialble at [U-Boot](https://gitlab.denx.de/u-boot/u-boot/blob/master/doc/board/sifive/fu540.rst)
The detailed U-Boot booting guide is avaialble at [U-Boot].
```
make PLATFORM=sifive/fu540 FW_PAYLOAD_PATH=<u-boot_build_dir>/u-boot.bin
or
(For U-Boot which follows Linux v5.2 (or higher) DT bindings)
make PLATFORM=sifive/fu540 FW_PAYLOAD_PATH=<u-boot_build_dir>/u-boot.bin FW_PAYLOAD_FDT_PATH=<hifive-unleashed-a00.dtb path from Linux kernel>
```
Generate the uImage from Linux Image.
```
mkimage -A riscv -O linux -T kernel -C none -a 0x80200000 -e 0x80200000 -n Linux -d \
<linux_build_directory>/arch/riscv/boot/Image \
<linux_build_directory>/arch/riscv/boot/uImage
make PLATFORM=sifive/fu540 FW_PAYLOAD_PATH=<u-boot_build_dir>/u-boot-dtb.bin
```
**U-Boot & Linux Kernel as a single payload**
@@ -74,37 +62,29 @@ mkimage -A riscv -O linux -T kernel -C none -a 0x80200000 -e 0x80200000 -n Linux
A single monolithic image containing both U-Boot & Linux can also be used if
network boot setup is not available.
1. Generate the uImage from Linux Image.
```
mkimage -A riscv -O linux -T kernel -C none -a 0x80200000 -e 0x80200000 -n Linux -d \
<linux_build_directory>/arch/riscv/boot/Image \
<linux_build_directory>/arch/riscv/boot/uImage
```
2. Create a temporary image with u-boot.bin as the first payload. The
1. Create a temporary image with u-boot-dtb.bin as the first payload. The
command-line example here assumes that U-Boot was compiled using
sifive_fu540_defconfig configuration.
```
dd if=~/workspace/u-boot-riscv/u-boot.bin of=/tmp/temp.bin bs=1M
dd if=~/workspace/u-boot-riscv/u-boot-dtb.bin of=/tmp/temp.bin bs=1M
```
3. Append the Linux Kernel image generated in step 1.
2. Append the Linux Kernel image.
```
dd if=<linux_build_directory>/arch/riscv/boot/uImage of=/tmp/temp.bin bs=1M seek=4
dd if=<linux_build_directory>/arch/riscv/boot/Image of=/tmp/temp.bin bs=1M seek=4
```
4. Compile OpenSBI with temp.bin (generated in step 3) as payload.
3. Compile OpenSBI with temp.bin (generated in step 2) as payload.
```
make PLATFORM=sifive/fu540 FW_PAYLOAD_PATH=/tmp/temp.bin
or
(For U-Boot which follows Linux v5.2 (or higher) DT bindings)
make PLATFORM=sifive/fu540 FW_PAYLOAD_PATH=/tmp/temp.bin FW_PAYLOAD_FDT_PATH=<hifive-unleashed-a00.dtb path from Linux kernel>
make PLATFORM=sifive/fu540 FW_PAYLOAD_PATH=/tmp/temp.bin
```
Flashing the OpenSBI firmware binary to storage media:
-----------------------------------------------------
The first stage boot loader([FSBL](https://github.com/sifive/freedom-u540-c000-bootloader))
expects the storage media to have a GPT partition table. It tries to look for
a partition with following GUID to load the next stage boot loader (OpenSBI
in this case).
------------------------------------------------------
The first stage boot loader ([FSBL]) expects the storage media to have a GPT
partition table. It tries to look for a partition with following GUID to load
the next stage boot loader (OpenSBI in this case).
```
2E54B353-1271-4842-806F-E436D6AF6985
@@ -144,43 +124,33 @@ As U-Boot image is used as payload, HiFive Unleashed will boot into a U-Boot
prompt. U-Boot tftp boot method can be used to load kernel image in U-Boot
prompt. Here are the steps do a tftpboot.
1. Set the mac address of the board.
```
setenv ethaddr <mac address of the board>
```
(Note: This step is optional)
2. Set the ip address of the board.
1. Set the ip address of the board.
```
setenv ipaddr <ipaddr of the board>
```
3. Set the tftpboot server IP.
2. Set the tftpboot server IP.
```
setenv serverip <ipaddr of the tftp server>
```
4. Set the network gateway address.
3. Set the network gateway address.
```
setenv gatewayip <ipaddress of the network gateway>
```
5. Load the Linux kernel image from the tftp server.
4. Load the Linux kernel image from the tftp server.
```
tftpboot ${kernel_addr_r} <uImage path in tftpboot directory>
tftpboot ${kernel_addr_r} <Image path in tftpboot directory>
```
6. Load the ramdisk image from the tftp server. This is only required if
5. Load the ramdisk image from the tftp server. This is only required if
ramdisk is loaded from tftp server. This step is optional, if rootfs is
already part of the kernel or loaded from an external storage by kernel.
```
tftpboot ${ramdisk_addr_r} <ramdisk path in tftpboot directory>
```
7. Load the pre-compiled device tree via tftpboot.
6. Load the pre-compiled device tree via tftpboot.
```
tftpboot ${fdt_addr_r} <linux source>/arch/riscv/boot/dts/sifive/hifive-unleashed-a00.dtb
tftpboot ${fdt_addr_r} <hifive-unleashed-a00.dtb path in tftpboot directory>
```
8. Set the boot command-line arguments.
7. Set the boot command-line arguments.
```
setenv bootargs "root=<root partition> rw console=ttySIF0 earlycon=sbi"
```
@@ -188,13 +158,12 @@ setenv bootargs "root=<root partition> rw console=ttySIF0 earlycon=sbi"
** /dev/ram ** - If a ramdisk is used
** root=/dev/mmcblk0pX ** - If a rootfs is already on some other partition
of sdcard)
9. Now boot into Linux.
8. Now boot into Linux.
```
bootm ${kernel_addr_r} ${ramdisk_addr_r} ${fdt_addr_r}
booti ${kernel_addr_r} ${ramdisk_addr_r} ${fdt_addr_r}
or
(If ramdisk is not loaded from network)
bootm ${kernel_addr_r} - ${fdt_addr_r}
booti ${kernel_addr_r} - ${fdt_addr_r}
```
**U-Boot & Linux Kernel as a single payload**
@@ -202,7 +171,7 @@ bootm ${kernel_addr_r} - ${fdt_addr_r}
At U-Boot prompt execute the following boot command to boot Linux.
```
bootm ${kernel_addr_r} - ${fdt_addr_r}
booti ${kernel_addr_r} - ${fdt_addr_r}
```
QEMU Specific Instructions
@@ -213,3 +182,20 @@ same instructions above, with the exception of not passing FW_PAYLOAD_FDT_PATH.
This is because QEMU generates a device tree blob on the fly based on the
command line parameters and it's compatible with the one used in the upstream
Linux kernel.
When U-Boot v2020.01 (or higher) is used as the payload, as the SiFive FU540
DTB for the real hardware is embedded in U-Boot binary itself, due to the same
reason above, we need to switch the U-Boot sifive_fu540_defconfig configuration
from CONFIG_OF_SEPARATE to CONFIG_OF_PRIOR_STAGE so that U-Boot uses the DTB
generated by QEMU, and u-boot.bin should be used as the payload image, like:
```
make PLATFORM=sifive/fu540 FW_PAYLOAD_PATH=<u-boot_build_dir>/u-boot.bin
```
While the real hardware operates at the 64-bit mode, it's possible for QEMU to
test the 32-bit OpenSBI firmware. This can be helpful for testing 32-bit SiFive
specific drivers.
[U-Boot]: https://gitlab.denx.de/u-boot/u-boot/blob/master/doc/board/sifive/fu540.rst
[FSBL]: https://github.com/sifive/freedom-u540-c000-bootloader

89
docs/platform/spike.md Normal file
View File

@@ -0,0 +1,89 @@
Spike Simulator Platform
========================
The **Spike** is a RISC-V ISA simulator which implements a functional model
of one or more RISC-V harts. The **Spike** compatible virtual platform is
also available on QEMU. In fact, we can use same OpenSBI firmware binaries
on **Spike** simulator and QEMU Spike machine.
For more details, refer [Spike on GitHub](https://github.com/riscv/riscv-isa-sim)
To build the platform-specific library and firmware images, provide the
*PLATFORM=spike* parameter to the top level `make` command.
Platform Options
----------------
The *Spike* platform does not have any platform-specific options.
Execution on Spike Simulator
----------------------------
**No Payload Case**
Build:
```
make PLATFORM=spike
```
Run:
```
spike build/platform/spike/firmware/fw_payload.elf
```
**Linux Kernel Payload**
Note: We assume that the Linux kernel is compiled using
*arch/riscv/configs/defconfig*.
Build:
```
make PLATFORM=spike FW_PAYLOAD_PATH=<linux_build_directory>/arch/riscv/boot/Image
```
Run:
```
spike --initrd <path_to_cpio_ramdisk> build/platform/spike/firmware/fw_payload.elf
```
Execution on QEMU RISC-V 64-bit
-------------------------------
**No Payload Case**
Build:
```
make PLATFORM=spike
```
Run:
```
qemu-system-riscv64 -M spike -m 256M -nographic \
-kernel build/platform/spike/firmware/fw_payload.elf
```
**Linux Kernel Payload**
Note: We assume that the Linux kernel is compiled using
*arch/riscv/configs/defconfig*.
Build:
```
make PLATFORM=spike FW_PAYLOAD_PATH=<linux_build_directory>/arch/riscv/boot/Image
```
Run:
```
qemu-system-riscv64 -M spike -m 256M -nographic \
-kernel build/platform/spike/firmware/fw_payload.elf \
-initrd <path_to_cpio_ramdisk> \
-append "root=/dev/ram rw console=hvc0 earlycon=sbi"
```
or
```
qemu-system-riscv64 -M spike -m 256M -nographic \
-bios build/platform/spike/firmware/fw_jump.elf \
-kernel <linux_build_directory>/arch/riscv/boot/Image \
-initrd <path_to_cpio_ramdisk> \
-append "root=/dev/ram rw console=hvc0 earlycon=sbi"
```

View File

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

View File

@@ -41,17 +41,26 @@
999:
.endm
.align 3
.section .entry, "ax", %progbits
.align 3
.globl _start
.globl _start_warm
_start:
/*
* Jump to warm-boot if this is not the first core booting,
* that is, for mhartid != 0
*/
csrr a6, CSR_MHARTID
blt zero, a6, _wait_relocate_copy_done
/* Find preferred boot HART id */
MOV_3R s0, a0, s1, a1, s2, a2
call fw_boot_hart
add a6, a0, zero
MOV_3R a0, s0, a1, s1, a2, s2
li a7, -1
beq a6, a7, _try_lottery
/* Jump to relocation wait loop if we are not boot hart */
bne a0, a6, _wait_relocate_copy_done
_try_lottery:
/* Jump to relocation wait loop if we don't get relocation lottery */
la a6, _relocate_lottery
li a7, 1
amoadd.w a6, a7, (a6)
bnez a6, _wait_relocate_copy_done
/* Save load address */
la t0, _load_start
@@ -75,6 +84,8 @@ _relocate:
blt t2, t0, _relocate_copy_to_upper
_relocate_copy_to_lower:
ble t1, t2, _relocate_copy_to_lower_loop
la t3, _relocate_lottery
BRANGE t2, t1, t3, _start_hang
la t3, _boot_status
BRANGE t2, t1, t3, _start_hang
la t3, _relocate
@@ -91,6 +102,8 @@ _relocate_copy_to_lower_loop:
jr t4
_relocate_copy_to_upper:
ble t3, t0, _relocate_copy_to_upper_loop
la t2, _relocate_lottery
BRANGE t0, t3, t2, _start_hang
la t2, _boot_status
BRANGE t0, t3, t2, _start_hang
la t2, _relocate
@@ -381,6 +394,8 @@ _start_warm:
j _start_hang
.align 3
_relocate_lottery:
RISCV_PTR 0
_boot_status:
RISCV_PTR 0
_load_start:
@@ -390,8 +405,8 @@ _link_start:
_link_end:
RISCV_PTR _fw_reloc_end
.align 3
.section .entry, "ax", %progbits
.align 3
.globl _hartid_to_scratch
_hartid_to_scratch:
add sp, sp, -(3 * __SIZEOF_POINTER__)
@@ -425,15 +440,15 @@ _hartid_to_scratch:
add sp, sp, (3 * __SIZEOF_POINTER__)
ret
.align 3
.section .entry, "ax", %progbits
.align 3
.globl _start_hang
_start_hang:
wfi
j _start_hang
.align 3
.section .entry, "ax", %progbits
.align 3
.globl _trap_handler
_trap_handler:
/* Swap TP and MSCRATCH */
@@ -588,8 +603,8 @@ _skip_mstatush_restore:
mret
.align 3
.section .entry, "ax", %progbits
.align 3
.globl _reset_regs
_reset_regs:

View File

@@ -11,14 +11,40 @@
#include "fw_base.S"
.align 3
.section .entry, "ax", %progbits
.align 3
_bad_dynamic_info:
wfi
j _bad_dynamic_info
.align 3
.section .entry, "ax", %progbits
.align 3
.global fw_boot_hart
/*
* This function is called very early even before
* fw_save_info() is called.
* We can only use a0, a1, and a2 registers here.
* The boot HART id should be returned in 'a0'.
*/
fw_boot_hart:
/* Sanity checks */
li a1, FW_DYNAMIC_INFO_MAGIC_VALUE
REG_L a0, FW_DYNAMIC_INFO_MAGIC_OFFSET(a2)
bne a0, a1, _bad_dynamic_info
li a1, FW_DYNAMIC_INFO_VERSION_MAX
REG_L a0, FW_DYNAMIC_INFO_VERSION_OFFSET(a2)
bgt a0, a1, _bad_dynamic_info
/* Read boot HART id */
li a1, 0x2
blt a0, a1, 2f
REG_L a0, FW_DYNAMIC_INFO_BOOT_HART_OFFSET(a2)
ret
2: li a0, -1
ret
.section .entry, "ax", %progbits
.align 3
.global fw_save_info
/*
* We can only use a0, a1, a2, a3, and a4 registers here.
@@ -27,14 +53,19 @@ _bad_dynamic_info:
* Nothing to be returned here.
*/
fw_save_info:
/* Save next arg1 in 'a1' */
la a4, _dynamic_next_arg1
REG_S a1, (a4)
/* Sanity checks */
li a4, FW_DYNAMIC_INFO_MAGIC_VALUE
REG_L a3, FW_DYNAMIC_INFO_MAGIC_OFFSET(a2)
bne a3, a4, _bad_dynamic_info
li a4, FW_DYNAMIC_INFO_VERSION_MAX
REG_L a3, FW_DYNAMIC_INFO_VERSION_OFFSET(a2)
bgt a3, a4, _bad_dynamic_info
/* Save version == 0x1 fields */
la a4, _dynamic_next_addr
REG_L a3, FW_DYNAMIC_INFO_NEXT_ADDR_OFFSET(a2)
REG_S a3, (a4)
@@ -44,24 +75,37 @@ fw_save_info:
la a4, _dynamic_options
REG_L a3, FW_DYNAMIC_INFO_OPTIONS_OFFSET(a2)
REG_S a3, (a4)
/* Save version == 0x2 fields */
li a4, 0x2
REG_L a3, FW_DYNAMIC_INFO_VERSION_OFFSET(a2)
blt a3, a4, 2f
la a4, _dynamic_boot_hart
REG_L a3, FW_DYNAMIC_INFO_BOOT_HART_OFFSET(a2)
REG_S a3, (a4)
2:
ret
.align 3
.section .entry, "ax", %progbits
.align 3
.global fw_prev_arg1
/*
* We can only use a0, a1, and a2 registers here.
* The a0, a1, and a2 registers will be same as passed by
* previous booting stage.
* The previous arg1 should be returned in 'a0'.
*/
fw_prev_arg1:
add a0, zero, zero
ret
.align 3
.section .entry, "ax", %progbits
.align 3
.global fw_next_arg1
/*
* We can only use a0, a1, and a2 registers here.
* The a0, a1, and a2 registers will be same as passed by
* previous booting stage.
* The next arg1 should be returned in 'a0'.
*/
fw_next_arg1:
@@ -69,8 +113,8 @@ fw_next_arg1:
REG_L a0, (a0)
ret
.align 3
.section .entry, "ax", %progbits
.align 3
.global fw_next_addr
/*
* We can only use a0, a1, and a2 registers here.
@@ -81,8 +125,8 @@ fw_next_addr:
REG_L a0, (a0)
ret
.align 3
.section .entry, "ax", %progbits
.align 3
.global fw_next_mode
/*
* We can only use a0, a1, and a2 registers here.
@@ -93,8 +137,8 @@ fw_next_mode:
REG_L a0, (a0)
ret
.align 3
.section .entry, "ax", %progbits
.align 3
.global fw_options
/*
* We can only use a0, a1, and a2 registers here.
@@ -106,8 +150,8 @@ fw_options:
REG_L a0, (a0)
ret
.align 3
.section .entry, "ax", %progbits
.align 3
_dynamic_next_arg1:
RISCV_PTR 0x0
_dynamic_next_addr:
@@ -116,3 +160,5 @@ _dynamic_next_mode:
RISCV_PTR PRV_S
_dynamic_options:
RISCV_PTR 0x0
_dynamic_boot_hart:
RISCV_PTR -1

View File

@@ -9,8 +9,21 @@
#include "fw_base.S"
.align 3
.section .entry, "ax", %progbits
.align 3
.global fw_boot_hart
/*
* This function is called very early even before
* fw_save_info() is called.
* We can only use a0, a1, and a2 registers here.
* The boot HART id should be returned in 'a0'.
*/
fw_boot_hart:
li a0, -1
ret
.section .entry, "ax", %progbits
.align 3
.global fw_save_info
/*
* We can only use a0, a1, a2, a3, and a4 registers here.
@@ -21,34 +34,38 @@
fw_save_info:
ret
.align 3
.section .entry, "ax", %progbits
.align 3
.global fw_prev_arg1
/*
* We can only use a0, a1, and a2 registers here.
* The a0, a1, and a2 registers will be same as passed by
* previous booting stage.
* The previous arg1 should be returned in 'a0'.
*/
fw_prev_arg1:
add a0, zero, zero
ret
.align 3
.section .entry, "ax", %progbits
.align 3
.global fw_next_arg1
/*
* We can only use a0, a1, and a2 registers here.
* The a0, a1, and a2 registers will be same as passed by
* previous booting stage.
* The next arg1 should be returned in 'a0'.
*/
fw_next_arg1:
#ifdef FW_JUMP_FDT_ADDR
li a0, FW_JUMP_FDT_ADDR
#else
add a0, zero, zero
add a0, a1, zero
#endif
ret
.align 3
.section .entry, "ax", %progbits
.align 3
.global fw_next_addr
/*
* We can only use a0, a1, and a2 registers here.
@@ -59,8 +76,8 @@ fw_next_addr:
REG_L a0, (a0)
ret
.align 3
.section .entry, "ax", %progbits
.align 3
.global fw_next_mode
/*
* We can only use a0, a1, and a2 registers here.
@@ -70,8 +87,8 @@ fw_next_mode:
li a0, PRV_S
ret
.align 3
.section .entry, "ax", %progbits
.align 3
.global fw_options
/*
* We can only use a0, a1, and a2 registers here.
@@ -86,7 +103,7 @@ fw_options:
#error "Must define FW_JUMP_ADDR"
#endif
.align 3
.section .entry, "ax", %progbits
.align 3
_jump_addr:
RISCV_PTR FW_JUMP_ADDR

View File

@@ -9,8 +9,21 @@
#include "fw_base.S"
.align 3
.section .entry, "ax", %progbits
.align 3
.global fw_boot_hart
/*
* This function is called very early even before
* fw_save_info() is called.
* We can only use a0, a1, and a2 registers here.
* The boot HART id should be returned in 'a0'.
*/
fw_boot_hart:
li a0, -1
ret
.section .entry, "ax", %progbits
.align 3
.global fw_save_info
/*
* We can only use a0, a1, a2, a3, and a4 registers here.
@@ -21,11 +34,13 @@
fw_save_info:
ret
.align 3
.section .entry, "ax", %progbits
.align 3
.global fw_prev_arg1
/*
* We can only use a0, a1, and a2 registers here.
* The a0, a1, and a2 registers will be same as passed by
* previous booting stage.
* The previous arg1 should be returned in 'a0'.
*/
fw_prev_arg1:
@@ -36,23 +51,25 @@ fw_prev_arg1:
#endif
ret
.align 3
.section .entry, "ax", %progbits
.align 3
.global fw_next_arg1
/*
* We can only use a0, a1, and a2 registers here.
* The a0, a1, and a2 registers will be same as passed by
* previous booting stage.
* The next arg1 should be returned in 'a0'.
*/
fw_next_arg1:
#ifdef FW_PAYLOAD_FDT_ADDR
li a0, FW_PAYLOAD_FDT_ADDR
#else
add a0, zero, zero
add a0, a1, zero
#endif
ret
.align 3
.section .entry, "ax", %progbits
.align 3
.global fw_next_addr
/*
* We can only use a0, a1, and a2 registers here.
@@ -62,8 +79,8 @@ fw_next_addr:
la a0, payload_bin
ret
.align 3
.section .entry, "ax", %progbits
.align 3
.global fw_next_mode
/*
* We can only use a0, a1, and a2 registers here.
@@ -73,8 +90,8 @@ fw_next_mode:
li a0, PRV_S
ret
.align 3
.section .entry, "ax", %progbits
.align 3
.global fw_options
/*
* We can only use a0, a1, and a2 registers here.
@@ -86,15 +103,15 @@ fw_options:
ret
#ifdef FW_PAYLOAD_FDT_PATH
.align 4
.section .text, "ax", %progbits
.align 4
.globl fdt_bin
fdt_bin:
.incbin FW_PAYLOAD_FDT_PATH
#endif
.align 4
.section .payload, "ax", %progbits
.align 4
.globl payload_bin
payload_bin:
#ifndef FW_PAYLOAD_PATH

View File

@@ -23,8 +23,8 @@
#define REG_L __REG_SEL(ld, lw)
#define REG_S __REG_SEL(sd, sw)
.align 3
.section .entry, "ax", %progbits
.align 3
.globl _start
_start:
/* Pick one hart to run the main boot sequence */
@@ -71,15 +71,15 @@ _start_warm:
/* We don't expect to reach here hence just hang */
j _start_hang
.align 3
.section .entry, "ax", %progbits
.align 3
.globl _start_hang
_start_hang:
wfi
j _start_hang
.align 3
.section .entry, "ax", %progbits
.align 3
_hart_lottery:
RISCV_PTR 0
_boot_a0:

View File

@@ -18,18 +18,20 @@
#define FW_DYNAMIC_INFO_MAGIC_OFFSET (0 * __SIZEOF_POINTER__)
/** Offset of version member in fw_dynamic_info */
#define FW_DYNAMIC_INFO_VERSION_OFFSET (1 * __SIZEOF_POINTER__)
/** Offset of next_addr member in fw_dynamic_info */
/** Offset of next_addr member in fw_dynamic_info (version >= 1) */
#define FW_DYNAMIC_INFO_NEXT_ADDR_OFFSET (2 * __SIZEOF_POINTER__)
/** Offset of next_mode member in fw_dynamic_info */
/** Offset of next_mode member in fw_dynamic_info (version >= 1) */
#define FW_DYNAMIC_INFO_NEXT_MODE_OFFSET (3 * __SIZEOF_POINTER__)
/** Offset of options member in fw_dynamic_info */
/** Offset of options member in fw_dynamic_info (version >= 1) */
#define FW_DYNAMIC_INFO_OPTIONS_OFFSET (4 * __SIZEOF_POINTER__)
/** Offset of boot_hart member in fw_dynamic_info (version >= 2) */
#define FW_DYNAMIC_INFO_BOOT_HART_OFFSET (5 * __SIZEOF_POINTER__)
/** Expected value of info magic ('OSBI' ascii string in hex) */
#define FW_DYNAMIC_INFO_MAGIC_VALUE 0x4942534f
/** Maximum supported info version */
#define FW_DYNAMIC_INFO_VERSION_MAX 0x1
#define FW_DYNAMIC_INFO_VERSION_MAX 0x2
/** Possible next mode values */
#define FW_DYNAMIC_INFO_NEXT_MODE_U 0x0
@@ -54,6 +56,22 @@ struct fw_dynamic_info {
unsigned long next_mode;
/** Options for OpenSBI library */
unsigned long options;
/**
* Preferred boot HART id
*
* It is possible that the previous booting stage uses same link
* address as the FW_DYNAMIC firmware. In this case, the relocation
* lottery mechanism can potentially overwrite the previous booting
* stage while other HARTs are still running in the previous booting
* stage leading to boot-time crash. To avoid this boot-time crash,
* the previous booting stage can specify last HART that will jump
* to the FW_DYNAMIC firmware as the preferred boot HART.
*
* To avoid specifying a preferred boot HART, the previous booting
* stage can set it to -1UL which will force the FW_DYNAMIC firmware
* to use the relocation lottery mechanism.
*/
unsigned long boot_hart;
} __packed;
#endif

View File

@@ -159,22 +159,26 @@ void csr_write_num(int csr_num, unsigned long val);
__asm__ __volatile__("wfi" ::: "memory"); \
} while (0)
static inline int misa_extension(char ext)
{
return csr_read(CSR_MISA) & (1 << (ext - 'A'));
}
static inline int misa_xlen(void)
{
return ((long)csr_read(CSR_MISA) < 0) ? 64 : 32;
}
/* determine CPU extension, return non-zero support */
int misa_extension_imp(char ext);
#define misa_extension(c)\
({\
_Static_assert(((c >= 'A') && (c <= 'Z')),\
"The parameter of misa_extension must be [A-Z]");\
misa_extension_imp(c);\
})
/* Get MXL field of misa, return -1 on error */
int misa_xlen(void);
static inline void misa_string(char *out, unsigned int out_sz)
{
unsigned long i, val = csr_read(CSR_MISA);
unsigned long i;
for (i = 0; i < 26; i++) {
if (val & (1 << i)) {
if (misa_extension_imp('A' + i)) {
*out = 'A' + i;
out++;
}

View File

@@ -12,193 +12,125 @@
#include <sbi/sbi_const.h>
/* TODO: Make constants usable in assembly with _AC() macro */
/* clang-format off */
#define MSTATUS_UIE 0x00000001
#define MSTATUS_SIE 0x00000002
#define MSTATUS_HIE 0x00000004
#define MSTATUS_MIE 0x00000008
#define MSTATUS_UPIE 0x00000010
#define MSTATUS_SIE _UL(0x00000002)
#define MSTATUS_MIE _UL(0x00000008)
#define MSTATUS_SPIE_SHIFT 5
#define MSTATUS_SPIE (1UL << MSTATUS_SPIE_SHIFT)
#define MSTATUS_HPIE 0x00000040
#define MSTATUS_MPIE 0x00000080
#define MSTATUS_SPIE (_UL(1) << MSTATUS_SPIE_SHIFT)
#define MSTATUS_UBE _UL(0x00000040)
#define MSTATUS_MPIE _UL(0x00000080)
#define MSTATUS_SPP_SHIFT 8
#define MSTATUS_SPP (1UL << MSTATUS_SPP_SHIFT)
#define MSTATUS_HPP 0x00000600
#define MSTATUS_SPP (_UL(1) << MSTATUS_SPP_SHIFT)
#define MSTATUS_MPP_SHIFT 11
#define MSTATUS_MPP (3UL << MSTATUS_MPP_SHIFT)
#define MSTATUS_FS 0x00006000
#define MSTATUS_XS 0x00018000
#define MSTATUS_MPRV 0x00020000
#define MSTATUS_SUM 0x00040000
#define MSTATUS_MXR 0x00080000
#define MSTATUS_TVM 0x00100000
#define MSTATUS_TW 0x00200000
#define MSTATUS_TSR 0x00400000
#define MSTATUS32_SD 0x80000000
#define MSTATUS_MPP (_UL(3) << MSTATUS_MPP_SHIFT)
#define MSTATUS_FS _UL(0x00006000)
#define MSTATUS_XS _UL(0x00018000)
#define MSTATUS_MPRV _UL(0x00020000)
#define MSTATUS_SUM _UL(0x00040000)
#define MSTATUS_MXR _UL(0x00080000)
#define MSTATUS_TVM _UL(0x00100000)
#define MSTATUS_TW _UL(0x00200000)
#define MSTATUS_TSR _UL(0x00400000)
#define MSTATUS32_SD _UL(0x80000000)
#if __riscv_xlen == 64
#define MSTATUS_UXL 0x0000000300000000
#define MSTATUS_SXL 0x0000000C00000000
#define MSTATUS_MTL 0x0000004000000000
#define MSTATUS_MTL_SHIFT 38
#define MSTATUS_MPV 0x0000008000000000
#define MSTATUS_MPV_HIFT 39
#define MSTATUS_UXL _ULL(0x0000000300000000)
#define MSTATUS_SXL _ULL(0x0000000C00000000)
#define MSTATUS_SBE _ULL(0x0000001000000000)
#define MSTATUS_MBE _ULL(0x0000002000000000)
#define MSTATUS_MPV _ULL(0x0000008000000000)
#else
#define MSTATUSH_UXL 0x00000003
#define MSTATUSH_SXL 0x0000000C
#define MSTATUSH_MTL 0x00000040
#define MSTATUSH_MTL_SHIFT 6
#define MSTATUSH_MPV 0x00000080
#define MSTATUSH_MPV_HIFT 7
#define MSTATUSH_SBE _UL(0x00000010)
#define MSTATUSH_MBE _UL(0x00000020)
#define MSTATUSH_MPV _UL(0x00000080)
#endif
#define MSTATUS64_SD 0x8000000000000000
#define MSTATUS32_SD _UL(0x80000000)
#define MSTATUS64_SD _ULL(0x8000000000000000)
#define SSTATUS_UIE 0x00000001
#define SSTATUS_SIE 0x00000002
#define SSTATUS_UPIE 0x00000010
#define SSTATUS_SPIE_SHIFT 5
#define SSTATUS_SPIE (1UL << MSTATUS_SPIE_SHIFT)
#define SSTATUS_SPP_SHIFT 8
#define SSTATUS_SPP (1UL << MSTATUS_SPP_SHIFT)
#define SSTATUS_FS 0x00006000
#define SSTATUS_XS 0x00018000
#define SSTATUS_SUM 0x00040000
#define SSTATUS_MXR 0x00080000
#define SSTATUS32_SD 0x80000000
#define SSTATUS_UXL 0x0000000300000000
#define SSTATUS64_SD 0x8000000000000000
#define SSTATUS_SIE MSTATUS_SIE
#define SSTATUS_SPIE_SHIFT MSTATUS_SPIE_SHIFT
#define SSTATUS_SPIE MSTATUS_SPIE
#define SSTATUS_SPP_SHIFT MSTATUS_SPP_SHIFT
#define SSTATUS_SPP MSTATUS_SPP
#define SSTATUS_FS MSTATUS_FS
#define SSTATUS_XS MSTATUS_XS
#define SSTATUS_SUM MSTATUS_SUM
#define SSTATUS_MXR MSTATUS_MXR
#define SSTATUS32_SD MSTATUS32_SD
#define SSTATUS64_UXL MSTATUS_UXL
#define SSTATUS64_SD MSTATUS64_SD
#define HSTATUS_VTSR 0x00400000
#define HSTATUS_VTVM 0x00100000
#define HSTATUS_SP2V 0x00000200
#define HSTATUS_SP2P 0x00000100
#define HSTATUS_SPV 0x00000080
#define HSTATUS_STL 0x00000040
#define HSTATUS_SPRV 0x00000001
#define DCSR_XDEBUGVER (3U<<30)
#define DCSR_NDRESET (1<<29)
#define DCSR_FULLRESET (1<<28)
#define DCSR_EBREAKM (1<<15)
#define DCSR_EBREAKH (1<<14)
#define DCSR_EBREAKS (1<<13)
#define DCSR_EBREAKU (1<<12)
#define DCSR_STOPCYCLE (1<<10)
#define DCSR_STOPTIME (1<<9)
#define DCSR_CAUSE (7<<6)
#define DCSR_DEBUGINT (1<<5)
#define DCSR_HALT (1<<3)
#define DCSR_STEP (1<<2)
#define DCSR_PRV (3<<0)
#define DCSR_CAUSE_NONE 0
#define DCSR_CAUSE_SWBP 1
#define DCSR_CAUSE_HWBP 2
#define DCSR_CAUSE_DEBUGINT 3
#define DCSR_CAUSE_STEP 4
#define DCSR_CAUSE_HALT 5
#define MCONTROL_TYPE(xlen) (0xfULL<<((xlen)-4))
#define MCONTROL_DMODE(xlen) (1ULL<<((xlen)-5))
#define MCONTROL_MASKMAX(xlen) (0x3fULL<<((xlen)-11))
#define MCONTROL_SELECT (1<<19)
#define MCONTROL_TIMING (1<<18)
#define MCONTROL_ACTION (0x3f<<12)
#define MCONTROL_CHAIN (1<<11)
#define MCONTROL_MATCH (0xf<<7)
#define MCONTROL_M (1<<6)
#define MCONTROL_H (1<<5)
#define MCONTROL_S (1<<4)
#define MCONTROL_U (1<<3)
#define MCONTROL_EXECUTE (1<<2)
#define MCONTROL_STORE (1<<1)
#define MCONTROL_LOAD (1<<0)
#define MCONTROL_TYPE_NONE 0
#define MCONTROL_TYPE_MATCH 2
#define MCONTROL_ACTION_DEBUG_EXCEPTION 0
#define MCONTROL_ACTION_DEBUG_MODE 1
#define MCONTROL_ACTION_TRACE_START 2
#define MCONTROL_ACTION_TRACE_STOP 3
#define MCONTROL_ACTION_TRACE_EMIT 4
#define MCONTROL_MATCH_EQUAL 0
#define MCONTROL_MATCH_NAPOT 1
#define MCONTROL_MATCH_GE 2
#define MCONTROL_MATCH_LT 3
#define MCONTROL_MATCH_MASK_LOW 4
#define MCONTROL_MATCH_MASK_HIGH 5
#define HSTATUS_VTSR _UL(0x00400000)
#define HSTATUS_VTVM _UL(0x00100000)
#define HSTATUS_SP2V _UL(0x00000200)
#define HSTATUS_SP2P _UL(0x00000100)
#define HSTATUS_SPV _UL(0x00000080)
#define HSTATUS_SPRV _UL(0x00000001)
#define IRQ_S_SOFT 1
#define IRQ_H_SOFT 2
#define IRQ_VS_SOFT 2
#define IRQ_M_SOFT 3
#define IRQ_S_TIMER 5
#define IRQ_H_TIMER 6
#define IRQ_VS_TIMER 6
#define IRQ_M_TIMER 7
#define IRQ_S_EXT 9
#define IRQ_H_EXT 10
#define IRQ_VS_EXT 10
#define IRQ_M_EXT 11
#define IRQ_COP 12
#define IRQ_HOST 13
#define IRQ_S_GEXT 12
#define MIP_SSIP (1 << IRQ_S_SOFT)
#define MIP_HSIP (1 << IRQ_H_SOFT)
#define MIP_MSIP (1 << IRQ_M_SOFT)
#define MIP_STIP (1 << IRQ_S_TIMER)
#define MIP_HTIP (1 << IRQ_H_TIMER)
#define MIP_MTIP (1 << IRQ_M_TIMER)
#define MIP_SEIP (1 << IRQ_S_EXT)
#define MIP_HEIP (1 << IRQ_H_EXT)
#define MIP_MEIP (1 << IRQ_M_EXT)
#define MIP_SSIP (_UL(1) << IRQ_S_SOFT)
#define MIP_VSSIP (_UL(1) << IRQ_VS_SOFT)
#define MIP_MSIP (_UL(1) << IRQ_M_SOFT)
#define MIP_STIP (_UL(1) << IRQ_S_TIMER)
#define MIP_VSTIP (_UL(1) << IRQ_VS_TIMER)
#define MIP_MTIP (_UL(1) << IRQ_M_TIMER)
#define MIP_SEIP (_UL(1) << IRQ_S_EXT)
#define MIP_VSEIP (_UL(1) << IRQ_VS_EXT)
#define MIP_MEIP (_UL(1) << IRQ_M_EXT)
#define MIP_SGEIP (_UL(1) << IRQ_S_GEXT)
#define SIP_SSIP MIP_SSIP
#define SIP_STIP MIP_STIP
#define PRV_U 0
#define PRV_S 1
#define PRV_H 2
#define PRV_M 3
#define PRV_U _UL(0)
#define PRV_S _UL(1)
#define PRV_M _UL(3)
#define SATP32_MODE 0x80000000
#define SATP32_ASID 0x7FC00000
#define SATP32_PPN 0x003FFFFF
#define SATP64_MODE 0xF000000000000000
#define SATP64_ASID 0x0FFFF00000000000
#define SATP64_PPN 0x00000FFFFFFFFFFF
#define SATP32_MODE _UL(0x80000000)
#define SATP32_ASID _UL(0x7FC00000)
#define SATP32_PPN _UL(0x003FFFFF)
#define SATP64_MODE _ULL(0xF000000000000000)
#define SATP64_ASID _ULL(0x0FFFF00000000000)
#define SATP64_PPN _ULL(0x00000FFFFFFFFFFF)
#define SATP_MODE_OFF 0
#define SATP_MODE_SV32 1
#define SATP_MODE_SV39 8
#define SATP_MODE_SV48 9
#define SATP_MODE_SV57 10
#define SATP_MODE_SV64 11
#define SATP_MODE_OFF _UL(0)
#define SATP_MODE_SV32 _UL(1)
#define SATP_MODE_SV39 _UL(8)
#define SATP_MODE_SV48 _UL(9)
#define SATP_MODE_SV57 _UL(10)
#define SATP_MODE_SV64 _UL(11)
#define PMP_R 0x01
#define PMP_W 0x02
#define PMP_X 0x04
#define PMP_A 0x18
#define PMP_A_TOR 0x08
#define PMP_A_NA4 0x10
#define PMP_A_NAPOT 0x18
#define PMP_L 0x80
#define PMP_R _UL(0x01)
#define PMP_W _UL(0x02)
#define PMP_X _UL(0x04)
#define PMP_A _UL(0x18)
#define PMP_A_TOR _UL(0x08)
#define PMP_A_NA4 _UL(0x10)
#define PMP_A_NAPOT _UL(0x18)
#define PMP_L _UL(0x80)
#define PMP_SHIFT 2
#define PMP_COUNT 16
/* page table entry (PTE) fields */
#define PTE_V 0x001 /* Valid */
#define PTE_R 0x002 /* Read */
#define PTE_W 0x004 /* Write */
#define PTE_X 0x008 /* Execute */
#define PTE_U 0x010 /* User */
#define PTE_G 0x020 /* Global */
#define PTE_A 0x040 /* Accessed */
#define PTE_D 0x080 /* Dirty */
#define PTE_SOFT 0x300 /* Reserved for Software */
#define PTE_V _UL(0x001) /* Valid */
#define PTE_R _UL(0x002) /* Read */
#define PTE_W _UL(0x004) /* Write */
#define PTE_X _UL(0x008) /* Execute */
#define PTE_U _UL(0x010) /* User */
#define PTE_G _UL(0x020) /* Global */
#define PTE_A _UL(0x040) /* Accessed */
#define PTE_D _UL(0x080) /* Dirty */
#define PTE_SOFT _UL(0x300) /* Reserved for Software */
#define PTE_PPN_SHIFT 10
@@ -276,10 +208,16 @@
#define CSR_HSTATUS 0x600
#define CSR_HEDELEG 0x602
#define CSR_HIDELEG 0x603
#define CSR_HIE 0x604
#define CSR_HTIMEDELTA 0x605
#define CSR_HTIMEDELTAH 0x615
#define CSR_HCOUNTERNEN 0x606
#define CSR_HGEIE 0x607
#define CSR_HTVAL 0x643
#define CSR_HIP 0x644
#define CSR_HTINST 0x64a
#define CSR_HGATP 0x680
#define CSR_HGEIP 0xe07
#define CSR_VSSTATUS 0x200
#define CSR_VSIE 0x204
@@ -304,6 +242,8 @@
#define CSR_MCAUSE 0x342
#define CSR_MTVAL 0x343
#define CSR_MIP 0x344
#define CSR_MTINST 0x34a
#define CSR_MTVAL2 0x34b
#define CSR_PMPCFG0 0x3a0
#define CSR_PMPCFG1 0x3a1
#define CSR_PMPCFG2 0x3a2
@@ -475,6 +415,9 @@
#define CAUSE_FETCH_PAGE_FAULT 0xc
#define CAUSE_LOAD_PAGE_FAULT 0xd
#define CAUSE_STORE_PAGE_FAULT 0xf
#define CAUSE_FETCH_GUEST_PAGE_FAULT 0x14
#define CAUSE_LOAD_GUEST_PAGE_FAULT 0x15
#define CAUSE_STORE_GUEST_PAGE_FAULT 0x17
#define INSN_MATCH_LB 0x3
#define INSN_MASK_LB 0x707f
@@ -549,7 +492,16 @@
#define INSN_MASK_WFI 0xffffff00
#define INSN_MATCH_WFI 0x10500000
#define INSN_LEN(insn) ((((insn) & 0x3) < 0x3) ? 2 : 4)
#define INSN_16BIT_MASK 0x3
#define INSN_32BIT_MASK 0x1c
#define INSN_IS_16BIT(insn) \
(((insn) & INSN_16BIT_MASK) != INSN_16BIT_MASK)
#define INSN_IS_32BIT(insn) \
(((insn) & INSN_16BIT_MASK) == INSN_16BIT_MASK && \
((insn) & INSN_32BIT_MASK) != INSN_32BIT_MASK)
#define INSN_LEN(insn) (INSN_IS_16BIT(insn) ? 2 : 4)
#if __riscv_xlen == 64
#define LOG_REGBYTES 3

View File

@@ -95,4 +95,78 @@ static inline int __ffs(unsigned long word)
*/
#define ffz(x) __ffs(~(x))
/**
* fls - find last (most-significant) bit set
* @x: the word to search
*
* This is defined the same way as ffs.
* Note fls(0) = 0, fls(1) = 1, fls(0x80000000) = 32.
*/
static inline int fls(int x)
{
int r = 32;
if (!x)
return 0;
if (!(x & 0xffff0000u)) {
x <<= 16;
r -= 16;
}
if (!(x & 0xff000000u)) {
x <<= 8;
r -= 8;
}
if (!(x & 0xf0000000u)) {
x <<= 4;
r -= 4;
}
if (!(x & 0xc0000000u)) {
x <<= 2;
r -= 2;
}
if (!(x & 0x80000000u)) {
x <<= 1;
r -= 1;
}
return r;
}
/**
* __fls - find last (most-significant) set bit in a long word
* @word: the word to search
*
* Undefined if no set bit exists, so code should check against 0 first.
*/
static inline unsigned long __fls(unsigned long word)
{
int num = BITS_PER_LONG - 1;
#if BITS_PER_LONG == 64
if (!(word & (~0ul << 32))) {
num -= 32;
word <<= 32;
}
#endif
if (!(word & (~0ul << (BITS_PER_LONG-16)))) {
num -= 16;
word <<= 16;
}
if (!(word & (~0ul << (BITS_PER_LONG-8)))) {
num -= 8;
word <<= 8;
}
if (!(word & (~0ul << (BITS_PER_LONG-4)))) {
num -= 4;
word <<= 4;
}
if (!(word & (~0ul << (BITS_PER_LONG-2)))) {
num -= 2;
word <<= 2;
}
if (!(word & (~0ul << (BITS_PER_LONG-1))))
num -= 1;
return num;
}
#endif

View File

@@ -10,23 +10,10 @@
#ifndef __SBI_BITS_H__
#define __SBI_BITS_H__
#define likely(x) __builtin_expect((x), 1)
#define unlikely(x) __builtin_expect((x), 0)
#define ROUNDUP(a, b) ((((a)-1) / (b) + 1) * (b))
#define ROUNDDOWN(a, b) ((a) / (b) * (b))
#define MAX(a, b) ((a) > (b) ? (a) : (b))
#define MIN(a, b) ((a) < (b) ? (a) : (b))
#define CLAMP(a, lo, hi) MIN(MAX(a, lo), hi)
#define EXTRACT_FIELD(val, which) (((val) & (which)) / ((which) & ~((which)-1)))
#define INSERT_FIELD(val, which, fieldval) \
(((val) & ~(which)) | ((fieldval) * ((which) & ~((which)-1))))
#define STR(x) XSTR(x)
#define XSTR(x) #x
#define BIT_MASK(nr) (1UL << ((nr) % BITS_PER_LONG))
#define BIT_WORD(nr) ((nr) / BITS_PER_LONG)
#endif

View File

@@ -11,15 +11,48 @@
#define __SBI_ECALL_H__
#include <sbi/sbi_types.h>
#include <sbi/sbi_list.h>
#define SBI_ECALL_VERSION_MAJOR 0
#define SBI_ECALL_VERSION_MINOR 2
#define SBI_OPENSBI_IMPID 1
struct sbi_trap_regs;
struct sbi_trap_info;
struct sbi_scratch;
struct sbi_ecall_extension {
struct sbi_dlist head;
unsigned long extid_start;
unsigned long extid_end;
int (* probe)(struct sbi_scratch *scratch,
unsigned long extid, unsigned long *out_val);
int (* handle)(struct sbi_scratch *scratch,
unsigned long extid, unsigned long funcid,
unsigned long *args, unsigned long *out_val,
struct sbi_trap_info *out_trap);
};
extern struct sbi_ecall_extension ecall_base;
extern struct sbi_ecall_extension ecall_legacy;
extern struct sbi_ecall_extension ecall_time;
extern struct sbi_ecall_extension ecall_rfence;
extern struct sbi_ecall_extension ecall_ipi;
extern struct sbi_ecall_extension ecall_vendor;
u16 sbi_ecall_version_major(void);
u16 sbi_ecall_version_minor(void);
struct sbi_ecall_extension *sbi_ecall_find_extension(unsigned long extid);
int sbi_ecall_register_extension(struct sbi_ecall_extension *ext);
void sbi_ecall_unregister_extension(struct sbi_ecall_extension *ext);
int sbi_ecall_handler(u32 hartid, ulong mcause, struct sbi_trap_regs *regs,
struct sbi_scratch *scratch);
int sbi_ecall_init(void);
#endif

View File

@@ -12,28 +12,44 @@
/* clang-format off */
enum sbi_ext_id {
SBI_EXT_0_1_SET_TIMER = 0x0,
SBI_EXT_0_1_CONSOLE_PUTCHAR = 0x1,
SBI_EXT_0_1_CONSOLE_GETCHAR = 0x2,
SBI_EXT_0_1_CLEAR_IPI = 0x3,
SBI_EXT_0_1_SEND_IPI = 0x4,
SBI_EXT_0_1_REMOTE_FENCE_I = 0x5,
SBI_EXT_0_1_REMOTE_SFENCE_VMA = 0x6,
SBI_EXT_0_1_REMOTE_SFENCE_VMA_ASID = 0x7,
SBI_EXT_0_1_SHUTDOWN = 0x8,
SBI_EXT_BASE = 0x10,
};
/* SBI Extension IDs */
#define SBI_EXT_0_1_SET_TIMER 0x0
#define SBI_EXT_0_1_CONSOLE_PUTCHAR 0x1
#define SBI_EXT_0_1_CONSOLE_GETCHAR 0x2
#define SBI_EXT_0_1_CLEAR_IPI 0x3
#define SBI_EXT_0_1_SEND_IPI 0x4
#define SBI_EXT_0_1_REMOTE_FENCE_I 0x5
#define SBI_EXT_0_1_REMOTE_SFENCE_VMA 0x6
#define SBI_EXT_0_1_REMOTE_SFENCE_VMA_ASID 0x7
#define SBI_EXT_0_1_SHUTDOWN 0x8
#define SBI_EXT_BASE 0x10
#define SBI_EXT_TIME 0x54494D45
#define SBI_EXT_IPI 0x735049
#define SBI_EXT_RFENCE 0x52464E43
enum sbi_ext_base_fid {
SBI_EXT_BASE_GET_SPEC_VERSION = 0,
SBI_EXT_BASE_GET_IMP_ID,
SBI_EXT_BASE_GET_IMP_VERSION,
SBI_EXT_BASE_PROBE_EXT,
SBI_EXT_BASE_GET_MVENDORID,
SBI_EXT_BASE_GET_MARCHID,
SBI_EXT_BASE_GET_MIMPID,
};
/* SBI function IDs for BASE extension*/
#define SBI_EXT_BASE_GET_SPEC_VERSION 0x0
#define SBI_EXT_BASE_GET_IMP_ID 0x1
#define SBI_EXT_BASE_GET_IMP_VERSION 0x2
#define SBI_EXT_BASE_PROBE_EXT 0x3
#define SBI_EXT_BASE_GET_MVENDORID 0x4
#define SBI_EXT_BASE_GET_MARCHID 0x5
#define SBI_EXT_BASE_GET_MIMPID 0x6
/* SBI function IDs for TIME extension*/
#define SBI_EXT_TIME_SET_TIMER 0x0
/* SBI function IDs for IPI extension*/
#define SBI_EXT_IPI_SEND_IPI 0x0
/* SBI function IDs for RFENCE extension*/
#define SBI_EXT_RFENCE_REMOTE_FENCE_I 0x0
#define SBI_EXT_RFENCE_REMOTE_SFENCE_VMA 0x1
#define SBI_EXT_RFENCE_REMOTE_SFENCE_VMA_ASID 0x2
#define SBI_EXT_RFENCE_REMOTE_HFENCE_GVMA 0x3
#define SBI_EXT_RFENCE_REMOTE_HFENCE_GVMA_VMID 0x4
#define SBI_EXT_RFENCE_REMOTE_HFENCE_VVMA 0x5
#define SBI_EXT_RFENCE_REMOTE_HFENCE_VVMA_ASID 0x6
#define SBI_SPEC_VERSION_MAJOR_OFFSET 24
#define SBI_SPEC_VERSION_MAJOR_MASK 0x7f

View File

@@ -20,6 +20,7 @@ void *sbi_hart_get_trap_info(struct sbi_scratch *scratch);
void sbi_hart_set_trap_info(struct sbi_scratch *scratch, void *data);
void sbi_hart_delegation_dump(struct sbi_scratch *scratch);
void sbi_hart_pmp_dump(struct sbi_scratch *scratch);
void __attribute__((noreturn)) sbi_hart_hang(void);

36
include/sbi/sbi_hfence.h Normal file
View File

@@ -0,0 +1,36 @@
/*
* SPDX-License-Identifier: BSD-2-Clause
*
* Copyright (c) 2019 Western Digital Corporation or its affiliates.
*
* Authors:
* Atish Patra <atish.patra@wdc.com>
* Anup Patel <anup.patel@wdc.com>
*/
#ifndef __SBI_FENCE_H__
#define __SBI_FENCE_H__
/** Invalidate Stage2 TLBs for given VMID and guest physical address */
void __sbi_hfence_gvma_vmid_gpa(unsigned long vmid, unsigned long gpa);
/** Invalidate Stage2 TLBs for given VMID */
void __sbi_hfence_gvma_vmid(unsigned long vmid);
/** Invalidate Stage2 TLBs for given guest physical address */
void __sbi_hfence_gvma_gpa(unsigned long gpa);
/** Invalidate all possible Stage2 TLBs */
void __sbi_hfence_gvma_all(void);
/** Invalidate unified TLB entries for given asid and guest virtual address */
void __sbi_hfence_vvma_asid_va(unsigned long asid, unsigned long va);
/** Invalidate unified TLB entries for given ASID for a guest*/
void __sbi_hfence_vvma_asid(unsigned long asid);
/** Invalidate unified TLB entries for a given guest virtual address */
void __sbi_hfence_vvma_va(unsigned long va);
/** Invalidate all possible Stage2 TLBs */
void __sbi_hfence_vvma_all(void);
#endif

View File

@@ -15,7 +15,7 @@
struct sbi_trap_regs;
struct sbi_scratch;
int sbi_illegal_insn_handler(u32 hartid, ulong mcause,
int sbi_illegal_insn_handler(u32 hartid, ulong mcause, ulong insn,
struct sbi_trap_regs *regs,
struct sbi_scratch *scratch);

View File

@@ -16,4 +16,8 @@ struct sbi_scratch;
void __noreturn sbi_init(struct sbi_scratch *scratch);
unsigned long sbi_init_count(u32 hartid);
void __noreturn sbi_exit(struct sbi_scratch *scratch);
#endif

View File

@@ -10,32 +10,59 @@
#ifndef __SBI_IPI_H__
#define __SBI_IPI_H__
#include <sbi/riscv_unpriv.h>
#include <sbi/sbi_types.h>
/* clang-format off */
#define SBI_IPI_EVENT_SOFT 0x1
#define SBI_IPI_EVENT_FENCE_I 0x2
#define SBI_IPI_EVENT_SFENCE_VMA 0x4
#define SBI_IPI_EVENT_SFENCE_VMA_ASID 0x8
#define SBI_IPI_EVENT_HALT 0x10
#define SBI_IPI_EVENT_MAX __riscv_xlen
/* clang-format on */
struct sbi_scratch;
struct sbi_ipi_data {
unsigned long ipi_type;
/** IPI event operations or callbacks */
struct sbi_ipi_event_ops {
/** Name of the IPI event operations */
char name[32];
/** Update callback to save/enqueue data for remote HART
* Note: This is an optional callback and it is called just before
* triggering IPI to remote HART.
*/
int (* update)(struct sbi_scratch *scratch,
struct sbi_scratch *remote_scratch,
u32 remote_hartid, void *data);
/** Sync callback to wait for remote HART
* Note: This is an optional callback and it is called just after
* triggering IPI to remote HART.
*/
void (* sync)(struct sbi_scratch *scratch);
/** Process callback to handle IPI event
* Note: This is a mandatory callback and it is called on the
* remote HART after IPI is triggered.
*/
void (* process)(struct sbi_scratch *scratch);
};
int sbi_ipi_send_many(struct sbi_scratch *scratch, struct unpriv_trap *uptrap,
ulong *pmask, u32 event, void *data);
int sbi_ipi_send_many(struct sbi_scratch *scratch, ulong hmask,
ulong hbase, u32 event, void *data);
int sbi_ipi_event_create(const struct sbi_ipi_event_ops *ops);
void sbi_ipi_event_destroy(u32 event);
int sbi_ipi_send_smode(struct sbi_scratch *scratch, ulong hmask, ulong hbase);
void sbi_ipi_clear_smode(struct sbi_scratch *scratch);
int sbi_ipi_send_halt(struct sbi_scratch *scratch, ulong hmask, ulong hbase);
void sbi_ipi_process(struct sbi_scratch *scratch);
int sbi_ipi_init(struct sbi_scratch *scratch, bool cold_boot);
void sbi_ipi_exit(struct sbi_scratch *scratch);
#endif

152
include/sbi/sbi_list.h Normal file
View File

@@ -0,0 +1,152 @@
/*
* SPDX-License-Identifier: BSD-2-Clause
*
* Simple doubly-linked list library.
*
* Adapted from Xvisor source file libs/include/libs/list.h
*
* Copyright (c) 2020 Western Digital Corporation or its affiliates.
*
* Authors:
* Anup Patel <anup.patel@wdc.com>
*/
#ifndef __SBI_LIST_H__
#define __SBI_LIST_H__
#include <sbi/sbi_types.h>
#define SBI_LIST_POISON_PREV 0xDEADBEEF
#define SBI_LIST_POISON_NEXT 0xFADEBABE
struct sbi_dlist {
struct sbi_dlist *next, *prev;
};
#define SBI_LIST_HEAD_INIT(__lname) { &(__lname), &(__lname) }
#define SBI_LIST_HEAD(_lname) \
struct sbi_dlist _lname = SBI_LIST_HEAD_INIT(_lname)
#define SBI_INIT_LIST_HEAD(ptr) \
do { \
(ptr)->next = ptr; (ptr)->prev = ptr; \
} while (0);
static inline void __sbi_list_add(struct sbi_dlist *new,
struct sbi_dlist *prev,
struct sbi_dlist *next)
{
new->prev = prev;
new->next = next;
prev->next = new;
next->prev = new;
}
/**
* Adds the new node after the given head.
* @param new New node that needs to be added to list.
* @param head List head after which the "new" node should be added.
* Note: the new node is added after the head.
*/
static inline void sbi_list_add(struct sbi_dlist *new, struct sbi_dlist *head)
{
__sbi_list_add(new, head, head->next);
}
/**
* Adds a node at the tail where tnode points to tail node.
* @param new The new node to be added before tail.
* @param tnode The current tail node.
* Note: the new node is added before tail node.
*/
static inline void sbi_list_add_tail(struct sbi_dlist *new,
struct sbi_dlist *tnode)
{
__sbi_list_add(new, tnode->prev, tnode);
}
static inline void __sbi_list_del(struct sbi_dlist *prev,
struct sbi_dlist *next)
{
prev->next = next;
next->prev = prev;
}
static inline void __sbi_list_del_entry(struct sbi_dlist *entry)
{
__sbi_list_del(entry->prev, entry->next);
}
/**
* Deletes a given entry from list.
* @param node Node to be deleted.
*/
static inline void sbi_list_del(struct sbi_dlist *entry)
{
__sbi_list_del(entry->prev, entry->next);
entry->next = (void *)SBI_LIST_POISON_NEXT;
entry->prev = (void *)SBI_LIST_POISON_PREV;
}
/**
* Deletes entry from list and reinitialize it.
* @param entry the element to delete from the list.
*/
static inline void sbi_list_del_init(struct sbi_dlist *entry)
{
__sbi_list_del_entry(entry);
SBI_INIT_LIST_HEAD(entry);
}
/**
* Get the struct for this entry
* @param ptr the &struct list_head pointer.
* @param type the type of the struct this is embedded in.
* @param member the name of the list_struct within the struct.
*/
#define sbi_list_entry(ptr, type, member) \
container_of(ptr, type, member)
/**
* Get the first element from a list
* @param ptr the list head to take the element from.
* @param type the type of the struct this is embedded in.
* @param member the name of the list_struct within the struct.
*
* Note: that list is expected to be not empty.
*/
#define sbi_list_first_entry(ptr, type, member) \
sbi_list_entry((ptr)->next, type, member)
/**
* Get the last element from a list
* @param ptr the list head to take the element from.
* @param type the type of the struct this is embedded in.
* @param member the name of the list_head within the struct.
*
* Note: that list is expected to be not empty.
*/
#define sbi_list_last_entry(ptr, type, member) \
sbi_list_entry((ptr)->prev, type, member)
/**
* Iterate over a list
* @param pos the &struct list_head to use as a loop cursor.
* @param head the head for your list.
*/
#define sbi_list_for_each(pos, head) \
for (pos = (head)->next; pos != (head); pos = pos->next)
/**
* Iterate over list of given type
* @param pos the type * to use as a loop cursor.
* @param head the head for your list.
* @param member the name of the list_struct within the struct.
*/
#define sbi_list_for_each_entry(pos, head, member) \
for (pos = sbi_list_entry((head)->next, typeof(*pos), member); \
&pos->member != (head); \
pos = sbi_list_entry(pos->member.next, typeof(*pos), member))
#endif

View File

@@ -16,10 +16,12 @@ struct sbi_trap_regs;
struct sbi_scratch;
int sbi_misaligned_load_handler(u32 hartid, ulong mcause,
ulong addr, ulong tval2, ulong tinst,
struct sbi_trap_regs *regs,
struct sbi_scratch *scratch);
int sbi_misaligned_store_handler(u32 hartid, ulong mcause,
ulong addr, ulong tval2, ulong tinst,
struct sbi_trap_regs *regs,
struct sbi_scratch *scratch);

View File

@@ -30,21 +30,20 @@
#define SBI_PLATFORM_HART_STACK_SIZE_OFFSET (0x54)
/** Offset of disabled_hart_mask in struct sbi_platform */
#define SBI_PLATFORM_DISABLED_HART_OFFSET (0x58)
/** Offset of tlb_range_flush_limit in struct sbi_platform */
#define SBI_PLATFORM_TLB_RANGE_FLUSH_LIMIT_OFFSET (0x60)
/** Offset of platform_ops_addr in struct sbi_platform */
#define SBI_PLATFORM_OPS_OFFSET (0x68)
#define SBI_PLATFORM_OPS_OFFSET (0x60)
/** Offset of firmware_context in struct sbi_platform */
#define SBI_PLATFORM_FIRMWARE_CONTEXT_OFFSET (0x68 + __SIZEOF_POINTER__)
#define SBI_PLATFORM_FIRMWARE_CONTEXT_OFFSET (0x60 + __SIZEOF_POINTER__)
#define SBI_PLATFORM_TLB_RANGE_FLUSH_LIMIT_DEFAULT (1UL << 12)
#ifndef __ASSEMBLY__
#include <sbi/sbi_version.h>
#include <sbi/sbi_scratch.h>
#include <sbi/sbi_ecall.h>
#include <sbi/sbi_error.h>
#include <sbi/sbi_scratch.h>
#include <sbi/sbi_trap.h>
#include <sbi/sbi_version.h>
/** Possible feature flags of a platform */
enum sbi_platform_features {
@@ -75,6 +74,21 @@ struct sbi_platform_operations {
/** Platform final initialization */
int (*final_init)(bool cold_boot);
/** Platform early exit */
void (*early_exit)(void);
/** Platform final exit */
void (*final_exit)(void);
/** For platforms that do not implement misa, non-standard
* methods are needed to determine cpu extension.
*/
int (*misa_check_extension)(char ext);
/** For platforms that do not implement misa, non-standard
* methods are needed to get MXL field of misa.
*/
int (*misa_get_xlen)(void);
/** Get number of PMP regions for given HART */
u32 (*pmp_region_count)(u32 hartid);
/**
@@ -93,6 +107,8 @@ struct sbi_platform_operations {
/** Initialize the platform interrupt controller for current HART */
int (*irqchip_init)(bool cold_boot);
/** Exit the platform interrupt controller for current HART */
void (*irqchip_exit)(void);
/** Send IPI to a target HART */
void (*ipi_send)(u32 target_hart);
@@ -100,6 +116,11 @@ struct sbi_platform_operations {
void (*ipi_clear)(u32 target_hart);
/** Initialize IPI for current HART */
int (*ipi_init)(bool cold_boot);
/** Exit IPI for current HART */
void (*ipi_exit)(void);
/** Get tlb flush limit value **/
u64 (*get_tlbr_flush_limit)(void);
/** Get platform timer value */
u64 (*timer_value)(void);
@@ -109,6 +130,8 @@ struct sbi_platform_operations {
void (*timer_event_stop)(void);
/** Initialize platform timer for current HART */
int (*timer_init)(bool cold_boot);
/** Exit platform timer for current HART */
void (*timer_exit)(void);
/** Reboot the platform */
int (*system_reboot)(u32 type);
@@ -119,9 +142,9 @@ struct sbi_platform_operations {
int (*vendor_ext_check)(long extid);
/** platform specific SBI extension implementation provider */
int (*vendor_ext_provider)(long extid, long funcid,
unsigned long *args, unsigned long *out_value,
unsigned long *out_trap_cause,
unsigned long *out_trap_val);
unsigned long *args,
unsigned long *out_value,
struct sbi_trap_info *out_trap);
} __packed;
/** Representation of a platform */
@@ -148,8 +171,6 @@ struct sbi_platform {
u32 hart_stack_size;
/** Mask representing the set of disabled HARTs */
u64 disabled_hart_mask;
/* Maximum value of tlb flush range request*/
u64 tlb_range_flush_limit;
/** Pointer to sbi platform operations */
unsigned long platform_ops_addr;
/** Pointer to system firmware specific context */
@@ -189,13 +210,13 @@ struct sbi_platform {
*
* @param plat pointer to struct sbi_platform
*
* @return pointer to platform name on success and NULL on failure
* @return pointer to platform name on success and "Unknown" on failure
*/
static inline const char *sbi_platform_name(const struct sbi_platform *plat)
{
if (plat)
return plat->name;
return NULL;
return "Unknown";
}
/**
@@ -225,8 +246,8 @@ static inline bool sbi_platform_hart_disabled(const struct sbi_platform *plat,
*/
static inline u64 sbi_platform_tlbr_flush_limit(const struct sbi_platform *plat)
{
if (plat && plat->tlb_range_flush_limit)
return plat->tlb_range_flush_limit;
if (plat && sbi_platform_ops(plat)->get_tlbr_flush_limit)
return sbi_platform_ops(plat)->get_tlbr_flush_limit();
return SBI_PLATFORM_TLB_RANGE_FLUSH_LIMIT_DEFAULT;
}
@@ -290,6 +311,58 @@ static inline int sbi_platform_final_init(const struct sbi_platform *plat,
return 0;
}
/**
* Early exit for current HART
*
* @param plat pointer to struct sbi_platform
*/
static inline void sbi_platform_early_exit(const struct sbi_platform *plat)
{
if (plat && sbi_platform_ops(plat)->early_exit)
sbi_platform_ops(plat)->early_exit();
}
/**
* Final exit for current HART
*
* @param plat pointer to struct sbi_platform
*/
static inline void sbi_platform_final_exit(const struct sbi_platform *plat)
{
if (plat && sbi_platform_ops(plat)->final_exit)
sbi_platform_ops(plat)->final_exit();
}
/**
* Check CPU extension in MISA
*
* @param plat pointer to struct sbi_platform
* @param ext shorthand letter for CPU extensions
*
* @return zero for not-supported and non-zero for supported
*/
static inline int sbi_platform_misa_extension(const struct sbi_platform *plat,
char ext)
{
if (plat && sbi_platform_ops(plat)->misa_check_extension)
return sbi_platform_ops(plat)->misa_check_extension(ext);
return 0;
}
/**
* Get MXL field of MISA
*
* @param plat pointer to struct sbi_platform
*
* @return 1/2/3 on success and error code on failure
*/
static inline int sbi_platform_misa_xlen(const struct sbi_platform *plat)
{
if (plat && sbi_platform_ops(plat)->misa_get_xlen)
return sbi_platform_ops(plat)->misa_get_xlen();
return -1;
}
/**
* Get the number of PMP regions of a HART
*
@@ -387,6 +460,17 @@ static inline int sbi_platform_irqchip_init(const struct sbi_platform *plat,
return 0;
}
/**
* Exit the platform interrupt controller for current HART
*
* @param plat pointer to struct sbi_platform
*/
static inline void sbi_platform_irqchip_exit(const struct sbi_platform *plat)
{
if (plat && sbi_platform_ops(plat)->irqchip_exit)
sbi_platform_ops(plat)->irqchip_exit();
}
/**
* Send IPI to a target HART
*
@@ -429,6 +513,17 @@ static inline int sbi_platform_ipi_init(const struct sbi_platform *plat,
return 0;
}
/**
* Exit the platform IPI support for current HART
*
* @param plat pointer to struct sbi_platform
*/
static inline void sbi_platform_ipi_exit(const struct sbi_platform *plat)
{
if (plat && sbi_platform_ops(plat)->ipi_exit)
sbi_platform_ops(plat)->ipi_exit();
}
/**
* Get platform timer value
*
@@ -484,6 +579,17 @@ static inline int sbi_platform_timer_init(const struct sbi_platform *plat,
return 0;
}
/**
* Exit the platform timer for current HART
*
* @param plat pointer to struct sbi_platform
*/
static inline void sbi_platform_timer_exit(const struct sbi_platform *plat)
{
if (plat && sbi_platform_ops(plat)->timer_exit)
sbi_platform_ops(plat)->timer_exit();
}
/**
* Reboot the platform
*
@@ -540,25 +646,23 @@ static inline int sbi_platform_vendor_ext_check(const struct sbi_platform *plat,
* @param extid vendor SBI extension id
* @param funcid SBI function id within the extension id
* @param args pointer to arguments passed by the caller
* @param out_value output value that can be filled the callee
* @param out_tcause trap cause that can be filled the callee
* @param out_tvalue possible trap value that can be filled the callee
* @param out_value output value that can be filled by the callee
* @param out_trap trap info that can be filled by the callee
*
* @return 0 on success and negative error code on failure
*/
static inline int sbi_platform_vendor_ext_provider(const struct sbi_platform *plat,
long extid, long funcid,
unsigned long *args,
unsigned long *out_value,
unsigned long *out_tcause,
unsigned long *out_tval)
static inline int sbi_platform_vendor_ext_provider(
const struct sbi_platform *plat,
long extid, long funcid,
unsigned long *args,
unsigned long *out_value,
struct sbi_trap_info *out_trap)
{
if (plat && sbi_platform_ops(plat)->vendor_ext_provider) {
return sbi_platform_ops(plat)->vendor_ext_provider(extid,
funcid, args,
out_value,
out_tcause,
out_tval);
funcid, args,
out_value,
out_trap);
}
return SBI_ENOTSUPP;

View File

@@ -36,7 +36,7 @@
#define SBI_SCRATCH_OPTIONS_OFFSET (9 * __SIZEOF_POINTER__)
/** Offset of extra space in sbi_scratch */
#define SBI_SCRATCH_EXTRA_SPACE_OFFSET (10 * __SIZEOF_POINTER__)
/** Maximum size of sbi_scratch and sbi_ipi_data */
/** Maximum size of sbi_scratch */
#define SBI_SCRATCH_SIZE (64 * __SIZEOF_POINTER__)
/* clang-format on */
@@ -44,7 +44,6 @@
#ifndef __ASSEMBLY__
#include <sbi/sbi_types.h>
#include <sbi/sbi_ipi.h>
/** Representation of per-HART scratch space */
struct sbi_scratch {

View File

@@ -18,10 +18,12 @@ int sbi_system_early_init(struct sbi_scratch *scratch, bool cold_boot);
int sbi_system_final_init(struct sbi_scratch *scratch, bool cold_boot);
void __attribute__((noreturn))
sbi_system_reboot(struct sbi_scratch *scratch, u32 type);
void sbi_system_early_exit(struct sbi_scratch *scratch);
void __attribute__((noreturn))
sbi_system_shutdown(struct sbi_scratch *scratch, u32 type);
void sbi_system_final_exit(struct sbi_scratch *scratch);
void __noreturn sbi_system_reboot(struct sbi_scratch *scratch, u32 type);
void __noreturn sbi_system_shutdown(struct sbi_scratch *scratch, u32 type);
#endif

View File

@@ -24,12 +24,12 @@ void sbi_timer_set_delta(struct sbi_scratch *scratch, ulong delta);
void sbi_timer_set_delta_upper(struct sbi_scratch *scratch, ulong delta_upper);
void sbi_timer_event_stop(struct sbi_scratch *scratch);
void sbi_timer_event_start(struct sbi_scratch *scratch, u64 next_event);
void sbi_timer_process(struct sbi_scratch *scratch);
int sbi_timer_init(struct sbi_scratch *scratch, bool cold_boot);
void sbi_timer_exit(struct sbi_scratch *scratch);
#endif

View File

@@ -24,7 +24,10 @@
enum sbi_tlb_info_types {
SBI_TLB_FLUSH_VMA,
SBI_TLB_FLUSH_VMA_ASID,
SBI_TLB_FLUSH_VMA_VMID,
SBI_TLB_FLUSH_GVMA,
SBI_TLB_FLUSH_GVMA_VMID,
SBI_TLB_FLUSH_VVMA,
SBI_TLB_FLUSH_VVMA_ASID,
SBI_ITLB_FLUSH
};
@@ -40,12 +43,9 @@ struct sbi_tlb_info {
#define SBI_TLB_INFO_SIZE sizeof(struct sbi_tlb_info)
int sbi_tlb_fifo_update(struct sbi_scratch *scratch, u32 hartid, void *data);
int sbi_tlb_request(struct sbi_scratch *scratch, ulong hmask,
ulong hbase, struct sbi_tlb_info *tinfo);
void sbi_tlb_fifo_process(struct sbi_scratch *scratch);
int sbi_tlb_fifo_init(struct sbi_scratch *scratch, bool cold_boot);
void sbi_tlb_fifo_sync(struct sbi_scratch *scratch);
int sbi_tlb_init(struct sbi_scratch *scratch, bool cold_boot);
#endif

View File

@@ -170,12 +170,28 @@ struct sbi_trap_regs {
unsigned long mstatusH;
} __packed;
/** Representation of trap details */
struct sbi_trap_info {
/** epc Trap program counter */
unsigned long epc;
/** cause Trap exception cause */
unsigned long cause;
/** tval Trap value */
unsigned long tval;
/** tval2 Trap value 2 */
unsigned long tval2;
/** tinst Trap instruction */
unsigned long tinst;
};
struct sbi_scratch;
int sbi_trap_redirect(struct sbi_trap_regs *regs, struct sbi_scratch *scratch,
ulong epc, ulong cause, ulong tval);
int sbi_trap_redirect(struct sbi_trap_regs *regs,
struct sbi_trap_info *trap,
struct sbi_scratch *scratch);
void sbi_trap_handler(struct sbi_trap_regs *regs, struct sbi_scratch *scratch);
void sbi_trap_handler(struct sbi_trap_regs *regs,
struct sbi_scratch *scratch);
#endif

View File

@@ -10,6 +10,8 @@
#ifndef __SBI_TYPES_H__
#define __SBI_TYPES_H__
#ifndef OPENSBI_EXTERNAL_SBI_TYPES
/* clang-format off */
typedef char s8;
@@ -60,6 +62,43 @@ typedef unsigned long physical_size_t;
#define __packed __attribute__((packed))
#define __noreturn __attribute__((noreturn))
#define likely(x) __builtin_expect((x), 1)
#define unlikely(x) __builtin_expect((x), 0)
#undef offsetof
#ifdef __compiler_offsetof
#define offsetof(TYPE, MEMBER) __compiler_offsetof(TYPE,MEMBER)
#else
#define offsetof(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER)
#endif
#define container_of(ptr, type, member) ({ \
const typeof(((type *)0)->member) * __mptr = (ptr); \
(type *)((char *)__mptr - offsetof(type, member)); })
#define MAX(a, b) ((a) > (b) ? (a) : (b))
#define MIN(a, b) ((a) < (b) ? (a) : (b))
#define CLAMP(a, lo, hi) MIN(MAX(a, lo), hi)
#define STR(x) XSTR(x)
#define XSTR(x) #x
#define ROUNDUP(a, b) ((((a)-1) / (b) + 1) * (b))
#define ROUNDDOWN(a, b) ((a) / (b) * (b))
/* clang-format on */
#else
/* OPENSBI_EXTERNAL_SBI_TYPES could be defined in CFLAGS for using the
* external definitions of data types and common macros.
* OPENSBI_EXTERNAL_SBI_TYPES is the file name to external header file,
* the external build system should address the additional include
* directory ccordingly.
*/
#define XSTR(x) #x
#define STR(x) XSTR(x)
#include STR(OPENSBI_EXTERNAL_SBI_TYPES)
#endif
#endif

View File

@@ -7,28 +7,23 @@
* Anup Patel <anup.patel@wdc.com>
*/
#ifndef __RISCV_UNPRIV_H__
#define __RISCV_UNPRIV_H__
#ifndef __SBI_UNPRIV_H__
#define __SBI_UNPRIV_H__
#include <sbi/sbi_types.h>
struct sbi_scratch;
struct sbi_trap_info;
struct unpriv_trap {
unsigned long ilen;
unsigned long cause;
unsigned long tval;
};
#define DECLARE_UNPRIVILEGED_LOAD_FUNCTION(type) \
type sbi_load_##type(const type *addr, \
struct sbi_scratch *scratch, \
struct sbi_trap_info *trap);
#define DECLARE_UNPRIVILEGED_LOAD_FUNCTION(type) \
type load_##type(const type *addr, \
struct sbi_scratch *scratch, \
struct unpriv_trap *trap);
#define DECLARE_UNPRIVILEGED_STORE_FUNCTION(type) \
void store_##type(type *addr, type val, \
struct sbi_scratch *scratch, \
struct unpriv_trap *trap);
#define DECLARE_UNPRIVILEGED_STORE_FUNCTION(type) \
void sbi_store_##type(type *addr, type val, \
struct sbi_scratch *scratch, \
struct sbi_trap_info *trap);
DECLARE_UNPRIVILEGED_LOAD_FUNCTION(u8)
DECLARE_UNPRIVILEGED_LOAD_FUNCTION(u16)
@@ -43,7 +38,7 @@ DECLARE_UNPRIVILEGED_LOAD_FUNCTION(u64)
DECLARE_UNPRIVILEGED_STORE_FUNCTION(u64)
DECLARE_UNPRIVILEGED_LOAD_FUNCTION(ulong)
ulong get_insn(ulong mepc, bool virt, struct sbi_scratch *scratch,
struct unpriv_trap *trap);
ulong sbi_get_insn(ulong mepc, struct sbi_scratch *scratch,
struct sbi_trap_info *trap);
#endif

View File

@@ -11,7 +11,7 @@
#define __SBI_VERSION_H__
#define OPENSBI_VERSION_MAJOR 0
#define OPENSBI_VERSION_MINOR 5
#define OPENSBI_VERSION_MINOR 6
/**
* OpenSBI 32-bit version with:

View File

@@ -30,6 +30,7 @@ void clint_timer_event_start(u64 next_event);
int clint_warm_timer_init(void);
int clint_cold_timer_init(unsigned long base, u32 hart_count);
int clint_cold_timer_init(unsigned long base, u32 hart_count,
bool has_64bit_mmio);
#endif

View File

@@ -0,0 +1,19 @@
/*
* SPDX-License-Identifier: BSD-3-Clause
*
* Copyright (c) 2010-2020, The Regents of the University of California
* (Regents). All Rights Reserved.
*/
#ifndef __SYS_HTIF_H__
#define __SYS_HTIF_H__
#include <sbi/sbi_types.h>
void htif_putc(char ch);
int htif_getc(void);
int htif_system_down(u32 type);
#endif

View File

@@ -11,12 +11,16 @@ libsbi-objs-y += riscv_asm.o
libsbi-objs-y += riscv_atomic.o
libsbi-objs-y += riscv_hardfp.o
libsbi-objs-y += riscv_locks.o
libsbi-objs-y += riscv_unpriv.o
libsbi-objs-y += sbi_console.o
libsbi-objs-y += sbi_ecall.o
libsbi-objs-y += sbi_ecall_base.o
libsbi-objs-y += sbi_ecall_legacy.o
libsbi-objs-y += sbi_ecall_replace.o
libsbi-objs-y += sbi_ecall_vendor.o
libsbi-objs-y += sbi_emulate_csr.o
libsbi-objs-y += sbi_fifo.o
libsbi-objs-y += sbi_hfence.o
libsbi-objs-y += sbi_hart.o
libsbi-objs-y += sbi_illegal_insn.o
libsbi-objs-y += sbi_init.o
@@ -28,3 +32,4 @@ libsbi-objs-y += sbi_timer.o
libsbi-objs-y += sbi_tlb.o
libsbi-objs-y += sbi_trap.o
libsbi-objs-y += sbi_string.o
libsbi-objs-y += sbi_unpriv.o

View File

@@ -10,6 +10,39 @@
#include <sbi/riscv_asm.h>
#include <sbi/riscv_encoding.h>
#include <sbi/sbi_error.h>
#include <sbi/sbi_platform.h>
/* determine CPU extension, return non-zero support */
int misa_extension_imp(char ext)
{
unsigned long misa = csr_read(CSR_MISA);
if (misa)
return misa & (1 << (ext - 'A'));
return sbi_platform_misa_extension(sbi_platform_thishart_ptr(), ext);
}
int misa_xlen(void)
{
long r;
if (csr_read(CSR_MISA) == 0)
return sbi_platform_misa_xlen(sbi_platform_thishart_ptr());
__asm__ __volatile__(
"csrr t0, misa\n\t"
"slti t1, t0, 0\n\t"
"slli t1, t1, 1\n\t"
"slli t0, t0, 1\n\t"
"slti t0, t0, 0\n\t"
"add %0, t0, t1"
: "=r"(r)
:
: "t0", "t1");
return r ? r : -1;
}
unsigned long csr_read_num(int csr_num)
{

View File

@@ -79,7 +79,7 @@ long atomic_sub_return(atomic_t *atom, long value)
#define axchg(ptr, x) \
({ \
__typeof__(*(ptr)) _x_ = (x); \
(__typeof__(*(ptr))) __xchg((ptr), _x_, sizeof(*(ptr))); \
(__typeof__(*(ptr))) __axchg((ptr), _x_, sizeof(*(ptr))); \
})

View File

@@ -7,23 +7,10 @@
* Anup Patel <anup.patel@wdc.com>
*/
#include <sbi/sbi_console.h>
#include <sbi/sbi_ecall.h>
#include <sbi/sbi_ecall_interface.h>
#include <sbi/sbi_error.h>
#include <sbi/sbi_ipi.h>
#include <sbi/sbi_platform.h>
#include <sbi/sbi_system.h>
#include <sbi/sbi_timer.h>
#include <sbi/sbi_tlb.h>
#include <sbi/sbi_trap.h>
#include <sbi/sbi_hart.h>
#include <sbi/sbi_version.h>
#include <sbi/riscv_asm.h>
#define SBI_ECALL_VERSION_MAJOR 0
#define SBI_ECALL_VERSION_MINOR 2
#define SBI_OPENSBI_IMPID 1
u16 sbi_ecall_version_major(void)
{
@@ -35,164 +22,64 @@ u16 sbi_ecall_version_minor(void)
return SBI_ECALL_VERSION_MINOR;
}
int sbi_check_extension(struct sbi_scratch *scratch, unsigned long extid,
unsigned long *out_val)
{
/**
* Each extension apart from base & 0.1, will be implemented as
* platform specific feature. Thus, extension probing can be achieved
* by checking the feature bits of the platform. We can create a map
* between extension ID & feature and use a generic function to check
* or just use a switch case for every new extension support added
* TODO: Implement it.
*/
static SBI_LIST_HEAD(ecall_exts_list);
if ((extid >= SBI_EXT_0_1_SET_TIMER &&
extid <= SBI_EXT_0_1_SHUTDOWN) || (extid == SBI_EXT_BASE)) {
*out_val = 1;
} else if (extid >= SBI_EXT_VENDOR_START &&
extid <= SBI_EXT_VENDOR_END) {
*out_val = sbi_platform_vendor_ext_check(
sbi_platform_ptr(scratch),
extid);
} else
*out_val = 0;
struct sbi_ecall_extension *sbi_ecall_find_extension(unsigned long extid)
{
struct sbi_ecall_extension *t, *ret = NULL;
sbi_list_for_each_entry(t, &ecall_exts_list, head) {
if (t->extid_start <= extid && extid <= t->extid_end) {
ret = t;
break;
}
}
return ret;
}
int sbi_ecall_register_extension(struct sbi_ecall_extension *ext)
{
if (!ext || (ext->extid_end < ext->extid_start) || !ext->handle)
return SBI_EINVAL;
if (sbi_ecall_find_extension(ext->extid_start) ||
sbi_ecall_find_extension(ext->extid_end))
return SBI_EINVAL;
SBI_INIT_LIST_HEAD(&ext->head);
sbi_list_add_tail(&ext->head, &ecall_exts_list);
return 0;
}
int sbi_ecall_vendor_ext_handler(struct sbi_scratch *scratch,
unsigned long extid, unsigned long funcid,
unsigned long *args, unsigned long *out_val,
unsigned long *out_tcause,
unsigned long *out_tval)
void sbi_ecall_unregister_extension(struct sbi_ecall_extension *ext)
{
return sbi_platform_vendor_ext_provider(sbi_platform_ptr(scratch),
extid, funcid, args, out_val,
out_tcause, out_tval);
}
bool found = FALSE;
struct sbi_ecall_extension *t;
int sbi_ecall_base_handler(struct sbi_scratch *scratch, unsigned long extid,
unsigned long funcid, unsigned long *args,
unsigned long *out_val, unsigned long *out_tcause,
unsigned long *out_tval)
{
int ret = 0;
if (!ext)
return;
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;
break;
case SBI_EXT_BASE_GET_IMP_ID:
*out_val = SBI_OPENSBI_IMPID;
break;
case SBI_EXT_BASE_GET_IMP_VERSION:
*out_val = OPENSBI_VERSION;
break;
case SBI_EXT_BASE_GET_MVENDORID:
*out_val = csr_read(CSR_MVENDORID);
break;
case SBI_EXT_BASE_GET_MARCHID:
*out_val = csr_read(CSR_MARCHID);
break;
case SBI_EXT_BASE_GET_MIMPID:
*out_val = csr_read(CSR_MIMPID);
break;
case SBI_EXT_BASE_PROBE_EXT:
ret = sbi_check_extension(scratch, args[0], out_val);
default:
ret = SBI_ENOTSUPP;
sbi_list_for_each_entry(t, &ecall_exts_list, head) {
if (t == ext) {
found = TRUE;
break;
}
}
return ret;
}
int sbi_ecall_0_1_handler(struct sbi_scratch *scratch, unsigned long extid,
unsigned long *args, unsigned long *tval,
unsigned long *tcause)
{
int ret = 0;
struct sbi_tlb_info tlb_info;
u32 source_hart = sbi_current_hartid();
struct unpriv_trap uptrap = {0};
switch (extid) {
case SBI_EXT_0_1_SET_TIMER:
#if __riscv_xlen == 32
sbi_timer_event_start(scratch,
(((u64)args[1] << 32) | (u64)args[0]));
#else
sbi_timer_event_start(scratch, (u64)args[0]);
#endif
break;
case SBI_EXT_0_1_CONSOLE_PUTCHAR:
sbi_putc(args[0]);
break;
case SBI_EXT_0_1_CONSOLE_GETCHAR:
ret = sbi_getc();
break;
case SBI_EXT_0_1_CLEAR_IPI:
sbi_ipi_clear_smode(scratch);
break;
case SBI_EXT_0_1_SEND_IPI:
ret = sbi_ipi_send_many(scratch, &uptrap, (ulong *)args[0],
SBI_IPI_EVENT_SOFT, NULL);
break;
case SBI_EXT_0_1_REMOTE_FENCE_I:
tlb_info.start = 0;
tlb_info.size = 0;
tlb_info.type = SBI_ITLB_FLUSH;
tlb_info.shart_mask = 1UL << source_hart;
ret = sbi_ipi_send_many(scratch, &uptrap, (ulong *)args[0],
SBI_IPI_EVENT_FENCE_I, &tlb_info);
break;
case SBI_EXT_0_1_REMOTE_SFENCE_VMA:
tlb_info.start = (unsigned long)args[1];
tlb_info.size = (unsigned long)args[2];
tlb_info.type = SBI_TLB_FLUSH_VMA;
tlb_info.shart_mask = 1UL << source_hart;
ret = sbi_ipi_send_many(scratch, &uptrap, (ulong *)args[0],
SBI_IPI_EVENT_SFENCE_VMA, &tlb_info);
break;
case SBI_EXT_0_1_REMOTE_SFENCE_VMA_ASID:
tlb_info.start = (unsigned long)args[1];
tlb_info.size = (unsigned long)args[2];
tlb_info.asid = (unsigned long)args[3];
tlb_info.type = SBI_TLB_FLUSH_VMA_ASID;
tlb_info.shart_mask = 1UL << source_hart;
ret = sbi_ipi_send_many(scratch, &uptrap, (ulong *)args[0],
SBI_IPI_EVENT_SFENCE_VMA_ASID,
&tlb_info);
break;
case SBI_EXT_0_1_SHUTDOWN:
sbi_system_shutdown(scratch, 0);
break;
default:
ret = SBI_ENOTSUPP;
};
if (ret == SBI_ETRAP) {
*tcause = uptrap.cause;
*tval = uptrap.tval;
}
return ret;
if (found)
sbi_list_del_init(&ext->head);
}
int sbi_ecall_handler(u32 hartid, ulong mcause, struct sbi_trap_regs *regs,
struct sbi_scratch *scratch)
{
int ret = 0;
struct sbi_ecall_extension *ext;
unsigned long extension_id = regs->a7;
unsigned long func_id = regs->a6;
unsigned long out_val;
unsigned long out_tval;
unsigned long out_tcause;
struct sbi_trap_info trap = {0};
unsigned long out_val = 0;
bool is_0_1_spec = 0;
unsigned long args[6];
@@ -203,27 +90,20 @@ int sbi_ecall_handler(u32 hartid, ulong mcause, struct sbi_trap_regs *regs,
args[4] = regs->a4;
args[5] = regs->a5;
if (extension_id >= SBI_EXT_0_1_SET_TIMER &&
extension_id <= SBI_EXT_0_1_SHUTDOWN) {
ret = sbi_ecall_0_1_handler(scratch, extension_id, args,
&out_tval, &out_tcause);
is_0_1_spec = 1;
} else if (extension_id == SBI_EXT_BASE)
ret = sbi_ecall_base_handler(scratch, extension_id, func_id,
args, &out_val,
&out_tval, &out_tcause);
else if (extension_id >= SBI_EXT_VENDOR_START &&
extension_id <= SBI_EXT_VENDOR_END) {
ret = sbi_ecall_vendor_ext_handler(scratch, extension_id,
func_id, args, &out_val,
&out_tval, &out_tcause);
ext = sbi_ecall_find_extension(extension_id);
if (ext && ext->handle) {
ret = ext->handle(scratch, extension_id, func_id,
args, &out_val, &trap);
if (extension_id >= SBI_EXT_0_1_SET_TIMER &&
extension_id <= SBI_EXT_0_1_SHUTDOWN)
is_0_1_spec = 1;
} else {
ret = SBI_ENOTSUPP;
}
if (ret == SBI_ETRAP) {
sbi_trap_redirect(regs, scratch, regs->mepc,
out_tcause, out_tval);
trap.epc = regs->mepc;
sbi_trap_redirect(regs, &trap, scratch);
} else {
/* This function should return non-zero value only in case of
* fatal error. However, there is no good way to distinguish
@@ -240,3 +120,30 @@ int sbi_ecall_handler(u32 hartid, ulong mcause, struct sbi_trap_regs *regs,
return 0;
}
int sbi_ecall_init(void)
{
int ret;
/* The order of below registrations is performance optimized */
ret = sbi_ecall_register_extension(&ecall_time);
if (ret)
return ret;
ret = sbi_ecall_register_extension(&ecall_rfence);
if (ret)
return ret;
ret = sbi_ecall_register_extension(&ecall_ipi);
if (ret)
return ret;
ret = sbi_ecall_register_extension(&ecall_base);
if (ret)
return ret;
ret = sbi_ecall_register_extension(&ecall_legacy);
if (ret)
return ret;
ret = sbi_ecall_register_extension(&ecall_vendor);
if (ret)
return ret;
return 0;
}

80
lib/sbi/sbi_ecall_base.c Normal file
View File

@@ -0,0 +1,80 @@
/*
* SPDX-License-Identifier: BSD-2-Clause
*
* Copyright (c) 2020 Western Digital Corporation or its affiliates.
*
* Authors:
* Anup Patel <anup.patel@wdc.com>
* Atish Patra <atish.patra@wdc.com>
*/
#include <sbi/sbi_ecall.h>
#include <sbi/sbi_ecall_interface.h>
#include <sbi/sbi_error.h>
#include <sbi/sbi_version.h>
#include <sbi/riscv_asm.h>
static int sbi_ecall_base_probe(struct sbi_scratch *scratch,
unsigned long extid,
unsigned long *out_val)
{
struct sbi_ecall_extension *ext;
ext = sbi_ecall_find_extension(extid);
if (!ext) {
*out_val = 0;
return 0;
}
if (ext->probe)
return ext->probe(scratch, extid, out_val);
*out_val = 1;
return 0;
}
static int sbi_ecall_base_handler(struct sbi_scratch *scratch,
unsigned long extid, unsigned long funcid,
unsigned long *args, unsigned long *out_val,
struct sbi_trap_info *out_trap)
{
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;
break;
case SBI_EXT_BASE_GET_IMP_ID:
*out_val = SBI_OPENSBI_IMPID;
break;
case SBI_EXT_BASE_GET_IMP_VERSION:
*out_val = OPENSBI_VERSION;
break;
case SBI_EXT_BASE_GET_MVENDORID:
*out_val = csr_read(CSR_MVENDORID);
break;
case SBI_EXT_BASE_GET_MARCHID:
*out_val = csr_read(CSR_MARCHID);
break;
case SBI_EXT_BASE_GET_MIMPID:
*out_val = csr_read(CSR_MIMPID);
break;
case SBI_EXT_BASE_PROBE_EXT:
ret = sbi_ecall_base_probe(scratch, args[0], out_val);
break;
default:
ret = SBI_ENOTSUPP;
}
return ret;
}
struct sbi_ecall_extension ecall_base = {
.extid_start = SBI_EXT_BASE,
.extid_end = SBI_EXT_BASE,
.handle = sbi_ecall_base_handler,
};

119
lib/sbi/sbi_ecall_legacy.c Normal file
View File

@@ -0,0 +1,119 @@
/*
* SPDX-License-Identifier: BSD-2-Clause
*
* Copyright (c) 2020 Western Digital Corporation or its affiliates.
*
* Authors:
* Anup Patel <anup.patel@wdc.com>
* Atish Patra <atish.patra@wdc.com>
*/
#include <sbi/sbi_console.h>
#include <sbi/sbi_ecall.h>
#include <sbi/sbi_ecall_interface.h>
#include <sbi/sbi_error.h>
#include <sbi/sbi_ipi.h>
#include <sbi/sbi_system.h>
#include <sbi/sbi_timer.h>
#include <sbi/sbi_tlb.h>
#include <sbi/sbi_trap.h>
#include <sbi/sbi_unpriv.h>
#include <sbi/sbi_hart.h>
static int sbi_load_hart_mask_unpriv(struct sbi_scratch *scratch,
ulong *pmask, ulong *hmask,
struct sbi_trap_info *uptrap)
{
ulong mask = 0;
if (pmask) {
mask = sbi_load_ulong(pmask, scratch, uptrap);
if (uptrap->cause)
return SBI_ETRAP;
} else {
mask = sbi_hart_available_mask();
}
*hmask = mask;
return 0;
}
static int sbi_ecall_legacy_handler(struct sbi_scratch *scratch,
unsigned long extid, unsigned long funcid,
unsigned long *args, unsigned long *out_val,
struct sbi_trap_info *out_trap)
{
int ret = 0;
struct sbi_tlb_info tlb_info;
u32 source_hart = sbi_current_hartid();
ulong hmask = 0;
switch (extid) {
case SBI_EXT_0_1_SET_TIMER:
#if __riscv_xlen == 32
sbi_timer_event_start(scratch,
(((u64)args[1] << 32) | (u64)args[0]));
#else
sbi_timer_event_start(scratch, (u64)args[0]);
#endif
break;
case SBI_EXT_0_1_CONSOLE_PUTCHAR:
sbi_putc(args[0]);
break;
case SBI_EXT_0_1_CONSOLE_GETCHAR:
ret = sbi_getc();
break;
case SBI_EXT_0_1_CLEAR_IPI:
sbi_ipi_clear_smode(scratch);
break;
case SBI_EXT_0_1_SEND_IPI:
ret = sbi_load_hart_mask_unpriv(scratch, (ulong *)args[0],
&hmask, out_trap);
if (ret != SBI_ETRAP)
ret = sbi_ipi_send_smode(scratch, hmask, 0);
break;
case SBI_EXT_0_1_REMOTE_FENCE_I:
tlb_info.start = 0;
tlb_info.size = 0;
tlb_info.type = SBI_ITLB_FLUSH;
tlb_info.shart_mask = 1UL << source_hart;
ret = sbi_load_hart_mask_unpriv(scratch, (ulong *)args[0],
&hmask, out_trap);
if (ret != SBI_ETRAP)
ret = sbi_tlb_request(scratch, hmask, 0, &tlb_info);
break;
case SBI_EXT_0_1_REMOTE_SFENCE_VMA:
tlb_info.start = (unsigned long)args[1];
tlb_info.size = (unsigned long)args[2];
tlb_info.type = SBI_TLB_FLUSH_VMA;
tlb_info.shart_mask = 1UL << source_hart;
ret = sbi_load_hart_mask_unpriv(scratch, (ulong *)args[0],
&hmask, out_trap);
if (ret != SBI_ETRAP)
ret = sbi_tlb_request(scratch, hmask, 0, &tlb_info);
break;
case SBI_EXT_0_1_REMOTE_SFENCE_VMA_ASID:
tlb_info.start = (unsigned long)args[1];
tlb_info.size = (unsigned long)args[2];
tlb_info.asid = (unsigned long)args[3];
tlb_info.type = SBI_TLB_FLUSH_VMA_ASID;
tlb_info.shart_mask = 1UL << source_hart;
ret = sbi_load_hart_mask_unpriv(scratch, (ulong *)args[0],
&hmask, out_trap);
if (ret != SBI_ETRAP)
ret = sbi_tlb_request(scratch, hmask, 0, &tlb_info);
break;
case SBI_EXT_0_1_SHUTDOWN:
sbi_system_shutdown(scratch, 0);
break;
default:
ret = SBI_ENOTSUPP;
};
return ret;
}
struct sbi_ecall_extension ecall_legacy = {
.extid_start = SBI_EXT_0_1_SET_TIMER,
.extid_end = SBI_EXT_0_1_SHUTDOWN,
.handle = sbi_ecall_legacy_handler,
};

146
lib/sbi/sbi_ecall_replace.c Normal file
View File

@@ -0,0 +1,146 @@
/*
* SPDX-License-Identifier: BSD-2-Clause
*
* Copyright (c) 2020 Western Digital Corporation or its affiliates.
*
* Authors:
* Anup Patel <anup.patel@wdc.com>
* Atish Patra <atish.patra@wdc.com>
*/
#include <sbi/sbi_ecall.h>
#include <sbi/sbi_ecall_interface.h>
#include <sbi/sbi_error.h>
#include <sbi/sbi_hart.h>
#include <sbi/sbi_ipi.h>
#include <sbi/sbi_timer.h>
#include <sbi/sbi_tlb.h>
#include <sbi/riscv_asm.h>
static int sbi_ecall_time_handler(struct sbi_scratch *scratch,
unsigned long extid, unsigned long funcid,
unsigned long *args, unsigned long *out_val,
struct sbi_trap_info *out_trap)
{
int ret = 0;
if (funcid == SBI_EXT_TIME_SET_TIMER) {
#if __riscv_xlen == 32
sbi_timer_event_start(scratch,
(((u64)args[1] << 32) | (u64)args[0]));
#else
sbi_timer_event_start(scratch, (u64)args[0]);
#endif
} else
ret = SBI_ENOTSUPP;
return ret;
}
struct sbi_ecall_extension ecall_time = {
.extid_start = SBI_EXT_TIME,
.extid_end = SBI_EXT_TIME,
.handle = sbi_ecall_time_handler,
};
static int sbi_ecall_rfence_handler(struct sbi_scratch *scratch,
unsigned long extid, unsigned long funcid,
unsigned long *args, unsigned long *out_val,
struct sbi_trap_info *out_trap)
{
int ret = 0;
struct sbi_tlb_info tlb_info;
u32 source_hart = sbi_current_hartid();
if (funcid >= SBI_EXT_RFENCE_REMOTE_HFENCE_GVMA &&
funcid <= SBI_EXT_RFENCE_REMOTE_HFENCE_VVMA_ASID)
if (!misa_extension('H'))
return SBI_ENOTSUPP;
switch (funcid) {
case SBI_EXT_RFENCE_REMOTE_FENCE_I:
tlb_info.start = 0;
tlb_info.size = 0;
tlb_info.type = SBI_ITLB_FLUSH;
tlb_info.shart_mask = 1UL << source_hart;
ret = sbi_tlb_request(scratch, args[0], args[1], &tlb_info);
break;
case SBI_EXT_RFENCE_REMOTE_HFENCE_GVMA:
tlb_info.start = (unsigned long)args[2];
tlb_info.size = (unsigned long)args[3];
tlb_info.type = SBI_TLB_FLUSH_GVMA;
tlb_info.shart_mask = 1UL << source_hart;
ret = sbi_tlb_request(scratch, args[0], args[1], &tlb_info);
break;
case SBI_EXT_RFENCE_REMOTE_HFENCE_GVMA_VMID:
tlb_info.start = (unsigned long)args[2];
tlb_info.size = (unsigned long)args[3];
tlb_info.asid = (unsigned long)args[4];
tlb_info.type = SBI_TLB_FLUSH_GVMA_VMID;
tlb_info.shart_mask = 1UL << source_hart;
ret = sbi_tlb_request(scratch, args[0], args[1], &tlb_info);
break;
case SBI_EXT_RFENCE_REMOTE_HFENCE_VVMA:
tlb_info.start = (unsigned long)args[2];
tlb_info.size = (unsigned long)args[3];
tlb_info.type = SBI_TLB_FLUSH_VVMA;
tlb_info.shart_mask = 1UL << source_hart;
ret = sbi_tlb_request(scratch, args[0], args[1], &tlb_info);
break;
case SBI_EXT_RFENCE_REMOTE_HFENCE_VVMA_ASID:
tlb_info.start = (unsigned long)args[2];
tlb_info.size = (unsigned long)args[3];
tlb_info.asid = (unsigned long)args[4];
tlb_info.type = SBI_TLB_FLUSH_VVMA_ASID;
tlb_info.shart_mask = 1UL << source_hart;
ret = sbi_tlb_request(scratch, args[0], args[1], &tlb_info);
break;
case SBI_EXT_RFENCE_REMOTE_SFENCE_VMA:
tlb_info.start = (unsigned long)args[2];
tlb_info.size = (unsigned long)args[3];
tlb_info.type = SBI_TLB_FLUSH_VMA;
tlb_info.shart_mask = 1UL << source_hart;
ret = sbi_tlb_request(scratch, args[0], args[1], &tlb_info);
break;
case SBI_EXT_RFENCE_REMOTE_SFENCE_VMA_ASID:
tlb_info.start = (unsigned long)args[2];
tlb_info.size = (unsigned long)args[3];
tlb_info.asid = (unsigned long)args[4];
tlb_info.type = SBI_TLB_FLUSH_VMA_ASID;
tlb_info.shart_mask = 1UL << source_hart;
ret = sbi_tlb_request(scratch, args[0], args[1], &tlb_info);
break;
default:
ret = SBI_ENOTSUPP;
};
return ret;
}
struct sbi_ecall_extension ecall_rfence = {
.extid_start = SBI_EXT_RFENCE,
.extid_end = SBI_EXT_RFENCE,
.handle = sbi_ecall_rfence_handler,
};
static int sbi_ecall_ipi_handler(struct sbi_scratch *scratch,
unsigned long extid, unsigned long funcid,
unsigned long *args, unsigned long *out_val,
struct sbi_trap_info *out_trap)
{
int ret = 0;
if (funcid == SBI_EXT_IPI_SEND_IPI)
ret = sbi_ipi_send_smode(scratch, args[0], args[1]);
else
ret = SBI_ENOTSUPP;
return ret;
}
struct sbi_ecall_extension ecall_ipi = {
.extid_start = SBI_EXT_IPI,
.extid_end = SBI_EXT_IPI,
.handle = sbi_ecall_ipi_handler,
};

View File

@@ -0,0 +1,40 @@
/*
* SPDX-License-Identifier: BSD-2-Clause
*
* Copyright (c) 2020 Western Digital Corporation or its affiliates.
*
* Authors:
* Anup Patel <anup.patel@wdc.com>
* Atish Patra <atish.patra@wdc.com>
*/
#include <sbi/sbi_ecall.h>
#include <sbi/sbi_ecall_interface.h>
#include <sbi/sbi_error.h>
#include <sbi/sbi_platform.h>
static int sbi_ecall_vendor_probe(struct sbi_scratch *scratch,
unsigned long extid,
unsigned long *out_val)
{
*out_val = sbi_platform_vendor_ext_check(sbi_platform_ptr(scratch),
extid);
return 0;
}
static int sbi_ecall_vendor_handler(struct sbi_scratch *scratch,
unsigned long extid, unsigned long funcid,
unsigned long *args, unsigned long *out_val,
struct sbi_trap_info *out_trap)
{
return sbi_platform_vendor_ext_provider(sbi_platform_ptr(scratch),
extid, funcid, args,
out_val, out_trap);
}
struct sbi_ecall_extension ecall_vendor = {
.extid_start = SBI_EXT_VENDOR_START,
.extid_end = SBI_EXT_VENDOR_END,
.probe = sbi_ecall_vendor_probe,
.handle = sbi_ecall_vendor_handler,
};

View File

@@ -88,24 +88,36 @@ static int delegate_traps(struct sbi_scratch *scratch, u32 hartid)
(1U << CAUSE_STORE_PAGE_FAULT);
/*
* If hypervisor extension available then we only handle
* hypervisor calls (i.e. ecalls from HS-mode) and we let
* HS-mode handle supervisor calls (i.e. ecalls from VS-mode)
* If hypervisor extension available then we only handle hypervisor
* calls (i.e. ecalls from HS-mode) in M-mode.
*
* The HS-mode will additionally handle supervisor calls (i.e. ecalls
* from VS-mode), Guest page faults and Virtual interrupts.
*/
if (misa_extension('H'))
if (misa_extension('H')) {
exceptions |= (1U << CAUSE_SUPERVISOR_ECALL);
exceptions |= (1U << CAUSE_FETCH_GUEST_PAGE_FAULT);
exceptions |= (1U << CAUSE_LOAD_GUEST_PAGE_FAULT);
exceptions |= (1U << CAUSE_STORE_GUEST_PAGE_FAULT);
}
csr_write(CSR_MIDELEG, interrupts);
csr_write(CSR_MEDELEG, exceptions);
if (csr_read(CSR_MIDELEG) != interrupts)
return SBI_EFAIL;
if (csr_read(CSR_MEDELEG) != exceptions)
return SBI_EFAIL;
return 0;
}
void sbi_hart_delegation_dump(struct sbi_scratch *scratch)
{
#if __riscv_xlen == 32
sbi_printf("MIDELEG : 0x%08lx\n", csr_read(CSR_MIDELEG));
sbi_printf("MEDELEG : 0x%08lx\n", csr_read(CSR_MEDELEG));
#else
sbi_printf("MIDELEG : 0x%016lx\n", csr_read(CSR_MIDELEG));
sbi_printf("MEDELEG : 0x%016lx\n", csr_read(CSR_MEDELEG));
#endif
}
unsigned long log2roundup(unsigned long x)
{
unsigned long ret = 0;
@@ -137,9 +149,9 @@ void sbi_hart_pmp_dump(struct sbi_scratch *scratch)
else
size = 0;
#if __riscv_xlen == 32
sbi_printf("PMP%d: 0x%08lx-0x%08lx (A",
sbi_printf("PMP%d : 0x%08lx-0x%08lx (A",
#else
sbi_printf("PMP%d: 0x%016lx-0x%016lx (A",
sbi_printf("PMP%d : 0x%016lx-0x%016lx (A",
#endif
i, addr, addr + size - 1);
if (prot & PMP_L)
@@ -271,7 +283,6 @@ sbi_hart_switch_mode(unsigned long arg0, unsigned long arg1,
#if __riscv_xlen == 32
if (misa_extension('H')) {
valH = csr_read(CSR_MSTATUSH);
valH = INSERT_FIELD(valH, MSTATUSH_MTL, 0);
if (next_virt)
valH = INSERT_FIELD(valH, MSTATUSH_MPV, 1);
else
@@ -280,7 +291,6 @@ sbi_hart_switch_mode(unsigned long arg0, unsigned long arg1,
}
#else
if (misa_extension('H')) {
val = INSERT_FIELD(val, MSTATUS_MTL, 0);
if (next_virt)
val = INSERT_FIELD(val, MSTATUS_MPV, 1);
else
@@ -350,12 +360,16 @@ static unsigned long coldboot_wait_bitmap = 0;
void sbi_hart_wait_for_coldboot(struct sbi_scratch *scratch, u32 hartid)
{
unsigned long saved_mie;
const struct sbi_platform *plat = sbi_platform_ptr(scratch);
if ((sbi_platform_hart_count(plat) <= hartid) ||
(COLDBOOT_WAIT_BITMAP_SIZE <= hartid))
sbi_hart_hang();
/* Save MIE CSR */
saved_mie = csr_read(CSR_MIE);
/* Set MSIE bit to receive IPI */
csr_set(CSR_MIE, MIP_MSIP);
@@ -378,6 +392,9 @@ void sbi_hart_wait_for_coldboot(struct sbi_scratch *scratch, u32 hartid)
/* Release coldboot lock */
spin_unlock(&coldboot_lock);
/* Restore MIE CSR */
csr_write(CSR_MIE, saved_mie);
/* Clear current HART IPI */
sbi_platform_ipi_clear(plat, hartid);
}

75
lib/sbi/sbi_hfence.S Normal file
View File

@@ -0,0 +1,75 @@
/*
* SPDX-License-Identifier: BSD-2-Clause
*
* Copyright (c) 2019 Western Digital Corporation or its affiliates.
*
* Authors:
* Anup Patel <anup.patel@wdc.com>
* Atish Patra <anup.patel@wdc.com>
*/
/*
* Instruction encoding of hfence.gvma is:
* 0110001 rs2(5) rs1(5) 000 00000 1110011
*/
.align 3
.global __sbi_hfence_gvma_vmid_gpa
__sbi_hfence_gvma_vmid_gpa:
/* hfence.gvma a1, a0 */
.word 0x62a60073
ret
.align 3
.global __sbi_hfence_gvma_vmid
__sbi_hfence_gvma_vmid:
/* hfence.gvma zero, a0 */
.word 0x62a00073
ret
.align 3
.global __sbi_hfence_gvma_gpa
__sbi_hfence_gvma_gpa:
/* hfence.gvma a0 */
.word 0x62050073
ret
.align 3
.global __sbi_hfence_gvma_all
__sbi_hfence_gvma_all:
/* hfence.gvma */
.word 0x62000073
ret
/*
* Instruction encoding of hfence.bvma is:
* 0010001 rs2(5) rs1(5) 000 00000 1110011
*/
.align 3
.global __sbi_hfence_vvma_asid_va
__sbi_hfence_vvma_asid_va:
/* hfence.bvma a1, a0 */
.word 0x22a60073
ret
.align 3
.global __sbi_hfence_vvma_asid
__sbi_hfence_vvma_asid:
/* hfence.bvma zero, a0 */
.word 0x22a00073
ret
.align 3
.global __sbi_hfence_vvma_va
__sbi_hfence_vvma_va:
/* hfence.bvma a0 */
.word 0x22050073
ret
.align 3
.global __sbi_hfence_vvma_all
__sbi_hfence_vvma_all:
/* hfence.bvma */
.word 0x22000073
ret

View File

@@ -9,12 +9,12 @@
#include <sbi/riscv_asm.h>
#include <sbi/riscv_encoding.h>
#include <sbi/riscv_unpriv.h>
#include <sbi/sbi_bits.h>
#include <sbi/sbi_emulate_csr.h>
#include <sbi/sbi_error.h>
#include <sbi/sbi_illegal_insn.h>
#include <sbi/sbi_trap.h>
#include <sbi/sbi_unpriv.h>
typedef int (*illegal_insn_func)(ulong insn, u32 hartid, ulong mcause,
struct sbi_trap_regs *regs,
@@ -24,7 +24,15 @@ static int truly_illegal_insn(ulong insn, u32 hartid, ulong mcause,
struct sbi_trap_regs *regs,
struct sbi_scratch *scratch)
{
return sbi_trap_redirect(regs, scratch, regs->mepc, mcause, insn);
struct sbi_trap_info trap;
trap.epc = regs->mepc;
trap.cause = mcause;
trap.tval = insn;
trap.tval2 = 0;
trap.tinst = 0;
return sbi_trap_redirect(regs, &trap, scratch);
}
static int system_opcode_insn(ulong insn, u32 hartid, ulong mcause,
@@ -46,8 +54,8 @@ static int system_opcode_insn(ulong insn, u32 hartid, ulong mcause,
if ((regs->mstatus & MSTATUS_MPV) &&
#endif
(insn & INSN_MASK_WFI) == INSN_MATCH_WFI)
return sbi_trap_redirect(regs, scratch,
regs->mepc, mcause, insn);
return truly_illegal_insn(insn, hartid, mcause,
regs, scratch);
if (sbi_emulate_csr_read(csr_num, hartid, regs, scratch, &csr_val))
return truly_illegal_insn(insn, hartid, mcause,
@@ -125,24 +133,20 @@ static illegal_insn_func illegal_insn_table[32] = {
truly_illegal_insn /* 31 */
};
int sbi_illegal_insn_handler(u32 hartid, ulong mcause,
int sbi_illegal_insn_handler(u32 hartid, ulong mcause, ulong insn,
struct sbi_trap_regs *regs,
struct sbi_scratch *scratch)
{
ulong insn = csr_read(CSR_MTVAL);
#if __riscv_xlen == 32
bool virt = (regs->mstatusH & MSTATUSH_MPV) ? TRUE : FALSE;
#else
bool virt = (regs->mstatus & MSTATUS_MPV) ? TRUE : FALSE;
#endif
struct unpriv_trap uptrap;
struct sbi_trap_info uptrap;
if (unlikely((insn & 3) != 3)) {
if (insn == 0) {
insn = get_insn(regs->mepc, virt, scratch, &uptrap);
if (uptrap.cause)
return sbi_trap_redirect(regs, scratch,
regs->mepc, uptrap.cause, uptrap.tval);
insn = sbi_get_insn(regs->mepc, scratch, &uptrap);
if (uptrap.cause) {
uptrap.epc = regs->mepc;
return sbi_trap_redirect(regs, &uptrap,
scratch);
}
}
if ((insn & 3) != 3)
return truly_illegal_insn(insn, hartid, mcause, regs,

View File

@@ -16,6 +16,7 @@
#include <sbi/sbi_platform.h>
#include <sbi/sbi_system.h>
#include <sbi/sbi_timer.h>
#include <sbi/sbi_tlb.h>
#include <sbi/sbi_version.h>
#define BANNER \
@@ -30,23 +31,31 @@
static void sbi_boot_prints(struct sbi_scratch *scratch, u32 hartid)
{
int xlen;
char str[64];
const struct sbi_platform *plat = sbi_platform_ptr(scratch);
misa_string(str, sizeof(str));
#ifdef OPENSBI_VERSION_GIT
sbi_printf("\nOpenSBI %s (%s %s)\n", OPENSBI_VERSION_GIT,
__DATE__, __TIME__);
sbi_printf("\nOpenSBI %s\n", OPENSBI_VERSION_GIT);
#else
sbi_printf("\nOpenSBI v%d.%d (%s %s)\n", OPENSBI_VERSION_MAJOR,
OPENSBI_VERSION_MINOR, __DATE__, __TIME__);
sbi_printf("\nOpenSBI v%d.%d\n", OPENSBI_VERSION_MAJOR,
OPENSBI_VERSION_MINOR);
#endif
sbi_printf(BANNER);
/* Determine MISA XLEN and MISA string */
xlen = misa_xlen();
if (xlen < 1) {
sbi_printf("Error %d getting MISA XLEN\n", xlen);
sbi_hart_hang();
}
xlen = 16 * (1 << xlen);
misa_string(str, sizeof(str));
/* Platform details */
sbi_printf("Platform Name : %s\n", sbi_platform_name(plat));
sbi_printf("Platform HART Features : RV%d%s\n", misa_xlen(), str);
sbi_printf("Platform HART Features : RV%d%s\n", xlen, str);
sbi_printf("Platform Max HARTs : %d\n",
sbi_platform_hart_count(plat));
sbi_printf("Current Hart : %u\n", hartid);
@@ -59,14 +68,23 @@ static void sbi_boot_prints(struct sbi_scratch *scratch, u32 hartid)
sbi_ecall_version_major(), sbi_ecall_version_minor());
sbi_printf("\n");
sbi_hart_delegation_dump(scratch);
sbi_hart_pmp_dump(scratch);
}
static unsigned long init_count_offset;
static void __noreturn init_coldboot(struct sbi_scratch *scratch, u32 hartid)
{
int rc;
unsigned long *init_count;
const struct sbi_platform *plat = sbi_platform_ptr(scratch);
init_count_offset = sbi_scratch_alloc_offset(__SIZEOF_POINTER__,
"INIT_COUNT");
if (!init_count_offset)
sbi_hart_hang();
rc = sbi_system_early_init(scratch, TRUE);
if (rc)
sbi_hart_hang();
@@ -87,10 +105,18 @@ static void __noreturn init_coldboot(struct sbi_scratch *scratch, u32 hartid)
if (rc)
sbi_hart_hang();
rc = sbi_tlb_init(scratch, TRUE);
if (rc)
sbi_hart_hang();
rc = sbi_timer_init(scratch, TRUE);
if (rc)
sbi_hart_hang();
rc = sbi_ecall_init();
if (rc)
sbi_hart_hang();
rc = sbi_system_final_init(scratch, TRUE);
if (rc)
sbi_hart_hang();
@@ -98,9 +124,13 @@ static void __noreturn init_coldboot(struct sbi_scratch *scratch, u32 hartid)
if (!(scratch->options & SBI_SCRATCH_NO_BOOT_PRINTS))
sbi_boot_prints(scratch, hartid);
if (!sbi_platform_has_hart_hotplug(plat))
sbi_hart_wake_coldboot_harts(scratch, hartid);
sbi_hart_wake_coldboot_harts(scratch, hartid);
sbi_hart_mark_available(hartid);
init_count = sbi_scratch_offset_ptr(scratch, init_count_offset);
(*init_count)++;
sbi_hart_switch_mode(hartid, scratch->next_arg1, scratch->next_addr,
scratch->next_mode, FALSE);
}
@@ -108,12 +138,12 @@ static void __noreturn init_coldboot(struct sbi_scratch *scratch, u32 hartid)
static void __noreturn init_warmboot(struct sbi_scratch *scratch, u32 hartid)
{
int rc;
unsigned long *init_count;
const struct sbi_platform *plat = sbi_platform_ptr(scratch);
if (!sbi_platform_has_hart_hotplug(plat))
sbi_hart_wait_for_coldboot(scratch, hartid);
sbi_hart_wait_for_coldboot(scratch, hartid);
if (sbi_platform_hart_disabled(plat, hartid))
if (!init_count_offset)
sbi_hart_hang();
rc = sbi_system_early_init(scratch, FALSE);
@@ -132,6 +162,10 @@ static void __noreturn init_warmboot(struct sbi_scratch *scratch, u32 hartid)
if (rc)
sbi_hart_hang();
rc = sbi_tlb_init(scratch, FALSE);
if (rc)
sbi_hart_hang();
rc = sbi_timer_init(scratch, FALSE);
if (rc)
sbi_hart_hang();
@@ -142,13 +176,12 @@ static void __noreturn init_warmboot(struct sbi_scratch *scratch, u32 hartid)
sbi_hart_mark_available(hartid);
if (sbi_platform_has_hart_hotplug(plat))
/* TODO: To be implemented in-future. */
sbi_hart_hang();
else
sbi_hart_switch_mode(hartid, scratch->next_arg1,
scratch->next_addr,
scratch->next_mode, FALSE);
init_count = sbi_scratch_offset_ptr(scratch, init_count_offset);
(*init_count)++;
sbi_hart_switch_mode(hartid, scratch->next_arg1,
scratch->next_addr,
scratch->next_mode, FALSE);
}
static atomic_t coldboot_lottery = ATOMIC_INITIALIZER(0);
@@ -182,3 +215,50 @@ void __noreturn sbi_init(struct sbi_scratch *scratch)
else
init_warmboot(scratch, hartid);
}
unsigned long sbi_init_count(u32 hartid)
{
struct sbi_scratch *scratch;
unsigned long *init_count;
if (sbi_platform_hart_count(sbi_platform_thishart_ptr()) <= hartid ||
!init_count_offset)
return 0;
scratch = sbi_hart_id_to_scratch(sbi_scratch_thishart_ptr(), hartid);
init_count = sbi_scratch_offset_ptr(scratch, init_count_offset);
return *init_count;
}
/**
* Exit OpenSBI library for current HART and stop HART
*
* The function expects following:
* 1. The 'mscratch' CSR is pointing to sbi_scratch of current HART
* 2. Stack pointer (SP) is setup for current HART
*
* @param scratch pointer to sbi_scratch of current HART
*/
void __noreturn sbi_exit(struct sbi_scratch *scratch)
{
u32 hartid = sbi_current_hartid();
const struct sbi_platform *plat = sbi_platform_ptr(scratch);
if (sbi_platform_hart_disabled(plat, hartid))
sbi_hart_hang();
sbi_hart_unmark_available(hartid);
sbi_platform_early_exit(plat);
sbi_timer_exit(scratch);
sbi_ipi_exit(scratch);
sbi_platform_irqchip_exit(plat);
sbi_platform_final_exit(plat);
sbi_hart_hang();
}

View File

@@ -11,89 +11,168 @@
#include <sbi/riscv_asm.h>
#include <sbi/riscv_atomic.h>
#include <sbi/riscv_barrier.h>
#include <sbi/riscv_unpriv.h>
#include <sbi/sbi_bitops.h>
#include <sbi/sbi_error.h>
#include <sbi/sbi_hart.h>
#include <sbi/sbi_init.h>
#include <sbi/sbi_ipi.h>
#include <sbi/sbi_platform.h>
#include <sbi/sbi_tlb.h>
struct sbi_ipi_data {
unsigned long ipi_type;
};
static unsigned long ipi_data_off;
static int sbi_ipi_send(struct sbi_scratch *scratch, u32 hartid, u32 event,
void *data)
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,
u32 event, void *data)
{
int ret;
struct sbi_scratch *remote_scratch = NULL;
const struct sbi_platform *plat = sbi_platform_ptr(scratch);
struct sbi_ipi_data *ipi_data;
const struct sbi_ipi_event_ops *ipi_ops;
if (sbi_platform_hart_disabled(plat, hartid))
return -1;
if ((SBI_IPI_EVENT_MAX <= event) ||
!ipi_ops_array[event] ||
sbi_platform_hart_disabled(plat, remote_hartid))
return SBI_EINVAL;
ipi_ops = ipi_ops_array[event];
/*
* Set IPI type on remote hart's scratch area and
* trigger the interrupt
*/
remote_scratch = sbi_hart_id_to_scratch(scratch, hartid);
remote_scratch = sbi_hart_id_to_scratch(scratch, remote_hartid);
ipi_data = sbi_scratch_offset_ptr(remote_scratch, ipi_data_off);
if (event == SBI_IPI_EVENT_SFENCE_VMA ||
event == SBI_IPI_EVENT_SFENCE_VMA_ASID ||
event == SBI_IPI_EVENT_FENCE_I ) {
ret = sbi_tlb_fifo_update(remote_scratch, hartid, data);
if (ipi_ops->update) {
ret = ipi_ops->update(scratch, remote_scratch,
remote_hartid, data);
if (ret < 0)
return ret;
}
atomic_raw_set_bit(event, &ipi_data->ipi_type);
smp_wmb();
sbi_platform_ipi_send(plat, hartid);
sbi_platform_ipi_send(plat, remote_hartid);
if (event == SBI_IPI_EVENT_SFENCE_VMA ||
event == SBI_IPI_EVENT_SFENCE_VMA_ASID ||
event == SBI_IPI_EVENT_FENCE_I ) {
sbi_tlb_fifo_sync(scratch);
}
if (ipi_ops->sync)
ipi_ops->sync(scratch);
return 0;
}
int sbi_ipi_send_many(struct sbi_scratch *scratch, struct unpriv_trap *uptrap,
ulong *pmask, u32 event, void *data)
/**
* As this this function only handlers scalar values of hart mask, it must be
* set to all online harts if the intention is to send IPIs to all the harts.
* If hmask is zero, no IPIs will be sent.
*/
int sbi_ipi_send_many(struct sbi_scratch *scratch, ulong hmask, ulong hbase,
u32 event, void *data)
{
ulong i, m;
ulong mask = sbi_hart_available_mask();
u32 hartid = sbi_current_hartid();
ulong tempmask;
unsigned long last_bit = __fls(mask);
if (pmask) {
mask &= load_ulong(pmask, scratch, uptrap);
if (uptrap->cause)
return SBI_ETRAP;
if (hbase != -1UL) {
if (hbase > last_bit)
/* hart base is not available */
return SBI_EINVAL;
/**
* FIXME: This check is valid only ULONG size. This is okay for
* now as avaialble hart mask can support upto ULONG size only.
*/
tempmask = hmask << hbase;
tempmask = ~mask & tempmask;
if (tempmask)
/* at least one of the hart in hmask is not available */
return SBI_EINVAL;
mask &= (hmask << hbase);
}
/* Send IPIs to every other hart on the set */
for (i = 0, m = mask; m; i++, m >>= 1)
if ((m & 1UL) && (i != hartid))
if (m & 1UL)
sbi_ipi_send(scratch, i, event, data);
/*
* If the current hart is on the set, send an IPI
* to it as well
*/
if (mask & (1UL << hartid))
sbi_ipi_send(scratch, hartid, event, data);
return 0;
}
int sbi_ipi_event_create(const struct sbi_ipi_event_ops *ops)
{
int i, ret = SBI_ENOSPC;
if (!ops || !ops->process)
return SBI_EINVAL;
for (i = 0; i < SBI_IPI_EVENT_MAX; i++) {
if (!ipi_ops_array[i]) {
ret = i;
ipi_ops_array[i] = ops;
break;
}
}
return ret;
}
void sbi_ipi_event_destroy(u32 event)
{
if (SBI_IPI_EVENT_MAX <= event)
return;
ipi_ops_array[event] = NULL;
}
static void sbi_ipi_process_smode(struct sbi_scratch *scratch)
{
csr_set(CSR_MIP, MIP_SSIP);
}
static struct sbi_ipi_event_ops ipi_smode_ops = {
.name = "IPI_SMODE",
.process = sbi_ipi_process_smode,
};
static u32 ipi_smode_event = SBI_IPI_EVENT_MAX;
int sbi_ipi_send_smode(struct sbi_scratch *scratch, ulong hmask, ulong hbase)
{
return sbi_ipi_send_many(scratch, hmask, hbase, ipi_smode_event, NULL);
}
void sbi_ipi_clear_smode(struct sbi_scratch *scratch)
{
csr_clear(CSR_MIP, MIP_SSIP);
}
static void sbi_ipi_process_halt(struct sbi_scratch *scratch)
{
sbi_exit(scratch);
}
static struct sbi_ipi_event_ops ipi_halt_ops = {
.name = "IPI_HALT",
.process = sbi_ipi_process_halt,
};
static u32 ipi_halt_event = SBI_IPI_EVENT_MAX;
int sbi_ipi_send_halt(struct sbi_scratch *scratch, ulong hmask, ulong hbase)
{
return sbi_ipi_send_many(scratch, hmask, hbase, ipi_halt_event, NULL);
}
void sbi_ipi_process(struct sbi_scratch *scratch)
{
unsigned long ipi_type;
unsigned int ipi_event;
const struct sbi_ipi_event_ops *ipi_ops;
const struct sbi_platform *plat = sbi_platform_ptr(scratch);
struct sbi_ipi_data *ipi_data =
sbi_scratch_offset_ptr(scratch, ipi_data_off);
@@ -107,21 +186,9 @@ void sbi_ipi_process(struct sbi_scratch *scratch)
if (!(ipi_type & 1UL))
goto skip;
switch (ipi_event) {
case SBI_IPI_EVENT_SOFT:
csr_set(CSR_MIP, MIP_SSIP);
break;
case SBI_IPI_EVENT_FENCE_I:
case SBI_IPI_EVENT_SFENCE_VMA:
case SBI_IPI_EVENT_SFENCE_VMA_ASID:
sbi_tlb_fifo_process(scratch);
break;
case SBI_IPI_EVENT_HALT:
sbi_hart_hang();
break;
default:
break;
};
ipi_ops = ipi_ops_array[ipi_event];
if (ipi_ops && ipi_ops->process)
ipi_ops->process(scratch);
skip:
ipi_type = ipi_type >> 1;
@@ -139,20 +206,44 @@ int sbi_ipi_init(struct sbi_scratch *scratch, bool cold_boot)
"IPI_DATA");
if (!ipi_data_off)
return SBI_ENOMEM;
ret = sbi_ipi_event_create(&ipi_smode_ops);
if (ret < 0)
return ret;
ipi_smode_event = ret;
ret = sbi_ipi_event_create(&ipi_halt_ops);
if (ret < 0)
return ret;
ipi_halt_event = ret;
} else {
if (!ipi_data_off)
return SBI_ENOMEM;
if (SBI_IPI_EVENT_MAX <= ipi_smode_event ||
SBI_IPI_EVENT_MAX <= ipi_halt_event)
return SBI_ENOSPC;
}
ipi_data = sbi_scratch_offset_ptr(scratch, ipi_data_off);
ipi_data->ipi_type = 0x00;
ret = sbi_tlb_fifo_init(scratch, cold_boot);
/* Platform init */
ret = sbi_platform_ipi_init(sbi_platform_ptr(scratch), cold_boot);
if (ret)
return ret;
/* Enable software interrupts */
csr_set(CSR_MIE, MIP_MSIP);
return sbi_platform_ipi_init(sbi_platform_ptr(scratch), cold_boot);
return 0;
}
void sbi_ipi_exit(struct sbi_scratch *scratch)
{
/* Disable software interrupts */
csr_clear(CSR_MIE, MIP_MSIP);
/* Process pending IPIs */
sbi_ipi_process(scratch);
/* Platform exit */
sbi_platform_ipi_exit(sbi_platform_ptr(scratch));
}

View File

@@ -9,11 +9,11 @@
#include <sbi/riscv_asm.h>
#include <sbi/riscv_encoding.h>
#include <sbi/riscv_unpriv.h>
#include <sbi/riscv_fp.h>
#include <sbi/sbi_error.h>
#include <sbi/sbi_misaligned_ldst.h>
#include <sbi/sbi_trap.h>
#include <sbi/sbi_unpriv.h>
union reg_data {
u8 data_bytes[8];
@@ -22,23 +22,32 @@ union reg_data {
};
int sbi_misaligned_load_handler(u32 hartid, ulong mcause,
ulong addr, ulong tval2, ulong tinst,
struct sbi_trap_regs *regs,
struct sbi_scratch *scratch)
{
ulong insn;
union reg_data val;
struct unpriv_trap uptrap;
ulong addr = csr_read(CSR_MTVAL);
struct sbi_trap_info uptrap;
int i, fp = 0, shift = 0, len = 0;
#if __riscv_xlen == 32
bool virt = (regs->mstatusH & MSTATUSH_MPV) ? TRUE : FALSE;
#else
bool virt = (regs->mstatus & MSTATUS_MPV) ? TRUE : FALSE;
#endif
ulong insn = get_insn(regs->mepc, virt, scratch, &uptrap);
if (uptrap.cause)
return sbi_trap_redirect(regs, scratch, regs->mepc,
uptrap.cause, uptrap.tval);
if (tinst & 0x1) {
/*
* Bit[0] == 1 implies trapped instruction value is
* transformed instruction or custom instruction.
*/
insn = tinst | INSN_16BIT_MASK;
} else {
/*
* Bit[0] == 0 implies trapped instruction value is
* zero or special value.
*/
insn = sbi_get_insn(regs->mepc, scratch, &uptrap);
if (uptrap.cause) {
uptrap.epc = regs->mepc;
return sbi_trap_redirect(regs, &uptrap, scratch);
}
}
if ((insn & INSN_MASK_LW) == INSN_MATCH_LW) {
len = 4;
@@ -101,17 +110,23 @@ int sbi_misaligned_load_handler(u32 hartid, ulong mcause,
#endif
#endif
#endif
} else
return sbi_trap_redirect(regs, scratch, regs->mepc,
mcause, addr);
} else {
uptrap.epc = regs->mepc;
uptrap.cause = mcause;
uptrap.tval = addr;
uptrap.tval2 = tval2;
uptrap.tinst = tinst;
return sbi_trap_redirect(regs, &uptrap, scratch);
}
val.data_u64 = 0;
for (i = 0; i < len; i++) {
val.data_bytes[i] = load_u8((void *)(addr + i),
scratch, &uptrap);
if (uptrap.cause)
return sbi_trap_redirect(regs, scratch, regs->mepc,
uptrap.cause, uptrap.tval);
val.data_bytes[i] = sbi_load_u8((void *)(addr + i),
scratch, &uptrap);
if (uptrap.cause) {
uptrap.epc = regs->mepc;
return sbi_trap_redirect(regs, &uptrap, scratch);
}
}
if (!fp)
@@ -129,23 +144,32 @@ int sbi_misaligned_load_handler(u32 hartid, ulong mcause,
}
int sbi_misaligned_store_handler(u32 hartid, ulong mcause,
ulong addr, ulong tval2, ulong tinst,
struct sbi_trap_regs *regs,
struct sbi_scratch *scratch)
{
ulong insn;
union reg_data val;
struct unpriv_trap uptrap;
ulong addr = csr_read(CSR_MTVAL);
struct sbi_trap_info uptrap;
int i, len = 0;
#if __riscv_xlen == 32
bool virt = (regs->mstatusH & MSTATUSH_MPV) ? TRUE : FALSE;
#else
bool virt = (regs->mstatus & MSTATUS_MPV) ? TRUE : FALSE;
#endif
ulong insn = get_insn(regs->mepc, virt, scratch, &uptrap);
if (uptrap.cause)
return sbi_trap_redirect(regs, scratch, regs->mepc,
uptrap.cause, uptrap.tval);
if (tinst & 0x1) {
/*
* Bit[0] == 1 implies trapped instruction value is
* transformed instruction or custom instruction.
*/
insn = tinst | INSN_16BIT_MASK;
} else {
/*
* Bit[0] == 0 implies trapped instruction value is
* zero or special value.
*/
insn = sbi_get_insn(regs->mepc, scratch, &uptrap);
if (uptrap.cause) {
uptrap.epc = regs->mepc;
return sbi_trap_redirect(regs, &uptrap, scratch);
}
}
val.data_ulong = GET_RS2(insn, regs);
@@ -199,16 +223,22 @@ int sbi_misaligned_store_handler(u32 hartid, ulong mcause,
#endif
#endif
#endif
} else
return sbi_trap_redirect(regs, scratch, regs->mepc,
mcause, addr);
} else {
uptrap.epc = regs->mepc;
uptrap.cause = mcause;
uptrap.tval = addr;
uptrap.tval2 = tval2;
uptrap.tinst = tinst;
return sbi_trap_redirect(regs, &uptrap, scratch);
}
for (i = 0; i < len; i++) {
store_u8((void *)(addr + i), val.data_bytes[i],
scratch, &uptrap);
if (uptrap.cause)
return sbi_trap_redirect(regs, scratch, regs->mepc,
uptrap.cause, uptrap.tval);
sbi_store_u8((void *)(addr + i), val.data_bytes[i],
scratch, &uptrap);
if (uptrap.cause) {
uptrap.epc = regs->mepc;
return sbi_trap_redirect(regs, &uptrap, scratch);
}
}
regs->mepc += INSN_LEN(insn);

View File

@@ -8,14 +8,21 @@
*/
#include <sbi/riscv_locks.h>
#include <sbi/sbi_hart.h>
#include <sbi/sbi_platform.h>
#include <sbi/sbi_scratch.h>
#include <sbi/sbi_string.h>
static spinlock_t extra_lock = SPIN_LOCK_INITIALIZER;
static unsigned long extra_offset = SBI_SCRATCH_EXTRA_SPACE_OFFSET;
unsigned long sbi_scratch_alloc_offset(unsigned long size, const char *owner)
{
u32 i;
void *ptr;
unsigned long ret = 0;
struct sbi_scratch *scratch, *rscratch;
const struct sbi_platform *plat;
/*
* We have a simple brain-dead allocator which never expects
@@ -29,8 +36,8 @@ unsigned long sbi_scratch_alloc_offset(unsigned long size, const char *owner)
if (!size)
return 0;
while (size & (__SIZEOF_POINTER__ - 1))
size++;
if (size & (__SIZEOF_POINTER__ - 1))
size = (size & ~(__SIZEOF_POINTER__ - 1)) + __SIZEOF_POINTER__;
spin_lock(&extra_lock);
@@ -43,6 +50,16 @@ unsigned long sbi_scratch_alloc_offset(unsigned long size, const char *owner)
done:
spin_unlock(&extra_lock);
if (ret) {
scratch = sbi_scratch_thishart_ptr();
plat = sbi_platform_ptr(scratch);
for (i = 0; i < sbi_platform_hart_count(plat); i++) {
rscratch = sbi_hart_id_to_scratch(scratch, i);
ptr = sbi_scratch_offset_ptr(rscratch, ret);
sbi_memset(ptr, 0, size);
}
}
return ret;
}

View File

@@ -12,6 +12,7 @@
#include <sbi/sbi_platform.h>
#include <sbi/sbi_system.h>
#include <sbi/sbi_ipi.h>
#include <sbi/sbi_init.h>
int sbi_system_early_init(struct sbi_scratch *scratch, bool cold_boot)
{
@@ -23,23 +24,42 @@ int sbi_system_final_init(struct sbi_scratch *scratch, bool cold_boot)
return sbi_platform_final_init(sbi_platform_ptr(scratch), cold_boot);
}
void __attribute__((noreturn))
sbi_system_reboot(struct sbi_scratch *scratch, u32 type)
void sbi_system_early_exit(struct sbi_scratch *scratch)
{
sbi_platform_system_reboot(sbi_platform_ptr(scratch), type);
sbi_hart_hang();
sbi_platform_early_exit(sbi_platform_ptr(scratch));
}
void __attribute__((noreturn))
sbi_system_shutdown(struct sbi_scratch *scratch, u32 type)
void sbi_system_final_exit(struct sbi_scratch *scratch)
{
/* First try the platform-specific method */
sbi_platform_final_exit(sbi_platform_ptr(scratch));
}
void __noreturn sbi_system_reboot(struct sbi_scratch *scratch, u32 type)
{
u32 current_hartid_mask = 1UL << sbi_current_hartid();
/* Send HALT IPI to every hart other than the current hart */
sbi_ipi_send_halt(scratch,
sbi_hart_available_mask() & ~current_hartid_mask, 0);
/* Platform specific reooot */
sbi_platform_system_reboot(sbi_platform_ptr(scratch), type);
/* If platform specific reboot did not work then do sbi_exit() */
sbi_exit(scratch);
}
void __noreturn sbi_system_shutdown(struct sbi_scratch *scratch, u32 type)
{
u32 current_hartid_mask = 1UL << sbi_current_hartid();
/* Send HALT IPI to every hart other than the current hart */
sbi_ipi_send_halt(scratch,
sbi_hart_available_mask() & ~current_hartid_mask, 0);
/* Platform specific shutdown */
sbi_platform_system_shutdown(sbi_platform_ptr(scratch), type);
/* If that fails (or is not implemented) send an IPI on every
* hart to hang and then hang the current hart */
sbi_ipi_send_many(scratch, NULL, NULL, SBI_IPI_EVENT_HALT, NULL);
sbi_hart_hang();
/* If platform specific shutdown did not work then do sbi_exit() */
sbi_exit(scratch);
}

View File

@@ -76,11 +76,6 @@ void sbi_timer_set_delta_upper(struct sbi_scratch *scratch, ulong delta_upper)
*time_delta |= ((u64)delta_upper << 32);
}
void sbi_timer_event_stop(struct sbi_scratch *scratch)
{
sbi_platform_timer_event_stop(sbi_platform_ptr(scratch));
}
void sbi_timer_event_start(struct sbi_scratch *scratch, u64 next_event)
{
sbi_platform_timer_event_start(sbi_platform_ptr(scratch), next_event);
@@ -113,3 +108,13 @@ int sbi_timer_init(struct sbi_scratch *scratch, bool cold_boot)
return sbi_platform_timer_init(sbi_platform_ptr(scratch), cold_boot);
}
void sbi_timer_exit(struct sbi_scratch *scratch)
{
sbi_platform_timer_event_stop(sbi_platform_ptr(scratch));
csr_clear(CSR_MIP, MIP_STIP);
csr_clear(CSR_MIE, MIP_MTIP);
sbi_platform_timer_exit(sbi_platform_ptr(scratch));
}

View File

@@ -14,8 +14,10 @@
#include <sbi/sbi_error.h>
#include <sbi/sbi_fifo.h>
#include <sbi/sbi_hart.h>
#include <sbi/sbi_ipi.h>
#include <sbi/sbi_scratch.h>
#include <sbi/sbi_tlb.h>
#include <sbi/sbi_hfence.h>
#include <sbi/sbi_string.h>
#include <sbi/sbi_console.h>
#include <sbi/sbi_platform.h>
@@ -30,7 +32,39 @@ static void sbi_tlb_flush_all(void)
__asm__ __volatile("sfence.vma");
}
static void sbi_tlb_fifo_sfence_vma(struct sbi_tlb_info *tinfo)
static void sbi_tlb_hfence_vvma(struct sbi_tlb_info *tinfo)
{
unsigned long start = tinfo->start;
unsigned long size = tinfo->size;
unsigned long i;
if ((start == 0 && size == 0) || (size == SBI_TLB_FLUSH_ALL)) {
__sbi_hfence_vvma_all();
return;
}
for (i = 0; i < size; i += PAGE_SIZE) {
__sbi_hfence_vvma_va(start+i);
}
}
static void sbi_tlb_hfence_gvma(struct sbi_tlb_info *tinfo)
{
unsigned long start = tinfo->start;
unsigned long size = tinfo->size;
unsigned long i;
if ((start == 0 && size == 0) || (size == SBI_TLB_FLUSH_ALL)) {
__sbi_hfence_gvma_all();
return;
}
for (i = 0; i < size; i += PAGE_SIZE) {
__sbi_hfence_gvma_gpa(start+i);
}
}
static void sbi_tlb_sfence_vma(struct sbi_tlb_info *tinfo)
{
unsigned long start = tinfo->start;
unsigned long size = tinfo->size;
@@ -49,7 +83,51 @@ static void sbi_tlb_fifo_sfence_vma(struct sbi_tlb_info *tinfo)
}
}
static void sbi_tlb_fifo_sfence_vma_asid(struct sbi_tlb_info *tinfo)
static void sbi_tlb_hfence_vvma_asid(struct sbi_tlb_info *tinfo)
{
unsigned long start = tinfo->start;
unsigned long size = tinfo->size;
unsigned long asid = tinfo->asid;
unsigned long i;
if (start == 0 && size == 0) {
__sbi_hfence_vvma_all();
return;
}
if (size == SBI_TLB_FLUSH_ALL) {
__sbi_hfence_vvma_asid(asid);
return;
}
for (i = 0; i < size; i += PAGE_SIZE) {
__sbi_hfence_vvma_asid_va(asid, start + i);
}
}
static void sbi_tlb_hfence_gvma_vmid(struct sbi_tlb_info *tinfo)
{
unsigned long start = tinfo->start;
unsigned long size = tinfo->size;
unsigned long vmid = tinfo->asid;
unsigned long i;
if (start == 0 && size == 0) {
__sbi_hfence_gvma_all();
return;
}
if (size == SBI_TLB_FLUSH_ALL) {
__sbi_hfence_gvma_vmid(vmid);
return;
}
for (i = 0; i < size; i += PAGE_SIZE) {
__sbi_hfence_gvma_vmid_gpa(vmid, start+i);
}
}
static void sbi_tlb_sfence_vma_asid(struct sbi_tlb_info *tinfo)
{
unsigned long start = tinfo->start;
unsigned long size = tinfo->size;
@@ -80,15 +158,32 @@ static void sbi_tlb_fifo_sfence_vma_asid(struct sbi_tlb_info *tinfo)
static void sbi_tlb_local_flush(struct sbi_tlb_info *tinfo)
{
if (tinfo->type == SBI_TLB_FLUSH_VMA) {
sbi_tlb_fifo_sfence_vma(tinfo);
} else if (tinfo->type == SBI_TLB_FLUSH_VMA_ASID) {
sbi_tlb_fifo_sfence_vma_asid(tinfo);
} else if (tinfo->type == SBI_ITLB_FLUSH)
switch (tinfo->type) {
case SBI_TLB_FLUSH_VMA:
sbi_tlb_sfence_vma(tinfo);
break;
case SBI_TLB_FLUSH_VMA_ASID:
sbi_tlb_sfence_vma_asid(tinfo);
break;
case SBI_TLB_FLUSH_GVMA:
sbi_tlb_hfence_gvma(tinfo);
break;
case SBI_TLB_FLUSH_GVMA_VMID:
sbi_tlb_hfence_gvma_vmid(tinfo);
break;
case SBI_TLB_FLUSH_VVMA:
sbi_tlb_hfence_vvma(tinfo);
break;
case SBI_TLB_FLUSH_VVMA_ASID:
sbi_tlb_hfence_vvma_asid(tinfo);
break;
case SBI_ITLB_FLUSH:
__asm__ __volatile("fence.i");
else
break;
default:
sbi_printf("Invalid tlb flush request type [%lu]\n",
tinfo->type);
}
return;
}
@@ -111,7 +206,7 @@ static void sbi_tlb_entry_process(struct sbi_scratch *scratch,
}
}
static void sbi_tlb_fifo_process_count(struct sbi_scratch *scratch, int count)
static void sbi_tlb_process_count(struct sbi_scratch *scratch, int count)
{
struct sbi_tlb_info tinfo;
u32 deq_count = 0;
@@ -127,7 +222,7 @@ static void sbi_tlb_fifo_process_count(struct sbi_scratch *scratch, int count)
}
}
void sbi_tlb_fifo_process(struct sbi_scratch *scratch)
static void sbi_tlb_process(struct sbi_scratch *scratch)
{
struct sbi_tlb_info tinfo;
struct sbi_fifo *tlb_fifo =
@@ -137,7 +232,7 @@ void sbi_tlb_fifo_process(struct sbi_scratch *scratch)
sbi_tlb_entry_process(scratch, &tinfo);
}
void sbi_tlb_fifo_sync(struct sbi_scratch *scratch)
static void sbi_tlb_sync(struct sbi_scratch *scratch)
{
unsigned long *tlb_sync =
sbi_scratch_offset_ptr(scratch, tlb_sync_off);
@@ -147,14 +242,14 @@ void sbi_tlb_fifo_sync(struct sbi_scratch *scratch)
* While we are waiting for remote hart to set the sync,
* consume fifo requests to avoid deadlock.
*/
sbi_tlb_fifo_process_count(scratch, 1);
sbi_tlb_process_count(scratch, 1);
}
return;
}
static inline int __sbi_tlb_fifo_range_check(struct sbi_tlb_info *curr,
struct sbi_tlb_info *next)
static inline int __sbi_tlb_range_check(struct sbi_tlb_info *curr,
struct sbi_tlb_info *next)
{
unsigned long curr_end;
unsigned long next_end;
@@ -196,7 +291,7 @@ static inline int __sbi_tlb_fifo_range_check(struct sbi_tlb_info *curr,
* before continuing the while loop. This method is preferred over wfi/ipi because
* of MMIO cost involved in later method.
*/
static int sbi_tlb_fifo_update_cb(void *in, void *data)
static int sbi_tlb_update_cb(void *in, void *data)
{
struct sbi_tlb_info *curr;
struct sbi_tlb_info *next;
@@ -211,20 +306,21 @@ static int sbi_tlb_fifo_update_cb(void *in, void *data)
if (next->type == SBI_TLB_FLUSH_VMA_ASID &&
curr->type == SBI_TLB_FLUSH_VMA_ASID) {
if (next->asid == curr->asid)
ret = __sbi_tlb_fifo_range_check(curr, next);
ret = __sbi_tlb_range_check(curr, next);
} else if (next->type == SBI_TLB_FLUSH_VMA &&
curr->type == SBI_TLB_FLUSH_VMA) {
ret = __sbi_tlb_fifo_range_check(curr, next);
ret = __sbi_tlb_range_check(curr, next);
}
return ret;
}
int sbi_tlb_fifo_update(struct sbi_scratch *rscratch, u32 hartid, void *data)
static int sbi_tlb_update(struct sbi_scratch *scratch,
struct sbi_scratch *remote_scratch,
u32 remote_hartid, void *data)
{
int ret;
struct sbi_fifo *tlb_fifo_r;
struct sbi_scratch *lscratch;
struct sbi_tlb_info *tinfo = data;
u32 curr_hartid = sbi_current_hartid();
@@ -242,15 +338,14 @@ int sbi_tlb_fifo_update(struct sbi_scratch *rscratch, u32 hartid, void *data)
* If the request is to queue a tlb flush entry for itself
* then just do a local flush and return;
*/
if (hartid == curr_hartid) {
if (remote_hartid == curr_hartid) {
sbi_tlb_local_flush(tinfo);
return -1;
}
lscratch = sbi_hart_id_to_scratch(rscratch, curr_hartid);
tlb_fifo_r = sbi_scratch_offset_ptr(rscratch, tlb_fifo_off);
tlb_fifo_r = sbi_scratch_offset_ptr(remote_scratch, tlb_fifo_off);
ret = sbi_fifo_inplace_update(tlb_fifo_r, data, sbi_tlb_fifo_update_cb);
ret = sbi_fifo_inplace_update(tlb_fifo_r, data, sbi_tlb_update_cb);
if (ret != SBI_FIFO_UNCHANGED) {
return 1;
}
@@ -264,16 +359,32 @@ int sbi_tlb_fifo_update(struct sbi_scratch *rscratch, u32 hartid, void *data)
* TODO: Introduce a wait/wakeup event mechanism to handle
* this properly.
*/
sbi_tlb_fifo_process_count(lscratch, 1);
sbi_dprintf(rscratch, "hart%d: hart%d tlb fifo full\n",
curr_hartid, hartid);
sbi_tlb_process_count(scratch, 1);
sbi_dprintf(remote_scratch, "hart%d: hart%d tlb fifo full\n",
curr_hartid, remote_hartid);
}
return 0;
}
int sbi_tlb_fifo_init(struct sbi_scratch *scratch, bool cold_boot)
static struct sbi_ipi_event_ops tlb_ops = {
.name = "IPI_TLB",
.update = sbi_tlb_update,
.sync = sbi_tlb_sync,
.process = sbi_tlb_process,
};
static u32 tlb_event = SBI_IPI_EVENT_MAX;
int sbi_tlb_request(struct sbi_scratch *scratch, ulong hmask,
ulong hbase, struct sbi_tlb_info *tinfo)
{
return sbi_ipi_send_many(scratch, hmask, hbase, tlb_event, tinfo);
}
int sbi_tlb_init(struct sbi_scratch *scratch, bool cold_boot)
{
int ret;
void *tlb_mem;
unsigned long *tlb_sync;
struct sbi_fifo *tlb_q;
@@ -298,12 +409,22 @@ int sbi_tlb_fifo_init(struct sbi_scratch *scratch, bool cold_boot)
sbi_scratch_free_offset(tlb_sync_off);
return SBI_ENOMEM;
}
ret = sbi_ipi_event_create(&tlb_ops);
if (ret < 0) {
sbi_scratch_free_offset(tlb_fifo_mem_off);
sbi_scratch_free_offset(tlb_fifo_off);
sbi_scratch_free_offset(tlb_sync_off);
return ret;
}
tlb_event = ret;
tlb_range_flush_limit = sbi_platform_tlbr_flush_limit(plat);
} else {
if (!tlb_sync_off ||
!tlb_fifo_off ||
!tlb_fifo_mem_off)
return SBI_ENOMEM;
if (SBI_IPI_EVENT_MAX <= tlb_event)
return SBI_ENOSPC;
}
tlb_sync = sbi_scratch_offset_ptr(scratch, tlb_sync_off);

View File

@@ -9,7 +9,6 @@
#include <sbi/riscv_asm.h>
#include <sbi/riscv_encoding.h>
#include <sbi/riscv_unpriv.h>
#include <sbi/sbi_console.h>
#include <sbi/sbi_ecall.h>
#include <sbi/sbi_error.h>
@@ -21,12 +20,17 @@
#include <sbi/sbi_trap.h>
static void __noreturn sbi_trap_error(const char *msg, int rc, u32 hartid,
ulong mcause, ulong mtval,
struct sbi_trap_regs *regs)
ulong mcause, ulong mtval, ulong mtval2,
ulong mtinst, struct sbi_trap_regs *regs)
{
sbi_printf("%s: hart%d: %s (error %d)\n", __func__, hartid, msg, rc);
sbi_printf("%s: hart%d: mcause=0x%" PRILX " mtval=0x%" PRILX "\n",
__func__, hartid, mcause, mtval);
if (misa_extension('H')) {
sbi_printf("%s: hart%d: mtval2=0x%" PRILX
" mtinst=0x%" PRILX "\n",
__func__, hartid, mtval2, mtinst);
}
sbi_printf("%s: hart%d: mepc=0x%" PRILX " mstatus=0x%" PRILX "\n",
__func__, hartid, regs->mepc, regs->mstatus);
sbi_printf("%s: hart%d: %s=0x%" PRILX " %s=0x%" PRILX "\n", __func__,
@@ -69,23 +73,20 @@ static void __noreturn sbi_trap_error(const char *msg, int rc, u32 hartid,
* Redirect trap to lower privledge mode (S-mode or U-mode)
*
* @param regs pointer to register state
* @param trap pointer to trap details
* @param scratch pointer to sbi_scratch of current HART
* @param epc error PC for lower privledge mode
* @param cause exception cause for lower privledge mode
* @param tval trap value for lower privledge mode
*
* @return 0 on success and negative error code on failure
*/
int sbi_trap_redirect(struct sbi_trap_regs *regs, struct sbi_scratch *scratch,
ulong epc, ulong cause, ulong tval)
int sbi_trap_redirect(struct sbi_trap_regs *regs,
struct sbi_trap_info *trap,
struct sbi_scratch *scratch)
{
ulong hstatus, vsstatus, prev_mode;
#if __riscv_xlen == 32
bool prev_virt = (regs->mstatusH & MSTATUSH_MPV) ? TRUE : FALSE;
bool prev_stage2 = (regs->mstatusH & MSTATUSH_MTL) ? TRUE : FALSE;
#else
bool prev_virt = (regs->mstatus & MSTATUS_MPV) ? TRUE : FALSE;
bool prev_stage2 = (regs->mstatus & MSTATUS_MTL) ? TRUE : FALSE;
#endif
/* By default, we redirect to HS-mode */
bool next_virt = FALSE;
@@ -96,8 +97,8 @@ int sbi_trap_redirect(struct sbi_trap_regs *regs, struct sbi_scratch *scratch,
return SBI_ENOTSUPP;
/* For certain exceptions from VS/VU-mode we redirect to VS-mode */
if (misa_extension('H') && prev_virt && !prev_stage2) {
switch (cause) {
if (misa_extension('H') && prev_virt) {
switch (trap->cause) {
case CAUSE_FETCH_PAGE_FAULT:
case CAUSE_LOAD_PAGE_FAULT:
case CAUSE_STORE_PAGE_FAULT:
@@ -108,20 +109,18 @@ int sbi_trap_redirect(struct sbi_trap_regs *regs, struct sbi_scratch *scratch,
};
}
/* Update MSTATUS MPV and MTL bits */
/* Update MSTATUS MPV bits */
#if __riscv_xlen == 32
regs->mstatusH &= ~MSTATUSH_MPV;
regs->mstatusH |= (next_virt) ? MSTATUSH_MPV : 0UL;
regs->mstatusH &= ~MSTATUSH_MTL;
#else
regs->mstatus &= ~MSTATUS_MPV;
regs->mstatus |= (next_virt) ? MSTATUS_MPV : 0UL;
regs->mstatus &= ~MSTATUS_MTL;
#endif
/* Update HSTATUS for VS/VU-mode to HS-mode transition */
if (misa_extension('H') && prev_virt && !next_virt) {
/* Update HSTATUS SP2P, SP2V, SPV, and STL bits */
/* Update HSTATUS SP2P, SP2V, and SPV bits */
hstatus = csr_read(CSR_HSTATUS);
hstatus &= ~HSTATUS_SP2P;
hstatus |= (regs->mstatus & MSTATUS_SPP) ? HSTATUS_SP2P : 0;
@@ -129,17 +128,17 @@ int sbi_trap_redirect(struct sbi_trap_regs *regs, struct sbi_scratch *scratch,
hstatus |= (hstatus & HSTATUS_SPV) ? HSTATUS_SP2V : 0;
hstatus &= ~HSTATUS_SPV;
hstatus |= (prev_virt) ? HSTATUS_SPV : 0;
hstatus &= ~HSTATUS_STL;
hstatus |= (prev_stage2) ? HSTATUS_STL : 0;
csr_write(CSR_HSTATUS, hstatus);
csr_write(CSR_HTVAL, trap->tval2);
csr_write(CSR_HTINST, trap->tinst);
}
/* Update exception related CSRs */
if (next_virt) {
/* Update VS-mode exception info */
csr_write(CSR_VSTVAL, tval);
csr_write(CSR_VSEPC, epc);
csr_write(CSR_VSCAUSE, cause);
csr_write(CSR_VSTVAL, trap->tval);
csr_write(CSR_VSEPC, trap->epc);
csr_write(CSR_VSCAUSE, trap->cause);
/* Set MEPC to VS-mode exception vector base */
regs->mepc = csr_read(CSR_VSTVEC);
@@ -168,9 +167,9 @@ int sbi_trap_redirect(struct sbi_trap_regs *regs, struct sbi_scratch *scratch,
csr_write(CSR_VSSTATUS, vsstatus);
} else {
/* Update S-mode exception info */
csr_write(CSR_STVAL, tval);
csr_write(CSR_SEPC, epc);
csr_write(CSR_SCAUSE, cause);
csr_write(CSR_STVAL, trap->tval);
csr_write(CSR_SEPC, trap->epc);
csr_write(CSR_SCAUSE, trap->cause);
/* Set MEPC to S-mode exception vector base */
regs->mepc = csr_read(CSR_STVEC);
@@ -205,20 +204,28 @@ int sbi_trap_redirect(struct sbi_trap_regs *regs, struct sbi_scratch *scratch,
* 1. The 'mscratch' CSR is pointing to sbi_scratch of current HART
* 2. The 'mcause' CSR is having exception/interrupt cause
* 3. The 'mtval' CSR is having additional trap information
* 4. Stack pointer (SP) is setup for current HART
* 5. Interrupts are disabled in MSTATUS CSR
* 4. The 'mtval2' CSR is having additional trap information
* 5. The 'mtinst' CSR is having decoded trap instruction
* 6. Stack pointer (SP) is setup for current HART
* 7. Interrupts are disabled in MSTATUS CSR
*
* @param regs pointer to register state
* @param scratch pointer to sbi_scratch of current HART
*/
void sbi_trap_handler(struct sbi_trap_regs *regs, struct sbi_scratch *scratch)
void sbi_trap_handler(struct sbi_trap_regs *regs,
struct sbi_scratch *scratch)
{
int rc = SBI_ENOTSUPP;
const char *msg = "trap handler failed";
u32 hartid = sbi_current_hartid();
ulong mcause = csr_read(CSR_MCAUSE);
ulong mtval = csr_read(CSR_MTVAL);
struct unpriv_trap *uptrap;
ulong mtval = csr_read(CSR_MTVAL), mtval2 = 0, mtinst = 0;
struct sbi_trap_info trap, *uptrap;
if (misa_extension('H')) {
mtval2 = csr_read(CSR_MTVAL2);
mtinst = csr_read(CSR_MTINST);
}
if (mcause & (1UL << (__riscv_xlen - 1))) {
mcause &= ~(1UL << (__riscv_xlen - 1));
@@ -238,15 +245,19 @@ void sbi_trap_handler(struct sbi_trap_regs *regs, struct sbi_scratch *scratch)
switch (mcause) {
case CAUSE_ILLEGAL_INSTRUCTION:
rc = sbi_illegal_insn_handler(hartid, mcause, regs, scratch);
rc = sbi_illegal_insn_handler(hartid, mcause, mtval,
regs, scratch);
msg = "illegal instruction handler failed";
break;
case CAUSE_MISALIGNED_LOAD:
rc = sbi_misaligned_load_handler(hartid, mcause, regs, scratch);
rc = sbi_misaligned_load_handler(hartid, mcause, mtval,
mtval2, mtinst, regs,
scratch);
msg = "misaligned load handler failed";
break;
case CAUSE_MISALIGNED_STORE:
rc = sbi_misaligned_store_handler(hartid, mcause, regs,
rc = sbi_misaligned_store_handler(hartid, mcause, mtval,
mtval2, mtinst, regs,
scratch);
msg = "misaligned store handler failed";
break;
@@ -262,25 +273,36 @@ void sbi_trap_handler(struct sbi_trap_regs *regs, struct sbi_scratch *scratch)
uptrap = sbi_hart_get_trap_info(scratch);
if ((regs->mstatus & MSTATUS_MPRV) && uptrap) {
rc = 0;
regs->mepc += uptrap->ilen;
uptrap->epc = regs->mepc;
regs->mepc += 4;
uptrap->cause = mcause;
uptrap->tval = mtval;
uptrap->tval2 = mtval2;
uptrap->tinst = mtinst;
} else {
rc = sbi_trap_redirect(regs, scratch, regs->mepc,
mcause, mtval);
trap.epc = regs->mepc;
trap.cause = mcause;
trap.tval = mtval;
trap.tval2 = mtval2;
trap.tinst = mtinst;
rc = sbi_trap_redirect(regs, &trap, scratch);
}
msg = "page/access fault handler failed";
break;
default:
/* If the trap came from S or U mode, redirect it there */
rc = sbi_trap_redirect(regs, scratch, regs->mepc,
mcause, mtval);
trap.epc = regs->mepc;
trap.cause = mcause;
trap.tval = mtval;
trap.tval2 = mtval2;
trap.tinst = mtinst;
rc = sbi_trap_redirect(regs, &trap, scratch);
break;
};
trap_error:
if (rc) {
sbi_trap_error(msg, rc, hartid, mcause, csr_read(CSR_MTVAL),
regs);
sbi_trap_error(msg, rc, hartid, mcause, mtval,
mtval2, mtinst, regs);
}
}

View File

@@ -8,25 +8,31 @@
*/
#include <sbi/riscv_encoding.h>
#include <sbi/riscv_unpriv.h>
#include <sbi/sbi_bits.h>
#include <sbi/sbi_hart.h>
#include <sbi/sbi_scratch.h>
#include <sbi/sbi_trap.h>
#include <sbi/sbi_unpriv.h>
#define DEFINE_UNPRIVILEGED_LOAD_FUNCTION(type, insn, insnlen) \
type load_##type(const type *addr, \
struct sbi_scratch *scratch, \
struct unpriv_trap *trap) \
#define DEFINE_UNPRIVILEGED_LOAD_FUNCTION(type, insn) \
type sbi_load_##type(const type *addr, \
struct sbi_scratch *scratch, \
struct sbi_trap_info *trap) \
{ \
register ulong __mstatus asm("a2"); \
type val = 0; \
trap->ilen = insnlen; \
trap->epc = 0; \
trap->cause = 0; \
trap->tval = 0; \
trap->tval2 = 0; \
trap->tinst = 0; \
sbi_hart_set_trap_info(scratch, trap); \
asm volatile( \
"csrrs %0, " STR(CSR_MSTATUS) ", %3\n" \
".option push\n" \
".option norvc\n" \
#insn " %1, %2\n" \
".option pop\n" \
"csrw " STR(CSR_MSTATUS) ", %0" \
: "+&r"(__mstatus), "=&r"(val) \
: "m"(*addr), "r"(MSTATUS_MPRV)); \
@@ -34,101 +40,116 @@
return val; \
}
#define DEFINE_UNPRIVILEGED_STORE_FUNCTION(type, insn, insnlen) \
void store_##type(type *addr, type val, \
struct sbi_scratch *scratch, \
struct unpriv_trap *trap) \
#define DEFINE_UNPRIVILEGED_STORE_FUNCTION(type, insn) \
void sbi_store_##type(type *addr, type val, \
struct sbi_scratch *scratch, \
struct sbi_trap_info *trap) \
{ \
register ulong __mstatus asm("a3"); \
trap->ilen = insnlen; \
trap->epc = 0; \
trap->cause = 0; \
trap->tval = 0; \
trap->tval2 = 0; \
trap->tinst = 0; \
sbi_hart_set_trap_info(scratch, trap); \
asm volatile( \
"csrrs %0, " STR(CSR_MSTATUS) ", %3\n" \
".option push\n" \
".option norvc\n" \
#insn " %1, %2\n" \
".option pop\n" \
"csrw " STR(CSR_MSTATUS) ", %0" \
: "+&r"(__mstatus) \
: "r"(val), "m"(*addr), "r"(MSTATUS_MPRV)); \
sbi_hart_set_trap_info(scratch, NULL); \
}
DEFINE_UNPRIVILEGED_LOAD_FUNCTION(u8, lbu, 4)
DEFINE_UNPRIVILEGED_LOAD_FUNCTION(u16, lhu, 4)
DEFINE_UNPRIVILEGED_LOAD_FUNCTION(s8, lb, 4)
DEFINE_UNPRIVILEGED_LOAD_FUNCTION(s16, lh, 4)
DEFINE_UNPRIVILEGED_LOAD_FUNCTION(s32, lw, 2)
DEFINE_UNPRIVILEGED_STORE_FUNCTION(u8, sb, 4)
DEFINE_UNPRIVILEGED_STORE_FUNCTION(u16, sh, 4)
DEFINE_UNPRIVILEGED_STORE_FUNCTION(u32, sw, 2)
DEFINE_UNPRIVILEGED_LOAD_FUNCTION(u8, lbu)
DEFINE_UNPRIVILEGED_LOAD_FUNCTION(u16, lhu)
DEFINE_UNPRIVILEGED_LOAD_FUNCTION(s8, lb)
DEFINE_UNPRIVILEGED_LOAD_FUNCTION(s16, lh)
DEFINE_UNPRIVILEGED_LOAD_FUNCTION(s32, lw)
DEFINE_UNPRIVILEGED_STORE_FUNCTION(u8, sb)
DEFINE_UNPRIVILEGED_STORE_FUNCTION(u16, sh)
DEFINE_UNPRIVILEGED_STORE_FUNCTION(u32, sw)
#if __riscv_xlen == 64
DEFINE_UNPRIVILEGED_LOAD_FUNCTION(u32, lwu, 4)
DEFINE_UNPRIVILEGED_LOAD_FUNCTION(u64, ld, 2)
DEFINE_UNPRIVILEGED_STORE_FUNCTION(u64, sd, 2)
DEFINE_UNPRIVILEGED_LOAD_FUNCTION(ulong, ld, 2)
DEFINE_UNPRIVILEGED_LOAD_FUNCTION(u32, lwu)
DEFINE_UNPRIVILEGED_LOAD_FUNCTION(u64, ld)
DEFINE_UNPRIVILEGED_STORE_FUNCTION(u64, sd)
DEFINE_UNPRIVILEGED_LOAD_FUNCTION(ulong, ld)
#else
DEFINE_UNPRIVILEGED_LOAD_FUNCTION(u32, lw, 2)
DEFINE_UNPRIVILEGED_LOAD_FUNCTION(ulong, lw, 2)
DEFINE_UNPRIVILEGED_LOAD_FUNCTION(u32, lw)
DEFINE_UNPRIVILEGED_LOAD_FUNCTION(ulong, lw)
u64 load_u64(const u64 *addr,
struct sbi_scratch *scratch, struct unpriv_trap *trap)
u64 sbi_load_u64(const u64 *addr,
struct sbi_scratch *scratch,
struct sbi_trap_info *trap)
{
u64 ret = load_u32((u32 *)addr, scratch, trap);
u64 ret = sbi_load_u32((u32 *)addr, scratch, trap);
if (trap->cause)
return 0;
ret |= ((u64)load_u32((u32 *)addr + 1, scratch, trap) << 32);
ret |= ((u64)sbi_load_u32((u32 *)addr + 1, scratch, trap) << 32);
if (trap->cause)
return 0;
return ret;
}
void store_u64(u64 *addr, u64 val,
struct sbi_scratch *scratch, struct unpriv_trap *trap)
void sbi_store_u64(u64 *addr, u64 val,
struct sbi_scratch *scratch,
struct sbi_trap_info *trap)
{
store_u32((u32 *)addr, val, scratch, trap);
sbi_store_u32((u32 *)addr, val, scratch, trap);
if (trap->cause)
return;
store_u32((u32 *)addr + 1, val >> 32, scratch, trap);
sbi_store_u32((u32 *)addr + 1, val >> 32, scratch, trap);
if (trap->cause)
return;
}
#endif
ulong get_insn(ulong mepc, bool virt, struct sbi_scratch *scratch,
struct unpriv_trap *trap)
ulong sbi_get_insn(ulong mepc, struct sbi_scratch *scratch,
struct sbi_trap_info *trap)
{
ulong __mstatus = 0, __vsstatus = 0, val = 0;
ulong __mstatus = 0, val = 0;
#ifdef __riscv_compressed
ulong rvc_mask = 3, tmp;
#endif
trap->ilen = 4;
trap->epc = 0;
trap->cause = 0;
trap->tval = 0;
trap->tval2 = 0;
trap->tinst = 0;
sbi_hart_set_trap_info(scratch, trap);
if (virt)
__vsstatus = csr_read_set(CSR_VSSTATUS, SSTATUS_MXR);
#ifndef __riscv_compressed
asm("csrrs %[mstatus], " STR(CSR_MSTATUS) ", %[mprv]\n"
".option push\n"
".option norvc\n"
#if __riscv_xlen == 64
STR(LWU) " %[insn], (%[addr])\n"
#else
STR(LW) " %[insn], (%[addr])\n"
#endif
".option pop\n"
"csrw " STR(CSR_MSTATUS) ", %[mstatus]"
: [mstatus] "+&r"(__mstatus), [insn] "=&r"(val)
: [mprv] "r"(MSTATUS_MPRV | MSTATUS_MXR), [addr] "r"(mepc));
#else
asm("csrrs %[mstatus], " STR(CSR_MSTATUS) ", %[mprv]\n"
".option push\n"
".option norvc\n"
"lhu %[insn], (%[addr])\n"
".option pop\n"
"and %[tmp], %[insn], %[rvc_mask]\n"
"bne %[tmp], %[rvc_mask], 2f\n"
".option push\n"
".option norvc\n"
"lhu %[tmp], 2(%[addr])\n"
".option pop\n"
"sll %[tmp], %[tmp], 16\n"
"add %[insn], %[insn], %[tmp]\n"
"2: csrw " STR(CSR_MSTATUS) ", %[mstatus]"
@@ -137,10 +158,8 @@ ulong get_insn(ulong mepc, bool virt, struct sbi_scratch *scratch,
[rvc_mask] "r"(rvc_mask));
#endif
if (virt)
csr_write(CSR_VSSTATUS, __vsstatus);
sbi_hart_set_trap_info(scratch, NULL);
switch (trap->cause) {
case CAUSE_LOAD_ACCESS:
trap->cause = CAUSE_FETCH_ACCESS;
@@ -150,6 +169,10 @@ ulong get_insn(ulong mepc, bool virt, struct sbi_scratch *scratch,
trap->cause = CAUSE_FETCH_PAGE_FAULT;
trap->tval = mepc;
break;
case CAUSE_LOAD_GUEST_PAGE_FAULT:
trap->cause = CAUSE_FETCH_GUEST_PAGE_FAULT;
trap->tval = mepc;
break;
default:
break;
};

View File

@@ -91,13 +91,13 @@ int plic_warm_irqchip_init(u32 target_hart, int m_cntx_id, int s_cntx_id)
plic_set_ie(s_cntx_id, i, 0);
}
/* By default, enable M-mode threshold */
/* By default, disable M-mode threshold */
if (m_cntx_id > -1)
plic_set_thresh(m_cntx_id, 1);
plic_set_thresh(m_cntx_id, 0xffffffff);
/* By default, disable S-mode threshold */
if (s_cntx_id > -1)
plic_set_thresh(s_cntx_id, 0);
plic_set_thresh(s_cntx_id, 0xffffffff);
return 0;
}
@@ -112,7 +112,7 @@ int plic_cold_irqchip_init(unsigned long base, u32 num_sources, u32 hart_count)
/* Configure default priorities of all IRQs */
for (i = 1; i <= plic_num_sources; i++)
plic_set_priority(i, 1);
plic_set_priority(i, 0);
return 0;
}

View File

@@ -62,25 +62,45 @@ static volatile void *clint_time_base;
static volatile u64 *clint_time_val;
static volatile u64 *clint_time_cmp;
static inline u32 clint_time_read_hi()
#if __riscv_xlen != 32
static u64 clint_time_rd64(volatile u64 *addr)
{
return readl_relaxed((u32 *)clint_time_val + 1);
return readq_relaxed(addr);
}
u64 clint_timer_value(void)
static void clint_time_wr64(u64 value, volatile u64 *addr)
{
writeq_relaxed(value, addr);
}
#endif
static u64 clint_time_rd32(volatile u64 *addr)
{
#if __riscv_xlen == 64
return readq_relaxed(clint_time_val);
#else
u32 lo, hi;
do {
hi = clint_time_read_hi();
lo = readl_relaxed(clint_time_val);
} while (hi != clint_time_read_hi());
hi = readl_relaxed((u32 *)addr + 1);
lo = readl_relaxed((u32 *)addr);
} while (hi != readl_relaxed((u32 *)addr + 1));
return ((u64)hi << 32) | (u64)lo;
#endif
}
static void clint_time_wr32(u64 value, volatile u64 *addr)
{
u32 mask = -1U;
writel_relaxed(value & mask, (void *)(addr));
writel_relaxed(value >> 32, (void *)(addr) + 0x04);
}
static u64 (*clint_time_rd)(volatile u64 *addr) = clint_time_rd32;
static void (*clint_time_wr)(u64 value, volatile u64 *addr) = clint_time_wr32;
u64 clint_timer_value(void)
{
/* Read CLINT Time Value */
return clint_time_rd(clint_time_val);
}
void clint_timer_event_stop(void)
@@ -90,13 +110,8 @@ void clint_timer_event_stop(void)
if (clint_time_hart_count <= target_hart)
return;
/* Clear CLINT Time Compare */
#if __riscv_xlen == 64
writeq_relaxed(-1ULL, &clint_time_cmp[target_hart]);
#else
writel_relaxed(-1UL, &clint_time_cmp[target_hart]);
writel_relaxed(-1UL, (void *)(&clint_time_cmp[target_hart]) + 0x04);
#endif
/* Clear CLINT Time Compare */
clint_time_wr(-1ULL, &clint_time_cmp[target_hart]);
}
void clint_timer_event_start(u64 next_event)
@@ -106,15 +121,8 @@ void clint_timer_event_start(u64 next_event)
if (clint_time_hart_count <= target_hart)
return;
/* Program CLINT Time Compare */
#if __riscv_xlen == 64
writeq_relaxed(next_event, &clint_time_cmp[target_hart]);
#else
u32 mask = -1UL;
writel_relaxed(next_event & mask, &clint_time_cmp[target_hart]);
writel_relaxed(next_event >> 32,
(void *)(&clint_time_cmp[target_hart]) + 0x04);
#endif
/* Program CLINT Time Compare */
clint_time_wr(next_event, &clint_time_cmp[target_hart]);
}
int clint_warm_timer_init(void)
@@ -124,24 +132,28 @@ int clint_warm_timer_init(void)
if (clint_time_hart_count <= target_hart || !clint_time_base)
return -1;
/* Clear CLINT Time Compare */
#if __riscv_xlen == 64
writeq_relaxed(-1ULL, &clint_time_cmp[target_hart]);
#else
writel_relaxed(-1UL, &clint_time_cmp[target_hart]);
writel_relaxed(-1UL, (void *)(&clint_time_cmp[target_hart]) + 0x04);
/* Clear CLINT Time Compare */
clint_time_wr(-1ULL, &clint_time_cmp[target_hart]);
return 0;
}
int clint_cold_timer_init(unsigned long base, u32 hart_count,
bool has_64bit_mmio)
{
/* Figure-out CLINT Time register address */
clint_time_hart_count = hart_count;
clint_time_base = (void *)base;
clint_time_val = (u64 *)(clint_time_base + 0xbff8);
clint_time_cmp = (u64 *)(clint_time_base + 0x4000);
/* Override read/write accessors for 64bit MMIO */
#if __riscv_xlen != 32
if (has_64bit_mmio) {
clint_time_rd = clint_time_rd64;
clint_time_wr = clint_time_wr64;
}
#endif
return 0;
}
int clint_cold_timer_init(unsigned long base, u32 hart_count)
{
/* Figure-out CLINT Time register address */
clint_time_hart_count = hart_count;
clint_time_base = (void *)base;
clint_time_val = (u64 *)(clint_time_base + 0xbff8);
clint_time_cmp = (u64 *)(clint_time_base + 0x4000);
return 0;
}

149
lib/utils/sys/htif.c Normal file
View File

@@ -0,0 +1,149 @@
/*
* SPDX-License-Identifier: BSD-3-Clause
*
* Copyright (c) 2010-2020, The Regents of the University of California
* (Regents). All Rights Reserved.
*/
#include <sbi/riscv_locks.h>
#include <sbi_utils/sys/htif.h>
#define HTIF_DATA_BITS 48
#define HTIF_DATA_MASK ((1ULL << HTIF_DATA_BITS) - 1)
#define HTIF_DATA_SHIFT 0
#define HTIF_CMD_BITS 8
#define HTIF_CMD_MASK ((1ULL << HTIF_CMD_BITS) - 1)
#define HTIF_CMD_SHIFT 48
#define HTIF_DEV_BITS 8
#define HTIF_DEV_MASK ((1ULL << HTIF_DEV_BITS) - 1)
#define HTIF_DEV_SHIFT 56
#define HTIF_DEV_SYSTEM 0
#define HTIF_DEV_CONSOLE 1
#define HTIF_CONSOLE_CMD_GETC 0
#define HTIF_CONSOLE_CMD_PUTC 1
#if __riscv_xlen == 64
# define TOHOST_CMD(dev, cmd, payload) \
(((uint64_t)(dev) << HTIF_DEV_SHIFT) | \
((uint64_t)(cmd) << HTIF_CMD_SHIFT) | \
(uint64_t)(payload))
#else
# define TOHOST_CMD(dev, cmd, payload) ({ \
if ((dev) || (cmd)) __builtin_trap(); \
(payload); })
#endif
#define FROMHOST_DEV(fromhost_value) \
((uint64_t)((fromhost_value) >> HTIF_DEV_SHIFT) & HTIF_DEV_MASK)
#define FROMHOST_CMD(fromhost_value) \
((uint64_t)((fromhost_value) >> HTIF_CMD_SHIFT) & HTIF_CMD_MASK)
#define FROMHOST_DATA(fromhost_value) \
((uint64_t)((fromhost_value) >> HTIF_DATA_SHIFT) & HTIF_DATA_MASK)
#define PK_SYS_write 64
volatile uint64_t tohost __attribute__((section(".htif")));
volatile uint64_t fromhost __attribute__((section(".htif")));
static int htif_console_buf;
static spinlock_t htif_lock = SPIN_LOCK_INITIALIZER;
static void __check_fromhost()
{
uint64_t fh = fromhost;
if (!fh)
return;
fromhost = 0;
/* this should be from the console */
if (FROMHOST_DEV(fh) != HTIF_DEV_CONSOLE)
__builtin_trap();
switch (FROMHOST_CMD(fh)) {
case HTIF_CONSOLE_CMD_GETC:
htif_console_buf = 1 + (uint8_t)FROMHOST_DATA(fh);
break;
case HTIF_CONSOLE_CMD_PUTC:
break;
default:
__builtin_trap();
}
}
static void __set_tohost(uint64_t dev, uint64_t cmd, uint64_t data)
{
while (tohost)
__check_fromhost();
tohost = TOHOST_CMD(dev, cmd, data);
}
#if __riscv_xlen == 32
static void do_tohost_fromhost(uint64_t dev, uint64_t cmd, uint64_t data)
{
spin_lock(&htif_lock);
__set_tohost(HTIF_DEV_SYSTEM, cmd, data);
while (1) {
uint64_t fh = fromhost;
if (fh) {
if (FROMHOST_DEV(fh) == HTIF_DEV_SYSTEM &&
FROMHOST_CMD(fh) == cmd) {
fromhost = 0;
break;
}
__check_fromhost();
}
}
spin_unlock(&htif_lock);
}
void htif_putc(char ch)
{
/* HTIF devices are not supported on RV32, so do a proxy write call */
volatile uint64_t magic_mem[8];
magic_mem[0] = PK_SYS_write;
magic_mem[1] = HTIF_DEV_CONSOLE;
magic_mem[2] = (uint64_t)(uintptr_t)&ch;
magic_mem[3] = HTIF_CONSOLE_CMD_PUTC;
do_tohost_fromhost(HTIF_DEV_SYSTEM, 0, (uint64_t)(uintptr_t)magic_mem);
}
#else
void htif_putc(char ch)
{
spin_lock(&htif_lock);
__set_tohost(HTIF_DEV_CONSOLE, HTIF_CONSOLE_CMD_PUTC, ch);
spin_unlock(&htif_lock);
}
#endif
int htif_getc(void)
{
int ch;
#if __riscv_xlen == 32
/* HTIF devices are not supported on RV32 */
return -1;
#endif
spin_lock(&htif_lock);
__check_fromhost();
ch = htif_console_buf;
if (ch >= 0) {
htif_console_buf = -1;
__set_tohost(HTIF_DEV_CONSOLE, HTIF_CONSOLE_CMD_GETC, 0);
}
spin_unlock(&htif_lock);
return ch - 1;
}
int htif_system_down(u32 type)
{
while (1) {
fromhost = 0;
tohost = 1;
}
}

View File

@@ -8,3 +8,4 @@
#
libsbiutils-objs-y += sys/clint.o
libsbiutils-objs-y += sys/htif.o

View File

@@ -9,11 +9,6 @@
PLATFORM_RISCV_XLEN = 64
# Common drivers to enable
PLATFORM_SERIAL_UART8250=y
PLATFORM_IRQCHIP_PLIC=y
PLATFORM_SYS_CLINT=y
# Blobs to build
FW_TEXT_START=0x80000000
FW_JUMP=n

View File

@@ -145,7 +145,7 @@ static int ariane_timer_init(bool cold_boot)
if (cold_boot) {
ret = clint_cold_timer_init(ARIANE_CLINT_ADDR,
ARIANE_HART_COUNT);
ARIANE_HART_COUNT, TRUE);
if (ret)
return ret;
}

View File

@@ -88,7 +88,7 @@ static int k210_timer_init(bool cold_boot)
if (cold_boot) {
rc = clint_cold_timer_init(K210_CLINT_BASE_ADDR,
K210_HART_COUNT);
K210_HART_COUNT, TRUE);
if (rc)
return rc;
}

View File

@@ -1,10 +0,0 @@
#
# SPDX-License-Identifier: BSD-2-Clause
#
# Copyright (c) 2019 Western Digital Corporation or its affiliates.
#
# Authors:
# Anup Patel <anup.patel@wdc.com>
#
platform-objs-y += platform.o

View File

@@ -1,158 +0,0 @@
/*
* SPDX-License-Identifier: BSD-2-Clause
*
* Copyright (c) 2019 Western Digital Corporation or its affiliates.
*
* Authors:
* Anup Patel <anup.patel@wdc.com>
*/
#include <sbi/riscv_encoding.h>
#include <sbi/sbi_const.h>
#include <sbi/sbi_hart.h>
#include <sbi/sbi_platform.h>
#include <sbi_utils/irqchip/plic.h>
#include <sbi_utils/serial/sifive-uart.h>
#include <sbi_utils/sys/clint.h>
/* clang-format off */
#define SIFIVE_U_HART_COUNT 4
#define SIFIVE_U_HART_STACK_SIZE 8192
#define SIFIVE_U_SYS_CLK 1000000000
#define SIFIVE_U_PERIPH_CLK (SIFIVE_U_SYS_CLK / 2)
#define SIFIVE_U_CLINT_ADDR 0x2000000
#define SIFIVE_U_PLIC_ADDR 0xc000000
#define SIFIVE_U_PLIC_NUM_SOURCES 0x35
#define SIFIVE_U_PLIC_NUM_PRIORITIES 7
#define SIFIVE_U_UART0_ADDR 0x10013000
#define SIFIVE_U_UART1_ADDR 0x10023000
/* clang-format on */
static int sifive_u_final_init(bool cold_boot)
{
void *fdt;
if (!cold_boot)
return 0;
fdt = sbi_scratch_thishart_arg1_ptr();
plic_fdt_fixup(fdt, "riscv,plic0");
return 0;
}
static u32 sifive_u_pmp_region_count(u32 hartid)
{
return 1;
}
static int sifive_u_pmp_region_info(u32 hartid, u32 index, ulong *prot,
ulong *addr, ulong *log2size)
{
int ret = 0;
switch (index) {
case 0:
*prot = PMP_R | PMP_W | PMP_X;
*addr = 0;
*log2size = __riscv_xlen;
break;
default:
ret = -1;
break;
};
return ret;
}
static int sifive_u_console_init(void)
{
return sifive_uart_init(SIFIVE_U_UART0_ADDR, SIFIVE_U_PERIPH_CLK,
115200);
}
static int sifive_u_irqchip_init(bool cold_boot)
{
int rc;
u32 hartid = sbi_current_hartid();
if (cold_boot) {
rc = plic_cold_irqchip_init(SIFIVE_U_PLIC_ADDR,
SIFIVE_U_PLIC_NUM_SOURCES,
SIFIVE_U_HART_COUNT);
if (rc)
return rc;
}
return plic_warm_irqchip_init(hartid, (2 * hartid), (2 * hartid + 1));
}
static int sifive_u_ipi_init(bool cold_boot)
{
int rc;
if (cold_boot) {
rc = clint_cold_ipi_init(SIFIVE_U_CLINT_ADDR,
SIFIVE_U_HART_COUNT);
if (rc)
return rc;
}
return clint_warm_ipi_init();
}
static int sifive_u_timer_init(bool cold_boot)
{
int rc;
if (cold_boot) {
rc = clint_cold_timer_init(SIFIVE_U_CLINT_ADDR,
SIFIVE_U_HART_COUNT);
if (rc)
return rc;
}
return clint_warm_timer_init();
}
static int sifive_u_system_down(u32 type)
{
/* For now nothing to do. */
return 0;
}
const struct sbi_platform_operations platform_ops = {
.pmp_region_count = sifive_u_pmp_region_count,
.pmp_region_info = sifive_u_pmp_region_info,
.final_init = sifive_u_final_init,
.console_putc = sifive_uart_putc,
.console_getc = sifive_uart_getc,
.console_init = sifive_u_console_init,
.irqchip_init = sifive_u_irqchip_init,
.ipi_send = clint_ipi_send,
.ipi_clear = clint_ipi_clear,
.ipi_init = sifive_u_ipi_init,
.timer_value = clint_timer_value,
.timer_event_stop = clint_timer_event_stop,
.timer_event_start = clint_timer_event_start,
.timer_init = sifive_u_timer_init,
.system_reboot = sifive_u_system_down,
.system_shutdown = sifive_u_system_down
};
const struct sbi_platform platform = {
.opensbi_version = OPENSBI_VERSION,
.platform_version = SBI_PLATFORM_VERSION(0x0, 0x01),
.name = "QEMU SiFive Unleashed",
.features = SBI_PLATFORM_DEFAULT_FEATURES,
.hart_count = SIFIVE_U_HART_COUNT,
.hart_stack_size = SIFIVE_U_HART_STACK_SIZE,
.disabled_hart_mask = 0,
.platform_ops_addr = (unsigned long)&platform_ops
};

View File

@@ -17,29 +17,24 @@ platform-ldflags-y =
platform-runcmd = qemu-system-riscv$(PLATFORM_RISCV_XLEN) -M virt -m 256M \
-nographic -kernel $(build_dir)/platform/qemu/virt/firmware/fw_payload.elf
# Common drivers to enable
PLATFORM_IRQCHIP_PLIC=y
PLATFORM_SERIAL_UART8250=y
PLATFORM_SYS_CLINT=y
# Blobs to build
FW_TEXT_START=0x80000000
FW_DYNAMIC=y
FW_JUMP=y
ifeq ($(PLATFORM_RISCV_XLEN), 32)
# This needs to be 4MB alligned for 32-bit system
# This needs to be 4MB aligned for 32-bit system
FW_JUMP_ADDR=0x80400000
else
# This needs to be 2MB alligned for 64-bit system
# This needs to be 2MB aligned for 64-bit system
FW_JUMP_ADDR=0x80200000
endif
FW_JUMP_FDT_ADDR=0x82200000
FW_PAYLOAD=y
ifeq ($(PLATFORM_RISCV_XLEN), 32)
# This needs to be 4MB alligned for 32-bit system
# This needs to be 4MB aligned for 32-bit system
FW_PAYLOAD_OFFSET=0x400000
else
# This needs to be 2MB alligned for 64-bit system
# This needs to be 2MB aligned for 64-bit system
FW_PAYLOAD_OFFSET=0x200000
endif
FW_PAYLOAD_FDT_ADDR=0x82200000

View File

@@ -114,7 +114,8 @@ static int virt_timer_init(bool cold_boot)
int rc;
if (cold_boot) {
rc = clint_cold_timer_init(VIRT_CLINT_ADDR, VIRT_HART_COUNT);
rc = clint_cold_timer_init(VIRT_CLINT_ADDR,
VIRT_HART_COUNT, TRUE);
if (rc)
return rc;
}

View File

@@ -13,12 +13,28 @@ platform-cflags-y =
platform-asflags-y =
platform-ldflags-y =
# Command for platform specific "make run"
platform-runcmd = qemu-system-riscv$(PLATFORM_RISCV_XLEN) -M sifive_u -m 256M \
-nographic -kernel $(build_dir)/platform/sifive/fu540/firmware/fw_payload.elf
# Blobs to build
FW_TEXT_START=0x80000000
FW_DYNAMIC=y
FW_JUMP=y
FW_JUMP_ADDR=0x80200000
ifeq ($(PLATFORM_RISCV_XLEN), 32)
# This needs to be 4MB aligned for 32-bit system
FW_JUMP_ADDR=0x80400000
else
# This needs to be 2MB aligned for 64-bit system
FW_JUMP_ADDR=0x80200000
endif
FW_JUMP_FDT_ADDR=0x88000000
FW_PAYLOAD=y
FW_PAYLOAD_OFFSET=0x200000
ifeq ($(PLATFORM_RISCV_XLEN), 32)
# This needs to be 4MB aligned for 32-bit system
FW_PAYLOAD_OFFSET=0x400000
else
# This needs to be 2MB aligned for 64-bit system
FW_PAYLOAD_OFFSET=0x200000
endif
FW_PAYLOAD_FDT_ADDR=0x88000000

View File

@@ -52,6 +52,9 @@
#define FU540_PRCI_CLKMUXSTATUSREG 0x002C
#define FU540_PRCI_CLKMUX_STATUS_TLCLKSEL (0x1 << 1)
/* Full tlb flush always */
#define FU540_TLB_RANGE_FLUSH_LIMIT 0
/* clang-format on */
static void fu540_modify_dt(void *fdt)
@@ -171,12 +174,18 @@ static int fu540_ipi_init(bool cold_boot)
return clint_warm_ipi_init();
}
static u64 fu540_get_tlbr_flush_limit(void)
{
return FU540_TLB_RANGE_FLUSH_LIMIT;
}
static int fu540_timer_init(bool cold_boot)
{
int rc;
if (cold_boot) {
rc = clint_cold_timer_init(FU540_CLINT_ADDR, FU540_HART_COUNT);
rc = clint_cold_timer_init(FU540_CLINT_ADDR,
FU540_HART_COUNT, TRUE);
if (rc)
return rc;
}
@@ -201,6 +210,7 @@ const struct sbi_platform_operations platform_ops = {
.ipi_send = clint_ipi_send,
.ipi_clear = clint_ipi_clear,
.ipi_init = fu540_ipi_init,
.get_tlbr_flush_limit = fu540_get_tlbr_flush_limit,
.timer_value = clint_timer_value,
.timer_event_stop = clint_timer_event_stop,
.timer_event_start = clint_timer_event_start,

View File

@@ -1,10 +1,7 @@
#
# SPDX-License-Identifier: BSD-2-Clause
#
# Copyright (c) 2019 Western Digital Corporation or its affiliates.
#
# Authors:
# Anup Patel <anup.patel@wdc.com>
# Copyright (c) 2020 Western Digital Corporation or its affiliates.
#
# Compiler flags
@@ -14,27 +11,26 @@ platform-asflags-y =
platform-ldflags-y =
# Command for platform specific "make run"
platform-runcmd = qemu-system-riscv$(PLATFORM_RISCV_XLEN) -M sifive_u -m 256M \
-nographic -kernel $(build_dir)/platform/qemu/sifive_u/firmware/fw_payload.elf
platform-runcmd = spike \
$(build_dir)/platform/spike/firmware/fw_payload.elf
# Blobs to build
FW_TEXT_START=0x80000000
FW_DYNAMIC=y
FW_JUMP=y
ifeq ($(PLATFORM_RISCV_XLEN), 32)
# This needs to be 4MB alligned for 32-bit system
# This needs to be 4MB aligned for 32-bit system
FW_JUMP_ADDR=0x80400000
else
# This needs to be 2MB alligned for 64-bit system
# This needs to be 2MB aligned for 64-bit system
FW_JUMP_ADDR=0x80200000
endif
FW_JUMP_FDT_ADDR=0x82200000
FW_PAYLOAD=y
ifeq ($(PLATFORM_RISCV_XLEN), 32)
# This needs to be 4MB alligned for 32-bit system
# This needs to be 4MB aligned for 32-bit system
FW_PAYLOAD_OFFSET=0x400000
else
# This needs to be 2MB alligned for 64-bit system
# This needs to be 2MB aligned for 64-bit system
FW_PAYLOAD_OFFSET=0x200000
endif
FW_PAYLOAD_FDT_ADDR=0x82200000

View File

@@ -0,0 +1,7 @@
#
# SPDX-License-Identifier: BSD-2-Clause
#
# Copyright (c) 2020 Western Digital Corporation or its affiliates.
#
platform-objs-y += platform.o

115
platform/spike/platform.c Normal file
View File

@@ -0,0 +1,115 @@
/*
* SPDX-License-Identifier: BSD-2-Clause
*
* Copyright (c) 2020 Western Digital Corporation or its affiliates.
*/
#include <sbi/sbi_platform.h>
#include <sbi_utils/sys/htif.h>
#include <sbi_utils/sys/clint.h>
/* clang-format off */
#define SPIKE_HART_COUNT 8
#define SPIKE_HART_STACK_SIZE 8192
#define SPIKE_CLINT_ADDR 0x2000000
/* clang-format on */
static int spike_final_init(bool cold_boot)
{
return 0;
}
static u32 spike_pmp_region_count(u32 hartid)
{
return 1;
}
static int spike_pmp_region_info(u32 hartid, u32 index, ulong *prot, ulong *addr,
ulong *log2size)
{
int ret = 0;
switch (index) {
case 0:
*prot = PMP_R | PMP_W | PMP_X;
*addr = 0;
*log2size = __riscv_xlen;
break;
default:
ret = -1;
break;
};
return ret;
}
static int spike_console_init(void)
{
return 0;
}
static int spike_irqchip_init(bool cold_boot)
{
return 0;
}
static int spike_ipi_init(bool cold_boot)
{
int ret;
if (cold_boot) {
ret = clint_cold_ipi_init(SPIKE_CLINT_ADDR,
SPIKE_HART_COUNT);
if (ret)
return ret;
}
return clint_warm_ipi_init();
}
static int spike_timer_init(bool cold_boot)
{
int rc;
if (cold_boot) {
rc = clint_cold_timer_init(SPIKE_CLINT_ADDR,
SPIKE_HART_COUNT, TRUE);
if (rc)
return rc;
}
return clint_warm_timer_init();
}
const struct sbi_platform_operations platform_ops = {
.pmp_region_count = spike_pmp_region_count,
.pmp_region_info = spike_pmp_region_info,
.final_init = spike_final_init,
.console_putc = htif_putc,
.console_getc = htif_getc,
.console_init = spike_console_init,
.irqchip_init = spike_irqchip_init,
.ipi_send = clint_ipi_send,
.ipi_clear = clint_ipi_clear,
.ipi_init = spike_ipi_init,
.timer_value = clint_timer_value,
.timer_event_stop = clint_timer_event_stop,
.timer_event_start = clint_timer_event_start,
.timer_init = spike_timer_init,
.system_reboot = htif_system_down,
.system_shutdown = htif_system_down
};
const struct sbi_platform platform = {
.opensbi_version = OPENSBI_VERSION,
.platform_version = SBI_PLATFORM_VERSION(0x0, 0x01),
.name = "Spike",
.features = SBI_PLATFORM_DEFAULT_FEATURES,
.hart_count = SPIKE_HART_COUNT,
.hart_stack_size = SPIKE_HART_STACK_SIZE,
.disabled_hart_mask = 0,
.platform_ops_addr = (unsigned long)&platform_ops
};

View File

@@ -143,7 +143,7 @@ static int platform_timer_init(bool cold_boot)
/* Example if the generic CLINT driver is used */
if (cold_boot) {
ret = clint_cold_timer_init(PLATFORM_CLINT_ADDR,
PLATFORM_HART_COUNT);
PLATFORM_HART_COUNT, TRUE);
if (ret)
return ret;
}
@@ -213,8 +213,8 @@ const struct sbi_platform_operations platform_ops = {
.timer_event_stop = platform_timer_event_stop,
.timer_event_start = platform_timer_event_start,
.timer_init = platform_timer_init,
.system_reboot = platform_system_down,
.system_shutdown = platform_system_down
.system_reboot = platform_system_reboot,
.system_shutdown = platform_system_shutdown
};
const struct sbi_platform platform = {
.opensbi_version = OPENSBI_VERSION,
@@ -224,6 +224,5 @@ const struct sbi_platform platform = {
.hart_count = 1,
.hart_stack_size = 4096,
.disabled_hart_mask = 0,
.tlb_range_flush_limit = 0,
.platform_ops_addr = (unsigned long)&platform_ops
};

View File

@@ -0,0 +1,14 @@
#
# SPDX-License-Identifier: BSD-2-Clause
#
# Compiler flags
platform-cppflags-y =
platform-cflags-y =
platform-asflags-y =
platform-ldflags-y =
# Blobs to build
FW_TEXT_START?=0x0
FW_JUMP=y
FW_JUMP_ADDR?=0x00200000

View File

@@ -0,0 +1,5 @@
#
# SPDX-License-Identifier: BSD-2-Clause
#
platform-objs-y += platform.o

View File

@@ -0,0 +1,158 @@
/*
* SPDX-License-Identifier: BSD-2-Clause
*/
#include <sbi/riscv_encoding.h>
#include <sbi/riscv_io.h>
#include <sbi/sbi_const.h>
#include <sbi/sbi_hart.h>
#include <sbi/sbi_platform.h>
#include <sbi/sbi_console.h>
#include <sbi_utils/irqchip/plic.h>
#include <sbi_utils/sys/clint.h>
#include <sbi_utils/serial/uart8250.h>
#include "platform.h"
static struct c910_regs_struct c910_regs;
static int c910_early_init(bool cold_boot)
{
if (cold_boot) {
/* Load from boot core */
c910_regs.pmpaddr0 = csr_read(CSR_PMPADDR0);
c910_regs.pmpaddr1 = csr_read(CSR_PMPADDR1);
c910_regs.pmpaddr2 = csr_read(CSR_PMPADDR2);
c910_regs.pmpaddr3 = csr_read(CSR_PMPADDR3);
c910_regs.pmpaddr4 = csr_read(CSR_PMPADDR4);
c910_regs.pmpaddr5 = csr_read(CSR_PMPADDR5);
c910_regs.pmpaddr6 = csr_read(CSR_PMPADDR6);
c910_regs.pmpaddr7 = csr_read(CSR_PMPADDR7);
c910_regs.pmpcfg0 = csr_read(CSR_PMPCFG0);
c910_regs.mcor = csr_read(CSR_MCOR);
c910_regs.mhcr = csr_read(CSR_MHCR);
c910_regs.mccr2 = csr_read(CSR_MCCR2);
c910_regs.mhint = csr_read(CSR_MHINT);
c910_regs.mxstatus = csr_read(CSR_MXSTATUS);
c910_regs.plic_base_addr = csr_read(CSR_PLIC_BASE);
c910_regs.clint_base_addr =
c910_regs.plic_base_addr + C910_PLIC_CLINT_OFFSET;
} else {
/* Store to other core */
csr_write(CSR_PMPADDR0, c910_regs.pmpaddr0);
csr_write(CSR_PMPADDR1, c910_regs.pmpaddr1);
csr_write(CSR_PMPADDR2, c910_regs.pmpaddr2);
csr_write(CSR_PMPADDR3, c910_regs.pmpaddr3);
csr_write(CSR_PMPADDR4, c910_regs.pmpaddr4);
csr_write(CSR_PMPADDR5, c910_regs.pmpaddr5);
csr_write(CSR_PMPADDR6, c910_regs.pmpaddr6);
csr_write(CSR_PMPADDR7, c910_regs.pmpaddr7);
csr_write(CSR_PMPCFG0, c910_regs.pmpcfg0);
csr_write(CSR_MCOR, c910_regs.mcor);
csr_write(CSR_MHCR, c910_regs.mhcr);
csr_write(CSR_MHINT, c910_regs.mhint);
csr_write(CSR_MXSTATUS, c910_regs.mxstatus);
}
return 0;
}
static int c910_final_init(bool cold_boot)
{
return 0;
}
static int c910_irqchip_init(bool cold_boot)
{
/* Delegate plic enable into S-mode */
writel(C910_PLIC_DELEG_ENABLE,
(void *)c910_regs.plic_base_addr + C910_PLIC_DELEG_OFFSET);
return 0;
}
static int c910_ipi_init(bool cold_boot)
{
int rc;
if (cold_boot) {
rc = clint_cold_ipi_init(c910_regs.clint_base_addr, C910_HART_COUNT);
if (rc)
return rc;
}
return clint_warm_ipi_init();
}
static int c910_timer_init(bool cold_boot)
{
int ret;
if (cold_boot) {
ret = clint_cold_timer_init(c910_regs.clint_base_addr,
C910_HART_COUNT, FALSE);
if (ret)
return ret;
}
return clint_warm_timer_init();
}
static int c910_system_shutdown(u32 type)
{
asm volatile ("ebreak");
return 0;
}
void sbi_boot_other_core(int hartid)
{
csr_write(CSR_MRVBR, FW_TEXT_START);
csr_write(CSR_MRMR, csr_read(CSR_MRMR) | (1 << hartid));
}
static int c910_vendor_ext_provider(long extid, long funcid,
unsigned long *args,
unsigned long *out_value,
struct sbi_trap_info *out_trap)
{
switch (extid) {
case SBI_EXT_VENDOR_C910_BOOT_OTHER_CORE:
sbi_boot_other_core((int)args[0]);
break;
default:
sbi_printf("Unsupported private sbi call: %ld\n", extid);
asm volatile ("ebreak");
}
return 0;
}
const struct sbi_platform_operations platform_ops = {
.early_init = c910_early_init,
.final_init = c910_final_init,
.irqchip_init = c910_irqchip_init,
.ipi_init = c910_ipi_init,
.ipi_send = clint_ipi_send,
.ipi_clear = clint_ipi_clear,
.timer_init = c910_timer_init,
.timer_event_start = clint_timer_event_start,
.system_shutdown = c910_system_shutdown,
.vendor_ext_provider = c910_vendor_ext_provider,
};
const struct sbi_platform platform = {
.opensbi_version = OPENSBI_VERSION,
.platform_version = SBI_PLATFORM_VERSION(0x0, 0x01),
.name = "T-HEAD Xuantie c910",
.features = SBI_THEAD_FEATURES,
.hart_count = C910_HART_COUNT,
.hart_stack_size = C910_HART_STACK_SIZE,
.disabled_hart_mask = 0,
.platform_ops_addr = (unsigned long)&platform_ops
};

View File

@@ -0,0 +1,50 @@
/*
* SPDX-License-Identifier: BSD-2-Clause
*/
#ifndef _C910_PLATFORM_H_
#define _C910_PLATFORM_H_
#define C910_HART_COUNT 16
#define C910_HART_STACK_SIZE 8192
#define SBI_THEAD_FEATURES \
(SBI_PLATFORM_HAS_SCOUNTEREN | \
SBI_PLATFORM_HAS_MCOUNTEREN | \
SBI_PLATFORM_HAS_MFAULTS_DELEGATION)
#define CSR_MCOR 0x7c2
#define CSR_MHCR 0x7c1
#define CSR_MCCR2 0x7c3
#define CSR_MHINT 0x7c5
#define CSR_MXSTATUS 0x7c0
#define CSR_PLIC_BASE 0xfc1
#define CSR_MRMR 0x7c6
#define CSR_MRVBR 0x7c7
#define SBI_EXT_VENDOR_C910_BOOT_OTHER_CORE 0x09000003
#define C910_PLIC_CLINT_OFFSET 0x04000000 /* 64M */
#define C910_PLIC_DELEG_OFFSET 0x001ffffc
#define C910_PLIC_DELEG_ENABLE 0x1
struct c910_regs_struct {
u64 pmpaddr0;
u64 pmpaddr1;
u64 pmpaddr2;
u64 pmpaddr3;
u64 pmpaddr4;
u64 pmpaddr5;
u64 pmpaddr6;
u64 pmpaddr7;
u64 pmpcfg0;
u64 mcor;
u64 mhcr;
u64 mccr2;
u64 mhint;
u64 mxstatus;
u64 plic_base_addr;
u64 clint_base_addr;
};
#endif /* _C910_PLATFORM_H_ */

View File

@@ -85,16 +85,16 @@ case "${BUILD_RISCV_XLEN}" in
32)
# Setup 32-bit platform list
BUILD_PLATFORM_SUBDIR=("qemu/virt")
BUILD_PLATFORM_SUBDIR+=("qemu/sifive_u")
;;
64)
# Setup 64-bit platform list
BUILD_PLATFORM_SUBDIR=("qemu/virt")
BUILD_PLATFORM_SUBDIR+=("qemu/sifive_u")
BUILD_PLATFORM_SUBDIR+=("sifive/fu540")
BUILD_PLATFORM_SUBDIR+=("kendryte/k210")
BUILD_PLATFORM_SUBDIR+=("ariane-fpga")
BUILD_PLATFORM_SUBDIR+=("andes/ae350")
BUILD_PLATFORM_SUBDIR+=("thead/c910")
BUILD_PLATFORM_SUBDIR+=("spike")
;;
*)
echo "Invalid RISC-V XLEN"