91 Commits
v0.8 ... v0.9

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

Signed-off-by: Anup Patel <anup.patel@wdc.com>
2021-01-18 18:47:19 +05:30
Anup Patel
da5293f742 platform: template: Fix compile error
This clint driver init functions were incorrectly used in
template platform which resulted in compile error. This patch
fixes clint driver function usage in template platform.

Signed-off-by: Anup Patel <anup.patel@wdc.com>
Reviewed-by: Atish Patra <atish.patra@wdc.com>
2021-01-18 14:49:56 +05:30
Anup Patel
1bbf36183e include: sbi: Don't pack struct sbi_platform and sbi_platform_operations
We don't need to pack struct sbi_platform and sbi_platform_operations
because GCC ensures member offsets match member data type irrespective
to the target system (RV32 or RV64). This also allows GCC to generate
more optimized instruction sequence when accessing members of struct
sbi_platform and struct sbi_platform_operations.

Reported-by: Paul Campbell <taniwha@gmail.com>
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>
2021-01-15 10:40:33 +05:30
Anup Patel
386eba21bf include: sbi: No need to pack struct sbi_scratch
All members in struct sbi_scrach are of machine word size so no need
to pack this structure. This also allows GCC to generate more optimized
instruction sequence when accessing members of struct sbi_scratch.

Reported-by: Paul Campbell <taniwha@gmail.com>
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>
2021-01-15 10:40:31 +05:30
Anup Patel
e884416650 include: sbi: No need to pack struct sbi_trap_regs
All members in struct sbi_trap_regs are of machine word size so
no need to pack this structure. This also allows GCC to generate
more optimized instruction sequence when accessing members of
struct sbi_trap_regs.

Reported-by: Paul Campbell <taniwha@gmail.com>
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>
2021-01-15 10:40:29 +05:30
Anup Patel
db56341dfa lib: sbi: Allow platforms to provide root domain memory regions
Currently, the root domain memory regions are fixed in generic
code but some of the platforms may want to explicitly define
memory regions for the root domain.

This patch adds optional domains_root_regions() platform callback
which platforms can use to provide platform specific root domain
memory regions. Due to this changes, the root domain should also
undergo all sanity checks (just like regular domain) so we use
sbi_domain_register() to register root domain.

Signed-off-by: Anup Patel <anup.patel@wdc.com>
Reviewed-by: Atish Patra <atish.patra@wdc.com>
2021-01-12 10:41:11 +05:30
Vijai Kumar K
0d49c3bc18 lib: utils: Fix shakti uart implementation
Fix uart_putc implementation.
Due to a bug in the IP, this went unnoticed.
Use macros instead of magic numbers to make the code
more readable.

Signed-off-by: Vijai Kumar K <vijai@behindbytes.com>
Reviewed-by: Anup Patel <anup.patel@wdc.com>
2021-01-07 10:18:23 +05:30
Anup Patel
12394a269b lib: sbi: Allow custom local TLB flush function
Currently, we have fixed TLB flush types supported by the
remote TLB library. This approach is not flexible and does
not allow custom local TLB flush function. For example,
after updating PMP entries on a set of HARTs at runtime,
we have to flush TLB on these HARTs as well.

To support custom local TLB flush function, we replace the
"type" field of "struct sbi_tlb_info" with a local TLB flush
function pointer. We also provide definitions of standard TLB
flush operations (such as fence_i, sfence.vma, hfence.vvma,
hfence.gvma, etc).

Signed-off-by: Anup Patel <anup.patel@wdc.com>
Reviewed-by: Atish Patra <atish.patra@wdc.com>
2021-01-07 09:53:19 +05:30
Anup Patel
b7df5e4392 lib: sbi: Introduce sbi_trap_exit() API
We introduce sbi_trap_exit() API which can help non-firmware
(i.e. generic or platform) code to force exit trap/interrupt
handling and resume execution at context pointed by parameter
"const struct sbi_trap_regs *regs".

This new sbi_trap_exit() API will help Keystone Enclave project
to resume execution of enclave from custom SBI call handler.

Signed-off-by: Anup Patel <anup.patel@wdc.com>
Reviewed-by: Atish Patra <atish.patra@wdc.com>
2021-01-07 09:53:17 +05:30
Anup Patel
80bc5065bb lib: sbi: Replace args with trap registers in ecall handler
We had added args pointer in ecall handler to ensure that ecall
handler only implements functionality and does not deal with
SBI calling convention. This also helped us to keep SBI calling
convention related code in one place at sbi_ecall_handler().

The Keystone Enclavce project needs access to the trap regsiters
in their ecall handler so that they can context switch enclaves
in custom SBI calls. To help the Keystone Enclave project, we
replace the args pointer in ecall handler parameter with a const
pointer to trap registers.

Signed-off-by: Anup Patel <anup.patel@wdc.com>
Reviewed-by: Atish Patra <atish.patra@wdc.com>
2021-01-07 09:53:14 +05:30
Anup Patel
7dcb1e1753 lib: sbi: Fix sign-extension in sbi_misaligned_load_handler()
The misaligned load emulation does not sign-extend values correctly
due to missing sign typecast in value passed to the SET_RD() macro.

A very easy way to reproduce this issue is to load 16-bit value
0xff1e from a byte aligned address using LH instruction on hardware
lacking misaligned load/store.

This patch fixes sbi_misaligned_load_handler() for above issue.

Signed-off-by: Anup Patel <anup.patel@wdc.com>
Reviewed-by: Atish Patra <atish.patra@wdc.com>
2020-12-24 16:35:28 +05:30
Anup Patel
a029bd90c6 lib: sbi: Remove domain_get() platform callback function
The domain_get() platform callback function is now redundant
because fdt_domain_populate() register new domain explicitly
using the sbi_domain_register() function.

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-12-16 10:10:28 +05:30
Anup Patel
6fc1986f50 lib: utils: Remove fdt_domain_get() function
The fdt_domain_get() function is now redundant because the
fdt_domains_populate() function can explicitly register new
domains using the sbi_domain_register() function.

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-12-16 10:10:25 +05:30
Anup Patel
7baccfca79 lib: sbi: Add function to register new domain
We add sbi_domain_register() function to help platform code register
a new domain explicitly instead of depending on domain_get() platform
callback. This function will eventually help us completely remove the
domain_get() platform callback.

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-12-16 10:10:22 +05:30
Anup Patel
2179777364 lib: utils: Allow FDT domain iteration functions to fail
We extend fdt_iterate_each_domain() and fdt_iterate_each_memregion()
functions to allow underlying iteration function to fail. This will
help us catch more domain misconfiguration issues at boot time.

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-12-16 10:10:19 +05:30
Dimitri John Ledkov
e7da0b4204 lib: utils/libfdt: Upgrade to v1.6.0 release
Sync with libfdt v1.6.0 release source codes.

Signed-off-by: Dimitri John Ledkov <xnox@ubuntu.com>
Reviewed-by: Anup Patel <anup.patel@wdc.com>
2020-12-13 09:52:25 +05:30
Anup Patel
4fffb53269 platform: generic: Populate domains from FDT
The generic platform should populate domains from FDT using the
domain FDT helper routines.

Signed-off-by: Anup Patel <anup.patel@wdc.com>
Reviewed-by: Atish Patra <atish.patra@wdc.com>
2020-12-04 21:14:25 +05:30
Anup Patel
ba741ea0ad lib: utils: Add helper routines to populate domains from FDT
We add various helper routines to populate domains, iterate domains,
iterate domain memregions, and parse HART to domain assignment from
the FDT.

These helper routines can be used by platform support code and FDT
fixup code.

Signed-off-by: Anup Patel <anup.patel@wdc.com>
Reviewed-by: Atish Patra <atish.patra@wdc.com>
2020-12-04 21:10:44 +05:30
Anup Patel
c0d2baa8c0 docs: Add domain device tree binding documentation
This patch adds domain device tree binding documentation in the
OpenSBI domain support documentation.

Signed-off-by: Anup Patel <anup.patel@wdc.com>
Reviewed-by: Atish Patra <atish.patra@wdc.com>
2020-12-04 18:58:12 +05:30
Anup Patel
9b65dcaedd include: sbi: Add domains_init() platform operation
We introduce domains_init() platform operation which can be used by
platform support to initialize/populate domains in the coldboot path.

The domains_init() is called late in the coldboot sequence from the
sbi_domain_finalize() so sbi_printf() can be used by platform support
to print errors/warnings at time of populating domains.

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-12-04 18:01:00 +05:30
Anup Patel
555e73778a lib: sbi: Add error prints in sbi_domain_finalize()
We add error prints in sbi_domain_finalize() and sanitize_domain()
to help debug domain configuration issues.

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-12-04 18:00:04 +05:30
Anup Patel
62ea4f4e2a lib: sbi: Override domain boot HART when coldboot HART assigned to it
If coldboot HART is assigned to a domain then we should use coldboot
HART as the boot HART of the domain. This allows coldboot HART to
continue boot sequence even when it is assigned to some non-root domain.

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-12-04 17:58:59 +05:30
Anup Patel
c1f6d89678 include: sbi: Use lower bits for domain memory region permissions
We should use lower bits for domain memory region access permissions
and higher bits for other domain memory region attributes. This helps
us use same bit assignment for parsing domain memory region access
permissions from device tree.

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-12-04 17:58:20 +05:30
Anup Patel
c709d40a67 lib: sbi: Auto start domain only if boot HART within limits
The sbi_domain_finalize() should auto start a domain only if the
boot HART is withing limits (i.e. less than SBI_HARTMASK_MAX_BITS).

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-12-04 17:57:46 +05:30
Anup Patel
4e370224df lib: sbi: Fix domain_count check in sbi_domain_finalize()
The domain_count check in sbi_domain_finalize() for newly discovered
domain is incorrect and should be reversed.

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-12-04 17:57:15 +05:30
Anup Patel
3d921fad0d lib: sbi: Fix typo in sbi_domain_finalize()
There has been typo in automatic domain boot hart startup
for non-root domains so this patch fixes it.

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-12-04 17:56:43 +05:30
Anup Patel
8d2edc4fc9 lib: sbi: Fix sbi_hart_switch_mode() for u-mode
We should check and access N-extension CSRs in sbi_hart_switch_mode()
when next_mode is u-mode because N-extension is optional.

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-12-04 17:56:10 +05:30
Anup Patel
2677324f90 firmware: fw_base: Optimize trap handler for RV32 systems
On RV32 systems, we have two CSRs for M-mode status (MSTATUS and
MSTATUSH) when H-extension is implemented. This means we have to
save/restore MSTATUSH for RV32 systems only when H-extension is
implemented. The current _trap_handler() has extra instructions
(roughly 10) for conditional save/restore of MSTATUSH CSR.

These extra instructions in RV32 _trap_handler() can be avoided
if we create separate low-level trap handler for RV32 systems
having H-extension. This patch optimizes low-level trap handler
for RV32 systems accordingly.

Signed-off-by: Anup Patel <anup.patel@wdc.com>
Reviewed-by: Alistair Francis <alistair.francis@wdc.com>
2020-12-01 17:14:32 +05:30
Anup Patel
548d03e577 lib: sbi: Implement System Reset (SRST) SBI extension
The SBI SRST extension has been accepted and merged in the latest
SBI v0.3-draft specification.
(Refer, https://github.com/riscv/riscv-sbi-doc)

It allows to S-mode software to request system shutdown, cold reboot,
and warm reboot.

This patch implements SBI SRST extension as a replacement of the
legacy sbi_shutdown() call of SBI v0.1 specification.

Signed-off-by: Anup Patel <anup.patel@wdc.com>
Reviewed-by: Atish Patra <atish.patra@wdc.com>
2020-12-01 17:11:11 +05:30
Anup Patel
5c429ae213 lib: sbi: Improve system reset platform operations
To implement the SBI SRST extension, we need two platform operations
for system reset:
1) system_reset_check() - This operation will check whether given
   reset type and reason are supported by the platform
2) system_reset() - This operation will do the actual platform
   system reset and it will not return if reset type and reason
   are supported by the platform

This patch updates system reset related code everywhere as-per above.

Signed-off-by: Anup Patel <anup.patel@wdc.com>
Reviewed-by: Atish Patra <atish.patra@wdc.com>
2020-12-01 17:10:31 +05:30
Anup Patel
da074796df platform: Remove dummy system reset functions
Few platforms have dummy system reset functions so let's remove
these dummy system reset functions to allow generic code deal
with it in the right way.

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-12-01 17:08:47 +05:30
Anup Patel
c4acc60a46 include: sbi: Remove opensbi specific reset type defines
We can now use the standard SBI SRST extension reset types instead
of the opensbi specific (SBI_PLATFORM_RESET_xyz) reset types hence
remove related opensbi specific defines. The "platform_" prefix of
the reset type parameter of sbi_system_reset() function should also
be removed.

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-12-01 17:05:12 +05:30
Anup Patel
54a7734d86 include: sbi: Add SBI SRST extension related defines
We extend the SBI ecall interface header for the SBI SRST extension
recently accepted in SBI specification v0.3-draft.

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-12-01 17:03:50 +05:30
Yuan Li
781cafdbee docs: fix a typo error
fix a typo error in docs/platform/sifive_fu540.md

Signed-off-by: Yuan Li <dskwelmcy@163.com>
Reviewed-by: Atish Patra <atish.patra@wdc.com>
2020-11-27 13:36:50 +05:30
Anup Patel
48616b3de2 lib: sbi: Improve boot prints in cold boot sequence
Currently, we have all boot prints at the end of cold boot sequence
which means if there is any failure in cold boot sequence before
boot prints then we don't get any print.

This patch improves boot prints in cold boot sequence as follows:
1. We divide the boot prints into multiple parts and print it
   from different locations after sbi_console_init()
2. We throw an error print if there is any failure in cold boot
   sequence after sbi_console_init()

Signed-off-by: Anup Patel <anup.patel@wdc.com>
Reviewed-by: Atish Patra <atish.patra@wdc.com>
2020-11-10 10:29:23 +05:30
Anup Patel
914f81fbee Makefile: Add option to use toolchain default ABI and ISA string
When PLATFORM_RISCV_ABI and PLATFORM_RISCV_ISA are not specified,
we force "-mabi=lp64 -march=rv64gc" for RV64 and force "-mabi=ilp32
-march=rv32gc" for RV32. This can prevent users from using the
toolchain default "-mabi" and "-march" options.

To allow using toolchain defaults, we add compile-time option
PLATFORM_RISCV_TOOLCHAIN_DEFAULT which when enabled forces the
top-level makefile to use toolchain default ABI and ISA string.

To enable the option, pass "PLATFORM_RISCV_TOOLCHAIN_DEFAULT=1"
to top-level make.

Reported-by: Alistair Francis <alistair.francis@wdc.com>
Signed-off-by: Anup Patel <anup.patel@wdc.com>
Reviewed-by: Alistair Francis <alistair.francis@wdc.com>
2020-11-02 09:21:50 +05:30
Atish Patra
a809f406b9 lib: sbi: Improve boot time print with additional PMP information
We know about pmp granularity and number of bits supported by PMP.
Show those information in the boot time info print

Signed-off-by: Atish Patra <atish.patra@wdc.com>
Reviewed-by: Anup Patel <anup.patel@wdc.com>
2020-10-26 22:59:09 +05:30
Atish Patra
bf21632860 lib: sbi: Detect PMP granularity and number of address bits
As per RISC-V privilege specification, a platform may choose to implement
a coarser granularity scheme for PMP addresses. In that case, we shouldn't
allow any pmp region size smaller than the platform supports. A platform
may not also implement all the bits for a PMP address specified in the priv
specification.

The pmp range granularity and address bits should be detected dynamically
before detecing PMP regions. Any pmp modification request beyond these detected
value must not succeed.

Signed-off-by: Atish Patra <atish.patra@wdc.com>
Reviewed-by: Anup Patel <anup.patel@wdc.com>
2020-10-26 22:44:52 +05:30
Atish Patra
74c0ea1e83 lib: utils: Implement "ranges" property parsing
The "reg" property in a device node may not be the correct address always.
If a parent node defines a "ranges" property, the child address need to be
translated with respect to parents address. If the ranges property is not
present, it will just use 1:1 translation.

Signed-off-by: Atish Patra <atish.patra@wdc.com>
Reviewed-by: Anup Patel <anup.patel@wdc.com>
2020-10-23 17:19:21 +05:30
Anup Patel
fdf5d5c322 docs: Add initial documentation for domain support
We add initial documentation for OpenSBI domain support to help
RISC-V platform vendors achieve system-level partitioning.

Signed-off-by: Anup Patel <anup.patel@wdc.com>
Reviewed-by: Atish Patra <atish.patra@wdc.com>
2020-10-21 12:29:36 +05:30
Anup Patel
c347408a39 lib: sbi: Display domain details in boot prints
We extend boot prints to display details of each domain. In the
process, we remove sbi_hart_pmp_dump() because it shows redundant
information which domain details already show.

Signed-off-by: Anup Patel <anup.patel@wdc.com>
Reviewed-by: Atish Patra <atish.patra@wdc.com>
2020-10-21 12:01:34 +05:30
Anup Patel
c10c30b485 lib: sbi: Configure PMP based on domain memory regions
The PMP configuration on each HART should be only based on the memory
regions of the assigned domain because each domain includes a memory
region to protect the underlying firmware.

This patch updates the sbi_hart_pmp_configure() function accordingly.

Signed-off-by: Anup Patel <anup.patel@wdc.com>
Reviewed-by: Atish Patra <atish.patra@wdc.com>
2020-10-20 14:12:54 +05:30
Anup Patel
e856462ac2 lib: sbi: Remove redundant sbi_hart_pmp_xyz() functions
The sbi_hart_pmp_get() and sbi_hart_pmp_check_addr() functions
are not used anymore hence this patch removes these functions.

Signed-off-by: Anup Patel <anup.patel@wdc.com>
Reviewed-by: Atish Patra <atish.patra@wdc.com>
2020-10-20 14:12:26 +05:30
Anup Patel
5fd99dbdaa lib: utils: Update fdt_cpu_fixup() to use current domain
The fdt_cpu_fixup() should disable a HART in DT if the HART
is not assigned to the current HART domain. This patch updates
fdt_cpu_fixup() accordingly.

Signed-off-by: Anup Patel <anup.patel@wdc.com>
Reviewed-by: Atish Patra <atish.patra@wdc.com>
2020-10-20 14:04:51 +05:30
Anup Patel
5edbb7cda1 lib: utils: Update fdt_reserved_memory_fixup() to use current domain
Now that each HART is mapped to a domain having a set of memory
regions, we update fdt_reserved_memory_fixup() to use domain memory
regions for adding reserved memory nodes in device tree.

We also change reserved memory node name prefix from "mmode_pmp"
to "mmode_resv" because domain memory regions can impact other
hardware configurations (such as IOPMP, etc) along with PMP.

Signed-off-by: Anup Patel <anup.patel@wdc.com>
Reviewed-by: Atish Patra <atish.patra@wdc.com>
2020-10-20 14:04:43 +05:30
Anup Patel
3e200370ee lib: sbi: Extend sbi_system_reset() for domains
The sbi_system_reset() should issue platform system reset only if
domain of current HART is allowed to do system reset.

This patch extends sbi_system_reset() as-per above.

Signed-off-by: Anup Patel <anup.patel@wdc.com>
Reviewed-by: Atish Patra <atish.patra@wdc.com>
2020-10-20 14:03:40 +05:30
Anup Patel
530e95bd63 lib: sbi: Optimize sbi_hsm_hart_started_mask() implementation
Instead of calling sbi_hsm_hart_get_state() in a loop, we can simply
call a new inline __sbi_hsm_hart_get_state() which only takes "hartid"
and enforce domain checks using sbi_domain_assigned_hartmask().

This patch optimizes sbi_hsm_hart_started_mask() as-per above.

Signed-off-by: Anup Patel <anup.patel@wdc.com>
Reviewed-by: Atish Patra <atish.patra@wdc.com>
2020-10-20 14:00:06 +05:30
Anup Patel
3a30d2c34d lib: sbi: Extend sbi_hsm_hart_start() for domains
The sbi_hsm_hart_start() should consider the domain under which we
are trying to start the HART. This will help ensure that HART A can
start HART B only if both HARTs A and B belong to the same domain.

We also have a special case when we bring-up boot HART of non-root
domains in sbi_domain_finalize() where we should skip domain checks
in sbi_hsm_hart_start(). To achieve this, sbi_hsm_hart_start() should
do domain checks only when domain parameter is non-NULL.

This patch extends sbi_hsm_hart_start() as-per above.

Signed-off-by: Anup Patel <anup.patel@wdc.com>
Reviewed-by: Atish Patra <atish.patra@wdc.com>
2020-10-20 13:56:36 +05:30
Anup Patel
e73b92d862 lib: sbi: Extend sbi_hsm_hart_started_mask() for domains
The sbi_hsm_hart_started_mask() API should take one more parameter
to allow caller specify domain under which started_mask is being
generated. Further, the sbi_hsm_hart_started_mask() depends on
sbi_hsm_hart_get_state() which also should return HART state under
specified domain.

This patch updates both sbi_hsm_hart_started_mask() and
sbi_hsm_hart_get_state() as-per above.

Signed-off-by: Anup Patel <anup.patel@wdc.com>
Reviewed-by: Alistair Francis <alistair.francis@wdc.com>
2020-10-20 11:32:40 +05:30
Anup Patel
b1678af210 lib: sbi: Add initial domain support
An OpenSBI domain is a logical entity representing a set of HARTs
and a set of memory regions for these HARTs.

The OpenSBI domains support will allow OpenSBI platforms and previous
booting stage (i.e. U-Boot SPL, Coreboot, etc) to partition a system
into multiple domains where each domain will run it's own software.

For inter-domain isolation, OpenSBI will eventually use various HW
features such as PMP, ePMP, IOPMP, SiFive shield, etc but initial
implementation only use HW PMP support.

This patch provides initial implementation of OpenSBI domains where
we have a root/default domain and OpenSBI platforms can provide
non-root/custom domains using domain_get() callback.

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-10-20 11:22:15 +05:30
Anup Patel
8b650050ec include: sbi: Make hartmask pointer const in sbi_hartmask_test_hart()
The sbi_hartmask_test_hart() does not modify hartmask so the
hartmask pointer parameter should be declared const.

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-10-20 11:19:13 +05:30
Anup Patel
f81d6f6f43 lib: sbi: Remove redundant hartid parameter from sbi_hart_init()
The hartid parameter of sbi_hart_init() is not used anywhere in
sbi_hart_init() implementation so let's remove it.

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-10-20 11:18:28 +05:30
Anup Patel
a126886bfa lib: sbi: Configure PMP late in coldboot and warmboot path
We factor-out PMP configuration from sbi_hart_init() as a separate
sbi_hart_pmp_configure() function and do the PMP configuration very
late in coldboot and warmboot path just before platform_final_init().

Eventually, this enable us to configure PMP totally based on OpenSBI
domain where OpenSBI domains can be parsed from device-tree in any of
the platform operations except platform_final_init().

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-10-20 11:18:03 +05:30
Anup Patel
a12d46a5e7 include: sbi: Remove pmp_region callbacks from sbi_platform_operations
The pmp_region_xyz() callbacks are not required in sbi_platform_operations
because we will be using OpenSBI domain memory regions to program the
PMP CSRs.

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-10-20 11:17:15 +05:30
Anup Patel
dbeeacb878 include: sbi: Remove redundant includes from sbi_platform.h
The sbi_ecall.h and sbi_trap.h are not required to be included in
sbi_platform.h hence we remove it. This way sources requiring
these headers will have to explicitly include it thereby reducing
implicit includes.

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-10-20 11:16:37 +05:30
Anup Patel
a0f2d4a10c platform: kendryte/k210: Add some padding for FDT fixups
The Kendryte K210 platform has built-in DTB and does not provides
FW_PAYLOAD_FDT_ADDR. This means the FDT fixups will be done on
the built-in DTB in absence of FW_PAYLOAD_FDT_ADDR. This patch
adds some padding in built-in DTB for FDT fixups.

Signed-off-by: Anup Patel <anup.patel@wdc.com>
Reviewed-by: Atish Patra <atish.patra@wdc.com>
2020-10-18 10:34:37 +05:30
Heinrich Schuchardt
e9a4bfb7b5 Makefile: Allow padding zeros when converting DTB to C source
We extend d2c.sh to allow padding zeros in output C source when
converting DTB to C source. Using this feature, platforms can
create extra room for in-place FDT fixups on built-in DTBs.

Signed-off-by: Heinrich Schuchardt <xypron.glpk@gmx.de>
Signed-off-by: Anup Patel <anup.patel@wdc.com>
Reviewed-by: Atish Patra <atish.patra@wdc.com>
2020-10-18 10:33:57 +05:30
Anup Patel
9c07c513aa firmware: Remove FW_PAYLOAD_FDT_PATH compile-time option
The FW_PAYLOAD_FDT_PATH compile-time option is replaced by
FW_FDT_PATH compile-time option which is more flexible and
common across all OpenSBI firmwares.

This patch removes FW_PAYLOAD_FDT_PATH and updates related
documentation to use FW_FDT_PATH.

Signed-off-by: Anup Patel <anup.patel@wdc.com>
Reviewed-by: Atish Patra <atish.patra@wdc.com>
2020-10-18 10:29:59 +05:30
Anup Patel
6ca096977d firmware: Add common FW_FDT_PATH compile-time option
Currently, only FW_PAYLOAD has mechanism to embed external
FDT using FW_PAYLOAD_FDT_PATH compile-time option.

This patch adds a common FW_FDT_PATH compile-time option to
embed external FDT for all OpenSBI firmwares (i.e FW_JUMP,
FW_PAYLOAD, and FW_DYNAMIC).

Signed-off-by: Anup Patel <anup.patel@wdc.com>
Reviewed-by: Atish Patra <atish.patra@wdc.com>
2020-10-18 10:28:26 +05:30
Anup Patel
af4b50f896 Makefile: Build ELF, BIN and LD script in platform build directory
Currently, the make rules for ELF, BIN and LD script are little
generic to allowing ELF, BIN and LD script to be anywhere in the
build directory. For OpenSBI firmwares, the ELF, BIN, and LD script
are always platform specific so we update make rules accordingly.

Signed-off-by: Anup Patel <anup.patel@wdc.com>
Reviewed-by: Atish Patra <atish.patra@wdc.com>
2020-10-18 10:14:17 +05:30
Damien Le Moal
a04c46506a makefile: fix clean directive
Add cleaning of compiled device tree files (.dtb files).

Signed-off-by: Damien Le Moal <damien.lemoal@wdc.com>
Reviewed-by: Anup Patel <anup.patel@wdc.com>
2020-10-10 11:02:23 +05:30
Heinrich Schuchardt
79bf80b44e lib: sbi_scratch: typo scatch
%s/scatch/scratch

Signed-off-by: Heinrich Schuchardt <xypron.glpk@gmx.de>
Reviewed-by: Anup Patel <anup.patel@wdc.com>
2020-10-02 15:50:55 +05:30
Pragnesh Patel
7701ea13be lib: sbi: Fix PMP CSR detection
HiFive unleashed currently implements fewer than 56 bits of physical
address so existing PMP CSR detection is broken.

PMP address register encodes bits 55-2 of a 56-bit physical address,
Not all physical address bits may be implemented, So just check
minimum 1 bit.

