293 Commits
v0.5 ... v0.8

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

Signed-off-by: Anup Patel <anup.patel@wdc.com>
2020-06-20 11:57:24 +05:30
Anup Patel
2314101989 lib: Don't return any invalid error from SBI ecall
We should only return valid error codes from SBI ecalls as
defined by the RISC-V SBI spec.

To achieve this:
1. We use SBI_Exxxx defines for OpenSBI internal errors with
   error values starting from -1000
2. We use SBI_ERR_xxxx defines for errors defined by SBI spec
3. We map some of the SBI_Exxxx defines to SBI_ERR_xxxx defines
   which are semantically same
4. We throw a error print and force return error code to
   SBI_ERR_FAILED in sbi_ecall_handler() if we see an invalid
   error code being returned to S-mode

Signed-off-by: Anup Patel <anup.patel@wdc.com>
Reviewed-by: Atish Patra <atish.patra@wdc.com>
2020-06-20 10:36:13 +05:30
Liush
9bd5f8f17d lib: sbi: Fix 32/64 bits variable compatibility
On RV64,"unsigned long" is 64bit and "unsigned int" is 32bit. So in
function "pmp_get" and "pmp_set", if "pmpcfg_shift >= 32", "0xff << pmpcfg_shift"
will go beyond "unsigned int" width. This patch tries to fix this issue.

In function 'pmp_get':
	cfgmask = (0xff << pmpcfg_shift);
			-->
	cfgmask = (0xffUL << pmpcfg_shift);
In function 'pmp_set':
	cfgmask = ~(0xff << pmpcfg_shift);
			-->
	cfgmask = ~(0xffUL << pmpcfg_shift);

Signed-off-by: Liush <liush.damon@gmail.com>
Reviewed-by: Anup Patel <anup.patel@wdc.com>
2020-06-20 08:47:11 +05:30
Vijai Kumar K
db56ef367c platform: Add support for Shakti C-class SoC from IIT-M
C-Class is a member of the SHAKTI family of processors from Indian
Institute of Technology - Madras(IIT-M).
It is an extremely configurable and commercial-grade 5-stage in-order
core supporting the standard RV64GCSUN ISA extensions.

https://gitlab.com/shaktiproject/cores/c-class/blob/master/README.md

We add OpenSBI support for Shakti C-class SoC.

Signed-off-by: Vijai Kumar K <vijai@behindbytes.com>
Reviewed-by: Anup Patel <anup.patel@wdc.com>
2020-06-19 09:21:46 +05:30
Alistair Francis
637b348224 lib: Fix the SBI_HART_HAS_MCOUNTEREN feature check
Signed-off-by: Alistair Francis <alistair.francis@wdc.com>
Reviewed-by: Atish Patra <atish.patra@wdc.com>
Reviewed-by: Anup Patel <anup.patel@wdc.com>
2020-06-18 08:58:13 +05:30
Alistair Francis
d5725c24c6 lib: Don't print delegation CSRs if there is no S-Mode
If the platform doesn't support S-Mode don't print the delegation
registers.

Signed-off-by: Alistair Francis <alistair.francis@wdc.com>
Reviewed-by: Atish Patra <atish.patra@wdc.com>
Reviewed-by: Anup Patel <anup.patel@wdc.com>
2020-06-18 08:56:54 +05:30
Huaqi Fang
518e85cccb platform: Update Nuclei ux600 platform support
Changes are made to support our FPGA evaluation board,
it has DDR memory(0xA0000000-0xB0000000).

* Adapt the config.mk to match FPGA evaluation board DDR memory address
* Since the RISC-V CPU core frequency of FPGA might change, so we use the
  fixed TIMER frequency to measure the real CPU core frequency.
* And the UART baudrate has to set to 57600bps for Nuclei FPGA evaluation
  board when CPU core frequency is about 8MHz, otherwise the UART input
  will not work correctly.

Signed-off-by: Huaqi Fang <578567190@qq.com>
Reviewed-by: Anup Patel <anup.patel@wdc.com>
2020-06-17 21:06:40 +05:30
Alexandre Ghiti
6966ad0abe platform/lib: Allow the OS to map the regions that are protected by PMP
This is achieved by removing the 'no-map' property from the
'reserved-memory' node when PMP is present, otherwise we keep it as it
offers a small protection if the OS does not map this region at all.
A new callback in platform_override is introduced and allows to fixup the
device-tree. It is used here to override this new default behaviour on
SiFive Fu540 platforms that has an erratum that prevents S-mode software
to access a PMP protected region using 1GB page table mapping.

If PMP is present, telling the OS not to map the reserved regions does not
add much protection since it only avoids access to regions that are already
protected by PMP. But by not allowing the OS to map those regions, it
creates holes in the OS system memory map and prevents the use of
hugepages which would generate, among other benefits, less TLB miss.

Signed-off-by: Alexandre Ghiti <alex@ghiti.fr>
Reviewed-by: Atish Patra <atish.patra@wdc.com>
Reviewed-by: Anup Patel <anup.patel@wdc.com>
2020-06-15 09:25:44 +05:30
Anup Patel
e2c3f01af4 lib: Fix __sbi_hfence_gvma_vmid_gpa() and __sbi_hfence_vvma_asid_va()
The arguments/parameters of __sbi_hfence_gvma_vmid_gpa() and
__sbi_hfence_vvma_asid_va() functions are swapped so we fix it.

Currently, we did not face any issues because QEMU does a full
TLB flush for all HFENCE instructions.

We also improve documentation of HFENCE.GVMA and HFENCE.VVMA
instruction encoding.

Signed-off-by: Anup Patel <anup.patel@wdc.com>
Reviewed-by: Atish Patra <atish.patra@wdc.com>
2020-06-15 09:24:27 +05:30
Nylon Chen
32f87e5a86 platform: Add AE350 cache control SBIs
This patch contains the following AE350 specific SBIs:

- get mcache_ctl status
- get mmisc_ctl status
- set mcache_ctl status
- set mmisc_ctl status
- I-cache operation
- D-cache operation
- enable/disable L1-I-cache prefetch
- enable/disable L1-D-cache prefetch
- enable/disable non-blocking load store
- enable/disable write-around

Signed-off-by: Nylon Chen <nylon7@andestech.com>
Reviewed-by: Anup Patel <Anup.Patel@wdc.com>
Reviewed-by: Atish Patra <Atish.Patra@wdc.com>
2020-06-10 09:28:52 +05:30
Nylon Chen
980290651f platform: Add AE350 platform specific SBI handler
We add AE350 platform specific SBI handler to implement
AE350 specific SBI calls.

Signed-off-by: Nylon Chen <nylon7@andestech.com>
Reviewed-by: Anup Patel <Anup.Patel@wdc.com>
Reviewed-by: Atish Patra <Atish.Patra@wdc.com>
2020-06-10 09:27:46 +05:30
Atish Patra
106b888e20 docs: Remove redundant documentation about combined payload use case
U-Boot now supports loading Linux kernel image via network and storage
media. Thus, we don't need to use a combined payload containing both
U-Boot & Linux kernel image to boot Linux from U-Boot prompt.

Remove the old documentation.

Signed-off-by: Atish Patra <atish.patra@wdc.com>
Reviewed-by: Anup Patel <anup.patel@wdc.com>
2020-06-08 17:04:12 +05:30
Atish Patra
79bfd67f9a docs: Use doxygen config to mark the main page
The doxygen config option "USE_MDFILE_AS_MAINPAGE" can be used to set
the main page in doxygen generated pdf. This allows us to remove the
"#mainpage" from the README file which markdown doesn't parse.

Signed-off-by: Atish Patra <atish.patra@wdc.com>
Reviewed-by: Anup Patel <anup.patel@wdc.com>
2020-06-08 17:02:41 +05:30
Anup Patel
1b8c0128f1 lib: Add RISC-V hypervisor v0.6.1 support
To support RISC-V hypervisor v0.6.1, we:
1. Don't need to explicitly forward WFI traps from VS/VU-mode
2. Have to delegate virtual instruction trap to HS-mode
3. Have to update trap redirection for changes in HSTATUS CSR

Signed-off-by: Anup Patel <anup.patel@wdc.com>
Reviewed-by: Atish Patra <atish.patra@wdc.com>
2020-06-08 15:41:23 +05:30
Anup Patel
51f0e4a053 firmware: Remove FW_PAYLOAD_FDT and related documentation
Now that no platform is using FW_PAYLOAD_FDT mechanism, we
remove related code from Makefile and related documentation.

Signed-off-by: Anup Patel <anup.patel@wdc.com>
Reviewed-by: Atish Patra <atish.patra@wdc.com>
2020-06-05 09:03:05 +05:30
Anup Patel
72019ee202 platform: kendryte/k210: Use new mechanism of builtin DTB
We update kendryte/k210 to use new mechanism of having builtin DTB
where we convert k210.dts to C source and further compile-n-link it
with libplatsbi.a.

Signed-off-by: Anup Patel <anup.patel@wdc.com>
Reviewed-by: Atish Patra <atish.patra@wdc.com>
2020-06-05 09:03:02 +05:30
Anup Patel
4e3876d5be Makefile: Add mechanism for platforms to have multiple builtin DTBs
Currently, we can only include one DTB as builtin for a platform
using FDT_PAYLOAD_DTB make variable in platform config.mk.

This patch adds new mechanism using which we can convert any DTS
file to C source and futher compile-n-link it with libplatsbi.a.

The generated C source will have the DTB contents as an array
"const char <varprefix>_start[]" where <varprefix> is specified
in platform objects.mk makefile.

Example1
--------
If we have built-in k210.dts and desired <varprefix> is
"dt_k210" then specify following in platform objects.mk:
platform-objs-y += k210.o
platform-varprefix-k210.o = dt_k210

Example2
--------
If we have built-in abc/k210.dts and desired <varprefix> is
"dt_abc_k210" then specify following in platform objects.mk:
platform-objs-y += abc/k210.o
platform-varprefix-abc-k210.o = dt_abc_k210

Signed-off-by: Anup Patel <anup.patel@wdc.com>
Reviewed-by: Atish Patra <atish.patra@wdc.com>
2020-06-05 09:02:59 +05:30
Anup Patel
c6c65ee861 Makefile: Preprocess builtin DTS
In order to use GCC style defines and macros in DTS, we should
preporcess builtin DTS before converting it to DTB.

Signed-off-by: Anup Patel <anup.patel@wdc.com>
Reviewed-by: Atish Patra <atish.patra@wdc.com>
2020-06-05 09:02:55 +05:30
Anup Patel
86ec5341e4 firmware: Allow fw_platform_init() to return updated FDT location
Currently, the fw_platform_init() does not return anything but we can
further improve by allowing fw_platform_init() to return updated FDT
location.

It is certainly not mandatory for fw_platform_init() to return a new
location of FDT (or modify FDT). In fact, the fw_platform_init() can
always return the original FDT location (i.e. 'arg1') unmodified.

This new capability of fw_platform_init() will allow platforms to:
1. Have multiple built-in FDTs and select one
2. Modify FDT before using based on platform specific straps or OTP

Signed-off-by: Anup Patel <anup.patel@wdc.com>
Reviewed-by: Atish Patra <atish.patra@wdc.com>
2020-06-05 09:02:34 +05:30
Anup Patel
4ce6b7a82a firmware: fw_base: Don't OR forced FW_OPTIONS
Currently, we are ORing FW_OPTIONS with the options passed by
previous booting stage to fw_dynamic. This causes confusion
because compiling fw_dynamic with FW_OPTIONS=0x2 does not force
enable boot prints as the U-Boot SPL passes options=0x1 in
fw_dyanmic_info.

The best thing to do is always prefer FW_OPTIONS when available.
This is intuitive for OpenSBI users and easy in debugging.

Signed-off-by: Anup Patel <anup.patel@wdc.com>
Reviewed-by: Atish Patra <atish.patra@wdc.com>
2020-06-05 09:02:32 +05:30
Anup Patel
64f140830d firmware: fw_base: Make builtin DTB available to fw_platform_init()
Currently, fw_prev_arg1() is called after fw_platform_init() which
caused builtin DTB to be not available to fw_platform_init().

To allow builtin DTB available to fw_platform_init(), we should
call fw_save_info() and fw_prev_arg1() before fw_platform_init().

Signed-off-by: Anup Patel <anup.patel@wdc.com>
Reviewed-by: Atish Patra <atish.patra@wdc.com>
2020-06-05 09:02:30 +05:30
Anup Patel
30b60401e1 Makefile: Fix builtin DTB compilation for out-of-tree platforms
The make rule for builtin DTB compilation does not consider
out-of-tree platforms so this patch fixes it.

Signed-off-by: Anup Patel <anup.patel@wdc.com>
Reviewed-by: Atish Patra <atish.patra@wdc.com>
2020-06-05 09:02:27 +05:30
Anup Patel
a63f05f3de lib: utils/timer: Initialize all matching timer DT nodes
We can have multiple matching DT nodes of the same FDT timer driver
so in this case we should call cold_init() for all matching DT nodes
instead of just first matching DT node.

Signed-off-by: Anup Patel <anup.patel@wdc.com>
Reviewed-by: Atish Patra <atish.patra@wdc.com>
2020-05-23 10:36:53 +05:30
Anup Patel
6956e83a94 lib: utils/ipi: Initialize all matching ipi DT nodes
We can have multiple matching DT nodes of the same FDT ipi driver
so in this case we should call cold_init() for all matching DT nodes
instead of just first matching DT node.

Signed-off-by: Anup Patel <anup.patel@wdc.com>
Reviewed-by: Atish Patra <atish.patra@wdc.com>
2020-05-23 10:36:49 +05:30
Anup Patel
569dd64b72 lib: utils: Add fdt_parse_clint_node() function
We add fdt_parse_clint_node() function which will be used by
fdt_ipi_clint and fdt_timer_clint drivers to parse CLINT details
from DT node.

Signed-off-by: Anup Patel <anup.patel@wdc.com>
Reviewed-by: Atish Patra <atish.patra@wdc.com>
2020-05-23 10:36:46 +05:30
Anup Patel
a9a9751185 lib: utils: Allow CLINT functions to be used for multiple CLINTs
We extend CLINT cold init function to have a "struct clint_data *"
parameter pointing to CLINT details. This allows platforms to use
CLINT functions for multiple CLINT instances.

When multiple CLINTs are present, the platform can also provide
one of the CLINT as reference CLINT for other CLINTs. This will
help CLINTs to sync their time value with reference CLINT using
a time_delta computed in warm init function.

Signed-off-by: Anup Patel <anup.patel@wdc.com>
Reviewed-by: Atish Patra <atish.patra@wdc.com>
2020-05-23 10:36:43 +05:30
Anup Patel
d30bb68448 lib: utils/irqchip: Initialize all matching irqchip DT nodes
We can have multiple matching DT nodes of the same FDT irqchip
driver so in this case we should call cold_init() for all matching
DT nodes instead of just first matching DT node.

Signed-off-by: Anup Patel <anup.patel@wdc.com>
Reviewed-by: Atish Patra <atish.patra@wdc.com>
2020-05-23 10:36:39 +05:30
Anup Patel
2c685c214f lib: utils: Extend fdt_find_match() Implementation
We extend fdt_find_match() implementation by adding node offset
parameter which represents the first node to match from.

The improved fdt_find_match() can be used to find multiple
match nodes.

Signed-off-by: Anup Patel <anup.patel@wdc.com>
Reviewed-by: Atish Patra <atish.patra@wdc.com>
2020-05-23 10:36:33 +05:30
Anup Patel
446a9c6d1e lib: utils: Allow PLIC functions to be used for multiple PLICs
We extend all PLIC functions to have a "struct plic_data *"
parameter pointing to PLIC details. This allows platforms to
use these functions for multiple PLIC instances.

Signed-off-by: Anup Patel <anup.patel@wdc.com>
Reviewed-by: Atish Patra <atish.patra@wdc.com>
2020-05-23 10:36:29 +05:30
Anup Patel
73d6ef3b29 lib: utils: Remove redundant parameters from PLIC init functions
The "target_hart" and "hart_count" parameters of PLIC cold and
warm init functions are only used for sanity checks and not
required in PLIC initialization.

Signed-off-by: Anup Patel <anup.patel@wdc.com>
Reviewed-by: Atish Patra <atish.patra@wdc.com>
2020-05-23 10:36:26 +05:30
Daniel Schaefer
89ba63493c include: sbi: Add firmware extension constants
Cc: Abner Chang <abner.chang@hpe.com>
Signed-off-by: Daniel Schaefer <git@danielschaefer.me>
Reviewed-by: Anup Patel <anup.patel@wdc.com>
2020-05-19 09:22:44 +05:30
Anup Patel
a38bea9341 lib: sbi_hart: Detect number of supported PMP regions
It is not mandatory for a RISC-V systems to implement all PMP
regions so we have to check all PMPADDRx CSRs to determine excat
number of supported PMP regions.

Signed-off-by: Anup Patel <anup.patel@wdc.com>
2020-05-19 09:19:48 +05:30
Anup Patel
2966510eed lib: sbi: Few cosmetic improvements to HART feature detection
This patch does few cosmetic improvements to HART feature detection:
1. Remove sbi_ perfix from HART feature detection functions
   because all local/static functions in sbi_hart.c don't have
   sbi_ prefix
2. Remove sbi_hart_set_feature() because it's quite small and
   local/static in sbi_hart.c

Signed-off-by: Anup Patel <anup.patel@wdc.com>
Reviewed-by: Atish Patra <atish.patra@wdc.com>
2020-05-19 09:19:44 +05:30
Anup Patel
63b0f5f71a include: sbi: Use scratch pointer as parmeter in HART feature APIs
It makes more sense to have scratch pointer as parameter in
HART feature APIs because:
1. We already have scratch pointer at places where these APIs
   are used.
2. This is consistent with lot of other APIs in sbi_hart.h

Signed-off-by: Anup Patel <anup.patel@wdc.com>
Reviewed-by: Atish Patra <atish.patra@wdc.com>
2020-05-19 09:19:42 +05:30
Anup Patel
3a8fc81357 lib: sbi: Print platform HART count just before boot HART id
On platforms with continuous HART ids starting from zero:
0 <= boot HART id < platform HART count

The above co-relation of boot HART id and platform HART count
is true for most RISC-V platfors so it's better to print platform
HART count just before boot HART id.

Signed-off-by: Anup Patel <anup.patel@wdc.com>
Reviewed-by: Atish Patra <atish.patra@wdc.com>
2020-05-19 09:19:39 +05:30
Anup Patel
3aa1036f91 lib: sbi: Remove extra spaces from boot time prints
We remove extra spaces from boot time prints.

Signed-off-by: Anup Patel <anup.patel@wdc.com>
Reviewed-by: Atish Patra <atish.patra@wdc.com>
2020-05-19 09:19:37 +05:30
Anup Patel
49841832b8 lib: sbi: Improve get_feature_str() implementation and usage
We do following improvements for get_feature_str():
1. We should return "none" from get_feature_str() no features
   available instead of sbi_boot_prints() explicitly handling
   failure.
2. We don't need to return failure (just like misa_xlen())
   because we are returning "none" for no features and we are
   truncating output when space is not available.
3. Based on 1 and 2, the sbi_boot_prints() can be further
   simplified.
4. No need for two char[] in sbi_boot_prints()

Signed-off-by: Anup Patel <anup.patel@wdc.com>
Reviewed-by: Atish Patra <atish.patra@wdc.com>
2020-05-19 09:19:34 +05:30
Anup Patel
28b4052849 lib: sbi: detect features before everything else in sbi_hart_init()
We should detect HART features in sbi_hart_init() before
mstatus_init(), delegate_traps() and pmp_init().

Signed-off-by: Anup Patel <anup.patel@wdc.com>
Reviewed-by: Atish Patra <atish.patra@wdc.com>
2020-05-19 09:19:32 +05:30
Daniel Schaefer
38a4b54cdc firmware: Correct spelling mistakes
Signed-off-by: Daniel Schaefer <git@danielschaefer.me>
Reviewed-by: Anup Patel <anup.patel@wdc.com>
2020-05-18 10:42:29 +05:30
Atish Patra
36833abfbb lib: Optimize inline assembly for unprivilege access functions
Currently, unprivileged access functions uses few additional instructions
which are redundant. It also uses specific registers which are not necessary.

Remove those additional instructions and let the compiler choose the
registers.

Signed-off-by: Atish Patra <atish.patra@wdc.com>
Reviewed-by: Anup Patel <anup.patel@wdc.com>
2020-05-16 17:52:42 +05:30
Atish Patra
22c4334f5c lib: Add hart features in boot time print
We have now clear distinction between platform and hart features.
Modify the boot print messages to print hart specific features in
a string format.

Signed-off-by: Atish Patra <atish.patra@wdc.com>
Tested-by: Jonathan Balkind <jbalkind@cs.princeton.edu>
Reviewed-by: Anup Patel <anup.patel@wdc.com>
2020-05-10 10:30:47 +05:30
Atish Patra
1f235ec47f lib: Add platform features in boot time print
We have now clear distinction between platform and hart features.
Modify the boot print messages to print platform features in a string
format. In the process, this patch moved relatively larger functions
to its own file from platform.h header file.

Signed-off-by: Atish Patra <atish.patra@wdc.com>
Tested-by: Jonathan Balkind <jbalkind@cs.princeton.edu>
Reviewed-by: Anup Patel <anup.patel@wdc.com>
2020-05-10 10:24:08 +05:30
Atish Patra
ec0d2a7d7d lib: timer: Provide a hart based timer feature
As per the RISC-V specification, time value can be obtained from a time
CSR implemented in hardware or a MMIO based IP block. Qemu virt machine
already supports timer csr while CLINT provides the timer for other
platforms.

Implement a hart specific timer feature that can be detected at runtime.
As CSR based timer implementation are faster than MMIO address based, it
is always preferred over MMIO based one.

Signed-off-by: Atish Patra <atish.patra@wdc.com>
Tested-by: Jonathan Balkind <jbalkind@cs.princeton.edu>
Reviewed-by: Anup Patel <anup.patel@wdc.com>
2020-05-10 10:14:54 +05:30
Atish Patra
4938024420 platform: fpga: Remove redundant platform specific features
Any platform feature that belongs to a hart, have already been moved to
hart features and are detected at run time. The remaining platform features
are identical to platform default features.

Use the platform default features instead of defining a separate copy of it.

Signed-off-by: Atish Patra <atish.patra@wdc.com>
Tested-by: Jonathan Balkind <jbalkind@cs.princeton.edu>
Reviewed-by: Anup Patel <anup.patel@wdc.com>
2020-05-10 10:09:29 +05:30
Atish Patra
b2df751acf platform: Move platform features to hart
PMP & performance counters belong to a hart rather than a platform.
In addition to that, these features enable reading/writing from a
particular csr. Thus, they can be detected and set at runtime rather
than compile time.

Move PMP/MCOUNTEREN/SCOUNTEREN features to hart and detect them at runtime.

Signed-off-by: Atish Patra <atish.patra@wdc.com>
Tested-by: Jonathan Balkind <jbalkind@cs.princeton.edu>
Reviewed-by: Anup Patel <anup.patel@wdc.com>
2020-05-10 10:05:41 +05:30
Atish Patra
6a053f6e6c lib: Add support for hart specific features
There may be some features which are hart specific rather than a platform
specific feature. Add a framework to support that.

Signed-off-by: Atish Patra <atish.patra@wdc.com>
Tested-by: Jonathan Balkind <jbalkind@cs.princeton.edu>
Reviewed-by: Anup Patel <anup.patel@wdc.com>
2020-05-10 10:02:49 +05:30
Atish Patra
79d0fadb06 lib: utils: Update reserved memory fdt node even if PMP is not present
As per RISC-V ISA, pmp is not mandatory. Currently, we only add reserved
memory node in DT only if PMP is present. That allows supervisor to access
the memory where OpenSBI continue to exist without realizing it for non-pmp
based platforms. It may result in corrupting OpenSBI. That's why OpenSBI
should at least let the supervisor know where it continue to exist.
This a best effort service provided by OpenSBI expecting that supervisor
software is not buggy and properly sets up its memory after parsing the
reserved-memory device tree node.

Signed-off-by: Atish Patra <atish.patra@wdc.com>
Reviewed-by: Anup Patel <anup.patel@wdc.com>
2020-05-10 10:00:02 +05:30
Atish Patra
13ca20d8df lib: Create a separate math helper function file
There may be few common mathematics helper functions which can be used
anywhere in OpenSBI project.

Add a separate math helper function file to add these functions.

Signed-off-by: Atish Patra <atish.patra@wdc.com>
Reviewed-by: Anup Patel <anup.patel@wdc.com>
2020-05-10 09:59:24 +05:30
Atish Patra
aef9a60d52 lib: Add csr detect support
As RISC-V ISA allows many CSRs such as pmp, s/mcounteren to be optional
in hardware, OpenSBI should provide an option to dynamically detect
these csr access capability at run time.

Implement a csr read/write access check helper macros.

Signed-off-by: Atish Patra <atish.patra@wdc.com>
Tested-by: Jonathan Balkind <jbalkind@cs.princeton.edu>
Reviewed-by: Anup Patel <anup.patel@wdc.com>
2020-05-10 09:59:20 +05:30
Atish Patra
63a513edec lib: Rename unprivileged trap handler
Unprivileged trap handler can be reused for any cases where the executing
code expects a trap.

Rename it to "expected" trap handler as it will be used in other cases in
future.

Signed-off-by: Atish Patra <atish.patra@wdc.com>
Tested-by: Jonathan Balkind <jbalkind@cs.princeton.edu>
Reviewed-by: Anup Patel <anup.patel@wdc.com>
2020-05-10 09:59:16 +05:30
Anup Patel
7be75f519f docs: Don't use italic text in page title
Doxygen does not support italic text in page title so fix
some of the markdown files accordingly.

Signed-off-by: Anup Patel <anup.patel@wdc.com>
Reviewed-by: Atish Patra <atish.patra@wdc.com>
2020-05-07 09:47:32 +05:30
Anup Patel
c2286b6f04 docs: Fix ordering of pages in table of contents
Currently, all markdown pages are randomly arranged in table of
contents so to fix this we treat top-level README.md as mainpage
and enable Doxygen TREEVIEW.

Also, there should not be any text before title of a markdown
page so we move project copyright as separate section in top-level
README.md.

Signed-off-by: Anup Patel <anup.patel@wdc.com>
Reviewed-by: Atish Patra <atish.patra@wdc.com>
2020-05-07 09:46:22 +05:30
Anup Patel
dfd9dd67dc docs: Add platform requirements document
We add platform requirements document to clarify OpenSBI
expectations from a RISC-V platform.

Signed-off-by: Anup Patel <anup.patel@wdc.com>
Reviewed-by: Atish Patra <atish.patra@wdc.com>
Reviewed-by: Bin Meng <bin.meng@windriver.com>
2020-05-07 09:45:52 +05:30
Anup Patel
b4efa70d12 docs: platform/generic: Add details about IPI and timer expectations
The generic platform provides IPI and timer functionality based on
DT node provided in the FDT passed by previous booting stage. This
patch updates generic platform documentation about IPI and timer
expectations.

Signed-off-by: Anup Patel <anup.patel@wdc.com>
Reviewed-by: Bin Meng <bin.meng@windriver.com>
Reviewed-by: Atish Patra <atish.patra@wdc.com>
2020-05-07 09:44:44 +05:30
Anup Patel
433bac7242 docs: platform/generic: Add details about stdout-path DT property
The generic platform will try to select serial console based on the
stdout-path DT property in /chosen DT node hence we document this.

Signed-off-by: Anup Patel <anup.patel@wdc.com>
Reviewed-by: Bin Meng <bin.meng@windriver.com>
Reviewed-by: Atish Patra <atish.patra@wdc.com>
2020-05-07 09:44:16 +05:30
Anup Patel
dc38929dfb lib: sbi: Improve misa_string() implementation
The RISC-V ISA string does not follow alphabetical order. Instead,
we have a RISC-V specific ordering of extensions in the RISC-V ISA
string. This patch improves misa_string() implementation to return
a valid RISC-V ISA string.

Signed-off-by: Anup Patel <anup.patel@wdc.com>
Reviewed-by: Atish Patra <atish.patra@wdc.com>
2020-05-07 09:08:26 +05:30
Anup Patel
5338679ff0 lib: sbi_tlb: Fix remote TLB HFENCE VVMA implementation
The HFENCE VVMA instructions flushes TLB based on the VMID
present in HGATP CSR. To handle this, we get the current
VMID for SBI HFENCE VVMA call and we use this current VMID
to do remote TLB HFENCE VVMA on desired set of HARTs.

Signed-off-by: Anup Patel <anup.patel@wdc.com>
Reviewed-by: Atish Patra <atish.patra@wdc.com>
2020-05-07 08:55:38 +05:30
Anup Patel
7993ca2c8e include: sbi: Remove redundant page table related defines
We don't have page table programming in OpenSBI so let's remove
redundant page table related defines from riscv_encoding.h.

Signed-off-by: Anup Patel <anup.patel@wdc.com>
Reviewed-by: Atish Patra <atish.patra@wdc.com>
2020-05-07 08:55:02 +05:30
Anup Patel
d626037258 docs: Add missing links in platform.md
The links to some of the platforms were missing in platform.md
file hence this patch.

Signed-off-by: Anup Patel <anup.patel@wdc.com>
Reviewed-by: Bin Meng <bin.meng@windriver.com>
Reviewed-by: Alistair Francis <alistair.francis@wdc.com>
2020-05-04 10:10:41 +05:30
Anup Patel
65c06b026d platform: Remove spike directory
The OpenSBI generic platform works perfectly fine on the QEMU spike
machine and Spike emulator so let's remove dedicated Spike platform
from OpenSBI.

All Spike platform related documentation in OpenSBI will now suggest
using OpenSBI generic platform.

Signed-off-by: Anup Patel <anup.patel@wdc.com>
Reviewed-by: Bin Meng <bin.meng@windriver.com>
Reviewed-by: Alistair Francis <alistair.francis@wdc.com>
2020-05-04 10:09:51 +05:30
Anup Patel
13717a8e53 platform: Remove qemu/virt directory
The OpenSBI generic platform works perfectly fine on the QEMU virt
machine so let's remove dedicated QEMU virt machine platform from
OpenSBI.

All QEMU virt machine related documentation in OpenSBI will now
suggest using OpenSBI generic platform.

Signed-off-by: Anup Patel <anup.patel@wdc.com>
Reviewed-by: Bin Meng <bin.meng@windriver.com>
Reviewed-by: Alistair Francis <alistair.francis@wdc.com>
2020-05-04 10:09:23 +05:30
Anup Patel
4f18c6e550 platform: generic: Add Sifive FU540 TLB flush range limit override
We need to override the remote TLB flush range limit for SiFive FU540
so we add platform override to achieve this.

Signed-off-by: Anup Patel <anup.patel@wdc.com>
Reviewed-by: Atish Patra <atish.patra@wdc.com>
2020-05-01 10:33:14 +05:30
Anup Patel
2ba7087b09 scripts: Add generic platform to create-binary-archive.sh
This patch adds generic platform to create-binary-archive.sh
script.

Signed-off-by: Anup Patel <anup.patel@wdc.com>
Reviewed-by: Atish Patra <atish.patra@wdc.com>
2020-05-01 10:33:11 +05:30
Anup Patel
1f21b99ff0 lib: sbi: Print platform hart count at boot time
Now that we have generic platform which detects hart count from
DTB, we should print platform hart count at boot time.

Signed-off-by: Anup Patel <anup.patel@wdc.com>
Reviewed-by: Atish Patra <atish.patra@wdc.com>
2020-05-01 10:33:08 +05:30
Anup Patel
f1aa9e54e0 platform: Add generic FDT based platform support
We add generic FDT based platform support which provides platform
specific functionality based on the FDT passed by previous booting
stage.

By default, the generic FDT platform makes following assumptions:
1. platform FW_TEXT_START is 0x80000000
2. platform features are default
3. platform stack size is default
4. platform has no quirks or work-arounds

The above assumptions (except 1) can be overridden by adding special
platform callbacks which will be called based on the FDT root node
compatible string.

By default, we compile OpenSBI generic platform as follows:
$ make PLATFORM=generic

For a non-standard FW_TEXT_START, we can compile OpenSBI generic
platform as follows:
$ make PLATFORM=generic FW_TEXT_START=<non_standard_text_start>

Signed-off-by: Anup Patel <anup.patel@wdc.com>
Reviewed-by: Atish Patra <atish.patra@wdc.com>
2020-05-01 10:33:05 +05:30
Anup Patel
4d063538f0 firmware: fw_base: Introduce optional fw_platform_init()
We add optional fw_platform_init() function which will allow
platform specific code to update "struct sbi_platform platform"
before it is used.

The fw_platform_init() can be a regular C function so before
callint it we:
1. zero-out BSS section
2. Setup temporary trap handler to catch bugs
3. Setup temporary stack pointer

Signed-off-by: Anup Patel <anup.patel@wdc.com>
Reviewed-by: Atish Patra <atish.patra@wdc.com>
2020-05-01 10:33:02 +05:30
Anup Patel
7cc6fa4d8a lib: utils: Add simple FDT reset framework
We add simple reset framework which will select and use reset driver
based on details in FDT passed by previous booting stage.

Signed-off-by: Anup Patel <anup.patel@wdc.com>
Reviewed-by: Atish Patra <atish.patra@wdc.com>
2020-05-01 10:31:37 +05:30
Anup Patel
76a89403c8 lib: utils: Add simple FDT serial framework
We add simple serial framework which will select and use serial driver
based on details in FDT passed by previous booting stage.

Signed-off-by: Anup Patel <anup.patel@wdc.com>
Reviewed-by: Atish Patra <atish.patra@wdc.com>
2020-05-01 10:02:39 +05:30
Anup Patel
75322a634b lib: utils: Add simple FDT irqchip framework
We add simple irqchip framework which will select and use irqchip driver
based on details in FDT passed by previous booting stage.

Signed-off-by: Anup Patel <anup.patel@wdc.com>
Reviewed-by: Atish Patra <atish.patra@wdc.com>
2020-05-01 10:00:35 +05:30
Anup Patel
76f0f81407 lib: utils: Add simple FDT ipi framework
We add simple ipi framework which will select and use ipi driver
based on details in FDT passed by previous booting stage.

Signed-off-by: Anup Patel <anup.patel@wdc.com>
Reviewed-by: Atish Patra <atish.patra@wdc.com>
2020-05-01 09:58:01 +05:30
Anup Patel
8ff2b94ea1 lib: utils: Add simple FDT timer framework
We add simple timer framework which will select and use timer driver
based on details in FDT passed by previous booting stage.

Signed-off-by: Anup Patel <anup.patel@wdc.com>
Reviewed-by: Atish Patra <atish.patra@wdc.com>
2020-05-01 09:57:55 +05:30
Anup Patel
1ac794cb61 include: Add array_size() macro
Getting array size of a dynmaic array can be very handy hence
this patch.

Signed-off-by: Anup Patel <anup.patel@wdc.com>
Reviewed-by: Alistair Francis <alistair.francis@wdc.com>
2020-05-01 09:57:24 +05:30
Anup Patel
f0eb503db4 lib: utils: Add fdt_parse_plic_node() function
We add fdt_parse_plic_node() function which will allow us to parse
a particular DT node as PLIC node. This will be useful in parsing
the DT node which we have found by matching compatible string.

Signed-off-by: Anup Patel <anup.patel@wdc.com>
Reviewed-by: Atish Patra <atish.patra@wdc.com>
2020-05-01 09:45:53 +05:30
Anup Patel
44dd7be3b2 lib: utils: Add fdt_parse_max_hart_id() API
We add fdt_parse_max_hart_id() API which return max HART id based
on CPU DT nodes. This will be used by generic FDT based drivers in
subsequent patches.

Signed-off-by: Anup Patel <anup.patel@wdc.com>
Reviewed-by: Atish Patra <atish.patra@wdc.com>
Reviewed-by: Alistair Francis <alistair.francis@wdc.com>
2020-05-01 09:44:55 +05:30
Anup Patel
19e966b862 lib: utils: Add fdt_parse_hart_id() function
Parsing HART id from a CPU DT node is a common requirement for
RISC-V systems. The newly added fdt_parse_hart_id() also helps
reduce duplicate code between fdt_cpu_fixup() function and
fdt_parse_hart_count() function.

Signed-off-by: Anup Patel <anup.patel@wdc.com>
Reviewed-by: Atish Patra <atish.patra@wdc.com>
Reviewed-by: Alistair Francis <alistair.francis@wdc.com>
2020-05-01 09:43:07 +05:30
Anup Patel
66185b3ec9 lib: utils: Add fdt_parse_sifive_uart_node() function
We add fdt_parse_sifive_uart_node() function which will allow
us to parse a particular DT node as SiFive UART node. This will
be useful in parsing the node pointed by stdout-path.

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>
2020-05-01 09:40:31 +05:30
Anup Patel
dd33b9e0a1 lib: utils: Make fdt_get_node_addr_size() public function
The fdt_get_node_addr_size() will be useful in FDT based simple
driver frameworks so we make it a public function.

Signed-off-by: Anup Patel <anup.patel@wdc.com>
Reviewed-by: Alistair Francis <alistair.francis@wdc.com>
2020-05-01 09:40:21 +05:30
Anup Patel
a39cd6fe4c lib: utils: Add FDT match table based node lookup
This patch adds FDT match table based node lookup funcitons.

These functions will be useful in implementing simple FDT
based driver frameworks.

