26 Commits

Author SHA1 Message Date
Chao Wei
adc7ba17f3 Fixbug, compile error without debug option
Signed-off-by: Chao Wei <chao.wei@sophgo.com>
2025-11-06 14:25:59 +08:00
Chao Wei
6eef399cfc SG2042: add virtual global timer device driver
Add a virtual global timer device driver. It uses a global timer
register as timer counter, and it uses mtimecmp CSR of clint as
interrupt source.
Using this virtul timer resolves dual way timer sync issue.
On dual way system, we should enable this driver and on single way
system, we should use standard risc-v clint timer.

1. Add a virtual global timer device driver, it is probed by fdt

	sg2042-global-mtimer@70300101c0 {
		compatible = "sophgo,sg2042-global-mtimer";
		reg = < 0x00000070 0x300101c0 0x00000000 0x00000008
			0x00000070 0xac000000 0x00000000 0x00200000>;
		clock-frequency = <50000000 50000000>;
	};

Its compatible should be "sophgo,sg2042-global-mtimer".
And the first region delcared in reg prop is the address of global
timer. The second region delcared in reg prop is the base of clint
timers.
The first clock in clock-frequency is the actual frequency of global
timer, the second clock is the actual frequency of clint timer.

2. Add a quirk in platform specific code.
Add a function sbi_platform_force_emulate_time_csr, it indicates if
opensbi should skip time CSR detection and make software in
supervisor and user mode use emulated time CSR.

Signed-off-by: Chao Wei <chao.wei@sophgo.com>
2025-10-14 17:54:32 +08:00
Chao Wei
506f47f9fa fixbug, syntax error on gcc15
Signed-off-by: Chao Wei <chao.wei@sophgo.com>
2025-07-30 10:12:31 +08:00
Inochi Amaoto
3745939ceb lib: ipi/timer: in favor of upstream linux settings
Signed-off-by: Inochi Amaoto <inochiama@outlook.com>
2023-09-25 10:51:41 +08:00
haijiao.liu
44fdaafcb4 platform: generic: allwinner: Clear the overflow generated during the deletion process
Signed-off-by: haijiao.liu <haijiao.liu@sophgo.com>
2023-08-15 17:23:02 +08:00
Xiang W
a82a033c74 fix hart_stack_size change 2023-08-15 11:46:23 +08:00
haijiao.liu
270f27b81b platform: generic: allwinner: fix OV process for T-HEAD
T-HEAD c9xx pmu only needs to clear OV bits of MCOUNTEROF when MOIP bit
of MIP is set, so correct the MIP value check to avoid race conditions
during processing interrupt.

In addition, the S-mode scounterof only have OV bit set when the related
bits of MCOUNTERWEN is set, so also configure MCOUNTERWEN to allow kernel
to access valid SCOUNTEROF.

Signed-off-by: haijiao.liu <haijiao.liu@sophgo.com>
2023-08-14 10:45:04 +08:00
haijiao.liu
f89d688f60 lib: sbi_pmu: ensure update hpm counter before starting
When detecting features of PMU, the hpm counter may be written to some
value, this will cause some unexpected behavior in some cases. So ensure
the hpm counter is updated before starting the counter.

Signed-off-by: haijiao.liu <haijiao.liu@sophgo.com>
2023-08-14 10:45:04 +08:00
haijiao.liu@sophgo.com
4826e4f743 SG2042: spinlock: Fix deadlock issue
This problem was found on sg2042 server platform with the litmus test.

This patch is based on Guo Ren's patch [1].

[1] c53925298d

riscv: qspinlock: errata: Add ERRATA_THEAD_WRITE_ONCE fixup
The early version of T-Head C9xx cores has a store merge buffer
delay problem. The store merge buffer could improve the store queue
performance by merging multi-store requests, but when there are not
continued store requests, the prior single store request would be
waiting in the store queue for a long time. That would cause
significant problems for communication between multi-cores. This
problem was found on sg2042 & th1520 platforms with the qspinlock
lock torture test.

So appending a fence w.o could immediately flush the store merge
buffer and let other cores see the write result.

This will apply the WRITE_ONCE errata to handle the non-standard
behavior via appending a fence w.o instruction for WRITE_ONCE().

Signed-off-by: haijiao.liu@sophgo.com <haijiao.liu@sophgo.com>
2023-08-09 18:36:18 +08:00
chunzhi.lin
d06c0a7858 lib:utils:support pisces's system reboot
pisces system reboot will ecall gpio chip but not watchdog, and pull up cpu gpio5 to tell
CPLD. CPLD will help for cold reboot.
Add the function, gpio chip will pull up gpio16 after chip is probed.

Signed-off-by: chunzhi.lin <chunzhi.lin@sophgo.com>
2023-06-29 14:02:49 +08:00
chunzhi.lin
d21bf89240 lib:utils:add reset and gpio device 2023-06-25 14:15:01 +08:00
haijiao.liu@sophgo.com
9af30e56df Fix system cannot boot when the some CPU status is set to disabled 2023-06-14 18:10:10 +08:00
xiaoguang.xing
d0b705e19c platform:generic:sophgo: Allow the harts of chip0 as cold boot hart 2023-06-10 10:49:27 +08:00
haijiao.liu@sophgo.com
546bc50f9a set tlb fifo entry number to 128 2023-06-07 16:52:52 +08:00
haijiao.liu@sophgo.com
4aab6f3263 set scratch and stack size to 8K 2023-06-07 16:52:52 +08:00
xiaoguang.xing
e1d3b68eeb barrier: add more stronger constraint 2023-05-29 10:00:22 +08:00
xiaoguang.xing
19622b6c93 platform: generic: sophgo: add cold_boot_allowed callback 2023-05-23 16:44:43 +08:00
chunzhi.lin
60142dc80c util:reset:mango-reset device support to X4 and milkv 2023-04-23 14:05:41 +08:00
chunzhi.lin
31087f36d7 lib:utils:delete mango-reset device node after register it 2023-04-13 11:13:19 +08:00
Chao Wei
58f9b858c5 lib: sbi_trap: optimize i-utlb workaround speed 2023-04-11 17:25:23 +08:00
xiaoguang.xing
be6e558f66 lib: sbi_trap: Workaroud for cpu still using i-utlb when into m mode 2023-04-04 17:17:46 +08:00
xiaoguang.xing
0e87f899c3 lib:sbi_tlb: Increase tlb fifo entry number
When tlb fifo is full, it takes more fails.
This makes lots of lock contention and
consumes much cpu time in sbi.
2023-03-29 10:12:01 +08:00
chunzhi.lin
0b5c942ee9 lib:utils:add sophgo-mcu, power management device 2023-03-20 21:29:01 +08:00
Inochi Amaoto
64fb41e927 lib: sbi_trap: change flush tlb in all cases
As flush tlb in interrupt and mode switch is not enough. Flush tlb
in all cases.

Signed-off-by: Inochi Amaoto <inochiama@outlook.com>
2023-03-19 08:20:10 +08:00
xiaoguang.xing
b210bc000c lib: sbi: Optimize sbi_tlb and sbi_ipi
This patch comes from:
[PATCH v4 0/4] Miscellaneous about sbi_tlb and sbi_ipi
http://lists.infradead.org/pipermail/opensbi/2023-February/004402.html
2023-03-18 18:43:21 +08:00
Inochi Amaoto
35fb234d39 platform: generic: sophgo: add mango soc support
The mango cpu of sophgo is a 64 cores C920 CPU. The board with mango can
have at most two sockets. The CPU have the following features:

 1) support RV64GCV
 2) one seperate timer each cluster
 3) T-HEAD pmu device

Signed-off-by: Inochi Amaoto <inochiama@outlook.com>
2023-03-18 18:42:09 +08:00
195 changed files with 3590 additions and 5377 deletions

8
.gitignore vendored
View File

@@ -1,10 +1,3 @@
# ignore anything begin with dot
.*
# exceptions we need even begin with dot
!.clang-format
!.gitignore
# Object files
*.o
*.a
@@ -17,3 +10,4 @@ install/
# Development friendly files
tags
cscope*
*.swp

View File

@@ -168,7 +168,7 @@ endif
OPENSBI_LD_PIE := $(shell $(CC) $(CLANG_TARGET) $(RELAX_FLAG) $(USE_LD_FLAG) -fPIE -nostdlib -Wl,-pie -x c /dev/null -o /dev/null >/dev/null 2>&1 && echo y || echo n)
# 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 -e "-save-restore" >/dev/null && echo n || echo y)
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)
@@ -375,7 +375,6 @@ ASFLAGS += $(firmware-asflags-y)
ARFLAGS = rcs
ELFFLAGS += $(USE_LD_FLAG)
ELFFLAGS += -Wl,--exclude-libs,ALL
ELFFLAGS += -Wl,--build-id=none
ELFFLAGS += $(platform-ldflags-y)
ELFFLAGS += $(firmware-ldflags-y)
@@ -402,10 +401,10 @@ merge_deps = $(CMD_PREFIX)mkdir -p `dirname $(1)`; \
cat $(2) > $(1)
copy_file = $(CMD_PREFIX)mkdir -p `dirname $(1)`; \
echo " COPY $(subst $(build_dir)/,,$(1))"; \
cp -L -f $(2) $(1)
cp -f $(2) $(1)
inst_file = $(CMD_PREFIX)mkdir -p `dirname $(1)`; \
echo " INSTALL $(subst $(install_root_dir)/,,$(1))"; \
cp -L -f $(2) $(1)
cp -f $(2) $(1)
inst_file_list = $(CMD_PREFIX)if [ ! -z "$(4)" ]; then \
mkdir -p $(1)/$(3); \
for file in $(4) ; do \
@@ -414,12 +413,12 @@ inst_file_list = $(CMD_PREFIX)if [ ! -z "$(4)" ]; then \
dest_dir=`dirname $$dest_file`; \
echo " INSTALL "$(3)"/"`echo $$rel_file`; \
mkdir -p $$dest_dir; \
cp -L -f $$file $$dest_file; \
cp -f $$file $$dest_file; \
done \
fi
inst_header_dir = $(CMD_PREFIX)mkdir -p $(1); \
echo " INSTALL $(subst $(install_root_dir)/,,$(1))"; \
cp -L -rf $(2) $(1)
cp -rf $(2) $(1)
compile_cpp_dep = $(CMD_PREFIX)mkdir -p `dirname $(1)`; \
echo " CPP-DEP $(subst $(build_dir)/,,$(1))"; \
printf %s `dirname $(1)`/ > $(1) && \

View File

@@ -1,15 +1,11 @@
RISC-V Open Source Supervisor Binary Interface (OpenSBI)
========================================================
![RISC-V OpenSBI](docs/riscv_opensbi_logo_final_color.png)
Copyright and License
---------------------
The OpenSBI project is:
* Copyright (c) 2019 Western Digital Corporation or its affiliates
* Copyright (c) 2023 RISC-V International
The OpenSBI project is copyright (c) 2019 Western Digital Corporation
or its affiliates and other contributors.
It is distributed under the terms of the BSD 2-clause license
("Simplified BSD License" or "FreeBSD License", SPDX: *BSD-2-Clause*).

View File

@@ -43,18 +43,18 @@ follows:
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 (e.g., using bash or zsh):
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` > (FW_JUMP_FDT_ADDR - FW_JUMP_ADDR) )) &&
echo fdt overlaps kernel, increase FW_JUMP_FDT_ADDR
${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` > (FW_JUMP_FDT_ADDR - FW_JUMP_ADDR) )) &&
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

@@ -36,7 +36,7 @@ options. These configuration parameters can be defined using either the top
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_START* where the payload binary
* **FW_PAYLOAD_OFFSET** - Offset from *FW_TEXT_BASE* where the payload binary
will be linked in the final *FW_PAYLOAD* firmware binary image. This
configuration parameter is mandatory if *FW_PAYLOAD_ALIGN* is not defined.
Compilation errors will result from an incorrect definition of

View File

@@ -1,7 +1,7 @@
T-HEAD C9xx Series Processors
=============================
The C9xx series processors are high-performance RISC-V architecture
The **C9xx** series processors are high-performance RISC-V architecture
multi-core processors with AI vector acceleration engine.
For more details, refer [T-HEAD.CN](https://www.t-head.cn/)
@@ -12,16 +12,185 @@ To build the platform-specific library and firmware images, provide the
Platform Options
----------------
The T-HEAD C9xx does not have any platform-specific compile options
The *T-HEAD C9xx* does not have any platform-specific compile options
because it uses generic platform.
```
CROSS_COMPILE=riscv64-linux-gnu- PLATFORM=generic make
CROSS_COMPILE=riscv64-linux-gnu- PLATFORM=generic /usr/bin/make
```
Here is the simplest boot flow for a fpga prototype:
The *T-HEAD C9xx* DTB provided to OpenSBI generic firmwares will usually have
"riscv,clint0", "riscv,plic0", "thead,reset-sample" compatible strings.
(Jtag gdbinit) -> (zsb) -> (opensbi) -> (linux)
DTS Example1: (Single core, eg: Allwinner D1 - c906)
----------------------------------------------------
For more details, refer:
[zero stage boot](https://github.com/c-sky/zero_stage_boot)
```
cpus {
#address-cells = <1>;
#size-cells = <0>;
timebase-frequency = <3000000>;
cpu@0 {
device_type = "cpu";
reg = <0>;
status = "okay";
compatible = "riscv";
riscv,isa = "rv64imafdcv";
mmu-type = "riscv,sv39";
cpu0_intc: interrupt-controller {
#interrupt-cells = <1>;
compatible = "riscv,cpu-intc";
interrupt-controller;
};
};
};
soc {
#address-cells = <2>;
#size-cells = <2>;
compatible = "simple-bus";
ranges;
clint0: clint@14000000 {
compatible = "allwinner,sun20i-d1-clint";
interrupts-extended = <
&cpu0_intc 3 &cpu0_intc 7
>;
reg = <0x0 0x14000000 0x0 0x04000000>;
};
intc: interrupt-controller@10000000 {
#interrupt-cells = <1>;
compatible = "allwinner,sun20i-d1-plic",
"thead,c900-plic";
interrupt-controller;
interrupts-extended = <
&cpu0_intc 0xffffffff &cpu0_intc 9
>;
reg = <0x0 0x10000000 0x0 0x04000000>;
reg-names = "control";
riscv,max-priority = <7>;
riscv,ndev = <200>;
};
}
```
DTS Example2: (Multi cores with soc reset-regs)
-----------------------------------------------
```
cpus {
#address-cells = <1>;
#size-cells = <0>;
timebase-frequency = <3000000>;
cpu@0 {
device_type = "cpu";
reg = <0>;
status = "okay";
compatible = "riscv";
riscv,isa = "rv64imafdc";
mmu-type = "riscv,sv39";
cpu0_intc: interrupt-controller {
#interrupt-cells = <1>;
compatible = "riscv,cpu-intc";
interrupt-controller;
};
};
cpu@1 {
device_type = "cpu";
reg = <1>;
status = "fail";
compatible = "riscv";
riscv,isa = "rv64imafdc";
mmu-type = "riscv,sv39";
cpu1_intc: interrupt-controller {
#interrupt-cells = <1>;
compatible = "riscv,cpu-intc";
interrupt-controller;
};
};
cpu@2 {
device_type = "cpu";
reg = <2>;
status = "fail";
compatible = "riscv";
riscv,isa = "rv64imafdc";
mmu-type = "riscv,sv39";
cpu2_intc: interrupt-controller {
#interrupt-cells = <1>;
compatible = "riscv,cpu-intc";
interrupt-controller;
};
};
cpu@3 {
device_type = "cpu";
reg = <3>;
status = "fail";
compatible = "riscv";
riscv,isa = "rv64imafdc";
mmu-type = "riscv,sv39";
cpu3_intc: interrupt-controller {
#interrupt-cells = <1>;
compatible = "riscv,cpu-intc";
interrupt-controller;
};
};
};
soc {
#address-cells = <2>;
#size-cells = <2>;
compatible = "simple-bus";
ranges;
reset: reset-sample {
compatible = "thead,reset-sample";
entry-reg = <0xff 0xff019050>;
entry-cnt = <4>;
control-reg = <0xff 0xff015004>;
control-val = <0x1c>;
csr-copy = <0x7f3 0x7c0 0x7c1 0x7c2 0x7c3 0x7c5 0x7cc>;
};
clint0: clint@ffdc000000 {
compatible = "riscv,clint0";
interrupts-extended = <
&cpu0_intc 3 &cpu0_intc 7
&cpu1_intc 3 &cpu1_intc 7
&cpu2_intc 3 &cpu2_intc 7
&cpu3_intc 3 &cpu3_intc 7
&cpu4_intc 3 &cpu4_intc 7
>;
reg = <0xff 0xdc000000 0x0 0x04000000>;
};
intc: interrupt-controller@ffd8000000 {
#interrupt-cells = <1>;
compatible = "thead,c900-plic";
interrupt-controller;
interrupts-extended = <
&cpu0_intc 0xffffffff &cpu0_intc 9
&cpu1_intc 0xffffffff &cpu1_intc 9
&cpu2_intc 0xffffffff &cpu2_intc 9
&cpu3_intc 0xffffffff &cpu3_intc 9
>;
reg = <0xff 0xd8000000 0x0 0x04000000>;
reg-names = "control";
riscv,max-priority = <7>;
riscv,ndev = <80>;
};
}
```
DTS Example2: (Multi cores with old reset csrs)
-----------------------------------------------
```
reset: reset-sample {
compatible = "thead,reset-sample";
using-csr-reset;
csr-copy = <0x7c0 0x7c1 0x7c2 0x7c3 0x7c5 0x7cc
0x3b0 0x3b1 0x3b2 0x3b3
0x3b4 0x3b5 0x3b6 0x3b7
0x3a0>;
};
```

View File

@@ -18,7 +18,7 @@ Base Platform Requirements
The base RISC-V platform requirements for OpenSBI are as follows:
1. At least rv32ima_zicsr or rv64ima_zicsr required on all HARTs
1. At least rv32ima or rv64ima required on all HARTs
2. At least one HART should have S-mode support because:
* SBI calls are meant for RISC-V S-mode (Supervisor mode)
@@ -33,7 +33,7 @@ The base RISC-V platform requirements for OpenSBI are as follows:
6. Hardware support for injecting M-mode software interrupts on
a multi-HART platform
The RISC-V extensions not covered by rv32ima_zicsr or rv64ima_zicsr are optional
The RISC-V extensions not covered by rv32ima or rv64ima are optional
for OpenSBI. Although, OpenSBI will detect and handle some of these
optional RISC-V extensions at runtime.

View File

@@ -125,85 +125,3 @@ pmu {
<0x0 0x2 0xffffffff 0xffffe0ff 0x18>;
};
```
### Example 3
```
/*
* For Andes 45-series platforms. The encodings can be found in the
* "Machine Performance Monitoring Event Selector" section
* http://www.andestech.com/wp-content/uploads/AX45MP-1C-Rev.-5.0.0-Datasheet.pdf
*/
pmu {
compatible = "riscv,pmu";
riscv,event-to-mhpmevent =
<0x1 0x0000 0x10>, /* CPU_CYCLES -> Cycle count */
<0x2 0x0000 0x20>, /* INSTRUCTIONS -> Retired instruction count */
<0x3 0x0000 0x41>, /* CACHE_REFERENCES -> D-Cache access */
<0x4 0x0000 0x51>, /* CACHE_MISSES -> D-Cache miss */
<0x5 0x0000 0x80>, /* BRANCH_INSTRUCTIONS -> Conditional branch instruction count */
<0x6 0x0000 0x02>, /* BRANCH_MISSES -> Misprediction of conditional branches */
<0x10000 0x0000 0x61>, /* L1D_READ_ACCESS -> D-Cache load access */
<0x10001 0x0000 0x71>, /* L1D_READ_MISS -> D-Cache load miss */
<0x10002 0x0000 0x81>, /* L1D_WRITE_ACCESS -> D-Cache store access */
<0x10003 0x0000 0x91>, /* L1D_WRITE_MISS -> D-Cache store miss */
<0x10008 0x0000 0x21>, /* L1I_READ_ACCESS -> I-Cache access */
<0x10009 0x0000 0x31>; /* L1I_READ_MISS -> I-Cache miss */
riscv,event-to-mhpmcounters = <0x1 0x6 0x78>,
<0x10000 0x10003 0x78>,
<0x10008 0x10009 0x78>;
riscv,raw-event-to-mhpmcounters =
<0x0 0x10 0xffffffff 0xffffffff 0x78>, /* Cycle count */
<0x0 0x20 0xffffffff 0xffffffff 0x78>, /* Retired instruction count */
<0x0 0x30 0xffffffff 0xffffffff 0x78>, /* Integer load instruction count */
<0x0 0x40 0xffffffff 0xffffffff 0x78>, /* Integer store instruction count */
<0x0 0x50 0xffffffff 0xffffffff 0x78>, /* Atomic instruction count */
<0x0 0x60 0xffffffff 0xffffffff 0x78>, /* System instruction count */
<0x0 0x70 0xffffffff 0xffffffff 0x78>, /* Integer computational instruction count */
<0x0 0x80 0xffffffff 0xffffffff 0x78>, /* Conditional branch instruction count */
<0x0 0x90 0xffffffff 0xffffffff 0x78>, /* Taken conditional branch instruction count */
<0x0 0xA0 0xffffffff 0xffffffff 0x78>, /* JAL instruction count */
<0x0 0xB0 0xffffffff 0xffffffff 0x78>, /* JALR instruction count */
<0x0 0xC0 0xffffffff 0xffffffff 0x78>, /* Return instruction count */
<0x0 0xD0 0xffffffff 0xffffffff 0x78>, /* Control transfer instruction count */
<0x0 0xE0 0xffffffff 0xffffffff 0x78>, /* EXEC.IT instruction count */
<0x0 0xF0 0xffffffff 0xffffffff 0x78>, /* Integer multiplication instruction count */
<0x0 0x100 0xffffffff 0xffffffff 0x78>, /* Integer division instruction count */
<0x0 0x110 0xffffffff 0xffffffff 0x78>, /* Floating-point load instruction count */
<0x0 0x120 0xffffffff 0xffffffff 0x78>, /* Floating-point store instruction count */
<0x0 0x130 0xffffffff 0xffffffff 0x78>, /* Floating-point addition/subtraction instruction count */
<0x0 0x140 0xffffffff 0xffffffff 0x78>, /* Floating-point multiplication instruction count */
<0x0 0x150 0xffffffff 0xffffffff 0x78>, /* Floating-point fused multiply-add instruction count */
<0x0 0x160 0xffffffff 0xffffffff 0x78>, /* Floating-point division or square-root instruction count */
<0x0 0x170 0xffffffff 0xffffffff 0x78>, /* Other floating-point instruction count */
<0x0 0x180 0xffffffff 0xffffffff 0x78>, /* Integer multiplication and add/sub instruction count */
<0x0 0x190 0xffffffff 0xffffffff 0x78>, /* Retired operation count */
<0x0 0x01 0xffffffff 0xffffffff 0x78>, /* ILM access */
<0x0 0x11 0xffffffff 0xffffffff 0x78>, /* DLM access */
<0x0 0x21 0xffffffff 0xffffffff 0x78>, /* I-Cache access */
<0x0 0x31 0xffffffff 0xffffffff 0x78>, /* I-Cache miss */
<0x0 0x41 0xffffffff 0xffffffff 0x78>, /* D-Cache access */
<0x0 0x51 0xffffffff 0xffffffff 0x78>, /* D-Cache miss */
<0x0 0x61 0xffffffff 0xffffffff 0x78>, /* D-Cache load access */
<0x0 0x71 0xffffffff 0xffffffff 0x78>, /* D-Cache load miss */
<0x0 0x81 0xffffffff 0xffffffff 0x78>, /* D-Cache store access */
<0x0 0x91 0xffffffff 0xffffffff 0x78>, /* D-Cache store miss */
<0x0 0xA1 0xffffffff 0xffffffff 0x78>, /* D-Cache writeback */
<0x0 0xB1 0xffffffff 0xffffffff 0x78>, /* Cycles waiting for I-Cache fill data */
<0x0 0xC1 0xffffffff 0xffffffff 0x78>, /* Cycles waiting for D-Cache fill data */
<0x0 0xD1 0xffffffff 0xffffffff 0x78>, /* Uncached fetch data access from bus */
<0x0 0xE1 0xffffffff 0xffffffff 0x78>, /* Uncached load data access from bus */
<0x0 0xF1 0xffffffff 0xffffffff 0x78>, /* Cycles waiting for uncached fetch data from bus */
<0x0 0x101 0xffffffff 0xffffffff 0x78>, /* Cycles waiting for uncached load data from bus */
<0x0 0x111 0xffffffff 0xffffffff 0x78>, /* Main ITLB access */
<0x0 0x121 0xffffffff 0xffffffff 0x78>, /* Main ITLB miss */
<0x0 0x131 0xffffffff 0xffffffff 0x78>, /* Main DTLB access */
<0x0 0x141 0xffffffff 0xffffffff 0x78>, /* Main DTLB miss */
<0x0 0x151 0xffffffff 0xffffffff 0x78>, /* Cycles waiting for Main ITLB fill data */
<0x0 0x161 0xffffffff 0xffffffff 0x78>, /* Pipeline stall cycles caused by Main DTLB miss */
<0x0 0x171 0xffffffff 0xffffffff 0x78>, /* Hardware prefetch bus access */
<0x0 0x02 0xffffffff 0xffffffff 0x78>, /* Misprediction of conditional branches */
<0x0 0x12 0xffffffff 0xffffffff 0x78>, /* Misprediction of taken conditional branches */
<0x0 0x22 0xffffffff 0xffffffff 0x78>; /* Misprediction of targets of Return instructions */
};
```

Binary file not shown.

Before

Width:  |  Height:  |  Size: 7.6 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 8.9 KiB

View File

@@ -79,19 +79,43 @@ _try_lottery:
lla t0, __rel_dyn_start
lla t1, __rel_dyn_end
beq t0, t1, _relocate_done
j 5f
2:
REG_L t5, REGBYTES(t0) /* t5 <-- relocation info:type */
REG_L t5, -(REGBYTES*2)(t0) /* t5 <-- relocation info:type */
li t3, R_RISCV_RELATIVE /* reloc type R_RISCV_RELATIVE */
bne t5, t3, 3f
REG_L t3, 0(t0)
REG_L t5, (REGBYTES * 2)(t0) /* t5 <-- addend */
REG_L t3, -(REGBYTES*3)(t0)
REG_L t5, -(REGBYTES)(t0) /* t5 <-- addend */
add t5, t5, t2
add t3, t3, t2
REG_S t5, 0(t3) /* store runtime address to the GOT entry */
j 5f
3:
addi t0, t0, (REGBYTES * 3)
blt t0, t1, 2b
lla t4, __dyn_sym_start
4:
REG_L t5, -(REGBYTES*2)(t0) /* t5 <-- relocation info:type */
srli t6, t5, SYM_INDEX /* t6 <--- sym table index */
andi t5, t5, 0xFF /* t5 <--- relocation type */
li t3, RELOC_TYPE
bne t5, t3, 5f
/* address R_RISCV_64 or R_RISCV_32 cases*/
REG_L t3, -(REGBYTES*3)(t0)
li t5, SYM_SIZE
mul t6, t6, t5
add s5, t4, t6
REG_L t6, -(REGBYTES)(t0) /* t0 <-- addend */
REG_L t5, REGBYTES(s5)
add t5, t5, t6
add t5, t5, t2 /* t5 <-- location to fix up in RAM */
add t3, t3, t2 /* t3 <-- location to fix up in RAM */
REG_S t5, 0(t3) /* store runtime address to the variable */
5:
addi t0, t0, (REGBYTES*3)
ble t0, t1, 2b
j _relocate_done
_wait_relocate_copy_done:
j _wait_for_boot_hart
@@ -233,28 +257,20 @@ _bss_zero:
/* Preload HART details
* s7 -> HART Count
* s8 -> HART Stack Size
* s9 -> Heap Size
* s10 -> Heap Offset
*/
lla a4, platform
#if __riscv_xlen > 32
lwu s7, SBI_PLATFORM_HART_COUNT_OFFSET(a4)
lwu s8, SBI_PLATFORM_HART_STACK_SIZE_OFFSET(a4)
lwu s9, SBI_PLATFORM_HEAP_SIZE_OFFSET(a4)
#else
lw s7, SBI_PLATFORM_HART_COUNT_OFFSET(a4)
lw s8, SBI_PLATFORM_HART_STACK_SIZE_OFFSET(a4)
lw s9, SBI_PLATFORM_HEAP_SIZE_OFFSET(a4)
#endif
/* Setup scratch space for all the HARTs*/
lla tp, _fw_end
mul a5, s7, s8
add tp, tp, a5
/* Setup heap base address */
lla s10, _fw_start
sub s10, tp, s10
add tp, tp, s9
/* Keep a copy of tp */
add t3, tp, zero
/* Counter */
@@ -269,11 +285,8 @@ _scratch_init:
* t3 -> the firmware end address
* s7 -> HART count
* s8 -> HART stack size
* s9 -> Heap Size
* s10 -> Heap Offset
*/
add tp, t3, zero
sub tp, tp, s9
mul a5, s8, t1
sub tp, tp, a5
li a5, SBI_SCRATCH_SIZE
@@ -287,14 +300,10 @@ _scratch_init:
REG_S a5, SBI_SCRATCH_FW_SIZE_OFFSET(tp)
/* Store R/W section's offset in scratch space */
lla a5, _fw_rw_start
sub a5, a5, a4
lla a4, __fw_rw_offset
REG_L a5, 0(a4)
REG_S a5, SBI_SCRATCH_FW_RW_OFFSET(tp)
/* Store fw_heap_offset and fw_heap_size in scratch space */
REG_S s10, SBI_SCRATCH_FW_HEAP_OFFSET(tp)
REG_S s9, SBI_SCRATCH_FW_HEAP_SIZE_OFFSET(tp)
/* Store next arg1 in scratch space */
MOV_3R s0, a0, s1, a1, s2, a2
call fw_next_arg1
@@ -399,8 +408,8 @@ _fdt_reloc_done:
/* mark boot hart done */
li t0, BOOT_STATUS_BOOT_HART_DONE
lla t1, _boot_status
fence rw, rw
REG_S t0, 0(t1)
fence rw, rw
j _start_warm
/* waiting for boot hart to be done (_boot_status == 2) */
@@ -409,9 +418,9 @@ _wait_for_boot_hart:
lla t1, _boot_status
REG_L t1, 0(t1)
/* Reduce the bus traffic so that boot hart may proceed faster */
div t2, t2, zero
div t2, t2, zero
div t2, t2, zero
nop
nop
nop
bne t0, t1, _wait_for_boot_hart
_start_warm:
@@ -421,6 +430,13 @@ _start_warm:
/* Disable all interrupts */
csrw CSR_MIE, zero
/*
* Only clear the MIP_SSIP and MIP_STIP. For the platform like QEMU,
* If we clear other interrupts like MIP_SEIP and the pendings of
* PLIC still exist, the QEMU may not set it back immediately.
*/
li t0, (MIP_SSIP | MIP_STIP)
csrc CSR_MIP, t0
/* Find HART count and HART stack size */
lla a4, platform
@@ -449,8 +465,9 @@ _start_warm:
add s9, s9, 4
add a4, a4, 1
blt a4, s7, 1b
li a4, -1
2: add s6, a4, zero
3: bge s6, s7, _start_hang
3: bgeu s6, s7, _start_hang
/* Find the scratch space based on HART index */
lla tp, _fw_end
@@ -514,6 +531,8 @@ _link_start:
RISCV_PTR FW_TEXT_START
_link_end:
RISCV_PTR _fw_reloc_end
__fw_rw_offset:
RISCV_PTR _fw_rw_start - _fw_start
.section .entry, "ax", %progbits
.align 3
@@ -738,6 +757,8 @@ memcmp:
.globl _trap_handler
.globl _trap_exit
_trap_handler:
sfence.vma zero, t0
TRAP_SAVE_AND_SETUP_SP_T0
TRAP_SAVE_MEPC_MSTATUS 0

View File

@@ -40,9 +40,16 @@
. = ALIGN(0x1000); /* Ensure next section is page aligned */
.dynsym : {
PROVIDE(__dyn_sym_start = .);
*(.dynsym)
PROVIDE(__dyn_sym_end = .);
}
.rela.dyn : {
PROVIDE(__rel_dyn_start = .);
*(.rela*)
. = ALIGN(8);
PROVIDE(__rel_dyn_end = .);
}

View File

@@ -129,7 +129,7 @@ fw_options:
REG_L a0, (a0)
ret
.section .data
.section .entry, "ax", %progbits
.align 3
_dynamic_next_arg1:
RISCV_PTR 0x0

View File

@@ -90,7 +90,7 @@ fw_options:
#error "Must define FW_JUMP_ADDR"
#endif
.section .rodata
.section .entry, "ax", %progbits
.align 3
_jump_addr:
RISCV_PTR FW_JUMP_ADDR

View File

@@ -78,7 +78,7 @@ _start_hang:
wfi
j _start_hang
.section .data
.section .entry, "ax", %progbits
.align 3
_hart_lottery:
RISCV_PTR 0

View File

@@ -8,42 +8,31 @@
*/
#include <sbi/sbi_ecall_interface.h>
#include <sbi/sbi_string.h>
struct sbiret {
unsigned long error;
unsigned long value;
};
#define SBI_ECALL(__eid, __fid, __a0, __a1, __a2) \
({ \
register unsigned long a0 asm("a0") = (unsigned long)(__a0); \
register unsigned long a1 asm("a1") = (unsigned long)(__a1); \
register unsigned long a2 asm("a2") = (unsigned long)(__a2); \
register unsigned long a6 asm("a6") = (unsigned long)(__fid); \
register unsigned long a7 asm("a7") = (unsigned long)(__eid); \
asm volatile("ecall" \
: "+r"(a0) \
: "r"(a1), "r"(a2), "r"(a6), "r"(a7) \
: "memory"); \
a0; \
})
struct sbiret sbi_ecall(int ext, int fid, unsigned long arg0,
unsigned long arg1, unsigned long arg2,
unsigned long arg3, unsigned long arg4,
unsigned long arg5)
{
struct sbiret ret;
#define SBI_ECALL_0(__eid, __fid) SBI_ECALL(__eid, __fid, 0, 0, 0)
#define SBI_ECALL_1(__eid, __fid, __a0) SBI_ECALL(__eid, __fid, __a0, 0, 0)
#define SBI_ECALL_2(__eid, __fid, __a0, __a1) SBI_ECALL(__eid, __fid, __a0, __a1, 0)
register unsigned long a0 asm ("a0") = (unsigned long)(arg0);
register unsigned long a1 asm ("a1") = (unsigned long)(arg1);
register unsigned long a2 asm ("a2") = (unsigned long)(arg2);
register unsigned long a3 asm ("a3") = (unsigned long)(arg3);
register unsigned long a4 asm ("a4") = (unsigned long)(arg4);
register unsigned long a5 asm ("a5") = (unsigned long)(arg5);
register unsigned long a6 asm ("a6") = (unsigned long)(fid);
register unsigned long a7 asm ("a7") = (unsigned long)(ext);
asm volatile ("ecall"
: "+r" (a0), "+r" (a1)
: "r" (a2), "r" (a3), "r" (a4), "r" (a5), "r" (a6), "r" (a7)
: "memory");
ret.error = a0;
ret.value = a1;
return ret;
}
#define sbi_ecall_console_putc(c) SBI_ECALL_1(SBI_EXT_0_1_CONSOLE_PUTCHAR, 0, (c))
static inline void sbi_ecall_console_puts(const char *str)
{
sbi_ecall(SBI_EXT_DBCN, SBI_EXT_DBCN_CONSOLE_WRITE,
sbi_strlen(str), (unsigned long)str, 0, 0, 0, 0);
while (str && *str)
sbi_ecall_console_putc(*str++);
}
#define wfi() \

View File

@@ -181,12 +181,6 @@ int misa_xlen(void);
/* Get RISC-V ISA string representation */
void misa_string(int xlen, char *out, unsigned int out_sz);
/* Disable pmp entry at a given index */
int pmp_disable(unsigned int n);
/* Check if the matching field is set */
int is_pmp_entry_mapped(unsigned long entry);
int pmp_set(unsigned int n, unsigned long prot, unsigned long addr,
unsigned long log2len);

View File

@@ -39,14 +39,14 @@ unsigned int atomic_raw_xchg_uint(volatile unsigned int *ptr,
unsigned long atomic_raw_xchg_ulong(volatile unsigned long *ptr,
unsigned long newval);
/**
* Set a bit in an atomic variable and return the value of bit before modify.
* Set a bit in an atomic variable and return the new value.
* @nr : Bit to set.
* @atom: atomic variable to modify
*/
int atomic_set_bit(int nr, atomic_t *atom);
/**
* Clear a bit in an atomic variable and return the value of bit before modify.
* Clear a bit in an atomic variable and return the new value.
* @nr : Bit to set.
* @atom: atomic variable to modify
*/
@@ -54,14 +54,14 @@ int atomic_set_bit(int nr, atomic_t *atom);
int atomic_clear_bit(int nr, atomic_t *atom);
/**
* Set a bit in any address and return the value of bit before modify.
* Set a bit in any address and return the new value .
* @nr : Bit to set.
* @addr: Address to modify
*/
int atomic_raw_set_bit(int nr, volatile unsigned long *addr);
/**
* Clear a bit in any address and return the value of bit before modify.
* Clear a bit in any address and return the new value .
* @nr : Bit to set.
* @addr: Address to modify
*/

View File

@@ -25,30 +25,39 @@
#define mb() RISCV_FENCE(iorw,iorw)
/* Read Memory barrier */
#define rmb() RISCV_FENCE(ir,ir)
#define rmb() RISCV_FENCE(ir,iorw)
/* Write Memory barrier */
#define wmb() RISCV_FENCE(ow,ow)
#define wmb() RISCV_FENCE(iorw,ow)
/* SMP Read & Write Memory barrier */
#define smp_mb() RISCV_FENCE(rw,rw)
/* SMP Read Memory barrier */
#define smp_rmb() RISCV_FENCE(r,r)
#define smp_rmb() RISCV_FENCE(r,rw)
/* SMP Write Memory barrier */
#define smp_wmb() RISCV_FENCE(w,w)
#define smp_wmb() RISCV_FENCE(rw,w)
/* CPU relax for busy loop */
#define cpu_relax() asm volatile ("" : : : "memory")
/* clang-format on */
#ifdef CONFIG_PLATFORM_SOPHGO_MANGO
#define __smp_store_release(p, v) \
do { \
RISCV_FENCE(rw, w); \
*(p) = (v); \
RISCV_FENCE(w, rw); \
} while (0)
#else
#define __smp_store_release(p, v) \
do { \
RISCV_FENCE(rw, w); \
*(p) = (v); \
} while (0)
#endif
#define __smp_load_acquire(p) \
({ \

View File

@@ -1,6 +1,14 @@
#ifndef __RISCV_ELF_H__
#define __RISCV_ELF_H__
#include <sbi/riscv_asm.h>
#define R_RISCV_32 1
#define R_RISCV_64 2
#define R_RISCV_RELATIVE 3
#define RELOC_TYPE __REG_SEL(R_RISCV_64, R_RISCV_32)
#define SYM_INDEX __REG_SEL(0x20, 0x8)
#define SYM_SIZE __REG_SEL(0x18,0x10)
#endif

View File

@@ -207,8 +207,13 @@
#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
@@ -218,6 +223,8 @@
#define ENVCFG_CBIE_INV _UL(0x3)
#define ENVCFG_FIOM _UL(0x1)
#define MCOUNTEREN_TM (_UL(1) << 1)
/* ===== User-level CSRs ===== */
/* User Trap Setup (N-extension) */
@@ -425,7 +432,6 @@
#define CSR_MARCHID 0xf12
#define CSR_MIMPID 0xf13
#define CSR_MHARTID 0xf14
#define CSR_MCONFIGPTR 0xf15
/* Machine Trap Setup */
#define CSR_MSTATUS 0x300
@@ -598,8 +604,6 @@
/* Machine Counter Setup */
#define CSR_MCOUNTINHIBIT 0x320
#define CSR_MCYCLECFG 0x321
#define CSR_MINSTRETCFG 0x322
#define CSR_MHPMEVENT3 0x323
#define CSR_MHPMEVENT4 0x324
#define CSR_MHPMEVENT5 0x325
@@ -631,8 +635,6 @@
#define CSR_MHPMEVENT31 0x33f
/* For RV32 */
#define CSR_MCYCLECFGH 0x721
#define CSR_MINSTRETCFGH 0x722
#define CSR_MHPMEVENT3H 0x723
#define CSR_MHPMEVENT4H 0x724
#define CSR_MHPMEVENT5H 0x725
@@ -663,21 +665,6 @@
#define CSR_MHPMEVENT30H 0x73e
#define CSR_MHPMEVENT31H 0x73f
/* Machine Security Configuration CSR (mseccfg) */
#define CSR_MSECCFG 0x747
#define CSR_MSECCFGH 0x757
#define MSECCFG_MML_SHIFT (0)
#define MSECCFG_MML (_UL(1) << MSECCFG_MML_SHIFT)
#define MSECCFG_MMWP_SHIFT (1)
#define MSECCFG_MMWP (_UL(1) << MSECCFG_MMWP_SHIFT)
#define MSECCFG_RLB_SHIFT (2)
#define MSECCFG_RLB (_UL(1) << MSECCFG_RLB_SHIFT)
#define MSECCFG_USEED_SHIFT (8)
#define MSECCFG_USEED (_UL(1) << MSECCFG_USEED_SHIFT)
#define MSECCFG_SSEED_SHIFT (9)
#define MSECCFG_SSEED (_UL(1) << MSECCFG_SSEED_SHIFT)
/* Counter Overflow CSR */
#define CSR_SCOUNTOVF 0xda0

View File

@@ -84,7 +84,7 @@
#define GET_FFLAGS() csr_read(CSR_FFLAGS)
#define SET_FFLAGS(value) csr_write(CSR_FFLAGS, (value))
#define SET_FS_DIRTY(regs) (regs->mstatus |= MSTATUS_FS)
#define SET_FS_DIRTY() ((void)0)
#define GET_F32_RS1(insn, regs) (GET_F32_REG(insn, 15, regs))
#define GET_F32_RS2(insn, regs) (GET_F32_REG(insn, 20, regs))
@@ -93,9 +93,9 @@
#define GET_F64_RS2(insn, regs) (GET_F64_REG(insn, 20, regs))
#define GET_F64_RS3(insn, regs) (GET_F64_REG(insn, 27, regs))
#define SET_F32_RD(insn, regs, val) \
(SET_F32_REG(insn, 7, regs, val), SET_FS_DIRTY(regs))
(SET_F32_REG(insn, 7, regs, val), SET_FS_DIRTY())
#define SET_F64_RD(insn, regs, val) \
(SET_F64_REG(insn, 7, regs, val), SET_FS_DIRTY(regs))
(SET_F64_REG(insn, 7, regs, val), SET_FS_DIRTY())
#define GET_F32_RS2C(insn, regs) (GET_F32_REG(insn, 2, regs))
#define GET_F32_RS2S(insn, regs) (GET_F32_REG(RVC_RS2S(insn), 0, regs))

View File

@@ -12,7 +12,13 @@
#include <sbi/sbi_types.h>
#define BITS_PER_LONG (8 * __SIZEOF_LONG__)
#if __SIZEOF_POINTER__ == 8
#define BITS_PER_LONG 64
#elif __SIZEOF_POINTER__ == 4
#define BITS_PER_LONG 32
#else
#error "Unexpected __SIZEOF_POINTER__"
#endif
#define EXTRACT_FIELD(val, which) \
(((val) & (which)) / ((which) & ~((which)-1)))
@@ -26,7 +32,6 @@
#define BIT_MASK(nr) (1UL << ((nr) % BITS_PER_LONG))
#define BIT_WORD(bit) ((bit) / BITS_PER_LONG)
#define BIT_WORD_OFFSET(bit) ((bit) & (BITS_PER_LONG - 1))
#define BIT_ALIGN(bit, align) (((bit) + ((align) - 1)) & ~((align) - 1))
#define GENMASK(h, l) \
(((~0UL) - (1UL << (l)) + 1) & (~0UL >> (BITS_PER_LONG - 1 - (h))))
@@ -113,22 +118,6 @@ static inline unsigned long sbi_fls(unsigned long word)
return num;
}
/**
* sbi_popcount - find the number of set bit in a long word
* @word: the word to search
*/
static inline unsigned long sbi_popcount(unsigned long word)
{
unsigned long count = 0;
while (word) {
word &= word - 1;
count++;
}
return count;
}
#define for_each_set_bit(bit, addr, size) \
for ((bit) = find_first_bit((addr), (size)); \
(bit) < (size); \

View File

@@ -1,35 +0,0 @@
/*
* SPDX-License-Identifier: BSD-2-Clause
*
* Copyright (c) 2023 Ventana Micro Systems Inc.
*
*/
#ifndef __SBI_CPPC_H__
#define __SBI_CPPC_H__
#include <sbi/sbi_types.h>
/** CPPC device */
struct sbi_cppc_device {
/** Name of the CPPC device */
char name[32];
/** probe - returns register width if implemented, 0 otherwise */
int (*cppc_probe)(unsigned long reg);
/** read the cppc register*/
int (*cppc_read)(unsigned long reg, uint64_t *val);
/** write to the cppc register*/
int (*cppc_write)(unsigned long reg, uint64_t val);
};
int sbi_cppc_probe(unsigned long reg);
int sbi_cppc_read(unsigned long reg, uint64_t *val);
int sbi_cppc_write(unsigned long reg, uint64_t val);
const struct sbi_cppc_device *sbi_cppc_get_device(void);
void sbi_cppc_set_device(const struct sbi_cppc_device *dev);
#endif

View File

@@ -43,80 +43,6 @@ struct sbi_domain_memregion {
#define SBI_DOMAIN_MEMREGION_SU_WRITABLE (1UL << 4)
#define SBI_DOMAIN_MEMREGION_SU_EXECUTABLE (1UL << 5)
#define SBI_DOMAIN_MEMREGION_ACCESS_MASK (0x3fUL)
#define SBI_DOMAIN_MEMREGION_M_ACCESS_MASK (0x7UL)
#define SBI_DOMAIN_MEMREGION_SU_ACCESS_MASK (0x38UL)
#define SBI_DOMAIN_MEMREGION_SU_ACCESS_SHIFT (3)
#define SBI_DOMAIN_MEMREGION_SHARED_RDONLY \
(SBI_DOMAIN_MEMREGION_M_READABLE | \
SBI_DOMAIN_MEMREGION_SU_READABLE)
#define SBI_DOMAIN_MEMREGION_SHARED_SUX_MRX \
(SBI_DOMAIN_MEMREGION_M_READABLE | \
SBI_DOMAIN_MEMREGION_M_EXECUTABLE | \
SBI_DOMAIN_MEMREGION_SU_EXECUTABLE)
#define SBI_DOMAIN_MEMREGION_SHARED_SUX_MX \
(SBI_DOMAIN_MEMREGION_M_EXECUTABLE | \
SBI_DOMAIN_MEMREGION_SU_EXECUTABLE)
#define SBI_DOMAIN_MEMREGION_SHARED_SURW_MRW \
(SBI_DOMAIN_MEMREGION_M_READABLE | \
SBI_DOMAIN_MEMREGION_M_WRITABLE | \
SBI_DOMAIN_MEMREGION_SU_READABLE| \
SBI_DOMAIN_MEMREGION_SU_WRITABLE)
#define SBI_DOMAIN_MEMREGION_SHARED_SUR_MRW \
(SBI_DOMAIN_MEMREGION_M_READABLE | \
SBI_DOMAIN_MEMREGION_M_WRITABLE | \
SBI_DOMAIN_MEMREGION_SU_READABLE)
/* Shared read-only region between M and SU mode */
#define SBI_DOMAIN_MEMREGION_IS_SUR_MR(__flags) \
((__flags & SBI_DOMAIN_MEMREGION_ACCESS_MASK) == \
SBI_DOMAIN_MEMREGION_SHARED_RDONLY)
/* Shared region: SU execute-only and M read/execute */
#define SBI_DOMAIN_MEMREGION_IS_SUX_MRX(__flags) \
((__flags & SBI_DOMAIN_MEMREGION_ACCESS_MASK) == \
SBI_DOMAIN_MEMREGION_SHARED_SUX_MRX)
/* Shared region: SU and M execute-only */
#define SBI_DOMAIN_MEMREGION_IS_SUX_MX(__flags) \
((__flags & SBI_DOMAIN_MEMREGION_ACCESS_MASK) == \
SBI_DOMAIN_MEMREGION_SHARED_SUX_MX)
/* Shared region: SU and M read/write */
#define SBI_DOMAIN_MEMREGION_IS_SURW_MRW(__flags) \
((__flags & SBI_DOMAIN_MEMREGION_ACCESS_MASK) == \
SBI_DOMAIN_MEMREGION_SHARED_SURW_MRW)
/* Shared region: SU read-only and M read/write */
#define SBI_DOMAIN_MEMREGION_IS_SUR_MRW(__flags) \
((__flags & SBI_DOMAIN_MEMREGION_ACCESS_MASK) == \
SBI_DOMAIN_MEMREGION_SHARED_SUR_MRW)
/*
* Check if region flags match with any of the above
* mentioned shared region type
*/
#define SBI_DOMAIN_MEMREGION_IS_SHARED(_flags) \
(SBI_DOMAIN_MEMREGION_IS_SUR_MR(_flags) || \
SBI_DOMAIN_MEMREGION_IS_SUX_MRX(_flags) || \
SBI_DOMAIN_MEMREGION_IS_SUX_MX(_flags) || \
SBI_DOMAIN_MEMREGION_IS_SURW_MRW(_flags)|| \
SBI_DOMAIN_MEMREGION_IS_SUR_MRW(_flags))
#define SBI_DOMAIN_MEMREGION_M_ONLY_ACCESS(__flags) \
((__flags & SBI_DOMAIN_MEMREGION_M_ACCESS_MASK) && \
!(__flags & SBI_DOMAIN_MEMREGION_SU_ACCESS_MASK))
#define SBI_DOMAIN_MEMREGION_SU_ONLY_ACCESS(__flags) \
((__flags & SBI_DOMAIN_MEMREGION_SU_ACCESS_MASK) && \
!(__flags & SBI_DOMAIN_MEMREGION_M_ACCESS_MASK))
/** Bit to control if permissions are enforced on all modes */
#define SBI_DOMAIN_MEMREGION_ENF_PERMISSIONS (1UL << 6)
@@ -152,6 +78,12 @@ struct sbi_domain_memregion {
(SBI_DOMAIN_MEMREGION_SU_EXECUTABLE | \
SBI_DOMAIN_MEMREGION_M_EXECUTABLE)
#define SBI_DOMAIN_MEMREGION_ACCESS_MASK (0x3fUL)
#define SBI_DOMAIN_MEMREGION_M_ACCESS_MASK (0x7UL)
#define SBI_DOMAIN_MEMREGION_SU_ACCESS_MASK (0x38UL)
#define SBI_DOMAIN_MEMREGION_SU_ACCESS_SHIFT (3)
#define SBI_DOMAIN_MEMREGION_MMIO (1UL << 31)
unsigned long flags;
};
@@ -190,19 +122,21 @@ struct sbi_domain {
bool system_reset_allowed;
/** Is domain allowed to suspend the system */
bool system_suspend_allowed;
/** Identifies whether to include the firmware region */
bool fw_region_inited;
};
/** The root domain instance */
extern struct sbi_domain root;
/** Get pointer to sbi_domain from HART index */
struct sbi_domain *sbi_hartindex_to_domain(u32 hartindex);
/** HART id to domain table */
extern struct sbi_domain *hartid_to_domain_table[];
/** Get pointer to sbi_domain from HART id */
#define sbi_hartid_to_domain(__hartid) \
hartid_to_domain_table[__hartid]
/** Get pointer to sbi_domain for current HART */
#define sbi_domain_thishart_ptr() \
sbi_hartindex_to_domain(sbi_hartid_to_hartindex(current_hartid()))
sbi_hartid_to_domain(current_hartid())
/** Index to domain table */
extern struct sbi_domain *domidx_to_domain_table[];

View File

@@ -13,64 +13,22 @@
#include <sbi/sbi_types.h>
#include <sbi/sbi_list.h>
#define SBI_ECALL_VERSION_MAJOR 2
#define SBI_ECALL_VERSION_MAJOR 1
#define SBI_ECALL_VERSION_MINOR 0
#define SBI_OPENSBI_IMPID 1
struct sbi_trap_regs;
struct sbi_trap_info;
struct sbi_ecall_return {
/* Return flag to skip register update */
bool skip_regs_update;
/* Return value */
unsigned long value;
};
struct sbi_ecall_extension {
/* head is used by the extension list */
struct sbi_dlist head;
/*
* extid_start and extid_end specify the range for this extension. As
* the initial range may be wider than the valid runtime range, the
* register_extensions callback is responsible for narrowing the range
* before other callbacks may be invoked.
*/
unsigned long extid_start;
unsigned long extid_end;
/*
* register_extensions
*
* Calls sbi_ecall_register_extension() one or more times to register
* extension ID range(s) which should be handled by this extension.
* More than one sbi_ecall_extension struct and
* sbi_ecall_register_extension() call is necessary when the supported
* extension ID ranges have gaps. Additionally, extension availability
* must be checked before registering, which means, when this callback
* returns, only valid extension IDs from the initial range, which are
* also available, have been registered.
*/
int (* register_extensions)(void);
/*
* probe
*
* Implements the Base extension's probe function for the extension. As
* the register_extensions callback ensures that no other extension
* callbacks will be invoked when the extension is not available, then
* probe can never fail. However, an extension may choose to set
* out_val to a nonzero value other than one. In those cases, it should
* implement this callback.
*/
int (* probe)(unsigned long extid, unsigned long *out_val);
/*
* handle
*
* This is the extension handler. register_extensions ensures it is
* never invoked with an invalid or unavailable extension ID.
*/
int (* handle)(unsigned long extid, unsigned long funcid,
struct sbi_trap_regs *regs,
struct sbi_ecall_return *out);
const struct sbi_trap_regs *regs,
unsigned long *out_val,
struct sbi_trap_info *out_trap);
};
u16 sbi_ecall_version_major(void);

View File

@@ -31,7 +31,6 @@
#define SBI_EXT_PMU 0x504D55
#define SBI_EXT_DBCN 0x4442434E
#define SBI_EXT_SUSP 0x53555350
#define SBI_EXT_CPPC 0x43505043
/* SBI function IDs for BASE extension*/
#define SBI_EXT_BASE_GET_SPEC_VERSION 0x0
@@ -103,7 +102,6 @@
#define SBI_EXT_PMU_COUNTER_STOP 0x4
#define SBI_EXT_PMU_COUNTER_FW_READ 0x5
#define SBI_EXT_PMU_COUNTER_FW_READ_HI 0x6
#define SBI_EXT_PMU_SNAPSHOT_SET_SHMEM 0x7
/** General pmu event codes specified in SBI PMU extension */
enum sbi_pmu_hw_generic_events_t {
@@ -216,10 +214,10 @@ enum sbi_pmu_ctr_type {
};
/* Helper macros to decode event idx */
#define SBI_PMU_EVENT_IDX_OFFSET 20
#define SBI_PMU_EVENT_IDX_MASK 0xFFFFF
#define SBI_PMU_EVENT_IDX_TYPE_OFFSET 16
#define SBI_PMU_EVENT_IDX_TYPE_MASK (0xF << SBI_PMU_EVENT_IDX_TYPE_OFFSET)
#define SBI_PMU_EVENT_IDX_CODE_MASK 0xFFFF
#define SBI_PMU_EVENT_IDX_TYPE_MASK 0xF0000
#define SBI_PMU_EVENT_RAW_IDX 0x20000
#define SBI_PMU_EVENT_IDX_INVALID 0xFFFFFFFF
@@ -242,11 +240,9 @@ enum sbi_pmu_ctr_type {
/* Flags defined for counter start function */
#define SBI_PMU_START_FLAG_SET_INIT_VALUE (1 << 0)
#define SBI_PMU_START_FLAG_INIT_FROM_SNAPSHOT (1 << 1)
/* Flags defined for counter stop function */
#define SBI_PMU_STOP_FLAG_RESET (1 << 0)
#define SBI_PMU_STOP_FLAG_TAKE_SNAPSHOT (1 << 1)
/* SBI function IDs for DBCN extension */
#define SBI_EXT_DBCN_CONSOLE_WRITE 0x0
@@ -260,39 +256,6 @@ enum sbi_pmu_ctr_type {
#define SBI_SUSP_SLEEP_TYPE_LAST SBI_SUSP_SLEEP_TYPE_SUSPEND
#define SBI_SUSP_PLATFORM_SLEEP_START 0x80000000
/* SBI function IDs for CPPC extension */
#define SBI_EXT_CPPC_PROBE 0x0
#define SBI_EXT_CPPC_READ 0x1
#define SBI_EXT_CPPC_READ_HI 0x2
#define SBI_EXT_CPPC_WRITE 0x3
enum sbi_cppc_reg_id {
SBI_CPPC_HIGHEST_PERF = 0x00000000,
SBI_CPPC_NOMINAL_PERF = 0x00000001,
SBI_CPPC_LOW_NON_LINEAR_PERF = 0x00000002,
SBI_CPPC_LOWEST_PERF = 0x00000003,
SBI_CPPC_GUARANTEED_PERF = 0x00000004,
SBI_CPPC_DESIRED_PERF = 0x00000005,
SBI_CPPC_MIN_PERF = 0x00000006,
SBI_CPPC_MAX_PERF = 0x00000007,
SBI_CPPC_PERF_REDUC_TOLERANCE = 0x00000008,
SBI_CPPC_TIME_WINDOW = 0x00000009,
SBI_CPPC_CTR_WRAP_TIME = 0x0000000A,
SBI_CPPC_REFERENCE_CTR = 0x0000000B,
SBI_CPPC_DELIVERED_CTR = 0x0000000C,
SBI_CPPC_PERF_LIMITED = 0x0000000D,
SBI_CPPC_ENABLE = 0x0000000E,
SBI_CPPC_AUTO_SEL_ENABLE = 0x0000000F,
SBI_CPPC_AUTO_ACT_WINDOW = 0x00000010,
SBI_CPPC_ENERGY_PERF_PREFERENCE = 0x00000011,
SBI_CPPC_REFERENCE_PERF = 0x00000012,
SBI_CPPC_LOWEST_FREQ = 0x00000013,
SBI_CPPC_NOMINAL_FREQ = 0x00000014,
SBI_CPPC_ACPI_LAST = SBI_CPPC_NOMINAL_FREQ,
SBI_CPPC_TRANSITION_LATENCY = 0x80000000,
SBI_CPPC_NON_ACPI_LAST = SBI_CPPC_TRANSITION_LATENCY,
};
/* SBI base specification related macros */
#define SBI_SPEC_VERSION_MAJOR_OFFSET 24
#define SBI_SPEC_VERSION_MAJOR_MASK 0x7f
@@ -312,9 +275,8 @@ enum sbi_cppc_reg_id {
#define SBI_ERR_ALREADY_AVAILABLE -6
#define SBI_ERR_ALREADY_STARTED -7
#define SBI_ERR_ALREADY_STOPPED -8
#define SBI_ERR_NO_SHMEM -9
#define SBI_LAST_ERR SBI_ERR_NO_SHMEM
#define SBI_LAST_ERR SBI_ERR_ALREADY_STOPPED
/* clang-format on */

View File

@@ -23,7 +23,6 @@
#define SBI_EALREADY SBI_ERR_ALREADY_AVAILABLE
#define SBI_EALREADY_STARTED SBI_ERR_ALREADY_STARTED
#define SBI_EALREADY_STOPPED SBI_ERR_ALREADY_STOPPED
#define SBI_ENO_SHMEM SBI_ERR_NO_SHMEM
#define SBI_ENODEV -1000
#define SBI_ENOSYS -1001
@@ -32,8 +31,9 @@
#define SBI_EILL -1004
#define SBI_ENOSPC -1005
#define SBI_ENOMEM -1006
#define SBI_EUNKNOWN -1007
#define SBI_ENOENT -1008
#define SBI_ETRAP -1007
#define SBI_EUNKNOWN -1008
#define SBI_ENOENT -1009
/* clang-format on */

View File

@@ -11,7 +11,6 @@
#define __SBI_HART_H__
#include <sbi/sbi_types.h>
#include <sbi/sbi_bitops.h>
/** Possible privileged specification versions of a hart */
enum sbi_hart_priv_versions {
@@ -27,67 +26,29 @@ enum sbi_hart_priv_versions {
/** 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 = 0,
/** HART has Smepmp */
SBI_HART_EXT_SMEPMP,
SBI_HART_EXT_SMAIA,
/** HART has Smstateen CSR **/
SBI_HART_EXT_SMSTATEEN,
/** Hart has Sscofpmt extension */
SBI_HART_EXT_SSCOFPMF,
/** HART has Sstc extension */
SBI_HART_EXT_SSTC,
/** HART has Zicntr extension (i.e. HW cycle, time & instret CSRs) */
SBI_HART_EXT_ZICNTR,
/** HART has Zihpm extension */
SBI_HART_EXT_ZIHPM,
/** HART has Zkr extension */
SBI_HART_EXT_ZKR,
/** Hart has Smcntrpmf extension */
SBI_HART_EXT_SMCNTRPMF,
/** Hart has Xandespmu extension */
SBI_HART_EXT_XANDESPMU,
/** Hart has Zicboz extension */
SBI_HART_EXT_ZICBOZ,
/** Hart has Zicbom extension */
SBI_HART_EXT_ZICBOM,
/** Hart has Svpbmt extension */
SBI_HART_EXT_SVPBMT,
/** Maximum index of Hart extension */
SBI_HART_EXT_MAX,
};
struct sbi_hart_ext_data {
const unsigned int id;
const char *name;
};
extern const struct sbi_hart_ext_data sbi_hart_ext[];
/*
* Smepmp enforces access boundaries between M-mode and
* S/U-mode. When it is enabled, the PMPs are programmed
* such that M-mode doesn't have access to S/U-mode memory.
*
* To give M-mode R/W access to the shared memory between M and
* S/U-mode, first entry is reserved. It is disabled at boot.
* When shared memory access is required, the physical address
* should be programmed into the first PMP entry with R/W
* permissions to the M-mode. Once the work is done, it should be
* unmapped. sbi_hart_map_saddr/sbi_hart_unmap_saddr function
* pair should be used to map/unmap the shared memory.
*/
#define SBI_SMEPMP_RESV_ENTRY 0
struct sbi_hart_features {
bool detected;
int priv_version;
unsigned long extensions[BITS_TO_LONGS(SBI_HART_EXT_MAX)];
unsigned long extensions;
unsigned int pmp_count;
unsigned int pmp_addr_bits;
unsigned int pmp_log2gran;
unsigned int mhpm_mask;
unsigned long pmp_gran;
unsigned int mhpm_count;
unsigned int mhpm_bits;
};
@@ -102,16 +63,14 @@ static inline ulong sbi_hart_expected_trap_addr(void)
return (ulong)sbi_hart_expected_trap;
}
unsigned int sbi_hart_mhpm_mask(struct sbi_scratch *scratch);
unsigned int sbi_hart_mhpm_count(struct sbi_scratch *scratch);
void sbi_hart_delegation_dump(struct sbi_scratch *scratch,
const char *prefix, const char *suffix);
unsigned int sbi_hart_pmp_count(struct sbi_scratch *scratch);
unsigned int sbi_hart_pmp_log2gran(struct sbi_scratch *scratch);
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);
int sbi_hart_map_saddr(unsigned long base, unsigned long size);
int sbi_hart_unmap_saddr(void);
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);

View File

@@ -11,7 +11,6 @@
#define __SBI_HARTMASK_H__
#include <sbi/sbi_bitmap.h>
#include <sbi/sbi_scratch.h>
/**
* Maximum number of bits in a hartmask
@@ -33,10 +32,7 @@ struct sbi_hartmask {
/** Initialize hartmask to zero except a particular HART id */
#define SBI_HARTMASK_INIT_EXCEPT(__m, __h) \
do { \
u32 __i = sbi_hartid_to_hartindex(__h); \
bitmap_zero_except(((__m)->bits), __i, SBI_HARTMASK_MAX_BITS); \
} while(0)
bitmap_zero_except(((__m)->bits), (__h), SBI_HARTMASK_MAX_BITS)
/**
* Get underlying bitmap of hartmask
@@ -45,68 +41,37 @@ struct sbi_hartmask {
#define sbi_hartmask_bits(__m) ((__m)->bits)
/**
* Set a HART index in hartmask
* @param i HART index to set
* @param m the hartmask pointer
*/
static inline void sbi_hartmask_set_hartindex(u32 i, struct sbi_hartmask *m)
{
if (i < SBI_HARTMASK_MAX_BITS)
__set_bit(i, m->bits);
}
/**
* Set a HART id in hartmask
* Set a HART in hartmask
* @param h HART id to set
* @param m the hartmask pointer
*/
static inline void sbi_hartmask_set_hartid(u32 h, struct sbi_hartmask *m)
static inline void sbi_hartmask_set_hart(u32 h, struct sbi_hartmask *m)
{
sbi_hartmask_set_hartindex(sbi_hartid_to_hartindex(h), m);
if (h < SBI_HARTMASK_MAX_BITS)
__set_bit(h, m->bits);
}
/**
* Clear a HART index in hartmask
* @param i HART index to clear
* @param m the hartmask pointer
*/
static inline void sbi_hartmask_clear_hartindex(u32 i, struct sbi_hartmask *m)
{
if (i < SBI_HARTMASK_MAX_BITS)
__clear_bit(i, m->bits);
}
/**
* Clear a HART id in hartmask
* Clear a HART in hartmask
* @param h HART id to clear
* @param m the hartmask pointer
*/
static inline void sbi_hartmask_clear_hartid(u32 h, struct sbi_hartmask *m)
static inline void sbi_hartmask_clear_hart(u32 h, struct sbi_hartmask *m)
{
sbi_hartmask_clear_hartindex(sbi_hartid_to_hartindex(h), m);
if (h < SBI_HARTMASK_MAX_BITS)
__clear_bit(h, m->bits);
}
/**
* Test a HART index in hartmask
* @param i HART index to test
* @param m the hartmask pointer
*/
static inline int sbi_hartmask_test_hartindex(u32 i,
const struct sbi_hartmask *m)
{
if (i < SBI_HARTMASK_MAX_BITS)
return __test_bit(i, m->bits);
return 0;
}
/**
* Test a HART id in hartmask
* Test a HART in hartmask
* @param h HART id to test
* @param m the hartmask pointer
*/
static inline int sbi_hartmask_test_hartid(u32 h, const struct sbi_hartmask *m)
static inline int sbi_hartmask_test_hart(u32 h, const struct sbi_hartmask *m)
{
return sbi_hartmask_test_hartindex(sbi_hartid_to_hartindex(h), m);
if (h < SBI_HARTMASK_MAX_BITS)
return __test_bit(h, m->bits);
return 0;
}
/**
@@ -169,14 +134,8 @@ static inline void sbi_hartmask_xor(struct sbi_hartmask *dstp,
sbi_hartmask_bits(src2p), SBI_HARTMASK_MAX_BITS);
}
/**
* Iterate over each HART index in hartmask
* __i hart index
* __m hartmask
*/
#define sbi_hartmask_for_each_hartindex(__i, __m) \
for((__i) = find_first_bit((__m)->bits, SBI_HARTMASK_MAX_BITS); \
(__i) < SBI_HARTMASK_MAX_BITS; \
(__i) = find_next_bit((__m)->bits, SBI_HARTMASK_MAX_BITS, (__i) + 1))
/** Iterate over each HART in hartmask */
#define sbi_hartmask_for_each_hart(__h, __m) \
for_each_set_bit(__h, (__m)->bits, SBI_HARTMASK_MAX_BITS)
#endif

View File

@@ -1,47 +0,0 @@
/*
* SPDX-License-Identifier: BSD-2-Clause
*
* Copyright (c) 2023 Ventana Micro Systems Inc.
*
* Authors:
* Anup Patel<apatel@ventanamicro.com>
*/
#ifndef __SBI_HEAP_H__
#define __SBI_HEAP_H__
#include <sbi/sbi_types.h>
/* Alignment of heap base address and size */
#define HEAP_BASE_ALIGN 1024
struct sbi_scratch;
/** Allocate from heap area */
void *sbi_malloc(size_t size);
/** Zero allocate from heap area */
void *sbi_zalloc(size_t size);
/** Allocate array from heap area */
static inline void *sbi_calloc(size_t nitems, size_t size)
{
return sbi_zalloc(nitems * size);
}
/** Free-up to heap area */
void sbi_free(void *ptr);
/** Amount (in bytes) of free space in the heap area */
unsigned long sbi_heap_free_space(void);
/** Amount (in bytes) of used space in the heap area */
unsigned long sbi_heap_used_space(void);
/** Amount (in bytes) of reserved space in the heap area */
unsigned long sbi_heap_reserved_space(void);
/** Initialize heap area */
int sbi_heap_init(struct sbi_scratch *scratch);
#endif

View File

@@ -16,8 +16,6 @@ struct sbi_scratch;
void __noreturn sbi_init(struct sbi_scratch *scratch);
unsigned long sbi_entry_count(u32 hartid);
unsigned long sbi_init_count(u32 hartid);
void __noreturn sbi_exit(struct sbi_scratch *scratch);

View File

@@ -14,7 +14,7 @@
/* clang-format off */
#define SBI_IPI_EVENT_MAX (8 * __SIZEOF_LONG__)
#define SBI_IPI_EVENT_MAX __riscv_xlen
/* clang-format on */
@@ -23,17 +23,11 @@ struct sbi_ipi_device {
/** Name of the IPI device */
char name[32];
/** Send IPI to a target HART index */
void (*ipi_send)(u32 hart_index);
/** Send IPI to a target HART */
void (*ipi_send)(u32 target_hart);
/** Clear IPI for a target HART index */
void (*ipi_clear)(u32 hart_index);
};
enum sbi_ipi_update_type {
SBI_IPI_UPDATE_SUCCESS,
SBI_IPI_UPDATE_BREAK,
SBI_IPI_UPDATE_RETRY,
/** Clear IPI for a target HART */
void (*ipi_clear)(u32 target_hart);
};
struct sbi_scratch;
@@ -47,14 +41,14 @@ struct sbi_ipi_event_ops {
* Update callback to save/enqueue data for remote HART
* Note: This is an optional callback and it is called just before
* triggering IPI to remote HART.
* @return < 0, error or failure
* @return SBI_IPI_UPDATE_SUCCESS, success
* @return SBI_IPI_UPDATE_BREAK, break IPI, done on local hart
* @return SBI_IPI_UPDATE_RETRY, need retry
* @return 0 success
* @return -1 break IPI, done on local hart
* @return -2 need retry
*/
int (* update)(struct sbi_scratch *scratch,
struct sbi_scratch *remote_scratch,
u32 remote_hartindex, void *data);
u32 remote_hartid, void *data);
/**
* Sync callback to wait for remote HART
@@ -85,9 +79,9 @@ int sbi_ipi_send_halt(ulong hmask, ulong hbase);
void sbi_ipi_process(void);
int sbi_ipi_raw_send(u32 hartindex);
int sbi_ipi_raw_send(u32 target_hart);
void sbi_ipi_raw_clear(u32 hartindex);
void sbi_ipi_raw_clear(u32 target_hart);
const struct sbi_ipi_device *sbi_ipi_get_device(void);

View File

@@ -31,7 +31,7 @@ struct sbi_dlist _lname = SBI_LIST_HEAD_INIT(_lname)
#define SBI_INIT_LIST_HEAD(ptr) \
do { \
(ptr)->next = ptr; (ptr)->prev = ptr; \
} while (0)
} while (0);
static inline void __sbi_list_add(struct sbi_dlist *new,
struct sbi_dlist *prev,

View File

@@ -29,16 +29,12 @@
#define SBI_PLATFORM_HART_COUNT_OFFSET (0x50)
/** Offset of hart_stack_size in struct sbi_platform */
#define SBI_PLATFORM_HART_STACK_SIZE_OFFSET (0x54)
/** Offset of heap_size in struct sbi_platform */
#define SBI_PLATFORM_HEAP_SIZE_OFFSET (0x58)
/** Offset of reserved in struct sbi_platform */
#define SBI_PLATFORM_RESERVED_OFFSET (0x5c)
/** Offset of platform_ops_addr in struct sbi_platform */
#define SBI_PLATFORM_OPS_OFFSET (0x60)
#define SBI_PLATFORM_OPS_OFFSET (0x58)
/** Offset of firmware_context in struct sbi_platform */
#define SBI_PLATFORM_FIRMWARE_CONTEXT_OFFSET (0x60 + __SIZEOF_POINTER__)
#define SBI_PLATFORM_FIRMWARE_CONTEXT_OFFSET (0x58 + __SIZEOF_POINTER__)
/** Offset of hart_index2id in struct sbi_platform */
#define SBI_PLATFORM_HART_INDEX2ID_OFFSET (0x60 + (__SIZEOF_POINTER__ * 2))
#define SBI_PLATFORM_HART_INDEX2ID_OFFSET (0x58 + (__SIZEOF_POINTER__ * 2))
#define SBI_PLATFORM_TLB_RANGE_FLUSH_LIMIT_DEFAULT (1UL << 12)
@@ -50,7 +46,7 @@
#include <sbi/sbi_version.h>
struct sbi_domain_memregion;
struct sbi_ecall_return;
struct sbi_trap_info;
struct sbi_trap_regs;
struct sbi_hart_features;
@@ -72,6 +68,9 @@ struct sbi_platform_operations {
/* Check if specified HART is allowed to do cold boot */
bool (*cold_boot_allowed)(u32 hartid);
/* Check if platform force emulate time csr, instead of using csr directly */
bool (*force_emulate_time_csr)(void);
/* Platform nascent initialization */
int (*nascent_init)(void);
@@ -125,9 +124,6 @@ struct sbi_platform_operations {
/** Get tlb flush limit value **/
u64 (*get_tlbr_flush_limit)(void);
/** Get tlb fifo num entries*/
u32 (*get_tlb_num_entries)(void);
/** Initialize platform timer for current HART */
int (*timer_init)(bool cold_boot);
/** Exit platform timer for current HART */
@@ -137,17 +133,14 @@ struct sbi_platform_operations {
bool (*vendor_ext_check)(void);
/** platform specific SBI extension implementation provider */
int (*vendor_ext_provider)(long funcid,
struct sbi_trap_regs *regs,
struct sbi_ecall_return *out);
const struct sbi_trap_regs *regs,
unsigned long *out_value,
struct sbi_trap_info *out_trap);
};
/** Platform default per-HART stack size for exception/interrupt handling */
#define SBI_PLATFORM_DEFAULT_HART_STACK_SIZE 8192
/** Platform default heap size */
#define SBI_PLATFORM_DEFAULT_HEAP_SIZE(__num_hart) \
(0x8000 + 0x800 * (__num_hart))
/** Representation of a platform */
struct sbi_platform {
/**
@@ -170,10 +163,6 @@ struct sbi_platform {
u32 hart_count;
/** Per-HART stack size for exception/interrupt handling */
u32 hart_stack_size;
/** Size of heap shared by all HARTs */
u32 heap_size;
/** Reserved for future use */
u32 reserved;
/** Pointer to sbi platform operations */
unsigned long platform_ops_addr;
/** Pointer to system firmware specific context */
@@ -260,6 +249,16 @@ _Static_assert(
#define sbi_platform_has_mfaults_delegation(__p) \
((__p)->features & SBI_PLATFORM_HAS_MFAULTS_DELEGATION)
/**
* Get HART index for the given HART
*
* @param plat pointer to struct sbi_platform
* @param hartid HART ID
*
* @return 0 <= value < hart_count for valid HART otherwise -1U
*/
u32 sbi_platform_hart_index(const struct sbi_platform *plat, u32 hartid);
/**
* Get the platform features in string format
*
@@ -317,20 +316,6 @@ static inline u64 sbi_platform_tlbr_flush_limit(const struct sbi_platform *plat)
return SBI_PLATFORM_TLB_RANGE_FLUSH_LIMIT_DEFAULT;
}
/**
* Get platform specific tlb fifo num entries.
*
* @param plat pointer to struct sbi_platform
*
* @return number of tlb fifo entries
*/
static inline u32 sbi_platform_tlb_fifo_num_entries(const struct sbi_platform *plat)
{
if (plat && sbi_platform_ops(plat)->get_tlb_num_entries)
return sbi_platform_ops(plat)->get_tlb_num_entries();
return sbi_scratch_last_hartindex() + 1;
}
/**
* Get total number of HARTs supported by the platform
*
@@ -359,6 +344,24 @@ static inline u32 sbi_platform_hart_stack_size(const struct sbi_platform *plat)
return 0;
}
/**
* Check whether given HART is invalid
*
* @param plat pointer to struct sbi_platform
* @param hartid HART ID
*
* @return true if HART is invalid and false otherwise
*/
static inline bool sbi_platform_hart_invalid(const struct sbi_platform *plat,
u32 hartid)
{
if (!plat)
return true;
if (plat->hart_count <= sbi_platform_hart_index(plat, hartid))
return true;
return false;
}
/**
* Check whether given HART is allowed to do cold boot
*
@@ -376,6 +379,20 @@ static inline bool sbi_platform_cold_boot_allowed(
return true;
}
/**
* Check whether given platform should force emulate time CSR
*
* @param plat pointer to struct sbi_platform
*
* @return true such platform force emulate time CSR, false otherwise
*/
static inline bool sbi_platform_force_emulate_time_csr(const struct sbi_platform *plat)
{
if (plat && sbi_platform_ops(plat)->force_emulate_time_csr)
return sbi_platform_ops(plat)->force_emulate_time_csr();
return false;
}
/**
* Nascent (very early) initialization for current HART
*
@@ -665,12 +682,16 @@ static inline bool sbi_platform_vendor_ext_check(
static inline int sbi_platform_vendor_ext_provider(
const struct sbi_platform *plat,
long funcid,
struct sbi_trap_regs *regs,
struct sbi_ecall_return *out)
const struct sbi_trap_regs *regs,
unsigned long *out_value,
struct sbi_trap_info *out_trap)
{
if (plat && sbi_platform_ops(plat)->vendor_ext_provider)
if (plat && sbi_platform_ops(plat)->vendor_ext_provider) {
return sbi_platform_ops(plat)->vendor_ext_provider(funcid,
regs, out);
regs,
out_value,
out_trap);
}
return SBI_ENOTSUPP;
}

View File

@@ -23,7 +23,6 @@ struct sbi_scratch;
#define SBI_PMU_HW_CTR_MAX 32
#define SBI_PMU_CTR_MAX (SBI_PMU_HW_CTR_MAX + SBI_PMU_FW_CTR_MAX)
#define SBI_PMU_FIXED_CTR_MASK 0x07
#define SBI_PMU_CY_IR_MASK 0x05
struct sbi_pmu_device {
/** Name of the PMU platform device */
@@ -90,12 +89,6 @@ struct sbi_pmu_device {
* Custom function returning the machine-specific irq-bit.
*/
int (*hw_counter_irq_bit)(void);
/**
* Custom function to inhibit counting of events while in
* specified mode.
*/
void (*hw_counter_filter_mode)(unsigned long flags, int counter_index);
};
/** Get the PMU platform device */

View File

@@ -20,32 +20,28 @@
#define SBI_SCRATCH_FW_SIZE_OFFSET (1 * __SIZEOF_POINTER__)
/** Offset (in sbi_scratch) of the R/W Offset */
#define SBI_SCRATCH_FW_RW_OFFSET (2 * __SIZEOF_POINTER__)
/** Offset of fw_heap_offset member in sbi_scratch */
#define SBI_SCRATCH_FW_HEAP_OFFSET (3 * __SIZEOF_POINTER__)
/** Offset of fw_heap_size_offset member in sbi_scratch */
#define SBI_SCRATCH_FW_HEAP_SIZE_OFFSET (4 * __SIZEOF_POINTER__)
/** Offset of next_arg1 member in sbi_scratch */
#define SBI_SCRATCH_NEXT_ARG1_OFFSET (5 * __SIZEOF_POINTER__)
#define SBI_SCRATCH_NEXT_ARG1_OFFSET (3 * __SIZEOF_POINTER__)
/** Offset of next_addr member in sbi_scratch */
#define SBI_SCRATCH_NEXT_ADDR_OFFSET (6 * __SIZEOF_POINTER__)
#define SBI_SCRATCH_NEXT_ADDR_OFFSET (4 * __SIZEOF_POINTER__)
/** Offset of next_mode member in sbi_scratch */
#define SBI_SCRATCH_NEXT_MODE_OFFSET (7 * __SIZEOF_POINTER__)
#define SBI_SCRATCH_NEXT_MODE_OFFSET (5 * __SIZEOF_POINTER__)
/** Offset of warmboot_addr member in sbi_scratch */
#define SBI_SCRATCH_WARMBOOT_ADDR_OFFSET (8 * __SIZEOF_POINTER__)
#define SBI_SCRATCH_WARMBOOT_ADDR_OFFSET (6 * __SIZEOF_POINTER__)
/** Offset of platform_addr member in sbi_scratch */
#define SBI_SCRATCH_PLATFORM_ADDR_OFFSET (9 * __SIZEOF_POINTER__)
#define SBI_SCRATCH_PLATFORM_ADDR_OFFSET (7 * __SIZEOF_POINTER__)
/** Offset of hartid_to_scratch member in sbi_scratch */
#define SBI_SCRATCH_HARTID_TO_SCRATCH_OFFSET (10 * __SIZEOF_POINTER__)
#define SBI_SCRATCH_HARTID_TO_SCRATCH_OFFSET (8 * __SIZEOF_POINTER__)
/** Offset of trap_exit member in sbi_scratch */
#define SBI_SCRATCH_TRAP_EXIT_OFFSET (11 * __SIZEOF_POINTER__)
#define SBI_SCRATCH_TRAP_EXIT_OFFSET (9 * __SIZEOF_POINTER__)
/** Offset of tmp0 member in sbi_scratch */
#define SBI_SCRATCH_TMP0_OFFSET (12 * __SIZEOF_POINTER__)
#define SBI_SCRATCH_TMP0_OFFSET (10 * __SIZEOF_POINTER__)
/** Offset of options member in sbi_scratch */
#define SBI_SCRATCH_OPTIONS_OFFSET (13 * __SIZEOF_POINTER__)
#define SBI_SCRATCH_OPTIONS_OFFSET (11 * __SIZEOF_POINTER__)
/** Offset of extra space in sbi_scratch */
#define SBI_SCRATCH_EXTRA_SPACE_OFFSET (14 * __SIZEOF_POINTER__)
#define SBI_SCRATCH_EXTRA_SPACE_OFFSET (12 * __SIZEOF_POINTER__)
/** Maximum size of sbi_scratch (4KB) */
#define SBI_SCRATCH_SIZE (0x1000)
#define SBI_SCRATCH_SIZE (0x2000)
/* clang-format on */
@@ -61,10 +57,6 @@ struct sbi_scratch {
unsigned long fw_size;
/** Offset (in bytes) of the R/W section */
unsigned long fw_rw_offset;
/** Offset (in bytes) of the heap area */
unsigned long fw_heap_offset;
/** Size (in bytes) of the heap area */
unsigned long fw_heap_size;
/** Arg1 (or 'a1' register) of next booting stage for this HART */
unsigned long next_arg1;
/** Address of next booting stage for this HART */
@@ -175,9 +167,6 @@ unsigned long sbi_scratch_alloc_offset(unsigned long size);
/** Free-up extra space in sbi_scratch */
void sbi_scratch_free_offset(unsigned long offset);
/** Amount (in bytes) of used space in in sbi_scratch */
unsigned long sbi_scratch_used_space(void);
/** Get pointer from offset in sbi_scratch */
#define sbi_scratch_offset_ptr(scratch, offset) (void *)((char *)(scratch) + (offset))
@@ -185,68 +174,18 @@ unsigned long sbi_scratch_used_space(void);
#define sbi_scratch_thishart_offset_ptr(offset) \
(void *)((char *)sbi_scratch_thishart_ptr() + (offset))
/** Allocate offset for a data type in sbi_scratch */
#define sbi_scratch_alloc_type_offset(__type) \
sbi_scratch_alloc_offset(sizeof(__type))
/** Read a data type from sbi_scratch at given offset */
#define sbi_scratch_read_type(__scratch, __type, __offset) \
({ \
*((__type *)sbi_scratch_offset_ptr((__scratch), (__offset))); \
})
/** Write a data type to sbi_scratch at given offset */
#define sbi_scratch_write_type(__scratch, __type, __offset, __ptr) \
do { \
*((__type *)sbi_scratch_offset_ptr((__scratch), (__offset))) \
= (__type)(__ptr); \
} while (0)
/** Last HART index having a sbi_scratch pointer */
extern u32 last_hartindex_having_scratch;
/** Get last HART index having a sbi_scratch pointer */
#define sbi_scratch_last_hartindex() last_hartindex_having_scratch
/** Check whether a particular HART index is valid or not */
#define sbi_hartindex_valid(__hartindex) \
(((__hartindex) <= sbi_scratch_last_hartindex()) ? true : false)
/** HART index to HART id table */
extern u32 hartindex_to_hartid_table[];
/** Get sbi_scratch from HART index */
#define sbi_hartindex_to_hartid(__hartindex) \
({ \
((__hartindex) <= sbi_scratch_last_hartindex()) ?\
hartindex_to_hartid_table[__hartindex] : -1U; \
})
/** HART index to scratch table */
extern struct sbi_scratch *hartindex_to_scratch_table[];
/** Get sbi_scratch from HART index */
#define sbi_hartindex_to_scratch(__hartindex) \
({ \
((__hartindex) <= sbi_scratch_last_hartindex()) ?\
hartindex_to_scratch_table[__hartindex] : NULL;\
})
/**
* Get logical index for given HART id
* @param hartid physical HART id
* @returns value between 0 to SBI_HARTMASK_MAX_BITS upon success and
* SBI_HARTMASK_MAX_BITS upon failure.
*/
u32 sbi_hartid_to_hartindex(u32 hartid);
/** HART id to scratch table */
extern struct sbi_scratch *hartid_to_scratch_table[];
/** Get sbi_scratch from HART id */
#define sbi_hartid_to_scratch(__hartid) \
sbi_hartindex_to_scratch(sbi_hartid_to_hartindex(__hartid))
hartid_to_scratch_table[__hartid]
/** Check whether particular HART id is valid or not */
#define sbi_hartid_valid(__hartid) \
sbi_hartindex_valid(sbi_hartid_to_hartindex(__hartid))
/** Last HART id having a sbi_scratch pointer */
extern u32 last_hartid_having_scratch;
/** Get last HART id having a sbi_scratch pointer */
#define sbi_scratch_last_hartid() last_hartid_having_scratch
#endif

View File

@@ -48,14 +48,7 @@ struct sbi_system_suspend_device {
/** Name of the system suspend device */
char name[32];
/**
* Check whether sleep type is supported by the device
*
* Returns 0 when @sleep_type supported, SBI_ERR_INVALID_PARAM
* when @sleep_type is reserved, or SBI_ERR_NOT_SUPPORTED when
* @sleep_type is not reserved and is implemented, but the
* platform doesn't support it due to missing dependencies.
*/
/* Check whether sleep type is supported by the device */
int (*system_suspend_check)(u32 sleep_type);
/**

View File

@@ -20,35 +20,34 @@
/* clang-format on */
struct sbi_scratch;
#define SBI_TLB_FIFO_NUM_ENTRIES 128
enum sbi_tlb_type {
SBI_TLB_FENCE_I = 0,
SBI_TLB_SFENCE_VMA,
SBI_TLB_SFENCE_VMA_ASID,
SBI_TLB_HFENCE_GVMA_VMID,
SBI_TLB_HFENCE_GVMA,
SBI_TLB_HFENCE_VVMA_ASID,
SBI_TLB_HFENCE_VVMA,
SBI_TLB_TYPE_MAX,
};
struct sbi_scratch;
struct sbi_tlb_info {
unsigned long start;
unsigned long size;
uint16_t asid;
uint16_t vmid;
enum sbi_tlb_type type;
unsigned long asid;
unsigned long vmid;
void (*local_fn)(struct sbi_tlb_info *tinfo);
struct sbi_hartmask smask;
};
#define SBI_TLB_INFO_INIT(__p, __start, __size, __asid, __vmid, __type, __src) \
void sbi_tlb_local_hfence_vvma(struct sbi_tlb_info *tinfo);
void sbi_tlb_local_hfence_gvma(struct sbi_tlb_info *tinfo);
void sbi_tlb_local_sfence_vma(struct sbi_tlb_info *tinfo);
void sbi_tlb_local_hfence_vvma_asid(struct sbi_tlb_info *tinfo);
void sbi_tlb_local_hfence_gvma_vmid(struct sbi_tlb_info *tinfo);
void sbi_tlb_local_sfence_vma_asid(struct sbi_tlb_info *tinfo);
void sbi_tlb_local_fence_i(struct sbi_tlb_info *tinfo);
#define SBI_TLB_INFO_INIT(__p, __start, __size, __asid, __vmid, __lfn, __src) \
do { \
(__p)->start = (__start); \
(__p)->size = (__size); \
(__p)->asid = (__asid); \
(__p)->vmid = (__vmid); \
(__p)->type = (__type); \
(__p)->local_fn = (__lfn); \
SBI_HARTMASK_INIT_EXCEPT(&(__p)->smask, (__src)); \
} while (0)

View File

@@ -44,7 +44,11 @@ typedef unsigned long long uint64_t;
#error "Unexpected __riscv_xlen"
#endif
#if __STDC_VERSION__ < 202000L
typedef int bool;
#define true 1
#define false 0
#endif
typedef unsigned long ulong;
typedef unsigned long uintptr_t;
typedef unsigned long size_t;
@@ -61,9 +65,6 @@ typedef uint32_t be32_t;
typedef uint64_t le64_t;
typedef uint64_t be64_t;
#define true 1
#define false 0
#define NULL ((void *)0)
#define __packed __attribute__((packed))

View File

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

View File

@@ -93,6 +93,20 @@ void fdt_plic_fixup(void *fdt);
*/
int fdt_reserved_memory_fixup(void *fdt);
/**
* Fix up the reserved memory subnodes in the device tree
*
* This routine adds the no-map property to the reserved memory subnodes so
* that the OS does not map those PMP protected memory regions.
*
* Platform codes must call this helper in their final_init() after fdt_fixups()
* if the OS should not map the PMP protected reserved regions.
*
* @param fdt: device tree blob
* @return zero on success and -ve on failure
*/
int fdt_reserved_memory_nomap_fixup(void *fdt);
/**
* General device tree fix-up
*

View File

@@ -48,9 +48,6 @@ 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);
int fdt_get_node_addr_size_by_name(void *fdt, int node, const char *name,
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);
@@ -59,9 +56,6 @@ 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_isa_extensions(void *fdt, unsigned int hard_id,
unsigned long *extensions);
int fdt_parse_gaisler_uart_node(void *fdt, int nodeoffset,
struct platform_uart_data *uart);
@@ -99,8 +93,7 @@ int fdt_parse_plic_node(void *fdt, int nodeoffset, struct plic_data *plic);
int fdt_parse_plic(void *fdt, struct plic_data *plic, const char *compat);
int fdt_parse_aclint_node(void *fdt, int nodeoffset,
bool for_timer, bool allow_regname,
int fdt_parse_aclint_node(void *fdt, int nodeoffset, bool for_timer,
unsigned long *out_addr1, unsigned long *out_size1,
unsigned long *out_addr2, unsigned long *out_size2,
u32 *out_first_hartid, u32 *out_hart_count);

View File

@@ -13,23 +13,6 @@
#include <sbi/sbi_types.h>
struct fdt_pmu_hw_event_select_map {
uint32_t eidx;
uint64_t select;
};
struct fdt_pmu_hw_event_counter_map {
uint32_t eidx_start;
uint32_t eidx_end;
uint32_t ctr_map;
};
struct fdt_pmu_raw_event_counter_map {
uint64_t select;
uint64_t select_mask;
uint32_t ctr_map;
};
#ifdef CONFIG_FDT_PMU
/**
@@ -43,7 +26,7 @@ struct fdt_pmu_raw_event_counter_map {
*
* @param fdt device tree blob
*/
int fdt_pmu_fixup(void *fdt);
void fdt_pmu_fixup(void *fdt);
/**
* Setup PMU data from device tree
@@ -62,11 +45,6 @@ int fdt_pmu_setup(void *fdt);
*/
uint64_t fdt_pmu_get_select_value(uint32_t event_idx);
/** The event index to selector value table instance */
extern struct fdt_pmu_hw_event_select_map fdt_pmu_evt_select[];
/** The number of valid entries in fdt_pmu_evt_select[] */
extern uint32_t hw_event_count;
#else
static inline void fdt_pmu_fixup(void *fdt) { }

View File

@@ -15,6 +15,9 @@
/** Representation of a I2C adapter */
struct i2c_adapter {
/** Pointer to I2C driver owning this I2C adapter */
void *driver;
/** Unique ID of the I2C adapter assigned by the driver */
int id;

View File

@@ -13,23 +13,30 @@
#ifndef _IPI_ANDES_PLICSW_H_
#define _IPI_ANDES_PLICSW_H_
#define PLICSW_PRIORITY_BASE 0x4
#define PLICSW_PRIORITY_BASE 0x4
#define PLICSW_PENDING_BASE 0x1000
#define PLICSW_PENDING_BASE 0x1000
#define PLICSW_PENDING_STRIDE 0x8
#define PLICSW_ENABLE_BASE 0x2000
#define PLICSW_ENABLE_STRIDE 0x80
#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_CONTEXT_BASE 0x200000
#define PLICSW_CONTEXT_STRIDE 0x1000
#define PLICSW_CONTEXT_CLAIM 0x4
#define PLICSW_REGION_ALIGN 0x1000
#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);

View File

@@ -14,7 +14,6 @@
struct plic_data {
unsigned long addr;
unsigned long size;
unsigned long num_src;
};

View File

@@ -1,31 +0,0 @@
/*
* SPDX-License-Identifier: BSD-2-Clause
*
* Copyright (c) 2023 Ventana Micro Systems Inc.
*
* Authors:
* Anup Patel <apatel@ventanamicro.com>
*/
#ifndef __FDT_REGMAP_H__
#define __FDT_REGMAP_H__
#include <sbi_utils/regmap/regmap.h>
struct fdt_phandle_args;
/** FDT based regmap driver */
struct fdt_regmap {
const struct fdt_match *match_table;
int (*init)(void *fdt, int nodeoff, u32 phandle,
const struct fdt_match *match);
};
/** Get regmap instance based on phandle */
int fdt_regmap_get_by_phandle(void *fdt, u32 phandle,
struct regmap **out_rmap);
/** Get regmap instance based on "regmap' property of the specified DT node */
int fdt_regmap_get(void *fdt, int nodeoff, struct regmap **out_rmap);
#endif

View File

@@ -1,67 +0,0 @@
/*
* SPDX-License-Identifier: BSD-2-Clause
*
* Copyright (c) 2023 Ventana Micro Systems Inc.
*
* Authors:
* Anup Patel <apatel@ventanamicro.com>
*/
#ifndef __REGMAP_H__
#define __REGMAP_H__
#include <sbi/sbi_types.h>
#include <sbi/sbi_list.h>
/** Representation of a regmap instance */
struct regmap {
/** Uniquie ID of the regmap instance assigned by the driver */
unsigned int id;
/** Configuration of regmap registers */
int reg_shift;
int reg_stride;
unsigned int reg_base;
unsigned int reg_max;
/** Read a regmap register */
int (*reg_read)(struct regmap *rmap, unsigned int reg,
unsigned int *val);
/** Write a regmap register */
int (*reg_write)(struct regmap *rmap, unsigned int reg,
unsigned int val);
/** Read-modify-write a regmap register */
int (*reg_update_bits)(struct regmap *rmap, unsigned int reg,
unsigned int mask, unsigned int val);
/** List */
struct sbi_dlist node;
};
static inline struct regmap *to_regmap(struct sbi_dlist *node)
{
return container_of(node, struct regmap, node);
}
/** Find a registered regmap instance */
struct regmap *regmap_find(unsigned int id);
/** Register a regmap instance */
int regmap_add(struct regmap *rmap);
/** Un-register a regmap instance */
void regmap_remove(struct regmap *rmap);
/** Read a register in a regmap instance */
int regmap_read(struct regmap *rmap, unsigned int reg, unsigned int *val);
/** Write a register in a regmap instance */
int regmap_write(struct regmap *rmap, unsigned int reg, unsigned int val);
/** Read-modify-write a register in a regmap instance */
int regmap_update_bits(struct regmap *rmap, unsigned int reg,
unsigned int mask, unsigned int val);
#endif

View File

@@ -38,7 +38,7 @@ enum semihosting_open_mode {
#ifdef CONFIG_SERIAL_SEMIHOSTING
int semihosting_init(void);
int semihosting_enabled(void);
bool semihosting_enabled(void);
#else
static inline int semihosting_init(void) { return SBI_ENODEV; }
static inline int semihosting_enabled(void) { return 0; }

View File

@@ -0,0 +1,17 @@
/*
* SPDX-License-Identifier: BSD-3-Clause
*
* Copyright (c) 2020 Western Digital Corporation or its affiliates.
*
* Authors:
* Anup Patel <anup.patel@wdc.com>
*/
#ifndef __SYS_SIFIVE_TEST_H__
#define __SYS_SIFIVE_TEST_H__
#include <sbi/sbi_types.h>
int sifive_test_init(unsigned long base);
#endif

View File

@@ -35,6 +35,7 @@ struct aclint_mtimer_data {
u32 hart_count;
bool has_64bit_mmio;
bool has_shared_mtime;
bool use_extern_domain;
/* Private details (initialized and used by ACLINT MTIMER library) */
struct aclint_mtimer_data *time_delta_reference;
unsigned long time_delta_computed;

View File

@@ -0,0 +1,21 @@
/*
* SPDX-License-Identifier: BSD-2-Clause
*
* Copyright (c) 2025 SOPHGO Corporation
*
* Authors:
* Chao Wei <chao.wei@sophgo.com>
*/
#ifndef __SG2042_GMT_H__
#define __SG2042_GMT_H__
int sg2042gmt_cold_timer_init(unsigned long mtimer_base,
unsigned long mtimecmp_base,
unsigned long mtimecmp_size,
unsigned long delcared_freq,
unsigned long actual_freq,
unsigned long timecmp_freq);
int sg2042gmt_warm_timer_init(void);
#endif /* __SG2042_GMT_H__ */

View File

@@ -34,10 +34,6 @@ config SBI_ECALL_DBCN
bool "Debug Console extension"
default y
config SBI_ECALL_CPPC
bool "CPPC extension"
default y
config SBI_ECALL_LEGACY
bool "SBI v0.1 legacy extensions"
default y

View File

@@ -43,9 +43,6 @@ libsbi-objs-$(CONFIG_SBI_ECALL_PMU) += sbi_ecall_pmu.o
carray-sbi_ecall_exts-$(CONFIG_SBI_ECALL_DBCN) += ecall_dbcn
libsbi-objs-$(CONFIG_SBI_ECALL_DBCN) += sbi_ecall_dbcn.o
carray-sbi_ecall_exts-$(CONFIG_SBI_ECALL_CPPC) += ecall_cppc
libsbi-objs-$(CONFIG_SBI_ECALL_CPPC) += sbi_ecall_cppc.o
carray-sbi_ecall_exts-$(CONFIG_SBI_ECALL_LEGACY) += ecall_legacy
libsbi-objs-$(CONFIG_SBI_ECALL_LEGACY) += sbi_ecall_legacy.o
@@ -59,7 +56,6 @@ libsbi-objs-y += sbi_domain.o
libsbi-objs-y += sbi_emulate_csr.o
libsbi-objs-y += sbi_fifo.o
libsbi-objs-y += sbi_hart.o
libsbi-objs-y += sbi_heap.o
libsbi-objs-y += sbi_math.o
libsbi-objs-y += sbi_hfence.o
libsbi-objs-y += sbi_hsm.o
@@ -78,4 +74,3 @@ libsbi-objs-y += sbi_tlb.o
libsbi-objs-y += sbi_trap.o
libsbi-objs-y += sbi_unpriv.o
libsbi-objs-y += sbi_expected_trap.o
libsbi-objs-y += sbi_cppc.o

View File

@@ -128,8 +128,6 @@ unsigned long csr_read_num(int csr_num)
switchcase_csr_read_8(CSR_MHPMCOUNTER8, ret)
switchcase_csr_read_16(CSR_MHPMCOUNTER16, ret)
switchcase_csr_read(CSR_MCOUNTINHIBIT, ret)
switchcase_csr_read(CSR_MCYCLECFG, ret)
switchcase_csr_read(CSR_MINSTRETCFG, ret)
switchcase_csr_read(CSR_MHPMEVENT3, ret)
switchcase_csr_read_4(CSR_MHPMEVENT4, ret)
switchcase_csr_read_8(CSR_MHPMEVENT8, ret)
@@ -141,12 +139,6 @@ 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 M[CYCLE, INSTRET]CFGH are available only if smcntrpmf
* extension is present. The caller must ensure that.
*/
switchcase_csr_read(CSR_MCYCLECFGH, ret)
switchcase_csr_read(CSR_MINSTRETCFGH, ret)
/**
* The CSR range MHPMEVENT[3-16]H are available only if sscofpmf
* extension is present. The caller must ensure that.
@@ -160,7 +152,7 @@ unsigned long csr_read_num(int csr_num)
default:
sbi_panic("%s: Unknown CSR %#x", __func__, csr_num);
break;
}
};
return ret;
@@ -214,16 +206,12 @@ void csr_write_num(int csr_num, unsigned long val)
switchcase_csr_write_4(CSR_MHPMCOUNTER4H, val)
switchcase_csr_write_8(CSR_MHPMCOUNTER8H, val)
switchcase_csr_write_16(CSR_MHPMCOUNTER16H, val)
switchcase_csr_write(CSR_MCYCLECFGH, val)
switchcase_csr_write(CSR_MINSTRETCFGH, val)
switchcase_csr_write(CSR_MHPMEVENT3H, val)
switchcase_csr_write_4(CSR_MHPMEVENT4H, val)
switchcase_csr_write_8(CSR_MHPMEVENT8H, val)
switchcase_csr_write_16(CSR_MHPMEVENT16H, val)
#endif
switchcase_csr_write(CSR_MCOUNTINHIBIT, val)
switchcase_csr_write(CSR_MCYCLECFG, val)
switchcase_csr_write(CSR_MINSTRETCFG, val)
switchcase_csr_write(CSR_MHPMEVENT3, val)
switchcase_csr_write_4(CSR_MHPMEVENT4, val)
switchcase_csr_write_8(CSR_MHPMEVENT8, val)
@@ -232,7 +220,7 @@ void csr_write_num(int csr_num, unsigned long val)
default:
sbi_panic("%s: Unknown CSR %#x", __func__, csr_num);
break;
}
};
#undef switchcase_csr_write_64
#undef switchcase_csr_write_32
@@ -258,48 +246,6 @@ static unsigned long ctz(unsigned long x)
return ret;
}
int pmp_disable(unsigned int n)
{
int pmpcfg_csr, pmpcfg_shift;
unsigned long cfgmask, pmpcfg;
if (n >= PMP_COUNT)
return SBI_EINVAL;
#if __riscv_xlen == 32
pmpcfg_csr = CSR_PMPCFG0 + (n >> 2);
pmpcfg_shift = (n & 3) << 3;
#elif __riscv_xlen == 64
pmpcfg_csr = (CSR_PMPCFG0 + (n >> 2)) & ~1;
pmpcfg_shift = (n & 7) << 3;
#else
# error "Unexpected __riscv_xlen"
#endif
/* Clear the address matching bits to disable the pmp entry */
cfgmask = ~(0xffUL << pmpcfg_shift);
pmpcfg = (csr_read_num(pmpcfg_csr) & cfgmask);
csr_write_num(pmpcfg_csr, pmpcfg);
return SBI_OK;
}
int is_pmp_entry_mapped(unsigned long entry)
{
unsigned long prot;
unsigned long addr;
unsigned long log2len;
pmp_get(entry, &prot, &addr, &log2len);
/* If address matching bits are non-zero, the entry is enable */
if (prot & PMP_A)
return true;
return false;
}
int pmp_set(unsigned int n, unsigned long prot, unsigned long addr,
unsigned long log2len)
{

View File

@@ -12,10 +12,6 @@
#include <sbi/riscv_atomic.h>
#include <sbi/riscv_barrier.h>
#ifndef __riscv_atomic
#error "opensbi strongly relies on the A extension of RISC-V"
#endif
long atomic_read(atomic_t *atom)
{
long ret = atom->counter;
@@ -83,51 +79,175 @@ long atomic_sub_return(atomic_t *atom, long value)
(__typeof__(*(ptr))) __axchg((ptr), _x_, sizeof(*(ptr))); \
})
#define __xchg(ptr, new, size) \
({ \
__typeof__(ptr) __ptr = (ptr); \
__typeof__(*(ptr)) __new = (new); \
__typeof__(*(ptr)) __ret; \
register unsigned int __rc; \
switch (size) { \
case 4: \
__asm__ __volatile__("0: lr.w %0, %2\n" \
" sc.w.rl %1, %z3, %2\n" \
" bnez %1, 0b\n" \
" fence rw, rw\n" \
: "=&r"(__ret), "=&r"(__rc), \
"+A"(*__ptr) \
: "rJ"(__new) \
: "memory"); \
break; \
case 8: \
__asm__ __volatile__("0: lr.d %0, %2\n" \
" sc.d.rl %1, %z3, %2\n" \
" bnez %1, 0b\n" \
" fence rw, rw\n" \
: "=&r"(__ret), "=&r"(__rc), \
"+A"(*__ptr) \
: "rJ"(__new) \
: "memory"); \
break; \
default: \
break; \
} \
__ret; \
})
#define xchg(ptr, n) \
({ \
__typeof__(*(ptr)) _n_ = (n); \
(__typeof__(*(ptr))) __xchg((ptr), _n_, sizeof(*(ptr))); \
})
#define __cmpxchg(ptr, old, new, size) \
({ \
__typeof__(ptr) __ptr = (ptr); \
__typeof__(*(ptr)) __old = (old); \
__typeof__(*(ptr)) __new = (new); \
__typeof__(*(ptr)) __ret; \
register unsigned int __rc; \
switch (size) { \
case 4: \
__asm__ __volatile__("0: lr.w %0, %2\n" \
" bne %0, %z3, 1f\n" \
" sc.w.rl %1, %z4, %2\n" \
" bnez %1, 0b\n" \
" fence rw, rw\n" \
"1:\n" \
: "=&r"(__ret), "=&r"(__rc), \
"+A"(*__ptr) \
: "rJ"(__old), "rJ"(__new) \
: "memory"); \
break; \
case 8: \
__asm__ __volatile__("0: lr.d %0, %2\n" \
" bne %0, %z3, 1f\n" \
" sc.d.rl %1, %z4, %2\n" \
" bnez %1, 0b\n" \
" fence rw, rw\n" \
"1:\n" \
: "=&r"(__ret), "=&r"(__rc), \
"+A"(*__ptr) \
: "rJ"(__old), "rJ"(__new) \
: "memory"); \
break; \
default: \
break; \
} \
__ret; \
})
#define cmpxchg(ptr, o, n) \
({ \
__typeof__(*(ptr)) _o_ = (o); \
__typeof__(*(ptr)) _n_ = (n); \
(__typeof__(*(ptr))) \
__cmpxchg((ptr), _o_, _n_, sizeof(*(ptr))); \
})
long atomic_cmpxchg(atomic_t *atom, long oldval, long newval)
{
#ifdef __riscv_atomic
return __sync_val_compare_and_swap(&atom->counter, oldval, newval);
#else
return cmpxchg(&atom->counter, oldval, newval);
#endif
}
long atomic_xchg(atomic_t *atom, long newval)
{
/* Atomically set new value and return old value. */
#ifdef __riscv_atomic
return axchg(&atom->counter, newval);
#else
return xchg(&atom->counter, newval);
#endif
}
unsigned int atomic_raw_xchg_uint(volatile unsigned int *ptr,
unsigned int newval)
{
/* Atomically set new value and return old value. */
#ifdef __riscv_atomic
return axchg(ptr, newval);
#else
return xchg(ptr, newval);
#endif
}
unsigned long atomic_raw_xchg_ulong(volatile unsigned long *ptr,
unsigned long newval)
{
/* Atomically set new value and return old value. */
#ifdef __riscv_atomic
return axchg(ptr, newval);
#else
return xchg(ptr, newval);
#endif
}
int atomic_raw_set_bit(int nr, volatile unsigned long *addr)
#if (__SIZEOF_POINTER__ == 8)
#define __AMO(op) "amo" #op ".d"
#elif (__SIZEOF_POINTER__ == 4)
#define __AMO(op) "amo" #op ".w"
#else
#error "Unexpected __SIZEOF_POINTER__"
#endif
#define __atomic_op_bit_ord(op, mod, nr, addr, ord) \
({ \
unsigned long __res, __mask; \
__mask = BIT_MASK(nr); \
__asm__ __volatile__(__AMO(op) #ord " %0, %2, %1" \
: "=r"(__res), "+A"(addr[BIT_WORD(nr)]) \
: "r"(mod(__mask)) \
: "memory"); \
__res; \
})
#define __atomic_op_bit(op, mod, nr, addr) \
__atomic_op_bit_ord(op, mod, nr, addr, .aqrl)
/* Bitmask modifiers */
#define __NOP(x) (x)
#define __NOT(x) (~(x))
inline int atomic_raw_set_bit(int nr, volatile unsigned long *addr)
{
unsigned long res, mask = BIT_MASK(nr);
res = __atomic_fetch_or(&addr[BIT_WORD(nr)], mask, __ATOMIC_RELAXED);
return res & mask ? 1 : 0;
return __atomic_op_bit(or, __NOP, nr, addr);
}
int atomic_raw_clear_bit(int nr, volatile unsigned long *addr)
inline int atomic_raw_clear_bit(int nr, volatile unsigned long *addr)
{
unsigned long res, mask = BIT_MASK(nr);
res = __atomic_fetch_and(&addr[BIT_WORD(nr)], ~mask, __ATOMIC_RELAXED);
return res & mask ? 1 : 0;
return __atomic_op_bit(and, __NOT, nr, addr);
}
int atomic_set_bit(int nr, atomic_t *atom)
inline int atomic_set_bit(int nr, atomic_t *atom)
{
return atomic_raw_set_bit(nr, (unsigned long *)&atom->counter);
}
int atomic_clear_bit(int nr, atomic_t *atom)
inline int atomic_clear_bit(int nr, atomic_t *atom)
{
return atomic_raw_clear_bit(nr, (unsigned long *)&atom->counter);
}

View File

@@ -37,22 +37,28 @@ int sbi_getc(void)
return -1;
}
void sbi_putc(char ch)
{
if (console_dev && console_dev->console_putc) {
if (ch == '\n')
console_dev->console_putc('\r');
console_dev->console_putc(ch);
}
}
static unsigned long nputs(const char *str, unsigned long len)
{
unsigned long i;
unsigned long i, ret;
if (console_dev) {
if (console_dev->console_puts)
return console_dev->console_puts(str, len);
else if (console_dev->console_putc) {
for (i = 0; i < len; i++) {
if (str[i] == '\n')
console_dev->console_putc('\r');
console_dev->console_putc(str[i]);
}
}
if (console_dev && console_dev->console_puts) {
ret = console_dev->console_puts(str, len);
} else {
for (i = 0; i < len; i++)
sbi_putc(str[i]);
ret = len;
}
return len;
return ret;
}
static void nputs_all(const char *str, unsigned long len)
@@ -63,11 +69,6 @@ static void nputs_all(const char *str, unsigned long len)
p += nputs(&str[p], len - p);
}
void sbi_putc(char ch)
{
nputs_all(&ch, 1);
}
void sbi_puts(const char *str)
{
unsigned long len = sbi_strlen(str);
@@ -119,8 +120,6 @@ unsigned long sbi_ngets(char *str, unsigned long len)
#define PAD_RIGHT 1
#define PAD_ZERO 2
#define PAD_ALTERNATE 4
#define PAD_SIGN 8
#define USE_TBUF 16
#define PRINT_BUF_LEN 64
#define va_start(v, l) __builtin_va_start((v), l)
@@ -128,7 +127,7 @@ unsigned long sbi_ngets(char *str, unsigned long len)
#define va_arg __builtin_va_arg
typedef __builtin_va_list va_list;
static void printc(char **out, u32 *out_len, char ch, int flags)
static void printc(char **out, u32 *out_len, char ch)
{
if (!out) {
sbi_putc(ch);
@@ -142,66 +141,60 @@ static void printc(char **out, u32 *out_len, char ch, int flags)
if (!out_len || *out_len > 1) {
*(*out)++ = ch;
**out = '\0';
if (out_len) {
--(*out_len);
if ((flags & USE_TBUF) && *out_len == 1) {
nputs_all(console_tbuf, CONSOLE_TBUF_MAX - *out_len);
*out = console_tbuf;
*out_len = CONSOLE_TBUF_MAX;
}
}
}
if (out_len && *out_len > 0)
--(*out_len);
}
static int prints(char **out, u32 *out_len, const char *string, int width,
int flags)
{
int pc = 0;
width -= sbi_strlen(string);
int pc = 0;
char padchar = ' ';
if (width > 0) {
int len = 0;
const char *ptr;
for (ptr = string; *ptr; ++ptr)
++len;
if (len >= width)
width = 0;
else
width -= len;
if (flags & PAD_ZERO)
padchar = '0';
}
if (!(flags & PAD_RIGHT)) {
for (; width > 0; --width) {
printc(out, out_len, flags & PAD_ZERO ? '0' : ' ', flags);
printc(out, out_len, padchar);
++pc;
}
}
for (; *string; ++string) {
printc(out, out_len, *string, flags);
printc(out, out_len, *string);
++pc;
}
for (; width > 0; --width) {
printc(out, out_len, ' ', flags);
printc(out, out_len, padchar);
++pc;
}
return pc;
}
static int printi(char **out, u32 *out_len, long long i,
int width, int flags, int type)
static int printi(char **out, u32 *out_len, long long i, int b, int sg,
int width, int flags, int letbase)
{
int pc = 0;
char *s, sign = 0, letbase, print_buf[PRINT_BUF_LEN];
unsigned long long u, b, t;
char print_buf[PRINT_BUF_LEN];
char *s;
int neg = 0, pc = 0;
u64 t;
unsigned long long u = i;
b = 10;
letbase = 'a';
if (type == 'o')
b = 8;
else if (type == 'x' || type == 'X' || type == 'p' || type == 'P') {
b = 16;
letbase &= ~0x20;
letbase |= type & 0x20;
}
u = i;
sign = 0;
if (type == 'i' || type == 'd') {
if ((flags & PAD_SIGN) && i > 0)
sign = '+';
if (i < 0) {
sign = '-';
u = -i;
}
if (sg && b == 10 && i < 0) {
neg = 1;
u = -i;
}
s = print_buf + PRINT_BUF_LEN - 1;
@@ -219,33 +212,23 @@ static int printi(char **out, u32 *out_len, long long i,
}
}
if (flags & PAD_ZERO) {
if (sign) {
printc(out, out_len, sign, flags);
if (flags & PAD_ALTERNATE) {
if ((b == 16) && (letbase == 'A')) {
*--s = 'X';
} else if ((b == 16) && (letbase == 'a')) {
*--s = 'x';
}
*--s = '0';
}
if (neg) {
if (width && (flags & PAD_ZERO)) {
printc(out, out_len, '-');
++pc;
--width;
} else {
*--s = '-';
}
if (i && (flags & PAD_ALTERNATE)) {
if (b == 16 || b == 8) {
printc(out, out_len, '0', flags);
++pc;
--width;
}
if (b == 16) {
printc(out, out_len, 'x' - 'a' + letbase, flags);
++pc;
--width;
}
}
} else {
if (i && (flags & PAD_ALTERNATE)) {
if (b == 16)
*--s = 'x' - 'a' + letbase;
if (b == 16 || b == 8)
*--s = '0';
}
if (sign)
*--s = sign;
}
return pc + prints(out, out_len, s, width, flags);
@@ -253,10 +236,10 @@ static int printi(char **out, u32 *out_len, long long i,
static int print(char **out, u32 *out_len, const char *format, va_list args)
{
bool flags_done;
int width, flags, pc = 0;
char type, scr[2], *tout;
char scr[2], *tout;
bool use_tbuf = (!out) ? true : false;
unsigned long long tmp;
/*
* The console_tbuf is protected by console_out_lock and
@@ -270,51 +253,33 @@ static int print(char **out, u32 *out_len, const char *format, va_list args)
out_len = &console_tbuf_len;
}
/* handle special case: *out_len == 1*/
if (out) {
if(!out_len || *out_len)
**out = '\0';
}
for (; *format != 0; ++format) {
width = flags = 0;
if (use_tbuf)
flags |= USE_TBUF;
if (use_tbuf && !console_tbuf_len) {
nputs_all(console_tbuf, CONSOLE_TBUF_MAX);
console_tbuf_len = CONSOLE_TBUF_MAX;
tout = console_tbuf;
}
if (*format == '%') {
++format;
width = flags = 0;
if (*format == '\0')
break;
if (*format == '%')
goto literal;
/* Get flags */
flags_done = false;
while (!flags_done) {
switch (*format) {
case '-':
flags |= PAD_RIGHT;
break;
case '+':
flags |= PAD_SIGN;
break;
case '#':
flags |= PAD_ALTERNATE;
break;
case '0':
flags |= PAD_ZERO;
break;
case ' ':
case '\'':
/* Ignored flags, do nothing */
break;
default:
flags_done = true;
break;
}
if (!flags_done)
++format;
if (*format == '-') {
++format;
flags = PAD_RIGHT;
}
if (*format == '#') {
++format;
flags |= PAD_ALTERNATE;
}
while (*format == '0') {
++format;
flags |= PAD_ZERO;
}
if (flags & PAD_RIGHT)
flags &= ~PAD_ZERO;
/* Get width */
for (; *format >= '0' && *format <= '9'; ++format) {
width *= 10;
@@ -328,47 +293,83 @@ 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),
width, flags, *format);
10, 1, width, flags, '0');
continue;
}
if ((*format == 'u') || (*format == 'o')
|| (*format == 'x') || (*format == 'X')) {
pc += printi(out, out_len, va_arg(args, unsigned int),
width, flags, *format);
if (*format == 'x') {
pc += printi(out, out_len,
va_arg(args, unsigned int), 16, 0,
width, flags, 'a');
continue;
}
if ((*format == 'p') || (*format == 'P')) {
pc += printi(out, out_len, (uintptr_t)va_arg(args, void*),
width, flags, *format);
if (*format == 'X') {
pc += printi(out, out_len,
va_arg(args, unsigned int), 16, 0,
width, flags, 'A');
continue;
}
if (*format == 'l') {
type = 'i';
if (format[1] == 'l') {
++format;
if ((format[1] == 'u') || (format[1] == 'o')
|| (format[1] == 'd') || (format[1] == 'i')
|| (format[1] == 'x') || (format[1] == 'X')) {
++format;
type = *format;
}
pc += printi(out, out_len, va_arg(args, long long),
width, flags, type);
continue;
if (*format == 'u') {
pc += printi(out, out_len,
va_arg(args, unsigned int), 10, 0,
width, flags, 'a');
continue;
}
if (*format == 'p') {
pc += printi(out, out_len,
va_arg(args, unsigned long), 16, 0,
width, flags, 'a');
continue;
}
if (*format == 'P') {
pc += printi(out, out_len,
va_arg(args, unsigned long), 16, 0,
width, flags, 'A');
continue;
}
if (*format == 'l' && *(format + 1) == 'l') {
tmp = va_arg(args, unsigned long long);
if (*(format + 2) == 'u') {
format += 2;
pc += printi(out, out_len, tmp, 10, 0,
width, flags, 'a');
} else if (*(format + 2) == 'x') {
format += 2;
pc += printi(out, out_len, tmp, 16, 0,
width, flags, 'a');
} else if (*(format + 2) == 'X') {
format += 2;
pc += printi(out, out_len, tmp, 16, 0,
width, flags, 'A');
} else {
format += 1;
pc += printi(out, out_len, tmp, 10, 1,
width, flags, '0');
}
if ((format[1] == 'u') || (format[1] == 'o')
|| (format[1] == 'd') || (format[1] == 'i')
|| (format[1] == 'x') || (format[1] == 'X')) {
++format;
type = *format;
}
if ((type == 'd') || (type == 'i'))
pc += printi(out, out_len, va_arg(args, long),
width, flags, type);
else
pc += printi(out, out_len, va_arg(args, unsigned long),
width, flags, type);
continue;
} else if (*format == 'l') {
if (*(format + 1) == 'u') {
format += 1;
pc += printi(
out, out_len,
va_arg(args, unsigned long), 10,
0, width, flags, 'a');
} else if (*(format + 1) == 'x') {
format += 1;
pc += printi(
out, out_len,
va_arg(args, unsigned long), 16,
0, width, flags, 'a');
} else if (*(format + 1) == 'X') {
format += 1;
pc += printi(
out, out_len,
va_arg(args, unsigned long), 16,
0, width, flags, 'A');
} else {
pc += printi(out, out_len,
va_arg(args, long), 10, 1,
width, flags, '0');
}
}
if (*format == 'c') {
/* char are converted to int then pushed on the stack */
@@ -379,7 +380,7 @@ static int print(char **out, u32 *out_len, const char *format, va_list args)
}
} else {
literal:
printc(out, out_len, *format, flags);
printc(out, out_len, *format);
++pc;
}
}
@@ -480,11 +481,5 @@ void sbi_console_set_device(const struct sbi_console_device *dev)
int sbi_console_init(struct sbi_scratch *scratch)
{
int rc = sbi_platform_console_init(sbi_platform_ptr(scratch));
/* console is not a necessary device */
if (rc == SBI_ENODEV)
return 0;
return rc;
return sbi_platform_console_init(sbi_platform_ptr(scratch));
}

View File

@@ -1,110 +0,0 @@
/*
* SPDX-License-Identifier: BSD-2-Clause
*
* Copyright (c) 2023 Ventana Micro Systems Inc.
*
*/
#include <sbi/sbi_error.h>
#include <sbi/sbi_cppc.h>
static const struct sbi_cppc_device *cppc_dev = NULL;
const struct sbi_cppc_device *sbi_cppc_get_device(void)
{
return cppc_dev;
}
void sbi_cppc_set_device(const struct sbi_cppc_device *dev)
{
if (!dev || cppc_dev)
return;
cppc_dev = dev;
}
static bool sbi_cppc_is_reserved(unsigned long reg)
{
if ((reg > SBI_CPPC_ACPI_LAST && reg < SBI_CPPC_TRANSITION_LATENCY) ||
reg > SBI_CPPC_NON_ACPI_LAST)
return true;
return false;
}
static bool sbi_cppc_readable(unsigned long reg)
{
/* there are no write-only cppc registers currently */
return true;
}
static bool sbi_cppc_writable(unsigned long reg)
{
switch (reg) {
case SBI_CPPC_HIGHEST_PERF:
case SBI_CPPC_NOMINAL_PERF:
case SBI_CPPC_LOW_NON_LINEAR_PERF:
case SBI_CPPC_LOWEST_PERF:
case SBI_CPPC_GUARANTEED_PERF:
case SBI_CPPC_CTR_WRAP_TIME:
case SBI_CPPC_REFERENCE_CTR:
case SBI_CPPC_DELIVERED_CTR:
case SBI_CPPC_REFERENCE_PERF:
case SBI_CPPC_LOWEST_FREQ:
case SBI_CPPC_NOMINAL_FREQ:
case SBI_CPPC_TRANSITION_LATENCY:
return false;
}
return true;
}
int sbi_cppc_probe(unsigned long reg)
{
if (!cppc_dev || !cppc_dev->cppc_probe)
return SBI_EFAIL;
/* Check whether register is reserved */
if (sbi_cppc_is_reserved(reg))
return SBI_ERR_INVALID_PARAM;
return cppc_dev->cppc_probe(reg);
}
int sbi_cppc_read(unsigned long reg, uint64_t *val)
{
int ret;
if (!cppc_dev || !cppc_dev->cppc_read)
return SBI_EFAIL;
/* Check whether register is implemented */
ret = sbi_cppc_probe(reg);
if (ret <= 0)
return SBI_ERR_NOT_SUPPORTED;
/* Check whether the register is write-only */
if (!sbi_cppc_readable(reg))
return SBI_ERR_DENIED;
return cppc_dev->cppc_read(reg, val);
}
int sbi_cppc_write(unsigned long reg, uint64_t val)
{
int ret;
if (!cppc_dev || !cppc_dev->cppc_write)
return SBI_EFAIL;
/* Check whether register is implemented */
ret = sbi_cppc_probe(reg);
if (ret <= 0)
return SBI_ERR_NOT_SUPPORTED;
/* Check whether the register is read-only */
if (!sbi_cppc_writable(reg))
return SBI_ERR_DENIED;
return cppc_dev->cppc_write(reg, val);
}

View File

@@ -11,7 +11,6 @@
#include <sbi/sbi_console.h>
#include <sbi/sbi_domain.h>
#include <sbi/sbi_hartmask.h>
#include <sbi/sbi_heap.h>
#include <sbi/sbi_hsm.h>
#include <sbi/sbi_math.h>
#include <sbi/sbi_platform.h>
@@ -23,49 +22,29 @@
* the array to be null-terminated.
*/
struct sbi_domain *domidx_to_domain_table[SBI_DOMAIN_MAX_INDEX + 1] = { 0 };
struct sbi_domain *hartid_to_domain_table[SBI_HARTMASK_MAX_BITS] = { 0 };
static u32 domain_count = 0;
static bool domain_finalized = false;
static struct sbi_hartmask root_hmask = { 0 };
#define ROOT_REGION_MAX 16
static u32 root_memregs_count = 0;
static struct sbi_domain_memregion root_fw_region;
static struct sbi_domain_memregion root_memregs[ROOT_REGION_MAX + 1] = { 0 };
struct sbi_domain root = {
.name = "root",
.possible_harts = NULL,
.regions = NULL,
.possible_harts = &root_hmask,
.regions = root_memregs,
.system_reset_allowed = true,
.system_suspend_allowed = true,
.fw_region_inited = false,
};
static unsigned long domain_hart_ptr_offset;
struct sbi_domain *sbi_hartindex_to_domain(u32 hartindex)
{
struct sbi_scratch *scratch;
scratch = sbi_hartindex_to_scratch(hartindex);
if (!scratch || !domain_hart_ptr_offset)
return NULL;
return sbi_scratch_read_type(scratch, void *, domain_hart_ptr_offset);
}
static void update_hartindex_to_domain(u32 hartindex, struct sbi_domain *dom)
{
struct sbi_scratch *scratch;
scratch = sbi_hartindex_to_scratch(hartindex);
if (!scratch)
return;
sbi_scratch_write_type(scratch, void *, domain_hart_ptr_offset, dom);
}
bool sbi_domain_is_assigned_hart(const struct sbi_domain *dom, u32 hartid)
{
if (dom)
return sbi_hartmask_test_hartid(hartid, &dom->assigned_harts);
return sbi_hartmask_test_hart(hartid, &dom->assigned_harts);
return false;
}
@@ -73,15 +52,31 @@ bool sbi_domain_is_assigned_hart(const struct sbi_domain *dom, u32 hartid)
ulong sbi_domain_get_assigned_hartmask(const struct sbi_domain *dom,
ulong hbase)
{
ulong ret = 0;
for (int i = 0; i < 8 * sizeof(ret); i++) {
if (sbi_domain_is_assigned_hart(dom, hbase + i))
ret |= 1UL << i;
ulong ret, bword, boff;
if (!dom)
return 0;
bword = BIT_WORD(hbase);
boff = BIT_WORD_OFFSET(hbase);
ret = sbi_hartmask_bits(&dom->assigned_harts)[bword++] >> boff;
if (boff && bword < BIT_WORD(SBI_HARTMASK_MAX_BITS)) {
ret |= (sbi_hartmask_bits(&dom->assigned_harts)[bword] &
(BIT(boff) - 1UL)) << (BITS_PER_LONG - boff);
}
return ret;
}
static void domain_memregion_initfw(struct sbi_domain_memregion *reg)
{
if (!reg)
return;
sbi_memcpy(reg, &root_fw_region, sizeof(*reg));
}
void sbi_domain_memregion_init(unsigned long addr,
unsigned long size,
unsigned long flags,
@@ -193,11 +188,12 @@ static bool is_region_subset(const struct sbi_domain_memregion *regA,
return false;
}
/** Check if regionA can be replaced by regionB */
static bool is_region_compatible(const struct sbi_domain_memregion *regA,
const struct sbi_domain_memregion *regB)
/** Check if regionA conflicts regionB */
static bool is_region_conflict(const struct sbi_domain_memregion *regA,
const struct sbi_domain_memregion *regB)
{
if (is_region_subset(regA, regB) && regA->flags == regB->flags)
if ((is_region_subset(regA, regB) || is_region_subset(regB, regA)) &&
regA->flags == regB->flags)
return true;
return false;
@@ -255,26 +251,12 @@ static const struct sbi_domain_memregion *find_next_subset_region(
return ret;
}
static void swap_region(struct sbi_domain_memregion* reg1,
struct sbi_domain_memregion* reg2)
{
struct sbi_domain_memregion treg;
sbi_memcpy(&treg, reg1, sizeof(treg));
sbi_memcpy(reg1, reg2, sizeof(treg));
sbi_memcpy(reg2, &treg, sizeof(treg));
}
static void clear_region(struct sbi_domain_memregion* reg)
{
sbi_memset(reg, 0x0, sizeof(*reg));
}
static int sanitize_domain(struct sbi_domain *dom)
static int sanitize_domain(const struct sbi_platform *plat,
struct sbi_domain *dom)
{
u32 i, j, count;
bool is_covered;
struct sbi_domain_memregion *reg, *reg1;
bool have_fw_reg;
struct sbi_domain_memregion treg, *reg, *reg1;
/* Check possible HARTs */
if (!dom->possible_harts) {
@@ -282,14 +264,13 @@ static int sanitize_domain(struct sbi_domain *dom)
__func__, dom->name);
return SBI_EINVAL;
}
sbi_hartmask_for_each_hartindex(i, dom->possible_harts) {
if (!sbi_hartindex_valid(i)) {
sbi_hartmask_for_each_hart(i, dom->possible_harts) {
if (sbi_platform_hart_invalid(plat, i)) {
sbi_printf("%s: %s possible HART mask has invalid "
"hart %d\n", __func__,
dom->name, sbi_hartindex_to_hartid(i));
"hart %d\n", __func__, dom->name, i);
return SBI_EINVAL;
}
}
};
/* Check memory regions */
if (!dom->regions) {
@@ -307,13 +288,17 @@ static int sanitize_domain(struct sbi_domain *dom)
}
}
/* Count memory regions */
/* Count memory regions and check presence of firmware region */
count = 0;
sbi_domain_for_each_memregion(dom, reg)
have_fw_reg = false;
sbi_domain_for_each_memregion(dom, reg) {
if (reg->order == root_fw_region.order &&
reg->base == root_fw_region.base &&
reg->flags == root_fw_region.flags)
have_fw_reg = true;
count++;
/* Check presence of firmware regions */
if (!dom->fw_region_inited) {
}
if (!have_fw_reg) {
sbi_printf("%s: %s does not have firmware region\n",
__func__, dom->name);
return SBI_EINVAL;
@@ -325,38 +310,25 @@ static int sanitize_domain(struct sbi_domain *dom)
for (j = i + 1; j < count; j++) {
reg1 = &dom->regions[j];
if (is_region_conflict(reg1, reg)) {
sbi_printf("%s: %s conflict between regions "
"(base=0x%lx order=%lu flags=0x%lx) and "
"(base=0x%lx order=%lu flags=0x%lx)\n",
__func__, dom->name,
reg->base, reg->order, reg->flags,
reg1->base, reg1->order, reg1->flags);
return SBI_EINVAL;
}
if (!is_region_before(reg1, reg))
continue;
swap_region(reg, reg1);
sbi_memcpy(&treg, reg1, sizeof(treg));
sbi_memcpy(reg1, reg, sizeof(treg));
sbi_memcpy(reg, &treg, sizeof(treg));
}
}
/* Remove covered regions */
while(i < (count - 1)) {
is_covered = false;
reg = &dom->regions[i];
for (j = i + 1; j < count; j++) {
reg1 = &dom->regions[j];
if (is_region_compatible(reg, reg1)) {
is_covered = true;
break;
}
}
/* find a region is superset of reg, remove reg */
if (is_covered) {
for (j = i; j < (count - 1); j++)
swap_region(&dom->regions[j],
&dom->regions[j + 1]);
clear_region(&dom->regions[count - 1]);
count--;
} else
i++;
}
/*
* We don't need to check boot HART id of domain because if boot
* HART id is not possible/assigned to this domain then it won't
@@ -420,7 +392,7 @@ bool sbi_domain_check_addr_range(const struct sbi_domain *dom,
void sbi_domain_dump(const struct sbi_domain *dom, const char *suffix)
{
u32 i, j, k;
u32 i, k;
unsigned long rstart, rend;
struct sbi_domain_memregion *reg;
@@ -432,11 +404,9 @@ void sbi_domain_dump(const struct sbi_domain *dom, const char *suffix)
k = 0;
sbi_printf("Domain%d HARTs %s: ", dom->index, suffix);
sbi_hartmask_for_each_hartindex(i, dom->possible_harts) {
j = sbi_hartindex_to_hartid(i);
sbi_hartmask_for_each_hart(i, dom->possible_harts)
sbi_printf("%s%d%s", (k++) ? "," : "",
j, sbi_domain_is_assigned_hart(dom, j) ? "*" : "");
}
i, sbi_domain_is_assigned_hart(dom, i) ? "*" : "");
sbi_printf("\n");
i = 0;
@@ -494,7 +464,7 @@ void sbi_domain_dump(const struct sbi_domain *dom, const char *suffix)
default:
sbi_printf("Unknown\n");
break;
}
};
sbi_printf("Domain%d SysReset %s: %s\n",
dom->index, suffix, (dom->system_reset_allowed) ? "yes" : "no");
@@ -521,6 +491,7 @@ int sbi_domain_register(struct sbi_domain *dom,
int rc;
struct sbi_domain *tdom;
u32 cold_hartid = current_hartid();
const struct sbi_platform *plat = sbi_platform_thishart_ptr();
/* Sanity checks */
if (!dom || !assign_mask || domain_finalized)
@@ -543,7 +514,7 @@ int sbi_domain_register(struct sbi_domain *dom,
}
/* Sanitize discovered domain */
rc = sanitize_domain(dom);
rc = sanitize_domain(plat, dom);
if (rc) {
sbi_printf("%s: sanity checks failed for"
" %s (error %d)\n", __func__,
@@ -559,22 +530,22 @@ int sbi_domain_register(struct sbi_domain *dom,
sbi_hartmask_clear_all(&dom->assigned_harts);
/* Assign domain to HART if HART is a possible HART */
sbi_hartmask_for_each_hartindex(i, assign_mask) {
if (!sbi_hartmask_test_hartindex(i, dom->possible_harts))
sbi_hartmask_for_each_hart(i, assign_mask) {
if (!sbi_hartmask_test_hart(i, dom->possible_harts))
continue;
tdom = sbi_hartindex_to_domain(i);
tdom = hartid_to_domain_table[i];
if (tdom)
sbi_hartmask_clear_hartindex(i,
sbi_hartmask_clear_hart(i,
&tdom->assigned_harts);
update_hartindex_to_domain(i, dom);
sbi_hartmask_set_hartindex(i, &dom->assigned_harts);
hartid_to_domain_table[i] = dom;
sbi_hartmask_set_hart(i, &dom->assigned_harts);
/*
* If cold boot HART is assigned to this domain then
* override boot HART of this domain.
*/
if (sbi_hartindex_to_hartid(i) == cold_hartid &&
if (i == cold_hartid &&
dom->boot_hartid != cold_hartid) {
sbi_printf("Domain%d Boot HARTID forced to"
" %d\n", dom->index, cold_hartid);
@@ -590,28 +561,34 @@ int sbi_domain_root_add_memregion(const struct sbi_domain_memregion *reg)
int rc;
bool reg_merged;
struct sbi_domain_memregion *nreg, *nreg1, *nreg2;
const struct sbi_platform *plat = sbi_platform_thishart_ptr();
/* Sanity checks */
if (!reg || domain_finalized || !root.regions ||
if (!reg || domain_finalized ||
(root.regions != root_memregs) ||
(ROOT_REGION_MAX <= root_memregs_count))
return SBI_EINVAL;
/* Check whether compatible region exists for the new one */
/* Check for conflicts */
sbi_domain_for_each_memregion(&root, nreg) {
if (is_region_compatible(reg, nreg))
return 0;
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 */
nreg = &root.regions[root_memregs_count];
nreg = &root_memregs[root_memregs_count];
sbi_memcpy(nreg, reg, sizeof(*reg));
root_memregs_count++;
root.regions[root_memregs_count].order = 0;
root_memregs[root_memregs_count].order = 0;
/* Sort and optimize root regions */
do {
/* Sanitize the root domain so that memregions are sorted */
rc = sanitize_domain(&root);
rc = sanitize_domain(plat, &root);
if (rc) {
sbi_printf("%s: sanity checks failed for"
" %s (error %d)\n", __func__,
@@ -689,37 +666,36 @@ int sbi_domain_finalize(struct sbi_scratch *scratch, u32 cold_hartid)
/* Startup boot HART of domains */
sbi_domain_for_each(i, dom) {
/* Domain boot HART index */
dhart = sbi_hartid_to_hartindex(dom->boot_hartid);
/* Domain boot HART */
dhart = dom->boot_hartid;
/* Ignore of boot HART is off limits */
if (!sbi_hartindex_valid(dhart))
if (SBI_HARTMASK_MAX_BITS <= dhart)
continue;
/* Ignore if boot HART not possible for this domain */
if (!sbi_hartmask_test_hartindex(dhart, dom->possible_harts))
if (!sbi_hartmask_test_hart(dhart, dom->possible_harts))
continue;
/* Ignore if boot HART assigned different domain */
if (sbi_hartindex_to_domain(dhart) != dom ||
!sbi_hartmask_test_hartindex(dhart, &dom->assigned_harts))
if (sbi_hartid_to_domain(dhart) != dom ||
!sbi_hartmask_test_hart(dhart, &dom->assigned_harts))
continue;
/* Startup boot HART of domain */
if (dom->boot_hartid == cold_hartid) {
if (dhart == cold_hartid) {
scratch->next_addr = dom->next_addr;
scratch->next_mode = dom->next_mode;
scratch->next_arg1 = dom->next_arg1;
} else {
rc = sbi_hsm_hart_start(scratch, NULL,
dom->boot_hartid,
rc = sbi_hsm_hart_start(scratch, NULL, dhart,
dom->next_addr,
dom->next_mode,
dom->next_arg1);
if (rc) {
sbi_printf("%s: failed to start boot HART %d"
" for %s (error %d)\n", __func__,
dom->boot_hartid, dom->name, rc);
dhart, dom->name, rc);
return rc;
}
}
@@ -737,9 +713,6 @@ int sbi_domain_finalize(struct sbi_scratch *scratch, u32 cold_hartid)
int sbi_domain_init(struct sbi_scratch *scratch, u32 cold_hartid)
{
u32 i;
int rc;
struct sbi_hartmask *root_hmask;
struct sbi_domain_memregion *root_memregs;
const struct sbi_platform *plat = sbi_platform_ptr(scratch);
if (scratch->fw_rw_offset == 0 ||
@@ -755,31 +728,12 @@ int sbi_domain_init(struct sbi_scratch *scratch, u32 cold_hartid)
return SBI_EINVAL;
}
domain_hart_ptr_offset = sbi_scratch_alloc_type_offset(void *);
if (!domain_hart_ptr_offset)
return SBI_ENOMEM;
root_memregs = sbi_calloc(sizeof(*root_memregs), ROOT_REGION_MAX + 1);
if (!root_memregs) {
sbi_printf("%s: no memory for root regions\n", __func__);
rc = SBI_ENOMEM;
goto fail_free_domain_hart_ptr_offset;
}
root.regions = root_memregs;
root_hmask = sbi_zalloc(sizeof(*root_hmask));
if (!root_hmask) {
sbi_printf("%s: no memory for root hartmask\n", __func__);
rc = SBI_ENOMEM;
goto fail_free_root_memregs;
}
root.possible_harts = root_hmask;
/* Root domain firmware memory region */
sbi_domain_memregion_init(scratch->fw_start, scratch->fw_rw_offset,
(SBI_DOMAIN_MEMREGION_M_READABLE |
SBI_DOMAIN_MEMREGION_M_EXECUTABLE),
&root_memregs[root_memregs_count++]);
&root_fw_region);
domain_memregion_initfw(&root_memregs[root_memregs_count++]);
sbi_domain_memregion_init((scratch->fw_start + scratch->fw_rw_offset),
(scratch->fw_size - scratch->fw_rw_offset),
@@ -787,19 +741,11 @@ int sbi_domain_init(struct sbi_scratch *scratch, u32 cold_hartid)
SBI_DOMAIN_MEMREGION_M_WRITABLE),
&root_memregs[root_memregs_count++]);
root.fw_region_inited = true;
/*
* Allow SU RWX on rest of the memory region. Since pmp entries
* have implicit priority on index, previous entries will
* deny access to SU on M-mode region. Also, M-mode will not
* have access to SU region while previous entries will allow
* access to M-mode regions.
*/
/* Root domain allow everything memory region */
sbi_domain_memregion_init(0, ~0UL,
(SBI_DOMAIN_MEMREGION_SU_READABLE |
SBI_DOMAIN_MEMREGION_SU_WRITABLE |
SBI_DOMAIN_MEMREGION_SU_EXECUTABLE),
(SBI_DOMAIN_MEMREGION_READABLE |
SBI_DOMAIN_MEMREGION_WRITEABLE |
SBI_DOMAIN_MEMREGION_EXECUTABLE),
&root_memregs[root_memregs_count++]);
/* Root domain memory region end */
@@ -814,21 +760,11 @@ int sbi_domain_init(struct sbi_scratch *scratch, u32 cold_hartid)
root.next_mode = scratch->next_mode;
/* Root domain possible and assigned HARTs */
for (i = 0; i < plat->hart_count; i++)
sbi_hartmask_set_hartindex(i, root_hmask);
for (i = 0; i < SBI_HARTMASK_MAX_BITS; i++) {
if (sbi_platform_hart_invalid(plat, i))
continue;
sbi_hartmask_set_hart(i, &root_hmask);
}
/* Finally register the root domain */
rc = sbi_domain_register(&root, root_hmask);
if (rc)
goto fail_free_root_hmask;
return 0;
fail_free_root_hmask:
sbi_free(root_hmask);
fail_free_root_memregs:
sbi_free(root_memregs);
fail_free_domain_hart_ptr_offset:
sbi_scratch_free_offset(domain_hart_ptr_offset);
return rc;
return sbi_domain_register(&root, &root_hmask);
}

View File

@@ -101,12 +101,14 @@ int sbi_ecall_handler(struct sbi_trap_regs *regs)
struct sbi_ecall_extension *ext;
unsigned long extension_id = regs->a7;
unsigned long func_id = regs->a6;
struct sbi_ecall_return out = {0};
struct sbi_trap_info trap = {0};
unsigned long out_val = 0;
bool is_0_1_spec = 0;
ext = sbi_ecall_find_extension(extension_id);
if (ext && ext->handle) {
ret = ext->handle(extension_id, func_id, regs, &out);
ret = ext->handle(extension_id, func_id,
regs, &out_val, &trap);
if (extension_id >= SBI_EXT_0_1_SET_TIMER &&
extension_id <= SBI_EXT_0_1_SHUTDOWN)
is_0_1_spec = 1;
@@ -114,10 +116,11 @@ int sbi_ecall_handler(struct sbi_trap_regs *regs)
ret = SBI_ENOTSUPP;
}
if (!out.skip_regs_update) {
if (ret < SBI_LAST_ERR ||
(extension_id != SBI_EXT_0_1_CONSOLE_GETCHAR &&
SBI_SUCCESS < ret)) {
if (ret == SBI_ETRAP) {
trap.epc = regs->mepc;
sbi_trap_redirect(regs, &trap);
} else {
if (ret < SBI_LAST_ERR || SBI_SUCCESS < ret) {
sbi_printf("%s: Invalid error %d for ext=0x%lx "
"func=0x%lx\n", __func__, ret,
extension_id, func_id);
@@ -135,7 +138,7 @@ int sbi_ecall_handler(struct sbi_trap_regs *regs)
regs->mepc += 4;
regs->a0 = ret;
if (!is_0_1_spec)
regs->a1 = out.value;
regs->a1 = out_val;
}
return 0;
@@ -149,10 +152,7 @@ int sbi_ecall_init(void)
for (i = 0; i < sbi_ecall_exts_size; i++) {
ext = sbi_ecall_exts[i];
ret = SBI_ENODEV;
if (ext->register_extensions)
ret = ext->register_extensions();
ret = sbi_ecall_register_extension(ext);
if (ret)
return ret;
}

View File

@@ -33,36 +33,37 @@ static int sbi_ecall_base_probe(unsigned long extid, unsigned long *out_val)
}
static int sbi_ecall_base_handler(unsigned long extid, unsigned long funcid,
struct sbi_trap_regs *regs,
struct sbi_ecall_return *out)
const struct sbi_trap_regs *regs,
unsigned long *out_val,
struct sbi_trap_info *out_trap)
{
int ret = 0;
switch (funcid) {
case SBI_EXT_BASE_GET_SPEC_VERSION:
out->value = (SBI_ECALL_VERSION_MAJOR <<
SBI_SPEC_VERSION_MAJOR_OFFSET) &
(SBI_SPEC_VERSION_MAJOR_MASK <<
SBI_SPEC_VERSION_MAJOR_OFFSET);
out->value = out->value | SBI_ECALL_VERSION_MINOR;
*out_val = (SBI_ECALL_VERSION_MAJOR <<
SBI_SPEC_VERSION_MAJOR_OFFSET) &
(SBI_SPEC_VERSION_MAJOR_MASK <<
SBI_SPEC_VERSION_MAJOR_OFFSET);
*out_val = *out_val | SBI_ECALL_VERSION_MINOR;
break;
case SBI_EXT_BASE_GET_IMP_ID:
out->value = sbi_ecall_get_impid();
*out_val = sbi_ecall_get_impid();
break;
case SBI_EXT_BASE_GET_IMP_VERSION:
out->value = OPENSBI_VERSION;
*out_val = OPENSBI_VERSION;
break;
case SBI_EXT_BASE_GET_MVENDORID:
out->value = csr_read(CSR_MVENDORID);
*out_val = csr_read(CSR_MVENDORID);
break;
case SBI_EXT_BASE_GET_MARCHID:
out->value = csr_read(CSR_MARCHID);
*out_val = csr_read(CSR_MARCHID);
break;
case SBI_EXT_BASE_GET_MIMPID:
out->value = csr_read(CSR_MIMPID);
*out_val = csr_read(CSR_MIMPID);
break;
case SBI_EXT_BASE_PROBE_EXT:
ret = sbi_ecall_base_probe(regs->a0, &out->value);
ret = sbi_ecall_base_probe(regs->a0, out_val);
break;
default:
ret = SBI_ENOTSUPP;
@@ -71,16 +72,8 @@ static int sbi_ecall_base_handler(unsigned long extid, unsigned long funcid,
return ret;
}
struct sbi_ecall_extension ecall_base;
static int sbi_ecall_base_register_extensions(void)
{
return sbi_ecall_register_extension(&ecall_base);
}
struct sbi_ecall_extension ecall_base = {
.extid_start = SBI_EXT_BASE,
.extid_end = SBI_EXT_BASE,
.register_extensions = sbi_ecall_base_register_extensions,
.handle = sbi_ecall_base_handler,
.extid_start = SBI_EXT_BASE,
.extid_end = SBI_EXT_BASE,
.handle = sbi_ecall_base_handler,
};

View File

@@ -1,66 +0,0 @@
/*
* SPDX-License-Identifier: BSD-2-Clause
*
* Copyright (c) 2023 Ventana Micro Systems Inc.
*
*/
#include <sbi/sbi_ecall.h>
#include <sbi/sbi_ecall_interface.h>
#include <sbi/sbi_error.h>
#include <sbi/sbi_trap.h>
#include <sbi/sbi_cppc.h>
static int sbi_ecall_cppc_handler(unsigned long extid, unsigned long funcid,
struct sbi_trap_regs *regs,
struct sbi_ecall_return *out)
{
int ret = 0;
uint64_t temp;
switch (funcid) {
case SBI_EXT_CPPC_READ:
ret = sbi_cppc_read(regs->a0, &temp);
out->value = temp;
break;
case SBI_EXT_CPPC_READ_HI:
#if __riscv_xlen == 32
ret = sbi_cppc_read(regs->a0, &temp);
out->value = temp >> 32;
#else
out->value = 0;
#endif
break;
case SBI_EXT_CPPC_WRITE:
ret = sbi_cppc_write(regs->a0, regs->a1);
break;
case SBI_EXT_CPPC_PROBE:
ret = sbi_cppc_probe(regs->a0);
if (ret >= 0) {
out->value = ret;
ret = 0;
}
break;
default:
ret = SBI_ENOTSUPP;
}
return ret;
}
struct sbi_ecall_extension ecall_cppc;
static int sbi_ecall_cppc_register_extensions(void)
{
if (!sbi_cppc_get_device())
return 0;
return sbi_ecall_register_extension(&ecall_cppc);
}
struct sbi_ecall_extension ecall_cppc = {
.extid_start = SBI_EXT_CPPC,
.extid_end = SBI_EXT_CPPC,
.register_extensions = sbi_ecall_cppc_register_extensions,
.handle = sbi_ecall_cppc_handler,
};

View File

@@ -14,11 +14,11 @@
#include <sbi/sbi_ecall_interface.h>
#include <sbi/sbi_trap.h>
#include <sbi/riscv_asm.h>
#include <sbi/sbi_hart.h>
static int sbi_ecall_dbcn_handler(unsigned long extid, unsigned long funcid,
struct sbi_trap_regs *regs,
struct sbi_ecall_return *out)
const struct sbi_trap_regs *regs,
unsigned long *out_val,
struct sbi_trap_info *out_trap)
{
ulong smode = (csr_read(CSR_MSTATUS) & MSTATUS_MPP) >>
MSTATUS_MPP_SHIFT;
@@ -34,24 +34,19 @@ static int sbi_ecall_dbcn_handler(unsigned long extid, unsigned long funcid,
* Based on above, we simply fail if the upper 32bits of
* the physical address (i.e. a2 register) is non-zero on
* RV32.
*
* Analogously, we fail if the upper 64bit of the
* physical address (i.e. a2 register) is non-zero on
* RV64.
*/
#if __riscv_xlen == 32
if (regs->a2)
return SBI_ERR_FAILED;
#endif
if (!sbi_domain_check_addr_range(sbi_domain_thishart_ptr(),
regs->a1, regs->a0, smode,
SBI_DOMAIN_READ|SBI_DOMAIN_WRITE))
return SBI_ERR_INVALID_PARAM;
sbi_hart_map_saddr(regs->a1, regs->a0);
if (funcid == SBI_EXT_DBCN_CONSOLE_WRITE)
out->value = sbi_nputs((const char *)regs->a1, regs->a0);
*out_val = sbi_nputs((const char *)regs->a1, regs->a0);
else
out->value = sbi_ngets((char *)regs->a1, regs->a0);
sbi_hart_unmap_saddr();
*out_val = sbi_ngets((char *)regs->a1, regs->a0);
return 0;
case SBI_EXT_DBCN_CONSOLE_WRITE_BYTE:
sbi_putc(regs->a0);
@@ -63,19 +58,15 @@ static int sbi_ecall_dbcn_handler(unsigned long extid, unsigned long funcid,
return SBI_ENOTSUPP;
}
struct sbi_ecall_extension ecall_dbcn;
static int sbi_ecall_dbcn_register_extensions(void)
static int sbi_ecall_dbcn_probe(unsigned long extid, unsigned long *out_val)
{
if (!sbi_console_get_device())
return 0;
return sbi_ecall_register_extension(&ecall_dbcn);
*out_val = sbi_console_get_device() ? 1 : 0;
return 0;
}
struct sbi_ecall_extension ecall_dbcn = {
.extid_start = SBI_EXT_DBCN,
.extid_end = SBI_EXT_DBCN,
.register_extensions = sbi_ecall_dbcn_register_extensions,
.handle = sbi_ecall_dbcn_handler,
.extid_start = SBI_EXT_DBCN,
.extid_end = SBI_EXT_DBCN,
.handle = sbi_ecall_dbcn_handler,
.probe = sbi_ecall_dbcn_probe,
};

View File

@@ -17,8 +17,9 @@
#include <sbi/riscv_asm.h>
static int sbi_ecall_hsm_handler(unsigned long extid, unsigned long funcid,
struct sbi_trap_regs *regs,
struct sbi_ecall_return *out)
const struct sbi_trap_regs *regs,
unsigned long *out_val,
struct sbi_trap_info *out_trap)
{
int ret = 0;
struct sbi_scratch *scratch = sbi_scratch_thishart_ptr();
@@ -46,23 +47,15 @@ static int sbi_ecall_hsm_handler(unsigned long extid, unsigned long funcid,
}
if (ret >= 0) {
out->value = ret;
*out_val = ret;
ret = 0;
}
return ret;
}
struct sbi_ecall_extension ecall_hsm;
static int sbi_ecall_hsm_register_extensions(void)
{
return sbi_ecall_register_extension(&ecall_hsm);
}
struct sbi_ecall_extension ecall_hsm = {
.extid_start = SBI_EXT_HSM,
.extid_end = SBI_EXT_HSM,
.register_extensions = sbi_ecall_hsm_register_extensions,
.handle = sbi_ecall_hsm_handler,
.extid_start = SBI_EXT_HSM,
.extid_end = SBI_EXT_HSM,
.handle = sbi_ecall_hsm_handler,
};

View File

@@ -15,8 +15,9 @@
#include <sbi/sbi_ipi.h>
static int sbi_ecall_ipi_handler(unsigned long extid, unsigned long funcid,
struct sbi_trap_regs *regs,
struct sbi_ecall_return *out)
const struct sbi_trap_regs *regs,
unsigned long *out_val,
struct sbi_trap_info *out_trap)
{
int ret = 0;
@@ -28,16 +29,8 @@ static int sbi_ecall_ipi_handler(unsigned long extid, unsigned long funcid,
return ret;
}
struct sbi_ecall_extension ecall_ipi;
static int sbi_ecall_ipi_register_extensions(void)
{
return sbi_ecall_register_extension(&ecall_ipi);
}
struct sbi_ecall_extension ecall_ipi = {
.extid_start = SBI_EXT_IPI,
.extid_end = SBI_EXT_IPI,
.register_extensions = sbi_ecall_ipi_register_extensions,
.handle = sbi_ecall_ipi_handler,
.extid_start = SBI_EXT_IPI,
.extid_end = SBI_EXT_IPI,
.handle = sbi_ecall_ipi_handler,
};

View File

@@ -24,32 +24,32 @@
#include <sbi/sbi_unpriv.h>
#include <sbi/sbi_hart.h>
static bool sbi_load_hart_mask_unpriv(ulong *pmask, ulong *hmask,
struct sbi_trap_info *uptrap)
static int sbi_load_hart_mask_unpriv(ulong *pmask, ulong *hmask,
struct sbi_trap_info *uptrap)
{
ulong mask = 0;
if (pmask) {
mask = sbi_load_ulong(pmask, uptrap);
if (uptrap->cause)
return false;
return SBI_ETRAP;
} else {
sbi_hsm_hart_interruptible_mask(sbi_domain_thishart_ptr(),
0, &mask);
}
*hmask = mask;
return true;
return 0;
}
static int sbi_ecall_legacy_handler(unsigned long extid, unsigned long funcid,
struct sbi_trap_regs *regs,
struct sbi_ecall_return *out)
const struct sbi_trap_regs *regs,
unsigned long *out_val,
struct sbi_trap_info *out_trap)
{
int ret = 0;
struct sbi_tlb_info tlb_info;
u32 source_hart = current_hartid();
struct sbi_trap_info trap = {0};
ulong hmask = 0;
switch (extid) {
@@ -70,51 +70,40 @@ static int sbi_ecall_legacy_handler(unsigned long extid, unsigned long funcid,
sbi_ipi_clear_smode();
break;
case SBI_EXT_0_1_SEND_IPI:
if (sbi_load_hart_mask_unpriv((ulong *)regs->a0,
&hmask, &trap)) {
ret = sbi_load_hart_mask_unpriv((ulong *)regs->a0,
&hmask, out_trap);
if (ret != SBI_ETRAP)
ret = sbi_ipi_send_smode(hmask, 0);
} else {
trap.epc = regs->mepc;
sbi_trap_redirect(regs, &trap);
out->skip_regs_update = true;
}
break;
case SBI_EXT_0_1_REMOTE_FENCE_I:
if (sbi_load_hart_mask_unpriv((ulong *)regs->a0,
&hmask, &trap)) {
ret = sbi_load_hart_mask_unpriv((ulong *)regs->a0,
&hmask, out_trap);
if (ret != SBI_ETRAP) {
SBI_TLB_INFO_INIT(&tlb_info, 0, 0, 0, 0,
SBI_TLB_FENCE_I, source_hart);
sbi_tlb_local_fence_i,
source_hart);
ret = sbi_tlb_request(hmask, 0, &tlb_info);
} else {
trap.epc = regs->mepc;
sbi_trap_redirect(regs, &trap);
out->skip_regs_update = true;
}
break;
case SBI_EXT_0_1_REMOTE_SFENCE_VMA:
if (sbi_load_hart_mask_unpriv((ulong *)regs->a0,
&hmask, &trap)) {
ret = sbi_load_hart_mask_unpriv((ulong *)regs->a0,
&hmask, out_trap);
if (ret != SBI_ETRAP) {
SBI_TLB_INFO_INIT(&tlb_info, regs->a1, regs->a2, 0, 0,
SBI_TLB_SFENCE_VMA, source_hart);
sbi_tlb_local_sfence_vma,
source_hart);
ret = sbi_tlb_request(hmask, 0, &tlb_info);
} else {
trap.epc = regs->mepc;
sbi_trap_redirect(regs, &trap);
out->skip_regs_update = true;
}
break;
case SBI_EXT_0_1_REMOTE_SFENCE_VMA_ASID:
if (sbi_load_hart_mask_unpriv((ulong *)regs->a0,
&hmask, &trap)) {
ret = sbi_load_hart_mask_unpriv((ulong *)regs->a0,
&hmask, out_trap);
if (ret != SBI_ETRAP) {
SBI_TLB_INFO_INIT(&tlb_info, regs->a1,
regs->a2, regs->a3, 0,
SBI_TLB_SFENCE_VMA_ASID,
sbi_tlb_local_sfence_vma_asid,
source_hart);
ret = sbi_tlb_request(hmask, 0, &tlb_info);
} else {
trap.epc = regs->mepc;
sbi_trap_redirect(regs, &trap);
out->skip_regs_update = true;
}
break;
case SBI_EXT_0_1_SHUTDOWN:
@@ -123,21 +112,13 @@ static int sbi_ecall_legacy_handler(unsigned long extid, unsigned long funcid,
break;
default:
ret = SBI_ENOTSUPP;
}
};
return ret;
}
struct sbi_ecall_extension ecall_legacy;
static int sbi_ecall_legacy_register_extensions(void)
{
return sbi_ecall_register_extension(&ecall_legacy);
}
struct sbi_ecall_extension ecall_legacy = {
.extid_start = SBI_EXT_0_1_SET_TIMER,
.extid_end = SBI_EXT_0_1_SHUTDOWN,
.register_extensions = sbi_ecall_legacy_register_extensions,
.handle = sbi_ecall_legacy_handler,
.extid_start = SBI_EXT_0_1_SET_TIMER,
.extid_end = SBI_EXT_0_1_SHUTDOWN,
.handle = sbi_ecall_legacy_handler,
};

View File

@@ -18,8 +18,9 @@
#include <sbi/riscv_asm.h>
static int sbi_ecall_pmu_handler(unsigned long extid, unsigned long funcid,
struct sbi_trap_regs *regs,
struct sbi_ecall_return *out)
const struct sbi_trap_regs *regs,
unsigned long *out_val,
struct sbi_trap_info *out_trap)
{
int ret = 0;
uint64_t temp;
@@ -28,12 +29,12 @@ static int sbi_ecall_pmu_handler(unsigned long extid, unsigned long funcid,
case SBI_EXT_PMU_NUM_COUNTERS:
ret = sbi_pmu_num_ctr();
if (ret >= 0) {
out->value = ret;
*out_val = ret;
ret = 0;
}
break;
case SBI_EXT_PMU_COUNTER_GET_INFO:
ret = sbi_pmu_ctr_get_info(regs->a0, &out->value);
ret = sbi_pmu_ctr_get_info(regs->a0, out_val);
break;
case SBI_EXT_PMU_COUNTER_CFG_MATCH:
#if __riscv_xlen == 32
@@ -44,21 +45,21 @@ static int sbi_ecall_pmu_handler(unsigned long extid, unsigned long funcid,
ret = sbi_pmu_ctr_cfg_match(regs->a0, regs->a1, regs->a2,
regs->a3, temp);
if (ret >= 0) {
out->value = ret;
*out_val = ret;
ret = 0;
}
break;
case SBI_EXT_PMU_COUNTER_FW_READ:
ret = sbi_pmu_ctr_fw_read(regs->a0, &temp);
out->value = temp;
*out_val = temp;
break;
case SBI_EXT_PMU_COUNTER_FW_READ_HI:
#if __riscv_xlen == 32
ret = sbi_pmu_ctr_fw_read(regs->a0, &temp);
out->value = temp >> 32;
*out_val = temp >> 32;
#else
out->value = 0;
*out_val = 0;
#endif
break;
case SBI_EXT_PMU_COUNTER_START:
@@ -73,25 +74,23 @@ static int sbi_ecall_pmu_handler(unsigned long extid, unsigned long funcid,
case SBI_EXT_PMU_COUNTER_STOP:
ret = sbi_pmu_ctr_stop(regs->a0, regs->a1, regs->a2);
break;
case SBI_EXT_PMU_SNAPSHOT_SET_SHMEM:
/* fallthrough as OpenSBI doesn't support snapshot yet */
default:
ret = SBI_ENOTSUPP;
}
};
return ret;
}
struct sbi_ecall_extension ecall_pmu;
static int sbi_ecall_pmu_register_extensions(void)
static int sbi_ecall_pmu_probe(unsigned long extid, unsigned long *out_val)
{
return sbi_ecall_register_extension(&ecall_pmu);
/* PMU extension is always enabled */
*out_val = 1;
return 0;
}
struct sbi_ecall_extension ecall_pmu = {
.extid_start = SBI_EXT_PMU,
.extid_end = SBI_EXT_PMU,
.register_extensions = sbi_ecall_pmu_register_extensions,
.handle = sbi_ecall_pmu_handler,
.extid_start = SBI_EXT_PMU,
.extid_end = SBI_EXT_PMU,
.handle = sbi_ecall_pmu_handler,
.probe = sbi_ecall_pmu_probe,
};

View File

@@ -16,8 +16,9 @@
#include <sbi/sbi_tlb.h>
static int sbi_ecall_rfence_handler(unsigned long extid, unsigned long funcid,
struct sbi_trap_regs *regs,
struct sbi_ecall_return *out)
const struct sbi_trap_regs *regs,
unsigned long *out_val,
struct sbi_trap_info *out_trap)
{
int ret = 0;
unsigned long vmid;
@@ -32,60 +33,54 @@ static int sbi_ecall_rfence_handler(unsigned long extid, unsigned long funcid,
switch (funcid) {
case SBI_EXT_RFENCE_REMOTE_FENCE_I:
SBI_TLB_INFO_INIT(&tlb_info, 0, 0, 0, 0,
SBI_TLB_FENCE_I, source_hart);
sbi_tlb_local_fence_i, source_hart);
ret = sbi_tlb_request(regs->a0, regs->a1, &tlb_info);
break;
case SBI_EXT_RFENCE_REMOTE_HFENCE_GVMA:
SBI_TLB_INFO_INIT(&tlb_info, regs->a2, regs->a3, 0, 0,
SBI_TLB_HFENCE_GVMA, source_hart);
sbi_tlb_local_hfence_gvma, source_hart);
ret = sbi_tlb_request(regs->a0, regs->a1, &tlb_info);
break;
case SBI_EXT_RFENCE_REMOTE_HFENCE_GVMA_VMID:
SBI_TLB_INFO_INIT(&tlb_info, regs->a2, regs->a3, 0, regs->a4,
SBI_TLB_HFENCE_GVMA_VMID, source_hart);
sbi_tlb_local_hfence_gvma_vmid,
source_hart);
ret = sbi_tlb_request(regs->a0, regs->a1, &tlb_info);
break;
case SBI_EXT_RFENCE_REMOTE_HFENCE_VVMA:
vmid = (csr_read(CSR_HGATP) & HGATP_VMID_MASK);
vmid = vmid >> HGATP_VMID_SHIFT;
SBI_TLB_INFO_INIT(&tlb_info, regs->a2, regs->a3, 0, vmid,
SBI_TLB_HFENCE_VVMA, source_hart);
sbi_tlb_local_hfence_vvma, source_hart);
ret = sbi_tlb_request(regs->a0, regs->a1, &tlb_info);
break;
case SBI_EXT_RFENCE_REMOTE_HFENCE_VVMA_ASID:
vmid = (csr_read(CSR_HGATP) & HGATP_VMID_MASK);
vmid = vmid >> HGATP_VMID_SHIFT;
SBI_TLB_INFO_INIT(&tlb_info, regs->a2, regs->a3, regs->a4,
vmid, SBI_TLB_HFENCE_VVMA_ASID, source_hart);
vmid, sbi_tlb_local_hfence_vvma_asid,
source_hart);
ret = sbi_tlb_request(regs->a0, regs->a1, &tlb_info);
break;
case SBI_EXT_RFENCE_REMOTE_SFENCE_VMA:
SBI_TLB_INFO_INIT(&tlb_info, regs->a2, regs->a3, 0, 0,
SBI_TLB_SFENCE_VMA, source_hart);
sbi_tlb_local_sfence_vma, source_hart);
ret = sbi_tlb_request(regs->a0, regs->a1, &tlb_info);
break;
case SBI_EXT_RFENCE_REMOTE_SFENCE_VMA_ASID:
SBI_TLB_INFO_INIT(&tlb_info, regs->a2, regs->a3, regs->a4, 0,
SBI_TLB_SFENCE_VMA_ASID, source_hart);
sbi_tlb_local_sfence_vma_asid, source_hart);
ret = sbi_tlb_request(regs->a0, regs->a1, &tlb_info);
break;
default:
ret = SBI_ENOTSUPP;
}
};
return ret;
}
struct sbi_ecall_extension ecall_rfence;
static int sbi_ecall_rfence_register_extensions(void)
{
return sbi_ecall_register_extension(&ecall_rfence);
}
struct sbi_ecall_extension ecall_rfence = {
.extid_start = SBI_EXT_RFENCE,
.extid_end = SBI_EXT_RFENCE,
.register_extensions = sbi_ecall_rfence_register_extensions,
.handle = sbi_ecall_rfence_handler,
.extid_start = SBI_EXT_RFENCE,
.extid_end = SBI_EXT_RFENCE,
.handle = sbi_ecall_rfence_handler,
};

View File

@@ -15,8 +15,9 @@
#include <sbi/sbi_system.h>
static int sbi_ecall_srst_handler(unsigned long extid, unsigned long funcid,
struct sbi_trap_regs *regs,
struct sbi_ecall_return *out)
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)) ||
@@ -47,36 +48,28 @@ static int sbi_ecall_srst_handler(unsigned long extid, unsigned long funcid,
return SBI_ENOTSUPP;
}
static bool srst_available(void)
static int sbi_ecall_srst_probe(unsigned long extid, unsigned long *out_val)
{
u32 type;
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))
return true;
count++;
}
return false;
}
struct sbi_ecall_extension ecall_srst;
static int sbi_ecall_srst_register_extensions(void)
{
if (!srst_available())
return 0;
return sbi_ecall_register_extension(&ecall_srst);
*out_val = (count) ? 1 : 0;
return 0;
}
struct sbi_ecall_extension ecall_srst = {
.extid_start = SBI_EXT_SRST,
.extid_end = SBI_EXT_SRST,
.register_extensions = sbi_ecall_srst_register_extensions,
.handle = sbi_ecall_srst_handler,
.extid_start = SBI_EXT_SRST,
.extid_end = SBI_EXT_SRST,
.handle = sbi_ecall_srst_handler,
.probe = sbi_ecall_srst_probe,
};

View File

@@ -6,8 +6,9 @@
#include <sbi/sbi_system.h>
static int sbi_ecall_susp_handler(unsigned long extid, unsigned long funcid,
struct sbi_trap_regs *regs,
struct sbi_ecall_return *out)
const struct sbi_trap_regs *regs,
unsigned long *out_val,
struct sbi_trap_info *out_trap)
{
int ret = SBI_ENOTSUPP;
@@ -15,16 +16,16 @@ static int sbi_ecall_susp_handler(unsigned long extid, unsigned long funcid,
ret = sbi_system_suspend(regs->a0, regs->a1, regs->a2);
if (ret >= 0) {
out->value = ret;
*out_val = ret;
ret = 0;
}
return ret;
}
static bool susp_available(void)
static int sbi_ecall_susp_probe(unsigned long extid, unsigned long *out_val)
{
u32 type;
u32 type, count = 0;
/*
* At least one suspend type should be supported by the
@@ -32,25 +33,16 @@ static bool susp_available(void)
*/
for (type = 0; type <= SBI_SUSP_SLEEP_TYPE_LAST; type++) {
if (sbi_system_suspend_supported(type))
return true;
count++;
}
return false;
}
struct sbi_ecall_extension ecall_susp;
static int sbi_ecall_susp_register_extensions(void)
{
if (!susp_available())
return 0;
return sbi_ecall_register_extension(&ecall_susp);
*out_val = count ? 1 : 0;
return 0;
}
struct sbi_ecall_extension ecall_susp = {
.extid_start = SBI_EXT_SUSP,
.extid_end = SBI_EXT_SUSP,
.register_extensions = sbi_ecall_susp_register_extensions,
.handle = sbi_ecall_susp_handler,
.extid_start = SBI_EXT_SUSP,
.extid_end = SBI_EXT_SUSP,
.handle = sbi_ecall_susp_handler,
.probe = sbi_ecall_susp_probe,
};

View File

@@ -15,8 +15,9 @@
#include <sbi/sbi_timer.h>
static int sbi_ecall_time_handler(unsigned long extid, unsigned long funcid,
struct sbi_trap_regs *regs,
struct sbi_ecall_return *out)
const struct sbi_trap_regs *regs,
unsigned long *out_val,
struct sbi_trap_info *out_trap)
{
int ret = 0;
@@ -32,16 +33,8 @@ static int sbi_ecall_time_handler(unsigned long extid, unsigned long funcid,
return ret;
}
struct sbi_ecall_extension ecall_time;
static int sbi_ecall_time_register_extensions(void)
{
return sbi_ecall_register_extension(&ecall_time);
}
struct sbi_ecall_extension ecall_time = {
.extid_start = SBI_EXT_TIME,
.extid_end = SBI_EXT_TIME,
.register_extensions = sbi_ecall_time_register_extensions,
.handle = sbi_ecall_time_handler,
.extid_start = SBI_EXT_TIME,
.extid_end = SBI_EXT_TIME,
.handle = sbi_ecall_time_handler,
};

View File

@@ -22,32 +22,34 @@ static inline unsigned long sbi_ecall_vendor_id(void)
(SBI_EXT_VENDOR_END - SBI_EXT_VENDOR_START));
}
static int sbi_ecall_vendor_handler(unsigned long extid, unsigned long funcid,
struct sbi_trap_regs *regs,
struct sbi_ecall_return *out)
static int sbi_ecall_vendor_probe(unsigned long extid,
unsigned long *out_val)
{
return sbi_platform_vendor_ext_provider(sbi_platform_thishart_ptr(),
funcid, regs, out);
if (!sbi_platform_vendor_ext_check(sbi_platform_thishart_ptr()) ||
extid != sbi_ecall_vendor_id())
*out_val = 0;
else
*out_val = 1;
return 0;
}
struct sbi_ecall_extension ecall_vendor;
static int sbi_ecall_vendor_register_extensions(void)
static int sbi_ecall_vendor_handler(unsigned long extid, unsigned long funcid,
const struct sbi_trap_regs *regs,
unsigned long *out_val,
struct sbi_trap_info *out_trap)
{
unsigned long extid = sbi_ecall_vendor_id();
if (!sbi_platform_vendor_ext_check(sbi_platform_thishart_ptr()) ||
extid != sbi_ecall_vendor_id())
return SBI_ERR_NOT_SUPPORTED;
if (!sbi_platform_vendor_ext_check(sbi_platform_thishart_ptr()))
return 0;
ecall_vendor.extid_start = extid;
ecall_vendor.extid_end = extid;
return sbi_ecall_register_extension(&ecall_vendor);
return sbi_platform_vendor_ext_provider(sbi_platform_thishart_ptr(),
funcid, regs,
out_val, out_trap);
}
struct sbi_ecall_extension ecall_vendor = {
.extid_start = SBI_EXT_VENDOR_START,
.extid_end = SBI_EXT_VENDOR_END,
.register_extensions = sbi_ecall_vendor_register_extensions,
.handle = sbi_ecall_vendor_handler,
.extid_start = SBI_EXT_VENDOR_START,
.extid_end = SBI_EXT_VENDOR_END,
.probe = sbi_ecall_vendor_probe,
.handle = sbi_ecall_vendor_handler,
};

View File

@@ -109,7 +109,7 @@ int sbi_emulate_csr_read(int csr_num, struct sbi_trap_regs *regs,
#define switchcase_hpm(__uref, __mref, __csr) \
case __csr: \
if (sbi_hart_mhpm_mask(scratch) & (1 << (__csr - __uref)))\
if ((sbi_hart_mhpm_count(scratch) + 3) <= (__csr - __uref))\
return SBI_ENOTSUPP; \
if (!hpm_allowed(__csr - __uref, prev_mode, virt)) \
return SBI_ENOTSUPP; \
@@ -149,7 +149,7 @@ int sbi_emulate_csr_read(int csr_num, struct sbi_trap_regs *regs,
default:
ret = SBI_ENOTSUPP;
break;
}
};
if (ret)
sbi_dprintf("%s: hartid%d: invalid csr_num=0x%x\n",
@@ -187,7 +187,7 @@ int sbi_emulate_csr_write(int csr_num, struct sbi_trap_regs *regs,
default:
ret = SBI_ENOTSUPP;
break;
}
};
if (ret)
sbi_dprintf("%s: hartid%d: invalid csr_num=0x%x\n",

View File

@@ -33,11 +33,12 @@ static unsigned long hart_features_offset;
static void mstatus_init(struct sbi_scratch *scratch)
{
const struct sbi_platform *plat = sbi_platform_ptr(scratch);
unsigned long menvcfg_val, mstatus_val = 0;
int cidx;
unsigned long mstatus_val = 0;
unsigned int mhpm_mask = sbi_hart_mhpm_mask(scratch);
unsigned int num_mhpm = sbi_hart_mhpm_count(scratch);
uint64_t mhpmevent_init_val = 0;
uint64_t menvcfg_val, mstateen_val;
uint64_t mstateen_val;
/* Enable FPU */
if (misa_extension('D') || misa_extension('F'))
@@ -62,6 +63,11 @@ static void mstatus_init(struct sbi_scratch *scratch)
if (sbi_hart_priv_version(scratch) >= SBI_HART_PRIV_VER_1_10)
csr_write(CSR_MCOUNTEREN, -1);
if (sbi_platform_force_emulate_time_csr(plat)) {
csr_clear(CSR_MCOUNTEREN, MCOUNTEREN_TM);
csr_clear(CSR_SCOUNTEREN, MCOUNTEREN_TM);
}
/* All programmable counters will start running at runtime after S-mode request */
if (sbi_hart_priv_version(scratch) >= SBI_HART_PRIV_VER_1_11)
csr_write(CSR_MCOUNTINHIBIT, 0xFFFFFFF8);
@@ -69,14 +75,13 @@ static void mstatus_init(struct sbi_scratch *scratch)
/**
* 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 <= 28; cidx++) {
if (!(mhpm_mask & 1 << (cidx + 3)))
continue;
for (cidx = 0; cidx < num_mhpm; cidx++) {
#if __riscv_xlen == 32
csr_write_num(CSR_MHPMEVENT3 + cidx,
mhpmevent_init_val & 0xFFFFFFFF);
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);
@@ -108,40 +113,58 @@ static void mstatus_init(struct sbi_scratch *scratch)
if (sbi_hart_priv_version(scratch) >= SBI_HART_PRIV_VER_1_12) {
menvcfg_val = csr_read(CSR_MENVCFG);
#if __riscv_xlen == 32
menvcfg_val |= ((uint64_t)csr_read(CSR_MENVCFGH)) << 32;
#endif
#define __set_menvcfg_ext(__ext, __bits) \
if (sbi_hart_has_extension(scratch, __ext)) \
menvcfg_val |= __bits;
/*
* Enable access to extensions if they are present in the
* hardware or in the device tree.
* 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_ext(SBI_HART_EXT_ZICBOZ, ENVCFG_CBZE)
__set_menvcfg_ext(SBI_HART_EXT_ZICBOM, ENVCFG_CBCFE)
__set_menvcfg_ext(SBI_HART_EXT_ZICBOM,
ENVCFG_CBIE_INV << ENVCFG_CBIE_SHIFT)
/*
* 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
__set_menvcfg_ext(SBI_HART_EXT_SVPBMT, ENVCFG_PBMTE)
menvcfg_val |= ENVCFG_PBMTE;
#endif
__set_menvcfg_ext(SBI_HART_EXT_SSTC, ENVCFG_STCE)
#undef __set_menvcfg_ext
/*
* 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);
#if __riscv_xlen == 32
csr_write(CSR_MENVCFGH, menvcfg_val >> 32);
#endif
/* Enable S-mode access to seed CSR */
if (sbi_hart_has_extension(scratch, SBI_HART_EXT_ZKR)) {
csr_set(CSR_MSECCFG, MSECCFG_SSEED);
csr_clear(CSR_MSECCFG, MSECCFG_USEED);
}
}
/* Disable all interrupts */
@@ -227,12 +250,12 @@ void sbi_hart_delegation_dump(struct sbi_scratch *scratch,
prefix, suffix, csr_read(CSR_MEDELEG));
}
unsigned int sbi_hart_mhpm_mask(struct sbi_scratch *scratch)
unsigned int sbi_hart_mhpm_count(struct sbi_scratch *scratch)
{
struct sbi_hart_features *hfeatures =
sbi_scratch_offset_ptr(scratch, hart_features_offset);
return hfeatures->mhpm_mask;
return hfeatures->mhpm_count;
}
unsigned int sbi_hart_pmp_count(struct sbi_scratch *scratch)
@@ -243,12 +266,12 @@ unsigned int sbi_hart_pmp_count(struct sbi_scratch *scratch)
return hfeatures->pmp_count;
}
unsigned int sbi_hart_pmp_log2gran(struct sbi_scratch *scratch)
unsigned long sbi_hart_pmp_granularity(struct sbi_scratch *scratch)
{
struct sbi_hart_features *hfeatures =
sbi_scratch_offset_ptr(scratch, hart_features_offset);
return hfeatures->pmp_log2gran;
return hfeatures->pmp_gran;
}
unsigned int sbi_hart_pmp_addrbits(struct sbi_scratch *scratch)
@@ -267,174 +290,20 @@ unsigned int sbi_hart_mhpm_bits(struct sbi_scratch *scratch)
return hfeatures->mhpm_bits;
}
/*
* Returns Smepmp flags for a given domain and region based on permissions.
*/
static unsigned int sbi_hart_get_smepmp_flags(struct sbi_scratch *scratch,
struct sbi_domain *dom,
struct sbi_domain_memregion *reg)
{
unsigned int pmp_flags = 0;
if (SBI_DOMAIN_MEMREGION_IS_SHARED(reg->flags)) {
/* Read only for both M and SU modes */
if (SBI_DOMAIN_MEMREGION_IS_SUR_MR(reg->flags))
pmp_flags = (PMP_L | PMP_R | PMP_W | PMP_X);
/* Execute for SU but Read/Execute for M mode */
else if (SBI_DOMAIN_MEMREGION_IS_SUX_MRX(reg->flags))
/* locked region */
pmp_flags = (PMP_L | PMP_W | PMP_X);
/* Execute only for both M and SU modes */
else if (SBI_DOMAIN_MEMREGION_IS_SUX_MX(reg->flags))
pmp_flags = (PMP_L | PMP_W);
/* Read/Write for both M and SU modes */
else if (SBI_DOMAIN_MEMREGION_IS_SURW_MRW(reg->flags))
pmp_flags = (PMP_W | PMP_X);
/* Read only for SU mode but Read/Write for M mode */
else if (SBI_DOMAIN_MEMREGION_IS_SUR_MRW(reg->flags))
pmp_flags = (PMP_W);
} else if (SBI_DOMAIN_MEMREGION_M_ONLY_ACCESS(reg->flags)) {
/*
* When smepmp is supported and used, M region cannot have RWX
* permissions on any region.
*/
if ((reg->flags & SBI_DOMAIN_MEMREGION_M_ACCESS_MASK)
== SBI_DOMAIN_MEMREGION_M_RWX) {
sbi_printf("%s: M-mode only regions cannot have"
"RWX permissions\n", __func__);
return 0;
}
/* M-mode only access regions are always locked */
pmp_flags |= PMP_L;
if (reg->flags & SBI_DOMAIN_MEMREGION_M_READABLE)
pmp_flags |= PMP_R;
if (reg->flags & SBI_DOMAIN_MEMREGION_M_WRITABLE)
pmp_flags |= PMP_W;
if (reg->flags & SBI_DOMAIN_MEMREGION_M_EXECUTABLE)
pmp_flags |= PMP_X;
} else if (SBI_DOMAIN_MEMREGION_SU_ONLY_ACCESS(reg->flags)) {
if (reg->flags & SBI_DOMAIN_MEMREGION_SU_READABLE)
pmp_flags |= PMP_R;
if (reg->flags & SBI_DOMAIN_MEMREGION_SU_WRITABLE)
pmp_flags |= PMP_W;
if (reg->flags & SBI_DOMAIN_MEMREGION_SU_EXECUTABLE)
pmp_flags |= PMP_X;
}
return pmp_flags;
}
static void sbi_hart_smepmp_set(struct sbi_scratch *scratch,
struct sbi_domain *dom,
struct sbi_domain_memregion *reg,
unsigned int pmp_idx,
unsigned int pmp_flags,
unsigned int pmp_log2gran,
unsigned long pmp_addr_max)
{
unsigned long pmp_addr = reg->base >> PMP_SHIFT;
if (pmp_log2gran <= reg->order && pmp_addr < pmp_addr_max) {
pmp_set(pmp_idx, pmp_flags, reg->base, reg->order);
} else {
sbi_printf("Can not configure pmp for domain %s because"
" memory region address 0x%lx or size 0x%lx "
"is not in range.\n", dom->name, reg->base,
reg->order);
}
}
static int sbi_hart_smepmp_configure(struct sbi_scratch *scratch,
unsigned int pmp_count,
unsigned int pmp_log2gran,
unsigned long pmp_addr_max)
int sbi_hart_pmp_configure(struct sbi_scratch *scratch)
{
struct sbi_domain_memregion *reg;
struct sbi_domain *dom = sbi_domain_thishart_ptr();
unsigned int pmp_idx, pmp_flags;
unsigned int pmp_idx = 0, pmp_flags, pmp_bits, pmp_gran_log2;
unsigned int pmp_count = sbi_hart_pmp_count(scratch);
unsigned long pmp_addr = 0, pmp_addr_max = 0;
/*
* Set the RLB so that, we can write to PMP entries without
* enforcement even if some entries are locked.
*/
csr_set(CSR_MSECCFG, MSECCFG_RLB);
if (!pmp_count)
return 0;
/* Disable the reserved entry */
pmp_disable(SBI_SMEPMP_RESV_ENTRY);
/* Program M-only regions when MML is not set. */
pmp_idx = 0;
sbi_domain_for_each_memregion(dom, reg) {
/* Skip reserved entry */
if (pmp_idx == SBI_SMEPMP_RESV_ENTRY)
pmp_idx++;
if (pmp_count <= pmp_idx)
break;
/* Skip shared and SU-only regions */
if (!SBI_DOMAIN_MEMREGION_M_ONLY_ACCESS(reg->flags)) {
pmp_idx++;
continue;
}
pmp_flags = sbi_hart_get_smepmp_flags(scratch, dom, reg);
if (!pmp_flags)
return 0;
sbi_hart_smepmp_set(scratch, dom, reg, pmp_idx++, pmp_flags,
pmp_log2gran, pmp_addr_max);
}
/* Set the MML to enforce new encoding */
csr_set(CSR_MSECCFG, MSECCFG_MML);
/* Program shared and SU-only regions */
pmp_idx = 0;
sbi_domain_for_each_memregion(dom, reg) {
/* Skip reserved entry */
if (pmp_idx == SBI_SMEPMP_RESV_ENTRY)
pmp_idx++;
if (pmp_count <= pmp_idx)
break;
/* Skip M-only regions */
if (SBI_DOMAIN_MEMREGION_M_ONLY_ACCESS(reg->flags)) {
pmp_idx++;
continue;
}
pmp_flags = sbi_hart_get_smepmp_flags(scratch, dom, reg);
if (!pmp_flags)
return 0;
sbi_hart_smepmp_set(scratch, dom, reg, pmp_idx++, pmp_flags,
pmp_log2gran, pmp_addr_max);
}
/*
* All entries are programmed.
* Keep the RLB bit so that dynamic mappings can be done.
*/
return 0;
}
static int sbi_hart_oldpmp_configure(struct sbi_scratch *scratch,
unsigned int pmp_count,
unsigned int pmp_log2gran,
unsigned long pmp_addr_max)
{
struct sbi_domain_memregion *reg;
struct sbi_domain *dom = sbi_domain_thishart_ptr();
unsigned int pmp_idx = 0;
unsigned int pmp_flags;
unsigned long pmp_addr;
pmp_gran_log2 = log2roundup(sbi_hart_pmp_granularity(scratch));
pmp_bits = sbi_hart_pmp_addrbits(scratch) - 1;
pmp_addr_max = (1UL << pmp_bits) | ((1UL << pmp_bits) - 1);
sbi_domain_for_each_memregion(dom, reg) {
if (pmp_count <= pmp_idx)
@@ -443,8 +312,8 @@ static int sbi_hart_oldpmp_configure(struct sbi_scratch *scratch,
pmp_flags = 0;
/*
* If permissions are to be enforced for all modes on
* this region, the lock bit should be set.
* If permissions are to be enforced for all modes on this
* region, the lock bit should be set.
*/
if (reg->flags & SBI_DOMAIN_MEMREGION_ENF_PERMISSIONS)
pmp_flags |= PMP_L;
@@ -456,84 +325,16 @@ static int sbi_hart_oldpmp_configure(struct sbi_scratch *scratch,
if (reg->flags & SBI_DOMAIN_MEMREGION_SU_EXECUTABLE)
pmp_flags |= PMP_X;
pmp_addr = reg->base >> PMP_SHIFT;
if (pmp_log2gran <= reg->order && pmp_addr < pmp_addr_max) {
pmp_addr = reg->base >> PMP_SHIFT;
if (pmp_gran_log2 <= reg->order && pmp_addr < pmp_addr_max)
pmp_set(pmp_idx++, pmp_flags, reg->base, reg->order);
} else {
sbi_printf("Can not configure pmp for domain %s because"
" memory region address 0x%lx or size 0x%lx "
"is not in range.\n", dom->name, reg->base,
reg->order);
else {
sbi_printf("Can not configure pmp for domain %s", dom->name);
sbi_printf(" because memory region address %lx or size %lx is not in range\n",
reg->base, reg->order);
}
}
return 0;
}
int sbi_hart_map_saddr(unsigned long addr, unsigned long size)
{
/* shared R/W access for M and S/U mode */
unsigned int pmp_flags = (PMP_W | PMP_X);
unsigned long order, base = 0;
struct sbi_scratch *scratch = sbi_scratch_thishart_ptr();
/* If Smepmp is not supported no special mapping is required */
if (!sbi_hart_has_extension(scratch, SBI_HART_EXT_SMEPMP))
return SBI_OK;
if (is_pmp_entry_mapped(SBI_SMEPMP_RESV_ENTRY))
return SBI_ENOSPC;
for (order = MAX(sbi_hart_pmp_log2gran(scratch), log2roundup(size));
order <= __riscv_xlen; order++) {
if (order < __riscv_xlen) {
base = addr & ~((1UL << order) - 1UL);
if ((base <= addr) &&
(addr < (base + (1UL << order))) &&
(base <= (addr + size - 1UL)) &&
((addr + size - 1UL) < (base + (1UL << order))))
break;
} else {
return SBI_EFAIL;
}
}
pmp_set(SBI_SMEPMP_RESV_ENTRY, pmp_flags, base, order);
return SBI_OK;
}
int sbi_hart_unmap_saddr(void)
{
struct sbi_scratch *scratch = sbi_scratch_thishart_ptr();
if (!sbi_hart_has_extension(scratch, SBI_HART_EXT_SMEPMP))
return SBI_OK;
return pmp_disable(SBI_SMEPMP_RESV_ENTRY);
}
int sbi_hart_pmp_configure(struct sbi_scratch *scratch)
{
int rc;
unsigned int pmp_bits, pmp_log2gran;
unsigned int pmp_count = sbi_hart_pmp_count(scratch);
unsigned long pmp_addr_max;
if (!pmp_count)
return 0;
pmp_log2gran = sbi_hart_pmp_log2gran(scratch);
pmp_bits = sbi_hart_pmp_addrbits(scratch) - 1;
pmp_addr_max = (1UL << pmp_bits) | ((1UL << pmp_bits) - 1);
if (sbi_hart_has_extension(scratch, SBI_HART_EXT_SMEPMP))
rc = sbi_hart_smepmp_configure(scratch, pmp_count,
pmp_log2gran, pmp_addr_max);
else
rc = sbi_hart_oldpmp_configure(scratch, pmp_count,
pmp_log2gran, pmp_addr_max);
/*
* As per section 3.7.2 of privileged specification v1.12,
* virtual address translations can be speculatively performed
@@ -555,7 +356,7 @@ int sbi_hart_pmp_configure(struct sbi_scratch *scratch)
__sbi_hfence_gvma_all();
}
return rc;
return 0;
}
int sbi_hart_priv_version(struct sbi_scratch *scratch)
@@ -597,9 +398,9 @@ static inline void __sbi_hart_update_extension(
bool enable)
{
if (enable)
__set_bit(ext, hfeatures->extensions);
hfeatures->extensions |= BIT(ext);
else
__clear_bit(ext, hfeatures->extensions);
hfeatures->extensions &= ~BIT(ext);
}
/**
@@ -632,32 +433,38 @@ bool sbi_hart_has_extension(struct sbi_scratch *scratch,
struct sbi_hart_features *hfeatures =
sbi_scratch_offset_ptr(scratch, hart_features_offset);
if (__test_bit(ext, hfeatures->extensions))
if (hfeatures->extensions & BIT(ext))
return true;
else
return false;
}
#define __SBI_HART_EXT_DATA(_name, _id) { \
.name = #_name, \
.id = _id, \
}
static inline char *sbi_hart_extension_id2string(int ext)
{
char *estr = NULL;
const struct sbi_hart_ext_data sbi_hart_ext[] = {
__SBI_HART_EXT_DATA(smaia, SBI_HART_EXT_SMAIA),
__SBI_HART_EXT_DATA(smepmp, SBI_HART_EXT_SMEPMP),
__SBI_HART_EXT_DATA(smstateen, SBI_HART_EXT_SMSTATEEN),
__SBI_HART_EXT_DATA(sscofpmf, SBI_HART_EXT_SSCOFPMF),
__SBI_HART_EXT_DATA(sstc, SBI_HART_EXT_SSTC),
__SBI_HART_EXT_DATA(zicntr, SBI_HART_EXT_ZICNTR),
__SBI_HART_EXT_DATA(zihpm, SBI_HART_EXT_ZIHPM),
__SBI_HART_EXT_DATA(zkr, SBI_HART_EXT_ZKR),
__SBI_HART_EXT_DATA(smcntrpmf, SBI_HART_EXT_SMCNTRPMF),
__SBI_HART_EXT_DATA(xandespmu, SBI_HART_EXT_XANDESPMU),
__SBI_HART_EXT_DATA(zicboz, SBI_HART_EXT_ZICBOZ),
__SBI_HART_EXT_DATA(zicbom, SBI_HART_EXT_ZICBOM),
__SBI_HART_EXT_DATA(svpbmt, SBI_HART_EXT_SVPBMT),
};
switch (ext) {
case SBI_HART_EXT_SSCOFPMF:
estr = "sscofpmf";
break;
case SBI_HART_EXT_TIME:
estr = "time";
break;
case SBI_HART_EXT_SMAIA:
estr = "smaia";
break;
case SBI_HART_EXT_SSTC:
estr = "sstc";
break;
case SBI_HART_EXT_SMSTATEEN:
estr = "smstateen";
break;
default:
break;
}
return estr;
}
/**
* Get the hart extensions in string format
@@ -674,18 +481,30 @@ void sbi_hart_get_extensions_str(struct sbi_scratch *scratch,
struct sbi_hart_features *hfeatures =
sbi_scratch_offset_ptr(scratch, hart_features_offset);
int offset = 0, ext = 0;
char *temp;
if (!extensions_str || nestr <= 0)
return;
sbi_memset(extensions_str, 0, nestr);
for_each_set_bit(ext, hfeatures->extensions, SBI_HART_EXT_MAX) {
sbi_snprintf(extensions_str + offset,
nestr - offset,
"%s,", sbi_hart_ext[ext].name);
offset = offset + sbi_strlen(sbi_hart_ext[ext].name) + 1;
}
if (!hfeatures->extensions)
goto done;
do {
if (hfeatures->extensions & BIT(ext)) {
temp = sbi_hart_extension_id2string(ext);
if (temp) {
sbi_snprintf(extensions_str + offset,
nestr - offset,
"%s,", temp);
offset = offset + sbi_strlen(temp) + 1;
}
}
ext++;
} while (ext < SBI_HART_EXT_MAX);
done:
if (offset)
extensions_str[offset - 1] = '\0';
else
@@ -711,7 +530,7 @@ static unsigned long hart_pmp_get_allowed_addr(void)
return val;
}
static int hart_mhpm_get_allowed_bits(void)
static int hart_pmu_get_allowed_bits(void)
{
unsigned long val = ~(0UL);
struct sbi_trap_info trap = {0};
@@ -745,10 +564,10 @@ static int hart_mhpm_get_allowed_bits(void)
static int hart_detect_features(struct sbi_scratch *scratch)
{
struct sbi_trap_info trap = {0};
const struct sbi_platform *plat = sbi_platform_ptr(scratch);
struct sbi_hart_features *hfeatures =
sbi_scratch_offset_ptr(scratch, hart_features_offset);
unsigned long val, oldval;
bool has_zicntr = false;
int rc;
/* If hart features already detected then do nothing */
@@ -756,32 +575,9 @@ static int hart_detect_features(struct sbi_scratch *scratch)
return 0;
/* Clear hart features */
sbi_memset(hfeatures->extensions, 0, sizeof(hfeatures->extensions));
hfeatures->extensions = 0;
hfeatures->pmp_count = 0;
hfeatures->mhpm_mask = 0;
hfeatures->priv_version = SBI_HART_PRIV_VER_UNKNOWN;
#define __check_hpm_csr(__csr, __mask) \
oldval = csr_read_allowed(__csr, (ulong)&trap); \
if (!trap.cause) { \
csr_write_allowed(__csr, (ulong)&trap, 1UL); \
if (!trap.cause && csr_swap(__csr, oldval) == 1UL) { \
(hfeatures->__mask) |= 1 << (__csr - CSR_MCYCLE); \
} \
}
#define __check_hpm_csr_2(__csr, __mask) \
__check_hpm_csr(__csr + 0, __mask) \
__check_hpm_csr(__csr + 1, __mask)
#define __check_hpm_csr_4(__csr, __mask) \
__check_hpm_csr_2(__csr + 0, __mask) \
__check_hpm_csr_2(__csr + 2, __mask)
#define __check_hpm_csr_8(__csr, __mask) \
__check_hpm_csr_4(__csr + 0, __mask) \
__check_hpm_csr_4(__csr + 4, __mask)
#define __check_hpm_csr_16(__csr, __mask) \
__check_hpm_csr_8(__csr + 0, __mask) \
__check_hpm_csr_8(__csr + 8, __mask)
hfeatures->mhpm_count = 0;
#define __check_csr(__csr, __rdonly, __wrval, __field, __skip) \
oldval = csr_read_allowed(__csr, (ulong)&trap); \
@@ -827,23 +623,28 @@ static int hart_detect_features(struct sbi_scratch *scratch)
*/
val = hart_pmp_get_allowed_addr();
if (val) {
hfeatures->pmp_log2gran = sbi_ffs(val) + 2;
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);
}
__pmp_skip:
/* Detect number of MHPM counters */
__check_hpm_csr(CSR_MHPMCOUNTER3, mhpm_mask);
hfeatures->mhpm_bits = hart_mhpm_get_allowed_bits();
__check_hpm_csr_4(CSR_MHPMCOUNTER4, mhpm_mask);
__check_hpm_csr_8(CSR_MHPMCOUNTER8, mhpm_mask);
__check_hpm_csr_16(CSR_MHPMCOUNTER16, mhpm_mask);
__check_csr(CSR_MHPMCOUNTER3, 0, 1UL, mhpm_count, __mhpm_skip);
hfeatures->mhpm_bits = hart_pmu_get_allowed_bits();
__check_csr_4(CSR_MHPMCOUNTER4, 0, 1UL, mhpm_count, __mhpm_skip);
__check_csr_8(CSR_MHPMCOUNTER8, 0, 1UL, mhpm_count, __mhpm_skip);
__check_csr_16(CSR_MHPMCOUNTER16, 0, 1UL, mhpm_count, __mhpm_skip);
/**
* No need to check for MHPMCOUNTERH for RV32 as they are expected to be
* implemented if MHPMCOUNTER is implemented.
*/
__mhpm_skip:
#undef __check_csr_64
#undef __check_csr_32
#undef __check_csr_16
@@ -852,57 +653,61 @@ __pmp_skip:
#undef __check_csr_2
#undef __check_csr
#define __check_priv(__csr, __base_priv, __priv) \
val = csr_read_allowed(__csr, (ulong)&trap); \
if (!trap.cause && (hfeatures->priv_version >= __base_priv)) { \
hfeatures->priv_version = __priv; \
}
/* Detect if hart supports Priv v1.10 */
__check_priv(CSR_MCOUNTEREN,
SBI_HART_PRIV_VER_UNKNOWN, SBI_HART_PRIV_VER_1_10);
val = csr_read_allowed(CSR_MCOUNTEREN, (unsigned long)&trap);
if (!trap.cause)
hfeatures->priv_version = SBI_HART_PRIV_VER_1_10;
/* Detect if hart supports Priv v1.11 */
__check_priv(CSR_MCOUNTINHIBIT,
SBI_HART_PRIV_VER_1_10, SBI_HART_PRIV_VER_1_11);
val = csr_read_allowed(CSR_MCOUNTINHIBIT, (unsigned long)&trap);
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 */
__check_priv(CSR_MENVCFG,
SBI_HART_PRIV_VER_1_11, SBI_HART_PRIV_VER_1_12);
#undef __check_priv_csr
#define __check_ext_csr(__base_priv, __csr, __ext) \
if (hfeatures->priv_version >= __base_priv) { \
csr_read_allowed(__csr, (ulong)&trap); \
if (!trap.cause) \
__sbi_hart_update_extension(hfeatures, \
__ext, true); \
}
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 */
/* Detect if hart supports sscofpmf */
__check_ext_csr(SBI_HART_PRIV_VER_1_11,
CSR_SCOUNTOVF, SBI_HART_EXT_SSCOFPMF);
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)
__sbi_hart_update_extension(hfeatures,
SBI_HART_EXT_SSCOFPMF, true);
}
/* Detect if hart supports time CSR */
__check_ext_csr(SBI_HART_PRIV_VER_UNKNOWN,
CSR_TIME, SBI_HART_EXT_ZICNTR);
if (!sbi_platform_force_emulate_time_csr(plat)) {
csr_read_allowed(CSR_TIME, (unsigned long)&trap);
if (!trap.cause)
__sbi_hart_update_extension(hfeatures,
SBI_HART_EXT_TIME, true);
}
/* Detect if hart has AIA local interrupt CSRs */
__check_ext_csr(SBI_HART_PRIV_VER_UNKNOWN,
CSR_MTOPI, SBI_HART_EXT_SMAIA);
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) */
__check_ext_csr(SBI_HART_PRIV_VER_1_12,
CSR_STIMECMP, SBI_HART_EXT_SSTC);
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 */
__check_ext_csr(SBI_HART_PRIV_VER_1_12,
CSR_MSTATEEN0, SBI_HART_EXT_SMSTATEEN);
/* Detect if hart supports smcntrpmf */
__check_ext_csr(SBI_HART_PRIV_VER_1_12,
CSR_MCYCLECFG, SBI_HART_EXT_SMCNTRPMF);
#undef __check_ext_csr
/* Save trap based detection of Zicntr */
has_zicntr = sbi_hart_has_extension(scratch, SBI_HART_EXT_ZICNTR);
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(),
@@ -910,28 +715,9 @@ __pmp_skip:
if (rc)
return rc;
/* Zicntr should only be detected using traps */
__sbi_hart_update_extension(hfeatures, SBI_HART_EXT_ZICNTR,
has_zicntr);
/* Extensions implied by other extensions and features */
if (hfeatures->mhpm_mask)
__sbi_hart_update_extension(hfeatures,
SBI_HART_EXT_ZIHPM, true);
/* Mark hart feature detection done */
hfeatures->detected = true;
/*
* On platforms with Smepmp, the previous booting stage must
* enter OpenSBI with mseccfg.MML == 0. This allows OpenSBI
* to configure it's own M-mode only regions without depending
* on the previous booting stage.
*/
if (sbi_hart_has_extension(scratch, SBI_HART_EXT_SMEPMP) &&
(csr_read(CSR_MSECCFG) & MSECCFG_MML))
return SBI_EILL;
return 0;
}
@@ -956,12 +742,6 @@ int sbi_hart_init(struct sbi_scratch *scratch, bool cold_boot)
{
int rc;
/*
* Clear mip CSR before proceeding with init to avoid any spurious
* external interrupts in S-mode.
*/
csr_write(CSR_MIP, 0);
if (cold_boot) {
if (misa_extension('H'))
sbi_hart_expected_trap = &__sbi_expected_trap_hext;

View File

@@ -1,204 +0,0 @@
/*
* SPDX-License-Identifier: BSD-2-Clause
*
* Copyright (c) 2023 Ventana Micro Systems Inc.
*
* Authors:
* Anup Patel<apatel@ventanamicro.com>
*/
#include <sbi/riscv_locks.h>
#include <sbi/sbi_error.h>
#include <sbi/sbi_heap.h>
#include <sbi/sbi_list.h>
#include <sbi/sbi_scratch.h>
#include <sbi/sbi_string.h>
/* Minimum size and alignment of heap allocations */
#define HEAP_ALLOC_ALIGN 64
#define HEAP_HOUSEKEEPING_FACTOR 16
struct heap_node {
struct sbi_dlist head;
unsigned long addr;
unsigned long size;
};
struct heap_control {
spinlock_t lock;
unsigned long base;
unsigned long size;
unsigned long hkbase;
unsigned long hksize;
struct sbi_dlist free_node_list;
struct sbi_dlist free_space_list;
struct sbi_dlist used_space_list;
};
static struct heap_control hpctrl;
void *sbi_malloc(size_t size)
{
void *ret = NULL;
struct heap_node *n, *np;
if (!size)
return NULL;
size += HEAP_ALLOC_ALIGN - 1;
size &= ~((unsigned long)HEAP_ALLOC_ALIGN - 1);
spin_lock(&hpctrl.lock);
np = NULL;
sbi_list_for_each_entry(n, &hpctrl.free_space_list, head) {
if (size <= n->size) {
np = n;
break;
}
}
if (np) {
if ((size < np->size) &&
!sbi_list_empty(&hpctrl.free_node_list)) {
n = sbi_list_first_entry(&hpctrl.free_node_list,
struct heap_node, head);
sbi_list_del(&n->head);
n->addr = np->addr + np->size - size;
n->size = size;
np->size -= size;
sbi_list_add_tail(&n->head, &hpctrl.used_space_list);
ret = (void *)n->addr;
} else if (size == np->size) {
sbi_list_del(&np->head);
sbi_list_add_tail(&np->head, &hpctrl.used_space_list);
ret = (void *)np->addr;
}
}
spin_unlock(&hpctrl.lock);
return ret;
}
void *sbi_zalloc(size_t size)
{
void *ret = sbi_malloc(size);
if (ret)
sbi_memset(ret, 0, size);
return ret;
}
void sbi_free(void *ptr)
{
struct heap_node *n, *np;
if (!ptr)
return;
spin_lock(&hpctrl.lock);
np = NULL;
sbi_list_for_each_entry(n, &hpctrl.used_space_list, head) {
if ((n->addr <= (unsigned long)ptr) &&
((unsigned long)ptr < (n->addr + n->size))) {
np = n;
break;
}
}
if (!np) {
spin_unlock(&hpctrl.lock);
return;
}
sbi_list_del(&np->head);
sbi_list_for_each_entry(n, &hpctrl.free_space_list, head) {
if ((np->addr + np->size) == n->addr) {
n->addr = np->addr;
n->size += np->size;
sbi_list_add_tail(&np->head, &hpctrl.free_node_list);
np = NULL;
break;
} else if (np->addr == (n->addr + n->size)) {
n->size += np->size;
sbi_list_add_tail(&np->head, &hpctrl.free_node_list);
np = NULL;
break;
} else if ((n->addr + n->size) < np->addr) {
sbi_list_add(&np->head, &n->head);
np = NULL;
break;
}
}
if (np)
sbi_list_add_tail(&np->head, &hpctrl.free_space_list);
spin_unlock(&hpctrl.lock);
}
unsigned long sbi_heap_free_space(void)
{
struct heap_node *n;
unsigned long ret = 0;
spin_lock(&hpctrl.lock);
sbi_list_for_each_entry(n, &hpctrl.free_space_list, head)
ret += n->size;
spin_unlock(&hpctrl.lock);
return ret;
}
unsigned long sbi_heap_used_space(void)
{
return hpctrl.size - hpctrl.hksize - sbi_heap_free_space();
}
unsigned long sbi_heap_reserved_space(void)
{
return hpctrl.hksize;
}
int sbi_heap_init(struct sbi_scratch *scratch)
{
unsigned long i;
struct heap_node *n;
/* Sanity checks on heap offset and size */
if (!scratch->fw_heap_size ||
(scratch->fw_heap_size & (HEAP_BASE_ALIGN - 1)) ||
(scratch->fw_heap_offset < scratch->fw_rw_offset) ||
(scratch->fw_size < (scratch->fw_heap_offset + scratch->fw_heap_size)) ||
(scratch->fw_heap_offset & (HEAP_BASE_ALIGN - 1)))
return SBI_EINVAL;
/* Initialize heap control */
SPIN_LOCK_INIT(hpctrl.lock);
hpctrl.base = scratch->fw_start + scratch->fw_heap_offset;
hpctrl.size = scratch->fw_heap_size;
hpctrl.hkbase = hpctrl.base;
hpctrl.hksize = hpctrl.size / HEAP_HOUSEKEEPING_FACTOR;
hpctrl.hksize &= ~((unsigned long)HEAP_BASE_ALIGN - 1);
SBI_INIT_LIST_HEAD(&hpctrl.free_node_list);
SBI_INIT_LIST_HEAD(&hpctrl.free_space_list);
SBI_INIT_LIST_HEAD(&hpctrl.used_space_list);
/* Prepare free node list */
for (i = 0; i < (hpctrl.hksize / sizeof(*n)); i++) {
n = (struct heap_node *)(hpctrl.hkbase + (sizeof(*n) * i));
SBI_INIT_LIST_HEAD(&n->head);
n->addr = n->size = 0;
sbi_list_add_tail(&n->head, &hpctrl.free_node_list);
}
/* Prepare free space list */
n = sbi_list_first_entry(&hpctrl.free_node_list,
struct heap_node, head);
sbi_list_del(&n->head);
n->addr = hpctrl.hkbase + hpctrl.hksize;
n->size = hpctrl.size - hpctrl.hksize;
sbi_list_add_tail(&n->head, &hpctrl.free_space_list);
return 0;
}

View File

@@ -115,22 +115,23 @@ int sbi_hsm_hart_interruptible_mask(const struct sbi_domain *dom,
{
int hstate;
ulong i, hmask, dmask;
ulong hend = sbi_scratch_last_hartid() + 1;
*out_hmask = 0;
if (!sbi_hartid_valid(hbase))
if (hend <= hbase)
return SBI_EINVAL;
if (BITS_PER_LONG < (hend - hbase))
hend = hbase + BITS_PER_LONG;
dmask = sbi_domain_get_assigned_hartmask(dom, hbase);
for (i = 0; i < BITS_PER_LONG; i++) {
hmask = 1UL << i;
if (!(dmask & hmask))
continue;
hstate = __sbi_hsm_hart_get_state(hbase + i);
if (hstate == SBI_HSM_STATE_STARTED ||
hstate == SBI_HSM_STATE_SUSPENDED ||
hstate == SBI_HSM_STATE_RESUME_PENDING)
*out_hmask |= hmask;
for (i = hbase; i < hend; i++) {
hmask = 1UL << (i - hbase);
if (dmask & hmask) {
hstate = __sbi_hsm_hart_get_state(i);
if (hstate == SBI_HSM_STATE_STARTED ||
hstate == SBI_HSM_STATE_SUSPENDED)
*out_hmask |= hmask;
}
}
return 0;
@@ -171,7 +172,7 @@ static void sbi_hsm_hart_wait(struct sbi_scratch *scratch, u32 hartid)
/* Wait for state transition requested by sbi_hsm_hart_start() */
while (atomic_read(&hdata->state) != SBI_HSM_STATE_START_PENDING) {
wfi();
}
};
/* Restore MIE CSR */
csr_write(CSR_MIE, saved_mie);
@@ -248,15 +249,15 @@ int sbi_hsm_init(struct sbi_scratch *scratch, u32 hartid, bool cold_boot)
return SBI_ENOMEM;
/* Initialize hart state data for every hart */
for (i = 0; i <= sbi_scratch_last_hartindex(); i++) {
rscratch = sbi_hartindex_to_scratch(i);
for (i = 0; i <= sbi_scratch_last_hartid(); i++) {
rscratch = sbi_hartid_to_scratch(i);
if (!rscratch)
continue;
hdata = sbi_scratch_offset_ptr(rscratch,
hart_data_offset);
ATOMIC_INIT(&hdata->state,
(sbi_hartindex_to_hartid(i) == hartid) ?
(i == hartid) ?
SBI_HSM_STATE_START_PENDING :
SBI_HSM_STATE_STOPPED);
ATOMIC_INIT(&hdata->start_ticket, 0);
@@ -300,7 +301,7 @@ int sbi_hsm_hart_start(struct sbi_scratch *scratch,
const struct sbi_domain *dom,
u32 hartid, ulong saddr, ulong smode, ulong arg1)
{
unsigned long init_count, entry_count;
unsigned long init_count;
unsigned int hstate;
struct sbi_scratch *rscratch;
struct sbi_hsm_data *hdata;
@@ -324,8 +325,6 @@ int sbi_hsm_hart_start(struct sbi_scratch *scratch,
return SBI_EINVAL;
init_count = sbi_init_count(hartid);
entry_count = sbi_entry_count(hartid);
rscratch->next_arg1 = arg1;
rscratch->next_addr = saddr;
rscratch->next_mode = smode;
@@ -351,11 +350,11 @@ int sbi_hsm_hart_start(struct sbi_scratch *scratch,
goto err;
}
if ((hsm_device_has_hart_hotplug() && (entry_count == init_count)) ||
if (hsm_device_has_hart_hotplug() ||
(hsm_device_has_hart_secondary_boot() && !init_count)) {
rc = hsm_device_hart_start(hartid, scratch->warmboot_addr);
} else {
rc = sbi_ipi_raw_send(sbi_hartid_to_hartindex(hartid));
rc = sbi_ipi_raw_send(hartid);
}
if (!rc)

View File

@@ -90,7 +90,7 @@ static int system_opcode_insn(ulong insn, struct sbi_trap_regs *regs)
break;
default:
return truly_illegal_insn(insn, regs);
}
};
if (do_write && sbi_emulate_csr_write(csr_num, regs, new_csr_val))
return truly_illegal_insn(insn, regs);

View File

@@ -12,12 +12,10 @@
#include <sbi/riscv_barrier.h>
#include <sbi/riscv_locks.h>
#include <sbi/sbi_console.h>
#include <sbi/sbi_cppc.h>
#include <sbi/sbi_domain.h>
#include <sbi/sbi_ecall.h>
#include <sbi/sbi_hart.h>
#include <sbi/sbi_hartmask.h>
#include <sbi/sbi_heap.h>
#include <sbi/sbi_hsm.h>
#include <sbi/sbi_ipi.h>
#include <sbi/sbi_irqchip.h>
@@ -72,7 +70,6 @@ static void sbi_boot_print_general(struct sbi_scratch *scratch)
const struct sbi_console_device *cdev;
const struct sbi_system_reset_device *srdev;
const struct sbi_system_suspend_device *susp_dev;
const struct sbi_cppc_device *cppc_dev;
const struct sbi_platform *plat = sbi_platform_ptr(scratch);
if (scratch->options & SBI_SCRATCH_NO_BOOT_PRINTS)
@@ -110,29 +107,12 @@ static void sbi_boot_print_general(struct sbi_scratch *scratch)
susp_dev = sbi_system_suspend_get_device();
sbi_printf("Platform Suspend Device : %s\n",
(susp_dev) ? susp_dev->name : "---");
cppc_dev = sbi_cppc_get_device();
sbi_printf("Platform CPPC Device : %s\n",
(cppc_dev) ? cppc_dev->name : "---");
/* Firmware details */
sbi_printf("Firmware Base : 0x%lx\n", scratch->fw_start);
sbi_printf("Firmware Size : %d KB\n",
(u32)(scratch->fw_size / 1024));
sbi_printf("Firmware RW Offset : 0x%lx\n", scratch->fw_rw_offset);
sbi_printf("Firmware RW Size : %d KB\n",
(u32)((scratch->fw_size - scratch->fw_rw_offset) / 1024));
sbi_printf("Firmware Heap Offset : 0x%lx\n", scratch->fw_heap_offset);
sbi_printf("Firmware Heap Size : "
"%d KB (total), %d KB (reserved), %d KB (used), %d KB (free)\n",
(u32)(scratch->fw_heap_size / 1024),
(u32)(sbi_heap_reserved_space() / 1024),
(u32)(sbi_heap_used_space() / 1024),
(u32)(sbi_heap_free_space() / 1024));
sbi_printf("Firmware Scratch Size : "
"%d B (total), %d B (used), %d B (free)\n",
SBI_SCRATCH_SIZE,
(u32)sbi_scratch_used_space(),
(u32)(SBI_SCRATCH_SIZE - sbi_scratch_used_space()));
/* SBI details */
sbi_printf("Runtime SBI Version : %d.%d\n",
@@ -176,13 +156,12 @@ static void sbi_boot_print_hart(struct sbi_scratch *scratch, u32 hartid)
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 : %u bits\n",
sbi_hart_pmp_log2gran(scratch));
sbi_printf("Boot HART PMP Granularity : %lu\n",
sbi_hart_pmp_granularity(scratch));
sbi_printf("Boot HART PMP Address Bits: %d\n",
sbi_hart_pmp_addrbits(scratch));
sbi_printf("Boot HART MHPM Info : %lu (0x%08x)\n",
sbi_popcount(sbi_hart_mhpm_mask(scratch)),
sbi_hart_mhpm_mask(scratch));
sbi_printf("Boot HART MHPM Count : %d\n",
sbi_hart_mhpm_count(scratch));
sbi_hart_delegation_dump(scratch, "Boot HART ", " ");
}
@@ -195,9 +174,6 @@ static void wait_for_coldboot(struct sbi_scratch *scratch, u32 hartid)
{
unsigned long saved_mie, cmip;
if (__smp_load_acquire(&coldboot_done))
return;
/* Save MIE CSR */
saved_mie = csr_read(CSR_MIE);
@@ -208,7 +184,7 @@ static void wait_for_coldboot(struct sbi_scratch *scratch, u32 hartid)
spin_lock(&coldboot_lock);
/* Mark current HART as waiting */
sbi_hartmask_set_hartid(hartid, &coldboot_wait_hmask);
sbi_hartmask_set_hart(hartid, &coldboot_wait_hmask);
/* Release coldboot lock */
spin_unlock(&coldboot_lock);
@@ -219,13 +195,13 @@ static void wait_for_coldboot(struct sbi_scratch *scratch, u32 hartid)
wfi();
cmip = csr_read(CSR_MIP);
} while (!(cmip & (MIP_MSIP | MIP_MEIP)));
}
};
/* Acquire coldboot lock */
spin_lock(&coldboot_lock);
/* Unmark current HART as waiting */
sbi_hartmask_clear_hartid(hartid, &coldboot_wait_hmask);
sbi_hartmask_clear_hart(hartid, &coldboot_wait_hmask);
/* Release coldboot lock */
spin_unlock(&coldboot_lock);
@@ -245,8 +221,6 @@ static void wait_for_coldboot(struct sbi_scratch *scratch, u32 hartid)
static void wake_coldboot_harts(struct sbi_scratch *scratch, u32 hartid)
{
u32 i, hartindex = sbi_hartid_to_hartindex(hartid);
/* Mark coldboot done */
__smp_store_release(&coldboot_done, 1);
@@ -254,23 +228,22 @@ static void wake_coldboot_harts(struct sbi_scratch *scratch, u32 hartid)
spin_lock(&coldboot_lock);
/* Send an IPI to all HARTs waiting for coldboot */
sbi_hartmask_for_each_hartindex(i, &coldboot_wait_hmask) {
if (i == hartindex)
continue;
sbi_ipi_raw_send(i);
for (u32 i = 0; i <= sbi_scratch_last_hartid(); i++) {
if ((i != hartid) &&
sbi_hartmask_test_hart(i, &coldboot_wait_hmask))
sbi_ipi_raw_send(i);
}
/* Release coldboot lock */
spin_unlock(&coldboot_lock);
}
static unsigned long entry_count_offset;
static unsigned long init_count_offset;
static void __noreturn init_coldboot(struct sbi_scratch *scratch, u32 hartid)
{
int rc;
unsigned long *count;
unsigned long *init_count;
const struct sbi_platform *plat = sbi_platform_ptr(scratch);
/* Note: This has to be first thing in coldboot init sequence */
@@ -279,26 +252,14 @@ static void __noreturn init_coldboot(struct sbi_scratch *scratch, u32 hartid)
sbi_hart_hang();
/* Note: This has to be second thing in coldboot init sequence */
rc = sbi_heap_init(scratch);
if (rc)
sbi_hart_hang();
/* Note: This has to be the third thing in coldboot init sequence */
rc = sbi_domain_init(scratch, hartid);
if (rc)
sbi_hart_hang();
entry_count_offset = sbi_scratch_alloc_offset(__SIZEOF_POINTER__);
if (!entry_count_offset)
sbi_hart_hang();
init_count_offset = sbi_scratch_alloc_offset(__SIZEOF_POINTER__);
if (!init_count_offset)
sbi_hart_hang();
count = sbi_scratch_offset_ptr(scratch, entry_count_offset);
(*count)++;
rc = sbi_hsm_init(scratch, hartid, true);
if (rc)
sbi_hart_hang();
@@ -316,11 +277,8 @@ static void __noreturn init_coldboot(struct sbi_scratch *scratch, u32 hartid)
sbi_hart_hang();
rc = sbi_pmu_init(scratch, true);
if (rc) {
sbi_printf("%s: pmu init failed (error %d)\n",
__func__, rc);
if (rc)
sbi_hart_hang();
}
sbi_boot_print_banner(scratch);
@@ -349,6 +307,12 @@ static void __noreturn init_coldboot(struct sbi_scratch *scratch, u32 hartid)
sbi_hart_hang();
}
rc = sbi_ecall_init();
if (rc) {
sbi_printf("%s: ecall init failed (error %d)\n", __func__, rc);
sbi_hart_hang();
}
/*
* Note: Finalize domains after HSM initialization so that we
* can startup non-root domains.
@@ -362,26 +326,21 @@ static void __noreturn init_coldboot(struct sbi_scratch *scratch, u32 hartid)
sbi_hart_hang();
}
/*
* Note: Platform final initialization should be after finalizing
* domains so that it sees correct domain assignment and PMP
* configuration for FDT fixups.
*/
rc = sbi_platform_final_init(plat, true);
rc = sbi_hart_pmp_configure(scratch);
if (rc) {
sbi_printf("%s: platform final init failed (error %d)\n",
sbi_printf("%s: PMP configure failed (error %d)\n",
__func__, rc);
sbi_hart_hang();
}
/*
* Note: Ecall initialization should be after platform final
* initialization so that all available platform devices are
* already registered.
* Note: Platform final initialization should be last so that
* it sees correct domain assignment and PMP configuration.
*/
rc = sbi_ecall_init();
rc = sbi_platform_final_init(plat, true);
if (rc) {
sbi_printf("%s: ecall init failed (error %d)\n", __func__, rc);
sbi_printf("%s: platform final init failed (error %d)\n",
__func__, rc);
sbi_hart_hang();
}
@@ -391,21 +350,10 @@ static void __noreturn init_coldboot(struct sbi_scratch *scratch, u32 hartid)
sbi_boot_print_hart(scratch, hartid);
/*
* Configure PMP at last because if SMEPMP is detected,
* M-mode access to the S/U space will be rescinded.
*/
rc = sbi_hart_pmp_configure(scratch);
if (rc) {
sbi_printf("%s: PMP configure failed (error %d)\n",
__func__, rc);
sbi_hart_hang();
}
wake_coldboot_harts(scratch, hartid);
count = sbi_scratch_offset_ptr(scratch, init_count_offset);
(*count)++;
init_count = sbi_scratch_offset_ptr(scratch, init_count_offset);
(*init_count)++;
sbi_hsm_hart_start_finish(scratch, hartid);
}
@@ -414,15 +362,12 @@ static void __noreturn init_warm_startup(struct sbi_scratch *scratch,
u32 hartid)
{
int rc;
unsigned long *count;
unsigned long *init_count;
const struct sbi_platform *plat = sbi_platform_ptr(scratch);
if (!entry_count_offset || !init_count_offset)
if (!init_count_offset)
sbi_hart_hang();
count = sbi_scratch_offset_ptr(scratch, entry_count_offset);
(*count)++;
rc = sbi_hsm_init(scratch, hartid, false);
if (rc)
sbi_hart_hang();
@@ -455,20 +400,16 @@ static void __noreturn init_warm_startup(struct sbi_scratch *scratch,
if (rc)
sbi_hart_hang();
rc = sbi_platform_final_init(plat, false);
if (rc)
sbi_hart_hang();
/*
* Configure PMP at last because if SMEPMP is detected,
* M-mode access to the S/U space will be rescinded.
*/
rc = sbi_hart_pmp_configure(scratch);
if (rc)
sbi_hart_hang();
count = sbi_scratch_offset_ptr(scratch, init_count_offset);
(*count)++;
rc = sbi_platform_final_init(plat, false);
if (rc)
sbi_hart_hang();
init_count = sbi_scratch_offset_ptr(scratch, init_count_offset);
(*init_count)++;
sbi_hsm_hart_start_finish(scratch, hartid);
}
@@ -504,7 +445,7 @@ static void __noreturn init_warmboot(struct sbi_scratch *scratch, u32 hartid)
if (hstate == SBI_HSM_STATE_SUSPENDED) {
init_warm_resume(scratch, hartid);
} else {
sbi_ipi_raw_clear(sbi_hartid_to_hartindex(hartid));
sbi_ipi_raw_clear(hartid);
init_warm_startup(scratch, hartid);
}
}
@@ -525,19 +466,13 @@ static atomic_t coldboot_lottery = ATOMIC_INITIALIZER(0);
*/
void __noreturn sbi_init(struct sbi_scratch *scratch)
{
u32 i, h;
bool hartid_valid = false;
bool next_mode_supported = false;
bool coldboot = false;
u32 hartid = current_hartid();
const struct sbi_platform *plat = sbi_platform_ptr(scratch);
for (i = 0; i < plat->hart_count; i++) {
h = (plat->hart_index2id) ? plat->hart_index2id[i] : i;
if (h == hartid)
hartid_valid = true;
}
if (!hartid_valid)
if ((SBI_HARTMASK_MAX_BITS <= hartid) ||
sbi_platform_hart_invalid(plat, hartid))
sbi_hart_hang();
switch (scratch->next_mode) {
@@ -586,23 +521,6 @@ void __noreturn sbi_init(struct sbi_scratch *scratch)
init_warmboot(scratch, hartid);
}
unsigned long sbi_entry_count(u32 hartid)
{
struct sbi_scratch *scratch;
unsigned long *entry_count;
if (!entry_count_offset)
return 0;
scratch = sbi_hartid_to_scratch(hartid);
if (!scratch)
return 0;
entry_count = sbi_scratch_offset_ptr(scratch, entry_count_offset);
return *entry_count;
}
unsigned long sbi_init_count(u32 hartid)
{
struct sbi_scratch *scratch;
@@ -634,7 +552,7 @@ void __noreturn sbi_exit(struct sbi_scratch *scratch)
u32 hartid = current_hartid();
const struct sbi_platform *plat = sbi_platform_ptr(scratch);
if (!sbi_hartid_valid(hartid))
if (sbi_platform_hart_invalid(plat, hartid))
sbi_hart_hang();
sbi_platform_early_exit(plat);

View File

@@ -15,6 +15,7 @@
#include <sbi/sbi_domain.h>
#include <sbi/sbi_error.h>
#include <sbi/sbi_hart.h>
#include <sbi/sbi_hartmask.h>
#include <sbi/sbi_hsm.h>
#include <sbi/sbi_init.h>
#include <sbi/sbi_ipi.h>
@@ -27,19 +28,14 @@ struct sbi_ipi_data {
unsigned long ipi_type;
};
_Static_assert(
8 * sizeof(((struct sbi_ipi_data*)0)->ipi_type) == SBI_IPI_EVENT_MAX,
"type of sbi_ipi_data.ipi_type has changed, please redefine SBI_IPI_EVENT_MAX"
);
static unsigned long ipi_data_off;
static const struct sbi_ipi_device *ipi_dev = NULL;
static const struct sbi_ipi_event_ops *ipi_ops_array[SBI_IPI_EVENT_MAX];
static int sbi_ipi_send(struct sbi_scratch *scratch, u32 remote_hartindex,
static int sbi_ipi_update(struct sbi_scratch *scratch, u32 remote_hartid,
u32 event, void *data)
{
int ret = 0;
int ret;
struct sbi_scratch *remote_scratch = NULL;
struct sbi_ipi_data *ipi_data;
const struct sbi_ipi_event_ops *ipi_ops;
@@ -49,7 +45,7 @@ static int sbi_ipi_send(struct sbi_scratch *scratch, u32 remote_hartindex,
return SBI_EINVAL;
ipi_ops = ipi_ops_array[event];
remote_scratch = sbi_hartindex_to_scratch(remote_hartindex);
remote_scratch = sbi_hartid_to_scratch(remote_hartid);
if (!remote_scratch)
return SBI_EINVAL;
@@ -57,34 +53,24 @@ static int sbi_ipi_send(struct sbi_scratch *scratch, u32 remote_hartindex,
if (ipi_ops->update) {
ret = ipi_ops->update(scratch, remote_scratch,
remote_hartindex, data);
if (ret != SBI_IPI_UPDATE_SUCCESS)
remote_hartid, data);
if (ret < 0)
return ret;
} else if (scratch == remote_scratch) {
/*
* IPI events with an update() callback are expected to return
* SBI_IPI_UPDATE_BREAK for self-IPIs. For other events, check
* for self-IPI and execute the callback directly here.
*/
ipi_ops->process(scratch);
return 0;
}
/*
* Set IPI type on remote hart's scratch area and
* trigger the interrupt.
*
* Multiple harts may be trying to send IPI to the
* remote hart so call sbi_ipi_raw_send() only when
* the ipi_type was previously zero.
* trigger the interrupt
*/
if (!__atomic_fetch_or(&ipi_data->ipi_type,
BIT(event), __ATOMIC_RELAXED))
ret = sbi_ipi_raw_send(remote_hartindex);
atomic_raw_set_bit(event, &ipi_data->ipi_type);
smp_wmb();
if (ipi_dev && ipi_dev->ipi_send)
ipi_dev->ipi_send(remote_hartid);
sbi_pmu_ctr_incr_fw(SBI_PMU_FW_IPI_SENT);
return ret;
return 0;
}
static int sbi_ipi_sync(struct sbi_scratch *scratch, u32 event)
@@ -92,7 +78,7 @@ static int sbi_ipi_sync(struct sbi_scratch *scratch, u32 event)
const struct sbi_ipi_event_ops *ipi_ops;
if ((SBI_IPI_EVENT_MAX <= event) ||
!ipi_ops_array[event])
!ipi_ops_array[event])
return SBI_EINVAL;
ipi_ops = ipi_ops_array[event];
@@ -109,14 +95,13 @@ static int sbi_ipi_sync(struct sbi_scratch *scratch, u32 event)
*/
int sbi_ipi_send_many(ulong hmask, ulong hbase, u32 event, void *data)
{
int rc = 0;
bool retry_needed;
int rc, done;
ulong i, m;
struct sbi_hartmask target_mask = {0};
struct sbi_hartmask retry_mask = {0};
struct sbi_domain *dom = sbi_domain_thishart_ptr();
struct sbi_scratch *scratch = sbi_scratch_thishart_ptr();
/* Find the target harts */
if (hbase != -1UL) {
rc = sbi_hsm_hart_interruptible_mask(dom, hbase, &m);
if (rc)
@@ -125,39 +110,35 @@ int sbi_ipi_send_many(ulong hmask, ulong hbase, u32 event, void *data)
for (i = hbase; m; i++, m >>= 1) {
if (m & 1UL)
sbi_hartmask_set_hartid(i, &target_mask);
sbi_hartmask_set_hart(i, &target_mask);
}
} else {
hbase = 0;
while (!sbi_hsm_hart_interruptible_mask(dom, hbase, &m)) {
for (i = hbase; m; i++, m >>= 1) {
if (m & 1UL)
sbi_hartmask_set_hartid(i, &target_mask);
sbi_hartmask_set_hart(i, &target_mask);
}
hbase += BITS_PER_LONG;
}
}
/* Send IPIs */
retry_mask = target_mask;
do {
retry_needed = false;
sbi_hartmask_for_each_hartindex(i, &target_mask) {
rc = sbi_ipi_send(scratch, i, event, data);
if (rc < 0)
goto done;
if (rc == SBI_IPI_UPDATE_RETRY)
retry_needed = true;
done = true;
sbi_hartmask_for_each_hart(i, &retry_mask) {
rc = sbi_ipi_update(scratch, i, event, data);
if (rc == -2)
done = false;
else
sbi_hartmask_clear_hartindex(i, &target_mask);
rc = 0;
sbi_hartmask_clear_hart(i, &retry_mask);
}
} while (retry_needed);
} while (!done);
done:
/* Sync IPIs */
/* sync IPIs */
sbi_ipi_sync(scratch, event);
return rc;
return 0;
}
int sbi_ipi_event_create(const struct sbi_ipi_event_ops *ops)
@@ -233,59 +214,41 @@ void sbi_ipi_process(void)
struct sbi_scratch *scratch = sbi_scratch_thishart_ptr();
struct sbi_ipi_data *ipi_data =
sbi_scratch_offset_ptr(scratch, ipi_data_off);
u32 hartindex = sbi_hartid_to_hartindex(current_hartid());
u32 hartid = current_hartid();
sbi_pmu_ctr_incr_fw(SBI_PMU_FW_IPI_RECVD);
sbi_ipi_raw_clear(hartindex);
if (ipi_dev && ipi_dev->ipi_clear)
ipi_dev->ipi_clear(hartid);
ipi_type = atomic_raw_xchg_ulong(&ipi_data->ipi_type, 0);
ipi_event = 0;
while (ipi_type) {
if (ipi_type & 1UL) {
ipi_ops = ipi_ops_array[ipi_event];
if (ipi_ops)
ipi_ops->process(scratch);
}
if (!(ipi_type & 1UL))
goto skip;
ipi_ops = ipi_ops_array[ipi_event];
if (ipi_ops && ipi_ops->process)
ipi_ops->process(scratch);
skip:
ipi_type = ipi_type >> 1;
ipi_event++;
}
};
}
int sbi_ipi_raw_send(u32 hartindex)
int sbi_ipi_raw_send(u32 target_hart)
{
if (!ipi_dev || !ipi_dev->ipi_send)
return SBI_EINVAL;
/*
* Ensure that memory or MMIO writes done before
* this function are not observed after the memory
* or MMIO writes done by the ipi_send() device
* callback. This also allows the ipi_send() device
* callback to use relaxed MMIO writes.
*
* This pairs with the wmb() in sbi_ipi_raw_clear().
*/
wmb();
ipi_dev->ipi_send(hartindex);
ipi_dev->ipi_send(target_hart);
return 0;
}
void sbi_ipi_raw_clear(u32 hartindex)
void sbi_ipi_raw_clear(u32 target_hart)
{
if (ipi_dev && ipi_dev->ipi_clear)
ipi_dev->ipi_clear(hartindex);
/*
* Ensure that memory or MMIO writes after this
* function returns are not observed before the
* memory or MMIO writes done by the ipi_clear()
* device callback. This also allows ipi_clear()
* device callback to use relaxed MMIO writes.
*
* This pairs with the wmb() in sbi_ipi_raw_send().
*/
wmb();
ipi_dev->ipi_clear(target_hart);
}
const struct sbi_ipi_device *sbi_ipi_get_device(void)

View File

@@ -211,14 +211,16 @@ int sbi_misaligned_store_handler(ulong addr, ulong tval2, ulong tinst,
} else if ((insn & INSN_MASK_C_SD) == INSN_MATCH_C_SD) {
len = 8;
val.data_ulong = GET_RS2S(insn, regs);
} else if ((insn & INSN_MASK_C_SDSP) == INSN_MATCH_C_SDSP) {
} else if ((insn & INSN_MASK_C_SDSP) == INSN_MATCH_C_SDSP &&
((insn >> SH_RD) & 0x1f)) {
len = 8;
val.data_ulong = GET_RS2C(insn, regs);
#endif
} else if ((insn & INSN_MASK_C_SW) == INSN_MATCH_C_SW) {
len = 4;
val.data_ulong = GET_RS2S(insn, regs);
} else if ((insn & INSN_MASK_C_SWSP) == INSN_MATCH_C_SWSP) {
} else if ((insn & INSN_MASK_C_SWSP) == INSN_MATCH_C_SWSP &&
((insn >> SH_RD) & 0x1f)) {
len = 4;
val.data_ulong = GET_RS2C(insn, regs);
#ifdef __riscv_flen

View File

@@ -71,3 +71,20 @@ done:
else
sbi_strncpy(features_str, "none", nfstr);
}
u32 sbi_platform_hart_index(const struct sbi_platform *plat, u32 hartid)
{
u32 i;
if (!plat)
return -1U;
if (plat->hart_index2id) {
for (i = 0; i < plat->hart_count; i++) {
if (plat->hart_index2id[i] == hartid)
return i;
}
return -1U;
}
return hartid;
}

View File

@@ -12,7 +12,7 @@
#include <sbi/sbi_console.h>
#include <sbi/sbi_ecall_interface.h>
#include <sbi/sbi_hart.h>
#include <sbi/sbi_heap.h>
#include <sbi/sbi_hartmask.h>
#include <sbi/sbi_platform.h>
#include <sbi/sbi_pmu.h>
#include <sbi/sbi_scratch.h>
@@ -50,43 +50,27 @@ union sbi_pmu_ctr_info {
};
};
#if SBI_PMU_FW_CTR_MAX >= BITS_PER_LONG
#error "Can't handle firmware counters beyond BITS_PER_LONG"
#endif
/** Per-HART state of the PMU counters */
struct sbi_pmu_hart_state {
/* HART to which this state belongs */
uint32_t hartid;
/* Counter to enabled event mapping */
uint32_t active_events[SBI_PMU_HW_CTR_MAX + SBI_PMU_FW_CTR_MAX];
/* Bitmap of firmware counters started */
unsigned long fw_counters_started;
/*
* Counter values for SBI firmware events and event codes
* for platform firmware events. Both are mutually exclusive
* and hence can optimally share the same memory.
*/
uint64_t fw_counters_data[SBI_PMU_FW_CTR_MAX];
};
/** Offset of pointer to PMU HART state in scratch space */
static unsigned long phs_ptr_offset;
#define pmu_get_hart_state_ptr(__scratch) \
sbi_scratch_read_type((__scratch), void *, phs_ptr_offset)
#define pmu_thishart_state_ptr() \
pmu_get_hart_state_ptr(sbi_scratch_thishart_ptr())
#define pmu_set_hart_state_ptr(__scratch, __phs) \
sbi_scratch_write_type((__scratch), void *, phs_ptr_offset, (__phs))
/* 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;
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];
/* 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];
/*
* Counter values for SBI firmware events and event codes for platform
* firmware events. Both are mutually exclusive and hence can optimally share
* the same memory.
*/
static uint64_t fw_counters_data[SBI_HARTMASK_MAX_BITS][SBI_PMU_FW_CTR_MAX] = {0};
/* Maximum number of hardware events available */
static uint32_t num_hw_events;
@@ -97,8 +81,7 @@ static uint32_t num_hw_ctrs;
static uint32_t total_ctrs;
/* Helper macros to retrieve event idx and code type */
#define get_cidx_type(x) \
(((x) & SBI_PMU_EVENT_IDX_TYPE_MASK) >> SBI_PMU_EVENT_IDX_TYPE_OFFSET)
#define get_cidx_type(x) ((x & SBI_PMU_EVENT_IDX_TYPE_MASK) >> 16)
#define get_cidx_code(x) (x & SBI_PMU_EVENT_IDX_CODE_MASK)
/**
@@ -127,13 +110,13 @@ static bool pmu_event_select_overlap(struct sbi_pmu_hw_event *evt,
return false;
}
static int pmu_event_validate(struct sbi_pmu_hart_state *phs,
unsigned long event_idx, uint64_t edata)
static int pmu_event_validate(unsigned long event_idx, uint64_t edata)
{
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;
u32 hartid = current_hartid();
switch(event_idx_type) {
case SBI_PMU_EVENT_TYPE_HW:
@@ -147,7 +130,7 @@ static int pmu_event_validate(struct sbi_pmu_hart_state *phs,
if (SBI_PMU_FW_PLATFORM == event_idx_code &&
pmu_dev && pmu_dev->fw_event_validate_encoding)
return pmu_dev->fw_event_validate_encoding(phs->hartid,
return pmu_dev->fw_event_validate_encoding(hartid,
edata);
else
event_idx_code_max = SBI_PMU_FW_MAX;
@@ -181,16 +164,16 @@ static int pmu_event_validate(struct sbi_pmu_hart_state *phs,
return SBI_EINVAL;
}
static int pmu_ctr_validate(struct sbi_pmu_hart_state *phs,
uint32_t cidx, uint32_t *event_idx_code)
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();
if (cidx >= total_ctrs)
return SBI_EINVAL;
event_idx_val = phs->active_events[cidx];
event_idx_val = active_events[hartid][cidx];
event_idx_type = get_cidx_type(event_idx_val);
if (event_idx_val == SBI_PMU_EVENT_IDX_INVALID ||
event_idx_type >= SBI_PMU_EVENT_TYPE_MAX)
@@ -205,9 +188,9 @@ int sbi_pmu_ctr_fw_read(uint32_t cidx, uint64_t *cval)
{
int event_idx_type;
uint32_t event_code;
struct sbi_pmu_hart_state *phs = pmu_thishart_state_ptr();
u32 hartid = current_hartid();
event_idx_type = pmu_ctr_validate(phs, cidx, &event_code);
event_idx_type = pmu_ctr_validate(cidx, &event_code);
if (event_idx_type != SBI_PMU_EVENT_TYPE_FW)
return SBI_EINVAL;
@@ -218,13 +201,13 @@ int sbi_pmu_ctr_fw_read(uint32_t cidx, uint64_t *cval)
if (SBI_PMU_FW_PLATFORM == event_code) {
if (pmu_dev && pmu_dev->fw_counter_read_value)
*cval = pmu_dev->fw_counter_read_value(phs->hartid,
*cval = pmu_dev->fw_counter_read_value(hartid,
cidx -
num_hw_ctrs);
else
*cval = 0;
} else
*cval = phs->fw_counters_data[cidx - num_hw_ctrs];
*cval = fw_counters_data[hartid][cidx - num_hw_ctrs];
return 0;
}
@@ -236,7 +219,8 @@ static int pmu_add_hw_event_map(u32 eidx_start, u32 eidx_end, u32 cmap,
bool is_overlap;
struct sbi_pmu_hw_event *event = &hw_event_map[num_hw_events];
struct sbi_scratch *scratch = sbi_scratch_thishart_ptr();
uint32_t ctr_avail_mask = sbi_hart_mhpm_mask(scratch) | 0x7;
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))
@@ -371,11 +355,12 @@ static int pmu_ctr_start_hw(uint32_t cidx, uint64_t ival, bool ival_update)
if (sbi_hart_has_extension(scratch, SBI_HART_EXT_SSCOFPMF))
pmu_ctr_enable_irq_hw(cidx);
if (ival_update)
pmu_ctr_write_hw(cidx, ival);
if (pmu_dev && pmu_dev->hw_counter_enable_irq)
pmu_dev->hw_counter_enable_irq(cidx);
if (ival_update)
pmu_ctr_write_hw(cidx, ival);
csr_write(CSR_MCOUNTINHIBIT, mctr_inhbt);
return 0;
@@ -393,11 +378,12 @@ int sbi_pmu_irq_bit(void)
return 0;
}
static int pmu_ctr_start_fw(struct sbi_pmu_hart_state *phs,
uint32_t cidx, uint32_t event_code,
static int pmu_ctr_start_fw(uint32_t cidx, uint32_t event_code,
uint64_t event_data, uint64_t ival,
bool ival_update)
{
u32 hartid = current_hartid();
if ((event_code >= SBI_PMU_FW_MAX &&
event_code <= SBI_PMU_FW_RESERVED_MAX) ||
event_code > SBI_PMU_FW_PLATFORM)
@@ -411,19 +397,18 @@ static int pmu_ctr_start_fw(struct sbi_pmu_hart_state *phs,
}
if (ival_update)
pmu_dev->fw_counter_write_value(phs->hartid,
pmu_dev->fw_counter_write_value(hartid,
cidx - num_hw_ctrs,
ival);
return pmu_dev->fw_counter_start(phs->hartid,
cidx - num_hw_ctrs,
return pmu_dev->fw_counter_start(hartid, cidx - num_hw_ctrs,
event_data);
} else {
if (ival_update)
phs->fw_counters_data[cidx - num_hw_ctrs] = ival;
fw_counters_data[hartid][cidx - num_hw_ctrs] = ival;
}
phs->fw_counters_started |= BIT(cidx - num_hw_ctrs);
fw_counters_started[hartid] |= BIT(cidx - num_hw_ctrs);
return 0;
}
@@ -431,7 +416,7 @@ static int pmu_ctr_start_fw(struct sbi_pmu_hart_state *phs,
int sbi_pmu_ctr_start(unsigned long cbase, unsigned long cmask,
unsigned long flags, uint64_t ival)
{
struct sbi_pmu_hart_state *phs = pmu_thishart_state_ptr();
u32 hartid = current_hartid();
int event_idx_type;
uint32_t event_code;
int ret = SBI_EINVAL;
@@ -442,24 +427,21 @@ int sbi_pmu_ctr_start(unsigned long cbase, unsigned long cmask,
if ((cbase + sbi_fls(cmask)) >= total_ctrs)
return ret;
if (flags & SBI_PMU_STOP_FLAG_TAKE_SNAPSHOT)
return SBI_ENO_SHMEM;
if (flags & SBI_PMU_START_FLAG_SET_INIT_VALUE)
bUpdate = true;
for_each_set_bit(i, &cmask, BITS_PER_LONG) {
for_each_set_bit(i, &cmask, total_ctrs) {
cidx = i + cbase;
event_idx_type = pmu_ctr_validate(phs, cidx, &event_code);
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) {
edata = (event_code == SBI_PMU_FW_PLATFORM) ?
phs->fw_counters_data[cidx - num_hw_ctrs]
fw_counters_data[hartid][cidx - num_hw_ctrs]
: 0x0;
ret = pmu_ctr_start_fw(phs, cidx, event_code, edata,
ival, bUpdate);
ret = pmu_ctr_start_fw(cidx, event_code, edata, ival,
bUpdate);
}
else
ret = pmu_ctr_start_hw(cidx, ival, bUpdate);
@@ -485,17 +467,14 @@ static int pmu_ctr_stop_hw(uint32_t cidx)
if (!__test_bit(cidx, &mctr_inhbt)) {
__set_bit(cidx, &mctr_inhbt);
csr_write(CSR_MCOUNTINHIBIT, mctr_inhbt);
if (pmu_dev && pmu_dev->hw_counter_disable_irq) {
pmu_dev->hw_counter_disable_irq(cidx);
}
return 0;
} else
return SBI_EALREADY_STOPPED;
}
static int pmu_ctr_stop_fw(struct sbi_pmu_hart_state *phs,
uint32_t cidx, uint32_t event_code)
static int pmu_ctr_stop_fw(uint32_t cidx, uint32_t event_code)
{
u32 hartid = current_hartid();
int ret;
if ((event_code >= SBI_PMU_FW_MAX &&
@@ -505,12 +484,12 @@ static int pmu_ctr_stop_fw(struct sbi_pmu_hart_state *phs,
if (SBI_PMU_FW_PLATFORM == event_code &&
pmu_dev && pmu_dev->fw_counter_stop) {
ret = pmu_dev->fw_counter_stop(phs->hartid, cidx - num_hw_ctrs);
ret = pmu_dev->fw_counter_stop(hartid, cidx - num_hw_ctrs);
if (ret)
return ret;
}
phs->fw_counters_started &= ~BIT(cidx - num_hw_ctrs);
fw_counters_started[current_hartid()] &= ~BIT(cidx - num_hw_ctrs);
return 0;
}
@@ -534,7 +513,7 @@ static int pmu_reset_hw_mhpmevent(int ctr_idx)
int sbi_pmu_ctr_stop(unsigned long cbase, unsigned long cmask,
unsigned long flag)
{
struct sbi_pmu_hart_state *phs = pmu_thishart_state_ptr();
u32 hartid = current_hartid();
int ret = SBI_EINVAL;
int event_idx_type;
uint32_t event_code;
@@ -543,23 +522,23 @@ int sbi_pmu_ctr_stop(unsigned long cbase, unsigned long cmask,
if ((cbase + sbi_fls(cmask)) >= total_ctrs)
return SBI_EINVAL;
if (flag & SBI_PMU_STOP_FLAG_TAKE_SNAPSHOT)
return SBI_ENO_SHMEM;
for_each_set_bit(i, &cmask, BITS_PER_LONG) {
for_each_set_bit(i, &cmask, total_ctrs) {
cidx = i + cbase;
event_idx_type = pmu_ctr_validate(phs, cidx, &event_code);
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(phs, cidx, event_code);
ret = pmu_ctr_stop_fw(cidx, event_code);
else
ret = pmu_ctr_stop_hw(cidx);
if (cidx > (CSR_INSTRET - CSR_CYCLE) && flag & SBI_PMU_STOP_FLAG_RESET) {
phs->active_events[cidx] = SBI_PMU_EVENT_IDX_INVALID;
if (flag & SBI_PMU_STOP_FLAG_RESET) {
if (pmu_dev && pmu_dev->hw_counter_disable_irq)
pmu_dev->hw_counter_disable_irq(cidx);
active_events[hartid][cidx] = SBI_PMU_EVENT_IDX_INVALID;
pmu_reset_hw_mhpmevent(cidx);
}
}
@@ -605,10 +584,7 @@ static int pmu_update_hw_mhpmevent(struct sbi_pmu_hw_event *hw_evt, int ctr_idx,
pmu_dev->hw_counter_disable_irq(ctr_idx);
/* Update the inhibit flags based on inhibit flags received from supervisor */
if (sbi_hart_has_extension(scratch, SBI_HART_EXT_SSCOFPMF))
pmu_update_inhibit_flags(flags, &mhpmevent_val);
if (pmu_dev && pmu_dev->hw_counter_filter_mode)
pmu_dev->hw_counter_filter_mode(flags, ctr_idx);
pmu_update_inhibit_flags(flags, &mhpmevent_val);
#if __riscv_xlen == 32
csr_write_num(CSR_MHPMEVENT3 + ctr_idx - 3, mhpmevent_val & 0xFFFFFFFF);
@@ -622,50 +598,7 @@ static int pmu_update_hw_mhpmevent(struct sbi_pmu_hw_event *hw_evt, int ctr_idx,
return 0;
}
static int pmu_fixed_ctr_update_inhibit_bits(int fixed_ctr, unsigned long flags)
{
struct sbi_scratch *scratch = sbi_scratch_thishart_ptr();
uint64_t cfg_val = 0, cfg_csr_no;
#if __riscv_xlen == 32
uint64_t cfgh_csr_no;
#endif
if (!sbi_hart_has_extension(scratch, SBI_HART_EXT_SMCNTRPMF) &&
!(pmu_dev && pmu_dev->hw_counter_filter_mode))
return fixed_ctr;
switch (fixed_ctr) {
case 0:
cfg_csr_no = CSR_MCYCLECFG;
#if __riscv_xlen == 32
cfgh_csr_no = CSR_MCYCLECFGH;
#endif
break;
case 2:
cfg_csr_no = CSR_MINSTRETCFG;
#if __riscv_xlen == 32
cfgh_csr_no = CSR_MINSTRETCFGH;
#endif
break;
default:
return SBI_EFAIL;
}
cfg_val |= MHPMEVENT_MINH;
if (sbi_hart_has_extension(scratch, SBI_HART_EXT_SMCNTRPMF)) {
pmu_update_inhibit_flags(flags, &cfg_val);
#if __riscv_xlen == 32
csr_write_num(cfg_csr_no, cfg_val & 0xFFFFFFFF);
csr_write_num(cfgh_csr_no, cfg_val >> BITS_PER_LONG);
#else
csr_write_num(cfg_csr_no, cfg_val);
#endif
}
if (pmu_dev && pmu_dev->hw_counter_filter_mode)
pmu_dev->hw_counter_filter_mode(flags, fixed_ctr);
return fixed_ctr;
}
static int pmu_ctr_find_fixed_hw(unsigned long evt_idx_code)
static int pmu_ctr_find_fixed_fw(unsigned long evt_idx_code)
{
/* Non-programmables counters are enabled always. No need to do lookup */
if (evt_idx_code == SBI_PMU_HW_CPU_CYCLES)
@@ -676,15 +609,14 @@ static int pmu_ctr_find_fixed_hw(unsigned long evt_idx_code)
return SBI_EINVAL;
}
static int pmu_ctr_find_hw(struct sbi_pmu_hart_state *phs,
unsigned long cbase, unsigned long cmask,
unsigned long flags,
static int pmu_ctr_find_hw(unsigned long cbase, unsigned long cmask, unsigned long flags,
unsigned long event_idx, uint64_t data)
{
unsigned long ctr_mask;
int i, ret = 0, fixed_ctr, ctr_idx = SBI_ENOTSUPP;
struct sbi_pmu_hw_event *temp;
unsigned long mctr_inhbt = 0;
u32 hartid = current_hartid();
struct sbi_scratch *scratch = sbi_scratch_thishart_ptr();
if (cbase >= num_hw_ctrs)
@@ -694,10 +626,10 @@ static int pmu_ctr_find_hw(struct sbi_pmu_hart_state *phs,
* If Sscof is present try to find the programmable counter for
* cycle/instret as well.
*/
fixed_ctr = pmu_ctr_find_fixed_hw(event_idx);
fixed_ctr = pmu_ctr_find_fixed_fw(event_idx);
if (fixed_ctr >= 0 &&
!sbi_hart_has_extension(scratch, SBI_HART_EXT_SSCOFPMF))
return pmu_fixed_ctr_update_inhibit_bits(fixed_ctr, flags);
return fixed_ctr;
if (sbi_hart_priv_version(scratch) >= SBI_HART_PRIV_VER_1_11)
mctr_inhbt = csr_read(CSR_MCOUNTINHIBIT);
@@ -723,7 +655,7 @@ static int pmu_ctr_find_hw(struct sbi_pmu_hart_state *phs,
* Some of the platform may not support mcountinhibit.
* Checking the active_events is enough for them
*/
if (phs->active_events[cbase] != SBI_PMU_EVENT_IDX_INVALID)
if (active_events[hartid][cbase] != SBI_PMU_EVENT_IDX_INVALID)
continue;
/* If mcountinhibit is supported, the bit must be enabled */
if ((sbi_hart_priv_version(scratch) >= SBI_HART_PRIV_VER_1_11) &&
@@ -740,7 +672,7 @@ static int pmu_ctr_find_hw(struct sbi_pmu_hart_state *phs,
* Return the fixed counter as they are mandatory anyways.
*/
if (fixed_ctr >= 0)
return pmu_fixed_ctr_update_inhibit_bits(fixed_ctr, flags);
return fixed_ctr;
else
return SBI_EFAIL;
}
@@ -758,9 +690,8 @@ static int pmu_ctr_find_hw(struct sbi_pmu_hart_state *phs,
* Thus, select the first available fw counter after sanity
* check.
*/
static int pmu_ctr_find_fw(struct sbi_pmu_hart_state *phs,
unsigned long cbase, unsigned long cmask,
uint32_t event_code, uint64_t edata)
static int pmu_ctr_find_fw(unsigned long cbase, unsigned long cmask,
uint32_t event_code, u32 hartid, uint64_t edata)
{
int i, cidx;
@@ -773,11 +704,11 @@ static int pmu_ctr_find_fw(struct sbi_pmu_hart_state *phs,
cidx = i + cbase;
if (cidx < num_hw_ctrs || total_ctrs <= cidx)
continue;
if (phs->active_events[i] != SBI_PMU_EVENT_IDX_INVALID)
if (active_events[hartid][i] != SBI_PMU_EVENT_IDX_INVALID)
continue;
if (SBI_PMU_FW_PLATFORM == event_code &&
pmu_dev && pmu_dev->fw_counter_match_encoding) {
if (!pmu_dev->fw_counter_match_encoding(phs->hartid,
if (!pmu_dev->fw_counter_match_encoding(hartid,
cidx - num_hw_ctrs,
edata))
continue;
@@ -793,15 +724,15 @@ 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)
{
struct sbi_pmu_hart_state *phs = pmu_thishart_state_ptr();
int ret, event_type, ctr_idx = SBI_ENOTSUPP;
u32 event_code;
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 ((cidx_base + sbi_fls(cidx_mask)) >= total_ctrs)
return SBI_EINVAL;
event_type = pmu_event_validate(phs, event_idx, event_data);
event_type = pmu_event_validate(event_idx, event_data);
if (event_type < 0)
return SBI_EINVAL;
event_code = get_cidx_code(event_idx);
@@ -810,34 +741,29 @@ int sbi_pmu_ctr_cfg_match(unsigned long cidx_base, unsigned long cidx_mask,
/* The caller wants to skip the match because it already knows the
* counter idx for the given event. Verify that the counter idx
* is still valid.
* As per the specification, we should "unconditionally select
* the first counter from the set of counters specified by the
* counter_idx_base and counter_idx_mask".
*/
unsigned long cidx_first = cidx_base + sbi_ffs(cidx_mask);
if (phs->active_events[cidx_first] == SBI_PMU_EVENT_IDX_INVALID)
if (active_events[hartid][cidx_base] == SBI_PMU_EVENT_IDX_INVALID)
return SBI_EINVAL;
ctr_idx = cidx_first;
ctr_idx = cidx_base;
goto skip_match;
}
if (event_type == SBI_PMU_EVENT_TYPE_FW) {
/* Any firmware counter can be used track any firmware event */
ctr_idx = pmu_ctr_find_fw(phs, cidx_base, cidx_mask,
event_code, event_data);
ctr_idx = pmu_ctr_find_fw(cidx_base, cidx_mask, event_code,
hartid, event_data);
if (event_code == SBI_PMU_FW_PLATFORM)
phs->fw_counters_data[ctr_idx - num_hw_ctrs] =
fw_counters_data[hartid][ctr_idx - num_hw_ctrs] =
event_data;
} else {
ctr_idx = pmu_ctr_find_hw(phs, cidx_base, cidx_mask, flags,
event_idx, event_data);
ctr_idx = pmu_ctr_find_hw(cidx_base, cidx_mask, flags, event_idx,
event_data);
}
if (ctr_idx < 0)
return SBI_ENOTSUPP;
phs->active_events[ctr_idx] = event_idx;
active_events[hartid][ctr_idx] = event_idx;
skip_match:
if (event_type == SBI_PMU_EVENT_TYPE_HW) {
if (flags & SBI_PMU_CFG_FLAG_CLEAR_VALUE)
@@ -846,17 +772,16 @@ skip_match:
pmu_ctr_start_hw(ctr_idx, 0, false);
} else if (event_type == SBI_PMU_EVENT_TYPE_FW) {
if (flags & SBI_PMU_CFG_FLAG_CLEAR_VALUE)
phs->fw_counters_data[ctr_idx - num_hw_ctrs] = 0;
fw_counters_data[hartid][ctr_idx - num_hw_ctrs] = 0;
if (flags & SBI_PMU_CFG_FLAG_AUTO_START) {
if (SBI_PMU_FW_PLATFORM == event_code &&
pmu_dev && pmu_dev->fw_counter_start) {
ret = pmu_dev->fw_counter_start(
phs->hartid,
ret = pmu_dev->fw_counter_start(hartid,
ctr_idx - num_hw_ctrs, event_data);
if (ret)
return ret;
}
phs->fw_counters_started |= BIT(ctr_idx - num_hw_ctrs);
fw_counters_started[hartid] |= BIT(ctr_idx - num_hw_ctrs);
}
}
@@ -865,20 +790,19 @@ skip_match:
int sbi_pmu_ctr_incr_fw(enum sbi_pmu_fw_event_code_id fw_id)
{
u32 cidx;
u32 cidx, hartid = current_hartid();
uint64_t *fcounter = NULL;
struct sbi_pmu_hart_state *phs = pmu_thishart_state_ptr();
if (likely(!phs->fw_counters_started))
if (likely(!fw_counters_started[hartid]))
return 0;
if (unlikely(fw_id >= SBI_PMU_FW_MAX))
return SBI_EINVAL;
for (cidx = num_hw_ctrs; cidx < total_ctrs; cidx++) {
if (get_cidx_code(phs->active_events[cidx]) == fw_id &&
(phs->fw_counters_started & BIT(cidx - num_hw_ctrs))) {
fcounter = &phs->fw_counters_data[cidx - num_hw_ctrs];
if (get_cidx_code(active_events[hartid][cidx]) == fw_id &&
(fw_counters_started[hartid] & BIT(cidx - num_hw_ctrs))) {
fcounter = &fw_counters_data[hartid][cidx - num_hw_ctrs];
break;
}
}
@@ -899,17 +823,13 @@ int sbi_pmu_ctr_get_info(uint32_t cidx, unsigned long *ctr_info)
int width;
union sbi_pmu_ctr_info cinfo = {0};
struct sbi_scratch *scratch = sbi_scratch_thishart_ptr();
unsigned long counter_mask = (unsigned long)sbi_hart_mhpm_mask(scratch) |
SBI_PMU_CY_IR_MASK;
/* Sanity check */
if (cidx >= total_ctrs)
/* Sanity check. Counter1 is not mapped at all */
if (cidx >= total_ctrs || cidx == 1)
return SBI_EINVAL;
/* We have 31 HW counters with 31 being the last index(MHPMCOUNTER31) */
if (cidx < num_hw_ctrs) {
if (!(__test_bit(cidx, &counter_mask)))
return SBI_EINVAL;
cinfo.type = SBI_PMU_CTR_TYPE_HW;
cinfo.csr = CSR_CYCLE + cidx;
/* mcycle & minstret are always 64 bit */
@@ -934,16 +854,16 @@ int sbi_pmu_ctr_get_info(uint32_t cidx, unsigned long *ctr_info)
return 0;
}
static void pmu_reset_event_map(struct sbi_pmu_hart_state *phs)
static void pmu_reset_event_map(u32 hartid)
{
int j;
/* Initialize the counter to event mapping table */
for (j = 3; j < total_ctrs; j++)
phs->active_events[j] = SBI_PMU_EVENT_IDX_INVALID;
active_events[hartid][j] = SBI_PMU_EVENT_IDX_INVALID;
for (j = 0; j < SBI_PMU_FW_CTR_MAX; j++)
phs->fw_counters_data[j] = 0;
phs->fw_counters_started = 0;
fw_counters_data[hartid][j] = 0;
fw_counters_started[hartid] = 0;
}
const struct sbi_pmu_device *sbi_pmu_get_device(void)
@@ -961,71 +881,44 @@ void sbi_pmu_set_device(const struct sbi_pmu_device *dev)
void sbi_pmu_exit(struct sbi_scratch *scratch)
{
u32 hartid = current_hartid();
const struct sbi_platform *plat = sbi_platform_ptr(scratch);
if (sbi_hart_priv_version(scratch) >= SBI_HART_PRIV_VER_1_11)
csr_write(CSR_MCOUNTINHIBIT, 0xFFFFFFF8);
if (sbi_hart_priv_version(scratch) >= SBI_HART_PRIV_VER_1_10)
csr_write(CSR_MCOUNTEREN, -1);
pmu_reset_event_map(pmu_get_hart_state_ptr(scratch));
if (sbi_platform_force_emulate_time_csr(plat))
csr_clear(CSR_MCOUNTEREN, MCOUNTEREN_TM);
pmu_reset_event_map(hartid);
}
int sbi_pmu_init(struct sbi_scratch *scratch, bool cold_boot)
{
int hpm_count = sbi_fls(sbi_hart_mhpm_mask(scratch));
struct sbi_pmu_hart_state *phs;
const struct sbi_platform *plat;
int rc;
u32 hartid = current_hartid();
if (cold_boot) {
hw_event_map = sbi_calloc(sizeof(*hw_event_map),
SBI_PMU_HW_EVENT_MAX);
if (!hw_event_map)
return SBI_ENOMEM;
phs_ptr_offset = sbi_scratch_alloc_type_offset(void *);
if (!phs_ptr_offset) {
sbi_free(hw_event_map);
return SBI_ENOMEM;
}
plat = sbi_platform_ptr(scratch);
/* Initialize hw pmu events */
rc = sbi_platform_pmu_init(plat);
if (rc)
sbi_dprintf("%s: platform pmu init failed "
"(error %d)\n", __func__, rc);
sbi_platform_pmu_init(plat);
/* mcycle & minstret is available always */
if (!hpm_count)
/* Only CY, TM & IR are implemented in the hw */
num_hw_ctrs = 3;
else
num_hw_ctrs = hpm_count + 1;
if (num_hw_ctrs > SBI_PMU_HW_CTR_MAX)
return SBI_EINVAL;
num_hw_ctrs = sbi_hart_mhpm_count(scratch) + 3;
total_ctrs = num_hw_ctrs + SBI_PMU_FW_CTR_MAX;
}
phs = pmu_get_hart_state_ptr(scratch);
if (!phs) {
phs = sbi_zalloc(sizeof(*phs));
if (!phs)
return SBI_ENOMEM;
phs->hartid = current_hartid();
pmu_set_hart_state_ptr(scratch, phs);
}
pmu_reset_event_map(phs);
pmu_reset_event_map(hartid);
/* First three counters are fixed by the priv spec and we enable it by default */
phs->active_events[0] = (SBI_PMU_EVENT_TYPE_HW << SBI_PMU_EVENT_IDX_TYPE_OFFSET) |
SBI_PMU_HW_CPU_CYCLES;
phs->active_events[1] = SBI_PMU_EVENT_IDX_INVALID;
phs->active_events[2] = (SBI_PMU_EVENT_TYPE_HW << SBI_PMU_EVENT_IDX_TYPE_OFFSET) |
SBI_PMU_HW_INSTRUCTIONS;
active_events[hartid][0] = SBI_PMU_EVENT_TYPE_HW << SBI_PMU_EVENT_IDX_OFFSET |
SBI_PMU_HW_CPU_CYCLES;
active_events[hartid][1] = SBI_PMU_EVENT_IDX_INVALID;
active_events[hartid][2] = SBI_PMU_EVENT_TYPE_HW << SBI_PMU_EVENT_IDX_OFFSET |
SBI_PMU_HW_INSTRUCTIONS;
return 0;
}

View File

@@ -14,40 +14,29 @@
#include <sbi/sbi_scratch.h>
#include <sbi/sbi_string.h>
u32 last_hartindex_having_scratch = 0;
u32 hartindex_to_hartid_table[SBI_HARTMASK_MAX_BITS + 1] = { -1U };
struct sbi_scratch *hartindex_to_scratch_table[SBI_HARTMASK_MAX_BITS + 1] = { 0 };
u32 last_hartid_having_scratch = SBI_HARTMASK_MAX_BITS - 1;
struct sbi_scratch *hartid_to_scratch_table[SBI_HARTMASK_MAX_BITS] = { 0 };
static spinlock_t extra_lock = SPIN_LOCK_INITIALIZER;
static unsigned long extra_offset = SBI_SCRATCH_EXTRA_SPACE_OFFSET;
u32 sbi_hartid_to_hartindex(u32 hartid)
{
u32 i;
for (i = 0; i <= last_hartindex_having_scratch; i++)
if (hartindex_to_hartid_table[i] == hartid)
return i;
return -1U;
}
typedef struct sbi_scratch *(*hartid2scratch)(ulong hartid, ulong hartindex);
int sbi_scratch_init(struct sbi_scratch *scratch)
{
u32 i, h;
u32 i;
const struct sbi_platform *plat = sbi_platform_ptr(scratch);
for (i = 0; i < plat->hart_count; i++) {
h = (plat->hart_index2id) ? plat->hart_index2id[i] : i;
hartindex_to_hartid_table[i] = h;
hartindex_to_scratch_table[i] =
((hartid2scratch)scratch->hartid_to_scratch)(h, i);
for (i = 0; i < SBI_HARTMASK_MAX_BITS; i++) {
if (sbi_platform_hart_invalid(plat, i))
continue;
hartid_to_scratch_table[i] =
((hartid2scratch)scratch->hartid_to_scratch)(i,
sbi_platform_hart_index(plat, i));
if (hartid_to_scratch_table[i])
last_hartid_having_scratch = i;
}
last_hartindex_having_scratch = plat->hart_count - 1;
return 0;
}
@@ -70,8 +59,8 @@ unsigned long sbi_scratch_alloc_offset(unsigned long size)
if (!size)
return 0;
size += __SIZEOF_POINTER__ - 1;
size &= ~((unsigned long)__SIZEOF_POINTER__ - 1);
if (size & (__SIZEOF_POINTER__ - 1))
size = (size & ~(__SIZEOF_POINTER__ - 1)) + __SIZEOF_POINTER__;
spin_lock(&extra_lock);
@@ -85,8 +74,8 @@ done:
spin_unlock(&extra_lock);
if (ret) {
for (i = 0; i <= sbi_scratch_last_hartindex(); i++) {
rscratch = sbi_hartindex_to_scratch(i);
for (i = 0; i <= sbi_scratch_last_hartid(); i++) {
rscratch = sbi_hartid_to_scratch(i);
if (!rscratch)
continue;
ptr = sbi_scratch_offset_ptr(rscratch, ret);
@@ -108,14 +97,3 @@ void sbi_scratch_free_offset(unsigned long offset)
* brain-dead allocator.
*/
}
unsigned long sbi_scratch_used_space(void)
{
unsigned long ret = 0;
spin_lock(&extra_lock);
ret = extra_offset;
spin_unlock(&extra_lock);
return ret;
}

View File

@@ -72,8 +72,7 @@ void __noreturn sbi_system_reset(u32 reset_type, u32 reset_reason)
/* Send HALT IPI to every hart other than the current hart */
while (!sbi_hsm_hart_interruptible_mask(dom, hbase, &hmask)) {
if ((hbase <= cur_hartid)
&& (cur_hartid < hbase + BITS_PER_LONG))
if (hbase <= cur_hartid)
hmask &= ~(1UL << (cur_hartid - hbase));
if (hmask)
sbi_ipi_send_halt(hmask, hbase);
@@ -112,7 +111,7 @@ void sbi_system_suspend_set_device(struct sbi_system_suspend_device *dev)
static int sbi_system_suspend_test_check(u32 sleep_type)
{
return sleep_type == SBI_SUSP_SLEEP_TYPE_SUSPEND ? 0 : SBI_EINVAL;
return sleep_type == SBI_SUSP_SLEEP_TYPE_SUSPEND;
}
static int sbi_system_suspend_test_suspend(u32 sleep_type,
@@ -143,40 +142,37 @@ void sbi_system_suspend_test_enable(void)
bool sbi_system_suspend_supported(u32 sleep_type)
{
return suspend_dev && suspend_dev->system_suspend_check &&
suspend_dev->system_suspend_check(sleep_type) == 0;
suspend_dev->system_suspend_check(sleep_type);
}
int sbi_system_suspend(u32 sleep_type, ulong resume_addr, ulong opaque)
{
int ret = SBI_ENOTSUPP;
const struct sbi_domain *dom = sbi_domain_thishart_ptr();
struct sbi_scratch *scratch = sbi_scratch_thishart_ptr();
void (*jump_warmboot)(void) = (void (*)(void))scratch->warmboot_addr;
unsigned int hartid = current_hartid();
unsigned long prev_mode;
unsigned long i, j;
int ret;
unsigned long i;
if (!dom || !dom->system_suspend_allowed)
return SBI_EFAIL;
if (!suspend_dev || !suspend_dev->system_suspend ||
!suspend_dev->system_suspend_check)
if (!suspend_dev || !suspend_dev->system_suspend)
return SBI_EFAIL;
ret = suspend_dev->system_suspend_check(sleep_type);
if (ret != SBI_OK)
return ret;
if (!sbi_system_suspend_supported(sleep_type))
return SBI_ENOTSUPP;
prev_mode = (csr_read(CSR_MSTATUS) & MSTATUS_MPP) >> MSTATUS_MPP_SHIFT;
if (prev_mode != PRV_S && prev_mode != PRV_U)
return SBI_EFAIL;
sbi_hartmask_for_each_hartindex(j, &dom->assigned_harts) {
i = sbi_hartindex_to_hartid(j);
sbi_hartmask_for_each_hart(i, &dom->assigned_harts) {
if (i == hartid)
continue;
if (__sbi_hsm_hart_get_state(i) != SBI_HSM_STATE_STOPPED)
return SBI_ERR_DENIED;
return SBI_EFAIL;
}
if (!sbi_domain_check_addr(dom, resume_addr, prev_mode,

View File

@@ -188,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_extension(scratch, SBI_HART_EXT_ZICNTR))
if (sbi_hart_has_extension(scratch, SBI_HART_EXT_TIME))
get_time_val = get_ticks;
} else {
if (!time_delta_off)

View File

@@ -14,7 +14,6 @@
#include <sbi/sbi_error.h>
#include <sbi/sbi_fifo.h>
#include <sbi/sbi_hart.h>
#include <sbi/sbi_heap.h>
#include <sbi/sbi_ipi.h>
#include <sbi/sbi_scratch.h>
#include <sbi/sbi_tlb.h>
@@ -34,7 +33,7 @@ static void tlb_flush_all(void)
__asm__ __volatile("sfence.vma");
}
static void sbi_tlb_local_hfence_vvma(struct sbi_tlb_info *tinfo)
void sbi_tlb_local_hfence_vvma(struct sbi_tlb_info *tinfo)
{
unsigned long start = tinfo->start;
unsigned long size = tinfo->size;
@@ -59,7 +58,7 @@ done:
csr_write(CSR_HGATP, hgatp);
}
static void sbi_tlb_local_hfence_gvma(struct sbi_tlb_info *tinfo)
void sbi_tlb_local_hfence_gvma(struct sbi_tlb_info *tinfo)
{
unsigned long start = tinfo->start;
unsigned long size = tinfo->size;
@@ -77,7 +76,7 @@ static void sbi_tlb_local_hfence_gvma(struct sbi_tlb_info *tinfo)
}
}
static void sbi_tlb_local_sfence_vma(struct sbi_tlb_info *tinfo)
void sbi_tlb_local_sfence_vma(struct sbi_tlb_info *tinfo)
{
unsigned long start = tinfo->start;
unsigned long size = tinfo->size;
@@ -98,7 +97,7 @@ static void sbi_tlb_local_sfence_vma(struct sbi_tlb_info *tinfo)
}
}
static void sbi_tlb_local_hfence_vvma_asid(struct sbi_tlb_info *tinfo)
void sbi_tlb_local_hfence_vvma_asid(struct sbi_tlb_info *tinfo)
{
unsigned long start = tinfo->start;
unsigned long size = tinfo->size;
@@ -111,7 +110,12 @@ static void sbi_tlb_local_hfence_vvma_asid(struct sbi_tlb_info *tinfo)
hgatp = csr_swap(CSR_HGATP,
(vmid << HGATP_VMID_SHIFT) & HGATP_VMID_MASK);
if ((start == 0 && size == 0) || (size == SBI_TLB_FLUSH_ALL)) {
if (start == 0 && size == 0) {
__sbi_hfence_vvma_all();
goto done;
}
if (size == SBI_TLB_FLUSH_ALL) {
__sbi_hfence_vvma_asid(asid);
goto done;
}
@@ -124,7 +128,7 @@ done:
csr_write(CSR_HGATP, hgatp);
}
static void sbi_tlb_local_hfence_gvma_vmid(struct sbi_tlb_info *tinfo)
void sbi_tlb_local_hfence_gvma_vmid(struct sbi_tlb_info *tinfo)
{
unsigned long start = tinfo->start;
unsigned long size = tinfo->size;
@@ -133,7 +137,12 @@ static void sbi_tlb_local_hfence_gvma_vmid(struct sbi_tlb_info *tinfo)
sbi_pmu_ctr_incr_fw(SBI_PMU_FW_HFENCE_GVMA_VMID_RCVD);
if ((start == 0 && size == 0) || (size == SBI_TLB_FLUSH_ALL)) {
if (start == 0 && size == 0) {
__sbi_hfence_gvma_all();
return;
}
if (size == SBI_TLB_FLUSH_ALL) {
__sbi_hfence_gvma_vmid(vmid);
return;
}
@@ -143,7 +152,7 @@ static void sbi_tlb_local_hfence_gvma_vmid(struct sbi_tlb_info *tinfo)
}
}
static void sbi_tlb_local_sfence_vma_asid(struct sbi_tlb_info *tinfo)
void sbi_tlb_local_sfence_vma_asid(struct sbi_tlb_info *tinfo)
{
unsigned long start = tinfo->start;
unsigned long size = tinfo->size;
@@ -152,8 +161,13 @@ static void sbi_tlb_local_sfence_vma_asid(struct sbi_tlb_info *tinfo)
sbi_pmu_ctr_incr_fw(SBI_PMU_FW_SFENCE_VMA_ASID_RCVD);
if (start == 0 && size == 0) {
tlb_flush_all();
return;
}
/* Flush entire MM context for a given ASID */
if ((start == 0 && size == 0) || (size == SBI_TLB_FLUSH_ALL)) {
if (size == SBI_TLB_FLUSH_ALL) {
__asm__ __volatile__("sfence.vma x0, %0"
:
: "r"(asid)
@@ -169,55 +183,44 @@ static void sbi_tlb_local_sfence_vma_asid(struct sbi_tlb_info *tinfo)
}
}
static void sbi_tlb_local_fence_i(struct sbi_tlb_info *tinfo)
void sbi_tlb_local_fence_i(struct sbi_tlb_info *tinfo)
{
sbi_pmu_ctr_incr_fw(SBI_PMU_FW_FENCE_I_RECVD);
__asm__ __volatile("fence.i");
}
static void tlb_entry_local_process(struct sbi_tlb_info *data)
static void tlb_pmu_incr_fw_ctr(struct sbi_tlb_info *data)
{
if (unlikely(!data))
return;
switch (data->type) {
case SBI_TLB_FENCE_I:
sbi_tlb_local_fence_i(data);
break;
case SBI_TLB_SFENCE_VMA:
sbi_tlb_local_sfence_vma(data);
break;
case SBI_TLB_SFENCE_VMA_ASID:
sbi_tlb_local_sfence_vma_asid(data);
break;
case SBI_TLB_HFENCE_GVMA_VMID:
sbi_tlb_local_hfence_gvma_vmid(data);
break;
case SBI_TLB_HFENCE_GVMA:
sbi_tlb_local_hfence_gvma(data);
break;
case SBI_TLB_HFENCE_VVMA_ASID:
sbi_tlb_local_hfence_vvma_asid(data);
break;
case SBI_TLB_HFENCE_VVMA:
sbi_tlb_local_hfence_vvma(data);
break;
default:
break;
};
if (data->local_fn == sbi_tlb_local_fence_i)
sbi_pmu_ctr_incr_fw(SBI_PMU_FW_FENCE_I_SENT);
else if (data->local_fn == sbi_tlb_local_sfence_vma)
sbi_pmu_ctr_incr_fw(SBI_PMU_FW_SFENCE_VMA_SENT);
else if (data->local_fn == sbi_tlb_local_sfence_vma_asid)
sbi_pmu_ctr_incr_fw(SBI_PMU_FW_SFENCE_VMA_ASID_SENT);
else if (data->local_fn == sbi_tlb_local_hfence_gvma)
sbi_pmu_ctr_incr_fw(SBI_PMU_FW_HFENCE_GVMA_SENT);
else if (data->local_fn == sbi_tlb_local_hfence_gvma_vmid)
sbi_pmu_ctr_incr_fw(SBI_PMU_FW_HFENCE_GVMA_VMID_SENT);
else if (data->local_fn == sbi_tlb_local_hfence_vvma)
sbi_pmu_ctr_incr_fw(SBI_PMU_FW_HFENCE_VVMA_SENT);
else if (data->local_fn == sbi_tlb_local_hfence_vvma_asid)
sbi_pmu_ctr_incr_fw(SBI_PMU_FW_HFENCE_VVMA_ASID_SENT);
}
static void tlb_entry_process(struct sbi_tlb_info *tinfo)
static void tlb_process_helper(struct sbi_tlb_info *tinfo)
{
u32 rindex;
u32 rhartid;
struct sbi_scratch *rscratch = NULL;
atomic_t *rtlb_sync = NULL;
tlb_entry_local_process(tinfo);
tinfo->local_fn(tinfo);
sbi_hartmask_for_each_hartindex(rindex, &tinfo->smask) {
rscratch = sbi_hartindex_to_scratch(rindex);
sbi_hartmask_for_each_hart(rhartid, &tinfo->smask) {
rscratch = sbi_hartid_to_scratch(rhartid);
if (!rscratch)
continue;
@@ -226,29 +229,29 @@ static void tlb_entry_process(struct sbi_tlb_info *tinfo)
}
}
static bool tlb_process_once(struct sbi_scratch *scratch)
static int tlb_process_once(struct sbi_scratch *scratch)
{
struct sbi_tlb_info tinfo;
struct sbi_fifo *tlb_fifo =
sbi_scratch_offset_ptr(scratch, tlb_fifo_off);
if (!sbi_fifo_dequeue(tlb_fifo, &tinfo)) {
tlb_entry_process(&tinfo);
return true;
tlb_process_helper(&tinfo);
return 0;
}
return false;
return -1;
}
static void tlb_process(struct sbi_scratch *scratch)
{
while (tlb_process_once(scratch));
while (!tlb_process_once(scratch));
}
static void tlb_sync(struct sbi_scratch *scratch)
{
atomic_t *tlb_sync =
sbi_scratch_offset_ptr(scratch, tlb_sync_off);
sbi_scratch_offset_ptr(scratch, tlb_sync_off);
while (atomic_read(tlb_sync) > 0) {
/*
@@ -316,12 +319,12 @@ static int tlb_update_cb(void *in, void *data)
curr = (struct sbi_tlb_info *)data;
next = (struct sbi_tlb_info *)in;
if (next->type == SBI_TLB_SFENCE_VMA_ASID &&
curr->type == SBI_TLB_SFENCE_VMA_ASID) {
if (next->local_fn == sbi_tlb_local_sfence_vma_asid &&
curr->local_fn == sbi_tlb_local_sfence_vma_asid) {
if (next->asid == curr->asid)
ret = tlb_range_check(curr, next);
} else if (next->type == SBI_TLB_SFENCE_VMA &&
curr->type == SBI_TLB_SFENCE_VMA) {
} else if (next->local_fn == sbi_tlb_local_sfence_vma &&
curr->local_fn == sbi_tlb_local_sfence_vma) {
ret = tlb_range_check(curr, next);
}
@@ -330,7 +333,7 @@ static int tlb_update_cb(void *in, void *data)
static int tlb_update(struct sbi_scratch *scratch,
struct sbi_scratch *remote_scratch,
u32 remote_hartindex, void *data)
u32 remote_hartid, void *data)
{
int ret;
atomic_t *tlb_sync;
@@ -338,64 +341,6 @@ static int tlb_update(struct sbi_scratch *scratch,
struct sbi_tlb_info *tinfo = data;
u32 curr_hartid = current_hartid();
/*
* If the request is to queue a tlb flush entry for itself
* then just do a local flush and return;
*/
if (sbi_hartindex_to_hartid(remote_hartindex) == curr_hartid) {
tlb_entry_local_process(tinfo);
return SBI_IPI_UPDATE_BREAK;
}
tlb_fifo_r = sbi_scratch_offset_ptr(remote_scratch, tlb_fifo_off);
ret = sbi_fifo_inplace_update(tlb_fifo_r, data, tlb_update_cb);
if (ret == SBI_FIFO_UNCHANGED && sbi_fifo_enqueue(tlb_fifo_r, data) < 0) {
/**
* For now, Busy loop until there is space in the fifo.
* There may be case where target hart is also
* enqueue in source hart's fifo. Both hart may busy
* loop leading to a deadlock.
* TODO: Introduce a wait/wakeup event mechanism to handle
* this properly.
*/
tlb_process_once(scratch);
sbi_dprintf("hart%d: hart%d tlb fifo full\n", curr_hartid,
sbi_hartindex_to_hartid(remote_hartindex));
return SBI_IPI_UPDATE_RETRY;
}
tlb_sync = sbi_scratch_offset_ptr(scratch, tlb_sync_off);
atomic_add_return(tlb_sync, 1);
return SBI_IPI_UPDATE_SUCCESS;
}
static struct sbi_ipi_event_ops tlb_ops = {
.name = "IPI_TLB",
.update = tlb_update,
.sync = tlb_sync,
.process = tlb_process,
};
static u32 tlb_event = SBI_IPI_EVENT_MAX;
static const u32 tlb_type_to_pmu_fw_event[SBI_TLB_TYPE_MAX] = {
[SBI_TLB_FENCE_I] = SBI_PMU_FW_FENCE_I_SENT,
[SBI_TLB_SFENCE_VMA] = SBI_PMU_FW_SFENCE_VMA_SENT,
[SBI_TLB_SFENCE_VMA_ASID] = SBI_PMU_FW_SFENCE_VMA_ASID_SENT,
[SBI_TLB_HFENCE_GVMA_VMID] = SBI_PMU_FW_HFENCE_GVMA_VMID_SENT,
[SBI_TLB_HFENCE_GVMA] = SBI_PMU_FW_HFENCE_GVMA_SENT,
[SBI_TLB_HFENCE_VVMA_ASID] = SBI_PMU_FW_HFENCE_VVMA_ASID_SENT,
[SBI_TLB_HFENCE_VVMA] = SBI_PMU_FW_HFENCE_VVMA_SENT,
};
int sbi_tlb_request(ulong hmask, ulong hbase, struct sbi_tlb_info *tinfo)
{
if (tinfo->type < 0 || tinfo->type >= SBI_TLB_TYPE_MAX)
return SBI_EINVAL;
/*
* If address range to flush is too big then simply
* upgrade it to flush all because we can only flush
@@ -406,7 +351,54 @@ int sbi_tlb_request(ulong hmask, ulong hbase, struct sbi_tlb_info *tinfo)
tinfo->size = SBI_TLB_FLUSH_ALL;
}
sbi_pmu_ctr_incr_fw(tlb_type_to_pmu_fw_event[tinfo->type]);
/*
* If the request is to queue a tlb flush entry for itself
* then just do a local flush and return;
*/
if (remote_hartid == curr_hartid) {
tinfo->local_fn(tinfo);
return -1;
}
tlb_fifo_r = sbi_scratch_offset_ptr(remote_scratch, tlb_fifo_off);
ret = sbi_fifo_inplace_update(tlb_fifo_r, data, tlb_update_cb);
if (ret == SBI_FIFO_UNCHANGED && sbi_fifo_enqueue(tlb_fifo_r, data) < 0) {
/**
* For now, Busy loop until there is space in the fifo.
* There may be case where target hart is also
* enqueue in source hart's fifo. Both hart may busy
* loop leading to a deadlock.
* TODO: Introduce a wait/wakeup event mechanism to handle
* this properly.
*/
tlb_process_once(scratch);
sbi_dprintf("hart%d: hart%d tlb fifo full\n",
curr_hartid, remote_hartid);
return -2;
}
tlb_sync = sbi_scratch_offset_ptr(scratch, tlb_sync_off);
atomic_add_return(tlb_sync, 1);
return 0;
}
static struct sbi_ipi_event_ops tlb_ops = {
.name = "IPI_TLB",
.update = tlb_update,
.sync = tlb_sync,
.process = tlb_process,
};
static u32 tlb_event = SBI_IPI_EVENT_MAX;
int sbi_tlb_request(ulong hmask, ulong hbase, struct sbi_tlb_info *tinfo)
{
if (!tinfo->local_fn)
return SBI_EINVAL;
tlb_pmu_incr_fw_ctr(tinfo);
return sbi_ipi_send_many(hmask, hbase, tlb_event, tinfo);
}
@@ -428,7 +420,8 @@ int sbi_tlb_init(struct sbi_scratch *scratch, bool cold_boot)
sbi_scratch_free_offset(tlb_sync_off);
return SBI_ENOMEM;
}
tlb_fifo_mem_off = sbi_scratch_alloc_offset(sizeof(tlb_mem));
tlb_fifo_mem_off = sbi_scratch_alloc_offset(
SBI_TLB_FIFO_NUM_ENTRIES * SBI_TLB_INFO_SIZE);
if (!tlb_fifo_mem_off) {
sbi_scratch_free_offset(tlb_fifo_off);
sbi_scratch_free_offset(tlb_sync_off);
@@ -454,19 +447,12 @@ int sbi_tlb_init(struct sbi_scratch *scratch, bool cold_boot)
tlb_sync = sbi_scratch_offset_ptr(scratch, tlb_sync_off);
tlb_q = sbi_scratch_offset_ptr(scratch, tlb_fifo_off);
tlb_mem = sbi_scratch_read_type(scratch, void *, tlb_fifo_mem_off);
if (!tlb_mem) {
tlb_mem = sbi_malloc(
sbi_platform_tlb_fifo_num_entries(plat) * SBI_TLB_INFO_SIZE);
if (!tlb_mem)
return SBI_ENOMEM;
sbi_scratch_write_type(scratch, void *, tlb_fifo_mem_off, tlb_mem);
}
tlb_mem = sbi_scratch_offset_ptr(scratch, tlb_fifo_mem_off);
ATOMIC_INIT(tlb_sync, 0);
tlb_sync->counter = 0;
sbi_fifo_init(tlb_q, tlb_mem,
sbi_platform_tlb_fifo_num_entries(plat), SBI_TLB_INFO_SIZE);
SBI_TLB_FIFO_NUM_ENTRIES, SBI_TLB_INFO_SIZE);
return 0;
}

View File

@@ -212,7 +212,7 @@ static int sbi_trap_nonaia_irq(struct sbi_trap_regs *regs, ulong mcause)
return sbi_irqchip_process(regs);
default:
return SBI_ENOENT;
}
};
return 0;
}
@@ -320,7 +320,7 @@ struct sbi_trap_regs *sbi_trap_handler(struct sbi_trap_regs *regs)
rc = sbi_trap_redirect(regs, &trap);
break;
}
};
trap_error:
if (rc)

View File

@@ -163,7 +163,7 @@ ulong sbi_get_insn(ulong mepc, struct sbi_trap_info *trap)
break;
default:
break;
}
};
return insn;
}

View File

@@ -14,8 +14,6 @@ source "$(OPENSBI_SRC_DIR)/lib/utils/irqchip/Kconfig"
source "$(OPENSBI_SRC_DIR)/lib/utils/libfdt/Kconfig"
source "$(OPENSBI_SRC_DIR)/lib/utils/regmap/Kconfig"
source "$(OPENSBI_SRC_DIR)/lib/utils/reset/Kconfig"
source "$(OPENSBI_SRC_DIR)/lib/utils/serial/Kconfig"

View File

@@ -15,11 +15,4 @@ config FDT_PMU
bool "FDT performance monitoring unit (PMU) support"
default n
config FDT_FIXUPS_PRESERVE_PMU_NODE
bool "Preserve PMU node in device-tree"
depends on FDT_PMU
default n
help
Preserve PMU node properties for debugging purposes.
endif

View File

@@ -13,7 +13,6 @@
#include <sbi/sbi_domain.h>
#include <sbi/sbi_error.h>
#include <sbi/sbi_hartmask.h>
#include <sbi/sbi_heap.h>
#include <sbi/sbi_scratch.h>
#include <sbi_utils/fdt/fdt_domain.h>
#include <sbi_utils/fdt/fdt_helper.h>
@@ -220,13 +219,14 @@ skip_device_disable:
fdt_nop_node(fdt, poffset);
}
#define FDT_DOMAIN_MAX_COUNT 8
#define FDT_DOMAIN_REGION_MAX_COUNT 16
struct parse_region_data {
struct sbi_domain *dom;
u32 region_count;
u32 max_regions;
};
static u32 fdt_domains_count;
static struct sbi_domain fdt_domains[FDT_DOMAIN_MAX_COUNT];
static struct sbi_hartmask fdt_masks[FDT_DOMAIN_MAX_COUNT];
static struct sbi_domain_memregion
fdt_regions[FDT_DOMAIN_MAX_COUNT][FDT_DOMAIN_REGION_MAX_COUNT + 1];
static int __fdt_parse_region(void *fdt, int domain_offset,
int region_offset, u32 region_access,
@@ -236,7 +236,7 @@ static int __fdt_parse_region(void *fdt, int domain_offset,
u32 val32;
u64 val64;
const u32 *val;
struct parse_region_data *preg = opaque;
u32 *region_count = opaque;
struct sbi_domain_memregion *region;
/*
@@ -252,9 +252,9 @@ static int __fdt_parse_region(void *fdt, int domain_offset,
return SBI_EINVAL;
/* Find next region of the domain */
if (preg->max_regions <= preg->region_count)
return SBI_ENOSPC;
region = &preg->dom->regions[preg->region_count];
if (FDT_DOMAIN_REGION_MAX_COUNT <= *region_count)
return SBI_EINVAL;
region = &fdt_regions[fdt_domains_count][*region_count];
/* Read "base" DT property */
val = fdt_getprop(fdt, region_offset, "base", &len);
@@ -278,7 +278,7 @@ static int __fdt_parse_region(void *fdt, int domain_offset,
if (fdt_get_property(fdt, region_offset, "mmio", NULL))
region->flags |= SBI_DOMAIN_MEMREGION_MMIO;
preg->region_count++;
(*region_count)++;
return 0;
}
@@ -291,30 +291,16 @@ static int __fdt_parse_domain(void *fdt, int domain_offset, void *opaque)
struct sbi_domain *dom;
struct sbi_hartmask *mask;
struct sbi_hartmask assign_mask;
struct parse_region_data preg;
int *cold_domain_offset = opaque;
struct sbi_domain_memregion *reg;
int i, err = 0, len, cpus_offset, cpu_offset, doffset;
struct sbi_domain_memregion *reg, *regions;
int i, err, len, cpus_offset, cpu_offset, doffset;
dom = sbi_zalloc(sizeof(*dom));
if (!dom)
return SBI_ENOMEM;
dom->regions = sbi_calloc(sizeof(*dom->regions),
FDT_DOMAIN_REGION_MAX_COUNT + 1);
if (!dom->regions) {
err = SBI_ENOMEM;
goto fail_free_domain;
}
preg.dom = dom;
preg.region_count = 0;
preg.max_regions = FDT_DOMAIN_REGION_MAX_COUNT;
mask = sbi_zalloc(sizeof(*mask));
if (!mask) {
err = SBI_ENOMEM;
goto fail_free_regions;
}
/* Sanity check on maximum domains we can handle */
if (FDT_DOMAIN_MAX_COUNT <= fdt_domains_count)
return SBI_EINVAL;
dom = &fdt_domains[fdt_domains_count];
mask = &fdt_masks[fdt_domains_count];
regions = &fdt_regions[fdt_domains_count][0];
/* Read DT node name */
strncpy(dom->name, fdt_get_name(fdt, domain_offset, NULL),
@@ -330,27 +316,29 @@ static int __fdt_parse_domain(void *fdt, int domain_offset, void *opaque)
for (i = 0; i < len; i++) {
cpu_offset = fdt_node_offset_by_phandle(fdt,
fdt32_to_cpu(val[i]));
if (cpu_offset < 0) {
err = cpu_offset;
goto fail_free_all;
}
if (cpu_offset < 0)
return cpu_offset;
err = fdt_parse_hart_id(fdt, cpu_offset, &val32);
if (err)
goto fail_free_all;
return err;
if (!fdt_node_is_enabled(fdt, cpu_offset))
continue;
sbi_hartmask_set_hartid(val32, mask);
sbi_hartmask_set_hart(val32, mask);
}
}
/* Setup memregions from DT */
err = fdt_iterate_each_memregion(fdt, domain_offset, &preg,
val32 = 0;
memset(regions, 0,
sizeof(*regions) * (FDT_DOMAIN_REGION_MAX_COUNT + 1));
dom->regions = regions;
err = fdt_iterate_each_memregion(fdt, domain_offset, &val32,
__fdt_parse_region);
if (err)
goto fail_free_all;
return err;
/*
* Copy over root domain memregions which don't allow
@@ -366,13 +354,10 @@ static int __fdt_parse_domain(void *fdt, int domain_offset, void *opaque)
(reg->flags & SBI_DOMAIN_MEMREGION_SU_WRITABLE) ||
(reg->flags & SBI_DOMAIN_MEMREGION_SU_EXECUTABLE))
continue;
if (preg.max_regions <= preg.region_count) {
err = SBI_EINVAL;
goto fail_free_all;
}
memcpy(&dom->regions[preg.region_count++], reg, sizeof(*reg));
if (FDT_DOMAIN_REGION_MAX_COUNT <= val32)
return SBI_EINVAL;
memcpy(&regions[val32++], reg, sizeof(*reg));
}
dom->fw_region_inited = root.fw_region_inited;
/* Read "boot-hart" DT property */
val32 = -1U;
@@ -441,10 +426,8 @@ static int __fdt_parse_domain(void *fdt, int domain_offset, void *opaque)
/* Find /cpus DT node */
cpus_offset = fdt_path_offset(fdt, "/cpus");
if (cpus_offset < 0) {
err = cpus_offset;
goto fail_free_all;
}
if (cpus_offset < 0)
return cpus_offset;
/* HART to domain assignment mask based on CPU DT nodes */
sbi_hartmask_clear_all(&assign_mask);
@@ -460,35 +443,22 @@ static int __fdt_parse_domain(void *fdt, int domain_offset, void *opaque)
continue;
val = fdt_getprop(fdt, cpu_offset, "opensbi-domain", &len);
if (!val || len < 4) {
err = SBI_EINVAL;
goto fail_free_all;
}
if (!val || len < 4)
return SBI_EINVAL;
doffset = fdt_node_offset_by_phandle(fdt, fdt32_to_cpu(*val));
if (doffset < 0) {
err = doffset;
goto fail_free_all;
}
if (doffset < 0)
return doffset;
if (doffset == domain_offset)
sbi_hartmask_set_hartid(val32, &assign_mask);
sbi_hartmask_set_hart(val32, &assign_mask);
}
/* Increment domains count */
fdt_domains_count++;
/* Register the domain */
err = sbi_domain_register(dom, &assign_mask);
if (err)
goto fail_free_all;
return 0;
fail_free_all:
sbi_free(mask);
fail_free_regions:
sbi_free(dom->regions);
fail_free_domain:
sbi_free(dom);
return err;
return sbi_domain_register(dom, &assign_mask);
}
int fdt_domains_populate(void *fdt)

View File

@@ -210,7 +210,7 @@ void fdt_plic_fixup(void *fdt)
static int fdt_resv_memory_update_node(void *fdt, unsigned long addr,
unsigned long size, int index,
int parent)
int parent, bool no_map)
{
int na = fdt_address_cells(fdt, 0);
int ns = fdt_size_cells(fdt, 0);
@@ -239,14 +239,16 @@ static int fdt_resv_memory_update_node(void *fdt, unsigned long addr,
if (subnode < 0)
return subnode;
/*
* Tell operating system not to create a virtual
* mapping of the region as part of its standard
* mapping of system memory.
*/
err = fdt_setprop_empty(fdt, subnode, "no-map");
if (err < 0)
return err;
if (no_map) {
/*
* Tell operating system not to create a virtual
* mapping of the region as part of its standard
* mapping of system memory.
*/
err = fdt_setprop_empty(fdt, subnode, "no-map");
if (err < 0)
return err;
}
/* encode the <reg> property value */
val = reg;
@@ -284,6 +286,7 @@ int fdt_reserved_memory_fixup(void *fdt)
{
struct sbi_domain_memregion *reg;
struct sbi_domain *dom = sbi_domain_thishart_ptr();
struct sbi_scratch *scratch = sbi_scratch_thishart_ptr();
unsigned long filtered_base[PMP_COUNT] = { 0 };
unsigned char filtered_order[PMP_COUNT] = { 0 };
unsigned long addr, size;
@@ -352,7 +355,7 @@ int fdt_reserved_memory_fixup(void *fdt)
if (reg->flags & SBI_DOMAIN_MEMREGION_SU_EXECUTABLE)
continue;
if (i >= PMP_COUNT) {
if (i > PMP_COUNT) {
sbi_printf("%s: Too many memory regions to fixup.\n",
__func__);
return SBI_ENOSPC;
@@ -379,7 +382,33 @@ int fdt_reserved_memory_fixup(void *fdt)
for (j = 0; j < i; j++) {
addr = filtered_base[j];
size = 1UL << filtered_order[j];
fdt_resv_memory_update_node(fdt, addr, size, j, parent);
fdt_resv_memory_update_node(fdt, addr, size, j, parent,
(sbi_hart_pmp_count(scratch))
? false : true);
}
return 0;
}
int fdt_reserved_memory_nomap_fixup(void *fdt)
{
int parent, subnode;
int err;
/* Locate the reserved memory node */
parent = fdt_path_offset(fdt, "/reserved-memory");
if (parent < 0)
return parent;
fdt_for_each_subnode(subnode, fdt, parent) {
/*
* Tell operating system not to create a virtual
* mapping of the region as part of its standard
* mapping of system memory.
*/
err = fdt_setprop_empty(fdt, subnode, "no-map");
if (err < 0)
return err;
}
return 0;
@@ -394,8 +423,5 @@ void fdt_fixups(void *fdt)
fdt_plic_fixup(fdt);
fdt_reserved_memory_fixup(fdt);
#ifndef CONFIG_FDT_FIXUPS_PRESERVE_PMU_NODE
fdt_pmu_fixup(fdt);
#endif
}

View File

@@ -12,7 +12,6 @@
#include <sbi/sbi_hartmask.h>
#include <sbi/sbi_platform.h>
#include <sbi/sbi_scratch.h>
#include <sbi/sbi_hart.h>
#include <sbi_utils/fdt/fdt_helper.h>
#include <sbi_utils/irqchip/aplic.h>
#include <sbi_utils/irqchip/imsic.h>
@@ -216,32 +215,6 @@ int fdt_get_node_addr_size(void *fdt, int node, int index,
return 0;
}
int fdt_get_node_addr_size_by_name(void *fdt, int node, const char *name,
uint64_t *addr, uint64_t *size)
{
int i, j, count;
const char *val;
const char *regname;
if (!fdt || node < 0 || !name)
return SBI_EINVAL;
val = fdt_getprop(fdt, node, "reg-names", &count);
if (!val)
return SBI_ENODEV;
for (i = 0, j = 0; i < count; i++, j++) {
regname = val + i;
if (strcmp(name, regname) == 0)
return fdt_get_node_addr_size(fdt, node, j, addr, size);
i += strlen(regname);
}
return SBI_ENODEV;
}
bool fdt_node_is_enabled(void *fdt, int nodeoff)
{
int len;
@@ -340,149 +313,6 @@ int fdt_parse_timebase_frequency(void *fdt, unsigned long *freq)
return 0;
}
#define RISCV_ISA_EXT_NAME_LEN_MAX 32
static unsigned long fdt_isa_bitmap_offset;
static int fdt_parse_isa_one_hart(const char *isa, unsigned long *extensions)
{
size_t i, j, isa_len;
char mstr[RISCV_ISA_EXT_NAME_LEN_MAX];
i = 0;
isa_len = strlen(isa);
if (isa[i] == 'r' || isa[i] == 'R')
i++;
else
return SBI_EINVAL;
if (isa[i] == 'v' || isa[i] == 'V')
i++;
else
return SBI_EINVAL;
if (isa[i] == '3' || isa[i+1] == '2')
i += 2;
else if (isa[i] == '6' || isa[i+1] == '4')
i += 2;
else
return SBI_EINVAL;
/* Skip base ISA extensions */
for (; i < isa_len; i++) {
if (isa[i] == '_')
break;
}
while (i < isa_len) {
if (isa[i] != '_') {
i++;
continue;
}
/* Skip the '_' character */
i++;
/* Extract the multi-letter extension name */
j = 0;
while ((i < isa_len) && (isa[i] != '_') &&
(j < (sizeof(mstr) - 1)))
mstr[j++] = isa[i++];
mstr[j] = '\0';
/* Skip empty multi-letter extension name */
if (!j)
continue;
#define set_multi_letter_ext(name, bit) \
if (!strcmp(mstr, name)) { \
__set_bit(bit, extensions); \
continue; \
}
for (j = 0; j < SBI_HART_EXT_MAX; j++) {
set_multi_letter_ext(sbi_hart_ext[j].name,
sbi_hart_ext[j].id);
}
#undef set_multi_letter_ext
}
return 0;
}
static int fdt_parse_isa_all_harts(void *fdt)
{
u32 hartid;
const fdt32_t *val;
unsigned long *hart_exts;
struct sbi_scratch *scratch;
int err, cpu_offset, cpus_offset, len;
if (!fdt || !fdt_isa_bitmap_offset)
return SBI_EINVAL;
cpus_offset = fdt_path_offset(fdt, "/cpus");
if (cpus_offset < 0)
return cpus_offset;
fdt_for_each_subnode(cpu_offset, fdt, cpus_offset) {
err = fdt_parse_hart_id(fdt, cpu_offset, &hartid);
if (err)
continue;
if (!fdt_node_is_enabled(fdt, cpu_offset))
continue;
val = fdt_getprop(fdt, cpu_offset, "riscv,isa", &len);
if (!val || len <= 0)
return SBI_ENOENT;
scratch = sbi_hartid_to_scratch(hartid);
if (!scratch)
return SBI_ENOENT;
hart_exts = sbi_scratch_offset_ptr(scratch,
fdt_isa_bitmap_offset);
err = fdt_parse_isa_one_hart((const char *)val, hart_exts);
if (err)
return err;
}
return 0;
}
int fdt_parse_isa_extensions(void *fdt, unsigned int hartid,
unsigned long *extensions)
{
int rc, i;
unsigned long *hart_exts;
struct sbi_scratch *scratch;
if (!fdt_isa_bitmap_offset) {
fdt_isa_bitmap_offset = sbi_scratch_alloc_offset(
sizeof(*hart_exts) *
BITS_TO_LONGS(SBI_HART_EXT_MAX));
if (!fdt_isa_bitmap_offset)
return SBI_ENOMEM;
rc = fdt_parse_isa_all_harts(fdt);
if (rc)
return rc;
}
scratch = sbi_hartid_to_scratch(hartid);
if (!scratch)
return SBI_ENOENT;
hart_exts = sbi_scratch_offset_ptr(scratch, fdt_isa_bitmap_offset);
for (i = 0; i < BITS_TO_LONGS(SBI_HART_EXT_MAX); i++)
extensions[i] |= hart_exts[i];
return 0;
}
static int fdt_parse_uart_node_common(void *fdt, int nodeoffset,
struct platform_uart_data *uart,
unsigned long default_freq,
@@ -859,7 +689,7 @@ int fdt_parse_imsic_node(void *fdt, int nodeoff, struct imsic_data *imsic)
break;
regs->addr = reg_addr;
regs->size = reg_size;
}
};
if (!imsic->regs[0].size)
return SBI_EINVAL;
@@ -880,7 +710,6 @@ int fdt_parse_plic_node(void *fdt, int nodeoffset, struct plic_data *plic)
if (rc < 0 || !reg_addr || !reg_size)
return SBI_ENODEV;
plic->addr = reg_addr;
plic->size = reg_size;
val = fdt_getprop(fdt, nodeoffset, "riscv,ndev", &len);
if (len > 0)
@@ -903,40 +732,21 @@ int fdt_parse_plic(void *fdt, struct plic_data *plic, const char *compat)
return fdt_parse_plic_node(fdt, nodeoffset, plic);
}
static int fdt_get_aclint_addr_size_by_name(void *fdt, int nodeoffset,
unsigned long *out_addr1,
unsigned long *out_size1,
unsigned long *out_addr2,
unsigned long *out_size2)
int fdt_parse_aclint_node(void *fdt, int nodeoffset, bool for_timer,
unsigned long *out_addr1, unsigned long *out_size1,
unsigned long *out_addr2, unsigned long *out_size2,
u32 *out_first_hartid, u32 *out_hart_count)
{
int rc;
const fdt32_t *val;
uint64_t reg_addr, reg_size;
int i, rc, count, cpu_offset, cpu_intc_offset;
u32 phandle, hwirq, hartid, first_hartid, last_hartid, hart_count;
u32 match_hwirq = (for_timer) ? IRQ_M_TIMER : IRQ_M_SOFT;
rc = fdt_get_node_addr_size_by_name(fdt, nodeoffset, "mtime",
&reg_addr, &reg_size);
if (rc < 0 || !reg_size)
reg_addr = reg_size = 0;
*out_addr1 = reg_addr;
*out_size1 = reg_size;
rc = fdt_get_node_addr_size_by_name(fdt, nodeoffset, "mtimecmp",
&reg_addr, &reg_size);
if (rc < 0 || !reg_size)
return SBI_ENODEV;
*out_addr2 = reg_addr;
*out_size2 = reg_size;
return 0;
}
static int fdt_get_aclint_addr_size(void *fdt, int nodeoffset,
unsigned long *out_addr1,
unsigned long *out_size1,
unsigned long *out_addr2,
unsigned long *out_size2)
{
int rc;
uint64_t reg_addr, reg_size;
if (nodeoffset < 0 || !fdt ||
!out_addr1 || !out_size1 ||
!out_first_hartid || !out_hart_count)
return SBI_EINVAL;
rc = fdt_get_node_addr_size(fdt, nodeoffset, 0,
&reg_addr, &reg_size);
@@ -954,37 +764,6 @@ static int fdt_get_aclint_addr_size(void *fdt, int nodeoffset,
if (out_size2)
*out_size2 = reg_size;
return 0;
}
int fdt_parse_aclint_node(void *fdt, int nodeoffset,
bool for_timer, bool allow_regname,
unsigned long *out_addr1, unsigned long *out_size1,
unsigned long *out_addr2, unsigned long *out_size2,
u32 *out_first_hartid, u32 *out_hart_count)
{
const fdt32_t *val;
int i, rc, count, cpu_offset, cpu_intc_offset;
u32 phandle, hwirq, hartid, first_hartid, last_hartid, hart_count;
u32 match_hwirq = (for_timer) ? IRQ_M_TIMER : IRQ_M_SOFT;
if (nodeoffset < 0 || !fdt ||
!out_addr1 || !out_size1 ||
!out_first_hartid || !out_hart_count)
return SBI_EINVAL;
if (for_timer && allow_regname && out_addr2 && out_size2 &&
fdt_getprop(fdt, nodeoffset, "reg-names", NULL))
rc = fdt_get_aclint_addr_size_by_name(fdt, nodeoffset,
out_addr1, out_size1,
out_addr2, out_size2);
else
rc = fdt_get_aclint_addr_size(fdt, nodeoffset,
out_addr1, out_size1,
out_addr2, out_size2);
if (rc)
return rc;
*out_first_hartid = 0;
*out_hart_count = 0;

View File

@@ -14,19 +14,23 @@
#include <sbi/sbi_pmu.h>
#include <sbi/sbi_scratch.h>
#include <sbi_utils/fdt/fdt_helper.h>
#include <sbi_utils/fdt/fdt_pmu.h>
#define FDT_PMU_HW_EVENT_MAX (SBI_PMU_HW_EVENT_MAX * 2)
struct fdt_pmu_hw_event_select_map fdt_pmu_evt_select[FDT_PMU_HW_EVENT_MAX] = {0};
uint32_t hw_event_count;
struct fdt_pmu_hw_event_select {
uint32_t eidx;
uint64_t select;
};
static struct fdt_pmu_hw_event_select fdt_pmu_evt_select[FDT_PMU_HW_EVENT_MAX] = {0};
static uint32_t hw_event_count;
uint64_t fdt_pmu_get_select_value(uint32_t event_idx)
{
int i;
struct fdt_pmu_hw_event_select_map *event;
struct fdt_pmu_hw_event_select *event;
for (i = 0; i < hw_event_count; i++) {
for (i = 0; i < SBI_PMU_HW_EVENT_MAX; i++) {
event = &fdt_pmu_evt_select[i];
if (event->eidx == event_idx)
return event->select;
@@ -61,7 +65,7 @@ int fdt_pmu_setup(void *fdt)
int i, pmu_offset, len, result;
const u32 *event_val;
const u32 *event_ctr_map;
struct fdt_pmu_hw_event_select_map *event;
struct fdt_pmu_hw_event_select *event;
uint64_t raw_selector, select_mask;
u32 event_idx_start, event_idx_end, ctr_map;
@@ -70,7 +74,7 @@ int fdt_pmu_setup(void *fdt)
pmu_offset = fdt_node_offset_by_compatible(fdt, -1, "riscv,pmu");
if (pmu_offset < 0)
return SBI_ENOENT;
return SBI_EFAIL;
event_ctr_map = fdt_getprop(fdt, pmu_offset,
"riscv,event-to-mhpmcounters", &len);

View File

@@ -10,14 +10,14 @@ config FDT_GPIO
if FDT_GPIO
config FDT_GPIO_DESIGNWARE
bool "DesignWare GPIO driver"
default n
config FDT_GPIO_SIFIVE
bool "SiFive GPIO FDT driver"
default n
config FDT_GPIO_SOPHGO
bool "Sophgo GPIO FDT driver"
default n
config FDT_GPIO_STARFIVE
bool "StarFive GPIO FDT driver"
default n

View File

@@ -1,140 +0,0 @@
/*
* SPDX-License-Identifier: BSD-2-Clause
*
* Copyright (c) 2022 SiFive
*
* GPIO driver for Synopsys DesignWare APB GPIO
*
* Authors:
* Ben Dooks <ben.dooks@sifive.com>
*/
#include <libfdt.h>
#include <sbi/riscv_io.h>
#include <sbi/sbi_error.h>
#include <sbi_utils/fdt/fdt_helper.h>
#include <sbi_utils/gpio/fdt_gpio.h>
#define DW_GPIO_CHIP_MAX 4 /* need 1 per bank in use */
#define DW_GPIO_PINS_MAX 32
#define DW_GPIO_DDR 0x4
#define DW_GPIO_DR 0x0
#define DW_GPIO_BIT(_b) (1UL << (_b))
struct dw_gpio_chip {
void *dr;
void *ext;
struct gpio_chip chip;
};
extern struct fdt_gpio fdt_gpio_designware;
static unsigned int dw_gpio_chip_count;
static struct dw_gpio_chip dw_gpio_chip_array[DW_GPIO_CHIP_MAX];
#define pin_to_chip(__p) container_of((__p)->chip, struct dw_gpio_chip, chip);
static int dw_gpio_direction_output(struct gpio_pin *gp, int value)
{
struct dw_gpio_chip *chip = pin_to_chip(gp);
unsigned long v;
v = readl(chip->dr + DW_GPIO_DR);
if (!value)
v &= ~DW_GPIO_BIT(gp->offset);
else
v |= DW_GPIO_BIT(gp->offset);
writel(v, chip->dr + DW_GPIO_DR);
/* the DR is output only so we can set it then the DDR to set
* the data direction, to avoid glitches.
*/
v = readl(chip->dr + DW_GPIO_DDR);
v |= DW_GPIO_BIT(gp->offset);
writel(v, chip->dr + DW_GPIO_DDR);
return 0;
}
static void dw_gpio_set(struct gpio_pin *gp, int value)
{
struct dw_gpio_chip *chip = pin_to_chip(gp);
unsigned long v;
v = readl(chip->dr + DW_GPIO_DR);
if (!value)
v &= ~DW_GPIO_BIT(gp->offset);
else
v |= DW_GPIO_BIT(gp->offset);
writel(v, chip->dr + DW_GPIO_DR);
}
/* notes:
* each sub node is a bank and has ngpios or snpns,nr-gpios and a reg property
* with the compatible `snps,dw-apb-gpio-port`.
* bank A is the only one with irq support but we're not using it here
*/
static int dw_gpio_init_bank(void *fdt, int nodeoff, u32 phandle,
const struct fdt_match *match)
{
struct dw_gpio_chip *chip;
const fdt32_t *val;
uint64_t addr;
int rc, poff, nr_pins, bank, len;
if (dw_gpio_chip_count >= DW_GPIO_CHIP_MAX)
return SBI_ENOSPC;
/* need to get parent for the address property */
poff = fdt_parent_offset(fdt, nodeoff);
if (poff < 0)
return SBI_EINVAL;
rc = fdt_get_node_addr_size(fdt, poff, 0, &addr, NULL);
if (rc)
return rc;
val = fdt_getprop(fdt, nodeoff, "reg", &len);
if (!val || len <= 0)
return SBI_EINVAL;
bank = fdt32_to_cpu(*val);
val = fdt_getprop(fdt, nodeoff, "snps,nr-gpios", &len);
if (!val)
val = fdt_getprop(fdt, nodeoff, "ngpios", &len);
if (!val || len <= 0)
return SBI_EINVAL;
nr_pins = fdt32_to_cpu(*val);
chip = &dw_gpio_chip_array[dw_gpio_chip_count];
chip->dr = (void *)(uintptr_t)addr + (bank * 0xc);
chip->ext = (void *)(uintptr_t)addr + (bank * 4) + 0x50;
chip->chip.driver = &fdt_gpio_designware;
chip->chip.id = phandle;
chip->chip.ngpio = nr_pins;
chip->chip.set = dw_gpio_set;
chip->chip.direction_output = dw_gpio_direction_output;
rc = gpio_chip_add(&chip->chip);
if (rc)
return rc;
dw_gpio_chip_count++;
return 0;
}
/* since we're only probed when used, match on port not main controller node */
static const struct fdt_match dw_gpio_match[] = {
{ .compatible = "snps,dw-apb-gpio-port" },
{ },
};
struct fdt_gpio fdt_gpio_designware = {
.match_table = dw_gpio_match,
.xlate = fdt_gpio_simple_xlate,
.init = dw_gpio_init_bank,
};

View File

@@ -9,10 +9,11 @@
#include <sbi/riscv_io.h>
#include <sbi/sbi_error.h>
#include <sbi/sbi_heap.h>
#include <sbi_utils/fdt/fdt_helper.h>
#include <sbi_utils/gpio/fdt_gpio.h>
#define SIFIVE_GPIO_CHIP_MAX 2
#define SIFIVE_GPIO_PINS_MIN 1
#define SIFIVE_GPIO_PINS_MAX 32
#define SIFIVE_GPIO_PINS_DEF 16
@@ -26,6 +27,9 @@ struct sifive_gpio_chip {
struct gpio_chip chip;
};
static unsigned int sifive_gpio_chip_count;
static struct sifive_gpio_chip sifive_gpio_chip_array[SIFIVE_GPIO_CHIP_MAX];
static int sifive_gpio_direction_output(struct gpio_pin *gp, int value)
{
unsigned int v;
@@ -69,15 +73,13 @@ static int sifive_gpio_init(void *fdt, int nodeoff, u32 phandle,
struct sifive_gpio_chip *chip;
uint64_t addr;
chip = sbi_zalloc(sizeof(*chip));
if (!chip)
return SBI_ENOMEM;
if (SIFIVE_GPIO_CHIP_MAX <= sifive_gpio_chip_count)
return SBI_ENOSPC;
chip = &sifive_gpio_chip_array[sifive_gpio_chip_count];
rc = fdt_get_node_addr_size(fdt, nodeoff, 0, &addr, NULL);
if (rc) {
sbi_free(chip);
if (rc)
return rc;
}
chip->addr = addr;
chip->chip.driver = &fdt_gpio_sifive;
@@ -86,11 +88,10 @@ static int sifive_gpio_init(void *fdt, int nodeoff, u32 phandle,
chip->chip.direction_output = sifive_gpio_direction_output;
chip->chip.set = sifive_gpio_set;
rc = gpio_chip_add(&chip->chip);
if (rc) {
sbi_free(chip);
if (rc)
return rc;
}
sifive_gpio_chip_count++;
return 0;
}

View File

@@ -0,0 +1,157 @@
/*
* SPDX-License-Identifier: BSD-2-Clause
*
* Copyright (c) 2023 Sophgo
*
* Author:
* Chunzhi Lin <chunzhi.lin@sophgo.com>
*/
#include <libfdt.h>
#include <sbi/riscv_io.h>
#include <sbi/sbi_error.h>
#include <sbi/sbi_console.h>
#include <sbi_utils/fdt/fdt_helper.h>
#include <sbi_utils/gpio/fdt_gpio.h>
#define SOPHGO_GPIO_CHIP_MAX 3
#define SOPHGO_GPIO_PINS_MIN 0
#define SOPHGO_GPIO_PINS_MAX 31
#define SOPHGO_GPIO_PINS_DEF 16
#define SOPHGO_GPIO_SWPORTA_DR_OFFSET 0x00
#define SOPHGO_GPIO_SWPORTA_DDR_OFFSET 0x04
#define SOPHGO_GPIO_SWPORTA_CTL_OFFSET 0x08
#define SOPHGO_GPIO_BIT(offset) (1U << (offset))
#define SOPHGO_GPIO_STARTUP_FLAG SOPHGO_GPIO_BIT(16)
struct sophgo_gpio_chip {
unsigned long addr;
struct gpio_chip chip;
};
static unsigned int sophgo_gpio_chip_count;
static struct sophgo_gpio_chip sophgo_gpio_chip_array[SOPHGO_GPIO_CHIP_MAX];
static int sophgo_gpio_direction_output(struct gpio_pin *gp, int value)
{
unsigned int v;
struct sophgo_gpio_chip *chip =
container_of(gp->chip, struct sophgo_gpio_chip, chip);
v = readl((volatile void *)(chip->addr + SOPHGO_GPIO_SWPORTA_DDR_OFFSET));
v |= SOPHGO_GPIO_BIT(gp->offset);
writel(v, (volatile void *)(chip->addr + SOPHGO_GPIO_SWPORTA_DDR_OFFSET));
v = readl((volatile void *)(chip->addr + SOPHGO_GPIO_SWPORTA_DR_OFFSET));
if (!value)
v &= ~SOPHGO_GPIO_BIT(gp->offset);
else
v |= SOPHGO_GPIO_BIT(gp->offset);
writel(v, (volatile void *)(chip->addr + SOPHGO_GPIO_SWPORTA_DR_OFFSET));
return 0;
}
static void sophgo_gpio_set(struct gpio_pin *gp, int value)
{
unsigned int v;
struct sophgo_gpio_chip *chip =
container_of(gp->chip, struct sophgo_gpio_chip, chip);
v = readl((volatile void *)(chip->addr + SOPHGO_GPIO_SWPORTA_DR_OFFSET));
if (!value)
v &= ~SOPHGO_GPIO_BIT(gp->offset);
else
v |= SOPHGO_GPIO_BIT(gp->offset);
writel(v, (volatile void *)(chip->addr + SOPHGO_GPIO_SWPORTA_DR_OFFSET));
return;
}
static int sophgo_gpio_addr_get(void *fdt, int nodeoff, unsigned long *addr)
{
int parent, len;
unsigned long addr_high, addr_low;
const fdt32_t *prop_addr;
parent = fdt_parent_offset(fdt, nodeoff);
if (parent < 0)
return parent;
prop_addr = fdt_getprop(fdt, parent, "reg", &len);
if (!prop_addr)
return SBI_ENODEV;
addr_high = fdt32_to_cpu(*prop_addr++);
addr_low = fdt32_to_cpu(*prop_addr);
*addr = addr_high << 32 | addr_low;
return 0;
}
static void sophgo_system_normal_startup_flag(unsigned long addr)
{
unsigned int v;
v = readl((volatile void *)(addr + SOPHGO_GPIO_SWPORTA_DDR_OFFSET));
v |= SOPHGO_GPIO_STARTUP_FLAG;
writel(v, (volatile void *)(addr + SOPHGO_GPIO_SWPORTA_DDR_OFFSET));
v = readl((volatile void *)(addr + SOPHGO_GPIO_SWPORTA_DR_OFFSET));
v |= SOPHGO_GPIO_STARTUP_FLAG;
writel(v, (volatile void *)(addr + SOPHGO_GPIO_SWPORTA_DR_OFFSET));
}
extern struct fdt_gpio fdt_gpio_sophgo;
static int sophgo_gpio_init(void *fdt, int nodeoff, u32 phandle,
const struct fdt_match *match)
{
int rc;
struct sophgo_gpio_chip *chip;
unsigned long addr;
if (SOPHGO_GPIO_CHIP_MAX <= sophgo_gpio_chip_count) {
rc = SBI_ENOSPC;
return rc;
}
chip = &sophgo_gpio_chip_array[sophgo_gpio_chip_count];
rc = sophgo_gpio_addr_get(fdt, nodeoff, &addr);
if (rc)
return rc;
chip->addr = addr;
chip->chip.driver = &fdt_gpio_sophgo;
chip->chip.id = phandle;
chip->chip.ngpio = SOPHGO_GPIO_PINS_MAX;
chip->chip.direction_output = sophgo_gpio_direction_output;
chip->chip.set = sophgo_gpio_set;
rc = gpio_chip_add(&chip->chip);
if (rc)
return rc;
sophgo_gpio_chip_count++;
sophgo_system_normal_startup_flag(addr);
return 0;
}
static const struct fdt_match sophgo_gpio_match[] = {
{ .compatible = "sophgo,gpio0" },
{ },
};
struct fdt_gpio fdt_gpio_sophgo = {
.match_table = sophgo_gpio_match,
.xlate = fdt_gpio_simple_xlate,
.init = sophgo_gpio_init,
};

View File

@@ -9,11 +9,11 @@
#include <sbi/riscv_io.h>
#include <sbi/sbi_error.h>
#include <sbi/sbi_heap.h>
#include <sbi/sbi_console.h>
#include <sbi_utils/fdt/fdt_helper.h>
#include <sbi_utils/gpio/fdt_gpio.h>
#define STARFIVE_GPIO_CHIP_MAX 2
#define STARFIVE_GPIO_PINS_DEF 64
#define STARFIVE_GPIO_OUTVAL 0x40
#define STARFIVE_GPIO_MASK 0xff
@@ -25,6 +25,9 @@ struct starfive_gpio_chip {
struct gpio_chip chip;
};
static unsigned int starfive_gpio_chip_count;
static struct starfive_gpio_chip starfive_gpio_chip_array[STARFIVE_GPIO_CHIP_MAX];
static int starfive_gpio_direction_output(struct gpio_pin *gp, int value)
{
u32 val;
@@ -37,6 +40,7 @@ static int starfive_gpio_direction_output(struct gpio_pin *gp, int value)
reg_addr = chip->addr + gp->offset;
reg_addr &= ~(STARFIVE_GPIO_REG_SHIFT_MASK);
val = readl((void *)(reg_addr));
shift_bits = (gp->offset & STARFIVE_GPIO_REG_SHIFT_MASK)
<< STARFIVE_GPIO_SHIFT_BITS;
bit_mask = STARFIVE_GPIO_MASK << shift_bits;
@@ -78,15 +82,13 @@ static int starfive_gpio_init(void *fdt, int nodeoff, u32 phandle,
struct starfive_gpio_chip *chip;
u64 addr;
chip = sbi_zalloc(sizeof(*chip));
if (!chip)
return SBI_ENOMEM;
if (starfive_gpio_chip_count >= STARFIVE_GPIO_CHIP_MAX)
return SBI_ENOSPC;
chip = &starfive_gpio_chip_array[starfive_gpio_chip_count];
rc = fdt_get_node_addr_size(fdt, nodeoff, 0, &addr, NULL);
if (rc) {
sbi_free(chip);
if (rc)
return rc;
}
chip->addr = addr;
chip->chip.driver = &fdt_gpio_starfive;
@@ -95,11 +97,10 @@ static int starfive_gpio_init(void *fdt, int nodeoff, u32 phandle,
chip->chip.direction_output = starfive_gpio_direction_output;
chip->chip.set = starfive_gpio_set;
rc = gpio_chip_add(&chip->chip);
if (rc) {
sbi_free(chip);
if (rc)
return rc;
}
starfive_gpio_chip_count++;
return 0;
}

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