Fixes: 74d1db7062 ("lib: sbi: Improve PMP CSR detection and
progamming")

Signed-off-by: Pragnesh Patel <pragnesh.patel@sifive.com>
Reviewed-by: Atish Patra <atish.patra@wdc.com>
Reviewed-by: Anup Patel <anup.patel@wdc.com>
2020-09-25 14:22:22 +05:30
Anup Patel
aaeca7eb4e platform: generic: Don't mark non-MMU HARTs as invalid
Currently, the generic platform fw_platform_init() marks non-MMU
HARTs (e.g. E-core on SiFive Unleashed) as invalid. This means
such non-MMU HARTs won't be allowed to go ahead by sbi_init().

The sbi_init() now has a check for next stage privilege mode when
selecting coldboot HART. This check will force non-MMU HARTS (i.e.
HARTs without S-mode) to proceed in warmboot path and wait in the
HSM STOPPED state. This means we don't need to mark non-MMU HARTs
as invalid in generic platform fw_platform_init().

Signed-off-by: Anup Patel <anup.patel@wdc.com>
Reviewed-by: Atish Patra <atish.patra@wdc.com>
2020-09-16 09:05:31 +05:30
Anup Patel
172fa1601c lib: sbi: Ensure coldboot HART supports next privilege mode
The coldboot HART jumps to the next booting stage at the end of
init_coldboot() so it is absolutely necessary for coldboot HART
to support the privilege mode expected by the next booting stage.

We extend the coldboot HART selection in sbi_init() to ensure that
the selected coldboot HART always supports privilege mode specified
in scratch space (i.e. scratch->next_mode). This will further help
us allow E-core (without MMU) on SiFive Unleashed and PolarFire
ICICLE boards to proceed further and wait in HSM STOPPED state.

Signed-off-by: Anup Patel <anup.patel@wdc.com>
Reviewed-by: Atish Patra <atish.patra@wdc.com>
2020-09-16 09:05:29 +05:30
Anup Patel
9f935a4a43 lib: utils: Improve fdt_cpu_fixup() implementation
The fdt_cpu_fixup() should work fine even if HARTs without MMU
are not marked invalid by platform support code.

In future, we plan to treat HARTs without MMU as valid in the
generic platform support so that we can hold these HARTs in
HSM STOPPED state.

Signed-off-by: Anup Patel <anup.patel@wdc.com>
Reviewed-by: Atish Patra <atish.patra@wdc.com>
2020-09-16 09:05:27 +05:30
Anup Patel
7ccf6bf54c lib: sbi: Allow specifying mode in sbi_hart_pmp_check_addr() API
We extend sbi_hart_pmp_check_addr() API so that users can specify
privilege mode of the address for checking PMP access permissions.

To achieve this, we end-up converting "unsigned long *size" parameter
to "unsigned long *log2len" for pmp_get() implementation so that we
can deal with regions of "1UL << __riscv_xlen" size in a special case
in sbi_hart_pmp_check_addr() implementation.

Signed-off-by: Anup Patel <anup.patel@wdc.com>
Reviewed-by: Atish Patra <atish.patra@wdc.com>
2020-09-16 09:05:25 +05:30
Anup Patel
6734304f8c lib: sbi: Allow specifying start mode to sbi_hsm_hart_start() API
The sbi_scratch already has provision to specify the next stage mode
so we can leverage this to specify start mode to sbi_hsm_hart_start().

In future, this will be useful in providing SBI calls to U-mode on
embedded cores where we M-mode and U-mode but no S-mode.

Signed-off-by: Anup Patel <anup.patel@wdc.com>
Reviewed-by: Atish Patra <atish.patra@wdc.com>
2020-09-16 09:05:22 +05:30
Anup Patel
c1c7c3ee9e lib: sbi_trap: Allow M-mode to M-mode ECALLs
We should allow M-mode to M-mode ECALLs because:
1. No other mode can handle M-mode ECALLs
2. In future, we can allow M-mode baremetal application (not
   linked to OpenSBI) running independently and cooperatively
   without corrupting OpenSBI M-mode state (CSRs and memory).

Signed-off-by: Anup Patel <anup.patel@wdc.com>
Reviewed-by: Atish Patra <atish.patra@wdc.com>
2020-09-09 09:32:04 +05:30
Anup Patel
bef63d6848 include: Rename ECALL defines to match latest RISC-V spec
We rename CAUSE_HYPERVISOR_ECALL to CAUSE_SUPERVISOR_ECALL and
CAUSE_SUPERVISOR_ECALL to CAUSE_VIRTUAL_SUPERVISOR_ECALL so that
it matches latest RISC-V privilege spec.

Signed-off-by: Anup Patel <anup.patel@wdc.com>
Reviewed-by: Atish Patra <atish.patra@wdc.com>
2020-09-09 09:32:02 +05:30
Anup Patel
dcb10c0056 lib: sbi: Don't handle VS-mode ecall in sbi_trap_handler()
The VS-mode ecall is supposed to be handled by HS-mode so
sbi_trap_handler() should fallback to default case for
VS-mode ecall trap.

Signed-off-by: Anup Patel <anup.patel@wdc.com>
Reviewed-by: Atish Patra <atish.patra@wdc.com>
2020-09-09 09:32:00 +05:30
Anup Patel
ebc8ebc0f8 lib: sbi: Improve HPM CSR read/write emulation
We improve HPM CSR read/write emulation as follows:
1. Fail for unimplemented counters so that trap is redirected
   to S-mode which can further help debugging S-mode software.
2. Check permissions in both MCOUNTEREN and SCOUNTEREN for
   HS-mode and U-mode.
3. Don't check permissions for TIME CSR because we emulate
   TIME CSR for both Host (HS/U-mode) and Guest (VS/VU-mode).
   Also, faster TIME CSR read is very helpful for good
   performance of S-mode software.
4. Don't emulate S-mode CSR read/write to M-mode HPM CSRs
   because these should not be accessible to S-mode software.

Signed-off-by: Anup Patel <anup.patel@wdc.com>
Reviewed-by: Atish Patra <atish.patra@wdc.com>
2020-09-01 10:28:35 +05:30
Anup Patel
162d453b49 include: sbi: Few cosmetic changes in riscv_encoding.h
This patch does following cosmentic changes to riscv_encoding.h:
1. Re-organize CSR defines to match CSR listing in latest RISC-V
   privilege spec
2. Rename CSR_HCOUNTERNEN to CSR_HCOUNTEREN

Signed-off-by: Anup Patel <anup.patel@wdc.com>
Reviewed-by: Atish Patra <atish.patra@wdc.com>
2020-09-01 10:28:33 +05:30
Anup Patel
2c341f7844 lib: sbi: Detect and print MHPM counters at boot-time
A RISC-V platform can leave unimplemented MHPM counters hard-wired
to zero. We extend hart_detect_features() to detect MHPM counters
which are accessible and not hard-wired to zero. We also print
number of available MHPM counters as part of boot prints.

Signed-off-by: Anup Patel <anup.patel@wdc.com>
Reviewed-by: Atish Patra <atish.patra@wdc.com>
2020-09-01 10:28:31 +05:30
Anup Patel
74d1db7062 lib: sbi: Improve PMP CSR detection and progamming
As-per latest RISC-V privilege spec up to 64 PMP entries are supported.
Implementations may implement zero, 16, or 64 PMP CSRs. All PMP CSR
fields are WARL and may be hardwired to zero.

This patch improves PMP CSR detection and progamming considering
above facts.

Signed-off-by: Anup Patel <anup.patel@wdc.com>
Reviewed-by: Atish Patra <atish.patra@wdc.com>
2020-09-01 10:28:28 +05:30
Anup Patel
7b0b289887 lib: sbi: Remove redundant SBI_HART_HAS_PMP feature
The SBI_HART_HAS_PMP feature is redundant because we already
have number of PMP regions returned by sbi_hart_pmp_count().

Checking whether PMP is supported for a HART can be simply done
by checking non-zero value returned by sbi_hart_pmp_count().

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-09-01 10:28:26 +05:30
Anup Patel
4f3bad6e43 lib: sbi: Handle the case where MTVAL has illegal instruction address
The Kendryte K210 follows RISC-V v1.9 spec so MTVAL has instruction
address (instead of instruction encoding) on illegal instruction trap.

To handle above case, we fix sbi_illegal_insn_handler() without any
impact on RISC-V v1.10 (or higher) systems. This achieved by exploiting
the fact that program counter (and instruction address) is always 2-byte
aligned in RISC-V world.

Signed-off-by: Anup Patel <anup.patel@wdc.com>
Tested-by: Heinrich Schuchardt <xypron.glpk@gmx.de>
Reviewed-by: Bin Meng <bin.meng@windriver.com>
Reviewed-by: Atish Patra <atish.patra@wdc.com>
2020-08-21 19:35:31 +05:30
Anup Patel
e435ba0524 lib: sbi_init: Avoid thundering hurd problem with coldboot_lock
We can have thundering hurd problem with coldboot_lock where the
boot HART can potentially starve trying to acquire coldboot_lock
because some of the non-boot HARTs are continuously acquiring and
releasing coldboot_lock. This can happen if MIP.MSIP bit is already
set for some of the non-boot HARTs.

To avoid thundering hurd problem for coldboot_lock, we use the
__smp_load_acquire() and __smp_store_release() for coldboot_done
flag and use coldboot_lock only for coldboot_wait_hmask.

Signed-off-by: Anup Patel <anup.patel@wdc.com>
Tested-by: Heinrich Schuchardt <xypron.glpk@gmx.de>
Reviewed-by: Atish Patra <atish.patra@wdc.com>
Reviewed-by: Bin Meng <bin.meng@windriver.com>
2020-08-21 19:35:28 +05:30
Heinrich Schuchardt
d7f87d99a3 platform: kendryte/k210: fixup FDT
When passing the device tree to the next stage we should apply necessary
device tree fix-ups first. These include:

* fix up the CPU node in the device tree
* fix up the PLIC node in the device tree
* fix up the reserved memory node in the device tree

Signed-off-by: Heinrich Schuchardt <xypron.glpk@gmx.de>
Reviewed-by: Atish Patra <atish.patra@wdc.com>
2020-08-20 15:07:52 +05:30
Georg Kotheimer
9d56961b23 lib: sbi_trap: Fix hstatus.SPVP update in sbi_trap_redirect()
When redirecting from VS/VU-mode to HS-mode, hstatus.SPVP was set
to the value of mstatus.SPP, as according to the specification both
flags should be set to the same value.
However, the assignment of SPVP takes place before SPP itself is
updated, which results in SPVP having an outdated value.

Signed-off-by: Georg Kotheimer <georg.kotheimer@tu-dresden.de>
Reviewed-by: Anup Patel <anup.patel@wdc.com>
2020-08-17 18:17:42 +05:30
Anup Patel
4b18a2acc2 firmware: fw_base: Improve exception stack setup in trap handler
Currently, the low-level trap handler (i.e. _trap_handler()) uses
branch instructions to conditionally setup exception stack based
on which mode trap occured.

This patch implements exception stack setup using xor instructions
which is faster with same number of instructions due to lack of
branch instructions.

The new exception stack setup approach can be best described by the
following pseudocode:

 Came_From_M_Mode = ((MSTATUS.MPP < PRV_M) ? 1 : 0) - 1;
 Exception_Stack = TP ^ (Came_From_M_Mode & (SP ^ TP))

 Came_From_M_Mode = 0    ==>    Exception_Stack = TP
 Came_From_M_Mode = -1   ==>    Exception_Stack = SP

Signed-off-by: Anup Patel <anup.patel@wdc.com>
Reviewed-by: Atish Patra <atish.patra@wdc.com>
2020-08-14 14:35:47 +05:30
Anup Patel
937caee083 lib: sbi_misaligned_ldst: Determine transformed instruction length correctly
If MTINST[0:0] bit is 1 then we have transformed instruction encoding
in MTINST CSR. For transformed instructions, if the MTINST[1:1] bit
is Zero then original trapped instruction was a 16bit instruction
which was converted to 32bit instruction at time of taking trap.

We should use MTINST[1:1] bit to determine correct instruction length
of transformed instruction.

This patch updates misaligned load/store emulation as-per above.

Signed-off-by: Anup Patel <anup.patel@wdc.com>
Reviewed-by: Atish Patra <atish.patra@wdc.com>
2020-08-04 08:48:41 +05:30
Abner Chang
2cfd2fc904 lib: utils: Use strncmp in fdt_parse_hart_id()
Use strncmp instead of using sbi_strcmp directly in fdt_parse_hart_id()
to allow compiling fdt_helper.c by external firmware.

Signed-off-by: Abner Chang <abner.chang@hpe.com>
Reviewed-by: Atish Patra <atish.patra@wdc.com>
Reviewed-by: Anup Patel <anup.patel@wdc.com>
2020-07-29 12:13:51 +05:30
Abner Chang
2845d2d2cf lib: utils: Add a macro in libfdt_env.h for strncmp
This commit add a macro to replace strncmp with sbi_strncmp.

Signed-off-by: Abner Chang <abner.chang@hpe.com>
Reviewed-by: Atish Patra <atish.patra@wdc.com>
Reviewed-by: Anup Patel <anup.patel@wdc.com>
2020-07-29 12:06:15 +05:30
Abner Chang
8e47649eff lib: Add sbi_strncmp implementation
This commit add an implementation of sbi_strncmp.

Signed-off-by: Abner Chang <abner.chang@hpe.com>
Reviewed-by: Atish Patra <atish.patra@wdc.com>
Reviewed-by: Anup Patel <anup.patel@wdc.com>
2020-07-29 12:03:45 +05:30
Tobias Klauser
ec1abf6657 include: sbi_bitops: Remove dead shift assignment in ffs/fls
The value assigned to x by the shift assignment in the last if block of
ffs/fls is never read. Remove it.

Signed-off-by: Tobias Klauser <tklauser@distanz.ch>
Reviewed-by: Anup Patel <anup.patel@wdc.com>
2020-07-14 17:03:30 +05:30
Bin Meng
a5f9104330 lib/utils: fdt: Update FDT expand size to 1024 for reserved memory node
Currently 256 bytes is used for the FDT expand size when fixing up
reserved memory node. Increase it to 1024 bytes with an estimated
size of 64 bytes per PMP memory region by 16 regions in total.

Signed-off-by: Bin Meng <bin.meng@windriver.com>
Reviewed-by: Atish Patra <atish.patra@wdc.com>
2020-07-06 14:05:29 +05:30
Tobias Klauser
7d61a68775 README.md: fix markdown link formatting
Consistently use reference-style markdown links in the README. This
won't show the URL next to the linked text for the [Github] and [U-Boot]
links and link the text "Bootlin toolchain repository" instead of
showing it verbatim with the URL next to it.

Signed-off-by: Tobias Klauser <tklauser@distanz.ch>
Reviewed-by: Bin Meng <bin.meng@windriver.com>
Reviewed-by: Anup Patel <anup.patel@wdc.com>
2020-07-04 09:58:03 +05:30
Bin Meng
ec3e5b14d5 docs/platform: sifive_fu540: Update U-Boot instructions
U-Boot v2020.07 release adds SPL support to SiFive HiFive Unleashed.
Update the doc to mention that detailed build instructions are in the
U-Boot doc.

This also adds detailed command line description to show how to boot
U-Boot v2020.07 S-mode payload in the QEMU chapter.

Signed-off-by: Bin Meng <bin.meng@windriver.com>
Reviewed-by: Atish Patra <atish.patra@wdc.com>
2020-06-29 09:17:58 +05:30
Bin Meng
78afe11ba2 config.mk: Update QEMU run command for generic and sifive fu540 platforms
Since QEMU v5.1, if there is no "-bios" option provided, the default
OpenSBI firmware will be loaded by QEMU as the BIOS automatically,
hence to load fw_payload type image, we should explicitly pass the
"-bios" option to QEMU.

Signed-off-by: Bin Meng <bin.meng@windriver.com>
Reviewed-by: Atish Patra <atish.patra@wdc.com>
2020-06-29 09:17:24 +05:30
Bin Meng
35bc810252 docs/platform: Update QEMU parameter for fw_payload
Since QEMU v5.1, if there is no "-bios" option provided, the default
OpenSBI firmware will be loaded by QEMU as the BIOS automatically,
hence to load fw_payload type image, we should explicitly pass the
"-bios" option to QEMU.

Signed-off-by: Bin Meng <bin.meng@windriver.com>
Reviewed-by: Atish Patra <atish.patra@wdc.com>
2020-06-29 09:16:40 +05:30
94 changed files with 3550 additions and 1214 deletions

View File

@@ -94,6 +94,8 @@ DTC = dtc
# Guess the compillers xlen
OPENSBI_CC_XLEN := $(shell TMP=`$(CC) -dumpmachine | sed 's/riscv\([0-9][0-9]\).*/\1/'`; echo $${TMP})
OPENSBI_CC_ABI := $(shell TMP=`$(CC) -v 2>&1 | sed -n 's/.*\(with\-abi=\([a-zA-Z0-9]*\)\).*/\2/p'`; echo $${TMP})
OPENSBI_CC_ISA := $(shell TMP=`$(CC) -v 2>&1 | sed -n 's/.*\(with\-arch=\([a-zA-Z0-9]*\)\).*/\2/p'`; echo $${TMP})
# Setup platform XLEN
ifndef PLATFORM_RISCV_XLEN
@@ -143,14 +145,22 @@ deps-y+=$(firmware-objs-path-y:.o=.dep)
# Setup platform ABI, ISA and Code Model
ifndef PLATFORM_RISCV_ABI
ifeq ($(PLATFORM_RISCV_XLEN), 32)
PLATFORM_RISCV_ABI = ilp$(PLATFORM_RISCV_XLEN)
ifneq ($(PLATFORM_RISCV_TOOLCHAIN_DEFAULT), 1)
ifeq ($(PLATFORM_RISCV_XLEN), 32)
PLATFORM_RISCV_ABI = ilp$(PLATFORM_RISCV_XLEN)
else
PLATFORM_RISCV_ABI = lp$(PLATFORM_RISCV_XLEN)
endif
else
PLATFORM_RISCV_ABI = lp$(PLATFORM_RISCV_XLEN)
PLATFORM_RISCV_ABI = $(OPENSBI_CC_ABI)
endif
endif
ifndef PLATFORM_RISCV_ISA
PLATFORM_RISCV_ISA = rv$(PLATFORM_RISCV_XLEN)imafdc
ifneq ($(PLATFORM_RISCV_TOOLCHAIN_DEFAULT), 1)
PLATFORM_RISCV_ISA = rv$(PLATFORM_RISCV_XLEN)imafdc
else
PLATFORM_RISCV_ISA = $(OPENSBI_CC_ISA)
endif
endif
ifndef PLATFORM_RISCV_CODE_MODEL
PLATFORM_RISCV_CODE_MODEL = medany
@@ -291,7 +301,10 @@ compile_dts = $(CMD_PREFIX)mkdir -p `dirname $(1)`; \
$(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)
$(if $($(2)-varalign-$(3)),$(eval D2C_ALIGN_BYTES := $($(2)-varalign-$(3))),$(eval D2C_ALIGN_BYTES := $(4))) \
$(if $($(2)-varprefix-$(3)),$(eval D2C_NAME_PREFIX := $($(2)-varprefix-$(3))),$(eval D2C_NAME_PREFIX := $(5))) \
$(if $($(2)-padding-$(3)),$(eval D2C_PADDING_BYTES := $($(2)-padding-$(3))),$(eval D2C_PADDING_BYTES := 0)) \
$(src_dir)/scripts/d2c.sh -i $(6) -a $(D2C_ALIGN_BYTES) -p $(D2C_NAME_PREFIX) -t $(D2C_PADDING_BYTES) > $(1)
compile_gen_dep = $(CMD_PREFIX)mkdir -p `dirname $(1)`; \
echo " GEN-DEP $(subst $(build_dir)/,,$(1))"; \
echo "$(1:.dep=$(2)): $(3)" >> $(1)
@@ -310,15 +323,6 @@ all: $(targets-y)
# Preserve all intermediate files
.SECONDARY:
$(build_dir)/%.bin: $(build_dir)/%.elf
$(call compile_objcopy,$@,$<)
$(build_dir)/%.elf: $(build_dir)/%.o $(build_dir)/%.elf.ld $(platform_build_dir)/lib/libplatsbi.a
$(call compile_elf,$@,$@.ld,$< $(platform_build_dir)/lib/libplatsbi.a)
$(platform_build_dir)/%.ld: $(src_dir)/%.ldS
$(call compile_cpp,$@,$<)
$(build_dir)/lib/libsbi.a: $(libsbi-objs-path-y)
$(call compile_ar,$@,$^)
@@ -340,6 +344,15 @@ $(build_dir)/%.dep: $(src_dir)/%.S
$(build_dir)/%.o: $(src_dir)/%.S
$(call compile_as,$@,$<)
$(platform_build_dir)/%.bin: $(platform_build_dir)/%.elf
$(call compile_objcopy,$@,$<)
$(platform_build_dir)/%.elf: $(platform_build_dir)/%.o $(platform_build_dir)/%.elf.ld $(platform_build_dir)/lib/libplatsbi.a
$(call compile_elf,$@,$@.ld,$< $(platform_build_dir)/lib/libplatsbi.a)
$(platform_build_dir)/%.ld: $(src_dir)/%.ldS
$(call compile_cpp,$@,$<)
$(platform_build_dir)/%.dep: $(platform_src_dir)/%.c
$(call compile_cc_dep,$@,$<)
@@ -361,7 +374,7 @@ $(platform_build_dir)/%.dep: $(platform_src_dir)/%.dts
$(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,$<)
$(call compile_d2c,$@,platform,$(subst .dtb,.o,$(subst /,-,$(subst $(platform_build_dir)/,,$<))),16,dt,$<)
$(platform_build_dir)/%.dtb: $(platform_src_dir)/%.dts
$(call compile_dts,$@,$<)
@@ -461,6 +474,8 @@ clean:
$(CMD_PREFIX)find $(build_dir) -type f -name "*.elf" -exec rm -rf {} +
$(if $(V), @echo " RM $(build_dir)/*.bin")
$(CMD_PREFIX)find $(build_dir) -type f -name "*.bin" -exec rm -rf {} +
$(if $(V), @echo " RM $(build_dir)/*.dtb")
$(CMD_PREFIX)find $(build_dir) -type f -name "*.dtb" -exec rm -rf {} +
# Rule for "make distclean"
.PHONY: distclean

View File

@@ -45,7 +45,7 @@ between:
executing in VS-mode.
The *RISC-V SBI specification* is maintained as an independent project by the
RISC-V Foundation on [Github] (https://github.com/riscv/riscv-sbi-doc).
RISC-V Foundation on [Github].
The goal of the OpenSBI project is to provide an open-source reference
implementation of the RISC-V SBI specifications for platform-specific firmwares
@@ -69,7 +69,7 @@ platform-dependent hardware manipulation functions. For all supported platforms,
OpenSBI also provides several runtime firmware examples built using the platform
*libplatsbi.a*. These example firmwares can be used to replace the legacy
*riscv-pk* bootloader (aka BBL) and enable the use of well-known bootloaders
such as [U-Boot] (https://git.denx.de/u-boot.git).
such as [U-Boot].
Supported SBI version
---------------------
@@ -97,8 +97,7 @@ Required Toolchain
OpenSBI can be compiled natively or cross-compiled on a x86 host. For
cross-compilation, you can build your own toolchain or just download
a prebuilt one from the
[Bootlin toolchain repository] (https://toolchains.bootlin.com/).
a prebuilt one from the [Bootlin toolchain repository].
Please note that only a 64-bit version of the toolchain is available in
the Bootlin toolchain repository for now.
@@ -226,6 +225,8 @@ Detailed documentation of various aspects of OpenSBI can be found under the
* [Platform Documentation]: Documentation of the platforms currently supported.
* [Firmware Documentation]: Documentation for the different types of firmware
examples build supported by OpenSBI.
* [Domain Support]: Documentation for the OpenSBI domain support which helps
users achieve system-level partitioning using OpenSBI.
OpenSBI source code is also well documented. For source level documentation,
doxygen style is used. Please refer to the [Doxygen manual] for details on this
@@ -269,6 +270,7 @@ make I=<install_directory> install_docs
[Github]: https://github.com/riscv/riscv-sbi-doc
[U-Boot]: https://www.denx.de/wiki/U-Boot/SourceCode
[Bootlin toolchain repository]: https://toolchains.bootlin.com/
[COPYING.BSD]: COPYING.BSD
[SPDX]: http://spdx.org/licenses/
[Contribution Guideline]: docs/contributing.md
@@ -278,6 +280,7 @@ make I=<install_directory> install_docs
[Platform Support Guide]: docs/platform_guide.md
[Platform Documentation]: docs/platform/platform.md
[Firmware Documentation]: docs/firmware/fw.md
[Domain Support]: docs/domain_support.md
[Doxygen manual]: http://www.doxygen.nl/manual/index.html
[Kendryte standalone SDK]: https://github.com/kendryte/kendryte-standalone-sdk
[third party notices]: ThirdPartyNotices.md

314
docs/domain_support.md Normal file
View File

@@ -0,0 +1,314 @@
OpenSBI Domain Support
======================
An OpenSBI domain is a system-level partition (subset) of underlying hardware
having it's own memory regions (RAM and MMIO devices) and HARTs. The OpenSBI
will try to achieve secure isolation between domains using RISC-V platform
features such as PMP, ePMP, IOPMP, SiFive Shield, etc.
Important entities which help implement OpenSBI domain support are:
* **struct sbi_domain_memregion** - Representation of a domain memory region
* **struct sbi_hartmask** - Representation of domain HART set
* **struct sbi_domain** - Representation of a domain instance
Each HART of a RISC-V platform must have an OpenSBI domain assigned to it.
The OpenSBI platform support is responsible for populating domains and
providing HART id to domain mapping. The OpenSBI domain support will by
default assign **the ROOT domain** to all HARTs of a RISC-V platform so
it is not mandatory for the OpenSBI platform support to populate domains.
Domain Memory Region
--------------------
A domain memory region is represented by **struct sbi_domain_memregion** in
OpenSBI and has following details:
* **order** - The size of a memory region is **2 ^ order** where **order**
must be **3 <= order <= __riscv_xlen**
* **base** - The base address of a memory region is **2 ^ order**
aligned start address
* **flags** - The flags of a memory region represent memory type (i.e.
RAM or MMIO) and allowed accesses (i.e. READ, WRITE, EXECUTE, etc)
Domain Instance
---------------
A domain instance is represented by **struct sbi_domain** in OpenSBI and
has following details:
* **index** - Logical index of this domain
* **name** - Name of this domain
* **assigned_harts** - HARTs assigned to this domain
* **possible_harts** - HARTs possible in this domain
* **regions** - Array of memory regions terminated by a memory region
with order zero
* **boot_hartid** - HART id of the HART booting this domain. The domain
boot HART will be started at boot-time if boot HART is possible and
assigned for this domain.
* **next_addr** - Address of the next booting stage for this domain
* **next_arg1** - Arg1 (or 'a1' register) of the next booting stage for
this domain
* **next_mode** - Privilege mode of the next booting stage for this
domain. This can be either S-mode or U-mode.
* **system_reset_allowed** - Is domain allowed to reset the system?
The memory regions represented by **regions** in **struct sbi_domain** have
following additional constraints to align with RISC-V PMP requirements:
* A memory region to protect OpenSBI firmware from S-mode and U-mode
should always be present
* For two overlapping memory regions, one should be sub-region of another
* Two overlapping memory regions should not be of same size
* Two overlapping memory regions cannot have same flags
* Memory access checks on overlapping address should prefer smallest
overlapping memory region flags.
ROOT Domain
-----------
**The ROOT domain** is the default OpenSBI domain which is assigned by
default to all HARTs of a RISC-V platform. The OpenSBI domain support
will hand-craft **the ROOT domain** very early at boot-time in the
following manner:
* **index** - Logical index of the ROOT domain is always zero
* **name** - Name of the ROOT domain is "root"
* **assigned_harts** - At boot-time all valid HARTs of a RISC-V platform
are assigned the ROOT domain which changes later based on OpenSBI
platform support
* **possible_harts** - All valid HARTs of a RISC-V platform are possible
HARTs of the ROOT domain
* **regions** - Two memory regions available to the ROOT domain:
**A)** A memory region to protect OpenSBI firmware from S-mode and U-mode
**B)** A memory region of **order=__riscv_xlen** allowing S-mode and
U-mode access to full memory address space
* **boot_hartid** - Coldboot HART is the HART booting the ROOT domain
* **next_addr** - Next booting stage address in coldboot HART scratch
space is the next address for the ROOT domain
* **next_arg1** - Next booting stage arg1 in coldboot HART scratch space
is the next arg1 for the ROOT domain
* **next_mode** - Next booting stage mode in coldboot HART scratch space
is the next mode for the ROOT domain
* **system_reset_allowed** - The ROOT domain is allowed to reset the system
Domain Effects
--------------
Few noteworthy effects of a system partitioned into domains are as follows:
* At any point in time, a HART is running in exactly one OpenSBI domain context
* The SBI IPI and RFENCE calls from HART A are restricted to the HARTs in
domain assigned to HART A
* The SBI HSM calls which try to change/read state of HART B from HART A will
only work if both HART A and HART B are assigned same domain
* A HART running in S-mode or U-mode can only access memory based on the
memory regions of the domain assigned to the HART
Domain Device Tree Bindings
---------------------------
The OpenSBI domains can be described in the **device tree (DT) blob** (or
flattened device tree) passed to the OpenSBI firmwares by the previous
booting stage. This allows OpenSBI platform support to parse and populate
OpenSBI domains from the device tree blob (or flattened device tree).
### Domain Configuration Node
All OpenSBI domain description related DT nodes should be under the domain
configuration DT node. The **/chosen** DT node is the preferred parent of
the domain configuration DT node.
The DT properties of a domain configuration DT node are as follows:
* **compatible** (Mandatory) - The compatible string of the domain
configuration. This DT property should have value *"opensbi,domain,config"*
### Domain Memory Region Node
The domain memory region DT node describes details of a memory region and
can be pointed by multiple domain instance DT nodes. The access permissions
of the memory region are specified separately in domain instance node.
The DT properties of a domain memory region DT node are as follows:
* **compatible** (Mandatory) - The compatible string of the domain memory
region. This DT property should have value *"opensbi,domain,memregion"*
* **base** (Mandatory) - The base address of the domain memory region. This
DT property should have a **2 ^ order** aligned 64 bit address (i.e. two
DT cells).
* **order** (Mandatory) - The order of the domain memory region. This DT
property should have a 32 bit value (i.e. one DT cell) in the range
**3 <= order <= __riscv_xlen**.
* **mmio** (Optional) - A boolean flag representing whether the domain
memory region is a memory-mapped I/O (MMIO) region.
* **devices** (Optional) - The list of device DT node phandles for devices
which fall under this domain memory region.
### Domain Instance Node
The domain instance DT node describes set of possible HARTs, set of memory
regions, and other details of a domain instance.
The DT properties of a domain instance DT node are as follows:
* **compatible** (Mandatory) - The compatible string of the domain instance.
This DT property should have value *"opensbi,domain,instance"*
* **possible-harts** (Optional) - The list of CPU DT node phandles for the
the domain instance. This list represents the possible HARTs of the
domain instance.
* **regions** (Optional) - The list of domain memory region DT node phandle
and access permissions for the domain instance. Each list entry is a pair
of DT node phandle and access permissions. The access permissions are
represented as a 32bit bitmask having bits: **readable** (BIT[0]),
**writeable** (BIT[1]), **executable** (BIT[2]), and **m-mode** (BIT[3]).
* **boot-hart** (Optional) - The DT node phandle of the HART booting the
domain instance. If coldboot HART is assigned to the domain instance then
this DT property is ignored and the coldboot HART is assumed to be the
boot HART of the domain instance.
* **next-arg1** (Optional) - The 64 bit next booting stage arg1 for the
domain instance. If this DT property is not available and coldboot HART
is not assigned to the domain instance then **0x0** is used as default
value. If this DT property is not available and coldboot HART is assigned
to the domain instance then **next booting stage arg1 of coldboot HART**
is used as default value.
* **next-addr** (Optional) - The 64 bit next booting stage address for the
domain instance. If this DT property is not available and coldboot HART
is not assigned to the domain instance then **0x0** is used as default
value. If this DT property is not available and coldboot HART is assigned
to the domain instance then **next booting stage address of coldboot HART**
is used as default value.
* **next-mode** (Optional) - The 32 bit next booting stage mode for the
domain instance. The possible values of this DT property are: **0x1**
(s-mode), and **0x0** (u-mode). If this DT property is not available
and coldboot HART is not assigned to the domain instance then **0x1**
is used as default value. If this DT property is not available and
coldboot HART is assigned to the domain instance then **next booting
stage mode of coldboot HART** is used as default value.
* **system-reset-allowed** (Optional) - A boolean flag representing
whether the domain instance is allowed to do system reset.
### Assigning HART To Domain Instance
By default, all HARTs are assigned to **the ROOT domain**. The OpenSBI
platform support can provide the HART to domain instance assignment using
platform specific callback.
The HART to domain instance assignment can be parsed from the device tree
using optional DT property **opensbi,domain** in each CPU DT node. The
value of DT property **opensbi,domain** is the DT phandle of the domain
instance DT node. If **opensbi,domain** DT property is not specified then
corresponding HART is assigned to **the ROOT domain**.
### Domain Configuration Only Accessible to OpenSBI
The software running inside a domain instance should only be aware of
devices and hardware resources accessible to itself.
To hide domain configuration from domain instances, the following should
be done:
* The previous booting stage should preferably provide a separate device
tree for each domain instance and mention location of device tree in
respective domain instance DT nodes using **next-arg1** DT property.
* If domain assigned to a HART does not have separate device tree then
OpenSBI platform support should remove all domain configuration details
from the device tree passed by previous booting stage before passing it
to the next booting stage.
### Example
```
chosen {
opensbi-domains {
compatible = "opensbi,domain,config";
tmem: tmem {
compatible = "opensbi,domain,memregion";
base = <0x0 0x80100000>;
order = <20>;
};
tuart: tuart {
compatible = "opensbi,domain,memregion";
base = <0x0 0x10011000>;
order = <12>;
mmio;
devices = <&uart1>;
};
allmem: allmem {
compatible = "opensbi,domain,memregion";
base = <0x0 0x0>;
order = <64>;
};
tdomain: trusted-domain {
compatible = "opensbi,domain,instance";
possible-harts = <&cpu0>;
regions = <&tmem 0x7>, <&tuart 0x7>;
boot-hart = <&cpu0>;
next-arg1 = <0x0 0x0>;
next-addr = <0x0 0x80100000>;
next-mode = <0x0>;
system-reset-allowed;
};
udomain: untrusted-domain {
compatible = "opensbi,domain,instance";
possible-harts = <&cpu1 &cpu2 &cpu3 &cpu4>;
regions = <&tmem 0x0>, <&tuart 0x0>, <&allmem 0x7>;
};
};
};
cpus {
#address-cells = <1>;
#size-cells = <0>;
timebase-frequency = <10000000>;
cpu0: cpu@0 {
device_type = "cpu";
reg = <0x00>;
compatible = "riscv";
opensbi-domain = <&tdomain>;
...
};
cpu1: cpu@1 {
device_type = "cpu";
reg = <0x01>;
compatible = "riscv";
opensbi-domain = <&udomain>;
...
};
cpu2: cpu@2 {
device_type = "cpu";
reg = <0x02>;
compatible = "riscv";
opensbi-domain = <&udomain>;
...
};
cpu3: cpu@3 {
device_type = "cpu";
reg = <0x03>;
compatible = "riscv";
opensbi-domain = <&udomain>;
...
};
cpu4: cpu@4 {
device_type = "cpu";
reg = <0x04>;
compatible = "riscv";
opensbi-domain = <&udomain>;
...
};
};
uart1: serial@10011000 {
...
};
```

View File

@@ -795,6 +795,7 @@ INPUT = @@SRC_DIR@@/README.md \
@@SRC_DIR@@/docs/platform_guide.md \
@@SRC_DIR@@/docs/platform_requirements.md \
@@SRC_DIR@@/docs/library_usage.md \
@@SRC_DIR@@/docs/domain_support.md \
@@SRC_DIR@@/docs/firmware \
@@SRC_DIR@@/docs/platform \
@@SRC_DIR@@/include \

View File

@@ -51,11 +51,17 @@ case, a *FW_PAYLOAD* firmware allows embedding a flattened device tree in the
Firmware Configuration and Compilation
--------------------------------------
All firmware types mandate the definition of the following compile time
configuration parameter.
All firmware types support the following common compile time configuration
parameters:
* **FW_TEXT_ADDR** - Defines the address at which the previous booting stage
loads OpenSBI firmware.
* **FW_TEXT_ADDR** - Defines the execution address of the OpenSBI firmware.
This configuration parameter is mandatory.
* **FW_FDT_PATH** - Path to an external flattened device tree binary file to
be embedded in the *.rodata* section of the final firmware. If this option
is not provided then the firmware will expect the FDT to be passed as an
argument by the prior booting stage.
* **FW_FDT_PADDING** - Optional zero bytes padding to the embedded flattened
device tree binary file specified by **FW_FDT_PATH** option.
Additionally, each firmware type as a set of type specific configuration
parameters. Detailed information for each firmware type can be found in the

View File

@@ -55,14 +55,9 @@ file. The parameters currently defined are as follows:
automatically generated and used as a payload. This test payload executes
an infinite `while (1)` loop after printing a message on the platform console.
* **FW_PAYLOAD_FDT_PATH** - Path to an external flattened device tree binary
file to be embedded in the *.text* section of the final firmware. If this
option is not provided then the firmware will expect the FDT to be passed
as an argument by the prior booting stage.
* **FW_PAYLOAD_FDT_ADDR** - Address where the FDT passed by the prior booting
stage or specified by the *FW_PAYLOAD_FDT_PATH* parameter and embedded in
the *.text* section will be placed before executing the next booting stage,
stage or specified by the *FW_FDT_PATH* parameter and embedded in the
*.rodata* section will be placed before executing the next booting stage,
that is, the payload firmware. If this option is not provided, then the
firmware will pass the FDT address passed by the previous booting stage
to the next booting stage.

View File

@@ -19,12 +19,12 @@ Building Andes AE350 Platform
-----------------------------
To use Linux v5.2 should be used to build Andes AE350 OpenSBI binaries by using
the compile time option FW_PAYLOAD_FDT_PATH.
the compile time option FW_FDT_PATH.
AE350's dts is included in https://github.com/andestech/linux/tree/ast-v3_2_0-release-public
**Linux Kernel Payload**
```
make PLATFORM=andes/ae350 FW_PAYLOAD_PATH=<linux_build_directory>/arch/riscv/boot/Image FW_PAYLOAD_FDT_PATH=<ae350.dtb path>
make PLATFORM=andes/ae350 FW_PAYLOAD_PATH=<linux_build_directory>/arch/riscv/boot/Image FW_FDT_PATH=<ae350.dtb path>
```

View File

@@ -28,7 +28,7 @@ make PLATFORM=generic
Run:
```
qemu-system-riscv64 -M virt -m 256M -nographic \
-kernel build/platform/generic/firmware/fw_payload.bin
-bios build/platform/generic/firmware/fw_payload.bin
```
**U-Boot Payload**
@@ -44,7 +44,7 @@ make PLATFORM=generic FW_PAYLOAD_PATH=<uboot_build_directory>/u-boot.bin
Run:
```
qemu-system-riscv64 -M virt -m 256M -nographic \
-kernel build/platform/generic/firmware/fw_payload.elf
-bios build/platform/generic/firmware/fw_payload.elf
```
or
```
@@ -66,7 +66,7 @@ make PLATFORM=generic FW_PAYLOAD_PATH=<linux_build_directory>/arch/riscv/boot/Im
Run:
```
qemu-system-riscv64 -M virt -m 256M -nographic \
-kernel build/platform/generic/firmware/fw_payload.elf \
-bios build/platform/generic/firmware/fw_payload.elf \
-drive file=<path_to_linux_rootfs>,format=raw,id=hd0 \
-device virtio-blk-device,drive=hd0 \
-append "root=/dev/vda rw console=ttyS0"
@@ -95,7 +95,7 @@ make PLATFORM=generic PLATFORM_RISCV_XLEN=32
Run:
```
qemu-system-riscv32 -M virt -m 256M -nographic \
-kernel build/platform/generic/firmware/fw_payload.bin
-bios build/platform/generic/firmware/fw_payload.bin
```
**U-Boot Payload**
@@ -111,7 +111,7 @@ make PLATFORM=generic PLATFORM_RISCV_XLEN=32 FW_PAYLOAD_PATH=<uboot_build_direct
Run:
```
qemu-system-riscv32 -M virt -m 256M -nographic \
-kernel build/platform/generic/firmware/fw_payload.elf
-bios build/platform/generic/firmware/fw_payload.elf
```
or
```
@@ -133,7 +133,7 @@ make PLATFORM=generic PLATFORM_RISCV_XLEN=32 FW_PAYLOAD_PATH=<linux_build_direct
Run:
```
qemu-system-riscv32 -M virt -m 256M -nographic \
-kernel build/platform/generic/firmware/fw_payload.elf \
-bios build/platform/generic/firmware/fw_payload.elf \
-drive file=<path_to_linux_rootfs>,format=raw,id=hd0 \
-device virtio-blk-device,drive=hd0 \
-append "root=/dev/vda rw console=ttyS0"

View File

@@ -23,11 +23,11 @@ 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>
make PLATFORM=generic FW_PAYLOAD_PATH=<linux_build_directory>/arch/riscv/boot/Image FW_FDT_PATH=<shakti.dtb path>
```
**Test Payload**
```
make PLATFORM=generic FW_PAYLOAD_FDT_PATH=<shakti.dtb path>
make PLATFORM=generic FW_FDT_PATH=<shakti.dtb path>
```

View File

@@ -27,27 +27,28 @@ U-Boot v2020.01 (or higher) should be used.
The HiFive Unleashed device tree(DT) is merged in Linux v5.2 release. This
DT (device tree) is not backward compatible with the DT passed from FSBL.
To use Linux v5.2 (or higher, the pre-built DTB (DT binary) from Linux v5.2
To use Linux v5.2 (or higher), the pre-built DTB (DT binary) from Linux v5.2
(or higher) should be used to build SiFive FU540 OpenSBI binaries by using
the compile time option *FW_PAYLOAD_FDT_PATH*.
the compile time option *FW_FDT_PATH*.
```
make PLATFORM=sifive/fu540 FW_PAYLOAD_PATH=<linux_build_directory>/arch/riscv/boot/Image
or
(For Linux v5.2 or higher)
make PLATFORM=sifive/fu540 FW_PAYLOAD_PATH=<linux_build_directory>/arch/riscv/boot/Image FW_PAYLOAD_FDT_PATH=<hifive-unleashed-a00.dtb path from Linux kernel>
make PLATFORM=sifive/fu540 FW_PAYLOAD_PATH=<linux_build_directory>/arch/riscv/boot/Image FW_FDT_PATH=<hifive-unleashed-a00.dtb path from Linux kernel>
```
**U-Boot Payload**
The command-line example here assumes that U-Boot was compiled using the
sifive_fu540_defconfig configuration and with U-Boot v2020.01 (or higher).
The detailed U-Boot booting guide is avaialble at [U-Boot].
sifive_fu540_defconfig configuration and with U-Boot v2020.01, and up to
v2020.07-rc3.
```
make PLATFORM=sifive/fu540 FW_PAYLOAD_PATH=<u-boot_build_dir>/u-boot-dtb.bin
```
For U-Boot v2020.07-rc4 or later releases, SPL support was added in U-Boot.
Please refer to the detailed U-Boot booting guide available at [U-Boot].
Flashing the OpenSBI firmware binary to storage media:
------------------------------------------------------
@@ -146,7 +147,7 @@ booti ${kernel_addr_r} - ${fdt_addr_r}
QEMU Specific Instructions
--------------------------
If you want to test OpenSBI with QEMU 'sifive_u' machine, please follow the
same instructions above, with the exception of not passing FW_PAYLOAD_FDT_PATH.
same instructions above, with the exception of not passing FW_FDT_PATH.
This is because QEMU generates a device tree blob on the fly based on the
command line parameters and it's compatible with the one used in the upstream
@@ -155,13 +156,37 @@ Linux kernel.
When U-Boot v2020.01 (or higher) is used as the payload, as the SiFive FU540
DTB for the real hardware is embedded in U-Boot binary itself, due to the same
reason above, we need to switch the U-Boot sifive_fu540_defconfig configuration
from CONFIG_OF_SEPARATE to CONFIG_OF_PRIOR_STAGE so that U-Boot uses the DTB
generated by QEMU, and u-boot.bin should be used as the payload image, like:
from **CONFIG_OF_SEPARATE** to **CONFIG_OF_PRIOR_STAGE** so that U-Boot uses the
DTB generated by QEMU, and u-boot.bin should be used as the payload image, like:
```
make PLATFORM=sifive/fu540 FW_PAYLOAD_PATH=<u-boot_build_dir>/u-boot.bin
```
U-Boot v2020.07 release added SPL support to SiFive HiFive Unleashed board,
hence a build error will be seen after you switch to **CONFIG_OF_PRIOR_STAGE**.
```
./tools/mkimage: Can't open arch/riscv/dts/hifive-unleashed-a00.dtb: No such file or directory
./tools/mkimage: failed to build FIT
Makefile:1402: recipe for target 'u-boot.img' failed
make: *** [u-boot.img] Error 1
```
The above errors can be safely ignored as we don't run U-Boot SPL under QEMU.
Run:
```
qemu-system-riscv64 -M sifive_u -m 256M -nographic \
-bios build/platform/sifive/fu540/firmware/fw_payload.bin
```
or
```
qemu-system-riscv64 -M sifive_u -m 256M -nographic \
-bios build/platform/sifive/fu540/firmware/fw_jump.bin \
-kernel <uboot_build_dir>/u-boot.bin
```
While the real hardware operates at the 64-bit mode, it's possible for QEMU to
test the 32-bit OpenSBI firmware. This can be helpful for testing 32-bit SiFive
specific drivers.

View File

@@ -59,7 +59,7 @@ make PLATFORM=generic
Run:
```
qemu-system-riscv64 -M spike -m 256M -nographic \
-kernel build/platform/generic/firmware/fw_payload.elf
-bios build/platform/generic/firmware/fw_payload.elf
```
**Linux Kernel Payload**
@@ -75,7 +75,7 @@ make PLATFORM=generic FW_PAYLOAD_PATH=<linux_build_directory>/arch/riscv/boot/Im
Run:
```
qemu-system-riscv64 -M spike -m 256M -nographic \
-kernel build/platform/generic/firmware/fw_payload.elf \
-bios build/platform/generic/firmware/fw_payload.elf \
-initrd <path_to_cpio_ramdisk> \
-append "root=/dev/ram rw console=hvc0 earlycon=sbi"
```

View File

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

View File

@@ -182,14 +182,10 @@ _bss_zero:
call fw_save_info
MOV_5R a0, s0, a1, s1, a2, s2, a3, s3, a4, s4
#ifdef FW_FDT_PATH
/* 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:
la a1, fw_fdt_bin
#endif
/*
* Initialize platform
@@ -265,6 +261,9 @@ _scratch_init:
/* Store hartid-to-scratch function address in scratch space */
la a4, _hartid_to_scratch
REG_S a4, SBI_SCRATCH_HARTID_TO_SCRATCH_OFFSET(tp)
/* Store trap-exit function address in scratch space */
la a4, _trap_exit
REG_S a4, SBI_SCRATCH_TRAP_EXIT_OFFSET(tp)
/* Clear tmp0 in scratch space */
REG_S zero, SBI_SCRATCH_TMP0_OFFSET(tp)
/* Store firmware options in scratch space */
@@ -417,8 +416,28 @@ _start_warm:
/* Setup trap handler */
la a4, _trap_handler
#if __riscv_xlen == 32
csrr a5, CSR_MISA
srli a5, a5, ('H' - 'A')
andi a5, a5, 0x1
beq a5, zero, _skip_trap_handler_rv32_hyp
la a4, _trap_handler_rv32_hyp
_skip_trap_handler_rv32_hyp:
#endif
csrw CSR_MTVEC, a4
#if __riscv_xlen == 32
/* Override trap exit for H-extension */
csrr a5, CSR_MISA
srli a5, a5, ('H' - 'A')
andi a5, a5, 0x1
beq a5, zero, _skip_trap_exit_rv32_hyp
la a4, _trap_exit_rv32_hyp
csrr a5, CSR_MSCRATCH
REG_S a4, SBI_SCRATCH_TRAP_EXIT_OFFSET(a5)
_skip_trap_exit_rv32_hyp:
#endif
/* Initialize SBI runtime */
csrr a0, CSR_MSCRATCH
call sbi_init
@@ -480,45 +499,37 @@ fw_platform_init:
add a0, a1, zero
ret
.section .entry, "ax", %progbits
.align 3
.globl _trap_handler
_trap_handler:
.macro TRAP_SAVE_AND_SETUP_SP_T0
/* Swap TP and MSCRATCH */
csrrw tp, CSR_MSCRATCH, tp
/* Save T0 in scratch space */
REG_S t0, SBI_SCRATCH_TMP0_OFFSET(tp)
/* Check which mode we came from */
/*
* Set T0 to appropriate exception stack
*
* Came_From_M_Mode = ((MSTATUS.MPP < PRV_M) ? 1 : 0) - 1;
* Exception_Stack = TP ^ (Came_From_M_Mode & (SP ^ TP))
*
* Came_From_M_Mode = 0 ==> Exception_Stack = TP
* Came_From_M_Mode = -1 ==> Exception_Stack = SP
*/
csrr t0, CSR_MSTATUS
srl t0, t0, MSTATUS_MPP_SHIFT
and t0, t0, PRV_M
xori t0, t0, PRV_M
beq t0, zero, _trap_handler_m_mode
slti t0, t0, PRV_M
add t0, t0, -1
xor sp, sp, tp
and t0, t0, sp
xor sp, sp, tp
xor t0, tp, t0
/* We came from S-mode or U-mode */
_trap_handler_s_mode:
/* Set T0 to original SP */
add t0, sp, zero
/* Save original SP on exception stack */
REG_S sp, (SBI_TRAP_REGS_OFFSET(sp) - SBI_TRAP_REGS_SIZE)(t0)
/* Setup exception stack */
add sp, tp, -(SBI_TRAP_REGS_SIZE)
/* Jump to code common for all modes */
j _trap_handler_all_mode
/* We came from M-mode */
_trap_handler_m_mode:
/* Set T0 to original SP */
add t0, sp, zero
/* Re-use current SP as exception stack */
add sp, sp, -(SBI_TRAP_REGS_SIZE)
_trap_handler_all_mode:
/* Save original SP (from T0) on stack */
REG_S t0, SBI_TRAP_REGS_OFFSET(sp)(sp)
/* Set SP to exception stack and make room for trap registers */
add sp, t0, -(SBI_TRAP_REGS_SIZE)
/* Restore T0 from scratch space */
REG_L t0, SBI_SCRATCH_TMP0_OFFSET(tp)
@@ -528,23 +539,23 @@ _trap_handler_all_mode:
/* Swap TP and MSCRATCH */
csrrw tp, CSR_MSCRATCH, tp
.endm
.macro TRAP_SAVE_MEPC_MSTATUS have_mstatush
/* Save MEPC and MSTATUS CSRs */
csrr t0, CSR_MEPC
REG_S t0, SBI_TRAP_REGS_OFFSET(mepc)(sp)
csrr t0, CSR_MSTATUS
REG_S t0, SBI_TRAP_REGS_OFFSET(mstatus)(sp)
REG_S zero, SBI_TRAP_REGS_OFFSET(mstatusH)(sp)
#if __riscv_xlen == 32
csrr t0, CSR_MISA
srli t0, t0, ('H' - 'A')
andi t0, t0, 0x1
beq t0, zero, _skip_mstatush_save
.if \have_mstatush
csrr t0, CSR_MSTATUSH
REG_S t0, SBI_TRAP_REGS_OFFSET(mstatusH)(sp)
_skip_mstatush_save:
#endif
.else
REG_S zero, SBI_TRAP_REGS_OFFSET(mstatusH)(sp)
.endif
.endm
.macro TRAP_SAVE_GENERAL_REGS_EXCEPT_SP_T0
/* Save all general regisers except SP and T0 */
REG_S zero, SBI_TRAP_REGS_OFFSET(zero)(sp)
REG_S ra, SBI_TRAP_REGS_OFFSET(ra)(sp)
@@ -576,11 +587,15 @@ _skip_mstatush_save:
REG_S t4, SBI_TRAP_REGS_OFFSET(t4)(sp)
REG_S t5, SBI_TRAP_REGS_OFFSET(t5)(sp)
REG_S t6, SBI_TRAP_REGS_OFFSET(t6)(sp)
.endm
.macro TRAP_CALL_C_ROUTINE
/* Call C routine */
add a0, sp, zero
call sbi_trap_handler
.endm
.macro TRAP_RESTORE_GENERAL_REGS_EXCEPT_SP_T0
/* Restore all general regisers except SP and T0 */
REG_L ra, SBI_TRAP_REGS_OFFSET(ra)(sp)
REG_L gp, SBI_TRAP_REGS_OFFSET(gp)(sp)
@@ -611,30 +626,98 @@ _skip_mstatush_save:
REG_L t4, SBI_TRAP_REGS_OFFSET(t4)(sp)
REG_L t5, SBI_TRAP_REGS_OFFSET(t5)(sp)
REG_L t6, SBI_TRAP_REGS_OFFSET(t6)(sp)
.endm
.macro TRAP_RESTORE_MEPC_MSTATUS have_mstatush
/* Restore MEPC and MSTATUS CSRs */
REG_L t0, SBI_TRAP_REGS_OFFSET(mepc)(sp)
csrw CSR_MEPC, t0
REG_L t0, SBI_TRAP_REGS_OFFSET(mstatus)(sp)
csrw CSR_MSTATUS, t0
#if __riscv_xlen == 32
csrr t0, CSR_MISA
srli t0, t0, ('H' - 'A')
andi t0, t0, 0x1
beq t0, zero, _skip_mstatush_restore
.if \have_mstatush
REG_L t0, SBI_TRAP_REGS_OFFSET(mstatusH)(sp)
csrw CSR_MSTATUSH, t0
_skip_mstatush_restore:
#endif
.endif
.endm
.macro TRAP_RESTORE_SP_T0
/* Restore T0 */
REG_L t0, SBI_TRAP_REGS_OFFSET(t0)(sp)
/* Restore SP */
REG_L sp, SBI_TRAP_REGS_OFFSET(sp)(sp)
.endm
.section .entry, "ax", %progbits
.align 3
.globl _trap_handler
_trap_handler:
TRAP_SAVE_AND_SETUP_SP_T0
TRAP_SAVE_MEPC_MSTATUS 0
TRAP_SAVE_GENERAL_REGS_EXCEPT_SP_T0
TRAP_CALL_C_ROUTINE
TRAP_RESTORE_GENERAL_REGS_EXCEPT_SP_T0
TRAP_RESTORE_MEPC_MSTATUS 0
TRAP_RESTORE_SP_T0
mret
.section .entry, "ax", %progbits
.align 3
.globl _trap_exit
_trap_exit:
add sp, a0, zero
TRAP_RESTORE_GENERAL_REGS_EXCEPT_SP_T0
TRAP_RESTORE_MEPC_MSTATUS 0
TRAP_RESTORE_SP_T0
mret
#if __riscv_xlen == 32
.section .entry, "ax", %progbits
.align 3
.globl _trap_handler_rv32_hyp
_trap_handler_rv32_hyp:
TRAP_SAVE_AND_SETUP_SP_T0
TRAP_SAVE_MEPC_MSTATUS 1
TRAP_SAVE_GENERAL_REGS_EXCEPT_SP_T0
TRAP_CALL_C_ROUTINE
TRAP_RESTORE_GENERAL_REGS_EXCEPT_SP_T0
TRAP_RESTORE_MEPC_MSTATUS 1
TRAP_RESTORE_SP_T0
mret
.section .entry, "ax", %progbits
.align 3
.globl _trap_exit_rv32_hyp
_trap_exit_rv32_hyp:
add sp, a0, zero
TRAP_RESTORE_GENERAL_REGS_EXCEPT_SP_T0
TRAP_RESTORE_MEPC_MSTATUS 1
TRAP_RESTORE_SP_T0
mret
#endif
.section .entry, "ax", %progbits
.align 3
.globl _reset_regs
@@ -673,3 +756,14 @@ _reset_regs:
csrw CSR_MSCRATCH, 0
ret
#ifdef FW_FDT_PATH
.section .rodata
.align 4
.globl fw_fdt_bin
fw_fdt_bin:
.incbin FW_FDT_PATH
#ifdef FW_FDT_PADDING
.fill FW_FDT_PADDING, 1, 0
#endif
#endif

View File

@@ -86,19 +86,6 @@ fw_save_info:
2:
ret
.section .entry, "ax", %progbits
.align 3
.global fw_prev_arg1
/*
* We can only use a0, a1, and a2 registers here.
* The a0, a1, and a2 registers will be same as passed by
* previous booting stage.
* The previous arg1 should be returned in 'a0'.
*/
fw_prev_arg1:
add a0, zero, zero
ret
.section .entry, "ax", %progbits
.align 3
.global fw_next_arg1

View File

@@ -34,19 +34,6 @@ fw_boot_hart:
fw_save_info:
ret
.section .entry, "ax", %progbits
.align 3
.global fw_prev_arg1
/*
* We can only use a0, a1, and a2 registers here.
* The a0, a1, and a2 registers will be same as passed by
* previous booting stage.
* The previous arg1 should be returned in 'a0'.
*/
fw_prev_arg1:
add a0, zero, zero
ret
.section .entry, "ax", %progbits
.align 3
.global fw_next_arg1

View File

@@ -34,23 +34,6 @@ fw_boot_hart:
fw_save_info:
ret
.section .entry, "ax", %progbits
.align 3
.global fw_prev_arg1
/*
* We can only use a0, a1, and a2 registers here.
* The a0, a1, and a2 registers will be same as passed by
* previous booting stage.
* The previous arg1 should be returned in 'a0'.
*/
fw_prev_arg1:
#ifdef FW_PAYLOAD_FDT_PATH
la a0, fdt_bin
#else
add a0, zero, zero
#endif
ret
.section .entry, "ax", %progbits
.align 3
.global fw_next_arg1
@@ -102,14 +85,6 @@ fw_options:
add a0, zero, zero
ret
#ifdef FW_PAYLOAD_FDT_PATH
.section .text, "ax", %progbits
.align 4
.globl fdt_bin
fdt_bin:
.incbin FW_PAYLOAD_FDT_PATH
#endif
.section .payload, "ax", %progbits
.align 4
.globl payload_bin

View File

@@ -17,6 +17,13 @@ ifdef FW_TEXT_START
firmware-genflags-y += -DFW_TEXT_START=$(FW_TEXT_START)
endif
ifdef FW_FDT_PATH
firmware-genflags-y += -DFW_FDT_PATH=\"$(FW_FDT_PATH)\"
ifdef FW_FDT_PADDING
firmware-genflags-y += -DFW_FDT_PADDING=$(FW_FDT_PADDING)
endif
endif
firmware-bins-$(FW_DYNAMIC) += fw_dynamic.bin
firmware-bins-$(FW_JUMP) += fw_jump.bin
@@ -41,9 +48,6 @@ ifdef FW_PAYLOAD_ALIGN
firmware-genflags-$(FW_PAYLOAD) += -DFW_PAYLOAD_ALIGN=$(FW_PAYLOAD_ALIGN)
endif
ifdef FW_PAYLOAD_FDT_PATH
firmware-genflags-$(FW_PAYLOAD) += -DFW_PAYLOAD_FDT_PATH=\"$(FW_PAYLOAD_FDT_PATH)\"
endif
ifdef FW_PAYLOAD_FDT_ADDR
firmware-genflags-$(FW_PAYLOAD) += -DFW_PAYLOAD_FDT_ADDR=$(FW_PAYLOAD_FDT_ADDR)
endif

View File

@@ -180,7 +180,7 @@ int pmp_set(unsigned int n, unsigned long prot, unsigned long addr,
unsigned long log2len);
int pmp_get(unsigned int n, unsigned long *prot_out, unsigned long *addr_out,
unsigned long *size);
unsigned long *log2len);
#endif /* !__ASSEMBLY__ */

View File

@@ -144,7 +144,12 @@
#define PMP_L _UL(0x80)
#define PMP_SHIFT 2
#define PMP_COUNT 16
#define PMP_COUNT 64
#if __riscv_xlen == 64
#define PMP_ADDR_MASK ((_ULL(0x1) << 54) - 1)
#else
#define PMP_ADDR_MASK _UL(0xFFFFFFFF)
#endif
#if __riscv_xlen == 64
#define MSTATUS_SD MSTATUS64_SD
@@ -166,18 +171,27 @@
#define HGATP_MODE_SHIFT HGATP32_MODE_SHIFT
#endif
#define CSR_USTATUS 0x0
#define CSR_FFLAGS 0x1
#define CSR_FRM 0x2
#define CSR_FCSR 0x3
/* ===== User-level CSRs ===== */
/* User Trap Setup (N-extension) */
#define CSR_USTATUS 0x000
#define CSR_UIE 0x004
#define CSR_UTVEC 0x005
/* User Trap Handling (N-extension) */
#define CSR_USCRATCH 0x040
#define CSR_UEPC 0x041
#define CSR_UCAUSE 0x042
#define CSR_UTVAL 0x043
#define CSR_UIP 0x044
/* User Floating-point CSRs */
#define CSR_FFLAGS 0x001
#define CSR_FRM 0x002
#define CSR_FCSR 0x003
/* User Counters/Timers */
#define CSR_CYCLE 0xc00
#define CSR_UIE 0x4
#define CSR_UTVEC 0x5
#define CSR_USCRATCH 0x40
#define CSR_UEPC 0x41
#define CSR_UCAUSE 0x42
#define CSR_UTVAL 0x43
#define CSR_UIP 0x44
#define CSR_TIME 0xc01
#define CSR_INSTRET 0xc02
#define CSR_HPMCOUNTER3 0xc03
@@ -209,148 +223,6 @@
#define CSR_HPMCOUNTER29 0xc1d
#define CSR_HPMCOUNTER30 0xc1e
#define CSR_HPMCOUNTER31 0xc1f
#define CSR_SSTATUS 0x100
#define CSR_SIE 0x104
#define CSR_STVEC 0x105
#define CSR_SCOUNTEREN 0x106
#define CSR_SSCRATCH 0x140
#define CSR_SEPC 0x141
#define CSR_SCAUSE 0x142
#define CSR_STVAL 0x143
#define CSR_SIP 0x144
#define CSR_SATP 0x180
#define CSR_HSTATUS 0x600
#define CSR_HEDELEG 0x602
#define CSR_HIDELEG 0x603
#define CSR_HIE 0x604
#define CSR_HTIMEDELTA 0x605
#define CSR_HTIMEDELTAH 0x615
#define CSR_HCOUNTERNEN 0x606
#define CSR_HGEIE 0x607
#define CSR_HTVAL 0x643
#define CSR_HIP 0x644
#define CSR_HTINST 0x64a
#define CSR_HGATP 0x680
#define CSR_HGEIP 0xe07
#define CSR_VSSTATUS 0x200
#define CSR_VSIE 0x204
#define CSR_VSTVEC 0x205
#define CSR_VSSCRATCH 0x240
#define CSR_VSEPC 0x241
#define CSR_VSCAUSE 0x242
#define CSR_VSTVAL 0x243
#define CSR_VSIP 0x244
#define CSR_VSATP 0x280
#define CSR_MSTATUS 0x300
#define CSR_MISA 0x301
#define CSR_MEDELEG 0x302
#define CSR_MIDELEG 0x303
#define CSR_MIE 0x304
#define CSR_MTVEC 0x305
#define CSR_MCOUNTEREN 0x306
#define CSR_MSTATUSH 0x310
#define CSR_MSCRATCH 0x340
#define CSR_MEPC 0x341
#define CSR_MCAUSE 0x342
#define CSR_MTVAL 0x343
#define CSR_MIP 0x344
#define CSR_MTINST 0x34a
#define CSR_MTVAL2 0x34b
#define CSR_PMPCFG0 0x3a0
#define CSR_PMPCFG1 0x3a1
#define CSR_PMPCFG2 0x3a2
#define CSR_PMPCFG3 0x3a3
#define CSR_PMPADDR0 0x3b0
#define CSR_PMPADDR1 0x3b1
#define CSR_PMPADDR2 0x3b2
#define CSR_PMPADDR3 0x3b3
#define CSR_PMPADDR4 0x3b4
#define CSR_PMPADDR5 0x3b5
#define CSR_PMPADDR6 0x3b6
#define CSR_PMPADDR7 0x3b7
#define CSR_PMPADDR8 0x3b8
#define CSR_PMPADDR9 0x3b9
#define CSR_PMPADDR10 0x3ba
#define CSR_PMPADDR11 0x3bb
#define CSR_PMPADDR12 0x3bc
#define CSR_PMPADDR13 0x3bd
#define CSR_PMPADDR14 0x3be
#define CSR_PMPADDR15 0x3bf
#define CSR_TSELECT 0x7a0
#define CSR_TDATA1 0x7a1
#define CSR_TDATA2 0x7a2
#define CSR_TDATA3 0x7a3
#define CSR_DCSR 0x7b0
#define CSR_DPC 0x7b1
#define CSR_DSCRATCH 0x7b2
#define CSR_MCYCLE 0xb00
#define CSR_MINSTRET 0xb02
#define CSR_MHPMCOUNTER3 0xb03
#define CSR_MHPMCOUNTER4 0xb04
#define CSR_MHPMCOUNTER5 0xb05
#define CSR_MHPMCOUNTER6 0xb06
#define CSR_MHPMCOUNTER7 0xb07
#define CSR_MHPMCOUNTER8 0xb08
#define CSR_MHPMCOUNTER9 0xb09
#define CSR_MHPMCOUNTER10 0xb0a
#define CSR_MHPMCOUNTER11 0xb0b
#define CSR_MHPMCOUNTER12 0xb0c
#define CSR_MHPMCOUNTER13 0xb0d
#define CSR_MHPMCOUNTER14 0xb0e
#define CSR_MHPMCOUNTER15 0xb0f
#define CSR_MHPMCOUNTER16 0xb10
#define CSR_MHPMCOUNTER17 0xb11
#define CSR_MHPMCOUNTER18 0xb12
#define CSR_MHPMCOUNTER19 0xb13
#define CSR_MHPMCOUNTER20 0xb14
#define CSR_MHPMCOUNTER21 0xb15
#define CSR_MHPMCOUNTER22 0xb16
#define CSR_MHPMCOUNTER23 0xb17
#define CSR_MHPMCOUNTER24 0xb18
#define CSR_MHPMCOUNTER25 0xb19
#define CSR_MHPMCOUNTER26 0xb1a
#define CSR_MHPMCOUNTER27 0xb1b
#define CSR_MHPMCOUNTER28 0xb1c
#define CSR_MHPMCOUNTER29 0xb1d
#define CSR_MHPMCOUNTER30 0xb1e
#define CSR_MHPMCOUNTER31 0xb1f
#define CSR_MHPMEVENT3 0x323
#define CSR_MHPMEVENT4 0x324
#define CSR_MHPMEVENT5 0x325
#define CSR_MHPMEVENT6 0x326
#define CSR_MHPMEVENT7 0x327
#define CSR_MHPMEVENT8 0x328
#define CSR_MHPMEVENT9 0x329
#define CSR_MHPMEVENT10 0x32a
#define CSR_MHPMEVENT11 0x32b
#define CSR_MHPMEVENT12 0x32c
#define CSR_MHPMEVENT13 0x32d
#define CSR_MHPMEVENT14 0x32e
#define CSR_MHPMEVENT15 0x32f
#define CSR_MHPMEVENT16 0x330
#define CSR_MHPMEVENT17 0x331
#define CSR_MHPMEVENT18 0x332
#define CSR_MHPMEVENT19 0x333
#define CSR_MHPMEVENT20 0x334
#define CSR_MHPMEVENT21 0x335
#define CSR_MHPMEVENT22 0x336
#define CSR_MHPMEVENT23 0x337
#define CSR_MHPMEVENT24 0x338
#define CSR_MHPMEVENT25 0x339
#define CSR_MHPMEVENT26 0x33a
#define CSR_MHPMEVENT27 0x33b
#define CSR_MHPMEVENT28 0x33c
#define CSR_MHPMEVENT29 0x33d
#define CSR_MHPMEVENT30 0x33e
#define CSR_MHPMEVENT31 0x33f
#define CSR_MVENDORID 0xf11
#define CSR_MARCHID 0xf12
#define CSR_MIMPID 0xf13
#define CSR_MHARTID 0xf14
#define CSR_CYCLEH 0xc80
#define CSR_TIMEH 0xc81
#define CSR_INSTRETH 0xc82
@@ -383,6 +255,203 @@
#define CSR_HPMCOUNTER29H 0xc9d
#define CSR_HPMCOUNTER30H 0xc9e
#define CSR_HPMCOUNTER31H 0xc9f
/* ===== Supervisor-level CSRs ===== */
/* Supervisor Trap Setup */
#define CSR_SSTATUS 0x100
#define CSR_SEDELEG 0x102
#define CSR_SIDELEG 0x103
#define CSR_SIE 0x104
#define CSR_STVEC 0x105
#define CSR_SCOUNTEREN 0x106
/* Supervisor Trap Handling */
#define CSR_SSCRATCH 0x140
#define CSR_SEPC 0x141
#define CSR_SCAUSE 0x142
#define CSR_STVAL 0x143
#define CSR_SIP 0x144
/* Supervisor Protection and Translation */
#define CSR_SATP 0x180
/* ===== Hypervisor-level CSRs ===== */
/* Hypervisor Trap Setup (H-extension) */
#define CSR_HSTATUS 0x600
#define CSR_HEDELEG 0x602
#define CSR_HIDELEG 0x603
#define CSR_HIE 0x604
#define CSR_HCOUNTEREN 0x606
#define CSR_HGEIE 0x607
/* Hypervisor Trap Handling (H-extension) */
#define CSR_HTVAL 0x643
#define CSR_HIP 0x644
#define CSR_HVIP 0x645
#define CSR_HTINST 0x64a
#define CSR_HGEIP 0xe12
/* Hypervisor Protection and Translation (H-extension) */
#define CSR_HGATP 0x680
/* Hypervisor Counter/Timer Virtualization Registers (H-extension) */
#define CSR_HTIMEDELTA 0x605
#define CSR_HTIMEDELTAH 0x615
/* Virtual Supervisor Registers (H-extension) */
#define CSR_VSSTATUS 0x200
#define CSR_VSIE 0x204
#define CSR_VSTVEC 0x205
#define CSR_VSSCRATCH 0x240
#define CSR_VSEPC 0x241
#define CSR_VSCAUSE 0x242
#define CSR_VSTVAL 0x243
#define CSR_VSIP 0x244
#define CSR_VSATP 0x280
/* ===== Machine-level CSRs ===== */
/* Machine Information Registers */
#define CSR_MVENDORID 0xf11
#define CSR_MARCHID 0xf12
#define CSR_MIMPID 0xf13
#define CSR_MHARTID 0xf14
/* Machine Trap Setup */
#define CSR_MSTATUS 0x300
#define CSR_MISA 0x301
#define CSR_MEDELEG 0x302
#define CSR_MIDELEG 0x303
#define CSR_MIE 0x304
#define CSR_MTVEC 0x305
#define CSR_MCOUNTEREN 0x306
#define CSR_MSTATUSH 0x310
/* Machine Trap Handling */
#define CSR_MSCRATCH 0x340
#define CSR_MEPC 0x341
#define CSR_MCAUSE 0x342
#define CSR_MTVAL 0x343
#define CSR_MIP 0x344
#define CSR_MTINST 0x34a
#define CSR_MTVAL2 0x34b
/* Machine Memory Protection */
#define CSR_PMPCFG0 0x3a0
#define CSR_PMPCFG1 0x3a1
#define CSR_PMPCFG2 0x3a2
#define CSR_PMPCFG3 0x3a3
#define CSR_PMPCFG4 0x3a4
#define CSR_PMPCFG5 0x3a5
#define CSR_PMPCFG6 0x3a6
#define CSR_PMPCFG7 0x3a7
#define CSR_PMPCFG8 0x3a8
#define CSR_PMPCFG9 0x3a9
#define CSR_PMPCFG10 0x3aa
#define CSR_PMPCFG11 0x3ab
#define CSR_PMPCFG12 0x3ac
#define CSR_PMPCFG13 0x3ad
#define CSR_PMPCFG14 0x3ae
#define CSR_PMPCFG15 0x3af
#define CSR_PMPADDR0 0x3b0
#define CSR_PMPADDR1 0x3b1
#define CSR_PMPADDR2 0x3b2
#define CSR_PMPADDR3 0x3b3
#define CSR_PMPADDR4 0x3b4
#define CSR_PMPADDR5 0x3b5
#define CSR_PMPADDR6 0x3b6
#define CSR_PMPADDR7 0x3b7
#define CSR_PMPADDR8 0x3b8
#define CSR_PMPADDR9 0x3b9
#define CSR_PMPADDR10 0x3ba
#define CSR_PMPADDR11 0x3bb
#define CSR_PMPADDR12 0x3bc
#define CSR_PMPADDR13 0x3bd
#define CSR_PMPADDR14 0x3be
#define CSR_PMPADDR15 0x3bf
#define CSR_PMPADDR16 0x3c0
#define CSR_PMPADDR17 0x3c1
#define CSR_PMPADDR18 0x3c2
#define CSR_PMPADDR19 0x3c3
#define CSR_PMPADDR20 0x3c4
#define CSR_PMPADDR21 0x3c5
#define CSR_PMPADDR22 0x3c6
#define CSR_PMPADDR23 0x3c7
#define CSR_PMPADDR24 0x3c8
#define CSR_PMPADDR25 0x3c9
#define CSR_PMPADDR26 0x3ca
#define CSR_PMPADDR27 0x3cb
#define CSR_PMPADDR28 0x3cc
#define CSR_PMPADDR29 0x3cd
#define CSR_PMPADDR30 0x3ce
#define CSR_PMPADDR31 0x3cf
#define CSR_PMPADDR32 0x3d0
#define CSR_PMPADDR33 0x3d1
#define CSR_PMPADDR34 0x3d2
#define CSR_PMPADDR35 0x3d3
#define CSR_PMPADDR36 0x3d4
#define CSR_PMPADDR37 0x3d5
#define CSR_PMPADDR38 0x3d6
#define CSR_PMPADDR39 0x3d7
#define CSR_PMPADDR40 0x3d8
#define CSR_PMPADDR41 0x3d9
#define CSR_PMPADDR42 0x3da
#define CSR_PMPADDR43 0x3db
#define CSR_PMPADDR44 0x3dc
#define CSR_PMPADDR45 0x3dd
#define CSR_PMPADDR46 0x3de
#define CSR_PMPADDR47 0x3df
#define CSR_PMPADDR48 0x3e0
#define CSR_PMPADDR49 0x3e1
#define CSR_PMPADDR50 0x3e2
#define CSR_PMPADDR51 0x3e3
#define CSR_PMPADDR52 0x3e4
#define CSR_PMPADDR53 0x3e5
#define CSR_PMPADDR54 0x3e6
#define CSR_PMPADDR55 0x3e7
#define CSR_PMPADDR56 0x3e8
#define CSR_PMPADDR57 0x3e9
#define CSR_PMPADDR58 0x3ea
#define CSR_PMPADDR59 0x3eb
#define CSR_PMPADDR60 0x3ec
#define CSR_PMPADDR61 0x3ed
#define CSR_PMPADDR62 0x3ee
#define CSR_PMPADDR63 0x3ef
/* Machine Counters/Timers */
#define CSR_MCYCLE 0xb00
#define CSR_MINSTRET 0xb02
#define CSR_MHPMCOUNTER3 0xb03
#define CSR_MHPMCOUNTER4 0xb04
#define CSR_MHPMCOUNTER5 0xb05
#define CSR_MHPMCOUNTER6 0xb06
#define CSR_MHPMCOUNTER7 0xb07
#define CSR_MHPMCOUNTER8 0xb08
#define CSR_MHPMCOUNTER9 0xb09
#define CSR_MHPMCOUNTER10 0xb0a
#define CSR_MHPMCOUNTER11 0xb0b
#define CSR_MHPMCOUNTER12 0xb0c
#define CSR_MHPMCOUNTER13 0xb0d
#define CSR_MHPMCOUNTER14 0xb0e
#define CSR_MHPMCOUNTER15 0xb0f
#define CSR_MHPMCOUNTER16 0xb10
#define CSR_MHPMCOUNTER17 0xb11
#define CSR_MHPMCOUNTER18 0xb12
#define CSR_MHPMCOUNTER19 0xb13
#define CSR_MHPMCOUNTER20 0xb14
#define CSR_MHPMCOUNTER21 0xb15
#define CSR_MHPMCOUNTER22 0xb16
#define CSR_MHPMCOUNTER23 0xb17
#define CSR_MHPMCOUNTER24 0xb18
#define CSR_MHPMCOUNTER25 0xb19
#define CSR_MHPMCOUNTER26 0xb1a
#define CSR_MHPMCOUNTER27 0xb1b
#define CSR_MHPMCOUNTER28 0xb1c
#define CSR_MHPMCOUNTER29 0xb1d
#define CSR_MHPMCOUNTER30 0xb1e
#define CSR_MHPMCOUNTER31 0xb1f
#define CSR_MCYCLEH 0xb80
#define CSR_MINSTRETH 0xb82
#define CSR_MHPMCOUNTER3H 0xb83
@@ -415,6 +484,52 @@
#define CSR_MHPMCOUNTER30H 0xb9e
#define CSR_MHPMCOUNTER31H 0xb9f
/* Machine Counter Setup */
#define CSR_MCOUNTINHIBIT 0x320
#define CSR_MHPMEVENT3 0x323
#define CSR_MHPMEVENT4 0x324
#define CSR_MHPMEVENT5 0x325
#define CSR_MHPMEVENT6 0x326
#define CSR_MHPMEVENT7 0x327
#define CSR_MHPMEVENT8 0x328
#define CSR_MHPMEVENT9 0x329
#define CSR_MHPMEVENT10 0x32a
#define CSR_MHPMEVENT11 0x32b
#define CSR_MHPMEVENT12 0x32c
#define CSR_MHPMEVENT13 0x32d
#define CSR_MHPMEVENT14 0x32e
#define CSR_MHPMEVENT15 0x32f
#define CSR_MHPMEVENT16 0x330
#define CSR_MHPMEVENT17 0x331
#define CSR_MHPMEVENT18 0x332
#define CSR_MHPMEVENT19 0x333
#define CSR_MHPMEVENT20 0x334
#define CSR_MHPMEVENT21 0x335
#define CSR_MHPMEVENT22 0x336
#define CSR_MHPMEVENT23 0x337
#define CSR_MHPMEVENT24 0x338
#define CSR_MHPMEVENT25 0x339
#define CSR_MHPMEVENT26 0x33a
#define CSR_MHPMEVENT27 0x33b
#define CSR_MHPMEVENT28 0x33c
#define CSR_MHPMEVENT29 0x33d
#define CSR_MHPMEVENT30 0x33e
#define CSR_MHPMEVENT31 0x33f
/* Debug/Trace Registers */
#define CSR_TSELECT 0x7a0
#define CSR_TDATA1 0x7a1
#define CSR_TDATA2 0x7a2
#define CSR_TDATA3 0x7a3
/* Debug Mode Registers */
#define CSR_DCSR 0x7b0
#define CSR_DPC 0x7b1
#define CSR_DSCRATCH0 0x7b2
#define CSR_DSCRATCH1 0x7b3
/* ===== Trap/Exception Causes ===== */
#define CAUSE_MISALIGNED_FETCH 0x0
#define CAUSE_FETCH_ACCESS 0x1
#define CAUSE_ILLEGAL_INSTRUCTION 0x2
@@ -424,8 +539,8 @@
#define CAUSE_MISALIGNED_STORE 0x6
#define CAUSE_STORE_ACCESS 0x7
#define CAUSE_USER_ECALL 0x8
#define CAUSE_HYPERVISOR_ECALL 0x9
#define CAUSE_SUPERVISOR_ECALL 0xa
#define CAUSE_SUPERVISOR_ECALL 0x9
#define CAUSE_VIRTUAL_SUPERVISOR_ECALL 0xa
#define CAUSE_MACHINE_ECALL 0xb
#define CAUSE_FETCH_PAGE_FAULT 0xc
#define CAUSE_LOAD_PAGE_FAULT 0xd
@@ -435,6 +550,8 @@
#define CAUSE_VIRTUAL_INST_FAULT 0x16
#define CAUSE_STORE_GUEST_PAGE_FAULT 0x17
/* ===== Instruction Encodings ===== */
#define INSN_MATCH_LB 0x3
#define INSN_MASK_LB 0x707f
#define INSN_MATCH_LH 0x1003

View File

@@ -66,10 +66,8 @@ static inline int ffs(int x)
x >>= 2;
r += 2;
}
if (!(x & 1)) {
x >>= 1;
if (!(x & 1))
r += 1;
}
return r;
}
@@ -148,10 +146,8 @@ static inline int fls(int x)
x <<= 2;
r -= 2;
}
if (!(x & 0x80000000u)) {
x <<= 1;
if (!(x & 0x80000000u))
r -= 1;
}
return r;
}

165
include/sbi/sbi_domain.h Normal file
View File

@@ -0,0 +1,165 @@
/*
* SPDX-License-Identifier: BSD-2-Clause
*
* Copyright (c) 2020 Western Digital Corporation or its affiliates.
*
* Authors:
* Anup Patel <anup.patel@wdc.com>
*/
#ifndef __SBI_DOMAIN_H__
#define __SBI_DOMAIN_H__
#include <sbi/sbi_types.h>
#include <sbi/sbi_hartmask.h>
struct sbi_scratch;
/** Domain access types */
enum sbi_domain_access {
SBI_DOMAIN_READ = (1UL << 0),
SBI_DOMAIN_WRITE = (1UL << 1),
SBI_DOMAIN_EXECUTE = (1UL << 2),
SBI_DOMAIN_MMIO = (1UL << 3)
};
/** Representation of OpenSBI domain memory region */
struct sbi_domain_memregion {
/**
* Size of memory region as power of 2
* It has to be minimum 3 and maximum __riscv_xlen
*/
unsigned long order;
/**
* Base address of memory region
* It must be 2^order aligned address
*/
unsigned long base;
/** Flags representing memory region attributes */
#define SBI_DOMAIN_MEMREGION_READABLE (1UL << 0)
#define SBI_DOMAIN_MEMREGION_WRITEABLE (1UL << 1)
#define SBI_DOMAIN_MEMREGION_EXECUTABLE (1UL << 2)
#define SBI_DOMAIN_MEMREGION_MMODE (1UL << 3)
#define SBI_DOMAIN_MEMREGION_ACCESS_MASK (0xfUL)
#define SBI_DOMAIN_MEMREGION_MMIO (1UL << 31)
unsigned long flags;
};
/** Maximum number of domains */
#define SBI_DOMAIN_MAX_INDEX 32
/** Representation of OpenSBI domain */
struct sbi_domain {
/**
* Logical index of this domain
* Note: This set by sbi_domain_finalize() in the coldboot path
*/
u32 index;
/**
* HARTs assigned to this domain
* Note: This set by sbi_domain_init() and sbi_domain_finalize()
* in the coldboot path
*/
struct sbi_hartmask assigned_harts;
/** Name of this domain */
char name[64];
/** Possible HARTs in this domain */
const struct sbi_hartmask *possible_harts;
/** Array of memory regions terminated by a region with order zero */
struct sbi_domain_memregion *regions;
/** HART id of the HART booting this domain */
u32 boot_hartid;
/** Arg1 (or 'a1' register) of next booting stage for this domain */
unsigned long next_arg1;
/** Address of next booting stage for this domain */
unsigned long next_addr;
/** Privilege mode of next booting stage for this domain */
unsigned long next_mode;
/** Is domain allowed to reset the system */
bool system_reset_allowed;
};
/** HART id to domain table */
extern struct sbi_domain *hartid_to_domain_table[];
/** Get pointer to sbi_domain from HART id */
#define sbi_hartid_to_domain(__hartid) \
hartid_to_domain_table[__hartid]
/** Get pointer to sbi_domain for current HART */
#define sbi_domain_thishart_ptr() \
sbi_hartid_to_domain(current_hartid())
/** Index to domain table */
extern struct sbi_domain *domidx_to_domain_table[];
/** Get pointer to sbi_domain from index */
#define sbi_index_to_domain(__index) \
domidx_to_domain_table[__index]
/** Iterate over each domain */
#define sbi_domain_for_each(__i, __d) \
for ((__i) = 0; ((__d) = sbi_index_to_domain(__i)); (__i)++)
/** Iterate over each memory region of a domain */
#define sbi_domain_for_each_memregion(__d, __r) \
for ((__r) = (__d)->regions; (__r)->order; (__r)++)
/**
* Check whether given HART is assigned to specified domain
* @param dom pointer to domain
* @param hartid the HART ID
* @return TRUE if HART is assigned to domain otherwise FALSE
*/
bool sbi_domain_is_assigned_hart(const struct sbi_domain *dom, u32 hartid);
/**
* Get ulong assigned HART mask for given domain and HART base ID
* @param dom pointer to domain
* @param hbase the HART base ID
* @return ulong possible HART mask
* Note: the return ulong mask will be set to zero on failure.
*/
ulong sbi_domain_get_assigned_hartmask(const struct sbi_domain *dom,
ulong hbase);
/** Initialize a domain memory region as firmware region */
void sbi_domain_memregion_initfw(struct sbi_domain_memregion *reg);
/**
* Check whether we can access specified address for given mode and
* memory region flags under a domain
* @param dom pointer to domain
* @param addr the address to be checked
* @param mode the privilege mode of access
* @param access_flags bitmask of domain access types (enum sbi_domain_access)
* @return TRUE if access allowed otherwise FALSE
*/
bool sbi_domain_check_addr(const struct sbi_domain *dom,
unsigned long addr, unsigned long mode,
unsigned long access_flags);
/** Dump domain details on the console */
void sbi_domain_dump(const struct sbi_domain *dom, const char *suffix);
/** Dump all domain details on the console */
void sbi_domain_dump_all(const char *suffix);
/**
* Register a new domain
* @param dom pointer to domain
* @param assign_mask pointer to HART mask of HARTs assigned to the domain
*
* @return 0 on success and negative error code on failure
*/
int sbi_domain_register(struct sbi_domain *dom,
const struct sbi_hartmask *assign_mask);
/** Finalize domain tables and startup non-root domains */
int sbi_domain_finalize(struct sbi_scratch *scratch, u32 cold_hartid);
/** Initialize domains */
int sbi_domain_init(struct sbi_scratch *scratch, u32 cold_hartid);
#endif

View File

@@ -26,7 +26,8 @@ struct sbi_ecall_extension {
unsigned long extid_end;
int (* probe)(unsigned long extid, unsigned long *out_val);
int (* handle)(unsigned long extid, unsigned long funcid,
unsigned long *args, unsigned long *out_val,
const struct sbi_trap_regs *regs,
unsigned long *out_val,
struct sbi_trap_info *out_trap);
};
@@ -37,6 +38,7 @@ extern struct sbi_ecall_extension ecall_rfence;
extern struct sbi_ecall_extension ecall_ipi;
extern struct sbi_ecall_extension ecall_vendor;
extern struct sbi_ecall_extension ecall_hsm;
extern struct sbi_ecall_extension ecall_srst;
u16 sbi_ecall_version_major(void);

View File

@@ -27,6 +27,7 @@
#define SBI_EXT_IPI 0x735049
#define SBI_EXT_RFENCE 0x52464E43
#define SBI_EXT_HSM 0x48534D
#define SBI_EXT_SRST 0x53525354
/* SBI function IDs for BASE extension*/
#define SBI_EXT_BASE_GET_SPEC_VERSION 0x0
@@ -62,6 +63,17 @@
#define SBI_HSM_HART_STATUS_START_PENDING 0x2
#define SBI_HSM_HART_STATUS_STOP_PENDING 0x3
/* SBI function IDs for SRST extension */
#define SBI_EXT_SRST_RESET 0x0
#define SBI_SRST_RESET_TYPE_SHUTDOWN 0x0
#define SBI_SRST_RESET_TYPE_COLD_REBOOT 0x1
#define SBI_SRST_RESET_TYPE_WARM_REBOOT 0x2
#define SBI_SRST_RESET_TYPE_LAST SBI_SRST_RESET_TYPE_WARM_REBOOT
#define SBI_SRST_RESET_REASON_NONE 0x0
#define SBI_SRST_RESET_REASON_SYSFAIL 0x1
#define SBI_SPEC_VERSION_MAJOR_OFFSET 24
#define SBI_SPEC_VERSION_MAJOR_MASK 0x7f
#define SBI_SPEC_VERSION_MINOR_MASK 0xffffff

View File

@@ -14,14 +14,12 @@
/** 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),
SBI_HART_HAS_SCOUNTEREN = (1 << 0),
/** Hart has M-mode counter enable */
SBI_HART_HAS_MCOUNTEREN = (1 << 2),
SBI_HART_HAS_MCOUNTEREN = (1 << 1),
/** HART has timer csr implementation in hardware */
SBI_HART_HAS_TIME = (1 << 3),
SBI_HART_HAS_TIME = (1 << 2),
/** Last index of Hart features*/
SBI_HART_HAS_LAST_FEATURE = SBI_HART_HAS_TIME,
@@ -29,7 +27,7 @@ enum sbi_hart_features {
struct sbi_scratch;
int sbi_hart_init(struct sbi_scratch *scratch, u32 hartid, bool cold_boot);
int sbi_hart_init(struct sbi_scratch *scratch, bool cold_boot);
extern void (*sbi_hart_expected_trap)(void);
static inline ulong sbi_hart_expected_trap_addr(void)
@@ -37,14 +35,13 @@ static inline ulong sbi_hart_expected_trap_addr(void)
return (ulong)sbi_hart_expected_trap;
}
void sbi_hart_delegation_dump(struct sbi_scratch *scratch);
unsigned int sbi_hart_mhpm_count(struct sbi_scratch *scratch);
void sbi_hart_delegation_dump(struct sbi_scratch *scratch,
const char *prefix, const char *suffix);
unsigned int sbi_hart_pmp_count(struct sbi_scratch *scratch);
int sbi_hart_pmp_get(struct sbi_scratch *scratch, unsigned int n,
unsigned long *prot_out, unsigned long *addr_out,
unsigned long *size);
void sbi_hart_pmp_dump(struct sbi_scratch *scratch);
int sbi_hart_pmp_check_addr(struct sbi_scratch *scratch, unsigned long daddr,
unsigned long attr);
unsigned long sbi_hart_pmp_granularity(struct sbi_scratch *scratch);
unsigned int sbi_hart_pmp_addrbits(struct sbi_scratch *scratch);
int sbi_hart_pmp_configure(struct sbi_scratch *scratch);
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);

View File

@@ -67,7 +67,7 @@ static inline void sbi_hartmask_clear_hart(u32 h, struct sbi_hartmask *m)
* @param h HART id to test
* @param m the hartmask pointer
*/
static inline int sbi_hartmask_test_hart(u32 h, struct sbi_hartmask *m)
static inline int sbi_hartmask_test_hart(u32 h, const struct sbi_hartmask *m)
{
if (h < SBI_HARTMASK_MAX_BITS)
return __test_bit(h, m->bits);

View File

@@ -19,18 +19,20 @@
#define SBI_HART_STARTED 3
#define SBI_HART_UNKNOWN 4
struct sbi_domain;
struct sbi_scratch;
int sbi_hsm_init(struct sbi_scratch *scratch, u32 hartid, bool cold_boot);
void __noreturn sbi_hsm_exit(struct sbi_scratch *scratch);
int sbi_hsm_hart_start(struct sbi_scratch *scratch, u32 hartid,
ulong saddr, ulong priv);
int sbi_hsm_hart_start(struct sbi_scratch *scratch,
const struct sbi_domain *dom,
u32 hartid, ulong saddr, ulong smode, ulong priv);
int sbi_hsm_hart_stop(struct sbi_scratch *scratch, bool exitnow);
int sbi_hsm_hart_get_state(u32 hartid);
int sbi_hsm_hart_get_state(const struct sbi_domain *dom, u32 hartid);
int sbi_hsm_hart_state_to_status(int state);
bool sbi_hsm_hart_started(u32 hartid);
int sbi_hsm_hart_started_mask(ulong hbase, ulong *out_hmask);
int sbi_hsm_hart_started_mask(const struct sbi_domain *dom,
ulong hbase, ulong *out_hmask);
void sbi_hsm_prepare_next_jump(struct sbi_scratch *scratch, u32 hartid);
#endif

View File

@@ -40,12 +40,15 @@
#ifndef __ASSEMBLY__
#include <sbi/sbi_ecall.h>
#include <sbi/sbi_ecall_interface.h>
#include <sbi/sbi_error.h>
#include <sbi/sbi_scratch.h>
#include <sbi/sbi_trap.h>
#include <sbi/sbi_version.h>
struct sbi_domain_memregion;
struct sbi_trap_info;
struct sbi_trap_regs;
/** Possible feature flags of a platform */
enum sbi_platform_features {
/** Platform has timer value */
@@ -89,14 +92,10 @@ struct sbi_platform_operations {
*/
int (*misa_get_xlen)(void);
/** Get number of PMP regions for given HART */
u32 (*pmp_region_count)(u32 hartid);
/**
* Get PMP regions details (namely: protection, base address,
* and size) for given HART
*/
int (*pmp_region_info)(u32 hartid, u32 index, ulong *prot, ulong *addr,
ulong *log2size);
/** Get platform specific root domain memory regions */
struct sbi_domain_memregion *(*domains_root_regions)(void);
/** Initialize (or populate) domains for the platform */
int (*domains_init)(void);
/** Write a character to the platform console output */
void (*console_putc)(char ch);
@@ -141,20 +140,19 @@ struct sbi_platform_operations {
*/
int (*hart_stop)(void);
/* Check whether reset type and reason supported by the platform */
int (*system_reset_check)(u32 reset_type, u32 reset_reason);
/** Reset the platform */
#define SBI_PLATFORM_RESET_SHUTDOWN 0
#define SBI_PLATFORM_RESET_COLD 1
#define SBI_PLATFORM_RESET_WARM 2
int (*system_reset)(u32 reset_type);
void (*system_reset)(u32 reset_type, u32 reset_reason);
/** platform specific SBI extension implementation probe function */
int (*vendor_ext_check)(long extid);
/** platform specific SBI extension implementation provider */
int (*vendor_ext_provider)(long extid, long funcid,
unsigned long *args,
const struct sbi_trap_regs *regs,
unsigned long *out_value,
struct sbi_trap_info *out_trap);
} __packed;
};
/** Platform default per-HART stack size for exception/interrupt handling */
#define SBI_PLATFORM_DEFAULT_HART_STACK_SIZE 8192
@@ -201,7 +199,7 @@ struct sbi_platform {
* 2. HART id < SBI_HARTMASK_MAX_BITS
*/
const u32 *hart_index2id;
} __packed;
};
/** Get pointer to sbi_platform for sbi_scratch pointer */
#define sbi_platform_ptr(__s) \
@@ -457,43 +455,32 @@ static inline int sbi_platform_misa_xlen(const struct sbi_platform *plat)
}
/**
* Get the number of PMP regions of a HART
* Get platform specific root domain memory regions
*
* @param plat pointer to struct sbi_platform
* @param hartid HART ID
*
* @return number of PMP regions
* @return an array of memory regions terminated by a region with order zero
* or NULL for no memory regions
*/
static inline u32 sbi_platform_pmp_region_count(const struct sbi_platform *plat,
u32 hartid)
static inline struct sbi_domain_memregion *
sbi_platform_domains_root_regions(const struct sbi_platform *plat)
{
if (plat && sbi_platform_ops(plat)->pmp_region_count)
return sbi_platform_ops(plat)->pmp_region_count(hartid);
return 0;
if (plat && sbi_platform_ops(plat)->domains_root_regions)
return sbi_platform_ops(plat)->domains_root_regions();
return NULL;
}
/**
* Get PMP regions details (namely: protection, base address,
* and size) of a HART
* Initialize (or populate) domains for the platform
*
* @param plat pointer to struct sbi_platform
* @param hartid HART ID
* @param index index of PMP region for which we want details
* @param prot output pointer for PMP region protection
* @param addr output pointer for PMP region base address
* @param log2size output pointer for log-of-2 PMP region size
*
* @return 0 on success and negative error code on failure
*/
static inline int sbi_platform_pmp_region_info(const struct sbi_platform *plat,
u32 hartid, u32 index,
ulong *prot, ulong *addr,
ulong *log2size)
static inline int sbi_platform_domains_init(const struct sbi_platform *plat)
{
if (plat && sbi_platform_ops(plat)->pmp_region_info)
return sbi_platform_ops(plat)->pmp_region_info(hartid, index,
prot, addr,
log2size);
if (plat && sbi_platform_ops(plat)->domains_init)
return sbi_platform_ops(plat)->domains_init();
return 0;
}
@@ -685,19 +672,38 @@ static inline void sbi_platform_timer_exit(const struct sbi_platform *plat)
}
/**
* Reset the platform
* Check whether reset type and reason supported by the platform
*
* @param plat pointer to struct sbi_platform
* @param reset_type type of reset
* @param reset_reason reason for reset
*
* @return 0 on success and negative error code on failure
* @return 0 if reset type and reason not supported and 1 if supported
*/
static inline int sbi_platform_system_reset(const struct sbi_platform *plat,
u32 reset_type)
static inline int sbi_platform_system_reset_check(
const struct sbi_platform *plat,
u32 reset_type, u32 reset_reason)
{
if (plat && sbi_platform_ops(plat)->system_reset_check)
return sbi_platform_ops(plat)->system_reset_check(reset_type,
reset_reason);
return 0;
}
/**
* Reset the platform
*
* This function will not return for supported reset type and reset reason
*
* @param plat pointer to struct sbi_platform
* @param reset_type type of reset
* @param reset_reason reason for reset
*/
static inline void sbi_platform_system_reset(const struct sbi_platform *plat,
u32 reset_type, u32 reset_reason)
{
if (plat && sbi_platform_ops(plat)->system_reset)
return sbi_platform_ops(plat)->system_reset(reset_type);
return 0;
sbi_platform_ops(plat)->system_reset(reset_type, reset_reason);
}
/**
@@ -723,7 +729,7 @@ static inline int sbi_platform_vendor_ext_check(const struct sbi_platform *plat,
* @param plat pointer to struct sbi_platform
* @param extid vendor SBI extension id
* @param funcid SBI function id within the extension id
* @param args pointer to arguments passed by the caller
* @param regs pointer to trap registers passed by the caller
* @param out_value output value that can be filled by the callee
* @param out_trap trap info that can be filled by the callee
*
@@ -732,13 +738,13 @@ static inline int sbi_platform_vendor_ext_check(const struct sbi_platform *plat,
static inline int sbi_platform_vendor_ext_provider(
const struct sbi_platform *plat,
long extid, long funcid,
unsigned long *args,
const struct sbi_trap_regs *regs,
unsigned long *out_value,
struct sbi_trap_info *out_trap)
{
if (plat && sbi_platform_ops(plat)->vendor_ext_provider) {
return sbi_platform_ops(plat)->vendor_ext_provider(extid,
funcid, args,
funcid, regs,
out_value,
out_trap);
}

View File

@@ -30,12 +30,14 @@
#define SBI_SCRATCH_PLATFORM_ADDR_OFFSET (6 * __SIZEOF_POINTER__)
/** Offset of hartid_to_scratch member in sbi_scratch */
#define SBI_SCRATCH_HARTID_TO_SCRATCH_OFFSET (7 * __SIZEOF_POINTER__)
/** Offset of trap_exit member in sbi_scratch */
#define SBI_SCRATCH_TRAP_EXIT_OFFSET (8 * __SIZEOF_POINTER__)
/** Offset of tmp0 member in sbi_scratch */
#define SBI_SCRATCH_TMP0_OFFSET (8 * __SIZEOF_POINTER__)
#define SBI_SCRATCH_TMP0_OFFSET (9 * __SIZEOF_POINTER__)
/** Offset of options member in sbi_scratch */
#define SBI_SCRATCH_OPTIONS_OFFSET (9 * __SIZEOF_POINTER__)
#define SBI_SCRATCH_OPTIONS_OFFSET (10 * __SIZEOF_POINTER__)
/** Offset of extra space in sbi_scratch */
#define SBI_SCRATCH_EXTRA_SPACE_OFFSET (10 * __SIZEOF_POINTER__)
#define SBI_SCRATCH_EXTRA_SPACE_OFFSET (11 * __SIZEOF_POINTER__)
/** Maximum size of sbi_scratch (4KB) */
#define SBI_SCRATCH_SIZE (0x1000)
@@ -63,11 +65,13 @@ struct sbi_scratch {
unsigned long platform_addr;
/** Address of HART ID to sbi_scratch conversion function */
unsigned long hartid_to_scratch;
/** Address of trap exit function */
unsigned long trap_exit;
/** Temporary storage */
unsigned long tmp0;
/** Options for OpenSBI library */
unsigned long options;
} __packed;
};
/** Possible options for OpenSBI library */
enum sbi_scratch_options {
@@ -85,7 +89,7 @@ enum sbi_scratch_options {
#define sbi_scratch_thishart_arg1_ptr() \
((void *)(sbi_scratch_thishart_ptr()->next_arg1))
/** Initialize scatch table and allocator */
/** Initialize scratch table and allocator */
int sbi_scratch_init(struct sbi_scratch *scratch);
/**

View File

@@ -12,8 +12,15 @@
#include <sbi/sbi_types.h>
/*
Provides sbi_strcmp for the completeness of supporting string functions.
it is not recommended to use sbi_strcmp() but use sbi_strncmp instead.
*/
int sbi_strcmp(const char *a, const char *b);
int sbi_strncmp(const char *a, const char *b, size_t count);
size_t sbi_strlen(const char *str);
size_t sbi_strnlen(const char *str, size_t count);

View File

@@ -12,6 +12,8 @@
#include <sbi/sbi_types.h>
void __noreturn sbi_system_reset(u32 platform_reset_type);
bool sbi_system_reset_supported(u32 reset_type, u32 reset_reason);
void __noreturn sbi_system_reset(u32 reset_type, u32 reset_reason);
#endif

View File

@@ -22,16 +22,6 @@
#define SBI_TLB_FIFO_NUM_ENTRIES 8
enum sbi_tlb_info_types {
SBI_TLB_FLUSH_VMA,
SBI_TLB_FLUSH_VMA_ASID,
SBI_TLB_FLUSH_GVMA,
SBI_TLB_FLUSH_GVMA_VMID,
SBI_TLB_FLUSH_VVMA,
SBI_TLB_FLUSH_VVMA_ASID,
SBI_ITLB_FLUSH
};
struct sbi_scratch;
struct sbi_tlb_info {
@@ -39,17 +29,25 @@ struct sbi_tlb_info {
unsigned long size;
unsigned long asid;
unsigned long vmid;
unsigned long type;
void (*local_fn)(struct sbi_tlb_info *tinfo);
struct sbi_hartmask smask;
};
#define SBI_TLB_INFO_INIT(__p, __start, __size, __asid, __vmid, __type, __src) \
void sbi_tlb_local_hfence_vvma(struct sbi_tlb_info *tinfo);
void sbi_tlb_local_hfence_gvma(struct sbi_tlb_info *tinfo);
void sbi_tlb_local_sfence_vma(struct sbi_tlb_info *tinfo);
void sbi_tlb_local_hfence_vvma_asid(struct sbi_tlb_info *tinfo);
void sbi_tlb_local_hfence_gvma_vmid(struct sbi_tlb_info *tinfo);
void sbi_tlb_local_sfence_vma_asid(struct sbi_tlb_info *tinfo);
void sbi_tlb_local_fence_i(struct sbi_tlb_info *tinfo);
#define SBI_TLB_INFO_INIT(__p, __start, __size, __asid, __vmid, __lfn, __src) \
do { \
(__p)->start = (__start); \
(__p)->size = (__size); \
(__p)->asid = (__asid); \
(__p)->vmid = (__vmid); \
(__p)->type = (__type); \
(__p)->local_fn = (__lfn); \
SBI_HARTMASK_INIT_EXCEPT(&(__p)->smask, (__src)); \
} while (0)

View File

@@ -186,7 +186,7 @@ struct sbi_trap_regs {
unsigned long mstatus;
/** mstatusH register state (only for 32-bit) */
unsigned long mstatusH;
} __packed;
};
/** Representation of trap details */
struct sbi_trap_info {
@@ -207,6 +207,8 @@ int sbi_trap_redirect(struct sbi_trap_regs *regs,
void sbi_trap_handler(struct sbi_trap_regs *regs);
void __noreturn sbi_trap_exit(const struct sbi_trap_regs *regs);
#endif
#endif

View File

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

View File

@@ -0,0 +1,73 @@
// SPDX-License-Identifier: BSD-2-Clause
/*
* fdt_domain.c - Flat Device Tree Domain helper routines
*
* Copyright (c) 2020 Western Digital Corporation or its affiliates.
*
* Authors:
* Anup Patel <anup.patel@wdc.com>
*/
#ifndef __FDT_DOMAIN_H__
#define __FDT_DOMAIN_H__
#include <sbi/sbi_types.h>
struct sbi_domain;
/**
* Iterate over each domains in device tree
*
* @param fdt device tree blob
* @param opaque private pointer for each iteration
* @param fn callback function for each iteration
*
* @return 0 on success and negative error code on failure
*/
int fdt_iterate_each_domain(void *fdt, void *opaque,
int (*fn)(void *fdt, int domain_offset,
void *opaque));
/**
* Iterate over each memregion of a domain in device tree
*
* @param fdt device tree blob
* @param domain_offset domain DT node offset
* @param opaque private pointer for each iteration
* @param fn callback function for each iteration
*
* @return 0 on success and negative error code on failure
*/
int fdt_iterate_each_memregion(void *fdt, int domain_offset, void *opaque,
int (*fn)(void *fdt, int domain_offset,
int region_offset, u32 region_access,
void *opaque));
/**
* Fix up the domain configuration in the device tree
*
* This routine:
* 1. Disables MMIO devices not accessible to the coldboot HART domain
* 2. Removes "opensbi-domain" DT property from CPU DT nodes
* 3. Removes domain configuration DT node under /chosen DT node
*
* It is recommended that platform support call this function in
* their final_init() platform operation.
*
* @param fdt device tree blob
*/
void fdt_domain_fixup(void *fdt);
/**
* Populate domains from device tree
*
* It is recommended that platform support call this function in
* their domains_init() platform operation.
*
* @param fdt device tree blob
*
* @return 0 on success and negative error code on failure
*/
int fdt_domains_populate(void *fdt);
#endif /* __FDT_DOMAIN_H__ */

View File

@@ -15,10 +15,13 @@
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 (*system_reset_check)(u32 reset_type, u32 reset_reason);
void (*system_reset)(u32 reset_type, u32 reset_reason);
};
int fdt_system_reset(u32 reset_type);
int fdt_system_reset_check(u32 reset_type, u32 reset_reason);
void fdt_system_reset(u32 reset_type, u32 reset_reason);
int fdt_reset_init(void);

View File

@@ -14,6 +14,8 @@ void htif_putc(char ch);
int htif_getc(void);
int htif_system_reset(u32 type);
int htif_system_reset_check(u32 type, u32 reason);
void htif_system_reset(u32 type, u32 reason);
#endif

View File

@@ -12,7 +12,9 @@
#include <sbi/sbi_types.h>
int sifive_test_system_reset(u32 type);
int sifive_test_system_reset_check(u32 type, u32 reason);
void sifive_test_system_reset(u32 type, u32 reason);
int sifive_test_init(unsigned long base);

View File

@@ -15,6 +15,7 @@ libsbi-objs-y += riscv_locks.o
libsbi-objs-y += sbi_bitmap.o
libsbi-objs-y += sbi_bitops.o
libsbi-objs-y += sbi_console.o
libsbi-objs-y += sbi_domain.o
libsbi-objs-y += sbi_ecall.o
libsbi-objs-y += sbi_ecall_base.o
libsbi-objs-y += sbi_ecall_hsm.o

View File

@@ -90,142 +90,88 @@ void misa_string(int xlen, char *out, unsigned int out_sz)
unsigned long csr_read_num(int csr_num)
{
#define switchcase_csr_read(__csr_num, __val) \
case __csr_num: \
__val = csr_read(__csr_num); \
break;
#define switchcase_csr_read_2(__csr_num, __val) \
switchcase_csr_read(__csr_num + 0, __val) \
switchcase_csr_read(__csr_num + 1, __val)
#define switchcase_csr_read_4(__csr_num, __val) \
switchcase_csr_read_2(__csr_num + 0, __val) \
switchcase_csr_read_2(__csr_num + 2, __val)
#define switchcase_csr_read_8(__csr_num, __val) \
switchcase_csr_read_4(__csr_num + 0, __val) \
switchcase_csr_read_4(__csr_num + 4, __val)
#define switchcase_csr_read_16(__csr_num, __val) \
switchcase_csr_read_8(__csr_num + 0, __val) \
switchcase_csr_read_8(__csr_num + 8, __val)
#define switchcase_csr_read_32(__csr_num, __val) \
switchcase_csr_read_16(__csr_num + 0, __val) \
switchcase_csr_read_16(__csr_num + 16, __val)
#define switchcase_csr_read_64(__csr_num, __val) \
switchcase_csr_read_32(__csr_num + 0, __val) \
switchcase_csr_read_32(__csr_num + 32, __val)
unsigned long ret = 0;
switch (csr_num) {
case CSR_PMPCFG0:
ret = csr_read(CSR_PMPCFG0);
break;
case CSR_PMPCFG1:
ret = csr_read(CSR_PMPCFG1);
break;
case CSR_PMPCFG2:
ret = csr_read(CSR_PMPCFG2);
break;
case CSR_PMPCFG3:
ret = csr_read(CSR_PMPCFG3);
break;
case CSR_PMPADDR0:
ret = csr_read(CSR_PMPADDR0);
break;
case CSR_PMPADDR1:
ret = csr_read(CSR_PMPADDR1);
break;
case CSR_PMPADDR2:
ret = csr_read(CSR_PMPADDR2);
break;
case CSR_PMPADDR3:
ret = csr_read(CSR_PMPADDR3);
break;
case CSR_PMPADDR4:
ret = csr_read(CSR_PMPADDR4);
break;
case CSR_PMPADDR5:
ret = csr_read(CSR_PMPADDR5);
break;
case CSR_PMPADDR6:
ret = csr_read(CSR_PMPADDR6);
break;
case CSR_PMPADDR7:
ret = csr_read(CSR_PMPADDR7);
break;
case CSR_PMPADDR8:
ret = csr_read(CSR_PMPADDR8);
break;
case CSR_PMPADDR9:
ret = csr_read(CSR_PMPADDR9);
break;
case CSR_PMPADDR10:
ret = csr_read(CSR_PMPADDR10);
break;
case CSR_PMPADDR11:
ret = csr_read(CSR_PMPADDR11);
break;
case CSR_PMPADDR12:
ret = csr_read(CSR_PMPADDR12);
break;
case CSR_PMPADDR13:
ret = csr_read(CSR_PMPADDR13);
break;
case CSR_PMPADDR14:
ret = csr_read(CSR_PMPADDR14);
break;
case CSR_PMPADDR15:
ret = csr_read(CSR_PMPADDR15);
break;
switchcase_csr_read_16(CSR_PMPCFG0, ret)
switchcase_csr_read_64(CSR_PMPADDR0, ret)
default:
break;
};
return ret;
#undef switchcase_csr_read_64
#undef switchcase_csr_read_32
#undef switchcase_csr_read_16
#undef switchcase_csr_read_8
#undef switchcase_csr_read_4
#undef switchcase_csr_read_2
#undef switchcase_csr_read
}
void csr_write_num(int csr_num, unsigned long val)
{
#define switchcase_csr_write(__csr_num, __val) \
case __csr_num: \
csr_write(__csr_num, __val); \
break;
#define switchcase_csr_write_2(__csr_num, __val) \
switchcase_csr_write(__csr_num + 0, __val) \
switchcase_csr_write(__csr_num + 1, __val)
#define switchcase_csr_write_4(__csr_num, __val) \
switchcase_csr_write_2(__csr_num + 0, __val) \
switchcase_csr_write_2(__csr_num + 2, __val)
#define switchcase_csr_write_8(__csr_num, __val) \
switchcase_csr_write_4(__csr_num + 0, __val) \
switchcase_csr_write_4(__csr_num + 4, __val)
#define switchcase_csr_write_16(__csr_num, __val) \
switchcase_csr_write_8(__csr_num + 0, __val) \
switchcase_csr_write_8(__csr_num + 8, __val)
#define switchcase_csr_write_32(__csr_num, __val) \
switchcase_csr_write_16(__csr_num + 0, __val) \
switchcase_csr_write_16(__csr_num + 16, __val)
#define switchcase_csr_write_64(__csr_num, __val) \
switchcase_csr_write_32(__csr_num + 0, __val) \
switchcase_csr_write_32(__csr_num + 32, __val)
switch (csr_num) {
case CSR_PMPCFG0:
csr_write(CSR_PMPCFG0, val);
break;
case CSR_PMPCFG1:
csr_write(CSR_PMPCFG1, val);
break;
case CSR_PMPCFG2:
csr_write(CSR_PMPCFG2, val);
break;
case CSR_PMPCFG3:
csr_write(CSR_PMPCFG3, val);
break;
case CSR_PMPADDR0:
csr_write(CSR_PMPADDR0, val);
break;
case CSR_PMPADDR1:
csr_write(CSR_PMPADDR1, val);
break;
case CSR_PMPADDR2:
csr_write(CSR_PMPADDR2, val);
break;
case CSR_PMPADDR3:
csr_write(CSR_PMPADDR3, val);
break;
case CSR_PMPADDR4:
csr_write(CSR_PMPADDR4, val);
break;
case CSR_PMPADDR5:
csr_write(CSR_PMPADDR5, val);
break;
case CSR_PMPADDR6:
csr_write(CSR_PMPADDR6, val);
break;
case CSR_PMPADDR7:
csr_write(CSR_PMPADDR7, val);
break;
case CSR_PMPADDR8:
csr_write(CSR_PMPADDR8, val);
break;
case CSR_PMPADDR9:
csr_write(CSR_PMPADDR9, val);
break;
case CSR_PMPADDR10:
csr_write(CSR_PMPADDR10, val);
break;
case CSR_PMPADDR11:
csr_write(CSR_PMPADDR11, val);
break;
case CSR_PMPADDR12:
csr_write(CSR_PMPADDR12, val);
break;
case CSR_PMPADDR13:
csr_write(CSR_PMPADDR13, val);
break;
case CSR_PMPADDR14:
csr_write(CSR_PMPADDR14, val);
break;
case CSR_PMPADDR15:
csr_write(CSR_PMPADDR15, val);
break;
switchcase_csr_write_16(CSR_PMPCFG0, val)
switchcase_csr_write_64(CSR_PMPADDR0, val)
default:
break;
};
#undef switchcase_csr_write_64
#undef switchcase_csr_write_32
#undef switchcase_csr_write_16
#undef switchcase_csr_write_8
#undef switchcase_csr_write_4
#undef switchcase_csr_write_2
#undef switchcase_csr_write
}
static unsigned long ctz(unsigned long x)
@@ -293,16 +239,16 @@ int pmp_set(unsigned int n, unsigned long prot, unsigned long addr,
}
int pmp_get(unsigned int n, unsigned long *prot_out, unsigned long *addr_out,
unsigned long *size)
unsigned long *log2len)
{
int pmpcfg_csr, pmpcfg_shift, pmpaddr_csr;
unsigned long cfgmask, pmpcfg, prot;
unsigned long t1, addr, log2len;
unsigned long t1, addr, len;
/* check parameters */
if (n >= PMP_COUNT || !prot_out || !addr_out || !size)
if (n >= PMP_COUNT || !prot_out || !addr_out || !log2len)
return SBI_EINVAL;
*prot_out = *addr_out = *size = 0;
*prot_out = *addr_out = *log2len = 0;
/* calculate PMP register and offset */
#if __riscv_xlen == 32
@@ -329,23 +275,21 @@ int pmp_get(unsigned int n, unsigned long *prot_out, unsigned long *addr_out,
addr = csr_read_num(pmpaddr_csr);
if (addr == -1UL) {
addr = 0;
log2len = __riscv_xlen;
len = __riscv_xlen;
} else {
t1 = ctz(~addr);
addr = (addr & ~((1UL << t1) - 1)) << PMP_SHIFT;
log2len = (t1 + PMP_SHIFT + 1);
len = (t1 + PMP_SHIFT + 1);
}
} else {
addr = csr_read_num(pmpaddr_csr) << PMP_SHIFT;
log2len = PMP_SHIFT;
len = PMP_SHIFT;
}
/* return details */
*prot_out = prot;
*addr_out = addr;
if (log2len < __riscv_xlen)
*size = (1UL << log2len);
*log2len = len;
return 0;
}

539
lib/sbi/sbi_domain.c Normal file
View File

@@ -0,0 +1,539 @@
/*
* SPDX-License-Identifier: BSD-2-Clause
*
* Copyright (c) 2020 Western Digital Corporation or its affiliates.
*
* Authors:
* Anup Patel <anup.patel@wdc.com>
*/
#include <sbi/riscv_asm.h>
#include <sbi/sbi_console.h>
#include <sbi/sbi_domain.h>
#include <sbi/sbi_hartmask.h>
#include <sbi/sbi_hsm.h>
#include <sbi/sbi_math.h>
#include <sbi/sbi_platform.h>
#include <sbi/sbi_scratch.h>
#include <sbi/sbi_string.h>
struct sbi_domain *hartid_to_domain_table[SBI_HARTMASK_MAX_BITS] = { 0 };
struct sbi_domain *domidx_to_domain_table[SBI_DOMAIN_MAX_INDEX] = { 0 };
static u32 domain_count = 0;
static struct sbi_hartmask root_hmask = { 0 };
#define ROOT_FW_REGION 0
#define ROOT_ALL_REGION 1
#define ROOT_END_REGION 2
static struct sbi_domain_memregion root_memregs[ROOT_END_REGION + 1] = { 0 };
static struct sbi_domain root = {
.name = "root",
.possible_harts = &root_hmask,
.regions = root_memregs,
.system_reset_allowed = TRUE,
};
bool sbi_domain_is_assigned_hart(const struct sbi_domain *dom, u32 hartid)
{
if (dom)
return sbi_hartmask_test_hart(hartid, &dom->assigned_harts);
return FALSE;
}
ulong sbi_domain_get_assigned_hartmask(const struct sbi_domain *dom,
ulong hbase)
{
ulong ret, bword, boff;
if (!dom)
return 0;
bword = BIT_WORD(hbase);
boff = BIT_WORD_OFFSET(hbase);
ret = sbi_hartmask_bits(&dom->assigned_harts)[bword++] >> boff;
if (boff && bword < BIT_WORD(SBI_HARTMASK_MAX_BITS)) {
ret |= (sbi_hartmask_bits(&dom->assigned_harts)[bword] &
(BIT(boff) - 1UL)) << (BITS_PER_LONG - boff);
}
return ret;
}
void sbi_domain_memregion_initfw(struct sbi_domain_memregion *reg)
{
if (!reg)
return;
sbi_memcpy(reg, &root_memregs[ROOT_FW_REGION], sizeof(*reg));
}
bool sbi_domain_check_addr(const struct sbi_domain *dom,
unsigned long addr, unsigned long mode,
unsigned long access_flags)
{
bool mmio = FALSE;
struct sbi_domain_memregion *reg;
unsigned long rstart, rend, rflags, rwx = 0;
if (!dom)
return FALSE;
if (access_flags & SBI_DOMAIN_READ)
rwx |= SBI_DOMAIN_MEMREGION_READABLE;
if (access_flags & SBI_DOMAIN_WRITE)
rwx |= SBI_DOMAIN_MEMREGION_WRITEABLE;
if (access_flags & SBI_DOMAIN_EXECUTE)
rwx |= SBI_DOMAIN_MEMREGION_EXECUTABLE;
if (access_flags & SBI_DOMAIN_MMIO)
mmio = TRUE;
sbi_domain_for_each_memregion(dom, reg) {
rflags = reg->flags;
if (mode == PRV_M && !(rflags & SBI_DOMAIN_MEMREGION_MMODE))
continue;
rstart = reg->base;
rend = (reg->order < __riscv_xlen) ?
rstart + ((1UL << reg->order) - 1) : -1UL;
if (rstart <= addr && addr <= rend) {
if ((mmio && !(rflags & SBI_DOMAIN_MEMREGION_MMIO)) ||
(!mmio && (rflags & SBI_DOMAIN_MEMREGION_MMIO)))
return FALSE;
return ((rflags & rwx) == rwx) ? TRUE : FALSE;
}
}
return (mode == PRV_M) ? TRUE : FALSE;
}
/* Check if region complies with constraints */
static bool is_region_valid(const struct sbi_domain_memregion *reg)
{
if (reg->order < 3 || __riscv_xlen < reg->order)
return FALSE;
if (reg->base & (BIT(reg->order) - 1))
return FALSE;
return TRUE;
}
/** Check if regionA is sub-region of regionB */
static bool is_region_subset(const struct sbi_domain_memregion *regA,
const struct sbi_domain_memregion *regB)
{
ulong regA_start = regA->base;
ulong regA_end = regA->base + (BIT(regA->order) - 1);
ulong regB_start = regB->base;
ulong regB_end = regB->base + (BIT(regA->order) - 1);
if ((regB_start <= regA_start) &&
(regA_start < regB_end) &&
(regB_start < regA_end) &&
(regA_end <= regB_end))
return TRUE;
return FALSE;
}
/** Check if regionA conflicts regionB */
static bool is_region_conflict(const struct sbi_domain_memregion *regA,
const struct sbi_domain_memregion *regB)
{
if ((is_region_subset(regA, regB) || is_region_subset(regB, regA)) &&
regA->flags == regB->flags)
return TRUE;
return FALSE;
}
/** Check if regionA should be placed before regionB */
static bool is_region_before(const struct sbi_domain_memregion *regA,
const struct sbi_domain_memregion *regB)
{
if (regA->order < regB->order)
return TRUE;
if ((regA->order == regB->order) &&
(regA->base < regB->base))
return TRUE;
return FALSE;
}
static int sanitize_domain(const struct sbi_platform *plat,
struct sbi_domain *dom)
{
u32 i, j, count;
bool have_fw_reg;
struct sbi_domain_memregion treg, *reg, *reg1;
/* Check possible HARTs */
if (!dom->possible_harts) {
sbi_printf("%s: %s possible HART mask is NULL\n",
__func__, dom->name);
return SBI_EINVAL;
}
sbi_hartmask_for_each_hart(i, dom->possible_harts) {
if (sbi_platform_hart_invalid(plat, i)) {
sbi_printf("%s: %s possible HART mask has invalid "
"hart %d\n", __func__, dom->name, i);
return SBI_EINVAL;
}
};
/* Check memory regions */
if (!dom->regions) {
sbi_printf("%s: %s regions is NULL\n",
__func__, dom->name);
return SBI_EINVAL;
}
sbi_domain_for_each_memregion(dom, reg) {
if (!is_region_valid(reg)) {
sbi_printf("%s: %s has invalid region base=0x%lx "
"order=%lu flags=0x%lx\n", __func__,
dom->name, reg->base, reg->order,
reg->flags);
return SBI_EINVAL;
}
}
/* Count memory regions and check presence of firmware region */
count = 0;
have_fw_reg = FALSE;
sbi_domain_for_each_memregion(dom, reg) {
if (reg->order == root_memregs[ROOT_FW_REGION].order &&
reg->base == root_memregs[ROOT_FW_REGION].base &&
reg->flags == root_memregs[ROOT_FW_REGION].flags)
have_fw_reg = TRUE;
count++;
}
if (!have_fw_reg) {
sbi_printf("%s: %s does not have firmware region\n",
__func__, dom->name);
return SBI_EINVAL;
}
/* Sort the memory regions */
for (i = 0; i < (count - 1); i++) {
reg = &dom->regions[i];
for (j = i + 1; j < count; j++) {
reg1 = &dom->regions[j];
if (is_region_conflict(reg1, reg)) {
sbi_printf("%s: %s conflict between regions "
"(base=0x%lx order=%lu flags=0x%lx) and "
"(base=0x%lx order=%lu flags=0x%lx)\n",
__func__, dom->name,
reg->base, reg->order, reg->flags,
reg1->base, reg1->order, reg1->flags);
return SBI_EINVAL;
}
if (!is_region_before(reg1, reg))
continue;
sbi_memcpy(&treg, reg1, sizeof(treg));
sbi_memcpy(reg1, reg, sizeof(treg));
sbi_memcpy(reg, &treg, sizeof(treg));
}
}
/*
* We don't need to check boot HART id of domain because if boot
* HART id is not possible/assigned to this domain then it won't
* be started at boot-time by sbi_domain_finalize().
*/
/*
* Check next mode
*
* We only allow next mode to be S-mode or U-mode.so that we can
* protect M-mode context and enforce checks on memory accesses.
*/
if (dom->next_mode != PRV_S &&
dom->next_mode != PRV_U) {
sbi_printf("%s: %s invalid next booting stage mode 0x%lx\n",
__func__, dom->name, dom->next_mode);
return SBI_EINVAL;
}
/* Check next address and next mode*/
if (!sbi_domain_check_addr(dom, dom->next_addr, dom->next_mode,
SBI_DOMAIN_EXECUTE)) {
sbi_printf("%s: %s next booting stage addres 0x%lx can't "
"execute\n", __func__, dom->name, dom->next_addr);
return SBI_EINVAL;
}
return 0;
}
void sbi_domain_dump(const struct sbi_domain *dom, const char *suffix)
{
u32 i, k;
unsigned long rstart, rend;
struct sbi_domain_memregion *reg;
sbi_printf("Domain%d Name %s: %s\n",
dom->index, suffix, dom->name);
sbi_printf("Domain%d Boot HART %s: %d\n",
dom->index, suffix, dom->boot_hartid);
k = 0;
sbi_printf("Domain%d HARTs %s: ", dom->index, suffix);
sbi_hartmask_for_each_hart(i, dom->possible_harts)
sbi_printf("%s%d%s", (k++) ? "," : "",
i, sbi_domain_is_assigned_hart(dom, i) ? "*" : "");
sbi_printf("\n");
i = 0;
sbi_domain_for_each_memregion(dom, reg) {
rstart = reg->base;
rend = (reg->order < __riscv_xlen) ?
rstart + ((1UL << reg->order) - 1) : -1UL;
#if __riscv_xlen == 32
sbi_printf("Domain%d Region%02d %s: 0x%08lx-0x%08lx ",
#else
sbi_printf("Domain%d Region%02d %s: 0x%016lx-0x%016lx ",
#endif
dom->index, i, suffix, rstart, rend);
k = 0;
if (reg->flags & SBI_DOMAIN_MEMREGION_MMODE)
sbi_printf("%cM", (k++) ? ',' : '(');
if (reg->flags & SBI_DOMAIN_MEMREGION_MMIO)
sbi_printf("%cI", (k++) ? ',' : '(');
if (reg->flags & SBI_DOMAIN_MEMREGION_READABLE)
sbi_printf("%cR", (k++) ? ',' : '(');
if (reg->flags & SBI_DOMAIN_MEMREGION_WRITEABLE)
sbi_printf("%cW", (k++) ? ',' : '(');
if (reg->flags & SBI_DOMAIN_MEMREGION_EXECUTABLE)
sbi_printf("%cX", (k++) ? ',' : '(');
sbi_printf("%s\n", (k++) ? ")" : "()");
i++;
}
#if __riscv_xlen == 32
sbi_printf("Domain%d Next Address%s: 0x%08lx\n",
#else
sbi_printf("Domain%d Next Address%s: 0x%016lx\n",
#endif
dom->index, suffix, dom->next_addr);
#if __riscv_xlen == 32
sbi_printf("Domain%d Next Arg1 %s: 0x%08lx\n",
#else
sbi_printf("Domain%d Next Arg1 %s: 0x%016lx\n",
#endif
dom->index, suffix, dom->next_arg1);
sbi_printf("Domain%d Next Mode %s: ", dom->index, suffix);
switch (dom->next_mode) {
case PRV_M:
sbi_printf("M-mode\n");
break;
case PRV_S:
sbi_printf("S-mode\n");
break;
case PRV_U:
sbi_printf("U-mode\n");
break;
default:
sbi_printf("Unknown\n");
break;
};
sbi_printf("Domain%d SysReset %s: %s\n",
dom->index, suffix, (dom->system_reset_allowed) ? "yes" : "no");
}
void sbi_domain_dump_all(const char *suffix)
{
u32 i;
const struct sbi_domain *dom;
sbi_domain_for_each(i, dom) {
sbi_domain_dump(dom, suffix);
sbi_printf("\n");
}
}
int sbi_domain_register(struct sbi_domain *dom,
const struct sbi_hartmask *assign_mask)
{
u32 i;
int rc;
struct sbi_domain *tdom;
u32 cold_hartid = current_hartid();
const struct sbi_platform *plat = sbi_platform_thishart_ptr();
if (!dom || !assign_mask)
return SBI_EINVAL;
/* Check if domain already discovered */
sbi_domain_for_each(i, tdom) {
if (tdom == dom)
return SBI_EALREADY;
}
/*
* Ensure that we have room for Domain Index to
* HART ID mapping
*/
if (SBI_DOMAIN_MAX_INDEX <= domain_count) {
sbi_printf("%s: No room for %s\n",
__func__, dom->name);
return SBI_ENOSPC;
}
/* Sanitize discovered domain */
rc = sanitize_domain(plat, dom);
if (rc) {
sbi_printf("%s: sanity checks failed for"
" %s (error %d)\n", __func__,
dom->name, rc);
return rc;
}
/* Assign index to domain */
dom->index = domain_count++;
domidx_to_domain_table[dom->index] = dom;
/* Clear assigned HARTs of domain */
sbi_hartmask_clear_all(&dom->assigned_harts);
/* Assign domain to HART if HART is a possible HART */
sbi_hartmask_for_each_hart(i, assign_mask) {
if (!sbi_hartmask_test_hart(i, dom->possible_harts))
continue;
tdom = hartid_to_domain_table[i];
if (tdom)
sbi_hartmask_clear_hart(i,
&tdom->assigned_harts);
hartid_to_domain_table[i] = dom;
sbi_hartmask_set_hart(i, &dom->assigned_harts);
/*
* If cold boot HART is assigned to this domain then
* override boot HART of this domain.
*/
if (i == cold_hartid &&
dom->boot_hartid != cold_hartid) {
sbi_printf("Domain%d Boot HARTID forced to"
" %d\n", dom->index, cold_hartid);
dom->boot_hartid = cold_hartid;
}
}
return 0;
}
int sbi_domain_finalize(struct sbi_scratch *scratch, u32 cold_hartid)
{
int rc;
u32 i, dhart;
struct sbi_domain *dom;
const struct sbi_platform *plat = sbi_platform_ptr(scratch);
/* Initialize and populate domains for the platform */
rc = sbi_platform_domains_init(plat);
if (rc) {
sbi_printf("%s: platform domains_init() failed (error %d)\n",
__func__, rc);
return rc;
}
/* Startup boot HART of domains */
sbi_domain_for_each(i, dom) {
/* Domain boot HART */
dhart = dom->boot_hartid;
/* Ignore of boot HART is off limits */
if (SBI_HARTMASK_MAX_BITS <= dhart)
continue;
/* Ignore if boot HART not possible for this domain */
if (!sbi_hartmask_test_hart(dhart, dom->possible_harts))
continue;
/* Ignore if boot HART assigned different domain */
if (sbi_hartid_to_domain(dhart) != dom ||
!sbi_hartmask_test_hart(dhart, &dom->assigned_harts))
continue;
/* Startup boot HART of domain */
if (dhart == cold_hartid) {
scratch->next_addr = dom->next_addr;
scratch->next_mode = dom->next_mode;
scratch->next_arg1 = dom->next_arg1;
} else {
rc = sbi_hsm_hart_start(scratch, NULL, dhart,
dom->next_addr,
dom->next_mode,
dom->next_arg1);
if (rc) {
sbi_printf("%s: failed to start boot HART %d"
" for %s (error %d)\n", __func__,
dhart, dom->name, rc);
return rc;
}
}
}
return 0;
}
int sbi_domain_init(struct sbi_scratch *scratch, u32 cold_hartid)
{
u32 i;
struct sbi_domain_memregion *memregs;
const struct sbi_platform *plat = sbi_platform_ptr(scratch);
/* Root domain firmware memory region */
root_memregs[ROOT_FW_REGION].order = log2roundup(scratch->fw_size);
root_memregs[ROOT_FW_REGION].base = scratch->fw_start &
~((1UL << root_memregs[0].order) - 1UL);
root_memregs[ROOT_FW_REGION].flags = 0;
/* Root domain allow everything memory region */
root_memregs[ROOT_ALL_REGION].order = __riscv_xlen;
root_memregs[ROOT_ALL_REGION].base = 0;
root_memregs[ROOT_ALL_REGION].flags = (SBI_DOMAIN_MEMREGION_READABLE |
SBI_DOMAIN_MEMREGION_WRITEABLE |
SBI_DOMAIN_MEMREGION_EXECUTABLE);
/* Root domain memory region end */
root_memregs[ROOT_END_REGION].order = 0;
/* Use platform specific root memory regions when available */
memregs = sbi_platform_domains_root_regions(plat);
if (memregs)
root.regions = memregs;
/* Root domain boot HART id is same as coldboot HART id */
root.boot_hartid = cold_hartid;
/* Root domain next booting stage details */
root.next_arg1 = scratch->next_arg1;
root.next_addr = scratch->next_addr;
root.next_mode = scratch->next_mode;
/* Root domain possible and assigned HARTs */
for (i = 0; i < SBI_HARTMASK_MAX_BITS; i++) {
if (sbi_platform_hart_invalid(plat, i))
continue;
sbi_hartmask_set_hart(i, &root_hmask);
}
return sbi_domain_register(&root, &root_hmask);
}

View File

@@ -101,19 +101,11 @@ int sbi_ecall_handler(struct sbi_trap_regs *regs)
struct sbi_trap_info trap = {0};
unsigned long out_val = 0;
bool is_0_1_spec = 0;
unsigned long args[6];
args[0] = regs->a0;
args[1] = regs->a1;
args[2] = regs->a2;
args[3] = regs->a3;
args[4] = regs->a4;
args[5] = regs->a5;
ext = sbi_ecall_find_extension(extension_id);
if (ext && ext->handle) {
ret = ext->handle(extension_id, func_id,
args, &out_val, &trap);
regs, &out_val, &trap);
if (extension_id >= SBI_EXT_0_1_SET_TIMER &&
extension_id <= SBI_EXT_0_1_SHUTDOWN)
is_0_1_spec = 1;
@@ -167,6 +159,9 @@ int sbi_ecall_init(void)
if (ret)
return ret;
ret = sbi_ecall_register_extension(&ecall_hsm);
if (ret)
return ret;
ret = sbi_ecall_register_extension(&ecall_srst);
if (ret)
return ret;
ret = sbi_ecall_register_extension(&ecall_legacy);

View File

@@ -11,6 +11,7 @@
#include <sbi/sbi_ecall.h>
#include <sbi/sbi_ecall_interface.h>
#include <sbi/sbi_error.h>
#include <sbi/sbi_trap.h>
#include <sbi/sbi_version.h>
#include <sbi/riscv_asm.h>
@@ -32,7 +33,8 @@ static int sbi_ecall_base_probe(unsigned long extid, unsigned long *out_val)
}
static int sbi_ecall_base_handler(unsigned long extid, unsigned long funcid,
unsigned long *args, unsigned long *out_val,
const struct sbi_trap_regs *regs,
unsigned long *out_val,
struct sbi_trap_info *out_trap)
{
int ret = 0;
@@ -61,7 +63,7 @@ static int sbi_ecall_base_handler(unsigned long extid, unsigned long funcid,
*out_val = csr_read(CSR_MIMPID);
break;
case SBI_EXT_BASE_PROBE_EXT:
ret = sbi_ecall_base_probe(args[0], out_val);
ret = sbi_ecall_base_probe(regs->a0, out_val);
break;
default:
ret = SBI_ENOTSUPP;

View File

@@ -7,30 +7,38 @@
* Atish Patra <atish.patra@wdc.com>
*/
#include <sbi/sbi_domain.h>
#include <sbi/sbi_ecall.h>
#include <sbi/sbi_ecall_interface.h>
#include <sbi/sbi_error.h>
#include <sbi/sbi_trap.h>
#include <sbi/sbi_version.h>
#include <sbi/sbi_hsm.h>
#include <sbi/sbi_scratch.h>
#include <sbi/riscv_asm.h>
static int sbi_ecall_hsm_handler(unsigned long extid, unsigned long funcid,
unsigned long *args, unsigned long *out_val,
const struct sbi_trap_regs *regs,
unsigned long *out_val,
struct sbi_trap_info *out_trap)
{
ulong smode;
int ret = 0, hstate;
struct sbi_scratch *scratch = sbi_scratch_thishart_ptr();
switch (funcid) {
case SBI_EXT_HSM_HART_START:
ret = sbi_hsm_hart_start(scratch, args[0], args[1], args[2]);
smode = csr_read(CSR_MSTATUS);
smode = (smode & MSTATUS_MPP) >> MSTATUS_MPP_SHIFT;
ret = sbi_hsm_hart_start(scratch, sbi_domain_thishart_ptr(),
regs->a0, regs->a1, smode, regs->a2);
break;
case SBI_EXT_HSM_HART_STOP:
ret = sbi_hsm_hart_stop(scratch, TRUE);
break;
case SBI_EXT_HSM_HART_GET_STATUS:
hstate = sbi_hsm_hart_get_state(args[0]);
hstate = sbi_hsm_hart_get_state(sbi_domain_thishart_ptr(),
regs->a0);
ret = sbi_hsm_hart_state_to_status(hstate);
break;
default:

View File

@@ -10,6 +10,7 @@
#include <sbi/riscv_asm.h>
#include <sbi/sbi_console.h>
#include <sbi/sbi_domain.h>
#include <sbi/sbi_ecall.h>
#include <sbi/sbi_ecall_interface.h>
#include <sbi/sbi_error.h>
@@ -33,7 +34,8 @@ static int sbi_load_hart_mask_unpriv(ulong *pmask, ulong *hmask,
if (uptrap->cause)
return SBI_ETRAP;
} else {
sbi_hsm_hart_started_mask(0, &mask);
sbi_hsm_hart_started_mask(sbi_domain_thishart_ptr(),
0, &mask);
}
*hmask = mask;
@@ -41,7 +43,8 @@ static int sbi_load_hart_mask_unpriv(ulong *pmask, ulong *hmask,
}
static int sbi_ecall_legacy_handler(unsigned long extid, unsigned long funcid,
unsigned long *args, unsigned long *out_val,
const struct sbi_trap_regs *regs,
unsigned long *out_val,
struct sbi_trap_info *out_trap)
{
int ret = 0;
@@ -52,13 +55,13 @@ static int sbi_ecall_legacy_handler(unsigned long extid, unsigned long funcid,
switch (extid) {
case SBI_EXT_0_1_SET_TIMER:
#if __riscv_xlen == 32
sbi_timer_event_start((((u64)args[1] << 32) | (u64)args[0]));
sbi_timer_event_start((((u64)regs->a1 << 32) | (u64)regs->a0));
#else
sbi_timer_event_start((u64)args[0]);
sbi_timer_event_start((u64)regs->a0);
#endif
break;
case SBI_EXT_0_1_CONSOLE_PUTCHAR:
sbi_putc(args[0]);
sbi_putc(regs->a0);
break;
case SBI_EXT_0_1_CONSOLE_GETCHAR:
ret = sbi_getc();
@@ -67,41 +70,45 @@ static int sbi_ecall_legacy_handler(unsigned long extid, unsigned long funcid,
sbi_ipi_clear_smode();
break;
case SBI_EXT_0_1_SEND_IPI:
ret = sbi_load_hart_mask_unpriv((ulong *)args[0],
ret = sbi_load_hart_mask_unpriv((ulong *)regs->a0,
&hmask, out_trap);
if (ret != SBI_ETRAP)
ret = sbi_ipi_send_smode(hmask, 0);
break;
case SBI_EXT_0_1_REMOTE_FENCE_I:
ret = sbi_load_hart_mask_unpriv((ulong *)args[0],
ret = sbi_load_hart_mask_unpriv((ulong *)regs->a0,
&hmask, out_trap);
if (ret != SBI_ETRAP) {
SBI_TLB_INFO_INIT(&tlb_info, 0, 0, 0, 0,
SBI_ITLB_FLUSH, source_hart);
sbi_tlb_local_fence_i,
source_hart);
ret = sbi_tlb_request(hmask, 0, &tlb_info);
}
break;
case SBI_EXT_0_1_REMOTE_SFENCE_VMA:
ret = sbi_load_hart_mask_unpriv((ulong *)args[0],
ret = sbi_load_hart_mask_unpriv((ulong *)regs->a0,
&hmask, out_trap);
if (ret != SBI_ETRAP) {
SBI_TLB_INFO_INIT(&tlb_info, args[1], args[2], 0, 0,
SBI_TLB_FLUSH_VMA, source_hart);
SBI_TLB_INFO_INIT(&tlb_info, regs->a1, regs->a2, 0, 0,
sbi_tlb_local_sfence_vma,
source_hart);
ret = sbi_tlb_request(hmask, 0, &tlb_info);
}
break;
case SBI_EXT_0_1_REMOTE_SFENCE_VMA_ASID:
ret = sbi_load_hart_mask_unpriv((ulong *)args[0],
ret = sbi_load_hart_mask_unpriv((ulong *)regs->a0,
&hmask, out_trap);
if (ret != SBI_ETRAP) {
SBI_TLB_INFO_INIT(&tlb_info, args[1], args[2], args[3],
0, SBI_TLB_FLUSH_VMA_ASID,
SBI_TLB_INFO_INIT(&tlb_info, regs->a1,
regs->a2, regs->a3, 0,
sbi_tlb_local_sfence_vma_asid,
source_hart);
ret = sbi_tlb_request(hmask, 0, &tlb_info);
}
break;
case SBI_EXT_0_1_SHUTDOWN:
sbi_system_reset(SBI_PLATFORM_RESET_SHUTDOWN);
sbi_system_reset(SBI_SRST_RESET_TYPE_SHUTDOWN,
SBI_SRST_RESET_REASON_NONE);
break;
default:
ret = SBI_ENOTSUPP;

View File

@@ -14,20 +14,23 @@
#include <sbi/sbi_error.h>
#include <sbi/sbi_hart.h>
#include <sbi/sbi_ipi.h>
#include <sbi/sbi_system.h>
#include <sbi/sbi_timer.h>
#include <sbi/sbi_tlb.h>
#include <sbi/sbi_trap.h>
static int sbi_ecall_time_handler(unsigned long extid, unsigned long funcid,
unsigned long *args, unsigned long *out_val,
const struct sbi_trap_regs *regs,
unsigned long *out_val,
struct sbi_trap_info *out_trap)
{
int ret = 0;
if (funcid == SBI_EXT_TIME_SET_TIMER) {
#if __riscv_xlen == 32
sbi_timer_event_start((((u64)args[1] << 32) | (u64)args[0]));
sbi_timer_event_start((((u64)regs->a1 << 32) | (u64)regs->a0));
#else
sbi_timer_event_start((u64)args[0]);
sbi_timer_event_start((u64)regs->a0);
#endif
} else
ret = SBI_ENOTSUPP;
@@ -42,7 +45,8 @@ struct sbi_ecall_extension ecall_time = {
};
static int sbi_ecall_rfence_handler(unsigned long extid, unsigned long funcid,
unsigned long *args, unsigned long *out_val,
const struct sbi_trap_regs *regs,
unsigned long *out_val,
struct sbi_trap_info *out_trap)
{
int ret = 0;
@@ -58,42 +62,44 @@ static int sbi_ecall_rfence_handler(unsigned long extid, unsigned long funcid,
switch (funcid) {
case SBI_EXT_RFENCE_REMOTE_FENCE_I:
SBI_TLB_INFO_INIT(&tlb_info, 0, 0, 0, 0,
SBI_ITLB_FLUSH, source_hart);
ret = sbi_tlb_request(args[0], args[1], &tlb_info);
sbi_tlb_local_fence_i, source_hart);
ret = sbi_tlb_request(regs->a0, regs->a1, &tlb_info);
break;
case SBI_EXT_RFENCE_REMOTE_HFENCE_GVMA:
SBI_TLB_INFO_INIT(&tlb_info, args[2], args[3], 0, 0,
SBI_TLB_FLUSH_GVMA, source_hart);
ret = sbi_tlb_request(args[0], args[1], &tlb_info);
SBI_TLB_INFO_INIT(&tlb_info, regs->a2, regs->a3, 0, 0,
sbi_tlb_local_hfence_gvma, source_hart);
ret = sbi_tlb_request(regs->a0, regs->a1, &tlb_info);
break;
case SBI_EXT_RFENCE_REMOTE_HFENCE_GVMA_VMID:
SBI_TLB_INFO_INIT(&tlb_info, args[2], args[3], 0, args[4],
SBI_TLB_FLUSH_GVMA_VMID, source_hart);
ret = sbi_tlb_request(args[0], args[1], &tlb_info);
SBI_TLB_INFO_INIT(&tlb_info, regs->a2, regs->a3, 0, regs->a4,
sbi_tlb_local_hfence_gvma_vmid,
source_hart);
ret = sbi_tlb_request(regs->a0, regs->a1, &tlb_info);
break;
case SBI_EXT_RFENCE_REMOTE_HFENCE_VVMA:
vmid = (csr_read(CSR_HGATP) & HGATP_VMID_MASK);
vmid = vmid >> HGATP_VMID_SHIFT;
SBI_TLB_INFO_INIT(&tlb_info, args[2], args[3], 0, vmid,
SBI_TLB_FLUSH_VVMA, source_hart);
ret = sbi_tlb_request(args[0], args[1], &tlb_info);
SBI_TLB_INFO_INIT(&tlb_info, regs->a2, regs->a3, 0, vmid,
sbi_tlb_local_hfence_vvma, source_hart);
ret = sbi_tlb_request(regs->a0, regs->a1, &tlb_info);
break;
case SBI_EXT_RFENCE_REMOTE_HFENCE_VVMA_ASID:
vmid = (csr_read(CSR_HGATP) & HGATP_VMID_MASK);
vmid = vmid >> HGATP_VMID_SHIFT;
SBI_TLB_INFO_INIT(&tlb_info, args[2], args[3], args[4], vmid,
SBI_TLB_FLUSH_VVMA_ASID, source_hart);
ret = sbi_tlb_request(args[0], args[1], &tlb_info);
SBI_TLB_INFO_INIT(&tlb_info, regs->a2, regs->a3, regs->a4,
vmid, sbi_tlb_local_hfence_vvma_asid,
source_hart);
ret = sbi_tlb_request(regs->a0, regs->a1, &tlb_info);
break;
case SBI_EXT_RFENCE_REMOTE_SFENCE_VMA:
SBI_TLB_INFO_INIT(&tlb_info, args[2], args[3], 0, 0,
SBI_TLB_FLUSH_VMA, source_hart);
ret = sbi_tlb_request(args[0], args[1], &tlb_info);
SBI_TLB_INFO_INIT(&tlb_info, regs->a2, regs->a3, 0, 0,
sbi_tlb_local_sfence_vma, source_hart);
ret = sbi_tlb_request(regs->a0, regs->a1, &tlb_info);
break;
case SBI_EXT_RFENCE_REMOTE_SFENCE_VMA_ASID:
SBI_TLB_INFO_INIT(&tlb_info, args[2], args[3], args[4], 0,
SBI_TLB_FLUSH_VMA_ASID, source_hart);
ret = sbi_tlb_request(args[0], args[1], &tlb_info);
SBI_TLB_INFO_INIT(&tlb_info, regs->a2, regs->a3, regs->a4, 0,
sbi_tlb_local_sfence_vma_asid, source_hart);
ret = sbi_tlb_request(regs->a0, regs->a1, &tlb_info);
break;
default:
ret = SBI_ENOTSUPP;
@@ -109,13 +115,14 @@ struct sbi_ecall_extension ecall_rfence = {
};
static int sbi_ecall_ipi_handler(unsigned long extid, unsigned long funcid,
unsigned long *args, unsigned long *out_val,
const struct sbi_trap_regs *regs,
unsigned long *out_val,
struct sbi_trap_info *out_trap)
{
int ret = 0;
if (funcid == SBI_EXT_IPI_SEND_IPI)
ret = sbi_ipi_send_smode(args[0], args[1]);
ret = sbi_ipi_send_smode(regs->a0, regs->a1);
else
ret = SBI_ENOTSUPP;
@@ -127,3 +134,63 @@ struct sbi_ecall_extension ecall_ipi = {
.extid_end = SBI_EXT_IPI,
.handle = sbi_ecall_ipi_handler,
};
static int sbi_ecall_srst_handler(unsigned long extid, unsigned long funcid,
const struct sbi_trap_regs *regs,
unsigned long *out_val,
struct sbi_trap_info *out_trap)
{
if (funcid == SBI_EXT_SRST_RESET) {
if ((((u32)-1U) <= ((u64)regs->a0)) ||
(((u32)-1U) <= ((u64)regs->a1)))
return SBI_EINVAL;
switch (regs->a0) {
case SBI_SRST_RESET_TYPE_SHUTDOWN:
case SBI_SRST_RESET_TYPE_COLD_REBOOT:
case SBI_SRST_RESET_TYPE_WARM_REBOOT:
break;
default:
return SBI_ENOTSUPP;
}
switch (regs->a1) {
case SBI_SRST_RESET_REASON_NONE:
case SBI_SRST_RESET_REASON_SYSFAIL:
break;
default:
return SBI_ENOTSUPP;
}
if (sbi_system_reset_supported(regs->a0, regs->a1))
sbi_system_reset(regs->a0, regs->a1);
}
return SBI_ENOTSUPP;
}
static int sbi_ecall_srst_probe(unsigned long extid, unsigned long *out_val)
{
u32 type, count = 0;
/*
* At least one standard reset types should be supported by
* the platform for SBI SRST extension to be usable.
*/
for (type = 0; type <= SBI_SRST_RESET_TYPE_LAST; type++) {
if (sbi_system_reset_supported(type,
SBI_SRST_RESET_REASON_NONE))
count++;
}
*out_val = (count) ? 1 : 0;
return 0;
}
struct sbi_ecall_extension ecall_srst = {
.extid_start = SBI_EXT_SRST,
.extid_end = SBI_EXT_SRST,
.handle = sbi_ecall_srst_handler,
.probe = sbi_ecall_srst_probe,
};

View File

@@ -12,6 +12,7 @@
#include <sbi/sbi_ecall_interface.h>
#include <sbi/sbi_error.h>
#include <sbi/sbi_platform.h>
#include <sbi/sbi_trap.h>
static int sbi_ecall_vendor_probe(unsigned long extid,
unsigned long *out_val)
@@ -22,11 +23,12 @@ static int sbi_ecall_vendor_probe(unsigned long extid,
}
static int sbi_ecall_vendor_handler(unsigned long extid, unsigned long funcid,
unsigned long *args, unsigned long *out_val,
const struct sbi_trap_regs *regs,
unsigned long *out_val,
struct sbi_trap_info *out_trap)
{
return sbi_platform_vendor_ext_provider(sbi_platform_thishart_ptr(),
extid, funcid, args,
extid, funcid, regs,
out_val, out_trap);
}

View File

@@ -13,14 +13,31 @@
#include <sbi/sbi_console.h>
#include <sbi/sbi_emulate_csr.h>
#include <sbi/sbi_error.h>
#include <sbi/sbi_hart.h>
#include <sbi/sbi_scratch.h>
#include <sbi/sbi_timer.h>
#include <sbi/sbi_trap.h>
static bool hpm_allowed(int hpm_num, ulong prev_mode, bool virt)
{
ulong cen = -1UL;
if (prev_mode <= PRV_S) {
cen &= csr_read(CSR_MCOUNTEREN);
if (virt)
cen &= csr_read(CSR_HCOUNTEREN);
}
if (prev_mode == PRV_U)
cen &= csr_read(CSR_SCOUNTEREN);
return ((cen >> hpm_num) & 1) ? TRUE : FALSE;
}
int sbi_emulate_csr_read(int csr_num, struct sbi_trap_regs *regs,
ulong *csr_val)
{
int ret = 0;
ulong cen = -1UL;
struct sbi_scratch *scratch = sbi_scratch_thishart_ptr();
ulong prev_mode = (regs->mstatus & MSTATUS_MPP) >> MSTATUS_MPP_SHIFT;
#if __riscv_xlen == 32
bool virt = (regs->mstatusH & MSTATUSH_MPV) ? TRUE : FALSE;
@@ -28,9 +45,6 @@ int sbi_emulate_csr_read(int csr_num, struct sbi_trap_regs *regs,
bool virt = (regs->mstatus & MSTATUS_MPV) ? TRUE : FALSE;
#endif
if (prev_mode == PRV_U)
cen = csr_read(CSR_SCOUNTEREN);
switch (csr_num) {
case CSR_HTIMEDELTA:
if (prev_mode == PRV_S && !virt)
@@ -39,31 +53,27 @@ int sbi_emulate_csr_read(int csr_num, struct sbi_trap_regs *regs,
ret = SBI_ENOTSUPP;
break;
case CSR_CYCLE:
if (!((cen >> (CSR_CYCLE - CSR_CYCLE)) & 1))
return -1;
if (!hpm_allowed(csr_num - CSR_CYCLE, prev_mode, virt))
return SBI_ENOTSUPP;
*csr_val = csr_read(CSR_MCYCLE);
break;
case CSR_TIME:
if (!((cen >> (CSR_TIME - CSR_CYCLE)) & 1))
return -1;
/*
* We emulate TIME CSR for both Host (HS/U-mode) and
* Guest (VS/VU-mode).
*
* Faster TIME CSR reads are critical for good performance
* in S-mode software so we don't check CSR permissions.
*/
*csr_val = (virt) ? sbi_timer_virt_value():
sbi_timer_value();
break;
case CSR_INSTRET:
if (!((cen >> (CSR_INSTRET - CSR_CYCLE)) & 1))
return -1;
if (!hpm_allowed(csr_num - CSR_CYCLE, prev_mode, virt))
return SBI_ENOTSUPP;
*csr_val = csr_read(CSR_MINSTRET);
break;
case CSR_MHPMCOUNTER3:
if (!((cen >> (3 + CSR_MHPMCOUNTER3 - CSR_MHPMCOUNTER3)) & 1))
return -1;
*csr_val = csr_read(CSR_MHPMCOUNTER3);
break;
case CSR_MHPMCOUNTER4:
if (!((cen >> (3 + CSR_MHPMCOUNTER4 - CSR_MHPMCOUNTER3)) & 1))
return -1;
*csr_val = csr_read(CSR_MHPMCOUNTER4);
break;
#if __riscv_xlen == 32
case CSR_HTIMEDELTAH:
if (prev_mode == PRV_S && !virt)
@@ -72,38 +82,61 @@ int sbi_emulate_csr_read(int csr_num, struct sbi_trap_regs *regs,
ret = SBI_ENOTSUPP;
break;
case CSR_CYCLEH:
if (!((cen >> (CSR_CYCLE - CSR_CYCLE)) & 1))
return -1;
if (!hpm_allowed(csr_num - CSR_CYCLEH, prev_mode, virt))
return SBI_ENOTSUPP;
*csr_val = csr_read(CSR_MCYCLEH);
break;
case CSR_TIMEH:
if (!((cen >> (CSR_TIME - CSR_CYCLE)) & 1))
return -1;
/* Refer comments on TIME CSR above. */
*csr_val = (virt) ? sbi_timer_virt_value() >> 32:
sbi_timer_value() >> 32;
break;
case CSR_INSTRETH:
if (!((cen >> (CSR_INSTRET - CSR_CYCLE)) & 1))
return -1;
if (!hpm_allowed(csr_num - CSR_CYCLEH, prev_mode, virt))
return SBI_ENOTSUPP;
*csr_val = csr_read(CSR_MINSTRETH);
break;
case CSR_MHPMCOUNTER3H:
if (!((cen >> (3 + CSR_MHPMCOUNTER3 - CSR_MHPMCOUNTER3)) & 1))
return -1;
*csr_val = csr_read(CSR_MHPMCOUNTER3H);
break;
case CSR_MHPMCOUNTER4H:
if (!((cen >> (3 + CSR_MHPMCOUNTER4 - CSR_MHPMCOUNTER3)) & 1))
return -1;
*csr_val = csr_read(CSR_MHPMCOUNTER4H);
break;
#endif
case CSR_MHPMEVENT3:
*csr_val = csr_read(CSR_MHPMEVENT3);
break;
case CSR_MHPMEVENT4:
*csr_val = csr_read(CSR_MHPMEVENT4);
#define switchcase_hpm(__uref, __mref, __csr) \
case __csr: \
if ((sbi_hart_mhpm_count(scratch) + 3) <= (__csr - __uref))\
return SBI_ENOTSUPP; \
if (!hpm_allowed(__csr - __uref, prev_mode, virt)) \
return SBI_ENOTSUPP; \
*csr_val = csr_read(__mref + __csr - __uref); \
break;
#define switchcase_hpm_2(__uref, __mref, __csr) \
switchcase_hpm(__uref, __mref, __csr + 0) \
switchcase_hpm(__uref, __mref, __csr + 1)
#define switchcase_hpm_4(__uref, __mref, __csr) \
switchcase_hpm_2(__uref, __mref, __csr + 0) \
switchcase_hpm_2(__uref, __mref, __csr + 2)
#define switchcase_hpm_8(__uref, __mref, __csr) \
switchcase_hpm_4(__uref, __mref, __csr + 0) \
switchcase_hpm_4(__uref, __mref, __csr + 4)
#define switchcase_hpm_16(__uref, __mref, __csr) \
switchcase_hpm_8(__uref, __mref, __csr + 0) \
switchcase_hpm_8(__uref, __mref, __csr + 8)
switchcase_hpm(CSR_CYCLE, CSR_MCYCLE, CSR_HPMCOUNTER3)
switchcase_hpm_4(CSR_CYCLE, CSR_MCYCLE, CSR_HPMCOUNTER4)
switchcase_hpm_8(CSR_CYCLE, CSR_MCYCLE, CSR_HPMCOUNTER8)
switchcase_hpm_16(CSR_CYCLE, CSR_MCYCLE, CSR_HPMCOUNTER16)
#if __riscv_xlen == 32
switchcase_hpm(CSR_CYCLEH, CSR_MCYCLEH, CSR_HPMCOUNTER3H)
switchcase_hpm_4(CSR_CYCLEH, CSR_MCYCLEH, CSR_HPMCOUNTER4H)
switchcase_hpm_8(CSR_CYCLEH, CSR_MCYCLEH, CSR_HPMCOUNTER8H)
switchcase_hpm_16(CSR_CYCLEH, CSR_MCYCLEH, CSR_HPMCOUNTER16H)
#endif
#undef switchcase_hpm_16
#undef switchcase_hpm_8
#undef switchcase_hpm_4
#undef switchcase_hpm_2
#undef switchcase_hpm
default:
ret = SBI_ENOTSUPP;
break;
@@ -134,18 +167,6 @@ int sbi_emulate_csr_write(int csr_num, struct sbi_trap_regs *regs,
else
ret = SBI_ENOTSUPP;
break;
case CSR_CYCLE:
csr_write(CSR_MCYCLE, csr_val);
break;
case CSR_INSTRET:
csr_write(CSR_MINSTRET, csr_val);
break;
case CSR_MHPMCOUNTER3:
csr_write(CSR_MHPMCOUNTER3, csr_val);
break;
case CSR_MHPMCOUNTER4:
csr_write(CSR_MHPMCOUNTER4, csr_val);
break;
#if __riscv_xlen == 32
case CSR_HTIMEDELTAH:
if (prev_mode == PRV_S && !virt)
@@ -153,25 +174,7 @@ int sbi_emulate_csr_write(int csr_num, struct sbi_trap_regs *regs,
else
ret = SBI_ENOTSUPP;
break;
case CSR_CYCLEH:
csr_write(CSR_MCYCLEH, csr_val);
break;
case CSR_INSTRETH:
csr_write(CSR_MINSTRETH, csr_val);
break;
case CSR_MHPMCOUNTER3H:
csr_write(CSR_MHPMCOUNTER3H, csr_val);
break;
case CSR_MHPMCOUNTER4H:
csr_write(CSR_MHPMCOUNTER4H, csr_val);
break;
#endif
case CSR_MHPMEVENT3:
csr_write(CSR_MHPMEVENT3, csr_val);
break;
case CSR_MHPMEVENT4:
csr_write(CSR_MHPMEVENT4, csr_val);
break;
default:
ret = SBI_ENOTSUPP;
break;

View File

@@ -13,12 +13,14 @@
#include <sbi/riscv_fp.h>
#include <sbi/sbi_bitops.h>
#include <sbi/sbi_console.h>
#include <sbi/sbi_domain.h>
#include <sbi/sbi_csr_detect.h>
#include <sbi/sbi_error.h>
#include <sbi/sbi_hart.h>
#include <sbi/sbi_math.h>
#include <sbi/sbi_platform.h>
#include <sbi/sbi_string.h>
#include <sbi/sbi_trap.h>
extern void __sbi_expected_trap(void);
extern void __sbi_expected_trap_hext(void);
@@ -28,10 +30,13 @@ void (*sbi_hart_expected_trap)(void) = &__sbi_expected_trap;
struct hart_features {
unsigned long features;
unsigned int pmp_count;
unsigned int pmp_addr_bits;
unsigned long pmp_gran;
unsigned int mhpm_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)
{
unsigned long mstatus_val = 0;
@@ -60,7 +65,7 @@ static void mstatus_init(struct sbi_scratch *scratch, u32 hartid)
csr_write(CSR_SATP, 0);
}
static int fp_init(u32 hartid)
static int fp_init(struct sbi_scratch *scratch)
{
#ifdef __riscv_flen
int i;
@@ -81,7 +86,7 @@ static int fp_init(u32 hartid)
return 0;
}
static int delegate_traps(struct sbi_scratch *scratch, u32 hartid)
static int delegate_traps(struct sbi_scratch *scratch)
{
const struct sbi_platform *plat = sbi_platform_ptr(scratch);
unsigned long interrupts, exceptions;
@@ -107,7 +112,7 @@ static int delegate_traps(struct sbi_scratch *scratch, u32 hartid)
* from VS-mode), Guest page faults and Virtual interrupts.
*/
if (misa_extension('H')) {
exceptions |= (1U << CAUSE_SUPERVISOR_ECALL);
exceptions |= (1U << CAUSE_VIRTUAL_SUPERVISOR_ECALL);
exceptions |= (1U << CAUSE_FETCH_GUEST_PAGE_FAULT);
exceptions |= (1U << CAUSE_LOAD_GUEST_PAGE_FAULT);
exceptions |= (1U << CAUSE_VIRTUAL_INST_FAULT);
@@ -120,21 +125,34 @@ static int delegate_traps(struct sbi_scratch *scratch, u32 hartid)
return 0;
}
void sbi_hart_delegation_dump(struct sbi_scratch *scratch)
void sbi_hart_delegation_dump(struct sbi_scratch *scratch,
const char *prefix, const char *suffix)
{
if (!misa_extension('S'))
/* No delegation possible as mideleg does not exist*/
return;
#if __riscv_xlen == 32
sbi_printf("MIDELEG : 0x%08lx\n", csr_read(CSR_MIDELEG));
sbi_printf("MEDELEG : 0x%08lx\n", csr_read(CSR_MEDELEG));
sbi_printf("%sMIDELEG%s: 0x%08lx\n",
prefix, suffix, csr_read(CSR_MIDELEG));
sbi_printf("%sMEDELEG%s: 0x%08lx\n",
prefix, suffix, csr_read(CSR_MEDELEG));
#else
sbi_printf("MIDELEG : 0x%016lx\n", csr_read(CSR_MIDELEG));
sbi_printf("MEDELEG : 0x%016lx\n", csr_read(CSR_MEDELEG));
sbi_printf("%sMIDELEG%s: 0x%016lx\n",
prefix, suffix, csr_read(CSR_MIDELEG));
sbi_printf("%sMEDELEG%s: 0x%016lx\n",
prefix, suffix, csr_read(CSR_MEDELEG));
#endif
}
unsigned int sbi_hart_mhpm_count(struct sbi_scratch *scratch)
{
struct hart_features *hfeatures =
sbi_scratch_offset_ptr(scratch, hart_features_offset);
return hfeatures->mhpm_count;
}
unsigned int sbi_hart_pmp_count(struct sbi_scratch *scratch)
{
struct hart_features *hfeatures =
@@ -143,102 +161,61 @@ unsigned int sbi_hart_pmp_count(struct sbi_scratch *scratch)
return hfeatures->pmp_count;
}
int sbi_hart_pmp_get(struct sbi_scratch *scratch, unsigned int n,
unsigned long *prot_out, unsigned long *addr_out,
unsigned long *size)
unsigned long sbi_hart_pmp_granularity(struct sbi_scratch *scratch)
{
if (sbi_hart_pmp_count(scratch) <= n)
return SBI_EINVAL;
struct hart_features *hfeatures =
sbi_scratch_offset_ptr(scratch, hart_features_offset);
return pmp_get(n, prot_out, addr_out, size);
return hfeatures->pmp_gran;
}
void sbi_hart_pmp_dump(struct sbi_scratch *scratch)
unsigned int sbi_hart_pmp_addrbits(struct sbi_scratch *scratch)
{
unsigned long prot, addr, size;
unsigned int i, pmp_count;
struct hart_features *hfeatures =
sbi_scratch_offset_ptr(scratch, hart_features_offset);
if (!sbi_hart_has_feature(scratch, SBI_HART_HAS_PMP))
return;
pmp_count = sbi_hart_pmp_count(scratch);
for (i = 0; i < pmp_count; i++) {
pmp_get(i, &prot, &addr, &size);
if (!(prot & PMP_A))
continue;
#if __riscv_xlen == 32
sbi_printf("PMP%d : 0x%08lx-0x%08lx (A",
#else
sbi_printf("PMP%d : 0x%016lx-0x%016lx (A",
#endif
i, addr, addr + size - 1);
if (prot & PMP_L)
sbi_printf(",L");
if (prot & PMP_R)
sbi_printf(",R");
if (prot & PMP_W)
sbi_printf(",W");
if (prot & PMP_X)
sbi_printf(",X");
sbi_printf(")\n");
}
return hfeatures->pmp_addr_bits;
}
int sbi_hart_pmp_check_addr(struct sbi_scratch *scratch, unsigned long addr,
unsigned long attr)
int sbi_hart_pmp_configure(struct sbi_scratch *scratch)
{
unsigned long prot, size, tempaddr;
unsigned int i, pmp_count;
struct sbi_domain_memregion *reg;
struct sbi_domain *dom = sbi_domain_thishart_ptr();
unsigned int pmp_idx = 0, pmp_flags, pmp_bits, pmp_gran_log2;
unsigned int pmp_count = sbi_hart_pmp_count(scratch);
unsigned long pmp_addr = 0, pmp_addr_max = 0;
if (!sbi_hart_has_feature(scratch, SBI_HART_HAS_PMP))
return SBI_OK;
pmp_count = sbi_hart_pmp_count(scratch);
for (i = 0; i < pmp_count; i++) {
pmp_get(i, &prot, &tempaddr, &size);
if (!(prot & PMP_A))
continue;
if (tempaddr <= addr && addr <= tempaddr + size)
if (!(prot & attr))
return SBI_EINVALID_ADDR;
}
return SBI_OK;
}
static int pmp_init(struct sbi_scratch *scratch, u32 hartid)
{
u32 i, pmp_idx = 0, pmp_count, count;
unsigned long fw_start, fw_size_log2;
ulong prot, addr, log2size;
const struct sbi_platform *plat = sbi_platform_ptr(scratch);
if (!sbi_hart_has_feature(scratch, SBI_HART_HAS_PMP))
if (!pmp_count)
return 0;
/* Firmware PMP region to protect OpenSBI firmware */
fw_size_log2 = log2roundup(scratch->fw_size);
fw_start = scratch->fw_start & ~((1UL << fw_size_log2) - 1UL);
pmp_set(pmp_idx++, 0, fw_start, fw_size_log2);
pmp_gran_log2 = log2roundup(sbi_hart_pmp_granularity(scratch));
pmp_bits = sbi_hart_pmp_addrbits(scratch) - 1;
pmp_addr_max = (1UL << pmp_bits) | ((1UL << pmp_bits) - 1);
/* Platform specific PMP regions */
count = sbi_platform_pmp_region_count(plat, hartid);
pmp_count = sbi_hart_pmp_count(scratch);
for (i = 0; i < count && pmp_idx < (pmp_count - 1); i++) {
if (sbi_platform_pmp_region_info(plat, hartid, i, &prot, &addr,
&log2size))
continue;
pmp_set(pmp_idx++, prot, addr, log2size);
sbi_domain_for_each_memregion(dom, reg) {
if (pmp_count <= pmp_idx)
break;
pmp_flags = 0;
if (reg->flags & SBI_DOMAIN_MEMREGION_READABLE)
pmp_flags |= PMP_R;
if (reg->flags & SBI_DOMAIN_MEMREGION_WRITEABLE)
pmp_flags |= PMP_W;
if (reg->flags & SBI_DOMAIN_MEMREGION_EXECUTABLE)
pmp_flags |= PMP_X;
if (reg->flags & SBI_DOMAIN_MEMREGION_MMODE)
pmp_flags |= PMP_L;
pmp_addr = reg->base >> PMP_SHIFT;
if (pmp_gran_log2 <= reg->order && pmp_addr < pmp_addr_max)
pmp_set(pmp_idx++, pmp_flags, reg->base, reg->order);
else {
sbi_printf("Can not configure pmp for domain %s", dom->name);
sbi_printf("because memory region address %lx or size %lx is not in range\n",
reg->base, reg->order);
}
}
/*
* 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;
}
@@ -276,9 +253,6 @@ static inline char *sbi_hart_feature_id2string(unsigned long feature)
return NULL;
switch (feature) {
case SBI_HART_HAS_PMP:
fstr = "pmp";
break;
case SBI_HART_HAS_SCOUNTEREN:
fstr = "scounteren";
break;
@@ -338,6 +312,21 @@ done:
sbi_strncpy(features_str, "none", nfstr);
}
static unsigned long hart_pmp_get_allowed_addr(void)
{
unsigned long val = 0;
struct sbi_trap_info trap = {0};
csr_write_allowed(CSR_PMPADDR0, (ulong)&trap, PMP_ADDR_MASK); \
if (!trap.cause) {
val = csr_read_allowed(CSR_PMPADDR0, (ulong)&trap);
if (trap.cause)
val = 0;
}
return val;
}
static void hart_detect_features(struct sbi_scratch *scratch)
{
struct sbi_trap_info trap = {0};
@@ -348,36 +337,73 @@ static void hart_detect_features(struct sbi_scratch *scratch)
hfeatures = sbi_scratch_offset_ptr(scratch, hart_features_offset);
hfeatures->features = 0;
hfeatures->pmp_count = 0;
hfeatures->mhpm_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++; \
#define __check_csr(__csr, __rdonly, __wrval, __field, __skip) \
val = csr_read_allowed(__csr, (ulong)&trap); \
if (!trap.cause) { \
if (__rdonly) { \
(hfeatures->__field)++; \
} else { \
csr_write_allowed(__csr, (ulong)&trap, __wrval);\
if (!trap.cause) { \
if (csr_swap(__csr, val) == __wrval) \
(hfeatures->__field)++; \
else \
goto __skip; \
} else { \
goto __skip; \
} \
} \
} else { \
goto __skip; \
}
__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
#define __check_csr_2(__csr, __rdonly, __wrval, __field, __skip) \
__check_csr(__csr + 0, __rdonly, __wrval, __field, __skip) \
__check_csr(__csr + 1, __rdonly, __wrval, __field, __skip)
#define __check_csr_4(__csr, __rdonly, __wrval, __field, __skip) \
__check_csr_2(__csr + 0, __rdonly, __wrval, __field, __skip) \
__check_csr_2(__csr + 2, __rdonly, __wrval, __field, __skip)
#define __check_csr_8(__csr, __rdonly, __wrval, __field, __skip) \
__check_csr_4(__csr + 0, __rdonly, __wrval, __field, __skip) \
__check_csr_4(__csr + 4, __rdonly, __wrval, __field, __skip)
#define __check_csr_16(__csr, __rdonly, __wrval, __field, __skip) \
__check_csr_8(__csr + 0, __rdonly, __wrval, __field, __skip) \
__check_csr_8(__csr + 8, __rdonly, __wrval, __field, __skip)
#define __check_csr_32(__csr, __rdonly, __wrval, __field, __skip) \
__check_csr_16(__csr + 0, __rdonly, __wrval, __field, __skip) \
__check_csr_16(__csr + 16, __rdonly, __wrval, __field, __skip)
#define __check_csr_64(__csr, __rdonly, __wrval, __field, __skip) \
__check_csr_32(__csr + 0, __rdonly, __wrval, __field, __skip) \
__check_csr_32(__csr + 32, __rdonly, __wrval, __field, __skip)
/* Set hart PMP feature if we have at least one PMP region */
if (hfeatures->pmp_count)
hfeatures->features |= SBI_HART_HAS_PMP;
/**
* Detect the allowed address bits & granularity. At least PMPADDR0
* should be implemented.
*/
val = hart_pmp_get_allowed_addr();
if (val) {
hfeatures->pmp_gran = 1 << (__ffs(val) + 2);
hfeatures->pmp_addr_bits = __fls(val) + 1;
/* Detect number of PMP regions. At least PMPADDR0 should be implemented*/
__check_csr_64(CSR_PMPADDR0, 0, val, pmp_count, __pmp_skip);
}
__pmp_skip:
/* Detect number of MHPM counters */
__check_csr(CSR_MHPMCOUNTER3, 0, 1UL, mhpm_count, __mhpm_skip);
__check_csr_4(CSR_MHPMCOUNTER4, 0, 1UL, mhpm_count, __mhpm_skip);
__check_csr_8(CSR_MHPMCOUNTER8, 0, 1UL, mhpm_count, __mhpm_skip);
__check_csr_16(CSR_MHPMCOUNTER16, 0, 1UL, mhpm_count, __mhpm_skip);
__mhpm_skip:
#undef __check_csr_64
#undef __check_csr_32
#undef __check_csr_16
#undef __check_csr_8
#undef __check_csr_4
#undef __check_csr_2
#undef __check_csr
/* Detect if hart supports SCOUNTEREN feature */
trap.cause = 0;
@@ -404,7 +430,7 @@ static void hart_detect_features(struct sbi_scratch *scratch)
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, bool cold_boot)
{
int rc;
@@ -421,17 +447,17 @@ int sbi_hart_init(struct sbi_scratch *scratch, u32 hartid, bool cold_boot)
hart_detect_features(scratch);
mstatus_init(scratch, hartid);
mstatus_init(scratch);
rc = fp_init(hartid);
rc = fp_init(scratch);
if (rc)
return rc;
rc = delegate_traps(scratch, hartid);
rc = delegate_traps(scratch);
if (rc)
return rc;
return pmp_init(scratch, hartid);
return 0;
}
void __attribute__((noreturn)) sbi_hart_hang(void)
@@ -496,9 +522,11 @@ sbi_hart_switch_mode(unsigned long arg0, unsigned long arg1,
csr_write(CSR_SIE, 0);
csr_write(CSR_SATP, 0);
} else if (next_mode == PRV_U) {
csr_write(CSR_UTVEC, next_addr);
csr_write(CSR_USCRATCH, 0);
csr_write(CSR_UIE, 0);
if (misa_extension('N')) {
csr_write(CSR_UTVEC, next_addr);
csr_write(CSR_USCRATCH, 0);
csr_write(CSR_UIE, 0);
}
}
register unsigned long a0 asm("a0") = arg0;

View File

@@ -13,6 +13,7 @@
#include <sbi/riscv_atomic.h>
#include <sbi/sbi_bitops.h>
#include <sbi/sbi_console.h>
#include <sbi/sbi_domain.h>
#include <sbi/sbi_error.h>
#include <sbi/sbi_ecall_interface.h>
#include <sbi/sbi_hart.h>
@@ -56,7 +57,7 @@ int sbi_hsm_hart_state_to_status(int state)
return ret;
}
int sbi_hsm_hart_get_state(u32 hartid)
static inline int __sbi_hsm_hart_get_state(u32 hartid)
{
struct sbi_hsm_data *hdata;
struct sbi_scratch *scratch;
@@ -66,13 +67,20 @@ int sbi_hsm_hart_get_state(u32 hartid)
return SBI_HART_UNKNOWN;
hdata = sbi_scratch_offset_ptr(scratch, hart_data_offset);
return atomic_read(&hdata->state);
}
bool sbi_hsm_hart_started(u32 hartid)
int sbi_hsm_hart_get_state(const struct sbi_domain *dom, u32 hartid)
{
if (sbi_hsm_hart_get_state(hartid) == SBI_HART_STARTED)
if (!sbi_domain_is_assigned_hart(dom, hartid))
return SBI_HART_UNKNOWN;
return __sbi_hsm_hart_get_state(hartid);
}
static bool sbi_hsm_hart_started(const struct sbi_domain *dom, u32 hartid)
{
if (sbi_hsm_hart_get_state(dom, hartid) == SBI_HART_STARTED)
return TRUE;
else
return FALSE;
@@ -80,25 +88,30 @@ bool sbi_hsm_hart_started(u32 hartid)
/**
* Get ulong HART mask for given HART base ID
* @param dom the domain to be used for output HART mask
* @param hbase the HART base ID
* @param out_hmask the output ulong HART mask
* @return 0 on success and SBI_Exxx (< 0) on failure
* Note: the output HART mask will be set to zero on failure as well.
*/
int sbi_hsm_hart_started_mask(ulong hbase, ulong *out_hmask)
int sbi_hsm_hart_started_mask(const struct sbi_domain *dom,
ulong hbase, ulong *out_hmask)
{
ulong i;
ulong hcount = sbi_scratch_last_hartid() + 1;
ulong i, hmask, dmask;
ulong hend = sbi_scratch_last_hartid() + 1;
*out_hmask = 0;
if (hcount <= hbase)
if (hend <= hbase)
return SBI_EINVAL;
if (BITS_PER_LONG < (hcount - hbase))
hcount = BITS_PER_LONG;
if (BITS_PER_LONG < (hend - hbase))
hend = hbase + BITS_PER_LONG;
for (i = hbase; i < hcount; i++) {
if (sbi_hsm_hart_get_state(i) == SBI_HART_STARTED)
*out_hmask |= 1UL << (i - hbase);
dmask = sbi_domain_get_assigned_hartmask(dom, hbase);
for (i = hbase; i < hend; i++) {
hmask = 1UL << (i - hbase);
if ((dmask & hmask) &&
(__sbi_hsm_hart_get_state(i) == SBI_HART_STARTED))
*out_hmask |= hmask;
}
return 0;
@@ -202,16 +215,25 @@ fail_exit:
sbi_hart_hang();
}
int sbi_hsm_hart_start(struct sbi_scratch *scratch, u32 hartid,
ulong saddr, ulong priv)
int sbi_hsm_hart_start(struct sbi_scratch *scratch,
const struct sbi_domain *dom,
u32 hartid, ulong saddr, ulong smode, ulong priv)
{
int rc;
unsigned long init_count;
unsigned int hstate;
struct sbi_scratch *rscratch;
struct sbi_hsm_data *hdata;
const struct sbi_platform *plat = sbi_platform_ptr(scratch);
/* For now, we only allow start mode to be S-mode or U-mode. */
if (smode != PRV_S && smode != PRV_U)
return SBI_EINVAL;
if (dom && !sbi_domain_is_assigned_hart(dom, hartid))
return SBI_EINVAL;
if (dom && !sbi_domain_check_addr(dom, saddr, smode,
SBI_DOMAIN_EXECUTE))
return SBI_EINVAL;
rscratch = sbi_hartid_to_scratch(hartid);
if (!rscratch)
return SBI_EINVAL;
@@ -228,14 +250,10 @@ int sbi_hsm_hart_start(struct sbi_scratch *scratch, u32 hartid,
if (hstate != SBI_HART_STOPPED)
return SBI_EINVAL;
rc = sbi_hart_pmp_check_addr(scratch, saddr, PMP_X);
if (rc)
return rc;
//TODO: We also need to check saddr for valid physical address as well.
init_count = sbi_init_count(hartid);
rscratch->next_arg1 = priv;
rscratch->next_addr = saddr;
rscratch->next_mode = smode;
if (sbi_platform_has_hart_hotplug(plat) ||
(sbi_platform_has_hart_secondary_boot(plat) && !init_count)) {
@@ -255,7 +273,7 @@ int sbi_hsm_hart_stop(struct sbi_scratch *scratch, bool exitnow)
struct sbi_hsm_data *hdata = sbi_scratch_offset_ptr(scratch,
hart_data_offset);
if (!sbi_hsm_hart_started(hartid))
if (!sbi_hsm_hart_started(sbi_domain_thishart_ptr(), hartid))
return SBI_EINVAL;
oldstate = atomic_cmpxchg(&hdata->state, SBI_HART_STARTED,

View File

@@ -118,13 +118,22 @@ int sbi_illegal_insn_handler(ulong insn, struct sbi_trap_regs *regs)
{
struct sbi_trap_info uptrap;
/*
* We only deal with 32-bit (or longer) illegal instructions. If we
* see instruction is zero OR instruction is 16-bit then we fetch and
* check the instruction encoding using unprivilege access.
*
* The program counter (PC) in RISC-V world is always 2-byte aligned
* so handling only 32-bit (or longer) illegal instructions also help
* the case where MTVAL CSR contains instruction address for illegal
* instruction trap.
*/
if (unlikely((insn & 3) != 3)) {
if (insn == 0) {
insn = sbi_get_insn(regs->mepc, &uptrap);
if (uptrap.cause) {
uptrap.epc = regs->mepc;
return sbi_trap_redirect(regs, &uptrap);
}
insn = sbi_get_insn(regs->mepc, &uptrap);
if (uptrap.cause) {
uptrap.epc = regs->mepc;
return sbi_trap_redirect(regs, &uptrap);
}
if ((insn & 3) != 3)
return truly_illegal_insn(insn, regs);

View File

@@ -9,8 +9,10 @@
#include <sbi/riscv_asm.h>
#include <sbi/riscv_atomic.h>
#include <sbi/riscv_barrier.h>
#include <sbi/riscv_locks.h>
#include <sbi/sbi_console.h>
#include <sbi/sbi_domain.h>
#include <sbi/sbi_ecall.h>
#include <sbi/sbi_hart.h>
#include <sbi/sbi_hartmask.h>
@@ -33,11 +35,10 @@
" | |\n" \
" |_|\n\n"
static void sbi_boot_prints(struct sbi_scratch *scratch, u32 hartid)
static void sbi_boot_print_banner(struct sbi_scratch *scratch)
{
int xlen;
char str[128];
const struct sbi_platform *plat = sbi_platform_ptr(scratch);
if (scratch->options & SBI_SCRATCH_NO_BOOT_PRINTS)
return;
#ifdef OPENSBI_VERSION_GIT
sbi_printf("\nOpenSBI %s\n", OPENSBI_VERSION_GIT);
@@ -47,6 +48,52 @@ static void sbi_boot_prints(struct sbi_scratch *scratch, u32 hartid)
#endif
sbi_printf(BANNER);
}
static void sbi_boot_print_general(struct sbi_scratch *scratch)
{
char str[128];
const struct sbi_platform *plat = sbi_platform_ptr(scratch);
if (scratch->options & SBI_SCRATCH_NO_BOOT_PRINTS)
return;
/* Platform details */
sbi_printf("Platform Name : %s\n",
sbi_platform_name(plat));
sbi_platform_get_features_str(plat, str, sizeof(str));
sbi_printf("Platform Features : %s\n", str);
sbi_printf("Platform HART Count : %u\n",
sbi_platform_hart_count(plat));
/* Firmware details */
sbi_printf("Firmware Base : 0x%lx\n", scratch->fw_start);
sbi_printf("Firmware Size : %d KB\n",
(u32)(scratch->fw_size / 1024));
/* SBI details */
sbi_printf("Runtime SBI Version : %d.%d\n",
sbi_ecall_version_major(), sbi_ecall_version_minor());
sbi_printf("\n");
}
static void sbi_boot_print_domains(struct sbi_scratch *scratch)
{
if (scratch->options & SBI_SCRATCH_NO_BOOT_PRINTS)
return;
/* Domain details */
sbi_domain_dump_all(" ");
}
static void sbi_boot_print_hart(struct sbi_scratch *scratch, u32 hartid)
{
int xlen;
char str[128];
const struct sbi_domain *dom = sbi_domain_thishart_ptr();
if (scratch->options & SBI_SCRATCH_NO_BOOT_PRINTS)
return;
/* Determine MISA XLEN and MISA string */
xlen = misa_xlen();
@@ -55,39 +102,31 @@ static void sbi_boot_prints(struct sbi_scratch *scratch, u32 hartid)
sbi_hart_hang();
}
/* Platform details */
sbi_printf("Platform Name : %s\n", sbi_platform_name(plat));
sbi_platform_get_features_str(plat, str, sizeof(str));
sbi_printf("Platform Features : %s\n", str);
sbi_printf("Platform HART Count : %u\n",
sbi_platform_hart_count(plat));
/* Boot HART details */
sbi_printf("Boot HART ID : %u\n", hartid);
sbi_printf("Boot HART ID : %u\n", hartid);
sbi_printf("Boot HART Domain : %s\n", dom->name);
misa_string(xlen, str, sizeof(str));
sbi_printf("Boot HART ISA : %s\n", str);
sbi_printf("Boot HART ISA : %s\n", str);
sbi_hart_get_features_str(scratch, str, sizeof(str));
sbi_printf("BOOT HART Features : %s\n", str);
sbi_printf("BOOT HART PMP Count : %d\n", sbi_hart_pmp_count(scratch));
/* Firmware details */
sbi_printf("Firmware Base : 0x%lx\n", scratch->fw_start);
sbi_printf("Firmware Size : %d KB\n",
(u32)(scratch->fw_size / 1024));
/* Generic details */
sbi_printf("Runtime SBI Version : %d.%d\n",
sbi_ecall_version_major(), sbi_ecall_version_minor());
sbi_printf("\n");
sbi_hart_delegation_dump(scratch);
sbi_hart_pmp_dump(scratch);
sbi_printf("Boot HART Features : %s\n", str);
sbi_printf("Boot HART PMP Count : %d\n",
sbi_hart_pmp_count(scratch));
sbi_printf("Boot HART PMP Granularity : %lu\n",
sbi_hart_pmp_granularity(scratch));
sbi_printf("Boot HART PMP Address Bits: %d\n",
sbi_hart_pmp_addrbits(scratch));
sbi_printf("Boot HART MHPM Count : %d\n",
sbi_hart_mhpm_count(scratch));
sbi_printf("Boot HART MHPM Count : %d\n",
sbi_hart_mhpm_count(scratch));
sbi_hart_delegation_dump(scratch, "Boot HART ", " ");
}
static spinlock_t coldboot_lock = SPIN_LOCK_INITIALIZER;
static unsigned long coldboot_done = 0;
static struct sbi_hartmask coldboot_wait_hmask = { 0 };
static unsigned long coldboot_done;
static void wait_for_coldboot(struct sbi_scratch *scratch, u32 hartid)
{
unsigned long saved_mie, cmip;
@@ -105,16 +144,20 @@ static void wait_for_coldboot(struct sbi_scratch *scratch, u32 hartid)
/* Mark current HART as waiting */
sbi_hartmask_set_hart(hartid, &coldboot_wait_hmask);
/* Release coldboot lock */
spin_unlock(&coldboot_lock);
/* Wait for coldboot to finish using WFI */
while (!coldboot_done) {
spin_unlock(&coldboot_lock);
while (!__smp_load_acquire(&coldboot_done)) {
do {
wfi();
cmip = csr_read(CSR_MIP);
} while (!(cmip & MIP_MSIP));
spin_lock(&coldboot_lock);
};
/* Acquire coldboot lock */
spin_lock(&coldboot_lock);
/* Unmark current HART as waiting */
sbi_hartmask_clear_hart(hartid, &coldboot_wait_hmask);
@@ -132,12 +175,12 @@ static void wake_coldboot_harts(struct sbi_scratch *scratch, u32 hartid)
{
const struct sbi_platform *plat = sbi_platform_ptr(scratch);
/* Mark coldboot done */
__smp_store_release(&coldboot_done, 1);
/* Acquire coldboot lock */
spin_lock(&coldboot_lock);
/* Mark coldboot done */
coldboot_done = 1;
/* Send an IPI to all HARTs waiting for coldboot */
for (int i = 0; i <= sbi_scratch_last_hartid(); i++) {
if ((i != hartid) &&
@@ -162,6 +205,11 @@ static void __noreturn init_coldboot(struct sbi_scratch *scratch, u32 hartid)
if (rc)
sbi_hart_hang();
/* Note: This has to be second thing in coldboot init sequence */
rc = sbi_domain_init(scratch, hartid);
if (rc)
sbi_hart_hang();
init_count_offset = sbi_scratch_alloc_offset(__SIZEOF_POINTER__,
"INIT_COUNT");
if (!init_count_offset)
@@ -175,7 +223,7 @@ static void __noreturn init_coldboot(struct sbi_scratch *scratch, u32 hartid)
if (rc)
sbi_hart_hang();
rc = sbi_hart_init(scratch, hartid, TRUE);
rc = sbi_hart_init(scratch, TRUE);
if (rc)
sbi_hart_hang();
@@ -183,32 +231,75 @@ static void __noreturn init_coldboot(struct sbi_scratch *scratch, u32 hartid)
if (rc)
sbi_hart_hang();
sbi_boot_print_banner(scratch);
rc = sbi_platform_irqchip_init(plat, TRUE);
if (rc)
if (rc) {
sbi_printf("%s: platform irqchip init failed (error %d)\n",
__func__, rc);
sbi_hart_hang();
}
rc = sbi_ipi_init(scratch, TRUE);
if (rc)
if (rc) {
sbi_printf("%s: ipi init failed (error %d)\n", __func__, rc);
sbi_hart_hang();
}
rc = sbi_tlb_init(scratch, TRUE);
if (rc)
if (rc) {
sbi_printf("%s: tlb init failed (error %d)\n", __func__, rc);
sbi_hart_hang();
}
rc = sbi_timer_init(scratch, TRUE);
if (rc)
if (rc) {
sbi_printf("%s: timer init failed (error %d)\n", __func__, rc);
sbi_hart_hang();
}
rc = sbi_ecall_init();
if (rc)
if (rc) {
sbi_printf("%s: ecall init failed (error %d)\n", __func__, rc);
sbi_hart_hang();
}
sbi_boot_print_general(scratch);
/*
* Note: Finalize domains after HSM initialization so that we
* can startup non-root domains.
* Note: Finalize domains before HART PMP configuration so
* that we use correct domain for configuring PMP.
*/
rc = sbi_domain_finalize(scratch, hartid);
if (rc) {
sbi_printf("%s: domain finalize failed (error %d)\n",
__func__, rc);
sbi_hart_hang();
}
sbi_boot_print_domains(scratch);
rc = sbi_hart_pmp_configure(scratch);
if (rc) {
sbi_printf("%s: PMP configure failed (error %d)\n",
__func__, rc);
sbi_hart_hang();
}
/*
* Note: Platform final initialization should be last so that
* it sees correct domain assignment and PMP configuration.
*/
rc = sbi_platform_final_init(plat, TRUE);
if (rc)
if (rc) {
sbi_printf("%s: platform final init failed (error %d)\n",
__func__, rc);
sbi_hart_hang();
}
if (!(scratch->options & SBI_SCRATCH_NO_BOOT_PRINTS))
sbi_boot_prints(scratch, hartid);
sbi_boot_print_hart(scratch, hartid);
wake_coldboot_harts(scratch, hartid);
@@ -239,7 +330,7 @@ static void __noreturn init_warmboot(struct sbi_scratch *scratch, u32 hartid)
if (rc)
sbi_hart_hang();
rc = sbi_hart_init(scratch, hartid, FALSE);
rc = sbi_hart_init(scratch, FALSE);
if (rc)
sbi_hart_hang();
@@ -259,6 +350,10 @@ static void __noreturn init_warmboot(struct sbi_scratch *scratch, u32 hartid)
if (rc)
sbi_hart_hang();
rc = sbi_hart_pmp_configure(scratch);
if (rc)
sbi_hart_hang();
rc = sbi_platform_final_init(plat, FALSE);
if (rc)
sbi_hart_hang();
@@ -288,6 +383,7 @@ static atomic_t coldboot_lottery = ATOMIC_INITIALIZER(0);
*/
void __noreturn sbi_init(struct sbi_scratch *scratch)
{
bool next_mode_supported = FALSE;
bool coldboot = FALSE;
u32 hartid = current_hartid();
const struct sbi_platform *plat = sbi_platform_ptr(scratch);
@@ -296,7 +392,33 @@ void __noreturn sbi_init(struct sbi_scratch *scratch)
sbi_platform_hart_invalid(plat, hartid))
sbi_hart_hang();
if (atomic_xchg(&coldboot_lottery, 1) == 0)
switch (scratch->next_mode) {
case PRV_M:
next_mode_supported = TRUE;
break;
case PRV_S:
if (misa_extension('S'))
next_mode_supported = TRUE;
break;
case PRV_U:
if (misa_extension('U'))
next_mode_supported = TRUE;
break;
default:
sbi_hart_hang();
}
/*
* Only the HART supporting privilege mode specified in the
* scratch->next_mode should be allowed to become the coldboot
* HART because the coldboot HART will be directly jumping to
* the next booting stage.
*
* We use a lottery mechanism to select coldboot HART among
* HARTs which satisfy above condition.
*/
if (next_mode_supported && atomic_xchg(&coldboot_lottery, 1) == 0)
coldboot = TRUE;
if (coldboot)

View File

@@ -12,6 +12,7 @@
#include <sbi/riscv_atomic.h>
#include <sbi/riscv_barrier.h>
#include <sbi/sbi_bitops.h>
#include <sbi/sbi_domain.h>
#include <sbi/sbi_error.h>
#include <sbi/sbi_hart.h>
#include <sbi/sbi_hsm.h>
@@ -77,10 +78,11 @@ int sbi_ipi_send_many(ulong hmask, ulong hbase, u32 event, void *data)
{
int rc;
ulong i, m;
struct sbi_domain *dom = sbi_domain_thishart_ptr();
struct sbi_scratch *scratch = sbi_scratch_thishart_ptr();
if (hbase != -1UL) {
rc = sbi_hsm_hart_started_mask(hbase, &m);
rc = sbi_hsm_hart_started_mask(dom, hbase, &m);
if (rc)
return rc;
m &= hmask;
@@ -92,7 +94,7 @@ int sbi_ipi_send_many(ulong hmask, ulong hbase, u32 event, void *data)
}
} else {
hbase = 0;
while (!sbi_hsm_hart_started_mask(hbase, &m)) {
while (!sbi_hsm_hart_started_mask(dom, hbase, &m)) {
/* Send IPIs */
for (i = hbase; m; i++, m >>= 1) {
if (m & 1UL)

View File

@@ -24,7 +24,7 @@ union reg_data {
int sbi_misaligned_load_handler(ulong addr, ulong tval2, ulong tinst,
struct sbi_trap_regs *regs)
{
ulong insn;
ulong insn, insn_len;
union reg_data val;
struct sbi_trap_info uptrap;
int i, fp = 0, shift = 0, len = 0;
@@ -35,6 +35,7 @@ int sbi_misaligned_load_handler(ulong addr, ulong tval2, ulong tinst,
* transformed instruction or custom instruction.
*/
insn = tinst | INSN_16BIT_MASK;
insn_len = (tinst & 0x2) ? INSN_LEN(insn) : 2;
} else {
/*
* Bit[0] == 0 implies trapped instruction value is
@@ -45,6 +46,7 @@ int sbi_misaligned_load_handler(ulong addr, ulong tval2, ulong tinst,
uptrap.epc = regs->mepc;
return sbi_trap_redirect(regs, &uptrap);
}
insn_len = INSN_LEN(insn);
}
if ((insn & INSN_MASK_LW) == INSN_MATCH_LW) {
@@ -126,7 +128,7 @@ int sbi_misaligned_load_handler(ulong addr, ulong tval2, ulong tinst,
}
if (!fp)
SET_RD(insn, regs, val.data_ulong << shift >> shift);
SET_RD(insn, regs, ((long)(val.data_ulong << shift)) >> shift);
#ifdef __riscv_flen
else if (len == 8)
SET_F64_RD(insn, regs, val.data_u64);
@@ -134,7 +136,7 @@ int sbi_misaligned_load_handler(ulong addr, ulong tval2, ulong tinst,
SET_F32_RD(insn, regs, val.data_ulong);
#endif
regs->mepc += INSN_LEN(insn);
regs->mepc += insn_len;
return 0;
}
@@ -142,7 +144,7 @@ int sbi_misaligned_load_handler(ulong addr, ulong tval2, ulong tinst,
int sbi_misaligned_store_handler(ulong addr, ulong tval2, ulong tinst,
struct sbi_trap_regs *regs)
{
ulong insn;
ulong insn, insn_len;
union reg_data val;
struct sbi_trap_info uptrap;
int i, len = 0;
@@ -153,6 +155,7 @@ int sbi_misaligned_store_handler(ulong addr, ulong tval2, ulong tinst,
* transformed instruction or custom instruction.
*/
insn = tinst | INSN_16BIT_MASK;
insn_len = (tinst & 0x2) ? INSN_LEN(insn) : 2;
} else {
/*
* Bit[0] == 0 implies trapped instruction value is
@@ -163,6 +166,7 @@ int sbi_misaligned_store_handler(ulong addr, ulong tval2, ulong tinst,
uptrap.epc = regs->mepc;
return sbi_trap_redirect(regs, &uptrap);
}
insn_len = INSN_LEN(insn);
}
val.data_ulong = GET_RS2(insn, regs);
@@ -233,7 +237,7 @@ int sbi_misaligned_store_handler(ulong addr, ulong tval2, ulong tinst,
}
}
regs->mepc += INSN_LEN(insn);
regs->mepc += insn_len;
return 0;
}

View File

@@ -14,6 +14,10 @@
#include <sbi/sbi_string.h>
/*
Provides sbi_strcmp for the completeness of supporting string functions.
it is not recommended to use sbi_strcmp() but use sbi_strncmp instead.
*/
int sbi_strcmp(const char *a, const char *b)
{
/* search first diff or end of string */
@@ -23,6 +27,15 @@ int sbi_strcmp(const char *a, const char *b)
return *a - *b;
}
int sbi_strncmp(const char *a, const char *b, size_t count)
{
/* search first diff or end of string */
for (; count > 0 && *a == *b && *a != '\0'; a++, b++, count--)
;
return *a - *b;
}
size_t sbi_strlen(const char *str)
{
unsigned long ret = 0;

View File

@@ -10,6 +10,7 @@
#include <sbi/riscv_asm.h>
#include <sbi/sbi_bitops.h>
#include <sbi/sbi_domain.h>
#include <sbi/sbi_hart.h>
#include <sbi/sbi_hsm.h>
#include <sbi/sbi_platform.h>
@@ -17,14 +18,24 @@
#include <sbi/sbi_ipi.h>
#include <sbi/sbi_init.h>
void __noreturn sbi_system_reset(u32 platform_reset_type)
bool sbi_system_reset_supported(u32 reset_type, u32 reset_reason)
{
if (sbi_platform_system_reset_check(sbi_platform_thishart_ptr(),
reset_type, reset_reason))
return TRUE;
return FALSE;
}
void __noreturn sbi_system_reset(u32 reset_type, u32 reset_reason)
{
ulong hbase = 0, hmask;
u32 cur_hartid = current_hartid();
struct sbi_domain *dom = sbi_domain_thishart_ptr();
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)) {
while (!sbi_hsm_hart_started_mask(dom, hbase, &hmask)) {
if (hbase <= cur_hartid)
hmask &= ~(1UL << (cur_hartid - hbase));
if (hmask)
@@ -35,9 +46,10 @@ void __noreturn sbi_system_reset(u32 platform_reset_type)
/* Stop current HART */
sbi_hsm_hart_stop(scratch, FALSE);
/* Platform specific reset */
sbi_platform_system_reset(sbi_platform_ptr(scratch),
platform_reset_type);
/* Platform specific reset if domain allowed system reset */
if (dom->system_reset_allowed)
sbi_platform_system_reset(sbi_platform_ptr(scratch),
reset_type, reset_reason);
/* If platform specific reset did not work then do sbi_exit() */
sbi_exit(scratch);

View File

@@ -32,7 +32,7 @@ static void sbi_tlb_flush_all(void)
__asm__ __volatile("sfence.vma");
}
static void sbi_tlb_hfence_vvma(struct sbi_tlb_info *tinfo)
void sbi_tlb_local_hfence_vvma(struct sbi_tlb_info *tinfo)
{
unsigned long start = tinfo->start;
unsigned long size = tinfo->size;
@@ -55,7 +55,7 @@ done:
csr_write(CSR_HGATP, hgatp);
}
static void sbi_tlb_hfence_gvma(struct sbi_tlb_info *tinfo)
void sbi_tlb_local_hfence_gvma(struct sbi_tlb_info *tinfo)
{
unsigned long start = tinfo->start;
unsigned long size = tinfo->size;
@@ -71,7 +71,7 @@ static void sbi_tlb_hfence_gvma(struct sbi_tlb_info *tinfo)
}
}
static void sbi_tlb_sfence_vma(struct sbi_tlb_info *tinfo)
void sbi_tlb_local_sfence_vma(struct sbi_tlb_info *tinfo)
{
unsigned long start = tinfo->start;
unsigned long size = tinfo->size;
@@ -90,7 +90,7 @@ static void sbi_tlb_sfence_vma(struct sbi_tlb_info *tinfo)
}
}
static void sbi_tlb_hfence_vvma_asid(struct sbi_tlb_info *tinfo)
void sbi_tlb_local_hfence_vvma_asid(struct sbi_tlb_info *tinfo)
{
unsigned long start = tinfo->start;
unsigned long size = tinfo->size;
@@ -119,7 +119,7 @@ done:
csr_write(CSR_HGATP, hgatp);
}
static void sbi_tlb_hfence_gvma_vmid(struct sbi_tlb_info *tinfo)
void sbi_tlb_local_hfence_gvma_vmid(struct sbi_tlb_info *tinfo)
{
unsigned long start = tinfo->start;
unsigned long size = tinfo->size;
@@ -141,7 +141,7 @@ static void sbi_tlb_hfence_gvma_vmid(struct sbi_tlb_info *tinfo)
}
}
static void sbi_tlb_sfence_vma_asid(struct sbi_tlb_info *tinfo)
void sbi_tlb_local_sfence_vma_asid(struct sbi_tlb_info *tinfo)
{
unsigned long start = tinfo->start;
unsigned long size = tinfo->size;
@@ -170,35 +170,9 @@ static void sbi_tlb_sfence_vma_asid(struct sbi_tlb_info *tinfo)
}
}
static void sbi_tlb_local_flush(struct sbi_tlb_info *tinfo)
void sbi_tlb_local_fence_i(struct sbi_tlb_info *tinfo)
{
switch (tinfo->type) {
case SBI_TLB_FLUSH_VMA:
sbi_tlb_sfence_vma(tinfo);
break;
case SBI_TLB_FLUSH_VMA_ASID:
sbi_tlb_sfence_vma_asid(tinfo);
break;
case SBI_TLB_FLUSH_GVMA:
sbi_tlb_hfence_gvma(tinfo);
break;
case SBI_TLB_FLUSH_GVMA_VMID:
sbi_tlb_hfence_gvma_vmid(tinfo);
break;
case SBI_TLB_FLUSH_VVMA:
sbi_tlb_hfence_vvma(tinfo);
break;
case SBI_TLB_FLUSH_VVMA_ASID:
sbi_tlb_hfence_vvma_asid(tinfo);
break;
case SBI_ITLB_FLUSH:
__asm__ __volatile("fence.i");
break;
default:
sbi_printf("Invalid tlb flush request type [%lu]\n",
tinfo->type);
}
return;
__asm__ __volatile("fence.i");
}
static void sbi_tlb_entry_process(struct sbi_tlb_info *tinfo)
@@ -207,7 +181,7 @@ static void sbi_tlb_entry_process(struct sbi_tlb_info *tinfo)
struct sbi_scratch *rscratch = NULL;
unsigned long *rtlb_sync = NULL;
sbi_tlb_local_flush(tinfo);
tinfo->local_fn(tinfo);
sbi_hartmask_for_each_hart(rhartid, &tinfo->smask) {
rscratch = sbi_hartid_to_scratch(rhartid);
@@ -316,13 +290,13 @@ static int sbi_tlb_update_cb(void *in, void *data)
curr = (struct sbi_tlb_info *)data;
next = (struct sbi_tlb_info *)in;
if (next->type == SBI_TLB_FLUSH_VMA_ASID &&
curr->type == SBI_TLB_FLUSH_VMA_ASID) {
if (next->local_fn == sbi_tlb_local_sfence_vma_asid &&
curr->local_fn == sbi_tlb_local_sfence_vma_asid) {
if (next->asid == curr->asid)
ret = __sbi_tlb_range_check(curr, next);
} else if (next->type == SBI_TLB_FLUSH_VMA &&
curr->type == SBI_TLB_FLUSH_VMA) {
ret = __sbi_tlb_range_check(curr, next);
} else if (next->local_fn == sbi_tlb_local_sfence_vma &&
curr->local_fn == sbi_tlb_local_sfence_vma) {
ret = __sbi_tlb_range_check(curr, next);
}
return ret;
@@ -352,7 +326,7 @@ static int sbi_tlb_update(struct sbi_scratch *scratch,
* then just do a local flush and return;
*/
if (remote_hartid == curr_hartid) {
sbi_tlb_local_flush(tinfo);
tinfo->local_fn(tinfo);
return -1;
}
@@ -391,6 +365,9 @@ static u32 tlb_event = SBI_IPI_EVENT_MAX;
int sbi_tlb_request(ulong hmask, ulong hbase, struct sbi_tlb_info *tinfo)
{
if (!tinfo->local_fn)
return SBI_EINVAL;
return sbi_ipi_send_many(hmask, hbase, tlb_event, tinfo);
}

View File

@@ -16,6 +16,7 @@
#include <sbi/sbi_illegal_insn.h>
#include <sbi/sbi_ipi.h>
#include <sbi/sbi_misaligned_ldst.h>
#include <sbi/sbi_scratch.h>
#include <sbi/sbi_timer.h>
#include <sbi/sbi_trap.h>
@@ -123,7 +124,7 @@ int sbi_trap_redirect(struct sbi_trap_regs *regs,
/* Update HSTATUS SPVP and SPV bits */
hstatus = csr_read(CSR_HSTATUS);
hstatus &= ~HSTATUS_SPVP;
hstatus |= (regs->mstatus & MSTATUS_SPP) ? HSTATUS_SPVP : 0;
hstatus |= (prev_mode == PRV_S) ? HSTATUS_SPVP : 0;
hstatus &= ~HSTATUS_SPV;
hstatus |= (prev_virt) ? HSTATUS_SPV : 0;
csr_write(CSR_HSTATUS, hstatus);
@@ -252,7 +253,7 @@ void sbi_trap_handler(struct sbi_trap_regs *regs)
msg = "misaligned store handler failed";
break;
case CAUSE_SUPERVISOR_ECALL:
case CAUSE_HYPERVISOR_ECALL:
case CAUSE_MACHINE_ECALL:
rc = sbi_ecall_handler(regs);
msg = "ecall handler failed";
break;
@@ -271,3 +272,22 @@ trap_error:
if (rc)
sbi_trap_error(msg, rc, mcause, mtval, mtval2, mtinst, regs);
}
typedef void (*trap_exit_t)(const struct sbi_trap_regs *regs);
/**
* Exit trap/interrupt handling
*
* This function is called by non-firmware code to abruptly exit
* trap/interrupt handling and resume execution at context pointed
* by given register state.
*
* @param regs pointer to register state
*/
void __noreturn sbi_trap_exit(const struct sbi_trap_regs *regs)
{
struct sbi_scratch *scratch = sbi_scratch_thishart_ptr();
((trap_exit_t)scratch->trap_exit)(regs);
__builtin_unreachable();
}

455
lib/utils/fdt/fdt_domain.c Normal file
View File

@@ -0,0 +1,455 @@
// SPDX-License-Identifier: BSD-2-Clause
/*
* fdt_domain.c - Flat Device Tree Domain helper routines
*
* Copyright (c) 2020 Western Digital Corporation or its affiliates.
*
* Authors:
* Anup Patel <anup.patel@wdc.com>
*/
#include <libfdt.h>
#include <sbi/sbi_domain.h>
#include <sbi/sbi_error.h>
#include <sbi/sbi_hartmask.h>
#include <sbi/sbi_scratch.h>
#include <sbi_utils/fdt/fdt_domain.h>
#include <sbi_utils/fdt/fdt_helper.h>
int fdt_iterate_each_domain(void *fdt, void *opaque,
int (*fn)(void *fdt, int domain_offset,
void *opaque))
{
int rc, doffset, poffset;
if (!fdt || !fn)
return SBI_EINVAL;
poffset = fdt_path_offset(fdt, "/chosen");
if (poffset < 0)
return 0;
poffset = fdt_node_offset_by_compatible(fdt, poffset,
"opensbi,domain,config");
if (poffset < 0)
return 0;
fdt_for_each_subnode(doffset, fdt, poffset) {
if (fdt_node_check_compatible(fdt, doffset,
"opensbi,domain,instance"))
continue;
rc = fn(fdt, doffset, opaque);
if (rc)
return rc;
}
return 0;
}
int fdt_iterate_each_memregion(void *fdt, int domain_offset, void *opaque,
int (*fn)(void *fdt, int domain_offset,
int region_offset, u32 region_access,
void *opaque))
{
u32 i, rcount;
int rc, len, region_offset;
const u32 *regions;
if (!fdt || (domain_offset < 0) || !fn)
return SBI_EINVAL;
if (fdt_node_check_compatible(fdt, domain_offset,
"opensbi,domain,instance"))
return SBI_EINVAL;
regions = fdt_getprop(fdt, domain_offset, "regions", &len);
if (!regions)
return 0;
rcount = (u32)len / (sizeof(u32) * 2);
for (i = 0; i < rcount; i++) {
region_offset = fdt_node_offset_by_phandle(fdt,
fdt32_to_cpu(regions[2 * i]));
if (region_offset < 0)
return region_offset;
if (fdt_node_check_compatible(fdt, region_offset,
"opensbi,domain,memregion"))
return SBI_EINVAL;
rc = fn(fdt, domain_offset, region_offset,
fdt32_to_cpu(regions[(2 * i) + 1]), opaque);
if (rc)
return rc;
}
return 0;
}
struct __fixup_find_domain_offset_info {
const char *name;
int *doffset;
};
static int __fixup_find_domain_offset(void *fdt, int doff, void *p)
{
struct __fixup_find_domain_offset_info *fdo = p;
if (!sbi_strcmp(fdo->name, fdt_get_name(fdt, doff, NULL)))
*fdo->doffset = doff;
return 0;
}
#define DISABLE_DEVICES_MASK (SBI_DOMAIN_MEMREGION_READABLE | \
SBI_DOMAIN_MEMREGION_WRITEABLE | \
SBI_DOMAIN_MEMREGION_EXECUTABLE)
static int __fixup_count_disable_devices(void *fdt, int doff, int roff,
u32 perm, void *p)
{
int len;
u32 *dcount = p;
if (perm & DISABLE_DEVICES_MASK)
return 0;
len = 0;
if (fdt_getprop(fdt, roff, "devices", &len))
*dcount += len / sizeof(u32);
return 0;
}
static int __fixup_disable_devices(void *fdt, int doff, int roff,
u32 raccess, void *p)
{
int i, len, coff;
const u32 *devices;
if (raccess & DISABLE_DEVICES_MASK)
return 0;
len = 0;
devices = fdt_getprop(fdt, roff, "devices", &len);
if (!devices)
return 0;
len = len / sizeof(u32);
for (i = 0; i < len; i++) {
coff = fdt_node_offset_by_phandle(fdt,
fdt32_to_cpu(devices[i]));
if (coff < 0)
return coff;
fdt_setprop_string(fdt, coff, "status", "disabled");
}
return 0;
}
void fdt_domain_fixup(void *fdt)
{
u32 i, dcount;
int err, poffset, doffset;
struct sbi_domain *dom = sbi_domain_thishart_ptr();
struct __fixup_find_domain_offset_info fdo;
/* Remove the domain assignment DT property from CPU DT nodes */
poffset = fdt_path_offset(fdt, "/cpus");
if (poffset < 0)
return;
fdt_for_each_subnode(doffset, fdt, poffset) {
err = fdt_parse_hart_id(fdt, doffset, &i);
if (err)
continue;
fdt_nop_property(fdt, doffset, "opensbi-domain");
}
/* Skip device disable for root domain */
if (!dom->index)
goto skip_device_disable;
/* Find current domain DT node */
doffset = -1;
fdo.name = dom->name;
fdo.doffset = &doffset;
fdt_iterate_each_domain(fdt, &fdo, __fixup_find_domain_offset);
if (doffset < 0)
goto skip_device_disable;
/* Count current domain device DT nodes to be disabled */
dcount = 0;
fdt_iterate_each_memregion(fdt, doffset, &dcount,
__fixup_count_disable_devices);
if (!dcount)
goto skip_device_disable;
/* Expand FDT based on device DT nodes to be disabled */
err = fdt_open_into(fdt, fdt, fdt_totalsize(fdt) + dcount * 32);
if (err < 0)
return;
/* Again find current domain DT node */
doffset = -1;
fdo.name = dom->name;
fdo.doffset = &doffset;
fdt_iterate_each_domain(fdt, &fdo, __fixup_find_domain_offset);
if (doffset < 0)
goto skip_device_disable;
/* Disable device DT nodes for current domain */
fdt_iterate_each_memregion(fdt, doffset, NULL,
__fixup_disable_devices);
skip_device_disable:
/* Remove the OpenSBI domain config DT node */
poffset = fdt_path_offset(fdt, "/chosen");
if (poffset < 0)
return;
poffset = fdt_node_offset_by_compatible(fdt, poffset,
"opensbi,domain,config");
if (poffset < 0)
return;
fdt_nop_node(fdt, poffset);
}
#define FDT_DOMAIN_MAX_COUNT 8
#define FDT_DOMAIN_REGION_MAX_COUNT 16
static u32 fdt_domains_count;
static struct sbi_domain fdt_domains[FDT_DOMAIN_MAX_COUNT];
static struct sbi_hartmask fdt_masks[FDT_DOMAIN_MAX_COUNT];
static struct sbi_domain_memregion
fdt_regions[FDT_DOMAIN_MAX_COUNT][FDT_DOMAIN_REGION_MAX_COUNT + 2];
static int __fdt_parse_region(void *fdt, int domain_offset,
int region_offset, u32 region_access,
void *opaque)
{
int len;
u32 val32;
u64 val64;
const u32 *val;
u32 *region_count = opaque;
struct sbi_domain_memregion *region;
/* Find next region of the domain */
if (FDT_DOMAIN_REGION_MAX_COUNT <= *region_count)
return SBI_EINVAL;
region = &fdt_regions[fdt_domains_count][*region_count];
/* Read "base" DT property */
val = fdt_getprop(fdt, region_offset, "base", &len);
if (!val && len >= 8)
return SBI_EINVAL;
val64 = fdt32_to_cpu(val[0]);
val64 = (val64 << 32) | fdt32_to_cpu(val[1]);
region->base = val64;
/* Read "order" DT property */
val = fdt_getprop(fdt, region_offset, "order", &len);
if (!val && len >= 4)
return SBI_EINVAL;
val32 = fdt32_to_cpu(*val);
if (val32 < 3 || __riscv_xlen < val32)
return SBI_EINVAL;
region->order = val32;
/* Read "mmio" DT property */
region->flags = region_access & SBI_DOMAIN_MEMREGION_ACCESS_MASK;
if (fdt_get_property(fdt, region_offset, "mmio", NULL))
region->flags |= SBI_DOMAIN_MEMREGION_MMIO;
(*region_count)++;
return 0;
}
static int __fdt_parse_domain(void *fdt, int domain_offset, void *opaque)
{
u32 val32;
u64 val64;
const u32 *val;
struct sbi_domain *dom;
struct sbi_hartmask *mask;
struct sbi_hartmask assign_mask;
int *cold_domain_offset = opaque;
struct sbi_domain_memregion *regions;
int i, err, len, cpus_offset, cpu_offset, doffset;
/* Sanity check on maximum domains we can handle */
if (FDT_DOMAIN_MAX_COUNT <= fdt_domains_count)
return SBI_EINVAL;
dom = &fdt_domains[fdt_domains_count];
mask = &fdt_masks[fdt_domains_count];
regions = &fdt_regions[fdt_domains_count][0];
/* Read DT node name */
sbi_strncpy(dom->name, fdt_get_name(fdt, domain_offset, NULL),
sizeof(dom->name));
dom->name[sizeof(dom->name) - 1] = '\0';
/* Setup possible HARTs mask */
SBI_HARTMASK_INIT(mask);
dom->possible_harts = mask;
val = fdt_getprop(fdt, domain_offset, "possible-harts", &len);
len = len / sizeof(u32);
if (val && len) {
for (i = 0; i < len; i++) {
cpu_offset = fdt_node_offset_by_phandle(fdt,
fdt32_to_cpu(val[i]));
if (cpu_offset < 0)
return cpu_offset;
err = fdt_parse_hart_id(fdt, cpu_offset, &val32);
if (err)
return err;
sbi_hartmask_set_hart(val32, mask);
}
}
/* Setup memregions from DT */
val32 = 0;
sbi_memset(regions, 0,
sizeof(*regions) * (FDT_DOMAIN_REGION_MAX_COUNT + 2));
dom->regions = regions;
err = fdt_iterate_each_memregion(fdt, domain_offset, &val32,
__fdt_parse_region);
if (err)
return err;
sbi_domain_memregion_initfw(&regions[val32]);
/* Read "boot-hart" DT property */
val32 = -1U;
val = fdt_getprop(fdt, domain_offset, "boot-hart", &len);
if (val && len >= 4) {
cpu_offset = fdt_node_offset_by_phandle(fdt,
fdt32_to_cpu(*val));
if (cpu_offset >= 0)
fdt_parse_hart_id(fdt, cpu_offset, &val32);
} else {
if (domain_offset == *cold_domain_offset)
val32 = current_hartid();
}
dom->boot_hartid = val32;
/* Read "next-arg1" DT property */
val64 = 0;
val = fdt_getprop(fdt, domain_offset, "next-arg1", &len);
if (val && len >= 8) {
val64 = fdt32_to_cpu(val[0]);
val64 = (val64 << 32) | fdt32_to_cpu(val[1]);
} else {
if (domain_offset == *cold_domain_offset)
val64 = sbi_scratch_thishart_ptr()->next_arg1;
}
dom->next_arg1 = val64;
/* Read "next-addr" DT property */
val64 = 0;
val = fdt_getprop(fdt, domain_offset, "next-addr", &len);
if (val && len >= 8) {
val64 = fdt32_to_cpu(val[0]);
val64 = (val64 << 32) | fdt32_to_cpu(val[1]);
} else {
if (domain_offset == *cold_domain_offset)
val64 = sbi_scratch_thishart_ptr()->next_addr;
}
dom->next_addr = val64;
/* Read "next-mode" DT property */
val32 = 0x1;
val = fdt_getprop(fdt, domain_offset, "next-mode", &len);
if (val && len >= 4) {
val32 = fdt32_to_cpu(val[0]);
if (val32 != 0x0 && val32 != 0x1)
val32 = 0x1;
} else {
if (domain_offset == *cold_domain_offset)
val32 = sbi_scratch_thishart_ptr()->next_mode;
}
dom->next_mode = val32;
/* Read "system-reset-allowed" DT property */
if (fdt_get_property(fdt, domain_offset,
"system-reset-allowed", NULL))
dom->system_reset_allowed = TRUE;
else
dom->system_reset_allowed = FALSE;
/* Find /cpus DT node */
cpus_offset = fdt_path_offset(fdt, "/cpus");
if (cpus_offset < 0)
return cpus_offset;
/* HART to domain assignment mask based on CPU DT nodes */
sbi_hartmask_clear_all(&assign_mask);
fdt_for_each_subnode(cpu_offset, fdt, cpus_offset) {
err = fdt_parse_hart_id(fdt, cpu_offset, &val32);
if (err)
continue;
if (SBI_HARTMASK_MAX_BITS <= val32)
continue;
val = fdt_getprop(fdt, cpu_offset, "opensbi-domain", &len);
if (!val || len < 4)
return SBI_EINVAL;
doffset = fdt_node_offset_by_phandle(fdt, fdt32_to_cpu(*val));
if (doffset < 0)
return doffset;
if (doffset == domain_offset)
sbi_hartmask_set_hart(val32, &assign_mask);
}
/* Increment domains count */
fdt_domains_count++;
/* Register the domain */
return sbi_domain_register(dom, &assign_mask);
}
int fdt_domains_populate(void *fdt)
{
const u32 *val;
int cold_domain_offset;
u32 hartid, cold_hartid;
int err, len, cpus_offset, cpu_offset;
/* Sanity checks */
if (!fdt)
return SBI_EINVAL;
/* Find /cpus DT node */
cpus_offset = fdt_path_offset(fdt, "/cpus");
if (cpus_offset < 0)
return cpus_offset;
/* Find coldboot HART domain DT node offset */
cold_domain_offset = -1;
cold_hartid = current_hartid();
fdt_for_each_subnode(cpu_offset, fdt, cpus_offset) {
err = fdt_parse_hart_id(fdt, cpu_offset, &hartid);
if (err)
continue;
if (hartid != cold_hartid)
continue;
val = fdt_getprop(fdt, cpu_offset, "opensbi-domain", &len);
if (val && len >= 4)
cold_domain_offset = fdt_node_offset_by_phandle(fdt,
fdt32_to_cpu(*val));
break;
}
/* Iterate over each domain in FDT and populate details */
return fdt_iterate_each_domain(fdt, &cold_domain_offset,
__fdt_parse_domain);
}

View File

@@ -9,9 +9,9 @@
#include <libfdt.h>
#include <sbi/sbi_console.h>
#include <sbi/sbi_domain.h>
#include <sbi/sbi_math.h>
#include <sbi/sbi_hart.h>
#include <sbi/sbi_platform.h>
#include <sbi/sbi_scratch.h>
#include <sbi/sbi_string.h>
#include <sbi_utils/fdt/fdt_fixup.h>
@@ -19,9 +19,9 @@
void fdt_cpu_fixup(void *fdt)
{
struct sbi_scratch *scratch = sbi_scratch_thishart_ptr();
const struct sbi_platform *plat = sbi_platform_ptr(scratch);
int err, cpu_offset, cpus_offset;
struct sbi_domain *dom = sbi_domain_thishart_ptr();
int err, cpu_offset, cpus_offset, len;
const char *mmu_type;
u32 hartid;
err = fdt_open_into(fdt, fdt, fdt_totalsize(fdt) + 32);
@@ -37,7 +37,15 @@ void fdt_cpu_fixup(void *fdt)
if (err)
continue;
if (sbi_platform_hart_invalid(plat, hartid))
/*
* Disable a HART DT node if one of the following is true:
* 1. The HART is not assigned to the current domain
* 2. MMU is not available for the HART
*/
mmu_type = fdt_getprop(fdt, cpu_offset, "mmu-type", &len);
if (!sbi_domain_is_assigned_hart(dom, hartid) ||
!mmu_type || !len)
fdt_setprop_string(fdt, cpu_offset, "status",
"disabled");
}
@@ -88,11 +96,11 @@ static int fdt_resv_memory_update_node(void *fdt, unsigned long addr,
if (na > 1 && addr_high)
sbi_snprintf(name, sizeof(name),
"mmode_pmp%d@%x,%x", index,
"mmode_resv%d@%x,%x", index,
addr_high, addr_low);
else
sbi_snprintf(name, sizeof(name),
"mmode_pmp%d@%x", index,
"mmode_resv%d@%x", index,
addr_low);
subnode = fdt_add_subnode(fdt, parent, name);
@@ -144,15 +152,22 @@ static int fdt_resv_memory_update_node(void *fdt, unsigned long addr,
*/
int fdt_reserved_memory_fixup(void *fdt)
{
struct sbi_domain_memregion *reg;
struct sbi_domain *dom = sbi_domain_thishart_ptr();
struct sbi_scratch *scratch = sbi_scratch_thishart_ptr();
unsigned long prot, addr, size;
int parent, i, j;
int err;
unsigned long addr, size;
int err, parent, i;
int na = fdt_address_cells(fdt, 0);
int ns = fdt_size_cells(fdt, 0);
/* expand the device tree to accommodate new node */
err = fdt_open_into(fdt, fdt, fdt_totalsize(fdt) + 256);
/*
* Expand the device tree to accommodate new node
* by the following estimated size:
*
* Each PMP memory region entry occupies 64 bytes.
* With 16 PMP memory regions we need 64 * 16 = 1024 bytes.
*/
err = fdt_open_into(fdt, fdt, fdt_totalsize(fdt) + 1024);
if (err < 0)
return err;
@@ -188,34 +203,29 @@ int fdt_reserved_memory_fixup(void *fdt)
* We assume the given device tree does not contain any memory region
* child node protected by PMP. Normally PMP programming happens at
* M-mode firmware. The memory space used by OpenSBI is protected.
* Some additional memory spaces may be protected by platform codes.
* Some additional memory spaces may be protected by domain memory
* regions.
*
* With above assumption, we create child nodes directly.
*/
if (!sbi_hart_has_feature(scratch, SBI_HART_HAS_PMP)) {
/*
* 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)
i = 0;
sbi_domain_for_each_memregion(dom, reg) {
/* Ignore MMIO or READABLE or WRITABLE or EXECUTABLE regions */
if (reg->flags & SBI_DOMAIN_MEMREGION_MMIO)
continue;
if (!(prot & PMP_A))
if (reg->flags & SBI_DOMAIN_MEMREGION_READABLE)
continue;
if (prot & (PMP_R | PMP_W | PMP_X))
if (reg->flags & SBI_DOMAIN_MEMREGION_WRITEABLE)
continue;
if (reg->flags & SBI_DOMAIN_MEMREGION_EXECUTABLE)
continue;
fdt_resv_memory_update_node(fdt, addr, size, j, parent, false);
j++;
addr = reg->base;
size = 1UL << reg->order;
fdt_resv_memory_update_node(fdt, addr, size, i, parent,
(sbi_hart_pmp_count(scratch)) ? false : true);
i++;
}
return 0;

View File

@@ -71,10 +71,48 @@ int fdt_find_match(void *fdt, int startoff,
return SBI_ENODEV;
}
static int fdt_translate_address(void *fdt, uint64_t reg, int parent,
unsigned long *addr)
{
int i, rlen;
int cell_addr, cell_size;
const fdt32_t *ranges;
uint64_t offset = 0, caddr = 0, paddr = 0, rsize = 0;
cell_addr = fdt_address_cells(fdt, parent);
if (cell_addr < 1)
return SBI_ENODEV;
cell_size = fdt_size_cells(fdt, parent);
if (cell_size < 0)
return SBI_ENODEV;
ranges = fdt_getprop(fdt, parent, "ranges", &rlen);
if (ranges && rlen > 0) {
for (i = 0; i < cell_addr; i++)
caddr = (caddr << 32) | fdt32_to_cpu(*ranges++);
for (i = 0; i < cell_addr; i++)
paddr = (paddr << 32) | fdt32_to_cpu(*ranges++);
for (i = 0; i < cell_size; i++)
rsize = (rsize << 32) | fdt32_to_cpu(*ranges++);
if (reg < caddr || caddr >= (reg + rsize )) {
sbi_printf("invalid address translation\n");
return SBI_ENODEV;
}
offset = reg - caddr;
*addr = paddr + offset;
} else {
/* No translation required */
*addr = reg;
}
return 0;
}
int fdt_get_node_addr_size(void *fdt, int node, unsigned long *addr,
unsigned long *size)
{
int parent, len, i;
int parent, len, i, rc;
int cell_addr, cell_size;
const fdt32_t *prop_addr, *prop_size;
uint64_t temp = 0;
@@ -98,7 +136,15 @@ int fdt_get_node_addr_size(void *fdt, int node, unsigned long *addr,
if (addr) {
for (i = 0; i < cell_addr; i++)
temp = (temp << 32) | fdt32_to_cpu(*prop_addr++);
*addr = temp;
do {
if (parent < 0)
break;
rc = fdt_translate_address(fdt, temp, parent, addr);
if (rc)
break;
parent = fdt_parent_offset(fdt, parent);
temp = *addr;
} while (1);
}
temp = 0;
@@ -123,7 +169,7 @@ int fdt_parse_hart_id(void *fdt, int cpu_offset, u32 *hartid)
prop = fdt_getprop(fdt, cpu_offset, "device_type", &len);
if (!prop || !len)
return SBI_EINVAL;
if (sbi_strcmp(prop, "cpu"))
if (strncmp (prop, "cpu", strlen ("cpu")))
return SBI_EINVAL;
val = fdt_getprop(fdt, cpu_offset, "reg", &len);

View File

@@ -4,5 +4,6 @@
# Copyright (C) 2020 Bin Meng <bmeng.cn@gmail.com>
#
libsbiutils-objs-y += fdt/fdt_domain.o
libsbiutils-objs-y += fdt/fdt_helper.o
libsbiutils-objs-y += fdt/fdt_fixup.o

View File

@@ -8,7 +8,7 @@ LIBFDT_soname = libfdt.$(SHAREDLIB_EXT).1
LIBFDT_INCLUDES = fdt.h libfdt.h libfdt_env.h
LIBFDT_VERSION = version.lds
LIBFDT_SRCS = fdt.c fdt_ro.c fdt_wip.c fdt_sw.c fdt_rw.c fdt_strerror.c fdt_empty_tree.c \
fdt_addresses.c fdt_overlay.c
fdt_addresses.c fdt_overlay.c fdt_check.c
LIBFDT_OBJS = $(LIBFDT_SRCS:%.c=%.o)
LIBFDT_LIB = libfdt-$(DTC_VERSION).$(SHAREDLIB_EXT)

View File

@@ -19,15 +19,21 @@ int32_t fdt_ro_probe_(const void *fdt)
{
uint32_t totalsize = fdt_totalsize(fdt);
if (can_assume(VALID_DTB))
return totalsize;
if (fdt_magic(fdt) == FDT_MAGIC) {
/* Complete tree */
if (fdt_version(fdt) < FDT_FIRST_SUPPORTED_VERSION)
return -FDT_ERR_BADVERSION;
if (fdt_last_comp_version(fdt) > FDT_LAST_SUPPORTED_VERSION)
return -FDT_ERR_BADVERSION;
if (!can_assume(LATEST)) {
if (fdt_version(fdt) < FDT_FIRST_SUPPORTED_VERSION)
return -FDT_ERR_BADVERSION;
if (fdt_last_comp_version(fdt) >
FDT_LAST_SUPPORTED_VERSION)
return -FDT_ERR_BADVERSION;
}
} else if (fdt_magic(fdt) == FDT_SW_MAGIC) {
/* Unfinished sequential-write blob */
if (fdt_size_dt_struct(fdt) == 0)
if (!can_assume(VALID_INPUT) && fdt_size_dt_struct(fdt) == 0)
return -FDT_ERR_BADSTATE;
} else {
return -FDT_ERR_BADMAGIC;
@@ -70,43 +76,58 @@ size_t fdt_header_size_(uint32_t version)
return FDT_V17_SIZE;
}
size_t fdt_header_size(const void *fdt)
{
return can_assume(LATEST) ? FDT_V17_SIZE :
fdt_header_size_(fdt_version(fdt));
}
int fdt_check_header(const void *fdt)
{
size_t hdrsize;
if (fdt_magic(fdt) != FDT_MAGIC)
return -FDT_ERR_BADMAGIC;
if (!can_assume(LATEST)) {
if ((fdt_version(fdt) < FDT_FIRST_SUPPORTED_VERSION)
|| (fdt_last_comp_version(fdt) >
FDT_LAST_SUPPORTED_VERSION))
return -FDT_ERR_BADVERSION;
if (fdt_version(fdt) < fdt_last_comp_version(fdt))
return -FDT_ERR_BADVERSION;
}
hdrsize = fdt_header_size(fdt);
if ((fdt_version(fdt) < FDT_FIRST_SUPPORTED_VERSION)
|| (fdt_last_comp_version(fdt) > FDT_LAST_SUPPORTED_VERSION))
return -FDT_ERR_BADVERSION;
if (fdt_version(fdt) < fdt_last_comp_version(fdt))
return -FDT_ERR_BADVERSION;
if (!can_assume(VALID_DTB)) {
if ((fdt_totalsize(fdt) < hdrsize)
|| (fdt_totalsize(fdt) > INT_MAX))
return -FDT_ERR_TRUNCATED;
/* Bounds check memrsv block */
if (!check_off_(hdrsize, fdt_totalsize(fdt), fdt_off_mem_rsvmap(fdt)))
return -FDT_ERR_TRUNCATED;
/* Bounds check structure block */
if (fdt_version(fdt) < 17) {
if (!check_off_(hdrsize, fdt_totalsize(fdt),
fdt_off_dt_struct(fdt)))
if ((fdt_totalsize(fdt) < hdrsize)
|| (fdt_totalsize(fdt) > INT_MAX))
return -FDT_ERR_TRUNCATED;
} else {
if (!check_block_(hdrsize, fdt_totalsize(fdt),
fdt_off_dt_struct(fdt),
fdt_size_dt_struct(fdt)))
/* Bounds check memrsv block */
if (!check_off_(hdrsize, fdt_totalsize(fdt),
fdt_off_mem_rsvmap(fdt)))
return -FDT_ERR_TRUNCATED;
}
/* Bounds check strings block */
if (!check_block_(hdrsize, fdt_totalsize(fdt),
fdt_off_dt_strings(fdt), fdt_size_dt_strings(fdt)))
return -FDT_ERR_TRUNCATED;
if (!can_assume(VALID_DTB)) {
/* Bounds check structure block */
if (!can_assume(LATEST) && fdt_version(fdt) < 17) {
if (!check_off_(hdrsize, fdt_totalsize(fdt),
fdt_off_dt_struct(fdt)))
return -FDT_ERR_TRUNCATED;
} else {
if (!check_block_(hdrsize, fdt_totalsize(fdt),
fdt_off_dt_struct(fdt),
fdt_size_dt_struct(fdt)))
return -FDT_ERR_TRUNCATED;
}
/* Bounds check strings block */
if (!check_block_(hdrsize, fdt_totalsize(fdt),
fdt_off_dt_strings(fdt),
fdt_size_dt_strings(fdt)))
return -FDT_ERR_TRUNCATED;
}
return 0;
}
@@ -115,12 +136,13 @@ const void *fdt_offset_ptr(const void *fdt, int offset, unsigned int len)
{
unsigned absoffset = offset + fdt_off_dt_struct(fdt);
if ((absoffset < offset)
|| ((absoffset + len) < absoffset)
|| (absoffset + len) > fdt_totalsize(fdt))
return NULL;
if (!can_assume(VALID_INPUT))
if ((absoffset < offset)
|| ((absoffset + len) < absoffset)
|| (absoffset + len) > fdt_totalsize(fdt))
return NULL;
if (fdt_version(fdt) >= 0x11)
if (can_assume(LATEST) || fdt_version(fdt) >= 0x11)
if (((offset + len) < offset)
|| ((offset + len) > fdt_size_dt_struct(fdt)))
return NULL;
@@ -137,7 +159,7 @@ uint32_t fdt_next_tag(const void *fdt, int startoffset, int *nextoffset)
*nextoffset = -FDT_ERR_TRUNCATED;
tagp = fdt_offset_ptr(fdt, offset, FDT_TAGSIZE);
if (!tagp)
if (!can_assume(VALID_DTB) && !tagp)
return FDT_END; /* premature end */
tag = fdt32_to_cpu(*tagp);
offset += FDT_TAGSIZE;
@@ -149,18 +171,19 @@ uint32_t fdt_next_tag(const void *fdt, int startoffset, int *nextoffset)
do {
p = fdt_offset_ptr(fdt, offset++, 1);
} while (p && (*p != '\0'));
if (!p)
if (!can_assume(VALID_DTB) && !p)
return FDT_END; /* premature end */
break;
case FDT_PROP:
lenp = fdt_offset_ptr(fdt, offset, sizeof(*lenp));
if (!lenp)
if (!can_assume(VALID_DTB) && !lenp)
return FDT_END; /* premature end */
/* skip-name offset, length and value */
offset += sizeof(struct fdt_property) - FDT_TAGSIZE
+ fdt32_to_cpu(*lenp);
if (fdt_version(fdt) < 0x10 && fdt32_to_cpu(*lenp) >= 8 &&
if (!can_assume(LATEST) &&
fdt_version(fdt) < 0x10 && fdt32_to_cpu(*lenp) >= 8 &&
((offset - fdt32_to_cpu(*lenp)) % 8) != 0)
offset += 4;
break;
@@ -183,6 +206,8 @@ uint32_t fdt_next_tag(const void *fdt, int startoffset, int *nextoffset)
int fdt_check_node_offset_(const void *fdt, int offset)
{
if (can_assume(VALID_INPUT))
return offset;
if ((offset < 0) || (offset % FDT_TAGSIZE)
|| (fdt_next_tag(fdt, offset, &offset) != FDT_BEGIN_NODE))
return -FDT_ERR_BADOFFSET;

View File

@@ -0,0 +1,74 @@
// SPDX-License-Identifier: (GPL-2.0-or-later OR BSD-2-Clause)
/*
* libfdt - Flat Device Tree manipulation
* Copyright (C) 2006 David Gibson, IBM Corporation.
*/
#include "libfdt_env.h"
#include <fdt.h>
#include <libfdt.h>
#include "libfdt_internal.h"
int fdt_check_full(const void *fdt, size_t bufsize)
{
int err;
int num_memrsv;
int offset, nextoffset = 0;
uint32_t tag;
unsigned int depth = 0;
const void *prop;
const char *propname;
if (bufsize < FDT_V1_SIZE)
return -FDT_ERR_TRUNCATED;
err = fdt_check_header(fdt);
if (err != 0)
return err;
if (bufsize < fdt_totalsize(fdt))
return -FDT_ERR_TRUNCATED;
num_memrsv = fdt_num_mem_rsv(fdt);
if (num_memrsv < 0)
return num_memrsv;
while (1) {
offset = nextoffset;
tag = fdt_next_tag(fdt, offset, &nextoffset);
if (nextoffset < 0)
return nextoffset;
switch (tag) {
case FDT_NOP:
break;
case FDT_END:
if (depth != 0)
return -FDT_ERR_BADSTRUCTURE;
return 0;
case FDT_BEGIN_NODE:
depth++;
if (depth > INT_MAX)
return -FDT_ERR_BADSTRUCTURE;
break;
case FDT_END_NODE:
if (depth == 0)
return -FDT_ERR_BADSTRUCTURE;
depth--;
break;
case FDT_PROP:
prop = fdt_getprop_by_offset(fdt, offset, &propname,
&err);
if (!prop)
return err;
break;
default:
return -FDT_ERR_INTERNAL;
}
}
}

View File

@@ -752,7 +752,7 @@ static int overlay_symbol_update(void *fdt, void *fdto)
if ((e - s) > len && (memcmp(s, "/__overlay__/", len) == 0)) {
/* /<fragment-name>/__overlay__/<relative-subnode-path> */
rel_path = s + len;
rel_path_len = e - rel_path;
rel_path_len = e - rel_path - 1;
} else if ((e - s) == len
&& (memcmp(s, "/__overlay__", len - 1) == 0)) {
/* /<fragment-name>/__overlay__ */

View File

@@ -33,17 +33,26 @@ static int fdt_nodename_eq_(const void *fdt, int offset,
const char *fdt_get_string(const void *fdt, int stroffset, int *lenp)
{
int32_t totalsize = fdt_ro_probe_(fdt);
uint32_t absoffset = stroffset + fdt_off_dt_strings(fdt);
int32_t totalsize;
uint32_t absoffset;
size_t len;
int err;
const char *s, *n;
if (can_assume(VALID_INPUT)) {
s = (const char *)fdt + fdt_off_dt_strings(fdt) + stroffset;
if (lenp)
*lenp = strlen(s);
return s;
}
totalsize = fdt_ro_probe_(fdt);
err = totalsize;
if (totalsize < 0)
goto fail;
err = -FDT_ERR_BADOFFSET;
absoffset = stroffset + fdt_off_dt_strings(fdt);
if (absoffset >= totalsize)
goto fail;
len = totalsize - absoffset;
@@ -51,7 +60,7 @@ const char *fdt_get_string(const void *fdt, int stroffset, int *lenp)
if (fdt_magic(fdt) == FDT_MAGIC) {
if (stroffset < 0)
goto fail;
if (fdt_version(fdt) >= 17) {
if (can_assume(LATEST) || fdt_version(fdt) >= 17) {
if (stroffset >= fdt_size_dt_strings(fdt))
goto fail;
if ((fdt_size_dt_strings(fdt) - stroffset) < len)
@@ -151,10 +160,13 @@ static const struct fdt_reserve_entry *fdt_mem_rsv(const void *fdt, int n)
int offset = n * sizeof(struct fdt_reserve_entry);
int absoffset = fdt_off_mem_rsvmap(fdt) + offset;
if (absoffset < fdt_off_mem_rsvmap(fdt))
return NULL;
if (absoffset > fdt_totalsize(fdt) - sizeof(struct fdt_reserve_entry))
return NULL;
if (!can_assume(VALID_INPUT)) {
if (absoffset < fdt_off_mem_rsvmap(fdt))
return NULL;
if (absoffset > fdt_totalsize(fdt) -
sizeof(struct fdt_reserve_entry))
return NULL;
}
return fdt_mem_rsv_(fdt, n);
}
@@ -164,7 +176,7 @@ int fdt_get_mem_rsv(const void *fdt, int n, uint64_t *address, uint64_t *size)
FDT_RO_PROBE(fdt);
re = fdt_mem_rsv(fdt, n);
if (!re)
if (!can_assume(VALID_INPUT) && !re)
return -FDT_ERR_BADOFFSET;
*address = fdt64_ld(&re->address);
@@ -295,7 +307,7 @@ const char *fdt_get_name(const void *fdt, int nodeoffset, int *len)
nameptr = nh->name;
if (fdt_version(fdt) < 0x10) {
if (!can_assume(LATEST) && fdt_version(fdt) < 0x10) {
/*
* For old FDT versions, match the naming conventions of V16:
* give only the leaf name (after all /). The actual tree
@@ -346,7 +358,8 @@ static const struct fdt_property *fdt_get_property_by_offset_(const void *fdt,
int err;
const struct fdt_property *prop;
if ((err = fdt_check_prop_offset_(fdt, offset)) < 0) {
if (!can_assume(VALID_INPUT) &&
(err = fdt_check_prop_offset_(fdt, offset)) < 0) {
if (lenp)
*lenp = err;
return NULL;
@@ -367,7 +380,7 @@ const struct fdt_property *fdt_get_property_by_offset(const void *fdt,
/* Prior to version 16, properties may need realignment
* and this API does not work. fdt_getprop_*() will, however. */
if (fdt_version(fdt) < 0x10) {
if (!can_assume(LATEST) && fdt_version(fdt) < 0x10) {
if (lenp)
*lenp = -FDT_ERR_BADVERSION;
return NULL;
@@ -388,7 +401,8 @@ static const struct fdt_property *fdt_get_property_namelen_(const void *fdt,
(offset = fdt_next_property_offset(fdt, offset))) {
const struct fdt_property *prop;
if (!(prop = fdt_get_property_by_offset_(fdt, offset, lenp))) {
prop = fdt_get_property_by_offset_(fdt, offset, lenp);
if (!can_assume(LIBFDT_FLAWLESS) && !prop) {
offset = -FDT_ERR_INTERNAL;
break;
}
@@ -413,7 +427,7 @@ const struct fdt_property *fdt_get_property_namelen(const void *fdt,
{
/* Prior to version 16, properties may need realignment
* and this API does not work. fdt_getprop_*() will, however. */
if (fdt_version(fdt) < 0x10) {
if (!can_assume(LATEST) && fdt_version(fdt) < 0x10) {
if (lenp)
*lenp = -FDT_ERR_BADVERSION;
return NULL;
@@ -444,8 +458,8 @@ const void *fdt_getprop_namelen(const void *fdt, int nodeoffset,
return NULL;
/* Handle realignment */
if (fdt_version(fdt) < 0x10 && (poffset + sizeof(*prop)) % 8 &&
fdt32_ld(&prop->len) >= 8)
if (!can_assume(LATEST) && fdt_version(fdt) < 0x10 &&
(poffset + sizeof(*prop)) % 8 && fdt32_ld(&prop->len) >= 8)
return prop->data + 4;
return prop->data;
}
@@ -461,19 +475,24 @@ const void *fdt_getprop_by_offset(const void *fdt, int offset,
if (namep) {
const char *name;
int namelen;
name = fdt_get_string(fdt, fdt32_ld(&prop->nameoff),
&namelen);
if (!name) {
if (lenp)
*lenp = namelen;
return NULL;
if (!can_assume(VALID_INPUT)) {
name = fdt_get_string(fdt, fdt32_ld(&prop->nameoff),
&namelen);
if (!name) {
if (lenp)
*lenp = namelen;
return NULL;
}
*namep = name;
} else {
*namep = fdt_string(fdt, fdt32_ld(&prop->nameoff));
}
*namep = name;
}
/* Handle realignment */
if (fdt_version(fdt) < 0x10 && (offset + sizeof(*prop)) % 8 &&
fdt32_ld(&prop->len) >= 8)
if (!can_assume(LATEST) && fdt_version(fdt) < 0x10 &&
(offset + sizeof(*prop)) % 8 && fdt32_ld(&prop->len) >= 8)
return prop->data + 4;
return prop->data;
}
@@ -598,10 +617,12 @@ int fdt_supernode_atdepth_offset(const void *fdt, int nodeoffset,
}
}
if ((offset == -FDT_ERR_NOTFOUND) || (offset >= 0))
return -FDT_ERR_BADOFFSET;
else if (offset == -FDT_ERR_BADOFFSET)
return -FDT_ERR_BADSTRUCTURE;
if (!can_assume(VALID_INPUT)) {
if ((offset == -FDT_ERR_NOTFOUND) || (offset >= 0))
return -FDT_ERR_BADOFFSET;
else if (offset == -FDT_ERR_BADOFFSET)
return -FDT_ERR_BADSTRUCTURE;
}
return offset; /* error from fdt_next_node() */
}
@@ -613,7 +634,8 @@ int fdt_node_depth(const void *fdt, int nodeoffset)
err = fdt_supernode_atdepth_offset(fdt, nodeoffset, 0, &nodedepth);
if (err)
return (err < 0) ? err : -FDT_ERR_INTERNAL;
return (can_assume(LIBFDT_FLAWLESS) || err < 0) ? err :
-FDT_ERR_INTERNAL;
return nodedepth;
}
@@ -833,66 +855,3 @@ int fdt_node_offset_by_compatible(const void *fdt, int startoffset,
return offset; /* error from fdt_next_node() */
}
int fdt_check_full(const void *fdt, size_t bufsize)
{
int err;
int num_memrsv;
int offset, nextoffset = 0;
uint32_t tag;
unsigned depth = 0;
const void *prop;
const char *propname;
if (bufsize < FDT_V1_SIZE)
return -FDT_ERR_TRUNCATED;
err = fdt_check_header(fdt);
if (err != 0)
return err;
if (bufsize < fdt_totalsize(fdt))
return -FDT_ERR_TRUNCATED;
num_memrsv = fdt_num_mem_rsv(fdt);
if (num_memrsv < 0)
return num_memrsv;
while (1) {
offset = nextoffset;
tag = fdt_next_tag(fdt, offset, &nextoffset);
if (nextoffset < 0)
return nextoffset;
switch (tag) {
case FDT_NOP:
break;
case FDT_END:
if (depth != 0)
return -FDT_ERR_BADSTRUCTURE;
return 0;
case FDT_BEGIN_NODE:
depth++;
if (depth > INT_MAX)
return -FDT_ERR_BADSTRUCTURE;
break;
case FDT_END_NODE:
if (depth == 0)
return -FDT_ERR_BADSTRUCTURE;
depth--;
break;
case FDT_PROP:
prop = fdt_getprop_by_offset(fdt, offset, &propname,
&err);
if (!prop)
return err;
break;
default:
return -FDT_ERR_INTERNAL;
}
}
}

View File

@@ -24,14 +24,16 @@ static int fdt_blocks_misordered_(const void *fdt,
static int fdt_rw_probe_(void *fdt)
{
if (can_assume(VALID_DTB))
return 0;
FDT_RO_PROBE(fdt);
if (fdt_version(fdt) < 17)
if (!can_assume(LATEST) && fdt_version(fdt) < 17)
return -FDT_ERR_BADVERSION;
if (fdt_blocks_misordered_(fdt, sizeof(struct fdt_reserve_entry),
fdt_size_dt_struct(fdt)))
return -FDT_ERR_BADLAYOUT;
if (fdt_version(fdt) > 17)
if (!can_assume(LATEST) && fdt_version(fdt) > 17)
fdt_set_version(fdt, 17);
return 0;
@@ -112,6 +114,15 @@ static int fdt_splice_string_(void *fdt, int newlen)
return 0;
}
/**
* fdt_find_add_string_() - Find or allocate a string
*
* @fdt: pointer to the device tree to check/adjust
* @s: string to find/add
* @allocated: Set to 0 if the string was found, 1 if not found and so
* allocated. Ignored if can_assume(NO_ROLLBACK)
* @return offset of string in the string table (whether found or added)
*/
static int fdt_find_add_string_(void *fdt, const char *s, int *allocated)
{
char *strtab = (char *)fdt + fdt_off_dt_strings(fdt);
@@ -120,7 +131,8 @@ static int fdt_find_add_string_(void *fdt, const char *s, int *allocated)
int len = strlen(s) + 1;
int err;
*allocated = 0;
if (!can_assume(NO_ROLLBACK))
*allocated = 0;
p = fdt_find_string_(strtab, fdt_size_dt_strings(fdt), s);
if (p)
@@ -132,7 +144,8 @@ static int fdt_find_add_string_(void *fdt, const char *s, int *allocated)
if (err)
return err;
*allocated = 1;
if (!can_assume(NO_ROLLBACK))
*allocated = 1;
memcpy(new, s, len);
return (new - strtab);
@@ -206,7 +219,8 @@ static int fdt_add_property_(void *fdt, int nodeoffset, const char *name,
err = fdt_splice_struct_(fdt, *prop, 0, proplen);
if (err) {
if (allocated)
/* Delete the string if we failed to add it */
if (!can_assume(NO_ROLLBACK) && allocated)
fdt_del_last_string_(fdt, name);
return err;
}
@@ -411,7 +425,7 @@ int fdt_open_into(const void *fdt, void *buf, int bufsize)
mem_rsv_size = (fdt_num_mem_rsv(fdt)+1)
* sizeof(struct fdt_reserve_entry);
if (fdt_version(fdt) >= 17) {
if (can_assume(LATEST) || fdt_version(fdt) >= 17) {
struct_size = fdt_size_dt_struct(fdt);
} else {
struct_size = 0;
@@ -421,7 +435,8 @@ int fdt_open_into(const void *fdt, void *buf, int bufsize)
return struct_size;
}
if (!fdt_blocks_misordered_(fdt, mem_rsv_size, struct_size)) {
if (can_assume(LIBFDT_ORDER) |
!fdt_blocks_misordered_(fdt, mem_rsv_size, struct_size)) {
/* no further work necessary */
err = fdt_move(fdt, buf, bufsize);
if (err)

View File

@@ -12,10 +12,13 @@
static int fdt_sw_probe_(void *fdt)
{
if (fdt_magic(fdt) == FDT_MAGIC)
return -FDT_ERR_BADSTATE;
else if (fdt_magic(fdt) != FDT_SW_MAGIC)
return -FDT_ERR_BADMAGIC;
if (!can_assume(VALID_INPUT)) {
if (fdt_magic(fdt) == FDT_MAGIC)
return -FDT_ERR_BADSTATE;
else if (fdt_magic(fdt) != FDT_SW_MAGIC)
return -FDT_ERR_BADMAGIC;
}
return 0;
}
@@ -38,7 +41,7 @@ static int fdt_sw_probe_memrsv_(void *fdt)
if (err)
return err;
if (fdt_off_dt_strings(fdt) != 0)
if (!can_assume(VALID_INPUT) && fdt_off_dt_strings(fdt) != 0)
return -FDT_ERR_BADSTATE;
return 0;
}
@@ -64,7 +67,8 @@ static int fdt_sw_probe_struct_(void *fdt)
if (err)
return err;
if (fdt_off_dt_strings(fdt) != fdt_totalsize(fdt))
if (!can_assume(VALID_INPUT) &&
fdt_off_dt_strings(fdt) != fdt_totalsize(fdt))
return -FDT_ERR_BADSTATE;
return 0;
}
@@ -151,7 +155,8 @@ int fdt_resize(void *fdt, void *buf, int bufsize)
headsize = fdt_off_dt_struct(fdt) + fdt_size_dt_struct(fdt);
tailsize = fdt_size_dt_strings(fdt);
if ((headsize + tailsize) > fdt_totalsize(fdt))
if (!can_assume(VALID_DTB) &&
headsize + tailsize > fdt_totalsize(fdt))
return -FDT_ERR_INTERNAL;
if ((headsize + tailsize) > bufsize)

View File

@@ -136,7 +136,7 @@ static inline uint32_t fdt32_ld(const fdt32_t *p)
static inline void fdt32_st(void *property, uint32_t value)
{
uint8_t *bp = property;
uint8_t *bp = (uint8_t *)property;
bp[0] = value >> 24;
bp[1] = (value >> 16) & 0xff;
@@ -160,7 +160,7 @@ static inline uint64_t fdt64_ld(const fdt64_t *p)
static inline void fdt64_st(void *property, uint64_t value)
{
uint8_t *bp = property;
uint8_t *bp = (uint8_t *)property;
bp[0] = value >> 56;
bp[1] = (value >> 48) & 0xff;
@@ -266,11 +266,12 @@ fdt_set_hdr_(size_dt_struct);
* fdt_header_size - return the size of the tree's header
* @fdt: pointer to a flattened device tree
*/
size_t fdt_header_size(const void *fdt);
/**
* fdt_header_size_ - internal function which takes a version number
*/
size_t fdt_header_size_(uint32_t version);
static inline size_t fdt_header_size(const void *fdt)
{
return fdt_header_size_(fdt_version(fdt));
}
/**
* fdt_check_header - sanity check a device tree header

View File

@@ -32,6 +32,7 @@
#define strrchr sbi_strrchr
#define strcpy sbi_strcpy
#define strcmp sbi_strcmp
#define strncmp sbi_strncmp
#define strlen sbi_strlen
#define strnlen sbi_strnlen

View File

@@ -10,10 +10,10 @@
#define FDT_ALIGN(x, a) (((x) + (a) - 1) & ~((a) - 1))
#define FDT_TAGALIGN(x) (FDT_ALIGN((x), FDT_TAGSIZE))
int fdt_ro_probe_(const void *fdt);
int32_t fdt_ro_probe_(const void *fdt);
#define FDT_RO_PROBE(fdt) \
{ \
int totalsize_; \
int32_t totalsize_; \
if ((totalsize_ = fdt_ro_probe_(fdt)) < 0) \
return totalsize_; \
}
@@ -48,4 +48,126 @@ static inline struct fdt_reserve_entry *fdt_mem_rsv_w_(void *fdt, int n)
#define FDT_SW_MAGIC (~FDT_MAGIC)
/**********************************************************************/
/* Checking controls */
/**********************************************************************/
#ifndef FDT_ASSUME_MASK
#define FDT_ASSUME_MASK 0
#endif
/*
* Defines assumptions which can be enabled. Each of these can be enabled
* individually. For maximum safety, don't enable any assumptions!
*
* For minimal code size and no safety, use ASSUME_PERFECT at your own risk.
* You should have another method of validating the device tree, such as a
* signature or hash check before using libfdt.
*
* For situations where security is not a concern it may be safe to enable
* ASSUME_SANE.
*/
enum {
/*
* This does essentially no checks. Only the latest device-tree
* version is correctly handled. Inconsistencies or errors in the device
* tree may cause undefined behaviour or crashes. Invalid parameters
* passed to libfdt may do the same.
*
* If an error occurs when modifying the tree it may leave the tree in
* an intermediate (but valid) state. As an example, adding a property
* where there is insufficient space may result in the property name
* being added to the string table even though the property itself is
* not added to the struct section.
*
* Only use this if you have a fully validated device tree with
* the latest supported version and wish to minimise code size.
*/
ASSUME_PERFECT = 0xff,
/*
* This assumes that the device tree is sane. i.e. header metadata
* and basic hierarchy are correct.
*
* With this assumption enabled, normal device trees produced by libfdt
* and the compiler should be handled safely. Malicious device trees and
* complete garbage may cause libfdt to behave badly or crash. Truncated
* device trees (e.g. those only partially loaded) can also cause
* problems.
*
* Note: Only checks that relate exclusively to the device tree itself
* (not the parameters passed to libfdt) are disabled by this
* assumption. This includes checking headers, tags and the like.
*/
ASSUME_VALID_DTB = 1 << 0,
/*
* This builds on ASSUME_VALID_DTB and further assumes that libfdt
* functions are called with valid parameters, i.e. not trigger
* FDT_ERR_BADOFFSET or offsets that are out of bounds. It disables any
* extensive checking of parameters and the device tree, making various
* assumptions about correctness.
*
* It doesn't make sense to enable this assumption unless
* ASSUME_VALID_DTB is also enabled.
*/
ASSUME_VALID_INPUT = 1 << 1,
/*
* This disables checks for device-tree version and removes all code
* which handles older versions.
*
* Only enable this if you know you have a device tree with the latest
* version.
*/
ASSUME_LATEST = 1 << 2,
/*
* This assumes that it is OK for a failed addition to the device tree,
* due to lack of space or some other problem, to skip any rollback
* steps (such as dropping the property name from the string table).
* This is safe to enable in most circumstances, even though it may
* leave the tree in a sub-optimal state.
*/
ASSUME_NO_ROLLBACK = 1 << 3,
/*
* This assumes that the device tree components appear in a 'convenient'
* order, i.e. the memory reservation block first, then the structure
* block and finally the string block.
*
* This order is not specified by the device-tree specification,
* but is expected by libfdt. The device-tree compiler always created
* device trees with this order.
*
* This assumption disables a check in fdt_open_into() and removes the
* ability to fix the problem there. This is safe if you know that the
* device tree is correctly ordered. See fdt_blocks_misordered_().
*/
ASSUME_LIBFDT_ORDER = 1 << 4,
/*
* This assumes that libfdt itself does not have any internal bugs. It
* drops certain checks that should never be needed unless libfdt has an
* undiscovered bug.
*
* This can generally be considered safe to enable.
*/
ASSUME_LIBFDT_FLAWLESS = 1 << 5,
};
/**
* can_assume_() - check if a particular assumption is enabled
*
* @mask: Mask to check (ASSUME_...)
* @return true if that assumption is enabled, else false
*/
static inline bool can_assume_(int mask)
{
return FDT_ASSUME_MASK & mask;
}
/** helper macros for checking assumptions */
#define can_assume(_assume) can_assume_(ASSUME_ ## _assume)
#endif /* LIBFDT_INTERNAL_H */

View File

@@ -7,7 +7,7 @@
# Atish Patra<atish.patra@wdc.com>
#
libfdt_files = fdt.o fdt_addresses.o fdt_empty_tree.o fdt_ro.o fdt_rw.o \
libfdt_files = fdt.o fdt_addresses.o fdt_check.o fdt_empty_tree.o fdt_ro.o fdt_rw.o \
fdt_strerror.o fdt_sw.o fdt_wip.o
$(foreach file, $(libfdt_files), \
$(eval CFLAGS_$(file) = -I$(src)/../../utils/libfdt))

View File

@@ -20,6 +20,7 @@ LIBFDT_1.2 {
fdt_get_alias_namelen;
fdt_get_alias;
fdt_get_path;
fdt_header_size;
fdt_supernode_atdepth_offset;
fdt_node_depth;
fdt_parent_offset;

View File

@@ -21,11 +21,18 @@ static struct fdt_reset *reset_drivers[] = {
static struct fdt_reset *current_driver = NULL;
int fdt_system_reset(u32 reset_type)
int fdt_system_reset_check(u32 reset_type, u32 reset_reason)
{
if (current_driver && current_driver->system_reset_check)
return current_driver->system_reset_check(reset_type,
reset_reason);
return 0;
}
void fdt_system_reset(u32 reset_type, u32 reset_reason)
{
if (current_driver && current_driver->system_reset)
return current_driver->system_reset(reset_type);
return 0;
current_driver->system_reset(reset_type, reset_reason);
}
int fdt_reset_init(void)

View File

@@ -18,5 +18,6 @@ static const struct fdt_match htif_reset_match[] = {
struct fdt_reset fdt_reset_htif = {
.match_table = htif_reset_match,
.system_reset_check = htif_system_reset_check,
.system_reset = htif_system_reset
};

View File

@@ -33,5 +33,6 @@ static const struct fdt_match sifive_test_reset_match[] = {
struct fdt_reset fdt_reset_sifive = {
.match_table = sifive_test_reset_match,
.init = sifive_test_reset_init,
.system_reset_check = sifive_test_system_reset_check,
.system_reset = sifive_test_system_reset
};

View File

@@ -18,18 +18,22 @@
#define REG_IQ_CYCLES 0x1C
#define REG_RX_THRES 0x20
#define UART_TX_FULL 0x2
#define UART_RX_FULL 0x8
static volatile void *uart_base;
void shakti_uart_putc(char ch)
{
while((readw(uart_base + REG_STATUS) & 0x2) == 0);
while((readw(uart_base + REG_STATUS) & UART_TX_FULL))
;
writeb(ch, uart_base + REG_TX);
}
int shakti_uart_getc(void)
{
u16 status = readw(uart_base + REG_STATUS);
if (status & 0x8)
if (status & UART_RX_FULL)
return readb(uart_base + REG_RX);
return -1;
}

View File

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

View File

@@ -8,7 +8,7 @@
*/
#include <sbi/riscv_io.h>
#include <sbi/sbi_platform.h>
#include <sbi/sbi_ecall_interface.h>
#include <sbi_utils/sys/sifive_test.h>
#define FINISHER_FAIL 0x3333
@@ -17,23 +17,36 @@
static void *sifive_test_base;
int sifive_test_system_reset(u32 type)
int sifive_test_system_reset_check(u32 type, u32 reason)
{
switch (type) {
case SBI_SRST_RESET_TYPE_SHUTDOWN:
case SBI_SRST_RESET_TYPE_COLD_REBOOT:
case SBI_SRST_RESET_TYPE_WARM_REBOOT:
return 1;
}
return 0;
}
void sifive_test_system_reset(u32 type, u32 reason)
{
/*
* 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);
case SBI_SRST_RESET_TYPE_SHUTDOWN:
if (reason == SBI_SRST_RESET_REASON_NONE)
writew(FINISHER_PASS, sifive_test_base);
else
writew(FINISHER_FAIL, sifive_test_base);
break;
case SBI_PLATFORM_RESET_COLD:
case SBI_PLATFORM_RESET_WARM:
case SBI_SRST_RESET_TYPE_COLD_REBOOT:
case SBI_SRST_RESET_TYPE_WARM_REBOOT:
writew(FINISHER_RESET, sifive_test_base);
break;
}
return 0;
}
int sifive_test_init(unsigned long base)

View File

@@ -13,6 +13,7 @@
#include <sbi/sbi_console.h>
#include <sbi/sbi_const.h>
#include <sbi/sbi_platform.h>
#include <sbi/sbi_trap.h>
#include <sbi_utils/fdt/fdt_fixup.h>
#include <sbi_utils/irqchip/plic.h>
#include <sbi_utils/serial/uart8250.h>
@@ -114,17 +115,9 @@ static int ae350_timer_init(bool cold_boot)
return plmt_warm_timer_init();
}
/* Reset the platform. */
static int ae350_system_reset(u32 type)
{
/* For now nothing to do. */
sbi_printf("System reset\n");
return 0;
}
/* Vendor-Specific SBI handler */
static int ae350_vendor_ext_provider(long extid, long funcid,
unsigned long *args, unsigned long *out_value,
const struct sbi_trap_regs *regs, unsigned long *out_value,
struct sbi_trap_info *out_trap)
{
int ret = 0;
@@ -136,28 +129,28 @@ static int ae350_vendor_ext_provider(long extid, long funcid,
*out_value = csr_read(CSR_MMISCCTL);
break;
case SBI_EXT_ANDES_SET_MCACHE_CTL:
ret = mcall_set_mcache_ctl(args[0]);
ret = mcall_set_mcache_ctl(regs->a0);
break;
case SBI_EXT_ANDES_SET_MMISC_CTL:
ret = mcall_set_mmisc_ctl(args[0]);
ret = mcall_set_mmisc_ctl(regs->a0);
break;
case SBI_EXT_ANDES_ICACHE_OP:
ret = mcall_icache_op(args[0]);
ret = mcall_icache_op(regs->a0);
break;
case SBI_EXT_ANDES_DCACHE_OP:
ret = mcall_dcache_op(args[0]);
ret = mcall_dcache_op(regs->a0);
break;
case SBI_EXT_ANDES_L1CACHE_I_PREFETCH:
ret = mcall_l1_cache_i_prefetch_op(args[0]);
ret = mcall_l1_cache_i_prefetch_op(regs->a0);
break;
case SBI_EXT_ANDES_L1CACHE_D_PREFETCH:
ret = mcall_l1_cache_d_prefetch_op(args[0]);
ret = mcall_l1_cache_d_prefetch_op(regs->a0);
break;
case SBI_EXT_ANDES_NON_BLOCKING_LOAD_STORE:
ret = mcall_non_blocking_load_store(args[0]);
ret = mcall_non_blocking_load_store(regs->a0);
break;
case SBI_EXT_ANDES_WRITE_AROUND:
ret = mcall_write_around(args[0]);
ret = mcall_write_around(regs->a0);
break;
default:
sbi_printf("Unsupported vendor sbi call : %ld\n", funcid);
@@ -185,8 +178,6 @@ const struct sbi_platform_operations platform_ops = {
.timer_event_start = plmt_timer_event_start,
.timer_event_stop = plmt_timer_event_stop,
.system_reset = ae350_system_reset,
.vendor_ext_provider = ae350_vendor_ext_provider
};

View File

@@ -147,16 +147,6 @@ static int ariane_timer_init(bool cold_boot)
return clint_warm_timer_init();
}
/*
* Reset the ariane.
*/
static int ariane_system_reset(u32 type)
{
/* For now nothing to do. */
sbi_printf("System reset\n");
return 0;
}
/*
* Platform descriptor.
*/
@@ -174,7 +164,6 @@ const struct sbi_platform_operations platform_ops = {
.timer_value = clint_timer_value,
.timer_event_start = clint_timer_event_start,
.timer_event_stop = clint_timer_event_stop,
.system_reset = ariane_system_reset
};
const struct sbi_platform platform = {

View File

@@ -173,16 +173,6 @@ static int openpiton_timer_init(bool cold_boot)
return clint_warm_timer_init();
}
/*
* Reset the openpiton.
*/
static int openpiton_system_reset(u32 type)
{
/* For now nothing to do. */
sbi_printf("System reset\n");
return 0;
}
/*
* Platform descriptor.
*/
@@ -200,7 +190,6 @@ const struct sbi_platform_operations platform_ops = {
.timer_value = clint_timer_value,
.timer_event_start = clint_timer_event_start,
.timer_event_stop = clint_timer_event_stop,
.system_reset = openpiton_system_reset
};
const struct sbi_platform platform = {

View File

@@ -15,7 +15,7 @@ platform-ldflags-y =
# Command for platform specific "make run"
platform-runcmd = qemu-system-riscv$(PLATFORM_RISCV_XLEN) -M virt -m 256M \
-nographic -kernel $(build_dir)/platform/generic/firmware/fw_payload.elf
-nographic -bios $(build_dir)/platform/generic/firmware/fw_payload.elf
# Blobs to build
FW_TEXT_START=0x80000000

View File

@@ -20,7 +20,10 @@ struct platform_override {
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 (*system_reset_check)(u32 reset_type, u32 reset_reason,
const struct fdt_match *match);
void (*system_reset)(u32 reset_type, u32 reset_reason,
const struct fdt_match *match);
int (*fdt_fixup)(void *fdt, const struct fdt_match *match);
};

View File

@@ -13,6 +13,7 @@
#include <sbi/sbi_hartmask.h>
#include <sbi/sbi_platform.h>
#include <sbi/sbi_string.h>
#include <sbi_utils/fdt/fdt_domain.h>
#include <sbi_utils/fdt/fdt_fixup.h>
#include <sbi_utils/fdt/fdt_helper.h>
#include <sbi_utils/irqchip/fdt_irqchip.h>
@@ -71,7 +72,7 @@ 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;
const char *model;
void *fdt = (void *)arg1;
u32 hartid, hart_count = 0;
int rc, root_offset, cpus_offset, cpu_offset, len;
@@ -101,10 +102,6 @@ unsigned long fw_platform_init(unsigned long arg0, unsigned long arg1,
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;
}
@@ -152,6 +149,7 @@ static int generic_final_init(bool cold_boot)
fdt_cpu_fixup(fdt);
fdt_fixups(fdt);
fdt_domain_fixup(fdt);
if (generic_plat && generic_plat->fdt_fixup) {
rc = generic_plat->fdt_fixup(fdt, generic_plat_match);
@@ -174,6 +172,11 @@ static void generic_final_exit(void)
generic_plat->final_exit(generic_plat_match);
}
static int generic_domains_init(void)
{
return fdt_domains_populate(sbi_scratch_thishart_arg1_ptr());
}
static u64 generic_tlbr_flush_limit(void)
{
if (generic_plat && generic_plat->tlbr_flush_limit)
@@ -181,12 +184,24 @@ static u64 generic_tlbr_flush_limit(void)
return SBI_PLATFORM_TLB_RANGE_FLUSH_LIMIT_DEFAULT;
}
static int generic_system_reset(u32 reset_type)
static int generic_system_reset_check(u32 reset_type, u32 reset_reason)
{
if (generic_plat && generic_plat->system_reset)
return generic_plat->system_reset(reset_type,
generic_plat_match);
return fdt_system_reset(reset_type);
if (generic_plat && generic_plat->system_reset_check)
return generic_plat->system_reset_check(reset_type,
reset_reason,
generic_plat_match);
return fdt_system_reset_check(reset_type, reset_reason);
}
static void generic_system_reset(u32 reset_type, u32 reset_reason)
{
if (generic_plat && generic_plat->system_reset) {
generic_plat->system_reset(reset_type, reset_reason,
generic_plat_match);
return;
}
fdt_system_reset(reset_type, reset_reason);
}
const struct sbi_platform_operations platform_ops = {
@@ -194,6 +209,7 @@ const struct sbi_platform_operations platform_ops = {
.final_init = generic_final_init,
.early_exit = generic_early_exit,
.final_exit = generic_final_exit,
.domains_init = generic_domains_init,
.console_putc = fdt_serial_putc,
.console_getc = fdt_serial_getc,
.console_init = fdt_serial_init,
@@ -209,6 +225,7 @@ const struct sbi_platform_operations platform_ops = {
.timer_event_start = fdt_timer_event_start,
.timer_init = fdt_timer_init,
.timer_exit = fdt_timer_exit,
.system_reset_check = generic_system_reset_check,
.system_reset = generic_system_reset,
};

View File

@@ -11,3 +11,4 @@ platform-objs-y += platform.o
platform-objs-y += k210.o
platform-varprefix-k210.o = dt_k210
platform-padding-k210.o = 2048

View File

@@ -12,6 +12,7 @@
#include <sbi/sbi_console.h>
#include <sbi/sbi_const.h>
#include <sbi/sbi_platform.h>
#include <sbi_utils/fdt/fdt_fixup.h>
#include <sbi_utils/irqchip/plic.h>
#include <sbi_utils/serial/sifive-uart.h>
#include <sbi_utils/sys/clint.h>
@@ -67,6 +68,21 @@ static u32 k210_get_clk_freq(void)
return pll0_freq / div;
}
static int k210_final_init(bool cold_boot)
{
void *fdt;
if (!cold_boot)
return 0;
fdt = sbi_scratch_thishart_arg1_ptr();
fdt_cpu_fixup(fdt);
fdt_fixups(fdt);
return 0;
}
static int k210_console_init(void)
{
return sifive_uart_init(K210_UART_BASE_ADDR, k210_get_clk_freq(),
@@ -113,15 +129,9 @@ static int k210_timer_init(bool cold_boot)
return clint_warm_timer_init();
}
static int k210_system_reset(u32 type)
{
/* For now nothing to do. */
sbi_printf("System reset\n");
return 0;
}
const struct sbi_platform_operations platform_ops = {
.final_init = k210_final_init,
.console_init = k210_console_init,
.console_putc = sifive_uart_putc,
.console_getc = sifive_uart_getc,
@@ -136,8 +146,6 @@ const struct sbi_platform_operations platform_ops = {
.timer_value = clint_timer_value,
.timer_event_stop = clint_timer_event_stop,
.timer_event_start = clint_timer_event_start,
.system_reset = k210_system_reset
};
const struct sbi_platform platform = {

View File

@@ -186,13 +186,17 @@ static int ux600_timer_init(bool cold_boot)
return clint_warm_timer_init();
}
static int ux600_system_reset(u32 type)
static int ux600_system_reset_check(u32 type, u32 reason)
{
return 1;
}
static void ux600_system_reset(u32 type, u32 reason)
{
/* Reset system using MSFTRST register in Nuclei Timer. */
writel(UX600_NUCLEI_TIMER_MSFTRST_KEY, (void *)(UX600_NUCLEI_TIMER_ADDR
+ UX600_NUCLEI_TIMER_MSFTRST_OFS));
while(1);
return 0;
}
const struct sbi_platform_operations platform_ops = {
@@ -209,6 +213,7 @@ const struct sbi_platform_operations platform_ops = {
.timer_event_stop = clint_timer_event_stop,
.timer_event_start = clint_timer_event_start,
.timer_init = ux600_timer_init,
.system_reset_check = ux600_system_reset_check,
.system_reset = ux600_system_reset
};

View File

@@ -15,7 +15,7 @@ platform-ldflags-y =
# Command for platform specific "make run"
platform-runcmd = qemu-system-riscv$(PLATFORM_RISCV_XLEN) -M sifive_u -m 256M \
-nographic -kernel $(build_dir)/platform/sifive/fu540/firmware/fw_payload.elf
-nographic -bios $(build_dir)/platform/sifive/fu540/firmware/fw_payload.elf
# Blobs to build
FW_TEXT_START=0x80000000

View File

@@ -154,12 +154,6 @@ static u32 fu540_hart_index2id[FU540_HART_COUNT - 1] = {
[3] = 4,
};
static int fu540_system_reset(u32 type)
{
/* For now nothing to do. */
return 0;
}
const struct sbi_platform_operations platform_ops = {
.final_init = fu540_final_init,
.console_putc = sifive_uart_putc,
@@ -174,7 +168,6 @@ const struct sbi_platform_operations platform_ops = {
.timer_event_stop = clint_timer_event_stop,
.timer_event_start = clint_timer_event_start,
.timer_init = fu540_timer_init,
.system_reset = fu540_system_reset
};
const struct sbi_platform platform = {

View File

@@ -34,6 +34,9 @@ platform-ldflags-y =
# Firmware load address configuration. This is mandatory.
FW_TEXT_START=0x80000000
# Optional parameter for path to external FDT
# FW_FDT_PATH="path to platform flattened device tree file"
#
# Dynamic firmware configuration.
# Optional parameters are commented out. Uncomment and define these parameters
@@ -71,5 +74,4 @@ FW_PAYLOAD_OFFSET=0x200000
endif
# FW_PAYLOAD_ALIGN=0x1000
# FW_PAYLOAD_PATH="path to next boot stage binary image file"
# FW_PAYLOAD_FDT_PATH="path to platform flattened device tree file"
# FW_PAYLOAD_FDT_ADDR=0x82200000

View File

@@ -107,7 +107,7 @@ static int platform_ipi_init(bool cold_boot)
/* Example if the generic CLINT driver is used */
if (cold_boot) {
ret = clint_cold_ipi_init(&clint, NULL);
ret = clint_cold_ipi_init(&clint);
if (ret)
return ret;
}
@@ -142,7 +142,7 @@ static int platform_timer_init(bool cold_boot)
/* Example if the generic CLINT driver is used */
if (cold_boot) {
ret = clint_cold_timer_init(&clint);
ret = clint_cold_timer_init(&clint, NULL);
if (ret)
return ret;
}
@@ -178,13 +178,20 @@ static void platform_timer_event_stop(void)
}
/*
* Reset the platform.
* Check reset type and reason supported by the platform.
*/
static int platform_system_reset(u32 type)
static int platform_system_reset_check(u32 type, u32 reason)
{
return 0;
}
/*
* Reset the platform.
*/
static void platform_system_reset(u32 type, u32 reason)
{
}
/*
* Platform descriptor.
*/
@@ -202,6 +209,7 @@ const struct sbi_platform_operations platform_ops = {
.timer_event_stop = platform_timer_event_stop,
.timer_event_start = platform_timer_event_start,
.timer_init = platform_timer_init,
.system_reset_check = platform_system_reset_check,
.system_reset = platform_system_reset
};
const struct sbi_platform platform = {

View File

@@ -108,10 +108,14 @@ static int c910_timer_init(bool cold_boot)
return clint_warm_timer_init();
}
static int c910_system_reset(u32 type)
static int c910_system_reset_check(u32 type, u32 reason)
{
return 1;
}
static void c910_system_reset(u32 type, u32 reason)
{
asm volatile ("ebreak");
return 0;
}
int c910_hart_start(u32 hartid, ulong saddr)
@@ -135,6 +139,7 @@ const struct sbi_platform_operations platform_ops = {
.timer_init = c910_timer_init,
.timer_event_start = clint_timer_event_start,
.system_reset_check = c910_system_reset_check,
.system_reset = c910_system_reset,
.hart_start = c910_hart_start,

View File

@@ -9,6 +9,7 @@ function usage()
echo " -i <input_file_path> Input binary file path"
echo " -a <c_align> Output C array alignment"
echo " -p <c_prefix> Output C array name prefix"
echo " -t <num_zero_bytes> Output padding zero bytes"
exit 1;
}
@@ -16,8 +17,9 @@ function usage()
INPUT_PATH=""
OUTPUT_C_ALIGN=""
OUTPUT_C_PREFIX=""
NUM_ZERO_BYTES=0
while getopts "hi:a:p:o:" o; do
while getopts "hi:a:p:t:" o; do
case "${o}" in
h)
usage
@@ -31,6 +33,9 @@ while getopts "hi:a:p:o:" o; do
p)
OUTPUT_C_PREFIX=${OPTARG}
;;
t)
NUM_ZERO_BYTES=${OPTARG}
;;
*)
usage
;;
@@ -62,6 +67,8 @@ printf "const char __attribute__((aligned(%s))) %s_start[] = {\n" "${OUTPUT_C_AL
od -v -t x1 -An ${INPUT_PATH} | awk '{for (i=1; i<=NF; i++) printf " 0x%s,", $i; printf "\n"; }'
echo __dummy__ | awk "{for (i=1; i<=${NUM_ZERO_BYTES}; i++) { printf \" 0x00,\"; if (i % 16 == 0) printf \"\n\"; } }"
printf "};\n"
printf "const unsigned long %s_size = sizeof(%s_start);\n" "${OUTPUT_C_PREFIX}" "${OUTPUT_C_PREFIX}"