89 Commits
v0.7 ... 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
118 changed files with 4008 additions and 1230 deletions

View File

@@ -130,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)) libsbiutils-objs-path-y=$(foreach obj,$(libsbiutils-objs-y),$(build_dir)/lib/utils/$(obj))
ifdef PLATFORM ifdef PLATFORM
platform-objs-path-y=$(foreach obj,$(platform-objs-y),$(platform_build_dir)/$(obj)) 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)) firmware-bins-path-y=$(foreach bin,$(firmware-bins-y),$(platform_build_dir)/firmware/$(bin))
endif endif
firmware-elfs-path-y=$(firmware-bins-path-y:.bin=.elf) firmware-elfs-path-y=$(firmware-bins-path-y:.bin=.elf)
@@ -227,7 +226,7 @@ MERGEFLAGS += -r
MERGEFLAGS += -b elf$(PLATFORM_RISCV_XLEN)-littleriscv MERGEFLAGS += -b elf$(PLATFORM_RISCV_XLEN)-littleriscv
MERGEFLAGS += -m elf$(PLATFORM_RISCV_XLEN)lriscv 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 # Setup functions for compilation
define dynamic_flags define dynamic_flags
@@ -289,13 +288,18 @@ compile_objcopy = $(CMD_PREFIX)mkdir -p `dirname $(1)`; \
$(OBJCOPY) -S -O binary $(2) $(1) $(OBJCOPY) -S -O binary $(2) $(1)
compile_dts = $(CMD_PREFIX)mkdir -p `dirname $(1)`; \ compile_dts = $(CMD_PREFIX)mkdir -p `dirname $(1)`; \
echo " DTC $(subst $(build_dir)/,,$(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/libsbi.a
targets-y += $(build_dir)/lib/libsbiutils.a targets-y += $(build_dir)/lib/libsbiutils.a
ifdef PLATFORM ifdef PLATFORM
targets-y += $(platform_build_dir)/lib/libplatsbi.a targets-y += $(platform_build_dir)/lib/libplatsbi.a
targets-y += $(platform-dtb-path-y)
endif endif
targets-y += $(firmware-bins-path-y) targets-y += $(firmware-bins-path-y)
@@ -342,12 +346,26 @@ $(platform_build_dir)/%.dep: $(platform_src_dir)/%.c
$(platform_build_dir)/%.o: $(platform_src_dir)/%.c $(platform_build_dir)/%.o: $(platform_src_dir)/%.c
$(call compile_cc,$@,$<) $(call compile_cc,$@,$<)
$(platform_build_dir)/%.o: $(platform_build_dir)/%.c
$(call compile_cc,$@,$<)
$(platform_build_dir)/%.dep: $(platform_src_dir)/%.S $(platform_build_dir)/%.dep: $(platform_src_dir)/%.S
$(call compile_as_dep,$@,$<) $(call compile_as_dep,$@,$<)
$(platform_build_dir)/%.o: $(platform_src_dir)/%.S $(platform_build_dir)/%.o: $(platform_src_dir)/%.S
$(call compile_as,$@,$<) $(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 $(platform_build_dir)/%.dep: $(src_dir)/%.c
$(call compile_cc_dep,$@,$<) $(call compile_cc_dep,$@,$<)
@@ -360,9 +378,6 @@ $(platform_build_dir)/%.dep: $(src_dir)/%.S
$(platform_build_dir)/%.o: $(src_dir)/%.S $(platform_build_dir)/%.o: $(src_dir)/%.S
$(call compile_as,$@,$<) $(call compile_as,$@,$<)
$(build_dir)/%.dtb: $(src_dir)/%.dts
$(call compile_dts,$@,$<)
# Rule for "make docs" # Rule for "make docs"
$(build_dir)/docs/latex/refman.pdf: $(build_dir)/docs/latex/refman.tex $(build_dir)/docs/latex/refman.pdf: $(build_dir)/docs/latex/refman.tex
$(CMD_PREFIX)mkdir -p $(build_dir)/docs $(CMD_PREFIX)mkdir -p $(build_dir)/docs

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) 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 The **RISC-V Supervisor Binary Interface (SBI)** is the recommended interface
between: between:
@@ -115,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 are built for the platform *<platform_subdir>* present in the directory
*platform* in the OpenSBI top directory. For example, to compile the platform *platform* in the OpenSBI top directory. For example, to compile the platform
library and the firmware examples for the QEMU RISC-V *virt* machine, library and the firmware examples for the QEMU RISC-V *virt* machine,
*<platform_subdir>* should be *qemu/virt*. *<platform_subdir>* should be *generic*.
To build *libsbi.a*, *libplatsbi.a* and the firmware for one of the supported To build *libsbi.a*, *libplatsbi.a* and the firmware for one of the supported
platforms, run: platforms, run:
@@ -171,35 +203,6 @@ export PLATFORM_RISCV_XLEN=32
will generate 32-bit OpenSBI images. And vice vesa. 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 Contributing to OpenSBI
----------------------- -----------------------
@@ -218,6 +221,7 @@ Detailed documentation of various aspects of OpenSBI can be found under the
* [Contribution Guideline]: Guideline for contributing code to OpenSBI project * [Contribution Guideline]: Guideline for contributing code to OpenSBI project
* [Library Usage]: API documentation of OpenSBI static library *libsbi.a* * [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 Support Guide]: Guideline for implementing support for new platforms
* [Platform Documentation]: Documentation of the platforms currently supported. * [Platform Documentation]: Documentation of the platforms currently supported.
* [Firmware Documentation]: Documentation for the different types of firmware * [Firmware Documentation]: Documentation for the different types of firmware
@@ -270,6 +274,7 @@ make I=<install_directory> install_docs
[Contribution Guideline]: docs/contributing.md [Contribution Guideline]: docs/contributing.md
[Contributors List]: CONTRIBUTORS.md [Contributors List]: CONTRIBUTORS.md
[Library Usage]: docs/library_usage.md [Library Usage]: docs/library_usage.md
[Platform Requirements]: docs/platform_requirements.md
[Platform Support Guide]: docs/platform_guide.md [Platform Support Guide]: docs/platform_guide.md
[Platform Documentation]: docs/platform/platform.md [Platform Documentation]: docs/platform/platform.md
[Firmware Documentation]: docs/firmware/fw.md [Firmware Documentation]: docs/firmware/fw.md

View File

@@ -793,6 +793,7 @@ WARN_LOGFILE =
INPUT = @@SRC_DIR@@/README.md \ INPUT = @@SRC_DIR@@/README.md \
@@SRC_DIR@@/docs/contributing.md \ @@SRC_DIR@@/docs/contributing.md \
@@SRC_DIR@@/docs/platform_guide.md \ @@SRC_DIR@@/docs/platform_guide.md \
@@SRC_DIR@@/docs/platform_requirements.md \
@@SRC_DIR@@/docs/library_usage.md \ @@SRC_DIR@@/docs/library_usage.md \
@@SRC_DIR@@/docs/firmware \ @@SRC_DIR@@/docs/firmware \
@@SRC_DIR@@/docs/platform \ @@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 # (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. # 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 # Configuration options related to source browsing
@@ -1444,7 +1445,7 @@ DISABLE_INDEX = NO
# The default value is: NO. # The default value is: NO.
# This tag requires that the tag GENERATE_HTML is set to YES. # 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 # 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. # doxygen will group on one line in the generated HTML documentation.

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 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 OpenSBI **firmware with Jump Address (FW_JUMP)** is a firmware which only

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 OpenSBI **firmware with Payload (FW_PAYLOAD)** is a firmware which directly
@@ -57,17 +57,8 @@ file. The parameters currently defined are as follows:
* **FW_PAYLOAD_FDT_PATH** - Path to an external flattened device tree binary * **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 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 option is not provided then the firmware will expect the FDT to be passed
platform (c.f. *FW_PAYLOAD_FDT*), then the firmware will expect the FDT to as an argument by the prior booting stage.
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.
* **FW_PAYLOAD_FDT_ADDR** - Address where the FDT passed by the prior booting * **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 stage or specified by the *FW_PAYLOAD_FDT_PATH* parameter and embedded in
@@ -83,7 +74,4 @@ The *[qemu/virt]* platforms illustrate how to configure and use a *FW_PAYLOAD*
firmware. Detailed information regarding these platforms can be found in the firmware. Detailed information regarding these platforms can be found in the
platform documentation files. platform documentation files.
The *kendryte/k210* platform also enables a build of a *FW_PAYLOAD* using an
internally defined device tree file (*FW_PAYLOAD_FDT*).
[qemu/virt]: ../platform/qemu_virt.md [qemu/virt]: ../platform/qemu_virt.md

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,6 +3,11 @@ OpenSBI Supported Platforms
OpenSBI currently supports the following virtual and hardware 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 * **QEMU RISC-V Virt Machine**: Platform support for the QEMU *virt* virtual
RISC-V machine. This virtual machine is intended for RISC-V software 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 development and tests. More details on this platform can be found in the
@@ -17,16 +22,25 @@ OpenSBI currently supports the following virtual and hardware platforms:
boards such as the Kendryte KD233 or the Sipeed MAIX Dock. boards such as the Kendryte KD233 or the Sipeed MAIX Dock.
* **Ariane FPGA SoC**: Platform support for the Ariane FPGA SoC used on * **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. * **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. * **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 * **OpenPiton FPGA SoC**: Platform support OpenPiton research platform based
ariane core. 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 The code for these supported platforms can be used as example to implement
support for other platforms. The *platform/template* directory also provides support for other platforms. The *platform/template* directory also provides
@@ -34,10 +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 *config.mk* and *platform.c* template files provides enough comments to
facilitate the implementation. facilitate the implementation.
[generic.md]: generic.md
[qemu_virt.md]: qemu_virt.md [qemu_virt.md]: qemu_virt.md
[sifive_fu540.md]: sifive_fu540.md [sifive_fu540.md]: sifive_fu540.md
[fpga-ariane.md]: fpga-ariane.md [fpga-ariane.md]: fpga-ariane.md
[andes_ae350.md]: andes-ae350.md [andes-ae350.md]: andes-ae350.md
[thead-c910.md]: thead-c910.md [thead-c910.md]: thead-c910.md
[spike.md]: spike.md [spike.md]: spike.md
[fpga_openpiton.md]: fpga_openpiton.md [fpga_openpiton.md]: fpga_openpiton.md
[shakti_cclass.md]: shakti_cclass.md

View File

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

View File

@@ -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

@@ -49,29 +49,6 @@ The detailed U-Boot booting guide is avaialble at [U-Boot].
make PLATFORM=sifive/fu540 FW_PAYLOAD_PATH=<u-boot_build_dir>/u-boot-dtb.bin make PLATFORM=sifive/fu540 FW_PAYLOAD_PATH=<u-boot_build_dir>/u-boot-dtb.bin
``` ```
**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. Create a temporary image with u-boot-dtb.bin as the first payload. The
command-line example here assumes that U-Boot was compiled using
sifive_fu540_defconfig configuration.
```
dd if=~/workspace/u-boot-riscv/u-boot-dtb.bin of=/tmp/temp.bin bs=1M
```
2. Append the Linux Kernel image.
```
dd if=<linux_build_directory>/arch/riscv/boot/Image of=/tmp/temp.bin bs=1M seek=4
```
3. Compile OpenSBI with temp.bin (generated in step 2) as payload.
```
make PLATFORM=sifive/fu540 FW_PAYLOAD_PATH=/tmp/temp.bin
or
(For U-Boot which follows Linux v5.2 (or higher) DT bindings)
make PLATFORM=sifive/fu540 FW_PAYLOAD_PATH=/tmp/temp.bin
```
Flashing the OpenSBI firmware binary to storage media: Flashing the OpenSBI firmware binary to storage media:
------------------------------------------------------ ------------------------------------------------------
The first stage boot loader ([FSBL]) expects the storage media to have a GPT The first stage boot loader ([FSBL]) expects the storage media to have a GPT

View File

@@ -9,7 +9,7 @@ on **Spike** simulator and QEMU Spike machine.
For more details, refer [Spike on GitHub](https://github.com/riscv/riscv-isa-sim) 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 To build the platform-specific library and firmware images, provide the
*PLATFORM=spike* parameter to the top level `make` command. *PLATFORM=generic* parameter to the top level `make` command.
Platform Options Platform Options
---------------- ----------------
@@ -23,12 +23,12 @@ Execution on Spike Simulator
Build: Build:
``` ```
make PLATFORM=spike make PLATFORM=generic
``` ```
Run: Run:
``` ```
spike build/platform/spike/firmware/fw_payload.elf spike build/platform/generic/firmware/fw_payload.elf
``` ```
**Linux Kernel Payload** **Linux Kernel Payload**
@@ -38,12 +38,12 @@ Note: We assume that the Linux kernel is compiled using
Build: Build:
``` ```
make PLATFORM=spike FW_PAYLOAD_PATH=<linux_build_directory>/arch/riscv/boot/Image make PLATFORM=generic FW_PAYLOAD_PATH=<linux_build_directory>/arch/riscv/boot/Image
``` ```
Run: Run:
``` ```
spike --initrd <path_to_cpio_ramdisk> build/platform/spike/firmware/fw_payload.elf spike --initrd <path_to_cpio_ramdisk> build/platform/generic/firmware/fw_payload.elf
``` ```
Execution on QEMU RISC-V 64-bit Execution on QEMU RISC-V 64-bit
@@ -53,13 +53,13 @@ Execution on QEMU RISC-V 64-bit
Build: Build:
``` ```
make PLATFORM=spike make PLATFORM=generic
``` ```
Run: Run:
``` ```
qemu-system-riscv64 -M spike -m 256M -nographic \ qemu-system-riscv64 -M spike -m 256M -nographic \
-kernel build/platform/spike/firmware/fw_payload.elf -kernel build/platform/generic/firmware/fw_payload.elf
``` ```
**Linux Kernel Payload** **Linux Kernel Payload**
@@ -69,20 +69,20 @@ Note: We assume that the Linux kernel is compiled using
Build: Build:
``` ```
make PLATFORM=spike FW_PAYLOAD_PATH=<linux_build_directory>/arch/riscv/boot/Image make PLATFORM=generic FW_PAYLOAD_PATH=<linux_build_directory>/arch/riscv/boot/Image
``` ```
Run: Run:
``` ```
qemu-system-riscv64 -M spike -m 256M -nographic \ qemu-system-riscv64 -M spike -m 256M -nographic \
-kernel build/platform/spike/firmware/fw_payload.elf \ -kernel build/platform/generic/firmware/fw_payload.elf \
-initrd <path_to_cpio_ramdisk> \ -initrd <path_to_cpio_ramdisk> \
-append "root=/dev/ram rw console=hvc0 earlycon=sbi" -append "root=/dev/ram rw console=hvc0 earlycon=sbi"
``` ```
or or
``` ```
qemu-system-riscv64 -M spike -m 256M -nographic \ qemu-system-riscv64 -M spike -m 256M -nographic \
-bios build/platform/spike/firmware/fw_jump.elf \ -bios build/platform/generic/firmware/fw_jump.elf \
-kernel <linux_build_directory>/arch/riscv/boot/Image \ -kernel <linux_build_directory>/arch/riscv/boot/Image \
-initrd <path_to_cpio_ramdisk> \ -initrd <path_to_cpio_ramdisk> \
-append "root=/dev/ram rw console=hvc0 earlycon=sbi" -append "root=/dev/ram rw console=hvc0 earlycon=sbi"

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

@@ -160,11 +160,48 @@ _relocate_done:
li ra, 0 li ra, 0
call _reset_regs 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 */ /* Allow main firmware to save info */
MOV_5R s0, a0, s1, a1, s2, a2, s3, a3, s4, a4 MOV_5R s0, a0, s1, a1, s2, a2, s3, a3, s4, a4
call fw_save_info call fw_save_info
MOV_5R a0, s0, a1, s1, a2, s2, a3, s3, a4, s4 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 /* Preload HART details
* s7 -> HART Count * s7 -> HART Count
* s8 -> HART Stack Size * s8 -> HART Stack Size
@@ -233,35 +270,16 @@ _scratch_init:
/* Store firmware options in scratch space */ /* Store firmware options in scratch space */
MOV_3R s0, a0, s1, a1, s2, a2 MOV_3R s0, a0, s1, a1, s2, a2
#ifdef FW_OPTIONS #ifdef FW_OPTIONS
li a4, FW_OPTIONS li a0, FW_OPTIONS
#else #else
add a4, zero, zero
#endif
call fw_options call fw_options
or a4, a4, a0 #endif
REG_S a4, SBI_SCRATCH_OPTIONS_OFFSET(tp) REG_S a0, SBI_SCRATCH_OPTIONS_OFFSET(tp)
MOV_3R a0, s0, a1, s1, a2, s2 MOV_3R a0, s0, a1, s1, a2, s2
/* Move to next scratch space */ /* Move to next scratch space */
add t1, t1, t2 add t1, t1, t2
blt t1, s7, _scratch_init 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) * Relocate Flatened Device Tree (FDT)
* source FDT address = previous arg1 * source FDT address = previous arg1
@@ -331,7 +349,7 @@ _fdt_reloc_done:
fence rw, rw fence rw, rw
j _start_warm 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: _wait_for_boot_hart:
li t0, BOOT_STATUS_BOOT_HART_DONE li t0, BOOT_STATUS_BOOT_HART_DONE
la t1, _boot_status la t1, _boot_status
@@ -400,9 +418,6 @@ _start_warm:
/* Setup trap handler */ /* Setup trap handler */
la a4, _trap_handler la a4, _trap_handler
csrw CSR_MTVEC, a4 csrw CSR_MTVEC, a4
/* Make sure that mtvec is updated */
1: csrr a5, CSR_MTVEC
bne a4, a5, 1b
/* Initialize SBI runtime */ /* Initialize SBI runtime */
csrr a0, CSR_MSCRATCH csrr a0, CSR_MSCRATCH
@@ -457,6 +472,14 @@ _start_hang:
wfi wfi
j _start_hang j _start_hang
.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 .section .entry, "ax", %progbits
.align 3 .align 3
.globl _trap_handler .globl _trap_handler

View File

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

View File

@@ -173,19 +173,8 @@ int misa_extension_imp(char ext);
/* Get MXL field of misa, return -1 on error */ /* Get MXL field of misa, return -1 on error */
int misa_xlen(void); int misa_xlen(void);
static inline void misa_string(char *out, unsigned int out_sz) /* Get RISC-V ISA string representation */
{ void misa_string(int xlen, char *out, unsigned int out_sz);
unsigned long i;
for (i = 0; i < 26; i++) {
if (misa_extension_imp('A' + i)) {
*out = 'A' + i;
out++;
}
}
*out = '\0';
out++;
}
int pmp_set(unsigned int n, unsigned long prot, unsigned long addr, int pmp_set(unsigned int n, unsigned long prot, unsigned long addr,
unsigned long log2len); unsigned long log2len);

View File

@@ -61,12 +61,20 @@
#define SSTATUS64_UXL MSTATUS_UXL #define SSTATUS64_UXL MSTATUS_UXL
#define SSTATUS64_SD MSTATUS64_SD #define SSTATUS64_SD MSTATUS64_SD
#if __riscv_xlen == 64
#define HSTATUS_VSXL _UL(0x300000000)
#define HSTATUS_VSXL_SHIFT 32
#endif
#define HSTATUS_VTSR _UL(0x00400000) #define HSTATUS_VTSR _UL(0x00400000)
#define HSTATUS_VTW _UL(0x00200000)
#define HSTATUS_VTVM _UL(0x00100000) #define HSTATUS_VTVM _UL(0x00100000)
#define HSTATUS_SP2V _UL(0x00000200) #define HSTATUS_VGEIN _UL(0x0003f000)
#define HSTATUS_SP2P _UL(0x00000100) #define HSTATUS_VGEIN_SHIFT 12
#define HSTATUS_HU _UL(0x00000200)
#define HSTATUS_SPVP _UL(0x00000100)
#define HSTATUS_SPV _UL(0x00000080) #define HSTATUS_SPV _UL(0x00000080)
#define HSTATUS_SPRV _UL(0x00000001) #define HSTATUS_GVA _UL(0x00000040)
#define HSTATUS_VSBE _UL(0x00000020)
#define IRQ_S_SOFT 1 #define IRQ_S_SOFT 1
#define IRQ_VS_SOFT 2 #define IRQ_VS_SOFT 2
@@ -111,6 +119,21 @@
#define SATP_MODE_SV57 _UL(10) #define SATP_MODE_SV57 _UL(10)
#define SATP_MODE_SV64 _UL(11) #define SATP_MODE_SV64 _UL(11)
#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_R _UL(0x01)
#define PMP_W _UL(0x02) #define PMP_W _UL(0x02)
#define PMP_X _UL(0x04) #define PMP_X _UL(0x04)
@@ -123,35 +146,25 @@
#define PMP_SHIFT 2 #define PMP_SHIFT 2
#define PMP_COUNT 16 #define PMP_COUNT 16
/* page table entry (PTE) fields */
#define PTE_V _UL(0x001) /* Valid */
#define PTE_R _UL(0x002) /* Read */
#define PTE_W _UL(0x004) /* Write */
#define PTE_X _UL(0x008) /* Execute */
#define PTE_U _UL(0x010) /* User */
#define PTE_G _UL(0x020) /* Global */
#define PTE_A _UL(0x040) /* Accessed */
#define PTE_D _UL(0x080) /* Dirty */
#define PTE_SOFT _UL(0x300) /* Reserved for Software */
#define PTE_PPN_SHIFT 10
#define PTE_TABLE(PTE) \
(((PTE) & (PTE_V | PTE_R | PTE_W | PTE_X)) == PTE_V)
#if __riscv_xlen == 64 #if __riscv_xlen == 64
#define MSTATUS_SD MSTATUS64_SD #define MSTATUS_SD MSTATUS64_SD
#define SSTATUS_SD SSTATUS64_SD #define SSTATUS_SD SSTATUS64_SD
#define RISCV_PGLEVEL_BITS 9
#define SATP_MODE SATP64_MODE #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 #else
#define MSTATUS_SD MSTATUS32_SD #define MSTATUS_SD MSTATUS32_SD
#define SSTATUS_SD SSTATUS32_SD #define SSTATUS_SD SSTATUS32_SD
#define RISCV_PGLEVEL_BITS 10
#define SATP_MODE SATP32_MODE #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 #endif
#define RISCV_PGSHIFT 12
#define RISCV_PGSIZE (1 << RISCV_PGSHIFT)
#define CSR_USTATUS 0x0 #define CSR_USTATUS 0x0
#define CSR_FFLAGS 0x1 #define CSR_FFLAGS 0x1
@@ -419,6 +432,7 @@
#define CAUSE_STORE_PAGE_FAULT 0xf #define CAUSE_STORE_PAGE_FAULT 0xf
#define CAUSE_FETCH_GUEST_PAGE_FAULT 0x14 #define CAUSE_FETCH_GUEST_PAGE_FAULT 0x14
#define CAUSE_LOAD_GUEST_PAGE_FAULT 0x15 #define CAUSE_LOAD_GUEST_PAGE_FAULT 0x15
#define CAUSE_VIRTUAL_INST_FAULT 0x16
#define CAUSE_STORE_GUEST_PAGE_FAULT 0x17 #define CAUSE_STORE_GUEST_PAGE_FAULT 0x17
#define INSN_MATCH_LB 0x3 #define INSN_MATCH_LB 0x3

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

