195 Commits
v0.1 ... v0.5

Author SHA1 Message Date
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
Anup Patel
ca20ac0cd4 include: Bump-up version to 0.3
This patch updates OpenSBI version to 0.3 as part of
release preparation.

Signed-off-by: Anup Patel <anup.patel@wdc.com>
2019-02-26 22:24:59 +05:30
Alistair Francis
42e9ad556d Makefile: Set the platform variables before parsing the platforms
Ensure the platform variable PLATFORM_RISCV_XLEN is set before we parse
the platform files.

This fixes the 32-bit openSBI FW_JUMP_ADDR.

Signed-off-by: Alistair Francis <alistair.francis@wdc.com>
2019-02-26 19:23:26 +05:30
Anup Patel
a1ffba1ac9 include: Bump-up version to 0.2
This patch increases OpenSBI version to 0.2.

Signed-off-by: Anup Patel <anup.patel@wdc.com>
2019-02-22 11:33:22 +05:30
Anup Patel
d022c5d3ae scripts: Add script for creating binary archive
This patch adds scripts/create-binary-archive.sh which helps
us create a common tarball containing headers, static library
and firmware ELFs for all platforms.

This script can be used for release purpose OR for compile
testing all platforms.

Example usage commands are as follows:

1) Binary release archive for 32bit systems
./scripts/create-binary-archive.sh -s "bin" -x 32 -d

2) Binary release archive for 64bit systems
./scripts/create-binary-archive.sh -s "bin" -d

3) Compile test for 32bit systems
./scripts/create-binary-archive.sh -x 32 -t

4) Compile test for 64bit systems
./scripts/create-binary-archive.sh -t

Signed-off-by: Anup Patel <anup.patel@wdc.com>
2019-02-22 11:28:41 +05:30
Anup Patel
889e746fd7 Makefile: Rename compile_ld() to compile_elf()
The compile_ld() is actually used to create ELF files so
the name is misleading hence this patch renames it to
compile_elf(). We also rename LDFLAGS to ELFFLAGS because
these will be used for ELF creation only.

Signed-off-by: Anup Patel <anup.patel@wdc.com>
2019-02-22 11:28:41 +05:30
Atish Patra
fde1c42db3 doc: Fix root partition details for fu540.
Signed-off-by: Atish Patra <atish.patra@wdc.com>
2019-02-22 09:58:55 +05:30
Anup Patel
122d00ba67 firmware: Improve low-level trap handler for M-mode to M-mode traps
This patch extends our low-level trap handler in fw_base.S for
handling M-mode to M-mode traps without overwritting stack.

Signed-off-by: Anup Patel <anup.patel@wdc.com>
2019-02-20 12:02:40 +05:30
Anup Patel
ce6189f7a5 include: Add PRILX define to help print unsigned long
The unsigned long is always machine word size. This means it is
4 bytes on 32bit system and 8 bytes on 64bit system.

This patch adds PRILX define for sbi_printf() which will help us
print unsigned long without worrying whether it is 32bit or 64bit
system.

Signed-off-by: Anup Patel <anup.patel@wdc.com>
2019-02-20 12:02:40 +05:30
Sergi Granell
db5b25af49 template: Fix some callback names 2019-02-19 18:22:58 +05:30
Sergi Granell
72a8272066 template: Remove trailing ';' 2019-02-19 18:22:58 +05:30
Sergi Granell
4b92518959 template: Fix typo in platform_final_init
There was a space instead of '_' in the function `platform_final_init`.
2019-02-19 18:22:58 +05:30
Atish Patra
d046974cf6 docs: Update unleashed platform guide.
Following updates to fu540 platform guide.

1. Update a section about flashing the firmware binary
to sdcard with correct partition identifier.
2. Refer the individual payload section.
3. Update uboot booting section.

Signed-off-by: Atish Patra <atish.patra@wdc.com>
2019-02-19 18:22:26 +05:30
Atish Patra
0db43770b3 docs: Add a payload section describing different payloads.
Signed-off-by: Atish Patra <atish.patra@wdc.com>
2019-02-19 18:22:26 +05:30
Atish Patra
3265310b05 docs: Wrap text to 80 columns.
Signed-off-by: Atish Patra <atish.patra@wdc.com>
2019-02-19 18:22:26 +05:30
Atish Patra
34bf6d4a0f docs: Update about toolchain section.
Signed-off-by: Atish Patra <atish.patra@wdc.com>
2019-02-19 18:22:26 +05:30
Anup Patel
6a3dc84f66 Makefile: Use sed instead of awk to parse OpenSBI version
This patch replaces use of awk with sed in top-level makefile
to parse OpenSBI version from include/sbi/sbi_version.h.

Signed-off-by: Anup Patel <anup.patel@wdc.com>
2019-02-19 13:47:18 +05:30
Anup Patel
f4a17177ce Makefile: Fix error evaluating OPENSBI_CC_XLEN
We get following error evaluating OPENSBI_CC_XLEN on
Ubuntu-18.04:
/bin/sh: 1: Bad substitution

This patch fixes above error by using "awk" in string
assigned to OPENSBI_CC_XLEN and it also moves "Setup
compilation commands" before OPENSBI_CC_XLEN.

Signed-off-by: Anup Patel <anup.patel@wdc.com>
2019-02-19 13:47:18 +05:30
Anup Patel
4e774f5470 lib: Fix mask shift in sbi_ipi_send_many()
The mask shift in for-loop of sbi_ipi_send_many() is
broken with commit 918c1354b7
("lib: Improve delivery of SBI_IPI_EVENT_HALT")

This patch fix it.

Signed-off-by: Anup Patel <anup.patel@wdc.com>
2019-02-18 18:39:02 +05:30
Nick Kossifidis
148423d141 lib: Fix small typo on sbi_ipi.c 2019-02-18 09:21:58 +05:30
Nick Kossifidis
918c1354b7 lib: Improve delivery of SBI_IPI_EVENT_HALT
When sbi_ipi_send_many gets called with the current hartid
included on pmask (or when pmask is NULL), and we send
a HALT event, since the for loop works sequentially over
all hartids on the mask, we may send a HALT event to the
current hart before the loop finishes. So we will halt
the current hart before it can deliver a HALT IPI to the
rest and some harts will remain active.

Make sure we send an IPI to the current hart after we've
finished with everybody else.

Signed-off-by: Nick Kossifidis <mick@ics.forth.gr>
2019-02-18 09:21:58 +05:30
Nick Kossifidis
51e543511a platform: qemu-virt: Implement system shutdown
In order for QEMU to be compatible with Spike, it implements
a simple protocol used for reporting back the simulation's
status, through the memory-mapped "test finisher" device. We
use that protocol to make QEMU exit on system shutdown.

Signed-off-by: Nick Kossifidis <mick@ics.forth.gr>
2019-02-18 09:21:58 +05:30
Nick Kossifidis
b44878b773 lib: Send IPI for all harts to hang on system shutdown
In case the platform specific method for shutting down
the system fails (or is not implemented), at least make
sure that all harts hang instead of just the current hart.

Signed-off-by: Nick Kossifidis <mick@ics.forth.gr>
2019-02-18 09:21:58 +05:30
Alistair Francis
16426420b5 Makefile: Fix the assignment of OPENSBI_CC_XLEN
Previously OPENSBI_CC_XLEN was not being correctly assigned either 32 or
64. It also was not assigned before config.mk was parsed. Ensure that it
will always be assigned.

Signed-off-by: Alistair Francis <alistair.francis@wdc.com>
2019-02-17 16:21:18 +05:30
Alistair Francis
3c53950b00 Merge pull request #59 from avpatel/make-run
Add 'make run' command for platform specific run
2019-02-15 15:02:19 -08:00
Olof Johansson
868e20df8b Makefile: Add 'make run' command for platform specific run
Makes for easy and quick build-run one-stop command.

For now only added for qemu targets. It can be added for
any platform having simulator/emulator (such as QEMU).

Signed-off-by: Olof Johansson <olof@lixom.net>
Signed-off-by: Anup Patel <anup.patel@wdc.com>
2019-02-15 15:54:44 +05:30
Alistair Francis
5cd69a496b docs: fu540: Add steps for the Microsemi Expansion board
Signed-off-by: Alistair Francis <alistair.francis@wdc.com>
2019-02-15 09:56:47 +05:30
Alistair Francis
ae4e0de700 platform: fu540: Initial commit of Microsemi device tree
Add a device tree for th HiFive Unleashed that includes the Microsemi
PCIe root complex.

Once we have support for u-boot and in tree Linux kernel device trees
this device tree should be removed.

Signed-off-by: Alistair Francis <alistair.francis@wdc.com>
2019-02-15 09:56:47 +05:30
Alistair Francis
afbb0cdf80 platform: fu540: Fix missing newline
Signed-off-by: Alistair Francis <alistair.francis@wdc.com>
2019-02-15 09:56:47 +05:30
Alistair Francis
d369e721e8 firmware: Ensure the payloads are 4 bit alligned
We expect the payloads to be 4 bit alligned as we later AND them
with ~0xf. As most of the addresses are manually specified we don't
really need this, but better to be over cautious.

Signed-off-by: Alistair Francis <alistair.francis@wdc.com>
2019-02-15 09:56:47 +05:30
Nick Kossifidis
286b80768b Makefile: Make sure ld is always aware of the target abi/emulation
On Makefile merge_objs calls ld without providing any hints
on the target so on a multilib toolchain for example it will
always pick the default one (elf64-littleriscv) which will
then result a failure when compiling on RV32 since the objects
will be 32bits and the target will be 64bits. The same happens
on compile_ld that calls gcc without CFLAGS so it doesn't
get mabi/march.

