104 Commits
v0.6 ... v0.7

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

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

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

Signed-off-by: Atish Patra <atish.patra@wdc.com>
Reviewed-by: Bin Meng <bmeng.cn@gmail.com>
Reviewed-by: Anup Patel <anup.patel@wdc.com>
2020-04-17 09:30:17 +05:30
Atish Patra
f281de885e lib: irqchip/plic: Fix maximum priority threshold value
As per the PLIC specification, maximum priority threshold value is 0x7.
Even though, writing a higher value doesn't cause any error in qemu
hifive unleashed, there may be some implementation which checks the upper
and may result in an illegal access.

Signed-off-by: Atish Patra <atish.patra@wdc.com>
Reviewed-by: Bin Meng <bmeng.cn@gmail.com>
Reviewed-by: Anup Patel <anup.patel@wdc.com>
2020-04-06 08:58:56 +05:30
Liu Yibin
e5a7f556ce platform: thead/c910: Use HSM extension to boot secondary cores
Remove custom vendor extension and use HSM extension
to boot secondary cores

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

Update this function to return decoded size directly.

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

Signed-off-by: Damien Le Moal <damien.lemoal@wdc.com>
Reviewed-by: Bin Meng <bmeng.cn@gmail.com>
Reviewed-by: Anup Patel <anup.patel@wdc.com>
2020-03-13 10:02:42 +05:30
Atish Patra
757bb44e6e docs: Remove out-of-date documentation
Upstream U-Boot now have SMP support and doesn't require any additional
patches for HiFive Unleashed.

Update the documentation.

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

Most the above is adopted from Xvisor sources.

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

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

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

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

[0]: 66fb729a1e

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

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

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

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

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

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

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

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

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

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

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

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

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

Signed-off-by: Atish Patra <atish.patra@wdc.com>
Reviewed-by: Anup Patel <anup.patel@wdc.com>
2020-02-24 18:04:23 +05:30
109 changed files with 3407 additions and 1825 deletions

View File

@@ -29,16 +29,17 @@ endif
ifeq ($(build_dir),$(CURDIR))
$(error Build directory is same as source directory.)
endif
install_root_dir_default=$(CURDIR)/install
ifdef I
install_dir=$(shell $(READLINK) -f $(I))
install_root_dir=$(shell $(READLINK) -f $(I))
else
install_dir=$(CURDIR)/install
install_root_dir=$(install_root_dir_default)/usr
endif
ifeq ($(install_dir),$(CURDIR))
$(error Install directory is same as source directory.)
ifeq ($(install_root_dir),$(CURDIR))
$(error Install root directory is same as source directory.)
endif
ifeq ($(install_dir),$(build_dir))
$(error Install directory is same as build directory.)
ifeq ($(install_root_dir),$(build_dir))
$(error Install root directory is same as build directory.)
endif
ifdef PLATFORM_DIR
platform_dir_path=$(shell $(READLINK) -f $(PLATFORM_DIR))
@@ -156,6 +157,33 @@ ifndef PLATFORM_RISCV_CODE_MODEL
PLATFORM_RISCV_CODE_MODEL = medany
endif
# Setup install directories
ifdef INSTALL_INCLUDE_PATH
install_include_path=$(INSTALL_INCLUDE_PATH)
else
install_include_path=include
endif
ifdef INSTALL_LIB_PATH
install_lib_path=$(INSTALL_LIB_PATH)
else
ifneq ($(origin INSTALL_LIB_SUBDIR), undefined)
install_lib_subdir=$(INSTALL_LIB_SUBDIR)
else
install_lib_subdir=$(PLATFORM_RISCV_ABI)
endif
install_lib_path=lib$(subst 32,,$(PLATFORM_RISCV_XLEN))/$(install_lib_subdir)
endif
ifdef INSTALL_FIRMWARE_PATH
install_firmware_path=$(INSTALL_FIRMWARE_PATH)
else
install_firmware_path=share/opensbi/$(PLATFORM_RISCV_ABI)
endif
ifdef INSTALL_DOCS_PATH
install_docs_path=$(INSTALL_DOCS_PATH)
else
install_docs_path=share/opensbi/docs
endif
# Setup compilation commands flags
GENFLAGS = -I$(platform_src_dir)/include
GENFLAGS += -I$(include_dir)
@@ -215,12 +243,12 @@ copy_file = $(CMD_PREFIX)mkdir -p `dirname $(1)`; \
echo " COPY $(subst $(build_dir)/,,$(1))"; \
cp -f $(2) $(1)
inst_file = $(CMD_PREFIX)mkdir -p `dirname $(1)`; \
echo " INSTALL $(subst $(install_dir)/,,$(1))"; \
echo " INSTALL $(subst $(install_root_dir)/,,$(1))"; \
cp -f $(2) $(1)
inst_file_list = $(CMD_PREFIX)if [ ! -z "$(4)" ]; then \
mkdir -p $(1)/$(3); \
for file in $(4) ; do \
rel_file=`echo $$file | sed -e 's@$(2)/$(3)/@@'`; \
rel_file=`echo $$file | sed -e 's@$(2)/$(subst $(install_firmware_path),platform,$(3))@@'`; \
dest_file=$(1)"/"$(3)"/"`echo $$rel_file`; \
dest_dir=`dirname $$dest_file`; \
echo " INSTALL "$(3)"/"`echo $$rel_file`; \
@@ -229,7 +257,7 @@ inst_file_list = $(CMD_PREFIX)if [ ! -z "$(4)" ]; then \
done \
fi
inst_header_dir = $(CMD_PREFIX)mkdir -p $(1); \
echo " INSTALL $(subst $(install_dir)/,,$(1))"; \
echo " INSTALL $(subst $(install_root_dir)/,,$(1))"; \
cp -rf $(2) $(1)
compile_cpp = $(CMD_PREFIX)mkdir -p `dirname $(1)`; \
echo " CPP $(subst $(build_dir)/,,$(1))"; \
@@ -385,26 +413,26 @@ install: $(install_targets-y)
.PHONY: install_libsbi
install_libsbi: $(build_dir)/lib/libsbi.a
$(call inst_header_dir,$(install_dir)/include,$(include_dir)/sbi)
$(call inst_file,$(install_dir)/lib/libsbi.a,$(build_dir)/lib/libsbi.a)
$(call inst_header_dir,$(install_root_dir)/$(install_include_path),$(include_dir)/sbi)
$(call inst_file,$(install_root_dir)/$(install_lib_path)/libsbi.a,$(build_dir)/lib/libsbi.a)
.PHONY: install_libsbiutils
install_libsbiutils: $(build_dir)/lib/libsbiutils.a
$(call inst_header_dir,$(install_dir)/include,$(include_dir)/sbi_utils)
$(call inst_file,$(install_dir)/lib/libsbiutils.a,$(build_dir)/lib/libsbiutils.a)
$(call inst_header_dir,$(install_root_dir)/$(install_include_path),$(include_dir)/sbi_utils)
$(call inst_file,$(install_root_dir)/$(install_lib_path)/libsbiutils.a,$(build_dir)/lib/libsbiutils.a)
.PHONY: install_libplatsbi
install_libplatsbi: $(platform_build_dir)/lib/libplatsbi.a $(build_dir)/lib/libsbi.a $(build_dir)/lib/libsbiutils.a
$(call inst_file,$(install_dir)/platform/$(platform_subdir)/lib/libplatsbi.a,$(platform_build_dir)/lib/libplatsbi.a)
$(call inst_file,$(install_root_dir)/$(install_lib_path)/opensbi/$(platform_subdir)/lib/libplatsbi.a,$(platform_build_dir)/lib/libplatsbi.a)
.PHONY: install_firmwares
install_firmwares: $(platform_build_dir)/lib/libplatsbi.a $(build_dir)/lib/libsbi.a $(build_dir)/lib/libsbiutils.a $(firmware-bins-path-y)
$(call inst_file_list,$(install_dir),$(build_dir),platform/$(platform_subdir)/firmware,$(firmware-elfs-path-y))
$(call inst_file_list,$(install_dir),$(build_dir),platform/$(platform_subdir)/firmware,$(firmware-bins-path-y))
$(call inst_file_list,$(install_root_dir),$(build_dir),$(install_firmware_path)/$(platform_subdir)/firmware,$(firmware-elfs-path-y))
$(call inst_file_list,$(install_root_dir),$(build_dir),$(install_firmware_path)/$(platform_subdir)/firmware,$(firmware-bins-path-y))
.PHONY: install_docs
install_docs: $(build_dir)/docs/latex/refman.pdf
$(call inst_file,$(install_dir)/docs/refman.pdf,$(build_dir)/docs/latex/refman.pdf)
$(call inst_file,$(install_root_dir)/$(install_docs_path)/refman.pdf,$(build_dir)/docs/latex/refman.pdf)
# Rule for "make clean"
.PHONY: clean
@@ -429,7 +457,7 @@ ifeq ($(build_dir),$(CURDIR)/build)
$(if $(V), @echo " RM $(build_dir)")
$(CMD_PREFIX)rm -rf $(build_dir)
endif
ifeq ($(install_dir),$(CURDIR)/install)
$(if $(V), @echo " RM $(install_dir)")
$(CMD_PREFIX)rm -rf $(install_dir)
ifeq ($(install_root_dir),$(install_root_dir_default)/usr)
$(if $(V), @echo " RM $(install_root_dir_default)")
$(CMD_PREFIX)rm -rf $(install_root_dir_default)
endif

View File

@@ -39,6 +39,27 @@ OpenSBI also provides several runtime firmware examples built using the platform
*riscv-pk* bootloader (aka BBL) and enable the use of well-known bootloaders
such as [U-Boot] (https://git.denx.de/u-boot.git).
Supported SBI version
---------------------
Currently, OpenSBI fully supports SBI specification *v0.2*. OpenSBI also
supports Hart State Management (HSM) SBI extension starting from OpenSBI v0.7.
HSM extension allows S-mode software to boot all the harts a defined order
rather than legacy method of random booting of harts. As a result, many
required features such as CPU hotplug, kexec/kdump can also be supported easily
in S-mode. HSM extension in OpenSBI is implemented in a non-backward compatible
manner to reduce the maintenance burden and avoid confusion. That's why, any
S-mode software using OpenSBI will not be able to boot more than 1 hart if HSM
extension is not supported in S-mode.
Linux kernel already supports SBI v0.2 and HSM SBI extension starting from
**v5.7-rc1**. If you are using an Linux kernel older than **5.7-rc1** or any
other S-mode software without HSM SBI extension, you should stick to OpenSBI
v0.6 to boot all the harts. For a UMP systems, it doesn't matter.
N.B. Any S-mode boot loader (i.e. U-Boot) doesn't need to support HSM extension,
as it doesn't need to boot all the harts. The operating system should be
capable enough to bring up all other non-booting harts using HSM extension.
Required Toolchain
------------------

View File

@@ -7,34 +7,9 @@ environment. In the context of OpenSBI, U-Boot can be specified as a payload to
the OpenSBI firmware, becoming the boot stage following the OpenSBI firmware
execution.
The current stable upstream code of U-Boot does not yet include all patches
necessary to fully support OpenSBI. To use U-Boot as an OpenSBI payload, the
following out-of-tree patch series must be applied to the upstream U-Boot source
code:
HiFive Unleashed support for U-Boot
https://lists.denx.de/pipermail/u-boot/2019-February/358058.html
This patch series enables a single CPU to execute U-Boot. As a result, the next
stage boot code such as a Linux kernel can also only execute on a single CPU.
U-Boot SMP support for RISC-V can be enabled with the following additional
patches:
https://lists.denx.de/pipermail/u-boot/2019-February/358393.html
Building and Generating U-Boot images
=====================================
Please refer to the U-Boot build documentation for detailed instructions on
how to build U-Boot images.
how to build U-Boot image and boot high level operating systems from U-Boot
prompt.
Once U-Boot images are built, the Linux kernel image needs to be converted
into a format that U-Boot understands:
```
<uboot-dir>/tools/mkimage -A riscv -O linux -T kernel -C none -a 0x80200000 -e 0x80200000 -n Linux -d \
<linux_build_directory>arch/riscv/boot/Image \
<linux_build_directory>/arch/riscv/boot/uImage
```
Copy the uImage to your tftpboot server path if network boot is required.

View File

@@ -13,7 +13,7 @@ The FPGA SoC currently contains the following peripherals:
- Bootrom containing zero stage bootloader and device tree.
To build platform specific library and firmwares, provide the
*PLATFORM=ariane-fpga* parameter to the top level `make` command.
*PLATFORM=fpga/ariane* parameter to the top level `make` command.
Platform Options
----------------
@@ -26,7 +26,7 @@ Building Ariane FPGA Platform
**Linux Kernel Payload**
```
make PLATFORM=ariane-fpga FW_PAYLOAD_PATH=<linux_build_directory>/arch/riscv/boot/Image
make PLATFORM=fpga/ariane FW_PAYLOAD_PATH=<linux_build_directory>/arch/riscv/boot/Image
```
Booting Ariane FPGA Platform

View File

@@ -0,0 +1,33 @@
OpenPiton FPGA SoC Platform
========================
OpenPiton is the world's first open source, general purpose, multithreaded
manycore processor. It is a tiled manycore framework scalable from one to
1/2 billion cores. Currently, OpenPiton supports the 64bit Ariane RISC-V
processor from ETH Zurich. To this end, Ariane has been equipped with a
different L1 cache subsystem that follows a write-through protocol and that has
support for cache invalidations and atomics.
To build platform specific library and firmwares, provide the
*PLATFORM=fpga/openpiton* parameter to the top level `make` command.
Platform Options
----------------
The *OpenPiton* platform does not have any platform-specific options.
Building Ariane FPGA Platform
-----------------------------
**Linux Kernel Payload**
```
make PLATFORM=fpga/openpiton FW_PAYLOAD_PATH=<linux_build_directory>/arch/riscv/boot/Image
```
Booting Ariane FPGA Platform
----------------------------
**Linux Kernel Payload**
As Linux kernel image is embedded in the OpenSBI firmware binary, Ariane will
directly boot into Linux directly after powered on.

View File

@@ -25,6 +25,9 @@ OpenSBI currently supports the following virtual and hardware platforms:
* **Spike**: Platform support for the Spike emulator.
* **OpenPiton FPGA SoC**: Platform support OpenPiton research platform based on
ariane core.
The code for these supported platforms can be used as example to implement
support for other platforms. The *platform/template* directory also provides
template files for implementing support for a new platform. The *object.mk*,
@@ -33,7 +36,8 @@ facilitate the implementation.
[qemu_virt.md]: qemu_virt.md
[sifive_fu540.md]: sifive_fu540.md
[ariane-fpga.md]: ariane-fpga.md
[fpga-ariane.md]: fpga-ariane.md
[andes_ae350.md]: andes-ae350.md
[thead-c910.md]: thead-c910.md
[spike.md]: spike.md
[fpga_openpiton.md]: fpga_openpiton.md

View File

@@ -13,16 +13,8 @@ To build platform specific library and firmwares, provide the
Platform Options
----------------
As hart0 in the FU540 doesn't have an MMU, only harts 1-4 boot by default.
A hart mask i.e. *FU540_ENABLED_HART_MASK* compile time option is provided
to select any other hart for booting. Please keep in mind that this is not
a generic option and it can only be specified for FU540 platform in the
following way:
```
make PLATFORM=sifive/fu540 FW_PAYLOAD_PATH=Image FU540_ENABLED_HART_MASK=0x02
```
This will let the board boot only hart1 instead of default 1-4.
The *SiFive FU540 SoC* platform does not have any platform-specific
options.
Building SiFive Fu540 Platform
------------------------------

View File

@@ -351,6 +351,7 @@ _start_warm:
csrw CSR_MIE, zero
csrw CSR_MIP, zero
/* Find HART count and HART stack size */
la a4, platform
#if __riscv_xlen == 64
lwu s7, SBI_PLATFORM_HART_COUNT_OFFSET(a4)
@@ -359,12 +360,29 @@ _start_warm:
lw s7, SBI_PLATFORM_HART_COUNT_OFFSET(a4)
lw s8, SBI_PLATFORM_HART_STACK_SIZE_OFFSET(a4)
#endif
REG_L s9, SBI_PLATFORM_HART_INDEX2ID_OFFSET(a4)
/* HART ID should be within expected limit */
/* Find HART id */
csrr s6, CSR_MHARTID
bge s6, s7, _start_hang
/* find the scratch space for this hart */
/* Find HART index */
beqz s9, 3f
li a4, 0
1:
#if __riscv_xlen == 64
lwu a5, (s9)
#else
lw a5, (s9)
#endif
beq a5, s6, 2f
add s9, s9, 4
add a4, a4, 1
blt a4, s7, 1b
li a4, -1
2: add s6, a4, zero
3: bge s6, s7, _start_hang
/* Find the scratch space based on HART index */
la tp, _fw_end
mul a5, s7, s8
add tp, tp, a5
@@ -409,35 +427,27 @@ _link_end:
.align 3
.globl _hartid_to_scratch
_hartid_to_scratch:
add sp, sp, -(3 * __SIZEOF_POINTER__)
REG_S s0, (sp)
REG_S s1, (__SIZEOF_POINTER__)(sp)
REG_S s2, (__SIZEOF_POINTER__ * 2)(sp)
/*
* a0 -> HART ID (passed by caller)
* s0 -> HART Stack Size
* s1 -> HART Stack End
* s2 -> Temporary
* a1 -> HART Index (passed by caller)
* t0 -> HART Stack Size
* t1 -> HART Stack End
* t2 -> Temporary
*/
la s2, platform
la t2, platform
#if __riscv_xlen == 64
lwu s0, SBI_PLATFORM_HART_STACK_SIZE_OFFSET(s2)
lwu s2, SBI_PLATFORM_HART_COUNT_OFFSET(s2)
lwu t0, SBI_PLATFORM_HART_STACK_SIZE_OFFSET(t2)
lwu t2, SBI_PLATFORM_HART_COUNT_OFFSET(t2)
#else
lw s0, SBI_PLATFORM_HART_STACK_SIZE_OFFSET(s2)
lw s2, SBI_PLATFORM_HART_COUNT_OFFSET(s2)
lw t0, SBI_PLATFORM_HART_STACK_SIZE_OFFSET(t2)
lw t2, SBI_PLATFORM_HART_COUNT_OFFSET(t2)
#endif
mul s2, s2, s0
la s1, _fw_end
add s1, s1, s2
mul s2, s0, a0
sub s1, s1, s2
li s2, SBI_SCRATCH_SIZE
sub a0, s1, s2
REG_L s0, (sp)
REG_L s1, (__SIZEOF_POINTER__)(sp)
REG_L s2, (__SIZEOF_POINTER__ * 2)(sp)
add sp, sp, (3 * __SIZEOF_POINTER__)
sub t2, t2, a1
mul t2, t2, t0
la t1, _fw_end
add t1, t1, t2
li t2, SBI_SCRATCH_SIZE
sub a0, t1, t2
ret
.section .entry, "ax", %progbits
@@ -546,7 +556,6 @@ _skip_mstatush_save:
/* Call C routine */
add a0, sp, zero
csrr a1, CSR_MSCRATCH
call sbi_trap_handler
/* Restore all general regisers except SP and T0 */

View File

@@ -28,9 +28,9 @@
#error "Unexpected __riscv_xlen"
#endif
#define PAGE_SHIFT (12)
#define PAGE_SIZE (_AC(1, UL) << PAGE_SHIFT)
#define PAGE_MASK (~(PAGE_SIZE - 1))
#define PAGE_SHIFT (12)
#define PAGE_SIZE (_AC(1, UL) << PAGE_SHIFT)
#define PAGE_MASK (~(PAGE_SIZE - 1))
#define REG_L __REG_SEL(ld, lw)
#define REG_S __REG_SEL(sd, sw)
@@ -38,7 +38,6 @@
#define LGREG __REG_SEL(3, 2)
#if __SIZEOF_POINTER__ == 8
#define BITS_PER_LONG 64
#ifdef __ASSEMBLY__
#define RISCV_PTR .dword
#define RISCV_SZPTR 8
@@ -49,7 +48,6 @@
#define RISCV_LGPTR "3"
#endif
#elif __SIZEOF_POINTER__ == 4
#define BITS_PER_LONG 32
#ifdef __ASSEMBLY__
#define RISCV_PTR .word
#define RISCV_SZPTR 4
@@ -159,6 +157,8 @@ void csr_write_num(int csr_num, unsigned long val);
__asm__ __volatile__("wfi" ::: "memory"); \
} while (0)
/* Get current HART id */
#define current_hartid() ((unsigned int)csr_read(CSR_MHARTID))
/* determine CPU extension, return non-zero support */
int misa_extension_imp(char ext);
@@ -191,7 +191,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 *log2len_out);
unsigned long *size);
#endif /* !__ASSEMBLY__ */

View File

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

View File

@@ -25,6 +25,7 @@
#define MSTATUS_MPP (_UL(3) << MSTATUS_MPP_SHIFT)
#define MSTATUS_FS _UL(0x00006000)
#define MSTATUS_XS _UL(0x00018000)
#define MSTATUS_VS _UL(0x01800000)
#define MSTATUS_MPRV _UL(0x00020000)
#define MSTATUS_SUM _UL(0x00040000)
#define MSTATUS_MXR _UL(0x00080000)
@@ -53,6 +54,7 @@
#define SSTATUS_SPP MSTATUS_SPP
#define SSTATUS_FS MSTATUS_FS
#define SSTATUS_XS MSTATUS_XS
#define SSTATUS_VS MSTATUS_VS
#define SSTATUS_SUM MSTATUS_SUM
#define SSTATUS_MXR MSTATUS_MXR
#define SSTATUS32_SD MSTATUS32_SD

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

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

View File

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

View File

@@ -1,19 +0,0 @@
/*
* SPDX-License-Identifier: BSD-2-Clause
*
* Copyright (c) 2019 Western Digital Corporation or its affiliates.
*
* Authors:
* Anup Patel <anup.patel@wdc.com>
*/
#ifndef __SBI_BITS_H__
#define __SBI_BITS_H__
#define EXTRACT_FIELD(val, which) (((val) & (which)) / ((which) & ~((which)-1)))
#define INSERT_FIELD(val, which, fieldval) \
(((val) & ~(which)) | ((fieldval) * ((which) & ~((which)-1))))
#define BIT_MASK(nr) (1UL << ((nr) % BITS_PER_LONG))
#define BIT_WORD(nr) ((nr) / BITS_PER_LONG)
#endif

View File

@@ -30,10 +30,9 @@ int __printf(3, 4) sbi_snprintf(char *out, u32 out_sz, const char *format, ...);
int __printf(1, 2) sbi_printf(const char *format, ...);
struct sbi_scratch;
int __printf(1, 2) sbi_dprintf(const char *format, ...);
int __printf(2, 3) sbi_dprintf(struct sbi_scratch *scratch,
const char *format, ...);
struct sbi_scratch;
int sbi_console_init(struct sbi_scratch *scratch);

View File

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

View File