Signed-off-by: Anup Patel <anup.patel@wdc.com>
Reviewed-by: Atish Patra <atish.patra@wdc.com>
2020-05-01 09:39:44 +05:30
Anup Patel
e3ad7c13a0 lib: utils: Rename fdt_parse_clint() to fdt_parse_compat_addr()
The fdt_parse_clint() is quite generic and can be used for other
types of devices so we rename it to fdt_parse_compat_addr().

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>
2020-05-01 09:36:13 +05:30
Anup Patel
243b0d0c0c lib: utils: Remove redundant clint_ipi_sync() declaration
The clint_ipi_sync() was removed long time back hence we remove
redundant declaration from clint.h

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>
2020-05-01 09:36:13 +05:30
Anup Patel
0a0093b0bc lib: utils: Add fdt_parse_uart8250_node() function
We add fdt_parse_uart8250_node() function which will allow us
to parse a particular DT node as UART 8250 node. This will be
useful in parsing the node pointed by stdout-path.

Signed-off-by: Anup Patel <anup.patel@wdc.com>
Reviewed-by: Atish Patra <atish.patra@wdc.com>
2020-05-01 09:36:13 +05:30
Anup Patel
01a8c8eebb lib: utils: Improve fdt_parse_uart8250() API
The information parsed by fdt_parse_uart8250() API is not complete.
We need to parse reg-shift and reg-io-width for UART 8520 as well.

Signed-off-by: Anup Patel <anup.patel@wdc.com>
Reviewed-by: Atish Patra <atish.patra@wdc.com>
Reviewed-by: Alistair Francis <alistair.francis@wdc.com>
2020-05-01 09:36:13 +05:30
Anup Patel
e6c1345f89 lib: utils/serial: Skip baudrate config if input frequency is zero
We should skip baudrate config for UART8250 and SiFive UART when
input frequency is zero.

Signed-off-by: Anup Patel <anup.patel@wdc.com>
Reviewed-by: Atish Patra <atish.patra@wdc.com>
Reviewed-by: Alistair Francis <alistair.francis@wdc.com>
2020-05-01 09:36:13 +05:30
Charles Papon
5bdf022d07 firmware: fw_base: Remove CSR_MTVEC update check
Remove unnecessary CSR_MTVEC read to reduce the openSBI CSR requirement.

Mux are costly in FPGA. Allowing CSR_MTVEC to be write only is usefull
for the FMax/Area of FPGA softcore.

https://github.com/SpinalHDL/opensbi.git branch mtvec

Signed-off-by: Charles Papon <charles.papon.90@gmail.com>
Reviewed-by: Atish Patra <atish.patra@wdc.com>
Reviewed-by: Anup Patel <anup.patel@wdc.com>
2020-05-01 09:28:38 +05:30
Huaqi Fang
3a326af9be scripts: adapt binary archive script for Nuclei UX600
Signed-off-by: Huaqi Fang <578567190@qq.com>
Reviewed-by: Anup Patel <anup.patel@wdc.com>
2020-04-30 09:39:03 +05:30
Huaqi Fang
4781545512 platform: Add Nuclei UX600 platform
* Nuclei UX600 is a 64-bit RISC-V core developed
  by Nuclei System Technology, see https://nucleisys.com/product.php

* The ISA is configurable in hardware on your demand

Signed-off-by: Huaqi Fang <578567190@qq.com>
Reviewed-by: Anup Patel <anup.patel@wdc.com>
Reviewed-by: Bin Meng <bmeng.cn@gmail.com>
2020-04-29 15:06:36 +05:30
Anup Patel
6585fabbcc lib: utils: Add SiFive test device
This patch factor-out SiFive test device related stuff into
it's own source file from qemu/virt platform. In future, we
can find SiFive test device address from device tree as well.

Signed-off-by: Anup Patel <anup.patel@wdc.com>
Reviewed-by: Atish Patra <atish.patra@wdc.com>
2020-04-27 14:37:57 +05:30
Anup Patel
a9eac67ad0 include: sbi_platform: Combine reboot and shutdown into one callback
We can achieve shutdown, cold reboot, and warm reboot using just
one sbi_platform callback so we combine system_reboot() and
system_shutdown() callbacks into one system_reset() callback.

Signed-off-by: Anup Patel <anup.patel@wdc.com>
Reviewed-by: Atish Patra <atish.patra@wdc.com>
2020-04-27 14:35:29 +05:30
Anup Patel
1bb00ab3ae lib: No need to provide default PMP region using platform callbacks
The default (usually last) PMP region provides S-mode access to
complete memory range not covered by other PMP regions.

Currently, the default PMP region is described as platform specific
PMP region which is not appropriate because all platforms need it
and default PMP region should be part of generic library.

Signed-off-by: Anup Patel <anup.patel@wdc.com>
Reviewed-by: Atish Patra <atish.patra@wdc.com>
Reviewed-by: Bin Meng <bmeng.cn@gmail.com>
2020-04-27 13:57:27 +05:30
Anup Patel
9f1b72ce66 include: Bump-up version to 0.7
This patch updates OpenSBI version to 0.7 as part of
release preparation.

Signed-off-by: Anup Patel <anup.patel@wdc.com>
2020-04-20 16:28:42 +05:30
Anup Patel
66d018499c lib: Allow overriding SBI implementation ID
Ideally, the SBI implementation ID for OpenSBI should always be
0x1 (as mentioned in SBI v0.2 spec) but external firmware (such
as EDK2) which use OpenSBI as library might want to override the
SBI implementation ID with their custom implementation ID.

Signed-off-by: Anup Patel <anup.patel@wdc.com>
Reviewed-by: Bin Meng <bmeng.cn@gmail.com>
Reviewed-by: Atish Patra <atish.patra@wdc.com>
2020-04-19 17:00:05 +05:30
Atish Patra
615587c336 docs: Update README about supported SBI versions
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>
2020-04-17 09:32:06 +05:30
Atish Patra
6c7922e23b lib: Support vector extension
Enable vector context in mstatus by updating the corresponding bits
in mstatus if vector extension is supported by the hart.

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>
2020-04-17 09:30:17 +05:30
Atish Patra
f281de885e lib: irqchip/plic: Fix maximum priority threshold value
As per the PLIC specification, maximum priority threshold value is 0x7.
Even though, writing a higher value doesn't cause any error in qemu
hifive unleashed, there may be some implementation which checks the upper
and may result in an illegal access.

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>
2020-04-06 08:58:56 +05:30
Liu Yibin
e5a7f556ce platform: thead/c910: Use HSM extension to boot secondary cores
Remove custom vendor extension and use HSM extension
to boot secondary cores

Signed-off-by: Liu Yibin <yibin_liu@c-sky.com>
Reviewed-by: Anup Patel <anup.patel@wdc.com>
Reviewed-by: Bin Meng <bmeng.cn@gmail.com>
2020-03-28 13:41:03 +05:30
Anup Patel
648507a867 include: sbi_console: Remove scratch parameter from sbi_dprintf()
This patch removes scratch parameter from sbi_dprintf() function
because sbi_dprintf() can use sbi_scratch_thishart_ptr() to get
current HART scratch space.

Signed-off-by: Anup Patel <anup.patel@wdc.com>
Reviewed-by: Atish Patra <atish.patra@wdc.com>
2020-03-28 13:32:58 +05:30
Anup Patel
0a28ea54dc include: sbi_timer: Remove scratch parameter from most funcitons
This patch removes scratch parameter from most sbi_timer functions.

Signed-off-by: Anup Patel <anup.patel@wdc.com>
Reviewed-by: Atish Patra <atish.patra@wdc.com>
2020-03-28 13:32:55 +05:30
Anup Patel
ec0d80f5b4 include: sbi_system: Remove scratch parameter and redundant functions
This patch removes scratch parameter and redundant functions from
sbi_system.

Signed-off-by: Anup Patel <anup.patel@wdc.com>
Reviewed-by: Atish Patra <atish.patra@wdc.com>
2020-03-28 13:32:52 +05:30
Anup Patel
9e52a45f4b include: sbi_ipi: Remove scratch parameter from most functions
This patch removes scratch parameter from most sbi_ipi functions.

Signed-off-by: Anup Patel <anup.patel@wdc.com>
Reviewed-by: Atish Patra <atish.patra@wdc.com>
2020-03-28 13:32:47 +05:30
Anup Patel
54b2779cfe include: sbi_tlb: Remove scratch parameter from sbi_tlb_request()
The sbi_ipi_send_many() should get current HART scratch pointer
on it's own using eventually hence removing scratch parameter from
sbi_tlb_request().

Signed-off-by: Anup Patel <anup.patel@wdc.com>
2020-03-28 13:32:44 +05:30
Anup Patel
dd0f21c560 lib: sbi_scratch: Introduce sbi_scratch_last_hartid() API
The patch adds sbi_scratch_last_hartid() API which returns
last HART id having a scratch space. We can use this new API
to optimize places where we iterate over HART id from 0 to
SBI_HARTMASK_MAX_BITS.

Signed-off-by: Anup Patel <anup.patel@wdc.com>
Reviewed-by: Atish Patra <atish.patra@wdc.com>
2020-03-28 13:32:41 +05:30
Anup Patel
5b6957eed7 include: Use more consistent name for atomic xchg() and cmpxchg()
We should remove the "arch_" prefix from atomic xchg() and cmpxchg()
function names to have consistent naming of all atomic functions.

Signed-off-by: Anup Patel <anup.patel@wdc.com>
Reviewed-by: Atish Patra <atish.patra@wdc.com>
2020-03-28 13:32:38 +05:30
Anup Patel
7b211ff924 include: sbi_platform: Remove priv parameter from hart_start() callback
The priv parameter in hart_start() platform callback is redundant hence
we remove it.

Signed-off-by: Anup Patel <anup.patel@wdc.com>
Reviewed-by: Atish Patra <atish.patra@wdc.com>
2020-03-28 13:32:26 +05:30
Anup Patel
40b221baff lib: sbi_trap: Simplify sbi_trap_handler() API
This patch simplify sbi_trap_handler() API as follows:
1. Remove current hartid local variable because sbi_trap_handler()
   itself does not need it.
2. Remove scratch parameter because none of the functions directly
   called by sbi_trap_handler() require it.

Signed-off-by: Anup Patel <anup.patel@wdc.com>
Reviewed-by: Atish Patra <atish.patra@wdc.com>
2020-03-28 13:32:23 +05:30
Anup Patel
7487116b41 lib: sbi_ecall: Remove mcause, scratch and hartid parameters
We remove mcause, scratch and hartid parameters from various
functions for ecall handling because we can always get current
HART id and current scratch pointer using just one CSR access.

Signed-off-by: Anup Patel <anup.patel@wdc.com>
Reviewed-by: Atish Patra <atish.patra@wdc.com>
2020-03-28 13:32:20 +05:30
Anup Patel
fe37d7da29 lib: sbi_misaligned_ldst: Remove mcause, scratch and hartid parameters
We remove mcause, scratch and hartid parameters from various functions
for misaligned load/store handling because we can always get current
HART id and current scratch pointer using just one CSR access.

Signed-off-by: Anup Patel <anup.patel@wdc.com>
Reviewed-by: Atish Patra <atish.patra@wdc.com>
2020-03-28 13:32:14 +05:30
Anup Patel
5a7bd0c88d lib: sbi_illegal_insn: Remove mcause, scratch and hartid parameters
We remove mcause, scratch and hartid parameters from various
functions for illegal instruction handling because we can always
get current HART id and current scratch pointer using just one
CSR access.

Signed-off-by: Anup Patel <anup.patel@wdc.com>
Reviewed-by: Atish Patra <atish.patra@wdc.com>
2020-03-28 13:32:11 +05:30
Anup Patel
d11c79cd97 lib: sbi_emulate_csr: Remove scratch and hartid parameter
We remove scratch and hartid parameter from various functions
for CSR emulation because we can always get current HART id
and current scratch pointer using just one CSR access.

Signed-off-by: Anup Patel <anup.patel@wdc.com>
Reviewed-by: Atish Patra <atish.patra@wdc.com>
2020-03-28 13:32:07 +05:30
Anup Patel
cb78a48231 lib: sbi_trap: Remove scratch parameter from sbi_trap_redirect()
The scratch parameter of sbi_trap_redirect() is not used hence we
remove it.

Signed-off-by: Anup Patel <anup.patel@wdc.com>
Reviewed-by: Atish Patra <atish.patra@wdc.com>
2020-03-28 13:32:04 +05:30
Anup Patel
626467cfd9 lib: Remove scratch parameter from unpriv load/store functions
The scratch parameter of unpriv load/store functions is now redundant
hence we remove it.

Signed-off-by: Anup Patel <anup.patel@wdc.com>
Reviewed-by: Atish Patra <atish.patra@wdc.com>
2020-03-28 13:32:01 +05:30
Anup Patel
1de66d170e lib: Optimize unpriv load/store implementation
This patch optimize unpriv load/store implementation by having
dedicated unpriv trap handler (just like KVM RISC-V).

As a result of this optimization:
1. We have reduced roughly 13+ instruction in all unpriv load/store
   functions. The reduced instruction also include two function calls.
2. Per-HART trap info pointer in scratch space is now redundant
   hence removed.
3. The sbi_trap_handler() is now much cleaner because we don't have
   to handle unpriv load/store traps.

Signed-off-by: Anup Patel <anup.patel@wdc.com>
Reviewed-by: Atish Patra <atish.patra@wdc.com>
2020-03-28 13:31:53 +05:30
Anup Patel
160c88535f lib: utils: Improve fdt_cpu_fixup() implementation
Currently, the fdt_cpu_fixup() implementation assumes:
1. We have one CPU DT for each HART under /cpus DT node
2. The CPU DT nodes are named sequentially (i.e cpu@0,
   cpu@1, ...) which is not true for discontinuous and
   sparse HART ids (i.e. cpu@0, cpu@4, cpu@5). Generally,
   CPU DT node are named based on HART id and not HART
   index

If any of the above assumptions are violated then the
fdt_cpu_fixup() will not work.

This improves fdt_cpu_fixup() implementation and makes
it independent of above assumptions.

Signed-off-by: Anup Patel <anup.patel@wdc.com>
Reviewed-by: Bin Meng <bmeng.cn@gmail.com>
Reviewed-by: Atish Patra <atish.patra@wdc.com>
2020-03-28 13:31:50 +05:30
Anup Patel
550ba88db1 scripts: Extend create-binary-archive.sh for unified binary tar ball
This patch extends/revamps create-binary-archive.sh to allow creating
unified binary tar ball containing both RV32 and RV64 images. Users
can also create "RV32 only" or "RV64 only" tar balls as well.

Few example commands are as follows:
./scripts/create-binary-archive.sh (Build both RV32 & RV64 images)
./scripts/create-binary-archive.sh -x 32 (Build RV32 only images)
./scripts/create-binary-archive.sh -x 64 (Build RV64 only images)

Signed-off-by: Anup Patel <anup.patel@wdc.com>
2020-03-28 13:31:47 +05:30
Xiang Wang
4d93586bfa lib: prevent coldboot_lottery from overflowing
HSM_STOP will trigger multiple executions of sbi_init, atomic_add_return may
trigger coldboot_lottery overflow

Signed-off-by: Xiang Wang <merle@hardenedlinux.org>
Reviewed-by: Anup Patel <anup.patel@wdc.com>
2020-03-26 17:32:34 +05:30
Atish Patra
4c374511fd platform: openpiton: Read the device configurations from device tree
OpenPiton is designed to run on different FPGAs with different
configurations. Use the fdt parser to retrieve the required values
from device tree instead of using fixed values.

Signed-off-by: Atish Patra <atish.patra@wdc.com>
Tested-by: Jonathan Balkind <jbalkind@cs.princeton.edu>
Reviewed-by: Anup Patel <anup.patel@wdc.com>
2020-03-24 13:33:39 +05:30
Atish Patra
040e4e2ec2 lib: utils: Move fdt fixup helper routines to a different file
FDT helper file contain both fdt fixup and parsing functions.

Split the fixup related functions to a separate file for a better code
organization.

Signed-off-by: Atish Patra <atish.patra@wdc.com>
Reviewed-by: Anup Patel <anup.patel@wdc.com>
2020-03-24 13:30:32 +05:30
Atish Patra
d1d6560a87 platform: fpga/common: Add a fdt parsing helper functions
Different DT based platforms from the sam family may reuse IP blocks with
different configurations. These different configurations can be obtained
by parsing the device tree.

Add a FDT parser framework that can parse various device configurations from
device tree. Currently, the parsing algorithms doesn't cover all the use cases
or possible combination of DT configurations. It will be improved over time.

Signed-off-by: Atish Patra <atish.patra@wdc.com>
Reviewed-by: Anup Patel <anup.patel@wdc.com>
2020-03-24 13:29:07 +05:30
Atish Patra
fb84879e66 platform: Add OpenPiton platform support
OpenPiton is a research platform from Princeton University [1].

"OpenPiton is the world's first open source, general purpose,
multithreaded manycore processor. It is a tiled manycore
framework scalable from one to 1/2 billion cores."

Add OpenSBI support for OpenPiton. As it is based on ariane core,
it reuses the platform code from arine project.

[1]. https://github.com/PrincetonUniversity/openpiton

Signed-off-by: Atish Patra <atish.patra@wdc.com>
Reviewed-by: Anup Patel <anup.patel@wdc.com>
2020-03-24 13:18:38 +05:30
Atish Patra
ed265b4498 platform: fpga/ariane: Remove redundant plic address macros
All the common PLIC specific macros are already defined in plic.c.

Remove it from platform code. While at it, Fix the other coding style
issues.

Signed-off-by: Atish Patra <atish.patra@wdc.com>
Reviewed-by: Anup Patel <anup.patel@wdc.com>
2020-03-24 13:15:52 +05:30
Atish Patra
5968894842 platform: Move ariane standalone fpga project to its own project
Signed-off-by: Atish Patra <atish.patra@wdc.com>
Reviewed-by: Anup Patel <anup.patel@wdc.com>
2020-03-24 13:12:17 +05:30
Atish Patra
9a74a64ae0 lib: Check MSIP bit after returning from WFI
Commit 71d2b837c4 (lib: Move all coldboot wait APIs to sbi_init.c)
caused a regression while moving the code from sbi_hart.c to sbi_init.c.

As per original commit text, WFI can be implemented as a NOP according
to the RISC-V privilege specification. Software should ensure that
relevant interrupt pending bits are set. Otherwise, loop back to WFI.
Fix the regression by applying the original patch to sbi_init.c.

Fixes: 71d2b837c4 ("lib: Move all coldboot wait APIs to sbi_init.c")

Signed-off-by: Atish Patra <atish.patra@wdc.com>
Reviewed-by: Anup Patel <anup.patel@wdc.com>
2020-03-21 09:21:47 +05:30
Xiang Wang
a0c88ddb31 lib: Fix sbi_ecall_register_extension to prevent extension IDs overlap
The original code does not prevent the following scenarios:
> sbi_ecall_register_extension(ext1); /* extension id (70-80) */
> sbi_ecall_register_extension(ext2); /* extension id (50-100) */

Signed-off-by: Xiang Wang <merle@hardenedlinux.org>
Reviewed-by: Anup Patel <anup.patel@wdc.com>
2020-03-19 10:16:17 +05:30
Anup Patel
315a87710f platform: sifive/fu540: Remove FU540_ENABLED_HART_MASK option
The FU540_ENABLED_HART_MASK compile time option was added for initial
bring-up on SiFive Unleashed. This option is redundant now because
disabled_hart_mask is already removed. Based on this rationale, we
remove FU540_ENABLED_HART_MASK compile time option.

Signed-off-by: Anup Patel <anup.patel@wdc.com>
Reviewed-by: Bin Meng <bmeng.cn@gmail.com>
Reviewed-by: Atish Patra <atish.patra@wdc.com>
2020-03-19 09:32:45 +05:30
Anup Patel
c51f02cf14 include: sbi_platform: Introduce HART index to HART id table
A platform can have discontinuous and/or sparse HART ids so we
cannot always assume a set of HARTs with continuous HART ids.

This patch adds support for discontinuous and sparse HART ids by
introducing HART index to HART id table. This table has platform
hart_count entries and it maps HART index to HART id.

The HART index to HART id table has only two restrictions:
1. HART index < sbi_platform hart_count
2. HART id < SBI_HARTMASK_MAX_BITS

Example1:
Let's say we have a platform with 2 HART ids 11 and 22, for such a
a platform:
hart_count = 2
hart_index2id[0] = 11
hart_index2id[1] = 22

Example2:
Let's say we have a platform with 5 HARTs ids 0, 1, 2, 3, and 4
but out of these HART with id 0 is not usable so for such a platform:
hart_count = 5
hart_index2id[0] = -1U
hart_index2id[1] = 1
hart_index2id[2] = 2
hart_index2id[3] = 3
hart_index2id[4] = 4
OR
hart_count = 4
hart_index2id[0] = 1
hart_index2id[1] = 2
hart_index2id[2] = 3
hart_index2id[3] = 4

With HART index to HART id table in place, the hart_disabled()
callback is now redundant so we remove it as well.

Signed-off-by: Anup Patel <anup.patel@wdc.com>
Reviewed-by: Bin Meng <bmeng.cn@gmail.com>
Reviewed-by: Atish Patra <atish.patra@wdc.com>
2020-03-19 09:30:01 +05:30
Anup Patel
75eec9dd3f lib: Don't use sbi_platform_hart_count() API
We don't need to use sbi_platform_hart_count() in sbi_init and
sbi_scratch because checking sbi_platform_hart_disabled() or
return value of sbi_hartid_to_scratch() is sufficient.

Signed-off-by: Anup Patel <anup.patel@wdc.com>
Reviewed-by: Bin Meng <bmeng.cn@gmail.com>
Reviewed-by: Atish Patra <atish.patra@wdc.com>
2020-03-19 09:27:51 +05:30
Anup Patel
814f38dc1d lib: sbi_hsm: Don't use sbi_platform_hart_disabled() API
Checking return value of sbi_hartid_to_scratch() is sufficient
so no need to explicitly check for disabled HART using the
sbi_platform_hart_disabled() API.

Signed-off-by: Anup Patel <anup.patel@wdc.com>
Reviewed-by: Bin Meng <bmeng.cn@gmail.com>
Reviewed-by: Atish Patra <atish.patra@wdc.com>
2020-03-19 09:26:25 +05:30
Anup Patel
db187d616c lib: sbi_hsm: Remove scratch parameter from hart_started_mask() API
The scratch parameter in sbi_hsm_hart_started_mask() API is now
redundant hence removing it.

Signed-off-by: Anup Patel <anup.patel@wdc.com>
Reviewed-by: Bin Meng <bmeng.cn@gmail.com>
Reviewed-by: Atish Patra <atish.patra@wdc.com>
2020-03-19 09:23:12 +05:30
Anup Patel
680b09872d lib: sbi_hsm: Don't use sbi_platform_hart_count() API
We remove usage of sbi_platform_hart_count() API from sbi_hsm
so that discontinuous and sparse HART ids can be supported.

Signed-off-by: Anup Patel <anup.patel@wdc.com>
Reviewed-by: Bin Meng <bmeng.cn@gmail.com>
2020-03-19 09:21:08 +05:30
Anup Patel
c9f60fc6b7 lib: sbi_scratch: Don't set hartid_to_scratch table for disabled HART
As a step towards supporting discontinuous and sparse HART ids, we
don't set hartid_to_scratch table for disabled HARTs.

Signed-off-by: Anup Patel <anup.patel@wdc.com>
Reviewed-by: Bin Meng <bmeng.cn@gmail.com>
Reviewed-by: Atish Patra <atish.patra@wdc.com>
2020-03-19 09:17:08 +05:30
Anup Patel
bd6ef02d47 include: sbi_platform: Improve sbi_platform_hart_disabled() API
The sbi_platform_hart_disabled() should return TRUE for HART id
greater than platform hart count.

Signed-off-by: Anup Patel <anup.patel@wdc.com>
Reviewed-by: Bin Meng <bmeng.cn@gmail.com>
2020-03-19 09:15:29 +05:30
Anup Patel
209134d8f9 lib: Handle failure of sbi_hartid_to_scratch() API
The sbi_hartid_to_scratch() API can fail for non-existent HARTs so
all uses of sbi_hartid_to_scratch() API should check return value.

Signed-off-by: Anup Patel <anup.patel@wdc.com>
Reviewed-by: Bin Meng <bmeng.cn@gmail.com>
Reviewed-by: Atish Patra <atish.patra@wdc.com>
2020-03-19 09:11:12 +05:30
Anup Patel
3ebfe0ec5d lib: sbi_tlb: Simplify sbi_tlb_entry_process() function
We remove redundant scratch parameter from sbi_tlb_entry_process()
function.

Signed-off-by: Anup Patel <anup.patel@wdc.com>
Reviewed-by: Bin Meng <bmeng.cn@gmail.com>
Reviewed-by: Atish Patra <atish.patra@wdc.com>
2020-03-19 09:09:45 +05:30
Anup Patel
19bd531a15 lib: sbi_hsm: Simplify hart_get_state() and hart_started() APIs
We remove redundant scratch parameter from sbi_hsm_hart_get_state()
and sbi_hsm_hart_started() APIs.

Signed-off-by: Anup Patel <anup.patel@wdc.com>
Reviewed-by: Bin Meng <bmeng.cn@gmail.com>
Reviewed-by: Atish Patra <atish.patra@wdc.com>
2020-03-19 09:08:26 +05:30
Anup Patel
e23d3ba936 include: Simplify HART id to scratch macro
This patch simplify HART id to scratch macro as follows:
1. Remove current "scratch" pointer argument because now we
   use HART id to scratch table
2. Rename sbi_hart_id_to_scratch() to sbi_hartid_to_scratch()
   to have macro name consistent with the name of callback
   in struct sbi_scratch

Signed-off-by: Anup Patel <anup.patel@wdc.com>
Reviewed-by: Bin Meng <bmeng.cn@gmail.com>
Reviewed-by: Atish Patra <atish.patra@wdc.com>
2020-03-19 09:04:29 +05:30
Anup Patel
87a7ef7659 lib: sbi_scratch: Introduce HART id to scratch table
Instead of calling hartid_to_scratch() callback every time when
we want sbi_scratch pointer from HART id, we create a table of
sbi_scratch pointers and use that to get sbi_scratch pointer.

As a result of HART id to scratch table, the conversion of
HART id to sbi_scratch pointer is just 2-3 instructions which
was 9 instructions previously.

Signed-off-by: Anup Patel <anup.patel@wdc.com>
Reviewed-by: Bin Meng <bmeng.cn@gmail.com>
Reviewed-by: Atish Patra <atish.patra@wdc.com>
2020-03-19 09:02:23 +05:30
Bin Meng
3f8d754c2c platform: Update to call general DT fix-up helper
Platform andes/ae350, ariane-fpga, qemu/virt and sifive/fu540 codes
have been updated to call this general DT fix-up helper.

Signed-off-by: Bin Meng <bmeng.cn@gmail.com>
Reviewed-by: Anup Patel <anup.patel@wdc.com>
2020-03-18 11:09:31 +05:30
Bin Meng
db6a2b5c68 lib: utils: Add a general device tree fix-up helper
This adds a general device tree fix-up helper to do all required
device tree fix-ups for a typical platform.

Signed-off-by: Bin Meng <bmeng.cn@gmail.com>
Reviewed-by: Anup Patel <anup.patel@wdc.com>
2020-03-18 11:04:48 +05:30
Bin Meng
3f1c847d1f platform: sifive/fu540: Replace cpu0 node fix-up with the new helper
This replaces the FU540 specific cpu0 node "status" property fix-up
with the newly introduced generic fdt_cpu_fixup() helper.

Unlike previous logic, the helper routine does not test the "mmu-type"
property to determine which node we should fix up, instead it uses
sbi_platform_hart_disabled() API.

Signed-off-by: Bin Meng <bmeng.cn@gmail.com>
Reviewed-by: Anup Patel <anup.patel@wdc.com>
2020-03-18 10:56:43 +05:30
Bin Meng
dd9439fbac lib: utils: Add a fdt_cpu_fixup() helper
Add a helper routine to updates the "status" property of a CPU node
in the device tree to "disabled" if that hart is in disabled state.

Signed-off-by: Bin Meng <bmeng.cn@gmail.com>
Reviewed-by: Anup Patel <anup.patel@wdc.com>
2020-03-18 10:43:53 +05:30
Bin Meng
1071f05663 platform: sifive/fu540: Remove "stdout-path" fix-up
As of today the upstream U-Boot & Linux kernel ships a device tree
that already has "stdout-path" properly set in the "/chosen" node.
This is the same with the QEMU 'sifive_u' machine. Hence the codes
to fix up the "stdout-path" in OpenSBI is not necessary.

Signed-off-by: Bin Meng <bmeng.cn@gmail.com>
Reviewed-by: Atish Patra <atish.patra@wdc.com>
2020-03-18 10:02:08 +05:30
Bin Meng
6f9bb83c1f platform: sifive/fu540: Fix up DT for reserved memory
This calls fdt_reserved_memory_fixup() helper in the platform's
final_init() routine.

Signed-off-by: Bin Meng <bmeng.cn@gmail.com>
Reviewed-by: Atish Patra <atish.patra@wdc.com>
2020-03-18 10:00:30 +05:30
Bin Meng
c9a526877c platform: qemu/virt: Fix up DT for reserved memory
This calls fdt_reserved_memory_fixup() helper in the platform's
final_init() routine.

Signed-off-by: Bin Meng <bmeng.cn@gmail.com>
Reviewed-by: Anup Patel <anup.patel@wdc.com>
2020-03-18 09:54:07 +05:30
Bin Meng
8135520e6f platform: ariane-fpga: Fix up DT for reserved memory
This calls fdt_reserved_memory_fixup() helper in the platform's
final_init() routine.

Signed-off-by: Bin Meng <bmeng.cn@gmail.com>
Reviewed-by: Atish Patra <atish.patra@wdc.com>
2020-03-18 09:52:51 +05:30
Bin Meng
e846ce1681 platform: andes/ae350: Fix up DT for reserved memory
This calls fdt_reserved_memory_fixup() helper in the platform's
final_init() routine.

Signed-off-by: Bin Meng <bmeng.cn@gmail.com>
Reviewed-by: Atish Patra <atish.patra@wdc.com>
2020-03-18 09:51:55 +05:30
Bin Meng
6af55769eb lib: utils: Move PLIC DT fix up codes to fdt_helper.c
Now that we have a dedicated fdt_helper.c file for DT releated
helper routines, move plic_fdt_fixup() codes from plic.c to
fdt_helper.c and rename it to fdt_plic_fixup() at the same time,
to keep name consistency in the same file.

Signed-off-by: Bin Meng <bmeng.cn@gmail.com>
Reviewed-by: Atish Patra <atish.patra@wdc.com>
2020-03-18 09:40:14 +05:30
Bin Meng
666be6d62b platform: Clean up include header files
Adjust the order of include header files in alphabetical order in
platform codes. Also remove unnecessary inclusions.

Signed-off-by: Bin Meng <bmeng.cn@gmail.com>
Reviewed-by: Atish Patra <atish.patra@wdc.com>
2020-03-18 09:31:39 +05:30
Bin Meng
fcb1dedb2d lib: utils: Add a fdt_reserved_memory_fixup() helper
Add a helper routine to insert a child node of the reserved memory
node in the device tree that describes the protected memory region
done by OpenSBI via PMP.

Signed-off-by: Bin Meng <bmeng.cn@gmail.com>
Reviewed-by: Atish Patra <atish.patra@wdc.com>
2020-03-18 09:19:44 +05:30
Bin Meng
dce88467af libfdt: Compile fdt_addresses.c
Pull fdt_addresses.o in for fdt_address_cells() & fdt_size_cells().

Signed-off-by: Bin Meng <bmeng.cn@gmail.com>
Reviewed-by: Atish Patra <atish.patra@wdc.com>
2020-03-18 09:08:33 +05:30
Bin Meng
5fbcd625bc lib: sbi: Update pmp_get() to return decoded size directly
Currently pmp_get() returns the log2 length of the PMP memory
region size. The caller has to calculate the size based on that
and the same codes are duplicated.

Update this function to return decoded size directly.

Signed-off-by: Bin Meng <bmeng.cn@gmail.com>
Reviewed-by: Atish Patra <atish.patra@wdc.com>
2020-03-18 08:58:26 +05:30
Bin Meng
327ba36211 scripts: Cover sifive/fu540 in the 32-bit build
We now support building sifive/fu540 as a 32-bit platform. Add it
in the 32-bit platform list of binary archive script.

Signed-off-by: Bin Meng <bmeng.cn@gmail.com>
Reviewed-by: Anup Patel <anup.patel@wdc.com>
2020-03-17 10:32:08 +05:30
Bin Meng
72a0628c7e platform: Use one unified per-HART stack size macro for all platforms
As of today all platforms use 8KB of per-HART stack hence there is
no need for each platform to define its own macro or use the magic
number. Create one macro for all platforms. Platform still can use
its own version if needed.

Signed-off-by: Bin Meng <bmeng.cn@gmail.com>
Reviewed-by: Anup Patel <anup.patel@wdc.com>
2020-03-14 09:14:00 +05:30
Bin Meng
2343efd040 platform: Set per-HART stack size to 8KB in the template platform codes
The template platform codes should set per-HART stack size to 8KB
to avoid possible mistakes of future platform ports.

Signed-off-by: Bin Meng <bmeng.cn@gmail.com>
Reviewed-by: Anup Patel <anup.patel@wdc.com>
2020-03-14 09:13:20 +05:30
Bin Meng
9275ed3949 platform: ariane-fpga: Set per-HART stack size to 8KB
Recent commit

  4a603eb ("platform: kendryte/k210: Set per-HART stack size to 8KB")

forgot to update ariane-fpga codes, and the following commit

  678c3c3 ("include: sbi_scratch: Set per-HART scratch size to 4KB")

changed the per-HART scratch size to 4KB, which potentially breaks
ariane-fpga platform.

This patch set per-HART stack size of ariane-fpga to 8KB for consistency.

Signed-off-by: Bin Meng <bmeng.cn@gmail.com>
Reviewed-by: Anup Patel <anup.patel@wdc.com>
2020-03-14 09:12:47 +05:30
Anup Patel
9aabba2665 Makefile: Fix distclean make target
The default install directory is not being removed correctly by
distclean make target due to recent changes. This patch fixes
distclean make target to fix default install directory removal.

