243 Commits
v0.3 ... 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
Anup Patel
be92da280d include: Bump-up version to 0.5
This patch updates OpenSBI version to 0.5 as part of
release preparation.

Signed-off-by: Anup Patel <anup.patel@wdc.com>
2019-10-09 11:33:53 +05:30
Atish Patra
30f09fbfd1 lib: Provide a platform hook to implement vendor specific SBI extensions.
SBI v0.2 specification allows vendor extensions and it should be
implemented in a independent of the core sbi library.

Introduce a single platform callback that will let platforms handle
all vendor extensions in platform specific code if they want.

Signed-off-by: Atish Patra <atish.patra@wdc.com>
Reviewed-by: Anup Patel <anup.patel@wdc.com>
2019-10-03 08:58:51 +05:30
Atish Patra
0790be0f2c lib: Implement SBI v0.2
SBI v0.2 introduces a base specification which is mandatory to
implement for any SBI implementations that is not legacy.

Add support for the base extension.

Signed-off-by: Atish Patra <atish.patra@wdc.com>
Reviewed-by: Anup Patel <anup.patel@wdc.com>
2019-10-03 08:56:55 +05:30
Atish Patra
848ed4f644 lib: Remove redundant variable assignment
An ecall handler should only return error if valid SBI function
fails. Otherwise, it should succeed with appropriate error in a0.

Get rid of unnecessary setting of the temporary return variable to
zero for the cases where errors are not expected.

Signed-off-by: Atish Patra <atish.patra@wdc.com>
Reviewed-by: Anup Patel <anup.patel@wdc.com>
2019-10-03 08:55:25 +05:30
Atish Patra
26aec6afed lib: Rename existing SBI implementation as 0.1.
Current SBI implementation is now considered as version 0.1 and will be
removed/replaced with newer extension/functions in future.

Rename the existing implementations accordingly to be in sync with the
specification.

Signed-off-by: Atish Patra <atish.patra@wdc.com>
Reviewed-by: Anup Patel <anup.patel@wdc.com>
Reviewed-by: Zong Li <zong.li@sifive.com>
2019-10-03 08:53:52 +05:30
Atish Patra
3d335bc54b lib: Align error codes as per SBI specification.
Follow the SBI specification for error codes.

Signed-off-by: Atish Patra <atish.patra@wdc.com>
Reviewed-by: Anup Patel <anup.patel@wdc.com>
2019-10-03 08:52:54 +05:30
Atish Patra
8925e3865c Test: Move test payload related code out of interface header
Test payload uses an SBI call and uses the macros defined in interface
header which is not the correct place to have these definitions.
The interface header file should be used to keep SBI specification
related macros.

Keep all the test payload related code in test itself.

Signed-off-by: Atish Patra <atish.patra@wdc.com>
Reviewed-by: Anup Patel <anup.patel@wdc.com>
2019-10-03 08:51:39 +05:30
Anup Patel
e561c63036 lib: Fix coldboot race condition observed on emulators/simulators
If we are running on RISC-V emulator/simulator with large number of
HARTs where each HART is a regular thread under UNIX host then it is
possible that some of the secondary HARTs don't get chance to run and
sbi_hart_wake_coldboot_harts() is called before secondary HARTs call
sbi_hart_wait_for_coldboot(). In this situation, some of the secondary
HARTs will never come-out of coldboot wait loop.

To tackle this, we introduce a global flag coldboot_done which will
be protected by coldboot lock and it will be set by primary HART from
sbi_hart_wake_coldboot_harts() before waking-up secondary HARTs. We
also re-arrange acquire/release of coldboot lock to reduce further
chances of race-condition.

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>
Reviewed-by: Nylon Chen<nylon7@andestech.com>
2019-10-02 17:03:58 +05:30
Anup Patel
2c7bab76a2 Makefile: Minor fix in OPENSBI_VERSION_GIT
Currently, if someone has forked OpenSBI repo quite sometime back
and this fork is not having updated tags from upstream riscv/opensbi
repo then "git describe" command can fail. To tackle this, we redirect
error output of "git describe" to /dev/null.

Signed-off-by: Anup Patel <anup.pate@wdc.com>
Reviewed-by: Bin Meng <bmeng.cn@gmail.com>
2019-10-02 17:03:54 +05:30
Anup Patel
1e9f88889f lib: Emulate HTIMEDELTA CSR for platforms not having TIME CSR
For platforms not having TIME CSR, we trap-n-emulate TIME CSR
read/write in OpenSBI. Same rationale applies to HTIMEDELTA CSR
as well so we trap-n-emulate HTIMEDELTA CSR for platforms not
having TIME CSR.

Signed-off-by: Anup Patel <anup.patel@wdc.com>
2019-09-30 15:36:14 +05:30
Anup Patel
7d4420bd69 include: Extend get_insn() to read instruction from VS/VU mode
Current implementation of get_insn() is not suitable for reading
instruction from VS/VU mode because we have to set SSTATUS_MXR bit
in VSSTATUS CSR for reading instruction from VS/VU mode.

This patch extends get_insn() to read instruction from VS/VU mode.

Signed-off-by: Anup Patel <anup.patel@wdc.com>
Signed-off-by: Alistair Francis <alistair.francis@wdc.com>
2019-09-30 15:35:43 +05:30
Anup Patel
a14e7ee82c lib: Redirect WFI trapped from VS/VU mode to HS-mode
The WFI will trap as illegal instruction trap when executed
in VS/VU mode so we just forward/redirect it to HS-mode so
that hypervisor can deal with it appropriately.

Signed-off-by: Anup Patel <anup.patel@wdc.com>
2019-09-30 15:32:00 +05:30
Anup Patel
bbeb8e619d lib: Extend sbi_trap_redirect() for hypervisor extension
When hypervisor extension is available, we can get traps from VS/VU
modes. We should be able to force redirect some of these traps to
HS-mode. In other words, we should be able forward traps from VS/VU
mode to HS-mode using sbi_trap_redirect() hence this patch.

Signed-off-by: Atish Patra <atish.patra@wdc.com>
Signed-off-by: Anup Patel <anup.patel@wdc.com>
Signed-off-by: Alistair Francis <alistair.francis@wdc.com>
2019-09-30 15:29:37 +05:30
Anup Patel
1a5614e971 lib: Extend sbi_hart_switch_mode() to support hypervisor extension
This patch extends sbi_hart_switch_mode() to support entering
VS/VU modes when hypervisor extension is available.

Signed-off-by: Anup Patel <anup.patel@wdc.com>
2019-09-30 15:18:06 +05:30
Anup Patel
0089897d41 lib: Delegate supervisor ecall to HS-mode when H extension available
When hypervisor extension is available, we only handle hypervisor
ecalls coming from HS-mode and we let hypervisor handle ecalls coming
from VS-mode.

Signed-off-by: Anup Patel <anup.patel@wdc.com>
2019-09-30 15:14:00 +05:30
Zong Li
1ed9eb255d Write MSIP by using memory-mapped control register
The machine-level MSIP bits are written by accesses to memory-mapped
control registers. Only use CSR instruction for SSIP and USIP.

There is no effect that using CSR instruction to write MSIP when testing
on unleashed board and QEMU.

Signed-off-by: Zong Li <zong.li@sifive.com>
Reviewed-by: Anup Patel <anup.patel@wdc.com>
2019-09-28 18:23:13 +05:30
Atish Patra
0a482e2edb lib: Fix tlb flush range limit value
Use platform defined flush range limit value only if it is non-zero.
Otherwise, use the default value.

Signed-off-by: Atish Patra <atish.patra@wdc.com>
Reviewed-by: Bin Meng <bmeng.cn@gmail.com>
2019-09-28 18:21:34 +05:30
Damien Le Moal
190e3f4bd9 kendryte/k210: remove unused file
Commit 9dfe720579 ("kendryte/k210: remove sysctl code") missed
removing the file sysctl.c. Fix this here.

Fixes: 9dfe720579 ("kendryte/k210: remove sysctl code")
Signed-off-by: Damien Le Moal <damien.lemoal@wdc.com>
Reviewed-by: Atish Patra <atish.patra@wdc.com>
2019-09-28 18:15:18 +05:30
Bin Meng
8853758268 docs: platform: Update descriptions for qemu/sifive_u support
With QEMU v4.2 release that has improved the emulation fidelity
of 'sifive_u' machine, OpenSBI v0.4 / U-Boot v2019.10-rc1 / Linux
kernel v5.3-rc2 images built for the SiFive HiFive Unleashed board
can be used out of the box without any special hack.

Update our documents to mention 'qemu/sifive_u' platform should
only be used with QEMU v4.1 or before, and it will be dropped
sometime in the future release.

Going forward, 'sifive/fu540' platform can be used on both real
hardware and QEMU v4.2+ 'sifive_u' machine.

Signed-off-by: Bin Meng <bmeng.cn@gmail.com>
Reviewed-by: Anup Patel <anup.patel@wdc.com>
2019-09-25 10:34:54 +05:30
Atish Patra
98ee15ca3a lib: provide a platform specific tlb range flush threshold
Currently, the tlb range flush threshold is fixed and set to 4k for
all platforms. However, it should be platform specific as it completely
depends upon how platform actually implements sfence instruction.

Define a platform feature that allows every individual platform to set
different values. If a platform doesn't define it, just use a page size as
the threshold.

Signed-off-by: Atish Patra <atish.patra@wdc.com>
Reviewed-by: Bin Meng <bmeng.cn@gmail.com>
Reviewed-by: Anup Patel <anup.patel@wdc.com>
2019-09-10 17:44:10 +05:30
Atish Patra
f2e82c3d79 lib: Change tlb range flush threshold to 4k page instead of 1G
In RISC-V, tlb flush happens at a page granularity. That's why OpenSBI
also have a tlb range flush limit which decides the which tlb flush
requests should be upgraded to full flush to avoid long delays.
Currently, this is set to 1G which would result in a many sfence.vma
execution in a tight loop for a large range.

Change the threshold to 4k to speed things up.

Signed-off-by: Atish Patra <atish.patra@wdc.com>
Reviewed-by: Bin Meng <bmeng.cn@gmail.com>
Reviewed-by: Anup Patel <anup.patel@wdc.com>
2019-09-10 17:44:07 +05:30
Damien Le Moal
144acef684 README: Update license information
With the Kendryte K210 platform code cleanup, none of the code copied
from Kendryte standalone SDK remains and this platform code is now
entirely licensed under OpenSBI BSD-2-clause license. Update the
README.md and ThirdPartyNotices.md files to reflect this.

Signed-off-by: Damien Le Moal <damien.lemoal@wdc.com>
Reviewed-by: Bin Meng <bmeng.cn@gmail.com>
Reviewed-by: Anup Patel <anup.patel@wdc.com>
2019-09-05 18:52:32 +05:30
Damien Le Moal
9dfe720579 kendryte/k210: remove sysctl code
Directly implement frequency discovery, making the sysctl code
unnecessary. While at it, Move all macro definitions from platform.c
into platform.h and cleanup that file, removing the need for the
Apache 2.0 license and Canaan Inc copyright.

Signed-off-by: Damien Le Moal <damien.lemoal@wdc.com>
Reviewed-by: Bin Meng <bmeng.cn@gmail.com>
Reviewed-by: Anup Patel <anup.patel@wdc.com>
2019-09-05 18:50:37 +05:30
Damien Le Moal
fca8c3be01 kendryte/k210: Use sifive UART driver
The Kendryte K210 UARTHS is compatible with SiFive UART. So use the
sifive uart driver and remove the k210 uarths platform code.

Signed-off-by: Damien Le Moal <damien.lemoal@wdc.com>
Reviewed-by: Bin Meng <bmeng.cn@gmail.com>
Reviewed-by: Anup Patel <anup.patel@wdc.com>
2019-09-05 18:47:56 +05:30
Atish Patra
6ed2bc154f docs: Update the fu540 platform guide as per U-Boot documents.
U-Boot readme for fu540 platform suggest that fdt_addr_r should be used
as DT address after DT is copied via tftpboot.

Update the OpenSBI docs to reflect that. Remove other stale informations
as well.

Signed-off-by: Atish Patra <atish.patra@wdc.com>
Reviewed-by: Anup Patel <anup.patel@wdc.com>
2019-08-31 13:16:44 +05:30
Atish Patra
7b7690ed9c lib: Upgrade to full flush if size is at least threshold
Currently, we upgrade to a full tlb flush only If a tlb flush request
size is greater than the threshold. This is done as sfence in RISC-V
can only flush 4KB at a time. Doing a large number of flushes page by
page impacts the performance. It is better to do a full tlbflush if the
request size is at least equal to the threshold size.

Signed-off-by: Atish Patra <atish.patra@wdc.com>
Reviewed-by: Anup Patel <anup.patel@wdc.com>
2019-08-31 13:15:21 +05:30
Atish Patra
6bd1512024 lib: Support atomic swap instructions
If compiler supports riscv atomic instructions, we should
use them instead of legacy gcc built-in macros
__sync_lock_test_and_set in atomic exchange functions.

Signed-off-by: Atish Patra <atish.patra@wdc.com>
Reviewed-by: Anup Patel <anup.patel@wdc.com>
2019-08-31 13:13:47 +05:30
Atish Patra
2e5cc9051b lib: Fix timer for 32 bit
To read 64bit time in 32 bit we have to read lower & upper half
separately and 'or' them together. However, upper half time may
have changed by the time we read lower half. Thus, the resultant
64 bit time may not be accurate.

Consider lower half time value only if upper half time value has
not changed.

Signed-off-by: Atish Patra <atish.patra@wdc.com>
Reviewed-by: Anup Patel <anup.patel@wdc.com>
2019-08-31 13:13:12 +05:30
Nylon Chen
ffa6c5f457 scripts: Add AE350 to platform list in the binary archive script
This patch adds Andes AE350 to RV64 platform list in the binary
archive script.

Signed-off-by: Nylon Chen <nylon7@andestech.com>
Reviewed-by: Bin Meng <bmeng.cn@gmail.com>
Reviewed-by: Anup Patel <anup.patel@wdc.com>
2019-08-31 13:10:06 +05:30
Nylon Chen
3cbb419def platform: Add Andes AE350 initial support
This commit provides basic support for the AE350 platform.

Signed-off-by: Zong Li <zongbox@gmail.com>
Signed-off-by: Nylon Chen <nylon7@andestech.com>
2019-08-23 16:25:56 +05:30
Palmer Dabbelt
a2a7763ac7 Include git describe in OpenSBI
OpenSBI includes a version, but that is only updated when tagged.  For
users that are using the git releases we instead end up with an
ambiguous version number, which makes it hard to figure out what
everyone is using.  This patch checks for a git directory and prints out
the result of `git describe`, which is a mix of pretty and unambiguous.

Signed-off-by: Palmer Dabbelt <palmer@sifive.com>
Signed-off-by: Anup Patel <anup.patel@wdc.com>
Reviewed-by: Bin Meng <bmeng.cn@gmail.com>
Tested-by: Bin Meng <bmeng.cn@gmail.com>
2019-08-19 10:58:21 +05:30
Atish Patra
75229705a0 platform: Remove the ipi_sync method from all platforms.
OpenSBI manages outstanding TLB flush requests by queueing
them in a fifo synchronously. An ipi sync which uses an
atomic operation on MMIO address is no longer required.

Remove the ipi sync method from platform header and all usage.

Signed-off-by: Atish Patra <atish.patra@wdc.com>
Reviewed-by: Anup Patel <anup.patel@wdc.com>
2019-08-16 08:42:58 +05:30
Atish Patra
897a97a6af lib: Fix race conditions in tlb fifo access.
Linux kernel expects tlb flush SBI call to be completely synchronous i.e.
the SBI call should only return once corresponding *fence* instruction is
executed.

OpenSBI manages the outstanding TLB flush requests by keeping them in a
per hart based fifo. However, there are few corner cases that may lead to
race conditions while updating the fifo.

Currently, the caller hart waits for IPI acknowledgement via clint
address which is not a very good method as synchronization on MMIO may not
be supported in every platform. Moreover, the waiter doesn't have any way of
identifying if the IPI is received for specific tlb flush request or any
other IPI. This may lead to unpredictable behavior in supervisor/user space.

Fix this by waiting on individual fifo entries rather than MMIO address.
Currently, a relaxed loop is being used because wfi again involves MMIO write
which would be slower compared to relaxed loop. To avoid deadlock, fifo
is processed every time a hart loops for fifo enqueue or fifo sync to consume
the tlb flush requests sent by other harts.

Signed-off-by: Anup Patel <anup.patel@wdc.com>
Signed-off-by: Atish Patra <atish.patra@wdc.com>
2019-08-16 08:42:55 +05:30
Atish Patra
f6e13e0dd3 lib: Provide an atomic exchange function unsigned long
Signed-off-by: Anup Patel <anup.patel@wdc.com>
Signed-off-by: Atish Patra <atish.patra@wdc.com>
2019-08-16 08:42:52 +05:30
Anup Patel
a88e424f6c lib: Handle traps when doing unpriv load/store in get_insn()
We can get a page/access trap when doing unpriv load/store in
get_insn() function because on a SMP system Linux swapper running
on HART A can unmap pages from page table used by HART B.

To tackle this we extend get_insn() implementation so that if
we get trap in get_insn() then we redirect it to S-mode as fetch
page/access fault.

Signed-off-by: Anup Patel <anup.patel@wdc.com>
2019-08-13 09:48:40 +05:30
Lukas Auer
2e0f3ac758 firmware: do not use relocated _boot_status before it is valid
When OpenSBI is started from an address not equal to the link address,
it is first relocated to the link address. Hart 0 performs the
relocation and notifies the other harts of its completion with the
_boot_status variable. It uses the copy of the variable relative to the
link address. This copy contains valid data only after relocation has
finished. The waiting harts will therefore read invalid data until
relocation has finished. This can cause them to continue execution too
early.

Fix this by using the _boot_status variable relative to the load address
while OpenSBI has not finished relocation.

Signed-off-by: Lukas Auer <lukas.auer@aisec.fraunhofer.de>
Reviewed-by: Anup Patel <anup.patel@wdc.com>
2019-08-13 09:07:16 +05:30
Jacob Garber
6c24193293 lib: Correct null pointer check
In order to prevent a possible null pointer dereference, return early if
either one of 'in' or 'data' is null.

Signed-off-by: Jacob Garber <jgarber1@ualberta.ca>
Reviewed-by: Bin Meng <bmeng.cn@gmail.com>
Reviewed-by: Atish Patra <atish.patra@wdc.com>
2019-08-12 09:27:47 +05:30
Jacob Garber
5e4021a2f5 lib: Prevent unintended sign extensions
In the last argument to sbi_memset() we essentially have the following
multiplication:

    size_t = u16 * u16

Due to C's integer semantics, both u16's are implicitly converted to int
before the multiplication, which cannot hold all possible values of a
u16 * u16. If the multiplication overflows, the intermediate result will
be a negative number. On 64-bit platforms, this will be sign-extended to
a huge integer in the conversion to a u64 (aka size_t). Being the size
argument to sbi_memset(), this could potentially cause a large
out-of-bounds write. The solution is to manually cast one of the u16 to
a size_t, which will make it large enough to avoid the implicit
conversion and any overflow.

Signed-off-by: Jacob Garber <jgarber1@ualberta.ca>
Reviewed-by: Bin Meng <bmeng.cn@gmail.com>
Reviewed-by: Atish Patra <atish.patra@wdc.com>
2019-08-12 09:26:38 +05:30
Jacob Garber
6ddf71e6e9 lib: Use correct type for return value
The error check 'plic_off < 0' does nothing, since plic_off is stored as
a u32. Fix this by changing it to an int, which matches the return type of
fdt_node_offset_by_compatible().

Signed-off-by: Jacob Garber <jgarber1@ualberta.ca>
Reviewed-by: Bin Meng <bmeng.cn@gmail.com>
Reviewed-by: Atish Patra <atish.patra@wdc.com>
2019-08-12 09:23:28 +05:30
Jacob Garber
3f738f5897 lib: Use bitwise & instead of boolean &&
!(mipval && MIP_MSIP) simplifies to !mipval, which checks if the entire
variable is zero, not just a single bit. Fix this to use bitwise &
instead.

Signed-off-by: Jacob Garber <jgarber1@ualberta.ca>
Reviewed-by: Bin Meng <bmeng.cn@gmail.com>
Reviewed-by: Atish Patra <atish.patra@wdc.com>
2019-08-12 09:22:20 +05:30
Anup Patel
88c87f0af4 lib: Use sbi_dprintf() for invalid CSRs
We should sbi_dprintf() instead of sbi_printf() for invalid CSRs
because we are forwarding invalid CSR access back to S-mode.

Signed-off-by: Anup Patel <anup.patel@wdc.com>
Reviewed-by: Bin Meng <bmeng.cn@gmail.com>
2019-08-09 12:38:36 +05:30
Anup Patel
dbff3e9f12 lib: Introduce sbi_dprintf() API
This patch introduces new sbi_dprintf() API for runtime debug
prints. The sbi_dprintf() will print to console for a given
HART only when SBI_SCRATCH_DEBUG_PRINTS option in enabled in
sbi_scratch for this HART.

We can now add debug prints using sbi_dprintf() at important
places in OpenSBI sources. These debug prints will only show
up when previous booting stage or compile time parameter sets
the SBI_SCRATCH_DEBUG_PRINTS option in scratch space.

Signed-off-by: Anup Patel <anup.patel@wdc.com>
Reviewed-by: Bin Meng <bmeng.cn@gmail.com>
2019-08-09 12:38:33 +05:30
Bin Meng
b1318e578b firmware: Use macro instead of magic number for boot status
The boot status is currently hard-coded. Define some macros for it.

Signed-off-by: Bin Meng <bmeng.cn@gmail.com>
Reviewed-by: Anup Patel <anup.patel@wdc.com>
2019-08-09 12:30:08 +05:30
Bin Meng
446b6f30a4 platform: sifive: fu540: Expand FDT size before any patching
We should expand the FDT size before any patching, otherwise it's
possible the "status" fix up might fail due to insufficient space.

Signed-off-by: Bin Meng <bmeng.cn@gmail.com>
Reviewed-by: Anup Patel <anup.patel@wdc.com>
2019-08-09 12:30:06 +05:30
Nylon Chen
c1b9dd3ab5 firmware: Fix the loop condition of _wait_relocate_copy_done section
If core-0 have finished _fdt_reloc_done but any of other cores has not
yet left the loop in _wait_relocate_copy_done, they could never leave
the loop because _boot_status is not equal to 1.
2019-08-07 18:04:53 +05:30
Anup Patel
0f18b3fe0a lib: Allow compiling without FP support
Currently, we mandate 'F' and 'D' extension in riscv_fp.h so that
misaligned load/store emulation has access to FP registers.

The above is too restrictive and we should certainly allow compilation
for soft-FP toolchains and explicit PLATFORM_RISCV_ISA not having 'F'
and 'D' extensions.

This patch extends riscv_fp.h and misaligned load/store emulation to
allow compiling OpenSBI without FP support.

Signed-off-by: Anup Patel <anup.patel@wdc.com>
Reviewed-by: Bin Meng <bmeng.cn@gmail.com>
2019-07-26 15:49:49 +05:30
Bin Meng
85546a5477 treewide: Use conventional names for 32-bit and 64-bit
There are several places in the source tree that have:

  32bit, 32 bit, 64bit, 64 bit

Fix by using the conventional names with a hyphen.

Signed-off-by: Bin Meng <bmeng.cn@gmail.com>
Reviewed-by: Lukas Auer <lukas.auer@aisec.fraunhofer.de>
Acked-by: Anup Patel <anup.patel@wdc.com>
2019-07-25 09:14:58 +05:30
Bin Meng
c90009aa20 README: Document 32-bit / 64-bit images build
At present the exact details of building 32-bit or 64-bit OpenSBI
images are missing in the docs. This adds the missing part.

Signed-off-by: Bin Meng <bmeng.cn@gmail.com>
Reviewed-by: Lukas Auer <lukas.auer@aisec.fraunhofer.de>
Acked-by: Anup Patel <anup.patel@wdc.com>
2019-07-25 09:11:49 +05:30
Georg Kotheimer
bf2ee7bcdc utils: Use cpu_to_fdt32() when writing to fdt
Although it does not make a functional difference, both cpu_to_fdt32()
and fdt32_to_cpu() pass on to CPU_TO_FDT32, we should use cpu_to_fdt32()
to be semantically correct.

Signed-off-by: Georg Kotheimer <georg.kotheimer@kernkonzept.com>
Reviewed-by: Atish Patra <atish.patra@wdc.com>
Acked-by: Anup Patel <anup.patel@wdc.com>
2019-07-25 08:59:50 +05:30
Anup Patel
e3f743339a platform: sifive/fu540: Move FDT further up
This patch changes FW_xyz_FDT_ADDR to RAM_START+128MB (i.e. 0x88000000)
so that next stage bootloader (i.e. U-Boot) has enough space to unpack
bigger kernel images.

Reported-by: David Abdurachmanov <david.abdurachmanov@sifive.com>
Signed-off-by: Anup Patel <anup.patel@wdc.com>
Reviewed-by: Bin Meng <bmeng.cn@gmail.com>
Reviewed-by: David Abdurachmanov <david.abdurachmanov@sifive.com>
Tested-by: David Abdurachmanov <david.abdurachmanov@sifive.com>
2019-07-24 09:24:28 +05:30
Bin Meng
e7456399e4 platform: sifive: fu540: Use standard value string for cpu node status
Per device tree spec, the standard value string for the "status"
property of a cpu node is either "okay" or "disabled". "masked"
was once used but it is unfortunately a spec violation.

Signed-off-by: Bin Meng <bmeng.cn@gmail.com>
Acked-by: Anup Patel <anup.patel@wdc.com>
2019-07-22 11:14:05 +05:30
Anup Patel
ce228ee091 include: Bump-up version to 0.4
This patch updates OpenSBI version to 0.4 as part of
release preparation.

Signed-off-by: Anup Patel <anup.patel@wdc.com>
2019-07-02 11:11:08 +05:30
Atish Patra
42c938e3f0 platform: Remove the HiFive Unleashed expansion board DT.
The Linux kernel will maintain the device tree (DT) for HiFive Unleashed
from release v5.2-rc6. This DT is incompatible with previous DT
present for Microsemi expansion board in OpenSBI.

Since, OpenSBI will directly load the pre-built DTB from kernel now onwards,
no need to keep the out-of-date DT in openSBI. Remove this DT and
it's related documentation.

Signed-off-by: Atish Patra <atish.patra@wdc.com>
Acked-by: Anup Patel <anup.patel@wdc.com>
2019-07-02 10:16:00 +05:30
Anup Patel
bb3edd36af firmware: For no relocation skip two stage wait for secondary HARTs
When relocation is not required (i.e. _load_start == _link_start), we
can skip two stage wait for secondary HARTs. This means secondary HARTs
can skip the _wait_relocate_copy_done() loop and directly jump to the
_wait_for_boot_hart() loop when no relocation not required.

Signed-off-by: Anup Patel <anup.patel@wdc.com>
2019-07-01 08:54:13 +05:30
Anup Patel
da398ef8d6 scripts: Add Ariane FPGA to platform list in binary archive script
This patch adds Ariane FPGA to RV64 platform list in the binary
archive script.

Signed-off-by: Anup Patel <anup.patel@wdc.com>
2019-06-30 12:07:56 +05:30
Atish Patra
d44bc16e4b docs: Update the fu540 platform guide for new DT.
With 5.2-rc6 release, Linux kernel hosts the DT for Unleashed board
which is incompatible with the default DT from FSBL.

Update the document to use the DT from kernel.

Signed-off-by: Atish Patra <atish.patra@wdc.com>
Acked-by: Anup Patel <anup.patel@wdc.com>
2019-06-30 11:56:57 +05:30
Abner Chang
9c18c2c610 include: Add firmware context to sbi_platform
Add firmware context field struct sbi_platform to carry firmware
specific information.

Signed-off-by: Abner Chang <abner.chang@hpe.com>
Acked-by: Anup Patel <anup.patel@wdc.com>
2019-06-29 20:59:45 +05:30
Abner Chang
08b196956d include: Add version info to struct sbi_platform
Add version control of sbi_platform structure
- Add opensbi_version, this gives information of opensbi revision on
which the sbi_platform table was created.
- Add platform_version field in sbi_platform structure for platform
level version control.

Signed-off-by: Abner Chang <abner.chang@hpe.com>
Acked-by: Anup Patel <anup.patel@wdc.com>
2019-06-29 19:26:26 +05:30
Abner Chang
fa6fd6bf86 include: Move callbacks in sbi_platform to separate struct
Move platform opensbi functions to sbi_platform_operations structure.
Both sbi_platform and sbi_platform_operations structures are maintained
by platform vendors.

Signed-off-by: Abner Chang <abner.chang@hpe.com>
Acked-by: Anup Patel <anup.patel@wdc.com>
2019-06-29 18:20:00 +05:30
Panagiotis Peristerakis
3048f979ca Add documentation for Ariane FPGA platform
Signed-off-by: Panagiotis Peristerakis <perister@ics.forth.gr>
2019-06-29 17:04:06 +05:30
Panagiotis Peristerakis
b44e844880 Add support for Ariane FPGA SoC
This patch adds support for Ariane platform.
We needed to enable PLIC interrupts early(like on BBL) due to some issue of the design.
Otherwise, Linux would not get any external interrupts.

Signed-off-by: Panagiotis Peristerakis <perister@ics.forth.gr>
2019-06-29 17:04:06 +05:30
Panagiotis Peristerakis
c6d06a9448 Changed plic_set_thresh() and plic_set_ie() to public
Signed-off-by: Panagiotis Peristerakis <perister@ics.forth.gr>
2019-06-29 17:04:06 +05:30
Xiang W
65aa5873c3 firmware: Handle overlapping load and link addresses in relocation
The old code may corrupt the code of the waiting hart hence this patch
keeps waiting HART within relocation code range at time of relocation.

Signed-off-by: Xiang W <wxjstz@126.com>
Acked-by: Anup Patel <anup.patel@wdc.com>
2019-06-24 09:39:18 +05:30
Atish Patra
cd2dfdc870 docs: Update docs as per new static library.
Signed-off-by: Atish Patra <atish.patra@wdc.com>
Acked-by: Anup Patel <anup.patel@wdc.com>
2019-06-19 09:56:24 +05:30
Atish Patra
5dd93e88fe utils: Remove tinyfdt.c
tinyfdt.c was originally added to provide a minimal implementation of
fdt parsing. However, we have already included libfdt in OpenSBI for
more complicated operations.

Remove tinfdt and replace its functiolity using libfdt.

Signed-off-by: Atish Patra <atish.patra@wdc.com>
Acked-by: Anup Patel <anup.patel@wdc.com>
2019-06-19 09:55:13 +05:30
Atish Patra
b2d0caf86b platform: Enable all drivers by default.
The drivers and libfdt are built as libsbiutils.a
instead of libplatsbi.a.

libsbiutils.a are not built per platform specific. Thus,
enable all drivers by default.

Signed-off-by: Atish Patra <atish.patra@wdc.com>
Acked-by: Anup Patel <anup.patel@wdc.com>
2019-06-19 09:49:05 +05:30
Atish Patra
200ed7c1bd lib: Rename string.x to sbi_string.x
All string functions are part of libsbi. It makes more sense
to rename them to sbi_string.x as the libsbi can be linked
with external libraries that can have similar implementation.

Signed-off-by: Atish Patra <atish.patra@wdc.com>
Acked-by: Anup Patel <anup.patel@wdc.com>
2019-06-19 09:48:59 +05:30
Atish Patra
793e5e1184 platform: Move platform common to lib/utils.
Currently, platform/common contains platform/non-platform specific
common minimal drivers and libraries. This is helpful is all platforms
are built within opensbi framework.

Move them to lib/utils so that any external platform code also can
reuse the minimalistic drivers or other common libraries.

This patch doesn't introduce any functional changes.

Signed-off-by: Atish Patra <atish.patra@wdc.com>
Acked-by: Anup Patel <anup.patel@wdc.com>
2019-06-19 09:48:56 +05:30
Atish Patra
98aaf8317b lib: Include helper libc functions directly in libsbi.
libsbi needs some of the custom libc functions. It should be directly
included in libsbi instead of platform specific libraries.

Signed-off-by: Atish Patra <atish.patra@wdc.com>
Acked-by: Anup Patel <anup.patel@wdc.com>
2019-06-19 09:48:54 +05:30
Atish Patra
749b0b0932 lib: Move sbi core library to lib/sbi
Signed-off-by: Atish Patra <atish.patra@wdc.com>
Acked-by: Anup Patel <anup.patel@wdc.com>
2019-06-19 09:48:51 +05:30
Xiang W
a5b37bd7d2 firmware: Handle overlapping load and link addresses in relocation
This patch extends relocation to handle overlapping load and link
addresses.

The updated relocation will work fine in most cases except when the
relocate copy loop itself falls in overlapping load and link addresses.

Signed-off-by: Xiang W <wxjstz@126.com>
Signed-off-by: Anup Patel <anup.patel@wdc.com>
2019-06-17 11:53:42 +05:30
Anup Patel
331f291e4c firmware: Relocate when load address is not equal to link address
This patch extends fw_base to relocate to link address whenever
firmware load address is not equal to link address.

The relocation will not work when load start to load end overlap
link start to link end.

Signed-off-by: Anup Patel <anup.patel@wdc.com>
Tested-by: Lukas Auer <lukas.auer@aisec.fraunhofer.de>
2019-06-12 17:56:28 +05:30
Lukas Auer
6fec1c7e11 firmware: add missing linker sections to fw_base.ldS
The linker sections .sdata and .sbss are missing from the linker script
fw_base.ldS. Add them to the .data and .bss sections.

On current builds, most variables are in the .sbss section. They are not
correctly initialized to zero, because they are not within the
boundaries indicated by _bss_start and _bss_end. Currently, this does
not cause any issues, however with relocation support lock-ups may occur
due to incorrectly initialized lock variables.

Signed-off-by: Lukas Auer <lukas.auer@aisec.fraunhofer.de>
Acked-by: Anup Patel <anup.patel@wdc.com>
2019-06-12 17:43:47 +05:30
Karsten Merker
f19611e1e4 docs: update CONTRIBUTORS.md
Add Andreas Schwab to the contributors list.

Signed-off-by: Karsten Merker <merker@debian.org>
Acked-by: Andreas Schwab <schwab@suse.de>
2019-05-31 16:56:43 +05:30
Bin Meng
b6ea152df2 docs: qemu/sifive_u: miscellaneous documentation fixes
- OpenSBI build target should be: qemu/sifive_u
- U-Boot config name should be: sifive_fu540_defconfig

Signed-off-by: Bin Meng <bmeng.cn@gmail.com>
Reviewed-by: Atish Patra <atish.patra@wdc.com>
2019-05-30 22:37:31 +05:30
Bin Meng
2b80945ac7 platform: qemu/sifive_u: Update the hart count to 4
Since QEMU commit 8b1d0714bfdd
"riscv: sifive_u: Allow up to 4 CPUs to be created",
the maximum number of hart for sifive_u is 4.

Change our hart count to match that.

Signed-off-by: Bin Meng <bmeng.cn@gmail.com>
Reviewed-by: Atish Patra <atish.patra@wdc.com>
2019-05-30 22:36:17 +05:30
Anup Patel
a6395acd6c lib: Handle page/access fault caused by unpriv load/store
The unpriv load/store instruction from M-mode can cause page/access
fault to M-mode if S-mode page table did not have mappings OR it did
not have PMP access permission.

To tackle this, we redirect trap back to S-mode if unpriv load/store
instruction traps in M-mode.

Signed-off-by: Anup Patel <anup.patel@wdc.com>
Reviewed-by: Atish Patra <atish.patra@wdc.com>
2019-05-24 08:22:47 +05:30
Anup Patel
bb915780ac lib: Add per-HART trap info pointer
This patch adds per-HART trap info pointer which can be used to
communicate trap information to sbi_trap_handler().

Signed-off-by: Anup Patel <anup.patel@wdc.com>
Reviewed-by: Atish Patra <atish.patra@wdc.com>
2019-05-24 08:22:47 +05:30
Anup Patel
a22c6891b7 include: Make unprivilege load/store functions as non-inline functions
Currently, the unprivilege load/store functions are inline functions.

We will be extending these functions to track whether a page/access
fault occurs when we execute unprivilege load/store instruction.

To make things simpler and debugable, we reduce number of places which
can potentially generate a page/access fault by making all unprivilege
load/store functions as regular (non-inline) functions.

Signed-off-by: Anup Patel <anup.patel@wdc.com>
Reviewed-by: Atish Patra <atish.patra@wdc.com>
2019-05-24 08:22:47 +05:30
Anup Patel
95b7480ab4 lib: Factor-out TLB management from IPI management
This patch factor-out TLB management from IPI management to separate
sources sbi_tlb.c and sbi_tlb.h.

Signed-off-by: Anup Patel <anup.patel@wdc.com>
Reviewed-by: Atish Patra <atish.patra@wdc.com>
2019-05-24 08:22:47 +05:30
Anup Patel
2dfed32c46 lib: Add a simple brain-dead allocator to manage extra scratch space
We have extra space above scratch space (sbi_scratch) which we are
currently using to manage per-HART IPI data and TLB request management.

In future, more parts of OpenSBI will use the extra scratch space so
it will become difficult to manage extra scratch space using just
defines and macros.

This patch adds a simple brain-dead allocator to manage extra scratch
space. This allocator never expects anything to be free-ed hence it
keeps incrementing to next allocation offset until it runs-out of space.

In future, we can have more sophisticated allocator which will allow
us to re-claim free-ed space and also allows us to track owner of
allocated space.

Signed-off-by: Anup Patel <anup.patel@wdc.com>
Reviewed-by: Atish Patra <atish.patra@wdc.com>
2019-05-24 08:22:47 +05:30
Anup Patel
4e2cd47820 lib: Flush everything when remote TLB flush range is too large
On latest Linux kernel (i.e. 5.2-rc1), we get large TLB flush
request for user space addresses (typically, start=x and end=-1).
This is caused by Linux kernel commit a21344dfc6 ("riscv: fix
sbi_remote_sfence_vma{,_asid}").

It's not practical to execute large number of sfence instructions
for a large TLB flush range because it takes too much time and
eventually causes CPU stall in Linux kernel.

This patch addresses above issue by upgrading TLB flush range to
TLB flush all whenever TLB flush range is greater than 1GB.

Signed-off-by: Anup Patel <anup.patel@wdc.com>
Reviewed-by: Atish Patra <atish.patra@wdc.com>
2019-05-21 10:06:08 +05:30
Anup Patel
392749f633 docs: Add documentation about dynamic firmware
This patch adds documenation about dynamic firmware.

Signed-off-by: Anup Patel <anup.patel@wdc.com>
Reviewed-by: Alistair Francis <alistair.francis@wdc.com>
Reviewed-by: Atish Patra <atish.patra@wdc.com>
2019-05-10 12:26:22 +05:30
Anup Patel
a4c2f50b64 platform: Enable dynamic firmware for appropriate platforms
This patch enables FW_DYNAMIC option (i.e. dynamic firmware) for
all appropriate/applicable platforms.

Signed-off-by: Anup Patel <anup.patel@wdc.com>
Reviewed-by: Alistair Francis <alistair.francis@wdc.com>
2019-05-10 12:26:22 +05:30
Anup Patel
bae54f7645 firmware: Add fw_dynamic firmware
This patch provides first-cut implementation of fw_dynamic firmware.

As compared to fw_jump and fw_payload, the fw_dynamic obtains next
address, next mode and OpenSBI options from struct fw_dynamic_info.

The previous booting stage can create struct fw_dynamic_info in memory
and pass address of struct fw_dynamic_info in 'a2' register. Also, the
struct fw_dynamic_info has versioning as well so changes to the struct
fw_dynamic_info can be done in a backward compatible manner.

Signed-off-by: Anup Patel <anup.patel@wdc.com>
Reviewed-by: Atish Patra <atish.patra@wdc.com>
2019-05-10 12:26:22 +05:30
Anup Patel
25472de89e firmware: Allow firmwares to provide next mode and options
This patch extends existing firmwares (i.e. fw_jump and fw_payload)
to explicitly provide next mode and options to fw_base.

We also introduce fw_save_info() which is called by fw_base very
early on boot HART. This function can be used by existing firmwares
(i.e. fw_jump and fw_payload) to save information passed by previous
booting stage.

Overall, this is a preparatory patch for implementing fw_dynamic.

Signed-off-by: Anup Patel <anup.patel@wdc.com>
Reviewed-by: Alistair Francis <alistair.francis@wdc.com>
Reviewed-by: Atish Patra <atish.patra@wdc.com>
2019-05-10 12:26:22 +05:30
Karsten Merker
243a5e0532 docs: update CONTRIBUTORS.md from git history
OpenSBI has recently gained a CONTRIBUTORS.md file as a way
to make contributions to OpenSBI more visible.  Add previous
contributors from the git history who have acked their
inclusion in the list to the file.

Signed-off-by: Karsten Merker <merker@debian.org>
Acked-by: Alistair Francis <alistair@alistair23.me>
Acked-by: Anup Patel <anup.patel@wdc.com>
Acked-by: Atish Patra <atish.patra@wdc.com>
Acked-by: Bin Meng <bmeng.cn@gmail.com>
Acked-by: Damien Le Moal <damien.lemoal@wdc.com>
Acked-by: Nick Kossifidis <mickflemm@gmail.com>
Acked-by: Shawn Chang <citypw@gmail.com>
Acked-by: Xiang Wang <wxjstz@126.com>
2019-05-06 11:09:03 +05:30
Karsten Merker
0d33a981ec docs: miscellaneous documentation fixes and updates
- fix some broken hyperlinks
- add additional hyperlinks to references to external documents
- reformat some paragraphs to keep lines under 80 characters
- unify the enumeration style between different parts of the
  documentation
- fix spelling/grammar mistakes
- extend the copyright notice in README.md to be the same as the
  one in COPYING.BSD

Signed-off-by: Karsten Merker <merker@debian.org>
Reviewed-by: Atish Patra <atish.patra@wdc.com>
2019-05-06 11:05:33 +05:30
Loys Ollivier
3bb2d25f44 Update sifive_fu540.md
Fix typo on parenthesis.
2019-05-06 09:42:56 +05:30
Karsten Merker
f9643f3472 Makefile: explicitly disable PIE
The various available RISC-V toolchains differ in their default
configuration regarding PIE, e.g. the buildroot RISC-V toolchain
has PIE disabled by default while the Debian toolchain has it
enabled by default.

OpenSBI currently doesn't support being built with PIE enabled,
therefore disable it explicitly by passing "-fno-pie -no-pie" in
CFLAGS.

Signed-off-by: Karsten Merker <merker@debian.org>
Acked-by: Anup Patel <anup.patel@wdc.com>
2019-04-30 09:21:47 +05:30
Xiang Wang
c1d01b0c2e platform/common/libfdt: fix unnecessary multiple inclusions
Signed-off-by: Xiang Wang <wxjstz@126.com>
2019-04-25 10:23:31 -07:00
Shawn Chang
03ec350c83 docs: Add a payload section about coreboot support #116
Signed-off-by: Shawn Chang <citypw@gmail.com>
2019-04-25 09:47:13 +05:30
Olof Johansson
10baa64c02 all: run clang-format and update checked-in files
Noisy commit, no functional changes.

Generated with an current upstream clang-format and:

clang-format -i $(find . -name \*.[ch])

Signed-off-by: Olof Johansson <olof@lixom.net>
2019-04-24 09:49:46 +05:30
Olof Johansson
fbf986ac2a all: Annotate some tables to have clang-format leave them alone
One of the shortcomings of clang-format is that it doesn't allow
for aligned define tables, which is used for a number of constants.

Add annotation to disable the automatic formatting where needed.

Signed-off-by: Olof Johansson <olof@lixom.net>
2019-04-24 09:49:46 +05:30
Olof Johansson
97fb8c0e3b libfdt: don't try to clang-format
Add an empty clang-format to disable reformatting of imported code and
make it easier to merge in upstream changes of that project over time.

Signed-off-by: Olof Johansson <olof@lixom.net>
2019-04-24 09:49:46 +05:30
Olof Johansson
1e43ce75ff top: add .clang-format
Add a clang-format to automate consistent code formatting.

Automating coding style reformatting removes a lot of manual
checkpatch-type fixups, and can easily be implemented as a linter in
code review environments.

Signed-off-by: Olof Johansson <olof@lixom.net>
2019-04-24 09:49:46 +05:30
Nick Kossifidis
804b997ed4 lib: Redirect unhandled traps from non-M modes to S mode
In case we didn't handle a trap with one of the available
handlers, check if the trap comes from S or U mode and
redirect it to S mode's trap handler.

Signed-off-by: Nick Kossifidis <mick@ics.forth.gr>
2019-04-22 09:56:20 +05:30
Atish Patra
194dbbe5a1 doc: Update docs as per latest kernel/u-boot status.
All dependant patches are merged in U-Boot and Linux kernel now.
Update the unleashed guide to reflect that and fix the documentation
about tftp loading path as well.

Signed-off-by: Atish Patra <atish.patra@wdc.com>
Reviewed-by: Bin Meng <bmeng.cn@gmail.com>
2019-04-15 10:00:04 +05:30
Anup Pate
b2cd5fda61 top: Add CONTRIBUTORS.md file
We add CONTRIBUTORS.md file to provide a list of individuals and
organizations actively contributing to the OpenSBI project.

Signed-off-by: Anup Patel <anup.patel@wdc.com>
2019-04-15 09:54:10 +05:30
Karsten Merker
743e8ae6e7 docs: qemu/virt platform documentation fixes and updates
- Correct the payload address in the RV64 examples that use
  fw_jump.elf.

- Change the qemu console configuration in the examples from
  "-display none -serial stdio" to "-nographic". This results in
  qemu handing down a CTRL-C on the emulated console to the VM
  instead of terminating the qemu process.

- Provide examples for RV32.

- Various text corrections.

Signed-off-by: Karsten Merker <merker@debian.org>
Reviewed-by: Alistair Francis <alistair.francis@wdc.com>
2019-04-15 08:52:59 +05:30
Atish Patra
999823c597 lib: Optimize TLB flush IPIs
Simulatenous requests for tlbflush IPIs can have overlapping address
ranges.

Ignore if address range is same or within already existing fifo entries.
Update the tlb flush info in fifo directly if the one of the existing
entry lies within the new flush request.
Delete all entries if flush all request is recieved for the vma.

Signed-off-by: Atish Patra <atish.patra@wdc.com>
2019-04-10 15:46:35 +05:30
Atish Patra
110eef44f0 lib: Provide a lock enabled iteration of fifo.
Implement a lock enabled iteration for fifo so that
caller can determine if next entry can be skipped or
any existing entries in fifo can be updated before enqueue.

Signed-off-by: Atish Patra <atish.patra@wdc.com>
2019-04-10 15:46:35 +05:30
Anup Patel
54f31e8209 TOP: Allow building platform out-of-tree
This patch extends our current build-system for building platform
sources which are not part of OpenSBI sources.

For example:

Let's say we have out-of-tree ABC platform sources. We place these
sources under <XYZ>/ABC directory along with its config.mk and
objects.mk.

To build out-of-tree ABC platform from OpenSBI directory:
$ make PLATFORM_DIR=<XYZ>/ABC
OR
$ make PLATFORM_DIR=<XYZ> PLATFORM=ABC

To build out-of-tree ABC platform from <XYZ>/ABC directory:
$ make PLATFORM_DIR=<XYZ>/ABC -C <path_to_opensbi>
OR
$ make PLATFORM_DIR=<XYZ> PLATFORM=ABC -C <path_to_opensbi>

Signed-off-by: Anup Patel <anup.patel@wdc.com>
Reviewed-by: Alistair Francis <alistair.francis@wdc.com>
2019-04-09 09:14:09 +05:30
Alistair Francis
40086daa62 lib: Fix the ecall macro definitions
Fix the ECALL definitions to matc the latest information in the
privlidge spec table 5.5.

Signed-off-by: Alistair Francis <alistair.francis@wdc.com>
2019-04-06 19:06:22 +05:30
Xiang Wang
09f976802b firmware: Fix source fdt alignment
When I tried to start opensbi with coreboot, I found that aligning to a 16-byte
boundary would make a copy error.

Corrected to align to an machine word length boundary.

Signed-off-by: Xiang Wang <wxjstz@126.com>
2019-04-04 09:10:28 +05:30
Anup Patel
3fbe233a15 lib: Pack struct sbi_fifo
This patch reduces memory consumed by struct sbi_fifo by droping
redundant "head" member and using u16 in-place of "unsigned long".

Signed-off-by: Anup Patel <anup.patel@wdc.com>
2019-04-03 13:48:38 -07:00
Anup Patel
9dc95021db lib: More improvements to sbi_fifo
This patch does following improvements to sbi_fifo:
1. Use valid SBI_Exxxx error codes instead of -1
2. The sbi_fifo_is_full() and sbi_fifo_is_empty() did
   not acquire qlock before accessing head and tail
   hence fixed it
3. Added avail member for ease in debugging and simplifying
   head/tail updates.

Due to above changes size of sbi_fifo changes from 48 bytes
to 56 bytes.

Signed-off-by: Anup Patel <anup.patel@wdc.com>
2019-04-03 13:48:38 -07:00
Anup Patel
6dc1b0f6e2 docs: Update mailing list details in contributing.md
We now have an OpenSBI mailing list available for development
and discussiong so update contributing.md accordingly. The
Github PR based review and issue tracking will also continue
to exist.

Signed-off-by: Anup Patel <anup.patel@wdc.com>
2019-04-03 13:48:22 -07:00
Atish Patra
f700216cb5 lib: Use a fifo to keep track of sfence related IPIs.
Currently, there is no provision for tracking multiple IPIs sent
to a single hart at the same time by different harts.

Use a fifo manage the outstanding requests. While dequeueing, read all
the entries once, because we have only 1 bit to track the type of IPI.
Once the queue is full, busy wait until the there is space available in
queue. This is not the most elegant approach. It should be changed in
favor of a wakeup event once available in opensbi.

Signed-off-by: Atish Patra <atish.patra@wdc.com>
2019-04-03 09:57:42 +05:30
Atish Patra
1eba298b0d lib: Increase the scratch space to 512 bytes.
Currently scratch space per hart is 256 bytes. Increase it to 512 bytes
to accomodate ipi queue.

Signed-off-by: Atish Patra <atish.patra@wdc.com>
2019-04-03 09:57:42 +05:30
Atish Patra
fd5418d92c lib: Introduce a tlb info type.
Add a tlb info to distinguish between different type of tlb flush
request pending.

Signed-off-by: Atish Patra <atish.patra@wdc.com>
2019-04-03 09:57:42 +05:30
Atish Patra
8334a88c63 lib: Add a fifo implementation.
Implement a fifo to accomodate outstanding IPIs for a specific hart
at the same time.

Signed-off-by: Atish Patra <atish.patra@wdc.com>
2019-04-03 09:57:42 +05:30
Damien Le Moal
14dadeab09 kendryte/k210: Fix file headers
Add missing SPDX and copyright information.

Signed-off-by: Damien Le Moal <damien.lemoal@wdc.com>
2019-04-03 10:22:57 +09:00
Damien Le Moal
bce71a00bd README: Update license information
Add information regarding the Apache License Version 2.0 of some of the
Kendryte/k210 platform files. Also repeat this information in a new
ThirdPartyNotices.md file.

Signed-off-by: Damien Le Moal <damien.lemoal@wdc.com>
2019-04-03 10:22:57 +09:00
Anup Patel
78c87cd13a include: Make mstatus parameter optional for get_insn()
The mstatus parameter of get_insn() is used to return MSTATUS CSR
value which get_insn() saw. Most of the get_insn() callers don't
use the value returned in mstatus so this patch makes mstatus
parameter optional for get_insn().

Signed-off-by: Anup Patel <anup.patel@wdc.com>
2019-04-01 10:10:38 +05:30
Anup Patel
13877c3a67 include: Rename sbi_unpriv.h to riscv_unpriv.h
The sbi_unpriv.h has quite a few load_xyz() and store_xyz() helper
routines based on RISC-V inline assembly for unpriviledged accesses
from M-mode. These helper routines are similar to helper routines
present in riscv_locks.h, riscv_io.h, and riscv_atomic.h so let's
rename sbi_unpriv.h to riscv_unpriv.h.

Signed-off-by: Anup Patel <anup.patel@wdc.com>
2019-04-01 10:10:38 +05:30
Anup Patel
cfff0126ab lib: Remove unused mepc arg from load_xyz() and store_xyz() functions
This patch removes unused mepc arg from load_xyz() and store_xyz()
unpriviledge access functions.

Signed-off-by: Anup Patel <anup.patel@wdc.com>
2019-04-01 10:10:38 +05:30
Bin Meng
f9cfe301c9 lib: Disable the boot prints if SBI_SCRATCH_NO_BOOT_PRINTS is set
Use the newly introduced "options" in "struct sbi_scratch" to
conditionally disable the boot prints.

Signed-off-by: Bin Meng <bmeng.cn@gmail.com>
2019-03-29 15:49:11 +05:30
Bin Meng
215c200ccb lib: Group all prints during boot into sbi_boot_prints()
Refactor the codes a little bit to put all prints during boot into
sbi_boot_prints().

Signed-off-by: Bin Meng <bmeng.cn@gmail.com>
2019-03-29 15:49:11 +05:30
Bin Meng
132f3e024b firmware: Introduce "options" in "struct sbi_scratch"
Introduce "options" in "struct sbi_scratch" and firmware can update
it based on optional compile time flags before calling sbi_init().

Signed-off-by: Bin Meng <bmeng.cn@gmail.com>
2019-03-29 15:49:11 +05:30
Bin Meng
e921fc2691 platform: plic: Fix comments of programming the interrupt enable register
The codes that currently program the interrupt enable register for
S-mode disagrees with what the comments say. Fix the comments.

While we are here, add one line comment to describe what is done
for M-mode too.

Signed-off-by: Bin Meng <bmeng.cn@gmail.com>
2019-03-18 18:18:16 +05:30
Atish Patra
6c39ea99ee lib: Return ENOTSUPP incase of invalid SBI function ID
OpenSBI should show error trace only if any valid SBI function
does not perform as expected.

However, OpenSBI should show notify the caller with a negative
error if given SBI function ID is not valid.

Signed-off-by: Atish Patra <atish.patra@wdc.com>
2019-03-14 20:44:22 +05:30
Bin Meng
312850148a platform: plic: Bypass interrupt ID 0's priority programming
Per PLIC spec, interrupt ID 0 is defined to mean "no interrupt".
We should bypass it.

Signed-off-by: Bin Meng <bmeng.cn@gmail.com>
2019-03-14 20:43:35 +05:30
Bin Meng
ebe351e550 platform: plic: Fix plic_set_priority()
At present plic_set_priority() ignores the 'source' and the priority
register to be programmed is constant. Fix it.

Signed-off-by: Bin Meng <bmeng.cn@gmail.com>
2019-03-14 20:43:35 +05:30
Atish Patra
ab91c143a3 firmware: Move scratch setup to _start instead of _start_warm
Scratch space setup needs to be done once for reboot for each
hart. _start_warm may be called several times if hart hotplug
is implemented.

Move scratch space setup to the beginning so that it is done
only once.

Signed-off-by: Atish Patra <atish.patra@wdc.com>
2019-03-14 20:43:09 +05:30
Atish Patra
1e24e21d56 lib: Fix full tlb flush behavior
Currently, global page mappings are not flushed if start and size
arguments are zero.

Flush entire TLB if both size and start argument is passed as zero.

Fixes : 90cb491 (lib: Implement sfence.vma correctly)

Signed-off-by: Atish Patra <atish.patra@wdc.com>
2019-03-14 20:41:13 +05:30
Bin Meng
896870e9b0 platform: fu540: Fix cosmetic styling issues
There are some spaces or mixed usage of spaces and tabs in the macro
definition. Change to use tab consistently.

Signed-off-by: Bin Meng <bmeng.cn@gmail.com>
2019-03-13 23:53:21 +05:30
Bin Meng
6cd668df12 docs: firmware: Fix spelling of U-Boot
It's U-Boot, not U-boot.

Signed-off-by: Bin Meng <bmeng.cn@gmail.com>
2019-03-13 23:53:21 +05:30
Atish Patra
90cb4917b5 lib: Implement sfence.vma correctly.
Currently, OpenSBI doesn't distinguish between sfence.vma
and sfence.vm asid calls. Moreover, it ignores the page
ranges and just flush entire TLB everytime.

Fix the sfence implementation by keeping all the tlb flush
info in scratch area.

The relevant Linux kernel code was added by
https://patchwork.kernel.org/project/linux-riscv/list/?series=89695

However, this patch is backward compatible with older version kernel
that doesn't have the above patches as well.

Fixes #87
Signed-off-by: Atish Patra <atish.patra@wdc.com>
2019-03-12 22:07:25 +05:30
Alistair Francis
508a27204c lib: Create a sbi_ipi_data structure
Create a sbi_ipi_data structure that holds unpacked IPI information. At
the same time remove ipi_type from the sbi_scratch struct and use a
fixed offset to access it.

This structure fits in behind the sbi_scratch structure.

This fixes https://github.com/riscv/opensbi/issues/81

Signed-off-by: Alistair Francis <alistair.francis@wdc.com>
2019-03-10 21:08:21 +05:30
Atish Patra
007a6b26d9 firmware: Reset all registers and flush icache
A warm reset using reset button may put icache and registers
in non-coherent state.

Flush the icache and reset all registers for every hart.

Signed-off-by: Atish Patra <atish.patra@wdc.com>
2019-03-07 08:07:18 +05:30
Atish Patra
b225583881 firmware: Add nop to reduce bus traffic.
All the non-boot harts run in a tight loop which may cause a heavy load
on the memory bus. This may delay the boot hart to complete the cold boot
process.

Introduce few nop that will ease up the traffic.

Signed-off-by: Atish Patra <atish.patra@wdc.com>
2019-03-07 08:07:18 +05:30
Atish Patra
69d794cbcb Revert "firmware: Add a barrier instruction for wait for boot hart"
This reverts commit 05602e2bf4.

Introducing a fence causes warm reset issue to reappear. Revert it
for the time being.
2019-03-07 08:07:18 +05:30
Xiang Wang
9eb8f0f90d platform: Make the platform read-only
platform should be a read-only variable, if it is placed in the data
segment, it may be exploited.

Signed-off-by: Xiang Wang <wxjstz@126.com>
2019-03-06 11:10:35 -08:00
Atish Patra
27fae182dc firmware: Reset all the general purpose registers to zero.
A warm reset by pressing the reset button may not initialize all the
registers to zero. Do it for every hart during warm boot.

Signed-off-by: Atish Patra <atish.patra@wdc.com>
2019-03-06 08:59:54 +05:30
Atish Patra
d4dd2b37f3 firmware: Ensure the mtvec is updated.
Signed-off-by: Atish Patra <atish.patra@wdc.com>
2019-03-06 08:59:54 +05:30
Atish Patra
754ff34108 firmware: Fix a typo
Signed-off-by: Atish Patra <atish.patra@wdc.com>
2019-03-06 08:59:54 +05:30
Atish Patra
86cc9b8633 lib:platform: Fix sbi_getc return type.
As per the current SBI specification, sbi_getc should return
an int instead of char.

In case of FIFO is empty, return -1 as per the specification.

Reported-by: Sergi Granell <xerpi.g.12@gmail.com>
Suggested-by:Thadeu Lima de Souza Cascardo <cascardo@cascardo.eti.br>
Signed-off-by: Atish Patra <atish.patra@wdc.com>
2019-03-05 14:05:12 +05:30
Xiang Wang
05602e2bf4 firmware: Add a barrier instruction for wait for boot hart
Multi-core communication via memory requires the addition of a barrier
instructions to ensure cache coherency.

Signed-off-by: Xiang Wang <wxjstz@126.com>
2019-03-05 09:09:40 +05:30
Xiang Wang
1c87f0f9b1 firmware: Move _boot_hart_done to the data section
Writable code section can cause some security problems, so move _boot_hart_done
to the data section

Signed-off-by: Xiang Wang <wxjstz@126.com>
2019-03-05 09:09:40 +05:30
Xiang Wang
a72467f574 Add tags to .gitignore for being development friendly
Signed-off-by: Xiang Wang <wxjstz@126.com>
2019-03-05 09:07:23 +05:30
Andreas Schwab
87fbcf9376 Fix missing quotes in Makefile 2019-02-28 09:02:54 +05:30
Andreas Schwab
178a0307a2 Fix makefile dependency generation 2019-02-28 09:02:54 +05:30
180 changed files with 8298 additions and 5194 deletions

16
.clang-format Normal file
View File

@@ -0,0 +1,16 @@
AlignConsecutiveAssignments: true
AlignEscapedNewlines: Left
AlignTrailingComments: true
AllowShortFunctionsOnASingleLine: None
BraceWrapping:
AfterFunction: true
BreakBeforeBraces: Custom
BreakStringLiterals: false
ContinuationIndentWidth: 8
Cpp11BracedListStyle: false
IndentWidth: 8
ReflowComments: false
SortIncludes: false
SpacesInContainerLiterals: false
TabWidth: 8
UseTab: Always

3
.gitignore vendored
View File

@@ -6,3 +6,6 @@
#Build & install directories #Build & install directories
build/ build/
install/ install/
# Development friendly files
tags

27
CONTRIBUTORS.md Normal file
View File

@@ -0,0 +1,27 @@
List of OpenSBI Contributors (Alphabetically sorted)
====================================================
* **[Western Digital Corporation](https://www.wdc.com/)**
* Project initiator and maintainer
* Copyright (c) 2019 Western Digital Corporation or its affiliates
* Alistair Francis <alistair@alistair23.me>
* Andreas Schwab <schwab@suse.de>
* Anup Patel <anup.patel@wdc.com>
* Atish Patra <atish.patra@wdc.com>
* Bin Meng <bmeng.cn@gmail.com>
* Damien Le Moal <damien.lemoal@wdc.com>
* Karsten Merker <merker@debian.org>
* Nick Kossifidis <mickflemm@gmail.com>
* Shawn Chang <citypw@gmail.com>
* Xiang Wang <wxjstz@126.com>

View File

@@ -1,7 +1,8 @@
The 2-Clause BSD License The 2-Clause BSD License
SPDX short identifier: BSD-2-Clause SPDX short identifier: BSD-2-Clause
Copyright (c) 2019 Western Digital Corporation or its affiliates. Copyright (c) 2019 Western Digital Corporation or its affiliates and other
contributors.
Redistribution and use in source and binary forms, with or without Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met: modification, are permitted provided that the following conditions are met:
@@ -22,4 +23,3 @@ LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

131
Makefile
View File

@@ -12,10 +12,17 @@
# o Do not print "Entering directory ..."; # o Do not print "Entering directory ...";
MAKEFLAGS += -r --no-print-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 # Find out source, build, and install directories
src_dir=$(CURDIR) src_dir=$(CURDIR)
ifdef O ifdef O
build_dir=$(shell readlink -f $(O)) build_dir=$(shell $(READLINK) -f $(O))
else else
build_dir=$(CURDIR)/build build_dir=$(CURDIR)/build
endif endif
@@ -23,7 +30,7 @@ ifeq ($(build_dir),$(CURDIR))
$(error Build directory is same as source directory.) $(error Build directory is same as source directory.)
endif endif
ifdef I ifdef I
install_dir=$(shell readlink -f $(I)) install_dir=$(shell $(READLINK) -f $(I))
else else
install_dir=$(CURDIR)/install install_dir=$(CURDIR)/install
endif endif
@@ -33,6 +40,17 @@ endif
ifeq ($(install_dir),$(build_dir)) ifeq ($(install_dir),$(build_dir))
$(error Install directory is same as build directory.) $(error Install directory is same as build directory.)
endif endif
ifdef PLATFORM_DIR
platform_dir_path=$(shell $(READLINK) -f $(PLATFORM_DIR))
ifdef PLATFORM
platform_parent_dir=$(platform_dir_path)
else
PLATFORM=$(shell basename $(platform_dir_path))
platform_parent_dir=$(subst $(PLATFORM),,$(platform_dir_path))
endif
else
platform_parent_dir=$(src_dir)/platform
endif
# Check if verbosity is ON for build process # Check if verbosity is ON for build process
CMD_PREFIX_DEFAULT := @ CMD_PREFIX_DEFAULT := @
@@ -43,16 +61,18 @@ else
endif endif
# Setup path of directories # Setup path of directories
export platform_subdir=platform/$(PLATFORM) export platform_subdir=$(PLATFORM)
export platform_dir=$(CURDIR)/$(platform_subdir) export platform_src_dir=$(platform_parent_dir)/$(platform_subdir)
export platform_common_dir=$(CURDIR)/platform/common export platform_build_dir=$(build_dir)/platform/$(platform_subdir)
export include_dir=$(CURDIR)/include export include_dir=$(CURDIR)/include
export lib_dir=$(CURDIR)/lib export libsbi_dir=$(CURDIR)/lib/sbi
export libsbiutils_dir=$(CURDIR)/lib/utils
export firmware_dir=$(CURDIR)/firmware export firmware_dir=$(CURDIR)/firmware
# Find library version # Find library version
OPENSBI_VERSION_MAJOR=`grep MAJOR $(include_dir)/sbi/sbi_version.h | sed 's/.*MAJOR.*\([0-9][0-9]*\)/\1/'` OPENSBI_VERSION_MAJOR=`grep "define OPENSBI_VERSION_MAJOR" $(include_dir)/sbi/sbi_version.h | sed 's/.*MAJOR.*\([0-9][0-9]*\)/\1/'`
OPENSBI_VERSION_MINOR=`grep MINOR $(include_dir)/sbi/sbi_version.h | sed 's/.*MINOR.*\([0-9][0-9]*\)/\1/'` OPENSBI_VERSION_MINOR=`grep "define OPENSBI_VERSION_MINOR" $(include_dir)/sbi/sbi_version.h | sed 's/.*MINOR.*\([0-9][0-9]*\)/\1/'`
OPENSBI_VERSION_GIT=$(shell if [ -d $(src_dir)/.git ]; then git describe 2> /dev/null; fi)
# Setup compilation commands # Setup compilation commands
ifdef CROSS_COMPILE ifdef CROSS_COMPILE
@@ -85,40 +105,40 @@ endif
# Setup list of objects.mk files # Setup list of objects.mk files
ifdef PLATFORM ifdef PLATFORM
platform-object-mks=$(shell if [ -d $(platform_dir) ]; then find $(platform_dir) -iname "objects.mk" | sort -r; fi) platform-object-mks=$(shell if [ -d $(platform_src_dir)/ ]; then find $(platform_src_dir) -iname "objects.mk" | sort -r; fi)
platform-common-object-mks=$(shell if [ -d $(platform_common_dir) ]; then find $(platform_common_dir) -iname "objects.mk" | sort -r; fi)
endif endif
lib-object-mks=$(shell if [ -d $(lib_dir) ]; then find $(lib_dir) -iname "objects.mk" | sort -r; fi) libsbi-object-mks=$(shell if [ -d $(libsbi_dir) ]; then find $(libsbi_dir) -iname "objects.mk" | sort -r; fi)
libsbiutils-object-mks=$(shell if [ -d $(libsbiutils_dir) ]; then find $(libsbiutils_dir) -iname "objects.mk" | sort -r; fi)
firmware-object-mks=$(shell if [ -d $(firmware_dir) ]; then find $(firmware_dir) -iname "objects.mk" | sort -r; fi) firmware-object-mks=$(shell if [ -d $(firmware_dir) ]; then find $(firmware_dir) -iname "objects.mk" | sort -r; fi)
# Include platform specifig config.mk # Include platform specifig config.mk
ifdef PLATFORM ifdef PLATFORM
include $(platform_dir)/config.mk include $(platform_src_dir)/config.mk
endif endif
# Include all object.mk files # Include all object.mk files
ifdef PLATFORM ifdef PLATFORM
include $(platform-object-mks) include $(platform-object-mks)
include $(platform-common-object-mks)
endif endif
include $(lib-object-mks) include $(libsbi-object-mks)
include $(libsbiutils-object-mks)
include $(firmware-object-mks) include $(firmware-object-mks)
# Setup list of objects # Setup list of objects
lib-objs-path-y=$(foreach obj,$(lib-objs-y),$(build_dir)/lib/$(obj)) libsbi-objs-path-y=$(foreach obj,$(libsbi-objs-y),$(build_dir)/lib/sbi/$(obj))
libsbiutils-objs-path-y=$(foreach obj,$(libsbiutils-objs-y),$(build_dir)/lib/utils/$(obj))
ifdef PLATFORM ifdef PLATFORM
platform-objs-path-y=$(foreach obj,$(platform-objs-y),$(build_dir)/$(platform_subdir)/$(obj)) platform-objs-path-y=$(foreach obj,$(platform-objs-y),$(platform_build_dir)/$(obj))
platform-dtb-path-y=$(foreach obj,$(platform-dtb-y),$(build_dir)/$(platform_subdir)/$(obj)) platform-dtb-path-y=$(foreach obj,$(platform-dtb-y),$(platform_build_dir)/$(obj))
platform-common-objs-path-y=$(foreach obj,$(platform-common-objs-y),$(build_dir)/platform/common/$(obj)) firmware-bins-path-y=$(foreach bin,$(firmware-bins-y),$(platform_build_dir)/firmware/$(bin))
firmware-bins-path-y=$(foreach bin,$(firmware-bins-y),$(build_dir)/$(platform_subdir)/firmware/$(bin))
endif endif
firmware-elfs-path-y=$(firmware-bins-path-y:.bin=.elf) firmware-elfs-path-y=$(firmware-bins-path-y:.bin=.elf)
firmware-objs-path-y=$(firmware-bins-path-y:.bin=.o) firmware-objs-path-y=$(firmware-bins-path-y:.bin=.o)
# Setup list of deps files for objects # Setup list of deps files for objects
deps-y=$(platform-objs-path-y:.o=.dep) deps-y=$(platform-objs-path-y:.o=.dep)
deps-y+=$(platform-common-objs-path-y:.o=.dep) deps-y+=$(libsbi-objs-path-y:.o=.dep)
deps-y+=$(lib-objs-path-y:.o=.dep) deps-y+=$(libsbiutils-objs-path-y:.o=.dep)
deps-y+=$(firmware-objs-path-y:.o=.dep) deps-y+=$(firmware-objs-path-y:.o=.dep)
# Setup platform ABI, ISA and Code Model # Setup platform ABI, ISA and Code Model
@@ -137,14 +157,16 @@ ifndef PLATFORM_RISCV_CODE_MODEL
endif endif
# Setup compilation commands flags # Setup compilation commands flags
GENFLAGS = -I$(platform_dir)/include GENFLAGS = -I$(platform_src_dir)/include
GENFLAGS += -I$(platform_common_dir)/include
GENFLAGS += -I$(include_dir) GENFLAGS += -I$(include_dir)
GENFLAGS += $(platform-common-genflags-y) ifneq ($(OPENSBI_VERSION_GIT),)
GENFLAGS += -DOPENSBI_VERSION_GIT="\"$(OPENSBI_VERSION_GIT)\""
endif
GENFLAGS += $(libsbiutils-genflags-y)
GENFLAGS += $(platform-genflags-y) GENFLAGS += $(platform-genflags-y)
GENFLAGS += $(firmware-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 += -fno-omit-frame-pointer -fno-optimize-sibling-calls
CFLAGS += -mno-save-restore -mstrict-align CFLAGS += -mno-save-restore -mstrict-align
CFLAGS += -mabi=$(PLATFORM_RISCV_ABI) -march=$(PLATFORM_RISCV_ISA) CFLAGS += -mabi=$(PLATFORM_RISCV_ABI) -march=$(PLATFORM_RISCV_ISA)
@@ -152,6 +174,7 @@ CFLAGS += -mcmodel=$(PLATFORM_RISCV_CODE_MODEL)
CFLAGS += $(GENFLAGS) CFLAGS += $(GENFLAGS)
CFLAGS += $(platform-cflags-y) CFLAGS += $(platform-cflags-y)
CFLAGS += $(firmware-cflags-y) CFLAGS += $(firmware-cflags-y)
CFLAGS += -fno-pie -no-pie
CPPFLAGS += $(GENFLAGS) CPPFLAGS += $(GENFLAGS)
CPPFLAGS += $(platform-cppflags-y) CPPFLAGS += $(platform-cppflags-y)
@@ -213,7 +236,7 @@ compile_cpp = $(CMD_PREFIX)mkdir -p `dirname $(1)`; \
$(CPP) $(CPPFLAGS) -x c $(2) | grep -v "\#" > $(1) $(CPP) $(CPPFLAGS) -x c $(2) | grep -v "\#" > $(1)
compile_cc_dep = $(CMD_PREFIX)mkdir -p `dirname $(1)`; \ compile_cc_dep = $(CMD_PREFIX)mkdir -p `dirname $(1)`; \
echo " CC-DEP $(subst $(build_dir)/,,$(1))"; \ echo " CC-DEP $(subst $(build_dir)/,,$(1))"; \
echo `dirname $(1)`/ \\ > $(1) && \ printf %s `dirname $(1)`/ > $(1) && \
$(CC) $(CFLAGS) $(call dynamic_flags,$(1),$(2)) \ $(CC) $(CFLAGS) $(call dynamic_flags,$(1),$(2)) \
-MM $(2) >> $(1) || rm -f $(1) -MM $(2) >> $(1) || rm -f $(1)
compile_cc = $(CMD_PREFIX)mkdir -p `dirname $(1)`; \ compile_cc = $(CMD_PREFIX)mkdir -p `dirname $(1)`; \
@@ -221,7 +244,7 @@ compile_cc = $(CMD_PREFIX)mkdir -p `dirname $(1)`; \
$(CC) $(CFLAGS) $(call dynamic_flags,$(1),$(2)) -c $(2) -o $(1) $(CC) $(CFLAGS) $(call dynamic_flags,$(1),$(2)) -c $(2) -o $(1)
compile_as_dep = $(CMD_PREFIX)mkdir -p `dirname $(1)`; \ compile_as_dep = $(CMD_PREFIX)mkdir -p `dirname $(1)`; \
echo " AS-DEP $(subst $(build_dir)/,,$(1))"; \ echo " AS-DEP $(subst $(build_dir)/,,$(1))"; \
echo `dirname $(1)`/ \\ > $(1) && \ printf %s `dirname $(1)`/ > $(1) && \
$(AS) $(ASFLAGS) $(call dynamic_flags,$(1),$(2)) \ $(AS) $(ASFLAGS) $(call dynamic_flags,$(1),$(2)) \
-MM $(2) >> $(1) || rm -f $(1) -MM $(2) >> $(1) || rm -f $(1)
compile_as = $(CMD_PREFIX)mkdir -p `dirname $(1)`; \ compile_as = $(CMD_PREFIX)mkdir -p `dirname $(1)`; \
@@ -241,8 +264,9 @@ compile_dts = $(CMD_PREFIX)mkdir -p `dirname $(1)`; \
$(DTC) $(DTCFLAGS) -o $(1) $(2) $(DTC) $(DTCFLAGS) -o $(1) $(2)
targets-y = $(build_dir)/lib/libsbi.a targets-y = $(build_dir)/lib/libsbi.a
targets-y += $(build_dir)/lib/libsbiutils.a
ifdef PLATFORM ifdef PLATFORM
targets-y += $(build_dir)/$(platform_subdir)/lib/libplatsbi.a targets-y += $(platform_build_dir)/lib/libplatsbi.a
targets-y += $(platform-dtb-path-y) targets-y += $(platform-dtb-path-y)
endif endif
targets-y += $(firmware-bins-path-y) targets-y += $(firmware-bins-path-y)
@@ -257,16 +281,19 @@ all: $(targets-y)
$(build_dir)/%.bin: $(build_dir)/%.elf $(build_dir)/%.bin: $(build_dir)/%.elf
$(call compile_objcopy,$@,$<) $(call compile_objcopy,$@,$<)
$(build_dir)/%.elf: $(build_dir)/%.o $(build_dir)/%.elf.ld $(build_dir)/$(platform_subdir)/lib/libplatsbi.a $(build_dir)/%.elf: $(build_dir)/%.o $(build_dir)/%.elf.ld $(platform_build_dir)/lib/libplatsbi.a
$(call compile_elf,$@,$@.ld,$< $(build_dir)/$(platform_subdir)/lib/libplatsbi.a) $(call compile_elf,$@,$@.ld,$< $(platform_build_dir)/lib/libplatsbi.a)
$(build_dir)/$(platform_subdir)/%.ld: $(src_dir)/%.ldS $(platform_build_dir)/%.ld: $(src_dir)/%.ldS
$(call compile_cpp,$@,$<) $(call compile_cpp,$@,$<)
$(build_dir)/lib/libsbi.a: $(lib-objs-path-y) $(build_dir)/lib/libsbi.a: $(libsbi-objs-path-y)
$(call compile_ar,$@,$^) $(call compile_ar,$@,$^)
$(build_dir)/$(platform_subdir)/lib/libplatsbi.a: $(lib-objs-path-y) $(platform-common-objs-path-y) $(platform-objs-path-y) $(build_dir)/lib/libsbiutils.a: $(libsbi-objs-path-y) $(libsbiutils-objs-path-y)
$(call compile_ar,$@,$^)
$(platform_build_dir)/lib/libplatsbi.a: $(libsbi-objs-path-y) $(libsbiutils-objs-path-y) $(platform-objs-path-y)
$(call compile_ar,$@,$^) $(call compile_ar,$@,$^)
$(build_dir)/%.dep: $(src_dir)/%.c $(build_dir)/%.dep: $(src_dir)/%.c
@@ -281,16 +308,28 @@ $(build_dir)/%.dep: $(src_dir)/%.S
$(build_dir)/%.o: $(src_dir)/%.S $(build_dir)/%.o: $(src_dir)/%.S
$(call compile_as,$@,$<) $(call compile_as,$@,$<)
$(build_dir)/$(platform_subdir)/%.dep: $(src_dir)/%.c $(platform_build_dir)/%.dep: $(platform_src_dir)/%.c
$(call compile_cc_dep,$@,$<) $(call compile_cc_dep,$@,$<)
$(build_dir)/$(platform_subdir)/%.o: $(src_dir)/%.c $(platform_build_dir)/%.o: $(platform_src_dir)/%.c
$(call compile_cc,$@,$<) $(call compile_cc,$@,$<)
$(build_dir)/$(platform_subdir)/%.dep: $(src_dir)/%.S $(platform_build_dir)/%.dep: $(platform_src_dir)/%.S
$(call compile_as_dep,$@,$<) $(call compile_as_dep,$@,$<)
$(build_dir)/$(platform_subdir)/%.o: $(src_dir)/%.S $(platform_build_dir)/%.o: $(platform_src_dir)/%.S
$(call compile_as,$@,$<)
$(platform_build_dir)/%.dep: $(src_dir)/%.c
$(call compile_cc_dep,$@,$<)
$(platform_build_dir)/%.o: $(src_dir)/%.c
$(call compile_cc,$@,$<)
$(platform_build_dir)/%.dep: $(src_dir)/%.S
$(call compile_as_dep,$@,$<)
$(platform_build_dir)/%.o: $(src_dir)/%.S
$(call compile_as,$@,$<) $(call compile_as,$@,$<)
$(build_dir)/%.dtb: $(src_dir)/%.dts $(build_dir)/%.dtb: $(src_dir)/%.dts
@@ -325,7 +364,7 @@ ifneq ($(platform-runcmd),)
$(platform-runcmd) $(RUN_ARGS) $(platform-runcmd) $(RUN_ARGS)
else else
ifdef PLATFORM ifdef PLATFORM
@echo Platform $(PLATFORM) doesn't specify a run command @echo "Platform $(PLATFORM) doesn't specify a run command"
@false @false
else else
@echo Run command only available when targeting a platform @echo Run command only available when targeting a platform
@@ -334,6 +373,7 @@ endif
endif endif
install_targets-y = install_libsbi install_targets-y = install_libsbi
install_targets-y += install_libsbiutils
ifdef PLATFORM ifdef PLATFORM
install_targets-y += install_libplatsbi install_targets-y += install_libplatsbi
install_targets-y += install_firmwares install_targets-y += install_firmwares
@@ -348,14 +388,19 @@ install_libsbi: $(build_dir)/lib/libsbi.a
$(call inst_header_dir,$(install_dir)/include,$(include_dir)/sbi) $(call inst_header_dir,$(install_dir)/include,$(include_dir)/sbi)
$(call inst_file,$(install_dir)/lib/libsbi.a,$(build_dir)/lib/libsbi.a) $(call inst_file,$(install_dir)/lib/libsbi.a,$(build_dir)/lib/libsbi.a)
.PHONY: install_libsbiutils
install_libsbiutils: $(build_dir)/lib/libsbiutils.a
$(call inst_header_dir,$(install_dir)/include,$(include_dir)/sbi_utils)
$(call inst_file,$(install_dir)/lib/libsbiutils.a,$(build_dir)/lib/libsbiutils.a)
.PHONY: install_libplatsbi .PHONY: install_libplatsbi
install_libplatsbi: $(build_dir)/$(platform_subdir)/lib/libplatsbi.a $(build_dir)/lib/libsbi.a install_libplatsbi: $(platform_build_dir)/lib/libplatsbi.a $(build_dir)/lib/libsbi.a $(build_dir)/lib/libsbiutils.a
$(call inst_file,$(install_dir)/$(platform_subdir)/lib/libplatsbi.a,$(build_dir)/$(platform_subdir)/lib/libplatsbi.a) $(call inst_file,$(install_dir)/platform/$(platform_subdir)/lib/libplatsbi.a,$(platform_build_dir)/lib/libplatsbi.a)
.PHONY: install_firmwares .PHONY: install_firmwares
install_firmwares: $(build_dir)/$(platform_subdir)/lib/libplatsbi.a $(build_dir)/lib/libsbi.a $(firmware-bins-path-y) install_firmwares: $(platform_build_dir)/lib/libplatsbi.a $(build_dir)/lib/libsbi.a $(build_dir)/lib/libsbiutils.a $(firmware-bins-path-y)
$(call inst_file_list,$(install_dir),$(build_dir),$(platform_subdir)/firmware,$(firmware-elfs-path-y)) $(call inst_file_list,$(install_dir),$(build_dir),platform/$(platform_subdir)/firmware,$(firmware-elfs-path-y))
$(call inst_file_list,$(install_dir),$(build_dir),$(platform_subdir)/firmware,$(firmware-bins-path-y)) $(call inst_file_list,$(install_dir),$(build_dir),platform/$(platform_subdir)/firmware,$(firmware-bins-path-y))
.PHONY: install_docs .PHONY: install_docs
install_docs: $(build_dir)/docs/latex/refman.pdf install_docs: $(build_dir)/docs/latex/refman.pdf

135
README.md
View File

@@ -1,56 +1,61 @@
Copyright (c) 2019 Western Digital Corporation or its affiliates
and other contributors.
RISC-V Open Source Supervisor Binary Interface (OpenSBI) RISC-V Open Source Supervisor Binary Interface (OpenSBI)
======================================================== ========================================================
The **RISC-V Supervisor Binary Interface (SBI)** is the recommended interface The **RISC-V Supervisor Binary Interface (SBI)** is the recommended interface
between: between:
1. A platform specific firmware running in M-mode and bootloader, hypervisor or 1. A platform-specific firmware running in M-mode and a bootloader, a
a general purpose OS executing in S-mode or HS-mode. hypervisor or a general-purpose OS executing in S-mode or HS-mode.
2. A hypervisor running in HS-mode and a bootloader or a general purpose OS 2. A hypervisor running in HS-mode and a bootloader or a general-purpose OS
executing in VS-mode. executing in VS-mode.
The *RISC-V SBI specification* is maintained as an independent project by the The *RISC-V SBI specification* is maintained as an independent project by the
RISC-V Foundation in [Github]. RISC-V Foundation on [Github] (https://github.com/riscv/riscv-sbi-doc).
The goal of the OpenSBI project is to provide an open-source reference The goal of the OpenSBI project is to provide an open-source reference
implementation of the RISC-V SBI specifications for platform specific firmwares implementation of the RISC-V SBI specifications for platform-specific firmwares
executing in M-mode (case 1 mentioned above). OpenSBI implementation can be executing in M-mode (case 1 mentioned above). An OpenSBI implementation can be
easily extended by RISC-V platform and system-on-chip vendors to fit a easily extended by RISC-V platform and system-on-chip vendors to fit a
particular hardware configuration. particular hardware configuration.
The main component of OpenSBI is provided in the form of a platform independent The main component of OpenSBI is provided in the form of a platform-independent
static library **libsbi.a** implementing the SBI interface. A firmware or static library **libsbi.a** implementing the SBI interface. A firmware or
bootloader implementation can link against this library to ensure conformance bootloader implementation can link against this library to ensure conformance
with the SBI interface specifications. *libsbi.a* also defines an interface for with the SBI interface specifications. *libsbi.a* also defines an interface for
integrating with platform specific operations provided by the platform firmware integrating with platform-specific operations provided by the platform firmware
implementation (e.g. console access functions, inter-processor interrupts implementation (e.g. console access functions, inter-processor interrupt
control, etc). control, etc).
To illustrate the use of *libsbi.a* library, OpenSBI also provides a set of To illustrate the use of the *libsbi.a* library, OpenSBI also provides a set of
platform specific support examples. For each example, a platform platform-specific support examples. For each example, a platform-specific
specific static library *libplatsbi.a* can be compiled. This library implements static library *libplatsbi.a* can be compiled. This library implements
SBI calls processing by integrating *libsbi.a* with necessary platform dependent SBI call processing by integrating *libsbi.a* with the necessary
hardware manipulation functions. For all supported platforms, OpenSBI also platform-dependent hardware manipulation functions. For all supported platforms,
provides several runtime firmware examples built using the platform OpenSBI also provides several runtime firmware examples built using the platform
*libplatsbi.a*. These example firmwares can be used to replace the legacy *libplatsbi.a*. These example firmwares can be used to replace the legacy
*riskv-pk* bootloader (aka BBL) and enable the use of well known bootloaders *riscv-pk* bootloader (aka BBL) and enable the use of well-known bootloaders
such as [U-Boot]. such as [U-Boot] (https://git.denx.de/u-boot.git).
Required Toolchain Required Toolchain
------------------ ------------------
OpenSBI can be compiled natively or cross-compiled on a x86 host. For OpenSBI can be compiled natively or cross-compiled on a x86 host. For
cross-compilation, you can build your tool chain or just download from cross-compilation, you can build your own toolchain or just download
the [bootlin] (https://toolchains.bootlin.com/). a prebuilt one from the
[Bootlin toolchain repository] (https://toolchains.bootlin.com/).
Please note that only 64bit version of toolchain is available in bootlin Please note that only a 64-bit version of the toolchain is available in
for now. the Bootlin toolchain repository for now.
Building and Installing OpenSBI Platform Independent Library Building and Installing the OpenSBI Platform-Independent Library
------------------------------------------------------------ ----------------------------------------------------------------
OpenSBI platform independent static library *libsbi.a* can be natively compiled The OpenSBI platform-independent static library *libsbi.a* can be compiled
or cross-compiled on a host with a different base architecture than RISC-V. natively or it can be cross-compiled on a host with a different base
architecture than RISC-V.
For cross-compiling, the environment variable *CROSS_COMPILE* must be defined For cross-compiling, the environment variable *CROSS_COMPILE* must be defined
to specify the name prefix of the RISC-V compiler toolchain executables, e.g. to specify the name prefix of the RISC-V compiler toolchain executables, e.g.
@@ -61,8 +66,8 @@ To build *libsbi.a* simply execute:
make make
``` ```
All compiled binaries as well as the result *libsbi.a* static library file will All compiled binaries as well as the resulting *libsbi.a* static library file
be placed in the *build/lib* directory. To specify an alternate build root will be placed in the *build/lib* directory. To specify an alternate build root
directory path, run: directory path, run:
``` ```
make O=<build_directory> make O=<build_directory>
@@ -74,38 +79,38 @@ make install
``` ```
This will create the *install* directory with all necessary include files This will create the *install* directory with all necessary include files
copied under the *install/include* directory and library file copied in the copied under the *install/include* directory and the library file copied into
*install/lib* directory. To specify an alternate installation root directory the *install/lib* directory. To specify an alternate installation root
path, run: directory path, run:
``` ```
make I=<install_directory> install make I=<install_directory> install
``` ```
Building and Installing a Reference Platform Static Library and Firmwares Building and Installing a Reference Platform Static Library and Firmware
------------------------------------------------------------------------- ------------------------------------------------------------------------
When the *PLATFORM=<platform_subdir>* argument is specified on the make command When the *PLATFORM=<platform_subdir>* argument is specified on the make command
line, the platform specific static library *libplatsbi.a* and firmware examples line, the platform-specific static library *libplatsbi.a* and firmware examples
are built for the platform *<platform_subdir>* present in the directory are built for the platform *<platform_subdir>* present in the directory
*platform* in OpenSBI top directory. For example, to compile the platform *platform* in the OpenSBI top directory. For example, to compile the platform
library and firmware examples for QEMU RISC-V *virt* machine, library and the firmware examples for the QEMU RISC-V *virt* machine,
*<platform_subdir>* should be *qemu/virt*. *<platform_subdir>* should be *qemu/virt*.
To build *libsbi.a*, *libplatsbi.a* and the firmwares for one of the supported To build *libsbi.a*, *libplatsbi.a* and the firmware for one of the supported
platform, run: platforms, run:
``` ```
make PLATFORM=<platform_subdir> make PLATFORM=<platform_subdir>
``` ```
An alternate build directory path can also be specified. An alternate build directory path can also be specified:
``` ```
make PLATFORM=<platform_subdir> O=<build_directory> make PLATFORM=<platform_subdir> O=<build_directory>
``` ```
The platform specific library *libplatsbi.a* will be generated in the The platform-specific library *libplatsbi.a* will be generated in the
*build/platform/<platform_subdir>/lib* directory. The platform firmware files *build/platform/<platform_subdir>/lib* directory. The platform firmware files
will be under the *build/platform/<platform_subdir>/firmware* directory. will be under the *build/platform/<platform_subdir>/firmware* directory.
The compiled firmwares will be available in two different format: an ELF file The compiled firmwares will be available in two different formats: an ELF file
and an expanded image file. and an expanded image file.
To install *libsbi.a*, *libplatsbi.a*, and the compiled firmwares, run: To install *libsbi.a*, *libplatsbi.a*, and the compiled firmwares, run:
@@ -113,19 +118,38 @@ To install *libsbi.a*, *libplatsbi.a*, and the compiled firmwares, run:
make PLATFORM=<platform_subdir> install make PLATFORM=<platform_subdir> install
``` ```
This will copy the compiled platform specific libraries and firmware files This will copy the compiled platform-specific libraries and firmware files
under the *install/platform/<platform_subdir>/* directory. An alternate under the *install/platform/<platform_subdir>/* directory. An alternate
install root directory path can be specified as follows. install root directory path can be specified as follows:
``` ```
make PLATFORM=<platform_subdir> I=<install_directory> install make PLATFORM=<platform_subdir> I=<install_directory> install
``` ```
In addition, platform specific configuration options can be specified with the In addition, platform-specific configuration options can be specified with the
top-level make command line. These options, such as *PLATFORM_<xyz>* or top-level make command line. These options, such as *PLATFORM_<xyz>* or
*FW_<abc>*, are platform specific and described in more details in the *FW_<abc>*, are platform-specific and described in more details in the
*docs/platform/<platform_name>.md* files and *docs/platform/<platform_name>.md* files and
*docs/firmware/<firmware_name>.md* files. *docs/firmware/<firmware_name>.md* files.
Building 32-bit / 64-bit OpenSBI Images
---------------------------------------
By default, building OpenSBI generates 32-bit or 64-bit images based on the
supplied RISC-V cross-compile toolchain. For example if *CROSS_COMPILE* is set
to *riscv64-unknown-elf-*, 64-bit OpenSBI images will be generated. If building
32-bit OpenSBI images, *CROSS_COMPILE* should be set to a toolchain that is
pre-configured to generate 32-bit RISC-V codes, like *riscv32-unknown-elf-*.
However it's possible to explicitly specify the image bits we want to build with
a given RISC-V toolchain. This can be done by setting the environment variable
*PLATFORM_RISCV_XLEN* to the desired width, for example:
```
export CROSS_COMPILE=riscv64-unknown-elf-
export PLATFORM_RISCV_XLEN=32
```
will generate 32-bit OpenSBI images. And vice vesa.
License License
------- -------
@@ -148,18 +172,23 @@ OpenSBI source code also contains code reused from other projects as listed
below. The original license text of these projects is included in the source below. The original license text of these projects is included in the source
files where the reused code is present. files where the reused code is present.
1. The libfdt source code is disjunctively dual licensed * The libfdt source code is disjunctively dual licensed
(GPL-2.0+ OR BSD-2-Clause). Some of this project code is used in OpenSBI (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. Any contributions to this under the terms of the BSD 2-Clause license. Any contributions to this
code must be made under the terms of both licenses. code must be made under the terms of both licenses.
See also the [third party notices] file for more information.
Contributing to OpenSBI Contributing to OpenSBI
----------------------- -----------------------
The OpenSBI project encourages and welcomes contributions. Contributions should The OpenSBI project encourages and welcomes contributions. Contributions should
follow the rules described in OpenSBI [Contribution Guideline] document. follow the rules described in the OpenSBI [Contribution Guideline] document.
In particular, all patches sent should contain a Signed-off-by tag. In particular, all patches sent should contain a Signed-off-by tag.
The [Contributors List] document provides a list of individuals and
organizations actively contributing to the OpenSBI project.
Documentation Documentation
------------- -------------
@@ -174,7 +203,7 @@ Detailed documentation of various aspects of OpenSBI can be found under the
examples build supported by OpenSBI. examples build supported by OpenSBI.
OpenSBI source code is also well documented. For source level documentation, OpenSBI source code is also well documented. For source level documentation,
doxygen style is used. Please refer to [Doxygen manual] for details on this doxygen style is used. Please refer to the [Doxygen manual] for details on this
format. format.
Doxygen can be installed on Linux distributions using *.deb* packages using Doxygen can be installed on Linux distributions using *.deb* packages using
@@ -218,9 +247,11 @@ make I=<install_directory> install_docs
[COPYING.BSD]: COPYING.BSD [COPYING.BSD]: COPYING.BSD
[SPDX]: http://spdx.org/licenses/ [SPDX]: http://spdx.org/licenses/
[Contribution Guideline]: docs/contributing.md [Contribution Guideline]: docs/contributing.md
[Contributors List]: CONTRIBUTORS.md
[Library Usage]: docs/library_usage.md [Library Usage]: docs/library_usage.md
[Platform Support Guide]: docs/platform_guide.md [Platform Support Guide]: docs/platform_guide.md
[Platform Documentation]: docs/platform/platform.md [Platform Documentation]: docs/platform/platform.md
[Firmware Documentation]: docs/firmware/fw.md [Firmware Documentation]: docs/firmware/fw.md
[Doxygen manual]: http://www.stack.nl/~dimitri/doxygen/manual.html [Doxygen manual]: http://www.doxygen.nl/manual/index.html
[Kendryte standalone SDK]: https://github.com/kendryte/kendryte-standalone-sdk
[third party notices]: ThirdPartyNotices.md

18
ThirdPartyNotices.md Normal file
View File

@@ -0,0 +1,18 @@
Copyright (c) 2019 Western Digital Corporation or its affiliates.
Third Party Notices
===================
This project includes or partly uses code from the following open source
software subject to the following open source licenses.
libfdt
------
Copyright (C) 2016 Free Electrons
Copyright (C) 2016 NextThing Co.
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,11 +1,20 @@
OpenSBI Contribution Guideline OpenSBI Contribution Guideline
============================== ==============================
All contributions to OpenSBI should be sent as GitHub Pull Requests (PRs) to All contributions to OpenSBI can be sent in the following ways:
[OpenSBI main repository]. 1. Email patches to the OpenSBI mailing list at `opensbi@lists.infradead.org`
2. GitHub Pull Requests (PRs) to the [OpenSBI main repository]
To join the OpenSBI mailing list, please visit the [OpenSBI infradead page].
The OpenSBI maintainers prefer patches via the OpenSBI mailing list
(option 1 above) so that they are visible to a wider audience. All
accepted patches on the OpenSBI mailing list will be taken by any of
the OpenSBI maintainers and merged into the [OpenSBI main repository]
using GitHub PRs.
All contributed work must follow the following rules: All contributed work must follow the following rules:
1. OpenSBI code should be written in accordance to [Linux coding style]. 1. OpenSBI code should be written in accordance to the [Linux coding style].
2. This project embraces the [Developer Certificate of Origin (DCO)] for 2. This project embraces the [Developer Certificate of Origin (DCO)] for
contributions. This means that you must agree to the following prior to contributions. This means that you must agree to the following prior to
submitting patches: if you agree with this developer certificate you submitting patches: if you agree with this developer certificate you
@@ -15,13 +24,14 @@ Every submitted patch must have this tag.
followed by a description of the patch content. A blank line and the author followed by a description of the patch content. A blank line and the author
Signed-off-by tag must follow this description. Signed-off-by tag must follow this description.
4. A commit subject line must start with a prefix followed by a ":". Common 4. A commit subject line must start with a prefix followed by a ":". Common
prefixes are for example "lib:", "platform:", "firmware:", "docs:" and "top:". prefixes are for example "lib:", "platform:", "firmware:", "docs:", "utils:"
and "top:".
5. Maintainers should use "Rebase and Merge" when using GitHub to merge pull 5. Maintainers should use "Rebase and Merge" when using GitHub to merge pull
requests to avoid creating unnecessary merge commits. requests to avoid creating unnecessary merge commits.
6. Maintainers should avoid creating branches directly in the main 6. Maintainers should avoid creating branches directly in the main
riscv/opensbi repository. Instead prefer using a fork of riscv/opensbi main riscv/opensbi repository. Instead prefer using a fork of the riscv/opensbi main
repository and branches within that fork to create pull requests. repository and branches within that fork to create pull requests.
7. A maintainer cannot merge his own pull requests in riscv/opensbi main 7. A maintainer cannot merge his own pull requests in the riscv/opensbi main
repository. repository.
8. A pull request must get at least one review from a maintainer. 8. A pull request must get at least one review from a maintainer.
9. A pull request must spend at least 24 hours in review to allow for other 9. A pull request must spend at least 24 hours in review to allow for other
@@ -69,6 +79,6 @@ By making a contribution to this project, I certify that:
----------------------------------------------------------------------- -----------------------------------------------------------------------
[OpenSBI main repository]: https://github.com/riscv/opensbi [OpenSBI main repository]: https://github.com/riscv/opensbi
[OpenSBI infradead page]: http://lists.infradead.org/mailman/listinfo/opensbi
[Linux coding style]: https://www.kernel.org/doc/html/v4.10/process/coding-style.html [Linux coding style]: https://www.kernel.org/doc/html/v4.10/process/coding-style.html
[Developer Certificate of Origin (DCO)]: http://developercertificate.org/ [Developer Certificate of Origin (DCO)]: http://developercertificate.org/

View File

@@ -44,7 +44,7 @@ PROJECT_NUMBER = "v@@OPENSBI_MAJOR@@.@@OPENSBI_MINOR@@"
# for a project that appears at the top of each page and should give viewer a # for a project that appears at the top of each page and should give viewer a
# quick idea about the purpose of the project. Keep the description short. # quick idea about the purpose of the project. Keep the description short.
PROJECT_BRIEF = "Open source implemenation of supervisor binary interface" PROJECT_BRIEF = "Open source implemenation of the supervisor binary interface"
# With the PROJECT_LOGO tag one can specify a logo or an icon that is included # With the PROJECT_LOGO tag one can specify a logo or an icon that is included
# in the documentation. The maximum height of the logo should not exceed 55 # in the documentation. The maximum height of the logo should not exceed 55

32
docs/external/coreboot.md vendored Normal file
View File

@@ -0,0 +1,32 @@
OpenSBI as coreboot payload
===========================
[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:
+-----------+
+------+ +------+ +------+ | BBL |
| MSEL |--->| ZSBL |--->| FSBL |--->| +-------+
+------+ +------+ +------+ | | linux |
+---+-------+
coreboot boot process:
+---------------------------------------------------------------------+
| coreboot |
+------+ +------+ | +-----------+ +----------+ +----------+ +-----------------------+
| MSEL |-->| ZSBL |-->| | bootblock |->| romstage |->| ramstage |->| payload ( OpenSBI) |
+------+ +------+ | +-----------+ +----------+ +----------+ | +-------+ |
| | | linux | |
+---------------------------------------------+-------------+-------+-+
```
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

@@ -9,12 +9,22 @@ OpenSBI generic library code. The supported firmwares type will differ in how
the arguments passed by the platform early boot stage are handled, as well as the arguments passed by the platform early boot stage are handled, as well as
how the boot stage following the firmware will be handled and executed. how the boot stage following the firmware will be handled and executed.
OpenSBI currently supports two different types of firmwares. OpenSBI currently supports three different types of firmwares.
Firmware with Dynamic Information (*FW_DYNAMIC*)
------------------------------------------------
The *FW_DYNAMIC* firmware gets information about the next booting stage entry,
e.g. a bootloader or an OS kernel, from previous booting stage at runtime.
A *FW_DYNAMIC* firmware is particularly useful when the booting stage executed
prior to OpenSBI firmware is capable of loading both the OpenSBI firmware
and the booting stage binary to follow OpenSBI firmware.
Firmware with Jump Address (*FW_JUMP*) Firmware with Jump Address (*FW_JUMP*)
-------------------------------------- --------------------------------------
The *FW_JUMP* firmware only handles the address of the next booting stage The *FW_JUMP* firmware assumes a fixed address of the next booting stage
entry, e.g. a bootloader or an OS kernel, without directly including the entry, e.g. a bootloader or an OS kernel, without directly including the
binary code for this next stage. binary code for this next stage.
@@ -48,14 +58,17 @@ configuration parameter.
loads OpenSBI firmware. loads OpenSBI firmware.
Additionally, each firmware type as a set of type specific configuration Additionally, each firmware type as a set of type specific configuration
parameters. Detailed information for each firmware type can be found in the parameters. Detailed information for each firmware type can be found in the
following documents. following documents.
* *[FW_DYNAMIC]*: The *Firmware with Dynamic Information (FW_DYNAMIC)* is
described in more details in the file *fw_dynamic.md*.
* *[FW_JUMP]*: The *Firmware with Jump Address (FW_JUMP)* is described in more * *[FW_JUMP]*: The *Firmware with Jump Address (FW_JUMP)* is described in more
details in the file *fw_jump.md*. details in the file *fw_jump.md*.
* *[FW_PAYLOAD]*: The *Firmware with Payload (FW_PAYLOAD)* is described in more * *[FW_PAYLOAD]*: The *Firmware with Payload (FW_PAYLOAD)* is described in more
details in the file *fw_payload.md*. details in the file *fw_payload.md*.
[FW_DYNAMIC]: fw_dynamic.md
[FW_JUMP]: fw_jump.md [FW_JUMP]: fw_jump.md
[FW_PAYLOAD]: fw_payload.md [FW_PAYLOAD]: fw_payload.md
@@ -75,3 +88,18 @@ make PLATFORM=<platform_subdir> FW_PAYLOAD_PATH=<payload path>
The instructions to build each payload is different and the details can The instructions to build each payload is different and the details can
be found in the be found in the
*docs/firmware/payload_<payload_name>.md* files. *docs/firmware/payload_<payload_name>.md* files.
Options for OpenSBI Firmware behaviors
--------------------------------------
An optional compile time flag FW_OPTIONS can be used to control the OpenSBI
firmware run-time behaviors.
```
make PLATFORM=<platform_subdir> FW_OPTIONS=<options>
```
FW_OPTIONS is a bitwise or'ed value of various options, eg: *FW_OPTIONS=0x1*
stands for disabling boot prints from the OpenSBI library.
For all supported options, please check "enum sbi_scratch_options" in the
*include/sbi/sbi_scratch.h* header file.

View File

@@ -0,0 +1,35 @@
OpenSBI Firmware with Dynamic Information *FW_DYNAMIC*
======================================================
OpenSBI **firmware with dynamic info (FW_DYNAMIC)** is a firmware which gets
information about next booting stage (e.g. a bootloader or an OS) and runtime
OpenSBI library options from previous booting stage.
The previous booting stage will pass information to *FW_DYNAMIC* by creating
*struct fw_dynamic_info* in memory and passing it's address to *FW_DYNAMIC*
via *a2* register of RISC-V CPU.
A *FW_DYNAMIC* firmware is particularly useful when the booting stage executed
prior to OpenSBI firmware is capable of loading both the OpenSBI firmware and
the booting stage binary to follow OpenSBI firmware.
*FW_DYNAMIC* Compilation
------------------------
A platform can enable *FW_DYNAMIC* firmware using any of the following methods.
1. Specifying `FW_DYNAMIC=y` on the top level `make` command line.
2. Specifying `FW_DYNAMIC=y` in the target platform *config.mk* configuration
file.
The compiled *FW_DYNAMIC* firmware ELF file is named *fw_dynamic.elf*. It's
expanded image file is *fw_dynamic.bin*. Both files are created in the platform
specific build directory under the *build/platform/<platform_subdir>/firmware*
directory.
*FW_DYNAMIC* Firmware Configuration Options
-------------------------------------------
The *FW_DYNAMIC* firmware does not requires any platform specific configuration
parameters because all required information is passed by previous booting stage
at runtime via *struct fw_dynamic_info*.

View File

@@ -6,19 +6,19 @@ handles the address of the next booting stage entry, e.g. a bootloader or an OS
kernel, without directly including the binary code for this next stage. kernel, without directly including the binary code for this next stage.
A *FW_JUMP* firmware is particularly useful when the booting stage executed A *FW_JUMP* firmware is particularly useful when the booting stage executed
prior to OpenSBI firmware is capable of loading both the OpenSBI firmware and prior to the OpenSBI firmware is capable of loading both the OpenSBI firmware
the booting stage binary to follow OpenSBI firmware. and the booting stage binary to follow the OpenSBI firmware.
*FW_JUMP* Compilation *FW_JUMP* Compilation
--------------------- ---------------------
A platform *FW_JUMP* firmware can be enabled by any of the following methods. A platform *FW_JUMP* firmware can be enabled by any of the following methods:
1. Specifying `FW_JUMP=y` on the top level `make` command line. 1. Specifying `FW_JUMP=y` on the top level `make` command line.
2. Specifying `FW_JUMP=y` in the target platform *config.mk* configuration file. 2. Specifying `FW_JUMP=y` in the target platform *config.mk* configuration file.
The compiled *FW_JUMP* firmware ELF file is named *fw_jump.elf*. Its expanded The compiled *FW_JUMP* firmware ELF file is named *fw_jump.elf*. Its expanded
image file is *fw_jump.bin*. Both files are created in the platform specific image file is *fw_jump.bin*. Both files are created in the platform-specific
build directory under the *build/platform/<platform_subdir>/firmware* directory. build directory under the *build/platform/<platform_subdir>/firmware* directory.
*FW_JUMP* Firmware Configuration Options *FW_JUMP* Firmware Configuration Options
@@ -27,26 +27,25 @@ build directory under the *build/platform/<platform_subdir>/firmware* directory.
To operate correctly, a *FW_JUMP* firmware requires some configuration To operate correctly, a *FW_JUMP* firmware requires some configuration
parameters to be defined using either the top level `make` command line or the parameters to be defined using either the top level `make` command line or the
target platform *config.mk* configuration file. The possible parameters are as target platform *config.mk* configuration file. The possible parameters are as
follows. follows:
* **FW_JUMP_ADDR** - Address of the entry point of the booting stage to be * **FW_JUMP_ADDR** - Address of the entry point of the booting stage to be
executed following OpenSBI firmware. This address generally correspond executed following OpenSBI firmware. This address generally corresponds
exactly to the address where this next booting stage was loaded. This is a exactly to the address where this next booting stage was loaded. This is a
mandatory parameter. Compilation errors will result from not defining this mandatory parameter. Compilation errors will result from not defining this
address. address.
* **FW_JUMP_FDT_ADDR** - Address where the *flattened device tree (FDT file)* * **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 passed by the prior booting stage will be placed in memory before executing
the booting stage following OpenSBI firmware. If this option is not provided, the booting stage following the OpenSBI firmware. If this option is not
then OpenSBI firmware will pass zero as the FDT address to the following provided, then the OpenSBI firmware will pass the FDT address passed by the
booting stage. previous booting stage to the next booting stage.
*FW_JUMP* Example *FW_JUMP* Example
----------------- -----------------
The *[qemu/virt]* and *[qemu/sifive_u]* platforms illustrates how to configure The *[qemu/virt]* platform illustrates how to configure and use a *FW_JUMP*
and use a *FW_JUMP* firmware. Detailed information regarding these platforms firmware. Detailed information regarding these platforms can be found in the
can be found in the platforms documentation files. platform documentation files.
[qemu/virt]: ../platform/qemu_virt.md [qemu/virt]: ../platform/qemu_virt.md
[qemu/sifive_u]: ../platform/qemu_sifive_u.md

View File

@@ -2,22 +2,22 @@ OpenSBI Firmware with Payload *FW_PAYLOAD*
========================================== ==========================================
OpenSBI **firmware with Payload (FW_PAYLOAD)** is a firmware which directly OpenSBI **firmware with Payload (FW_PAYLOAD)** is a firmware which directly
includes the binary for the booting stage to follow OpenSBI firmware execution. includes the binary for the booting stage to follow the OpenSBI firmware
Typically, this payload will be a bootloader or an OS kernel. execution. Typically, this payload will be a bootloader or an OS kernel.
A *FW_PAYLOAD* firmware is particularly useful when the booting stage executed A *FW_PAYLOAD* firmware is particularly useful when the booting stage executed
prior to OpenSBI firmware is not capable of loading both OpenSBI firmware and prior to the OpenSBI firmware is not capable of loading both the OpenSBI
the booting stage to follow OpenSBI firmware. firmware and the booting stage to follow OpenSBI firmware.
A *FW_PAYLOAD* firmware is also useful for cases where the booting stage prior A *FW_PAYLOAD* firmware is also useful for cases where the booting stage prior
to OpenSBI firmware does not pass a *flattened device tree (FDT file)*. In such to the OpenSBI firmware does not pass a *flattened device tree (FDT file)*. In
case, a *FW_PAYLOAD* firmware allows embedding a flattened device tree in the such a case, a *FW_PAYLOAD* firmware allows embedding a flattened device tree
.text section of the final firmware. in the .text section of the final firmware.
Enabling *FW_PAYLOAD* compilation Enabling *FW_PAYLOAD* compilation
--------------------------------- ---------------------------------
The *FW_PAYLOAD* firmware can be enabled by any of the following methods. The *FW_PAYLOAD* firmware can be enabled by any of the following methods:
1. Specifying `FW_PAYLOAD=y` on the top level `make` command line. 1. Specifying `FW_PAYLOAD=y` on the top level `make` command line.
2. Specifying `FW_PAYLOAD=y` in the target platform *config.mk* configuration 2. Specifying `FW_PAYLOAD=y` in the target platform *config.mk* configuration
@@ -25,7 +25,7 @@ The *FW_PAYLOAD* firmware can be enabled by any of the following methods.
The compiled *FW_PAYLOAD* firmware ELF file is named *fw_jump.elf*. Its The compiled *FW_PAYLOAD* firmware ELF file is named *fw_jump.elf*. Its
expanded image file is *fw_payload.bin*. Both files are created in the expanded image file is *fw_payload.bin*. Both files are created in the
platform specific build directory under the platform-specific build directory under the
*build/platform/<platform_subdir>/firmware* directory. *build/platform/<platform_subdir>/firmware* directory.
Configuration Options Configuration Options
@@ -34,7 +34,7 @@ Configuration Options
A *FW_PAYLOAD* firmware is built according to configuration parameters and A *FW_PAYLOAD* firmware is built according to configuration parameters and
options. These configuration parameters can be defined using either the top options. These configuration parameters can be defined using either the top
level `make` command line or the target platform *config.mk* configuration level `make` command line or the target platform *config.mk* configuration
file. The parameters currently defined are as follows. file. The parameters currently defined are as follows:
* **FW_PAYLOAD_OFFSET** - Offset from *FW_TEXT_BASE* where the payload binary * **FW_PAYLOAD_OFFSET** - Offset from *FW_TEXT_BASE* where the payload binary
will be linked in the final *FW_PAYLOAD* firmware binary image. This will be linked in the final *FW_PAYLOAD* firmware binary image. This
@@ -47,8 +47,8 @@ file. The parameters currently defined are as follows.
will be linked after the end of the base firmware binary in the final will be linked after the end of the base firmware binary in the final
*FW_PAYLOAD* firmware binary image. This configuration parameter is mandatory *FW_PAYLOAD* firmware binary image. This configuration parameter is mandatory
if *FW_PAYLOAD_OFFSET* is not defined. If both *FW_PAYLOAD_OFFSET* and if *FW_PAYLOAD_OFFSET* is not defined. If both *FW_PAYLOAD_OFFSET* and
*FW_PAYLOAD_ALIGN* are defined, *FW_PAYLOAD_OFFSET* is used and *FW_PAYLOAD_ALIGN* are defined, *FW_PAYLOAD_OFFSET* is used and
*FW_PAYLOAD_ALIGN* ignored. *FW_PAYLOAD_ALIGN* is ignored.
* **FW_PAYLOAD_PATH** - Path to the image file of the next booting stage * **FW_PAYLOAD_PATH** - Path to the image file of the next booting stage
binary. If this option is not provided then a simple test payload is binary. If this option is not provided then a simple test payload is
@@ -73,18 +73,17 @@ file. The parameters currently defined are as follows.
stage or specified by the *FW_PAYLOAD_FDT_PATH* parameter and embedded in 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, 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 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 *FW_PAYLOAD* Example
-------------------- --------------------
The *[qemu/virt]* and *[qemu/sifive_u]* platforms illustrates how to configure The *[qemu/virt]* platforms illustrate how to configure and use a *FW_PAYLOAD*
and use a *FW_PAYLOAD* firmware. Detailed information regarding these platforms firmware. Detailed information regarding these platforms can be found in the
can be found in the platforms documentation files. platform documentation files.
The *kendryte/k210* platform also enables build of a *FW_PAYLOAD* using an The *kendryte/k210* platform also enables a build of a *FW_PAYLOAD* using an
internally defined device tree file (*FW_PAYLOAD_FDT*). internally defined device tree file (*FW_PAYLOAD_FDT*).
[qemu/virt]: ../platform/qemu_virt.md [qemu/virt]: ../platform/qemu_virt.md
[qemu/sifive_u]: ../platform/qemu_sifive_u.md

View File

@@ -1,11 +1,9 @@
Linux as a direct payload to OpenSBI Linux as a direct payload to OpenSBI
==================================== ====================================
OpenSBI has the capability to load Linux kernel image directly in supervisor OpenSBI has the capability to load a Linux kernel image directly in supervisor
mode. The flattened image generated by the Linux kernel build process can be mode. The flattened image generated by the Linux kernel build process can be
provided as payload to OpenSBI. provided as a payload to OpenSBI.
Detailed examples and platform guides can be found in both [QEMU](
../platform/qemu_virt.md) and [HiFive Unleashed](../platform/sifive_fu540.md)
platform guide respectively.
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

@@ -3,31 +3,33 @@ U-Boot as a payload to OpenSBI
[U-Boot](https://www.denx.de/wiki/U-Boot) is an open-source primary boot loader. [U-Boot](https://www.denx.de/wiki/U-Boot) is an open-source primary boot loader.
It can be used as first and/or second stage boot loader in an embedded It can be used as first and/or second stage boot loader in an embedded
environment. In the context of OpenSBI, U-boot can be specified as a payload to environment. In the context of OpenSBI, U-Boot can be specified as a payload to
OpenSBI firmware, becoming the boot stage following OpenSBI firmware the OpenSBI firmware, becoming the boot stage following the OpenSBI firmware
execution. execution.
The current stable upstream code of U-boot does not yet include all patches The current stable upstream code of U-Boot does not yet include all patches
necessary to fully support OpenSBI. To use U-Boot as an OpenSBI payload, the necessary to fully support OpenSBI. To use U-Boot as an OpenSBI payload, the
following out-of-tree patch series must be applied to the upstream U-Boot source following out-of-tree patch series must be applied to the upstream U-Boot source
code. code:
HiFive Unleashed support for U-Boot HiFive Unleashed support for U-Boot
https://lists.denx.de/pipermail/u-boot/2019-February/358058.html https://lists.denx.de/pipermail/u-boot/2019-February/358058.html
This patch series enables a single CPU to execute U-Boot. As a result, the next This patch series enables a single CPU to execute U-Boot. As a result, the next
stage boot code such as Linux kernel can also only execute a single CPU. U-Boot stage boot code such as a Linux kernel can also only execute on a single CPU.
SMP support for RISC-V can be enabled with the following additional patches. U-Boot SMP support for RISC-V can be enabled with the following additional
patches:
https://lists.denx.de/pipermail/u-boot/2019-February/358393.html https://lists.denx.de/pipermail/u-boot/2019-February/358393.html
Building and Generating U-Boot images Building and Generating U-Boot images
===================================== =====================================
Please refer to U-Boot build documentation for detailed instructions on how to build U-Boot images. Please refer to the U-Boot build documentation for detailed instructions on
how to build U-Boot images.
Once U-Boot images are built, Linux kernel image need to be converted to a format Once U-Boot images are built, the Linux kernel image needs to be converted
that U-Boot understands. into a format that U-Boot understands:
``` ```
<uboot-dir>/tools/mkimage -A riscv -O linux -T kernel -C none -a 0x80200000 -e 0x80200000 -n Linux -d \ <uboot-dir>/tools/mkimage -A riscv -O linux -T kernel -C none -a 0x80200000 -e 0x80200000 -n Linux -d \

View File

@@ -3,46 +3,50 @@ OpenSBI Library Usage
OpenSBI provides two types of static libraries: OpenSBI provides two types of static libraries:
1. *libsbi.a* - A platform independent generic static library implementing the 1. *libsbi.a* - A platform-independent generic static library implementing the
interface defined by the SBI specifications. Platform specific processing interface defined by the SBI specifications. Platform-specific processing
hooks for the execution of this interface must be provided by the firmware or hooks for the execution of this interface must be provided by the firmware or
bootloader linking with this library. This library is installed as bootloader linking with this library. This library is installed as
*<install_directory>/lib/libsbi.a* *<install_directory>/lib/libsbi.a*
2. *libplatsbi.a* - An example platform specific static library integrating 2. *libsbiutils.a* - A static library that will contain all common code required
*libsbi.a* with platform specific hooks. This library is available only for by any platform supported in OpenSBI. It will be built by default and included
in libplatsbi.a. This library is installed as
*<install_directory>/lib/libsbiutils.a*.
3. *libplatsbi.a* - An example platform-specific static library integrating
*libsbi.a* with platform-specific hooks. This library is available only for
the platforms supported by OpenSBI. This library is installed as the platforms supported by OpenSBI. This library is installed as
*<install_directory>/platform/<platform_subdir>/lib/libplatsbi.a* *<install_directory>/platform/<platform_subdir>/lib/libplatsbi.a*
Implementations may choose either *libsbi.a* or *libplatsbi.a* to link with Implementations may choose either *libsbi.a* or *libplatsbi.a* to link with
their firmware or bootloader. In the case of *libsbi.a*, platform specific their firmware or bootloader. In the case of *libsbi.a*, platform-specific
hooks in the form of a *struct sbi_platform* instance needs to be provided. hooks in the form of a *struct sbi_platform* instance need to be provided.
The platform specific example firmwares provided by OpenSBI are not mandatory. The platform-specific example firmwares provided by OpenSBI are not mandatory.
An implementation may choose to link OpenSBI generic static library together An implementation may choose to link the OpenSBI generic static library together
with an M-mode firmware or bootloader providing hardware specific hooks. Since with an M-mode firmware or bootloader providing the hardware-specific hooks.
OpenSBI is a statically linked library, users must ensure that the license of Since OpenSBI is a statically linked library, users must ensure that the
these external components is compatible with OpenSBI license. license of these external components is compatible with the OpenSBI license.
Constraints on OpenSBI usage from external firmware Constraints on OpenSBI usage from external firmware
--------------------------------------------------- ---------------------------------------------------
Users have to ensure that an external firmware or bootloader linking against Users have to ensure that an external firmware or bootloader linking against
OpenSBI static libraries (*libsbi.a* or *libplatsbi.a*) are compiled with the OpenSBI static libraries (*libsbi.a* or *libplatsbi.a*) is compiled with the
same GCC target options *-mabi*, *-march*, and *-mcmodel*. same GCC target options *-mabi*, *-march*, and *-mcmodel*.
There are only two constraints on calling any OpenSBI library function from an There are only two constraints on calling any OpenSBI library function from an
external M-mode firmware or bootloader: external M-mode firmware or bootloader:
1. The RISC-V *MSCRATCH* CSR must point to a valid OpenSBI scratch space 1. The RISC-V *MSCRATCH* CSR must point to a valid OpenSBI scratch space
(i.e. *struct sbi_scratch* instance) (i.e. a *struct sbi_scratch* instance).
2. The RISC-V *SP* register (i.e. stack pointer) must be set per-HART 2. The RISC-V *SP* register (i.e. the stack pointer) must be set per-HART
pointing to distinct non-overlapping stacks pointing to distinct non-overlapping stacks.
The most important functions from an external firmware or bootloader The most important functions from an external firmware or bootloader
perspective are *sbi_init()* and *sbi_trap_handler()*. perspective are *sbi_init()* and *sbi_trap_handler()*.
In addition to the above constraints, the external firmware or bootloader must In addition to the above constraints, the external firmware or bootloader must
ensure that interrupts are disabled in *MSTATUS* and *MIE* CSRs when calling ensure that interrupts are disabled in the *MSTATUS* and *MIE* CSRs when calling
the functions *sbi_init()* and *sbi_trap_handler()*. the functions *sbi_init()* and *sbi_trap_handler()*.
The *sbi_init()* function should be called by the external firmware or The *sbi_init()* function should be called by the external firmware or
@@ -63,3 +67,23 @@ bootloader to service the following interrupts and traps:
**Note:** external firmwares or bootloaders can be more conservative by **Note:** external firmwares or bootloaders can be more conservative by
forwarding all traps and interrupts to *sbi_trap_handler()*. 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

@@ -0,0 +1,30 @@
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.
To build platform specific library and firmwares, provide the
*PLATFORM=andes/ae350* parameter to the top level make command.
Platform Options
----------------
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.
AE350's dts is included in https://github.com/andestech/linux/tree/ast-v3_2_0-release-public
**Linux Kernel Payload**
```
make PLATFORM=andes/ae350 FW_PAYLOAD_PATH=<linux_build_directory>/arch/riscv/boot/Image FW_PAYLOAD_FDT_PATH=<ae350.dtb path>
```

View File

@@ -0,0 +1,38 @@
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
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
- JTAG port (see debugging section below)
- Bootrom containing zero stage bootloader and device tree.
To build platform specific library and firmwares, provide the
*PLATFORM=ariane-fpga* parameter to the top level `make` command.
Platform Options
----------------
The *Ariane FPGA* platform does not have any platform-specific options.
Building Ariane FPGA Platform
-----------------------------
**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.

View File

@@ -1,30 +1,39 @@
OpenSBI Supported Platforms OpenSBI Supported Platforms
=========================== ===========================
OpenSBI currently supports the following virtual and hardware platforms. OpenSBI currently supports the following virtual and hardware platforms:
* **QEMU RISC-V Virt Machine**: Platform support for QEMU *virt* virtual RISC-V * **QEMU RISC-V Virt Machine**: Platform support for the QEMU *virt* virtual
machine. This virtual machine is intended for RISC-V software development and RISC-V machine. This virtual machine is intended for RISC-V software
test. More details on this platform can be found in the file *[qemu_virt.md]*. 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 * **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* HiFive Unleashed board, as well as the *sifive_u* QEMU virtual RISC-V
platform. More details on this platform can be found in the file machine. More details on this platform can be found in the file
*[sifive_fu540.md]*. *[sifive_fu540.md]*.
* **Kendryte K210 SoC**: Platform support for the Kendryte K210 SoC used on * **Kendryte K210 SoC**: Platform support for the Kendryte K210 SoC used on
boards such as the Kendryte KD233 and Sipeed MAIX Dock boards. boards such as the Kendryte KD233 or the Sipeed MAIX Dock.
* **Ariane FPGA SoC**: Platform support for the Ariane FPGA SoC used on
Genesys 2 board.
* **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 The code for these supported platforms can be used as example to implement
support for other platforms. The *platform/template* directory also provides support for other platforms. The *platform/template* directory also provides
template files for implementing support for a new platform. The *object.mk*, template files for implementing support for a new platform. The *object.mk*,
*config.mk* and *platform.c* template files provides enough comments to facilitate *config.mk* and *platform.c* template files provides enough comments to
the implementation. facilitate the implementation.
[qemu_virt.md]: qemu_virt.md [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,52 +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.
Platform Options
----------------
The *QEMU SiFive Unleashed Machine* platform does not have any platform specific
options.
Executing on QEMU RISC-V 64bit
------------------------------
**No Payload Case**
Build:
```
make PLATFORM=qemu/virt
```
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 `qemu-riscv64_smode_defconfig` configuration.
Build:
```
make PLATFORM=qemu/virt 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

@@ -1,22 +1,22 @@
QEMU RISC-V Virt Machine Platform QEMU RISC-V Virt Machine Platform
================================= =================================
The **QEMU RISC-V Virt Machine** is virtual platform created for RISC-V The **QEMU RISC-V Virt Machine** is a virtual platform created for RISC-V
software development and testing. It is also referred as software development and testing. It is also referred to as
*QEMU RISC-V VirtIO machine* because it uses VirtIO devices for network, *QEMU RISC-V VirtIO machine* because it uses VirtIO devices for network,
storage, and other types of IO. storage, and other types of IO.
To build platform specific library and firmwares, provide the To build the platform-specific library and firmware images, provide the
*PLATFORM=qemu/virt* parameter to the top level `make` command. *PLATFORM=qemu/virt* parameter to the top level `make` command.
Platform Options Platform Options
---------------- ----------------
The *QEMU RISC-V Virt Machine* platform does not have any platform specific The *QEMU RISC-V Virt Machine* platform does not have any platform-specific
options. options.
Execution on QEMU RISC-V 64bit Execution on QEMU RISC-V 64-bit
------------------------------ -------------------------------
**No Payload Case** **No Payload Case**
@@ -27,7 +27,7 @@ make PLATFORM=qemu/virt
Run: Run:
``` ```
qemu-system-riscv64 -M virt -m 256M -display none -serial stdio \ qemu-system-riscv64 -M virt -m 256M -nographic \
-kernel build/platform/qemu/virt/firmware/fw_payload.elf -kernel build/platform/qemu/virt/firmware/fw_payload.elf
``` ```
@@ -43,19 +43,19 @@ make PLATFORM=qemu/virt FW_PAYLOAD_PATH=<uboot_build_directory>/u-boot.bin
Run: Run:
``` ```
qemu-system-riscv64 -M virt -m 256M -display none -serial stdio \ qemu-system-riscv64 -M virt -m 256M -nographic \
-kernel build/platform/qemu/virt/firmware/fw_payload.elf -kernel build/platform/qemu/virt/firmware/fw_payload.elf
``` ```
or or
``` ```
qemu-system-riscv64 -M virt -m 256M -display none -serial stdio \ qemu-system-riscv64 -M virt -m 256M -nographic \
-kernel build/platform/qemu/virt/firmware/fw_jump.elf \ -kernel build/platform/qemu/virt/firmware/fw_jump.elf \
-device loader,file=<uboot_build_directory>/u-boot.bin,addr=0x80400000 -device loader,file=<uboot_build_directory>/u-boot.bin,addr=0x80200000
``` ```
**Linux Kernel Payload** **Linux Kernel Payload**
Note: We assume that Linux kernel is compiled using Note: We assume that the Linux kernel is compiled using
*arch/riscv/configs/defconfig*. *arch/riscv/configs/defconfig*.
Build: Build:
@@ -65,7 +65,7 @@ make PLATFORM=qemu/virt FW_PAYLOAD_PATH=<linux_build_directory>/arch/riscv/boot/
Run: Run:
``` ```
qemu-system-riscv64 -M virt -m 256M -display none -serial stdio \ qemu-system-riscv64 -M virt -m 256M -nographic \
-kernel build/platform/qemu/virt/firmware/fw_payload.elf \ -kernel build/platform/qemu/virt/firmware/fw_payload.elf \
-drive file=<path_to_linux_rootfs>,format=raw,id=hd0 \ -drive file=<path_to_linux_rootfs>,format=raw,id=hd0 \
-device virtio-blk-device,drive=hd0 \ -device virtio-blk-device,drive=hd0 \
@@ -73,11 +73,79 @@ qemu-system-riscv64 -M virt -m 256M -display none -serial stdio \
``` ```
or or
``` ```
qemu-system-riscv64 -M virt -m 256M -display none -serial stdio \ qemu-system-riscv64 -M virt -m 256M -nographic \
-kernel build/platform/qemu/virt/firmware/fw_jump.elf \
-device loader,file=<linux_build_directory>/arch/riscv/boot/Image,addr=0x80200000 \
-drive file=<path_to_linux_rootfs>,format=raw,id=hd0 \
-device virtio-blk-device,drive=hd0 \
-append "root=/dev/vda rw console=ttyS0"
```
Execution on QEMU RISC-V 32-bit
-------------------------------
**No Payload Case**
Build:
```
make PLATFORM=qemu/virt
```
Run:
```
qemu-system-riscv32 -M virt -m 256M -nographic \
-kernel build/platform/qemu/virt/firmware/fw_payload.elf
```
**U-Boot Payload**
Note: the command line examples here assume that U-Boot was compiled using
the `qemu-riscv32_smode_defconfig` configuration.
Build:
```
make PLATFORM=qemu/virt FW_PAYLOAD_PATH=<uboot_build_directory>/u-boot.bin
```
Run:
```
qemu-system-riscv32 -M virt -m 256M -nographic \
-kernel build/platform/qemu/virt/firmware/fw_payload.elf
```
or
```
qemu-system-riscv32 -M virt -m 256M -nographic \
-kernel build/platform/qemu/virt/firmware/fw_jump.elf \
-device loader,file=<uboot_build_directory>/u-boot.bin,addr=0x80400000
```
**Linux Kernel Payload**
Note: We assume that the Linux kernel is compiled using
*arch/riscv/configs/rv32_defconfig* (kernel 5.1 and newer)
respectively using *arch/riscv/configs/defconfig* plus setting
CONFIG_ARCH_RV32I=y (kernel 5.0 and older).
Build:
```
make PLATFORM=qemu/virt FW_PAYLOAD_PATH=<linux_build_directory>/arch/riscv/boot/Image
```
Run:
```
qemu-system-riscv32 -M virt -m 256M -nographic \
-kernel build/platform/qemu/virt/firmware/fw_payload.elf \
-drive file=<path_to_linux_rootfs>,format=raw,id=hd0 \
-device virtio-blk-device,drive=hd0 \
-append "root=/dev/vda rw console=ttyS0"
```
or
```
qemu-system-riscv32 -M virt -m 256M -nographic \
-kernel build/platform/qemu/virt/firmware/fw_jump.elf \ -kernel build/platform/qemu/virt/firmware/fw_jump.elf \
-device loader,file=<linux_build_directory>/arch/riscv/boot/Image,addr=0x80400000 \ -device loader,file=<linux_build_directory>/arch/riscv/boot/Image,addr=0x80400000 \
-drive file=<path_to_linux_rootfs>,format=raw,id=hd0 \ -drive file=<path_to_linux_rootfs>,format=raw,id=hd0 \
-device virtio-blk-device,drive=hd0 \ -device virtio-blk-device,drive=hd0 \
-append "root=/dev/vda rw console=ttyS0" -append "root=/dev/vda rw console=ttyS0"
``` ```

View File

@@ -1,9 +1,12 @@
SiFive FU540 SoC Platform SiFive FU540 SoC Platform
========================== =========================
The FU540-C000 is the worlds first 4+1 64-bit RISC-V SoC from SiFive. 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 The HiFive Unleashed development platform is based on FU540-C000 and capable
of running Linux. of running Linux.
With QEMU v4.2 or above release, the 'sifive_u' machine can be used to test
OpenSBI image built for the real hardware as well.
To build platform specific library and firmwares, provide the To build platform specific library and firmwares, provide the
*PLATFORM=sifive/fu540* parameter to the top level `make` command. *PLATFORM=sifive/fu540* parameter to the top level `make` command.
@@ -11,9 +14,10 @@ Platform Options
---------------- ----------------
As hart0 in the FU540 doesn't have an MMU, only harts 1-4 boot by default. As hart0 in the FU540 doesn't have an MMU, only harts 1-4 boot by default.
A hart mask i.e. *FU540_ENABLED_HART_MASK* compile time option is provided to A hart mask i.e. *FU540_ENABLED_HART_MASK* compile time option is provided
select any other hart for booting. Please keep in mind that this is not to select any other hart for booting. Please keep in mind that this is not
platform wide option. It can only be specified for FU540 platform in following way. a generic option and it can only be specified for FU540 platform in the
following way:
``` ```
make PLATFORM=sifive/fu540 FW_PAYLOAD_PATH=Image FU540_ENABLED_HART_MASK=0x02 make PLATFORM=sifive/fu540 FW_PAYLOAD_PATH=Image FU540_ENABLED_HART_MASK=0x02
@@ -21,85 +25,80 @@ 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. This will let the board boot only hart1 instead of default 1-4.
Building SiFive Fu540 Platform Building SiFive Fu540 Platform
----------------------------- ------------------------------
As of this writing, the required Linux kernel and U-Boot patches are not In order to boot SMP Linux in U-Boot, Linux v5.1 (or higher) and latest
accepted in mainline. Please follow the below instructions to cherry-pick U-Boot v2020.01 (or higher) should be used.
them into your repository.
[U-Boot patches](../firmware/payload_uboot.md)
[Linux kernel patches](../firmware/payload_linux.md)
**Linux Kernel Payload** **Linux Kernel Payload**
The HiFive Unleashed device tree(DT) is merged in Linux v5.2 release. This
DT (device tree) is not backward compatible with the DT passed from FSBL.
To use Linux v5.2 (or higher, the pre-built DTB (DT binary) from Linux v5.2
(or higher) should be used to build SiFive FU540 OpenSBI binaries by using
the compile time option *FW_PAYLOAD_FDT_PATH*.
``` ```
make PLATFORM=sifive/fu540 FW_PAYLOAD_PATH=<linux_build_directory>/arch/riscv/boot/Image make PLATFORM=sifive/fu540 FW_PAYLOAD_PATH=<linux_build_directory>/arch/riscv/boot/Image
or
(For Linux v5.2 or higher)
make PLATFORM=sifive/fu540 FW_PAYLOAD_PATH=<linux_build_directory>/arch/riscv/boot/Image FW_PAYLOAD_FDT_PATH=<hifive-unleashed-a00.dtb path from Linux kernel>
``` ```
**U-Boot Payload** **U-Boot Payload**
The command-line example here assumes that U-Boot was compiled using the
sifive_fu540_defconfig configuration and with U-Boot v2020.01 (or higher).
The command-line example here assumes that U-Boot was compiled using sifive_fu540_defconfig configuration. The detailed U-Boot booting guide is avaialble at [U-Boot].
With SMP support enabled in U-Boot:
``` ```
make PLATFORM=sifive/fu540 FW_PAYLOAD_PATH=<u-boot_build_dir>/u-boot.bin make PLATFORM=sifive/fu540 FW_PAYLOAD_PATH=<u-boot_build_dir>/u-boot-dtb.bin
```
Without SMP support enabled in U-Boot:
```
make PLATFORM=sifive/fu540 FW_PAYLOAD_PATH=<u-boot_build_dir>/u-boot.bin FU540_ENABLED_HART_MASK=0x02
``` ```
**U-Boot & Linux Kernel as a single payload** **U-Boot & Linux Kernel as a single payload**
A single monolithic image containing both U-Boot & Linux can also be used if network boot setup is A single monolithic image containing both U-Boot & Linux can also be used if
not available. network boot setup is not available.
1. Generate the uImage from Linux Image. 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.
``` ```
mkimage -A riscv -O linux -T kernel -C none -a 0x80200000 -e 0x80200000 -n Linux -d \ dd if=~/workspace/u-boot-riscv/u-boot-dtb.bin of=/tmp/temp.bin bs=1M
<linux_build_directory>arch/riscv/boot/Image \
<linux_build_directory>/arch/riscv/boot/uImage
``` ```
2. Append the Linux Kernel image.
2. Create a temporary image with u-boot.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=<linux_build_directory>/arch/riscv/boot/Image of=/tmp/temp.bin bs=1M seek=4
``` ```
3. Append the Linux Kernel image generated in step 1. 3. Compile OpenSBI with temp.bin (generated in step 2) as payload.
```
dd if=<linux_build_directory>/arch/riscv/boot/uImage of=/tmp/temp.bin bs=1M seek=4
```
4. Compile OpenSBI with temp.bin (generated in step 3) as payload.
``` ```
make PLATFORM=sifive/fu540 FW_PAYLOAD_PATH=/tmp/temp.bin 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
``` ```
Flashing the OpenSBI firmware binary to storage media: Flashing the OpenSBI firmware binary to storage media:
----------------------------------------------------- ------------------------------------------------------
The first stage boot loader([FSBL](https://github.com/sifive/freedom-u540-c000-bootloader)) The first stage boot loader ([FSBL]) expects the storage media to have a GPT
expects the storage media to have a GPT partition table. It tries to look for a partition table. It tries to look for a partition with following GUID to load
partition with following GUID to load the next stage boot loader (OpenSBI in this case). the next stage boot loader (OpenSBI in this case).
``` ```
2E54B353-1271-4842-806F-E436D6AF6985 2E54B353-1271-4842-806F-E436D6AF6985
``` ```
That's why the generated firmware binary in above steps should be copied to the That's why the generated firmware binary in above steps should be copied to
partition of the sdcard with above GUID. the partition of the sdcard with above GUID.
``` ```
dd if=build/platform/sifive/fu540/firmware/fw_payload.bin of=/dev/disk2s1 bs=1024 dd if=build/platform/sifive/fu540/firmware/fw_payload.bin of=/dev/disk2s1 bs=1024
``` ```
In my case, it is the first partition is **disk2s1** that has been formatted with the In my case, it is the first partition is **disk2s1** that has been formatted
above specified GUID. with the above specified GUID.
In case of a brand new sdcard, it should be formatted with below partition In case of a brand new sdcard, it should be formatted with below partition
tables as described here. tables as described here.
@@ -108,7 +107,7 @@ tables as described here.
sgdisk --clear \ sgdisk --clear \
--new=1:2048:67583 --change-name=1:bootloader --typecode=1:2E54B353-1271-4842-806F-E436D6AF6985 \ --new=1:2048:67583 --change-name=1:bootloader --typecode=1:2E54B353-1271-4842-806F-E436D6AF6985 \
--new=2:264192: --change-name=2:root --typecode=2:0FC63DAF-8483-4772-8E79-3D69D8477DE4 \ --new=2:264192: --change-name=2:root --typecode=2:0FC63DAF-8483-4772-8E79-3D69D8477DE4 \
$(DISK) ${DISK}
``` ```
Booting SiFive Fu540 Platform Booting SiFive Fu540 Platform
@@ -116,67 +115,55 @@ Booting SiFive Fu540 Platform
**Linux Kernel Payload** **Linux Kernel Payload**
As Linux kernel image is embedded in the OpenSBI firmware binary, HiFive Unleashed will directly As Linux kernel image is embedded in the OpenSBI firmware binary, HiFive
boot into Linux directly after powered on. Unleashed will directly boot into Linux directly after powered on.
**U-Boot Payload** **U-Boot Payload**
As U-Boot image is used as payload, HiFive Unleashed will boot into a U-Boot prompt. As U-Boot image is used as payload, HiFive Unleashed will boot into a U-Boot
U-Boot tftp boot method can be used to load kernel image in U-Boot prompt. prompt. U-Boot tftp boot method can be used to load kernel image in U-Boot
Here are the steps do a tftpboot. prompt. Here are the steps do a tftpboot.
1. Set the mac address of the board.
```
setenv ethaddr <mac address of the board>
```
2. Set the ip address of the board.
1. Set the ip address of the board.
``` ```
setenv ipaddr <ipaddr 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> 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> 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} /sifive/fu540/uImage tftpboot ${kernel_addr_r} <Image path in tftpboot directory>
``` ```
5. Load the ramdisk image from the tftp server. This is only required if
6. Load the ramdisk image from the tftp server. This is only required if ramdisk ramdisk is loaded from tftp server. This step is optional, if rootfs is
is loaded from tftp server. This step is optional, if rootfs is already part already part of the kernel or loaded from an external storage by kernel.
of the kernel or loaded from an external storage by kernel.
``` ```
tftpboot ${ramdisk_addr_r} /sifive/fu540/uRamdisk tftpboot ${ramdisk_addr_r} <ramdisk path in tftpboot directory>
```
6. Load the pre-compiled device tree via tftpboot.
```
tftpboot ${fdt_addr_r} <hifive-unleashed-a00.dtb path in tftpboot directory>
``` ```
7. Set the boot command-line arguments. 7. Set the boot command-line arguments.
``` ```
setenv bootargs "root=<root partition> rw console=ttySIF0 earlycon=sbi" setenv bootargs "root=<root partition> rw console=ttySIF0 earlycon=sbi"
``` ```
(Note: root partition should point to
N.B. root partition should point to ** /dev/ram ** - If a ramdisk is used
** /dev/ram ** - If a ramdisk is used ** root=/dev/mmcblk0pX ** - If a rootfs is already on some other partition
** root=/dev/mmcblk0pX ** - If a rootfs is already on some other partition of sdcard of sdcard)
8. Now boot into Linux. 8. Now boot into Linux.
``` ```
bootm ${kernel_addr_r} ${ramdisk_addr_r} ${fdtcontroladdr} booti ${kernel_addr_r} ${ramdisk_addr_r} ${fdt_addr_r}
or
``` (If ramdisk is not loaded from network)
or (if ramdisk is not loaded from network) booti ${kernel_addr_r} - ${fdt_addr_r}
```
bootm ${kernel_addr_r} - ${fdtcontroladdr}
``` ```
**U-Boot & Linux Kernel as a single payload** **U-Boot & Linux Kernel as a single payload**
@@ -184,19 +171,31 @@ bootm ${kernel_addr_r} - ${fdtcontroladdr}
At U-Boot prompt execute the following boot command to boot Linux. At U-Boot prompt execute the following boot command to boot Linux.
``` ```
bootm ${kernel_addr_r} - ${fdtcontroladdr} booti ${kernel_addr_r} - ${fdt_addr_r}
``` ```
Booting SiFive Fu540 Platform with Microsemi Expansion board
------------------------------------------------------------
Until the Linux kernel has in-tree support for device trees and mainline u-boot QEMU Specific Instructions
is fully supported on the HiFive Unleashed you can follow these steps to boot --------------------------
Linux with the Microsemi expansion board. This method should not be copied on If you want to test OpenSBI with QEMU 'sifive_u' machine, please follow the
future boards and is considered a temporary solution until we can use a more same instructions above, with the exception of not passing FW_PAYLOAD_FDT_PATH.
standardised boot flow.
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:
To boot the Linux kernel with a device tree that has support for the Microsemi
Expansion board you can include the following line when compiling the firmware:
``` ```
FW_PAYLOAD_FDT="HiFiveUnleashed-MicroSemi-Expansion.dtb" 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

@@ -1,15 +1,15 @@
OpenSBI Platform Support Guideline OpenSBI Platform Support Guideline
================================== ==================================
OpenSBI platform support allows an implementation to define a set of platform The OpenSBI platform support allows an implementation to define a set of
specific hooks (hardware manipulation functions) in the form of a platform-specific hooks (hardware manipulation functions) in the form of a
*struct sbi_platform* data structure instance. This instance is required by *struct sbi_platform* data structure instance. This instance is required by
platform independent *libsbi.a* to execute platform specific operations. the platform-independent *libsbi.a* to execute platform-specific operations.
Each of the reference platform support provided by OpenSBI define an instance Each of the reference platform supports provided by OpenSBI defines an instance
of the *struct sbi_platform* data structure. For each supported platform, of the *struct sbi_platform* data structure. For each supported platform,
*libplatsbi.a* integrates this instance with *libsbi.a* to create a platform *libplatsbi.a* integrates this instance with *libsbi.a* to create a
specific OpenSBI static library. This library is installed platform-specific OpenSBI static library. This library is installed
in *<install_directory>/platform/<platform_subdir>/lib/libplatsbi.a* in *<install_directory>/platform/<platform_subdir>/lib/libplatsbi.a*
OpenSBI also provides implementation examples of bootable runtime firmwares for OpenSBI also provides implementation examples of bootable runtime firmwares for
@@ -22,21 +22,21 @@ for the legacy *riskv-pk* boot loader (BBL).
A complete doxygen-style documentation of *struct sbi_platform* and related A complete doxygen-style documentation of *struct sbi_platform* and related
APIs is available in the file *include/sbi/sbi_platform.h*. APIs is available in the file *include/sbi/sbi_platform.h*.
Adding a new platform support Adding support for a new platform
----------------------------- ---------------------------------
Support for a new platform named *<xyz>* can be added as follows: Support for a new platform named *<xyz>* can be added as follows:
1. Create a directory named *<xyz>* under *platform/* directory 1. Create a directory named *<xyz>* under the *platform/* directory.
2. Create a platform configuration file named *config.mk* under 2. Create a platform configuration file named *config.mk* under the
*platform/<xyz>/* directory. This configuration file will provide *platform/<xyz>/* directory. This configuration file will provide
compiler flags, select common drivers, and select firmware options compiler flags, and select firmware options.
3. Create *platform/<xyz>/objects.mk* file for listing the platform 3. Create a *platform/<xyz>/objects.mk* file for listing the
specific object files to be compiled platform-specific object files to be compiled.
4. Create *platform/<xyz>/platform.c* file providing a *struct sbi_platform* 4. Create a *platform/<xyz>/platform.c* file providing a *struct sbi_platform*
instance instance.
A template platform support code is available under the *platform/template* A platform support code template is available under the *platform/template*
directory. Copying this directory and its content as a new directory named directory. Copying this directory and its content as a new directory named
*<xyz>* under the *platform/* directory will create all the files mentioned *<xyz>* under the *platform/* directory will create all the files mentioned
above. above.

View File

@@ -7,5 +7,5 @@
# Anup Patel <anup.patel@wdc.com> # Anup Patel <anup.patel@wdc.com>
# #
$(build_dir)/$(platform_subdir)/firmware/fw_payload.o: $(FW_PAYLOAD_PATH_FINAL) $(platform_build_dir)/firmware/fw_payload.o: $(FW_PAYLOAD_PATH_FINAL)
$(build_dir)/$(platform_subdir)/firmware/fw_payload.o: $(FW_PAYLOAD_FDT_PATH) $(platform_build_dir)/firmware/fw_payload.o: $(FW_PAYLOAD_FDT_PATH)

View File

@@ -13,17 +13,237 @@
#include <sbi/sbi_scratch.h> #include <sbi/sbi_scratch.h>
#include <sbi/sbi_trap.h> #include <sbi/sbi_trap.h>
.align 3 #define BOOT_STATUS_RELOCATE_DONE 1
#define BOOT_STATUS_BOOT_HART_DONE 2
.macro MOV_3R __d0, __s0, __d1, __s1, __d2, __s2
add \__d0, \__s0, zero
add \__d1, \__s1, zero
add \__d2, \__s2, zero
.endm
.macro MOV_5R __d0, __s0, __d1, __s1, __d2, __s2, __d3, __s3, __d4, __s4
add \__d0, \__s0, zero
add \__d1, \__s1, zero
add \__d2, \__s2, zero
add \__d3, \__s3, zero
add \__d4, \__s4, zero
.endm
/*
* If __start_reg <= __check_reg and __check_reg < __end_reg then
* jump to __pass
*/
.macro BRANGE __start_reg, __end_reg, __check_reg, __jump_lable
blt \__check_reg, \__start_reg, 999f
bge \__check_reg, \__end_reg, 999f
j \__jump_lable
999:
.endm
.section .entry, "ax", %progbits .section .entry, "ax", %progbits
.align 3
.globl _start .globl _start
.globl _start_warm .globl _start_warm
_start: _start:
/* 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
la t1, _start
REG_S t1, 0(t0)
/* Relocate if load address != link address */
_relocate:
la t0, _link_start
REG_L t0, 0(t0)
la t1, _link_end
REG_L t1, 0(t1)
la t2, _load_start
REG_L t2, 0(t2)
sub t3, t1, t0
add t3, t3, t2
beq t0, t2, _relocate_done
la t4, _relocate_done
sub t4, t4, t2
add t4, t4, t0
blt t2, t0, _relocate_copy_to_upper
_relocate_copy_to_lower:
ble t1, t2, _relocate_copy_to_lower_loop
la t3, _relocate_lottery
BRANGE t2, t1, t3, _start_hang
la t3, _boot_status
BRANGE t2, t1, t3, _start_hang
la t3, _relocate
la t5, _relocate_done
BRANGE t2, t1, t3, _start_hang
BRANGE t2, t1, t5, _start_hang
BRANGE t3, t5, t2, _start_hang
_relocate_copy_to_lower_loop:
REG_L t3, 0(t2)
REG_S t3, 0(t0)
add t0, t0, __SIZEOF_POINTER__
add t2, t2, __SIZEOF_POINTER__
blt t0, t1, _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
la t5, _relocate_done
BRANGE t0, t3, t2, _start_hang
BRANGE t0, t3, t5, _start_hang
BRANGE t2, t5, t0, _start_hang
_relocate_copy_to_upper_loop:
add t3, t3, -__SIZEOF_POINTER__
add t1, t1, -__SIZEOF_POINTER__
REG_L t2, 0(t3)
REG_S t2, 0(t1)
blt t0, t1, _relocate_copy_to_upper_loop
jr t4
_wait_relocate_copy_done:
la t0, _start
la t1, _link_start
REG_L t1, 0(t1)
beq t0, t1, _wait_for_boot_hart
la t2, _boot_status
la t3, _wait_for_boot_hart
sub t3, t3, t0
add t3, t3, t1
1:
/* waitting for relocate copy done (_boot_status == 1) */
li t4, BOOT_STATUS_RELOCATE_DONE
REG_L t5, 0(t2)
/* Reduce the bus traffic so that boot hart may proceed faster */
nop
nop
nop
bgt t4, t5, 1b
jr t3
_relocate_done:
/* /*
* Jump to warm-boot if this is not the first core booting, * Mark relocate copy done
* that is, for mhartid != 0 * Use _boot_status copy relative to the load address
*/ */
csrr a6, CSR_MHARTID la t0, _boot_status
blt zero, a6, _wait_for_boot_hart la t1, _link_start
REG_L t1, 0(t1)
la t2, _load_start
REG_L t2, 0(t2)
sub t0, t0, t1
add t0, t0, t2
li t1, BOOT_STATUS_RELOCATE_DONE
REG_S t1, 0(t0)
fence rw, rw
/* At this point we are running from link address */
/* Reset all registers for boot HART */
li ra, 0
call _reset_regs
/* Allow main firmware to save info */
MOV_5R s0, a0, s1, a1, s2, a2, s3, a3, s4, a4
call fw_save_info
MOV_5R a0, s0, a1, s1, a2, s2, a3, s3, a4, s4
/* Preload HART details
* s7 -> HART Count
* s8 -> HART Stack Size
*/
la a4, platform
#if __riscv_xlen == 64
lwu s7, SBI_PLATFORM_HART_COUNT_OFFSET(a4)
lwu s8, SBI_PLATFORM_HART_STACK_SIZE_OFFSET(a4)
#else
lw s7, SBI_PLATFORM_HART_COUNT_OFFSET(a4)
lw s8, SBI_PLATFORM_HART_STACK_SIZE_OFFSET(a4)
#endif
/* Setup scratch space for all the HARTs*/
la tp, _fw_end
mul a5, s7, s8
add tp, tp, a5
/* Keep a copy of tp */
add t3, tp, zero
/* Counter */
li t2, 1
/* hartid 0 is mandated by ISA */
li t1, 0
_scratch_init:
add tp, t3, zero
mul a5, s8, t1
sub tp, tp, a5
li a5, SBI_SCRATCH_SIZE
sub tp, tp, a5
/* Initialize scratch space */
/* Store fw_start and fw_size in scratch space */
la a4, _fw_start
la a5, _fw_end
mul t0, s7, s8
add a5, a5, t0
sub a5, a5, a4
REG_S a4, SBI_SCRATCH_FW_START_OFFSET(tp)
REG_S a5, SBI_SCRATCH_FW_SIZE_OFFSET(tp)
/* Store next arg1 in scratch space */
MOV_3R s0, a0, s1, a1, s2, a2
call fw_next_arg1
REG_S a0, SBI_SCRATCH_NEXT_ARG1_OFFSET(tp)
MOV_3R a0, s0, a1, s1, a2, s2
/* Store next address in scratch space */
MOV_3R s0, a0, s1, a1, s2, a2
call fw_next_addr
REG_S a0, SBI_SCRATCH_NEXT_ADDR_OFFSET(tp)
MOV_3R a0, s0, a1, s1, a2, s2
/* Store next mode in scratch space */
MOV_3R s0, a0, s1, a1, s2, a2
call fw_next_mode
REG_S a0, SBI_SCRATCH_NEXT_MODE_OFFSET(tp)
MOV_3R a0, s0, a1, s1, a2, s2
/* Store warm_boot address in scratch space */
la a4, _start_warm
REG_S a4, SBI_SCRATCH_WARMBOOT_ADDR_OFFSET(tp)
/* Store platform address in scratch space */
la a4, platform
REG_S a4, SBI_SCRATCH_PLATFORM_ADDR_OFFSET(tp)
/* Store hartid-to-scratch function address in scratch space */
la a4, _hartid_to_scratch
REG_S a4, SBI_SCRATCH_HARTID_TO_SCRATCH_OFFSET(tp)
/* Clear tmp0 in scratch space */
REG_S zero, SBI_SCRATCH_TMP0_OFFSET(tp)
/* Store firmware options in scratch space */
MOV_3R s0, a0, s1, a1, s2, a2
#ifdef FW_OPTIONS
li a4, FW_OPTIONS
#else
add a4, zero, zero
#endif
call fw_options
or a4, a4, a0
REG_S a4, SBI_SCRATCH_OPTIONS_OFFSET(tp)
MOV_3R a0, s0, a1, s1, a2, s2
/* Move to next scratch space */
add t1, t1, t2
blt t1, s7, _scratch_init
/* Zero-out BSS */ /* Zero-out BSS */
la a4, _bss_start la a4, _bss_start
@@ -34,12 +254,10 @@ _bss_zero:
blt a4, a5, _bss_zero blt a4, a5, _bss_zero
/* Override pervious arg1 */ /* Override pervious arg1 */
add s0, a0, zero MOV_3R s0, a0, s1, a1, s2, a2
add s1, a1, zero
call fw_prev_arg1 call fw_prev_arg1
add t1, a0, zero add t1, a0, zero
add a0, s0, zero MOV_3R a0, s0, a1, s1, a2, s2
add a1, s1, zero
beqz t1, _prev_arg1_override_done beqz t1, _prev_arg1_override_done
add a1, t1, zero add a1, t1, zero
_prev_arg1_override_done: _prev_arg1_override_done:
@@ -54,16 +272,15 @@ _prev_arg1_override_done:
*/ */
beqz a1, _fdt_reloc_done beqz a1, _fdt_reloc_done
/* Mask values in a3 and a4 */ /* Mask values in a3 and a4 */
li a3, ~0xf li a3, ~(__SIZEOF_POINTER__ - 1)
li a4, 0xff li a4, 0xff
/* t1 = destination FDT start address */ /* t1 = destination FDT start address */
add s0, a0, zero MOV_3R s0, a0, s1, a1, s2, a2
add s1, a1, zero
call fw_next_arg1 call fw_next_arg1
add t1, a0, zero add t1, a0, zero
add a0, s0, zero MOV_3R a0, s0, a1, s1, a2, s2
add a1, s1, zero
beqz t1, _fdt_reloc_done beqz t1, _fdt_reloc_done
beq t1, a1, _fdt_reloc_done
and t1, t1, a3 and t1, t1, a3
/* t0 = source FDT start address */ /* t0 = source FDT start address */
add t0, a1, zero add t0, a1, zero
@@ -107,34 +324,33 @@ _fdt_reloc_again:
blt t1, t2, _fdt_reloc_again blt t1, t2, _fdt_reloc_again
_fdt_reloc_done: _fdt_reloc_done:
/* Update boot hart flag */ /* mark boot hart done */
la a4, _boot_hart_done li t0, BOOT_STATUS_BOOT_HART_DONE
li a5, 1 la t1, _boot_status
REG_S a5, (a4) REG_S t0, 0(t1)
j _wait_for_boot_hart fence rw, rw
j _start_warm
.align 3 /* waitting for boot hart done (_boot_status == 2) */
_boot_hart_done:
RISCV_PTR 0
.align 3
/* Wait for boot hart */
_wait_for_boot_hart: _wait_for_boot_hart:
la a4, _boot_hart_done li t0, BOOT_STATUS_BOOT_HART_DONE
REG_L a5, (a4) la t1, _boot_status
beqz a5, _wait_for_boot_hart REG_L t1, 0(t1)
/* Reduce the bus traffic so that boot hart may proceed faster */
nop
nop
nop
bne t0, t1, _wait_for_boot_hart
_start_warm: _start_warm:
/* Reset all registers for non-boot HARTs */
li ra, 0
call _reset_regs
/* Disable and clear all interrupts */ /* Disable and clear all interrupts */
csrw CSR_MIE, zero csrw CSR_MIE, zero
csrw CSR_MIP, zero csrw CSR_MIP, zero
/* Preload per-HART details
* s6 -> HART ID
* s7 -> HART Count
* s8 -> HART Stack Size
*/
csrr s6, CSR_MHARTID
la a4, platform la a4, platform
#if __riscv_xlen == 64 #if __riscv_xlen == 64
lwu s7, SBI_PLATFORM_HART_COUNT_OFFSET(a4) lwu s7, SBI_PLATFORM_HART_COUNT_OFFSET(a4)
@@ -148,7 +364,7 @@ _start_warm:
csrr s6, CSR_MHARTID csrr s6, CSR_MHARTID
bge s6, s7, _start_hang bge s6, s7, _start_hang
/* Setup scratch space */ /* find the scratch space for this hart */
la tp, _fw_end la tp, _fw_end
mul a5, s7, s8 mul a5, s7, s8
add tp, tp, a5 add tp, tp, a5
@@ -156,32 +372,9 @@ _start_warm:
sub tp, tp, a5 sub tp, tp, a5
li a5, SBI_SCRATCH_SIZE li a5, SBI_SCRATCH_SIZE
sub tp, tp, a5 sub tp, tp, a5
csrw CSR_MSCRATCH, tp
/* Initialize scratch space */ /* update the mscratch */
la a4, _fw_start csrw CSR_MSCRATCH, tp
la a5, _fw_end
mul t0, s7, s8
add a5, a5, t0
sub a5, a5, a4
REG_S a4, SBI_SCRATCH_FW_START_OFFSET(tp)
REG_S a5, SBI_SCRATCH_FW_SIZE_OFFSET(tp)
/* Note: fw_next_arg1() uses a0, a1, and ra */
call fw_next_arg1
REG_S a0, SBI_SCRATCH_NEXT_ARG1_OFFSET(tp)
/* Note: fw_next_addr() uses a0, a1, and ra */
call fw_next_addr
REG_S a0, SBI_SCRATCH_NEXT_ADDR_OFFSET(tp)
li a4, PRV_S
REG_S a4, SBI_SCRATCH_NEXT_MODE_OFFSET(tp)
la a4, _start_warm
REG_S a4, SBI_SCRATCH_WARMBOOT_ADDR_OFFSET(tp)
la a4, platform
REG_S a4, SBI_SCRATCH_PLATFORM_ADDR_OFFSET(tp)
la a4, _hartid_to_scratch
REG_S a4, SBI_SCRATCH_HARTID_TO_SCRATCH_OFFSET(tp)
REG_S zero, SBI_SCRATCH_IPI_TYPE_OFFSET(tp)
REG_S zero, SBI_SCRATCH_TMP0_OFFSET(tp)
/* Setup stack */ /* Setup stack */
add sp, tp, zero add sp, tp, zero
@@ -189,16 +382,31 @@ _start_warm:
/* Setup trap handler */ /* Setup trap handler */
la a4, _trap_handler la a4, _trap_handler
csrw CSR_MTVEC, a4 csrw CSR_MTVEC, a4
/* Make sure that mtvec is updated */
1: csrr a5, CSR_MTVEC
bne a4, a5, 1b
/* Initialize SBI runtime */ /* Initialize SBI runtime */
csrr a0, CSR_MSCRATCH csrr a0, CSR_MSCRATCH
Call sbi_init call sbi_init
/* We don't expect to reach here hence just hang */ /* We don't expect to reach here hence just hang */
j _start_hang j _start_hang
.align 3 .align 3
_relocate_lottery:
RISCV_PTR 0
_boot_status:
RISCV_PTR 0
_load_start:
RISCV_PTR _fw_start
_link_start:
RISCV_PTR _fw_start
_link_end:
RISCV_PTR _fw_reloc_end
.section .entry, "ax", %progbits .section .entry, "ax", %progbits
.align 3
.globl _hartid_to_scratch .globl _hartid_to_scratch
_hartid_to_scratch: _hartid_to_scratch:
add sp, sp, -(3 * __SIZEOF_POINTER__) add sp, sp, -(3 * __SIZEOF_POINTER__)
@@ -232,15 +440,15 @@ _hartid_to_scratch:
add sp, sp, (3 * __SIZEOF_POINTER__) add sp, sp, (3 * __SIZEOF_POINTER__)
ret ret
.align 3
.section .entry, "ax", %progbits .section .entry, "ax", %progbits
.align 3
.globl _start_hang .globl _start_hang
_start_hang: _start_hang:
wfi wfi
j _start_hang j _start_hang
.align 3
.section .entry, "ax", %progbits .section .entry, "ax", %progbits
.align 3
.globl _trap_handler .globl _trap_handler
_trap_handler: _trap_handler:
/* Swap TP and MSCRATCH */ /* Swap TP and MSCRATCH */
@@ -293,6 +501,16 @@ _trap_handler_all_mode:
REG_S t0, SBI_TRAP_REGS_OFFSET(mepc)(sp) REG_S t0, SBI_TRAP_REGS_OFFSET(mepc)(sp)
csrr t0, CSR_MSTATUS csrr t0, CSR_MSTATUS
REG_S t0, SBI_TRAP_REGS_OFFSET(mstatus)(sp) REG_S t0, SBI_TRAP_REGS_OFFSET(mstatus)(sp)
REG_S zero, SBI_TRAP_REGS_OFFSET(mstatusH)(sp)
#if __riscv_xlen == 32
csrr t0, CSR_MISA
srli t0, t0, ('H' - 'A')
andi t0, t0, 0x1
beq t0, zero, _skip_mstatush_save
csrr t0, CSR_MSTATUSH
REG_S t0, SBI_TRAP_REGS_OFFSET(mstatusH)(sp)
_skip_mstatush_save:
#endif
/* Save all general regisers except SP and T0 */ /* Save all general regisers except SP and T0 */
REG_S zero, SBI_TRAP_REGS_OFFSET(zero)(sp) REG_S zero, SBI_TRAP_REGS_OFFSET(zero)(sp)
@@ -367,6 +585,15 @@ _trap_handler_all_mode:
csrw CSR_MEPC, t0 csrw CSR_MEPC, t0
REG_L t0, SBI_TRAP_REGS_OFFSET(mstatus)(sp) REG_L t0, SBI_TRAP_REGS_OFFSET(mstatus)(sp)
csrw CSR_MSTATUS, t0 csrw CSR_MSTATUS, t0
#if __riscv_xlen == 32
csrr t0, CSR_MISA
srli t0, t0, ('H' - 'A')
andi t0, t0, 0x1
beq t0, zero, _skip_mstatush_restore
REG_L t0, SBI_TRAP_REGS_OFFSET(mstatusH)(sp)
csrw CSR_MSTATUSH, t0
_skip_mstatush_restore:
#endif
/* Restore T0 */ /* Restore T0 */
REG_L t0, SBI_TRAP_REGS_OFFSET(t0)(sp) REG_L t0, SBI_TRAP_REGS_OFFSET(t0)(sp)
@@ -375,3 +602,42 @@ _trap_handler_all_mode:
REG_L sp, SBI_TRAP_REGS_OFFSET(sp)(sp) REG_L sp, SBI_TRAP_REGS_OFFSET(sp)(sp)
mret mret
.section .entry, "ax", %progbits
.align 3
.globl _reset_regs
_reset_regs:
/* flush the instruction cache */
fence.i
/* Reset all registers except ra, a0, a1 and a2 */
li sp, 0
li gp, 0
li tp, 0
li t0, 0
li t1, 0
li t2, 0
li s0, 0
li s1, 0
li a3, 0
li a4, 0
li a5, 0
li a6, 0
li a7, 0
li s2, 0
li s3, 0
li s4, 0
li s5, 0
li s6, 0
li s7, 0
li s8, 0
li s9, 0
li s10, 0
li s11, 0
li t3, 0
li t4, 0
li t5, 0
li t6, 0
csrw CSR_MSCRATCH, 0
ret

View File

@@ -50,6 +50,8 @@
{ {
PROVIDE(_data_start = .); PROVIDE(_data_start = .);
*(.sdata)
*(.sdata.*)
*(.data) *(.data)
*(.data.*) *(.data.*)
*(.readmostly.data) *(.readmostly.data)
@@ -64,6 +66,8 @@
.bss : .bss :
{ {
PROVIDE(_bss_start = .); PROVIDE(_bss_start = .);
*(.sbss)
*(.sbss.*)
*(.bss) *(.bss)
*(.bss.*) *(.bss.*)
. = ALIGN(8); . = ALIGN(8);

164
firmware/fw_dynamic.S Normal file
View File

@@ -0,0 +1,164 @@
/*
* SPDX-License-Identifier: BSD-2-Clause
*
* Copyright (c) 2019 Western Digital Corporation or its affiliates.
*
* Authors:
* Anup Patel <anup.patel@wdc.com>
*/
#include <sbi/fw_dynamic.h>
#include "fw_base.S"
.section .entry, "ax", %progbits
.align 3
_bad_dynamic_info:
wfi
j _bad_dynamic_info
.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.
* The a0, a1, and a2 registers will be same as passed by
* previous booting stage.
* 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)
la a4, _dynamic_next_mode
REG_L a3, FW_DYNAMIC_INFO_NEXT_MODE_OFFSET(a2)
REG_S a3, (a4)
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
.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
.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:
la a0, _dynamic_next_arg1
REG_L a0, (a0)
ret
.section .entry, "ax", %progbits
.align 3
.global fw_next_addr
/*
* We can only use a0, a1, and a2 registers here.
* The next address should be returned in 'a0'.
*/
fw_next_addr:
la a0, _dynamic_next_addr
REG_L a0, (a0)
ret
.section .entry, "ax", %progbits
.align 3
.global fw_next_mode
/*
* We can only use a0, a1, and a2 registers here.
* The next address should be returned in 'a0'
*/
fw_next_mode:
la a0, _dynamic_next_mode
REG_L a0, (a0)
ret
.section .entry, "ax", %progbits
.align 3
.global fw_options
/*
* We can only use a0, a1, and a2 registers here.
* The 'a4' register will have default options.
* The next address should be returned in 'a0'.
*/
fw_options:
la a0, _dynamic_options
REG_L a0, (a0)
ret
.section .entry, "ax", %progbits
.align 3
_dynamic_next_arg1:
RISCV_PTR 0x0
_dynamic_next_addr:
RISCV_PTR 0x0
_dynamic_next_mode:
RISCV_PTR PRV_S
_dynamic_options:
RISCV_PTR 0x0
_dynamic_boot_hart:
RISCV_PTR -1

View File

@@ -0,0 +1,18 @@
/*
* SPDX-License-Identifier: BSD-2-Clause
*
* Copyright (c) 2019 Western Digital Corporation or its affiliates.
*
* Authors:
* Anup Patel <anup.patel@wdc.com>
*/
OUTPUT_ARCH(riscv)
ENTRY(_start)
SECTIONS
{
#include "fw_base.ldS"
PROVIDE(_fw_reloc_end = .);
}

View File

@@ -9,40 +9,101 @@
#include "fw_base.S" #include "fw_base.S"
.align 3
.section .entry, "ax", %progbits .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.
* The a0, a1, and a2 registers will be same as passed by
* previous booting stage.
* Nothing to be returned here.
*/
fw_save_info:
ret
.section .entry, "ax", %progbits
.align 3
.global fw_prev_arg1 .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: fw_prev_arg1:
/* We return previous arg1 in 'a0' */
add a0, zero, zero add a0, zero, zero
ret ret
.align 3
.section .entry, "ax", %progbits .section .entry, "ax", %progbits
.align 3
.global fw_next_arg1 .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: fw_next_arg1:
/* We return next arg1 in 'a0' */
#ifdef FW_JUMP_FDT_ADDR #ifdef FW_JUMP_FDT_ADDR
li a0, FW_JUMP_FDT_ADDR li a0, FW_JUMP_FDT_ADDR
#else #else
add a0, zero, zero add a0, a1, zero
#endif #endif
ret ret
.align 3
.section .entry, "ax", %progbits .section .entry, "ax", %progbits
.align 3
.global fw_next_addr .global fw_next_addr
/*
* We can only use a0, a1, and a2 registers here.
* The next address should be returned in 'a0'.
*/
fw_next_addr: fw_next_addr:
/* We return next address in 'a0' */
la a0, _jump_addr la a0, _jump_addr
REG_L a0, (a0) REG_L a0, (a0)
ret ret
.section .entry, "ax", %progbits
.align 3
.global fw_next_mode
/*
* We can only use a0, a1, and a2 registers here.
* The next address should be returned in 'a0'
*/
fw_next_mode:
li a0, PRV_S
ret
.section .entry, "ax", %progbits
.align 3
.global fw_options
/*
* We can only use a0, a1, and a2 registers here.
* The 'a4' register will have default options.
* The next address should be returned in 'a0'.
*/
fw_options:
add a0, zero, zero
ret
#ifndef FW_JUMP_ADDR #ifndef FW_JUMP_ADDR
#error "Must define FW_JUMP_ADDR" #error "Must define FW_JUMP_ADDR"
#endif #endif
.align 3
.section .entry, "ax", %progbits .section .entry, "ax", %progbits
.align 3
_jump_addr: _jump_addr:
RISCV_PTR FW_JUMP_ADDR RISCV_PTR FW_JUMP_ADDR

View File

@@ -13,4 +13,6 @@ ENTRY(_start)
SECTIONS SECTIONS
{ {
#include "fw_base.ldS" #include "fw_base.ldS"
PROVIDE(_fw_reloc_end = .);
} }

View File

@@ -9,11 +9,41 @@
#include "fw_base.S" #include "fw_base.S"
.align 4
.section .entry, "ax", %progbits .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.
* The a0, a1, and a2 registers will be same as passed by
* previous booting stage.
* Nothing to be returned here.
*/
fw_save_info:
ret
.section .entry, "ax", %progbits
.align 3
.global fw_prev_arg1 .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: fw_prev_arg1:
/* We return previous arg1 in 'a0' */
#ifdef FW_PAYLOAD_FDT_PATH #ifdef FW_PAYLOAD_FDT_PATH
la a0, fdt_bin la a0, fdt_bin
#else #else
@@ -21,36 +51,67 @@ fw_prev_arg1:
#endif #endif
ret ret
.align 4
.section .entry, "ax", %progbits .section .entry, "ax", %progbits
.align 3
.global fw_next_arg1 .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: fw_next_arg1:
/* We return next arg1 in 'a0' */
#ifdef FW_PAYLOAD_FDT_ADDR #ifdef FW_PAYLOAD_FDT_ADDR
li a0, FW_PAYLOAD_FDT_ADDR li a0, FW_PAYLOAD_FDT_ADDR
#else #else
add a0, zero, zero add a0, a1, zero
#endif #endif
ret ret
.align 4
.section .entry, "ax", %progbits .section .entry, "ax", %progbits
.align 3
.global fw_next_addr .global fw_next_addr
/*
* We can only use a0, a1, and a2 registers here.
* The next address should be returned in 'a0'.
*/
fw_next_addr: fw_next_addr:
/* We return next address in 'a0' */
la a0, payload_bin la a0, payload_bin
ret ret
.section .entry, "ax", %progbits
.align 3
.global fw_next_mode
/*
* We can only use a0, a1, and a2 registers here.
* The next address should be returned in 'a0'.
*/
fw_next_mode:
li a0, PRV_S
ret
.section .entry, "ax", %progbits
.align 3
.global fw_options
/*
* We can only use a0, a1, and a2 registers here.
* The 'a4' register will have default options.
* The next address should be returned in 'a0'.
*/
fw_options:
add a0, zero, zero
ret
#ifdef FW_PAYLOAD_FDT_PATH #ifdef FW_PAYLOAD_FDT_PATH
.align 4
.section .text, "ax", %progbits .section .text, "ax", %progbits
.align 4
.globl fdt_bin .globl fdt_bin
fdt_bin: fdt_bin:
.incbin FW_PAYLOAD_FDT_PATH .incbin FW_PAYLOAD_FDT_PATH
#endif #endif
.align 4
.section .payload, "ax", %progbits .section .payload, "ax", %progbits
.align 4
.globl payload_bin .globl payload_bin
payload_bin: payload_bin:
#ifndef FW_PAYLOAD_PATH #ifndef FW_PAYLOAD_PATH

View File

@@ -27,4 +27,6 @@ SECTIONS
. = ALIGN(8); . = ALIGN(8);
PROVIDE(_payload_end = .); PROVIDE(_payload_end = .);
} }
PROVIDE(_fw_reloc_end = .);
} }

View File

@@ -17,6 +17,8 @@ ifdef FW_TEXT_START
firmware-genflags-y += -DFW_TEXT_START=$(FW_TEXT_START) firmware-genflags-y += -DFW_TEXT_START=$(FW_TEXT_START)
endif endif
firmware-bins-$(FW_DYNAMIC) += fw_dynamic.bin
firmware-bins-$(FW_JUMP) += fw_jump.bin firmware-bins-$(FW_JUMP) += fw_jump.bin
ifdef FW_JUMP_ADDR ifdef FW_JUMP_ADDR
firmware-genflags-$(FW_JUMP) += -DFW_JUMP_ADDR=$(FW_JUMP_ADDR) firmware-genflags-$(FW_JUMP) += -DFW_JUMP_ADDR=$(FW_JUMP_ADDR)
@@ -29,7 +31,7 @@ firmware-bins-$(FW_PAYLOAD) += fw_payload.bin
ifdef FW_PAYLOAD_PATH ifdef FW_PAYLOAD_PATH
FW_PAYLOAD_PATH_FINAL=$(FW_PAYLOAD_PATH) FW_PAYLOAD_PATH_FINAL=$(FW_PAYLOAD_PATH)
else else
FW_PAYLOAD_PATH_FINAL=$(build_dir)/$(platform_subdir)/firmware/payloads/test.bin FW_PAYLOAD_PATH_FINAL=$(platform_build_dir)/firmware/payloads/test.bin
endif endif
firmware-genflags-$(FW_PAYLOAD) += -DFW_PAYLOAD_PATH=\"$(FW_PAYLOAD_PATH_FINAL)\" firmware-genflags-$(FW_PAYLOAD) += -DFW_PAYLOAD_PATH=\"$(FW_PAYLOAD_PATH_FINAL)\"
ifdef FW_PAYLOAD_OFFSET ifdef FW_PAYLOAD_OFFSET
@@ -41,7 +43,7 @@ endif
ifndef FW_PAYLOAD_FDT_PATH ifndef FW_PAYLOAD_FDT_PATH
ifdef FW_PAYLOAD_FDT ifdef FW_PAYLOAD_FDT
FW_PAYLOAD_FDT_PATH=$(build_dir)/$(platform_subdir)/$(FW_PAYLOAD_FDT) FW_PAYLOAD_FDT_PATH=$(platform_build_dir)/$(FW_PAYLOAD_FDT)
endif endif
endif endif
ifdef FW_PAYLOAD_FDT_PATH ifdef FW_PAYLOAD_FDT_PATH
@@ -50,3 +52,7 @@ endif
ifdef FW_PAYLOAD_FDT_ADDR ifdef FW_PAYLOAD_FDT_ADDR
firmware-genflags-$(FW_PAYLOAD) += -DFW_PAYLOAD_FDT_ADDR=$(FW_PAYLOAD_FDT_ADDR) firmware-genflags-$(FW_PAYLOAD) += -DFW_PAYLOAD_FDT_ADDR=$(FW_PAYLOAD_FDT_ADDR)
endif endif
ifdef FW_OPTIONS
firmware-genflags-y += -DFW_OPTIONS=$(FW_OPTIONS)
endif

View File

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

View File

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

79
include/sbi/fw_dynamic.h Normal file
View File

@@ -0,0 +1,79 @@
/*
* SPDX-License-Identifier: BSD-2-Clause
*
* Copyright (c) 2019 Western Digital Corporation or its affiliates.
*
* Authors:
* Anup Patel <anup.patel@wdc.com>
*/
#ifndef __FW_DYNAMIC_H__
#define __FW_DYNAMIC_H__
#include <sbi/riscv_asm.h>
/* clang-format off */
/** Offset of magic member in fw_dynamic_info */
#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 (version >= 1) */
#define FW_DYNAMIC_INFO_NEXT_ADDR_OFFSET (2 * __SIZEOF_POINTER__)
/** 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 (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 0x2
/** Possible next mode values */
#define FW_DYNAMIC_INFO_NEXT_MODE_U 0x0
#define FW_DYNAMIC_INFO_NEXT_MODE_S 0x1
#define FW_DYNAMIC_INFO_NEXT_MODE_M 0x3
/* clang-format on */
#ifndef __ASSEMBLY__
#include <sbi/sbi_types.h>
/** Representation dynamic info passed by previous booting stage */
struct fw_dynamic_info {
/** Info magic */
unsigned long magic;
/** Info version */
unsigned long version;
/** Next booting stage address */
unsigned long next_addr;
/** Next booting stage mode */
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
#endif

View File

@@ -12,6 +12,8 @@
#include <sbi/riscv_encoding.h> #include <sbi/riscv_encoding.h>
/* clang-format off */
#ifdef __ASSEMBLY__ #ifdef __ASSEMBLY__
#define __ASM_STR(x) x #define __ASM_STR(x) x
#else #else
@@ -26,6 +28,10 @@
#error "Unexpected __riscv_xlen" #error "Unexpected __riscv_xlen"
#endif #endif
#define PAGE_SHIFT (12)
#define PAGE_SIZE (_AC(1, UL) << PAGE_SHIFT)
#define PAGE_MASK (~(PAGE_SIZE - 1))
#define REG_L __REG_SEL(ld, lw) #define REG_L __REG_SEL(ld, lw)
#define REG_S __REG_SEL(sd, sw) #define REG_S __REG_SEL(sd, sw)
#define SZREG __REG_SEL(8, 4) #define SZREG __REG_SEL(8, 4)
@@ -73,93 +79,106 @@
#error "Unexpected __SIZEOF_SHORT__" #error "Unexpected __SIZEOF_SHORT__"
#endif #endif
/* clang-format on */
#ifndef __ASSEMBLY__ #ifndef __ASSEMBLY__
#define csr_swap(csr, val) \ #define csr_swap(csr, val) \
({ \ ({ \
unsigned long __v = (unsigned long)(val); \ unsigned long __v = (unsigned long)(val); \
__asm__ __volatile__ ("csrrw %0, " __ASM_STR(csr) ", %1"\ __asm__ __volatile__("csrrw %0, " __ASM_STR(csr) ", %1" \
: "=r" (__v) : "rK" (__v) \ : "=r"(__v) \
: "memory"); \ : "rK"(__v) \
__v; \ : "memory"); \
}) __v; \
})
#define csr_read(csr) \ #define csr_read(csr) \
({ \ ({ \
register unsigned long __v; \ register unsigned long __v; \
__asm__ __volatile__ ("csrr %0, " __ASM_STR(csr) \ __asm__ __volatile__("csrr %0, " __ASM_STR(csr) \
: "=r" (__v) : \ : "=r"(__v) \
: "memory"); \ : \
__v; \ : "memory"); \
}) __v; \
})
#define csr_write(csr, val) \ #define csr_write(csr, val) \
({ \ ({ \
unsigned long __v = (unsigned long)(val); \ unsigned long __v = (unsigned long)(val); \
__asm__ __volatile__ ("csrw " __ASM_STR(csr) ", %0" \ __asm__ __volatile__("csrw " __ASM_STR(csr) ", %0" \
: : "rK" (__v) \ : \
: "memory"); \ : "rK"(__v) \
}) : "memory"); \
})
#define csr_read_set(csr, val) \ #define csr_read_set(csr, val) \
({ \ ({ \
unsigned long __v = (unsigned long)(val); \ unsigned long __v = (unsigned long)(val); \
__asm__ __volatile__ ("csrrs %0, " __ASM_STR(csr) ", %1"\ __asm__ __volatile__("csrrs %0, " __ASM_STR(csr) ", %1" \
: "=r" (__v) : "rK" (__v) \ : "=r"(__v) \
: "memory"); \ : "rK"(__v) \
__v; \ : "memory"); \
}) __v; \
})
#define csr_set(csr, val) \ #define csr_set(csr, val) \
({ \ ({ \
unsigned long __v = (unsigned long)(val); \ unsigned long __v = (unsigned long)(val); \
__asm__ __volatile__ ("csrs " __ASM_STR(csr) ", %0" \ __asm__ __volatile__("csrs " __ASM_STR(csr) ", %0" \
: : "rK" (__v) \ : \
: "memory"); \ : "rK"(__v) \
}) : "memory"); \
})
#define csr_read_clear(csr, val) \ #define csr_read_clear(csr, val) \
({ \ ({ \
unsigned long __v = (unsigned long)(val); \ unsigned long __v = (unsigned long)(val); \
__asm__ __volatile__ ("csrrc %0, " __ASM_STR(csr) ", %1"\ __asm__ __volatile__("csrrc %0, " __ASM_STR(csr) ", %1" \
: "=r" (__v) : "rK" (__v) \ : "=r"(__v) \
: "memory"); \ : "rK"(__v) \
__v; \ : "memory"); \
}) __v; \
})
#define csr_clear(csr, val) \ #define csr_clear(csr, val) \
({ \ ({ \
unsigned long __v = (unsigned long)(val); \ unsigned long __v = (unsigned long)(val); \
__asm__ __volatile__ ("csrc " __ASM_STR(csr) ", %0" \ __asm__ __volatile__("csrc " __ASM_STR(csr) ", %0" \
: : "rK" (__v) \ : \
: "memory"); \ : "rK"(__v) \
}) : "memory"); \
})
unsigned long csr_read_num(int csr_num); unsigned long csr_read_num(int csr_num);
void csr_write_num(int csr_num, unsigned long val); void csr_write_num(int csr_num, unsigned long val);
#define wfi() \ #define wfi() \
do { \ do { \
__asm__ __volatile__ ("wfi" ::: "memory"); \ __asm__ __volatile__("wfi" ::: "memory"); \
} while (0) } while (0)
static inline int misa_extension(char ext)
{
return csr_read(CSR_MISA) & (1 << (ext - 'A'));
}
static inline int misa_xlen(void) /* determine CPU extension, return non-zero support */
{ int misa_extension_imp(char ext);
return ((long)csr_read(CSR_MISA) < 0) ? 64 : 32;
} #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) 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++) { for (i = 0; i < 26; i++) {
if (val & (1 << i)) { if (misa_extension_imp('A' + i)) {
*out = 'A' + i; *out = 'A' + i;
out++; out++;
} }
@@ -168,11 +187,11 @@ static inline void misa_string(char *out, unsigned int out_sz)
out++; out++;
} }
int pmp_set(unsigned int n, unsigned long prot, int pmp_set(unsigned int n, unsigned long prot, unsigned long addr,
unsigned long addr, unsigned long log2len); unsigned long log2len);
int pmp_get(unsigned int n, unsigned long *prot_out, int pmp_get(unsigned int n, unsigned long *prot_out, unsigned long *addr_out,
unsigned long *addr_out, unsigned long *log2len_out); unsigned long *log2len_out);
#endif /* !__ASSEMBLY__ */ #endif /* !__ASSEMBLY__ */

View File

@@ -14,11 +14,12 @@ typedef struct {
volatile long counter; volatile long counter;
} atomic_t; } atomic_t;
#define ATOMIC_INIT(_lptr, val) \ #define ATOMIC_INIT(_lptr, val) (_lptr)->counter = (val)
(_lptr)->counter = (val)
#define ATOMIC_INITIALIZER(val) \ #define ATOMIC_INITIALIZER(val) \
{ .counter = (val), } { \
.counter = (val), \
}
long atomic_read(atomic_t *atom); long atomic_read(atomic_t *atom);
@@ -34,6 +35,9 @@ long arch_atomic_xchg(atomic_t *atom, long newval);
unsigned int atomic_raw_xchg_uint(volatile unsigned int *ptr, unsigned int atomic_raw_xchg_uint(volatile unsigned int *ptr,
unsigned int newval); unsigned int newval);
unsigned long atomic_raw_xchg_ulong(volatile unsigned long *ptr,
unsigned long newval);
/** /**
* Set a bit in an atomic variable and return the new value. * Set a bit in an atomic variable and return the new value.
* @nr : Bit to set. * @nr : Bit to set.

View File

@@ -10,6 +10,8 @@
#ifndef __RISCV_BARRIER_H__ #ifndef __RISCV_BARRIER_H__
#define __RISCV_BARRIER_H__ #define __RISCV_BARRIER_H__
/* clang-format off */
#define RISCV_ACQUIRE_BARRIER "\tfence r , rw\n" #define RISCV_ACQUIRE_BARRIER "\tfence r , rw\n"
#define RISCV_RELEASE_BARRIER "\tfence rw, w\n" #define RISCV_RELEASE_BARRIER "\tfence rw, w\n"
@@ -37,17 +39,19 @@
/* CPU relax for busy loop */ /* CPU relax for busy loop */
#define cpu_relax() asm volatile ("" : : : "memory") #define cpu_relax() asm volatile ("" : : : "memory")
#define __smp_store_release(p, v) \ /* clang-format on */
do { \
RISCV_FENCE(rw,w); \
*(p) = (v); \
} while (0)
#define __smp_load_acquire(p) \ #define __smp_store_release(p, v) \
({ \ do { \
typeof(*p) ___p1 = *(p); \ RISCV_FENCE(rw, w); \
RISCV_FENCE(r,rw); \ *(p) = (v); \
___p1; \ } while (0)
})
#define __smp_load_acquire(p) \
({ \
typeof(*p) ___p1 = *(p); \
RISCV_FENCE(r, rw); \
___p1; \
})
#endif #endif

View File

@@ -12,169 +12,125 @@
#include <sbi/sbi_const.h> #include <sbi/sbi_const.h>
/* TODO: Make constants usable in assembly with _AC() macro */ /* clang-format off */
#define MSTATUS_SIE _UL(0x00000002)
#define MSTATUS_UIE 0x00000001 #define MSTATUS_MIE _UL(0x00000008)
#define MSTATUS_SIE 0x00000002
#define MSTATUS_HIE 0x00000004
#define MSTATUS_MIE 0x00000008
#define MSTATUS_UPIE 0x00000010
#define MSTATUS_SPIE_SHIFT 5 #define MSTATUS_SPIE_SHIFT 5
#define MSTATUS_SPIE (1UL << MSTATUS_SPIE_SHIFT) #define MSTATUS_SPIE (_UL(1) << MSTATUS_SPIE_SHIFT)
#define MSTATUS_HPIE 0x00000040 #define MSTATUS_UBE _UL(0x00000040)
#define MSTATUS_MPIE 0x00000080 #define MSTATUS_MPIE _UL(0x00000080)
#define MSTATUS_SPP_SHIFT 8 #define MSTATUS_SPP_SHIFT 8
#define MSTATUS_SPP (1UL << MSTATUS_SPP_SHIFT) #define MSTATUS_SPP (_UL(1) << MSTATUS_SPP_SHIFT)
#define MSTATUS_HPP 0x00000600
#define MSTATUS_MPP_SHIFT 11 #define MSTATUS_MPP_SHIFT 11
#define MSTATUS_MPP (3UL << MSTATUS_MPP_SHIFT) #define MSTATUS_MPP (_UL(3) << MSTATUS_MPP_SHIFT)
#define MSTATUS_FS 0x00006000 #define MSTATUS_FS _UL(0x00006000)
#define MSTATUS_XS 0x00018000 #define MSTATUS_XS _UL(0x00018000)
#define MSTATUS_MPRV 0x00020000 #define MSTATUS_MPRV _UL(0x00020000)
#define MSTATUS_SUM 0x00040000 #define MSTATUS_SUM _UL(0x00040000)
#define MSTATUS_MXR 0x00080000 #define MSTATUS_MXR _UL(0x00080000)
#define MSTATUS_TVM 0x00100000 #define MSTATUS_TVM _UL(0x00100000)
#define MSTATUS_TW 0x00200000 #define MSTATUS_TW _UL(0x00200000)
#define MSTATUS_TSR 0x00400000 #define MSTATUS_TSR _UL(0x00400000)
#define MSTATUS32_SD 0x80000000 #define MSTATUS32_SD _UL(0x80000000)
#define MSTATUS_UXL 0x0000000300000000 #if __riscv_xlen == 64
#define MSTATUS_SXL 0x0000000C00000000 #define MSTATUS_UXL _ULL(0x0000000300000000)
#define MSTATUS64_SD 0x8000000000000000 #define MSTATUS_SXL _ULL(0x0000000C00000000)
#define MSTATUS_SBE _ULL(0x0000001000000000)
#define MSTATUS_MBE _ULL(0x0000002000000000)
#define MSTATUS_MPV _ULL(0x0000008000000000)
#else
#define MSTATUSH_SBE _UL(0x00000010)
#define MSTATUSH_MBE _UL(0x00000020)
#define MSTATUSH_MPV _UL(0x00000080)
#endif
#define MSTATUS32_SD _UL(0x80000000)
#define MSTATUS64_SD _ULL(0x8000000000000000)
#define SSTATUS_UIE 0x00000001 #define SSTATUS_SIE MSTATUS_SIE
#define SSTATUS_SIE 0x00000002 #define SSTATUS_SPIE_SHIFT MSTATUS_SPIE_SHIFT
#define SSTATUS_UPIE 0x00000010 #define SSTATUS_SPIE MSTATUS_SPIE
#define SSTATUS_SPIE 0x00000020 #define SSTATUS_SPP_SHIFT MSTATUS_SPP_SHIFT
#define SSTATUS_SPP 0x00000100 #define SSTATUS_SPP MSTATUS_SPP
#define SSTATUS_FS 0x00006000 #define SSTATUS_FS MSTATUS_FS
#define SSTATUS_XS 0x00018000 #define SSTATUS_XS MSTATUS_XS
#define SSTATUS_SUM 0x00040000 #define SSTATUS_SUM MSTATUS_SUM
#define SSTATUS_MXR 0x00080000 #define SSTATUS_MXR MSTATUS_MXR
#define SSTATUS32_SD 0x80000000 #define SSTATUS32_SD MSTATUS32_SD
#define SSTATUS_UXL 0x0000000300000000 #define SSTATUS64_UXL MSTATUS_UXL
#define SSTATUS64_SD 0x8000000000000000 #define SSTATUS64_SD MSTATUS64_SD
#define DCSR_XDEBUGVER (3U<<30) #define HSTATUS_VTSR _UL(0x00400000)
#define DCSR_NDRESET (1<<29) #define HSTATUS_VTVM _UL(0x00100000)
#define DCSR_FULLRESET (1<<28) #define HSTATUS_SP2V _UL(0x00000200)
#define DCSR_EBREAKM (1<<15) #define HSTATUS_SP2P _UL(0x00000100)
#define DCSR_EBREAKH (1<<14) #define HSTATUS_SPV _UL(0x00000080)
#define DCSR_EBREAKS (1<<13) #define HSTATUS_SPRV _UL(0x00000001)
#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 IRQ_S_SOFT 1 #define IRQ_S_SOFT 1
#define IRQ_H_SOFT 2 #define IRQ_VS_SOFT 2
#define IRQ_M_SOFT 3 #define IRQ_M_SOFT 3
#define IRQ_S_TIMER 5 #define IRQ_S_TIMER 5
#define IRQ_H_TIMER 6 #define IRQ_VS_TIMER 6
#define IRQ_M_TIMER 7 #define IRQ_M_TIMER 7
#define IRQ_S_EXT 9 #define IRQ_S_EXT 9
#define IRQ_H_EXT 10 #define IRQ_VS_EXT 10
#define IRQ_M_EXT 11 #define IRQ_M_EXT 11
#define IRQ_COP 12 #define IRQ_S_GEXT 12
#define IRQ_HOST 13
#define MIP_SSIP (1 << IRQ_S_SOFT) #define MIP_SSIP (_UL(1) << IRQ_S_SOFT)
#define MIP_HSIP (1 << IRQ_H_SOFT) #define MIP_VSSIP (_UL(1) << IRQ_VS_SOFT)
#define MIP_MSIP (1 << IRQ_M_SOFT) #define MIP_MSIP (_UL(1) << IRQ_M_SOFT)
#define MIP_STIP (1 << IRQ_S_TIMER) #define MIP_STIP (_UL(1) << IRQ_S_TIMER)
#define MIP_HTIP (1 << IRQ_H_TIMER) #define MIP_VSTIP (_UL(1) << IRQ_VS_TIMER)
#define MIP_MTIP (1 << IRQ_M_TIMER) #define MIP_MTIP (_UL(1) << IRQ_M_TIMER)
#define MIP_SEIP (1 << IRQ_S_EXT) #define MIP_SEIP (_UL(1) << IRQ_S_EXT)
#define MIP_HEIP (1 << IRQ_H_EXT) #define MIP_VSEIP (_UL(1) << IRQ_VS_EXT)
#define MIP_MEIP (1 << IRQ_M_EXT) #define MIP_MEIP (_UL(1) << IRQ_M_EXT)
#define MIP_SGEIP (_UL(1) << IRQ_S_GEXT)
#define SIP_SSIP MIP_SSIP #define SIP_SSIP MIP_SSIP
#define SIP_STIP MIP_STIP #define SIP_STIP MIP_STIP
#define PRV_U 0 #define PRV_U _UL(0)
#define PRV_S 1 #define PRV_S _UL(1)
#define PRV_H 2 #define PRV_M _UL(3)
#define PRV_M 3
#define SATP32_MODE 0x80000000 #define SATP32_MODE _UL(0x80000000)
#define SATP32_ASID 0x7FC00000 #define SATP32_ASID _UL(0x7FC00000)
#define SATP32_PPN 0x003FFFFF #define SATP32_PPN _UL(0x003FFFFF)
#define SATP64_MODE 0xF000000000000000 #define SATP64_MODE _ULL(0xF000000000000000)
#define SATP64_ASID 0x0FFFF00000000000 #define SATP64_ASID _ULL(0x0FFFF00000000000)
#define SATP64_PPN 0x00000FFFFFFFFFFF #define SATP64_PPN _ULL(0x00000FFFFFFFFFFF)
#define SATP_MODE_OFF 0 #define SATP_MODE_OFF _UL(0)
#define SATP_MODE_SV32 1 #define SATP_MODE_SV32 _UL(1)
#define SATP_MODE_SV39 8 #define SATP_MODE_SV39 _UL(8)
#define SATP_MODE_SV48 9 #define SATP_MODE_SV48 _UL(9)
#define SATP_MODE_SV57 10 #define SATP_MODE_SV57 _UL(10)
#define SATP_MODE_SV64 11 #define SATP_MODE_SV64 _UL(11)
#define PMP_R 0x01 #define PMP_R _UL(0x01)
#define PMP_W 0x02 #define PMP_W _UL(0x02)
#define PMP_X 0x04 #define PMP_X _UL(0x04)
#define PMP_A 0x18 #define PMP_A _UL(0x18)
#define PMP_A_TOR 0x08 #define PMP_A_TOR _UL(0x08)
#define PMP_A_NA4 0x10 #define PMP_A_NA4 _UL(0x10)
#define PMP_A_NAPOT 0x18 #define PMP_A_NAPOT _UL(0x18)
#define PMP_L 0x80 #define PMP_L _UL(0x80)
#define PMP_SHIFT 2 #define PMP_SHIFT 2
#define PMP_COUNT 16 #define PMP_COUNT 16
/* page table entry (PTE) fields */ /* page table entry (PTE) fields */
#define PTE_V 0x001 /* Valid */ #define PTE_V _UL(0x001) /* Valid */
#define PTE_R 0x002 /* Read */ #define PTE_R _UL(0x002) /* Read */
#define PTE_W 0x004 /* Write */ #define PTE_W _UL(0x004) /* Write */
#define PTE_X 0x008 /* Execute */ #define PTE_X _UL(0x008) /* Execute */
#define PTE_U 0x010 /* User */ #define PTE_U _UL(0x010) /* User */
#define PTE_G 0x020 /* Global */ #define PTE_G _UL(0x020) /* Global */
#define PTE_A 0x040 /* Accessed */ #define PTE_A _UL(0x040) /* Accessed */
#define PTE_D 0x080 /* Dirty */ #define PTE_D _UL(0x080) /* Dirty */
#define PTE_SOFT 0x300 /* Reserved for Software */ #define PTE_SOFT _UL(0x300) /* Reserved for Software */
#define PTE_PPN_SHIFT 10 #define PTE_PPN_SHIFT 10
@@ -248,6 +204,31 @@
#define CSR_STVAL 0x143 #define CSR_STVAL 0x143
#define CSR_SIP 0x144 #define CSR_SIP 0x144
#define CSR_SATP 0x180 #define CSR_SATP 0x180
#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
#define CSR_VSTVEC 0x205
#define CSR_VSSCRATCH 0x240
#define CSR_VSEPC 0x241
#define CSR_VSCAUSE 0x242
#define CSR_VSTVAL 0x243
#define CSR_VSIP 0x244
#define CSR_VSATP 0x280
#define CSR_MSTATUS 0x300 #define CSR_MSTATUS 0x300
#define CSR_MISA 0x301 #define CSR_MISA 0x301
#define CSR_MEDELEG 0x302 #define CSR_MEDELEG 0x302
@@ -255,11 +236,14 @@
#define CSR_MIE 0x304 #define CSR_MIE 0x304
#define CSR_MTVEC 0x305 #define CSR_MTVEC 0x305
#define CSR_MCOUNTEREN 0x306 #define CSR_MCOUNTEREN 0x306
#define CSR_MSTATUSH 0x310
#define CSR_MSCRATCH 0x340 #define CSR_MSCRATCH 0x340
#define CSR_MEPC 0x341 #define CSR_MEPC 0x341
#define CSR_MCAUSE 0x342 #define CSR_MCAUSE 0x342
#define CSR_MTVAL 0x343 #define CSR_MTVAL 0x343
#define CSR_MIP 0x344 #define CSR_MIP 0x344
#define CSR_MTINST 0x34a
#define CSR_MTVAL2 0x34b
#define CSR_PMPCFG0 0x3a0 #define CSR_PMPCFG0 0x3a0
#define CSR_PMPCFG1 0x3a1 #define CSR_PMPCFG1 0x3a1
#define CSR_PMPCFG2 0x3a2 #define CSR_PMPCFG2 0x3a2
@@ -287,6 +271,7 @@
#define CSR_DCSR 0x7b0 #define CSR_DCSR 0x7b0
#define CSR_DPC 0x7b1 #define CSR_DPC 0x7b1
#define CSR_DSCRATCH 0x7b2 #define CSR_DSCRATCH 0x7b2
#define CSR_MCYCLE 0xb00 #define CSR_MCYCLE 0xb00
#define CSR_MINSTRET 0xb02 #define CSR_MINSTRET 0xb02
#define CSR_MHPMCOUNTER3 0xb03 #define CSR_MHPMCOUNTER3 0xb03
@@ -424,12 +409,15 @@
#define CAUSE_MISALIGNED_STORE 0x6 #define CAUSE_MISALIGNED_STORE 0x6
#define CAUSE_STORE_ACCESS 0x7 #define CAUSE_STORE_ACCESS 0x7
#define CAUSE_USER_ECALL 0x8 #define CAUSE_USER_ECALL 0x8
#define CAUSE_SUPERVISOR_ECALL 0x9 #define CAUSE_HYPERVISOR_ECALL 0x9
#define CAUSE_HYPERVISOR_ECALL 0xa #define CAUSE_SUPERVISOR_ECALL 0xa
#define CAUSE_MACHINE_ECALL 0xb #define CAUSE_MACHINE_ECALL 0xb
#define CAUSE_FETCH_PAGE_FAULT 0xc #define CAUSE_FETCH_PAGE_FAULT 0xc
#define CAUSE_LOAD_PAGE_FAULT 0xd #define CAUSE_LOAD_PAGE_FAULT 0xd
#define CAUSE_STORE_PAGE_FAULT 0xf #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_MATCH_LB 0x3
#define INSN_MASK_LB 0x707f #define INSN_MASK_LB 0x707f
@@ -501,7 +489,19 @@
#define INSN_MATCH_C_FSWSP 0xe002 #define INSN_MATCH_C_FSWSP 0xe002
#define INSN_MASK_C_FSWSP 0xe003 #define INSN_MASK_C_FSWSP 0xe003
#define INSN_LEN(insn) ((((insn) & 0x3) < 0x3) ? 2 : 4) #define INSN_MASK_WFI 0xffffff00
#define INSN_MATCH_WFI 0x10500000
#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 #if __riscv_xlen == 64
#define LOG_REGBYTES 3 #define LOG_REGBYTES 3
@@ -561,4 +561,6 @@
(s32)(((insn) >> 7) & 0x1f)) (s32)(((insn) >> 7) & 0x1f))
#define MASK_FUNCT3 0x7000 #define MASK_FUNCT3 0x7000
/* clang-format on */
#endif #endif

View File

@@ -21,28 +21,49 @@
#ifdef __riscv_flen #ifdef __riscv_flen
#define GET_F32_REG(insn, pos, regs) ({ \ #define GET_F32_REG(insn, pos, regs) \
register s32 value asm("a0") = SHIFT_RIGHT(insn, (pos)-3) & 0xf8; \ ({ \
ulong tmp; \ register s32 value asm("a0") = \
asm ("1: auipc %0, %%pcrel_hi(get_f32_reg); add %0, %0, %1; jalr t0, %0, %%pcrel_lo(1b)" : "=&r"(tmp), "+&r"(value) :: "t0"); \ SHIFT_RIGHT(insn, (pos)-3) & 0xf8; \
value; }) ulong tmp; \
#define SET_F32_REG(insn, pos, regs, val) ({ \ asm("1: auipc %0, %%pcrel_hi(get_f32_reg); add %0, %0, %1; jalr t0, %0, %%pcrel_lo(1b)" \
register u32 value asm("a0") = (val); \ : "=&r"(tmp), "+&r"(value)::"t0"); \
ulong offset = SHIFT_RIGHT(insn, (pos)-3) & 0xf8; \ value; \
ulong tmp; \ })
asm volatile ("1: auipc %0, %%pcrel_hi(put_f32_reg); add %0, %0, %2; jalr t0, %0, %%pcrel_lo(1b)" : "=&r"(tmp) : "r"(value), "r"(offset) : "t0"); }) #define SET_F32_REG(insn, pos, regs, val) \
({ \
register u32 value asm("a0") = (val); \
ulong offset = SHIFT_RIGHT(insn, (pos)-3) & 0xf8; \
ulong tmp; \
asm volatile( \
"1: auipc %0, %%pcrel_hi(put_f32_reg); add %0, %0, %2; jalr t0, %0, %%pcrel_lo(1b)" \
: "=&r"(tmp) \
: "r"(value), "r"(offset) \
: "t0"); \
})
#define init_fp_reg(i) SET_F32_REG((i) << 3, 3, 0, 0) #define init_fp_reg(i) SET_F32_REG((i) << 3, 3, 0, 0)
#define GET_F64_REG(insn, pos, regs) ({ \ #define GET_F64_REG(insn, pos, regs) \
register ulong value asm("a0") = SHIFT_RIGHT(insn, (pos)-3) & 0xf8; \ ({ \
ulong tmp; \ register ulong value asm("a0") = \
asm ("1: auipc %0, %%pcrel_hi(get_f64_reg); add %0, %0, %1; jalr t0, %0, %%pcrel_lo(1b)" : "=&r"(tmp), "+&r"(value) :: "t0"); \ SHIFT_RIGHT(insn, (pos)-3) & 0xf8; \
sizeof(ulong) == 4 ? *(int64_t*)value : (int64_t)value; }) ulong tmp; \
#define SET_F64_REG(insn, pos, regs, val) ({ \ asm("1: auipc %0, %%pcrel_hi(get_f64_reg); add %0, %0, %1; jalr t0, %0, %%pcrel_lo(1b)" \
uint64_t __val = (val); \ : "=&r"(tmp), "+&r"(value)::"t0"); \
register ulong value asm("a0") = sizeof(ulong) == 4 ? (ulong)&__val : (ulong)__val; \ sizeof(ulong) == 4 ? *(int64_t *)value : (int64_t)value; \
ulong offset = SHIFT_RIGHT(insn, (pos)-3) & 0xf8; \ })
ulong tmp; \ #define SET_F64_REG(insn, pos, regs, val) \
asm volatile ("1: auipc %0, %%pcrel_hi(put_f64_reg); add %0, %0, %2; jalr t0, %0, %%pcrel_lo(1b)" : "=&r"(tmp) : "r"(value), "r"(offset) : "t0"); }) ({ \
uint64_t __val = (val); \
register ulong value asm("a0") = \
sizeof(ulong) == 4 ? (ulong)&__val : (ulong)__val; \
ulong offset = SHIFT_RIGHT(insn, (pos)-3) & 0xf8; \
ulong tmp; \
asm volatile( \
"1: auipc %0, %%pcrel_hi(put_f64_reg); add %0, %0, %2; jalr t0, %0, %%pcrel_lo(1b)" \
: "=&r"(tmp) \
: "r"(value), "r"(offset) \
: "t0"); \
})
#define GET_FCSR() csr_read(CSR_FCSR) #define GET_FCSR() csr_read(CSR_FCSR)
#define SET_FCSR(value) csr_write(CSR_FCSR, (value)) #define SET_FCSR(value) csr_write(CSR_FCSR, (value))
#define GET_FRM() csr_read(CSR_FRM) #define GET_FRM() csr_read(CSR_FRM)
@@ -50,11 +71,7 @@
#define GET_FFLAGS() csr_read(CSR_FFLAGS) #define GET_FFLAGS() csr_read(CSR_FFLAGS)
#define SET_FFLAGS(value) csr_write(CSR_FFLAGS, (value)) #define SET_FFLAGS(value) csr_write(CSR_FFLAGS, (value))
#define SET_FS_DIRTY() ((void) 0) #define SET_FS_DIRTY() ((void)0)
#else
#error "Floating point emulation not supported.\n"
#endif
#define GET_F32_RS1(insn, regs) (GET_F32_REG(insn, 15, regs)) #define GET_F32_RS1(insn, regs) (GET_F32_REG(insn, 15, regs))
#define GET_F32_RS2(insn, regs) (GET_F32_REG(insn, 20, regs)) #define GET_F32_RS2(insn, regs) (GET_F32_REG(insn, 20, regs))
@@ -62,8 +79,10 @@
#define GET_F64_RS1(insn, regs) (GET_F64_REG(insn, 15, regs)) #define GET_F64_RS1(insn, regs) (GET_F64_REG(insn, 15, regs))
#define GET_F64_RS2(insn, regs) (GET_F64_REG(insn, 20, regs)) #define GET_F64_RS2(insn, regs) (GET_F64_REG(insn, 20, regs))
#define GET_F64_RS3(insn, regs) (GET_F64_REG(insn, 27, regs)) #define GET_F64_RS3(insn, regs) (GET_F64_REG(insn, 27, regs))
#define SET_F32_RD(insn, regs, val) (SET_F32_REG(insn, 7, regs, val), SET_FS_DIRTY()) #define SET_F32_RD(insn, regs, val) \
#define SET_F64_RD(insn, regs, val) (SET_F64_REG(insn, 7, regs, val), SET_FS_DIRTY()) (SET_F32_REG(insn, 7, regs, val), SET_FS_DIRTY())
#define SET_F64_RD(insn, regs, val) \
(SET_F64_REG(insn, 7, regs, val), SET_FS_DIRTY())
#define GET_F32_RS2C(insn, regs) (GET_F32_REG(insn, 2, regs)) #define GET_F32_RS2C(insn, regs) (GET_F32_REG(insn, 2, regs))
#define GET_F32_RS2S(insn, regs) (GET_F32_REG(RVC_RS2S(insn), 0, regs)) #define GET_F32_RS2S(insn, regs) (GET_F32_REG(RVC_RS2S(insn), 0, regs))
@@ -71,3 +90,5 @@
#define GET_F64_RS2S(insn, regs) (GET_F64_REG(RVC_RS2S(insn), 0, regs)) #define GET_F64_RS2S(insn, regs) (GET_F64_REG(RVC_RS2S(insn), 0, regs))
#endif #endif
#endif

View File

@@ -15,23 +15,23 @@
static inline void __raw_writeb(u8 val, volatile void *addr) static inline void __raw_writeb(u8 val, volatile void *addr)
{ {
asm volatile("sb %0, 0(%1)" : : "r" (val), "r" (addr)); asm volatile("sb %0, 0(%1)" : : "r"(val), "r"(addr));
} }
static inline void __raw_writew(u16 val, volatile void *addr) static inline void __raw_writew(u16 val, volatile void *addr)
{ {
asm volatile("sh %0, 0(%1)" : : "r" (val), "r" (addr)); asm volatile("sh %0, 0(%1)" : : "r"(val), "r"(addr));
} }
static inline void __raw_writel(u32 val, volatile void *addr) static inline void __raw_writel(u32 val, volatile void *addr)
{ {
asm volatile("sw %0, 0(%1)" : : "r" (val), "r" (addr)); asm volatile("sw %0, 0(%1)" : : "r"(val), "r"(addr));
} }
#if __riscv_xlen != 32 #if __riscv_xlen != 32
static inline void __raw_writeq(u64 val, volatile void *addr) static inline void __raw_writeq(u64 val, volatile void *addr)
{ {
asm volatile("sd %0, 0(%1)" : : "r" (val), "r" (addr)); asm volatile("sd %0, 0(%1)" : : "r"(val), "r"(addr));
} }
#endif #endif
@@ -39,7 +39,7 @@ static inline u8 __raw_readb(const volatile void *addr)
{ {
u8 val; u8 val;
asm volatile("lb %0, 0(%1)" : "=r" (val) : "r" (addr)); asm volatile("lb %0, 0(%1)" : "=r"(val) : "r"(addr));
return val; return val;
} }
@@ -47,7 +47,7 @@ static inline u16 __raw_readw(const volatile void *addr)
{ {
u16 val; u16 val;
asm volatile("lh %0, 0(%1)" : "=r" (val) : "r" (addr)); asm volatile("lh %0, 0(%1)" : "=r"(val) : "r"(addr));
return val; return val;
} }
@@ -55,7 +55,7 @@ static inline u32 __raw_readl(const volatile void *addr)
{ {
u32 val; u32 val;
asm volatile("lw %0, 0(%1)" : "=r" (val) : "r" (addr)); asm volatile("lw %0, 0(%1)" : "=r"(val) : "r"(addr));
return val; return val;
} }
@@ -64,12 +64,15 @@ static inline u64 __raw_readq(const volatile void *addr)
{ {
u64 val; u64 val;
asm volatile("ld %0, 0(%1)" : "=r" (val) : "r" (addr)); asm volatile("ld %0, 0(%1)" : "=r"(val) : "r"(addr));
return val; return val;
} }
#endif #endif
/* FIXME: These are now the same as asm-generic */ /* FIXME: These are now the same as asm-generic */
/* clang-format off */
#define __io_rbr() do {} while (0) #define __io_rbr() do {} while (0)
#define __io_rar() do {} while (0) #define __io_rar() do {} while (0)
#define __io_rbw() do {} while (0) #define __io_rbw() do {} while (0)
@@ -106,4 +109,6 @@ static inline u64 __raw_readq(const volatile void *addr)
#define writeq(v,c) ({ __io_bw(); __raw_writeq((v),(c)); __io_aw(); }) #define writeq(v,c) ({ __io_bw(); __raw_writeq((v),(c)); __io_aw(); })
#endif #endif
/* clang-format on */
#endif #endif

View File

@@ -14,13 +14,14 @@ typedef struct {
volatile long lock; volatile long lock;
} spinlock_t; } spinlock_t;
#define __RISCV_SPIN_UNLOCKED 0 #define __RISCV_SPIN_UNLOCKED 0
#define SPIN_LOCK_INIT(_lptr) \ #define SPIN_LOCK_INIT(_lptr) (_lptr)->lock = __RISCV_SPIN_UNLOCKED
(_lptr)->lock = __RISCV_SPIN_UNLOCKED
#define SPIN_LOCK_INITIALIZER \ #define SPIN_LOCK_INITIALIZER \
{ .lock = __RISCV_SPIN_UNLOCKED, } { \
.lock = __RISCV_SPIN_UNLOCKED, \
}
int spin_lock_check(spinlock_t *lock); int spin_lock_check(spinlock_t *lock);

View File

@@ -93,6 +93,80 @@ static inline int __ffs(unsigned long word)
* *
* Undefined if no zero exists, so code should check against ~0UL first. * Undefined if no zero exists, so code should check against ~0UL first.
*/ */
#define ffz(x) __ffs(~(x)) #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 #endif

View File

@@ -10,22 +10,10 @@
#ifndef __SBI_BITS_H__ #ifndef __SBI_BITS_H__
#define __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 EXTRACT_FIELD(val, which) (((val) & (which)) / ((which) & ~((which)-1)))
#define INSERT_FIELD(val, which, fieldval) (((val) & ~(which)) | ((fieldval) * ((which) & ~((which)-1)))) #define INSERT_FIELD(val, which, fieldval) \
(((val) & ~(which)) | ((fieldval) * ((which) & ~((which)-1))))
#define STR(x) XSTR(x) #define BIT_MASK(nr) (1UL << ((nr) % BITS_PER_LONG))
#define XSTR(x) #x #define BIT_WORD(nr) ((nr) / BITS_PER_LONG)
#define BIT_MASK(nr) (1UL << ((nr) % BITS_PER_LONG))
#define BIT_WORD(nr) ((nr) / BITS_PER_LONG)
#endif #endif

View File

@@ -12,11 +12,11 @@
#include <sbi/sbi_types.h> #include <sbi/sbi_types.h>
#define __printf(a, b) __attribute__((format(printf, a, b))) #define __printf(a, b) __attribute__((format(printf, a, b)))
bool sbi_isprintable(char ch); bool sbi_isprintable(char ch);
char sbi_getc(void); int sbi_getc(void);
void sbi_putc(char ch); void sbi_putc(char ch);
@@ -26,12 +26,15 @@ void sbi_gets(char *s, int maxwidth, char endchar);
int __printf(2, 3) sbi_sprintf(char *out, const char *format, ...); int __printf(2, 3) sbi_sprintf(char *out, const char *format, ...);
int __printf(3, 4) sbi_snprintf(char *out, u32 out_sz, int __printf(3, 4) sbi_snprintf(char *out, u32 out_sz, const char *format, ...);
const char *format, ...);
int __printf(1, 2) sbi_printf(const char *format, ...); int __printf(1, 2) sbi_printf(const char *format, ...);
struct sbi_scratch; struct sbi_scratch;
int __printf(2, 3) sbi_dprintf(struct sbi_scratch *scratch,
const char *format, ...);
int sbi_console_init(struct sbi_scratch *scratch); int sbi_console_init(struct sbi_scratch *scratch);
#endif #endif

View File

@@ -19,6 +19,8 @@
* leave it unchanged in asm. * leave it unchanged in asm.
*/ */
/* clang-format off */
#ifdef __ASSEMBLY__ #ifdef __ASSEMBLY__
#define _AC(X,Y) X #define _AC(X,Y) X
#define _AT(T,X) X #define _AT(T,X) X
@@ -40,4 +42,6 @@
#define __STR(s) #s #define __STR(s) #s
#define STRINGIFY(s) __STR(s) #define STRINGIFY(s) __STR(s)
/* clang-format on */
#endif #endif

View File

@@ -11,16 +11,48 @@
#define __SBI_ECALL_H__ #define __SBI_ECALL_H__
#include <sbi/sbi_types.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_regs;
struct sbi_trap_info;
struct sbi_scratch; 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_major(void);
u16 sbi_ecall_version_minor(void); u16 sbi_ecall_version_minor(void);
int sbi_ecall_handler(u32 hartid, ulong mcause, struct sbi_ecall_extension *sbi_ecall_find_extension(unsigned long extid);
struct sbi_trap_regs *regs,
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); struct sbi_scratch *scratch);
int sbi_ecall_init(void);
#endif #endif

View File

@@ -10,39 +10,52 @@
#ifndef __SBI_ECALL_INTERFACE_H__ #ifndef __SBI_ECALL_INTERFACE_H__
#define __SBI_ECALL_INTERFACE_H__ #define __SBI_ECALL_INTERFACE_H__
#define SBI_ECALL_SET_TIMER 0 /* clang-format off */
#define SBI_ECALL_CONSOLE_PUTCHAR 1
#define SBI_ECALL_CONSOLE_GETCHAR 2
#define SBI_ECALL_CLEAR_IPI 3
#define SBI_ECALL_SEND_IPI 4
#define SBI_ECALL_REMOTE_FENCE_I 5
#define SBI_ECALL_REMOTE_SFENCE_VMA 6
#define SBI_ECALL_REMOTE_SFENCE_VMA_ASID 7
#define SBI_ECALL_SHUTDOWN 8
#define SBI_ECALL(__num, __a0, __a1, __a2) ({ \ /* SBI Extension IDs */
register unsigned long a0 asm ("a0") = (unsigned long)(__a0); \ #define SBI_EXT_0_1_SET_TIMER 0x0
register unsigned long a1 asm ("a1") = (unsigned long)(__a1); \ #define SBI_EXT_0_1_CONSOLE_PUTCHAR 0x1
register unsigned long a2 asm ("a2") = (unsigned long)(__a2); \ #define SBI_EXT_0_1_CONSOLE_GETCHAR 0x2
register unsigned long a7 asm ("a7") = (unsigned long)(__num); \ #define SBI_EXT_0_1_CLEAR_IPI 0x3
asm volatile ("ecall" \ #define SBI_EXT_0_1_SEND_IPI 0x4
: "+r" (a0) \ #define SBI_EXT_0_1_REMOTE_FENCE_I 0x5
: "r" (a1), "r" (a2), "r" (a7) \ #define SBI_EXT_0_1_REMOTE_SFENCE_VMA 0x6
: "memory"); \ #define SBI_EXT_0_1_REMOTE_SFENCE_VMA_ASID 0x7
a0; \ #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
#define SBI_ECALL_0(__num) SBI_ECALL(__num, 0, 0, 0) /* SBI function IDs for BASE extension*/
#define SBI_ECALL_1(__num, __a0) SBI_ECALL(__num, __a0, 0, 0) #define SBI_EXT_BASE_GET_SPEC_VERSION 0x0
#define SBI_ECALL_2(__num, __a0, __a1) SBI_ECALL(__num, __a0, __a1, 0) #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
#define sbi_ecall_console_putc(c) \ /* SBI function IDs for TIME extension*/
SBI_ECALL_1(SBI_ECALL_CONSOLE_PUTCHAR, (c)); #define SBI_EXT_TIME_SET_TIMER 0x0
static inline void sbi_ecall_console_puts(const char *str) /* SBI function IDs for IPI extension*/
{ #define SBI_EXT_IPI_SEND_IPI 0x0
while (str && *str)
sbi_ecall_console_putc(*str++); /* 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
#define SBI_SPEC_VERSION_MINOR_MASK 0xffffff
#define SBI_EXT_VENDOR_START 0x09000000
#define SBI_EXT_VENDOR_END 0x09FFFFFF
/* clang-format on */
#endif #endif

View File

@@ -12,16 +12,13 @@
#include <sbi/sbi_types.h> #include <sbi/sbi_types.h>
struct sbi_trap_regs;
struct sbi_scratch; struct sbi_scratch;
int sbi_emulate_csr_read(int csr_num, int sbi_emulate_csr_read(int csr_num, u32 hartid, struct sbi_trap_regs *regs,
u32 hartid, ulong mstatus, struct sbi_scratch *scratch, ulong *csr_val);
struct sbi_scratch *scratch,
ulong *csr_val);
int sbi_emulate_csr_write(int csr_num, int sbi_emulate_csr_write(int csr_num, u32 hartid, struct sbi_trap_regs *regs,
u32 hartid, ulong mstatus, struct sbi_scratch *scratch, ulong csr_val);
struct sbi_scratch *scratch,
ulong csr_val);
#endif #endif

View File

@@ -10,16 +10,25 @@
#ifndef __SBI_ERROR_H__ #ifndef __SBI_ERROR_H__
#define __SBI_ERROR_H__ #define __SBI_ERROR_H__
/* clang-format off */
#define SBI_OK 0 #define SBI_OK 0
#define SBI_EUNKNOWN -1 #define SBI_EFAIL -1
#define SBI_EFAIL -2 #define SBI_ENOTSUPP -2
#define SBI_EINVAL -3 #define SBI_EINVAL -3
#define SBI_ENOENT -4 #define SBI_DENIED -4
#define SBI_ENOTSUPP -5 #define SBI_INVALID_ADDR -5
#define SBI_ENODEV -6 #define SBI_ENODEV -6
#define SBI_ENOSYS -7 #define SBI_ENOSYS -7
#define SBI_ETIMEDOUT -8 #define SBI_ETIMEDOUT -8
#define SBI_EIO -9 #define SBI_EIO -9
#define SBI_EILL -10 #define SBI_EILL -10
#define SBI_ENOSPC -11
#define SBI_ENOMEM -12
#define SBI_ETRAP -13
#define SBI_EUNKNOWN -14
#define SBI_ENOENT -15
/* clang-format on */
#endif #endif

42
include/sbi/sbi_fifo.h Normal file
View File

@@ -0,0 +1,42 @@
/*
* SPDX-License-Identifier: BSD-2-Clause
*
* Copyright (c) 2019 Western Digital Corporation or its affiliates.
*
* Authors:
* Atish Patra<atish.patra@wdc.com>
*
*/
#ifndef __SBI_FIFO_H__
#define __SBI_FIFO_H__
#include <sbi/riscv_locks.h>
#include <sbi/sbi_types.h>
struct sbi_fifo {
void *queue;
spinlock_t qlock;
u16 entry_size;
u16 num_entries;
u16 avail;
u16 tail;
};
enum sbi_fifo_inplace_update_types {
SBI_FIFO_SKIP,
SBI_FIFO_UPDATED,
SBI_FIFO_UNCHANGED,
};
int sbi_fifo_dequeue(struct sbi_fifo *fifo, void *data);
int sbi_fifo_enqueue(struct sbi_fifo *fifo, void *data);
void sbi_fifo_init(struct sbi_fifo *fifo, void *queue_mem, u16 entries,
u16 entry_size);
bool sbi_fifo_is_empty(struct sbi_fifo *fifo);
bool sbi_fifo_is_full(struct sbi_fifo *fifo);
int sbi_fifo_inplace_update(struct sbi_fifo *fifo, void *in,
int (*fptr)(void *in, void *data));
u16 sbi_fifo_avail(struct sbi_fifo *fifo);
#endif

View File

@@ -14,16 +14,21 @@
struct sbi_scratch; struct sbi_scratch;
int sbi_hart_init(struct sbi_scratch *scratch, u32 hartid); int sbi_hart_init(struct sbi_scratch *scratch, u32 hartid, bool cold_boot);
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 sbi_hart_pmp_dump(struct sbi_scratch *scratch);
void __attribute__((noreturn)) sbi_hart_hang(void); void __attribute__((noreturn)) sbi_hart_hang(void);
void __attribute__((noreturn)) sbi_hart_switch_mode(unsigned long arg0, void __attribute__((noreturn))
unsigned long arg1, sbi_hart_switch_mode(unsigned long arg0, unsigned long arg1,
unsigned long next_addr, unsigned long next_addr, unsigned long next_mode,
unsigned long next_mode); bool next_virt);
void sbi_hart_mark_available(u32 hartid); void sbi_hart_mark_available(u32 hartid);

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_trap_regs;
struct sbi_scratch; 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_trap_regs *regs,
struct sbi_scratch *scratch); struct sbi_scratch *scratch);

View File

@@ -16,4 +16,8 @@ struct sbi_scratch;
void __noreturn sbi_init(struct sbi_scratch *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 #endif

View File

@@ -12,20 +12,57 @@
#include <sbi/sbi_types.h> #include <sbi/sbi_types.h>
#define SBI_IPI_EVENT_SOFT 0x1 /* clang-format off */
#define SBI_IPI_EVENT_FENCE_I 0x2
#define SBI_IPI_EVENT_SFENCE_VMA 0x4 #define SBI_IPI_EVENT_MAX __riscv_xlen
#define SBI_IPI_EVENT_HALT 0x8
/* clang-format on */
struct sbi_scratch; struct sbi_scratch;
int sbi_ipi_send_many(struct sbi_scratch *scratch, /** IPI event operations or callbacks */
ulong *pmask, u32 event); 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, 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); 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); void sbi_ipi_process(struct sbi_scratch *scratch);
int sbi_ipi_init(struct sbi_scratch *scratch, bool cold_boot); int sbi_ipi_init(struct sbi_scratch *scratch, bool cold_boot);
void sbi_ipi_exit(struct sbi_scratch *scratch);
#endif #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; struct sbi_scratch;
int sbi_misaligned_load_handler(u32 hartid, ulong mcause, int sbi_misaligned_load_handler(u32 hartid, ulong mcause,
ulong addr, ulong tval2, ulong tinst,
struct sbi_trap_regs *regs, struct sbi_trap_regs *regs,
struct sbi_scratch *scratch); struct sbi_scratch *scratch);
int sbi_misaligned_store_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_trap_regs *regs,
struct sbi_scratch *scratch); struct sbi_scratch *scratch);

View File

@@ -10,45 +10,157 @@
#ifndef __SBI_PLATFORM_H__ #ifndef __SBI_PLATFORM_H__
#define __SBI_PLATFORM_H__ #define __SBI_PLATFORM_H__
/** OpenSBI 32-bit platform version with:
* 1. upper 16-bits as major number
* 2. lower 16-bits as minor number
*/
#define SBI_PLATFORM_VERSION(Major, Minor) ((Major << 16) | Minor)
/** Offset of opensbi_version in struct sbi_platform */
#define SBI_PLATFORM_OPENSBI_VERSION_OFFSET (0x00)
/** Offset of platform_version in struct sbi_platform */
#define SBI_PLATFORM_VERSION_OFFSET (0x04)
/** Offset of name in struct sbi_platform */ /** Offset of name in struct sbi_platform */
#define SBI_PLATFORM_NAME_OFFSET (0x0) #define SBI_PLATFORM_NAME_OFFSET (0x08)
/** Offset of features in struct sbi_platform */ /** Offset of features in struct sbi_platform */
#define SBI_PLATFORM_FEATURES_OFFSET (0x40) #define SBI_PLATFORM_FEATURES_OFFSET (0x48)
/** Offset of hart_count in struct sbi_platform */ /** Offset of hart_count in struct sbi_platform */
#define SBI_PLATFORM_HART_COUNT_OFFSET (0x48) #define SBI_PLATFORM_HART_COUNT_OFFSET (0x50)
/** Offset of hart_stack_size in struct sbi_platform */ /** Offset of hart_stack_size in struct sbi_platform */
#define SBI_PLATFORM_HART_STACK_SIZE_OFFSET (0x4c) #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 platform_ops_addr in struct sbi_platform */
#define SBI_PLATFORM_OPS_OFFSET (0x60)
/** Offset of firmware_context in struct sbi_platform */
#define SBI_PLATFORM_FIRMWARE_CONTEXT_OFFSET (0x60 + __SIZEOF_POINTER__)
#define SBI_PLATFORM_TLB_RANGE_FLUSH_LIMIT_DEFAULT (1UL << 12)
#ifndef __ASSEMBLY__ #ifndef __ASSEMBLY__
#include <sbi/sbi_ecall.h>
#include <sbi/sbi_error.h>
#include <sbi/sbi_scratch.h> #include <sbi/sbi_scratch.h>
#include <sbi/sbi_trap.h>
#include <sbi/sbi_version.h>
/** Possible feature flags of a platform */ /** Possible feature flags of a platform */
enum sbi_platform_features { enum sbi_platform_features {
/** Platform has timer value */ /** Platform has timer value */
SBI_PLATFORM_HAS_TIMER_VALUE = (1 << 0), SBI_PLATFORM_HAS_TIMER_VALUE = (1 << 0),
/** Platform has HART hotplug support */ /** Platform has HART hotplug support */
SBI_PLATFORM_HAS_HART_HOTPLUG = (1 << 1), SBI_PLATFORM_HAS_HART_HOTPLUG = (1 << 1),
/** Platform has PMP support */ /** Platform has PMP support */
SBI_PLATFORM_HAS_PMP = (1 << 2), SBI_PLATFORM_HAS_PMP = (1 << 2),
/** Platform has S-mode counter enable */ /** Platform has S-mode counter enable */
SBI_PLATFORM_HAS_SCOUNTEREN = (1 << 3), SBI_PLATFORM_HAS_SCOUNTEREN = (1 << 3),
/** Platform has M-mode counter enable */ /** Platform has M-mode counter enable */
SBI_PLATFORM_HAS_MCOUNTEREN = (1 << 4), SBI_PLATFORM_HAS_MCOUNTEREN = (1 << 4),
/** Platform has fault delegation support */ /** Platform has fault delegation support */
SBI_PLATFORM_HAS_MFAULTS_DELEGATION = (1 << 5), SBI_PLATFORM_HAS_MFAULTS_DELEGATION = (1 << 5),
}; };
/** Default feature set for a platform */ /** Default feature set for a platform */
#define SBI_PLATFORM_DEFAULT_FEATURES \ #define SBI_PLATFORM_DEFAULT_FEATURES \
(SBI_PLATFORM_HAS_TIMER_VALUE | \ (SBI_PLATFORM_HAS_TIMER_VALUE | SBI_PLATFORM_HAS_PMP | \
SBI_PLATFORM_HAS_PMP | \ SBI_PLATFORM_HAS_SCOUNTEREN | SBI_PLATFORM_HAS_MCOUNTEREN | \
SBI_PLATFORM_HAS_SCOUNTEREN | \
SBI_PLATFORM_HAS_MCOUNTEREN | \
SBI_PLATFORM_HAS_MFAULTS_DELEGATION) SBI_PLATFORM_HAS_MFAULTS_DELEGATION)
/** Platform functions */
struct sbi_platform_operations {
/** Platform early initialization */
int (*early_init)(bool cold_boot);
/** 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);
/**
* Get PMP regions details (namely: protection, base address,
* and size) for given HART
*/
int (*pmp_region_info)(u32 hartid, u32 index, ulong *prot, ulong *addr,
ulong *log2size);
/** Write a character to the platform console output */
void (*console_putc)(char ch);
/** Read a character from the platform console input */
int (*console_getc)(void);
/** Initialize the platform console */
int (*console_init)(void);
/** 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);
/** Clear IPI for a target HART */
void (*ipi_clear)(u32 target_hart);
/** Initialize IPI for current HART */
int (*ipi_init)(bool cold_boot);
/** Exit IPI for current HART */
void (*ipi_exit)(void);
/** Get tlb flush limit value **/
u64 (*get_tlbr_flush_limit)(void);
/** Get platform timer value */
u64 (*timer_value)(void);
/** Start platform timer event for current HART */
void (*timer_event_start)(u64 next_event);
/** Stop platform timer event for current HART */
void (*timer_event_stop)(void);
/** Initialize platform timer for current HART */
int (*timer_init)(bool cold_boot);
/** Exit platform timer for current HART */
void (*timer_exit)(void);
/** Reboot the platform */
int (*system_reboot)(u32 type);
/** Shutdown or poweroff the platform */
int (*system_shutdown)(u32 type);
/** platform specific SBI extension implementation probe function */
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,
struct sbi_trap_info *out_trap);
} __packed;
/** Representation of a platform */ /** Representation of a platform */
struct sbi_platform { struct sbi_platform {
/**
* OpenSBI version this sbi_platform is based on.
* It's a 32-bit value where upper 16-bits are major number
* and lower 16-bits are minor number
*/
u32 opensbi_version;
/**
* OpenSBI platform version released by vendor.
* It's a 32-bit value where upper 16-bits are major number
* and lower 16-bits are minor number
*/
u32 platform_version;
/** Name of the platform */ /** Name of the platform */
char name[64]; char name[64];
/** Supported features */ /** Supported features */
@@ -59,78 +171,38 @@ struct sbi_platform {
u32 hart_stack_size; u32 hart_stack_size;
/** Mask representing the set of disabled HARTs */ /** Mask representing the set of disabled HARTs */
u64 disabled_hart_mask; u64 disabled_hart_mask;
/** Pointer to sbi platform operations */
/** Platform early initialization */ unsigned long platform_ops_addr;
int (*early_init)(bool cold_boot); /** Pointer to system firmware specific context */
/** Platform final initialization */ unsigned long firmware_context;
int (*final_init)(bool cold_boot);
/** Get number of PMP regions for given HART */
u32 (*pmp_region_count)(u32 hartid);
/**
* Get PMP regions details (namely: protection, base address,
* and size) for given HART
*/
int (*pmp_region_info)(u32 hartid, u32 index,
ulong *prot, ulong *addr, ulong *log2size);
/** Write a character to the platform console output */
void (*console_putc)(char ch);
/** Read a character from the platform console input */
char (*console_getc)(void);
/** Initialize the platform console */
int (*console_init)(void);
/** Initialize the platform interrupt controller for current HART */
int (*irqchip_init)(bool cold_boot);
/** Send IPI to a target HART */
void (*ipi_send)(u32 target_hart);
/** Wait for target HART to acknowledge IPI */
void (*ipi_sync)(u32 target_hart);
/** Clear IPI for a target HART */
void (*ipi_clear)(u32 target_hart);
/** Initialize IPI for current HART */
int (*ipi_init)(bool cold_boot);
/** Get platform timer value */
u64 (*timer_value)(void);
/** Start platform timer event for current HART */
void (*timer_event_start)(u64 next_event);
/** Stop platform timer event for current HART */
void (*timer_event_stop)(void);
/** Initialize platform timer for current HART */
int (*timer_init)(bool cold_boot);
/** Reboot the platform */
int (*system_reboot)(u32 type);
/** Shutdown or poweroff the platform */
int (*system_shutdown)(u32 type);
} __packed; } __packed;
/** Get pointer to sbi_platform for sbi_scratch pointer */ /** Get pointer to sbi_platform for sbi_scratch pointer */
#define sbi_platform_ptr(__s) \ #define sbi_platform_ptr(__s) \
((struct sbi_platform *)((__s)->platform_addr)) ((const struct sbi_platform *)((__s)->platform_addr))
/** Get pointer to sbi_platform for current HART */ /** Get pointer to sbi_platform for current HART */
#define sbi_platform_thishart_ptr() \ #define sbi_platform_thishart_ptr() ((const struct sbi_platform *) \
((struct sbi_platform *)(sbi_scratch_thishart_ptr()->platform_addr)) (sbi_scratch_thishart_ptr()->platform_addr))
/** Get pointer to platform_ops_addr from platform pointer **/
#define sbi_platform_ops(__p) \
((const struct sbi_platform_operations *)(__p)->platform_ops_addr)
/** Check whether the platform supports timer value */ /** Check whether the platform supports timer value */
#define sbi_platform_has_timer_value(__p) \ #define sbi_platform_has_timer_value(__p) \
((__p)->features & SBI_PLATFORM_HAS_TIMER_VALUE) ((__p)->features & SBI_PLATFORM_HAS_TIMER_VALUE)
/** Check whether the platform supports HART hotplug */ /** Check whether the platform supports HART hotplug */
#define sbi_platform_has_hart_hotplug(__p) \ #define sbi_platform_has_hart_hotplug(__p) \
((__p)->features & SBI_PLATFORM_HAS_HART_HOTPLUG) ((__p)->features & SBI_PLATFORM_HAS_HART_HOTPLUG)
/** Check whether the platform has PMP support */ /** Check whether the platform has PMP support */
#define sbi_platform_has_pmp(__p) \ #define sbi_platform_has_pmp(__p) ((__p)->features & SBI_PLATFORM_HAS_PMP)
((__p)->features & SBI_PLATFORM_HAS_PMP)
/** Check whether the platform supports scounteren CSR */ /** Check whether the platform supports scounteren CSR */
#define sbi_platform_has_scounteren(__p) \ #define sbi_platform_has_scounteren(__p) \
((__p)->features & SBI_PLATFORM_HAS_SCOUNTEREN) ((__p)->features & SBI_PLATFORM_HAS_SCOUNTEREN)
/** Check whether the platform supports mcounteren CSR */ /** Check whether the platform supports mcounteren CSR */
#define sbi_platform_has_mcounteren(__p) \ #define sbi_platform_has_mcounteren(__p) \
((__p)->features & SBI_PLATFORM_HAS_MCOUNTEREN) ((__p)->features & SBI_PLATFORM_HAS_MCOUNTEREN)
/** Check whether the platform supports fault delegation */ /** Check whether the platform supports fault delegation */
#define sbi_platform_has_mfaults_delegation(__p) \ #define sbi_platform_has_mfaults_delegation(__p) \
((__p)->features & SBI_PLATFORM_HAS_MFAULTS_DELEGATION) ((__p)->features & SBI_PLATFORM_HAS_MFAULTS_DELEGATION)
/** /**
@@ -138,13 +210,13 @@ struct sbi_platform {
* *
* @param plat pointer to 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(struct sbi_platform *plat) static inline const char *sbi_platform_name(const struct sbi_platform *plat)
{ {
if (plat) if (plat)
return plat->name; return plat->name;
return NULL; return "Unknown";
} }
/** /**
@@ -155,7 +227,7 @@ static inline const char *sbi_platform_name(struct sbi_platform *plat)
* *
* @return TRUE if HART is disabled and FALSE otherwise * @return TRUE if HART is disabled and FALSE otherwise
*/ */
static inline bool sbi_platform_hart_disabled(struct sbi_platform *plat, static inline bool sbi_platform_hart_disabled(const struct sbi_platform *plat,
u32 hartid) u32 hartid)
{ {
if (plat && (plat->disabled_hart_mask & (1 << hartid))) if (plat && (plat->disabled_hart_mask & (1 << hartid)))
@@ -163,6 +235,22 @@ static inline bool sbi_platform_hart_disabled(struct sbi_platform *plat,
return FALSE; return FALSE;
} }
/**
* Get platform specific tlb range flush maximum value. Any request with size
* higher than this is upgraded to a full flush.
*
* @param plat pointer to struct sbi_platform
*
* @return tlb range flush limit value. Returns a default (page size) if not
* defined by platform.
*/
static inline u64 sbi_platform_tlbr_flush_limit(const struct sbi_platform *plat)
{
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;
}
/** /**
* Get total number of HARTs supported by the platform * Get total number of HARTs supported by the platform
* *
@@ -170,7 +258,7 @@ static inline bool sbi_platform_hart_disabled(struct sbi_platform *plat,
* *
* @return total number of HARTs * @return total number of HARTs
*/ */
static inline u32 sbi_platform_hart_count(struct sbi_platform *plat) static inline u32 sbi_platform_hart_count(const struct sbi_platform *plat)
{ {
if (plat) if (plat)
return plat->hart_count; return plat->hart_count;
@@ -184,7 +272,7 @@ static inline u32 sbi_platform_hart_count(struct sbi_platform *plat)
* *
* @return stack size in bytes * @return stack size in bytes
*/ */
static inline u32 sbi_platform_hart_stack_size(struct sbi_platform *plat) static inline u32 sbi_platform_hart_stack_size(const struct sbi_platform *plat)
{ {
if (plat) if (plat)
return plat->hart_stack_size; return plat->hart_stack_size;
@@ -199,11 +287,11 @@ static inline u32 sbi_platform_hart_stack_size(struct sbi_platform *plat)
* *
* @return 0 on success and negative error code on failure * @return 0 on success and negative error code on failure
*/ */
static inline int sbi_platform_early_init(struct sbi_platform *plat, static inline int sbi_platform_early_init(const struct sbi_platform *plat,
bool cold_boot) bool cold_boot)
{ {
if (plat && plat->early_init) if (plat && sbi_platform_ops(plat)->early_init)
return plat->early_init(cold_boot); return sbi_platform_ops(plat)->early_init(cold_boot);
return 0; return 0;
} }
@@ -215,14 +303,66 @@ static inline int sbi_platform_early_init(struct sbi_platform *plat,
* *
* @return 0 on success and negative error code on failure * @return 0 on success and negative error code on failure
*/ */
static inline int sbi_platform_final_init(struct sbi_platform *plat, static inline int sbi_platform_final_init(const struct sbi_platform *plat,
bool cold_boot) bool cold_boot)
{ {
if (plat && plat->final_init) if (plat && sbi_platform_ops(plat)->final_init)
return plat->final_init(cold_boot); return sbi_platform_ops(plat)->final_init(cold_boot);
return 0; 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 * Get the number of PMP regions of a HART
* *
@@ -231,11 +371,11 @@ static inline int sbi_platform_final_init(struct sbi_platform *plat,
* *
* @return number of PMP regions * @return number of PMP regions
*/ */
static inline u32 sbi_platform_pmp_region_count(struct sbi_platform *plat, static inline u32 sbi_platform_pmp_region_count(const struct sbi_platform *plat,
u32 hartid) u32 hartid)
{ {
if (plat && plat->pmp_region_count) if (plat && sbi_platform_ops(plat)->pmp_region_count)
return plat->pmp_region_count(hartid); return sbi_platform_ops(plat)->pmp_region_count(hartid);
return 0; return 0;
} }
@@ -252,14 +392,14 @@ static inline u32 sbi_platform_pmp_region_count(struct sbi_platform *plat,
* *
* @return 0 on success and negative error code on failure * @return 0 on success and negative error code on failure
*/ */
static inline int sbi_platform_pmp_region_info(struct sbi_platform *plat, static inline int sbi_platform_pmp_region_info(const struct sbi_platform *plat,
u32 hartid, u32 index, u32 hartid, u32 index,
ulong *prot, ulong *addr, ulong *prot, ulong *addr,
ulong *log2size) ulong *log2size)
{ {
if (plat && plat->pmp_region_info) if (plat && sbi_platform_ops(plat)->pmp_region_info)
return plat->pmp_region_info(hartid, index, return sbi_platform_ops(plat)->pmp_region_info(hartid, index, prot, addr,
prot, addr, log2size); log2size);
return 0; return 0;
} }
@@ -269,11 +409,11 @@ static inline int sbi_platform_pmp_region_info(struct sbi_platform *plat,
* @param plat pointer to struct sbi_platform * @param plat pointer to struct sbi_platform
* @param ch character to write * @param ch character to write
*/ */
static inline void sbi_platform_console_putc(struct sbi_platform *plat, static inline void sbi_platform_console_putc(const struct sbi_platform *plat,
char ch) char ch)
{ {
if (plat && plat->console_putc) if (plat && sbi_platform_ops(plat)->console_putc)
plat->console_putc(ch); sbi_platform_ops(plat)->console_putc(ch);
} }
/** /**
@@ -283,11 +423,11 @@ static inline void sbi_platform_console_putc(struct sbi_platform *plat,
* *
* @return character read from console input * @return character read from console input
*/ */
static inline char sbi_platform_console_getc(struct sbi_platform *plat) static inline int sbi_platform_console_getc(const struct sbi_platform *plat)
{ {
if (plat && plat->console_getc) if (plat && sbi_platform_ops(plat)->console_getc)
return plat->console_getc(); return sbi_platform_ops(plat)->console_getc();
return 0; return -1;
} }
/** /**
@@ -297,10 +437,10 @@ static inline char sbi_platform_console_getc(struct sbi_platform *plat)
* *
* @return 0 on success and negative error code on failure * @return 0 on success and negative error code on failure
*/ */
static inline int sbi_platform_console_init(struct sbi_platform *plat) static inline int sbi_platform_console_init(const struct sbi_platform *plat)
{ {
if (plat && plat->console_init) if (plat && sbi_platform_ops(plat)->console_init)
return plat->console_init(); return sbi_platform_ops(plat)->console_init();
return 0; return 0;
} }
@@ -312,38 +452,36 @@ static inline int sbi_platform_console_init(struct sbi_platform *plat)
* *
* @return 0 on success and negative error code on failure * @return 0 on success and negative error code on failure
*/ */
static inline int sbi_platform_irqchip_init(struct sbi_platform *plat, static inline int sbi_platform_irqchip_init(const struct sbi_platform *plat,
bool cold_boot) bool cold_boot)
{ {
if (plat && plat->irqchip_init) if (plat && sbi_platform_ops(plat)->irqchip_init)
return plat->irqchip_init(cold_boot); return sbi_platform_ops(plat)->irqchip_init(cold_boot);
return 0; 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 * Send IPI to a target HART
* *
* @param plat pointer to struct sbi_platform * @param plat pointer to struct sbi_platform
* @param target_hart HART ID of IPI target * @param target_hart HART ID of IPI target
*/ */
static inline void sbi_platform_ipi_send(struct sbi_platform *plat, static inline void sbi_platform_ipi_send(const struct sbi_platform *plat,
u32 target_hart) u32 target_hart)
{ {
if (plat && plat->ipi_send) if (plat && sbi_platform_ops(plat)->ipi_send)
plat->ipi_send(target_hart); sbi_platform_ops(plat)->ipi_send(target_hart);
}
/**
* Wait for target HART to acknowledge IPI
*
* @param plat pointer to struct sbi_platform
* @param target_hart HART ID of IPI target
*/
static inline void sbi_platform_ipi_sync(struct sbi_platform *plat,
u32 target_hart)
{
if (plat && plat->ipi_sync)
plat->ipi_sync(target_hart);
} }
/** /**
@@ -352,11 +490,11 @@ static inline void sbi_platform_ipi_sync(struct sbi_platform *plat,
* @param plat pointer to struct sbi_platform * @param plat pointer to struct sbi_platform
* @param target_hart HART ID of IPI target * @param target_hart HART ID of IPI target
*/ */
static inline void sbi_platform_ipi_clear(struct sbi_platform *plat, static inline void sbi_platform_ipi_clear(const struct sbi_platform *plat,
u32 target_hart) u32 target_hart)
{ {
if (plat && plat->ipi_clear) if (plat && sbi_platform_ops(plat)->ipi_clear)
plat->ipi_clear(target_hart); sbi_platform_ops(plat)->ipi_clear(target_hart);
} }
/** /**
@@ -367,25 +505,36 @@ static inline void sbi_platform_ipi_clear(struct sbi_platform *plat,
* *
* @return 0 on success and negative error code on failure * @return 0 on success and negative error code on failure
*/ */
static inline int sbi_platform_ipi_init(struct sbi_platform *plat, static inline int sbi_platform_ipi_init(const struct sbi_platform *plat,
bool cold_boot) bool cold_boot)
{ {
if (plat && plat->ipi_init) if (plat && sbi_platform_ops(plat)->ipi_init)
return plat->ipi_init(cold_boot); return sbi_platform_ops(plat)->ipi_init(cold_boot);
return 0; 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 * Get platform timer value
* *
* @param plat pointer to struct sbi_platform * @param plat pointer to struct sbi_platform
* *
* @return 64bit timer value * @return 64-bit timer value
*/ */
static inline u64 sbi_platform_timer_value(struct sbi_platform *plat) static inline u64 sbi_platform_timer_value(const struct sbi_platform *plat)
{ {
if (plat && plat->timer_value) if (plat && sbi_platform_ops(plat)->timer_value)
return plat->timer_value(); return sbi_platform_ops(plat)->timer_value();
return 0; return 0;
} }
@@ -395,11 +544,11 @@ static inline u64 sbi_platform_timer_value(struct sbi_platform *plat)
* @param plat pointer to struct struct sbi_platform * @param plat pointer to struct struct sbi_platform
* @param next_event timer value when timer event will happen * @param next_event timer value when timer event will happen
*/ */
static inline void sbi_platform_timer_event_start(struct sbi_platform *plat, static inline void
u64 next_event) sbi_platform_timer_event_start(const struct sbi_platform *plat, u64 next_event)
{ {
if (plat && plat->timer_event_start) if (plat && sbi_platform_ops(plat)->timer_event_start)
plat->timer_event_start(next_event); sbi_platform_ops(plat)->timer_event_start(next_event);
} }
/** /**
@@ -407,10 +556,11 @@ static inline void sbi_platform_timer_event_start(struct sbi_platform *plat,
* *
* @param plat pointer to struct sbi_platform * @param plat pointer to struct sbi_platform
*/ */
static inline void sbi_platform_timer_event_stop(struct sbi_platform *plat) static inline void
sbi_platform_timer_event_stop(const struct sbi_platform *plat)
{ {
if (plat && plat->timer_event_stop) if (plat && sbi_platform_ops(plat)->timer_event_stop)
plat->timer_event_stop(); sbi_platform_ops(plat)->timer_event_stop();
} }
/** /**
@@ -421,14 +571,25 @@ static inline void sbi_platform_timer_event_stop(struct sbi_platform *plat)
* *
* @return 0 on success and negative error code on failure * @return 0 on success and negative error code on failure
*/ */
static inline int sbi_platform_timer_init(struct sbi_platform *plat, static inline int sbi_platform_timer_init(const struct sbi_platform *plat,
bool cold_boot) bool cold_boot)
{ {
if (plat && plat->timer_init) if (plat && sbi_platform_ops(plat)->timer_init)
return plat->timer_init(cold_boot); return sbi_platform_ops(plat)->timer_init(cold_boot);
return 0; 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 * Reboot the platform
* *
@@ -437,11 +598,11 @@ static inline int sbi_platform_timer_init(struct sbi_platform *plat,
* *
* @return 0 on success and negative error code on failure * @return 0 on success and negative error code on failure
*/ */
static inline int sbi_platform_system_reboot(struct sbi_platform *plat, static inline int sbi_platform_system_reboot(const struct sbi_platform *plat,
u32 type) u32 type)
{ {
if (plat && plat->system_reboot) if (plat && sbi_platform_ops(plat)->system_reboot)
return plat->system_reboot(type); return sbi_platform_ops(plat)->system_reboot(type);
return 0; return 0;
} }
@@ -453,14 +614,60 @@ static inline int sbi_platform_system_reboot(struct sbi_platform *plat,
* *
* @return 0 on success and negative error code on failure * @return 0 on success and negative error code on failure
*/ */
static inline int sbi_platform_system_shutdown(struct sbi_platform *plat, static inline int sbi_platform_system_shutdown(const struct sbi_platform *plat,
u32 type) u32 type)
{ {
if (plat && plat->system_shutdown) if (plat && sbi_platform_ops(plat)->system_shutdown)
return plat->system_shutdown(type); return sbi_platform_ops(plat)->system_shutdown(type);
return 0; return 0;
} }
/**
* Check if a vendor extension is implemented or not.
*
* @param plat pointer to struct sbi_platform
* @param extid vendor SBI extension id
*
* @return 0 if extid is not implemented and 1 if implemented
*/
static inline int sbi_platform_vendor_ext_check(const struct sbi_platform *plat,
long extid)
{
if (plat && sbi_platform_ops(plat)->vendor_ext_check)
return sbi_platform_ops(plat)->vendor_ext_check(extid);
return 0;
}
/**
* Invoke platform specific vendor SBI extension implementation.
*
* @param plat pointer to struct sbi_platform
* @param extid vendor SBI extension id
* @param funcid SBI function id within the extension id
* @param args pointer to arguments passed by the caller
* @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,
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_trap);
}
return SBI_ENOTSUPP;
}
#endif #endif
#endif #endif

View File

@@ -12,6 +12,8 @@
#include <sbi/riscv_asm.h> #include <sbi/riscv_asm.h>
/* clang-format off */
/** Offset of fw_start member in sbi_scratch */ /** Offset of fw_start member in sbi_scratch */
#define SBI_SCRATCH_FW_START_OFFSET (0 * __SIZEOF_POINTER__) #define SBI_SCRATCH_FW_START_OFFSET (0 * __SIZEOF_POINTER__)
/** Offset of fw_size member in sbi_scratch */ /** Offset of fw_size member in sbi_scratch */
@@ -28,12 +30,16 @@
#define SBI_SCRATCH_PLATFORM_ADDR_OFFSET (6 * __SIZEOF_POINTER__) #define SBI_SCRATCH_PLATFORM_ADDR_OFFSET (6 * __SIZEOF_POINTER__)
/** Offset of hartid_to_scratch member in sbi_scratch */ /** Offset of hartid_to_scratch member in sbi_scratch */
#define SBI_SCRATCH_HARTID_TO_SCRATCH_OFFSET (7 * __SIZEOF_POINTER__) #define SBI_SCRATCH_HARTID_TO_SCRATCH_OFFSET (7 * __SIZEOF_POINTER__)
/** Offset of ipi_type member in sbi_scratch */
#define SBI_SCRATCH_IPI_TYPE_OFFSET (8 * __SIZEOF_POINTER__)
/** Offset of tmp0 member in sbi_scratch */ /** Offset of tmp0 member in sbi_scratch */
#define SBI_SCRATCH_TMP0_OFFSET (9 * __SIZEOF_POINTER__) #define SBI_SCRATCH_TMP0_OFFSET (8 * __SIZEOF_POINTER__)
/** Offset of options member in sbi_scratch */
#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 */ /** Maximum size of sbi_scratch */
#define SBI_SCRATCH_SIZE 256 #define SBI_SCRATCH_SIZE (64 * __SIZEOF_POINTER__)
/* clang-format on */
#ifndef __ASSEMBLY__ #ifndef __ASSEMBLY__
@@ -57,19 +63,44 @@ struct sbi_scratch {
unsigned long platform_addr; unsigned long platform_addr;
/** Address of HART ID to sbi_scratch conversion function */ /** Address of HART ID to sbi_scratch conversion function */
unsigned long hartid_to_scratch; unsigned long hartid_to_scratch;
/** IPI type (or flags) */
unsigned long ipi_type;
/** Temporary storage */ /** Temporary storage */
unsigned long tmp0; unsigned long tmp0;
/** Options for OpenSBI library */
unsigned long options;
} __packed; } __packed;
/** Possible options for OpenSBI library */
enum sbi_scratch_options {
/** Disable prints during boot */
SBI_SCRATCH_NO_BOOT_PRINTS = (1 << 0),
/** Enable runtime debug prints */
SBI_SCRATCH_DEBUG_PRINTS = (1 << 1),
};
/** Get pointer to sbi_scratch for current HART */ /** Get pointer to sbi_scratch for current HART */
#define sbi_scratch_thishart_ptr() \ #define sbi_scratch_thishart_ptr() \
((struct sbi_scratch *)csr_read(CSR_MSCRATCH)) ((struct sbi_scratch *)csr_read(CSR_MSCRATCH))
/** Get Arg1 of next booting stage for current HART */ /** Get Arg1 of next booting stage for current HART */
#define sbi_scratch_thishart_arg1_ptr() \ #define sbi_scratch_thishart_arg1_ptr() \
((void *)(sbi_scratch_thishart_ptr()->next_arg1)) ((void *)(sbi_scratch_thishart_ptr()->next_arg1))
/** Allocate from extra space in sbi_scratch
*
* @return zero on failure and non-zero (>= SBI_SCRATCH_EXTRA_SPACE_OFFSET)
* on success
*/
unsigned long sbi_scratch_alloc_offset(unsigned long size, const char *owner);
/** Free-up extra space in sbi_scratch */
void sbi_scratch_free_offset(unsigned long offset);
/** Get pointer from offset in sbi_scratch */
#define sbi_scratch_offset_ptr(scratch, offset) ((void *)scratch + (offset))
/** Get pointer from offset in sbi_scratch for current HART */
#define sbi_scratch_thishart_offset_ptr(offset) \
((void *)sbi_scratch_thishart_ptr() + (offset))
#endif #endif

39
include/sbi/sbi_string.h Normal file
View File

@@ -0,0 +1,39 @@
/*
* SPDX-License-Identifier: BSD-2-Clause
*
* Copyright (c) 2019 Western Digital Corporation or its affiliates.
*
* Authors:
* Atish Patra <atish.patra@wdc.com>
*/
#ifndef __STRING_H__
#define __STRING_H__
#include <sbi/sbi_types.h>
int sbi_strcmp(const char *a, const char *b);
size_t sbi_strlen(const char *str);
size_t sbi_strnlen(const char *str, size_t count);
char *sbi_strcpy(char *dest, const char *src);
char *sbi_strncpy(char *dest, const char *src, size_t count);
char *sbi_strchr(const char *s, int c);
char *sbi_strrchr(const char *s, int c);
void *sbi_memset(void *s, int c, size_t count);
void *sbi_memcpy(void *dest, const void *src, size_t count);
void *sbi_memmove(void *dest, const void *src, size_t count);
int sbi_memcmp(const void *s1, const void *s2, size_t count);
void *sbi_memchr(const void *s, int c, size_t count);
#endif

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); int sbi_system_final_init(struct sbi_scratch *scratch, bool cold_boot);
void __attribute__((noreturn)) sbi_system_reboot(struct sbi_scratch *scratch, void sbi_system_early_exit(struct sbi_scratch *scratch);
u32 type);
void __attribute__((noreturn)) sbi_system_shutdown(struct sbi_scratch *scratch, void sbi_system_final_exit(struct sbi_scratch *scratch);
u32 type);
void __noreturn sbi_system_reboot(struct sbi_scratch *scratch, u32 type);
void __noreturn sbi_system_shutdown(struct sbi_scratch *scratch, u32 type);
#endif #endif

View File

@@ -16,7 +16,13 @@ struct sbi_scratch;
u64 sbi_timer_value(struct sbi_scratch *scratch); u64 sbi_timer_value(struct sbi_scratch *scratch);
void sbi_timer_event_stop(struct sbi_scratch *scratch); u64 sbi_timer_virt_value(struct sbi_scratch *scratch);
u64 sbi_timer_get_delta(struct sbi_scratch *scratch);
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_start(struct sbi_scratch *scratch, u64 next_event); void sbi_timer_event_start(struct sbi_scratch *scratch, u64 next_event);
@@ -24,4 +30,6 @@ void sbi_timer_process(struct sbi_scratch *scratch);
int sbi_timer_init(struct sbi_scratch *scratch, bool cold_boot); int sbi_timer_init(struct sbi_scratch *scratch, bool cold_boot);
void sbi_timer_exit(struct sbi_scratch *scratch);
#endif #endif

51
include/sbi/sbi_tlb.h Normal file
View File

@@ -0,0 +1,51 @@
/*
* 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_TLB_H__
#define __SBI_TLB_H__
#include <sbi/sbi_types.h>
/* clang-format off */
#define SBI_TLB_FLUSH_ALL ((unsigned long)-1)
/* clang-format on */
#define SBI_TLB_FIFO_NUM_ENTRIES 8
enum sbi_tlb_info_types {
SBI_TLB_FLUSH_VMA,
SBI_TLB_FLUSH_VMA_ASID,
SBI_TLB_FLUSH_GVMA,
SBI_TLB_FLUSH_GVMA_VMID,
SBI_TLB_FLUSH_VVMA,
SBI_TLB_FLUSH_VVMA_ASID,
SBI_ITLB_FLUSH
};
struct sbi_scratch;
struct sbi_tlb_info {
unsigned long start;
unsigned long size;
unsigned long asid;
unsigned long type;
unsigned long shart_mask;
};
#define SBI_TLB_INFO_SIZE sizeof(struct sbi_tlb_info)
int sbi_tlb_request(struct sbi_scratch *scratch, ulong hmask,
ulong hbase, struct sbi_tlb_info *tinfo);
int sbi_tlb_init(struct sbi_scratch *scratch, bool cold_boot);
#endif

View File

@@ -10,6 +10,8 @@
#ifndef __SBI_TRAP_H__ #ifndef __SBI_TRAP_H__
#define __SBI_TRAP_H__ #define __SBI_TRAP_H__
/* clang-format off */
/** Index of zero member in sbi_trap_regs */ /** Index of zero member in sbi_trap_regs */
#define SBI_TRAP_REGS_zero 0 #define SBI_TRAP_REGS_zero 0
/** Index of ra member in sbi_trap_regs */ /** Index of ra member in sbi_trap_regs */
@@ -78,14 +80,17 @@
#define SBI_TRAP_REGS_mepc 32 #define SBI_TRAP_REGS_mepc 32
/** Index of mstatus member in sbi_trap_regs */ /** Index of mstatus member in sbi_trap_regs */
#define SBI_TRAP_REGS_mstatus 33 #define SBI_TRAP_REGS_mstatus 33
/** Index of mstatusH member in sbi_trap_regs */
#define SBI_TRAP_REGS_mstatusH 34
/** Last member index in sbi_trap_regs */ /** Last member index in sbi_trap_regs */
#define SBI_TRAP_REGS_last 34 #define SBI_TRAP_REGS_last 35
/* clang-format on */
/** Get offset of member with name 'x' in sbi_trap_regs */ /** Get offset of member with name 'x' in sbi_trap_regs */
#define SBI_TRAP_REGS_OFFSET(x) \ #define SBI_TRAP_REGS_OFFSET(x) ((SBI_TRAP_REGS_##x) * __SIZEOF_POINTER__)
((SBI_TRAP_REGS_##x) * __SIZEOF_POINTER__)
/** Size (in bytes) of sbi_trap_regs */ /** Size (in bytes) of sbi_trap_regs */
#define SBI_TRAP_REGS_SIZE SBI_TRAP_REGS_OFFSET(last) #define SBI_TRAP_REGS_SIZE SBI_TRAP_REGS_OFFSET(last)
#ifndef __ASSEMBLY__ #ifndef __ASSEMBLY__
@@ -161,13 +166,29 @@ struct sbi_trap_regs {
unsigned long mepc; unsigned long mepc;
/** mstatus register state */ /** mstatus register state */
unsigned long mstatus; unsigned long mstatus;
/** mstatusH register state (only for 32-bit) */
unsigned long mstatusH;
} __packed; } __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; struct sbi_scratch;
int sbi_trap_redirect(struct sbi_trap_regs *regs, int sbi_trap_redirect(struct sbi_trap_regs *regs,
struct sbi_scratch *scratch, struct sbi_trap_info *trap,
ulong epc, ulong cause, ulong tval); struct sbi_scratch *scratch);
void sbi_trap_handler(struct sbi_trap_regs *regs, void sbi_trap_handler(struct sbi_trap_regs *regs,
struct sbi_scratch *scratch); struct sbi_scratch *scratch);

View File

@@ -10,6 +10,10 @@
#ifndef __SBI_TYPES_H__ #ifndef __SBI_TYPES_H__
#define __SBI_TYPES_H__ #define __SBI_TYPES_H__
#ifndef OPENSBI_EXTERNAL_SBI_TYPES
/* clang-format off */
typedef char s8; typedef char s8;
typedef unsigned char u8; typedef unsigned char u8;
typedef unsigned char uint8_t; typedef unsigned char uint8_t;
@@ -58,4 +62,43 @@ typedef unsigned long physical_size_t;
#define __packed __attribute__((packed)) #define __packed __attribute__((packed))
#define __noreturn __attribute__((noreturn)) #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 #endif

View File

@@ -10,110 +10,35 @@
#ifndef __SBI_UNPRIV_H__ #ifndef __SBI_UNPRIV_H__
#define __SBI_UNPRIV_H__ #define __SBI_UNPRIV_H__
#include <sbi/riscv_encoding.h>
#include <sbi/sbi_bits.h>
#include <sbi/sbi_types.h> #include <sbi/sbi_types.h>
#define DECLARE_UNPRIVILEGED_LOAD_FUNCTION(type, insn) \ struct sbi_scratch;
static inline type load_##type(const type *addr, ulong mepc) \ struct sbi_trap_info;
{ \
register ulong __mepc asm ("a2") = mepc; \
register ulong __mstatus asm ("a3"); \
type val; \
asm ("csrrs %0, "STR(CSR_MSTATUS)", %3\n" \
#insn " %1, %2\n" \
"csrw "STR(CSR_MSTATUS)", %0" \
: "+&r" (__mstatus), "=&r" (val) \
: "m" (*addr), "r" (MSTATUS_MPRV), "r" (__mepc)); \
return val; \
}
#define DECLARE_UNPRIVILEGED_STORE_FUNCTION(type, insn) \ #define DECLARE_UNPRIVILEGED_LOAD_FUNCTION(type) \
static inline void store_##type(type *addr, type val, ulong mepc) \ type sbi_load_##type(const type *addr, \
{ \ struct sbi_scratch *scratch, \
register ulong __mepc asm ("a2") = mepc; \ struct sbi_trap_info *trap);
register ulong __mstatus asm ("a3"); \
asm volatile ("csrrs %0, "STR(CSR_MSTATUS)", %3\n" \
#insn " %1, %2\n" \
"csrw "STR(CSR_MSTATUS)", %0" \
: "+&r" (__mstatus) \
: "r" (val), "m" (*addr), "r" (MSTATUS_MPRV), "r" (__mepc)); \
}
DECLARE_UNPRIVILEGED_LOAD_FUNCTION(u8, lbu) #define DECLARE_UNPRIVILEGED_STORE_FUNCTION(type) \
DECLARE_UNPRIVILEGED_LOAD_FUNCTION(u16, lhu) void sbi_store_##type(type *addr, type val, \
DECLARE_UNPRIVILEGED_LOAD_FUNCTION(s8, lb) struct sbi_scratch *scratch, \
DECLARE_UNPRIVILEGED_LOAD_FUNCTION(s16, lh) struct sbi_trap_info *trap);
DECLARE_UNPRIVILEGED_LOAD_FUNCTION(s32, lw)
DECLARE_UNPRIVILEGED_STORE_FUNCTION(u8, sb)
DECLARE_UNPRIVILEGED_STORE_FUNCTION(u16, sh)
DECLARE_UNPRIVILEGED_STORE_FUNCTION(u32, sw)
#if __riscv_xlen == 64
DECLARE_UNPRIVILEGED_LOAD_FUNCTION(u32, lwu)
DECLARE_UNPRIVILEGED_LOAD_FUNCTION(u64, ld)
DECLARE_UNPRIVILEGED_STORE_FUNCTION(u64, sd)
DECLARE_UNPRIVILEGED_LOAD_FUNCTION(ulong, ld)
#else
DECLARE_UNPRIVILEGED_LOAD_FUNCTION(u32, lw)
DECLARE_UNPRIVILEGED_LOAD_FUNCTION(ulong, lw)
static inline u64 load_u64(const u64 *addr, ulong mepc) DECLARE_UNPRIVILEGED_LOAD_FUNCTION(u8)
{ DECLARE_UNPRIVILEGED_LOAD_FUNCTION(u16)
return load_u32((u32 *)addr, mepc) DECLARE_UNPRIVILEGED_LOAD_FUNCTION(s8)
+ ((u64)load_u32((u32 *)addr + 1, mepc) << 32); DECLARE_UNPRIVILEGED_LOAD_FUNCTION(s16)
} DECLARE_UNPRIVILEGED_LOAD_FUNCTION(s32)
DECLARE_UNPRIVILEGED_STORE_FUNCTION(u8)
DECLARE_UNPRIVILEGED_STORE_FUNCTION(u16)
DECLARE_UNPRIVILEGED_STORE_FUNCTION(u32)
DECLARE_UNPRIVILEGED_LOAD_FUNCTION(u32)
DECLARE_UNPRIVILEGED_LOAD_FUNCTION(u64)
DECLARE_UNPRIVILEGED_STORE_FUNCTION(u64)
DECLARE_UNPRIVILEGED_LOAD_FUNCTION(ulong)
static inline void store_u64(u64 *addr, u64 val, ulong mepc) ulong sbi_get_insn(ulong mepc, struct sbi_scratch *scratch,
{ struct sbi_trap_info *trap);
store_u32((u32 *)addr, val, mepc);
store_u32((u32 *)addr + 1, val >> 32, mepc);
}
#endif
static inline ulong get_insn(ulong mepc, ulong *mstatus)
{
register ulong __mepc asm ("a2") = mepc;
register ulong __mstatus asm ("a3");
ulong val;
#ifndef __riscv_compressed
asm ("csrrs %[mstatus], "STR(CSR_MSTATUS)", %[mprv]\n"
#if __riscv_xlen == 64
STR(LWU) " %[insn], (%[addr])\n"
#else
STR(LW) " %[insn], (%[addr])\n"
#endif
"csrw "STR(CSR_MSTATUS)", %[mstatus]"
: [mstatus] "+&r" (__mstatus), [insn] "=&r" (val)
: [mprv] "r" (MSTATUS_MPRV | MSTATUS_MXR), [addr] "r" (__mepc));
#else
ulong rvc_mask = 3, tmp;
asm ("csrrs %[mstatus], "STR(CSR_MSTATUS)", %[mprv]\n"
"and %[tmp], %[addr], 2\n"
"bnez %[tmp], 1f\n"
#if __riscv_xlen == 64
STR(LWU) " %[insn], (%[addr])\n"
#else
STR(LW) " %[insn], (%[addr])\n"
#endif
"and %[tmp], %[insn], %[rvc_mask]\n"
"beq %[tmp], %[rvc_mask], 2f\n"
"sll %[insn], %[insn], %[xlen_minus_16]\n"
"srl %[insn], %[insn], %[xlen_minus_16]\n"
"j 2f\n"
"1:\n"
"lhu %[insn], (%[addr])\n"
"and %[tmp], %[insn], %[rvc_mask]\n"
"bne %[tmp], %[rvc_mask], 2f\n"
"lhu %[tmp], 2(%[addr])\n"
"sll %[tmp], %[tmp], 16\n"
"add %[insn], %[insn], %[tmp]\n"
"2: csrw "STR(CSR_MSTATUS)", %[mstatus]"
: [mstatus] "+&r" (__mstatus), [insn] "=&r" (val), [tmp] "=&r" (tmp)
: [mprv] "r" (MSTATUS_MPRV | MSTATUS_MXR), [addr] "r" (__mepc),
[rvc_mask] "r" (rvc_mask), [xlen_minus_16] "i" (__riscv_xlen - 16));
#endif
*mstatus = __mstatus;
return val;
}
#endif #endif

View File

@@ -10,7 +10,15 @@
#ifndef __SBI_VERSION_H__ #ifndef __SBI_VERSION_H__
#define __SBI_VERSION_H__ #define __SBI_VERSION_H__
#define OPENSBI_VERSION_MAJOR 0 #define OPENSBI_VERSION_MAJOR 0
#define OPENSBI_VERSION_MINOR 3 #define OPENSBI_VERSION_MINOR 6
/**
* OpenSBI 32-bit version with:
* 1. upper 16-bits as major number
* 2. lower 16-bits as minor number
*/
#define OPENSBI_VERSION ((OPENSBI_VERSION_MAJOR << 16) | \
(OPENSBI_VERSION_MINOR))
#endif #endif

View File

@@ -14,10 +14,12 @@
void plic_fdt_fixup(void *fdt, const char *compat); void plic_fdt_fixup(void *fdt, const char *compat);
int plic_warm_irqchip_init(u32 target_hart, int plic_warm_irqchip_init(u32 target_hart, int m_cntx_id, int s_cntx_id);
int m_cntx_id, int s_cntx_id);
int plic_cold_irqchip_init(unsigned long base, int plic_cold_irqchip_init(unsigned long base, u32 num_sources, u32 hart_count);
u32 num_sources, u32 hart_count);
void plic_set_thresh(u32 cntxid, u32 val);
void plic_set_ie(u32 cntxid, u32 word_index, u32 val);
#endif #endif

View File

@@ -14,9 +14,8 @@
void sifive_uart_putc(char ch); void sifive_uart_putc(char ch);
char sifive_uart_getc(void); int sifive_uart_getc(void);
int sifive_uart_init(unsigned long base, int sifive_uart_init(unsigned long base, u32 in_freq, u32 baudrate);
u32 in_freq, u32 baudrate);
#endif #endif

View File

@@ -14,10 +14,9 @@
void uart8250_putc(char ch); void uart8250_putc(char ch);
char uart8250_getc(void); int uart8250_getc(void);
int uart8250_init(unsigned long base, int uart8250_init(unsigned long base, u32 in_freq, u32 baudrate, u32 reg_shift,
u32 in_freq, u32 baudrate, u32 reg_width);
u32 reg_shift, u32 reg_width);
#endif #endif

View File

@@ -30,6 +30,7 @@ void clint_timer_event_start(u64 next_event);
int clint_warm_timer_init(void); 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 #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

@@ -1,25 +0,0 @@
#
# SPDX-License-Identifier: BSD-2-Clause
#
# Copyright (c) 2019 Western Digital Corporation or its affiliates.
#
# Authors:
# Anup Patel <anup.patel@wdc.com>
#
lib-objs-y += riscv_asm.o
lib-objs-y += riscv_atomic.o
lib-objs-y += riscv_hardfp.o
lib-objs-y += riscv_locks.o
lib-objs-y += sbi_console.o
lib-objs-y += sbi_ecall.o
lib-objs-y += sbi_emulate_csr.o
lib-objs-y += sbi_hart.o
lib-objs-y += sbi_illegal_insn.o
lib-objs-y += sbi_init.o
lib-objs-y += sbi_ipi.o
lib-objs-y += sbi_misaligned_ldst.o
lib-objs-y += sbi_system.o
lib-objs-y += sbi_timer.o
lib-objs-y += sbi_trap.o

View File

@@ -1,225 +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/sbi_types.h>
#include <sbi/riscv_asm.h>
#include <sbi/riscv_atomic.h>
#include <sbi/riscv_barrier.h>
#include <sbi/sbi_bits.h>
long atomic_read(atomic_t *atom)
{
long ret = atom->counter;
rmb();
return ret;
}
void atomic_write(atomic_t *atom, long value)
{
atom->counter = value;
wmb();
}
long atomic_add_return(atomic_t *atom, long value)
{
long ret;
__asm__ __volatile__ (
" amoadd.w.aqrl %1, %2, %0"
: "+A" (atom->counter), "=r" (ret)
: "r" (value)
: "memory");
return ret + value;
}
long atomic_sub_return(atomic_t *atom, long value)
{
long ret;
__asm__ __volatile__ (
" amoadd.w.aqrl %1, %2, %0"
: "+A" (atom->counter), "=r" (ret)
: "r" (-value)
: "memory");
return ret - value;
}
#define __xchg(ptr, new, size) \
({ \
__typeof__(ptr) __ptr = (ptr); \
__typeof__(*(ptr)) __new = (new); \
__typeof__(*(ptr)) __ret; \
register unsigned int __rc; \
switch (size) { \
case 4: \
__asm__ __volatile__ ( \
"0: lr.w %0, %2\n" \
" sc.w.rl %1, %z3, %2\n" \
" bnez %1, 0b\n" \
" fence rw, rw\n" \
: "=&r" (__ret), "=&r" (__rc), "+A" (*__ptr) \
: "rJ" (__new) \
: "memory"); \
break; \
case 8: \
__asm__ __volatile__ ( \
"0: lr.d %0, %2\n" \
" sc.d.rl %1, %z3, %2\n" \
" bnez %1, 0b\n" \
" fence rw, rw\n" \
: "=&r" (__ret), "=&r" (__rc), "+A" (*__ptr) \
: "rJ" (__new) \
: "memory"); \
break; \
default: \
break; \
} \
__ret; \
})
#define xchg(ptr, n) \
({ \
__typeof__(*(ptr)) _n_ = (n); \
(__typeof__(*(ptr))) __xchg((ptr), _n_, sizeof(*(ptr))); \
})
#define __cmpxchg(ptr, old, new, size) \
({ \
__typeof__(ptr) __ptr = (ptr); \
__typeof__(*(ptr)) __old = (old); \
__typeof__(*(ptr)) __new = (new); \
__typeof__(*(ptr)) __ret; \
register unsigned int __rc; \
switch (size) { \
case 4: \
__asm__ __volatile__ ( \
"0: lr.w %0, %2\n" \
" bne %0, %z3, 1f\n" \
" sc.w.rl %1, %z4, %2\n" \
" bnez %1, 0b\n" \
" fence rw, rw\n" \
"1:\n" \
: "=&r" (__ret), "=&r" (__rc), "+A" (*__ptr) \
: "rJ" (__old), "rJ" (__new) \
: "memory"); \
break; \
case 8: \
__asm__ __volatile__ ( \
"0: lr.d %0, %2\n" \
" bne %0, %z3, 1f\n" \
" sc.d.rl %1, %z4, %2\n" \
" bnez %1, 0b\n" \
" fence rw, rw\n" \
"1:\n" \
: "=&r" (__ret), "=&r" (__rc), "+A" (*__ptr) \
: "rJ" (__old), "rJ" (__new) \
: "memory"); \
break; \
default: \
break; \
} \
__ret; \
})
#define cmpxchg(ptr, o, n) \
({ \
__typeof__(*(ptr)) _o_ = (o); \
__typeof__(*(ptr)) _n_ = (n); \
(__typeof__(*(ptr))) __cmpxchg((ptr), \
_o_, _n_, sizeof(*(ptr))); \
})
long arch_atomic_cmpxchg(atomic_t *atom, long oldval, long newval)
{
#ifdef __riscv_atomic
return __sync_val_compare_and_swap(&atom->counter, oldval, newval);
#else
return cmpxchg(&atom->counter, oldval, newval);
#endif
}
long arch_atomic_xchg(atomic_t *atom, long newval)
{
/* Atomically set new value and return old value. */
#ifdef __riscv_atomic
/*
* The name of GCC built-in macro __sync_lock_test_and_set()
* is misleading. A more appropriate name for GCC built-in
* macro would be __sync_val_exchange().
*/
return __sync_lock_test_and_set(&atom->counter, newval);
#else
return xchg(&atom->counter, newval);
#endif
}
unsigned int atomic_raw_xchg_uint(volatile unsigned int *ptr,
unsigned int newval)
{
/* Atomically set new value and return old value. */
#ifdef __riscv_atomic
/*
* The name of GCC built-in macro __sync_lock_test_and_set()
* is misleading. A more appropriate name for GCC built-in
* macro would be __sync_val_exchange().
*/
return __sync_lock_test_and_set(ptr, newval);
#else
return xchg(ptr, newval);
#endif
}
#if (BITS_PER_LONG == 64)
#define __AMO(op) "amo" #op ".d"
#elif (BITS_PER_LONG == 32)
#define __AMO(op) "amo" #op ".w"
#else
#error "Unexpected BITS_PER_LONG"
#endif
#define __atomic_op_bit_ord(op, mod, nr, addr, ord) \
({ \
unsigned long __res, __mask; \
__mask = BIT_MASK(nr); \
__asm__ __volatile__ ( \
__AMO(op) #ord " %0, %2, %1" \
: "=r" (__res), "+A" (addr[BIT_WORD(nr)]) \
: "r" (mod(__mask)) \
: "memory"); \
__res; \
})
#define __atomic_op_bit(op, mod, nr, addr) \
__atomic_op_bit_ord(op, mod, nr, addr, .aqrl)
/* Bitmask modifiers */
#define __NOP(x) (x)
#define __NOT(x) (~(x))
inline int atomic_raw_set_bit(int nr, volatile unsigned long *addr)
{
return __atomic_op_bit(or, __NOP, nr, addr);
}
inline int atomic_raw_clear_bit(int nr, volatile unsigned long *addr)
{
return __atomic_op_bit(and, __NOT, nr, addr);
}
inline int atomic_set_bit(int nr, atomic_t *atom)
{
return atomic_raw_set_bit(nr, (unsigned long *)&atom->counter);
}
inline int atomic_clear_bit(int nr, atomic_t *atom)
{
return atomic_raw_clear_bit(nr, (unsigned long *)&atom->counter);
}

35
lib/sbi/objects.mk Normal file
View File

@@ -0,0 +1,35 @@
#
# SPDX-License-Identifier: BSD-2-Clause
#
# Copyright (c) 2019 Western Digital Corporation or its affiliates.
#
# Authors:
# Anup Patel <anup.patel@wdc.com>
#
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 += 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
libsbi-objs-y += sbi_ipi.o
libsbi-objs-y += sbi_misaligned_ldst.o
libsbi-objs-y += sbi_scratch.o
libsbi-objs-y += sbi_system.o
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_asm.h>
#include <sbi/riscv_encoding.h> #include <sbi/riscv_encoding.h>
#include <sbi/sbi_error.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) unsigned long csr_read_num(int csr_num)
{ {
@@ -163,28 +196,26 @@ static unsigned long ctz(unsigned long x)
return ret; return ret;
} }
int pmp_set(unsigned int n, unsigned long prot, int pmp_set(unsigned int n, unsigned long prot, unsigned long addr,
unsigned long addr, unsigned long log2len) unsigned long log2len)
{ {
int pmpcfg_csr, pmpcfg_shift, pmpaddr_csr; int pmpcfg_csr, pmpcfg_shift, pmpaddr_csr;
unsigned long cfgmask, pmpcfg; unsigned long cfgmask, pmpcfg;
unsigned long addrmask, pmpaddr; unsigned long addrmask, pmpaddr;
/* check parameters */ /* check parameters */
if (n >= PMP_COUNT || if (n >= PMP_COUNT || log2len > __riscv_xlen || log2len < PMP_SHIFT)
log2len > __riscv_xlen ||
log2len < PMP_SHIFT)
return SBI_EINVAL; return SBI_EINVAL;
/* calculate PMP register and offset */ /* calculate PMP register and offset */
#if __riscv_xlen == 32 #if __riscv_xlen == 32
pmpcfg_csr = CSR_PMPCFG0 + (n >> 2); pmpcfg_csr = CSR_PMPCFG0 + (n >> 2);
pmpcfg_shift = (n & 3) << 3; pmpcfg_shift = (n & 3) << 3;
#elif __riscv_xlen == 64 #elif __riscv_xlen == 64
pmpcfg_csr = (CSR_PMPCFG0 + (n >> 2)) & ~1; pmpcfg_csr = (CSR_PMPCFG0 + (n >> 2)) & ~1;
pmpcfg_shift = (n & 7) << 3; pmpcfg_shift = (n & 7) << 3;
#else #else
pmpcfg_csr = -1; pmpcfg_csr = -1;
pmpcfg_shift = -1; pmpcfg_shift = -1;
#endif #endif
pmpaddr_csr = CSR_PMPADDR0 + n; pmpaddr_csr = CSR_PMPADDR0 + n;
@@ -194,7 +225,7 @@ int pmp_set(unsigned int n, unsigned long prot,
/* encode PMP config */ /* encode PMP config */
prot |= (log2len == PMP_SHIFT) ? PMP_A_NA4 : PMP_A_NAPOT; prot |= (log2len == PMP_SHIFT) ? PMP_A_NA4 : PMP_A_NAPOT;
cfgmask = ~(0xff << pmpcfg_shift); cfgmask = ~(0xff << pmpcfg_shift);
pmpcfg = (csr_read_num(pmpcfg_csr) & cfgmask); pmpcfg = (csr_read_num(pmpcfg_csr) & cfgmask);
pmpcfg |= ((prot << pmpcfg_shift) & ~cfgmask); pmpcfg |= ((prot << pmpcfg_shift) & ~cfgmask);
/* encode PMP address */ /* encode PMP address */
@@ -205,7 +236,7 @@ int pmp_set(unsigned int n, unsigned long prot,
pmpaddr = -1UL; pmpaddr = -1UL;
} else { } else {
addrmask = (1UL << (log2len - PMP_SHIFT)) - 1; addrmask = (1UL << (log2len - PMP_SHIFT)) - 1;
pmpaddr = ((addr >> PMP_SHIFT) & ~addrmask); pmpaddr = ((addr >> PMP_SHIFT) & ~addrmask);
pmpaddr |= (addrmask >> 1); pmpaddr |= (addrmask >> 1);
} }
} }
@@ -217,28 +248,27 @@ int pmp_set(unsigned int n, unsigned long prot,
return 0; return 0;
} }
int pmp_get(unsigned int n, unsigned long *prot_out, int pmp_get(unsigned int n, unsigned long *prot_out, unsigned long *addr_out,
unsigned long *addr_out, unsigned long *log2len_out) unsigned long *log2len_out)
{ {
int pmpcfg_csr, pmpcfg_shift, pmpaddr_csr; int pmpcfg_csr, pmpcfg_shift, pmpaddr_csr;
unsigned long cfgmask, pmpcfg, prot; unsigned long cfgmask, pmpcfg, prot;
unsigned long t1, addr, log2len; unsigned long t1, addr, log2len;
/* check parameters */ /* check parameters */
if (n >= PMP_COUNT || !prot_out || if (n >= PMP_COUNT || !prot_out || !addr_out || !log2len_out)
!addr_out || !log2len_out)
return SBI_EINVAL; return SBI_EINVAL;
*prot_out = *addr_out = *log2len_out = 0; *prot_out = *addr_out = *log2len_out = 0;
/* calculate PMP register and offset */ /* calculate PMP register and offset */
#if __riscv_xlen == 32 #if __riscv_xlen == 32
pmpcfg_csr = CSR_PMPCFG0 + (n >> 2); pmpcfg_csr = CSR_PMPCFG0 + (n >> 2);
pmpcfg_shift = (n & 3) << 3; pmpcfg_shift = (n & 3) << 3;
#elif __riscv_xlen == 64 #elif __riscv_xlen == 64
pmpcfg_csr = (CSR_PMPCFG0 + (n >> 2)) & ~1; pmpcfg_csr = (CSR_PMPCFG0 + (n >> 2)) & ~1;
pmpcfg_shift = (n & 7) << 3; pmpcfg_shift = (n & 7) << 3;
#else #else
pmpcfg_csr = -1; pmpcfg_csr = -1;
pmpcfg_shift = -1; pmpcfg_shift = -1;
#endif #endif
pmpaddr_csr = CSR_PMPADDR0 + n; pmpaddr_csr = CSR_PMPADDR0 + n;
@@ -247,28 +277,28 @@ int pmp_get(unsigned int n, unsigned long *prot_out,
/* decode PMP config */ /* decode PMP config */
cfgmask = (0xff << pmpcfg_shift); cfgmask = (0xff << pmpcfg_shift);
pmpcfg = csr_read_num(pmpcfg_csr) & cfgmask; pmpcfg = csr_read_num(pmpcfg_csr) & cfgmask;
prot = pmpcfg >> pmpcfg_shift; prot = pmpcfg >> pmpcfg_shift;
/* decode PMP address */ /* decode PMP address */
if ((prot & PMP_A) == PMP_A_NAPOT) { if ((prot & PMP_A) == PMP_A_NAPOT) {
addr = csr_read_num(pmpaddr_csr); addr = csr_read_num(pmpaddr_csr);
if (addr == -1UL) { if (addr == -1UL) {
addr = 0; addr = 0;
log2len = __riscv_xlen; log2len = __riscv_xlen;
} else { } else {
t1 = ctz(~addr); t1 = ctz(~addr);
addr = (addr & ~((1UL << t1) - 1)) << PMP_SHIFT; addr = (addr & ~((1UL << t1) - 1)) << PMP_SHIFT;
log2len = (t1 + PMP_SHIFT + 1); log2len = (t1 + PMP_SHIFT + 1);
} }
} else { } else {
addr = csr_read_num(pmpaddr_csr) << PMP_SHIFT; addr = csr_read_num(pmpaddr_csr) << PMP_SHIFT;
log2len = PMP_SHIFT; log2len = PMP_SHIFT;
} }
/* return details */ /* return details */
*prot_out = prot; *prot_out = prot;
*addr_out = addr; *addr_out = addr;
*log2len_out = log2len; *log2len_out = log2len;
return 0; return 0;

256
lib/sbi/riscv_atomic.c Normal file
View File

@@ -0,0 +1,256 @@
/*
* SPDX-License-Identifier: BSD-2-Clause
*
* Copyright (c) 2019 Western Digital Corporation or its affiliates.
*
* Authors:
* Anup Patel <anup.patel@wdc.com>
*/
#include <sbi/sbi_types.h>
#include <sbi/riscv_asm.h>
#include <sbi/riscv_atomic.h>
#include <sbi/riscv_barrier.h>
#include <sbi/sbi_bits.h>
long atomic_read(atomic_t *atom)
{
long ret = atom->counter;
rmb();
return ret;
}
void atomic_write(atomic_t *atom, long value)
{
atom->counter = value;
wmb();
}
long atomic_add_return(atomic_t *atom, long value)
{
long ret;
__asm__ __volatile__(" amoadd.w.aqrl %1, %2, %0"
: "+A"(atom->counter), "=r"(ret)
: "r"(value)
: "memory");
return ret + value;
}
long atomic_sub_return(atomic_t *atom, long value)
{
long ret;
__asm__ __volatile__(" amoadd.w.aqrl %1, %2, %0"
: "+A"(atom->counter), "=r"(ret)
: "r"(-value)
: "memory");
return ret - value;
}
#define __axchg(ptr, new, size) \
({ \
__typeof__(ptr) __ptr = (ptr); \
__typeof__(new) __new = (new); \
__typeof__(*(ptr)) __ret; \
switch (size) { \
case 4: \
__asm__ __volatile__ ( \
" amoswap.w.aqrl %0, %2, %1\n" \
: "=r" (__ret), "+A" (*__ptr) \
: "r" (__new) \
: "memory"); \
break; \
case 8: \
__asm__ __volatile__ ( \
" amoswap.d.aqrl %0, %2, %1\n" \
: "=r" (__ret), "+A" (*__ptr) \
: "r" (__new) \
: "memory"); \
break; \
default: \
break; \
} \
__ret; \
})
#define axchg(ptr, x) \
({ \
__typeof__(*(ptr)) _x_ = (x); \
(__typeof__(*(ptr))) __axchg((ptr), _x_, sizeof(*(ptr))); \
})
#define __xchg(ptr, new, size) \
({ \
__typeof__(ptr) __ptr = (ptr); \
__typeof__(*(ptr)) __new = (new); \
__typeof__(*(ptr)) __ret; \
register unsigned int __rc; \
switch (size) { \
case 4: \
__asm__ __volatile__("0: lr.w %0, %2\n" \
" sc.w.rl %1, %z3, %2\n" \
" bnez %1, 0b\n" \
" fence rw, rw\n" \
: "=&r"(__ret), "=&r"(__rc), \
"+A"(*__ptr) \
: "rJ"(__new) \
: "memory"); \
break; \
case 8: \
__asm__ __volatile__("0: lr.d %0, %2\n" \
" sc.d.rl %1, %z3, %2\n" \
" bnez %1, 0b\n" \
" fence rw, rw\n" \
: "=&r"(__ret), "=&r"(__rc), \
"+A"(*__ptr) \
: "rJ"(__new) \
: "memory"); \
break; \
default: \
break; \
} \
__ret; \
})
#define xchg(ptr, n) \
({ \
__typeof__(*(ptr)) _n_ = (n); \
(__typeof__(*(ptr))) __xchg((ptr), _n_, sizeof(*(ptr))); \
})
#define __cmpxchg(ptr, old, new, size) \
({ \
__typeof__(ptr) __ptr = (ptr); \
__typeof__(*(ptr)) __old = (old); \
__typeof__(*(ptr)) __new = (new); \
__typeof__(*(ptr)) __ret; \
register unsigned int __rc; \
switch (size) { \
case 4: \
__asm__ __volatile__("0: lr.w %0, %2\n" \
" bne %0, %z3, 1f\n" \
" sc.w.rl %1, %z4, %2\n" \
" bnez %1, 0b\n" \
" fence rw, rw\n" \
"1:\n" \
: "=&r"(__ret), "=&r"(__rc), \
"+A"(*__ptr) \
: "rJ"(__old), "rJ"(__new) \
: "memory"); \
break; \
case 8: \
__asm__ __volatile__("0: lr.d %0, %2\n" \
" bne %0, %z3, 1f\n" \
" sc.d.rl %1, %z4, %2\n" \
" bnez %1, 0b\n" \
" fence rw, rw\n" \
"1:\n" \
: "=&r"(__ret), "=&r"(__rc), \
"+A"(*__ptr) \
: "rJ"(__old), "rJ"(__new) \
: "memory"); \
break; \
default: \
break; \
} \
__ret; \
})
#define cmpxchg(ptr, o, n) \
({ \
__typeof__(*(ptr)) _o_ = (o); \
__typeof__(*(ptr)) _n_ = (n); \
(__typeof__(*(ptr))) \
__cmpxchg((ptr), _o_, _n_, sizeof(*(ptr))); \
})
long arch_atomic_cmpxchg(atomic_t *atom, long oldval, long newval)
{
#ifdef __riscv_atomic
return __sync_val_compare_and_swap(&atom->counter, oldval, newval);
#else
return cmpxchg(&atom->counter, oldval, newval);
#endif
}
long arch_atomic_xchg(atomic_t *atom, long newval)
{
/* Atomically set new value and return old value. */
#ifdef __riscv_atomic
return axchg(&atom->counter, newval);
#else
return xchg(&atom->counter, newval);
#endif
}
unsigned int atomic_raw_xchg_uint(volatile unsigned int *ptr,
unsigned int newval)
{
/* Atomically set new value and return old value. */
#ifdef __riscv_atomic
return axchg(ptr, newval);
#else
return xchg(ptr, newval);
#endif
}
unsigned long atomic_raw_xchg_ulong(volatile unsigned long *ptr,
unsigned long newval)
{
/* Atomically set new value and return old value. */
#ifdef __riscv_atomic
return axchg(ptr, newval);
#else
return xchg(ptr, newval);
#endif
}
#if (BITS_PER_LONG == 64)
#define __AMO(op) "amo" #op ".d"
#elif (BITS_PER_LONG == 32)
#define __AMO(op) "amo" #op ".w"
#else
#error "Unexpected BITS_PER_LONG"
#endif
#define __atomic_op_bit_ord(op, mod, nr, addr, ord) \
({ \
unsigned long __res, __mask; \
__mask = BIT_MASK(nr); \
__asm__ __volatile__(__AMO(op) #ord " %0, %2, %1" \
: "=r"(__res), "+A"(addr[BIT_WORD(nr)]) \
: "r"(mod(__mask)) \
: "memory"); \
__res; \
})
#define __atomic_op_bit(op, mod, nr, addr) \
__atomic_op_bit_ord(op, mod, nr, addr, .aqrl)
/* Bitmask modifiers */
#define __NOP(x) (x)
#define __NOT(x) (~(x))
inline int atomic_raw_set_bit(int nr, volatile unsigned long *addr)
{
return __atomic_op_bit(or, __NOP, nr, addr);
}
inline int atomic_raw_clear_bit(int nr, volatile unsigned long *addr)
{
return __atomic_op_bit(and, __NOT, nr, addr);
}
inline int atomic_set_bit(int nr, atomic_t *atom)
{
return atomic_raw_set_bit(nr, (unsigned long *)&atom->counter);
}
inline int atomic_clear_bit(int nr, atomic_t *atom)
{
return atomic_raw_clear_bit(nr, (unsigned long *)&atom->counter);
}

View File

@@ -19,11 +19,10 @@ int spin_trylock(spinlock_t *lock)
{ {
int tmp = 1, busy; int tmp = 1, busy;
__asm__ __volatile__ ( __asm__ __volatile__(
" amoswap.w %0, %2, %1\n" " amoswap.w %0, %2, %1\n" RISCV_ACQUIRE_BARRIER
RISCV_ACQUIRE_BARRIER : "=r"(busy), "+A"(lock->lock)
: "=r" (busy), "+A" (lock->lock) : "r"(tmp)
: "r" (tmp)
: "memory"); : "memory");
return !busy; return !busy;

View File

@@ -11,22 +11,19 @@
#include <sbi/sbi_console.h> #include <sbi/sbi_console.h>
#include <sbi/riscv_locks.h> #include <sbi/riscv_locks.h>
static struct sbi_platform *console_plat = NULL; static const struct sbi_platform *console_plat = NULL;
static spinlock_t console_out_lock = SPIN_LOCK_INITIALIZER; static spinlock_t console_out_lock = SPIN_LOCK_INITIALIZER;
bool sbi_isprintable(char c) bool sbi_isprintable(char c)
{ {
if (((31 < c) && (c < 127)) || if (((31 < c) && (c < 127)) || (c == '\f') || (c == '\r') ||
(c == '\f') || (c == '\n') || (c == '\t')) {
(c == '\r') ||
(c == '\n') ||
(c == '\t')) {
return TRUE; return TRUE;
} }
return FALSE; return FALSE;
} }
char sbi_getc(void) int sbi_getc(void)
{ {
return sbi_platform_console_getc(console_plat); return sbi_platform_console_getc(console_plat);
} }
@@ -50,25 +47,26 @@ void sbi_puts(const char *str)
void sbi_gets(char *s, int maxwidth, char endchar) void sbi_gets(char *s, int maxwidth, char endchar)
{ {
char ch, *retval = s; int ch;
char *retval = s;
while ((ch = sbi_getc()) != endchar && maxwidth > 1) { while ((ch = sbi_getc()) != endchar && ch >= 0 && maxwidth > 1) {
*retval = ch; *retval = (char)ch;
retval++; retval++;
maxwidth--; maxwidth--;
} }
*retval = '\0'; *retval = '\0';
} }
#define PAD_RIGHT 1 #define PAD_RIGHT 1
#define PAD_ZERO 2 #define PAD_ZERO 2
#define PAD_ALTERNATE 4 #define PAD_ALTERNATE 4
#define PRINT_BUF_LEN 64 #define PRINT_BUF_LEN 64
#define va_start(v,l) __builtin_va_start((v),l) #define va_start(v, l) __builtin_va_start((v), l)
#define va_end __builtin_va_end #define va_end __builtin_va_end
#define va_arg __builtin_va_arg #define va_arg __builtin_va_arg
typedef __builtin_va_list va_list; typedef __builtin_va_list va_list;
static void printc(char **out, u32 *out_len, char ch) static void printc(char **out, u32 *out_len, char ch)
{ {
@@ -88,9 +86,10 @@ static void printc(char **out, u32 *out_len, char ch)
} }
} }
static int prints(char **out, u32 *out_len, const char *string, int width, int flags) static int prints(char **out, u32 *out_len, const char *string, int width,
int flags)
{ {
int pc = 0; int pc = 0;
char padchar = ' '; char padchar = ' ';
if (width > 0) { if (width > 0) {
@@ -134,10 +133,10 @@ static int printi(char **out, u32 *out_len, long long i, int b, int sg,
if (sg && b == 10 && i < 0) { if (sg && b == 10 && i < 0) {
neg = 1; neg = 1;
u = -i; u = -i;
} }
s = print_buf + PRINT_BUF_LEN - 1; s = print_buf + PRINT_BUF_LEN - 1;
*s = '\0'; *s = '\0';
if (!u) { if (!u) {
@@ -210,59 +209,59 @@ static int print(char **out, u32 *out_len, const char *format, va_list args)
if (*format == 's') { if (*format == 's') {
char *s = va_arg(args, char *); char *s = va_arg(args, char *);
acnt += sizeof(char *); acnt += sizeof(char *);
pc += prints(out, out_len, pc += prints(out, out_len, s ? s : "(null)",
s ? s : "(null)", width, flags); width, flags);
continue; continue;
} }
if ((*format == 'd') || (*format == 'i')) { if ((*format == 'd') || (*format == 'i')) {
pc += printi(out, out_len, pc += printi(out, out_len, va_arg(args, int),
va_arg(args, int), 10, 1, width, flags, '0');
10, 1, width, flags, '0');
acnt += sizeof(int); acnt += sizeof(int);
continue; continue;
} }
if (*format == 'x') { if (*format == 'x') {
pc += printi(out, out_len, pc += printi(out, out_len,
va_arg(args, unsigned int), va_arg(args, unsigned int), 16, 0,
16, 0, width, flags, 'a'); width, flags, 'a');
acnt += sizeof(unsigned int); acnt += sizeof(unsigned int);
continue; continue;
} }
if (*format == 'X') { if (*format == 'X') {
pc += printi(out, out_len, pc += printi(out, out_len,
va_arg(args, unsigned int), va_arg(args, unsigned int), 16, 0,
16, 0, width, flags, 'A'); width, flags, 'A');
acnt += sizeof(unsigned int); acnt += sizeof(unsigned int);
continue; continue;
} }
if (*format == 'u') { if (*format == 'u') {
pc += printi(out, out_len, pc += printi(out, out_len,
va_arg(args, unsigned int), va_arg(args, unsigned int), 10, 0,
10, 0, width, flags, 'a'); width, flags, 'a');
acnt += sizeof(unsigned int); acnt += sizeof(unsigned int);
continue; continue;
} }
if (*format == 'p') { if (*format == 'p') {
pc += printi(out, out_len, pc += printi(out, out_len,
va_arg(args, unsigned long), va_arg(args, unsigned long), 16, 0,
16, 0, width, flags, 'a'); width, flags, 'a');
acnt += sizeof(unsigned long); acnt += sizeof(unsigned long);
continue; continue;
} }
if (*format == 'P') { if (*format == 'P') {
pc += printi(out, out_len, pc += printi(out, out_len,
va_arg(args, unsigned long), va_arg(args, unsigned long), 16, 0,
16, 0, width, flags, 'A'); width, flags, 'A');
acnt += sizeof(unsigned long); acnt += sizeof(unsigned long);
continue; continue;
} }
if (*format == 'l' && *(format + 1) == 'l') { if (*format == 'l' && *(format + 1) == 'l') {
while (acnt & (sizeof(unsigned long long)-1)) { while (acnt &
(sizeof(unsigned long long) - 1)) {
va_arg(args, int); va_arg(args, int);
acnt += sizeof(int); acnt += sizeof(int);
} }
if (sizeof(unsigned long long) == if (sizeof(unsigned long long) ==
sizeof(unsigned long)) { sizeof(unsigned long)) {
tmp = va_arg(args, unsigned long long); tmp = va_arg(args, unsigned long long);
acnt += sizeof(unsigned long long); acnt += sizeof(unsigned long long);
} else { } else {
@@ -270,48 +269,51 @@ static int print(char **out, u32 *out_len, const char *format, va_list args)
va_arg(args, unsigned long); va_arg(args, unsigned long);
((unsigned long *)&tmp)[1] = ((unsigned long *)&tmp)[1] =
va_arg(args, unsigned long); va_arg(args, unsigned long);
acnt += 2*sizeof(unsigned long); acnt += 2 * sizeof(unsigned long);
} }
if (*(format + 2) == 'u') { if (*(format + 2) == 'u') {
format += 2; format += 2;
pc += printi(out, out_len, tmp, pc += printi(out, out_len, tmp, 10, 0,
10, 0, width, flags, 'a'); width, flags, 'a');
} else if (*(format + 2) == 'x') { } else if (*(format + 2) == 'x') {
format += 2; format += 2;
pc += printi(out, out_len, tmp, pc += printi(out, out_len, tmp, 16, 0,
16, 0, width, flags, 'a'); width, flags, 'a');
} else if (*(format + 2) == 'X') { } else if (*(format + 2) == 'X') {
format += 2; format += 2;
pc += printi(out, out_len, tmp, pc += printi(out, out_len, tmp, 16, 0,
16, 0, width, flags, 'A'); width, flags, 'A');
} else { } else {
format += 1; format += 1;
pc += printi(out, out_len, tmp, pc += printi(out, out_len, tmp, 10, 1,
10, 1, width, flags, '0'); width, flags, '0');
} }
continue; continue;
} else if (*format == 'l') { } else if (*format == 'l') {
if (*(format + 1) == 'u') { if (*(format + 1) == 'u') {
format += 1; format += 1;
pc += printi(out, out_len, pc += printi(
va_arg(args, unsigned long), out, out_len,
10, 0, width, flags, 'a'); va_arg(args, unsigned long), 10,
0, width, flags, 'a');
} else if (*(format + 1) == 'x') { } else if (*(format + 1) == 'x') {
format += 1; format += 1;
pc += printi(out, out_len, pc += printi(
va_arg(args, unsigned long), out, out_len,
16, 0, width, flags, 'a'); va_arg(args, unsigned long), 16,
0, width, flags, 'a');
acnt += sizeof(unsigned long); acnt += sizeof(unsigned long);
} else if (*(format + 1) == 'X') { } else if (*(format + 1) == 'X') {
format += 1; format += 1;
pc += printi(out, out_len, pc += printi(
va_arg(args, unsigned long), out, out_len,
16, 0, width, flags, 'A'); va_arg(args, unsigned long), 16,
0, width, flags, 'A');
acnt += sizeof(unsigned long); acnt += sizeof(unsigned long);
} else { } else {
pc += printi(out, out_len, pc += printi(out, out_len,
va_arg(args, long), va_arg(args, long), 10, 1,
10, 1, width, flags, '0'); width, flags, '0');
acnt += sizeof(long); acnt += sizeof(long);
} }
} }
@@ -324,7 +326,7 @@ static int print(char **out, u32 *out_len, const char *format, va_list args)
continue; continue;
} }
} else { } else {
out: out:
printc(out, out_len, *format); printc(out, out_len, *format);
++pc; ++pc;
} }
@@ -373,6 +375,19 @@ int sbi_printf(const char *format, ...)
return retval; return retval;
} }
int sbi_dprintf(struct sbi_scratch *scratch, const char *format, ...)
{
va_list args;
int retval = 0;
va_start(args, format);
if (scratch->options & SBI_SCRATCH_DEBUG_PRINTS)
retval = print(NULL, NULL, format, args);
va_end(args);
return retval;
}
int sbi_console_init(struct sbi_scratch *scratch) int sbi_console_init(struct sbi_scratch *scratch)
{ {
console_plat = sbi_platform_ptr(scratch); console_plat = sbi_platform_ptr(scratch);

149
lib/sbi/sbi_ecall.c Normal file
View File

@@ -0,0 +1,149 @@
/*
* SPDX-License-Identifier: BSD-2-Clause
*
* Copyright (c) 2019 Western Digital Corporation or its affiliates.
*
* Authors:
* Anup Patel <anup.patel@wdc.com>
*/
#include <sbi/sbi_ecall.h>
#include <sbi/sbi_ecall_interface.h>
#include <sbi/sbi_error.h>
#include <sbi/sbi_trap.h>
u16 sbi_ecall_version_major(void)
{
return SBI_ECALL_VERSION_MAJOR;
}
u16 sbi_ecall_version_minor(void)
{
return SBI_ECALL_VERSION_MINOR;
}
static SBI_LIST_HEAD(ecall_exts_list);
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;
}
void sbi_ecall_unregister_extension(struct sbi_ecall_extension *ext)
{
bool found = FALSE;
struct sbi_ecall_extension *t;
if (!ext)
return;
sbi_list_for_each_entry(t, &ecall_exts_list, head) {
if (t == ext) {
found = TRUE;
break;
}
}
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;
struct sbi_trap_info trap = {0};
unsigned long out_val = 0;
bool is_0_1_spec = 0;
unsigned long args[6];
args[0] = regs->a0;
args[1] = regs->a1;
args[2] = regs->a2;
args[3] = regs->a3;
args[4] = regs->a4;
args[5] = regs->a5;
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) {
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
* between a fatal and non-fatal errors yet. That's why we treat
* every return value except ETRAP as non-fatal and just return
* accordingly for now. Once fatal errors are defined, that
* case should be handled differently.
*/
regs->mepc += 4;
regs->a0 = ret;
if (!is_0_1_spec)
regs->a1 = out_val;
}
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

@@ -14,18 +14,30 @@
#include <sbi/sbi_emulate_csr.h> #include <sbi/sbi_emulate_csr.h>
#include <sbi/sbi_error.h> #include <sbi/sbi_error.h>
#include <sbi/sbi_timer.h> #include <sbi/sbi_timer.h>
#include <sbi/sbi_trap.h>
int sbi_emulate_csr_read(int csr_num, int sbi_emulate_csr_read(int csr_num, u32 hartid, struct sbi_trap_regs *regs,
u32 hartid, ulong mstatus, struct sbi_scratch *scratch, ulong *csr_val)
struct sbi_scratch *scratch,
ulong *csr_val)
{ {
int ret = 0;
ulong cen = -1UL; ulong cen = -1UL;
ulong prev_mode = (regs->mstatus & MSTATUS_MPP) >> MSTATUS_MPP_SHIFT;
#if __riscv_xlen == 32
bool virt = (regs->mstatusH & MSTATUSH_MPV) ? TRUE : FALSE;
#else
bool virt = (regs->mstatus & MSTATUS_MPV) ? TRUE : FALSE;
#endif
if (EXTRACT_FIELD(mstatus, MSTATUS_MPP) == PRV_U) if (prev_mode == PRV_U)
cen = csr_read(CSR_SCOUNTEREN); cen = csr_read(CSR_SCOUNTEREN);
switch (csr_num) { switch (csr_num) {
case CSR_HTIMEDELTA:
if (prev_mode == PRV_S && !virt)
*csr_val = sbi_timer_get_delta(scratch);
else
ret = SBI_ENOTSUPP;
break;
case CSR_CYCLE: case CSR_CYCLE:
if (!((cen >> (CSR_CYCLE - CSR_CYCLE)) & 1)) if (!((cen >> (CSR_CYCLE - CSR_CYCLE)) & 1))
return -1; return -1;
@@ -34,7 +46,8 @@ int sbi_emulate_csr_read(int csr_num,
case CSR_TIME: case CSR_TIME:
if (!((cen >> (CSR_TIME - CSR_CYCLE)) & 1)) if (!((cen >> (CSR_TIME - CSR_CYCLE)) & 1))
return -1; return -1;
*csr_val = sbi_timer_value(scratch); *csr_val = (virt) ? sbi_timer_virt_value(scratch):
sbi_timer_value(scratch);
break; break;
case CSR_INSTRET: case CSR_INSTRET:
if (!((cen >> (CSR_INSTRET - CSR_CYCLE)) & 1)) if (!((cen >> (CSR_INSTRET - CSR_CYCLE)) & 1))
@@ -52,6 +65,12 @@ int sbi_emulate_csr_read(int csr_num,
*csr_val = csr_read(CSR_MHPMCOUNTER4); *csr_val = csr_read(CSR_MHPMCOUNTER4);
break; break;
#if __riscv_xlen == 32 #if __riscv_xlen == 32
case CSR_HTIMEDELTAH:
if (prev_mode == PRV_S && !virt)
*csr_val = sbi_timer_get_delta(scratch) >> 32;
else
ret = SBI_ENOTSUPP;
break;
case CSR_CYCLEH: case CSR_CYCLEH:
if (!((cen >> (CSR_CYCLE - CSR_CYCLE)) & 1)) if (!((cen >> (CSR_CYCLE - CSR_CYCLE)) & 1))
return -1; return -1;
@@ -60,7 +79,8 @@ int sbi_emulate_csr_read(int csr_num,
case CSR_TIMEH: case CSR_TIMEH:
if (!((cen >> (CSR_TIME - CSR_CYCLE)) & 1)) if (!((cen >> (CSR_TIME - CSR_CYCLE)) & 1))
return -1; return -1;
*csr_val = sbi_timer_value(scratch) >> 32; *csr_val = (virt) ? sbi_timer_virt_value(scratch) >> 32:
sbi_timer_value(scratch) >> 32;
break; break;
case CSR_INSTRETH: case CSR_INSTRETH:
if (!((cen >> (CSR_INSTRET - CSR_CYCLE)) & 1)) if (!((cen >> (CSR_INSTRET - CSR_CYCLE)) & 1))
@@ -85,20 +105,35 @@ int sbi_emulate_csr_read(int csr_num,
*csr_val = csr_read(CSR_MHPMEVENT4); *csr_val = csr_read(CSR_MHPMEVENT4);
break; break;
default: default:
sbi_printf("%s: hartid%d: invalid csr_num=0x%x\n", ret = SBI_ENOTSUPP;
__func__, hartid, csr_num); break;
return SBI_ENOTSUPP;
}; };
return 0; if (ret)
sbi_dprintf(scratch, "%s: hartid%d: invalid csr_num=0x%x\n",
__func__, hartid, csr_num);
return ret;
} }
int sbi_emulate_csr_write(int csr_num, int sbi_emulate_csr_write(int csr_num, u32 hartid, struct sbi_trap_regs *regs,
u32 hartid, ulong mstatus, struct sbi_scratch *scratch, ulong csr_val)
struct sbi_scratch *scratch,
ulong csr_val)
{ {
int ret = 0;
ulong prev_mode = (regs->mstatus & MSTATUS_MPP) >> MSTATUS_MPP_SHIFT;
#if __riscv_xlen == 32
bool virt = (regs->mstatusH & MSTATUSH_MPV) ? TRUE : FALSE;
#else
bool virt = (regs->mstatus & MSTATUS_MPV) ? TRUE : FALSE;
#endif
switch (csr_num) { switch (csr_num) {
case CSR_HTIMEDELTA:
if (prev_mode == PRV_S && !virt)
sbi_timer_set_delta(scratch, csr_val);
else
ret = SBI_ENOTSUPP;
break;
case CSR_CYCLE: case CSR_CYCLE:
csr_write(CSR_MCYCLE, csr_val); csr_write(CSR_MCYCLE, csr_val);
break; break;
@@ -112,6 +147,12 @@ int sbi_emulate_csr_write(int csr_num,
csr_write(CSR_MHPMCOUNTER4, csr_val); csr_write(CSR_MHPMCOUNTER4, csr_val);
break; break;
#if __riscv_xlen == 32 #if __riscv_xlen == 32
case CSR_HTIMEDELTAH:
if (prev_mode == PRV_S && !virt)
sbi_timer_set_delta_upper(scratch, csr_val);
else
ret = SBI_ENOTSUPP;
break;
case CSR_CYCLEH: case CSR_CYCLEH:
csr_write(CSR_MCYCLEH, csr_val); csr_write(CSR_MCYCLEH, csr_val);
break; break;
@@ -132,10 +173,13 @@ int sbi_emulate_csr_write(int csr_num,
csr_write(CSR_MHPMEVENT4, csr_val); csr_write(CSR_MHPMEVENT4, csr_val);
break; break;
default: default:
sbi_printf("%s: hartid%d: invalid csr_num=0x%x\n", ret = SBI_ENOTSUPP;
__func__, hartid, csr_num); break;
return SBI_ENOTSUPP;
}; };
return 0; if (ret)
sbi_dprintf(scratch, "%s: hartid%d: invalid csr_num=0x%x\n",
__func__, hartid, csr_num);
return ret;
} }

192
lib/sbi/sbi_fifo.c Normal file
View File

@@ -0,0 +1,192 @@
/*
* SPDX-License-Identifier: BSD-2-Clause
*
* Copyright (c) 2019 Western Digital Corporation or its affiliates.
*
* Authors:
* Atish Patra<atish.patra@wdc.com>
*
*/
#include <sbi/riscv_locks.h>
#include <sbi/sbi_error.h>
#include <sbi/sbi_fifo.h>
#include <sbi/sbi_string.h>
void sbi_fifo_init(struct sbi_fifo *fifo, void *queue_mem, u16 entries,
u16 entry_size)
{
fifo->queue = queue_mem;
fifo->num_entries = entries;
fifo->entry_size = entry_size;
SPIN_LOCK_INIT(&fifo->qlock);
fifo->avail = fifo->tail = 0;
sbi_memset(fifo->queue, 0, (size_t)entries * entry_size);
}
/* Note: must be called with fifo->qlock held */
static inline bool __sbi_fifo_is_full(struct sbi_fifo *fifo)
{
return (fifo->avail == fifo->num_entries) ? TRUE : FALSE;
}
u16 sbi_fifo_avail(struct sbi_fifo *fifo)
{
u16 ret;
if (!fifo)
return 0;
spin_lock(&fifo->qlock);
ret = fifo->avail;
spin_unlock(&fifo->qlock);
return ret;
}
bool sbi_fifo_is_full(struct sbi_fifo *fifo)
{
bool ret;
spin_lock(&fifo->qlock);
ret = __sbi_fifo_is_full(fifo);
spin_unlock(&fifo->qlock);
return ret;
}
/* Note: must be called with fifo->qlock held */
static inline void __sbi_fifo_enqueue(struct sbi_fifo *fifo, void *data)
{
u32 head;
head = (u32)fifo->tail + fifo->avail;
if (head >= fifo->num_entries)
head = head - fifo->num_entries;
sbi_memcpy(fifo->queue + head * fifo->entry_size, data, fifo->entry_size);
fifo->avail++;
}
/* Note: must be called with fifo->qlock held */
static inline bool __sbi_fifo_is_empty(struct sbi_fifo *fifo)
{
return (fifo->avail == 0) ? TRUE : FALSE;
}
bool sbi_fifo_is_empty(struct sbi_fifo *fifo)
{
bool ret;
spin_lock(&fifo->qlock);
ret = __sbi_fifo_is_empty(fifo);
spin_unlock(&fifo->qlock);
return ret;
}
/* Note: must be called with fifo->qlock held */
static inline void __sbi_fifo_reset(struct sbi_fifo *fifo)
{
size_t size = (size_t)fifo->num_entries * fifo->entry_size;
fifo->avail = 0;
fifo->tail = 0;
sbi_memset(fifo->queue, 0, size);
}
bool sbi_fifo_reset(struct sbi_fifo *fifo)
{
if (!fifo)
return FALSE;
spin_lock(&fifo->qlock);
__sbi_fifo_reset(fifo);
spin_unlock(&fifo->qlock);
return TRUE;
}
/**
* Provide a helper function to do inplace update to the fifo.
* Note: The callback function is called with lock being held.
*
* **Do not** invoke any other fifo function from callback. Otherwise, it will
* lead to deadlock.
*/
int sbi_fifo_inplace_update(struct sbi_fifo *fifo, void *in,
int (*fptr)(void *in, void *data))
{
int i, index = 0;
int ret = SBI_FIFO_UNCHANGED;
void *entry;
if (!fifo || !in)
return ret;
spin_lock(&fifo->qlock);
if (__sbi_fifo_is_empty(fifo)) {
spin_unlock(&fifo->qlock);
return ret;
}
for (i = 0; i < fifo->avail; i++) {
index = fifo->tail + i;
if (index >= fifo->num_entries)
index = index - fifo->num_entries;
entry = (void *)fifo->queue + (u32)index * fifo->entry_size;
ret = fptr(in, entry);
if (ret == SBI_FIFO_SKIP || ret == SBI_FIFO_UPDATED) {
break;
}
}
spin_unlock(&fifo->qlock);
return ret;
}
int sbi_fifo_enqueue(struct sbi_fifo *fifo, void *data)
{
if (!fifo || !data)
return SBI_EINVAL;
spin_lock(&fifo->qlock);
if (__sbi_fifo_is_full(fifo)) {
spin_unlock(&fifo->qlock);
return SBI_ENOSPC;
}
__sbi_fifo_enqueue(fifo, data);
spin_unlock(&fifo->qlock);
return 0;
}
int sbi_fifo_dequeue(struct sbi_fifo *fifo, void *data)
{
if (!fifo || !data)
return SBI_EINVAL;
spin_lock(&fifo->qlock);
if (__sbi_fifo_is_empty(fifo)) {
spin_unlock(&fifo->qlock);
return SBI_ENOENT;
}
sbi_memcpy(data, fifo->queue + (u32)fifo->tail * fifo->entry_size,
fifo->entry_size);
fifo->avail--;
fifo->tail++;
if (fifo->tail >= fifo->num_entries)
fifo->tail = 0;
spin_unlock(&fifo->qlock);
return 0;
}

View File

@@ -28,15 +28,14 @@ unsigned int sbi_current_hartid()
static void mstatus_init(struct sbi_scratch *scratch, u32 hartid) static void mstatus_init(struct sbi_scratch *scratch, u32 hartid)
{ {
struct sbi_platform *plat = sbi_platform_ptr(scratch); const struct sbi_platform *plat = sbi_platform_ptr(scratch);
/* Enable FPU */ /* Enable FPU */
if (misa_extension('D') || misa_extension('F')) if (misa_extension('D') || misa_extension('F'))
csr_write(CSR_MSTATUS, MSTATUS_FS); csr_write(CSR_MSTATUS, MSTATUS_FS);
/* Enable user/supervisor use of perf counters */ /* Enable user/supervisor use of perf counters */
if (misa_extension('S') && if (misa_extension('S') && sbi_platform_has_scounteren(plat))
sbi_platform_has_scounteren(plat))
csr_write(CSR_SCOUNTEREN, -1); csr_write(CSR_SCOUNTEREN, -1);
if (sbi_platform_has_mcounteren(plat)) if (sbi_platform_has_mcounteren(plat))
csr_write(CSR_MCOUNTEREN, -1); csr_write(CSR_MCOUNTEREN, -1);
@@ -53,8 +52,6 @@ static int fp_init(u32 hartid)
{ {
#ifdef __riscv_flen #ifdef __riscv_flen
int i; int i;
#else
unsigned long fd_mask;
#endif #endif
if (!misa_extension('D') && !misa_extension('F')) if (!misa_extension('D') && !misa_extension('F'))
@@ -67,11 +64,6 @@ static int fp_init(u32 hartid)
for (i = 0; i < 32; i++) for (i = 0; i < 32; i++)
init_fp_reg(i); init_fp_reg(i);
csr_write(CSR_FCSR, 0); csr_write(CSR_FCSR, 0);
#else
fd_mask = (1 << ('F' - 'A')) | (1 << ('D' - 'A'));
csr_clear(CSR_MISA, fd_mask);
if (csr_read(CSR_MISA) & fd_mask)
return SBI_ENOTSUPP;
#endif #endif
return 0; return 0;
@@ -79,7 +71,7 @@ static int fp_init(u32 hartid)
static int delegate_traps(struct sbi_scratch *scratch, u32 hartid) static int delegate_traps(struct sbi_scratch *scratch, u32 hartid)
{ {
struct sbi_platform *plat = sbi_platform_ptr(scratch); const struct sbi_platform *plat = sbi_platform_ptr(scratch);
unsigned long interrupts, exceptions; unsigned long interrupts, exceptions;
if (!misa_extension('S')) if (!misa_extension('S'))
@@ -88,25 +80,44 @@ static int delegate_traps(struct sbi_scratch *scratch, u32 hartid)
/* Send M-mode interrupts and most exceptions to S-mode */ /* Send M-mode interrupts and most exceptions to S-mode */
interrupts = MIP_SSIP | MIP_STIP | MIP_SEIP; interrupts = MIP_SSIP | MIP_STIP | MIP_SEIP;
exceptions = (1U << CAUSE_MISALIGNED_FETCH) | exceptions = (1U << CAUSE_MISALIGNED_FETCH) | (1U << CAUSE_BREAKPOINT) |
(1U << CAUSE_BREAKPOINT) |
(1U << CAUSE_USER_ECALL); (1U << CAUSE_USER_ECALL);
if (sbi_platform_has_mfaults_delegation(plat)) if (sbi_platform_has_mfaults_delegation(plat))
exceptions |= (1U << CAUSE_FETCH_PAGE_FAULT) | exceptions |= (1U << CAUSE_FETCH_PAGE_FAULT) |
(1U << CAUSE_LOAD_PAGE_FAULT) | (1U << CAUSE_LOAD_PAGE_FAULT) |
(1U << CAUSE_STORE_PAGE_FAULT); (1U << CAUSE_STORE_PAGE_FAULT);
/*
* 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')) {
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_MIDELEG, interrupts);
csr_write(CSR_MEDELEG, exceptions); 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; 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 log2roundup(unsigned long x)
{ {
unsigned long ret = 0; unsigned long ret = 0;
@@ -122,7 +133,7 @@ unsigned long log2roundup(unsigned long x)
void sbi_hart_pmp_dump(struct sbi_scratch *scratch) void sbi_hart_pmp_dump(struct sbi_scratch *scratch)
{ {
struct sbi_platform *plat = sbi_platform_ptr(scratch); const struct sbi_platform *plat = sbi_platform_ptr(scratch);
unsigned long prot, addr, size, l2l; unsigned long prot, addr, size, l2l;
unsigned int i; unsigned int i;
@@ -138,9 +149,9 @@ void sbi_hart_pmp_dump(struct sbi_scratch *scratch)
else else
size = 0; size = 0;
#if __riscv_xlen == 32 #if __riscv_xlen == 32
sbi_printf("PMP%d: 0x%08lx-0x%08lx (A", sbi_printf("PMP%d : 0x%08lx-0x%08lx (A",
#else #else
sbi_printf("PMP%d: 0x%016lx-0x%016lx (A", sbi_printf("PMP%d : 0x%016lx-0x%016lx (A",
#endif #endif
i, addr, addr + size - 1); i, addr, addr + size - 1);
if (prot & PMP_L) if (prot & PMP_L)
@@ -160,13 +171,13 @@ static int pmp_init(struct sbi_scratch *scratch, u32 hartid)
u32 i, count; u32 i, count;
unsigned long fw_start, fw_size_log2; unsigned long fw_start, fw_size_log2;
ulong prot, addr, log2size; ulong prot, addr, log2size;
struct sbi_platform *plat = sbi_platform_ptr(scratch); const struct sbi_platform *plat = sbi_platform_ptr(scratch);
if (!sbi_platform_has_pmp(plat)) if (!sbi_platform_has_pmp(plat))
return 0; return 0;
fw_size_log2 = log2roundup(scratch->fw_size); fw_size_log2 = log2roundup(scratch->fw_size);
fw_start = scratch->fw_start & ~((1UL << fw_size_log2) - 1UL); fw_start = scratch->fw_start & ~((1UL << fw_size_log2) - 1UL);
pmp_set(0, 0, fw_start, fw_size_log2); pmp_set(0, 0, fw_start, fw_size_log2);
@@ -175,8 +186,8 @@ static int pmp_init(struct sbi_scratch *scratch, u32 hartid)
count = (PMP_COUNT - 1); count = (PMP_COUNT - 1);
for (i = 0; i < count; i++) { for (i = 0; i < count; i++) {
if (sbi_platform_pmp_region_info(plat, hartid, i, if (sbi_platform_pmp_region_info(plat, hartid, i, &prot, &addr,
&prot, &addr, &log2size)) &log2size))
continue; continue;
pmp_set(i + 1, prot, addr, log2size); pmp_set(i + 1, prot, addr, log2size);
} }
@@ -184,10 +195,19 @@ static int pmp_init(struct sbi_scratch *scratch, u32 hartid)
return 0; return 0;
} }
int sbi_hart_init(struct sbi_scratch *scratch, u32 hartid) static unsigned long trap_info_offset;
int sbi_hart_init(struct sbi_scratch *scratch, u32 hartid, bool cold_boot)
{ {
int rc; int rc;
if (cold_boot) {
trap_info_offset = sbi_scratch_alloc_offset(__SIZEOF_POINTER__,
"HART_TRAP_INFO");
if (!trap_info_offset)
return SBI_ENOMEM;
}
mstatus_init(scratch, hartid); mstatus_init(scratch, hartid);
rc = fp_init(hartid); rc = fp_init(hartid);
@@ -201,6 +221,29 @@ int sbi_hart_init(struct sbi_scratch *scratch, u32 hartid)
return pmp_init(scratch, hartid); return pmp_init(scratch, hartid);
} }
void *sbi_hart_get_trap_info(struct sbi_scratch *scratch)
{
unsigned long *trap_info;
if (!trap_info_offset)
return NULL;
trap_info = sbi_scratch_offset_ptr(scratch, trap_info_offset);
return (void *)(*trap_info);
}
void sbi_hart_set_trap_info(struct sbi_scratch *scratch, void *data)
{
unsigned long *trap_info;
if (!trap_info_offset)
return;
trap_info = sbi_scratch_offset_ptr(scratch, trap_info_offset);
*trap_info = (unsigned long)data;
}
void __attribute__((noreturn)) sbi_hart_hang(void) void __attribute__((noreturn)) sbi_hart_hang(void)
{ {
while (1) while (1)
@@ -208,12 +251,16 @@ void __attribute__((noreturn)) sbi_hart_hang(void)
__builtin_unreachable(); __builtin_unreachable();
} }
void __attribute__((noreturn)) sbi_hart_switch_mode(unsigned long arg0, void __attribute__((noreturn))
unsigned long arg1, sbi_hart_switch_mode(unsigned long arg0, unsigned long arg1,
unsigned long next_addr, unsigned long next_addr, unsigned long next_mode,
unsigned long next_mode) bool next_virt)
{ {
#if __riscv_xlen == 32
unsigned long val, valH;
#else
unsigned long val; unsigned long val;
#endif
switch (next_mode) { switch (next_mode) {
case PRV_M: case PRV_M:
@@ -233,7 +280,23 @@ void __attribute__((noreturn)) sbi_hart_switch_mode(unsigned long arg0,
val = csr_read(CSR_MSTATUS); val = csr_read(CSR_MSTATUS);
val = INSERT_FIELD(val, MSTATUS_MPP, next_mode); val = INSERT_FIELD(val, MSTATUS_MPP, next_mode);
val = INSERT_FIELD(val, MSTATUS_MPIE, 0); val = INSERT_FIELD(val, MSTATUS_MPIE, 0);
#if __riscv_xlen == 32
if (misa_extension('H')) {
valH = csr_read(CSR_MSTATUSH);
if (next_virt)
valH = INSERT_FIELD(valH, MSTATUSH_MPV, 1);
else
valH = INSERT_FIELD(valH, MSTATUSH_MPV, 0);
csr_write(CSR_MSTATUSH, valH);
}
#else
if (misa_extension('H')) {
if (next_virt)
val = INSERT_FIELD(val, MSTATUS_MPV, 1);
else
val = INSERT_FIELD(val, MSTATUS_MPV, 0);
}
#endif
csr_write(CSR_MSTATUS, val); csr_write(CSR_MSTATUS, val);
csr_write(CSR_MEPC, next_addr); csr_write(CSR_MEPC, next_addr);
@@ -248,13 +311,13 @@ void __attribute__((noreturn)) sbi_hart_switch_mode(unsigned long arg0,
csr_write(CSR_UIE, 0); csr_write(CSR_UIE, 0);
} }
register unsigned long a0 asm ("a0") = arg0; register unsigned long a0 asm("a0") = arg0;
register unsigned long a1 asm ("a1") = arg1; register unsigned long a1 asm("a1") = arg1;
__asm__ __volatile__ ("mret" : : "r" (a0), "r" (a1)); __asm__ __volatile__("mret" : : "r"(a0), "r"(a1));
__builtin_unreachable(); __builtin_unreachable();
} }
static spinlock_t avail_hart_mask_lock = SPIN_LOCK_INITIALIZER; static spinlock_t avail_hart_mask_lock = SPIN_LOCK_INITIALIZER;
static volatile unsigned long avail_hart_mask = 0; static volatile unsigned long avail_hart_mask = 0;
void sbi_hart_mark_available(u32 hartid) void sbi_hart_mark_available(u32 hartid)
@@ -290,48 +353,69 @@ struct sbi_scratch *sbi_hart_id_to_scratch(struct sbi_scratch *scratch,
return ((h2s)scratch->hartid_to_scratch)(hartid); return ((h2s)scratch->hartid_to_scratch)(hartid);
} }
#define COLDBOOT_WAIT_BITMAP_SIZE __riscv_xlen #define COLDBOOT_WAIT_BITMAP_SIZE __riscv_xlen
static spinlock_t coldboot_wait_bitmap_lock = SPIN_LOCK_INITIALIZER; static spinlock_t coldboot_lock = SPIN_LOCK_INITIALIZER;
static unsigned long coldboot_done = 0;
static unsigned long coldboot_wait_bitmap = 0; static unsigned long coldboot_wait_bitmap = 0;
void sbi_hart_wait_for_coldboot(struct sbi_scratch *scratch, u32 hartid) void sbi_hart_wait_for_coldboot(struct sbi_scratch *scratch, u32 hartid)
{ {
unsigned long mipval; unsigned long saved_mie;
struct sbi_platform *plat = sbi_platform_ptr(scratch); const struct sbi_platform *plat = sbi_platform_ptr(scratch);
if ((sbi_platform_hart_count(plat) <= hartid) || if ((sbi_platform_hart_count(plat) <= hartid) ||
(COLDBOOT_WAIT_BITMAP_SIZE <= hartid)) (COLDBOOT_WAIT_BITMAP_SIZE <= hartid))
sbi_hart_hang(); sbi_hart_hang();
/* Save MIE CSR */
saved_mie = csr_read(CSR_MIE);
/* Set MSIE bit to receive IPI */ /* Set MSIE bit to receive IPI */
csr_set(CSR_MIE, MIP_MSIP); csr_set(CSR_MIE, MIP_MSIP);
do { /* Acquire coldboot lock */
spin_lock(&coldboot_wait_bitmap_lock); spin_lock(&coldboot_lock);
coldboot_wait_bitmap |= (1UL << hartid);
spin_unlock(&coldboot_wait_bitmap_lock);
/* Mark current HART as waiting */
coldboot_wait_bitmap |= (1UL << hartid);
/* Wait for coldboot to finish using WFI */
while (!coldboot_done) {
spin_unlock(&coldboot_lock);
wfi(); wfi();
mipval = csr_read(CSR_MIP); spin_lock(&coldboot_lock);
};
spin_lock(&coldboot_wait_bitmap_lock); /* Unmark current HART as waiting */
coldboot_wait_bitmap &= ~(1UL << hartid); coldboot_wait_bitmap &= ~(1UL << hartid);
spin_unlock(&coldboot_wait_bitmap_lock);
} while (!(mipval && MIP_MSIP));
csr_clear(CSR_MIP, MIP_MSIP); /* 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);
} }
void sbi_hart_wake_coldboot_harts(struct sbi_scratch *scratch, u32 hartid) void sbi_hart_wake_coldboot_harts(struct sbi_scratch *scratch, u32 hartid)
{ {
struct sbi_platform *plat = sbi_platform_ptr(scratch); const struct sbi_platform *plat = sbi_platform_ptr(scratch);
int max_hart = sbi_platform_hart_count(plat); int max_hart = sbi_platform_hart_count(plat);
for(int i = 0; i < max_hart ; i++) { /* Acquire coldboot lock */
/* send an IPI to every other hart */ spin_lock(&coldboot_lock);
spin_lock(&coldboot_wait_bitmap_lock);
/* Mark coldboot done */
coldboot_done = 1;
/* Send an IPI to all HARTs waiting for coldboot */
for (int i = 0; i < max_hart; i++) {
if ((i != hartid) && (coldboot_wait_bitmap & (1UL << i))) if ((i != hartid) && (coldboot_wait_bitmap & (1UL << i)))
sbi_platform_ipi_send(plat, i); sbi_platform_ipi_send(plat, i);
spin_unlock(&coldboot_wait_bitmap_lock);
} }
/* Release coldboot lock */
spin_unlock(&coldboot_lock);
} }

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

@@ -16,31 +16,48 @@
#include <sbi/sbi_trap.h> #include <sbi/sbi_trap.h>
#include <sbi/sbi_unpriv.h> #include <sbi/sbi_unpriv.h>
typedef int (*illegal_insn_func)(ulong insn, typedef int (*illegal_insn_func)(ulong insn, u32 hartid, ulong mcause,
u32 hartid, ulong mcause,
struct sbi_trap_regs *regs, struct sbi_trap_regs *regs,
struct sbi_scratch *scratch); struct sbi_scratch *scratch);
static int truly_illegal_insn(ulong insn, static int truly_illegal_insn(ulong insn, u32 hartid, ulong mcause,
u32 hartid, ulong mcause,
struct sbi_trap_regs *regs, struct sbi_trap_regs *regs,
struct sbi_scratch *scratch) 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, static int system_opcode_insn(ulong insn, u32 hartid, ulong mcause,
u32 hartid, ulong mcause,
struct sbi_trap_regs *regs, struct sbi_trap_regs *regs,
struct sbi_scratch *scratch) struct sbi_scratch *scratch)
{ {
int do_write, rs1_num = (insn >> 15) & 0x1f; int do_write, rs1_num = (insn >> 15) & 0x1f;
ulong rs1_val = GET_RS1(insn, regs); ulong rs1_val = GET_RS1(insn, regs);
int csr_num = (u32)insn >> 20; int csr_num = (u32)insn >> 20;
ulong csr_val, new_csr_val; ulong csr_val, new_csr_val;
if (sbi_emulate_csr_read(csr_num, hartid, regs->mstatus, /*
scratch, &csr_val)) * WFI always traps as illegal instruction when executed from
* VS/VU mode so we just forward it to HS-mode.
*/
#if __riscv_xlen == 32
if ((regs->mstatusH & MSTATUSH_MPV) &&
#else
if ((regs->mstatus & MSTATUS_MPV) &&
#endif
(insn & INSN_MASK_WFI) == INSN_MATCH_WFI)
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, return truly_illegal_insn(insn, hartid, mcause,
regs, scratch); regs, scratch);
@@ -48,16 +65,17 @@ static int system_opcode_insn(ulong insn,
switch (GET_RM(insn)) { switch (GET_RM(insn)) {
case 1: case 1:
new_csr_val = rs1_val; new_csr_val = rs1_val;
do_write = 1; do_write = 1;
break; break;
case 2: case 2:
new_csr_val = csr_val | rs1_val; new_csr_val = csr_val | rs1_val;
break; break;
case 3: new_csr_val = csr_val & ~rs1_val; case 3:
new_csr_val = csr_val & ~rs1_val;
break; break;
case 5: case 5:
new_csr_val = rs1_num; new_csr_val = rs1_num;
do_write = 1; do_write = 1;
break; break;
case 6: case 6:
new_csr_val = csr_val | rs1_num; new_csr_val = csr_val | rs1_num;
@@ -66,15 +84,12 @@ static int system_opcode_insn(ulong insn,
new_csr_val = csr_val & ~rs1_num; new_csr_val = csr_val & ~rs1_num;
break; break;
default: default:
return truly_illegal_insn(insn, hartid, mcause, return truly_illegal_insn(insn, hartid, mcause, regs, scratch);
regs, scratch);
}; };
if (do_write && if (do_write && sbi_emulate_csr_write(csr_num, hartid, regs,
sbi_emulate_csr_write(csr_num, hartid, regs->mstatus, scratch, new_csr_val))
scratch, new_csr_val)) return truly_illegal_insn(insn, hartid, mcause, regs, scratch);
return truly_illegal_insn(insn, hartid, mcause,
regs, scratch);
SET_RD(insn, regs, csr_val); SET_RD(insn, regs, csr_val);
@@ -118,21 +133,24 @@ static illegal_insn_func illegal_insn_table[32] = {
truly_illegal_insn /* 31 */ 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_trap_regs *regs,
struct sbi_scratch *scratch) struct sbi_scratch *scratch)
{ {
ulong mstatus; struct sbi_trap_info uptrap;
ulong insn = csr_read(mbadaddr);
if (unlikely((insn & 3) != 3)) { if (unlikely((insn & 3) != 3)) {
if (insn == 0) { if (insn == 0) {
mstatus = csr_read(CSR_MSTATUS); insn = sbi_get_insn(regs->mepc, scratch, &uptrap);
insn = get_insn(regs->mepc, &mstatus); if (uptrap.cause) {
uptrap.epc = regs->mepc;
return sbi_trap_redirect(regs, &uptrap,
scratch);
}
} }
if ((insn & 3) != 3) if ((insn & 3) != 3)
return truly_illegal_insn(insn, hartid, mcause, return truly_illegal_insn(insn, hartid, mcause, regs,
regs, scratch); scratch);
} }
return illegal_insn_table[(insn & 0x7c) >> 2](insn, hartid, mcause, return illegal_insn_table[(insn & 0x7c) >> 2](insn, hartid, mcause,

264
lib/sbi/sbi_init.c Normal file
View File

@@ -0,0 +1,264 @@
/*
* 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_asm.h>
#include <sbi/riscv_atomic.h>
#include <sbi/sbi_console.h>
#include <sbi/sbi_ecall.h>
#include <sbi/sbi_hart.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_version.h>
#define BANNER \
" ____ _____ ____ _____\n" \
" / __ \\ / ____| _ \\_ _|\n" \
" | | | |_ __ ___ _ __ | (___ | |_) || |\n" \
" | | | | '_ \\ / _ \\ '_ \\ \\___ \\| _ < | |\n" \
" | |__| | |_) | __/ | | |____) | |_) || |_\n" \
" \\____/| .__/ \\___|_| |_|_____/|____/_____|\n" \
" | |\n" \
" |_|\n\n"
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);
#ifdef OPENSBI_VERSION_GIT
sbi_printf("\nOpenSBI %s\n", OPENSBI_VERSION_GIT);
#else
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", xlen, str);
sbi_printf("Platform Max HARTs : %d\n",
sbi_platform_hart_count(plat));
sbi_printf("Current Hart : %u\n", hartid);
/* Firmware details */
sbi_printf("Firmware Base : 0x%lx\n", scratch->fw_start);
sbi_printf("Firmware Size : %d KB\n",
(u32)(scratch->fw_size / 1024));
/* Generic details */
sbi_printf("Runtime SBI Version : %d.%d\n",
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();
rc = sbi_hart_init(scratch, hartid, TRUE);
if (rc)
sbi_hart_hang();
rc = sbi_console_init(scratch);
if (rc)
sbi_hart_hang();
rc = sbi_platform_irqchip_init(plat, TRUE);
if (rc)
sbi_hart_hang();
rc = sbi_ipi_init(scratch, TRUE);
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();
if (!(scratch->options & SBI_SCRATCH_NO_BOOT_PRINTS))
sbi_boot_prints(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);
}
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);
sbi_hart_wait_for_coldboot(scratch, hartid);
if (!init_count_offset)
sbi_hart_hang();
rc = sbi_system_early_init(scratch, FALSE);
if (rc)
sbi_hart_hang();
rc = sbi_hart_init(scratch, hartid, FALSE);
if (rc)
sbi_hart_hang();
rc = sbi_platform_irqchip_init(plat, FALSE);
if (rc)
sbi_hart_hang();
rc = sbi_ipi_init(scratch, FALSE);
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();
rc = sbi_system_final_init(scratch, FALSE);
if (rc)
sbi_hart_hang();
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);
}
static atomic_t coldboot_lottery = ATOMIC_INITIALIZER(0);
/**
* Initialize OpenSBI library for current HART and jump to next
* booting stage.
*
* 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
* 3. Interrupts are disabled in MSTATUS CSR
* 4. All interrupts are disabled in MIE CSR
*
* @param scratch pointer to sbi_scratch of current HART
*/
void __noreturn sbi_init(struct sbi_scratch *scratch)
{
bool coldboot = FALSE;
u32 hartid = sbi_current_hartid();
const struct sbi_platform *plat = sbi_platform_ptr(scratch);
if (sbi_platform_hart_disabled(plat, hartid))
sbi_hart_hang();
if (atomic_add_return(&coldboot_lottery, 1) == 1)
coldboot = TRUE;
if (coldboot)
init_coldboot(scratch, hartid);
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();
}

249
lib/sbi/sbi_ipi.c Normal file
View File

@@ -0,0 +1,249 @@
/*
* SPDX-License-Identifier: BSD-2-Clause
*
* Copyright (c) 2019 Western Digital Corporation or its affiliates.
*
* Authors:
* Anup Patel <anup.patel@wdc.com>
* Nick Kossifidis <mick@ics.forth.gr>
*/
#include <sbi/riscv_asm.h>
#include <sbi/riscv_atomic.h>
#include <sbi/riscv_barrier.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>
struct sbi_ipi_data {
unsigned long ipi_type;
};
static unsigned long ipi_data_off;
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_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, remote_hartid);
ipi_data = sbi_scratch_offset_ptr(remote_scratch, ipi_data_off);
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, remote_hartid);
if (ipi_ops->sync)
ipi_ops->sync(scratch);
return 0;
}
/**
* 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();
ulong tempmask;
unsigned long last_bit = __fls(mask);
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)
sbi_ipi_send(scratch, i, 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);
u32 hartid = sbi_current_hartid();
sbi_platform_ipi_clear(plat, hartid);
ipi_type = atomic_raw_xchg_ulong(&ipi_data->ipi_type, 0);
ipi_event = 0;
while (ipi_type) {
if (!(ipi_type & 1UL))
goto skip;
ipi_ops = ipi_ops_array[ipi_event];
if (ipi_ops && ipi_ops->process)
ipi_ops->process(scratch);
skip:
ipi_type = ipi_type >> 1;
ipi_event++;
};
}
int sbi_ipi_init(struct sbi_scratch *scratch, bool cold_boot)
{
int ret;
struct sbi_ipi_data *ipi_data;
if (cold_boot) {
ipi_data_off = sbi_scratch_alloc_offset(sizeof(*ipi_data),
"IPI_DATA");
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;
/* 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 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

@@ -22,85 +22,121 @@ union reg_data {
}; };
int sbi_misaligned_load_handler(u32 hartid, ulong mcause, int sbi_misaligned_load_handler(u32 hartid, ulong mcause,
ulong addr, ulong tval2, ulong tinst,
struct sbi_trap_regs *regs, struct sbi_trap_regs *regs,
struct sbi_scratch *scratch) struct sbi_scratch *scratch)
{ {
ulong insn;
union reg_data val; union reg_data val;
ulong mstatus = csr_read(CSR_MSTATUS); struct sbi_trap_info uptrap;
ulong insn = get_insn(regs->mepc, &mstatus);
ulong addr = csr_read(CSR_MTVAL);
int i, fp = 0, shift = 0, len = 0; int i, fp = 0, shift = 0, len = 0;
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) { if ((insn & INSN_MASK_LW) == INSN_MATCH_LW) {
len = 4; len = 4;
shift = 8 * (sizeof(ulong) - len); shift = 8 * (sizeof(ulong) - len);
#if __riscv_xlen == 64 #if __riscv_xlen == 64
} else if ((insn & INSN_MASK_LD) == INSN_MATCH_LD) { } else if ((insn & INSN_MASK_LD) == INSN_MATCH_LD) {
len = 8; len = 8;
shift = 8 * (sizeof(ulong) - len); shift = 8 * (sizeof(ulong) - len);
} else if ((insn & INSN_MASK_LWU) == INSN_MATCH_LWU) { } else if ((insn & INSN_MASK_LWU) == INSN_MATCH_LWU) {
len = 4; len = 4;
#endif #endif
#ifdef __riscv_flen
} else if ((insn & INSN_MASK_FLD) == INSN_MATCH_FLD) { } else if ((insn & INSN_MASK_FLD) == INSN_MATCH_FLD) {
fp = 1; fp = 1;
len = 8; len = 8;
} else if ((insn & INSN_MASK_FLW) == INSN_MATCH_FLW) { } else if ((insn & INSN_MASK_FLW) == INSN_MATCH_FLW) {
fp = 1; fp = 1;
len = 4; len = 4;
#endif
} else if ((insn & INSN_MASK_LH) == INSN_MATCH_LH) { } else if ((insn & INSN_MASK_LH) == INSN_MATCH_LH) {
len = 2; len = 2;
shift = 8 * (sizeof(ulong) - len); shift = 8 * (sizeof(ulong) - len);
} else if ((insn & INSN_MASK_LHU) == INSN_MATCH_LHU) { } else if ((insn & INSN_MASK_LHU) == INSN_MATCH_LHU) {
len = 2; len = 2;
#ifdef __riscv_compressed #ifdef __riscv_compressed
# if __riscv_xlen >= 64 #if __riscv_xlen >= 64
} else if ((insn & INSN_MASK_C_LD) == INSN_MATCH_C_LD) { } else if ((insn & INSN_MASK_C_LD) == INSN_MATCH_C_LD) {
len = 8; len = 8;
shift = 8 * (sizeof(ulong) - len); shift = 8 * (sizeof(ulong) - len);
insn = RVC_RS2S(insn) << SH_RD; insn = RVC_RS2S(insn) << SH_RD;
} else if ((insn & INSN_MASK_C_LDSP) == INSN_MATCH_C_LDSP && } else if ((insn & INSN_MASK_C_LDSP) == INSN_MATCH_C_LDSP &&
((insn >> SH_RD) & 0x1f)) { ((insn >> SH_RD) & 0x1f)) {
len = 8; len = 8;
shift = 8 * (sizeof(ulong) - len); shift = 8 * (sizeof(ulong) - len);
# endif #endif
} else if ((insn & INSN_MASK_C_LW) ==INSN_MATCH_C_LW) { } else if ((insn & INSN_MASK_C_LW) == INSN_MATCH_C_LW) {
len = 4; len = 4;
shift = 8 * (sizeof(ulong) - len); shift = 8 * (sizeof(ulong) - len);
insn = RVC_RS2S(insn) << SH_RD; insn = RVC_RS2S(insn) << SH_RD;
} else if ((insn & INSN_MASK_C_LWSP) == INSN_MATCH_C_LWSP && } else if ((insn & INSN_MASK_C_LWSP) == INSN_MATCH_C_LWSP &&
((insn >> SH_RD) & 0x1f)) { ((insn >> SH_RD) & 0x1f)) {
len = 4; len = 4;
shift = 8 * (sizeof(ulong) - len); shift = 8 * (sizeof(ulong) - len);
#ifdef __riscv_flen
} else if ((insn & INSN_MASK_C_FLD) == INSN_MATCH_C_FLD) { } else if ((insn & INSN_MASK_C_FLD) == INSN_MATCH_C_FLD) {
fp = 1; fp = 1;
len = 8; len = 8;
insn = RVC_RS2S(insn) << SH_RD; insn = RVC_RS2S(insn) << SH_RD;
} else if ((insn & INSN_MASK_C_FLDSP) == INSN_MATCH_C_FLDSP) { } else if ((insn & INSN_MASK_C_FLDSP) == INSN_MATCH_C_FLDSP) {
fp = 1; fp = 1;
len = 8; len = 8;
# if __riscv_xlen == 32 #if __riscv_xlen == 32
} else if ((insn & INSN_MASK_C_FLW) == INSN_MATCH_C_FLW) { } else if ((insn & INSN_MASK_C_FLW) == INSN_MATCH_C_FLW) {
fp = 1; fp = 1;
len = 4; len = 4;
insn = RVC_RS2S(insn) << SH_RD; insn = RVC_RS2S(insn) << SH_RD;
} else if ((insn & INSN_MASK_C_FLWSP) == INSN_MATCH_C_FLWSP) { } else if ((insn & INSN_MASK_C_FLWSP) == INSN_MATCH_C_FLWSP) {
fp = 1; fp = 1;
len = 4; len = 4;
# endif
#endif #endif
} else #endif
return SBI_EILL; #endif
} 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; val.data_u64 = 0;
for (i = 0; i < len; i++) for (i = 0; i < len; i++) {
val.data_bytes[i] = load_u8((void *)(addr + i), regs->mepc); 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) if (!fp)
SET_RD(insn, regs, val.data_ulong << shift >> shift); SET_RD(insn, regs, val.data_ulong << shift >> shift);
#ifdef __riscv_flen
else if (len == 8) else if (len == 8)
SET_F64_RD(insn, regs, val.data_u64); SET_F64_RD(insn, regs, val.data_u64);
else else
SET_F32_RD(insn, regs, val.data_ulong); SET_F32_RD(insn, regs, val.data_ulong);
#endif
regs->mepc += INSN_LEN(insn); regs->mepc += INSN_LEN(insn);
@@ -108,15 +144,33 @@ int sbi_misaligned_load_handler(u32 hartid, ulong mcause,
} }
int sbi_misaligned_store_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_trap_regs *regs,
struct sbi_scratch *scratch) struct sbi_scratch *scratch)
{ {
ulong insn;
union reg_data val; union reg_data val;
ulong mstatus = csr_read(CSR_MSTATUS); struct sbi_trap_info uptrap;
ulong insn = get_insn(regs->mepc, &mstatus);
ulong addr = csr_read(CSR_MTVAL);
int i, len = 0; int i, len = 0;
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); val.data_ulong = GET_RS2(insn, regs);
if ((insn & INSN_MASK_SW) == INSN_MATCH_SW) { if ((insn & INSN_MASK_SW) == INSN_MATCH_SW) {
@@ -125,51 +179,67 @@ int sbi_misaligned_store_handler(u32 hartid, ulong mcause,
} else if ((insn & INSN_MASK_SD) == INSN_MATCH_SD) { } else if ((insn & INSN_MASK_SD) == INSN_MATCH_SD) {
len = 8; len = 8;
#endif #endif
#ifdef __riscv_flen
} else if ((insn & INSN_MASK_FSD) == INSN_MATCH_FSD) { } else if ((insn & INSN_MASK_FSD) == INSN_MATCH_FSD) {
len = 8; len = 8;
val.data_u64 = GET_F64_RS2(insn, regs); val.data_u64 = GET_F64_RS2(insn, regs);
} else if ((insn & INSN_MASK_FSW) == INSN_MATCH_FSW) { } else if ((insn & INSN_MASK_FSW) == INSN_MATCH_FSW) {
len = 4; len = 4;
val.data_ulong = GET_F32_RS2(insn, regs); val.data_ulong = GET_F32_RS2(insn, regs);
#endif
} else if ((insn & INSN_MASK_SH) == INSN_MATCH_SH) { } else if ((insn & INSN_MASK_SH) == INSN_MATCH_SH) {
len = 2; len = 2;
#ifdef __riscv_compressed #ifdef __riscv_compressed
# if __riscv_xlen >= 64 #if __riscv_xlen >= 64
} else if ((insn & INSN_MASK_C_SD) == INSN_MATCH_C_SD) { } else if ((insn & INSN_MASK_C_SD) == INSN_MATCH_C_SD) {
len = 8; len = 8;
val.data_ulong = GET_RS2S(insn, regs); val.data_ulong = GET_RS2S(insn, regs);
} else if ((insn & INSN_MASK_C_SDSP) == INSN_MATCH_C_SDSP && } else if ((insn & INSN_MASK_C_SDSP) == INSN_MATCH_C_SDSP &&
((insn >> SH_RD) & 0x1f)) { ((insn >> SH_RD) & 0x1f)) {
len = 8; len = 8;
val.data_ulong = GET_RS2C(insn, regs); val.data_ulong = GET_RS2C(insn, regs);
# endif #endif
} else if ((insn & INSN_MASK_C_SW) == INSN_MATCH_C_SW) { } else if ((insn & INSN_MASK_C_SW) == INSN_MATCH_C_SW) {
len = 4; len = 4;
val.data_ulong = GET_RS2S(insn, regs); val.data_ulong = GET_RS2S(insn, regs);
} else if ((insn & INSN_MASK_C_SWSP) == INSN_MATCH_C_SWSP && } else if ((insn & INSN_MASK_C_SWSP) == INSN_MATCH_C_SWSP &&
((insn >> SH_RD) & 0x1f)) { ((insn >> SH_RD) & 0x1f)) {
len = 4; len = 4;
val.data_ulong = GET_RS2C(insn, regs); val.data_ulong = GET_RS2C(insn, regs);
#ifdef __riscv_flen
} else if ((insn & INSN_MASK_C_FSD) == INSN_MATCH_C_FSD) { } else if ((insn & INSN_MASK_C_FSD) == INSN_MATCH_C_FSD) {
len = 8; len = 8;
val.data_u64 = GET_F64_RS2S(insn, regs); val.data_u64 = GET_F64_RS2S(insn, regs);
} else if ((insn & INSN_MASK_C_FSDSP) == INSN_MATCH_C_FSDSP) { } else if ((insn & INSN_MASK_C_FSDSP) == INSN_MATCH_C_FSDSP) {
len = 8; len = 8;
val.data_u64 = GET_F64_RS2C(insn, regs); val.data_u64 = GET_F64_RS2C(insn, regs);
# if __riscv_xlen == 32 #if __riscv_xlen == 32
} else if ((insn & INSN_MASK_C_FSW) == INSN_MATCH_C_FSW) { } else if ((insn & INSN_MASK_C_FSW) == INSN_MATCH_C_FSW) {
len = 4; len = 4;
val.data_ulong = GET_F32_RS2S(insn, regs); val.data_ulong = GET_F32_RS2S(insn, regs);
} else if ((insn & INSN_MASK_C_FSWSP) == INSN_MATCH_C_FSWSP) { } else if ((insn & INSN_MASK_C_FSWSP) == INSN_MATCH_C_FSWSP) {
len = 4; len = 4;
val.data_ulong = GET_F32_RS2C(insn, regs); val.data_ulong = GET_F32_RS2C(insn, regs);
# endif
#endif #endif
} else #endif
return SBI_EILL; #endif
} 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++) for (i = 0; i < len; i++) {
store_u8((void *)(addr + i), val.data_bytes[i], regs->mepc); 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); regs->mepc += INSN_LEN(insn);

76
lib/sbi/sbi_scratch.c Normal file
View File

@@ -0,0 +1,76 @@
/*
* 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_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
* anything to be free-ed hence it keeps incrementing the
* next allocation offset until it runs-out of space.
*
* In future, we will have more sophisticated allocator which
* will allow us to re-claim free-ed space.
*/
if (!size)
return 0;
if (size & (__SIZEOF_POINTER__ - 1))
size = (size & ~(__SIZEOF_POINTER__ - 1)) + __SIZEOF_POINTER__;
spin_lock(&extra_lock);
if (SBI_SCRATCH_SIZE < (extra_offset + size))
goto done;
ret = extra_offset;
extra_offset += size;
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;
}
void sbi_scratch_free_offset(unsigned long offset)
{
if ((offset < SBI_SCRATCH_EXTRA_SPACE_OFFSET) ||
(SBI_SCRATCH_SIZE <= offset))
return;
/*
* We don't actually free-up because it's a simple
* brain-dead allocator.
*/
}

View File

@@ -12,17 +12,18 @@
* bugs as well. Use any optimized routines from newlib or glibc if required. * bugs as well. Use any optimized routines from newlib or glibc if required.
*/ */
#include <plat/string.h> #include <sbi/sbi_string.h>
int strcmp(const char *a, const char *b) int sbi_strcmp(const char *a, const char *b)
{ {
/* search first diff or end of string */ /* search first diff or end of string */
for (; *a == *b && *a != '\0'; a++, b++); for (; *a == *b && *a != '\0'; a++, b++)
;
return *a - *b; return *a - *b;
} }
size_t strlen(const char *str) size_t sbi_strlen(const char *str)
{ {
unsigned long ret = 0; unsigned long ret = 0;
@@ -34,7 +35,7 @@ size_t strlen(const char *str)
return ret; return ret;
} }
size_t strnlen(const char *str, size_t count) size_t sbi_strnlen(const char *str, size_t count)
{ {
unsigned long ret = 0; unsigned long ret = 0;
@@ -47,31 +48,31 @@ size_t strnlen(const char *str, size_t count)
return ret; return ret;
} }
char *strcpy(char *dest, const char *src) char *sbi_strcpy(char *dest, const char *src)
{ {
char *ret = dest; char *ret = dest;
while(*src != '\0') { while (*src != '\0') {
*dest++ = *src++; *dest++ = *src++;
} }
return ret; return ret;
} }
char *strncpy(char *dest, const char *src, size_t count) char *sbi_strncpy(char *dest, const char *src, size_t count)
{ {
char *ret = dest; char *ret = dest;
while(count-- && *src != '\0') { while (count-- && *src != '\0') {
*dest++ = *src++; *dest++ = *src++;
} }
return ret; return ret;
} }
char *strchr(const char *s, int c) char *sbi_strchr(const char *s, int c)
{ {
while(*s != '\0' && *s != (char)c) while (*s != '\0' && *s != (char)c)
s++; s++;
if (*s == '\0') if (*s == '\0')
@@ -80,9 +81,9 @@ char *strchr(const char *s, int c)
return (char *)s; return (char *)s;
} }
char *strrchr(const char *s, int c) char *sbi_strrchr(const char *s, int c)
{ {
const char *last = s + strlen(s); const char *last = s + sbi_strlen(s);
while (last > s && *last != (char)c) while (last > s && *last != (char)c)
last--; last--;
@@ -92,11 +93,11 @@ char *strrchr(const char *s, int c)
else else
return (char *)last; return (char *)last;
} }
void *memset(void *s, int c, size_t count) void *sbi_memset(void *s, int c, size_t count)
{ {
char *temp = s; char *temp = s;
while(count > 0 ){ while (count > 0) {
count--; count--;
*temp++ = c; *temp++ = c;
} }
@@ -104,9 +105,9 @@ void *memset(void *s, int c, size_t count)
return s; return s;
} }
void *memcpy(void *dest, const void *src, size_t count) void *sbi_memcpy(void *dest, const void *src, size_t count)
{ {
char *temp1 = dest; char *temp1 = dest;
const char *temp2 = src; const char *temp2 = src;
while (count > 0) { while (count > 0) {
@@ -117,16 +118,16 @@ void *memcpy(void *dest, const void *src, size_t count)
return dest; return dest;
} }
void *memmove(void *dest, const void *src, size_t count) void *sbi_memmove(void *dest, const void *src, size_t count)
{ {
char *temp1 = (char *)dest; char *temp1 = (char *)dest;
const char *temp2 = (char *)src; const char *temp2 = (char *)src;
if (src == dest) if (src == dest)
return dest; return dest;
if (dest < src) { if (dest < src) {
while(count > 0) { while (count > 0) {
*temp1++ = *temp2++; *temp1++ = *temp2++;
count--; count--;
} }
@@ -134,7 +135,7 @@ void *memmove(void *dest, const void *src, size_t count)
temp1 = dest + count - 1; temp1 = dest + count - 1;
temp2 = src + count - 1; temp2 = src + count - 1;
while(count > 0) { while (count > 0) {
*temp1-- = *temp2--; *temp1-- = *temp2--;
count--; count--;
} }
@@ -143,7 +144,7 @@ void *memmove(void *dest, const void *src, size_t count)
return dest; return dest;
} }
int memcmp(const void *s1, const void *s2, size_t count) int sbi_memcmp(const void *s1, const void *s2, size_t count)
{ {
const char *temp1 = s1; const char *temp1 = s1;
const char *temp2 = s2; const char *temp2 = s2;
@@ -159,13 +160,13 @@ int memcmp(const void *s1, const void *s2, size_t count)
return 0; return 0;
} }
void *memchr(const void *s, int c, size_t count) void *sbi_memchr(const void *s, int c, size_t count)
{ {
const unsigned char *temp = s; const unsigned char *temp = s;
while (count > 0) { while (count > 0) {
if ((unsigned char)c == *temp++) { if ((unsigned char)c == *temp++) {
return (void *)(temp-1); return (void *)(temp - 1);
} }
count--; count--;
} }

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