@@ -13,7 +13,7 @@
/* clang-format off */ /* clang-format off */
/* SBI Extension IDs */ /* SBI Extension IDs */
#define SBI_EXT_0_1_SET_TIMER 0x0 #define SBI_EXT_0_1_SET_TIMER 0x0
#define SBI_EXT_0_1_CONSOLE_PUTCHAR 0x1 #define SBI_EXT_0_1_CONSOLE_PUTCHAR 0x1
#define SBI_EXT_0_1_CONSOLE_GETCHAR 0x2 #define SBI_EXT_0_1_CONSOLE_GETCHAR 0x2
#define SBI_EXT_0_1_CLEAR_IPI 0x3 #define SBI_EXT_0_1_CLEAR_IPI 0x3
@@ -67,6 +67,20 @@
#define SBI_SPEC_VERSION_MINOR_MASK 0xffffff #define SBI_SPEC_VERSION_MINOR_MASK 0xffffff
#define SBI_EXT_VENDOR_START 0x09000000 #define SBI_EXT_VENDOR_START 0x09000000
#define SBI_EXT_VENDOR_END 0x09FFFFFF #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
/* clang-format on */ /* clang-format on */
#endif #endif

View File

@@ -10,25 +10,28 @@
#ifndef __SBI_ERROR_H__ #ifndef __SBI_ERROR_H__
#define __SBI_ERROR_H__ #define __SBI_ERROR_H__
#include <sbi/sbi_ecall_interface.h>
/* clang-format off */ /* clang-format off */
#define SBI_OK 0 #define SBI_OK 0
#define SBI_EFAIL -1 #define SBI_EFAIL SBI_ERR_FAILED
#define SBI_ENOTSUPP -2 #define SBI_ENOTSUPP SBI_ERR_NOT_SUPPORTED
#define SBI_EINVAL -3 #define SBI_EINVAL SBI_ERR_INVALID_PARAM
#define SBI_DENIED -4 #define SBI_EDENIED SBI_ERR_DENIED
#define SBI_INVALID_ADDR -5 #define SBI_EINVALID_ADDR SBI_ERR_INVALID_ADDRESS
#define SBI_ENODEV -6 #define SBI_EALREADY SBI_ERR_ALREADY_AVAILABLE
#define SBI_ENOSYS -7
#define SBI_ETIMEDOUT -8 #define SBI_ENODEV -1000
#define SBI_EIO -9 #define SBI_ENOSYS -1001
#define SBI_EILL -10 #define SBI_ETIMEDOUT -1002
#define SBI_ENOSPC -11 #define SBI_EIO -1003
#define SBI_ENOMEM -12 #define SBI_EILL -1004
#define SBI_ETRAP -13 #define SBI_ENOSPC -1005
#define SBI_EUNKNOWN -14 #define SBI_ENOMEM -1006
#define SBI_ENOENT -15 #define SBI_ETRAP -1007
#define SBI_EALREADY_STARTED -16 #define SBI_EUNKNOWN -1008
#define SBI_ENOENT -1009
/* clang-format on */ /* clang-format on */

View File

@@ -12,20 +12,42 @@
#include <sbi/sbi_types.h> #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; struct sbi_scratch;
int sbi_hart_init(struct sbi_scratch *scratch, u32 hartid, bool cold_boot); int sbi_hart_init(struct sbi_scratch *scratch, u32 hartid, bool cold_boot);
extern void (*sbi_hart_unpriv_trap)(void); extern void (*sbi_hart_expected_trap)(void);
static inline ulong sbi_hart_unpriv_trap_addr(void) static inline ulong sbi_hart_expected_trap_addr(void)
{ {
return (ulong)sbi_hart_unpriv_trap; return (ulong)sbi_hart_expected_trap;
} }
void sbi_hart_delegation_dump(struct sbi_scratch *scratch); 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); void sbi_hart_pmp_dump(struct sbi_scratch *scratch);
int sbi_hart_pmp_check_addr(struct sbi_scratch *scratch, unsigned long daddr, int sbi_hart_pmp_check_addr(struct sbi_scratch *scratch, unsigned long daddr,
unsigned long attr); 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); void __attribute__((noreturn)) sbi_hart_hang(void);

View File

@@ -10,8 +10,9 @@
#ifndef __SBI_FENCE_H__ #ifndef __SBI_FENCE_H__
#define __SBI_FENCE_H__ #define __SBI_FENCE_H__
/** Invalidate Stage2 TLBs for given VMID and guest physical address */ /** Invalidate Stage2 TLBs for given VMID and guest physical address */
void __sbi_hfence_gvma_vmid_gpa(unsigned long vmid, unsigned long gpa); void __sbi_hfence_gvma_vmid_gpa(unsigned long gpa, unsigned long vmid);
/** Invalidate Stage2 TLBs for given VMID */ /** Invalidate Stage2 TLBs for given VMID */
void __sbi_hfence_gvma_vmid(unsigned long vmid); void __sbi_hfence_gvma_vmid(unsigned long vmid);
@@ -23,7 +24,7 @@ void __sbi_hfence_gvma_gpa(unsigned long gpa);
void __sbi_hfence_gvma_all(void); void __sbi_hfence_gvma_all(void);
/** Invalidate unified TLB entries for given asid and guest virtual address */ /** Invalidate unified TLB entries for given asid and guest virtual address */
void __sbi_hfence_vvma_asid_va(unsigned long asid, unsigned long va); void __sbi_hfence_vvma_asid_va(unsigned long va, unsigned long asid);
/** Invalidate unified TLB entries for given ASID for a guest*/ /** Invalidate unified TLB entries for given ASID for a guest*/
void __sbi_hfence_vvma_asid(unsigned long asid); void __sbi_hfence_vvma_asid(unsigned long asid);
@@ -33,4 +34,5 @@ void __sbi_hfence_vvma_va(unsigned long va);
/** Invalidate all possible Stage2 TLBs */ /** Invalidate all possible Stage2 TLBs */
void __sbi_hfence_vvma_all(void); void __sbi_hfence_vvma_all(void);
#endif #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

@@ -52,23 +52,18 @@ enum sbi_platform_features {
SBI_PLATFORM_HAS_TIMER_VALUE = (1 << 0), SBI_PLATFORM_HAS_TIMER_VALUE = (1 << 0),
/** Platform has HART hotplug support */ /** Platform has HART hotplug support */
SBI_PLATFORM_HAS_HART_HOTPLUG = (1 << 1), SBI_PLATFORM_HAS_HART_HOTPLUG = (1 << 1),
/** Platform has PMP support */
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 */ /** 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 */ /** Platform has custom secondary hart booting support */
SBI_PLATFORM_HAS_HART_SECONDARY_BOOT = (1 << 6), 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 */ /** Default feature set for a platform */
#define SBI_PLATFORM_DEFAULT_FEATURES \ #define SBI_PLATFORM_DEFAULT_FEATURES \
(SBI_PLATFORM_HAS_TIMER_VALUE | SBI_PLATFORM_HAS_PMP | \ (SBI_PLATFORM_HAS_TIMER_VALUE | SBI_PLATFORM_HAS_MFAULTS_DELEGATION)
SBI_PLATFORM_HAS_SCOUNTEREN | SBI_PLATFORM_HAS_MCOUNTEREN | \
SBI_PLATFORM_HAS_MFAULTS_DELEGATION)
/** Platform functions */ /** Platform functions */
struct sbi_platform_operations { struct sbi_platform_operations {
@@ -146,10 +141,11 @@ struct sbi_platform_operations {
*/ */
int (*hart_stop)(void); int (*hart_stop)(void);
/** Reboot the platform */ /** Reset the platform */
int (*system_reboot)(u32 type); #define SBI_PLATFORM_RESET_SHUTDOWN 0
/** Shutdown or poweroff the platform */ #define SBI_PLATFORM_RESET_COLD 1
int (*system_shutdown)(u32 type); #define SBI_PLATFORM_RESET_WARM 2
int (*system_reset)(u32 reset_type);
/** platform specific SBI extension implementation probe function */ /** platform specific SBI extension implementation probe function */
int (*vendor_ext_check)(long extid); int (*vendor_ext_check)(long extid);
@@ -223,14 +219,6 @@ struct sbi_platform {
/** Check whether the platform supports HART hotplug */ /** Check whether the platform supports HART hotplug */
#define sbi_platform_has_hart_hotplug(__p) \ #define sbi_platform_has_hart_hotplug(__p) \
((__p)->features & SBI_PLATFORM_HAS_HART_HOTPLUG) ((__p)->features & SBI_PLATFORM_HAS_HART_HOTPLUG)
/** Check whether the platform has PMP support */
#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 */ /** Check whether the platform supports fault delegation */
#define sbi_platform_has_mfaults_delegation(__p) \ #define sbi_platform_has_mfaults_delegation(__p) \
((__p)->features & SBI_PLATFORM_HAS_MFAULTS_DELEGATION) ((__p)->features & SBI_PLATFORM_HAS_MFAULTS_DELEGATION)
@@ -238,6 +226,28 @@ struct sbi_platform {
#define sbi_platform_has_hart_secondary_boot(__p) \ #define sbi_platform_has_hart_secondary_boot(__p) \
((__p)->features & SBI_PLATFORM_HAS_HART_SECONDARY_BOOT) ((__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 * Get name of the platform
* *
@@ -252,6 +262,21 @@ static inline const char *sbi_platform_name(const struct sbi_platform *plat)
return "Unknown"; return "Unknown";
} }
/**
* Get the platform features
*
* @param plat pointer to struct sbi_platform
*
* @return the features value currently set for the given platform
*/
static inline unsigned long sbi_platform_get_features(
const struct sbi_platform *plat)
{
if (plat)
return plat->features;
return 0;
}
/** /**
* Get platform specific tlb range flush maximum value. Any request with size * Get platform specific tlb range flush maximum value. Any request with size
* higher than this is upgraded to a full flush. * higher than this is upgraded to a full flush.
@@ -296,32 +321,6 @@ static inline u32 sbi_platform_hart_stack_size(const struct sbi_platform *plat)
return 0; return 0;
} }
/**
* 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
*/
static inline 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;
}
/** /**
* Check whether given HART is invalid * Check whether given HART is invalid
* *
@@ -492,8 +491,9 @@ static inline int sbi_platform_pmp_region_info(const struct sbi_platform *plat,
ulong *log2size) ulong *log2size)
{ {
if (plat && sbi_platform_ops(plat)->pmp_region_info) if (plat && sbi_platform_ops(plat)->pmp_region_info)
return sbi_platform_ops(plat)->pmp_region_info(hartid, index, prot, addr, return sbi_platform_ops(plat)->pmp_region_info(hartid, index,
log2size); prot, addr,
log2size);
return 0; return 0;
} }
@@ -685,34 +685,18 @@ static inline void sbi_platform_timer_exit(const struct sbi_platform *plat)
} }
/** /**
* Reboot the platform * Reset the platform
* *
* @param plat pointer to struct sbi_platform * @param plat pointer to struct sbi_platform
* @param type type of reboot * @param reset_type type of reset
* *
* @return 0 on success and negative error code on failure * @return 0 on success and negative error code on failure
*/ */
static inline int sbi_platform_system_reboot(const struct sbi_platform *plat, static inline int sbi_platform_system_reset(const struct sbi_platform *plat,
u32 type) u32 reset_type)
{ {
if (plat && sbi_platform_ops(plat)->system_reboot) if (plat && sbi_platform_ops(plat)->system_reset)
return sbi_platform_ops(plat)->system_reboot(type); return sbi_platform_ops(plat)->system_reset(reset_type);
return 0;
}
/**
* Shutdown or poweroff the platform
*
* @param plat pointer to struct sbi_platform
* @param type type of shutdown or poweroff
*
* @return 0 on success and negative error code on failure
*/
static inline int sbi_platform_system_shutdown(const struct sbi_platform *plat,
u32 type)
{
if (plat && sbi_platform_ops(plat)->system_shutdown)
return sbi_platform_ops(plat)->system_shutdown(type);
return 0; return 0;
} }

View File

@@ -12,8 +12,6 @@
#include <sbi/sbi_types.h> #include <sbi/sbi_types.h>
void __noreturn sbi_system_reboot(u32 type); void __noreturn sbi_system_reset(u32 platform_reset_type);
void __noreturn sbi_system_shutdown(u32 type);
#endif #endif

View File

@@ -38,17 +38,19 @@ struct sbi_tlb_info {
unsigned long start; unsigned long start;
unsigned long size; unsigned long size;
unsigned long asid; unsigned long asid;
unsigned long vmid;
unsigned long type; unsigned long type;
struct sbi_hartmask smask; struct sbi_hartmask smask;
}; };
#define SBI_TLB_INFO_INIT(__ptr, __start, __size, __asid, __type, __src_hart) \ #define SBI_TLB_INFO_INIT(__p, __start, __size, __asid, __vmid, __type, __src) \
do { \ do { \
(__ptr)->start = (__start); \ (__p)->start = (__start); \
(__ptr)->size = (__size); \ (__p)->size = (__size); \
(__ptr)->asid = (__asid); \ (__p)->asid = (__asid); \
(__ptr)->type = (__type); \ (__p)->vmid = (__vmid); \
SBI_HARTMASK_INIT_EXCEPT(&(__ptr)->smask, (__src_hart)); \ (__p)->type = (__type); \
SBI_HARTMASK_INIT_EXCEPT(&(__p)->smask, (__src)); \
} while (0) } while (0)
#define SBI_TLB_INFO_SIZE sizeof(struct sbi_tlb_info) #define SBI_TLB_INFO_SIZE sizeof(struct sbi_tlb_info)

View File

@@ -78,6 +78,8 @@ typedef unsigned long physical_size_t;
const typeof(((type *)0)->member) * __mptr = (ptr); \ const typeof(((type *)0)->member) * __mptr = (ptr); \
(type *)((char *)__mptr - offsetof(type, member)); }) (type *)((char *)__mptr - offsetof(type, member)); })
#define array_size(x) (sizeof(x) / sizeof((x)[0]))
#define MAX(a, b) ((a) > (b) ? (a) : (b)) #define MAX(a, b) ((a) > (b) ? (a) : (b))
#define MIN(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 CLAMP(a, lo, hi) MIN(MAX(a, lo), hi)

View File

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

View File

@@ -47,6 +47,20 @@ void fdt_plic_fixup(void *fdt, const char *compat);
*/ */
int fdt_reserved_memory_fixup(void *fdt); 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 * General device tree fix-up
* *

View File

@@ -10,24 +10,59 @@
#ifndef __FDT_HELPER_H__ #ifndef __FDT_HELPER_H__
#define __FDT_HELPER_H__ #define __FDT_HELPER_H__
#include <sbi/sbi_types.h>
struct fdt_match {
const char *compatible;
void *data;
};
struct platform_uart_data { struct platform_uart_data {
unsigned long addr; unsigned long addr;
unsigned long freq; unsigned long freq;
unsigned long baud; unsigned long baud;
unsigned long reg_shift;
unsigned long reg_io_width;
}; };
struct platform_plic_data { const struct fdt_match *fdt_match_node(void *fdt, int nodeoff,
unsigned long addr; const struct fdt_match *match_table);
unsigned long num_src;
}; 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, int fdt_parse_uart8250(void *fdt, struct platform_uart_data *uart,
const char *compatible); const char *compatible);
int fdt_parse_plic(void *fdt, struct platform_plic_data *plic, struct plic_data;
const char *compatible);
int fdt_parse_clint(void *fdt, unsigned long *clint_addr, int fdt_parse_plic_node(void *fdt, int nodeoffset, struct plic_data *plic);
const char *compatible);
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__ */ #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,12 +12,18 @@
#include <sbi/sbi_types.h> #include <sbi/sbi_types.h>
int plic_warm_irqchip_init(u32 target_hart, int m_cntx_id, int s_cntx_id); struct plic_data {
unsigned long addr;
unsigned long num_src;
};
int plic_cold_irqchip_init(unsigned long base, u32 num_sources, u32 hart_count); int plic_warm_irqchip_init(struct plic_data *plic,
int m_cntx_id, int s_cntx_id);
void plic_set_thresh(u32 cntxid, u32 val); int plic_cold_irqchip_init(struct plic_data *plic);
void plic_set_ie(u32 cntxid, u32 word_index, u32 val); void plic_set_thresh(struct plic_data *plic, u32 cntxid, u32 val);
void plic_set_ie(struct plic_data *plic, u32 cntxid, u32 word_index, u32 val);
#endif #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> #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); void clint_ipi_clear(u32 target_hart);
int clint_warm_ipi_init(void); 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); u64 clint_timer_value(void);
@@ -30,7 +45,7 @@ void clint_timer_event_start(u64 next_event);
int clint_warm_timer_init(void); int clint_warm_timer_init(void);
int clint_cold_timer_init(unsigned long base, u32 hart_count, int clint_cold_timer_init(struct clint_data *clint,
bool has_64bit_mmio); struct clint_data *reference);
#endif #endif

View File

@@ -14,6 +14,6 @@ void htif_putc(char ch);
int htif_getc(void); int htif_getc(void);
int htif_system_down(u32 type); int htif_system_reset(u32 type);
#endif #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

@@ -24,12 +24,14 @@ libsbi-objs-y += sbi_ecall_vendor.o
libsbi-objs-y += sbi_emulate_csr.o libsbi-objs-y += sbi_emulate_csr.o
libsbi-objs-y += sbi_fifo.o libsbi-objs-y += sbi_fifo.o
libsbi-objs-y += sbi_hart.o libsbi-objs-y += sbi_hart.o
libsbi-objs-y += sbi_math.o
libsbi-objs-y += sbi_hfence.o libsbi-objs-y += sbi_hfence.o
libsbi-objs-y += sbi_hsm.o libsbi-objs-y += sbi_hsm.o
libsbi-objs-y += sbi_illegal_insn.o libsbi-objs-y += sbi_illegal_insn.o
libsbi-objs-y += sbi_init.o libsbi-objs-y += sbi_init.o
libsbi-objs-y += sbi_ipi.o libsbi-objs-y += sbi_ipi.o
libsbi-objs-y += sbi_misaligned_ldst.o libsbi-objs-y += sbi_misaligned_ldst.o
libsbi-objs-y += sbi_platform.o
libsbi-objs-y += sbi_scratch.o libsbi-objs-y += sbi_scratch.o
libsbi-objs-y += sbi_string.o libsbi-objs-y += sbi_string.o
libsbi-objs-y += sbi_system.o libsbi-objs-y += sbi_system.o
@@ -37,4 +39,4 @@ libsbi-objs-y += sbi_timer.o
libsbi-objs-y += sbi_tlb.o libsbi-objs-y += sbi_tlb.o
libsbi-objs-y += sbi_trap.o libsbi-objs-y += sbi_trap.o
libsbi-objs-y += sbi_unpriv.o libsbi-objs-y += sbi_unpriv.o
libsbi-objs-y += sbi_unpriv_trap.o libsbi-objs-y += sbi_expected_trap.o

View File

