230 Commits
v1.0 ... v1.2

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

Signed-off-by: Anup Patel <apatel@ventanamicro.com>
2022-12-24 11:36:49 +05:30
Atish Patra
d5d12a91d1 docs: pmu: Update the pmu doc with removal of mcountinhbit restriction
Since commit b28f070, it is possible for platforms to run perf monitoring
even if mcountinhibit is not supported. Sampling still won't be possible
though as it requires sscofpmf extension.

Update the docs to remove the restriction.

Signed-off-by: Atish Patra <atishp@rivosinc.com>
Reviewed-by: Anup Patel <anup@brainfault.org>
2022-12-24 11:07:14 +05:30
Conor Dooley
0412460baf docs: pmu: update a reference to a deprecated property name
event-to-mhpmevent was deprecated and replaced by
riscv,event-to-mhpmevent, but a reference remains to the old name.
Replace it with the new one.

Signed-off-by: Conor Dooley <conor.dooley@microchip.com>
Reviewed-by: Atish Patra <atishp@rivosinc.com>
Reviewed-by: Anup Patel <anup@brainfault.org>
2022-12-24 11:06:04 +05:30
Conor Dooley
391ec85875 docs: pmu: fix binding example
The first PMU binding example does not terminate properties with a ;,
which is invalid. Noticed while converting the binding to yaml.

Signed-off-by: Conor Dooley <conor.dooley@microchip.com>
Reviewed-by: Bin Meng <bmeng@tinylab.org>
Reviewed-by: Anup Patel <anup@brainfault.org>
2022-12-24 11:05:09 +05:30
Icenowy Zheng
b848d8763a lib: utils/timer: mtimer: add T-Head C9xx CLINT compatible
As we already added the quirk for lacking mtime register to MTIMER
driver, add T-Head C9xx CLINT compatible to it and wire the quirk.

Signed-off-by: Icenowy Zheng <uwu@icenowy.me>
Reviewed-by: Anup Patel <anup@brainfault.org>
2022-12-17 11:01:06 +05:30
Icenowy Zheng
ca7810aecd lib: utils/timer: mtimer: add a quirk for lacking mtime register
T-Head developers surely have a different understanding of time CSR and
CLINT's mtime register with SiFive ones, that they did not implement
the mtime register at all -- as shown in openC906 source code, their
time CSR value is just exposed at the top of their processor IP block
and expects an external continous counter, which makes it not
overrideable, and thus mtime register is not implemented, even not for
reading. However, if CLINTEE is not enabled in T-Head's MXSTATUS
extended CSR, these systems still rely on the mtimecmp registers to
generate timer interrupts. This makes it necessary to implement T-Head
C9xx CLINT support in OpenSBI MTIMER driver, which skips implementing
reading mtime register and falls back to default code that reads time
CSR.

Add a quirk into MTIMER driver, which represents a mtime register is
lacking and time CSR value should be used instead.

Signed-off-by: Icenowy Zheng <uwu@icenowy.me>
Reviewed-by: Anup Patel <anup@brainfault.org>
2022-12-17 11:01:03 +05:30
Icenowy Zheng
a8ee82cd8c lib: utils/ipi: mswi: add T-Head C9xx CLINT compatible
Althoug the MTIMER part of a C9xx CLINT differs from a SiFive one, the
MSWI part is compliant.

Add T-Head C9xx CLINT compatible string to fdt_ipi_mswi code, sharing
the same codepath with SiFive CLINT.

Signed-off-by: Icenowy Zheng <uwu@icenowy.me>
Reviewed-by: Anup Patel <anup@brainfault.org>
2022-12-17 11:01:00 +05:30
Bin Meng
9a2eeb4aae lib: utils/irqchip: plic: Ensure no out-of-bound access in context save/restore helpers
Currently the context save/restore helpers writes/reads the provided
array using an index whose maximum value is determined by PLIC, which
potentially may disagree with the caller to these helpers.

Add a parameter to ask the caller to provide the size limit of the
array to ensure no out-of-bound access happens.

Signed-off-by: Bin Meng <bmeng@tinylab.org>
Reviewed-by: Anup Patel <anup@brainfault.org>
2022-12-17 09:03:30 +05:30
Bin Meng
fabbc00668 lib: utils/irqchip: plic: Fix the off-by-one error in context save/restore helpers
plic->num_src holds the number of interrupt sources without interrupt
source 0 but the interrupt enable register includes a bit for the
interrupt source 0 in the first word.

Fixes: 415ecf28f7 ("lib: irqchip/plic: Add context save/restore helpers")
Signed-off-by: Bin Meng <bmeng@tinylab.org>
Reviewed-by: Anup Patel <anup@brainfault.org>
Reviewed-by: Samuel Holland <samuel@sholland.org>
2022-12-17 09:02:40 +05:30
Bin Meng
91c8a7d5ce lib: utils/irqchip: plic: Fix the off-by-one error in plic_context_init()
The number of interrupt enable register in words was once correct,
but was wrongly changed to have an off-by-one error since
commit 8c362e7d06 ("lib: irqchip/plic: Factor out a context init function").

Fixes: 8c362e7d06 ("lib: irqchip/plic: Factor out a context init function")
Signed-off-by: Bin Meng <bmeng@tinylab.org>
Reviewed-by: Anup Patel <anup@brainfault.org>
Reviewed-by: Samuel Holland <samuel@sholland.org>
2022-12-17 09:00:35 +05:30
Bin Meng
8509e46ca6 lib: utils/irqchip: plic: Ensure no out-of-bound access in priority save/restore helpers
Currently the priority save/restore helpers writes/reads the provided
array using an index whose maximum value is determined by PLIC, which
potentially may disagree with the caller to these helpers.

Add a parameter to ask the caller to provide the size limit of the
array to ensure no out-of-bound access happens.

Signed-off-by: Bin Meng <bmeng@tinylab.org>
Reviewed-by: Anup Patel <anup@brainfault.org>
2022-12-17 09:00:29 +05:30
Bin Meng
34da6638ad lib: utils/irqchip: plic: Fix the off-by-one error in priority save/restore helpers
Interrupt source 0 is reserved. Hence the irq should start from 1.

Fixes: 2b79b694a8 ("lib: irqchip/plic: Add priority save/restore helpers")
Signed-off-by: Bin Meng <bmeng@tinylab.org>
Reviewed-by: Anup Patel <anup@brainfault.org>
2022-12-17 08:42:21 +05:30
Lad Prabhakar
7a3354ac15 docs: platform: Add documentation for Renesas RZ/Five SoC
This patch adds documentation to build Renesas RZ/Five (R9A07G043F) SoC.

Signed-off-by: Lad Prabhakar <prabhakar.mahadev-lad.rj@bp.renesas.com>
Reviewed-by: Anup Patel <anup@brainfault.org>
2022-12-12 18:51:10 +05:30
Lad Prabhakar
8b1617d13a platform: generic: Add Renesas RZ/Five initial support
This commit provides basic support for the Renesas RZ/Five
(R9A07G043F) SoC.

The RZ/Five microprocessor includes a single RISC-V CPU Core (Andes AX45MP)
1.0 GHz, 16-bit DDR3L/DDR4 interface. Supported interfaces include:
- Gigabit Ethernet 2ch
- CAN interface (CAN-FD) 2ch
- USB 2.0 interface 2ch
- SD interface 2ch
- AD converter 2ch

Useful links:
-------------
Links: https://www.renesas.com/us/en/products/microcontrollers-microprocessors/rz-mpus/rzfive-risc-v-general-purpose-microprocessors-risc-v-cpu-core-andes-ax45mp-single-10-ghz-2ch-gigabit-ethernet
Links: http://www.andestech.com/en/products-solutions/andescore-processors/riscv-ax45mp/

Signed-off-by: Lad Prabhakar <prabhakar.mahadev-lad.rj@bp.renesas.com>
Reviewed-by: Anup Patel <anup@brainfault.org>
2022-12-12 18:50:56 +05:30
Lad Prabhakar
684090272a lib: utils/irqchip: Add compatible string for Andestech NCEPLIC100
Add compatible string for Andestech NCEPLIC100 found on Renesas RZ/Five SoC
which is equipped with AX45MP AndesCore.

While at it drop the comma after the sentinel as it does not make sense to
have a comma after a sentinel, as any new elements must be added before the
sentinel.

dts example (Single-core AX45MP):

    soc: soc {
          ....
          plic: interrupt-controller@12c00000 {
              compatible = "renesas,r9a07g043-plic", "andestech,nceplic100";
              #interrupt-cells = <2>;
              #address-cells = <0>;
              riscv,ndev = <511>;
              interrupt-controller;
              reg = <0x0 0x12c00000 0 0x400000>;
              clocks = <&cpg CPG_MOD R9A07G043_NCEPLIC_ACLK>;
              power-domains = <&cpg>;
              resets = <&cpg R9A07G043_NCEPLIC_ARESETN>;
              interrupts-extended = <&cpu0_intc 11 &cpu0_intc 9>;
          };
          ....
    };

Signed-off-by: Lad Prabhakar <prabhakar.mahadev-lad.rj@bp.renesas.com>
Reviewed-by: Anup Patel <anup@brainfault.org>
Reviewed-by: Bin Meng <bmeng@tinylab.org>
2022-12-12 18:50:46 +05:30
Lad Prabhakar
0021b43737 lib: utils: serial: Add FDT driver for Renesas SCIF
Add FDT driver for Renesas SCIF.

    dts example:

    soc: soc {
          ....
            scif0: serial@1004b800 {
                    compatible = "renesas,scif-r9a07g043",
                                 "renesas,scif-r9a07g044";
                    reg = <0 0x1004b800 0 0x400>;
                    interrupts = <412 IRQ_TYPE_LEVEL_HIGH>,
                                 <414 IRQ_TYPE_LEVEL_HIGH>,
                                 <415 IRQ_TYPE_LEVEL_HIGH>,
                                 <413 IRQ_TYPE_LEVEL_HIGH>,
                                 <416 IRQ_TYPE_LEVEL_HIGH>,
                                 <416 IRQ_TYPE_LEVEL_HIGH>;
                    interrupt-names = "eri", "rxi", "txi",
                                      "bri", "dri", "tei";
                    clocks = <&cpg CPG_MOD R9A07G043_SCIF0_CLK_PCK>;
                    clock-names = "fck";
                    power-domains = <&cpg>;
                    resets = <&cpg R9A07G043_SCIF0_RST_SYSTEM_N>;
                    status = "disabled";
            };
          ....
    };

Signed-off-by: Lad Prabhakar <prabhakar.mahadev-lad.rj@bp.renesas.com>
Reviewed-by: Anup Patel <anup@brainfault.org>
2022-12-12 18:50:35 +05:30
Lad Prabhakar
64e8b9f72e lib: utils: serial: Add Renesas SCIF driver
Add Renesas SCIF driver.

Based on a patch in the BSP by Takeki Hamada
<takeki.hamada.ak@bp.renesas.com>
Link: https://github.com/renesas-rz/rz_opensbi/commits/work/OpenSBI-PMA

Signed-off-by: Lad Prabhakar <prabhakar.mahadev-lad.rj@bp.renesas.com>
Reviewed-by: Anup Patel <anup@brainfault.org>
2022-12-12 18:50:26 +05:30
Himanshu Chauhan
506928a1be scripts: use env to invoke bash
Not all systems have bash at a fixed location like /bin/bash.
FreeBSD, for example, would typically have it at /usr/local/bin/bash.
When building OpenSBI on freebsd system, the build breaks.

Its advisable to use: #!/usr/bin/env bash

Signed-off-by: Himanshu Chauhan <hchauhan@ventanamicro.com>
Reviewed-by: Xiang W <wxjstz@126.com>
Reviewed-by: Anup Patel <anup@brainfault.org>
2022-12-10 22:00:27 +05:30
Himanshu Chauhan
cb568b9b29 lib: sbi: Synchronize PMP settings with virtual memory system
As per section 3.7.2 of RISC-V Privileged Specification,
PMP settings must be synchronized with the virtual memory
system after PMP settings have been written.

Signed-off-by: Himanshu Chauhan <hchauhan@ventanamicro.com>
Reviewed-by: Anup Patel <anup@brainfault.org>
2022-12-09 14:17:56 +05:30
Heinrich Schuchardt
7b087781c2 lib: fix irqchip_plic_update_hartid_table
After determining cpu_offset we have to check this value.

Addresses-Coverity-ID: 1529706 ("Logically dead code")
Signed-off-by: Heinrich Schuchardt <heinrich.schuchardt@canonical.com>
Reviewed-by: Xiang W <wxjstz@126.com>
Reviewed-by: Atish Patra <atishp@rivosinc.com>
Reviewed-by: Anup Patel <anup@brainfault.org>
2022-12-09 11:27:28 +05:30
Heinrich Schuchardt
c2be21432c lib: fix __fdt_parse_region()
If fdt_getprop() returns NULL, this indicates an error. In this case lenp
is set to an error code. But even if lenp = 0 we should not continue.

If fdt_getprop() returns a wider value than we expect this is a separate
error condition.

In both cases the device-tree is invalid.

Addresses-Coverity-ID: 1529703 ("Dereference after null check")
Signed-off-by: Heinrich Schuchardt <heinrich.schuchardt@canonical.com>
Reviewed-by: Xiang W <wxjstz@126.com>
Reviewed-by: Anup Patel <anup@brainfault.org>
2022-12-09 11:26:39 +05:30
Heinrich Schuchardt
8b00be6927 lib: fix is_region_valid()
For 'reg->order == __riscv_xlen' the term 'BIT(reg->order)' is undefined.

Addresses-Coverity-ID: 1529706 ("Bad bit shift operation")
Signed-off-by: Heinrich Schuchardt <heinrich.schuchardt@canonical.com>
Reviewed-by: Xiang W <wxjstz@126.com>
Reviewed-by: Anup Patel <anup@brainfault.org>
2022-12-09 11:25:27 +05:30
Lad Prabhakar
ed8b8f5254 platform: generic: Make use of fdt_match_node()
It makes sense to use fdt_match_node() instead of fdt_find_match()
in fw_platform_lookup_special() as we already have the start offset
to search from.

Signed-off-by: Lad Prabhakar <prabhakar.mahadev-lad.rj@bp.renesas.com>
Reviewed-by: Anup Patel <anup@brainfault.org>
2022-12-09 11:13:00 +05:30
Sergey Matyukevich
e1a0cb062a gitignore: add vim swap files
Update .gitignore for vim swap files.

Signed-off-by: Sergey Matyukevich <sergey.matyukevich@syntacore.com>
Reviewed-by: Bin Meng <bmeng@tinylab.org>
Reviewed-by: Xiang W <wxjstz@126.com>
Reviewed-by: Anup Patel <anup@brainfault.org>
2022-12-05 17:57:30 +05:30
Lad Prabhakar
e9775120f5 lib: utils: Add fdt_fixup_node() helper function
Add a helper function fdt_fixup_node() based on the compatible string.
This will avoid code duplication for every new node fixup being added.

Signed-off-by: Lad Prabhakar <prabhakar.mahadev-lad.rj@bp.renesas.com>
Reviewed-by: Bin Meng <bmeng@tinylab.org>
Reviewed-by: Xiang W <wxjstz@126.com>
Reviewed-by: Anup Patel <anup@brainfault.org>
2022-12-05 17:54:45 +05:30
Yu Chien Peter Lin
4640d041d3 scripts/create-binary-archive.sh: remove andes/ae350 build directory
The andes-specific files have been moved to generic platform so we
can drop this line.

Signed-off-by: Yu Chien Peter Lin <peterlin@andestech.com>
Reviewed-by: Bin Meng <bmeng@tinylab.org>
Reviewed-by: Anup Patel <anup@brainfault.org>
2022-12-05 17:33:03 +05:30
Yu Chien Peter Lin
d3fcff77a1 docs: andes-ae350.md: fix watchdog nodename in dts example
The example should use watchdog as nodename instead of wdt.
This is defined in watchdog common schemas:
https://github.com/torvalds/linux/blob/v6.0/Documentation/devicetree/bindings/watchdog/watchdog.yaml#L19

Signed-off-by: Yu Chien Peter Lin <peterlin@andestech.com>
Reviewed-by: Bin Meng <bmeng@tinylab.org>
Reviewed-by: Anup Patel <anup@brainfault.org>
2022-12-05 17:32:16 +05:30
Yu Chien Peter Lin
6cd4b9b223 docs: platform: Update AE350 and generic platform documentation
Update compile option and platform compatible string for AE350 and
add it to the generic platform list.

Signed-off-by: Yu Chien Peter Lin <peterlin@andestech.com>
Reviewed-by: Bin Meng <bmeng@tinylab.org>
Reviewed-by: Anup Patel <anup@brainfault.org>
2022-12-05 17:30:55 +05:30
Yu Chien Peter Lin
a36d455182 platform: generic/andes: Enable generic platform support for AE350
We move andes directory to platform/generic as the necessary fdt
drivers are available, the users can enable the console, timer, ipi,
irqchip and reset devices by adding device tree nodes stated in the
docs/platform/andes-ae350.md.

Signed-off-by: Yu Chien Peter Lin <peterlin@andestech.com>
Reviewed-by: Bin Meng <bmeng@tinylab.org>
Reviewed-by: Anup Patel <anup@brainfault.org>
2022-12-05 17:24:32 +05:30
Dongdong Zhang
cfbabb9ec6 firmware: Minor optimization for relocate
The t3 register stores the address of _load_end. If relocation is not
required, it is unnecessary to calculate the address of _load_end.

This can reduce the operation time of two instructions.

Signed-off-by: Dongdong Zhang <zhangdongdong@eswincomputing.com>
Reviewed-by: Bin Meng <bmeng@tinylab.org>
Reviewed-by: Anup Patel <anup@brainfault.org>
2022-12-05 10:47:38 +05:30
Heinrich Schuchardt
ad2ac29263 lib: fix fdt_parse_aclint_node()
After determining cpu_offset we have to check this variable and not
cpu_intc_offset.

Signed-off-by: Heinrich Schuchardt <heinrich.schuchardt@canonical.com>
Reviewed-by: Xiang W <wxjstz@126.com>
Reviewed-by: Bin Meng <bmeng@tinylab.org>
2022-12-05 10:37:38 +05:30
Heinrich Schuchardt
1f6866e015 lib: simplify fdt_translate_address()
Don't assign a value to offset which is never used.

Signed-off-by: Heinrich Schuchardt <heinrich.schuchardt@canonical.com>
Reviewed-by: Xiang W <wxjstz@126.com>
Reviewed-by: Bin Meng <bmeng@tinylab.org>
2022-12-05 10:36:41 +05:30
Heinrich Schuchardt
5daa0ef087 lib: fix fdt_parse_plicsw_node()
cpu_offset and cpu_intc_offset must be int to detect failed invocations of
fdt_node_offset_by_phandle() or fdt_parent_offset().

After determining cpu_offset we have to check this value and not
cpu_intc_offset.

Signed-off-by: Heinrich Schuchardt <heinrich.schuchardt@canonical.com>
Reviewed-by: Xiang W <wxjstz@126.com>
Reviewed-by: Yu Chien Peter Lin <peterlin@andestech.com>
Reviewed-by: Bin Meng <bmeng@tinylab.org>
2022-12-05 10:35:36 +05:30
Heinrich Schuchardt
e9bc7f1757 lib: fix fdt_parse_plmt_node()
cpu_offset, cpu_intc_offset must be int to discover failed invocations of
fdt_node_offset_by_phandle() or fdt_parent_offset().

After determining cpu_offset we have to check this value and not
cpu_intc_offset.

Signed-off-by: Heinrich Schuchardt <heinrich.schuchardt@canonical.com>
Reviewed-by: Xiang W <wxjstz@126.com>
Reviewed-by: Yu Chien Peter Lin <peterlin@andestech.com>
Reviewed-by: Bin Meng <bmeng@tinylab.org>
2022-12-05 10:33:42 +05:30
Heinrich Schuchardt
cc54184619 lib: simplify fdt_parse_plicsw_node()
We should not check !plicsw_base || !size twice.

Signed-off-by: Heinrich Schuchardt <heinrich.schuchardt@canonical.com>
Reviewed-by: Xiang W <wxjstz@126.com>
Reviewed-by: Yu Chien Peter Lin <peterlin@andestech.com>
Reviewed-by: Bin Meng <bmeng@tinylab.org>
2022-12-05 10:31:01 +05:30
Heinrich Schuchardt
f8eec91de8 lib: simplify fdt_parse_plmt_node()
We should not check !plmt_base || !plmt_size twice.

Signed-off-by: Heinrich Schuchardt <heinrich.schuchardt@canonical.com>
Reviewed-by: Xiang W <wxjstz@126.com>
Reviewed-by: Yu Chien Peter Lin <peterlin@andestech.com>
Reviewed-by: Bin Meng <bmeng@tinylab.org>
2022-12-05 10:10:48 +05:30
Xiang W
fc82e84329 lib: sbi: Fix is_region_valid()
When order is equal to __riscv_xlen, the shift operation will not perform
any operation, which will cause reg->base & (BIT(reg->order) - 1) to always
be 0, and the condition has not been established.

This patch fixes this bug.

Signed-off-by: Xiang W <wxjstz@126.com>
Reviewed-by: Anup Patel <anup@brainfault.org>
2022-12-04 21:52:52 +05:30
Xiang W
74e20293c4 lib: sbi: Simplified mmio match checking
We simplify the mmio flag matching in sbi_domain_check_addr().

Signed-off-by: Xiang W <wxjstz@126.com>
Reviewed-by: Anup Patel <anup@brainfault.org>
2022-12-04 21:16:45 +05:30
Alejandro Cabrera Aldaya
49b0e355e6 Makefile: bugfix for handling platform paths
If the path where this repo is located contains the platform name on
it, the original Makefile replaced its occurrences from the path making
it an invalid path. This commit prevents this behavior replacing only
the last part of the path as intended.

Signed-off-by: Alejandro Cabrera Aldaya <aldaya@gmail.com>
Reviewed-by: Xiang W <wxjstz@126.com>
Reviewed-by: Andrew Jones <ajones@ventanamicro.com>
Reviewed-by: Anup Patel <anup@brainfault.org>
2022-12-04 21:02:33 +05:30
KaDiWa
ba32021683 Makefile: replace echo with printf for compatibility
I don't know why but `echo -n` didn't work for me. macOS supports
the `-n` option but it doesn't work in the makefile. What it does
instead is it literally writes `-n` to the file and then also
leaves a newline at the end.

I'm using GNU Make 4.4 (`gmake` from Homebrew).

Signed-off-by: KaDiWa <kalle.wachsmuth@gmail.com>
Reviewed-by: Andrew Jones <ajones@ventanamicro.com>
Reviewed-by: Anup Patel <anup@brainfault.org>
2022-12-04 20:41:30 +05:30
Xiang W
9a740f5c46 platform: generic/allwinner: Remove ghostly type cast
Corrected the same parameter of writel_relaxed in sun20i_d1_riscv_cfg_init
to be u32 for a while and u64 for a while.

Signed-off-by: Xiang W <wxjstz@126.com>
Reviewed-by: Anup Patel <anup@brainfault.org>
2022-12-04 20:38:46 +05:30
Leizheng Zhang
1b0d71bb9f platform: generic/allwinner: Remove unused header files
Remove "#include <sbi/sbi_console.h>"

Signed-off-by: Leizheng Zhang <zhangleizheng@eswincomputing.com>
Reviewed-by: Bin Meng <bmeng@tinylab.org>
Reviewed-by: Xiang W <wxjstz@126.com>
2022-11-22 11:46:19 +05:30
Leizheng Zhang
8e63716c1c firmware: payloads: Optimize usage of "ALIGN"
Delete the redundant "ALIGN" and adjust the position of "ALIGN"

Signed-off-by: Leizheng Zhang <zhangleizheng@eswincomputing.com>
Reviewed-by: Andrew Jones <ajones@ventanamicro.com>
Reviewed-by: Atish Patra <atishp@rivosinc.com>
Reviewed-by: Bin Meng <bmeng@tinylab.org>
2022-11-22 11:20:11 +05:30
Vivian Wang
14f5c4cb4d lib: sbi_ecall: Split up sbi_ecall_replace
Split up sbi_ecall_replace so that each extension is in its individual
file.

Also reorganize the corresponding section in lib/sbi/objects.mk so
that it is grouped by extension, now that the object file targets are
split up.

Signed-off-by: Vivian Wang <dramforever@live.com>
Reviewed-by: Anup Patel <anup@brainfault.org>
2022-11-15 16:44:03 +05:30
Anup Patel
7b29264f11 lib: utils/serial: Fix semihosting compile error using LLVM
We fix the following semihosting compile error observed using LLVM:
lib/utils/serial/semihosting.c:158:12: error: result of comparison of constant -1 with expression of type 'char' is always true [-Werror,-Wtautological-constant-out-of-range-compare]
                ret = ch > -1 ? ch : -1;
                      ~~ ^ ~~

Fixes: 7f09fba86e ("lib: utils/serial: add semihosting support")
Signed-off-by: Anup Patel <apatel@ventanamicro.com>
Reviewed-by: Xiang W <wxjstz@126.com>
Reviewed-by: Bin Meng <bmeng@tinylab.org>
2022-11-15 16:38:41 +05:30
zhangdongdong
8e9966c1a7 docs: fix some typos
Corrected the typos of some documents in the 'docs' folder.

Signed-off-by: zhangdongdong <zhangdongdong@eswincomputing.com>
Reviewed-by: Anup Patel <anup@brainfault.org>
2022-11-14 22:21:31 +05:30
Xiang W
21ba418f1a lib: utils/fdt: Simplified code
Simplified fdt_parse_xxx_uart_node which direct call
fdt_parse_uart_node_common.

Signed-off-by: Xiang W <wxjstz@126.com>
Reviewed-by: Atish Patra <atishp@rivosinc.com>
Reviewed-by: Anup Patel <anup@brainfault.org>
2022-11-14 22:07:36 +05:30
Xiang W
85cf56c159 lib: utils/fdt: Remove redundant code
uart->reg_offset and uart->reg_io_width are only used on uart8250 and
not required on other platforms. Remove for sifive and gaisler.

Signed-off-by: Xiang W <wxjstz@126.com>
Reviewed-by: Atish Patra <atishp@rivosinc.com>
Reviewed-by: Anup Patel <anup@brainfault.org>
2022-11-14 22:02:33 +05:30
Vivian Wang
22f38ee6c6 lib: sbi_ecall: Add Kconfig option for each extension
For each SBI extension, we:

- Add a Kconfig option for it
- Add the extension to sbi_ecall_exts only if the extension is enabled
- Add the corresponding sbi_ecall_* object file only if the extension is
  enabled

Special cases are as follows:

- The legacy extensions are lumped together as one 'big' extension, as
  has always been the case in OpenSBI code.
- The platform-defined vendor extensions are regarded as one extension.
- The Base extension cannot be disabled.
- sbi_ecall_replace implements multiple extensions, so it's not easy to
  avoid linking it in. Enable it always, and use #ifdef to
  disable/enable individual extensions.

Signed-off-by: Vivian Wang <dramforever@live.com>
Reviewed-by: Andrew Jones <ajones@ventanamicro.com>
Reviewed-by: Anup Patel <anup@brainfault.org>
2022-10-23 11:01:33 +05:30
Vivian Wang
56bed1a0fe lib: sbi_ecall: Generate extensions list with carray
Instead of hard-coding the list of extensions in C code, use carray to
generate the list of extensions.

Using carray makes adding and removing extensions slightly cleaner. This
also paves the way for using Kconfig to disable unneeded extensions.

Signed-off-by: Vivian Wang <dramforever@live.com>
Reviewed-by: Andrew Jones <ajones@ventanamicro.com>
Reviewed-by: Anup Patel <anup@brainfault.org>
2022-10-23 11:00:30 +05:30
Vivian Wang
9d54f431e8 Makefile: Add rules for carray sources in lib/sbi
Add back the missing rules needed to build carray files in lib/sbi. This
allows future usage of carray in lib/sbi.

Fixes: de80e9337d ("Makefile: Compile lib/utils sources separately for each platform")
Signed-off-by: Vivian Wang <dramforever@live.com>
Reviewed-by: Andrew Jones <ajones@ventanamicro.com>
Reviewed-by: Anup Patel <anup@brainfault.org>
2022-10-23 10:59:26 +05:30
Yangjie Zhang
51acd4956a docs/firmware: update the document
Since
commit 9c07c513aa ("firmware:Remove FW_PAYLOAD_FDT_PATH compile-time option"),
the section where FDT would be embedded in has changed from *.text* to *.rodata*,
but some places in fw_payload.md and fw.md are still *.text*.
This patch updates the document.

Signed-off-by: Yangjie Zhang <pyjmstr@gmail.com>
Reviewed-by: Bin Meng <bmeng.cn@gmail.com>
Reviewed-by: Anup Patel <anup@brainfault.org>
2022-10-23 10:49:39 +05:30
Tan En De
0fee0bf826 Makefile: Add cscope support
Add cscope support so that running `make cscope` will generate/update
cscope files used for source code browsing, while running `make
distclean` will remove the cscope files.

Also add entry in .gitignore to ignore generated cscope files.

Signed-off-by: Tan En De <ende.tan@linux.starfivetech.com>
Reviewed-by: Xiang W <wxjstz@126.com>
Reviewed-by: Anup Patel <anup@brainfault.org>
Reviewed-by: Andrew Jones <ajones@ventanamicro.com>
2022-10-23 10:47:40 +05:30
Yu Chien Peter Lin
d682a0afa1 docs: andes-ae350.md: Update ae350 documentation for fdt driver support
We update ae350 documentation to add details about platform device tree.
The nodes and their properties must be provided to properly initialize
data of underlying hardware and access their mmio registers.

Signed-off-by: Yu Chien Peter Lin <peterlin@andestech.com>
Reviewed-by: Anup Patel <anup@brainfault.org>
2022-10-23 10:35:45 +05:30
Yu Chien Peter Lin
c8683c57f6 platform: andes/ae350: Add AE350 domain support
Add domains_init platform hook for Andes AE350, users can add domain
description in device tree and select FDT domain support in Kconfig
to achieve system-level partitioning.

Signed-off-by: Yu Chien Peter Lin <peterlin@andestech.com>
Reviewed-by: Leo Yu-Chi Liang <ycliang@andestech.com>
Reviewed-by: Anup Patel <anup@brainfault.org>
2022-10-23 10:35:00 +05:30
Yu Chien Peter Lin
ce7c490719 lib: utils/ipi: Add Andes fdt ipi driver support
Move Andes PLICSW ipi device to fdt ipi framework, this patch is based
on Leo's modified IPI scheme on PLICSW.

Current IPI scheme uses bit 0 of pending reigster on PLICSW to send IPI
from hart 0 to hart 7, but bit 0 needs to be hardwired to 0 according
to spec. After some investigation, self-IPI seems to be seldom or never
used, so we re-order the IPI scheme to support 8 core platforms.

dts example (Quad-core AX45MP):

  plicsw: interrupt-controller@e6400000 {
          compatible = "andestech,plicsw";
          reg = <0x00000000 0xe6400000 0x00000000 0x00400000>;
          interrupts-extended = <&CPU0_intc 3
                                 &CPU1_intc 3
                                 &CPU2_intc 3
                                 &CPU3_intc 3>;
          interrupt-controller;
          #address-cells = <2>;
          #interrupt-cells = <2>;
  };

Signed-off-by: Yu Chien Peter Lin <peterlin@andestech.com>
Reviewed-by: Anup Patel <anup@brainfault.org>
2022-10-23 10:31:01 +05:30
Yu Chien Peter Lin
6f3258e671 platform: andes/ae350: Add fw_platform_init for platform initialization
This patch adds fw_platform_init() to initialize ae350 platform.name
and platform.hart_count by parsing device tree.

Signed-off-by: Yu Chien Peter Lin <peterlin@andestech.com>
Reviewed-by: Leo Yu-Chi Liang <ycliang@andestech.com>
Reviewed-by: Anup Patel <anup@brainfault.org>
2022-10-23 10:30:21 +05:30
Yu Chien Peter Lin
127a3f2ab4 platform: andes/ae350: Use fdt irqchip driver
Andes PLIC is compatible with plic driver. The PLIC base address and
number of source can be obtained by parsing the device tree.

Signed-off-by: Yu Chien Peter Lin <peterlin@andestech.com>
Reviewed-by: Leo Yu-Chi Liang <ycliang@andestech.com>
Reviewed-by: Anup Patel <anup@brainfault.org>
2022-10-23 10:29:58 +05:30
Yu Chien Peter Lin
8234fc1bdf lib: utils/reset: Add Andes fdt reset driver support
Add ATCWDT200 as reset device of AE350 platform, this driver requires
SMU to program the reset vector registers before triggering WDT software
restart signal.

dts example:

  smu@f0100000 {
    compatible = "andestech,atcsmu";
    reg = <0x00000000 0xf0100000 0x00000000 0x00001000>;
  };

  wdt: wdt@f0500000 {
    compatible = "andestech,atcwdt200";
    reg = <0x00000000 0xf0500000 0x00000000 0x00001000>;
    interrupts = <3 4>;
    interrupt-parent = <&plic0>;
    clock-frequency = <15000000>;
  };

Signed-off-by: Yu Chien Peter Lin <peterlin@andestech.com>
Reviewed-by: Leo Yu-Chi Liang <ycliang@andestech.com>
Reviewed-by: Anup Patel <anup@brainfault.org>
2022-10-23 10:29:23 +05:30
Yu Chien Peter Lin
ef9f02e7fb lib: utils/timer: Add Andes fdt timer support
Since we can get the PLMT base address and timer frequency from
device tree, move plmt timer device to fdt timer framework.

dts example (Quad-core AX45MP):

  cpus {
      ...
      timebase-frequency = <0x3938700>;
      ...
  }
  soc {
      ...
      plmt0@e6000000 {
          compatible = "andestech,plmt0";
          reg = <0x00 0xe6000000 0x00 0x100000>;
          interrupts-extended = <&cpu0_intc 0x07
                                 &cpu1_intc 0x07
                                 &cpu2_intc 0x07
                                 &cpu3_intc 0x07>;
      };
      ...
  }

Signed-off-by: Yu Chien Peter Lin <peterlin@andestech.com>
Reviewed-by: Anup Patel <anup@brainfault.org>
2022-10-23 10:26:39 +05:30
Yu Chien Peter Lin
88f58a3694 platform: andes/ae350: Use fdt serial driver
Andes UART is compatible with uart8250 driver. We can use
fdt_serial_init() as platform console init hook.

dts example:

  serial0: serial@f0300000 {
    compatible = "andestech,uart16550", "ns16550a";
    reg = <0x00000000 0xf0300000 0x00000000 0x00001000>;
    interrupts = <9 4>;
    interrupt-parent = <&plic0>;
    clock-frequency = <19660800>;
    current-speed = <38400>;
    reg-shift = <2>;
    reg-offset = <32>;
    reg-io-width = <4>;
    no-loopback-test = <1>;
  };

Signed-off-by: Yu Chien Peter Lin <peterlin@andestech.com>
Reviewed-by: Anup Patel <anup@brainfault.org>
2022-10-23 10:26:06 +05:30
Yu Chien Peter Lin
9899b59beb platform: andes/ae350: Use kconfig to set platform version and default name
This patch makes andes platform name and version can be set in
menuconfig interface.

Signed-off-by: Yu Chien Peter Lin <peterlin@andestech.com>
Reviewed-by: Leo Yu-Chi Liang <ycliang@andestech.com>
Reviewed-by: Anup Patel <anup@brainfault.org>
2022-10-23 10:25:13 +05:30
Yu Chien Peter Lin
bd7ef41398 platform: andes/ae350: Remove enabling cache from an350_final_init
The boot-time cache operations have been handled by U-boot SPL, so we
can drop duplicate code.

Signed-off-by: Yu Chien Peter Lin <peterlin@andestech.com>
Reviewed-by: Leo Yu-Chi Liang <ycliang@andestech.com>
Reviewed-by: Anup Patel <anup@brainfault.org>
2022-10-23 10:23:13 +05:30
Yu Chien Peter Lin
dcdaf30274 lib: sbi: Add sbi_domain_root_add_memrange() API
This patch generalizes the logic to add a memory range with desired
alignment and flags of consecutive regions to the root domain.

Signed-off-by: Yu Chien Peter Lin <peterlin@andestech.com>
Reviewed-by: Anup Patel <anup@brainfault.org>
2022-10-23 10:21:21 +05:30
Yu Chien Peter Lin
60b78fee92 include: sbi: Fix grammar in comment
Fix minor grammar issue in function description.

Signed-off-by: Yu Chien Peter Lin <peterlin@andestech.com>
Reviewed-by: Anup Patel <anup@brainfault.org>
2022-10-23 10:20:04 +05:30
Yu Chien Peter Lin
11d14ae7f2 lib: sbi: Fix typo in comment
%s/is is/is

Signed-off-by: Yu Chien Peter Lin <peterlin@andestech.com>
Reviewed-by: Anup Patel <anup@brainfault.org>
2022-10-23 10:19:28 +05:30
Yu Chien Peter Lin
98aa12738d include: sbi: Fix typo in comment
%s/Priviledge/Privilege

Signed-off-by: Yu Chien Peter Lin <peterlin@andestech.com>
Reviewed-by: Anup Patel <anup@brainfault.org>
2022-10-23 10:17:22 +05:30
Heiko Stuebner
b6e520b2a8 platform: generic: allwinner: add support for c9xx pmu
With the T-HEAD C9XX cores being designed before or during ratification
of the SSCOFPMF extension, they implement a PMU extension that behaves
very similar but not equal to it by providing overflow interrupts though
in a slightly different registers format.

The sun20i-d1 is using this core. So implement the necessary overrides
to allow its pmu to be used via the standard sbi-pmu extension.

For now it's also the only soc using this core, so keep the additional
code in the d1-space for now.

Reviewed-by: Andrew Jones <ajones@ventanamicro.com>
Reviewed-by: Guo Ren <guoren@kernel.org>
Reviewed-by: Anup Patel <anup@brainfault.org>
Signed-off-by: Heiko Stuebner <heiko@sntech.de>
2022-10-13 09:52:09 +05:30
Heiko Stuebner
2f63f2465c platform: generic: add extensions_init handler and platform-override
Init of non-standard extensions is a platform-specific thing,
so allow generic platforms to do this via a platform-override.

Reviewed-by: Andrew Jones <ajones@ventanamicro.com>
Reviewed-by: Guo Ren <guoren@kernel.org>
Reviewed-by: Anup Patel <anup@brainfault.org>
Signed-off-by: Heiko Stuebner <heiko@sntech.de>
2022-10-13 09:52:06 +05:30
Heiko Stuebner
4f2acb53e2 lib: sbi_platform: expose hart_features to extension_init callback
The platform-specific extension_init callback is supposed to
set specific things for the platform opensbi is running on.

So it's also the right place to override specific hart_features
if needed - when it's know that autodetection has provided
wrong results for example.

Suggested-by: Atish Patra <atishp@atishpatra.org>
Reviewed-by: Andrew Jones <ajones@ventanamicro.com>
Reviewed-by: Guo Ren <guoren@kernel.org>
Reviewed-by: Anup Patel <anup@brainfault.org>
Signed-off-by: Heiko Stuebner <heiko@sntech.de>
2022-10-13 09:52:05 +05:30
Heiko Stuebner
c316fa38c2 lib: sbi_hart: move hart_features struct to a public location
Platforms may need to override auto-detected hart features
in their override functions. So move the hart_features
struct to the sbi_hart.h header allowing us to pass it over
to platform-handlers.

Suggested-by: Atish Patra <atishp@atishpatra.org>
Reviewed-by: Andrew Jones <ajones@ventanamicro.com>
Reviewed-by: Guo Ren <guoren@kernel.org>
Reviewed-by: Anup Patel <anup@brainfault.org>
Signed-off-by: Heiko Stuebner <heiko@sntech.de>
2022-10-13 09:52:03 +05:30
Heiko Stuebner
e54cb3298b lib: sbi_pmu: move pmu irq information into pmu itself
Don't spread checking for pmu extensions through the code
but instead introduce a sbi-pmu function that other code can
call to get the correct information about the existence of the
pmu interrupt.

Add a sbi_pmu_device override function to allow overridung this
bit as well if needed.

Reviewed-by: Atish Patra <atishp@rivosinc.com>
Reviewed-by: Andrew Jones <ajones@ventanamicro.com>
Reviewed-by: Guo Ren <guoren@kernel.org>
Reviewed-by: Anup Patel <anup@brainfault.org>
Signed-off-by: Heiko Stuebner <heiko@sntech.de>
2022-10-13 09:52:01 +05:30
zhangdongdong
3f3d401d2d docs: Fix some typos
We fix few typos in documentation.

Signed-off-by: zhangdongdong <zhangdongdong@eswincomputing.com>
Reviewed-by: Andrew Jones <ajones@ventanamicro.com>
Reviewed-by: Xiang W <wxjstz@126.com>
Reviewed-by: Anup Patel <anup@brainfault.org>
2022-10-13 09:28:54 +05:30
Nylon.Chen
7105c189f6 docs/firmware: Update FW_JUMP documentation
Add a tip for OpenSBI's FW_JUMP which helps
users avoid overwriting the kernel.

Signed-off-by: Nylon Chen <nylon.chen@sifive.com>
Reviewed-by: Andrew Jones <ajones@ventanamicro.com>
Reviewed-by: Anup Patel <anup@brainfault.org>
2022-10-13 09:25:15 +05:30
Kautuk Consul
7f09fba86e lib: utils/serial: add semihosting support
We add RISC-V semihosting based serial console for JTAG based early
debugging.

The RISC-V semihosting specification is available at:
https://github.com/riscv/riscv-semihosting-spec/blob/main/riscv-semihosting-spec.adoc

Signed-off-by: Anup Patel <apatel@ventanamicro.com>
Signed-off-by: Kautuk Consul <kconsul@ventanamicro.com>
Reviewed-by: Anup Patel <anup@brainfault.org>
2022-09-13 18:24:42 +05:30
Rahul Pathak
49372f2691 lib: sbi: Fix sbi_strnlen wrong count decrement
count(maxlen) should not be decremented here

Fixes: 1901e8a287 ("platform: Add minimal libc support.")
Signed-off-by: Rahul Pathak <rpathak@ventanamicro.com>
Reviewed-by: Anup Patel <anup@brainfault.org>
2022-09-13 17:17:10 +05:30
Anup Patel
8ce486a781 lib: utils/fdt: Fix DT parsing in fdt_pmu_setup()
This patch does following fixes in fdt_pmu_setup():
1) If any of the event mapping DT property is absent or too small
   then don't skip parsing of other DT properties.
2) Return failure if sbi_pmu_add_hw_event_counter_map() fails.
3) Return failure if sbi_pmu_add_raw_event_counter_map() fails.

Signed-off-by: Anup Patel <apatel@ventanamicro.com>
Reviewed-by: Andrew Jones <ajones@ventanamicro.com>
Reviewed-by: Atish Patra <atishp@rivosinc.com>
2022-09-13 17:15:58 +05:30
Vivian Wang
46e744ab67 lib: sbi_misaligned_ldst: Set GVA if not emulating
If a particular misaligned load or store cannot be emulated at all, for
the redirected trap, trap.gva is set to 0, but it should be the same as
mstatus[h].GVA of the original trap. Fix this so that if the trap is
destined for HS-mode, hstatus.GVA is then set correctly.

Fixes: 1c4ce74f51 ("lib: sbi: Set gva when creating sbi_trap_info")
Signed-off-by: Vivian Wang <dramforever@live.com>
Reviewed-by: Andrew Jones <ajones@ventanamicro.com>
Reviewed-by: Anup Patel <anup@brainfault.org>
2022-09-13 16:43:07 +05:30
Vivian Wang
37a0d83b6d lib: sbi_trap: Add helper to get GVA in sbi_trap_regs
The GVA bit is in mstatus on RV64, and in mstatush in RV32. Refactor
code handling this in sbi_trap_handler into a helper function to extract
GVA from sbi_trap_regs, so that future code accessing GVA can be
XLEN-agnostic.

Signed-off-by: Vivian Wang <dramforever@live.com>
Reviewed-by: Andrew Jones <ajones@ventanamicro.com>
Reviewed-by: Anup Patel <anup@brainfault.org>
2022-09-13 16:42:59 +05:30
Nikita Shubin
19664f6757 docs: pmu: extend bindings example for Unmatched
Extend example for Unmatched board to provide SBI PMU bindings
for generalized and cache event's where they are applicable.

Signed-off-by: Nikita Shubin <n.shubin@yadro.com>
Reviewed-by: Anup Patel <anup@brainfault.org>
2022-09-13 16:42:10 +05:30
Nikita Shubin
d32b0a92db docs: pmu: fix Unmatched example typo
bitmap for MHPMCOUNTERx should be 0x18 and not 0x0c, we check
against SBI_PMU_FIXED_CTR_MASK which assumes than first 3 bits are
dedicated to mcycle, mtime and minstret, u74 has 2 hardware counters.

Reported-by: Zhang Xin <zhangxin.xa@gmail.com>
Signed-off-by: Nikita Shubin <n.shubin@yadro.com>
Reviewed-by: Anup Patel <anup@brainfault.org>
2022-09-13 16:42:03 +05:30
Anup Patel
5019fd124b include: sbi: Reduce includes in sbi_pmu.h
The sbi_pmu.h should only include minimal required headers whereas
sbi_pmu.c should include all required headers.

Signed-off-by: Anup Patel <apatel@ventanamicro.com>
Reviewed-by: Andrew Jones <ajones@ventanamicro.com>
Reviewed-by: Atish Patra <atishp@rivosinc.com>
2022-09-01 16:53:28 +05:30
Anup Patel
ee69f8eeb3 lib: sbi: Print platform PMU device at boot-time
Let us print the platform PMU device name at the boot-time so that users
know whether the underlying platform has custom per-HART PMU operations.

Signed-off-by: Anup Patel <apatel@ventanamicro.com>
Reviewed-by: Andrew Jones <ajones@ventanamicro.com>
Reviewed-by: Atish Patra <atishp@rivosinc.com>
2022-09-01 16:53:25 +05:30
Anup Patel
d10c1f4acd lib: sbi_pmu: Add custom PMU device operations
We extend SBI PMU implementation to allow custom PMU device operations
which a platform can use for platform specific quirks.

The custom PMU device operations added by this patch include:
1) Operations to allow a platform implement custom firmware events.
   These custom firmware events can be SBI vendor extension related
   events or platform specific per-HART events are not possible to
   count through HPM CSRs.
2) Operations to allow a platform implement custom way for enabling
   (or disabling) an overflow interrupt (e.g. T-Head C9xx).

Signed-off-by: Anup Patel <apatel@ventanamicro.com>
Reviewed-by: Andrew Jones <ajones@ventanamicro.com>
Reviewed-by: Atish Patra <atishp@rivosinc.com>
2022-09-01 16:53:22 +05:30
Anup Patel
c9b388d578 lib: sbi_pmu: Simplify FW counters to reduce memory usage
Currently, we have 32 elements (i.e. SBI_PMU_FW_EVENT_MAX) array of
"struct sbi_pmu_fw_event" for each of 128 possible HARTs
(i.e. SBI_HARTMASK_MAX_BITS).

To reduce memory usage of OpenSBI, we update FW counter implementation
as follows:
1) Remove SBI_PMU_FW_EVENT_MAX
2) Remove "struct sbi_pmu_fw_event"
3) Create per-HART bitmap of XLEN bits to track FW counters
   which are started on each HART
4) Create per-HART uint64_t array to track values of FW
   counters on each HART.

Signed-off-by: Anup Patel <apatel@ventanamicro.com>
Reviewed-by: Andrew Jones <ajones@ventanamicro.com>
Reviewed-by: Atish Patra <atishp@rivosinc.com>
2022-09-01 16:53:20 +05:30
Anup Patel
e238459fab lib: sbi_pmu: Firmware counters are always 64 bits wide
As-per SBI specification, all firmware counters are always 64 bits
wide so let us update the SBI PMU implementation to reflect this fact.

Signed-off-by: Anup Patel <apatel@ventanamicro.com>
Reviewed-by: Andrew Jones <ajones@ventanamicro.com>
Reviewed-by: Atish Patra <atishp@rivosinc.com>
2022-09-01 16:53:18 +05:30
Anup Patel
1664d0efce lib: sbi_pmu: Replace sbi_pmu_ctr_read() with sbi_pmu_ctr_fw_read()
The "read a firmware counter" SBI call should only work for firmware
counters so let us replace sbi_pmu_ctr_read() with sbi_pmu_ctr_fw_read()
which works only on firmware counters.

Signed-off-by: Anup Patel <apatel@ventanamicro.com>
Reviewed-by: Andrew Jones <ajones@ventanamicro.com>
Reviewed-by: Atish Patra <atishp@rivosinc.com>
2022-09-01 16:53:16 +05:30
Anup Patel
a90cf6b186 lib: sbi_pmu: Remove "event_idx" member from struct sbi_pmu_fw_event
The "event_idx" member of struct sbi_pmu_fw_event is not used
anywhere so let us remove it.

Signed-off-by: Anup Patel <apatel@ventanamicro.com>
Reviewed-by: Andrew Jones <ajones@ventanamicro.com>
Reviewed-by: Atish Patra <atishp@rivosinc.com>
2022-09-01 16:53:14 +05:30
Rahul Pathak
622cc5f014 include: Remove sideleg and sedeleg
sideleg and sedeleg csrs are not part of riscv isa spec
anymore, these csrs were part of N extension which
is removed from the riscv isa specification.

These commits removed all traces of these csrs from
riscv spec (https://github.com/riscv/riscv-isa-manual) -

commit f8d27f805b65 ("Remove or downgrade more references to N extension (#674)")
commit b6cade07034d ("Remove N extension chapter for now")

Signed-off-by: Rahul Pathak <rpathak@ventanamicro.com>
Reviewed-by: Andrew Jones <ajones@ventanamicro.com>
Reviewed-by: Anup Patel <anup@brainfault.org>
2022-09-01 15:37:22 +05:30
Jun Liang Tan
cbaa9b0333 lib: utils: serial: Add Cadence UART driver
Add Cadence UART driver

Signed-off-by: Jun Liang Tan <junliang.tan@linux.starfivetech.com>
Signed-off-by: Wei Liang Lim <weiliang.lim@linux.starfivetech.com>
Reviewed-by: Andrew Jones <ajones@ventanamicro.com>
Reviewed-by: Anup Patel <anup@brainfault.org>
2022-08-23 08:40:17 +05:30
Anup Patel
adf44b51ba lib: sbi: Use the official extension name for AIA M-mode CSRs
The arch review of AIA spec is completed and we now have official
extension names for AIA: Smaia (M-mode AIA CSRs) and Ssaia (S-mode
AIA CSRs).

Refer, section 1.6 of the latest AIA v0.3.1 stable specification at
https://github.com/riscv/riscv-aia/releases/download/0.3.1-draft.32/riscv-interrupts-032.pdf)

Based on above, we update generic library to use "Smaia" extension
name for AIA M-mode CSRs.

Signed-off-by: Anup Patel <apatel@ventanamicro.com>
Reviewed-by: Andrew Jones <ajones@ventanamicro.com>
Reviewed-by: Atish Patra <atishp@rivosinc.com>
2022-08-22 09:01:33 +05:30
Rahul Pathak
111afc1230 lib: sbi_illegal_insn: Fix FENCE.TSO emulation infinite trap loop
In case of missing "FENCE.TSO" instruction implementation,
opensbi can emulate the "FENCE.TSO" with "FENCE RW,RW", but
mepc was not incremented to continue from the next instruction
causing infinite trap.

Fixes: cb8271c8 ("lib: sbi_illegal_insn: Add emulation for fence.tso")
Signed-off-by: Rahul Pathak <rpathak@ventanamicro.com>
Reviewed-by: Andrew Jones <ajones@ventanamicro.com>
Reviewed-by: Xiang W <wxjstz@126.com>
Reviewed-by: Samuel Holland <samuel@sholland.org>
2022-08-22 08:57:23 +05:30
Vivian Wang
a69eb6cc65 lib: sbi_trap: Set hstatus.GVA when going to HS-mode
The privileged spec specifies that on a trap to HS-mode, hstatus.GVA
should be set to 1 if stval is written with a guest virtual address, and
to 0 otherwise. Implement this by setting hstatus.GVA to trap->gva when
redirecting traps to HS-mode.

Signed-off-by: Vivian Wang <dramforever@live.com>
Reviewed-by: Andrew Jones <ajones@ventanamicro.com>
Reviewed-by: Anup Patel <anup@brainfault.org>
2022-08-22 08:50:23 +05:30
Vivian Wang
5a0ca098f1 lib: sbi_trap: Set hypervisor CSRs for HS-mode
The hypervisor CSRs hstatus, htval, htinst should always be set if the
trap is to be taken in HS-mode, regardless of which mode it came from.

Signed-off-by: Vivian Wang <dramforever@live.com>
Reviewed-by: Andrew Jones <ajones@ventanamicro.com>
Reviewed-by: Anup Patel <anup@brainfault.org>
2022-08-22 08:50:04 +05:30
Vivian Wang
1c4ce74f51 lib: sbi: Set gva when creating sbi_trap_info
In some cases the sbi_trap_info argument passed to sbi_trap_redirect is
created from scratch by filling its fields. Since we previously added a
gva field to struct sbi_trap_info, initialize gva in these cases also.

Suggested-by: Andrew Jones <ajones@ventanamicro.com>
Signed-off-by: Vivian Wang <dramforever@live.com>
Reviewed-by: Andrew Jones <ajones@ventanamicro.com>
Reviewed-by: Anup Patel <anup@brainfault.org>
2022-08-22 08:49:49 +05:30
Vivian Wang
1fbe7778c9 lib: sbi_trap: Save mstatus[h].GVA in trap->gva
The machine mode GVA field is available if the hypervisor extension is
implemented, and indicates if mtval is a guest virtual address. Add a
gva field to sbi_trap_info for this, and in __sbi_expected_trap_hext,
save mstatus[h].GVA to it, so that gva indicates if tval is a guest
virtual address. If the hypervisor extension is not implemented, always
set gva to 0.

Signed-off-by: Vivian Wang <dramforever@live.com>
Reviewed-by: Andrew Jones <ajones@ventanamicro.com>
Reviewed-by: Anup Patel <anup@brainfault.org>
2022-08-22 08:49:39 +05:30
Vivian Wang
9529e360df include: Add mstatus[h].GVA encodings
The machine mode GVA field is in mstatus for RV64 and mstatush for RV32,
and is available if the hypervisor extension is available. If an
exception occurs, we may need to redirect the trap to HS-mode, in which
case, hstatus.GVA should be set to same as the machine mode GVA bit.

Add MSTATUS_GVA for RV64, MSTATUSH_GVA for RV32, and their SHIFT
encodings. The SHIFT index is helpful in assembly code, since field
extraction can be implemented in only one register. In pseudocode:

- For RV32: gva = (mstatus >> MSTATUS_GVA_SHIFT) & 1;
- For RV64: gva = (mstatush >> MSTATUSH_GVA_SHIFT) & 1;

Signed-off-by: Vivian Wang <dramforever@live.com>
Reviewed-by: Andrew Jones <ajones@ventanamicro.com>
Reviewed-by: Anup Patel <anup@brainfault.org>
2022-08-22 08:49:29 +05:30
Anup Patel
a6a85579b6 Makefile: Fix typo related to object.mk
The "object.mk" name referred in top-level makefile should be
"objects.mk".

Signed-off-by: Anup Patel <apatel@ventanamicro.com>
Reviewed-by: Andrew Jones <ajones@ventanamicro.com>
Tested-by: Andrew Jones <ajones@ventanamicro.com>
Acked-by: Atish Patra <atishp@rivosinc.com>
Tested-by: Atish Patra <atishp@rivosinc.com>
2022-08-08 09:34:43 +05:30
Anup Patel
0723bab8fe docs: Update documentation for kconfig support
We update all documentation files to:
1) Remove references to platform specific config.mk file since it is
   has been removed.
2) Add details about platform specific configs/defconfig and Kconfig
   files mandatory for each platform.
3) Add required packages in top-level README.md
4) Fix typo releated to object.mk in docs/platform/platform.md

Signed-off-by: Anup Patel <apatel@ventanamicro.com>
Reviewed-by: Andrew Jones <ajones@ventanamicro.com>
Tested-by: Andrew Jones <ajones@ventanamicro.com>
Acked-by: Atish Patra <atishp@rivosinc.com>
Tested-by: Atish Patra <atishp@rivosinc.com>
2022-08-08 09:34:31 +05:30
Anup Patel
eccb9df5cf platform: Remove redundant config.mk from all platforms
The options defined in config.mk can be specified in objects.mk of each
platform so let us remove config.mk from all platforms.

Signed-off-by: Anup Patel <apatel@ventanamicro.com>
Tested-by: Andrew Jones <ajones@ventanamicro.com>
Acked-by: Atish Patra <atishp@rivosinc.com>
Tested-by: Atish Patra <atishp@rivosinc.com>
2022-08-08 09:34:25 +05:30
Anup Patel
bc317a378f platform: generic: Use kconfig to set platform version and default name
The generic platform version and default name should be set based
on kconfig options so that users can override it.

Signed-off-by: Anup Patel <apatel@ventanamicro.com>
Reviewed-by: Andrew Jones <ajones@ventanamicro.com>
Tested-by: Andrew Jones <ajones@ventanamicro.com>
Acked-by: Atish Patra <atishp@rivosinc.com>
Tested-by: Atish Patra <atishp@rivosinc.com>
2022-08-08 09:34:20 +05:30
Anup Patel
d514a8f0dc platform: generic: Use kconfig for enabling/disabling overrides
We update generic platform to use kconfig for enabling/disabling
platform overrides. We also enable all platform overrides in generic
platform defconfig.

Signed-off-by: Anup Patel <apatel@ventanamicro.com>
Tested-by: Andrew Jones <ajones@ventanamicro.com>
Acked-by: Atish Patra <atishp@rivosinc.com>
Tested-by: Atish Patra <atishp@rivosinc.com>
2022-08-08 09:34:14 +05:30
Anup Patel
68d7b85ec7 lib: utils/fdt: Use kconfig for enabling/disabling
We update FDT support makefile to use kconfig for enabling/disabling.
To avoid compilation errors, we also enable FDT for each platform.

Signed-off-by: Anup Patel <apatel@ventanamicro.com>
Tested-by: Andrew Jones <ajones@ventanamicro.com>
Acked-by: Atish Patra <atishp@rivosinc.com>
Tested-by: Atish Patra <atishp@rivosinc.com>
2022-08-08 09:34:08 +05:30
Anup Patel
5616aa4f4a lib: utils/gpio: Use kconfig for enabling/disabling drivers
We update gpio drivers makefile to use kconfig for enabling/disabling
drivers. To avoid compile errors, we also enable appropriate gpio
drivers for each platform.

Signed-off-by: Anup Patel <apatel@ventanamicro.com>
Tested-by: Andrew Jones <ajones@ventanamicro.com>
Acked-by: Atish Patra <atishp@rivosinc.com>
Tested-by: Atish Patra <atishp@rivosinc.com>
2022-08-08 09:34:02 +05:30
Anup Patel
b126ce4a8f lib: utils/i2c: Use kconfig for enabling/disabling drivers
We update i2c drivers makefile to use kconfig for enabling/disabling
drivers. To avoid compile errors, we also enable appropriate i2c
drivers for each platform.

Signed-off-by: Anup Patel <apatel@ventanamicro.com>
Tested-by: Andrew Jones <ajones@ventanamicro.com>
Acked-by: Atish Patra <atishp@rivosinc.com>
Tested-by: Atish Patra <atishp@rivosinc.com>
2022-08-08 09:33:57 +05:30
Anup Patel
0b1cf2f645 lib: utils/irqchip: Use kconfig for enabling/disabling drivers
We update irqchip drivers makefile to use kconfig for enabling/disabling
drivers. To avoid compile errors, we also enable appropriate irqchip
drivers for each platform.

Signed-off-by: Anup Patel <apatel@ventanamicro.com>
Tested-by: Andrew Jones <ajones@ventanamicro.com>
Acked-by: Atish Patra <atishp@rivosinc.com>
Tested-by: Atish Patra <atishp@rivosinc.com>
2022-08-08 09:33:52 +05:30
Anup Patel
76af9d40da lib: utils/ipi: Use kconfig for enabling/disabling drivers
We update ipi drivers makefile to use kconfig for enabling/disabling
drivers. To avoid compile errors, we also enable appropriate ipi
drivers for each platform.

Signed-off-by: Anup Patel <apatel@ventanamicro.com>
Tested-by: Andrew Jones <ajones@ventanamicro.com>
Acked-by: Atish Patra <atishp@rivosinc.com>
Tested-by: Atish Patra <atishp@rivosinc.com>
2022-08-08 09:33:45 +05:30
Anup Patel
013dbb3a60 lib: utils/timer: Use kconfig for enabling/disabling drivers
We update timer drivers makefile to use kconfig for enabling/disabling
drivers. To avoid compile errors, we also enable appropriate timer
drivers for each platform.

Signed-off-by: Anup Patel <apatel@ventanamicro.com>
Tested-by: Andrew Jones <ajones@ventanamicro.com>
Acked-by: Atish Patra <atishp@rivosinc.com>
Tested-by: Atish Patra <atishp@rivosinc.com>
2022-08-08 09:33:37 +05:30
Anup Patel
3e76a607b5 lib: utils/sys: Use kconfig for enabling/disabling drivers
We update system drivers makefile to use kconfig for enabling/disabling
drivers. To avoid compile errors, we also enable appropriate system
drivers for each platform.

Signed-off-by: Anup Patel <apatel@ventanamicro.com>
Tested-by: Andrew Jones <ajones@ventanamicro.com>
Acked-by: Atish Patra <atishp@rivosinc.com>
Tested-by: Atish Patra <atishp@rivosinc.com>
2022-08-08 09:33:31 +05:30
Anup Patel
2adc94b466 lib: utils/reset: Use kconfig for enabling/disabling drivers
We update reset drivers makefile to use kconfig for enabling/disabling
drivers. To avoid compile errors, we also enable appropriate reset
drivers for each platform.

Signed-off-by: Anup Patel <apatel@ventanamicro.com>
Tested-by: Andrew Jones <ajones@ventanamicro.com>
Acked-by: Atish Patra <atishp@rivosinc.com>
Tested-by: Atish Patra <atishp@rivosinc.com>
2022-08-08 09:33:26 +05:30
Anup Patel
26bbff5f76 lib: utils/serial: Use kconfig for enabling/disabling drivers
We update serial drivers makefile to use kconfig for enabling/disabling
drivers. To avoid compile errors, we also enable appropriate serial
drivers for each platform.

Signed-off-by: Anup Patel <apatel@ventanamicro.com>
Tested-by: Andrew Jones <ajones@ventanamicro.com>
Acked-by: Atish Patra <atishp@rivosinc.com>
Tested-by: Atish Patra <atishp@rivosinc.com>
2022-08-08 09:33:21 +05:30
Anup Patel
de80e9337d Makefile: Compile lib/utils sources separately for each platform
Currently, if same build directory is used to compile two different
platforms then lib/utils objects are shared for these platforms.

We will be having platform specific configs to enable/disable drivers
in lib/utils and select compile time options for lib/utils sources.
This means lib/utils sources will now be compiled in a platform
specific way.

To tackle above, we update top-level Makefile as follows:
1) Don't create libsbiutils.a anymore because this can't be shared
   between platforms.
2) Compile lib/utils sources separately for each platform.
3) Add comments showing which make rules are for lib/sbi, lib/utils,
   firmware, and platform sources.

Signed-off-by: Anup Patel <apatel@ventanamicro.com>
Tested-by: Andrew Jones <ajones@ventanamicro.com>
Acked-by: Atish Patra <atishp@rivosinc.com>
Tested-by: Atish Patra <atishp@rivosinc.com>
2022-08-08 09:33:14 +05:30
Anup Patel
662e631cce Makefile: Add initial kconfig support for each platform
We extend the top-level makefile to allow kconfig based configuration
for each platform where each platform has it's own set of configs with
"defconfig" being the default config.

Signed-off-by: Anup Patel <apatel@ventanamicro.com>
Tested-by: Andrew Jones <ajones@ventanamicro.com>
Acked-by: Atish Patra <atishp@rivosinc.com>
Tested-by: Atish Patra <atishp@rivosinc.com>
2022-08-08 09:33:09 +05:30
Anup Patel
422f0e0486 scripts: Add Kconfiglib v14.1.0 under scripts directory
We adopt Kconfiglib v14.1.0 sources under scripts directory so that
top-level OpenSBI makefile can directly use Kconfiglib scripts without
expecting users to install a particular version of Kconfiglib on their
build system.

Signed-off-by: Anup Patel <apatel@ventanamicro.com>
Tested-by: Andrew Jones <ajones@ventanamicro.com>
Acked-by: Atish Patra <atishp@rivosinc.com>
Tested-by: Atish Patra <atishp@rivosinc.com>
2022-08-08 09:33:03 +05:30
dramforever
b9edf49b67 lib: sbi: Fix printf handling of long long
Read long long arguments directly using va_arg. Remove original hack for
RV32 that read a long long arg as two long args.

This un-breaks the case on RV64 where e.g. the long long is followed by
an odd number of ints:

    sbi_printf("%d %lld", (int) 1, (long long) 2LL);

Also remove the acnt variable, which is now unused.

Signed-off-by: dramforever <dramforever@live.com>
Reviewed-by: Andrew Jones <ajones@ventanamicro.com>
Reviewed-by: Anup Patel <anup@brainfault.org>
2022-07-30 11:55:51 +05:30
Andrew Jones
f27203525a lib: utils/serial: Ensure baudrate is non-zero before using
RISC-V doesn't generate exceptions on divide-by-zero, but the result,
all bits set, is not likely what people expect either. In all cases
where we divide by baudrate there's a chance it's zero (when the DT
it came from is "bad"). To avoid difficult to debug situations, leave
baudrate dependent registers alone when baudrate is zero, as, also in
all cases, it appears we can skip initialization of those registers
and still [hopefully] have a functioning UART.

Signed-off-by: Andrew Jones <ajones@ventanamicro.com>
Reviewed-by: Anup Patel <anup@brainfault.org>
2022-07-30 11:39:42 +05:30
Andrew Jones
7198e1d06f lib: serial: Clean up coding style in sifive-uart.c
Signed-off-by: Andrew Jones <ajones@ventanamicro.com>
Reviewed-by: Xiang W <wxjstz@126.com>
Reviewed-by: Anup Patel <anup@brainfault.org>
2022-07-30 11:39:19 +05:30
Andrew Jones
7d28d3be50 lib: utils/serial: Initialize platform_uart_data to zero
While it doesn't look like there are any current cases of using
uninitialized data, let's zero all the UART data members to be
safe. Zero may not actually be better than a random number in
some cases, so all structure members should still be validated
before use, but at least zero is usually easier to debug than
some random stack garbage...

Signed-off-by: Andrew Jones <ajones@ventanamicro.com>
Reviewed-by: Anup Patel <anup@brainfault.org>
2022-07-30 11:39:10 +05:30
Andrew Jones
8e86b23db9 lib: utils/fdt: Factor out common uart node code
Factor out the common code used by the fdt UART node parsers,
allowing us to drop duplicate code.

Signed-off-by: Andrew Jones <ajones@ventanamicro.com>
Reviewed-by: Anup Patel <anup@brainfault.org>
2022-07-30 11:39:01 +05:30
Atish Patra
11c0008862 lib: sbi: Fix fw_event_map initialization
fw_event_map represents array of firmware events. It should initialized
for maximum number of firmware events not counters.

Reviewed-by: Andrew Jones <ajones@ventanamicro.com>
Signed-off-by: Atish Patra <atishp@rivosinc.com>
Reviewed-by: Anup Patel <anup@brainfault.org>
2022-07-30 11:28:36 +05:30
Atish Patra
860a376817 lib: sbi: Fix possible buffer overrun in counter validation
The active_events array is accessed with counter ID passed from the supervisor
software before the counter ID bound check. This may cause a buffer overrun
if a supervisor passes an invalid counter ID.

Fix this by moving the access part after the bound check.

Reported-by: Andrew Jones <ajones@ventanamicro.com>
Reviewed-by: Andrew Jones <ajones@ventanamicro.com>
Signed-off-by: Atish Patra <atishp@rivosinc.com>
Reviewed-by: Anup Patel <anup@brainfault.org>
2022-07-30 11:25:48 +05:30
Atish Patra
83db3af5f9 lib: sbi: Add the bound check for events during config match
Currently, there is no sanity check for firmware event code. We don't see
any issue as Linux kernel driver does a bound check on firmware events
already. However, OpenSBI can't assume sane supervisor mode software
always. Thus, an invalid event idx can cause a buffer overflow error.
For hardware events, the match will fail for invalid event code anyways.
However, a search is unecessary if event code is invalid.

Add a event ID validation function to solve the issue.

Signed-off-by: Atish Patra <atishp@rivosinc.com>
Reviewed-by: Andrew Jones <ajones@ventanamicro.com>
Reviewed-by: Anup Patel <anup@brainfault.org>
2022-07-30 11:22:50 +05:30
Atish Patra
1545afd342 lib: sbi: Fix counter index sanity check
The current implementation computes the possible counter range
by doing a left shift of counter base. However, this may overflow depending
on the counter base value. In case of overflow, the highest counter id
may be computed incorrectly. As per the SBI specification, the respective
function should return an error if any of the counter is not valid.

Fix the counter index check by avoiding left shifting while doing the
sanity checks. Without the shift, the implementation just iterates
over the counter mask and computes the correct counter index by adding
the base to it.

Reviewed-by: Andrew Jones <ajones@ventanamicro.com>
Signed-off-by: Atish Patra <atishp@rivosinc.com>
Reviewed-by: Anup Patel <anup@brainfault.org>
2022-07-30 11:09:18 +05:30
Andrew Jones
88b790f129 lib: sbi: Fix sbi_snprintf
printc would happily write to 'out' even when 'out_len' was zero,
potentially overflowing buffers. Rework printc to not do that and
also ensure the null byte is written at the last position when
necessary, as stated in the snprintf man page. Also, panic if
sprintf or snprintf are called with NULL output strings (except
the special case of snprintf having a NULL output string and
a zero output size, allowing it to be used to get the number of
characters that would have been written). Finally, rename a
goto label which clashed with 'out'.

Fixes: 9e8ff05cb6 ("Initial commit.")
Signed-off-by: Andrew Jones <ajones@ventanamicro.com>
Reviewed-by: Anup Patel <anup@brainfault.org>
2022-07-30 11:02:07 +05:30
Prasanna T
4e21ccacd1 lib: utils/serial: Update Shakti UART based on latest implementation
The age old version of Shakti UART was upgraded long back, but we missed
updating the driver in OpenSBI. The old version of UART is not supported
anymore, hence removed the inline comment which is also outdated now.

Signed-off-by: Prasanna T <ptprasanna@gmail.com>
Signed-off-by: Anup Patel <apatel@ventanamicro.com>
Reviewed-by: Xiang W <wxjstz@126.com>
2022-07-20 10:06:25 +05:30
gagachang
0374ccf3f1 lib: sbi_hart: Shorten the code to set MPV bit
MPV bit is set when the value of next_virt boolean variable equals
true. Since the value of next_virt is either 0 or 1, we can set
MPV bit without if-else logic.

Signed-off-by: Che-Chia Chang <alvinga@andestech.com>
Reviewed-by: Andrew Jones <ajones@ventanamicro.com>
Reviewed-by: Anup Patel <anup@brainfault.org>
2022-07-20 10:05:33 +05:30
Ben Dooks
caa5eeacac lib: sbi: add check for ipi device for hsm start
If the ecall SBI_EXT_HSM_HART_START is called it might try to wake the
secondary hart using sbi_ipi_raw_send() to send an IPI to the hart.
This can fail if there is no IPI device but no error is returned from
sbi_ipi_raw_send() so the ecall returns as if the action completed and
the caller continues without noticing (in the case of Linux it just hangs
waiting for the secondary hart to become active)

Fix this by changing sbi_ipi_raw_send() to return and error, and if an
error is returned, then return it via SBI_EXT_HSM_HART_START call.

Signed-off-by: Ben Dooks <ben.dooks@sifive.com>
Reviewed-by: Anup Patel <anup@brainfault.org>
2022-07-11 15:46:59 +05:30
Adnan Rahman Chowdhury
994c8cfb29 lib: sbi_timer: Added a conditional wait function which can timeout
Motivation: Suppose a peripheral needs to be configured to transmit
data. There is an SFR bit which indicates that the peripheral is ready
to transmit. The firmware should check the bit and will only transmit
data when the peripheral is ready. When the firmware starts polling the
SFR, the peripheral could be busy transmitting/receiving other data so
the firmware must wait till that completes. Assuming that there is no
other way, the firmware shouldn't wait indefinitely.

The function sbi_timer_waitms_until() will constantly check whether a
certain condition is satisfied, or timeout occurs. It can be used for
the cases when a timeout is required.

Signed-off-by: Adnan Rahman Chowdhury <adnan.chowdhury@sifive.com>
Reviewed-by: Xiang W <wxjstz@126.com>
Reviewed-by: Anup Patel <anup@brainfault.org>
2022-07-08 14:51:24 +05:30
Anup Patel
4489876e93 include: Bump-up version to 1.1
This patch updates OpenSBI version to 1.1 as part of
release preparation.

Signed-off-by: Anup Patel <apatel@ventanamicro.com>
2022-06-25 09:12:10 +05:30
Sergey Matyukevich
3f66465fb6 lib: pmu: allow to use the highest available counter
OpenSBI explicitly assumes that there is no pmu hardware counter with
index 1: hardware uses that bit for TM control. So OpenSBI filters
out that index in sanity checks. However OpenSBI also excludes that
counter when reports total amount of hardware counters to Linux. As
a result, Linux uses incomplete counters mask excluding the highest
available counter.

Return accurate number of counters, update the firmware counter
starting index, fix range checks that include num_hw_ctrs.

The simple test is to make sure that there is no counter multiplexing
in the following command:

$ perf stat -e \
	r8000000000000000,r8000000000000001,r8000000000000002,r8000000000000003, \
	r8000000000000004,r8000000000000005,r8000000000000006,r8000000000000007, \
	r8000000000000008,r8000000000000009,r800000000000000a,r800000000000000b, \
	r800000000000000c,r800000000000000d,r800000000000000e,r800000000000000f  \
	ls

Note that 16 firmware events with 16 counters won't require multiplexing.

Signed-off-by: Sergey Matyukevich <geomatsi@gmail.com>
Signed-off-by: Atish Patra <atishp@rivosinc.com>
Reviewed-by: Atish Patra <atishp@rivosinc.com>
2022-06-25 08:44:20 +05:30
Anup Patel
c6fdbcf83f include: sbi: Change spec version to 1.0
Now that SBI v1.0 specification is ratified, we change spec verion
implemented by OpenSBI to v1.0.

Signed-off-by: Anup Patel <apatel@ventanamicro.com>
Reviewed-by: Atish Patra <atishp@rivosinc.com>
2022-06-24 08:54:59 +05:30
Samuel Holland
6f1fe98c2f lib: utils/timer: Remove Allwinner D1 CLINT compatibles
The allwinner,sun20i-d1-clint compatible string is not documented in any
official binding, so it should not be used by drivers.

The MSWI in the D1 CLINT is compatible with the ACLINT specification, so
it can take advantage of generic driver support. However, that is only
possible if the MSWI and MTIMER are split into separate DT nodes. This
means the final binding for this device is likely to be incompatible
with what is implemented here.

Remove this compatible string from the driver to prevent it from
appearing in a stable version and causing future issues.

Signed-off-by: Samuel Holland <samuel@sholland.org>
Reviewed-by: Anup Patel <anup@brainfault.org>
2022-06-22 10:55:37 +05:30
Jan Remes
d76a196bfc lib: irqchip/plic: fix typo in plic_warm_irqchip_init
The second invocation of plic_context_init() incorrectly calls the
function with m_cntx_id instead of s_cntx_id. This breaks systems which
only have 1 external interrupt per hart.

Fixes: 8c362e7 ("lib: irqchip/plic: Factor out a context init function")
Signed-off-by: Jan Remes <jan.remes@codasip.com>
Reviewed-by: Anup Patel <anup@brainfault.org>
Reviewed-by: Samuel Holland <samuel@sholland.org>
2022-06-22 10:55:27 +05:30
Samuel Holland
7738345396 lib: utils/timer: Add a separate compatible for the D1 CLINT
The CLINT in the Allwinner D1 SoC apparently does not support 64-bit
MMIO access. A property was added to support this quirk (and that
property was copied to the ACLINT MTIMER code). However, since this
difference in behavior makes the D1 CLINT incompatible with the SiFive
CLINT's programming interface, a better solution is to use a separate
compatible string.

Signed-off-by: Samuel Holland <samuel@sholland.org>
Reviewed-by: Anup Patel <anup@brainfault.org>
2022-06-21 09:20:59 +05:30
Anup Patel
c6530012d4 lib: utils: Remove CSRs that set/clear an IMSIC interrupt file bits
Based on architecture review committee feedback, the [m|s|vs]seteienum,
[m|s|vs]clreienum, [m|s|vs]seteipnum, and [m|s|vs]clreipnum CSRs are
removed in the latest AIA draft v0.3.0 specification.
(Refer, https://github.com/riscv/riscv-aia/releases/tag/0.3.0-draft.31)

These CSRs were mostly for software convenience and software can always
use [m|s|vs]iselect and [m|s|vs]ireg CSRs to update the IMSIC interrupt
file bits.

We update the IMSIC programming as-per above to match the latest AIA
draft specification.

Signed-off-by: Anup Patel <apatel@ventanamicro.com>
Reviewed-by: Atish Patra <atishp@rivosinc.com>
2022-06-21 08:44:45 +05:30
dramforever
a07402ac9c lib: sbi: Fix tval and tinst for sbi_get_insn()
We should not change trap->tval to mepc because mtval already points to
the faulting portion of the emulated instruction fetch, which is also
what stval is expected to be.

In addition, htinst is only allowed to be zero for instruction access
faults or page faults, and is only allowed to be zero or a
psuedoinstruction for instruction guest-page faults. Fix trap->tinst for
these cases.

Signed-off-by: dramforever <dramforever@live.com>
Reviewed-by: Anup Patel <anup@brainfault.org>
2022-06-21 08:31:56 +05:30
dramforever
187127fb89 lib: sbi: Fixup tinst for exceptions in sbi_misaligned_*()
If there is an exception while emulating a misaligned load/store, fixup
uptrap.tinst before redirecting. Otherwise, HS-mode software may receive
an htinst describing the lbu/sb instruction that faulted during
emulation[1].

[1]: https://github.com/riscv-software-src/opensbi/issues/258

Signed-off-by: dramforever <dramforever@live.com>
Reviewed-by: Anup Patel <anup@brainfault.org>
2022-06-21 08:31:14 +05:30
dramforever
551c70c040 include: sbi: Add mtinst/htinst psuedoinstructions
Add psuedoinstruction encodings written to mtinst/htinst for faults
caused by implicit memory access for VS-stage address translation

Signed-off-by: dramforever <dramforever@live.com>
Reviewed-by: Anup Patel <anup@brainfault.org>
2022-06-21 08:31:04 +05:30
Samuel Holland
9dc5ec5c51 platform: Add HSM implementation for Allwinner D1
Allwinner D1 contains a "PPU" power domain controller which can
automatically power down/up the CPU power domain. This power domain
includes the C906 core along with its CLINT and PLIC.

This HSM implementation supports non-retentive hart suspend by:
  1) Saving/restoring state that is lost during hart suspend,
  2) Performing cache maintenance before/after hart suspend,
  3) Configuring wakeup sources before hart suspend, and
  4) Asking the PPU to power down the hart when it enters WFI.

Since this HSM implementation is for a single-core SoC, it does not need
to worry about concurrency or saving multiple instances of state.

Reviewed-by: Anup Patel <anup@brainfault.org>
Signed-off-by: Samuel Holland <samuel@sholland.org>
2022-06-13 11:59:09 +05:30
Samuel Holland
5e5675874c lib: utils/irqchip: Add wrapper for T-HEAD PLIC delegation
The delegation bit is lost along with the rest of the PLIC state when
the CPU power domain in the Allwinner D1 is powered down, so the PLIC
needs to be re-delegated to S-mode during the hart resume path.

Reviewed-by: Anup Patel <anup@brainfault.org>
Signed-off-by: Samuel Holland <samuel@sholland.org>
2022-06-13 11:54:06 +05:30
Samuel Holland
69be3dff9d lib: utils/irqchip: Add FDT wrappers for PLIC save/restore functions
These functions save/restore the state of the PLIC associated with the
current hart. The context save/restore functions only manipulate a
single context, since most likely the M-mode context is unused and does
not need to be saved.

Signed-off-by: Samuel Holland <samuel@sholland.org>
Reviewed-by: Anup Patel <anup@brainfault.org>
2022-06-13 11:54:06 +05:30
Samuel Holland
2b79b694a8 lib: irqchip/plic: Add priority save/restore helpers
These can be used by platform code to save the PLIC priority state, if
it would otherwise be lost during non-retentive suspend. The platform
is responsible for allocating all necessary storage.

As a space optimization, store the saved priority values as 8-bit
integers, since that is large enough to hold any priority value on the
relevant platforms.

Reviewed-by: Anup Patel <anup@brainfault.org>
Signed-off-by: Samuel Holland <samuel@sholland.org>
2022-06-13 11:54:06 +05:30
Samuel Holland
415ecf28f7 lib: irqchip/plic: Add context save/restore helpers
These can be used by platform code to save the PLIC context state, if
it would otherwise be lost during non-retentive suspend. The platform
is responsible for allocating all necessary storage.

Reviewed-by: Anup Patel <anup@brainfault.org>
Signed-off-by: Samuel Holland <samuel@sholland.org>
2022-06-13 11:54:06 +05:30
Samuel Holland
8c362e7d06 lib: irqchip/plic: Factor out a context init function
This simplifies both the callers and the callees by removing duplicated
code and consolidating the error handling. It also fixes two bugs in the
process:
  1) ie_words was one too large when plic->num_src was a multiple of 32.
  2) plic_set_ie takes a 32-bit mask, not a Boolean value, so the FPGA
     platforms previously only enabled one out of every 32 interrupts.

Reviewed-by: Anup Patel <anup@brainfault.org>
Signed-off-by: Samuel Holland <samuel@sholland.org>
2022-06-13 11:54:06 +05:30
Samuel Holland
2ea7799d56 lib: irqchip/plic: Constify plic_data pointers
None of the functions modify the passed-in plic_data, so mark it const.

Reviewed-by: Anup Patel <anup@brainfault.org>
Signed-off-by: Samuel Holland <samuel@sholland.org>
2022-06-13 11:54:06 +05:30
Samuel Holland
79e42eb2d6 lib: sbi_hsm: Assume a consistent resume address
The suspend code needs to know the resume address for two reasons:
  1) Programming some hardware register or management firmware. Here we
     assume the hardware/firmware maintains its state between suspends,
     so it only needs to be programmed once at startup.
  2) When a non-retentive suspend request ends up being retentive, due
     to lack of hardware support, pending interrupt, or for some other
     reason. However, the behavior here is not platform-dependent, and
     this can be handled in the generic hart suspend function.

Since neither situation requires the platform-level suspend function to
know the resume address, stop passing it to that function. Instead,
handle the non-retentive to retentive situation generically.

Reviewed-by: Anup Patel <anup@brainfault.org>
Signed-off-by: Samuel Holland <samuel@sholland.org>
2022-06-13 11:54:06 +05:30
Samuel Holland
b20ed9febe lib: sbi_hsm: Call a device hook during hart resume
Non-retentive suspend states may require platform-specific actions
during resume. For example, firmware may need to save and restore the
values of custom CSRs. Add a hook to support this.

Reviewed-by: Anup Patel <anup@brainfault.org>
Signed-off-by: Samuel Holland <samuel@sholland.org>
2022-06-13 11:54:06 +05:30
Mayuresh Chitale
ce1d6188a2 platform: generic: add overrides for vendor extensions
Allow the vendor_ext_check and vendor_ext_provider APIs of the
generic platform to be overridden by other platforms

Signed-off-by: Mayuresh Chitale <mchitale@ventanamicro.com>
Reviewed-by: Anup Patel <anup@brainfault.org>
2022-06-13 11:17:38 +05:30
dramforever
adc3388d76 lib: sbi_trap: Redirect exception based on hedeleg
HS-mode software can choose what exceptions to delegate to VS-mode using
the hedeleg CSR. Synthetic VS/VU-mode exceptions should also honor
hedeleg. They should be redirected to VS-mode if and only if delegated
by HS-mode.

Signed-off-by: dramforever <dramforever@live.com>
Reviewed-by: Xiang W <wxjstz@126.com>
Reviewed-by: Anup Patel <anup@brainfault.org>
2022-06-13 11:02:49 +05:30
Samuel Holland
cb8271c8e4 lib: sbi_illegal_insn: Add emulation for fence.tso
While OpenC906 appears to properly decode `fence.tso` as a fence
instruction[1], the version of the C906 taped out in the Allwinner D1
does not, and raises illegal instruction.

Handle this errata by emulating `fence.tso` as `fence rw, rw`.

[1]: https://github.com/T-head-Semi/openc906/blob/30827e7f/C906_RTL_FACTORY/gen_rtl/idu/rtl/aq_idu_id_decd.v#L2097

Signed-off-by: Samuel Holland <samuel@sholland.org>
Reviewed-by: Anup Patel <anup@brainfault.org>
2022-06-01 17:20:20 +05:30
Samuel Holland
ff65bfec4e lib: sbi_illegal_insn: Constify illegal_insn_table
This table does not need to be modified at runtime.

Signed-off-by: Samuel Holland <samuel@sholland.org>
Reviewed-by: Anup Patel <anup@brainfault.org>
2022-05-30 10:54:31 +05:30
Samuel Holland
295e5f3c69 lib: sbi_timer: Drop unnecessary get_platform_ticks wrapper
The device's timer_value callback is already the right prototype to use
for the get_time_val function pointer.

Signed-off-by: Samuel Holland <samuel@sholland.org>
Reviewed-by: Anup Patel <anup@brainfault.org>
2022-05-30 10:43:03 +05:30
Samuel Holland
fab0379bb6 lib: utils/fdt: Require match data to be const
Match data stores hardware attributes which do not change at runtime, so
it does not need to be mutable. Make it const.

Reviewed-by: Guo Ren <guoren@kernel.org>
Reviewed-by: Xiang W <wxjstz@126.com>
Reviewed-by: Anup Patel <anup@brainfault.org>
Signed-off-by: Samuel Holland <samuel@sholland.org>
2022-05-30 10:32:35 +05:30
Xiang W
f067bb84cf lib: sbi: fix system_opcode_insn
If the csr's operation comes from M mode, it should not be forwarded
to low-privilege processing, this patch fixes this problem.

Signed-off-by: Xiang W <wxjstz@126.com>
Reviewed-by: Anup Patel <anup@brainfault.org>
2022-05-30 10:22:13 +05:30
Jan Remes
1bc67db80c lib: utils/fdt: rename fdt_parse_max_hart_id
The function returns the highest hart-id of the harts actually used in
the system (enabled). Change the name to reflect this fact.

Signed-off-by: Jan Remes <jan.remes@codasip.com>
Reviewed-by: Anup Patel <anup@brainfault.org>
2022-05-14 10:18:12 +05:30
Jan Remes
575bb4e8ca platform: generic: check if CPU node is enabled
Ignore CPU nodes in FDT which are not enabled.

Signed-off-by: Jan Remes <jan.remes@codasip.com>
Reviewed-by: Xiang W <wxjstz@126.com>
Reviewed-by: Anup Patel <anup@brainfault.org>
2022-05-14 10:17:33 +05:30
Jan Remes
616da52e18 lib: utils: check if CPU node is enabled
Ignore CPU nodes in FDT that are not enabled.

Signed-off-by: Jan Remes <jan.remes@codasip.com>
Reviewed-by: Anup Patel <anup@brainfault.org>
2022-05-14 10:16:50 +05:30
Jan Remes
90a9dd2b22 lib: utils/fdt: introduce fdt_node_is_enabled()
If an FDT node contains a "status" property and this property is not
"ok" or "okay", this node should be ignored. Introduce a function that
checks this.

Signed-off-by: Jan Remes <jan.remes@codasip.com>
Reviewed-by: Xiang W <wxjstz@126.com>
Reviewed-by: Anup Patel <anup@brainfault.org>
2022-05-14 10:16:24 +05:30
Jan Remes
851c14d455 lib: utils/irqchip: fix typo when checking for CPU node
Fix typo in irqchip_imsic_update_hartid_table() when checking for CPU
node.

Signed-off-by: Jan Remes <jan.remes@codasip.com>
Reviewed-by: Anup Patel <anup@brainfault.org>
Reviewed-by: Bin Meng <bmeng.cn@gmail.com>
2022-05-13 09:58:54 +05:30
Anup Patel
9a7a677d5f platform: generic: Move Sifive platform overrides into own directory
Let us move SiFive platform overrides for FU540 and FU740 into a separate
directory so better maintainability. Other SoC vendors can also create
their own directory under platform/generic.

Signed-off-by: Anup Patel <apatel@ventanamicro.com>
Reviewed-by: Atish Patra <atishp@rivosinc.com>
2022-05-13 09:27:23 +05:30
Anup Patel
a3a3c60b66 platform: generic: Generate platform override module list at compile-time
Instead of having platform override module list hard-coded in the C source,
we generate it using carray.sh at compile-time.

Signed-off-by: Anup Patel <apatel@ventanamicro.com>
Reviewed-by: Atish Patra <atishp@rivosinc.com>
2022-05-13 09:27:18 +05:30
Anup Patel
4eacd8229b lib: utils/gpio: Generate FDT gpio driver list at compile-time
Instead of having FDT gpio driver list hard-coded in the C source,
we generate it using carray.sh at compile-time.

Signed-off-by: Anup Patel <apatel@ventanamicro.com>
Reviewed-by: Atish Patra <atishp@rivosinc.com>
2022-05-13 09:27:12 +05:30
Anup Patel
998ed43fde lib: utils/i2c: Generate FDT i2c adapter driver list at compile-time
Instead of having FDT i2c adapter driver list hard-coded in the C source,
we generate it using carray.sh at compile-time.

Signed-off-by: Anup Patel <apatel@ventanamicro.com>
Reviewed-by: Atish Patra <atishp@rivosinc.com>
2022-05-13 09:26:45 +05:30
Anup Patel
4ee0c57969 lib: utils/ipi: Generate FDT ipi driver list at compile-time
Instead of having FDT ipi driver list hard-coded in the C source,
we generate it using carray.sh at compile-time.

Signed-off-by: Anup Patel <apatel@ventanamicro.com>
Reviewed-by: Atish Patra <atishp@rivosinc.com>
2022-05-13 09:26:35 +05:30
Anup Patel
3a69d12fc3 lib: utils/irqchip: Generate FDT irqchip driver list at compile-time
Instead of having FDT irqchip driver list hard-coded in the C source,
we generate it using carray.sh at compile-time.

Signed-off-by: Anup Patel <apatel@ventanamicro.com>
Reviewed-by: Atish Patra <atishp@rivosinc.com>
2022-05-13 09:26:27 +05:30
Anup Patel
bfeb305e0f lib: utils/timer: Generate FDT timer driver list at compile-time
Instead of having FDT timer driver list hard-coded in the C source,
we generate it using carray.sh at compile-time.

Signed-off-by: Anup Patel <apatel@ventanamicro.com>
Reviewed-by: Atish Patra <atishp@rivosinc.com>
2022-05-13 09:26:20 +05:30
Anup Patel
1e62705adc lib: utils/serial: Generate FDT serial driver list at compile-time
Instead of having FDT serial driver list hard-coded in the C source,
we generate it using carray.sh at compile-time.

Signed-off-by: Anup Patel <apatel@ventanamicro.com>
Reviewed-by: Atish Patra <atishp@rivosinc.com>
2022-05-13 09:26:13 +05:30
Anup Patel
73cf511914 lib: utils/reset: Generate FDT reset driver list at compile-time
Instead of having FDT reset driver list hard-coded in the C source,
we generate it using carray.sh at compile-time.

Signed-off-by: Anup Patel <apatel@ventanamicro.com>
Reviewed-by: Atish Patra <atishp@rivosinc.com>
2022-05-13 09:26:06 +05:30
Anup Patel
7fb474b9dd Makefile: Add support for generating C array at compile time
Generating C array at compile time based on details provided by
objects.mk is a very useful feature which will help us compile
only a subset of drivers or modules.

We add a bash script (carray.sh) which takes array details and
object/variable list from command-line to generate a C source
containing array of object/variable pointers. We also extend
top-level makefile to use carray.sh whenever specified through
objects.mk.

Signed-off-by: Anup Patel <apatel@ventanamicro.com>
Reviewed-by: Atish Patra <atishp@rivosinc.com>
2022-05-13 09:26:00 +05:30
Anup Patel
f726f2dc01 Makefile: Allow generated C source to be anywhere in build directory
The generated C source could be anywhere within build directory so
let us update the make rule to comple generated C source accordingly.

Signed-off-by: Anup Patel <apatel@ventanamicro.com>
Reviewed-by: Atish Patra <atishp@rivosinc.com>
2022-05-13 09:25:50 +05:30
Anup Patel
023f0ad2d9 lib: sbi_platform: Add callback to populate HART extensions
We add platform specific extensions_init() callback which allows
platforms to populate HART extensions for each HART. For example,
the generic platform can populate HART extensions from HART ISA
string described in DeviceTree.

Signed-off-by: Anup Patel <apatel@ventanamicro.com>
Reviewed-by: Atish Patra <atishp@rivosinc.com>
2022-05-07 10:17:28 +05:30
Anup Patel
994ace30f7 lib: sbi: Add sbi_hart_update_extension() function
We add sbi_hart_update_extension() function which allow platforms
to enable/disable hart extensions.

Signed-off-by: Anup Patel <anup@brainfault.org>
Reviewed-by: Atish Patra <atishp@rivosinc.com>
2022-05-07 10:17:25 +05:30
Anup Patel
be4903ae00 lib: sbi: Detect hart features only once for each hart
Currently, the hart_detect_features() is called everytime a hart
is stopped and started again which is unnecessary work.

We update hart_detect_features() to detect hart features only
once for each hart.

Signed-off-by: Anup Patel <apatel@ventanamicro.com>
Reviewed-by: Atish Patra <atishp@rivosinc.com>
2022-05-07 10:17:22 +05:30
Anup Patel
cad6c91045 lib: sbi: Convert hart features into hart extensions
Since past few years, we have been using "hart features" in OpenSBI
to represent all optionalities and multi-letter extensions defined
by the RISC-V specifications.

The RISC-V profiles specification has taken a different approach and
started assigning extension names for all optionalities which did not
have any extension name previously.
(Refer, https://github.com/riscv/riscv-profiles/blob/main/profiles.adoc)

Inspired from the RISC-V profiles specification, we convert OpenSBI
hart features into hart extensions. Going forward, we align the
extension naming with RISC-V profiles specification. Currently, only
"time CSR" and "AIA CSR" have not been assigned extension name but
for everything else we have a name.

Signed-off-by: Anup Patel <apatel@ventanamicro.com>
Reviewed-by: Atish Patra <atishp@rivosinc.com>
2022-05-07 10:16:30 +05:30
Anup Patel
a6ab94fdbf lib: sbi: Fix AIA feature detection
The AIA feature detection uses unnecessary goto which is not need
and AIA case in sbi_hart_feature_id2string() does not break. This
patch fixes both issues in AIA feature detection.

Signed-off-by: Anup Patel <apatel@ventanamicro.com>
Reviewed-by: Atish Patra <atishp@rivosinc.com>
2022-05-07 10:06:57 +05:30
Anup Patel
97a17c2e5c lib: sbi: Remove MENVCFG hart feature
If a hart implements privileged spec v1.12 (or higher) then we can
safely assume that menvcfg CSR is present and we don't need MENVCFG
as a hart feature.

Signed-off-by: Anup Patel <apatel@ventanamicro.com>
Reviewed-by: Atish Patra <atishp@rivosinc.com>
2022-05-07 10:06:19 +05:30
Anup Patel
dbc3d8f0ef lib: sbi: Remove MCOUNTINHIBT hart feature
If a hart implements privileged spec v1.11 (or higher) then we can
safely assume that mcountinhibit CSR is present and we don't need
MCOUNTINHIBT as a hart feature.

Signed-off-by: Anup Patel <apatel@ventanamicro.com>
Reviewed-by: Atish Patra <atishp@rivosinc.com>
2022-05-07 10:05:37 +05:30
Anup Patel
d4b563c881 lib: sbi: Remove MCOUNTEREN and SCOUNTEREN hart features
If a hart implements privileged spec v1.10 (or higher) then we can
safely assume that [m|s]counteren CSR are present and we don't need
MCOUNTEREN and SCOUNTEREN as hart features.

Signed-off-by: Anup Patel <apatel@ventanamicro.com>
Reviewed-by: Atish Patra <atishp@rivosinc.com>
2022-05-07 10:04:54 +05:30
Anup Patel
5b8b377178 lib: sbi: Update the name of ISA string printed at boot time
The ISA string printed at boot time is not the complete ISA string
representing all single letter and multi-letter extensions rather
it is base ISA string derived from misa CSR so let us update the
boot print accordingly.

Signed-off-by: Anup Patel <apatel@ventanamicro.com>
Reviewed-by: Atish Patra <atishp@rivosinc.com>
2022-05-07 10:03:24 +05:30
Anup Patel
5a6be99cc5 lib: sbi: Remove 's' and 'u' from misa_string() output
Both 's' and 'u' are not treated as ISA extensions since these are
privilege modes so let's remove it from misa_string() output.

Signed-off-by: Anup Patel <apatel@ventanamicro.com>
Reviewed-by: Atish Patra <atishp@rivosinc.com>
2022-05-07 10:02:28 +05:30
Anup Patel
1a754bb365 lib: sbi: Detect and print privileged spec version
It is possible to guess privileged spec versions based on the CSRs
that where introduced in different privileged spec versions. In
future, if we are not able guess privileged spec version then we
can have platform provide it.

We add privileged spec version as per-hart feature and try to guess
it based on presence of mcounteren, mcountinhibit, and menvcfg CSRs.

Signed-off-by: Anup Patel <apatel@ventanamicro.com>
Reviewed-by: Atish Patra <atishp@rivosinc.com>
2022-05-07 09:49:54 +05:30
Atish Patra
b0c9df514b lib: sbi: Fix mhpmeventh access for rv32 in absence of sscofpmf
MHPMEVENT3H-31H are defined in sscofpmf extension. Thus, they should be
accessed only if sscofpmf is present.

Signed-off-by: Atish Patra <atishp@rivosinc.com>
Reviewed-by: Anup Patel <anup@brainfault.org>
2022-05-07 09:40:59 +05:30
Jun Liang Tan
e576b3e620 include: sbi: Define SBI_PMU_HW_EVENT_MAX to 256
Increase maximum number of PMU hardware events that can be mapped
by OpenSBI to 256

Signed-off-by: Jun Liang Tan <junliang.tan@linux.starfivetech.com>
Signed-off-by: Wei Liang Lim <weiliang.lim@linux.starfivetech.com>
Reviewed-by: Anup Patel <anup@brainfault.org>
2022-05-07 09:37:42 +05:30
Anup Patel
474a9d4555 lib: sbi: Fix mstatus_init() for RV32 when Sscofpmf is not available
The mhpmevent3h to mhpmevent31h CSRs are available on RV32 only when
Sscofpmf extension is available so mstatus_init() should set this
CSRs only when Sscofpmf extension is available.

Signed-off-by: Anup Patel <apatel@ventanamicro.com>
Reviewed-by: Atish Patra <atishp@rivosinc.com>
2022-04-28 19:39:01 +05:30
Atish Patra
d62f6da062 lib: sbi: Implement Sstc extension
Recently, Sstc extension was ratified. It defines stimecmp which allows
the supervisor mode to directly update the timecmp value without the
need of the SBI call. The hardware also can inject the S-mode timer
interrupt direclty to the supervisor without going through the M-mode.
To maintain backward compatibility with the older software, SBI call
now uses stimecmp directly if the hardware supports.

Implement the Sstc extension.

Signed-off-by: Atish Patra <atishp@rivosinc.com>
Reviewed-by: Anup Patel <anup@brainfault.org>
2022-04-28 11:45:21 +05:30
Atish Patra
4035ae94be docs: pmu: Improve the PMU DT bindings
The current DT binding description is misleading and confusing. Clarify
the text and provide more examples.

Signed-off-by: Atish Patra <atishp@rivosinc.com>
Reviewed-by: Anup Patel <anup@brainfault.org>
2022-04-28 11:40:15 +05:30
Dmitry Dunaev
9cd95e13bb lib: sbi/hart: preserve csr validation value
The OpenSBI hart init function hart_detect_features() try to read
important CSRs but reasign the last read value to the variable that
initially contains write probe value. So for series of CSRs (like
PMPADDRx) the second CSR probe value will became the initial value of
first probing CSR. To avoid of this issue the CSR read value should be
saved in different variable. In this configuration the count of PMP
will detect rightly if any PMPADDR is hardwired to zero.

Signed-off-by: Dmitry Dunaev <dunaich@mail.ru>
Signed-off-by: Anup Patel <anup@brainfault.org>
2022-04-17 14:43:08 +05:30
Vincent Chen
c1e47d0c3f include: correct the definition of MSTATUS_VS
Accordind to the RISC-V privileged specification, the VS filed is
mstatus[10:9] instead of mstatus[24:23]. Modify the MSTATUS_VS
to the correct value.

Reported-by: I-Cheng Cheng <i-cheng.cheng@sifive.com>
Signed-off-by: Vincent Chen <vincent.chen@sifive.com>
Reviewed-by: Xiang W <wxjstz@126.com>
Reviewed-by: Anup Patel <anup@brainfault.org>
2022-04-17 14:30:19 +05:30
Zong Li
5c5cbb53a4 lib: utils/serial: support 'reg-offset' property
reg-offset property is used for offset to apply to the mapbase
from the start of the registers in 8250 UART. In Linux kernel,
it has been handled in 8250 UART driver.

dt-bindings:
<linux>/Documentation/devicetree/bindings/serial/8250.yaml

Signed-off-by: Zong Li <zong.li@sifive.com>
Reviewed-by: Anup Patel <anup@brainfault.org>
2022-04-17 13:57:48 +05:30
Mayuresh Chitale
3383d6a4d1 lib: irqchip/imsic: configure mstateen
When mstateen registers are implemented, the AIA related
configurations need to be done in mstateen for the IMSIC
initialization to succeed.

Signed-off-by: Mayuresh Chitale <mchitale@ventanamicro.com>
Reviewed-by: Xiang W <wxjstz@126.com>
Reviewed-by: Anup Patel <anup@brainfault.org>
2022-04-11 08:34:17 +05:30
Mayuresh Chitale
d44568a0f2 lib: sbi: Detect Smstateen CSRs at boot-time
Extend HART feature detection to discover Smstateen CSRs at boot-time
and configure mstateen envcfg bit depending on availability of
menvcfg CSR.

Signed-off-by: Mayuresh Chitale <mchitale@ventanamicro.com>
Reviewed-by: Xiang W <wxjstz@126.com>
Reviewed-by: Anup Patel <anup@brainfault.org>
2022-04-11 08:34:10 +05:30
Mayuresh Chitale
499601a4ff lib: sbi: Add Smstateen extension defines
Smstateen extension provides a mechanism to plug potential
covert channels which are opened by extensions that add to
processor state that may not get context-switched.

Signed-off-by: Mayuresh Chitale <mchitale@ventanamicro.com>
Reviewed-by: Xiang W <wxjstz@126.com>
Reviewed-by: Anup Patel <anup@brainfault.org>
2022-04-11 08:34:02 +05:30
Anup Patel
794986f87f lib: sbi: Enable Svpbmt extension in the menvcfg CSR
The menvcfg.PBMTE bit is read-only zero when Svpbmt extension is not
available so we try to enable menvcfg.PBMTE bit irrespective whether
Svpbmt is available or not.

Signed-off-by: Anup Patel <apatel@ventanamicro.com>
Reviewed-by: Atish Patra <atishp@rivosinc.com>
Reviewed-by: Xiang W <wxjstz@126.com>
2022-04-05 08:53:11 +05:30
Anup Patel
47d676570d lib: sbi: Enable Zicbo[m|z] extensions in the menvcfg CSR
The bits to configure/enable Zicbo[m|z] extensions in the menvcfg
CSR are WARL. We try to enable these bits irrespective whether
these extensions are available or not because writes to these
bits will be ignored if these extensions are not available.

Signed-off-by: Anup Patel <apatel@ventanamicro.com>
Reviewed-by: Atish Patra <atishp@rivosinc.com>
Reviewed-by: Xiang W <wxjstz@126.com>
2022-04-05 08:51:40 +05:30
Atish Patra
31fecad46d lib: sbi: Detect menvcfg CSR at boot time
We add the menvcfg CSR as a HART feature and detect it at boot time
using traping mechanism.

Signed-off-by: Atish Patra <atishp@rivosinc.com>
Signed-off-by: Anup Patel <apatel@ventanamicro.com>
Reviewed-by: Xiang W <wxjstz@126.com>
2022-04-05 08:50:48 +05:30
Anup Patel
722f80d8e9 include: Add defines for [m|h|s]envcfg CSRs
The latest RISC-V privileged specification introduces xenvcfg CSRs
to enable/disable certain features/extensions for lower privilege
modes. This patch adds defines for these new [m|h|s]envcfg CSRs.

Signed-off-by: Anup Patel <apatel@ventanamicro.com>
Reviewed-by: Atish Patra <atishp@rivosinc.com>
Reviewed-by: Xiang W <wxjstz@126.com>
2022-04-05 08:50:17 +05:30
Xiang W
7924a0b220 include: Use static asserts for FW_DYNAMIC_INFO_xxx_OFFSET defines
Add static detection to prevent the modification of struct fw_dynamic_info
from forgetting the modification of FW_DYNAMIC_INFO_xxx_OFFSET

Signed-off-by: Xiang W <wxjstz@126.com>
Reviewed-by: Anup Patel <anup@brainfault.org>
2022-03-27 09:44:58 +05:30
Xiang W
1b42d3ace3 include: Use static asserts for SBI_SCRATCH_xxx_OFFSET defines
Add static detection to prevent the modification of struct sbi_scratch
from forgetting the modification of SBI_SCRATCH_xxx_OFFSET

Signed-off-by: Xiang W <wxjstz@126.com>
Reviewed-by: Anup Patel <anup@brainfault.org>
2022-03-27 09:44:54 +05:30
Xiang W
555bdb1cf3 include: Use static asserts for SBI_PLATFORM_xxx_OFFSET defines
Add static detection to prevent the modification of struct sbi_platform
from forgetting the modification of SBI_PLATFORM_xxx_OFFSET

Signed-off-by: Xiang W <wxjstz@126.com>
Reviewed-by: Anup Patel <anup@brainfault.org>
2022-03-27 09:07:44 +05:30
Xiang W
d552fc8d36 lib: Add error messages via conditional compilation for the future
On 128-bit machines, sbi_load_xx/sbi_store_xx needs to be improved.
Through this conditional compile, the corresponding implementation
can be prompted to be added.

Signed-off-by: Xiang W <wxjstz@126.com>
Reviewed-by: Anup Patel <anup@brainfault.org>
2022-03-27 08:54:12 +05:30
Xiang W
b6b7220a47 firmware: Fix code for accessing hart_count and stack_size
lwu exists under the current rv64 and should also exist under the rv128
in the future, so I modified the conditions of conditional compilation
so that it can adapt to the future situation

Signed-off-by: Xiang W <wxjstz@126.com>
Reviewed-by: Anup Patel <anup@brainfault.org>
2022-03-27 08:53:27 +05:30
Xiang W
2dfbd3c0e2 lib: pmp_set/pmp_get moved errors from runtime to compile time
pmp_set/pmp_get calculates the location of the CSR register separately
through conditional compilation. In the case of non-32-bit and 64-bit,
we can report an error directly through #error without putting it at
runtime

Signed-off-by: Xiang W <wxjstz@126.com>
Reviewed-by: Anup Patel <anup@brainfault.org>
2022-03-27 08:52:19 +05:30
Alistair Francis
4998a712b2 lib: utils: serial: Initial commit of xlnx-uartlite
Initial commit of the xlnx-uartlite device and FDT support. This was
tested by running OpenSBI on a modified QEMU virt machine using the
xlnx-uartlite for serial.

Signed-off-by: Alistair Francis <alistair.francis@wdc.com>
Reviewed-by: Xiang W <wxjstz@126.com>
Reviewed-by: Anup Patel <anup@brainfault.org>
2022-02-28 09:50:09 +05:30
Anup Patel
f3f4604c19 lib: sbi: Add a simple external interrupt handling framework
Currently, the external interrupt handling is scattered between
sbi_init and sbi_trap. This patch moves all external interrupt
handling into a simple framework called sbi_irqchip.

Signed-off-by: Anup Patel <apatel@ventanamicro.com>
Reviewed-by: Xiang W <wxjstz@126.com>
Reviewed-by: Atish Patra <atishp@rivosinc.com>
2022-02-28 09:43:12 +05:30
Nikita Shubin
f2ccf2f783 lib: sbi: verbose sbi_domain_root_add_memregion
Be more verbose on region confict, print addresses in conflict.

Signed-off-by: Nikita Shubin <n.shubin@yadro.com>
Reviewed-by: Xiang W <wxjstz@126.com>
Reviewed-by: Anup Patel <anup@brainfault.org>
2022-02-15 20:59:38 +05:30
Nikita Shubin
3a69cc1487 lib: sbi: fix typo in is_region_subset
Fix typo in is_region_subset, regB_end should be calculated from regB.

Signed-off-by: Nikita Shubin <n.shubin@yadro.com>
Reviewed-by: Dong Du <Dd_nirvana@sjtu.edu.cn>
Reviewed-by: Xiang W <wxjstz@126.com>
Reviewed-by: Anup Patel <anup@brainfault.org>
2022-02-15 20:58:04 +05:30
Anup Patel
8e2ef4f7af lib: utils: Disable appropriate APLIC DT nodes in fdt_fixups()
We should disable APLIC DT nodes in fdt_fixups() which are not
accessible to the next booting stage based on currently assigned
domain.

Signed-off-by: Anup Patel <anup.patel@wdc.com>
Signed-off-by: Anup Patel <apatel@ventanamicro.com>
Reviewed-by: Atish Patra <atishp@rivosinc.com>
2022-02-15 20:39:15 +05:30
Anup Patel
34612193af lib: utils/irqchip: Add FDT based driver for APLIC
We add simple FDT irqchip driver for APLIC so that generic platform (and
other FDT based platforms) can utilize common APLIC initialization library.

Signed-off-by: Anup Patel <anup.patel@wdc.com>
Signed-off-by: Anup Patel <apatel@ventanamicro.com>
Reviewed-by: Atish Patra <atishp@rivosinc.com>
2022-02-15 20:39:01 +05:30
Anup Patel
99792653de lib: utils/irqchip: Add APLIC initialization library
We add simple APLIC initialization library which is independent of
hardware description format (FDT or ACPI). This APLIC initialization
library can be used by custom OpenSBI platform support to setup
APLIC domains.

Signed-off-by: Anup Patel <anup.patel@wdc.com>
Signed-off-by: Anup Patel <apatel@ventanamicro.com>
Reviewed-by: Atish Patra <atishp@rivosinc.com>
2022-02-15 20:37:55 +05:30
Anup Patel
7127aaaaf7 lib: utils: Disable appropriate IMSIC DT nodes in fdt_fixups()
We should disable IMSIC DT nodes in fdt_fixups() which are not
accessible to the next booting stage based on currently assigned
domain.

Signed-off-by: Anup Patel <anup.patel@wdc.com>
Signed-off-by: Anup Patel <apatel@ventanamicro.com>
Reviewed-by: Atish Patra <atishp@rivosinc.com>
2022-02-15 20:37:27 +05:30
Anup Patel
811da5c541 lib: utils/irqchip: Add FDT based driver for IMSIC
We add simple FDT irqchip driver for IMSIC so that generic platform
(and other FDT based platforms) can utilize common IMIC library.

Signed-off-by: Anup Patel <anup.patel@wdc.com>
Signed-off-by: Anup Patel <apatel@ventanamicro.com>
Reviewed-by: Atish Patra <atishp@rivosinc.com>
2022-02-15 20:37:05 +05:30
Anup Patel
9f73669959 lib: utils/irqchip: Add IMSIC library
We add simple IMSIC library which is independent of hardware description
format (FDT or ACPI). This IMSIC library can be used by custom OpenSBI
platform support to setup IMSIC for external interrupts.

Signed-off-by: Anup Patel <anup.patel@wdc.com>
Signed-off-by: Anup Patel <apatel@ventanamicro.com>
Reviewed-by: Atish Patra <atishp@rivosinc.com>
2022-02-15 20:36:24 +05:30
Anup Patel
55e79f823d lib: sbi: Enable mie.MEIE bit for IPIs based on external interrupts.
We can have IPIs based on external interrupts provided by devices
such as AIA IMSIC so we should enable mie.MEIE bit at appropriate
places in generic library.

Signed-off-by: Anup Patel <anup@brainfault.org>
Signed-off-by: Anup Patel <apatel@ventanamicro.com>
Reviewed-by: Atish Patra <atishp@rivosinc.com>
2022-02-15 20:35:45 +05:30
Anup Patel
10509405b2 include: sbi: Introduce nascent_init() platform callback
We introduce nascent_init() platform callback which will allow
platforms to do very early initialization of platform specific
per-HART CSRs and per-HART devices.

Signed-off-by: Anup Patel <anup.patel@wdc.com>
Signed-off-by: Anup Patel <apatel@ventanamicro.com>
Reviewed-by: Atish Patra <atishp@rivosinc.com>
2022-02-15 20:34:24 +05:30
Anup Patel
5f56314618 lib: utils/irqchip: Allow multiple FDT irqchip drivers
We can have multiple FDT irqchip drivers to be probed when a RISC-V
system has different types of interrupt controller in a hierarchy.

This will be certainly the case when a RISC-V system has both
RISC-V AIA IMSIC and RISC-V AIA APLIC implemented.

We extend simple FDT irqchip framework to allow multiple FDT
irqchip drivers to be used for same RISC-V platform.

Signed-off-by: Anup Patel <anup.patel@wdc.com>
Signed-off-by: Anup Patel <apatel@ventanamicro.com>
Reviewed-by: Atish Patra <atishp@rivosinc.com>
2022-02-15 20:34:08 +05:30
Anup Patel
222132f48c lib: sbi: Add sbi_trap_set_external_irqfn() API
This patch adds sbi_trap_set_external_irqfn() API which can be used by
OpenSBI platform code to set a callback function for external interrupts.
The RISC-V AIA IMSIC driver will use this API to implement inter-processor
interrupts on-top-of MSIs.

Signed-off-by: Anup Patel <anup.patel@wdc.com>
Signed-off-by: Anup Patel <apatel@ventanamicro.com>
Reviewed-by: Atish Patra <atishp@rivosinc.com>
2022-02-15 20:33:55 +05:30
Anup Patel
65b4c7c01e lib: sbi: Use AIA CSRs for local interrupts when available
We should use AIA CSRs to process local interrupts whenever AIA
is available.

Signed-off-by: Anup Patel <anup.patel@wdc.com>
Signed-off-by: Anup Patel <apatel@ventanamicro.com>
Reviewed-by: Atish Patra <atishp@rivosinc.com>
2022-02-15 20:33:31 +05:30
Anup Patel
8f96070067 lib: sbi: Detect AIA CSRs at boot-time
We extend HART feature detection to discover AIA CSRs at boot-time.

Signed-off-by: Anup Patel <anup.patel@wdc.com>
Signed-off-by: Anup Patel <apatel@ventanamicro.com>
Reviewed-by: Atish Patra <atishp@rivosinc.com>
2022-02-15 20:32:42 +05:30
Anup Patel
01250d0044 include: sbi: Add AIA related CSR defines
The RISC-V AIA specification improves handling of per-HART local
interrupts in a backward compatible manner. This patch adds defines
for the new RISC-V AIA CSRs.

Signed-off-by: Anup Patel <anup.patel@wdc.com>
Signed-off-by: Anup Patel <apatel@ventanamicro.com>
Reviewed-by: Atish Patra <atishp@rivosinc.com>
2022-02-15 20:32:07 +05:30
Jakub Luzny
ce4c0188d9 lib: utils/serial: Round UART8250 baud rate divisor to nearest integer
Previously, it was rounded down and that gives suboptimal results when
non-standard clock sources or baud rates are used.

Signed-off-by: Jakub Luzny <jakub.luzny@codasip.com>
Reviewed-by: Anup Patel <anup@brainfault.org>
2022-02-04 11:16:29 +05:30
Petro Karashchenko
6ad8917b7e lib: fix compilation when strings.h is included
In a systems that provide strings.h and it is included
together with sbi_bitops.h the compilation error appears.
The ffs() and fls() are provided by strings.h

Signed-off-by: Petro Karashchenko <petro.karashchenko@gmail.com>
Reviewed-by: Anup Patel <anup@brainfault.org>
2022-02-04 11:04:19 +05:30
Aurelien Jarno
5d53b55aa7 Makefile: fix build with binutils 2.38
From version 2.38, binutils default to ISA spec version 20191213. This
means that the csr read/write (csrr*/csrw*) instructions and fence.i
instruction has separated from the `I` extension, become two standalone
extensions: Zicsr and Zifencei. As the kernel uses those instruction,
this causes the following build failure:

 CC        lib/sbi/sbi_tlb.o
<<BUILDDIR>>/lib/sbi/sbi_tlb.c: Assembler messages:
<<BUILDDIR>>/lib/sbi/sbi_tlb.c:190: Error: unrecognized opcode `fence.i'
make: *** [Makefile:431: <<BUILDDIR>>/build/lib/sbi/sbi_tlb.o] Error 1

The fix is to specify those extensions explicitly in -march. However as
older binutils version do not support this, we first need to detect
that.

Signed-off-by: Aurelien Jarno <aurelien@aurel32.net>
Reviewed-by: Bin Meng <bmeng.cn@gmail.com>
Tested-by: Alexandre Ghiti <alexandre.ghiti@canonical.com>
Reviewed-by: Anup Patel <anup@brainfault.org>
2022-02-04 10:47:24 +05:30
Atish Patra
a26dc609df lib: sbi: Disable interrupt and inhibit counting in M-mode during init
Currently, the mhpmevent CSRs are untouched during hart init during
cold/warm boot. Ideally, we should clear out all the bits except
overflow and MINH bit. That is required to disable overflow
interrupt and inhibit counting in M-mode to avoid any spurious
interrupts before perf start.

Signed-off-by: Atish Patra <atishp@rivosinc.com>
Reviewed-by: Anup Patel <anup@brainfault.org>
2022-02-04 10:10:28 +05:30
Atish Patra
3b7c204dca lib: sbi: Disable interrupt during config matching
PMU overflow interrupt should be disabled durinig initial configuration of
counters. They should be enabled while starting counters.

Fixes: 730f01bb41 ("lib: sbi: Support sscofpmf extension in OpenSBI")
Signed-off-by: Atish Patra <atishp@rivosinc.com>
Reviewed-by: Anup Patel <anup@brainfault.org>
2022-02-04 10:08:57 +05:30
Atish Patra
632f59392b lib: sbi: Map only the counters enabled in hardware
The counter mapping in DT may be incorrect if all the counters specified
in the mapping are actually not physically present in the hardware.
OpenSBI should only keep a mapping of counters enabled in hardware and
defined in DT. This assume that all the programmable hpmcounters are
consecutive as it doesn't make sense to build a system with sparse
hpmcounters.

Signed-off-by: Atish Patra <atishp@rivosinc.com>
Reviewed-by: Anup Patel <anup@brainfault.org>
2022-02-04 10:07:07 +05:30
Jukka Laitinen
5d025eb235 lib: fix pointer of type 'void *' used in arithmetic
Using "void *" in arithmetic causes errors with strict compiler settings:
"error: pointer of type 'void *' used in arithmetic [-Werror=pointer-arith]"

Avoid these by calculating on "char *" where 1-byte data size is assumed.

Signed-off-by: Jukka Laitinen <jukkax@ssrc.tii.ae>
Reviewed-by: Dong Du <Dd_nirvana@sjtu.edu.cn>
Reviewed-by: Xiang W <wxjstz@126.com>
Reviewed-by: Anup Patel <anup@brainfault.org>
2022-01-21 21:58:12 +05:30
Aurelien Jarno
fb688d9e9d platform: sifive_fu740: fix reset when watchdog is running
When the watchdog is running the HiFive Unmatched board does not reboot
properly and shuts down itself a few seconds after reboot, in the early
stages of the u-boot loading. On a Linux kernel this happens when the
da9063_wdt module is loaded. This does not happen if the module is
unloaded before reboot or if the watchdog module is loaded with
"stop_on_reboot=1".

Fix that by stopping the watchdog before attempting to reset the board.
This is done by zeroing the TWDSCALE field of CONTROL_D register, unless
it was already set to 0.

Reported-by: Tianon Gravi <tianon@debian.org>
Signed-off-by: Aurelien Jarno <aurelien@aurel32.net>
Reviewed-by: Nikita Shubin <n.shubin@yadro.com>
Tested-by: Nikita Shubin <n.shubin@yadro.com>
Reviewed-by: Anup Patel <anup@brainfault.org>
2022-01-21 21:44:57 +05:30
Aurelien Jarno
8257262dbf platform: sifive_fu740: do not use a global in da9063_reset/shutdown
da9063_reset() and da9063_shutdown() take the chip address in argument
(like similar functions), but in practice use the da9063 global struct
instead. Fix that.

Signed-off-by: Aurelien Jarno <aurelien@aurel32.net>
Reviewed-by: Nikita Shubin <n.shubin@yadro.com>
Reviewed-by: Anup Patel <anup@brainfault.org>
Reviewed-by: Xiang W <wxjstz@126.com>
2022-01-21 21:41:33 +05:30
Anup Patel
6dde43584f lib: utils/sys: Extend HTIF library to allow custom base address
Some of RISC-V emulators provide HTIF at fixed base address so for
such emulators users have to hard-code HTIF base address in the
linker script.

To address this problem, we let users optionally provide fixed HTIF
base address via platform support (or device tree).

Signed-off-by: Anup Patel <apatel@ventanamicro.com>
Reviewed-by: Dong Du <Dd_nirvana@sjtu.edu.cn>
Reviewed-by: Atish Patra <atishp@rivosinc.com>
2022-01-11 18:17:49 +05:30
Anup Patel
5b9960379f lib: utils/ipi: Fix size check in aclint_mswi_cold_init()
Currently, the ACLINT MSWI size check is forcing size to be at least
0x4000. This is inappropriate check because most systems will never
utilize full 16KB for a single ACLINT MSWI device so instead we should
check that ACLINT MSWI size is enough for on the associated HARTs.

Signed-off-by: Anup Patel <apatel@ventanamicro.com>
Reviewed-by: Dong Du <Dd_nirvana@sjtu.edu.cn>
Reviewed-by: Alistair Francis <alistair.francis@wdc.com>
2022-01-11 18:17:07 +05:30
233 changed files with 18351 additions and 2306 deletions

2
.gitignore vendored
View File

@@ -9,3 +9,5 @@ install/
# Development friendly files
tags
cscope*
*.swp

25
Kconfig Normal file
View File

@@ -0,0 +1,25 @@
# SPDX-License-Identifier: BSD-2-Clause
mainmenu "OpenSBI $(OPENSBI_PLATFORM) Configuration"
config OPENSBI_SRC_DIR
string
option env="OPENSBI_SRC_DIR"
config OPENSBI_PLATFORM
string
option env="OPENSBI_PLATFORM"
config OPENSBI_PLATFORM_SRC_DIR
string
option env="OPENSBI_PLATFORM_SRC_DIR"
menu "Platform Options"
source "$(OPENSBI_PLATFORM_SRC_DIR)/Kconfig"
endmenu
source "$(OPENSBI_SRC_DIR)/lib/sbi/Kconfig"
source "$(OPENSBI_SRC_DIR)/lib/utils/Kconfig"
source "$(OPENSBI_SRC_DIR)/firmware/Kconfig"

158
Makefile
View File

@@ -47,11 +47,14 @@ ifdef PLATFORM_DIR
platform_parent_dir=$(platform_dir_path)
else
PLATFORM=$(shell basename $(platform_dir_path))
platform_parent_dir=$(subst $(PLATFORM),,$(platform_dir_path))
platform_parent_dir=$(shell realpath ${platform_dir_path}/..)
endif
else
platform_parent_dir=$(src_dir)/platform
endif
ifndef PLATFORM_DEFCONFIG
PLATFORM_DEFCONFIG=defconfig
endif
# Check if verbosity is ON for build process
CMD_PREFIX_DEFAULT := @
@@ -70,6 +73,20 @@ export libsbi_dir=$(CURDIR)/lib/sbi
export libsbiutils_dir=$(CURDIR)/lib/utils
export firmware_dir=$(CURDIR)/firmware
# Setup variables for kconfig
ifdef PLATFORM
export PYTHONDONTWRITEBYTECODE=1
export KCONFIG_DIR=$(platform_build_dir)/kconfig
export KCONFIG_AUTOLIST=$(KCONFIG_DIR)/auto.list
export KCONFIG_AUTOHEADER=$(KCONFIG_DIR)/autoconf.h
export KCONFIG_AUTOCMD=$(KCONFIG_DIR)/auto.conf.cmd
export KCONFIG_CONFIG=$(KCONFIG_DIR)/.config
# Additional exports for include paths in Kconfig files
export OPENSBI_SRC_DIR=$(src_dir)
export OPENSBI_PLATFORM=$(PLATFORM)
export OPENSBI_PLATFORM_SRC_DIR=$(platform_src_dir)
endif
# Find library version
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 "define OPENSBI_VERSION_MINOR" $(include_dir)/sbi/sbi_version.h | sed 's/.*MINOR.*\([0-9][0-9]*\)/\1/'`
@@ -153,6 +170,9 @@ OPENSBI_LD_PIE := $(shell $(CC) $(CLANG_TARGET) $(RELAX_FLAG) $(USE_LD_FLAG) -fP
# Check whether the compiler supports -m(no-)save-restore
CC_SUPPORT_SAVE_RESTORE := $(shell $(CC) $(CLANG_TARGET) $(RELAX_FLAG) -nostdlib -mno-save-restore -x c /dev/null -o /dev/null 2>&1 | grep "\-save\-restore" >/dev/null && echo n || echo y)
# Check whether the assembler and the compiler support the Zicsr and Zifencei extensions
CC_SUPPORT_ZICSR_ZIFENCEI := $(shell $(CC) $(CLANG_TARGET) $(RELAX_FLAG) -nostdlib -march=rv$(OPENSBI_CC_XLEN)imafd_zicsr_zifencei -x c /dev/null -o /dev/null 2>&1 | grep "zicsr\|zifencei" > /dev/null && echo n || echo y)
# Build Info:
# OPENSBI_BUILD_TIME_STAMP -- the compilation time stamp
# OPENSBI_BUILD_COMPILER_VERSION -- the compiler version info
@@ -180,12 +200,38 @@ libsbi-object-mks=$(shell if [ -d $(libsbi_dir) ]; then find $(libsbi_dir) -inam
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)
# Include platform specifig config.mk
# The "make all" rule should always be first rule
.PHONY: all
all:
# Include platform specific .config
ifdef PLATFORM
include $(platform_src_dir)/config.mk
.PHONY: menuconfig
menuconfig: $(platform_src_dir)/Kconfig $(src_dir)/Kconfig
$(CMD_PREFIX)mkdir -p $(KCONFIG_DIR)
$(CMD_PREFIX)$(src_dir)/scripts/Kconfiglib/menuconfig.py $(src_dir)/Kconfig
$(CMD_PREFIX)$(src_dir)/scripts/Kconfiglib/genconfig.py --header-path $(KCONFIG_AUTOHEADER) --sync-deps $(KCONFIG_DIR) --file-list $(KCONFIG_AUTOLIST) $(src_dir)/Kconfig
.PHONY: savedefconfig
savedefconfig: $(platform_src_dir)/Kconfig $(src_dir)/Kconfig
$(CMD_PREFIX)mkdir -p $(KCONFIG_DIR)
$(CMD_PREFIX)$(src_dir)/scripts/Kconfiglib/savedefconfig.py --kconfig $(src_dir)/Kconfig --out $(KCONFIG_DIR)/defconfig
$(KCONFIG_CONFIG): $(platform_src_dir)/configs/$(PLATFORM_DEFCONFIG) $(platform_src_dir)/Kconfig $(src_dir)/Kconfig
$(CMD_PREFIX)mkdir -p $(KCONFIG_DIR)
$(CMD_PREFIX)$(src_dir)/scripts/Kconfiglib/defconfig.py --kconfig $(src_dir)/Kconfig $(platform_src_dir)/configs/$(PLATFORM_DEFCONFIG)
$(CMD_PREFIX)$(src_dir)/scripts/Kconfiglib/genconfig.py --header-path $(KCONFIG_AUTOHEADER) --sync-deps $(KCONFIG_DIR) --file-list $(KCONFIG_AUTOLIST) $(src_dir)/Kconfig
$(KCONFIG_AUTOCMD): $(KCONFIG_CONFIG)
$(CMD_PREFIX)mkdir -p $(KCONFIG_DIR)
$(CMD_PREFIX)printf "%s: " $(KCONFIG_CONFIG) > $(KCONFIG_AUTOCMD)
$(CMD_PREFIX)cat $(KCONFIG_AUTOLIST) | tr '\n' ' ' >> $(KCONFIG_AUTOCMD)
include $(KCONFIG_CONFIG)
include $(KCONFIG_AUTOCMD)
endif
# Include all object.mk files
# Include all objects.mk files
ifdef PLATFORM
include $(platform-object-mks)
endif
@@ -195,8 +241,8 @@ include $(firmware-object-mks)
# Setup list of objects
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
libsbiutils-objs-path-y=$(foreach obj,$(libsbiutils-objs-y),$(platform_build_dir)/lib/utils/$(obj))
platform-objs-path-y=$(foreach obj,$(platform-objs-y),$(platform_build_dir)/$(obj))
firmware-bins-path-y=$(foreach bin,$(firmware-bins-y),$(platform_build_dir)/firmware/$(bin))
endif
@@ -223,7 +269,11 @@ ifndef PLATFORM_RISCV_ABI
endif
ifndef PLATFORM_RISCV_ISA
ifneq ($(PLATFORM_RISCV_TOOLCHAIN_DEFAULT), 1)
PLATFORM_RISCV_ISA = rv$(PLATFORM_RISCV_XLEN)imafdc
ifeq ($(CC_SUPPORT_ZICSR_ZIFENCEI), y)
PLATFORM_RISCV_ISA = rv$(PLATFORM_RISCV_XLEN)imafdc_zicsr_zifencei
else
PLATFORM_RISCV_ISA = rv$(PLATFORM_RISCV_XLEN)imafdc
endif
else
PLATFORM_RISCV_ISA = $(OPENSBI_CC_ISA)
endif
@@ -273,6 +323,9 @@ ifeq ($(BUILD_INFO),y)
GENFLAGS += -DOPENSBI_BUILD_TIME_STAMP="\"$(OPENSBI_BUILD_TIME_STAMP)\""
GENFLAGS += -DOPENSBI_BUILD_COMPILER_VERSION="\"$(OPENSBI_BUILD_COMPILER_VERSION)\""
endif
ifdef PLATFORM
GENFLAGS += -include $(KCONFIG_AUTOHEADER)
endif
GENFLAGS += $(libsbiutils-genflags-y)
GENFLAGS += $(platform-genflags-y)
GENFLAGS += $(firmware-genflags-y)
@@ -397,66 +450,73 @@ compile_d2c = $(CMD_PREFIX)mkdir -p `dirname $(1)`; \
$(if $($(2)-varprefix-$(3)),$(eval D2C_NAME_PREFIX := $($(2)-varprefix-$(3))),$(eval D2C_NAME_PREFIX := $(5))) \
$(if $($(2)-padding-$(3)),$(eval D2C_PADDING_BYTES := $($(2)-padding-$(3))),$(eval D2C_PADDING_BYTES := 0)) \
$(src_dir)/scripts/d2c.sh -i $(6) -a $(D2C_ALIGN_BYTES) -p $(D2C_NAME_PREFIX) -t $(D2C_PADDING_BYTES) > $(1)
compile_carray = $(CMD_PREFIX)mkdir -p `dirname $(1)`; \
echo " CARRAY $(subst $(build_dir)/,,$(1))"; \
$(eval CARRAY_VAR_LIST := $(carray-$(subst .c,,$(shell basename $(1)))-y)) \
$(src_dir)/scripts/carray.sh -i $(2) -l "$(CARRAY_VAR_LIST)" > $(1)
compile_gen_dep = $(CMD_PREFIX)mkdir -p `dirname $(1)`; \
echo " GEN-DEP $(subst $(build_dir)/,,$(1))"; \
echo "$(1:.dep=$(2)): $(3)" >> $(1)
targets-y = $(build_dir)/lib/libsbi.a
targets-y += $(build_dir)/lib/libsbiutils.a
ifdef PLATFORM
targets-y += $(platform_build_dir)/lib/libplatsbi.a
endif
targets-y += $(firmware-bins-path-y)
# Default rule "make" should always be first rule
# The default "make all" rule
.PHONY: all
all: $(targets-y)
# Preserve all intermediate files
.SECONDARY:
# Rules for lib/sbi sources
$(build_dir)/lib/libsbi.a: $(libsbi-objs-path-y)
$(call compile_ar,$@,$^)
$(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,$@,$^)
$(build_dir)/%.dep: $(src_dir)/%.c
$(build_dir)/%.dep: $(src_dir)/%.carray $(KCONFIG_CONFIG)
$(call compile_gen_dep,$@,.c,$< $(KCONFIG_CONFIG))
$(call compile_gen_dep,$@,.o,$(@:.dep=.c))
$(build_dir)/%.c: $(src_dir)/%.carray
$(call compile_carray,$@,$<)
$(build_dir)/%.dep: $(src_dir)/%.c $(KCONFIG_CONFIG)
$(call compile_cc_dep,$@,$<)
$(build_dir)/%.o: $(src_dir)/%.c
$(call compile_cc,$@,$<)
$(build_dir)/%.o: $(build_dir)/%.c
$(call compile_cc,$@,$<)
ifeq ($(BUILD_INFO),y)
$(build_dir)/lib/sbi/sbi_init.o: $(libsbi_dir)/sbi_init.c FORCE
$(call compile_cc,$@,$<)
endif
$(build_dir)/%.dep: $(src_dir)/%.S
$(build_dir)/%.dep: $(src_dir)/%.S $(KCONFIG_CONFIG)
$(call compile_as_dep,$@,$<)
$(build_dir)/%.o: $(src_dir)/%.S
$(call compile_as,$@,$<)
$(platform_build_dir)/%.bin: $(platform_build_dir)/%.elf
$(call compile_objcopy,$@,$<)
# Rules for platform sources
$(platform_build_dir)/%.dep: $(platform_src_dir)/%.carray $(KCONFIG_CONFIG)
$(call compile_gen_dep,$@,.c,$< $(KCONFIG_CONFIG))
$(call compile_gen_dep,$@,.o,$(@:.dep=.c))
$(platform_build_dir)/%.elf: $(platform_build_dir)/%.o $(platform_build_dir)/%.elf.ld $(platform_build_dir)/lib/libplatsbi.a
$(call compile_elf,$@,$@.ld,$< $(platform_build_dir)/lib/libplatsbi.a)
$(platform_build_dir)/%.c: $(platform_src_dir)/%.carray
$(call compile_carray,$@,$<)
$(platform_build_dir)/%.ld: $(src_dir)/%.ldS
$(call compile_cpp,$@,$<)
$(platform_build_dir)/%.dep: $(platform_src_dir)/%.c
$(platform_build_dir)/%.dep: $(platform_src_dir)/%.c $(KCONFIG_CONFIG)
$(call compile_cc_dep,$@,$<)
$(platform_build_dir)/%.o: $(platform_src_dir)/%.c
$(call compile_cc,$@,$<)
$(platform_build_dir)/%.o: $(platform_build_dir)/%.c
$(platform_build_dir)/%.o: $(platform_src_dir)/%.c $(KCONFIG_CONFIG)
$(call compile_cc,$@,$<)
$(platform_build_dir)/%.dep: $(platform_src_dir)/%.S
@@ -465,8 +525,8 @@ $(platform_build_dir)/%.dep: $(platform_src_dir)/%.S
$(platform_build_dir)/%.o: $(platform_src_dir)/%.S
$(call compile_as,$@,$<)
$(platform_build_dir)/%.dep: $(platform_src_dir)/%.dts
$(call compile_gen_dep,$@,.dtb,$<)
$(platform_build_dir)/%.dep: $(platform_src_dir)/%.dts $(KCONFIG_CONFIG)
$(call compile_gen_dep,$@,.dtb,$< $(KCONFIG_CONFIG))
$(call compile_gen_dep,$@,.c,$(@:.dep=.dtb))
$(call compile_gen_dep,$@,.o,$(@:.dep=.c))
@@ -476,13 +536,30 @@ $(platform_build_dir)/%.c: $(platform_build_dir)/%.dtb
$(platform_build_dir)/%.dtb: $(platform_src_dir)/%.dts
$(call compile_dts,$@,$<)
$(platform_build_dir)/%.dep: $(src_dir)/%.c
# Rules for lib/utils and firmware sources
$(platform_build_dir)/%.bin: $(platform_build_dir)/%.elf
$(call compile_objcopy,$@,$<)
$(platform_build_dir)/%.elf: $(platform_build_dir)/%.o $(platform_build_dir)/%.elf.ld $(platform_build_dir)/lib/libplatsbi.a
$(call compile_elf,$@,$@.ld,$< $(platform_build_dir)/lib/libplatsbi.a)
$(platform_build_dir)/%.ld: $(src_dir)/%.ldS
$(call compile_cpp,$@,$<)
$(platform_build_dir)/%.dep: $(src_dir)/%.carray $(KCONFIG_CONFIG)
$(call compile_gen_dep,$@,.c,$< $(KCONFIG_CONFIG))
$(call compile_gen_dep,$@,.o,$(@:.dep=.c))
$(platform_build_dir)/%.c: $(src_dir)/%.carray
$(call compile_carray,$@,$<)
$(platform_build_dir)/%.dep: $(src_dir)/%.c $(KCONFIG_CONFIG)
$(call compile_cc_dep,$@,$<)
$(platform_build_dir)/%.o: $(src_dir)/%.c
$(call compile_cc,$@,$<)
$(platform_build_dir)/%.dep: $(src_dir)/%.S
$(platform_build_dir)/%.dep: $(src_dir)/%.S $(KCONFIG_CONFIG)
$(call compile_as_dep,$@,$<)
$(platform_build_dir)/%.o: $(src_dir)/%.S
@@ -526,7 +603,6 @@ endif
endif
install_targets-y = install_libsbi
install_targets-y += install_libsbiutils
ifdef PLATFORM
install_targets-y += install_libplatsbi
install_targets-y += install_firmwares
@@ -541,17 +617,12 @@ install_libsbi: $(build_dir)/lib/libsbi.a
$(call inst_header_dir,$(install_root_dir)/$(install_include_path),$(include_dir)/sbi)
$(call inst_file,$(install_root_dir)/$(install_lib_path)/libsbi.a,$(build_dir)/lib/libsbi.a)
.PHONY: install_libsbiutils
install_libsbiutils: $(build_dir)/lib/libsbiutils.a
$(call inst_header_dir,$(install_root_dir)/$(install_include_path),$(include_dir)/sbi_utils)
$(call inst_file,$(install_root_dir)/$(install_lib_path)/libsbiutils.a,$(build_dir)/lib/libsbiutils.a)
.PHONY: install_libplatsbi
install_libplatsbi: $(platform_build_dir)/lib/libplatsbi.a $(build_dir)/lib/libsbi.a $(build_dir)/lib/libsbiutils.a
install_libplatsbi: $(platform_build_dir)/lib/libplatsbi.a $(build_dir)/lib/libsbi.a
$(call inst_file,$(install_root_dir)/$(install_lib_path)/opensbi/$(platform_subdir)/lib/libplatsbi.a,$(platform_build_dir)/lib/libplatsbi.a)
.PHONY: install_firmwares
install_firmwares: $(platform_build_dir)/lib/libplatsbi.a $(build_dir)/lib/libsbi.a $(build_dir)/lib/libsbiutils.a $(firmware-bins-path-y)
install_firmwares: $(platform_build_dir)/lib/libplatsbi.a $(build_dir)/lib/libsbi.a $(firmware-bins-path-y)
$(call inst_file_list,$(install_root_dir),$(build_dir),$(install_firmware_path)/$(platform_subdir)/firmware,$(firmware-elfs-path-y))
$(call inst_file_list,$(install_root_dir),$(build_dir),$(install_firmware_path)/$(platform_subdir)/firmware,$(firmware-bins-path-y))
@@ -559,6 +630,17 @@ install_firmwares: $(platform_build_dir)/lib/libplatsbi.a $(build_dir)/lib/libsb
install_docs: $(build_dir)/docs/latex/refman.pdf
$(call inst_file,$(install_root_dir)/$(install_docs_path)/refman.pdf,$(build_dir)/docs/latex/refman.pdf)
.PHONY: cscope
cscope:
$(CMD_PREFIX)find \
"$(src_dir)/firmware" \
"$(src_dir)/include" \
"$(src_dir)/lib" \
"$(platform_src_dir)" \
-name "*.[chS]" -print > cscope.files
$(CMD_PREFIX)echo "$(KCONFIG_AUTOHEADER)" >> cscope.files
$(CMD_PREFIX)cscope -bkq -i cscope.files -f cscope.out
# Rule for "make clean"
.PHONY: clean
clean:
@@ -588,6 +670,8 @@ ifeq ($(install_root_dir),$(install_root_dir_default)/usr)
$(if $(V), @echo " RM $(install_root_dir_default)")
$(CMD_PREFIX)rm -rf $(install_root_dir_default)
endif
$(if $(V), @echo " RM $(src_dir)/cscope*")
$(CMD_PREFIX)rm -f $(src_dir)/cscope*
.PHONY: FORCE
FORCE:

View File

@@ -92,8 +92,8 @@ N.B. Any S-mode boot loader (i.e. U-Boot) doesn't need to support HSM extension,
as it doesn't need to boot all the harts. The operating system should be
capable enough to bring up all other non-booting harts using HSM extension.
Required Toolchain
------------------
Required Toolchain and Packages
-------------------------------
OpenSBI can be compiled natively or cross-compiled on a x86 host. For
cross-compilation, you can build your own toolchain, download a prebuilt one
@@ -115,6 +115,14 @@ triple is used (e.g. *-target riscv64-unknown-elf*).
Please note that only a 64-bit version of the toolchain is available in
the Bootlin toolchain repository for now.
In addition to a toolchain, OpenSBI also requires the following packages on
the host:
1. device-tree-compiler: The device tree compiler for compiling device
tree sources (DTS files).
2. python3: The python 3.0 (or compatible) language support for various
scripts.
Building and Installing the OpenSBI Platform-Independent Library
----------------------------------------------------------------
@@ -196,6 +204,19 @@ top-level make command line. These options, such as *PLATFORM_<xyz>* or
*docs/platform/<platform_name>.md* files and
*docs/firmware/<firmware_name>.md* files.
All OpenSBI platforms support Kconfig style build-time configuration. Users
can change the build-time configuration of a platform using a graphical
interface as follows:
```
make PLATFORM=<platform_subdir> menuconfig
```
Alternately, an OpenSBI platform can have multiple default configurations
and users can select a custom default configuration as follows:
```
make PLATFORM=<platform_subdir> PLATFORM_DEFCONFIG=<platform_custom_defconfig>
```
Building 32-bit / 64-bit OpenSBI Images
---------------------------------------
By default, building OpenSBI generates 32-bit or 64-bit images based on the

View File

@@ -29,7 +29,7 @@ and "top:".
5. Maintainers should use "Rebase and Merge" when using GitHub to merge pull
requests to avoid creating unnecessary merge commits.
6. Maintainers should avoid creating branches directly in the main
riscv/opensbi repository. Instead prefer using a fork of the 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.
7. A maintainer cannot merge his own pull requests in the riscv/opensbi main
repository.

View File

@@ -2,7 +2,7 @@ OpenSBI Domain Support
======================
An OpenSBI domain is a system-level partition (subset) of underlying hardware
having it's own memory regions (RAM and MMIO devices) and HARTs. The OpenSBI
having its own memory regions (RAM and MMIO devices) and HARTs. The OpenSBI
will try to achieve secure isolation between domains using RISC-V platform
features such as PMP, ePMP, IOPMP, SiFive Shield, etc.
@@ -15,7 +15,7 @@ Important entities which help implement OpenSBI domain support are:
Each HART of a RISC-V platform must have an OpenSBI domain assigned to it.
The OpenSBI platform support is responsible for populating domains and
providing HART id to domain mapping. The OpenSBI domain support will by
default assign **the ROOT domain** to all HARTs of a RISC-V platform so
default assign **the ROOT domain** to all HARTs of a RISC-V platform, so
it is not mandatory for the OpenSBI platform support to populate domains.
Domain Memory Region
@@ -29,7 +29,7 @@ OpenSBI and has following details:
* **base** - The base address of a memory region is **2 ^ order**
aligned start address
* **flags** - The flags of a memory region represent memory type (i.e.
RAM or MMIO) and allowed accesses (i.e. READ, WRITE, EXECUTE, etc)
RAM or MMIO) and allowed accesses (i.e. READ, WRITE, EXECUTE, etc.)
Domain Instance
---------------

View File

@@ -53,7 +53,7 @@ the booting stage to follow OpenSBI firmware.
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
case, a *FW_PAYLOAD* firmware allows embedding a flattened device tree in the
.text section of the final firmware.
.rodata section of the final firmware.
Firmware Configuration and Compilation
--------------------------------------

View File

@@ -20,7 +20,7 @@ the booting stage binary to follow OpenSBI firmware.
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
2. Specifying `FW_DYNAMIC=y` in the target platform *objects.mk* configuration
file.
The compiled *FW_DYNAMIC* firmware ELF file is named *fw_dynamic.elf*. It's
@@ -31,6 +31,6 @@ directory.
*FW_DYNAMIC* Firmware Configuration Options
-------------------------------------------
The *FW_DYNAMIC* firmware does not requires any platform specific configuration
The *FW_DYNAMIC* firmware does not require any platform specific configuration
parameters because all required information is passed by previous booting stage
at runtime via *struct fw_dynamic_info*.

View File

@@ -15,7 +15,7 @@ and the booting stage binary to follow the OpenSBI firmware.
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.
2. Specifying `FW_JUMP=y` in the target platform *config.mk* configuration file.
2. Specifying `FW_JUMP=y` in the target platform *objects.mk* configuration file.
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
@@ -26,7 +26,7 @@ build directory under the *build/platform/<platform_subdir>/firmware* directory.
To operate correctly, a *FW_JUMP* firmware requires some configuration
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 *objects.mk* configuration file. The possible parameters are as
follows:
* **FW_JUMP_ADDR** - Address of the entry point of the booting stage to be
@@ -41,6 +41,22 @@ follows:
provided, then the OpenSBI firmware will pass the FDT address passed by the
previous booting stage to the next booting stage.
When using the default *FW_JUMP_FDT_ADDR* with *PLATFORM=generic*, you must
ensure *FW_JUMP_FDT_ADDR* is set high enough to avoid overwriting the kernel.
You can use the following method.
```
${CROSS_COMPILE}objdump -h $KERNEL_ELF | sort -k 5,5 | awk -n '/^ +[0-9]+ /\
{addr="0x"$3; size="0x"$5; printf "0x""%x\n",addr+size}' \
| (( `tail -1` > 0x2200000 )) && echo fdt overlaps kernel,\
increase FW_JUMP_FDT_ADDR
${LLVM}objdump -h --show-lma $KERNEL_ELF | sort -k 5,5 | \
awk -n '/^ +[0-9]+ / {addr="0x"$3; size="0x"$5; printf "0x""%x\n",addr+size}'\
| (( `tail -1` > 0x2200000 )) && echo fdt overlaps kernel,\
increase FW_JUMP_FDT_ADDR
```
*FW_JUMP* Example
-----------------

View File

@@ -12,7 +12,7 @@ firmware and the booting stage to follow OpenSBI firmware.
A *FW_PAYLOAD* firmware is also useful for cases where the booting stage prior
to the OpenSBI firmware does not pass a *flattened device tree (FDT file)*. In
such a case, a *FW_PAYLOAD* firmware allows embedding a flattened device tree
in the .text section of the final firmware.
in the .rodata section of the final firmware.
Enabling *FW_PAYLOAD* compilation
---------------------------------
@@ -20,7 +20,7 @@ Enabling *FW_PAYLOAD* compilation
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.
2. Specifying `FW_PAYLOAD=y` in the target platform *config.mk* configuration
2. Specifying `FW_PAYLOAD=y` in the target platform *objects.mk* configuration
file.
The compiled *FW_PAYLOAD* firmware ELF file is named *fw_jump.elf*. Its
@@ -33,7 +33,7 @@ Configuration Options
A *FW_PAYLOAD* firmware is built according to configuration parameters and
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 *objects.mk* configuration
file. The parameters currently defined are as follows:
* **FW_PAYLOAD_OFFSET** - Offset from *FW_TEXT_BASE* where the payload binary

View File

@@ -8,11 +8,7 @@ OpenSBI provides two types of static libraries:
hooks for the execution of this interface must be provided by the firmware or
bootloader linking with this library. This library is installed as
*<install_directory>/lib/libsbi.a*
2. *libsbiutils.a* - A static library that will contain all common code required
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
2. *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
*<install_directory>/platform/<platform_subdir>/lib/libplatsbi.a*
@@ -77,7 +73,7 @@ firmware drivers based on the external firmware architecture.
**OPENSBI_EXTERNAL_SBI_TYPES** identifier is introduced to *sbi_types.h* for selecting
external header file during the build preprocess in order to define OpensSBI data types
based on external firmware data type binding.
For example, *bool* is declared as *int* in sbi_types.h. However in EDK2 build system,
For example, *bool* is declared as *int* in sbi_types.h. However, in EDK2 build system,
*bool* is declared as *BOOLEAN* which is defined as *unsigned char* data type.
External firmware can define **OPENSBI_EXTERNAL_SBI_TYPES** in CFLAGS and specify it to the

View File

@@ -8,7 +8,7 @@ AHB/APB IPs suites a majority embedded systems, and the verified platform serves
as a starting point to jump start SoC designs.
To build platform specific library and firmwares, provide the
*PLATFORM=andes/ae350* parameter to the top level make command.
*PLATFORM=generic* parameter to the top level `make` command.
Platform Options
----------------
@@ -18,13 +18,190 @@ The Andes AE350 platform does not have any platform-specific options.
Building Andes AE350 Platform
-----------------------------
To use Linux v5.2 should be used to build Andes AE350 OpenSBI binaries by using
the compile time option FW_FDT_PATH.
AE350's dts is included in https://github.com/andestech/linux/tree/ast-v3_2_0-release-public
AE350's dts is included in https://github.com/andestech/linux/tree/RISCV-Linux-5.4-ast-v5_1_0-branch
**Linux Kernel Payload**
```
make PLATFORM=andes/ae350 FW_PAYLOAD_PATH=<linux_build_directory>/arch/riscv/boot/Image FW_FDT_PATH=<ae350.dtb path>
make PLATFORM=generic FW_PAYLOAD_PATH=<linux_build_directory>/arch/riscv/boot/Image FW_FDT_PATH=<ae350.dtb path>
```
DTS Example: (Quad-core AX45MP)
-------------------------------
```
compatible = "andestech,ae350";
cpus {
#address-cells = <1>;
#size-cells = <0>;
timebase-frequency = <60000000>;
CPU0: cpu@0 {
device_type = "cpu";
reg = <0>;
status = "okay";
compatible = "riscv";
riscv,isa = "rv64imafdc";
riscv,priv-major = <1>;
riscv,priv-minor = <10>;
mmu-type = "riscv,sv48";
clock-frequency = <60000000>;
i-cache-size = <0x8000>;
i-cache-sets = <256>;
i-cache-line-size = <64>;
i-cache-block-size = <64>;
d-cache-size = <0x8000>;
d-cache-sets = <128>;
d-cache-line-size = <64>;
d-cache-block-size = <64>;
next-level-cache = <&L2>;
CPU0_intc: interrupt-controller {
#interrupt-cells = <1>;
interrupt-controller;
compatible = "riscv,cpu-intc";
};
};
CPU1: cpu@1 {
device_type = "cpu";
reg = <1>;
status = "okay";
compatible = "riscv";
riscv,isa = "rv64imafdc";
riscv,priv-major = <1>;
riscv,priv-minor = <10>;
mmu-type = "riscv,sv48";
clock-frequency = <60000000>;
i-cache-size = <0x8000>;
i-cache-sets = <256>;
i-cache-line-size = <64>;
i-cache-block-size = <64>;
d-cache-size = <0x8000>;
d-cache-sets = <128>;
d-cache-line-size = <64>;
d-cache-block-size = <64>;
next-level-cache = <&L2>;
CPU1_intc: interrupt-controller {
#interrupt-cells = <1>;
interrupt-controller;
compatible = "riscv,cpu-intc";
};
};
CPU2: cpu@2 {
device_type = "cpu";
reg = <2>;
status = "okay";
compatible = "riscv";
riscv,isa = "rv64imafdc";
riscv,priv-major = <1>;
riscv,priv-minor = <10>;
mmu-type = "riscv,sv48";
clock-frequency = <60000000>;
i-cache-size = <0x8000>;
i-cache-sets = <256>;
i-cache-line-size = <64>;
i-cache-block-size = <64>;
d-cache-size = <0x8000>;
d-cache-sets = <128>;
d-cache-line-size = <64>;
d-cache-block-size = <64>;
next-level-cache = <&L2>;
CPU2_intc: interrupt-controller {
#interrupt-cells = <1>;
interrupt-controller;
compatible = "riscv,cpu-intc";
};
};
CPU3: cpu@3 {
device_type = "cpu";
reg = <3>;
status = "okay";
compatible = "riscv";
riscv,isa = "rv64imafdc";
riscv,priv-major = <1>;
riscv,priv-minor = <10>;
mmu-type = "riscv,sv48";
clock-frequency = <60000000>;
i-cache-size = <0x8000>;
i-cache-sets = <256>;
i-cache-line-size = <64>;
i-cache-block-size = <64>;
d-cache-size = <0x8000>;
d-cache-sets = <128>;
d-cache-line-size = <64>;
d-cache-block-size = <64>;
next-level-cache = <&L2>;
CPU3_intc: interrupt-controller {
#interrupt-cells = <1>;
interrupt-controller;
compatible = "riscv,cpu-intc";
};
};
};
soc {
#address-cells = <2>;
#size-cells = <2>;
compatible = "andestech,riscv-ae350-soc", "simple-bus";
ranges;
plic0: interrupt-controller@e4000000 {
compatible = "riscv,plic0";
reg = <0x00000000 0xe4000000 0x00000000 0x02000000>;
interrupts-extended = < &CPU0_intc 11 &CPU0_intc 9
&CPU1_intc 11 &CPU1_intc 9
&CPU2_intc 11 &CPU2_intc 9
&CPU3_intc 11 &CPU3_intc 9 >;
interrupt-controller;
#address-cells = <2>;
#interrupt-cells = <2>;
riscv,ndev = <71>;
};
plicsw: interrupt-controller@e6400000 {
compatible = "andestech,plicsw";
reg = <0x00000000 0xe6400000 0x00000000 0x00400000>;
interrupts-extended = < &CPU0_intc 3
&CPU1_intc 3
&CPU2_intc 3
&CPU3_intc 3 >;
interrupt-controller;
#address-cells = <2>;
#interrupt-cells = <2>;
};
plmt0: plmt0@e6000000 {
compatible = "andestech,plmt0";
reg = <0x00000000 0xe6000000 0x00000000 0x00100000>;
interrupts-extended = < &CPU0_intc 7
&CPU1_intc 7
&CPU2_intc 7
&CPU3_intc 7 >;
};
wdt: watchdog@f0500000 {
compatible = "andestech,atcwdt200";
reg = <0x00000000 0xf0500000 0x00000000 0x00001000>;
interrupts = <3 4>;
interrupt-parent = <&plic0>;
clock-frequency = <15000000>;
};
serial0: serial@f0300000 {
compatible = "andestech,uart16550", "ns16550a";
reg = <0x00000000 0xf0300000 0x00000000 0x00001000>;
interrupts = <9 4>;
interrupt-parent = <&plic0>;
clock-frequency = <19660800>;
current-speed = <38400>;
reg-shift = <2>;
reg-offset = <32>;
reg-io-width = <4>;
no-loopback-test = <1>;
};
smu: smu@f0100000 {
compatible = "andestech,atcsmu";
reg = <0x00000000 0xf0100000 0x00000000 0x00001000>;
};
};
```

View File

@@ -7,7 +7,7 @@ Linux.
The FPGA SoC currently contains the following peripherals:
- DDR3 memory controller
- SPI controller to conncet to an SDCard
- SPI controller to connect to an SDCard
- Ethernet controller
- JTAG port (see debugging section below)
- Bootrom containing zero stage bootloader and device tree.

View File

@@ -45,13 +45,17 @@ The *Generic* platform does not have any platform-specific options.
RISC-V Platforms Using Generic Platform
---------------------------------------
* **Andes AE350 Platform** (*[andes-ae350.md]*)
* **QEMU RISC-V Virt Machine** (*[qemu_virt.md]*)
* **Renesas RZ/Five SoC** (*[renesas-rzfive.md]*)
* **Shakti C-class SoC Platform** (*[shakti_cclass.md]*)
* **SiFive HiFive Unleashed** (*[sifive_fu540.md]*)
* **Spike** (*[spike.md]*)
* **T-HEAD C9xx series Processors** (*[thead-c9xx.md]*)
[andes-ae350.md]: andse-ae350.md
[qemu_virt.md]: qemu_virt.md
[renesas-rzfive.md]: renesas-rzfive.md
[shakti_cclass.md]: shakti_cclass.md
[sifive_fu540.md]: sifive_fu540.md
[spike.md]: spike.md

View File

@@ -39,11 +39,15 @@ OpenSBI currently supports the following virtual and hardware platforms:
processor based SOCs. More details on this platform can be found in the
file *[shakti_cclass.md]*.
* **Renesas RZ/Five SoC**: Platform support for Renesas RZ/Five (R9A07G043F) SoC
used on the Renesas RZ/Five SMARC EVK board. More details on this platform can
be found in the file *[renesas-rzfive.md]*.
The code for these supported platforms can be used as example to implement
support for other platforms. The *platform/template* directory also provides
template files for implementing support for a new platform. The *object.mk*,
*config.mk* and *platform.c* template files provides enough comments to
facilitate the implementation.
template files for implementing support for a new platform. The *objects.mk*,
*Kconfig*, *configs/defconfig* and *platform.c* template files provides enough
comments to facilitate the implementation.
[generic.md]: generic.md
[qemu_virt.md]: qemu_virt.md
@@ -54,3 +58,4 @@ facilitate the implementation.
[spike.md]: spike.md
[fpga-openpiton.md]: fpga-openpiton.md
[shakti_cclass.md]: shakti_cclass.md
[renesas-rzfive.md]: renesas-rzfive.md

View File

@@ -0,0 +1,160 @@
Renesas RZ/Five SoC (R9A07G043F) Platform
=========================================
The RZ/Five microprocessor includes a single RISC-V CPU Core (Andes AX45MP)
1.0 GHz, 16-bit DDR3L/DDR4 interface. Supported interfaces include:
- Memory controller for DDR4-1600 / DDR3L-1333 with 16 bits
- System RAM (RAM of 128 Kbytes (ECC))
- SPI Multi I/O Bus Controller 1ch
- SD Card Host Interface/Multimedia Card Interface (SD/MMC) 2ch
- Serial Sound Interface (SSI) 4ch
- Sampling Rate Converter (SRC) 1ch
- USB2.0 host/function interface 2ch (ch0: Host-Function ch1: Host only)
- Gigabit Ethernet Interface (GbE) 2ch
- Controller Area Network Interface (CAN) 2ch (CAN-FD ISO 11898-1 (CD2014) compliant)
- Multi-function Timer Pulse Unit 3 (MTU3a) 9 ch (16 bits × 8 channels, 32 bits × 1 channel)
- Port Output Enable 3 (POE3)
- Watchdog Timer (WDT) 1ch
- General Timer (GTM) 3ch (32bits)
- I2C Bus Interface (I2C) 4ch
- Serial Communication Interface with FIFO (SCIFA) 5ch
- Serial Communication Interface (SCI) 2ch
- Renesas Serial Peripheral Interface (RSPI) 3ch
- A/D Converter (ADC) 2ch
making it ideal for applications such as entry-class social infrastructure
gateway control and industrial gateway control. More details can be found at
below link [0].
[0] https://www.renesas.com/us/en/products/microcontrollers-microprocessors/rz-mpus/rzfive-general-purpose-microprocessors-risc-v-cpu-core-andes-ax45mp-single-10-ghz-2ch-gigabit-ethernet
To build platform specific library and firmwares, provide the
*PLATFORM=generic* parameter to the top level make command.
Platform Options
----------------
The Renesas RZ/Five platform does not have any platform-specific options.
Building Renesas RZ/Five Platform
---------------------------------
```
make PLATFORM=generic
```
DTS Example: (RZ/Five AX45MP)
-----------------------------
```
compatible = "renesas,r9a07g043f01", "renesas,r9a07g043";
cpus {
#address-cells = <1>;
#size-cells = <0>;
timebase-frequency = <12000000>;
cpu0: cpu@0 {
compatible = "andestech,ax45mp", "riscv";
device_type = "cpu";
reg = <0x0>;
status = "okay";
riscv,isa = "rv64imafdc";
mmu-type = "riscv,sv39";
i-cache-size = <0x8000>;
i-cache-line-size = <0x40>;
d-cache-size = <0x8000>;
d-cache-line-size = <0x40>;
clocks = <&cpg CPG_CORE R9A07G043_CLK_I>;
cpu0_intc: interrupt-controller {
#interrupt-cells = <1>;
compatible = "riscv,cpu-intc";
interrupt-controller;
};
};
};
soc {
compatible = "simple-bus";
#address-cells = <1>;
#size-cells = <0>;
ranges;
scif0: serial@1004b800 {
compatible = "renesas,scif-r9a07g043",
"renesas,scif-r9a07g044";
reg = <0 0x1004b800 0 0x400>;
interrupts = <412 IRQ_TYPE_LEVEL_HIGH>,
<414 IRQ_TYPE_LEVEL_HIGH>,
<415 IRQ_TYPE_LEVEL_HIGH>,
<413 IRQ_TYPE_LEVEL_HIGH>,
<416 IRQ_TYPE_LEVEL_HIGH>,
<416 IRQ_TYPE_LEVEL_HIGH>;
interrupt-names = "eri", "rxi", "txi",
"bri", "dri", "tei";
clocks = <&cpg CPG_MOD R9A07G043_SCIF0_CLK_PCK>;
clock-names = "fck";
power-domains = <&cpg>;
resets = <&cpg R9A07G043_SCIF0_RST_SYSTEM_N>;
status = "disabled";
};
cpg: clock-controller@11010000 {
compatible = "renesas,r9a07g043-cpg";
reg = <0 0x11010000 0 0x10000>;
clocks = <&extal_clk>;
clock-names = "extal";
#clock-cells = <2>;
#reset-cells = <1>;
#power-domain-cells = <0>;
};
sysc: system-controller@11020000 {
compatible = "renesas,r9a07g043-sysc";
reg = <0 0x11020000 0 0x10000>;
status = "disabled";
};
pinctrl: pinctrl@11030000 {
compatible = "renesas,r9a07g043-pinctrl";
reg = <0 0x11030000 0 0x10000>;
gpio-controller;
#gpio-cells = <2>;
#interrupt-cells = <2>;
interrupt-controller;
gpio-ranges = <&pinctrl 0 0 152>;
clocks = <&cpg CPG_MOD R9A07G043_GPIO_HCLK>;
power-domains = <&cpg>;
resets = <&cpg R9A07G043_GPIO_RSTN>,
<&cpg R9A07G043_GPIO_PORT_RESETN>,
<&cpg R9A07G043_GPIO_SPARE_RESETN>;
};
plmt0: plmt0@110c0000 {
compatible = "andestech,plmt0", "riscv,plmt0";
reg = <0x0 0x110c0000 0x0 0x10000>;
interrupts-extended = <&cpu0_intc 7>;
};
plic: interrupt-controller@12c00000 {
compatible = "renesas,r9a07g043-plic", "andestech,nceplic100";
#interrupt-cells = <2>;
#address-cells = <0>;
riscv,ndev = <511>;
interrupt-controller;
reg = <0x0 0x12c00000 0x0 0x400000>;
clocks = <&cpg CPG_MOD R9A07G043_NCEPLIC_ACLK>;
power-domains = <&cpg>;
resets = <&cpg R9A07G043_NCEPLIC_ARESETN>;
interrupts-extended = <&cpu0_intc 11 &cpu0_intc 9>;
};
plicsw: interrupt-controller@13000000 {
compatible = "andestech,plicsw";
reg = <0x0 0x13000000 0x0 0x400000>;
interrupts-extended = <&cpu0_intc 3>;
interrupt-controller;
#address-cells = <2>;
#interrupt-cells = <2>;
};
};
```

View File

@@ -150,7 +150,7 @@ If you want to test OpenSBI with QEMU 'sifive_u' machine, please follow the
same instructions above, with the exception of not passing FW_FDT_PATH.
This is because QEMU generates a device tree blob on the fly based on the
command line parameters and it's compatible with the one used in the upstream
command line parameters, and it's compatible with the one used in the upstream
Linux kernel.
When U-Boot v2021.07 (or higher) is used as the payload, as the SiFive FU540

View File

@@ -13,7 +13,7 @@ Platform Options
----------------
The *T-HEAD C9xx* does not have any platform-specific compile options
because it use generic platform.
because it uses generic platform.
```
CROSS_COMPILE=riscv64-linux-gnu- PLATFORM=generic /usr/bin/make
@@ -52,12 +52,11 @@ DTS Example1: (Single core, eg: Allwinner D1 - c906)
ranges;
clint0: clint@14000000 {
compatible = "riscv,clint0";
compatible = "allwinner,sun20i-d1-clint";
interrupts-extended = <
&cpu0_intc 3 &cpu0_intc 7
>;
reg = <0x0 0x14000000 0x0 0x04000000>;
clint,has-no-64bit-mmio;
};
intc: interrupt-controller@10000000 {
@@ -163,7 +162,6 @@ DTS Example2: (Multi cores with soc reset-regs)
&cpu4_intc 3 &cpu4_intc 7
>;
reg = <0xff 0xdc000000 0x0 0x04000000>;
clint,has-no-64bit-mmio;
};
intc: interrupt-controller@ffd8000000 {

View File

@@ -28,11 +28,12 @@ Adding support for a new platform
Support for a new platform named *&lt;xyz&gt;* can be added as follows:
1. Create a directory named *&lt;xyz&gt;* under the *platform/* directory.
2. Create a platform configuration file named *config.mk* under the
*platform/&lt;xyz&gt;/* directory. This configuration file will provide
2. Create platform configuration files named *Kconfig* and *configs/defconfig*
under the *platform/&lt;xyz&gt;/* directory. These configuration files will
provide the build time configuration for the sources to be compiled.
3. Create a *platform/&lt;xyz&gt;/objects.mk* file for listing the platform
object files to be compiled. This file also provides platform-specific
compiler flags, and select firmware options.
3. Create a *platform/&lt;xyz&gt;/objects.mk* file for listing the
platform-specific object files to be compiled.
4. Create a *platform/&lt;xyz&gt;/platform.c* file providing a
*struct sbi_platform* instance.

View File

@@ -10,7 +10,7 @@ To handle this, we have two types of RISC-V platform requirements:
2. **Release specific platform requirements** which apply to a OpenSBI
release and later releases
Currently, we don't have any **Release specific platform requirements**
Currently, we don't have any **Release specific platform requirements**,
but such platform requirements will be added in future.
Base Platform Requirements

View File

@@ -1,14 +1,11 @@
OpenSBI SBI PMU extension support
==================================
SBI PMU extension supports allow supervisor software to configure/start/stop
any performance counter at anytime. Thus, an user can leverage full
any performance counter at anytime. Thus, a user can leverage full
capability of performance analysis tools such as perf if SBI PMU extension is
enabled. The OpenSBI implementation makes the following assumptions about the
hardware platform.
* MCOUNTINHIBIT CSR must be implemented in the hardware. Otherwise, SBI PMU
extension will not be enabled.
* The platform must provide information about PMU event to counter mapping
via device tree or platform specific hooks. Otherwise, SBI PMU extension will
not be enabled.
@@ -25,7 +22,7 @@ SBI PMU Device Tree Bindings
----------------------------
Platforms may choose to describe PMU event selector and event to counter mapping
values via device tree. The following sections describes the PMU DT node
values via device tree. The following sections describe the PMU DT node
bindings in details.
* **compatible** (Mandatory) - The compatible string of SBI PMU device tree node.
@@ -42,46 +39,89 @@ This property shouldn't encode any raw hardware event.
* **riscv,event-to-mhpmcounters**(Optional) - It represents a MANY-to-MANY
mapping between a range of events and all the MHPMCOUNTERx in a bitmap format
that can be used to monitor these range of events. The information is encoded in
a table format where each row represent a certain range of events and
a table format where each row represents a certain range of events and
corresponding counters. The first column represents starting of the pmu event id
and 2nd column represents the end of the pmu event id. The third column
represent a bitmap of all the MHPMCOUNTERx. This property is mandatory if
event-to-mhpmevent is present. Otherwise, it can be omitted. This property
riscv,event-to-mhpmevent is present. Otherwise, it can be omitted. This property
shouldn't encode any raw event.
* **riscv,raw-event-to-mhpmcounters**(Optional) - It represents an ONE-to-MANY
or MANY-to-MANY mapping between the raw event(s) and all the MHPMCOUNTERx in
a bitmap format that can be used to monitor that raw event, which depends on
how the platform encodes the monitor events. Currently, only the following three
encoding methods are supported, encoding each event as a number, using a bitmap
to encode monitor events, and mixing the previous two methods. The information
is encoded in a table format where each row represent the specific raw event(s).
The first column represents a 64-bit selector value which can indicate an
monitor event ID (encoded by a number) or an event set (encoded by a bitmap).
In case of the latter, the lower bits used to encode a set of events should be
set to zero. The second column is a 64-bit selector mask where any bits used
for event encoding will be cleared. If a platform directly encodes each raw PMU
event as a unique ID, the value of select_mask will be 0xffffffff_ffffffff.
The third column represent a bitmap of all the MHPMCOUNTERx that can be used for
monitoring the specified event(s).
a bitmap format that can be used to monitor that raw event. The encoding of the
raw events are platform specific. The information is encoded in a table format
where each row represents the specific raw event(s). The first column is a 64bit
match value where the invariant bits of range of events are set. The second
column is a 64 bit mask that will have all the variant bits of the range of
events cleared. All other bits should be set in the mask.
The third column is a 32bit value to represent bitmap of all MHPMCOUNTERx that
can monitor these set of event(s).
If a platform directly encodes each raw PMU event as a unique ID, the value of
select_mask must be 0xffffffff_ffffffff.
*Note:* A platform may choose to provide the mapping between event & counters
via platform hooks rather than the device tree.
### Example
### Example 1
```
pmu {
compatible = "riscv,pmu";
interrupts = <0x100>;
interrupt-parent = <&plic>
riscv,event-to-mhpmevent = <0x0000B 0x0000 0x0001>,
riscv,event-to-mhpmevent = <0x0000B 0x0000 0x0001>;
riscv,event-to-mhpmcounters = <0x00001 0x00001 0x00000001>,
<0x00002 0x00002 0x00000004>,
<0x00003 0x0000A 0x00000ff8>,
<0x10000 0x10033 0x000ff000>,
riscv,raw-event-to-mhpmcounters = <0x0000 0x0002 0xffffffff 0xffffffff 0x00000f8>,
<0xffffffff 0xfffffff0 0xffffffff 0xfffffff0 0x00000ff0>,
<0x10000 0x10033 0x000ff000>;
/* For event ID 0x0002 */
riscv,raw-event-to-mhpmcounters = <0x0000 0x0002 0xffffffff 0xffffffff 0x00000f8>,
/* For event ID 0-4 */
<0x0 0x0 0xffffffff 0xfffffff0 0x00000ff0>,
/* For event ID 0xffffffff0000000f - 0xffffffff000000ff */
<0xffffffff 0x0 0xffffffff 0xffffff0f 0x00000ff0>;
};
```
### Example 2
```
/*
* For HiFive Unmatched board. The encodings can be found here
* https://sifive.cdn.prismic.io/sifive/1a82e600-1f93-4f41-b2d8-86ed8b16acba_fu740-c000-manual-v1p6.pdf
* This example also binds standard SBI PMU hardware id's to U74 PMU event codes, U74 uses bitfield for
* events encoding, so several U74 events can be bound to single perf id.
* See SBI PMU hardware id's in include/sbi/sbi_ecall_interface.h
*/
pmu {
compatible = "riscv,pmu";
riscv,event-to-mhpmevent =
/* SBI_PMU_HW_CACHE_REFERENCES -> Instruction cache/ITIM busy | Data cache/DTIM busy */
<0x00003 0x00000000 0x1801>,
/* SBI_PMU_HW_CACHE_MISSES -> Instruction cache miss | Data cache miss or memory-mapped I/O access */
<0x00004 0x00000000 0x0302>,
/* SBI_PMU_HW_BRANCH_INSTRUCTIONS -> Conditional branch retired */
<0x00005 0x00000000 0x4000>,
/* SBI_PMU_HW_BRANCH_MISSES -> Branch direction misprediction | Branch/jump target misprediction */
<0x00006 0x00000000 0x6001>,
/* L1D_READ_MISS -> Data cache miss or memory-mapped I/O access */
<0x10001 0x00000000 0x0202>,
/* L1D_WRITE_ACCESS -> Data cache write-back */
<0x10002 0x00000000 0x0402>,
/* L1I_READ_ACCESS -> Instruction cache miss */
<0x10009 0x00000000 0x0102>,
/* LL_READ_MISS -> UTLB miss */
<0x10011 0x00000000 0x2002>,
/* DTLB_READ_MISS -> Data TLB miss */
<0x10019 0x00000000 0x1002>,
/* ITLB_READ_MISS-> Instruction TLB miss */
<0x10021 0x00000000 0x0802>;
riscv,event-to-mhpmcounters = <0x00003 0x00006 0x18>,
<0x10001 0x10002 0x18>,
<0x10009 0x10009 0x18>,
<0x10011 0x10011 0x18>,
<0x10019 0x10019 0x18>,
<0x10021 0x10021 0x18>;
riscv,raw-event-to-mhpmcounters = <0x0 0x0 0xffffffff 0xfc0000ff 0x18>,
<0x0 0x1 0xffffffff 0xfff800ff 0x18>,
<0x0 0x2 0xffffffff 0xffffe0ff 0x18>;
};
```

1
firmware/Kconfig Normal file
View File

@@ -0,0 +1 @@
# SPDX-License-Identifier: BSD-2-Clause

View File

@@ -128,9 +128,9 @@ _relocate:
REG_L t1, 0(t1)
lla t2, _load_start
REG_L t2, 0(t2)
beq t0, t2, _relocate_done
sub t3, t1, t0
add t3, t3, t2
beq t0, t2, _relocate_done
lla t4, _relocate_done
sub t4, t4, t2
add t4, t4, t0
@@ -259,7 +259,7 @@ _bss_zero:
* s8 -> HART Stack Size
*/
lla a4, platform
#if __riscv_xlen == 64
#if __riscv_xlen > 32
lwu s7, SBI_PLATFORM_HART_COUNT_OFFSET(a4)
lwu s8, SBI_PLATFORM_HART_STACK_SIZE_OFFSET(a4)
#else

View File

@@ -24,14 +24,12 @@
PROVIDE(_text_end = .);
}
. = ALIGN(0x1000); /* Ensure next section is page aligned */
/* End of the code sections */
/* Beginning of the read-only data sections */
. = ALIGN(0x1000); /* Ensure next section is page aligned */
/* Beginning of the read-only data sections */
.rodata :
{
PROVIDE(_rodata_start = .);
@@ -42,10 +40,10 @@
/* End of the read-only data sections */
/* Beginning of the read-write data sections */
. = ALIGN(0x1000); /* Ensure next section is page aligned */
/* Beginning of the read-write data sections */
.data :
{
PROVIDE(_data_start = .);

View File

@@ -33,14 +33,12 @@ SECTIONS
PROVIDE(_text_end = .);
}
. = ALIGN(0x1000); /* Ensure next section is page aligned */
/* End of the code sections */
/* Beginning of the read-only data sections */
. = ALIGN(0x1000); /* Ensure next section is page aligned */
/* Beginning of the read-only data sections */
.rodata :
{
PROVIDE(_rodata_start = .);
@@ -51,10 +49,10 @@ SECTIONS
/* End of the read-only data sections */
/* Beginning of the read-write data sections */
. = ALIGN(0x1000); /* Ensure next section is page aligned */
/* Beginning of the read-write data sections */
.data :
{
PROVIDE(_data_start = .);

View File

@@ -75,6 +75,41 @@ struct fw_dynamic_info {
unsigned long boot_hart;
} __packed;
/**
* Prevent modification of struct fw_dynamic_info from affecting
* FW_DYNAMIC_INFO_xxx_OFFSET
*/
_Static_assert(
offsetof(struct fw_dynamic_info, magic)
== FW_DYNAMIC_INFO_MAGIC_OFFSET,
"struct fw_dynamic_info definition has changed, please redefine "
"FW_DYNAMIC_INFO_MAGIC_OFFSET");
_Static_assert(
offsetof(struct fw_dynamic_info, version)
== FW_DYNAMIC_INFO_VERSION_OFFSET,
"struct fw_dynamic_info definition has changed, please redefine "
"FW_DYNAMIC_INFO_VERSION_OFFSET");
_Static_assert(
offsetof(struct fw_dynamic_info, next_addr)
== FW_DYNAMIC_INFO_NEXT_ADDR_OFFSET,
"struct fw_dynamic_info definition has changed, please redefine "
"FW_DYNAMIC_INFO_NEXT_ADDR_OFFSET");
_Static_assert(
offsetof(struct fw_dynamic_info, next_mode)
== FW_DYNAMIC_INFO_NEXT_MODE_OFFSET,
"struct fw_dynamic_info definition has changed, please redefine "
"FW_DYNAMIC_INFO_NEXT_MODE_OFFSET");
_Static_assert(
offsetof(struct fw_dynamic_info, options)
== FW_DYNAMIC_INFO_OPTIONS_OFFSET,
"struct fw_dynamic_info definition has changed, please redefine "
"FW_DYNAMIC_INFO_OPTIONS_OFFSET");
_Static_assert(
offsetof(struct fw_dynamic_info, boot_hart)
== FW_DYNAMIC_INFO_BOOT_HART_OFFSET,
"struct fw_dynamic_info definition has changed, please redefine "
"FW_DYNAMIC_INFO_BOOT_HART_OFFSET");
#endif
#endif

View File

@@ -25,7 +25,7 @@
#define MSTATUS_MPP (_UL(3) << MSTATUS_MPP_SHIFT)
#define MSTATUS_FS _UL(0x00006000)
#define MSTATUS_XS _UL(0x00018000)
#define MSTATUS_VS _UL(0x01800000)
#define MSTATUS_VS _UL(0x00000600)
#define MSTATUS_MPRV _UL(0x00020000)
#define MSTATUS_SUM _UL(0x00040000)
#define MSTATUS_MXR _UL(0x00080000)
@@ -38,10 +38,14 @@
#define MSTATUS_SXL _ULL(0x0000000C00000000)
#define MSTATUS_SBE _ULL(0x0000001000000000)
#define MSTATUS_MBE _ULL(0x0000002000000000)
#define MSTATUS_GVA _ULL(0x0000004000000000)
#define MSTATUS_GVA_SHIFT 38
#define MSTATUS_MPV _ULL(0x0000008000000000)
#else
#define MSTATUSH_SBE _UL(0x00000010)
#define MSTATUSH_MBE _UL(0x00000020)
#define MSTATUSH_GVA _UL(0x00000040)
#define MSTATUSH_GVA_SHIFT 6
#define MSTATUSH_MPV _UL(0x00000080)
#endif
#define MSTATUS32_SD _UL(0x80000000)
@@ -173,6 +177,10 @@
#define HGATP_MODE_SHIFT HGATP32_MODE_SHIFT
#endif
#define TOPI_IID_SHIFT 16
#define TOPI_IID_MASK 0xfff
#define TOPI_IPRIO_MASK 0xff
#if __riscv_xlen == 64
#define MHPMEVENT_OF (_UL(1) << 63)
#define MHPMEVENT_MINH (_UL(1) << 62)
@@ -181,13 +189,14 @@
#define MHPMEVENT_VSINH (_UL(1) << 59)
#define MHPMEVENT_VUINH (_UL(1) << 58)
#else
#define MHPMEVENTH_OF (_UL(1) << 31)
#define MHPMEVENTH_OF (_ULL(1) << 31)
#define MHPMEVENTH_MINH (_ULL(1) << 30)
#define MHPMEVENTH_SINH (_ULL(1) << 29)
#define MHPMEVENTH_UINH (_ULL(1) << 28)
#define MHPMEVENTH_VSINH (_ULL(1) << 27)
#define MHPMEVENTH_VUINH (_ULL(1) << 26)
#define MHPMEVENT_OF (MHPMEVENTH_OF << 32)
#define MHPMEVENT_MINH (MHPMEVENTH_MINH << 32)
#define MHPMEVENT_SINH (MHPMEVENTH_SINH << 32)
#define MHPMEVENT_UINH (MHPMEVENTH_UINH << 32)
@@ -198,6 +207,22 @@
#define MHPMEVENT_SSCOF_MASK _ULL(0xFFFF000000000000)
#if __riscv_xlen > 32
#define ENVCFG_STCE (_ULL(1) << 63)
#define ENVCFG_PBMTE (_ULL(1) << 62)
#else
#define ENVCFGH_STCE (_UL(1) << 31)
#define ENVCFGH_PBMTE (_UL(1) << 30)
#endif
#define ENVCFG_CBZE (_UL(1) << 7)
#define ENVCFG_CBCFE (_UL(1) << 6)
#define ENVCFG_CBIE_SHIFT 4
#define ENVCFG_CBIE (_UL(0x3) << ENVCFG_CBIE_SHIFT)
#define ENVCFG_CBIE_ILL _UL(0x0)
#define ENVCFG_CBIE_FLUSH _UL(0x1)
#define ENVCFG_CBIE_INV _UL(0x3)
#define ENVCFG_FIOM _UL(0x1)
/* ===== User-level CSRs ===== */
/* User Trap Setup (N-extension) */
@@ -287,12 +312,13 @@
/* Supervisor Trap Setup */
#define CSR_SSTATUS 0x100
#define CSR_SEDELEG 0x102
#define CSR_SIDELEG 0x103
#define CSR_SIE 0x104
#define CSR_STVEC 0x105
#define CSR_SCOUNTEREN 0x106
/* Supervisor Configuration */
#define CSR_SENVCFG 0x10a
/* Supervisor Trap Handling */
#define CSR_SSCRATCH 0x140
#define CSR_SEPC 0x141
@@ -300,9 +326,31 @@
#define CSR_STVAL 0x143
#define CSR_SIP 0x144
/* Sstc extension */
#define CSR_STIMECMP 0x14D
#define CSR_STIMECMPH 0x15D
/* Supervisor Protection and Translation */
#define CSR_SATP 0x180
/* Supervisor-Level Window to Indirectly Accessed Registers (AIA) */
#define CSR_SISELECT 0x150
#define CSR_SIREG 0x151
/* Supervisor-Level Interrupts (AIA) */
#define CSR_STOPEI 0x15c
#define CSR_STOPI 0xdb0
/* Supervisor-Level High-Half CSRs (AIA) */
#define CSR_SIEH 0x114
#define CSR_SIPH 0x154
/* Supervisor stateen CSRs */
#define CSR_SSTATEEN0 0x10C
#define CSR_SSTATEEN1 0x10D
#define CSR_SSTATEEN2 0x10E
#define CSR_SSTATEEN3 0x10F
/* ===== Hypervisor-level CSRs ===== */
/* Hypervisor Trap Setup (H-extension) */
@@ -313,6 +361,10 @@
#define CSR_HCOUNTEREN 0x606
#define CSR_HGEIE 0x607
/* Hypervisor Configuration */
#define CSR_HENVCFG 0x60a
#define CSR_HENVCFGH 0x61a
/* Hypervisor Trap Handling (H-extension) */
#define CSR_HTVAL 0x643
#define CSR_HIP 0x644
@@ -338,6 +390,39 @@
#define CSR_VSIP 0x244
#define CSR_VSATP 0x280
/* Virtual Interrupts and Interrupt Priorities (H-extension with AIA) */
#define CSR_HVIEN 0x608
#define CSR_HVICTL 0x609
#define CSR_HVIPRIO1 0x646
#define CSR_HVIPRIO2 0x647
/* VS-Level Window to Indirectly Accessed Registers (H-extension with AIA) */
#define CSR_VSISELECT 0x250
#define CSR_VSIREG 0x251
/* VS-Level Interrupts (H-extension with AIA) */
#define CSR_VSTOPEI 0x25c
#define CSR_VSTOPI 0xeb0
/* Hypervisor and VS-Level High-Half CSRs (H-extension with AIA) */
#define CSR_HIDELEGH 0x613
#define CSR_HVIENH 0x618
#define CSR_HVIPH 0x655
#define CSR_HVIPRIO1H 0x656
#define CSR_HVIPRIO2H 0x657
#define CSR_VSIEH 0x214
#define CSR_VSIPH 0x254
/* Hypervisor stateen CSRs */
#define CSR_HSTATEEN0 0x60C
#define CSR_HSTATEEN0H 0x61C
#define CSR_HSTATEEN1 0x60D
#define CSR_HSTATEEN1H 0x61D
#define CSR_HSTATEEN2 0x60E
#define CSR_HSTATEEN2H 0x61E
#define CSR_HSTATEEN3 0x60F
#define CSR_HSTATEEN3H 0x61F
/* ===== Machine-level CSRs ===== */
/* Machine Information Registers */
@@ -356,6 +441,10 @@
#define CSR_MCOUNTEREN 0x306
#define CSR_MSTATUSH 0x310
/* Machine Configuration */
#define CSR_MENVCFG 0x30a
#define CSR_MENVCFGH 0x31a
/* Machine Trap Handling */
#define CSR_MSCRATCH 0x340
#define CSR_MEPC 0x341
@@ -589,6 +678,36 @@
#define CSR_DSCRATCH0 0x7b2
#define CSR_DSCRATCH1 0x7b3
/* Machine-Level Window to Indirectly Accessed Registers (AIA) */
#define CSR_MISELECT 0x350
#define CSR_MIREG 0x351
/* Machine-Level Interrupts (AIA) */
#define CSR_MTOPEI 0x35c
#define CSR_MTOPI 0xfb0
/* Virtual Interrupts for Supervisor Level (AIA) */
#define CSR_MVIEN 0x308
#define CSR_MVIP 0x309
/* Smstateen extension registers */
/* Machine stateen CSRs */
#define CSR_MSTATEEN0 0x30C
#define CSR_MSTATEEN0H 0x31C
#define CSR_MSTATEEN1 0x30D
#define CSR_MSTATEEN1H 0x31D
#define CSR_MSTATEEN2 0x30E
#define CSR_MSTATEEN2H 0x31E
#define CSR_MSTATEEN3 0x30F
#define CSR_MSTATEEN3H 0x31F
/* Machine-Level High-Half CSRs (AIA) */
#define CSR_MIDELEGH 0x313
#define CSR_MIEH 0x314
#define CSR_MVIENH 0x318
#define CSR_MVIPH 0x319
#define CSR_MIPH 0x354
/* ===== Trap/Exception Causes ===== */
#define CAUSE_MISALIGNED_FETCH 0x0
@@ -611,6 +730,23 @@
#define CAUSE_VIRTUAL_INST_FAULT 0x16
#define CAUSE_STORE_GUEST_PAGE_FAULT 0x17
/* Common defines for all smstateen */
#define SMSTATEEN_MAX_COUNT 4
#define SMSTATEEN0_CS_SHIFT 0
#define SMSTATEEN0_CS (_ULL(1) << SMSTATEEN0_CS_SHIFT)
#define SMSTATEEN0_FCSR_SHIFT 1
#define SMSTATEEN0_FCSR (_ULL(1) << SMSTATEEN0_FCSR_SHIFT)
#define SMSTATEEN0_IMSIC_SHIFT 58
#define SMSTATEEN0_IMSIC (_ULL(1) << SMSTATEEN0_IMSIC_SHIFT)
#define SMSTATEEN0_AIA_SHIFT 59
#define SMSTATEEN0_AIA (_ULL(1) << SMSTATEEN0_AIA_SHIFT)
#define SMSTATEEN0_SVSLCT_SHIFT 60
#define SMSTATEEN0_SVSLCT (_ULL(1) << SMSTATEEN0_SVSLCT_SHIFT)
#define SMSTATEEN0_HSENVCFG_SHIFT 62
#define SMSTATEEN0_HSENVCFG (_ULL(1) << SMSTATEEN0_HSENVCFG_SHIFT)
#define SMSTATEEN_STATEN_SHIFT 63
#define SMSTATEEN_STATEN (_ULL(1) << SMSTATEEN_STATEN_SHIFT)
/* ===== Instruction Encodings ===== */
#define INSN_MATCH_LB 0x3
@@ -686,6 +822,29 @@
#define INSN_MASK_WFI 0xffffff00
#define INSN_MATCH_WFI 0x10500000
#define INSN_MASK_FENCE_TSO 0xffffffff
#define INSN_MATCH_FENCE_TSO 0x8330000f
#if __riscv_xlen == 64
/* 64-bit read for VS-stage address translation (RV64) */
#define INSN_PSEUDO_VS_LOAD 0x00003000
/* 64-bit write for VS-stage address translation (RV64) */
#define INSN_PSEUDO_VS_STORE 0x00003020
#elif __riscv_xlen == 32
/* 32-bit read for VS-stage address translation (RV32) */
#define INSN_PSEUDO_VS_LOAD 0x00002000
/* 32-bit write for VS-stage address translation (RV32) */
#define INSN_PSEUDO_VS_STORE 0x00002020
#else
#error "Unexpected __riscv_xlen"
#endif
#define INSN_16BIT_MASK 0x3
#define INSN_32BIT_MASK 0x1c

View File

@@ -37,47 +37,12 @@
(((~0UL) - (1UL << (l)) + 1) & (~0UL >> (BITS_PER_LONG - 1 - (h))))
/**
* ffs - Find first bit set
* @x: the word to search
*
* This is defined the same way as
* the libc and compiler builtin ffs routines, therefore
* differs in spirit from the above ffz (man ffs).
*/
static inline int ffs(int x)
{
int r = 1;
if (!x)
return 0;
if (!(x & 0xffff)) {
x >>= 16;
r += 16;
}
if (!(x & 0xff)) {
x >>= 8;
r += 8;
}
if (!(x & 0xf)) {
x >>= 4;
r += 4;
}
if (!(x & 3)) {
x >>= 2;
r += 2;
}
if (!(x & 1))
r += 1;
return r;
}
/**
* __ffs - find first bit in word.
* sbi_ffs - find first (less-significant) set bit in a long word.
* @word: The word to search
*
* Undefined if no bit exists, so code should check against 0 first.
*/
static inline int __ffs(unsigned long word)
static inline int sbi_ffs(unsigned long word)
{
int num = 0;
@@ -109,55 +74,20 @@ static inline int __ffs(unsigned long word)
}
/*
* ffz - find first zero in word.
* sbi_ffz - find first zero in word.
* @word: The word to search
*
* Undefined if no zero exists, so code should check against ~0UL first.
*/
#define ffz(x) __ffs(~(x))
#define sbi_ffz(x) sbi_ffs(~(x))
/**
* fls - find last (most-significant) bit set
* @x: the word to search
*
* This is defined the same way as ffs.
* Note fls(0) = 0, fls(1) = 1, fls(0x80000000) = 32.
*/
static inline int fls(int x)
{
int r = 32;
if (!x)
return 0;
if (!(x & 0xffff0000u)) {
x <<= 16;
r -= 16;
}
if (!(x & 0xff000000u)) {
x <<= 8;
r -= 8;
}
if (!(x & 0xf0000000u)) {
x <<= 4;
r -= 4;
}
if (!(x & 0xc0000000u)) {
x <<= 2;
r -= 2;
}
if (!(x & 0x80000000u))
r -= 1;
return r;
}
/**
* __fls - find last (most-significant) set bit in a long word
* sbi_fls - find last (most-significant) set bit in a long word
* @word: the word to search
*
* Undefined if no set bit exists, so code should check against 0 first.
*/
static inline unsigned long __fls(unsigned long word)
static inline unsigned long sbi_fls(unsigned long word)
{
int num = BITS_PER_LONG - 1;

View File

@@ -174,10 +174,26 @@ int sbi_domain_register(struct sbi_domain *dom,
* Add a memory region to the root domain
* @param reg pointer to the memory region to be added
*
* @return 0 on success and negative error code on failure
* @return 0 on success
* @return SBI_EALREADY if memory region conflicts with the existing one
* @return SBI_EINVAL otherwise
*/
int sbi_domain_root_add_memregion(const struct sbi_domain_memregion *reg);
/**
* Add a memory range with its flags to the root domain
* @param addr start physical address of memory range
* @param size physical size of memory range
* @param align alignment of memory region
* @param region_flags memory range flags
*
* @return 0 on success
* @return SBI_EALREADY if memory region conflicts with the existing one
* @return SBI_EINVAL otherwise
*/
int sbi_domain_root_add_memrange(unsigned long addr, unsigned long size,
unsigned long align, unsigned long region_flags);
/** Finalize domain tables and startup non-root domains */
int sbi_domain_finalize(struct sbi_scratch *scratch, u32 cold_hartid);

View File

@@ -13,8 +13,8 @@
#include <sbi/sbi_types.h>
#include <sbi/sbi_list.h>
#define SBI_ECALL_VERSION_MAJOR 0
#define SBI_ECALL_VERSION_MINOR 3
#define SBI_ECALL_VERSION_MAJOR 1
#define SBI_ECALL_VERSION_MINOR 0
#define SBI_OPENSBI_IMPID 1
struct sbi_trap_regs;
@@ -31,16 +31,6 @@ struct sbi_ecall_extension {
struct sbi_trap_info *out_trap);
};
extern struct sbi_ecall_extension ecall_base;
extern struct sbi_ecall_extension ecall_legacy;
extern struct sbi_ecall_extension ecall_time;
extern struct sbi_ecall_extension ecall_rfence;
extern struct sbi_ecall_extension ecall_ipi;
extern struct sbi_ecall_extension ecall_vendor;
extern struct sbi_ecall_extension ecall_hsm;
extern struct sbi_ecall_extension ecall_srst;
extern struct sbi_ecall_extension ecall_pmu;
u16 sbi_ecall_version_major(void);
u16 sbi_ecall_version_minor(void);

View File

@@ -208,6 +208,12 @@ enum sbi_pmu_ctr_type {
#define SBI_PMU_EVENT_IDX_INVALID 0xFFFFFFFF
#define SBI_PMU_EVENT_HW_CACHE_OPS_RESULT 0x1
#define SBI_PMU_EVENT_HW_CACHE_OPS_ID_MASK 0x6
#define SBI_PMU_EVENT_HW_CACHE_OPS_ID_OFFSET 1
#define SBI_PMU_EVENT_HW_CACHE_ID_MASK 0xfff8
#define SBI_PMU_EVENT_HW_CACHE_ID_OFFSET 3
/* Flags defined for config matching function */
#define SBI_PMU_CFG_FLAG_SKIP_MATCH (1 << 0)
#define SBI_PMU_CFG_FLAG_CLEAR_VALUE (1 << 1)

View File

@@ -12,21 +12,44 @@
#include <sbi/sbi_types.h>
/** Possible feature flags of a hart */
enum sbi_hart_features {
/** Hart has S-mode counter enable */
SBI_HART_HAS_SCOUNTEREN = (1 << 0),
/** Hart has M-mode counter enable */
SBI_HART_HAS_MCOUNTEREN = (1 << 1),
/** Hart has counter inhibit CSR */
SBI_HART_HAS_MCOUNTINHIBIT = (1 << 2),
/** Hart has sscofpmf extension */
SBI_HART_HAS_SSCOFPMF = (1 << 3),
/** HART has timer csr implementation in hardware */
SBI_HART_HAS_TIME = (1 << 4),
/** Possible privileged specification versions of a hart */
enum sbi_hart_priv_versions {
/** Unknown privileged specification */
SBI_HART_PRIV_VER_UNKNOWN = 0,
/** Privileged specification v1.10 */
SBI_HART_PRIV_VER_1_10 = 1,
/** Privileged specification v1.11 */
SBI_HART_PRIV_VER_1_11 = 2,
/** Privileged specification v1.12 */
SBI_HART_PRIV_VER_1_12 = 3,
};
/** Last index of Hart features*/
SBI_HART_HAS_LAST_FEATURE = SBI_HART_HAS_TIME,
/** Possible ISA extensions of a hart */
enum sbi_hart_extensions {
/** Hart has Sscofpmt extension */
SBI_HART_EXT_SSCOFPMF = 0,
/** HART has HW time CSR (extension name not available) */
SBI_HART_EXT_TIME,
/** HART has AIA M-mode CSRs */
SBI_HART_EXT_SMAIA,
/** HART has Smstateen CSR **/
SBI_HART_EXT_SMSTATEEN,
/** HART has Sstc extension */
SBI_HART_EXT_SSTC,
/** Maximum index of Hart extension */
SBI_HART_EXT_MAX,
};
struct sbi_hart_features {
bool detected;
int priv_version;
unsigned long extensions;
unsigned int pmp_count;
unsigned int pmp_addr_bits;
unsigned long pmp_gran;
unsigned int mhpm_count;
unsigned int mhpm_bits;
};
struct sbi_scratch;
@@ -48,9 +71,16 @@ unsigned long sbi_hart_pmp_granularity(struct sbi_scratch *scratch);
unsigned int sbi_hart_pmp_addrbits(struct sbi_scratch *scratch);
unsigned int sbi_hart_mhpm_bits(struct sbi_scratch *scratch);
int sbi_hart_pmp_configure(struct sbi_scratch *scratch);
bool sbi_hart_has_feature(struct sbi_scratch *scratch, unsigned long feature);
void sbi_hart_get_features_str(struct sbi_scratch *scratch,
char *features_str, int nfstr);
int sbi_hart_priv_version(struct sbi_scratch *scratch);
void sbi_hart_get_priv_version_str(struct sbi_scratch *scratch,
char *version_str, int nvstr);
void sbi_hart_update_extension(struct sbi_scratch *scratch,
enum sbi_hart_extensions ext,
bool enable);
bool sbi_hart_has_extension(struct sbi_scratch *scratch,
enum sbi_hart_extensions ext);
void sbi_hart_get_extensions_str(struct sbi_scratch *scratch,
char *extension_str, int nestr);
void __attribute__((noreturn)) sbi_hart_hang(void);

View File

@@ -34,9 +34,17 @@ struct sbi_hsm_device {
* the hart resumes normal execution.
*
* For successful non-retentive suspend, the hart will resume from
* specified resume address
* the warm boot entry point.
*/
int (*hart_suspend)(u32 suspend_type, ulong raddr);
int (*hart_suspend)(u32 suspend_type);
/**
* Perform platform-specific actions to resume from a suspended state.
*
* This includes restoring any platform state that was lost during
* non-retentive suspend.
*/
void (*hart_resume)(void);
};
struct sbi_domain;

View File

@@ -75,7 +75,7 @@ int sbi_ipi_send_halt(ulong hmask, ulong hbase);
void sbi_ipi_process(void);
void sbi_ipi_raw_send(u32 target_hart);
int sbi_ipi_raw_send(u32 target_hart);
const struct sbi_ipi_device *sbi_ipi_get_device(void);

44
include/sbi/sbi_irqchip.h Normal file
View File

@@ -0,0 +1,44 @@
/*
* SPDX-License-Identifier: BSD-2-Clause
*
* Copyright (c) 2022 Ventana Micro Systems Inc.
*
* Authors:
* Anup Patel <apatel@ventanamicro.com>
*/
#ifndef __SBI_IRQCHIP_H__
#define __SBI_IRQCHIP_H__
#include <sbi/sbi_types.h>
struct sbi_scratch;
struct sbi_trap_regs;
/**
* Set external interrupt handling function
*
* This function is called by OpenSBI platform code to set a handler for
* external interrupts
*
* @param fn function pointer for handling external irqs
*/
void sbi_irqchip_set_irqfn(int (*fn)(struct sbi_trap_regs *regs));
/**
* Process external interrupts
*
* This function is called by sbi_trap_handler() to handle external
* interrupts.
*
* @param regs pointer for trap registers
*/
int sbi_irqchip_process(struct sbi_trap_regs *regs);
/** Initialize interrupt controllers */
int sbi_irqchip_init(struct sbi_scratch *scratch, bool cold_boot);
/** Exit interrupt controllers */
void sbi_irqchip_exit(struct sbi_scratch *scratch);
#endif

View File

@@ -48,6 +48,7 @@
struct sbi_domain_memregion;
struct sbi_trap_info;
struct sbi_trap_regs;
struct sbi_hart_features;
/** Possible feature flags of a platform */
enum sbi_platform_features {
@@ -64,6 +65,9 @@ enum sbi_platform_features {
/** Platform functions */
struct sbi_platform_operations {
/* Platform nascent initialization */
int (*nascent_init)(void);
/** Platform early initialization */
int (*early_init)(bool cold_boot);
/** Platform final initialization */
@@ -86,6 +90,9 @@ struct sbi_platform_operations {
*/
int (*misa_get_xlen)(void);
/** Initialize (or populate) HART extensions for the platform */
int (*extensions_init)(struct sbi_hart_features *hfeatures);
/** Initialize (or populate) domains for the platform */
int (*domains_init)(void);
@@ -172,6 +179,56 @@ struct sbi_platform {
const u32 *hart_index2id;
};
/**
* Prevent modification of struct sbi_platform from affecting
* SBI_PLATFORM_xxx_OFFSET
*/
_Static_assert(
offsetof(struct sbi_platform, opensbi_version)
== SBI_PLATFORM_OPENSBI_VERSION_OFFSET,
"struct sbi_platform definition has changed, please redefine "
"SBI_PLATFORM_OPENSBI_VERSION_OFFSET");
_Static_assert(
offsetof(struct sbi_platform, platform_version)
== SBI_PLATFORM_VERSION_OFFSET,
"struct sbi_platform definition has changed, please redefine "
"SBI_PLATFORM_VERSION_OFFSET");
_Static_assert(
offsetof(struct sbi_platform, name)
== SBI_PLATFORM_NAME_OFFSET,
"struct sbi_platform definition has changed, please redefine "
"SBI_PLATFORM_NAME_OFFSET");
_Static_assert(
offsetof(struct sbi_platform, features)
== SBI_PLATFORM_FEATURES_OFFSET,
"struct sbi_platform definition has changed, please redefine "
"SBI_PLATFORM_FEATURES_OFFSET");
_Static_assert(
offsetof(struct sbi_platform, hart_count)
== SBI_PLATFORM_HART_COUNT_OFFSET,
"struct sbi_platform definition has changed, please redefine "
"SBI_PLATFORM_HART_COUNT_OFFSET");
_Static_assert(
offsetof(struct sbi_platform, hart_stack_size)
== SBI_PLATFORM_HART_STACK_SIZE_OFFSET,
"struct sbi_platform definition has changed, please redefine "
"SBI_PLATFORM_HART_STACK_SIZE_OFFSET");
_Static_assert(
offsetof(struct sbi_platform, platform_ops_addr)
== SBI_PLATFORM_OPS_OFFSET,
"struct sbi_platform definition has changed, please redefine "
"SBI_PLATFORM_OPS_OFFSET");
_Static_assert(
offsetof(struct sbi_platform, firmware_context)
== SBI_PLATFORM_FIRMWARE_CONTEXT_OFFSET,
"struct sbi_platform definition has changed, please redefine "
"SBI_PLATFORM_FIRMWARE_CONTEXT_OFFSET");
_Static_assert(
offsetof(struct sbi_platform, hart_index2id)
== SBI_PLATFORM_HART_INDEX2ID_OFFSET,
"struct sbi_platform definition has changed, please redefine "
"SBI_PLATFORM_HART_INDEX2ID_OFFSET");
/** Get pointer to sbi_platform for sbi_scratch pointer */
#define sbi_platform_ptr(__s) \
((const struct sbi_platform *)((__s)->platform_addr))
@@ -299,6 +356,23 @@ static inline bool sbi_platform_hart_invalid(const struct sbi_platform *plat,
return FALSE;
}
/**
* Nascent (very early) initialization for current HART
*
* NOTE: This function can be used to do very early initialization of
* platform specific per-HART CSRs and devices.
*
* @param plat pointer to struct sbi_platform
*
* @return 0 on success and negative error code on failure
*/
static inline int sbi_platform_nascent_init(const struct sbi_platform *plat)
{
if (plat && sbi_platform_ops(plat)->nascent_init)
return sbi_platform_ops(plat)->nascent_init();
return 0;
}
/**
* Early initialization for current HART
*
@@ -383,6 +457,22 @@ static inline int sbi_platform_misa_xlen(const struct sbi_platform *plat)
return -1;
}
/**
* Initialize (or populate) HART extensions for the platform
*
* @param plat pointer to struct sbi_platform
*
* @return 0 on success and negative error code on failure
*/
static inline int sbi_platform_extensions_init(
const struct sbi_platform *plat,
struct sbi_hart_features *hfeatures)
{
if (plat && sbi_platform_ops(plat)->extensions_init)
return sbi_platform_ops(plat)->extensions_init(hfeatures);
return 0;
}
/**
* Initialize (or populate) domains for the platform
*

View File

@@ -11,16 +11,12 @@
#define __SBI_PMU_H__
#include <sbi/sbi_types.h>
#include <sbi/sbi_hartmask.h>
#include <sbi/sbi_scratch.h>
#include <sbi/sbi_ecall_interface.h>
struct sbi_scratch;
/* Event related macros */
/* Maximum number of hardware events that can mapped by OpenSBI */
#define SBI_PMU_HW_EVENT_MAX 64
/* Maximum number of firmware events that can mapped by OpenSBI */
#define SBI_PMU_FW_EVENT_MAX 32
#define SBI_PMU_HW_EVENT_MAX 256
/* Counter related macros */
#define SBI_PMU_FW_CTR_MAX 16
@@ -28,12 +24,77 @@
#define SBI_PMU_CTR_MAX (SBI_PMU_HW_CTR_MAX + SBI_PMU_FW_CTR_MAX)
#define SBI_PMU_FIXED_CTR_MASK 0x07
struct sbi_pmu_device {
/** Name of the PMU platform device */
char name[32];
/**
* Validate event code of custom firmware event
* Note: SBI_PMU_FW_MAX <= event_idx_code
*/
int (*fw_event_validate_code)(uint32_t event_idx_code);
/**
* Match custom firmware counter with custom firmware event
* Note: 0 <= counter_index < SBI_PMU_FW_CTR_MAX
*/
bool (*fw_counter_match_code)(uint32_t counter_index,
uint32_t event_idx_code);
/**
* Read value of custom firmware counter
* Note: 0 <= counter_index < SBI_PMU_FW_CTR_MAX
*/
uint64_t (*fw_counter_read_value)(uint32_t counter_index);
/**
* Start custom firmware counter
* Note: SBI_PMU_FW_MAX <= event_idx_code
* Note: 0 <= counter_index < SBI_PMU_FW_CTR_MAX
*/
int (*fw_counter_start)(uint32_t counter_index,
uint32_t event_idx_code,
uint64_t init_val, bool init_val_update);
/**
* Stop custom firmware counter
* Note: 0 <= counter_index < SBI_PMU_FW_CTR_MAX
*/
int (*fw_counter_stop)(uint32_t counter_index);
/**
* Custom enable irq for hardware counter
* Note: 0 <= counter_index < SBI_PMU_HW_CTR_MAX
*/
void (*hw_counter_enable_irq)(uint32_t counter_index);
/**
* Custom disable irq for hardware counter
* Note: 0 <= counter_index < SBI_PMU_HW_CTR_MAX
*/
void (*hw_counter_disable_irq)(uint32_t counter_index);
/**
* Custom function returning the machine-specific irq-bit.
*/
int (*hw_counter_irq_bit)(void);
};
/** Get the PMU platform device */
const struct sbi_pmu_device *sbi_pmu_get_device(void);
/** Set the PMU platform device */
void sbi_pmu_set_device(const struct sbi_pmu_device *dev);
/** Initialize PMU */
int sbi_pmu_init(struct sbi_scratch *scratch, bool cold_boot);
/** Reset PMU during hart exit */
void sbi_pmu_exit(struct sbi_scratch *scratch);
/** Return the pmu irq bit depending on extension existence */
int sbi_pmu_irq_bit(void);
/**
* Add the hardware event to counter mapping information. This should be called
* from the platform code to update the mapping table.
@@ -53,7 +114,7 @@ int sbi_pmu_add_hw_event_counter_map(u32 eidx_start, u32 eidx_end, u32 cmap);
int sbi_pmu_add_raw_event_counter_map(uint64_t select, uint64_t select_mask, u32 cmap);
int sbi_pmu_ctr_read(uint32_t cidx, unsigned long *cval);
int sbi_pmu_ctr_fw_read(uint32_t cidx, uint64_t *cval);
int sbi_pmu_ctr_stop(unsigned long cidx_base, unsigned long cidx_mask,
unsigned long flag);

View File

@@ -57,7 +57,7 @@ struct sbi_scratch {
unsigned long next_arg1;
/** Address of next booting stage for this HART */
unsigned long next_addr;
/** Priviledge mode of next booting stage for this HART */
/** Privilege mode of next booting stage for this HART */
unsigned long next_mode;
/** Warm boot entry point address for this HART */
unsigned long warmboot_addr;
@@ -73,6 +73,66 @@ struct sbi_scratch {
unsigned long options;
};
/**
* Prevent modification of struct sbi_scratch from affecting
* SBI_SCRATCH_xxx_OFFSET
*/
_Static_assert(
offsetof(struct sbi_scratch, fw_start)
== SBI_SCRATCH_FW_START_OFFSET,
"struct sbi_scratch definition has changed, please redefine "
"SBI_SCRATCH_FW_START_OFFSET");
_Static_assert(
offsetof(struct sbi_scratch, fw_size)
== SBI_SCRATCH_FW_SIZE_OFFSET,
"struct sbi_scratch definition has changed, please redefine "
"SBI_SCRATCH_FW_SIZE_OFFSET");
_Static_assert(
offsetof(struct sbi_scratch, next_arg1)
== SBI_SCRATCH_NEXT_ARG1_OFFSET,
"struct sbi_scratch definition has changed, please redefine "
"SBI_SCRATCH_NEXT_ARG1_OFFSET");
_Static_assert(
offsetof(struct sbi_scratch, next_addr)
== SBI_SCRATCH_NEXT_ADDR_OFFSET,
"struct sbi_scratch definition has changed, please redefine "
"SBI_SCRATCH_NEXT_ADDR_OFFSET");
_Static_assert(
offsetof(struct sbi_scratch, next_mode)
== SBI_SCRATCH_NEXT_MODE_OFFSET,
"struct sbi_scratch definition has changed, please redefine "
"SBI_SCRATCH_NEXT_MODE_OFFSET");
_Static_assert(
offsetof(struct sbi_scratch, warmboot_addr)
== SBI_SCRATCH_WARMBOOT_ADDR_OFFSET,
"struct sbi_scratch definition has changed, please redefine "
"SBI_SCRATCH_WARMBOOT_ADDR_OFFSET");
_Static_assert(
offsetof(struct sbi_scratch, platform_addr)
== SBI_SCRATCH_PLATFORM_ADDR_OFFSET,
"struct sbi_scratch definition has changed, please redefine "
"SBI_SCRATCH_PLATFORM_ADDR_OFFSET");
_Static_assert(
offsetof(struct sbi_scratch, hartid_to_scratch)
== SBI_SCRATCH_HARTID_TO_SCRATCH_OFFSET,
"struct sbi_scratch definition has changed, please redefine "
"SBI_SCRATCH_HARTID_TO_SCRATCH_OFFSET");
_Static_assert(
offsetof(struct sbi_scratch, trap_exit)
== SBI_SCRATCH_TRAP_EXIT_OFFSET,
"struct sbi_scratch definition has changed, please redefine "
"SBI_SCRATCH_TRAP_EXIT_OFFSET");
_Static_assert(
offsetof(struct sbi_scratch, tmp0)
== SBI_SCRATCH_TMP0_OFFSET,
"struct sbi_scratch definition has changed, please redefine "
"SBI_SCRATCH_TMP0_OFFSET");
_Static_assert(
offsetof(struct sbi_scratch, options)
== SBI_SCRATCH_OPTIONS_OFFSET,
"struct sbi_scratch definition has changed, please redefine "
"SBI_SCRATCH_OPTIONS_OFFSET");
/** Possible options for OpenSBI library */
enum sbi_scratch_options {
/** Disable prints during boot */
@@ -104,11 +164,11 @@ unsigned long sbi_scratch_alloc_offset(unsigned long size);
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))
#define sbi_scratch_offset_ptr(scratch, offset) (void *)((char *)(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))
(void *)((char *)sbi_scratch_thishart_ptr() + (offset))
/** HART id to scratch table */
extern struct sbi_scratch *hartid_to_scratch_table[];

View File

@@ -48,6 +48,24 @@ static inline void sbi_timer_udelay(ulong usecs)
sbi_timer_delay_loop(usecs, 1000000, NULL, NULL);
}
/**
* A blocking function that will wait until @p predicate returns true or
* @p timeout_ms milliseconds elapsed. @p arg will be passed as argument to
* @p predicate function.
*
* @param predicate Pointer to a function that returns true if certain
* condition is met. It shouldn't block the code execution.
* @param arg Argument to pass to @p predicate.
* @param timeout_ms Timeout value in milliseconds. The function will return
* false if @p timeout_ms time period elapsed but still @p predicate doesn't
* return true.
*
* @return true if @p predicate returns true within @p timeout_ms, false
* otherwise.
*/
bool sbi_timer_waitms_until(bool (*predicate)(void *), void *arg,
uint64_t timeout_ms);
/** Get timer value for current HART */
u64 sbi_timer_value(void);

View File

@@ -10,6 +10,8 @@
#ifndef __SBI_TRAP_H__
#define __SBI_TRAP_H__
#include <sbi/riscv_encoding.h>
/* clang-format off */
/** Index of zero member in sbi_trap_regs */
@@ -95,8 +97,10 @@
#define SBI_TRAP_INFO_tval2 3
/** Index of tinst member in sbi_trap_info */
#define SBI_TRAP_INFO_tinst 4
/** Index of gva member in sbi_trap_info */
#define SBI_TRAP_INFO_gva 5
/** Last member index in sbi_trap_info */
#define SBI_TRAP_INFO_last 5
#define SBI_TRAP_INFO_last 6
/* clang-format on */
@@ -200,8 +204,26 @@ struct sbi_trap_info {
unsigned long tval2;
/** tinst Trap instruction */
unsigned long tinst;
/** gva Guest virtual address in tval flag */
unsigned long gva;
};
static inline unsigned long sbi_regs_gva(const struct sbi_trap_regs *regs)
{
/*
* If the hypervisor extension is not implemented, mstatus[h].GVA is a
* WPRI field, which is guaranteed to read as zero. In addition, in this
* case we don't read mstatush and instead pretend it is zero, which
* handles privileged spec version < 1.12.
*/
#if __riscv_xlen == 32
return (regs->mstatusH & MSTATUSH_GVA) ? 1 : 0;
#else
return (regs->mstatus & MSTATUS_GVA) ? 1 : 0;
#endif
}
int sbi_trap_redirect(struct sbi_trap_regs *regs,
struct sbi_trap_info *trap);

View File

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

View File

@@ -13,6 +13,8 @@
#include <sbi/sbi_types.h>
#ifdef CONFIG_FDT_DOMAIN
struct sbi_domain;
/**
@@ -70,4 +72,11 @@ void fdt_domain_fixup(void *fdt);
*/
int fdt_domains_populate(void *fdt);
#else
static inline void fdt_domain_fixup(void *fdt) { }
static inline int fdt_domains_populate(void *fdt) { return 0; }
#endif
#endif /* __FDT_DOMAIN_H__ */

View File

@@ -21,6 +21,30 @@
*/
void fdt_cpu_fixup(void *fdt);
/**
* Fix up the APLIC nodes in the device tree
*
* This routine disables APLIC nodes which are not accessible to the next
* booting stage based on currently assigned domain.
*
* It is recommended that platform codes call this helper in their final_init()
*
* @param fdt: device tree blob
*/
void fdt_aplic_fixup(void *fdt);
/**
* Fix up the IMSIC nodes in the device tree
*
* This routine disables IMSIC nodes which are not accessible to the next
* booting stage based on currently assigned domain.
*
* It is recommended that platform codes call this helper in their final_init()
*
* @param fdt: device tree blob
*/
void fdt_imsic_fixup(void *fdt);
/**
* Fix up the PLIC node in the device tree
*
@@ -64,8 +88,9 @@ int fdt_reserved_memory_nomap_fixup(void *fdt);
* General device tree fix-up
*
* This routine do all required device tree fix-ups for a typical platform.
* It fixes up the PLIC node and the reserved memory node in the device tree
* by calling the corresponding helper routines to accomplish the task.
* It fixes up the PLIC node, IMSIC nodes, APLIC nodes, and the reserved
* memory node in the device tree by calling the corresponding helper
* routines to accomplish the task.
*
* It is recommended that platform codes call this helper in their final_init()
*

View File

@@ -15,7 +15,7 @@
struct fdt_match {
const char *compatible;
void *data;
const void *data;
};
#define FDT_MAX_PHANDLE_ARGS 16
@@ -31,6 +31,7 @@ struct platform_uart_data {
unsigned long baud;
unsigned long reg_shift;
unsigned long reg_io_width;
unsigned long reg_offset;
};
const struct fdt_match *fdt_match_node(void *fdt, int nodeoff,
@@ -47,27 +48,45 @@ int fdt_parse_phandle_with_args(void *fdt, int nodeoff,
int fdt_get_node_addr_size(void *fdt, int node, int index,
uint64_t *addr, uint64_t *size);
bool fdt_node_is_enabled(void *fdt, int nodeoff);
int fdt_parse_hart_id(void *fdt, int cpu_offset, u32 *hartid);
int fdt_parse_max_hart_id(void *fdt, u32 *max_hartid);
int fdt_parse_max_enabled_hart_id(void *fdt, u32 *max_hartid);
int fdt_parse_timebase_frequency(void *fdt, unsigned long *freq);
int fdt_parse_gaisler_uart_node(void *fdt, int nodeoffset,
struct platform_uart_data *uart);
int fdt_parse_renesas_scif_node(void *fdt, int nodeoffset,
struct platform_uart_data *uart);
int fdt_parse_shakti_uart_node(void *fdt, int nodeoffset,
struct platform_uart_data *uart);
int fdt_parse_sifive_uart_node(void *fdt, int nodeoffset,
struct platform_uart_data *uart);
int fdt_parse_uart8250_node(void *fdt, int nodeoffset,
struct platform_uart_data *uart);
int fdt_parse_uart_node(void *fdt, int nodeoffset,
struct platform_uart_data *uart);
int fdt_parse_uart8250(void *fdt, struct platform_uart_data *uart,
const char *compatible);
int fdt_parse_xlnx_uartlite_node(void *fdt, int nodeoffset,
struct platform_uart_data *uart);
struct aplic_data;
int fdt_parse_aplic_node(void *fdt, int nodeoff, struct aplic_data *aplic);
struct imsic_data;
bool fdt_check_imsic_mlevel(void *fdt);
int fdt_parse_imsic_node(void *fdt, int nodeoff, struct imsic_data *imsic);
struct plic_data;
int fdt_parse_plic_node(void *fdt, int nodeoffset, struct plic_data *plic);
@@ -79,6 +98,12 @@ int fdt_parse_aclint_node(void *fdt, int nodeoffset, bool for_timer,
unsigned long *out_addr2, unsigned long *out_size2,
u32 *out_first_hartid, u32 *out_hart_count);
int fdt_parse_plmt_node(void *fdt, int nodeoffset, unsigned long *plmt_base,
unsigned long *plmt_size, u32 *hart_count);
int fdt_parse_plicsw_node(void *fdt, int nodeoffset, unsigned long *plicsw_base,
unsigned long *size, u32 *hart_count);
int fdt_parse_compat_addr(void *fdt, uint64_t *addr,
const char *compatible);

View File

@@ -13,6 +13,8 @@
#include <sbi/sbi_types.h>
#ifdef CONFIG_FDT_PMU
/**
* Fix up the PMU node in the device tree
*
@@ -43,4 +45,12 @@ int fdt_pmu_setup(void *fdt);
*/
uint64_t fdt_pmu_get_select_value(uint32_t event_idx);
#else
static inline void fdt_pmu_fixup(void *fdt) { }
static inline int fdt_pmu_setup(void *fdt) { return 0; }
static inline uint64_t fdt_pmu_get_select_value(uint32_t event_idx) { return 0; }
#endif
#endif

View File

@@ -12,6 +12,8 @@
#include <sbi_utils/gpio/gpio.h>
struct fdt_phandle_args;
/** FDT based GPIO driver */
struct fdt_gpio {
const struct fdt_match *match_table;

View File

@@ -0,0 +1,46 @@
/*
* SPDX-License-Identifier: BSD-2-Clause
*
* Copyright (c) 2022 Andes Technology Corporation
*
* Authors:
* Zong Li <zong@andestech.com>
* Nylon Chen <nylon7@andestech.com>
* Leo Yu-Chi Liang <ycliang@andestech.com>
* Yu Chien Peter Lin <peterlin@andestech.com>
*/
#ifndef _IPI_ANDES_PLICSW_H_
#define _IPI_ANDES_PLICSW_H_
#define PLICSW_PRIORITY_BASE 0x4
#define PLICSW_PENDING_BASE 0x1000
#define PLICSW_PENDING_STRIDE 0x8
#define PLICSW_ENABLE_BASE 0x2000
#define PLICSW_ENABLE_STRIDE 0x80
#define PLICSW_CONTEXT_BASE 0x200000
#define PLICSW_CONTEXT_STRIDE 0x1000
#define PLICSW_CONTEXT_CLAIM 0x4
#define PLICSW_HART_MASK 0x01010101
#define PLICSW_HART_MAX_NR 8
#define PLICSW_REGION_ALIGN 0x1000
struct plicsw_data {
unsigned long addr;
unsigned long size;
uint32_t hart_count;
/* hart id to source id table */
uint32_t source_id[PLICSW_HART_MAX_NR];
};
int plicsw_warm_ipi_init(void);
int plicsw_cold_ipi_init(struct plicsw_data *plicsw);
#endif /* _IPI_ANDES_PLICSW_H_ */

View File

@@ -12,6 +12,8 @@
#include <sbi/sbi_types.h>
#ifdef CONFIG_FDT_IPI
struct fdt_ipi {
const struct fdt_match *match_table;
int (*cold_init)(void *fdt, int nodeoff, const struct fdt_match *match);
@@ -23,4 +25,11 @@ void fdt_ipi_exit(void);
int fdt_ipi_init(bool cold_boot);
#else
static inline void fdt_ipi_exit(void) { }
static inline int fdt_ipi_init(bool cold_boot) { return 0; }
#endif
#endif

View File

@@ -0,0 +1,47 @@
/*
* SPDX-License-Identifier: BSD-2-Clause
*
* Copyright (c) 2021 Western Digital Corporation or its affiliates.
* Copyright (c) 2022 Ventana Micro Systems Inc.
*
* Authors:
* Anup Patel <anup.patel@wdc.com>
*/
#ifndef __IRQCHIP_APLIC_H__
#define __IRQCHIP_APLIC_H__
#include <sbi/sbi_types.h>
#define APLIC_MAX_DELEGATE 16
struct aplic_msicfg_data {
unsigned long lhxs;
unsigned long lhxw;
unsigned long hhxs;
unsigned long hhxw;
unsigned long base_addr;
};
struct aplic_delegate_data {
u32 first_irq;
u32 last_irq;
u32 child_index;
};
struct aplic_data {
unsigned long addr;
unsigned long size;
unsigned long num_idc;
unsigned long num_source;
bool targets_mmode;
bool has_msicfg_mmode;
struct aplic_msicfg_data msicfg_mmode;
bool has_msicfg_smode;
struct aplic_msicfg_data msicfg_smode;
struct aplic_delegate_data delegate[APLIC_MAX_DELEGATE];
};
int aplic_cold_irqchip_init(struct aplic_data *aplic);
#endif

View File

@@ -12,6 +12,8 @@
#include <sbi/sbi_types.h>
#ifdef CONFIG_FDT_IRQCHIP
struct fdt_irqchip {
const struct fdt_match *match_table;
int (*cold_init)(void *fdt, int nodeoff, const struct fdt_match *match);
@@ -23,4 +25,12 @@ void fdt_irqchip_exit(void);
int fdt_irqchip_init(bool cold_boot);
#else
static inline void fdt_irqchip_exit(void) { }
static inline int fdt_irqchip_init(bool cold_boot) { return 0; }
#endif
#endif

View File

@@ -0,0 +1,33 @@
/*
* SPDX-License-Identifier: BSD-2-Clause
*
* Copyright (c) 2022 Samuel Holland <samuel@sholland.org>
*/
#ifndef __IRQCHIP_FDT_IRQCHIP_PLIC_H__
#define __IRQCHIP_FDT_IRQCHIP_PLIC_H__
#include <sbi/sbi_types.h>
/**
* Save the PLIC priority state
* @param priority pointer to the memory region for the saved priority
* @param num size of the memory region including interrupt source 0
*/
void fdt_plic_priority_save(u8 *priority, u32 num);
/**
* Restore the PLIC priority state
* @param priority pointer to the memory region for the saved priority
* @param num size of the memory region including interrupt source 0
*/
void fdt_plic_priority_restore(const u8 *priority, u32 num);
void fdt_plic_context_save(bool smode, u32 *enable, u32 *threshold, u32 num);
void fdt_plic_context_restore(bool smode, const u32 *enable, u32 threshold,
u32 num);
void thead_plic_restore(void);
#endif

View File

@@ -0,0 +1,60 @@
/*
* SPDX-License-Identifier: BSD-2-Clause
*
* Copyright (c) 2021 Western Digital Corporation or its affiliates.
* Copyright (c) 2022 Ventana Micro Systems Inc.
*
* Authors:
* Anup Patel <anup.patel@wdc.com>
*/
#ifndef __IRQCHIP_IMSIC_H__
#define __IRQCHIP_IMSIC_H__
#include <sbi/sbi_types.h>
#define IMSIC_MMIO_PAGE_SHIFT 12
#define IMSIC_MMIO_PAGE_SZ (1UL << IMSIC_MMIO_PAGE_SHIFT)
#define IMSIC_MAX_REGS 16
struct imsic_regs {
unsigned long addr;
unsigned long size;
};
struct imsic_data {
bool targets_mmode;
u32 guest_index_bits;
u32 hart_index_bits;
u32 group_index_bits;
u32 group_index_shift;
unsigned long num_ids;
struct imsic_regs regs[IMSIC_MAX_REGS];
};
#ifdef CONFIG_IRQCHIP_IMSIC
int imsic_map_hartid_to_data(u32 hartid, struct imsic_data *imsic, int file);
struct imsic_data *imsic_get_data(u32 hartid);
int imsic_get_target_file(u32 hartid);
void imsic_local_irqchip_init(void);
int imsic_warm_irqchip_init(void);
int imsic_data_check(struct imsic_data *imsic);
int imsic_cold_irqchip_init(struct imsic_data *imsic);
#else
static inline void imsic_local_irqchip_init(void) { }
static inline int imsic_data_check(struct imsic_data *imsic) { return 0; }
#endif
#endif

View File

@@ -17,13 +17,24 @@ struct plic_data {
unsigned long num_src;
};
int plic_warm_irqchip_init(struct plic_data *plic,
/* So far, priorities on all consumers of these functions fit in 8 bits. */
void plic_priority_save(const struct plic_data *plic, u8 *priority, u32 num);
void plic_priority_restore(const struct plic_data *plic, const u8 *priority,
u32 num);
void plic_context_save(const struct plic_data *plic, int context_id,
u32 *enable, u32 *threshold, u32 num);
void plic_context_restore(const struct plic_data *plic, int context_id,
const u32 *enable, u32 threshold, u32 num);
int plic_context_init(const struct plic_data *plic, int context_id,
bool enable, u32 threshold);
int plic_warm_irqchip_init(const struct plic_data *plic,
int m_cntx_id, int s_cntx_id);
int plic_cold_irqchip_init(struct plic_data *plic);
void plic_set_thresh(struct plic_data *plic, u32 cntxid, u32 val);
void plic_set_ie(struct plic_data *plic, u32 cntxid, u32 word_index, u32 val);
int plic_cold_irqchip_init(const struct plic_data *plic);
#endif

View File

@@ -17,6 +17,8 @@ struct fdt_reset {
int (*init)(void *fdt, int nodeoff, const struct fdt_match *match);
};
#ifdef CONFIG_FDT_RESET
/**
* fdt_reset_driver_init() - initialize reset driver based on the device-tree
*/
@@ -29,4 +31,14 @@ int fdt_reset_driver_init(void *fdt, struct fdt_reset *drv);
*/
void fdt_reset_init(void);
#else
static inline int fdt_reset_driver_init(void *fdt, struct fdt_reset *drv)
{
return 0;
}
static inline void fdt_reset_init(void) { }
#endif
#endif

View File

@@ -0,0 +1,16 @@
/*
* SPDX-License-Identifier: BSD-2-Clause
*
* Copyright (c) 2022 StarFive Technology Co., Ltd.
*
* Author: Jun Liang Tan <junliang.tan@linux.starfivetech.com>
*/
#ifndef __SERIAL_CADENCE_UART_H__
#define __SERIAL_CADENCE_UART_H__
#include <sbi/sbi_types.h>
int cadence_uart_init(unsigned long base, u32 in_freq, u32 baudrate);
#endif

View File

@@ -12,6 +12,8 @@
#include <sbi/sbi_types.h>
#ifdef CONFIG_FDT_SERIAL
struct fdt_serial {
const struct fdt_match *match_table;
int (*init)(void *fdt, int nodeoff, const struct fdt_match *match);
@@ -19,4 +21,10 @@ struct fdt_serial {
int fdt_serial_init(void);
#else
static inline int fdt_serial_init(void) { return 0; }
#endif
#endif

View File

@@ -0,0 +1,11 @@
/* SPDX-License-Identifier: BSD-2-Clause */
/*
* Copyright (C) 2022 Renesas Electronics Corporation
*/
#ifndef __SERIAL_RENESAS_SCIF_H__
#define __SERIAL_RENESAS_SCIF_H__
int renesas_scif_init(unsigned long base, u32 in_freq, u32 baudrate);
#endif /* __SERIAL_RENESAS_SCIF_H__ */

View File

@@ -0,0 +1,47 @@
/*
* SPDX-License-Identifier: BSD-2-Clause
*
* Copyright (c) 2022 Ventana Micro Systems Inc.
*
* Authors:
* Anup Patel <apatel@ventanamicro.com>
* Kautuk Consul <kconsul@ventanamicro.com>
*/
#ifndef __SERIAL_SEMIHOSTING_H__
#define __SERIAL_SEMIHOSTING_H__
#include <sbi/sbi_types.h>
/**
* enum semihosting_open_mode - Numeric file modes for use with semihosting_open()
* MODE_READ: 'r'
* MODE_BINARY: 'b'
* MODE_PLUS: '+'
* MODE_WRITE: 'w'
* MODE_APPEND: 'a'
*
* These modes represent the mode string used by fopen(3) in a form which can
* be passed to semihosting_open(). These do NOT correspond directly to %O_RDONLY,
* %O_CREAT, etc; see fopen(3) for details. In particular, @MODE_PLUS
* effectively results in adding %O_RDWR, and @MODE_WRITE will add %O_TRUNC.
* For compatibility, @MODE_BINARY should be added when opening non-text files
* (such as images).
*/
enum semihosting_open_mode {
MODE_READ = 0x0,
MODE_BINARY = 0x1,
MODE_PLUS = 0x2,
MODE_WRITE = 0x4,
MODE_APPEND = 0x8,
};
#ifdef CONFIG_SERIAL_SEMIHOSTING
int semihosting_init(void);
int semihosting_enabled(void);
#else
static inline int semihosting_init(void) { return SBI_ENODEV; }
static inline int semihosting_enabled(void) { return 0; }
#endif
#endif

View File

@@ -13,6 +13,6 @@
#include <sbi/sbi_types.h>
int uart8250_init(unsigned long base, u32 in_freq, u32 baudrate, u32 reg_shift,
u32 reg_width);
u32 reg_width, u32 reg_offset);
#endif

View File

@@ -0,0 +1,16 @@
/*
* SPDX-License-Identifier: BSD-2-Clause
*
* Copyright (c) 2022 Western Digital Corporation or its affiliates.
*
* Authors:
* Alistair Francis <alistair.francis@wdc.com>
*/
#ifndef __SERIAL_XLNX_UARTLITE_H__
#define __SERIAL_XLNX_UARTLITE_H__
#include <sbi/sbi_types.h>
int xlnx_uartlite_init(unsigned long base);
#endif

View File

@@ -10,8 +10,12 @@
#include <sbi/sbi_types.h>
int htif_serial_init(void);
int htif_serial_init(bool custom_addr,
unsigned long custom_fromhost_addr,
unsigned long custom_tohost_addr);
int htif_system_reset_init(void);
int htif_system_reset_init(bool custom_addr,
unsigned long custom_fromhost_addr,
unsigned long custom_tohost_addr);
#endif

View File

@@ -22,6 +22,8 @@
#define CLINT_MTIMER_OFFSET 0x4000
#define MTIMER_REGION_ALIGN 0x1000
struct aclint_mtimer_data {
/* Public details */
unsigned long mtime_freq;

View File

@@ -0,0 +1,29 @@
/*
* SPDX-License-Identifier: BSD-2-Clause
*
* Copyright (c) 2022 Andes Technology Corporation
*
* Authors:
* Zong Li <zong@andestech.com>
* Nylon Chen <nylon7@andestech.com>
* Yu Chien Peter Lin <peterlin@andestech.com>
*/
#ifndef __TIMER_ANDES_PLMT_H__
#define __TIMER_ANDES_PLMT_H__
#define DEFAULT_AE350_PLMT_FREQ 60000000
#define PLMT_REGION_ALIGN 0x1000
struct plmt_data {
u32 hart_count;
unsigned long size;
unsigned long timer_freq;
volatile u64 *time_val;
volatile u64 *time_cmp;
};
int plmt_cold_timer_init(struct plmt_data *plmt);
int plmt_warm_timer_init(void);
#endif /* __TIMER_ANDES_PLMT_H__ */

View File

@@ -12,6 +12,8 @@
#include <sbi/sbi_types.h>
#ifdef CONFIG_FDT_TIMER
struct fdt_timer {
const struct fdt_match *match_table;
int (*cold_init)(void *fdt, int nodeoff, const struct fdt_match *match);
@@ -23,4 +25,11 @@ void fdt_timer_exit(void);
int fdt_timer_init(bool cold_boot);
#else
static inline void fdt_timer_exit(void) { }
static inline int fdt_timer_init(bool cold_boot) { return 0; }
#endif
#endif

37
lib/sbi/Kconfig Normal file
View File

@@ -0,0 +1,37 @@
# SPDX-License-Identifier: BSD-2-Clause
menu "SBI Extension Support"
config SBI_ECALL_TIME
bool "Timer extension"
default y
config SBI_ECALL_RFENCE
bool "RFENCE extension"
default y
config SBI_ECALL_IPI
bool "IPI extension"
default y
config SBI_ECALL_HSM
bool "Hart State Management extension"
default y
config SBI_ECALL_SRST
bool "System Reset extension"
default y
config SBI_ECALL_PMU
bool "Performance Monitoring Unit extension"
default y
config SBI_ECALL_LEGACY
bool "SBI v0.1 legacy extensions"
default y
config SBI_ECALL_VENDOR
bool "Platform-defined vendor extensions"
default y
endmenu

View File

@@ -12,17 +12,41 @@ libsbi-objs-y += riscv_atomic.o
libsbi-objs-y += riscv_hardfp.o
libsbi-objs-y += riscv_locks.o
libsbi-objs-y += sbi_ecall.o
libsbi-objs-y += sbi_ecall_exts.o
# The order of below extensions is performance optimized
carray-sbi_ecall_exts-$(CONFIG_SBI_ECALL_TIME) += ecall_time
libsbi-objs-$(CONFIG_SBI_ECALL_TIME) += sbi_ecall_time.o
carray-sbi_ecall_exts-$(CONFIG_SBI_ECALL_RFENCE) += ecall_rfence
libsbi-objs-$(CONFIG_SBI_ECALL_RFENCE) += sbi_ecall_rfence.o
carray-sbi_ecall_exts-$(CONFIG_SBI_ECALL_IPI) += ecall_ipi
libsbi-objs-$(CONFIG_SBI_ECALL_IPI) += sbi_ecall_ipi.o
carray-sbi_ecall_exts-y += ecall_base
libsbi-objs-y += sbi_ecall_base.o
carray-sbi_ecall_exts-$(CONFIG_SBI_ECALL_HSM) += ecall_hsm
libsbi-objs-$(CONFIG_SBI_ECALL_HSM) += sbi_ecall_hsm.o
carray-sbi_ecall_exts-$(CONFIG_SBI_ECALL_SRST) += ecall_srst
libsbi-objs-$(CONFIG_SBI_ECALL_SRST) += sbi_ecall_srst.o
carray-sbi_ecall_exts-$(CONFIG_SBI_ECALL_PMU) += ecall_pmu
libsbi-objs-$(CONFIG_SBI_ECALL_PMU) += sbi_ecall_pmu.o
carray-sbi_ecall_exts-$(CONFIG_SBI_ECALL_LEGACY) += ecall_legacy
libsbi-objs-$(CONFIG_SBI_ECALL_LEGACY) += sbi_ecall_legacy.o
carray-sbi_ecall_exts-$(CONFIG_SBI_ECALL_VENDOR) += ecall_vendor
libsbi-objs-$(CONFIG_SBI_ECALL_VENDOR) += sbi_ecall_vendor.o
libsbi-objs-y += sbi_bitmap.o
libsbi-objs-y += sbi_bitops.o
libsbi-objs-y += sbi_console.o
libsbi-objs-y += sbi_domain.o
libsbi-objs-y += sbi_ecall.o
libsbi-objs-y += sbi_ecall_base.o
libsbi-objs-y += sbi_ecall_hsm.o
libsbi-objs-y += sbi_ecall_legacy.o
libsbi-objs-y += sbi_ecall_pmu.o
libsbi-objs-y += sbi_ecall_replace.o
libsbi-objs-y += sbi_ecall_vendor.o
libsbi-objs-y += sbi_emulate_csr.o
libsbi-objs-y += sbi_fifo.o
libsbi-objs-y += sbi_hart.o
@@ -32,6 +56,7 @@ libsbi-objs-y += sbi_hsm.o
libsbi-objs-y += sbi_illegal_insn.o
libsbi-objs-y += sbi_init.o
libsbi-objs-y += sbi_ipi.o
libsbi-objs-y += sbi_irqchip.o
libsbi-objs-y += sbi_misaligned_ldst.o
libsbi-objs-y += sbi_platform.o
libsbi-objs-y += sbi_pmu.o

View File

@@ -53,7 +53,7 @@ int misa_xlen(void)
void misa_string(int xlen, char *out, unsigned int out_sz)
{
unsigned int i, pos = 0;
const char valid_isa_order[] = "iemafdqclbjtpvnsuhkorwxyzg";
const char valid_isa_order[] = "iemafdqclbjtpvnhkorwxyzg";
if (!out)
return;
@@ -139,6 +139,10 @@ unsigned long csr_read_num(int csr_num)
switchcase_csr_read_4(CSR_MHPMCOUNTER4H, ret)
switchcase_csr_read_8(CSR_MHPMCOUNTER8H, ret)
switchcase_csr_read_16(CSR_MHPMCOUNTER16H, ret)
/**
* The CSR range MHPMEVENT[3-16]H are available only if sscofpmf
* extension is present. The caller must ensure that.
*/
switchcase_csr_read(CSR_MHPMEVENT3H, ret)
switchcase_csr_read_4(CSR_MHPMEVENT4H, ret)
switchcase_csr_read_8(CSR_MHPMEVENT8H, ret)
@@ -261,7 +265,7 @@ int pmp_set(unsigned int n, unsigned long prot, unsigned long addr,
pmpcfg_csr = (CSR_PMPCFG0 + (n >> 2)) & ~1;
pmpcfg_shift = (n & 7) << 3;
#else
return SBI_ENOTSUPP;
# error "Unexpected __riscv_xlen"
#endif
pmpaddr_csr = CSR_PMPADDR0 + n;
@@ -312,7 +316,7 @@ int pmp_get(unsigned int n, unsigned long *prot_out, unsigned long *addr_out,
pmpcfg_csr = (CSR_PMPCFG0 + (n >> 2)) & ~1;
pmpcfg_shift = (n & 7) << 3;
#else
return SBI_ENOTSUPP;
# error "Unexpected __riscv_xlen"
#endif
pmpaddr_csr = CSR_PMPADDR0 + n;

View File

@@ -39,7 +39,7 @@ unsigned long find_first_bit(const unsigned long *addr,
if (tmp == 0UL) /* Are any bits set? */
return result + size; /* Nope. */
found:
return result + __ffs(tmp);
return result + sbi_ffs(tmp);
}
/**
@@ -69,7 +69,7 @@ unsigned long find_first_zero_bit(const unsigned long *addr,
if (tmp == ~0UL) /* Are any bits zero? */
return result + size; /* Nope. */
found:
return result + ffz(tmp);
return result + sbi_ffz(tmp);
}
/**
@@ -100,7 +100,7 @@ unsigned long find_last_bit(const unsigned long *addr,
tmp = addr[--words];
if (tmp) {
found:
return words * BITS_PER_LONG + __fls(tmp);
return words * BITS_PER_LONG + sbi_fls(tmp);
}
}
@@ -150,7 +150,7 @@ found_first:
if (tmp == 0UL) /* Are any bits set? */
return result + size; /* Nope. */
found_middle:
return result + __ffs(tmp);
return result + sbi_ffs(tmp);
}
/**
@@ -196,5 +196,5 @@ found_first:
if (tmp == ~0UL) /* Are any bits zero? */
return result + size; /* Nope. */
found_middle:
return result + ffz(tmp);
return result + sbi_ffz(tmp);
}

View File

@@ -76,20 +76,22 @@ typedef __builtin_va_list va_list;
static void printc(char **out, u32 *out_len, char ch)
{
if (out) {
if (*out) {
if (out_len && (0 < *out_len)) {
**out = ch;
++(*out);
(*out_len)--;
} else {
**out = ch;
++(*out);
}
}
} else {
if (!out) {
sbi_putc(ch);
return;
}
/*
* The *printf entry point functions have enforced that (*out) can
* only be null when out_len is non-null and its value is zero.
*/
if (!out_len || *out_len > 1) {
*(*out)++ = ch;
**out = '\0';
}
if (out_len && *out_len > 0)
--(*out_len);
}
static int prints(char **out, u32 *out_len, const char *string, int width,
@@ -181,7 +183,7 @@ static int printi(char **out, u32 *out_len, long long i, int b, int sg,
static int print(char **out, u32 *out_len, const char *format, va_list args)
{
int width, flags, acnt = 0;
int width, flags;
int pc = 0;
char scr[2];
unsigned long long tmp;
@@ -193,7 +195,7 @@ static int print(char **out, u32 *out_len, const char *format, va_list args)
if (*format == '\0')
break;
if (*format == '%')
goto out;
goto literal;
/* Get flags */
if (*format == '-') {
++format;
@@ -214,7 +216,6 @@ static int print(char **out, u32 *out_len, const char *format, va_list args)
}
if (*format == 's') {
char *s = va_arg(args, char *);
acnt += sizeof(char *);
pc += prints(out, out_len, s ? s : "(null)",
width, flags);
continue;
@@ -222,61 +223,40 @@ static int print(char **out, u32 *out_len, const char *format, va_list args)
if ((*format == 'd') || (*format == 'i')) {
pc += printi(out, out_len, va_arg(args, int),
10, 1, width, flags, '0');
acnt += sizeof(int);
continue;
}
if (*format == 'x') {
pc += printi(out, out_len,
va_arg(args, unsigned int), 16, 0,
width, flags, 'a');
acnt += sizeof(unsigned int);
continue;
}
if (*format == 'X') {
pc += printi(out, out_len,
va_arg(args, unsigned int), 16, 0,
width, flags, 'A');
acnt += sizeof(unsigned int);
continue;
}
if (*format == 'u') {
pc += printi(out, out_len,
va_arg(args, unsigned int), 10, 0,
width, flags, 'a');
acnt += sizeof(unsigned int);
continue;
}
if (*format == 'p') {
pc += printi(out, out_len,
va_arg(args, unsigned long), 16, 0,
width, flags, 'a');
acnt += sizeof(unsigned long);
continue;
}
if (*format == 'P') {
pc += printi(out, out_len,
va_arg(args, unsigned long), 16, 0,
width, flags, 'A');
acnt += sizeof(unsigned long);
continue;
}
if (*format == 'l' && *(format + 1) == 'l') {
while (acnt &
(sizeof(unsigned long long) - 1)) {
va_arg(args, int);
acnt += sizeof(int);
}
if (sizeof(unsigned long long) ==
sizeof(unsigned long)) {
tmp = va_arg(args, unsigned long long);
acnt += sizeof(unsigned long long);
} else {
((unsigned long *)&tmp)[0] =
va_arg(args, unsigned long);
((unsigned long *)&tmp)[1] =
va_arg(args, unsigned long);
acnt += 2 * sizeof(unsigned long);
}
tmp = va_arg(args, unsigned long long);
if (*(format + 2) == 'u') {
format += 2;
pc += printi(out, out_len, tmp, 10, 0,
@@ -308,19 +288,16 @@ static int print(char **out, u32 *out_len, const char *format, va_list args)
out, out_len,
va_arg(args, unsigned long), 16,
0, width, flags, 'a');
acnt += sizeof(unsigned long);
} else if (*(format + 1) == 'X') {
format += 1;
pc += printi(
out, out_len,
va_arg(args, unsigned long), 16,
0, width, flags, 'A');
acnt += sizeof(unsigned long);
} else {
pc += printi(out, out_len,
va_arg(args, long), 10, 1,
width, flags, '0');
acnt += sizeof(long);
}
}
if (*format == 'c') {
@@ -328,17 +305,14 @@ static int print(char **out, u32 *out_len, const char *format, va_list args)
scr[0] = va_arg(args, int);
scr[1] = '\0';
pc += prints(out, out_len, scr, width, flags);
acnt += sizeof(int);
continue;
}
} else {
out:
literal:
printc(out, out_len, *format);
++pc;
}
}
if (out)
**out = '\0';
return pc;
}
@@ -348,6 +322,9 @@ int sbi_sprintf(char *out, const char *format, ...)
va_list args;
int retval;
if (unlikely(!out))
sbi_panic("sbi_sprintf called with NULL output string\n");
va_start(args, format);
retval = print(&out, NULL, format, args);
va_end(args);
@@ -360,6 +337,10 @@ int sbi_snprintf(char *out, u32 out_sz, const char *format, ...)
va_list args;
int retval;
if (unlikely(!out && out_sz != 0))
sbi_panic("sbi_snprintf called with NULL output string and "
"output size is not zero\n");
va_start(args, format);
retval = print(&out, &out_sz, format, args);
va_end(args);

View File

@@ -105,7 +105,7 @@ bool sbi_domain_check_addr(const struct sbi_domain *dom,
unsigned long addr, unsigned long mode,
unsigned long access_flags)
{
bool mmio = FALSE;
bool rmmio, mmio = FALSE;
struct sbi_domain_memregion *reg;
unsigned long rstart, rend, rflags, rwx = 0;
@@ -130,8 +130,8 @@ bool sbi_domain_check_addr(const struct sbi_domain *dom,
rend = (reg->order < __riscv_xlen) ?
rstart + ((1UL << reg->order) - 1) : -1UL;
if (rstart <= addr && addr <= rend) {
if ((mmio && !(rflags & SBI_DOMAIN_MEMREGION_MMIO)) ||
(!mmio && (rflags & SBI_DOMAIN_MEMREGION_MMIO)))
rmmio = (rflags & SBI_DOMAIN_MEMREGION_MMIO) ? TRUE : FALSE;
if (mmio != rmmio)
return FALSE;
return ((rflags & rwx) == rwx) ? TRUE : FALSE;
}
@@ -146,7 +146,10 @@ static bool is_region_valid(const struct sbi_domain_memregion *reg)
if (reg->order < 3 || __riscv_xlen < reg->order)
return FALSE;
if (reg->base & (BIT(reg->order) - 1))
if (reg->order == __riscv_xlen && reg->base != 0)
return FALSE;
if (reg->order < __riscv_xlen && (reg->base & (BIT(reg->order) - 1)))
return FALSE;
return TRUE;
@@ -159,7 +162,7 @@ static bool is_region_subset(const struct sbi_domain_memregion *regA,
ulong regA_start = regA->base;
ulong regA_end = regA->base + (BIT(regA->order) - 1);
ulong regB_start = regB->base;
ulong regB_end = regB->base + (BIT(regA->order) - 1);
ulong regB_end = regB->base + (BIT(regB->order) - 1);
if ((regB_start <= regA_start) &&
(regA_start < regB_end) &&
@@ -471,8 +474,12 @@ int sbi_domain_root_add_memregion(const struct sbi_domain_memregion *reg)
/* Check for conflicts */
sbi_domain_for_each_memregion(&root, nreg) {
if (is_region_conflict(reg, nreg))
return SBI_EINVAL;
if (is_region_conflict(reg, nreg)) {
sbi_printf("%s: is_region_conflict check failed"
" 0x%lx conflicts existing 0x%lx\n", __func__,
reg->base, nreg->base);
return SBI_EALREADY;
}
}
/* Append the memregion to root memregions */
@@ -518,6 +525,33 @@ int sbi_domain_root_add_memregion(const struct sbi_domain_memregion *reg)
return 0;
}
int sbi_domain_root_add_memrange(unsigned long addr, unsigned long size,
unsigned long align, unsigned long region_flags)
{
int rc;
unsigned long pos, end, rsize;
struct sbi_domain_memregion reg;
pos = addr;
end = addr + size;
while (pos < end) {
rsize = pos & (align - 1);
if (rsize)
rsize = 1UL << sbi_ffs(pos);
else
rsize = ((end - pos) < align) ?
(end - pos) : align;
sbi_domain_memregion_init(pos, rsize, region_flags, &reg);
rc = sbi_domain_root_add_memregion(&reg);
if (rc)
return rc;
pos += rsize;
}
return 0;
}
int sbi_domain_finalize(struct sbi_scratch *scratch, u32 cold_hartid)
{
int rc;

View File

@@ -13,6 +13,9 @@
#include <sbi/sbi_error.h>
#include <sbi/sbi_trap.h>
extern struct sbi_ecall_extension *sbi_ecall_exts[];
extern unsigned long sbi_ecall_exts_size;
u16 sbi_ecall_version_major(void)
{
return SBI_ECALL_VERSION_MAJOR;
@@ -144,35 +147,15 @@ int sbi_ecall_handler(struct sbi_trap_regs *regs)
int sbi_ecall_init(void)
{
int ret;
struct sbi_ecall_extension *ext;
unsigned long i;
/* The order of below registrations is performance optimized */
ret = sbi_ecall_register_extension(&ecall_time);
if (ret)
return ret;
ret = sbi_ecall_register_extension(&ecall_rfence);
if (ret)
return ret;
ret = sbi_ecall_register_extension(&ecall_ipi);
if (ret)
return ret;
ret = sbi_ecall_register_extension(&ecall_base);
if (ret)
return ret;
ret = sbi_ecall_register_extension(&ecall_hsm);
if (ret)
return ret;
ret = sbi_ecall_register_extension(&ecall_srst);
if (ret)
return ret;
ret = sbi_ecall_register_extension(&ecall_pmu);
if (ret)
return ret;
ret = sbi_ecall_register_extension(&ecall_legacy);
if (ret)
return ret;
ret = sbi_ecall_register_extension(&ecall_vendor);
if (ret)
return ret;
for (i = 0; i < sbi_ecall_exts_size; i++) {
ext = sbi_ecall_exts[i];
ret = sbi_ecall_register_extension(ext);
if (ret)
return ret;
}
return 0;
}

View File

@@ -0,0 +1,3 @@
HEADER: sbi/sbi_ecall.h
TYPE: struct sbi_ecall_extension
NAME: sbi_ecall_exts

36
lib/sbi/sbi_ecall_ipi.c Normal file
View File

@@ -0,0 +1,36 @@
/*
* SPDX-License-Identifier: BSD-2-Clause
*
* Copyright (c) 2020 Western Digital Corporation or its affiliates.
*
* Authors:
* Anup Patel <anup.patel@wdc.com>
* Atish Patra <atish.patra@wdc.com>
*/
#include <sbi/sbi_error.h>
#include <sbi/sbi_ecall.h>
#include <sbi/sbi_ecall_interface.h>
#include <sbi/sbi_trap.h>
#include <sbi/sbi_ipi.h>
static int sbi_ecall_ipi_handler(unsigned long extid, unsigned long funcid,
const struct sbi_trap_regs *regs,
unsigned long *out_val,
struct sbi_trap_info *out_trap)
{
int ret = 0;
if (funcid == SBI_EXT_IPI_SEND_IPI)
ret = sbi_ipi_send_smode(regs->a0, regs->a1);
else
ret = SBI_ENOTSUPP;
return ret;
}
struct sbi_ecall_extension ecall_ipi = {
.extid_start = SBI_EXT_IPI,
.extid_end = SBI_EXT_IPI,
.handle = sbi_ecall_ipi_handler,
};

View File

@@ -51,7 +51,8 @@ static int sbi_ecall_pmu_handler(unsigned long extid, unsigned long funcid,
break;
case SBI_EXT_PMU_COUNTER_FW_READ:
ret = sbi_pmu_ctr_read(regs->a0, out_val);
ret = sbi_pmu_ctr_fw_read(regs->a0, &temp);
*out_val = temp;
break;
case SBI_EXT_PMU_COUNTER_START:

View File

@@ -9,40 +9,11 @@
*/
#include <sbi/riscv_asm.h>
#include <sbi/sbi_error.h>
#include <sbi/sbi_ecall.h>
#include <sbi/sbi_ecall_interface.h>
#include <sbi/sbi_error.h>
#include <sbi/sbi_hart.h>
#include <sbi/sbi_ipi.h>
#include <sbi/sbi_system.h>
#include <sbi/sbi_timer.h>
#include <sbi/sbi_tlb.h>
#include <sbi/sbi_trap.h>
static int sbi_ecall_time_handler(unsigned long extid, unsigned long funcid,
const struct sbi_trap_regs *regs,
unsigned long *out_val,
struct sbi_trap_info *out_trap)
{
int ret = 0;
if (funcid == SBI_EXT_TIME_SET_TIMER) {
#if __riscv_xlen == 32
sbi_timer_event_start((((u64)regs->a1 << 32) | (u64)regs->a0));
#else
sbi_timer_event_start((u64)regs->a0);
#endif
} else
ret = SBI_ENOTSUPP;
return ret;
}
struct sbi_ecall_extension ecall_time = {
.extid_start = SBI_EXT_TIME,
.extid_end = SBI_EXT_TIME,
.handle = sbi_ecall_time_handler,
};
#include <sbi/sbi_tlb.h>
static int sbi_ecall_rfence_handler(unsigned long extid, unsigned long funcid,
const struct sbi_trap_regs *regs,
@@ -113,84 +84,3 @@ struct sbi_ecall_extension ecall_rfence = {
.extid_end = SBI_EXT_RFENCE,
.handle = sbi_ecall_rfence_handler,
};
static int sbi_ecall_ipi_handler(unsigned long extid, unsigned long funcid,
const struct sbi_trap_regs *regs,
unsigned long *out_val,
struct sbi_trap_info *out_trap)
{
int ret = 0;
if (funcid == SBI_EXT_IPI_SEND_IPI)
ret = sbi_ipi_send_smode(regs->a0, regs->a1);
else
ret = SBI_ENOTSUPP;
return ret;
}
struct sbi_ecall_extension ecall_ipi = {
.extid_start = SBI_EXT_IPI,
.extid_end = SBI_EXT_IPI,
.handle = sbi_ecall_ipi_handler,
};
static int sbi_ecall_srst_handler(unsigned long extid, unsigned long funcid,
const struct sbi_trap_regs *regs,
unsigned long *out_val,
struct sbi_trap_info *out_trap)
{
if (funcid == SBI_EXT_SRST_RESET) {
if ((((u32)-1U) <= ((u64)regs->a0)) ||
(((u32)-1U) <= ((u64)regs->a1)))
return SBI_EINVAL;
switch (regs->a0) {
case SBI_SRST_RESET_TYPE_SHUTDOWN:
case SBI_SRST_RESET_TYPE_COLD_REBOOT:
case SBI_SRST_RESET_TYPE_WARM_REBOOT:
break;
default:
return SBI_EINVAL;
}
switch (regs->a1) {
case SBI_SRST_RESET_REASON_NONE:
case SBI_SRST_RESET_REASON_SYSFAIL:
break;
default:
return SBI_EINVAL;
}
if (sbi_system_reset_supported(regs->a0, regs->a1))
sbi_system_reset(regs->a0, regs->a1);
}
return SBI_ENOTSUPP;
}
static int sbi_ecall_srst_probe(unsigned long extid, unsigned long *out_val)
{
u32 type, count = 0;
/*
* At least one standard reset types should be supported by
* the platform for SBI SRST extension to be usable.
*/
for (type = 0; type <= SBI_SRST_RESET_TYPE_LAST; type++) {
if (sbi_system_reset_supported(type,
SBI_SRST_RESET_REASON_NONE))
count++;
}
*out_val = (count) ? 1 : 0;
return 0;
}
struct sbi_ecall_extension ecall_srst = {
.extid_start = SBI_EXT_SRST,
.extid_end = SBI_EXT_SRST,
.handle = sbi_ecall_srst_handler,
.probe = sbi_ecall_srst_probe,
};

75
lib/sbi/sbi_ecall_srst.c Normal file
View File

@@ -0,0 +1,75 @@
/*
* SPDX-License-Identifier: BSD-2-Clause
*
* Copyright (c) 2020 Western Digital Corporation or its affiliates.
*
* Authors:
* Anup Patel <anup.patel@wdc.com>
* Atish Patra <atish.patra@wdc.com>
*/
#include <sbi/sbi_error.h>
#include <sbi/sbi_ecall.h>
#include <sbi/sbi_ecall_interface.h>
#include <sbi/sbi_trap.h>
#include <sbi/sbi_system.h>
static int sbi_ecall_srst_handler(unsigned long extid, unsigned long funcid,
const struct sbi_trap_regs *regs,
unsigned long *out_val,
struct sbi_trap_info *out_trap)
{
if (funcid == SBI_EXT_SRST_RESET) {
if ((((u32)-1U) <= ((u64)regs->a0)) ||
(((u32)-1U) <= ((u64)regs->a1)))
return SBI_EINVAL;
switch (regs->a0) {
case SBI_SRST_RESET_TYPE_SHUTDOWN:
case SBI_SRST_RESET_TYPE_COLD_REBOOT:
case SBI_SRST_RESET_TYPE_WARM_REBOOT:
break;
default:
return SBI_EINVAL;
}
switch (regs->a1) {
case SBI_SRST_RESET_REASON_NONE:
case SBI_SRST_RESET_REASON_SYSFAIL:
break;
default:
return SBI_EINVAL;
}
if (sbi_system_reset_supported(regs->a0, regs->a1))
sbi_system_reset(regs->a0, regs->a1);
}
return SBI_ENOTSUPP;
}
static int sbi_ecall_srst_probe(unsigned long extid, unsigned long *out_val)
{
u32 type, count = 0;
/*
* At least one standard reset types should be supported by
* the platform for SBI SRST extension to be usable.
*/
for (type = 0; type <= SBI_SRST_RESET_TYPE_LAST; type++) {
if (sbi_system_reset_supported(type,
SBI_SRST_RESET_REASON_NONE))
count++;
}
*out_val = (count) ? 1 : 0;
return 0;
}
struct sbi_ecall_extension ecall_srst = {
.extid_start = SBI_EXT_SRST,
.extid_end = SBI_EXT_SRST,
.handle = sbi_ecall_srst_handler,
.probe = sbi_ecall_srst_probe,
};

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

@@ -0,0 +1,40 @@
/*
* SPDX-License-Identifier: BSD-2-Clause
*
* Copyright (c) 2020 Western Digital Corporation or its affiliates.
*
* Authors:
* Anup Patel <anup.patel@wdc.com>
* Atish Patra <atish.patra@wdc.com>
*/
#include <sbi/sbi_error.h>
#include <sbi/sbi_ecall.h>
#include <sbi/sbi_ecall_interface.h>
#include <sbi/sbi_trap.h>
#include <sbi/sbi_timer.h>
static int sbi_ecall_time_handler(unsigned long extid, unsigned long funcid,
const struct sbi_trap_regs *regs,
unsigned long *out_val,
struct sbi_trap_info *out_trap)
{
int ret = 0;
if (funcid == SBI_EXT_TIME_SET_TIMER) {
#if __riscv_xlen == 32
sbi_timer_event_start((((u64)regs->a1 << 32) | (u64)regs->a0));
#else
sbi_timer_event_start((u64)regs->a0);
#endif
} else
ret = SBI_ENOTSUPP;
return ret;
}
struct sbi_ecall_extension ecall_time = {
.extid_start = SBI_EXT_TIME,
.extid_end = SBI_EXT_TIME,
.handle = sbi_ecall_time_handler,
};

View File

@@ -24,7 +24,7 @@ static bool hpm_allowed(int hpm_num, ulong prev_mode, bool virt)
struct sbi_scratch *scratch = sbi_scratch_thishart_ptr();
if (prev_mode <= PRV_S) {
if (sbi_hart_has_feature(scratch, SBI_HART_HAS_MCOUNTEREN)) {
if (sbi_hart_priv_version(scratch) >= SBI_HART_PRIV_VER_1_10) {
cen &= csr_read(CSR_MCOUNTEREN);
if (virt)
cen &= csr_read(CSR_HCOUNTEREN);
@@ -33,7 +33,7 @@ static bool hpm_allowed(int hpm_num, ulong prev_mode, bool virt)
}
}
if (prev_mode == PRV_U) {
if (sbi_hart_has_feature(scratch, SBI_HART_HAS_SCOUNTEREN))
if (sbi_hart_priv_version(scratch) >= SBI_HART_PRIV_VER_1_10)
cen &= csr_read(CSR_SCOUNTEREN);
else
cen = 0;

View File

@@ -11,7 +11,7 @@
#include <sbi/sbi_trap.h>
/*
* We assume that faulting instruction is is 4-byte long and blindly
* We assume that faulting instruction is 4-byte long and blindly
* increment SEPC by 4.
*
* The trap info will be saved as follows:
@@ -22,7 +22,7 @@
.align 3
.global __sbi_expected_trap
__sbi_expected_trap:
/* Without H-extension so, MTVAL2 and MTINST CSRs not available */
/* Without H-extension so, MTVAL2 and MTINST CSRs and GVA not available */
csrr a4, CSR_MEPC
REG_S a4, SBI_TRAP_INFO_OFFSET(epc)(a3)
csrr a4, CSR_MCAUSE
@@ -31,6 +31,7 @@ __sbi_expected_trap:
REG_S a4, SBI_TRAP_INFO_OFFSET(tval)(a3)
REG_S zero, SBI_TRAP_INFO_OFFSET(tval2)(a3)
REG_S zero, SBI_TRAP_INFO_OFFSET(tinst)(a3)
REG_S zero, SBI_TRAP_INFO_OFFSET(gva)(a3)
csrr a4, CSR_MEPC
addi a4, a4, 4
csrw CSR_MEPC, a4
@@ -39,7 +40,7 @@ __sbi_expected_trap:
.align 3
.global __sbi_expected_trap_hext
__sbi_expected_trap_hext:
/* With H-extension so, MTVAL2 and MTINST CSRs available */
/* With H-extension so, MTVAL2 and MTINST CSRs and GVA available */
csrr a4, CSR_MEPC
REG_S a4, SBI_TRAP_INFO_OFFSET(epc)(a3)
csrr a4, CSR_MCAUSE
@@ -50,6 +51,18 @@ __sbi_expected_trap_hext:
REG_S a4, SBI_TRAP_INFO_OFFSET(tval2)(a3)
csrr a4, CSR_MTINST
REG_S a4, SBI_TRAP_INFO_OFFSET(tinst)(a3)
/* Extract GVA bit from MSTATUS or MSTATUSH */
#if __riscv_xlen == 32
csrr a4, CSR_MSTATUSH
srli a4, a4, MSTATUSH_GVA_SHIFT
#else
csrr a4, CSR_MSTATUS
srli a4, a4, MSTATUS_GVA_SHIFT
#endif
andi a4, a4, 1
REG_S a4, SBI_TRAP_INFO_OFFSET(gva)(a3)
csrr a4, CSR_MEPC
addi a4, a4, 4
csrw CSR_MEPC, a4

View File

@@ -66,7 +66,7 @@ static inline void __sbi_fifo_enqueue(struct sbi_fifo *fifo, void *data)
if (head >= fifo->num_entries)
head = head - fifo->num_entries;
sbi_memcpy(fifo->queue + head * fifo->entry_size, data, fifo->entry_size);
sbi_memcpy((char *)fifo->queue + head * fifo->entry_size, data, fifo->entry_size);
fifo->avail++;
}
@@ -142,7 +142,7 @@ int sbi_fifo_inplace_update(struct sbi_fifo *fifo, void *in,
index = fifo->tail + i;
if (index >= fifo->num_entries)
index -= fifo->num_entries;
entry = (void *)fifo->queue + (u32)index * fifo->entry_size;
entry = (char *)fifo->queue + (u32)index * fifo->entry_size;
ret = fptr(in, entry);
if (ret == SBI_FIFO_SKIP || ret == SBI_FIFO_UPDATED) {
@@ -184,7 +184,7 @@ int sbi_fifo_dequeue(struct sbi_fifo *fifo, void *data)
return SBI_ENOENT;
}
sbi_memcpy(data, fifo->queue + (u32)fifo->tail * fifo->entry_size,
sbi_memcpy(data, (char *)fifo->queue + (u32)fifo->tail * fifo->entry_size,
fifo->entry_size);
fifo->avail--;

View File

@@ -19,27 +19,25 @@
#include <sbi/sbi_hart.h>
#include <sbi/sbi_math.h>
#include <sbi/sbi_platform.h>
#include <sbi/sbi_pmu.h>
#include <sbi/sbi_string.h>
#include <sbi/sbi_trap.h>
#include <sbi/sbi_hfence.h>
extern void __sbi_expected_trap(void);
extern void __sbi_expected_trap_hext(void);
void (*sbi_hart_expected_trap)(void) = &__sbi_expected_trap;
struct hart_features {
unsigned long features;
unsigned int pmp_count;
unsigned int pmp_addr_bits;
unsigned long pmp_gran;
unsigned int mhpm_count;
unsigned int mhpm_bits;
};
static unsigned long hart_features_offset;
static void mstatus_init(struct sbi_scratch *scratch)
{
unsigned long mstatus_val = 0;
unsigned long menvcfg_val, mstatus_val = 0;
int cidx;
unsigned int num_mhpm = sbi_hart_mhpm_count(scratch);
uint64_t mhpmevent_init_val = 0;
uint64_t mstateen_val;
/* Enable FPU */
if (misa_extension('D') || misa_extension('F'))
@@ -53,7 +51,7 @@ static void mstatus_init(struct sbi_scratch *scratch)
/* Disable user mode usage of all perf counters except default ones (CY, TM, IR) */
if (misa_extension('S') &&
sbi_hart_has_feature(scratch, SBI_HART_HAS_SCOUNTEREN))
sbi_hart_priv_version(scratch) >= SBI_HART_PRIV_VER_1_10)
csr_write(CSR_SCOUNTEREN, 7);
/**
@@ -61,13 +59,107 @@ static void mstatus_init(struct sbi_scratch *scratch)
* Supervisor mode usage for all counters are enabled by default
* But counters will not run until mcountinhibit is set.
*/
if (sbi_hart_has_feature(scratch, SBI_HART_HAS_MCOUNTEREN))
if (sbi_hart_priv_version(scratch) >= SBI_HART_PRIV_VER_1_10)
csr_write(CSR_MCOUNTEREN, -1);
/* All programmable counters will start running at runtime after S-mode request */
if (sbi_hart_has_feature(scratch, SBI_HART_HAS_MCOUNTINHIBIT))
if (sbi_hart_priv_version(scratch) >= SBI_HART_PRIV_VER_1_11)
csr_write(CSR_MCOUNTINHIBIT, 0xFFFFFFF8);
/**
* The mhpmeventn[h] CSR should be initialized with interrupt disabled
* and inhibited running in M-mode during init.
* To keep it simple, only contiguous mhpmcounters are supported as a
* platform with discontiguous mhpmcounters may not make much sense.
*/
mhpmevent_init_val |= (MHPMEVENT_OF | MHPMEVENT_MINH);
for (cidx = 0; cidx < num_mhpm; cidx++) {
#if __riscv_xlen == 32
csr_write_num(CSR_MHPMEVENT3 + cidx, mhpmevent_init_val & 0xFFFFFFFF);
if (sbi_hart_has_extension(scratch, SBI_HART_EXT_SSCOFPMF))
csr_write_num(CSR_MHPMEVENT3H + cidx,
mhpmevent_init_val >> BITS_PER_LONG);
#else
csr_write_num(CSR_MHPMEVENT3 + cidx, mhpmevent_init_val);
#endif
}
if (sbi_hart_has_extension(scratch, SBI_HART_EXT_SMSTATEEN)) {
mstateen_val = csr_read(CSR_MSTATEEN0);
#if __riscv_xlen == 32
mstateen_val |= ((uint64_t)csr_read(CSR_MSTATEEN0H)) << 32;
#endif
mstateen_val |= SMSTATEEN_STATEN;
mstateen_val |= SMSTATEEN0_HSENVCFG;
if (sbi_hart_has_extension(scratch, SBI_HART_EXT_SMAIA))
mstateen_val |= (SMSTATEEN0_AIA | SMSTATEEN0_SVSLCT |
SMSTATEEN0_IMSIC);
else
mstateen_val &= ~(SMSTATEEN0_AIA | SMSTATEEN0_SVSLCT |
SMSTATEEN0_IMSIC);
csr_write(CSR_MSTATEEN0, mstateen_val);
#if __riscv_xlen == 32
csr_write(CSR_MSTATEEN0H, mstateen_val >> 32);
#endif
}
if (sbi_hart_priv_version(scratch) >= SBI_HART_PRIV_VER_1_12) {
menvcfg_val = csr_read(CSR_MENVCFG);
/*
* Set menvcfg.CBZE == 1
*
* If Zicboz extension is not available then writes to
* menvcfg.CBZE will be ignored because it is a WARL field.
*/
menvcfg_val |= ENVCFG_CBZE;
/*
* Set menvcfg.CBCFE == 1
*
* If Zicbom extension is not available then writes to
* menvcfg.CBCFE will be ignored because it is a WARL field.
*/
menvcfg_val |= ENVCFG_CBCFE;
/*
* Set menvcfg.CBIE == 3
*
* If Zicbom extension is not available then writes to
* menvcfg.CBIE will be ignored because it is a WARL field.
*/
menvcfg_val |= ENVCFG_CBIE_INV << ENVCFG_CBIE_SHIFT;
/*
* Set menvcfg.PBMTE == 1 for RV64 or RV128
*
* If Svpbmt extension is not available then menvcfg.PBMTE
* will be read-only zero.
*/
#if __riscv_xlen > 32
menvcfg_val |= ENVCFG_PBMTE;
#endif
/*
* The spec doesn't explicitly describe the reset value of menvcfg.
* Enable access to stimecmp if sstc extension is present in the
* hardware.
*/
if (sbi_hart_has_extension(scratch, SBI_HART_EXT_SSTC)) {
#if __riscv_xlen == 32
unsigned long menvcfgh_val;
menvcfgh_val = csr_read(CSR_MENVCFGH);
menvcfgh_val |= ENVCFGH_STCE;
csr_write(CSR_MENVCFGH, menvcfgh_val);
#else
menvcfg_val |= ENVCFG_STCE;
#endif
}
csr_write(CSR_MENVCFG, menvcfg_val);
}
/* Disable all interrupts */
csr_write(CSR_MIE, 0);
@@ -108,8 +200,7 @@ static int delegate_traps(struct sbi_scratch *scratch)
/* Send M-mode interrupts and most exceptions to S-mode */
interrupts = MIP_SSIP | MIP_STIP | MIP_SEIP;
if (sbi_hart_has_feature(scratch, SBI_HART_HAS_SSCOFPMF))
interrupts |= MIP_LCOFIP;
interrupts |= sbi_pmu_irq_bit();
exceptions = (1U << CAUSE_MISALIGNED_FETCH) | (1U << CAUSE_BREAKPOINT) |
(1U << CAUSE_USER_ECALL);
@@ -154,7 +245,7 @@ void sbi_hart_delegation_dump(struct sbi_scratch *scratch,
unsigned int sbi_hart_mhpm_count(struct sbi_scratch *scratch)
{
struct hart_features *hfeatures =
struct sbi_hart_features *hfeatures =
sbi_scratch_offset_ptr(scratch, hart_features_offset);
return hfeatures->mhpm_count;
@@ -162,7 +253,7 @@ unsigned int sbi_hart_mhpm_count(struct sbi_scratch *scratch)
unsigned int sbi_hart_pmp_count(struct sbi_scratch *scratch)
{
struct hart_features *hfeatures =
struct sbi_hart_features *hfeatures =
sbi_scratch_offset_ptr(scratch, hart_features_offset);
return hfeatures->pmp_count;
@@ -170,7 +261,7 @@ unsigned int sbi_hart_pmp_count(struct sbi_scratch *scratch)
unsigned long sbi_hart_pmp_granularity(struct sbi_scratch *scratch)
{
struct hart_features *hfeatures =
struct sbi_hart_features *hfeatures =
sbi_scratch_offset_ptr(scratch, hart_features_offset);
return hfeatures->pmp_gran;
@@ -178,7 +269,7 @@ unsigned long sbi_hart_pmp_granularity(struct sbi_scratch *scratch)
unsigned int sbi_hart_pmp_addrbits(struct sbi_scratch *scratch)
{
struct hart_features *hfeatures =
struct sbi_hart_features *hfeatures =
sbi_scratch_offset_ptr(scratch, hart_features_offset);
return hfeatures->pmp_addr_bits;
@@ -186,7 +277,7 @@ unsigned int sbi_hart_pmp_addrbits(struct sbi_scratch *scratch)
unsigned int sbi_hart_mhpm_bits(struct sbi_scratch *scratch)
{
struct hart_features *hfeatures =
struct sbi_hart_features *hfeatures =
sbi_scratch_offset_ptr(scratch, hart_features_offset);
return hfeatures->mhpm_bits;
@@ -231,106 +322,180 @@ int sbi_hart_pmp_configure(struct sbi_scratch *scratch)
}
}
/*
* As per section 3.7.2 of privileged specification v1.12,
* virtual address translations can be speculatively performed
* (even before actual access). These, along with PMP traslations,
* can be cached. This can pose a problem with CPU hotplug
* and non-retentive suspend scenario because PMP states are
* not preserved.
* It is advisable to flush the caching structures under such
* conditions.
*/
if (misa_extension('S')) {
__asm__ __volatile__("sfence.vma");
/*
* If hypervisor mode is supported, flush caching
* structures in guest mode too.
*/
if (misa_extension('H'))
__sbi_hfence_gvma_all();
}
return 0;
}
/**
* Check whether a particular hart feature is available
*
* @param scratch pointer to the HART scratch space
* @param feature the feature to check
* @returns true (feature available) or false (feature not available)
*/
bool sbi_hart_has_feature(struct sbi_scratch *scratch, unsigned long feature)
int sbi_hart_priv_version(struct sbi_scratch *scratch)
{
struct hart_features *hfeatures =
struct sbi_hart_features *hfeatures =
sbi_scratch_offset_ptr(scratch, hart_features_offset);
if (hfeatures->features & feature)
return hfeatures->priv_version;
}
void sbi_hart_get_priv_version_str(struct sbi_scratch *scratch,
char *version_str, int nvstr)
{
char *temp;
struct sbi_hart_features *hfeatures =
sbi_scratch_offset_ptr(scratch, hart_features_offset);
switch (hfeatures->priv_version) {
case SBI_HART_PRIV_VER_1_10:
temp = "v1.10";
break;
case SBI_HART_PRIV_VER_1_11:
temp = "v1.11";
break;
case SBI_HART_PRIV_VER_1_12:
temp = "v1.12";
break;
default:
temp = "unknown";
break;
}
sbi_snprintf(version_str, nvstr, "%s", temp);
}
static inline void __sbi_hart_update_extension(
struct sbi_hart_features *hfeatures,
enum sbi_hart_extensions ext,
bool enable)
{
if (enable)
hfeatures->extensions |= BIT(ext);
else
hfeatures->extensions &= ~BIT(ext);
}
/**
* Enable/Disable a particular hart extension
*
* @param scratch pointer to the HART scratch space
* @param ext the extension number to check
* @param enable new state of hart extension
*/
void sbi_hart_update_extension(struct sbi_scratch *scratch,
enum sbi_hart_extensions ext,
bool enable)
{
struct sbi_hart_features *hfeatures =
sbi_scratch_offset_ptr(scratch, hart_features_offset);
__sbi_hart_update_extension(hfeatures, ext, enable);
}
/**
* Check whether a particular hart extension is available
*
* @param scratch pointer to the HART scratch space
* @param ext the extension number to check
* @returns true (available) or false (not available)
*/
bool sbi_hart_has_extension(struct sbi_scratch *scratch,
enum sbi_hart_extensions ext)
{
struct sbi_hart_features *hfeatures =
sbi_scratch_offset_ptr(scratch, hart_features_offset);
if (hfeatures->extensions & BIT(ext))
return true;
else
return false;
}
static unsigned long hart_get_features(struct sbi_scratch *scratch)
static inline char *sbi_hart_extension_id2string(int ext)
{
struct hart_features *hfeatures =
sbi_scratch_offset_ptr(scratch, hart_features_offset);
char *estr = NULL;
return hfeatures->features;
}
static inline char *sbi_hart_feature_id2string(unsigned long feature)
{
char *fstr = NULL;
if (!feature)
return NULL;
switch (feature) {
case SBI_HART_HAS_SCOUNTEREN:
fstr = "scounteren";
switch (ext) {
case SBI_HART_EXT_SSCOFPMF:
estr = "sscofpmf";
break;
case SBI_HART_HAS_MCOUNTEREN:
fstr = "mcounteren";
case SBI_HART_EXT_TIME:
estr = "time";
break;
case SBI_HART_HAS_MCOUNTINHIBIT:
fstr = "mcountinhibit";
case SBI_HART_EXT_SMAIA:
estr = "smaia";
break;
case SBI_HART_HAS_SSCOFPMF:
fstr = "sscofpmf";
case SBI_HART_EXT_SSTC:
estr = "sstc";
break;
case SBI_HART_HAS_TIME:
fstr = "time";
case SBI_HART_EXT_SMSTATEEN:
estr = "smstateen";
break;
default:
break;
}
return fstr;
return estr;
}
/**
* Get the hart features in string format
* Get the hart extensions in string format
*
* @param scratch pointer to the HART scratch space
* @param features_str pointer to a char array where the features string will be
* updated
* @param nfstr length of the features_str. The feature string will be truncated
* if nfstr is not long enough.
* @param extensions_str pointer to a char array where the extensions string
* will be updated
* @param nestr length of the features_str. The feature string will be
* truncated if nestr is not long enough.
*/
void sbi_hart_get_features_str(struct sbi_scratch *scratch,
char *features_str, int nfstr)
void sbi_hart_get_extensions_str(struct sbi_scratch *scratch,
char *extensions_str, int nestr)
{
unsigned long features, feat = 1UL;
struct sbi_hart_features *hfeatures =
sbi_scratch_offset_ptr(scratch, hart_features_offset);
int offset = 0, ext = 0;
char *temp;
int offset = 0;
if (!features_str || nfstr <= 0)
if (!extensions_str || nestr <= 0)
return;
sbi_memset(features_str, 0, nfstr);
sbi_memset(extensions_str, 0, nestr);
features = hart_get_features(scratch);
if (!features)
if (!hfeatures->extensions)
goto done;
do {
if (features & feat) {
temp = sbi_hart_feature_id2string(feat);
if (hfeatures->extensions & BIT(ext)) {
temp = sbi_hart_extension_id2string(ext);
if (temp) {
sbi_snprintf(features_str + offset, nfstr,
sbi_snprintf(extensions_str + offset,
nestr - offset,
"%s,", temp);
offset = offset + sbi_strlen(temp) + 1;
}
}
feat = feat << 1;
} while (feat <= SBI_HART_HAS_LAST_FEATURE);
ext++;
} while (ext < SBI_HART_EXT_MAX);
done:
if (offset)
features_str[offset - 1] = '\0';
extensions_str[offset - 1] = '\0';
else
sbi_strncpy(features_str, "none", nfstr);
sbi_strncpy(extensions_str, "none", nestr);
}
static unsigned long hart_pmp_get_allowed_addr(void)
@@ -368,7 +533,7 @@ static int hart_pmu_get_allowed_bits(void)
if (trap.cause)
return 0;
}
num_bits = __fls(val) + 1;
num_bits = sbi_fls(val) + 1;
#if __riscv_xlen == 32
csr_write_allowed(CSR_MHPMCOUNTER3H, (ulong)&trap, val);
if (!trap.cause) {
@@ -376,34 +541,39 @@ static int hart_pmu_get_allowed_bits(void)
if (trap.cause)
return num_bits;
}
num_bits += __fls(val) + 1;
num_bits += sbi_fls(val) + 1;
#endif
return num_bits;
}
static void hart_detect_features(struct sbi_scratch *scratch)
static int hart_detect_features(struct sbi_scratch *scratch)
{
struct sbi_trap_info trap = {0};
struct hart_features *hfeatures;
unsigned long val;
struct sbi_hart_features *hfeatures =
sbi_scratch_offset_ptr(scratch, hart_features_offset);
unsigned long val, oldval;
int rc;
/* Reset hart features */
hfeatures = sbi_scratch_offset_ptr(scratch, hart_features_offset);
hfeatures->features = 0;
/* If hart features already detected then do nothing */
if (hfeatures->detected)
return 0;
/* Clear hart features */
hfeatures->extensions = 0;
hfeatures->pmp_count = 0;
hfeatures->mhpm_count = 0;
#define __check_csr(__csr, __rdonly, __wrval, __field, __skip) \
val = csr_read_allowed(__csr, (ulong)&trap); \
oldval = csr_read_allowed(__csr, (ulong)&trap); \
if (!trap.cause) { \
if (__rdonly) { \
(hfeatures->__field)++; \
} else { \
csr_write_allowed(__csr, (ulong)&trap, __wrval);\
if (!trap.cause) { \
if (csr_swap(__csr, val) == __wrval) \
if (csr_swap(__csr, oldval) == __wrval) \
(hfeatures->__field)++; \
else \
goto __skip; \
@@ -439,8 +609,8 @@ static void hart_detect_features(struct sbi_scratch *scratch)
*/
val = hart_pmp_get_allowed_addr();
if (val) {
hfeatures->pmp_gran = 1 << (__ffs(val) + 2);
hfeatures->pmp_addr_bits = __fls(val) + 1;
hfeatures->pmp_gran = 1 << (sbi_ffs(val) + 2);
hfeatures->pmp_addr_bits = sbi_fls(val) + 1;
/* Detect number of PMP regions. At least PMPADDR0 should be implemented*/
__check_csr_64(CSR_PMPADDR0, 0, val, pmp_count, __pmp_skip);
}
@@ -469,43 +639,70 @@ __mhpm_skip:
#undef __check_csr_2
#undef __check_csr
/* Detect if hart supports SCOUNTEREN feature */
val = csr_read_allowed(CSR_SCOUNTEREN, (unsigned long)&trap);
if (!trap.cause) {
csr_write_allowed(CSR_SCOUNTEREN, (unsigned long)&trap, val);
if (!trap.cause)
hfeatures->features |= SBI_HART_HAS_SCOUNTEREN;
}
/* Detect if hart supports MCOUNTEREN feature */
/* Detect if hart supports Priv v1.10 */
val = csr_read_allowed(CSR_MCOUNTEREN, (unsigned long)&trap);
if (!trap.cause) {
csr_write_allowed(CSR_MCOUNTEREN, (unsigned long)&trap, val);
if (!trap.cause)
hfeatures->features |= SBI_HART_HAS_MCOUNTEREN;
}
if (!trap.cause)
hfeatures->priv_version = SBI_HART_PRIV_VER_1_10;
/* Detect if hart supports MCOUNTINHIBIT feature */
/* Detect if hart supports Priv v1.11 */
val = csr_read_allowed(CSR_MCOUNTINHIBIT, (unsigned long)&trap);
if (!trap.cause) {
csr_write_allowed(CSR_MCOUNTINHIBIT, (unsigned long)&trap, val);
if (!trap.cause)
hfeatures->features |= SBI_HART_HAS_MCOUNTINHIBIT;
}
if (!trap.cause &&
(hfeatures->priv_version >= SBI_HART_PRIV_VER_1_10))
hfeatures->priv_version = SBI_HART_PRIV_VER_1_11;
/* Detect if hart supports Priv v1.12 */
csr_read_allowed(CSR_MENVCFG, (unsigned long)&trap);
if (!trap.cause &&
(hfeatures->priv_version >= SBI_HART_PRIV_VER_1_11))
hfeatures->priv_version = SBI_HART_PRIV_VER_1_12;
/* Counter overflow/filtering is not useful without mcounter/inhibit */
if (hfeatures->features & SBI_HART_HAS_MCOUNTINHIBIT &&
hfeatures->features & SBI_HART_HAS_MCOUNTEREN) {
if (hfeatures->priv_version >= SBI_HART_PRIV_VER_1_12) {
/* Detect if hart supports sscofpmf */
csr_read_allowed(CSR_SCOUNTOVF, (unsigned long)&trap);
if (!trap.cause)
hfeatures->features |= SBI_HART_HAS_SSCOFPMF;
__sbi_hart_update_extension(hfeatures,
SBI_HART_EXT_SSCOFPMF, true);
}
/* Detect if hart supports time CSR */
csr_read_allowed(CSR_TIME, (unsigned long)&trap);
if (!trap.cause)
hfeatures->features |= SBI_HART_HAS_TIME;
__sbi_hart_update_extension(hfeatures,
SBI_HART_EXT_TIME, true);
/* Detect if hart has AIA local interrupt CSRs */
csr_read_allowed(CSR_MTOPI, (unsigned long)&trap);
if (!trap.cause)
__sbi_hart_update_extension(hfeatures,
SBI_HART_EXT_SMAIA, true);
/* Detect if hart supports stimecmp CSR(Sstc extension) */
if (hfeatures->priv_version >= SBI_HART_PRIV_VER_1_12) {
csr_read_allowed(CSR_STIMECMP, (unsigned long)&trap);
if (!trap.cause)
__sbi_hart_update_extension(hfeatures,
SBI_HART_EXT_SSTC, true);
}
/* Detect if hart supports mstateen CSRs */
if (hfeatures->priv_version >= SBI_HART_PRIV_VER_1_12) {
val = csr_read_allowed(CSR_MSTATEEN0, (unsigned long)&trap);
if (!trap.cause)
__sbi_hart_update_extension(hfeatures,
SBI_HART_EXT_SMSTATEEN, true);
}
/* Let platform populate extensions */
rc = sbi_platform_extensions_init(sbi_platform_thishart_ptr(),
hfeatures);
if (rc)
return rc;
/* Mark hart feature detection done */
hfeatures->detected = true;
return 0;
}
int sbi_hart_reinit(struct sbi_scratch *scratch)
@@ -527,17 +724,21 @@ int sbi_hart_reinit(struct sbi_scratch *scratch)
int sbi_hart_init(struct sbi_scratch *scratch, bool cold_boot)
{
int rc;
if (cold_boot) {
if (misa_extension('H'))
sbi_hart_expected_trap = &__sbi_expected_trap_hext;
hart_features_offset = sbi_scratch_alloc_offset(
sizeof(struct hart_features));
sizeof(struct sbi_hart_features));
if (!hart_features_offset)
return SBI_ENOMEM;
}
hart_detect_features(scratch);
rc = hart_detect_features(scratch);
if (rc)
return rc;
return sbi_hart_reinit(scratch);
}
@@ -581,19 +782,12 @@ sbi_hart_switch_mode(unsigned long arg0, unsigned long arg1,
#if __riscv_xlen == 32
if (misa_extension('H')) {
valH = csr_read(CSR_MSTATUSH);
if (next_virt)
valH = INSERT_FIELD(valH, MSTATUSH_MPV, 1);
else
valH = INSERT_FIELD(valH, MSTATUSH_MPV, 0);
valH = INSERT_FIELD(valH, MSTATUSH_MPV, next_virt);
csr_write(CSR_MSTATUSH, valH);
}
#else
if (misa_extension('H')) {
if (next_virt)
val = INSERT_FIELD(val, MSTATUS_MPV, 1);
else
val = INSERT_FIELD(val, MSTATUS_MPV, 0);
}
if (misa_extension('H'))
val = INSERT_FIELD(val, MSTATUS_MPV, next_virt);
#endif
csr_write(CSR_MSTATUS, val);
csr_write(CSR_MEPC, next_addr);

View File

@@ -113,8 +113,8 @@ static void sbi_hsm_hart_wait(struct sbi_scratch *scratch, u32 hartid)
/* Save MIE CSR */
saved_mie = csr_read(CSR_MIE);
/* Set MSIE bit to receive IPI */
csr_set(CSR_MIE, MIP_MSIP);
/* Set MSIE and MEIE bits to receive IPI */
csr_set(CSR_MIE, MIP_MSIP | MIP_MEIP);
/* Wait for hart_add call*/
while (atomic_read(&hdata->state) != SBI_HSM_STATE_START_PENDING) {
@@ -171,13 +171,19 @@ static int hsm_device_hart_stop(void)
return SBI_ENOTSUPP;
}
static int hsm_device_hart_suspend(u32 suspend_type, ulong raddr)
static int hsm_device_hart_suspend(u32 suspend_type)
{
if (hsm_dev && hsm_dev->hart_suspend)
return hsm_dev->hart_suspend(suspend_type, raddr);
return hsm_dev->hart_suspend(suspend_type);
return SBI_ENOTSUPP;
}
static void hsm_device_hart_resume(void)
{
if (hsm_dev && hsm_dev->hart_resume)
hsm_dev->hart_resume();
}
int sbi_hsm_init(struct sbi_scratch *scratch, u32 hartid, bool cold_boot)
{
u32 i;
@@ -283,7 +289,9 @@ int sbi_hsm_hart_start(struct sbi_scratch *scratch,
(hsm_device_has_hart_secondary_boot() && !init_count)) {
return hsm_device_hart_start(hartid, scratch->warmboot_addr);
} else {
sbi_ipi_raw_send(hartid);
int rc = sbi_ipi_raw_send(hartid);
if (rc)
return rc;
}
return 0;
@@ -313,7 +321,7 @@ int sbi_hsm_hart_stop(struct sbi_scratch *scratch, bool exitnow)
return 0;
}
static int __sbi_hsm_suspend_ret_default(struct sbi_scratch *scratch)
static int __sbi_hsm_suspend_default(struct sbi_scratch *scratch)
{
/* Wait for interrupt */
wfi();
@@ -353,23 +361,6 @@ static void __sbi_hsm_suspend_non_ret_restore(struct sbi_scratch *scratch)
csr_write(CSR_MIP, (hdata->saved_mip & (MIP_SSIP | MIP_STIP)));
}
static int __sbi_hsm_suspend_non_ret_default(struct sbi_scratch *scratch,
ulong raddr)
{
void (*jump_warmboot)(void) = (void (*)(void))scratch->warmboot_addr;
/* Wait for interrupt */
wfi();
/*
* Directly jump to warm reboot to simulate resume from a
* non-retentive suspend.
*/
jump_warmboot();
return 0;
}
void sbi_hsm_hart_resume_start(struct sbi_scratch *scratch)
{
int oldstate;
@@ -384,6 +375,8 @@ void sbi_hsm_hart_resume_start(struct sbi_scratch *scratch)
__func__, oldstate);
sbi_hart_hang();
}
hsm_device_hart_resume();
}
void sbi_hsm_hart_resume_finish(struct sbi_scratch *scratch)
@@ -465,17 +458,28 @@ int sbi_hsm_hart_suspend(struct sbi_scratch *scratch, u32 suspend_type,
__sbi_hsm_suspend_non_ret_save(scratch);
/* Try platform specific suspend */
ret = hsm_device_hart_suspend(suspend_type, scratch->warmboot_addr);
ret = hsm_device_hart_suspend(suspend_type);
if (ret == SBI_ENOTSUPP) {
/* Try generic implementation of default suspend types */
if (suspend_type == SBI_HSM_SUSPEND_RET_DEFAULT) {
ret = __sbi_hsm_suspend_ret_default(scratch);
} else if (suspend_type == SBI_HSM_SUSPEND_NON_RET_DEFAULT) {
ret = __sbi_hsm_suspend_non_ret_default(scratch,
scratch->warmboot_addr);
if (suspend_type == SBI_HSM_SUSPEND_RET_DEFAULT ||
suspend_type == SBI_HSM_SUSPEND_NON_RET_DEFAULT) {
ret = __sbi_hsm_suspend_default(scratch);
}
}
/*
* The platform may have coordinated a retentive suspend, or it may
* have exited early from a non-retentive suspend. Either way, the
* caller is not expecting a successful return, so jump to the warm
* boot entry point to simulate resume from a non-retentive suspend.
*/
if (ret == 0 && (suspend_type & SBI_HSM_SUSP_NON_RET_BIT)) {
void (*jump_warmboot)(void) =
(void (*)(void))scratch->warmboot_addr;
jump_warmboot();
}
fail_restore_state:
/*
* We might have successfully resumed from retentive suspend

View File

@@ -8,6 +8,7 @@
*/
#include <sbi/riscv_asm.h>
#include <sbi/riscv_barrier.h>
#include <sbi/riscv_encoding.h>
#include <sbi/sbi_bitops.h>
#include <sbi/sbi_emulate_csr.h>
@@ -16,6 +17,7 @@
#include <sbi/sbi_pmu.h>
#include <sbi/sbi_trap.h>
#include <sbi/sbi_unpriv.h>
#include <sbi/sbi_console.h>
typedef int (*illegal_insn_func)(ulong insn, struct sbi_trap_regs *regs);
@@ -28,17 +30,37 @@ static int truly_illegal_insn(ulong insn, struct sbi_trap_regs *regs)
trap.tval = insn;
trap.tval2 = 0;
trap.tinst = 0;
trap.gva = 0;
return sbi_trap_redirect(regs, &trap);
}
static int misc_mem_opcode_insn(ulong insn, struct sbi_trap_regs *regs)
{
/* Errata workaround: emulate `fence.tso` as `fence rw, rw`. */
if ((insn & INSN_MASK_FENCE_TSO) == INSN_MATCH_FENCE_TSO) {
smp_mb();
regs->mepc += 4;
return 0;
}
return truly_illegal_insn(insn, regs);
}
static int system_opcode_insn(ulong insn, struct sbi_trap_regs *regs)
{
int do_write, rs1_num = (insn >> 15) & 0x1f;
ulong rs1_val = GET_RS1(insn, regs);
int csr_num = (u32)insn >> 20;
ulong prev_mode = (regs->mstatus & MSTATUS_MPP) >> MSTATUS_MPP_SHIFT;
ulong csr_val, new_csr_val;
if (prev_mode == PRV_M) {
sbi_printf("%s: Failed to access CSR %#x from M-mode",
__func__, csr_num);
return SBI_EFAIL;
}
/* TODO: Ensure that we got CSR read/write instruction */
if (sbi_emulate_csr_read(csr_num, regs, &csr_val))
@@ -80,11 +102,11 @@ static int system_opcode_insn(ulong insn, struct sbi_trap_regs *regs)
return 0;
}
static illegal_insn_func illegal_insn_table[32] = {
static const illegal_insn_func illegal_insn_table[32] = {
truly_illegal_insn, /* 0 */
truly_illegal_insn, /* 1 */
truly_illegal_insn, /* 2 */
truly_illegal_insn, /* 3 */
misc_mem_opcode_insn, /* 3 */
truly_illegal_insn, /* 4 */
truly_illegal_insn, /* 5 */
truly_illegal_insn, /* 6 */

View File

@@ -18,6 +18,7 @@
#include <sbi/sbi_hartmask.h>
#include <sbi/sbi_hsm.h>
#include <sbi/sbi_ipi.h>
#include <sbi/sbi_irqchip.h>
#include <sbi/sbi_platform.h>
#include <sbi/sbi_pmu.h>
#include <sbi/sbi_system.h>
@@ -62,6 +63,7 @@ static void sbi_boot_print_banner(struct sbi_scratch *scratch)
static void sbi_boot_print_general(struct sbi_scratch *scratch)
{
char str[128];
const struct sbi_pmu_device *pdev;
const struct sbi_hsm_device *hdev;
const struct sbi_ipi_device *idev;
const struct sbi_timer_device *tdev;
@@ -92,6 +94,9 @@ static void sbi_boot_print_general(struct sbi_scratch *scratch)
hdev = sbi_hsm_get_device();
sbi_printf("Platform HSM Device : %s\n",
(hdev) ? hdev->name : "---");
pdev = sbi_pmu_get_device();
sbi_printf("Platform PMU Device : %s\n",
(pdev) ? pdev->name : "---");
srdev = sbi_system_reset_get_device(SBI_SRST_RESET_TYPE_COLD_REBOOT, 0);
sbi_printf("Platform Reboot Device : %s\n",
(srdev) ? srdev->name : "---");
@@ -138,10 +143,12 @@ static void sbi_boot_print_hart(struct sbi_scratch *scratch, u32 hartid)
/* Boot HART details */
sbi_printf("Boot HART ID : %u\n", hartid);
sbi_printf("Boot HART Domain : %s\n", dom->name);
sbi_hart_get_priv_version_str(scratch, str, sizeof(str));
sbi_printf("Boot HART Priv Version : %s\n", str);
misa_string(xlen, str, sizeof(str));
sbi_printf("Boot HART ISA : %s\n", str);
sbi_hart_get_features_str(scratch, str, sizeof(str));
sbi_printf("Boot HART Features : %s\n", str);
sbi_printf("Boot HART Base ISA : %s\n", str);
sbi_hart_get_extensions_str(scratch, str, sizeof(str));
sbi_printf("Boot HART ISA Extensions : %s\n", str);
sbi_printf("Boot HART PMP Count : %d\n",
sbi_hart_pmp_count(scratch));
sbi_printf("Boot HART PMP Granularity : %lu\n",
@@ -165,8 +172,8 @@ static void wait_for_coldboot(struct sbi_scratch *scratch, u32 hartid)
/* Save MIE CSR */
saved_mie = csr_read(CSR_MIE);
/* Set MSIE bit to receive IPI */
csr_set(CSR_MIE, MIP_MSIP);
/* Set MSIE and MEIE bits to receive IPI */
csr_set(CSR_MIE, MIP_MSIP | MIP_MEIP);
/* Acquire coldboot lock */
spin_lock(&coldboot_lock);
@@ -182,7 +189,7 @@ static void wait_for_coldboot(struct sbi_scratch *scratch, u32 hartid)
do {
wfi();
cmip = csr_read(CSR_MIP);
} while (!(cmip & MIP_MSIP));
} while (!(cmip & (MIP_MSIP | MIP_MEIP)));
};
/* Acquire coldboot lock */
@@ -270,9 +277,9 @@ static void __noreturn init_coldboot(struct sbi_scratch *scratch, u32 hartid)
sbi_boot_print_banner(scratch);
rc = sbi_platform_irqchip_init(plat, TRUE);
rc = sbi_irqchip_init(scratch, TRUE);
if (rc) {
sbi_printf("%s: platform irqchip init failed (error %d)\n",
sbi_printf("%s: irqchip init failed (error %d)\n",
__func__, rc);
sbi_hart_hang();
}
@@ -373,7 +380,7 @@ static void init_warm_startup(struct sbi_scratch *scratch, u32 hartid)
if (rc)
sbi_hart_hang();
rc = sbi_platform_irqchip_init(plat, FALSE);
rc = sbi_irqchip_init(scratch, FALSE);
if (rc)
sbi_hart_hang();
@@ -494,6 +501,14 @@ void __noreturn sbi_init(struct sbi_scratch *scratch)
if (next_mode_supported && atomic_xchg(&coldboot_lottery, 1) == 0)
coldboot = TRUE;
/*
* Do platform specific nascent (very early) initialization so
* that platform can initialize platform specific per-HART CSRs
* or per-HART devices.
*/
if (sbi_platform_nascent_init(plat))
sbi_hart_hang();
if (coldboot)
init_coldboot(scratch, hartid);
else
@@ -542,7 +557,7 @@ void __noreturn sbi_exit(struct sbi_scratch *scratch)
sbi_ipi_exit(scratch);
sbi_platform_irqchip_exit(plat);
sbi_irqchip_exit(scratch);
sbi_platform_final_exit(plat);

View File

@@ -208,10 +208,13 @@ skip:
};
}
void sbi_ipi_raw_send(u32 target_hart)
int sbi_ipi_raw_send(u32 target_hart)
{
if (ipi_dev && ipi_dev->ipi_send)
ipi_dev->ipi_send(target_hart);
if (!ipi_dev || !ipi_dev->ipi_send)
return SBI_EINVAL;
ipi_dev->ipi_send(target_hart);
return 0;
}
const struct sbi_ipi_device *sbi_ipi_get_device(void)

54
lib/sbi/sbi_irqchip.c Normal file
View File

@@ -0,0 +1,54 @@
/*
* SPDX-License-Identifier: BSD-2-Clause
*
* Copyright (c) 2022 Ventana Micro Systems Inc.
*
* Authors:
* Anup Patel <apatel@ventanamicro.com>
*/
#include <sbi/sbi_irqchip.h>
#include <sbi/sbi_platform.h>
static int default_irqfn(struct sbi_trap_regs *regs)
{
return SBI_ENODEV;
}
static int (*ext_irqfn)(struct sbi_trap_regs *regs) = default_irqfn;
void sbi_irqchip_set_irqfn(int (*fn)(struct sbi_trap_regs *regs))
{
if (fn)
ext_irqfn = fn;
}
int sbi_irqchip_process(struct sbi_trap_regs *regs)
{
return ext_irqfn(regs);
}
int sbi_irqchip_init(struct sbi_scratch *scratch, bool cold_boot)
{
int rc;
const struct sbi_platform *plat = sbi_platform_ptr(scratch);
rc = sbi_platform_irqchip_init(plat, cold_boot);
if (rc)
return rc;
if (ext_irqfn != default_irqfn)
csr_set(CSR_MIE, MIP_MEIP);
return 0;
}
void sbi_irqchip_exit(struct sbi_scratch *scratch)
{
const struct sbi_platform *plat = sbi_platform_ptr(scratch);
if (ext_irqfn != default_irqfn)
csr_clear(CSR_MIE, MIP_MEIP);
sbi_platform_irqchip_exit(plat);
}

View File

@@ -22,6 +22,18 @@ union reg_data {
u64 data_u64;
};
static ulong sbi_misaligned_tinst_fixup(ulong orig_tinst, ulong new_tinst,
ulong addr_offset)
{
if (new_tinst == INSN_PSEUDO_VS_LOAD ||
new_tinst == INSN_PSEUDO_VS_STORE)
return new_tinst;
else if (orig_tinst == 0)
return 0UL;
else
return orig_tinst | (addr_offset << SH_RS1);
}
int sbi_misaligned_load_handler(ulong addr, ulong tval2, ulong tinst,
struct sbi_trap_regs *regs)
{
@@ -117,6 +129,7 @@ int sbi_misaligned_load_handler(ulong addr, ulong tval2, ulong tinst,
uptrap.tval = addr;
uptrap.tval2 = tval2;
uptrap.tinst = tinst;
uptrap.gva = sbi_regs_gva(regs);
return sbi_trap_redirect(regs, &uptrap);
}
@@ -126,6 +139,8 @@ int sbi_misaligned_load_handler(ulong addr, ulong tval2, ulong tinst,
&uptrap);
if (uptrap.cause) {
uptrap.epc = regs->mepc;
uptrap.tinst = sbi_misaligned_tinst_fixup(
tinst, uptrap.tinst, i);
return sbi_trap_redirect(regs, &uptrap);
}
}
@@ -230,6 +245,7 @@ int sbi_misaligned_store_handler(ulong addr, ulong tval2, ulong tinst,
uptrap.tval = addr;
uptrap.tval2 = tval2;
uptrap.tinst = tinst;
uptrap.gva = sbi_regs_gva(regs);
return sbi_trap_redirect(regs, &uptrap);
}
@@ -238,6 +254,8 @@ int sbi_misaligned_store_handler(ulong addr, ulong tval2, ulong tinst,
&uptrap);
if (uptrap.cause) {
uptrap.epc = regs->mepc;
uptrap.tinst = sbi_misaligned_tinst_fixup(
tinst, uptrap.tinst, i);
return sbi_trap_redirect(regs, &uptrap);
}
}

View File

@@ -10,7 +10,9 @@
#include <sbi/riscv_asm.h>
#include <sbi/sbi_bitops.h>
#include <sbi/sbi_console.h>
#include <sbi/sbi_ecall_interface.h>
#include <sbi/sbi_hart.h>
#include <sbi/sbi_hartmask.h>
#include <sbi/sbi_platform.h>
#include <sbi/sbi_pmu.h>
#include <sbi/sbi_scratch.h>
@@ -33,18 +35,6 @@ struct sbi_pmu_hw_event {
uint64_t select_mask;
};
/** Representation of a firmware event */
struct sbi_pmu_fw_event {
/* Event associated with the particular counter */
uint32_t event_idx;
/* Current value of the counter */
unsigned long curr_count;
/* A flag indicating pmu event monitoring is started */
bool bStarted;
};
/* Information about PMU counters as per SBI specification */
union sbi_pmu_ctr_info {
unsigned long value;
@@ -60,14 +50,23 @@ union sbi_pmu_ctr_info {
};
};
/* Platform specific PMU device */
static const struct sbi_pmu_device *pmu_dev = NULL;
/* Mapping between event range and possible counters */
static struct sbi_pmu_hw_event hw_event_map[SBI_PMU_HW_EVENT_MAX] = {0};
/* counter to enabled event mapping */
static uint32_t active_events[SBI_HARTMASK_MAX_BITS][SBI_PMU_HW_CTR_MAX + SBI_PMU_FW_CTR_MAX];
/* Contains all the information about firmwares events */
static struct sbi_pmu_fw_event fw_event_map[SBI_HARTMASK_MAX_BITS][SBI_PMU_FW_EVENT_MAX] = {0};
/* Bitmap of firmware counters started on each HART */
#if SBI_PMU_FW_CTR_MAX >= BITS_PER_LONG
#error "Can't handle firmware counters beyond BITS_PER_LONG"
#endif
static unsigned long fw_counters_started[SBI_HARTMASK_MAX_BITS];
/* Values of firmwares counters on each HART */
static uint64_t fw_counters_value[SBI_HARTMASK_MAX_BITS][SBI_PMU_FW_CTR_MAX] = {0};
/* Maximum number of hardware events available */
static uint32_t num_hw_events;
@@ -107,19 +106,66 @@ static bool pmu_event_select_overlap(struct sbi_pmu_hw_event *evt,
return FALSE;
}
static int pmu_event_validate(unsigned long event_idx)
{
uint32_t event_idx_type = get_cidx_type(event_idx);
uint32_t event_idx_code = get_cidx_code(event_idx);
uint32_t event_idx_code_max = -1;
uint32_t cache_ops_result, cache_ops_id, cache_id;
switch(event_idx_type) {
case SBI_PMU_EVENT_TYPE_HW:
event_idx_code_max = SBI_PMU_HW_GENERAL_MAX;
break;
case SBI_PMU_EVENT_TYPE_FW:
if (SBI_PMU_FW_MAX <= event_idx_code &&
pmu_dev && pmu_dev->fw_event_validate_code)
return pmu_dev->fw_event_validate_code(event_idx_code);
else
event_idx_code_max = SBI_PMU_FW_MAX;
break;
case SBI_PMU_EVENT_TYPE_HW_CACHE:
cache_ops_result = event_idx_code &
SBI_PMU_EVENT_HW_CACHE_OPS_RESULT;
cache_ops_id = (event_idx_code &
SBI_PMU_EVENT_HW_CACHE_OPS_ID_MASK) >>
SBI_PMU_EVENT_HW_CACHE_OPS_ID_OFFSET;
cache_id = (event_idx_code &
SBI_PMU_EVENT_HW_CACHE_ID_MASK) >>
SBI_PMU_EVENT_HW_CACHE_ID_OFFSET;
if ((cache_ops_result < SBI_PMU_HW_CACHE_RESULT_MAX) &&
(cache_ops_id < SBI_PMU_HW_CACHE_OP_MAX) &&
(cache_id < SBI_PMU_HW_CACHE_MAX))
return event_idx_type;
else
return SBI_EINVAL;
break;
case SBI_PMU_EVENT_TYPE_HW_RAW:
event_idx_code_max = 1; // event_idx.code should be zero
break;
default:
return SBI_EINVAL;
}
if (event_idx_code < event_idx_code_max)
return event_idx_type;
return SBI_EINVAL;
}
static int pmu_ctr_validate(uint32_t cidx, uint32_t *event_idx_code)
{
uint32_t event_idx_val;
uint32_t event_idx_type;
u32 hartid = current_hartid();
event_idx_val = active_events[hartid][cidx];
if (cidx >= total_ctrs || (event_idx_val == SBI_PMU_EVENT_IDX_INVALID))
if (cidx >= total_ctrs)
return SBI_EINVAL;
event_idx_val = active_events[hartid][cidx];
event_idx_type = get_cidx_type(event_idx_val);
if (event_idx_type >= SBI_PMU_EVENT_TYPE_MAX)
if (event_idx_val == SBI_PMU_EVENT_IDX_INVALID ||
event_idx_type >= SBI_PMU_EVENT_TYPE_MAX)
return SBI_EINVAL;
*event_idx_code = get_cidx_code(event_idx_val);
@@ -127,50 +173,22 @@ static int pmu_ctr_validate(uint32_t cidx, uint32_t *event_idx_code)
return event_idx_type;
}
static int pmu_ctr_read_fw(uint32_t cidx, unsigned long *cval,
uint32_t fw_evt_code)
{
u32 hartid = current_hartid();
struct sbi_pmu_fw_event fevent;
fevent = fw_event_map[hartid][fw_evt_code];
*cval = fevent.curr_count;
return 0;
}
/* Add a hardware counter read for completeness for future purpose */
static int pmu_ctr_read_hw(uint32_t cidx, uint64_t *cval)
{
/* Check for invalid hw counter read requests */
if (unlikely(cidx == 1))
return SBI_EINVAL;
#if __riscv_xlen == 32
uint32_t temp, temph = 0;
temp = csr_read_num(CSR_MCYCLE + cidx);
temph = csr_read_num(CSR_MCYCLEH + cidx);
*cval = ((uint64_t)temph << 32) | temp;
#else
*cval = csr_read_num(CSR_MCYCLE + cidx);
#endif
return 0;
}
int sbi_pmu_ctr_read(uint32_t cidx, unsigned long *cval)
int sbi_pmu_ctr_fw_read(uint32_t cidx, uint64_t *cval)
{
int event_idx_type;
uint32_t event_code;
uint64_t cval64;
u32 hartid = current_hartid();
event_idx_type = pmu_ctr_validate(cidx, &event_code);
if (event_idx_type < 0)
if (event_idx_type != SBI_PMU_EVENT_TYPE_FW)
return SBI_EINVAL;
else if (event_idx_type == SBI_PMU_EVENT_TYPE_FW)
pmu_ctr_read_fw(cidx, cval, event_code);
else
pmu_ctr_read_hw(cidx, &cval64);
if (SBI_PMU_FW_MAX <= event_code &&
pmu_dev && pmu_dev->fw_counter_read_value)
fw_counters_value[hartid][cidx - num_hw_ctrs] =
pmu_dev->fw_counter_read_value(cidx - num_hw_ctrs);
*cval = fw_counters_value[hartid][cidx - num_hw_ctrs];
return 0;
}
@@ -181,6 +199,9 @@ static int pmu_add_hw_event_map(u32 eidx_start, u32 eidx_end, u32 cmap,
int i = 0;
bool is_overlap;
struct sbi_pmu_hw_event *event = &hw_event_map[num_hw_events];
struct sbi_scratch *scratch = sbi_scratch_thishart_ptr();
int hw_ctr_avail = sbi_hart_mhpm_count(scratch);
uint32_t ctr_avail_mask = ((uint32_t)(~0) >> (32 - (hw_ctr_avail + 3)));
/* The first two counters are reserved by priv spec */
if (eidx_start > SBI_PMU_HW_INSTRUCTIONS && (cmap & SBI_PMU_FIXED_CTR_MASK))
@@ -208,7 +229,8 @@ static int pmu_add_hw_event_map(u32 eidx_start, u32 eidx_end, u32 cmap,
}
event->select_mask = select_mask;
event->counters = cmap;
/* Map the only the counters that are available in the hardware */
event->counters = cmap & ctr_avail_mask;
event->select = select;
num_hw_events++;
@@ -252,7 +274,7 @@ static int pmu_ctr_enable_irq_hw(int ctr_idx)
#if __riscv_xlen == 32
mhpmevent_csr = CSR_MHPMEVENT3H + ctr_idx - 3;
of_mask = ~MHPMEVENTH_OF;
of_mask = (uint32_t)~MHPMEVENTH_OF;
#else
mhpmevent_csr = CSR_MHPMEVENT3 + ctr_idx - 3;
of_mask = ~MHPMEVENT_OF;
@@ -293,10 +315,10 @@ static int pmu_ctr_start_hw(uint32_t cidx, uint64_t ival, bool ival_update)
unsigned long mctr_inhbt;
/* Make sure the counter index lies within the range and is not TM bit */
if (cidx > num_hw_ctrs || cidx == 1)
if (cidx >= num_hw_ctrs || cidx == 1)
return SBI_EINVAL;
if (!sbi_hart_has_feature(scratch, SBI_HART_HAS_MCOUNTINHIBIT))
if (sbi_hart_priv_version(scratch) < SBI_HART_PRIV_VER_1_11)
goto skip_inhibit_update;
/*
@@ -309,8 +331,10 @@ static int pmu_ctr_start_hw(uint32_t cidx, uint64_t ival, bool ival_update)
__clear_bit(cidx, &mctr_inhbt);
if (sbi_hart_has_feature(scratch, SBI_HART_HAS_SSCOFPMF))
if (sbi_hart_has_extension(scratch, SBI_HART_EXT_SSCOFPMF))
pmu_ctr_enable_irq_hw(cidx);
if (pmu_dev && pmu_dev->hw_counter_enable_irq)
pmu_dev->hw_counter_enable_irq(cidx);
csr_write(CSR_MCOUNTINHIBIT, mctr_inhbt);
skip_inhibit_update:
@@ -320,16 +344,36 @@ skip_inhibit_update:
return 0;
}
static int pmu_ctr_start_fw(uint32_t cidx, uint32_t fw_evt_code,
int sbi_pmu_irq_bit(void)
{
struct sbi_scratch *scratch = sbi_scratch_thishart_ptr();
if (sbi_hart_has_extension(scratch, SBI_HART_EXT_SSCOFPMF))
return MIP_LCOFIP;
if (pmu_dev && pmu_dev->hw_counter_irq_bit)
return pmu_dev->hw_counter_irq_bit();
return 0;
}
static int pmu_ctr_start_fw(uint32_t cidx, uint32_t event_code,
uint64_t ival, bool ival_update)
{
int ret;
u32 hartid = current_hartid();
struct sbi_pmu_fw_event *fevent;
fevent = &fw_event_map[hartid][fw_evt_code];
if (SBI_PMU_FW_MAX <= event_code &&
pmu_dev && pmu_dev->fw_counter_start) {
ret = pmu_dev->fw_counter_start(cidx - num_hw_ctrs,
event_code,
ival, ival_update);
if (ret)
return ret;
}
if (ival_update)
fevent->curr_count = ival;
fevent->bStarted = TRUE;
fw_counters_value[hartid][cidx - num_hw_ctrs] = ival;
fw_counters_started[hartid] |= BIT(cidx - num_hw_ctrs);
return 0;
}
@@ -339,25 +383,26 @@ int sbi_pmu_ctr_start(unsigned long cbase, unsigned long cmask,
{
int event_idx_type;
uint32_t event_code;
unsigned long ctr_mask = cmask << cbase;
int ret = SBI_EINVAL;
bool bUpdate = FALSE;
int i, cidx;
if (__fls(ctr_mask) >= total_ctrs)
if ((cbase + sbi_fls(cmask)) >= total_ctrs)
return ret;
if (flags & SBI_PMU_START_FLAG_SET_INIT_VALUE)
bUpdate = TRUE;
for_each_set_bit_from(cbase, &ctr_mask, total_ctrs) {
event_idx_type = pmu_ctr_validate(cbase, &event_code);
for_each_set_bit(i, &cmask, total_ctrs) {
cidx = i + cbase;
event_idx_type = pmu_ctr_validate(cidx, &event_code);
if (event_idx_type < 0)
/* Continue the start operation for other counters */
continue;
else if (event_idx_type == SBI_PMU_EVENT_TYPE_FW)
ret = pmu_ctr_start_fw(cbase, event_code, ival, bUpdate);
ret = pmu_ctr_start_fw(cidx, event_code, ival, bUpdate);
else
ret = pmu_ctr_start_hw(cbase, ival, bUpdate);
ret = pmu_ctr_start_hw(cidx, ival, bUpdate);
}
return ret;
@@ -368,13 +413,13 @@ static int pmu_ctr_stop_hw(uint32_t cidx)
struct sbi_scratch *scratch = sbi_scratch_thishart_ptr();
unsigned long mctr_inhbt;
if (!sbi_hart_has_feature(scratch, SBI_HART_HAS_MCOUNTINHIBIT))
if (sbi_hart_priv_version(scratch) < SBI_HART_PRIV_VER_1_11)
return 0;
mctr_inhbt = csr_read(CSR_MCOUNTINHIBIT);
/* Make sure the counter index lies within the range and is not TM bit */
if (cidx > num_hw_ctrs || cidx == 1)
if (cidx >= num_hw_ctrs || cidx == 1)
return SBI_EINVAL;
if (!__test_bit(cidx, &mctr_inhbt)) {
@@ -385,11 +430,18 @@ static int pmu_ctr_stop_hw(uint32_t cidx)
return SBI_EALREADY_STOPPED;
}
static int pmu_ctr_stop_fw(uint32_t cidx, uint32_t fw_evt_code)
static int pmu_ctr_stop_fw(uint32_t cidx, uint32_t event_code)
{
u32 hartid = current_hartid();
int ret;
fw_event_map[hartid][fw_evt_code].bStarted = FALSE;
if (SBI_PMU_FW_MAX <= event_code &&
pmu_dev && pmu_dev->fw_counter_stop) {
ret = pmu_dev->fw_counter_stop(cidx - num_hw_ctrs);
if (ret)
return ret;
}
fw_counters_started[current_hartid()] &= ~BIT(cidx - num_hw_ctrs);
return 0;
}
@@ -400,7 +452,9 @@ static int pmu_reset_hw_mhpmevent(int ctr_idx)
return SBI_EFAIL;
#if __riscv_xlen == 32
csr_write_num(CSR_MHPMEVENT3 + ctr_idx - 3, 0);
csr_write_num(CSR_MHPMEVENT3H + ctr_idx - 3, 0);
if (sbi_hart_has_extension(sbi_scratch_thishart_ptr(),
SBI_HART_EXT_SSCOFPMF))
csr_write_num(CSR_MHPMEVENT3H + ctr_idx - 3, 0);
#else
csr_write_num(CSR_MHPMEVENT3 + ctr_idx - 3, 0);
#endif
@@ -415,25 +469,26 @@ int sbi_pmu_ctr_stop(unsigned long cbase, unsigned long cmask,
int ret = SBI_EINVAL;
int event_idx_type;
uint32_t event_code;
unsigned long ctr_mask = cmask << cbase;
int i, cidx;
if (__fls(ctr_mask) >= total_ctrs)
if ((cbase + sbi_fls(cmask)) >= total_ctrs)
return SBI_EINVAL;
for_each_set_bit_from(cbase, &ctr_mask, total_ctrs) {
event_idx_type = pmu_ctr_validate(cbase, &event_code);
for_each_set_bit(i, &cmask, total_ctrs) {
cidx = i + cbase;
event_idx_type = pmu_ctr_validate(cidx, &event_code);
if (event_idx_type < 0)
/* Continue the stop operation for other counters */
continue;
else if (event_idx_type == SBI_PMU_EVENT_TYPE_FW)
ret = pmu_ctr_stop_fw(cbase, event_code);
ret = pmu_ctr_stop_fw(cidx, event_code);
else
ret = pmu_ctr_stop_hw(cbase);
ret = pmu_ctr_stop_hw(cidx);
if (flag & SBI_PMU_STOP_FLAG_RESET) {
active_events[hartid][cbase] = SBI_PMU_EVENT_IDX_INVALID;
pmu_reset_hw_mhpmevent(cbase);
active_events[hartid][cidx] = SBI_PMU_EVENT_IDX_INVALID;
pmu_reset_hw_mhpmevent(cidx);
}
}
@@ -466,16 +521,25 @@ static int pmu_update_hw_mhpmevent(struct sbi_pmu_hw_event *hw_evt, int ctr_idx,
if (!mhpmevent_val || ctr_idx < 3 || ctr_idx >= SBI_PMU_HW_CTR_MAX)
return SBI_EFAIL;
/* Always clear the OVF bit and inhibit countin of events in M-mode */
if (sbi_hart_has_feature(scratch, SBI_HART_HAS_SSCOFPMF))
mhpmevent_val = (mhpmevent_val & ~MHPMEVENT_SSCOF_MASK) | MHPMEVENT_MINH;
/**
* Always set the OVF bit(disable interrupts) and inhibit counting of
* events in M-mode. The OVF bit should be enabled during the start call.
*/
if (sbi_hart_has_extension(scratch, SBI_HART_EXT_SSCOFPMF))
mhpmevent_val = (mhpmevent_val & ~MHPMEVENT_SSCOF_MASK) |
MHPMEVENT_MINH | MHPMEVENT_OF;
if (pmu_dev && pmu_dev->hw_counter_disable_irq)
pmu_dev->hw_counter_disable_irq(ctr_idx);
/* Update the inhibit flags based on inhibit flags received from supervisor */
pmu_update_inhibit_flags(flags, &mhpmevent_val);
#if __riscv_xlen == 32
csr_write_num(CSR_MHPMEVENT3 + ctr_idx - 3, mhpmevent_val & 0xFFFFFFFF);
csr_write_num(CSR_MHPMEVENT3H + ctr_idx - 3, mhpmevent_val >> BITS_PER_LONG);
if (sbi_hart_has_extension(scratch, SBI_HART_EXT_SSCOFPMF))
csr_write_num(CSR_MHPMEVENT3H + ctr_idx - 3,
mhpmevent_val >> BITS_PER_LONG);
#else
csr_write_num(CSR_MHPMEVENT3 + ctr_idx - 3, mhpmevent_val);
#endif
@@ -504,7 +568,7 @@ static int pmu_ctr_find_hw(unsigned long cbase, unsigned long cmask, unsigned lo
u32 hartid = current_hartid();
struct sbi_scratch *scratch = sbi_scratch_thishart_ptr();
if (cbase > num_hw_ctrs)
if (cbase >= num_hw_ctrs)
return SBI_EINVAL;
/**
@@ -513,10 +577,10 @@ static int pmu_ctr_find_hw(unsigned long cbase, unsigned long cmask, unsigned lo
*/
fixed_ctr = pmu_ctr_find_fixed_fw(event_idx);
if (fixed_ctr >= 0 &&
!sbi_hart_has_feature(scratch, SBI_HART_HAS_SSCOFPMF))
!sbi_hart_has_extension(scratch, SBI_HART_EXT_SSCOFPMF))
return fixed_ctr;
if (sbi_hart_has_feature(scratch, SBI_HART_HAS_MCOUNTINHIBIT))
if (sbi_hart_priv_version(scratch) >= SBI_HART_PRIV_VER_1_11)
mctr_inhbt = csr_read(CSR_MCOUNTINHIBIT);
for (i = 0; i < num_hw_events; i++) {
temp = &hw_event_map[i];
@@ -543,7 +607,7 @@ static int pmu_ctr_find_hw(unsigned long cbase, unsigned long cmask, unsigned lo
if (active_events[hartid][cbase] != SBI_PMU_EVENT_IDX_INVALID)
continue;
/* If mcountinhibit is supported, the bit must be enabled */
if ((sbi_hart_has_feature(scratch, SBI_HART_HAS_MCOUNTINHIBIT)) &&
if ((sbi_hart_priv_version(scratch) >= SBI_HART_PRIV_VER_1_11) &&
!__test_bit(cbase, &mctr_inhbt))
continue;
/* We found a valid counter that is not started yet */
@@ -575,21 +639,26 @@ static int pmu_ctr_find_hw(unsigned long cbase, unsigned long cmask, unsigned lo
* Thus, select the first available fw counter after sanity
* check.
*/
static int pmu_ctr_find_fw(unsigned long cbase, unsigned long cmask, u32 hartid)
static int pmu_ctr_find_fw(unsigned long cbase, unsigned long cmask,
uint32_t event_code, u32 hartid)
{
int i = 0;
int fw_base;
unsigned long ctr_mask = cmask << cbase;
int i, cidx;
if (cbase <= num_hw_ctrs)
fw_base = num_hw_ctrs + 1;
else
fw_base = cbase;
for_each_set_bit(i, &cmask, BITS_PER_LONG) {
cidx = i + cbase;
if (cidx < num_hw_ctrs || total_ctrs <= cidx)
continue;
if (active_events[hartid][i] != SBI_PMU_EVENT_IDX_INVALID)
continue;
if (SBI_PMU_FW_MAX <= event_code &&
pmu_dev && pmu_dev->fw_counter_match_code) {
if (!pmu_dev->fw_counter_match_code(cidx - num_hw_ctrs,
event_code))
continue;
}
for (i = fw_base; i < total_ctrs; i++)
if ((active_events[hartid][i] == SBI_PMU_EVENT_IDX_INVALID) &&
((1UL << i) & ctr_mask))
return i;
return i;
}
return SBI_ENOTSUPP;
}
@@ -598,17 +667,19 @@ int sbi_pmu_ctr_cfg_match(unsigned long cidx_base, unsigned long cidx_mask,
unsigned long flags, unsigned long event_idx,
uint64_t event_data)
{
int ctr_idx = SBI_ENOTSUPP;
u32 hartid = current_hartid();
int event_type = get_cidx_type(event_idx);
struct sbi_pmu_fw_event *fevent;
uint32_t fw_evt_code;
unsigned long tmp = cidx_mask << cidx_base;
int ret, ctr_idx = SBI_ENOTSUPP;
u32 event_code, hartid = current_hartid();
int event_type;
/* Do a basic sanity check of counter base & mask */
if (__fls(tmp) >= total_ctrs || event_type >= SBI_PMU_EVENT_TYPE_MAX)
if ((cidx_base + sbi_fls(cidx_mask)) >= total_ctrs)
return SBI_EINVAL;
event_type = pmu_event_validate(event_idx);
if (event_type < 0)
return SBI_EINVAL;
event_code = get_cidx_code(event_idx);
if (flags & SBI_PMU_CFG_FLAG_SKIP_MATCH) {
/* The caller wants to skip the match because it already knows the
* counter idx for the given event. Verify that the counter idx
@@ -622,7 +693,7 @@ int sbi_pmu_ctr_cfg_match(unsigned long cidx_base, unsigned long cidx_mask,
if (event_type == SBI_PMU_EVENT_TYPE_FW) {
/* Any firmware counter can be used track any firmware event */
ctr_idx = pmu_ctr_find_fw(cidx_base, cidx_mask, hartid);
ctr_idx = pmu_ctr_find_fw(cidx_base, cidx_mask, event_code, hartid);
} else {
ctr_idx = pmu_ctr_find_hw(cidx_base, cidx_mask, flags, event_idx,
event_data);
@@ -639,30 +710,46 @@ skip_match:
if (flags & SBI_PMU_CFG_FLAG_AUTO_START)
pmu_ctr_start_hw(ctr_idx, 0, false);
} else if (event_type == SBI_PMU_EVENT_TYPE_FW) {
fw_evt_code = get_cidx_code(event_idx);
fevent = &fw_event_map[hartid][fw_evt_code];
if (flags & SBI_PMU_CFG_FLAG_CLEAR_VALUE)
fevent->curr_count = 0;
if (flags & SBI_PMU_CFG_FLAG_AUTO_START)
fevent->bStarted = TRUE;
fw_counters_value[hartid][ctr_idx - num_hw_ctrs] = 0;
if (flags & SBI_PMU_CFG_FLAG_AUTO_START) {
if (SBI_PMU_FW_MAX <= event_code &&
pmu_dev && pmu_dev->fw_counter_start) {
ret = pmu_dev->fw_counter_start(
ctr_idx - num_hw_ctrs, event_code,
fw_counters_value[hartid][ctr_idx - num_hw_ctrs],
true);
if (ret)
return ret;
}
fw_counters_started[hartid] |= BIT(ctr_idx - num_hw_ctrs);
}
}
return ctr_idx;
}
inline int sbi_pmu_ctr_incr_fw(enum sbi_pmu_fw_event_code_id fw_id)
int sbi_pmu_ctr_incr_fw(enum sbi_pmu_fw_event_code_id fw_id)
{
u32 hartid = current_hartid();
struct sbi_pmu_fw_event *fevent;
u32 cidx, hartid = current_hartid();
uint64_t *fcounter = NULL;
if (likely(!fw_counters_started[hartid]))
return 0;
if (unlikely(fw_id >= SBI_PMU_FW_MAX))
return SBI_EINVAL;
fevent = &fw_event_map[hartid][fw_id];
for (cidx = num_hw_ctrs; cidx < total_ctrs; cidx++) {
if (get_cidx_code(active_events[hartid][cidx]) == fw_id &&
(fw_counters_started[hartid] & BIT(cidx - num_hw_ctrs))) {
fcounter = &fw_counters_value[hartid][cidx - num_hw_ctrs];
break;
}
}
/* PMU counters will be only enabled during performance debugging */
if (unlikely(fevent->bStarted))
fevent->curr_count++;
if (fcounter)
(*fcounter)++;
return 0;
}
@@ -682,7 +769,7 @@ int sbi_pmu_ctr_get_info(uint32_t cidx, unsigned long *ctr_info)
return SBI_EINVAL;
/* We have 31 HW counters with 31 being the last index(MHPMCOUNTER31) */
if (cidx <= num_hw_ctrs) {
if (cidx < num_hw_ctrs) {
cinfo.type = SBI_PMU_CTR_TYPE_HW;
cinfo.csr = CSR_CYCLE + cidx;
/* mcycle & minstret are always 64 bit */
@@ -693,8 +780,8 @@ int sbi_pmu_ctr_get_info(uint32_t cidx, unsigned long *ctr_info)
} else {
/* it's a firmware counter */
cinfo.type = SBI_PMU_CTR_TYPE_FW;
/* Firmware counters are XLEN bits wide */
cinfo.width = BITS_PER_LONG - 1;
/* Firmware counters are always 64 bits wide */
cinfo.width = 63;
}
*ctr_info = cinfo.value;
@@ -710,18 +797,32 @@ static void pmu_reset_event_map(u32 hartid)
for (j = 3; j < total_ctrs; j++)
active_events[hartid][j] = SBI_PMU_EVENT_IDX_INVALID;
for (j = 0; j < SBI_PMU_FW_CTR_MAX; j++)
sbi_memset(&fw_event_map[hartid][j], 0,
sizeof(struct sbi_pmu_fw_event));
fw_counters_value[hartid][j] = 0;
fw_counters_started[hartid] = 0;
}
const struct sbi_pmu_device *sbi_pmu_get_device(void)
{
return pmu_dev;
}
void sbi_pmu_set_device(const struct sbi_pmu_device *dev)
{
if (!dev || pmu_dev)
return;
pmu_dev = dev;
}
void sbi_pmu_exit(struct sbi_scratch *scratch)
{
u32 hartid = current_hartid();
if (sbi_hart_has_feature(scratch, SBI_HART_HAS_MCOUNTINHIBIT))
if (sbi_hart_priv_version(scratch) >= SBI_HART_PRIV_VER_1_11)
csr_write(CSR_MCOUNTINHIBIT, 0xFFFFFFF8);
csr_write(CSR_MCOUNTEREN, -1);
if (sbi_hart_priv_version(scratch) >= SBI_HART_PRIV_VER_1_10)
csr_write(CSR_MCOUNTEREN, -1);
pmu_reset_event_map(hartid);
}
@@ -736,7 +837,7 @@ int sbi_pmu_init(struct sbi_scratch *scratch, bool cold_boot)
sbi_platform_pmu_init(plat);
/* mcycle & minstret is available always */
num_hw_ctrs = sbi_hart_mhpm_count(scratch) + 2;
num_hw_ctrs = sbi_hart_mhpm_count(scratch) + 3;
total_ctrs = num_hw_ctrs + SBI_PMU_FW_CTR_MAX;
}

View File

@@ -59,7 +59,6 @@ size_t sbi_strnlen(const char *str, size_t count)
while (*str != '\0' && ret < count) {
ret++;
str++;
count--;
}
return ret;
@@ -149,8 +148,8 @@ void *sbi_memmove(void *dest, const void *src, size_t count)
count--;
}
} else {
temp1 = dest + count - 1;
temp2 = src + count - 1;
temp1 = (char *)dest + count - 1;
temp2 = (char *)src + count - 1;
while (count > 0) {
*temp1-- = *temp2--;

View File

@@ -44,11 +44,6 @@ static u64 get_ticks(void)
}
#endif
static u64 get_platform_ticks(void)
{
return timer_dev->timer_value();
}
static void nop_delay_fn(void *opaque)
{
cpu_relax();
@@ -81,6 +76,19 @@ void sbi_timer_delay_loop(ulong units, u64 unit_freq,
delay_fn(opaque);
}
bool sbi_timer_waitms_until(bool (*predicate)(void *), void *arg,
uint64_t timeout_ms)
{
uint64_t start_time = sbi_timer_value();
uint64_t ticks =
(sbi_timer_get_device()->timer_freq / 1000) *
timeout_ms;
while(!predicate(arg))
if (sbi_timer_value() - start_time >= ticks)
return false;
return true;
}
u64 sbi_timer_value(void)
{
if (get_time_val)
@@ -124,16 +132,35 @@ void sbi_timer_set_delta_upper(ulong delta_upper)
void sbi_timer_event_start(u64 next_event)
{
sbi_pmu_ctr_incr_fw(SBI_PMU_FW_SET_TIMER);
if (timer_dev && timer_dev->timer_event_start)
/**
* Update the stimecmp directly if available. This allows
* the older software to leverage sstc extension on newer hardware.
*/
if (sbi_hart_has_extension(sbi_scratch_thishart_ptr(), SBI_HART_EXT_SSTC)) {
#if __riscv_xlen == 32
csr_write(CSR_STIMECMP, next_event & 0xFFFFFFFF);
csr_write(CSR_STIMECMPH, next_event >> 32);
#else
csr_write(CSR_STIMECMP, next_event);
#endif
} else if (timer_dev && timer_dev->timer_event_start) {
timer_dev->timer_event_start(next_event);
csr_clear(CSR_MIP, MIP_STIP);
csr_clear(CSR_MIP, MIP_STIP);
}
csr_set(CSR_MIE, MIP_MTIP);
}
void sbi_timer_process(void)
{
csr_clear(CSR_MIE, MIP_MTIP);
csr_set(CSR_MIP, MIP_STIP);
/*
* If sstc extension is available, supervisor can receive the timer
* directly without M-mode come in between. This function should
* only invoked if M-mode programs the timer for its own purpose.
*/
if (!sbi_hart_has_extension(sbi_scratch_thishart_ptr(), SBI_HART_EXT_SSTC))
csr_set(CSR_MIP, MIP_STIP);
}
const struct sbi_timer_device *sbi_timer_get_device(void)
@@ -148,7 +175,7 @@ void sbi_timer_set_device(const struct sbi_timer_device *dev)
timer_dev = dev;
if (!get_time_val && timer_dev->timer_value)
get_time_val = get_platform_ticks;
get_time_val = timer_dev->timer_value;
}
int sbi_timer_init(struct sbi_scratch *scratch, bool cold_boot)
@@ -161,7 +188,7 @@ int sbi_timer_init(struct sbi_scratch *scratch, bool cold_boot)
if (!time_delta_off)
return SBI_ENOMEM;
if (sbi_hart_has_feature(scratch, SBI_HART_HAS_TIME))
if (sbi_hart_has_extension(scratch, SBI_HART_EXT_TIME))
get_time_val = get_ticks;
} else {
if (!time_delta_off)

View File

@@ -9,12 +9,14 @@
#include <sbi/riscv_asm.h>
#include <sbi/riscv_encoding.h>
#include <sbi/sbi_bitops.h>
#include <sbi/sbi_console.h>
#include <sbi/sbi_ecall.h>
#include <sbi/sbi_error.h>
#include <sbi/sbi_hart.h>
#include <sbi/sbi_illegal_insn.h>
#include <sbi/sbi_ipi.h>
#include <sbi/sbi_irqchip.h>
#include <sbi/sbi_misaligned_ldst.h>
#include <sbi/sbi_pmu.h>
#include <sbi/sbi_scratch.h>
@@ -98,17 +100,14 @@ int sbi_trap_redirect(struct sbi_trap_regs *regs,
if (prev_mode != PRV_S && prev_mode != PRV_U)
return SBI_ENOTSUPP;
/* For certain exceptions from VS/VU-mode we redirect to VS-mode */
/* If exceptions came from VS/VU-mode, redirect to VS-mode if
* delegated in hedeleg
*/
if (misa_extension('H') && prev_virt) {
switch (trap->cause) {
case CAUSE_FETCH_PAGE_FAULT:
case CAUSE_LOAD_PAGE_FAULT:
case CAUSE_STORE_PAGE_FAULT:
if ((trap->cause < __riscv_xlen) &&
(csr_read(CSR_HEDELEG) & BIT(trap->cause))) {
next_virt = TRUE;
break;
default:
break;
};
}
}
/* Update MSTATUS MPV bits */
@@ -120,14 +119,18 @@ int sbi_trap_redirect(struct sbi_trap_regs *regs,
regs->mstatus |= (next_virt) ? MSTATUS_MPV : 0UL;
#endif
/* Update HSTATUS for VS/VU-mode to HS-mode transition */
if (misa_extension('H') && prev_virt && !next_virt) {
/* Update HSTATUS SPVP and SPV bits */
/* Update hypervisor CSRs if going to HS-mode */
if (misa_extension('H') && !next_virt) {
hstatus = csr_read(CSR_HSTATUS);
hstatus &= ~HSTATUS_SPVP;
hstatus |= (prev_mode == PRV_S) ? HSTATUS_SPVP : 0;
if (prev_virt) {
/* hstatus.SPVP is only updated if coming from VS/VU-mode */
hstatus &= ~HSTATUS_SPVP;
hstatus |= (prev_mode == PRV_S) ? HSTATUS_SPVP : 0;
}
hstatus &= ~HSTATUS_SPV;
hstatus |= (prev_virt) ? HSTATUS_SPV : 0;
hstatus &= ~HSTATUS_GVA;
hstatus |= (trap->gva) ? HSTATUS_GVA : 0;
csr_write(CSR_HSTATUS, hstatus);
csr_write(CSR_HTVAL, trap->tval2);
csr_write(CSR_HTINST, trap->tinst);
@@ -195,6 +198,52 @@ int sbi_trap_redirect(struct sbi_trap_regs *regs,
return 0;
}
static int sbi_trap_nonaia_irq(struct sbi_trap_regs *regs, ulong mcause)
{
mcause &= ~(1UL << (__riscv_xlen - 1));
switch (mcause) {
case IRQ_M_TIMER:
sbi_timer_process();
break;
case IRQ_M_SOFT:
sbi_ipi_process();
break;
case IRQ_M_EXT:
return sbi_irqchip_process(regs);
default:
return SBI_ENOENT;
};
return 0;
}
static int sbi_trap_aia_irq(struct sbi_trap_regs *regs, ulong mcause)
{
int rc;
unsigned long mtopi;
while ((mtopi = csr_read(CSR_MTOPI))) {
mtopi = mtopi >> TOPI_IID_SHIFT;
switch (mtopi) {
case IRQ_M_TIMER:
sbi_timer_process();
break;
case IRQ_M_SOFT:
sbi_ipi_process();
break;
case IRQ_M_EXT:
rc = sbi_irqchip_process(regs);
if (rc)
return rc;
break;
default:
return SBI_ENOENT;
}
}
return 0;
}
/**
* Handle trap/interrupt
*
@@ -225,18 +274,15 @@ struct sbi_trap_regs *sbi_trap_handler(struct sbi_trap_regs *regs)
}
if (mcause & (1UL << (__riscv_xlen - 1))) {
mcause &= ~(1UL << (__riscv_xlen - 1));
switch (mcause) {
case IRQ_M_TIMER:
sbi_timer_process();
break;
case IRQ_M_SOFT:
sbi_ipi_process();
break;
default:
msg = "unhandled external interrupt";
if (sbi_hart_has_extension(sbi_scratch_thishart_ptr(),
SBI_HART_EXT_SMAIA))
rc = sbi_trap_aia_irq(regs, mcause);
else
rc = sbi_trap_nonaia_irq(regs, mcause);
if (rc) {
msg = "unhandled local interrupt";
goto trap_error;
};
}
return regs;
}
@@ -270,6 +316,8 @@ struct sbi_trap_regs *sbi_trap_handler(struct sbi_trap_regs *regs)
trap.tval = mtval;
trap.tval2 = mtval2;
trap.tinst = mtinst;
trap.gva = sbi_regs_gva(regs);
rc = sbi_trap_redirect(regs, &trap);
break;
};

View File

@@ -83,7 +83,7 @@ DEFINE_UNPRIVILEGED_LOAD_FUNCTION(u32, lwu)
DEFINE_UNPRIVILEGED_LOAD_FUNCTION(u64, ld)
DEFINE_UNPRIVILEGED_STORE_FUNCTION(u64, sd)
DEFINE_UNPRIVILEGED_LOAD_FUNCTION(ulong, ld)
#else
#elif __riscv_xlen == 32
DEFINE_UNPRIVILEGED_LOAD_FUNCTION(u32, lw)
DEFINE_UNPRIVILEGED_LOAD_FUNCTION(ulong, lw)
@@ -112,6 +112,8 @@ void sbi_store_u64(u64 *addr, u64 val,
if (trap->cause)
return;
}
#else
# error "Unexpected __riscv_xlen"
#endif
ulong sbi_get_insn(ulong mepc, struct sbi_trap_info *trap)
@@ -147,15 +149,17 @@ ulong sbi_get_insn(ulong mepc, struct sbi_trap_info *trap)
switch (trap->cause) {
case CAUSE_LOAD_ACCESS:
trap->cause = CAUSE_FETCH_ACCESS;
trap->tval = mepc;
trap->tinst = 0UL;
break;
case CAUSE_LOAD_PAGE_FAULT:
trap->cause = CAUSE_FETCH_PAGE_FAULT;
trap->tval = mepc;
trap->tinst = 0UL;
break;
case CAUSE_LOAD_GUEST_PAGE_FAULT:
trap->cause = CAUSE_FETCH_GUEST_PAGE_FAULT;
trap->tval = mepc;
if (trap->tinst != INSN_PSEUDO_VS_LOAD &&
trap->tinst != INSN_PSEUDO_VS_STORE)
trap->tinst = 0UL;
break;
default:
break;

25
lib/utils/Kconfig Normal file
View File

@@ -0,0 +1,25 @@
# SPDX-License-Identifier: BSD-2-Clause
menu "Utils and Drivers Support"
source "$(OPENSBI_SRC_DIR)/lib/utils/fdt/Kconfig"
source "$(OPENSBI_SRC_DIR)/lib/utils/gpio/Kconfig"
source "$(OPENSBI_SRC_DIR)/lib/utils/i2c/Kconfig"
source "$(OPENSBI_SRC_DIR)/lib/utils/ipi/Kconfig"
source "$(OPENSBI_SRC_DIR)/lib/utils/irqchip/Kconfig"
source "$(OPENSBI_SRC_DIR)/lib/utils/libfdt/Kconfig"
source "$(OPENSBI_SRC_DIR)/lib/utils/reset/Kconfig"
source "$(OPENSBI_SRC_DIR)/lib/utils/serial/Kconfig"
source "$(OPENSBI_SRC_DIR)/lib/utils/sys/Kconfig"
source "$(OPENSBI_SRC_DIR)/lib/utils/timer/Kconfig"
endmenu

18
lib/utils/fdt/Kconfig Normal file
View File

@@ -0,0 +1,18 @@
# SPDX-License-Identifier: BSD-2-Clause
menuconfig FDT
bool "Flattened Device Tree (FDT) support"
select LIBFDT
default n
if FDT
config FDT_DOMAIN
bool "FDT domain support"
default n
config FDT_PMU
bool "FDT performance monitoring unit (PMU) support"
default n
endif

View File

@@ -165,6 +165,9 @@ void fdt_domain_fixup(void *fdt)
if (err)
continue;
if (!fdt_node_is_enabled(fdt, doffset))
continue;
fdt_nop_property(fdt, doffset, "opensbi-domain");
}
@@ -243,7 +246,7 @@ static int __fdt_parse_region(void *fdt, int domain_offset,
/* Read "base" DT property */
val = fdt_getprop(fdt, region_offset, "base", &len);
if (!val && len >= 8)
if (!val || len != 8)
return SBI_EINVAL;
val64 = fdt32_to_cpu(val[0]);
val64 = (val64 << 32) | fdt32_to_cpu(val[1]);
@@ -251,7 +254,7 @@ static int __fdt_parse_region(void *fdt, int domain_offset,
/* Read "order" DT property */
val = fdt_getprop(fdt, region_offset, "order", &len);
if (!val && len >= 4)
if (!val || len != 4)
return SBI_EINVAL;
val32 = fdt32_to_cpu(*val);
if (val32 < 3 || __riscv_xlen < val32)
@@ -308,6 +311,9 @@ static int __fdt_parse_domain(void *fdt, int domain_offset, void *opaque)
if (err)
return err;
if (!fdt_node_is_enabled(fdt, cpu_offset))
continue;
sbi_hartmask_set_hart(val32, mask);
}
}
@@ -347,7 +353,7 @@ static int __fdt_parse_domain(void *fdt, int domain_offset, void *opaque)
if (val && len >= 4) {
cpu_offset = fdt_node_offset_by_phandle(fdt,
fdt32_to_cpu(*val));
if (cpu_offset >= 0)
if (cpu_offset >= 0 && fdt_node_is_enabled(fdt, cpu_offset))
fdt_parse_hart_id(fdt, cpu_offset, &val32);
} else {
if (domain_offset == *cold_domain_offset)
@@ -414,6 +420,9 @@ static int __fdt_parse_domain(void *fdt, int domain_offset, void *opaque)
if (SBI_HARTMASK_MAX_BITS <= val32)
continue;
if (!fdt_node_is_enabled(fdt, cpu_offset))
continue;
val = fdt_getprop(fdt, cpu_offset, "opensbi-domain", &len);
if (!val || len < 4)
return SBI_EINVAL;
@@ -460,6 +469,9 @@ int fdt_domains_populate(void *fdt)
if (hartid != cold_hartid)
continue;
if (!fdt_node_is_enabled(fdt, cpu_offset))
continue;
val = fdt_getprop(fdt, cpu_offset, "opensbi-domain", &len);
if (val && len >= 4)
cold_domain_offset = fdt_node_offset_by_phandle(fdt,

View File

@@ -38,6 +38,9 @@ void fdt_cpu_fixup(void *fdt)
if (err)
continue;
if (!fdt_node_is_enabled(fdt, cpu_offset))
continue;
/*
* Disable a HART DT node if one of the following is true:
* 1. The HART is not assigned to the current domain
@@ -52,6 +55,44 @@ void fdt_cpu_fixup(void *fdt)
}
}
static void fdt_domain_based_fixup_one(void *fdt, int nodeoff)
{
int rc;
uint64_t reg_addr, reg_size;
struct sbi_domain *dom = sbi_domain_thishart_ptr();
rc = fdt_get_node_addr_size(fdt, nodeoff, 0, &reg_addr, &reg_size);
if (rc < 0 || !reg_addr || !reg_size)
return;
if (!sbi_domain_check_addr(dom, reg_addr, dom->next_mode,
SBI_DOMAIN_READ | SBI_DOMAIN_WRITE)) {
rc = fdt_open_into(fdt, fdt, fdt_totalsize(fdt) + 32);
if (rc < 0)
return;
fdt_setprop_string(fdt, nodeoff, "status", "disabled");
}
}
static void fdt_fixup_node(void *fdt, const char *compatible)
{
int noff = 0;
while ((noff = fdt_node_offset_by_compatible(fdt, noff,
compatible)) >= 0)
fdt_domain_based_fixup_one(fdt, noff);
}
void fdt_aplic_fixup(void *fdt)
{
fdt_fixup_node(fdt, "riscv,aplic");
}
void fdt_imsic_fixup(void *fdt)
{
fdt_fixup_node(fdt, "riscv,imsics");
}
void fdt_plic_fixup(void *fdt)
{
u32 *cells;
@@ -261,10 +302,12 @@ int fdt_reserved_memory_nomap_fixup(void *fdt)
void fdt_fixups(void *fdt)
{
fdt_aplic_fixup(fdt);
fdt_imsic_fixup(fdt);
fdt_plic_fixup(fdt);
fdt_reserved_memory_fixup(fdt);
fdt_pmu_fixup(fdt);
}

View File

@@ -13,19 +13,21 @@
#include <sbi/sbi_platform.h>
#include <sbi/sbi_scratch.h>
#include <sbi_utils/fdt/fdt_helper.h>
#include <sbi_utils/irqchip/aplic.h>
#include <sbi_utils/irqchip/imsic.h>
#include <sbi_utils/irqchip/plic.h>
#define DEFAULT_UART_FREQ 0
#define DEFAULT_UART_BAUD 115200
#define DEFAULT_UART_REG_SHIFT 0
#define DEFAULT_UART_REG_IO_WIDTH 1
#define DEFAULT_UART_REG_OFFSET 0
#define DEFAULT_RENESAS_SCIF_FREQ 100000000
#define DEFAULT_RENESAS_SCIF_BAUD 115200
#define DEFAULT_SIFIVE_UART_FREQ 0
#define DEFAULT_SIFIVE_UART_BAUD 115200
#define DEFAULT_SIFIVE_UART_REG_SHIFT 0
#define DEFAULT_SIFIVE_UART_REG_IO_WIDTH 4
#define DEFAULT_GAISLER_UART_REG_IO_WIDTH 4
#define DEFAULT_SHAKTI_UART_FREQ 50000000
#define DEFAULT_SHAKTI_UART_BAUD 115200
@@ -125,7 +127,7 @@ static int fdt_translate_address(void *fdt, uint64_t reg, int parent,
int i, rlen;
int cell_addr, cell_size;
const fdt32_t *ranges;
uint64_t offset = 0, caddr = 0, paddr = 0, rsize = 0;
uint64_t offset, caddr = 0, paddr = 0, rsize = 0;
cell_addr = fdt_address_cells(fdt, parent);
if (cell_addr < 1)
@@ -213,6 +215,24 @@ int fdt_get_node_addr_size(void *fdt, int node, int index,
return 0;
}
bool fdt_node_is_enabled(void *fdt, int nodeoff)
{
int len;
const void *prop;
prop = fdt_getprop(fdt, nodeoff, "status", &len);
if (!prop)
return true;
if (!strncmp(prop, "okay", strlen("okay")))
return true;
if (!strncmp(prop, "ok", strlen("ok")))
return true;
return false;
}
int fdt_parse_hart_id(void *fdt, int cpu_offset, u32 *hartid)
{
int len;
@@ -241,7 +261,7 @@ int fdt_parse_hart_id(void *fdt, int cpu_offset, u32 *hartid)
return 0;
}
int fdt_parse_max_hart_id(void *fdt, u32 *max_hartid)
int fdt_parse_max_enabled_hart_id(void *fdt, u32 *max_hartid)
{
u32 hartid;
int err, cpu_offset, cpus_offset;
@@ -262,6 +282,9 @@ int fdt_parse_max_hart_id(void *fdt, u32 *max_hartid)
if (err)
continue;
if (!fdt_node_is_enabled(fdt, cpu_offset))
continue;
if (hartid > *max_hartid)
*max_hartid = hartid;
}
@@ -290,8 +313,10 @@ int fdt_parse_timebase_frequency(void *fdt, unsigned long *freq)
return 0;
}
int fdt_parse_gaisler_uart_node(void *fdt, int nodeoffset,
struct platform_uart_data *uart)
static int fdt_parse_uart_node_common(void *fdt, int nodeoffset,
struct platform_uart_data *uart,
unsigned long default_freq,
unsigned long default_baud)
{
int len, rc;
const fdt32_t *val;
@@ -314,126 +339,60 @@ int fdt_parse_gaisler_uart_node(void *fdt, int nodeoffset,
if (len > 0 && val)
uart->freq = fdt32_to_cpu(*val);
else
uart->freq = DEFAULT_UART_FREQ;
uart->freq = default_freq;
val = (fdt32_t *)fdt_getprop(fdt, nodeoffset, "current-speed", &len);
if (len > 0 && val)
uart->baud = fdt32_to_cpu(*val);
else
uart->baud = DEFAULT_UART_BAUD;
/* For Gaisler APBUART, the reg-shift and reg-io-width are fixed .*/
uart->reg_shift = DEFAULT_UART_REG_SHIFT;
uart->reg_io_width = DEFAULT_GAISLER_UART_REG_IO_WIDTH;
uart->baud = default_baud;
return 0;
}
int fdt_parse_gaisler_uart_node(void *fdt, int nodeoffset,
struct platform_uart_data *uart)
{
return fdt_parse_uart_node_common(fdt, nodeoffset, uart,
DEFAULT_UART_FREQ,
DEFAULT_UART_BAUD);
}
int fdt_parse_renesas_scif_node(void *fdt, int nodeoffset,
struct platform_uart_data *uart)
{
return fdt_parse_uart_node_common(fdt, nodeoffset, uart,
DEFAULT_RENESAS_SCIF_FREQ,
DEFAULT_RENESAS_SCIF_BAUD);
}
int fdt_parse_shakti_uart_node(void *fdt, int nodeoffset,
struct platform_uart_data *uart)
{
int len, rc;
const fdt32_t *val;
uint64_t reg_addr, reg_size;
if (nodeoffset < 0 || !uart || !fdt)
return SBI_ENODEV;
rc = fdt_get_node_addr_size(fdt, nodeoffset, 0,
&reg_addr, &reg_size);
if (rc < 0 || !reg_addr || !reg_size)
return SBI_ENODEV;
uart->addr = reg_addr;
/**
* UART address is mandaotry. clock-frequency and current-speed
* may not be present. Don't return error.
*/
val = (fdt32_t *)fdt_getprop(fdt, nodeoffset, "clock-frequency", &len);
if (len > 0 && val)
uart->freq = fdt32_to_cpu(*val);
else
uart->freq = DEFAULT_SHAKTI_UART_FREQ;
val = (fdt32_t *)fdt_getprop(fdt, nodeoffset, "current-speed", &len);
if (len > 0 && val)
uart->baud = fdt32_to_cpu(*val);
else
uart->baud = DEFAULT_SHAKTI_UART_BAUD;
return 0;
return fdt_parse_uart_node_common(fdt, nodeoffset, uart,
DEFAULT_SHAKTI_UART_FREQ,
DEFAULT_SHAKTI_UART_BAUD);
}
int fdt_parse_sifive_uart_node(void *fdt, int nodeoffset,
struct platform_uart_data *uart)
{
int len, rc;
const fdt32_t *val;
uint64_t reg_addr, reg_size;
if (nodeoffset < 0 || !uart || !fdt)
return SBI_ENODEV;
rc = fdt_get_node_addr_size(fdt, nodeoffset, 0,
&reg_addr, &reg_size);
if (rc < 0 || !reg_addr || !reg_size)
return SBI_ENODEV;
uart->addr = reg_addr;
/**
* UART address is mandaotry. clock-frequency and current-speed
* may not be present. Don't return error.
*/
val = (fdt32_t *)fdt_getprop(fdt, nodeoffset, "clock-frequency", &len);
if (len > 0 && val)
uart->freq = fdt32_to_cpu(*val);
else
uart->freq = DEFAULT_SIFIVE_UART_FREQ;
val = (fdt32_t *)fdt_getprop(fdt, nodeoffset, "current-speed", &len);
if (len > 0 && val)
uart->baud = fdt32_to_cpu(*val);
else
uart->baud = DEFAULT_SIFIVE_UART_BAUD;
/* For SiFive UART, the reg-shift and reg-io-width are fixed .*/
uart->reg_shift = DEFAULT_SIFIVE_UART_REG_SHIFT;
uart->reg_io_width = DEFAULT_SIFIVE_UART_REG_IO_WIDTH;
return 0;
return fdt_parse_uart_node_common(fdt, nodeoffset, uart,
DEFAULT_SIFIVE_UART_FREQ,
DEFAULT_SIFIVE_UART_BAUD);
}
int fdt_parse_uart8250_node(void *fdt, int nodeoffset,
struct platform_uart_data *uart)
int fdt_parse_uart_node(void *fdt, int nodeoffset,
struct platform_uart_data *uart)
{
int len, rc;
const fdt32_t *val;
uint64_t reg_addr, reg_size;
if (nodeoffset < 0 || !uart || !fdt)
return SBI_ENODEV;
rc = fdt_get_node_addr_size(fdt, nodeoffset, 0,
&reg_addr, &reg_size);
if (rc < 0 || !reg_addr || !reg_size)
return SBI_ENODEV;
uart->addr = reg_addr;
/**
* UART address is mandaotry. clock-frequency and current-speed
* may not be present. Don't return error.
*/
val = (fdt32_t *)fdt_getprop(fdt, nodeoffset, "clock-frequency", &len);
if (len > 0 && val)
uart->freq = fdt32_to_cpu(*val);
else
uart->freq = DEFAULT_UART_FREQ;
val = (fdt32_t *)fdt_getprop(fdt, nodeoffset, "current-speed", &len);
if (len > 0 && val)
uart->baud = fdt32_to_cpu(*val);
else
uart->baud = DEFAULT_UART_BAUD;
rc = fdt_parse_uart_node_common(fdt, nodeoffset, uart,
DEFAULT_UART_FREQ,
DEFAULT_UART_BAUD);
if (rc)
return rc;
val = (fdt32_t *)fdt_getprop(fdt, nodeoffset, "reg-shift", &len);
if (len > 0 && val)
@@ -447,6 +406,12 @@ int fdt_parse_uart8250_node(void *fdt, int nodeoffset,
else
uart->reg_io_width = DEFAULT_UART_REG_IO_WIDTH;
val = (fdt32_t *)fdt_getprop(fdt, nodeoffset, "reg-offset", &len);
if (len > 0 && val)
uart->reg_offset = fdt32_to_cpu(*val);
else
uart->reg_offset = DEFAULT_UART_REG_OFFSET;
return 0;
}
@@ -462,7 +427,273 @@ int fdt_parse_uart8250(void *fdt, struct platform_uart_data *uart,
if (nodeoffset < 0)
return nodeoffset;
return fdt_parse_uart8250_node(fdt, nodeoffset, uart);
return fdt_parse_uart_node(fdt, nodeoffset, uart);
}
int fdt_parse_xlnx_uartlite_node(void *fdt, int nodeoffset,
struct platform_uart_data *uart)
{
return fdt_parse_uart_node_common(fdt, nodeoffset, uart, 0, 0);
}
int fdt_parse_aplic_node(void *fdt, int nodeoff, struct aplic_data *aplic)
{
bool child_found;
const fdt32_t *val;
const fdt32_t *del;
struct imsic_data imsic;
int i, j, d, dcnt, len, noff, rc;
uint64_t reg_addr, reg_size;
struct aplic_delegate_data *deleg;
if (nodeoff < 0 || !aplic || !fdt)
return SBI_ENODEV;
memset(aplic, 0, sizeof(*aplic));
rc = fdt_get_node_addr_size(fdt, nodeoff, 0, &reg_addr, &reg_size);
if (rc < 0 || !reg_addr || !reg_size)
return SBI_ENODEV;
aplic->addr = reg_addr;
aplic->size = reg_size;
val = fdt_getprop(fdt, nodeoff, "riscv,num-sources", &len);
if (len > 0)
aplic->num_source = fdt32_to_cpu(*val);
val = fdt_getprop(fdt, nodeoff, "interrupts-extended", &len);
if (val && len > sizeof(fdt32_t)) {
len = len / sizeof(fdt32_t);
for (i = 0; i < len; i += 2) {
if (fdt32_to_cpu(val[i + 1]) == IRQ_M_EXT) {
aplic->targets_mmode = true;
break;
}
}
aplic->num_idc = len / 2;
goto aplic_msi_parent_done;
}
val = fdt_getprop(fdt, nodeoff, "msi-parent", &len);
if (val && len >= sizeof(fdt32_t)) {
noff = fdt_node_offset_by_phandle(fdt, fdt32_to_cpu(*val));
if (noff < 0)
return noff;
rc = fdt_parse_imsic_node(fdt, noff, &imsic);
if (rc)
return rc;
rc = imsic_data_check(&imsic);
if (rc)
return rc;
aplic->targets_mmode = imsic.targets_mmode;
if (imsic.targets_mmode) {
aplic->has_msicfg_mmode = true;
aplic->msicfg_mmode.lhxs = imsic.guest_index_bits;
aplic->msicfg_mmode.lhxw = imsic.hart_index_bits;
aplic->msicfg_mmode.hhxw = imsic.group_index_bits;
aplic->msicfg_mmode.hhxs = imsic.group_index_shift;
if (aplic->msicfg_mmode.hhxs <
(2 * IMSIC_MMIO_PAGE_SHIFT))
return SBI_EINVAL;
aplic->msicfg_mmode.hhxs -= 24;
aplic->msicfg_mmode.base_addr = imsic.regs[0].addr;
} else {
goto aplic_msi_parent_done;
}
val = fdt_getprop(fdt, nodeoff, "riscv,children", &len);
if (!val || len < sizeof(fdt32_t))
goto aplic_msi_parent_done;
noff = fdt_node_offset_by_phandle(fdt, fdt32_to_cpu(*val));
if (noff < 0)
return noff;
val = fdt_getprop(fdt, noff, "msi-parent", &len);
if (!val || len < sizeof(fdt32_t))
goto aplic_msi_parent_done;
noff = fdt_node_offset_by_phandle(fdt, fdt32_to_cpu(*val));
if (noff < 0)
return noff;
rc = fdt_parse_imsic_node(fdt, noff, &imsic);
if (rc)
return rc;
rc = imsic_data_check(&imsic);
if (rc)
return rc;
if (!imsic.targets_mmode) {
aplic->has_msicfg_smode = true;
aplic->msicfg_smode.lhxs = imsic.guest_index_bits;
aplic->msicfg_smode.lhxw = imsic.hart_index_bits;
aplic->msicfg_smode.hhxw = imsic.group_index_bits;
aplic->msicfg_smode.hhxs = imsic.group_index_shift;
if (aplic->msicfg_smode.hhxs <
(2 * IMSIC_MMIO_PAGE_SHIFT))
return SBI_EINVAL;
aplic->msicfg_smode.hhxs -= 24;
aplic->msicfg_smode.base_addr = imsic.regs[0].addr;
}
}
aplic_msi_parent_done:
for (d = 0; d < APLIC_MAX_DELEGATE; d++) {
deleg = &aplic->delegate[d];
deleg->first_irq = 0;
deleg->last_irq = 0;
deleg->child_index = 0;
}
del = fdt_getprop(fdt, nodeoff, "riscv,delegate", &len);
if (!del || len < (3 * sizeof(fdt32_t)))
goto skip_delegate_parse;
d = 0;
dcnt = len / sizeof(fdt32_t);
for (i = 0; i < dcnt; i += 3) {
if (d >= APLIC_MAX_DELEGATE)
break;
deleg = &aplic->delegate[d];
deleg->first_irq = fdt32_to_cpu(del[i + 1]);
deleg->last_irq = fdt32_to_cpu(del[i + 2]);
deleg->child_index = 0;
child_found = false;
val = fdt_getprop(fdt, nodeoff, "riscv,children", &len);
if (!val || len < sizeof(fdt32_t)) {
deleg->first_irq = 0;
deleg->last_irq = 0;
deleg->child_index = 0;
continue;
}
len = len / sizeof(fdt32_t);
for (j = 0; j < len; j++) {
if (del[i] != val[j])
continue;
deleg->child_index = j;
child_found = true;
break;
}
if (child_found) {
d++;
} else {
deleg->first_irq = 0;
deleg->last_irq = 0;
deleg->child_index = 0;
}
}
skip_delegate_parse:
return 0;
}
bool fdt_check_imsic_mlevel(void *fdt)
{
const fdt32_t *val;
int i, len, noff = 0;
if (!fdt)
return false;
while ((noff = fdt_node_offset_by_compatible(fdt, noff,
"riscv,imsics")) >= 0) {
val = fdt_getprop(fdt, noff, "interrupts-extended", &len);
if (val && len > sizeof(fdt32_t)) {
len = len / sizeof(fdt32_t);
for (i = 0; i < len; i += 2) {
if (fdt32_to_cpu(val[i + 1]) == IRQ_M_EXT)
return true;
}
}
}
return false;
}
int fdt_parse_imsic_node(void *fdt, int nodeoff, struct imsic_data *imsic)
{
const fdt32_t *val;
struct imsic_regs *regs;
uint64_t reg_addr, reg_size;
int i, rc, len, nr_parent_irqs;
if (nodeoff < 0 || !imsic || !fdt)
return SBI_ENODEV;
imsic->targets_mmode = false;
val = fdt_getprop(fdt, nodeoff, "interrupts-extended", &len);
if (val && len > sizeof(fdt32_t)) {
len = len / sizeof(fdt32_t);
nr_parent_irqs = len / 2;
for (i = 0; i < len; i += 2) {
if (fdt32_to_cpu(val[i + 1]) == IRQ_M_EXT) {
imsic->targets_mmode = true;
break;
}
}
} else
return SBI_EINVAL;
val = fdt_getprop(fdt, nodeoff, "riscv,guest-index-bits", &len);
if (val && len > 0)
imsic->guest_index_bits = fdt32_to_cpu(*val);
else
imsic->guest_index_bits = 0;
val = fdt_getprop(fdt, nodeoff, "riscv,hart-index-bits", &len);
if (val && len > 0) {
imsic->hart_index_bits = fdt32_to_cpu(*val);
} else {
imsic->hart_index_bits = sbi_fls(nr_parent_irqs);
if ((1UL << imsic->hart_index_bits) < nr_parent_irqs)
imsic->hart_index_bits++;
}
val = fdt_getprop(fdt, nodeoff, "riscv,group-index-bits", &len);
if (val && len > 0)
imsic->group_index_bits = fdt32_to_cpu(*val);
else
imsic->group_index_bits = 0;
val = fdt_getprop(fdt, nodeoff, "riscv,group-index-shift", &len);
if (val && len > 0)
imsic->group_index_shift = fdt32_to_cpu(*val);
else
imsic->group_index_shift = 2 * IMSIC_MMIO_PAGE_SHIFT;
val = fdt_getprop(fdt, nodeoff, "riscv,num-ids", &len);
if (val && len > 0)
imsic->num_ids = fdt32_to_cpu(*val);
else
return SBI_EINVAL;
for (i = 0; i < IMSIC_MAX_REGS; i++) {
regs = &imsic->regs[i];
regs->addr = 0;
regs->size = 0;
}
for (i = 0; i < (IMSIC_MAX_REGS - 1); i++) {
regs = &imsic->regs[i];
rc = fdt_get_node_addr_size(fdt, nodeoff, i,
&reg_addr, &reg_size);
if (rc < 0 || !reg_addr || !reg_size)
break;
regs->addr = reg_addr;
regs->size = reg_size;
};
if (!imsic->regs[0].size)
return SBI_EINVAL;
return 0;
}
int fdt_parse_plic_node(void *fdt, int nodeoffset, struct plic_data *plic)
@@ -552,7 +783,7 @@ int fdt_parse_aclint_node(void *fdt, int nodeoffset, bool for_timer,
continue;
cpu_offset = fdt_parent_offset(fdt, cpu_intc_offset);
if (cpu_intc_offset < 0)
if (cpu_offset < 0)
continue;
rc = fdt_parse_hart_id(fdt, cpu_offset, &hartid);
@@ -580,6 +811,118 @@ int fdt_parse_aclint_node(void *fdt, int nodeoffset, bool for_timer,
return 0;
}
int fdt_parse_plmt_node(void *fdt, int nodeoffset, unsigned long *plmt_base,
unsigned long *plmt_size, u32 *hart_count)
{
const fdt32_t *val;
int rc, i, count;
uint64_t reg_addr, reg_size;
u32 phandle, hwirq, hartid, hcount;
if (nodeoffset < 0 || !fdt || !plmt_base ||
!hart_count || !plmt_size)
return SBI_EINVAL;
rc = fdt_get_node_addr_size(fdt, nodeoffset, 0,
&reg_addr, &reg_size);
if (rc < 0)
return SBI_ENODEV;
*plmt_base = reg_addr;
*plmt_size = reg_size;
val = fdt_getprop(fdt, nodeoffset, "interrupts-extended", &count);
if (!val || count < sizeof(fdt32_t))
return 0;
count = count / sizeof(fdt32_t);
hcount = 0;
for (i = 0; i < (count / 2); i++) {
int cpu_offset, cpu_intc_offset;
phandle = fdt32_to_cpu(val[2 * i]);
hwirq = fdt32_to_cpu(val[2 * i + 1]);
cpu_intc_offset = fdt_node_offset_by_phandle(fdt, phandle);
if (cpu_intc_offset < 0)
continue;
cpu_offset = fdt_parent_offset(fdt, cpu_intc_offset);
if (cpu_offset < 0)
continue;
rc = fdt_parse_hart_id(fdt, cpu_offset, &hartid);
if (rc)
continue;
if (SBI_HARTMASK_MAX_BITS <= hartid)
continue;
if (hwirq == IRQ_M_TIMER)
hcount++;
}
*hart_count = hcount;
return 0;
}
int fdt_parse_plicsw_node(void *fdt, int nodeoffset, unsigned long *plicsw_base,
unsigned long *size, u32 *hart_count)
{
const fdt32_t *val;
int rc, i, count;
uint64_t reg_addr, reg_size;
u32 phandle, hwirq, hartid, hcount;
if (nodeoffset < 0 || !fdt || !plicsw_base ||
!hart_count || !size)
return SBI_EINVAL;
rc = fdt_get_node_addr_size(fdt, nodeoffset, 0,
&reg_addr, &reg_size);
if (rc < 0)
return SBI_ENODEV;
*plicsw_base = reg_addr;
*size = reg_size;
val = fdt_getprop(fdt, nodeoffset, "interrupts-extended", &count);
if (!val || count < sizeof(fdt32_t))
return 0;
count = count / sizeof(fdt32_t);
hcount = 0;
for (i = 0; i < (count / 2); i++) {
int cpu_offset, cpu_intc_offset;
phandle = fdt32_to_cpu(val[2 * i]);
hwirq = fdt32_to_cpu(val[2 * i + 1]);
cpu_intc_offset = fdt_node_offset_by_phandle(fdt, phandle);
if (cpu_intc_offset < 0)
continue;
cpu_offset = fdt_parent_offset(fdt, cpu_intc_offset);
if (cpu_offset < 0)
continue;
rc = fdt_parse_hart_id(fdt, cpu_offset, &hartid);
if (rc)
continue;
if (SBI_HARTMASK_MAX_BITS <= hartid)
continue;
if (hwirq == IRQ_M_SOFT)
hcount++;
}
*hart_count = hcount;
return 0;
}
int fdt_parse_compat_addr(void *fdt, uint64_t *addr,
const char *compatible)
{

View File

@@ -53,7 +53,7 @@ int fdt_pmu_fixup(void *fdt)
fdt_delprop(fdt, pmu_offset, "riscv,event-to-mhpmcounters");
fdt_delprop(fdt, pmu_offset, "riscv,event-to-mhpmevent");
fdt_delprop(fdt, pmu_offset, "riscv,raw-event-to-mhpmcounters");
if (!sbi_hart_has_feature(scratch, SBI_HART_HAS_SSCOFPMF))
if (!sbi_hart_has_extension(scratch, SBI_HART_EXT_SSCOFPMF))
fdt_delprop(fdt, pmu_offset, "interrupts-extended");
return 0;
@@ -75,42 +75,52 @@ int fdt_pmu_setup(void *fdt)
if (pmu_offset < 0)
return SBI_EFAIL;
event_ctr_map = fdt_getprop(fdt, pmu_offset, "riscv,event-to-mhpmcounters", &len);
if (!event_ctr_map || len < 8)
return SBI_EFAIL;
len = len / (sizeof(u32) * 3);
for (i = 0; i < len; i++) {
event_idx_start = fdt32_to_cpu(event_ctr_map[3 * i]);
event_idx_end = fdt32_to_cpu(event_ctr_map[3 * i + 1]);
ctr_map = fdt32_to_cpu(event_ctr_map[3 * i + 2]);
sbi_pmu_add_hw_event_counter_map(event_idx_start, event_idx_end, ctr_map);
event_ctr_map = fdt_getprop(fdt, pmu_offset,
"riscv,event-to-mhpmcounters", &len);
if (event_ctr_map && len >= 8) {
len = len / (sizeof(u32) * 3);
for (i = 0; i < len; i++) {
event_idx_start = fdt32_to_cpu(event_ctr_map[3 * i]);
event_idx_end = fdt32_to_cpu(event_ctr_map[3 * i + 1]);
ctr_map = fdt32_to_cpu(event_ctr_map[3 * i + 2]);
result = sbi_pmu_add_hw_event_counter_map(
event_idx_start, event_idx_end, ctr_map);
if (result)
return result;
}
}
event_val = fdt_getprop(fdt, pmu_offset, "riscv,event-to-mhpmevent", &len);
if (!event_val || len < 8)
return SBI_EFAIL;
len = len / (sizeof(u32) * 3);
for (i = 0; i < len; i++) {
event = &fdt_pmu_evt_select[hw_event_count];
event->eidx = fdt32_to_cpu(event_val[3 * i]);
event->select = fdt32_to_cpu(event_val[3 * i + 1]);
event->select = (event->select << 32) | fdt32_to_cpu(event_val[3 * i + 2]);
hw_event_count++;
}
event_val = fdt_getprop(fdt, pmu_offset, "riscv,raw-event-to-mhpmcounters", &len);
if (!event_val || len < 20)
return SBI_EFAIL;
len = len / (sizeof(u32) * 5);
for (i = 0; i < len; i++) {
raw_selector = fdt32_to_cpu(event_val[5 * i]);
raw_selector = (raw_selector << 32) | fdt32_to_cpu(event_val[5 * i + 1]);
select_mask = fdt32_to_cpu(event_val[5 * i + 2]);
select_mask = (select_mask << 32) | fdt32_to_cpu(event_val[5 * i + 3]);
ctr_map = fdt32_to_cpu(event_val[5 * i + 4]);
result = sbi_pmu_add_raw_event_counter_map(raw_selector, select_mask, ctr_map);
if (!result)
event_val = fdt_getprop(fdt, pmu_offset,
"riscv,event-to-mhpmevent", &len);
if (event_val && len >= 8) {
len = len / (sizeof(u32) * 3);
for (i = 0; i < len; i++) {
event = &fdt_pmu_evt_select[hw_event_count];
event->eidx = fdt32_to_cpu(event_val[3 * i]);
event->select = fdt32_to_cpu(event_val[3 * i + 1]);
event->select = (event->select << 32) |
fdt32_to_cpu(event_val[3 * i + 2]);
hw_event_count++;
}
}
event_val = fdt_getprop(fdt, pmu_offset,
"riscv,raw-event-to-mhpmcounters", &len);
if (event_val && len >= 20) {
len = len / (sizeof(u32) * 5);
for (i = 0; i < len; i++) {
raw_selector = fdt32_to_cpu(event_val[5 * i]);
raw_selector = (raw_selector << 32) |
fdt32_to_cpu(event_val[5 * i + 1]);
select_mask = fdt32_to_cpu(event_val[5 * i + 2]);
select_mask = (select_mask << 32) |
fdt32_to_cpu(event_val[5 * i + 3]);
ctr_map = fdt32_to_cpu(event_val[5 * i + 4]);
result = sbi_pmu_add_raw_event_counter_map(
raw_selector, select_mask, ctr_map);
if (result)
return result;
}
}
return 0;

View File

@@ -4,7 +4,7 @@
# Copyright (C) 2020 Bin Meng <bmeng.cn@gmail.com>
#
libsbiutils-objs-y += fdt/fdt_domain.o
libsbiutils-objs-y += fdt/fdt_pmu.o
libsbiutils-objs-y += fdt/fdt_helper.o
libsbiutils-objs-y += fdt/fdt_fixup.o
libsbiutils-objs-$(CONFIG_FDT_DOMAIN) += fdt/fdt_domain.o
libsbiutils-objs-$(CONFIG_FDT_PMU) += fdt/fdt_pmu.o
libsbiutils-objs-$(CONFIG_FDT) += fdt/fdt_helper.o
libsbiutils-objs-$(CONFIG_FDT) += fdt/fdt_fixup.o

23
lib/utils/gpio/Kconfig Normal file
View File

@@ -0,0 +1,23 @@
# SPDX-License-Identifier: BSD-2-Clause
menu "GPIO Support"
config FDT_GPIO
bool "FDT based GPIO drivers"
depends on FDT
select GPIO
default n
if FDT_GPIO
config FDT_GPIO_SIFIVE
bool "SiFive GPIO FDT driver"
default n
endif
config GPIO
bool "GPIO support"
default n
endmenu

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