Fixes: 82ae8e8fe2 ("makefile: Do setup of the install target
more flexible")
Signed-off-by: Anup Patel <anup.patel@wdc.com>
Reviewed-by: Atish Patra <atish.patra@wdc.com>
2020-03-13 12:22:34 +05:30
Anup Patel
823345ecae include: Make sbi_current_hartid() as macro in riscv_asm.h
The sbi_current_hartid() being a regular function is quite
expensive because for callers it is a function call instead
of a direct CSR read. This patch converts sbi_current_hartid()
into a macro in riscv_asm.h.

Signed-off-by: Anup Patel <anup.patel@wdc.com>
Reviewed-by: Atish Patra <atish.patra@wdc.com>
2020-03-13 12:22:02 +05:30
Anup Patel
16e7071f6d lib: sbi_hsm: Optimize sbi_hsm_hart_get_state() implementation
Now that sbi_hart_id_to_scratch() is optimized, we don't need
the "if ()" statement. Also, the hstate local variable is
redundant so we remove that as well.

Signed-off-by: Anup Patel <anup.patel@wdc.com>
Reviewed-by: Atish Patra <atish.patra@wdc.com>
2020-03-13 12:19:36 +05:30
Anup Patel
eeae3d9582 firmware: fw_base: Optimize _hartid_to_scratch() implementation
This patch optimizes _hartid_to_scratch() in following ways:
1. Use caller saved registers instead of callee saved registers
   so that we don't need to save/restore registers on stack
2. Remove second redundant mul instruction by re-arranging
   instructions

Overall, we reduce 9 instructions in _hartid_to_scratch()
implementation.

Signed-off-by: Anup Patel <anup.patel@wdc.com>
Reviewed-by: Atish Patra <atish.patra@wdc.com>
Reviewed-by: Bin Meng <bmeng.cn@gmail.com>
2020-03-13 12:18:51 +05:30
Anup Patel
f92147c2b2 include: Make sbi_hart_id_to_scratch() as macro
The sbi_hart_id_to_scratch() just forwards call to firmware specific
hartid_to_scratch() callback so we make sbi_hart_id_to_scratch() as
macro in sbi_scratch.h instead of regular function in sbi_hart.c.

Signed-off-by: Anup Patel <anup.patel@wdc.com>
Reviewed-by: Atish Patra <atish.patra@wdc.com>
Reviewed-by: Bin Meng <bmeng.cn@gmail.com>
2020-03-13 12:18:07 +05:30
Bin Meng
baac7e066d libfdt: Upgrade to v1.5.1 release
Sync with latest libfdt v1.5.1 release source codes.

Signed-off-by: Bin Meng <bmeng.cn@gmail.com>
Reviewed-by: Anup Patel <anup.patel@wdc.com>
2020-03-13 10:28:11 +05:30
Bin Meng
0cfe49ad63 libfdt: Add INT32_MAX and UINT32_MAX in libfdt_env.h
Add two macros in preparation to sync libfdt codes to latest v1.5.1
release from upstream.

Signed-off-by: Bin Meng <bmeng.cn@gmail.com>
Reviewed-by: Anup Patel <anup.patel@wdc.com>
2020-03-13 10:23:31 +05:30
Bin Meng
4b2f594b85 sbi: Add definitions for true/false
We currently have TRUE/FALSE, but it could be convenient to have
true/false as well.

Signed-off-by: Bin Meng <bmeng.cn@gmail.com>
Reviewed-by: Anup Patel <anup.patel@wdc.com>
2020-03-13 10:20:37 +05:30
Panagiotis Peristerakis
ffdc858f72 platform: ariane-fpga: Change license for ariane-fpga from GPL-2.0 to BSD-2
Signed-off-by: Panagiotis Peristerakis <perister@ics.forth.gr>
Reviewed-by: Bin Meng <bmeng.cn@gmail.com>
Reviewed-by: Anup Patel <anup.patel@wdc.com>
2020-03-13 10:09:53 +05:30
Damien Le Moal
86d37bbd7d lib: sbi: Fix misaligned trap handling
Compile time checks of __riscv_compressed can only check if OpenSBI is
being compiled using compressed instructions or not. Checking this macro
does not indicate if an instruction that generated a misaligned trap is
a compressed instruction or not.

Since the misaligned trap handling code inspects instructions _C_ bits
to detect compressed instructions, we can remove all static checks on
__riscv_compressed and dissociate hanlding of misaligned traps and
OpenSBI compilation.

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>
2020-03-13 10:02:42 +05:30
Atish Patra
757bb44e6e docs: Remove out-of-date documentation
Upstream U-Boot now have SMP support and doesn't require any additional
patches for HiFive Unleashed.

Update the documentation.

Signed-off-by: Atish Patra <atish.patra@wdc.com>
Reviewed-by: Anup Patel <anup.patel@wdc.com>
Reviewed-by: Bin Meng <bmeng.cn@gmail.com>
2020-03-11 17:09:36 +05:30
Anup Patel
eede1aa7c7 lib: sbi_hart: Remove HART available mask and related APIs
The HART available mask and related APIs are now totally redundant
because of more extensive HART state machine implemented by sbi_hsm.

Due to above, we remove HART available mask and related APIs.

Signed-off-by: Anup Patel <anup.patel@wdc.com>
Reviewed-by: Bin Meng <bmeng.cn@gmail.com>
2020-03-11 15:30:30 +05:30
Anup Patel
9aad831e87 lib: sbi_ipi: Use sbi_hsm_hart_started_mask() API
This patch replaces use of sbi_hart_available_mask() API with
sbi_hsm_hart_started_mask() API.

Signed-off-by: Anup Patel <anup.patel@wdc.com>
Reviewed-by: Bin Meng <bmeng.cn@gmail.com>
2020-03-11 15:30:26 +05:30
Anup Patel
466fecb957 lib: sbi_system: Use sbi_hsm_hart_started_mask() API
This patch replaces use of sbi_hart_available_mask() API with
sbi_hsm_hart_started_mask() API.

Signed-off-by: Anup Patel <anup.patel@wdc.com>
Reviewed-by: Bin Meng <bmeng.cn@gmail.com>
2020-03-11 15:30:23 +05:30
Anup Patel
61f776861f lib: sbi_ecall_legacy: Use sbi_hsm_hart_started_mask() API
This patch replaces use of sbi_hart_available_mask() API with
sbi_hsm_hart_started_mask API.

Signed-off-by: Anup Patel <anup.patel@wdc.com>
Reviewed-by: Bin Meng <bmeng.cn@gmail.com>
2020-03-11 15:30:19 +05:30
Anup Patel
2db381fc74 lib: Introduce sbi_hsm_hart_started_mask() API
This patch introduce sbi_hsm_hart_started_mask() API as
a replacement of sbi_hart_available_mask() API.

Signed-off-by: Anup Patel <anup.patel@wdc.com>
Reviewed-by: Bin Meng <bmeng.cn@gmail.com>
2020-03-11 15:30:16 +05:30
Anup Patel
44ce5b99e9 include: Remove disabled_hart_mask from sbi_platform
The disabled_hard_mask in sbi_platform is only 64bits wide so we
cannot disable a HART with HARTID > 63. To tackle this, we remove
disabled_hart_mask and replace it with hart_disabled() platform
callback.

Signed-off-by: Anup Patel <anup.patel@wdc.com>
Reviewed-by: Bin Meng <bmeng.cn@gmail.com>
Reviewed-by: Atish Patra <atish.patra@wdc.com>
2020-03-11 15:30:12 +05:30
Anup Patel
2b945fc180 lib: sbi_init: Use hartmask for coldboot wait
The coldboot_wait_bitmap is of fixed size and has __riscv_xlen
bits. This limits us to scale beyond __riscv_xlen HARTs hence
we replace coldboot_wait_bitmap with coldboot_wait_hmask which
is of type struct sbi_hartmask.

Signed-off-by: Anup Patel <anup.patel@wdc.com>
Reviewed-by: Bin Meng <bmeng.cn@gmail.com>
Reviewed-by: Atish Patra <atish.patra@wdc.com>
2020-03-11 15:30:08 +05:30
Anup Patel
71d2b837c4 lib: Move all coldboot wait APIs to sbi_init.c
The coldboot wait APIs are only used by sbi_init.c so no point in
having coldboot related code in sbi_hart.c.

As per-above rationale, we move all coldboot wait related APIs to
sbi_init.c as static/local functions.

Signed-off-by: Anup Patel <anup.patel@wdc.com>
Reviewed-by: Bin Meng <bmeng.cn@gmail.com>
2020-03-11 15:30:00 +05:30
Anup Patel
d96316481d lib: sbi_tlb: Use sbi_hartmask in sbi_tlb_info
Instead of using single ulong as source mask for sbi_tlb_info,
we use sbi_hartmask. This way sbi_tlb_info can easily scale
for large number of HARTs.

Signed-off-by: Anup Patel <anup.patel@wdc.com>
Reviewed-by: Bin Meng <bmeng.cn@gmail.com>
Reviewed-by: Atish Patra <atish.patra@wdc.com>
2020-03-11 15:29:57 +05:30
Anup Patel
a4a6a81b7d lib: Introduce SBI_TLB_INFO_INIT() helper macro
We introduce SBI_TLB_INFO_INIT() helper macro to help easy
initialization of struct sbi_tlb_info which is passed to the
sbi_tlb_request() API.

Signed-off-by: Anup Patel <anup.patel@wdc.com>
Reviewed-by: Bin Meng <bmeng.cn@gmail.com>
Reviewed-by: Atish Patra <atish.patra@wdc.com>
2020-03-11 15:29:55 +05:30
Anup Patel
d6d7e18d1d lib: sbi_init: Don't allow HARTID greater than SBI_HARTMASK_MAX_BITS
We only allow HARTs with HARTID less than SBI_HARTMASK_MAX_BITS in
sbi_init() function so that sbi_hartmask can safely used across
OpenSBI sources.

Signed-off-by: Anup Patel <anup.patel@wdc.com>
Reviewed-by: Bin Meng <bmeng.cn@gmail.com>
Reviewed-by: Atish Patra <atish.patra@wdc.com>
2020-03-11 15:29:51 +05:30
Anup Patel
c741abcd40 include: Simple hartmask library
We add a simple hartmask library to create and maintain HART mask
in different parts of OpenSBI sources. This new library is build
as wrapper library on-top-of bitmap library.

Signed-off-by: Anup Patel <anup.patel@wdc.com>
Reviewed-by: Bin Meng <bmeng.cn@gmail.com>
Reviewed-by: Atish Patra <atish.patra@wdc.com>
2020-03-11 15:29:47 +05:30
Anup Patel
3226bd93ce lib: Simple bitmap library
We add simple bitmap library which will help us create and maintain
bitmaps. It will also help us create a simple HART mask library.

Signed-off-by: Anup Patel <anup.patel@wdc.com>
Reviewed-by: Bin Meng <bmeng.cn@gmail.com>
Reviewed-by: Atish Patra <atish.patra@wdc.com>
2020-03-11 15:29:45 +05:30
Bin Meng
078686d75c lib: serial: Fix coding style issues
This fixes various coding style issues found in the serial codes.
No functional changes.

Signed-off-by: Bin Meng <bmeng.cn@gmail.com>
Reviewed-by: Anup Patel <anup.patel@wdc.com>
2020-03-10 10:38:08 +05:30
Bin Meng
650c0e525c lib: sbi: Fix coding style issues
This fixes various coding style issues found in the SBI codes.
No functional changes.

Signed-off-by: Bin Meng <bmeng.cn@gmail.com>
Reviewed-by: Anup Patel <anup.patel@wdc.com>
2020-03-10 10:27:28 +05:30
Bin Meng
6e87507db6 platform: ae350: Sort build objects in alphabetical order
Signed-off-by: Bin Meng <bmeng.cn@gmail.com>
Reviewed-by: Anup Patel <anup.patel@wdc.com>
2020-03-10 10:13:02 +05:30
Bin Meng
2abc55bb39 lib: Sort build objects in alphabetical order
Signed-off-by: Bin Meng <bmeng.cn@gmail.com>
Reviewed-by: Anup Patel <anup.patel@wdc.com>
2020-03-10 10:02:48 +05:30
Anup Patel
678c3c3655 include: sbi_scratch: Set per-HART scratch size to 4KB
Currently, the per-HART scratch size is 256 bytes on RV32 and
512 bytes on RV64. This patch set per-HART scratch size to 4KB
(4096 bytes) for both RV32 and RV64 so that we don't run-out
of scratch space anytime soon.

Signed-off-by: Anup Patel <anup.patel@wdc.com>
Reviewed-by: Atish Patra <atish.patra@wdc.com>
2020-03-08 11:17:01 +05:30
Anup Patel
4a603eb6dc platform: kendryte/k210: Set per-HART stack size to 8KB
All platform except kendryte/k210 use 8KB of per-HART stack hence
this patch set per-HART stack size of kendryte/k210 to 8KB for
consistency.

Signed-off-by: Anup Patel <anup.patel@wdc.com>
Reviewed-by: Atish Patra <atish.patra@wdc.com>
2020-03-08 11:13:31 +05:30
Anup Patel
a148996a7f include: sbi_bitops: More useful bit operations
This patch extends our bit operation library with mechanism to:
1. Iteratively traverse bits
2. Set bit
3. Clear bit
4. Change bit
5. ... other helpful functions ...

Most the above is adopted from Xvisor sources.

Signed-off-by: Anup Patel <anup.patel@wdc.com>
Reviewed-by: Atish Patra <atish.patra@wdc.com>
2020-03-08 11:09:46 +05:30
Anup Patel
00d332bbe7 include: Move bits related defines and macros to sbi_bitops.h
The right location for all bits related defines and macros is
sbi_bitops.h hence this patch. With this patch, the sbi_bits.h
is redundant so we remove it.

Signed-off-by: Anup Patel <anup.patel@wdc.com>
Reviewed-by: Atish Patra <atish.patra@wdc.com>
2020-03-08 11:06:18 +05:30
Anup Patel
8c83fb2fc8 lib: Fix return type of sbi_hsm_hart_started()
The return type of sbi_hsm_hart_started() should be bool.

Signed-off-by: Anup Patel <anup.patel@wdc.com>
Reviewed-by: Atish Patra <atish.patra@wdc.com>
Reviewed-by: Bin Meng <bmeng.cn@gmail.com>
2020-03-08 11:02:51 +05:30
e1a5b737ef platform: sifive: fu540: allow sv32 as an mmu-type
There has already been a commit to master which added 32-bit specific
fdt/payload addresses for the sifive/fu540 platform [0]. This commit
introduces another change for using sifive/fu540 as a 32-bit platform.
On 32-bit platforms, cores with the SV32 MMU type should not be
disabled. For this reason, this commit also allows using this MMU type
on the sifive/fu540 platform.

Alternatively it would also be possible to only allow SV39 and SV48 if
`__riscv_xlen == 64` and SV32 if `__riscv_xlen == 32`. Removing the
check entirely would also be an option.

[0]: 66fb729a1e

Signed-off-by: Sören Tempel <tempel@uni-bremen.de>
Reviewed-by: Bin Meng <bmeng.cn@gmail.com>
Reviewed-by: Anup Patel <anup.patel@wdc.com>
Reviewed-by: Alistair Francis <alistair.francis@wdc.com>
2020-03-08 10:35:32 +05:30
Nikita Ermakov
82ae8e8fe2 makefile: Do setup of the install target more flexible
- Add possibility to setup include, libs, firmware and docs paths.

- Change the default installation paths for include, libs, firmware
  and docs to meet FHS [1].

[1] https://refspecs.linuxfoundation.org/FHS_3.0/fhs/index.html

Signed-off-by: Nikita Ermakov <coffe92@gmail.com>
Reviewed-by: Anup Patel <anup.patel@wdc.com>
2020-03-08 10:05:45 +05:30
Atish Patra
6704216732 lib: Check MSIP bit after returning from WFI
As per the RISC-V privilege specification, WFI can be implemented as
a NOP. Software should ensure that relevant interrupt pending bits
are set. Otherwise, loop back to WFI.

Signed-off-by: Atish Patra <atish.patra@wdc.com>
Reviewed-by: Anup Patel <anup.patel@wdc.com>
Reviewed-by: Bin Meng <bmeng.cn@gmail.com>
2020-03-07 13:15:56 +05:30
Atish Patra
e3f69fc1e9 lib: Implement Hart State Management (HSM) SBI extension
This patch adds support HSM extension. The specification is available
at https://github.com/riscv/riscv-sbi-doc.

It allows to implement hart hotplug and fixed ordered hart booting in
supervisor.

Signed-off-by: Atish Patra <atish.patra@wdc.com>
Reviewed-by: Anup Patel <anup.patel@wdc.com>
2020-02-24 18:13:23 +05:30
Atish Patra
5b4824082f lib: Add possible hart status values
SBI HSM extension defines possible hart status values in the
specification.

Define all possible status values. Add a helper function to
convert hart state to status because hart states are internal
to OpenSBI only and may not match the status values defined in
the specification.

Signed-off-by: Atish Patra <atish.patra@wdc.com>
Reviewed-by: Anup Patel <anup.patel@wdc.com>
2020-02-24 18:11:47 +05:30
Atish Patra
b677a9b8d6 lib: Implement hart hotplug
This patch adds support for hart hotplug in OpenSBI using a generic WFI
based approach. Hart hotplug can be achieved via SBI HSM extension which
allows supervisor mode software to start or stop any harts anytime.

Any platform wishes to implement platform specific hart hotplug must
implement both hart_start and hart_stop in addition to enable platform
feature SBI_PLATFORM_HAS_HART_HOTPLUG.

Signed-off-by: Atish Patra <atish.patra@wdc.com>
Reviewed-by: Anup Patel <anup.patel@wdc.com>
2020-02-24 18:07:55 +05:30
Atish Patra
f64f4b92e4 lib: Add a new platform feature to bringup secondary harts
A platform may have a specific method to bring-up secondary harts for the
first time but may rely on generic WFI based approach for hart hotplug in
absence of a platform specific hart hotplug method.

Define a platform feature flag for such platforms. The platform needs to
implement platform specific bring-up method in hart_start and not define
hart_stop method in this case. They must only define
SBI_PLATFORM_HAS_HART_SECONDARY_BOOT.

SBI_PLATFORM_HAS_HART_HOTPLUG should only be defined when the platform
intend to support both hart_start and hart_stop and do not intend to rely
on generic WFI based approach.

Signed-off-by: Atish Patra <atish.patra@wdc.com>
Reviewed-by: Anup Patel <anup.patel@wdc.com>
2020-02-24 18:04:23 +05:30
Anup Patel
ac5e821d50 include: Bump-up version to 0.6
This patch updates OpenSBI version to 0.6 as part of
release preparation.

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

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

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

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

Fix the typo.

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

Fix the comment and initialize the threshold/priorities correctly.

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

Initialize it to zero to avoid nasty supervisor bugs.

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

Remove the unnecessary IPI types related to individual fence types.

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

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

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

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

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

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

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

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

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

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

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

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

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

Fix the typo.

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

This way any HART can be boot/main HART.

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

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

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

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

110
Makefile
View File

@@ -12,29 +12,37 @@
# o Do not print "Entering directory ...";
MAKEFLAGS += -r --no-print-directory
# Readlink -f requires GNU readlink
ifeq ($(shell uname -s),Darwin)
READLINK ?= greadlink
else
READLINK ?= readlink
endif
# Find out source, build, and install directories
src_dir=$(CURDIR)
ifdef O
build_dir=$(shell readlink -f $(O))
build_dir=$(shell $(READLINK) -f $(O))
else
build_dir=$(CURDIR)/build
endif
ifeq ($(build_dir),$(CURDIR))
$(error Build directory is same as source directory.)
endif
install_root_dir_default=$(CURDIR)/install
ifdef I
install_dir=$(shell readlink -f $(I))
install_root_dir=$(shell $(READLINK) -f $(I))
else
install_dir=$(CURDIR)/install
install_root_dir=$(install_root_dir_default)/usr
endif
ifeq ($(install_dir),$(CURDIR))
$(error Install directory is same as source directory.)
ifeq ($(install_root_dir),$(CURDIR))
$(error Install root directory is same as source directory.)
endif
ifeq ($(install_dir),$(build_dir))
$(error Install directory is same as build directory.)
ifeq ($(install_root_dir),$(build_dir))
$(error Install root directory is same as build directory.)
endif
ifdef PLATFORM_DIR
platform_dir_path=$(shell readlink -f $(PLATFORM_DIR))
platform_dir_path=$(shell $(READLINK) -f $(PLATFORM_DIR))
ifdef PLATFORM
platform_parent_dir=$(platform_dir_path)
else
@@ -122,7 +130,6 @@ 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)
@@ -149,6 +156,33 @@ ifndef PLATFORM_RISCV_CODE_MODEL
PLATFORM_RISCV_CODE_MODEL = medany
endif
# Setup install directories
ifdef INSTALL_INCLUDE_PATH
install_include_path=$(INSTALL_INCLUDE_PATH)
else
install_include_path=include
endif
ifdef INSTALL_LIB_PATH
install_lib_path=$(INSTALL_LIB_PATH)
else
ifneq ($(origin INSTALL_LIB_SUBDIR), undefined)
install_lib_subdir=$(INSTALL_LIB_SUBDIR)
else
install_lib_subdir=$(PLATFORM_RISCV_ABI)
endif
install_lib_path=lib$(subst 32,,$(PLATFORM_RISCV_XLEN))/$(install_lib_subdir)
endif
ifdef INSTALL_FIRMWARE_PATH
install_firmware_path=$(INSTALL_FIRMWARE_PATH)
else
install_firmware_path=share/opensbi/$(PLATFORM_RISCV_ABI)
endif
ifdef INSTALL_DOCS_PATH
install_docs_path=$(INSTALL_DOCS_PATH)
else
install_docs_path=share/opensbi/docs
endif
# Setup compilation commands flags
GENFLAGS = -I$(platform_src_dir)/include
GENFLAGS += -I$(include_dir)
@@ -159,7 +193,7 @@ GENFLAGS += $(libsbiutils-genflags-y)
GENFLAGS += $(platform-genflags-y)
GENFLAGS += $(firmware-genflags-y)
CFLAGS = -g -Wall -Werror -nostdlib -fno-strict-aliasing -O2
CFLAGS = -g -Wall -Werror -ffreestanding -nostdlib -fno-strict-aliasing -O2
CFLAGS += -fno-omit-frame-pointer -fno-optimize-sibling-calls
CFLAGS += -mno-save-restore -mstrict-align
CFLAGS += -mabi=$(PLATFORM_RISCV_ABI) -march=$(PLATFORM_RISCV_ISA)
@@ -192,7 +226,7 @@ MERGEFLAGS += -r
MERGEFLAGS += -b elf$(PLATFORM_RISCV_XLEN)-littleriscv
MERGEFLAGS += -m elf$(PLATFORM_RISCV_XLEN)lriscv
DTCFLAGS = -O dtb
DTSCPPFLAGS = $(CPPFLAGS) -nostdinc -nostdlib -fno-builtin -D__DTS__ -x assembler-with-cpp
# Setup functions for compilation
define dynamic_flags
@@ -208,12 +242,12 @@ copy_file = $(CMD_PREFIX)mkdir -p `dirname $(1)`; \
echo " COPY $(subst $(build_dir)/,,$(1))"; \
cp -f $(2) $(1)
inst_file = $(CMD_PREFIX)mkdir -p `dirname $(1)`; \
echo " INSTALL $(subst $(install_dir)/,,$(1))"; \
echo " INSTALL $(subst $(install_root_dir)/,,$(1))"; \
cp -f $(2) $(1)
inst_file_list = $(CMD_PREFIX)if [ ! -z "$(4)" ]; then \
mkdir -p $(1)/$(3); \
for file in $(4) ; do \
rel_file=`echo $$file | sed -e 's@$(2)/$(3)/@@'`; \
rel_file=`echo $$file | sed -e 's@$(2)/$(subst $(install_firmware_path),platform,$(3))@@'`; \
dest_file=$(1)"/"$(3)"/"`echo $$rel_file`; \
dest_dir=`dirname $$dest_file`; \
echo " INSTALL "$(3)"/"`echo $$rel_file`; \
@@ -222,7 +256,7 @@ inst_file_list = $(CMD_PREFIX)if [ ! -z "$(4)" ]; then \
done \
fi
inst_header_dir = $(CMD_PREFIX)mkdir -p $(1); \
echo " INSTALL $(subst $(install_dir)/,,$(1))"; \
echo " INSTALL $(subst $(install_root_dir)/,,$(1))"; \
cp -rf $(2) $(1)
compile_cpp = $(CMD_PREFIX)mkdir -p `dirname $(1)`; \
echo " CPP $(subst $(build_dir)/,,$(1))"; \
@@ -254,13 +288,18 @@ compile_objcopy = $(CMD_PREFIX)mkdir -p `dirname $(1)`; \
$(OBJCOPY) -S -O binary $(2) $(1)
compile_dts = $(CMD_PREFIX)mkdir -p `dirname $(1)`; \
echo " DTC $(subst $(build_dir)/,,$(1))"; \
$(DTC) $(DTCFLAGS) -o $(1) $(2)
$(CPP) $(DTSCPPFLAGS) $(2) | $(DTC) -O dtb -i `dirname $(2)` -o $(1)
compile_d2c = $(CMD_PREFIX)mkdir -p `dirname $(1)`; \
echo " D2C $(subst $(build_dir)/,,$(1))"; \
$(src_dir)/scripts/d2c.sh -i $(4) -a $(3) -p $(2) > $(1)
compile_gen_dep = $(CMD_PREFIX)mkdir -p `dirname $(1)`; \
echo " GEN-DEP $(subst $(build_dir)/,,$(1))"; \
echo "$(1:.dep=$(2)): $(3)" >> $(1)
targets-y = $(build_dir)/lib/libsbi.a
targets-y += $(build_dir)/lib/libsbiutils.a
ifdef PLATFORM
targets-y += $(platform_build_dir)/lib/libplatsbi.a
targets-y += $(platform-dtb-path-y)
endif
targets-y += $(firmware-bins-path-y)
@@ -307,12 +346,26 @@ $(platform_build_dir)/%.dep: $(platform_src_dir)/%.c
$(platform_build_dir)/%.o: $(platform_src_dir)/%.c
$(call compile_cc,$@,$<)
$(platform_build_dir)/%.o: $(platform_build_dir)/%.c
$(call compile_cc,$@,$<)
$(platform_build_dir)/%.dep: $(platform_src_dir)/%.S
$(call compile_as_dep,$@,$<)
$(platform_build_dir)/%.o: $(platform_src_dir)/%.S
$(call compile_as,$@,$<)
$(platform_build_dir)/%.dep: $(platform_src_dir)/%.dts
$(call compile_gen_dep,$@,.dtb,$<)
$(call compile_gen_dep,$@,.c,$(@:.dep=.dtb))
$(call compile_gen_dep,$@,.o,$(@:.dep=.c))
$(platform_build_dir)/%.c: $(platform_build_dir)/%.dtb
$(call compile_d2c,$@,$(platform-varprefix-$(subst .dtb,.o,$(subst /,-,$(subst $(platform_build_dir)/,,$<)))),16,$<)
$(platform_build_dir)/%.dtb: $(platform_src_dir)/%.dts
$(call compile_dts,$@,$<)
$(platform_build_dir)/%.dep: $(src_dir)/%.c
$(call compile_cc_dep,$@,$<)
@@ -325,9 +378,6 @@ $(platform_build_dir)/%.dep: $(src_dir)/%.S
$(platform_build_dir)/%.o: $(src_dir)/%.S
$(call compile_as,$@,$<)
$(build_dir)/%.dtb: $(src_dir)/%.dts
$(call compile_dts,$@,$<)
# Rule for "make docs"
$(build_dir)/docs/latex/refman.pdf: $(build_dir)/docs/latex/refman.tex
$(CMD_PREFIX)mkdir -p $(build_dir)/docs
@@ -378,26 +428,26 @@ install: $(install_targets-y)
.PHONY: install_libsbi
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)
$(call inst_header_dir,$(install_root_dir)/$(install_include_path),$(include_dir)/sbi)
$(call inst_file,$(install_root_dir)/$(install_lib_path)/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)
$(call inst_header_dir,$(install_root_dir)/$(install_include_path),$(include_dir)/sbi_utils)
$(call inst_file,$(install_root_dir)/$(install_lib_path)/libsbiutils.a,$(build_dir)/lib/libsbiutils.a)
.PHONY: install_libplatsbi
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)
$(call inst_file,$(install_root_dir)/$(install_lib_path)/opensbi/$(platform_subdir)/lib/libplatsbi.a,$(platform_build_dir)/lib/libplatsbi.a)
.PHONY: install_firmwares
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))
$(call inst_file_list,$(install_root_dir),$(build_dir),$(install_firmware_path)/$(platform_subdir)/firmware,$(firmware-elfs-path-y))
$(call inst_file_list,$(install_root_dir),$(build_dir),$(install_firmware_path)/$(platform_subdir)/firmware,$(firmware-bins-path-y))
.PHONY: install_docs
install_docs: $(build_dir)/docs/latex/refman.pdf
$(call inst_file,$(install_dir)/docs/refman.pdf,$(build_dir)/docs/latex/refman.pdf)
$(call inst_file,$(install_root_dir)/$(install_docs_path)/refman.pdf,$(build_dir)/docs/latex/refman.pdf)
# Rule for "make clean"
.PHONY: clean
@@ -422,7 +472,7 @@ ifeq ($(build_dir),$(CURDIR)/build)
$(if $(V), @echo " RM $(build_dir)")
$(CMD_PREFIX)rm -rf $(build_dir)
endif
ifeq ($(install_dir),$(CURDIR)/install)
$(if $(V), @echo " RM $(install_dir)")
$(CMD_PREFIX)rm -rf $(install_dir)
ifeq ($(install_root_dir),$(install_root_dir_default)/usr)
$(if $(V), @echo " RM $(install_root_dir_default)")
$(CMD_PREFIX)rm -rf $(install_root_dir_default)
endif

View File