@@ -17,8 +17,13 @@ int misa_extension_imp(char ext)
{ {
unsigned long misa = csr_read(CSR_MISA); unsigned long misa = csr_read(CSR_MISA);
if (misa) if (misa) {
return misa & (1 << (ext - 'A')); 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); return sbi_platform_misa_extension(sbi_platform_thishart_ptr(), ext);
} }
@@ -44,6 +49,45 @@ int misa_xlen(void)
return r ? r : -1; 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) unsigned long csr_read_num(int csr_num)
{ {
unsigned long ret = 0; unsigned long ret = 0;
@@ -224,7 +268,7 @@ int pmp_set(unsigned int n, unsigned long prot, unsigned long addr,
/* encode PMP config */ /* encode PMP config */
prot |= (log2len == PMP_SHIFT) ? PMP_A_NA4 : PMP_A_NAPOT; prot |= (log2len == PMP_SHIFT) ? PMP_A_NA4 : PMP_A_NAPOT;
cfgmask = ~(0xff << pmpcfg_shift); cfgmask = ~(0xffUL << pmpcfg_shift);
pmpcfg = (csr_read_num(pmpcfg_csr) & cfgmask); pmpcfg = (csr_read_num(pmpcfg_csr) & cfgmask);
pmpcfg |= ((prot << pmpcfg_shift) & ~cfgmask); pmpcfg |= ((prot << pmpcfg_shift) & ~cfgmask);
@@ -276,7 +320,7 @@ int pmp_get(unsigned int n, unsigned long *prot_out, unsigned long *addr_out,
return SBI_ENOTSUPP; return SBI_ENOTSUPP;
/* decode PMP config */ /* decode PMP config */
cfgmask = (0xff << pmpcfg_shift); cfgmask = (0xffUL << pmpcfg_shift);
pmpcfg = csr_read_num(pmpcfg_csr) & cfgmask; pmpcfg = csr_read_num(pmpcfg_csr) & cfgmask;
prot = pmpcfg >> pmpcfg_shift; prot = pmpcfg >> pmpcfg_shift;

View File

@@ -7,6 +7,7 @@
* Anup Patel <anup.patel@wdc.com> * Anup Patel <anup.patel@wdc.com>
*/ */
#include <sbi/sbi_console.h>
#include <sbi/sbi_ecall.h> #include <sbi/sbi_ecall.h>
#include <sbi/sbi_ecall_interface.h> #include <sbi/sbi_ecall_interface.h>
#include <sbi/sbi_error.h> #include <sbi/sbi_error.h>
@@ -124,6 +125,13 @@ int sbi_ecall_handler(struct sbi_trap_regs *regs)
trap.epc = regs->mepc; trap.epc = regs->mepc;
sbi_trap_redirect(regs, &trap); sbi_trap_redirect(regs, &trap);
} else { } else {
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 * This function should return non-zero value only in case of
* fatal error. However, there is no good way to distinguish * fatal error. However, there is no good way to distinguish

View File

@@ -15,6 +15,7 @@
#include <sbi/sbi_error.h> #include <sbi/sbi_error.h>
#include <sbi/sbi_hsm.h> #include <sbi/sbi_hsm.h>
#include <sbi/sbi_ipi.h> #include <sbi/sbi_ipi.h>
#include <sbi/sbi_platform.h>
#include <sbi/sbi_system.h> #include <sbi/sbi_system.h>
#include <sbi/sbi_timer.h> #include <sbi/sbi_timer.h>
#include <sbi/sbi_tlb.h> #include <sbi/sbi_tlb.h>
@@ -75,7 +76,7 @@ static int sbi_ecall_legacy_handler(unsigned long extid, unsigned long funcid,
ret = sbi_load_hart_mask_unpriv((ulong *)args[0], ret = sbi_load_hart_mask_unpriv((ulong *)args[0],
&hmask, out_trap); &hmask, out_trap);
if (ret != SBI_ETRAP) { if (ret != SBI_ETRAP) {
SBI_TLB_INFO_INIT(&tlb_info, 0, 0, 0, SBI_TLB_INFO_INIT(&tlb_info, 0, 0, 0, 0,
SBI_ITLB_FLUSH, source_hart); SBI_ITLB_FLUSH, source_hart);
ret = sbi_tlb_request(hmask, 0, &tlb_info); ret = sbi_tlb_request(hmask, 0, &tlb_info);
} }
@@ -84,7 +85,7 @@ static int sbi_ecall_legacy_handler(unsigned long extid, unsigned long funcid,
ret = sbi_load_hart_mask_unpriv((ulong *)args[0], ret = sbi_load_hart_mask_unpriv((ulong *)args[0],
&hmask, out_trap); &hmask, out_trap);
if (ret != SBI_ETRAP) { if (ret != SBI_ETRAP) {
SBI_TLB_INFO_INIT(&tlb_info, args[1], args[2], 0, SBI_TLB_INFO_INIT(&tlb_info, args[1], args[2], 0, 0,
SBI_TLB_FLUSH_VMA, source_hart); SBI_TLB_FLUSH_VMA, source_hart);
ret = sbi_tlb_request(hmask, 0, &tlb_info); ret = sbi_tlb_request(hmask, 0, &tlb_info);
} }
@@ -94,12 +95,13 @@ static int sbi_ecall_legacy_handler(unsigned long extid, unsigned long funcid,
&hmask, out_trap); &hmask, out_trap);
if (ret != SBI_ETRAP) { if (ret != SBI_ETRAP) {
SBI_TLB_INFO_INIT(&tlb_info, args[1], args[2], args[3], SBI_TLB_INFO_INIT(&tlb_info, args[1], args[2], args[3],
SBI_TLB_FLUSH_VMA_ASID, source_hart); 0, SBI_TLB_FLUSH_VMA_ASID,
source_hart);
ret = sbi_tlb_request(hmask, 0, &tlb_info); ret = sbi_tlb_request(hmask, 0, &tlb_info);
} }
break; break;
case SBI_EXT_0_1_SHUTDOWN: case SBI_EXT_0_1_SHUTDOWN:
sbi_system_shutdown(0); sbi_system_reset(SBI_PLATFORM_RESET_SHUTDOWN);
break; break;
default: default:
ret = SBI_ENOTSUPP; ret = SBI_ENOTSUPP;

View File

@@ -46,6 +46,7 @@ static int sbi_ecall_rfence_handler(unsigned long extid, unsigned long funcid,
struct sbi_trap_info *out_trap) struct sbi_trap_info *out_trap)
{ {
int ret = 0; int ret = 0;
unsigned long vmid;
struct sbi_tlb_info tlb_info; struct sbi_tlb_info tlb_info;
u32 source_hart = current_hartid(); u32 source_hart = current_hartid();
@@ -56,37 +57,41 @@ static int sbi_ecall_rfence_handler(unsigned long extid, unsigned long funcid,
switch (funcid) { switch (funcid) {
case SBI_EXT_RFENCE_REMOTE_FENCE_I: case SBI_EXT_RFENCE_REMOTE_FENCE_I:
SBI_TLB_INFO_INIT(&tlb_info, 0, 0, 0, SBI_TLB_INFO_INIT(&tlb_info, 0, 0, 0, 0,
SBI_ITLB_FLUSH, source_hart); SBI_ITLB_FLUSH, source_hart);
ret = sbi_tlb_request(args[0], args[1], &tlb_info); ret = sbi_tlb_request(args[0], args[1], &tlb_info);
break; break;
case SBI_EXT_RFENCE_REMOTE_HFENCE_GVMA: case SBI_EXT_RFENCE_REMOTE_HFENCE_GVMA:
SBI_TLB_INFO_INIT(&tlb_info, args[2], args[3], 0, SBI_TLB_INFO_INIT(&tlb_info, args[2], args[3], 0, 0,
SBI_TLB_FLUSH_GVMA, source_hart); SBI_TLB_FLUSH_GVMA, source_hart);
ret = sbi_tlb_request(args[0], args[1], &tlb_info); ret = sbi_tlb_request(args[0], args[1], &tlb_info);
break; break;
case SBI_EXT_RFENCE_REMOTE_HFENCE_GVMA_VMID: case SBI_EXT_RFENCE_REMOTE_HFENCE_GVMA_VMID:
SBI_TLB_INFO_INIT(&tlb_info, args[2], args[3], args[4], SBI_TLB_INFO_INIT(&tlb_info, args[2], args[3], 0, args[4],
SBI_TLB_FLUSH_GVMA_VMID, source_hart); SBI_TLB_FLUSH_GVMA_VMID, source_hart);
ret = sbi_tlb_request(args[0], args[1], &tlb_info); ret = sbi_tlb_request(args[0], args[1], &tlb_info);
break; break;
case SBI_EXT_RFENCE_REMOTE_HFENCE_VVMA: case SBI_EXT_RFENCE_REMOTE_HFENCE_VVMA:
SBI_TLB_INFO_INIT(&tlb_info, args[2], args[3], 0, 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); SBI_TLB_FLUSH_VVMA, source_hart);
ret = sbi_tlb_request(args[0], args[1], &tlb_info); ret = sbi_tlb_request(args[0], args[1], &tlb_info);
break; break;
case SBI_EXT_RFENCE_REMOTE_HFENCE_VVMA_ASID: case SBI_EXT_RFENCE_REMOTE_HFENCE_VVMA_ASID:
SBI_TLB_INFO_INIT(&tlb_info, args[2], args[3], args[4], 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); SBI_TLB_FLUSH_VVMA_ASID, source_hart);
ret = sbi_tlb_request(args[0], args[1], &tlb_info); ret = sbi_tlb_request(args[0], args[1], &tlb_info);
break; break;
case SBI_EXT_RFENCE_REMOTE_SFENCE_VMA: case SBI_EXT_RFENCE_REMOTE_SFENCE_VMA:
SBI_TLB_INFO_INIT(&tlb_info, args[2], args[3], 0, SBI_TLB_INFO_INIT(&tlb_info, args[2], args[3], 0, 0,
SBI_TLB_FLUSH_VMA, source_hart); SBI_TLB_FLUSH_VMA, source_hart);
ret = sbi_tlb_request(args[0], args[1], &tlb_info); ret = sbi_tlb_request(args[0], args[1], &tlb_info);
break; break;
case SBI_EXT_RFENCE_REMOTE_SFENCE_VMA_ASID: case SBI_EXT_RFENCE_REMOTE_SFENCE_VMA_ASID:
SBI_TLB_INFO_INIT(&tlb_info, args[2], args[3], args[4], SBI_TLB_INFO_INIT(&tlb_info, args[2], args[3], args[4], 0,
SBI_TLB_FLUSH_VMA_ASID, source_hart); SBI_TLB_FLUSH_VMA_ASID, source_hart);
ret = sbi_tlb_request(args[0], args[1], &tlb_info); ret = sbi_tlb_request(args[0], args[1], &tlb_info);
break; break;

View File

@@ -11,8 +11,8 @@
#include <sbi/sbi_trap.h> #include <sbi/sbi_trap.h>
/* /*
* We assume that faulting unpriv load/store instruction is * We assume that faulting instruction is is 4-byte long and blindly
* is 4-byte long and blindly increment SEPC by 4. * increment SEPC by 4.
* *
* The trap info will be saved as follows: * The trap info will be saved as follows:
* A3 <- pointer struct sbi_trap_info * A3 <- pointer struct sbi_trap_info
@@ -20,8 +20,8 @@
*/ */
.align 3 .align 3
.global __sbi_unpriv_trap .global __sbi_expected_trap
__sbi_unpriv_trap: __sbi_expected_trap:
/* Without H-extension so, MTVAL2 and MTINST CSRs not available */ /* Without H-extension so, MTVAL2 and MTINST CSRs not available */
csrr a4, CSR_MEPC csrr a4, CSR_MEPC
REG_S a4, SBI_TRAP_INFO_OFFSET(epc)(a3) REG_S a4, SBI_TRAP_INFO_OFFSET(epc)(a3)
@@ -37,8 +37,8 @@ __sbi_unpriv_trap:
mret mret
.align 3 .align 3
.global __sbi_unpriv_trap_hext .global __sbi_expected_trap_hext
__sbi_unpriv_trap_hext: __sbi_expected_trap_hext:
/* With H-extension so, MTVAL2 and MTINST CSRs available */ /* With H-extension so, MTVAL2 and MTINST CSRs available */
csrr a4, CSR_MEPC csrr a4, CSR_MEPC
REG_S a4, SBI_TRAP_INFO_OFFSET(epc)(a3) REG_S a4, SBI_TRAP_INFO_OFFSET(epc)(a3)

View File

@@ -13,18 +13,26 @@
#include <sbi/riscv_fp.h> #include <sbi/riscv_fp.h>
#include <sbi/sbi_bitops.h> #include <sbi/sbi_bitops.h>
#include <sbi/sbi_console.h> #include <sbi/sbi_console.h>
#include <sbi/sbi_csr_detect.h>
#include <sbi/sbi_error.h> #include <sbi/sbi_error.h>
#include <sbi/sbi_hart.h> #include <sbi/sbi_hart.h>
#include <sbi/sbi_math.h>
#include <sbi/sbi_platform.h> #include <sbi/sbi_platform.h>
#include <sbi/sbi_string.h>
extern void __sbi_unpriv_trap(void); extern void __sbi_expected_trap(void);
extern void __sbi_unpriv_trap_hext(void); extern void __sbi_expected_trap_hext(void);
void (*sbi_hart_unpriv_trap)(void) = &__sbi_unpriv_trap; 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) static void mstatus_init(struct sbi_scratch *scratch, u32 hartid)
{ {
const struct sbi_platform *plat = sbi_platform_ptr(scratch);
unsigned long mstatus_val = 0; unsigned long mstatus_val = 0;
/* Enable FPU */ /* Enable FPU */
@@ -38,9 +46,10 @@ static void mstatus_init(struct sbi_scratch *scratch, u32 hartid)
csr_write(CSR_MSTATUS, mstatus_val); csr_write(CSR_MSTATUS, mstatus_val);
/* Enable user/supervisor use of perf counters */ /* 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); 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); csr_write(CSR_MCOUNTEREN, -1);
/* Disable all interrupts */ /* Disable all interrupts */
@@ -101,6 +110,7 @@ static int delegate_traps(struct sbi_scratch *scratch, u32 hartid)
exceptions |= (1U << CAUSE_SUPERVISOR_ECALL); exceptions |= (1U << CAUSE_SUPERVISOR_ECALL);
exceptions |= (1U << CAUSE_FETCH_GUEST_PAGE_FAULT); exceptions |= (1U << CAUSE_FETCH_GUEST_PAGE_FAULT);
exceptions |= (1U << CAUSE_LOAD_GUEST_PAGE_FAULT); exceptions |= (1U << CAUSE_LOAD_GUEST_PAGE_FAULT);
exceptions |= (1U << CAUSE_VIRTUAL_INST_FAULT);
exceptions |= (1U << CAUSE_STORE_GUEST_PAGE_FAULT); exceptions |= (1U << CAUSE_STORE_GUEST_PAGE_FAULT);
} }
@@ -112,6 +122,10 @@ static int delegate_traps(struct sbi_scratch *scratch, u32 hartid)
void sbi_hart_delegation_dump(struct sbi_scratch *scratch) void sbi_hart_delegation_dump(struct sbi_scratch *scratch)
{ {
if (!misa_extension('S'))
/* No delegation possible as mideleg does not exist*/
return;
#if __riscv_xlen == 32 #if __riscv_xlen == 32
sbi_printf("MIDELEG : 0x%08lx\n", csr_read(CSR_MIDELEG)); sbi_printf("MIDELEG : 0x%08lx\n", csr_read(CSR_MIDELEG));
sbi_printf("MEDELEG : 0x%08lx\n", csr_read(CSR_MEDELEG)); sbi_printf("MEDELEG : 0x%08lx\n", csr_read(CSR_MEDELEG));
@@ -121,29 +135,34 @@ void sbi_hart_delegation_dump(struct sbi_scratch *scratch)
#endif #endif
} }
unsigned long log2roundup(unsigned long x) unsigned int sbi_hart_pmp_count(struct sbi_scratch *scratch)
{ {
unsigned long ret = 0; struct hart_features *hfeatures =
sbi_scratch_offset_ptr(scratch, hart_features_offset);
while (ret < __riscv_xlen) { return hfeatures->pmp_count;
if (x <= (1UL << ret)) }
break;
ret++;
}
return ret; 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) void sbi_hart_pmp_dump(struct sbi_scratch *scratch)
{ {
const struct sbi_platform *plat = sbi_platform_ptr(scratch);
unsigned long prot, addr, size; unsigned long prot, addr, size;
unsigned int i; unsigned int i, pmp_count;
if (!sbi_platform_has_pmp(plat)) if (!sbi_hart_has_feature(scratch, SBI_HART_HAS_PMP))
return; return;
for (i = 0; i < PMP_COUNT; i++) { pmp_count = sbi_hart_pmp_count(scratch);
for (i = 0; i < pmp_count; i++) {
pmp_get(i, &prot, &addr, &size); pmp_get(i, &prot, &addr, &size);
if (!(prot & PMP_A)) if (!(prot & PMP_A))
continue; continue;
@@ -168,19 +187,20 @@ void sbi_hart_pmp_dump(struct sbi_scratch *scratch)
int sbi_hart_pmp_check_addr(struct sbi_scratch *scratch, unsigned long addr, int sbi_hart_pmp_check_addr(struct sbi_scratch *scratch, unsigned long addr,
unsigned long attr) unsigned long attr)
{ {
unsigned long prot, size, i, tempaddr; unsigned long prot, size, tempaddr;
const struct sbi_platform *plat = sbi_platform_ptr(scratch); unsigned int i, pmp_count;
if (!sbi_platform_has_pmp(plat)) if (!sbi_hart_has_feature(scratch, SBI_HART_HAS_PMP))
return SBI_OK; return SBI_OK;
for (i = 0; i < PMP_COUNT; i++) { pmp_count = sbi_hart_pmp_count(scratch);
for (i = 0; i < pmp_count; i++) {
pmp_get(i, &prot, &tempaddr, &size); pmp_get(i, &prot, &tempaddr, &size);
if (!(prot & PMP_A)) if (!(prot & PMP_A))
continue; continue;
if (tempaddr <= addr && addr <= tempaddr + size) if (tempaddr <= addr && addr <= tempaddr + size)
if (!(prot & attr)) if (!(prot & attr))
return SBI_INVALID_ADDR; return SBI_EINVALID_ADDR;
} }
return SBI_OK; return SBI_OK;
@@ -188,42 +208,219 @@ int sbi_hart_pmp_check_addr(struct sbi_scratch *scratch, unsigned long addr,
static int pmp_init(struct sbi_scratch *scratch, u32 hartid) 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; unsigned long fw_start, fw_size_log2;
ulong prot, addr, log2size; ulong prot, addr, log2size;
const struct sbi_platform *plat = sbi_platform_ptr(scratch); const struct sbi_platform *plat = sbi_platform_ptr(scratch);
if (!sbi_platform_has_pmp(plat)) if (!sbi_hart_has_feature(scratch, SBI_HART_HAS_PMP))
return 0; return 0;
/* Firmware PMP region to protect OpenSBI firmware */
fw_size_log2 = log2roundup(scratch->fw_size); fw_size_log2 = log2roundup(scratch->fw_size);
fw_start = scratch->fw_start & ~((1UL << fw_size_log2) - 1UL); fw_start = scratch->fw_start & ~((1UL << fw_size_log2) - 1UL);
pmp_set(pmp_idx++, 0, fw_start, fw_size_log2);
pmp_set(0, 0, fw_start, fw_size_log2);
/* Platform specific PMP regions */
count = sbi_platform_pmp_region_count(plat, hartid); count = sbi_platform_pmp_region_count(plat, hartid);
if ((PMP_COUNT - 1) < count) pmp_count = sbi_hart_pmp_count(scratch);
count = (PMP_COUNT - 1); for (i = 0; i < count && pmp_idx < (pmp_count - 1); i++) {
for (i = 0; i < count; i++) {
if (sbi_platform_pmp_region_info(plat, hartid, i, &prot, &addr, if (sbi_platform_pmp_region_info(plat, hartid, i, &prot, &addr,
&log2size)) &log2size))
continue; 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; return 0;
} }
/**
* 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 sbi_hart_init(struct sbi_scratch *scratch, u32 hartid, bool cold_boot)
{ {
int rc; int rc;
if (cold_boot) { if (cold_boot) {
if (misa_extension('H')) if (misa_extension('H'))
sbi_hart_unpriv_trap = &__sbi_unpriv_trap_hext; 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); mstatus_init(scratch, hartid);
rc = fp_init(hartid); rc = fp_init(hartid);

View File

@@ -9,67 +9,127 @@
*/ */
/* /*
* Instruction encoding of hfence.gvma is: * 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 * 0110001 rs2(5) rs1(5) 000 00000 1110011
*/ */
.align 3 .align 3
.global __sbi_hfence_gvma_vmid_gpa .global __sbi_hfence_gvma_vmid_gpa
__sbi_hfence_gvma_vmid_gpa: __sbi_hfence_gvma_vmid_gpa:
/* hfence.gvma a1, a0 */ /*
.word 0x62a60073 * rs1 = a0 (GPA)
* rs2 = a1 (VMID)
* HFENCE.GVMA a0, a1
* 0110001 01011 01010 000 00000 1110011
*/
.word 0x62b50073
ret ret
.align 3 .align 3
.global __sbi_hfence_gvma_vmid .global __sbi_hfence_gvma_vmid
__sbi_hfence_gvma_vmid: __sbi_hfence_gvma_vmid:
/* hfence.gvma zero, a0 */ /*
* rs1 = zero
* rs2 = a0 (VMID)
* HFENCE.GVMA zero, a0
* 0110001 01010 00000 000 00000 1110011
*/
.word 0x62a00073 .word 0x62a00073
ret ret
.align 3 .align 3
.global __sbi_hfence_gvma_gpa .global __sbi_hfence_gvma_gpa
__sbi_hfence_gvma_gpa: __sbi_hfence_gvma_gpa:
/* hfence.gvma a0 */ /*
* rs1 = a0 (GPA)
* rs2 = zero
* HFENCE.GVMA a0
* 0110001 00000 01010 000 00000 1110011
*/
.word 0x62050073 .word 0x62050073
ret ret
.align 3 .align 3
.global __sbi_hfence_gvma_all .global __sbi_hfence_gvma_all
__sbi_hfence_gvma_all: __sbi_hfence_gvma_all:
/* hfence.gvma */ /*
* rs1 = zero
* rs2 = zero
* HFENCE.GVMA
* 0110001 00000 00000 000 00000 1110011
*/
.word 0x62000073 .word 0x62000073
ret ret
/* /*
* Instruction encoding of hfence.bvma is: * 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 * 0010001 rs2(5) rs1(5) 000 00000 1110011
*/ */
.align 3 .align 3
.global __sbi_hfence_vvma_asid_va .global __sbi_hfence_vvma_asid_va
__sbi_hfence_vvma_asid_va: __sbi_hfence_vvma_asid_va:
/* hfence.bvma a1, a0 */ /*
.word 0x22a60073 * rs1 = a0 (VA)
* rs2 = a1 (ASID)
* HFENCE.VVMA a0, a1
* 0010001 01011 01010 000 00000 1110011
*/
.word 0x22b50073
ret ret
.align 3 .align 3
.global __sbi_hfence_vvma_asid .global __sbi_hfence_vvma_asid
__sbi_hfence_vvma_asid: __sbi_hfence_vvma_asid:
/* hfence.bvma zero, a0 */ /*
* rs1 = zero
* rs2 = a0 (ASID)
* HFENCE.VVMA zero, a0
* 0010001 01010 00000 000 00000 1110011
*/
.word 0x22a00073 .word 0x22a00073
ret ret
.align 3 .align 3
.global __sbi_hfence_vvma_va .global __sbi_hfence_vvma_va
__sbi_hfence_vvma_va: __sbi_hfence_vvma_va:
/* hfence.bvma a0 */ /*
* rs1 = a0 (VA)
* rs2 = zero
* HFENCE.VVMA zero, a0
* 0010001 00000 01010 000 00000 1110011
*/
.word 0x22050073 .word 0x22050073
ret ret
.align 3 .align 3
.global __sbi_hfence_vvma_all .global __sbi_hfence_vvma_all
__sbi_hfence_vvma_all: __sbi_hfence_vvma_all:
/* hfence.bvma */ /*
* rs1 = zero
* rs2 = zero
* HFENCE.VVMA
* 0010001 00000 00000 000 00000 1110011
*/
.word 0x22000073 .word 0x22000073
ret ret

View File

@@ -219,7 +219,7 @@ int sbi_hsm_hart_start(struct sbi_scratch *scratch, u32 hartid,
hstate = atomic_cmpxchg(&hdata->state, SBI_HART_STOPPED, hstate = atomic_cmpxchg(&hdata->state, SBI_HART_STOPPED,
SBI_HART_STARTING); SBI_HART_STARTING);
if (hstate == SBI_HART_STARTED) if (hstate == SBI_HART_STARTED)
return SBI_EALREADY_STARTED; return SBI_EALREADY;
/** /**
* if a hart is already transition to start or stop, another start call * if a hart is already transition to start or stop, another start call
@@ -263,7 +263,7 @@ int sbi_hsm_hart_stop(struct sbi_scratch *scratch, bool exitnow)
if (oldstate != SBI_HART_STARTED) { if (oldstate != SBI_HART_STARTED) {
sbi_printf("%s: ERR: The hart is in invalid state [%u]\n", sbi_printf("%s: ERR: The hart is in invalid state [%u]\n",
__func__, oldstate); __func__, oldstate);
return SBI_DENIED; return SBI_EDENIED;
} }
if (exitnow) if (exitnow)

View File

@@ -38,17 +38,7 @@ static int system_opcode_insn(ulong insn, struct sbi_trap_regs *regs)
int csr_num = (u32)insn >> 20; int csr_num = (u32)insn >> 20;
ulong csr_val, new_csr_val; ulong csr_val, new_csr_val;
/* /* TODO: Ensure that we got CSR read/write instruction */
* WFI always traps as illegal instruction when executed from
* VS/VU mode so we just forward it to HS-mode.
*/
#if __riscv_xlen == 32
if ((regs->mstatusH & MSTATUSH_MPV) &&
#else
if ((regs->mstatus & MSTATUS_MPV) &&
#endif
(insn & INSN_MASK_WFI) == INSN_MATCH_WFI)
return truly_illegal_insn(insn, regs);
if (sbi_emulate_csr_read(csr_num, regs, &csr_val)) if (sbi_emulate_csr_read(csr_num, regs, &csr_val))
return truly_illegal_insn(insn, regs); return truly_illegal_insn(insn, regs);

View File

@@ -18,6 +18,7 @@
#include <sbi/sbi_ipi.h> #include <sbi/sbi_ipi.h>
#include <sbi/sbi_platform.h> #include <sbi/sbi_platform.h>
#include <sbi/sbi_system.h> #include <sbi/sbi_system.h>
#include <sbi/sbi_string.h>
#include <sbi/sbi_timer.h> #include <sbi/sbi_timer.h>
#include <sbi/sbi_tlb.h> #include <sbi/sbi_tlb.h>
#include <sbi/sbi_version.h> #include <sbi/sbi_version.h>
@@ -35,7 +36,7 @@
static void sbi_boot_prints(struct sbi_scratch *scratch, u32 hartid) static void sbi_boot_prints(struct sbi_scratch *scratch, u32 hartid)
{ {
int xlen; int xlen;
char str[64]; char str[128];
const struct sbi_platform *plat = sbi_platform_ptr(scratch); const struct sbi_platform *plat = sbi_platform_ptr(scratch);
#ifdef OPENSBI_VERSION_GIT #ifdef OPENSBI_VERSION_GIT
@@ -53,19 +54,29 @@ static void sbi_boot_prints(struct sbi_scratch *scratch, u32 hartid)
sbi_printf("Error %d getting MISA XLEN\n", xlen); sbi_printf("Error %d getting MISA XLEN\n", xlen);
sbi_hart_hang(); sbi_hart_hang();
} }
xlen = 16 * (1 << xlen);
misa_string(str, sizeof(str));
/* Platform details */ /* Platform details */
sbi_printf("Platform Name : %s\n", sbi_platform_name(plat)); sbi_printf("Platform Name : %s\n", sbi_platform_name(plat));
sbi_printf("Platform HART Features : RV%d%s\n", xlen, str); sbi_platform_get_features_str(plat, str, sizeof(str));
sbi_printf("Current Hart : %u\n", hartid); sbi_printf("Platform Features : %s\n", str);
sbi_printf("Platform HART Count : %u\n",
sbi_platform_hart_count(plat));
/* 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 */ /* Firmware details */
sbi_printf("Firmware Base : 0x%lx\n", scratch->fw_start); sbi_printf("Firmware Base : 0x%lx\n", scratch->fw_start);
sbi_printf("Firmware Size : %d KB\n", sbi_printf("Firmware Size : %d KB\n",
(u32)(scratch->fw_size / 1024)); (u32)(scratch->fw_size / 1024));
/* Generic details */ /* 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_ecall_version_major(), sbi_ecall_version_minor());
sbi_printf("\n"); sbi_printf("\n");

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;
}

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

@@ -17,7 +17,7 @@
#include <sbi/sbi_ipi.h> #include <sbi/sbi_ipi.h>
#include <sbi/sbi_init.h> #include <sbi/sbi_init.h>
void __noreturn sbi_system_reboot(u32 type) void __noreturn sbi_system_reset(u32 platform_reset_type)
{ {
ulong hbase = 0, hmask; ulong hbase = 0, hmask;
u32 cur_hartid = current_hartid(); u32 cur_hartid = current_hartid();
@@ -35,34 +35,10 @@ void __noreturn sbi_system_reboot(u32 type)
/* Stop current HART */ /* Stop current HART */
sbi_hsm_hart_stop(scratch, FALSE); sbi_hsm_hart_stop(scratch, FALSE);
/* Platform specific reooot */ /* Platform specific reset */
sbi_platform_system_reboot(sbi_platform_ptr(scratch), type); sbi_platform_system_reset(sbi_platform_ptr(scratch),
platform_reset_type);
/* If platform specific reboot did not work then do sbi_exit() */ /* If platform specific reset did not work then do sbi_exit() */
sbi_exit(scratch);
}
void __noreturn sbi_system_shutdown(u32 type)
{
ulong hbase = 0, hmask;
u32 cur_hartid = current_hartid();
struct sbi_scratch *scratch = sbi_scratch_thishart_ptr();
/* Send HALT IPI to every hart other than the current hart */
while (!sbi_hsm_hart_started_mask(hbase, &hmask)) {
if (hbase <= cur_hartid)
hmask &= ~(1UL << (cur_hartid - hbase));
if (hmask)
sbi_ipi_send_halt(hmask, hbase);
hbase += BITS_PER_LONG;
}
/* Stop current HART */
sbi_hsm_hart_stop(scratch, FALSE);
/* Platform specific shutdown */
sbi_platform_system_shutdown(sbi_platform_ptr(scratch), type);
/* If platform specific shutdown did not work then do sbi_exit() */
sbi_exit(scratch); sbi_exit(scratch);
} }

View File

@@ -10,14 +10,16 @@
#include <sbi/riscv_asm.h> #include <sbi/riscv_asm.h>
#include <sbi/riscv_encoding.h> #include <sbi/riscv_encoding.h>
#include <sbi/sbi_error.h> #include <sbi/sbi_error.h>
#include <sbi/sbi_hart.h>
#include <sbi/sbi_platform.h> #include <sbi/sbi_platform.h>
#include <sbi/sbi_scratch.h> #include <sbi/sbi_scratch.h>
#include <sbi/sbi_timer.h> #include <sbi/sbi_timer.h>
static unsigned long time_delta_off; static unsigned long time_delta_off;
static u64 (*get_time_val)(const struct sbi_platform *plat);
#if __riscv_xlen == 32 #if __riscv_xlen == 32
u64 get_ticks(void) static u64 get_ticks(const struct sbi_platform *plat)
{ {
u32 lo, hi, tmp; u32 lo, hi, tmp;
__asm__ __volatile__("1:\n" __asm__ __volatile__("1:\n"
@@ -29,7 +31,7 @@ u64 get_ticks(void)
return ((u64)hi << 32) | lo; return ((u64)hi << 32) | lo;
} }
#else #else
u64 get_ticks(void) static u64 get_ticks(const struct sbi_platform *plat)
{ {
unsigned long n; unsigned long n;
@@ -40,12 +42,7 @@ u64 get_ticks(void)
u64 sbi_timer_value(void) u64 sbi_timer_value(void)
{ {
const struct sbi_platform *plat = sbi_platform_thishart_ptr(); return get_time_val(sbi_platform_thishart_ptr());
if (sbi_platform_has_timer_value(plat))
return sbi_platform_timer_value(plat);
else
return get_ticks();
} }
u64 sbi_timer_virt_value(void) u64 sbi_timer_virt_value(void)
@@ -97,6 +94,8 @@ void sbi_timer_process(void)
int sbi_timer_init(struct sbi_scratch *scratch, bool cold_boot) int sbi_timer_init(struct sbi_scratch *scratch, bool cold_boot)
{ {
u64 *time_delta; u64 *time_delta;
const struct sbi_platform *plat = sbi_platform_ptr(scratch);
int ret;
if (cold_boot) { if (cold_boot) {
time_delta_off = sbi_scratch_alloc_offset(sizeof(*time_delta), time_delta_off = sbi_scratch_alloc_offset(sizeof(*time_delta),
@@ -111,7 +110,19 @@ int sbi_timer_init(struct sbi_scratch *scratch, bool cold_boot)
time_delta = sbi_scratch_offset_ptr(scratch, time_delta_off); time_delta = sbi_scratch_offset_ptr(scratch, time_delta_off);
*time_delta = 0; *time_delta = 0;
return sbi_platform_timer_init(sbi_platform_ptr(scratch), cold_boot); ret = sbi_platform_timer_init(plat, cold_boot);
if (ret)
return ret;
if (sbi_hart_has_feature(scratch, SBI_HART_HAS_TIME))
get_time_val = get_ticks;
else if (sbi_platform_has_timer_value(plat))
get_time_val = sbi_platform_timer_value;
else
/* There is no method to provide timer value */
return SBI_ENODEV;
return 0;
} }
void sbi_timer_exit(struct sbi_scratch *scratch) void sbi_timer_exit(struct sbi_scratch *scratch)

View File

@@ -36,16 +36,23 @@ static void sbi_tlb_hfence_vvma(struct sbi_tlb_info *tinfo)
{ {
unsigned long start = tinfo->start; unsigned long start = tinfo->start;
unsigned long size = tinfo->size; unsigned long size = tinfo->size;
unsigned long i; unsigned long vmid = tinfo->vmid;
unsigned long i, hgatp;
hgatp = csr_swap(CSR_HGATP,
(vmid << HGATP_VMID_SHIFT) & HGATP_VMID_MASK);
if ((start == 0 && size == 0) || (size == SBI_TLB_FLUSH_ALL)) { if ((start == 0 && size == 0) || (size == SBI_TLB_FLUSH_ALL)) {
__sbi_hfence_vvma_all(); __sbi_hfence_vvma_all();
return; goto done;
} }
for (i = 0; i < size; i += PAGE_SIZE) { for (i = 0; i < size; i += PAGE_SIZE) {
__sbi_hfence_vvma_va(start+i); __sbi_hfence_vvma_va(start+i);
} }
done:
csr_write(CSR_HGATP, hgatp);
} }
static void sbi_tlb_hfence_gvma(struct sbi_tlb_info *tinfo) static void sbi_tlb_hfence_gvma(struct sbi_tlb_info *tinfo)
@@ -88,28 +95,35 @@ static void sbi_tlb_hfence_vvma_asid(struct sbi_tlb_info *tinfo)
unsigned long start = tinfo->start; unsigned long start = tinfo->start;
unsigned long size = tinfo->size; unsigned long size = tinfo->size;
unsigned long asid = tinfo->asid; unsigned long asid = tinfo->asid;
unsigned long i; unsigned long vmid = tinfo->vmid;
unsigned long i, hgatp;
hgatp = csr_swap(CSR_HGATP,
(vmid << HGATP_VMID_SHIFT) & HGATP_VMID_MASK);
if (start == 0 && size == 0) { if (start == 0 && size == 0) {
__sbi_hfence_vvma_all(); __sbi_hfence_vvma_all();
return; goto done;
} }
if (size == SBI_TLB_FLUSH_ALL) { if (size == SBI_TLB_FLUSH_ALL) {
__sbi_hfence_vvma_asid(asid); __sbi_hfence_vvma_asid(asid);
return; goto done;
} }
for (i = 0; i < size; i += PAGE_SIZE) { for (i = 0; i < size; i += PAGE_SIZE) {
__sbi_hfence_vvma_asid_va(asid, start + i); __sbi_hfence_vvma_asid_va(start + i, asid);
} }
done:
csr_write(CSR_HGATP, hgatp);
} }
static void sbi_tlb_hfence_gvma_vmid(struct sbi_tlb_info *tinfo) static void sbi_tlb_hfence_gvma_vmid(struct sbi_tlb_info *tinfo)
{ {
unsigned long start = tinfo->start; unsigned long start = tinfo->start;
unsigned long size = tinfo->size; unsigned long size = tinfo->size;
unsigned long vmid = tinfo->asid; unsigned long vmid = tinfo->vmid;
unsigned long i; unsigned long i;
if (start == 0 && size == 0) { if (start == 0 && size == 0) {
@@ -123,7 +137,7 @@ static void sbi_tlb_hfence_gvma_vmid(struct sbi_tlb_info *tinfo)
} }
for (i = 0; i < size; i += PAGE_SIZE) { for (i = 0; i < size; i += PAGE_SIZE) {
__sbi_hfence_gvma_vmid_gpa(vmid, start+i); __sbi_hfence_gvma_vmid_gpa(start + i, vmid);
} }
} }

View File

@@ -120,12 +120,10 @@ int sbi_trap_redirect(struct sbi_trap_regs *regs,
/* Update HSTATUS for VS/VU-mode to HS-mode transition */ /* Update HSTATUS for VS/VU-mode to HS-mode transition */
if (misa_extension('H') && prev_virt && !next_virt) { if (misa_extension('H') && prev_virt && !next_virt) {
/* Update HSTATUS SP2P, SP2V, and SPV bits */ /* Update HSTATUS SPVP and SPV bits */
hstatus = csr_read(CSR_HSTATUS); hstatus = csr_read(CSR_HSTATUS);
hstatus &= ~HSTATUS_SP2P; hstatus &= ~HSTATUS_SPVP;
hstatus |= (regs->mstatus & MSTATUS_SPP) ? HSTATUS_SP2P : 0; hstatus |= (regs->mstatus & MSTATUS_SPP) ? HSTATUS_SPVP : 0;
hstatus &= ~HSTATUS_SP2V;
hstatus |= (hstatus & HSTATUS_SPV) ? HSTATUS_SP2V : 0;
hstatus &= ~HSTATUS_SPV; hstatus &= ~HSTATUS_SPV;
hstatus |= (prev_virt) ? HSTATUS_SPV : 0; hstatus |= (prev_virt) ? HSTATUS_SPV : 0;
csr_write(CSR_HSTATUS, hstatus); csr_write(CSR_HSTATUS, hstatus);

View File

@@ -14,19 +14,21 @@
#include <sbi/sbi_trap.h> #include <sbi/sbi_trap.h>
#include <sbi/sbi_unpriv.h> #include <sbi/sbi_unpriv.h>
/**
* a3 must a pointer to the sbi_trap_info and a4 is used as a temporary
* register in the trap handler. Make sure that compiler doesn't use a3 & a4.
*/
#define DEFINE_UNPRIVILEGED_LOAD_FUNCTION(type, insn) \ #define DEFINE_UNPRIVILEGED_LOAD_FUNCTION(type, insn) \
type sbi_load_##type(const type *addr, \ type sbi_load_##type(const type *addr, \
struct sbi_trap_info *trap) \ struct sbi_trap_info *trap) \
{ \ { \
register ulong tinfo asm("a3"); \ register ulong tinfo asm("a3"); \
register ulong ttmp asm("a4"); \ register ulong mstatus = 0; \
register ulong mstatus asm("a5"); \ register ulong mtvec = sbi_hart_expected_trap_addr(); \
register ulong mtvec asm("a6") = sbi_hart_unpriv_trap_addr(); \
type ret = 0; \ type ret = 0; \
trap->cause = 0; \ trap->cause = 0; \
asm volatile( \ asm volatile( \
"add %[tinfo], %[taddr], zero\n" \ "add %[tinfo], %[taddr], zero\n" \
"add %[ttmp], %[taddr], zero\n" \
"csrrw %[mtvec], " STR(CSR_MTVEC) ", %[mtvec]\n" \ "csrrw %[mtvec], " STR(CSR_MTVEC) ", %[mtvec]\n" \
"csrrs %[mstatus], " STR(CSR_MSTATUS) ", %[mprv]\n" \ "csrrs %[mstatus], " STR(CSR_MSTATUS) ", %[mprv]\n" \
".option push\n" \ ".option push\n" \
@@ -36,11 +38,10 @@
"csrw " STR(CSR_MSTATUS) ", %[mstatus]\n" \ "csrw " STR(CSR_MSTATUS) ", %[mstatus]\n" \
"csrw " STR(CSR_MTVEC) ", %[mtvec]" \ "csrw " STR(CSR_MTVEC) ", %[mtvec]" \
: [mstatus] "+&r"(mstatus), [mtvec] "+&r"(mtvec), \ : [mstatus] "+&r"(mstatus), [mtvec] "+&r"(mtvec), \
[tinfo] "+&r"(tinfo), [ttmp] "+&r"(ttmp), \ [tinfo] "+&r"(tinfo), [ret] "=&r"(ret) \
[ret] "=&r"(ret) \
: [addr] "m"(*addr), [mprv] "r"(MSTATUS_MPRV), \ : [addr] "m"(*addr), [mprv] "r"(MSTATUS_MPRV), \
[taddr] "r"((ulong)trap) \ [taddr] "r"((ulong)trap) \
: "memory"); \ : "a4", "memory"); \
return ret; \ return ret; \
} }
@@ -48,14 +49,12 @@
void sbi_store_##type(type *addr, type val, \ void sbi_store_##type(type *addr, type val, \
struct sbi_trap_info *trap) \ struct sbi_trap_info *trap) \
{ \ { \
register ulong tinfo asm("a3"); \ register ulong tinfo asm("a3") = (ulong)trap; \
register ulong ttmp asm("a4"); \ register ulong mstatus = 0; \
register ulong mstatus asm("a5"); \ register ulong mtvec = sbi_hart_expected_trap_addr(); \
register ulong mtvec asm("a6") = sbi_hart_unpriv_trap_addr(); \
trap->cause = 0; \ trap->cause = 0; \
asm volatile( \ asm volatile( \
"add %[tinfo], %[taddr], zero\n" \ "add %[tinfo], %[taddr], zero\n" \
"add %[ttmp], %[taddr], zero\n" \
"csrrw %[mtvec], " STR(CSR_MTVEC) ", %[mtvec]\n" \ "csrrw %[mtvec], " STR(CSR_MTVEC) ", %[mtvec]\n" \
"csrrs %[mstatus], " STR(CSR_MSTATUS) ", %[mprv]\n" \ "csrrs %[mstatus], " STR(CSR_MSTATUS) ", %[mprv]\n" \
".option push\n" \ ".option push\n" \
@@ -65,10 +64,10 @@
"csrw " STR(CSR_MSTATUS) ", %[mstatus]\n" \ "csrw " STR(CSR_MSTATUS) ", %[mstatus]\n" \
"csrw " STR(CSR_MTVEC) ", %[mtvec]" \ "csrw " STR(CSR_MTVEC) ", %[mtvec]" \
: [mstatus] "+&r"(mstatus), [mtvec] "+&r"(mtvec), \ : [mstatus] "+&r"(mstatus), [mtvec] "+&r"(mtvec), \
[tinfo] "+&r"(tinfo), [ttmp] "+&r"(ttmp) \ [tinfo] "+&r"(tinfo) \
: [addr] "m"(*addr), [mprv] "r"(MSTATUS_MPRV), \ : [addr] "m"(*addr), [mprv] "r"(MSTATUS_MPRV), \
[taddr] "r"((ulong)trap), [val] "r"(val) \ [val] "r"(val), [taddr] "r"((ulong)trap) \
: "memory"); \ : "a4", "memory"); \
} }
DEFINE_UNPRIVILEGED_LOAD_FUNCTION(u8, lbu) DEFINE_UNPRIVILEGED_LOAD_FUNCTION(u8, lbu)
@@ -119,8 +118,8 @@ ulong sbi_get_insn(ulong mepc, struct sbi_trap_info *trap)
{ {
register ulong tinfo asm("a3"); register ulong tinfo asm("a3");
register ulong ttmp asm("a4"); register ulong ttmp asm("a4");
register ulong mstatus asm("a5"); register ulong mstatus = 0;
register ulong mtvec asm("a6") = sbi_hart_unpriv_trap_addr(); register ulong mtvec = sbi_hart_expected_trap_addr();
ulong insn = 0; ulong insn = 0;
trap->cause = 0; trap->cause = 0;

View File

@@ -8,19 +8,20 @@
*/ */
#include <libfdt.h> #include <libfdt.h>
#include <sbi/riscv_asm.h>
#include <sbi/sbi_console.h> #include <sbi/sbi_console.h>
#include <sbi/sbi_math.h>
#include <sbi/sbi_hart.h>
#include <sbi/sbi_platform.h> #include <sbi/sbi_platform.h>
#include <sbi/sbi_scratch.h> #include <sbi/sbi_scratch.h>
#include <sbi/sbi_string.h> #include <sbi/sbi_string.h>
#include <sbi_utils/fdt/fdt_fixup.h>
#include <sbi_utils/fdt/fdt_helper.h>
void fdt_cpu_fixup(void *fdt) void fdt_cpu_fixup(void *fdt)
{ {
struct sbi_scratch *scratch = sbi_scratch_thishart_ptr(); struct sbi_scratch *scratch = sbi_scratch_thishart_ptr();
const struct sbi_platform *plat = sbi_platform_ptr(scratch); const struct sbi_platform *plat = sbi_platform_ptr(scratch);
int err, len, cpu_offset, cpus_offset; int err, cpu_offset, cpus_offset;
const fdt32_t *val;
const void *prop;
u32 hartid; u32 hartid;
err = fdt_open_into(fdt, fdt, fdt_totalsize(fdt) + 32); err = fdt_open_into(fdt, fdt, fdt_totalsize(fdt) + 32);
@@ -32,19 +33,9 @@ void fdt_cpu_fixup(void *fdt)
return; return;
fdt_for_each_subnode(cpu_offset, fdt, cpus_offset) { fdt_for_each_subnode(cpu_offset, fdt, cpus_offset) {
prop = fdt_getprop(fdt, cpu_offset, "device_type", &len); err = fdt_parse_hart_id(fdt, cpu_offset, &hartid);
if (!prop || !len) if (err)
continue; continue;
if (sbi_strcmp(prop, "cpu"))
continue;
val = fdt_getprop(fdt, cpu_offset, "reg", &len);
if (!val || len < sizeof(fdt32_t))
continue;
if (len > sizeof(fdt32_t))
val++;
hartid = fdt32_to_cpu(*val);
if (sbi_platform_hart_invalid(plat, hartid)) if (sbi_platform_hart_invalid(plat, hartid))
fdt_setprop_string(fdt, cpu_offset, "status", fdt_setprop_string(fdt, cpu_offset, "status",
@@ -77,6 +68,65 @@ void fdt_plic_fixup(void *fdt, const char *compat)
} }
} }
static int fdt_resv_memory_update_node(void *fdt, unsigned long addr,
unsigned long size, int index,
int parent, bool no_map)
{
int na = fdt_address_cells(fdt, 0);
int ns = fdt_size_cells(fdt, 0);
fdt32_t addr_high, addr_low;
fdt32_t size_high, size_low;
int subnode, err;
fdt32_t reg[4];
fdt32_t *val;
char name[32];
addr_high = (u64)addr >> 32;
addr_low = addr;
size_high = (u64)size >> 32;
size_low = size;
if (na > 1 && addr_high)
sbi_snprintf(name, sizeof(name),
"mmode_pmp%d@%x,%x", index,
addr_high, addr_low);
else
sbi_snprintf(name, sizeof(name),
"mmode_pmp%d@%x", index,
addr_low);
subnode = fdt_add_subnode(fdt, parent, name);
if (subnode < 0)
return subnode;
if (no_map) {
/*
* Tell operating system not to create a virtual
* mapping of the region as part of its standard
* mapping of system memory.
*/
err = fdt_setprop_empty(fdt, subnode, "no-map");
if (err < 0)
return err;
}
/* encode the <reg> property value */
val = reg;
if (na > 1)
*val++ = cpu_to_fdt32(addr_high);
*val++ = cpu_to_fdt32(addr_low);
if (ns > 1)
*val++ = cpu_to_fdt32(size_high);
*val++ = cpu_to_fdt32(size_low);
err = fdt_setprop(fdt, subnode, "reg", reg,
(na + ns) * sizeof(fdt32_t));
if (err < 0)
return err;
return 0;
}
/** /**
* We use PMP to protect OpenSBI firmware to safe-guard it from buggy S-mode * We use PMP to protect OpenSBI firmware to safe-guard it from buggy S-mode
* software, see pmp_init() in lib/sbi/sbi_hart.c. The protected memory region * software, see pmp_init() in lib/sbi/sbi_hart.c. The protected memory region
@@ -95,21 +145,11 @@ void fdt_plic_fixup(void *fdt, const char *compat)
int fdt_reserved_memory_fixup(void *fdt) int fdt_reserved_memory_fixup(void *fdt)
{ {
struct sbi_scratch *scratch = sbi_scratch_thishart_ptr(); struct sbi_scratch *scratch = sbi_scratch_thishart_ptr();
const struct sbi_platform *plat = sbi_platform_ptr(scratch);
unsigned long prot, addr, size; unsigned long prot, addr, size;
int parent, i, j;
int err;
int na = fdt_address_cells(fdt, 0); int na = fdt_address_cells(fdt, 0);
int ns = fdt_size_cells(fdt, 0); int ns = fdt_size_cells(fdt, 0);
fdt32_t addr_high, addr_low;
fdt32_t size_high, size_low;
fdt32_t reg[4];
fdt32_t *val;
char name[32];
int parent, subnode;
int i, j;
int err;
if (!sbi_platform_has_pmp(plat))
return 0;
/* expand the device tree to accommodate new node */ /* expand the device tree to accommodate new node */
err = fdt_open_into(fdt, fdt, fdt_totalsize(fdt) + 256); err = fdt_open_into(fdt, fdt, fdt_totalsize(fdt) + 256);
@@ -153,54 +193,53 @@ int fdt_reserved_memory_fixup(void *fdt)
* With above assumption, we create child nodes directly. * With above assumption, we create child nodes directly.
*/ */
for (i = 0, j = 0; i < PMP_COUNT; i++) { if (!sbi_hart_has_feature(scratch, SBI_HART_HAS_PMP)) {
pmp_get(i, &prot, &addr, &size); /*
* Update the DT with firmware start & size even if PMP is not
* supported. This makes sure that supervisor OS is always
* aware of OpenSBI resident memory area.
*/
addr = scratch->fw_start & ~(scratch->fw_size - 1UL);
size = (1UL << log2roundup(scratch->fw_size));
return fdt_resv_memory_update_node(fdt, addr, size,
0, parent, true);
}
for (i = 0, j = 0; i < sbi_hart_pmp_count(scratch); i++) {
err = sbi_hart_pmp_get(scratch, i, &prot, &addr, &size);
if (err)
continue;
if (!(prot & PMP_A)) if (!(prot & PMP_A))
continue; continue;
if (!(prot & (PMP_R | PMP_W | PMP_X))) { if (prot & (PMP_R | PMP_W | PMP_X))
addr_high = (u64)addr >> 32; continue;
addr_low = addr;
size_high = (u64)size >> 32;
size_low = size;
if (na > 1 && addr_high) fdt_resv_memory_update_node(fdt, addr, size, j, parent, false);
sbi_snprintf(name, sizeof(name), j++;
"mmode_pmp%d@%x,%x", j, }
addr_high, addr_low);
else
sbi_snprintf(name, sizeof(name),
"mmode_pmp%d@%x", j,
addr_low);
subnode = fdt_add_subnode(fdt, parent, name); return 0;
if (subnode < 0) }
return subnode;
/* int fdt_reserved_memory_nomap_fixup(void *fdt)
* Tell operating system not to create a virtual {
* mapping of the region as part of its standard int parent, subnode;
* mapping of system memory. int err;
*/
err = fdt_setprop_empty(fdt, subnode, "no-map");
if (err < 0)
return err;
/* encode the <reg> property value */ /* Locate the reserved memory node */
val = reg; parent = fdt_path_offset(fdt, "/reserved-memory");
if (na > 1) if (parent < 0)
*val++ = cpu_to_fdt32(addr_high); return parent;
*val++ = cpu_to_fdt32(addr_low);
if (ns > 1)
*val++ = cpu_to_fdt32(size_high);
*val++ = cpu_to_fdt32(size_low);
err = fdt_setprop(fdt, subnode, "reg", reg, fdt_for_each_subnode(subnode, fdt, parent) {
(na + ns) * sizeof(fdt32_t)); /*
if (err < 0) * Tell operating system not to create a virtual
return err; * mapping of the region as part of its standard
* mapping of system memory.
j++; */
} err = fdt_setprop_empty(fdt, subnode, "no-map");
if (err < 0)
return err;
} }
return 0; return 0;

View File

@@ -9,12 +9,70 @@
#include <libfdt.h> #include <libfdt.h>
#include <sbi/riscv_asm.h> #include <sbi/riscv_asm.h>
#include <sbi/sbi_console.h> #include <sbi/sbi_console.h>
#include <sbi/sbi_hartmask.h>
#include <sbi/sbi_platform.h> #include <sbi/sbi_platform.h>
#include <sbi/sbi_scratch.h> #include <sbi/sbi_scratch.h>
#include <sbi_utils/fdt/fdt_helper.h> #include <sbi_utils/fdt/fdt_helper.h>
#include <sbi_utils/irqchip/plic.h>
#include <sbi_utils/sys/clint.h>
static int fdt_get_node_addr_size(void *fdt, int node, unsigned long *addr, #define DEFAULT_UART_FREQ 0
unsigned long *size) #define DEFAULT_UART_BAUD 115200
#define DEFAULT_UART_REG_SHIFT 0
#define DEFAULT_UART_REG_IO_WIDTH 1
#define DEFAULT_SIFIVE_UART_FREQ 0
#define DEFAULT_SIFIVE_UART_BAUD 115200
#define DEFAULT_SIFIVE_UART_REG_SHIFT 0
#define DEFAULT_SIFIVE_UART_REG_IO_WIDTH 4
#define DEFAULT_SHAKTI_UART_FREQ 50000000
#define DEFAULT_SHAKTI_UART_BAUD 115200
const struct fdt_match *fdt_match_node(void *fdt, int nodeoff,
const struct fdt_match *match_table)
{
int ret;
if (!fdt || nodeoff < 0 || !match_table)
return NULL;
while (match_table->compatible) {
ret = fdt_node_check_compatible(fdt, nodeoff,
match_table->compatible);
if (!ret)
return match_table;
match_table++;
}
return NULL;
}
int fdt_find_match(void *fdt, int startoff,
const struct fdt_match *match_table,
const struct fdt_match **out_match)
{
int nodeoff;
if (!fdt || !match_table)
return SBI_ENODEV;
while (match_table->compatible) {
nodeoff = fdt_node_offset_by_compatible(fdt, startoff,
match_table->compatible);
if (nodeoff >= 0) {
if (out_match)
*out_match = match_table;
return nodeoff;
}
match_table++;
}
return SBI_ENODEV;
}
int fdt_get_node_addr_size(void *fdt, int node, unsigned long *addr,
unsigned long *size)
{ {
int parent, len, i; int parent, len, i;
int cell_addr, cell_size; int cell_addr, cell_size;
@@ -53,21 +111,71 @@ static int fdt_get_node_addr_size(void *fdt, int node, unsigned long *addr,
return 0; return 0;
} }
int fdt_parse_uart8250(void *fdt, struct platform_uart_data *uart, int fdt_parse_hart_id(void *fdt, int cpu_offset, u32 *hartid)
const char *compatible)
{ {
int nodeoffset, len, rc; int len;
fdt32_t *val; const void *prop;
const fdt32_t *val;
if (!fdt || cpu_offset < 0)
return SBI_EINVAL;
prop = fdt_getprop(fdt, cpu_offset, "device_type", &len);
if (!prop || !len)
return SBI_EINVAL;
if (sbi_strcmp(prop, "cpu"))
return SBI_EINVAL;
val = fdt_getprop(fdt, cpu_offset, "reg", &len);
if (!val || len < sizeof(fdt32_t))
return SBI_EINVAL;
if (len > sizeof(fdt32_t))
val++;
if (hartid)
*hartid = fdt32_to_cpu(*val);
return 0;
}
int fdt_parse_max_hart_id(void *fdt, u32 *max_hartid)
{
u32 hartid;
int err, cpu_offset, cpus_offset;
if (!fdt)
return SBI_EINVAL;
if (!max_hartid)
return 0;
*max_hartid = 0;
cpus_offset = fdt_path_offset(fdt, "/cpus");
if (cpus_offset < 0)
return cpus_offset;
fdt_for_each_subnode(cpu_offset, fdt, cpus_offset) {
err = fdt_parse_hart_id(fdt, cpu_offset, &hartid);
if (err)
continue;
if (hartid > *max_hartid)
*max_hartid = hartid;
}
return 0;
}
int fdt_parse_shakti_uart_node(void *fdt, int nodeoffset,
struct platform_uart_data *uart)
{
int len, rc;
const fdt32_t *val;
unsigned long reg_addr, reg_size; unsigned long reg_addr, reg_size;
/** if (nodeoffset < 0 || !uart || !fdt)
* TODO: We don't know how to handle multiple nodes with the same return SBI_ENODEV;
* compatible sring. Just return the first node for now.
*/
nodeoffset = fdt_node_offset_by_compatible(fdt, -1, compatible);
if (nodeoffset < 0)
return nodeoffset;
rc = fdt_get_node_addr_size(fdt, nodeoffset, &reg_addr, &reg_size); rc = fdt_get_node_addr_size(fdt, nodeoffset, &reg_addr, &reg_size);
if (rc < 0 || !reg_addr || !reg_size) if (rc < 0 || !reg_addr || !reg_size)
@@ -75,31 +183,132 @@ int fdt_parse_uart8250(void *fdt, struct platform_uart_data *uart,
uart->addr = reg_addr; uart->addr = reg_addr;
/** /**
* UART address is mandaotry. clock-frequency and current-speed may not * UART address is mandaotry. clock-frequency and current-speed
* be present. Don't return error. * may not be present. Don't return error.
*/ */
val = (fdt32_t *)fdt_getprop(fdt, nodeoffset, "clock-frequency", &len); val = (fdt32_t *)fdt_getprop(fdt, nodeoffset, "clock-frequency", &len);
if (len > 0 && val) if (len > 0 && val)
uart->freq = fdt32_to_cpu(*val); uart->freq = fdt32_to_cpu(*val);
else
uart->freq = DEFAULT_SHAKTI_UART_FREQ;
val = (fdt32_t *)fdt_getprop(fdt, nodeoffset, "current-speed", &len); val = (fdt32_t *)fdt_getprop(fdt, nodeoffset, "current-speed", &len);
if (len > 0 && val) if (len > 0 && val)
uart->baud = fdt32_to_cpu(*val); uart->baud = fdt32_to_cpu(*val);
else
uart->baud = DEFAULT_SHAKTI_UART_BAUD;
return 0; return 0;
} }
int fdt_parse_plic(void *fdt, struct platform_plic_data *plic, int fdt_parse_sifive_uart_node(void *fdt, int nodeoffset,
const char *compatible) struct platform_uart_data *uart)
{ {
int nodeoffset, len, rc; int len, rc;
const fdt32_t *val; const fdt32_t *val;
unsigned long reg_addr, reg_size; unsigned long reg_addr, reg_size;
if (nodeoffset < 0 || !uart || !fdt)
return SBI_ENODEV;
rc = fdt_get_node_addr_size(fdt, nodeoffset, &reg_addr, &reg_size);
if (rc < 0 || !reg_addr || !reg_size)
return SBI_ENODEV;
uart->addr = reg_addr;
/**
* UART address is mandaotry. clock-frequency and current-speed
* may not be present. Don't return error.
*/
val = (fdt32_t *)fdt_getprop(fdt, nodeoffset, "clock-frequency", &len);
if (len > 0 && val)
uart->freq = fdt32_to_cpu(*val);
else
uart->freq = DEFAULT_SIFIVE_UART_FREQ;
val = (fdt32_t *)fdt_getprop(fdt, nodeoffset, "current-speed", &len);
if (len > 0 && val)
uart->baud = fdt32_to_cpu(*val);
else
uart->baud = DEFAULT_SIFIVE_UART_BAUD;
/* For SiFive UART, the reg-shift and reg-io-width are fixed .*/
uart->reg_shift = DEFAULT_SIFIVE_UART_REG_SHIFT;
uart->reg_io_width = DEFAULT_SIFIVE_UART_REG_IO_WIDTH;
return 0;
}
int fdt_parse_uart8250_node(void *fdt, int nodeoffset,
struct platform_uart_data *uart)
{
int len, rc;
const fdt32_t *val;
unsigned long reg_addr, reg_size;
if (nodeoffset < 0 || !uart || !fdt)
return SBI_ENODEV;
rc = fdt_get_node_addr_size(fdt, nodeoffset, &reg_addr, &reg_size);
if (rc < 0 || !reg_addr || !reg_size)
return SBI_ENODEV;
uart->addr = reg_addr;
/**
* UART address is mandaotry. clock-frequency and current-speed
* may not be present. Don't return error.
*/
val = (fdt32_t *)fdt_getprop(fdt, nodeoffset, "clock-frequency", &len);
if (len > 0 && val)
uart->freq = fdt32_to_cpu(*val);
else
uart->freq = DEFAULT_UART_FREQ;
val = (fdt32_t *)fdt_getprop(fdt, nodeoffset, "current-speed", &len);
if (len > 0 && val)
uart->baud = fdt32_to_cpu(*val);
else
uart->baud = DEFAULT_UART_BAUD;
val = (fdt32_t *)fdt_getprop(fdt, nodeoffset, "reg-shift", &len);
if (len > 0 && val)
uart->reg_shift = fdt32_to_cpu(*val);
else
uart->reg_shift = DEFAULT_UART_REG_SHIFT;
val = (fdt32_t *)fdt_getprop(fdt, nodeoffset, "reg-io-width", &len);
if (len > 0 && val)
uart->reg_io_width = fdt32_to_cpu(*val);
else
uart->reg_io_width = DEFAULT_UART_REG_IO_WIDTH;
return 0;
}
int fdt_parse_uart8250(void *fdt, struct platform_uart_data *uart,
const char *compatible)
{
int nodeoffset;
if (!compatible || !uart || !fdt)
return SBI_ENODEV;
nodeoffset = fdt_node_offset_by_compatible(fdt, -1, compatible); nodeoffset = fdt_node_offset_by_compatible(fdt, -1, compatible);
if (nodeoffset < 0) if (nodeoffset < 0)
return nodeoffset; return nodeoffset;
return fdt_parse_uart8250_node(fdt, nodeoffset, uart);
}
int fdt_parse_plic_node(void *fdt, int nodeoffset, struct plic_data *plic)
{
int len, rc;
const fdt32_t *val;
unsigned long reg_addr, reg_size;
if (nodeoffset < 0 || !plic || !fdt)
return SBI_ENODEV;
rc = fdt_get_node_addr_size(fdt, nodeoffset, &reg_addr, &reg_size); rc = fdt_get_node_addr_size(fdt, nodeoffset, &reg_addr, &reg_size);
if (rc < 0 || !reg_addr || !reg_size) if (rc < 0 || !reg_addr || !reg_size)
return SBI_ENODEV; return SBI_ENODEV;
@@ -112,8 +321,89 @@ int fdt_parse_plic(void *fdt, struct platform_plic_data *plic,
return 0; return 0;
} }
int fdt_parse_clint(void *fdt, unsigned long *clint_addr, int fdt_parse_plic(void *fdt, struct plic_data *plic, const char *compat)
const char *compatible) {
int nodeoffset;
if (!compat || !plic || !fdt)
return SBI_ENODEV;
nodeoffset = fdt_node_offset_by_compatible(fdt, -1, compat);
if (nodeoffset < 0)
return nodeoffset;
return fdt_parse_plic_node(fdt, nodeoffset, plic);
}
int fdt_parse_clint_node(void *fdt, int nodeoffset, bool for_timer,
struct clint_data *clint)
{
const fdt32_t *val;
unsigned long reg_addr, reg_size;
int i, rc, count, cpu_offset, cpu_intc_offset;
u32 phandle, hwirq, hartid, first_hartid, last_hartid;
u32 match_hwirq = (for_timer) ? IRQ_M_TIMER : IRQ_M_SOFT;
if (nodeoffset < 0 || !clint || !fdt)
return SBI_ENODEV;
rc = fdt_get_node_addr_size(fdt, nodeoffset, &reg_addr, &reg_size);
if (rc < 0 || !reg_addr || !reg_size)
return SBI_ENODEV;
clint->addr = reg_addr;
val = fdt_getprop(fdt, nodeoffset, "interrupts-extended", &count);
if (!val || count < sizeof(fdt32_t))
return SBI_EINVAL;
count = count / sizeof(fdt32_t);
first_hartid = -1U;
last_hartid = 0;
clint->hart_count = 0;
for (i = 0; i < count; i += 2) {
phandle = fdt32_to_cpu(val[i]);
hwirq = fdt32_to_cpu(val[i + 1]);
cpu_intc_offset = fdt_node_offset_by_phandle(fdt, phandle);
if (cpu_intc_offset < 0)
continue;
cpu_offset = fdt_parent_offset(fdt, cpu_intc_offset);
if (cpu_intc_offset < 0)
continue;
rc = fdt_parse_hart_id(fdt, cpu_offset, &hartid);
if (rc)
continue;
if (SBI_HARTMASK_MAX_BITS <= hartid)
continue;
if (match_hwirq == hwirq) {
if (hartid < first_hartid)
first_hartid = hartid;
if (hartid > last_hartid)
last_hartid = hartid;
clint->hart_count++;
}
}
if ((last_hartid < first_hartid) || first_hartid == -1U)
return SBI_ENODEV;
clint->first_hartid = first_hartid;
count = last_hartid - first_hartid + 1;
if (clint->hart_count < count)
clint->hart_count = count;
/* TODO: We should figure-out CLINT has_64bit_mmio from DT node */
clint->has_64bit_mmio = TRUE;
return 0;
}
int fdt_parse_compat_addr(void *fdt, unsigned long *addr,
const char *compatible)
{ {
int nodeoffset, rc; int nodeoffset, rc;
@@ -121,8 +411,8 @@ int fdt_parse_clint(void *fdt, unsigned long *clint_addr,
if (nodeoffset < 0) if (nodeoffset < 0)
return nodeoffset; return nodeoffset;
rc = fdt_get_node_addr_size(fdt, nodeoffset, clint_addr, NULL); rc = fdt_get_node_addr_size(fdt, nodeoffset, addr, NULL);
if (rc < 0 || !clint_addr) if (rc < 0 || !addr)
return SBI_ENODEV; return SBI_ENODEV;
return 0; return 0;

101
lib/utils/ipi/fdt_ipi.c Normal file
View File

@@ -0,0 +1,101 @@
/*
* 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_scratch.h>
#include <sbi_utils/fdt/fdt_helper.h>
#include <sbi_utils/ipi/fdt_ipi.h>
extern struct fdt_ipi fdt_ipi_clint;
static struct fdt_ipi *ipi_drivers[] = {
&fdt_ipi_clint
};
static void dummy_send(u32 target_hart)
{
}
static void dummy_clear(u32 target_hart)
{
}
static struct fdt_ipi dummy = {
.match_table = NULL,
.cold_init = NULL,
.warm_init = NULL,
.exit = NULL,
.send = dummy_send,
.clear = dummy_clear
};
static struct fdt_ipi *current_driver = &dummy;
void fdt_ipi_send(u32 target_hart)
{
current_driver->send(target_hart);
}
void fdt_ipi_clear(u32 target_hart)
{
current_driver->clear(target_hart);
}
void fdt_ipi_exit(void)
{
if (current_driver->exit)
current_driver->exit();
}
static int fdt_ipi_warm_init(void)
{
if (current_driver->warm_init)
return current_driver->warm_init();
return 0;
}
static int fdt_ipi_cold_init(void)
{
int pos, noff, rc;
struct fdt_ipi *drv;
const struct fdt_match *match;
void *fdt = sbi_scratch_thishart_arg1_ptr();
for (pos = 0; pos < array_size(ipi_drivers); pos++) {
drv = ipi_drivers[pos];
noff = -1;
while ((noff = fdt_find_match(fdt, noff,
drv->match_table, &match)) >= 0) {
if (drv->cold_init) {
rc = drv->cold_init(fdt, noff, match);
if (rc)
return rc;
}
current_driver = drv;
}
if (current_driver != &dummy)
break;
}
return 0;
}
int fdt_ipi_init(bool cold_boot)
{
int rc;
if (cold_boot) {
rc = fdt_ipi_cold_init();
if (rc)
return rc;
}
return fdt_ipi_warm_init();
}

View File

@@ -0,0 +1,49 @@
/*
* 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_error.h>
#include <sbi_utils/fdt/fdt_helper.h>
#include <sbi_utils/ipi/fdt_ipi.h>
#include <sbi_utils/sys/clint.h>
#define CLINT_IPI_MAX_NR 16
static unsigned long clint_ipi_count = 0;
static struct clint_data clint_ipi[CLINT_IPI_MAX_NR];
static int ipi_clint_cold_init(void *fdt, int nodeoff,
const struct fdt_match *match)
{
int rc;
struct clint_data *ci;
if (CLINT_IPI_MAX_NR <= clint_ipi_count)
return SBI_ENOSPC;
ci = &clint_ipi[clint_ipi_count++];
rc = fdt_parse_clint_node(fdt, nodeoff, FALSE, ci);
if (rc)
return rc;
return clint_cold_ipi_init(ci);
}
static const struct fdt_match ipi_clint_match[] = {
{ .compatible = "riscv,clint0" },
{ },
};
struct fdt_ipi fdt_ipi_clint = {
.match_table = ipi_clint_match,
.cold_init = ipi_clint_cold_init,
.warm_init = clint_warm_ipi_init,
.exit = NULL,
.send = clint_ipi_send,
.clear = clint_ipi_clear,
};

11
lib/utils/ipi/objects.mk Normal file
View File

@@ -0,0 +1,11 @@
#
# SPDX-License-Identifier: BSD-2-Clause
#
# Copyright (c) 2020 Western Digital Corporation or its affiliates.
#
# Authors:
# Anup Patel <anup.patel@wdc.com>
#
libsbiutils-objs-y += ipi/fdt_ipi.o
libsbiutils-objs-y += ipi/fdt_ipi_clint.o

View File

@@ -0,0 +1,74 @@
/*
* 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_scratch.h>
#include <sbi_utils/fdt/fdt_helper.h>
#include <sbi_utils/irqchip/fdt_irqchip.h>
extern struct fdt_irqchip fdt_irqchip_plic;
static struct fdt_irqchip *irqchip_drivers[] = {
&fdt_irqchip_plic
};
static struct fdt_irqchip *current_driver = NULL;
void fdt_irqchip_exit(void)
{
if (current_driver && current_driver->exit)
current_driver->exit();
}
static int fdt_irqchip_warm_init(void)
{
if (current_driver && current_driver->warm_init)
return current_driver->warm_init();
return 0;
}
static int fdt_irqchip_cold_init(void)
{
int pos, noff, rc;
struct fdt_irqchip *drv;
const struct fdt_match *match;
void *fdt = sbi_scratch_thishart_arg1_ptr();
for (pos = 0; pos < array_size(irqchip_drivers); pos++) {
drv = irqchip_drivers[pos];
noff = -1;
while ((noff = fdt_find_match(fdt, noff,
drv->match_table, &match)) >= 0) {
if (drv->cold_init) {
rc = drv->cold_init(fdt, noff, match);
if (rc)
return rc;
}
current_driver = drv;
}
if (current_driver)
break;
}
return 0;
}
int fdt_irqchip_init(bool cold_boot)
{
int rc;
if (cold_boot) {
rc = fdt_irqchip_cold_init();
if (rc)
return rc;
}
return fdt_irqchip_warm_init();
}

View File

@@ -0,0 +1,120 @@
/*
* SPDX-License-Identifier: BSD-2-Clause
*
* Copyright (c) 2020 Western Digital Corporation or its affiliates.
*
* Authors:
* Anup Patel <anup.patel@wdc.com>
*/
#include <libfdt.h>
#include <sbi/riscv_asm.h>
#include <sbi/sbi_error.h>
#include <sbi/sbi_hartmask.h>
#include <sbi_utils/fdt/fdt_helper.h>
#include <sbi_utils/irqchip/fdt_irqchip.h>
#include <sbi_utils/irqchip/plic.h>
#define PLIC_MAX_NR 16
static unsigned long plic_count = 0;
static struct plic_data plic[PLIC_MAX_NR];
static struct plic_data *plic_hartid2data[SBI_HARTMASK_MAX_BITS];
static int plic_hartid2context[SBI_HARTMASK_MAX_BITS][2];
static int irqchip_plic_warm_init(void)
{
u32 hartid = current_hartid();
return plic_warm_irqchip_init(plic_hartid2data[hartid],
plic_hartid2context[hartid][0],
plic_hartid2context[hartid][1]);
}
static int irqchip_plic_update_hartid_table(void *fdt, int nodeoff,
struct plic_data *pd)
{
const fdt32_t *val;
u32 phandle, hwirq, hartid;
int i, err, count, cpu_offset, cpu_intc_offset;
val = fdt_getprop(fdt, nodeoff, "interrupts-extended", &count);
if (!val || count < sizeof(fdt32_t))
return SBI_EINVAL;
count = count / sizeof(fdt32_t);
for (i = 0; i < count; i += 2) {
phandle = fdt32_to_cpu(val[i]);
hwirq = fdt32_to_cpu(val[i + 1]);
cpu_intc_offset = fdt_node_offset_by_phandle(fdt, phandle);
if (cpu_intc_offset < 0)
continue;
cpu_offset = fdt_parent_offset(fdt, cpu_intc_offset);
if (cpu_intc_offset < 0)
continue;
err = fdt_parse_hart_id(fdt, cpu_offset, &hartid);
if (err)
continue;
if (SBI_HARTMASK_MAX_BITS <= hartid)
continue;
plic_hartid2data[hartid] = pd;
switch (hwirq) {
case IRQ_M_EXT:
plic_hartid2context[hartid][0] = i / 2;
break;
case IRQ_S_EXT:
plic_hartid2context[hartid][1] = i / 2;
break;
}
}
return 0;
}
static int irqchip_plic_cold_init(void *fdt, int nodeoff,
const struct fdt_match *match)
{
int i, rc;
struct plic_data *pd;
if (PLIC_MAX_NR <= plic_count)
return SBI_ENOSPC;
pd = &plic[plic_count++];
rc = fdt_parse_plic_node(fdt, nodeoff, pd);
if (rc)
return rc;
rc = plic_cold_irqchip_init(pd);
if (rc)
return rc;
if (plic_count == 1) {
for (i = 0; i < SBI_HARTMASK_MAX_BITS; i++) {
plic_hartid2data[i] = NULL;
plic_hartid2context[i][0] = -1;
plic_hartid2context[i][1] = -1;
}
}
return irqchip_plic_update_hartid_table(fdt, nodeoff, pd);
}
static const struct fdt_match irqchip_plic_match[] = {
{ .compatible = "riscv,plic0" },
{ .compatible = "sifive,plic-1.0.0" },
{ },
};
struct fdt_irqchip fdt_irqchip_plic = {
.match_table = irqchip_plic_match,
.cold_init = irqchip_plic_cold_init,
.warm_init = irqchip_plic_warm_init,
.exit = NULL,
};

View File

@@ -7,4 +7,6 @@
# Anup Patel <anup.patel@wdc.com> # Anup Patel <anup.patel@wdc.com>
# #
libsbiutils-objs-y += irqchip/fdt_irqchip.o
libsbiutils-objs-y += irqchip/fdt_irqchip_plic.o
libsbiutils-objs-y += irqchip/plic.o libsbiutils-objs-y += irqchip/plic.o

View File

@@ -10,6 +10,7 @@
#include <sbi/riscv_io.h> #include <sbi/riscv_io.h>
#include <sbi/riscv_encoding.h> #include <sbi/riscv_encoding.h>
#include <sbi/sbi_console.h> #include <sbi/sbi_console.h>
#include <sbi/sbi_error.h>
#include <sbi/sbi_string.h> #include <sbi/sbi_string.h>
#include <sbi_utils/irqchip/plic.h> #include <sbi_utils/irqchip/plic.h>
@@ -20,72 +21,80 @@
#define PLIC_CONTEXT_BASE 0x200000 #define PLIC_CONTEXT_BASE 0x200000
#define PLIC_CONTEXT_STRIDE 0x1000 #define PLIC_CONTEXT_STRIDE 0x1000
static u32 plic_hart_count; static void plic_set_priority(struct plic_data *plic, u32 source, u32 val)
static u32 plic_num_sources;
static volatile void *plic_base;
static void plic_set_priority(u32 source, u32 val)
{ {
volatile void *plic_priority = volatile void *plic_priority = (void *)plic->addr +
plic_base + PLIC_PRIORITY_BASE + 4 * source; PLIC_PRIORITY_BASE + 4 * source;
writel(val, plic_priority); writel(val, plic_priority);
} }
void plic_set_thresh(u32 cntxid, u32 val) void plic_set_thresh(struct plic_data *plic, u32 cntxid, u32 val)
{ {
volatile void *plic_thresh = volatile void *plic_thresh;
plic_base + PLIC_CONTEXT_BASE + PLIC_CONTEXT_STRIDE * cntxid;
if (!plic)
return;
plic_thresh = (void *)plic->addr +
PLIC_CONTEXT_BASE + PLIC_CONTEXT_STRIDE * cntxid;
writel(val, plic_thresh); writel(val, plic_thresh);
} }
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)
{ {
volatile void *plic_ie = volatile void *plic_ie;
plic_base + PLIC_ENABLE_BASE + PLIC_ENABLE_STRIDE * cntxid;
if (!plic)
return;
plic_ie = (void *)plic->addr +
PLIC_ENABLE_BASE + PLIC_ENABLE_STRIDE * cntxid;
writel(val, plic_ie + word_index * 4); writel(val, plic_ie + word_index * 4);
} }
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)
{ {
size_t i, ie_words = plic_num_sources / 32 + 1; size_t i, ie_words;
if (plic_hart_count <= target_hart) if (!plic)
return -1; return SBI_EINVAL;
ie_words = plic->num_src / 32 + 1;
/* By default, disable all IRQs for M-mode of target HART */ /* By default, disable all IRQs for M-mode of target HART */
if (m_cntx_id > -1) { if (m_cntx_id > -1) {
for (i = 0; i < ie_words; i++) for (i = 0; i < ie_words; i++)
plic_set_ie(m_cntx_id, i, 0); plic_set_ie(plic, m_cntx_id, i, 0);
} }
/* By default, disable all IRQs for S-mode of target HART */ /* By default, disable all IRQs for S-mode of target HART */
if (s_cntx_id > -1) { if (s_cntx_id > -1) {
for (i = 0; i < ie_words; i++) for (i = 0; i < ie_words; i++)
plic_set_ie(s_cntx_id, i, 0); plic_set_ie(plic, s_cntx_id, i, 0);
} }
/* By default, disable M-mode threshold */ /* By default, disable M-mode threshold */
if (m_cntx_id > -1) if (m_cntx_id > -1)
plic_set_thresh(m_cntx_id, 0x7); plic_set_thresh(plic, m_cntx_id, 0x7);
/* By default, disable S-mode threshold */ /* By default, disable S-mode threshold */
if (s_cntx_id > -1) if (s_cntx_id > -1)
plic_set_thresh(s_cntx_id, 0x7); plic_set_thresh(plic, s_cntx_id, 0x7);
return 0; return 0;
} }
int plic_cold_irqchip_init(unsigned long base, u32 num_sources, u32 hart_count) int plic_cold_irqchip_init(struct plic_data *plic)
{ {
int i; int i;
plic_hart_count = hart_count; if (!plic)
plic_num_sources = num_sources; return SBI_EINVAL;
plic_base = (void *)base;
/* Configure default priorities of all IRQs */ /* Configure default priorities of all IRQs */
for (i = 1; i <= plic_num_sources; i++) for (i = 1; i <= plic->num_src; i++)
plic_set_priority(i, 0); plic_set_priority(plic, i, 0);
return 0; return 0;
} }

View File

@@ -0,0 +1,55 @@
/*
* 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_scratch.h>
#include <sbi_utils/fdt/fdt_helper.h>
#include <sbi_utils/reset/fdt_reset.h>
extern struct fdt_reset fdt_reset_sifive;
extern struct fdt_reset fdt_reset_htif;
static struct fdt_reset *reset_drivers[] = {
&fdt_reset_sifive,
&fdt_reset_htif,
};
static struct fdt_reset *current_driver = NULL;
int fdt_system_reset(u32 reset_type)
{
if (current_driver && current_driver->system_reset)
return current_driver->system_reset(reset_type);
return 0;
}
int fdt_reset_init(void)
{
int pos, noff, rc;
struct fdt_reset *drv;
const struct fdt_match *match;
void *fdt = sbi_scratch_thishart_arg1_ptr();
for (pos = 0; pos < array_size(reset_drivers); pos++) {
drv = reset_drivers[pos];
noff = fdt_find_match(fdt, -1, drv->match_table, &match);
if (noff < 0)
continue;
if (drv->init) {
rc = drv->init(fdt, noff, match);
if (rc)
return rc;
}
current_driver = drv;
break;
}
return 0;
}

View File

@@ -0,0 +1,22 @@
/*
* SPDX-License-Identifier: BSD-2-Clause
*
* Copyright (c) 2020 Western Digital Corporation or its affiliates.
*
* Authors:
* Anup Patel <anup.patel@wdc.com>
*/
#include <sbi_utils/reset/fdt_reset.h>
#include <sbi_utils/fdt/fdt_helper.h>
#include <sbi_utils/sys/htif.h>
static const struct fdt_match htif_reset_match[] = {
{ .compatible = "ucb,htif0" },
{ },
};
struct fdt_reset fdt_reset_htif = {
.match_table = htif_reset_match,
.system_reset = htif_system_reset
};

View File

@@ -0,0 +1,37 @@
/*
* 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_scratch.h>
#include <sbi_utils/fdt/fdt_helper.h>
#include <sbi_utils/reset/fdt_reset.h>
#include <sbi_utils/sys/sifive_test.h>
static int sifive_test_reset_init(void *fdt, int nodeoff,
const struct fdt_match *match)
{
int rc;
unsigned long addr;
rc = fdt_get_node_addr_size(fdt, nodeoff, &addr, NULL);
if (rc)
return rc;
return sifive_test_init(addr);
}
static const struct fdt_match sifive_test_reset_match[] = {
{ .compatible = "sifive,test1" },
{ },
};
struct fdt_reset fdt_reset_sifive = {
.match_table = sifive_test_reset_match,
.init = sifive_test_reset_init,
.system_reset = sifive_test_system_reset
};

View File

@@ -0,0 +1,12 @@
#
# SPDX-License-Identifier: BSD-2-Clause
#
# Copyright (c) 2020 Western Digital Corporation or its affiliates.
#
# Authors:
# Anup Patel <anup.patel@wdc.com>
#
libsbiutils-objs-y += reset/fdt_reset.o
libsbiutils-objs-y += reset/fdt_reset_htif.o
libsbiutils-objs-y += reset/fdt_reset_sifive.o

View File

@@ -0,0 +1,111 @@
/*
* SPDX-License-Identifier: BSD-2-Clause
*
* Copyright (c) 2020 Western Digital Corporation or its affiliates.
*
* Authors:
* Anup Patel <anup.patel@wdc.com>
*/
#include <libfdt.h>
#include <sbi/sbi_scratch.h>
#include <sbi_utils/fdt/fdt_helper.h>
#include <sbi_utils/serial/fdt_serial.h>
extern struct fdt_serial fdt_serial_uart8250;
extern struct fdt_serial fdt_serial_sifive;
extern struct fdt_serial fdt_serial_htif;
extern struct fdt_serial fdt_serial_shakti;
static struct fdt_serial *serial_drivers[] = {
&fdt_serial_uart8250,
&fdt_serial_sifive,
&fdt_serial_htif,
&fdt_serial_shakti,
};
static void dummy_putc(char ch)
{
}
static int dummy_getc(void)
{
return -1;
}
static struct fdt_serial dummy = {
.match_table = NULL,
.init = NULL,
.putc = dummy_putc,
.getc = dummy_getc,
};
static struct fdt_serial *current_driver = &dummy;
void fdt_serial_putc(char ch)
{
current_driver->putc(ch);
}
int fdt_serial_getc(void)
{
return current_driver->getc();
}
int fdt_serial_init(void)
{
const void *prop;
struct fdt_serial *drv;
const struct fdt_match *match;
int pos, noff = -1, len, coff, rc;
void *fdt = sbi_scratch_thishart_arg1_ptr();
/* Find offset of node pointed by stdout-path */
coff = fdt_path_offset(fdt, "/chosen");
if (-1 < coff) {
prop = fdt_getprop(fdt, coff, "stdout-path", &len);
if (prop && len)
noff = fdt_path_offset(fdt, prop);
}
/* First check DT node pointed by stdout-path */
for (pos = 0; pos < array_size(serial_drivers) && -1 < noff; pos++) {
drv = serial_drivers[pos];
match = fdt_match_node(fdt, noff, drv->match_table);
if (!match)
continue;
if (drv->init) {
rc = drv->init(fdt, noff, match);
if (rc)
return rc;
}
current_driver = drv;
break;
}
/* Check if we found desired driver */
if (current_driver != &dummy)
goto done;
/* Lastly check all DT nodes */
for (pos = 0; pos < array_size(serial_drivers); pos++) {
drv = serial_drivers[pos];
noff = fdt_find_match(fdt, -1, drv->match_table, &match);
if (noff < 0)
continue;
if (drv->init) {
rc = drv->init(fdt, noff, match);
if (rc)
return rc;
}
current_driver = drv;
break;
}
done:
return 0;
}

View File

@@ -0,0 +1,24 @@
/*
* SPDX-License-Identifier: BSD-2-Clause
*
* Copyright (c) 2020 Western Digital Corporation or its affiliates.
*
* Authors:
* Anup Patel <anup.patel@wdc.com>
*/
#include <sbi_utils/fdt/fdt_helper.h>
#include <sbi_utils/serial/fdt_serial.h>
#include <sbi_utils/sys/htif.h>
static const struct fdt_match serial_htif_match[] = {
{ .compatible = "ucb,htif0" },
{ },
};
struct fdt_serial fdt_serial_htif = {
.match_table = serial_htif_match,
.init = NULL,
.getc = htif_getc,
.putc = htif_putc
};

View File

@@ -0,0 +1,35 @@
/*
* SPDX-License-Identifier: BSD-2-Clause
*
* Copyright (c) 2020 Vijai Kumar K <vijai@behindbytes.com>
*
*/
#include <sbi_utils/fdt/fdt_helper.h>
#include <sbi_utils/serial/fdt_serial.h>
#include <sbi_utils/serial/shakti-uart.h>
static int serial_shakti_init(void *fdt, int nodeoff,
const struct fdt_match *match)
{
int rc;
struct platform_uart_data uart;
rc = fdt_parse_shakti_uart_node(fdt, nodeoff, &uart);
if (rc)
return rc;
return shakti_uart_init(uart.addr, uart.freq, uart.baud);
}
static const struct fdt_match serial_shakti_match[] = {
{ .compatible = "shakti,uart0" },
{ },
};
struct fdt_serial fdt_serial_shakti = {
.match_table = serial_shakti_match,
.init = serial_shakti_init,
.getc = shakti_uart_getc,
.putc = shakti_uart_putc
};

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>
*/
#include <sbi_utils/fdt/fdt_helper.h>
#include <sbi_utils/serial/fdt_serial.h>
#include <sbi_utils/serial/sifive-uart.h>
static int serial_sifive_init(void *fdt, int nodeoff,
const struct fdt_match *match)
{
int rc;
struct platform_uart_data uart;
rc = fdt_parse_sifive_uart_node(fdt, nodeoff, &uart);
if (rc)
return rc;
return sifive_uart_init(uart.addr, uart.freq, uart.baud);
}
static const struct fdt_match serial_sifive_match[] = {
{ .compatible = "sifive,fu540-c000-uart" },
{ .compatible = "sifive,uart0" },
{ },
};
struct fdt_serial fdt_serial_sifive = {
.match_table = serial_sifive_match,
.init = serial_sifive_init,
.getc = sifive_uart_getc,
.putc = sifive_uart_putc
};

View File

@@ -0,0 +1,39 @@
/*
* SPDX-License-Identifier: BSD-2-Clause
*
* Copyright (c) 2020 Western Digital Corporation or its affiliates.
*
* Authors:
* Anup Patel <anup.patel@wdc.com>
*/
#include <sbi_utils/fdt/fdt_helper.h>
#include <sbi_utils/serial/fdt_serial.h>
#include <sbi_utils/serial/uart8250.h>
static int serial_uart8250_init(void *fdt, int nodeoff,
const struct fdt_match *match)
{
int rc;
struct platform_uart_data uart;
rc = fdt_parse_uart8250_node(fdt, nodeoff, &uart);
if (rc)
return rc;
return uart8250_init(uart.addr, uart.freq, uart.baud,
uart.reg_shift, uart.reg_io_width);
}
static const struct fdt_match serial_uart8250_match[] = {
{ .compatible = "ns16550" },
{ .compatible = "ns16550a" },
{ },
};
struct fdt_serial fdt_serial_uart8250 = {
.match_table = serial_uart8250_match,
.init = serial_uart8250_init,
.getc = uart8250_getc,
.putc = uart8250_putc
};

View File

@@ -7,5 +7,11 @@
# Anup Patel <anup.patel@wdc.com> # Anup Patel <anup.patel@wdc.com>
# #
libsbiutils-objs-y += serial/fdt_serial.o
libsbiutils-objs-y += serial/fdt_serial_htif.o
libsbiutils-objs-y += serial/fdt_serial_shakti.o
libsbiutils-objs-y += serial/fdt_serial_sifive.o
libsbiutils-objs-y += serial/fdt_serial_uart8250.o
libsbiutils-objs-y += serial/shakti-uart.o
libsbiutils-objs-y += serial/sifive-uart.o libsbiutils-objs-y += serial/sifive-uart.o
libsbiutils-objs-y += serial/uart8250.o libsbiutils-objs-y += serial/uart8250.o

View File

@@ -0,0 +1,44 @@
/*
* SPDX-License-Identifier: BSD-2-Clause
*
* Copyright (c) 2020 Vijai Kumar K <vijai@behindbytes.com>
*/
#include <sbi/riscv_io.h>
#include <sbi/sbi_console.h>
#include <sbi_utils/serial/shakti-uart.h>
#define REG_BAUD 0x00
#define REG_TX 0x04
#define REG_RX 0x08
#define REG_STATUS 0x0C
#define REG_DELAY 0x10
#define REG_CONTROL 0x14
#define REG_INT_EN 0x18
#define REG_IQ_CYCLES 0x1C
#define REG_RX_THRES 0x20
static volatile void *uart_base;
void shakti_uart_putc(char ch)
{
while((readw(uart_base + REG_STATUS) & 0x2) == 0);
writeb(ch, uart_base + REG_TX);
}
int shakti_uart_getc(void)
{
u16 status = readw(uart_base + REG_STATUS);
if (status & 0x8)
return readb(uart_base + REG_RX);
return -1;
}
int shakti_uart_init(unsigned long base, u32 in_freq, u32 baudrate)
{
uart_base = (volatile void *)base;
u16 baud = (u16)(in_freq/(16 * baudrate));
writew(baud, uart_base + REG_BAUD);
return 0;
}

View File

@@ -89,7 +89,8 @@ int sifive_uart_init(unsigned long base, u32 in_freq, u32 baudrate)
uart_baudrate = baudrate; uart_baudrate = baudrate;
/* Configure baudrate */ /* Configure baudrate */
set_reg(UART_REG_DIV, uart_min_clk_divisor(in_freq, baudrate)); if (in_freq)
set_reg(UART_REG_DIV, uart_min_clk_divisor(in_freq, baudrate));
/* Disable interrupts */ /* Disable interrupts */
set_reg(UART_REG_IE, 0); set_reg(UART_REG_IE, 0);
/* Enable TX */ /* Enable TX */

View File

@@ -100,10 +100,14 @@ int uart8250_init(unsigned long base, u32 in_freq, u32 baudrate, u32 reg_shift,
set_reg(UART_IER_OFFSET, 0x00); set_reg(UART_IER_OFFSET, 0x00);
/* Enable DLAB */ /* Enable DLAB */
set_reg(UART_LCR_OFFSET, 0x80); set_reg(UART_LCR_OFFSET, 0x80);
/* Set divisor low byte */
set_reg(UART_DLL_OFFSET, bdiv & 0xff); if (bdiv) {
/* Set divisor high byte */ /* Set divisor low byte */
set_reg(UART_DLM_OFFSET, (bdiv >> 8) & 0xff); set_reg(UART_DLL_OFFSET, bdiv & 0xff);
/* Set divisor high byte */
set_reg(UART_DLM_OFFSET, (bdiv >> 8) & 0xff);
}
/* 8 bits, no parity, one stop bit */ /* 8 bits, no parity, one stop bit */
set_reg(UART_LCR_OFFSET, 0x03); set_reg(UART_LCR_OFFSET, 0x03);
/* Enable FIFO */ /* Enable FIFO */

View File

@@ -10,57 +10,70 @@
#include <sbi/riscv_asm.h> #include <sbi/riscv_asm.h>
#include <sbi/riscv_atomic.h> #include <sbi/riscv_atomic.h>
#include <sbi/riscv_io.h> #include <sbi/riscv_io.h>
#include <sbi/sbi_error.h>
#include <sbi/sbi_hartmask.h>
#include <sbi_utils/sys/clint.h> #include <sbi_utils/sys/clint.h>
static u32 clint_ipi_hart_count; #define CLINT_IPI_OFF 0
static volatile void *clint_ipi_base; #define CLINT_TIME_CMP_OFF 0x4000
static volatile u32 *clint_ipi; #define CLINT_TIME_VAL_OFF 0xbff8
static struct clint_data *clint_ipi_hartid2data[SBI_HARTMASK_MAX_BITS];
void clint_ipi_send(u32 target_hart) void clint_ipi_send(u32 target_hart)
{ {
if (clint_ipi_hart_count <= target_hart) struct clint_data *clint;
if (SBI_HARTMASK_MAX_BITS <= target_hart)
return;
clint = clint_ipi_hartid2data[target_hart];
if (!clint)
return; return;
/* Set CLINT IPI */ /* Set CLINT IPI */
writel(1, &clint_ipi[target_hart]); writel(1, &clint->ipi[target_hart - clint->first_hartid]);
} }
void clint_ipi_clear(u32 target_hart) void clint_ipi_clear(u32 target_hart)
{ {
if (clint_ipi_hart_count <= target_hart) struct clint_data *clint;
if (SBI_HARTMASK_MAX_BITS <= target_hart)
return;
clint = clint_ipi_hartid2data[target_hart];
if (!clint)
return; return;
/* Clear CLINT IPI */ /* Clear CLINT IPI */
writel(0, &clint_ipi[target_hart]); writel(0, &clint->ipi[target_hart - clint->first_hartid]);
} }
int clint_warm_ipi_init(void) int clint_warm_ipi_init(void)
{ {
u32 hartid = current_hartid(); /* Clear CLINT IPI for current HART */
clint_ipi_clear(current_hartid());
if (!clint_ipi_base)
return -1;
/* Clear CLINT IPI */
clint_ipi_clear(hartid);
return 0; return 0;
} }
int clint_cold_ipi_init(unsigned long base, u32 hart_count) int clint_cold_ipi_init(struct clint_data *clint)
{ {
/* Figure-out CLINT IPI register address */ u32 i;
clint_ipi_hart_count = hart_count;
clint_ipi_base = (void *)base; if (!clint)
clint_ipi = (u32 *)clint_ipi_base; return SBI_EINVAL;
/* Initialize private data */
clint->ipi = (void *)clint->addr;
/* Update IPI hartid table */
for (i = 0; i < clint->hart_count; i++)
clint_ipi_hartid2data[clint->first_hartid + i] = clint;
return 0; return 0;
} }
static u32 clint_time_hart_count; static struct clint_data *clint_timer_hartid2data[SBI_HARTMASK_MAX_BITS];
static volatile void *clint_time_base;
static volatile u64 *clint_time_val;
static volatile u64 *clint_time_cmp;
#if __riscv_xlen != 32 #if __riscv_xlen != 32
static u64 clint_time_rd64(volatile u64 *addr) static u64 clint_time_rd64(volatile u64 *addr)
@@ -94,66 +107,97 @@ static void clint_time_wr32(u64 value, volatile u64 *addr)
writel_relaxed(value >> 32, (void *)(addr) + 0x04); writel_relaxed(value >> 32, (void *)(addr) + 0x04);
} }
static u64 (*clint_time_rd)(volatile u64 *addr) = clint_time_rd32;
static void (*clint_time_wr)(u64 value, volatile u64 *addr) = clint_time_wr32;
u64 clint_timer_value(void) u64 clint_timer_value(void)
{ {
struct clint_data *clint = clint_timer_hartid2data[current_hartid()];
/* Read CLINT Time Value */ /* Read CLINT Time Value */
return clint_time_rd(clint_time_val); return clint->time_rd(clint->time_val) + clint->time_delta;
} }
void clint_timer_event_stop(void) void clint_timer_event_stop(void)
{ {
u32 target_hart = current_hartid(); u32 target_hart = current_hartid();
struct clint_data *clint = clint_timer_hartid2data[target_hart];
if (clint_time_hart_count <= target_hart)
return;
/* Clear CLINT Time Compare */ /* Clear CLINT Time Compare */
clint_time_wr(-1ULL, &clint_time_cmp[target_hart]); clint->time_wr(-1ULL,
&clint->time_cmp[target_hart - clint->first_hartid]);
} }
void clint_timer_event_start(u64 next_event) void clint_timer_event_start(u64 next_event)
{ {
u32 target_hart = current_hartid(); u32 target_hart = current_hartid();
struct clint_data *clint = clint_timer_hartid2data[target_hart];
if (clint_time_hart_count <= target_hart)
return;
/* Program CLINT Time Compare */ /* Program CLINT Time Compare */
clint_time_wr(next_event, &clint_time_cmp[target_hart]); clint->time_wr(next_event - clint->time_delta,
&clint->time_cmp[target_hart - clint->first_hartid]);
} }
int clint_warm_timer_init(void) int clint_warm_timer_init(void)
{ {
u64 v1, v2, mv;
u32 target_hart = current_hartid(); u32 target_hart = current_hartid();
struct clint_data *reference;
struct clint_data *clint = clint_timer_hartid2data[target_hart];
if (clint_time_hart_count <= target_hart || !clint_time_base) if (!clint)
return -1; return SBI_ENODEV;
/*
* Compute delta if reference available
*
* We deliberately compute time_delta in warm init so that time_delta
* is computed on a HART which is going to use given CLINT. We use
* atomic flag timer_delta_computed to ensure that only one HART does
* time_delta computation.
*/
if (clint->time_delta_reference) {
reference = clint->time_delta_reference;
if (!atomic_raw_xchg_ulong(&clint->time_delta_computed, 1)) {
v1 = clint->time_rd(clint->time_val);
mv = reference->time_rd(reference->time_val);
v2 = clint->time_rd(clint->time_val);
clint->time_delta = mv - ((v1 / 2) + (v2 / 2));
}
}
/* Clear CLINT Time Compare */ /* Clear CLINT Time Compare */
clint_time_wr(-1ULL, &clint_time_cmp[target_hart]); clint->time_wr(-1ULL,
&clint->time_cmp[target_hart - clint->first_hartid]);
return 0; return 0;
} }
int clint_cold_timer_init(unsigned long base, u32 hart_count, int clint_cold_timer_init(struct clint_data *clint,
bool has_64bit_mmio) struct clint_data *reference)
{ {
/* Figure-out CLINT Time register address */ u32 i;
clint_time_hart_count = hart_count;
clint_time_base = (void *)base; if (!clint)
clint_time_val = (u64 *)(clint_time_base + 0xbff8); return SBI_EINVAL;
clint_time_cmp = (u64 *)(clint_time_base + 0x4000);
/* Initialize private data */
clint->time_delta_reference = reference;
clint->time_delta_computed = 0;
clint->time_delta = 0;
clint->time_val = (u64 *)((void *)clint->addr + CLINT_TIME_VAL_OFF);
clint->time_cmp = (u64 *)((void *)clint->addr + CLINT_TIME_CMP_OFF);
clint->time_rd = clint_time_rd32;
clint->time_wr = clint_time_wr32;
/* Override read/write accessors for 64bit MMIO */ /* Override read/write accessors for 64bit MMIO */
#if __riscv_xlen != 32 #if __riscv_xlen != 32
if (has_64bit_mmio) { if (clint->has_64bit_mmio) {
clint_time_rd = clint_time_rd64; clint->time_rd = clint_time_rd64;
clint_time_wr = clint_time_wr64; clint->time_wr = clint_time_wr64;
} }
#endif #endif
/* Update timer hartid table */
for (i = 0; i < clint->hart_count; i++)
clint_timer_hartid2data[clint->first_hartid + i] = clint;
return 0; return 0;
} }

View File

@@ -140,7 +140,7 @@ int htif_getc(void)
return ch - 1; return ch - 1;
} }
int htif_system_down(u32 type) int htif_system_reset(u32 type)
{ {
while (1) { while (1) {
fromhost = 0; fromhost = 0;

View File

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

View File

@@ -0,0 +1,44 @@
/*
* SPDX-License-Identifier: BSD-3-Clause
*
* Copyright (c) 2020 Western Digital Corporation or its affiliates.
*
* Authors:
* Anup Patel <anup.patel@wdc.com>
*/
#include <sbi/riscv_io.h>
#include <sbi/sbi_platform.h>
#include <sbi_utils/sys/sifive_test.h>
#define FINISHER_FAIL 0x3333
#define FINISHER_PASS 0x5555
#define FINISHER_RESET 0x7777
static void *sifive_test_base;
int sifive_test_system_reset(u32 type)
{
/*
* Tell the "finisher" that the simulation
* was successful so that QEMU exits
*/
switch (type) {
case SBI_PLATFORM_RESET_SHUTDOWN:
writew(FINISHER_PASS, sifive_test_base);
break;
case SBI_PLATFORM_RESET_COLD:
case SBI_PLATFORM_RESET_WARM:
writew(FINISHER_RESET, sifive_test_base);
break;
}
return 0;
}
int sifive_test_init(unsigned long base)
{
sifive_test_base = (void *)base;
return 0;
}

112
lib/utils/timer/fdt_timer.c Normal file
View File

@@ -0,0 +1,112 @@
/*
* 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_scratch.h>
#include <sbi_utils/fdt/fdt_helper.h>
#include <sbi_utils/timer/fdt_timer.h>
extern struct fdt_timer fdt_timer_clint;
static struct fdt_timer *timer_drivers[] = {
&fdt_timer_clint
};
static u64 dummy_value(void)
{
return 0;
}
static void dummy_event_stop(void)
{
}
static void dummy_event_start(u64 next_event)
{
}
static struct fdt_timer dummy = {
.match_table = NULL,
.cold_init = NULL,
.warm_init = NULL,
.exit = NULL,
.value = dummy_value,
.event_stop = dummy_event_stop,
.event_start = dummy_event_start
};
static struct fdt_timer *current_driver = &dummy;
u64 fdt_timer_value(void)
{
return current_driver->value();
}
void fdt_timer_event_stop(void)
{
current_driver->event_stop();
}
void fdt_timer_event_start(u64 next_event)
{
current_driver->event_start(next_event);
}
void fdt_timer_exit(void)
{
if (current_driver->exit)
current_driver->exit();
}
static int fdt_timer_warm_init(void)
{
if (current_driver->warm_init)
return current_driver->warm_init();
return 0;
}
static int fdt_timer_cold_init(void)
{
int pos, noff, rc;
struct fdt_timer *drv;
const struct fdt_match *match;
void *fdt = sbi_scratch_thishart_arg1_ptr();
for (pos = 0; pos < array_size(timer_drivers); pos++) {
drv = timer_drivers[pos];
noff = -1;
while ((noff = fdt_find_match(fdt, noff,
drv->match_table, &match)) >= 0) {
if (drv->cold_init) {
rc = drv->cold_init(fdt, noff, match);
if (rc)
return rc;
}
current_driver = drv;
}
if (current_driver != &dummy)
break;
}
return 0;
}
int fdt_timer_init(bool cold_boot)
{
int rc;
if (cold_boot) {
rc = fdt_timer_cold_init();
if (rc)
return rc;
}
return fdt_timer_warm_init();
}

View File

@@ -0,0 +1,52 @@
/*
* 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_error.h>
#include <sbi_utils/fdt/fdt_helper.h>
#include <sbi_utils/timer/fdt_timer.h>
#include <sbi_utils/sys/clint.h>
#define CLINT_TIMER_MAX_NR 16
static unsigned long clint_timer_count = 0;
static struct clint_data clint_timer[CLINT_TIMER_MAX_NR];
static int timer_clint_cold_init(void *fdt, int nodeoff,
const struct fdt_match *match)
{
int rc;
struct clint_data *ct, *ctmaster = NULL;
if (CLINT_TIMER_MAX_NR <= clint_timer_count)
return SBI_ENOSPC;
ct = &clint_timer[clint_timer_count++];
if (1 < clint_timer_count)
ctmaster = &clint_timer[0];
rc = fdt_parse_clint_node(fdt, nodeoff, TRUE, ct);
if (rc)
return rc;
return clint_cold_timer_init(ct, ctmaster);
}
static const struct fdt_match timer_clint_match[] = {
{ .compatible = "riscv,clint0" },
{ },
};
struct fdt_timer fdt_timer_clint = {
.match_table = timer_clint_match,
.cold_init = timer_clint_cold_init,
.warm_init = clint_warm_timer_init,
.exit = NULL,
.value = clint_timer_value,
.event_stop = clint_timer_event_stop,
.event_start = clint_timer_event_start,
};

View File

@@ -0,0 +1,11 @@
#
# SPDX-License-Identifier: BSD-2-Clause
#
# Copyright (c) 2020 Western Digital Corporation or its affiliates.
#
# Authors:
# Anup Patel <anup.patel@wdc.com>
#
libsbiutils-objs-y += timer/fdt_timer.o
libsbiutils-objs-y += timer/fdt_timer_clint.o

View File

@@ -0,0 +1,89 @@
/*
* SPDX-License-Identifier: BSD-2-Clause
*
* Copyright (c) 2020 Andes Technology Corporation
*
* Authors:
* Nylon Chen <nylon7@andestech.com>
*/
#include <sbi/riscv_asm.h>
#include <sbi/riscv_io.h>
#include <sbi/sbi_types.h>
#include "platform.h"
uintptr_t mcall_set_mcache_ctl(unsigned long input)
{
csr_clear(CSR_MCACHECTL, V5_MCACHE_CTL_MASK);
csr_write(CSR_MCACHECTL, input);
return 0;
}
uintptr_t mcall_set_mmisc_ctl(unsigned long input)
{
csr_clear(CSR_MMISCCTL, V5_MMISC_CTL_MASK);
csr_write(CSR_MMISCCTL, input);
return 0;
}
uintptr_t mcall_icache_op(unsigned int enable)
{
if (enable) {
csr_set(CSR_MCACHECTL, V5_MCACHE_CTL_IC_EN);
} else {
csr_clear(CSR_MCACHECTL, V5_MCACHE_CTL_IC_EN);
asm volatile("fence.i\n\t");
}
return 0;
}
uintptr_t mcall_dcache_op(unsigned int enable)
{
if (enable) {
csr_set(CSR_MCACHECTL, V5_MCACHE_CTL_DC_EN);
} else {
csr_clear(CSR_MCACHECTL, V5_MCACHE_CTL_DC_EN);
csr_write(CSR_MCCTLCOMMAND, V5_UCCTL_L1D_WBINVAL_ALL);
}
return 0;
}
uintptr_t mcall_l1_cache_i_prefetch_op(unsigned long enable)
{
if (enable) {
csr_set(CSR_MCACHECTL, V5_MCACHE_CTL_L1I_PREFETCH_EN);
} else {
csr_clear(CSR_MCACHECTL, V5_MCACHE_CTL_L1I_PREFETCH_EN);
}
return 0;
}
uintptr_t mcall_l1_cache_d_prefetch_op(unsigned long enable)
{
if (enable) {
csr_set(CSR_MCACHECTL, V5_MCACHE_CTL_L1D_PREFETCH_EN);
} else {
csr_clear(CSR_MCACHECTL, V5_MCACHE_CTL_L1D_PREFETCH_EN);
}
return 0;
}
uintptr_t mcall_non_blocking_load_store(unsigned long enable)
{
if (enable) {
csr_set(CSR_MCACHECTL, V5_MMISC_CTL_NON_BLOCKING_EN);
} else {
csr_clear(CSR_MCACHECTL, V5_MMISC_CTL_NON_BLOCKING_EN);
}
return 0;
}
uintptr_t mcall_write_around(unsigned long enable)
{
if (enable) {
csr_set(CSR_MCACHECTL, V5_MCACHE_CTL_DC_WAROUND_1_EN);
} else {
csr_clear(CSR_MCACHECTL, V5_MCACHE_CTL_DC_WAROUND_1_EN);
}
return 0;
}

View File

@@ -0,0 +1,17 @@
/*
* SPDX-License-Identifier: BSD-2-Clause
*
* Copyright (c) 2020 Andes Technology Corporation
*
* Authors:
* Nylon Chen <nylon7@andestech.com>
*/
uintptr_t mcall_set_mcache_ctl(unsigned long input);
uintptr_t mcall_set_mmisc_ctl(unsigned long input);
uintptr_t mcall_icache_op(unsigned int enable);
uintptr_t mcall_dcache_op(unsigned int enable);
uintptr_t mcall_l1_cache_i_prefetch_op(unsigned long enable);
uintptr_t mcall_l1_cache_d_prefetch_op(unsigned long enable);
uintptr_t mcall_non_blocking_load_store(unsigned long enable);
uintptr_t mcall_write_around(unsigned long enable);

View File

@@ -8,4 +8,4 @@
# Nylon Chen <nylon7@andestech.com> # Nylon Chen <nylon7@andestech.com>
# #
platform-objs-y += platform.o plicsw.o plmt.o platform-objs-y += cache.o platform.o plicsw.o plmt.o

View File

@@ -19,6 +19,12 @@
#include "platform.h" #include "platform.h"
#include "plicsw.h" #include "plicsw.h"
#include "plmt.h" #include "plmt.h"
#include "cache.h"
static struct plic_data plic = {
.addr = AE350_PLIC_ADDR,
.num_src = AE350_PLIC_NUM_SOURCES,
};
/* Platform final initialization. */ /* Platform final initialization. */
static int ae350_final_init(bool cold_boot) static int ae350_final_init(bool cold_boot)
@@ -53,35 +59,6 @@ static int ae350_final_init(bool cold_boot)
return 0; return 0;
} }
/* Get number of PMP regions for given HART. */
static u32 ae350_pmp_region_count(u32 hartid)
{
return 1;
}
/*
* Get PMP regions details (namely: protection, base address, and size) for
* a given HART.
*/
static int ae350_pmp_region_info(u32 hartid, u32 index, ulong *prot,
ulong *addr, ulong *log2size)
{
int ret = 0;
switch (index) {
case 0:
*prot = PMP_R | PMP_W | PMP_X;
*addr = 0;
*log2size = __riscv_xlen;
break;
default:
ret = -1;
break;
};
return ret;
}
/* Initialize the platform console. */ /* Initialize the platform console. */
static int ae350_console_init(void) static int ae350_console_init(void)
{ {
@@ -99,14 +76,12 @@ static int ae350_irqchip_init(bool cold_boot)
int ret; int ret;
if (cold_boot) { if (cold_boot) {
ret = plic_cold_irqchip_init(AE350_PLIC_ADDR, ret = plic_cold_irqchip_init(&plic);
AE350_PLIC_NUM_SOURCES,
AE350_HART_COUNT);
if (ret) if (ret)
return ret; return ret;
} }
return plic_warm_irqchip_init(hartid, 2 * hartid, 2 * hartid + 1); return plic_warm_irqchip_init(&plic, 2 * hartid, 2 * hartid + 1);
} }
/* Initialize IPI for current HART. */ /* Initialize IPI for current HART. */
@@ -139,29 +114,62 @@ static int ae350_timer_init(bool cold_boot)
return plmt_warm_timer_init(); return plmt_warm_timer_init();
} }
/* Reboot the platform. */ /* Reset the platform. */
static int ae350_system_reboot(u32 type) static int ae350_system_reset(u32 type)
{ {
/* For now nothing to do. */ /* For now nothing to do. */
sbi_printf("System reboot\n"); sbi_printf("System reset\n");
return 0; return 0;
} }
/* Shutdown or poweroff the platform. */ /* Vendor-Specific SBI handler */
static int ae350_system_shutdown(u32 type) static int ae350_vendor_ext_provider(long extid, long funcid,
unsigned long *args, unsigned long *out_value,
struct sbi_trap_info *out_trap)
{ {
/* For now nothing to do. */ int ret = 0;
sbi_printf("System shutdown\n"); switch (funcid) {
return 0; case SBI_EXT_ANDES_GET_MCACHE_CTL_STATUS:
*out_value = csr_read(CSR_MCACHECTL);
break;
case SBI_EXT_ANDES_GET_MMISC_CTL_STATUS:
*out_value = csr_read(CSR_MMISCCTL);
break;
case SBI_EXT_ANDES_SET_MCACHE_CTL:
ret = mcall_set_mcache_ctl(args[0]);
break;
case SBI_EXT_ANDES_SET_MMISC_CTL:
ret = mcall_set_mmisc_ctl(args[0]);
break;
case SBI_EXT_ANDES_ICACHE_OP:
ret = mcall_icache_op(args[0]);
break;
case SBI_EXT_ANDES_DCACHE_OP:
ret = mcall_dcache_op(args[0]);
break;
case SBI_EXT_ANDES_L1CACHE_I_PREFETCH:
ret = mcall_l1_cache_i_prefetch_op(args[0]);
break;
case SBI_EXT_ANDES_L1CACHE_D_PREFETCH:
ret = mcall_l1_cache_d_prefetch_op(args[0]);
break;
case SBI_EXT_ANDES_NON_BLOCKING_LOAD_STORE:
ret = mcall_non_blocking_load_store(args[0]);
break;
case SBI_EXT_ANDES_WRITE_AROUND:
ret = mcall_write_around(args[0]);
break;
default:
sbi_printf("Unsupported vendor sbi call : %ld\n", funcid);
asm volatile("ebreak");
}
return ret;
} }
/* Platform descriptor. */ /* Platform descriptor. */
const struct sbi_platform_operations platform_ops = { const struct sbi_platform_operations platform_ops = {
.final_init = ae350_final_init, .final_init = ae350_final_init,
.pmp_region_count = ae350_pmp_region_count,
.pmp_region_info = ae350_pmp_region_info,
.console_init = ae350_console_init, .console_init = ae350_console_init,
.console_putc = uart8250_putc, .console_putc = uart8250_putc,
.console_getc = uart8250_getc, .console_getc = uart8250_getc,
@@ -177,8 +185,9 @@ const struct sbi_platform_operations platform_ops = {
.timer_event_start = plmt_timer_event_start, .timer_event_start = plmt_timer_event_start,
.timer_event_stop = plmt_timer_event_stop, .timer_event_stop = plmt_timer_event_stop,
.system_reboot = ae350_system_reboot, .system_reset = ae350_system_reset,
.system_shutdown = ae350_system_shutdown
.vendor_ext_provider = ae350_vendor_ext_provider
}; };
const struct sbi_platform platform = { const struct sbi_platform platform = {

View File

@@ -29,9 +29,58 @@
#define AE350_UART_REG_SHIFT 2 #define AE350_UART_REG_SHIFT 2
#define AE350_UART_REG_WIDTH 0 #define AE350_UART_REG_WIDTH 0
/* nds mcache_ctl register*/ /*Memory and Miscellaneous Registers*/
#define CSR_MCACHECTL 0x7ca #define CSR_MILMB 0x7c0
#define CSR_MDLMB 0x7c1
#define CSR_MECC_CDOE 0x7c2
#define CSR_MNVEC 0x7c3
#define CSR_MPFTCTL 0x7c5
#define CSR_MCACHECTL 0x7ca
#define CSR_MCCTLBEGINADDR 0x7cb
#define CSR_MCCTLCOMMAND 0x7cc
#define CSR_MCCTLDATA 0x7cc
#define CSR_SCCTLDATA 0x9cd
#define CSR_UCCTLBEGINADDR 0x80c
#define CSR_MMISCCTL 0x7d0
enum sbi_ext_andes_fid {
SBI_EXT_ANDES_GET_MCACHE_CTL_STATUS = 0,
SBI_EXT_ANDES_GET_MMISC_CTL_STATUS,
SBI_EXT_ANDES_SET_MCACHE_CTL,
SBI_EXT_ANDES_SET_MMISC_CTL,
SBI_EXT_ANDES_ICACHE_OP,
SBI_EXT_ANDES_DCACHE_OP,
SBI_EXT_ANDES_L1CACHE_I_PREFETCH,
SBI_EXT_ANDES_L1CACHE_D_PREFETCH,
SBI_EXT_ANDES_NON_BLOCKING_LOAD_STORE,
SBI_EXT_ANDES_WRITE_AROUND,
};
/* nds v5 mmisc_ctl register*/
#define V5_MMISC_CTL_VEC_PLIC_OFFSET 1
#define V5_MMISC_CTL_RVCOMPM_OFFSET 2
#define V5_MMISC_CTL_BRPE_OFFSET 3
#define V5_MMISC_CTL_MSA_OR_UNA_OFFSET 6
#define V5_MMISC_CTL_NON_BLOCKING_OFFSET 8
#define V5_MCACHE_CTL_L1I_PREFETCH_OFFSET 9
#define V5_MCACHE_CTL_L1D_PREFETCH_OFFSET 10
#define V5_MCACHE_CTL_DC_WAROUND_OFFSET_1 13
#define V5_MCACHE_CTL_DC_WAROUND_OFFSET_2 14
#define V5_MMISC_CTL_VEC_PLIC_EN (1UL << V5_MMISC_CTL_VEC_PLIC_OFFSET)
#define V5_MMISC_CTL_RVCOMPM_EN (1UL << V5_MMISC_CTL_RVCOMPM_OFFSET)
#define V5_MMISC_CTL_BRPE_EN (1UL << V5_MMISC_CTL_BRPE_OFFSET)
#define V5_MMISC_CTL_MSA_OR_UNA_EN (1UL << V5_MMISC_CTL_MSA_OR_UNA_OFFSET)
#define V5_MMISC_CTL_NON_BLOCKING_EN (1UL << V5_MMISC_CTL_NON_BLOCKING_OFFSET)
#define V5_MCACHE_CTL_L1I_PREFETCH_EN (1UL << V5_MCACHE_CTL_L1I_PREFETCH_OFFSET)
#define V5_MCACHE_CTL_L1D_PREFETCH_EN (1UL << V5_MCACHE_CTL_L1D_PREFETCH_OFFSET)
#define V5_MCACHE_CTL_DC_WAROUND_1_EN (1UL << V5_MCACHE_CTL_DC_WAROUND_OFFSET_1)
#define V5_MCACHE_CTL_DC_WAROUND_2_EN (1UL << V5_MCACHE_CTL_DC_WAROUND_OFFSET_2)
#define V5_MMISC_CTL_MASK (V5_MMISC_CTL_VEC_PLIC_EN | V5_MMISC_CTL_RVCOMPM_EN \
| V5_MMISC_CTL_BRPE_EN | V5_MMISC_CTL_MSA_OR_UNA_EN | V5_MMISC_CTL_NON_BLOCKING_EN)
/* nds mcache_ctl register*/
#define V5_MCACHE_CTL_IC_EN_OFFSET 0 #define V5_MCACHE_CTL_IC_EN_OFFSET 0
#define V5_MCACHE_CTL_DC_EN_OFFSET 1 #define V5_MCACHE_CTL_DC_EN_OFFSET 1
#define V5_MCACHE_CTL_IC_ECCEN_OFFSET 2 #define V5_MCACHE_CTL_IC_ECCEN_OFFSET 2
@@ -40,12 +89,22 @@
#define V5_MCACHE_CTL_DC_RWECC_OFFSET 7 #define V5_MCACHE_CTL_DC_RWECC_OFFSET 7
#define V5_MCACHE_CTL_CCTL_SUEN_OFFSET 8 #define V5_MCACHE_CTL_CCTL_SUEN_OFFSET 8
/*nds cctl command*/
#define V5_UCCTL_L1D_WBINVAL_ALL 6
#define V5_UCCTL_L1D_WB_ALL 7
#define V5_MCACHE_CTL_IC_EN (1UL << V5_MCACHE_CTL_IC_EN_OFFSET) #define V5_MCACHE_CTL_IC_EN (1UL << V5_MCACHE_CTL_IC_EN_OFFSET)
#define V5_MCACHE_CTL_DC_EN (1UL << V5_MCACHE_CTL_DC_EN_OFFSET) #define V5_MCACHE_CTL_DC_EN (1UL << V5_MCACHE_CTL_DC_EN_OFFSET)
#define V5_MCACHE_CTL_IC_RWECC (1UL << V5_MCACHE_CTL_IC_RWECC_OFFSET) #define V5_MCACHE_CTL_IC_RWECC (1UL << V5_MCACHE_CTL_IC_RWECC_OFFSET)
#define V5_MCACHE_CTL_DC_RWECC (1UL << V5_MCACHE_CTL_DC_RWECC_OFFSET) #define V5_MCACHE_CTL_DC_RWECC (1UL << V5_MCACHE_CTL_DC_RWECC_OFFSET)
#define V5_MCACHE_CTL_CCTL_SUEN (1UL << V5_MCACHE_CTL_CCTL_SUEN_OFFSET) #define V5_MCACHE_CTL_CCTL_SUEN (1UL << V5_MCACHE_CTL_CCTL_SUEN_OFFSET)
#define V5_MCACHE_CTL_MASK (V5_MCACHE_CTL_IC_EN | V5_MCACHE_CTL_DC_EN \
| V5_MCACHE_CTL_IC_RWECC | V5_MCACHE_CTL_DC_RWECC \
| V5_MCACHE_CTL_CCTL_SUEN | V5_MCACHE_CTL_L1I_PREFETCH_EN \
| V5_MCACHE_CTL_L1D_PREFETCH_EN | V5_MCACHE_CTL_DC_WAROUND_1_EN \
| V5_MCACHE_CTL_DC_WAROUND_2_EN)
#define V5_L2C_CTL_OFFSET 0x8 #define V5_L2C_CTL_OFFSET 0x8
#define V5_L2C_CTL_ENABLE_OFFSET 0 #define V5_L2C_CTL_ENABLE_OFFSET 0
#define V5_L2C_CTL_IPFDPT_OFFSET 3 #define V5_L2C_CTL_IPFDPT_OFFSET 3

View File

@@ -24,13 +24,19 @@
#define ARIANE_PLIC_ADDR 0xc000000 #define ARIANE_PLIC_ADDR 0xc000000
#define ARIANE_PLIC_NUM_SOURCES 3 #define ARIANE_PLIC_NUM_SOURCES 3
#define ARIANE_HART_COUNT 1 #define ARIANE_HART_COUNT 1
#define ARIANE_CLINT_ADDR 0x2000000 #define ARIANE_CLINT_ADDR 0x2000000
#define SBI_ARIANE_FEATURES \ static struct plic_data plic = {
(SBI_PLATFORM_HAS_TIMER_VALUE | \ .addr = ARIANE_PLIC_ADDR,
SBI_PLATFORM_HAS_SCOUNTEREN | \ .num_src = ARIANE_PLIC_NUM_SOURCES,
SBI_PLATFORM_HAS_MCOUNTEREN | \ };
SBI_PLATFORM_HAS_MFAULTS_DELEGATION)
static struct clint_data clint = {
.addr = ARIANE_CLINT_ADDR,
.first_hartid = 0,
.hart_count = ARIANE_HART_COUNT,
.has_64bit_mmio = TRUE,
};
/* /*
* Ariane platform early initialization. * Ariane platform early initialization.
@@ -69,29 +75,26 @@ static int ariane_console_init(void)
ARIANE_UART_REG_WIDTH); ARIANE_UART_REG_WIDTH);
} }
static int plic_ariane_warm_irqchip_init(u32 target_hart, static int plic_ariane_warm_irqchip_init(int m_cntx_id, int s_cntx_id)
int m_cntx_id, int s_cntx_id)
{ {
size_t i, ie_words = ARIANE_PLIC_NUM_SOURCES / 32 + 1; size_t i, ie_words = ARIANE_PLIC_NUM_SOURCES / 32 + 1;
if (ARIANE_HART_COUNT <= target_hart)
return -1;
/* By default, enable all IRQs for M-mode of target HART */ /* By default, enable all IRQs for M-mode of target HART */
if (m_cntx_id > -1) { if (m_cntx_id > -1) {
for (i = 0; i < ie_words; i++) for (i = 0; i < ie_words; i++)
plic_set_ie(m_cntx_id, i, 1); plic_set_ie(&plic, m_cntx_id, i, 1);
} }
/* Enable all IRQs for S-mode of target HART */ /* Enable all IRQs for S-mode of target HART */
if (s_cntx_id > -1) { if (s_cntx_id > -1) {
for (i = 0; i < ie_words; i++) for (i = 0; i < ie_words; i++)
plic_set_ie(s_cntx_id, i, 1); plic_set_ie(&plic, s_cntx_id, i, 1);
} }
/* By default, enable M-mode threshold */ /* By default, enable M-mode threshold */
if (m_cntx_id > -1) if (m_cntx_id > -1)
plic_set_thresh(m_cntx_id, 1); plic_set_thresh(&plic, m_cntx_id, 1);
/* By default, disable S-mode threshold */ /* By default, disable S-mode threshold */
if (s_cntx_id > -1) if (s_cntx_id > -1)
plic_set_thresh(s_cntx_id, 0); plic_set_thresh(&plic, s_cntx_id, 0);
return 0; return 0;
} }
@@ -105,14 +108,11 @@ static int ariane_irqchip_init(bool cold_boot)
int ret; int ret;
if (cold_boot) { if (cold_boot) {
ret = plic_cold_irqchip_init(ARIANE_PLIC_ADDR, ret = plic_cold_irqchip_init(&plic);
ARIANE_PLIC_NUM_SOURCES,
ARIANE_HART_COUNT);
if (ret) if (ret)
return ret; return ret;
} }
return plic_ariane_warm_irqchip_init(hartid, return plic_ariane_warm_irqchip_init(2 * hartid, 2 * hartid + 1);
2 * hartid, 2 * hartid + 1);
} }
/* /*
@@ -123,8 +123,7 @@ static int ariane_ipi_init(bool cold_boot)
int ret; int ret;
if (cold_boot) { if (cold_boot) {
ret = clint_cold_ipi_init(ARIANE_CLINT_ADDR, ret = clint_cold_ipi_init(&clint);
ARIANE_HART_COUNT);
if (ret) if (ret)
return ret; return ret;
} }
@@ -140,8 +139,7 @@ static int ariane_timer_init(bool cold_boot)
int ret; int ret;
if (cold_boot) { if (cold_boot) {
ret = clint_cold_timer_init(ARIANE_CLINT_ADDR, ret = clint_cold_timer_init(&clint, NULL);
ARIANE_HART_COUNT, TRUE);
if (ret) if (ret)
return ret; return ret;
} }
@@ -150,22 +148,12 @@ static int ariane_timer_init(bool cold_boot)
} }
/* /*
* Reboot the ariane. * Reset the ariane.
*/ */
static int ariane_system_reboot(u32 type) static int ariane_system_reset(u32 type)
{ {
/* For now nothing to do. */ /* For now nothing to do. */
sbi_printf("System reboot\n"); sbi_printf("System reset\n");
return 0;
}
/*
* Shutdown or poweroff the ariane.
*/
static int ariane_system_shutdown(u32 type)
{
/* For now nothing to do. */
sbi_printf("System shutdown\n");
return 0; return 0;
} }
@@ -186,15 +174,14 @@ const struct sbi_platform_operations platform_ops = {
.timer_value = clint_timer_value, .timer_value = clint_timer_value,
.timer_event_start = clint_timer_event_start, .timer_event_start = clint_timer_event_start,
.timer_event_stop = clint_timer_event_stop, .timer_event_stop = clint_timer_event_stop,
.system_reboot = ariane_system_reboot, .system_reset = ariane_system_reset
.system_shutdown = ariane_system_shutdown
}; };
const struct sbi_platform platform = { const struct sbi_platform platform = {
.opensbi_version = OPENSBI_VERSION, .opensbi_version = OPENSBI_VERSION,
.platform_version = SBI_PLATFORM_VERSION(0x0, 0x01), .platform_version = SBI_PLATFORM_VERSION(0x0, 0x01),
.name = "ARIANE RISC-V", .name = "ARIANE RISC-V",
.features = SBI_ARIANE_FEATURES, .features = SBI_PLATFORM_DEFAULT_FEATURES,
.hart_count = ARIANE_HART_COUNT, .hart_count = ARIANE_HART_COUNT,
.hart_stack_size = SBI_PLATFORM_DEFAULT_HART_STACK_SIZE, .hart_stack_size = SBI_PLATFORM_DEFAULT_HART_STACK_SIZE,
.platform_ops_addr = (unsigned long)&platform_ops .platform_ops_addr = (unsigned long)&platform_ops

View File

@@ -26,22 +26,22 @@
#define OPENPITON_DEFAULT_HART_COUNT 3 #define OPENPITON_DEFAULT_HART_COUNT 3
#define OPENPITON_DEFAULT_CLINT_ADDR 0xfff1020000 #define OPENPITON_DEFAULT_CLINT_ADDR 0xfff1020000
#define SBI_OPENPITON_FEATURES \
(SBI_PLATFORM_HAS_TIMER_VALUE | \
SBI_PLATFORM_HAS_SCOUNTEREN | \
SBI_PLATFORM_HAS_MCOUNTEREN | \
SBI_PLATFORM_HAS_MFAULTS_DELEGATION)
static struct platform_uart_data uart = { static struct platform_uart_data uart = {
OPENPITON_DEFAULT_UART_ADDR, OPENPITON_DEFAULT_UART_ADDR,
OPENPITON_DEFAULT_UART_FREQ, OPENPITON_DEFAULT_UART_FREQ,
OPENPITON_DEFAULT_UART_BAUDRATE, OPENPITON_DEFAULT_UART_BAUDRATE,
}; };
static struct platform_plic_data plic = { static struct plic_data plic = {
OPENPITON_DEFAULT_PLIC_ADDR, .addr = OPENPITON_DEFAULT_PLIC_ADDR,
OPENPITON_DEFAULT_PLIC_NUM_SOURCES, .num_src = OPENPITON_DEFAULT_PLIC_NUM_SOURCES,
}; };
static unsigned long clint_addr = OPENPITON_DEFAULT_CLINT_ADDR;
static struct clint_data clint = {
.addr = OPENPITON_DEFAULT_CLINT_ADDR,
.first_hartid = 0,
.hart_count = OPENPITON_DEFAULT_HART_COUNT,
.has_64bit_mmio = TRUE,
};
/* /*
* OpenPiton platform early initialization. * OpenPiton platform early initialization.
@@ -50,8 +50,8 @@ static int openpiton_early_init(bool cold_boot)
{ {
void *fdt; void *fdt;
struct platform_uart_data uart_data; struct platform_uart_data uart_data;
struct platform_plic_data plic_data; struct plic_data plic_data;
unsigned long clint_data; unsigned long clint_addr;
int rc; int rc;
if (!cold_boot) if (!cold_boot)
@@ -66,9 +66,9 @@ static int openpiton_early_init(bool cold_boot)
if (!rc) if (!rc)
plic = plic_data; plic = plic_data;
rc = fdt_parse_clint(fdt, &clint_data, "riscv,clint0"); rc = fdt_parse_compat_addr(fdt, &clint_addr, "riscv,clint0");
if (!rc) if (!rc)
clint_addr = clint_data; clint.addr = clint_addr;
return 0; return 0;
} }
@@ -101,29 +101,26 @@ static int openpiton_console_init(void)
OPENPITON_DEFAULT_UART_REG_WIDTH); OPENPITON_DEFAULT_UART_REG_WIDTH);
} }
static int plic_openpiton_warm_irqchip_init(u32 target_hart, static int plic_openpiton_warm_irqchip_init(int m_cntx_id, int s_cntx_id)
int m_cntx_id, int s_cntx_id)
{ {
size_t i, ie_words = plic.num_src / 32 + 1; size_t i, ie_words = plic.num_src / 32 + 1;
if (target_hart >= OPENPITON_DEFAULT_HART_COUNT)
return -1;
/* By default, enable all IRQs for M-mode of target HART */ /* By default, enable all IRQs for M-mode of target HART */
if (m_cntx_id > -1) { if (m_cntx_id > -1) {
for (i = 0; i < ie_words; i++) for (i = 0; i < ie_words; i++)
plic_set_ie(m_cntx_id, i, 1); plic_set_ie(&plic, m_cntx_id, i, 1);
} }
/* Enable all IRQs for S-mode of target HART */ /* Enable all IRQs for S-mode of target HART */
if (s_cntx_id > -1) { if (s_cntx_id > -1) {
for (i = 0; i < ie_words; i++) for (i = 0; i < ie_words; i++)
plic_set_ie(s_cntx_id, i, 1); plic_set_ie(&plic, s_cntx_id, i, 1);
} }
/* By default, enable M-mode threshold */ /* By default, enable M-mode threshold */
if (m_cntx_id > -1) if (m_cntx_id > -1)
plic_set_thresh(m_cntx_id, 1); plic_set_thresh(&plic, m_cntx_id, 1);
/* By default, disable S-mode threshold */ /* By default, disable S-mode threshold */
if (s_cntx_id > -1) if (s_cntx_id > -1)
plic_set_thresh(s_cntx_id, 0); plic_set_thresh(&plic, s_cntx_id, 0);
return 0; return 0;
} }
@@ -137,14 +134,11 @@ static int openpiton_irqchip_init(bool cold_boot)
int ret; int ret;
if (cold_boot) { if (cold_boot) {
ret = plic_cold_irqchip_init(plic.addr, ret = plic_cold_irqchip_init(&plic);
plic.num_src,
OPENPITON_DEFAULT_HART_COUNT);
if (ret) if (ret)
return ret; return ret;
} }
return plic_openpiton_warm_irqchip_init(hartid, return plic_openpiton_warm_irqchip_init(2 * hartid, 2 * hartid + 1);
2 * hartid, 2 * hartid + 1);
} }
/* /*
@@ -155,8 +149,7 @@ static int openpiton_ipi_init(bool cold_boot)
int ret; int ret;
if (cold_boot) { if (cold_boot) {
ret = clint_cold_ipi_init(clint_addr, ret = clint_cold_ipi_init(&clint);
OPENPITON_DEFAULT_HART_COUNT);
if (ret) if (ret)
return ret; return ret;
} }
@@ -172,8 +165,7 @@ static int openpiton_timer_init(bool cold_boot)
int ret; int ret;
if (cold_boot) { if (cold_boot) {
ret = clint_cold_timer_init(clint_addr, ret = clint_cold_timer_init(&clint, NULL);
OPENPITON_DEFAULT_HART_COUNT, TRUE);
if (ret) if (ret)
return ret; return ret;
} }
@@ -182,22 +174,12 @@ static int openpiton_timer_init(bool cold_boot)
} }
/* /*
* Reboot the openpiton. * Reset the openpiton.
*/ */
static int openpiton_system_reboot(u32 type) static int openpiton_system_reset(u32 type)
{ {
/* For now nothing to do. */ /* For now nothing to do. */
sbi_printf("System reboot\n"); sbi_printf("System reset\n");
return 0;
}
/*
* Shutdown or poweroff the openpiton.
*/
static int openpiton_system_shutdown(u32 type)
{
/* For now nothing to do. */
sbi_printf("System shutdown\n");
return 0; return 0;
} }
@@ -218,15 +200,14 @@ const struct sbi_platform_operations platform_ops = {
.timer_value = clint_timer_value, .timer_value = clint_timer_value,
.timer_event_start = clint_timer_event_start, .timer_event_start = clint_timer_event_start,
.timer_event_stop = clint_timer_event_stop, .timer_event_stop = clint_timer_event_stop,
.system_reboot = openpiton_system_reboot, .system_reset = openpiton_system_reset
.system_shutdown = openpiton_system_shutdown
}; };
const struct sbi_platform platform = { const struct sbi_platform platform = {
.opensbi_version = OPENSBI_VERSION, .opensbi_version = OPENSBI_VERSION,
.platform_version = SBI_PLATFORM_VERSION(0x0, 0x01), .platform_version = SBI_PLATFORM_VERSION(0x0, 0x01),
.name = "OPENPITON RISC-V", .name = "OPENPITON RISC-V",
.features = SBI_OPENPITON_FEATURES, .features = SBI_PLATFORM_DEFAULT_FEATURES,
.hart_count = OPENPITON_DEFAULT_HART_COUNT, .hart_count = OPENPITON_DEFAULT_HART_COUNT,
.hart_stack_size = SBI_PLATFORM_DEFAULT_HART_STACK_SIZE, .hart_stack_size = SBI_PLATFORM_DEFAULT_HART_STACK_SIZE,
.platform_ops_addr = (unsigned long)&platform_ops .platform_ops_addr = (unsigned long)&platform_ops

View File

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

View File

@@ -0,0 +1,27 @@
/*
* SPDX-License-Identifier: BSD-2-Clause
*
* Copyright (c) 2020 Western Digital Corporation or its affiliates.
*
* Authors:
* Anup Patel <anup.patel@wdc.com>
*/
#ifndef __PLATFORM_OVERRIDE_H__
#define __PLATFORM_OVERRIDE_H__
#include <sbi/sbi_types.h>
struct platform_override {
const struct fdt_match *match_table;
u64 (*features)(const struct fdt_match *match);
u64 (*tlbr_flush_limit)(const struct fdt_match *match);
int (*early_init)(bool cold_boot, const struct fdt_match *match);
int (*final_init)(bool cold_boot, const struct fdt_match *match);
void (*early_exit)(const struct fdt_match *match);
void (*final_exit)(const struct fdt_match *match);
int (*system_reset)(u32 reset_type, const struct fdt_match *match);
int (*fdt_fixup)(void *fdt, const struct fdt_match *match);
};
#endif

View File

@@ -3,5 +3,9 @@
# #
# Copyright (c) 2020 Western Digital Corporation or its affiliates. # Copyright (c) 2020 Western Digital Corporation or its affiliates.
# #
# Authors:
# Anup Patel <anup.patel@wdc.com>
#
platform-objs-y += platform.o platform-objs-y += platform.o
platform-objs-y += sifive_fu540.o

224
platform/generic/platform.c Normal file
View File

@@ -0,0 +1,224 @@
/*
* SPDX-License-Identifier: BSD-2-Clause
*
* Copyright (c) 2020 Western Digital Corporation or its affiliates.
*
* Authors:
* Anup Patel <anup.patel@wdc.com>
*/
#include <libfdt.h>
#include <platform_override.h>
#include <sbi/riscv_asm.h>
#include <sbi/sbi_hartmask.h>
#include <sbi/sbi_platform.h>
#include <sbi/sbi_string.h>
#include <sbi_utils/fdt/fdt_fixup.h>
#include <sbi_utils/fdt/fdt_helper.h>
#include <sbi_utils/irqchip/fdt_irqchip.h>
#include <sbi_utils/serial/fdt_serial.h>
#include <sbi_utils/timer/fdt_timer.h>
#include <sbi_utils/ipi/fdt_ipi.h>
#include <sbi_utils/reset/fdt_reset.h>
extern const struct platform_override sifive_fu540;
static const struct platform_override *special_platforms[] = {
&sifive_fu540,
};
static const struct platform_override *generic_plat = NULL;
static const struct fdt_match *generic_plat_match = NULL;
static void fw_platform_lookup_special(void *fdt, int root_offset)
{
int pos, noff;
const struct platform_override *plat;
const struct fdt_match *match;
for (pos = 0; pos < array_size(special_platforms); pos++) {
plat = special_platforms[pos];
if (!plat->match_table)
continue;
noff = fdt_find_match(fdt, -1, plat->match_table, &match);
if (noff < 0)
continue;
generic_plat = plat;
generic_plat_match = match;
break;
}
}
extern struct sbi_platform platform;
static u32 generic_hart_index2id[SBI_HARTMASK_MAX_BITS] = { 0 };
/*
* The fw_platform_init() function is called very early on the boot HART
* OpenSBI reference firmwares so that platform specific code get chance
* to update "platform" instance before it is used.
*
* The arguments passed to fw_platform_init() function are boot time state
* of A0 to A4 register. The "arg0" will be boot HART id and "arg1" will
* be address of FDT passed by previous booting stage.
*
* The return value of fw_platform_init() function is the FDT location. If
* FDT is unchanged (or FDT is modified in-place) then fw_platform_init()
* can always return the original FDT location (i.e. 'arg1') unmodified.
*/
unsigned long fw_platform_init(unsigned long arg0, unsigned long arg1,
unsigned long arg2, unsigned long arg3,
unsigned long arg4)
{
const char *model, *mmu_type;
void *fdt = (void *)arg1;
u32 hartid, hart_count = 0;
int rc, root_offset, cpus_offset, cpu_offset, len;
root_offset = fdt_path_offset(fdt, "/");
if (root_offset < 0)
goto fail;
fw_platform_lookup_special(fdt, root_offset);
model = fdt_getprop(fdt, root_offset, "model", &len);
if (model)
sbi_strncpy(platform.name, model, sizeof(platform.name));
if (generic_plat && generic_plat->features)
platform.features = generic_plat->features(generic_plat_match);
cpus_offset = fdt_path_offset(fdt, "/cpus");
if (cpus_offset < 0)
goto fail;
fdt_for_each_subnode(cpu_offset, fdt, cpus_offset) {
rc = fdt_parse_hart_id(fdt, cpu_offset, &hartid);
if (rc)
continue;
if (SBI_HARTMASK_MAX_BITS <= hartid)
continue;
mmu_type = fdt_getprop(fdt, cpu_offset, "mmu-type", &len);
if (!mmu_type || !len)
hartid = -1U;
generic_hart_index2id[hart_count++] = hartid;
}
platform.hart_count = hart_count;
/* Return original FDT pointer */
return arg1;
fail:
while (1)
wfi();
}
static int generic_early_init(bool cold_boot)
{
int rc;
if (generic_plat && generic_plat->early_init) {
rc = generic_plat->early_init(cold_boot, generic_plat_match);
if (rc)
return rc;
}
if (!cold_boot)
return 0;
return fdt_reset_init();
}
static int generic_final_init(bool cold_boot)
{
void *fdt;
int rc;
if (generic_plat && generic_plat->final_init) {
rc = generic_plat->final_init(cold_boot, generic_plat_match);
if (rc)
return rc;
}
if (!cold_boot)
return 0;
fdt = sbi_scratch_thishart_arg1_ptr();
fdt_cpu_fixup(fdt);
fdt_fixups(fdt);
if (generic_plat && generic_plat->fdt_fixup) {
rc = generic_plat->fdt_fixup(fdt, generic_plat_match);
if (rc)
return rc;
}
return 0;
}
static void generic_early_exit(void)
{
if (generic_plat && generic_plat->early_exit)
generic_plat->early_exit(generic_plat_match);
}
static void generic_final_exit(void)
{
if (generic_plat && generic_plat->final_exit)
generic_plat->final_exit(generic_plat_match);
}
static u64 generic_tlbr_flush_limit(void)
{
if (generic_plat && generic_plat->tlbr_flush_limit)
return generic_plat->tlbr_flush_limit(generic_plat_match);
return SBI_PLATFORM_TLB_RANGE_FLUSH_LIMIT_DEFAULT;
}
static int generic_system_reset(u32 reset_type)
{
if (generic_plat && generic_plat->system_reset)
return generic_plat->system_reset(reset_type,
generic_plat_match);
return fdt_system_reset(reset_type);
}
const struct sbi_platform_operations platform_ops = {
.early_init = generic_early_init,
.final_init = generic_final_init,
.early_exit = generic_early_exit,
.final_exit = generic_final_exit,
.console_putc = fdt_serial_putc,
.console_getc = fdt_serial_getc,
.console_init = fdt_serial_init,
.irqchip_init = fdt_irqchip_init,
.irqchip_exit = fdt_irqchip_exit,
.ipi_send = fdt_ipi_send,
.ipi_clear = fdt_ipi_clear,
.ipi_init = fdt_ipi_init,
.ipi_exit = fdt_ipi_exit,
.get_tlbr_flush_limit = generic_tlbr_flush_limit,
.timer_value = fdt_timer_value,
.timer_event_stop = fdt_timer_event_stop,
.timer_event_start = fdt_timer_event_start,
.timer_init = fdt_timer_init,
.timer_exit = fdt_timer_exit,
.system_reset = generic_system_reset,
};
struct sbi_platform platform = {
.opensbi_version = OPENSBI_VERSION,
.platform_version = SBI_PLATFORM_VERSION(0x0, 0x01),
.name = "Generic",
.features = SBI_PLATFORM_DEFAULT_FEATURES,
.hart_count = SBI_HARTMASK_MAX_BITS,
.hart_index2id = generic_hart_index2id,
.hart_stack_size = SBI_PLATFORM_DEFAULT_HART_STACK_SIZE,
.platform_ops_addr = (unsigned long)&platform_ops
};

View File

@@ -0,0 +1,47 @@
/*
* SPDX-License-Identifier: BSD-2-Clause
*
* Copyright (c) 2020 Western Digital Corporation or its affiliates.
*
* Authors:
* Anup Patel <anup.patel@wdc.com>
*/
#include <platform_override.h>
#include <sbi_utils/fdt/fdt_helper.h>
#include <sbi_utils/fdt/fdt_fixup.h>
static u64 sifive_fu540_tlbr_flush_limit(const struct fdt_match *match)
{
/*
* The sfence.vma by virtual address does not work on
* SiFive FU540 so we return remote TLB flush limit as zero.
*/
return 0;
}
static int sifive_fu540_fdt_fixup(void *fdt, const struct fdt_match *match)
{
/*
* SiFive Freedom U540 has an erratum that prevents S-mode software
* to access a PMP protected region using 1GB page table mapping, so
* always add the no-map attribute on this platform.
*/
fdt_reserved_memory_nomap_fixup(fdt);
return 0;
}
static const struct fdt_match sifive_fu540_match[] = {
{ .compatible = "sifive,fu540" },
{ .compatible = "sifive,fu540g" },
{ .compatible = "sifive,fu540-c000" },
{ .compatible = "sifive,hifive-unleashed-a00" },
{ },
};
const struct platform_override sifive_fu540 = {
.match_table = sifive_fu540_match,
.tlbr_flush_limit = sifive_fu540_tlbr_flush_limit,
.fdt_fixup = sifive_fu540_fdt_fixup,
};

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