92 Commits
v0.3 ... v0.4

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

Signed-off-by: Anup Patel <anup.patel@wdc.com>
2019-07-02 11:11:08 +05:30
Atish Patra
42c938e3f0 platform: Remove the HiFive Unleashed expansion board DT.
The Linux kernel will maintain the device tree (DT) for HiFive Unleashed
from release v5.2-rc6. This DT is incompatible with previous DT
present for Microsemi expansion board in OpenSBI.

Since, OpenSBI will directly load the pre-built DTB from kernel now onwards,
no need to keep the out-of-date DT in openSBI. Remove this DT and
it's related documentation.

Signed-off-by: Atish Patra <atish.patra@wdc.com>
Acked-by: Anup Patel <anup.patel@wdc.com>
2019-07-02 10:16:00 +05:30
Anup Patel
bb3edd36af firmware: For no relocation skip two stage wait for secondary HARTs
When relocation is not required (i.e. _load_start == _link_start), we
can skip two stage wait for secondary HARTs. This means secondary HARTs
can skip the _wait_relocate_copy_done() loop and directly jump to the
_wait_for_boot_hart() loop when no relocation not required.

Signed-off-by: Anup Patel <anup.patel@wdc.com>
2019-07-01 08:54:13 +05:30
Anup Patel
da398ef8d6 scripts: Add Ariane FPGA to platform list in binary archive script
This patch adds Ariane FPGA to RV64 platform list in the binary
archive script.

Signed-off-by: Anup Patel <anup.patel@wdc.com>
2019-06-30 12:07:56 +05:30
Atish Patra
d44bc16e4b docs: Update the fu540 platform guide for new DT.
With 5.2-rc6 release, Linux kernel hosts the DT for Unleashed board
which is incompatible with the default DT from FSBL.

Update the document to use the DT from kernel.

Signed-off-by: Atish Patra <atish.patra@wdc.com>
Acked-by: Anup Patel <anup.patel@wdc.com>
2019-06-30 11:56:57 +05:30
Abner Chang
9c18c2c610 include: Add firmware context to sbi_platform
Add firmware context field struct sbi_platform to carry firmware
specific information.

Signed-off-by: Abner Chang <abner.chang@hpe.com>
Acked-by: Anup Patel <anup.patel@wdc.com>
2019-06-29 20:59:45 +05:30
Abner Chang
08b196956d include: Add version info to struct sbi_platform
Add version control of sbi_platform structure
- Add opensbi_version, this gives information of opensbi revision on
which the sbi_platform table was created.
- Add platform_version field in sbi_platform structure for platform
level version control.

Signed-off-by: Abner Chang <abner.chang@hpe.com>
Acked-by: Anup Patel <anup.patel@wdc.com>
2019-06-29 19:26:26 +05:30
Abner Chang
fa6fd6bf86 include: Move callbacks in sbi_platform to separate struct
Move platform opensbi functions to sbi_platform_operations structure.
Both sbi_platform and sbi_platform_operations structures are maintained
by platform vendors.

Signed-off-by: Abner Chang <abner.chang@hpe.com>
Acked-by: Anup Patel <anup.patel@wdc.com>
2019-06-29 18:20:00 +05:30
Panagiotis Peristerakis
3048f979ca Add documentation for Ariane FPGA platform
Signed-off-by: Panagiotis Peristerakis <perister@ics.forth.gr>
2019-06-29 17:04:06 +05:30
Panagiotis Peristerakis
b44e844880 Add support for Ariane FPGA SoC
This patch adds support for Ariane platform.
We needed to enable PLIC interrupts early(like on BBL) due to some issue of the design.
Otherwise, Linux would not get any external interrupts.

Signed-off-by: Panagiotis Peristerakis <perister@ics.forth.gr>
2019-06-29 17:04:06 +05:30
Panagiotis Peristerakis
c6d06a9448 Changed plic_set_thresh() and plic_set_ie() to public
Signed-off-by: Panagiotis Peristerakis <perister@ics.forth.gr>
2019-06-29 17:04:06 +05:30
Xiang W
65aa5873c3 firmware: Handle overlapping load and link addresses in relocation
The old code may corrupt the code of the waiting hart hence this patch
keeps waiting HART within relocation code range at time of relocation.

Signed-off-by: Xiang W <wxjstz@126.com>
Acked-by: Anup Patel <anup.patel@wdc.com>
2019-06-24 09:39:18 +05:30
Atish Patra
cd2dfdc870 docs: Update docs as per new static library.
Signed-off-by: Atish Patra <atish.patra@wdc.com>
Acked-by: Anup Patel <anup.patel@wdc.com>
2019-06-19 09:56:24 +05:30
Atish Patra
5dd93e88fe utils: Remove tinyfdt.c
tinyfdt.c was originally added to provide a minimal implementation of
fdt parsing. However, we have already included libfdt in OpenSBI for
more complicated operations.

Remove tinfdt and replace its functiolity using libfdt.

Signed-off-by: Atish Patra <atish.patra@wdc.com>
Acked-by: Anup Patel <anup.patel@wdc.com>
2019-06-19 09:55:13 +05:30
Atish Patra
b2d0caf86b platform: Enable all drivers by default.
The drivers and libfdt are built as libsbiutils.a
instead of libplatsbi.a.

libsbiutils.a are not built per platform specific. Thus,
enable all drivers by default.

Signed-off-by: Atish Patra <atish.patra@wdc.com>
Acked-by: Anup Patel <anup.patel@wdc.com>
2019-06-19 09:49:05 +05:30
Atish Patra
200ed7c1bd lib: Rename string.x to sbi_string.x
All string functions are part of libsbi. It makes more sense
to rename them to sbi_string.x as the libsbi can be linked
with external libraries that can have similar implementation.

Signed-off-by: Atish Patra <atish.patra@wdc.com>
Acked-by: Anup Patel <anup.patel@wdc.com>
2019-06-19 09:48:59 +05:30
Atish Patra
793e5e1184 platform: Move platform common to lib/utils.
Currently, platform/common contains platform/non-platform specific
common minimal drivers and libraries. This is helpful is all platforms
are built within opensbi framework.

Move them to lib/utils so that any external platform code also can
reuse the minimalistic drivers or other common libraries.

This patch doesn't introduce any functional changes.

Signed-off-by: Atish Patra <atish.patra@wdc.com>
Acked-by: Anup Patel <anup.patel@wdc.com>
2019-06-19 09:48:56 +05:30
Atish Patra
98aaf8317b lib: Include helper libc functions directly in libsbi.
libsbi needs some of the custom libc functions. It should be directly
included in libsbi instead of platform specific libraries.

Signed-off-by: Atish Patra <atish.patra@wdc.com>
Acked-by: Anup Patel <anup.patel@wdc.com>
2019-06-19 09:48:54 +05:30
Atish Patra
749b0b0932 lib: Move sbi core library to lib/sbi
Signed-off-by: Atish Patra <atish.patra@wdc.com>
Acked-by: Anup Patel <anup.patel@wdc.com>
2019-06-19 09:48:51 +05:30
Xiang W
a5b37bd7d2 firmware: Handle overlapping load and link addresses in relocation
This patch extends relocation to handle overlapping load and link
addresses.

The updated relocation will work fine in most cases except when the
relocate copy loop itself falls in overlapping load and link addresses.

Signed-off-by: Xiang W <wxjstz@126.com>
Signed-off-by: Anup Patel <anup.patel@wdc.com>
2019-06-17 11:53:42 +05:30
Anup Patel
331f291e4c firmware: Relocate when load address is not equal to link address
This patch extends fw_base to relocate to link address whenever
firmware load address is not equal to link address.

The relocation will not work when load start to load end overlap
link start to link end.

Signed-off-by: Anup Patel <anup.patel@wdc.com>
Tested-by: Lukas Auer <lukas.auer@aisec.fraunhofer.de>
2019-06-12 17:56:28 +05:30
Lukas Auer
6fec1c7e11 firmware: add missing linker sections to fw_base.ldS
The linker sections .sdata and .sbss are missing from the linker script
fw_base.ldS. Add them to the .data and .bss sections.

On current builds, most variables are in the .sbss section. They are not
correctly initialized to zero, because they are not within the
boundaries indicated by _bss_start and _bss_end. Currently, this does
not cause any issues, however with relocation support lock-ups may occur
due to incorrectly initialized lock variables.

Signed-off-by: Lukas Auer <lukas.auer@aisec.fraunhofer.de>
Acked-by: Anup Patel <anup.patel@wdc.com>
2019-06-12 17:43:47 +05:30
Karsten Merker
f19611e1e4 docs: update CONTRIBUTORS.md
Add Andreas Schwab to the contributors list.

Signed-off-by: Karsten Merker <merker@debian.org>
Acked-by: Andreas Schwab <schwab@suse.de>
2019-05-31 16:56:43 +05:30
Bin Meng
b6ea152df2 docs: qemu/sifive_u: miscellaneous documentation fixes
- OpenSBI build target should be: qemu/sifive_u
- U-Boot config name should be: sifive_fu540_defconfig

Signed-off-by: Bin Meng <bmeng.cn@gmail.com>
Reviewed-by: Atish Patra <atish.patra@wdc.com>
2019-05-30 22:37:31 +05:30
Bin Meng
2b80945ac7 platform: qemu/sifive_u: Update the hart count to 4
Since QEMU commit 8b1d0714bfdd
"riscv: sifive_u: Allow up to 4 CPUs to be created",
the maximum number of hart for sifive_u is 4.

Change our hart count to match that.

Signed-off-by: Bin Meng <bmeng.cn@gmail.com>
Reviewed-by: Atish Patra <atish.patra@wdc.com>
2019-05-30 22:36:17 +05:30
Anup Patel
a6395acd6c lib: Handle page/access fault caused by unpriv load/store
The unpriv load/store instruction from M-mode can cause page/access
fault to M-mode if S-mode page table did not have mappings OR it did
not have PMP access permission.

To tackle this, we redirect trap back to S-mode if unpriv load/store
instruction traps in M-mode.

Signed-off-by: Anup Patel <anup.patel@wdc.com>
Reviewed-by: Atish Patra <atish.patra@wdc.com>
2019-05-24 08:22:47 +05:30
Anup Patel
bb915780ac lib: Add per-HART trap info pointer
This patch adds per-HART trap info pointer which can be used to
communicate trap information to sbi_trap_handler().

Signed-off-by: Anup Patel <anup.patel@wdc.com>
Reviewed-by: Atish Patra <atish.patra@wdc.com>
2019-05-24 08:22:47 +05:30
Anup Patel
a22c6891b7 include: Make unprivilege load/store functions as non-inline functions
Currently, the unprivilege load/store functions are inline functions.

We will be extending these functions to track whether a page/access
fault occurs when we execute unprivilege load/store instruction.

To make things simpler and debugable, we reduce number of places which
can potentially generate a page/access fault by making all unprivilege
load/store functions as regular (non-inline) functions.

Signed-off-by: Anup Patel <anup.patel@wdc.com>
Reviewed-by: Atish Patra <atish.patra@wdc.com>
2019-05-24 08:22:47 +05:30
Anup Patel
95b7480ab4 lib: Factor-out TLB management from IPI management
This patch factor-out TLB management from IPI management to separate
sources sbi_tlb.c and sbi_tlb.h.

Signed-off-by: Anup Patel <anup.patel@wdc.com>
Reviewed-by: Atish Patra <atish.patra@wdc.com>
2019-05-24 08:22:47 +05:30
Anup Patel
2dfed32c46 lib: Add a simple brain-dead allocator to manage extra scratch space
We have extra space above scratch space (sbi_scratch) which we are
currently using to manage per-HART IPI data and TLB request management.

In future, more parts of OpenSBI will use the extra scratch space so
it will become difficult to manage extra scratch space using just
defines and macros.

This patch adds a simple brain-dead allocator to manage extra scratch
space. This allocator never expects anything to be free-ed hence it
keeps incrementing to next allocation offset until it runs-out of space.

In future, we can have more sophisticated allocator which will allow
us to re-claim free-ed space and also allows us to track owner of
allocated space.

Signed-off-by: Anup Patel <anup.patel@wdc.com>
Reviewed-by: Atish Patra <atish.patra@wdc.com>
2019-05-24 08:22:47 +05:30
Anup Patel
4e2cd47820 lib: Flush everything when remote TLB flush range is too large
On latest Linux kernel (i.e. 5.2-rc1), we get large TLB flush
request for user space addresses (typically, start=x and end=-1).
This is caused by Linux kernel commit a21344dfc6 ("riscv: fix
sbi_remote_sfence_vma{,_asid}").

It's not practical to execute large number of sfence instructions
for a large TLB flush range because it takes too much time and
eventually causes CPU stall in Linux kernel.

This patch addresses above issue by upgrading TLB flush range to
TLB flush all whenever TLB flush range is greater than 1GB.

Signed-off-by: Anup Patel <anup.patel@wdc.com>
Reviewed-by: Atish Patra <atish.patra@wdc.com>
2019-05-21 10:06:08 +05:30
Anup Patel
392749f633 docs: Add documentation about dynamic firmware
This patch adds documenation about dynamic firmware.

Signed-off-by: Anup Patel <anup.patel@wdc.com>
Reviewed-by: Alistair Francis <alistair.francis@wdc.com>
Reviewed-by: Atish Patra <atish.patra@wdc.com>
2019-05-10 12:26:22 +05:30
Anup Patel
a4c2f50b64 platform: Enable dynamic firmware for appropriate platforms
This patch enables FW_DYNAMIC option (i.e. dynamic firmware) for
all appropriate/applicable platforms.

Signed-off-by: Anup Patel <anup.patel@wdc.com>
Reviewed-by: Alistair Francis <alistair.francis@wdc.com>
2019-05-10 12:26:22 +05:30
Anup Patel
bae54f7645 firmware: Add fw_dynamic firmware
This patch provides first-cut implementation of fw_dynamic firmware.

As compared to fw_jump and fw_payload, the fw_dynamic obtains next
address, next mode and OpenSBI options from struct fw_dynamic_info.

The previous booting stage can create struct fw_dynamic_info in memory
and pass address of struct fw_dynamic_info in 'a2' register. Also, the
struct fw_dynamic_info has versioning as well so changes to the struct
fw_dynamic_info can be done in a backward compatible manner.

Signed-off-by: Anup Patel <anup.patel@wdc.com>
Reviewed-by: Atish Patra <atish.patra@wdc.com>
2019-05-10 12:26:22 +05:30
Anup Patel
25472de89e firmware: Allow firmwares to provide next mode and options
This patch extends existing firmwares (i.e. fw_jump and fw_payload)
to explicitly provide next mode and options to fw_base.

We also introduce fw_save_info() which is called by fw_base very
early on boot HART. This function can be used by existing firmwares
(i.e. fw_jump and fw_payload) to save information passed by previous
booting stage.

Overall, this is a preparatory patch for implementing fw_dynamic.

Signed-off-by: Anup Patel <anup.patel@wdc.com>
Reviewed-by: Alistair Francis <alistair.francis@wdc.com>
Reviewed-by: Atish Patra <atish.patra@wdc.com>
2019-05-10 12:26:22 +05:30
Karsten Merker
243a5e0532 docs: update CONTRIBUTORS.md from git history
OpenSBI has recently gained a CONTRIBUTORS.md file as a way
to make contributions to OpenSBI more visible.  Add previous
contributors from the git history who have acked their
inclusion in the list to the file.

Signed-off-by: Karsten Merker <merker@debian.org>
Acked-by: Alistair Francis <alistair@alistair23.me>
Acked-by: Anup Patel <anup.patel@wdc.com>
Acked-by: Atish Patra <atish.patra@wdc.com>
Acked-by: Bin Meng <bmeng.cn@gmail.com>
Acked-by: Damien Le Moal <damien.lemoal@wdc.com>
Acked-by: Nick Kossifidis <mickflemm@gmail.com>
Acked-by: Shawn Chang <citypw@gmail.com>
Acked-by: Xiang Wang <wxjstz@126.com>
2019-05-06 11:09:03 +05:30
Karsten Merker
0d33a981ec docs: miscellaneous documentation fixes and updates
- fix some broken hyperlinks
- add additional hyperlinks to references to external documents
- reformat some paragraphs to keep lines under 80 characters
- unify the enumeration style between different parts of the
  documentation
- fix spelling/grammar mistakes
- extend the copyright notice in README.md to be the same as the
  one in COPYING.BSD

Signed-off-by: Karsten Merker <merker@debian.org>
Reviewed-by: Atish Patra <atish.patra@wdc.com>
2019-05-06 11:05:33 +05:30
Loys Ollivier
3bb2d25f44 Update sifive_fu540.md
Fix typo on parenthesis.
2019-05-06 09:42:56 +05:30
Karsten Merker
f9643f3472 Makefile: explicitly disable PIE
The various available RISC-V toolchains differ in their default
configuration regarding PIE, e.g. the buildroot RISC-V toolchain
has PIE disabled by default while the Debian toolchain has it
enabled by default.

OpenSBI currently doesn't support being built with PIE enabled,
therefore disable it explicitly by passing "-fno-pie -no-pie" in
CFLAGS.

Signed-off-by: Karsten Merker <merker@debian.org>
Acked-by: Anup Patel <anup.patel@wdc.com>
2019-04-30 09:21:47 +05:30
Xiang Wang
c1d01b0c2e platform/common/libfdt: fix unnecessary multiple inclusions
Signed-off-by: Xiang Wang <wxjstz@126.com>
2019-04-25 10:23:31 -07:00
Shawn Chang
03ec350c83 docs: Add a payload section about coreboot support #116
Signed-off-by: Shawn Chang <citypw@gmail.com>
2019-04-25 09:47:13 +05:30
Olof Johansson
10baa64c02 all: run clang-format and update checked-in files
Noisy commit, no functional changes.

Generated with an current upstream clang-format and:

clang-format -i $(find . -name \*.[ch])

Signed-off-by: Olof Johansson <olof@lixom.net>
2019-04-24 09:49:46 +05:30
Olof Johansson
fbf986ac2a all: Annotate some tables to have clang-format leave them alone
One of the shortcomings of clang-format is that it doesn't allow
for aligned define tables, which is used for a number of constants.

Add annotation to disable the automatic formatting where needed.

Signed-off-by: Olof Johansson <olof@lixom.net>
2019-04-24 09:49:46 +05:30
Olof Johansson
97fb8c0e3b libfdt: don't try to clang-format
Add an empty clang-format to disable reformatting of imported code and
make it easier to merge in upstream changes of that project over time.

Signed-off-by: Olof Johansson <olof@lixom.net>
2019-04-24 09:49:46 +05:30
Olof Johansson
1e43ce75ff top: add .clang-format
Add a clang-format to automate consistent code formatting.

Automating coding style reformatting removes a lot of manual
checkpatch-type fixups, and can easily be implemented as a linter in
code review environments.

Signed-off-by: Olof Johansson <olof@lixom.net>
2019-04-24 09:49:46 +05:30
Nick Kossifidis
804b997ed4 lib: Redirect unhandled traps from non-M modes to S mode
In case we didn't handle a trap with one of the available
handlers, check if the trap comes from S or U mode and
redirect it to S mode's trap handler.

Signed-off-by: Nick Kossifidis <mick@ics.forth.gr>
2019-04-22 09:56:20 +05:30
Atish Patra
194dbbe5a1 doc: Update docs as per latest kernel/u-boot status.
All dependant patches are merged in U-Boot and Linux kernel now.
Update the unleashed guide to reflect that and fix the documentation
about tftp loading path as well.

Signed-off-by: Atish Patra <atish.patra@wdc.com>
Reviewed-by: Bin Meng <bmeng.cn@gmail.com>
2019-04-15 10:00:04 +05:30
Anup Pate
b2cd5fda61 top: Add CONTRIBUTORS.md file
We add CONTRIBUTORS.md file to provide a list of individuals and
organizations actively contributing to the OpenSBI project.

Signed-off-by: Anup Patel <anup.patel@wdc.com>
2019-04-15 09:54:10 +05:30
Karsten Merker
743e8ae6e7 docs: qemu/virt platform documentation fixes and updates
- Correct the payload address in the RV64 examples that use
  fw_jump.elf.

- Change the qemu console configuration in the examples from
  "-display none -serial stdio" to "-nographic". This results in
  qemu handing down a CTRL-C on the emulated console to the VM
  instead of terminating the qemu process.

- Provide examples for RV32.

- Various text corrections.

Signed-off-by: Karsten Merker <merker@debian.org>
Reviewed-by: Alistair Francis <alistair.francis@wdc.com>
2019-04-15 08:52:59 +05:30
Atish Patra
999823c597 lib: Optimize TLB flush IPIs
Simulatenous requests for tlbflush IPIs can have overlapping address
ranges.

Ignore if address range is same or within already existing fifo entries.
Update the tlb flush info in fifo directly if the one of the existing
entry lies within the new flush request.
Delete all entries if flush all request is recieved for the vma.

Signed-off-by: Atish Patra <atish.patra@wdc.com>
2019-04-10 15:46:35 +05:30
Atish Patra
110eef44f0 lib: Provide a lock enabled iteration of fifo.
Implement a lock enabled iteration for fifo so that
caller can determine if next entry can be skipped or
any existing entries in fifo can be updated before enqueue.

Signed-off-by: Atish Patra <atish.patra@wdc.com>
2019-04-10 15:46:35 +05:30
Anup Patel
54f31e8209 TOP: Allow building platform out-of-tree
This patch extends our current build-system for building platform
sources which are not part of OpenSBI sources.

For example:

Let's say we have out-of-tree ABC platform sources. We place these
sources under <XYZ>/ABC directory along with its config.mk and
objects.mk.

To build out-of-tree ABC platform from OpenSBI directory:
$ make PLATFORM_DIR=<XYZ>/ABC
OR
$ make PLATFORM_DIR=<XYZ> PLATFORM=ABC

To build out-of-tree ABC platform from <XYZ>/ABC directory:
$ make PLATFORM_DIR=<XYZ>/ABC -C <path_to_opensbi>
OR
$ make PLATFORM_DIR=<XYZ> PLATFORM=ABC -C <path_to_opensbi>

Signed-off-by: Anup Patel <anup.patel@wdc.com>
Reviewed-by: Alistair Francis <alistair.francis@wdc.com>
2019-04-09 09:14:09 +05:30
Alistair Francis
40086daa62 lib: Fix the ecall macro definitions
Fix the ECALL definitions to matc the latest information in the
privlidge spec table 5.5.

Signed-off-by: Alistair Francis <alistair.francis@wdc.com>
2019-04-06 19:06:22 +05:30
Xiang Wang
09f976802b firmware: Fix source fdt alignment
When I tried to start opensbi with coreboot, I found that aligning to a 16-byte
boundary would make a copy error.

Corrected to align to an machine word length boundary.

Signed-off-by: Xiang Wang <wxjstz@126.com>
2019-04-04 09:10:28 +05:30
Anup Patel
3fbe233a15 lib: Pack struct sbi_fifo
This patch reduces memory consumed by struct sbi_fifo by droping
redundant "head" member and using u16 in-place of "unsigned long".

Signed-off-by: Anup Patel <anup.patel@wdc.com>
2019-04-03 13:48:38 -07:00
Anup Patel
9dc95021db lib: More improvements to sbi_fifo
This patch does following improvements to sbi_fifo:
1. Use valid SBI_Exxxx error codes instead of -1
2. The sbi_fifo_is_full() and sbi_fifo_is_empty() did
   not acquire qlock before accessing head and tail
   hence fixed it
3. Added avail member for ease in debugging and simplifying
   head/tail updates.

Due to above changes size of sbi_fifo changes from 48 bytes
to 56 bytes.

Signed-off-by: Anup Patel <anup.patel@wdc.com>
2019-04-03 13:48:38 -07:00
Anup Patel
6dc1b0f6e2 docs: Update mailing list details in contributing.md
We now have an OpenSBI mailing list available for development
and discussiong so update contributing.md accordingly. The
Github PR based review and issue tracking will also continue
to exist.

Signed-off-by: Anup Patel <anup.patel@wdc.com>
2019-04-03 13:48:22 -07:00
Atish Patra
f700216cb5 lib: Use a fifo to keep track of sfence related IPIs.
Currently, there is no provision for tracking multiple IPIs sent
to a single hart at the same time by different harts.

Use a fifo manage the outstanding requests. While dequeueing, read all
the entries once, because we have only 1 bit to track the type of IPI.
Once the queue is full, busy wait until the there is space available in
queue. This is not the most elegant approach. It should be changed in
favor of a wakeup event once available in opensbi.

Signed-off-by: Atish Patra <atish.patra@wdc.com>
2019-04-03 09:57:42 +05:30
Atish Patra
1eba298b0d lib: Increase the scratch space to 512 bytes.
Currently scratch space per hart is 256 bytes. Increase it to 512 bytes
to accomodate ipi queue.

Signed-off-by: Atish Patra <atish.patra@wdc.com>
2019-04-03 09:57:42 +05:30
Atish Patra
fd5418d92c lib: Introduce a tlb info type.
Add a tlb info to distinguish between different type of tlb flush
request pending.

Signed-off-by: Atish Patra <atish.patra@wdc.com>
2019-04-03 09:57:42 +05:30
Atish Patra
8334a88c63 lib: Add a fifo implementation.
Implement a fifo to accomodate outstanding IPIs for a specific hart
at the same time.

Signed-off-by: Atish Patra <atish.patra@wdc.com>
2019-04-03 09:57:42 +05:30
Damien Le Moal
14dadeab09 kendryte/k210: Fix file headers
Add missing SPDX and copyright information.

Signed-off-by: Damien Le Moal <damien.lemoal@wdc.com>
2019-04-03 10:22:57 +09:00
Damien Le Moal
bce71a00bd README: Update license information
Add information regarding the Apache License Version 2.0 of some of the
Kendryte/k210 platform files. Also repeat this information in a new
ThirdPartyNotices.md file.

Signed-off-by: Damien Le Moal <damien.lemoal@wdc.com>
2019-04-03 10:22:57 +09:00
Anup Patel
78c87cd13a include: Make mstatus parameter optional for get_insn()
The mstatus parameter of get_insn() is used to return MSTATUS CSR
value which get_insn() saw. Most of the get_insn() callers don't
use the value returned in mstatus so this patch makes mstatus
parameter optional for get_insn().

Signed-off-by: Anup Patel <anup.patel@wdc.com>
2019-04-01 10:10:38 +05:30
Anup Patel
13877c3a67 include: Rename sbi_unpriv.h to riscv_unpriv.h
The sbi_unpriv.h has quite a few load_xyz() and store_xyz() helper
routines based on RISC-V inline assembly for unpriviledged accesses
from M-mode. These helper routines are similar to helper routines
present in riscv_locks.h, riscv_io.h, and riscv_atomic.h so let's
rename sbi_unpriv.h to riscv_unpriv.h.

Signed-off-by: Anup Patel <anup.patel@wdc.com>
2019-04-01 10:10:38 +05:30
Anup Patel
cfff0126ab lib: Remove unused mepc arg from load_xyz() and store_xyz() functions
This patch removes unused mepc arg from load_xyz() and store_xyz()
unpriviledge access functions.

Signed-off-by: Anup Patel <anup.patel@wdc.com>
2019-04-01 10:10:38 +05:30
Bin Meng
f9cfe301c9 lib: Disable the boot prints if SBI_SCRATCH_NO_BOOT_PRINTS is set
Use the newly introduced "options" in "struct sbi_scratch" to
conditionally disable the boot prints.

Signed-off-by: Bin Meng <bmeng.cn@gmail.com>
2019-03-29 15:49:11 +05:30
Bin Meng
215c200ccb lib: Group all prints during boot into sbi_boot_prints()
Refactor the codes a little bit to put all prints during boot into
sbi_boot_prints().

Signed-off-by: Bin Meng <bmeng.cn@gmail.com>
2019-03-29 15:49:11 +05:30
Bin Meng
132f3e024b firmware: Introduce "options" in "struct sbi_scratch"
Introduce "options" in "struct sbi_scratch" and firmware can update
it based on optional compile time flags before calling sbi_init().

Signed-off-by: Bin Meng <bmeng.cn@gmail.com>
2019-03-29 15:49:11 +05:30
Bin Meng
e921fc2691 platform: plic: Fix comments of programming the interrupt enable register
The codes that currently program the interrupt enable register for
S-mode disagrees with what the comments say. Fix the comments.

While we are here, add one line comment to describe what is done
for M-mode too.

Signed-off-by: Bin Meng <bmeng.cn@gmail.com>
2019-03-18 18:18:16 +05:30
Atish Patra
6c39ea99ee lib: Return ENOTSUPP incase of invalid SBI function ID
OpenSBI should show error trace only if any valid SBI function
does not perform as expected.

However, OpenSBI should show notify the caller with a negative
error if given SBI function ID is not valid.

Signed-off-by: Atish Patra <atish.patra@wdc.com>
2019-03-14 20:44:22 +05:30
Bin Meng
312850148a platform: plic: Bypass interrupt ID 0's priority programming
Per PLIC spec, interrupt ID 0 is defined to mean "no interrupt".
We should bypass it.

Signed-off-by: Bin Meng <bmeng.cn@gmail.com>
2019-03-14 20:43:35 +05:30
Bin Meng
ebe351e550 platform: plic: Fix plic_set_priority()
At present plic_set_priority() ignores the 'source' and the priority
register to be programmed is constant. Fix it.

Signed-off-by: Bin Meng <bmeng.cn@gmail.com>
2019-03-14 20:43:35 +05:30
Atish Patra
ab91c143a3 firmware: Move scratch setup to _start instead of _start_warm
Scratch space setup needs to be done once for reboot for each
hart. _start_warm may be called several times if hart hotplug
is implemented.

Move scratch space setup to the beginning so that it is done
only once.

Signed-off-by: Atish Patra <atish.patra@wdc.com>
2019-03-14 20:43:09 +05:30
Atish Patra
1e24e21d56 lib: Fix full tlb flush behavior
Currently, global page mappings are not flushed if start and size
arguments are zero.

Flush entire TLB if both size and start argument is passed as zero.

Fixes : 90cb491 (lib: Implement sfence.vma correctly)

Signed-off-by: Atish Patra <atish.patra@wdc.com>
2019-03-14 20:41:13 +05:30
Bin Meng
896870e9b0 platform: fu540: Fix cosmetic styling issues
There are some spaces or mixed usage of spaces and tabs in the macro
definition. Change to use tab consistently.

Signed-off-by: Bin Meng <bmeng.cn@gmail.com>
2019-03-13 23:53:21 +05:30
Bin Meng
6cd668df12 docs: firmware: Fix spelling of U-Boot
It's U-Boot, not U-boot.

Signed-off-by: Bin Meng <bmeng.cn@gmail.com>
2019-03-13 23:53:21 +05:30
Atish Patra
90cb4917b5 lib: Implement sfence.vma correctly.
Currently, OpenSBI doesn't distinguish between sfence.vma
and sfence.vm asid calls. Moreover, it ignores the page
ranges and just flush entire TLB everytime.

Fix the sfence implementation by keeping all the tlb flush
info in scratch area.

The relevant Linux kernel code was added by
https://patchwork.kernel.org/project/linux-riscv/list/?series=89695

However, this patch is backward compatible with older version kernel
that doesn't have the above patches as well.

Fixes #87
Signed-off-by: Atish Patra <atish.patra@wdc.com>
2019-03-12 22:07:25 +05:30
Alistair Francis
508a27204c lib: Create a sbi_ipi_data structure
Create a sbi_ipi_data structure that holds unpacked IPI information. At
the same time remove ipi_type from the sbi_scratch struct and use a
fixed offset to access it.

This structure fits in behind the sbi_scratch structure.

This fixes https://github.com/riscv/opensbi/issues/81

Signed-off-by: Alistair Francis <alistair.francis@wdc.com>
2019-03-10 21:08:21 +05:30
Atish Patra
007a6b26d9 firmware: Reset all registers and flush icache
A warm reset using reset button may put icache and registers
in non-coherent state.

Flush the icache and reset all registers for every hart.

Signed-off-by: Atish Patra <atish.patra@wdc.com>
2019-03-07 08:07:18 +05:30
Atish Patra
b225583881 firmware: Add nop to reduce bus traffic.
All the non-boot harts run in a tight loop which may cause a heavy load
on the memory bus. This may delay the boot hart to complete the cold boot
process.

Introduce few nop that will ease up the traffic.

Signed-off-by: Atish Patra <atish.patra@wdc.com>
2019-03-07 08:07:18 +05:30
Atish Patra
69d794cbcb Revert "firmware: Add a barrier instruction for wait for boot hart"
This reverts commit 05602e2bf4.

Introducing a fence causes warm reset issue to reappear. Revert it
for the time being.
2019-03-07 08:07:18 +05:30
Xiang Wang
9eb8f0f90d platform: Make the platform read-only
platform should be a read-only variable, if it is placed in the data
segment, it may be exploited.

Signed-off-by: Xiang Wang <wxjstz@126.com>
2019-03-06 11:10:35 -08:00
Atish Patra
27fae182dc firmware: Reset all the general purpose registers to zero.
A warm reset by pressing the reset button may not initialize all the
registers to zero. Do it for every hart during warm boot.

Signed-off-by: Atish Patra <atish.patra@wdc.com>
2019-03-06 08:59:54 +05:30
Atish Patra
d4dd2b37f3 firmware: Ensure the mtvec is updated.
Signed-off-by: Atish Patra <atish.patra@wdc.com>
2019-03-06 08:59:54 +05:30
Atish Patra
754ff34108 firmware: Fix a typo
Signed-off-by: Atish Patra <atish.patra@wdc.com>
2019-03-06 08:59:54 +05:30
Atish Patra
86cc9b8633 lib:platform: Fix sbi_getc return type.
As per the current SBI specification, sbi_getc should return
an int instead of char.

In case of FIFO is empty, return -1 as per the specification.

Reported-by: Sergi Granell <xerpi.g.12@gmail.com>
Suggested-by:Thadeu Lima de Souza Cascardo <cascardo@cascardo.eti.br>
Signed-off-by: Atish Patra <atish.patra@wdc.com>
2019-03-05 14:05:12 +05:30
Xiang Wang
05602e2bf4 firmware: Add a barrier instruction for wait for boot hart
Multi-core communication via memory requires the addition of a barrier
instructions to ensure cache coherency.

Signed-off-by: Xiang Wang <wxjstz@126.com>
2019-03-05 09:09:40 +05:30
Xiang Wang
1c87f0f9b1 firmware: Move _boot_hart_done to the data section
Writable code section can cause some security problems, so move _boot_hart_done
to the data section

Signed-off-by: Xiang Wang <wxjstz@126.com>
2019-03-05 09:09:40 +05:30
Xiang Wang
a72467f574 Add tags to .gitignore for being development friendly
Signed-off-by: Xiang Wang <wxjstz@126.com>
2019-03-05 09:07:23 +05:30
Andreas Schwab
87fbcf9376 Fix missing quotes in Makefile 2019-02-28 09:02:54 +05:30
Andreas Schwab
178a0307a2 Fix makefile dependency generation 2019-02-28 09:02:54 +05:30
141 changed files with 4076 additions and 2844 deletions

16
.clang-format Normal file
View File

@@ -0,0 +1,16 @@
AlignConsecutiveAssignments: true
AlignEscapedNewlines: Left
AlignTrailingComments: true
AllowShortFunctionsOnASingleLine: None
BraceWrapping:
AfterFunction: true
BreakBeforeBraces: Custom
BreakStringLiterals: false
ContinuationIndentWidth: 8
Cpp11BracedListStyle: false
IndentWidth: 8
ReflowComments: false
SortIncludes: false
SpacesInContainerLiterals: false
TabWidth: 8
UseTab: Always

3
.gitignore vendored
View File

@@ -6,3 +6,6 @@
#Build & install directories #Build & install directories
build/ build/
install/ install/
# Development friendly files
tags

27
CONTRIBUTORS.md Normal file
View File

@@ -0,0 +1,27 @@
List of OpenSBI Contributors (Alphabetically sorted)
====================================================
* **[Western Digital Corporation](https://www.wdc.com/)**
* Project initiator and maintainer
* Copyright (c) 2019 Western Digital Corporation or its affiliates
* Alistair Francis <alistair@alistair23.me>
* Andreas Schwab <schwab@suse.de>
* Anup Patel <anup.patel@wdc.com>
* Atish Patra <atish.patra@wdc.com>
* Bin Meng <bmeng.cn@gmail.com>
* Damien Le Moal <damien.lemoal@wdc.com>
* Karsten Merker <merker@debian.org>
* Nick Kossifidis <mickflemm@gmail.com>
* Shawn Chang <citypw@gmail.com>
* Xiang Wang <wxjstz@126.com>

View File

@@ -1,7 +1,8 @@
The 2-Clause BSD License The 2-Clause BSD License
SPDX short identifier: BSD-2-Clause SPDX short identifier: BSD-2-Clause
Copyright (c) 2019 Western Digital Corporation or its affiliates. Copyright (c) 2019 Western Digital Corporation or its affiliates and other
contributors.
Redistribution and use in source and binary forms, with or without Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met: modification, are permitted provided that the following conditions are met:
@@ -22,4 +23,3 @@ LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 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 (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

114
Makefile
View File

@@ -33,6 +33,17 @@ endif
ifeq ($(install_dir),$(build_dir)) ifeq ($(install_dir),$(build_dir))
$(error Install directory is same as build directory.) $(error Install directory is same as build directory.)
endif endif
ifdef PLATFORM_DIR
platform_dir_path=$(shell readlink -f $(PLATFORM_DIR))
ifdef PLATFORM
platform_parent_dir=$(platform_dir_path)
else
PLATFORM=$(shell basename $(platform_dir_path))
platform_parent_dir=$(subst $(PLATFORM),,$(platform_dir_path))
endif
else
platform_parent_dir=$(src_dir)/platform
endif
# Check if verbosity is ON for build process # Check if verbosity is ON for build process
CMD_PREFIX_DEFAULT := @ CMD_PREFIX_DEFAULT := @
@@ -43,16 +54,17 @@ else
endif endif
# Setup path of directories # Setup path of directories
export platform_subdir=platform/$(PLATFORM) export platform_subdir=$(PLATFORM)
export platform_dir=$(CURDIR)/$(platform_subdir) export platform_src_dir=$(platform_parent_dir)/$(platform_subdir)
export platform_common_dir=$(CURDIR)/platform/common export platform_build_dir=$(build_dir)/platform/$(platform_subdir)
export include_dir=$(CURDIR)/include export include_dir=$(CURDIR)/include
export lib_dir=$(CURDIR)/lib export libsbi_dir=$(CURDIR)/lib/sbi
export libsbiutils_dir=$(CURDIR)/lib/utils
export firmware_dir=$(CURDIR)/firmware export firmware_dir=$(CURDIR)/firmware
# Find library version # Find library version
OPENSBI_VERSION_MAJOR=`grep MAJOR $(include_dir)/sbi/sbi_version.h | sed 's/.*MAJOR.*\([0-9][0-9]*\)/\1/'` OPENSBI_VERSION_MAJOR=`grep "define OPENSBI_VERSION_MAJOR" $(include_dir)/sbi/sbi_version.h | sed 's/.*MAJOR.*\([0-9][0-9]*\)/\1/'`
OPENSBI_VERSION_MINOR=`grep MINOR $(include_dir)/sbi/sbi_version.h | sed 's/.*MINOR.*\([0-9][0-9]*\)/\1/'` OPENSBI_VERSION_MINOR=`grep "define OPENSBI_VERSION_MINOR" $(include_dir)/sbi/sbi_version.h | sed 's/.*MINOR.*\([0-9][0-9]*\)/\1/'`
# Setup compilation commands # Setup compilation commands
ifdef CROSS_COMPILE ifdef CROSS_COMPILE
@@ -85,40 +97,40 @@ endif
# Setup list of objects.mk files # Setup list of objects.mk files
ifdef PLATFORM ifdef PLATFORM
platform-object-mks=$(shell if [ -d $(platform_dir) ]; then find $(platform_dir) -iname "objects.mk" | sort -r; fi) platform-object-mks=$(shell if [ -d $(platform_src_dir)/ ]; then find $(platform_src_dir) -iname "objects.mk" | sort -r; fi)
platform-common-object-mks=$(shell if [ -d $(platform_common_dir) ]; then find $(platform_common_dir) -iname "objects.mk" | sort -r; fi)
endif endif
lib-object-mks=$(shell if [ -d $(lib_dir) ]; then find $(lib_dir) -iname "objects.mk" | sort -r; fi) libsbi-object-mks=$(shell if [ -d $(libsbi_dir) ]; then find $(libsbi_dir) -iname "objects.mk" | sort -r; fi)
libsbiutils-object-mks=$(shell if [ -d $(libsbiutils_dir) ]; then find $(libsbiutils_dir) -iname "objects.mk" | sort -r; fi)
firmware-object-mks=$(shell if [ -d $(firmware_dir) ]; then find $(firmware_dir) -iname "objects.mk" | sort -r; fi) firmware-object-mks=$(shell if [ -d $(firmware_dir) ]; then find $(firmware_dir) -iname "objects.mk" | sort -r; fi)
# Include platform specifig config.mk # Include platform specifig config.mk
ifdef PLATFORM ifdef PLATFORM
include $(platform_dir)/config.mk include $(platform_src_dir)/config.mk
endif endif
# Include all object.mk files # Include all object.mk files
ifdef PLATFORM ifdef PLATFORM
include $(platform-object-mks) include $(platform-object-mks)
include $(platform-common-object-mks)
endif endif
include $(lib-object-mks) include $(libsbi-object-mks)
include $(libsbiutils-object-mks)
include $(firmware-object-mks) include $(firmware-object-mks)
# Setup list of objects # Setup list of objects
lib-objs-path-y=$(foreach obj,$(lib-objs-y),$(build_dir)/lib/$(obj)) libsbi-objs-path-y=$(foreach obj,$(libsbi-objs-y),$(build_dir)/lib/sbi/$(obj))
libsbiutils-objs-path-y=$(foreach obj,$(libsbiutils-objs-y),$(build_dir)/lib/utils/$(obj))
ifdef PLATFORM ifdef PLATFORM
platform-objs-path-y=$(foreach obj,$(platform-objs-y),$(build_dir)/$(platform_subdir)/$(obj)) platform-objs-path-y=$(foreach obj,$(platform-objs-y),$(platform_build_dir)/$(obj))
platform-dtb-path-y=$(foreach obj,$(platform-dtb-y),$(build_dir)/$(platform_subdir)/$(obj)) platform-dtb-path-y=$(foreach obj,$(platform-dtb-y),$(platform_build_dir)/$(obj))
platform-common-objs-path-y=$(foreach obj,$(platform-common-objs-y),$(build_dir)/platform/common/$(obj)) firmware-bins-path-y=$(foreach bin,$(firmware-bins-y),$(platform_build_dir)/firmware/$(bin))
firmware-bins-path-y=$(foreach bin,$(firmware-bins-y),$(build_dir)/$(platform_subdir)/firmware/$(bin))
endif endif
firmware-elfs-path-y=$(firmware-bins-path-y:.bin=.elf) firmware-elfs-path-y=$(firmware-bins-path-y:.bin=.elf)
firmware-objs-path-y=$(firmware-bins-path-y:.bin=.o) firmware-objs-path-y=$(firmware-bins-path-y:.bin=.o)
# Setup list of deps files for objects # Setup list of deps files for objects
deps-y=$(platform-objs-path-y:.o=.dep) deps-y=$(platform-objs-path-y:.o=.dep)
deps-y+=$(platform-common-objs-path-y:.o=.dep) deps-y+=$(libsbi-objs-path-y:.o=.dep)
deps-y+=$(lib-objs-path-y:.o=.dep) deps-y+=$(libsbiutils-objs-path-y:.o=.dep)
deps-y+=$(firmware-objs-path-y:.o=.dep) deps-y+=$(firmware-objs-path-y:.o=.dep)
# Setup platform ABI, ISA and Code Model # Setup platform ABI, ISA and Code Model
@@ -137,10 +149,9 @@ ifndef PLATFORM_RISCV_CODE_MODEL
endif endif
# Setup compilation commands flags # Setup compilation commands flags
GENFLAGS = -I$(platform_dir)/include GENFLAGS = -I$(platform_src_dir)/include
GENFLAGS += -I$(platform_common_dir)/include
GENFLAGS += -I$(include_dir) GENFLAGS += -I$(include_dir)
GENFLAGS += $(platform-common-genflags-y) GENFLAGS += $(libsbiutils-genflags-y)
GENFLAGS += $(platform-genflags-y) GENFLAGS += $(platform-genflags-y)
GENFLAGS += $(firmware-genflags-y) GENFLAGS += $(firmware-genflags-y)
@@ -152,6 +163,7 @@ CFLAGS += -mcmodel=$(PLATFORM_RISCV_CODE_MODEL)
CFLAGS += $(GENFLAGS) CFLAGS += $(GENFLAGS)
CFLAGS += $(platform-cflags-y) CFLAGS += $(platform-cflags-y)
CFLAGS += $(firmware-cflags-y) CFLAGS += $(firmware-cflags-y)
CFLAGS += -fno-pie -no-pie
CPPFLAGS += $(GENFLAGS) CPPFLAGS += $(GENFLAGS)
CPPFLAGS += $(platform-cppflags-y) CPPFLAGS += $(platform-cppflags-y)
@@ -213,7 +225,7 @@ compile_cpp = $(CMD_PREFIX)mkdir -p `dirname $(1)`; \
$(CPP) $(CPPFLAGS) -x c $(2) | grep -v "\#" > $(1) $(CPP) $(CPPFLAGS) -x c $(2) | grep -v "\#" > $(1)
compile_cc_dep = $(CMD_PREFIX)mkdir -p `dirname $(1)`; \ compile_cc_dep = $(CMD_PREFIX)mkdir -p `dirname $(1)`; \
echo " CC-DEP $(subst $(build_dir)/,,$(1))"; \ echo " CC-DEP $(subst $(build_dir)/,,$(1))"; \
echo `dirname $(1)`/ \\ > $(1) && \ printf %s `dirname $(1)`/ > $(1) && \
$(CC) $(CFLAGS) $(call dynamic_flags,$(1),$(2)) \ $(CC) $(CFLAGS) $(call dynamic_flags,$(1),$(2)) \
-MM $(2) >> $(1) || rm -f $(1) -MM $(2) >> $(1) || rm -f $(1)
compile_cc = $(CMD_PREFIX)mkdir -p `dirname $(1)`; \ compile_cc = $(CMD_PREFIX)mkdir -p `dirname $(1)`; \
@@ -221,7 +233,7 @@ compile_cc = $(CMD_PREFIX)mkdir -p `dirname $(1)`; \
$(CC) $(CFLAGS) $(call dynamic_flags,$(1),$(2)) -c $(2) -o $(1) $(CC) $(CFLAGS) $(call dynamic_flags,$(1),$(2)) -c $(2) -o $(1)
compile_as_dep = $(CMD_PREFIX)mkdir -p `dirname $(1)`; \ compile_as_dep = $(CMD_PREFIX)mkdir -p `dirname $(1)`; \
echo " AS-DEP $(subst $(build_dir)/,,$(1))"; \ echo " AS-DEP $(subst $(build_dir)/,,$(1))"; \
echo `dirname $(1)`/ \\ > $(1) && \ printf %s `dirname $(1)`/ > $(1) && \
$(AS) $(ASFLAGS) $(call dynamic_flags,$(1),$(2)) \ $(AS) $(ASFLAGS) $(call dynamic_flags,$(1),$(2)) \
-MM $(2) >> $(1) || rm -f $(1) -MM $(2) >> $(1) || rm -f $(1)
compile_as = $(CMD_PREFIX)mkdir -p `dirname $(1)`; \ compile_as = $(CMD_PREFIX)mkdir -p `dirname $(1)`; \
@@ -241,8 +253,9 @@ compile_dts = $(CMD_PREFIX)mkdir -p `dirname $(1)`; \
$(DTC) $(DTCFLAGS) -o $(1) $(2) $(DTC) $(DTCFLAGS) -o $(1) $(2)
targets-y = $(build_dir)/lib/libsbi.a targets-y = $(build_dir)/lib/libsbi.a
targets-y += $(build_dir)/lib/libsbiutils.a
ifdef PLATFORM ifdef PLATFORM
targets-y += $(build_dir)/$(platform_subdir)/lib/libplatsbi.a targets-y += $(platform_build_dir)/lib/libplatsbi.a
targets-y += $(platform-dtb-path-y) targets-y += $(platform-dtb-path-y)
endif endif
targets-y += $(firmware-bins-path-y) targets-y += $(firmware-bins-path-y)
@@ -257,16 +270,19 @@ all: $(targets-y)
$(build_dir)/%.bin: $(build_dir)/%.elf $(build_dir)/%.bin: $(build_dir)/%.elf
$(call compile_objcopy,$@,$<) $(call compile_objcopy,$@,$<)
$(build_dir)/%.elf: $(build_dir)/%.o $(build_dir)/%.elf.ld $(build_dir)/$(platform_subdir)/lib/libplatsbi.a $(build_dir)/%.elf: $(build_dir)/%.o $(build_dir)/%.elf.ld $(platform_build_dir)/lib/libplatsbi.a
$(call compile_elf,$@,$@.ld,$< $(build_dir)/$(platform_subdir)/lib/libplatsbi.a) $(call compile_elf,$@,$@.ld,$< $(platform_build_dir)/lib/libplatsbi.a)
$(build_dir)/$(platform_subdir)/%.ld: $(src_dir)/%.ldS $(platform_build_dir)/%.ld: $(src_dir)/%.ldS
$(call compile_cpp,$@,$<) $(call compile_cpp,$@,$<)
$(build_dir)/lib/libsbi.a: $(lib-objs-path-y) $(build_dir)/lib/libsbi.a: $(libsbi-objs-path-y)
$(call compile_ar,$@,$^) $(call compile_ar,$@,$^)
$(build_dir)/$(platform_subdir)/lib/libplatsbi.a: $(lib-objs-path-y) $(platform-common-objs-path-y) $(platform-objs-path-y) $(build_dir)/lib/libsbiutils.a: $(libsbi-objs-path-y) $(libsbiutils-objs-path-y)
$(call compile_ar,$@,$^)
$(platform_build_dir)/lib/libplatsbi.a: $(libsbi-objs-path-y) $(libsbiutils-objs-path-y) $(platform-objs-path-y)
$(call compile_ar,$@,$^) $(call compile_ar,$@,$^)
$(build_dir)/%.dep: $(src_dir)/%.c $(build_dir)/%.dep: $(src_dir)/%.c
@@ -281,16 +297,28 @@ $(build_dir)/%.dep: $(src_dir)/%.S
$(build_dir)/%.o: $(src_dir)/%.S $(build_dir)/%.o: $(src_dir)/%.S
$(call compile_as,$@,$<) $(call compile_as,$@,$<)
$(build_dir)/$(platform_subdir)/%.dep: $(src_dir)/%.c $(platform_build_dir)/%.dep: $(platform_src_dir)/%.c
$(call compile_cc_dep,$@,$<) $(call compile_cc_dep,$@,$<)
$(build_dir)/$(platform_subdir)/%.o: $(src_dir)/%.c $(platform_build_dir)/%.o: $(platform_src_dir)/%.c
$(call compile_cc,$@,$<) $(call compile_cc,$@,$<)
$(build_dir)/$(platform_subdir)/%.dep: $(src_dir)/%.S $(platform_build_dir)/%.dep: $(platform_src_dir)/%.S
$(call compile_as_dep,$@,$<) $(call compile_as_dep,$@,$<)
$(build_dir)/$(platform_subdir)/%.o: $(src_dir)/%.S $(platform_build_dir)/%.o: $(platform_src_dir)/%.S
$(call compile_as,$@,$<)
$(platform_build_dir)/%.dep: $(src_dir)/%.c
$(call compile_cc_dep,$@,$<)
$(platform_build_dir)/%.o: $(src_dir)/%.c
$(call compile_cc,$@,$<)
$(platform_build_dir)/%.dep: $(src_dir)/%.S
$(call compile_as_dep,$@,$<)
$(platform_build_dir)/%.o: $(src_dir)/%.S
$(call compile_as,$@,$<) $(call compile_as,$@,$<)
$(build_dir)/%.dtb: $(src_dir)/%.dts $(build_dir)/%.dtb: $(src_dir)/%.dts
@@ -325,7 +353,7 @@ ifneq ($(platform-runcmd),)
$(platform-runcmd) $(RUN_ARGS) $(platform-runcmd) $(RUN_ARGS)
else else
ifdef PLATFORM ifdef PLATFORM
@echo Platform $(PLATFORM) doesn't specify a run command @echo "Platform $(PLATFORM) doesn't specify a run command"
@false @false
else else
@echo Run command only available when targeting a platform @echo Run command only available when targeting a platform
@@ -334,6 +362,7 @@ endif
endif endif
install_targets-y = install_libsbi install_targets-y = install_libsbi
install_targets-y += install_libsbiutils
ifdef PLATFORM ifdef PLATFORM
install_targets-y += install_libplatsbi install_targets-y += install_libplatsbi
install_targets-y += install_firmwares install_targets-y += install_firmwares
@@ -348,14 +377,19 @@ install_libsbi: $(build_dir)/lib/libsbi.a
$(call inst_header_dir,$(install_dir)/include,$(include_dir)/sbi) $(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_file,$(install_dir)/lib/libsbi.a,$(build_dir)/lib/libsbi.a)
.PHONY: install_libsbiutils
install_libsbiutils: $(build_dir)/lib/libsbiutils.a
$(call inst_header_dir,$(install_dir)/include,$(include_dir)/sbi_utils)
$(call inst_file,$(install_dir)/lib/libsbiutils.a,$(build_dir)/lib/libsbiutils.a)
.PHONY: install_libplatsbi .PHONY: install_libplatsbi
install_libplatsbi: $(build_dir)/$(platform_subdir)/lib/libplatsbi.a $(build_dir)/lib/libsbi.a install_libplatsbi: $(platform_build_dir)/lib/libplatsbi.a $(build_dir)/lib/libsbi.a $(build_dir)/lib/libsbiutils.a
$(call inst_file,$(install_dir)/$(platform_subdir)/lib/libplatsbi.a,$(build_dir)/$(platform_subdir)/lib/libplatsbi.a) $(call inst_file,$(install_dir)/platform/$(platform_subdir)/lib/libplatsbi.a,$(platform_build_dir)/lib/libplatsbi.a)
.PHONY: install_firmwares .PHONY: install_firmwares
install_firmwares: $(build_dir)/$(platform_subdir)/lib/libplatsbi.a $(build_dir)/lib/libsbi.a $(firmware-bins-path-y) install_firmwares: $(platform_build_dir)/lib/libplatsbi.a $(build_dir)/lib/libsbi.a $(build_dir)/lib/libsbiutils.a $(firmware-bins-path-y)
$(call inst_file_list,$(install_dir),$(build_dir),$(platform_subdir)/firmware,$(firmware-elfs-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_subdir)/firmware,$(firmware-bins-path-y)) $(call inst_file_list,$(install_dir),$(build_dir),platform/$(platform_subdir)/firmware,$(firmware-bins-path-y))
.PHONY: install_docs .PHONY: install_docs
install_docs: $(build_dir)/docs/latex/refman.pdf install_docs: $(build_dir)/docs/latex/refman.pdf

112
README.md
View File

@@ -1,56 +1,61 @@
Copyright (c) 2019 Western Digital Corporation or its affiliates
and other contributors.
RISC-V Open Source Supervisor Binary Interface (OpenSBI) RISC-V Open Source Supervisor Binary Interface (OpenSBI)
======================================================== ========================================================
The **RISC-V Supervisor Binary Interface (SBI)** is the recommended interface The **RISC-V Supervisor Binary Interface (SBI)** is the recommended interface
between: between:
1. A platform specific firmware running in M-mode and bootloader, hypervisor or 1. A platform-specific firmware running in M-mode and a bootloader, a
a general purpose OS executing in S-mode or HS-mode. hypervisor or a general-purpose OS executing in S-mode or HS-mode.
2. A hypervisor running in HS-mode and a bootloader or a general purpose OS 2. A hypervisor running in HS-mode and a bootloader or a general-purpose OS
executing in VS-mode. executing in VS-mode.
The *RISC-V SBI specification* is maintained as an independent project by the The *RISC-V SBI specification* is maintained as an independent project by the
RISC-V Foundation in [Github]. RISC-V Foundation on [Github] (https://github.com/riscv/riscv-sbi-doc).
The goal of the OpenSBI project is to provide an open-source reference The goal of the OpenSBI project is to provide an open-source reference
implementation of the RISC-V SBI specifications for platform specific firmwares implementation of the RISC-V SBI specifications for platform-specific firmwares
executing in M-mode (case 1 mentioned above). OpenSBI implementation can be executing in M-mode (case 1 mentioned above). An OpenSBI implementation can be
easily extended by RISC-V platform and system-on-chip vendors to fit a easily extended by RISC-V platform and system-on-chip vendors to fit a
particular hardware configuration. particular hardware configuration.
The main component of OpenSBI is provided in the form of a platform independent The main component of OpenSBI is provided in the form of a platform-independent
static library **libsbi.a** implementing the SBI interface. A firmware or static library **libsbi.a** implementing the SBI interface. A firmware or
bootloader implementation can link against this library to ensure conformance bootloader implementation can link against this library to ensure conformance
with the SBI interface specifications. *libsbi.a* also defines an interface for with the SBI interface specifications. *libsbi.a* also defines an interface for
integrating with platform specific operations provided by the platform firmware integrating with platform-specific operations provided by the platform firmware
implementation (e.g. console access functions, inter-processor interrupts implementation (e.g. console access functions, inter-processor interrupt
control, etc). control, etc).
To illustrate the use of *libsbi.a* library, OpenSBI also provides a set of To illustrate the use of the *libsbi.a* library, OpenSBI also provides a set of
platform specific support examples. For each example, a platform platform-specific support examples. For each example, a platform-specific
specific static library *libplatsbi.a* can be compiled. This library implements static library *libplatsbi.a* can be compiled. This library implements
SBI calls processing by integrating *libsbi.a* with necessary platform dependent SBI call processing by integrating *libsbi.a* with the necessary
hardware manipulation functions. For all supported platforms, OpenSBI also platform-dependent hardware manipulation functions. For all supported platforms,
provides several runtime firmware examples built using the platform OpenSBI also provides several runtime firmware examples built using the platform
*libplatsbi.a*. These example firmwares can be used to replace the legacy *libplatsbi.a*. These example firmwares can be used to replace the legacy
*riskv-pk* bootloader (aka BBL) and enable the use of well known bootloaders *riscv-pk* bootloader (aka BBL) and enable the use of well-known bootloaders
such as [U-Boot]. such as [U-Boot] (https://git.denx.de/u-boot.git).
Required Toolchain Required Toolchain
------------------ ------------------
OpenSBI can be compiled natively or cross-compiled on a x86 host. For OpenSBI can be compiled natively or cross-compiled on a x86 host. For
cross-compilation, you can build your tool chain or just download from cross-compilation, you can build your own toolchain or just download
the [bootlin] (https://toolchains.bootlin.com/). a prebuilt one from the
[Bootlin toolchain repository] (https://toolchains.bootlin.com/).
Please note that only 64bit version of toolchain is available in bootlin Please note that only a 64bit version of the toolchain is available in
for now. the Bootlin toolchain repository for now.
Building and Installing OpenSBI Platform Independent Library Building and Installing the OpenSBI Platform-Independent Library
------------------------------------------------------------ ----------------------------------------------------------------
OpenSBI platform independent static library *libsbi.a* can be natively compiled The OpenSBI platform-independent static library *libsbi.a* can be compiled
or cross-compiled on a host with a different base architecture than RISC-V. natively or it can be cross-compiled on a host with a different base
architecture than RISC-V.
For cross-compiling, the environment variable *CROSS_COMPILE* must be defined For cross-compiling, the environment variable *CROSS_COMPILE* must be defined
to specify the name prefix of the RISC-V compiler toolchain executables, e.g. to specify the name prefix of the RISC-V compiler toolchain executables, e.g.
@@ -61,8 +66,8 @@ To build *libsbi.a* simply execute:
make make
``` ```
All compiled binaries as well as the result *libsbi.a* static library file will All compiled binaries as well as the resulting *libsbi.a* static library file
be placed in the *build/lib* directory. To specify an alternate build root will be placed in the *build/lib* directory. To specify an alternate build root
directory path, run: directory path, run:
``` ```
make O=<build_directory> make O=<build_directory>
@@ -74,38 +79,38 @@ make install
``` ```
This will create the *install* directory with all necessary include files This will create the *install* directory with all necessary include files
copied under the *install/include* directory and library file copied in the copied under the *install/include* directory and the library file copied into
*install/lib* directory. To specify an alternate installation root directory the *install/lib* directory. To specify an alternate installation root
path, run: directory path, run:
``` ```
make I=<install_directory> install make I=<install_directory> install
``` ```
Building and Installing a Reference Platform Static Library and Firmwares Building and Installing a Reference Platform Static Library and Firmware
------------------------------------------------------------------------- ------------------------------------------------------------------------
When the *PLATFORM=<platform_subdir>* argument is specified on the make command When the *PLATFORM=<platform_subdir>* argument is specified on the make command
line, the platform specific static library *libplatsbi.a* and firmware examples line, the platform-specific static library *libplatsbi.a* and firmware examples
are built for the platform *<platform_subdir>* present in the directory are built for the platform *<platform_subdir>* present in the directory
*platform* in OpenSBI top directory. For example, to compile the platform *platform* in the OpenSBI top directory. For example, to compile the platform
library and firmware examples for QEMU RISC-V *virt* machine, library and the firmware examples for the QEMU RISC-V *virt* machine,
*<platform_subdir>* should be *qemu/virt*. *<platform_subdir>* should be *qemu/virt*.
To build *libsbi.a*, *libplatsbi.a* and the firmwares for one of the supported To build *libsbi.a*, *libplatsbi.a* and the firmware for one of the supported
platform, run: platforms, run:
``` ```
make PLATFORM=<platform_subdir> make PLATFORM=<platform_subdir>
``` ```
An alternate build directory path can also be specified. An alternate build directory path can also be specified:
``` ```
make PLATFORM=<platform_subdir> O=<build_directory> make PLATFORM=<platform_subdir> O=<build_directory>
``` ```
The platform specific library *libplatsbi.a* will be generated in the The platform-specific library *libplatsbi.a* will be generated in the
*build/platform/<platform_subdir>/lib* directory. The platform firmware files *build/platform/<platform_subdir>/lib* directory. The platform firmware files
will be under the *build/platform/<platform_subdir>/firmware* directory. will be under the *build/platform/<platform_subdir>/firmware* directory.
The compiled firmwares will be available in two different format: an ELF file The compiled firmwares will be available in two different formats: an ELF file
and an expanded image file. and an expanded image file.
To install *libsbi.a*, *libplatsbi.a*, and the compiled firmwares, run: To install *libsbi.a*, *libplatsbi.a*, and the compiled firmwares, run:
@@ -113,16 +118,16 @@ To install *libsbi.a*, *libplatsbi.a*, and the compiled firmwares, run:
make PLATFORM=<platform_subdir> install make PLATFORM=<platform_subdir> install
``` ```
This will copy the compiled platform specific libraries and firmware files This will copy the compiled platform-specific libraries and firmware files
under the *install/platform/<platform_subdir>/* directory. An alternate under the *install/platform/<platform_subdir>/* directory. An alternate
install root directory path can be specified as follows. install root directory path can be specified as follows:
``` ```
make PLATFORM=<platform_subdir> I=<install_directory> install make PLATFORM=<platform_subdir> I=<install_directory> install
``` ```
In addition, platform specific configuration options can be specified with the In addition, platform-specific configuration options can be specified with the
top-level make command line. These options, such as *PLATFORM_<xyz>* or top-level make command line. These options, such as *PLATFORM_<xyz>* or
*FW_<abc>*, are platform specific and described in more details in the *FW_<abc>*, are platform-specific and described in more details in the
*docs/platform/<platform_name>.md* files and *docs/platform/<platform_name>.md* files and
*docs/firmware/<firmware_name>.md* files. *docs/firmware/<firmware_name>.md* files.
@@ -152,14 +157,23 @@ files where the reused code is present.
(GPL-2.0+ OR BSD-2-Clause). Some of this project code is used in OpenSBI (GPL-2.0+ OR BSD-2-Clause). Some of this project code is used in OpenSBI
under the terms of the BSD 2-Clause license. Any contributions to this under the terms of the BSD 2-Clause license. Any contributions to this
code must be made under the terms of both licenses. code must be made under the terms of both licenses.
2. Some source file for the Kendryte/k210 platform code are based on code from
the [Kendryte standalone SDK] available on github. These files retain the
original copyright and license of the Kendryte standalone SDK project and
are licensed under the terms of the Apache License, Version 2.0.
See also the [third party notices] file for more information.
Contributing to OpenSBI Contributing to OpenSBI
----------------------- -----------------------
The OpenSBI project encourages and welcomes contributions. Contributions should The OpenSBI project encourages and welcomes contributions. Contributions should
follow the rules described in OpenSBI [Contribution Guideline] document. follow the rules described in the OpenSBI [Contribution Guideline] document.
In particular, all patches sent should contain a Signed-off-by tag. In particular, all patches sent should contain a Signed-off-by tag.
The [Contributors List] document provides a list of individuals and
organizations actively contributing to the OpenSBI project.
Documentation Documentation
------------- -------------
@@ -174,7 +188,7 @@ Detailed documentation of various aspects of OpenSBI can be found under the
examples build supported by OpenSBI. examples build supported by OpenSBI.
OpenSBI source code is also well documented. For source level documentation, OpenSBI source code is also well documented. For source level documentation,
doxygen style is used. Please refer to [Doxygen manual] for details on this doxygen style is used. Please refer to the [Doxygen manual] for details on this
format. format.
Doxygen can be installed on Linux distributions using *.deb* packages using Doxygen can be installed on Linux distributions using *.deb* packages using
@@ -218,9 +232,11 @@ make I=<install_directory> install_docs
[COPYING.BSD]: COPYING.BSD [COPYING.BSD]: COPYING.BSD
[SPDX]: http://spdx.org/licenses/ [SPDX]: http://spdx.org/licenses/
[Contribution Guideline]: docs/contributing.md [Contribution Guideline]: docs/contributing.md
[Contributors List]: CONTRIBUTORS.md
[Library Usage]: docs/library_usage.md [Library Usage]: docs/library_usage.md
[Platform Support Guide]: docs/platform_guide.md [Platform Support Guide]: docs/platform_guide.md
[Platform Documentation]: docs/platform/platform.md [Platform Documentation]: docs/platform/platform.md
[Firmware Documentation]: docs/firmware/fw.md [Firmware Documentation]: docs/firmware/fw.md
[Doxygen manual]: http://www.stack.nl/~dimitri/doxygen/manual.html [Doxygen manual]: http://www.doxygen.nl/manual/index.html
[Kendryte standalone SDK]: https://github.com/kendryte/kendryte-standalone-sdk
[third party notices]: ThirdPartyNotices.md

207
ThirdPartyNotices.md Normal file
View File

@@ -0,0 +1,207 @@
Copyright (c) 2019 Western Digital Corporation or its affiliates.
Third Party Notices
===================
This project includes or partly uses code from the following open source
software subject to the following open source licenses.
libfdt
------
Copyright (C) 2016 Free Electrons
Copyright (C) 2016 NextThing Co.
The libfdt source code is disjunctively dual licensed (GPL-2.0+ or
BSD-2-Clause). Some of this project code is used in OpenSBI under the terms of
the BSD 2-Clause license. The full text of this license can be found in the
file [COPYING.BSD](COPYING.BSD).
Kendryte Standalone SDK
-----------------------
Copyright 2018 Canaan Inc.
The Kendryte K210 platform code reuses some code from Kendryte standalone SDK
licensed under the terms of the Apache License, Version 2.0. The full text of
this license is available at http://www.apache.org/licenses/LICENSE-2.0 and
included below.
```
Apache License
Version 2.0, January 2004
http://www.apache.org/licenses/
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
1. Definitions.
"License" shall mean the terms and conditions for use, reproduction,
and distribution as defined by Sections 1 through 9 of this document.
"Licensor" shall mean the copyright owner or entity authorized by
the copyright owner that is granting the License.
"Legal Entity" shall mean the union of the acting entity and all
other entities that control, are controlled by, or are under common
control with that entity. For the purposes of this definition,
"control" means (i) the power, direct or indirect, to cause the
direction or management of such entity, whether by contract or
otherwise, or (ii) ownership of fifty percent (50%) or more of the
outstanding shares, or (iii) beneficial ownership of such entity.
"You" (or "Your") shall mean an individual or Legal Entity
exercising permissions granted by this License.
"Source" form shall mean the preferred form for making modifications,
including but not limited to software source code, documentation
source, and configuration files.
"Object" form shall mean any form resulting from mechanical
transformation or translation of a Source form, including but
not limited to compiled object code, generated documentation,
and conversions to other media types.
"Work" shall mean the work of authorship, whether in Source or
Object form, made available under the License, as indicated by a
copyright notice that is included in or attached to the work
(an example is provided in the Appendix below).
"Derivative Works" shall mean any work, whether in Source or Object
form, that is based on (or derived from) the Work and for which the
editorial revisions, annotations, elaborations, or other modifications
represent, as a whole, an original work of authorship. For the purposes
of this License, Derivative Works shall not include works that remain
separable from, or merely link (or bind by name) to the interfaces of,
the Work and Derivative Works thereof.
"Contribution" shall mean any work of authorship, including
the original version of the Work and any modifications or additions
to that Work or Derivative Works thereof, that is intentionally
submitted to Licensor for inclusion in the Work by the copyright owner
or by an individual or Legal Entity authorized to submit on behalf of
the copyright owner. For the purposes of this definition, "submitted"
means any form of electronic, verbal, or written communication sent
to the Licensor or its representatives, including but not limited to
communication on electronic mailing lists, source code control systems,
and issue tracking systems that are managed by, or on behalf of, the
Licensor for the purpose of discussing and improving the Work, but
excluding communication that is conspicuously marked or otherwise
designated in writing by the copyright owner as "Not a Contribution."
"Contributor" shall mean Licensor and any individual or Legal Entity
on behalf of whom a Contribution has been received by Licensor and
subsequently incorporated within the Work.
2. Grant of Copyright License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
copyright license to reproduce, prepare Derivative Works of,
publicly display, publicly perform, sublicense, and distribute the
Work and such Derivative Works in Source or Object form.
3. Grant of Patent License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
(except as stated in this section) patent license to make, have made,
use, offer to sell, sell, import, and otherwise transfer the Work,
where such license applies only to those patent claims licensable
by such Contributor that are necessarily infringed by their
Contribution(s) alone or by combination of their Contribution(s)
with the Work to which such Contribution(s) was submitted. If You
institute patent litigation against any entity (including a
cross-claim or counterclaim in a lawsuit) alleging that the Work
or a Contribution incorporated within the Work constitutes direct
or contributory patent infringement, then any patent licenses
granted to You under this License for that Work shall terminate
as of the date such litigation is filed.
4. Redistribution. You may reproduce and distribute copies of the
Work or Derivative Works thereof in any medium, with or without
modifications, and in Source or Object form, provided that You
meet the following conditions:
(a) You must give any other recipients of the Work or
Derivative Works a copy of this License; and
(b) You must cause any modified files to carry prominent notices
stating that You changed the files; and
(c) You must retain, in the Source form of any Derivative Works
that You distribute, all copyright, patent, trademark, and
attribution notices from the Source form of the Work,
excluding those notices that do not pertain to any part of
the Derivative Works; and
(d) If the Work includes a "NOTICE" text file as part of its
distribution, then any Derivative Works that You distribute must
include a readable copy of the attribution notices contained
within such NOTICE file, excluding those notices that do not
pertain to any part of the Derivative Works, in at least one
of the following places: within a NOTICE text file distributed
as part of the Derivative Works; within the Source form or
documentation, if provided along with the Derivative Works; or,
within a display generated by the Derivative Works, if and
wherever such third-party notices normally appear. The contents
of the NOTICE file are for informational purposes only and
do not modify the License. You may add Your own attribution
notices within Derivative Works that You distribute, alongside
or as an addendum to the NOTICE text from the Work, provided
that such additional attribution notices cannot be construed
as modifying the License.
You may add Your own copyright statement to Your modifications and
may provide additional or different license terms and conditions
for use, reproduction, or distribution of Your modifications, or
for any such Derivative Works as a whole, provided Your use,
reproduction, and distribution of the Work otherwise complies with
the conditions stated in this License.
5. Submission of Contributions. Unless You explicitly state otherwise,
any Contribution intentionally submitted for inclusion in the Work
by You to the Licensor shall be under the terms and conditions of
this License, without any additional terms or conditions.
Notwithstanding the above, nothing herein shall supersede or modify
the terms of any separate license agreement you may have executed
with Licensor regarding such Contributions.
6. Trademarks. This License does not grant permission to use the trade
names, trademarks, service marks, or product names of the Licensor,
except as required for reasonable and customary use in describing the
origin of the Work and reproducing the content of the NOTICE file.
7. Disclaimer of Warranty. Unless required by applicable law or
agreed to in writing, Licensor provides the Work (and each
Contributor provides its Contributions) on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
implied, including, without limitation, any warranties or conditions
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
PARTICULAR PURPOSE. You are solely responsible for determining the
appropriateness of using or redistributing the Work and assume any
risks associated with Your exercise of permissions under this License.
8. Limitation of Liability. In no event and under no legal theory,
whether in tort (including negligence), contract, or otherwise,
unless required by applicable law (such as deliberate and grossly
negligent acts) or agreed to in writing, shall any Contributor be
liable to You for damages, including any direct, indirect, special,
incidental, or consequential damages of any character arising as a
result of this License or out of the use or inability to use the
Work (including but not limited to damages for loss of goodwill,
work stoppage, computer failure or malfunction, or any and all
other commercial damages or losses), even if such Contributor
has been advised of the possibility of such damages.
9. Accepting Warranty or Additional Liability. While redistributing
the Work or Derivative Works thereof, You may choose to offer,
and charge a fee for, acceptance of support, warranty, indemnity,
or other liability obligations and/or rights consistent with this
License. However, in accepting such obligations, You may act only
on Your own behalf and on Your sole responsibility, not on behalf
of any other Contributor, and only if You agree to indemnify,
defend, and hold each Contributor harmless for any liability
incurred by, or claims asserted against, such Contributor by reason
of your accepting any such warranty or additional liability.
END OF TERMS AND CONDITIONS
```

View File

@@ -1,11 +1,20 @@
OpenSBI Contribution Guideline OpenSBI Contribution Guideline
============================== ==============================
All contributions to OpenSBI should be sent as GitHub Pull Requests (PRs) to All contributions to OpenSBI can be sent in the following ways:
[OpenSBI main repository]. 1. Email patches to the OpenSBI mailing list at `opensbi@lists.infradead.org`
2. GitHub Pull Requests (PRs) to the [OpenSBI main repository]
To join the OpenSBI mailing list, please visit the [OpenSBI infradead page].
The OpenSBI maintainers prefer patches via the OpenSBI mailing list
(option 1 above) so that they are visible to a wider audience. All
accepted patches on the OpenSBI mailing list will be taken by any of
the OpenSBI maintainers and merged into the [OpenSBI main repository]
using GitHub PRs.
All contributed work must follow the following rules: All contributed work must follow the following rules:
1. OpenSBI code should be written in accordance to [Linux coding style]. 1. OpenSBI code should be written in accordance to the [Linux coding style].
2. This project embraces the [Developer Certificate of Origin (DCO)] for 2. This project embraces the [Developer Certificate of Origin (DCO)] for
contributions. This means that you must agree to the following prior to contributions. This means that you must agree to the following prior to
submitting patches: if you agree with this developer certificate you submitting patches: if you agree with this developer certificate you
@@ -15,13 +24,14 @@ Every submitted patch must have this tag.
followed by a description of the patch content. A blank line and the author followed by a description of the patch content. A blank line and the author
Signed-off-by tag must follow this description. Signed-off-by tag must follow this description.
4. A commit subject line must start with a prefix followed by a ":". Common 4. A commit subject line must start with a prefix followed by a ":". Common
prefixes are for example "lib:", "platform:", "firmware:", "docs:" and "top:". prefixes are for example "lib:", "platform:", "firmware:", "docs:", "utils:"
and "top:".
5. Maintainers should use "Rebase and Merge" when using GitHub to merge pull 5. Maintainers should use "Rebase and Merge" when using GitHub to merge pull
requests to avoid creating unnecessary merge commits. requests to avoid creating unnecessary merge commits.
6. Maintainers should avoid creating branches directly in the main 6. Maintainers should avoid creating branches directly in the main
riscv/opensbi repository. Instead prefer using a fork of riscv/opensbi main riscv/opensbi repository. Instead prefer using a fork of the riscv/opensbi main
repository and branches within that fork to create pull requests. repository and branches within that fork to create pull requests.
7. A maintainer cannot merge his own pull requests in riscv/opensbi main 7. A maintainer cannot merge his own pull requests in the riscv/opensbi main
repository. repository.
8. A pull request must get at least one review from a maintainer. 8. A pull request must get at least one review from a maintainer.
9. A pull request must spend at least 24 hours in review to allow for other 9. A pull request must spend at least 24 hours in review to allow for other
@@ -69,6 +79,6 @@ By making a contribution to this project, I certify that:
----------------------------------------------------------------------- -----------------------------------------------------------------------
[OpenSBI main repository]: https://github.com/riscv/opensbi [OpenSBI main repository]: https://github.com/riscv/opensbi
[OpenSBI infradead page]: http://lists.infradead.org/mailman/listinfo/opensbi
[Linux coding style]: https://www.kernel.org/doc/html/v4.10/process/coding-style.html [Linux coding style]: https://www.kernel.org/doc/html/v4.10/process/coding-style.html
[Developer Certificate of Origin (DCO)]: http://developercertificate.org/ [Developer Certificate of Origin (DCO)]: http://developercertificate.org/

View File

@@ -44,7 +44,7 @@ PROJECT_NUMBER = "v@@OPENSBI_MAJOR@@.@@OPENSBI_MINOR@@"
# for a project that appears at the top of each page and should give viewer a # for a project that appears at the top of each page and should give viewer a
# quick idea about the purpose of the project. Keep the description short. # quick idea about the purpose of the project. Keep the description short.
PROJECT_BRIEF = "Open source implemenation of supervisor binary interface" PROJECT_BRIEF = "Open source implemenation of the supervisor binary interface"
# With the PROJECT_LOGO tag one can specify a logo or an icon that is included # With the PROJECT_LOGO tag one can specify a logo or an icon that is included
# in the documentation. The maximum height of the logo should not exceed 55 # in the documentation. The maximum height of the logo should not exceed 55

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

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

View File

@@ -9,12 +9,22 @@ OpenSBI generic library code. The supported firmwares type will differ in how
the arguments passed by the platform early boot stage are handled, as well as the arguments passed by the platform early boot stage are handled, as well as
how the boot stage following the firmware will be handled and executed. how the boot stage following the firmware will be handled and executed.
OpenSBI currently supports two different types of firmwares. OpenSBI currently supports three different types of firmwares.
Firmware with Dynamic Information (*FW_DYNAMIC*)
------------------------------------------------
The *FW_DYNAMIC* firmware gets information about the next booting stage entry,
e.g. a bootloader or an OS kernel, from previous booting stage at runtime.
A *FW_DYNAMIC* firmware is particularly useful when the booting stage executed
prior to OpenSBI firmware is capable of loading both the OpenSBI firmware
and the booting stage binary to follow OpenSBI firmware.
Firmware with Jump Address (*FW_JUMP*) Firmware with Jump Address (*FW_JUMP*)
-------------------------------------- --------------------------------------
The *FW_JUMP* firmware only handles the address of the next booting stage The *FW_JUMP* firmware assumes a fixed address of the next booting stage
entry, e.g. a bootloader or an OS kernel, without directly including the entry, e.g. a bootloader or an OS kernel, without directly including the
binary code for this next stage. binary code for this next stage.
@@ -48,14 +58,17 @@ configuration parameter.
loads OpenSBI firmware. loads OpenSBI firmware.
Additionally, each firmware type as a set of type specific configuration Additionally, each firmware type as a set of type specific configuration
parameters. Detailed information for each firmware type can be found in the parameters. Detailed information for each firmware type can be found in the
following documents. following documents.
* *[FW_DYNAMIC]*: The *Firmware with Dynamic Information (FW_DYNAMIC)* is
described in more details in the file *fw_dynamic.md*.
* *[FW_JUMP]*: The *Firmware with Jump Address (FW_JUMP)* is described in more * *[FW_JUMP]*: The *Firmware with Jump Address (FW_JUMP)* is described in more
details in the file *fw_jump.md*. details in the file *fw_jump.md*.
* *[FW_PAYLOAD]*: The *Firmware with Payload (FW_PAYLOAD)* is described in more * *[FW_PAYLOAD]*: The *Firmware with Payload (FW_PAYLOAD)* is described in more
details in the file *fw_payload.md*. details in the file *fw_payload.md*.
[FW_DYNAMIC]: fw_dynamic.md
[FW_JUMP]: fw_jump.md [FW_JUMP]: fw_jump.md
[FW_PAYLOAD]: fw_payload.md [FW_PAYLOAD]: fw_payload.md
@@ -75,3 +88,18 @@ make PLATFORM=<platform_subdir> FW_PAYLOAD_PATH=<payload path>
The instructions to build each payload is different and the details can The instructions to build each payload is different and the details can
be found in the be found in the
*docs/firmware/payload_<payload_name>.md* files. *docs/firmware/payload_<payload_name>.md* files.
Options for OpenSBI Firmware behaviors
--------------------------------------
An optional compile time flag FW_OPTIONS can be used to control the OpenSBI
firmware run-time behaviors.
```
make PLATFORM=<platform_subdir> FW_OPTIONS=<options>
```
FW_OPTIONS is a bitwise or'ed value of various options, eg: *FW_OPTIONS=0x1*
stands for disabling boot prints from the OpenSBI library.
For all supported options, please check "enum sbi_scratch_options" in the
*include/sbi/sbi_scratch.h* header file.

View File

@@ -0,0 +1,35 @@
OpenSBI Firmware with Dynamic Information *FW_DYNAMIC*
======================================================
OpenSBI **firmware with dynamic info (FW_DYNAMIC)** is a firmware which gets
information about next booting stage (e.g. a bootloader or an OS) and runtime
OpenSBI library options from previous booting stage.
The previous booting stage will pass information to *FW_DYNAMIC* by creating
*struct fw_dynamic_info* in memory and passing it's address to *FW_DYNAMIC*
via *a2* register of RISC-V CPU.
A *FW_DYNAMIC* firmware is particularly useful when the booting stage executed
prior to OpenSBI firmware is capable of loading both the OpenSBI firmware and
the booting stage binary to follow OpenSBI firmware.
*FW_DYNAMIC* Compilation
------------------------
A platform can enable *FW_DYNAMIC* firmware using any of the following methods.
1. Specifying `FW_DYNAMIC=y` on the top level `make` command line.
2. Specifying `FW_DYNAMIC=y` in the target platform *config.mk* configuration
file.
The compiled *FW_DYNAMIC* firmware ELF file is named *fw_dynamic.elf*. It's
expanded image file is *fw_dynamic.bin*. Both files are created in the platform
specific build directory under the *build/platform/<platform_subdir>/firmware*
directory.
*FW_DYNAMIC* Firmware Configuration Options
-------------------------------------------
The *FW_DYNAMIC* firmware does not requires any platform specific configuration
parameters because all required information is passed by previous booting stage
at runtime via *struct fw_dynamic_info*.

View File

@@ -6,19 +6,19 @@ handles the address of the next booting stage entry, e.g. a bootloader or an OS
kernel, without directly including the binary code for this next stage. kernel, without directly including the binary code for this next stage.
A *FW_JUMP* firmware is particularly useful when the booting stage executed A *FW_JUMP* firmware is particularly useful when the booting stage executed
prior to OpenSBI firmware is capable of loading both the OpenSBI firmware and prior to the OpenSBI firmware is capable of loading both the OpenSBI firmware
the booting stage binary to follow OpenSBI firmware. and the booting stage binary to follow the OpenSBI firmware.
*FW_JUMP* Compilation *FW_JUMP* Compilation
--------------------- ---------------------
A platform *FW_JUMP* firmware can be enabled by any of the following methods. A platform *FW_JUMP* firmware can be enabled by any of the following methods:
1. Specifying `FW_JUMP=y` on the top level `make` command line. 1. Specifying `FW_JUMP=y` on the top level `make` command line.
2. Specifying `FW_JUMP=y` in the target platform *config.mk* configuration file. 2. Specifying `FW_JUMP=y` in the target platform *config.mk* configuration file.
The compiled *FW_JUMP* firmware ELF file is named *fw_jump.elf*. Its expanded The compiled *FW_JUMP* firmware ELF file is named *fw_jump.elf*. Its expanded
image file is *fw_jump.bin*. Both files are created in the platform specific image file is *fw_jump.bin*. Both files are created in the platform-specific
build directory under the *build/platform/<platform_subdir>/firmware* directory. build directory under the *build/platform/<platform_subdir>/firmware* directory.
*FW_JUMP* Firmware Configuration Options *FW_JUMP* Firmware Configuration Options
@@ -27,26 +27,26 @@ build directory under the *build/platform/<platform_subdir>/firmware* directory.
To operate correctly, a *FW_JUMP* firmware requires some configuration To operate correctly, a *FW_JUMP* firmware requires some configuration
parameters to be defined using either the top level `make` command line or the parameters to be defined using either the top level `make` command line or the
target platform *config.mk* configuration file. The possible parameters are as target platform *config.mk* configuration file. The possible parameters are as
follows. follows:
* **FW_JUMP_ADDR** - Address of the entry point of the booting stage to be * **FW_JUMP_ADDR** - Address of the entry point of the booting stage to be
executed following OpenSBI firmware. This address generally correspond executed following OpenSBI firmware. This address generally corresponds
exactly to the address where this next booting stage was loaded. This is a exactly to the address where this next booting stage was loaded. This is a
mandatory parameter. Compilation errors will result from not defining this mandatory parameter. Compilation errors will result from not defining this
address. address.
* **FW_JUMP_FDT_ADDR** - Address where the *flattened device tree (FDT file)* * **FW_JUMP_FDT_ADDR** - Address where the *flattened device tree (FDT file)*
passed by the prior booting stage will be placed in memory before executing passed by the prior booting stage will be placed in memory before executing
the booting stage following OpenSBI firmware. If this option is not provided, the booting stage following the OpenSBI firmware. If this option is not
then OpenSBI firmware will pass zero as the FDT address to the following provided, then the OpenSBI firmware will pass zero as the FDT address to the
booting stage. following booting stage.
*FW_JUMP* Example *FW_JUMP* Example
----------------- -----------------
The *[qemu/virt]* and *[qemu/sifive_u]* platforms illustrates how to configure The *[qemu/virt]* and *[qemu/sifive_u]* platforms illustrate how to configure
and use a *FW_JUMP* firmware. Detailed information regarding these platforms and use a *FW_JUMP* firmware. Detailed information regarding these platforms
can be found in the platforms documentation files. can be found in the platform documentation files.
[qemu/virt]: ../platform/qemu_virt.md [qemu/virt]: ../platform/qemu_virt.md
[qemu/sifive_u]: ../platform/qemu_sifive_u.md [qemu/sifive_u]: ../platform/qemu_sifive_u.md

View File

@@ -2,22 +2,22 @@ OpenSBI Firmware with Payload *FW_PAYLOAD*
========================================== ==========================================
OpenSBI **firmware with Payload (FW_PAYLOAD)** is a firmware which directly OpenSBI **firmware with Payload (FW_PAYLOAD)** is a firmware which directly
includes the binary for the booting stage to follow OpenSBI firmware execution. includes the binary for the booting stage to follow the OpenSBI firmware
Typically, this payload will be a bootloader or an OS kernel. execution. Typically, this payload will be a bootloader or an OS kernel.
A *FW_PAYLOAD* firmware is particularly useful when the booting stage executed A *FW_PAYLOAD* firmware is particularly useful when the booting stage executed
prior to OpenSBI firmware is not capable of loading both OpenSBI firmware and prior to the OpenSBI firmware is not capable of loading both the OpenSBI
the booting stage to follow OpenSBI firmware. firmware and the booting stage to follow OpenSBI firmware.
A *FW_PAYLOAD* firmware is also useful for cases where the booting stage prior A *FW_PAYLOAD* firmware is also useful for cases where the booting stage prior
to OpenSBI firmware does not pass a *flattened device tree (FDT file)*. In such to the OpenSBI firmware does not pass a *flattened device tree (FDT file)*. In
case, a *FW_PAYLOAD* firmware allows embedding a flattened device tree in the such a case, a *FW_PAYLOAD* firmware allows embedding a flattened device tree
.text section of the final firmware. in the .text section of the final firmware.
Enabling *FW_PAYLOAD* compilation Enabling *FW_PAYLOAD* compilation
--------------------------------- ---------------------------------
The *FW_PAYLOAD* firmware can be enabled by any of the following methods. The *FW_PAYLOAD* firmware can be enabled by any of the following methods:
1. Specifying `FW_PAYLOAD=y` on the top level `make` command line. 1. Specifying `FW_PAYLOAD=y` on the top level `make` command line.
2. Specifying `FW_PAYLOAD=y` in the target platform *config.mk* configuration 2. Specifying `FW_PAYLOAD=y` in the target platform *config.mk* configuration
@@ -25,7 +25,7 @@ The *FW_PAYLOAD* firmware can be enabled by any of the following methods.
The compiled *FW_PAYLOAD* firmware ELF file is named *fw_jump.elf*. Its The compiled *FW_PAYLOAD* firmware ELF file is named *fw_jump.elf*. Its
expanded image file is *fw_payload.bin*. Both files are created in the expanded image file is *fw_payload.bin*. Both files are created in the
platform specific build directory under the platform-specific build directory under the
*build/platform/<platform_subdir>/firmware* directory. *build/platform/<platform_subdir>/firmware* directory.
Configuration Options Configuration Options
@@ -34,7 +34,7 @@ Configuration Options
A *FW_PAYLOAD* firmware is built according to configuration parameters and A *FW_PAYLOAD* firmware is built according to configuration parameters and
options. These configuration parameters can be defined using either the top options. These configuration parameters can be defined using either the top
level `make` command line or the target platform *config.mk* configuration level `make` command line or the target platform *config.mk* configuration
file. The parameters currently defined are as follows. file. The parameters currently defined are as follows:
* **FW_PAYLOAD_OFFSET** - Offset from *FW_TEXT_BASE* where the payload binary * **FW_PAYLOAD_OFFSET** - Offset from *FW_TEXT_BASE* where the payload binary
will be linked in the final *FW_PAYLOAD* firmware binary image. This will be linked in the final *FW_PAYLOAD* firmware binary image. This
@@ -47,8 +47,8 @@ file. The parameters currently defined are as follows.
will be linked after the end of the base firmware binary in the final will be linked after the end of the base firmware binary in the final
*FW_PAYLOAD* firmware binary image. This configuration parameter is mandatory *FW_PAYLOAD* firmware binary image. This configuration parameter is mandatory
if *FW_PAYLOAD_OFFSET* is not defined. If both *FW_PAYLOAD_OFFSET* and if *FW_PAYLOAD_OFFSET* is not defined. If both *FW_PAYLOAD_OFFSET* and
*FW_PAYLOAD_ALIGN* are defined, *FW_PAYLOAD_OFFSET* is used and *FW_PAYLOAD_ALIGN* are defined, *FW_PAYLOAD_OFFSET* is used and
*FW_PAYLOAD_ALIGN* ignored. *FW_PAYLOAD_ALIGN* is ignored.
* **FW_PAYLOAD_PATH** - Path to the image file of the next booting stage * **FW_PAYLOAD_PATH** - Path to the image file of the next booting stage
binary. If this option is not provided then a simple test payload is binary. If this option is not provided then a simple test payload is
@@ -78,13 +78,12 @@ file. The parameters currently defined are as follows.
*FW_PAYLOAD* Example *FW_PAYLOAD* Example
-------------------- --------------------
The *[qemu/virt]* and *[qemu/sifive_u]* platforms illustrates how to configure The *[qemu/virt]* and *[qemu/sifive_u]* platforms illustrate how to configure
and use a *FW_PAYLOAD* firmware. Detailed information regarding these platforms and use a *FW_PAYLOAD* firmware. Detailed information regarding these platforms
can be found in the platforms documentation files. can be found in the platform documentation files.
The *kendryte/k210* platform also enables build of a *FW_PAYLOAD* using an The *kendryte/k210* platform also enables a build of a *FW_PAYLOAD* using an
internally defined device tree file (*FW_PAYLOAD_FDT*). internally defined device tree file (*FW_PAYLOAD_FDT*).
[qemu/virt]: ../platform/qemu_virt.md [qemu/virt]: ../platform/qemu_virt.md
[qemu/sifive_u]: ../platform/qemu_sifive_u.md [qemu/sifive_u]: ../platform/qemu_sifive_u.md

View File

@@ -1,11 +1,10 @@
Linux as a direct payload to OpenSBI Linux as a direct payload to OpenSBI
==================================== ====================================
OpenSBI has the capability to load Linux kernel image directly in supervisor OpenSBI has the capability to load a Linux kernel image directly in supervisor
mode. The flattened image generated by the Linux kernel build process can be mode. The flattened image generated by the Linux kernel build process can be
provided as payload to OpenSBI. provided as a payload to OpenSBI.
Detailed examples and platform guides can be found in both [QEMU]( Detailed examples can be found in both the [QEMU](../platform/qemu_virt.md)
../platform/qemu_virt.md) and [HiFive Unleashed](../platform/sifive_fu540.md) and the [HiFive Unleashed](../platform/sifive_fu540.md) platform guides.
platform guide respectively.

View File

@@ -3,31 +3,33 @@ U-Boot as a payload to OpenSBI
[U-Boot](https://www.denx.de/wiki/U-Boot) is an open-source primary boot loader. [U-Boot](https://www.denx.de/wiki/U-Boot) is an open-source primary boot loader.
It can be used as first and/or second stage boot loader in an embedded It can be used as first and/or second stage boot loader in an embedded
environment. In the context of OpenSBI, U-boot can be specified as a payload to environment. In the context of OpenSBI, U-Boot can be specified as a payload to
OpenSBI firmware, becoming the boot stage following OpenSBI firmware the OpenSBI firmware, becoming the boot stage following the OpenSBI firmware
execution. execution.
The current stable upstream code of U-boot does not yet include all patches 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 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 following out-of-tree patch series must be applied to the upstream U-Boot source
code. code:
HiFive Unleashed support for U-Boot HiFive Unleashed support for U-Boot
https://lists.denx.de/pipermail/u-boot/2019-February/358058.html 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 This patch series enables a single CPU to execute U-Boot. As a result, the next
stage boot code such as Linux kernel can also only execute a single CPU. U-Boot stage boot code such as a Linux kernel can also only execute on a single CPU.
SMP support for RISC-V can be enabled with the following additional patches. 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 https://lists.denx.de/pipermail/u-boot/2019-February/358393.html
Building and Generating U-Boot images Building and Generating U-Boot images
===================================== =====================================
Please refer to U-Boot build documentation for detailed instructions on how to build U-Boot images. Please refer to the U-Boot build documentation for detailed instructions on
how to build U-Boot images.
Once U-Boot images are built, Linux kernel image need to be converted to a format Once U-Boot images are built, the Linux kernel image needs to be converted
that U-Boot understands. 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 \ <uboot-dir>/tools/mkimage -A riscv -O linux -T kernel -C none -a 0x80200000 -e 0x80200000 -n Linux -d \

View File

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

View File

@@ -0,0 +1,37 @@
Ariane FPGA SoC Platform
==========================
Ariane is a 6-stage, single issue, in-order CPU which implements the 64-bit RISC-V instruction set.
The Ariane FPGA development platform is based on FPGA FPGA SoC(which currently supports only Genesys 2 board) and is capable
of running Linux.
The FPGA SoC currently contains the following peripherals:
- DDR3 memory controller
- SPI controller to conncet to an SDCard
- Ethernet controller
- JTAG port (see debugging section below)
- Bootrom containing zero stage bootloader and device tree.
To build platform specific library and firmwares, provide the
*PLATFORM=ariane-fpga* parameter to the top level `make` command.
Platform Options
----------------
The *Ariane FPGA* platform does not have any platform-specific
options.
Building Ariane FPGA Platform
-----------------------------
**Linux Kernel Payload**
```
make PLATFORM=ariane-fpga FW_PAYLOAD_PATH=<linux_build_directory>/arch/riscv/boot/Image
```
Booting Ariane FPGA Platform
-----------------------------
**Linux Kernel Payload**
As Linux kernel image is embedded in the OpenSBI firmware binary, Ariane will directly
boot into Linux directly after powered on.

View File

@@ -1,11 +1,12 @@
OpenSBI Supported Platforms OpenSBI Supported Platforms
=========================== ===========================
OpenSBI currently supports the following virtual and hardware platforms. OpenSBI currently supports the following virtual and hardware platforms:
* **QEMU RISC-V Virt Machine**: Platform support for QEMU *virt* virtual RISC-V * **QEMU RISC-V Virt Machine**: Platform support for the QEMU *virt* virtual
machine. This virtual machine is intended for RISC-V software development and RISC-V machine. This virtual machine is intended for RISC-V software
test. More details on this platform can be found in the file *[qemu_virt.md]*. development and tests. More details on this platform can be found in the
file *[qemu_virt.md]*.
* **QEMU SiFive Unleashed Machine**: Platform support for the *sifive_u* QEMU * **QEMU SiFive Unleashed Machine**: Platform support for the *sifive_u* QEMU
virtual RISC-V machine. This is an emulation machine of the HiFive Unleashed virtual RISC-V machine. This is an emulation machine of the HiFive Unleashed
@@ -18,13 +19,18 @@ OpenSBI currently supports the following virtual and hardware platforms.
*[sifive_fu540.md]*. *[sifive_fu540.md]*.
* **Kendryte K210 SoC**: Platform support for the Kendryte K210 SoC used on * **Kendryte K210 SoC**: Platform support for the Kendryte K210 SoC used on
boards such as the Kendryte KD233 and Sipeed MAIX Dock boards. boards such as the Kendryte KD233 or the Sipeed MAIX Dock.
* **Ariane FPGA SoC**: Platform support for the Ariane FPGA SoC used on
Genesys 2 board.
The code for these supported platforms can be used as example to implement The code for these supported platforms can be used as example to implement
support for other platforms. The *platform/template* directory also provides support for other platforms. The *platform/template* directory also provides
template files for implementing support for a new platform. The *object.mk*, template files for implementing support for a new platform. The *object.mk*,
*config.mk* and *platform.c* template files provides enough comments to facilitate *config.mk* and *platform.c* template files provides enough comments to
the implementation. facilitate the implementation.
[qemu_virt.md]: qemu_virt.md [qemu_virt.md]: qemu_virt.md
[qemu_sifive_u.md]: qemu_sifive_u.md [qemu_sifive_u.md]: qemu_sifive_u.md
[sifive_fu540.md]: sifive_fu540.md
[ariane-fpga.md]: ariane-fpga.md

View File

@@ -20,7 +20,7 @@ Executing on QEMU RISC-V 64bit
Build: Build:
``` ```
make PLATFORM=qemu/virt make PLATFORM=qemu/sifive_u
``` ```
Run: Run:
@@ -32,11 +32,11 @@ qemu-system-riscv64 -M sifive_u -m 256M -display none -serial stdio \
**U-Boot as a Payload** **U-Boot as a Payload**
Note: the command line examples here assume that U-Boot was compiled using Note: the command line examples here assume that U-Boot was compiled using
the `qemu-riscv64_smode_defconfig` configuration. the `sifive_fu540_defconfig` configuration.
Build: Build:
``` ```
make PLATFORM=qemu/virt FW_PAYLOAD_PATH=<uboot_build_directory>/u-boot.bin make PLATFORM=qemu/sifive_u FW_PAYLOAD_PATH=<uboot_build_directory>/u-boot.bin
``` ```
Run: Run:

View File

@@ -1,18 +1,18 @@
QEMU RISC-V Virt Machine Platform QEMU RISC-V Virt Machine Platform
================================= =================================
The **QEMU RISC-V Virt Machine** is virtual platform created for RISC-V The **QEMU RISC-V Virt Machine** is a virtual platform created for RISC-V
software development and testing. It is also referred as software development and testing. It is also referred to as
*QEMU RISC-V VirtIO machine* because it uses VirtIO devices for network, *QEMU RISC-V VirtIO machine* because it uses VirtIO devices for network,
storage, and other types of IO. storage, and other types of IO.
To build platform specific library and firmwares, provide the To build the platform-specific library and firmware images, provide the
*PLATFORM=qemu/virt* parameter to the top level `make` command. *PLATFORM=qemu/virt* parameter to the top level `make` command.
Platform Options Platform Options
---------------- ----------------
The *QEMU RISC-V Virt Machine* platform does not have any platform specific The *QEMU RISC-V Virt Machine* platform does not have any platform-specific
options. options.
Execution on QEMU RISC-V 64bit Execution on QEMU RISC-V 64bit
@@ -27,7 +27,7 @@ make PLATFORM=qemu/virt
Run: Run:
``` ```
qemu-system-riscv64 -M virt -m 256M -display none -serial stdio \ qemu-system-riscv64 -M virt -m 256M -nographic \
-kernel build/platform/qemu/virt/firmware/fw_payload.elf -kernel build/platform/qemu/virt/firmware/fw_payload.elf
``` ```
@@ -43,19 +43,19 @@ make PLATFORM=qemu/virt FW_PAYLOAD_PATH=<uboot_build_directory>/u-boot.bin
Run: Run:
``` ```
qemu-system-riscv64 -M virt -m 256M -display none -serial stdio \ qemu-system-riscv64 -M virt -m 256M -nographic \
-kernel build/platform/qemu/virt/firmware/fw_payload.elf -kernel build/platform/qemu/virt/firmware/fw_payload.elf
``` ```
or or
``` ```
qemu-system-riscv64 -M virt -m 256M -display none -serial stdio \ qemu-system-riscv64 -M virt -m 256M -nographic \
-kernel build/platform/qemu/virt/firmware/fw_jump.elf \ -kernel build/platform/qemu/virt/firmware/fw_jump.elf \
-device loader,file=<uboot_build_directory>/u-boot.bin,addr=0x80400000 -device loader,file=<uboot_build_directory>/u-boot.bin,addr=0x80200000
``` ```
**Linux Kernel Payload** **Linux Kernel Payload**
Note: We assume that Linux kernel is compiled using Note: We assume that the Linux kernel is compiled using
*arch/riscv/configs/defconfig*. *arch/riscv/configs/defconfig*.
Build: Build:
@@ -65,7 +65,7 @@ make PLATFORM=qemu/virt FW_PAYLOAD_PATH=<linux_build_directory>/arch/riscv/boot/
Run: Run:
``` ```
qemu-system-riscv64 -M virt -m 256M -display none -serial stdio \ qemu-system-riscv64 -M virt -m 256M -nographic \
-kernel build/platform/qemu/virt/firmware/fw_payload.elf \ -kernel build/platform/qemu/virt/firmware/fw_payload.elf \
-drive file=<path_to_linux_rootfs>,format=raw,id=hd0 \ -drive file=<path_to_linux_rootfs>,format=raw,id=hd0 \
-device virtio-blk-device,drive=hd0 \ -device virtio-blk-device,drive=hd0 \
@@ -73,7 +73,76 @@ qemu-system-riscv64 -M virt -m 256M -display none -serial stdio \
``` ```
or or
``` ```
qemu-system-riscv64 -M virt -m 256M -display none -serial stdio \ qemu-system-riscv64 -M virt -m 256M -nographic \
-kernel build/platform/qemu/virt/firmware/fw_jump.elf \
-device loader,file=<linux_build_directory>/arch/riscv/boot/Image,addr=0x80200000 \
-drive file=<path_to_linux_rootfs>,format=raw,id=hd0 \
-device virtio-blk-device,drive=hd0 \
-append "root=/dev/vda rw console=ttyS0"
```
Execution on QEMU RISC-V 32bit
------------------------------
**No Payload Case**
Build:
```
make PLATFORM=qemu/virt
```
Run:
```
qemu-system-riscv32 -M virt -m 256M -nographic \
-kernel build/platform/qemu/virt/firmware/fw_payload.elf
```
**U-Boot Payload**
Note: the command line examples here assume that U-Boot was compiled using
the `qemu-riscv32_smode_defconfig` configuration.
Build:
```
make PLATFORM=qemu/virt FW_PAYLOAD_PATH=<uboot_build_directory>/u-boot.bin
```
Run:
```
qemu-system-riscv32 -M virt -m 256M -nographic \
-kernel build/platform/qemu/virt/firmware/fw_payload.elf
```
or
```
qemu-system-riscv32 -M virt -m 256M -nographic \
-kernel build/platform/qemu/virt/firmware/fw_jump.elf \
-device loader,file=<uboot_build_directory>/u-boot.bin,addr=0x80400000
```
**Linux Kernel Payload**
Note: We assume that the Linux kernel is compiled using
*arch/riscv/configs/rv32_defconfig* (kernel 5.1 and newer)
respectively using *arch/riscv/configs/defconfig* plus setting
CONFIG_ARCH_RV32I=y (kernel 5.0 and older).
Build:
```
make PLATFORM=qemu/virt FW_PAYLOAD_PATH=<linux_build_directory>/arch/riscv/boot/Image
```
Run:
```
qemu-system-riscv32 -M virt -m 256M -nographic \
-kernel build/platform/qemu/virt/firmware/fw_payload.elf \
-drive file=<path_to_linux_rootfs>,format=raw,id=hd0 \
-device virtio-blk-device,drive=hd0 \
-append "root=/dev/vda rw console=ttyS0"
```
or
```
qemu-system-riscv32 -M virt -m 256M -nographic \
-kernel build/platform/qemu/virt/firmware/fw_jump.elf \ -kernel build/platform/qemu/virt/firmware/fw_jump.elf \
-device loader,file=<linux_build_directory>/arch/riscv/boot/Image,addr=0x80400000 \ -device loader,file=<linux_build_directory>/arch/riscv/boot/Image,addr=0x80400000 \
-drive file=<path_to_linux_rootfs>,format=raw,id=hd0 \ -drive file=<path_to_linux_rootfs>,format=raw,id=hd0 \

View File

@@ -11,9 +11,10 @@ Platform Options
---------------- ----------------
As hart0 in the FU540 doesn't have an MMU, only harts 1-4 boot by default. 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 A hart mask i.e. *FU540_ENABLED_HART_MASK* compile time option is provided
select any other hart for booting. Please keep in mind that this is not to select any other hart for booting. Please keep in mind that this is not
platform wide option. It can only be specified for FU540 platform in following way. 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 make PLATFORM=sifive/fu540 FW_PAYLOAD_PATH=Image FU540_ENABLED_HART_MASK=0x02
@@ -23,52 +24,64 @@ This will let the board boot only hart1 instead of default 1-4.
Building SiFive Fu540 Platform Building SiFive Fu540 Platform
----------------------------- -----------------------------
As of this writing, the required Linux kernel and U-Boot patches are not In order to boot SMP Linux in U-Boot, Linux v5.1 (or higher) and latest
accepted in mainline. Please follow the below instructions to cherry-pick U-Boot v2019.04 (or higher) should be used.
them into your repository.
[U-Boot patches](../firmware/payload_uboot.md)
[Linux kernel patches](../firmware/payload_linux.md)
**Linux Kernel Payload** **Linux Kernel Payload**
The HiFive Unleashed device tree(DT) is merged in Linux v5.2 release. This
DT (device tree) is not backward compatible with the DT passed from FSBL.
To use Linux v5.2 (or higher, the pre-built DTB (DT binary) from Linux v5.2
(or higher) should be used to build SiFive FU540 OpenSBI binaries by using
the compile time option *FW_PAYLOAD_FDT_PATH*.
``` ```
make PLATFORM=sifive/fu540 FW_PAYLOAD_PATH=<linux_build_directory>/arch/riscv/boot/Image make PLATFORM=sifive/fu540 FW_PAYLOAD_PATH=<linux_build_directory>/arch/riscv/boot/Image
or
(For Linux v5.2 or higher)
make PLATFORM=sifive/fu540 FW_PAYLOAD_PATH=<linux_build_directory>/arch/riscv/boot/Image FW_PAYLOAD_FDT_PATH=<hifive-unleashed-a00.dtb path from Linux kernel>
``` ```
**U-Boot Payload** **U-Boot Payload**
The command-line example here assumes that U-Boot was compiled using the
sifive_fu540_defconfig configuration and with U-Boot v2019.04 (or higher)
having SMP support.
The command-line example here assumes that U-Boot was compiled using sifive_fu540_defconfig configuration. To use U-Boot which follows Linux v5.2 (or higher) DT bindings, we will
need custom U-Boot with required driver changes which can be found in
With SMP support enabled in U-Boot: riscv_unleashed_mmc_spi_v2 branch of https://github.com/avpatel/u-boot.git
``` ```
make PLATFORM=sifive/fu540 FW_PAYLOAD_PATH=<u-boot_build_dir>/u-boot.bin make PLATFORM=sifive/fu540 FW_PAYLOAD_PATH=<u-boot_build_dir>/u-boot.bin
or
(For U-Boot which follows Linux v5.2 (or higher) DT bindings)
make PLATFORM=sifive/fu540 FW_PAYLOAD_PATH=<u-boot_build_dir>/u-boot.bin FW_PAYLOAD_FDT_PATH=<hifive-unleashed-a00.dtb path from Linux kernel>
``` ```
Without SMP support enabled in U-Boot: Generate the uImage from Linux Image.
``` ```
make PLATFORM=sifive/fu540 FW_PAYLOAD_PATH=<u-boot_build_dir>/u-boot.bin FU540_ENABLED_HART_MASK=0x02 mkimage -A riscv -O linux -T kernel -C none -a 0x80200000 -e 0x80200000 -n Linux -d \
<linux_build_directory>/arch/riscv/boot/Image \
<linux_build_directory>/arch/riscv/boot/uImage
``` ```
**U-Boot & Linux Kernel as a single payload** **U-Boot & Linux Kernel as a single payload**
A single monolithic image containing both U-Boot & Linux can also be used if network boot setup is A single monolithic image containing both U-Boot & Linux can also be used if
not available. network boot setup is not available.
1. Generate the uImage from Linux Image. 1. Generate the uImage from Linux Image.
``` ```
mkimage -A riscv -O linux -T kernel -C none -a 0x80200000 -e 0x80200000 -n Linux -d \ mkimage -A riscv -O linux -T kernel -C none -a 0x80200000 -e 0x80200000 -n Linux -d \
<linux_build_directory>arch/riscv/boot/Image \ <linux_build_directory>/arch/riscv/boot/Image \
<linux_build_directory>/arch/riscv/boot/uImage <linux_build_directory>/arch/riscv/boot/uImage
``` ```
2. Create a temporary image with u-boot.bin as the first payload. The command-line 2. Create a temporary image with u-boot.bin as the first payload. The
example here assumes that U-Boot was compiled using sifive_fu540_defconfig command-line example here assumes that U-Boot was compiled using
configuration. sifive_fu540_defconfig configuration.
``` ```
dd if=~/workspace/u-boot-riscv/u-boot.bin of=/tmp/temp.bin bs=1M dd if=~/workspace/u-boot-riscv/u-boot.bin of=/tmp/temp.bin bs=1M
``` ```
@@ -79,27 +92,31 @@ dd if=<linux_build_directory>/arch/riscv/boot/uImage of=/tmp/temp.bin bs=1M seek
4. Compile OpenSBI with temp.bin (generated in step 3) as payload. 4. Compile OpenSBI with temp.bin (generated in step 3) as payload.
``` ```
make PLATFORM=sifive/fu540 FW_PAYLOAD_PATH=/tmp/temp.bin make PLATFORM=sifive/fu540 FW_PAYLOAD_PATH=/tmp/temp.bin
or
(For U-Boot which follows Linux v5.2 (or higher) DT bindings)
make PLATFORM=sifive/fu540 FW_PAYLOAD_PATH=/tmp/temp.bin FW_PAYLOAD_FDT_PATH=<hifive-unleashed-a00.dtb path from Linux kernel>
``` ```
Flashing the OpenSBI firmware binary to storage media: Flashing the OpenSBI firmware binary to storage media:
----------------------------------------------------- -----------------------------------------------------
The first stage boot loader([FSBL](https://github.com/sifive/freedom-u540-c000-bootloader)) The first stage boot loader([FSBL](https://github.com/sifive/freedom-u540-c000-bootloader))
expects the storage media to have a GPT partition table. It tries to look for a expects the storage media to have a GPT partition table. It tries to look for
partition with following GUID to load the next stage boot loader (OpenSBI in this case). a partition with following GUID to load the next stage boot loader (OpenSBI
in this case).
``` ```
2E54B353-1271-4842-806F-E436D6AF6985 2E54B353-1271-4842-806F-E436D6AF6985
``` ```
That's why the generated firmware binary in above steps should be copied to the That's why the generated firmware binary in above steps should be copied to
partition of the sdcard with above GUID. the partition of the sdcard with above GUID.
``` ```
dd if=build/platform/sifive/fu540/firmware/fw_payload.bin of=/dev/disk2s1 bs=1024 dd if=build/platform/sifive/fu540/firmware/fw_payload.bin of=/dev/disk2s1 bs=1024
``` ```
In my case, it is the first partition is **disk2s1** that has been formatted with the In my case, it is the first partition is **disk2s1** that has been formatted
above specified GUID. with the above specified GUID.
In case of a brand new sdcard, it should be formatted with below partition In case of a brand new sdcard, it should be formatted with below partition
tables as described here. tables as described here.
@@ -108,7 +125,7 @@ tables as described here.
sgdisk --clear \ sgdisk --clear \
--new=1:2048:67583 --change-name=1:bootloader --typecode=1:2E54B353-1271-4842-806F-E436D6AF6985 \ --new=1:2048:67583 --change-name=1:bootloader --typecode=1:2E54B353-1271-4842-806F-E436D6AF6985 \
--new=2:264192: --change-name=2:root --typecode=2:0FC63DAF-8483-4772-8E79-3D69D8477DE4 \ --new=2:264192: --change-name=2:root --typecode=2:0FC63DAF-8483-4772-8E79-3D69D8477DE4 \
$(DISK) ${DISK}
``` ```
Booting SiFive Fu540 Platform Booting SiFive Fu540 Platform
@@ -116,66 +133,62 @@ Booting SiFive Fu540 Platform
**Linux Kernel Payload** **Linux Kernel Payload**
As Linux kernel image is embedded in the OpenSBI firmware binary, HiFive Unleashed will directly As Linux kernel image is embedded in the OpenSBI firmware binary, HiFive
boot into Linux directly after powered on. Unleashed will directly boot into Linux directly after powered on.
**U-Boot Payload** **U-Boot Payload**
As U-Boot image is used as payload, HiFive Unleashed will boot into a U-Boot prompt. As U-Boot image is used as payload, HiFive Unleashed will boot into a U-Boot
U-Boot tftp boot method can be used to load kernel image in U-Boot prompt. prompt. U-Boot tftp boot method can be used to load kernel image in U-Boot
Here are the steps do a tftpboot. prompt. Here are the steps do a tftpboot.
1. Set the mac address of the board. 1. Set the mac address of the board.
``` ```
setenv ethaddr <mac address of the board> setenv ethaddr <mac address of the board>
``` ```
2. Set the ip address of the board. (Note: This step is optional)
2. Set the ip address of the board.
``` ```
setenv ipaddr <ipaddr of the board> setenv ipaddr <ipaddr of the board>
``` ```
3. Set the tftpboot server IP.
3. Set the tftpboot server IP.
``` ```
setenv serverip <ipaddr of the tftp server> setenv serverip <ipaddr of the tftp server>
``` ```
4. Set the network gateway address.
4. Set the network gateway address.
``` ```
setenv gatewayip <ipaddress of the network gateway> setenv gatewayip <ipaddress of the network gateway>
``` ```
5. Load the Linux kernel image from the tftp server. 5. Load the Linux kernel image from the tftp server.
``` ```
tftpboot ${kernel_addr_r} /sifive/fu540/uImage tftpboot ${kernel_addr_r} <uImage path in tftpboot directory>
``` ```
6. Load the ramdisk image from the tftp server. This is only required if ramdisk 6. Load the ramdisk image from the tftp server. This is only required if
is loaded from tftp server. This step is optional, if rootfs is already part ramdisk is loaded from tftp server. This step is optional, if rootfs is
of the kernel or loaded from an external storage by kernel. already part of the kernel or loaded from an external storage by kernel.
```
tftpboot ${ramdisk_addr_r} <ramdisk path in tftpboot directory>
```
```
tftpboot ${ramdisk_addr_r} /sifive/fu540/uRamdisk
```
7. Set the boot command-line arguments. 7. Set the boot command-line arguments.
``` ```
setenv bootargs "root=<root partition> rw console=ttySIF0 earlycon=sbi" setenv bootargs "root=<root partition> rw console=ttySIF0 earlycon=sbi"
``` ```
(Note: root partition should point to
N.B. root partition should point to ** /dev/ram ** - If a ramdisk is used
** /dev/ram ** - If a ramdisk is used ** root=/dev/mmcblk0pX ** - If a rootfs is already on some other partition
** root=/dev/mmcblk0pX ** - If a rootfs is already on some other partition of sdcard of sdcard)
8. Now boot into Linux. 8. Now boot into Linux.
``` ```
bootm ${kernel_addr_r} ${ramdisk_addr_r} ${fdtcontroladdr} bootm ${kernel_addr_r} ${ramdisk_addr_r} ${fdtcontroladdr}
or
``` (If ramdisk is not loaded from network)
or (if ramdisk is not loaded from network)
```
bootm ${kernel_addr_r} - ${fdtcontroladdr} bootm ${kernel_addr_r} - ${fdtcontroladdr}
``` ```
@@ -186,17 +199,3 @@ At U-Boot prompt execute the following boot command to boot Linux.
``` ```
bootm ${kernel_addr_r} - ${fdtcontroladdr} bootm ${kernel_addr_r} - ${fdtcontroladdr}
``` ```
Booting SiFive Fu540 Platform with Microsemi Expansion board
------------------------------------------------------------
Until the Linux kernel has in-tree support for device trees and mainline u-boot
is fully supported on the HiFive Unleashed you can follow these steps to boot
Linux with the Microsemi expansion board. This method should not be copied on
future boards and is considered a temporary solution until we can use a more
standardised boot flow.
To boot the Linux kernel with a device tree that has support for the Microsemi
Expansion board you can include the following line when compiling the firmware:
```
FW_PAYLOAD_FDT="HiFiveUnleashed-MicroSemi-Expansion.dtb"
```

View File

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

View File

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

View File

@@ -13,6 +13,31 @@
#include <sbi/sbi_scratch.h> #include <sbi/sbi_scratch.h>
#include <sbi/sbi_trap.h> #include <sbi/sbi_trap.h>
.macro MOV_3R __d0, __s0, __d1, __s1, __d2, __s2
add \__d0, \__s0, zero
add \__d1, \__s1, zero
add \__d2, \__s2, zero
.endm
.macro MOV_5R __d0, __s0, __d1, __s1, __d2, __s2, __d3, __s3, __d4, __s4
add \__d0, \__s0, zero
add \__d1, \__s1, zero
add \__d2, \__s2, zero
add \__d3, \__s3, zero
add \__d4, \__s4, zero
.endm
/*
* If __start_reg <= __check_reg and __check_reg < __end_reg then
* jump to __pass
*/
.macro BRANGE __start_reg, __end_reg, __check_reg, __jump_lable
blt \__check_reg, \__start_reg, 999f
bge \__check_reg, \__end_reg, 999f
j \__jump_lable
999:
.endm
.align 3 .align 3
.section .entry, "ax", %progbits .section .entry, "ax", %progbits
.globl _start .globl _start
@@ -23,7 +48,179 @@ _start:
* that is, for mhartid != 0 * that is, for mhartid != 0
*/ */
csrr a6, CSR_MHARTID csrr a6, CSR_MHARTID
blt zero, a6, _wait_for_boot_hart blt zero, a6, _wait_relocate_copy_done
/* Save load address */
la t0, _load_start
la t1, _start
REG_S t1, 0(t0)
/* Relocate if load address != link address */
_relocate:
la t0, _link_start
REG_L t0, 0(t0)
la t1, _link_end
REG_L t1, 0(t1)
la t2, _load_start
REG_L t2, 0(t2)
sub t3, t1, t0
add t3, t3, t2
beq t0, t2, _relocate_done
la t4, _relocate_done
sub t4, t4, t2
add t4, t4, t0
blt t2, t0, _relocate_copy_to_upper
_relocate_copy_to_lower:
ble t1, t2, _relocate_copy_to_lower_loop
la t3, _boot_status
BRANGE t2, t1, t3, _start_hang
la t3, _relocate
la t5, _relocate_done
BRANGE t2, t1, t3, _start_hang
BRANGE t2, t1, t5, _start_hang
BRANGE t3, t5, t2, _start_hang
_relocate_copy_to_lower_loop:
REG_L t3, 0(t2)
REG_S t3, 0(t0)
add t0, t0, __SIZEOF_POINTER__
add t2, t2, __SIZEOF_POINTER__
blt t0, t1, _relocate_copy_to_lower_loop
jr t4
_relocate_copy_to_upper:
ble t3, t0, _relocate_copy_to_upper_loop
la t2, _boot_status
BRANGE t0, t3, t2, _start_hang
la t2, _relocate
la t5, _relocate_done
BRANGE t0, t3, t2, _start_hang
BRANGE t0, t3, t5, _start_hang
BRANGE t2, t5, t0, _start_hang
_relocate_copy_to_upper_loop:
add t3, t3, -__SIZEOF_POINTER__
add t1, t1, -__SIZEOF_POINTER__
REG_L t2, 0(t3)
REG_S t2, 0(t1)
blt t0, t1, _relocate_copy_to_upper_loop
jr t4
_wait_relocate_copy_done:
la t0, _start
la t1, _link_start
REG_L t1, 0(t1)
beq t0, t1, _wait_for_boot_hart
la t2, _boot_status
sub t2, t2, t0
add t2, t2, t1
la t3, _wait_for_boot_hart
sub t3, t3, t0
add t3, t3, t1
1:
/* waitting for relocate copy done (_boot_status == 1) */
li t4, 1
REG_L t5, 0(t2)
/* Reduce the bus traffic so that boot hart may proceed faster */
nop
nop
nop
bne t4, t5, 1b
jr t3
_relocate_done:
/* mark relocate copy done */
la t0, _boot_status
li t1, 1
REG_S t1, 0(t0)
fence rw, rw
/* At this point we are running from link address */
/* Reset all registers for boot HART */
li ra, 0
call _reset_regs
/* Allow main firmware to save info */
MOV_5R s0, a0, s1, a1, s2, a2, s3, a3, s4, a4
call fw_save_info
MOV_5R a0, s0, a1, s1, a2, s2, a3, s3, a4, s4
/* Preload HART details
* s7 -> HART Count
* s8 -> HART Stack Size
*/
la a4, platform
#if __riscv_xlen == 64
lwu s7, SBI_PLATFORM_HART_COUNT_OFFSET(a4)
lwu s8, SBI_PLATFORM_HART_STACK_SIZE_OFFSET(a4)
#else
lw s7, SBI_PLATFORM_HART_COUNT_OFFSET(a4)
lw s8, SBI_PLATFORM_HART_STACK_SIZE_OFFSET(a4)
#endif
/* Setup scratch space for all the HARTs*/
la tp, _fw_end
mul a5, s7, s8
add tp, tp, a5
/* Keep a copy of tp */
add t3, tp, zero
/* Counter */
li t2, 1
/* hartid 0 is mandated by ISA */
li t1, 0
_scratch_init:
add tp, t3, zero
mul a5, s8, t1
sub tp, tp, a5
li a5, SBI_SCRATCH_SIZE
sub tp, tp, a5
/* Initialize scratch space */
/* Store fw_start and fw_size in scratch space */
la a4, _fw_start
la a5, _fw_end
mul t0, s7, s8
add a5, a5, t0
sub a5, a5, a4
REG_S a4, SBI_SCRATCH_FW_START_OFFSET(tp)
REG_S a5, SBI_SCRATCH_FW_SIZE_OFFSET(tp)
/* Store next arg1 in scratch space */
MOV_3R s0, a0, s1, a1, s2, a2
call fw_next_arg1
REG_S a0, SBI_SCRATCH_NEXT_ARG1_OFFSET(tp)
MOV_3R a0, s0, a1, s1, a2, s2
/* Store next address in scratch space */
MOV_3R s0, a0, s1, a1, s2, a2
call fw_next_addr
REG_S a0, SBI_SCRATCH_NEXT_ADDR_OFFSET(tp)
MOV_3R a0, s0, a1, s1, a2, s2
/* Store next mode in scratch space */
MOV_3R s0, a0, s1, a1, s2, a2
call fw_next_mode
REG_S a0, SBI_SCRATCH_NEXT_MODE_OFFSET(tp)
MOV_3R a0, s0, a1, s1, a2, s2
/* Store warm_boot address in scratch space */
la a4, _start_warm
REG_S a4, SBI_SCRATCH_WARMBOOT_ADDR_OFFSET(tp)
/* Store platform address in scratch space */
la a4, platform
REG_S a4, SBI_SCRATCH_PLATFORM_ADDR_OFFSET(tp)
/* Store hartid-to-scratch function address in scratch space */
la a4, _hartid_to_scratch
REG_S a4, SBI_SCRATCH_HARTID_TO_SCRATCH_OFFSET(tp)
/* Clear tmp0 in scratch space */
REG_S zero, SBI_SCRATCH_TMP0_OFFSET(tp)
/* Store firmware options in scratch space */
MOV_3R s0, a0, s1, a1, s2, a2
#ifdef FW_OPTIONS
li a4, FW_OPTIONS
#else
add a4, zero, zero
#endif
call fw_options
or a4, a4, a0
REG_S a4, SBI_SCRATCH_OPTIONS_OFFSET(tp)
MOV_3R a0, s0, a1, s1, a2, s2
/* Move to next scratch space */
add t1, t1, t2
blt t1, s7, _scratch_init
/* Zero-out BSS */ /* Zero-out BSS */
la a4, _bss_start la a4, _bss_start
@@ -34,12 +231,10 @@ _bss_zero:
blt a4, a5, _bss_zero blt a4, a5, _bss_zero
/* Override pervious arg1 */ /* Override pervious arg1 */
add s0, a0, zero MOV_3R s0, a0, s1, a1, s2, a2
add s1, a1, zero
call fw_prev_arg1 call fw_prev_arg1
add t1, a0, zero add t1, a0, zero
add a0, s0, zero MOV_3R a0, s0, a1, s1, a2, s2
add a1, s1, zero
beqz t1, _prev_arg1_override_done beqz t1, _prev_arg1_override_done
add a1, t1, zero add a1, t1, zero
_prev_arg1_override_done: _prev_arg1_override_done:
@@ -54,16 +249,15 @@ _prev_arg1_override_done:
*/ */
beqz a1, _fdt_reloc_done beqz a1, _fdt_reloc_done
/* Mask values in a3 and a4 */ /* Mask values in a3 and a4 */
li a3, ~0xf li a3, ~(__SIZEOF_POINTER__ - 1)
li a4, 0xff li a4, 0xff
/* t1 = destination FDT start address */ /* t1 = destination FDT start address */
add s0, a0, zero MOV_3R s0, a0, s1, a1, s2, a2
add s1, a1, zero
call fw_next_arg1 call fw_next_arg1
add t1, a0, zero add t1, a0, zero
add a0, s0, zero MOV_3R a0, s0, a1, s1, a2, s2
add a1, s1, zero
beqz t1, _fdt_reloc_done beqz t1, _fdt_reloc_done
beq t1, a1, _fdt_reloc_done
and t1, t1, a3 and t1, t1, a3
/* t0 = source FDT start address */ /* t0 = source FDT start address */
add t0, a1, zero add t0, a1, zero
@@ -107,34 +301,33 @@ _fdt_reloc_again:
blt t1, t2, _fdt_reloc_again blt t1, t2, _fdt_reloc_again
_fdt_reloc_done: _fdt_reloc_done:
/* Update boot hart flag */ /* mark boot hart done */
la a4, _boot_hart_done li t0, 2
li a5, 1 la t1, _boot_status
REG_S a5, (a4) REG_S t0, 0(t1)
j _wait_for_boot_hart fence rw, rw
j _start_warm
.align 3 /* waitting for boot hart done (_boot_status == 2) */
_boot_hart_done:
RISCV_PTR 0
.align 3
/* Wait for boot hart */
_wait_for_boot_hart: _wait_for_boot_hart:
la a4, _boot_hart_done li t0, 2
REG_L a5, (a4) la t1, _boot_status
beqz a5, _wait_for_boot_hart REG_L t1, 0(t1)
/* Reduce the bus traffic so that boot hart may proceed faster */
nop
nop
nop
bne t0, t1, _wait_for_boot_hart
_start_warm: _start_warm:
/* Reset all registers for non-boot HARTs */
li ra, 0
call _reset_regs
/* Disable and clear all interrupts */ /* Disable and clear all interrupts */
csrw CSR_MIE, zero csrw CSR_MIE, zero
csrw CSR_MIP, zero csrw CSR_MIP, zero
/* Preload per-HART details
* s6 -> HART ID
* s7 -> HART Count
* s8 -> HART Stack Size
*/
csrr s6, CSR_MHARTID
la a4, platform la a4, platform
#if __riscv_xlen == 64 #if __riscv_xlen == 64
lwu s7, SBI_PLATFORM_HART_COUNT_OFFSET(a4) lwu s7, SBI_PLATFORM_HART_COUNT_OFFSET(a4)
@@ -148,7 +341,7 @@ _start_warm:
csrr s6, CSR_MHARTID csrr s6, CSR_MHARTID
bge s6, s7, _start_hang bge s6, s7, _start_hang
/* Setup scratch space */ /* find the scratch space for this hart */
la tp, _fw_end la tp, _fw_end
mul a5, s7, s8 mul a5, s7, s8
add tp, tp, a5 add tp, tp, a5
@@ -156,32 +349,9 @@ _start_warm:
sub tp, tp, a5 sub tp, tp, a5
li a5, SBI_SCRATCH_SIZE li a5, SBI_SCRATCH_SIZE
sub tp, tp, a5 sub tp, tp, a5
csrw CSR_MSCRATCH, tp
/* Initialize scratch space */ /* update the mscratch */
la a4, _fw_start csrw CSR_MSCRATCH, tp
la a5, _fw_end
mul t0, s7, s8
add a5, a5, t0
sub a5, a5, a4
REG_S a4, SBI_SCRATCH_FW_START_OFFSET(tp)
REG_S a5, SBI_SCRATCH_FW_SIZE_OFFSET(tp)
/* Note: fw_next_arg1() uses a0, a1, and ra */
call fw_next_arg1
REG_S a0, SBI_SCRATCH_NEXT_ARG1_OFFSET(tp)
/* Note: fw_next_addr() uses a0, a1, and ra */
call fw_next_addr
REG_S a0, SBI_SCRATCH_NEXT_ADDR_OFFSET(tp)
li a4, PRV_S
REG_S a4, SBI_SCRATCH_NEXT_MODE_OFFSET(tp)
la a4, _start_warm
REG_S a4, SBI_SCRATCH_WARMBOOT_ADDR_OFFSET(tp)
la a4, platform
REG_S a4, SBI_SCRATCH_PLATFORM_ADDR_OFFSET(tp)
la a4, _hartid_to_scratch
REG_S a4, SBI_SCRATCH_HARTID_TO_SCRATCH_OFFSET(tp)
REG_S zero, SBI_SCRATCH_IPI_TYPE_OFFSET(tp)
REG_S zero, SBI_SCRATCH_TMP0_OFFSET(tp)
/* Setup stack */ /* Setup stack */
add sp, tp, zero add sp, tp, zero
@@ -189,14 +359,27 @@ _start_warm:
/* Setup trap handler */ /* Setup trap handler */
la a4, _trap_handler la a4, _trap_handler
csrw CSR_MTVEC, a4 csrw CSR_MTVEC, a4
/* Make sure that mtvec is updated */
1: csrr a5, CSR_MTVEC
bne a4, a5, 1b
/* Initialize SBI runtime */ /* Initialize SBI runtime */
csrr a0, CSR_MSCRATCH csrr a0, CSR_MSCRATCH
Call sbi_init call sbi_init
/* We don't expect to reach here hence just hang */ /* We don't expect to reach here hence just hang */
j _start_hang j _start_hang
.align 3
_boot_status:
RISCV_PTR 0
_load_start:
RISCV_PTR _fw_start
_link_start:
RISCV_PTR _fw_start
_link_end:
RISCV_PTR _fw_reloc_end
.align 3 .align 3
.section .entry, "ax", %progbits .section .entry, "ax", %progbits
.globl _hartid_to_scratch .globl _hartid_to_scratch
@@ -375,3 +558,42 @@ _trap_handler_all_mode:
REG_L sp, SBI_TRAP_REGS_OFFSET(sp)(sp) REG_L sp, SBI_TRAP_REGS_OFFSET(sp)(sp)
mret mret
.align 3
.section .entry, "ax", %progbits
.globl _reset_regs
_reset_regs:
/* flush the instruction cache */
fence.i
/* Reset all registers except ra, a0, a1 and a2 */
li sp, 0
li gp, 0
li tp, 0
li t0, 0
li t1, 0
li t2, 0
li s0, 0
li s1, 0
li a3, 0
li a4, 0
li a5, 0
li a6, 0
li a7, 0
li s2, 0
li s3, 0
li s4, 0
li s5, 0
li s6, 0
li s7, 0
li s8, 0
li s9, 0
li s10, 0
li s11, 0
li t3, 0
li t4, 0
li t5, 0
li t6, 0
csrw CSR_MSCRATCH, 0
ret

View File

@@ -50,6 +50,8 @@
{ {
PROVIDE(_data_start = .); PROVIDE(_data_start = .);
*(.sdata)
*(.sdata.*)
*(.data) *(.data)
*(.data.*) *(.data.*)
*(.readmostly.data) *(.readmostly.data)
@@ -64,6 +66,8 @@
.bss : .bss :
{ {
PROVIDE(_bss_start = .); PROVIDE(_bss_start = .);
*(.sbss)
*(.sbss.*)
*(.bss) *(.bss)
*(.bss.*) *(.bss.*)
. = ALIGN(8); . = ALIGN(8);

118
firmware/fw_dynamic.S Normal file
View File

@@ -0,0 +1,118 @@
/*
* SPDX-License-Identifier: BSD-2-Clause
*
* Copyright (c) 2019 Western Digital Corporation or its affiliates.
*
* Authors:
* Anup Patel <anup.patel@wdc.com>
*/
#include <sbi/fw_dynamic.h>
#include "fw_base.S"
.align 3
.section .entry, "ax", %progbits
_bad_dynamic_info:
wfi
j _bad_dynamic_info
.align 3
.section .entry, "ax", %progbits
.global fw_save_info
/*
* We can only use a0, a1, a2, a3, and a4 registers here.
* The a0, a1, and a2 registers will be same as passed by
* previous booting stage.
* Nothing to be returned here.
*/
fw_save_info:
la a4, _dynamic_next_arg1
REG_S a1, (a4)
li a4, FW_DYNAMIC_INFO_MAGIC_VALUE
REG_L a3, FW_DYNAMIC_INFO_MAGIC_OFFSET(a2)
bne a3, a4, _bad_dynamic_info
li a4, FW_DYNAMIC_INFO_VERSION_MAX
REG_L a3, FW_DYNAMIC_INFO_VERSION_OFFSET(a2)
bgt a3, a4, _bad_dynamic_info
la a4, _dynamic_next_addr
REG_L a3, FW_DYNAMIC_INFO_NEXT_ADDR_OFFSET(a2)
REG_S a3, (a4)
la a4, _dynamic_next_mode
REG_L a3, FW_DYNAMIC_INFO_NEXT_MODE_OFFSET(a2)
REG_S a3, (a4)
la a4, _dynamic_options
REG_L a3, FW_DYNAMIC_INFO_OPTIONS_OFFSET(a2)
REG_S a3, (a4)
ret
.align 3
.section .entry, "ax", %progbits
.global fw_prev_arg1
/*
* We can only use a0, a1, and a2 registers here.
* The previous arg1 should be returned in 'a0'.
*/
fw_prev_arg1:
add a0, zero, zero
ret
.align 3
.section .entry, "ax", %progbits
.global fw_next_arg1
/*
* We can only use a0, a1, and a2 registers here.
* The next arg1 should be returned in 'a0'.
*/
fw_next_arg1:
la a0, _dynamic_next_arg1
REG_L a0, (a0)
ret
.align 3
.section .entry, "ax", %progbits
.global fw_next_addr
/*
* We can only use a0, a1, and a2 registers here.
* The next address should be returned in 'a0'.
*/
fw_next_addr:
la a0, _dynamic_next_addr
REG_L a0, (a0)
ret
.align 3
.section .entry, "ax", %progbits
.global fw_next_mode
/*
* We can only use a0, a1, and a2 registers here.
* The next address should be returned in 'a0'
*/
fw_next_mode:
la a0, _dynamic_next_mode
REG_L a0, (a0)
ret
.align 3
.section .entry, "ax", %progbits
.global fw_options
/*
* We can only use a0, a1, and a2 registers here.
* The 'a4' register will have default options.
* The next address should be returned in 'a0'.
*/
fw_options:
la a0, _dynamic_options
REG_L a0, (a0)
ret
.align 3
.section .entry, "ax", %progbits
_dynamic_next_arg1:
RISCV_PTR 0x0
_dynamic_next_addr:
RISCV_PTR 0x0
_dynamic_next_mode:
RISCV_PTR PRV_S
_dynamic_options:
RISCV_PTR 0x0

View File

@@ -0,0 +1,18 @@
/*
* SPDX-License-Identifier: BSD-2-Clause
*
* Copyright (c) 2019 Western Digital Corporation or its affiliates.
*
* Authors:
* Anup Patel <anup.patel@wdc.com>
*/
OUTPUT_ARCH(riscv)
ENTRY(_start)
SECTIONS
{
#include "fw_base.ldS"
PROVIDE(_fw_reloc_end = .);
}

View File

@@ -9,19 +9,37 @@
#include "fw_base.S" #include "fw_base.S"
.align 3
.section .entry, "ax", %progbits
.global fw_save_info
/*
* We can only use a0, a1, a2, a3, and a4 registers here.
* The a0, a1, and a2 registers will be same as passed by
* previous booting stage.
* Nothing to be returned here.
*/
fw_save_info:
ret
.align 3 .align 3
.section .entry, "ax", %progbits .section .entry, "ax", %progbits
.global fw_prev_arg1 .global fw_prev_arg1
/*
* We can only use a0, a1, and a2 registers here.
* The previous arg1 should be returned in 'a0'.
*/
fw_prev_arg1: fw_prev_arg1:
/* We return previous arg1 in 'a0' */
add a0, zero, zero add a0, zero, zero
ret ret
.align 3 .align 3
.section .entry, "ax", %progbits .section .entry, "ax", %progbits
.global fw_next_arg1 .global fw_next_arg1
/*
* We can only use a0, a1, and a2 registers here.
* The next arg1 should be returned in 'a0'.
*/
fw_next_arg1: fw_next_arg1:
/* We return next arg1 in 'a0' */
#ifdef FW_JUMP_FDT_ADDR #ifdef FW_JUMP_FDT_ADDR
li a0, FW_JUMP_FDT_ADDR li a0, FW_JUMP_FDT_ADDR
#else #else
@@ -32,12 +50,38 @@ fw_next_arg1:
.align 3 .align 3
.section .entry, "ax", %progbits .section .entry, "ax", %progbits
.global fw_next_addr .global fw_next_addr
/*
* We can only use a0, a1, and a2 registers here.
* The next address should be returned in 'a0'.
*/
fw_next_addr: fw_next_addr:
/* We return next address in 'a0' */
la a0, _jump_addr la a0, _jump_addr
REG_L a0, (a0) REG_L a0, (a0)
ret ret
.align 3
.section .entry, "ax", %progbits
.global fw_next_mode
/*
* We can only use a0, a1, and a2 registers here.
* The next address should be returned in 'a0'
*/
fw_next_mode:
li a0, PRV_S
ret
.align 3
.section .entry, "ax", %progbits
.global fw_options
/*
* We can only use a0, a1, and a2 registers here.
* The 'a4' register will have default options.
* The next address should be returned in 'a0'.
*/
fw_options:
add a0, zero, zero
ret
#ifndef FW_JUMP_ADDR #ifndef FW_JUMP_ADDR
#error "Must define FW_JUMP_ADDR" #error "Must define FW_JUMP_ADDR"
#endif #endif

View File

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

View File

@@ -9,11 +9,26 @@
#include "fw_base.S" #include "fw_base.S"
.align 4 .align 3
.section .entry, "ax", %progbits
.global fw_save_info
/*
* We can only use a0, a1, a2, a3, and a4 registers here.
* The a0, a1, and a2 registers will be same as passed by
* previous booting stage.
* Nothing to be returned here.
*/
fw_save_info:
ret
.align 3
.section .entry, "ax", %progbits .section .entry, "ax", %progbits
.global fw_prev_arg1 .global fw_prev_arg1
/*
* We can only use a0, a1, and a2 registers here.
* The previous arg1 should be returned in 'a0'.
*/
fw_prev_arg1: fw_prev_arg1:
/* We return previous arg1 in 'a0' */
#ifdef FW_PAYLOAD_FDT_PATH #ifdef FW_PAYLOAD_FDT_PATH
la a0, fdt_bin la a0, fdt_bin
#else #else
@@ -21,11 +36,14 @@ fw_prev_arg1:
#endif #endif
ret ret
.align 4 .align 3
.section .entry, "ax", %progbits .section .entry, "ax", %progbits
.global fw_next_arg1 .global fw_next_arg1
/*
* We can only use a0, a1, and a2 registers here.
* The next arg1 should be returned in 'a0'.
*/
fw_next_arg1: fw_next_arg1:
/* We return next arg1 in 'a0' */
#ifdef FW_PAYLOAD_FDT_ADDR #ifdef FW_PAYLOAD_FDT_ADDR
li a0, FW_PAYLOAD_FDT_ADDR li a0, FW_PAYLOAD_FDT_ADDR
#else #else
@@ -33,14 +51,40 @@ fw_next_arg1:
#endif #endif
ret ret
.align 4 .align 3
.section .entry, "ax", %progbits .section .entry, "ax", %progbits
.global fw_next_addr .global fw_next_addr
/*
* We can only use a0, a1, and a2 registers here.
* The next address should be returned in 'a0'.
*/
fw_next_addr: fw_next_addr:
/* We return next address in 'a0' */
la a0, payload_bin la a0, payload_bin
ret ret
.align 3
.section .entry, "ax", %progbits
.global fw_next_mode
/*
* We can only use a0, a1, and a2 registers here.
* The next address should be returned in 'a0'.
*/
fw_next_mode:
li a0, PRV_S
ret
.align 3
.section .entry, "ax", %progbits
.global fw_options
/*
* We can only use a0, a1, and a2 registers here.
* The 'a4' register will have default options.
* The next address should be returned in 'a0'.
*/
fw_options:
add a0, zero, zero
ret
#ifdef FW_PAYLOAD_FDT_PATH #ifdef FW_PAYLOAD_FDT_PATH
.align 4 .align 4
.section .text, "ax", %progbits .section .text, "ax", %progbits

View File

@@ -27,4 +27,6 @@ SECTIONS
. = ALIGN(8); . = ALIGN(8);
PROVIDE(_payload_end = .); PROVIDE(_payload_end = .);
} }
PROVIDE(_fw_reloc_end = .);
} }

View File

@@ -17,6 +17,8 @@ ifdef FW_TEXT_START
firmware-genflags-y += -DFW_TEXT_START=$(FW_TEXT_START) firmware-genflags-y += -DFW_TEXT_START=$(FW_TEXT_START)
endif endif
firmware-bins-$(FW_DYNAMIC) += fw_dynamic.bin
firmware-bins-$(FW_JUMP) += fw_jump.bin firmware-bins-$(FW_JUMP) += fw_jump.bin
ifdef FW_JUMP_ADDR ifdef FW_JUMP_ADDR
firmware-genflags-$(FW_JUMP) += -DFW_JUMP_ADDR=$(FW_JUMP_ADDR) firmware-genflags-$(FW_JUMP) += -DFW_JUMP_ADDR=$(FW_JUMP_ADDR)
@@ -29,7 +31,7 @@ firmware-bins-$(FW_PAYLOAD) += fw_payload.bin
ifdef FW_PAYLOAD_PATH ifdef FW_PAYLOAD_PATH
FW_PAYLOAD_PATH_FINAL=$(FW_PAYLOAD_PATH) FW_PAYLOAD_PATH_FINAL=$(FW_PAYLOAD_PATH)
else else
FW_PAYLOAD_PATH_FINAL=$(build_dir)/$(platform_subdir)/firmware/payloads/test.bin FW_PAYLOAD_PATH_FINAL=$(platform_build_dir)/firmware/payloads/test.bin
endif endif
firmware-genflags-$(FW_PAYLOAD) += -DFW_PAYLOAD_PATH=\"$(FW_PAYLOAD_PATH_FINAL)\" firmware-genflags-$(FW_PAYLOAD) += -DFW_PAYLOAD_PATH=\"$(FW_PAYLOAD_PATH_FINAL)\"
ifdef FW_PAYLOAD_OFFSET ifdef FW_PAYLOAD_OFFSET
@@ -41,7 +43,7 @@ endif
ifndef FW_PAYLOAD_FDT_PATH ifndef FW_PAYLOAD_FDT_PATH
ifdef FW_PAYLOAD_FDT ifdef FW_PAYLOAD_FDT
FW_PAYLOAD_FDT_PATH=$(build_dir)/$(platform_subdir)/$(FW_PAYLOAD_FDT) FW_PAYLOAD_FDT_PATH=$(platform_build_dir)/$(FW_PAYLOAD_FDT)
endif endif
endif endif
ifdef FW_PAYLOAD_FDT_PATH ifdef FW_PAYLOAD_FDT_PATH
@@ -50,3 +52,7 @@ endif
ifdef FW_PAYLOAD_FDT_ADDR ifdef FW_PAYLOAD_FDT_ADDR
firmware-genflags-$(FW_PAYLOAD) += -DFW_PAYLOAD_FDT_ADDR=$(FW_PAYLOAD_FDT_ADDR) firmware-genflags-$(FW_PAYLOAD) += -DFW_PAYLOAD_FDT_ADDR=$(FW_PAYLOAD_FDT_ADDR)
endif endif
ifdef FW_OPTIONS
firmware-genflags-y += -DFW_OPTIONS=$(FW_OPTIONS)
endif

View File

@@ -9,10 +9,10 @@
#include <sbi/sbi_ecall_interface.h> #include <sbi/sbi_ecall_interface.h>
#define wfi() \ #define wfi() \
do { \ do { \
__asm__ __volatile__ ("wfi" ::: "memory"); \ __asm__ __volatile__("wfi" ::: "memory"); \
} while (0) } while (0)
void test_main(unsigned long a0, unsigned long a1) void test_main(unsigned long a0, unsigned long a1)
{ {

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

@@ -0,0 +1,61 @@
/*
* SPDX-License-Identifier: BSD-2-Clause
*
* Copyright (c) 2019 Western Digital Corporation or its affiliates.
*
* Authors:
* Anup Patel <anup.patel@wdc.com>
*/
#ifndef __FW_DYNAMIC_H__
#define __FW_DYNAMIC_H__
#include <sbi/riscv_asm.h>
/* clang-format off */
/** Offset of magic member in fw_dynamic_info */
#define FW_DYNAMIC_INFO_MAGIC_OFFSET (0 * __SIZEOF_POINTER__)
/** Offset of version member in fw_dynamic_info */
#define FW_DYNAMIC_INFO_VERSION_OFFSET (1 * __SIZEOF_POINTER__)
/** Offset of next_addr member in fw_dynamic_info */
#define FW_DYNAMIC_INFO_NEXT_ADDR_OFFSET (2 * __SIZEOF_POINTER__)
/** Offset of next_mode member in fw_dynamic_info */
#define FW_DYNAMIC_INFO_NEXT_MODE_OFFSET (3 * __SIZEOF_POINTER__)
/** Offset of options member in fw_dynamic_info */
#define FW_DYNAMIC_INFO_OPTIONS_OFFSET (4 * __SIZEOF_POINTER__)
/** Expected value of info magic ('OSBI' ascii string in hex) */
#define FW_DYNAMIC_INFO_MAGIC_VALUE 0x4942534f
/** Maximum supported info version */
#define FW_DYNAMIC_INFO_VERSION_MAX 0x1
/** Possible next mode values */
#define FW_DYNAMIC_INFO_NEXT_MODE_U 0x0
#define FW_DYNAMIC_INFO_NEXT_MODE_S 0x1
#define FW_DYNAMIC_INFO_NEXT_MODE_M 0x3
/* clang-format on */
#ifndef __ASSEMBLY__
#include <sbi/sbi_types.h>
/** Representation dynamic info passed by previous booting stage */
struct fw_dynamic_info {
/** Info magic */
unsigned long magic;
/** Info version */
unsigned long version;
/** Next booting stage address */
unsigned long next_addr;
/** Next booting stage mode */
unsigned long next_mode;
/** Options for OpenSBI library */
unsigned long options;
} __packed;
#endif
#endif

View File

@@ -12,6 +12,8 @@
#include <sbi/riscv_encoding.h> #include <sbi/riscv_encoding.h>
/* clang-format off */
#ifdef __ASSEMBLY__ #ifdef __ASSEMBLY__
#define __ASM_STR(x) x #define __ASM_STR(x) x
#else #else
@@ -26,6 +28,10 @@
#error "Unexpected __riscv_xlen" #error "Unexpected __riscv_xlen"
#endif #endif
#define PAGE_SHIFT (12)
#define PAGE_SIZE (_AC(1, UL) << PAGE_SHIFT)
#define PAGE_MASK (~(PAGE_SIZE - 1))
#define REG_L __REG_SEL(ld, lw) #define REG_L __REG_SEL(ld, lw)
#define REG_S __REG_SEL(sd, sw) #define REG_S __REG_SEL(sd, sw)
#define SZREG __REG_SEL(8, 4) #define SZREG __REG_SEL(8, 4)
@@ -73,76 +79,85 @@
#error "Unexpected __SIZEOF_SHORT__" #error "Unexpected __SIZEOF_SHORT__"
#endif #endif
/* clang-format on */
#ifndef __ASSEMBLY__ #ifndef __ASSEMBLY__
#define csr_swap(csr, val) \ #define csr_swap(csr, val) \
({ \ ({ \
unsigned long __v = (unsigned long)(val); \ unsigned long __v = (unsigned long)(val); \
__asm__ __volatile__ ("csrrw %0, " __ASM_STR(csr) ", %1"\ __asm__ __volatile__("csrrw %0, " __ASM_STR(csr) ", %1" \
: "=r" (__v) : "rK" (__v) \ : "=r"(__v) \
: "memory"); \ : "rK"(__v) \
__v; \ : "memory"); \
}) __v; \
})
#define csr_read(csr) \ #define csr_read(csr) \
({ \ ({ \
register unsigned long __v; \ register unsigned long __v; \
__asm__ __volatile__ ("csrr %0, " __ASM_STR(csr) \ __asm__ __volatile__("csrr %0, " __ASM_STR(csr) \
: "=r" (__v) : \ : "=r"(__v) \
: "memory"); \ : \
__v; \ : "memory"); \
}) __v; \
})
#define csr_write(csr, val) \ #define csr_write(csr, val) \
({ \ ({ \
unsigned long __v = (unsigned long)(val); \ unsigned long __v = (unsigned long)(val); \
__asm__ __volatile__ ("csrw " __ASM_STR(csr) ", %0" \ __asm__ __volatile__("csrw " __ASM_STR(csr) ", %0" \
: : "rK" (__v) \ : \
: "memory"); \ : "rK"(__v) \
}) : "memory"); \
})
#define csr_read_set(csr, val) \ #define csr_read_set(csr, val) \
({ \ ({ \
unsigned long __v = (unsigned long)(val); \ unsigned long __v = (unsigned long)(val); \
__asm__ __volatile__ ("csrrs %0, " __ASM_STR(csr) ", %1"\ __asm__ __volatile__("csrrs %0, " __ASM_STR(csr) ", %1" \
: "=r" (__v) : "rK" (__v) \ : "=r"(__v) \
: "memory"); \ : "rK"(__v) \
__v; \ : "memory"); \
}) __v; \
})
#define csr_set(csr, val) \ #define csr_set(csr, val) \
({ \ ({ \
unsigned long __v = (unsigned long)(val); \ unsigned long __v = (unsigned long)(val); \
__asm__ __volatile__ ("csrs " __ASM_STR(csr) ", %0" \ __asm__ __volatile__("csrs " __ASM_STR(csr) ", %0" \
: : "rK" (__v) \ : \
: "memory"); \ : "rK"(__v) \
}) : "memory"); \
})
#define csr_read_clear(csr, val) \ #define csr_read_clear(csr, val) \
({ \ ({ \
unsigned long __v = (unsigned long)(val); \ unsigned long __v = (unsigned long)(val); \
__asm__ __volatile__ ("csrrc %0, " __ASM_STR(csr) ", %1"\ __asm__ __volatile__("csrrc %0, " __ASM_STR(csr) ", %1" \
: "=r" (__v) : "rK" (__v) \ : "=r"(__v) \
: "memory"); \ : "rK"(__v) \
__v; \ : "memory"); \
}) __v; \
})
#define csr_clear(csr, val) \ #define csr_clear(csr, val) \
({ \ ({ \
unsigned long __v = (unsigned long)(val); \ unsigned long __v = (unsigned long)(val); \
__asm__ __volatile__ ("csrc " __ASM_STR(csr) ", %0" \ __asm__ __volatile__("csrc " __ASM_STR(csr) ", %0" \
: : "rK" (__v) \ : \
: "memory"); \ : "rK"(__v) \
}) : "memory"); \
})
unsigned long csr_read_num(int csr_num); unsigned long csr_read_num(int csr_num);
void csr_write_num(int csr_num, unsigned long val); void csr_write_num(int csr_num, unsigned long val);
#define wfi() \ #define wfi() \
do { \ do { \
__asm__ __volatile__ ("wfi" ::: "memory"); \ __asm__ __volatile__("wfi" ::: "memory"); \
} while (0) } while (0)
static inline int misa_extension(char ext) static inline int misa_extension(char ext)
{ {
@@ -168,11 +183,11 @@ static inline void misa_string(char *out, unsigned int out_sz)
out++; out++;
} }
int pmp_set(unsigned int n, unsigned long prot, int pmp_set(unsigned int n, unsigned long prot, unsigned long addr,
unsigned long addr, unsigned long log2len); unsigned long log2len);
int pmp_get(unsigned int n, unsigned long *prot_out, int pmp_get(unsigned int n, unsigned long *prot_out, unsigned long *addr_out,
unsigned long *addr_out, unsigned long *log2len_out); unsigned long *log2len_out);
#endif /* !__ASSEMBLY__ */ #endif /* !__ASSEMBLY__ */

View File

@@ -14,11 +14,12 @@ typedef struct {
volatile long counter; volatile long counter;
} atomic_t; } atomic_t;
#define ATOMIC_INIT(_lptr, val) \ #define ATOMIC_INIT(_lptr, val) (_lptr)->counter = (val)
(_lptr)->counter = (val)
#define ATOMIC_INITIALIZER(val) \ #define ATOMIC_INITIALIZER(val) \
{ .counter = (val), } { \
.counter = (val), \
}
long atomic_read(atomic_t *atom); long atomic_read(atomic_t *atom);

View File

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

View File

@@ -14,6 +14,7 @@
/* TODO: Make constants usable in assembly with _AC() macro */ /* TODO: Make constants usable in assembly with _AC() macro */
/* clang-format off */
#define MSTATUS_UIE 0x00000001 #define MSTATUS_UIE 0x00000001
#define MSTATUS_SIE 0x00000002 #define MSTATUS_SIE 0x00000002
#define MSTATUS_HIE 0x00000004 #define MSTATUS_HIE 0x00000004
@@ -424,8 +425,8 @@
#define CAUSE_MISALIGNED_STORE 0x6 #define CAUSE_MISALIGNED_STORE 0x6
#define CAUSE_STORE_ACCESS 0x7 #define CAUSE_STORE_ACCESS 0x7
#define CAUSE_USER_ECALL 0x8 #define CAUSE_USER_ECALL 0x8
#define CAUSE_SUPERVISOR_ECALL 0x9 #define CAUSE_HYPERVISOR_ECALL 0x9
#define CAUSE_HYPERVISOR_ECALL 0xa #define CAUSE_SUPERVISOR_ECALL 0xa
#define CAUSE_MACHINE_ECALL 0xb #define CAUSE_MACHINE_ECALL 0xb
#define CAUSE_FETCH_PAGE_FAULT 0xc #define CAUSE_FETCH_PAGE_FAULT 0xc
#define CAUSE_LOAD_PAGE_FAULT 0xd #define CAUSE_LOAD_PAGE_FAULT 0xd
@@ -561,4 +562,6 @@
(s32)(((insn) >> 7) & 0x1f)) (s32)(((insn) >> 7) & 0x1f))
#define MASK_FUNCT3 0x7000 #define MASK_FUNCT3 0x7000
/* clang-format on */
#endif #endif

View File

@@ -21,28 +21,49 @@
#ifdef __riscv_flen #ifdef __riscv_flen
#define GET_F32_REG(insn, pos, regs) ({ \ #define GET_F32_REG(insn, pos, regs) \
register s32 value asm("a0") = SHIFT_RIGHT(insn, (pos)-3) & 0xf8; \ ({ \
ulong tmp; \ register s32 value asm("a0") = \
asm ("1: auipc %0, %%pcrel_hi(get_f32_reg); add %0, %0, %1; jalr t0, %0, %%pcrel_lo(1b)" : "=&r"(tmp), "+&r"(value) :: "t0"); \ SHIFT_RIGHT(insn, (pos)-3) & 0xf8; \
value; }) ulong tmp; \
#define SET_F32_REG(insn, pos, regs, val) ({ \ asm("1: auipc %0, %%pcrel_hi(get_f32_reg); add %0, %0, %1; jalr t0, %0, %%pcrel_lo(1b)" \
register u32 value asm("a0") = (val); \ : "=&r"(tmp), "+&r"(value)::"t0"); \
ulong offset = SHIFT_RIGHT(insn, (pos)-3) & 0xf8; \ value; \
ulong tmp; \ })
asm volatile ("1: auipc %0, %%pcrel_hi(put_f32_reg); add %0, %0, %2; jalr t0, %0, %%pcrel_lo(1b)" : "=&r"(tmp) : "r"(value), "r"(offset) : "t0"); }) #define SET_F32_REG(insn, pos, regs, val) \
({ \
register u32 value asm("a0") = (val); \
ulong offset = SHIFT_RIGHT(insn, (pos)-3) & 0xf8; \
ulong tmp; \
asm volatile( \
"1: auipc %0, %%pcrel_hi(put_f32_reg); add %0, %0, %2; jalr t0, %0, %%pcrel_lo(1b)" \
: "=&r"(tmp) \
: "r"(value), "r"(offset) \
: "t0"); \
})
#define init_fp_reg(i) SET_F32_REG((i) << 3, 3, 0, 0) #define init_fp_reg(i) SET_F32_REG((i) << 3, 3, 0, 0)
#define GET_F64_REG(insn, pos, regs) ({ \ #define GET_F64_REG(insn, pos, regs) \
register ulong value asm("a0") = SHIFT_RIGHT(insn, (pos)-3) & 0xf8; \ ({ \
ulong tmp; \ register ulong value asm("a0") = \
asm ("1: auipc %0, %%pcrel_hi(get_f64_reg); add %0, %0, %1; jalr t0, %0, %%pcrel_lo(1b)" : "=&r"(tmp), "+&r"(value) :: "t0"); \ SHIFT_RIGHT(insn, (pos)-3) & 0xf8; \
sizeof(ulong) == 4 ? *(int64_t*)value : (int64_t)value; }) ulong tmp; \
#define SET_F64_REG(insn, pos, regs, val) ({ \ asm("1: auipc %0, %%pcrel_hi(get_f64_reg); add %0, %0, %1; jalr t0, %0, %%pcrel_lo(1b)" \
uint64_t __val = (val); \ : "=&r"(tmp), "+&r"(value)::"t0"); \
register ulong value asm("a0") = sizeof(ulong) == 4 ? (ulong)&__val : (ulong)__val; \ sizeof(ulong) == 4 ? *(int64_t *)value : (int64_t)value; \
ulong offset = SHIFT_RIGHT(insn, (pos)-3) & 0xf8; \ })
ulong tmp; \ #define SET_F64_REG(insn, pos, regs, val) \
asm volatile ("1: auipc %0, %%pcrel_hi(put_f64_reg); add %0, %0, %2; jalr t0, %0, %%pcrel_lo(1b)" : "=&r"(tmp) : "r"(value), "r"(offset) : "t0"); }) ({ \
uint64_t __val = (val); \
register ulong value asm("a0") = \
sizeof(ulong) == 4 ? (ulong)&__val : (ulong)__val; \
ulong offset = SHIFT_RIGHT(insn, (pos)-3) & 0xf8; \
ulong tmp; \
asm volatile( \
"1: auipc %0, %%pcrel_hi(put_f64_reg); add %0, %0, %2; jalr t0, %0, %%pcrel_lo(1b)" \
: "=&r"(tmp) \
: "r"(value), "r"(offset) \
: "t0"); \
})
#define GET_FCSR() csr_read(CSR_FCSR) #define GET_FCSR() csr_read(CSR_FCSR)
#define SET_FCSR(value) csr_write(CSR_FCSR, (value)) #define SET_FCSR(value) csr_write(CSR_FCSR, (value))
#define GET_FRM() csr_read(CSR_FRM) #define GET_FRM() csr_read(CSR_FRM)
@@ -50,7 +71,7 @@
#define GET_FFLAGS() csr_read(CSR_FFLAGS) #define GET_FFLAGS() csr_read(CSR_FFLAGS)
#define SET_FFLAGS(value) csr_write(CSR_FFLAGS, (value)) #define SET_FFLAGS(value) csr_write(CSR_FFLAGS, (value))
#define SET_FS_DIRTY() ((void) 0) #define SET_FS_DIRTY() ((void)0)
#else #else
#error "Floating point emulation not supported.\n" #error "Floating point emulation not supported.\n"
@@ -62,8 +83,10 @@
#define GET_F64_RS1(insn, regs) (GET_F64_REG(insn, 15, regs)) #define GET_F64_RS1(insn, regs) (GET_F64_REG(insn, 15, regs))
#define GET_F64_RS2(insn, regs) (GET_F64_REG(insn, 20, regs)) #define GET_F64_RS2(insn, regs) (GET_F64_REG(insn, 20, regs))
#define GET_F64_RS3(insn, regs) (GET_F64_REG(insn, 27, regs)) #define GET_F64_RS3(insn, regs) (GET_F64_REG(insn, 27, regs))
#define SET_F32_RD(insn, regs, val) (SET_F32_REG(insn, 7, regs, val), SET_FS_DIRTY()) #define SET_F32_RD(insn, regs, val) \
#define SET_F64_RD(insn, regs, val) (SET_F64_REG(insn, 7, regs, val), SET_FS_DIRTY()) (SET_F32_REG(insn, 7, regs, val), SET_FS_DIRTY())
#define SET_F64_RD(insn, regs, val) \
(SET_F64_REG(insn, 7, regs, val), SET_FS_DIRTY())
#define GET_F32_RS2C(insn, regs) (GET_F32_REG(insn, 2, regs)) #define GET_F32_RS2C(insn, regs) (GET_F32_REG(insn, 2, regs))
#define GET_F32_RS2S(insn, regs) (GET_F32_REG(RVC_RS2S(insn), 0, regs)) #define GET_F32_RS2S(insn, regs) (GET_F32_REG(RVC_RS2S(insn), 0, regs))

View File

@@ -15,23 +15,23 @@
static inline void __raw_writeb(u8 val, volatile void *addr) static inline void __raw_writeb(u8 val, volatile void *addr)
{ {
asm volatile("sb %0, 0(%1)" : : "r" (val), "r" (addr)); asm volatile("sb %0, 0(%1)" : : "r"(val), "r"(addr));
} }
static inline void __raw_writew(u16 val, volatile void *addr) static inline void __raw_writew(u16 val, volatile void *addr)
{ {
asm volatile("sh %0, 0(%1)" : : "r" (val), "r" (addr)); asm volatile("sh %0, 0(%1)" : : "r"(val), "r"(addr));
} }
static inline void __raw_writel(u32 val, volatile void *addr) static inline void __raw_writel(u32 val, volatile void *addr)
{ {
asm volatile("sw %0, 0(%1)" : : "r" (val), "r" (addr)); asm volatile("sw %0, 0(%1)" : : "r"(val), "r"(addr));
} }
#if __riscv_xlen != 32 #if __riscv_xlen != 32
static inline void __raw_writeq(u64 val, volatile void *addr) static inline void __raw_writeq(u64 val, volatile void *addr)
{ {
asm volatile("sd %0, 0(%1)" : : "r" (val), "r" (addr)); asm volatile("sd %0, 0(%1)" : : "r"(val), "r"(addr));
} }
#endif #endif
@@ -39,7 +39,7 @@ static inline u8 __raw_readb(const volatile void *addr)
{ {
u8 val; u8 val;
asm volatile("lb %0, 0(%1)" : "=r" (val) : "r" (addr)); asm volatile("lb %0, 0(%1)" : "=r"(val) : "r"(addr));
return val; return val;
} }
@@ -47,7 +47,7 @@ static inline u16 __raw_readw(const volatile void *addr)
{ {
u16 val; u16 val;
asm volatile("lh %0, 0(%1)" : "=r" (val) : "r" (addr)); asm volatile("lh %0, 0(%1)" : "=r"(val) : "r"(addr));
return val; return val;
} }
@@ -55,7 +55,7 @@ static inline u32 __raw_readl(const volatile void *addr)
{ {
u32 val; u32 val;
asm volatile("lw %0, 0(%1)" : "=r" (val) : "r" (addr)); asm volatile("lw %0, 0(%1)" : "=r"(val) : "r"(addr));
return val; return val;
} }
@@ -64,12 +64,15 @@ static inline u64 __raw_readq(const volatile void *addr)
{ {
u64 val; u64 val;
asm volatile("ld %0, 0(%1)" : "=r" (val) : "r" (addr)); asm volatile("ld %0, 0(%1)" : "=r"(val) : "r"(addr));
return val; return val;
} }
#endif #endif
/* FIXME: These are now the same as asm-generic */ /* FIXME: These are now the same as asm-generic */
/* clang-format off */
#define __io_rbr() do {} while (0) #define __io_rbr() do {} while (0)
#define __io_rar() do {} while (0) #define __io_rar() do {} while (0)
#define __io_rbw() do {} while (0) #define __io_rbw() do {} while (0)
@@ -106,4 +109,6 @@ static inline u64 __raw_readq(const volatile void *addr)
#define writeq(v,c) ({ __io_bw(); __raw_writeq((v),(c)); __io_aw(); }) #define writeq(v,c) ({ __io_bw(); __raw_writeq((v),(c)); __io_aw(); })
#endif #endif
/* clang-format on */
#endif #endif

View File

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

View File

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

View File

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

View File

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

View File

@@ -12,11 +12,11 @@
#include <sbi/sbi_types.h> #include <sbi/sbi_types.h>
#define __printf(a, b) __attribute__((format(printf, a, b))) #define __printf(a, b) __attribute__((format(printf, a, b)))
bool sbi_isprintable(char ch); bool sbi_isprintable(char ch);
char sbi_getc(void); int sbi_getc(void);
void sbi_putc(char ch); void sbi_putc(char ch);
@@ -26,8 +26,7 @@ void sbi_gets(char *s, int maxwidth, char endchar);
int __printf(2, 3) sbi_sprintf(char *out, const char *format, ...); int __printf(2, 3) sbi_sprintf(char *out, const char *format, ...);
int __printf(3, 4) sbi_snprintf(char *out, u32 out_sz, int __printf(3, 4) sbi_snprintf(char *out, u32 out_sz, const char *format, ...);
const char *format, ...);
int __printf(1, 2) sbi_printf(const char *format, ...); int __printf(1, 2) sbi_printf(const char *format, ...);

View File

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

View File

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

View File

@@ -10,6 +10,8 @@
#ifndef __SBI_ECALL_INTERFACE_H__ #ifndef __SBI_ECALL_INTERFACE_H__
#define __SBI_ECALL_INTERFACE_H__ #define __SBI_ECALL_INTERFACE_H__
/* clang-format off */
#define SBI_ECALL_SET_TIMER 0 #define SBI_ECALL_SET_TIMER 0
#define SBI_ECALL_CONSOLE_PUTCHAR 1 #define SBI_ECALL_CONSOLE_PUTCHAR 1
#define SBI_ECALL_CONSOLE_GETCHAR 2 #define SBI_ECALL_CONSOLE_GETCHAR 2
@@ -20,24 +22,26 @@
#define SBI_ECALL_REMOTE_SFENCE_VMA_ASID 7 #define SBI_ECALL_REMOTE_SFENCE_VMA_ASID 7
#define SBI_ECALL_SHUTDOWN 8 #define SBI_ECALL_SHUTDOWN 8
#define SBI_ECALL(__num, __a0, __a1, __a2) ({ \ /* clang-format on */
register unsigned long a0 asm ("a0") = (unsigned long)(__a0); \
register unsigned long a1 asm ("a1") = (unsigned long)(__a1); \
register unsigned long a2 asm ("a2") = (unsigned long)(__a2); \
register unsigned long a7 asm ("a7") = (unsigned long)(__num); \
asm volatile ("ecall" \
: "+r" (a0) \
: "r" (a1), "r" (a2), "r" (a7) \
: "memory"); \
a0; \
})
#define SBI_ECALL_0(__num) SBI_ECALL(__num, 0, 0, 0) #define SBI_ECALL(__num, __a0, __a1, __a2) \
#define SBI_ECALL_1(__num, __a0) SBI_ECALL(__num, __a0, 0, 0) ({ \
#define SBI_ECALL_2(__num, __a0, __a1) SBI_ECALL(__num, __a0, __a1, 0) register unsigned long a0 asm("a0") = (unsigned long)(__a0); \
register unsigned long a1 asm("a1") = (unsigned long)(__a1); \
register unsigned long a2 asm("a2") = (unsigned long)(__a2); \
register unsigned long a7 asm("a7") = (unsigned long)(__num); \
asm volatile("ecall" \
: "+r"(a0) \
: "r"(a1), "r"(a2), "r"(a7) \
: "memory"); \
a0; \
})
#define sbi_ecall_console_putc(c) \ #define SBI_ECALL_0(__num) SBI_ECALL(__num, 0, 0, 0)
SBI_ECALL_1(SBI_ECALL_CONSOLE_PUTCHAR, (c)); #define SBI_ECALL_1(__num, __a0) SBI_ECALL(__num, __a0, 0, 0)
#define SBI_ECALL_2(__num, __a0, __a1) SBI_ECALL(__num, __a0, __a1, 0)
#define sbi_ecall_console_putc(c) SBI_ECALL_1(SBI_ECALL_CONSOLE_PUTCHAR, (c));
static inline void sbi_ecall_console_puts(const char *str) static inline void sbi_ecall_console_puts(const char *str)
{ {

View File

@@ -14,14 +14,10 @@
struct sbi_scratch; struct sbi_scratch;
int sbi_emulate_csr_read(int csr_num, int sbi_emulate_csr_read(int csr_num, u32 hartid, ulong mstatus,
u32 hartid, ulong mstatus, struct sbi_scratch *scratch, ulong *csr_val);
struct sbi_scratch *scratch,
ulong *csr_val);
int sbi_emulate_csr_write(int csr_num, int sbi_emulate_csr_write(int csr_num, u32 hartid, ulong mstatus,
u32 hartid, ulong mstatus, struct sbi_scratch *scratch, ulong csr_val);
struct sbi_scratch *scratch,
ulong csr_val);
#endif #endif

View File

@@ -10,6 +10,8 @@
#ifndef __SBI_ERROR_H__ #ifndef __SBI_ERROR_H__
#define __SBI_ERROR_H__ #define __SBI_ERROR_H__
/* clang-format off */
#define SBI_OK 0 #define SBI_OK 0
#define SBI_EUNKNOWN -1 #define SBI_EUNKNOWN -1
#define SBI_EFAIL -2 #define SBI_EFAIL -2
@@ -21,5 +23,10 @@
#define SBI_ETIMEDOUT -8 #define SBI_ETIMEDOUT -8
#define SBI_EIO -9 #define SBI_EIO -9
#define SBI_EILL -10 #define SBI_EILL -10
#define SBI_ENOSPC -11
#define SBI_ENOMEM -12
#define SBI_ETRAP -13
/* clang-format on */
#endif #endif

43
include/sbi/sbi_fifo.h Normal file
View File

@@ -0,0 +1,43 @@
/*
* SPDX-License-Identifier: BSD-2-Clause
*
* Copyright (c) 2019 Western Digital Corporation or its affiliates.
*
* Authors:
* Atish Patra<atish.patra@wdc.com>
*
*/
#ifndef __SBI_FIFO_H__
#define __SBI_FIFO_H__
#include <sbi/riscv_locks.h>
#include <sbi/sbi_types.h>
struct sbi_fifo {
void *queue;
spinlock_t qlock;
u16 entry_size;
u16 num_entries;
u16 avail;
u16 tail;
};
enum sbi_fifo_inplace_update_types {
SBI_FIFO_SKIP,
SBI_FIFO_UPDATED,
SBI_FIFO_RESET,
SBI_FIFO_UNCHANGED,
};
int sbi_fifo_dequeue(struct sbi_fifo *fifo, void *data);
int sbi_fifo_enqueue(struct sbi_fifo *fifo, void *data);
void sbi_fifo_init(struct sbi_fifo *fifo, void *queue_mem, u16 entries,
u16 entry_size);
bool sbi_fifo_is_empty(struct sbi_fifo *fifo);
bool sbi_fifo_is_full(struct sbi_fifo *fifo);
int sbi_fifo_inplace_update(struct sbi_fifo *fifo, void *in,
int (*fptr)(void *in, void *data));
u16 sbi_fifo_avail(struct sbi_fifo *fifo);
#endif

View File

@@ -14,16 +14,19 @@
struct sbi_scratch; struct sbi_scratch;
int sbi_hart_init(struct sbi_scratch *scratch, u32 hartid); int sbi_hart_init(struct sbi_scratch *scratch, u32 hartid, bool cold_boot);
void *sbi_hart_get_trap_info(struct sbi_scratch *scratch);
void sbi_hart_set_trap_info(struct sbi_scratch *scratch, void *data);
void sbi_hart_pmp_dump(struct sbi_scratch *scratch); void sbi_hart_pmp_dump(struct sbi_scratch *scratch);
void __attribute__((noreturn)) sbi_hart_hang(void); void __attribute__((noreturn)) sbi_hart_hang(void);
void __attribute__((noreturn)) sbi_hart_switch_mode(unsigned long arg0, void __attribute__((noreturn))
unsigned long arg1, sbi_hart_switch_mode(unsigned long arg0, unsigned long arg1,
unsigned long next_addr, unsigned long next_addr, unsigned long next_mode);
unsigned long next_mode);
void sbi_hart_mark_available(u32 hartid); void sbi_hart_mark_available(u32 hartid);

View File

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

View File

@@ -10,56 +10,60 @@
#ifndef __SBI_PLATFORM_H__ #ifndef __SBI_PLATFORM_H__
#define __SBI_PLATFORM_H__ #define __SBI_PLATFORM_H__
/** OpenSBI 32-bit platform version with:
* 1. upper 16-bits as major number
* 2. lower 16-bits as minor number
*/
#define SBI_PLATFORM_VERSION(Major, Minor) ((Major << 16) | Minor)
/** Offset of opensbi_version in struct sbi_platform */
#define SBI_PLATFORM_OPENSBI_VERSION_OFFSET (0x00)
/** Offset of platform_version in struct sbi_platform */
#define SBI_PLATFORM_VERSION_OFFSET (0x04)
/** Offset of name in struct sbi_platform */ /** Offset of name in struct sbi_platform */
#define SBI_PLATFORM_NAME_OFFSET (0x0) #define SBI_PLATFORM_NAME_OFFSET (0x08)
/** Offset of features in struct sbi_platform */ /** Offset of features in struct sbi_platform */
#define SBI_PLATFORM_FEATURES_OFFSET (0x40) #define SBI_PLATFORM_FEATURES_OFFSET (0x48)
/** Offset of hart_count in struct sbi_platform */ /** Offset of hart_count in struct sbi_platform */
#define SBI_PLATFORM_HART_COUNT_OFFSET (0x48) #define SBI_PLATFORM_HART_COUNT_OFFSET (0x50)
/** Offset of hart_stack_size in struct sbi_platform */ /** Offset of hart_stack_size in struct sbi_platform */
#define SBI_PLATFORM_HART_STACK_SIZE_OFFSET (0x4c) #define SBI_PLATFORM_HART_STACK_SIZE_OFFSET (0x54)
/** Offset of disabled_hart_mask in struct sbi_platform */
#define SBI_PLATFORM_DISABLED_HART_OFFSET (0x58)
/** Offset of platform_ops_addr in struct sbi_platform */
#define SBI_PLATFORM_OPS_OFFSET (0x60)
/** Offset of firmware_context in struct sbi_platform */
#define SBI_PLATFORM_FIRMWARE_CONTEXT_OFFSET (0x60 + __SIZEOF_POINTER__)
#ifndef __ASSEMBLY__ #ifndef __ASSEMBLY__
#include <sbi/sbi_version.h>
#include <sbi/sbi_scratch.h> #include <sbi/sbi_scratch.h>
/** Possible feature flags of a platform */ /** Possible feature flags of a platform */
enum sbi_platform_features { enum sbi_platform_features {
/** Platform has timer value */ /** Platform has timer value */
SBI_PLATFORM_HAS_TIMER_VALUE = (1 << 0), SBI_PLATFORM_HAS_TIMER_VALUE = (1 << 0),
/** Platform has HART hotplug support */ /** Platform has HART hotplug support */
SBI_PLATFORM_HAS_HART_HOTPLUG = (1 << 1), SBI_PLATFORM_HAS_HART_HOTPLUG = (1 << 1),
/** Platform has PMP support */ /** Platform has PMP support */
SBI_PLATFORM_HAS_PMP = (1 << 2), SBI_PLATFORM_HAS_PMP = (1 << 2),
/** Platform has S-mode counter enable */ /** Platform has S-mode counter enable */
SBI_PLATFORM_HAS_SCOUNTEREN = (1 << 3), SBI_PLATFORM_HAS_SCOUNTEREN = (1 << 3),
/** Platform has M-mode counter enable */ /** Platform has M-mode counter enable */
SBI_PLATFORM_HAS_MCOUNTEREN = (1 << 4), SBI_PLATFORM_HAS_MCOUNTEREN = (1 << 4),
/** Platform has fault delegation support */ /** Platform has fault delegation support */
SBI_PLATFORM_HAS_MFAULTS_DELEGATION = (1 << 5), SBI_PLATFORM_HAS_MFAULTS_DELEGATION = (1 << 5),
}; };
/** Default feature set for a platform */ /** Default feature set for a platform */
#define SBI_PLATFORM_DEFAULT_FEATURES \ #define SBI_PLATFORM_DEFAULT_FEATURES \
(SBI_PLATFORM_HAS_TIMER_VALUE | \ (SBI_PLATFORM_HAS_TIMER_VALUE | SBI_PLATFORM_HAS_PMP | \
SBI_PLATFORM_HAS_PMP | \ SBI_PLATFORM_HAS_SCOUNTEREN | SBI_PLATFORM_HAS_MCOUNTEREN | \
SBI_PLATFORM_HAS_SCOUNTEREN | \
SBI_PLATFORM_HAS_MCOUNTEREN | \
SBI_PLATFORM_HAS_MFAULTS_DELEGATION) SBI_PLATFORM_HAS_MFAULTS_DELEGATION)
/** Representation of a platform */ /** Platform functions */
struct sbi_platform { struct sbi_platform_operations {
/** Name of the platform */
char name[64];
/** Supported features */
u64 features;
/** Total number of HARTs */
u32 hart_count;
/** Per-HART stack size for exception/interrupt handling */
u32 hart_stack_size;
/** Mask representing the set of disabled HARTs */
u64 disabled_hart_mask;
/** Platform early initialization */ /** Platform early initialization */
int (*early_init)(bool cold_boot); int (*early_init)(bool cold_boot);
/** Platform final initialization */ /** Platform final initialization */
@@ -71,13 +75,13 @@ struct sbi_platform {
* Get PMP regions details (namely: protection, base address, * Get PMP regions details (namely: protection, base address,
* and size) for given HART * and size) for given HART
*/ */
int (*pmp_region_info)(u32 hartid, u32 index, int (*pmp_region_info)(u32 hartid, u32 index, ulong *prot, ulong *addr,
ulong *prot, ulong *addr, ulong *log2size); ulong *log2size);
/** Write a character to the platform console output */ /** Write a character to the platform console output */
void (*console_putc)(char ch); void (*console_putc)(char ch);
/** Read a character from the platform console input */ /** Read a character from the platform console input */
char (*console_getc)(void); int (*console_getc)(void);
/** Initialize the platform console */ /** Initialize the platform console */
int (*console_init)(void); int (*console_init)(void);
@@ -108,29 +112,62 @@ struct sbi_platform {
int (*system_shutdown)(u32 type); int (*system_shutdown)(u32 type);
} __packed; } __packed;
/** Representation of a platform */
struct sbi_platform {
/**
* OpenSBI version this sbi_platform is based on.
* It's a 32-bit value where upper 16-bits are major number
* and lower 16-bits are minor number
*/
u32 opensbi_version;
/**
* OpenSBI platform version released by vendor.
* It's a 32-bit value where upper 16-bits are major number
* and lower 16-bits are minor number
*/
u32 platform_version;
/** Name of the platform */
char name[64];
/** Supported features */
u64 features;
/** Total number of HARTs */
u32 hart_count;
/** Per-HART stack size for exception/interrupt handling */
u32 hart_stack_size;
/** Mask representing the set of disabled HARTs */
u64 disabled_hart_mask;
/** Pointer to sbi platform operations */
unsigned long platform_ops_addr;
/** Pointer to system firmware specific context */
unsigned long firmware_context;
} __packed;
/** Get pointer to sbi_platform for sbi_scratch pointer */ /** Get pointer to sbi_platform for sbi_scratch pointer */
#define sbi_platform_ptr(__s) \ #define sbi_platform_ptr(__s) \
((struct sbi_platform *)((__s)->platform_addr)) ((const struct sbi_platform *)((__s)->platform_addr))
/** Get pointer to sbi_platform for current HART */ /** Get pointer to sbi_platform for current HART */
#define sbi_platform_thishart_ptr() \ #define sbi_platform_thishart_ptr() ((const struct sbi_platform *) \
((struct sbi_platform *)(sbi_scratch_thishart_ptr()->platform_addr)) (sbi_scratch_thishart_ptr()->platform_addr))
/** Get pointer to platform_ops_addr from platform pointer **/
#define sbi_platform_ops(__p) \
((const struct sbi_platform_operations *)(__p)->platform_ops_addr)
/** Check whether the platform supports timer value */ /** Check whether the platform supports timer value */
#define sbi_platform_has_timer_value(__p) \ #define sbi_platform_has_timer_value(__p) \
((__p)->features & SBI_PLATFORM_HAS_TIMER_VALUE) ((__p)->features & SBI_PLATFORM_HAS_TIMER_VALUE)
/** Check whether the platform supports HART hotplug */ /** Check whether the platform supports HART hotplug */
#define sbi_platform_has_hart_hotplug(__p) \ #define sbi_platform_has_hart_hotplug(__p) \
((__p)->features & SBI_PLATFORM_HAS_HART_HOTPLUG) ((__p)->features & SBI_PLATFORM_HAS_HART_HOTPLUG)
/** Check whether the platform has PMP support */ /** Check whether the platform has PMP support */
#define sbi_platform_has_pmp(__p) \ #define sbi_platform_has_pmp(__p) ((__p)->features & SBI_PLATFORM_HAS_PMP)
((__p)->features & SBI_PLATFORM_HAS_PMP)
/** Check whether the platform supports scounteren CSR */ /** Check whether the platform supports scounteren CSR */
#define sbi_platform_has_scounteren(__p) \ #define sbi_platform_has_scounteren(__p) \
((__p)->features & SBI_PLATFORM_HAS_SCOUNTEREN) ((__p)->features & SBI_PLATFORM_HAS_SCOUNTEREN)
/** Check whether the platform supports mcounteren CSR */ /** Check whether the platform supports mcounteren CSR */
#define sbi_platform_has_mcounteren(__p) \ #define sbi_platform_has_mcounteren(__p) \
((__p)->features & SBI_PLATFORM_HAS_MCOUNTEREN) ((__p)->features & SBI_PLATFORM_HAS_MCOUNTEREN)
/** Check whether the platform supports fault delegation */ /** Check whether the platform supports fault delegation */
#define sbi_platform_has_mfaults_delegation(__p) \ #define sbi_platform_has_mfaults_delegation(__p) \
((__p)->features & SBI_PLATFORM_HAS_MFAULTS_DELEGATION) ((__p)->features & SBI_PLATFORM_HAS_MFAULTS_DELEGATION)
/** /**
@@ -140,7 +177,7 @@ struct sbi_platform {
* *
* @return pointer to platform name on success and NULL on failure * @return pointer to platform name on success and NULL on failure
*/ */
static inline const char *sbi_platform_name(struct sbi_platform *plat) static inline const char *sbi_platform_name(const struct sbi_platform *plat)
{ {
if (plat) if (plat)
return plat->name; return plat->name;
@@ -155,7 +192,7 @@ static inline const char *sbi_platform_name(struct sbi_platform *plat)
* *
* @return TRUE if HART is disabled and FALSE otherwise * @return TRUE if HART is disabled and FALSE otherwise
*/ */
static inline bool sbi_platform_hart_disabled(struct sbi_platform *plat, static inline bool sbi_platform_hart_disabled(const struct sbi_platform *plat,
u32 hartid) u32 hartid)
{ {
if (plat && (plat->disabled_hart_mask & (1 << hartid))) if (plat && (plat->disabled_hart_mask & (1 << hartid)))
@@ -170,7 +207,7 @@ static inline bool sbi_platform_hart_disabled(struct sbi_platform *plat,
* *
* @return total number of HARTs * @return total number of HARTs
*/ */
static inline u32 sbi_platform_hart_count(struct sbi_platform *plat) static inline u32 sbi_platform_hart_count(const struct sbi_platform *plat)
{ {
if (plat) if (plat)
return plat->hart_count; return plat->hart_count;
@@ -184,7 +221,7 @@ static inline u32 sbi_platform_hart_count(struct sbi_platform *plat)
* *
* @return stack size in bytes * @return stack size in bytes
*/ */
static inline u32 sbi_platform_hart_stack_size(struct sbi_platform *plat) static inline u32 sbi_platform_hart_stack_size(const struct sbi_platform *plat)
{ {
if (plat) if (plat)
return plat->hart_stack_size; return plat->hart_stack_size;
@@ -199,11 +236,11 @@ static inline u32 sbi_platform_hart_stack_size(struct sbi_platform *plat)
* *
* @return 0 on success and negative error code on failure * @return 0 on success and negative error code on failure
*/ */
static inline int sbi_platform_early_init(struct sbi_platform *plat, static inline int sbi_platform_early_init(const struct sbi_platform *plat,
bool cold_boot) bool cold_boot)
{ {
if (plat && plat->early_init) if (plat && sbi_platform_ops(plat)->early_init)
return plat->early_init(cold_boot); return sbi_platform_ops(plat)->early_init(cold_boot);
return 0; return 0;
} }
@@ -215,11 +252,11 @@ static inline int sbi_platform_early_init(struct sbi_platform *plat,
* *
* @return 0 on success and negative error code on failure * @return 0 on success and negative error code on failure
*/ */
static inline int sbi_platform_final_init(struct sbi_platform *plat, static inline int sbi_platform_final_init(const struct sbi_platform *plat,
bool cold_boot) bool cold_boot)
{ {
if (plat && plat->final_init) if (plat && sbi_platform_ops(plat)->final_init)
return plat->final_init(cold_boot); return sbi_platform_ops(plat)->final_init(cold_boot);
return 0; return 0;
} }
@@ -231,11 +268,11 @@ static inline int sbi_platform_final_init(struct sbi_platform *plat,
* *
* @return number of PMP regions * @return number of PMP regions
*/ */
static inline u32 sbi_platform_pmp_region_count(struct sbi_platform *plat, static inline u32 sbi_platform_pmp_region_count(const struct sbi_platform *plat,
u32 hartid) u32 hartid)
{ {
if (plat && plat->pmp_region_count) if (plat && sbi_platform_ops(plat)->pmp_region_count)
return plat->pmp_region_count(hartid); return sbi_platform_ops(plat)->pmp_region_count(hartid);
return 0; return 0;
} }
@@ -252,14 +289,14 @@ static inline u32 sbi_platform_pmp_region_count(struct sbi_platform *plat,
* *
* @return 0 on success and negative error code on failure * @return 0 on success and negative error code on failure
*/ */
static inline int sbi_platform_pmp_region_info(struct sbi_platform *plat, static inline int sbi_platform_pmp_region_info(const struct sbi_platform *plat,
u32 hartid, u32 index, u32 hartid, u32 index,
ulong *prot, ulong *addr, ulong *prot, ulong *addr,
ulong *log2size) ulong *log2size)
{ {
if (plat && plat->pmp_region_info) if (plat && sbi_platform_ops(plat)->pmp_region_info)
return plat->pmp_region_info(hartid, index, return sbi_platform_ops(plat)->pmp_region_info(hartid, index, prot, addr,
prot, addr, log2size); log2size);
return 0; return 0;
} }
@@ -269,11 +306,11 @@ static inline int sbi_platform_pmp_region_info(struct sbi_platform *plat,
* @param plat pointer to struct sbi_platform * @param plat pointer to struct sbi_platform
* @param ch character to write * @param ch character to write
*/ */
static inline void sbi_platform_console_putc(struct sbi_platform *plat, static inline void sbi_platform_console_putc(const struct sbi_platform *plat,
char ch) char ch)
{ {
if (plat && plat->console_putc) if (plat && sbi_platform_ops(plat)->console_putc)
plat->console_putc(ch); sbi_platform_ops(plat)->console_putc(ch);
} }
/** /**
@@ -283,11 +320,11 @@ static inline void sbi_platform_console_putc(struct sbi_platform *plat,
* *
* @return character read from console input * @return character read from console input
*/ */
static inline char sbi_platform_console_getc(struct sbi_platform *plat) static inline int sbi_platform_console_getc(const struct sbi_platform *plat)
{ {
if (plat && plat->console_getc) if (plat && sbi_platform_ops(plat)->console_getc)
return plat->console_getc(); return sbi_platform_ops(plat)->console_getc();
return 0; return -1;
} }
/** /**
@@ -297,10 +334,10 @@ static inline char sbi_platform_console_getc(struct sbi_platform *plat)
* *
* @return 0 on success and negative error code on failure * @return 0 on success and negative error code on failure
*/ */
static inline int sbi_platform_console_init(struct sbi_platform *plat) static inline int sbi_platform_console_init(const struct sbi_platform *plat)
{ {
if (plat && plat->console_init) if (plat && sbi_platform_ops(plat)->console_init)
return plat->console_init(); return sbi_platform_ops(plat)->console_init();
return 0; return 0;
} }
@@ -312,11 +349,11 @@ static inline int sbi_platform_console_init(struct sbi_platform *plat)
* *
* @return 0 on success and negative error code on failure * @return 0 on success and negative error code on failure
*/ */
static inline int sbi_platform_irqchip_init(struct sbi_platform *plat, static inline int sbi_platform_irqchip_init(const struct sbi_platform *plat,
bool cold_boot) bool cold_boot)
{ {
if (plat && plat->irqchip_init) if (plat && sbi_platform_ops(plat)->irqchip_init)
return plat->irqchip_init(cold_boot); return sbi_platform_ops(plat)->irqchip_init(cold_boot);
return 0; return 0;
} }
@@ -326,11 +363,11 @@ static inline int sbi_platform_irqchip_init(struct sbi_platform *plat,
* @param plat pointer to struct sbi_platform * @param plat pointer to struct sbi_platform
* @param target_hart HART ID of IPI target * @param target_hart HART ID of IPI target
*/ */
static inline void sbi_platform_ipi_send(struct sbi_platform *plat, static inline void sbi_platform_ipi_send(const struct sbi_platform *plat,
u32 target_hart) u32 target_hart)
{ {
if (plat && plat->ipi_send) if (plat && sbi_platform_ops(plat)->ipi_send)
plat->ipi_send(target_hart); sbi_platform_ops(plat)->ipi_send(target_hart);
} }
/** /**
@@ -339,11 +376,11 @@ static inline void sbi_platform_ipi_send(struct sbi_platform *plat,
* @param plat pointer to struct sbi_platform * @param plat pointer to struct sbi_platform
* @param target_hart HART ID of IPI target * @param target_hart HART ID of IPI target
*/ */
static inline void sbi_platform_ipi_sync(struct sbi_platform *plat, static inline void sbi_platform_ipi_sync(const struct sbi_platform *plat,
u32 target_hart) u32 target_hart)
{ {
if (plat && plat->ipi_sync) if (plat && sbi_platform_ops(plat)->ipi_sync)
plat->ipi_sync(target_hart); sbi_platform_ops(plat)->ipi_sync(target_hart);
} }
/** /**
@@ -352,11 +389,11 @@ static inline void sbi_platform_ipi_sync(struct sbi_platform *plat,
* @param plat pointer to struct sbi_platform * @param plat pointer to struct sbi_platform
* @param target_hart HART ID of IPI target * @param target_hart HART ID of IPI target
*/ */
static inline void sbi_platform_ipi_clear(struct sbi_platform *plat, static inline void sbi_platform_ipi_clear(const struct sbi_platform *plat,
u32 target_hart) u32 target_hart)
{ {
if (plat && plat->ipi_clear) if (plat && sbi_platform_ops(plat)->ipi_clear)
plat->ipi_clear(target_hart); sbi_platform_ops(plat)->ipi_clear(target_hart);
} }
/** /**
@@ -367,11 +404,11 @@ static inline void sbi_platform_ipi_clear(struct sbi_platform *plat,
* *
* @return 0 on success and negative error code on failure * @return 0 on success and negative error code on failure
*/ */
static inline int sbi_platform_ipi_init(struct sbi_platform *plat, static inline int sbi_platform_ipi_init(const struct sbi_platform *plat,
bool cold_boot) bool cold_boot)
{ {
if (plat && plat->ipi_init) if (plat && sbi_platform_ops(plat)->ipi_init)
return plat->ipi_init(cold_boot); return sbi_platform_ops(plat)->ipi_init(cold_boot);
return 0; return 0;
} }
@@ -382,10 +419,10 @@ static inline int sbi_platform_ipi_init(struct sbi_platform *plat,
* *
* @return 64bit timer value * @return 64bit timer value
*/ */
static inline u64 sbi_platform_timer_value(struct sbi_platform *plat) static inline u64 sbi_platform_timer_value(const struct sbi_platform *plat)
{ {
if (plat && plat->timer_value) if (plat && sbi_platform_ops(plat)->timer_value)
return plat->timer_value(); return sbi_platform_ops(plat)->timer_value();
return 0; return 0;
} }
@@ -395,11 +432,11 @@ static inline u64 sbi_platform_timer_value(struct sbi_platform *plat)
* @param plat pointer to struct struct sbi_platform * @param plat pointer to struct struct sbi_platform
* @param next_event timer value when timer event will happen * @param next_event timer value when timer event will happen
*/ */
static inline void sbi_platform_timer_event_start(struct sbi_platform *plat, static inline void
u64 next_event) sbi_platform_timer_event_start(const struct sbi_platform *plat, u64 next_event)
{ {
if (plat && plat->timer_event_start) if (plat && sbi_platform_ops(plat)->timer_event_start)
plat->timer_event_start(next_event); sbi_platform_ops(plat)->timer_event_start(next_event);
} }
/** /**
@@ -407,10 +444,11 @@ static inline void sbi_platform_timer_event_start(struct sbi_platform *plat,
* *
* @param plat pointer to struct sbi_platform * @param plat pointer to struct sbi_platform
*/ */
static inline void sbi_platform_timer_event_stop(struct sbi_platform *plat) static inline void
sbi_platform_timer_event_stop(const struct sbi_platform *plat)
{ {
if (plat && plat->timer_event_stop) if (plat && sbi_platform_ops(plat)->timer_event_stop)
plat->timer_event_stop(); sbi_platform_ops(plat)->timer_event_stop();
} }
/** /**
@@ -421,11 +459,11 @@ static inline void sbi_platform_timer_event_stop(struct sbi_platform *plat)
* *
* @return 0 on success and negative error code on failure * @return 0 on success and negative error code on failure
*/ */
static inline int sbi_platform_timer_init(struct sbi_platform *plat, static inline int sbi_platform_timer_init(const struct sbi_platform *plat,
bool cold_boot) bool cold_boot)
{ {
if (plat && plat->timer_init) if (plat && sbi_platform_ops(plat)->timer_init)
return plat->timer_init(cold_boot); return sbi_platform_ops(plat)->timer_init(cold_boot);
return 0; return 0;
} }
@@ -437,11 +475,11 @@ static inline int sbi_platform_timer_init(struct sbi_platform *plat,
* *
* @return 0 on success and negative error code on failure * @return 0 on success and negative error code on failure
*/ */
static inline int sbi_platform_system_reboot(struct sbi_platform *plat, static inline int sbi_platform_system_reboot(const struct sbi_platform *plat,
u32 type) u32 type)
{ {
if (plat && plat->system_reboot) if (plat && sbi_platform_ops(plat)->system_reboot)
return plat->system_reboot(type); return sbi_platform_ops(plat)->system_reboot(type);
return 0; return 0;
} }
@@ -453,11 +491,11 @@ static inline int sbi_platform_system_reboot(struct sbi_platform *plat,
* *
* @return 0 on success and negative error code on failure * @return 0 on success and negative error code on failure
*/ */
static inline int sbi_platform_system_shutdown(struct sbi_platform *plat, static inline int sbi_platform_system_shutdown(const struct sbi_platform *plat,
u32 type) u32 type)
{ {
if (plat && plat->system_shutdown) if (plat && sbi_platform_ops(plat)->system_shutdown)
return plat->system_shutdown(type); return sbi_platform_ops(plat)->system_shutdown(type);
return 0; return 0;
} }

View File

@@ -12,6 +12,8 @@
#include <sbi/riscv_asm.h> #include <sbi/riscv_asm.h>
/* clang-format off */
/** Offset of fw_start member in sbi_scratch */ /** Offset of fw_start member in sbi_scratch */
#define SBI_SCRATCH_FW_START_OFFSET (0 * __SIZEOF_POINTER__) #define SBI_SCRATCH_FW_START_OFFSET (0 * __SIZEOF_POINTER__)
/** Offset of fw_size member in sbi_scratch */ /** Offset of fw_size member in sbi_scratch */
@@ -28,16 +30,21 @@
#define SBI_SCRATCH_PLATFORM_ADDR_OFFSET (6 * __SIZEOF_POINTER__) #define SBI_SCRATCH_PLATFORM_ADDR_OFFSET (6 * __SIZEOF_POINTER__)
/** Offset of hartid_to_scratch member in sbi_scratch */ /** Offset of hartid_to_scratch member in sbi_scratch */
#define SBI_SCRATCH_HARTID_TO_SCRATCH_OFFSET (7 * __SIZEOF_POINTER__) #define SBI_SCRATCH_HARTID_TO_SCRATCH_OFFSET (7 * __SIZEOF_POINTER__)
/** Offset of ipi_type member in sbi_scratch */
#define SBI_SCRATCH_IPI_TYPE_OFFSET (8 * __SIZEOF_POINTER__)
/** Offset of tmp0 member in sbi_scratch */ /** Offset of tmp0 member in sbi_scratch */
#define SBI_SCRATCH_TMP0_OFFSET (9 * __SIZEOF_POINTER__) #define SBI_SCRATCH_TMP0_OFFSET (8 * __SIZEOF_POINTER__)
/** Maximum size of sbi_scratch */ /** Offset of options member in sbi_scratch */
#define SBI_SCRATCH_SIZE 256 #define SBI_SCRATCH_OPTIONS_OFFSET (9 * __SIZEOF_POINTER__)
/** Offset of extra space in sbi_scratch */
#define SBI_SCRATCH_EXTRA_SPACE_OFFSET (10 * __SIZEOF_POINTER__)
/** Maximum size of sbi_scratch and sbi_ipi_data */
#define SBI_SCRATCH_SIZE (64 * __SIZEOF_POINTER__)
/* clang-format on */
#ifndef __ASSEMBLY__ #ifndef __ASSEMBLY__
#include <sbi/sbi_types.h> #include <sbi/sbi_types.h>
#include <sbi/sbi_ipi.h>
/** Representation of per-HART scratch space */ /** Representation of per-HART scratch space */
struct sbi_scratch { struct sbi_scratch {
@@ -57,19 +64,42 @@ struct sbi_scratch {
unsigned long platform_addr; unsigned long platform_addr;
/** Address of HART ID to sbi_scratch conversion function */ /** Address of HART ID to sbi_scratch conversion function */
unsigned long hartid_to_scratch; unsigned long hartid_to_scratch;
/** IPI type (or flags) */
unsigned long ipi_type;
/** Temporary storage */ /** Temporary storage */
unsigned long tmp0; unsigned long tmp0;
/** Options for OpenSBI library */
unsigned long options;
} __packed; } __packed;
/** Possible options for OpenSBI library */
enum sbi_scratch_options {
/** Disable prints during boot */
SBI_SCRATCH_NO_BOOT_PRINTS = (1 << 0),
};
/** Get pointer to sbi_scratch for current HART */ /** Get pointer to sbi_scratch for current HART */
#define sbi_scratch_thishart_ptr() \ #define sbi_scratch_thishart_ptr() \
((struct sbi_scratch *)csr_read(CSR_MSCRATCH)) ((struct sbi_scratch *)csr_read(CSR_MSCRATCH))
/** Get Arg1 of next booting stage for current HART */ /** Get Arg1 of next booting stage for current HART */
#define sbi_scratch_thishart_arg1_ptr() \ #define sbi_scratch_thishart_arg1_ptr() \
((void *)(sbi_scratch_thishart_ptr()->next_arg1)) ((void *)(sbi_scratch_thishart_ptr()->next_arg1))
/** Allocate from extra space in sbi_scratch
*
* @return zero on failure and non-zero (>= SBI_SCRATCH_EXTRA_SPACE_OFFSET)
* on success
*/
unsigned long sbi_scratch_alloc_offset(unsigned long size, const char *owner);
/** Free-up extra space in sbi_scratch */
void sbi_scratch_free_offset(unsigned long offset);
/** Get pointer from offset in sbi_scratch */
#define sbi_scratch_offset_ptr(scratch, offset) ((void *)scratch + (offset))
/** Get pointer from offset in sbi_scratch for current HART */
#define sbi_scratch_thishart_offset_ptr(offset) \
((void *)sbi_scratch_thishart_ptr() + (offset))
#endif #endif

39
include/sbi/sbi_string.h Normal file
View File

@@ -0,0 +1,39 @@
/*
* SPDX-License-Identifier: BSD-2-Clause
*
* Copyright (c) 2019 Western Digital Corporation or its affiliates.
*
* Authors:
* Atish Patra <atish.patra@wdc.com>
*/
#ifndef __STRING_H__
#define __STRING_H__
#include <sbi/sbi_types.h>
int sbi_strcmp(const char *a, const char *b);
size_t sbi_strlen(const char *str);
size_t sbi_strnlen(const char *str, size_t count);
char *sbi_strcpy(char *dest, const char *src);
char *sbi_strncpy(char *dest, const char *src, size_t count);
char *sbi_strchr(const char *s, int c);
char *sbi_strrchr(const char *s, int c);
void *sbi_memset(void *s, int c, size_t count);
void *sbi_memcpy(void *dest, const void *src, size_t count);
void *sbi_memmove(void *dest, const void *src, size_t count);
int sbi_memcmp(const void *s1, const void *s2, size_t count);
void *sbi_memchr(const void *s, int c, size_t count);
#endif

View File

@@ -18,10 +18,10 @@ int sbi_system_early_init(struct sbi_scratch *scratch, bool cold_boot);
int sbi_system_final_init(struct sbi_scratch *scratch, bool cold_boot); int sbi_system_final_init(struct sbi_scratch *scratch, bool cold_boot);
void __attribute__((noreturn)) sbi_system_reboot(struct sbi_scratch *scratch, void __attribute__((noreturn))
u32 type); sbi_system_reboot(struct sbi_scratch *scratch, u32 type);
void __attribute__((noreturn)) sbi_system_shutdown(struct sbi_scratch *scratch, void __attribute__((noreturn))
u32 type); sbi_system_shutdown(struct sbi_scratch *scratch, u32 type);
#endif #endif

48
include/sbi/sbi_tlb.h Normal file
View File

@@ -0,0 +1,48 @@
/*
* SPDX-License-Identifier: BSD-2-Clause
*
* Copyright (c) 2019 Western Digital Corporation or its affiliates.
*
* Authors:
* Atish Patra <atish.patra@wdc.com>
* Anup Patel <anup.patel@wdc.com>
*/
#ifndef __SBI_TLB_H__
#define __SBI_TLB_H__
#include <sbi/sbi_types.h>
/* clang-format off */
#define SBI_TLB_FLUSH_ALL ((unsigned long)-1)
#define SBI_TLB_FLUSH_MAX_SIZE (1UL << 30)
/* clang-format on */
#define SBI_TLB_FIFO_NUM_ENTRIES 4
enum sbi_tlb_info_types {
SBI_TLB_FLUSH_VMA,
SBI_TLB_FLUSH_VMA_ASID,
SBI_TLB_FLUSH_VMA_VMID
};
struct sbi_scratch;
struct sbi_tlb_info {
unsigned long start;
unsigned long size;
unsigned long asid;
unsigned long type;
};
#define SBI_TLB_INFO_SIZE sizeof(struct sbi_tlb_info)
int sbi_tlb_fifo_update(struct sbi_scratch *scratch, u32 event, void *data);
void sbi_tlb_fifo_process(struct sbi_scratch *scratch, u32 event);
int sbi_tlb_fifo_init(struct sbi_scratch *scratch, bool cold_boot);
#endif

View File

@@ -10,6 +10,8 @@
#ifndef __SBI_TRAP_H__ #ifndef __SBI_TRAP_H__
#define __SBI_TRAP_H__ #define __SBI_TRAP_H__
/* clang-format off */
/** Index of zero member in sbi_trap_regs */ /** Index of zero member in sbi_trap_regs */
#define SBI_TRAP_REGS_zero 0 #define SBI_TRAP_REGS_zero 0
/** Index of ra member in sbi_trap_regs */ /** Index of ra member in sbi_trap_regs */
@@ -81,11 +83,12 @@
/** Last member index in sbi_trap_regs */ /** Last member index in sbi_trap_regs */
#define SBI_TRAP_REGS_last 34 #define SBI_TRAP_REGS_last 34
/* clang-format on */
/** Get offset of member with name 'x' in sbi_trap_regs */ /** Get offset of member with name 'x' in sbi_trap_regs */
#define SBI_TRAP_REGS_OFFSET(x) \ #define SBI_TRAP_REGS_OFFSET(x) ((SBI_TRAP_REGS_##x) * __SIZEOF_POINTER__)
((SBI_TRAP_REGS_##x) * __SIZEOF_POINTER__)
/** Size (in bytes) of sbi_trap_regs */ /** Size (in bytes) of sbi_trap_regs */
#define SBI_TRAP_REGS_SIZE SBI_TRAP_REGS_OFFSET(last) #define SBI_TRAP_REGS_SIZE SBI_TRAP_REGS_OFFSET(last)
#ifndef __ASSEMBLY__ #ifndef __ASSEMBLY__
@@ -165,12 +168,10 @@ struct sbi_trap_regs {
struct sbi_scratch; struct sbi_scratch;
int sbi_trap_redirect(struct sbi_trap_regs *regs, int sbi_trap_redirect(struct sbi_trap_regs *regs, struct sbi_scratch *scratch,
struct sbi_scratch *scratch,
ulong epc, ulong cause, ulong tval); ulong epc, ulong cause, ulong tval);
void sbi_trap_handler(struct sbi_trap_regs *regs, void sbi_trap_handler(struct sbi_trap_regs *regs, struct sbi_scratch *scratch);
struct sbi_scratch *scratch);
#endif #endif

View File

@@ -10,6 +10,8 @@
#ifndef __SBI_TYPES_H__ #ifndef __SBI_TYPES_H__
#define __SBI_TYPES_H__ #define __SBI_TYPES_H__
/* clang-format off */
typedef char s8; typedef char s8;
typedef unsigned char u8; typedef unsigned char u8;
typedef unsigned char uint8_t; typedef unsigned char uint8_t;
@@ -58,4 +60,6 @@ typedef unsigned long physical_size_t;
#define __packed __attribute__((packed)) #define __packed __attribute__((packed))
#define __noreturn __attribute__((noreturn)) #define __noreturn __attribute__((noreturn))
/* clang-format on */
#endif #endif

View File

@@ -1,119 +0,0 @@
/*
* SPDX-License-Identifier: BSD-2-Clause
*
* Copyright (c) 2019 Western Digital Corporation or its affiliates.
*
* Authors:
* Anup Patel <anup.patel@wdc.com>
*/
#ifndef __SBI_UNPRIV_H__
#define __SBI_UNPRIV_H__
#include <sbi/riscv_encoding.h>
#include <sbi/sbi_bits.h>
#include <sbi/sbi_types.h>
#define DECLARE_UNPRIVILEGED_LOAD_FUNCTION(type, insn) \
static inline type load_##type(const type *addr, ulong mepc) \
{ \
register ulong __mepc asm ("a2") = mepc; \
register ulong __mstatus asm ("a3"); \
type val; \
asm ("csrrs %0, "STR(CSR_MSTATUS)", %3\n" \
#insn " %1, %2\n" \
"csrw "STR(CSR_MSTATUS)", %0" \
: "+&r" (__mstatus), "=&r" (val) \
: "m" (*addr), "r" (MSTATUS_MPRV), "r" (__mepc)); \
return val; \
}
#define DECLARE_UNPRIVILEGED_STORE_FUNCTION(type, insn) \
static inline void store_##type(type *addr, type val, ulong mepc) \
{ \
register ulong __mepc asm ("a2") = mepc; \
register ulong __mstatus asm ("a3"); \
asm volatile ("csrrs %0, "STR(CSR_MSTATUS)", %3\n" \
#insn " %1, %2\n" \
"csrw "STR(CSR_MSTATUS)", %0" \
: "+&r" (__mstatus) \
: "r" (val), "m" (*addr), "r" (MSTATUS_MPRV), "r" (__mepc)); \
}
DECLARE_UNPRIVILEGED_LOAD_FUNCTION(u8, lbu)
DECLARE_UNPRIVILEGED_LOAD_FUNCTION(u16, lhu)
DECLARE_UNPRIVILEGED_LOAD_FUNCTION(s8, lb)
DECLARE_UNPRIVILEGED_LOAD_FUNCTION(s16, lh)
DECLARE_UNPRIVILEGED_LOAD_FUNCTION(s32, lw)
DECLARE_UNPRIVILEGED_STORE_FUNCTION(u8, sb)
DECLARE_UNPRIVILEGED_STORE_FUNCTION(u16, sh)
DECLARE_UNPRIVILEGED_STORE_FUNCTION(u32, sw)
#if __riscv_xlen == 64
DECLARE_UNPRIVILEGED_LOAD_FUNCTION(u32, lwu)
DECLARE_UNPRIVILEGED_LOAD_FUNCTION(u64, ld)
DECLARE_UNPRIVILEGED_STORE_FUNCTION(u64, sd)
DECLARE_UNPRIVILEGED_LOAD_FUNCTION(ulong, ld)
#else
DECLARE_UNPRIVILEGED_LOAD_FUNCTION(u32, lw)
DECLARE_UNPRIVILEGED_LOAD_FUNCTION(ulong, lw)
static inline u64 load_u64(const u64 *addr, ulong mepc)
{
return load_u32((u32 *)addr, mepc)
+ ((u64)load_u32((u32 *)addr + 1, mepc) << 32);
}
static inline void store_u64(u64 *addr, u64 val, ulong mepc)
{
store_u32((u32 *)addr, val, mepc);
store_u32((u32 *)addr + 1, val >> 32, mepc);
}
#endif
static inline ulong get_insn(ulong mepc, ulong *mstatus)
{
register ulong __mepc asm ("a2") = mepc;
register ulong __mstatus asm ("a3");
ulong val;
#ifndef __riscv_compressed
asm ("csrrs %[mstatus], "STR(CSR_MSTATUS)", %[mprv]\n"
#if __riscv_xlen == 64
STR(LWU) " %[insn], (%[addr])\n"
#else
STR(LW) " %[insn], (%[addr])\n"
#endif
"csrw "STR(CSR_MSTATUS)", %[mstatus]"
: [mstatus] "+&r" (__mstatus), [insn] "=&r" (val)
: [mprv] "r" (MSTATUS_MPRV | MSTATUS_MXR), [addr] "r" (__mepc));
#else
ulong rvc_mask = 3, tmp;
asm ("csrrs %[mstatus], "STR(CSR_MSTATUS)", %[mprv]\n"
"and %[tmp], %[addr], 2\n"
"bnez %[tmp], 1f\n"
#if __riscv_xlen == 64
STR(LWU) " %[insn], (%[addr])\n"
#else
STR(LW) " %[insn], (%[addr])\n"
#endif
"and %[tmp], %[insn], %[rvc_mask]\n"
"beq %[tmp], %[rvc_mask], 2f\n"
"sll %[insn], %[insn], %[xlen_minus_16]\n"
"srl %[insn], %[insn], %[xlen_minus_16]\n"
"j 2f\n"
"1:\n"
"lhu %[insn], (%[addr])\n"
"and %[tmp], %[insn], %[rvc_mask]\n"
"bne %[tmp], %[rvc_mask], 2f\n"
"lhu %[tmp], 2(%[addr])\n"
"sll %[tmp], %[tmp], 16\n"
"add %[insn], %[insn], %[tmp]\n"
"2: csrw "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), [xlen_minus_16] "i" (__riscv_xlen - 16));
#endif
*mstatus = __mstatus;
return val;
}
#endif

View File

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

View File

@@ -14,10 +14,12 @@
void plic_fdt_fixup(void *fdt, const char *compat); void plic_fdt_fixup(void *fdt, const char *compat);
int plic_warm_irqchip_init(u32 target_hart, int plic_warm_irqchip_init(u32 target_hart, int m_cntx_id, int s_cntx_id);
int m_cntx_id, int s_cntx_id);
int plic_cold_irqchip_init(unsigned long base, int plic_cold_irqchip_init(unsigned long base, u32 num_sources, u32 hart_count);
u32 num_sources, u32 hart_count);
void plic_set_thresh(u32 cntxid, u32 val);
void plic_set_ie(u32 cntxid, u32 word_index, u32 val);
#endif #endif

View File

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

View File

@@ -14,10 +14,9 @@
void uart8250_putc(char ch); void uart8250_putc(char ch);
char uart8250_getc(void); int uart8250_getc(void);
int uart8250_init(unsigned long base, int uart8250_init(unsigned long base, u32 in_freq, u32 baudrate, u32 reg_shift,
u32 in_freq, u32 baudrate, u32 reg_width);
u32 reg_shift, u32 reg_width);
#endif #endif

View File

@@ -1,25 +0,0 @@
#
# SPDX-License-Identifier: BSD-2-Clause
#
# Copyright (c) 2019 Western Digital Corporation or its affiliates.
#
# Authors:
# Anup Patel <anup.patel@wdc.com>
#
lib-objs-y += riscv_asm.o
lib-objs-y += riscv_atomic.o
lib-objs-y += riscv_hardfp.o
lib-objs-y += riscv_locks.o
lib-objs-y += sbi_console.o
lib-objs-y += sbi_ecall.o
lib-objs-y += sbi_emulate_csr.o
lib-objs-y += sbi_hart.o
lib-objs-y += sbi_illegal_insn.o
lib-objs-y += sbi_init.o
lib-objs-y += sbi_ipi.o
lib-objs-y += sbi_misaligned_ldst.o
lib-objs-y += sbi_system.o
lib-objs-y += sbi_timer.o
lib-objs-y += sbi_trap.o

View File

@@ -1,225 +0,0 @@
/*
* SPDX-License-Identifier: BSD-2-Clause
*
* Copyright (c) 2019 Western Digital Corporation or its affiliates.
*
* Authors:
* Anup Patel <anup.patel@wdc.com>
*/
#include <sbi/sbi_types.h>
#include <sbi/riscv_asm.h>
#include <sbi/riscv_atomic.h>
#include <sbi/riscv_barrier.h>
#include <sbi/sbi_bits.h>
long atomic_read(atomic_t *atom)
{
long ret = atom->counter;
rmb();
return ret;
}
void atomic_write(atomic_t *atom, long value)
{
atom->counter = value;
wmb();
}
long atomic_add_return(atomic_t *atom, long value)
{
long ret;
__asm__ __volatile__ (
" amoadd.w.aqrl %1, %2, %0"
: "+A" (atom->counter), "=r" (ret)
: "r" (value)
: "memory");
return ret + value;
}
long atomic_sub_return(atomic_t *atom, long value)
{
long ret;
__asm__ __volatile__ (
" amoadd.w.aqrl %1, %2, %0"
: "+A" (atom->counter), "=r" (ret)
: "r" (-value)
: "memory");
return ret - value;
}
#define __xchg(ptr, new, size) \
({ \
__typeof__(ptr) __ptr = (ptr); \
__typeof__(*(ptr)) __new = (new); \
__typeof__(*(ptr)) __ret; \
register unsigned int __rc; \
switch (size) { \
case 4: \
__asm__ __volatile__ ( \
"0: lr.w %0, %2\n" \
" sc.w.rl %1, %z3, %2\n" \
" bnez %1, 0b\n" \
" fence rw, rw\n" \
: "=&r" (__ret), "=&r" (__rc), "+A" (*__ptr) \
: "rJ" (__new) \
: "memory"); \
break; \
case 8: \
__asm__ __volatile__ ( \
"0: lr.d %0, %2\n" \
" sc.d.rl %1, %z3, %2\n" \
" bnez %1, 0b\n" \
" fence rw, rw\n" \
: "=&r" (__ret), "=&r" (__rc), "+A" (*__ptr) \
: "rJ" (__new) \
: "memory"); \
break; \
default: \
break; \
} \
__ret; \
})
#define xchg(ptr, n) \
({ \
__typeof__(*(ptr)) _n_ = (n); \
(__typeof__(*(ptr))) __xchg((ptr), _n_, sizeof(*(ptr))); \
})
#define __cmpxchg(ptr, old, new, size) \
({ \
__typeof__(ptr) __ptr = (ptr); \
__typeof__(*(ptr)) __old = (old); \
__typeof__(*(ptr)) __new = (new); \
__typeof__(*(ptr)) __ret; \
register unsigned int __rc; \
switch (size) { \
case 4: \
__asm__ __volatile__ ( \
"0: lr.w %0, %2\n" \
" bne %0, %z3, 1f\n" \
" sc.w.rl %1, %z4, %2\n" \
" bnez %1, 0b\n" \
" fence rw, rw\n" \
"1:\n" \
: "=&r" (__ret), "=&r" (__rc), "+A" (*__ptr) \
: "rJ" (__old), "rJ" (__new) \
: "memory"); \
break; \
case 8: \
__asm__ __volatile__ ( \
"0: lr.d %0, %2\n" \
" bne %0, %z3, 1f\n" \
" sc.d.rl %1, %z4, %2\n" \
" bnez %1, 0b\n" \
" fence rw, rw\n" \
"1:\n" \
: "=&r" (__ret), "=&r" (__rc), "+A" (*__ptr) \
: "rJ" (__old), "rJ" (__new) \
: "memory"); \
break; \
default: \
break; \
} \
__ret; \
})
#define cmpxchg(ptr, o, n) \
({ \
__typeof__(*(ptr)) _o_ = (o); \
__typeof__(*(ptr)) _n_ = (n); \
(__typeof__(*(ptr))) __cmpxchg((ptr), \
_o_, _n_, sizeof(*(ptr))); \
})
long arch_atomic_cmpxchg(atomic_t *atom, long oldval, long newval)
{
#ifdef __riscv_atomic
return __sync_val_compare_and_swap(&atom->counter, oldval, newval);
#else
return cmpxchg(&atom->counter, oldval, newval);
#endif
}
long arch_atomic_xchg(atomic_t *atom, long newval)
{
/* Atomically set new value and return old value. */
#ifdef __riscv_atomic
/*
* The name of GCC built-in macro __sync_lock_test_and_set()
* is misleading. A more appropriate name for GCC built-in
* macro would be __sync_val_exchange().
*/
return __sync_lock_test_and_set(&atom->counter, newval);
#else
return xchg(&atom->counter, newval);
#endif
}
unsigned int atomic_raw_xchg_uint(volatile unsigned int *ptr,
unsigned int newval)
{
/* Atomically set new value and return old value. */
#ifdef __riscv_atomic
/*
* The name of GCC built-in macro __sync_lock_test_and_set()
* is misleading. A more appropriate name for GCC built-in
* macro would be __sync_val_exchange().
*/
return __sync_lock_test_and_set(ptr, newval);
#else
return xchg(ptr, newval);
#endif
}
#if (BITS_PER_LONG == 64)
#define __AMO(op) "amo" #op ".d"
#elif (BITS_PER_LONG == 32)
#define __AMO(op) "amo" #op ".w"
#else
#error "Unexpected BITS_PER_LONG"
#endif
#define __atomic_op_bit_ord(op, mod, nr, addr, ord) \
({ \
unsigned long __res, __mask; \
__mask = BIT_MASK(nr); \
__asm__ __volatile__ ( \
__AMO(op) #ord " %0, %2, %1" \
: "=r" (__res), "+A" (addr[BIT_WORD(nr)]) \
: "r" (mod(__mask)) \
: "memory"); \
__res; \
})
#define __atomic_op_bit(op, mod, nr, addr) \
__atomic_op_bit_ord(op, mod, nr, addr, .aqrl)
/* Bitmask modifiers */
#define __NOP(x) (x)
#define __NOT(x) (~(x))
inline int atomic_raw_set_bit(int nr, volatile unsigned long *addr)
{
return __atomic_op_bit(or, __NOP, nr, addr);
}
inline int atomic_raw_clear_bit(int nr, volatile unsigned long *addr)
{
return __atomic_op_bit(and, __NOT, nr, addr);
}
inline int atomic_set_bit(int nr, atomic_t *atom)
{
return atomic_raw_set_bit(nr, (unsigned long *)&atom->counter);
}
inline int atomic_clear_bit(int nr, atomic_t *atom)
{
return atomic_raw_clear_bit(nr, (unsigned long *)&atom->counter);
}

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

@@ -0,0 +1,30 @@
#
# SPDX-License-Identifier: BSD-2-Clause
#
# Copyright (c) 2019 Western Digital Corporation or its affiliates.
#
# Authors:
# Anup Patel <anup.patel@wdc.com>
#
libsbi-objs-y += riscv_asm.o
libsbi-objs-y += riscv_atomic.o
libsbi-objs-y += riscv_hardfp.o
libsbi-objs-y += riscv_locks.o
libsbi-objs-y += riscv_unpriv.o
libsbi-objs-y += sbi_console.o
libsbi-objs-y += sbi_ecall.o
libsbi-objs-y += sbi_emulate_csr.o
libsbi-objs-y += sbi_fifo.o
libsbi-objs-y += sbi_hart.o
libsbi-objs-y += sbi_illegal_insn.o
libsbi-objs-y += sbi_init.o
libsbi-objs-y += sbi_ipi.o
libsbi-objs-y += sbi_misaligned_ldst.o
libsbi-objs-y += sbi_scratch.o
libsbi-objs-y += sbi_system.o
libsbi-objs-y += sbi_timer.o
libsbi-objs-y += sbi_tlb.o
libsbi-objs-y += sbi_trap.o
libsbi-objs-y += sbi_string.o

View File

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

222
lib/sbi/riscv_atomic.c Normal file
View File

@@ -0,0 +1,222 @@
/*
* SPDX-License-Identifier: BSD-2-Clause
*
* Copyright (c) 2019 Western Digital Corporation or its affiliates.
*
* Authors:
* Anup Patel <anup.patel@wdc.com>
*/
#include <sbi/sbi_types.h>
#include <sbi/riscv_asm.h>
#include <sbi/riscv_atomic.h>
#include <sbi/riscv_barrier.h>
#include <sbi/sbi_bits.h>
long atomic_read(atomic_t *atom)
{
long ret = atom->counter;
rmb();
return ret;
}
void atomic_write(atomic_t *atom, long value)
{
atom->counter = value;
wmb();
}
long atomic_add_return(atomic_t *atom, long value)
{
long ret;
__asm__ __volatile__(" amoadd.w.aqrl %1, %2, %0"
: "+A"(atom->counter), "=r"(ret)
: "r"(value)
: "memory");
return ret + value;
}
long atomic_sub_return(atomic_t *atom, long value)
{
long ret;
__asm__ __volatile__(" amoadd.w.aqrl %1, %2, %0"
: "+A"(atom->counter), "=r"(ret)
: "r"(-value)
: "memory");
return ret - value;
}
#define __xchg(ptr, new, size) \
({ \
__typeof__(ptr) __ptr = (ptr); \
__typeof__(*(ptr)) __new = (new); \
__typeof__(*(ptr)) __ret; \
register unsigned int __rc; \
switch (size) { \
case 4: \
__asm__ __volatile__("0: lr.w %0, %2\n" \
" sc.w.rl %1, %z3, %2\n" \
" bnez %1, 0b\n" \
" fence rw, rw\n" \
: "=&r"(__ret), "=&r"(__rc), \
"+A"(*__ptr) \
: "rJ"(__new) \
: "memory"); \
break; \
case 8: \
__asm__ __volatile__("0: lr.d %0, %2\n" \
" sc.d.rl %1, %z3, %2\n" \
" bnez %1, 0b\n" \
" fence rw, rw\n" \
: "=&r"(__ret), "=&r"(__rc), \
"+A"(*__ptr) \
: "rJ"(__new) \
: "memory"); \
break; \
default: \
break; \
} \
__ret; \
})
#define xchg(ptr, n) \
({ \
__typeof__(*(ptr)) _n_ = (n); \
(__typeof__(*(ptr))) __xchg((ptr), _n_, sizeof(*(ptr))); \
})
#define __cmpxchg(ptr, old, new, size) \
({ \
__typeof__(ptr) __ptr = (ptr); \
__typeof__(*(ptr)) __old = (old); \
__typeof__(*(ptr)) __new = (new); \
__typeof__(*(ptr)) __ret; \
register unsigned int __rc; \
switch (size) { \
case 4: \
__asm__ __volatile__("0: lr.w %0, %2\n" \
" bne %0, %z3, 1f\n" \
" sc.w.rl %1, %z4, %2\n" \
" bnez %1, 0b\n" \
" fence rw, rw\n" \
"1:\n" \
: "=&r"(__ret), "=&r"(__rc), \
"+A"(*__ptr) \
: "rJ"(__old), "rJ"(__new) \
: "memory"); \
break; \
case 8: \
__asm__ __volatile__("0: lr.d %0, %2\n" \
" bne %0, %z3, 1f\n" \
" sc.d.rl %1, %z4, %2\n" \
" bnez %1, 0b\n" \
" fence rw, rw\n" \
"1:\n" \
: "=&r"(__ret), "=&r"(__rc), \
"+A"(*__ptr) \
: "rJ"(__old), "rJ"(__new) \
: "memory"); \
break; \
default: \
break; \
} \
__ret; \
})
#define cmpxchg(ptr, o, n) \
({ \
__typeof__(*(ptr)) _o_ = (o); \
__typeof__(*(ptr)) _n_ = (n); \
(__typeof__(*(ptr))) \
__cmpxchg((ptr), _o_, _n_, sizeof(*(ptr))); \
})
long arch_atomic_cmpxchg(atomic_t *atom, long oldval, long newval)
{
#ifdef __riscv_atomic
return __sync_val_compare_and_swap(&atom->counter, oldval, newval);
#else
return cmpxchg(&atom->counter, oldval, newval);
#endif
}
long arch_atomic_xchg(atomic_t *atom, long newval)
{
/* Atomically set new value and return old value. */
#ifdef __riscv_atomic
/*
* The name of GCC built-in macro __sync_lock_test_and_set()
* is misleading. A more appropriate name for GCC built-in
* macro would be __sync_val_exchange().
*/
return __sync_lock_test_and_set(&atom->counter, newval);
#else
return xchg(&atom->counter, newval);
#endif
}
unsigned int atomic_raw_xchg_uint(volatile unsigned int *ptr,
unsigned int newval)
{
/* Atomically set new value and return old value. */
#ifdef __riscv_atomic
/*
* The name of GCC built-in macro __sync_lock_test_and_set()
* is misleading. A more appropriate name for GCC built-in
* macro would be __sync_val_exchange().
*/
return __sync_lock_test_and_set(ptr, newval);
#else
return xchg(ptr, newval);
#endif
}
#if (BITS_PER_LONG == 64)
#define __AMO(op) "amo" #op ".d"
#elif (BITS_PER_LONG == 32)
#define __AMO(op) "amo" #op ".w"
#else
#error "Unexpected BITS_PER_LONG"
#endif
#define __atomic_op_bit_ord(op, mod, nr, addr, ord) \
({ \
unsigned long __res, __mask; \
__mask = BIT_MASK(nr); \
__asm__ __volatile__(__AMO(op) #ord " %0, %2, %1" \
: "=r"(__res), "+A"(addr[BIT_WORD(nr)]) \
: "r"(mod(__mask)) \
: "memory"); \
__res; \
})
#define __atomic_op_bit(op, mod, nr, addr) \
__atomic_op_bit_ord(op, mod, nr, addr, .aqrl)
/* Bitmask modifiers */
#define __NOP(x) (x)
#define __NOT(x) (~(x))
inline int atomic_raw_set_bit(int nr, volatile unsigned long *addr)
{
return __atomic_op_bit(or, __NOP, nr, addr);
}
inline int atomic_raw_clear_bit(int nr, volatile unsigned long *addr)
{
return __atomic_op_bit(and, __NOT, nr, addr);
}
inline int atomic_set_bit(int nr, atomic_t *atom)
{
return atomic_raw_set_bit(nr, (unsigned long *)&atom->counter);
}
inline int atomic_clear_bit(int nr, atomic_t *atom)
{
return atomic_raw_clear_bit(nr, (unsigned long *)&atom->counter);
}

View File

@@ -19,11 +19,10 @@ int spin_trylock(spinlock_t *lock)
{ {
int tmp = 1, busy; int tmp = 1, busy;
__asm__ __volatile__ ( __asm__ __volatile__(
" amoswap.w %0, %2, %1\n" " amoswap.w %0, %2, %1\n" RISCV_ACQUIRE_BARRIER
RISCV_ACQUIRE_BARRIER : "=r"(busy), "+A"(lock->lock)
: "=r" (busy), "+A" (lock->lock) : "r"(tmp)
: "r" (tmp)
: "memory"); : "memory");
return !busy; return !busy;

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

@@ -0,0 +1,145 @@
/*
* SPDX-License-Identifier: BSD-2-Clause
*
* Copyright (c) 2019 Western Digital Corporation or its affiliates.
*
* Authors:
* Anup Patel <anup.patel@wdc.com>
*/
#include <sbi/riscv_encoding.h>
#include <sbi/riscv_unpriv.h>
#include <sbi/sbi_bits.h>
#include <sbi/sbi_hart.h>
#include <sbi/sbi_scratch.h>
#define DEFINE_UNPRIVILEGED_LOAD_FUNCTION(type, insn, insnlen) \
type load_##type(const type *addr, \
struct sbi_scratch *scratch, \
struct unpriv_trap *trap) \
{ \
register ulong __mstatus asm("a2"); \
type val = 0; \
trap->ilen = insnlen; \
trap->cause = 0; \
trap->tval = 0; \
sbi_hart_set_trap_info(scratch, trap); \
asm volatile( \
"csrrs %0, " STR(CSR_MSTATUS) ", %3\n" \
#insn " %1, %2\n" \
"csrw " STR(CSR_MSTATUS) ", %0" \
: "+&r"(__mstatus), "=&r"(val) \
: "m"(*addr), "r"(MSTATUS_MPRV)); \
sbi_hart_set_trap_info(scratch, NULL); \
return val; \
}
#define DEFINE_UNPRIVILEGED_STORE_FUNCTION(type, insn, insnlen) \
void store_##type(type *addr, type val, \
struct sbi_scratch *scratch, \
struct unpriv_trap *trap) \
{ \
register ulong __mstatus asm("a3"); \
trap->ilen = insnlen; \
trap->cause = 0; \
trap->tval = 0; \
sbi_hart_set_trap_info(scratch, trap); \
asm volatile( \
"csrrs %0, " STR(CSR_MSTATUS) ", %3\n" \
#insn " %1, %2\n" \
"csrw " STR(CSR_MSTATUS) ", %0" \
: "+&r"(__mstatus) \
: "r"(val), "m"(*addr), "r"(MSTATUS_MPRV)); \
sbi_hart_set_trap_info(scratch, NULL); \
}
DEFINE_UNPRIVILEGED_LOAD_FUNCTION(u8, lbu, 4)
DEFINE_UNPRIVILEGED_LOAD_FUNCTION(u16, lhu, 4)
DEFINE_UNPRIVILEGED_LOAD_FUNCTION(s8, lb, 4)
DEFINE_UNPRIVILEGED_LOAD_FUNCTION(s16, lh, 4)
DEFINE_UNPRIVILEGED_LOAD_FUNCTION(s32, lw, 2)
DEFINE_UNPRIVILEGED_STORE_FUNCTION(u8, sb, 4)
DEFINE_UNPRIVILEGED_STORE_FUNCTION(u16, sh, 4)
DEFINE_UNPRIVILEGED_STORE_FUNCTION(u32, sw, 2)
#if __riscv_xlen == 64
DEFINE_UNPRIVILEGED_LOAD_FUNCTION(u32, lwu, 4)
DEFINE_UNPRIVILEGED_LOAD_FUNCTION(u64, ld, 2)
DEFINE_UNPRIVILEGED_STORE_FUNCTION(u64, sd, 2)
DEFINE_UNPRIVILEGED_LOAD_FUNCTION(ulong, ld, 2)
#else
DEFINE_UNPRIVILEGED_LOAD_FUNCTION(u32, lw, 2)
DEFINE_UNPRIVILEGED_LOAD_FUNCTION(ulong, lw, 2)
u64 load_u64(const u64 *addr,
struct sbi_scratch *scratch, struct unpriv_trap *trap)
{
u64 ret = load_u32((u32 *)addr, scratch, trap);
if (trap->cause)
return 0;
ret |= ((u64)load_u32((u32 *)addr + 1, scratch, trap) << 32);
if (trap->cause)
return 0;
return ret;
}
void store_u64(u64 *addr, u64 val,
struct sbi_scratch *scratch, struct unpriv_trap *trap)
{
store_u32((u32 *)addr, val, scratch, trap);
if (trap->cause)
return;
store_u32((u32 *)addr + 1, val >> 32, scratch, trap);
if (trap->cause)
return;
}
#endif
ulong get_insn(ulong mepc, ulong *mstatus)
{
register ulong __mepc asm("a2") = mepc;
register ulong __mstatus asm("a3");
ulong val;
#ifndef __riscv_compressed
asm("csrrs %[mstatus], " STR(CSR_MSTATUS) ", %[mprv]\n"
#if __riscv_xlen == 64
STR(LWU) " %[insn], (%[addr])\n"
#else
STR(LW) " %[insn], (%[addr])\n"
#endif
"csrw " STR(CSR_MSTATUS) ", %[mstatus]"
: [mstatus] "+&r"(__mstatus), [insn] "=&r"(val)
: [mprv] "r"(MSTATUS_MPRV | MSTATUS_MXR), [addr] "r"(__mepc));
#else
ulong rvc_mask = 3, tmp;
asm("csrrs %[mstatus], " STR(CSR_MSTATUS) ", %[mprv]\n"
"and %[tmp], %[addr], 2\n"
"bnez %[tmp], 1f\n"
#if __riscv_xlen == 64
STR(LWU) " %[insn], (%[addr])\n"
#else
STR(LW) " %[insn], (%[addr])\n"
#endif
"and %[tmp], %[insn], %[rvc_mask]\n"
"beq %[tmp], %[rvc_mask], 2f\n"
"sll %[insn], %[insn], %[xlen_minus_16]\n"
"srl %[insn], %[insn], %[xlen_minus_16]\n"
"j 2f\n"
"1:\n"
"lhu %[insn], (%[addr])\n"
"and %[tmp], %[insn], %[rvc_mask]\n"
"bne %[tmp], %[rvc_mask], 2f\n"
"lhu %[tmp], 2(%[addr])\n"
"sll %[tmp], %[tmp], 16\n"
"add %[insn], %[insn], %[tmp]\n"
"2: csrw " 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), [xlen_minus_16] "i"(__riscv_xlen - 16));
#endif
if (mstatus)
*mstatus = __mstatus;
return val;
}

View File

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

View File

@@ -14,10 +14,11 @@
#include <sbi/sbi_ipi.h> #include <sbi/sbi_ipi.h>
#include <sbi/sbi_system.h> #include <sbi/sbi_system.h>
#include <sbi/sbi_timer.h> #include <sbi/sbi_timer.h>
#include <sbi/sbi_tlb.h>
#include <sbi/sbi_trap.h> #include <sbi/sbi_trap.h>
#define SBI_ECALL_VERSION_MAJOR 0 #define SBI_ECALL_VERSION_MAJOR 0
#define SBI_ECALL_VERSION_MINOR 1 #define SBI_ECALL_VERSION_MINOR 1
u16 sbi_ecall_version_major(void) u16 sbi_ecall_version_major(void)
{ {
@@ -29,17 +30,18 @@ u16 sbi_ecall_version_minor(void)
return SBI_ECALL_VERSION_MINOR; return SBI_ECALL_VERSION_MINOR;
} }
int sbi_ecall_handler(u32 hartid, ulong mcause, int sbi_ecall_handler(u32 hartid, ulong mcause, struct sbi_trap_regs *regs,
struct sbi_trap_regs *regs,
struct sbi_scratch *scratch) struct sbi_scratch *scratch)
{ {
int ret = SBI_ENOTSUPP; int ret = SBI_ENOTSUPP;
struct unpriv_trap uptrap;
struct sbi_tlb_info tlb_info;
switch (regs->a7) { switch (regs->a7) {
case SBI_ECALL_SET_TIMER: case SBI_ECALL_SET_TIMER:
#if __riscv_xlen == 32 #if __riscv_xlen == 32
sbi_timer_event_start(scratch, sbi_timer_event_start(scratch,
(((u64)regs->a1 << 32) | (u64)regs->a0)); (((u64)regs->a1 << 32) | (u64)regs->a0));
#else #else
sbi_timer_event_start(scratch, (u64)regs->a0); sbi_timer_event_start(scratch, (u64)regs->a0);
#endif #endif
@@ -51,35 +53,54 @@ int sbi_ecall_handler(u32 hartid, ulong mcause,
break; break;
case SBI_ECALL_CONSOLE_GETCHAR: case SBI_ECALL_CONSOLE_GETCHAR:
regs->a0 = sbi_getc(); regs->a0 = sbi_getc();
ret = 0; ret = 0;
break; break;
case SBI_ECALL_CLEAR_IPI: case SBI_ECALL_CLEAR_IPI:
sbi_ipi_clear_smode(scratch); sbi_ipi_clear_smode(scratch);
ret = 0; ret = 0;
break; break;
case SBI_ECALL_SEND_IPI: case SBI_ECALL_SEND_IPI:
ret = sbi_ipi_send_many(scratch, (ulong *)regs->a0, ret = sbi_ipi_send_many(scratch, &uptrap, (ulong *)regs->a0,
SBI_IPI_EVENT_SOFT); SBI_IPI_EVENT_SOFT, NULL);
break; break;
case SBI_ECALL_REMOTE_FENCE_I: case SBI_ECALL_REMOTE_FENCE_I:
ret = sbi_ipi_send_many(scratch, (ulong *)regs->a0, ret = sbi_ipi_send_many(scratch, &uptrap, (ulong *)regs->a0,
SBI_IPI_EVENT_FENCE_I); SBI_IPI_EVENT_FENCE_I, NULL);
break; break;
case SBI_ECALL_REMOTE_SFENCE_VMA: case SBI_ECALL_REMOTE_SFENCE_VMA:
tlb_info.start = (unsigned long)regs->a1;
tlb_info.size = (unsigned long)regs->a2;
tlb_info.type = SBI_TLB_FLUSH_VMA;
ret = sbi_ipi_send_many(scratch, &uptrap, (ulong *)regs->a0,
SBI_IPI_EVENT_SFENCE_VMA, &tlb_info);
break;
case SBI_ECALL_REMOTE_SFENCE_VMA_ASID: case SBI_ECALL_REMOTE_SFENCE_VMA_ASID:
ret = sbi_ipi_send_many(scratch, (ulong *)regs->a0, tlb_info.start = (unsigned long)regs->a1;
SBI_IPI_EVENT_SFENCE_VMA); tlb_info.size = (unsigned long)regs->a2;
tlb_info.asid = (unsigned long)regs->a3;
tlb_info.type = SBI_TLB_FLUSH_VMA_ASID;
ret = sbi_ipi_send_many(scratch, &uptrap, (ulong *)regs->a0,
SBI_IPI_EVENT_SFENCE_VMA_ASID,
&tlb_info);
break; break;
case SBI_ECALL_SHUTDOWN: case SBI_ECALL_SHUTDOWN:
sbi_system_shutdown(scratch, 0); sbi_system_shutdown(scratch, 0);
ret = 0; ret = 0;
break; break;
default: default:
regs->a0 = SBI_ENOTSUPP;
ret = 0;
break; break;
}; };
if (!ret) { if (!ret) {
regs->mepc += 4; regs->mepc += 4;
} else if (ret == SBI_ETRAP) {
ret = 0;
sbi_trap_redirect(regs, scratch, regs->mepc,
uptrap.cause, uptrap.tval);
} }
return ret; return ret;

View File

@@ -15,10 +15,8 @@
#include <sbi/sbi_error.h> #include <sbi/sbi_error.h>
#include <sbi/sbi_timer.h> #include <sbi/sbi_timer.h>
int sbi_emulate_csr_read(int csr_num, int sbi_emulate_csr_read(int csr_num, u32 hartid, ulong mstatus,
u32 hartid, ulong mstatus, struct sbi_scratch *scratch, ulong *csr_val)
struct sbi_scratch *scratch,
ulong *csr_val)
{ {
ulong cen = -1UL; ulong cen = -1UL;
@@ -85,18 +83,16 @@ int sbi_emulate_csr_read(int csr_num,
*csr_val = csr_read(CSR_MHPMEVENT4); *csr_val = csr_read(CSR_MHPMEVENT4);
break; break;
default: default:
sbi_printf("%s: hartid%d: invalid csr_num=0x%x\n", sbi_printf("%s: hartid%d: invalid csr_num=0x%x\n", __func__,
__func__, hartid, csr_num); hartid, csr_num);
return SBI_ENOTSUPP; return SBI_ENOTSUPP;
}; };
return 0; return 0;
} }
int sbi_emulate_csr_write(int csr_num, int sbi_emulate_csr_write(int csr_num, u32 hartid, ulong mstatus,
u32 hartid, ulong mstatus, struct sbi_scratch *scratch, ulong csr_val)
struct sbi_scratch *scratch,
ulong csr_val)
{ {
switch (csr_num) { switch (csr_num) {
case CSR_CYCLE: case CSR_CYCLE:
@@ -132,8 +128,8 @@ int sbi_emulate_csr_write(int csr_num,
csr_write(CSR_MHPMEVENT4, csr_val); csr_write(CSR_MHPMEVENT4, csr_val);
break; break;
default: default:
sbi_printf("%s: hartid%d: invalid csr_num=0x%x\n", sbi_printf("%s: hartid%d: invalid csr_num=0x%x\n", __func__,
__func__, hartid, csr_num); hartid, csr_num);
return SBI_ENOTSUPP; return SBI_ENOTSUPP;
}; };

184
lib/sbi/sbi_fifo.c Normal file
View File

@@ -0,0 +1,184 @@
/*
* SPDX-License-Identifier: BSD-2-Clause
*
* Copyright (c) 2019 Western Digital Corporation or its affiliates.
*
* Authors:
* Atish Patra<atish.patra@wdc.com>
*
*/
#include <sbi/riscv_locks.h>
#include <sbi/sbi_error.h>
#include <sbi/sbi_fifo.h>
#include <sbi/sbi_string.h>
void sbi_fifo_init(struct sbi_fifo *fifo, void *queue_mem, u16 entries,
u16 entry_size)
{
fifo->queue = queue_mem;
fifo->num_entries = entries;
fifo->entry_size = entry_size;
SPIN_LOCK_INIT(&fifo->qlock);
fifo->avail = fifo->tail = 0;
sbi_memset(fifo->queue, 0, entries * entry_size);
}
/* Note: must be called with fifo->qlock held */
static inline bool __sbi_fifo_is_full(struct sbi_fifo *fifo)
{
return (fifo->avail == fifo->num_entries) ? TRUE : FALSE;
}
u16 sbi_fifo_avail(struct sbi_fifo *fifo)
{
u16 ret;
if (!fifo)
return 0;
spin_lock(&fifo->qlock);
ret = fifo->avail;
spin_unlock(&fifo->qlock);
return ret;
}
bool sbi_fifo_is_full(struct sbi_fifo *fifo)
{
bool ret;
spin_lock(&fifo->qlock);
ret = __sbi_fifo_is_full(fifo);
spin_unlock(&fifo->qlock);
return ret;
}
/* Note: must be called with fifo->qlock held */
static inline bool __sbi_fifo_is_empty(struct sbi_fifo *fifo)
{
return (fifo->avail == 0) ? TRUE : FALSE;
}
bool sbi_fifo_is_empty(struct sbi_fifo *fifo)
{
bool ret;
spin_lock(&fifo->qlock);
ret = __sbi_fifo_is_empty(fifo);
spin_unlock(&fifo->qlock);
return ret;
}
/* Note: must be called with fifo->qlock held */
static inline void __sbi_fifo_reset(struct sbi_fifo *fifo)
{
fifo->avail = 0;
fifo->tail = 0;
sbi_memset(fifo->queue, 0, fifo->num_entries * fifo->entry_size);
}
bool sbi_fifo_reset(struct sbi_fifo *fifo)
{
if (!fifo)
return FALSE;
spin_lock(&fifo->qlock);
__sbi_fifo_reset(fifo);
spin_unlock(&fifo->qlock);
return TRUE;
}
/**
* Provide a helper function to do inplace update to the fifo.
* Note: The callback function is called with lock being held.
*
* **Do not** invoke any other fifo function from callback. Otherwise, it will
* lead to deadlock.
*/
int sbi_fifo_inplace_update(struct sbi_fifo *fifo, void *in,
int (*fptr)(void *in, void *data))
{
int i, index = 0;
int ret = SBI_FIFO_UNCHANGED;
void *entry;
if (!fifo || !in)
return ret;
spin_lock(&fifo->qlock);
if (__sbi_fifo_is_empty(fifo)) {
spin_unlock(&fifo->qlock);
return ret;
}
for (i = 0; i < fifo->avail; i++) {
index = fifo->tail + i;
if (index >= fifo->num_entries)
index = index - fifo->num_entries;
entry = (void *)fifo->queue + (u32)index * fifo->entry_size;
ret = fptr(in, entry);
if (ret == SBI_FIFO_SKIP || ret == SBI_FIFO_UPDATED) {
break;
} else if (ret == SBI_FIFO_RESET) {
__sbi_fifo_reset(fifo);
break;
}
}
spin_unlock(&fifo->qlock);
return ret;
}
int sbi_fifo_enqueue(struct sbi_fifo *fifo, void *data)
{
u32 head;
if (!fifo || !data)
return SBI_EINVAL;
spin_lock(&fifo->qlock);
if (__sbi_fifo_is_full(fifo)) {
spin_unlock(&fifo->qlock);
return SBI_ENOSPC;
}
head = (u32)fifo->tail + fifo->avail;
if (head >= fifo->num_entries)
head = head - fifo->num_entries;
sbi_memcpy(fifo->queue + head * fifo->entry_size, data, fifo->entry_size);
fifo->avail++;
spin_unlock(&fifo->qlock);
return 0;
}
int sbi_fifo_dequeue(struct sbi_fifo *fifo, void *data)
{
if (!fifo || !data)
return SBI_EINVAL;
spin_lock(&fifo->qlock);
if (__sbi_fifo_is_empty(fifo)) {
spin_unlock(&fifo->qlock);
return SBI_ENOENT;
}
sbi_memcpy(data, fifo->queue + (u32)fifo->tail * fifo->entry_size,
fifo->entry_size);
fifo->avail--;
fifo->tail++;
if (fifo->tail >= fifo->num_entries)
fifo->tail = 0;
spin_unlock(&fifo->qlock);
return 0;
}

View File

@@ -28,15 +28,14 @@ unsigned int sbi_current_hartid()
static void mstatus_init(struct sbi_scratch *scratch, u32 hartid) static void mstatus_init(struct sbi_scratch *scratch, u32 hartid)
{ {
struct sbi_platform *plat = sbi_platform_ptr(scratch); const struct sbi_platform *plat = sbi_platform_ptr(scratch);
/* Enable FPU */ /* Enable FPU */
if (misa_extension('D') || misa_extension('F')) if (misa_extension('D') || misa_extension('F'))
csr_write(CSR_MSTATUS, MSTATUS_FS); csr_write(CSR_MSTATUS, MSTATUS_FS);
/* Enable user/supervisor use of perf counters */ /* Enable user/supervisor use of perf counters */
if (misa_extension('S') && if (misa_extension('S') && sbi_platform_has_scounteren(plat))
sbi_platform_has_scounteren(plat))
csr_write(CSR_SCOUNTEREN, -1); csr_write(CSR_SCOUNTEREN, -1);
if (sbi_platform_has_mcounteren(plat)) if (sbi_platform_has_mcounteren(plat))
csr_write(CSR_MCOUNTEREN, -1); csr_write(CSR_MCOUNTEREN, -1);
@@ -79,7 +78,7 @@ static int fp_init(u32 hartid)
static int delegate_traps(struct sbi_scratch *scratch, u32 hartid) static int delegate_traps(struct sbi_scratch *scratch, u32 hartid)
{ {
struct sbi_platform *plat = sbi_platform_ptr(scratch); const struct sbi_platform *plat = sbi_platform_ptr(scratch);
unsigned long interrupts, exceptions; unsigned long interrupts, exceptions;
if (!misa_extension('S')) if (!misa_extension('S'))
@@ -88,8 +87,7 @@ static int delegate_traps(struct sbi_scratch *scratch, u32 hartid)
/* Send M-mode interrupts and most exceptions to S-mode */ /* Send M-mode interrupts and most exceptions to S-mode */
interrupts = MIP_SSIP | MIP_STIP | MIP_SEIP; interrupts = MIP_SSIP | MIP_STIP | MIP_SEIP;
exceptions = (1U << CAUSE_MISALIGNED_FETCH) | exceptions = (1U << CAUSE_MISALIGNED_FETCH) | (1U << CAUSE_BREAKPOINT) |
(1U << CAUSE_BREAKPOINT) |
(1U << CAUSE_USER_ECALL); (1U << CAUSE_USER_ECALL);
if (sbi_platform_has_mfaults_delegation(plat)) if (sbi_platform_has_mfaults_delegation(plat))
exceptions |= (1U << CAUSE_FETCH_PAGE_FAULT) | exceptions |= (1U << CAUSE_FETCH_PAGE_FAULT) |
@@ -122,7 +120,7 @@ unsigned long log2roundup(unsigned long x)
void sbi_hart_pmp_dump(struct sbi_scratch *scratch) void sbi_hart_pmp_dump(struct sbi_scratch *scratch)
{ {
struct sbi_platform *plat = sbi_platform_ptr(scratch); const struct sbi_platform *plat = sbi_platform_ptr(scratch);
unsigned long prot, addr, size, l2l; unsigned long prot, addr, size, l2l;
unsigned int i; unsigned int i;
@@ -160,13 +158,13 @@ static int pmp_init(struct sbi_scratch *scratch, u32 hartid)
u32 i, count; u32 i, count;
unsigned long fw_start, fw_size_log2; unsigned long fw_start, fw_size_log2;
ulong prot, addr, log2size; ulong prot, addr, log2size;
struct sbi_platform *plat = sbi_platform_ptr(scratch); const struct sbi_platform *plat = sbi_platform_ptr(scratch);
if (!sbi_platform_has_pmp(plat)) if (!sbi_platform_has_pmp(plat))
return 0; return 0;
fw_size_log2 = log2roundup(scratch->fw_size); fw_size_log2 = log2roundup(scratch->fw_size);
fw_start = scratch->fw_start & ~((1UL << fw_size_log2) - 1UL); fw_start = scratch->fw_start & ~((1UL << fw_size_log2) - 1UL);
pmp_set(0, 0, fw_start, fw_size_log2); pmp_set(0, 0, fw_start, fw_size_log2);
@@ -175,8 +173,8 @@ static int pmp_init(struct sbi_scratch *scratch, u32 hartid)
count = (PMP_COUNT - 1); count = (PMP_COUNT - 1);
for (i = 0; i < count; i++) { for (i = 0; i < count; i++) {
if (sbi_platform_pmp_region_info(plat, hartid, i, if (sbi_platform_pmp_region_info(plat, hartid, i, &prot, &addr,
&prot, &addr, &log2size)) &log2size))
continue; continue;
pmp_set(i + 1, prot, addr, log2size); pmp_set(i + 1, prot, addr, log2size);
} }
@@ -184,10 +182,19 @@ static int pmp_init(struct sbi_scratch *scratch, u32 hartid)
return 0; return 0;
} }
int sbi_hart_init(struct sbi_scratch *scratch, u32 hartid) static unsigned long trap_info_offset;
int sbi_hart_init(struct sbi_scratch *scratch, u32 hartid, bool cold_boot)
{ {
int rc; int rc;
if (cold_boot) {
trap_info_offset = sbi_scratch_alloc_offset(__SIZEOF_POINTER__,
"HART_TRAP_INFO");
if (!trap_info_offset)
return SBI_ENOMEM;
}
mstatus_init(scratch, hartid); mstatus_init(scratch, hartid);
rc = fp_init(hartid); rc = fp_init(hartid);
@@ -201,6 +208,29 @@ int sbi_hart_init(struct sbi_scratch *scratch, u32 hartid)
return pmp_init(scratch, hartid); return pmp_init(scratch, hartid);
} }
void *sbi_hart_get_trap_info(struct sbi_scratch *scratch)
{
unsigned long *trap_info;
if (!trap_info_offset)
return NULL;
trap_info = sbi_scratch_offset_ptr(scratch, trap_info_offset);
return (void *)(*trap_info);
}
void sbi_hart_set_trap_info(struct sbi_scratch *scratch, void *data)
{
unsigned long *trap_info;
if (!trap_info_offset)
return;
trap_info = sbi_scratch_offset_ptr(scratch, trap_info_offset);
*trap_info = (unsigned long)data;
}
void __attribute__((noreturn)) sbi_hart_hang(void) void __attribute__((noreturn)) sbi_hart_hang(void)
{ {
while (1) while (1)
@@ -208,10 +238,9 @@ void __attribute__((noreturn)) sbi_hart_hang(void)
__builtin_unreachable(); __builtin_unreachable();
} }
void __attribute__((noreturn)) sbi_hart_switch_mode(unsigned long arg0, void __attribute__((noreturn))
unsigned long arg1, sbi_hart_switch_mode(unsigned long arg0, unsigned long arg1,
unsigned long next_addr, unsigned long next_addr, unsigned long next_mode)
unsigned long next_mode)
{ {
unsigned long val; unsigned long val;
@@ -248,13 +277,13 @@ void __attribute__((noreturn)) sbi_hart_switch_mode(unsigned long arg0,
csr_write(CSR_UIE, 0); csr_write(CSR_UIE, 0);
} }
register unsigned long a0 asm ("a0") = arg0; register unsigned long a0 asm("a0") = arg0;
register unsigned long a1 asm ("a1") = arg1; register unsigned long a1 asm("a1") = arg1;
__asm__ __volatile__ ("mret" : : "r" (a0), "r" (a1)); __asm__ __volatile__("mret" : : "r"(a0), "r"(a1));
__builtin_unreachable(); __builtin_unreachable();
} }
static spinlock_t avail_hart_mask_lock = SPIN_LOCK_INITIALIZER; static spinlock_t avail_hart_mask_lock = SPIN_LOCK_INITIALIZER;
static volatile unsigned long avail_hart_mask = 0; static volatile unsigned long avail_hart_mask = 0;
void sbi_hart_mark_available(u32 hartid) void sbi_hart_mark_available(u32 hartid)
@@ -290,19 +319,19 @@ struct sbi_scratch *sbi_hart_id_to_scratch(struct sbi_scratch *scratch,
return ((h2s)scratch->hartid_to_scratch)(hartid); return ((h2s)scratch->hartid_to_scratch)(hartid);
} }
#define COLDBOOT_WAIT_BITMAP_SIZE __riscv_xlen #define COLDBOOT_WAIT_BITMAP_SIZE __riscv_xlen
static spinlock_t coldboot_wait_bitmap_lock = SPIN_LOCK_INITIALIZER; static spinlock_t coldboot_wait_bitmap_lock = SPIN_LOCK_INITIALIZER;
static unsigned long coldboot_wait_bitmap = 0; static unsigned long coldboot_wait_bitmap = 0;
void sbi_hart_wait_for_coldboot(struct sbi_scratch *scratch, u32 hartid) void sbi_hart_wait_for_coldboot(struct sbi_scratch *scratch, u32 hartid)
{ {
unsigned long mipval; unsigned long mipval;
struct sbi_platform *plat = sbi_platform_ptr(scratch); const struct sbi_platform *plat = sbi_platform_ptr(scratch);
if ((sbi_platform_hart_count(plat) <= hartid) || if ((sbi_platform_hart_count(plat) <= hartid) ||
(COLDBOOT_WAIT_BITMAP_SIZE <= hartid)) (COLDBOOT_WAIT_BITMAP_SIZE <= hartid))
sbi_hart_hang(); sbi_hart_hang();
/* Set MSIE bit to receive IPI */ /* Set MSIE bit to receive IPI */
csr_set(CSR_MIE, MIP_MSIP); csr_set(CSR_MIE, MIP_MSIP);
@@ -324,10 +353,10 @@ void sbi_hart_wait_for_coldboot(struct sbi_scratch *scratch, u32 hartid)
void sbi_hart_wake_coldboot_harts(struct sbi_scratch *scratch, u32 hartid) void sbi_hart_wake_coldboot_harts(struct sbi_scratch *scratch, u32 hartid)
{ {
struct sbi_platform *plat = sbi_platform_ptr(scratch); const struct sbi_platform *plat = sbi_platform_ptr(scratch);
int max_hart = sbi_platform_hart_count(plat); int max_hart = sbi_platform_hart_count(plat);
for(int i = 0; i < max_hart ; i++) { for (int i = 0; i < max_hart; i++) {
/* send an IPI to every other hart */ /* send an IPI to every other hart */
spin_lock(&coldboot_wait_bitmap_lock); spin_lock(&coldboot_wait_bitmap_lock);
if ((i != hartid) && (coldboot_wait_bitmap & (1UL << i))) if ((i != hartid) && (coldboot_wait_bitmap & (1UL << i)))

View File

@@ -9,55 +9,52 @@
#include <sbi/riscv_asm.h> #include <sbi/riscv_asm.h>
#include <sbi/riscv_encoding.h> #include <sbi/riscv_encoding.h>
#include <sbi/riscv_unpriv.h>
#include <sbi/sbi_bits.h> #include <sbi/sbi_bits.h>
#include <sbi/sbi_emulate_csr.h> #include <sbi/sbi_emulate_csr.h>
#include <sbi/sbi_error.h> #include <sbi/sbi_error.h>
#include <sbi/sbi_illegal_insn.h> #include <sbi/sbi_illegal_insn.h>
#include <sbi/sbi_trap.h> #include <sbi/sbi_trap.h>
#include <sbi/sbi_unpriv.h>
typedef int (*illegal_insn_func)(ulong insn, typedef int (*illegal_insn_func)(ulong insn, u32 hartid, ulong mcause,
u32 hartid, ulong mcause,
struct sbi_trap_regs *regs, struct sbi_trap_regs *regs,
struct sbi_scratch *scratch); struct sbi_scratch *scratch);
static int truly_illegal_insn(ulong insn, static int truly_illegal_insn(ulong insn, u32 hartid, ulong mcause,
u32 hartid, ulong mcause,
struct sbi_trap_regs *regs, struct sbi_trap_regs *regs,
struct sbi_scratch *scratch) struct sbi_scratch *scratch)
{ {
return sbi_trap_redirect(regs, scratch, regs->mepc, mcause, insn); return sbi_trap_redirect(regs, scratch, regs->mepc, mcause, insn);
} }
static int system_opcode_insn(ulong insn, static int system_opcode_insn(ulong insn, u32 hartid, ulong mcause,
u32 hartid, ulong mcause,
struct sbi_trap_regs *regs, struct sbi_trap_regs *regs,
struct sbi_scratch *scratch) struct sbi_scratch *scratch)
{ {
int do_write, rs1_num = (insn >> 15) & 0x1f; int do_write, rs1_num = (insn >> 15) & 0x1f;
ulong rs1_val = GET_RS1(insn, regs); ulong rs1_val = GET_RS1(insn, regs);
int csr_num = (u32)insn >> 20; int csr_num = (u32)insn >> 20;
ulong csr_val, new_csr_val; ulong csr_val, new_csr_val;
if (sbi_emulate_csr_read(csr_num, hartid, regs->mstatus, if (sbi_emulate_csr_read(csr_num, hartid, regs->mstatus, scratch,
scratch, &csr_val)) &csr_val))
return truly_illegal_insn(insn, hartid, mcause, return truly_illegal_insn(insn, hartid, mcause, regs, scratch);
regs, scratch);
do_write = rs1_num; do_write = rs1_num;
switch (GET_RM(insn)) { switch (GET_RM(insn)) {
case 1: case 1:
new_csr_val = rs1_val; new_csr_val = rs1_val;
do_write = 1; do_write = 1;
break; break;
case 2: case 2:
new_csr_val = csr_val | rs1_val; new_csr_val = csr_val | rs1_val;
break; break;
case 3: new_csr_val = csr_val & ~rs1_val; case 3:
new_csr_val = csr_val & ~rs1_val;
break; break;
case 5: case 5:
new_csr_val = rs1_num; new_csr_val = rs1_num;
do_write = 1; do_write = 1;
break; break;
case 6: case 6:
new_csr_val = csr_val | rs1_num; new_csr_val = csr_val | rs1_num;
@@ -66,15 +63,12 @@ static int system_opcode_insn(ulong insn,
new_csr_val = csr_val & ~rs1_num; new_csr_val = csr_val & ~rs1_num;
break; break;
default: default:
return truly_illegal_insn(insn, hartid, mcause, return truly_illegal_insn(insn, hartid, mcause, regs, scratch);
regs, scratch);
}; };
if (do_write && if (do_write && sbi_emulate_csr_write(csr_num, hartid, regs->mstatus,
sbi_emulate_csr_write(csr_num, hartid, regs->mstatus, scratch, new_csr_val))
scratch, new_csr_val)) return truly_illegal_insn(insn, hartid, mcause, regs, scratch);
return truly_illegal_insn(insn, hartid, mcause,
regs, scratch);
SET_RD(insn, regs, csr_val); SET_RD(insn, regs, csr_val);
@@ -122,17 +116,14 @@ int sbi_illegal_insn_handler(u32 hartid, ulong mcause,
struct sbi_trap_regs *regs, struct sbi_trap_regs *regs,
struct sbi_scratch *scratch) struct sbi_scratch *scratch)
{ {
ulong mstatus;
ulong insn = csr_read(mbadaddr); ulong insn = csr_read(mbadaddr);
if (unlikely((insn & 3) != 3)) { if (unlikely((insn & 3) != 3)) {
if (insn == 0) { if (insn == 0)
mstatus = csr_read(CSR_MSTATUS); insn = get_insn(regs->mepc, NULL);
insn = get_insn(regs->mepc, &mstatus);
}
if ((insn & 3) != 3) if ((insn & 3) != 3)
return truly_illegal_insn(insn, hartid, mcause, return truly_illegal_insn(insn, hartid, mcause, regs,
regs, scratch); scratch);
} }
return illegal_insn_table[(insn & 0x7c) >> 2](insn, hartid, mcause, return illegal_insn_table[(insn & 0x7c) >> 2](insn, hartid, mcause,

View File

@@ -18,27 +18,55 @@
#include <sbi/sbi_timer.h> #include <sbi/sbi_timer.h>
#include <sbi/sbi_version.h> #include <sbi/sbi_version.h>
#define BANNER \ #define BANNER \
" ____ _____ ____ _____\n" \ " ____ _____ ____ _____\n" \
" / __ \\ / ____| _ \\_ _|\n" \ " / __ \\ / ____| _ \\_ _|\n" \
" | | | |_ __ ___ _ __ | (___ | |_) || |\n" \ " | | | |_ __ ___ _ __ | (___ | |_) || |\n" \
" | | | | '_ \\ / _ \\ '_ \\ \\___ \\| _ < | |\n" \ " | | | | '_ \\ / _ \\ '_ \\ \\___ \\| _ < | |\n" \
" | |__| | |_) | __/ | | |____) | |_) || |_\n" \ " | |__| | |_) | __/ | | |____) | |_) || |_\n" \
" \\____/| .__/ \\___|_| |_|_____/|____/_____|\n" \ " \\____/| .__/ \\___|_| |_|_____/|____/_____|\n" \
" | |\n" \ " | |\n" \
" |_|\n\n" " |_|\n\n"
static void sbi_boot_prints(struct sbi_scratch *scratch, u32 hartid)
{
char str[64];
const struct sbi_platform *plat = sbi_platform_ptr(scratch);
misa_string(str, sizeof(str));
sbi_printf("\nOpenSBI v%d.%d (%s %s)\n", OPENSBI_VERSION_MAJOR,
OPENSBI_VERSION_MINOR, __DATE__, __TIME__);
sbi_printf(BANNER);
/* Platform details */
sbi_printf("Platform Name : %s\n", sbi_platform_name(plat));
sbi_printf("Platform HART Features : RV%d%s\n", misa_xlen(), str);
sbi_printf("Platform Max HARTs : %d\n",
sbi_platform_hart_count(plat));
sbi_printf("Current Hart : %u\n", hartid);
/* Firmware details */
sbi_printf("Firmware Base : 0x%lx\n", scratch->fw_start);
sbi_printf("Firmware Size : %d KB\n",
(u32)(scratch->fw_size / 1024));
/* Generic details */
sbi_printf("Runtime SBI Version : %d.%d\n",
sbi_ecall_version_major(), sbi_ecall_version_minor());
sbi_printf("\n");
sbi_hart_pmp_dump(scratch);
}
static void __noreturn init_coldboot(struct sbi_scratch *scratch, u32 hartid) static void __noreturn init_coldboot(struct sbi_scratch *scratch, u32 hartid)
{ {
int rc; int rc;
char str[64]; const struct sbi_platform *plat = sbi_platform_ptr(scratch);
struct sbi_platform *plat = sbi_platform_ptr(scratch);
rc = sbi_system_early_init(scratch, TRUE); rc = sbi_system_early_init(scratch, TRUE);
if (rc) if (rc)
sbi_hart_hang(); sbi_hart_hang();
rc = sbi_hart_init(scratch, hartid); rc = sbi_hart_init(scratch, hartid, TRUE);
if (rc) if (rc)
sbi_hart_hang(); sbi_hart_hang();
@@ -62,41 +90,20 @@ static void __noreturn init_coldboot(struct sbi_scratch *scratch, u32 hartid)
if (rc) if (rc)
sbi_hart_hang(); sbi_hart_hang();
misa_string(str, sizeof(str)); if (!(scratch->options & SBI_SCRATCH_NO_BOOT_PRINTS))
sbi_printf("\nOpenSBI v%d.%d (%s %s)\n", sbi_boot_prints(scratch, hartid);
OPENSBI_VERSION_MAJOR, OPENSBI_VERSION_MINOR,
__DATE__, __TIME__);
sbi_printf(BANNER);
/* Platform details */
sbi_printf("Platform Name : %s\n", sbi_platform_name(plat));
sbi_printf("Platform HART Features : RV%d%s\n", misa_xlen(), str);
sbi_printf("Platform Max HARTs : %d\n",
sbi_platform_hart_count(plat));
sbi_printf("Current Hart : %u\n", hartid);
/* Firmware details */
sbi_printf("Firmware Base : 0x%lx\n", scratch->fw_start);
sbi_printf("Firmware Size : %d KB\n",
(u32)(scratch->fw_size / 1024));
/* Generic details */
sbi_printf("Runtime SBI Version : %d.%d\n",
sbi_ecall_version_major(), sbi_ecall_version_minor());
sbi_printf("\n");
sbi_hart_pmp_dump(scratch);
if (!sbi_platform_has_hart_hotplug(plat)) if (!sbi_platform_has_hart_hotplug(plat))
sbi_hart_wake_coldboot_harts(scratch, hartid); sbi_hart_wake_coldboot_harts(scratch, hartid);
sbi_hart_mark_available(hartid); sbi_hart_mark_available(hartid);
sbi_hart_switch_mode(hartid, scratch->next_arg1, sbi_hart_switch_mode(hartid, scratch->next_arg1, scratch->next_addr,
scratch->next_addr, scratch->next_mode); scratch->next_mode);
} }
static void __noreturn init_warmboot(struct sbi_scratch *scratch, u32 hartid) static void __noreturn init_warmboot(struct sbi_scratch *scratch, u32 hartid)
{ {
int rc; int rc;
struct sbi_platform *plat = sbi_platform_ptr(scratch); const struct sbi_platform *plat = sbi_platform_ptr(scratch);
if (!sbi_platform_has_hart_hotplug(plat)) if (!sbi_platform_has_hart_hotplug(plat))
sbi_hart_wait_for_coldboot(scratch, hartid); sbi_hart_wait_for_coldboot(scratch, hartid);
@@ -108,7 +115,7 @@ static void __noreturn init_warmboot(struct sbi_scratch *scratch, u32 hartid)
if (rc) if (rc)
sbi_hart_hang(); sbi_hart_hang();
rc = sbi_hart_init(scratch, hartid); rc = sbi_hart_init(scratch, hartid, FALSE);
if (rc) if (rc)
sbi_hart_hang(); sbi_hart_hang();
@@ -154,13 +161,13 @@ static atomic_t coldboot_lottery = ATOMIC_INITIALIZER(0);
*/ */
void __noreturn sbi_init(struct sbi_scratch *scratch) void __noreturn sbi_init(struct sbi_scratch *scratch)
{ {
bool coldboot = FALSE; bool coldboot = FALSE;
u32 hartid = sbi_current_hartid(); u32 hartid = sbi_current_hartid();
struct sbi_platform *plat = sbi_platform_ptr(scratch); const struct sbi_platform *plat = sbi_platform_ptr(scratch);
if (sbi_platform_hart_disabled(plat, hartid)) if (sbi_platform_hart_disabled(plat, hartid))
sbi_hart_hang(); sbi_hart_hang();
if (atomic_add_return(&coldboot_lottery, 1) == 1) if (atomic_add_return(&coldboot_lottery, 1) == 1)
coldboot = TRUE; coldboot = TRUE;

View File

@@ -11,56 +11,75 @@
#include <sbi/riscv_asm.h> #include <sbi/riscv_asm.h>
#include <sbi/riscv_barrier.h> #include <sbi/riscv_barrier.h>
#include <sbi/riscv_atomic.h> #include <sbi/riscv_atomic.h>
#include <sbi/sbi_hart.h> #include <sbi/riscv_unpriv.h>
#include <sbi/sbi_error.h>
#include <sbi/sbi_bitops.h> #include <sbi/sbi_bitops.h>
#include <sbi/sbi_console.h> #include <sbi/sbi_hart.h>
#include <sbi/sbi_ipi.h> #include <sbi/sbi_ipi.h>
#include <sbi/sbi_platform.h> #include <sbi/sbi_platform.h>
#include <sbi/sbi_timer.h> #include <sbi/sbi_timer.h>
#include <sbi/sbi_unpriv.h> #include <sbi/sbi_tlb.h>
static int sbi_ipi_send(struct sbi_scratch *scratch, u32 hartid, u32 event) static unsigned long ipi_data_off;
static int sbi_ipi_send(struct sbi_scratch *scratch, u32 hartid, u32 event,
void *data)
{ {
int ret;
struct sbi_scratch *remote_scratch = NULL; struct sbi_scratch *remote_scratch = NULL;
struct sbi_platform *plat = sbi_platform_ptr(scratch); const struct sbi_platform *plat = sbi_platform_ptr(scratch);
struct sbi_ipi_data *ipi_data;
if (sbi_platform_hart_disabled(plat, hartid)) if (sbi_platform_hart_disabled(plat, hartid))
return -1; return -1;
/* Set IPI type on remote hart's scratch area and /*
* Set IPI type on remote hart's scratch area and
* trigger the interrupt * trigger the interrupt
*/ */
remote_scratch = sbi_hart_id_to_scratch(scratch, hartid); remote_scratch = sbi_hart_id_to_scratch(scratch, hartid);
atomic_raw_set_bit(event, &remote_scratch->ipi_type); ipi_data = sbi_scratch_offset_ptr(remote_scratch, ipi_data_off);
if (event == SBI_IPI_EVENT_SFENCE_VMA ||
event == SBI_IPI_EVENT_SFENCE_VMA_ASID) {
ret = sbi_tlb_fifo_update(remote_scratch, event, data);
if (ret > 0)
goto done;
else if (ret < 0)
return ret;
}
atomic_raw_set_bit(event, &ipi_data->ipi_type);
mb(); mb();
sbi_platform_ipi_send(plat, hartid); sbi_platform_ipi_send(plat, hartid);
if (event != SBI_IPI_EVENT_SOFT) if (event != SBI_IPI_EVENT_SOFT)
sbi_platform_ipi_sync(plat, hartid); sbi_platform_ipi_sync(plat, hartid);
done:
return 0; return 0;
} }
int sbi_ipi_send_many(struct sbi_scratch *scratch, int sbi_ipi_send_many(struct sbi_scratch *scratch, struct unpriv_trap *uptrap,
ulong *pmask, u32 event) ulong *pmask, u32 event, void *data)
{ {
ulong i, m; ulong i, m;
ulong mask = sbi_hart_available_mask(); ulong mask = sbi_hart_available_mask();
u32 hartid = sbi_current_hartid(); u32 hartid = sbi_current_hartid();
if (pmask) if (pmask) {
mask &= load_ulong(pmask, csr_read(CSR_MEPC)); mask &= load_ulong(pmask, scratch, uptrap);
if (uptrap->cause)
return SBI_ETRAP;
}
/* send IPIs to every other hart on the set */ /* send IPIs to every other hart on the set */
for (i = 0, m = mask; m; i++, m >>= 1) for (i = 0, m = mask; m; i++, m >>= 1)
if ((m & 1UL) && (i != hartid)) if ((m & 1UL) && (i != hartid))
sbi_ipi_send(scratch, i, event); sbi_ipi_send(scratch, i, event, data);
/* If the current hart is on the set, send an IPI /* If the current hart is on the set, send an IPI
* to it as well * to it as well
*/ */
if (mask & (1UL << hartid)) if (mask & (1UL << hartid))
sbi_ipi_send(scratch, hartid, event); sbi_ipi_send(scratch, hartid, event, data);
return 0; return 0;
} }
@@ -72,15 +91,17 @@ void sbi_ipi_clear_smode(struct sbi_scratch *scratch)
void sbi_ipi_process(struct sbi_scratch *scratch) void sbi_ipi_process(struct sbi_scratch *scratch)
{ {
struct sbi_platform *plat = sbi_platform_ptr(scratch);
volatile unsigned long ipi_type; volatile unsigned long ipi_type;
unsigned int ipi_event; unsigned int ipi_event;
u32 hartid = sbi_current_hartid(); const struct sbi_platform *plat = sbi_platform_ptr(scratch);
struct sbi_ipi_data *ipi_data =
sbi_scratch_offset_ptr(scratch, ipi_data_off);
u32 hartid = sbi_current_hartid();
sbi_platform_ipi_clear(plat, hartid); sbi_platform_ipi_clear(plat, hartid);
do { do {
ipi_type = scratch->ipi_type; ipi_type = ipi_data->ipi_type;
rmb(); rmb();
ipi_event = __ffs(ipi_type); ipi_event = __ffs(ipi_type);
switch (ipi_event) { switch (ipi_event) {
@@ -91,21 +112,41 @@ void sbi_ipi_process(struct sbi_scratch *scratch)
__asm__ __volatile("fence.i"); __asm__ __volatile("fence.i");
break; break;
case SBI_IPI_EVENT_SFENCE_VMA: case SBI_IPI_EVENT_SFENCE_VMA:
__asm__ __volatile("sfence.vma"); case SBI_IPI_EVENT_SFENCE_VMA_ASID:
sbi_tlb_fifo_process(scratch, ipi_event);
break; break;
case SBI_IPI_EVENT_HALT: case SBI_IPI_EVENT_HALT:
sbi_hart_hang(); sbi_hart_hang();
break; break;
}; };
ipi_type = atomic_raw_clear_bit(ipi_event, &scratch->ipi_type); ipi_type = atomic_raw_clear_bit(ipi_event, &ipi_data->ipi_type);
} while(ipi_type > 0); } while (ipi_type > 0);
} }
int sbi_ipi_init(struct sbi_scratch *scratch, bool cold_boot) int sbi_ipi_init(struct sbi_scratch *scratch, bool cold_boot)
{ {
int ret;
struct sbi_ipi_data *ipi_data;
if (cold_boot) {
ipi_data_off = sbi_scratch_alloc_offset(sizeof(*ipi_data),
"IPI_DATA");
if (!ipi_data_off)
return SBI_ENOMEM;
} else {
if (!ipi_data_off)
return SBI_ENOMEM;
}
ipi_data = sbi_scratch_offset_ptr(scratch, ipi_data_off);
ipi_data->ipi_type = 0x00;
ret = sbi_tlb_fifo_init(scratch, cold_boot);
if (ret)
return ret;
/* Enable software interrupts */ /* Enable software interrupts */
csr_set(CSR_MIE, MIP_MSIP); csr_set(CSR_MIE, MIP_MSIP);
return sbi_platform_ipi_init(sbi_platform_ptr(scratch), return sbi_platform_ipi_init(sbi_platform_ptr(scratch), cold_boot);
cold_boot);
} }

View File

@@ -9,11 +9,11 @@
#include <sbi/riscv_asm.h> #include <sbi/riscv_asm.h>
#include <sbi/riscv_encoding.h> #include <sbi/riscv_encoding.h>
#include <sbi/riscv_unpriv.h>
#include <sbi/riscv_fp.h> #include <sbi/riscv_fp.h>
#include <sbi/sbi_error.h> #include <sbi/sbi_error.h>
#include <sbi/sbi_misaligned_ldst.h> #include <sbi/sbi_misaligned_ldst.h>
#include <sbi/sbi_trap.h> #include <sbi/sbi_trap.h>
#include <sbi/sbi_unpriv.h>
union reg_data { union reg_data {
u8 data_bytes[8]; u8 data_bytes[8];
@@ -26,74 +26,81 @@ int sbi_misaligned_load_handler(u32 hartid, ulong mcause,
struct sbi_scratch *scratch) struct sbi_scratch *scratch)
{ {
union reg_data val; union reg_data val;
ulong mstatus = csr_read(CSR_MSTATUS); struct unpriv_trap uptrap;
ulong insn = get_insn(regs->mepc, &mstatus); ulong insn = get_insn(regs->mepc, NULL);
ulong addr = csr_read(CSR_MTVAL); ulong addr = csr_read(CSR_MTVAL);
int i, fp = 0, shift = 0, len = 0; int i, fp = 0, shift = 0, len = 0;
if ((insn & INSN_MASK_LW) == INSN_MATCH_LW) { if ((insn & INSN_MASK_LW) == INSN_MATCH_LW) {
len = 4; len = 4;
shift = 8 * (sizeof(ulong) - len); shift = 8 * (sizeof(ulong) - len);
#if __riscv_xlen == 64 #if __riscv_xlen == 64
} else if ((insn & INSN_MASK_LD) == INSN_MATCH_LD) { } else if ((insn & INSN_MASK_LD) == INSN_MATCH_LD) {
len = 8; len = 8;
shift = 8 * (sizeof(ulong) - len); shift = 8 * (sizeof(ulong) - len);
} else if ((insn & INSN_MASK_LWU) == INSN_MATCH_LWU) { } else if ((insn & INSN_MASK_LWU) == INSN_MATCH_LWU) {
len = 4; len = 4;
#endif #endif
} else if ((insn & INSN_MASK_FLD) == INSN_MATCH_FLD) { } else if ((insn & INSN_MASK_FLD) == INSN_MATCH_FLD) {
fp = 1; fp = 1;
len = 8; len = 8;
} else if ((insn & INSN_MASK_FLW) == INSN_MATCH_FLW) { } else if ((insn & INSN_MASK_FLW) == INSN_MATCH_FLW) {
fp = 1; fp = 1;
len = 4; len = 4;
} else if ((insn & INSN_MASK_LH) == INSN_MATCH_LH) { } else if ((insn & INSN_MASK_LH) == INSN_MATCH_LH) {
len = 2; len = 2;
shift = 8 * (sizeof(ulong) - len); shift = 8 * (sizeof(ulong) - len);
} else if ((insn & INSN_MASK_LHU) == INSN_MATCH_LHU) { } else if ((insn & INSN_MASK_LHU) == INSN_MATCH_LHU) {
len = 2; len = 2;
#ifdef __riscv_compressed #ifdef __riscv_compressed
# if __riscv_xlen >= 64 #if __riscv_xlen >= 64
} else if ((insn & INSN_MASK_C_LD) == INSN_MATCH_C_LD) { } else if ((insn & INSN_MASK_C_LD) == INSN_MATCH_C_LD) {
len = 8; len = 8;
shift = 8 * (sizeof(ulong) - len); shift = 8 * (sizeof(ulong) - len);
insn = RVC_RS2S(insn) << SH_RD; insn = RVC_RS2S(insn) << SH_RD;
} else if ((insn & INSN_MASK_C_LDSP) == INSN_MATCH_C_LDSP && } else if ((insn & INSN_MASK_C_LDSP) == INSN_MATCH_C_LDSP &&
((insn >> SH_RD) & 0x1f)) { ((insn >> SH_RD) & 0x1f)) {
len = 8; len = 8;
shift = 8 * (sizeof(ulong) - len); shift = 8 * (sizeof(ulong) - len);
# endif #endif
} else if ((insn & INSN_MASK_C_LW) ==INSN_MATCH_C_LW) { } else if ((insn & INSN_MASK_C_LW) == INSN_MATCH_C_LW) {
len = 4; len = 4;
shift = 8 * (sizeof(ulong) - len); shift = 8 * (sizeof(ulong) - len);
insn = RVC_RS2S(insn) << SH_RD; insn = RVC_RS2S(insn) << SH_RD;
} else if ((insn & INSN_MASK_C_LWSP) == INSN_MATCH_C_LWSP && } else if ((insn & INSN_MASK_C_LWSP) == INSN_MATCH_C_LWSP &&
((insn >> SH_RD) & 0x1f)) { ((insn >> SH_RD) & 0x1f)) {
len = 4; len = 4;
shift = 8 * (sizeof(ulong) - len); shift = 8 * (sizeof(ulong) - len);
} else if ((insn & INSN_MASK_C_FLD) == INSN_MATCH_C_FLD) { } else if ((insn & INSN_MASK_C_FLD) == INSN_MATCH_C_FLD) {
fp = 1; fp = 1;
len = 8; len = 8;
insn = RVC_RS2S(insn) << SH_RD; insn = RVC_RS2S(insn) << SH_RD;
} else if ((insn & INSN_MASK_C_FLDSP) == INSN_MATCH_C_FLDSP) { } else if ((insn & INSN_MASK_C_FLDSP) == INSN_MATCH_C_FLDSP) {
fp = 1; fp = 1;
len = 8; len = 8;
# if __riscv_xlen == 32 #if __riscv_xlen == 32
} else if ((insn & INSN_MASK_C_FLW) == INSN_MATCH_C_FLW) { } else if ((insn & INSN_MASK_C_FLW) == INSN_MATCH_C_FLW) {
fp = 1; fp = 1;
len = 4; len = 4;
insn = RVC_RS2S(insn) << SH_RD; insn = RVC_RS2S(insn) << SH_RD;
} else if ((insn & INSN_MASK_C_FLWSP) == INSN_MATCH_C_FLWSP) { } else if ((insn & INSN_MASK_C_FLWSP) == INSN_MATCH_C_FLWSP) {
fp = 1; fp = 1;
len = 4; len = 4;
# endif #endif
#endif #endif
} else } else
return SBI_EILL; return SBI_EILL;
val.data_u64 = 0; val.data_u64 = 0;
for (i = 0; i < len; i++) for (i = 0; i < len; i++) {
val.data_bytes[i] = load_u8((void *)(addr + i), regs->mepc); val.data_bytes[i] = load_u8((void *)(addr + i),
scratch, &uptrap);
if (uptrap.cause) {
sbi_trap_redirect(regs, scratch, regs->mepc,
uptrap.cause, uptrap.tval);
return 0;
}
}
if (!fp) if (!fp)
SET_RD(insn, regs, val.data_ulong << shift >> shift); SET_RD(insn, regs, val.data_ulong << shift >> shift);
@@ -112,8 +119,8 @@ int sbi_misaligned_store_handler(u32 hartid, ulong mcause,
struct sbi_scratch *scratch) struct sbi_scratch *scratch)
{ {
union reg_data val; union reg_data val;
ulong mstatus = csr_read(CSR_MSTATUS); struct unpriv_trap uptrap;
ulong insn = get_insn(regs->mepc, &mstatus); ulong insn = get_insn(regs->mepc, NULL);
ulong addr = csr_read(CSR_MTVAL); ulong addr = csr_read(CSR_MTVAL);
int i, len = 0; int i, len = 0;
@@ -126,50 +133,57 @@ int sbi_misaligned_store_handler(u32 hartid, ulong mcause,
len = 8; len = 8;
#endif #endif
} else if ((insn & INSN_MASK_FSD) == INSN_MATCH_FSD) { } else if ((insn & INSN_MASK_FSD) == INSN_MATCH_FSD) {
len = 8; len = 8;
val.data_u64 = GET_F64_RS2(insn, regs); val.data_u64 = GET_F64_RS2(insn, regs);
} else if ((insn & INSN_MASK_FSW) == INSN_MATCH_FSW) { } else if ((insn & INSN_MASK_FSW) == INSN_MATCH_FSW) {
len = 4; len = 4;
val.data_ulong = GET_F32_RS2(insn, regs); val.data_ulong = GET_F32_RS2(insn, regs);
} else if ((insn & INSN_MASK_SH) == INSN_MATCH_SH) { } else if ((insn & INSN_MASK_SH) == INSN_MATCH_SH) {
len = 2; len = 2;
#ifdef __riscv_compressed #ifdef __riscv_compressed
# if __riscv_xlen >= 64 #if __riscv_xlen >= 64
} else if ((insn & INSN_MASK_C_SD) == INSN_MATCH_C_SD) { } else if ((insn & INSN_MASK_C_SD) == INSN_MATCH_C_SD) {
len = 8; len = 8;
val.data_ulong = GET_RS2S(insn, regs); val.data_ulong = GET_RS2S(insn, regs);
} else if ((insn & INSN_MASK_C_SDSP) == INSN_MATCH_C_SDSP && } else if ((insn & INSN_MASK_C_SDSP) == INSN_MATCH_C_SDSP &&
((insn >> SH_RD) & 0x1f)) { ((insn >> SH_RD) & 0x1f)) {
len = 8; len = 8;
val.data_ulong = GET_RS2C(insn, regs); val.data_ulong = GET_RS2C(insn, regs);
# endif #endif
} else if ((insn & INSN_MASK_C_SW) == INSN_MATCH_C_SW) { } else if ((insn & INSN_MASK_C_SW) == INSN_MATCH_C_SW) {
len = 4; len = 4;
val.data_ulong = GET_RS2S(insn, regs); val.data_ulong = GET_RS2S(insn, regs);
} else if ((insn & INSN_MASK_C_SWSP) == INSN_MATCH_C_SWSP && } else if ((insn & INSN_MASK_C_SWSP) == INSN_MATCH_C_SWSP &&
((insn >> SH_RD) & 0x1f)) { ((insn >> SH_RD) & 0x1f)) {
len = 4; len = 4;
val.data_ulong = GET_RS2C(insn, regs); val.data_ulong = GET_RS2C(insn, regs);
} else if ((insn & INSN_MASK_C_FSD) == INSN_MATCH_C_FSD) { } else if ((insn & INSN_MASK_C_FSD) == INSN_MATCH_C_FSD) {
len = 8; len = 8;
val.data_u64 = GET_F64_RS2S(insn, regs); val.data_u64 = GET_F64_RS2S(insn, regs);
} else if ((insn & INSN_MASK_C_FSDSP) == INSN_MATCH_C_FSDSP) { } else if ((insn & INSN_MASK_C_FSDSP) == INSN_MATCH_C_FSDSP) {
len = 8; len = 8;
val.data_u64 = GET_F64_RS2C(insn, regs); val.data_u64 = GET_F64_RS2C(insn, regs);
# if __riscv_xlen == 32 #if __riscv_xlen == 32
} else if ((insn & INSN_MASK_C_FSW) == INSN_MATCH_C_FSW) { } else if ((insn & INSN_MASK_C_FSW) == INSN_MATCH_C_FSW) {
len = 4; len = 4;
val.data_ulong = GET_F32_RS2S(insn, regs); val.data_ulong = GET_F32_RS2S(insn, regs);
} else if ((insn & INSN_MASK_C_FSWSP) == INSN_MATCH_C_FSWSP) { } else if ((insn & INSN_MASK_C_FSWSP) == INSN_MATCH_C_FSWSP) {
len = 4; len = 4;
val.data_ulong = GET_F32_RS2C(insn, regs); val.data_ulong = GET_F32_RS2C(insn, regs);
# endif #endif
#endif #endif
} else } else
return SBI_EILL; return SBI_EILL;
for (i = 0; i < len; i++) for (i = 0; i < len; i++) {
store_u8((void *)(addr + i), val.data_bytes[i], regs->mepc); store_u8((void *)(addr + i), val.data_bytes[i],
scratch, &uptrap);
if (uptrap.cause) {
sbi_trap_redirect(regs, scratch, regs->mepc,
uptrap.cause, uptrap.tval);
return 0;
}
}
regs->mepc += INSN_LEN(insn); regs->mepc += INSN_LEN(insn);

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

@@ -0,0 +1,59 @@
/*
* SPDX-License-Identifier: BSD-2-Clause
*
* Copyright (c) 2019 Western Digital Corporation or its affiliates.
*
* Authors:
* Anup Patel <anup.patel@wdc.com>
*/
#include <sbi/riscv_locks.h>
#include <sbi/sbi_scratch.h>
static spinlock_t extra_lock = SPIN_LOCK_INITIALIZER;
static unsigned long extra_offset = SBI_SCRATCH_EXTRA_SPACE_OFFSET;
unsigned long sbi_scratch_alloc_offset(unsigned long size, const char *owner)
{
unsigned long ret = 0;
/*
* We have a simple brain-dead allocator which never expects
* anything to be free-ed hence it keeps incrementing the
* next allocation offset until it runs-out of space.
*
* In future, we will have more sophisticated allocator which
* will allow us to re-claim free-ed space.
*/
if (!size)
return 0;
while (size & (__SIZEOF_POINTER__ - 1))
size++;
spin_lock(&extra_lock);
if (SBI_SCRATCH_SIZE < (extra_offset + size))
goto done;
ret = extra_offset;
extra_offset += size;
done:
spin_unlock(&extra_lock);
return ret;
}
void sbi_scratch_free_offset(unsigned long offset)
{
if ((offset < SBI_SCRATCH_EXTRA_SPACE_OFFSET) ||
(SBI_SCRATCH_SIZE <= offset))
return;
/*
* We don't actually free-up because it's a simple
* brain-dead allocator.
*/
}

View File

@@ -12,17 +12,18 @@
* bugs as well. Use any optimized routines from newlib or glibc if required. * bugs as well. Use any optimized routines from newlib or glibc if required.
*/ */
#include <plat/string.h> #include <sbi/sbi_string.h>
int strcmp(const char *a, const char *b) int sbi_strcmp(const char *a, const char *b)
{ {
/* search first diff or end of string */ /* search first diff or end of string */
for (; *a == *b && *a != '\0'; a++, b++); for (; *a == *b && *a != '\0'; a++, b++)
;
return *a - *b; return *a - *b;
} }
size_t strlen(const char *str) size_t sbi_strlen(const char *str)
{ {
unsigned long ret = 0; unsigned long ret = 0;
@@ -34,7 +35,7 @@ size_t strlen(const char *str)
return ret; return ret;
} }
size_t strnlen(const char *str, size_t count) size_t sbi_strnlen(const char *str, size_t count)
{ {
unsigned long ret = 0; unsigned long ret = 0;
@@ -47,31 +48,31 @@ size_t strnlen(const char *str, size_t count)
return ret; return ret;
} }
char *strcpy(char *dest, const char *src) char *sbi_strcpy(char *dest, const char *src)
{ {
char *ret = dest; char *ret = dest;
while(*src != '\0') { while (*src != '\0') {
*dest++ = *src++; *dest++ = *src++;
} }
return ret; return ret;
} }
char *strncpy(char *dest, const char *src, size_t count) char *sbi_strncpy(char *dest, const char *src, size_t count)
{ {
char *ret = dest; char *ret = dest;
while(count-- && *src != '\0') { while (count-- && *src != '\0') {
*dest++ = *src++; *dest++ = *src++;
} }
return ret; return ret;
} }
char *strchr(const char *s, int c) char *sbi_strchr(const char *s, int c)
{ {
while(*s != '\0' && *s != (char)c) while (*s != '\0' && *s != (char)c)
s++; s++;
if (*s == '\0') if (*s == '\0')
@@ -80,9 +81,9 @@ char *strchr(const char *s, int c)
return (char *)s; return (char *)s;
} }
char *strrchr(const char *s, int c) char *sbi_strrchr(const char *s, int c)
{ {
const char *last = s + strlen(s); const char *last = s + sbi_strlen(s);
while (last > s && *last != (char)c) while (last > s && *last != (char)c)
last--; last--;
@@ -92,11 +93,11 @@ char *strrchr(const char *s, int c)
else else
return (char *)last; return (char *)last;
} }
void *memset(void *s, int c, size_t count) void *sbi_memset(void *s, int c, size_t count)
{ {
char *temp = s; char *temp = s;
while(count > 0 ){ while (count > 0) {
count--; count--;
*temp++ = c; *temp++ = c;
} }
@@ -104,9 +105,9 @@ void *memset(void *s, int c, size_t count)
return s; return s;
} }
void *memcpy(void *dest, const void *src, size_t count) void *sbi_memcpy(void *dest, const void *src, size_t count)
{ {
char *temp1 = dest; char *temp1 = dest;
const char *temp2 = src; const char *temp2 = src;
while (count > 0) { while (count > 0) {
@@ -117,16 +118,16 @@ void *memcpy(void *dest, const void *src, size_t count)
return dest; return dest;
} }
void *memmove(void *dest, const void *src, size_t count) void *sbi_memmove(void *dest, const void *src, size_t count)
{ {
char *temp1 = (char *)dest; char *temp1 = (char *)dest;
const char *temp2 = (char *)src; const char *temp2 = (char *)src;
if (src == dest) if (src == dest)
return dest; return dest;
if (dest < src) { if (dest < src) {
while(count > 0) { while (count > 0) {
*temp1++ = *temp2++; *temp1++ = *temp2++;
count--; count--;
} }
@@ -134,7 +135,7 @@ void *memmove(void *dest, const void *src, size_t count)
temp1 = dest + count - 1; temp1 = dest + count - 1;
temp2 = src + count - 1; temp2 = src + count - 1;
while(count > 0) { while (count > 0) {
*temp1-- = *temp2--; *temp1-- = *temp2--;
count--; count--;
} }
@@ -143,7 +144,7 @@ void *memmove(void *dest, const void *src, size_t count)
return dest; return dest;
} }
int memcmp(const void *s1, const void *s2, size_t count) int sbi_memcmp(const void *s1, const void *s2, size_t count)
{ {
const char *temp1 = s1; const char *temp1 = s1;
const char *temp2 = s2; const char *temp2 = s2;
@@ -159,13 +160,13 @@ int memcmp(const void *s1, const void *s2, size_t count)
return 0; return 0;
} }
void *memchr(const void *s, int c, size_t count) void *sbi_memchr(const void *s, int c, size_t count)
{ {
const unsigned char *temp = s; const unsigned char *temp = s;
while (count > 0) { while (count > 0) {
if ((unsigned char)c == *temp++) { if ((unsigned char)c == *temp++) {
return (void *)(temp-1); return (void *)(temp - 1);
} }
count--; count--;
} }

View File

@@ -15,33 +15,31 @@
int sbi_system_early_init(struct sbi_scratch *scratch, bool cold_boot) int sbi_system_early_init(struct sbi_scratch *scratch, bool cold_boot)
{ {
return sbi_platform_early_init(sbi_platform_ptr(scratch), return sbi_platform_early_init(sbi_platform_ptr(scratch), cold_boot);
cold_boot);
} }
int sbi_system_final_init(struct sbi_scratch *scratch, bool cold_boot) int sbi_system_final_init(struct sbi_scratch *scratch, bool cold_boot)
{ {
return sbi_platform_final_init(sbi_platform_ptr(scratch), return sbi_platform_final_init(sbi_platform_ptr(scratch), cold_boot);
cold_boot);
} }
void __attribute__((noreturn)) sbi_system_reboot(struct sbi_scratch *scratch, void __attribute__((noreturn))
u32 type) sbi_system_reboot(struct sbi_scratch *scratch, u32 type)
{ {
sbi_platform_system_reboot(sbi_platform_ptr(scratch), type); sbi_platform_system_reboot(sbi_platform_ptr(scratch), type);
sbi_hart_hang(); sbi_hart_hang();
} }
void __attribute__((noreturn)) sbi_system_shutdown(struct sbi_scratch *scratch, void __attribute__((noreturn))
u32 type) sbi_system_shutdown(struct sbi_scratch *scratch, u32 type)
{ {
/* First try the platform-specific method */ /* First try the platform-specific method */
sbi_platform_system_shutdown(sbi_platform_ptr(scratch), type); sbi_platform_system_shutdown(sbi_platform_ptr(scratch), type);
/* If that fails (or is not implemented) send an IPI on every /* If that fails (or is not implemented) send an IPI on every
* hart to hang and then hang the current hart */ * hart to hang and then hang the current hart */
sbi_ipi_send_many(scratch, NULL, SBI_IPI_EVENT_HALT); sbi_ipi_send_many(scratch, NULL, NULL, SBI_IPI_EVENT_HALT, NULL);
sbi_hart_hang(); sbi_hart_hang();
} }

View File

@@ -16,13 +16,12 @@
u64 get_ticks(void) u64 get_ticks(void)
{ {
u32 lo, hi, tmp; u32 lo, hi, tmp;
__asm__ __volatile__ ( __asm__ __volatile__("1:\n"
"1:\n" "rdtimeh %0\n"
"rdtimeh %0\n" "rdtime %1\n"
"rdtime %1\n" "rdtimeh %2\n"
"rdtimeh %2\n" "bne %0, %2, 1b"
"bne %0, %2, 1b" : "=&r"(hi), "=&r"(lo), "=&r"(tmp));
: "=&r" (hi), "=&r" (lo), "=&r" (tmp));
return ((u64)hi << 32) | lo; return ((u64)hi << 32) | lo;
} }
#else #else
@@ -30,16 +29,14 @@ u64 get_ticks(void)
{ {
unsigned long n; unsigned long n;
__asm__ __volatile__ ( __asm__ __volatile__("rdtime %0" : "=r"(n));
"rdtime %0"
: "=r" (n));
return n; return n;
} }
#endif #endif
u64 sbi_timer_value(struct sbi_scratch *scratch) u64 sbi_timer_value(struct sbi_scratch *scratch)
{ {
struct sbi_platform *plat = sbi_platform_ptr(scratch); const struct sbi_platform *plat = sbi_platform_ptr(scratch);
if (sbi_platform_has_timer_value(plat)) if (sbi_platform_has_timer_value(plat))
return sbi_platform_timer_value(plat); return sbi_platform_timer_value(plat);
@@ -54,8 +51,7 @@ void sbi_timer_event_stop(struct sbi_scratch *scratch)
void sbi_timer_event_start(struct sbi_scratch *scratch, u64 next_event) void sbi_timer_event_start(struct sbi_scratch *scratch, u64 next_event)
{ {
sbi_platform_timer_event_start(sbi_platform_ptr(scratch), sbi_platform_timer_event_start(sbi_platform_ptr(scratch), next_event);
next_event);
csr_clear(CSR_MIP, MIP_STIP); csr_clear(CSR_MIP, MIP_STIP);
csr_set(CSR_MIE, MIP_MTIP); csr_set(CSR_MIE, MIP_MTIP);
} }
@@ -68,6 +64,5 @@ void sbi_timer_process(struct sbi_scratch *scratch)
int sbi_timer_init(struct sbi_scratch *scratch, bool cold_boot) int sbi_timer_init(struct sbi_scratch *scratch, bool cold_boot)
{ {
return sbi_platform_timer_init(sbi_platform_ptr(scratch), return sbi_platform_timer_init(sbi_platform_ptr(scratch), cold_boot);
cold_boot);
} }

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

@@ -0,0 +1,227 @@
/*
* SPDX-License-Identifier: BSD-2-Clause
*
* Copyright (c) 2019 Western Digital Corporation or its affiliates.
*
* Authors:
* Atish Patra <atish.patra@wdc.com>
* Anup Patel <anup.patel@wdc.com>
*/
#include <sbi/riscv_asm.h>
#include <sbi/riscv_barrier.h>
#include <sbi/sbi_error.h>
#include <sbi/sbi_fifo.h>
#include <sbi/sbi_hart.h>
#include <sbi/sbi_bitops.h>
#include <sbi/sbi_scratch.h>
#include <sbi/sbi_tlb.h>
#include <sbi/sbi_string.h>
static unsigned long ipi_tlb_fifo_off;
static unsigned long ipi_tlb_fifo_mem_off;
static inline int __sbi_tlb_fifo_range_check(struct sbi_tlb_info *curr,
struct sbi_tlb_info *next)
{
unsigned long curr_end;
unsigned long next_end;
int ret = SBI_FIFO_UNCHANGED;
if (!curr || !next)
return ret;
next_end = next->start + next->size;
curr_end = curr->start + curr->size;
if (next->start <= curr->start && next_end > curr_end) {
curr->start = next->start;
curr->size = next->size;
ret = SBI_FIFO_UPDATED;
} else if (next->start >= curr->start && next_end <= curr_end) {
ret = SBI_FIFO_SKIP;
}
return ret;
}
/**
* Call back to decide if an inplace fifo update is required or next entry can
* can be skipped. Here are the different cases that are being handled.
*
* Case1:
* if next flush request range lies within one of the existing entry, skip
* the next entry.
* Case2:
* if flush request range in current fifo entry lies within next flush
* request, update the current entry.
* Case3:
if a complete vma flush is requested, then all entries can be deleted
and new request can be enqueued. This will not be done for ASID case
as that means we have to iterate again in the fifo to figure out which
entries belong to that ASID.
*/
static int sbi_tlb_fifo_update_cb(void *in, void *data)
{
struct sbi_tlb_info *curr;
struct sbi_tlb_info *next;
int ret = SBI_FIFO_UNCHANGED;
if (!in && !!data)
return ret;
curr = (struct sbi_tlb_info *)data;
next = (struct sbi_tlb_info *)in;
if (next->type == SBI_TLB_FLUSH_VMA_ASID &&
curr->type == SBI_TLB_FLUSH_VMA_ASID) {
if (next->asid == curr->asid)
ret = __sbi_tlb_fifo_range_check(curr, next);
} else if (next->type == SBI_TLB_FLUSH_VMA &&
curr->type == SBI_TLB_FLUSH_VMA) {
if (next->size == SBI_TLB_FLUSH_ALL)
ret = SBI_FIFO_RESET;
else
ret = __sbi_tlb_fifo_range_check(curr, next);
}
return ret;
}
int sbi_tlb_fifo_update(struct sbi_scratch *scratch, u32 event, void *data)
{
int ret;
struct sbi_fifo *ipi_tlb_fifo;
struct sbi_tlb_info *tinfo = data;
ipi_tlb_fifo = sbi_scratch_offset_ptr(scratch,
ipi_tlb_fifo_off);
/*
* If address range to flush is too big then simply
* upgrade it to flush all because we can only flush
* 4KB at a time.
*/
if (tinfo->size >= SBI_TLB_FLUSH_MAX_SIZE) {
tinfo->start = 0;
tinfo->size = SBI_TLB_FLUSH_ALL;
}
ret = sbi_fifo_inplace_update(ipi_tlb_fifo, data,
sbi_tlb_fifo_update_cb);
if (ret == SBI_FIFO_SKIP || ret == SBI_FIFO_UPDATED) {
return 1;
}
while (sbi_fifo_enqueue(ipi_tlb_fifo, data) < 0) {
/**
* For now, Busy loop until there is space in the fifo.
* There may be case where target hart is also
* enqueue in source hart's fifo. Both hart may busy
* loop leading to a deadlock.
* TODO: Introduce a wait/wakeup event mechansim to handle
* this properly.
*/
__asm__ __volatile("nop");
__asm__ __volatile("nop");
}
return 0;
}
static void sbi_tlb_flush_all(void)
{
__asm__ __volatile("sfence.vma");
}
static void sbi_tlb_fifo_sfence_vma(struct sbi_tlb_info *tinfo)
{
unsigned long start = tinfo->start;
unsigned long size = tinfo->size;
unsigned long i;
if ((start == 0 && size == 0) || (size == SBI_TLB_FLUSH_ALL)) {
sbi_tlb_flush_all();
return;
}
for (i = 0; i < size; i += PAGE_SIZE) {
__asm__ __volatile__("sfence.vma %0"
:
: "r"(start + i)
: "memory");
}
}
static void sbi_tlb_fifo_sfence_vma_asid(struct sbi_tlb_info *tinfo)
{
unsigned long start = tinfo->start;
unsigned long size = tinfo->size;
unsigned long asid = tinfo->asid;
unsigned long i;
if (start == 0 && size == 0) {
sbi_tlb_flush_all();
return;
}
/* Flush entire MM context for a given ASID */
if (size == SBI_TLB_FLUSH_ALL) {
__asm__ __volatile__("sfence.vma x0, %0"
:
: "r"(asid)
: "memory");
return;
}
for (i = 0; i < size; i += PAGE_SIZE) {
__asm__ __volatile__("sfence.vma %0, %1"
:
: "r"(start + i), "r"(asid)
: "memory");
}
}
void sbi_tlb_fifo_process(struct sbi_scratch *scratch, u32 event)
{
struct sbi_tlb_info tinfo;
struct sbi_fifo *ipi_tlb_fifo =
sbi_scratch_offset_ptr(scratch, ipi_tlb_fifo_off);
while (!sbi_fifo_dequeue(ipi_tlb_fifo, &tinfo)) {
if (tinfo.type == SBI_TLB_FLUSH_VMA)
sbi_tlb_fifo_sfence_vma(&tinfo);
else if (tinfo.type == SBI_TLB_FLUSH_VMA_ASID)
sbi_tlb_fifo_sfence_vma_asid(&tinfo);
sbi_memset(&tinfo, 0, SBI_TLB_INFO_SIZE);
}
}
int sbi_tlb_fifo_init(struct sbi_scratch *scratch, bool cold_boot)
{
void *ipi_tlb_mem;
struct sbi_fifo *ipi_tlb_q;
if (cold_boot) {
ipi_tlb_fifo_off = sbi_scratch_alloc_offset(sizeof(*ipi_tlb_q),
"IPI_TLB_FIFO");
if (!ipi_tlb_fifo_off)
return SBI_ENOMEM;
ipi_tlb_fifo_mem_off = sbi_scratch_alloc_offset(
SBI_TLB_FIFO_NUM_ENTRIES * SBI_TLB_INFO_SIZE,
"IPI_TLB_FIFO_MEM");
if (!ipi_tlb_fifo_mem_off) {
sbi_scratch_free_offset(ipi_tlb_fifo_off);
return SBI_ENOMEM;
}
} else {
if (!ipi_tlb_fifo_off ||
!ipi_tlb_fifo_mem_off)
return SBI_ENOMEM;
}
ipi_tlb_q = sbi_scratch_offset_ptr(scratch, ipi_tlb_fifo_off);
ipi_tlb_mem = sbi_scratch_offset_ptr(scratch, ipi_tlb_fifo_mem_off);
sbi_fifo_init(ipi_tlb_q, ipi_tlb_mem,
SBI_TLB_FIFO_NUM_ENTRIES, SBI_TLB_INFO_SIZE);
return 0;
}

View File

@@ -9,6 +9,7 @@
#include <sbi/riscv_asm.h> #include <sbi/riscv_asm.h>
#include <sbi/riscv_encoding.h> #include <sbi/riscv_encoding.h>
#include <sbi/riscv_unpriv.h>
#include <sbi/sbi_console.h> #include <sbi/sbi_console.h>
#include <sbi/sbi_ecall.h> #include <sbi/sbi_ecall.h>
#include <sbi/sbi_error.h> #include <sbi/sbi_error.h>
@@ -19,49 +20,47 @@
#include <sbi/sbi_timer.h> #include <sbi/sbi_timer.h>
#include <sbi/sbi_trap.h> #include <sbi/sbi_trap.h>
static void __noreturn sbi_trap_error(const char *msg, static void __noreturn sbi_trap_error(const char *msg, int rc, u32 hartid,
int rc, u32 hartid,
ulong mcause, ulong mtval, ulong mcause, ulong mtval,
struct sbi_trap_regs *regs) struct sbi_trap_regs *regs)
{ {
sbi_printf("%s: hart%d: %s (error %d)\n", sbi_printf("%s: hart%d: %s (error %d)\n", __func__, hartid, msg, rc);
__func__, hartid, msg, rc); sbi_printf("%s: hart%d: mcause=0x%" PRILX " mtval=0x%" PRILX "\n",
sbi_printf("%s: hart%d: mcause=0x%"PRILX" mtval=0x%"PRILX"\n",
__func__, hartid, mcause, mtval); __func__, hartid, mcause, mtval);
sbi_printf("%s: hart%d: mepc=0x%"PRILX" mstatus=0x%"PRILX"\n", sbi_printf("%s: hart%d: mepc=0x%" PRILX " mstatus=0x%" PRILX "\n",
__func__, hartid, regs->mepc, regs->mstatus); __func__, hartid, regs->mepc, regs->mstatus);
sbi_printf("%s: hart%d: %s=0x%"PRILX" %s=0x%"PRILX"\n", sbi_printf("%s: hart%d: %s=0x%" PRILX " %s=0x%" PRILX "\n", __func__,
__func__, hartid, "ra", regs->ra, "sp", regs->sp); hartid, "ra", regs->ra, "sp", regs->sp);
sbi_printf("%s: hart%d: %s=0x%"PRILX" %s=0x%"PRILX"\n", sbi_printf("%s: hart%d: %s=0x%" PRILX " %s=0x%" PRILX "\n", __func__,
__func__, hartid, "gp", regs->gp, "tp", regs->tp); hartid, "gp", regs->gp, "tp", regs->tp);
sbi_printf("%s: hart%d: %s=0x%"PRILX" %s=0x%"PRILX"\n", sbi_printf("%s: hart%d: %s=0x%" PRILX " %s=0x%" PRILX "\n", __func__,
__func__, hartid, "s0", regs->s0, "s1", regs->s1); hartid, "s0", regs->s0, "s1", regs->s1);
sbi_printf("%s: hart%d: %s=0x%"PRILX" %s=0x%"PRILX"\n", sbi_printf("%s: hart%d: %s=0x%" PRILX " %s=0x%" PRILX "\n", __func__,
__func__, hartid, "a0", regs->a0, "a1", regs->a1); hartid, "a0", regs->a0, "a1", regs->a1);
sbi_printf("%s: hart%d: %s=0x%"PRILX" %s=0x%"PRILX"\n", sbi_printf("%s: hart%d: %s=0x%" PRILX " %s=0x%" PRILX "\n", __func__,
__func__, hartid, "a2", regs->a2, "a3", regs->a3); hartid, "a2", regs->a2, "a3", regs->a3);
sbi_printf("%s: hart%d: %s=0x%"PRILX" %s=0x%"PRILX"\n", sbi_printf("%s: hart%d: %s=0x%" PRILX " %s=0x%" PRILX "\n", __func__,
__func__, hartid, "a4", regs->a4, "a5", regs->a5); hartid, "a4", regs->a4, "a5", regs->a5);
sbi_printf("%s: hart%d: %s=0x%"PRILX" %s=0x%"PRILX"\n", sbi_printf("%s: hart%d: %s=0x%" PRILX " %s=0x%" PRILX "\n", __func__,
__func__, hartid, "a6", regs->a6, "a7", regs->a7); hartid, "a6", regs->a6, "a7", regs->a7);
sbi_printf("%s: hart%d: %s=0x%"PRILX" %s=0x%"PRILX"\n", sbi_printf("%s: hart%d: %s=0x%" PRILX " %s=0x%" PRILX "\n", __func__,
__func__, hartid, "s2", regs->s2, "s3", regs->s3); hartid, "s2", regs->s2, "s3", regs->s3);
sbi_printf("%s: hart%d: %s=0x%"PRILX" %s=0x%"PRILX"\n", sbi_printf("%s: hart%d: %s=0x%" PRILX " %s=0x%" PRILX "\n", __func__,
__func__, hartid, "s4", regs->s4, "s5", regs->s5); hartid, "s4", regs->s4, "s5", regs->s5);
sbi_printf("%s: hart%d: %s=0x%"PRILX" %s=0x%"PRILX"\n", sbi_printf("%s: hart%d: %s=0x%" PRILX " %s=0x%" PRILX "\n", __func__,
__func__, hartid, "s6", regs->s6, "s7", regs->s7); hartid, "s6", regs->s6, "s7", regs->s7);
sbi_printf("%s: hart%d: %s=0x%"PRILX" %s=0x%"PRILX"\n", sbi_printf("%s: hart%d: %s=0x%" PRILX " %s=0x%" PRILX "\n", __func__,
__func__, hartid, "s8", regs->s8, "s9", regs->s9); hartid, "s8", regs->s8, "s9", regs->s9);
sbi_printf("%s: hart%d: %s=0x%"PRILX" %s=0x%"PRILX"\n", sbi_printf("%s: hart%d: %s=0x%" PRILX " %s=0x%" PRILX "\n", __func__,
__func__, hartid, "s10", regs->s10, "s11", regs->s11); hartid, "s10", regs->s10, "s11", regs->s11);
sbi_printf("%s: hart%d: %s=0x%"PRILX" %s=0x%"PRILX"\n", sbi_printf("%s: hart%d: %s=0x%" PRILX " %s=0x%" PRILX "\n", __func__,
__func__, hartid, "t0", regs->t0, "t1", regs->t1); hartid, "t0", regs->t0, "t1", regs->t1);
sbi_printf("%s: hart%d: %s=0x%"PRILX" %s=0x%"PRILX"\n", sbi_printf("%s: hart%d: %s=0x%" PRILX " %s=0x%" PRILX "\n", __func__,
__func__, hartid, "t2", regs->t2, "t3", regs->t3); hartid, "t2", regs->t2, "t3", regs->t3);
sbi_printf("%s: hart%d: %s=0x%"PRILX" %s=0x%"PRILX"\n", sbi_printf("%s: hart%d: %s=0x%" PRILX " %s=0x%" PRILX "\n", __func__,
__func__, hartid, "t4", regs->t4, "t5", regs->t5); hartid, "t4", regs->t4, "t5", regs->t5);
sbi_printf("%s: hart%d: %s=0x%"PRILX"\n", sbi_printf("%s: hart%d: %s=0x%" PRILX "\n", __func__, hartid, "t6",
__func__, hartid, "t6", regs->t6); regs->t6);
sbi_hart_hang(); sbi_hart_hang();
} }
@@ -77,8 +76,7 @@ static void __noreturn sbi_trap_error(const char *msg,
* *
* @return 0 on success and negative error code on failure * @return 0 on success and negative error code on failure
*/ */
int sbi_trap_redirect(struct sbi_trap_regs *regs, int sbi_trap_redirect(struct sbi_trap_regs *regs, struct sbi_scratch *scratch,
struct sbi_scratch *scratch,
ulong epc, ulong cause, ulong tval) ulong epc, ulong cause, ulong tval)
{ {
ulong new_mstatus, prev_mode; ulong new_mstatus, prev_mode;
@@ -100,8 +98,8 @@ int sbi_trap_redirect(struct sbi_trap_regs *regs,
new_mstatus = regs->mstatus; new_mstatus = regs->mstatus;
/* Clear MPP, SPP, SPIE, and SIE */ /* Clear MPP, SPP, SPIE, and SIE */
new_mstatus &= ~(MSTATUS_MPP | new_mstatus &=
MSTATUS_SPP | MSTATUS_SPIE | MSTATUS_SIE); ~(MSTATUS_MPP | MSTATUS_SPP | MSTATUS_SPIE | MSTATUS_SIE);
/* Set SPP */ /* Set SPP */
if (prev_mode == PRV_S) if (prev_mode == PRV_S)
@@ -135,13 +133,14 @@ int sbi_trap_redirect(struct sbi_trap_regs *regs,
* @param regs pointer to register state * @param regs pointer to register state
* @param scratch pointer to sbi_scratch of current HART * @param scratch pointer to sbi_scratch of current HART
*/ */
void sbi_trap_handler(struct sbi_trap_regs *regs, void sbi_trap_handler(struct sbi_trap_regs *regs, struct sbi_scratch *scratch)
struct sbi_scratch *scratch)
{ {
int rc = SBI_ENOTSUPP; int rc = SBI_ENOTSUPP;
const char *msg = "trap handler failed"; const char *msg = "trap handler failed";
u32 hartid = sbi_current_hartid(); u32 hartid = sbi_current_hartid();
ulong mcause = csr_read(CSR_MCAUSE); ulong mcause = csr_read(CSR_MCAUSE);
ulong mtval = csr_read(CSR_MTVAL);
struct unpriv_trap *uptrap;
if (mcause & (1UL << (__riscv_xlen - 1))) { if (mcause & (1UL << (__riscv_xlen - 1))) {
mcause &= ~(1UL << (__riscv_xlen - 1)); mcause &= ~(1UL << (__riscv_xlen - 1));
@@ -161,7 +160,7 @@ void sbi_trap_handler(struct sbi_trap_regs *regs,
switch (mcause) { switch (mcause) {
case CAUSE_ILLEGAL_INSTRUCTION: case CAUSE_ILLEGAL_INSTRUCTION:
rc = sbi_illegal_insn_handler(hartid, mcause, regs, scratch); rc = sbi_illegal_insn_handler(hartid, mcause, regs, scratch);
msg = "illegal instruction handler failed"; msg = "illegal instruction handler failed";
break; break;
case CAUSE_MISALIGNED_LOAD: case CAUSE_MISALIGNED_LOAD:
@@ -169,20 +168,40 @@ void sbi_trap_handler(struct sbi_trap_regs *regs,
msg = "misaligned load handler failed"; msg = "misaligned load handler failed";
break; break;
case CAUSE_MISALIGNED_STORE: case CAUSE_MISALIGNED_STORE:
rc = sbi_misaligned_store_handler(hartid, mcause, regs, scratch); rc = sbi_misaligned_store_handler(hartid, mcause, regs,
scratch);
msg = "misaligned store handler failed"; msg = "misaligned store handler failed";
break; break;
case CAUSE_SUPERVISOR_ECALL: case CAUSE_SUPERVISOR_ECALL:
case CAUSE_HYPERVISOR_ECALL: case CAUSE_HYPERVISOR_ECALL:
rc = sbi_ecall_handler(hartid, mcause, regs, scratch); rc = sbi_ecall_handler(hartid, mcause, regs, scratch);
msg = "ecall handler failed"; msg = "ecall handler failed";
break; break;
case CAUSE_LOAD_ACCESS:
case CAUSE_STORE_ACCESS:
case CAUSE_LOAD_PAGE_FAULT:
case CAUSE_STORE_PAGE_FAULT:
uptrap = sbi_hart_get_trap_info(scratch);
if ((regs->mstatus & MSTATUS_MPRV) && uptrap) {
rc = 0;
regs->mepc += uptrap->ilen;
uptrap->cause = mcause;
uptrap->tval = mtval;
} else {
rc = sbi_trap_redirect(regs, scratch, regs->mepc,
mcause, mtval);
}
msg = "page/access fault handler failed";
break;
default: default:
/* If the trap came from S or U mode, redirect it there */
rc = sbi_trap_redirect(regs, scratch, regs->mepc, mcause, mtval);
break; break;
}; };
trap_error: trap_error:
if (rc) { if (rc) {
sbi_trap_error(msg, rc, hartid, mcause, csr_read(CSR_MTVAL), regs); sbi_trap_error(msg, rc, hartid, mcause, csr_read(CSR_MTVAL),
regs);
} }
} }

View File

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

118
lib/utils/irqchip/plic.c Normal file
View File

@@ -0,0 +1,118 @@
/*
* SPDX-License-Identifier: BSD-2-Clause
*
* Copyright (c) 2019 Western Digital Corporation or its affiliates.
*
* Authors:
* Anup Patel <anup.patel@wdc.com>
*/
#include <sbi/riscv_io.h>
#include <sbi/riscv_encoding.h>
#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
#define PLIC_ENABLE_BASE 0x2000
#define PLIC_ENABLE_STRIDE 0x80
#define PLIC_CONTEXT_BASE 0x200000
#define PLIC_CONTEXT_STRIDE 0x1000
static u32 plic_hart_count;
static u32 plic_num_sources;
static volatile void *plic_base;
static void plic_set_priority(u32 source, u32 val)
{
volatile void *plic_priority =
plic_base + PLIC_PRIORITY_BASE + 4 * source;
writel(val, plic_priority);
}
void plic_set_thresh(u32 cntxid, u32 val)
{
volatile void *plic_thresh =
plic_base + PLIC_CONTEXT_BASE + PLIC_CONTEXT_STRIDE * cntxid;
writel(val, plic_thresh);
}
void plic_set_ie(u32 cntxid, u32 word_index, u32 val)
{
volatile void *plic_ie =
plic_base + PLIC_ENABLE_BASE + PLIC_ENABLE_STRIDE * cntxid;
writel(val, plic_ie + word_index * 4);
}
void plic_fdt_fixup(void *fdt, const char *compat)
{
u32 *cells;
int i, cells_count;
u32 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] = fdt32_to_cpu(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;
if (plic_hart_count <= target_hart)
return -1;
/* By default, disable 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, 0);
}
/* By default, disable 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, 0);
}
/* 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;
}
int plic_cold_irqchip_init(unsigned long base, u32 num_sources, u32 hart_count)
{
int i;
plic_hart_count = hart_count;
plic_num_sources = num_sources;
plic_base = (void *)base;
/* Configure default priorities of all IRQs */
for (i = 1; i <= plic_num_sources; i++)
plic_set_priority(i, 1);
return 0;
}

View File

@@ -0,0 +1 @@
DisableFormat: true

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