@@ -1,9 +1,41 @@
Copyright (c) 2019 Western Digital Corporation or its affiliates
and other contributors.
RISC-V Open Source Supervisor Binary Interface (OpenSBI)
========================================================
Copyright and License
---------------------
The OpenSBI project is copyright (c) 2019 Western Digital Corporation
or its affiliates and other contributors.
It is distributed under the terms of the BSD 2-clause license
("Simplified BSD License" or "FreeBSD License", SPDX: *BSD-2-Clause*).
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
identifier in place of the full license text.
```
SPDX-License-Identifier: BSD-2-Clause
```
This enables machine processing of license information based on the SPDX
License Identifiers that are available on the [SPDX] web site.
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.
* 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.
Introduction
------------
The **RISC-V Supervisor Binary Interface (SBI)** is the recommended interface
between:
@@ -39,6 +71,27 @@ OpenSBI also provides several runtime firmware examples built using the platform
*riscv-pk* bootloader (aka BBL) and enable the use of well-known bootloaders
such as [U-Boot] (https://git.denx.de/u-boot.git).
Supported SBI version
---------------------
Currently, OpenSBI fully supports SBI specification *v0.2*. OpenSBI also
supports Hart State Management (HSM) SBI extension starting from OpenSBI v0.7.
HSM extension allows S-mode software to boot all the harts a defined order
rather than legacy method of random booting of harts. As a result, many
required features such as CPU hotplug, kexec/kdump can also be supported easily
in S-mode. HSM extension in OpenSBI is implemented in a non-backward compatible
manner to reduce the maintenance burden and avoid confusion. That's why, any
S-mode software using OpenSBI will not be able to boot more than 1 hart if HSM
extension is not supported in S-mode.
Linux kernel already supports SBI v0.2 and HSM SBI extension starting from
**v5.7-rc1**. If you are using an Linux kernel older than **5.7-rc1** or any
other S-mode software without HSM SBI extension, you should stick to OpenSBI
v0.6 to boot all the harts. For a UMP systems, it doesn't matter.
N.B. Any S-mode boot loader (i.e. U-Boot) doesn't need to support HSM extension,
as it doesn't need to boot all the harts. The operating system should be
capable enough to bring up all other non-booting harts using HSM extension.
Required Toolchain
------------------
@@ -94,7 +147,7 @@ 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*.
*<platform_subdir>* should be *generic*.
To build *libsbi.a*, *libplatsbi.a* and the firmware for one of the supported
platforms, run:
@@ -150,35 +203,6 @@ export PLATFORM_RISCV_XLEN=32
will generate 32-bit OpenSBI images. And vice vesa.
License
-------
OpenSBI is distributed under the terms of the BSD 2-clause license
("Simplified BSD License" or "FreeBSD License", SPDX: *BSD-2-Clause*).
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
identifier in place of the full license text.
```
SPDX-License-Identifier: BSD-2-Clause
```
This enables machine processing of license information based on the SPDX
License Identifiers that are available on the [SPDX] web site.
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.
* 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
-----------------------
@@ -197,6 +221,7 @@ Detailed documentation of various aspects of OpenSBI can be found under the
* [Contribution Guideline]: Guideline for contributing code to OpenSBI project
* [Library Usage]: API documentation of OpenSBI static library *libsbi.a*
* [Platform Requirements]: Requirements for using OpenSBI on a platform
* [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
@@ -249,6 +274,7 @@ make I=<install_directory> install_docs
[Contribution Guideline]: docs/contributing.md
[Contributors List]: CONTRIBUTORS.md
[Library Usage]: docs/library_usage.md
[Platform Requirements]: docs/platform_requirements.md
[Platform Support Guide]: docs/platform_guide.md
[Platform Documentation]: docs/platform/platform.md
[Firmware Documentation]: docs/firmware/fw.md

View File

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

View File

@@ -793,6 +793,7 @@ WARN_LOGFILE =
INPUT = @@SRC_DIR@@/README.md \
@@SRC_DIR@@/docs/contributing.md \
@@SRC_DIR@@/docs/platform_guide.md \
@@SRC_DIR@@/docs/platform_requirements.md \
@@SRC_DIR@@/docs/library_usage.md \
@@SRC_DIR@@/docs/firmware \
@@SRC_DIR@@/docs/platform \
@@ -948,7 +949,7 @@ FILTER_SOURCE_PATTERNS =
# (index.html). This can be useful if you have a project on for instance GitHub
# and want to reuse the introduction page also for the doxygen output.
USE_MDFILE_AS_MAINPAGE =
USE_MDFILE_AS_MAINPAGE = README.md
#---------------------------------------------------------------------------
# Configuration options related to source browsing
@@ -1444,7 +1445,7 @@ DISABLE_INDEX = NO
# The default value is: NO.
# This tag requires that the tag GENERATE_HTML is set to YES.
GENERATE_TREEVIEW = NO
GENERATE_TREEVIEW = YES
# The ENUM_VALUES_PER_LINE tag can be used to set the number of enum values that
# doxygen will group on one line in the generated HTML documentation.

View File

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

View File

@@ -1,4 +1,4 @@
OpenSBI Firmware with Dynamic Information *FW_DYNAMIC*
OpenSBI Firmware with Dynamic Information (FW_DYNAMIC)
======================================================
OpenSBI **firmware with dynamic info (FW_DYNAMIC)** is a firmware which gets

View File

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

View File

@@ -1,4 +1,4 @@
OpenSBI Firmware with Payload *FW_PAYLOAD*
OpenSBI Firmware with Payload (FW_PAYLOAD)
==========================================
OpenSBI **firmware with Payload (FW_PAYLOAD)** is a firmware which directly
@@ -57,33 +57,21 @@ file. The parameters currently defined are as follows:
* **FW_PAYLOAD_FDT_PATH** - Path to an external flattened device tree binary
file to be embedded in the *.text* section of the final firmware. If this
option is not provided and no internal device tree file is specified by the
platform (c.f. *FW_PAYLOAD_FDT*), then the firmware will expect the FDT to
be passed as an argument by the prior booting stage.
* **FW_PAYLOAD_FDT** - Path to an internal flattened device tree binary file
defined by the platform code. The file name must match the DTB file name
specified in the platform *objects.mk* file with the *platform-dtb-y* entry.
This option results in *FW_PAYLOAD_FDT_PATH* to be automatically set.
Specifying *FW_PAYLOAD_FDT_PATH* on the `make` command line disables
*FW_PAYLOAD_FDT* and the command line specified device tree binary file is
used for building the final firmware.
option is not provided then the firmware will expect the FDT to be passed
as an argument by the prior booting stage.
* **FW_PAYLOAD_FDT_ADDR** - Address where the FDT passed by the prior booting
stage or specified by the *FW_PAYLOAD_FDT_PATH* parameter and embedded in
the *.text* section will be placed before executing the next booting stage,
that is, the payload firmware. If this option is not provided, then the
firmware will pass zero as the FDT address to the next booting stage.
firmware will pass the FDT address passed by the previous booting stage
to the next booting stage.
*FW_PAYLOAD* Example
--------------------
The *[qemu/virt]* and *[qemu/sifive_u]* platforms illustrate how to configure
and use a *FW_PAYLOAD* firmware. Detailed information regarding these platforms
can be found in the platform documentation files.
The *kendryte/k210* platform also enables a build of a *FW_PAYLOAD* using an
internally defined device tree file (*FW_PAYLOAD_FDT*).
The *[qemu/virt]* platforms illustrate how to configure and use a *FW_PAYLOAD*
firmware. Detailed information regarding these platforms can be found in the
platform documentation files.
[qemu/virt]: ../platform/qemu_virt.md
[qemu/sifive_u]: ../platform/qemu_sifive_u.md

View File

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

View File

@@ -7,34 +7,9 @@ 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.
how to build U-Boot image and boot high level operating systems from U-Boot
prompt.
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

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

View File

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

View File

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

View File

@@ -0,0 +1,33 @@
OpenPiton FPGA SoC Platform
========================
OpenPiton is the world's first open source, general purpose, multithreaded
manycore processor. It is a tiled manycore framework scalable from one to
1/2 billion cores. Currently, OpenPiton supports the 64bit Ariane RISC-V
processor from ETH Zurich. To this end, Ariane has been equipped with a
different L1 cache subsystem that follows a write-through protocol and that has
support for cache invalidations and atomics.
To build platform specific library and firmwares, provide the
*PLATFORM=fpga/openpiton* parameter to the top level `make` command.
Platform Options
----------------
The *OpenPiton* platform does not have any platform-specific options.
Building Ariane FPGA Platform
-----------------------------
**Linux Kernel Payload**
```
make PLATFORM=fpga/openpiton 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.

54
docs/platform/generic.md Normal file
View File

@@ -0,0 +1,54 @@
Generic Platform
================
The **Generic** platform is a flattened device tree (FDT) based platform
where all platform specific functionality is provided based on FDT passed
by previous booting stage. The **Generic** platform allows us to use same
OpenSBI firmware binaries on various emulators, simulators, FPGAs, and
boards.
By default, the generic FDT platform makes following assumptions:
1. platform FW_TEXT_START is 0x80000000
2. platform features are default
3. platform stack size is default
4. platform has no quirks or work-arounds
The above assumptions (except 1) can be overridden by adding special platform
callbacks which will be called based on FDT root node compatible string.
Users of the generic FDT platform will have to ensure that:
1. Various FDT based drivers under lib/utils directory are upto date
based on their platform requirements
2. The FDT passed by previous booting stage has DT compatible strings and
DT properties in sync with the FDT based drivers under lib/utils directory
3. The FDT must have "stdout-path" DT property in the "/chosen" DT node when
a platform has multiple serial ports or consoles
4. On multi-HART platform, the FDT must have a DT node for IPI device and
lib/utils/ipi directory must have corresponding FDT based IPI driver
5. The FDT must have a DT node for timer device and lib/utils/timer directory
must have corresponding FDT based timer driver
To build the platform-specific library and firmware images, provide the
*PLATFORM=generic* parameter to the top level `make` command.
For custom FW_TEXT_START, we can build the platform-specific library and
firmware images by passing *PLATFORM=generic FW_TEXT_START=<custom_text_start>*
parameter to the top level `make` command.
Platform Options
----------------
The *Generic* platform does not have any platform-specific options.
RISC-V Platforms Using Generic Platform
---------------------------------------
* **QEMU RISC-V Virt Machine** (*[qemu_virt.md]*)
* **Spike** (*[spike.md]*)
* **Shakti C-class SoC Platform** (*[shakti_cclass.md]*)
[qemu_virt.md]: qemu_virt.md
[spike.md]: spike.md
[shakti_cclass.md]: shakti_cclass.md

View File

@@ -0,0 +1,22 @@
Nuclei UX600 Platform
=====================
The **Nuclei UX600** is a 64-bit RISC-V Core which is capable of running Linux.
> Nuclei UX600: single core, pipeline as single-issue and 6~9 variable stages, in-order dispatch and out-of-order write-back, running up to >1.2GHz
To build the platform-specific library and firmware images, provide the
*PLATFORM=nuclei/ux600* parameter to the top level `make` command.
Platform Options
----------------
The *Nuclei UX600* platform does not have any platform-specific options.
Building Nuclei UX600 Platform
------------------------------
```
make PLATFORM=nuclei/ux600 clean all
```

View File

@@ -3,28 +3,44 @@ OpenSBI Supported Platforms
OpenSBI currently supports the following virtual and hardware platforms:
* **Generic**: Flattened device tree (FDT) based platform where platform
specific functionality is provided based on the FDT passed by previous
booting stage. More details on this platform can be found in the file
*[generic.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
board by SiFive. More details on this platform can be found in the file
*[qemu_sifive_u.md]*.
* **SiFive FU540 SoC**: Platform support for SiFive FU540 SoC used on the
HiFive Unleashed board. This platform is very similar to the *QEMU sifive_u*
platform. More details on this platform can be found in the file
HiFive Unleashed board, as well as the *sifive_u* QEMU virtual RISC-V
machine. More details on this platform can be found in the file
*[sifive_fu540.md]*.
* **Kendryte K210 SoC**: Platform support for the Kendryte K210 SoC used on
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.
Genesys 2 board. More details on this platform can be found in the file
*[fpga-ariane.md]*.
* **Andes AE350 SoC**: Platform support for the Andes's SoC (AE350).
* **Andes AE350 SoC**: Platform support for the Andes's SoC (AE350). More
details on this platform can be found in the file *[andes-ae350.md]*.
* **T-HEAD C910**: Platform support for the T-HEAD C910 Processor. More
details on this platform can be found in the file *[thead-c910.md]*.
* **Spike**: Platform support for the Spike emulator. More
details on this platform can be found in the file *[spike.md]*.
* **OpenPiton FPGA SoC**: Platform support OpenPiton research platform based
on ariane core. More details on this platform can be found in the file
*[fpga_openpiton.md]*.
* **Shakti C-class SoC Platform**: Platform support for Shakti C-class
processor based SOCs. More details on this platform can be found in the
file *[shakti_cclass.md]*.
The code for these supported platforms can be used as example to implement
support for other platforms. The *platform/template* directory also provides
@@ -32,8 +48,12 @@ 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.
[generic.md]: generic.md
[qemu_virt.md]: qemu_virt.md
[qemu_sifive_u.md]: qemu_sifive_u.md
[sifive_fu540.md]: sifive_fu540.md
[ariane-fpga.md]: ariane-fpga.md
[andes_ae350.md]: andes-ae350.md
[fpga-ariane.md]: fpga-ariane.md
[andes-ae350.md]: andes-ae350.md
[thead-c910.md]: thead-c910.md
[spike.md]: spike.md
[fpga_openpiton.md]: fpga_openpiton.md
[shakti_cclass.md]: shakti_cclass.md

View File

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

View File

@@ -7,7 +7,7 @@ software development and testing. It is also referred to as
storage, and other types of IO.
To build the platform-specific library and firmware images, provide the
*PLATFORM=qemu/virt* parameter to the top level `make` command.
*PLATFORM=generic* parameter to the top level `make` command.
Platform Options
----------------
@@ -22,13 +22,13 @@ Execution on QEMU RISC-V 64-bit
Build:
```
make PLATFORM=qemu/virt
make PLATFORM=generic
```
Run:
```
qemu-system-riscv64 -M virt -m 256M -nographic \
-kernel build/platform/qemu/virt/firmware/fw_payload.elf
-kernel build/platform/generic/firmware/fw_payload.bin
```
**U-Boot Payload**
@@ -38,19 +38,19 @@ the `qemu-riscv64_smode_defconfig` configuration.
Build:
```
make PLATFORM=qemu/virt FW_PAYLOAD_PATH=<uboot_build_directory>/u-boot.bin
make PLATFORM=generic FW_PAYLOAD_PATH=<uboot_build_directory>/u-boot.bin
```
Run:
```
qemu-system-riscv64 -M virt -m 256M -nographic \
-kernel build/platform/qemu/virt/firmware/fw_payload.elf
-kernel build/platform/generic/firmware/fw_payload.elf
```
or
```
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
-bios build/platform/generic/firmware/fw_jump.bin \
-kernel <uboot_build_directory>/u-boot.bin
```
**Linux Kernel Payload**
@@ -60,13 +60,13 @@ Note: We assume that the Linux kernel is compiled using
Build:
```
make PLATFORM=qemu/virt FW_PAYLOAD_PATH=<linux_build_directory>/arch/riscv/boot/Image
make PLATFORM=generic FW_PAYLOAD_PATH=<linux_build_directory>/arch/riscv/boot/Image
```
Run:
```
qemu-system-riscv64 -M virt -m 256M -nographic \
-kernel build/platform/qemu/virt/firmware/fw_payload.elf \
-kernel build/platform/generic/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"
@@ -74,8 +74,8 @@ qemu-system-riscv64 -M virt -m 256M -nographic \
or
```
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 \
-bios build/platform/generic/firmware/fw_jump.bin \
-kernel <linux_build_directory>/arch/riscv/boot/Image \
-drive file=<path_to_linux_rootfs>,format=raw,id=hd0 \
-device virtio-blk-device,drive=hd0 \
-append "root=/dev/vda rw console=ttyS0"
@@ -89,13 +89,13 @@ Execution on QEMU RISC-V 32-bit
Build:
```
make PLATFORM=qemu/virt
make PLATFORM=generic PLATFORM_RISCV_XLEN=32
```
Run:
```
qemu-system-riscv32 -M virt -m 256M -nographic \
-kernel build/platform/qemu/virt/firmware/fw_payload.elf
-kernel build/platform/generic/firmware/fw_payload.bin
```
**U-Boot Payload**
@@ -105,37 +105,35 @@ the `qemu-riscv32_smode_defconfig` configuration.
Build:
```
make PLATFORM=qemu/virt FW_PAYLOAD_PATH=<uboot_build_directory>/u-boot.bin
make PLATFORM=generic PLATFORM_RISCV_XLEN=32 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
-kernel build/platform/generic/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
-bios build/platform/generic/firmware/fw_jump.bin \
-kernel <uboot_build_directory>/u-boot.bin
```
**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).
*arch/riscv/configs/rv32_defconfig*.
Build:
```
make PLATFORM=qemu/virt FW_PAYLOAD_PATH=<linux_build_directory>/arch/riscv/boot/Image
make PLATFORM=generic PLATFORM_RISCV_XLEN=32 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 \
-kernel build/platform/generic/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"
@@ -143,10 +141,9 @@ qemu-system-riscv32 -M virt -m 256M -nographic \
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 \
-bios build/platform/generic/firmware/fw_jump.bin \
-kernel <linux_build_directory>/arch/riscv/boot/Image \
-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

@@ -0,0 +1,33 @@
Shakti C-class SoC Platform
===========================
C-Class is a member of the SHAKTI family of processors from
Indian Institute of Technology - Madras (IIT-M).
It is an extremely configurable and commercial-grade 5-stage
in-order core supporting the standard RV64GCSUN ISA extensions.
For more details, refer:
* https://gitlab.com/shaktiproject/cores/c-class/blob/master/README.md
* https://c-class.readthedocs.io/en/latest
* https://shakti.org.in
Platform Options
----------------
The *Shakti C-class SoC* platform does not have any platform-specific
options.
Building Shakti C-class Platform
--------------------------------
**Linux Kernel Payload**
```
make PLATFORM=generic FW_PAYLOAD_PATH=<linux_build_directory>/arch/riscv/boot/Image FW_PAYLOAD_FDT_PATH=<shakti.dtb path>
```
**Test Payload**
```
make PLATFORM=generic FW_PAYLOAD_FDT_PATH=<shakti.dtb path>
```

View File

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

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

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

View File

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

View File

@@ -0,0 +1,44 @@
OpenSBI Platform Requirements
=============================
The RISC-V platform requirements for OpenSBI can change over time
with advances in RISC-V specifications and ecosystem.
To handle this, we have two types of RISC-V platform requirements:
1. **Base platform requirements** which apply to all OpenSBI releases
2. **Release specific platform requirements** which apply to a OpenSBI
release and later releases
Currently, we don't have any **Release specific platform requirements**
but such platform requirements will be added in future.
Base Platform Requirements
--------------------------
The base RISC-V platform requirements for OpenSBI are as follows:
1. At least rv32ima or rv64ima required on all HARTs
2. At least one HART should have S-mode support because:
* SBI calls are meant for RISC-V S-mode (Supervisor mode)
* OpenSBI implements SBI calls for S-mode software
3. The MTVEC CSR on all HARTs must support direct mode
4. The PMP CSRs are optional. If PMP CSRs are not implemented then
OpenSBI cannot protect M-mode firmware and secured memory regions
5. The TIME CSR is optional. If TIME CSR is not implemented in
hardware then a 64-bit MMIO counter is required to track time
and emulate TIME CSR
6. Hardware support for injecting M-mode software interrupts on
a multi-HART platform
The RISC-V extensions not covered by rv32ima or rv64ima are optional
for OpenSBI. Although, OpenSBI will detect and handle some of these
optional RISC-V extensions at runtime.
The optional RISC-V extensions handled by OpenSBI at runtime are:
* D-extension: Double precision floating point
* F-extension: Single precision floating point
* H-extension: Hypervisor

View File

@@ -41,17 +41,26 @@
999:
.endm
.align 3
.section .entry, "ax", %progbits
.align 3
.globl _start
.globl _start_warm
_start:
/*
* Jump to warm-boot if this is not the first core booting,
* that is, for mhartid != 0
*/
csrr a6, CSR_MHARTID
blt zero, a6, _wait_relocate_copy_done
/* Find preferred boot HART id */
MOV_3R s0, a0, s1, a1, s2, a2
call fw_boot_hart
add a6, a0, zero
MOV_3R a0, s0, a1, s1, a2, s2
li a7, -1
beq a6, a7, _try_lottery
/* Jump to relocation wait loop if we are not boot hart */
bne a0, a6, _wait_relocate_copy_done
_try_lottery:
/* Jump to relocation wait loop if we don't get relocation lottery */
la a6, _relocate_lottery
li a7, 1
amoadd.w a6, a7, (a6)
bnez a6, _wait_relocate_copy_done
/* Save load address */
la t0, _load_start
@@ -75,6 +84,8 @@ _relocate:
blt t2, t0, _relocate_copy_to_upper
_relocate_copy_to_lower:
ble t1, t2, _relocate_copy_to_lower_loop
la t3, _relocate_lottery
BRANGE t2, t1, t3, _start_hang
la t3, _boot_status
BRANGE t2, t1, t3, _start_hang
la t3, _relocate
@@ -91,6 +102,8 @@ _relocate_copy_to_lower_loop:
jr t4
_relocate_copy_to_upper:
ble t3, t0, _relocate_copy_to_upper_loop
la t2, _relocate_lottery
BRANGE t0, t3, t2, _start_hang
la t2, _boot_status
BRANGE t0, t3, t2, _start_hang
la t2, _relocate
@@ -147,11 +160,48 @@ _relocate_done:
li ra, 0
call _reset_regs
/* Zero-out BSS */
la s4, _bss_start
la s5, _bss_end
_bss_zero:
REG_S zero, (s4)
add s4, s4, __SIZEOF_POINTER__
blt s4, s5, _bss_zero
/* Setup temporary trap handler */
la s4, _start_hang
csrw CSR_MTVEC, s4
/* Setup temporary stack */
la s4, _fw_end
li s5, (SBI_SCRATCH_SIZE * 2)
add sp, s4, s5
/* 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
/* Override previous arg1 */
MOV_3R s0, a0, s1, a1, s2, a2
call fw_prev_arg1
add t1, a0, zero
MOV_3R a0, s0, a1, s1, a2, s2
beqz t1, _prev_arg1_override_done
add a1, t1, zero
_prev_arg1_override_done:
/*
* Initialize platform
* Note: The a0 to a4 registers passed to the
* firmware are parameters to this function.
*/
MOV_5R s0, a0, s1, a1, s2, a2, s3, a3, s4, a4
call fw_platform_init
add t0, a0, zero
MOV_5R a0, s0, a1, s1, a2, s2, a3, s3, a4, s4
add a1, t0, zero
/* Preload HART details
* s7 -> HART Count
* s8 -> HART Stack Size
@@ -220,35 +270,16 @@ _scratch_init:
/* Store firmware options in scratch space */
MOV_3R s0, a0, s1, a1, s2, a2
#ifdef FW_OPTIONS
li a4, FW_OPTIONS
li a0, FW_OPTIONS
#else
add a4, zero, zero
#endif
call fw_options
or a4, a4, a0
REG_S a4, SBI_SCRATCH_OPTIONS_OFFSET(tp)
#endif
REG_S a0, 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
la a5, _bss_end
_bss_zero:
REG_S zero, (a4)
add a4, a4, __SIZEOF_POINTER__
blt a4, a5, _bss_zero
/* Override pervious arg1 */
MOV_3R s0, a0, s1, a1, s2, a2
call fw_prev_arg1
add t1, a0, zero
MOV_3R a0, s0, a1, s1, a2, s2
beqz t1, _prev_arg1_override_done
add a1, t1, zero
_prev_arg1_override_done:
/*
* Relocate Flatened Device Tree (FDT)
* source FDT address = previous arg1
@@ -318,7 +349,7 @@ _fdt_reloc_done:
fence rw, rw
j _start_warm
/* waitting for boot hart done (_boot_status == 2) */
/* waiting for boot hart to be done (_boot_status == 2) */
_wait_for_boot_hart:
li t0, BOOT_STATUS_BOOT_HART_DONE
la t1, _boot_status
@@ -338,6 +369,7 @@ _start_warm:
csrw CSR_MIE, zero
csrw CSR_MIP, zero
/* Find HART count and HART stack size */
la a4, platform
#if __riscv_xlen == 64
lwu s7, SBI_PLATFORM_HART_COUNT_OFFSET(a4)
@@ -346,12 +378,29 @@ _start_warm:
lw s7, SBI_PLATFORM_HART_COUNT_OFFSET(a4)
lw s8, SBI_PLATFORM_HART_STACK_SIZE_OFFSET(a4)
#endif
REG_L s9, SBI_PLATFORM_HART_INDEX2ID_OFFSET(a4)
/* HART ID should be within expected limit */
/* Find HART id */
csrr s6, CSR_MHARTID
bge s6, s7, _start_hang
/* find the scratch space for this hart */
/* Find HART index */
beqz s9, 3f
li a4, 0
1:
#if __riscv_xlen == 64
lwu a5, (s9)
#else
lw a5, (s9)
#endif
beq a5, s6, 2f
add s9, s9, 4
add a4, a4, 1
blt a4, s7, 1b
li a4, -1
2: add s6, a4, zero
3: bge s6, s7, _start_hang
/* Find the scratch space based on HART index */
la tp, _fw_end
mul a5, s7, s8
add tp, tp, a5
@@ -369,9 +418,6 @@ _start_warm:
/* Setup trap handler */
la a4, _trap_handler
csrw CSR_MTVEC, a4
/* Make sure that mtvec is updated */
1: csrr a5, CSR_MTVEC
bne a4, a5, 1b
/* Initialize SBI runtime */
csrr a0, CSR_MSCRATCH
@@ -381,6 +427,8 @@ _start_warm:
j _start_hang
.align 3
_relocate_lottery:
RISCV_PTR 0
_boot_status:
RISCV_PTR 0
_load_start:
@@ -390,50 +438,50 @@ _link_start:
_link_end:
RISCV_PTR _fw_reloc_end
.align 3
.section .entry, "ax", %progbits
.align 3
.globl _hartid_to_scratch
_hartid_to_scratch:
add sp, sp, -(3 * __SIZEOF_POINTER__)
REG_S s0, (sp)
REG_S s1, (__SIZEOF_POINTER__)(sp)
REG_S s2, (__SIZEOF_POINTER__ * 2)(sp)
/*
* a0 -> HART ID (passed by caller)
* s0 -> HART Stack Size
* s1 -> HART Stack End
* s2 -> Temporary
* a1 -> HART Index (passed by caller)
* t0 -> HART Stack Size
* t1 -> HART Stack End
* t2 -> Temporary
*/
la s2, platform
la t2, platform
#if __riscv_xlen == 64
lwu s0, SBI_PLATFORM_HART_STACK_SIZE_OFFSET(s2)
lwu s2, SBI_PLATFORM_HART_COUNT_OFFSET(s2)
lwu t0, SBI_PLATFORM_HART_STACK_SIZE_OFFSET(t2)
lwu t2, SBI_PLATFORM_HART_COUNT_OFFSET(t2)
#else
lw s0, SBI_PLATFORM_HART_STACK_SIZE_OFFSET(s2)
lw s2, SBI_PLATFORM_HART_COUNT_OFFSET(s2)
lw t0, SBI_PLATFORM_HART_STACK_SIZE_OFFSET(t2)
lw t2, SBI_PLATFORM_HART_COUNT_OFFSET(t2)
#endif
mul s2, s2, s0
la s1, _fw_end
add s1, s1, s2
mul s2, s0, a0
sub s1, s1, s2
li s2, SBI_SCRATCH_SIZE
sub a0, s1, s2
REG_L s0, (sp)
REG_L s1, (__SIZEOF_POINTER__)(sp)
REG_L s2, (__SIZEOF_POINTER__ * 2)(sp)
add sp, sp, (3 * __SIZEOF_POINTER__)
sub t2, t2, a1
mul t2, t2, t0
la t1, _fw_end
add t1, t1, t2
li t2, SBI_SCRATCH_SIZE
sub a0, t1, t2
ret
.align 3
.section .entry, "ax", %progbits
.align 3
.globl _start_hang
_start_hang:
wfi
j _start_hang
.align 3
.section .entry, "ax", %progbits
.align 3
.globl fw_platform_init
.weak fw_platform_init
fw_platform_init:
add a0, a1, zero
ret
.section .entry, "ax", %progbits
.align 3
.globl _trap_handler
_trap_handler:
/* Swap TP and MSCRATCH */
@@ -531,7 +579,6 @@ _skip_mstatush_save:
/* Call C routine */
add a0, sp, zero
csrr a1, CSR_MSCRATCH
call sbi_trap_handler
/* Restore all general regisers except SP and T0 */
@@ -588,8 +635,8 @@ _skip_mstatush_restore:
mret
.align 3
.section .entry, "ax", %progbits
.align 3
.globl _reset_regs
_reset_regs:

View File

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

View File

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

View File

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

View File

@@ -41,11 +41,6 @@ ifdef FW_PAYLOAD_ALIGN
firmware-genflags-$(FW_PAYLOAD) += -DFW_PAYLOAD_ALIGN=$(FW_PAYLOAD_ALIGN)
endif
ifndef FW_PAYLOAD_FDT_PATH
ifdef 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)\"
endif

View File

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

View File

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

View File

@@ -28,9 +28,9 @@
#error "Unexpected __riscv_xlen"
#endif
#define PAGE_SHIFT (12)
#define PAGE_SIZE (_AC(1, UL) << PAGE_SHIFT)
#define PAGE_MASK (~(PAGE_SIZE - 1))
#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)
@@ -38,7 +38,6 @@
#define LGREG __REG_SEL(3, 2)
#if __SIZEOF_POINTER__ == 8
#define BITS_PER_LONG 64
#ifdef __ASSEMBLY__
#define RISCV_PTR .dword
#define RISCV_SZPTR 8
@@ -49,7 +48,6 @@
#define RISCV_LGPTR "3"
#endif
#elif __SIZEOF_POINTER__ == 4
#define BITS_PER_LONG 32
#ifdef __ASSEMBLY__
#define RISCV_PTR .word
#define RISCV_SZPTR 4
@@ -159,35 +157,30 @@ void csr_write_num(int csr_num, unsigned long val);
__asm__ __volatile__("wfi" ::: "memory"); \
} while (0)
static inline int misa_extension(char ext)
{
return csr_read(CSR_MISA) & (1 << (ext - 'A'));
}
/* Get current HART id */
#define current_hartid() ((unsigned int)csr_read(CSR_MHARTID))
static inline int misa_xlen(void)
{
return ((long)csr_read(CSR_MISA) < 0) ? 64 : 32;
}
/* determine CPU extension, return non-zero support */
int misa_extension_imp(char ext);
static inline void misa_string(char *out, unsigned int out_sz)
{
unsigned long i, val = csr_read(CSR_MISA);
#define misa_extension(c)\
({\
_Static_assert(((c >= 'A') && (c <= 'Z')),\
"The parameter of misa_extension must be [A-Z]");\
misa_extension_imp(c);\
})
for (i = 0; i < 26; i++) {
if (val & (1 << i)) {
*out = 'A' + i;
out++;
}
}
*out = '\0';
out++;
}
/* Get MXL field of misa, return -1 on error */
int misa_xlen(void);
/* Get RISC-V ISA string representation */
void misa_string(int xlen, char *out, unsigned int out_sz);
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);
unsigned long *size);
#endif /* !__ASSEMBLY__ */

View File

@@ -29,9 +29,9 @@ long atomic_add_return(atomic_t *atom, long value);
long atomic_sub_return(atomic_t *atom, long value);
long arch_atomic_cmpxchg(atomic_t *atom, long oldval, long newval);
long atomic_cmpxchg(atomic_t *atom, long oldval, long newval);
long arch_atomic_xchg(atomic_t *atom, long newval);
long atomic_xchg(atomic_t *atom, long newval);
unsigned int atomic_raw_xchg_uint(volatile unsigned int *ptr,
unsigned int newval);

View File

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

128
include/sbi/sbi_bitmap.h Normal file
View File

@@ -0,0 +1,128 @@
/*
* SPDX-License-Identifier: BSD-2-Clause
*
* Copyright (c) 2020 Western Digital Corporation or its affiliates.
*
* Authors:
* Anup Patel <anup.patel@wdc.com>
*/
#ifndef __SBI_BITMAP_H__
#define __SBI_BITMAP_H__
#include <sbi/sbi_bitops.h>
#define BITMAP_FIRST_WORD_MASK(start) (~0UL << ((start) % BITS_PER_LONG))
#define BITMAP_LAST_WORD_MASK(nbits) \
( \
((nbits) % BITS_PER_LONG) ? \
((1UL << ((nbits) % BITS_PER_LONG)) - 1) : ~0UL \
)
#define small_const_nbits(nbits) \
(__builtin_constant_p(nbits) && (nbits) <= BITS_PER_LONG)
#define DECLARE_BITMAP(name, nbits) unsigned long name[BITS_TO_LONGS(nbits)]
#define DEFINE_BITMAP(name) extern unsigned long name[]
static inline unsigned long bitmap_estimate_size(int nbits)
{
return (BITS_TO_LONGS(nbits) * sizeof(unsigned long));
}
void __bitmap_and(unsigned long *dst, const unsigned long *bitmap1,
const unsigned long *bitmap2, int bits);
void __bitmap_or(unsigned long *dst, const unsigned long *bitmap1,
const unsigned long *bitmap2, int bits);
void __bitmap_xor(unsigned long *dst, const unsigned long *bitmap1,
const unsigned long *bitmap2, int bits);
static inline void bitmap_set(unsigned long *bmap, int start, int len)
{
int bit;
for (bit = start; bit < (start + len); bit++)
bmap[BIT_WORD(bit)] |= (0x1UL << BIT_WORD_OFFSET(bit));
}
static inline void bitmap_clear(unsigned long *bmap, int start, int len)
{
int bit;
for (bit = start; bit < (start + len); bit++)
bmap[BIT_WORD(bit)] &= ~(0x1UL << BIT_WORD_OFFSET(bit));
}
static inline void bitmap_zero(unsigned long *dst, int nbits)
{
if (small_const_nbits(nbits))
*dst = 0UL;
else {
size_t i, len = BITS_TO_LONGS(nbits);
for (i = 0; i < len; i++)
dst[i] = 0;
}
}
static inline void bitmap_zero_except(unsigned long *dst,
int exception, int nbits)
{
if (small_const_nbits(nbits))
*dst = 0UL;
else {
size_t i, len = BITS_TO_LONGS(nbits);
for (i = 0; i < len; i++)
dst[i] = 0;
}
if (exception < nbits)
__set_bit(exception, dst);
}
static inline void bitmap_fill(unsigned long *dst, int nbits)
{
size_t i, nlongs = BITS_TO_LONGS(nbits);
if (!small_const_nbits(nbits)) {
for (i = 0; i < (nlongs - 1); i++)
dst[i] = -1UL;
}
dst[nlongs - 1] = BITMAP_LAST_WORD_MASK(nbits);
}
static inline void bitmap_copy(unsigned long *dst,
const unsigned long *src, int nbits)
{
if (small_const_nbits(nbits))
*dst = *src;
else {
size_t i, len = BITS_TO_LONGS(nbits);
for (i = 0; i < len; i++)
dst[i] = src[i];
}
}
static inline void bitmap_and(unsigned long *dst, const unsigned long *src1,
const unsigned long *src2, int nbits)
{
if (small_const_nbits(nbits))
*dst = *src1 & *src2;
else
__bitmap_and(dst, src1, src2, nbits);
}
static inline void bitmap_or(unsigned long *dst, const unsigned long *src1,
const unsigned long *src2, int nbits)
{
if (small_const_nbits(nbits))
*dst = *src1 | *src2;
else
__bitmap_or(dst, src1, src2, nbits);
}
static inline void bitmap_xor(unsigned long *dst, const unsigned long *src1,
const unsigned long *src2, int nbits)
{
if (small_const_nbits(nbits))
*dst = *src1 ^ *src2;
else
__bitmap_xor(dst, src1, src2, nbits);
}
#endif

View File

@@ -4,14 +4,37 @@
* Copyright (c) 2019 Western Digital Corporation or its affiliates.
*
* Authors:
* Atish Patra<atish.patra@wdc.com>
* Atish Patra <atish.patra@wdc.com>
*/
#ifndef __SBI_BITOPS_H__
#define __SBI_BITOPS_H__
#include <sbi/sbi_bits.h>
#include <sbi/riscv_asm.h>
#include <sbi/sbi_types.h>
#if __SIZEOF_POINTER__ == 8
#define BITS_PER_LONG 64
#elif __SIZEOF_POINTER__ == 4
#define BITS_PER_LONG 32
#else
#error "Unexpected __SIZEOF_POINTER__"
#endif
#define EXTRACT_FIELD(val, which) \
(((val) & (which)) / ((which) & ~((which)-1)))
#define INSERT_FIELD(val, which, fieldval) \
(((val) & ~(which)) | ((fieldval) * ((which) & ~((which)-1))))
#define BITS_TO_LONGS(nbits) (((nbits) + BITS_PER_LONG - 1) / \
BITS_PER_LONG)
#define BIT(nr) (1UL << (nr))
#define BIT_MASK(nr) (1UL << ((nr) % BITS_PER_LONG))
#define BIT_WORD(bit) ((bit) / BITS_PER_LONG)
#define BIT_WORD_OFFSET(bit) ((bit) & (BITS_PER_LONG - 1))
#define GENMASK(h, l) \
(((~0UL) - (1UL << (l)) + 1) & (~0UL >> (BITS_PER_LONG - 1 - (h))))
/**
* ffs - Find first bit set
@@ -95,4 +118,207 @@ static inline int __ffs(unsigned long word)
*/
#define ffz(x) __ffs(~(x))
/**
* fls - find last (most-significant) bit set
* @x: the word to search
*
* This is defined the same way as ffs.
* Note fls(0) = 0, fls(1) = 1, fls(0x80000000) = 32.
*/
static inline int fls(int x)
{
int r = 32;
if (!x)
return 0;
if (!(x & 0xffff0000u)) {
x <<= 16;
r -= 16;
}
if (!(x & 0xff000000u)) {
x <<= 8;
r -= 8;
}
if (!(x & 0xf0000000u)) {
x <<= 4;
r -= 4;
}
if (!(x & 0xc0000000u)) {
x <<= 2;
r -= 2;
}
if (!(x & 0x80000000u)) {
x <<= 1;
r -= 1;
}
return r;
}
/**
* __fls - find last (most-significant) set bit in a long word
* @word: the word to search
*
* Undefined if no set bit exists, so code should check against 0 first.
*/
static inline unsigned long __fls(unsigned long word)
{
int num = BITS_PER_LONG - 1;
#if BITS_PER_LONG == 64
if (!(word & (~0ul << 32))) {
num -= 32;
word <<= 32;
}
#endif
if (!(word & (~0ul << (BITS_PER_LONG-16)))) {
num -= 16;
word <<= 16;
}
if (!(word & (~0ul << (BITS_PER_LONG-8)))) {
num -= 8;
word <<= 8;
}
if (!(word & (~0ul << (BITS_PER_LONG-4)))) {
num -= 4;
word <<= 4;
}
if (!(word & (~0ul << (BITS_PER_LONG-2)))) {
num -= 2;
word <<= 2;
}
if (!(word & (~0ul << (BITS_PER_LONG-1))))
num -= 1;
return num;
}
#define for_each_set_bit(bit, addr, size) \
for ((bit) = find_first_bit((addr), (size)); \
(bit) < (size); \
(bit) = find_next_bit((addr), (size), (bit) + 1))
/* same as for_each_set_bit() but use bit as value to start with */
#define for_each_set_bit_from(bit, addr, size) \
for ((bit) = find_next_bit((addr), (size), (bit)); \
(bit) < (size); \
(bit) = find_next_bit((addr), (size), (bit) + 1))
#define for_each_clear_bit(bit, addr, size) \
for ((bit) = find_first_zero_bit((addr), (size)); \
(bit) < (size); \
(bit) = find_next_zero_bit((addr), (size), (bit) + 1))
/* same as for_each_clear_bit() but use bit as value to start with */
#define for_each_clear_bit_from(bit, addr, size) \
for ((bit) = find_next_zero_bit((addr), (size), (bit)); \
(bit) < (size); \
(bit) = find_next_zero_bit((addr), (size), (bit) + 1))
unsigned long find_first_bit(const unsigned long *addr,
unsigned long size);
unsigned long find_first_zero_bit(const unsigned long *addr,
unsigned long size);
unsigned long find_last_bit(const unsigned long *addr,
unsigned long size);
unsigned long find_next_bit(const unsigned long *addr,
unsigned long size, unsigned long offset);
unsigned long find_next_zero_bit(const unsigned long *addr,
unsigned long size,
unsigned long offset);
/**
* __set_bit - Set a bit in memory
* @nr: the bit to set
* @addr: the address to start counting from
*
* This function is non-atomic and may be reordered.
*/
static inline void __set_bit(int nr, volatile unsigned long *addr)
{
unsigned long mask = BIT_MASK(nr);
unsigned long *p = ((unsigned long *)addr) + BIT_WORD(nr);
*p |= mask;
}
/**
* __clear_bit - Clear a bit in memory
* @nr: the bit to clear
* @addr: the address to start counting from
*
* This function is non-atomic and may be reordered.
*/
static inline void __clear_bit(int nr, volatile unsigned long *addr)
{
unsigned long mask = BIT_MASK(nr);
unsigned long *p = ((unsigned long *)addr) + BIT_WORD(nr);
*p &= ~mask;
}
/**
* __change_bit - Toggle a bit in memory
* @nr: the bit to change
* @addr: the address to start counting from
*
* This function is non-atomic and may be reordered.
*/
static inline void __change_bit(int nr, volatile unsigned long *addr)
{
unsigned long mask = BIT_MASK(nr);
unsigned long *p = ((unsigned long *)addr) + BIT_WORD(nr);
*p ^= mask;
}
/**
* __test_and_set_bit - Set a bit and return its old value
* @nr: Bit to set
* @addr: Address to count from
*
* This operation is non-atomic and can be reordered.
*/
static inline int __test_and_set_bit(int nr, volatile unsigned long *addr)
{
unsigned long mask = BIT_MASK(nr);
unsigned long *p = ((unsigned long *)addr) + BIT_WORD(nr);
unsigned long old = *p;
*p = old | mask;
return (old & mask) != 0;
}
/**
* __test_and_clear_bit - Clear a bit and return its old value
* @nr: Bit to clear
* @addr: Address to count from
*
* This operation is non-atomic and can be reordered.
*/
static inline int __test_and_clear_bit(int nr, volatile unsigned long *addr)
{
unsigned long mask = BIT_MASK(nr);
unsigned long *p = ((unsigned long *)addr) + BIT_WORD(nr);
unsigned long old = *p;
*p = old & ~mask;
return (old & mask) != 0;
}
/**
* __test_bit - Determine whether a bit is set
* @nr: bit number to test
* @addr: Address to start counting from
*
* This operation is non-atomic and can be reordered.
*/
static inline int __test_bit(int nr, const volatile unsigned long *addr)
{
return 1UL & (addr[BIT_WORD(nr)] >> (nr & (BITS_PER_LONG-1)));
}
#endif

View File

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

View File

@@ -30,10 +30,9 @@ 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(1, 2) sbi_dprintf(const char *format, ...);
int __printf(2, 3) sbi_dprintf(struct sbi_scratch *scratch,
const char *format, ...);
struct sbi_scratch;
int sbi_console_init(struct sbi_scratch *scratch);

View File

@@ -10,7 +10,8 @@
#ifndef __SBI_CONST_H__
#define __SBI_CONST_H__
/* Some constant macros are used in both assembler and
/*
* Some constant macros are used in both assembler and
* C code. Therefore we cannot annotate them always with
* 'UL' and other type specifiers unilaterally. We
* use the following macros to deal with this.
@@ -39,8 +40,8 @@
#define UL(x) (_UL(x))
#define ULL(x) (_ULL(x))
#define __STR(s) #s
#define STRINGIFY(s) __STR(s)
#define __STR(s) #s
#define STRINGIFY(s) __STR(s)
/* clang-format on */

View File

@@ -0,0 +1,50 @@
/*
* SPDX-License-Identifier: BSD-2-Clause
*
* Copyright (c) 2020 Western Digital Corporation or its affiliates.
*
* Authors:
* Atish Patra <atish.patra@wdc.com>
*/
#ifndef __SBI_CSR_DETECT__H
#define __SBI_CSR_DETECT__H
#include <sbi/riscv_encoding.h>
#include <sbi/sbi_hart.h>
#define csr_read_allowed(csr_num, trap) \
({ \
register ulong tinfo asm("a3") = (ulong)trap; \
register ulong ttmp asm("a4"); \
register ulong mtvec = sbi_hart_expected_trap_addr(); \
register ulong ret = 0; \
asm volatile( \
"add %[ttmp], %[tinfo], zero\n" \
"csrrw %[mtvec], " STR(CSR_MTVEC) ", %[mtvec]\n" \
"csrr %[ret], %[csr]\n" \
"csrw " STR(CSR_MTVEC) ", %[mtvec]" \
: [mtvec] "+&r"(mtvec), [tinfo] "+&r"(tinfo), \
[ttmp] "+&r"(ttmp), [ret] "=&r" (ret) \
: [csr] "i" (csr_num) \
: "memory"); \
ret; \
}) \
#define csr_write_allowed(csr_num, trap, value) \
({ \
register ulong tinfo asm("a3") = (ulong)trap; \
register ulong ttmp asm("a4"); \
register ulong mtvec = sbi_hart_expected_trap_addr(); \
asm volatile( \
"add %[ttmp], %[tinfo], zero\n" \
"csrrw %[mtvec], " STR(CSR_MTVEC) ", %[mtvec]\n" \
"csrw %[csr], %[val]\n" \
"csrw " STR(CSR_MTVEC) ", %[mtvec]" \
: [mtvec] "+&r"(mtvec), \
[tinfo] "+&r"(tinfo), [ttmp] "+&r"(ttmp) \
: [csr] "i" (csr_num), [val] "r" (value) \
: "memory"); \
}) \
#endif

View File

@@ -11,15 +11,49 @@
#define __SBI_ECALL_H__
#include <sbi/sbi_types.h>
#include <sbi/sbi_list.h>
#define SBI_ECALL_VERSION_MAJOR 0
#define SBI_ECALL_VERSION_MINOR 2
#define SBI_OPENSBI_IMPID 1
struct sbi_trap_regs;
struct sbi_scratch;
struct sbi_trap_info;
struct sbi_ecall_extension {
struct sbi_dlist head;
unsigned long extid_start;
unsigned long extid_end;
int (* probe)(unsigned long extid, unsigned long *out_val);
int (* handle)(unsigned long extid, unsigned long funcid,
unsigned long *args, unsigned long *out_val,
struct sbi_trap_info *out_trap);
};
extern struct sbi_ecall_extension ecall_base;
extern struct sbi_ecall_extension ecall_legacy;
extern struct sbi_ecall_extension ecall_time;
extern struct sbi_ecall_extension ecall_rfence;
extern struct sbi_ecall_extension ecall_ipi;
extern struct sbi_ecall_extension ecall_vendor;
extern struct sbi_ecall_extension ecall_hsm;
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,
struct sbi_scratch *scratch);
unsigned long sbi_ecall_get_impid(void);
void sbi_ecall_set_impid(unsigned long impid);
struct sbi_ecall_extension *sbi_ecall_find_extension(unsigned long extid);
int sbi_ecall_register_extension(struct sbi_ecall_extension *ext);
void sbi_ecall_unregister_extension(struct sbi_ecall_extension *ext);
int sbi_ecall_handler(struct sbi_trap_regs *regs);
int sbi_ecall_init(void);
#endif

View File