With this patch OpenSBI compiles on RV32 (PLATFORM_RISCV_XLEN=32),
I tested fw_jump.elf on qemu (but it doesn't boot the kernel yet
-bbl also doesn't boot the kernel so it may be something else).

Signed-off-by: Nick Kossifidis <mickflemm@gmail.com>
2019-02-15 08:55:45 +05:30
Atish Patra
35e617385f firmware: Use CSR_<FOO> instead of <foo> for csr*
Some older toolchains may not have all the csr's defined. Update all
the csr functions to use the CSR_ #define values instead of the
toolchain defined values.

Signed-off-by: Atish Patra <atish.patra@wdc.com>
2019-02-14 09:31:18 +05:30
Atish Patra
28d1dd2430 platform: Use CSR_<FOO> instead of <foo> for csr_*()
Some older toolchains may not have all the csr's defined. Update all
the csr functions to use the CSR_ #define values instead of the
toolchain defined values.

Suggested-by: Olof Johansson <olof@lixom.net>
Signed-off-by: Atish Patra <atish.patra@wdc.com>
2019-02-14 09:31:18 +05:30
Atish Patra
70a474d2c2 lib: Use CSR_<FOO> instead of <foo> for csr_*()
Some older toolchains may not have all the csr's defined. Update all
the csr functions to use the CSR_ #define values instead of the
toolchain defined values.

Suggested-by: Olof Johansson <olof@lixom.net>
Signed-off-by: Atish Patra <atish.patra@wdc.com>
2019-02-14 09:31:18 +05:30
Atish Patra
4cb4d46875 docs: Use normal hyphen instead of non-breaking hyphen
Usage non-breaking hyphen breaks make docs as doxygen doesn't know
how to handle this.

Signed-off-by: Atish Patra <atish.patra@wdc.com>
2019-02-14 09:29:56 +05:30
Anup Patel
c5467fce46 Makefile: Set ABI, ISA and Code Model in top-level make
This patch introduces following optional PLATFORM options:
PLATFORM_RISCV_XLEN -> RISC-V register width
PLATFORM_RISCV_ABI -> RISC-V GCC ABI
PLATFORM_RISCV_ISA -> RISC-V GCC ISA string
PLATFORM_RISCV_CODE_MODEL -> RISC-V GCC Code Model

If the above options are not provided by platform config.mk
or by command-line parameters then:
1. PLATFORM_RISCV_XLEN will be determined using toolchain
capability
2. PLATFORM_RISCV_ABI, PLATFORM_RISCV_ISA, and
PLATFORM_RISCV_CODE_MODEL is set to value best suited for
generic libsbi.a

As a result of these optional PLATFORM options, the
platform-cflags-y and platform-asflags-y is further
simplified for platform config.mk.

Signed-off-by: Anup Patel <anup.patel@wdc.com>
2019-02-12 15:55:15 +05:30
Anup Patel
84169e2e69 platform: qemu: Set FW_JUMP_ADDR and FW_PAYLOAD_OFFSET as-per XLEN
The current 4MB aligned FW_JUMP_ADDR and FW_PAYLOAD_OFFSET breaks
U-Boot on QEMU virt and sifive_u machines.

Instead of using 4MB aligned for both 32bit and 64bit systems, we
use different values based compiler XLEN. Another advantage of this
approach will be that our fw_payload.bin will smaller for 64bit
systems.

Signed-off-by: Anup Patel <anup.patel@wdc.com>
2019-02-12 15:55:15 +05:30
Anup Patel
ab12d6ef8f platform: template: Improve comments for FW_JUMP_ADDR and FW_PAYLOAD_OFFSET
Both FW_JUMP_ADDR and FW_PAYLOAD_OFFSET, should be:
1. 4MB aligned for 32bit system
2. 2MB aligned for 64bit system

Explicitly specify the above details in config.mk comments
for template platform.

Signed-off-by: Anup Patel <anup.patel@wdc.com>
2019-02-12 15:55:15 +05:30
Damien Le Moal
01fe779113 docs: improve library usage document
Clarify the libraries descriptions.

Signed-off-by: Damien Le Moal <damien.lemoal@wdc.com>
2019-02-08 09:36:06 +05:30
Damien Le Moal
b1b7e49c63 docs: platform guide updates
Clarify platform support description.
Also fix some Typos, grammar and document style.

Signed-off-by: Damien Le Moal <damien.lemoal@wdc.com>
2019-02-08 09:36:06 +05:30
Damien Le Moal
7b3da0ef0d top: README.md updates
Clarify OpenSBI components explanation.

Signed-off-by: Damien Le Moal <damien.lemoal@wdc.com>
2019-02-08 09:36:06 +05:30
Alistair Francis
76c759df6a Makefile: Ensure lgcc is included
This fixes errors like this:
  undefined reference to `__umoddi3'
when buildilng for 32-bit systems

Signed-off-by: Alistair Francis <alistair.francis@wdc.com>
2019-02-08 09:18:46 +05:30
Alistair Francis
4f32b13802 firmware: Use lw instead of lwu for 32-bit architectures
Signed-off-by: Alistair Francis <alistair.francis@wdc.com>
2019-02-08 09:18:46 +05:30
Alistair Francis
f9b033e577 platform: clint: Allow running on 32-bit systems
Signed-off-by: Alistair Francis <alistair.francis@wdc.com>
2019-02-08 09:18:46 +05:30
Alistair Francis
f4cf6da7ff sbi_emulate_csr: Shift sbi_timer_value directly
csr_val is a tartget length based variable, so on 32-bit devices it's
only 32-bits. To avoid clearing the entire register perform both steps
in a single line.

Signed-off-by: Alistair Francis <alistair.francis@wdc.com>
2019-02-08 09:18:46 +05:30
Alistair Francis
9f44d07df5 platform: qemu/virt: Move kernel start address to 4MB alligned
In order to support 32-bit guests move the start address to a 4MB
allignment. As 64-bit kernels have a requirement on being 2MB alligned
let's just make this the default for both 32 and 64 bit kernels.

Signed-off-by: Alistair Francis <alistair.francis@wdc.com>
2019-02-08 09:18:46 +05:30
Alistair Francis
a5f06b30c1 platform: template: Move kernel start address to 4MB alligned
In order to support 32-bit guests move the start address to a 4MB
allignment. As 64-bit kernels have a requirement on being 2MB alligned
let's just make this the default for both 32 and 64 bit kernels.

Signed-off-by: Alistair Francis <alistair.francis@wdc.com>
2019-02-08 09:18:46 +05:30
Alistair Francis
5a91fec1a8 platform/qemu/virt: Dynamically calculate xlen
The QEMU virt machine can be either 32 or 66 bit. Don't hard code the
CPU bit length and instead let the compiler determine it.

Signed-off-by: Alistair Francis <alistair.francis@wdc.com>
2019-02-08 09:18:46 +05:30
Alistair Francis
b4c72deba9 sbi_ecall: Fix logical OR to be bitwise OR
Signed-off-by: Alistair Francis <alistair.francis@wdc.com>
2019-02-08 09:18:46 +05:30
Andreas Schwab
93f806af32 firwmare: don't expand macros in FW_PAYLOAD_PATH
Signed-off-by: Andreas Schwab <schwab@suse.de>
2019-02-06 10:39:17 +05:30
Andreas Schwab
190a80dc40 Makefile: don't disable built-in variables
Signed-off-by: Andreas Schwab <schwab@suse.de>
2019-02-06 10:39:17 +05:30
Olof Johansson
9a72e5006c Makefile: Don't rely on "echo -n"
Turns out it doesn't behave as expected on MacOS, it doesn't honor
-n and echoes that to the file instead. Add a slash and just let
the newline be there instead.

Signed-off-by: Olof Johansson <olof@lixom.net>
2019-02-05 18:53:27 +05:30
Olof Johansson
c0addfe751 riscv_asm.h: Use CSR_<FOO> instead of <foo> for csr_read()
Some toolchains might not have all the CSRs available (as seen with
GCC 7.2). So, instead use the defined CSR_ values.

Signed-off-by: Olof Johansson <olof@lixom.net>
2019-02-05 18:53:09 +05:30
158 changed files with 6575 additions and 4174 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/
# 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
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
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
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

238
Makefile
View File

@@ -8,9 +8,9 @@
#
# Select Make Options:
# o Do not use make's built-in rules and variables
# o Do not use make's built-in rules
# o Do not print "Entering directory ...";
MAKEFLAGS += -rR --no-print-directory
MAKEFLAGS += -r --no-print-directory
# Find out source, build, and install directories
src_dir=$(CURDIR)
@@ -33,6 +33,17 @@ endif
ifeq ($(install_dir),$(build_dir))
$(error Install directory is same as build directory.)
endif
ifdef PLATFORM_DIR
platform_dir_path=$(shell readlink -f $(PLATFORM_DIR))
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
CMD_PREFIX_DEFAULT := @
@@ -43,61 +54,18 @@ else
endif
# Setup path of directories
export platform_subdir=platform/$(PLATFORM)
export platform_dir=$(CURDIR)/$(platform_subdir)
export platform_common_dir=$(CURDIR)/platform/common
export platform_subdir=$(PLATFORM)
export platform_src_dir=$(platform_parent_dir)/$(platform_subdir)
export platform_build_dir=$(build_dir)/platform/$(platform_subdir)
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
# Find library version
OPENSBI_VERSION_MAJOR=`grep MAJOR $(include_dir)/sbi/sbi_version.h | awk '{ print $$3 }'`
OPENSBI_VERSION_MINOR=`grep MINOR $(include_dir)/sbi/sbi_version.h | awk '{ print $$3 }'`
# Setup list of objects.mk files
ifdef PLATFORM
platform-object-mks=$(shell if [ -d $(platform_dir) ]; then find $(platform_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
lib-object-mks=$(shell if [ -d $(lib_dir) ]; then find $(lib_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
ifdef PLATFORM
include $(platform_dir)/config.mk
endif
# Include all object.mk files
ifdef PLATFORM
include $(platform-object-mks)
include $(platform-common-object-mks)
endif
include $(lib-object-mks)
include $(firmware-object-mks)
# Setup list of objects
lib-objs-path-y=$(foreach obj,$(lib-objs-y),$(build_dir)/lib/$(obj))
ifdef PLATFORM
platform-objs-path-y=$(foreach obj,$(platform-objs-y),$(build_dir)/$(platform_subdir)/$(obj))
platform-dtb-path-y=$(foreach obj,$(platform-dtb-y),$(build_dir)/$(platform_subdir)/$(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),$(build_dir)/$(platform_subdir)/firmware/$(bin))
endif
firmware-elfs-path-y=$(firmware-bins-path-y:.bin=.elf)
firmware-objs-path-y=$(firmware-bins-path-y:.bin=.o)
# Setup list of deps files for objects
deps-y=$(platform-objs-path-y:.o=.dep)
deps-y+=$(platform-common-objs-path-y:.o=.dep)
deps-y+=$(lib-objs-path-y:.o=.dep)
deps-y+=$(firmware-objs-path-y:.o=.dep)
GENFLAGS = -I$(platform_dir)/include
GENFLAGS += -I$(platform_common_dir)/include
GENFLAGS += -I$(include_dir)
GENFLAGS += $(platform-common-genflags-y)
GENFLAGS += $(platform-genflags-y)
GENFLAGS += $(firmware-genflags-y)
OPENSBI_VERSION_MAJOR=`grep "define OPENSBI_VERSION_MAJOR" $(include_dir)/sbi/sbi_version.h | sed 's/.*MAJOR.*\([0-9][0-9]*\)/\1/'`
OPENSBI_VERSION_MINOR=`grep "define OPENSBI_VERSION_MINOR" $(include_dir)/sbi/sbi_version.h | sed 's/.*MINOR.*\([0-9][0-9]*\)/\1/'`
OPENSBI_VERSION_GIT=$(shell if [ -d $(src_dir)/.git ]; then git describe 2> /dev/null; fi)
# Setup compilation commands
ifdef CROSS_COMPILE
@@ -116,13 +84,90 @@ endif
AS = $(CC)
DTC = dtc
# Guess the compillers xlen
OPENSBI_CC_XLEN := $(shell TMP=`$(CC) -dumpmachine | sed 's/riscv\([0-9][0-9]\).*/\1/'`; echo $${TMP})
# Setup platform XLEN
ifndef PLATFORM_RISCV_XLEN
ifeq ($(OPENSBI_CC_XLEN), 32)
PLATFORM_RISCV_XLEN = 32
else
PLATFORM_RISCV_XLEN = 64
endif
endif
# Setup list of objects.mk files
ifdef PLATFORM
platform-object-mks=$(shell if [ -d $(platform_src_dir)/ ]; then find $(platform_src_dir) -iname "objects.mk" | sort -r; fi)
endif
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)
# Include platform specifig config.mk
ifdef PLATFORM
include $(platform_src_dir)/config.mk
endif
# Include all object.mk files
ifdef PLATFORM
include $(platform-object-mks)
endif
include $(libsbi-object-mks)
include $(libsbiutils-object-mks)
include $(firmware-object-mks)
# Setup list of objects
libsbi-objs-path-y=$(foreach obj,$(libsbi-objs-y),$(build_dir)/lib/sbi/$(obj))
libsbiutils-objs-path-y=$(foreach obj,$(libsbiutils-objs-y),$(build_dir)/lib/utils/$(obj))
ifdef PLATFORM
platform-objs-path-y=$(foreach obj,$(platform-objs-y),$(platform_build_dir)/$(obj))
platform-dtb-path-y=$(foreach obj,$(platform-dtb-y),$(platform_build_dir)/$(obj))
firmware-bins-path-y=$(foreach bin,$(firmware-bins-y),$(platform_build_dir)/firmware/$(bin))
endif
firmware-elfs-path-y=$(firmware-bins-path-y:.bin=.elf)
firmware-objs-path-y=$(firmware-bins-path-y:.bin=.o)
# Setup list of deps files for objects
deps-y=$(platform-objs-path-y:.o=.dep)
deps-y+=$(libsbi-objs-path-y:.o=.dep)
deps-y+=$(libsbiutils-objs-path-y:.o=.dep)
deps-y+=$(firmware-objs-path-y:.o=.dep)
# Setup platform ABI, ISA and Code Model
ifndef PLATFORM_RISCV_ABI
ifeq ($(PLATFORM_RISCV_XLEN), 32)
PLATFORM_RISCV_ABI = ilp$(PLATFORM_RISCV_XLEN)
else
PLATFORM_RISCV_ABI = lp$(PLATFORM_RISCV_XLEN)
endif
endif
ifndef PLATFORM_RISCV_ISA
PLATFORM_RISCV_ISA = rv$(PLATFORM_RISCV_XLEN)imafdc
endif
ifndef PLATFORM_RISCV_CODE_MODEL
PLATFORM_RISCV_CODE_MODEL = medany
endif
# Setup compilation commands flags
GENFLAGS = -I$(platform_src_dir)/include
GENFLAGS += -I$(include_dir)
ifneq ($(OPENSBI_VERSION_GIT),)
GENFLAGS += -DOPENSBI_VERSION_GIT="\"$(OPENSBI_VERSION_GIT)\""
endif
GENFLAGS += $(libsbiutils-genflags-y)
GENFLAGS += $(platform-genflags-y)
GENFLAGS += $(firmware-genflags-y)
CFLAGS = -g -Wall -Werror -nostdlib -fno-strict-aliasing -O2
CFLAGS += -fno-omit-frame-pointer -fno-optimize-sibling-calls
CFLAGS += -mno-save-restore -mstrict-align
CFLAGS += -mabi=$(PLATFORM_RISCV_ABI) -march=$(PLATFORM_RISCV_ISA)
CFLAGS += -mcmodel=$(PLATFORM_RISCV_CODE_MODEL)
CFLAGS += $(GENFLAGS)
CFLAGS += $(platform-cflags-y)
CFLAGS += $(firmware-cflags-y)
CFLAGS += -fno-pie -no-pie
CPPFLAGS += $(GENFLAGS)
CPPFLAGS += $(platform-cppflags-y)
@@ -131,17 +176,21 @@ CPPFLAGS += $(firmware-cppflags-y)
ASFLAGS = -g -Wall -nostdlib -D__ASSEMBLY__
ASFLAGS += -fno-omit-frame-pointer -fno-optimize-sibling-calls
ASFLAGS += -mno-save-restore -mstrict-align
ASFLAGS += -mabi=$(PLATFORM_RISCV_ABI) -march=$(PLATFORM_RISCV_ISA)
ASFLAGS += -mcmodel=$(PLATFORM_RISCV_CODE_MODEL)
ASFLAGS += $(GENFLAGS)
ASFLAGS += $(platform-asflags-y)
ASFLAGS += $(firmware-asflags-y)
ARFLAGS = rcs
LDFLAGS += -g -Wall -nostdlib -Wl,--build-id=none -N
LDFLAGS += $(platform-ldflags-y)
LDFLAGS += $(firmware-ldflags-y)
ELFFLAGS += -Wl,--build-id=none -N -static-libgcc -lgcc
ELFFLAGS += $(platform-ldflags-y)
ELFFLAGS += $(firmware-ldflags-y)
MERGEFLAGS += -r
MERGEFLAGS += -b elf$(PLATFORM_RISCV_XLEN)-littleriscv
MERGEFLAGS += -m elf$(PLATFORM_RISCV_XLEN)lriscv
DTCFLAGS = -O dtb
@@ -180,7 +229,7 @@ compile_cpp = $(CMD_PREFIX)mkdir -p `dirname $(1)`; \
$(CPP) $(CPPFLAGS) -x c $(2) | grep -v "\#" > $(1)
compile_cc_dep = $(CMD_PREFIX)mkdir -p `dirname $(1)`; \
echo " CC-DEP $(subst $(build_dir)/,,$(1))"; \
echo -n `dirname $(1)`/ > $(1) && \
printf %s `dirname $(1)`/ > $(1) && \
$(CC) $(CFLAGS) $(call dynamic_flags,$(1),$(2)) \
-MM $(2) >> $(1) || rm -f $(1)
compile_cc = $(CMD_PREFIX)mkdir -p `dirname $(1)`; \
@@ -188,15 +237,15 @@ compile_cc = $(CMD_PREFIX)mkdir -p `dirname $(1)`; \
$(CC) $(CFLAGS) $(call dynamic_flags,$(1),$(2)) -c $(2) -o $(1)
compile_as_dep = $(CMD_PREFIX)mkdir -p `dirname $(1)`; \
echo " AS-DEP $(subst $(build_dir)/,,$(1))"; \
echo -n `dirname $(1)`/ > $(1) && \
printf %s `dirname $(1)`/ > $(1) && \
$(AS) $(ASFLAGS) $(call dynamic_flags,$(1),$(2)) \
-MM $(2) >> $(1) || rm -f $(1)
compile_as = $(CMD_PREFIX)mkdir -p `dirname $(1)`; \
echo " AS $(subst $(build_dir)/,,$(1))"; \
$(AS) $(ASFLAGS) $(call dynamic_flags,$(1),$(2)) -c $(2) -o $(1)
compile_ld = $(CMD_PREFIX)mkdir -p `dirname $(1)`; \
echo " LD $(subst $(build_dir)/,,$(1))"; \
$(CC) $(3) $(LDFLAGS) -Wl,-T$(2) -o $(1)
compile_elf = $(CMD_PREFIX)mkdir -p `dirname $(1)`; \
echo " ELF $(subst $(build_dir)/,,$(1))"; \
$(CC) $(CFLAGS) $(3) $(ELFFLAGS) -Wl,-T$(2) -o $(1)
compile_ar = $(CMD_PREFIX)mkdir -p `dirname $(1)`; \
echo " AR $(subst $(build_dir)/,,$(1))"; \
$(AR) $(ARFLAGS) $(1) $(2)
@@ -208,8 +257,9 @@ compile_dts = $(CMD_PREFIX)mkdir -p `dirname $(1)`; \
$(DTC) $(DTCFLAGS) -o $(1) $(2)
targets-y = $(build_dir)/lib/libsbi.a
targets-y += $(build_dir)/lib/libsbiutils.a
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)
endif
targets-y += $(firmware-bins-path-y)
@@ -224,16 +274,19 @@ all: $(targets-y)
$(build_dir)/%.bin: $(build_dir)/%.elf
$(call compile_objcopy,$@,$<)
$(build_dir)/%.elf: $(build_dir)/%.o $(build_dir)/%.elf.ld $(build_dir)/$(platform_subdir)/lib/libplatsbi.a
$(call compile_ld,$@,$@.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,$< $(platform_build_dir)/lib/libplatsbi.a)
$(build_dir)/$(platform_subdir)/%.ld: $(src_dir)/%.ldS
$(platform_build_dir)/%.ld: $(src_dir)/%.ldS
$(call compile_cpp,$@,$<)
$(build_dir)/lib/libsbi.a: $(lib-objs-path-y)
$(build_dir)/lib/libsbi.a: $(libsbi-objs-path-y)
$(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,$@,$^)
$(build_dir)/%.dep: $(src_dir)/%.c
@@ -248,16 +301,28 @@ $(build_dir)/%.dep: $(src_dir)/%.S
$(build_dir)/%.o: $(src_dir)/%.S
$(call compile_as,$@,$<)
$(build_dir)/$(platform_subdir)/%.dep: $(src_dir)/%.c
$(platform_build_dir)/%.dep: $(platform_src_dir)/%.c
$(call compile_cc_dep,$@,$<)
$(build_dir)/$(platform_subdir)/%.o: $(src_dir)/%.c
$(platform_build_dir)/%.o: $(platform_src_dir)/%.c
$(call compile_cc,$@,$<)
$(build_dir)/$(platform_subdir)/%.dep: $(src_dir)/%.S
$(platform_build_dir)/%.dep: $(platform_src_dir)/%.S
$(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,$@,$<)
$(build_dir)/%.dtb: $(src_dir)/%.dts
@@ -285,7 +350,23 @@ all-deps-2 = $(if $(findstring clean,$(MAKECMDGOALS)),,$(all-deps-1))
# Include external dependency of firmwares after default Makefile rules
include $(src_dir)/firmware/external_deps.mk
# Convenient "make run" command for emulated platforms
.PHONY: run
run: all
ifneq ($(platform-runcmd),)
$(platform-runcmd) $(RUN_ARGS)
else
ifdef PLATFORM
@echo "Platform $(PLATFORM) doesn't specify a run command"
@false
else
@echo Run command only available when targeting a platform
@false
endif
endif
install_targets-y = install_libsbi
install_targets-y += install_libsbiutils
ifdef PLATFORM
install_targets-y += install_libplatsbi
install_targets-y += install_firmwares
@@ -300,14 +381,19 @@ install_libsbi: $(build_dir)/lib/libsbi.a
$(call inst_header_dir,$(install_dir)/include,$(include_dir)/sbi)
$(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
install_libplatsbi: $(build_dir)/$(platform_subdir)/lib/libplatsbi.a $(build_dir)/lib/libsbi.a
$(call inst_file,$(install_dir)/$(platform_subdir)/lib/libplatsbi.a,$(build_dir)/$(platform_subdir)/lib/libplatsbi.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/$(platform_subdir)/lib/libplatsbi.a,$(platform_build_dir)/lib/libplatsbi.a)
.PHONY: install_firmwares
install_firmwares: $(build_dir)/$(platform_subdir)/lib/libplatsbi.a $(build_dir)/lib/libsbi.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_subdir)/firmware,$(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/$(platform_subdir)/firmware,$(firmware-elfs-path-y))
$(call inst_file_list,$(install_dir),$(build_dir),platform/$(platform_subdir)/firmware,$(firmware-bins-path-y))
.PHONY: install_docs
install_docs: $(build_dir)/docs/latex/refman.pdf

161
README.md
View File

@@ -1,45 +1,73 @@
Copyright (c) 2019 Western Digital Corporation or its affiliates
and other contributors.
RISC-V Open Source Supervisor Binary Interface (OpenSBI)
========================================================
The **RISC-V Supervisor Binary Interface (SBI)** is a recommended interface
The **RISC-V Supervisor Binary Interface (SBI)** is the recommended interface
between:
1. A platform specific firmware running in M-mode and a general purpose OS,
hypervisor or bootloader running in S-mode or HS-mode.
2. A hypervisor running in HS-mode and a general purpose OS or bootloader
executed in VS-mode.
1. A platform-specific firmware running in M-mode and a bootloader, a
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
executing in VS-mode.
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).
OpenSBI aims to provides an open-source and extensible implementation of the
RISC-V SBI specification for case 1 mentioned above. OpenSBI implementation
can be easily extended by RISC-V platform or System-on-Chip vendors to fit a
The goal of the OpenSBI project is to provide an open-source reference
implementation of the RISC-V SBI specifications for platform-specific firmwares
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
particular hardware configuration.
OpenSBI provides three different components:
1. *libsbi.a* - A generic OpenSBI static library
2. *libplatsbi.a* - A platform specific OpenSBI static library, that is,
libsbi.a plus platform specific hooks
3. *firmwares* - Platform specific bootable firmware binaries
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
bootloader implementation can link against this library to ensure conformance
with the SBI interface specifications. *libsbi.a* also defines an interface for
integrating with platform-specific operations provided by the platform firmware
implementation (e.g. console access functions, inter-processor interrupt
control, etc).
Building and Installing the generic OpenSBI static library
----------------------------------------------------------
To illustrate the use of the *libsbi.a* library, OpenSBI also provides a set of
platform-specific support examples. For each example, a platform-specific
static library *libplatsbi.a* can be compiled. This library implements
SBI call processing by integrating *libsbi.a* with the necessary
platform-dependent hardware manipulation functions. For all supported platforms,
OpenSBI also provides several runtime firmware examples built using the platform
*libplatsbi.a*. These example firmwares can be used to replace the legacy
*riscv-pk* bootloader (aka BBL) and enable the use of well-known bootloaders
such as [U-Boot] (https://git.denx.de/u-boot.git).
*libsbi.a* can be natively compiled or cross-compiled on a host with a
different base architecture than RISC-V.
Required Toolchain
------------------
OpenSBI can be compiled natively or cross-compiled on a x86 host. For
cross-compilation, you can build your own toolchain or just download
a prebuilt one from the
[Bootlin toolchain repository] (https://toolchains.bootlin.com/).
Please note that only a 64-bit version of the toolchain is available in
the Bootlin toolchain repository for now.
Building and Installing the OpenSBI Platform-Independent Library
----------------------------------------------------------------
The OpenSBI platform-independent static library *libsbi.a* can be compiled
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
to specify the name prefix of the RISC-V compiler toolchain executables, e.g.
*riscv64-unknown-elf-* if the gcc executable used is *riscv64-unknown-elf-gcc*.
To build the generic OpenSBI library *libsbi.a*, simply execute:
To build *libsbi.a* simply execute:
```
make
```
All compiled binaries as well as the result *libsbi.a* static library file will
be placed in the *build/lib* directory. To specify an alternate build root
All compiled binaries as well as the resulting *libsbi.a* static library file
will be placed in the *build/lib* directory. To specify an alternate build root
directory path, run:
```
make O=<build_directory>
@@ -51,38 +79,38 @@ make install
```
This will create the *install* directory with all necessary include files
copied under the *install/include* directory and library file copied in the
*install/lib* directory. To specify an alternate installation root directory
path, run:
copied under the *install/include* directory and the library file copied into
the *install/lib* directory. To specify an alternate installation root
directory path, run:
```
make I=<install_directory> install
```
Building and Installing the platform specific static library and firmwares
--------------------------------------------------------------------------
Building and Installing a Reference Platform Static Library and Firmware
------------------------------------------------------------------------
The platform specific *libplatsbi.a* static library and the platform firmwares
are only built if the *PLATFORM=<platform_subdir>* argument is specified on
the make command line. *<platform_subdir>* must specify the relative path from
OpenSBI code directory to one of the leaf directories under the *platform*
directory. For example, to compile the platform library and firmwares for QEMU
RISC-V *virt* machine, *<platform_subdir>* should be *qemu/virt*.
When the *PLATFORM=<platform_subdir>* argument is specified on the make command
line, the platform-specific static library *libplatsbi.a* and firmware examples
are built for the platform *<platform_subdir>* present in the directory
*platform* in the OpenSBI top directory. For example, to compile the platform
library and the firmware examples for the QEMU RISC-V *virt* machine,
*<platform_subdir>* should be *qemu/virt*.
To build *libsbi.a*, *libplatsbi.a* and the firmwares for a specific platform,
run:
To build *libsbi.a*, *libplatsbi.a* and the firmware for one of the supported
platforms, run:
```
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>
```
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
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.
To install *libsbi.a*, *libplatsbi.a*, and the compiled firmwares, run:
@@ -90,19 +118,38 @@ To install *libsbi.a*, *libplatsbi.a*, and the compiled firmwares, run:
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
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
```
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
*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/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
-------
@@ -112,7 +159,7 @@ A copy of this license with OpenSBI copyright can be found in the file
[COPYING.BSD].
All source files in OpenSBI contain the 2-Clause BSD license SPDX short
indentifier in place of the full license text.
identifier in place of the full license text.
```
SPDX-License-Identifier: BSD-2-Clause
@@ -125,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
files where the reused code is present.
1. 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. Any contributions to this
code must be made under the terms of both licenses.
* 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. Any contributions to this
code must be made under the terms of both licenses.
See also the [third party notices] file for more information.
Contributing to OpenSBI
-----------------------
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.
The [Contributors List] document provides a list of individuals and
organizations actively contributing to the OpenSBI project.
Documentation
-------------
@@ -144,14 +196,14 @@ Detailed documentation of various aspects of OpenSBI can be found under the
*docs* directory. The documentation covers the following topics.
* [Contribution Guideline]: Guideline for contributing code to OpenSBI project
* [Platform Support Guide]: Guideline for implementing support for new platforms
* [Library Usage]: API documentation of OpenSBI static library *libsbi.a*
* [Platform Support Guide]: Guideline for implementing support for new platforms
* [Platform Documentation]: Documentation of the platforms currently supported.
* [Firmware Documentation]: Documentation for the different types of firmware
build supported by OpenSBI.
examples build supported by OpenSBI.
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.
Doxygen can be installed on Linux distributions using *.deb* packages using
@@ -191,12 +243,15 @@ make I=<install_directory> install_docs
*refman.pdf* will be installed under *<install_directory>/docs*.
[Github]: https://github.com/riscv/riscv-sbi-doc
[U-Boot]: https://www.denx.de/wiki/U-Boot/SourceCode
[COPYING.BSD]: COPYING.BSD
[SPDX]: http://spdx.org/licenses/
[Contribution Guideline]: docs/contributing.md
[Platform Support Guide]: docs/platform_guide.md
[Contributors List]: CONTRIBUTORS.md
[Library Usage]: docs/library_usage.md
[Platform Support Guide]: docs/platform_guide.md
[Platform Documentation]: docs/platform/platform.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

19
ThirdPartyNotices.md Normal file
View File

@@ -0,0 +1,19 @@
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
==============================
All contributions to OpenSBI should be sent as GitHub Pull Requests (PRs) to
[OpenSBI main repository].
All contributions to OpenSBI can be sent in the following ways:
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:
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
contributions. This means that you must agree to the following prior to
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
Signed-off-by tag must follow this description.
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
requests to avoid creating unnecessary merge commits.
6. Maintainers should avoid creating branches directly in the main
riscv/opensbi repository. Instead prefer using a fork of riscv/opensbi main
riscv/opensbi repository. Instead prefer using a fork of the riscv/opensbi main
repository and branches within that fork to create pull requests.
7. A maintainer cannot merge his own pull requests in riscv/opensbi main
7. A maintainer cannot merge his own pull requests in the riscv/opensbi main
repository.
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
@@ -69,6 +79,6 @@ By making a contribution to this project, I certify that:
-----------------------------------------------------------------------
[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
[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
# 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
# in the documentation. The maximum height of the logo should not exceed 55

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

@@ -0,0 +1,24 @@
OpenSBI as coreboot payload
==============================
[coreboot](https://www.coreboot.org/) is a free/libre and open source firmware platform support multiple hardware architectures( x86, ARMv7, arm64, PowerPC64, MIPS and RISC-V) and diverse hardware models. In RISC-V world, coreboot currently support HiFive Unleashed with OpenSBI as a payload to boot GNU/Linux:
```
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](https://github.com/hardenedlinux/embedded-iot_profile/blob/master/docs/riscv/hifiveunleashed_coreboot_notes-en.md) about how to build [out-of-tree code](https://github.com/hardenedlinux/coreboot-HiFiveUnleashed) to load OpenSBI.

View File

@@ -5,16 +5,26 @@ OpenSBI provides firmware builds for specific platforms. Different types of
firmwares are supported to deal with the differences between different platforms
early boot stage. All firmwares will execute the same initialization procedure
of the platform hardware according to the platform specific code as well as
OpenSBI generic library code. The supported firmwares types will differ in how
OpenSBI generic library code. The supported firmwares type will differ in how
the arguments passed by the platform early boot stage are handled, as well as
how the boot stage following the firmware will be handled and executed.
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*)
--------------------------------------
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
binary code for this next stage.
@@ -48,13 +58,48 @@ configuration parameter.
loads OpenSBI firmware.
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.
* *[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
details in the file *fw_jump.md*.
* *[FW_PAYLOAD]*: The *Firmware with Payload (FW_PAYLOAD)* is described in more
details in the file *fw_payload.md*.
[FW_DYNAMIC]: fw_dynamic.md
[FW_JUMP]: fw_jump.md
[FW_PAYLOAD]: fw_payload.md
Providing different payloads to OpenSBI Firmware
------------------------------------------------
OpenSBI firmware can accept various payloads using a compile time option.
Typically, these payloads refer to the next stage boot loader (e.g. U-Boot)
or operating system kernel images (e.g. Linux). By default, OpenSBI
automatically provides a test payload if no specific payload is specified
at compile time.
To specify a payload at compile time, the make variable _FW_PAYLOAD_PATH_ is
used.
```
make PLATFORM=<platform_subdir> FW_PAYLOAD_PATH=<payload path>
```
The instructions to build each payload is different and the details can
be found in the
*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.
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
the booting stage binary to follow OpenSBI firmware.
prior to the OpenSBI firmware is capable of loading both the OpenSBI firmware
and the booting stage binary to follow the OpenSBI firmware.
*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.
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
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.
*FW_JUMP* Firmware Configuration Options
@@ -27,26 +27,26 @@ build directory under the *build/platform/<platform_subdir>/firmware* directory.
To operate correctly, a *FW_JUMP* firmware requires some configuration
parameters to be defined using either the top level `make` command line or the
target platform *config.mk* configuration file. The possible parameters are as
follows.
follows:
* **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
mandatory parameter. Compilation errors will result from not defining this
address.
* **FW_JUMP_FDT_ADDR** - Address where the *flattened device tree (FDT file)*
passed by the prior booting stage will be placed in memory before executing
the booting stage following OpenSBI firmware. If this option is not provided,
then OpenSBI firmware will pass zero as the FDT address to the following
booting stage.
the booting stage following the OpenSBI firmware. If this option is not
provided, then the OpenSBI firmware will pass zero as the FDT address to the
following booting stage.
*FW_JUMP* Example
-----------------
The *[qemu/virt]* and *[qemu/sifive_u]* platforms illustrates how to configure
The *[qemu/virt]* and *[qemu/sifive_u]* platforms illustrate how to configure
and use a *FW_JUMP* firmware. Detailed information regarding these platforms
can be found in the platforms documentation files.
can be found in the platform documentation files.
[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
includes the binary for the booting stage to follow OpenSBI firmware execution.
Typically, this payload will be a bootloader or an OS kernel.
includes the binary for the booting stage to follow the OpenSBI firmware
execution. Typically, this payload will be a bootloader or an OS kernel.
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
the booting stage to follow OpenSBI firmware.
prior to the OpenSBI firmware is not capable of loading both the OpenSBI
firmware and the booting stage to follow OpenSBI firmware.
A *FW_PAYLOAD* firmware is also useful for cases where the booting stage prior
to OpenSBI firmware does not pass a *flattened device tree (FDT file)*. In such
case, a *FW_PAYLOAD* firmware allows embedding a flattened device tree in the
.text section of the final firmware.
to the OpenSBI firmware does not pass a *flattened device tree (FDT file)*. In
such a case, a *FW_PAYLOAD* firmware allows embedding a flattened device tree
in the .text section of the final firmware.
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.
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
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.
Configuration Options
@@ -34,7 +34,7 @@ Configuration Options
A *FW_PAYLOAD* firmware is built according to configuration parameters and
options. These configuration parameters can be defined using either the top
level `make` command line or the target platform *config.mk* configuration
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
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
*FW_PAYLOAD* firmware binary image. This configuration parameter is mandatory
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* ignored.
*FW_PAYLOAD_ALIGN* are defined, *FW_PAYLOAD_OFFSET* is used and
*FW_PAYLOAD_ALIGN* is ignored.
* **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
@@ -78,13 +78,12 @@ file. The parameters currently defined are as follows.
*FW_PAYLOAD* Example
--------------------
The *[qemu/virt]* and *[qemu/sifive_u]* platforms illustrates how to configure
The *[qemu/virt]* and *[qemu/sifive_u]* platforms illustrate how to configure
and use a *FW_PAYLOAD* firmware. Detailed information regarding these platforms
can be found in the platforms documentation files.
can be found in the 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*).
[qemu/virt]: ../platform/qemu_virt.md
[qemu/sifive_u]: ../platform/qemu_sifive_u.md

View File

@@ -0,0 +1,10 @@
Linux as a direct payload to OpenSBI
====================================
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
provided as a payload to OpenSBI.
Detailed examples can be found in both the [QEMU](../platform/qemu_virt.md)
and the [HiFive Unleashed](../platform/sifive_fu540.md) platform guides.

View File

@@ -0,0 +1,40 @@
U-Boot as a payload to OpenSBI
==============================
[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
environment. In the context of OpenSBI, U-Boot can be specified as a payload to
the OpenSBI firmware, becoming the boot stage following the OpenSBI firmware
execution.
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
following out-of-tree patch series must be applied to the upstream U-Boot source
code:
HiFive Unleashed support for U-Boot
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
stage boot code such as a Linux kernel can also only execute on a single CPU.
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
Building and Generating 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, the Linux kernel image needs to be converted
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 \
<linux_build_directory>arch/riscv/boot/Image \
<linux_build_directory>/arch/riscv/boot/uImage
```
Copy the uImage to your tftpboot server path if network boot is required.

View File

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

View File

@@ -0,0 +1,28 @@
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,37 @@
Ariane FPGA SoC Platform
==========================
Ariane is a 6-stage, single issue, in-order CPU which implements the 64-bit RISC-V instruction set.
The Ariane FPGA development platform is based on FPGA FPGA SoC(which currently supports only Genesys 2 board) and is capable
of running Linux.
The FPGA SoC currently contains the following peripherals:
- 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,11 +1,12 @@
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
machine. This virtual machine is intended for RISC-V software development and
test. More details on this platform can be found in the file *[qemu_virt.md]*.
* **QEMU RISC-V Virt Machine**: Platform support for the QEMU *virt* virtual
RISC-V machine. This virtual machine is intended for RISC-V software
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
@@ -18,13 +19,21 @@ OpenSBI currently supports the following virtual and hardware platforms.
*[sifive_fu540.md]*.
* **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).
The code for these supported platforms can be used as example to implement
support for other platforms. The *platform/template* directory also provides
template files for implementing support for a new platform. The *object.mk*,
*config.mk* and *platform.c* template files provides enough comments to facilitate
the implementation.
*config.mk* and *platform.c* template files provides enough comments to
facilitate the implementation.
[qemu_virt.md]: qemu_virt.md
[qemu_sifive_u.md]: qemu_sifive_u.md
[sifive_fu540.md]: sifive_fu540.md
[ariane-fpga.md]: ariane-fpga.md
[andes_ae350.md]: andes-ae350.md

View File

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

View File

@@ -1,22 +1,22 @@
QEMU RISC-V Virt Machine Platform
=================================
The **QEMU RISC-V Virt Machine** is virtual platform created for RISC-V
software development and testing. It is also referred as
The **QEMU RISC-V Virt Machine** is a virtual platform created for RISC-V
software development and testing. It is also referred to as
*QEMU RISC-V VirtIO machine* because it uses VirtIO devices for network,
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 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.
Execution on QEMU RISC-V 64bit
------------------------------
Execution on QEMU RISC-V 64-bit
-------------------------------
**No Payload Case**
@@ -27,7 +27,7 @@ make PLATFORM=qemu/virt
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
```
@@ -43,19 +43,19 @@ make PLATFORM=qemu/virt FW_PAYLOAD_PATH=<uboot_build_directory>/u-boot.bin
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
```
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=<uboot_build_directory>/u-boot.bin,addr=0x80200000
```
**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*.
Build:
@@ -65,7 +65,7 @@ make PLATFORM=qemu/virt FW_PAYLOAD_PATH=<linux_build_directory>/arch/riscv/boot/
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 \
-drive file=<path_to_linux_rootfs>,format=raw,id=hd0 \
-device virtio-blk-device,drive=hd0 \
@@ -73,7 +73,7 @@ qemu-system-riscv64 -M virt -m 256M -display none -serial stdio \
```
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 \
@@ -81,3 +81,72 @@ qemu-system-riscv64 -M virt -m 256M -display none -serial stdio \
-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 \
-device loader,file=<linux_build_directory>/arch/riscv/boot/Image,addr=0x80400000 \
-drive file=<path_to_linux_rootfs>,format=raw,id=hd0 \
-device virtio-blk-device,drive=hd0 \
-append "root=/dev/vda rw console=ttyS0"
```

View File

@@ -1,9 +1,12 @@
SiFive FU540 SoC Platform
==========================
The FU540-C000 is the worlds first 4+1 64-bit RISCV 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
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
*PLATFORM=sifive/fu540* parameter to the top level `make` command.
@@ -11,75 +14,76 @@ Platform Options
----------------
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
select any other hart for booting. Please keep in mind that this is not
platform wide option. It can only be specificd for FU540 platform in following way.
A hart mask i.e. *FU540_ENABLED_HART_MASK* compile time option is provided
to select any other hart for booting. Please keep in mind that this is not
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
```
This will let the board boot only hart1 instead of default 1-4.
Booting SiFive Fu540 Platform
Building SiFive Fu540 Platform
-----------------------------
In order to boot SMP Linux in U-Boot, Linux v5.1 (or higher) and latest
U-Boot v2019.04 (or higher) should be used.
**Linux Kernel Payload**
Build:
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
```
Flash:
The generated firmware binary should be copied to the first partition of the sdcard.
```
dd if=build/platform/sifive/fu540/firmware/fw_payload.bin of=/dev/disk2s1 bs=1024
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**
Note: U-Boot doesn't have SMP support. So you can only boot single cpu with non-smp
kernel configuration using U-Boot.
The command-line example here assumes that U-Boot was compiled using the
sifive_fu540_defconfig configuration and with U-Boot v2019.04 (or higher)
having SMP support. From, Linux v5.2 (or higher) device tree is hosted in
Linux kernel and compiled as a part of Linux kernel build process.
Build:
The commandline example here assumes that U-Boot was compiled using sifive_fu540_defconfig configuration.
```
make PLATFORM=sifive/fu540 FW_PAYLOAD_PATH=<u-boot_build_dir>/u-boot.bin FU540_ENABLED_HART_MASK=0x02
```
Flash:
The generated firmware binary should be copied to the first partition of the sdcard.
The detailed U-Boot booting guide is avaialble at [U-Boot](https://gitlab.denx.de/u-boot/u-boot/blob/master/doc/board/sifive/fu540.rst)
```
dd if=build/platform/sifive/fu540/firmware/fw_payload.bin of=/dev/disk2s1 bs=1024
make PLATFORM=sifive/fu540 FW_PAYLOAD_PATH=<u-boot_build_dir>/u-boot.bin
or
(For U-Boot which follows Linux v5.2 (or higher) DT bindings)
make PLATFORM=sifive/fu540 FW_PAYLOAD_PATH=<u-boot_build_dir>/u-boot.bin FW_PAYLOAD_FDT_PATH=<hifive-unleashed-a00.dtb path from Linux kernel>
```
U-Boot tftp boot method can be used to load kernel image in U-Boot prompt.
Note: As the U-Boot & Linux kernel patches are not in upstream it, you can cherry-pick from here.
U-Boot patchset:
https://lists.denx.de/pipermail/u-boot/2019-January/355941.html
Linux kernel patchset:
https://lkml.org/lkml/2019/1/8/192
Generate the uImage from Linux Image.
```
mkimage -A riscv -O linux -T kernel -C none -a 0x80200000 -e 0x80200000 -n Linux -d \
<linux_build_directory>/arch/riscv/boot/Image \
<linux_build_directory>/arch/riscv/boot/uImage
```
**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
not available.
A single monolithic image containing both U-Boot & Linux can also be used if
network boot setup is not available.
1. Generate the uImage from Linux Image.
```
mkimage -A riscv -O linux -T kernel -C none -a 0x80200000 -e 0x80200000 -n Linux -d \
<linux_build_directory>arch/riscv/boot/Image \
<linux_build_directory>/arch/riscv/boot/Image \
<linux_build_directory>/arch/riscv/boot/uImage
```
2. Create a temporary image with u-boot.bin as the first payload. The commandline example here assumes
that U-Boot was compiled using sifive_fu540_defconfig configuration.
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
```
@@ -87,16 +91,125 @@ dd if=~/workspace/u-boot-riscv/u-boot.bin of=/tmp/temp.bin bs=1M
```
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 and single hart enabled.
4. Compile OpenSBI with temp.bin (generated in step 3) as payload.
```
make PLATFORM=sifive/fu540 FW_PAYLOAD_PATH=/tmp/temp.bin FU540_ENABLED_HART_MASK=0x02
make PLATFORM=sifive/fu540 FW_PAYLOAD_PATH=/tmp/temp.bin
or
(For U-Boot which follows Linux v5.2 (or higher) DT bindings)
make PLATFORM=sifive/fu540 FW_PAYLOAD_PATH=/tmp/temp.bin FW_PAYLOAD_FDT_PATH=<hifive-unleashed-a00.dtb path from Linux kernel>
```
5. The generated firmware binary should be copied to the first partition of the sdcard.
Flashing the OpenSBI firmware binary to storage media:
-----------------------------------------------------
The first stage boot loader([FSBL](https://github.com/sifive/freedom-u540-c000-bootloader))
expects the storage media to have a GPT partition table. It tries to look for
a partition with following GUID to load the next stage boot loader (OpenSBI
in this case).
```
2E54B353-1271-4842-806F-E436D6AF6985
```
That's why the generated firmware binary in above steps should be copied to
the partition of the sdcard with above GUID.
```
dd if=build/platform/sifive/fu540/firmware/fw_payload.bin of=/dev/disk2s1 bs=1024
```
6. At U-Boot prompt execute following boot command to boot non-SMP linux.
In my case, it is the first partition is **disk2s1** that has been formatted
with the above specified GUID.
In case of a brand new sdcard, it should be formatted with below partition
tables as described here.
```
bootm 0x80600000 - 0x82200000
sgdisk --clear \
--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 \
${DISK}
```
Booting SiFive Fu540 Platform
-----------------------------
**Linux Kernel Payload**
As Linux kernel image is embedded in the OpenSBI firmware binary, HiFive
Unleashed will directly boot into Linux directly after powered on.
**U-Boot Payload**
As U-Boot image is used as payload, HiFive Unleashed will boot into a U-Boot
prompt. U-Boot tftp boot method can be used to load kernel image in U-Boot
prompt. Here are the steps do a tftpboot.
1. Set the mac address of the board.
```
setenv ethaddr <mac address of the board>
```
(Note: This step is optional)
2. Set the ip address of the board.
```
setenv ipaddr <ipaddr of the board>
```
3. Set the tftpboot server IP.
```
setenv serverip <ipaddr of the tftp server>
```
4. Set the network gateway address.
```
setenv gatewayip <ipaddress of the network gateway>
```
5. Load the Linux kernel image from the tftp server.
```
tftpboot ${kernel_addr_r} <uImage path in tftpboot directory>
```
6. Load the ramdisk image from the tftp server. This is only required if
ramdisk is loaded from tftp server. This step is optional, if rootfs is
already part of the kernel or loaded from an external storage by kernel.
```
tftpboot ${ramdisk_addr_r} <ramdisk path in tftpboot directory>
```
7. Load the pre-compiled device tree via tftpboot.
```
tftpboot ${fdt_addr_r} <linux source>/arch/riscv/boot/dts/sifive/hifive-unleashed-a00.dtb
```
8. Set the boot command-line arguments.
```
setenv bootargs "root=<root partition> rw console=ttySIF0 earlycon=sbi"
```
(Note: root partition should point to
** /dev/ram ** - If a ramdisk is used
** root=/dev/mmcblk0pX ** - If a rootfs is already on some other partition
of sdcard)
9. Now boot into Linux.
```
bootm ${kernel_addr_r} ${ramdisk_addr_r} ${fdt_addr_r}
or
(If ramdisk is not loaded from network)
bootm ${kernel_addr_r} - ${fdt_addr_r}
```
**U-Boot & Linux Kernel as a single payload**
At U-Boot prompt execute the following boot command to boot Linux.
```
bootm ${kernel_addr_r} - ${fdt_addr_r}
```
QEMU Specific Instructions
--------------------------
If you want to test OpenSBI with QEMU 'sifive_u' machine, please follow the
same instructions above, with the exception of not passing FW_PAYLOAD_FDT_PATH.
This is because QEMU generates a device tree blob on the fly based on the
command line parameters and it's compatible with the one used in the upstream
Linux kernel.

View File

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

View File

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

View File

@@ -13,6 +13,34 @@
#include <sbi/sbi_scratch.h>
#include <sbi/sbi_trap.h>
#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
.align 3
.section .entry, "ax", %progbits
.globl _start
@@ -22,8 +50,187 @@ _start:
* Jump to warm-boot if this is not the first core booting,
* that is, for mhartid != 0
*/
csrr a6, mhartid
blt zero, a6, _wait_for_boot_hart
csrr a6, CSR_MHARTID
blt zero, 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, _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, _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:
/*
* Mark relocate copy done
* Use _boot_status copy relative to the load address
*/
la t0, _boot_status
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 */
la a4, _bss_start
@@ -34,12 +241,10 @@ _bss_zero:
blt a4, a5, _bss_zero
/* Override pervious arg1 */
add s0, a0, zero
add s1, a1, zero
MOV_3R s0, a0, s1, a1, s2, a2
call fw_prev_arg1
add t1, a0, zero
add a0, s0, zero
add a1, s1, zero
MOV_3R a0, s0, a1, s1, a2, s2
beqz t1, _prev_arg1_override_done
add a1, t1, zero
_prev_arg1_override_done:
@@ -54,22 +259,25 @@ _prev_arg1_override_done:
*/
beqz a1, _fdt_reloc_done
/* Mask values in a3 and a4 */
li a3, ~0xf
li a3, ~(__SIZEOF_POINTER__ - 1)
li a4, 0xff
/* t1 = destination FDT start address */
add s0, a0, zero
add s1, a1, zero
MOV_3R s0, a0, s1, a1, s2, a2
call fw_next_arg1
add t1, a0, zero
add a0, s0, zero
add a1, s1, zero
MOV_3R a0, s0, a1, s1, a2, s2
beqz t1, _fdt_reloc_done
beq t1, a1, _fdt_reloc_done
and t1, t1, a3
/* t0 = source FDT start address */
add t0, a1, zero
and t0, t0, a3
/* t2 = source FDT size in big-endian */
#if __riscv_xlen == 64
lwu t2, 4(t0)
#else
lw t2, 4(t0)
#endif
/* t3 = bit[15:8] of FDT size */
add t3, t2, zero
srli t3, t3, 16
@@ -103,43 +311,47 @@ _fdt_reloc_again:
blt t1, t2, _fdt_reloc_again
_fdt_reloc_done:
/* Update boot hart flag */
la a4, _boot_hart_done
li a5, 1
REG_S a5, (a4)
j _wait_for_boot_hart
/* mark boot hart done */
li t0, BOOT_STATUS_BOOT_HART_DONE
la t1, _boot_status
REG_S t0, 0(t1)
fence rw, rw
j _start_warm
.align 3
_boot_hart_done:
RISCV_PTR 0
.align 3
/* Wait for boot hart */
/* waitting for boot hart done (_boot_status == 2) */
_wait_for_boot_hart:
la a4, _boot_hart_done
REG_L a5, (a4)
beqz a5, _wait_for_boot_hart
li t0, BOOT_STATUS_BOOT_HART_DONE
la t1, _boot_status
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:
/* Disable and clear all interrupts */
csrw mie, zero
csrw mip, zero
/* Reset all registers for non-boot HARTs */
li ra, 0
call _reset_regs
/* Disable and clear all interrupts */
csrw CSR_MIE, zero
csrw CSR_MIP, zero
/* Preload per-HART details
* s6 -> HART ID
* s7 -> HART Count
* s8 -> HART Stack Size
*/
csrr s6, mhartid
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
/* HART ID should be within expected limit */
csrr s6, mhartid
csrr s6, CSR_MHARTID
bge s6, s7, _start_hang
/* Setup scratch space */
/* find the scratch space for this hart */
la tp, _fw_end
mul a5, s7, s8
add tp, tp, a5
@@ -147,46 +359,37 @@ _start_warm:
sub tp, tp, a5
li a5, SBI_SCRATCH_SIZE
sub tp, tp, a5
csrw mscratch, tp
/* Initialize 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)
/* 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)
/* update the mscratch */
csrw CSR_MSCRATCH, tp
/* Setup stack */
add sp, tp, zero
/* Setup trap handler */
la a4, _trap_handler
csrw mtvec, a4
csrw CSR_MTVEC, a4
/* Make sure that mtvec is updated */
1: csrr a5, CSR_MTVEC
bne a4, a5, 1b
/* Initialize SBI runtime */
csrr a0, mscratch
csrr a0, CSR_MSCRATCH
call sbi_init
/* We don't expect to reach here hence just hang */
j _start_hang
.align 3
_boot_status:
RISCV_PTR 0
_load_start:
RISCV_PTR _fw_start
_link_start:
RISCV_PTR _fw_start
_link_end:
RISCV_PTR _fw_reloc_end
.align 3
.section .entry, "ax", %progbits
.globl _hartid_to_scratch
@@ -202,8 +405,13 @@ _hartid_to_scratch:
* s2 -> Temporary
*/
la s2, platform
#if __riscv_xlen == 64
lwu s0, SBI_PLATFORM_HART_STACK_SIZE_OFFSET(s2)
lwu s2, SBI_PLATFORM_HART_COUNT_OFFSET(s2)
#else
lw s0, SBI_PLATFORM_HART_STACK_SIZE_OFFSET(s2)
lw s2, SBI_PLATFORM_HART_COUNT_OFFSET(s2)
#endif
mul s2, s2, s0
la s1, _fw_end
add s1, s1, s2
@@ -228,42 +436,74 @@ _start_hang:
.section .entry, "ax", %progbits
.globl _trap_handler
_trap_handler:
/* Swap SP and MSCRATCH */
csrrw sp, mscratch, sp
/* Swap TP and MSCRATCH */
csrrw tp, CSR_MSCRATCH, tp
/* Save T0 in scratch space */
REG_S t0, SBI_SCRATCH_TMP0_OFFSET(tp)
/* Check which mode we came from */
csrr t0, CSR_MSTATUS
srl t0, t0, MSTATUS_MPP_SHIFT
and t0, t0, PRV_M
xori t0, t0, PRV_M
beq t0, zero, _trap_handler_m_mode
/* We came from S-mode or U-mode */
_trap_handler_s_mode:
/* Set T0 to original SP */
add t0, sp, zero
/* Setup exception stack */
add sp, tp, -(SBI_TRAP_REGS_SIZE)
/* Jump to code common for all modes */
j _trap_handler_all_mode
/* We came from M-mode */
_trap_handler_m_mode:
/* Set T0 to original SP */
add t0, sp, zero
/* Re-use current SP as exception stack */
add sp, sp, -(SBI_TRAP_REGS_SIZE)
/* Save RA, T0, T1, and T2 */
REG_S ra, SBI_TRAP_REGS_OFFSET(ra)(sp)
REG_S t0, SBI_TRAP_REGS_OFFSET(t0)(sp)
REG_S t1, SBI_TRAP_REGS_OFFSET(t1)(sp)
REG_S t2, SBI_TRAP_REGS_OFFSET(t2)(sp)
/* Save original SP and restore MSCRATCH */
add t0, sp, SBI_TRAP_REGS_SIZE
csrrw t0, mscratch, t0
_trap_handler_all_mode:
/* Save original SP (from T0) on stack */
REG_S t0, SBI_TRAP_REGS_OFFSET(sp)(sp)
/* Save MEPC and MSTATUS CSRs */
csrr t0, mepc
csrr t1, mstatus
/* Restore T0 from scratch space */
REG_L t0, SBI_SCRATCH_TMP0_OFFSET(tp)
/*
* Note: Fast path trap handling can be done here
* using SP, RA, T0, T1, and T2 registers where
* T0 <- MEPC
* T1 <- MSTATUS
*/
/* Save T0 on stack */
REG_S t0, SBI_TRAP_REGS_OFFSET(t0)(sp)
/* Swap TP and MSCRATCH */
csrrw tp, CSR_MSCRATCH, tp
/* Save MEPC and MSTATUS CSRs */
csrr t0, CSR_MEPC
REG_S t0, SBI_TRAP_REGS_OFFSET(mepc)(sp)
REG_S t1, SBI_TRAP_REGS_OFFSET(mstatus)(sp)
csrr t0, CSR_MSTATUS
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, RA, T0, T1, and T2 */
/* Save all general regisers except SP and T0 */
REG_S zero, SBI_TRAP_REGS_OFFSET(zero)(sp)
REG_S ra, SBI_TRAP_REGS_OFFSET(ra)(sp)
REG_S gp, SBI_TRAP_REGS_OFFSET(gp)(sp)
REG_S tp, SBI_TRAP_REGS_OFFSET(tp)(sp)
REG_S t1, SBI_TRAP_REGS_OFFSET(t1)(sp)
REG_S t2, SBI_TRAP_REGS_OFFSET(t2)(sp)
REG_S s0, SBI_TRAP_REGS_OFFSET(s0)(sp)
REG_S s1, SBI_TRAP_REGS_OFFSET(s1)(sp)
REG_S a0, SBI_TRAP_REGS_OFFSET(a0)(sp)
@@ -291,12 +531,15 @@ _trap_handler:
/* Call C routine */
add a0, sp, zero
csrr a1, mscratch
csrr a1, CSR_MSCRATCH
call sbi_trap_handler
/* Restore all general regisers except SP, RA, T0, T1, T2, and T3 */
/* Restore all general regisers except SP and T0 */
REG_L ra, SBI_TRAP_REGS_OFFSET(ra)(sp)
REG_L gp, SBI_TRAP_REGS_OFFSET(gp)(sp)
REG_L tp, SBI_TRAP_REGS_OFFSET(tp)(sp)
REG_L t1, SBI_TRAP_REGS_OFFSET(t1)(sp)
REG_L t2, SBI_TRAP_REGS_OFFSET(t2)(sp)
REG_L s0, SBI_TRAP_REGS_OFFSET(s0)(sp)
REG_L s1, SBI_TRAP_REGS_OFFSET(s1)(sp)
REG_L a0, SBI_TRAP_REGS_OFFSET(a0)(sp)
@@ -322,28 +565,64 @@ _trap_handler:
REG_L t5, SBI_TRAP_REGS_OFFSET(t5)(sp)
REG_L t6, SBI_TRAP_REGS_OFFSET(t6)(sp)
/* Load T0 and T1 with MEPC and MSTATUS */
REG_L t0, SBI_TRAP_REGS_OFFSET(mepc)(sp)
REG_L t1, SBI_TRAP_REGS_OFFSET(mstatus)(sp)
/*
* Note: Jump here after fast trap handling
* using SP, RA, T0, T1, and T2
* T0 <- MEPC
* T1 <- MSTATUS
*/
/* Restore MEPC and MSTATUS CSRs */
csrw mepc, t0
csrw mstatus, t1
REG_L t0, SBI_TRAP_REGS_OFFSET(mepc)(sp)
csrw CSR_MEPC, t0
REG_L t0, SBI_TRAP_REGS_OFFSET(mstatus)(sp)
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 RA, T0, T1, and T2 */
REG_L ra, SBI_TRAP_REGS_OFFSET(ra)(sp)
/* Restore T0 */
REG_L t0, SBI_TRAP_REGS_OFFSET(t0)(sp)
REG_L t1, SBI_TRAP_REGS_OFFSET(t1)(sp)
REG_L t2, SBI_TRAP_REGS_OFFSET(t2)(sp)
/* Restore SP */
REG_L sp, SBI_TRAP_REGS_OFFSET(sp)(sp)
mret
.align 3
.section .entry, "ax", %progbits
.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 = .);
*(.sdata)
*(.sdata.*)
*(.data)
*(.data.*)
*(.readmostly.data)
@@ -64,6 +66,8 @@
.bss :
{
PROVIDE(_bss_start = .);
*(.sbss)
*(.sbss.*)
*(.bss)
*(.bss.*)
. = ALIGN(8);

118
firmware/fw_dynamic.S Normal file
View File

@@ -0,0 +1,118 @@
/*
* 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"
.align 3
.section .entry, "ax", %progbits
_bad_dynamic_info:
wfi
j _bad_dynamic_info
.align 3
.section .entry, "ax", %progbits
.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:
la a4, _dynamic_next_arg1
REG_S a1, (a4)
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
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)
ret
.align 3
.section .entry, "ax", %progbits
.global fw_prev_arg1
/*
* We can only use a0, a1, and a2 registers here.
* The previous arg1 should be returned in 'a0'.
*/
fw_prev_arg1:
add a0, zero, zero
ret
.align 3
.section .entry, "ax", %progbits
.global fw_next_arg1
/*
* We can only use a0, a1, and a2 registers here.
* The next arg1 should be returned in 'a0'.
*/
fw_next_arg1:
la a0, _dynamic_next_arg1
REG_L a0, (a0)
ret
.align 3
.section .entry, "ax", %progbits
.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
.align 3
.section .entry, "ax", %progbits
.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
.align 3
.section .entry, "ax", %progbits
.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
.align 3
.section .entry, "ax", %progbits
_dynamic_next_arg1:
RISCV_PTR 0x0
_dynamic_next_addr:
RISCV_PTR 0x0
_dynamic_next_mode:
RISCV_PTR PRV_S
_dynamic_options:
RISCV_PTR 0x0

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,19 +9,37 @@
#include "fw_base.S"
.align 3
.section .entry, "ax", %progbits
.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
.align 3
.section .entry, "ax", %progbits
.global fw_prev_arg1
/*
* We can only use a0, a1, and a2 registers here.
* The previous arg1 should be returned in 'a0'.
*/
fw_prev_arg1:
/* We return previous arg1 in 'a0' */
add a0, zero, zero
ret
.align 3
.section .entry, "ax", %progbits
.global fw_next_arg1
/*
* We can only use a0, a1, and a2 registers here.
* The next arg1 should be returned in 'a0'.
*/
fw_next_arg1:
/* We return next arg1 in 'a0' */
#ifdef FW_JUMP_FDT_ADDR
li a0, FW_JUMP_FDT_ADDR
#else
@@ -32,12 +50,38 @@ fw_next_arg1:
.align 3
.section .entry, "ax", %progbits
.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:
/* We return next address in 'a0' */
la a0, _jump_addr
REG_L a0, (a0)
ret
.align 3
.section .entry, "ax", %progbits
.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
.align 3
.section .entry, "ax", %progbits
.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
#error "Must define FW_JUMP_ADDR"
#endif

View File

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

View File

@@ -9,11 +9,26 @@
#include "fw_base.S"
.align 3
.section .entry, "ax", %progbits
.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
.align 3
.section .entry, "ax", %progbits
.global fw_prev_arg1
/*
* We can only use a0, a1, and a2 registers here.
* The previous arg1 should be returned in 'a0'.
*/
fw_prev_arg1:
/* We return previous arg1 in 'a0' */
#ifdef FW_PAYLOAD_FDT_PATH
la a0, fdt_bin
#else
@@ -24,8 +39,11 @@ fw_prev_arg1:
.align 3
.section .entry, "ax", %progbits
.global fw_next_arg1
/*
* We can only use a0, a1, and a2 registers here.
* The next arg1 should be returned in 'a0'.
*/
fw_next_arg1:
/* We return next arg1 in 'a0' */
#ifdef FW_PAYLOAD_FDT_ADDR
li a0, FW_PAYLOAD_FDT_ADDR
#else
@@ -36,22 +54,46 @@ fw_next_arg1:
.align 3
.section .entry, "ax", %progbits
.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:
/* We return next address in 'a0' */
la a0, payload_bin
ret
#define str(s) #s
#define stringify(s) str(s)
.align 3
.section .entry, "ax", %progbits
.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
.align 3
.section .entry, "ax", %progbits
.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
.align 3
.align 4
.section .text, "ax", %progbits
.globl fdt_bin
fdt_bin:
.incbin stringify(FW_PAYLOAD_FDT_PATH)
.incbin FW_PAYLOAD_FDT_PATH
#endif
.align 4
.section .payload, "ax", %progbits
.globl payload_bin
payload_bin:
@@ -59,5 +101,5 @@ payload_bin:
wfi
j payload_bin
#else
.incbin stringify(FW_PAYLOAD_PATH)
.incbin FW_PAYLOAD_PATH
#endif

View File

@@ -27,4 +27,6 @@ SECTIONS
. = ALIGN(8);
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)
endif
firmware-bins-$(FW_DYNAMIC) += fw_dynamic.bin
firmware-bins-$(FW_JUMP) += fw_jump.bin
ifdef FW_JUMP_ADDR
firmware-genflags-$(FW_JUMP) += -DFW_JUMP_ADDR=$(FW_JUMP_ADDR)
@@ -29,9 +31,9 @@ firmware-bins-$(FW_PAYLOAD) += fw_payload.bin
ifdef FW_PAYLOAD_PATH
FW_PAYLOAD_PATH_FINAL=$(FW_PAYLOAD_PATH)
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
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
firmware-genflags-$(FW_PAYLOAD) += -DFW_PAYLOAD_OFFSET=$(FW_PAYLOAD_OFFSET)
endif
@@ -41,12 +43,16 @@ endif
ifndef FW_PAYLOAD_FDT_PATH
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
ifdef FW_PAYLOAD_FDT_PATH
firmware-genflags-$(FW_PAYLOAD) += -DFW_PAYLOAD_FDT_PATH=$(FW_PAYLOAD_FDT_PATH)
firmware-genflags-$(FW_PAYLOAD) += -DFW_PAYLOAD_FDT_PATH=\"$(FW_PAYLOAD_FDT_PATH)\"
endif
ifdef FW_PAYLOAD_FDT_ADDR
firmware-genflags-$(FW_PAYLOAD) += -DFW_PAYLOAD_FDT_ADDR=$(FW_PAYLOAD_FDT_ADDR)
endif
ifdef FW_OPTIONS
firmware-genflags-y += -DFW_OPTIONS=$(FW_OPTIONS)
endif

View File

@@ -7,6 +7,7 @@
* Anup Patel <anup.patel@wdc.com>
*/
#include <sbi/riscv_encoding.h>
#define __ASM_STR(x) x
#if __riscv_xlen == 64
@@ -48,12 +49,12 @@ _bss_zero:
_start_warm:
/* Disable and clear all interrupts */
csrw sie, zero
csrw sip, zero
csrw CSR_SIE, zero
csrw CSR_SIP, zero
/* Setup exception vectors */
la a3, _start_hang
csrw stvec, a3
csrw CSR_STVEC, a3
/* Setup stack */
la a3, _payload_end

View File

@@ -9,10 +9,35 @@
#include <sbi/sbi_ecall_interface.h>
#define wfi() \
do { \
__asm__ __volatile__ ("wfi" ::: "memory"); \
} while (0)
#define SBI_ECALL(__num, __a0, __a1, __a2) \
({ \
register unsigned long a0 asm("a0") = (unsigned long)(__a0); \
register unsigned long a1 asm("a1") = (unsigned long)(__a1); \
register unsigned long a2 asm("a2") = (unsigned long)(__a2); \
register unsigned long a7 asm("a7") = (unsigned long)(__num); \
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)
{

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

@@ -0,0 +1,61 @@
/*
* 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 */
#define FW_DYNAMIC_INFO_NEXT_ADDR_OFFSET (2 * __SIZEOF_POINTER__)
/** Offset of next_mode member in fw_dynamic_info */
#define FW_DYNAMIC_INFO_NEXT_MODE_OFFSET (3 * __SIZEOF_POINTER__)
/** Offset of options member in fw_dynamic_info */
#define FW_DYNAMIC_INFO_OPTIONS_OFFSET (4 * __SIZEOF_POINTER__)
/** Expected value of info magic ('OSBI' ascii string in hex) */
#define FW_DYNAMIC_INFO_MAGIC_VALUE 0x4942534f
/** Maximum supported info version */
#define FW_DYNAMIC_INFO_VERSION_MAX 0x1
/** 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;
} __packed;
#endif
#endif

View File

@@ -10,6 +10,10 @@
#ifndef __RISCV_ASM_H__
#define __RISCV_ASM_H__
#include <sbi/riscv_encoding.h>
/* clang-format off */
#ifdef __ASSEMBLY__
#define __ASM_STR(x) x
#else
@@ -24,6 +28,10 @@
#error "Unexpected __riscv_xlen"
#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_S __REG_SEL(sd, sw)
#define SZREG __REG_SEL(8, 4)
@@ -71,90 +79,99 @@
#error "Unexpected __SIZEOF_SHORT__"
#endif
/* clang-format on */
#ifndef __ASSEMBLY__
#define csr_swap(csr, val) \
({ \
unsigned long __v = (unsigned long)(val); \
__asm__ __volatile__ ("csrrw %0, " __ASM_STR(csr) ", %1"\
: "=r" (__v) : "rK" (__v) \
: "memory"); \
__v; \
})
#define csr_swap(csr, val) \
({ \
unsigned long __v = (unsigned long)(val); \
__asm__ __volatile__("csrrw %0, " __ASM_STR(csr) ", %1" \
: "=r"(__v) \
: "rK"(__v) \
: "memory"); \
__v; \
})
#define csr_read(csr) \
({ \
register unsigned long __v; \
__asm__ __volatile__ ("csrr %0, " __ASM_STR(csr) \
: "=r" (__v) : \
: "memory"); \
__v; \
})
#define csr_read(csr) \
({ \
register unsigned long __v; \
__asm__ __volatile__("csrr %0, " __ASM_STR(csr) \
: "=r"(__v) \
: \
: "memory"); \
__v; \
})
#define csr_write(csr, val) \
({ \
unsigned long __v = (unsigned long)(val); \
__asm__ __volatile__ ("csrw " __ASM_STR(csr) ", %0" \
: : "rK" (__v) \
: "memory"); \
})
#define csr_write(csr, val) \
({ \
unsigned long __v = (unsigned long)(val); \
__asm__ __volatile__("csrw " __ASM_STR(csr) ", %0" \
: \
: "rK"(__v) \
: "memory"); \
})
#define csr_read_set(csr, val) \
({ \
unsigned long __v = (unsigned long)(val); \
__asm__ __volatile__ ("csrrs %0, " __ASM_STR(csr) ", %1"\
: "=r" (__v) : "rK" (__v) \
: "memory"); \
__v; \
})
#define csr_read_set(csr, val) \
({ \
unsigned long __v = (unsigned long)(val); \
__asm__ __volatile__("csrrs %0, " __ASM_STR(csr) ", %1" \
: "=r"(__v) \
: "rK"(__v) \
: "memory"); \
__v; \
})
#define csr_set(csr, val) \
({ \
unsigned long __v = (unsigned long)(val); \
__asm__ __volatile__ ("csrs " __ASM_STR(csr) ", %0" \
: : "rK" (__v) \
: "memory"); \
})
#define csr_set(csr, val) \
({ \
unsigned long __v = (unsigned long)(val); \
__asm__ __volatile__("csrs " __ASM_STR(csr) ", %0" \
: \
: "rK"(__v) \
: "memory"); \
})
#define csr_read_clear(csr, val) \
({ \
unsigned long __v = (unsigned long)(val); \
__asm__ __volatile__ ("csrrc %0, " __ASM_STR(csr) ", %1"\
: "=r" (__v) : "rK" (__v) \
: "memory"); \
__v; \
})
#define csr_read_clear(csr, val) \
({ \
unsigned long __v = (unsigned long)(val); \
__asm__ __volatile__("csrrc %0, " __ASM_STR(csr) ", %1" \
: "=r"(__v) \
: "rK"(__v) \
: "memory"); \
__v; \
})
#define csr_clear(csr, val) \
({ \
unsigned long __v = (unsigned long)(val); \
__asm__ __volatile__ ("csrc " __ASM_STR(csr) ", %0" \
: : "rK" (__v) \
: "memory"); \
})
#define csr_clear(csr, val) \
({ \
unsigned long __v = (unsigned long)(val); \
__asm__ __volatile__("csrc " __ASM_STR(csr) ", %0" \
: \
: "rK"(__v) \
: "memory"); \
})
unsigned long csr_read_num(int csr_num);
void csr_write_num(int csr_num, unsigned long val);
#define wfi() \
do { \
__asm__ __volatile__ ("wfi" ::: "memory"); \
} while (0)
#define wfi() \
do { \
__asm__ __volatile__("wfi" ::: "memory"); \
} while (0)
static inline int misa_extension(char ext)
{
return csr_read(misa) & (1 << (ext - 'A'));
return csr_read(CSR_MISA) & (1 << (ext - 'A'));
}
static inline int misa_xlen(void)
{
return ((long)csr_read(misa) < 0) ? 64 : 32;
return ((long)csr_read(CSR_MISA) < 0) ? 64 : 32;
}
static inline void misa_string(char *out, unsigned int out_sz)
{
unsigned long i, val = csr_read(misa);
unsigned long i, val = csr_read(CSR_MISA);
for (i = 0; i < 26; i++) {
if (val & (1 << i)) {
@@ -166,11 +183,11 @@ static inline void misa_string(char *out, unsigned int out_sz)
out++;
}
int pmp_set(unsigned int n, unsigned long prot,
unsigned long addr, unsigned long log2len);
int pmp_set(unsigned int n, unsigned long prot, unsigned long addr,
unsigned long log2len);
int pmp_get(unsigned int n, unsigned long *prot_out,
unsigned long *addr_out, unsigned long *log2len_out);
int pmp_get(unsigned int n, unsigned long *prot_out, unsigned long *addr_out,
unsigned long *log2len_out);
#endif /* !__ASSEMBLY__ */

View File

@@ -14,11 +14,12 @@ typedef struct {
volatile long counter;
} atomic_t;
#define ATOMIC_INIT(_lptr, val) \
(_lptr)->counter = (val)
#define ATOMIC_INIT(_lptr, val) (_lptr)->counter = (val)
#define ATOMIC_INITIALIZER(val) \
{ .counter = (val), }
#define ATOMIC_INITIALIZER(val) \
{ \
.counter = (val), \
}
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 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.
* @nr : Bit to set.

View File

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

View File

@@ -14,6 +14,7 @@
/* TODO: Make constants usable in assembly with _AC() macro */
/* clang-format off */
#define MSTATUS_UIE 0x00000001
#define MSTATUS_SIE 0x00000002
#define MSTATUS_HIE 0x00000004
@@ -37,15 +38,30 @@
#define MSTATUS_TW 0x00200000
#define MSTATUS_TSR 0x00400000
#define MSTATUS32_SD 0x80000000
#if __riscv_xlen == 64
#define MSTATUS_UXL 0x0000000300000000
#define MSTATUS_SXL 0x0000000C00000000
#define MSTATUS_MTL 0x0000004000000000
#define MSTATUS_MTL_SHIFT 38
#define MSTATUS_MPV 0x0000008000000000
#define MSTATUS_MPV_HIFT 39
#else
#define MSTATUSH_UXL 0x00000003
#define MSTATUSH_SXL 0x0000000C
#define MSTATUSH_MTL 0x00000040
#define MSTATUSH_MTL_SHIFT 6
#define MSTATUSH_MPV 0x00000080
#define MSTATUSH_MPV_HIFT 7
#endif
#define MSTATUS64_SD 0x8000000000000000
#define SSTATUS_UIE 0x00000001
#define SSTATUS_SIE 0x00000002
#define SSTATUS_UPIE 0x00000010
#define SSTATUS_SPIE 0x00000020
#define SSTATUS_SPP 0x00000100
#define SSTATUS_SPIE_SHIFT 5
#define SSTATUS_SPIE (1UL << MSTATUS_SPIE_SHIFT)
#define SSTATUS_SPP_SHIFT 8
#define SSTATUS_SPP (1UL << MSTATUS_SPP_SHIFT)
#define SSTATUS_FS 0x00006000
#define SSTATUS_XS 0x00018000
#define SSTATUS_SUM 0x00040000
@@ -54,6 +70,14 @@
#define SSTATUS_UXL 0x0000000300000000
#define SSTATUS64_SD 0x8000000000000000
#define HSTATUS_VTSR 0x00400000
#define HSTATUS_VTVM 0x00100000
#define HSTATUS_SP2V 0x00000200
#define HSTATUS_SP2P 0x00000100
#define HSTATUS_SPV 0x00000080
#define HSTATUS_STL 0x00000040
#define HSTATUS_SPRV 0x00000001
#define DCSR_XDEBUGVER (3U<<30)
#define DCSR_NDRESET (1<<29)
#define DCSR_FULLRESET (1<<28)
@@ -195,10 +219,18 @@
#define RISCV_PGSHIFT 12
#define RISCV_PGSIZE (1 << RISCV_PGSHIFT)
#define CSR_USTATUS 0x0
#define CSR_FFLAGS 0x1
#define CSR_FRM 0x2
#define CSR_FCSR 0x3
#define CSR_CYCLE 0xc00
#define CSR_UIE 0x4
#define CSR_UTVEC 0x5
#define CSR_USCRATCH 0x40
#define CSR_UEPC 0x41
#define CSR_UCAUSE 0x42
#define CSR_UTVAL 0x43
#define CSR_UIP 0x44
#define CSR_TIME 0xc01
#define CSR_INSTRET 0xc02
#define CSR_HPMCOUNTER3 0xc03
@@ -240,6 +272,25 @@
#define CSR_STVAL 0x143
#define CSR_SIP 0x144
#define CSR_SATP 0x180
#define CSR_HSTATUS 0x600
#define CSR_HEDELEG 0x602
#define CSR_HIDELEG 0x603
#define CSR_HTIMEDELTA 0x605
#define CSR_HTIMEDELTAH 0x615
#define CSR_HCOUNTERNEN 0x606
#define CSR_HGATP 0x680
#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_MISA 0x301
#define CSR_MEDELEG 0x302
@@ -247,6 +298,7 @@
#define CSR_MIE 0x304
#define CSR_MTVEC 0x305
#define CSR_MCOUNTEREN 0x306
#define CSR_MSTATUSH 0x310
#define CSR_MSCRATCH 0x340
#define CSR_MEPC 0x341
#define CSR_MCAUSE 0x342
@@ -279,6 +331,7 @@
#define CSR_DCSR 0x7b0
#define CSR_DPC 0x7b1
#define CSR_DSCRATCH 0x7b2
#define CSR_MCYCLE 0xb00
#define CSR_MINSTRET 0xb02
#define CSR_MHPMCOUNTER3 0xb03
@@ -416,8 +469,8 @@
#define CAUSE_MISALIGNED_STORE 0x6
#define CAUSE_STORE_ACCESS 0x7
#define CAUSE_USER_ECALL 0x8
#define CAUSE_SUPERVISOR_ECALL 0x9
#define CAUSE_HYPERVISOR_ECALL 0xa
#define CAUSE_HYPERVISOR_ECALL 0x9
#define CAUSE_SUPERVISOR_ECALL 0xa
#define CAUSE_MACHINE_ECALL 0xb
#define CAUSE_FETCH_PAGE_FAULT 0xc
#define CAUSE_LOAD_PAGE_FAULT 0xd
@@ -493,6 +546,9 @@
#define INSN_MATCH_C_FSWSP 0xe002
#define INSN_MASK_C_FSWSP 0xe003
#define INSN_MASK_WFI 0xffffff00
#define INSN_MATCH_WFI 0x10500000
#define INSN_LEN(insn) ((((insn) & 0x3) < 0x3) ? 2 : 4)
#if __riscv_xlen == 64
@@ -553,4 +609,6 @@
(s32)(((insn) >> 7) & 0x1f))
#define MASK_FUNCT3 0x7000
/* clang-format on */
#endif

View File

@@ -21,40 +21,57 @@
#ifdef __riscv_flen
#define GET_F32_REG(insn, pos, regs) ({ \
register s32 value asm("a0") = SHIFT_RIGHT(insn, (pos)-3) & 0xf8; \
ulong tmp; \
asm ("1: auipc %0, %%pcrel_hi(get_f32_reg); add %0, %0, %1; jalr t0, %0, %%pcrel_lo(1b)" : "=&r"(tmp), "+&r"(value) :: "t0"); \
value; })
#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 GET_F32_REG(insn, pos, regs) \
({ \
register s32 value asm("a0") = \
SHIFT_RIGHT(insn, (pos)-3) & 0xf8; \
ulong tmp; \
asm("1: auipc %0, %%pcrel_hi(get_f32_reg); add %0, %0, %1; jalr t0, %0, %%pcrel_lo(1b)" \
: "=&r"(tmp), "+&r"(value)::"t0"); \
value; \
})
#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 GET_F64_REG(insn, pos, regs) ({ \
register ulong value asm("a0") = SHIFT_RIGHT(insn, (pos)-3) & 0xf8; \
ulong tmp; \
asm ("1: auipc %0, %%pcrel_hi(get_f64_reg); add %0, %0, %1; jalr t0, %0, %%pcrel_lo(1b)" : "=&r"(tmp), "+&r"(value) :: "t0"); \
sizeof(ulong) == 4 ? *(int64_t*)value : (int64_t)value; })
#define SET_F64_REG(insn, pos, regs, val) ({ \
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(fcsr)
#define SET_FCSR(value) csr_write(fcsr, (value))
#define GET_FRM() csr_read(frm)
#define SET_FRM(value) csr_write(frm, (value))
#define GET_FFLAGS() csr_read(fflags)
#define SET_FFLAGS(value) csr_write(fflags, (value))
#define GET_F64_REG(insn, pos, regs) \
({ \
register ulong value asm("a0") = \
SHIFT_RIGHT(insn, (pos)-3) & 0xf8; \
ulong tmp; \
asm("1: auipc %0, %%pcrel_hi(get_f64_reg); add %0, %0, %1; jalr t0, %0, %%pcrel_lo(1b)" \
: "=&r"(tmp), "+&r"(value)::"t0"); \
sizeof(ulong) == 4 ? *(int64_t *)value : (int64_t)value; \
})
#define SET_F64_REG(insn, pos, regs, val) \
({ \
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 SET_FCSR(value) csr_write(CSR_FCSR, (value))
#define GET_FRM() csr_read(CSR_FRM)
#define SET_FRM(value) csr_write(CSR_FRM, (value))
#define GET_FFLAGS() csr_read(CSR_FFLAGS)
#define SET_FFLAGS(value) csr_write(CSR_FFLAGS, (value))
#define SET_FS_DIRTY() ((void) 0)
#else
#error "Floating point emulation not supported.\n"
#endif
#define SET_FS_DIRTY() ((void)0)
#define GET_F32_RS1(insn, regs) (GET_F32_REG(insn, 15, 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_RS2(insn, regs) (GET_F64_REG(insn, 20, regs))
#define GET_F64_RS3(insn, regs) (GET_F64_REG(insn, 27, regs))
#define SET_F32_RD(insn, regs, val) (SET_F32_REG(insn, 7, regs, val), SET_FS_DIRTY())
#define SET_F64_RD(insn, regs, val) (SET_F64_REG(insn, 7, regs, val), SET_FS_DIRTY())
#define SET_F32_RD(insn, regs, val) \
(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_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))
#endif
#endif

View File

@@ -15,23 +15,23 @@
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)
{
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)
{
asm volatile("sw %0, 0(%1)" : : "r" (val), "r" (addr));
asm volatile("sw %0, 0(%1)" : : "r"(val), "r"(addr));
}
#if __riscv_xlen != 32
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
@@ -39,7 +39,7 @@ static inline u8 __raw_readb(const volatile void *addr)
{
u8 val;
asm volatile("lb %0, 0(%1)" : "=r" (val) : "r" (addr));
asm volatile("lb %0, 0(%1)" : "=r"(val) : "r"(addr));
return val;
}
@@ -47,7 +47,7 @@ static inline u16 __raw_readw(const volatile void *addr)
{
u16 val;
asm volatile("lh %0, 0(%1)" : "=r" (val) : "r" (addr));
asm volatile("lh %0, 0(%1)" : "=r"(val) : "r"(addr));
return val;
}
@@ -55,7 +55,7 @@ static inline u32 __raw_readl(const volatile void *addr)
{
u32 val;
asm volatile("lw %0, 0(%1)" : "=r" (val) : "r" (addr));
asm volatile("lw %0, 0(%1)" : "=r"(val) : "r"(addr));
return val;
}
@@ -64,12 +64,15 @@ static inline u64 __raw_readq(const volatile void *addr)
{
u64 val;
asm volatile("ld %0, 0(%1)" : "=r" (val) : "r" (addr));
asm volatile("ld %0, 0(%1)" : "=r"(val) : "r"(addr));
return val;
}
#endif
/* FIXME: These are now the same as asm-generic */
/* clang-format off */
#define __io_rbr() do {} while (0)
#define __io_rar() 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(); })
#endif
/* clang-format on */
#endif

View File

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

View File

@@ -0,0 +1,49 @@
/*
* SPDX-License-Identifier: BSD-2-Clause
*
* Copyright (c) 2019 Western Digital Corporation or its affiliates.
*
* Authors:
* Anup Patel <anup.patel@wdc.com>
*/
#ifndef __RISCV_UNPRIV_H__
#define __RISCV_UNPRIV_H__
#include <sbi/sbi_types.h>
struct sbi_scratch;
struct unpriv_trap {
unsigned long ilen;
unsigned long cause;
unsigned long tval;
};
#define DECLARE_UNPRIVILEGED_LOAD_FUNCTION(type) \
type load_##type(const type *addr, \
struct sbi_scratch *scratch, \
struct unpriv_trap *trap);
#define DECLARE_UNPRIVILEGED_STORE_FUNCTION(type) \
void store_##type(type *addr, type val, \
struct sbi_scratch *scratch, \
struct unpriv_trap *trap);
DECLARE_UNPRIVILEGED_LOAD_FUNCTION(u8)
DECLARE_UNPRIVILEGED_LOAD_FUNCTION(u16)
DECLARE_UNPRIVILEGED_LOAD_FUNCTION(s8)
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)
ulong get_insn(ulong mepc, bool virt, struct sbi_scratch *scratch,
struct unpriv_trap *trap);
#endif

View File

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

View File

@@ -13,19 +13,20 @@
#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 ROUNDUP(a, b) ((((a)-1) / (b) + 1) * (b))
#define ROUNDDOWN(a, b) ((a) / (b) * (b))
#define MAX(a, b) ((a) > (b) ? (a) : (b))
#define MIN(a, b) ((a) < (b) ? (a) : (b))
#define CLAMP(a, lo, hi) MIN(MAX(a, lo), hi)
#define EXTRACT_FIELD(val, which) (((val) & (which)) / ((which) & ~((which)-1)))
#define INSERT_FIELD(val, which, fieldval) (((val) & ~(which)) | ((fieldval) * ((which) & ~((which)-1))))
#define INSERT_FIELD(val, which, fieldval) \
(((val) & ~(which)) | ((fieldval) * ((which) & ~((which)-1))))
#define STR(x) XSTR(x)
#define XSTR(x) #x
#define BIT_MASK(nr) (1UL << ((nr) % BITS_PER_LONG))
#define BIT_WORD(nr) ((nr) / BITS_PER_LONG)
#define BIT_MASK(nr) (1UL << ((nr) % BITS_PER_LONG))
#define BIT_WORD(nr) ((nr) / BITS_PER_LONG)
#endif

View File

@@ -12,11 +12,11 @@
#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);
char sbi_getc(void);
int sbi_getc(void);
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(3, 4) sbi_snprintf(char *out, u32 out_sz,
const char *format, ...);
int __printf(3, 4) sbi_snprintf(char *out, u32 out_sz, const char *format, ...);
int __printf(1, 2) sbi_printf(const char *format, ...);
struct sbi_scratch;
int __printf(2, 3) sbi_dprintf(struct sbi_scratch *scratch,
const char *format, ...);
int sbi_console_init(struct sbi_scratch *scratch);
#endif

View File

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

View File

@@ -19,8 +19,7 @@ u16 sbi_ecall_version_major(void);
u16 sbi_ecall_version_minor(void);
int sbi_ecall_handler(u32 hartid, ulong mcause,
struct sbi_trap_regs *regs,
int sbi_ecall_handler(u32 hartid, ulong mcause, struct sbi_trap_regs *regs,
struct sbi_scratch *scratch);
#endif

View File

@@ -10,39 +10,36 @@
#ifndef __SBI_ECALL_INTERFACE_H__
#define __SBI_ECALL_INTERFACE_H__
#define SBI_ECALL_SET_TIMER 0
#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
/* clang-format off */
#define SBI_ECALL(__num, __a0, __a1, __a2) ({ \
register unsigned long a0 asm ("a0") = (unsigned long)(__a0); \
register unsigned long a1 asm ("a1") = (unsigned long)(__a1); \
register unsigned long a2 asm ("a2") = (unsigned long)(__a2); \
register unsigned long a7 asm ("a7") = (unsigned long)(__num); \
asm volatile ("ecall" \
: "+r" (a0) \
: "r" (a1), "r" (a2), "r" (a7) \
: "memory"); \
a0; \
})
enum sbi_ext_id {
SBI_EXT_0_1_SET_TIMER = 0x0,
SBI_EXT_0_1_CONSOLE_PUTCHAR = 0x1,
SBI_EXT_0_1_CONSOLE_GETCHAR = 0x2,
SBI_EXT_0_1_CLEAR_IPI = 0x3,
SBI_EXT_0_1_SEND_IPI = 0x4,
SBI_EXT_0_1_REMOTE_FENCE_I = 0x5,
SBI_EXT_0_1_REMOTE_SFENCE_VMA = 0x6,
SBI_EXT_0_1_REMOTE_SFENCE_VMA_ASID = 0x7,
SBI_EXT_0_1_SHUTDOWN = 0x8,
SBI_EXT_BASE = 0x10,
};
#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)
enum sbi_ext_base_fid {
SBI_EXT_BASE_GET_SPEC_VERSION = 0,
SBI_EXT_BASE_GET_IMP_ID,
SBI_EXT_BASE_GET_IMP_VERSION,
SBI_EXT_BASE_PROBE_EXT,
SBI_EXT_BASE_GET_MVENDORID,
SBI_EXT_BASE_GET_MARCHID,
SBI_EXT_BASE_GET_MIMPID,
};
#define sbi_ecall_console_putc(c) \
SBI_ECALL_1(SBI_ECALL_CONSOLE_PUTCHAR, (c));
static inline void sbi_ecall_console_puts(const char *str)
{
while (str && *str)
sbi_ecall_console_putc(*str++);
}
#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

View File

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

View File

@@ -10,16 +10,25 @@
#ifndef __SBI_ERROR_H__
#define __SBI_ERROR_H__
/* clang-format off */
#define SBI_OK 0
#define SBI_EUNKNOWN -1
#define SBI_EFAIL -2
#define SBI_EFAIL -1
#define SBI_ENOTSUPP -2
#define SBI_EINVAL -3
#define SBI_ENOENT -4
#define SBI_ENOTSUPP -5
#define SBI_DENIED -4
#define SBI_INVALID_ADDR -5
#define SBI_ENODEV -6
#define SBI_ENOSYS -7
#define SBI_ETIMEDOUT -8
#define SBI_EIO -9
#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

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,20 @@
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_pmp_dump(struct sbi_scratch *scratch);
void __attribute__((noreturn)) sbi_hart_hang(void);
void __attribute__((noreturn)) sbi_hart_switch_mode(unsigned long arg0,
unsigned long arg1,
unsigned long next_addr,
unsigned long next_mode);
void __attribute__((noreturn))
sbi_hart_switch_mode(unsigned long arg0, unsigned long arg1,
unsigned long next_addr, unsigned long next_mode,
bool next_virt);
void sbi_hart_mark_available(u32 hartid);

View File

@@ -10,17 +10,27 @@
#ifndef __SBI_IPI_H__
#define __SBI_IPI_H__
#include <sbi/riscv_unpriv.h>
#include <sbi/sbi_types.h>
/* clang-format off */
#define SBI_IPI_EVENT_SOFT 0x1
#define SBI_IPI_EVENT_FENCE_I 0x2
#define SBI_IPI_EVENT_SFENCE_VMA 0x4
#define SBI_IPI_EVENT_HALT 0x8
#define SBI_IPI_EVENT_SFENCE_VMA_ASID 0x8
#define SBI_IPI_EVENT_HALT 0x10
/* clang-format on */
struct sbi_scratch;
int sbi_ipi_send_many(struct sbi_scratch *scratch,
ulong *pmask, u32 event);
struct sbi_ipi_data {
unsigned long ipi_type;
};
int sbi_ipi_send_many(struct sbi_scratch *scratch, struct unpriv_trap *uptrap,
ulong *pmask, u32 event, void *data);
void sbi_ipi_clear_smode(struct sbi_scratch *scratch);

View File

@@ -10,56 +10,66 @@
#ifndef __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 */
#define SBI_PLATFORM_NAME_OFFSET (0x0)
#define SBI_PLATFORM_NAME_OFFSET (0x08)
/** 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 */
#define SBI_PLATFORM_HART_COUNT_OFFSET (0x48)
#define SBI_PLATFORM_HART_COUNT_OFFSET (0x50)
/** 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 tlb_range_flush_limit in struct sbi_platform */
#define SBI_PLATFORM_TLB_RANGE_FLUSH_LIMIT_OFFSET (0x60)
/** Offset of platform_ops_addr in struct sbi_platform */
#define SBI_PLATFORM_OPS_OFFSET (0x68)
/** Offset of firmware_context in struct sbi_platform */
#define SBI_PLATFORM_FIRMWARE_CONTEXT_OFFSET (0x68 + __SIZEOF_POINTER__)
#define SBI_PLATFORM_TLB_RANGE_FLUSH_LIMIT_DEFAULT (1UL << 12)
#ifndef __ASSEMBLY__
#include <sbi/sbi_version.h>
#include <sbi/sbi_scratch.h>
#include <sbi/sbi_ecall.h>
#include <sbi/sbi_error.h>
/** Possible feature flags of a platform */
enum sbi_platform_features {
/** Platform has timer value */
SBI_PLATFORM_HAS_TIMER_VALUE = (1 << 0),
SBI_PLATFORM_HAS_TIMER_VALUE = (1 << 0),
/** Platform has HART hotplug support */
SBI_PLATFORM_HAS_HART_HOTPLUG = (1 << 1),
SBI_PLATFORM_HAS_HART_HOTPLUG = (1 << 1),
/** Platform has PMP support */
SBI_PLATFORM_HAS_PMP = (1 << 2),
SBI_PLATFORM_HAS_PMP = (1 << 2),
/** Platform has S-mode counter enable */
SBI_PLATFORM_HAS_SCOUNTEREN = (1 << 3),
SBI_PLATFORM_HAS_SCOUNTEREN = (1 << 3),
/** Platform has M-mode counter enable */
SBI_PLATFORM_HAS_MCOUNTEREN = (1 << 4),
SBI_PLATFORM_HAS_MCOUNTEREN = (1 << 4),
/** 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 */
#define SBI_PLATFORM_DEFAULT_FEATURES \
(SBI_PLATFORM_HAS_TIMER_VALUE | \
SBI_PLATFORM_HAS_PMP | \
SBI_PLATFORM_HAS_SCOUNTEREN | \
SBI_PLATFORM_HAS_MCOUNTEREN | \
#define SBI_PLATFORM_DEFAULT_FEATURES \
(SBI_PLATFORM_HAS_TIMER_VALUE | SBI_PLATFORM_HAS_PMP | \
SBI_PLATFORM_HAS_SCOUNTEREN | SBI_PLATFORM_HAS_MCOUNTEREN | \
SBI_PLATFORM_HAS_MFAULTS_DELEGATION)
/** Representation of a platform */
struct sbi_platform {
/** Name of the platform */
char name[64];
/** Supported features */
u64 features;
/** Total number of HARTs */
u32 hart_count;
/** Per-HART stack size for exception/interrupt handling */
u32 hart_stack_size;
/** Mask representing the set of disabled HARTs */
u64 disabled_hart_mask;
/** Platform functions */
struct sbi_platform_operations {
/** Platform early initialization */
int (*early_init)(bool cold_boot);
/** Platform final initialization */
@@ -71,13 +81,13 @@ struct sbi_platform {
* 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);
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);
int (*console_getc)(void);
/** Initialize the platform console */
int (*console_init)(void);
@@ -86,8 +96,6 @@ struct sbi_platform {
/** 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 */
@@ -106,31 +114,74 @@ struct sbi_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,
unsigned long *out_trap_cause,
unsigned long *out_trap_val);
} __packed;
/** Representation of a 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 */
char name[64];
/** Supported features */
u64 features;
/** Total number of HARTs */
u32 hart_count;
/** Per-HART stack size for exception/interrupt handling */
u32 hart_stack_size;
/** Mask representing the set of disabled HARTs */
u64 disabled_hart_mask;
/* Maximum value of tlb flush range request*/
u64 tlb_range_flush_limit;
/** Pointer to sbi platform operations */
unsigned long platform_ops_addr;
/** Pointer to system firmware specific context */
unsigned long firmware_context;
} __packed;
/** Get pointer to sbi_platform for sbi_scratch pointer */
#define sbi_platform_ptr(__s) \
((struct sbi_platform *)((__s)->platform_addr))
#define sbi_platform_ptr(__s) \
((const struct sbi_platform *)((__s)->platform_addr))
/** Get pointer to sbi_platform for current HART */
#define sbi_platform_thishart_ptr() \
((struct sbi_platform *)(sbi_scratch_thishart_ptr()->platform_addr))
#define sbi_platform_thishart_ptr() ((const struct sbi_platform *) \
(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 */
#define sbi_platform_has_timer_value(__p) \
#define sbi_platform_has_timer_value(__p) \
((__p)->features & SBI_PLATFORM_HAS_TIMER_VALUE)
/** Check whether the platform supports HART hotplug */
#define sbi_platform_has_hart_hotplug(__p) \
#define sbi_platform_has_hart_hotplug(__p) \
((__p)->features & SBI_PLATFORM_HAS_HART_HOTPLUG)
/** Check whether the platform has PMP support */
#define sbi_platform_has_pmp(__p) \
((__p)->features & SBI_PLATFORM_HAS_PMP)
#define sbi_platform_has_pmp(__p) ((__p)->features & SBI_PLATFORM_HAS_PMP)
/** 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)
/** 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)
/** 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)
/**
@@ -140,7 +191,7 @@ struct sbi_platform {
*
* @return pointer to platform name on success and NULL 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)
return plat->name;
@@ -155,7 +206,7 @@ static inline const char *sbi_platform_name(struct sbi_platform *plat)
*
* @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)
{
if (plat && (plat->disabled_hart_mask & (1 << hartid)))
@@ -163,6 +214,22 @@ static inline bool sbi_platform_hart_disabled(struct sbi_platform *plat,
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 && plat->tlb_range_flush_limit)
return plat->tlb_range_flush_limit;
return SBI_PLATFORM_TLB_RANGE_FLUSH_LIMIT_DEFAULT;
}
/**
* Get total number of HARTs supported by the platform
*
@@ -170,7 +237,7 @@ static inline bool sbi_platform_hart_disabled(struct sbi_platform *plat,
*
* @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)
return plat->hart_count;
@@ -184,7 +251,7 @@ static inline u32 sbi_platform_hart_count(struct sbi_platform *plat)
*
* @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)
return plat->hart_stack_size;
@@ -199,11 +266,11 @@ static inline u32 sbi_platform_hart_stack_size(struct sbi_platform *plat)
*
* @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)
{
if (plat && plat->early_init)
return plat->early_init(cold_boot);
if (plat && sbi_platform_ops(plat)->early_init)
return sbi_platform_ops(plat)->early_init(cold_boot);
return 0;
}
@@ -215,11 +282,11 @@ static inline int sbi_platform_early_init(struct sbi_platform *plat,
*
* @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)
{
if (plat && plat->final_init)
return plat->final_init(cold_boot);
if (plat && sbi_platform_ops(plat)->final_init)
return sbi_platform_ops(plat)->final_init(cold_boot);
return 0;
}
@@ -231,11 +298,11 @@ static inline int sbi_platform_final_init(struct sbi_platform *plat,
*
* @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)
{
if (plat && plat->pmp_region_count)
return plat->pmp_region_count(hartid);
if (plat && sbi_platform_ops(plat)->pmp_region_count)
return sbi_platform_ops(plat)->pmp_region_count(hartid);
return 0;
}
@@ -252,14 +319,14 @@ static inline u32 sbi_platform_pmp_region_count(struct sbi_platform *plat,
*
* @return 0 on success and negative error code on failure
*/
static inline int sbi_platform_pmp_region_info(struct sbi_platform *plat,
u32 hartid, u32 index,
ulong *prot, ulong *addr,
ulong *log2size)
static inline int sbi_platform_pmp_region_info(const struct sbi_platform *plat,
u32 hartid, u32 index,
ulong *prot, ulong *addr,
ulong *log2size)
{
if (plat && plat->pmp_region_info)
return plat->pmp_region_info(hartid, index,
prot, addr, log2size);
if (plat && sbi_platform_ops(plat)->pmp_region_info)
return sbi_platform_ops(plat)->pmp_region_info(hartid, index, prot, addr,
log2size);
return 0;
}
@@ -269,11 +336,11 @@ static inline int sbi_platform_pmp_region_info(struct sbi_platform *plat,
* @param plat pointer to struct sbi_platform
* @param ch character to write
*/
static inline void sbi_platform_console_putc(struct sbi_platform *plat,
char ch)
static inline void sbi_platform_console_putc(const struct sbi_platform *plat,
char ch)
{
if (plat && plat->console_putc)
plat->console_putc(ch);
if (plat && sbi_platform_ops(plat)->console_putc)
sbi_platform_ops(plat)->console_putc(ch);
}
/**
@@ -283,11 +350,11 @@ static inline void sbi_platform_console_putc(struct sbi_platform *plat,
*
* @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)
return plat->console_getc();
return 0;
if (plat && sbi_platform_ops(plat)->console_getc)
return sbi_platform_ops(plat)->console_getc();
return -1;
}
/**
@@ -297,10 +364,10 @@ static inline char sbi_platform_console_getc(struct sbi_platform *plat)
*
* @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)
return plat->console_init();
if (plat && sbi_platform_ops(plat)->console_init)
return sbi_platform_ops(plat)->console_init();
return 0;
}
@@ -312,11 +379,11 @@ static inline int sbi_platform_console_init(struct sbi_platform *plat)
*
* @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)
{
if (plat && plat->irqchip_init)
return plat->irqchip_init(cold_boot);
if (plat && sbi_platform_ops(plat)->irqchip_init)
return sbi_platform_ops(plat)->irqchip_init(cold_boot);
return 0;
}
@@ -326,24 +393,11 @@ static inline int sbi_platform_irqchip_init(struct sbi_platform *plat,
* @param plat pointer to struct sbi_platform
* @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)
{
if (plat && plat->ipi_send)
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);
if (plat && sbi_platform_ops(plat)->ipi_send)
sbi_platform_ops(plat)->ipi_send(target_hart);
}
/**
@@ -352,11 +406,11 @@ static inline void sbi_platform_ipi_sync(struct sbi_platform *plat,
* @param plat pointer to struct sbi_platform
* @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)
{
if (plat && plat->ipi_clear)
plat->ipi_clear(target_hart);
if (plat && sbi_platform_ops(plat)->ipi_clear)
sbi_platform_ops(plat)->ipi_clear(target_hart);
}
/**
@@ -367,11 +421,11 @@ static inline void sbi_platform_ipi_clear(struct sbi_platform *plat,
*
* @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)
{
if (plat && plat->ipi_init)
return plat->ipi_init(cold_boot);
if (plat && sbi_platform_ops(plat)->ipi_init)
return sbi_platform_ops(plat)->ipi_init(cold_boot);
return 0;
}
@@ -380,12 +434,12 @@ static inline int sbi_platform_ipi_init(struct sbi_platform *plat,
*
* @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)
return plat->timer_value();
if (plat && sbi_platform_ops(plat)->timer_value)
return sbi_platform_ops(plat)->timer_value();
return 0;
}
@@ -395,11 +449,11 @@ static inline u64 sbi_platform_timer_value(struct sbi_platform *plat)
* @param plat pointer to struct struct sbi_platform
* @param next_event timer value when timer event will happen
*/
static inline void sbi_platform_timer_event_start(struct sbi_platform *plat,
u64 next_event)
static inline void
sbi_platform_timer_event_start(const struct sbi_platform *plat, u64 next_event)
{
if (plat && plat->timer_event_start)
plat->timer_event_start(next_event);
if (plat && sbi_platform_ops(plat)->timer_event_start)
sbi_platform_ops(plat)->timer_event_start(next_event);
}
/**
@@ -407,10 +461,11 @@ static inline void sbi_platform_timer_event_start(struct sbi_platform *plat,
*
* @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)
plat->timer_event_stop();
if (plat && sbi_platform_ops(plat)->timer_event_stop)
sbi_platform_ops(plat)->timer_event_stop();
}
/**
@@ -421,11 +476,11 @@ static inline void sbi_platform_timer_event_stop(struct sbi_platform *plat)
*
* @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)
{
if (plat && plat->timer_init)
return plat->timer_init(cold_boot);
if (plat && sbi_platform_ops(plat)->timer_init)
return sbi_platform_ops(plat)->timer_init(cold_boot);
return 0;
}
@@ -437,11 +492,11 @@ static inline int sbi_platform_timer_init(struct sbi_platform *plat,
*
* @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)
{
if (plat && plat->system_reboot)
return plat->system_reboot(type);
if (plat && sbi_platform_ops(plat)->system_reboot)
return sbi_platform_ops(plat)->system_reboot(type);
return 0;
}
@@ -453,14 +508,62 @@ static inline int sbi_platform_system_reboot(struct sbi_platform *plat,
*
* @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)
{
if (plat && plat->system_shutdown)
return plat->system_shutdown(type);
if (plat && sbi_platform_ops(plat)->system_shutdown)
return sbi_platform_ops(plat)->system_shutdown(type);
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 the callee
* @param out_tcause trap cause that can be filled the callee
* @param out_tvalue possible trap value that can be filled the callee
*
* @return 0 on success and negative error code on failure
*/
static inline int sbi_platform_vendor_ext_provider(const struct sbi_platform *plat,
long extid, long funcid,
unsigned long *args,
unsigned long *out_value,
unsigned long *out_tcause,
unsigned long *out_tval)
{
if (plat && sbi_platform_ops(plat)->vendor_ext_provider) {
return sbi_platform_ops(plat)->vendor_ext_provider(extid,
funcid, args,
out_value,
out_tcause,
out_tval);
}
return SBI_ENOTSUPP;
}
#endif
#endif

View File

@@ -12,6 +12,8 @@
#include <sbi/riscv_asm.h>
/* clang-format off */
/** Offset of fw_start member in sbi_scratch */
#define SBI_SCRATCH_FW_START_OFFSET (0 * __SIZEOF_POINTER__)
/** Offset of fw_size member in sbi_scratch */
@@ -28,14 +30,21 @@
#define SBI_SCRATCH_PLATFORM_ADDR_OFFSET (6 * __SIZEOF_POINTER__)
/** Offset of hartid_to_scratch member in sbi_scratch */
#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__)
/** Maximum size of sbi_scratch */
#define SBI_SCRATCH_SIZE 256
/** Offset of tmp0 member in sbi_scratch */
#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 and sbi_ipi_data */
#define SBI_SCRATCH_SIZE (64 * __SIZEOF_POINTER__)
/* clang-format on */
#ifndef __ASSEMBLY__
#include <sbi/sbi_types.h>
#include <sbi/sbi_ipi.h>
/** Representation of per-HART scratch space */
struct sbi_scratch {
@@ -55,17 +64,44 @@ struct sbi_scratch {
unsigned long platform_addr;
/** Address of HART ID to sbi_scratch conversion function */
unsigned long hartid_to_scratch;
/** IPI type (or flags) */
unsigned long ipi_type;
/** Temporary storage */
unsigned long tmp0;
/** Options for OpenSBI library */
unsigned long options;
} __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 */
#define sbi_scratch_thishart_ptr() \
((struct sbi_scratch *)csr_read(mscratch))
#define sbi_scratch_thishart_ptr() \
((struct sbi_scratch *)csr_read(CSR_MSCRATCH))
/** Get Arg1 of next booting stage for current HART */
#define sbi_scratch_thishart_arg1_ptr() \
((void *)(sbi_scratch_thishart_ptr()->next_arg1))
#define sbi_scratch_thishart_arg1_ptr() \
((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

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

View File

@@ -16,6 +16,14 @@ struct sbi_scratch;
u64 sbi_timer_value(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_stop(struct sbi_scratch *scratch);
void sbi_timer_event_start(struct sbi_scratch *scratch, u64 next_event);

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_VMA_VMID,
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_fifo_update(struct sbi_scratch *scratch, u32 hartid, void *data);
void sbi_tlb_fifo_process(struct sbi_scratch *scratch);
int sbi_tlb_fifo_init(struct sbi_scratch *scratch, bool cold_boot);
void sbi_tlb_fifo_sync(struct sbi_scratch *scratch);
#endif

View File

@@ -10,6 +10,8 @@
#ifndef __SBI_TRAP_H__
#define __SBI_TRAP_H__
/* clang-format off */
/** Index of zero member in sbi_trap_regs */
#define SBI_TRAP_REGS_zero 0
/** Index of ra member in sbi_trap_regs */
@@ -78,14 +80,17 @@
#define SBI_TRAP_REGS_mepc 32
/** Index of mstatus member in sbi_trap_regs */
#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 */
#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 */
#define SBI_TRAP_REGS_OFFSET(x) \
((SBI_TRAP_REGS_##x) * __SIZEOF_POINTER__)
#define SBI_TRAP_REGS_OFFSET(x) ((SBI_TRAP_REGS_##x) * __SIZEOF_POINTER__)
/** 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__
@@ -161,16 +166,16 @@ struct sbi_trap_regs {
unsigned long mepc;
/** mstatus register state */
unsigned long mstatus;
/** mstatusH register state (only for 32-bit) */
unsigned long mstatusH;
} __packed;
struct sbi_scratch;
int sbi_trap_redirect(struct sbi_trap_regs *regs,
struct sbi_scratch *scratch,
int sbi_trap_redirect(struct sbi_trap_regs *regs, struct sbi_scratch *scratch,
ulong epc, ulong cause, ulong tval);
void sbi_trap_handler(struct sbi_trap_regs *regs,
struct sbi_scratch *scratch);
void sbi_trap_handler(struct sbi_trap_regs *regs, struct sbi_scratch *scratch);
#endif

View File

@@ -10,6 +10,8 @@
#ifndef __SBI_TYPES_H__
#define __SBI_TYPES_H__
/* clang-format off */
typedef char s8;
typedef unsigned char u8;
typedef unsigned char uint8_t;
@@ -29,11 +31,13 @@ typedef long s64;
typedef unsigned long u64;
typedef long int64_t;
typedef unsigned long uint64_t;
#define PRILX "016lx"
#elif __riscv_xlen == 32
typedef long long s64;
typedef unsigned long long u64;
typedef long long int64_t;
typedef unsigned long long uint64_t;
#define PRILX "08lx"
#else
#error "Unexpected __riscv_xlen"
#endif
@@ -56,4 +60,6 @@ typedef unsigned long physical_size_t;
#define __packed __attribute__((packed))
#define __noreturn __attribute__((noreturn))
/* clang-format on */
#endif

View File

@@ -1,111 +0,0 @@
/*
* SPDX-License-Identifier: BSD-2-Clause
*
* Copyright (c) 2019 Western Digital Corporation or its affiliates.
*
* Authors:
* Anup Patel <anup.patel@wdc.com>
*/
#ifndef __SBI_UNPRIV_H__
#define __SBI_UNPRIV_H__
#include <sbi/riscv_encoding.h>
#include <sbi/sbi_bits.h>
#include <sbi/sbi_types.h>
#define DECLARE_UNPRIVILEGED_LOAD_FUNCTION(type, insn) \
static inline type load_##type(const type *addr, ulong mepc) \
{ \
register ulong __mepc asm ("a2") = mepc; \
register ulong __mstatus asm ("a3"); \
type val; \
asm ("csrrs %0, mstatus, %3\n" \
#insn " %1, %2\n" \
"csrw mstatus, %0" \
: "+&r" (__mstatus), "=&r" (val) \
: "m" (*addr), "r" (MSTATUS_MPRV), "r" (__mepc)); \
return val; \
}
#define DECLARE_UNPRIVILEGED_STORE_FUNCTION(type, insn) \
static inline void store_##type(type *addr, type val, ulong mepc) \
{ \
register ulong __mepc asm ("a2") = mepc; \
register ulong __mstatus asm ("a3"); \
asm volatile ("csrrs %0, mstatus, %3\n" \
#insn " %1, %2\n" \
"csrw mstatus, %0" \
: "+&r" (__mstatus) \
: "r" (val), "m" (*addr), "r" (MSTATUS_MPRV), "r" (__mepc)); \
}
DECLARE_UNPRIVILEGED_LOAD_FUNCTION(u8, lbu)
DECLARE_UNPRIVILEGED_LOAD_FUNCTION(u16, lhu)
DECLARE_UNPRIVILEGED_LOAD_FUNCTION(s8, lb)
DECLARE_UNPRIVILEGED_LOAD_FUNCTION(s16, lh)
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)
{
return load_u32((u32 *)addr, mepc)
+ ((u64)load_u32((u32 *)addr + 1, mepc) << 32);
}
static inline void store_u64(u64 *addr, u64 val, ulong mepc)
{
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], mstatus, %[mprv]\n"
STR(LWU) " %[insn], (%[addr])\n"
"csrw 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], mstatus, %[mprv]\n"
"and %[tmp], %[addr], 2\n"
"bnez %[tmp], 1f\n"
STR(LWU) " %[insn], (%[addr])\n"
"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 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

View File

@@ -10,7 +10,15 @@
#ifndef __SBI_VERSION_H__
#define __SBI_VERSION_H__
#define OPENSBI_VERSION_MAJOR 0
#define OPENSBI_VERSION_MINOR 1
#define OPENSBI_VERSION_MAJOR 0
#define OPENSBI_VERSION_MINOR 5
/**
* 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

View File

@@ -14,10 +14,12 @@
void plic_fdt_fixup(void *fdt, const char *compat);
int plic_warm_irqchip_init(u32 target_hart,
int m_cntx_id, int s_cntx_id);
int plic_warm_irqchip_init(u32 target_hart, int m_cntx_id, int s_cntx_id);
int plic_cold_irqchip_init(unsigned long base,
u32 num_sources, u32 hart_count);
int plic_cold_irqchip_init(unsigned long base, 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

View File

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

View File

@@ -14,10 +14,9 @@
void uart8250_putc(char ch);
char uart8250_getc(void);
int uart8250_getc(void);
int uart8250_init(unsigned long base,
u32 in_freq, u32 baudrate,
u32 reg_shift, u32 reg_width);
int uart8250_init(unsigned long base, u32 in_freq, u32 baudrate, u32 reg_shift,
u32 reg_width);
#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);
}

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

@@ -0,0 +1,30 @@
#
# 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 += riscv_unpriv.o
libsbi-objs-y += sbi_console.o
libsbi-objs-y += sbi_ecall.o
libsbi-objs-y += sbi_emulate_csr.o
libsbi-objs-y += sbi_fifo.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

View File

@@ -163,28 +163,26 @@ static unsigned long ctz(unsigned long x)
return ret;
}
int pmp_set(unsigned int n, unsigned long prot,
unsigned long addr, unsigned long log2len)
int pmp_set(unsigned int n, unsigned long prot, unsigned long addr,
unsigned long log2len)
{
int pmpcfg_csr, pmpcfg_shift, pmpaddr_csr;
unsigned long cfgmask, pmpcfg;
unsigned long addrmask, pmpaddr;
/* check parameters */
if (n >= PMP_COUNT ||
log2len > __riscv_xlen ||
log2len < PMP_SHIFT)
if (n >= PMP_COUNT || log2len > __riscv_xlen || log2len < PMP_SHIFT)
return SBI_EINVAL;
/* calculate PMP register and offset */
/* calculate PMP register and offset */
#if __riscv_xlen == 32
pmpcfg_csr = CSR_PMPCFG0 + (n >> 2);
pmpcfg_csr = CSR_PMPCFG0 + (n >> 2);
pmpcfg_shift = (n & 3) << 3;
#elif __riscv_xlen == 64
pmpcfg_csr = (CSR_PMPCFG0 + (n >> 2)) & ~1;
pmpcfg_csr = (CSR_PMPCFG0 + (n >> 2)) & ~1;
pmpcfg_shift = (n & 7) << 3;
#else
pmpcfg_csr = -1;
pmpcfg_csr = -1;
pmpcfg_shift = -1;
#endif
pmpaddr_csr = CSR_PMPADDR0 + n;
@@ -194,7 +192,7 @@ int pmp_set(unsigned int n, unsigned long prot,
/* encode PMP config */
prot |= (log2len == PMP_SHIFT) ? PMP_A_NA4 : PMP_A_NAPOT;
cfgmask = ~(0xff << pmpcfg_shift);
pmpcfg = (csr_read_num(pmpcfg_csr) & cfgmask);
pmpcfg = (csr_read_num(pmpcfg_csr) & cfgmask);
pmpcfg |= ((prot << pmpcfg_shift) & ~cfgmask);
/* encode PMP address */
@@ -205,7 +203,7 @@ int pmp_set(unsigned int n, unsigned long prot,
pmpaddr = -1UL;
} else {
addrmask = (1UL << (log2len - PMP_SHIFT)) - 1;
pmpaddr = ((addr >> PMP_SHIFT) & ~addrmask);
pmpaddr = ((addr >> PMP_SHIFT) & ~addrmask);
pmpaddr |= (addrmask >> 1);
}
}
@@ -217,28 +215,27 @@ int pmp_set(unsigned int n, unsigned long prot,
return 0;
}
int pmp_get(unsigned int n, unsigned long *prot_out,
unsigned long *addr_out, unsigned long *log2len_out)
int pmp_get(unsigned int n, unsigned long *prot_out, unsigned long *addr_out,
unsigned long *log2len_out)
{
int pmpcfg_csr, pmpcfg_shift, pmpaddr_csr;
unsigned long cfgmask, pmpcfg, prot;
unsigned long t1, addr, log2len;
/* check parameters */
if (n >= PMP_COUNT || !prot_out ||
!addr_out || !log2len_out)
if (n >= PMP_COUNT || !prot_out || !addr_out || !log2len_out)
return SBI_EINVAL;
*prot_out = *addr_out = *log2len_out = 0;
/* calculate PMP register and offset */
#if __riscv_xlen == 32
pmpcfg_csr = CSR_PMPCFG0 + (n >> 2);
pmpcfg_csr = CSR_PMPCFG0 + (n >> 2);
pmpcfg_shift = (n & 3) << 3;
#elif __riscv_xlen == 64
pmpcfg_csr = (CSR_PMPCFG0 + (n >> 2)) & ~1;
pmpcfg_csr = (CSR_PMPCFG0 + (n >> 2)) & ~1;
pmpcfg_shift = (n & 7) << 3;
#else
pmpcfg_csr = -1;
pmpcfg_csr = -1;
pmpcfg_shift = -1;
#endif
pmpaddr_csr = CSR_PMPADDR0 + n;
@@ -247,28 +244,28 @@ int pmp_get(unsigned int n, unsigned long *prot_out,
/* decode PMP config */
cfgmask = (0xff << pmpcfg_shift);
pmpcfg = csr_read_num(pmpcfg_csr) & cfgmask;
prot = pmpcfg >> pmpcfg_shift;
pmpcfg = csr_read_num(pmpcfg_csr) & cfgmask;
prot = pmpcfg >> pmpcfg_shift;
/* decode PMP address */
if ((prot & PMP_A) == PMP_A_NAPOT) {
addr = csr_read_num(pmpaddr_csr);
if (addr == -1UL) {
addr = 0;
addr = 0;
log2len = __riscv_xlen;
} else {
t1 = ctz(~addr);
addr = (addr & ~((1UL << t1) - 1)) << PMP_SHIFT;
t1 = ctz(~addr);
addr = (addr & ~((1UL << t1) - 1)) << PMP_SHIFT;
log2len = (t1 + PMP_SHIFT + 1);
}
} else {
addr = csr_read_num(pmpaddr_csr) << PMP_SHIFT;
addr = csr_read_num(pmpaddr_csr) << PMP_SHIFT;
log2len = PMP_SHIFT;
}
/* return details */
*prot_out = prot;
*addr_out = addr;
*prot_out = prot;
*addr_out = addr;
*log2len_out = log2len;
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))) __xchg((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;
__asm__ __volatile__ (
" amoswap.w %0, %2, %1\n"
RISCV_ACQUIRE_BARRIER
: "=r" (busy), "+A" (lock->lock)
: "r" (tmp)
__asm__ __volatile__(
" amoswap.w %0, %2, %1\n" RISCV_ACQUIRE_BARRIER
: "=r"(busy), "+A"(lock->lock)
: "r"(tmp)
: "memory");
return !busy;

158
lib/sbi/riscv_unpriv.c Normal file
View File

@@ -0,0 +1,158 @@
/*
* SPDX-License-Identifier: BSD-2-Clause
*
* Copyright (c) 2019 Western Digital Corporation or its affiliates.
*
* Authors:
* Anup Patel <anup.patel@wdc.com>
*/
#include <sbi/riscv_encoding.h>
#include <sbi/riscv_unpriv.h>
#include <sbi/sbi_bits.h>
#include <sbi/sbi_hart.h>
#include <sbi/sbi_scratch.h>
#define DEFINE_UNPRIVILEGED_LOAD_FUNCTION(type, insn, insnlen) \
type load_##type(const type *addr, \
struct sbi_scratch *scratch, \
struct unpriv_trap *trap) \
{ \
register ulong __mstatus asm("a2"); \
type val = 0; \
trap->ilen = insnlen; \
trap->cause = 0; \
trap->tval = 0; \
sbi_hart_set_trap_info(scratch, trap); \
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)); \
sbi_hart_set_trap_info(scratch, NULL); \
return val; \
}
#define DEFINE_UNPRIVILEGED_STORE_FUNCTION(type, insn, insnlen) \
void store_##type(type *addr, type val, \
struct sbi_scratch *scratch, \
struct unpriv_trap *trap) \
{ \
register ulong __mstatus asm("a3"); \
trap->ilen = insnlen; \
trap->cause = 0; \
trap->tval = 0; \
sbi_hart_set_trap_info(scratch, trap); \
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)); \
sbi_hart_set_trap_info(scratch, NULL); \
}
DEFINE_UNPRIVILEGED_LOAD_FUNCTION(u8, lbu, 4)
DEFINE_UNPRIVILEGED_LOAD_FUNCTION(u16, lhu, 4)
DEFINE_UNPRIVILEGED_LOAD_FUNCTION(s8, lb, 4)
DEFINE_UNPRIVILEGED_LOAD_FUNCTION(s16, lh, 4)
DEFINE_UNPRIVILEGED_LOAD_FUNCTION(s32, lw, 2)
DEFINE_UNPRIVILEGED_STORE_FUNCTION(u8, sb, 4)
DEFINE_UNPRIVILEGED_STORE_FUNCTION(u16, sh, 4)
DEFINE_UNPRIVILEGED_STORE_FUNCTION(u32, sw, 2)
#if __riscv_xlen == 64
DEFINE_UNPRIVILEGED_LOAD_FUNCTION(u32, lwu, 4)
DEFINE_UNPRIVILEGED_LOAD_FUNCTION(u64, ld, 2)
DEFINE_UNPRIVILEGED_STORE_FUNCTION(u64, sd, 2)
DEFINE_UNPRIVILEGED_LOAD_FUNCTION(ulong, ld, 2)
#else
DEFINE_UNPRIVILEGED_LOAD_FUNCTION(u32, lw, 2)
DEFINE_UNPRIVILEGED_LOAD_FUNCTION(ulong, lw, 2)
u64 load_u64(const u64 *addr,
struct sbi_scratch *scratch, struct unpriv_trap *trap)
{
u64 ret = load_u32((u32 *)addr, scratch, trap);
if (trap->cause)
return 0;
ret |= ((u64)load_u32((u32 *)addr + 1, scratch, trap) << 32);
if (trap->cause)
return 0;
return ret;
}
void store_u64(u64 *addr, u64 val,
struct sbi_scratch *scratch, struct unpriv_trap *trap)
{
store_u32((u32 *)addr, val, scratch, trap);
if (trap->cause)
return;
store_u32((u32 *)addr + 1, val >> 32, scratch, trap);
if (trap->cause)
return;
}
#endif
ulong get_insn(ulong mepc, bool virt, struct sbi_scratch *scratch,
struct unpriv_trap *trap)
{
ulong __mstatus = 0, __vsstatus = 0, val = 0;
#ifdef __riscv_compressed
ulong rvc_mask = 3, tmp;
#endif
trap->ilen = 4;
trap->cause = 0;
trap->tval = 0;
sbi_hart_set_trap_info(scratch, trap);
if (virt)
__vsstatus = csr_read_set(CSR_VSSTATUS, SSTATUS_MXR);
#ifndef __riscv_compressed
asm("csrrs %[mstatus], " STR(CSR_MSTATUS) ", %[mprv]\n"
#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
asm("csrrs %[mstatus], " STR(CSR_MSTATUS) ", %[mprv]\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));
#endif
if (virt)
csr_write(CSR_VSSTATUS, __vsstatus);
sbi_hart_set_trap_info(scratch, NULL);
switch (trap->cause) {
case CAUSE_LOAD_ACCESS:
trap->cause = CAUSE_FETCH_ACCESS;
trap->tval = mepc;
break;
case CAUSE_LOAD_PAGE_FAULT:
trap->cause = CAUSE_FETCH_PAGE_FAULT;
trap->tval = mepc;
break;
default:
break;
};
return val;
}

View File

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

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

@@ -0,0 +1,242 @@
/*
* 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_console.h>
#include <sbi/sbi_ecall.h>
#include <sbi/sbi_ecall_interface.h>
#include <sbi/sbi_error.h>
#include <sbi/sbi_ipi.h>
#include <sbi/sbi_platform.h>
#include <sbi/sbi_system.h>
#include <sbi/sbi_timer.h>
#include <sbi/sbi_tlb.h>
#include <sbi/sbi_trap.h>
#include <sbi/sbi_hart.h>
#include <sbi/sbi_version.h>
#include <sbi/riscv_asm.h>
#define SBI_ECALL_VERSION_MAJOR 0
#define SBI_ECALL_VERSION_MINOR 2
#define SBI_OPENSBI_IMPID 1
u16 sbi_ecall_version_major(void)
{
return SBI_ECALL_VERSION_MAJOR;
}
u16 sbi_ecall_version_minor(void)
{
return SBI_ECALL_VERSION_MINOR;
}
int sbi_check_extension(struct sbi_scratch *scratch, unsigned long extid,
unsigned long *out_val)
{
/**
* Each extension apart from base & 0.1, will be implemented as
* platform specific feature. Thus, extension probing can be achieved
* by checking the feature bits of the platform. We can create a map
* between extension ID & feature and use a generic function to check
* or just use a switch case for every new extension support added
* TODO: Implement it.
*/
if ((extid >= SBI_EXT_0_1_SET_TIMER &&
extid <= SBI_EXT_0_1_SHUTDOWN) || (extid == SBI_EXT_BASE)) {
*out_val = 1;
} else if (extid >= SBI_EXT_VENDOR_START &&
extid <= SBI_EXT_VENDOR_END) {
*out_val = sbi_platform_vendor_ext_check(
sbi_platform_ptr(scratch),
extid);
} else
*out_val = 0;
return 0;
}
int sbi_ecall_vendor_ext_handler(struct sbi_scratch *scratch,
unsigned long extid, unsigned long funcid,
unsigned long *args, unsigned long *out_val,
unsigned long *out_tcause,
unsigned long *out_tval)
{
return sbi_platform_vendor_ext_provider(sbi_platform_ptr(scratch),
extid, funcid, args, out_val,
out_tcause, out_tval);
}
int sbi_ecall_base_handler(struct sbi_scratch *scratch, unsigned long extid,
unsigned long funcid, unsigned long *args,
unsigned long *out_val, unsigned long *out_tcause,
unsigned long *out_tval)
{
int ret = 0;
switch (funcid) {
case SBI_EXT_BASE_GET_SPEC_VERSION:
*out_val = (SBI_ECALL_VERSION_MAJOR <<
SBI_SPEC_VERSION_MAJOR_OFFSET) &
(SBI_SPEC_VERSION_MAJOR_MASK <<
SBI_SPEC_VERSION_MAJOR_OFFSET);
*out_val = *out_val | SBI_ECALL_VERSION_MINOR;
break;
case SBI_EXT_BASE_GET_IMP_ID:
*out_val = SBI_OPENSBI_IMPID;
break;
case SBI_EXT_BASE_GET_IMP_VERSION:
*out_val = OPENSBI_VERSION;
break;
case SBI_EXT_BASE_GET_MVENDORID:
*out_val = csr_read(CSR_MVENDORID);
break;
case SBI_EXT_BASE_GET_MARCHID:
*out_val = csr_read(CSR_MARCHID);
break;
case SBI_EXT_BASE_GET_MIMPID:
*out_val = csr_read(CSR_MIMPID);
break;
case SBI_EXT_BASE_PROBE_EXT:
ret = sbi_check_extension(scratch, args[0], out_val);
default:
ret = SBI_ENOTSUPP;
}
return ret;
}
int sbi_ecall_0_1_handler(struct sbi_scratch *scratch, unsigned long extid,
unsigned long *args, unsigned long *tval,
unsigned long *tcause)
{
int ret = 0;
struct sbi_tlb_info tlb_info;
u32 source_hart = sbi_current_hartid();
struct unpriv_trap uptrap = {0};
switch (extid) {
case SBI_EXT_0_1_SET_TIMER:
#if __riscv_xlen == 32
sbi_timer_event_start(scratch,
(((u64)args[1] << 32) | (u64)args[0]));
#else
sbi_timer_event_start(scratch, (u64)args[0]);
#endif
break;
case SBI_EXT_0_1_CONSOLE_PUTCHAR:
sbi_putc(args[0]);
break;
case SBI_EXT_0_1_CONSOLE_GETCHAR:
ret = sbi_getc();
break;
case SBI_EXT_0_1_CLEAR_IPI:
sbi_ipi_clear_smode(scratch);
break;
case SBI_EXT_0_1_SEND_IPI:
ret = sbi_ipi_send_many(scratch, &uptrap, (ulong *)args[0],
SBI_IPI_EVENT_SOFT, NULL);
break;
case SBI_EXT_0_1_REMOTE_FENCE_I:
tlb_info.start = 0;
tlb_info.size = 0;
tlb_info.type = SBI_ITLB_FLUSH;
tlb_info.shart_mask = 1UL << source_hart;
ret = sbi_ipi_send_many(scratch, &uptrap, (ulong *)args[0],
SBI_IPI_EVENT_FENCE_I, &tlb_info);
break;
case SBI_EXT_0_1_REMOTE_SFENCE_VMA:
tlb_info.start = (unsigned long)args[1];
tlb_info.size = (unsigned long)args[2];
tlb_info.type = SBI_TLB_FLUSH_VMA;
tlb_info.shart_mask = 1UL << source_hart;
ret = sbi_ipi_send_many(scratch, &uptrap, (ulong *)args[0],
SBI_IPI_EVENT_SFENCE_VMA, &tlb_info);
break;
case SBI_EXT_0_1_REMOTE_SFENCE_VMA_ASID:
tlb_info.start = (unsigned long)args[1];
tlb_info.size = (unsigned long)args[2];
tlb_info.asid = (unsigned long)args[3];
tlb_info.type = SBI_TLB_FLUSH_VMA_ASID;
tlb_info.shart_mask = 1UL << source_hart;
ret = sbi_ipi_send_many(scratch, &uptrap, (ulong *)args[0],
SBI_IPI_EVENT_SFENCE_VMA_ASID,
&tlb_info);
break;
case SBI_EXT_0_1_SHUTDOWN:
sbi_system_shutdown(scratch, 0);
break;
default:
ret = SBI_ENOTSUPP;
};
if (ret == SBI_ETRAP) {
*tcause = uptrap.cause;
*tval = uptrap.tval;
}
return ret;
}
int sbi_ecall_handler(u32 hartid, ulong mcause, struct sbi_trap_regs *regs,
struct sbi_scratch *scratch)
{
int ret = 0;
unsigned long extension_id = regs->a7;
unsigned long func_id = regs->a6;
unsigned long out_val;
unsigned long out_tval;
unsigned long out_tcause;
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;
if (extension_id >= SBI_EXT_0_1_SET_TIMER &&
extension_id <= SBI_EXT_0_1_SHUTDOWN) {
ret = sbi_ecall_0_1_handler(scratch, extension_id, args,
&out_tval, &out_tcause);
is_0_1_spec = 1;
} else if (extension_id == SBI_EXT_BASE)
ret = sbi_ecall_base_handler(scratch, extension_id, func_id,
args, &out_val,
&out_tval, &out_tcause);
else if (extension_id >= SBI_EXT_VENDOR_START &&
extension_id <= SBI_EXT_VENDOR_END) {
ret = sbi_ecall_vendor_ext_handler(scratch, extension_id,
func_id, args, &out_val,
&out_tval, &out_tcause);
} else {
ret = SBI_ENOTSUPP;
}
if (ret == SBI_ETRAP) {
sbi_trap_redirect(regs, scratch, regs->mepc,
out_tcause, out_tval);
} 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;
}

185
lib/sbi/sbi_emulate_csr.c Normal file
View File

@@ -0,0 +1,185 @@
/*
* 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_encoding.h>
#include <sbi/sbi_bits.h>
#include <sbi/sbi_console.h>
#include <sbi/sbi_emulate_csr.h>
#include <sbi/sbi_error.h>
#include <sbi/sbi_timer.h>
#include <sbi/sbi_trap.h>
int sbi_emulate_csr_read(int csr_num, u32 hartid, struct sbi_trap_regs *regs,
struct sbi_scratch *scratch, ulong *csr_val)
{
int ret = 0;
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 (prev_mode == PRV_U)
cen = csr_read(CSR_SCOUNTEREN);
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:
if (!((cen >> (CSR_CYCLE - CSR_CYCLE)) & 1))
return -1;
*csr_val = csr_read(CSR_MCYCLE);
break;
case CSR_TIME:
if (!((cen >> (CSR_TIME - CSR_CYCLE)) & 1))
return -1;
*csr_val = (virt) ? sbi_timer_virt_value(scratch):
sbi_timer_value(scratch);
break;
case CSR_INSTRET:
if (!((cen >> (CSR_INSTRET - CSR_CYCLE)) & 1))
return -1;
*csr_val = csr_read(CSR_MINSTRET);
break;
case CSR_MHPMCOUNTER3:
if (!((cen >> (3 + CSR_MHPMCOUNTER3 - CSR_MHPMCOUNTER3)) & 1))
return -1;
*csr_val = csr_read(CSR_MHPMCOUNTER3);
break;
case CSR_MHPMCOUNTER4:
if (!((cen >> (3 + CSR_MHPMCOUNTER4 - CSR_MHPMCOUNTER3)) & 1))
return -1;
*csr_val = csr_read(CSR_MHPMCOUNTER4);
break;
#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:
if (!((cen >> (CSR_CYCLE - CSR_CYCLE)) & 1))
return -1;
*csr_val = csr_read(CSR_MCYCLEH);
break;
case CSR_TIMEH:
if (!((cen >> (CSR_TIME - CSR_CYCLE)) & 1))
return -1;
*csr_val = (virt) ? sbi_timer_virt_value(scratch) >> 32:
sbi_timer_value(scratch) >> 32;
break;
case CSR_INSTRETH:
if (!((cen >> (CSR_INSTRET - CSR_CYCLE)) & 1))
return -1;
*csr_val = csr_read(CSR_MINSTRETH);
break;
case CSR_MHPMCOUNTER3H:
if (!((cen >> (3 + CSR_MHPMCOUNTER3 - CSR_MHPMCOUNTER3)) & 1))
return -1;
*csr_val = csr_read(CSR_MHPMCOUNTER3H);
break;
case CSR_MHPMCOUNTER4H:
if (!((cen >> (3 + CSR_MHPMCOUNTER4 - CSR_MHPMCOUNTER3)) & 1))
return -1;
*csr_val = csr_read(CSR_MHPMCOUNTER4H);
break;
#endif
case CSR_MHPMEVENT3:
*csr_val = csr_read(CSR_MHPMEVENT3);
break;
case CSR_MHPMEVENT4:
*csr_val = csr_read(CSR_MHPMEVENT4);
break;
default:
ret = SBI_ENOTSUPP;
break;
};
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, u32 hartid, struct sbi_trap_regs *regs,
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) {
case CSR_HTIMEDELTA:
if (prev_mode == PRV_S && !virt)
sbi_timer_set_delta(scratch, csr_val);
else
ret = SBI_ENOTSUPP;
break;
case CSR_CYCLE:
csr_write(CSR_MCYCLE, csr_val);
break;
case CSR_INSTRET:
csr_write(CSR_MINSTRET, csr_val);
break;
case CSR_MHPMCOUNTER3:
csr_write(CSR_MHPMCOUNTER3, csr_val);
break;
case CSR_MHPMCOUNTER4:
csr_write(CSR_MHPMCOUNTER4, csr_val);
break;
#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:
csr_write(CSR_MCYCLEH, csr_val);
break;
case CSR_INSTRETH:
csr_write(CSR_MINSTRETH, csr_val);
break;
case CSR_MHPMCOUNTER3H:
csr_write(CSR_MHPMCOUNTER3H, csr_val);
break;
case CSR_MHPMCOUNTER4H:
csr_write(CSR_MHPMCOUNTER4H, csr_val);
break;
#endif
case CSR_MHPMEVENT3:
csr_write(CSR_MHPMEVENT3, csr_val);
break;
case CSR_MHPMEVENT4:
csr_write(CSR_MHPMEVENT4, csr_val);
break;
default:
ret = SBI_ENOTSUPP;
break;
};
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

@@ -23,55 +23,47 @@
*/
unsigned int sbi_current_hartid()
{
return (u32)csr_read(mhartid);
return (u32)csr_read(CSR_MHARTID);
}
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 */
if (misa_extension('D') || misa_extension('F'))
csr_write(mstatus, MSTATUS_FS);
csr_write(CSR_MSTATUS, MSTATUS_FS);
/* Enable user/supervisor use of perf counters */
if (misa_extension('S') &&
sbi_platform_has_scounteren(plat))
csr_write(scounteren, -1);
if (misa_extension('S') && sbi_platform_has_scounteren(plat))
csr_write(CSR_SCOUNTEREN, -1);
if (sbi_platform_has_mcounteren(plat))
csr_write(mcounteren, -1);
csr_write(CSR_MCOUNTEREN, -1);
/* Disable all interrupts */
csr_write(mie, 0);
csr_write(CSR_MIE, 0);
/* Disable S-mode paging */
if (misa_extension('S'))
csr_write(sptbr, 0);
csr_write(CSR_SATP, 0);
}
static int fp_init(u32 hartid)
{
#ifdef __riscv_flen
int i;
#else
unsigned long fd_mask;
#endif
if (!misa_extension('D') && !misa_extension('F'))
return 0;
if (!(csr_read(mstatus) & MSTATUS_FS))
if (!(csr_read(CSR_MSTATUS) & MSTATUS_FS))
return SBI_EINVAL;
#ifdef __riscv_flen
for (i = 0; i < 32; i++)
init_fp_reg(i);
csr_write(fcsr, 0);
#else
fd_mask = (1 << ('F' - 'A')) | (1 << ('D' - 'A'));
csr_clear(misa, fd_mask);
if (csr_read(misa) & fd_mask)
return SBI_ENOTSUPP;
csr_write(CSR_FCSR, 0);
#endif
return 0;
@@ -79,7 +71,7 @@ static int fp_init(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;
if (!misa_extension('S'))
@@ -88,20 +80,27 @@ static int delegate_traps(struct sbi_scratch *scratch, u32 hartid)
/* Send M-mode interrupts and most exceptions to S-mode */
interrupts = MIP_SSIP | MIP_STIP | MIP_SEIP;
exceptions = (1U << CAUSE_MISALIGNED_FETCH) |
(1U << CAUSE_BREAKPOINT) |
exceptions = (1U << CAUSE_MISALIGNED_FETCH) | (1U << CAUSE_BREAKPOINT) |
(1U << CAUSE_USER_ECALL);
if (sbi_platform_has_mfaults_delegation(plat))
exceptions |= (1U << CAUSE_FETCH_PAGE_FAULT) |
(1U << CAUSE_LOAD_PAGE_FAULT) |
(1U << CAUSE_STORE_PAGE_FAULT);
csr_write(mideleg, interrupts);
csr_write(medeleg, exceptions);
/*
* If hypervisor extension available then we only handle
* hypervisor calls (i.e. ecalls from HS-mode) and we let
* HS-mode handle supervisor calls (i.e. ecalls from VS-mode)
*/
if (misa_extension('H'))
exceptions |= (1U << CAUSE_SUPERVISOR_ECALL);
if (csr_read(mideleg) != interrupts)
csr_write(CSR_MIDELEG, interrupts);
csr_write(CSR_MEDELEG, exceptions);
if (csr_read(CSR_MIDELEG) != interrupts)
return SBI_EFAIL;
if (csr_read(medeleg) != exceptions)
if (csr_read(CSR_MEDELEG) != exceptions)
return SBI_EFAIL;
return 0;
@@ -122,7 +121,7 @@ unsigned long log2roundup(unsigned long x)
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 int i;
@@ -160,13 +159,13 @@ static int pmp_init(struct sbi_scratch *scratch, u32 hartid)
u32 i, count;
unsigned long fw_start, fw_size_log2;
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))
return 0;
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);
@@ -175,8 +174,8 @@ static int pmp_init(struct sbi_scratch *scratch, u32 hartid)
count = (PMP_COUNT - 1);
for (i = 0; i < count; i++) {
if (sbi_platform_pmp_region_info(plat, hartid, i,
&prot, &addr, &log2size))
if (sbi_platform_pmp_region_info(plat, hartid, i, &prot, &addr,
&log2size))
continue;
pmp_set(i + 1, prot, addr, log2size);
}
@@ -184,10 +183,19 @@ static int pmp_init(struct sbi_scratch *scratch, u32 hartid)
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;
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);
rc = fp_init(hartid);
@@ -201,6 +209,29 @@ int sbi_hart_init(struct sbi_scratch *scratch, u32 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)
{
while (1)
@@ -208,12 +239,16 @@ void __attribute__((noreturn)) sbi_hart_hang(void)
__builtin_unreachable();
}
void __attribute__((noreturn)) sbi_hart_switch_mode(unsigned long arg0,
unsigned long arg1,
unsigned long next_addr,
unsigned long next_mode)
void __attribute__((noreturn))
sbi_hart_switch_mode(unsigned long arg0, unsigned long arg1,
unsigned long next_addr, unsigned long next_mode,
bool next_virt)
{
#if __riscv_xlen == 32
unsigned long val, valH;
#else
unsigned long val;
#endif
switch (next_mode) {
case PRV_M:
@@ -230,31 +265,49 @@ void __attribute__((noreturn)) sbi_hart_switch_mode(unsigned long arg0,
sbi_hart_hang();
}
val = csr_read(mstatus);
val = csr_read(CSR_MSTATUS);
val = INSERT_FIELD(val, MSTATUS_MPP, next_mode);
val = INSERT_FIELD(val, MSTATUS_MPIE, 0);
csr_write(mstatus, val);
csr_write(mepc, next_addr);
#if __riscv_xlen == 32
if (misa_extension('H')) {
valH = csr_read(CSR_MSTATUSH);
valH = INSERT_FIELD(valH, MSTATUSH_MTL, 0);
if (next_virt)
valH = INSERT_FIELD(valH, MSTATUSH_MPV, 1);
else
valH = INSERT_FIELD(valH, MSTATUSH_MPV, 0);
csr_write(CSR_MSTATUSH, valH);
}
#else
if (misa_extension('H')) {
val = INSERT_FIELD(val, MSTATUS_MTL, 0);
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_MEPC, next_addr);
if (next_mode == PRV_S) {
csr_write(stvec, next_addr);
csr_write(sscratch, 0);
csr_write(sie, 0);
csr_write(satp, 0);
csr_write(CSR_STVEC, next_addr);
csr_write(CSR_SSCRATCH, 0);
csr_write(CSR_SIE, 0);
csr_write(CSR_SATP, 0);
} else if (next_mode == PRV_U) {
csr_write(utvec, next_addr);
csr_write(uscratch, 0);
csr_write(uie, 0);
csr_write(CSR_UTVEC, next_addr);
csr_write(CSR_USCRATCH, 0);
csr_write(CSR_UIE, 0);
}
register unsigned long a0 asm ("a0") = arg0;
register unsigned long a1 asm ("a1") = arg1;
__asm__ __volatile__ ("mret" : : "r" (a0), "r" (a1));
register unsigned long a0 asm("a0") = arg0;
register unsigned long a1 asm("a1") = arg1;
__asm__ __volatile__("mret" : : "r"(a0), "r"(a1));
__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;
void sbi_hart_mark_available(u32 hartid)
@@ -290,48 +343,62 @@ struct sbi_scratch *sbi_hart_id_to_scratch(struct sbi_scratch *scratch,
return ((h2s)scratch->hartid_to_scratch)(hartid);
}
#define COLDBOOT_WAIT_BITMAP_SIZE __riscv_xlen
static spinlock_t coldboot_wait_bitmap_lock = SPIN_LOCK_INITIALIZER;
#define COLDBOOT_WAIT_BITMAP_SIZE __riscv_xlen
static spinlock_t coldboot_lock = SPIN_LOCK_INITIALIZER;
static unsigned long coldboot_done = 0;
static unsigned long coldboot_wait_bitmap = 0;
void sbi_hart_wait_for_coldboot(struct sbi_scratch *scratch, u32 hartid)
{
unsigned long mipval;
struct sbi_platform *plat = sbi_platform_ptr(scratch);
const struct sbi_platform *plat = sbi_platform_ptr(scratch);
if ((sbi_platform_hart_count(plat) <= hartid) ||
(COLDBOOT_WAIT_BITMAP_SIZE <= hartid))
sbi_hart_hang();
/* Set MSIE bit to receive IPI */
csr_set(mie, MIP_MSIP);
csr_set(CSR_MIE, MIP_MSIP);
do {
spin_lock(&coldboot_wait_bitmap_lock);
coldboot_wait_bitmap |= (1UL << hartid);
spin_unlock(&coldboot_wait_bitmap_lock);
/* Acquire coldboot lock */
spin_lock(&coldboot_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();
mipval = csr_read(mip);
spin_lock(&coldboot_lock);
};
spin_lock(&coldboot_wait_bitmap_lock);
coldboot_wait_bitmap &= ~(1UL << hartid);
spin_unlock(&coldboot_wait_bitmap_lock);
} while (!(mipval && MIP_MSIP));
/* Unmark current HART as waiting */
coldboot_wait_bitmap &= ~(1UL << hartid);
csr_clear(mip, MIP_MSIP);
/* Release coldboot lock */
spin_unlock(&coldboot_lock);
/* Clear current HART IPI */
sbi_platform_ipi_clear(plat, hartid);
}
void sbi_hart_wake_coldboot_harts(struct sbi_scratch *scratch, u32 hartid)
{
struct sbi_platform *plat = sbi_platform_ptr(scratch);
int max_hart = sbi_platform_hart_count(plat);
const struct sbi_platform *plat = sbi_platform_ptr(scratch);
int max_hart = sbi_platform_hart_count(plat);
for(int i = 0; i < max_hart ; i++) {
/* send an IPI to every other hart */
spin_lock(&coldboot_wait_bitmap_lock);
/* Acquire coldboot lock */
spin_lock(&coldboot_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)))
sbi_platform_ipi_send(plat, i);
spin_unlock(&coldboot_wait_bitmap_lock);
}
/* Release coldboot lock */
spin_unlock(&coldboot_lock);
}

View File

@@ -9,38 +9,47 @@
#include <sbi/riscv_asm.h>
#include <sbi/riscv_encoding.h>
#include <sbi/riscv_unpriv.h>
#include <sbi/sbi_bits.h>
#include <sbi/sbi_emulate_csr.h>
#include <sbi/sbi_error.h>
#include <sbi/sbi_illegal_insn.h>
#include <sbi/sbi_trap.h>
#include <sbi/sbi_unpriv.h>
typedef int (*illegal_insn_func)(ulong insn,
u32 hartid, ulong mcause,
typedef int (*illegal_insn_func)(ulong insn, u32 hartid, ulong mcause,
struct sbi_trap_regs *regs,
struct sbi_scratch *scratch);
static int truly_illegal_insn(ulong insn,
u32 hartid, ulong mcause,
static int truly_illegal_insn(ulong insn, u32 hartid, ulong mcause,
struct sbi_trap_regs *regs,
struct sbi_scratch *scratch)
{
return sbi_trap_redirect(regs, scratch, regs->mepc, mcause, insn);
}
static int system_opcode_insn(ulong insn,
u32 hartid, ulong mcause,
static int system_opcode_insn(ulong insn, u32 hartid, ulong mcause,
struct sbi_trap_regs *regs,
struct sbi_scratch *scratch)
{
int do_write, rs1_num = (insn >> 15) & 0x1f;
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;
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 sbi_trap_redirect(regs, scratch,
regs->mepc, mcause, insn);
if (sbi_emulate_csr_read(csr_num, hartid, regs, scratch, &csr_val))
return truly_illegal_insn(insn, hartid, mcause,
regs, scratch);
@@ -48,16 +57,17 @@ static int system_opcode_insn(ulong insn,
switch (GET_RM(insn)) {
case 1:
new_csr_val = rs1_val;
do_write = 1;
do_write = 1;
break;
case 2:
new_csr_val = csr_val | rs1_val;
break;
case 3: new_csr_val = csr_val & ~rs1_val;
case 3:
new_csr_val = csr_val & ~rs1_val;
break;
case 5:
new_csr_val = rs1_num;
do_write = 1;
do_write = 1;
break;
case 6:
new_csr_val = csr_val | rs1_num;
@@ -66,15 +76,12 @@ static int system_opcode_insn(ulong insn,
new_csr_val = csr_val & ~rs1_num;
break;
default:
return truly_illegal_insn(insn, hartid, mcause,
regs, scratch);
return truly_illegal_insn(insn, hartid, mcause, regs, scratch);
};
if (do_write &&
sbi_emulate_csr_write(csr_num, hartid, regs->mstatus,
scratch, new_csr_val))
return truly_illegal_insn(insn, hartid, mcause,
regs, scratch);
if (do_write && sbi_emulate_csr_write(csr_num, hartid, regs,
scratch, new_csr_val))
return truly_illegal_insn(insn, hartid, mcause, regs, scratch);
SET_RD(insn, regs, csr_val);
@@ -122,17 +129,24 @@ int sbi_illegal_insn_handler(u32 hartid, ulong mcause,
struct sbi_trap_regs *regs,
struct sbi_scratch *scratch)
{
ulong mstatus;
ulong insn = csr_read(mbadaddr);
ulong insn = csr_read(CSR_MTVAL);
#if __riscv_xlen == 32
bool virt = (regs->mstatusH & MSTATUSH_MPV) ? TRUE : FALSE;
#else
bool virt = (regs->mstatus & MSTATUS_MPV) ? TRUE : FALSE;
#endif
struct unpriv_trap uptrap;
if (unlikely((insn & 3) != 3)) {
if (insn == 0) {
mstatus = csr_read(mstatus);
insn = get_insn(regs->mepc, &mstatus);
insn = get_insn(regs->mepc, virt, scratch, &uptrap);
if (uptrap.cause)
return sbi_trap_redirect(regs, scratch,
regs->mepc, uptrap.cause, uptrap.tval);
}
if ((insn & 3) != 3)
return truly_illegal_insn(insn, hartid, mcause,
regs, scratch);
return truly_illegal_insn(insn, hartid, mcause, regs,
scratch);
}
return illegal_insn_table[(insn & 0x7c) >> 2](insn, hartid, mcause,

View File

@@ -18,27 +18,60 @@
#include <sbi/sbi_timer.h>
#include <sbi/sbi_version.h>
#define BANNER \
" ____ _____ ____ _____\n" \
" / __ \\ / ____| _ \\_ _|\n" \
" | | | |_ __ ___ _ __ | (___ | |_) || |\n" \
#define BANNER \
" ____ _____ ____ _____\n" \
" / __ \\ / ____| _ \\_ _|\n" \
" | | | |_ __ ___ _ __ | (___ | |_) || |\n" \
" | | | | '_ \\ / _ \\ '_ \\ \\___ \\| _ < | |\n" \
" | |__| | |_) | __/ | | |____) | |_) || |_\n" \
" \\____/| .__/ \\___|_| |_|_____/|____/_____|\n" \
" | |\n" \
" | |__| | |_) | __/ | | |____) | |_) || |_\n" \
" \\____/| .__/ \\___|_| |_|_____/|____/_____|\n" \
" | |\n" \
" |_|\n\n"
static void sbi_boot_prints(struct sbi_scratch *scratch, u32 hartid)
{
char str[64];
const struct sbi_platform *plat = sbi_platform_ptr(scratch);
misa_string(str, sizeof(str));
#ifdef OPENSBI_VERSION_GIT
sbi_printf("\nOpenSBI %s (%s %s)\n", OPENSBI_VERSION_GIT,
__DATE__, __TIME__);
#else
sbi_printf("\nOpenSBI v%d.%d (%s %s)\n", OPENSBI_VERSION_MAJOR,
OPENSBI_VERSION_MINOR, __DATE__, __TIME__);
#endif
sbi_printf(BANNER);
/* Platform details */
sbi_printf("Platform Name : %s\n", sbi_platform_name(plat));
sbi_printf("Platform HART Features : RV%d%s\n", misa_xlen(), str);
sbi_printf("Platform 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_pmp_dump(scratch);
}
static void __noreturn init_coldboot(struct sbi_scratch *scratch, u32 hartid)
{
int rc;
char str[64];
struct sbi_platform *plat = sbi_platform_ptr(scratch);
const struct sbi_platform *plat = sbi_platform_ptr(scratch);
rc = sbi_system_early_init(scratch, TRUE);
if (rc)
sbi_hart_hang();
rc = sbi_hart_init(scratch, hartid);
rc = sbi_hart_init(scratch, hartid, TRUE);
if (rc)
sbi_hart_hang();
@@ -62,41 +95,20 @@ static void __noreturn init_coldboot(struct sbi_scratch *scratch, u32 hartid)
if (rc)
sbi_hart_hang();
misa_string(str, sizeof(str));
sbi_printf("\nOpenSBI v%d.%d (%s %s)\n",
OPENSBI_VERSION_MAJOR, OPENSBI_VERSION_MINOR,
__DATE__, __TIME__);
sbi_printf(BANNER);
/* Platform details */
sbi_printf("Platform Name : %s\n", sbi_platform_name(plat));
sbi_printf("Platform HART Features : RV%d%s\n", misa_xlen(), str);
sbi_printf("Platform 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_pmp_dump(scratch);
if (!(scratch->options & SBI_SCRATCH_NO_BOOT_PRINTS))
sbi_boot_prints(scratch, hartid);
if (!sbi_platform_has_hart_hotplug(plat))
sbi_hart_wake_coldboot_harts(scratch, hartid);
sbi_hart_mark_available(hartid);
sbi_hart_switch_mode(hartid, scratch->next_arg1,
scratch->next_addr, scratch->next_mode);
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;
struct sbi_platform *plat = sbi_platform_ptr(scratch);
const struct sbi_platform *plat = sbi_platform_ptr(scratch);
if (!sbi_platform_has_hart_hotplug(plat))
sbi_hart_wait_for_coldboot(scratch, hartid);
@@ -108,7 +120,7 @@ static void __noreturn init_warmboot(struct sbi_scratch *scratch, u32 hartid)
if (rc)
sbi_hart_hang();
rc = sbi_hart_init(scratch, hartid);
rc = sbi_hart_init(scratch, hartid, FALSE);
if (rc)
sbi_hart_hang();
@@ -135,7 +147,8 @@ static void __noreturn init_warmboot(struct sbi_scratch *scratch, u32 hartid)
sbi_hart_hang();
else
sbi_hart_switch_mode(hartid, scratch->next_arg1,
scratch->next_addr, scratch->next_mode);
scratch->next_addr,
scratch->next_mode, FALSE);
}
static atomic_t coldboot_lottery = ATOMIC_INITIALIZER(0);
@@ -154,13 +167,13 @@ static atomic_t coldboot_lottery = ATOMIC_INITIALIZER(0);
*/
void __noreturn sbi_init(struct sbi_scratch *scratch)
{
bool coldboot = FALSE;
u32 hartid = sbi_current_hartid();
struct sbi_platform *plat = sbi_platform_ptr(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;

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

@@ -0,0 +1,158 @@
/*
* 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/riscv_unpriv.h>
#include <sbi/sbi_error.h>
#include <sbi/sbi_hart.h>
#include <sbi/sbi_ipi.h>
#include <sbi/sbi_platform.h>
#include <sbi/sbi_tlb.h>
static unsigned long ipi_data_off;
static int sbi_ipi_send(struct sbi_scratch *scratch, u32 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;
if (sbi_platform_hart_disabled(plat, hartid))
return -1;
/*
* Set IPI type on remote hart's scratch area and
* trigger the interrupt
*/
remote_scratch = sbi_hart_id_to_scratch(scratch, hartid);
ipi_data = sbi_scratch_offset_ptr(remote_scratch, ipi_data_off);
if (event == SBI_IPI_EVENT_SFENCE_VMA ||
event == SBI_IPI_EVENT_SFENCE_VMA_ASID ||
event == SBI_IPI_EVENT_FENCE_I ) {
ret = sbi_tlb_fifo_update(remote_scratch, hartid, data);
if (ret < 0)
return ret;
}
atomic_raw_set_bit(event, &ipi_data->ipi_type);
smp_wmb();
sbi_platform_ipi_send(plat, hartid);
if (event == SBI_IPI_EVENT_SFENCE_VMA ||
event == SBI_IPI_EVENT_SFENCE_VMA_ASID ||
event == SBI_IPI_EVENT_FENCE_I ) {
sbi_tlb_fifo_sync(scratch);
}
return 0;
}
int sbi_ipi_send_many(struct sbi_scratch *scratch, struct unpriv_trap *uptrap,
ulong *pmask, u32 event, void *data)
{
ulong i, m;
ulong mask = sbi_hart_available_mask();
u32 hartid = sbi_current_hartid();
if (pmask) {
mask &= load_ulong(pmask, scratch, uptrap);
if (uptrap->cause)
return SBI_ETRAP;
}
/* Send IPIs to every other hart on the set */
for (i = 0, m = mask; m; i++, m >>= 1)
if ((m & 1UL) && (i != hartid))
sbi_ipi_send(scratch, i, event, data);
/*
* If the current hart is on the set, send an IPI
* to it as well
*/
if (mask & (1UL << hartid))
sbi_ipi_send(scratch, hartid, event, data);
return 0;
}
void sbi_ipi_clear_smode(struct sbi_scratch *scratch)
{
csr_clear(CSR_MIP, MIP_SSIP);
}
void sbi_ipi_process(struct sbi_scratch *scratch)
{
unsigned long ipi_type;
unsigned int ipi_event;
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;
switch (ipi_event) {
case SBI_IPI_EVENT_SOFT:
csr_set(CSR_MIP, MIP_SSIP);
break;
case SBI_IPI_EVENT_FENCE_I:
case SBI_IPI_EVENT_SFENCE_VMA:
case SBI_IPI_EVENT_SFENCE_VMA_ASID:
sbi_tlb_fifo_process(scratch);
break;
case SBI_IPI_EVENT_HALT:
sbi_hart_hang();
break;
default:
break;
};
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;
} else {
if (!ipi_data_off)
return SBI_ENOMEM;
}
ipi_data = sbi_scratch_offset_ptr(scratch, ipi_data_off);
ipi_data->ipi_type = 0x00;
ret = sbi_tlb_fifo_init(scratch, cold_boot);
if (ret)
return ret;
/* Enable software interrupts */
csr_set(CSR_MIE, MIP_MSIP);
return sbi_platform_ipi_init(sbi_platform_ptr(scratch), cold_boot);
}

View File

@@ -9,11 +9,11 @@
#include <sbi/riscv_asm.h>
#include <sbi/riscv_encoding.h>
#include <sbi/riscv_unpriv.h>
#include <sbi/riscv_fp.h>
#include <sbi/sbi_error.h>
#include <sbi/sbi_misaligned_ldst.h>
#include <sbi/sbi_trap.h>
#include <sbi/sbi_unpriv.h>
union reg_data {
u8 data_bytes[8];
@@ -26,81 +26,102 @@ int sbi_misaligned_load_handler(u32 hartid, ulong mcause,
struct sbi_scratch *scratch)
{
union reg_data val;
ulong mstatus = csr_read(mstatus);
ulong insn = get_insn(regs->mepc, &mstatus);
ulong addr = csr_read(mtval);
struct unpriv_trap uptrap;
ulong addr = csr_read(CSR_MTVAL);
int i, fp = 0, shift = 0, len = 0;
#if __riscv_xlen == 32
bool virt = (regs->mstatusH & MSTATUSH_MPV) ? TRUE : FALSE;
#else
bool virt = (regs->mstatus & MSTATUS_MPV) ? TRUE : FALSE;
#endif
ulong insn = get_insn(regs->mepc, virt, scratch, &uptrap);
if (uptrap.cause)
return sbi_trap_redirect(regs, scratch, regs->mepc,
uptrap.cause, uptrap.tval);
if ((insn & INSN_MASK_LW) == INSN_MATCH_LW) {
len = 4;
len = 4;
shift = 8 * (sizeof(ulong) - len);
#if __riscv_xlen == 64
} else if ((insn & INSN_MASK_LD) == INSN_MATCH_LD) {
len = 8;
len = 8;
shift = 8 * (sizeof(ulong) - len);
} else if ((insn & INSN_MASK_LWU) == INSN_MATCH_LWU) {
len = 4;
#endif
#ifdef __riscv_flen
} else if ((insn & INSN_MASK_FLD) == INSN_MATCH_FLD) {
fp = 1;
fp = 1;
len = 8;
} else if ((insn & INSN_MASK_FLW) == INSN_MATCH_FLW) {
fp = 1;
fp = 1;
len = 4;
#endif
} else if ((insn & INSN_MASK_LH) == INSN_MATCH_LH) {
len = 2;
len = 2;
shift = 8 * (sizeof(ulong) - len);
} else if ((insn & INSN_MASK_LHU) == INSN_MATCH_LHU) {
len = 2;
#ifdef __riscv_compressed
# if __riscv_xlen >= 64
#if __riscv_xlen >= 64
} else if ((insn & INSN_MASK_C_LD) == INSN_MATCH_C_LD) {
len = 8;
len = 8;
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 &&
((insn >> SH_RD) & 0x1f)) {
len = 8;
len = 8;
shift = 8 * (sizeof(ulong) - len);
# endif
} else if ((insn & INSN_MASK_C_LW) ==INSN_MATCH_C_LW) {
len = 4;
#endif
} else if ((insn & INSN_MASK_C_LW) == INSN_MATCH_C_LW) {
len = 4;
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 &&
((insn >> SH_RD) & 0x1f)) {
len = 4;
len = 4;
shift = 8 * (sizeof(ulong) - len);
#ifdef __riscv_flen
} else if ((insn & INSN_MASK_C_FLD) == INSN_MATCH_C_FLD) {
fp = 1;
len = 8;
fp = 1;
len = 8;
insn = RVC_RS2S(insn) << SH_RD;
} else if ((insn & INSN_MASK_C_FLDSP) == INSN_MATCH_C_FLDSP) {
fp = 1;
fp = 1;
len = 8;
# if __riscv_xlen == 32
#if __riscv_xlen == 32
} else if ((insn & INSN_MASK_C_FLW) == INSN_MATCH_C_FLW) {
fp = 1;
len = 4;
fp = 1;
len = 4;
insn = RVC_RS2S(insn) << SH_RD;
} else if ((insn & INSN_MASK_C_FLWSP) == INSN_MATCH_C_FLWSP) {
fp = 1;
fp = 1;
len = 4;
# endif
#endif
#endif
#endif
} else
return SBI_EILL;
return sbi_trap_redirect(regs, scratch, regs->mepc,
mcause, addr);
val.data_u64 = 0;
for (i = 0; i < len; i++)
val.data_bytes[i] = load_u8((void *)(addr + i), regs->mepc);
for (i = 0; i < len; i++) {
val.data_bytes[i] = load_u8((void *)(addr + i),
scratch, &uptrap);
if (uptrap.cause)
return sbi_trap_redirect(regs, scratch, regs->mepc,
uptrap.cause, uptrap.tval);
}
if (!fp)
SET_RD(insn, regs, val.data_ulong << shift >> shift);
#ifdef __riscv_flen
else if (len == 8)
SET_F64_RD(insn, regs, val.data_u64);
else
SET_F32_RD(insn, regs, val.data_ulong);
#endif
regs->mepc += INSN_LEN(insn);
@@ -112,10 +133,19 @@ int sbi_misaligned_store_handler(u32 hartid, ulong mcause,
struct sbi_scratch *scratch)
{
union reg_data val;
ulong mstatus = csr_read(mstatus);
ulong insn = get_insn(regs->mepc, &mstatus);
ulong addr = csr_read(mtval);
struct unpriv_trap uptrap;
ulong addr = csr_read(CSR_MTVAL);
int i, len = 0;
#if __riscv_xlen == 32
bool virt = (regs->mstatusH & MSTATUSH_MPV) ? TRUE : FALSE;
#else
bool virt = (regs->mstatus & MSTATUS_MPV) ? TRUE : FALSE;
#endif
ulong insn = get_insn(regs->mepc, virt, scratch, &uptrap);
if (uptrap.cause)
return sbi_trap_redirect(regs, scratch, regs->mepc,
uptrap.cause, uptrap.tval);
val.data_ulong = GET_RS2(insn, regs);
@@ -125,51 +155,61 @@ int sbi_misaligned_store_handler(u32 hartid, ulong mcause,
} else if ((insn & INSN_MASK_SD) == INSN_MATCH_SD) {
len = 8;
#endif
#ifdef __riscv_flen
} else if ((insn & INSN_MASK_FSD) == INSN_MATCH_FSD) {
len = 8;
len = 8;
val.data_u64 = GET_F64_RS2(insn, regs);
} else if ((insn & INSN_MASK_FSW) == INSN_MATCH_FSW) {
len = 4;
len = 4;
val.data_ulong = GET_F32_RS2(insn, regs);
#endif
} else if ((insn & INSN_MASK_SH) == INSN_MATCH_SH) {
len = 2;
#ifdef __riscv_compressed
# if __riscv_xlen >= 64
#if __riscv_xlen >= 64
} else if ((insn & INSN_MASK_C_SD) == INSN_MATCH_C_SD) {
len = 8;
len = 8;
val.data_ulong = GET_RS2S(insn, regs);
} else if ((insn & INSN_MASK_C_SDSP) == INSN_MATCH_C_SDSP &&
((insn >> SH_RD) & 0x1f)) {
len = 8;
len = 8;
val.data_ulong = GET_RS2C(insn, regs);
# endif
#endif
} else if ((insn & INSN_MASK_C_SW) == INSN_MATCH_C_SW) {
len = 4;
len = 4;
val.data_ulong = GET_RS2S(insn, regs);
} else if ((insn & INSN_MASK_C_SWSP) == INSN_MATCH_C_SWSP &&
((insn >> SH_RD) & 0x1f)) {
len = 4;
len = 4;
val.data_ulong = GET_RS2C(insn, regs);
#ifdef __riscv_flen
} else if ((insn & INSN_MASK_C_FSD) == INSN_MATCH_C_FSD) {
len = 8;
len = 8;
val.data_u64 = GET_F64_RS2S(insn, regs);
} else if ((insn & INSN_MASK_C_FSDSP) == INSN_MATCH_C_FSDSP) {
len = 8;
len = 8;
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) {
len = 4;
len = 4;
val.data_ulong = GET_F32_RS2S(insn, regs);
} else if ((insn & INSN_MASK_C_FSWSP) == INSN_MATCH_C_FSWSP) {
len = 4;
len = 4;
val.data_ulong = GET_F32_RS2C(insn, regs);
# endif
#endif
#endif
#endif
} else
return SBI_EILL;
return sbi_trap_redirect(regs, scratch, regs->mepc,
mcause, addr);
for (i = 0; i < len; i++)
store_u8((void *)(addr + i), val.data_bytes[i], regs->mepc);
for (i = 0; i < len; i++) {
store_u8((void *)(addr + i), val.data_bytes[i],
scratch, &uptrap);
if (uptrap.cause)
return sbi_trap_redirect(regs, scratch, regs->mepc,
uptrap.cause, uptrap.tval);
}
regs->mepc += INSN_LEN(insn);

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

@@ -0,0 +1,59 @@
/*
* 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_scratch.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)
{
unsigned long ret = 0;
/*
* 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;
while (size & (__SIZEOF_POINTER__ - 1))
size++;
spin_lock(&extra_lock);
if (SBI_SCRATCH_SIZE < (extra_offset + size))
goto done;
ret = extra_offset;
extra_offset += size;
done:
spin_unlock(&extra_lock);
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.
*/
#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 */
for (; *a == *b && *a != '\0'; a++, b++);
for (; *a == *b && *a != '\0'; a++, b++)
;
return *a - *b;
}
size_t strlen(const char *str)
size_t sbi_strlen(const char *str)
{
unsigned long ret = 0;
@@ -34,7 +35,7 @@ size_t strlen(const char *str)
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;
@@ -47,31 +48,31 @@ size_t strnlen(const char *str, size_t count)
return ret;
}
char *strcpy(char *dest, const char *src)
char *sbi_strcpy(char *dest, const char *src)
{
char *ret = dest;
while(*src != '\0') {
while (*src != '\0') {
*dest++ = *src++;
}
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;
while(count-- && *src != '\0') {
while (count-- && *src != '\0') {
*dest++ = *src++;
}
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++;
if (*s == '\0')
@@ -80,9 +81,9 @@ char *strchr(const char *s, int c)
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)
last--;
@@ -92,11 +93,11 @@ char *strrchr(const char *s, int c)
else
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;
while(count > 0 ){
while (count > 0) {
count--;
*temp++ = c;
}
@@ -104,9 +105,9 @@ void *memset(void *s, int c, size_t count)
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;
while (count > 0) {
@@ -117,16 +118,16 @@ void *memcpy(void *dest, const void *src, size_t count)
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;
if (src == dest)
return dest;
if (dest < src) {
while(count > 0) {
while (count > 0) {
*temp1++ = *temp2++;
count--;
}
@@ -134,7 +135,7 @@ void *memmove(void *dest, const void *src, size_t count)
temp1 = dest + count - 1;
temp2 = src + count - 1;
while(count > 0) {
while (count > 0) {
*temp1-- = *temp2--;
count--;
}
@@ -143,7 +144,7 @@ void *memmove(void *dest, const void *src, size_t count)
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 *temp2 = s2;
@@ -159,13 +160,13 @@ int memcmp(const void *s1, const void *s2, size_t count)
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;
while (count > 0) {
if ((unsigned char)c == *temp++) {
return (void *)(temp-1);
return (void *)(temp - 1);
}
count--;
}

45
lib/sbi/sbi_system.c Normal file
View File

@@ -0,0 +1,45 @@
/*
* 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/sbi_hart.h>
#include <sbi/sbi_platform.h>
#include <sbi/sbi_system.h>
#include <sbi/sbi_ipi.h>
int sbi_system_early_init(struct sbi_scratch *scratch, bool cold_boot)
{
return sbi_platform_early_init(sbi_platform_ptr(scratch), cold_boot);
}
int sbi_system_final_init(struct sbi_scratch *scratch, bool cold_boot)
{
return sbi_platform_final_init(sbi_platform_ptr(scratch), cold_boot);
}
void __attribute__((noreturn))
sbi_system_reboot(struct sbi_scratch *scratch, u32 type)
{
sbi_platform_system_reboot(sbi_platform_ptr(scratch), type);
sbi_hart_hang();
}
void __attribute__((noreturn))
sbi_system_shutdown(struct sbi_scratch *scratch, u32 type)
{
/* First try the platform-specific method */
sbi_platform_system_shutdown(sbi_platform_ptr(scratch), type);
/* If that fails (or is not implemented) send an IPI on every
* hart to hang and then hang the current hart */
sbi_ipi_send_many(scratch, NULL, NULL, SBI_IPI_EVENT_HALT, NULL);
sbi_hart_hang();
}

115
lib/sbi/sbi_timer.c Normal file
View File

@@ -0,0 +1,115 @@
/*
* 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_encoding.h>
#include <sbi/sbi_error.h>
#include <sbi/sbi_platform.h>
#include <sbi/sbi_timer.h>
static unsigned long time_delta_off;
#if __riscv_xlen == 32
u64 get_ticks(void)
{
u32 lo, hi, tmp;
__asm__ __volatile__("1:\n"
"rdtimeh %0\n"
"rdtime %1\n"
"rdtimeh %2\n"
"bne %0, %2, 1b"
: "=&r"(hi), "=&r"(lo), "=&r"(tmp));
return ((u64)hi << 32) | lo;
}
#else
u64 get_ticks(void)
{
unsigned long n;
__asm__ __volatile__("rdtime %0" : "=r"(n));
return n;
}
#endif
u64 sbi_timer_value(struct sbi_scratch *scratch)
{
const struct sbi_platform *plat = sbi_platform_ptr(scratch);
if (sbi_platform_has_timer_value(plat))
return sbi_platform_timer_value(plat);
else
return get_ticks();
}
u64 sbi_timer_virt_value(struct sbi_scratch *scratch)
{
u64 *time_delta = sbi_scratch_offset_ptr(scratch, time_delta_off);
return sbi_timer_value(scratch) + *time_delta;
}
u64 sbi_timer_get_delta(struct sbi_scratch *scratch)
{
u64 *time_delta = sbi_scratch_offset_ptr(scratch, time_delta_off);
return *time_delta;
}
void sbi_timer_set_delta(struct sbi_scratch *scratch, ulong delta)
{
u64 *time_delta = sbi_scratch_offset_ptr(scratch, time_delta_off);
*time_delta = (u64)delta;
}
void sbi_timer_set_delta_upper(struct sbi_scratch *scratch, ulong delta_upper)
{
u64 *time_delta = sbi_scratch_offset_ptr(scratch, time_delta_off);
*time_delta &= 0xffffffffULL;
*time_delta |= ((u64)delta_upper << 32);
}
void sbi_timer_event_stop(struct sbi_scratch *scratch)
{
sbi_platform_timer_event_stop(sbi_platform_ptr(scratch));
}
void sbi_timer_event_start(struct sbi_scratch *scratch, u64 next_event)
{
sbi_platform_timer_event_start(sbi_platform_ptr(scratch), next_event);
csr_clear(CSR_MIP, MIP_STIP);
csr_set(CSR_MIE, MIP_MTIP);
}
void sbi_timer_process(struct sbi_scratch *scratch)
{
csr_clear(CSR_MIE, MIP_MTIP);
csr_set(CSR_MIP, MIP_STIP);
}
int sbi_timer_init(struct sbi_scratch *scratch, bool cold_boot)
{
u64 *time_delta;
if (cold_boot) {
time_delta_off = sbi_scratch_alloc_offset(sizeof(*time_delta),
"TIME_DELTA");
if (!time_delta_off)
return SBI_ENOMEM;
} else {
if (!time_delta_off)
return SBI_ENOMEM;
}
time_delta = sbi_scratch_offset_ptr(scratch, time_delta_off);
*time_delta = 0;
return sbi_platform_timer_init(sbi_platform_ptr(scratch), cold_boot);
}

319
lib/sbi/sbi_tlb.c Normal file
View File

@@ -0,0 +1,319 @@
/*
* 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>
*/
#include <sbi/riscv_asm.h>
#include <sbi/riscv_atomic.h>
#include <sbi/riscv_barrier.h>
#include <sbi/sbi_error.h>
#include <sbi/sbi_fifo.h>
#include <sbi/sbi_hart.h>
#include <sbi/sbi_scratch.h>
#include <sbi/sbi_tlb.h>
#include <sbi/sbi_string.h>
#include <sbi/sbi_console.h>
#include <sbi/sbi_platform.h>
static unsigned long tlb_sync_off;
static unsigned long tlb_fifo_off;
static unsigned long tlb_fifo_mem_off;
static unsigned long tlb_range_flush_limit;
static void sbi_tlb_flush_all(void)
{
__asm__ __volatile("sfence.vma");
}
static void sbi_tlb_fifo_sfence_vma(struct sbi_tlb_info *tinfo)
{
unsigned long start = tinfo->start;
unsigned long size = tinfo->size;
unsigned long i;
if ((start == 0 && size == 0) || (size == SBI_TLB_FLUSH_ALL)) {
sbi_tlb_flush_all();
return;
}
for (i = 0; i < size; i += PAGE_SIZE) {
__asm__ __volatile__("sfence.vma %0"
:
: "r"(start + i)
: "memory");
}
}
static void sbi_tlb_fifo_sfence_vma_asid(struct sbi_tlb_info *tinfo)
{
unsigned long start = tinfo->start;
unsigned long size = tinfo->size;
unsigned long asid = tinfo->asid;
unsigned long i;
if (start == 0 && size == 0) {
sbi_tlb_flush_all();
return;
}
/* Flush entire MM context for a given ASID */
if (size == SBI_TLB_FLUSH_ALL) {
__asm__ __volatile__("sfence.vma x0, %0"
:
: "r"(asid)
: "memory");
return;
}
for (i = 0; i < size; i += PAGE_SIZE) {
__asm__ __volatile__("sfence.vma %0, %1"
:
: "r"(start + i), "r"(asid)
: "memory");
}
}
static void sbi_tlb_local_flush(struct sbi_tlb_info *tinfo)
{
if (tinfo->type == SBI_TLB_FLUSH_VMA) {
sbi_tlb_fifo_sfence_vma(tinfo);
} else if (tinfo->type == SBI_TLB_FLUSH_VMA_ASID) {
sbi_tlb_fifo_sfence_vma_asid(tinfo);
} else if (tinfo->type == SBI_ITLB_FLUSH)
__asm__ __volatile("fence.i");
else
sbi_printf("Invalid tlb flush request type [%lu]\n",
tinfo->type);
return;
}
static void sbi_tlb_entry_process(struct sbi_scratch *scratch,
struct sbi_tlb_info *tinfo)
{
u32 i;
u64 m;
struct sbi_scratch *rscratch = NULL;
unsigned long *rtlb_sync = NULL;
sbi_tlb_local_flush(tinfo);
for (i = 0, m = tinfo->shart_mask; m; i++, m >>= 1) {
if (!(m & 1UL))
continue;
rscratch = sbi_hart_id_to_scratch(scratch, i);
rtlb_sync = sbi_scratch_offset_ptr(rscratch, tlb_sync_off);
while (atomic_raw_xchg_ulong(rtlb_sync, 1)) ;
}
}
static void sbi_tlb_fifo_process_count(struct sbi_scratch *scratch, int count)
{
struct sbi_tlb_info tinfo;
u32 deq_count = 0;
struct sbi_fifo *tlb_fifo =
sbi_scratch_offset_ptr(scratch, tlb_fifo_off);
while (!sbi_fifo_dequeue(tlb_fifo, &tinfo)) {
sbi_tlb_entry_process(scratch, &tinfo);
deq_count++;
if (deq_count > count)
break;
}
}
void sbi_tlb_fifo_process(struct sbi_scratch *scratch)
{
struct sbi_tlb_info tinfo;
struct sbi_fifo *tlb_fifo =
sbi_scratch_offset_ptr(scratch, tlb_fifo_off);
while (!sbi_fifo_dequeue(tlb_fifo, &tinfo))
sbi_tlb_entry_process(scratch, &tinfo);
}
void sbi_tlb_fifo_sync(struct sbi_scratch *scratch)
{
unsigned long *tlb_sync =
sbi_scratch_offset_ptr(scratch, tlb_sync_off);
while (!atomic_raw_xchg_ulong(tlb_sync, 0)) {
/*
* While we are waiting for remote hart to set the sync,
* consume fifo requests to avoid deadlock.
*/
sbi_tlb_fifo_process_count(scratch, 1);
}
return;
}
static inline int __sbi_tlb_fifo_range_check(struct sbi_tlb_info *curr,
struct sbi_tlb_info *next)
{
unsigned long curr_end;
unsigned long next_end;
int ret = SBI_FIFO_UNCHANGED;
if (!curr || !next)
return ret;
next_end = next->start + next->size;
curr_end = curr->start + curr->size;
if (next->start <= curr->start && next_end > curr_end) {
curr->start = next->start;
curr->size = next->size;
curr->shart_mask = curr->shart_mask | next->shart_mask;
ret = SBI_FIFO_UPDATED;
} else if (next->start >= curr->start && next_end <= curr_end) {
curr->shart_mask = curr->shart_mask | next->shart_mask;
ret = SBI_FIFO_SKIP;
}
return ret;
}
/**
* Call back to decide if an inplace fifo update is required or next entry can
* can be skipped. Here are the different cases that are being handled.
*
* Case1:
* if next flush request range lies within one of the existing entry, skip
* the next entry.
* Case2:
* if flush request range in current fifo entry lies within next flush
* request, update the current entry.
*
* Note:
* We can not issue a fifo reset anymore if a complete vma flush is requested.
* This is because we are queueing FENCE.I requests as well now.
* To ease up the pressure in enqueue/fifo sync path, try to dequeue 1 element
* before continuing the while loop. This method is preferred over wfi/ipi because
* of MMIO cost involved in later method.
*/
static int sbi_tlb_fifo_update_cb(void *in, void *data)
{
struct sbi_tlb_info *curr;
struct sbi_tlb_info *next;
int ret = SBI_FIFO_UNCHANGED;
if (!in || !data)
return ret;
curr = (struct sbi_tlb_info *)data;
next = (struct sbi_tlb_info *)in;
if (next->type == SBI_TLB_FLUSH_VMA_ASID &&
curr->type == SBI_TLB_FLUSH_VMA_ASID) {
if (next->asid == curr->asid)
ret = __sbi_tlb_fifo_range_check(curr, next);
} else if (next->type == SBI_TLB_FLUSH_VMA &&
curr->type == SBI_TLB_FLUSH_VMA) {
ret = __sbi_tlb_fifo_range_check(curr, next);
}
return ret;
}
int sbi_tlb_fifo_update(struct sbi_scratch *rscratch, u32 hartid, void *data)
{
int ret;
struct sbi_fifo *tlb_fifo_r;
struct sbi_scratch *lscratch;
struct sbi_tlb_info *tinfo = data;
u32 curr_hartid = sbi_current_hartid();
/*
* If address range to flush is too big then simply
* upgrade it to flush all because we can only flush
* 4KB at a time.
*/
if (tinfo->size > tlb_range_flush_limit) {
tinfo->start = 0;
tinfo->size = SBI_TLB_FLUSH_ALL;
}
/*
* If the request is to queue a tlb flush entry for itself
* then just do a local flush and return;
*/
if (hartid == curr_hartid) {
sbi_tlb_local_flush(tinfo);
return -1;
}
lscratch = sbi_hart_id_to_scratch(rscratch, curr_hartid);
tlb_fifo_r = sbi_scratch_offset_ptr(rscratch, tlb_fifo_off);
ret = sbi_fifo_inplace_update(tlb_fifo_r, data, sbi_tlb_fifo_update_cb);
if (ret != SBI_FIFO_UNCHANGED) {
return 1;
}
while (sbi_fifo_enqueue(tlb_fifo_r, data) < 0) {
/**
* For now, Busy loop until there is space in the fifo.
* There may be case where target hart is also
* enqueue in source hart's fifo. Both hart may busy
* loop leading to a deadlock.
* TODO: Introduce a wait/wakeup event mechanism to handle
* this properly.
*/
sbi_tlb_fifo_process_count(lscratch, 1);
sbi_dprintf(rscratch, "hart%d: hart%d tlb fifo full\n",
curr_hartid, hartid);
}
return 0;
}
int sbi_tlb_fifo_init(struct sbi_scratch *scratch, bool cold_boot)
{
void *tlb_mem;
unsigned long *tlb_sync;
struct sbi_fifo *tlb_q;
const struct sbi_platform *plat = sbi_platform_ptr(scratch);
if (cold_boot) {
tlb_sync_off = sbi_scratch_alloc_offset(sizeof(*tlb_sync),
"IPI_TLB_SYNC");
if (!tlb_sync_off)
return SBI_ENOMEM;
tlb_fifo_off = sbi_scratch_alloc_offset(sizeof(*tlb_q),
"IPI_TLB_FIFO");
if (!tlb_fifo_off) {
sbi_scratch_free_offset(tlb_sync_off);
return SBI_ENOMEM;
}
tlb_fifo_mem_off = sbi_scratch_alloc_offset(
SBI_TLB_FIFO_NUM_ENTRIES * SBI_TLB_INFO_SIZE,
"IPI_TLB_FIFO_MEM");
if (!tlb_fifo_mem_off) {
sbi_scratch_free_offset(tlb_fifo_off);
sbi_scratch_free_offset(tlb_sync_off);
return SBI_ENOMEM;
}
tlb_range_flush_limit = sbi_platform_tlbr_flush_limit(plat);
} else {
if (!tlb_sync_off ||
!tlb_fifo_off ||
!tlb_fifo_mem_off)
return SBI_ENOMEM;
}
tlb_sync = sbi_scratch_offset_ptr(scratch, tlb_sync_off);
tlb_q = sbi_scratch_offset_ptr(scratch, tlb_fifo_off);
tlb_mem = sbi_scratch_offset_ptr(scratch, tlb_fifo_mem_off);
*tlb_sync = 0;
sbi_fifo_init(tlb_q, tlb_mem,
SBI_TLB_FIFO_NUM_ENTRIES, SBI_TLB_INFO_SIZE);
return 0;
}

286
lib/sbi/sbi_trap.c Normal file
View File

@@ -0,0 +1,286 @@
/*
* 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_encoding.h>
#include <sbi/riscv_unpriv.h>
#include <sbi/sbi_console.h>
#include <sbi/sbi_ecall.h>
#include <sbi/sbi_error.h>
#include <sbi/sbi_hart.h>
#include <sbi/sbi_illegal_insn.h>
#include <sbi/sbi_ipi.h>
#include <sbi/sbi_misaligned_ldst.h>
#include <sbi/sbi_timer.h>
#include <sbi/sbi_trap.h>
static void __noreturn sbi_trap_error(const char *msg, int rc, u32 hartid,
ulong mcause, ulong mtval,
struct sbi_trap_regs *regs)
{
sbi_printf("%s: hart%d: %s (error %d)\n", __func__, hartid, msg, rc);
sbi_printf("%s: hart%d: mcause=0x%" PRILX " mtval=0x%" PRILX "\n",
__func__, hartid, mcause, mtval);
sbi_printf("%s: hart%d: mepc=0x%" PRILX " mstatus=0x%" PRILX "\n",
__func__, hartid, regs->mepc, regs->mstatus);
sbi_printf("%s: hart%d: %s=0x%" PRILX " %s=0x%" PRILX "\n", __func__,
hartid, "ra", regs->ra, "sp", regs->sp);
sbi_printf("%s: hart%d: %s=0x%" PRILX " %s=0x%" PRILX "\n", __func__,
hartid, "gp", regs->gp, "tp", regs->tp);
sbi_printf("%s: hart%d: %s=0x%" PRILX " %s=0x%" PRILX "\n", __func__,
hartid, "s0", regs->s0, "s1", regs->s1);
sbi_printf("%s: hart%d: %s=0x%" PRILX " %s=0x%" PRILX "\n", __func__,
hartid, "a0", regs->a0, "a1", regs->a1);
sbi_printf("%s: hart%d: %s=0x%" PRILX " %s=0x%" PRILX "\n", __func__,
hartid, "a2", regs->a2, "a3", regs->a3);
sbi_printf("%s: hart%d: %s=0x%" PRILX " %s=0x%" PRILX "\n", __func__,
hartid, "a4", regs->a4, "a5", regs->a5);
sbi_printf("%s: hart%d: %s=0x%" PRILX " %s=0x%" PRILX "\n", __func__,
hartid, "a6", regs->a6, "a7", regs->a7);
sbi_printf("%s: hart%d: %s=0x%" PRILX " %s=0x%" PRILX "\n", __func__,
hartid, "s2", regs->s2, "s3", regs->s3);
sbi_printf("%s: hart%d: %s=0x%" PRILX " %s=0x%" PRILX "\n", __func__,
hartid, "s4", regs->s4, "s5", regs->s5);
sbi_printf("%s: hart%d: %s=0x%" PRILX " %s=0x%" PRILX "\n", __func__,
hartid, "s6", regs->s6, "s7", regs->s7);
sbi_printf("%s: hart%d: %s=0x%" PRILX " %s=0x%" PRILX "\n", __func__,
hartid, "s8", regs->s8, "s9", regs->s9);
sbi_printf("%s: hart%d: %s=0x%" PRILX " %s=0x%" PRILX "\n", __func__,
hartid, "s10", regs->s10, "s11", regs->s11);
sbi_printf("%s: hart%d: %s=0x%" PRILX " %s=0x%" PRILX "\n", __func__,
hartid, "t0", regs->t0, "t1", regs->t1);
sbi_printf("%s: hart%d: %s=0x%" PRILX " %s=0x%" PRILX "\n", __func__,
hartid, "t2", regs->t2, "t3", regs->t3);
sbi_printf("%s: hart%d: %s=0x%" PRILX " %s=0x%" PRILX "\n", __func__,
hartid, "t4", regs->t4, "t5", regs->t5);
sbi_printf("%s: hart%d: %s=0x%" PRILX "\n", __func__, hartid, "t6",
regs->t6);
sbi_hart_hang();
}
/**
* Redirect trap to lower privledge mode (S-mode or U-mode)
*
* @param regs pointer to register state
* @param scratch pointer to sbi_scratch of current HART
* @param epc error PC for lower privledge mode
* @param cause exception cause for lower privledge mode
* @param tval trap value for lower privledge mode
*
* @return 0 on success and negative error code on failure
*/
int sbi_trap_redirect(struct sbi_trap_regs *regs, struct sbi_scratch *scratch,
ulong epc, ulong cause, ulong tval)
{
ulong hstatus, vsstatus, prev_mode;
#if __riscv_xlen == 32
bool prev_virt = (regs->mstatusH & MSTATUSH_MPV) ? TRUE : FALSE;
bool prev_stage2 = (regs->mstatusH & MSTATUSH_MTL) ? TRUE : FALSE;
#else
bool prev_virt = (regs->mstatus & MSTATUS_MPV) ? TRUE : FALSE;
bool prev_stage2 = (regs->mstatus & MSTATUS_MTL) ? TRUE : FALSE;
#endif
/* By default, we redirect to HS-mode */
bool next_virt = FALSE;
/* Sanity check on previous mode */
prev_mode = (regs->mstatus & MSTATUS_MPP) >> MSTATUS_MPP_SHIFT;
if (prev_mode != PRV_S && prev_mode != PRV_U)
return SBI_ENOTSUPP;
/* For certain exceptions from VS/VU-mode we redirect to VS-mode */
if (misa_extension('H') && prev_virt && !prev_stage2) {
switch (cause) {
case CAUSE_FETCH_PAGE_FAULT:
case CAUSE_LOAD_PAGE_FAULT:
case CAUSE_STORE_PAGE_FAULT:
next_virt = TRUE;
break;
default:
break;
};
}
/* Update MSTATUS MPV and MTL bits */
#if __riscv_xlen == 32
regs->mstatusH &= ~MSTATUSH_MPV;
regs->mstatusH |= (next_virt) ? MSTATUSH_MPV : 0UL;
regs->mstatusH &= ~MSTATUSH_MTL;
#else
regs->mstatus &= ~MSTATUS_MPV;
regs->mstatus |= (next_virt) ? MSTATUS_MPV : 0UL;
regs->mstatus &= ~MSTATUS_MTL;
#endif
/* Update HSTATUS for VS/VU-mode to HS-mode transition */
if (misa_extension('H') && prev_virt && !next_virt) {
/* Update HSTATUS SP2P, SP2V, SPV, and STL bits */
hstatus = csr_read(CSR_HSTATUS);
hstatus &= ~HSTATUS_SP2P;
hstatus |= (regs->mstatus & MSTATUS_SPP) ? HSTATUS_SP2P : 0;
hstatus &= ~HSTATUS_SP2V;
hstatus |= (hstatus & HSTATUS_SPV) ? HSTATUS_SP2V : 0;
hstatus &= ~HSTATUS_SPV;
hstatus |= (prev_virt) ? HSTATUS_SPV : 0;
hstatus &= ~HSTATUS_STL;
hstatus |= (prev_stage2) ? HSTATUS_STL : 0;
csr_write(CSR_HSTATUS, hstatus);
}
/* Update exception related CSRs */
if (next_virt) {
/* Update VS-mode exception info */
csr_write(CSR_VSTVAL, tval);
csr_write(CSR_VSEPC, epc);
csr_write(CSR_VSCAUSE, cause);
/* Set MEPC to VS-mode exception vector base */
regs->mepc = csr_read(CSR_VSTVEC);
/* Set MPP to VS-mode */
regs->mstatus &= ~MSTATUS_MPP;
regs->mstatus |= (PRV_S << MSTATUS_MPP_SHIFT);
/* Get VS-mode SSTATUS CSR */
vsstatus = csr_read(CSR_VSSTATUS);
/* Set SPP for VS-mode */
vsstatus &= ~SSTATUS_SPP;
if (prev_mode == PRV_S)
vsstatus |= (1UL << SSTATUS_SPP_SHIFT);
/* Set SPIE for VS-mode */
vsstatus &= ~SSTATUS_SPIE;
if (vsstatus & SSTATUS_SIE)
vsstatus |= (1UL << SSTATUS_SPIE_SHIFT);
/* Clear SIE for VS-mode */
vsstatus &= ~SSTATUS_SIE;
/* Update VS-mode SSTATUS CSR */
csr_write(CSR_VSSTATUS, vsstatus);
} else {
/* Update S-mode exception info */
csr_write(CSR_STVAL, tval);
csr_write(CSR_SEPC, epc);
csr_write(CSR_SCAUSE, cause);
/* Set MEPC to S-mode exception vector base */
regs->mepc = csr_read(CSR_STVEC);
/* Set MPP to S-mode */
regs->mstatus &= ~MSTATUS_MPP;
regs->mstatus |= (PRV_S << MSTATUS_MPP_SHIFT);
/* Set SPP for S-mode*/
regs->mstatus &= ~MSTATUS_SPP;
if (prev_mode == PRV_S)
regs->mstatus |= (1UL << MSTATUS_SPP_SHIFT);
/* Set SPIE for S-mode */
regs->mstatus &= ~MSTATUS_SPIE;
if (regs->mstatus & MSTATUS_SIE)
regs->mstatus |= (1UL << MSTATUS_SPIE_SHIFT);
/* Clear SIE for S-mode */
regs->mstatus &= ~MSTATUS_SIE;
}
return 0;
}
/**
* Handle trap/interrupt
*
* This function is called by firmware linked to OpenSBI
* library for handling trap/interrupt. It expects the
* following:
* 1. The 'mscratch' CSR is pointing to sbi_scratch of current HART
* 2. The 'mcause' CSR is having exception/interrupt cause
* 3. The 'mtval' CSR is having additional trap information
* 4. Stack pointer (SP) is setup for current HART
* 5. Interrupts are disabled in MSTATUS CSR
*
* @param regs pointer to register state
* @param scratch pointer to sbi_scratch of current HART
*/
void sbi_trap_handler(struct sbi_trap_regs *regs, struct sbi_scratch *scratch)
{
int rc = SBI_ENOTSUPP;
const char *msg = "trap handler failed";
u32 hartid = sbi_current_hartid();
ulong mcause = csr_read(CSR_MCAUSE);
ulong mtval = csr_read(CSR_MTVAL);
struct unpriv_trap *uptrap;
if (mcause & (1UL << (__riscv_xlen - 1))) {
mcause &= ~(1UL << (__riscv_xlen - 1));
switch (mcause) {
case IRQ_M_TIMER:
sbi_timer_process(scratch);
break;
case IRQ_M_SOFT:
sbi_ipi_process(scratch);
break;
default:
msg = "unhandled external interrupt";
goto trap_error;
};
return;
}
switch (mcause) {
case CAUSE_ILLEGAL_INSTRUCTION:
rc = sbi_illegal_insn_handler(hartid, mcause, regs, scratch);
msg = "illegal instruction handler failed";
break;
case CAUSE_MISALIGNED_LOAD:
rc = sbi_misaligned_load_handler(hartid, mcause, regs, scratch);
msg = "misaligned load handler failed";
break;
case CAUSE_MISALIGNED_STORE:
rc = sbi_misaligned_store_handler(hartid, mcause, regs,
scratch);
msg = "misaligned store handler failed";
break;
case CAUSE_SUPERVISOR_ECALL:
case CAUSE_HYPERVISOR_ECALL:
rc = sbi_ecall_handler(hartid, mcause, regs, scratch);
msg = "ecall handler failed";
break;
case CAUSE_LOAD_ACCESS:
case CAUSE_STORE_ACCESS:
case CAUSE_LOAD_PAGE_FAULT:
case CAUSE_STORE_PAGE_FAULT:
uptrap = sbi_hart_get_trap_info(scratch);
if ((regs->mstatus & MSTATUS_MPRV) && uptrap) {
rc = 0;
regs->mepc += uptrap->ilen;
uptrap->cause = mcause;
uptrap->tval = mtval;
} else {
rc = sbi_trap_redirect(regs, scratch, regs->mepc,
mcause, mtval);
}
msg = "page/access fault handler failed";
break;
default:
/* If the trap came from S or U mode, redirect it there */
rc = sbi_trap_redirect(regs, scratch, regs->mepc,
mcause, mtval);
break;
};
trap_error:
if (rc) {
sbi_trap_error(msg, rc, hartid, mcause, csr_read(CSR_MTVAL),
regs);
}
}

View File

@@ -1,86 +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_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_trap.h>
#define SBI_ECALL_VERSION_MAJOR 0
#define SBI_ECALL_VERSION_MINOR 1
u16 sbi_ecall_version_major(void)
{
return SBI_ECALL_VERSION_MAJOR;
}
u16 sbi_ecall_version_minor(void)
{
return SBI_ECALL_VERSION_MINOR;
}
int sbi_ecall_handler(u32 hartid, ulong mcause,
struct sbi_trap_regs *regs,
struct sbi_scratch *scratch)
{
int ret = SBI_ENOTSUPP;
switch (regs->a7) {
case SBI_ECALL_SET_TIMER:
#if __riscv_xlen == 32
sbi_timer_event_start(scratch,
(((u64)regs->a1 << 32) || (u64)regs->a0));
#else
sbi_timer_event_start(scratch, (u64)regs->a0);
#endif
ret = 0;
break;
case SBI_ECALL_CONSOLE_PUTCHAR:
sbi_putc(regs->a0);
ret = 0;
break;
case SBI_ECALL_CONSOLE_GETCHAR:
regs->a0 = sbi_getc();
ret = 0;
break;
case SBI_ECALL_CLEAR_IPI:
sbi_ipi_clear_smode(scratch);
ret = 0;
break;
case SBI_ECALL_SEND_IPI:
ret = sbi_ipi_send_many(scratch, (ulong *)regs->a0,
SBI_IPI_EVENT_SOFT);
break;
case SBI_ECALL_REMOTE_FENCE_I:
ret = sbi_ipi_send_many(scratch, (ulong *)regs->a0,
SBI_IPI_EVENT_FENCE_I);
break;
case SBI_ECALL_REMOTE_SFENCE_VMA:
case SBI_ECALL_REMOTE_SFENCE_VMA_ASID:
ret = sbi_ipi_send_many(scratch, (ulong *)regs->a0,
SBI_IPI_EVENT_SFENCE_VMA);
break;
case SBI_ECALL_SHUTDOWN:
sbi_system_shutdown(scratch, 0);
ret = 0;
break;
default:
break;
};
if (!ret) {
regs->mepc += 4;
}
return ret;
}

View File

@@ -1,142 +0,0 @@
/*
* SPDX-License-Identifier: BSD-2-Clause
*
* Copyright (c) 2019 Western Digital Corporation or its affiliates.
*
* Authors:
* Anup Patel <anup.patel@wdc.com>
*/
#include <sbi/riscv_asm.h>
#include <sbi/riscv_encoding.h>
#include <sbi/sbi_bits.h>
#include <sbi/sbi_console.h>
#include <sbi/sbi_emulate_csr.h>
#include <sbi/sbi_error.h>
#include <sbi/sbi_timer.h>
int sbi_emulate_csr_read(int csr_num,
u32 hartid, ulong mstatus,
struct sbi_scratch *scratch,
ulong *csr_val)
{
ulong cen = -1UL;
if (EXTRACT_FIELD(mstatus, MSTATUS_MPP) == PRV_U)
cen = csr_read(scounteren);
switch (csr_num) {
case CSR_CYCLE:
if (!((cen >> (CSR_CYCLE - CSR_CYCLE)) & 1))
return -1;
*csr_val = csr_read(mcycle);
break;
case CSR_TIME:
if (!((cen >> (CSR_TIME - CSR_CYCLE)) & 1))
return -1;
*csr_val = sbi_timer_value(scratch);
break;
case CSR_INSTRET:
if (!((cen >> (CSR_INSTRET - CSR_CYCLE)) & 1))
return -1;
*csr_val = csr_read(minstret);
break;
case CSR_MHPMCOUNTER3:
if (!((cen >> (3 + CSR_MHPMCOUNTER3 - CSR_MHPMCOUNTER3)) & 1))
return -1;
*csr_val = csr_read(mhpmcounter3);
break;
case CSR_MHPMCOUNTER4:
if (!((cen >> (3 + CSR_MHPMCOUNTER4 - CSR_MHPMCOUNTER3)) & 1))
return -1;
*csr_val = csr_read(mhpmcounter4);
break;
#if __riscv_xlen == 32
case CSR_CYCLEH:
if (!((cen >> (CSR_CYCLE - CSR_CYCLE)) & 1))
return -1;
*csr_val = csr_read(mcycleh);
break;
case CSR_TIMEH:
if (!((cen >> (CSR_TIME - CSR_CYCLE)) & 1))
return -1;
*csr_val = sbi_timer_value(scratch);
*csr_val = *csr_val >> 32;
break;
case CSR_INSTRETH:
if (!((cen >> (CSR_INSTRET - CSR_CYCLE)) & 1))
return -1;
*csr_val = csr_read(minstreth);
break;
case CSR_MHPMCOUNTER3H:
if (!((cen >> (3 + CSR_MHPMCOUNTER3 - CSR_MHPMCOUNTER3)) & 1))
return -1;
*csr_val = csr_read(mhpmcounter3h);
break;
case CSR_MHPMCOUNTER4H:
if (!((cen >> (3 + CSR_MHPMCOUNTER4 - CSR_MHPMCOUNTER3)) & 1))
return -1;
*csr_val = csr_read(mhpmcounter4h);
break;
#endif
case CSR_MHPMEVENT3:
*csr_val = csr_read(mhpmevent3);
break;
case CSR_MHPMEVENT4:
*csr_val = csr_read(mhpmevent4);
break;
default:
sbi_printf("%s: hartid%d: invalid csr_num=0x%x\n",
__func__, hartid, csr_num);
return SBI_ENOTSUPP;
};
return 0;
}
int sbi_emulate_csr_write(int csr_num,
u32 hartid, ulong mstatus,
struct sbi_scratch *scratch,
ulong csr_val)
{
switch (csr_num) {
case CSR_CYCLE:
csr_write(mcycle, csr_val);
break;
case CSR_INSTRET:
csr_write(minstret, csr_val);
break;
case CSR_MHPMCOUNTER3:
csr_write(mhpmcounter3, csr_val);
break;
case CSR_MHPMCOUNTER4:
csr_write(mhpmcounter4, csr_val);
break;
#if __riscv_xlen == 32
case CSR_CYCLEH:
csr_write(mcycleh, csr_val);
break;
case CSR_INSTRETH:
csr_write(minstreth, csr_val);
break;
case CSR_MHPMCOUNTER3H:
csr_write(mhpmcounter3h, csr_val);
break;
case CSR_MHPMCOUNTER4H:
csr_write(mhpmcounter4h, csr_val);
break;
#endif
case CSR_MHPMEVENT3:
csr_write(mhpmevent3, csr_val);
break;
case CSR_MHPMEVENT4:
csr_write(mhpmevent4, csr_val);
break;
default:
sbi_printf("%s: hartid%d: invalid csr_num=0x%x\n",
__func__, hartid, csr_num);
return SBI_ENOTSUPP;
};
return 0;
}

View File

@@ -1,90 +0,0 @@
/*
* SPDX-License-Identifier: BSD-2-Clause
*
* Copyright (c) 2019 Western Digital Corporation or its affiliates.
*
* Authors:
* Anup Patel <anup.patel@wdc.com>
*/
#include <sbi/riscv_asm.h>
#include <sbi/riscv_barrier.h>
#include <sbi/riscv_atomic.h>
#include <sbi/sbi_hart.h>
#include <sbi/sbi_bitops.h>
#include <sbi/sbi_console.h>
#include <sbi/sbi_ipi.h>
#include <sbi/sbi_platform.h>
#include <sbi/sbi_timer.h>
#include <sbi/sbi_unpriv.h>
int sbi_ipi_send_many(struct sbi_scratch *scratch,
ulong *pmask, u32 event)
{
ulong i, m;
struct sbi_scratch *oth;
ulong mask = sbi_hart_available_mask();
struct sbi_platform *plat = sbi_platform_ptr(scratch);
if (pmask)
mask &= load_ulong(pmask, csr_read(mepc));
/* send IPIs to everyone */
for (i = 0, m = mask; m; i++, m >>= 1) {
if ((m & 1) && !sbi_platform_hart_disabled(plat, i)) {
oth = sbi_hart_id_to_scratch(scratch, i);
atomic_raw_set_bit(event, &oth->ipi_type);
mb();
sbi_platform_ipi_send(plat, i);
if (event != SBI_IPI_EVENT_SOFT)
sbi_platform_ipi_sync(plat, i);
}
}
return 0;
}
void sbi_ipi_clear_smode(struct sbi_scratch *scratch)
{
csr_clear(mip, MIP_SSIP);
}
void sbi_ipi_process(struct sbi_scratch *scratch)
{
struct sbi_platform *plat = sbi_platform_ptr(scratch);
volatile unsigned long ipi_type;
unsigned int ipi_event;
u32 hartid = sbi_current_hartid();
sbi_platform_ipi_clear(plat, hartid);
do {
ipi_type = scratch->ipi_type;
rmb();
ipi_event = __ffs(ipi_type);
switch (ipi_event) {
case SBI_IPI_EVENT_SOFT:
csr_set(mip, MIP_SSIP);
break;
case SBI_IPI_EVENT_FENCE_I:
__asm__ __volatile("fence.i");
break;
case SBI_IPI_EVENT_SFENCE_VMA:
__asm__ __volatile("sfence.vma");
break;
case SBI_IPI_EVENT_HALT:
sbi_hart_hang();
break;
};
ipi_type = atomic_raw_clear_bit(ipi_event, &scratch->ipi_type);
} while(ipi_type > 0);
}
int sbi_ipi_init(struct sbi_scratch *scratch, bool cold_boot)
{
/* Enable software interrupts */
csr_set(mie, MIP_MSIP);
return sbi_platform_ipi_init(sbi_platform_ptr(scratch),
cold_boot);
}

View File

@@ -1,39 +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_hart.h>
#include <sbi/sbi_platform.h>
#include <sbi/sbi_system.h>
int sbi_system_early_init(struct sbi_scratch *scratch, bool cold_boot)
{
return sbi_platform_early_init(sbi_platform_ptr(scratch),
cold_boot);
}
int sbi_system_final_init(struct sbi_scratch *scratch, bool cold_boot)
{
return sbi_platform_final_init(sbi_platform_ptr(scratch),
cold_boot);
}
void __attribute__((noreturn)) sbi_system_reboot(struct sbi_scratch *scratch,
u32 type)
{
sbi_platform_system_reboot(sbi_platform_ptr(scratch), type);
sbi_hart_hang();
}
void __attribute__((noreturn)) sbi_system_shutdown(struct sbi_scratch *scratch,
u32 type)
{
sbi_platform_system_shutdown(sbi_platform_ptr(scratch), type);
sbi_hart_hang();
}

View File

@@ -1,73 +0,0 @@
/*
* SPDX-License-Identifier: BSD-2-Clause
*
* Copyright (c) 2019 Western Digital Corporation or its affiliates.
*
* Authors:
* Anup Patel <anup.patel@wdc.com>
*/
#include <sbi/riscv_asm.h>
#include <sbi/riscv_encoding.h>
#include <sbi/sbi_platform.h>
#include <sbi/sbi_timer.h>
#if __riscv_xlen == 32
u64 get_ticks(void)
{
u32 lo, hi, tmp;
__asm__ __volatile__ (
"1:\n"
"rdtimeh %0\n"
"rdtime %1\n"
"rdtimeh %2\n"
"bne %0, %2, 1b"
: "=&r" (hi), "=&r" (lo), "=&r" (tmp));
return ((u64)hi << 32) | lo;
}
#else
u64 get_ticks(void)
{
unsigned long n;
__asm__ __volatile__ (
"rdtime %0"
: "=r" (n));
return n;
}
#endif
u64 sbi_timer_value(struct sbi_scratch *scratch)
{
struct sbi_platform *plat = sbi_platform_ptr(scratch);
if (sbi_platform_has_timer_value(plat))
return sbi_platform_timer_value(plat);
else
return get_ticks();
}
void sbi_timer_event_stop(struct sbi_scratch *scratch)
{
sbi_platform_timer_event_stop(sbi_platform_ptr(scratch));
}
void sbi_timer_event_start(struct sbi_scratch *scratch, u64 next_event)
{
sbi_platform_timer_event_start(sbi_platform_ptr(scratch),
next_event);
csr_clear(mip, MIP_STIP);
csr_set(mie, MIP_MTIP);
}
void sbi_timer_process(struct sbi_scratch *scratch)
{
csr_clear(mie, MIP_MTIP);
csr_set(mip, MIP_STIP);
}
int sbi_timer_init(struct sbi_scratch *scratch, bool cold_boot)
{
return sbi_platform_timer_init(sbi_platform_ptr(scratch),
cold_boot);
}

View File

@@ -1,188 +0,0 @@
/*
* SPDX-License-Identifier: BSD-2-Clause
*
* Copyright (c) 2019 Western Digital Corporation or its affiliates.
*
* Authors:
* Anup Patel <anup.patel@wdc.com>
*/
#include <sbi/riscv_asm.h>
#include <sbi/riscv_encoding.h>
#include <sbi/sbi_console.h>
#include <sbi/sbi_ecall.h>
#include <sbi/sbi_error.h>
#include <sbi/sbi_hart.h>
#include <sbi/sbi_illegal_insn.h>
#include <sbi/sbi_ipi.h>
#include <sbi/sbi_misaligned_ldst.h>
#include <sbi/sbi_timer.h>
#include <sbi/sbi_trap.h>
static void __noreturn sbi_trap_error(const char *msg,
int rc, u32 hartid,
ulong mcause, ulong mtval,
struct sbi_trap_regs *regs)
{
sbi_printf("%s: hart%d: %s (error %d)\n",
__func__, hartid, msg, rc);
sbi_printf("%s: hart%d: mcause=0x%lx mtval=0x%lx\n",
__func__, hartid, mcause, mtval);
sbi_printf("%s: hart%d: mepc=0x%lx mstatus=0x%lx\n",
__func__, hartid, regs->mepc, regs->mstatus);
sbi_printf("%s: hart%d: %s=0x%lx %s=0x%lx\n",
__func__, hartid, "ra", regs->ra, "sp", regs->sp);
sbi_printf("%s: hart%d: %s=0x%lx %s=0x%lx\n",
__func__, hartid, "gp", regs->gp, "tp", regs->tp);
sbi_printf("%s: hart%d: %s=0x%lx %s=0x%lx\n",
__func__, hartid, "s0", regs->s0, "s1", regs->s1);
sbi_printf("%s: hart%d: %s=0x%lx %s=0x%lx\n",
__func__, hartid, "a0", regs->a0, "a1", regs->a1);
sbi_printf("%s: hart%d: %s=0x%lx %s=0x%lx\n",
__func__, hartid, "a2", regs->a2, "a3", regs->a3);
sbi_printf("%s: hart%d: %s=0x%lx %s=0x%lx\n",
__func__, hartid, "a4", regs->a4, "a5", regs->a5);
sbi_printf("%s: hart%d: %s=0x%lx %s=0x%lx\n",
__func__, hartid, "a6", regs->a6, "a7", regs->a7);
sbi_printf("%s: hart%d: %s=0x%lx %s=0x%lx\n",
__func__, hartid, "s2", regs->s2, "s3", regs->s3);
sbi_printf("%s: hart%d: %s=0x%lx %s=0x%lx\n",
__func__, hartid, "s4", regs->s4, "s5", regs->s5);
sbi_printf("%s: hart%d: %s=0x%lx %s=0x%lx\n",
__func__, hartid, "s6", regs->s6, "s7", regs->s7);
sbi_printf("%s: hart%d: %s=0x%lx %s=0x%lx\n",
__func__, hartid, "s8", regs->s8, "s9", regs->s9);
sbi_printf("%s: hart%d: %s=0x%lx %s=0x%lx\n",
__func__, hartid, "s10", regs->s10, "s11", regs->s11);
sbi_printf("%s: hart%d: %s=0x%lx %s=0x%lx\n",
__func__, hartid, "t0", regs->t0, "t1", regs->t1);
sbi_printf("%s: hart%d: %s=0x%lx %s=0x%lx\n",
__func__, hartid, "t2", regs->t2, "t3", regs->t3);
sbi_printf("%s: hart%d: %s=0x%lx %s=0x%lx\n",
__func__, hartid, "t4", regs->t4, "t5", regs->t5);
sbi_printf("%s: hart%d: %s=0x%lx\n",
__func__, hartid, "t6", regs->t6);
sbi_hart_hang();
}
/**
* Redirect trap to lower privledge mode (S-mode or U-mode)
*
* @param regs pointer to register state
* @param scratch pointer to sbi_scratch of current HART
* @param epc error PC for lower privledge mode
* @param cause exception cause for lower privledge mode
* @param tval trap value for lower privledge mode
*
* @return 0 on success and negative error code on failure
*/
int sbi_trap_redirect(struct sbi_trap_regs *regs,
struct sbi_scratch *scratch,
ulong epc, ulong cause, ulong tval)
{
ulong new_mstatus, prev_mode;
/* Sanity check on previous mode */
prev_mode = (regs->mstatus & MSTATUS_MPP) >> MSTATUS_MPP_SHIFT;
if (prev_mode != PRV_S && prev_mode != PRV_U)
return SBI_ENOTSUPP;
/* Update S-mode exception info */
csr_write(stval, tval);
csr_write(sepc, epc);
csr_write(scause, cause);
/* Set MEPC to S-mode exception vector base */
regs->mepc = csr_read(stvec);
/* Initial value of new MSTATUS */
new_mstatus = regs->mstatus;
/* Clear MPP, SPP, SPIE, and SIE */
new_mstatus &= ~(MSTATUS_MPP |
MSTATUS_SPP | MSTATUS_SPIE | MSTATUS_SIE);
/* Set SPP */
if (prev_mode == PRV_S)
new_mstatus |= (1UL << MSTATUS_SPP_SHIFT);
/* Set SPIE */
if (regs->mstatus & MSTATUS_SIE)
new_mstatus |= (1UL << MSTATUS_SPIE_SHIFT);
/* Set MPP */
new_mstatus |= (PRV_S << MSTATUS_MPP_SHIFT);
/* Set new value in MSTATUS */
regs->mstatus = new_mstatus;
return 0;
}
/**
* Handle trap/interrupt
*
* This function is called by firmware linked to OpenSBI
* library for handling trap/interrupt. It expects the
* following:
* 1. The 'mscratch' CSR is pointing to sbi_scratch of current HART
* 2. The 'mcause' CSR is having exception/interrupt cause
* 3. The 'mtval' CSR is having additional trap information
* 4. Stack pointer (SP) is setup for current HART
* 5. Interrupts are disabled in MSTATUS CSR
*
* @param regs pointer to register state
* @param scratch pointer to sbi_scratch of current HART
*/
void sbi_trap_handler(struct sbi_trap_regs *regs,
struct sbi_scratch *scratch)
{
int rc = SBI_ENOTSUPP;
const char *msg = "trap handler failed";
u32 hartid = sbi_current_hartid();
ulong mcause = csr_read(mcause);
if (mcause & (1UL << (__riscv_xlen - 1))) {
mcause &= ~(1UL << (__riscv_xlen - 1));
switch (mcause) {
case IRQ_M_TIMER:
sbi_timer_process(scratch);
break;
case IRQ_M_SOFT:
sbi_ipi_process(scratch);
break;
default:
msg = "unhandled external interrupt";
goto trap_error;
};
return;
}
switch (mcause) {
case CAUSE_ILLEGAL_INSTRUCTION:
rc = sbi_illegal_insn_handler(hartid, mcause, regs, scratch);
msg = "illegal instruction handler failed";
break;
case CAUSE_MISALIGNED_LOAD:
rc = sbi_misaligned_load_handler(hartid, mcause, regs, scratch);
msg = "misaligned load handler failed";
break;
case CAUSE_MISALIGNED_STORE:
rc = sbi_misaligned_store_handler(hartid, mcause, regs, scratch);
msg = "misaligned store handler failed";
break;
case CAUSE_SUPERVISOR_ECALL:
case CAUSE_HYPERVISOR_ECALL:
rc = sbi_ecall_handler(hartid, mcause, regs, scratch);
msg = "ecall handler failed";
break;
default:
break;
};
trap_error:
if (rc) {
sbi_trap_error(msg, rc, hartid, mcause, csr_read(mtval), regs);
}
}

View File

@@ -7,4 +7,4 @@
# Anup Patel <anup.patel@wdc.com>
#
platform-common-objs-$(PLATFORM_SYS_CLINT) += sys/clint.o
libsbiutils-objs-y += irqchip/plic.o

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