@@ -19,16 +19,13 @@
struct sbi_trap_regs;
struct sbi_trap_info;
struct sbi_scratch;
struct sbi_ecall_extension {
struct sbi_dlist head;
unsigned long extid_start;
unsigned long extid_end;
int (* probe)(struct sbi_scratch *scratch,
unsigned long extid, unsigned long *out_val);
int (* handle)(struct sbi_scratch *scratch,
unsigned long extid, unsigned long funcid,
int (* probe)(unsigned long extid, unsigned long *out_val);
int (* handle)(unsigned long extid, unsigned long funcid,
unsigned long *args, unsigned long *out_val,
struct sbi_trap_info *out_trap);
};
@@ -39,19 +36,23 @@ extern struct sbi_ecall_extension ecall_time;
extern struct sbi_ecall_extension ecall_rfence;
extern struct sbi_ecall_extension ecall_ipi;
extern struct sbi_ecall_extension ecall_vendor;
extern struct sbi_ecall_extension ecall_hsm;
u16 sbi_ecall_version_major(void);
u16 sbi_ecall_version_minor(void);
unsigned long sbi_ecall_get_impid(void);
void sbi_ecall_set_impid(unsigned long impid);
struct sbi_ecall_extension *sbi_ecall_find_extension(unsigned long extid);
int sbi_ecall_register_extension(struct sbi_ecall_extension *ext);
void sbi_ecall_unregister_extension(struct sbi_ecall_extension *ext);
int sbi_ecall_handler(u32 hartid, ulong mcause, struct sbi_trap_regs *regs,
struct sbi_scratch *scratch);
int sbi_ecall_handler(struct sbi_trap_regs *regs);
int sbi_ecall_init(void);

View File

@@ -26,15 +26,16 @@
#define SBI_EXT_TIME 0x54494D45
#define SBI_EXT_IPI 0x735049
#define SBI_EXT_RFENCE 0x52464E43
#define SBI_EXT_HSM 0x48534D
/* SBI function IDs for BASE extension*/
#define SBI_EXT_BASE_GET_SPEC_VERSION 0x0
#define SBI_EXT_BASE_GET_IMP_ID 0x1
#define SBI_EXT_BASE_GET_IMP_VERSION 0x2
#define SBI_EXT_BASE_PROBE_EXT 0x3
#define SBI_EXT_BASE_GET_MVENDORID 0x4
#define SBI_EXT_BASE_GET_MARCHID 0x5
#define SBI_EXT_BASE_GET_MIMPID 0x6
#define SBI_EXT_BASE_GET_IMP_VERSION 0x2
#define SBI_EXT_BASE_PROBE_EXT 0x3
#define SBI_EXT_BASE_GET_MVENDORID 0x4
#define SBI_EXT_BASE_GET_MARCHID 0x5
#define SBI_EXT_BASE_GET_MIMPID 0x6
/* SBI function IDs for TIME extension*/
#define SBI_EXT_TIME_SET_TIMER 0x0
@@ -43,7 +44,7 @@
#define SBI_EXT_IPI_SEND_IPI 0x0
/* SBI function IDs for RFENCE extension*/
#define SBI_EXT_RFENCE_REMOTE_FENCE_I 0x0
#define SBI_EXT_RFENCE_REMOTE_FENCE_I 0x0
#define SBI_EXT_RFENCE_REMOTE_SFENCE_VMA 0x1
#define SBI_EXT_RFENCE_REMOTE_SFENCE_VMA_ASID 0x2
#define SBI_EXT_RFENCE_REMOTE_HFENCE_GVMA 0x3
@@ -51,11 +52,21 @@
#define SBI_EXT_RFENCE_REMOTE_HFENCE_VVMA 0x5
#define SBI_EXT_RFENCE_REMOTE_HFENCE_VVMA_ASID 0x6
#define SBI_SPEC_VERSION_MAJOR_OFFSET 24
#define SBI_SPEC_VERSION_MAJOR_MASK 0x7f
#define SBI_SPEC_VERSION_MINOR_MASK 0xffffff
#define SBI_EXT_VENDOR_START 0x09000000
#define SBI_EXT_VENDOR_END 0x09FFFFFF
/* SBI function IDs for HSM extension */
#define SBI_EXT_HSM_HART_START 0x0
#define SBI_EXT_HSM_HART_STOP 0x1
#define SBI_EXT_HSM_HART_GET_STATUS 0x2
#define SBI_HSM_HART_STATUS_STARTED 0x0
#define SBI_HSM_HART_STATUS_STOPPED 0x1
#define SBI_HSM_HART_STATUS_START_PENDING 0x2
#define SBI_HSM_HART_STATUS_STOP_PENDING 0x3
#define SBI_SPEC_VERSION_MAJOR_OFFSET 24
#define SBI_SPEC_VERSION_MAJOR_MASK 0x7f
#define SBI_SPEC_VERSION_MINOR_MASK 0xffffff
#define SBI_EXT_VENDOR_START 0x09000000
#define SBI_EXT_VENDOR_END 0x09FFFFFF
/* clang-format on */
#endif

View File

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

View File

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

View File

@@ -16,12 +16,16 @@ struct sbi_scratch;
int sbi_hart_init(struct sbi_scratch *scratch, u32 hartid, bool cold_boot);
void *sbi_hart_get_trap_info(struct sbi_scratch *scratch);
void sbi_hart_set_trap_info(struct sbi_scratch *scratch, void *data);
extern void (*sbi_hart_unpriv_trap)(void);
static inline ulong sbi_hart_unpriv_trap_addr(void)
{
return (ulong)sbi_hart_unpriv_trap;
}
void sbi_hart_delegation_dump(struct sbi_scratch *scratch);
void sbi_hart_pmp_dump(struct sbi_scratch *scratch);
int sbi_hart_pmp_check_addr(struct sbi_scratch *scratch, unsigned long daddr,
unsigned long attr);
void __attribute__((noreturn)) sbi_hart_hang(void);
@@ -30,19 +34,4 @@ sbi_hart_switch_mode(unsigned long arg0, unsigned long arg1,
unsigned long next_addr, unsigned long next_mode,
bool next_virt);
void sbi_hart_mark_available(u32 hartid);
ulong sbi_hart_available_mask(void);
void sbi_hart_unmark_available(u32 hartid);
struct sbi_scratch *sbi_hart_id_to_scratch(struct sbi_scratch *scratch,
u32 hartid);
void sbi_hart_wait_for_coldboot(struct sbi_scratch *scratch, u32 hartid);
void sbi_hart_wake_coldboot_harts(struct sbi_scratch *scratch, u32 hartid);
u32 sbi_current_hartid(void);
#endif

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

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

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

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

View File

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

View File

@@ -25,41 +25,43 @@ struct sbi_ipi_event_ops {
/** Name of the IPI event operations */
char name[32];
/** Update callback to save/enqueue data for remote HART
* Note: This is an optional callback and it is called just before
* triggering IPI to remote HART.
/**
* Update callback to save/enqueue data for remote HART
* Note: This is an optional callback and it is called just before
* triggering IPI to remote HART.
*/
int (* update)(struct sbi_scratch *scratch,
struct sbi_scratch *remote_scratch,
u32 remote_hartid, void *data);
/** Sync callback to wait for remote HART
* Note: This is an optional callback and it is called just after
* triggering IPI to remote HART.
/**
* Sync callback to wait for remote HART
* Note: This is an optional callback and it is called just after
* triggering IPI to remote HART.
*/
void (* sync)(struct sbi_scratch *scratch);
/** Process callback to handle IPI event
* Note: This is a mandatory callback and it is called on the
* remote HART after IPI is triggered.
/**
* Process callback to handle IPI event
* Note: This is a mandatory callback and it is called on the
* remote HART after IPI is triggered.
*/
void (* process)(struct sbi_scratch *scratch);
};
int sbi_ipi_send_many(struct sbi_scratch *scratch, ulong hmask,
ulong hbase, u32 event, void *data);
int sbi_ipi_send_many(ulong hmask, ulong hbase, u32 event, void *data);
int sbi_ipi_event_create(const struct sbi_ipi_event_ops *ops);
void sbi_ipi_event_destroy(u32 event);
int sbi_ipi_send_smode(struct sbi_scratch *scratch, ulong hmask, ulong hbase);
int sbi_ipi_send_smode(ulong hmask, ulong hbase);
void sbi_ipi_clear_smode(struct sbi_scratch *scratch);
void sbi_ipi_clear_smode(void);
int sbi_ipi_send_halt(struct sbi_scratch *scratch, ulong hmask, ulong hbase);
int sbi_ipi_send_halt(ulong hmask, ulong hbase);
void sbi_ipi_process(struct sbi_scratch *scratch);
void sbi_ipi_process(void);
int sbi_ipi_init(struct sbi_scratch *scratch, bool cold_boot);

View File

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

View File

@@ -10,9 +10,10 @@
#ifndef __SBI_PLATFORM_H__
#define __SBI_PLATFORM_H__
/** OpenSBI 32-bit platform version with:
* 1. upper 16-bits as major number
* 2. lower 16-bits as minor number
/**
* OpenSBI 32-bit platform version with:
* 1. upper 16-bits as major number
* 2. lower 16-bits as minor number
*/
#define SBI_PLATFORM_VERSION(Major, Minor) ((Major << 16) | Minor)
@@ -28,12 +29,12 @@
#define SBI_PLATFORM_HART_COUNT_OFFSET (0x50)
/** Offset of hart_stack_size in struct sbi_platform */
#define SBI_PLATFORM_HART_STACK_SIZE_OFFSET (0x54)
/** Offset of disabled_hart_mask in struct sbi_platform */
#define SBI_PLATFORM_DISABLED_HART_OFFSET (0x58)
/** Offset of platform_ops_addr in struct sbi_platform */
#define SBI_PLATFORM_OPS_OFFSET (0x60)
#define SBI_PLATFORM_OPS_OFFSET (0x58)
/** Offset of firmware_context in struct sbi_platform */
#define SBI_PLATFORM_FIRMWARE_CONTEXT_OFFSET (0x60 + __SIZEOF_POINTER__)
#define SBI_PLATFORM_FIRMWARE_CONTEXT_OFFSET (0x58 + __SIZEOF_POINTER__)
/** Offset of hart_index2id in struct sbi_platform */
#define SBI_PLATFORM_HART_INDEX2ID_OFFSET (0x58 + (__SIZEOF_POINTER__ * 2))
#define SBI_PLATFORM_TLB_RANGE_FLUSH_LIMIT_DEFAULT (1UL << 12)
@@ -59,6 +60,8 @@ enum sbi_platform_features {
SBI_PLATFORM_HAS_MCOUNTEREN = (1 << 4),
/** Platform has fault delegation support */
SBI_PLATFORM_HAS_MFAULTS_DELEGATION = (1 << 5),
/** Platform has custom secondary hart booting support */
SBI_PLATFORM_HAS_HART_SECONDARY_BOOT = (1 << 6),
};
/** Default feature set for a platform */
@@ -79,12 +82,14 @@ struct sbi_platform_operations {
/** Platform final exit */
void (*final_exit)(void);
/** For platforms that do not implement misa, non-standard
/**
* For platforms that do not implement misa, non-standard
* methods are needed to determine cpu extension.
*/
int (*misa_check_extension)(char ext);
/** For platforms that do not implement misa, non-standard
/**
* For platforms that do not implement misa, non-standard
* methods are needed to get MXL field of misa.
*/
int (*misa_get_xlen)(void);
@@ -133,6 +138,14 @@ struct sbi_platform_operations {
/** Exit platform timer for current HART */
void (*timer_exit)(void);
/** Bringup the given hart */
int (*hart_start)(u32 hartid, ulong saddr);
/**
* Stop the current hart from running. This call doesn't expect to
* return if success.
*/
int (*hart_stop)(void);
/** Reboot the platform */
int (*system_reboot)(u32 type);
/** Shutdown or poweroff the platform */
@@ -147,6 +160,9 @@ struct sbi_platform_operations {
struct sbi_trap_info *out_trap);
} __packed;
/** Platform default per-HART stack size for exception/interrupt handling */
#define SBI_PLATFORM_DEFAULT_HART_STACK_SIZE 8192
/** Representation of a platform */
struct sbi_platform {
/**
@@ -169,12 +185,26 @@ struct sbi_platform {
u32 hart_count;
/** Per-HART stack size for exception/interrupt handling */
u32 hart_stack_size;
/** Mask representing the set of disabled HARTs */
u64 disabled_hart_mask;
/** Pointer to sbi platform operations */
unsigned long platform_ops_addr;
/** Pointer to system firmware specific context */
unsigned long firmware_context;
/**
* HART index to HART id table
*
* For used HART index <abc>:
* hart_index2id[<abc>] = some HART id
* For unused HART index <abc>:
* hart_index2id[<abc>] = -1U
*
* If hart_index2id == NULL then we assume identity mapping
* hart_index2id[<abc>] = <abc>
*
* We have only two restrictions:
* 1. HART index < sbi_platform hart_count
* 2. HART id < SBI_HARTMASK_MAX_BITS
*/
const u32 *hart_index2id;
} __packed;
/** Get pointer to sbi_platform for sbi_scratch pointer */
@@ -204,6 +234,9 @@ struct sbi_platform {
/** Check whether the platform supports fault delegation */
#define sbi_platform_has_mfaults_delegation(__p) \
((__p)->features & SBI_PLATFORM_HAS_MFAULTS_DELEGATION)
/** Check whether the platform supports custom secondary hart booting support */
#define sbi_platform_has_hart_secondary_boot(__p) \
((__p)->features & SBI_PLATFORM_HAS_HART_SECONDARY_BOOT)
/**
* Get name of the platform
@@ -219,22 +252,6 @@ static inline const char *sbi_platform_name(const struct sbi_platform *plat)
return "Unknown";
}
/**
* Check whether the given HART is disabled
*
* @param plat pointer to struct sbi_platform
* @param hartid HART ID
*
* @return TRUE if HART is disabled and FALSE otherwise
*/
static inline bool sbi_platform_hart_disabled(const struct sbi_platform *plat,
u32 hartid)
{
if (plat && (plat->disabled_hart_mask & (1 << hartid)))
return TRUE;
return FALSE;
}
/**
* Get platform specific tlb range flush maximum value. Any request with size
* higher than this is upgraded to a full flush.
@@ -279,6 +296,83 @@ static inline u32 sbi_platform_hart_stack_size(const struct sbi_platform *plat)
return 0;
}
/**
* Get HART index for the given HART
*
* @param plat pointer to struct sbi_platform
* @param hartid HART ID
*
* @return 0 <= value < hart_count for valid HART otherwise -1U
*/
static inline u32 sbi_platform_hart_index(const struct sbi_platform *plat,
u32 hartid)
{
u32 i;
if (!plat)
return -1U;
if (plat->hart_index2id) {
for (i = 0; i < plat->hart_count; i++) {
if (plat->hart_index2id[i] == hartid)
return i;
}
return -1U;
}
return hartid;
}
/**
* Check whether given HART is invalid
*
* @param plat pointer to struct sbi_platform
* @param hartid HART ID
*
* @return TRUE if HART is invalid and FALSE otherwise
*/
static inline bool sbi_platform_hart_invalid(const struct sbi_platform *plat,
u32 hartid)
{
if (!plat)
return TRUE;
if (plat->hart_count <= sbi_platform_hart_index(plat, hartid))
return TRUE;
return FALSE;
}
/**
* Bringup a given hart from previous stage. Platform should implement this
* operation if they support a custom mechanism to start a hart. Otherwise,
* a generic WFI based approach will be used to start/stop a hart in OpenSBI.
*
* @param plat pointer to struct sbi_platform
* @param hartid HART id
* @param saddr M-mode start physical address for the HART
*
* @return 0 if sucessful and negative error code on failure
*/
static inline int sbi_platform_hart_start(const struct sbi_platform *plat,
u32 hartid, ulong saddr)
{
if (plat && sbi_platform_ops(plat)->hart_start)
return sbi_platform_ops(plat)->hart_start(hartid, saddr);
return SBI_ENOTSUPP;
}
/**
* Stop the current hart in OpenSBI.
*
* @param plat pointer to struct sbi_platform
*
* @return Negative error code on failure. It doesn't return on success.
*/
static inline int sbi_platform_hart_stop(const struct sbi_platform *plat)
{
if (plat && sbi_platform_ops(plat)->hart_stop)
return sbi_platform_ops(plat)->hart_stop();
return SBI_ENOTSUPP;
}
/**
* Early initialization for current HART
*

View File

@@ -36,8 +36,8 @@
#define SBI_SCRATCH_OPTIONS_OFFSET (9 * __SIZEOF_POINTER__)
/** Offset of extra space in sbi_scratch */
#define SBI_SCRATCH_EXTRA_SPACE_OFFSET (10 * __SIZEOF_POINTER__)
/** Maximum size of sbi_scratch */
#define SBI_SCRATCH_SIZE (64 * __SIZEOF_POINTER__)
/** Maximum size of sbi_scratch (4KB) */
#define SBI_SCRATCH_SIZE (0x1000)
/* clang-format on */
@@ -85,7 +85,11 @@ enum sbi_scratch_options {
#define sbi_scratch_thishart_arg1_ptr() \
((void *)(sbi_scratch_thishart_ptr()->next_arg1))
/** Allocate from extra space in sbi_scratch
/** Initialize scatch table and allocator */
int sbi_scratch_init(struct sbi_scratch *scratch);
/**
* Allocate from extra space in sbi_scratch
*
* @return zero on failure and non-zero (>= SBI_SCRATCH_EXTRA_SPACE_OFFSET)
* on success
@@ -102,6 +106,19 @@ void sbi_scratch_free_offset(unsigned long offset);
#define sbi_scratch_thishart_offset_ptr(offset) \
((void *)sbi_scratch_thishart_ptr() + (offset))
/** HART id to scratch table */
extern struct sbi_scratch *hartid_to_scratch_table[];
/** Get sbi_scratch from HART id */
#define sbi_hartid_to_scratch(__hartid) \
hartid_to_scratch_table[__hartid]
/** Last HART id having a sbi_scratch pointer */
extern u32 last_hartid_having_scratch;
/** Get last HART id having a sbi_scratch pointer */
#define sbi_scratch_last_hartid() last_hartid_having_scratch
#endif
#endif

View File

@@ -12,18 +12,8 @@
#include <sbi/sbi_types.h>
struct sbi_scratch;
void __noreturn sbi_system_reboot(u32 type);
int sbi_system_early_init(struct sbi_scratch *scratch, bool cold_boot);
int sbi_system_final_init(struct sbi_scratch *scratch, bool cold_boot);
void sbi_system_early_exit(struct sbi_scratch *scratch);
void sbi_system_final_exit(struct sbi_scratch *scratch);
void __noreturn sbi_system_reboot(struct sbi_scratch *scratch, u32 type);
void __noreturn sbi_system_shutdown(struct sbi_scratch *scratch, u32 type);
void __noreturn sbi_system_shutdown(u32 type);
#endif

View File

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

View File

@@ -12,6 +12,7 @@
#define __SBI_TLB_H__
#include <sbi/sbi_types.h>
#include <sbi/sbi_hartmask.h>
/* clang-format off */
@@ -38,13 +39,21 @@ struct sbi_tlb_info {
unsigned long size;
unsigned long asid;
unsigned long type;
unsigned long shart_mask;
struct sbi_hartmask smask;
};
#define SBI_TLB_INFO_SIZE sizeof(struct sbi_tlb_info)
#define SBI_TLB_INFO_INIT(__ptr, __start, __size, __asid, __type, __src_hart) \
do { \
(__ptr)->start = (__start); \
(__ptr)->size = (__size); \
(__ptr)->asid = (__asid); \
(__ptr)->type = (__type); \
SBI_HARTMASK_INIT_EXCEPT(&(__ptr)->smask, (__src_hart)); \
} while (0)
int sbi_tlb_request(struct sbi_scratch *scratch, ulong hmask,
ulong hbase, struct sbi_tlb_info *tinfo);
#define SBI_TLB_INFO_SIZE sizeof(struct sbi_tlb_info)
int sbi_tlb_request(ulong hmask, ulong hbase, struct sbi_tlb_info *tinfo);
int sbi_tlb_init(struct sbi_scratch *scratch, bool cold_boot);

View File

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

View File

@@ -56,6 +56,8 @@ typedef unsigned long physical_size_t;
#define TRUE 1
#define FALSE 0
#define true TRUE
#define false FALSE
#define NULL ((void *)0)
@@ -89,7 +91,8 @@ typedef unsigned long physical_size_t;
/* clang-format on */
#else
/* OPENSBI_EXTERNAL_SBI_TYPES could be defined in CFLAGS for using the
/*
* OPENSBI_EXTERNAL_SBI_TYPES could be defined in CFLAGS for using the
* external definitions of data types and common macros.
* OPENSBI_EXTERNAL_SBI_TYPES is the file name to external header file,
* the external build system should address the additional include

View File

@@ -17,12 +17,10 @@ struct sbi_trap_info;
#define DECLARE_UNPRIVILEGED_LOAD_FUNCTION(type) \
type sbi_load_##type(const type *addr, \
struct sbi_scratch *scratch, \
struct sbi_trap_info *trap);
#define DECLARE_UNPRIVILEGED_STORE_FUNCTION(type) \
void sbi_store_##type(type *addr, type val, \
struct sbi_scratch *scratch, \
struct sbi_trap_info *trap);
DECLARE_UNPRIVILEGED_LOAD_FUNCTION(u8)
@@ -38,7 +36,6 @@ DECLARE_UNPRIVILEGED_LOAD_FUNCTION(u64)
DECLARE_UNPRIVILEGED_STORE_FUNCTION(u64)
DECLARE_UNPRIVILEGED_LOAD_FUNCTION(ulong)
ulong sbi_get_insn(ulong mepc, struct sbi_scratch *scratch,
struct sbi_trap_info *trap);
ulong sbi_get_insn(ulong mepc, struct sbi_trap_info *trap);
#endif

View File

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

View File

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

View File

@@ -0,0 +1,33 @@
// SPDX-License-Identifier: BSD-2-Clause
/*
* fdt_helper.h - Flat Device Tree parsing helper routines
* Implement helper routines to parse FDT nodes on top of
* libfdt for OpenSBI usage
*
* Copyright (C) 2020 Bin Meng <bmeng.cn@gmail.com>
*/
#ifndef __FDT_HELPER_H__
#define __FDT_HELPER_H__
struct platform_uart_data {
unsigned long addr;
unsigned long freq;
unsigned long baud;
};
struct platform_plic_data {
unsigned long addr;
unsigned long num_src;
};
int fdt_parse_uart8250(void *fdt, struct platform_uart_data *uart,
const char *compatible);
int fdt_parse_plic(void *fdt, struct platform_plic_data *plic,
const char *compatible);
int fdt_parse_clint(void *fdt, unsigned long *clint_addr,
const char *compatible);
#endif /* __FDT_HELPER_H__ */

View File

@@ -12,8 +12,6 @@
#include <sbi/sbi_types.h>
void plic_fdt_fixup(void *fdt, const char *compat);
int plic_warm_irqchip_init(u32 target_hart, int m_cntx_id, int s_cntx_id);
int plic_cold_irqchip_init(unsigned long base, u32 num_sources, u32 hart_count);

View File

@@ -12,24 +12,29 @@ libsbi-objs-y += riscv_atomic.o
libsbi-objs-y += riscv_hardfp.o
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_ecall.o
libsbi-objs-y += sbi_ecall_base.o
libsbi-objs-y += sbi_ecall_hsm.o
libsbi-objs-y += sbi_ecall_legacy.o
libsbi-objs-y += sbi_ecall_replace.o
libsbi-objs-y += sbi_ecall_vendor.o
libsbi-objs-y += sbi_emulate_csr.o
libsbi-objs-y += sbi_fifo.o
libsbi-objs-y += sbi_hfence.o
libsbi-objs-y += sbi_hart.o
libsbi-objs-y += sbi_hfence.o
libsbi-objs-y += sbi_hsm.o
libsbi-objs-y += sbi_illegal_insn.o
libsbi-objs-y += sbi_init.o
libsbi-objs-y += sbi_ipi.o
libsbi-objs-y += sbi_misaligned_ldst.o
libsbi-objs-y += sbi_scratch.o
libsbi-objs-y += sbi_string.o
libsbi-objs-y += sbi_system.o
libsbi-objs-y += sbi_timer.o
libsbi-objs-y += sbi_tlb.o
libsbi-objs-y += sbi_trap.o
libsbi-objs-y += sbi_string.o
libsbi-objs-y += sbi_unpriv.o
libsbi-objs-y += sbi_unpriv_trap.o

View File

@@ -207,7 +207,7 @@ int pmp_set(unsigned int n, unsigned long prot, unsigned long addr,
if (n >= PMP_COUNT || log2len > __riscv_xlen || log2len < PMP_SHIFT)
return SBI_EINVAL;
/* calculate PMP register and offset */
/* calculate PMP register and offset */
#if __riscv_xlen == 32
pmpcfg_csr = CSR_PMPCFG0 + (n >> 2);
pmpcfg_shift = (n & 3) << 3;
@@ -249,16 +249,16 @@ int pmp_set(unsigned int n, unsigned long prot, unsigned long addr,
}
int pmp_get(unsigned int n, unsigned long *prot_out, unsigned long *addr_out,
unsigned long *log2len_out)
unsigned long *size)
{
int pmpcfg_csr, pmpcfg_shift, pmpaddr_csr;
unsigned long cfgmask, pmpcfg, prot;
unsigned long t1, addr, log2len;
/* check parameters */
if (n >= PMP_COUNT || !prot_out || !addr_out || !log2len_out)
if (n >= PMP_COUNT || !prot_out || !addr_out || !size)
return SBI_EINVAL;
*prot_out = *addr_out = *log2len_out = 0;
*prot_out = *addr_out = *size = 0;
/* calculate PMP register and offset */
#if __riscv_xlen == 32
@@ -299,7 +299,9 @@ int pmp_get(unsigned int n, unsigned long *prot_out, unsigned long *addr_out,
/* return details */
*prot_out = prot;
*addr_out = addr;
*log2len_out = log2len;
if (log2len < __riscv_xlen)
*size = (1UL << log2len);
return 0;
}

View File

@@ -7,11 +7,10 @@
* Anup Patel <anup.patel@wdc.com>
*/
#include <sbi/sbi_types.h>
#include <sbi/sbi_bitops.h>
#include <sbi/riscv_asm.h>
#include <sbi/riscv_atomic.h>
#include <sbi/riscv_barrier.h>
#include <sbi/sbi_bits.h>
long atomic_read(atomic_t *atom)
{
@@ -50,7 +49,7 @@ long atomic_sub_return(atomic_t *atom, long value)
return ret - value;
}
#define __axchg(ptr, new, size) \
#define __axchg(ptr, new, size) \
({ \
__typeof__(ptr) __ptr = (ptr); \
__typeof__(new) __new = (new); \
@@ -71,12 +70,12 @@ long atomic_sub_return(atomic_t *atom, long value)
: "memory"); \
break; \
default: \
break; \
break; \
} \
__ret; \
})
#define axchg(ptr, x) \
#define axchg(ptr, x) \
({ \
__typeof__(*(ptr)) _x_ = (x); \
(__typeof__(*(ptr))) __axchg((ptr), _x_, sizeof(*(ptr))); \
@@ -91,20 +90,20 @@ long atomic_sub_return(atomic_t *atom, long value)
register unsigned int __rc; \
switch (size) { \
case 4: \
__asm__ __volatile__("0: lr.w %0, %2\n" \
" sc.w.rl %1, %z3, %2\n" \
" bnez %1, 0b\n" \
" fence rw, rw\n" \
__asm__ __volatile__("0: lr.w %0, %2\n" \
" sc.w.rl %1, %z3, %2\n" \
" bnez %1, 0b\n" \
" fence rw, rw\n" \
: "=&r"(__ret), "=&r"(__rc), \
"+A"(*__ptr) \
: "rJ"(__new) \
: "memory"); \
break; \
case 8: \
__asm__ __volatile__("0: lr.d %0, %2\n" \
" sc.d.rl %1, %z3, %2\n" \
" bnez %1, 0b\n" \
" fence rw, rw\n" \
__asm__ __volatile__("0: lr.d %0, %2\n" \
" sc.d.rl %1, %z3, %2\n" \
" bnez %1, 0b\n" \
" fence rw, rw\n" \
: "=&r"(__ret), "=&r"(__rc), \
"+A"(*__ptr) \
: "rJ"(__new) \
@@ -131,11 +130,11 @@ long atomic_sub_return(atomic_t *atom, long value)
register unsigned int __rc; \
switch (size) { \
case 4: \
__asm__ __volatile__("0: lr.w %0, %2\n" \
" bne %0, %z3, 1f\n" \
" sc.w.rl %1, %z4, %2\n" \
" bnez %1, 0b\n" \
" fence rw, rw\n" \
__asm__ __volatile__("0: lr.w %0, %2\n" \
" bne %0, %z3, 1f\n" \
" sc.w.rl %1, %z4, %2\n" \
" bnez %1, 0b\n" \
" fence rw, rw\n" \
"1:\n" \
: "=&r"(__ret), "=&r"(__rc), \
"+A"(*__ptr) \
@@ -143,11 +142,11 @@ long atomic_sub_return(atomic_t *atom, long value)
: "memory"); \
break; \
case 8: \
__asm__ __volatile__("0: lr.d %0, %2\n" \
" bne %0, %z3, 1f\n" \
" sc.d.rl %1, %z4, %2\n" \
" bnez %1, 0b\n" \
" fence rw, rw\n" \
__asm__ __volatile__("0: lr.d %0, %2\n" \
" bne %0, %z3, 1f\n" \
" sc.d.rl %1, %z4, %2\n" \
" bnez %1, 0b\n" \
" fence rw, rw\n" \
"1:\n" \
: "=&r"(__ret), "=&r"(__rc), \
"+A"(*__ptr) \
@@ -168,7 +167,7 @@ long atomic_sub_return(atomic_t *atom, long value)
__cmpxchg((ptr), _o_, _n_, sizeof(*(ptr))); \
})
long arch_atomic_cmpxchg(atomic_t *atom, long oldval, long newval)
long atomic_cmpxchg(atomic_t *atom, long oldval, long newval)
{
#ifdef __riscv_atomic
return __sync_val_compare_and_swap(&atom->counter, oldval, newval);
@@ -177,7 +176,7 @@ long arch_atomic_cmpxchg(atomic_t *atom, long oldval, long newval)
#endif
}
long arch_atomic_xchg(atomic_t *atom, long newval)
long atomic_xchg(atomic_t *atom, long newval)
{
/* Atomically set new value and return old value. */
#ifdef __riscv_atomic
@@ -209,12 +208,12 @@ unsigned long atomic_raw_xchg_ulong(volatile unsigned long *ptr,
#endif
}
#if (BITS_PER_LONG == 64)
#if (__SIZEOF_POINTER__ == 8)
#define __AMO(op) "amo" #op ".d"
#elif (BITS_PER_LONG == 32)
#elif (__SIZEOF_POINTER__ == 4)
#define __AMO(op) "amo" #op ".w"
#else
#error "Unexpected BITS_PER_LONG"
#error "Unexpected __SIZEOF_POINTER__"
#endif
#define __atomic_op_bit_ord(op, mod, nr, addr, ord) \

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

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

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

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

View File

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

View File

@@ -22,6 +22,18 @@ u16 sbi_ecall_version_minor(void)
return SBI_ECALL_VERSION_MINOR;
}
static unsigned long ecall_impid = SBI_OPENSBI_IMPID;
unsigned long sbi_ecall_get_impid(void)
{
return ecall_impid;
}
void sbi_ecall_set_impid(unsigned long impid)
{
ecall_impid = impid;
}
static SBI_LIST_HEAD(ecall_exts_list);
struct sbi_ecall_extension *sbi_ecall_find_extension(unsigned long extid)
@@ -40,11 +52,19 @@ struct sbi_ecall_extension *sbi_ecall_find_extension(unsigned long extid)
int sbi_ecall_register_extension(struct sbi_ecall_extension *ext)
{
struct sbi_ecall_extension *t;
if (!ext || (ext->extid_end < ext->extid_start) || !ext->handle)
return SBI_EINVAL;
if (sbi_ecall_find_extension(ext->extid_start) ||
sbi_ecall_find_extension(ext->extid_end))
return SBI_EINVAL;
sbi_list_for_each_entry(t, &ecall_exts_list, head) {
unsigned long start = t->extid_start;
unsigned long end = t->extid_end;
if (end < ext->extid_start || ext->extid_end < start)
/* no overlap */;
else
return SBI_EINVAL;
}
SBI_INIT_LIST_HEAD(&ext->head);
sbi_list_add_tail(&ext->head, &ecall_exts_list);
@@ -71,8 +91,7 @@ void sbi_ecall_unregister_extension(struct sbi_ecall_extension *ext)
sbi_list_del_init(&ext->head);
}
int sbi_ecall_handler(u32 hartid, ulong mcause, struct sbi_trap_regs *regs,
struct sbi_scratch *scratch)
int sbi_ecall_handler(struct sbi_trap_regs *regs)
{
int ret = 0;
struct sbi_ecall_extension *ext;
@@ -92,7 +111,7 @@ int sbi_ecall_handler(u32 hartid, ulong mcause, struct sbi_trap_regs *regs,
ext = sbi_ecall_find_extension(extension_id);
if (ext && ext->handle) {
ret = ext->handle(scratch, extension_id, func_id,
ret = ext->handle(extension_id, func_id,
args, &out_val, &trap);
if (extension_id >= SBI_EXT_0_1_SET_TIMER &&
extension_id <= SBI_EXT_0_1_SHUTDOWN)
@@ -103,9 +122,10 @@ int sbi_ecall_handler(u32 hartid, ulong mcause, struct sbi_trap_regs *regs,
if (ret == SBI_ETRAP) {
trap.epc = regs->mepc;
sbi_trap_redirect(regs, &trap, scratch);
sbi_trap_redirect(regs, &trap);
} else {
/* This function should return non-zero value only in case of
/*
* This function should return non-zero value only in case of
* fatal error. However, there is no good way to distinguish
* between a fatal and non-fatal errors yet. That's why we treat
* every return value except ETRAP as non-fatal and just return
@@ -136,6 +156,9 @@ int sbi_ecall_init(void)
if (ret)
return ret;
ret = sbi_ecall_register_extension(&ecall_base);
if (ret)
return ret;
ret = sbi_ecall_register_extension(&ecall_hsm);
if (ret)
return ret;
ret = sbi_ecall_register_extension(&ecall_legacy);

View File

@@ -14,9 +14,7 @@
#include <sbi/sbi_version.h>
#include <sbi/riscv_asm.h>
static int sbi_ecall_base_probe(struct sbi_scratch *scratch,
unsigned long extid,
unsigned long *out_val)
static int sbi_ecall_base_probe(unsigned long extid, unsigned long *out_val)
{
struct sbi_ecall_extension *ext;
@@ -27,14 +25,13 @@ static int sbi_ecall_base_probe(struct sbi_scratch *scratch,
}
if (ext->probe)
return ext->probe(scratch, extid, out_val);
return ext->probe(extid, out_val);
*out_val = 1;
return 0;
}
static int sbi_ecall_base_handler(struct sbi_scratch *scratch,
unsigned long extid, unsigned long funcid,
static int sbi_ecall_base_handler(unsigned long extid, unsigned long funcid,
unsigned long *args, unsigned long *out_val,
struct sbi_trap_info *out_trap)
{
@@ -49,7 +46,7 @@ static int sbi_ecall_base_handler(struct sbi_scratch *scratch,
*out_val = *out_val | SBI_ECALL_VERSION_MINOR;
break;
case SBI_EXT_BASE_GET_IMP_ID:
*out_val = SBI_OPENSBI_IMPID;
*out_val = sbi_ecall_get_impid();
break;
case SBI_EXT_BASE_GET_IMP_VERSION:
*out_val = OPENSBI_VERSION;
@@ -64,7 +61,7 @@ static int sbi_ecall_base_handler(struct sbi_scratch *scratch,
*out_val = csr_read(CSR_MIMPID);
break;
case SBI_EXT_BASE_PROBE_EXT:
ret = sbi_ecall_base_probe(scratch, args[0], out_val);
ret = sbi_ecall_base_probe(args[0], out_val);
break;
default:
ret = SBI_ENOTSUPP;

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

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

View File

@@ -8,10 +8,12 @@
* Atish Patra <atish.patra@wdc.com>
*/
#include <sbi/riscv_asm.h>
#include <sbi/sbi_console.h>
#include <sbi/sbi_ecall.h>
#include <sbi/sbi_ecall_interface.h>
#include <sbi/sbi_error.h>
#include <sbi/sbi_hsm.h>
#include <sbi/sbi_ipi.h>
#include <sbi/sbi_system.h>
#include <sbi/sbi_timer.h>
@@ -20,40 +22,38 @@
#include <sbi/sbi_unpriv.h>
#include <sbi/sbi_hart.h>
static int sbi_load_hart_mask_unpriv(struct sbi_scratch *scratch,
ulong *pmask, ulong *hmask,
static int sbi_load_hart_mask_unpriv(ulong *pmask, ulong *hmask,
struct sbi_trap_info *uptrap)
{
ulong mask = 0;
if (pmask) {
mask = sbi_load_ulong(pmask, scratch, uptrap);
mask = sbi_load_ulong(pmask, uptrap);
if (uptrap->cause)
return SBI_ETRAP;
} else {
mask = sbi_hart_available_mask();
sbi_hsm_hart_started_mask(0, &mask);
}
*hmask = mask;
return 0;
}
static int sbi_ecall_legacy_handler(struct sbi_scratch *scratch,
unsigned long extid, unsigned long funcid,
static int sbi_ecall_legacy_handler(unsigned long extid, unsigned long funcid,
unsigned long *args, unsigned long *out_val,
struct sbi_trap_info *out_trap)
{
int ret = 0;
struct sbi_tlb_info tlb_info;
u32 source_hart = sbi_current_hartid();
u32 source_hart = current_hartid();
ulong hmask = 0;
switch (extid) {
case SBI_EXT_0_1_SET_TIMER:
#if __riscv_xlen == 32
sbi_timer_event_start(scratch,
(((u64)args[1] << 32) | (u64)args[0]));
sbi_timer_event_start((((u64)args[1] << 32) | (u64)args[0]));
#else
sbi_timer_event_start(scratch, (u64)args[0]);
sbi_timer_event_start((u64)args[0]);
#endif
break;
case SBI_EXT_0_1_CONSOLE_PUTCHAR:
@@ -63,47 +63,43 @@ static int sbi_ecall_legacy_handler(struct sbi_scratch *scratch,
ret = sbi_getc();
break;
case SBI_EXT_0_1_CLEAR_IPI:
sbi_ipi_clear_smode(scratch);
sbi_ipi_clear_smode();
break;
case SBI_EXT_0_1_SEND_IPI:
ret = sbi_load_hart_mask_unpriv(scratch, (ulong *)args[0],
ret = sbi_load_hart_mask_unpriv((ulong *)args[0],
&hmask, out_trap);
if (ret != SBI_ETRAP)
ret = sbi_ipi_send_smode(scratch, hmask, 0);
ret = sbi_ipi_send_smode(hmask, 0);
break;
case SBI_EXT_0_1_REMOTE_FENCE_I:
tlb_info.start = 0;
tlb_info.size = 0;
tlb_info.type = SBI_ITLB_FLUSH;
tlb_info.shart_mask = 1UL << source_hart;
ret = sbi_load_hart_mask_unpriv(scratch, (ulong *)args[0],
ret = sbi_load_hart_mask_unpriv((ulong *)args[0],
&hmask, out_trap);
if (ret != SBI_ETRAP)
ret = sbi_tlb_request(scratch, hmask, 0, &tlb_info);
if (ret != SBI_ETRAP) {
SBI_TLB_INFO_INIT(&tlb_info, 0, 0, 0,
SBI_ITLB_FLUSH, source_hart);
ret = sbi_tlb_request(hmask, 0, &tlb_info);
}
break;
case SBI_EXT_0_1_REMOTE_SFENCE_VMA:
tlb_info.start = (unsigned long)args[1];
tlb_info.size = (unsigned long)args[2];
tlb_info.type = SBI_TLB_FLUSH_VMA;
tlb_info.shart_mask = 1UL << source_hart;
ret = sbi_load_hart_mask_unpriv(scratch, (ulong *)args[0],
ret = sbi_load_hart_mask_unpriv((ulong *)args[0],
&hmask, out_trap);
if (ret != SBI_ETRAP)
ret = sbi_tlb_request(scratch, hmask, 0, &tlb_info);
if (ret != SBI_ETRAP) {
SBI_TLB_INFO_INIT(&tlb_info, args[1], args[2], 0,
SBI_TLB_FLUSH_VMA, source_hart);
ret = sbi_tlb_request(hmask, 0, &tlb_info);
}
break;
case SBI_EXT_0_1_REMOTE_SFENCE_VMA_ASID:
tlb_info.start = (unsigned long)args[1];
tlb_info.size = (unsigned long)args[2];
tlb_info.asid = (unsigned long)args[3];
tlb_info.type = SBI_TLB_FLUSH_VMA_ASID;
tlb_info.shart_mask = 1UL << source_hart;
ret = sbi_load_hart_mask_unpriv(scratch, (ulong *)args[0],
ret = sbi_load_hart_mask_unpriv((ulong *)args[0],
&hmask, out_trap);
if (ret != SBI_ETRAP)
ret = sbi_tlb_request(scratch, hmask, 0, &tlb_info);
if (ret != SBI_ETRAP) {
SBI_TLB_INFO_INIT(&tlb_info, args[1], args[2], args[3],
SBI_TLB_FLUSH_VMA_ASID, source_hart);
ret = sbi_tlb_request(hmask, 0, &tlb_info);
}
break;
case SBI_EXT_0_1_SHUTDOWN:
sbi_system_shutdown(scratch, 0);
sbi_system_shutdown(0);
break;
default:
ret = SBI_ENOTSUPP;

View File

@@ -8,6 +8,7 @@
* Atish Patra <atish.patra@wdc.com>
*/
#include <sbi/riscv_asm.h>
#include <sbi/sbi_ecall.h>
#include <sbi/sbi_ecall_interface.h>
#include <sbi/sbi_error.h>
@@ -15,10 +16,8 @@
#include <sbi/sbi_ipi.h>
#include <sbi/sbi_timer.h>
#include <sbi/sbi_tlb.h>
#include <sbi/riscv_asm.h>
static int sbi_ecall_time_handler(struct sbi_scratch *scratch,
unsigned long extid, unsigned long funcid,
static int sbi_ecall_time_handler(unsigned long extid, unsigned long funcid,
unsigned long *args, unsigned long *out_val,
struct sbi_trap_info *out_trap)
{
@@ -26,10 +25,9 @@ static int sbi_ecall_time_handler(struct sbi_scratch *scratch,
if (funcid == SBI_EXT_TIME_SET_TIMER) {
#if __riscv_xlen == 32
sbi_timer_event_start(scratch,
(((u64)args[1] << 32) | (u64)args[0]));
sbi_timer_event_start((((u64)args[1] << 32) | (u64)args[0]));
#else
sbi_timer_event_start(scratch, (u64)args[0]);
sbi_timer_event_start((u64)args[0]);
#endif
} else
ret = SBI_ENOTSUPP;
@@ -43,14 +41,13 @@ struct sbi_ecall_extension ecall_time = {
.handle = sbi_ecall_time_handler,
};
static int sbi_ecall_rfence_handler(struct sbi_scratch *scratch,
unsigned long extid, unsigned long funcid,
static int sbi_ecall_rfence_handler(unsigned long extid, unsigned long funcid,
unsigned long *args, unsigned long *out_val,
struct sbi_trap_info *out_trap)
{
int ret = 0;
struct sbi_tlb_info tlb_info;
u32 source_hart = sbi_current_hartid();
u32 source_hart = current_hartid();
if (funcid >= SBI_EXT_RFENCE_REMOTE_HFENCE_GVMA &&
funcid <= SBI_EXT_RFENCE_REMOTE_HFENCE_VVMA_ASID)
@@ -59,58 +56,40 @@ static int sbi_ecall_rfence_handler(struct sbi_scratch *scratch,
switch (funcid) {
case SBI_EXT_RFENCE_REMOTE_FENCE_I:
tlb_info.start = 0;
tlb_info.size = 0;
tlb_info.type = SBI_ITLB_FLUSH;
tlb_info.shart_mask = 1UL << source_hart;
ret = sbi_tlb_request(scratch, args[0], args[1], &tlb_info);
SBI_TLB_INFO_INIT(&tlb_info, 0, 0, 0,
SBI_ITLB_FLUSH, source_hart);
ret = sbi_tlb_request(args[0], args[1], &tlb_info);
break;
case SBI_EXT_RFENCE_REMOTE_HFENCE_GVMA:
tlb_info.start = (unsigned long)args[2];
tlb_info.size = (unsigned long)args[3];
tlb_info.type = SBI_TLB_FLUSH_GVMA;
tlb_info.shart_mask = 1UL << source_hart;
ret = sbi_tlb_request(scratch, args[0], args[1], &tlb_info);
SBI_TLB_INFO_INIT(&tlb_info, args[2], args[3], 0,
SBI_TLB_FLUSH_GVMA, source_hart);
ret = sbi_tlb_request(args[0], args[1], &tlb_info);
break;
case SBI_EXT_RFENCE_REMOTE_HFENCE_GVMA_VMID:
tlb_info.start = (unsigned long)args[2];
tlb_info.size = (unsigned long)args[3];
tlb_info.asid = (unsigned long)args[4];
tlb_info.type = SBI_TLB_FLUSH_GVMA_VMID;
tlb_info.shart_mask = 1UL << source_hart;
ret = sbi_tlb_request(scratch, args[0], args[1], &tlb_info);
SBI_TLB_INFO_INIT(&tlb_info, args[2], args[3], args[4],
SBI_TLB_FLUSH_GVMA_VMID, source_hart);
ret = sbi_tlb_request(args[0], args[1], &tlb_info);
break;
case SBI_EXT_RFENCE_REMOTE_HFENCE_VVMA:
tlb_info.start = (unsigned long)args[2];
tlb_info.size = (unsigned long)args[3];
tlb_info.type = SBI_TLB_FLUSH_VVMA;
tlb_info.shart_mask = 1UL << source_hart;
ret = sbi_tlb_request(scratch, args[0], args[1], &tlb_info);
SBI_TLB_INFO_INIT(&tlb_info, args[2], args[3], 0,
SBI_TLB_FLUSH_VVMA, source_hart);
ret = sbi_tlb_request(args[0], args[1], &tlb_info);
break;
case SBI_EXT_RFENCE_REMOTE_HFENCE_VVMA_ASID:
tlb_info.start = (unsigned long)args[2];
tlb_info.size = (unsigned long)args[3];
tlb_info.asid = (unsigned long)args[4];
tlb_info.type = SBI_TLB_FLUSH_VVMA_ASID;
tlb_info.shart_mask = 1UL << source_hart;
ret = sbi_tlb_request(scratch, args[0], args[1], &tlb_info);
SBI_TLB_INFO_INIT(&tlb_info, args[2], args[3], args[4],
SBI_TLB_FLUSH_VVMA_ASID, source_hart);
ret = sbi_tlb_request(args[0], args[1], &tlb_info);
break;
case SBI_EXT_RFENCE_REMOTE_SFENCE_VMA:
tlb_info.start = (unsigned long)args[2];
tlb_info.size = (unsigned long)args[3];
tlb_info.type = SBI_TLB_FLUSH_VMA;
tlb_info.shart_mask = 1UL << source_hart;
ret = sbi_tlb_request(scratch, args[0], args[1], &tlb_info);
SBI_TLB_INFO_INIT(&tlb_info, args[2], args[3], 0,
SBI_TLB_FLUSH_VMA, source_hart);
ret = sbi_tlb_request(args[0], args[1], &tlb_info);
break;
case SBI_EXT_RFENCE_REMOTE_SFENCE_VMA_ASID:
tlb_info.start = (unsigned long)args[2];
tlb_info.size = (unsigned long)args[3];
tlb_info.asid = (unsigned long)args[4];
tlb_info.type = SBI_TLB_FLUSH_VMA_ASID;
tlb_info.shart_mask = 1UL << source_hart;
ret = sbi_tlb_request(scratch, args[0], args[1], &tlb_info);
SBI_TLB_INFO_INIT(&tlb_info, args[2], args[3], args[4],
SBI_TLB_FLUSH_VMA_ASID, source_hart);
ret = sbi_tlb_request(args[0], args[1], &tlb_info);
break;
default:
ret = SBI_ENOTSUPP;
};
@@ -124,15 +103,14 @@ struct sbi_ecall_extension ecall_rfence = {
.handle = sbi_ecall_rfence_handler,
};
static int sbi_ecall_ipi_handler(struct sbi_scratch *scratch,
unsigned long extid, unsigned long funcid,
static int sbi_ecall_ipi_handler(unsigned long extid, unsigned long funcid,
unsigned long *args, unsigned long *out_val,
struct sbi_trap_info *out_trap)
{
int ret = 0;
if (funcid == SBI_EXT_IPI_SEND_IPI)
ret = sbi_ipi_send_smode(scratch, args[0], args[1]);
ret = sbi_ipi_send_smode(args[0], args[1]);
else
ret = SBI_ENOTSUPP;

View File

@@ -13,21 +13,19 @@
#include <sbi/sbi_error.h>
#include <sbi/sbi_platform.h>
static int sbi_ecall_vendor_probe(struct sbi_scratch *scratch,
unsigned long extid,
static int sbi_ecall_vendor_probe(unsigned long extid,
unsigned long *out_val)
{
*out_val = sbi_platform_vendor_ext_check(sbi_platform_ptr(scratch),
*out_val = sbi_platform_vendor_ext_check(sbi_platform_thishart_ptr(),
extid);
return 0;
}
static int sbi_ecall_vendor_handler(struct sbi_scratch *scratch,
unsigned long extid, unsigned long funcid,
static int sbi_ecall_vendor_handler(unsigned long extid, unsigned long funcid,
unsigned long *args, unsigned long *out_val,
struct sbi_trap_info *out_trap)
{
return sbi_platform_vendor_ext_provider(sbi_platform_ptr(scratch),
return sbi_platform_vendor_ext_provider(sbi_platform_thishart_ptr(),
extid, funcid, args,
out_val, out_trap);
}

View File

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

View File

@@ -11,28 +11,31 @@
#include <sbi/riscv_barrier.h>
#include <sbi/riscv_encoding.h>
#include <sbi/riscv_fp.h>
#include <sbi/riscv_locks.h>
#include <sbi/sbi_bits.h>
#include <sbi/sbi_bitops.h>
#include <sbi/sbi_console.h>
#include <sbi/sbi_error.h>
#include <sbi/sbi_hart.h>
#include <sbi/sbi_platform.h>
/**
* Return HART ID of the caller.
*/
unsigned int sbi_current_hartid()
{
return (u32)csr_read(CSR_MHARTID);
}
extern void __sbi_unpriv_trap(void);
extern void __sbi_unpriv_trap_hext(void);
void (*sbi_hart_unpriv_trap)(void) = &__sbi_unpriv_trap;
static void mstatus_init(struct sbi_scratch *scratch, u32 hartid)
{
const struct sbi_platform *plat = sbi_platform_ptr(scratch);
unsigned long mstatus_val = 0;
/* Enable FPU */
if (misa_extension('D') || misa_extension('F'))
csr_write(CSR_MSTATUS, MSTATUS_FS);
mstatus_val |= MSTATUS_FS;
/* Enable Vector context */
if (misa_extension('V'))
mstatus_val |= MSTATUS_VS;
csr_write(CSR_MSTATUS, mstatus_val);
/* Enable user/supervisor use of perf counters */
if (misa_extension('S') && sbi_platform_has_scounteren(plat))
@@ -75,7 +78,7 @@ static int delegate_traps(struct sbi_scratch *scratch, u32 hartid)
unsigned long interrupts, exceptions;
if (!misa_extension('S'))
/* No delegation possible as mideleg does not exist*/
/* No delegation possible as mideleg does not exist */
return 0;
/* Send M-mode interrupts and most exceptions to S-mode */
@@ -134,20 +137,16 @@ unsigned long log2roundup(unsigned long x)
void sbi_hart_pmp_dump(struct sbi_scratch *scratch)
{
const struct sbi_platform *plat = sbi_platform_ptr(scratch);
unsigned long prot, addr, size, l2l;
unsigned long prot, addr, size;
unsigned int i;
if (!sbi_platform_has_pmp(plat))
return;
for (i = 0; i < PMP_COUNT; i++) {
pmp_get(i, &prot, &addr, &l2l);
pmp_get(i, &prot, &addr, &size);
if (!(prot & PMP_A))
continue;
if (l2l < __riscv_xlen)
size = (1UL << l2l);
else
size = 0;
#if __riscv_xlen == 32
sbi_printf("PMP%d : 0x%08lx-0x%08lx (A",
#else
@@ -166,6 +165,27 @@ void sbi_hart_pmp_dump(struct sbi_scratch *scratch)
}
}
int sbi_hart_pmp_check_addr(struct sbi_scratch *scratch, unsigned long addr,
unsigned long attr)
{
unsigned long prot, size, i, tempaddr;
const struct sbi_platform *plat = sbi_platform_ptr(scratch);
if (!sbi_platform_has_pmp(plat))
return SBI_OK;
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_INVALID_ADDR;
}
return SBI_OK;
}
static int pmp_init(struct sbi_scratch *scratch, u32 hartid)
{
u32 i, count;
@@ -195,17 +215,13 @@ static int pmp_init(struct sbi_scratch *scratch, u32 hartid)
return 0;
}
static unsigned long trap_info_offset;
int sbi_hart_init(struct sbi_scratch *scratch, u32 hartid, bool cold_boot)
{
int rc;
if (cold_boot) {
trap_info_offset = sbi_scratch_alloc_offset(__SIZEOF_POINTER__,
"HART_TRAP_INFO");
if (!trap_info_offset)
return SBI_ENOMEM;
if (misa_extension('H'))
sbi_hart_unpriv_trap = &__sbi_unpriv_trap_hext;
}
mstatus_init(scratch, hartid);
@@ -221,29 +237,6 @@ int sbi_hart_init(struct sbi_scratch *scratch, u32 hartid, bool cold_boot)
return pmp_init(scratch, hartid);
}
void *sbi_hart_get_trap_info(struct sbi_scratch *scratch)
{
unsigned long *trap_info;
if (!trap_info_offset)
return NULL;
trap_info = sbi_scratch_offset_ptr(scratch, trap_info_offset);
return (void *)(*trap_info);
}
void sbi_hart_set_trap_info(struct sbi_scratch *scratch, void *data)
{
unsigned long *trap_info;
if (!trap_info_offset)
return;
trap_info = sbi_scratch_offset_ptr(scratch, trap_info_offset);
*trap_info = (unsigned long)data;
}
void __attribute__((noreturn)) sbi_hart_hang(void)
{
while (1)
@@ -316,106 +309,3 @@ sbi_hart_switch_mode(unsigned long arg0, unsigned long arg1,
__asm__ __volatile__("mret" : : "r"(a0), "r"(a1));
__builtin_unreachable();
}
static spinlock_t avail_hart_mask_lock = SPIN_LOCK_INITIALIZER;
static volatile unsigned long avail_hart_mask = 0;
void sbi_hart_mark_available(u32 hartid)
{
spin_lock(&avail_hart_mask_lock);
avail_hart_mask |= (1UL << hartid);
spin_unlock(&avail_hart_mask_lock);
}
void sbi_hart_unmark_available(u32 hartid)
{
spin_lock(&avail_hart_mask_lock);
avail_hart_mask &= ~(1UL << hartid);
spin_unlock(&avail_hart_mask_lock);
}
ulong sbi_hart_available_mask(void)
{
ulong ret;
spin_lock(&avail_hart_mask_lock);
ret = avail_hart_mask;
spin_unlock(&avail_hart_mask_lock);
return ret;
}
typedef struct sbi_scratch *(*h2s)(ulong hartid);
struct sbi_scratch *sbi_hart_id_to_scratch(struct sbi_scratch *scratch,
u32 hartid)
{
return ((h2s)scratch->hartid_to_scratch)(hartid);
}
#define COLDBOOT_WAIT_BITMAP_SIZE __riscv_xlen
static spinlock_t coldboot_lock = SPIN_LOCK_INITIALIZER;
static unsigned long coldboot_done = 0;
static unsigned long coldboot_wait_bitmap = 0;
void sbi_hart_wait_for_coldboot(struct sbi_scratch *scratch, u32 hartid)
{
unsigned long saved_mie;
const struct sbi_platform *plat = sbi_platform_ptr(scratch);
if ((sbi_platform_hart_count(plat) <= hartid) ||
(COLDBOOT_WAIT_BITMAP_SIZE <= hartid))
sbi_hart_hang();
/* Save MIE CSR */
saved_mie = csr_read(CSR_MIE);
/* Set MSIE bit to receive IPI */
csr_set(CSR_MIE, MIP_MSIP);
/* Acquire coldboot lock */
spin_lock(&coldboot_lock);
/* Mark current HART as waiting */
coldboot_wait_bitmap |= (1UL << hartid);
/* Wait for coldboot to finish using WFI */
while (!coldboot_done) {
spin_unlock(&coldboot_lock);
wfi();
spin_lock(&coldboot_lock);
};
/* Unmark current HART as waiting */
coldboot_wait_bitmap &= ~(1UL << hartid);
/* Release coldboot lock */
spin_unlock(&coldboot_lock);
/* Restore MIE CSR */
csr_write(CSR_MIE, saved_mie);
/* Clear current HART IPI */
sbi_platform_ipi_clear(plat, hartid);
}
void sbi_hart_wake_coldboot_harts(struct sbi_scratch *scratch, u32 hartid)
{
const struct sbi_platform *plat = sbi_platform_ptr(scratch);
int max_hart = sbi_platform_hart_count(plat);
/* Acquire coldboot lock */
spin_lock(&coldboot_lock);
/* Mark coldboot done */
coldboot_done = 1;
/* Send an IPI to all HARTs waiting for coldboot */
for (int i = 0; i < max_hart; i++) {
if ((i != hartid) && (coldboot_wait_bitmap & (1UL << i)))
sbi_platform_ipi_send(plat, i);
}
/* Release coldboot lock */
spin_unlock(&coldboot_lock);
}

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

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

View File

@@ -9,35 +9,29 @@
#include <sbi/riscv_asm.h>
#include <sbi/riscv_encoding.h>
#include <sbi/sbi_bits.h>
#include <sbi/sbi_bitops.h>
#include <sbi/sbi_emulate_csr.h>
#include <sbi/sbi_error.h>
#include <sbi/sbi_illegal_insn.h>
#include <sbi/sbi_trap.h>
#include <sbi/sbi_unpriv.h>
typedef int (*illegal_insn_func)(ulong insn, u32 hartid, ulong mcause,
struct sbi_trap_regs *regs,
struct sbi_scratch *scratch);
typedef int (*illegal_insn_func)(ulong insn, struct sbi_trap_regs *regs);
static int truly_illegal_insn(ulong insn, u32 hartid, ulong mcause,
struct sbi_trap_regs *regs,
struct sbi_scratch *scratch)
static int truly_illegal_insn(ulong insn, struct sbi_trap_regs *regs)
{
struct sbi_trap_info trap;
trap.epc = regs->mepc;
trap.cause = mcause;
trap.cause = CAUSE_ILLEGAL_INSTRUCTION;
trap.tval = insn;
trap.tval2 = 0;
trap.tinst = 0;
return sbi_trap_redirect(regs, &trap, scratch);
return sbi_trap_redirect(regs, &trap);
}
static int system_opcode_insn(ulong insn, u32 hartid, ulong mcause,
struct sbi_trap_regs *regs,
struct sbi_scratch *scratch)
static int system_opcode_insn(ulong insn, struct sbi_trap_regs *regs)
{
int do_write, rs1_num = (insn >> 15) & 0x1f;
ulong rs1_val = GET_RS1(insn, regs);
@@ -54,12 +48,10 @@ static int system_opcode_insn(ulong insn, u32 hartid, ulong mcause,
if ((regs->mstatus & MSTATUS_MPV) &&
#endif
(insn & INSN_MASK_WFI) == INSN_MATCH_WFI)
return truly_illegal_insn(insn, hartid, mcause,
regs, scratch);
return truly_illegal_insn(insn, regs);
if (sbi_emulate_csr_read(csr_num, hartid, regs, scratch, &csr_val))
return truly_illegal_insn(insn, hartid, mcause,
regs, scratch);
if (sbi_emulate_csr_read(csr_num, regs, &csr_val))
return truly_illegal_insn(insn, regs);
do_write = rs1_num;
switch (GET_RM(insn)) {
@@ -84,12 +76,11 @@ static int system_opcode_insn(ulong insn, u32 hartid, ulong mcause,
new_csr_val = csr_val & ~rs1_num;
break;
default:
return truly_illegal_insn(insn, hartid, mcause, regs, scratch);
return truly_illegal_insn(insn, regs);
};
if (do_write && sbi_emulate_csr_write(csr_num, hartid, regs,
scratch, new_csr_val))
return truly_illegal_insn(insn, hartid, mcause, regs, scratch);
if (do_write && sbi_emulate_csr_write(csr_num, regs, new_csr_val))
return truly_illegal_insn(insn, regs);
SET_RD(insn, regs, csr_val);
@@ -133,26 +124,21 @@ static illegal_insn_func illegal_insn_table[32] = {
truly_illegal_insn /* 31 */
};
int sbi_illegal_insn_handler(u32 hartid, ulong mcause, ulong insn,
struct sbi_trap_regs *regs,
struct sbi_scratch *scratch)
int sbi_illegal_insn_handler(ulong insn, struct sbi_trap_regs *regs)
{
struct sbi_trap_info uptrap;
if (unlikely((insn & 3) != 3)) {
if (insn == 0) {
insn = sbi_get_insn(regs->mepc, scratch, &uptrap);
insn = sbi_get_insn(regs->mepc, &uptrap);
if (uptrap.cause) {
uptrap.epc = regs->mepc;
return sbi_trap_redirect(regs, &uptrap,
scratch);
return sbi_trap_redirect(regs, &uptrap);
}
}
if ((insn & 3) != 3)
return truly_illegal_insn(insn, hartid, mcause, regs,
scratch);
return truly_illegal_insn(insn, regs);
}
return illegal_insn_table[(insn & 0x7c) >> 2](insn, hartid, mcause,
regs, scratch);
return illegal_insn_table[(insn & 0x7c) >> 2](insn, regs);
}

View File

@@ -9,9 +9,12 @@
#include <sbi/riscv_asm.h>
#include <sbi/riscv_atomic.h>
#include <sbi/riscv_locks.h>
#include <sbi/sbi_console.h>
#include <sbi/sbi_ecall.h>
#include <sbi/sbi_hart.h>
#include <sbi/sbi_hartmask.h>
#include <sbi/sbi_hsm.h>
#include <sbi/sbi_ipi.h>
#include <sbi/sbi_platform.h>
#include <sbi/sbi_system.h>
@@ -56,8 +59,6 @@ static void sbi_boot_prints(struct sbi_scratch *scratch, u32 hartid)
/* Platform details */
sbi_printf("Platform Name : %s\n", sbi_platform_name(plat));
sbi_printf("Platform HART Features : RV%d%s\n", xlen, str);
sbi_printf("Platform Max HARTs : %d\n",
sbi_platform_hart_count(plat));
sbi_printf("Current Hart : %u\n", hartid);
/* Firmware details */
sbi_printf("Firmware Base : 0x%lx\n", scratch->fw_start);
@@ -72,6 +73,71 @@ static void sbi_boot_prints(struct sbi_scratch *scratch, u32 hartid)
sbi_hart_pmp_dump(scratch);
}
static spinlock_t coldboot_lock = SPIN_LOCK_INITIALIZER;
static unsigned long coldboot_done = 0;
static struct sbi_hartmask coldboot_wait_hmask = { 0 };
static void wait_for_coldboot(struct sbi_scratch *scratch, u32 hartid)
{
unsigned long saved_mie, cmip;
const struct sbi_platform *plat = sbi_platform_ptr(scratch);
/* Save MIE CSR */
saved_mie = csr_read(CSR_MIE);
/* Set MSIE bit to receive IPI */
csr_set(CSR_MIE, MIP_MSIP);
/* Acquire coldboot lock */
spin_lock(&coldboot_lock);
/* Mark current HART as waiting */
sbi_hartmask_set_hart(hartid, &coldboot_wait_hmask);
/* Wait for coldboot to finish using WFI */
while (!coldboot_done) {
spin_unlock(&coldboot_lock);
do {
wfi();
cmip = csr_read(CSR_MIP);
} while (!(cmip & MIP_MSIP));
spin_lock(&coldboot_lock);
};
/* Unmark current HART as waiting */
sbi_hartmask_clear_hart(hartid, &coldboot_wait_hmask);
/* Release coldboot lock */
spin_unlock(&coldboot_lock);
/* Restore MIE CSR */
csr_write(CSR_MIE, saved_mie);
/* Clear current HART IPI */
sbi_platform_ipi_clear(plat, hartid);
}
static void wake_coldboot_harts(struct sbi_scratch *scratch, u32 hartid)
{
const struct sbi_platform *plat = sbi_platform_ptr(scratch);
/* Acquire coldboot lock */
spin_lock(&coldboot_lock);
/* Mark coldboot done */
coldboot_done = 1;
/* Send an IPI to all HARTs waiting for coldboot */
for (int i = 0; i <= sbi_scratch_last_hartid(); i++) {
if ((i != hartid) &&
sbi_hartmask_test_hart(i, &coldboot_wait_hmask))
sbi_platform_ipi_send(plat, i);
}
/* Release coldboot lock */
spin_unlock(&coldboot_lock);
}
static unsigned long init_count_offset;
static void __noreturn init_coldboot(struct sbi_scratch *scratch, u32 hartid)
@@ -80,12 +146,21 @@ static void __noreturn init_coldboot(struct sbi_scratch *scratch, u32 hartid)
unsigned long *init_count;
const struct sbi_platform *plat = sbi_platform_ptr(scratch);
/* Note: This has to be first thing in coldboot init sequence */
rc = sbi_scratch_init(scratch);
if (rc)
sbi_hart_hang();
init_count_offset = sbi_scratch_alloc_offset(__SIZEOF_POINTER__,
"INIT_COUNT");
if (!init_count_offset)
sbi_hart_hang();
rc = sbi_system_early_init(scratch, TRUE);
rc = sbi_hsm_init(scratch, hartid, TRUE);
if (rc)
sbi_hart_hang();
rc = sbi_platform_early_init(plat, TRUE);
if (rc)
sbi_hart_hang();
@@ -117,20 +192,19 @@ static void __noreturn init_coldboot(struct sbi_scratch *scratch, u32 hartid)
if (rc)
sbi_hart_hang();
rc = sbi_system_final_init(scratch, TRUE);
rc = sbi_platform_final_init(plat, TRUE);
if (rc)
sbi_hart_hang();
if (!(scratch->options & SBI_SCRATCH_NO_BOOT_PRINTS))
sbi_boot_prints(scratch, hartid);
sbi_hart_wake_coldboot_harts(scratch, hartid);
sbi_hart_mark_available(hartid);
wake_coldboot_harts(scratch, hartid);
init_count = sbi_scratch_offset_ptr(scratch, init_count_offset);
(*init_count)++;
sbi_hsm_prepare_next_jump(scratch, hartid);
sbi_hart_switch_mode(hartid, scratch->next_arg1, scratch->next_addr,
scratch->next_mode, FALSE);
}
@@ -141,12 +215,16 @@ static void __noreturn init_warmboot(struct sbi_scratch *scratch, u32 hartid)
unsigned long *init_count;
const struct sbi_platform *plat = sbi_platform_ptr(scratch);
sbi_hart_wait_for_coldboot(scratch, hartid);
wait_for_coldboot(scratch, hartid);
if (!init_count_offset)
sbi_hart_hang();
rc = sbi_system_early_init(scratch, FALSE);
rc = sbi_hsm_init(scratch, hartid, FALSE);
if (rc)
sbi_hart_hang();
rc = sbi_platform_early_init(plat, FALSE);
if (rc)
sbi_hart_hang();
@@ -170,15 +248,14 @@ static void __noreturn init_warmboot(struct sbi_scratch *scratch, u32 hartid)
if (rc)
sbi_hart_hang();
rc = sbi_system_final_init(scratch, FALSE);
rc = sbi_platform_final_init(plat, FALSE);
if (rc)
sbi_hart_hang();
sbi_hart_mark_available(hartid);
init_count = sbi_scratch_offset_ptr(scratch, init_count_offset);
(*init_count)++;
sbi_hsm_prepare_next_jump(scratch, hartid);
sbi_hart_switch_mode(hartid, scratch->next_arg1,
scratch->next_addr,
scratch->next_mode, FALSE);
@@ -201,13 +278,14 @@ static atomic_t coldboot_lottery = ATOMIC_INITIALIZER(0);
void __noreturn sbi_init(struct sbi_scratch *scratch)
{
bool coldboot = FALSE;
u32 hartid = sbi_current_hartid();
u32 hartid = current_hartid();
const struct sbi_platform *plat = sbi_platform_ptr(scratch);
if (sbi_platform_hart_disabled(plat, hartid))
if ((SBI_HARTMASK_MAX_BITS <= hartid) ||
sbi_platform_hart_invalid(plat, hartid))
sbi_hart_hang();
if (atomic_add_return(&coldboot_lottery, 1) == 1)
if (atomic_xchg(&coldboot_lottery, 1) == 0)
coldboot = TRUE;
if (coldboot)
@@ -221,11 +299,13 @@ unsigned long sbi_init_count(u32 hartid)
struct sbi_scratch *scratch;
unsigned long *init_count;
if (sbi_platform_hart_count(sbi_platform_thishart_ptr()) <= hartid ||
!init_count_offset)
if (!init_count_offset)
return 0;
scratch = sbi_hartid_to_scratch(hartid);
if (!scratch)
return 0;
scratch = sbi_hart_id_to_scratch(sbi_scratch_thishart_ptr(), hartid);
init_count = sbi_scratch_offset_ptr(scratch, init_count_offset);
return *init_count;
@@ -242,14 +322,12 @@ unsigned long sbi_init_count(u32 hartid)
*/
void __noreturn sbi_exit(struct sbi_scratch *scratch)
{
u32 hartid = sbi_current_hartid();
u32 hartid = current_hartid();
const struct sbi_platform *plat = sbi_platform_ptr(scratch);
if (sbi_platform_hart_disabled(plat, hartid))
if (sbi_platform_hart_invalid(plat, hartid))
sbi_hart_hang();
sbi_hart_unmark_available(hartid);
sbi_platform_early_exit(plat);
sbi_timer_exit(scratch);
@@ -260,5 +338,5 @@ void __noreturn sbi_exit(struct sbi_scratch *scratch)
sbi_platform_final_exit(plat);
sbi_hart_hang();
sbi_hsm_exit(scratch);
}

View File

@@ -14,6 +14,7 @@
#include <sbi/sbi_bitops.h>
#include <sbi/sbi_error.h>
#include <sbi/sbi_hart.h>
#include <sbi/sbi_hsm.h>
#include <sbi/sbi_init.h>
#include <sbi/sbi_ipi.h>
#include <sbi/sbi_platform.h>
@@ -36,16 +37,14 @@ static int sbi_ipi_send(struct sbi_scratch *scratch, u32 remote_hartid,
const struct sbi_ipi_event_ops *ipi_ops;
if ((SBI_IPI_EVENT_MAX <= event) ||
!ipi_ops_array[event] ||
sbi_platform_hart_disabled(plat, remote_hartid))
!ipi_ops_array[event])
return SBI_EINVAL;
ipi_ops = ipi_ops_array[event];
/*
* Set IPI type on remote hart's scratch area and
* trigger the interrupt
*/
remote_scratch = sbi_hart_id_to_scratch(scratch, remote_hartid);
remote_scratch = sbi_hartid_to_scratch(remote_hartid);
if (!remote_scratch)
return SBI_EINVAL;
ipi_data = sbi_scratch_offset_ptr(remote_scratch, ipi_data_off);
if (ipi_ops->update) {
@@ -55,6 +54,10 @@ static int sbi_ipi_send(struct sbi_scratch *scratch, u32 remote_hartid,
return ret;
}
/*
* Set IPI type on remote hart's scratch area and
* trigger the interrupt
*/
atomic_raw_set_bit(event, &ipi_data->ipi_type);
smp_wmb();
sbi_platform_ipi_send(plat, remote_hartid);
@@ -70,36 +73,35 @@ static int sbi_ipi_send(struct sbi_scratch *scratch, u32 remote_hartid,
* set to all online harts if the intention is to send IPIs to all the harts.
* If hmask is zero, no IPIs will be sent.
*/
int sbi_ipi_send_many(struct sbi_scratch *scratch, ulong hmask, ulong hbase,
u32 event, void *data)
int sbi_ipi_send_many(ulong hmask, ulong hbase, u32 event, void *data)
{
int rc;
ulong i, m;
ulong mask = sbi_hart_available_mask();
ulong tempmask;
unsigned long last_bit = __fls(mask);
struct sbi_scratch *scratch = sbi_scratch_thishart_ptr();
if (hbase != -1UL) {
if (hbase > last_bit)
/* hart base is not available */
return SBI_EINVAL;
/**
* FIXME: This check is valid only ULONG size. This is okay for
* now as avaialble hart mask can support upto ULONG size only.
*/
tempmask = hmask << hbase;
tempmask = ~mask & tempmask;
if (tempmask)
/* at least one of the hart in hmask is not available */
return SBI_EINVAL;
rc = sbi_hsm_hart_started_mask(hbase, &m);
if (rc)
return rc;
m &= hmask;
mask &= (hmask << hbase);
/* Send IPIs */
for (i = hbase; m; i++, m >>= 1) {
if (m & 1UL)
sbi_ipi_send(scratch, i, event, data);
}
} else {
hbase = 0;
while (!sbi_hsm_hart_started_mask(hbase, &m)) {
/* Send IPIs */
for (i = hbase; m; i++, m >>= 1) {
if (m & 1UL)
sbi_ipi_send(scratch, i, event, data);
}
hbase += BITS_PER_LONG;
}
}
/* Send IPIs to every other hart on the set */
for (i = 0, m = mask; m; i++, m >>= 1)
if (m & 1UL)
sbi_ipi_send(scratch, i, event, data);
return 0;
}
@@ -141,19 +143,19 @@ static struct sbi_ipi_event_ops ipi_smode_ops = {
static u32 ipi_smode_event = SBI_IPI_EVENT_MAX;
int sbi_ipi_send_smode(struct sbi_scratch *scratch, ulong hmask, ulong hbase)
int sbi_ipi_send_smode(ulong hmask, ulong hbase)
{
return sbi_ipi_send_many(scratch, hmask, hbase, ipi_smode_event, NULL);
return sbi_ipi_send_many(hmask, hbase, ipi_smode_event, NULL);
}
void sbi_ipi_clear_smode(struct sbi_scratch *scratch)
void sbi_ipi_clear_smode(void)
{
csr_clear(CSR_MIP, MIP_SSIP);
}
static void sbi_ipi_process_halt(struct sbi_scratch *scratch)
{
sbi_exit(scratch);
sbi_hsm_hart_stop(scratch, TRUE);
}
static struct sbi_ipi_event_ops ipi_halt_ops = {
@@ -163,21 +165,22 @@ static struct sbi_ipi_event_ops ipi_halt_ops = {
static u32 ipi_halt_event = SBI_IPI_EVENT_MAX;
int sbi_ipi_send_halt(struct sbi_scratch *scratch, ulong hmask, ulong hbase)
int sbi_ipi_send_halt(ulong hmask, ulong hbase)
{
return sbi_ipi_send_many(scratch, hmask, hbase, ipi_halt_event, NULL);
return sbi_ipi_send_many(hmask, hbase, ipi_halt_event, NULL);
}
void sbi_ipi_process(struct sbi_scratch *scratch)
void sbi_ipi_process(void)
{
unsigned long ipi_type;
unsigned int ipi_event;
const struct sbi_ipi_event_ops *ipi_ops;
struct sbi_scratch *scratch = sbi_scratch_thishart_ptr();
const struct sbi_platform *plat = sbi_platform_ptr(scratch);
struct sbi_ipi_data *ipi_data =
sbi_scratch_offset_ptr(scratch, ipi_data_off);
u32 hartid = sbi_current_hartid();
u32 hartid = current_hartid();
sbi_platform_ipi_clear(plat, hartid);
ipi_type = atomic_raw_xchg_ulong(&ipi_data->ipi_type, 0);
@@ -242,7 +245,7 @@ void sbi_ipi_exit(struct sbi_scratch *scratch)
csr_clear(CSR_MIE, MIP_MSIP);
/* Process pending IPIs */
sbi_ipi_process(scratch);
sbi_ipi_process();
/* Platform exit */
sbi_platform_ipi_exit(sbi_platform_ptr(scratch));

View File

@@ -21,10 +21,8 @@ union reg_data {
u64 data_u64;
};
int sbi_misaligned_load_handler(u32 hartid, ulong mcause,
ulong addr, ulong tval2, ulong tinst,
struct sbi_trap_regs *regs,
struct sbi_scratch *scratch)
int sbi_misaligned_load_handler(ulong addr, ulong tval2, ulong tinst,
struct sbi_trap_regs *regs)
{
ulong insn;
union reg_data val;
@@ -42,10 +40,10 @@ int sbi_misaligned_load_handler(u32 hartid, ulong mcause,
* Bit[0] == 0 implies trapped instruction value is
* zero or special value.
*/
insn = sbi_get_insn(regs->mepc, scratch, &uptrap);
insn = sbi_get_insn(regs->mepc, &uptrap);
if (uptrap.cause) {
uptrap.epc = regs->mepc;
return sbi_trap_redirect(regs, &uptrap, scratch);
return sbi_trap_redirect(regs, &uptrap);
}
}
@@ -72,7 +70,6 @@ int sbi_misaligned_load_handler(u32 hartid, ulong mcause,
shift = 8 * (sizeof(ulong) - len);
} else if ((insn & INSN_MASK_LHU) == INSN_MATCH_LHU) {
len = 2;
#ifdef __riscv_compressed
#if __riscv_xlen >= 64
} else if ((insn & INSN_MASK_C_LD) == INSN_MATCH_C_LD) {
len = 8;
@@ -108,24 +105,23 @@ int sbi_misaligned_load_handler(u32 hartid, ulong mcause,
fp = 1;
len = 4;
#endif
#endif
#endif
} else {
uptrap.epc = regs->mepc;
uptrap.cause = mcause;
uptrap.cause = CAUSE_MISALIGNED_LOAD;
uptrap.tval = addr;
uptrap.tval2 = tval2;
uptrap.tinst = tinst;
return sbi_trap_redirect(regs, &uptrap, scratch);
return sbi_trap_redirect(regs, &uptrap);
}
val.data_u64 = 0;
for (i = 0; i < len; i++) {
val.data_bytes[i] = sbi_load_u8((void *)(addr + i),
scratch, &uptrap);
&uptrap);
if (uptrap.cause) {
uptrap.epc = regs->mepc;
return sbi_trap_redirect(regs, &uptrap, scratch);
return sbi_trap_redirect(regs, &uptrap);
}
}
@@ -143,10 +139,8 @@ int sbi_misaligned_load_handler(u32 hartid, ulong mcause,
return 0;
}
int sbi_misaligned_store_handler(u32 hartid, ulong mcause,
ulong addr, ulong tval2, ulong tinst,
struct sbi_trap_regs *regs,
struct sbi_scratch *scratch)
int sbi_misaligned_store_handler(ulong addr, ulong tval2, ulong tinst,
struct sbi_trap_regs *regs)
{
ulong insn;
union reg_data val;
@@ -164,10 +158,10 @@ int sbi_misaligned_store_handler(u32 hartid, ulong mcause,
* Bit[0] == 0 implies trapped instruction value is
* zero or special value.
*/
insn = sbi_get_insn(regs->mepc, scratch, &uptrap);
insn = sbi_get_insn(regs->mepc, &uptrap);
if (uptrap.cause) {
uptrap.epc = regs->mepc;
return sbi_trap_redirect(regs, &uptrap, scratch);
return sbi_trap_redirect(regs, &uptrap);
}
}
@@ -189,7 +183,6 @@ int sbi_misaligned_store_handler(u32 hartid, ulong mcause,
#endif
} else if ((insn & INSN_MASK_SH) == INSN_MATCH_SH) {
len = 2;
#ifdef __riscv_compressed
#if __riscv_xlen >= 64
} else if ((insn & INSN_MASK_C_SD) == INSN_MATCH_C_SD) {
len = 8;
@@ -221,23 +214,22 @@ int sbi_misaligned_store_handler(u32 hartid, ulong mcause,
len = 4;
val.data_ulong = GET_F32_RS2C(insn, regs);
#endif
#endif
#endif
} else {
uptrap.epc = regs->mepc;
uptrap.cause = mcause;
uptrap.cause = CAUSE_MISALIGNED_STORE;
uptrap.tval = addr;
uptrap.tval2 = tval2;
uptrap.tinst = tinst;
return sbi_trap_redirect(regs, &uptrap, scratch);
return sbi_trap_redirect(regs, &uptrap);
}
for (i = 0; i < len; i++) {
sbi_store_u8((void *)(addr + i), val.data_bytes[i],
scratch, &uptrap);
&uptrap);
if (uptrap.cause) {
uptrap.epc = regs->mepc;
return sbi_trap_redirect(regs, &uptrap, scratch);
return sbi_trap_redirect(regs, &uptrap);
}
}

View File

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

View File

@@ -8,39 +8,32 @@
* Nick Kossifidis <mick@ics.forth.gr>
*/
#include <sbi/riscv_asm.h>
#include <sbi/sbi_bitops.h>
#include <sbi/sbi_hart.h>
#include <sbi/sbi_hsm.h>
#include <sbi/sbi_platform.h>
#include <sbi/sbi_system.h>
#include <sbi/sbi_ipi.h>
#include <sbi/sbi_init.h>
int sbi_system_early_init(struct sbi_scratch *scratch, bool cold_boot)
void __noreturn sbi_system_reboot(u32 type)
{
return sbi_platform_early_init(sbi_platform_ptr(scratch), cold_boot);
}
int sbi_system_final_init(struct sbi_scratch *scratch, bool cold_boot)
{
return sbi_platform_final_init(sbi_platform_ptr(scratch), cold_boot);
}
void sbi_system_early_exit(struct sbi_scratch *scratch)
{
sbi_platform_early_exit(sbi_platform_ptr(scratch));
}
void sbi_system_final_exit(struct sbi_scratch *scratch)
{
sbi_platform_final_exit(sbi_platform_ptr(scratch));
}
void __noreturn sbi_system_reboot(struct sbi_scratch *scratch, u32 type)
{
u32 current_hartid_mask = 1UL << sbi_current_hartid();
ulong hbase = 0, hmask;
u32 cur_hartid = current_hartid();
struct sbi_scratch *scratch = sbi_scratch_thishart_ptr();
/* Send HALT IPI to every hart other than the current hart */
sbi_ipi_send_halt(scratch,
sbi_hart_available_mask() & ~current_hartid_mask, 0);
while (!sbi_hsm_hart_started_mask(hbase, &hmask)) {
if (hbase <= cur_hartid)
hmask &= ~(1UL << (cur_hartid - hbase));
if (hmask)
sbi_ipi_send_halt(hmask, hbase);
hbase += BITS_PER_LONG;
}
/* Stop current HART */
sbi_hsm_hart_stop(scratch, FALSE);
/* Platform specific reooot */
sbi_platform_system_reboot(sbi_platform_ptr(scratch), type);
@@ -49,13 +42,23 @@ void __noreturn sbi_system_reboot(struct sbi_scratch *scratch, u32 type)
sbi_exit(scratch);
}
void __noreturn sbi_system_shutdown(struct sbi_scratch *scratch, u32 type)
void __noreturn sbi_system_shutdown(u32 type)
{
u32 current_hartid_mask = 1UL << sbi_current_hartid();
ulong hbase = 0, hmask;
u32 cur_hartid = current_hartid();
struct sbi_scratch *scratch = sbi_scratch_thishart_ptr();
/* Send HALT IPI to every hart other than the current hart */
sbi_ipi_send_halt(scratch,
sbi_hart_available_mask() & ~current_hartid_mask, 0);
while (!sbi_hsm_hart_started_mask(hbase, &hmask)) {
if (hbase <= cur_hartid)
hmask &= ~(1UL << (cur_hartid - hbase));
if (hmask)
sbi_ipi_send_halt(hmask, hbase);
hbase += BITS_PER_LONG;
}
/* Stop current HART */
sbi_hsm_hart_stop(scratch, FALSE);
/* Platform specific shutdown */
sbi_platform_system_shutdown(sbi_platform_ptr(scratch), type);

View File

@@ -11,6 +11,7 @@
#include <sbi/riscv_encoding.h>
#include <sbi/sbi_error.h>
#include <sbi/sbi_platform.h>
#include <sbi/sbi_scratch.h>
#include <sbi/sbi_timer.h>
static unsigned long time_delta_off;
@@ -37,9 +38,9 @@ u64 get_ticks(void)
}
#endif
u64 sbi_timer_value(struct sbi_scratch *scratch)
u64 sbi_timer_value(void)
{
const struct sbi_platform *plat = sbi_platform_ptr(scratch);
const struct sbi_platform *plat = sbi_platform_thishart_ptr();
if (sbi_platform_has_timer_value(plat))
return sbi_platform_timer_value(plat);
@@ -47,43 +48,47 @@ u64 sbi_timer_value(struct sbi_scratch *scratch)
return get_ticks();
}
u64 sbi_timer_virt_value(struct sbi_scratch *scratch)
u64 sbi_timer_virt_value(void)
{
u64 *time_delta = sbi_scratch_offset_ptr(scratch, time_delta_off);
u64 *time_delta = sbi_scratch_offset_ptr(sbi_scratch_thishart_ptr(),
time_delta_off);
return sbi_timer_value(scratch) + *time_delta;
return sbi_timer_value() + *time_delta;
}
u64 sbi_timer_get_delta(struct sbi_scratch *scratch)
u64 sbi_timer_get_delta(void)
{
u64 *time_delta = sbi_scratch_offset_ptr(scratch, time_delta_off);
u64 *time_delta = sbi_scratch_offset_ptr(sbi_scratch_thishart_ptr(),
time_delta_off);
return *time_delta;
}
void sbi_timer_set_delta(struct sbi_scratch *scratch, ulong delta)
void sbi_timer_set_delta(ulong delta)
{
u64 *time_delta = sbi_scratch_offset_ptr(scratch, time_delta_off);
u64 *time_delta = sbi_scratch_offset_ptr(sbi_scratch_thishart_ptr(),
time_delta_off);
*time_delta = (u64)delta;
}
void sbi_timer_set_delta_upper(struct sbi_scratch *scratch, ulong delta_upper)
void sbi_timer_set_delta_upper(ulong delta_upper)
{
u64 *time_delta = sbi_scratch_offset_ptr(scratch, time_delta_off);
u64 *time_delta = sbi_scratch_offset_ptr(sbi_scratch_thishart_ptr(),
time_delta_off);
*time_delta &= 0xffffffffULL;
*time_delta |= ((u64)delta_upper << 32);
}
void sbi_timer_event_start(struct sbi_scratch *scratch, u64 next_event)
void sbi_timer_event_start(u64 next_event)
{
sbi_platform_timer_event_start(sbi_platform_ptr(scratch), next_event);
sbi_platform_timer_event_start(sbi_platform_thishart_ptr(), next_event);
csr_clear(CSR_MIP, MIP_STIP);
csr_set(CSR_MIE, MIP_MTIP);
}
void sbi_timer_process(struct sbi_scratch *scratch)
void sbi_timer_process(void)
{
csr_clear(CSR_MIE, MIP_MTIP);
csr_set(CSR_MIP, MIP_STIP);

View File

@@ -187,20 +187,19 @@ static void sbi_tlb_local_flush(struct sbi_tlb_info *tinfo)
return;
}
static void sbi_tlb_entry_process(struct sbi_scratch *scratch,
struct sbi_tlb_info *tinfo)
static void sbi_tlb_entry_process(struct sbi_tlb_info *tinfo)
{
u32 i;
u64 m;
u32 rhartid;
struct sbi_scratch *rscratch = NULL;
unsigned long *rtlb_sync = NULL;
sbi_tlb_local_flush(tinfo);
for (i = 0, m = tinfo->shart_mask; m; i++, m >>= 1) {
if (!(m & 1UL))
sbi_hartmask_for_each_hart(rhartid, &tinfo->smask) {
rscratch = sbi_hartid_to_scratch(rhartid);
if (!rscratch)
continue;
rscratch = sbi_hart_id_to_scratch(scratch, i);
rtlb_sync = sbi_scratch_offset_ptr(rscratch, tlb_sync_off);
while (atomic_raw_xchg_ulong(rtlb_sync, 1)) ;
}
@@ -214,7 +213,7 @@ static void sbi_tlb_process_count(struct sbi_scratch *scratch, int count)
sbi_scratch_offset_ptr(scratch, tlb_fifo_off);
while (!sbi_fifo_dequeue(tlb_fifo, &tinfo)) {
sbi_tlb_entry_process(scratch, &tinfo);
sbi_tlb_entry_process(&tinfo);
deq_count++;
if (deq_count > count)
break;
@@ -229,7 +228,7 @@ static void sbi_tlb_process(struct sbi_scratch *scratch)
sbi_scratch_offset_ptr(scratch, tlb_fifo_off);
while (!sbi_fifo_dequeue(tlb_fifo, &tinfo))
sbi_tlb_entry_process(scratch, &tinfo);
sbi_tlb_entry_process(&tinfo);
}
static void sbi_tlb_sync(struct sbi_scratch *scratch)
@@ -263,11 +262,11 @@ static inline int __sbi_tlb_range_check(struct sbi_tlb_info *curr,
if (next->start <= curr->start && next_end > curr_end) {
curr->start = next->start;
curr->size = next->size;
curr->shart_mask = curr->shart_mask | next->shart_mask;
ret = SBI_FIFO_UPDATED;
sbi_hartmask_or(&curr->smask, &curr->smask, &next->smask);
ret = SBI_FIFO_UPDATED;
} else if (next->start >= curr->start && next_end <= curr_end) {
curr->shart_mask = curr->shart_mask | next->shart_mask;
ret = SBI_FIFO_SKIP;
sbi_hartmask_or(&curr->smask, &curr->smask, &next->smask);
ret = SBI_FIFO_SKIP;
}
return ret;
@@ -322,7 +321,7 @@ static int sbi_tlb_update(struct sbi_scratch *scratch,
int ret;
struct sbi_fifo *tlb_fifo_r;
struct sbi_tlb_info *tinfo = data;
u32 curr_hartid = sbi_current_hartid();
u32 curr_hartid = current_hartid();
/*
* If address range to flush is too big then simply
@@ -360,7 +359,7 @@ static int sbi_tlb_update(struct sbi_scratch *scratch,
* this properly.
*/
sbi_tlb_process_count(scratch, 1);
sbi_dprintf(remote_scratch, "hart%d: hart%d tlb fifo full\n",
sbi_dprintf("hart%d: hart%d tlb fifo full\n",
curr_hartid, remote_hartid);
}
@@ -376,10 +375,9 @@ static struct sbi_ipi_event_ops tlb_ops = {
static u32 tlb_event = SBI_IPI_EVENT_MAX;
int sbi_tlb_request(struct sbi_scratch *scratch, ulong hmask,
ulong hbase, struct sbi_tlb_info *tinfo)
int sbi_tlb_request(ulong hmask, ulong hbase, struct sbi_tlb_info *tinfo)
{
return sbi_ipi_send_many(scratch, hmask, hbase, tlb_event, tinfo);
return sbi_ipi_send_many(hmask, hbase, tlb_event, tinfo);
}
int sbi_tlb_init(struct sbi_scratch *scratch, bool cold_boot)
@@ -392,11 +390,11 @@ int sbi_tlb_init(struct sbi_scratch *scratch, bool cold_boot)
if (cold_boot) {
tlb_sync_off = sbi_scratch_alloc_offset(sizeof(*tlb_sync),
"IPI_TLB_SYNC");
"IPI_TLB_SYNC");
if (!tlb_sync_off)
return SBI_ENOMEM;
tlb_fifo_off = sbi_scratch_alloc_offset(sizeof(*tlb_q),
"IPI_TLB_FIFO");
"IPI_TLB_FIFO");
if (!tlb_fifo_off) {
sbi_scratch_free_offset(tlb_sync_off);
return SBI_ENOMEM;

View File

@@ -19,10 +19,12 @@
#include <sbi/sbi_timer.h>
#include <sbi/sbi_trap.h>
static void __noreturn sbi_trap_error(const char *msg, int rc, u32 hartid,
static void __noreturn sbi_trap_error(const char *msg, int rc,
ulong mcause, ulong mtval, ulong mtval2,
ulong mtinst, struct sbi_trap_regs *regs)
{
u32 hartid = current_hartid();
sbi_printf("%s: hart%d: %s (error %d)\n", __func__, hartid, msg, rc);
sbi_printf("%s: hart%d: mcause=0x%" PRILX " mtval=0x%" PRILX "\n",
__func__, hartid, mcause, mtval);
@@ -74,13 +76,11 @@ static void __noreturn sbi_trap_error(const char *msg, int rc, u32 hartid,
*
* @param regs pointer to register state
* @param trap pointer to trap details
* @param scratch pointer to sbi_scratch of current HART
*
* @return 0 on success and negative error code on failure
*/
int sbi_trap_redirect(struct sbi_trap_regs *regs,
struct sbi_trap_info *trap,
struct sbi_scratch *scratch)
struct sbi_trap_info *trap)
{
ulong hstatus, vsstatus, prev_mode;
#if __riscv_xlen == 32
@@ -178,7 +178,7 @@ int sbi_trap_redirect(struct sbi_trap_regs *regs,
regs->mstatus &= ~MSTATUS_MPP;
regs->mstatus |= (PRV_S << MSTATUS_MPP_SHIFT);
/* Set SPP for S-mode*/
/* Set SPP for S-mode */
regs->mstatus &= ~MSTATUS_SPP;
if (prev_mode == PRV_S)
regs->mstatus |= (1UL << MSTATUS_SPP_SHIFT);
@@ -210,17 +210,14 @@ int sbi_trap_redirect(struct sbi_trap_regs *regs,
* 7. Interrupts are disabled in MSTATUS CSR
*
* @param regs pointer to register state
* @param scratch pointer to sbi_scratch of current HART
*/
void sbi_trap_handler(struct sbi_trap_regs *regs,
struct sbi_scratch *scratch)
void sbi_trap_handler(struct sbi_trap_regs *regs)
{
int rc = SBI_ENOTSUPP;
const char *msg = "trap handler failed";
u32 hartid = sbi_current_hartid();
ulong mcause = csr_read(CSR_MCAUSE);
ulong mtval = csr_read(CSR_MTVAL), mtval2 = 0, mtinst = 0;
struct sbi_trap_info trap, *uptrap;
struct sbi_trap_info trap;
if (misa_extension('H')) {
mtval2 = csr_read(CSR_MTVAL2);
@@ -231,10 +228,10 @@ void sbi_trap_handler(struct sbi_trap_regs *regs,
mcause &= ~(1UL << (__riscv_xlen - 1));
switch (mcause) {
case IRQ_M_TIMER:
sbi_timer_process(scratch);
sbi_timer_process();
break;
case IRQ_M_SOFT:
sbi_ipi_process(scratch);
sbi_ipi_process();
break;
default:
msg = "unhandled external interrupt";
@@ -245,50 +242,22 @@ void sbi_trap_handler(struct sbi_trap_regs *regs,
switch (mcause) {
case CAUSE_ILLEGAL_INSTRUCTION:
rc = sbi_illegal_insn_handler(hartid, mcause, mtval,
regs, scratch);
rc = sbi_illegal_insn_handler(mtval, regs);
msg = "illegal instruction handler failed";
break;
case CAUSE_MISALIGNED_LOAD:
rc = sbi_misaligned_load_handler(hartid, mcause, mtval,
mtval2, mtinst, regs,
scratch);
rc = sbi_misaligned_load_handler(mtval, mtval2, mtinst, regs);
msg = "misaligned load handler failed";
break;
case CAUSE_MISALIGNED_STORE:
rc = sbi_misaligned_store_handler(hartid, mcause, mtval,
mtval2, mtinst, regs,
scratch);
rc = sbi_misaligned_store_handler(mtval, mtval2, mtinst, regs);
msg = "misaligned store handler failed";
break;
case CAUSE_SUPERVISOR_ECALL:
case CAUSE_HYPERVISOR_ECALL:
rc = sbi_ecall_handler(hartid, mcause, regs, scratch);
rc = sbi_ecall_handler(regs);
msg = "ecall handler failed";
break;
case CAUSE_LOAD_ACCESS:
case CAUSE_STORE_ACCESS:
case CAUSE_LOAD_PAGE_FAULT:
case CAUSE_STORE_PAGE_FAULT:
uptrap = sbi_hart_get_trap_info(scratch);
if ((regs->mstatus & MSTATUS_MPRV) && uptrap) {
rc = 0;
uptrap->epc = regs->mepc;
regs->mepc += 4;
uptrap->cause = mcause;
uptrap->tval = mtval;
uptrap->tval2 = mtval2;
uptrap->tinst = mtinst;
} else {
trap.epc = regs->mepc;
trap.cause = mcause;
trap.tval = mtval;
trap.tval2 = mtval2;
trap.tinst = mtinst;
rc = sbi_trap_redirect(regs, &trap, scratch);
}
msg = "page/access fault handler failed";
break;
default:
/* If the trap came from S or U mode, redirect it there */
trap.epc = regs->mepc;
@@ -296,13 +265,11 @@ void sbi_trap_handler(struct sbi_trap_regs *regs,
trap.tval = mtval;
trap.tval2 = mtval2;
trap.tinst = mtinst;
rc = sbi_trap_redirect(regs, &trap, scratch);
rc = sbi_trap_redirect(regs, &trap);
break;
};
trap_error:
if (rc) {
sbi_trap_error(msg, rc, hartid, mcause, mtval,
mtval2, mtinst, regs);
}
if (rc)
sbi_trap_error(msg, rc, mcause, mtval, mtval2, mtinst, regs);
}

View File

@@ -8,7 +8,7 @@
*/
#include <sbi/riscv_encoding.h>
#include <sbi/sbi_bits.h>
#include <sbi/sbi_bitops.h>
#include <sbi/sbi_hart.h>
#include <sbi/sbi_scratch.h>
#include <sbi/sbi_trap.h>
@@ -16,52 +16,59 @@
#define DEFINE_UNPRIVILEGED_LOAD_FUNCTION(type, insn) \
type sbi_load_##type(const type *addr, \
struct sbi_scratch *scratch, \
struct sbi_trap_info *trap) \
{ \
register ulong __mstatus asm("a2"); \
type val = 0; \
trap->epc = 0; \
register ulong tinfo asm("a3"); \
register ulong ttmp asm("a4"); \
register ulong mstatus asm("a5"); \
register ulong mtvec asm("a6") = sbi_hart_unpriv_trap_addr(); \
type ret = 0; \
trap->cause = 0; \
trap->tval = 0; \
trap->tval2 = 0; \
trap->tinst = 0; \
sbi_hart_set_trap_info(scratch, trap); \
asm volatile( \
"csrrs %0, " STR(CSR_MSTATUS) ", %3\n" \
"add %[tinfo], %[taddr], zero\n" \
"add %[ttmp], %[taddr], zero\n" \
"csrrw %[mtvec], " STR(CSR_MTVEC) ", %[mtvec]\n" \
"csrrs %[mstatus], " STR(CSR_MSTATUS) ", %[mprv]\n" \
".option push\n" \
".option norvc\n" \
#insn " %1, %2\n" \
#insn " %[ret], %[addr]\n" \
".option pop\n" \
"csrw " STR(CSR_MSTATUS) ", %0" \
: "+&r"(__mstatus), "=&r"(val) \
: "m"(*addr), "r"(MSTATUS_MPRV)); \
sbi_hart_set_trap_info(scratch, NULL); \
return val; \
"csrw " STR(CSR_MSTATUS) ", %[mstatus]\n" \
"csrw " STR(CSR_MTVEC) ", %[mtvec]" \
: [mstatus] "+&r"(mstatus), [mtvec] "+&r"(mtvec), \
[tinfo] "+&r"(tinfo), [ttmp] "+&r"(ttmp), \
[ret] "=&r"(ret) \
: [addr] "m"(*addr), [mprv] "r"(MSTATUS_MPRV), \
[taddr] "r"((ulong)trap) \
: "memory"); \
return ret; \
}
#define DEFINE_UNPRIVILEGED_STORE_FUNCTION(type, insn) \
void sbi_store_##type(type *addr, type val, \
struct sbi_scratch *scratch, \
struct sbi_trap_info *trap) \
{ \
register ulong __mstatus asm("a3"); \
trap->epc = 0; \
register ulong tinfo asm("a3"); \
register ulong ttmp asm("a4"); \
register ulong mstatus asm("a5"); \
register ulong mtvec asm("a6") = sbi_hart_unpriv_trap_addr(); \
trap->cause = 0; \
trap->tval = 0; \
trap->tval2 = 0; \
trap->tinst = 0; \
sbi_hart_set_trap_info(scratch, trap); \
asm volatile( \
"csrrs %0, " STR(CSR_MSTATUS) ", %3\n" \
"add %[tinfo], %[taddr], zero\n" \
"add %[ttmp], %[taddr], zero\n" \
"csrrw %[mtvec], " STR(CSR_MTVEC) ", %[mtvec]\n" \
"csrrs %[mstatus], " STR(CSR_MSTATUS) ", %[mprv]\n" \
".option push\n" \
".option norvc\n" \
#insn " %1, %2\n" \
#insn " %[val], %[addr]\n" \
".option pop\n" \
"csrw " STR(CSR_MSTATUS) ", %0" \
: "+&r"(__mstatus) \
: "r"(val), "m"(*addr), "r"(MSTATUS_MPRV)); \
sbi_hart_set_trap_info(scratch, NULL); \
"csrw " STR(CSR_MSTATUS) ", %[mstatus]\n" \
"csrw " STR(CSR_MTVEC) ", %[mtvec]" \
: [mstatus] "+&r"(mstatus), [mtvec] "+&r"(mtvec), \
[tinfo] "+&r"(tinfo), [ttmp] "+&r"(ttmp) \
: [addr] "m"(*addr), [mprv] "r"(MSTATUS_MPRV), \
[taddr] "r"((ulong)trap), [val] "r"(val) \
: "memory"); \
}
DEFINE_UNPRIVILEGED_LOAD_FUNCTION(u8, lbu)
@@ -82,14 +89,13 @@ DEFINE_UNPRIVILEGED_LOAD_FUNCTION(u32, lw)
DEFINE_UNPRIVILEGED_LOAD_FUNCTION(ulong, lw)
u64 sbi_load_u64(const u64 *addr,
struct sbi_scratch *scratch,
struct sbi_trap_info *trap)
{
u64 ret = sbi_load_u32((u32 *)addr, scratch, trap);
u64 ret = sbi_load_u32((u32 *)addr, trap);
if (trap->cause)
return 0;
ret |= ((u64)sbi_load_u32((u32 *)addr + 1, scratch, trap) << 32);
ret |= ((u64)sbi_load_u32((u32 *)addr + 1, trap) << 32);
if (trap->cause)
return 0;
@@ -97,68 +103,47 @@ u64 sbi_load_u64(const u64 *addr,
}
void sbi_store_u64(u64 *addr, u64 val,
struct sbi_scratch *scratch,
struct sbi_trap_info *trap)
{
sbi_store_u32((u32 *)addr, val, scratch, trap);
sbi_store_u32((u32 *)addr, val, trap);
if (trap->cause)
return;
sbi_store_u32((u32 *)addr + 1, val >> 32, scratch, trap);
sbi_store_u32((u32 *)addr + 1, val >> 32, trap);
if (trap->cause)
return;
}
#endif
ulong sbi_get_insn(ulong mepc, struct sbi_scratch *scratch,
struct sbi_trap_info *trap)
ulong sbi_get_insn(ulong mepc, struct sbi_trap_info *trap)
{
ulong __mstatus = 0, val = 0;
#ifdef __riscv_compressed
ulong rvc_mask = 3, tmp;
#endif
register ulong tinfo asm("a3");
register ulong ttmp asm("a4");
register ulong mstatus asm("a5");
register ulong mtvec asm("a6") = sbi_hart_unpriv_trap_addr();
ulong insn = 0;
trap->epc = 0;
trap->cause = 0;
trap->tval = 0;
trap->tval2 = 0;
trap->tinst = 0;
sbi_hart_set_trap_info(scratch, trap);
#ifndef __riscv_compressed
asm("csrrs %[mstatus], " STR(CSR_MSTATUS) ", %[mprv]\n"
".option push\n"
".option norvc\n"
#if __riscv_xlen == 64
STR(LWU) " %[insn], (%[addr])\n"
#else
STR(LW) " %[insn], (%[addr])\n"
#endif
".option pop\n"
"csrw " STR(CSR_MSTATUS) ", %[mstatus]"
: [mstatus] "+&r"(__mstatus), [insn] "=&r"(val)
: [mprv] "r"(MSTATUS_MPRV | MSTATUS_MXR), [addr] "r"(mepc));
#else
asm("csrrs %[mstatus], " STR(CSR_MSTATUS) ", %[mprv]\n"
".option push\n"
".option norvc\n"
asm volatile(
"add %[tinfo], %[taddr], zero\n"
"csrrw %[mtvec], " STR(CSR_MTVEC) ", %[mtvec]\n"
"csrrs %[mstatus], " STR(CSR_MSTATUS) ", %[mprv]\n"
"lhu %[insn], (%[addr])\n"
".option pop\n"
"and %[tmp], %[insn], %[rvc_mask]\n"
"bne %[tmp], %[rvc_mask], 2f\n"
".option push\n"
".option norvc\n"
"lhu %[tmp], 2(%[addr])\n"
".option pop\n"
"sll %[tmp], %[tmp], 16\n"
"add %[insn], %[insn], %[tmp]\n"
"2: csrw " STR(CSR_MSTATUS) ", %[mstatus]"
: [mstatus] "+&r"(__mstatus), [insn] "=&r"(val), [tmp] "=&r"(tmp)
: [mprv] "r"(MSTATUS_MPRV | MSTATUS_MXR), [addr] "r"(mepc),
[rvc_mask] "r"(rvc_mask));
#endif
sbi_hart_set_trap_info(scratch, NULL);
"andi %[ttmp], %[insn], 3\n"
"addi %[ttmp], %[ttmp], -3\n"
"bne %[ttmp], zero, 2f\n"
"lhu %[ttmp], 2(%[addr])\n"
"sll %[ttmp], %[ttmp], 16\n"
"add %[insn], %[insn], %[ttmp]\n"
"2: csrw " STR(CSR_MSTATUS) ", %[mstatus]\n"
"csrw " STR(CSR_MTVEC) ", %[mtvec]"
: [mstatus] "+&r"(mstatus), [mtvec] "+&r"(mtvec),
[tinfo] "+&r"(tinfo), [ttmp] "+&r"(ttmp),
[insn] "=&r"(insn)
: [mprv] "r"(MSTATUS_MPRV | MSTATUS_MXR),
[taddr] "r"((ulong)trap), [addr] "r"(mepc)
: "memory");
switch (trap->cause) {
case CAUSE_LOAD_ACCESS:
@@ -177,5 +162,5 @@ ulong sbi_get_insn(ulong mepc, struct sbi_scratch *scratch,
break;
};
return val;
return insn;
}

56
lib/sbi/sbi_unpriv_trap.S Normal file
View File

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

216
lib/utils/fdt/fdt_fixup.c Normal file
View File

@@ -0,0 +1,216 @@
// SPDX-License-Identifier: BSD-2-Clause
/*
* fdt_fixup.c - Flat Device Tree parsing helper routines
* Implement helper routines to parse FDT nodes on top of
* libfdt for OpenSBI usage
*
* Copyright (C) 2020 Bin Meng <bmeng.cn@gmail.com>
*/
#include <libfdt.h>
#include <sbi/riscv_asm.h>
#include <sbi/sbi_console.h>
#include <sbi/sbi_platform.h>
#include <sbi/sbi_scratch.h>
#include <sbi/sbi_string.h>
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, len, cpu_offset, cpus_offset;
const fdt32_t *val;
const void *prop;
u32 hartid;
err = fdt_open_into(fdt, fdt, fdt_totalsize(fdt) + 32);
if (err < 0)
return;
cpus_offset = fdt_path_offset(fdt, "/cpus");
if (cpus_offset < 0)
return;
fdt_for_each_subnode(cpu_offset, fdt, cpus_offset) {
prop = fdt_getprop(fdt, cpu_offset, "device_type", &len);
if (!prop || !len)
continue;
if (sbi_strcmp(prop, "cpu"))
continue;
val = fdt_getprop(fdt, cpu_offset, "reg", &len);
if (!val || len < sizeof(fdt32_t))
continue;
if (len > sizeof(fdt32_t))
val++;
hartid = fdt32_to_cpu(*val);
if (sbi_platform_hart_invalid(plat, hartid))
fdt_setprop_string(fdt, cpu_offset, "status",
"disabled");
}
}
void fdt_plic_fixup(void *fdt, const char *compat)
{
u32 *cells;
int i, cells_count;
int plic_off;
plic_off = fdt_node_offset_by_compatible(fdt, 0, compat);
if (plic_off < 0)
return;
cells = (u32 *)fdt_getprop(fdt, plic_off,
"interrupts-extended", &cells_count);
if (!cells)
return;
cells_count = cells_count / sizeof(u32);
if (!cells_count)
return;
for (i = 0; i < (cells_count / 2); i++) {
if (fdt32_to_cpu(cells[2 * i + 1]) == IRQ_M_EXT)
cells[2 * i + 1] = cpu_to_fdt32(0xffffffff);
}
}
/**
* We use PMP to protect OpenSBI firmware to safe-guard it from buggy S-mode
* software, see pmp_init() in lib/sbi/sbi_hart.c. The protected memory region
* information needs to be conveyed to S-mode software (e.g.: operating system)
* via some well-known method.
*
* With device tree, this can be done by inserting a child node of the reserved
* memory node which is used to specify one or more regions of reserved memory.
*
* For the reserved memory node bindings, see Linux kernel documentation at
* Documentation/devicetree/bindings/reserved-memory/reserved-memory.txt
*
* Some additional memory spaces may be protected by platform codes via PMP as
* well, and corresponding child nodes will be inserted.
*/
int fdt_reserved_memory_fixup(void *fdt)
{
struct sbi_scratch *scratch = sbi_scratch_thishart_ptr();
const struct sbi_platform *plat = sbi_platform_ptr(scratch);
unsigned long prot, addr, size;
int na = fdt_address_cells(fdt, 0);
int ns = fdt_size_cells(fdt, 0);
fdt32_t addr_high, addr_low;
fdt32_t size_high, size_low;
fdt32_t reg[4];
fdt32_t *val;
char name[32];
int parent, subnode;
int i, j;
int err;
if (!sbi_platform_has_pmp(plat))
return 0;
/* expand the device tree to accommodate new node */
err = fdt_open_into(fdt, fdt, fdt_totalsize(fdt) + 256);
if (err < 0)
return err;
/* try to locate the reserved memory node */
parent = fdt_path_offset(fdt, "/reserved-memory");
if (parent < 0) {
/* if such node does not exist, create one */
parent = fdt_add_subnode(fdt, 0, "reserved-memory");
if (parent < 0)
return parent;
/*
* reserved-memory node has 3 required properties:
* - #address-cells: the same value as the root node
* - #size-cells: the same value as the root node
* - ranges: should be empty
*/
err = fdt_setprop_empty(fdt, parent, "ranges");
if (err < 0)
return err;
err = fdt_setprop_u32(fdt, parent, "#size-cells", ns);
if (err < 0)
return err;
err = fdt_setprop_u32(fdt, parent, "#address-cells", na);
if (err < 0)
return err;
}
/*
* 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.
*
* With above assumption, we create child nodes directly.
*/
for (i = 0, j = 0; i < PMP_COUNT; i++) {
pmp_get(i, &prot, &addr, &size);
if (!(prot & PMP_A))
continue;
if (!(prot & (PMP_R | PMP_W | PMP_X))) {
addr_high = (u64)addr >> 32;
addr_low = addr;
size_high = (u64)size >> 32;
size_low = size;
if (na > 1 && addr_high)
sbi_snprintf(name, sizeof(name),
"mmode_pmp%d@%x,%x", j,
addr_high, addr_low);
else
sbi_snprintf(name, sizeof(name),
"mmode_pmp%d@%x", j,
addr_low);
subnode = fdt_add_subnode(fdt, parent, name);
if (subnode < 0)
return subnode;
/*
* Tell operating system not to create a virtual
* mapping of the region as part of its standard
* mapping of system memory.
*/
err = fdt_setprop_empty(fdt, subnode, "no-map");
if (err < 0)
return err;
/* encode the <reg> property value */
val = reg;
if (na > 1)
*val++ = cpu_to_fdt32(addr_high);
*val++ = cpu_to_fdt32(addr_low);
if (ns > 1)
*val++ = cpu_to_fdt32(size_high);
*val++ = cpu_to_fdt32(size_low);
err = fdt_setprop(fdt, subnode, "reg", reg,
(na + ns) * sizeof(fdt32_t));
if (err < 0)
return err;
j++;
}
}
return 0;
}
void fdt_fixups(void *fdt)
{
fdt_plic_fixup(fdt, "riscv,plic0");
fdt_reserved_memory_fixup(fdt);
}

129
lib/utils/fdt/fdt_helper.c Normal file
View File

@@ -0,0 +1,129 @@
// SPDX-License-Identifier: BSD-2-Clause
/*
* fdt_helper.c - Flat Device Tree manipulation helper routines
* Implement helper routines on top of libfdt for OpenSBI usage
*
* Copyright (C) 2020 Bin Meng <bmeng.cn@gmail.com>
*/
#include <libfdt.h>
#include <sbi/riscv_asm.h>
#include <sbi/sbi_console.h>
#include <sbi/sbi_platform.h>
#include <sbi/sbi_scratch.h>
#include <sbi_utils/fdt/fdt_helper.h>
static int fdt_get_node_addr_size(void *fdt, int node, unsigned long *addr,
unsigned long *size)
{
int parent, len, i;
int cell_addr, cell_size;
const fdt32_t *prop_addr, *prop_size;
uint64_t temp = 0;
parent = fdt_parent_offset(fdt, node);
if (parent < 0)
return parent;
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;
prop_addr = fdt_getprop(fdt, node, "reg", &len);
if (!prop_addr)
return SBI_ENODEV;
prop_size = prop_addr + cell_addr;
if (addr) {
for (i = 0; i < cell_addr; i++)
temp = (temp << 32) | fdt32_to_cpu(*prop_addr++);
*addr = temp;
}
temp = 0;
if (size) {
for (i = 0; i < cell_size; i++)
temp = (temp << 32) | fdt32_to_cpu(*prop_size++);
*size = temp;
}
return 0;
}
int fdt_parse_uart8250(void *fdt, struct platform_uart_data *uart,
const char *compatible)
{
int nodeoffset, len, rc;
fdt32_t *val;
unsigned long reg_addr, reg_size;
/**
* TODO: We don't know how to handle multiple nodes with the same
* compatible sring. Just return the first node for now.
*/
nodeoffset = fdt_node_offset_by_compatible(fdt, -1, compatible);
if (nodeoffset < 0)
return nodeoffset;
rc = fdt_get_node_addr_size(fdt, nodeoffset, &reg_addr, &reg_size);
if (rc < 0 || !reg_addr || !reg_size)
return SBI_ENODEV;
uart->addr = reg_addr;
/**
* UART address is mandaotry. clock-frequency and current-speed may not
* be present. Don't return error.
*/
val = (fdt32_t *)fdt_getprop(fdt, nodeoffset, "clock-frequency", &len);
if (len > 0 && val)
uart->freq = fdt32_to_cpu(*val);
val = (fdt32_t *)fdt_getprop(fdt, nodeoffset, "current-speed", &len);
if (len > 0 && val)
uart->baud = fdt32_to_cpu(*val);
return 0;
}
int fdt_parse_plic(void *fdt, struct platform_plic_data *plic,
const char *compatible)
{
int nodeoffset, len, rc;
const fdt32_t *val;
unsigned long reg_addr, reg_size;
nodeoffset = fdt_node_offset_by_compatible(fdt, -1, compatible);
if (nodeoffset < 0)
return nodeoffset;
rc = fdt_get_node_addr_size(fdt, nodeoffset, &reg_addr, &reg_size);
if (rc < 0 || !reg_addr || !reg_size)
return SBI_ENODEV;
plic->addr = reg_addr;
val = fdt_getprop(fdt, nodeoffset, "riscv,ndev", &len);
if (len > 0)
plic->num_src = fdt32_to_cpu(*val);
return 0;
}
int fdt_parse_clint(void *fdt, unsigned long *clint_addr,
const char *compatible)
{
int nodeoffset, rc;
nodeoffset = fdt_node_offset_by_compatible(fdt, -1, compatible);
if (nodeoffset < 0)
return nodeoffset;
rc = fdt_get_node_addr_size(fdt, nodeoffset, clint_addr, NULL);
if (rc < 0 || !clint_addr)
return SBI_ENODEV;
return 0;
}

8
lib/utils/fdt/objects.mk Normal file
View File

@@ -0,0 +1,8 @@
#
# SPDX-License-Identifier: BSD-2-Clause
#
# Copyright (C) 2020 Bin Meng <bmeng.cn@gmail.com>
#
libsbiutils-objs-y += fdt/fdt_helper.o
libsbiutils-objs-y += fdt/fdt_fixup.o

View File

@@ -12,8 +12,6 @@
#include <sbi/sbi_console.h>
#include <sbi/sbi_string.h>
#include <sbi_utils/irqchip/plic.h>
#include <libfdt.h>
#include <fdt.h>
#define PLIC_PRIORITY_BASE 0x0
#define PLIC_PENDING_BASE 0x1000
@@ -47,31 +45,6 @@ void plic_set_ie(u32 cntxid, u32 word_index, u32 val)
writel(val, plic_ie + word_index * 4);
}
void plic_fdt_fixup(void *fdt, const char *compat)
{
u32 *cells;
int i, cells_count;
int plic_off;
plic_off = fdt_node_offset_by_compatible(fdt, 0, compat);
if (plic_off < 0)
return;
cells = (u32 *)fdt_getprop(fdt, plic_off,
"interrupts-extended", &cells_count);
if (!cells)
return;
cells_count = cells_count / sizeof(u32);
if (!cells_count)
return;
for (i = 0; i < (cells_count / 2); i++) {
if (fdt32_to_cpu(cells[2 * i + 1]) == IRQ_M_EXT)
cells[2 * i + 1] = cpu_to_fdt32(0xffffffff);
}
}
int plic_warm_irqchip_init(u32 target_hart, int m_cntx_id, int s_cntx_id)
{
size_t i, ie_words = plic_num_sources / 32 + 1;
@@ -93,11 +66,11 @@ int plic_warm_irqchip_init(u32 target_hart, int m_cntx_id, int s_cntx_id)
/* By default, disable M-mode threshold */
if (m_cntx_id > -1)
plic_set_thresh(m_cntx_id, 0xffffffff);
plic_set_thresh(m_cntx_id, 0x7);
/* By default, disable S-mode threshold */
if (s_cntx_id > -1)
plic_set_thresh(s_cntx_id, 0xffffffff);
plic_set_thresh(s_cntx_id, 0x7);
return 0;
}

View File

@@ -1,3 +1,4 @@
# SPDX-License-Identifier: (GPL-2.0-or-later OR BSD-2-Clause)
# Makefile.libfdt
#
# This is not a complete Makefile of itself. Instead, it is designed to
@@ -9,7 +10,9 @@ 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
LIBFDT_OBJS = $(LIBFDT_SRCS:%.c=%.o)
LIBFDT_LIB = libfdt-$(DTC_VERSION).$(SHAREDLIB_EXT)
libfdt_clean:
@$(VECHO) CLEAN "(libfdt)"
rm -f $(STD_CLEANFILES:%=$(LIBFDT_dir)/%)
rm -f $(LIBFDT_dir)/$(LIBFDT_soname)

View File

@@ -1,52 +1,7 @@
// SPDX-License-Identifier: (GPL-2.0-or-later OR BSD-2-Clause)
/*
* libfdt - Flat Device Tree manipulation
* Copyright (C) 2006 David Gibson, IBM Corporation.
*
* libfdt is dual licensed: you can use it either under the terms of
* the GPL, or the BSD license, at your option.
*
* a) This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation; either version 2 of the
* License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public
* License along with this library; if not, write to the Free
* Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston,
* MA 02110-1301 USA
*
* Alternatively,
*
* b) Redistribution and use in source and binary forms, with or
* without modification, are permitted provided that the following
* conditions are met:
*
* 1. Redistributions of source code must retain the above
* copyright notice, this list of conditions and the following
* disclaimer.
* 2. Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following
* disclaimer in the documentation and/or other materials
* provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
* CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
* INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
* OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "libfdt_env.h"
@@ -60,8 +15,10 @@
* that the given buffer contains what appears to be a flattened
* device tree with sane information in its header.
*/
int fdt_ro_probe_(const void *fdt)
int32_t fdt_ro_probe_(const void *fdt)
{
uint32_t totalsize = fdt_totalsize(fdt);
if (fdt_magic(fdt) == FDT_MAGIC) {
/* Complete tree */
if (fdt_version(fdt) < FDT_FIRST_SUPPORTED_VERSION)
@@ -76,7 +33,10 @@ int fdt_ro_probe_(const void *fdt)
return -FDT_ERR_BADMAGIC;
}
return 0;
if (totalsize < INT32_MAX)
return totalsize;
else
return -FDT_ERR_TRUNCATED;
}
static int check_off_(uint32_t hdrsize, uint32_t totalsize, uint32_t off)

View File

@@ -1,55 +1,10 @@
/* SPDX-License-Identifier: (GPL-2.0-or-later OR BSD-2-Clause) */
#ifndef FDT_H
#define FDT_H
/*
* libfdt - Flat Device Tree manipulation
* Copyright (C) 2006 David Gibson, IBM Corporation.
* Copyright 2012 Kim Phillips, Freescale Semiconductor.
*
* libfdt is dual licensed: you can use it either under the terms of
* the GPL, or the BSD license, at your option.
*
* a) This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation; either version 2 of the
* License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public
* License along with this library; if not, write to the Free
* Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston,
* MA 02110-1301 USA
*
* Alternatively,
*
* b) Redistribution and use in source and binary forms, with or
* without modification, are permitted provided that the following
* conditions are met:
*
* 1. Redistributions of source code must retain the above
* copyright notice, this list of conditions and the following
* disclaimer.
* 2. Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following
* disclaimer in the documentation and/or other materials
* provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
* CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
* INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
* OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef __ASSEMBLY__

View File

@@ -1,53 +1,8 @@
// SPDX-License-Identifier: (GPL-2.0-or-later OR BSD-2-Clause)
/*
* libfdt - Flat Device Tree manipulation
* Copyright (C) 2014 David Gibson <david@gibson.dropbear.id.au>
* Copyright (C) 2018 embedded brains GmbH
*
* libfdt is dual licensed: you can use it either under the terms of
* the GPL, or the BSD license, at your option.
*
* a) This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation; either version 2 of the
* License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public
* License along with this library; if not, write to the Free
* Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston,
* MA 02110-1301 USA
*
* Alternatively,
*
* b) Redistribution and use in source and binary forms, with or
* without modification, are permitted provided that the following
* conditions are met:
*
* 1. Redistributions of source code must retain the above
* copyright notice, this list of conditions and the following
* disclaimer.
* 2. Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following
* disclaimer in the documentation and/or other materials
* provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
* CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
* INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
* OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "libfdt_env.h"
@@ -59,7 +14,7 @@
static int fdt_cells(const void *fdt, int nodeoffset, const char *name)
{
const fdt32_t *c;
int val;
uint32_t val;
int len;
c = fdt_getprop(fdt, nodeoffset, name, &len);
@@ -70,10 +25,10 @@ static int fdt_cells(const void *fdt, int nodeoffset, const char *name)
return -FDT_ERR_BADNCELLS;
val = fdt32_to_cpu(*c);
if ((val <= 0) || (val > FDT_MAX_NCELLS))
if (val > FDT_MAX_NCELLS)
return -FDT_ERR_BADNCELLS;
return val;
return (int)val;
}
int fdt_address_cells(const void *fdt, int nodeoffset)
@@ -81,6 +36,8 @@ int fdt_address_cells(const void *fdt, int nodeoffset)
int val;
val = fdt_cells(fdt, nodeoffset, "#address-cells");
if (val == 0)
return -FDT_ERR_BADNCELLS;
if (val == -FDT_ERR_NOTFOUND)
return 2;
return val;
@@ -95,3 +52,50 @@ int fdt_size_cells(const void *fdt, int nodeoffset)
return 1;
return val;
}
/* This function assumes that [address|size]_cells is 1 or 2 */
int fdt_appendprop_addrrange(void *fdt, int parent, int nodeoffset,
const char *name, uint64_t addr, uint64_t size)
{
int addr_cells, size_cells, ret;
uint8_t data[sizeof(fdt64_t) * 2], *prop;
ret = fdt_address_cells(fdt, parent);
if (ret < 0)
return ret;
addr_cells = ret;
ret = fdt_size_cells(fdt, parent);
if (ret < 0)
return ret;
size_cells = ret;
/* check validity of address */
prop = data;
if (addr_cells == 1) {
if ((addr > UINT32_MAX) || ((UINT32_MAX + 1 - addr) < size))
return -FDT_ERR_BADVALUE;
fdt32_st(prop, (uint32_t)addr);
} else if (addr_cells == 2) {
fdt64_st(prop, addr);
} else {
return -FDT_ERR_BADNCELLS;
}
/* check validity of size */
prop += addr_cells * sizeof(fdt32_t);
if (size_cells == 1) {
if (size > UINT32_MAX)
return -FDT_ERR_BADVALUE;
fdt32_st(prop, (uint32_t)size);
} else if (size_cells == 2) {
fdt64_st(prop, size);
} else {
return -FDT_ERR_BADNCELLS;
}
return fdt_appendprop(fdt, nodeoffset, name, data,
(addr_cells + size_cells) * sizeof(fdt32_t));
}

View File

@@ -1,52 +1,7 @@
// SPDX-License-Identifier: (GPL-2.0-or-later OR BSD-2-Clause)
/*
* libfdt - Flat Device Tree manipulation
* Copyright (C) 2012 David Gibson, IBM Corporation.
*
* libfdt is dual licensed: you can use it either under the terms of
* the GPL, or the BSD license, at your option.
*
* a) This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation; either version 2 of the
* License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public
* License along with this library; if not, write to the Free
* Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston,
* MA 02110-1301 USA
*
* Alternatively,
*
* b) Redistribution and use in source and binary forms, with or
* without modification, are permitted provided that the following
* conditions are met:
*
* 1. Redistributions of source code must retain the above
* copyright notice, this list of conditions and the following
* disclaimer.
* 2. Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following
* disclaimer in the documentation and/or other materials
* provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
* CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
* INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
* OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "libfdt_env.h"

View File

@@ -1,53 +1,8 @@
// SPDX-License-Identifier: (GPL-2.0-or-later OR BSD-2-Clause)
/*
* libfdt - Flat Device Tree manipulation
* Copyright (C) 2016 Free Electrons
* Copyright (C) 2016 NextThing Co.
*
* libfdt is dual licensed: you can use it either under the terms of
* the GPL, or the BSD license, at your option.
*
* a) This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation; either version 2 of the
* License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public
* License along with this library; if not, write to the Free
* Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston,
* MA 02110-1301 USA
*
* Alternatively,
*
* b) Redistribution and use in source and binary forms, with or
* without modification, are permitted provided that the following
* conditions are met:
*
* 1. Redistributions of source code must retain the above
* copyright notice, this list of conditions and the following
* disclaimer.
* 2. Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following
* disclaimer in the documentation and/or other materials
* provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
* CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
* INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
* OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "libfdt_env.h"
@@ -93,11 +48,11 @@ static uint32_t overlay_get_target_phandle(const void *fdto, int fragment)
* @pathp: pointer which receives the path of the target (or NULL)
*
* overlay_get_target() retrieves the target offset in the base
* device tree of a fragment, no matter how the actual targetting is
* device tree of a fragment, no matter how the actual targeting is
* done (through a phandle or a path)
*
* returns:
* the targetted node offset in the base device tree
* the targeted node offset in the base device tree
* Negative error code on error
*/
static int overlay_get_target(const void *fdt, const void *fdto,
@@ -778,26 +733,36 @@ static int overlay_symbol_update(void *fdt, void *fdto)
/* keep end marker to avoid strlen() */
e = path + path_len;
/* format: /<fragment-name>/__overlay__/<relative-subnode-path> */
if (*path != '/')
return -FDT_ERR_BADVALUE;
/* get fragment name first */
s = strchr(path + 1, '/');
if (!s)
return -FDT_ERR_BADOVERLAY;
if (!s) {
/* Symbol refers to something that won't end
* up in the target tree */
continue;
}
frag_name = path + 1;
frag_name_len = s - path - 1;
/* verify format; safe since "s" lies in \0 terminated prop */
len = sizeof("/__overlay__/") - 1;
if ((e - s) < len || memcmp(s, "/__overlay__/", len))
return -FDT_ERR_BADOVERLAY;
rel_path = s + len;
rel_path_len = e - rel_path;
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;
} else if ((e - s) == len
&& (memcmp(s, "/__overlay__", len - 1) == 0)) {
/* /<fragment-name>/__overlay__ */
rel_path = "";
rel_path_len = 0;
} else {
/* Symbol refers to something that won't end
* up in the target tree */
continue;
}
/* find the fragment index in which the symbol lies */
ret = fdt_subnode_offset_namelen(fdto, 0, frag_name,
@@ -863,12 +828,16 @@ static int overlay_symbol_update(void *fdt, void *fdto)
int fdt_overlay_apply(void *fdt, void *fdto)
{
uint32_t delta = fdt_get_max_phandle(fdt);
uint32_t delta;
int ret;
FDT_RO_PROBE(fdt);
FDT_RO_PROBE(fdto);
ret = fdt_find_max_phandle(fdt, &delta);
if (ret)
goto err;
ret = overlay_adjust_local_phandles(fdto, delta);
if (ret)
goto err;

View File

@@ -1,52 +1,7 @@
// SPDX-License-Identifier: (GPL-2.0-or-later OR BSD-2-Clause)
/*
* libfdt - Flat Device Tree manipulation
* Copyright (C) 2006 David Gibson, IBM Corporation.
*
* libfdt is dual licensed: you can use it either under the terms of
* the GPL, or the BSD license, at your option.
*
* a) This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation; either version 2 of the
* License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public
* License along with this library; if not, write to the Free
* Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston,
* MA 02110-1301 USA
*
* Alternatively,
*
* b) Redistribution and use in source and binary forms, with or
* without modification, are permitted provided that the following
* conditions are met:
*
* 1. Redistributions of source code must retain the above
* copyright notice, this list of conditions and the following
* disclaimer.
* 2. Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following
* disclaimer in the documentation and/or other materials
* provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
* CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
* INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
* OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "libfdt_env.h"
@@ -78,19 +33,20 @@ 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);
size_t len;
int err;
const char *s, *n;
err = fdt_ro_probe_(fdt);
if (err != 0)
err = totalsize;
if (totalsize < 0)
goto fail;
err = -FDT_ERR_BADOFFSET;
if (absoffset >= fdt_totalsize(fdt))
if (absoffset >= totalsize)
goto fail;
len = fdt_totalsize(fdt) - absoffset;
len = totalsize - absoffset;
if (fdt_magic(fdt) == FDT_MAGIC) {
if (stroffset < 0)
@@ -144,29 +100,49 @@ static int fdt_string_eq_(const void *fdt, int stroffset,
return p && (slen == len) && (memcmp(p, s, len) == 0);
}
uint32_t fdt_get_max_phandle(const void *fdt)
int fdt_find_max_phandle(const void *fdt, uint32_t *phandle)
{
uint32_t max_phandle = 0;
int offset;
uint32_t max = 0;
int offset = -1;
for (offset = fdt_next_node(fdt, -1, NULL);;
offset = fdt_next_node(fdt, offset, NULL)) {
uint32_t phandle;
while (true) {
uint32_t value;
if (offset == -FDT_ERR_NOTFOUND)
return max_phandle;
offset = fdt_next_node(fdt, offset, NULL);
if (offset < 0) {
if (offset == -FDT_ERR_NOTFOUND)
break;
if (offset < 0)
return (uint32_t)-1;
return offset;
}
phandle = fdt_get_phandle(fdt, offset);
if (phandle == (uint32_t)-1)
continue;
value = fdt_get_phandle(fdt, offset);
if (phandle > max_phandle)
max_phandle = phandle;
if (value > max)
max = value;
}
if (phandle)
*phandle = max;
return 0;
}
int fdt_generate_phandle(const void *fdt, uint32_t *phandle)
{
uint32_t max;
int err;
err = fdt_find_max_phandle(fdt, &max);
if (err < 0)
return err;
if (max == FDT_MAX_PHANDLE)
return -FDT_ERR_NOPHANDLES;
if (phandle)
*phandle = max + 1;
return 0;
}
@@ -313,7 +289,7 @@ const char *fdt_get_name(const void *fdt, int nodeoffset, int *len)
const char *nameptr;
int err;
if (((err = fdt_ro_probe_(fdt)) != 0)
if (((err = fdt_ro_probe_(fdt)) < 0)
|| ((err = fdt_check_node_offset_(fdt, nodeoffset)) < 0))
goto fail;

View File

@@ -1,52 +1,7 @@
// SPDX-License-Identifier: (GPL-2.0-or-later OR BSD-2-Clause)
/*
* libfdt - Flat Device Tree manipulation
* Copyright (C) 2006 David Gibson, IBM Corporation.
*
* libfdt is dual licensed: you can use it either under the terms of
* the GPL, or the BSD license, at your option.
*
* a) This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation; either version 2 of the
* License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public
* License along with this library; if not, write to the Free
* Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston,
* MA 02110-1301 USA
*
* Alternatively,
*
* b) Redistribution and use in source and binary forms, with or
* without modification, are permitted provided that the following
* conditions are met:
*
* 1. Redistributions of source code must retain the above
* copyright notice, this list of conditions and the following
* disclaimer.
* 2. Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following
* disclaimer in the documentation and/or other materials
* provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
* CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
* INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
* OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "libfdt_env.h"
@@ -136,6 +91,14 @@ static int fdt_splice_struct_(void *fdt, void *p,
return 0;
}
/* Must only be used to roll back in case of error */
static void fdt_del_last_string_(void *fdt, const char *s)
{
int newlen = strlen(s) + 1;
fdt_set_size_dt_strings(fdt, fdt_size_dt_strings(fdt) - newlen);
}
static int fdt_splice_string_(void *fdt, int newlen)
{
void *p = (char *)fdt
@@ -149,7 +112,7 @@ static int fdt_splice_string_(void *fdt, int newlen)
return 0;
}
static int fdt_find_add_string_(void *fdt, const char *s)
static int fdt_find_add_string_(void *fdt, const char *s, int *allocated)
{
char *strtab = (char *)fdt + fdt_off_dt_strings(fdt);
const char *p;
@@ -157,6 +120,8 @@ static int fdt_find_add_string_(void *fdt, const char *s)
int len = strlen(s) + 1;
int err;
*allocated = 0;
p = fdt_find_string_(strtab, fdt_size_dt_strings(fdt), s);
if (p)
/* found it */
@@ -167,6 +132,8 @@ static int fdt_find_add_string_(void *fdt, const char *s)
if (err)
return err;
*allocated = 1;
memcpy(new, s, len);
return (new - strtab);
}
@@ -225,11 +192,12 @@ static int fdt_add_property_(void *fdt, int nodeoffset, const char *name,
int nextoffset;
int namestroff;
int err;
int allocated;
if ((nextoffset = fdt_check_node_offset_(fdt, nodeoffset)) < 0)
return nextoffset;
namestroff = fdt_find_add_string_(fdt, name);
namestroff = fdt_find_add_string_(fdt, name, &allocated);
if (namestroff < 0)
return namestroff;
@@ -237,8 +205,11 @@ static int fdt_add_property_(void *fdt, int nodeoffset, const char *name,
proplen = sizeof(**prop) + FDT_TAGALIGN(len);
err = fdt_splice_struct_(fdt, *prop, 0, proplen);
if (err)
if (err) {
if (allocated)
fdt_del_last_string_(fdt, name);
return err;
}
(*prop)->tag = cpu_to_fdt32(FDT_PROP);
(*prop)->nameoff = cpu_to_fdt32(namestroff);

View File

@@ -1,51 +1,7 @@
// SPDX-License-Identifier: (GPL-2.0-or-later OR BSD-2-Clause)
/*
* libfdt - Flat Device Tree manipulation
* Copyright (C) 2006 David Gibson, IBM Corporation.
*
* libfdt is dual licensed: you can use it either under the terms of
* the GPL, or the BSD license, at your option.
*
* a) This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation; either version 2 of the
* License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public
* License along with this library; if not, write to the Free
* Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston,
* MA 02110-1301 USA
*
* Alternatively,
*
* b) Redistribution and use in source and binary forms, with or
* without modification, are permitted provided that the following
* conditions are met:
*
* 1. Redistributions of source code must retain the above
* copyright notice, this list of conditions and the following
* disclaimer.
* 2. Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following
* disclaimer in the documentation and/or other materials
* provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
* CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
* INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
* OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "libfdt_env.h"
@@ -82,6 +38,7 @@ static struct fdt_errtabent fdt_errtable[] = {
FDT_ERRTABENT(FDT_ERR_BADVALUE),
FDT_ERRTABENT(FDT_ERR_BADOVERLAY),
FDT_ERRTABENT(FDT_ERR_NOPHANDLES),
FDT_ERRTABENT(FDT_ERR_BADFLAGS),
};
#define FDT_ERRTABSIZE (sizeof(fdt_errtable) / sizeof(fdt_errtable[0]))

View File

@@ -1,52 +1,7 @@
// SPDX-License-Identifier: (GPL-2.0-or-later OR BSD-2-Clause)
/*
* libfdt - Flat Device Tree manipulation
* Copyright (C) 2006 David Gibson, IBM Corporation.
*
* libfdt is dual licensed: you can use it either under the terms of
* the GPL, or the BSD license, at your option.
*
* a) This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation; either version 2 of the
* License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public
* License along with this library; if not, write to the Free
* Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston,
* MA 02110-1301 USA
*
* Alternatively,
*
* b) Redistribution and use in source and binary forms, with or
* without modification, are permitted provided that the following
* conditions are met:
*
* 1. Redistributions of source code must retain the above
* copyright notice, this list of conditions and the following
* disclaimer.
* 2. Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following
* disclaimer in the documentation and/or other materials
* provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
* CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
* INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
* OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "libfdt_env.h"
@@ -121,6 +76,12 @@ static int fdt_sw_probe_struct_(void *fdt)
return err; \
}
static inline uint32_t sw_flags(void *fdt)
{
/* assert: (fdt_magic(fdt) == FDT_SW_MAGIC) */
return fdt_last_comp_version(fdt);
}
/* 'complete' state: Enter this state after fdt_finish()
*
* Allowed functions: none
@@ -141,7 +102,7 @@ static void *fdt_grab_space_(void *fdt, size_t len)
return fdt_offset_ptr_w_(fdt, offset);
}
int fdt_create(void *buf, int bufsize)
int fdt_create_with_flags(void *buf, int bufsize, uint32_t flags)
{
const size_t hdrsize = FDT_ALIGN(sizeof(struct fdt_header),
sizeof(struct fdt_reserve_entry));
@@ -150,11 +111,22 @@ int fdt_create(void *buf, int bufsize)
if (bufsize < hdrsize)
return -FDT_ERR_NOSPACE;
if (flags & ~FDT_CREATE_FLAGS_ALL)
return -FDT_ERR_BADFLAGS;
memset(buf, 0, bufsize);
/*
* magic and last_comp_version keep intermediate state during the fdt
* creation process, which is replaced with the proper FDT format by
* fdt_finish().
*
* flags should be accessed with sw_flags().
*/
fdt_set_magic(fdt, FDT_SW_MAGIC);
fdt_set_version(fdt, FDT_LAST_SUPPORTED_VERSION);
fdt_set_last_comp_version(fdt, FDT_FIRST_SUPPORTED_VERSION);
fdt_set_last_comp_version(fdt, flags);
fdt_set_totalsize(fdt, bufsize);
fdt_set_off_mem_rsvmap(fdt, hdrsize);
@@ -164,6 +136,11 @@ int fdt_create(void *buf, int bufsize)
return 0;
}
int fdt_create(void *buf, int bufsize)
{
return fdt_create_with_flags(buf, bufsize, 0);
}
int fdt_resize(void *fdt, void *buf, int bufsize)
{
size_t headsize, tailsize;
@@ -262,19 +239,13 @@ int fdt_end_node(void *fdt)
return 0;
}
static int fdt_find_add_string_(void *fdt, const char *s)
static int fdt_add_string_(void *fdt, const char *s)
{
char *strtab = (char *)fdt + fdt_totalsize(fdt);
const char *p;
int strtabsize = fdt_size_dt_strings(fdt);
int len = strlen(s) + 1;
int struct_top, offset;
p = fdt_find_string_(strtab - strtabsize, strtabsize, s);
if (p)
return p - strtab;
/* Add it */
offset = -strtabsize - len;
struct_top = fdt_off_dt_struct(fdt) + fdt_size_dt_struct(fdt);
if (fdt_totalsize(fdt) + offset < struct_top)
@@ -285,20 +256,56 @@ static int fdt_find_add_string_(void *fdt, const char *s)
return offset;
}
/* Must only be used to roll back in case of error */
static void fdt_del_last_string_(void *fdt, const char *s)
{
int strtabsize = fdt_size_dt_strings(fdt);
int len = strlen(s) + 1;
fdt_set_size_dt_strings(fdt, strtabsize - len);
}
static int fdt_find_add_string_(void *fdt, const char *s, int *allocated)
{
char *strtab = (char *)fdt + fdt_totalsize(fdt);
int strtabsize = fdt_size_dt_strings(fdt);
const char *p;
*allocated = 0;
p = fdt_find_string_(strtab - strtabsize, strtabsize, s);
if (p)
return p - strtab;
*allocated = 1;
return fdt_add_string_(fdt, s);
}
int fdt_property_placeholder(void *fdt, const char *name, int len, void **valp)
{
struct fdt_property *prop;
int nameoff;
int allocated;
FDT_SW_PROBE_STRUCT(fdt);
nameoff = fdt_find_add_string_(fdt, name);
/* String de-duplication can be slow, _NO_NAME_DEDUP skips it */
if (sw_flags(fdt) & FDT_CREATE_FLAG_NO_NAME_DEDUP) {
allocated = 1;
nameoff = fdt_add_string_(fdt, name);
} else {
nameoff = fdt_find_add_string_(fdt, name, &allocated);
}
if (nameoff == 0)
return -FDT_ERR_NOSPACE;
prop = fdt_grab_space_(fdt, sizeof(*prop) + FDT_TAGALIGN(len));
if (! prop)
if (! prop) {
if (allocated)
fdt_del_last_string_(fdt, name);
return -FDT_ERR_NOSPACE;
}
prop->tag = cpu_to_fdt32(FDT_PROP);
prop->nameoff = cpu_to_fdt32(nameoff);
@@ -360,6 +367,10 @@ int fdt_finish(void *fdt)
/* Finally, adjust the header */
fdt_set_totalsize(fdt, newstroffset + fdt_size_dt_strings(fdt));
/* And fix up fields that were keeping intermediate state. */
fdt_set_last_comp_version(fdt, FDT_FIRST_SUPPORTED_VERSION);
fdt_set_magic(fdt, FDT_MAGIC);
return 0;
}

View File

@@ -1,52 +1,7 @@
// SPDX-License-Identifier: (GPL-2.0-or-later OR BSD-2-Clause)
/*
* libfdt - Flat Device Tree manipulation
* Copyright (C) 2006 David Gibson, IBM Corporation.
*
* libfdt is dual licensed: you can use it either under the terms of
* the GPL, or the BSD license, at your option.
*
* a) This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation; either version 2 of the
* License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public
* License along with this library; if not, write to the Free
* Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston,
* MA 02110-1301 USA
*
* Alternatively,
*
* b) Redistribution and use in source and binary forms, with or
* without modification, are permitted provided that the following
* conditions are met:
*
* 1. Redistributions of source code must retain the above
* copyright notice, this list of conditions and the following
* disclaimer.
* 2. Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following
* disclaimer in the documentation and/or other materials
* provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
* CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
* INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
* OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "libfdt_env.h"

View File

@@ -1,54 +1,9 @@
/* SPDX-License-Identifier: (GPL-2.0-or-later OR BSD-2-Clause) */
#ifndef LIBFDT_H
#define LIBFDT_H
/*
* libfdt - Flat Device Tree manipulation
* Copyright (C) 2006 David Gibson, IBM Corporation.
*
* libfdt is dual licensed: you can use it either under the terms of
* the GPL, or the BSD license, at your option.
*
* a) This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation; either version 2 of the
* License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public
* License along with this library; if not, write to the Free
* Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston,
* MA 02110-1301 USA
*
* Alternatively,
*
* b) Redistribution and use in source and binary forms, with or
* without modification, are permitted provided that the following
* conditions are met:
*
* 1. Redistributions of source code must retain the above
* copyright notice, this list of conditions and the following
* disclaimer.
* 2. Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following
* disclaimer in the documentation and/or other materials
* provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
* CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
* INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
* OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include <libfdt_env.h>
@@ -138,7 +93,15 @@
/* FDT_ERR_NOPHANDLES: The device tree doesn't have any
* phandle available anymore without causing an overflow */
#define FDT_ERR_MAX 17
#define FDT_ERR_BADFLAGS 18
/* FDT_ERR_BADFLAGS: The function was passed a flags field that
* contains invalid flags or an invalid combination of flags. */
#define FDT_ERR_MAX 18
/* constants */
#define FDT_MAX_PHANDLE 0xfffffffe
/* Valid values for phandles range from 1 to 2^32-2. */
/**********************************************************************/
/* Low-level functions (you probably don't need these) */
@@ -171,6 +134,16 @@ static inline uint32_t fdt32_ld(const fdt32_t *p)
| bp[3];
}
static inline void fdt32_st(void *property, uint32_t value)
{
uint8_t *bp = property;
bp[0] = value >> 24;
bp[1] = (value >> 16) & 0xff;
bp[2] = (value >> 8) & 0xff;
bp[3] = value & 0xff;
}
static inline uint64_t fdt64_ld(const fdt64_t *p)
{
const uint8_t *bp = (const uint8_t *)p;
@@ -185,6 +158,20 @@ static inline uint64_t fdt64_ld(const fdt64_t *p)
| bp[7];
}
static inline void fdt64_st(void *property, uint64_t value)
{
uint8_t *bp = property;
bp[0] = value >> 56;
bp[1] = (value >> 48) & 0xff;
bp[2] = (value >> 40) & 0xff;
bp[3] = (value >> 32) & 0xff;
bp[4] = (value >> 24) & 0xff;
bp[5] = (value >> 16) & 0xff;
bp[6] = (value >> 8) & 0xff;
bp[7] = value & 0xff;
}
/**********************************************************************/
/* Traversal functions */
/**********************************************************************/
@@ -361,6 +348,20 @@ const char *fdt_get_string(const void *fdt, int stroffset, int *lenp);
*/
const char *fdt_string(const void *fdt, int stroffset);
/**
* fdt_find_max_phandle - find and return the highest phandle in a tree
* @fdt: pointer to the device tree blob
* @phandle: return location for the highest phandle value found in the tree
*
* fdt_find_max_phandle() finds the highest phandle value in the given device
* tree. The value returned in @phandle is only valid if the function returns
* success.
*
* returns:
* 0 on success or a negative error code on failure
*/
int fdt_find_max_phandle(const void *fdt, uint32_t *phandle);
/**
* fdt_get_max_phandle - retrieves the highest phandle in a tree
* @fdt: pointer to the device tree blob
@@ -369,12 +370,39 @@ const char *fdt_string(const void *fdt, int stroffset);
* device tree. This will ignore badly formatted phandles, or phandles
* with a value of 0 or -1.
*
* This function is deprecated in favour of fdt_find_max_phandle().
*
* returns:
* the highest phandle on success
* 0, if no phandle was found in the device tree
* -1, if an error occurred
*/
uint32_t fdt_get_max_phandle(const void *fdt);
static inline uint32_t fdt_get_max_phandle(const void *fdt)
{
uint32_t phandle;
int err;
err = fdt_find_max_phandle(fdt, &phandle);
if (err < 0)
return (uint32_t)-1;
return phandle;
}
/**
* fdt_generate_phandle - return a new, unused phandle for a device tree blob
* @fdt: pointer to the device tree blob
* @phandle: return location for the new phandle
*
* Walks the device tree blob and looks for the highest phandle value. On
* success, the new, unused phandle value (one higher than the previously
* highest phandle value in the device tree blob) will be returned in the
* @phandle parameter.
*
* Returns:
* 0 on success or a negative error-code on failure
*/
int fdt_generate_phandle(const void *fdt, uint32_t *phandle);
/**
* fdt_num_mem_rsv - retrieve the number of memory reserve map entries
@@ -1360,7 +1388,45 @@ int fdt_nop_node(void *fdt, int nodeoffset);
/* Sequential write functions */
/**********************************************************************/
/* fdt_create_with_flags flags */
#define FDT_CREATE_FLAG_NO_NAME_DEDUP 0x1
/* FDT_CREATE_FLAG_NO_NAME_DEDUP: Do not try to de-duplicate property
* names in the fdt. This can result in faster creation times, but
* a larger fdt. */
#define FDT_CREATE_FLAGS_ALL (FDT_CREATE_FLAG_NO_NAME_DEDUP)
/**
* fdt_create_with_flags - begin creation of a new fdt
* @fdt: pointer to memory allocated where fdt will be created
* @bufsize: size of the memory space at fdt
* @flags: a valid combination of FDT_CREATE_FLAG_ flags, or 0.
*
* fdt_create_with_flags() begins the process of creating a new fdt with
* the sequential write interface.
*
* fdt creation process must end with fdt_finished() to produce a valid fdt.
*
* returns:
* 0, on success
* -FDT_ERR_NOSPACE, bufsize is insufficient for a minimal fdt
* -FDT_ERR_BADFLAGS, flags is not valid
*/
int fdt_create_with_flags(void *buf, int bufsize, uint32_t flags);
/**
* fdt_create - begin creation of a new fdt
* @fdt: pointer to memory allocated where fdt will be created
* @bufsize: size of the memory space at fdt
*
* fdt_create() is equivalent to fdt_create_with_flags() with flags=0.
*
* returns:
* 0, on success
* -FDT_ERR_NOSPACE, bufsize is insufficient for a minimal fdt
*/
int fdt_create(void *buf, int bufsize);
int fdt_resize(void *fdt, void *buf, int bufsize);
int fdt_add_reservemap_entry(void *fdt, uint64_t addr, uint64_t size);
int fdt_finish_reservemap(void *fdt);
@@ -1831,6 +1897,43 @@ static inline int fdt_appendprop_cell(void *fdt, int nodeoffset,
#define fdt_appendprop_string(fdt, nodeoffset, name, str) \
fdt_appendprop((fdt), (nodeoffset), (name), (str), strlen(str)+1)
/**
* fdt_appendprop_addrrange - append a address range property
* @fdt: pointer to the device tree blob
* @parent: offset of the parent node
* @nodeoffset: offset of the node to add a property at
* @name: name of property
* @addr: start address of a given range
* @size: size of a given range
*
* fdt_appendprop_addrrange() appends an address range value (start
* address and size) to the value of the named property in the given
* node, or creates a new property with that value if it does not
* already exist.
* If "name" is not specified, a default "reg" is used.
* Cell sizes are determined by parent's #address-cells and #size-cells.
*
* This function may insert data into the blob, and will therefore
* change the offsets of some existing nodes.
*
* returns:
* 0, on success
* -FDT_ERR_BADLAYOUT,
* -FDT_ERR_BADMAGIC,
* -FDT_ERR_BADNCELLS, if the node has a badly formatted or invalid
* #address-cells property
* -FDT_ERR_BADOFFSET, nodeoffset did not point to FDT_BEGIN_NODE tag
* -FDT_ERR_BADSTATE,
* -FDT_ERR_BADSTRUCTURE,
* -FDT_ERR_BADVERSION,
* -FDT_ERR_BADVALUE, addr or size doesn't fit to respective cells size
* -FDT_ERR_NOSPACE, there is insufficient free space in the blob to
* contain a new property
* -FDT_ERR_TRUNCATED, standard meanings
*/
int fdt_appendprop_addrrange(void *fdt, int parent, int nodeoffset,
const char *name, uint64_t addr, uint64_t size);
/**
* fdt_delprop - delete a property
* @fdt: pointer to the device tree blob

View File

@@ -1,55 +1,10 @@
/* SPDX-License-Identifier: (GPL-2.0-or-later OR BSD-2-Clause) */
#ifndef LIBFDT_ENV_H
#define LIBFDT_ENV_H
/*
* libfdt - Flat Device Tree manipulation
* Copyright (C) 2006 David Gibson, IBM Corporation.
* Copyright 2012 Kim Phillips, Freescale Semiconductor.
*
* libfdt is dual licensed: you can use it either under the terms of
* the GPL, or the BSD license, at your option.
*
* a) This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation; either version 2 of the
* License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public
* License along with this library; if not, write to the Free
* Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston,
* MA 02110-1301 USA
*
* Alternatively,
*
* b) Redistribution and use in source and binary forms, with or
* without modification, are permitted provided that the following
* conditions are met:
*
* 1. Redistributions of source code must retain the above
* copyright notice, this list of conditions and the following
* disclaimer.
* 2. Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following
* disclaimer in the documentation and/or other materials
* provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
* CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
* INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
* OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include <sbi/sbi_string.h>
@@ -57,6 +12,8 @@
#define INT_MAX ((int)(~0U >> 1))
#define UINT_MAX ((unsigned int)~0U)
#define INT32_MAX INT_MAX
#define UINT32_MAX UINT_MAX
#ifdef __CHECKER__
#define FDT_FORCE __attribute__((force))

View File

@@ -1,54 +1,9 @@
/* SPDX-License-Identifier: (GPL-2.0-or-later OR BSD-2-Clause) */
#ifndef LIBFDT_INTERNAL_H
#define LIBFDT_INTERNAL_H
/*
* libfdt - Flat Device Tree manipulation
* Copyright (C) 2006 David Gibson, IBM Corporation.
*
* libfdt is dual licensed: you can use it either under the terms of
* the GPL, or the BSD license, at your option.
*
* a) This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation; either version 2 of the
* License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public
* License along with this library; if not, write to the Free
* Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston,
* MA 02110-1301 USA
*
* Alternatively,
*
* b) Redistribution and use in source and binary forms, with or
* without modification, are permitted provided that the following
* conditions are met:
*
* 1. Redistributions of source code must retain the above
* copyright notice, this list of conditions and the following
* disclaimer.
* 2. Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following
* disclaimer in the documentation and/or other materials
* provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
* CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
* INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
* OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include <fdt.h>
@@ -56,11 +11,11 @@
#define FDT_TAGALIGN(x) (FDT_ALIGN((x), FDT_TAGSIZE))
int fdt_ro_probe_(const void *fdt);
#define FDT_RO_PROBE(fdt) \
{ \
int err_; \
if ((err_ = fdt_ro_probe_(fdt)) != 0) \
return err_; \
#define FDT_RO_PROBE(fdt) \
{ \
int totalsize_; \
if ((totalsize_ = fdt_ro_probe_(fdt)) < 0) \
return totalsize_; \
}
int fdt_check_node_offset_(const void *fdt, int offset);

View File

@@ -7,8 +7,8 @@
# Atish Patra<atish.patra@wdc.com>
#
libfdt_files = fdt.o fdt_ro.o fdt_wip.o fdt_rw.o fdt_sw.o fdt_strerror.o \
fdt_empty_tree.o
libfdt_files = fdt.o fdt_addresses.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

@@ -1,3 +1,4 @@
/* SPDX-License-Identifier: (GPL-2.0-or-later OR BSD-2-Clause) */
LIBFDT_1.2 {
global:
fdt_next_node;
@@ -66,6 +67,15 @@ LIBFDT_1.2 {
fdt_resize;
fdt_overlay_apply;
fdt_get_string;
fdt_find_max_phandle;
fdt_generate_phandle;
fdt_check_full;
fdt_setprop_placeholder;
fdt_property_placeholder;
fdt_header_size_;
fdt_appendprop_addrrange;
fdt_setprop_inplace_namelen_partial;
fdt_create_with_flags;
local:
*;
};

View File

@@ -7,5 +7,5 @@
# Anup Patel <anup.patel@wdc.com>
#
libsbiutils-objs-y += serial/uart8250.o
libsbiutils-objs-y += serial/sifive-uart.o
libsbiutils-objs-y += serial/uart8250.o

View File

@@ -48,7 +48,7 @@ static inline unsigned int uart_min_clk_divisor(uint64_t in_freq,
uint64_t max_target_hz)
{
uint64_t quotient = (in_freq + max_target_hz - 1) / (max_target_hz);
// Avoid underflow
/* Avoid underflow */
if (quotient == 0) {
return 0;
} else {

View File

@@ -26,15 +26,15 @@
#define UART_SCR_OFFSET 7 /* I/O: Scratch Register */
#define UART_MDR1_OFFSET 8 /* I/O: Mode Register */
#define UART_LSR_FIFOE 0x80 /* Fifo error */
#define UART_LSR_TEMT 0x40 /* Transmitter empty */
#define UART_LSR_THRE 0x20 /* Transmit-hold-register empty */
#define UART_LSR_BI 0x10 /* Break interrupt indicator */
#define UART_LSR_FE 0x08 /* Frame error indicator */
#define UART_LSR_PE 0x04 /* Parity error indicator */
#define UART_LSR_OE 0x02 /* Overrun error indicator */
#define UART_LSR_DR 0x01 /* Receiver data ready */
#define UART_LSR_BRK_ERROR_BITS 0x1E /* BI, FE, PE, OE bits */
#define UART_LSR_FIFOE 0x80 /* Fifo error */
#define UART_LSR_TEMT 0x40 /* Transmitter empty */
#define UART_LSR_THRE 0x20 /* Transmit-hold-register empty */
#define UART_LSR_BI 0x10 /* Break interrupt indicator */
#define UART_LSR_FE 0x08 /* Frame error indicator */
#define UART_LSR_PE 0x04 /* Parity error indicator */
#define UART_LSR_OE 0x02 /* Overrun error indicator */
#define UART_LSR_DR 0x01 /* Receiver data ready */
#define UART_LSR_BRK_ERROR_BITS 0x1E /* BI, FE, PE, OE bits */
/* clang-format on */
@@ -88,7 +88,7 @@ int uart8250_init(unsigned long base, u32 in_freq, u32 baudrate, u32 reg_shift,
{
u16 bdiv;
uart8250_base = (volatile void *)base;
uart8250_base = (volatile void *)base;
uart8250_reg_shift = reg_shift;
uart8250_reg_width = reg_width;
uart8250_in_freq = in_freq;

View File

@@ -7,9 +7,9 @@
* Anup Patel <anup.patel@wdc.com>
*/
#include <sbi/riscv_io.h>
#include <sbi/riscv_asm.h>
#include <sbi/riscv_atomic.h>
#include <sbi/sbi_hart.h>
#include <sbi/riscv_io.h>
#include <sbi_utils/sys/clint.h>
static u32 clint_ipi_hart_count;
@@ -36,7 +36,7 @@ void clint_ipi_clear(u32 target_hart)
int clint_warm_ipi_init(void)
{
u32 hartid = sbi_current_hartid();
u32 hartid = current_hartid();
if (!clint_ipi_base)
return -1;
@@ -105,7 +105,7 @@ u64 clint_timer_value(void)
void clint_timer_event_stop(void)
{
u32 target_hart = sbi_current_hartid();
u32 target_hart = current_hartid();
if (clint_time_hart_count <= target_hart)
return;
@@ -116,7 +116,7 @@ void clint_timer_event_stop(void)
void clint_timer_event_start(u64 next_event)
{
u32 target_hart = sbi_current_hartid();
u32 target_hart = current_hartid();
if (clint_time_hart_count <= target_hart)
return;
@@ -127,7 +127,7 @@ void clint_timer_event_start(u64 next_event)
int clint_warm_timer_init(void)
{
u32 target_hart = sbi_current_hartid();
u32 target_hart = current_hartid();
if (clint_time_hart_count <= target_hart || !clint_time_base)
return -1;

View File

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

View File

@@ -8,16 +8,17 @@
* Nylon Chen <nylon7@andestech.com>
*/
#include <sbi/riscv_asm.h>
#include <sbi/riscv_encoding.h>
#include <sbi/sbi_const.h>
#include <sbi/sbi_hart.h>
#include <sbi/sbi_platform.h>
#include <sbi/sbi_console.h>
#include <sbi_utils/serial/uart8250.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/uart8250.h>
#include "platform.h"
#include "plmt.h"
#include "plicsw.h"
#include "plmt.h"
/* Platform final initialization. */
static int ae350_final_init(bool cold_boot)
@@ -47,7 +48,7 @@ static int ae350_final_init(bool cold_boot)
return 0;
fdt = sbi_scratch_thishart_arg1_ptr();
plic_fdt_fixup(fdt, "riscv,plic0");
fdt_fixups(fdt);
return 0;
}
@@ -94,7 +95,7 @@ static int ae350_console_init(void)
/* Initialize the platform interrupt controller for current HART. */
static int ae350_irqchip_init(bool cold_boot)
{
u32 hartid = sbi_current_hartid();
u32 hartid = current_hartid();
int ret;
if (cold_boot) {
@@ -156,7 +157,6 @@ static int ae350_system_shutdown(u32 type)
/* Platform descriptor. */
const struct sbi_platform_operations platform_ops = {
.final_init = ae350_final_init,
.pmp_region_count = ae350_pmp_region_count,
@@ -182,13 +182,11 @@ const struct sbi_platform_operations platform_ops = {
};
const struct sbi_platform platform = {
.opensbi_version = OPENSBI_VERSION,
.platform_version = SBI_PLATFORM_VERSION(0x0, 0x01),
.name = "Andes AE350",
.features = SBI_PLATFORM_DEFAULT_FEATURES,
.hart_count = AE350_HART_COUNT,
.hart_stack_size = AE350_HART_STACK_SIZE,
.disabled_hart_mask = 0,
.hart_stack_size = SBI_PLATFORM_DEFAULT_HART_STACK_SIZE,
.platform_ops_addr = (unsigned long)&platform_ops
};

View File

@@ -12,7 +12,6 @@
#define _AE350_PLATFORM_H_
#define AE350_HART_COUNT 4
#define AE350_HART_STACK_SIZE 8192
#define AE350_PLIC_ADDR 0xe4000000
#define AE350_PLIC_NUM_SOURCES 71

View File

@@ -8,9 +8,9 @@
* Nylon Chen <nylon7@andestech.com>
*/
#include <sbi/sbi_types.h>
#include <sbi/sbi_hart.h>
#include <sbi/riscv_asm.h>
#include <sbi/riscv_io.h>
#include <sbi/sbi_types.h>
#include "plicsw.h"
#include "platform.h"
@@ -19,7 +19,7 @@ static struct plicsw plicsw_dev[AE350_HART_COUNT];
static inline void plicsw_claim(void)
{
u32 source_hart = sbi_current_hartid();
u32 source_hart = current_hartid();
plicsw_dev[source_hart].source_id =
readl(plicsw_dev[source_hart].plicsw_claim);
@@ -27,7 +27,7 @@ static inline void plicsw_claim(void)
static inline void plicsw_complete(void)
{
u32 source_hart = sbi_current_hartid();
u32 source_hart = current_hartid();
u32 source = plicsw_dev[source_hart].source_id;
writel(source, plicsw_dev[source_hart].plicsw_claim);
@@ -61,7 +61,7 @@ static inline void plic_sw_pending(u32 target_hart)
* The bit 5 is used to send IPI to hart 2
* The bit 4 is used to send IPI to hart 3
*/
u32 source_hart = sbi_current_hartid();
u32 source_hart = current_hartid();
u32 target_offset = (PLICSW_PENDING_PER_HART - 1) - target_hart;
u32 per_hart_offset = PLICSW_PENDING_PER_HART * source_hart;
u32 val = 1 << target_offset << per_hart_offset;
@@ -90,7 +90,7 @@ void plicsw_ipi_clear(u32 target_hart)
int plicsw_warm_ipi_init(void)
{
u32 hartid = sbi_current_hartid();
u32 hartid = current_hartid();
if (!plicsw_dev[hartid].plicsw_pending
&& !plicsw_dev[hartid].plicsw_enable

View File

@@ -8,8 +8,8 @@
* Nylon Chen <nylon7@andestech.com>
*/
#include <sbi/riscv_asm.h>
#include <sbi/riscv_io.h>
#include <sbi/sbi_hart.h>
static u32 plmt_time_hart_count;
static volatile void *plmt_time_base;
@@ -34,7 +34,7 @@ u64 plmt_timer_value(void)
void plmt_timer_event_stop(void)
{
u32 target_hart = sbi_current_hartid();
u32 target_hart = current_hartid();
if (plmt_time_hart_count <= target_hart)
return;
@@ -50,7 +50,7 @@ void plmt_timer_event_stop(void)
void plmt_timer_event_start(u64 next_event)
{
u32 target_hart = sbi_current_hartid();
u32 target_hart = current_hartid();
if (plmt_time_hart_count <= target_hart)
return;
@@ -70,7 +70,7 @@ void plmt_timer_event_start(u64 next_event)
int plmt_warm_timer_init(void)
{
u32 target_hart = sbi_current_hartid();
u32 target_hart = current_hartid();
if (plmt_time_hart_count <= target_hart || !plmt_time_base)
return -1;

View File

@@ -1,5 +1,5 @@
#
# SPDX-License-Identifier: GPL-2.0
# SPDX-License-Identifier: BSD-2-Clause
#
# Copyright (C) 2019 FORTH-ICS/CARV
# Panagiotis Peristerakis <perister@ics.forth.gr>

View File

@@ -1,5 +1,5 @@
#
# SPDX-License-Identifier: GPL-2.0
# SPDX-License-Identifier: BSD-2-Clause
#
# Copyright (C) 2019 FORTH-ICS/CARV
# Panagiotis Peristerakis <perister@ics.forth.gr>

View File

@@ -1,21 +1,20 @@
/* SPDX-License-Identifier: GPL-2.0 */
/* SPDX-License-Identifier: BSD-2-Clause */
/*
* Copyright (C) 2019 FORTH-ICS/CARV
* Panagiotis Peristerakis <perister@ics.forth.gr>
*/
#include <sbi/riscv_asm.h>
#include <sbi/riscv_encoding.h>
#include <sbi/riscv_io.h>
#include <sbi/sbi_console.h>
#include <sbi/sbi_const.h>
#include <sbi/sbi_hart.h>
#include <sbi/sbi_platform.h>
#include <sbi_utils/fdt/fdt_fixup.h>
#include <sbi_utils/irqchip/plic.h>
#include <sbi_utils/serial/uart8250.h>
#include <sbi_utils/sys/clint.h>
#include <sbi/sbi_console.h>
#include <sbi/sbi_hart.h>
#include <libfdt.h>
#include <fdt.h>
#include <sbi_utils/irqchip/plic.h>
#include <sbi/riscv_io.h>
#define ARIANE_UART_ADDR 0x10000000
#define ARIANE_UART_FREQ 50000000
@@ -26,10 +25,6 @@
#define ARIANE_PLIC_NUM_SOURCES 3
#define ARIANE_HART_COUNT 1
#define ARIANE_CLINT_ADDR 0x2000000
#define PLIC_ENABLE_BASE 0x2000
#define PLIC_ENABLE_STRIDE 0x80
#define PLIC_CONTEXT_BASE 0x200000
#define PLIC_CONTEXT_STRIDE 0x1000
#define SBI_ARIANE_FEATURES \
(SBI_PLATFORM_HAS_TIMER_VALUE | \
@@ -37,7 +32,6 @@
SBI_PLATFORM_HAS_MCOUNTEREN | \
SBI_PLATFORM_HAS_MFAULTS_DELEGATION)
/*
* Ariane platform early initialization.
*/
@@ -56,8 +50,10 @@ static int ariane_final_init(bool cold_boot)
if (!cold_boot)
return 0;
fdt = sbi_scratch_thishart_arg1_ptr();
plic_fdt_fixup(fdt, "riscv,plic0");
fdt_fixups(fdt);
return 0;
}
@@ -67,10 +63,10 @@ static int ariane_final_init(bool cold_boot)
static int ariane_console_init(void)
{
return uart8250_init(ARIANE_UART_ADDR,
ARIANE_UART_FREQ,
ARIANE_UART_BAUDRATE,
ARIANE_UART_REG_SHIFT,
ARIANE_UART_REG_WIDTH);
ARIANE_UART_FREQ,
ARIANE_UART_BAUDRATE,
ARIANE_UART_REG_SHIFT,
ARIANE_UART_REG_WIDTH);
}
static int plic_ariane_warm_irqchip_init(u32 target_hart,
@@ -105,7 +101,7 @@ static int plic_ariane_warm_irqchip_init(u32 target_hart,
*/
static int ariane_irqchip_init(bool cold_boot)
{
u32 hartid = sbi_current_hartid();
u32 hartid = current_hartid();
int ret;
if (cold_boot) {
@@ -200,7 +196,6 @@ const struct sbi_platform platform = {
.name = "ARIANE RISC-V",
.features = SBI_ARIANE_FEATURES,
.hart_count = ARIANE_HART_COUNT,
.hart_stack_size = 4096,
.disabled_hart_mask = 0,
.hart_stack_size = SBI_PLATFORM_DEFAULT_HART_STACK_SIZE,
.platform_ops_addr = (unsigned long)&platform_ops
};

View File

@@ -0,0 +1,35 @@
#
# SPDX-License-Identifier: BSD-2-Clause
#
# Copyright (c) 2020 Western Digital Corporation or its affiliates.
#
#for more infos, check out /platform/template/config.mk
PLATFORM_RISCV_XLEN = 64
# Blobs to build
FW_TEXT_START=0x80000000
FW_JUMP=n
ifeq ($(PLATFORM_RISCV_XLEN), 32)
# This needs to be 4MB aligned for 32-bit support
FW_JUMP_ADDR=0x80400000
else
# This needs to be 2MB aligned for 64-bit support
FW_JUMP_ADDR=0x80200000
endif
FW_JUMP_FDT_ADDR=0x82200000
# Firmware with payload configuration.
FW_PAYLOAD=y
ifeq ($(PLATFORM_RISCV_XLEN), 32)
# This needs to be 4MB aligned for 32-bit support
FW_PAYLOAD_OFFSET=0x400000
else
# This needs to be 2MB aligned for 64-bit support
FW_PAYLOAD_OFFSET=0x200000
endif
FW_PAYLOAD_FDT_ADDR=0x82200000
FW_PAYLOAD_ALIGN=0x1000

View File

@@ -0,0 +1,7 @@
#
# SPDX-License-Identifier: BSD-2-Clause
#
# Copyright (c) 2020 Western Digital Corporation or its affiliates.
#
platform-objs-y += platform.o

View File

@@ -0,0 +1,233 @@
// SPDX-License-Identifier: BSD-2-Clause
/*
* Copyright (c) 2020 Western Digital Corporation or its affiliates.
*/
#include <sbi/riscv_asm.h>
#include <sbi/riscv_encoding.h>
#include <sbi/riscv_io.h>
#include <sbi/sbi_console.h>
#include <sbi/sbi_const.h>
#include <sbi/sbi_hart.h>
#include <sbi/sbi_platform.h>
#include <sbi_utils/fdt/fdt_helper.h>
#include <sbi_utils/fdt/fdt_fixup.h>
#include <sbi_utils/irqchip/plic.h>
#include <sbi_utils/serial/uart8250.h>
#include <sbi_utils/sys/clint.h>
#define OPENPITON_DEFAULT_UART_ADDR 0xfff0c2c000
#define OPENPITON_DEFAULT_UART_FREQ 60000000
#define OPENPITON_DEFAULT_UART_BAUDRATE 115200
#define OPENPITON_DEFAULT_UART_REG_SHIFT 0
#define OPENPITON_DEFAULT_UART_REG_WIDTH 1
#define OPENPITON_DEFAULT_PLIC_ADDR 0xfff1100000
#define OPENPITON_DEFAULT_PLIC_NUM_SOURCES 2
#define OPENPITON_DEFAULT_HART_COUNT 3
#define OPENPITON_DEFAULT_CLINT_ADDR 0xfff1020000
#define SBI_OPENPITON_FEATURES \
(SBI_PLATFORM_HAS_TIMER_VALUE | \
SBI_PLATFORM_HAS_SCOUNTEREN | \
SBI_PLATFORM_HAS_MCOUNTEREN | \
SBI_PLATFORM_HAS_MFAULTS_DELEGATION)
static struct platform_uart_data uart = {
OPENPITON_DEFAULT_UART_ADDR,
OPENPITON_DEFAULT_UART_FREQ,
OPENPITON_DEFAULT_UART_BAUDRATE,
};
static struct platform_plic_data plic = {
OPENPITON_DEFAULT_PLIC_ADDR,
OPENPITON_DEFAULT_PLIC_NUM_SOURCES,
};
static unsigned long clint_addr = OPENPITON_DEFAULT_CLINT_ADDR;
/*
* OpenPiton platform early initialization.
*/
static int openpiton_early_init(bool cold_boot)
{
void *fdt;
struct platform_uart_data uart_data;
struct platform_plic_data plic_data;
unsigned long clint_data;
int rc;
if (!cold_boot)
return 0;
fdt = sbi_scratch_thishart_arg1_ptr();
rc = fdt_parse_uart8250(fdt, &uart_data, "ns16550");
if (!rc)
uart = uart_data;
rc = fdt_parse_plic(fdt, &plic_data, "riscv,plic0");
if (!rc)
plic = plic_data;
rc = fdt_parse_clint(fdt, &clint_data, "riscv,clint0");
if (!rc)
clint_addr = clint_data;
return 0;
}
/*
* OpenPiton platform final initialization.
*/
static int openpiton_final_init(bool cold_boot)
{
void *fdt;
if (!cold_boot)
return 0;
fdt = sbi_scratch_thishart_arg1_ptr();
fdt_fixups(fdt);
return 0;
}
/*
* Initialize the openpiton console.
*/
static int openpiton_console_init(void)
{
return uart8250_init(uart.addr,
uart.freq,
uart.baud,
OPENPITON_DEFAULT_UART_REG_SHIFT,
OPENPITON_DEFAULT_UART_REG_WIDTH);
}
static int plic_openpiton_warm_irqchip_init(u32 target_hart,
int m_cntx_id, int s_cntx_id)
{
size_t i, ie_words = plic.num_src / 32 + 1;
if (target_hart >= OPENPITON_DEFAULT_HART_COUNT)
return -1;
/* By default, enable all IRQs for M-mode of target HART */
if (m_cntx_id > -1) {
for (i = 0; i < ie_words; i++)
plic_set_ie(m_cntx_id, i, 1);
}
/* Enable all IRQs for S-mode of target HART */
if (s_cntx_id > -1) {
for (i = 0; i < ie_words; i++)
plic_set_ie(s_cntx_id, i, 1);
}
/* By default, enable M-mode threshold */
if (m_cntx_id > -1)
plic_set_thresh(m_cntx_id, 1);
/* By default, disable S-mode threshold */
if (s_cntx_id > -1)
plic_set_thresh(s_cntx_id, 0);
return 0;
}
/*
* Initialize the openpiton interrupt controller for current HART.
*/
static int openpiton_irqchip_init(bool cold_boot)
{
u32 hartid = current_hartid();
int ret;
if (cold_boot) {
ret = plic_cold_irqchip_init(plic.addr,
plic.num_src,
OPENPITON_DEFAULT_HART_COUNT);
if (ret)
return ret;
}
return plic_openpiton_warm_irqchip_init(hartid,
2 * hartid, 2 * hartid + 1);
}
/*
* Initialize IPI for current HART.
*/
static int openpiton_ipi_init(bool cold_boot)
{
int ret;
if (cold_boot) {
ret = clint_cold_ipi_init(clint_addr,
OPENPITON_DEFAULT_HART_COUNT);
if (ret)
return ret;
}
return clint_warm_ipi_init();
}
/*
* Initialize openpiton timer for current HART.
*/
static int openpiton_timer_init(bool cold_boot)
{
int ret;
if (cold_boot) {
ret = clint_cold_timer_init(clint_addr,
OPENPITON_DEFAULT_HART_COUNT, TRUE);
if (ret)
return ret;
}
return clint_warm_timer_init();
}
/*
* Reboot the openpiton.
*/
static int openpiton_system_reboot(u32 type)
{
/* For now nothing to do. */
sbi_printf("System reboot\n");
return 0;
}
/*
* Shutdown or poweroff the openpiton.
*/
static int openpiton_system_shutdown(u32 type)
{
/* For now nothing to do. */
sbi_printf("System shutdown\n");
return 0;
}
/*
* Platform descriptor.
*/
const struct sbi_platform_operations platform_ops = {
.early_init = openpiton_early_init,
.final_init = openpiton_final_init,
.console_init = openpiton_console_init,
.console_putc = uart8250_putc,
.console_getc = uart8250_getc,
.irqchip_init = openpiton_irqchip_init,
.ipi_init = openpiton_ipi_init,
.ipi_send = clint_ipi_send,
.ipi_clear = clint_ipi_clear,
.timer_init = openpiton_timer_init,
.timer_value = clint_timer_value,
.timer_event_start = clint_timer_event_start,
.timer_event_stop = clint_timer_event_stop,
.system_reboot = openpiton_system_reboot,
.system_shutdown = openpiton_system_shutdown
};
const struct sbi_platform platform = {
.opensbi_version = OPENSBI_VERSION,
.platform_version = SBI_PLATFORM_VERSION(0x0, 0x01),
.name = "OPENPITON RISC-V",
.features = SBI_OPENPITON_FEATURES,
.hart_count = OPENPITON_DEFAULT_HART_COUNT,
.hart_stack_size = SBI_PLATFORM_DEFAULT_HART_STACK_SIZE,
.platform_ops_addr = (unsigned long)&platform_ops
};

View File

@@ -7,14 +7,14 @@
* Damien Le Moal <damien.lemoal@wdc.com>
*/
#include <sbi/riscv_asm.h>
#include <sbi/riscv_encoding.h>
#include <sbi/sbi_const.h>
#include <sbi/sbi_hart.h>
#include <sbi/sbi_platform.h>
#include <sbi/sbi_console.h>
#include <sbi/sbi_const.h>
#include <sbi/sbi_platform.h>
#include <sbi_utils/irqchip/plic.h>
#include <sbi_utils/sys/clint.h>
#include <sbi_utils/serial/sifive-uart.h>
#include <sbi_utils/sys/clint.h>
#include "platform.h"
static u32 k210_get_clk_freq(void)
@@ -55,7 +55,7 @@ static int k210_console_init(void)
static int k210_irqchip_init(bool cold_boot)
{
int rc;
u32 hartid = sbi_current_hartid();
u32 hartid = current_hartid();
if (cold_boot) {
rc = plic_cold_irqchip_init(K210_PLIC_BASE_ADDR,
@@ -138,7 +138,6 @@ const struct sbi_platform platform = {
.name = "Kendryte K210",
.features = SBI_PLATFORM_HAS_TIMER_VALUE,
.hart_count = K210_HART_COUNT,
.hart_stack_size = K210_HART_STACK_SIZE,
.disabled_hart_mask = 0,
.hart_stack_size = SBI_PLATFORM_DEFAULT_HART_STACK_SIZE,
.platform_ops_addr = (unsigned long)&platform_ops
};

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