@@ -12,34 +12,75 @@
/* clang-format off */
enum sbi_ext_id {
SBI_EXT_0_1_SET_TIMER = 0x0,
SBI_EXT_0_1_CONSOLE_PUTCHAR = 0x1,
SBI_EXT_0_1_CONSOLE_GETCHAR = 0x2,
SBI_EXT_0_1_CLEAR_IPI = 0x3,
SBI_EXT_0_1_SEND_IPI = 0x4,
SBI_EXT_0_1_REMOTE_FENCE_I = 0x5,
SBI_EXT_0_1_REMOTE_SFENCE_VMA = 0x6,
SBI_EXT_0_1_REMOTE_SFENCE_VMA_ASID = 0x7,
SBI_EXT_0_1_SHUTDOWN = 0x8,
SBI_EXT_BASE = 0x10,
};
/* SBI Extension IDs */
#define SBI_EXT_0_1_SET_TIMER 0x0
#define SBI_EXT_0_1_CONSOLE_PUTCHAR 0x1
#define SBI_EXT_0_1_CONSOLE_GETCHAR 0x2
#define SBI_EXT_0_1_CLEAR_IPI 0x3
#define SBI_EXT_0_1_SEND_IPI 0x4
#define SBI_EXT_0_1_REMOTE_FENCE_I 0x5
#define SBI_EXT_0_1_REMOTE_SFENCE_VMA 0x6
#define SBI_EXT_0_1_REMOTE_SFENCE_VMA_ASID 0x7
#define SBI_EXT_0_1_SHUTDOWN 0x8
#define SBI_EXT_BASE 0x10
#define SBI_EXT_TIME 0x54494D45
#define SBI_EXT_IPI 0x735049
#define SBI_EXT_RFENCE 0x52464E43
#define SBI_EXT_HSM 0x48534D
enum sbi_ext_base_fid {
SBI_EXT_BASE_GET_SPEC_VERSION = 0,
SBI_EXT_BASE_GET_IMP_ID,
SBI_EXT_BASE_GET_IMP_VERSION,
SBI_EXT_BASE_PROBE_EXT,
SBI_EXT_BASE_GET_MVENDORID,
SBI_EXT_BASE_GET_MARCHID,
SBI_EXT_BASE_GET_MIMPID,
};
/* SBI function IDs for BASE extension*/
#define SBI_EXT_BASE_GET_SPEC_VERSION 0x0
#define SBI_EXT_BASE_GET_IMP_ID 0x1
#define SBI_EXT_BASE_GET_IMP_VERSION 0x2
#define SBI_EXT_BASE_PROBE_EXT 0x3
#define SBI_EXT_BASE_GET_MVENDORID 0x4
#define SBI_EXT_BASE_GET_MARCHID 0x5
#define SBI_EXT_BASE_GET_MIMPID 0x6
/* SBI function IDs for TIME extension*/
#define SBI_EXT_TIME_SET_TIMER 0x0
/* SBI function IDs for IPI extension*/
#define SBI_EXT_IPI_SEND_IPI 0x0
/* SBI function IDs for RFENCE extension*/
#define SBI_EXT_RFENCE_REMOTE_FENCE_I 0x0
#define SBI_EXT_RFENCE_REMOTE_SFENCE_VMA 0x1
#define SBI_EXT_RFENCE_REMOTE_SFENCE_VMA_ASID 0x2
#define SBI_EXT_RFENCE_REMOTE_HFENCE_GVMA 0x3
#define SBI_EXT_RFENCE_REMOTE_HFENCE_GVMA_VMID 0x4
#define SBI_EXT_RFENCE_REMOTE_HFENCE_VVMA 0x5
#define SBI_EXT_RFENCE_REMOTE_HFENCE_VVMA_ASID 0x6
/* SBI function IDs for HSM extension */
#define SBI_EXT_HSM_HART_START 0x0
#define SBI_EXT_HSM_HART_STOP 0x1
#define SBI_EXT_HSM_HART_GET_STATUS 0x2
#define SBI_HSM_HART_STATUS_STARTED 0x0
#define SBI_HSM_HART_STATUS_STOPPED 0x1
#define SBI_HSM_HART_STATUS_START_PENDING 0x2
#define SBI_HSM_HART_STATUS_STOP_PENDING 0x3
#define SBI_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
#define SBI_EXT_FIRMWARE_START 0x0A000000
#define SBI_EXT_FIRMWARE_END 0x0AFFFFFF
/* SBI return error codes */
#define SBI_SUCCESS 0
#define SBI_ERR_FAILED -1
#define SBI_ERR_NOT_SUPPORTED -2
#define SBI_ERR_INVALID_PARAM -3
#define SBI_ERR_DENIED -4
#define SBI_ERR_INVALID_ADDRESS -5
#define SBI_ERR_ALREADY_AVAILABLE -6
#define SBI_LAST_ERR SBI_ERR_ALREADY_AVAILABLE
#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

@@ -13,12 +13,11 @@
#include <sbi/sbi_types.h>
struct sbi_trap_regs;
struct sbi_scratch;
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_read(int csr_num, struct sbi_trap_regs *regs,
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);
int sbi_emulate_csr_write(int csr_num, struct sbi_trap_regs *regs,
ulong csr_val);
#endif

View File

@@ -10,24 +10,28 @@
#ifndef __SBI_ERROR_H__
#define __SBI_ERROR_H__
#include <sbi/sbi_ecall_interface.h>
/* clang-format off */
#define SBI_OK 0
#define SBI_EFAIL -1
#define SBI_ENOTSUPP -2
#define SBI_EINVAL -3
#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
#define SBI_OK 0
#define SBI_EFAIL SBI_ERR_FAILED
#define SBI_ENOTSUPP SBI_ERR_NOT_SUPPORTED
#define SBI_EINVAL SBI_ERR_INVALID_PARAM
#define SBI_EDENIED SBI_ERR_DENIED
#define SBI_EINVALID_ADDR SBI_ERR_INVALID_ADDRESS
#define SBI_EALREADY SBI_ERR_ALREADY_AVAILABLE
#define SBI_ENODEV -1000
#define SBI_ENOSYS -1001
#define SBI_ETIMEDOUT -1002
#define SBI_EIO -1003
#define SBI_EILL -1004
#define SBI_ENOSPC -1005
#define SBI_ENOMEM -1006
#define SBI_ETRAP -1007
#define SBI_EUNKNOWN -1008
#define SBI_ENOENT -1009
/* clang-format on */

View File

@@ -12,15 +12,42 @@
#include <sbi/sbi_types.h>
/** Possible feature flags of a hart */
enum sbi_hart_features {
/** Hart has PMP support */
SBI_HART_HAS_PMP = (1 << 0),
/** Hart has S-mode counter enable */
SBI_HART_HAS_SCOUNTEREN = (1 << 1),
/** Hart has M-mode counter enable */
SBI_HART_HAS_MCOUNTEREN = (1 << 2),
/** HART has timer csr implementation in hardware */
SBI_HART_HAS_TIME = (1 << 3),
/** Last index of Hart features*/
SBI_HART_HAS_LAST_FEATURE = SBI_HART_HAS_TIME,
};
struct sbi_scratch;
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);
extern void (*sbi_hart_expected_trap)(void);
static inline ulong sbi_hart_expected_trap_addr(void)
{
return (ulong)sbi_hart_expected_trap;
}
void sbi_hart_delegation_dump(struct sbi_scratch *scratch);
unsigned int sbi_hart_pmp_count(struct sbi_scratch *scratch);
int sbi_hart_pmp_get(struct sbi_scratch *scratch, unsigned int n,
unsigned long *prot_out, unsigned long *addr_out,
unsigned long *size);
void sbi_hart_pmp_dump(struct sbi_scratch *scratch);
int sbi_hart_pmp_check_addr(struct sbi_scratch *scratch, unsigned long daddr,
unsigned long attr);
bool sbi_hart_has_feature(struct sbi_scratch *scratch, unsigned long feature);
void sbi_hart_get_features_str(struct sbi_scratch *scratch,
char *features_str, int nfstr);
void __attribute__((noreturn)) sbi_hart_hang(void);
@@ -29,19 +56,4 @@ 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);
ulong sbi_hart_available_mask(void);
void sbi_hart_unmark_available(u32 hartid);
struct sbi_scratch *sbi_hart_id_to_scratch(struct sbi_scratch *scratch,
u32 hartid);
void sbi_hart_wait_for_coldboot(struct sbi_scratch *scratch, u32 hartid);
void sbi_hart_wake_coldboot_harts(struct sbi_scratch *scratch, u32 hartid);
u32 sbi_current_hartid(void);
#endif

141
include/sbi/sbi_hartmask.h Normal file
View File

@@ -0,0 +1,141 @@
/*
* SPDX-License-Identifier: BSD-2-Clause
*
* Copyright (c) 2020 Western Digital Corporation or its affiliates.
*
* Authors:
* Anup Patel <anup.patel@wdc.com>
*/
#ifndef __SBI_HARTMASK_H__
#define __SBI_HARTMASK_H__
#include <sbi/sbi_bitmap.h>
/**
* Maximum number of bits in a hartmask
*
* The hartmask is indexed using physical HART id so this define
* also represents the maximum number of HART ids generic OpenSBI
* can handle.
*/
#define SBI_HARTMASK_MAX_BITS 128
/** Representation of hartmask */
struct sbi_hartmask {
DECLARE_BITMAP(bits, SBI_HARTMASK_MAX_BITS);
};
/** Initialize hartmask to zero */
#define SBI_HARTMASK_INIT(__m) \
bitmap_zero(((__m)->bits), SBI_HARTMASK_MAX_BITS)
/** Initialize hartmask to zero except a particular HART id */
#define SBI_HARTMASK_INIT_EXCEPT(__m, __h) \
bitmap_zero_except(((__m)->bits), (__h), SBI_HARTMASK_MAX_BITS)
/**
* Get underlying bitmap of hartmask
* @param m the hartmask pointer
*/
#define sbi_hartmask_bits(__m) ((__m)->bits)
/**
* Set a HART in hartmask
* @param h HART id to set
* @param m the hartmask pointer
*/
static inline void sbi_hartmask_set_hart(u32 h, struct sbi_hartmask *m)
{
if (h < SBI_HARTMASK_MAX_BITS)
__set_bit(h, m->bits);
}
/**
* Clear a HART in hartmask
* @param h HART id to clear
* @param m the hartmask pointer
*/
static inline void sbi_hartmask_clear_hart(u32 h, struct sbi_hartmask *m)
{
if (h < SBI_HARTMASK_MAX_BITS)
__clear_bit(h, m->bits);
}
/**
* Test a HART in hartmask
* @param h HART id to test
* @param m the hartmask pointer
*/
static inline int sbi_hartmask_test_hart(u32 h, struct sbi_hartmask *m)
{
if (h < SBI_HARTMASK_MAX_BITS)
return __test_bit(h, m->bits);
return 0;
}
/**
* Set all HARTs in a hartmask
* @param dstp the hartmask pointer
*/
static inline void sbi_hartmask_set_all(struct sbi_hartmask *dstp)
{
bitmap_fill(sbi_hartmask_bits(dstp), SBI_HARTMASK_MAX_BITS);
}
/**
* Clear all HARTs in a hartmask
* @param dstp the hartmask pointer
*/
static inline void sbi_hartmask_clear_all(struct sbi_hartmask *dstp)
{
bitmap_zero(sbi_hartmask_bits(dstp), SBI_HARTMASK_MAX_BITS);
}
/**
* *dstp = *src1p & *src2p
* @param dstp the hartmask result
* @param src1p the first input
* @param src2p the second input
*/
static inline void sbi_hartmask_and(struct sbi_hartmask *dstp,
const struct sbi_hartmask *src1p,
const struct sbi_hartmask *src2p)
{
bitmap_and(sbi_hartmask_bits(dstp), sbi_hartmask_bits(src1p),
sbi_hartmask_bits(src2p), SBI_HARTMASK_MAX_BITS);
}
/**
* *dstp = *src1p | *src2p
* @param dstp the hartmask result
* @param src1p the first input
* @param src2p the second input
*/
static inline void sbi_hartmask_or(struct sbi_hartmask *dstp,
const struct sbi_hartmask *src1p,
const struct sbi_hartmask *src2p)
{
bitmap_or(sbi_hartmask_bits(dstp), sbi_hartmask_bits(src1p),
sbi_hartmask_bits(src2p), SBI_HARTMASK_MAX_BITS);
}
/**
* *dstp = *src1p ^ *src2p
* @param dstp the hartmask result
* @param src1p the first input
* @param src2p the second input
*/
static inline void sbi_hartmask_xor(struct sbi_hartmask *dstp,
const struct sbi_hartmask *src1p,
const struct sbi_hartmask *src2p)
{
bitmap_xor(sbi_hartmask_bits(dstp), sbi_hartmask_bits(src1p),
sbi_hartmask_bits(src2p), SBI_HARTMASK_MAX_BITS);
}
/** Iterate over each HART in hartmask */
#define sbi_hartmask_for_each_hart(__h, __m) \
for_each_set_bit(__h, (__m)->bits, SBI_HARTMASK_MAX_BITS)
#endif

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

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

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

@@ -0,0 +1,36 @@
/*
* SPDX-License-Identifier: BSD-2-Clause
*
* Copyright (c) 2020 Western Digital Corporation or its affiliates.
*
* Authors:
* Atish Patra <atish.patra@wdc.com>
*/
#ifndef __SBI_HSM_H__
#define __SBI_HSM_H__
#include <sbi/sbi_types.h>
/** Hart state values **/
#define SBI_HART_STOPPED 0
#define SBI_HART_STOPPING 1
#define SBI_HART_STARTING 2
#define SBI_HART_STARTED 3
#define SBI_HART_UNKNOWN 4
struct sbi_scratch;
int sbi_hsm_init(struct sbi_scratch *scratch, u32 hartid, bool cold_boot);
void __noreturn sbi_hsm_exit(struct sbi_scratch *scratch);
int sbi_hsm_hart_start(struct sbi_scratch *scratch, u32 hartid,
ulong saddr, ulong priv);
int sbi_hsm_hart_stop(struct sbi_scratch *scratch, bool exitnow);
int sbi_hsm_hart_get_state(u32 hartid);
int sbi_hsm_hart_state_to_status(int state);
bool sbi_hsm_hart_started(u32 hartid);
int sbi_hsm_hart_started_mask(ulong hbase, ulong *out_hmask);
void sbi_hsm_prepare_next_jump(struct sbi_scratch *scratch, u32 hartid);
#endif

View File

@@ -13,10 +13,7 @@
#include <sbi/sbi_types.h>
struct sbi_trap_regs;
struct sbi_scratch;
int sbi_illegal_insn_handler(u32 hartid, ulong mcause,
struct sbi_trap_regs *regs,
struct sbi_scratch *scratch);
int sbi_illegal_insn_handler(ulong insn, struct sbi_trap_regs *regs);
#endif

View File

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

View File

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

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

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

15
include/sbi/sbi_math.h Normal file
View File

@@ -0,0 +1,15 @@
/*
* SPDX-License-Identifier: BSD-2-Clause
*
* Copyright (c) 2020 Western Digital Corporation or its affiliates.
*
* Authors:
* Atish Patra <atish.patra@wdc.com>
*/
#ifndef __SBI_MATH_H__
#define __SBI_MATH_H__
unsigned long log2roundup(unsigned long x);
#endif

View File

@@ -13,14 +13,11 @@
#include <sbi/sbi_types.h>
struct sbi_trap_regs;
struct sbi_scratch;
int sbi_misaligned_load_handler(u32 hartid, ulong mcause,
struct sbi_trap_regs *regs,
struct sbi_scratch *scratch);
int sbi_misaligned_load_handler(ulong addr, ulong tval2, ulong tinst,
struct sbi_trap_regs *regs);
int sbi_misaligned_store_handler(u32 hartid, ulong mcause,
struct sbi_trap_regs *regs,
struct sbi_scratch *scratch);
int sbi_misaligned_store_handler(ulong addr, ulong tval2, ulong tinst,
struct sbi_trap_regs *regs);
#endif

View File

@@ -10,9 +10,10 @@
#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
/**
* 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)
@@ -28,23 +29,22 @@
#define SBI_PLATFORM_HART_COUNT_OFFSET (0x50)
/** Offset of hart_stack_size in struct sbi_platform */
#define SBI_PLATFORM_HART_STACK_SIZE_OFFSET (0x54)
/** Offset of disabled_hart_mask in struct sbi_platform */
#define SBI_PLATFORM_DISABLED_HART_OFFSET (0x58)
/** Offset of tlb_range_flush_limit in struct sbi_platform */
#define SBI_PLATFORM_TLB_RANGE_FLUSH_LIMIT_OFFSET (0x60)
/** Offset of platform_ops_addr in struct sbi_platform */
#define SBI_PLATFORM_OPS_OFFSET (0x68)
#define SBI_PLATFORM_OPS_OFFSET (0x58)
/** Offset of firmware_context in struct sbi_platform */
#define SBI_PLATFORM_FIRMWARE_CONTEXT_OFFSET (0x68 + __SIZEOF_POINTER__)
#define SBI_PLATFORM_FIRMWARE_CONTEXT_OFFSET (0x58 + __SIZEOF_POINTER__)
/** Offset of hart_index2id in struct sbi_platform */
#define SBI_PLATFORM_HART_INDEX2ID_OFFSET (0x58 + (__SIZEOF_POINTER__ * 2))
#define SBI_PLATFORM_TLB_RANGE_FLUSH_LIMIT_DEFAULT (1UL << 12)
#ifndef __ASSEMBLY__
#include <sbi/sbi_version.h>
#include <sbi/sbi_scratch.h>
#include <sbi/sbi_ecall.h>
#include <sbi/sbi_error.h>
#include <sbi/sbi_scratch.h>
#include <sbi/sbi_trap.h>
#include <sbi/sbi_version.h>
/** Possible feature flags of a platform */
enum sbi_platform_features {
@@ -52,21 +52,18 @@ enum sbi_platform_features {
SBI_PLATFORM_HAS_TIMER_VALUE = (1 << 0),
/** Platform has HART hotplug support */
SBI_PLATFORM_HAS_HART_HOTPLUG = (1 << 1),
/** Platform has PMP support */
SBI_PLATFORM_HAS_PMP = (1 << 2),
/** Platform has S-mode counter enable */
SBI_PLATFORM_HAS_SCOUNTEREN = (1 << 3),
/** Platform has M-mode counter enable */
SBI_PLATFORM_HAS_MCOUNTEREN = (1 << 4),
/** Platform has fault delegation support */
SBI_PLATFORM_HAS_MFAULTS_DELEGATION = (1 << 5),
SBI_PLATFORM_HAS_MFAULTS_DELEGATION = (1 << 2),
/** Platform has custom secondary hart booting support */
SBI_PLATFORM_HAS_HART_SECONDARY_BOOT = (1 << 3),
/** Last index of Platform features*/
SBI_PLATFORM_HAS_LAST_FEATURE = SBI_PLATFORM_HAS_HART_SECONDARY_BOOT,
};
/** 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 | \
SBI_PLATFORM_HAS_MFAULTS_DELEGATION)
(SBI_PLATFORM_HAS_TIMER_VALUE | SBI_PLATFORM_HAS_MFAULTS_DELEGATION)
/** Platform functions */
struct sbi_platform_operations {
@@ -75,6 +72,23 @@ struct sbi_platform_operations {
/** Platform final initialization */
int (*final_init)(bool cold_boot);
/** Platform early exit */
void (*early_exit)(void);
/** Platform final exit */
void (*final_exit)(void);
/**
* For platforms that do not implement misa, non-standard
* methods are needed to determine cpu extension.
*/
int (*misa_check_extension)(char ext);
/**
* For platforms that do not implement misa, non-standard
* methods are needed to get MXL field of misa.
*/
int (*misa_get_xlen)(void);
/** Get number of PMP regions for given HART */
u32 (*pmp_region_count)(u32 hartid);
/**
@@ -93,6 +107,8 @@ struct sbi_platform_operations {
/** Initialize the platform interrupt controller for current HART */
int (*irqchip_init)(bool cold_boot);
/** Exit the platform interrupt controller for current HART */
void (*irqchip_exit)(void);
/** Send IPI to a target HART */
void (*ipi_send)(u32 target_hart);
@@ -100,6 +116,11 @@ struct sbi_platform_operations {
void (*ipi_clear)(u32 target_hart);
/** Initialize IPI for current HART */
int (*ipi_init)(bool cold_boot);
/** Exit IPI for current HART */
void (*ipi_exit)(void);
/** Get tlb flush limit value **/
u64 (*get_tlbr_flush_limit)(void);
/** Get platform timer value */
u64 (*timer_value)(void);
@@ -109,21 +130,35 @@ struct sbi_platform_operations {
void (*timer_event_stop)(void);
/** Initialize platform timer for current HART */
int (*timer_init)(bool cold_boot);
/** Exit platform timer for current HART */
void (*timer_exit)(void);
/** Reboot the platform */
int (*system_reboot)(u32 type);
/** Shutdown or poweroff the platform */
int (*system_shutdown)(u32 type);
/** Bringup the given hart */
int (*hart_start)(u32 hartid, ulong saddr);
/**
* Stop the current hart from running. This call doesn't expect to
* return if success.
*/
int (*hart_stop)(void);
/** Reset the platform */
#define SBI_PLATFORM_RESET_SHUTDOWN 0
#define SBI_PLATFORM_RESET_COLD 1
#define SBI_PLATFORM_RESET_WARM 2
int (*system_reset)(u32 reset_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);
unsigned long *args,
unsigned long *out_value,
struct sbi_trap_info *out_trap);
} __packed;
/** Platform default per-HART stack size for exception/interrupt handling */
#define SBI_PLATFORM_DEFAULT_HART_STACK_SIZE 8192
/** Representation of a platform */
struct sbi_platform {
/**
@@ -146,14 +181,26 @@ struct sbi_platform {
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;
/**
* HART index to HART id table
*
* For used HART index <abc>:
* hart_index2id[<abc>] = some HART id
* For unused HART index <abc>:
* hart_index2id[<abc>] = -1U
*
* If hart_index2id == NULL then we assume identity mapping
* hart_index2id[<abc>] = <abc>
*
* We have only two restrictions:
* 1. HART index < sbi_platform hart_count
* 2. HART id < SBI_HARTMASK_MAX_BITS
*/
const u32 *hart_index2id;
} __packed;
/** Get pointer to sbi_platform for sbi_scratch pointer */
@@ -172,46 +219,62 @@ struct sbi_platform {
/** Check whether the platform supports HART hotplug */
#define sbi_platform_has_hart_hotplug(__p) \
((__p)->features & SBI_PLATFORM_HAS_HART_HOTPLUG)
/** Check whether the platform has PMP support */
#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) \
((__p)->features & SBI_PLATFORM_HAS_SCOUNTEREN)
/** Check whether the platform supports mcounteren CSR */
#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) \
((__p)->features & SBI_PLATFORM_HAS_MFAULTS_DELEGATION)
/** Check whether the platform supports custom secondary hart booting support */
#define sbi_platform_has_hart_secondary_boot(__p) \
((__p)->features & SBI_PLATFORM_HAS_HART_SECONDARY_BOOT)
/**
* Get HART index for the given HART
*
* @param plat pointer to struct sbi_platform
* @param hartid HART ID
*
* @return 0 <= value < hart_count for valid HART otherwise -1U
*/
u32 sbi_platform_hart_index(const struct sbi_platform *plat, u32 hartid);
/**
* Get the platform features in string format
*
* @param plat pointer to struct sbi_platform
* @param features_str pointer to a char array where the features string will be
* updated
* @param nfstr length of the features_str. The feature string will be truncated
* if nfstr is not long enough.
*/
void sbi_platform_get_features_str(const struct sbi_platform *plat,
char *features_str, int nfstr);
/**
* Get name of the platform
*
* @param plat pointer to struct sbi_platform
*
* @return pointer to platform name on success and NULL on failure
* @return pointer to platform name on success and "Unknown" on failure
*/
static inline const char *sbi_platform_name(const struct sbi_platform *plat)
{
if (plat)
return plat->name;
return NULL;
return "Unknown";
}
/**
* Check whether the given HART is disabled
* Get the platform features
*
* @param plat pointer to struct sbi_platform
* @param hartid HART ID
*
* @return TRUE if HART is disabled and FALSE otherwise
* @return the features value currently set for the given platform
*/
static inline bool sbi_platform_hart_disabled(const struct sbi_platform *plat,
u32 hartid)
static inline unsigned long sbi_platform_get_features(
const struct sbi_platform *plat)
{
if (plat && (plat->disabled_hart_mask & (1 << hartid)))
return TRUE;
return FALSE;
if (plat)
return plat->features;
return 0;
}
/**
@@ -225,8 +288,8 @@ static inline bool sbi_platform_hart_disabled(const struct sbi_platform *plat,
*/
static inline u64 sbi_platform_tlbr_flush_limit(const struct sbi_platform *plat)
{
if (plat && plat->tlb_range_flush_limit)
return plat->tlb_range_flush_limit;
if (plat && sbi_platform_ops(plat)->get_tlbr_flush_limit)
return sbi_platform_ops(plat)->get_tlbr_flush_limit();
return SBI_PLATFORM_TLB_RANGE_FLUSH_LIMIT_DEFAULT;
}
@@ -258,6 +321,57 @@ static inline u32 sbi_platform_hart_stack_size(const struct sbi_platform *plat)
return 0;
}
/**
* Check whether given HART is invalid
*
* @param plat pointer to struct sbi_platform
* @param hartid HART ID
*
* @return TRUE if HART is invalid and FALSE otherwise
*/
static inline bool sbi_platform_hart_invalid(const struct sbi_platform *plat,
u32 hartid)
{
if (!plat)
return TRUE;
if (plat->hart_count <= sbi_platform_hart_index(plat, hartid))
return TRUE;
return FALSE;
}
/**
* Bringup a given hart from previous stage. Platform should implement this
* operation if they support a custom mechanism to start a hart. Otherwise,
* a generic WFI based approach will be used to start/stop a hart in OpenSBI.
*
* @param plat pointer to struct sbi_platform
* @param hartid HART id
* @param saddr M-mode start physical address for the HART
*
* @return 0 if sucessful and negative error code on failure
*/
static inline int sbi_platform_hart_start(const struct sbi_platform *plat,
u32 hartid, ulong saddr)
{
if (plat && sbi_platform_ops(plat)->hart_start)
return sbi_platform_ops(plat)->hart_start(hartid, saddr);
return SBI_ENOTSUPP;
}
/**
* Stop the current hart in OpenSBI.
*
* @param plat pointer to struct sbi_platform
*
* @return Negative error code on failure. It doesn't return on success.
*/
static inline int sbi_platform_hart_stop(const struct sbi_platform *plat)
{
if (plat && sbi_platform_ops(plat)->hart_stop)
return sbi_platform_ops(plat)->hart_stop();
return SBI_ENOTSUPP;
}
/**
* Early initialization for current HART
*
@@ -290,6 +404,58 @@ static inline int sbi_platform_final_init(const struct sbi_platform *plat,
return 0;
}
/**
* Early exit for current HART
*
* @param plat pointer to struct sbi_platform
*/
static inline void sbi_platform_early_exit(const struct sbi_platform *plat)
{
if (plat && sbi_platform_ops(plat)->early_exit)
sbi_platform_ops(plat)->early_exit();
}
/**
* Final exit for current HART
*
* @param plat pointer to struct sbi_platform
*/
static inline void sbi_platform_final_exit(const struct sbi_platform *plat)
{
if (plat && sbi_platform_ops(plat)->final_exit)
sbi_platform_ops(plat)->final_exit();
}
/**
* Check CPU extension in MISA
*
* @param plat pointer to struct sbi_platform
* @param ext shorthand letter for CPU extensions
*
* @return zero for not-supported and non-zero for supported
*/
static inline int sbi_platform_misa_extension(const struct sbi_platform *plat,
char ext)
{
if (plat && sbi_platform_ops(plat)->misa_check_extension)
return sbi_platform_ops(plat)->misa_check_extension(ext);
return 0;
}
/**
* Get MXL field of MISA
*
* @param plat pointer to struct sbi_platform
*
* @return 1/2/3 on success and error code on failure
*/
static inline int sbi_platform_misa_xlen(const struct sbi_platform *plat)
{
if (plat && sbi_platform_ops(plat)->misa_get_xlen)
return sbi_platform_ops(plat)->misa_get_xlen();
return -1;
}
/**
* Get the number of PMP regions of a HART
*
@@ -325,8 +491,9 @@ static inline int sbi_platform_pmp_region_info(const struct sbi_platform *plat,
ulong *log2size)
{
if (plat && sbi_platform_ops(plat)->pmp_region_info)
return sbi_platform_ops(plat)->pmp_region_info(hartid, index, prot, addr,
log2size);
return sbi_platform_ops(plat)->pmp_region_info(hartid, index,
prot, addr,
log2size);
return 0;
}
@@ -387,6 +554,17 @@ static inline int sbi_platform_irqchip_init(const struct sbi_platform *plat,
return 0;
}
/**
* Exit the platform interrupt controller for current HART
*
* @param plat pointer to struct sbi_platform
*/
static inline void sbi_platform_irqchip_exit(const struct sbi_platform *plat)
{
if (plat && sbi_platform_ops(plat)->irqchip_exit)
sbi_platform_ops(plat)->irqchip_exit();
}
/**
* Send IPI to a target HART
*
@@ -429,6 +607,17 @@ static inline int sbi_platform_ipi_init(const struct sbi_platform *plat,
return 0;
}
/**
* Exit the platform IPI support for current HART
*
* @param plat pointer to struct sbi_platform
*/
static inline void sbi_platform_ipi_exit(const struct sbi_platform *plat)
{
if (plat && sbi_platform_ops(plat)->ipi_exit)
sbi_platform_ops(plat)->ipi_exit();
}
/**
* Get platform timer value
*
@@ -485,34 +674,29 @@ static inline int sbi_platform_timer_init(const struct sbi_platform *plat,
}
/**
* Reboot the platform
* Exit the platform timer for current HART
*
* @param plat pointer to struct sbi_platform
* @param type type of reboot
*
* @return 0 on success and negative error code on failure
*/
static inline int sbi_platform_system_reboot(const struct sbi_platform *plat,
u32 type)
static inline void sbi_platform_timer_exit(const struct sbi_platform *plat)
{
if (plat && sbi_platform_ops(plat)->system_reboot)
return sbi_platform_ops(plat)->system_reboot(type);
return 0;
if (plat && sbi_platform_ops(plat)->timer_exit)
sbi_platform_ops(plat)->timer_exit();
}
/**
* Shutdown or poweroff the platform
* Reset the platform
*
* @param plat pointer to struct sbi_platform
* @param type type of shutdown or poweroff
* @param reset_type type of reset
*
* @return 0 on success and negative error code on failure
*/
static inline int sbi_platform_system_shutdown(const struct sbi_platform *plat,
u32 type)
static inline int sbi_platform_system_reset(const struct sbi_platform *plat,
u32 reset_type)
{
if (plat && sbi_platform_ops(plat)->system_shutdown)
return sbi_platform_ops(plat)->system_shutdown(type);
if (plat && sbi_platform_ops(plat)->system_reset)
return sbi_platform_ops(plat)->system_reset(reset_type);
return 0;
}
@@ -540,25 +724,23 @@ static inline int sbi_platform_vendor_ext_check(const struct sbi_platform *plat,
* @param extid vendor SBI extension id
* @param funcid SBI function id within the extension id
* @param args pointer to arguments passed by the caller
* @param out_value output value that can be filled the callee
* @param out_tcause trap cause that can be filled the callee
* @param out_tvalue possible trap value that can be filled the callee
* @param out_value output value that can be filled by the callee
* @param out_trap trap info that can be filled by the callee
*
* @return 0 on success and negative error code on failure
*/
static inline int sbi_platform_vendor_ext_provider(const struct sbi_platform *plat,
long extid, long funcid,
unsigned long *args,
unsigned long *out_value,
unsigned long *out_tcause,
unsigned long *out_tval)
static inline int sbi_platform_vendor_ext_provider(
const struct sbi_platform *plat,
long extid, long funcid,
unsigned long *args,
unsigned long *out_value,
struct sbi_trap_info *out_trap)
{
if (plat && sbi_platform_ops(plat)->vendor_ext_provider) {
return sbi_platform_ops(plat)->vendor_ext_provider(extid,
funcid, args,
out_value,
out_tcause,
out_tval);
funcid, args,
out_value,
out_trap);
}
return SBI_ENOTSUPP;

View File

@@ -36,15 +36,14 @@
#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__)
/** Maximum size of sbi_scratch (4KB) */
#define SBI_SCRATCH_SIZE (0x1000)
/* clang-format on */
#ifndef __ASSEMBLY__
#include <sbi/sbi_types.h>
#include <sbi/sbi_ipi.h>
/** Representation of per-HART scratch space */
struct sbi_scratch {
@@ -86,7 +85,11 @@ enum sbi_scratch_options {
#define sbi_scratch_thishart_arg1_ptr() \
((void *)(sbi_scratch_thishart_ptr()->next_arg1))
/** Allocate from extra space in sbi_scratch
/** Initialize scatch table and allocator */
int sbi_scratch_init(struct sbi_scratch *scratch);
/**
* Allocate from extra space in sbi_scratch
*
* @return zero on failure and non-zero (>= SBI_SCRATCH_EXTRA_SPACE_OFFSET)
* on success
@@ -103,6 +106,19 @@ void sbi_scratch_free_offset(unsigned long offset);
#define sbi_scratch_thishart_offset_ptr(offset) \
((void *)sbi_scratch_thishart_ptr() + (offset))
/** HART id to scratch table */
extern struct sbi_scratch *hartid_to_scratch_table[];
/** Get sbi_scratch from HART id */
#define sbi_hartid_to_scratch(__hartid) \
hartid_to_scratch_table[__hartid]
/** Last HART id having a sbi_scratch pointer */
extern u32 last_hartid_having_scratch;
/** Get last HART id having a sbi_scratch pointer */
#define sbi_scratch_last_hartid() last_hartid_having_scratch
#endif
#endif

View File

@@ -12,16 +12,6 @@
#include <sbi/sbi_types.h>
struct sbi_scratch;
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_shutdown(struct sbi_scratch *scratch, u32 type);
void __noreturn sbi_system_reset(u32 platform_reset_type);
#endif

View File

@@ -14,22 +14,31 @@
struct sbi_scratch;
u64 sbi_timer_value(struct sbi_scratch *scratch);
/** Get timer value for current HART */
u64 sbi_timer_value(void);
u64 sbi_timer_virt_value(struct sbi_scratch *scratch);
/** Get virtualized timer value for current HART */
u64 sbi_timer_virt_value(void);
u64 sbi_timer_get_delta(struct sbi_scratch *scratch);
/** Get timer delta value for current HART */
u64 sbi_timer_get_delta(void);
void sbi_timer_set_delta(struct sbi_scratch *scratch, ulong delta);
/** Set timer delta value for current HART */
void sbi_timer_set_delta(ulong delta);
void sbi_timer_set_delta_upper(struct sbi_scratch *scratch, ulong delta_upper);
/** Set upper 32-bits of timer delta value for current HART */
void sbi_timer_set_delta_upper(ulong delta_upper);
void sbi_timer_event_stop(struct sbi_scratch *scratch);
/** Start timer event for current HART */
void sbi_timer_event_start(u64 next_event);
void sbi_timer_event_start(struct sbi_scratch *scratch, u64 next_event);
void sbi_timer_process(struct sbi_scratch *scratch);
/** Process timer event for current HART */
void sbi_timer_process(void);
/* Initialize timer */
int sbi_timer_init(struct sbi_scratch *scratch, bool cold_boot);
/* Exit timer */
void sbi_timer_exit(struct sbi_scratch *scratch);
#endif

View File

@@ -12,6 +12,7 @@
#define __SBI_TLB_H__
#include <sbi/sbi_types.h>
#include <sbi/sbi_hartmask.h>
/* clang-format off */
@@ -24,7 +25,10 @@
enum sbi_tlb_info_types {
SBI_TLB_FLUSH_VMA,
SBI_TLB_FLUSH_VMA_ASID,
SBI_TLB_FLUSH_VMA_VMID,
SBI_TLB_FLUSH_GVMA,
SBI_TLB_FLUSH_GVMA_VMID,
SBI_TLB_FLUSH_VVMA,
SBI_TLB_FLUSH_VVMA_ASID,
SBI_ITLB_FLUSH
};
@@ -34,18 +38,25 @@ struct sbi_tlb_info {
unsigned long start;
unsigned long size;
unsigned long asid;
unsigned long vmid;
unsigned long type;
unsigned long shart_mask;
struct sbi_hartmask smask;
};
#define SBI_TLB_INFO_SIZE sizeof(struct sbi_tlb_info)
#define SBI_TLB_INFO_INIT(__p, __start, __size, __asid, __vmid, __type, __src) \
do { \
(__p)->start = (__start); \
(__p)->size = (__size); \
(__p)->asid = (__asid); \
(__p)->vmid = (__vmid); \
(__p)->type = (__type); \
SBI_HARTMASK_INIT_EXCEPT(&(__p)->smask, (__src)); \
} while (0)
int sbi_tlb_fifo_update(struct sbi_scratch *scratch, u32 hartid, void *data);
#define SBI_TLB_INFO_SIZE sizeof(struct sbi_tlb_info)
void sbi_tlb_fifo_process(struct sbi_scratch *scratch);
int sbi_tlb_request(ulong hmask, ulong hbase, struct sbi_tlb_info *tinfo);
int sbi_tlb_fifo_init(struct sbi_scratch *scratch, bool cold_boot);
void sbi_tlb_fifo_sync(struct sbi_scratch *scratch);
int sbi_tlb_init(struct sbi_scratch *scratch, bool cold_boot);
#endif

View File

@@ -85,6 +85,19 @@
/** Last member index in sbi_trap_regs */
#define SBI_TRAP_REGS_last 35
/** Index of epc member in sbi_trap_info */
#define SBI_TRAP_INFO_epc 0
/** Index of cause member in sbi_trap_info */
#define SBI_TRAP_INFO_cause 1
/** Index of tval member in sbi_trap_info */
#define SBI_TRAP_INFO_tval 2
/** Index of tval2 member in sbi_trap_info */
#define SBI_TRAP_INFO_tval2 3
/** Index of tinst member in sbi_trap_info */
#define SBI_TRAP_INFO_tinst 4
/** Last member index in sbi_trap_info */
#define SBI_TRAP_INFO_last 5
/* clang-format on */
/** Get offset of member with name 'x' in sbi_trap_regs */
@@ -92,6 +105,11 @@
/** Size (in bytes) of sbi_trap_regs */
#define SBI_TRAP_REGS_SIZE SBI_TRAP_REGS_OFFSET(last)
/** Get offset of member with name 'x' in sbi_trap_info */
#define SBI_TRAP_INFO_OFFSET(x) ((SBI_TRAP_INFO_##x) * __SIZEOF_POINTER__)
/** Size (in bytes) of sbi_trap_info */
#define SBI_TRAP_INFO_SIZE SBI_TRAP_INFO_OFFSET(last)
#ifndef __ASSEMBLY__
#include <sbi/sbi_types.h>
@@ -170,12 +188,24 @@ struct sbi_trap_regs {
unsigned long mstatusH;
} __packed;
struct sbi_scratch;
/** Representation of trap details */
struct sbi_trap_info {
/** epc Trap program counter */
unsigned long epc;
/** cause Trap exception cause */
unsigned long cause;
/** tval Trap value */
unsigned long tval;
/** tval2 Trap value 2 */
unsigned long tval2;
/** tinst Trap instruction */
unsigned long tinst;
};
int sbi_trap_redirect(struct sbi_trap_regs *regs, struct sbi_scratch *scratch,
ulong epc, ulong cause, ulong tval);
int sbi_trap_redirect(struct sbi_trap_regs *regs,
struct sbi_trap_info *trap);
void sbi_trap_handler(struct sbi_trap_regs *regs, struct sbi_scratch *scratch);
void sbi_trap_handler(struct sbi_trap_regs *regs);
#endif

View File

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

View File

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

View File

@@ -11,12 +11,12 @@
#define __SBI_VERSION_H__
#define OPENSBI_VERSION_MAJOR 0
#define OPENSBI_VERSION_MINOR 5
#define OPENSBI_VERSION_MINOR 8
/**
* OpenSBI 32-bit version with:
* 1. upper 16-bits as major number
* 2. lower 16-bits as minor number
* 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))

View File

@@ -0,0 +1,78 @@
// SPDX-License-Identifier: BSD-2-Clause
/*
* fdt_fixup.h - Flat Device Tree manipulation helper routines
* Implement platform specific DT fixups on top of libfdt.
*
* Copyright (C) 2020 Bin Meng <bmeng.cn@gmail.com>
*/
#ifndef __FDT_FIXUP_H__
#define __FDT_FIXUP_H__
/**
* Fix up the CPU node in the device tree
*
* This routine updates the "status" property of a CPU node in the device tree
* to "disabled" if that hart is in disabled state in OpenSBI.
*
* It is recommended that platform codes call this helper in their final_init()
*
* @param fdt: device tree blob
*/
void fdt_cpu_fixup(void *fdt);
/**
* Fix up the PLIC node in the device tree
*
* This routine updates the "interrupt-extended" property of the PLIC node in
* the device tree to hide the M-mode external interrupt from CPUs.
*
* It is recommended that platform codes call this helper in their final_init()
*
* @param fdt: device tree blob
* @param compat: PLIC node compatible string
*/
void fdt_plic_fixup(void *fdt, const char *compat);
/**
* Fix up the reserved memory node in the device tree
*
* This routine inserts a child node of the reserved memory node in the device
* tree that describes the protected memory region done by OpenSBI via PMP.
*
* It is recommended that platform codes call this helper in their final_init()
*
* @param fdt: device tree blob
* @return zero on success and -ve on failure
*/
int fdt_reserved_memory_fixup(void *fdt);
/**
* Fix up the reserved memory subnodes in the device tree
*
* This routine adds the no-map property to the reserved memory subnodes so
* that the OS does not map those PMP protected memory regions.
*
* Platform codes must call this helper in their final_init() after fdt_fixups()
* if the OS should not map the PMP protected reserved regions.
*
* @param fdt: device tree blob
* @return zero on success and -ve on failure
*/
int fdt_reserved_memory_nomap_fixup(void *fdt);
/**
* General device tree fix-up
*
* This routine do all required device tree fix-ups for a typical platform.
* It fixes up the PLIC node and the reserved memory node in the device tree
* by calling the corresponding helper routines to accomplish the task.
*
* It is recommended that platform codes call this helper in their final_init()
*
* @param fdt: device tree blob
*/
void fdt_fixups(void *fdt);
#endif /* __FDT_FIXUP_H__ */

View File

@@ -0,0 +1,68 @@
// SPDX-License-Identifier: BSD-2-Clause
/*
* fdt_helper.h - Flat Device Tree parsing helper routines
* Implement helper routines to parse FDT nodes on top of
* libfdt for OpenSBI usage
*
* Copyright (C) 2020 Bin Meng <bmeng.cn@gmail.com>
*/
#ifndef __FDT_HELPER_H__
#define __FDT_HELPER_H__
#include <sbi/sbi_types.h>
struct fdt_match {
const char *compatible;
void *data;
};
struct platform_uart_data {
unsigned long addr;
unsigned long freq;
unsigned long baud;
unsigned long reg_shift;
unsigned long reg_io_width;
};
const struct fdt_match *fdt_match_node(void *fdt, int nodeoff,
const struct fdt_match *match_table);
int fdt_find_match(void *fdt, int startoff,
const struct fdt_match *match_table,
const struct fdt_match **out_match);
int fdt_get_node_addr_size(void *fdt, int node, unsigned long *addr,
unsigned long *size);
int fdt_parse_hart_id(void *fdt, int cpu_offset, u32 *hartid);
int fdt_parse_max_hart_id(void *fdt, u32 *max_hartid);
int fdt_parse_shakti_uart_node(void *fdt, int nodeoffset,
struct platform_uart_data *uart);
int fdt_parse_sifive_uart_node(void *fdt, int nodeoffset,
struct platform_uart_data *uart);
int fdt_parse_uart8250_node(void *fdt, int nodeoffset,
struct platform_uart_data *uart);
int fdt_parse_uart8250(void *fdt, struct platform_uart_data *uart,
const char *compatible);
struct plic_data;
int fdt_parse_plic_node(void *fdt, int nodeoffset, struct plic_data *plic);
int fdt_parse_plic(void *fdt, struct plic_data *plic, const char *compat);
struct clint_data;
int fdt_parse_clint_node(void *fdt, int nodeoffset, bool for_timer,
struct clint_data *clint);
int fdt_parse_compat_addr(void *fdt, unsigned long *addr,
const char *compatible);
#endif /* __FDT_HELPER_H__ */

View File

@@ -0,0 +1,32 @@
/*
* SPDX-License-Identifier: BSD-2-Clause
*
* Copyright (c) 2020 Western Digital Corporation or its affiliates.
*
* Authors:
* Anup Patel <anup.patel@wdc.com>
*/
#ifndef __FDT_IPI_H__
#define __FDT_IPI_H__
#include <sbi/sbi_types.h>
struct fdt_ipi {
const struct fdt_match *match_table;
int (*cold_init)(void *fdt, int nodeoff, const struct fdt_match *match);
int (*warm_init)(void);
void (*exit)(void);
void (*send)(u32 target_hart);
void (*clear)(u32 target_hart);
};
void fdt_ipi_send(u32 target_hart);
void fdt_ipi_clear(u32 target_hart);
void fdt_ipi_exit(void);
int fdt_ipi_init(bool cold_boot);
#endif

View File

@@ -0,0 +1,26 @@
/*
* SPDX-License-Identifier: BSD-2-Clause
*
* Copyright (c) 2020 Western Digital Corporation or its affiliates.
*
* Authors:
* Anup Patel <anup.patel@wdc.com>
*/
#ifndef __FDT_IRQCHIP_H__
#define __FDT_IRQCHIP_H__
#include <sbi/sbi_types.h>
struct fdt_irqchip {
const struct fdt_match *match_table;
int (*cold_init)(void *fdt, int nodeoff, const struct fdt_match *match);
int (*warm_init)(void);
void (*exit)(void);
};
void fdt_irqchip_exit(void);
int fdt_irqchip_init(bool cold_boot);
#endif

View File

@@ -12,14 +12,18 @@
#include <sbi/sbi_types.h>
void plic_fdt_fixup(void *fdt, const char *compat);
struct plic_data {
unsigned long addr;
unsigned long num_src;
};
int plic_warm_irqchip_init(u32 target_hart, int m_cntx_id, int s_cntx_id);
int plic_warm_irqchip_init(struct plic_data *plic,
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(struct plic_data *plic);
void plic_set_thresh(u32 cntxid, u32 val);
void plic_set_thresh(struct plic_data *plic, u32 cntxid, u32 val);
void plic_set_ie(u32 cntxid, u32 word_index, u32 val);
void plic_set_ie(struct plic_data *plic, u32 cntxid, u32 word_index, u32 val);
#endif

View File

@@ -0,0 +1,25 @@
/*
* SPDX-License-Identifier: BSD-2-Clause
*
* Copyright (c) 2020 Western Digital Corporation or its affiliates.
*
* Authors:
* Anup Patel <anup.patel@wdc.com>
*/
#ifndef __FDT_RESET_H__
#define __FDT_RESET_H__
#include <sbi/sbi_types.h>
struct fdt_reset {
const struct fdt_match *match_table;
int (*init)(void *fdt, int nodeoff, const struct fdt_match *match);
int (*system_reset)(u32 reset_type);
};
int fdt_system_reset(u32 reset_type);
int fdt_reset_init(void);
#endif

View File

@@ -0,0 +1,28 @@
/*
* SPDX-License-Identifier: BSD-2-Clause
*
* Copyright (c) 2020 Western Digital Corporation or its affiliates.
*
* Authors:
* Anup Patel <anup.patel@wdc.com>
*/
#ifndef __FDT_SERIAL_H__
#define __FDT_SERIAL_H__
#include <sbi/sbi_types.h>
struct fdt_serial {
const struct fdt_match *match_table;
int (*init)(void *fdt, int nodeoff, const struct fdt_match *match);
void (*putc)(char ch);
int (*getc)(void);
};
void fdt_serial_putc(char ch);
int fdt_serial_getc(void);
int fdt_serial_init(void);
#endif

View File

@@ -0,0 +1,18 @@
/*
* SPDX-License-Identifier: BSD-2-Clause
*
* Copyright (c) 2020 Vijai Kumar K <vijai@behindbytes.com>
*/
#ifndef __SERIAL_SHAKTI_UART_H__
#define __SERIAL_SHAKTI_UART_H__
#include <sbi/sbi_types.h>
void shakti_uart_putc(char ch);
int shakti_uart_getc(void);
int shakti_uart_init(unsigned long base, u32 in_freq, u32 baudrate);
#endif

View File

@@ -12,15 +12,30 @@
#include <sbi/sbi_types.h>
void clint_ipi_send(u32 target_hart);
struct clint_data {
/* Public details */
unsigned long addr;
u32 first_hartid;
u32 hart_count;
bool has_64bit_mmio;
/* Private details (initialized and used by CLINT library)*/
u32 *ipi;
struct clint_data *time_delta_reference;
unsigned long time_delta_computed;
u64 time_delta;
u64 *time_val;
u64 *time_cmp;
u64 (*time_rd)(volatile u64 *addr);
void (*time_wr)(u64 value, volatile u64 *addr);
};
void clint_ipi_sync(u32 target_hart);
void clint_ipi_send(u32 target_hart);
void clint_ipi_clear(u32 target_hart);
int clint_warm_ipi_init(void);
int clint_cold_ipi_init(unsigned long base, u32 hart_count);
int clint_cold_ipi_init(struct clint_data *clint);
u64 clint_timer_value(void);
@@ -30,6 +45,7 @@ void clint_timer_event_start(u64 next_event);
int clint_warm_timer_init(void);
int clint_cold_timer_init(unsigned long base, u32 hart_count);
int clint_cold_timer_init(struct clint_data *clint,
struct clint_data *reference);
#endif

View File

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

View File

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

View File

@@ -0,0 +1,35 @@
/*
* SPDX-License-Identifier: BSD-2-Clause
*
* Copyright (c) 2020 Western Digital Corporation or its affiliates.
*
* Authors:
* Anup Patel <anup.patel@wdc.com>
*/
#ifndef __FDT_TIMER_H__
#define __FDT_TIMER_H__
#include <sbi/sbi_types.h>
struct fdt_timer {
const struct fdt_match *match_table;
int (*cold_init)(void *fdt, int nodeoff, const struct fdt_match *match);
int (*warm_init)(void);
void (*exit)(void);
u64 (*value)(void);
void (*event_stop)(void);
void (*event_start)(u64 next_event);
};
u64 fdt_timer_value(void);
void fdt_timer_event_stop(void);
void fdt_timer_event_start(u64 next_event);
void fdt_timer_exit(void);
int fdt_timer_init(bool cold_boot);
#endif

View File

@@ -11,20 +11,32 @@ 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_bitmap.o
libsbi-objs-y += sbi_bitops.o
libsbi-objs-y += sbi_console.o
libsbi-objs-y += sbi_ecall.o
libsbi-objs-y += sbi_ecall_base.o
libsbi-objs-y += sbi_ecall_hsm.o
libsbi-objs-y += sbi_ecall_legacy.o
libsbi-objs-y += sbi_ecall_replace.o
libsbi-objs-y += sbi_ecall_vendor.o
libsbi-objs-y += sbi_emulate_csr.o
libsbi-objs-y += sbi_fifo.o
libsbi-objs-y += sbi_hart.o
libsbi-objs-y += sbi_math.o
libsbi-objs-y += sbi_hfence.o
libsbi-objs-y += sbi_hsm.o
libsbi-objs-y += sbi_illegal_insn.o
libsbi-objs-y += sbi_init.o
libsbi-objs-y += sbi_ipi.o
libsbi-objs-y += sbi_misaligned_ldst.o
libsbi-objs-y += sbi_platform.o
libsbi-objs-y += sbi_scratch.o
libsbi-objs-y += sbi_string.o
libsbi-objs-y += sbi_system.o
libsbi-objs-y += sbi_timer.o
libsbi-objs-y += sbi_tlb.o
libsbi-objs-y += sbi_trap.o
libsbi-objs-y += sbi_string.o
libsbi-objs-y += sbi_unpriv.o
libsbi-objs-y += sbi_expected_trap.o

View File

@@ -10,6 +10,83 @@
#include <sbi/riscv_asm.h>
#include <sbi/riscv_encoding.h>
#include <sbi/sbi_error.h>
#include <sbi/sbi_platform.h>
/* determine CPU extension, return non-zero support */
int misa_extension_imp(char ext)
{
unsigned long misa = csr_read(CSR_MISA);
if (misa) {
if ('A' <= ext && ext <= 'Z')
return misa & (1 << (ext - 'A'));
if ('a' <= ext && ext <= 'z')
return misa & (1 << (ext - 'a'));
return 0;
}
return sbi_platform_misa_extension(sbi_platform_thishart_ptr(), ext);
}
int misa_xlen(void)
{
long r;
if (csr_read(CSR_MISA) == 0)
return sbi_platform_misa_xlen(sbi_platform_thishart_ptr());
__asm__ __volatile__(
"csrr t0, misa\n\t"
"slti t1, t0, 0\n\t"
"slli t1, t1, 1\n\t"
"slli t0, t0, 1\n\t"
"slti t0, t0, 0\n\t"
"add %0, t0, t1"
: "=r"(r)
:
: "t0", "t1");
return r ? r : -1;
}
void misa_string(int xlen, char *out, unsigned int out_sz)
{
unsigned int i, pos = 0;
const char valid_isa_order[] = "iemafdqclbjtpvnsuhkorwxyzg";
if (!out)
return;
if (5 <= (out_sz - pos)) {
out[pos++] = 'r';
out[pos++] = 'v';
switch (xlen) {
case 1:
out[pos++] = '3';
out[pos++] = '2';
break;
case 2:
out[pos++] = '6';
out[pos++] = '4';
break;
case 3:
out[pos++] = '1';
out[pos++] = '2';
out[pos++] = '8';
break;
default:
return;
}
}
for (i = 0; i < array_size(valid_isa_order) && (pos < out_sz); i++) {
if (misa_extension_imp(valid_isa_order[i]))
out[pos++] = valid_isa_order[i];
}
if (pos < out_sz)
out[pos++] = '\0';
}
unsigned long csr_read_num(int csr_num)
{
@@ -174,7 +251,7 @@ int pmp_set(unsigned int n, unsigned long prot, unsigned long addr,
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_shift = (n & 3) << 3;
@@ -191,7 +268,7 @@ int pmp_set(unsigned int n, unsigned long prot, unsigned long addr,
/* encode PMP config */
prot |= (log2len == PMP_SHIFT) ? PMP_A_NA4 : PMP_A_NAPOT;
cfgmask = ~(0xff << pmpcfg_shift);
cfgmask = ~(0xffUL << pmpcfg_shift);
pmpcfg = (csr_read_num(pmpcfg_csr) & cfgmask);
pmpcfg |= ((prot << pmpcfg_shift) & ~cfgmask);
@@ -216,16 +293,16 @@ int pmp_set(unsigned int n, unsigned long prot, unsigned long addr,
}
int pmp_get(unsigned int n, unsigned long *prot_out, unsigned long *addr_out,
unsigned long *log2len_out)
unsigned long *size)
{
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 || !size)
return SBI_EINVAL;
*prot_out = *addr_out = *log2len_out = 0;
*prot_out = *addr_out = *size = 0;
/* calculate PMP register and offset */
#if __riscv_xlen == 32
@@ -243,7 +320,7 @@ int pmp_get(unsigned int n, unsigned long *prot_out, unsigned long *addr_out,
return SBI_ENOTSUPP;
/* decode PMP config */
cfgmask = (0xff << pmpcfg_shift);
cfgmask = (0xffUL << pmpcfg_shift);
pmpcfg = csr_read_num(pmpcfg_csr) & cfgmask;
prot = pmpcfg >> pmpcfg_shift;
@@ -266,7 +343,9 @@ int pmp_get(unsigned int n, unsigned long *prot_out, unsigned long *addr_out,
/* return details */
*prot_out = prot;
*addr_out = addr;
*log2len_out = log2len;
if (log2len < __riscv_xlen)
*size = (1UL << log2len);
return 0;
}

View File

@@ -7,11 +7,10 @@
* Anup Patel <anup.patel@wdc.com>
*/
#include <sbi/sbi_types.h>
#include <sbi/sbi_bitops.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)
{
@@ -50,7 +49,7 @@ long atomic_sub_return(atomic_t *atom, long value)
return ret - value;
}
#define __axchg(ptr, new, size) \
#define __axchg(ptr, new, size) \
({ \
__typeof__(ptr) __ptr = (ptr); \
__typeof__(new) __new = (new); \
@@ -71,15 +70,15 @@ long atomic_sub_return(atomic_t *atom, long value)
: "memory"); \
break; \
default: \
break; \
break; \
} \
__ret; \
})
#define axchg(ptr, x) \
#define axchg(ptr, x) \
({ \
__typeof__(*(ptr)) _x_ = (x); \
(__typeof__(*(ptr))) __xchg((ptr), _x_, sizeof(*(ptr))); \
(__typeof__(*(ptr))) __axchg((ptr), _x_, sizeof(*(ptr))); \
})
@@ -91,20 +90,20 @@ long atomic_sub_return(atomic_t *atom, long value)
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" \
__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" \
__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) \
@@ -131,11 +130,11 @@ long atomic_sub_return(atomic_t *atom, long value)
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" \
__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) \
@@ -143,11 +142,11 @@ long atomic_sub_return(atomic_t *atom, long value)
: "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" \
__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) \
@@ -168,7 +167,7 @@ long atomic_sub_return(atomic_t *atom, long value)
__cmpxchg((ptr), _o_, _n_, sizeof(*(ptr))); \
})
long arch_atomic_cmpxchg(atomic_t *atom, long oldval, long newval)
long atomic_cmpxchg(atomic_t *atom, long oldval, long newval)
{
#ifdef __riscv_atomic
return __sync_val_compare_and_swap(&atom->counter, oldval, newval);
@@ -177,7 +176,7 @@ long arch_atomic_cmpxchg(atomic_t *atom, long oldval, long newval)
#endif
}
long arch_atomic_xchg(atomic_t *atom, long newval)
long atomic_xchg(atomic_t *atom, long newval)
{
/* Atomically set new value and return old value. */
#ifdef __riscv_atomic
@@ -209,12 +208,12 @@ unsigned long atomic_raw_xchg_ulong(volatile unsigned long *ptr,
#endif
}
#if (BITS_PER_LONG == 64)
#if (__SIZEOF_POINTER__ == 8)
#define __AMO(op) "amo" #op ".d"
#elif (BITS_PER_LONG == 32)
#elif (__SIZEOF_POINTER__ == 4)
#define __AMO(op) "amo" #op ".w"
#else
#error "Unexpected BITS_PER_LONG"
#error "Unexpected __SIZEOF_POINTER__"
#endif
#define __atomic_op_bit_ord(op, mod, nr, addr, ord) \

View File

@@ -1,158 +0,0 @@
/*
* SPDX-License-Identifier: BSD-2-Clause
*
* Copyright (c) 2019 Western Digital Corporation or its affiliates.
*
* Authors:
* Anup Patel <anup.patel@wdc.com>
*/
#include <sbi/riscv_encoding.h>
#include <sbi/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;
}

40
lib/sbi/sbi_bitmap.c Normal file
View File

@@ -0,0 +1,40 @@
/*
* SPDX-License-Identifier: BSD-2-Clause
*
* Copyright (c) 2020 Western Digital Corporation or its affiliates.
*
* Authors:
* Anup Patel <anup.patel@wdc.com>
*/
#include <sbi/sbi_bitmap.h>
void __bitmap_and(unsigned long *dst, const unsigned long *bitmap1,
const unsigned long *bitmap2, int bits)
{
int k;
int nr = BITS_TO_LONGS(bits);
for (k = 0; k < nr; k++)
dst[k] = bitmap1[k] & bitmap2[k];
}
void __bitmap_or(unsigned long *dst, const unsigned long *bitmap1,
const unsigned long *bitmap2, int bits)
{
int k;
int nr = BITS_TO_LONGS(bits);
for (k = 0; k < nr; k++)
dst[k] = bitmap1[k] | bitmap2[k];
}
void __bitmap_xor(unsigned long *dst, const unsigned long *bitmap1,
const unsigned long *bitmap2, int bits)
{
int k;
int nr = BITS_TO_LONGS(bits);
for (k = 0; k < nr; k++)
dst[k] = bitmap1[k] ^ bitmap2[k];
}

200
lib/sbi/sbi_bitops.c Normal file
View File

@@ -0,0 +1,200 @@
/*
* SPDX-License-Identifier: BSD-2-Clause
*
* Copyright (c) 2020 Western Digital Corporation or its affiliates.
*
* Authors:
* Atish Patra <atish.patra@wdc.com>
* Anup Patel <anup.patel@wdc.com>
*/
#include <sbi/sbi_bitops.h>
#define BITOP_WORD(nr) ((nr) / BITS_PER_LONG)
/**
* find_first_bit - find the first set bit in a memory region
* @addr: The address to start the search at
* @size: The maximum size to search
*
* Returns the bit number of the first set bit.
*/
unsigned long find_first_bit(const unsigned long *addr,
unsigned long size)
{
const unsigned long *p = addr;
unsigned long result = 0;
unsigned long tmp;
while (size & ~(BITS_PER_LONG-1)) {
if ((tmp = *(p++)))
goto found;
result += BITS_PER_LONG;
size -= BITS_PER_LONG;
}
if (!size)
return result;
tmp = (*p) & (~0UL >> (BITS_PER_LONG - size));
if (tmp == 0UL) /* Are any bits set? */
return result + size; /* Nope. */
found:
return result + __ffs(tmp);
}
/**
* find_first_zero_bit - find the first cleared bit in a memory region
* @addr: The address to start the search at
* @size: The maximum size to search
*
* Returns the bit number of the first cleared bit.
*/
unsigned long find_first_zero_bit(const unsigned long *addr,
unsigned long size)
{
const unsigned long *p = addr;
unsigned long result = 0;
unsigned long tmp;
while (size & ~(BITS_PER_LONG-1)) {
if (~(tmp = *(p++)))
goto found;
result += BITS_PER_LONG;
size -= BITS_PER_LONG;
}
if (!size)
return result;
tmp = (*p) | (~0UL << size);
if (tmp == ~0UL) /* Are any bits zero? */
return result + size; /* Nope. */
found:
return result + ffz(tmp);
}
/**
* find_last_bit - find the last set bit in a memory region
* @addr: The address to start the search at
* @size: The maximum size to search
*
* Returns the bit number of the first set bit, or size.
*/
unsigned long find_last_bit(const unsigned long *addr,
unsigned long size)
{
unsigned long words;
unsigned long tmp;
/* Start at final word. */
words = size / BITS_PER_LONG;
/* Partial final word? */
if (size & (BITS_PER_LONG-1)) {
tmp = (addr[words] & (~0UL >> (BITS_PER_LONG
- (size & (BITS_PER_LONG-1)))));
if (tmp)
goto found;
}
while (words) {
tmp = addr[--words];
if (tmp) {
found:
return words * BITS_PER_LONG + __fls(tmp);
}
}
/* Not found */
return size;
}
/**
* find_next_bit - find the next set bit in a memory region
* @addr: The address to base the search on
* @offset: The bitnumber to start searching at
* @size: The bitmap size in bits
*/
unsigned long find_next_bit(const unsigned long *addr,
unsigned long size, unsigned long offset)
{
const unsigned long *p = addr + BITOP_WORD(offset);
unsigned long result = offset & ~(BITS_PER_LONG-1);
unsigned long tmp;
if (offset >= size)
return size;
size -= result;
offset %= BITS_PER_LONG;
if (offset) {
tmp = *(p++);
tmp &= (~0UL << offset);
if (size < BITS_PER_LONG)
goto found_first;
if (tmp)
goto found_middle;
size -= BITS_PER_LONG;
result += BITS_PER_LONG;
}
while (size & ~(BITS_PER_LONG-1)) {
if ((tmp = *(p++)))
goto found_middle;
result += BITS_PER_LONG;
size -= BITS_PER_LONG;
}
if (!size)
return result;
tmp = *p;
found_first:
tmp &= (~0UL >> (BITS_PER_LONG - size));
if (tmp == 0UL) /* Are any bits set? */
return result + size; /* Nope. */
found_middle:
return result + __ffs(tmp);
}
/**
* find_next_zero_bit - find the next cleared bit in a memory region
* @addr: The address to base the search on
* @offset: The bitnumber to start searching at
* @size: The bitmap size in bits
*/
unsigned long find_next_zero_bit(const unsigned long *addr,
unsigned long size,
unsigned long offset)
{
const unsigned long *p = addr + BITOP_WORD(offset);
unsigned long result = offset & ~(BITS_PER_LONG-1);
unsigned long tmp;
if (offset >= size)
return size;
size -= result;
offset %= BITS_PER_LONG;
if (offset) {
tmp = *(p++);
tmp |= ~0UL >> (BITS_PER_LONG - offset);
if (size < BITS_PER_LONG)
goto found_first;
if (~tmp)
goto found_middle;
size -= BITS_PER_LONG;
result += BITS_PER_LONG;
}
while (size & ~(BITS_PER_LONG-1)) {
if (~(tmp = *(p++)))
goto found_middle;
result += BITS_PER_LONG;
size -= BITS_PER_LONG;
}
if (!size)
return result;
tmp = *p;
found_first:
tmp |= ~0UL << size;
if (tmp == ~0UL) /* Are any bits zero? */
return result + size; /* Nope. */
found_middle:
return result + ffz(tmp);
}

View File

@@ -7,9 +7,10 @@
* Anup Patel <anup.patel@wdc.com>
*/
#include <sbi/sbi_platform.h>
#include <sbi/sbi_console.h>
#include <sbi/riscv_locks.h>
#include <sbi/sbi_console.h>
#include <sbi/sbi_platform.h>
#include <sbi/sbi_scratch.h>
static const struct sbi_platform *console_plat = NULL;
static spinlock_t console_out_lock = SPIN_LOCK_INITIALIZER;
@@ -375,10 +376,11 @@ int sbi_printf(const char *format, ...)
return retval;
}
int sbi_dprintf(struct sbi_scratch *scratch, const char *format, ...)
int sbi_dprintf(const char *format, ...)
{
va_list args;
int retval = 0;
struct sbi_scratch *scratch = sbi_scratch_thishart_ptr();
va_start(args, format);
if (scratch->options & SBI_SCRATCH_DEBUG_PRINTS)

View File

@@ -11,19 +11,7 @@
#include <sbi/sbi_ecall.h>
#include <sbi/sbi_ecall_interface.h>
#include <sbi/sbi_error.h>
#include <sbi/sbi_ipi.h>
#include <sbi/sbi_platform.h>
#include <sbi/sbi_system.h>
#include <sbi/sbi_timer.h>
#include <sbi/sbi_tlb.h>
#include <sbi/sbi_trap.h>
#include <sbi/sbi_hart.h>
#include <sbi/sbi_version.h>
#include <sbi/riscv_asm.h>
#define SBI_ECALL_VERSION_MAJOR 0
#define SBI_ECALL_VERSION_MINOR 2
#define SBI_OPENSBI_IMPID 1
u16 sbi_ecall_version_major(void)
{
@@ -35,164 +23,83 @@ u16 sbi_ecall_version_minor(void)
return SBI_ECALL_VERSION_MINOR;
}
int sbi_check_extension(struct sbi_scratch *scratch, unsigned long extid,
unsigned long *out_val)
{
/**
* Each extension apart from base & 0.1, will be implemented as
* platform specific feature. Thus, extension probing can be achieved
* by checking the feature bits of the platform. We can create a map
* between extension ID & feature and use a generic function to check
* or just use a switch case for every new extension support added
* TODO: Implement it.
*/
static unsigned long ecall_impid = SBI_OPENSBI_IMPID;
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;
unsigned long sbi_ecall_get_impid(void)
{
return ecall_impid;
}
void sbi_ecall_set_impid(unsigned long impid)
{
ecall_impid = impid;
}
static SBI_LIST_HEAD(ecall_exts_list);
struct sbi_ecall_extension *sbi_ecall_find_extension(unsigned long extid)
{
struct sbi_ecall_extension *t, *ret = NULL;
sbi_list_for_each_entry(t, &ecall_exts_list, head) {
if (t->extid_start <= extid && extid <= t->extid_end) {
ret = t;
break;
}
}
return ret;
}
int sbi_ecall_register_extension(struct sbi_ecall_extension *ext)
{
struct sbi_ecall_extension *t;
if (!ext || (ext->extid_end < ext->extid_start) || !ext->handle)
return SBI_EINVAL;
sbi_list_for_each_entry(t, &ecall_exts_list, head) {
unsigned long start = t->extid_start;
unsigned long end = t->extid_end;
if (end < ext->extid_start || ext->extid_end < start)
/* no overlap */;
else
return SBI_EINVAL;
}
SBI_INIT_LIST_HEAD(&ext->head);
sbi_list_add_tail(&ext->head, &ecall_exts_list);
return 0;
}
int sbi_ecall_vendor_ext_handler(struct sbi_scratch *scratch,
unsigned long extid, unsigned long funcid,
unsigned long *args, unsigned long *out_val,
unsigned long *out_tcause,
unsigned long *out_tval)
void sbi_ecall_unregister_extension(struct sbi_ecall_extension *ext)
{
return sbi_platform_vendor_ext_provider(sbi_platform_ptr(scratch),
extid, funcid, args, out_val,
out_tcause, out_tval);
}
bool found = FALSE;
struct sbi_ecall_extension *t;
int sbi_ecall_base_handler(struct sbi_scratch *scratch, unsigned long extid,
unsigned long funcid, unsigned long *args,
unsigned long *out_val, unsigned long *out_tcause,
unsigned long *out_tval)
{
int ret = 0;
if (!ext)
return;
switch (funcid) {
case SBI_EXT_BASE_GET_SPEC_VERSION:
*out_val = (SBI_ECALL_VERSION_MAJOR <<
SBI_SPEC_VERSION_MAJOR_OFFSET) &
(SBI_SPEC_VERSION_MAJOR_MASK <<
SBI_SPEC_VERSION_MAJOR_OFFSET);
*out_val = *out_val | SBI_ECALL_VERSION_MINOR;
break;
case SBI_EXT_BASE_GET_IMP_ID:
*out_val = SBI_OPENSBI_IMPID;
break;
case SBI_EXT_BASE_GET_IMP_VERSION:
*out_val = OPENSBI_VERSION;
break;
case SBI_EXT_BASE_GET_MVENDORID:
*out_val = csr_read(CSR_MVENDORID);
break;
case SBI_EXT_BASE_GET_MARCHID:
*out_val = csr_read(CSR_MARCHID);
break;
case SBI_EXT_BASE_GET_MIMPID:
*out_val = csr_read(CSR_MIMPID);
break;
case SBI_EXT_BASE_PROBE_EXT:
ret = sbi_check_extension(scratch, args[0], out_val);
default:
ret = SBI_ENOTSUPP;
sbi_list_for_each_entry(t, &ecall_exts_list, head) {
if (t == ext) {
found = TRUE;
break;
}
}
return ret;
if (found)
sbi_list_del_init(&ext->head);
}
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 sbi_ecall_handler(struct sbi_trap_regs *regs)
{
int ret = 0;
struct sbi_ecall_extension *ext;
unsigned long extension_id = regs->a7;
unsigned long func_id = regs->a6;
unsigned long out_val;
unsigned long out_tval;
unsigned long out_tcause;
struct sbi_trap_info trap = {0};
unsigned long out_val = 0;
bool is_0_1_spec = 0;
unsigned long args[6];
@@ -203,29 +110,30 @@ int sbi_ecall_handler(u32 hartid, ulong mcause, struct sbi_trap_regs *regs,
args[4] = regs->a4;
args[5] = regs->a5;
if (extension_id >= SBI_EXT_0_1_SET_TIMER &&
extension_id <= SBI_EXT_0_1_SHUTDOWN) {
ret = sbi_ecall_0_1_handler(scratch, extension_id, args,
&out_tval, &out_tcause);
is_0_1_spec = 1;
} else if (extension_id == SBI_EXT_BASE)
ret = sbi_ecall_base_handler(scratch, extension_id, func_id,
args, &out_val,
&out_tval, &out_tcause);
else if (extension_id >= SBI_EXT_VENDOR_START &&
extension_id <= SBI_EXT_VENDOR_END) {
ret = sbi_ecall_vendor_ext_handler(scratch, extension_id,
func_id, args, &out_val,
&out_tval, &out_tcause);
ext = sbi_ecall_find_extension(extension_id);
if (ext && ext->handle) {
ret = ext->handle(extension_id, func_id,
args, &out_val, &trap);
if (extension_id >= SBI_EXT_0_1_SET_TIMER &&
extension_id <= SBI_EXT_0_1_SHUTDOWN)
is_0_1_spec = 1;
} else {
ret = SBI_ENOTSUPP;
}
if (ret == SBI_ETRAP) {
sbi_trap_redirect(regs, scratch, regs->mepc,
out_tcause, out_tval);
trap.epc = regs->mepc;
sbi_trap_redirect(regs, &trap);
} else {
/* This function should return non-zero value only in case of
if (ret < SBI_LAST_ERR) {
sbi_printf("%s: Invalid error %d for ext=0x%lx "
"func=0x%lx\n", __func__, ret,
extension_id, func_id);
ret = SBI_ERR_FAILED;
}
/*
* 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
@@ -240,3 +148,33 @@ int sbi_ecall_handler(u32 hartid, ulong mcause, struct sbi_trap_regs *regs,
return 0;
}
int sbi_ecall_init(void)
{
int ret;
/* The order of below registrations is performance optimized */
ret = sbi_ecall_register_extension(&ecall_time);
if (ret)
return ret;
ret = sbi_ecall_register_extension(&ecall_rfence);
if (ret)
return ret;
ret = sbi_ecall_register_extension(&ecall_ipi);
if (ret)
return ret;
ret = sbi_ecall_register_extension(&ecall_base);
if (ret)
return ret;
ret = sbi_ecall_register_extension(&ecall_hsm);
if (ret)
return ret;
ret = sbi_ecall_register_extension(&ecall_legacy);
if (ret)
return ret;
ret = sbi_ecall_register_extension(&ecall_vendor);
if (ret)
return ret;
return 0;
}

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

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

51
lib/sbi/sbi_ecall_hsm.c Normal file
View File

@@ -0,0 +1,51 @@
/*
* SPDX-License-Identifier: BSD-2-Clause
*
* Copyright (c) 2020 Western Digital Corporation or its affiliates.
*
* Authors:
* Atish Patra <atish.patra@wdc.com>
*/
#include <sbi/sbi_ecall.h>
#include <sbi/sbi_ecall_interface.h>
#include <sbi/sbi_error.h>
#include <sbi/sbi_version.h>
#include <sbi/sbi_hsm.h>
#include <sbi/sbi_scratch.h>
#include <sbi/riscv_asm.h>
static int sbi_ecall_hsm_handler(unsigned long extid, unsigned long funcid,
unsigned long *args, unsigned long *out_val,
struct sbi_trap_info *out_trap)
{
int ret = 0, hstate;
struct sbi_scratch *scratch = sbi_scratch_thishart_ptr();
switch (funcid) {
case SBI_EXT_HSM_HART_START:
ret = sbi_hsm_hart_start(scratch, args[0], args[1], args[2]);
break;
case SBI_EXT_HSM_HART_STOP:
ret = sbi_hsm_hart_stop(scratch, TRUE);
break;
case SBI_EXT_HSM_HART_GET_STATUS:
hstate = sbi_hsm_hart_get_state(args[0]);
ret = sbi_hsm_hart_state_to_status(hstate);
break;
default:
ret = SBI_ENOTSUPP;
};
if (ret >= 0) {
*out_val = ret;
ret = 0;
}
return ret;
}
struct sbi_ecall_extension ecall_hsm = {
.extid_start = SBI_EXT_HSM,
.extid_end = SBI_EXT_HSM,
.handle = sbi_ecall_hsm_handler,
};

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

@@ -0,0 +1,117 @@
/*
* SPDX-License-Identifier: BSD-2-Clause
*
* Copyright (c) 2020 Western Digital Corporation or its affiliates.
*
* Authors:
* Anup Patel <anup.patel@wdc.com>
* Atish Patra <atish.patra@wdc.com>
*/
#include <sbi/riscv_asm.h>
#include <sbi/sbi_console.h>
#include <sbi/sbi_ecall.h>
#include <sbi/sbi_ecall_interface.h>
#include <sbi/sbi_error.h>
#include <sbi/sbi_hsm.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_unpriv.h>
#include <sbi/sbi_hart.h>
static int sbi_load_hart_mask_unpriv(ulong *pmask, ulong *hmask,
struct sbi_trap_info *uptrap)
{
ulong mask = 0;
if (pmask) {
mask = sbi_load_ulong(pmask, uptrap);
if (uptrap->cause)
return SBI_ETRAP;
} else {
sbi_hsm_hart_started_mask(0, &mask);
}
*hmask = mask;
return 0;
}
static int sbi_ecall_legacy_handler(unsigned long extid, unsigned long funcid,
unsigned long *args, unsigned long *out_val,
struct sbi_trap_info *out_trap)
{
int ret = 0;
struct sbi_tlb_info tlb_info;
u32 source_hart = current_hartid();
ulong hmask = 0;
switch (extid) {
case SBI_EXT_0_1_SET_TIMER:
#if __riscv_xlen == 32
sbi_timer_event_start((((u64)args[1] << 32) | (u64)args[0]));
#else
sbi_timer_event_start((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();
break;
case SBI_EXT_0_1_SEND_IPI:
ret = sbi_load_hart_mask_unpriv((ulong *)args[0],
&hmask, out_trap);
if (ret != SBI_ETRAP)
ret = sbi_ipi_send_smode(hmask, 0);
break;
case SBI_EXT_0_1_REMOTE_FENCE_I:
ret = sbi_load_hart_mask_unpriv((ulong *)args[0],
&hmask, out_trap);
if (ret != SBI_ETRAP) {
SBI_TLB_INFO_INIT(&tlb_info, 0, 0, 0, 0,
SBI_ITLB_FLUSH, source_hart);
ret = sbi_tlb_request(hmask, 0, &tlb_info);
}
break;
case SBI_EXT_0_1_REMOTE_SFENCE_VMA:
ret = sbi_load_hart_mask_unpriv((ulong *)args[0],
&hmask, out_trap);
if (ret != SBI_ETRAP) {
SBI_TLB_INFO_INIT(&tlb_info, args[1], args[2], 0, 0,
SBI_TLB_FLUSH_VMA, source_hart);
ret = sbi_tlb_request(hmask, 0, &tlb_info);
}
break;
case SBI_EXT_0_1_REMOTE_SFENCE_VMA_ASID:
ret = sbi_load_hart_mask_unpriv((ulong *)args[0],
&hmask, out_trap);
if (ret != SBI_ETRAP) {
SBI_TLB_INFO_INIT(&tlb_info, args[1], args[2], args[3],
0, SBI_TLB_FLUSH_VMA_ASID,
source_hart);
ret = sbi_tlb_request(hmask, 0, &tlb_info);
}
break;
case SBI_EXT_0_1_SHUTDOWN:
sbi_system_reset(SBI_PLATFORM_RESET_SHUTDOWN);
break;
default:
ret = SBI_ENOTSUPP;
};
return ret;
}
struct sbi_ecall_extension ecall_legacy = {
.extid_start = SBI_EXT_0_1_SET_TIMER,
.extid_end = SBI_EXT_0_1_SHUTDOWN,
.handle = sbi_ecall_legacy_handler,
};

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

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

View File

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

View File

@@ -9,15 +9,15 @@
#include <sbi/riscv_asm.h>
#include <sbi/riscv_encoding.h>
#include <sbi/sbi_bits.h>
#include <sbi/sbi_bitops.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 sbi_emulate_csr_read(int csr_num, struct sbi_trap_regs *regs,
ulong *csr_val)
{
int ret = 0;
ulong cen = -1UL;
@@ -34,7 +34,7 @@ int sbi_emulate_csr_read(int csr_num, u32 hartid, struct sbi_trap_regs *regs,
switch (csr_num) {
case CSR_HTIMEDELTA:
if (prev_mode == PRV_S && !virt)
*csr_val = sbi_timer_get_delta(scratch);
*csr_val = sbi_timer_get_delta();
else
ret = SBI_ENOTSUPP;
break;
@@ -46,8 +46,8 @@ int sbi_emulate_csr_read(int csr_num, u32 hartid, struct sbi_trap_regs *regs,
case CSR_TIME:
if (!((cen >> (CSR_TIME - CSR_CYCLE)) & 1))
return -1;
*csr_val = (virt) ? sbi_timer_virt_value(scratch):
sbi_timer_value(scratch);
*csr_val = (virt) ? sbi_timer_virt_value():
sbi_timer_value();
break;
case CSR_INSTRET:
if (!((cen >> (CSR_INSTRET - CSR_CYCLE)) & 1))
@@ -67,7 +67,7 @@ int sbi_emulate_csr_read(int csr_num, u32 hartid, struct sbi_trap_regs *regs,
#if __riscv_xlen == 32
case CSR_HTIMEDELTAH:
if (prev_mode == PRV_S && !virt)
*csr_val = sbi_timer_get_delta(scratch) >> 32;
*csr_val = sbi_timer_get_delta() >> 32;
else
ret = SBI_ENOTSUPP;
break;
@@ -79,8 +79,8 @@ int sbi_emulate_csr_read(int csr_num, u32 hartid, struct sbi_trap_regs *regs,
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;
*csr_val = (virt) ? sbi_timer_virt_value() >> 32:
sbi_timer_value() >> 32;
break;
case CSR_INSTRETH:
if (!((cen >> (CSR_INSTRET - CSR_CYCLE)) & 1))
@@ -110,14 +110,14 @@ int sbi_emulate_csr_read(int csr_num, u32 hartid, struct sbi_trap_regs *regs,
};
if (ret)
sbi_dprintf(scratch, "%s: hartid%d: invalid csr_num=0x%x\n",
__func__, hartid, csr_num);
sbi_dprintf("%s: hartid%d: invalid csr_num=0x%x\n",
__func__, current_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 sbi_emulate_csr_write(int csr_num, struct sbi_trap_regs *regs,
ulong csr_val)
{
int ret = 0;
ulong prev_mode = (regs->mstatus & MSTATUS_MPP) >> MSTATUS_MPP_SHIFT;
@@ -130,7 +130,7 @@ int sbi_emulate_csr_write(int csr_num, u32 hartid, struct sbi_trap_regs *regs,
switch (csr_num) {
case CSR_HTIMEDELTA:
if (prev_mode == PRV_S && !virt)
sbi_timer_set_delta(scratch, csr_val);
sbi_timer_set_delta(csr_val);
else
ret = SBI_ENOTSUPP;
break;
@@ -149,7 +149,7 @@ int sbi_emulate_csr_write(int csr_num, u32 hartid, struct sbi_trap_regs *regs,
#if __riscv_xlen == 32
case CSR_HTIMEDELTAH:
if (prev_mode == PRV_S && !virt)
sbi_timer_set_delta_upper(scratch, csr_val);
sbi_timer_set_delta_upper(csr_val);
else
ret = SBI_ENOTSUPP;
break;
@@ -178,8 +178,8 @@ int sbi_emulate_csr_write(int csr_num, u32 hartid, struct sbi_trap_regs *regs,
};
if (ret)
sbi_dprintf(scratch, "%s: hartid%d: invalid csr_num=0x%x\n",
__func__, hartid, csr_num);
sbi_dprintf("%s: hartid%d: invalid csr_num=0x%x\n",
__func__, current_hartid(), csr_num);
return ret;
}

View File

@@ -0,0 +1,56 @@
/*
* SPDX-License-Identifier: BSD-2-Clause
*
* Copyright (c) 2020 Western Digital Corporation or its affiliates.
*
* Authors:
* Anup Patel <anup.patel@wdc.com>
*/
#include <sbi/riscv_asm.h>
#include <sbi/sbi_trap.h>
/*
* We assume that faulting instruction is is 4-byte long and blindly
* increment SEPC by 4.
*
* The trap info will be saved as follows:
* A3 <- pointer struct sbi_trap_info
* A4 <- temporary
*/
.align 3
.global __sbi_expected_trap
__sbi_expected_trap:
/* Without H-extension so, MTVAL2 and MTINST CSRs not available */
csrr a4, CSR_MEPC
REG_S a4, SBI_TRAP_INFO_OFFSET(epc)(a3)
csrr a4, CSR_MCAUSE
REG_S a4, SBI_TRAP_INFO_OFFSET(cause)(a3)
csrr a4, CSR_MTVAL
REG_S a4, SBI_TRAP_INFO_OFFSET(tval)(a3)
REG_S zero, SBI_TRAP_INFO_OFFSET(tval2)(a3)
REG_S zero, SBI_TRAP_INFO_OFFSET(tinst)(a3)
csrr a4, CSR_MEPC
addi a4, a4, 4
csrw CSR_MEPC, a4
mret
.align 3
.global __sbi_expected_trap_hext
__sbi_expected_trap_hext:
/* With H-extension so, MTVAL2 and MTINST CSRs available */
csrr a4, CSR_MEPC
REG_S a4, SBI_TRAP_INFO_OFFSET(epc)(a3)
csrr a4, CSR_MCAUSE
REG_S a4, SBI_TRAP_INFO_OFFSET(cause)(a3)
csrr a4, CSR_MTVAL
REG_S a4, SBI_TRAP_INFO_OFFSET(tval)(a3)
csrr a4, CSR_MTVAL2
REG_S a4, SBI_TRAP_INFO_OFFSET(tval2)(a3)
csrr a4, CSR_MTINST
REG_S a4, SBI_TRAP_INFO_OFFSET(tinst)(a3)
csrr a4, CSR_MEPC
addi a4, a4, 4
csrw CSR_MEPC, a4
mret

View File

@@ -11,33 +11,45 @@
#include <sbi/riscv_barrier.h>
#include <sbi/riscv_encoding.h>
#include <sbi/riscv_fp.h>
#include <sbi/riscv_locks.h>
#include <sbi/sbi_bits.h>
#include <sbi/sbi_bitops.h>
#include <sbi/sbi_console.h>
#include <sbi/sbi_csr_detect.h>
#include <sbi/sbi_error.h>
#include <sbi/sbi_hart.h>
#include <sbi/sbi_math.h>
#include <sbi/sbi_platform.h>
#include <sbi/sbi_string.h>
/**
* Return HART ID of the caller.
*/
unsigned int sbi_current_hartid()
{
return (u32)csr_read(CSR_MHARTID);
}
extern void __sbi_expected_trap(void);
extern void __sbi_expected_trap_hext(void);
void (*sbi_hart_expected_trap)(void) = &__sbi_expected_trap;
struct hart_features {
unsigned long features;
unsigned int pmp_count;
};
static unsigned long hart_features_offset;
static void mstatus_init(struct sbi_scratch *scratch, u32 hartid)
{
const struct sbi_platform *plat = sbi_platform_ptr(scratch);
unsigned long mstatus_val = 0;
/* Enable FPU */
if (misa_extension('D') || misa_extension('F'))
csr_write(CSR_MSTATUS, MSTATUS_FS);
mstatus_val |= MSTATUS_FS;
/* Enable Vector context */
if (misa_extension('V'))
mstatus_val |= MSTATUS_VS;
csr_write(CSR_MSTATUS, mstatus_val);
/* Enable user/supervisor use of perf counters */
if (misa_extension('S') && sbi_platform_has_scounteren(plat))
if (misa_extension('S') &&
sbi_hart_has_feature(scratch, SBI_HART_HAS_SCOUNTEREN))
csr_write(CSR_SCOUNTEREN, -1);
if (sbi_platform_has_mcounteren(plat))
if (sbi_hart_has_feature(scratch, SBI_HART_HAS_MCOUNTEREN))
csr_write(CSR_MCOUNTEREN, -1);
/* Disable all interrupts */
@@ -75,7 +87,7 @@ static int delegate_traps(struct sbi_scratch *scratch, u32 hartid)
unsigned long interrupts, exceptions;
if (!misa_extension('S'))
/* No delegation possible as mideleg does not exist*/
/* No delegation possible as mideleg does not exist */
return 0;
/* Send M-mode interrupts and most exceptions to S-mode */
@@ -88,58 +100,76 @@ static int delegate_traps(struct sbi_scratch *scratch, u32 hartid)
(1U << CAUSE_STORE_PAGE_FAULT);
/*
* If hypervisor extension available then we only handle
* hypervisor calls (i.e. ecalls from HS-mode) and we let
* HS-mode handle supervisor calls (i.e. ecalls from VS-mode)
* If hypervisor extension available then we only handle hypervisor
* calls (i.e. ecalls from HS-mode) in M-mode.
*
* The HS-mode will additionally handle supervisor calls (i.e. ecalls
* from VS-mode), Guest page faults and Virtual interrupts.
*/
if (misa_extension('H'))
if (misa_extension('H')) {
exceptions |= (1U << CAUSE_SUPERVISOR_ECALL);
exceptions |= (1U << CAUSE_FETCH_GUEST_PAGE_FAULT);
exceptions |= (1U << CAUSE_LOAD_GUEST_PAGE_FAULT);
exceptions |= (1U << CAUSE_VIRTUAL_INST_FAULT);
exceptions |= (1U << CAUSE_STORE_GUEST_PAGE_FAULT);
}
csr_write(CSR_MIDELEG, interrupts);
csr_write(CSR_MEDELEG, exceptions);
if (csr_read(CSR_MIDELEG) != interrupts)
return SBI_EFAIL;
if (csr_read(CSR_MEDELEG) != exceptions)
return SBI_EFAIL;
return 0;
}
unsigned long log2roundup(unsigned long x)
void sbi_hart_delegation_dump(struct sbi_scratch *scratch)
{
unsigned long ret = 0;
if (!misa_extension('S'))
/* No delegation possible as mideleg does not exist*/
return;
while (ret < __riscv_xlen) {
if (x <= (1UL << ret))
break;
ret++;
}
#if __riscv_xlen == 32
sbi_printf("MIDELEG : 0x%08lx\n", csr_read(CSR_MIDELEG));
sbi_printf("MEDELEG : 0x%08lx\n", csr_read(CSR_MEDELEG));
#else
sbi_printf("MIDELEG : 0x%016lx\n", csr_read(CSR_MIDELEG));
sbi_printf("MEDELEG : 0x%016lx\n", csr_read(CSR_MEDELEG));
#endif
}
return ret;
unsigned int sbi_hart_pmp_count(struct sbi_scratch *scratch)
{
struct hart_features *hfeatures =
sbi_scratch_offset_ptr(scratch, hart_features_offset);
return hfeatures->pmp_count;
}
int sbi_hart_pmp_get(struct sbi_scratch *scratch, unsigned int n,
unsigned long *prot_out, unsigned long *addr_out,
unsigned long *size)
{
if (sbi_hart_pmp_count(scratch) <= n)
return SBI_EINVAL;
return pmp_get(n, prot_out, addr_out, size);
}
void sbi_hart_pmp_dump(struct sbi_scratch *scratch)
{
const struct sbi_platform *plat = sbi_platform_ptr(scratch);
unsigned long prot, addr, size, l2l;
unsigned int i;
unsigned long prot, addr, size;
unsigned int i, pmp_count;
if (!sbi_platform_has_pmp(plat))
if (!sbi_hart_has_feature(scratch, SBI_HART_HAS_PMP))
return;
for (i = 0; i < PMP_COUNT; i++) {
pmp_get(i, &prot, &addr, &l2l);
pmp_count = sbi_hart_pmp_count(scratch);
for (i = 0; i < pmp_count; i++) {
pmp_get(i, &prot, &addr, &size);
if (!(prot & PMP_A))
continue;
if (l2l < __riscv_xlen)
size = (1UL << l2l);
else
size = 0;
#if __riscv_xlen == 32
sbi_printf("PMP%d: 0x%08lx-0x%08lx (A",
sbi_printf("PMP%d : 0x%08lx-0x%08lx (A",
#else
sbi_printf("PMP%d: 0x%016lx-0x%016lx (A",
sbi_printf("PMP%d : 0x%016lx-0x%016lx (A",
#endif
i, addr, addr + size - 1);
if (prot & PMP_L)
@@ -154,48 +184,243 @@ void sbi_hart_pmp_dump(struct sbi_scratch *scratch)
}
}
int sbi_hart_pmp_check_addr(struct sbi_scratch *scratch, unsigned long addr,
unsigned long attr)
{
unsigned long prot, size, tempaddr;
unsigned int i, pmp_count;
if (!sbi_hart_has_feature(scratch, SBI_HART_HAS_PMP))
return SBI_OK;
pmp_count = sbi_hart_pmp_count(scratch);
for (i = 0; i < pmp_count; i++) {
pmp_get(i, &prot, &tempaddr, &size);
if (!(prot & PMP_A))
continue;
if (tempaddr <= addr && addr <= tempaddr + size)
if (!(prot & attr))
return SBI_EINVALID_ADDR;
}
return SBI_OK;
}
static int pmp_init(struct sbi_scratch *scratch, u32 hartid)
{
u32 i, count;
u32 i, pmp_idx = 0, pmp_count, count;
unsigned long fw_start, fw_size_log2;
ulong prot, addr, log2size;
const struct sbi_platform *plat = sbi_platform_ptr(scratch);
if (!sbi_platform_has_pmp(plat))
if (!sbi_hart_has_feature(scratch, SBI_HART_HAS_PMP))
return 0;
/* Firmware PMP region to protect OpenSBI firmware */
fw_size_log2 = log2roundup(scratch->fw_size);
fw_start = scratch->fw_start & ~((1UL << fw_size_log2) - 1UL);
pmp_set(0, 0, fw_start, fw_size_log2);
fw_start = scratch->fw_start & ~((1UL << fw_size_log2) - 1UL);
pmp_set(pmp_idx++, 0, fw_start, fw_size_log2);
/* Platform specific PMP regions */
count = sbi_platform_pmp_region_count(plat, hartid);
if ((PMP_COUNT - 1) < count)
count = (PMP_COUNT - 1);
for (i = 0; i < count; i++) {
pmp_count = sbi_hart_pmp_count(scratch);
for (i = 0; i < count && pmp_idx < (pmp_count - 1); i++) {
if (sbi_platform_pmp_region_info(plat, hartid, i, &prot, &addr,
&log2size))
continue;
pmp_set(i + 1, prot, addr, log2size);
pmp_set(pmp_idx++, prot, addr, log2size);
}
/*
* Default PMP region for allowing S-mode and U-mode access to
* memory not covered by:
* 1) Firmware PMP region
* 2) Platform specific PMP regions
*/
pmp_set(pmp_idx++, PMP_R | PMP_W | PMP_X, 0, __riscv_xlen);
return 0;
}
static unsigned long trap_info_offset;
/**
* Check whether a particular hart feature is available
*
* @param scratch pointer to the HART scratch space
* @param feature the feature to check
* @returns true (feature available) or false (feature not available)
*/
bool sbi_hart_has_feature(struct sbi_scratch *scratch, unsigned long feature)
{
struct hart_features *hfeatures =
sbi_scratch_offset_ptr(scratch, hart_features_offset);
if (hfeatures->features & feature)
return true;
else
return false;
}
static unsigned long hart_get_features(struct sbi_scratch *scratch)
{
struct hart_features *hfeatures =
sbi_scratch_offset_ptr(scratch, hart_features_offset);
return hfeatures->features;
}
static inline char *sbi_hart_feature_id2string(unsigned long feature)
{
char *fstr = NULL;
if (!feature)
return NULL;
switch (feature) {
case SBI_HART_HAS_PMP:
fstr = "pmp";
break;
case SBI_HART_HAS_SCOUNTEREN:
fstr = "scounteren";
break;
case SBI_HART_HAS_MCOUNTEREN:
fstr = "mcounteren";
break;
case SBI_HART_HAS_TIME:
fstr = "time";
break;
default:
break;
}
return fstr;
}
/**
* Get the hart features in string format
*
* @param scratch pointer to the HART scratch space
* @param features_str pointer to a char array where the features string will be
* updated
* @param nfstr length of the features_str. The feature string will be truncated
* if nfstr is not long enough.
*/
void sbi_hart_get_features_str(struct sbi_scratch *scratch,
char *features_str, int nfstr)
{
unsigned long features, feat = 1UL;
char *temp;
int offset = 0;
if (!features_str || nfstr <= 0)
return;
sbi_memset(features_str, 0, nfstr);
features = hart_get_features(scratch);
if (!features)
goto done;
do {
if (features & feat) {
temp = sbi_hart_feature_id2string(feat);
if (temp) {
sbi_snprintf(features_str + offset, nfstr,
"%s,", temp);
offset = offset + sbi_strlen(temp) + 1;
}
}
feat = feat << 1;
} while (feat <= SBI_HART_HAS_LAST_FEATURE);
done:
if (offset)
features_str[offset - 1] = '\0';
else
sbi_strncpy(features_str, "none", nfstr);
}
static void hart_detect_features(struct sbi_scratch *scratch)
{
struct sbi_trap_info trap = {0};
struct hart_features *hfeatures;
unsigned long val;
/* Reset hart features */
hfeatures = sbi_scratch_offset_ptr(scratch, hart_features_offset);
hfeatures->features = 0;
hfeatures->pmp_count = 0;
/* Detect if hart supports PMP feature */
#define __detect_pmp(__pmp_csr) \
val = csr_read_allowed(__pmp_csr, (ulong)&trap); \
if (!trap.cause) { \
csr_write_allowed(__pmp_csr, (ulong)&trap, val);\
if (!trap.cause) \
hfeatures->pmp_count++; \
}
__detect_pmp(CSR_PMPADDR0);
__detect_pmp(CSR_PMPADDR1);
__detect_pmp(CSR_PMPADDR2);
__detect_pmp(CSR_PMPADDR3);
__detect_pmp(CSR_PMPADDR4);
__detect_pmp(CSR_PMPADDR5);
__detect_pmp(CSR_PMPADDR6);
__detect_pmp(CSR_PMPADDR7);
__detect_pmp(CSR_PMPADDR8);
__detect_pmp(CSR_PMPADDR9);
__detect_pmp(CSR_PMPADDR10);
__detect_pmp(CSR_PMPADDR11);
__detect_pmp(CSR_PMPADDR12);
__detect_pmp(CSR_PMPADDR13);
__detect_pmp(CSR_PMPADDR14);
__detect_pmp(CSR_PMPADDR15);
#undef __detect_pmp
/* Set hart PMP feature if we have at least one PMP region */
if (hfeatures->pmp_count)
hfeatures->features |= SBI_HART_HAS_PMP;
/* Detect if hart supports SCOUNTEREN feature */
trap.cause = 0;
val = csr_read_allowed(CSR_SCOUNTEREN, (unsigned long)&trap);
if (!trap.cause) {
csr_write_allowed(CSR_SCOUNTEREN, (unsigned long)&trap, val);
if (!trap.cause)
hfeatures->features |= SBI_HART_HAS_SCOUNTEREN;
}
/* Detect if hart supports MCOUNTEREN feature */
trap.cause = 0;
val = csr_read_allowed(CSR_MCOUNTEREN, (unsigned long)&trap);
if (!trap.cause) {
csr_write_allowed(CSR_MCOUNTEREN, (unsigned long)&trap, val);
if (!trap.cause)
hfeatures->features |= SBI_HART_HAS_MCOUNTEREN;
}
/* Detect if hart supports time CSR */
trap.cause = 0;
csr_read_allowed(CSR_TIME, (unsigned long)&trap);
if (!trap.cause)
hfeatures->features |= SBI_HART_HAS_TIME;
}
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)
if (misa_extension('H'))
sbi_hart_expected_trap = &__sbi_expected_trap_hext;
hart_features_offset = sbi_scratch_alloc_offset(
sizeof(struct hart_features),
"HART_FEATURES");
if (!hart_features_offset)
return SBI_ENOMEM;
}
hart_detect_features(scratch);
mstatus_init(scratch, hartid);
rc = fp_init(hartid);
@@ -209,29 +434,6 @@ int sbi_hart_init(struct sbi_scratch *scratch, u32 hartid, bool cold_boot)
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)
@@ -271,7 +473,6 @@ sbi_hart_switch_mode(unsigned long arg0, unsigned long arg1,
#if __riscv_xlen == 32
if (misa_extension('H')) {
valH = csr_read(CSR_MSTATUSH);
valH = INSERT_FIELD(valH, MSTATUSH_MTL, 0);
if (next_virt)
valH = INSERT_FIELD(valH, MSTATUSH_MPV, 1);
else
@@ -280,7 +481,6 @@ sbi_hart_switch_mode(unsigned long arg0, unsigned long arg1,
}
#else
if (misa_extension('H')) {
val = INSERT_FIELD(val, MSTATUS_MTL, 0);
if (next_virt)
val = INSERT_FIELD(val, MSTATUS_MPV, 1);
else
@@ -306,99 +506,3 @@ sbi_hart_switch_mode(unsigned long arg0, unsigned long arg1,
__asm__ __volatile__("mret" : : "r"(a0), "r"(a1));
__builtin_unreachable();
}
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)
{
spin_lock(&avail_hart_mask_lock);
avail_hart_mask |= (1UL << hartid);
spin_unlock(&avail_hart_mask_lock);
}
void sbi_hart_unmark_available(u32 hartid)
{
spin_lock(&avail_hart_mask_lock);
avail_hart_mask &= ~(1UL << hartid);
spin_unlock(&avail_hart_mask_lock);
}
ulong sbi_hart_available_mask(void)
{
ulong ret;
spin_lock(&avail_hart_mask_lock);
ret = avail_hart_mask;
spin_unlock(&avail_hart_mask_lock);
return ret;
}
typedef struct sbi_scratch *(*h2s)(ulong hartid);
struct sbi_scratch *sbi_hart_id_to_scratch(struct sbi_scratch *scratch,
u32 hartid)
{
return ((h2s)scratch->hartid_to_scratch)(hartid);
}
#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)
{
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(CSR_MIE, MIP_MSIP);
/* 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();
spin_lock(&coldboot_lock);
};
/* Unmark current HART as waiting */
coldboot_wait_bitmap &= ~(1UL << hartid);
/* 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)
{
const struct sbi_platform *plat = sbi_platform_ptr(scratch);
int max_hart = sbi_platform_hart_count(plat);
/* 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);
}
/* Release coldboot lock */
spin_unlock(&coldboot_lock);
}

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

@@ -0,0 +1,135 @@
/*
* SPDX-License-Identifier: BSD-2-Clause
*
* Copyright (c) 2019 Western Digital Corporation or its affiliates.
*
* Authors:
* Anup Patel <anup.patel@wdc.com>
* Atish Patra <anup.patel@wdc.com>
*/
/*
* HFENCE.GVMA rs1, rs2
* HFENCE.GVMA zero, rs2
* HFENCE.GVMA rs1
* HFENCE.GVMA
*
* rs1!=zero and rs2!=zero ==> HFENCE.GVMA rs1, rs2
* rs1==zero and rs2!=zero ==> HFENCE.GVMA zero, rs2
* rs1!=zero and rs2==zero ==> HFENCE.GVMA rs1
* rs1==zero and rs2==zero ==> HFENCE.GVMA
*
* Instruction encoding of HFENCE.GVMA is:
* 0110001 rs2(5) rs1(5) 000 00000 1110011
*/
.align 3
.global __sbi_hfence_gvma_vmid_gpa
__sbi_hfence_gvma_vmid_gpa:
/*
* rs1 = a0 (GPA)
* rs2 = a1 (VMID)
* HFENCE.GVMA a0, a1
* 0110001 01011 01010 000 00000 1110011
*/
.word 0x62b50073
ret
.align 3
.global __sbi_hfence_gvma_vmid
__sbi_hfence_gvma_vmid:
/*
* rs1 = zero
* rs2 = a0 (VMID)
* HFENCE.GVMA zero, a0
* 0110001 01010 00000 000 00000 1110011
*/
.word 0x62a00073
ret
.align 3
.global __sbi_hfence_gvma_gpa
__sbi_hfence_gvma_gpa:
/*
* rs1 = a0 (GPA)
* rs2 = zero
* HFENCE.GVMA a0
* 0110001 00000 01010 000 00000 1110011
*/
.word 0x62050073
ret
.align 3
.global __sbi_hfence_gvma_all
__sbi_hfence_gvma_all:
/*
* rs1 = zero
* rs2 = zero
* HFENCE.GVMA
* 0110001 00000 00000 000 00000 1110011
*/
.word 0x62000073
ret
/*
* HFENCE.VVMA rs1, rs2
* HFENCE.VVMA zero, rs2
* HFENCE.VVMA rs1
* HFENCE.VVMA
*
* rs1!=zero and rs2!=zero ==> HFENCE.VVMA rs1, rs2
* rs1==zero and rs2!=zero ==> HFENCE.VVMA zero, rs2
* rs1!=zero and rs2==zero ==> HFENCE.VVMA rs1
* rs1==zero and rs2==zero ==> HFENCE.vVMA
*
* Instruction encoding of HFENCE.VVMA is:
* 0010001 rs2(5) rs1(5) 000 00000 1110011
*/
.align 3
.global __sbi_hfence_vvma_asid_va
__sbi_hfence_vvma_asid_va:
/*
* rs1 = a0 (VA)
* rs2 = a1 (ASID)
* HFENCE.VVMA a0, a1
* 0010001 01011 01010 000 00000 1110011
*/
.word 0x22b50073
ret
.align 3
.global __sbi_hfence_vvma_asid
__sbi_hfence_vvma_asid:
/*
* rs1 = zero
* rs2 = a0 (ASID)
* HFENCE.VVMA zero, a0
* 0010001 01010 00000 000 00000 1110011
*/
.word 0x22a00073
ret
.align 3
.global __sbi_hfence_vvma_va
__sbi_hfence_vvma_va:
/*
* rs1 = a0 (VA)
* rs2 = zero
* HFENCE.VVMA zero, a0
* 0010001 00000 01010 000 00000 1110011
*/
.word 0x22050073
ret
.align 3
.global __sbi_hfence_vvma_all
__sbi_hfence_vvma_all:
/*
* rs1 = zero
* rs2 = zero
* HFENCE.VVMA
* 0010001 00000 00000 000 00000 1110011
*/
.word 0x22000073
ret

273
lib/sbi/sbi_hsm.c Normal file
View File

@@ -0,0 +1,273 @@
/*
* SPDX-License-Identifier: BSD-2-Clause
*
* Copyright (c) 2020 Western Digital Corporation or its affiliates.
*
* Authors:
* Atish Patra <atish.patra@wdc.com>
*/
#include <sbi/riscv_asm.h>
#include <sbi/riscv_barrier.h>
#include <sbi/riscv_encoding.h>
#include <sbi/riscv_atomic.h>
#include <sbi/sbi_bitops.h>
#include <sbi/sbi_console.h>
#include <sbi/sbi_error.h>
#include <sbi/sbi_ecall_interface.h>
#include <sbi/sbi_hart.h>
#include <sbi/sbi_hartmask.h>
#include <sbi/sbi_hsm.h>
#include <sbi/sbi_init.h>
#include <sbi/sbi_ipi.h>
#include <sbi/sbi_platform.h>
#include <sbi/sbi_system.h>
#include <sbi/sbi_timer.h>
#include <sbi/sbi_console.h>
static unsigned long hart_data_offset;
/** Per hart specific data to manage state transition **/
struct sbi_hsm_data {
atomic_t state;
};
int sbi_hsm_hart_state_to_status(int state)
{
int ret;
switch (state) {
case SBI_HART_STOPPED:
ret = SBI_HSM_HART_STATUS_STOPPED;
break;
case SBI_HART_STOPPING:
ret = SBI_HSM_HART_STATUS_STOP_PENDING;
break;
case SBI_HART_STARTING:
ret = SBI_HSM_HART_STATUS_START_PENDING;
break;
case SBI_HART_STARTED:
ret = SBI_HSM_HART_STATUS_STARTED;
break;
default:
ret = SBI_EINVAL;
}
return ret;
}
int sbi_hsm_hart_get_state(u32 hartid)
{
struct sbi_hsm_data *hdata;
struct sbi_scratch *scratch;
scratch = sbi_hartid_to_scratch(hartid);
if (!scratch)
return SBI_HART_UNKNOWN;
hdata = sbi_scratch_offset_ptr(scratch, hart_data_offset);
return atomic_read(&hdata->state);
}
bool sbi_hsm_hart_started(u32 hartid)
{
if (sbi_hsm_hart_get_state(hartid) == SBI_HART_STARTED)
return TRUE;
else
return FALSE;
}
/**
* Get ulong HART mask for given HART base ID
* @param hbase the HART base ID
* @param out_hmask the output ulong HART mask
* @return 0 on success and SBI_Exxx (< 0) on failure
* Note: the output HART mask will be set to zero on failure as well.
*/
int sbi_hsm_hart_started_mask(ulong hbase, ulong *out_hmask)
{
ulong i;
ulong hcount = sbi_scratch_last_hartid() + 1;
*out_hmask = 0;
if (hcount <= hbase)
return SBI_EINVAL;
if (BITS_PER_LONG < (hcount - hbase))
hcount = BITS_PER_LONG;
for (i = hbase; i < hcount; i++) {
if (sbi_hsm_hart_get_state(i) == SBI_HART_STARTED)
*out_hmask |= 1UL << (i - hbase);
}
return 0;
}
void sbi_hsm_prepare_next_jump(struct sbi_scratch *scratch, u32 hartid)
{
u32 oldstate;
struct sbi_hsm_data *hdata = sbi_scratch_offset_ptr(scratch,
hart_data_offset);
oldstate = atomic_cmpxchg(&hdata->state, SBI_HART_STARTING,
SBI_HART_STARTED);
if (oldstate != SBI_HART_STARTING)
sbi_hart_hang();
}
static void sbi_hsm_hart_wait(struct sbi_scratch *scratch, u32 hartid)
{
unsigned long saved_mie;
const struct sbi_platform *plat = sbi_platform_ptr(scratch);
struct sbi_hsm_data *hdata = sbi_scratch_offset_ptr(scratch,
hart_data_offset);
/* Save MIE CSR */
saved_mie = csr_read(CSR_MIE);
/* Set MSIE bit to receive IPI */
csr_set(CSR_MIE, MIP_MSIP);
/* Wait for hart_add call*/
while (atomic_read(&hdata->state) != SBI_HART_STARTING) {
wfi();
};
/* Restore MIE CSR */
csr_write(CSR_MIE, saved_mie);
/* Clear current HART IPI */
sbi_platform_ipi_clear(plat, hartid);
}
int sbi_hsm_init(struct sbi_scratch *scratch, u32 hartid, bool cold_boot)
{
u32 i;
struct sbi_scratch *rscratch;
struct sbi_hsm_data *hdata;
if (cold_boot) {
hart_data_offset = sbi_scratch_alloc_offset(sizeof(*hdata),
"HART_DATA");
if (!hart_data_offset)
return SBI_ENOMEM;
/* Initialize hart state data for every hart */
for (i = 0; i <= sbi_scratch_last_hartid(); i++) {
rscratch = sbi_hartid_to_scratch(i);
if (!rscratch)
continue;
hdata = sbi_scratch_offset_ptr(rscratch,
hart_data_offset);
ATOMIC_INIT(&hdata->state,
(i == hartid) ? SBI_HART_STARTING : SBI_HART_STOPPED);
}
} else {
sbi_hsm_hart_wait(scratch, hartid);
}
return 0;
}
void __noreturn sbi_hsm_exit(struct sbi_scratch *scratch)
{
u32 hstate;
const struct sbi_platform *plat = sbi_platform_ptr(scratch);
struct sbi_hsm_data *hdata = sbi_scratch_offset_ptr(scratch,
hart_data_offset);
void (*jump_warmboot)(void) = (void (*)(void))scratch->warmboot_addr;
hstate = atomic_cmpxchg(&hdata->state, SBI_HART_STOPPING,
SBI_HART_STOPPED);
if (hstate != SBI_HART_STOPPING)
goto fail_exit;
if (sbi_platform_has_hart_hotplug(plat)) {
sbi_platform_hart_stop(plat);
/* It should never reach here */
goto fail_exit;
}
/**
* As platform is lacking support for hotplug, directly jump to warmboot
* and wait for interrupts in warmboot. We do it preemptively in order
* preserve the hart states and reuse the code path for hotplug.
*/
jump_warmboot();
fail_exit:
/* It should never reach here */
sbi_printf("ERR: Failed stop hart [%u]\n", current_hartid());
sbi_hart_hang();
}
int sbi_hsm_hart_start(struct sbi_scratch *scratch, u32 hartid,
ulong saddr, ulong priv)
{
int rc;
unsigned long init_count;
unsigned int hstate;
struct sbi_scratch *rscratch;
struct sbi_hsm_data *hdata;
const struct sbi_platform *plat = sbi_platform_ptr(scratch);
rscratch = sbi_hartid_to_scratch(hartid);
if (!rscratch)
return SBI_EINVAL;
hdata = sbi_scratch_offset_ptr(rscratch, hart_data_offset);
hstate = atomic_cmpxchg(&hdata->state, SBI_HART_STOPPED,
SBI_HART_STARTING);
if (hstate == SBI_HART_STARTED)
return SBI_EALREADY;
/**
* if a hart is already transition to start or stop, another start call
* is considered as invalid request.
*/
if (hstate != SBI_HART_STOPPED)
return SBI_EINVAL;
rc = sbi_hart_pmp_check_addr(scratch, saddr, PMP_X);
if (rc)
return rc;
//TODO: We also need to check saddr for valid physical address as well.
init_count = sbi_init_count(hartid);
rscratch->next_arg1 = priv;
rscratch->next_addr = saddr;
if (sbi_platform_has_hart_hotplug(plat) ||
(sbi_platform_has_hart_secondary_boot(plat) && !init_count)) {
return sbi_platform_hart_start(plat, hartid,
scratch->warmboot_addr);
} else {
sbi_platform_ipi_send(plat, hartid);
}
return 0;
}
int sbi_hsm_hart_stop(struct sbi_scratch *scratch, bool exitnow)
{
int oldstate;
u32 hartid = current_hartid();
struct sbi_hsm_data *hdata = sbi_scratch_offset_ptr(scratch,
hart_data_offset);
if (!sbi_hsm_hart_started(hartid))
return SBI_EINVAL;
oldstate = atomic_cmpxchg(&hdata->state, SBI_HART_STARTED,
SBI_HART_STOPPING);
if (oldstate != SBI_HART_STARTED) {
sbi_printf("%s: ERR: The hart is in invalid state [%u]\n",
__func__, oldstate);
return SBI_EDENIED;
}
if (exitnow)
sbi_exit(scratch);
return 0;
}

View File

@@ -9,49 +9,39 @@
#include <sbi/riscv_asm.h>
#include <sbi/riscv_encoding.h>
#include <sbi/riscv_unpriv.h>
#include <sbi/sbi_bits.h>
#include <sbi/sbi_bitops.h>
#include <sbi/sbi_emulate_csr.h>
#include <sbi/sbi_error.h>
#include <sbi/sbi_illegal_insn.h>
#include <sbi/sbi_trap.h>
#include <sbi/sbi_unpriv.h>
typedef int (*illegal_insn_func)(ulong insn, u32 hartid, ulong mcause,
struct sbi_trap_regs *regs,
struct sbi_scratch *scratch);
typedef int (*illegal_insn_func)(ulong insn, struct sbi_trap_regs *regs);
static int truly_illegal_insn(ulong insn, u32 hartid, ulong mcause,
struct sbi_trap_regs *regs,
struct sbi_scratch *scratch)
static int truly_illegal_insn(ulong insn, struct sbi_trap_regs *regs)
{
return sbi_trap_redirect(regs, scratch, regs->mepc, mcause, insn);
struct sbi_trap_info trap;
trap.epc = regs->mepc;
trap.cause = CAUSE_ILLEGAL_INSTRUCTION;
trap.tval = insn;
trap.tval2 = 0;
trap.tinst = 0;
return sbi_trap_redirect(regs, &trap);
}
static int system_opcode_insn(ulong insn, u32 hartid, ulong mcause,
struct sbi_trap_regs *regs,
struct sbi_scratch *scratch)
static int system_opcode_insn(ulong insn, struct sbi_trap_regs *regs)
{
int do_write, rs1_num = (insn >> 15) & 0x1f;
ulong rs1_val = GET_RS1(insn, regs);
int csr_num = (u32)insn >> 20;
ulong csr_val, new_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);
/* TODO: Ensure that we got CSR read/write instruction */
if (sbi_emulate_csr_read(csr_num, hartid, regs, scratch, &csr_val))
return truly_illegal_insn(insn, hartid, mcause,
regs, scratch);
if (sbi_emulate_csr_read(csr_num, regs, &csr_val))
return truly_illegal_insn(insn, regs);
do_write = rs1_num;
switch (GET_RM(insn)) {
@@ -76,12 +66,11 @@ static int system_opcode_insn(ulong insn, u32 hartid, ulong mcause,
new_csr_val = csr_val & ~rs1_num;
break;
default:
return truly_illegal_insn(insn, hartid, mcause, regs, scratch);
return truly_illegal_insn(insn, regs);
};
if (do_write && sbi_emulate_csr_write(csr_num, hartid, regs,
scratch, new_csr_val))
return truly_illegal_insn(insn, hartid, mcause, regs, scratch);
if (do_write && sbi_emulate_csr_write(csr_num, regs, new_csr_val))
return truly_illegal_insn(insn, regs);
SET_RD(insn, regs, csr_val);
@@ -125,30 +114,21 @@ static illegal_insn_func illegal_insn_table[32] = {
truly_illegal_insn /* 31 */
};
int sbi_illegal_insn_handler(u32 hartid, ulong mcause,
struct sbi_trap_regs *regs,
struct sbi_scratch *scratch)
int sbi_illegal_insn_handler(ulong insn, struct sbi_trap_regs *regs)
{
ulong insn = csr_read(CSR_MTVAL);
#if __riscv_xlen == 32
bool virt = (regs->mstatusH & MSTATUSH_MPV) ? TRUE : FALSE;
#else
bool virt = (regs->mstatus & MSTATUS_MPV) ? TRUE : FALSE;
#endif
struct unpriv_trap uptrap;
struct sbi_trap_info uptrap;
if (unlikely((insn & 3) != 3)) {
if (insn == 0) {
insn = get_insn(regs->mepc, virt, scratch, &uptrap);
if (uptrap.cause)
return sbi_trap_redirect(regs, scratch,
regs->mepc, uptrap.cause, uptrap.tval);
insn = sbi_get_insn(regs->mepc, &uptrap);
if (uptrap.cause) {
uptrap.epc = regs->mepc;
return sbi_trap_redirect(regs, &uptrap);
}
}
if ((insn & 3) != 3)
return truly_illegal_insn(insn, hartid, mcause, regs,
scratch);
return truly_illegal_insn(insn, regs);
}
return illegal_insn_table[(insn & 0x7c) >> 2](insn, hartid, mcause,
regs, scratch);
return illegal_insn_table[(insn & 0x7c) >> 2](insn, regs);
}

View File

@@ -9,13 +9,18 @@
#include <sbi/riscv_asm.h>
#include <sbi/riscv_atomic.h>
#include <sbi/riscv_locks.h>
#include <sbi/sbi_console.h>
#include <sbi/sbi_ecall.h>
#include <sbi/sbi_hart.h>
#include <sbi/sbi_hartmask.h>
#include <sbi/sbi_hsm.h>
#include <sbi/sbi_ipi.h>
#include <sbi/sbi_platform.h>
#include <sbi/sbi_system.h>
#include <sbi/sbi_string.h>
#include <sbi/sbi_timer.h>
#include <sbi/sbi_tlb.h>
#include <sbi/sbi_version.h>
#define BANNER \
@@ -30,44 +35,143 @@
static void sbi_boot_prints(struct sbi_scratch *scratch, u32 hartid)
{
char str[64];
int xlen;
char str[128];
const struct sbi_platform *plat = sbi_platform_ptr(scratch);
misa_string(str, sizeof(str));
#ifdef OPENSBI_VERSION_GIT
sbi_printf("\nOpenSBI %s (%s %s)\n", OPENSBI_VERSION_GIT,
__DATE__, __TIME__);
sbi_printf("\nOpenSBI %s\n", OPENSBI_VERSION_GIT);
#else
sbi_printf("\nOpenSBI v%d.%d (%s %s)\n", OPENSBI_VERSION_MAJOR,
OPENSBI_VERSION_MINOR, __DATE__, __TIME__);
sbi_printf("\nOpenSBI v%d.%d\n", OPENSBI_VERSION_MAJOR,
OPENSBI_VERSION_MINOR);
#endif
sbi_printf(BANNER);
/* Determine MISA XLEN and MISA string */
xlen = misa_xlen();
if (xlen < 1) {
sbi_printf("Error %d getting MISA XLEN\n", xlen);
sbi_hart_hang();
}
/* 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_printf("Platform Name : %s\n", sbi_platform_name(plat));
sbi_platform_get_features_str(plat, str, sizeof(str));
sbi_printf("Platform Features : %s\n", str);
sbi_printf("Platform HART Count : %u\n",
sbi_platform_hart_count(plat));
sbi_printf("Current Hart : %u\n", hartid);
/* Boot HART details */
sbi_printf("Boot HART ID : %u\n", hartid);
misa_string(xlen, str, sizeof(str));
sbi_printf("Boot HART ISA : %s\n", str);
sbi_hart_get_features_str(scratch, str, sizeof(str));
sbi_printf("BOOT HART Features : %s\n", str);
sbi_printf("BOOT HART PMP Count : %d\n", sbi_hart_pmp_count(scratch));
/* Firmware details */
sbi_printf("Firmware Base : 0x%lx\n", scratch->fw_start);
sbi_printf("Firmware Size : %d KB\n",
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_printf("Runtime SBI Version : %d.%d\n",
sbi_ecall_version_major(), sbi_ecall_version_minor());
sbi_printf("\n");
sbi_hart_delegation_dump(scratch);
sbi_hart_pmp_dump(scratch);
}
static spinlock_t coldboot_lock = SPIN_LOCK_INITIALIZER;
static unsigned long coldboot_done = 0;
static struct sbi_hartmask coldboot_wait_hmask = { 0 };
static void wait_for_coldboot(struct sbi_scratch *scratch, u32 hartid)
{
unsigned long saved_mie, cmip;
const struct sbi_platform *plat = sbi_platform_ptr(scratch);
/* Save MIE CSR */
saved_mie = csr_read(CSR_MIE);
/* Set MSIE bit to receive IPI */
csr_set(CSR_MIE, MIP_MSIP);
/* Acquire coldboot lock */
spin_lock(&coldboot_lock);
/* Mark current HART as waiting */
sbi_hartmask_set_hart(hartid, &coldboot_wait_hmask);
/* Wait for coldboot to finish using WFI */
while (!coldboot_done) {
spin_unlock(&coldboot_lock);
do {
wfi();
cmip = csr_read(CSR_MIP);
} while (!(cmip & MIP_MSIP));
spin_lock(&coldboot_lock);
};
/* Unmark current HART as waiting */
sbi_hartmask_clear_hart(hartid, &coldboot_wait_hmask);
/* Release coldboot lock */
spin_unlock(&coldboot_lock);
/* Restore MIE CSR */
csr_write(CSR_MIE, saved_mie);
/* Clear current HART IPI */
sbi_platform_ipi_clear(plat, hartid);
}
static void wake_coldboot_harts(struct sbi_scratch *scratch, u32 hartid)
{
const struct sbi_platform *plat = sbi_platform_ptr(scratch);
/* 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 <= sbi_scratch_last_hartid(); i++) {
if ((i != hartid) &&
sbi_hartmask_test_hart(i, &coldboot_wait_hmask))
sbi_platform_ipi_send(plat, i);
}
/* Release coldboot lock */
spin_unlock(&coldboot_lock);
}
static unsigned long init_count_offset;
static void __noreturn init_coldboot(struct sbi_scratch *scratch, u32 hartid)
{
int rc;
unsigned long *init_count;
const struct sbi_platform *plat = sbi_platform_ptr(scratch);
rc = sbi_system_early_init(scratch, TRUE);
/* Note: This has to be first thing in coldboot init sequence */
rc = sbi_scratch_init(scratch);
if (rc)
sbi_hart_hang();
init_count_offset = sbi_scratch_alloc_offset(__SIZEOF_POINTER__,
"INIT_COUNT");
if (!init_count_offset)
sbi_hart_hang();
rc = sbi_hsm_init(scratch, hartid, TRUE);
if (rc)
sbi_hart_hang();
rc = sbi_platform_early_init(plat, TRUE);
if (rc)
sbi_hart_hang();
@@ -87,20 +191,31 @@ static void __noreturn init_coldboot(struct sbi_scratch *scratch, u32 hartid)
if (rc)
sbi_hart_hang();
rc = sbi_tlb_init(scratch, TRUE);
if (rc)
sbi_hart_hang();
rc = sbi_timer_init(scratch, TRUE);
if (rc)
sbi_hart_hang();
rc = sbi_system_final_init(scratch, TRUE);
rc = sbi_ecall_init();
if (rc)
sbi_hart_hang();
rc = sbi_platform_final_init(plat, TRUE);
if (rc)
sbi_hart_hang();
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);
wake_coldboot_harts(scratch, hartid);
init_count = sbi_scratch_offset_ptr(scratch, init_count_offset);
(*init_count)++;
sbi_hsm_prepare_next_jump(scratch, hartid);
sbi_hart_switch_mode(hartid, scratch->next_arg1, scratch->next_addr,
scratch->next_mode, FALSE);
}
@@ -108,15 +223,19 @@ static void __noreturn init_coldboot(struct sbi_scratch *scratch, u32 hartid)
static void __noreturn init_warmboot(struct sbi_scratch *scratch, u32 hartid)
{
int rc;
unsigned long *init_count;
const struct sbi_platform *plat = sbi_platform_ptr(scratch);
if (!sbi_platform_has_hart_hotplug(plat))
sbi_hart_wait_for_coldboot(scratch, hartid);
wait_for_coldboot(scratch, hartid);
if (sbi_platform_hart_disabled(plat, hartid))
if (!init_count_offset)
sbi_hart_hang();
rc = sbi_system_early_init(scratch, FALSE);
rc = sbi_hsm_init(scratch, hartid, FALSE);
if (rc)
sbi_hart_hang();
rc = sbi_platform_early_init(plat, FALSE);
if (rc)
sbi_hart_hang();
@@ -132,23 +251,25 @@ static void __noreturn init_warmboot(struct sbi_scratch *scratch, u32 hartid)
if (rc)
sbi_hart_hang();
rc = sbi_tlb_init(scratch, FALSE);
if (rc)
sbi_hart_hang();
rc = sbi_timer_init(scratch, FALSE);
if (rc)
sbi_hart_hang();
rc = sbi_system_final_init(scratch, FALSE);
rc = sbi_platform_final_init(plat, FALSE);
if (rc)
sbi_hart_hang();
sbi_hart_mark_available(hartid);
init_count = sbi_scratch_offset_ptr(scratch, init_count_offset);
(*init_count)++;
if (sbi_platform_has_hart_hotplug(plat))
/* TODO: To be implemented in-future. */
sbi_hart_hang();
else
sbi_hart_switch_mode(hartid, scratch->next_arg1,
scratch->next_addr,
scratch->next_mode, FALSE);
sbi_hsm_prepare_next_jump(scratch, hartid);
sbi_hart_switch_mode(hartid, scratch->next_arg1,
scratch->next_addr,
scratch->next_mode, FALSE);
}
static atomic_t coldboot_lottery = ATOMIC_INITIALIZER(0);
@@ -168,13 +289,14 @@ static atomic_t coldboot_lottery = ATOMIC_INITIALIZER(0);
void __noreturn sbi_init(struct sbi_scratch *scratch)
{
bool coldboot = FALSE;
u32 hartid = sbi_current_hartid();
u32 hartid = current_hartid();
const struct sbi_platform *plat = sbi_platform_ptr(scratch);
if (sbi_platform_hart_disabled(plat, hartid))
if ((SBI_HARTMASK_MAX_BITS <= hartid) ||
sbi_platform_hart_invalid(plat, hartid))
sbi_hart_hang();
if (atomic_add_return(&coldboot_lottery, 1) == 1)
if (atomic_xchg(&coldboot_lottery, 1) == 0)
coldboot = TRUE;
if (coldboot)
@@ -182,3 +304,50 @@ void __noreturn sbi_init(struct sbi_scratch *scratch)
else
init_warmboot(scratch, hartid);
}
unsigned long sbi_init_count(u32 hartid)
{
struct sbi_scratch *scratch;
unsigned long *init_count;
if (!init_count_offset)
return 0;
scratch = sbi_hartid_to_scratch(hartid);
if (!scratch)
return 0;
init_count = sbi_scratch_offset_ptr(scratch, init_count_offset);
return *init_count;
}
/**
* Exit OpenSBI library for current HART and stop HART
*
* The function expects following:
* 1. The 'mscratch' CSR is pointing to sbi_scratch of current HART
* 2. Stack pointer (SP) is setup for current HART
*
* @param scratch pointer to sbi_scratch of current HART
*/
void __noreturn sbi_exit(struct sbi_scratch *scratch)
{
u32 hartid = current_hartid();
const struct sbi_platform *plat = sbi_platform_ptr(scratch);
if (sbi_platform_hart_invalid(plat, hartid))
sbi_hart_hang();
sbi_platform_early_exit(plat);
sbi_timer_exit(scratch);
sbi_ipi_exit(scratch);
sbi_platform_irqchip_exit(plat);
sbi_platform_final_exit(plat);
sbi_hsm_exit(scratch);
}

View File

@@ -11,94 +11,176 @@
#include <sbi/riscv_asm.h>
#include <sbi/riscv_atomic.h>
#include <sbi/riscv_barrier.h>
#include <sbi/riscv_unpriv.h>
#include <sbi/sbi_bitops.h>
#include <sbi/sbi_error.h>
#include <sbi/sbi_hart.h>
#include <sbi/sbi_hsm.h>
#include <sbi/sbi_init.h>
#include <sbi/sbi_ipi.h>
#include <sbi/sbi_platform.h>
#include <sbi/sbi_tlb.h>
struct sbi_ipi_data {
unsigned long ipi_type;
};
static unsigned long ipi_data_off;
static int sbi_ipi_send(struct sbi_scratch *scratch, u32 hartid, u32 event,
void *data)
static const struct sbi_ipi_event_ops *ipi_ops_array[SBI_IPI_EVENT_MAX];
static int sbi_ipi_send(struct sbi_scratch *scratch, u32 remote_hartid,
u32 event, void *data)
{
int ret;
struct sbi_scratch *remote_scratch = NULL;
const struct sbi_platform *plat = sbi_platform_ptr(scratch);
struct sbi_ipi_data *ipi_data;
const struct sbi_ipi_event_ops *ipi_ops;
if (sbi_platform_hart_disabled(plat, hartid))
return -1;
if ((SBI_IPI_EVENT_MAX <= event) ||
!ipi_ops_array[event])
return SBI_EINVAL;
ipi_ops = ipi_ops_array[event];
remote_scratch = sbi_hartid_to_scratch(remote_hartid);
if (!remote_scratch)
return SBI_EINVAL;
ipi_data = sbi_scratch_offset_ptr(remote_scratch, ipi_data_off);
if (ipi_ops->update) {
ret = ipi_ops->update(scratch, remote_scratch,
remote_hartid, data);
if (ret < 0)
return ret;
}
/*
* 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);
sbi_platform_ipi_send(plat, remote_hartid);
if (event == SBI_IPI_EVENT_SFENCE_VMA ||
event == SBI_IPI_EVENT_SFENCE_VMA_ASID ||
event == SBI_IPI_EVENT_FENCE_I ) {
sbi_tlb_fifo_sync(scratch);
}
if (ipi_ops->sync)
ipi_ops->sync(scratch);
return 0;
}
int sbi_ipi_send_many(struct sbi_scratch *scratch, struct unpriv_trap *uptrap,
ulong *pmask, u32 event, void *data)
/**
* As this this function only handlers scalar values of hart mask, it must be
* set to all online harts if the intention is to send IPIs to all the harts.
* If hmask is zero, no IPIs will be sent.
*/
int sbi_ipi_send_many(ulong hmask, ulong hbase, u32 event, void *data)
{
int rc;
ulong i, m;
ulong mask = sbi_hart_available_mask();
u32 hartid = sbi_current_hartid();
struct sbi_scratch *scratch = sbi_scratch_thishart_ptr();
if (pmask) {
mask &= load_ulong(pmask, scratch, uptrap);
if (uptrap->cause)
return SBI_ETRAP;
if (hbase != -1UL) {
rc = sbi_hsm_hart_started_mask(hbase, &m);
if (rc)
return rc;
m &= hmask;
/* Send IPIs */
for (i = hbase; m; i++, m >>= 1) {
if (m & 1UL)
sbi_ipi_send(scratch, i, event, data);
}
} else {
hbase = 0;
while (!sbi_hsm_hart_started_mask(hbase, &m)) {
/* Send IPIs */
for (i = hbase; m; i++, m >>= 1) {
if (m & 1UL)
sbi_ipi_send(scratch, i, event, data);
}
hbase += BITS_PER_LONG;
}
}
/* 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)
int sbi_ipi_event_create(const struct sbi_ipi_event_ops *ops)
{
int i, ret = SBI_ENOSPC;
if (!ops || !ops->process)
return SBI_EINVAL;
for (i = 0; i < SBI_IPI_EVENT_MAX; i++) {
if (!ipi_ops_array[i]) {
ret = i;
ipi_ops_array[i] = ops;
break;
}
}
return ret;
}
void sbi_ipi_event_destroy(u32 event)
{
if (SBI_IPI_EVENT_MAX <= event)
return;
ipi_ops_array[event] = NULL;
}
static void sbi_ipi_process_smode(struct sbi_scratch *scratch)
{
csr_set(CSR_MIP, MIP_SSIP);
}
static struct sbi_ipi_event_ops ipi_smode_ops = {
.name = "IPI_SMODE",
.process = sbi_ipi_process_smode,
};
static u32 ipi_smode_event = SBI_IPI_EVENT_MAX;
int sbi_ipi_send_smode(ulong hmask, ulong hbase)
{
return sbi_ipi_send_many(hmask, hbase, ipi_smode_event, NULL);
}
void sbi_ipi_clear_smode(void)
{
csr_clear(CSR_MIP, MIP_SSIP);
}
void sbi_ipi_process(struct sbi_scratch *scratch)
static void sbi_ipi_process_halt(struct sbi_scratch *scratch)
{
sbi_hsm_hart_stop(scratch, TRUE);
}
static struct sbi_ipi_event_ops ipi_halt_ops = {
.name = "IPI_HALT",
.process = sbi_ipi_process_halt,
};
static u32 ipi_halt_event = SBI_IPI_EVENT_MAX;
int sbi_ipi_send_halt(ulong hmask, ulong hbase)
{
return sbi_ipi_send_many(hmask, hbase, ipi_halt_event, NULL);
}
void sbi_ipi_process(void)
{
unsigned long ipi_type;
unsigned int ipi_event;
const struct sbi_ipi_event_ops *ipi_ops;
struct sbi_scratch *scratch = sbi_scratch_thishart_ptr();
const struct sbi_platform *plat = sbi_platform_ptr(scratch);
struct sbi_ipi_data *ipi_data =
sbi_scratch_offset_ptr(scratch, ipi_data_off);
u32 hartid = sbi_current_hartid();
u32 hartid = current_hartid();
sbi_platform_ipi_clear(plat, hartid);
ipi_type = atomic_raw_xchg_ulong(&ipi_data->ipi_type, 0);
@@ -107,21 +189,9 @@ void sbi_ipi_process(struct sbi_scratch *scratch)
if (!(ipi_type & 1UL))
goto skip;
switch (ipi_event) {
case SBI_IPI_EVENT_SOFT:
csr_set(CSR_MIP, MIP_SSIP);
break;
case SBI_IPI_EVENT_FENCE_I:
case SBI_IPI_EVENT_SFENCE_VMA:
case SBI_IPI_EVENT_SFENCE_VMA_ASID:
sbi_tlb_fifo_process(scratch);
break;
case SBI_IPI_EVENT_HALT:
sbi_hart_hang();
break;
default:
break;
};
ipi_ops = ipi_ops_array[ipi_event];
if (ipi_ops && ipi_ops->process)
ipi_ops->process(scratch);
skip:
ipi_type = ipi_type >> 1;
@@ -139,20 +209,44 @@ int sbi_ipi_init(struct sbi_scratch *scratch, bool cold_boot)
"IPI_DATA");
if (!ipi_data_off)
return SBI_ENOMEM;
ret = sbi_ipi_event_create(&ipi_smode_ops);
if (ret < 0)
return ret;
ipi_smode_event = ret;
ret = sbi_ipi_event_create(&ipi_halt_ops);
if (ret < 0)
return ret;
ipi_halt_event = ret;
} else {
if (!ipi_data_off)
return SBI_ENOMEM;
if (SBI_IPI_EVENT_MAX <= ipi_smode_event ||
SBI_IPI_EVENT_MAX <= ipi_halt_event)
return SBI_ENOSPC;
}
ipi_data = sbi_scratch_offset_ptr(scratch, ipi_data_off);
ipi_data->ipi_type = 0x00;
ret = sbi_tlb_fifo_init(scratch, cold_boot);
/* Platform init */
ret = sbi_platform_ipi_init(sbi_platform_ptr(scratch), cold_boot);
if (ret)
return ret;
/* Enable software interrupts */
csr_set(CSR_MIE, MIP_MSIP);
return sbi_platform_ipi_init(sbi_platform_ptr(scratch), cold_boot);
return 0;
}
void sbi_ipi_exit(struct sbi_scratch *scratch)
{
/* Disable software interrupts */
csr_clear(CSR_MIE, MIP_MSIP);
/* Process pending IPIs */
sbi_ipi_process();
/* Platform exit */
sbi_platform_ipi_exit(sbi_platform_ptr(scratch));
}

23
lib/sbi/sbi_math.c Normal file
View File

@@ -0,0 +1,23 @@
/*
* SPDX-License-Identifier: BSD-2-Clause
*
* Copyright (c) 2020 Western Digital Corporation or its affiliates.
*
* Common helper functions used across OpenSBI project.
*
* Authors:
* Atish Patra <atish.patra@wdc.com>
*/
unsigned long log2roundup(unsigned long x)
{
unsigned long ret = 0;
while (ret < __riscv_xlen) {
if (x <= (1UL << ret))
break;
ret++;
}
return ret;
}

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];
@@ -21,24 +21,31 @@ union reg_data {
u64 data_u64;
};
int sbi_misaligned_load_handler(u32 hartid, ulong mcause,
struct sbi_trap_regs *regs,
struct sbi_scratch *scratch)
int sbi_misaligned_load_handler(ulong addr, ulong tval2, ulong tinst,
struct sbi_trap_regs *regs)
{
ulong insn;
union reg_data val;
struct unpriv_trap uptrap;
ulong addr = csr_read(CSR_MTVAL);
struct sbi_trap_info uptrap;
int i, fp = 0, shift = 0, len = 0;
#if __riscv_xlen == 32
bool virt = (regs->mstatusH & MSTATUSH_MPV) ? TRUE : FALSE;
#else
bool virt = (regs->mstatus & MSTATUS_MPV) ? TRUE : FALSE;
#endif
ulong insn = get_insn(regs->mepc, virt, scratch, &uptrap);
if (uptrap.cause)
return sbi_trap_redirect(regs, scratch, regs->mepc,
uptrap.cause, uptrap.tval);
if (tinst & 0x1) {
/*
* Bit[0] == 1 implies trapped instruction value is
* transformed instruction or custom instruction.
*/
insn = tinst | INSN_16BIT_MASK;
} else {
/*
* Bit[0] == 0 implies trapped instruction value is
* zero or special value.
*/
insn = sbi_get_insn(regs->mepc, &uptrap);
if (uptrap.cause) {
uptrap.epc = regs->mepc;
return sbi_trap_redirect(regs, &uptrap);
}
}
if ((insn & INSN_MASK_LW) == INSN_MATCH_LW) {
len = 4;
@@ -63,7 +70,6 @@ int sbi_misaligned_load_handler(u32 hartid, ulong mcause,
shift = 8 * (sizeof(ulong) - len);
} else if ((insn & INSN_MASK_LHU) == INSN_MATCH_LHU) {
len = 2;
#ifdef __riscv_compressed
#if __riscv_xlen >= 64
} else if ((insn & INSN_MASK_C_LD) == INSN_MATCH_C_LD) {
len = 8;
@@ -100,18 +106,23 @@ int sbi_misaligned_load_handler(u32 hartid, ulong mcause,
len = 4;
#endif
#endif
#endif
} else
return sbi_trap_redirect(regs, scratch, regs->mepc,
mcause, addr);
} else {
uptrap.epc = regs->mepc;
uptrap.cause = CAUSE_MISALIGNED_LOAD;
uptrap.tval = addr;
uptrap.tval2 = tval2;
uptrap.tinst = tinst;
return sbi_trap_redirect(regs, &uptrap);
}
val.data_u64 = 0;
for (i = 0; i < len; i++) {
val.data_bytes[i] = load_u8((void *)(addr + i),
scratch, &uptrap);
if (uptrap.cause)
return sbi_trap_redirect(regs, scratch, regs->mepc,
uptrap.cause, uptrap.tval);
val.data_bytes[i] = sbi_load_u8((void *)(addr + i),
&uptrap);
if (uptrap.cause) {
uptrap.epc = regs->mepc;
return sbi_trap_redirect(regs, &uptrap);
}
}
if (!fp)
@@ -128,24 +139,31 @@ int sbi_misaligned_load_handler(u32 hartid, ulong mcause,
return 0;
}
int sbi_misaligned_store_handler(u32 hartid, ulong mcause,
struct sbi_trap_regs *regs,
struct sbi_scratch *scratch)
int sbi_misaligned_store_handler(ulong addr, ulong tval2, ulong tinst,
struct sbi_trap_regs *regs)
{
ulong insn;
union reg_data val;
struct unpriv_trap uptrap;
ulong addr = csr_read(CSR_MTVAL);
struct sbi_trap_info uptrap;
int i, len = 0;
#if __riscv_xlen == 32
bool virt = (regs->mstatusH & MSTATUSH_MPV) ? TRUE : FALSE;
#else
bool virt = (regs->mstatus & MSTATUS_MPV) ? TRUE : FALSE;
#endif
ulong insn = get_insn(regs->mepc, virt, scratch, &uptrap);
if (uptrap.cause)
return sbi_trap_redirect(regs, scratch, regs->mepc,
uptrap.cause, uptrap.tval);
if (tinst & 0x1) {
/*
* Bit[0] == 1 implies trapped instruction value is
* transformed instruction or custom instruction.
*/
insn = tinst | INSN_16BIT_MASK;
} else {
/*
* Bit[0] == 0 implies trapped instruction value is
* zero or special value.
*/
insn = sbi_get_insn(regs->mepc, &uptrap);
if (uptrap.cause) {
uptrap.epc = regs->mepc;
return sbi_trap_redirect(regs, &uptrap);
}
}
val.data_ulong = GET_RS2(insn, regs);
@@ -165,7 +183,6 @@ int sbi_misaligned_store_handler(u32 hartid, ulong mcause,
#endif
} else if ((insn & INSN_MASK_SH) == INSN_MATCH_SH) {
len = 2;
#ifdef __riscv_compressed
#if __riscv_xlen >= 64
} else if ((insn & INSN_MASK_C_SD) == INSN_MATCH_C_SD) {
len = 8;
@@ -198,17 +215,22 @@ int sbi_misaligned_store_handler(u32 hartid, ulong mcause,
val.data_ulong = GET_F32_RS2C(insn, regs);
#endif
#endif
#endif
} else
return sbi_trap_redirect(regs, scratch, regs->mepc,
mcause, addr);
} else {
uptrap.epc = regs->mepc;
uptrap.cause = CAUSE_MISALIGNED_STORE;
uptrap.tval = addr;
uptrap.tval2 = tval2;
uptrap.tinst = tinst;
return sbi_trap_redirect(regs, &uptrap);
}
for (i = 0; i < len; i++) {
store_u8((void *)(addr + i), val.data_bytes[i],
scratch, &uptrap);
if (uptrap.cause)
return sbi_trap_redirect(regs, scratch, regs->mepc,
uptrap.cause, uptrap.tval);
sbi_store_u8((void *)(addr + i), val.data_bytes[i],
&uptrap);
if (uptrap.cause) {
uptrap.epc = regs->mepc;
return sbi_trap_redirect(regs, &uptrap);
}
}
regs->mepc += INSN_LEN(insn);

90
lib/sbi/sbi_platform.c Normal file
View File

@@ -0,0 +1,90 @@
/*
* SPDX-License-Identifier: BSD-2-Clause
*
* Copyright (c) 2020 Western Digital Corporation or its affiliates.
*
* Authors:
* Atish Patra <atish.patra@wdc.com>
*/
#include <sbi/sbi_console.h>
#include <sbi/sbi_platform.h>
#include <sbi/sbi_string.h>
static inline char *sbi_platform_feature_id2string(unsigned long feature)
{
char *fstr = NULL;
if (!feature)
return NULL;
switch (feature) {
case SBI_PLATFORM_HAS_TIMER_VALUE:
fstr = "timer";
break;
case SBI_PLATFORM_HAS_HART_HOTPLUG:
fstr = "hotplug";
break;
case SBI_PLATFORM_HAS_MFAULTS_DELEGATION:
fstr = "mfdeleg";
break;
case SBI_PLATFORM_HAS_HART_SECONDARY_BOOT:
fstr = "sec_boot";
break;
default:
break;
}
return fstr;
}
void sbi_platform_get_features_str(const struct sbi_platform *plat,
char *features_str, int nfstr)
{
unsigned long features, feat = 1UL;
char *temp;
int offset = 0;
if (!plat || !features_str || !nfstr)
return;
sbi_memset(features_str, 0, nfstr);
features = sbi_platform_get_features(plat);
if (!features)
goto done;
do {
if (features & feat) {
temp = sbi_platform_feature_id2string(feat);
if (temp) {
sbi_snprintf(features_str + offset, nfstr,
"%s,", temp);
offset = offset + sbi_strlen(temp) + 1;
}
}
feat = feat << 1;
} while (feat <= SBI_PLATFORM_HAS_LAST_FEATURE);
done:
if (offset)
features_str[offset - 1] = '\0';
else
sbi_strncpy(features_str, "none", nfstr);
}
u32 sbi_platform_hart_index(const struct sbi_platform *plat, u32 hartid)
{
u32 i;
if (!plat)
return -1U;
if (plat->hart_index2id) {
for (i = 0; i < plat->hart_count; i++) {
if (plat->hart_index2id[i] == hartid)
return i;
}
return -1U;
}
return hartid;
}

View File

@@ -8,14 +8,44 @@
*/
#include <sbi/riscv_locks.h>
#include <sbi/sbi_hart.h>
#include <sbi/sbi_hartmask.h>
#include <sbi/sbi_platform.h>
#include <sbi/sbi_scratch.h>
#include <sbi/sbi_string.h>
u32 last_hartid_having_scratch = SBI_HARTMASK_MAX_BITS;
struct sbi_scratch *hartid_to_scratch_table[SBI_HARTMASK_MAX_BITS] = { 0 };
static spinlock_t extra_lock = SPIN_LOCK_INITIALIZER;
static unsigned long extra_offset = SBI_SCRATCH_EXTRA_SPACE_OFFSET;
typedef struct sbi_scratch *(*hartid2scratch)(ulong hartid, ulong hartindex);
int sbi_scratch_init(struct sbi_scratch *scratch)
{
u32 i;
const struct sbi_platform *plat = sbi_platform_ptr(scratch);
for (i = 0; i < SBI_HARTMASK_MAX_BITS; i++) {
if (sbi_platform_hart_invalid(plat, i))
continue;
hartid_to_scratch_table[i] =
((hartid2scratch)scratch->hartid_to_scratch)(i,
sbi_platform_hart_index(plat, i));
if (hartid_to_scratch_table[i])
last_hartid_having_scratch = i;
}
return 0;
}
unsigned long sbi_scratch_alloc_offset(unsigned long size, const char *owner)
{
u32 i;
void *ptr;
unsigned long ret = 0;
struct sbi_scratch *rscratch;
/*
* We have a simple brain-dead allocator which never expects
@@ -29,8 +59,8 @@ unsigned long sbi_scratch_alloc_offset(unsigned long size, const char *owner)
if (!size)
return 0;
while (size & (__SIZEOF_POINTER__ - 1))
size++;
if (size & (__SIZEOF_POINTER__ - 1))
size = (size & ~(__SIZEOF_POINTER__ - 1)) + __SIZEOF_POINTER__;
spin_lock(&extra_lock);
@@ -43,6 +73,16 @@ unsigned long sbi_scratch_alloc_offset(unsigned long size, const char *owner)
done:
spin_unlock(&extra_lock);
if (ret) {
for (i = 0; i < sbi_scratch_last_hartid(); i++) {
rscratch = sbi_hartid_to_scratch(i);
if (!rscratch)
continue;
ptr = sbi_scratch_offset_ptr(rscratch, ret);
sbi_memset(ptr, 0, size);
}
}
return ret;
}

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