RISC-V Patches for the 5.12 Merge Window
I have a handful of new RISC-V related patches for this merge window: * A check to ensure drivers are properly using uaccess. This isn't manifesting with any of the drivers I'm currently using, but may catch errors in new drivers. * Some preliminary support for the FU740, along with the HiFive Unleashed it will appear on. * NUMA support for RISC-V, which involves making the arm64 code generic. * Support for kasan on the vmalloc region. * A handful of new drivers for the Kendryte K210, along with the DT plumbing required to boot on a handful of K210-based boards. * Support for allocating ASIDs. * Preliminary support for kernels larger than 128MiB. * Various other improvements to our KASAN support, including the utilization of huge pages when allocating the KASAN regions. We may have already found a bug with the KASAN_VMALLOC code, but it's passing my tests. There's a fix in the works, but that will probably miss the merge window. -----BEGIN PGP SIGNATURE----- iQJHBAABCgAxFiEEKzw3R0RoQ7JKlDp6LhMZ81+7GIkFAmA4hXATHHBhbG1lckBk YWJiZWx0LmNvbQAKCRAuExnzX7sYifryD/0SfXGOfj93Cxq7I7AYhhzCN7lJ5jvv iEQScTlPqU9nfvYodo4EDq0fp+5LIPpTL/XBHtqVjzv0FqRNa28Ea0K7kO8HuXc4 BaUd0m/DqyB4Gfgm4qjc5bDneQ1ZYxVXprYERWNQ5Fj+tdWhaQGOW64N/TVodjjj NgJtTqbIAcjJqjUtttM8TZN5U1TgwLo+KCqw3iYW12lV1YKBBuvrwvSdD6jnFdIQ AzG/wRGZhxLoFxgBB/NEsZxDoSd6ztiwxLhS9lX4okZVsryyIdOE70Q/MflfiTlU xE+AdxQXTMUiiqYSmHeDD6PDb57GT/K3hnjI1yP+lIZpbInsi29JKow1qjyYjfHl 9cSSKYCIXHL7jKU6pgt34G1O5N5+fgqHQhNbfKvlrQ2UPlfs/tWdKHpFIP/z9Jlr 0vCAou7NSEB9zZGqzO63uBLXoN8yfL8FT3uRnnRvoRpfpex5dQX2QqPLQ7327D7N GUG31nd1PHTJPdxJ1cI4SO24PqPpWDWY9uaea+0jv7ivGClVadZPco/S3ZKloguT lazYUvyA4oRrSAyln785Rd8vg4CinqTxMtIyZbRMbNkgzVQARi9a8rjvu4n9qms2 2wlXDFi8nR8B4ih5n79dSiiLM9ay9GJDxMcf9VxIxSAYZV2fJALnpK6gV2fzRBUe +k/uv8BIsFmlwQ== =CutX -----END PGP SIGNATURE----- Merge tag 'riscv-for-linus-5.12-mw0' of git://git.kernel.org/pub/scm/linux/kernel/git/riscv/linux Pull RISC-V updates from Palmer Dabbelt: "A handful of new RISC-V related patches for this merge window: - A check to ensure drivers are properly using uaccess. This isn't manifesting with any of the drivers I'm currently using, but may catch errors in new drivers. - Some preliminary support for the FU740, along with the HiFive Unleashed it will appear on. - NUMA support for RISC-V, which involves making the arm64 code generic. - Support for kasan on the vmalloc region. - A handful of new drivers for the Kendryte K210, along with the DT plumbing required to boot on a handful of K210-based boards. - Support for allocating ASIDs. - Preliminary support for kernels larger than 128MiB. - Various other improvements to our KASAN support, including the utilization of huge pages when allocating the KASAN regions. We may have already found a bug with the KASAN_VMALLOC code, but it's passing my tests. There's a fix in the works, but that will probably miss the merge window. * tag 'riscv-for-linus-5.12-mw0' of git://git.kernel.org/pub/scm/linux/kernel/git/riscv/linux: (75 commits) riscv: Improve kasan population by using hugepages when possible riscv: Improve kasan population function riscv: Use KASAN_SHADOW_INIT define for kasan memory initialization riscv: Improve kasan definitions riscv: Get rid of MAX_EARLY_MAPPING_SIZE soc: canaan: Sort the Makefile alphabetically riscv: Disable KSAN_SANITIZE for vDSO riscv: Remove unnecessary declaration riscv: Add Canaan Kendryte K210 SD card defconfig riscv: Update Canaan Kendryte K210 defconfig riscv: Add Kendryte KD233 board device tree riscv: Add SiPeed MAIXDUINO board device tree riscv: Add SiPeed MAIX GO board device tree riscv: Add SiPeed MAIX DOCK board device tree riscv: Add SiPeed MAIX BiT board device tree riscv: Update Canaan Kendryte K210 device tree dt-bindings: add resets property to dw-apb-timer dt-bindings: fix sifive gpio properties dt-bindings: update sifive uart compatible string dt-bindings: update sifive clint compatible string ...
This commit is contained in:
commit
8b83369ddc
|
@ -13,7 +13,10 @@ maintainers:
|
|||
properties:
|
||||
compatible:
|
||||
items:
|
||||
- const: sifive,fu540-c000-gpio
|
||||
- enum:
|
||||
- sifive,fu540-c000-gpio
|
||||
- sifive,fu740-c000-gpio
|
||||
- canaan,k210-gpiohs
|
||||
- const: sifive,gpio0
|
||||
|
||||
reg:
|
||||
|
@ -21,9 +24,9 @@ properties:
|
|||
|
||||
interrupts:
|
||||
description:
|
||||
interrupt mapping one per GPIO. Maximum 16 GPIOs.
|
||||
Interrupt mapping, one per GPIO. Maximum 32 GPIOs.
|
||||
minItems: 1
|
||||
maxItems: 16
|
||||
maxItems: 32
|
||||
|
||||
interrupt-controller: true
|
||||
|
||||
|
@ -36,6 +39,14 @@ properties:
|
|||
"#gpio-cells":
|
||||
const: 2
|
||||
|
||||
ngpios:
|
||||
description:
|
||||
The number of GPIOs available on the controller implementation.
|
||||
It is 16 for the SiFive SoCs and 32 for the Canaan K210.
|
||||
minimum: 1
|
||||
maximum: 32
|
||||
default: 16
|
||||
|
||||
gpio-controller: true
|
||||
|
||||
required:
|
||||
|
@ -44,10 +55,20 @@ required:
|
|||
- interrupts
|
||||
- interrupt-controller
|
||||
- "#interrupt-cells"
|
||||
- clocks
|
||||
- "#gpio-cells"
|
||||
- gpio-controller
|
||||
|
||||
if:
|
||||
properties:
|
||||
compatible:
|
||||
contains:
|
||||
enum:
|
||||
- sifive,fu540-c000-gpio
|
||||
- sifive,fu740-c000-gpio
|
||||
then:
|
||||
required:
|
||||
- clocks
|
||||
|
||||
additionalProperties: false
|
||||
|
||||
examples:
|
||||
|
|
|
@ -8,10 +8,11 @@ $schema: http://devicetree.org/meta-schemas/core.yaml#
|
|||
title: SiFive Platform-Level Interrupt Controller (PLIC)
|
||||
|
||||
description:
|
||||
SiFive SOCs include an implementation of the Platform-Level Interrupt Controller
|
||||
(PLIC) high-level specification in the RISC-V Privileged Architecture
|
||||
specification. The PLIC connects all external interrupts in the system to all
|
||||
hart contexts in the system, via the external interrupt source in each hart.
|
||||
SiFive SoCs and other RISC-V SoCs include an implementation of the
|
||||
Platform-Level Interrupt Controller (PLIC) high-level specification in
|
||||
the RISC-V Privileged Architecture specification. The PLIC connects all
|
||||
external interrupts in the system to all hart contexts in the system, via
|
||||
the external interrupt source in each hart.
|
||||
|
||||
A hart context is a privilege mode in a hardware execution thread. For example,
|
||||
in an 4 core system with 2-way SMT, you have 8 harts and probably at least two
|
||||
|
@ -42,7 +43,9 @@ maintainers:
|
|||
properties:
|
||||
compatible:
|
||||
items:
|
||||
- const: sifive,fu540-c000-plic
|
||||
- enum:
|
||||
- sifive,fu540-c000-plic
|
||||
- canaan,k210-plic
|
||||
- const: sifive,plic-1.0.0
|
||||
|
||||
reg:
|
||||
|
|
|
@ -0,0 +1,109 @@
|
|||
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
|
||||
%YAML 1.2
|
||||
---
|
||||
$id: http://devicetree.org/schemas/mfd/canaan,k210-sysctl.yaml#
|
||||
$schema: http://devicetree.org/meta-schemas/core.yaml#
|
||||
|
||||
title: Canaan Kendryte K210 System Controller Device Tree Bindings
|
||||
|
||||
maintainers:
|
||||
- Damien Le Moal <damien.lemoal@wdc.com>
|
||||
|
||||
description:
|
||||
Canaan Inc. Kendryte K210 SoC system controller which provides a
|
||||
register map for controlling the clocks, reset signals and pin power
|
||||
domains of the SoC.
|
||||
|
||||
properties:
|
||||
compatible:
|
||||
items:
|
||||
- const: canaan,k210-sysctl
|
||||
- const: syscon
|
||||
- const: simple-mfd
|
||||
|
||||
clocks:
|
||||
maxItems: 1
|
||||
description:
|
||||
System controller Advanced Power Bus (APB) interface clock source.
|
||||
|
||||
clock-names:
|
||||
items:
|
||||
- const: pclk
|
||||
|
||||
reg:
|
||||
maxItems: 1
|
||||
|
||||
clock-controller:
|
||||
# Child node
|
||||
type: object
|
||||
$ref: "../clock/canaan,k210-clk.yaml"
|
||||
description:
|
||||
Clock controller for the SoC clocks. This child node definition
|
||||
should follow the bindings specified in
|
||||
Documentation/devicetree/bindings/clock/canaan,k210-clk.yaml.
|
||||
|
||||
reset-controller:
|
||||
# Child node
|
||||
type: object
|
||||
$ref: "../reset/canaan,k210-rst.yaml"
|
||||
description:
|
||||
Reset controller for the SoC. This child node definition
|
||||
should follow the bindings specified in
|
||||
Documentation/devicetree/bindings/reset/canaan,k210-rst.yaml.
|
||||
|
||||
syscon-reboot:
|
||||
# Child node
|
||||
type: object
|
||||
$ref: "../power/reset/syscon-reboot.yaml"
|
||||
description:
|
||||
Reboot method for the SoC. This child node definition
|
||||
should follow the bindings specified in
|
||||
Documentation/devicetree/bindings/power/reset/syscon-reboot.yaml.
|
||||
|
||||
required:
|
||||
- compatible
|
||||
- clocks
|
||||
- reg
|
||||
- clock-controller
|
||||
|
||||
additionalProperties: false
|
||||
|
||||
examples:
|
||||
- |
|
||||
#include <dt-bindings/clock/k210-clk.h>
|
||||
#include <dt-bindings/reset/k210-rst.h>
|
||||
|
||||
clocks {
|
||||
in0: oscllator {
|
||||
compatible = "fixed-clock";
|
||||
#clock-cells = <0>;
|
||||
clock-frequency = <26000000>;
|
||||
};
|
||||
};
|
||||
|
||||
sysctl: syscon@50440000 {
|
||||
compatible = "canaan,k210-sysctl",
|
||||
"syscon", "simple-mfd";
|
||||
reg = <0x50440000 0x100>;
|
||||
clocks = <&sysclk K210_CLK_APB1>;
|
||||
clock-names = "pclk";
|
||||
|
||||
sysclk: clock-controller {
|
||||
#clock-cells = <1>;
|
||||
compatible = "canaan,k210-clk";
|
||||
clocks = <&in0>;
|
||||
};
|
||||
|
||||
sysrst: reset-controller {
|
||||
compatible = "canaan,k210-rst";
|
||||
#reset-cells = <1>;
|
||||
};
|
||||
|
||||
reboot: syscon-reboot {
|
||||
compatible = "syscon-reboot";
|
||||
regmap = <&sysctl>;
|
||||
offset = <48>;
|
||||
mask = <1>;
|
||||
value = <1>;
|
||||
};
|
||||
};
|
|
@ -0,0 +1,171 @@
|
|||
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
|
||||
%YAML 1.2
|
||||
---
|
||||
$id: http://devicetree.org/schemas/pinctrl/canaan,k210-fpioa.yaml#
|
||||
$schema: http://devicetree.org/meta-schemas/core.yaml#
|
||||
|
||||
title: Canaan Kendryte K210 FPIOA Device Tree Bindings
|
||||
|
||||
maintainers:
|
||||
- Damien Le Moal <damien.lemoal@wdc.com>
|
||||
|
||||
description:
|
||||
The Canaan Kendryte K210 SoC Fully Programmable IO Array (FPIOA)
|
||||
controller allows assiging any of 256 possible functions to any of
|
||||
48 IO pins of the SoC. Pin function configuration is performed on
|
||||
a per-pin basis.
|
||||
|
||||
properties:
|
||||
compatible:
|
||||
const: canaan,k210-fpioa
|
||||
|
||||
reg:
|
||||
maxItems: 1
|
||||
description:
|
||||
Address and length of the register set for the FPIOA controller.
|
||||
|
||||
clocks:
|
||||
items:
|
||||
- description: Controller reference clock source
|
||||
- description: APB interface clock source
|
||||
|
||||
clock-names:
|
||||
items:
|
||||
- const: ref
|
||||
- const: pclk
|
||||
|
||||
resets:
|
||||
maxItems: 1
|
||||
|
||||
canaan,k210-sysctl-power:
|
||||
$ref: /schemas/types.yaml#/definitions/phandle-array
|
||||
description: |
|
||||
phandle of the K210 system controller node and offset of its
|
||||
power domain control register.
|
||||
|
||||
patternProperties:
|
||||
'-pinmux$':
|
||||
type: object
|
||||
$ref: /schemas/pinctrl/pinmux-node.yaml
|
||||
description:
|
||||
FPIOA client devices use sub-nodes to define the desired pin
|
||||
configuration. Client device sub-nodes use the pinux property
|
||||
below.
|
||||
|
||||
properties:
|
||||
pinmux:
|
||||
description:
|
||||
List of IO pins alternate functions. The values for each IO
|
||||
pin is a combination of an IO pin number (0 to 47) with the
|
||||
desired function for the IO pin. Functions are defined as
|
||||
macros in include/dt-bindings/pinctrl/k210-fpioa.h.
|
||||
The K210_FPIOA(IO pin, function) macro is provided to
|
||||
facilitate the combination of IO pin numbers and functions.
|
||||
|
||||
required:
|
||||
- pinmux
|
||||
|
||||
additionalProperties: false
|
||||
|
||||
'-pins$':
|
||||
type: object
|
||||
$ref: /schemas/pinctrl/pincfg-node.yaml
|
||||
description:
|
||||
FPIOA client devices use sub-nodes to define the desired
|
||||
configuration of pins. Client device sub-nodes use the
|
||||
properties below.
|
||||
|
||||
properties:
|
||||
pins:
|
||||
description:
|
||||
List of IO pins affected by the properties specified in this
|
||||
subnode. IO pins are identified using the pin names "IO_xx".
|
||||
Pin configuration nodes can also define the power domain to
|
||||
be used for the SoC pin groups A0 (IO pins 0-5),
|
||||
A1 (IO pins 6-11), A2 (IO pins 12-17), B0 (IO pins 18-23),
|
||||
B1 (IO pins 24-29), B2 (IO pins 30-35), B3 (IO pins 30-35),
|
||||
C0 (IO pins 36-41) and C1 (IO pins 42-47) using the
|
||||
power-source property.
|
||||
items:
|
||||
anyOf:
|
||||
- pattern: "^(IO_([0-9]*))|(A[0-2])|(B[3-5])|(C[6-7])$"
|
||||
- enum: [ IO_0, IO_1, IO_2, IO_3, IO_4, IO_5, IO_6, IO_7,
|
||||
IO_8, IO_9, IO_10, IO_11, IO_12, IO_13, IO_14,
|
||||
IO_15, IO_16, IO_17, IO_18, IO_19, IO_20, IO_21,
|
||||
IO_22, IO_23, IO_24, IO_25, IO_26, IO_27, IO_28,
|
||||
IO_29, IO_30, IO_31, IO_32, IO_33, IO_34, IO_35,
|
||||
IO_36, IO_37, IO_38, IO_39, IO_40, IO_41, IO_42,
|
||||
IO_43, IO_44, IO_45, IO_46, IO_47,
|
||||
A0, A1, A2, B3, B4, B5, C6, C7 ]
|
||||
bias-disable: true
|
||||
|
||||
bias-pull-down: true
|
||||
|
||||
bias-pull-up: true
|
||||
|
||||
drive-strength: true
|
||||
|
||||
drive-strength-microamp: true
|
||||
|
||||
input-enable: true
|
||||
|
||||
input-disable: true
|
||||
|
||||
input-schmitt-enable: true
|
||||
|
||||
input-schmitt-disable: true
|
||||
|
||||
input-polarity-invert:
|
||||
description:
|
||||
Enable or disable pin input polarity inversion.
|
||||
|
||||
output-enable: true
|
||||
|
||||
output-disable: true
|
||||
|
||||
output-high: true
|
||||
|
||||
output-low: true
|
||||
|
||||
output-polarity-invert:
|
||||
description:
|
||||
Enable or disable pin output polarity inversion.
|
||||
|
||||
slew-rate: true
|
||||
|
||||
power-source: true
|
||||
|
||||
additionalProperties: false
|
||||
|
||||
required:
|
||||
- compatible
|
||||
- reg
|
||||
- clocks
|
||||
- canaan,k210-sysctl-power
|
||||
|
||||
additionalProperties: false
|
||||
|
||||
examples:
|
||||
- |
|
||||
#include <dt-bindings/pinctrl/k210-fpioa.h>
|
||||
#include <dt-bindings/clock/k210-clk.h>
|
||||
#include <dt-bindings/reset/k210-rst.h>
|
||||
|
||||
fpioa: pinmux@502B0000 {
|
||||
compatible = "canaan,k210-fpioa";
|
||||
reg = <0x502B0000 0x100>;
|
||||
clocks = <&sysclk K210_CLK_FPIOA>,
|
||||
<&sysclk K210_CLK_APB0>;
|
||||
clock-names = "ref", "pclk";
|
||||
resets = <&sysrst K210_RST_FPIOA>;
|
||||
canaan,k210-sysctl-power = <&sysctl 108>;
|
||||
pinctrl-0 = <&jtag_pinctrl>;
|
||||
pinctrl-names = "default";
|
||||
|
||||
jtag_pinctrl: jtag-pinmux {
|
||||
pinmux = <K210_FPIOA(0, K210_PCF_JTAG_TCLK)>,
|
||||
<K210_FPIOA(1, K210_PCF_JTAG_TDI)>,
|
||||
<K210_FPIOA(2, K210_PCF_JTAG_TMS)>,
|
||||
<K210_FPIOA(3, K210_PCF_JTAG_TDO)>;
|
||||
};
|
||||
};
|
|
@ -25,12 +25,15 @@ description:
|
|||
properties:
|
||||
compatible:
|
||||
items:
|
||||
- const: sifive,fu540-c000-pwm
|
||||
- enum:
|
||||
- sifive,fu540-c000-pwm
|
||||
- sifive,fu740-c000-pwm
|
||||
- const: sifive,pwm0
|
||||
description:
|
||||
Should be "sifive,<chip>-pwm" and "sifive,pwm<version>". Supported
|
||||
compatible strings are "sifive,fu540-c000-pwm" for the SiFive PWM v0
|
||||
as integrated onto the SiFive FU540 chip, and "sifive,pwm0" for the
|
||||
compatible strings are "sifive,fu540-c000-pwm" and
|
||||
"sifive,fu740-c000-pwm" for the SiFive PWM v0 as integrated onto the
|
||||
SiFive FU540 and FU740 chip respectively, and "sifive,pwm0" for the
|
||||
SiFive PWM v0 IP block with no chip integration tweaks.
|
||||
Please refer to sifive-blocks-ip-versioning.txt for details.
|
||||
|
||||
|
|
|
@ -0,0 +1,40 @@
|
|||
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
|
||||
%YAML 1.2
|
||||
---
|
||||
$id: http://devicetree.org/schemas/reset/canaan,k210-rst.yaml#
|
||||
$schema: http://devicetree.org/meta-schemas/core.yaml#
|
||||
|
||||
title: Canaan Kendryte K210 Reset Controller Device Tree Bindings
|
||||
|
||||
maintainers:
|
||||
- Damien Le Moal <damien.lemoal@wdc.com>
|
||||
|
||||
description: |
|
||||
Canaan Kendryte K210 reset controller driver which supports the SoC
|
||||
system controller supplied reset registers for the various peripherals
|
||||
of the SoC. The K210 reset controller node must be defined as a child
|
||||
node of the K210 system controller node.
|
||||
|
||||
See also:
|
||||
- dt-bindings/reset/k210-rst.h
|
||||
|
||||
properties:
|
||||
compatible:
|
||||
const: canaan,k210-rst
|
||||
|
||||
'#reset-cells':
|
||||
const: 1
|
||||
|
||||
required:
|
||||
- '#reset-cells'
|
||||
- compatible
|
||||
|
||||
additionalProperties: false
|
||||
|
||||
examples:
|
||||
- |
|
||||
#include <dt-bindings/reset/k210-rst.h>
|
||||
sysrst: reset-controller {
|
||||
compatible = "canaan,k210-rst";
|
||||
#reset-cells = <1>;
|
||||
};
|
|
@ -0,0 +1,47 @@
|
|||
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
|
||||
%YAML 1.2
|
||||
---
|
||||
$id: http://devicetree.org/schemas/riscv/canaan.yaml#
|
||||
$schema: http://devicetree.org/meta-schemas/core.yaml#
|
||||
|
||||
title: Canaan SoC-based boards
|
||||
|
||||
maintainers:
|
||||
- Damien Le Moal <damien.lemoal@wdc.com>
|
||||
|
||||
description:
|
||||
Canaan Kendryte K210 SoC-based boards
|
||||
|
||||
properties:
|
||||
$nodename:
|
||||
const: '/'
|
||||
compatible:
|
||||
oneOf:
|
||||
- items:
|
||||
- const: sipeed,maix-bit
|
||||
- const: sipeed,maix-bitm
|
||||
- const: canaan,kendryte-k210
|
||||
|
||||
- items:
|
||||
- const: sipeed,maix-go
|
||||
- const: canaan,kendryte-k210
|
||||
|
||||
- items:
|
||||
- const: sipeed,maix-dock-m1
|
||||
- const: sipeed,maix-dock-m1w
|
||||
- const: canaan,kendryte-k210
|
||||
|
||||
- items:
|
||||
- const: sipeed,maixduino
|
||||
- const: canaan,kendryte-k210
|
||||
|
||||
- items:
|
||||
- const: canaan,kendryte-kd233
|
||||
- const: canaan,kendryte-k210
|
||||
|
||||
- items:
|
||||
- const: canaan,kendryte-k210
|
||||
|
||||
additionalProperties: true
|
||||
|
||||
...
|
|
@ -28,11 +28,18 @@ properties:
|
|||
- items:
|
||||
- enum:
|
||||
- sifive,rocket0
|
||||
- sifive,bullet0
|
||||
- sifive,e5
|
||||
- sifive,e7
|
||||
- sifive,e51
|
||||
- sifive,e71
|
||||
- sifive,u54-mc
|
||||
- sifive,u74-mc
|
||||
- sifive,u54
|
||||
- sifive,u74
|
||||
- sifive,u5
|
||||
- sifive,u7
|
||||
- canaan,k210
|
||||
- const: riscv
|
||||
- const: riscv # Simulator only
|
||||
description:
|
||||
|
@ -50,6 +57,7 @@ properties:
|
|||
- riscv,sv32
|
||||
- riscv,sv39
|
||||
- riscv,sv48
|
||||
- riscv,none
|
||||
|
||||
riscv,isa:
|
||||
description:
|
||||
|
|
|
@ -27,6 +27,7 @@ select:
|
|||
items:
|
||||
- enum:
|
||||
- sifive,fu540-c000-ccache
|
||||
- sifive,fu740-c000-ccache
|
||||
|
||||
required:
|
||||
- compatible
|
||||
|
@ -34,7 +35,9 @@ select:
|
|||
properties:
|
||||
compatible:
|
||||
items:
|
||||
- const: sifive,fu540-c000-ccache
|
||||
- enum:
|
||||
- sifive,fu540-c000-ccache
|
||||
- sifive,fu740-c000-ccache
|
||||
- const: cache
|
||||
|
||||
cache-block-size:
|
||||
|
@ -52,10 +55,13 @@ properties:
|
|||
cache-unified: true
|
||||
|
||||
interrupts:
|
||||
description: |
|
||||
Must contain entries for DirError, DataError and DataFail signals.
|
||||
minItems: 3
|
||||
maxItems: 3
|
||||
maxItems: 4
|
||||
items:
|
||||
- description: DirError interrupt
|
||||
- description: DataError interrupt
|
||||
- description: DataFail interrupt
|
||||
- description: DirFail interrupt
|
||||
|
||||
reg:
|
||||
maxItems: 1
|
||||
|
@ -68,6 +74,26 @@ properties:
|
|||
The reference to the reserved-memory for the L2 Loosely Integrated Memory region.
|
||||
The reserved memory node should be defined as per the bindings in reserved-memory.txt.
|
||||
|
||||
if:
|
||||
properties:
|
||||
compatible:
|
||||
contains:
|
||||
const: sifive,fu540-c000-ccache
|
||||
|
||||
then:
|
||||
properties:
|
||||
interrupts:
|
||||
description: |
|
||||
Must contain entries for DirError, DataError and DataFail signals.
|
||||
maxItems: 3
|
||||
|
||||
else:
|
||||
properties:
|
||||
interrupts:
|
||||
description: |
|
||||
Must contain entries for DirError, DataError, DataFail, DirFail signals.
|
||||
minItems: 4
|
||||
|
||||
additionalProperties: false
|
||||
|
||||
required:
|
||||
|
|
|
@ -17,11 +17,18 @@ properties:
|
|||
$nodename:
|
||||
const: '/'
|
||||
compatible:
|
||||
items:
|
||||
- enum:
|
||||
- sifive,hifive-unleashed-a00
|
||||
- const: sifive,fu540-c000
|
||||
- const: sifive,fu540
|
||||
oneOf:
|
||||
- items:
|
||||
- enum:
|
||||
- sifive,hifive-unleashed-a00
|
||||
- const: sifive,fu540-c000
|
||||
- const: sifive,fu540
|
||||
|
||||
- items:
|
||||
- enum:
|
||||
- sifive,hifive-unmatched-a00
|
||||
- const: sifive,fu740-c000
|
||||
- const: sifive,fu740
|
||||
|
||||
additionalProperties: true
|
||||
|
||||
|
|
|
@ -20,6 +20,7 @@ properties:
|
|||
- enum:
|
||||
- sifive,fu540-c000-uart
|
||||
- sifive,fu740-c000-uart
|
||||
- canaan,k210-uarths
|
||||
- const: sifive,uart0
|
||||
|
||||
description:
|
||||
|
|
|
@ -23,15 +23,19 @@ description:
|
|||
properties:
|
||||
compatible:
|
||||
items:
|
||||
- const: sifive,fu540-c000-clint
|
||||
- enum:
|
||||
- sifive,fu540-c000-clint
|
||||
- canaan,k210-clint
|
||||
- const: sifive,clint0
|
||||
|
||||
description:
|
||||
Should be "sifive,<chip>-clint" and "sifive,clint<version>".
|
||||
Should be "<vendor>,<chip>-clint" and "sifive,clint<version>".
|
||||
Supported compatible strings are -
|
||||
"sifive,fu540-c000-clint" for the SiFive CLINT v0 as integrated
|
||||
onto the SiFive FU540 chip, and "sifive,clint0" for the SiFive
|
||||
CLINT v0 IP block with no chip integration tweaks.
|
||||
onto the SiFive FU540 chip, "canaan,k210-clint" for the SiFive
|
||||
CLINT v0 as integrated onto the Canaan Kendryte K210 chip, and
|
||||
"sifive,clint0" for the SiFive CLINT v0 IP block with no chip
|
||||
integration tweaks.
|
||||
Please refer to sifive-blocks-ip-versioning.txt for details
|
||||
|
||||
reg:
|
||||
|
|
|
@ -24,6 +24,9 @@ properties:
|
|||
interrupts:
|
||||
maxItems: 1
|
||||
|
||||
resets:
|
||||
maxItems: 1
|
||||
|
||||
clocks:
|
||||
minItems: 1
|
||||
items:
|
||||
|
|
23
MAINTAINERS
23
MAINTAINERS
|
@ -3855,6 +3855,29 @@ W: https://github.com/Cascoda/ca8210-linux.git
|
|||
F: Documentation/devicetree/bindings/net/ieee802154/ca8210.txt
|
||||
F: drivers/net/ieee802154/ca8210.c
|
||||
|
||||
CANAAN/KENDRYTE K210 SOC FPIOA DRIVER
|
||||
M: Damien Le Moal <damien.lemoal@wdc.com>
|
||||
L: linux-riscv@lists.infradead.org
|
||||
L: linux-gpio@vger.kernel.org (pinctrl driver)
|
||||
F: Documentation/devicetree/bindings/pinctrl/canaan,k210-fpioa.yaml
|
||||
F: drivers/pinctrl/pinctrl-k210.c
|
||||
|
||||
CANAAN/KENDRYTE K210 SOC RESET CONTROLLER DRIVER
|
||||
M: Damien Le Moal <damien.lemoal@wdc.com>
|
||||
L: linux-kernel@vger.kernel.org
|
||||
L: linux-riscv@lists.infradead.org
|
||||
S: Maintained
|
||||
F: Documentation/devicetree/bindings/reset/canaan,k210-rst.yaml
|
||||
F: drivers/reset/reset-k210.c
|
||||
|
||||
CANAAN/KENDRYTE K210 SOC SYSTEM CONTROLLER DRIVER
|
||||
M: Damien Le Moal <damien.lemoal@wdc.com>
|
||||
L: linux-riscv@lists.infradead.org
|
||||
S: Maintained
|
||||
F: Documentation/devicetree/bindings/mfd/canaan,k210-sysctl.yaml
|
||||
F: drivers/soc/canaan/
|
||||
F: include/soc/canaan/
|
||||
|
||||
CACHEFILES: FS-CACHE BACKEND FOR CACHING ON MOUNTED FILESYSTEMS
|
||||
M: David Howells <dhowells@redhat.com>
|
||||
L: linux-cachefs@redhat.com (moderated for non-subscribers)
|
||||
|
|
|
@ -999,6 +999,7 @@ config HOTPLUG_CPU
|
|||
# Common NUMA Features
|
||||
config NUMA
|
||||
bool "NUMA Memory Allocation and Scheduler Support"
|
||||
select GENERIC_ARCH_NUMA
|
||||
select ACPI_NUMA if ACPI
|
||||
select OF_NUMA
|
||||
help
|
||||
|
|
|
@ -3,52 +3,6 @@
|
|||
#define __ASM_NUMA_H
|
||||
|
||||
#include <asm/topology.h>
|
||||
|
||||
#ifdef CONFIG_NUMA
|
||||
|
||||
#define NR_NODE_MEMBLKS (MAX_NUMNODES * 2)
|
||||
|
||||
int __node_distance(int from, int to);
|
||||
#define node_distance(a, b) __node_distance(a, b)
|
||||
|
||||
extern nodemask_t numa_nodes_parsed __initdata;
|
||||
|
||||
extern bool numa_off;
|
||||
|
||||
/* Mappings between node number and cpus on that node. */
|
||||
extern cpumask_var_t node_to_cpumask_map[MAX_NUMNODES];
|
||||
void numa_clear_node(unsigned int cpu);
|
||||
|
||||
#ifdef CONFIG_DEBUG_PER_CPU_MAPS
|
||||
const struct cpumask *cpumask_of_node(int node);
|
||||
#else
|
||||
/* Returns a pointer to the cpumask of CPUs on Node 'node'. */
|
||||
static inline const struct cpumask *cpumask_of_node(int node)
|
||||
{
|
||||
if (node == NUMA_NO_NODE)
|
||||
return cpu_all_mask;
|
||||
|
||||
return node_to_cpumask_map[node];
|
||||
}
|
||||
#endif
|
||||
|
||||
void __init arm64_numa_init(void);
|
||||
int __init numa_add_memblk(int nodeid, u64 start, u64 end);
|
||||
void __init numa_set_distance(int from, int to, int distance);
|
||||
void __init numa_free_distance(void);
|
||||
void __init early_map_cpu_to_node(unsigned int cpu, int nid);
|
||||
void numa_store_cpu_info(unsigned int cpu);
|
||||
void numa_add_cpu(unsigned int cpu);
|
||||
void numa_remove_cpu(unsigned int cpu);
|
||||
|
||||
#else /* CONFIG_NUMA */
|
||||
|
||||
static inline void numa_store_cpu_info(unsigned int cpu) { }
|
||||
static inline void numa_add_cpu(unsigned int cpu) { }
|
||||
static inline void numa_remove_cpu(unsigned int cpu) { }
|
||||
static inline void arm64_numa_init(void) { }
|
||||
static inline void early_map_cpu_to_node(unsigned int cpu, int nid) { }
|
||||
|
||||
#endif /* CONFIG_NUMA */
|
||||
#include <asm-generic/numa.h>
|
||||
|
||||
#endif /* __ASM_NUMA_H */
|
||||
|
|
|
@ -118,15 +118,3 @@ void __init acpi_numa_gicc_affinity_init(struct acpi_srat_gicc_affinity *pa)
|
|||
node_set(node, numa_nodes_parsed);
|
||||
}
|
||||
|
||||
int __init arm64_acpi_numa_init(void)
|
||||
{
|
||||
int ret;
|
||||
|
||||
ret = acpi_numa_init();
|
||||
if (ret) {
|
||||
pr_info("Failed to initialise from firmware\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
return srat_disabled() ? -EINVAL : 0;
|
||||
}
|
||||
|
|
|
@ -7,7 +7,6 @@ obj-$(CONFIG_HUGETLB_PAGE) += hugetlbpage.o
|
|||
obj-$(CONFIG_PTDUMP_CORE) += ptdump.o
|
||||
obj-$(CONFIG_PTDUMP_DEBUGFS) += ptdump_debugfs.o
|
||||
obj-$(CONFIG_TRANS_TABLE) += trans_pgd.o
|
||||
obj-$(CONFIG_NUMA) += numa.o
|
||||
obj-$(CONFIG_DEBUG_VIRTUAL) += physaddr.o
|
||||
obj-$(CONFIG_ARM64_MTE) += mteswap.o
|
||||
KASAN_SANITIZE_physaddr.o += n
|
||||
|
|
|
@ -416,10 +416,10 @@ void __init bootmem_init(void)
|
|||
max_pfn = max_low_pfn = max;
|
||||
min_low_pfn = min;
|
||||
|
||||
arm64_numa_init();
|
||||
arch_numa_init();
|
||||
|
||||
/*
|
||||
* must be done after arm64_numa_init() which calls numa_init() to
|
||||
* must be done after arch_numa_init() which calls numa_init() to
|
||||
* initialize node_online_map that gets used in hugetlb_cma_reserve()
|
||||
* while allocating required CMA size across online nodes.
|
||||
*/
|
||||
|
|
|
@ -57,6 +57,7 @@ config RISCV
|
|||
select HAVE_ARCH_JUMP_LABEL
|
||||
select HAVE_ARCH_JUMP_LABEL_RELATIVE
|
||||
select HAVE_ARCH_KASAN if MMU && 64BIT
|
||||
select HAVE_ARCH_KASAN_VMALLOC if MMU && 64BIT
|
||||
select HAVE_ARCH_KGDB
|
||||
select HAVE_ARCH_KGDB_QXFER_PKT
|
||||
select HAVE_ARCH_MMAP_RND_BITS if MMU
|
||||
|
@ -67,14 +68,19 @@ config RISCV
|
|||
select HAVE_DEBUG_KMEMLEAK
|
||||
select HAVE_DMA_CONTIGUOUS if MMU
|
||||
select HAVE_EBPF_JIT if MMU
|
||||
select HAVE_FUNCTION_ERROR_INJECTION
|
||||
select HAVE_FUTEX_CMPXCHG if FUTEX
|
||||
select HAVE_GCC_PLUGINS
|
||||
select HAVE_GENERIC_VDSO if MMU && 64BIT
|
||||
select HAVE_IRQ_TIME_ACCOUNTING
|
||||
select HAVE_KPROBES
|
||||
select HAVE_KPROBES_ON_FTRACE
|
||||
select HAVE_KRETPROBES
|
||||
select HAVE_PCI
|
||||
select HAVE_PERF_EVENTS
|
||||
select HAVE_PERF_REGS
|
||||
select HAVE_PERF_USER_STACK_DUMP
|
||||
select HAVE_REGS_AND_STACK_ACCESS_API
|
||||
select HAVE_STACKPROTECTOR
|
||||
select HAVE_SYSCALL_TRACEPOINTS
|
||||
select IRQ_DOMAIN
|
||||
|
@ -143,7 +149,7 @@ config PAGE_OFFSET
|
|||
default 0xffffffe000000000 if 64BIT && MAXPHYSMEM_128GB
|
||||
|
||||
config ARCH_FLATMEM_ENABLE
|
||||
def_bool y
|
||||
def_bool !NUMA
|
||||
|
||||
config ARCH_SPARSEMEM_ENABLE
|
||||
def_bool y
|
||||
|
@ -156,6 +162,9 @@ config ARCH_SELECT_MEMORY_MODEL
|
|||
config ARCH_WANT_GENERAL_HUGETLB
|
||||
def_bool y
|
||||
|
||||
config ARCH_SUPPORTS_UPROBES
|
||||
def_bool y
|
||||
|
||||
config SYS_SUPPORTS_HUGETLBFS
|
||||
depends on MMU
|
||||
def_bool y
|
||||
|
@ -302,6 +311,35 @@ config TUNE_GENERIC
|
|||
|
||||
endchoice
|
||||
|
||||
# Common NUMA Features
|
||||
config NUMA
|
||||
bool "NUMA Memory Allocation and Scheduler Support"
|
||||
select GENERIC_ARCH_NUMA
|
||||
select OF_NUMA
|
||||
select ARCH_SUPPORTS_NUMA_BALANCING
|
||||
help
|
||||
Enable NUMA (Non-Uniform Memory Access) support.
|
||||
|
||||
The kernel will try to allocate memory used by a CPU on the
|
||||
local memory of the CPU and add some more NUMA awareness to the kernel.
|
||||
|
||||
config NODES_SHIFT
|
||||
int "Maximum NUMA Nodes (as a power of 2)"
|
||||
range 1 10
|
||||
default "2"
|
||||
depends on NEED_MULTIPLE_NODES
|
||||
help
|
||||
Specify the maximum number of NUMA Nodes available on the target
|
||||
system. Increases memory reserved to accommodate various tables.
|
||||
|
||||
config USE_PERCPU_NUMA_NODE_ID
|
||||
def_bool y
|
||||
depends on NUMA
|
||||
|
||||
config NEED_PER_CPU_EMBED_FIRST_CHUNK
|
||||
def_bool y
|
||||
depends on NUMA
|
||||
|
||||
config RISCV_ISA_C
|
||||
bool "Emit compressed instructions when building Linux"
|
||||
default y
|
||||
|
@ -416,11 +454,17 @@ config EFI
|
|||
allow the kernel to be booted as an EFI application. This
|
||||
is only useful on systems that have UEFI firmware.
|
||||
|
||||
config CC_HAVE_STACKPROTECTOR_TLS
|
||||
def_bool $(cc-option,-mstack-protector-guard=tls -mstack-protector-guard-reg=tp -mstack-protector-guard-offset=0)
|
||||
|
||||
config STACKPROTECTOR_PER_TASK
|
||||
def_bool y
|
||||
depends on STACKPROTECTOR && CC_HAVE_STACKPROTECTOR_TLS
|
||||
|
||||
endmenu
|
||||
|
||||
config BUILTIN_DTB
|
||||
def_bool n
|
||||
depends on RISCV_M_MODE
|
||||
depends on OF
|
||||
|
||||
menu "Power management options"
|
||||
|
|
|
@ -22,30 +22,41 @@ config SOC_VIRT
|
|||
help
|
||||
This enables support for QEMU Virt Machine.
|
||||
|
||||
config SOC_KENDRYTE
|
||||
bool "Kendryte K210 SoC"
|
||||
config SOC_CANAAN
|
||||
bool "Canaan Kendryte K210 SoC"
|
||||
depends on !MMU
|
||||
select CLINT_TIMER if RISCV_M_MODE
|
||||
select SERIAL_SIFIVE if TTY
|
||||
select SERIAL_SIFIVE_CONSOLE if TTY
|
||||
select SIFIVE_PLIC
|
||||
select ARCH_HAS_RESET_CONTROLLER
|
||||
select PINCTRL
|
||||
help
|
||||
This enables support for Kendryte K210 SoC platform hardware.
|
||||
This enables support for Canaan Kendryte K210 SoC platform hardware.
|
||||
|
||||
config SOC_KENDRYTE_K210_DTB
|
||||
def_bool y
|
||||
depends on SOC_KENDRYTE_K210_DTB_BUILTIN
|
||||
if SOC_CANAAN
|
||||
|
||||
config SOC_KENDRYTE_K210_DTB_BUILTIN
|
||||
bool "Builtin device tree for the Kendryte K210"
|
||||
depends on SOC_KENDRYTE
|
||||
config SOC_CANAAN_K210_DTB_BUILTIN
|
||||
bool "Builtin device tree for the Canaan Kendryte K210"
|
||||
depends on SOC_CANAAN
|
||||
default y
|
||||
select OF
|
||||
select BUILTIN_DTB
|
||||
select SOC_KENDRYTE_K210_DTB
|
||||
help
|
||||
Builds a device tree for the Kendryte K210 into the Linux image.
|
||||
Build a device tree for the Kendryte K210 into the Linux image.
|
||||
This option should be selected if no bootloader is being used.
|
||||
If unsure, say Y.
|
||||
|
||||
config SOC_CANAAN_K210_DTB_SOURCE
|
||||
string "Source file for the Canaan Kendryte K210 builtin DTB"
|
||||
depends on SOC_CANAAN
|
||||
depends on SOC_CANAAN_K210_DTB_BUILTIN
|
||||
default "k210_generic"
|
||||
help
|
||||
Base name (without suffix, relative to arch/riscv/boot/dts/canaan)
|
||||
for the DTS file that will be used to produce the DTB linked into the
|
||||
kernel.
|
||||
|
||||
endif
|
||||
|
||||
endmenu
|
||||
|
|
|
@ -12,6 +12,8 @@ OBJCOPYFLAGS := -O binary
|
|||
LDFLAGS_vmlinux :=
|
||||
ifeq ($(CONFIG_DYNAMIC_FTRACE),y)
|
||||
LDFLAGS_vmlinux := --no-relax
|
||||
KBUILD_CPPFLAGS += -DCC_USING_PATCHABLE_FUNCTION_ENTRY
|
||||
CC_FLAGS_FTRACE := -fpatchable-function-entry=8
|
||||
endif
|
||||
|
||||
ifeq ($(CONFIG_64BIT)$(CONFIG_CMODEL_MEDLOW),yy)
|
||||
|
@ -65,6 +67,16 @@ KBUILD_CFLAGS_MODULE += $(call cc-option,-mno-relax)
|
|||
# architectures. It's faster to have GCC emit only aligned accesses.
|
||||
KBUILD_CFLAGS += $(call cc-option,-mstrict-align)
|
||||
|
||||
ifeq ($(CONFIG_STACKPROTECTOR_PER_TASK),y)
|
||||
prepare: stack_protector_prepare
|
||||
stack_protector_prepare: prepare0
|
||||
$(eval KBUILD_CFLAGS += -mstack-protector-guard=tls \
|
||||
-mstack-protector-guard-reg=tp \
|
||||
-mstack-protector-guard-offset=$(shell \
|
||||
awk '{if ($$2 == "TSK_STACK_CANARY") print $$3;}' \
|
||||
include/generated/asm-offsets.h))
|
||||
endif
|
||||
|
||||
# arch specific predefines for sparse
|
||||
CHECKFLAGS += -D__riscv -D__riscv_xlen=$(BITS)
|
||||
|
||||
|
@ -83,7 +95,7 @@ PHONY += vdso_install
|
|||
vdso_install:
|
||||
$(Q)$(MAKE) $(build)=arch/riscv/kernel/vdso $@
|
||||
|
||||
ifeq ($(CONFIG_RISCV_M_MODE)$(CONFIG_SOC_KENDRYTE),yy)
|
||||
ifeq ($(CONFIG_RISCV_M_MODE)$(CONFIG_SOC_CANAAN),yy)
|
||||
KBUILD_IMAGE := $(boot)/loader.bin
|
||||
else
|
||||
KBUILD_IMAGE := $(boot)/Image.gz
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
# SPDX-License-Identifier: GPL-2.0
|
||||
subdir-y += sifive
|
||||
subdir-y += kendryte
|
||||
subdir-$(CONFIG_SOC_CANAAN_K210_DTB_BUILTIN) += canaan
|
||||
|
||||
obj-$(CONFIG_BUILTIN_DTB) := $(addsuffix /, $(subdir-y))
|
||||
|
|
|
@ -0,0 +1,5 @@
|
|||
# SPDX-License-Identifier: GPL-2.0
|
||||
ifneq ($(CONFIG_SOC_CANAAN_K210_DTB_SOURCE),"")
|
||||
dtb-y += $(strip $(shell echo $(CONFIG_SOC_CANAAN_K210_DTB_SOURCE))).dtb
|
||||
obj-$(CONFIG_SOC_CANAAN_K210_DTB_BUILTIN) += $(addsuffix .o, $(dtb-y))
|
||||
endif
|
|
@ -0,0 +1,152 @@
|
|||
// SPDX-License-Identifier: GPL-2.0+
|
||||
/*
|
||||
* Copyright (C) 2019-20 Sean Anderson <seanga2@gmail.com>
|
||||
* Copyright (C) 2020 Western Digital Corporation or its affiliates.
|
||||
*/
|
||||
|
||||
/dts-v1/;
|
||||
|
||||
#include "k210.dtsi"
|
||||
|
||||
#include <dt-bindings/gpio/gpio.h>
|
||||
#include <dt-bindings/input/input.h>
|
||||
|
||||
/ {
|
||||
model = "Kendryte KD233";
|
||||
compatible = "canaan,kendryte-kd233", "canaan,kendryte-k210";
|
||||
|
||||
chosen {
|
||||
bootargs = "earlycon console=ttySIF0";
|
||||
stdout-path = "serial0:115200n8";
|
||||
};
|
||||
|
||||
gpio-leds {
|
||||
compatible = "gpio-leds";
|
||||
|
||||
led0 {
|
||||
gpios = <&gpio0 8 GPIO_ACTIVE_LOW>;
|
||||
};
|
||||
|
||||
led1 {
|
||||
gpios = <&gpio0 9 GPIO_ACTIVE_LOW>;
|
||||
};
|
||||
};
|
||||
|
||||
gpio-keys {
|
||||
compatible = "gpio-keys";
|
||||
|
||||
key0 {
|
||||
label = "KEY0";
|
||||
linux,code = <BTN_0>;
|
||||
gpios = <&gpio0 10 GPIO_ACTIVE_LOW>;
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
&fpioa {
|
||||
pinctrl-0 = <&jtag_pinctrl>;
|
||||
pinctrl-names = "default";
|
||||
status = "okay";
|
||||
|
||||
jtag_pinctrl: jtag-pinmux {
|
||||
pinmux = <K210_FPIOA(0, K210_PCF_JTAG_TCLK)>,
|
||||
<K210_FPIOA(1, K210_PCF_JTAG_TDI)>,
|
||||
<K210_FPIOA(2, K210_PCF_JTAG_TMS)>,
|
||||
<K210_FPIOA(3, K210_PCF_JTAG_TDO)>;
|
||||
};
|
||||
|
||||
uarths_pinctrl: uarths-pinmux {
|
||||
pinmux = <K210_FPIOA(4, K210_PCF_UARTHS_RX)>,
|
||||
<K210_FPIOA(5, K210_PCF_UARTHS_TX)>;
|
||||
};
|
||||
|
||||
spi0_pinctrl: spi0-pinmux {
|
||||
pinmux = <K210_FPIOA(6, K210_PCF_GPIOHS20)>, /* cs */
|
||||
<K210_FPIOA(7, K210_PCF_SPI0_SCLK)>, /* wr */
|
||||
<K210_FPIOA(8, K210_PCF_GPIOHS21)>; /* dc */
|
||||
};
|
||||
|
||||
dvp_pinctrl: dvp-pinmux {
|
||||
pinmux = <K210_FPIOA(9, K210_PCF_SCCB_SCLK)>,
|
||||
<K210_FPIOA(10, K210_PCF_SCCB_SDA)>,
|
||||
<K210_FPIOA(11, K210_PCF_DVP_RST)>,
|
||||
<K210_FPIOA(12, K210_PCF_DVP_VSYNC)>,
|
||||
<K210_FPIOA(13, K210_PCF_DVP_PWDN)>,
|
||||
<K210_FPIOA(14, K210_PCF_DVP_XCLK)>,
|
||||
<K210_FPIOA(15, K210_PCF_DVP_PCLK)>,
|
||||
<K210_FPIOA(17, K210_PCF_DVP_HSYNC)>;
|
||||
};
|
||||
|
||||
gpiohs_pinctrl: gpiohs-pinmux {
|
||||
pinmux = <K210_FPIOA(16, K210_PCF_GPIOHS0)>,
|
||||
<K210_FPIOA(20, K210_PCF_GPIOHS4)>, /* Rot. dip sw line 8 */
|
||||
<K210_FPIOA(21, K210_PCF_GPIOHS5)>, /* Rot. dip sw line 4 */
|
||||
<K210_FPIOA(22, K210_PCF_GPIOHS6)>, /* Rot. dip sw line 2 */
|
||||
<K210_FPIOA(23, K210_PCF_GPIOHS7)>, /* Rot. dip sw line 1 */
|
||||
<K210_FPIOA(24, K210_PCF_GPIOHS8)>,
|
||||
<K210_FPIOA(25, K210_PCF_GPIOHS9)>,
|
||||
<K210_FPIOA(26, K210_PCF_GPIOHS10)>;
|
||||
};
|
||||
|
||||
spi1_pinctrl: spi1-pinmux {
|
||||
pinmux = <K210_FPIOA(29, K210_PCF_SPI1_SCLK)>,
|
||||
<K210_FPIOA(30, K210_PCF_SPI1_D0)>,
|
||||
<K210_FPIOA(31, K210_PCF_SPI1_D1)>,
|
||||
<K210_FPIOA(32, K210_PCF_GPIOHS16)>; /* cs */
|
||||
};
|
||||
|
||||
i2s0_pinctrl: i2s0-pinmux {
|
||||
pinmux = <K210_FPIOA(33, K210_PCF_I2S0_IN_D0)>,
|
||||
<K210_FPIOA(34, K210_PCF_I2S0_WS)>,
|
||||
<K210_FPIOA(35, K210_PCF_I2S0_SCLK)>;
|
||||
};
|
||||
};
|
||||
|
||||
&uarths0 {
|
||||
pinctrl-0 = <&uarths_pinctrl>;
|
||||
pinctrl-names = "default";
|
||||
status = "okay";
|
||||
};
|
||||
|
||||
&gpio0 {
|
||||
pinctrl-0 = <&gpiohs_pinctrl>;
|
||||
pinctrl-names = "default";
|
||||
status = "okay";
|
||||
};
|
||||
|
||||
&i2s0 {
|
||||
#sound-dai-cells = <1>;
|
||||
pinctrl-0 = <&i2s0_pinctrl>;
|
||||
pinctrl-names = "default";
|
||||
};
|
||||
|
||||
&spi0 {
|
||||
pinctrl-0 = <&spi0_pinctrl>;
|
||||
pinctrl-names = "default";
|
||||
num-cs = <1>;
|
||||
cs-gpios = <&gpio0 20 GPIO_ACTIVE_HIGH>;
|
||||
|
||||
panel@0 {
|
||||
compatible = "ilitek,ili9341";
|
||||
reg = <0>;
|
||||
dc-gpios = <&gpio0 21 GPIO_ACTIVE_HIGH>;
|
||||
spi-max-frequency = <15000000>;
|
||||
status = "disabled";
|
||||
};
|
||||
};
|
||||
|
||||
&spi1 {
|
||||
pinctrl-0 = <&spi1_pinctrl>;
|
||||
pinctrl-names = "default";
|
||||
num-cs = <1>;
|
||||
cs-gpios = <&gpio0 16 GPIO_ACTIVE_LOW>;
|
||||
status = "okay";
|
||||
|
||||
slot@0 {
|
||||
compatible = "mmc-spi-slot";
|
||||
reg = <0>;
|
||||
voltage-ranges = <3300 3300>;
|
||||
spi-max-frequency = <25000000>;
|
||||
broken-cd;
|
||||
};
|
||||
};
|
|
@ -0,0 +1,459 @@
|
|||
// SPDX-License-Identifier: GPL-2.0+
|
||||
/*
|
||||
* Copyright (C) 2019-20 Sean Anderson <seanga2@gmail.com>
|
||||
* Copyright (C) 2020 Western Digital Corporation or its affiliates.
|
||||
*/
|
||||
#include <dt-bindings/clock/k210-clk.h>
|
||||
#include <dt-bindings/pinctrl/k210-fpioa.h>
|
||||
#include <dt-bindings/reset/k210-rst.h>
|
||||
|
||||
/ {
|
||||
/*
|
||||
* Although the K210 is a 64-bit CPU, the address bus is only 32-bits
|
||||
* wide, and the upper half of all addresses is ignored.
|
||||
*/
|
||||
#address-cells = <1>;
|
||||
#size-cells = <1>;
|
||||
compatible = "canaan,kendryte-k210";
|
||||
|
||||
aliases {
|
||||
serial0 = &uarths0;
|
||||
serial1 = &uart1;
|
||||
serial2 = &uart2;
|
||||
serial3 = &uart3;
|
||||
};
|
||||
|
||||
/*
|
||||
* The K210 has an sv39 MMU following the privileged specification v1.9.
|
||||
* Since this is a non-ratified draft specification, the kernel does not
|
||||
* support it and the K210 support enabled only for the !MMU case.
|
||||
* Be consistent with this by setting the CPUs MMU type to "none".
|
||||
*/
|
||||
cpus {
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
timebase-frequency = <7800000>;
|
||||
cpu0: cpu@0 {
|
||||
device_type = "cpu";
|
||||
compatible = "canaan,k210", "riscv";
|
||||
reg = <0>;
|
||||
riscv,isa = "rv64imafdc";
|
||||
mmu-type = "riscv,none";
|
||||
i-cache-block-size = <64>;
|
||||
i-cache-size = <0x8000>;
|
||||
d-cache-block-size = <64>;
|
||||
d-cache-size = <0x8000>;
|
||||
cpu0_intc: interrupt-controller {
|
||||
#interrupt-cells = <1>;
|
||||
interrupt-controller;
|
||||
compatible = "riscv,cpu-intc";
|
||||
};
|
||||
};
|
||||
cpu1: cpu@1 {
|
||||
device_type = "cpu";
|
||||
compatible = "canaan,k210", "riscv";
|
||||
reg = <1>;
|
||||
riscv,isa = "rv64imafdc";
|
||||
mmu-type = "riscv,none";
|
||||
i-cache-block-size = <64>;
|
||||
i-cache-size = <0x8000>;
|
||||
d-cache-block-size = <64>;
|
||||
d-cache-size = <0x8000>;
|
||||
cpu1_intc: interrupt-controller {
|
||||
#interrupt-cells = <1>;
|
||||
interrupt-controller;
|
||||
compatible = "riscv,cpu-intc";
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
sram: memory@80000000 {
|
||||
device_type = "memory";
|
||||
compatible = "canaan,k210-sram";
|
||||
reg = <0x80000000 0x400000>,
|
||||
<0x80400000 0x200000>,
|
||||
<0x80600000 0x200000>;
|
||||
reg-names = "sram0", "sram1", "aisram";
|
||||
clocks = <&sysclk K210_CLK_SRAM0>,
|
||||
<&sysclk K210_CLK_SRAM1>,
|
||||
<&sysclk K210_CLK_AI>;
|
||||
clock-names = "sram0", "sram1", "aisram";
|
||||
};
|
||||
|
||||
clocks {
|
||||
in0: oscillator {
|
||||
compatible = "fixed-clock";
|
||||
#clock-cells = <0>;
|
||||
clock-frequency = <26000000>;
|
||||
};
|
||||
};
|
||||
|
||||
soc {
|
||||
#address-cells = <1>;
|
||||
#size-cells = <1>;
|
||||
compatible = "simple-bus";
|
||||
ranges;
|
||||
interrupt-parent = <&plic0>;
|
||||
|
||||
rom0: nvmem@1000 {
|
||||
reg = <0x1000 0x1000>;
|
||||
read-only;
|
||||
};
|
||||
|
||||
clint0: timer@2000000 {
|
||||
compatible = "canaan,k210-clint", "sifive,clint0";
|
||||
reg = <0x2000000 0xC000>;
|
||||
interrupts-extended = <&cpu0_intc 3 &cpu0_intc 7
|
||||
&cpu1_intc 3 &cpu1_intc 7>;
|
||||
};
|
||||
|
||||
plic0: interrupt-controller@c000000 {
|
||||
#interrupt-cells = <1>;
|
||||
#address-cells = <0>;
|
||||
compatible = "canaan,k210-plic", "sifive,plic-1.0.0";
|
||||
reg = <0xC000000 0x4000000>;
|
||||
interrupt-controller;
|
||||
interrupts-extended = <&cpu0_intc 11 &cpu1_intc 11>;
|
||||
riscv,ndev = <65>;
|
||||
};
|
||||
|
||||
uarths0: serial@38000000 {
|
||||
compatible = "canaan,k210-uarths", "sifive,uart0";
|
||||
reg = <0x38000000 0x1000>;
|
||||
interrupts = <33>;
|
||||
clocks = <&sysclk K210_CLK_CPU>;
|
||||
};
|
||||
|
||||
gpio0: gpio-controller@38001000 {
|
||||
#interrupt-cells = <2>;
|
||||
#gpio-cells = <2>;
|
||||
compatible = "canaan,k210-gpiohs", "sifive,gpio0";
|
||||
reg = <0x38001000 0x1000>;
|
||||
interrupt-controller;
|
||||
interrupts = <34 35 36 37 38 39 40 41
|
||||
42 43 44 45 46 47 48 49
|
||||
50 51 52 53 54 55 56 57
|
||||
58 59 60 61 62 63 64 65>;
|
||||
gpio-controller;
|
||||
ngpios = <32>;
|
||||
};
|
||||
|
||||
dmac0: dma-controller@50000000 {
|
||||
compatible = "snps,axi-dma-1.01a";
|
||||
reg = <0x50000000 0x1000>;
|
||||
interrupts = <27 28 29 30 31 32>;
|
||||
#dma-cells = <1>;
|
||||
clocks = <&sysclk K210_CLK_DMA>, <&sysclk K210_CLK_DMA>;
|
||||
clock-names = "core-clk", "cfgr-clk";
|
||||
resets = <&sysrst K210_RST_DMA>;
|
||||
dma-channels = <6>;
|
||||
snps,dma-masters = <2>;
|
||||
snps,priority = <0 1 2 3 4 5>;
|
||||
snps,data-width = <5>;
|
||||
snps,block-size = <0x200000 0x200000 0x200000
|
||||
0x200000 0x200000 0x200000>;
|
||||
snps,axi-max-burst-len = <256>;
|
||||
};
|
||||
|
||||
apb0: bus@50200000 {
|
||||
#address-cells = <1>;
|
||||
#size-cells = <1>;
|
||||
compatible = "simple-pm-bus";
|
||||
ranges;
|
||||
clocks = <&sysclk K210_CLK_APB0>;
|
||||
|
||||
gpio1: gpio@50200000 {
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
compatible = "snps,dw-apb-gpio";
|
||||
reg = <0x50200000 0x80>;
|
||||
clocks = <&sysclk K210_CLK_APB0>,
|
||||
<&sysclk K210_CLK_GPIO>;
|
||||
clock-names = "bus", "db";
|
||||
resets = <&sysrst K210_RST_GPIO>;
|
||||
|
||||
gpio1_0: gpio-port@0 {
|
||||
#gpio-cells = <2>;
|
||||
#interrupt-cells = <2>;
|
||||
compatible = "snps,dw-apb-gpio-port";
|
||||
reg = <0>;
|
||||
interrupt-controller;
|
||||
interrupts = <23>;
|
||||
gpio-controller;
|
||||
ngpios = <8>;
|
||||
};
|
||||
};
|
||||
|
||||
uart1: serial@50210000 {
|
||||
compatible = "snps,dw-apb-uart";
|
||||
reg = <0x50210000 0x100>;
|
||||
interrupts = <11>;
|
||||
clocks = <&sysclk K210_CLK_UART1>,
|
||||
<&sysclk K210_CLK_APB0>;
|
||||
clock-names = "baudclk", "apb_pclk";
|
||||
resets = <&sysrst K210_RST_UART1>;
|
||||
reg-io-width = <4>;
|
||||
reg-shift = <2>;
|
||||
dcd-override;
|
||||
dsr-override;
|
||||
cts-override;
|
||||
ri-override;
|
||||
};
|
||||
|
||||
uart2: serial@50220000 {
|
||||
compatible = "snps,dw-apb-uart";
|
||||
reg = <0x50220000 0x100>;
|
||||
interrupts = <12>;
|
||||
clocks = <&sysclk K210_CLK_UART2>,
|
||||
<&sysclk K210_CLK_APB0>;
|
||||
clock-names = "baudclk", "apb_pclk";
|
||||
resets = <&sysrst K210_RST_UART2>;
|
||||
reg-io-width = <4>;
|
||||
reg-shift = <2>;
|
||||
dcd-override;
|
||||
dsr-override;
|
||||
cts-override;
|
||||
ri-override;
|
||||
};
|
||||
|
||||
uart3: serial@50230000 {
|
||||
compatible = "snps,dw-apb-uart";
|
||||
reg = <0x50230000 0x100>;
|
||||
interrupts = <13>;
|
||||
clocks = <&sysclk K210_CLK_UART3>,
|
||||
<&sysclk K210_CLK_APB0>;
|
||||
clock-names = "baudclk", "apb_pclk";
|
||||
resets = <&sysrst K210_RST_UART3>;
|
||||
reg-io-width = <4>;
|
||||
reg-shift = <2>;
|
||||
dcd-override;
|
||||
dsr-override;
|
||||
cts-override;
|
||||
ri-override;
|
||||
};
|
||||
|
||||
spi2: spi@50240000 {
|
||||
compatible = "canaan,k210-spi";
|
||||
spi-slave;
|
||||
reg = <0x50240000 0x100>;
|
||||
#address-cells = <0>;
|
||||
#size-cells = <0>;
|
||||
interrupts = <3>;
|
||||
clocks = <&sysclk K210_CLK_SPI2>,
|
||||
<&sysclk K210_CLK_APB0>;
|
||||
clock-names = "ssi_clk", "pclk";
|
||||
resets = <&sysrst K210_RST_SPI2>;
|
||||
spi-max-frequency = <25000000>;
|
||||
};
|
||||
|
||||
i2s0: i2s@50250000 {
|
||||
compatible = "snps,designware-i2s";
|
||||
reg = <0x50250000 0x200>;
|
||||
interrupts = <5>;
|
||||
clocks = <&sysclk K210_CLK_I2S0>;
|
||||
clock-names = "i2sclk";
|
||||
resets = <&sysrst K210_RST_I2S0>;
|
||||
};
|
||||
|
||||
i2s1: i2s@50260000 {
|
||||
compatible = "snps,designware-i2s";
|
||||
reg = <0x50260000 0x200>;
|
||||
interrupts = <6>;
|
||||
clocks = <&sysclk K210_CLK_I2S1>;
|
||||
clock-names = "i2sclk";
|
||||
resets = <&sysrst K210_RST_I2S1>;
|
||||
};
|
||||
|
||||
i2s2: i2s@50270000 {
|
||||
compatible = "snps,designware-i2s";
|
||||
reg = <0x50270000 0x200>;
|
||||
interrupts = <7>;
|
||||
clocks = <&sysclk K210_CLK_I2S2>;
|
||||
clock-names = "i2sclk";
|
||||
resets = <&sysrst K210_RST_I2S2>;
|
||||
};
|
||||
|
||||
i2c0: i2c@50280000 {
|
||||
compatible = "snps,designware-i2c";
|
||||
reg = <0x50280000 0x100>;
|
||||
interrupts = <8>;
|
||||
clocks = <&sysclk K210_CLK_I2C0>,
|
||||
<&sysclk K210_CLK_APB0>;
|
||||
clock-names = "ref", "pclk";
|
||||
resets = <&sysrst K210_RST_I2C0>;
|
||||
};
|
||||
|
||||
i2c1: i2c@50290000 {
|
||||
compatible = "snps,designware-i2c";
|
||||
reg = <0x50290000 0x100>;
|
||||
interrupts = <9>;
|
||||
clocks = <&sysclk K210_CLK_I2C1>,
|
||||
<&sysclk K210_CLK_APB0>;
|
||||
clock-names = "ref", "pclk";
|
||||
resets = <&sysrst K210_RST_I2C1>;
|
||||
};
|
||||
|
||||
i2c2: i2c@502a0000 {
|
||||
compatible = "snps,designware-i2c";
|
||||
reg = <0x502A0000 0x100>;
|
||||
interrupts = <10>;
|
||||
clocks = <&sysclk K210_CLK_I2C2>,
|
||||
<&sysclk K210_CLK_APB0>;
|
||||
clock-names = "ref", "pclk";
|
||||
resets = <&sysrst K210_RST_I2C2>;
|
||||
};
|
||||
|
||||
fpioa: pinmux@502b0000 {
|
||||
compatible = "canaan,k210-fpioa";
|
||||
reg = <0x502B0000 0x100>;
|
||||
clocks = <&sysclk K210_CLK_FPIOA>,
|
||||
<&sysclk K210_CLK_APB0>;
|
||||
clock-names = "ref", "pclk";
|
||||
resets = <&sysrst K210_RST_FPIOA>;
|
||||
canaan,k210-sysctl-power = <&sysctl 108>;
|
||||
};
|
||||
|
||||
timer0: timer@502d0000 {
|
||||
compatible = "snps,dw-apb-timer";
|
||||
reg = <0x502D0000 0x100>;
|
||||
interrupts = <14 15>;
|
||||
clocks = <&sysclk K210_CLK_TIMER0>,
|
||||
<&sysclk K210_CLK_APB0>;
|
||||
clock-names = "timer", "pclk";
|
||||
resets = <&sysrst K210_RST_TIMER0>;
|
||||
};
|
||||
|
||||
timer1: timer@502e0000 {
|
||||
compatible = "snps,dw-apb-timer";
|
||||
reg = <0x502E0000 0x100>;
|
||||
interrupts = <16 17>;
|
||||
clocks = <&sysclk K210_CLK_TIMER1>,
|
||||
<&sysclk K210_CLK_APB0>;
|
||||
clock-names = "timer", "pclk";
|
||||
resets = <&sysrst K210_RST_TIMER1>;
|
||||
};
|
||||
|
||||
timer2: timer@502f0000 {
|
||||
compatible = "snps,dw-apb-timer";
|
||||
reg = <0x502F0000 0x100>;
|
||||
interrupts = <18 19>;
|
||||
clocks = <&sysclk K210_CLK_TIMER2>,
|
||||
<&sysclk K210_CLK_APB0>;
|
||||
clock-names = "timer", "pclk";
|
||||
resets = <&sysrst K210_RST_TIMER2>;
|
||||
};
|
||||
};
|
||||
|
||||
apb1: bus@50400000 {
|
||||
#address-cells = <1>;
|
||||
#size-cells = <1>;
|
||||
compatible = "simple-pm-bus";
|
||||
ranges;
|
||||
clocks = <&sysclk K210_CLK_APB1>;
|
||||
|
||||
wdt0: watchdog@50400000 {
|
||||
compatible = "snps,dw-wdt";
|
||||
reg = <0x50400000 0x100>;
|
||||
interrupts = <21>;
|
||||
clocks = <&sysclk K210_CLK_WDT0>,
|
||||
<&sysclk K210_CLK_APB1>;
|
||||
clock-names = "tclk", "pclk";
|
||||
resets = <&sysrst K210_RST_WDT0>;
|
||||
};
|
||||
|
||||
wdt1: watchdog@50410000 {
|
||||
compatible = "snps,dw-wdt";
|
||||
reg = <0x50410000 0x100>;
|
||||
interrupts = <22>;
|
||||
clocks = <&sysclk K210_CLK_WDT1>,
|
||||
<&sysclk K210_CLK_APB1>;
|
||||
clock-names = "tclk", "pclk";
|
||||
resets = <&sysrst K210_RST_WDT1>;
|
||||
};
|
||||
|
||||
sysctl: syscon@50440000 {
|
||||
compatible = "canaan,k210-sysctl",
|
||||
"syscon", "simple-mfd";
|
||||
reg = <0x50440000 0x100>;
|
||||
clocks = <&sysclk K210_CLK_APB1>;
|
||||
clock-names = "pclk";
|
||||
|
||||
sysclk: clock-controller {
|
||||
#clock-cells = <1>;
|
||||
compatible = "canaan,k210-clk";
|
||||
clocks = <&in0>;
|
||||
};
|
||||
|
||||
sysrst: reset-controller {
|
||||
compatible = "canaan,k210-rst";
|
||||
#reset-cells = <1>;
|
||||
};
|
||||
|
||||
reboot: syscon-reboot {
|
||||
compatible = "syscon-reboot";
|
||||
regmap = <&sysctl>;
|
||||
offset = <48>;
|
||||
mask = <1>;
|
||||
value = <1>;
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
apb2: bus@52000000 {
|
||||
#address-cells = <1>;
|
||||
#size-cells = <1>;
|
||||
compatible = "simple-pm-bus";
|
||||
ranges;
|
||||
clocks = <&sysclk K210_CLK_APB2>;
|
||||
|
||||
spi0: spi@52000000 {
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
compatible = "canaan,k210-spi";
|
||||
reg = <0x52000000 0x100>;
|
||||
interrupts = <1>;
|
||||
clocks = <&sysclk K210_CLK_SPI0>,
|
||||
<&sysclk K210_CLK_APB2>;
|
||||
clock-names = "ssi_clk", "pclk";
|
||||
resets = <&sysrst K210_RST_SPI0>;
|
||||
reset-names = "spi";
|
||||
spi-max-frequency = <25000000>;
|
||||
num-cs = <4>;
|
||||
reg-io-width = <4>;
|
||||
};
|
||||
|
||||
spi1: spi@53000000 {
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
compatible = "canaan,k210-spi";
|
||||
reg = <0x53000000 0x100>;
|
||||
interrupts = <2>;
|
||||
clocks = <&sysclk K210_CLK_SPI1>,
|
||||
<&sysclk K210_CLK_APB2>;
|
||||
clock-names = "ssi_clk", "pclk";
|
||||
resets = <&sysrst K210_RST_SPI1>;
|
||||
reset-names = "spi";
|
||||
spi-max-frequency = <25000000>;
|
||||
num-cs = <4>;
|
||||
reg-io-width = <4>;
|
||||
};
|
||||
|
||||
spi3: spi@54000000 {
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
compatible = "snps,dwc-ssi-1.01a";
|
||||
reg = <0x54000000 0x200>;
|
||||
interrupts = <4>;
|
||||
clocks = <&sysclk K210_CLK_SPI3>,
|
||||
<&sysclk K210_CLK_APB2>;
|
||||
clock-names = "ssi_clk", "pclk";
|
||||
resets = <&sysrst K210_RST_SPI3>;
|
||||
reset-names = "spi";
|
||||
/* Could possibly go up to 200 MHz */
|
||||
spi-max-frequency = <100000000>;
|
||||
num-cs = <4>;
|
||||
reg-io-width = <4>;
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
|
@ -0,0 +1,46 @@
|
|||
// SPDX-License-Identifier: GPL-2.0+
|
||||
/*
|
||||
* Copyright (C) 2019-20 Sean Anderson <seanga2@gmail.com>
|
||||
* Copyright (C) 2020 Western Digital Corporation or its affiliates.
|
||||
*/
|
||||
|
||||
/dts-v1/;
|
||||
|
||||
#include "k210.dtsi"
|
||||
|
||||
#include <dt-bindings/gpio/gpio.h>
|
||||
#include <dt-bindings/input/input.h>
|
||||
|
||||
/ {
|
||||
model = "Kendryte K210 generic";
|
||||
compatible = "canaan,kendryte-k210";
|
||||
|
||||
chosen {
|
||||
bootargs = "earlycon console=ttySIF0";
|
||||
stdout-path = "serial0:115200n8";
|
||||
};
|
||||
};
|
||||
|
||||
&fpioa {
|
||||
pinctrl-0 = <&jtag_pins>;
|
||||
pinctrl-names = "default";
|
||||
status = "okay";
|
||||
|
||||
jtag_pins: jtag-pinmux {
|
||||
pinmux = <K210_FPIOA(0, K210_PCF_JTAG_TCLK)>,
|
||||
<K210_FPIOA(1, K210_PCF_JTAG_TDI)>,
|
||||
<K210_FPIOA(2, K210_PCF_JTAG_TMS)>,
|
||||
<K210_FPIOA(3, K210_PCF_JTAG_TDO)>;
|
||||
};
|
||||
|
||||
uarths_pins: uarths-pinmux {
|
||||
pinmux = <K210_FPIOA(4, K210_PCF_UARTHS_RX)>,
|
||||
<K210_FPIOA(5, K210_PCF_UARTHS_TX)>;
|
||||
};
|
||||
};
|
||||
|
||||
&uarths0 {
|
||||
pinctrl-0 = <&uarths_pins>;
|
||||
pinctrl-names = "default";
|
||||
status = "okay";
|
||||
};
|
|
@ -0,0 +1,209 @@
|
|||
// SPDX-License-Identifier: GPL-2.0+
|
||||
/*
|
||||
* Copyright (C) 2019-20 Sean Anderson <seanga2@gmail.com>
|
||||
* Copyright (C) 2020 Western Digital Corporation or its affiliates.
|
||||
*/
|
||||
|
||||
/dts-v1/;
|
||||
|
||||
#include "k210.dtsi"
|
||||
|
||||
#include <dt-bindings/gpio/gpio.h>
|
||||
#include <dt-bindings/input/input.h>
|
||||
#include <dt-bindings/leds/common.h>
|
||||
|
||||
/ {
|
||||
model = "SiPeed MAIX BiT";
|
||||
compatible = "sipeed,maix-bit", "sipeed,maix-bitm",
|
||||
"canaan,kendryte-k210";
|
||||
|
||||
chosen {
|
||||
bootargs = "earlycon console=ttySIF0";
|
||||
stdout-path = "serial0:115200n8";
|
||||
};
|
||||
|
||||
gpio-leds {
|
||||
compatible = "gpio-leds";
|
||||
|
||||
led0 {
|
||||
color = <LED_COLOR_ID_GREEN>;
|
||||
label = "green";
|
||||
gpios = <&gpio1_0 4 GPIO_ACTIVE_LOW>;
|
||||
};
|
||||
|
||||
led1 {
|
||||
color = <LED_COLOR_ID_RED>;
|
||||
label = "red";
|
||||
gpios = <&gpio1_0 5 GPIO_ACTIVE_LOW>;
|
||||
};
|
||||
|
||||
led2 {
|
||||
color = <LED_COLOR_ID_BLUE>;
|
||||
label = "blue";
|
||||
gpios = <&gpio1_0 6 GPIO_ACTIVE_LOW>;
|
||||
};
|
||||
};
|
||||
|
||||
gpio-keys {
|
||||
compatible = "gpio-keys";
|
||||
|
||||
boot {
|
||||
label = "BOOT";
|
||||
linux,code = <BTN_0>;
|
||||
gpios = <&gpio0 0 GPIO_ACTIVE_LOW>;
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
&fpioa {
|
||||
pinctrl-names = "default";
|
||||
pinctrl-0 = <&jtag_pinctrl>;
|
||||
status = "okay";
|
||||
|
||||
jtag_pinctrl: jtag-pinmux {
|
||||
pinmux = <K210_FPIOA(0, K210_PCF_JTAG_TCLK)>,
|
||||
<K210_FPIOA(1, K210_PCF_JTAG_TDI)>,
|
||||
<K210_FPIOA(2, K210_PCF_JTAG_TMS)>,
|
||||
<K210_FPIOA(3, K210_PCF_JTAG_TDO)>;
|
||||
};
|
||||
|
||||
uarths_pinctrl: uarths-pinmux {
|
||||
pinmux = <K210_FPIOA(4, K210_PCF_UARTHS_RX)>,
|
||||
<K210_FPIOA(5, K210_PCF_UARTHS_TX)>;
|
||||
};
|
||||
|
||||
gpio_pinctrl: gpio-pinmux {
|
||||
pinmux = <K210_FPIOA(8, K210_PCF_GPIO0)>,
|
||||
<K210_FPIOA(9, K210_PCF_GPIO1)>,
|
||||
<K210_FPIOA(10, K210_PCF_GPIO2)>,
|
||||
<K210_FPIOA(11, K210_PCF_GPIO3)>,
|
||||
<K210_FPIOA(12, K210_PCF_GPIO4)>,
|
||||
<K210_FPIOA(13, K210_PCF_GPIO5)>,
|
||||
<K210_FPIOA(14, K210_PCF_GPIO6)>,
|
||||
<K210_FPIOA(15, K210_PCF_GPIO7)>;
|
||||
};
|
||||
|
||||
gpiohs_pinctrl: gpiohs-pinmux {
|
||||
pinmux = <K210_FPIOA(16, K210_PCF_GPIOHS0)>,
|
||||
<K210_FPIOA(17, K210_PCF_GPIOHS1)>,
|
||||
<K210_FPIOA(21, K210_PCF_GPIOHS5)>,
|
||||
<K210_FPIOA(22, K210_PCF_GPIOHS6)>,
|
||||
<K210_FPIOA(23, K210_PCF_GPIOHS7)>,
|
||||
<K210_FPIOA(24, K210_PCF_GPIOHS8)>,
|
||||
<K210_FPIOA(25, K210_PCF_GPIOHS9)>,
|
||||
<K210_FPIOA(32, K210_PCF_GPIOHS16)>,
|
||||
<K210_FPIOA(33, K210_PCF_GPIOHS17)>,
|
||||
<K210_FPIOA(34, K210_PCF_GPIOHS18)>,
|
||||
<K210_FPIOA(35, K210_PCF_GPIOHS19)>;
|
||||
};
|
||||
|
||||
i2s0_pinctrl: i2s0-pinmux {
|
||||
pinmux = <K210_FPIOA(18, K210_PCF_I2S0_SCLK)>,
|
||||
<K210_FPIOA(19, K210_PCF_I2S0_WS)>,
|
||||
<K210_FPIOA(20, K210_PCF_I2S0_IN_D0)>;
|
||||
};
|
||||
|
||||
dvp_pinctrl: dvp-pinmux {
|
||||
pinmux = <K210_FPIOA(40, K210_PCF_SCCB_SDA)>,
|
||||
<K210_FPIOA(41, K210_PCF_SCCB_SCLK)>,
|
||||
<K210_FPIOA(42, K210_PCF_DVP_RST)>,
|
||||
<K210_FPIOA(43, K210_PCF_DVP_VSYNC)>,
|
||||
<K210_FPIOA(44, K210_PCF_DVP_PWDN)>,
|
||||
<K210_FPIOA(45, K210_PCF_DVP_HSYNC)>,
|
||||
<K210_FPIOA(46, K210_PCF_DVP_XCLK)>,
|
||||
<K210_FPIOA(47, K210_PCF_DVP_PCLK)>;
|
||||
};
|
||||
|
||||
spi0_pinctrl: spi0-pinmux {
|
||||
pinmux = <K210_FPIOA(36, K210_PCF_GPIOHS20)>, /* cs */
|
||||
<K210_FPIOA(37, K210_PCF_GPIOHS21)>, /* rst */
|
||||
<K210_FPIOA(38, K210_PCF_GPIOHS22)>, /* dc */
|
||||
<K210_FPIOA(39, K210_PCF_SPI0_SCLK)>; /* wr */
|
||||
};
|
||||
|
||||
spi1_pinctrl: spi1-pinmux {
|
||||
pinmux = <K210_FPIOA(26, K210_PCF_SPI1_D1)>,
|
||||
<K210_FPIOA(27, K210_PCF_SPI1_SCLK)>,
|
||||
<K210_FPIOA(28, K210_PCF_SPI1_D0)>,
|
||||
<K210_FPIOA(29, K210_PCF_GPIOHS13)>; /* cs */
|
||||
};
|
||||
|
||||
i2c1_pinctrl: i2c1-pinmux {
|
||||
pinmux = <K210_FPIOA(30, K210_PCF_I2C1_SCLK)>,
|
||||
<K210_FPIOA(31, K210_PCF_I2C1_SDA)>;
|
||||
};
|
||||
};
|
||||
|
||||
&uarths0 {
|
||||
pinctrl-0 = <&uarths_pinctrl>;
|
||||
pinctrl-names = "default";
|
||||
status = "okay";
|
||||
};
|
||||
|
||||
&gpio0 {
|
||||
pinctrl-0 = <&gpiohs_pinctrl>;
|
||||
pinctrl-names = "default";
|
||||
status = "okay";
|
||||
};
|
||||
|
||||
&gpio1 {
|
||||
pinctrl-0 = <&gpio_pinctrl>;
|
||||
pinctrl-names = "default";
|
||||
status = "okay";
|
||||
};
|
||||
|
||||
&i2s0 {
|
||||
#sound-dai-cells = <1>;
|
||||
pinctrl-0 = <&i2s0_pinctrl>;
|
||||
pinctrl-names = "default";
|
||||
};
|
||||
|
||||
&i2c1 {
|
||||
pinctrl-0 = <&i2c1_pinctrl>;
|
||||
pinctrl-names = "default";
|
||||
clock-frequency = <400000>;
|
||||
status = "okay";
|
||||
};
|
||||
|
||||
&spi0 {
|
||||
pinctrl-0 = <&spi0_pinctrl>;
|
||||
pinctrl-names = "default";
|
||||
num-cs = <1>;
|
||||
cs-gpios = <&gpio0 20 GPIO_ACTIVE_HIGH>;
|
||||
|
||||
panel@0 {
|
||||
compatible = "sitronix,st7789v";
|
||||
reg = <0>;
|
||||
reset-gpios = <&gpio0 21 GPIO_ACTIVE_LOW>;
|
||||
dc-gpios = <&gpio0 22 GPIO_ACTIVE_HIGH>;
|
||||
spi-max-frequency = <15000000>;
|
||||
spi-cs-high;
|
||||
status = "disabled";
|
||||
};
|
||||
};
|
||||
|
||||
&spi1 {
|
||||
pinctrl-0 = <&spi1_pinctrl>;
|
||||
pinctrl-names = "default";
|
||||
num-cs = <1>;
|
||||
cs-gpios = <&gpio0 13 GPIO_ACTIVE_LOW>;
|
||||
status = "okay";
|
||||
|
||||
slot@0 {
|
||||
compatible = "mmc-spi-slot";
|
||||
reg = <0>;
|
||||
voltage-ranges = <3300 3300>;
|
||||
spi-max-frequency = <25000000>;
|
||||
broken-cd;
|
||||
};
|
||||
};
|
||||
|
||||
&spi3 {
|
||||
spi-flash@0 {
|
||||
compatible = "jedec,spi-nor";
|
||||
reg = <0>;
|
||||
spi-max-frequency = <50000000>;
|
||||
m25p,fast-read;
|
||||
broken-flash-reset;
|
||||
};
|
||||
};
|
|
@ -0,0 +1,211 @@
|
|||
// SPDX-License-Identifier: GPL-2.0+
|
||||
/*
|
||||
* Copyright (C) 2019-20 Sean Anderson <seanga2@gmail.com>
|
||||
* Copyright (C) 2020 Western Digital Corporation or its affiliates.
|
||||
*/
|
||||
|
||||
/dts-v1/;
|
||||
|
||||
#include "k210.dtsi"
|
||||
|
||||
#include <dt-bindings/gpio/gpio.h>
|
||||
#include <dt-bindings/input/input.h>
|
||||
#include <dt-bindings/leds/common.h>
|
||||
|
||||
/ {
|
||||
model = "SiPeed MAIX Dock";
|
||||
compatible = "sipeed,maix-dock-m1", "sipeed,maix-dock-m1w",
|
||||
"canaan,kendryte-k210";
|
||||
|
||||
chosen {
|
||||
bootargs = "earlycon console=ttySIF0";
|
||||
stdout-path = "serial0:115200n8";
|
||||
};
|
||||
|
||||
gpio-leds {
|
||||
compatible = "gpio-leds";
|
||||
|
||||
/*
|
||||
* Note: the board wiring drawing documents green on
|
||||
* gpio #4, red on gpio #5 and blue on gpio #6. However,
|
||||
* the board is actually wired differently as defined here.
|
||||
*/
|
||||
led0 {
|
||||
color = <LED_COLOR_ID_BLUE>;
|
||||
label = "blue";
|
||||
gpios = <&gpio1_0 4 GPIO_ACTIVE_LOW>;
|
||||
};
|
||||
|
||||
led1 {
|
||||
color = <LED_COLOR_ID_GREEN>;
|
||||
label = "green";
|
||||
gpios = <&gpio1_0 5 GPIO_ACTIVE_LOW>;
|
||||
};
|
||||
|
||||
led2 {
|
||||
color = <LED_COLOR_ID_RED>;
|
||||
label = "red";
|
||||
gpios = <&gpio1_0 6 GPIO_ACTIVE_LOW>;
|
||||
};
|
||||
};
|
||||
|
||||
gpio-keys {
|
||||
compatible = "gpio-keys";
|
||||
|
||||
boot {
|
||||
label = "BOOT";
|
||||
linux,code = <BTN_0>;
|
||||
gpios = <&gpio0 0 GPIO_ACTIVE_LOW>;
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
&fpioa {
|
||||
pinctrl-0 = <&jtag_pinctrl>;
|
||||
pinctrl-names = "default";
|
||||
status = "okay";
|
||||
|
||||
jtag_pinctrl: jtag-pinmux {
|
||||
pinmux = <K210_FPIOA(0, K210_PCF_JTAG_TCLK)>,
|
||||
<K210_FPIOA(1, K210_PCF_JTAG_TDI)>,
|
||||
<K210_FPIOA(2, K210_PCF_JTAG_TMS)>,
|
||||
<K210_FPIOA(3, K210_PCF_JTAG_TDO)>;
|
||||
};
|
||||
|
||||
uarths_pinctrl: uarths-pinmux {
|
||||
pinmux = <K210_FPIOA(4, K210_PCF_UARTHS_RX)>,
|
||||
<K210_FPIOA(5, K210_PCF_UARTHS_TX)>;
|
||||
};
|
||||
|
||||
gpio_pinctrl: gpio-pinmux {
|
||||
pinmux = <K210_FPIOA(8, K210_PCF_GPIO0)>,
|
||||
<K210_FPIOA(11, K210_PCF_GPIO3)>,
|
||||
<K210_FPIOA(12, K210_PCF_GPIO4)>,
|
||||
<K210_FPIOA(13, K210_PCF_GPIO5)>,
|
||||
<K210_FPIOA(14, K210_PCF_GPIO6)>,
|
||||
<K210_FPIOA(15, K210_PCF_GPIO7)>;
|
||||
};
|
||||
|
||||
gpiohs_pinctrl: gpiohs-pinmux {
|
||||
pinmux = <K210_FPIOA(16, K210_PCF_GPIOHS0)>,
|
||||
<K210_FPIOA(17, K210_PCF_GPIOHS1)>,
|
||||
<K210_FPIOA(21, K210_PCF_GPIOHS5)>,
|
||||
<K210_FPIOA(22, K210_PCF_GPIOHS6)>,
|
||||
<K210_FPIOA(23, K210_PCF_GPIOHS7)>,
|
||||
<K210_FPIOA(24, K210_PCF_GPIOHS8)>,
|
||||
<K210_FPIOA(25, K210_PCF_GPIOHS9)>,
|
||||
<K210_FPIOA(32, K210_PCF_GPIOHS16)>,
|
||||
<K210_FPIOA(33, K210_PCF_GPIOHS17)>,
|
||||
<K210_FPIOA(34, K210_PCF_GPIOHS18)>,
|
||||
<K210_FPIOA(35, K210_PCF_GPIOHS19)>;
|
||||
};
|
||||
|
||||
i2s0_pinctrl: i2s0-pinmux {
|
||||
pinmux = <K210_FPIOA(18, K210_PCF_I2S0_SCLK)>,
|
||||
<K210_FPIOA(19, K210_PCF_I2S0_WS)>,
|
||||
<K210_FPIOA(20, K210_PCF_I2S0_IN_D0)>;
|
||||
};
|
||||
|
||||
dvp_pinctrl: dvp-pinmux {
|
||||
pinmux = <K210_FPIOA(40, K210_PCF_SCCB_SDA)>,
|
||||
<K210_FPIOA(41, K210_PCF_SCCB_SCLK)>,
|
||||
<K210_FPIOA(42, K210_PCF_DVP_RST)>,
|
||||
<K210_FPIOA(43, K210_PCF_DVP_VSYNC)>,
|
||||
<K210_FPIOA(44, K210_PCF_DVP_PWDN)>,
|
||||
<K210_FPIOA(45, K210_PCF_DVP_HSYNC)>,
|
||||
<K210_FPIOA(46, K210_PCF_DVP_XCLK)>,
|
||||
<K210_FPIOA(47, K210_PCF_DVP_PCLK)>;
|
||||
};
|
||||
|
||||
spi0_pinctrl: spi0-pinmux {
|
||||
pinmux = <K210_FPIOA(36, K210_PCF_GPIOHS20)>, /* cs */
|
||||
<K210_FPIOA(37, K210_PCF_GPIOHS21)>, /* rst */
|
||||
<K210_FPIOA(38, K210_PCF_GPIOHS22)>, /* dc */
|
||||
<K210_FPIOA(39, K210_PCF_SPI0_SCLK)>; /* wr */
|
||||
};
|
||||
|
||||
spi1_pinctrl: spi1-pinmux {
|
||||
pinmux = <K210_FPIOA(26, K210_PCF_SPI1_D1)>,
|
||||
<K210_FPIOA(27, K210_PCF_SPI1_SCLK)>,
|
||||
<K210_FPIOA(28, K210_PCF_SPI1_D0)>,
|
||||
<K210_FPIOA(29, K210_PCF_GPIOHS13)>; /* cs */
|
||||
};
|
||||
|
||||
i2c1_pinctrl: i2c1-pinmux {
|
||||
pinmux = <K210_FPIOA(9, K210_PCF_I2C1_SCLK)>,
|
||||
<K210_FPIOA(10, K210_PCF_I2C1_SDA)>;
|
||||
};
|
||||
};
|
||||
|
||||
&uarths0 {
|
||||
pinctrl-0 = <&uarths_pinctrl>;
|
||||
pinctrl-names = "default";
|
||||
status = "okay";
|
||||
};
|
||||
|
||||
&gpio0 {
|
||||
pinctrl-0 = <&gpiohs_pinctrl>;
|
||||
pinctrl-names = "default";
|
||||
status = "okay";
|
||||
};
|
||||
|
||||
&gpio1 {
|
||||
pinctrl-0 = <&gpio_pinctrl>;
|
||||
pinctrl-names = "default";
|
||||
status = "okay";
|
||||
};
|
||||
|
||||
&i2s0 {
|
||||
#sound-dai-cells = <1>;
|
||||
pinctrl-0 = <&i2s0_pinctrl>;
|
||||
pinctrl-names = "default";
|
||||
};
|
||||
|
||||
&i2c1 {
|
||||
pinctrl-0 = <&i2c1_pinctrl>;
|
||||
pinctrl-names = "default";
|
||||
clock-frequency = <400000>;
|
||||
status = "okay";
|
||||
};
|
||||
|
||||
&spi0 {
|
||||
pinctrl-0 = <&spi0_pinctrl>;
|
||||
pinctrl-names = "default";
|
||||
num-cs = <1>;
|
||||
cs-gpios = <&gpio0 20 GPIO_ACTIVE_HIGH>;
|
||||
|
||||
panel@0 {
|
||||
compatible = "sitronix,st7789v";
|
||||
reg = <0>;
|
||||
reset-gpios = <&gpio0 21 GPIO_ACTIVE_LOW>;
|
||||
dc-gpios = <&gpio0 22 0>;
|
||||
spi-max-frequency = <15000000>;
|
||||
status = "disabled";
|
||||
};
|
||||
};
|
||||
|
||||
&spi1 {
|
||||
pinctrl-0 = <&spi1_pinctrl>;
|
||||
pinctrl-names = "default";
|
||||
num-cs = <1>;
|
||||
cs-gpios = <&gpio0 13 GPIO_ACTIVE_LOW>;
|
||||
status = "okay";
|
||||
|
||||
slot@0 {
|
||||
compatible = "mmc-spi-slot";
|
||||
reg = <0>;
|
||||
voltage-ranges = <3300 3300>;
|
||||
spi-max-frequency = <25000000>;
|
||||
broken-cd;
|
||||
};
|
||||
};
|
||||
|
||||
&spi3 {
|
||||
spi-flash@0 {
|
||||
compatible = "jedec,spi-nor";
|
||||
reg = <0>;
|
||||
spi-max-frequency = <50000000>;
|
||||
m25p,fast-read;
|
||||
broken-flash-reset;
|
||||
};
|
||||
};
|
|
@ -0,0 +1,219 @@
|
|||
// SPDX-License-Identifier: GPL-2.0+
|
||||
/*
|
||||
* Copyright (C) 2019-20 Sean Anderson <seanga2@gmail.com>
|
||||
* Copyright (C) 2020 Western Digital Corporation or its affiliates.
|
||||
*/
|
||||
|
||||
/dts-v1/;
|
||||
|
||||
#include "k210.dtsi"
|
||||
|
||||
#include <dt-bindings/gpio/gpio.h>
|
||||
#include <dt-bindings/input/input.h>
|
||||
#include <dt-bindings/leds/common.h>
|
||||
|
||||
/ {
|
||||
model = "SiPeed MAIX GO";
|
||||
compatible = "sipeed,maix-go", "canaan,kendryte-k210";
|
||||
|
||||
chosen {
|
||||
bootargs = "earlycon console=ttySIF0";
|
||||
stdout-path = "serial0:115200n8";
|
||||
};
|
||||
|
||||
gpio-leds {
|
||||
compatible = "gpio-leds";
|
||||
|
||||
led0 {
|
||||
color = <LED_COLOR_ID_GREEN>;
|
||||
label = "green";
|
||||
gpios = <&gpio1_0 4 GPIO_ACTIVE_LOW>;
|
||||
};
|
||||
|
||||
led1 {
|
||||
color = <LED_COLOR_ID_RED>;
|
||||
label = "red";
|
||||
gpios = <&gpio1_0 5 GPIO_ACTIVE_LOW>;
|
||||
};
|
||||
|
||||
led2 {
|
||||
color = <LED_COLOR_ID_BLUE>;
|
||||
label = "blue";
|
||||
gpios = <&gpio1_0 6 GPIO_ACTIVE_LOW>;
|
||||
};
|
||||
};
|
||||
|
||||
gpio-keys {
|
||||
compatible = "gpio-keys";
|
||||
|
||||
up {
|
||||
label = "UP";
|
||||
linux,code = <BTN_1>;
|
||||
gpios = <&gpio1_0 7 GPIO_ACTIVE_LOW>;
|
||||
};
|
||||
|
||||
press {
|
||||
label = "PRESS";
|
||||
linux,code = <BTN_0>;
|
||||
gpios = <&gpio0 0 GPIO_ACTIVE_LOW>;
|
||||
};
|
||||
|
||||
down {
|
||||
label = "DOWN";
|
||||
linux,code = <BTN_2>;
|
||||
gpios = <&gpio0 1 GPIO_ACTIVE_LOW>;
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
&fpioa {
|
||||
pinctrl-0 = <&jtag_pinctrl>;
|
||||
pinctrl-names = "default";
|
||||
status = "okay";
|
||||
|
||||
jtag_pinctrl: jtag-pinmux {
|
||||
pinmux = <K210_FPIOA(0, K210_PCF_JTAG_TCLK)>,
|
||||
<K210_FPIOA(1, K210_PCF_JTAG_TDI)>,
|
||||
<K210_FPIOA(2, K210_PCF_JTAG_TMS)>,
|
||||
<K210_FPIOA(3, K210_PCF_JTAG_TDO)>;
|
||||
};
|
||||
|
||||
uarths_pinctrl: uarths-pinmux {
|
||||
pinmux = <K210_FPIOA(4, K210_PCF_UARTHS_RX)>,
|
||||
<K210_FPIOA(5, K210_PCF_UARTHS_TX)>;
|
||||
};
|
||||
|
||||
gpio_pinctrl: gpio-pinmux {
|
||||
pinmux = <K210_FPIOA(8, K210_PCF_GPIO0)>,
|
||||
<K210_FPIOA(9, K210_PCF_GPIO1)>,
|
||||
<K210_FPIOA(10, K210_PCF_GPIO2)>,
|
||||
<K210_FPIOA(11, K210_PCF_GPIO3)>,
|
||||
<K210_FPIOA(12, K210_PCF_GPIO4)>,
|
||||
<K210_FPIOA(13, K210_PCF_GPIO5)>,
|
||||
<K210_FPIOA(14, K210_PCF_GPIO6)>,
|
||||
<K210_FPIOA(15, K210_PCF_GPIO7)>;
|
||||
};
|
||||
|
||||
gpiohs_pinctrl: gpiohs-pinmux {
|
||||
pinmux = <K210_FPIOA(16, K210_PCF_GPIOHS0)>,
|
||||
<K210_FPIOA(17, K210_PCF_GPIOHS1)>,
|
||||
<K210_FPIOA(21, K210_PCF_GPIOHS5)>,
|
||||
<K210_FPIOA(22, K210_PCF_GPIOHS6)>,
|
||||
<K210_FPIOA(23, K210_PCF_GPIOHS7)>,
|
||||
<K210_FPIOA(24, K210_PCF_GPIOHS8)>,
|
||||
<K210_FPIOA(25, K210_PCF_GPIOHS9)>,
|
||||
<K210_FPIOA(32, K210_PCF_GPIOHS16)>,
|
||||
<K210_FPIOA(33, K210_PCF_GPIOHS17)>,
|
||||
<K210_FPIOA(34, K210_PCF_GPIOHS18)>,
|
||||
<K210_FPIOA(35, K210_PCF_GPIOHS19)>;
|
||||
};
|
||||
|
||||
i2s0_pinctrl: i2s0-pinmux {
|
||||
pinmux = <K210_FPIOA(18, K210_PCF_I2S0_SCLK)>,
|
||||
<K210_FPIOA(19, K210_PCF_I2S0_WS)>,
|
||||
<K210_FPIOA(20, K210_PCF_I2S0_IN_D0)>;
|
||||
};
|
||||
|
||||
dvp_pinctrl: dvp-pinmux {
|
||||
pinmux = <K210_FPIOA(40, K210_PCF_SCCB_SDA)>,
|
||||
<K210_FPIOA(41, K210_PCF_SCCB_SCLK)>,
|
||||
<K210_FPIOA(42, K210_PCF_DVP_RST)>,
|
||||
<K210_FPIOA(43, K210_PCF_DVP_VSYNC)>,
|
||||
<K210_FPIOA(44, K210_PCF_DVP_PWDN)>,
|
||||
<K210_FPIOA(45, K210_PCF_DVP_HSYNC)>,
|
||||
<K210_FPIOA(46, K210_PCF_DVP_XCLK)>,
|
||||
<K210_FPIOA(47, K210_PCF_DVP_PCLK)>;
|
||||
};
|
||||
|
||||
spi0_pinctrl: spi0-pinmux {
|
||||
pinmux = <K210_FPIOA(36, K210_PCF_GPIOHS20)>, /* cs */
|
||||
<K210_FPIOA(37, K210_PCF_GPIOHS21)>, /* rst */
|
||||
<K210_FPIOA(38, K210_PCF_GPIOHS22)>, /* dc */
|
||||
<K210_FPIOA(39, K210_PCF_SPI0_SCLK)>; /* wr */
|
||||
};
|
||||
|
||||
spi1_pinctrl: spi1-pinmux {
|
||||
pinmux = <K210_FPIOA(26, K210_PCF_SPI1_D1)>,
|
||||
<K210_FPIOA(27, K210_PCF_SPI1_SCLK)>,
|
||||
<K210_FPIOA(28, K210_PCF_SPI1_D0)>,
|
||||
<K210_FPIOA(29, K210_PCF_GPIOHS13)>; /* cs */
|
||||
};
|
||||
|
||||
i2c1_pinctrl: i2c1-pinmux {
|
||||
pinmux = <K210_FPIOA(30, K210_PCF_I2C1_SCLK)>,
|
||||
<K210_FPIOA(31, K210_PCF_I2C1_SDA)>;
|
||||
};
|
||||
};
|
||||
|
||||
&uarths0 {
|
||||
pinctrl-0 = <&uarths_pinctrl>;
|
||||
pinctrl-names = "default";
|
||||
status = "okay";
|
||||
};
|
||||
|
||||
&gpio0 {
|
||||
pinctrl-0 = <&gpiohs_pinctrl>;
|
||||
pinctrl-names = "default";
|
||||
status = "okay";
|
||||
};
|
||||
|
||||
&gpio1 {
|
||||
pinctrl-0 = <&gpio_pinctrl>;
|
||||
pinctrl-names = "default";
|
||||
status = "okay";
|
||||
};
|
||||
|
||||
&i2s0 {
|
||||
#sound-dai-cells = <1>;
|
||||
pinctrl-0 = <&i2s0_pinctrl>;
|
||||
pinctrl-names = "default";
|
||||
};
|
||||
|
||||
&i2c1 {
|
||||
pinctrl-0 = <&i2c1_pinctrl>;
|
||||
pinctrl-names = "default";
|
||||
clock-frequency = <400000>;
|
||||
status = "okay";
|
||||
};
|
||||
|
||||
&spi0 {
|
||||
pinctrl-0 = <&spi0_pinctrl>;
|
||||
pinctrl-names = "default";
|
||||
num-cs = <1>;
|
||||
cs-gpios = <&gpio0 20 GPIO_ACTIVE_HIGH>;
|
||||
|
||||
panel@0 {
|
||||
compatible = "sitronix,st7789v";
|
||||
reg = <0>;
|
||||
reset-gpios = <&gpio0 21 GPIO_ACTIVE_LOW>;
|
||||
dc-gpios = <&gpio0 22 GPIO_ACTIVE_HIGH>;
|
||||
spi-max-frequency = <15000000>;
|
||||
status = "disabled";
|
||||
};
|
||||
};
|
||||
|
||||
&spi1 {
|
||||
pinctrl-0 = <&spi1_pinctrl>;
|
||||
pinctrl-names = "default";
|
||||
num-cs = <1>;
|
||||
cs-gpios = <&gpio0 13 GPIO_ACTIVE_LOW>;
|
||||
status = "okay";
|
||||
|
||||
slot@0 {
|
||||
compatible = "mmc-spi-slot";
|
||||
reg = <0>;
|
||||
voltage-ranges = <3300 3300>;
|
||||
spi-max-frequency = <25000000>;
|
||||
broken-cd;
|
||||
};
|
||||
};
|
||||
|
||||
&spi3 {
|
||||
spi-flash@0 {
|
||||
compatible = "jedec,spi-nor";
|
||||
reg = <0>;
|
||||
spi-max-frequency = <50000000>;
|
||||
m25p,fast-read;
|
||||
broken-flash-reset;
|
||||
};
|
||||
};
|
|
@ -0,0 +1,184 @@
|
|||
// SPDX-License-Identifier: GPL-2.0+
|
||||
/*
|
||||
* Copyright (C) 2019-20 Sean Anderson <seanga2@gmail.com>
|
||||
* Copyright (C) 2020 Western Digital Corporation or its affiliates.
|
||||
*/
|
||||
|
||||
/dts-v1/;
|
||||
|
||||
#include "k210.dtsi"
|
||||
|
||||
#include <dt-bindings/gpio/gpio.h>
|
||||
#include <dt-bindings/input/input.h>
|
||||
|
||||
/ {
|
||||
model = "SiPeed MAIXDUINO";
|
||||
compatible = "sipeed,maixduino", "canaan,kendryte-k210";
|
||||
|
||||
chosen {
|
||||
bootargs = "earlycon console=ttySIF0";
|
||||
stdout-path = "serial0:115200n8";
|
||||
};
|
||||
|
||||
gpio-keys {
|
||||
compatible = "gpio-keys";
|
||||
|
||||
boot {
|
||||
label = "BOOT";
|
||||
linux,code = <BTN_0>;
|
||||
gpios = <&gpio0 0 GPIO_ACTIVE_LOW>;
|
||||
};
|
||||
};
|
||||
|
||||
vcc_3v3: regulator-3v3 {
|
||||
compatible = "regulator-fixed";
|
||||
regulator-name = "3v3";
|
||||
regulator-min-microvolt = <3300000>;
|
||||
regulator-max-microvolt = <3300000>;
|
||||
};
|
||||
};
|
||||
|
||||
&fpioa {
|
||||
status = "okay";
|
||||
|
||||
uarths_pinctrl: uarths-pinmux {
|
||||
pinmux = <K210_FPIOA(4, K210_PCF_UARTHS_RX)>, /* Header "0" */
|
||||
<K210_FPIOA(5, K210_PCF_UARTHS_TX)>; /* Header "1" */
|
||||
};
|
||||
|
||||
gpio_pinctrl: gpio-pinmux {
|
||||
pinmux = <K210_FPIOA(8, K210_PCF_GPIO0)>,
|
||||
<K210_FPIOA(9, K210_PCF_GPIO1)>;
|
||||
};
|
||||
|
||||
gpiohs_pinctrl: gpiohs-pinmux {
|
||||
pinmux = <K210_FPIOA(16, K210_PCF_GPIOHS0)>, /* BOOT */
|
||||
<K210_FPIOA(21, K210_PCF_GPIOHS2)>, /* Header "2" */
|
||||
<K210_FPIOA(22, K210_PCF_GPIOHS3)>, /* Header "3" */
|
||||
<K210_FPIOA(23, K210_PCF_GPIOHS4)>, /* Header "4" */
|
||||
<K210_FPIOA(24, K210_PCF_GPIOHS5)>, /* Header "5" */
|
||||
<K210_FPIOA(32, K210_PCF_GPIOHS6)>, /* Header "6" */
|
||||
<K210_FPIOA(15, K210_PCF_GPIOHS7)>, /* Header "7" */
|
||||
<K210_FPIOA(14, K210_PCF_GPIOHS8)>, /* Header "8" */
|
||||
<K210_FPIOA(13, K210_PCF_GPIOHS9)>, /* Header "9" */
|
||||
<K210_FPIOA(12, K210_PCF_GPIOHS10)>, /* Header "10" */
|
||||
<K210_FPIOA(11, K210_PCF_GPIOHS11)>, /* Header "11" */
|
||||
<K210_FPIOA(10, K210_PCF_GPIOHS12)>, /* Header "12" */
|
||||
<K210_FPIOA(3, K210_PCF_GPIOHS13)>; /* Header "13" */
|
||||
};
|
||||
|
||||
i2s0_pinctrl: i2s0-pinmux {
|
||||
pinmux = <K210_FPIOA(18, K210_PCF_I2S0_SCLK)>,
|
||||
<K210_FPIOA(19, K210_PCF_I2S0_WS)>,
|
||||
<K210_FPIOA(20, K210_PCF_I2S0_IN_D0)>;
|
||||
};
|
||||
|
||||
spi1_pinctrl: spi1-pinmux {
|
||||
pinmux = <K210_FPIOA(26, K210_PCF_SPI1_D1)>,
|
||||
<K210_FPIOA(27, K210_PCF_SPI1_SCLK)>,
|
||||
<K210_FPIOA(28, K210_PCF_SPI1_D0)>,
|
||||
<K210_FPIOA(29, K210_PCF_GPIO2)>; /* cs */
|
||||
};
|
||||
|
||||
i2c1_pinctrl: i2c1-pinmux {
|
||||
pinmux = <K210_FPIOA(30, K210_PCF_I2C1_SCLK)>, /* Header "scl" */
|
||||
<K210_FPIOA(31, K210_PCF_I2C1_SDA)>; /* Header "sda" */
|
||||
};
|
||||
|
||||
i2s1_pinctrl: i2s1-pinmux {
|
||||
pinmux = <K210_FPIOA(33, K210_PCF_I2S1_WS)>,
|
||||
<K210_FPIOA(34, K210_PCF_I2S1_IN_D0)>,
|
||||
<K210_FPIOA(35, K210_PCF_I2S1_SCLK)>;
|
||||
};
|
||||
|
||||
spi0_pinctrl: spi0-pinmux {
|
||||
pinmux = <K210_FPIOA(36, K210_PCF_GPIOHS20)>, /* cs */
|
||||
<K210_FPIOA(37, K210_PCF_GPIOHS21)>, /* rst */
|
||||
<K210_FPIOA(38, K210_PCF_GPIOHS22)>, /* dc */
|
||||
<K210_FPIOA(39, K210_PCF_SPI0_SCLK)>; /* wr */
|
||||
};
|
||||
|
||||
dvp_pinctrl: dvp-pinmux {
|
||||
pinmux = <K210_FPIOA(40, K210_PCF_SCCB_SDA)>,
|
||||
<K210_FPIOA(41, K210_PCF_SCCB_SCLK)>,
|
||||
<K210_FPIOA(42, K210_PCF_DVP_RST)>,
|
||||
<K210_FPIOA(43, K210_PCF_DVP_VSYNC)>,
|
||||
<K210_FPIOA(44, K210_PCF_DVP_PWDN)>,
|
||||
<K210_FPIOA(45, K210_PCF_DVP_HSYNC)>,
|
||||
<K210_FPIOA(46, K210_PCF_DVP_XCLK)>,
|
||||
<K210_FPIOA(47, K210_PCF_DVP_PCLK)>;
|
||||
};
|
||||
};
|
||||
|
||||
&uarths0 {
|
||||
pinctrl-0 = <&uarths_pinctrl>;
|
||||
pinctrl-names = "default";
|
||||
status = "okay";
|
||||
};
|
||||
|
||||
&gpio0 {
|
||||
pinctrl-0 = <&gpiohs_pinctrl>;
|
||||
pinctrl-names = "default";
|
||||
status = "okay";
|
||||
};
|
||||
|
||||
&gpio1 {
|
||||
pinctrl-0 = <&gpio_pinctrl>;
|
||||
pinctrl-names = "default";
|
||||
status = "okay";
|
||||
};
|
||||
|
||||
&i2s0 {
|
||||
#sound-dai-cells = <1>;
|
||||
pinctrl-0 = <&i2s0_pinctrl>;
|
||||
pinctrl-names = "default";
|
||||
};
|
||||
|
||||
&i2c1 {
|
||||
pinctrl-0 = <&i2c1_pinctrl>;
|
||||
pinctrl-names = "default";
|
||||
clock-frequency = <400000>;
|
||||
status = "okay";
|
||||
};
|
||||
|
||||
&spi0 {
|
||||
pinctrl-0 = <&spi0_pinctrl>;
|
||||
pinctrl-names = "default";
|
||||
num-cs = <1>;
|
||||
cs-gpios = <&gpio0 20 GPIO_ACTIVE_HIGH>;
|
||||
|
||||
panel@0 {
|
||||
compatible = "sitronix,st7789v";
|
||||
reg = <0>;
|
||||
reset-gpios = <&gpio0 21 GPIO_ACTIVE_LOW>;
|
||||
dc-gpios = <&gpio0 22 0>;
|
||||
spi-max-frequency = <15000000>;
|
||||
power-supply = <&vcc_3v3>;
|
||||
};
|
||||
};
|
||||
|
||||
&spi1 {
|
||||
pinctrl-0 = <&spi1_pinctrl>;
|
||||
pinctrl-names = "default";
|
||||
num-cs = <1>;
|
||||
cs-gpios = <&gpio1_0 2 GPIO_ACTIVE_LOW>;
|
||||
status = "okay";
|
||||
|
||||
slot@0 {
|
||||
compatible = "mmc-spi-slot";
|
||||
reg = <0>;
|
||||
voltage-ranges = <3300 3300>;
|
||||
spi-max-frequency = <25000000>;
|
||||
broken-cd;
|
||||
};
|
||||
};
|
||||
|
||||
&spi3 {
|
||||
spi-flash@0 {
|
||||
compatible = "jedec,spi-nor";
|
||||
reg = <0>;
|
||||
spi-max-frequency = <50000000>;
|
||||
m25p,fast-read;
|
||||
broken-flash-reset;
|
||||
};
|
||||
};
|
|
@ -1,4 +0,0 @@
|
|||
# SPDX-License-Identifier: GPL-2.0
|
||||
dtb-$(CONFIG_SOC_KENDRYTE_K210_DTB) += k210.dtb
|
||||
|
||||
obj-$(CONFIG_SOC_KENDRYTE_K210_DTB_BUILTIN) += $(addsuffix .o, $(dtb-y))
|
|
@ -1,23 +0,0 @@
|
|||
// SPDX-License-Identifier: GPL-2.0+
|
||||
/*
|
||||
* Copyright (C) 2020 Western Digital Corporation or its affiliates.
|
||||
*/
|
||||
|
||||
/dts-v1/;
|
||||
|
||||
#include "k210.dtsi"
|
||||
|
||||
/ {
|
||||
model = "Kendryte K210 generic";
|
||||
compatible = "kendryte,k210";
|
||||
|
||||
chosen {
|
||||
bootargs = "earlycon console=ttySIF0";
|
||||
stdout-path = "serial0";
|
||||
};
|
||||
};
|
||||
|
||||
&uarths0 {
|
||||
status = "okay";
|
||||
};
|
||||
|
|
@ -1,125 +0,0 @@
|
|||
// SPDX-License-Identifier: GPL-2.0+
|
||||
/*
|
||||
* Copyright (C) 2019 Sean Anderson <seanga2@gmail.com>
|
||||
* Copyright (C) 2020 Western Digital Corporation or its affiliates.
|
||||
*/
|
||||
#include <dt-bindings/clock/k210-clk.h>
|
||||
|
||||
/ {
|
||||
/*
|
||||
* Although the K210 is a 64-bit CPU, the address bus is only 32-bits
|
||||
* wide, and the upper half of all addresses is ignored.
|
||||
*/
|
||||
#address-cells = <1>;
|
||||
#size-cells = <1>;
|
||||
compatible = "kendryte,k210";
|
||||
|
||||
aliases {
|
||||
serial0 = &uarths0;
|
||||
};
|
||||
|
||||
/*
|
||||
* The K210 has an sv39 MMU following the priviledge specification v1.9.
|
||||
* Since this is a non-ratified draft specification, the kernel does not
|
||||
* support it and the K210 support enabled only for the !MMU case.
|
||||
* Be consistent with this by setting the CPUs MMU type to "none".
|
||||
*/
|
||||
cpus {
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
timebase-frequency = <7800000>;
|
||||
cpu0: cpu@0 {
|
||||
device_type = "cpu";
|
||||
reg = <0>;
|
||||
compatible = "kendryte,k210", "sifive,rocket0", "riscv";
|
||||
riscv,isa = "rv64imafdc";
|
||||
mmu-type = "none";
|
||||
i-cache-size = <0x8000>;
|
||||
i-cache-block-size = <64>;
|
||||
d-cache-size = <0x8000>;
|
||||
d-cache-block-size = <64>;
|
||||
clocks = <&sysctl K210_CLK_CPU>;
|
||||
clock-frequency = <390000000>;
|
||||
cpu0_intc: interrupt-controller {
|
||||
#interrupt-cells = <1>;
|
||||
interrupt-controller;
|
||||
compatible = "riscv,cpu-intc";
|
||||
};
|
||||
};
|
||||
cpu1: cpu@1 {
|
||||
device_type = "cpu";
|
||||
reg = <1>;
|
||||
compatible = "kendryte,k210", "sifive,rocket0", "riscv";
|
||||
riscv,isa = "rv64imafdc";
|
||||
mmu-type = "none";
|
||||
i-cache-size = <0x8000>;
|
||||
i-cache-block-size = <64>;
|
||||
d-cache-size = <0x8000>;
|
||||
d-cache-block-size = <64>;
|
||||
clocks = <&sysctl K210_CLK_CPU>;
|
||||
clock-frequency = <390000000>;
|
||||
cpu1_intc: interrupt-controller {
|
||||
#interrupt-cells = <1>;
|
||||
interrupt-controller;
|
||||
compatible = "riscv,cpu-intc";
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
sram: memory@80000000 {
|
||||
device_type = "memory";
|
||||
reg = <0x80000000 0x400000>,
|
||||
<0x80400000 0x200000>,
|
||||
<0x80600000 0x200000>;
|
||||
reg-names = "sram0", "sram1", "aisram";
|
||||
};
|
||||
|
||||
clocks {
|
||||
in0: oscillator {
|
||||
compatible = "fixed-clock";
|
||||
#clock-cells = <0>;
|
||||
clock-frequency = <26000000>;
|
||||
};
|
||||
};
|
||||
|
||||
soc {
|
||||
#address-cells = <1>;
|
||||
#size-cells = <1>;
|
||||
compatible = "kendryte,k210-soc", "simple-bus";
|
||||
ranges;
|
||||
interrupt-parent = <&plic0>;
|
||||
|
||||
sysctl: sysctl@50440000 {
|
||||
compatible = "kendryte,k210-sysctl", "simple-mfd";
|
||||
reg = <0x50440000 0x1000>;
|
||||
#clock-cells = <1>;
|
||||
};
|
||||
|
||||
clint0: clint@2000000 {
|
||||
#interrupt-cells = <1>;
|
||||
compatible = "riscv,clint0";
|
||||
reg = <0x2000000 0xC000>;
|
||||
interrupts-extended = <&cpu0_intc 3 &cpu0_intc 7
|
||||
&cpu1_intc 3 &cpu1_intc 7>;
|
||||
clocks = <&sysctl K210_CLK_ACLK>;
|
||||
};
|
||||
|
||||
plic0: interrupt-controller@c000000 {
|
||||
#interrupt-cells = <1>;
|
||||
interrupt-controller;
|
||||
compatible = "kendryte,k210-plic0", "riscv,plic0";
|
||||
reg = <0xC000000 0x4000000>;
|
||||
interrupts-extended = <&cpu0_intc 11>, <&cpu0_intc 0xffffffff>,
|
||||
<&cpu1_intc 11>, <&cpu1_intc 0xffffffff>;
|
||||
riscv,ndev = <65>;
|
||||
riscv,max-priority = <7>;
|
||||
};
|
||||
|
||||
uarths0: serial@38000000 {
|
||||
compatible = "kendryte,k210-uarths", "sifive,uart0";
|
||||
reg = <0x38000000 0x1000>;
|
||||
interrupts = <33>;
|
||||
clocks = <&sysctl K210_CLK_CPU>;
|
||||
};
|
||||
};
|
||||
};
|
|
@ -1,2 +1,3 @@
|
|||
# SPDX-License-Identifier: GPL-2.0
|
||||
dtb-$(CONFIG_SOC_SIFIVE) += hifive-unleashed-a00.dtb
|
||||
dtb-$(CONFIG_SOC_SIFIVE) += hifive-unleashed-a00.dtb \
|
||||
hifive-unmatched-a00.dtb
|
||||
|
|
|
@ -0,0 +1,293 @@
|
|||
// SPDX-License-Identifier: (GPL-2.0 OR MIT)
|
||||
/* Copyright (c) 2020 SiFive, Inc */
|
||||
|
||||
/dts-v1/;
|
||||
|
||||
#include <dt-bindings/clock/sifive-fu740-prci.h>
|
||||
|
||||
/ {
|
||||
#address-cells = <2>;
|
||||
#size-cells = <2>;
|
||||
compatible = "sifive,fu740-c000", "sifive,fu740";
|
||||
|
||||
aliases {
|
||||
serial0 = &uart0;
|
||||
serial1 = &uart1;
|
||||
ethernet0 = ð0;
|
||||
};
|
||||
|
||||
chosen {
|
||||
};
|
||||
|
||||
cpus {
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
cpu0: cpu@0 {
|
||||
compatible = "sifive,bullet0", "riscv";
|
||||
device_type = "cpu";
|
||||
i-cache-block-size = <64>;
|
||||
i-cache-sets = <128>;
|
||||
i-cache-size = <16384>;
|
||||
next-level-cache = <&ccache>;
|
||||
reg = <0x0>;
|
||||
riscv,isa = "rv64imac";
|
||||
status = "disabled";
|
||||
cpu0_intc: interrupt-controller {
|
||||
#interrupt-cells = <1>;
|
||||
compatible = "riscv,cpu-intc";
|
||||
interrupt-controller;
|
||||
};
|
||||
};
|
||||
cpu1: cpu@1 {
|
||||
compatible = "sifive,bullet0", "riscv";
|
||||
d-cache-block-size = <64>;
|
||||
d-cache-sets = <64>;
|
||||
d-cache-size = <32768>;
|
||||
d-tlb-sets = <1>;
|
||||
d-tlb-size = <40>;
|
||||
device_type = "cpu";
|
||||
i-cache-block-size = <64>;
|
||||
i-cache-sets = <128>;
|
||||
i-cache-size = <32768>;
|
||||
i-tlb-sets = <1>;
|
||||
i-tlb-size = <40>;
|
||||
mmu-type = "riscv,sv39";
|
||||
next-level-cache = <&ccache>;
|
||||
reg = <0x1>;
|
||||
riscv,isa = "rv64imafdc";
|
||||
tlb-split;
|
||||
cpu1_intc: interrupt-controller {
|
||||
#interrupt-cells = <1>;
|
||||
compatible = "riscv,cpu-intc";
|
||||
interrupt-controller;
|
||||
};
|
||||
};
|
||||
cpu2: cpu@2 {
|
||||
compatible = "sifive,bullet0", "riscv";
|
||||
d-cache-block-size = <64>;
|
||||
d-cache-sets = <64>;
|
||||
d-cache-size = <32768>;
|
||||
d-tlb-sets = <1>;
|
||||
d-tlb-size = <40>;
|
||||
device_type = "cpu";
|
||||
i-cache-block-size = <64>;
|
||||
i-cache-sets = <128>;
|
||||
i-cache-size = <32768>;
|
||||
i-tlb-sets = <1>;
|
||||
i-tlb-size = <40>;
|
||||
mmu-type = "riscv,sv39";
|
||||
next-level-cache = <&ccache>;
|
||||
reg = <0x2>;
|
||||
riscv,isa = "rv64imafdc";
|
||||
tlb-split;
|
||||
cpu2_intc: interrupt-controller {
|
||||
#interrupt-cells = <1>;
|
||||
compatible = "riscv,cpu-intc";
|
||||
interrupt-controller;
|
||||
};
|
||||
};
|
||||
cpu3: cpu@3 {
|
||||
compatible = "sifive,bullet0", "riscv";
|
||||
d-cache-block-size = <64>;
|
||||
d-cache-sets = <64>;
|
||||
d-cache-size = <32768>;
|
||||
d-tlb-sets = <1>;
|
||||
d-tlb-size = <40>;
|
||||
device_type = "cpu";
|
||||
i-cache-block-size = <64>;
|
||||
i-cache-sets = <128>;
|
||||
i-cache-size = <32768>;
|
||||
i-tlb-sets = <1>;
|
||||
i-tlb-size = <40>;
|
||||
mmu-type = "riscv,sv39";
|
||||
next-level-cache = <&ccache>;
|
||||
reg = <0x3>;
|
||||
riscv,isa = "rv64imafdc";
|
||||
tlb-split;
|
||||
cpu3_intc: interrupt-controller {
|
||||
#interrupt-cells = <1>;
|
||||
compatible = "riscv,cpu-intc";
|
||||
interrupt-controller;
|
||||
};
|
||||
};
|
||||
cpu4: cpu@4 {
|
||||
compatible = "sifive,bullet0", "riscv";
|
||||
d-cache-block-size = <64>;
|
||||
d-cache-sets = <64>;
|
||||
d-cache-size = <32768>;
|
||||
d-tlb-sets = <1>;
|
||||
d-tlb-size = <40>;
|
||||
device_type = "cpu";
|
||||
i-cache-block-size = <64>;
|
||||
i-cache-sets = <128>;
|
||||
i-cache-size = <32768>;
|
||||
i-tlb-sets = <1>;
|
||||
i-tlb-size = <40>;
|
||||
mmu-type = "riscv,sv39";
|
||||
next-level-cache = <&ccache>;
|
||||
reg = <0x4>;
|
||||
riscv,isa = "rv64imafdc";
|
||||
tlb-split;
|
||||
cpu4_intc: interrupt-controller {
|
||||
#interrupt-cells = <1>;
|
||||
compatible = "riscv,cpu-intc";
|
||||
interrupt-controller;
|
||||
};
|
||||
};
|
||||
};
|
||||
soc {
|
||||
#address-cells = <2>;
|
||||
#size-cells = <2>;
|
||||
compatible = "simple-bus";
|
||||
ranges;
|
||||
plic0: interrupt-controller@c000000 {
|
||||
#interrupt-cells = <1>;
|
||||
#address-cells = <0>;
|
||||
compatible = "sifive,fu540-c000-plic", "sifive,plic-1.0.0";
|
||||
reg = <0x0 0xc000000 0x0 0x4000000>;
|
||||
riscv,ndev = <69>;
|
||||
interrupt-controller;
|
||||
interrupts-extended = <
|
||||
&cpu0_intc 0xffffffff
|
||||
&cpu1_intc 0xffffffff &cpu1_intc 9
|
||||
&cpu2_intc 0xffffffff &cpu2_intc 9
|
||||
&cpu3_intc 0xffffffff &cpu3_intc 9
|
||||
&cpu4_intc 0xffffffff &cpu4_intc 9>;
|
||||
};
|
||||
prci: clock-controller@10000000 {
|
||||
compatible = "sifive,fu740-c000-prci";
|
||||
reg = <0x0 0x10000000 0x0 0x1000>;
|
||||
clocks = <&hfclk>, <&rtcclk>;
|
||||
#clock-cells = <1>;
|
||||
};
|
||||
uart0: serial@10010000 {
|
||||
compatible = "sifive,fu740-c000-uart", "sifive,uart0";
|
||||
reg = <0x0 0x10010000 0x0 0x1000>;
|
||||
interrupt-parent = <&plic0>;
|
||||
interrupts = <39>;
|
||||
clocks = <&prci PRCI_CLK_PCLK>;
|
||||
status = "disabled";
|
||||
};
|
||||
uart1: serial@10011000 {
|
||||
compatible = "sifive,fu740-c000-uart", "sifive,uart0";
|
||||
reg = <0x0 0x10011000 0x0 0x1000>;
|
||||
interrupt-parent = <&plic0>;
|
||||
interrupts = <40>;
|
||||
clocks = <&prci PRCI_CLK_PCLK>;
|
||||
status = "disabled";
|
||||
};
|
||||
i2c0: i2c@10030000 {
|
||||
compatible = "sifive,fu740-c000-i2c", "sifive,i2c0";
|
||||
reg = <0x0 0x10030000 0x0 0x1000>;
|
||||
interrupt-parent = <&plic0>;
|
||||
interrupts = <52>;
|
||||
clocks = <&prci PRCI_CLK_PCLK>;
|
||||
reg-shift = <2>;
|
||||
reg-io-width = <1>;
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
status = "disabled";
|
||||
};
|
||||
i2c1: i2c@10031000 {
|
||||
compatible = "sifive,fu740-c000-i2c", "sifive,i2c0";
|
||||
reg = <0x0 0x10031000 0x0 0x1000>;
|
||||
interrupt-parent = <&plic0>;
|
||||
interrupts = <53>;
|
||||
clocks = <&prci PRCI_CLK_PCLK>;
|
||||
reg-shift = <2>;
|
||||
reg-io-width = <1>;
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
status = "disabled";
|
||||
};
|
||||
qspi0: spi@10040000 {
|
||||
compatible = "sifive,fu740-c000-spi", "sifive,spi0";
|
||||
reg = <0x0 0x10040000 0x0 0x1000>,
|
||||
<0x0 0x20000000 0x0 0x10000000>;
|
||||
interrupt-parent = <&plic0>;
|
||||
interrupts = <41>;
|
||||
clocks = <&prci PRCI_CLK_PCLK>;
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
status = "disabled";
|
||||
};
|
||||
qspi1: spi@10041000 {
|
||||
compatible = "sifive,fu740-c000-spi", "sifive,spi0";
|
||||
reg = <0x0 0x10041000 0x0 0x1000>,
|
||||
<0x0 0x30000000 0x0 0x10000000>;
|
||||
interrupt-parent = <&plic0>;
|
||||
interrupts = <42>;
|
||||
clocks = <&prci PRCI_CLK_PCLK>;
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
status = "disabled";
|
||||
};
|
||||
spi0: spi@10050000 {
|
||||
compatible = "sifive,fu740-c000-spi", "sifive,spi0";
|
||||
reg = <0x0 0x10050000 0x0 0x1000>;
|
||||
interrupt-parent = <&plic0>;
|
||||
interrupts = <43>;
|
||||
clocks = <&prci PRCI_CLK_PCLK>;
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
status = "disabled";
|
||||
};
|
||||
eth0: ethernet@10090000 {
|
||||
compatible = "sifive,fu540-c000-gem";
|
||||
interrupt-parent = <&plic0>;
|
||||
interrupts = <55>;
|
||||
reg = <0x0 0x10090000 0x0 0x2000>,
|
||||
<0x0 0x100a0000 0x0 0x1000>;
|
||||
local-mac-address = [00 00 00 00 00 00];
|
||||
clock-names = "pclk", "hclk";
|
||||
clocks = <&prci PRCI_CLK_GEMGXLPLL>,
|
||||
<&prci PRCI_CLK_GEMGXLPLL>;
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
status = "disabled";
|
||||
};
|
||||
pwm0: pwm@10020000 {
|
||||
compatible = "sifive,fu740-c000-pwm", "sifive,pwm0";
|
||||
reg = <0x0 0x10020000 0x0 0x1000>;
|
||||
interrupt-parent = <&plic0>;
|
||||
interrupts = <44>, <45>, <46>, <47>;
|
||||
clocks = <&prci PRCI_CLK_PCLK>;
|
||||
#pwm-cells = <3>;
|
||||
status = "disabled";
|
||||
};
|
||||
pwm1: pwm@10021000 {
|
||||
compatible = "sifive,fu740-c000-pwm", "sifive,pwm0";
|
||||
reg = <0x0 0x10021000 0x0 0x1000>;
|
||||
interrupt-parent = <&plic0>;
|
||||
interrupts = <48>, <49>, <50>, <51>;
|
||||
clocks = <&prci PRCI_CLK_PCLK>;
|
||||
#pwm-cells = <3>;
|
||||
status = "disabled";
|
||||
};
|
||||
ccache: cache-controller@2010000 {
|
||||
compatible = "sifive,fu740-c000-ccache", "cache";
|
||||
cache-block-size = <64>;
|
||||
cache-level = <2>;
|
||||
cache-sets = <2048>;
|
||||
cache-size = <2097152>;
|
||||
cache-unified;
|
||||
interrupt-parent = <&plic0>;
|
||||
interrupts = <19 20 21 22>;
|
||||
reg = <0x0 0x2010000 0x0 0x1000>;
|
||||
};
|
||||
gpio: gpio@10060000 {
|
||||
compatible = "sifive,fu740-c000-gpio", "sifive,gpio0";
|
||||
interrupt-parent = <&plic0>;
|
||||
interrupts = <23>, <24>, <25>, <26>, <27>, <28>, <29>,
|
||||
<30>, <31>, <32>, <33>, <34>, <35>, <36>,
|
||||
<37>, <38>;
|
||||
reg = <0x0 0x10060000 0x0 0x1000>;
|
||||
gpio-controller;
|
||||
#gpio-cells = <2>;
|
||||
interrupt-controller;
|
||||
#interrupt-cells = <2>;
|
||||
clocks = <&prci PRCI_CLK_PCLK>;
|
||||
status = "disabled";
|
||||
};
|
||||
};
|
||||
};
|
|
@ -0,0 +1,253 @@
|
|||
// SPDX-License-Identifier: (GPL-2.0 OR MIT)
|
||||
/* Copyright (c) 2020 SiFive, Inc */
|
||||
|
||||
#include "fu740-c000.dtsi"
|
||||
#include <dt-bindings/interrupt-controller/irq.h>
|
||||
|
||||
/* Clock frequency (in Hz) of the PCB crystal for rtcclk */
|
||||
#define RTCCLK_FREQ 1000000
|
||||
|
||||
/ {
|
||||
#address-cells = <2>;
|
||||
#size-cells = <2>;
|
||||
model = "SiFive HiFive Unmatched A00";
|
||||
compatible = "sifive,hifive-unmatched-a00", "sifive,fu740-c000",
|
||||
"sifive,fu740";
|
||||
|
||||
chosen {
|
||||
stdout-path = "serial0";
|
||||
};
|
||||
|
||||
cpus {
|
||||
timebase-frequency = <RTCCLK_FREQ>;
|
||||
};
|
||||
|
||||
memory@80000000 {
|
||||
device_type = "memory";
|
||||
reg = <0x0 0x80000000 0x2 0x00000000>;
|
||||
};
|
||||
|
||||
soc {
|
||||
};
|
||||
|
||||
hfclk: hfclk {
|
||||
#clock-cells = <0>;
|
||||
compatible = "fixed-clock";
|
||||
clock-frequency = <26000000>;
|
||||
clock-output-names = "hfclk";
|
||||
};
|
||||
|
||||
rtcclk: rtcclk {
|
||||
#clock-cells = <0>;
|
||||
compatible = "fixed-clock";
|
||||
clock-frequency = <RTCCLK_FREQ>;
|
||||
clock-output-names = "rtcclk";
|
||||
};
|
||||
};
|
||||
|
||||
&uart0 {
|
||||
status = "okay";
|
||||
};
|
||||
|
||||
&uart1 {
|
||||
status = "okay";
|
||||
};
|
||||
|
||||
&i2c0 {
|
||||
status = "okay";
|
||||
|
||||
temperature-sensor@4c {
|
||||
compatible = "ti,tmp451";
|
||||
reg = <0x4c>;
|
||||
interrupt-parent = <&gpio>;
|
||||
interrupts = <6 IRQ_TYPE_LEVEL_LOW>;
|
||||
};
|
||||
|
||||
pmic@58 {
|
||||
compatible = "dlg,da9063";
|
||||
reg = <0x58>;
|
||||
interrupt-parent = <&gpio>;
|
||||
interrupts = <1 IRQ_TYPE_LEVEL_LOW>;
|
||||
interrupt-controller;
|
||||
|
||||
regulators {
|
||||
vdd_bcore1: bcore1 {
|
||||
regulator-min-microvolt = <900000>;
|
||||
regulator-max-microvolt = <900000>;
|
||||
regulator-min-microamp = <5000000>;
|
||||
regulator-max-microamp = <5000000>;
|
||||
regulator-always-on;
|
||||
};
|
||||
|
||||
vdd_bcore2: bcore2 {
|
||||
regulator-min-microvolt = <900000>;
|
||||
regulator-max-microvolt = <900000>;
|
||||
regulator-min-microamp = <5000000>;
|
||||
regulator-max-microamp = <5000000>;
|
||||
regulator-always-on;
|
||||
};
|
||||
|
||||
vdd_bpro: bpro {
|
||||
regulator-min-microvolt = <1800000>;
|
||||
regulator-max-microvolt = <1800000>;
|
||||
regulator-min-microamp = <2500000>;
|
||||
regulator-max-microamp = <2500000>;
|
||||
regulator-always-on;
|
||||
};
|
||||
|
||||
vdd_bperi: bperi {
|
||||
regulator-min-microvolt = <1050000>;
|
||||
regulator-max-microvolt = <1050000>;
|
||||
regulator-min-microamp = <1500000>;
|
||||
regulator-max-microamp = <1500000>;
|
||||
regulator-always-on;
|
||||
};
|
||||
|
||||
vdd_bmem: bmem {
|
||||
regulator-min-microvolt = <1200000>;
|
||||
regulator-max-microvolt = <1200000>;
|
||||
regulator-min-microamp = <3000000>;
|
||||
regulator-max-microamp = <3000000>;
|
||||
regulator-always-on;
|
||||
};
|
||||
|
||||
vdd_bio: bio {
|
||||
regulator-min-microvolt = <1200000>;
|
||||
regulator-max-microvolt = <1200000>;
|
||||
regulator-min-microamp = <3000000>;
|
||||
regulator-max-microamp = <3000000>;
|
||||
regulator-always-on;
|
||||
};
|
||||
|
||||
vdd_ldo1: ldo1 {
|
||||
regulator-min-microvolt = <1800000>;
|
||||
regulator-max-microvolt = <1800000>;
|
||||
regulator-min-microamp = <100000>;
|
||||
regulator-max-microamp = <100000>;
|
||||
regulator-always-on;
|
||||
};
|
||||
|
||||
vdd_ldo2: ldo2 {
|
||||
regulator-min-microvolt = <1800000>;
|
||||
regulator-max-microvolt = <1800000>;
|
||||
regulator-min-microamp = <200000>;
|
||||
regulator-max-microamp = <200000>;
|
||||
regulator-always-on;
|
||||
};
|
||||
|
||||
vdd_ldo3: ldo3 {
|
||||
regulator-min-microvolt = <1800000>;
|
||||
regulator-max-microvolt = <1800000>;
|
||||
regulator-min-microamp = <200000>;
|
||||
regulator-max-microamp = <200000>;
|
||||
regulator-always-on;
|
||||
};
|
||||
|
||||
vdd_ldo4: ldo4 {
|
||||
regulator-min-microvolt = <1800000>;
|
||||
regulator-max-microvolt = <1800000>;
|
||||
regulator-min-microamp = <200000>;
|
||||
regulator-max-microamp = <200000>;
|
||||
regulator-always-on;
|
||||
};
|
||||
|
||||
vdd_ldo5: ldo5 {
|
||||
regulator-min-microvolt = <1800000>;
|
||||
regulator-max-microvolt = <1800000>;
|
||||
regulator-min-microamp = <100000>;
|
||||
regulator-max-microamp = <100000>;
|
||||
regulator-always-on;
|
||||
};
|
||||
|
||||
vdd_ldo6: ldo6 {
|
||||
regulator-min-microvolt = <3300000>;
|
||||
regulator-max-microvolt = <3300000>;
|
||||
regulator-min-microamp = <200000>;
|
||||
regulator-max-microamp = <200000>;
|
||||
regulator-always-on;
|
||||
};
|
||||
|
||||
vdd_ldo7: ldo7 {
|
||||
regulator-min-microvolt = <1800000>;
|
||||
regulator-max-microvolt = <1800000>;
|
||||
regulator-min-microamp = <200000>;
|
||||
regulator-max-microamp = <200000>;
|
||||
regulator-always-on;
|
||||
};
|
||||
|
||||
vdd_ldo8: ldo8 {
|
||||
regulator-min-microvolt = <1800000>;
|
||||
regulator-max-microvolt = <1800000>;
|
||||
regulator-min-microamp = <200000>;
|
||||
regulator-max-microamp = <200000>;
|
||||
regulator-always-on;
|
||||
};
|
||||
|
||||
vdd_ld09: ldo9 {
|
||||
regulator-min-microvolt = <1050000>;
|
||||
regulator-max-microvolt = <1050000>;
|
||||
regulator-min-microamp = <200000>;
|
||||
regulator-max-microamp = <200000>;
|
||||
};
|
||||
|
||||
vdd_ldo10: ldo10 {
|
||||
regulator-min-microvolt = <1000000>;
|
||||
regulator-max-microvolt = <1000000>;
|
||||
regulator-min-microamp = <300000>;
|
||||
regulator-max-microamp = <300000>;
|
||||
};
|
||||
|
||||
vdd_ldo11: ldo11 {
|
||||
regulator-min-microvolt = <2500000>;
|
||||
regulator-max-microvolt = <2500000>;
|
||||
regulator-min-microamp = <300000>;
|
||||
regulator-max-microamp = <300000>;
|
||||
regulator-always-on;
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
&qspi0 {
|
||||
status = "okay";
|
||||
flash@0 {
|
||||
compatible = "issi,is25wp256", "jedec,spi-nor";
|
||||
reg = <0>;
|
||||
spi-max-frequency = <50000000>;
|
||||
m25p,fast-read;
|
||||
spi-tx-bus-width = <4>;
|
||||
spi-rx-bus-width = <4>;
|
||||
};
|
||||
};
|
||||
|
||||
&spi0 {
|
||||
status = "okay";
|
||||
mmc@0 {
|
||||
compatible = "mmc-spi-slot";
|
||||
reg = <0>;
|
||||
spi-max-frequency = <20000000>;
|
||||
voltage-ranges = <3300 3300>;
|
||||
disable-wp;
|
||||
};
|
||||
};
|
||||
|
||||
ð0 {
|
||||
status = "okay";
|
||||
phy-mode = "gmii";
|
||||
phy-handle = <&phy0>;
|
||||
phy0: ethernet-phy@0 {
|
||||
reg = <0>;
|
||||
};
|
||||
};
|
||||
|
||||
&pwm0 {
|
||||
status = "okay";
|
||||
};
|
||||
|
||||
&pwm1 {
|
||||
status = "okay";
|
||||
};
|
||||
|
||||
&gpio {
|
||||
status = "okay";
|
||||
};
|
|
@ -1,17 +1,19 @@
|
|||
# CONFIG_CPU_ISOLATION is not set
|
||||
CONFIG_LOG_BUF_SHIFT=15
|
||||
CONFIG_LOG_BUF_SHIFT=13
|
||||
CONFIG_PRINTK_SAFE_LOG_BUF_SHIFT=12
|
||||
CONFIG_BLK_DEV_INITRD=y
|
||||
CONFIG_INITRAMFS_FORCE=y
|
||||
# CONFIG_RD_GZIP is not set
|
||||
# CONFIG_RD_BZIP2 is not set
|
||||
# CONFIG_RD_LZMA is not set
|
||||
# CONFIG_RD_XZ is not set
|
||||
# CONFIG_RD_LZO is not set
|
||||
# CONFIG_RD_LZ4 is not set
|
||||
# CONFIG_RD_ZSTD is not set
|
||||
CONFIG_CC_OPTIMIZE_FOR_SIZE=y
|
||||
# CONFIG_SYSFS_SYSCALL is not set
|
||||
# CONFIG_FHANDLE is not set
|
||||
# CONFIG_BASE_FULL is not set
|
||||
# CONFIG_FUTEX is not set
|
||||
# CONFIG_EPOLL is not set
|
||||
# CONFIG_SIGNALFD is not set
|
||||
# CONFIG_TIMERFD is not set
|
||||
|
@ -25,15 +27,17 @@ CONFIG_EMBEDDED=y
|
|||
# CONFIG_VM_EVENT_COUNTERS is not set
|
||||
# CONFIG_COMPAT_BRK is not set
|
||||
CONFIG_SLOB=y
|
||||
# CONFIG_SLAB_MERGE_DEFAULT is not set
|
||||
# CONFIG_MMU is not set
|
||||
CONFIG_SOC_KENDRYTE=y
|
||||
CONFIG_SOC_CANAAN=y
|
||||
CONFIG_SOC_CANAAN_K210_DTB_SOURCE="k210_generic"
|
||||
CONFIG_MAXPHYSMEM_2GB=y
|
||||
CONFIG_SMP=y
|
||||
CONFIG_NR_CPUS=2
|
||||
CONFIG_CMDLINE="earlycon console=ttySIF0"
|
||||
CONFIG_CMDLINE_FORCE=y
|
||||
CONFIG_JUMP_LABEL=y
|
||||
# CONFIG_SECCOMP is not set
|
||||
# CONFIG_STACKPROTECTOR is not set
|
||||
# CONFIG_GCC_PLUGINS is not set
|
||||
# CONFIG_BLOCK is not set
|
||||
CONFIG_BINFMT_FLAT=y
|
||||
# CONFIG_COREDUMP is not set
|
||||
|
@ -41,23 +45,47 @@ CONFIG_DEVTMPFS=y
|
|||
CONFIG_DEVTMPFS_MOUNT=y
|
||||
# CONFIG_FW_LOADER is not set
|
||||
# CONFIG_ALLOW_DEV_COREDUMP is not set
|
||||
# CONFIG_INPUT_KEYBOARD is not set
|
||||
# CONFIG_INPUT_MOUSE is not set
|
||||
# CONFIG_INPUT is not set
|
||||
# CONFIG_SERIO is not set
|
||||
# CONFIG_VT is not set
|
||||
# CONFIG_UNIX98_PTYS is not set
|
||||
# CONFIG_LEGACY_PTYS is not set
|
||||
# CONFIG_LDISC_AUTOLOAD is not set
|
||||
# CONFIG_HW_RANDOM is not set
|
||||
# CONFIG_DEVMEM is not set
|
||||
CONFIG_I2C=y
|
||||
# CONFIG_I2C_COMPAT is not set
|
||||
CONFIG_I2C_CHARDEV=y
|
||||
# CONFIG_I2C_HELPER_AUTO is not set
|
||||
CONFIG_I2C_DESIGNWARE_PLATFORM=y
|
||||
CONFIG_SPI=y
|
||||
# CONFIG_SPI_MEM is not set
|
||||
CONFIG_SPI_DESIGNWARE=y
|
||||
CONFIG_SPI_DW_MMIO=y
|
||||
# CONFIG_GPIO_CDEV_V1 is not set
|
||||
CONFIG_GPIO_DWAPB=y
|
||||
CONFIG_GPIO_SIFIVE=y
|
||||
CONFIG_POWER_RESET=y
|
||||
CONFIG_POWER_RESET_SYSCON=y
|
||||
# CONFIG_HWMON is not set
|
||||
# CONFIG_VGA_CONSOLE is not set
|
||||
# CONFIG_HID is not set
|
||||
# CONFIG_USB_SUPPORT is not set
|
||||
CONFIG_NEW_LEDS=y
|
||||
CONFIG_LEDS_CLASS=y
|
||||
CONFIG_LEDS_GPIO=y
|
||||
CONFIG_LEDS_USER=y
|
||||
# CONFIG_VIRTIO_MENU is not set
|
||||
# CONFIG_VHOST_MENU is not set
|
||||
# CONFIG_SURFACE_PLATFORMS is not set
|
||||
# CONFIG_FILE_LOCKING is not set
|
||||
# CONFIG_DNOTIFY is not set
|
||||
# CONFIG_INOTIFY_USER is not set
|
||||
# CONFIG_MISC_FILESYSTEMS is not set
|
||||
CONFIG_LSM="[]"
|
||||
CONFIG_PRINTK_TIME=y
|
||||
# CONFIG_SYMBOLIC_ERRNAME is not set
|
||||
# CONFIG_DEBUG_BUGVERBOSE is not set
|
||||
# CONFIG_SECTION_MISMATCH_WARN_ONLY is not set
|
||||
# CONFIG_FRAME_POINTER is not set
|
||||
# CONFIG_DEBUG_MISC is not set
|
||||
CONFIG_PANIC_ON_OOPS=y
|
||||
# CONFIG_SCHED_DEBUG is not set
|
||||
|
|
|
@ -0,0 +1,92 @@
|
|||
# CONFIG_CPU_ISOLATION is not set
|
||||
CONFIG_LOG_BUF_SHIFT=13
|
||||
CONFIG_PRINTK_SAFE_LOG_BUF_SHIFT=12
|
||||
CONFIG_CC_OPTIMIZE_FOR_SIZE=y
|
||||
# CONFIG_SYSFS_SYSCALL is not set
|
||||
# CONFIG_FHANDLE is not set
|
||||
# CONFIG_BASE_FULL is not set
|
||||
# CONFIG_FUTEX is not set
|
||||
# CONFIG_EPOLL is not set
|
||||
# CONFIG_SIGNALFD is not set
|
||||
# CONFIG_TIMERFD is not set
|
||||
# CONFIG_EVENTFD is not set
|
||||
# CONFIG_AIO is not set
|
||||
# CONFIG_IO_URING is not set
|
||||
# CONFIG_ADVISE_SYSCALLS is not set
|
||||
# CONFIG_MEMBARRIER is not set
|
||||
# CONFIG_KALLSYMS is not set
|
||||
CONFIG_EMBEDDED=y
|
||||
# CONFIG_VM_EVENT_COUNTERS is not set
|
||||
# CONFIG_COMPAT_BRK is not set
|
||||
CONFIG_SLOB=y
|
||||
# CONFIG_MMU is not set
|
||||
CONFIG_SOC_CANAAN=y
|
||||
CONFIG_SOC_CANAAN_K210_DTB_SOURCE="k210_generic"
|
||||
CONFIG_MAXPHYSMEM_2GB=y
|
||||
CONFIG_SMP=y
|
||||
CONFIG_NR_CPUS=2
|
||||
CONFIG_CMDLINE="earlycon console=ttySIF0 rootdelay=2 root=/dev/mmcblk0p1 ro"
|
||||
CONFIG_CMDLINE_FORCE=y
|
||||
# CONFIG_SECCOMP is not set
|
||||
# CONFIG_STACKPROTECTOR is not set
|
||||
# CONFIG_GCC_PLUGINS is not set
|
||||
# CONFIG_BLK_DEV_BSG is not set
|
||||
# CONFIG_MQ_IOSCHED_DEADLINE is not set
|
||||
# CONFIG_MQ_IOSCHED_KYBER is not set
|
||||
CONFIG_BINFMT_FLAT=y
|
||||
# CONFIG_COREDUMP is not set
|
||||
CONFIG_DEVTMPFS=y
|
||||
CONFIG_DEVTMPFS_MOUNT=y
|
||||
# CONFIG_FW_LOADER is not set
|
||||
# CONFIG_ALLOW_DEV_COREDUMP is not set
|
||||
# CONFIG_BLK_DEV is not set
|
||||
# CONFIG_INPUT is not set
|
||||
# CONFIG_SERIO is not set
|
||||
# CONFIG_VT is not set
|
||||
# CONFIG_LEGACY_PTYS is not set
|
||||
# CONFIG_LDISC_AUTOLOAD is not set
|
||||
# CONFIG_HW_RANDOM is not set
|
||||
# CONFIG_DEVMEM is not set
|
||||
CONFIG_I2C=y
|
||||
CONFIG_I2C_CHARDEV=y
|
||||
# CONFIG_I2C_HELPER_AUTO is not set
|
||||
CONFIG_I2C_DESIGNWARE_PLATFORM=y
|
||||
CONFIG_SPI=y
|
||||
# CONFIG_SPI_MEM is not set
|
||||
CONFIG_SPI_DESIGNWARE=y
|
||||
CONFIG_SPI_DW_MMIO=y
|
||||
# CONFIG_GPIO_CDEV_V1 is not set
|
||||
CONFIG_GPIO_DWAPB=y
|
||||
CONFIG_GPIO_SIFIVE=y
|
||||
CONFIG_POWER_RESET=y
|
||||
CONFIG_POWER_RESET_SYSCON=y
|
||||
# CONFIG_HWMON is not set
|
||||
# CONFIG_USB_SUPPORT is not set
|
||||
CONFIG_MMC=y
|
||||
# CONFIG_PWRSEQ_EMMC is not set
|
||||
# CONFIG_PWRSEQ_SIMPLE is not set
|
||||
CONFIG_MMC_SPI=y
|
||||
CONFIG_NEW_LEDS=y
|
||||
CONFIG_LEDS_CLASS=y
|
||||
CONFIG_LEDS_GPIO=y
|
||||
CONFIG_LEDS_USER=y
|
||||
# CONFIG_VIRTIO_MENU is not set
|
||||
# CONFIG_VHOST_MENU is not set
|
||||
# CONFIG_SURFACE_PLATFORMS is not set
|
||||
CONFIG_EXT2_FS=y
|
||||
# CONFIG_FILE_LOCKING is not set
|
||||
# CONFIG_DNOTIFY is not set
|
||||
# CONFIG_INOTIFY_USER is not set
|
||||
# CONFIG_MISC_FILESYSTEMS is not set
|
||||
CONFIG_LSM="[]"
|
||||
CONFIG_PRINTK_TIME=y
|
||||
# CONFIG_SYMBOLIC_ERRNAME is not set
|
||||
# CONFIG_DEBUG_BUGVERBOSE is not set
|
||||
# CONFIG_SECTION_MISMATCH_WARN_ONLY is not set
|
||||
# CONFIG_FRAME_POINTER is not set
|
||||
# CONFIG_DEBUG_MISC is not set
|
||||
CONFIG_PANIC_ON_OOPS=y
|
||||
# CONFIG_SCHED_DEBUG is not set
|
||||
# CONFIG_RCU_TRACE is not set
|
||||
# CONFIG_FTRACE is not set
|
||||
# CONFIG_RUNTIME_TESTING_MENU is not set
|
|
@ -85,6 +85,7 @@ do { \
|
|||
struct pt_regs;
|
||||
struct task_struct;
|
||||
|
||||
void __show_regs(struct pt_regs *regs);
|
||||
void die(struct pt_regs *regs, const char *str);
|
||||
void do_trap(struct pt_regs *regs, int signo, int code, unsigned long addr);
|
||||
|
||||
|
|
|
@ -41,10 +41,16 @@
|
|||
#define SATP_PPN _AC(0x003FFFFF, UL)
|
||||
#define SATP_MODE_32 _AC(0x80000000, UL)
|
||||
#define SATP_MODE SATP_MODE_32
|
||||
#define SATP_ASID_BITS 9
|
||||
#define SATP_ASID_SHIFT 22
|
||||
#define SATP_ASID_MASK _AC(0x1FF, UL)
|
||||
#else
|
||||
#define SATP_PPN _AC(0x00000FFFFFFFFFFF, UL)
|
||||
#define SATP_MODE_39 _AC(0x8000000000000000, UL)
|
||||
#define SATP_MODE SATP_MODE_39
|
||||
#define SATP_ASID_BITS 16
|
||||
#define SATP_ASID_SHIFT 44
|
||||
#define SATP_ASID_MASK _AC(0xFFFF, UL)
|
||||
#endif
|
||||
|
||||
/* Exception cause high bit - is an interrupt if set */
|
||||
|
|
|
@ -8,12 +8,28 @@
|
|||
|
||||
#ifdef CONFIG_KASAN
|
||||
|
||||
/*
|
||||
* The following comment was copied from arm64:
|
||||
* KASAN_SHADOW_START: beginning of the kernel virtual addresses.
|
||||
* KASAN_SHADOW_END: KASAN_SHADOW_START + 1/N of kernel virtual addresses,
|
||||
* where N = (1 << KASAN_SHADOW_SCALE_SHIFT).
|
||||
*
|
||||
* KASAN_SHADOW_OFFSET:
|
||||
* This value is used to map an address to the corresponding shadow
|
||||
* address by the following formula:
|
||||
* shadow_addr = (address >> KASAN_SHADOW_SCALE_SHIFT) + KASAN_SHADOW_OFFSET
|
||||
*
|
||||
* (1 << (64 - KASAN_SHADOW_SCALE_SHIFT)) shadow addresses that lie in range
|
||||
* [KASAN_SHADOW_OFFSET, KASAN_SHADOW_END) cover all 64-bits of virtual
|
||||
* addresses. So KASAN_SHADOW_OFFSET should satisfy the following equation:
|
||||
* KASAN_SHADOW_OFFSET = KASAN_SHADOW_END -
|
||||
* (1ULL << (64 - KASAN_SHADOW_SCALE_SHIFT))
|
||||
*/
|
||||
#define KASAN_SHADOW_SCALE_SHIFT 3
|
||||
|
||||
#define KASAN_SHADOW_SIZE (UL(1) << (38 - KASAN_SHADOW_SCALE_SHIFT))
|
||||
#define KASAN_SHADOW_START KERN_VIRT_START /* 2^64 - 2^38 */
|
||||
#define KASAN_SHADOW_SIZE (UL(1) << ((CONFIG_VA_BITS - 1) - KASAN_SHADOW_SCALE_SHIFT))
|
||||
#define KASAN_SHADOW_START KERN_VIRT_START
|
||||
#define KASAN_SHADOW_END (KASAN_SHADOW_START + KASAN_SHADOW_SIZE)
|
||||
|
||||
#define KASAN_SHADOW_OFFSET (KASAN_SHADOW_END - (1ULL << \
|
||||
(64 - KASAN_SHADOW_SCALE_SHIFT)))
|
||||
|
||||
|
|
|
@ -11,4 +11,44 @@
|
|||
|
||||
#include <asm-generic/kprobes.h>
|
||||
|
||||
#ifdef CONFIG_KPROBES
|
||||
#include <linux/types.h>
|
||||
#include <linux/ptrace.h>
|
||||
#include <linux/percpu.h>
|
||||
|
||||
#define __ARCH_WANT_KPROBES_INSN_SLOT
|
||||
#define MAX_INSN_SIZE 2
|
||||
|
||||
#define flush_insn_slot(p) do { } while (0)
|
||||
#define kretprobe_blacklist_size 0
|
||||
|
||||
#include <asm/probes.h>
|
||||
|
||||
struct prev_kprobe {
|
||||
struct kprobe *kp;
|
||||
unsigned int status;
|
||||
};
|
||||
|
||||
/* Single step context for kprobe */
|
||||
struct kprobe_step_ctx {
|
||||
unsigned long ss_pending;
|
||||
unsigned long match_addr;
|
||||
};
|
||||
|
||||
/* per-cpu kprobe control block */
|
||||
struct kprobe_ctlblk {
|
||||
unsigned int kprobe_status;
|
||||
unsigned long saved_status;
|
||||
struct prev_kprobe prev_kprobe;
|
||||
struct kprobe_step_ctx ss_ctx;
|
||||
};
|
||||
|
||||
void arch_remove_kprobe(struct kprobe *p);
|
||||
int kprobe_fault_handler(struct pt_regs *regs, unsigned int trapnr);
|
||||
bool kprobe_breakpoint_handler(struct pt_regs *regs);
|
||||
bool kprobe_single_step_handler(struct pt_regs *regs);
|
||||
void kretprobe_trampoline(void);
|
||||
void __kprobes *trampoline_probe_handler(struct pt_regs *regs);
|
||||
|
||||
#endif /* CONFIG_KPROBES */
|
||||
#endif /* _ASM_RISCV_KPROBES_H */
|
||||
|
|
|
@ -12,6 +12,8 @@
|
|||
typedef struct {
|
||||
#ifndef CONFIG_MMU
|
||||
unsigned long end_brk;
|
||||
#else
|
||||
atomic_long_t id;
|
||||
#endif
|
||||
void *vdso;
|
||||
#ifdef CONFIG_SMP
|
||||
|
|
|
@ -23,6 +23,16 @@ static inline void activate_mm(struct mm_struct *prev,
|
|||
switch_mm(prev, next, NULL);
|
||||
}
|
||||
|
||||
#define init_new_context init_new_context
|
||||
static inline int init_new_context(struct task_struct *tsk,
|
||||
struct mm_struct *mm)
|
||||
{
|
||||
#ifdef CONFIG_MMU
|
||||
atomic_long_set(&mm->context.id, 0);
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
|
||||
#include <asm-generic/mmu_context.h>
|
||||
|
||||
#endif /* _ASM_RISCV_MMU_CONTEXT_H */
|
||||
|
|
|
@ -0,0 +1,13 @@
|
|||
/* SPDX-License-Identifier: GPL-2.0 */
|
||||
#ifndef __ASM_MMZONE_H
|
||||
#define __ASM_MMZONE_H
|
||||
|
||||
#ifdef CONFIG_NUMA
|
||||
|
||||
#include <asm/numa.h>
|
||||
|
||||
extern struct pglist_data *node_data[];
|
||||
#define NODE_DATA(nid) (node_data[(nid)])
|
||||
|
||||
#endif /* CONFIG_NUMA */
|
||||
#endif /* __ASM_MMZONE_H */
|
|
@ -0,0 +1,8 @@
|
|||
/* SPDX-License-Identifier: GPL-2.0 */
|
||||
#ifndef __ASM_NUMA_H
|
||||
#define __ASM_NUMA_H
|
||||
|
||||
#include <asm/topology.h>
|
||||
#include <asm-generic/numa.h>
|
||||
|
||||
#endif /* __ASM_NUMA_H */
|
|
@ -97,9 +97,6 @@ extern unsigned long pfn_base;
|
|||
#define ARCH_PFN_OFFSET (PAGE_OFFSET >> PAGE_SHIFT)
|
||||
#endif /* CONFIG_MMU */
|
||||
|
||||
extern unsigned long max_low_pfn;
|
||||
extern unsigned long min_low_pfn;
|
||||
|
||||
#define __pa_to_va_nodebug(x) ((void *)((unsigned long) (x) + va_pa_offset))
|
||||
#define __va_to_pa_nodebug(x) ((unsigned long)(x) - va_pa_offset)
|
||||
|
||||
|
|
|
@ -32,6 +32,20 @@ static inline int pci_proc_domain(struct pci_bus *bus)
|
|||
/* always show the domain in /proc */
|
||||
return 1;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_NUMA
|
||||
|
||||
static inline int pcibus_to_node(struct pci_bus *bus)
|
||||
{
|
||||
return dev_to_node(&bus->dev);
|
||||
}
|
||||
#ifndef cpumask_of_pcibus
|
||||
#define cpumask_of_pcibus(bus) (pcibus_to_node(bus) == -1 ? \
|
||||
cpu_all_mask : \
|
||||
cpumask_of_node(pcibus_to_node(bus)))
|
||||
#endif
|
||||
#endif /* CONFIG_NUMA */
|
||||
|
||||
#endif /* CONFIG_PCI */
|
||||
|
||||
#endif /* _ASM_RISCV_PCI_H */
|
||||
|
|
|
@ -186,6 +186,11 @@ static inline unsigned long pmd_page_vaddr(pmd_t pmd)
|
|||
return (unsigned long)pfn_to_virt(pmd_val(pmd) >> _PAGE_PFN_SHIFT);
|
||||
}
|
||||
|
||||
static inline pte_t pmd_pte(pmd_t pmd)
|
||||
{
|
||||
return __pte(pmd_val(pmd));
|
||||
}
|
||||
|
||||
/* Yields the page frame number (PFN) of a page table entry */
|
||||
static inline unsigned long pte_pfn(pte_t pte)
|
||||
{
|
||||
|
@ -289,6 +294,21 @@ static inline pte_t pte_mkhuge(pte_t pte)
|
|||
return pte;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_NUMA_BALANCING
|
||||
/*
|
||||
* See the comment in include/asm-generic/pgtable.h
|
||||
*/
|
||||
static inline int pte_protnone(pte_t pte)
|
||||
{
|
||||
return (pte_val(pte) & (_PAGE_PRESENT | _PAGE_PROT_NONE)) == _PAGE_PROT_NONE;
|
||||
}
|
||||
|
||||
static inline int pmd_protnone(pmd_t pmd)
|
||||
{
|
||||
return pte_protnone(pmd_pte(pmd));
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Modify page protection bits */
|
||||
static inline pte_t pte_modify(pte_t pte, pgprot_t newprot)
|
||||
{
|
||||
|
@ -468,6 +488,7 @@ extern void *dtb_early_va;
|
|||
extern uintptr_t dtb_early_pa;
|
||||
void setup_bootmem(void);
|
||||
void paging_init(void);
|
||||
void misc_mem_init(void);
|
||||
|
||||
#define FIRST_USER_ADDRESS 0
|
||||
|
||||
|
|
|
@ -0,0 +1,24 @@
|
|||
/* SPDX-License-Identifier: GPL-2.0 */
|
||||
|
||||
#ifndef _ASM_RISCV_PROBES_H
|
||||
#define _ASM_RISCV_PROBES_H
|
||||
|
||||
typedef u32 probe_opcode_t;
|
||||
typedef bool (probes_handler_t) (u32 opcode, unsigned long addr, struct pt_regs *);
|
||||
|
||||
/* architecture specific copy of original instruction */
|
||||
struct arch_probe_insn {
|
||||
probe_opcode_t *insn;
|
||||
probes_handler_t *handler;
|
||||
/* restore address after simulation */
|
||||
unsigned long restore;
|
||||
};
|
||||
|
||||
#ifdef CONFIG_KPROBES
|
||||
typedef u32 kprobe_opcode_t;
|
||||
struct arch_specific_insn {
|
||||
struct arch_probe_insn api;
|
||||
};
|
||||
#endif
|
||||
|
||||
#endif /* _ASM_RISCV_PROBES_H */
|
|
@ -34,6 +34,7 @@ struct thread_struct {
|
|||
unsigned long sp; /* Kernel mode stack */
|
||||
unsigned long s[12]; /* s[0]: frame pointer */
|
||||
struct __riscv_d_ext_state fstate;
|
||||
unsigned long bad_cause;
|
||||
};
|
||||
|
||||
#define INIT_THREAD { \
|
||||
|
|
|
@ -8,6 +8,7 @@
|
|||
|
||||
#include <uapi/asm/ptrace.h>
|
||||
#include <asm/csr.h>
|
||||
#include <linux/compiler.h>
|
||||
|
||||
#ifndef __ASSEMBLY__
|
||||
|
||||
|
@ -60,6 +61,7 @@ struct pt_regs {
|
|||
|
||||
#define user_mode(regs) (((regs)->status & SR_PP) == 0)
|
||||
|
||||
#define MAX_REG_OFFSET offsetof(struct pt_regs, orig_a0)
|
||||
|
||||
/* Helpers for working with the instruction pointer */
|
||||
static inline unsigned long instruction_pointer(struct pt_regs *regs)
|
||||
|
@ -85,6 +87,12 @@ static inline void user_stack_pointer_set(struct pt_regs *regs,
|
|||
regs->sp = val;
|
||||
}
|
||||
|
||||
/* Valid only for Kernel mode traps. */
|
||||
static inline unsigned long kernel_stack_pointer(struct pt_regs *regs)
|
||||
{
|
||||
return regs->sp;
|
||||
}
|
||||
|
||||
/* Helpers for working with the frame pointer */
|
||||
static inline unsigned long frame_pointer(struct pt_regs *regs)
|
||||
{
|
||||
|
@ -101,6 +109,33 @@ static inline unsigned long regs_return_value(struct pt_regs *regs)
|
|||
return regs->a0;
|
||||
}
|
||||
|
||||
static inline void regs_set_return_value(struct pt_regs *regs,
|
||||
unsigned long val)
|
||||
{
|
||||
regs->a0 = val;
|
||||
}
|
||||
|
||||
extern int regs_query_register_offset(const char *name);
|
||||
extern unsigned long regs_get_kernel_stack_nth(struct pt_regs *regs,
|
||||
unsigned int n);
|
||||
|
||||
/**
|
||||
* regs_get_register() - get register value from its offset
|
||||
* @regs: pt_regs from which register value is gotten
|
||||
* @offset: offset of the register.
|
||||
*
|
||||
* regs_get_register returns the value of a register whose offset from @regs.
|
||||
* The @offset is the offset of the register in struct pt_regs.
|
||||
* If @offset is bigger than MAX_REG_OFFSET, this returns 0.
|
||||
*/
|
||||
static inline unsigned long regs_get_register(struct pt_regs *regs,
|
||||
unsigned int offset)
|
||||
{
|
||||
if (unlikely(offset > MAX_REG_OFFSET))
|
||||
return 0;
|
||||
|
||||
return *(unsigned long *)((unsigned long)regs + offset);
|
||||
}
|
||||
#endif /* __ASSEMBLY__ */
|
||||
|
||||
#endif /* _ASM_RISCV_PTRACE_H */
|
||||
|
|
|
@ -89,7 +89,7 @@ struct sbiret {
|
|||
long value;
|
||||
};
|
||||
|
||||
int sbi_init(void);
|
||||
void sbi_init(void);
|
||||
struct sbiret sbi_ecall(int ext, int fid, unsigned long arg0,
|
||||
unsigned long arg1, unsigned long arg2,
|
||||
unsigned long arg3, unsigned long arg4,
|
||||
|
@ -100,13 +100,13 @@ int sbi_console_getchar(void);
|
|||
void sbi_set_timer(uint64_t stime_value);
|
||||
void sbi_shutdown(void);
|
||||
void sbi_clear_ipi(void);
|
||||
void sbi_send_ipi(const unsigned long *hart_mask);
|
||||
void sbi_remote_fence_i(const unsigned long *hart_mask);
|
||||
void sbi_remote_sfence_vma(const unsigned long *hart_mask,
|
||||
int sbi_send_ipi(const unsigned long *hart_mask);
|
||||
int sbi_remote_fence_i(const unsigned long *hart_mask);
|
||||
int sbi_remote_sfence_vma(const unsigned long *hart_mask,
|
||||
unsigned long start,
|
||||
unsigned long size);
|
||||
|
||||
void sbi_remote_sfence_vma_asid(const unsigned long *hart_mask,
|
||||
int sbi_remote_sfence_vma_asid(const unsigned long *hart_mask,
|
||||
unsigned long start,
|
||||
unsigned long size,
|
||||
unsigned long asid);
|
||||
|
@ -147,11 +147,7 @@ static inline unsigned long sbi_minor_version(void)
|
|||
|
||||
int sbi_err_map_linux_errno(int err);
|
||||
#else /* CONFIG_RISCV_SBI */
|
||||
/* stubs for code that is only reachable under IS_ENABLED(CONFIG_RISCV_SBI): */
|
||||
void sbi_set_timer(uint64_t stime_value);
|
||||
void sbi_clear_ipi(void);
|
||||
void sbi_send_ipi(const unsigned long *hart_mask);
|
||||
void sbi_remote_fence_i(const unsigned long *hart_mask);
|
||||
void sbi_init(void);
|
||||
static inline int sbi_remote_fence_i(const unsigned long *hart_mask) { return -1; }
|
||||
static inline void sbi_init(void) {}
|
||||
#endif /* CONFIG_RISCV_SBI */
|
||||
#endif /* _ASM_RISCV_SBI_H */
|
||||
|
|
|
@ -22,7 +22,7 @@ static inline int set_memory_ro(unsigned long addr, int numpages) { return 0; }
|
|||
static inline int set_memory_rw(unsigned long addr, int numpages) { return 0; }
|
||||
static inline int set_memory_x(unsigned long addr, int numpages) { return 0; }
|
||||
static inline int set_memory_nx(unsigned long addr, int numpages) { return 0; }
|
||||
static inline void protect_kernel_text_data(void) {};
|
||||
static inline void protect_kernel_text_data(void) {}
|
||||
static inline int set_memory_rw_nx(unsigned long addr, int numpages) { return 0; }
|
||||
#endif
|
||||
|
||||
|
|
|
@ -21,42 +21,4 @@ void soc_early_init(void);
|
|||
extern unsigned long __soc_early_init_table_start;
|
||||
extern unsigned long __soc_early_init_table_end;
|
||||
|
||||
/*
|
||||
* Allows Linux to provide a device tree, which is necessary for SOCs that
|
||||
* don't provide a useful one on their own.
|
||||
*/
|
||||
struct soc_builtin_dtb {
|
||||
unsigned long vendor_id;
|
||||
unsigned long arch_id;
|
||||
unsigned long imp_id;
|
||||
void *(*dtb_func)(void);
|
||||
};
|
||||
|
||||
/*
|
||||
* The argument name must specify a valid DTS file name without the dts
|
||||
* extension.
|
||||
*/
|
||||
#define SOC_BUILTIN_DTB_DECLARE(name, vendor, arch, impl) \
|
||||
extern void *__dtb_##name##_begin; \
|
||||
\
|
||||
static __init __used \
|
||||
void *__soc_builtin_dtb_f__##name(void) \
|
||||
{ \
|
||||
return (void *)&__dtb_##name##_begin; \
|
||||
} \
|
||||
\
|
||||
static const struct soc_builtin_dtb __soc_builtin_dtb__##name \
|
||||
__used __section("__soc_builtin_dtb_table") = \
|
||||
{ \
|
||||
.vendor_id = vendor, \
|
||||
.arch_id = arch, \
|
||||
.imp_id = impl, \
|
||||
.dtb_func = __soc_builtin_dtb_f__##name, \
|
||||
}
|
||||
|
||||
extern unsigned long __soc_builtin_dtb_table_start;
|
||||
extern unsigned long __soc_builtin_dtb_table_end;
|
||||
|
||||
void *soc_lookup_builtin_dtb(void);
|
||||
|
||||
#endif
|
||||
|
|
|
@ -24,6 +24,7 @@ static __always_inline void boot_init_stack_canary(void)
|
|||
canary &= CANARY_MASK;
|
||||
|
||||
current->stack_canary = canary;
|
||||
__stack_chk_guard = current->stack_canary;
|
||||
if (!IS_ENABLED(CONFIG_STACKPROTECTOR_PER_TASK))
|
||||
__stack_chk_guard = current->stack_canary;
|
||||
}
|
||||
#endif /* _ASM_RISCV_STACKPROTECTOR_H */
|
||||
|
|
|
@ -13,5 +13,7 @@ struct stackframe {
|
|||
|
||||
extern void notrace walk_stackframe(struct task_struct *task, struct pt_regs *regs,
|
||||
bool (*fn)(void *, unsigned long), void *arg);
|
||||
extern void dump_backtrace(struct pt_regs *regs, struct task_struct *task,
|
||||
const char *loglvl);
|
||||
|
||||
#endif /* _ASM_RISCV_STACKTRACE_H */
|
||||
|
|
|
@ -75,6 +75,7 @@ struct thread_info {
|
|||
#define TIF_SYSCALL_AUDIT 7 /* syscall auditing */
|
||||
#define TIF_SECCOMP 8 /* syscall secure computing */
|
||||
#define TIF_NOTIFY_SIGNAL 9 /* signal notifications exist */
|
||||
#define TIF_UPROBE 10 /* uprobe breakpoint or singlestep */
|
||||
|
||||
#define _TIF_SYSCALL_TRACE (1 << TIF_SYSCALL_TRACE)
|
||||
#define _TIF_NOTIFY_RESUME (1 << TIF_NOTIFY_RESUME)
|
||||
|
@ -84,10 +85,11 @@ struct thread_info {
|
|||
#define _TIF_SYSCALL_AUDIT (1 << TIF_SYSCALL_AUDIT)
|
||||
#define _TIF_SECCOMP (1 << TIF_SECCOMP)
|
||||
#define _TIF_NOTIFY_SIGNAL (1 << TIF_NOTIFY_SIGNAL)
|
||||
#define _TIF_UPROBE (1 << TIF_UPROBE)
|
||||
|
||||
#define _TIF_WORK_MASK \
|
||||
(_TIF_NOTIFY_RESUME | _TIF_SIGPENDING | _TIF_NEED_RESCHED | \
|
||||
_TIF_NOTIFY_SIGNAL)
|
||||
_TIF_NOTIFY_SIGNAL | _TIF_UPROBE)
|
||||
|
||||
#define _TIF_SYSCALL_WORK \
|
||||
(_TIF_SYSCALL_TRACE | _TIF_SYSCALL_TRACEPOINT | _TIF_SYSCALL_AUDIT | \
|
||||
|
|
|
@ -0,0 +1,40 @@
|
|||
/* SPDX-License-Identifier: GPL-2.0-only */
|
||||
|
||||
#ifndef _ASM_RISCV_UPROBES_H
|
||||
#define _ASM_RISCV_UPROBES_H
|
||||
|
||||
#include <asm/probes.h>
|
||||
#include <asm/patch.h>
|
||||
#include <asm/bug.h>
|
||||
|
||||
#define MAX_UINSN_BYTES 8
|
||||
|
||||
#ifdef CONFIG_RISCV_ISA_C
|
||||
#define UPROBE_SWBP_INSN __BUG_INSN_16
|
||||
#define UPROBE_SWBP_INSN_SIZE 2
|
||||
#else
|
||||
#define UPROBE_SWBP_INSN __BUG_INSN_32
|
||||
#define UPROBE_SWBP_INSN_SIZE 4
|
||||
#endif
|
||||
#define UPROBE_XOL_SLOT_BYTES MAX_UINSN_BYTES
|
||||
|
||||
typedef u32 uprobe_opcode_t;
|
||||
|
||||
struct arch_uprobe_task {
|
||||
unsigned long saved_cause;
|
||||
};
|
||||
|
||||
struct arch_uprobe {
|
||||
union {
|
||||
u8 insn[MAX_UINSN_BYTES];
|
||||
u8 ixol[MAX_UINSN_BYTES];
|
||||
};
|
||||
struct arch_probe_insn api;
|
||||
unsigned long insn_size;
|
||||
bool simulate;
|
||||
};
|
||||
|
||||
bool uprobe_breakpoint_handler(struct pt_regs *regs);
|
||||
bool uprobe_single_step_handler(struct pt_regs *regs);
|
||||
|
||||
#endif /* _ASM_RISCV_UPROBES_H */
|
|
@ -4,8 +4,9 @@
|
|||
#
|
||||
|
||||
ifdef CONFIG_FTRACE
|
||||
CFLAGS_REMOVE_ftrace.o = -pg
|
||||
CFLAGS_REMOVE_patch.o = -pg
|
||||
CFLAGS_REMOVE_ftrace.o = $(CC_FLAGS_FTRACE)
|
||||
CFLAGS_REMOVE_patch.o = $(CC_FLAGS_FTRACE)
|
||||
CFLAGS_REMOVE_sbi.o = $(CC_FLAGS_FTRACE)
|
||||
endif
|
||||
|
||||
extra-y += head.o
|
||||
|
@ -29,6 +30,7 @@ obj-y += riscv_ksyms.o
|
|||
obj-y += stacktrace.o
|
||||
obj-y += cacheinfo.o
|
||||
obj-y += patch.o
|
||||
obj-y += probes/
|
||||
obj-$(CONFIG_MMU) += vdso.o vdso/
|
||||
|
||||
obj-$(CONFIG_RISCV_M_MODE) += traps_misaligned.o
|
||||
|
|
|
@ -68,6 +68,9 @@ void asm_offsets(void)
|
|||
OFFSET(TASK_THREAD_F30, task_struct, thread.fstate.f[30]);
|
||||
OFFSET(TASK_THREAD_F31, task_struct, thread.fstate.f[31]);
|
||||
OFFSET(TASK_THREAD_FCSR, task_struct, thread.fstate.fcsr);
|
||||
#ifdef CONFIG_STACKPROTECTOR
|
||||
OFFSET(TSK_STACK_CANARY, task_struct, stack_canary);
|
||||
#endif
|
||||
|
||||
DEFINE(PT_SIZE, sizeof(struct pt_regs));
|
||||
OFFSET(PT_EPC, pt_regs, epc);
|
||||
|
|
|
@ -72,29 +72,56 @@ static int __ftrace_modify_call(unsigned long hook_pos, unsigned long target,
|
|||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Put 5 instructions with 16 bytes at the front of function within
|
||||
* patchable function entry nops' area.
|
||||
*
|
||||
* 0: REG_S ra, -SZREG(sp)
|
||||
* 1: auipc ra, 0x?
|
||||
* 2: jalr -?(ra)
|
||||
* 3: REG_L ra, -SZREG(sp)
|
||||
*
|
||||
* So the opcodes is:
|
||||
* 0: 0xfe113c23 (sd)/0xfe112e23 (sw)
|
||||
* 1: 0x???????? -> auipc
|
||||
* 2: 0x???????? -> jalr
|
||||
* 3: 0xff813083 (ld)/0xffc12083 (lw)
|
||||
*/
|
||||
#if __riscv_xlen == 64
|
||||
#define INSN0 0xfe113c23
|
||||
#define INSN3 0xff813083
|
||||
#elif __riscv_xlen == 32
|
||||
#define INSN0 0xfe112e23
|
||||
#define INSN3 0xffc12083
|
||||
#endif
|
||||
|
||||
#define FUNC_ENTRY_SIZE 16
|
||||
#define FUNC_ENTRY_JMP 4
|
||||
|
||||
int ftrace_make_call(struct dyn_ftrace *rec, unsigned long addr)
|
||||
{
|
||||
int ret = ftrace_check_current_call(rec->ip, NULL);
|
||||
unsigned int call[4] = {INSN0, 0, 0, INSN3};
|
||||
unsigned long target = addr;
|
||||
unsigned long caller = rec->ip + FUNC_ENTRY_JMP;
|
||||
|
||||
if (ret)
|
||||
return ret;
|
||||
call[1] = to_auipc_insn((unsigned int)(target - caller));
|
||||
call[2] = to_jalr_insn((unsigned int)(target - caller));
|
||||
|
||||
return __ftrace_modify_call(rec->ip, addr, true);
|
||||
if (patch_text_nosync((void *)rec->ip, call, FUNC_ENTRY_SIZE))
|
||||
return -EPERM;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int ftrace_make_nop(struct module *mod, struct dyn_ftrace *rec,
|
||||
unsigned long addr)
|
||||
{
|
||||
unsigned int call[2];
|
||||
int ret;
|
||||
unsigned int nops[4] = {NOP4, NOP4, NOP4, NOP4};
|
||||
|
||||
make_call(rec->ip, addr, call);
|
||||
ret = ftrace_check_current_call(rec->ip, call);
|
||||
if (patch_text_nosync((void *)rec->ip, nops, FUNC_ENTRY_SIZE))
|
||||
return -EPERM;
|
||||
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
return __ftrace_modify_call(rec->ip, addr, false);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
|
@ -139,15 +166,16 @@ int ftrace_modify_call(struct dyn_ftrace *rec, unsigned long old_addr,
|
|||
unsigned long addr)
|
||||
{
|
||||
unsigned int call[2];
|
||||
unsigned long caller = rec->ip + FUNC_ENTRY_JMP;
|
||||
int ret;
|
||||
|
||||
make_call(rec->ip, old_addr, call);
|
||||
ret = ftrace_check_current_call(rec->ip, call);
|
||||
make_call(caller, old_addr, call);
|
||||
ret = ftrace_check_current_call(caller, call);
|
||||
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
return __ftrace_modify_call(rec->ip, addr, true);
|
||||
return __ftrace_modify_call(caller, addr, true);
|
||||
}
|
||||
#endif
|
||||
|
||||
|
@ -176,53 +204,30 @@ void prepare_ftrace_return(unsigned long *parent, unsigned long self_addr,
|
|||
|
||||
#ifdef CONFIG_DYNAMIC_FTRACE
|
||||
extern void ftrace_graph_call(void);
|
||||
extern void ftrace_graph_regs_call(void);
|
||||
int ftrace_enable_ftrace_graph_caller(void)
|
||||
{
|
||||
unsigned int call[2];
|
||||
static int init_graph = 1;
|
||||
int ret;
|
||||
|
||||
make_call(&ftrace_graph_call, &ftrace_stub, call);
|
||||
|
||||
/*
|
||||
* When enabling graph tracer for the first time, ftrace_graph_call
|
||||
* should contains a call to ftrace_stub. Once it has been disabled,
|
||||
* the 8-bytes at the position becomes NOPs.
|
||||
*/
|
||||
if (init_graph) {
|
||||
ret = ftrace_check_current_call((unsigned long)&ftrace_graph_call,
|
||||
call);
|
||||
init_graph = 0;
|
||||
} else {
|
||||
ret = ftrace_check_current_call((unsigned long)&ftrace_graph_call,
|
||||
NULL);
|
||||
}
|
||||
|
||||
ret = __ftrace_modify_call((unsigned long)&ftrace_graph_call,
|
||||
(unsigned long)&prepare_ftrace_return, true);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
return __ftrace_modify_call((unsigned long)&ftrace_graph_call,
|
||||
return __ftrace_modify_call((unsigned long)&ftrace_graph_regs_call,
|
||||
(unsigned long)&prepare_ftrace_return, true);
|
||||
}
|
||||
|
||||
int ftrace_disable_ftrace_graph_caller(void)
|
||||
{
|
||||
unsigned int call[2];
|
||||
int ret;
|
||||
|
||||
make_call(&ftrace_graph_call, &prepare_ftrace_return, call);
|
||||
|
||||
/*
|
||||
* This is to make sure that ftrace_enable_ftrace_graph_caller
|
||||
* did the right thing.
|
||||
*/
|
||||
ret = ftrace_check_current_call((unsigned long)&ftrace_graph_call,
|
||||
call);
|
||||
|
||||
ret = __ftrace_modify_call((unsigned long)&ftrace_graph_call,
|
||||
(unsigned long)&prepare_ftrace_return, false);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
return __ftrace_modify_call((unsigned long)&ftrace_graph_call,
|
||||
return __ftrace_modify_call((unsigned long)&ftrace_graph_regs_call,
|
||||
(unsigned long)&prepare_ftrace_return, false);
|
||||
}
|
||||
#endif /* CONFIG_DYNAMIC_FTRACE */
|
||||
|
|
|
@ -260,7 +260,11 @@ clear_bss_done:
|
|||
|
||||
/* Initialize page tables and relocate to virtual addresses */
|
||||
la sp, init_thread_union + THREAD_SIZE
|
||||
#ifdef CONFIG_BUILTIN_DTB
|
||||
la a0, __dtb_start
|
||||
#else
|
||||
mv a0, s1
|
||||
#endif /* CONFIG_BUILTIN_DTB */
|
||||
call setup_vm
|
||||
#ifdef CONFIG_MMU
|
||||
la a0, early_pg_dir
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
* Copyright (C) 2020 Western Digital Corporation or its affiliates.
|
||||
* Linker script variables to be set after section resolution, as
|
||||
* ld.lld does not like variables assigned before SECTIONS is processed.
|
||||
* Based on arch/arm64/kerne/image-vars.h
|
||||
* Based on arch/arm64/kernel/image-vars.h
|
||||
*/
|
||||
#ifndef __RISCV_KERNEL_IMAGE_VARS_H
|
||||
#define __RISCV_KERNEL_IMAGE_VARS_H
|
||||
|
|
|
@ -13,224 +13,186 @@
|
|||
|
||||
.text
|
||||
|
||||
.macro SAVE_ABI_STATE
|
||||
#ifdef CONFIG_FUNCTION_GRAPH_TRACER
|
||||
addi sp, sp, -48
|
||||
sd s0, 32(sp)
|
||||
sd ra, 40(sp)
|
||||
addi s0, sp, 48
|
||||
sd t0, 24(sp)
|
||||
sd t1, 16(sp)
|
||||
#ifdef HAVE_FUNCTION_GRAPH_FP_TEST
|
||||
sd t2, 8(sp)
|
||||
#endif
|
||||
#else
|
||||
addi sp, sp, -16
|
||||
sd s0, 0(sp)
|
||||
sd ra, 8(sp)
|
||||
addi s0, sp, 16
|
||||
#endif
|
||||
#define FENTRY_RA_OFFSET 12
|
||||
#define ABI_SIZE_ON_STACK 72
|
||||
#define ABI_A0 0
|
||||
#define ABI_A1 8
|
||||
#define ABI_A2 16
|
||||
#define ABI_A3 24
|
||||
#define ABI_A4 32
|
||||
#define ABI_A5 40
|
||||
#define ABI_A6 48
|
||||
#define ABI_A7 56
|
||||
#define ABI_RA 64
|
||||
|
||||
.macro SAVE_ABI
|
||||
addi sp, sp, -SZREG
|
||||
addi sp, sp, -ABI_SIZE_ON_STACK
|
||||
|
||||
REG_S a0, ABI_A0(sp)
|
||||
REG_S a1, ABI_A1(sp)
|
||||
REG_S a2, ABI_A2(sp)
|
||||
REG_S a3, ABI_A3(sp)
|
||||
REG_S a4, ABI_A4(sp)
|
||||
REG_S a5, ABI_A5(sp)
|
||||
REG_S a6, ABI_A6(sp)
|
||||
REG_S a7, ABI_A7(sp)
|
||||
REG_S ra, ABI_RA(sp)
|
||||
.endm
|
||||
|
||||
.macro RESTORE_ABI_STATE
|
||||
#ifdef CONFIG_FUNCTION_GRAPH_TRACER
|
||||
ld s0, 32(sp)
|
||||
ld ra, 40(sp)
|
||||
addi sp, sp, 48
|
||||
#else
|
||||
ld ra, 8(sp)
|
||||
ld s0, 0(sp)
|
||||
addi sp, sp, 16
|
||||
#endif
|
||||
.macro RESTORE_ABI
|
||||
REG_L a0, ABI_A0(sp)
|
||||
REG_L a1, ABI_A1(sp)
|
||||
REG_L a2, ABI_A2(sp)
|
||||
REG_L a3, ABI_A3(sp)
|
||||
REG_L a4, ABI_A4(sp)
|
||||
REG_L a5, ABI_A5(sp)
|
||||
REG_L a6, ABI_A6(sp)
|
||||
REG_L a7, ABI_A7(sp)
|
||||
REG_L ra, ABI_RA(sp)
|
||||
|
||||
addi sp, sp, ABI_SIZE_ON_STACK
|
||||
addi sp, sp, SZREG
|
||||
.endm
|
||||
|
||||
.macro RESTORE_GRAPH_ARGS
|
||||
ld a0, 24(sp)
|
||||
ld a1, 16(sp)
|
||||
#ifdef HAVE_FUNCTION_GRAPH_FP_TEST
|
||||
ld a2, 8(sp)
|
||||
#endif
|
||||
#ifdef CONFIG_DYNAMIC_FTRACE_WITH_REGS
|
||||
.macro SAVE_ALL
|
||||
addi sp, sp, -SZREG
|
||||
addi sp, sp, -PT_SIZE_ON_STACK
|
||||
|
||||
REG_S x1, PT_EPC(sp)
|
||||
addi sp, sp, PT_SIZE_ON_STACK
|
||||
REG_L x1, (sp)
|
||||
addi sp, sp, -PT_SIZE_ON_STACK
|
||||
REG_S x1, PT_RA(sp)
|
||||
REG_L x1, PT_EPC(sp)
|
||||
|
||||
REG_S x2, PT_SP(sp)
|
||||
REG_S x3, PT_GP(sp)
|
||||
REG_S x4, PT_TP(sp)
|
||||
REG_S x5, PT_T0(sp)
|
||||
REG_S x6, PT_T1(sp)
|
||||
REG_S x7, PT_T2(sp)
|
||||
REG_S x8, PT_S0(sp)
|
||||
REG_S x9, PT_S1(sp)
|
||||
REG_S x10, PT_A0(sp)
|
||||
REG_S x11, PT_A1(sp)
|
||||
REG_S x12, PT_A2(sp)
|
||||
REG_S x13, PT_A3(sp)
|
||||
REG_S x14, PT_A4(sp)
|
||||
REG_S x15, PT_A5(sp)
|
||||
REG_S x16, PT_A6(sp)
|
||||
REG_S x17, PT_A7(sp)
|
||||
REG_S x18, PT_S2(sp)
|
||||
REG_S x19, PT_S3(sp)
|
||||
REG_S x20, PT_S4(sp)
|
||||
REG_S x21, PT_S5(sp)
|
||||
REG_S x22, PT_S6(sp)
|
||||
REG_S x23, PT_S7(sp)
|
||||
REG_S x24, PT_S8(sp)
|
||||
REG_S x25, PT_S9(sp)
|
||||
REG_S x26, PT_S10(sp)
|
||||
REG_S x27, PT_S11(sp)
|
||||
REG_S x28, PT_T3(sp)
|
||||
REG_S x29, PT_T4(sp)
|
||||
REG_S x30, PT_T5(sp)
|
||||
REG_S x31, PT_T6(sp)
|
||||
.endm
|
||||
|
||||
ENTRY(ftrace_graph_caller)
|
||||
addi sp, sp, -16
|
||||
sd s0, 0(sp)
|
||||
sd ra, 8(sp)
|
||||
addi s0, sp, 16
|
||||
ftrace_graph_call:
|
||||
.global ftrace_graph_call
|
||||
/*
|
||||
* Calling ftrace_enable/disable_ftrace_graph_caller would overwrite the
|
||||
* call below. Check ftrace_modify_all_code for details.
|
||||
*/
|
||||
call ftrace_stub
|
||||
ld ra, 8(sp)
|
||||
ld s0, 0(sp)
|
||||
addi sp, sp, 16
|
||||
ret
|
||||
ENDPROC(ftrace_graph_caller)
|
||||
.macro RESTORE_ALL
|
||||
REG_L x1, PT_RA(sp)
|
||||
addi sp, sp, PT_SIZE_ON_STACK
|
||||
REG_S x1, (sp)
|
||||
addi sp, sp, -PT_SIZE_ON_STACK
|
||||
REG_L x1, PT_EPC(sp)
|
||||
REG_L x2, PT_SP(sp)
|
||||
REG_L x3, PT_GP(sp)
|
||||
REG_L x4, PT_TP(sp)
|
||||
REG_L x5, PT_T0(sp)
|
||||
REG_L x6, PT_T1(sp)
|
||||
REG_L x7, PT_T2(sp)
|
||||
REG_L x8, PT_S0(sp)
|
||||
REG_L x9, PT_S1(sp)
|
||||
REG_L x10, PT_A0(sp)
|
||||
REG_L x11, PT_A1(sp)
|
||||
REG_L x12, PT_A2(sp)
|
||||
REG_L x13, PT_A3(sp)
|
||||
REG_L x14, PT_A4(sp)
|
||||
REG_L x15, PT_A5(sp)
|
||||
REG_L x16, PT_A6(sp)
|
||||
REG_L x17, PT_A7(sp)
|
||||
REG_L x18, PT_S2(sp)
|
||||
REG_L x19, PT_S3(sp)
|
||||
REG_L x20, PT_S4(sp)
|
||||
REG_L x21, PT_S5(sp)
|
||||
REG_L x22, PT_S6(sp)
|
||||
REG_L x23, PT_S7(sp)
|
||||
REG_L x24, PT_S8(sp)
|
||||
REG_L x25, PT_S9(sp)
|
||||
REG_L x26, PT_S10(sp)
|
||||
REG_L x27, PT_S11(sp)
|
||||
REG_L x28, PT_T3(sp)
|
||||
REG_L x29, PT_T4(sp)
|
||||
REG_L x30, PT_T5(sp)
|
||||
REG_L x31, PT_T6(sp)
|
||||
|
||||
addi sp, sp, PT_SIZE_ON_STACK
|
||||
addi sp, sp, SZREG
|
||||
.endm
|
||||
#endif /* CONFIG_DYNAMIC_FTRACE_WITH_REGS */
|
||||
|
||||
ENTRY(ftrace_caller)
|
||||
/*
|
||||
* a0: the address in the caller when calling ftrace_caller
|
||||
* a1: the caller's return address
|
||||
* a2: the address of global variable function_trace_op
|
||||
*/
|
||||
ld a1, -8(s0)
|
||||
addi a0, ra, -MCOUNT_INSN_SIZE
|
||||
la t5, function_trace_op
|
||||
ld a2, 0(t5)
|
||||
SAVE_ABI
|
||||
|
||||
#ifdef CONFIG_FUNCTION_GRAPH_TRACER
|
||||
/*
|
||||
* the graph tracer (specifically, prepare_ftrace_return) needs these
|
||||
* arguments but for now the function tracer occupies the regs, so we
|
||||
* save them in temporary regs to recover later.
|
||||
*/
|
||||
addi t0, s0, -8
|
||||
mv t1, a0
|
||||
#ifdef HAVE_FUNCTION_GRAPH_FP_TEST
|
||||
ld t2, -16(s0)
|
||||
#endif
|
||||
#endif
|
||||
addi a0, ra, -FENTRY_RA_OFFSET
|
||||
la a1, function_trace_op
|
||||
REG_L a2, 0(a1)
|
||||
REG_L a1, ABI_SIZE_ON_STACK(sp)
|
||||
mv a3, sp
|
||||
|
||||
SAVE_ABI_STATE
|
||||
ftrace_call:
|
||||
.global ftrace_call
|
||||
/*
|
||||
* For the dynamic ftrace to work, here we should reserve at least
|
||||
* 8 bytes for a functional auipc-jalr pair. The following call
|
||||
* serves this purpose.
|
||||
*
|
||||
* Calling ftrace_update_ftrace_func would overwrite the nops below.
|
||||
* Check ftrace_modify_all_code for details.
|
||||
*/
|
||||
call ftrace_stub
|
||||
|
||||
#ifdef CONFIG_FUNCTION_GRAPH_TRACER
|
||||
RESTORE_GRAPH_ARGS
|
||||
call ftrace_graph_caller
|
||||
addi a0, sp, ABI_SIZE_ON_STACK
|
||||
REG_L a1, ABI_RA(sp)
|
||||
addi a1, a1, -FENTRY_RA_OFFSET
|
||||
#ifdef HAVE_FUNCTION_GRAPH_FP_TEST
|
||||
mv a2, s0
|
||||
#endif
|
||||
|
||||
RESTORE_ABI_STATE
|
||||
ftrace_graph_call:
|
||||
.global ftrace_graph_call
|
||||
call ftrace_stub
|
||||
#endif
|
||||
RESTORE_ABI
|
||||
ret
|
||||
ENDPROC(ftrace_caller)
|
||||
|
||||
#ifdef CONFIG_DYNAMIC_FTRACE_WITH_REGS
|
||||
.macro SAVE_ALL
|
||||
addi sp, sp, -(PT_SIZE_ON_STACK+16)
|
||||
sd s0, (PT_SIZE_ON_STACK)(sp)
|
||||
sd ra, (PT_SIZE_ON_STACK+8)(sp)
|
||||
addi s0, sp, (PT_SIZE_ON_STACK+16)
|
||||
|
||||
sd x1, PT_RA(sp)
|
||||
sd x2, PT_SP(sp)
|
||||
sd x3, PT_GP(sp)
|
||||
sd x4, PT_TP(sp)
|
||||
sd x5, PT_T0(sp)
|
||||
sd x6, PT_T1(sp)
|
||||
sd x7, PT_T2(sp)
|
||||
sd x8, PT_S0(sp)
|
||||
sd x9, PT_S1(sp)
|
||||
sd x10, PT_A0(sp)
|
||||
sd x11, PT_A1(sp)
|
||||
sd x12, PT_A2(sp)
|
||||
sd x13, PT_A3(sp)
|
||||
sd x14, PT_A4(sp)
|
||||
sd x15, PT_A5(sp)
|
||||
sd x16, PT_A6(sp)
|
||||
sd x17, PT_A7(sp)
|
||||
sd x18, PT_S2(sp)
|
||||
sd x19, PT_S3(sp)
|
||||
sd x20, PT_S4(sp)
|
||||
sd x21, PT_S5(sp)
|
||||
sd x22, PT_S6(sp)
|
||||
sd x23, PT_S7(sp)
|
||||
sd x24, PT_S8(sp)
|
||||
sd x25, PT_S9(sp)
|
||||
sd x26, PT_S10(sp)
|
||||
sd x27, PT_S11(sp)
|
||||
sd x28, PT_T3(sp)
|
||||
sd x29, PT_T4(sp)
|
||||
sd x30, PT_T5(sp)
|
||||
sd x31, PT_T6(sp)
|
||||
.endm
|
||||
|
||||
.macro RESTORE_ALL
|
||||
ld x1, PT_RA(sp)
|
||||
ld x2, PT_SP(sp)
|
||||
ld x3, PT_GP(sp)
|
||||
ld x4, PT_TP(sp)
|
||||
ld x5, PT_T0(sp)
|
||||
ld x6, PT_T1(sp)
|
||||
ld x7, PT_T2(sp)
|
||||
ld x8, PT_S0(sp)
|
||||
ld x9, PT_S1(sp)
|
||||
ld x10, PT_A0(sp)
|
||||
ld x11, PT_A1(sp)
|
||||
ld x12, PT_A2(sp)
|
||||
ld x13, PT_A3(sp)
|
||||
ld x14, PT_A4(sp)
|
||||
ld x15, PT_A5(sp)
|
||||
ld x16, PT_A6(sp)
|
||||
ld x17, PT_A7(sp)
|
||||
ld x18, PT_S2(sp)
|
||||
ld x19, PT_S3(sp)
|
||||
ld x20, PT_S4(sp)
|
||||
ld x21, PT_S5(sp)
|
||||
ld x22, PT_S6(sp)
|
||||
ld x23, PT_S7(sp)
|
||||
ld x24, PT_S8(sp)
|
||||
ld x25, PT_S9(sp)
|
||||
ld x26, PT_S10(sp)
|
||||
ld x27, PT_S11(sp)
|
||||
ld x28, PT_T3(sp)
|
||||
ld x29, PT_T4(sp)
|
||||
ld x30, PT_T5(sp)
|
||||
ld x31, PT_T6(sp)
|
||||
|
||||
ld s0, (PT_SIZE_ON_STACK)(sp)
|
||||
ld ra, (PT_SIZE_ON_STACK+8)(sp)
|
||||
addi sp, sp, (PT_SIZE_ON_STACK+16)
|
||||
.endm
|
||||
|
||||
.macro RESTORE_GRAPH_REG_ARGS
|
||||
ld a0, PT_T0(sp)
|
||||
ld a1, PT_T1(sp)
|
||||
#ifdef HAVE_FUNCTION_GRAPH_FP_TEST
|
||||
ld a2, PT_T2(sp)
|
||||
#endif
|
||||
.endm
|
||||
|
||||
/*
|
||||
* Most of the contents are the same as ftrace_caller.
|
||||
*/
|
||||
ENTRY(ftrace_regs_caller)
|
||||
/*
|
||||
* a3: the address of all registers in the stack
|
||||
*/
|
||||
ld a1, -8(s0)
|
||||
addi a0, ra, -MCOUNT_INSN_SIZE
|
||||
la t5, function_trace_op
|
||||
ld a2, 0(t5)
|
||||
addi a3, sp, -(PT_SIZE_ON_STACK+16)
|
||||
|
||||
#ifdef CONFIG_FUNCTION_GRAPH_TRACER
|
||||
addi t0, s0, -8
|
||||
mv t1, a0
|
||||
#ifdef HAVE_FUNCTION_GRAPH_FP_TEST
|
||||
ld t2, -16(s0)
|
||||
#endif
|
||||
#endif
|
||||
SAVE_ALL
|
||||
|
||||
addi a0, ra, -FENTRY_RA_OFFSET
|
||||
la a1, function_trace_op
|
||||
REG_L a2, 0(a1)
|
||||
REG_L a1, PT_SIZE_ON_STACK(sp)
|
||||
mv a3, sp
|
||||
|
||||
ftrace_regs_call:
|
||||
.global ftrace_regs_call
|
||||
call ftrace_stub
|
||||
|
||||
#ifdef CONFIG_FUNCTION_GRAPH_TRACER
|
||||
RESTORE_GRAPH_REG_ARGS
|
||||
call ftrace_graph_caller
|
||||
addi a0, sp, PT_RA
|
||||
REG_L a1, PT_EPC(sp)
|
||||
addi a1, a1, -FENTRY_RA_OFFSET
|
||||
#ifdef HAVE_FUNCTION_GRAPH_FP_TEST
|
||||
mv a2, s0
|
||||
#endif
|
||||
ftrace_graph_regs_call:
|
||||
.global ftrace_graph_regs_call
|
||||
call ftrace_stub
|
||||
#endif
|
||||
|
||||
RESTORE_ALL
|
||||
|
|
|
@ -20,7 +20,12 @@ struct patch_insn {
|
|||
};
|
||||
|
||||
#ifdef CONFIG_MMU
|
||||
static void *patch_map(void *addr, int fixmap)
|
||||
/*
|
||||
* The fix_to_virt(, idx) needs a const value (not a dynamic variable of
|
||||
* reg-a0) or BUILD_BUG_ON failed with "idx >= __end_of_fixed_addresses".
|
||||
* So use '__always_inline' and 'const unsigned int fixmap' here.
|
||||
*/
|
||||
static __always_inline void *patch_map(void *addr, const unsigned int fixmap)
|
||||
{
|
||||
uintptr_t uintaddr = (uintptr_t) addr;
|
||||
struct page *page;
|
||||
|
@ -37,7 +42,6 @@ static void *patch_map(void *addr, int fixmap)
|
|||
return (void *)set_fixmap_offset(fixmap, page_to_phys(page) +
|
||||
(uintaddr & ~PAGE_MASK));
|
||||
}
|
||||
NOKPROBE_SYMBOL(patch_map);
|
||||
|
||||
static void patch_unmap(int fixmap)
|
||||
{
|
||||
|
|
|
@ -0,0 +1,6 @@
|
|||
# SPDX-License-Identifier: GPL-2.0
|
||||
obj-$(CONFIG_KPROBES) += kprobes.o decode-insn.o simulate-insn.o
|
||||
obj-$(CONFIG_KPROBES) += kprobes_trampoline.o
|
||||
obj-$(CONFIG_KPROBES_ON_FTRACE) += ftrace.o
|
||||
obj-$(CONFIG_UPROBES) += uprobes.o decode-insn.o simulate-insn.o
|
||||
CFLAGS_REMOVE_simulate-insn.o = $(CC_FLAGS_FTRACE)
|
|
@ -0,0 +1,48 @@
|
|||
// SPDX-License-Identifier: GPL-2.0+
|
||||
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/kprobes.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/kallsyms.h>
|
||||
#include <asm/sections.h>
|
||||
|
||||
#include "decode-insn.h"
|
||||
#include "simulate-insn.h"
|
||||
|
||||
/* Return:
|
||||
* INSN_REJECTED If instruction is one not allowed to kprobe,
|
||||
* INSN_GOOD_NO_SLOT If instruction is supported but doesn't use its slot.
|
||||
*/
|
||||
enum probe_insn __kprobes
|
||||
riscv_probe_decode_insn(probe_opcode_t *addr, struct arch_probe_insn *api)
|
||||
{
|
||||
probe_opcode_t insn = *addr;
|
||||
|
||||
/*
|
||||
* Reject instructions list:
|
||||
*/
|
||||
RISCV_INSN_REJECTED(system, insn);
|
||||
RISCV_INSN_REJECTED(fence, insn);
|
||||
|
||||
/*
|
||||
* Simulate instructions list:
|
||||
* TODO: the REJECTED ones below need to be implemented
|
||||
*/
|
||||
#ifdef CONFIG_RISCV_ISA_C
|
||||
RISCV_INSN_REJECTED(c_j, insn);
|
||||
RISCV_INSN_REJECTED(c_jr, insn);
|
||||
RISCV_INSN_REJECTED(c_jal, insn);
|
||||
RISCV_INSN_REJECTED(c_jalr, insn);
|
||||
RISCV_INSN_REJECTED(c_beqz, insn);
|
||||
RISCV_INSN_REJECTED(c_bnez, insn);
|
||||
RISCV_INSN_REJECTED(c_ebreak, insn);
|
||||
#endif
|
||||
|
||||
RISCV_INSN_REJECTED(auipc, insn);
|
||||
RISCV_INSN_REJECTED(branch, insn);
|
||||
|
||||
RISCV_INSN_SET_SIMULATE(jal, insn);
|
||||
RISCV_INSN_SET_SIMULATE(jalr, insn);
|
||||
|
||||
return INSN_GOOD;
|
||||
}
|
|
@ -0,0 +1,18 @@
|
|||
/* SPDX-License-Identifier: GPL-2.0+ */
|
||||
|
||||
#ifndef _RISCV_KERNEL_KPROBES_DECODE_INSN_H
|
||||
#define _RISCV_KERNEL_KPROBES_DECODE_INSN_H
|
||||
|
||||
#include <asm/sections.h>
|
||||
#include <asm/kprobes.h>
|
||||
|
||||
enum probe_insn {
|
||||
INSN_REJECTED,
|
||||
INSN_GOOD_NO_SLOT,
|
||||
INSN_GOOD,
|
||||
};
|
||||
|
||||
enum probe_insn __kprobes
|
||||
riscv_probe_decode_insn(probe_opcode_t *addr, struct arch_probe_insn *asi);
|
||||
|
||||
#endif /* _RISCV_KERNEL_KPROBES_DECODE_INSN_H */
|
|
@ -0,0 +1,53 @@
|
|||
// SPDX-License-Identifier: GPL-2.0
|
||||
|
||||
#include <linux/kprobes.h>
|
||||
|
||||
/* Ftrace callback handler for kprobes -- called under preepmt disabed */
|
||||
void kprobe_ftrace_handler(unsigned long ip, unsigned long parent_ip,
|
||||
struct ftrace_ops *ops, struct ftrace_regs *regs)
|
||||
{
|
||||
struct kprobe *p;
|
||||
struct kprobe_ctlblk *kcb;
|
||||
|
||||
p = get_kprobe((kprobe_opcode_t *)ip);
|
||||
if (unlikely(!p) || kprobe_disabled(p))
|
||||
return;
|
||||
|
||||
kcb = get_kprobe_ctlblk();
|
||||
if (kprobe_running()) {
|
||||
kprobes_inc_nmissed_count(p);
|
||||
} else {
|
||||
unsigned long orig_ip = instruction_pointer(&(regs->regs));
|
||||
|
||||
instruction_pointer_set(&(regs->regs), ip);
|
||||
|
||||
__this_cpu_write(current_kprobe, p);
|
||||
kcb->kprobe_status = KPROBE_HIT_ACTIVE;
|
||||
if (!p->pre_handler || !p->pre_handler(p, &(regs->regs))) {
|
||||
/*
|
||||
* Emulate singlestep (and also recover regs->pc)
|
||||
* as if there is a nop
|
||||
*/
|
||||
instruction_pointer_set(&(regs->regs),
|
||||
(unsigned long)p->addr + MCOUNT_INSN_SIZE);
|
||||
if (unlikely(p->post_handler)) {
|
||||
kcb->kprobe_status = KPROBE_HIT_SSDONE;
|
||||
p->post_handler(p, &(regs->regs), 0);
|
||||
}
|
||||
instruction_pointer_set(&(regs->regs), orig_ip);
|
||||
}
|
||||
|
||||
/*
|
||||
* If pre_handler returns !0, it changes regs->pc. We have to
|
||||
* skip emulating post_handler.
|
||||
*/
|
||||
__this_cpu_write(current_kprobe, NULL);
|
||||
}
|
||||
}
|
||||
NOKPROBE_SYMBOL(kprobe_ftrace_handler);
|
||||
|
||||
int arch_prepare_kprobe_ftrace(struct kprobe *p)
|
||||
{
|
||||
p->ainsn.api.insn = NULL;
|
||||
return 0;
|
||||
}
|
|
@ -0,0 +1,398 @@
|
|||
// SPDX-License-Identifier: GPL-2.0+
|
||||
|
||||
#include <linux/kprobes.h>
|
||||
#include <linux/extable.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/stop_machine.h>
|
||||
#include <asm/ptrace.h>
|
||||
#include <linux/uaccess.h>
|
||||
#include <asm/sections.h>
|
||||
#include <asm/cacheflush.h>
|
||||
#include <asm/bug.h>
|
||||
#include <asm/patch.h>
|
||||
|
||||
#include "decode-insn.h"
|
||||
|
||||
DEFINE_PER_CPU(struct kprobe *, current_kprobe) = NULL;
|
||||
DEFINE_PER_CPU(struct kprobe_ctlblk, kprobe_ctlblk);
|
||||
|
||||
static void __kprobes
|
||||
post_kprobe_handler(struct kprobe_ctlblk *, struct pt_regs *);
|
||||
|
||||
static void __kprobes arch_prepare_ss_slot(struct kprobe *p)
|
||||
{
|
||||
unsigned long offset = GET_INSN_LENGTH(p->opcode);
|
||||
|
||||
p->ainsn.api.restore = (unsigned long)p->addr + offset;
|
||||
|
||||
patch_text(p->ainsn.api.insn, p->opcode);
|
||||
patch_text((void *)((unsigned long)(p->ainsn.api.insn) + offset),
|
||||
__BUG_INSN_32);
|
||||
}
|
||||
|
||||
static void __kprobes arch_prepare_simulate(struct kprobe *p)
|
||||
{
|
||||
p->ainsn.api.restore = 0;
|
||||
}
|
||||
|
||||
static void __kprobes arch_simulate_insn(struct kprobe *p, struct pt_regs *regs)
|
||||
{
|
||||
struct kprobe_ctlblk *kcb = get_kprobe_ctlblk();
|
||||
|
||||
if (p->ainsn.api.handler)
|
||||
p->ainsn.api.handler((u32)p->opcode,
|
||||
(unsigned long)p->addr, regs);
|
||||
|
||||
post_kprobe_handler(kcb, regs);
|
||||
}
|
||||
|
||||
int __kprobes arch_prepare_kprobe(struct kprobe *p)
|
||||
{
|
||||
unsigned long probe_addr = (unsigned long)p->addr;
|
||||
|
||||
if (probe_addr & 0x1) {
|
||||
pr_warn("Address not aligned.\n");
|
||||
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/* copy instruction */
|
||||
p->opcode = *p->addr;
|
||||
|
||||
/* decode instruction */
|
||||
switch (riscv_probe_decode_insn(p->addr, &p->ainsn.api)) {
|
||||
case INSN_REJECTED: /* insn not supported */
|
||||
return -EINVAL;
|
||||
|
||||
case INSN_GOOD_NO_SLOT: /* insn need simulation */
|
||||
p->ainsn.api.insn = NULL;
|
||||
break;
|
||||
|
||||
case INSN_GOOD: /* instruction uses slot */
|
||||
p->ainsn.api.insn = get_insn_slot();
|
||||
if (!p->ainsn.api.insn)
|
||||
return -ENOMEM;
|
||||
break;
|
||||
}
|
||||
|
||||
/* prepare the instruction */
|
||||
if (p->ainsn.api.insn)
|
||||
arch_prepare_ss_slot(p);
|
||||
else
|
||||
arch_prepare_simulate(p);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* install breakpoint in text */
|
||||
void __kprobes arch_arm_kprobe(struct kprobe *p)
|
||||
{
|
||||
if ((p->opcode & __INSN_LENGTH_MASK) == __INSN_LENGTH_32)
|
||||
patch_text(p->addr, __BUG_INSN_32);
|
||||
else
|
||||
patch_text(p->addr, __BUG_INSN_16);
|
||||
}
|
||||
|
||||
/* remove breakpoint from text */
|
||||
void __kprobes arch_disarm_kprobe(struct kprobe *p)
|
||||
{
|
||||
patch_text(p->addr, p->opcode);
|
||||
}
|
||||
|
||||
void __kprobes arch_remove_kprobe(struct kprobe *p)
|
||||
{
|
||||
}
|
||||
|
||||
static void __kprobes save_previous_kprobe(struct kprobe_ctlblk *kcb)
|
||||
{
|
||||
kcb->prev_kprobe.kp = kprobe_running();
|
||||
kcb->prev_kprobe.status = kcb->kprobe_status;
|
||||
}
|
||||
|
||||
static void __kprobes restore_previous_kprobe(struct kprobe_ctlblk *kcb)
|
||||
{
|
||||
__this_cpu_write(current_kprobe, kcb->prev_kprobe.kp);
|
||||
kcb->kprobe_status = kcb->prev_kprobe.status;
|
||||
}
|
||||
|
||||
static void __kprobes set_current_kprobe(struct kprobe *p)
|
||||
{
|
||||
__this_cpu_write(current_kprobe, p);
|
||||
}
|
||||
|
||||
/*
|
||||
* Interrupts need to be disabled before single-step mode is set, and not
|
||||
* reenabled until after single-step mode ends.
|
||||
* Without disabling interrupt on local CPU, there is a chance of
|
||||
* interrupt occurrence in the period of exception return and start of
|
||||
* out-of-line single-step, that result in wrongly single stepping
|
||||
* into the interrupt handler.
|
||||
*/
|
||||
static void __kprobes kprobes_save_local_irqflag(struct kprobe_ctlblk *kcb,
|
||||
struct pt_regs *regs)
|
||||
{
|
||||
kcb->saved_status = regs->status;
|
||||
regs->status &= ~SR_SPIE;
|
||||
}
|
||||
|
||||
static void __kprobes kprobes_restore_local_irqflag(struct kprobe_ctlblk *kcb,
|
||||
struct pt_regs *regs)
|
||||
{
|
||||
regs->status = kcb->saved_status;
|
||||
}
|
||||
|
||||
static void __kprobes
|
||||
set_ss_context(struct kprobe_ctlblk *kcb, unsigned long addr, struct kprobe *p)
|
||||
{
|
||||
unsigned long offset = GET_INSN_LENGTH(p->opcode);
|
||||
|
||||
kcb->ss_ctx.ss_pending = true;
|
||||
kcb->ss_ctx.match_addr = addr + offset;
|
||||
}
|
||||
|
||||
static void __kprobes clear_ss_context(struct kprobe_ctlblk *kcb)
|
||||
{
|
||||
kcb->ss_ctx.ss_pending = false;
|
||||
kcb->ss_ctx.match_addr = 0;
|
||||
}
|
||||
|
||||
static void __kprobes setup_singlestep(struct kprobe *p,
|
||||
struct pt_regs *regs,
|
||||
struct kprobe_ctlblk *kcb, int reenter)
|
||||
{
|
||||
unsigned long slot;
|
||||
|
||||
if (reenter) {
|
||||
save_previous_kprobe(kcb);
|
||||
set_current_kprobe(p);
|
||||
kcb->kprobe_status = KPROBE_REENTER;
|
||||
} else {
|
||||
kcb->kprobe_status = KPROBE_HIT_SS;
|
||||
}
|
||||
|
||||
if (p->ainsn.api.insn) {
|
||||
/* prepare for single stepping */
|
||||
slot = (unsigned long)p->ainsn.api.insn;
|
||||
|
||||
set_ss_context(kcb, slot, p); /* mark pending ss */
|
||||
|
||||
/* IRQs and single stepping do not mix well. */
|
||||
kprobes_save_local_irqflag(kcb, regs);
|
||||
|
||||
instruction_pointer_set(regs, slot);
|
||||
} else {
|
||||
/* insn simulation */
|
||||
arch_simulate_insn(p, regs);
|
||||
}
|
||||
}
|
||||
|
||||
static int __kprobes reenter_kprobe(struct kprobe *p,
|
||||
struct pt_regs *regs,
|
||||
struct kprobe_ctlblk *kcb)
|
||||
{
|
||||
switch (kcb->kprobe_status) {
|
||||
case KPROBE_HIT_SSDONE:
|
||||
case KPROBE_HIT_ACTIVE:
|
||||
kprobes_inc_nmissed_count(p);
|
||||
setup_singlestep(p, regs, kcb, 1);
|
||||
break;
|
||||
case KPROBE_HIT_SS:
|
||||
case KPROBE_REENTER:
|
||||
pr_warn("Unrecoverable kprobe detected.\n");
|
||||
dump_kprobe(p);
|
||||
BUG();
|
||||
break;
|
||||
default:
|
||||
WARN_ON(1);
|
||||
return 0;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static void __kprobes
|
||||
post_kprobe_handler(struct kprobe_ctlblk *kcb, struct pt_regs *regs)
|
||||
{
|
||||
struct kprobe *cur = kprobe_running();
|
||||
|
||||
if (!cur)
|
||||
return;
|
||||
|
||||
/* return addr restore if non-branching insn */
|
||||
if (cur->ainsn.api.restore != 0)
|
||||
regs->epc = cur->ainsn.api.restore;
|
||||
|
||||
/* restore back original saved kprobe variables and continue */
|
||||
if (kcb->kprobe_status == KPROBE_REENTER) {
|
||||
restore_previous_kprobe(kcb);
|
||||
return;
|
||||
}
|
||||
|
||||
/* call post handler */
|
||||
kcb->kprobe_status = KPROBE_HIT_SSDONE;
|
||||
if (cur->post_handler) {
|
||||
/* post_handler can hit breakpoint and single step
|
||||
* again, so we enable D-flag for recursive exception.
|
||||
*/
|
||||
cur->post_handler(cur, regs, 0);
|
||||
}
|
||||
|
||||
reset_current_kprobe();
|
||||
}
|
||||
|
||||
int __kprobes kprobe_fault_handler(struct pt_regs *regs, unsigned int trapnr)
|
||||
{
|
||||
struct kprobe *cur = kprobe_running();
|
||||
struct kprobe_ctlblk *kcb = get_kprobe_ctlblk();
|
||||
|
||||
switch (kcb->kprobe_status) {
|
||||
case KPROBE_HIT_SS:
|
||||
case KPROBE_REENTER:
|
||||
/*
|
||||
* We are here because the instruction being single
|
||||
* stepped caused a page fault. We reset the current
|
||||
* kprobe and the ip points back to the probe address
|
||||
* and allow the page fault handler to continue as a
|
||||
* normal page fault.
|
||||
*/
|
||||
regs->epc = (unsigned long) cur->addr;
|
||||
if (!instruction_pointer(regs))
|
||||
BUG();
|
||||
|
||||
if (kcb->kprobe_status == KPROBE_REENTER)
|
||||
restore_previous_kprobe(kcb);
|
||||
else
|
||||
reset_current_kprobe();
|
||||
|
||||
break;
|
||||
case KPROBE_HIT_ACTIVE:
|
||||
case KPROBE_HIT_SSDONE:
|
||||
/*
|
||||
* We increment the nmissed count for accounting,
|
||||
* we can also use npre/npostfault count for accounting
|
||||
* these specific fault cases.
|
||||
*/
|
||||
kprobes_inc_nmissed_count(cur);
|
||||
|
||||
/*
|
||||
* We come here because instructions in the pre/post
|
||||
* handler caused the page_fault, this could happen
|
||||
* if handler tries to access user space by
|
||||
* copy_from_user(), get_user() etc. Let the
|
||||
* user-specified handler try to fix it first.
|
||||
*/
|
||||
if (cur->fault_handler && cur->fault_handler(cur, regs, trapnr))
|
||||
return 1;
|
||||
|
||||
/*
|
||||
* In case the user-specified fault handler returned
|
||||
* zero, try to fix up.
|
||||
*/
|
||||
if (fixup_exception(regs))
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
bool __kprobes
|
||||
kprobe_breakpoint_handler(struct pt_regs *regs)
|
||||
{
|
||||
struct kprobe *p, *cur_kprobe;
|
||||
struct kprobe_ctlblk *kcb;
|
||||
unsigned long addr = instruction_pointer(regs);
|
||||
|
||||
kcb = get_kprobe_ctlblk();
|
||||
cur_kprobe = kprobe_running();
|
||||
|
||||
p = get_kprobe((kprobe_opcode_t *) addr);
|
||||
|
||||
if (p) {
|
||||
if (cur_kprobe) {
|
||||
if (reenter_kprobe(p, regs, kcb))
|
||||
return true;
|
||||
} else {
|
||||
/* Probe hit */
|
||||
set_current_kprobe(p);
|
||||
kcb->kprobe_status = KPROBE_HIT_ACTIVE;
|
||||
|
||||
/*
|
||||
* If we have no pre-handler or it returned 0, we
|
||||
* continue with normal processing. If we have a
|
||||
* pre-handler and it returned non-zero, it will
|
||||
* modify the execution path and no need to single
|
||||
* stepping. Let's just reset current kprobe and exit.
|
||||
*
|
||||
* pre_handler can hit a breakpoint and can step thru
|
||||
* before return.
|
||||
*/
|
||||
if (!p->pre_handler || !p->pre_handler(p, regs))
|
||||
setup_singlestep(p, regs, kcb, 0);
|
||||
else
|
||||
reset_current_kprobe();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/*
|
||||
* The breakpoint instruction was removed right
|
||||
* after we hit it. Another cpu has removed
|
||||
* either a probepoint or a debugger breakpoint
|
||||
* at this address. In either case, no further
|
||||
* handling of this interrupt is appropriate.
|
||||
* Return back to original instruction, and continue.
|
||||
*/
|
||||
return false;
|
||||
}
|
||||
|
||||
bool __kprobes
|
||||
kprobe_single_step_handler(struct pt_regs *regs)
|
||||
{
|
||||
struct kprobe_ctlblk *kcb = get_kprobe_ctlblk();
|
||||
|
||||
if ((kcb->ss_ctx.ss_pending)
|
||||
&& (kcb->ss_ctx.match_addr == instruction_pointer(regs))) {
|
||||
clear_ss_context(kcb); /* clear pending ss */
|
||||
|
||||
kprobes_restore_local_irqflag(kcb, regs);
|
||||
|
||||
post_kprobe_handler(kcb, regs);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/*
|
||||
* Provide a blacklist of symbols identifying ranges which cannot be kprobed.
|
||||
* This blacklist is exposed to userspace via debugfs (kprobes/blacklist).
|
||||
*/
|
||||
int __init arch_populate_kprobe_blacklist(void)
|
||||
{
|
||||
int ret;
|
||||
|
||||
ret = kprobe_add_area_blacklist((unsigned long)__irqentry_text_start,
|
||||
(unsigned long)__irqentry_text_end);
|
||||
return ret;
|
||||
}
|
||||
|
||||
void __kprobes __used *trampoline_probe_handler(struct pt_regs *regs)
|
||||
{
|
||||
return (void *)kretprobe_trampoline_handler(regs, &kretprobe_trampoline, NULL);
|
||||
}
|
||||
|
||||
void __kprobes arch_prepare_kretprobe(struct kretprobe_instance *ri,
|
||||
struct pt_regs *regs)
|
||||
{
|
||||
ri->ret_addr = (kprobe_opcode_t *)regs->ra;
|
||||
ri->fp = NULL;
|
||||
regs->ra = (unsigned long) &kretprobe_trampoline;
|
||||
}
|
||||
|
||||
int __kprobes arch_trampoline_kprobe(struct kprobe *p)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
int __init arch_init_kprobes(void)
|
||||
{
|
||||
return 0;
|
||||
}
|
|
@ -0,0 +1,93 @@
|
|||
/* SPDX-License-Identifier: GPL-2.0+ */
|
||||
/*
|
||||
* Author: Patrick Stählin <me@packi.ch>
|
||||
*/
|
||||
#include <linux/linkage.h>
|
||||
|
||||
#include <asm/asm.h>
|
||||
#include <asm/asm-offsets.h>
|
||||
|
||||
.text
|
||||
.altmacro
|
||||
|
||||
.macro save_all_base_regs
|
||||
REG_S x1, PT_RA(sp)
|
||||
REG_S x3, PT_GP(sp)
|
||||
REG_S x4, PT_TP(sp)
|
||||
REG_S x5, PT_T0(sp)
|
||||
REG_S x6, PT_T1(sp)
|
||||
REG_S x7, PT_T2(sp)
|
||||
REG_S x8, PT_S0(sp)
|
||||
REG_S x9, PT_S1(sp)
|
||||
REG_S x10, PT_A0(sp)
|
||||
REG_S x11, PT_A1(sp)
|
||||
REG_S x12, PT_A2(sp)
|
||||
REG_S x13, PT_A3(sp)
|
||||
REG_S x14, PT_A4(sp)
|
||||
REG_S x15, PT_A5(sp)
|
||||
REG_S x16, PT_A6(sp)
|
||||
REG_S x17, PT_A7(sp)
|
||||
REG_S x18, PT_S2(sp)
|
||||
REG_S x19, PT_S3(sp)
|
||||
REG_S x20, PT_S4(sp)
|
||||
REG_S x21, PT_S5(sp)
|
||||
REG_S x22, PT_S6(sp)
|
||||
REG_S x23, PT_S7(sp)
|
||||
REG_S x24, PT_S8(sp)
|
||||
REG_S x25, PT_S9(sp)
|
||||
REG_S x26, PT_S10(sp)
|
||||
REG_S x27, PT_S11(sp)
|
||||
REG_S x28, PT_T3(sp)
|
||||
REG_S x29, PT_T4(sp)
|
||||
REG_S x30, PT_T5(sp)
|
||||
REG_S x31, PT_T6(sp)
|
||||
.endm
|
||||
|
||||
.macro restore_all_base_regs
|
||||
REG_L x3, PT_GP(sp)
|
||||
REG_L x4, PT_TP(sp)
|
||||
REG_L x5, PT_T0(sp)
|
||||
REG_L x6, PT_T1(sp)
|
||||
REG_L x7, PT_T2(sp)
|
||||
REG_L x8, PT_S0(sp)
|
||||
REG_L x9, PT_S1(sp)
|
||||
REG_L x10, PT_A0(sp)
|
||||
REG_L x11, PT_A1(sp)
|
||||
REG_L x12, PT_A2(sp)
|
||||
REG_L x13, PT_A3(sp)
|
||||
REG_L x14, PT_A4(sp)
|
||||
REG_L x15, PT_A5(sp)
|
||||
REG_L x16, PT_A6(sp)
|
||||
REG_L x17, PT_A7(sp)
|
||||
REG_L x18, PT_S2(sp)
|
||||
REG_L x19, PT_S3(sp)
|
||||
REG_L x20, PT_S4(sp)
|
||||
REG_L x21, PT_S5(sp)
|
||||
REG_L x22, PT_S6(sp)
|
||||
REG_L x23, PT_S7(sp)
|
||||
REG_L x24, PT_S8(sp)
|
||||
REG_L x25, PT_S9(sp)
|
||||
REG_L x26, PT_S10(sp)
|
||||
REG_L x27, PT_S11(sp)
|
||||
REG_L x28, PT_T3(sp)
|
||||
REG_L x29, PT_T4(sp)
|
||||
REG_L x30, PT_T5(sp)
|
||||
REG_L x31, PT_T6(sp)
|
||||
.endm
|
||||
|
||||
ENTRY(kretprobe_trampoline)
|
||||
addi sp, sp, -(PT_SIZE_ON_STACK)
|
||||
save_all_base_regs
|
||||
|
||||
move a0, sp /* pt_regs */
|
||||
|
||||
call trampoline_probe_handler
|
||||
|
||||
/* use the result as the return-address */
|
||||
move ra, a0
|
||||
|
||||
restore_all_base_regs
|
||||
addi sp, sp, PT_SIZE_ON_STACK
|
||||
|
||||
ret
|
||||
ENDPROC(kretprobe_trampoline)
|
|
@ -0,0 +1,85 @@
|
|||
// SPDX-License-Identifier: GPL-2.0+
|
||||
|
||||
#include <linux/bitops.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/kprobes.h>
|
||||
|
||||
#include "decode-insn.h"
|
||||
#include "simulate-insn.h"
|
||||
|
||||
static inline bool rv_insn_reg_get_val(struct pt_regs *regs, u32 index,
|
||||
unsigned long *ptr)
|
||||
{
|
||||
if (index == 0)
|
||||
*ptr = 0;
|
||||
else if (index <= 31)
|
||||
*ptr = *((unsigned long *)regs + index);
|
||||
else
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static inline bool rv_insn_reg_set_val(struct pt_regs *regs, u32 index,
|
||||
unsigned long val)
|
||||
{
|
||||
if (index == 0)
|
||||
return false;
|
||||
else if (index <= 31)
|
||||
*((unsigned long *)regs + index) = val;
|
||||
else
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool __kprobes simulate_jal(u32 opcode, unsigned long addr, struct pt_regs *regs)
|
||||
{
|
||||
/*
|
||||
* 31 30 21 20 19 12 11 7 6 0
|
||||
* imm [20] | imm[10:1] | imm[11] | imm[19:12] | rd | opcode
|
||||
* 1 10 1 8 5 JAL/J
|
||||
*/
|
||||
bool ret;
|
||||
u32 imm;
|
||||
u32 index = (opcode >> 7) & 0x1f;
|
||||
|
||||
ret = rv_insn_reg_set_val(regs, index, addr + 4);
|
||||
if (!ret)
|
||||
return ret;
|
||||
|
||||
imm = ((opcode >> 21) & 0x3ff) << 1;
|
||||
imm |= ((opcode >> 20) & 0x1) << 11;
|
||||
imm |= ((opcode >> 12) & 0xff) << 12;
|
||||
imm |= ((opcode >> 31) & 0x1) << 20;
|
||||
|
||||
instruction_pointer_set(regs, addr + sign_extend32((imm), 20));
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
bool __kprobes simulate_jalr(u32 opcode, unsigned long addr, struct pt_regs *regs)
|
||||
{
|
||||
/*
|
||||
* 31 20 19 15 14 12 11 7 6 0
|
||||
* offset[11:0] | rs1 | 010 | rd | opcode
|
||||
* 12 5 3 5 JALR/JR
|
||||
*/
|
||||
bool ret;
|
||||
unsigned long base_addr;
|
||||
u32 imm = (opcode >> 20) & 0xfff;
|
||||
u32 rd_index = (opcode >> 7) & 0x1f;
|
||||
u32 rs1_index = (opcode >> 15) & 0x1f;
|
||||
|
||||
ret = rv_insn_reg_set_val(regs, rd_index, addr + 4);
|
||||
if (!ret)
|
||||
return ret;
|
||||
|
||||
ret = rv_insn_reg_get_val(regs, rs1_index, &base_addr);
|
||||
if (!ret)
|
||||
return ret;
|
||||
|
||||
instruction_pointer_set(regs, (base_addr + sign_extend32((imm), 11))&~1);
|
||||
|
||||
return ret;
|
||||
}
|
|
@ -0,0 +1,47 @@
|
|||
/* SPDX-License-Identifier: GPL-2.0+ */
|
||||
|
||||
#ifndef _RISCV_KERNEL_PROBES_SIMULATE_INSN_H
|
||||
#define _RISCV_KERNEL_PROBES_SIMULATE_INSN_H
|
||||
|
||||
#define __RISCV_INSN_FUNCS(name, mask, val) \
|
||||
static __always_inline bool riscv_insn_is_##name(probe_opcode_t code) \
|
||||
{ \
|
||||
BUILD_BUG_ON(~(mask) & (val)); \
|
||||
return (code & (mask)) == (val); \
|
||||
} \
|
||||
bool simulate_##name(u32 opcode, unsigned long addr, \
|
||||
struct pt_regs *regs)
|
||||
|
||||
#define RISCV_INSN_REJECTED(name, code) \
|
||||
do { \
|
||||
if (riscv_insn_is_##name(code)) { \
|
||||
return INSN_REJECTED; \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
__RISCV_INSN_FUNCS(system, 0x7f, 0x73);
|
||||
__RISCV_INSN_FUNCS(fence, 0x7f, 0x0f);
|
||||
|
||||
#define RISCV_INSN_SET_SIMULATE(name, code) \
|
||||
do { \
|
||||
if (riscv_insn_is_##name(code)) { \
|
||||
api->handler = simulate_##name; \
|
||||
return INSN_GOOD_NO_SLOT; \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
__RISCV_INSN_FUNCS(c_j, 0xe003, 0xa001);
|
||||
__RISCV_INSN_FUNCS(c_jr, 0xf007, 0x8002);
|
||||
__RISCV_INSN_FUNCS(c_jal, 0xe003, 0x2001);
|
||||
__RISCV_INSN_FUNCS(c_jalr, 0xf007, 0x9002);
|
||||
__RISCV_INSN_FUNCS(c_beqz, 0xe003, 0xc001);
|
||||
__RISCV_INSN_FUNCS(c_bnez, 0xe003, 0xe001);
|
||||
__RISCV_INSN_FUNCS(c_ebreak, 0xffff, 0x9002);
|
||||
|
||||
__RISCV_INSN_FUNCS(auipc, 0x7f, 0x17);
|
||||
__RISCV_INSN_FUNCS(branch, 0x7f, 0x63);
|
||||
|
||||
__RISCV_INSN_FUNCS(jal, 0x7f, 0x6f);
|
||||
__RISCV_INSN_FUNCS(jalr, 0x707f, 0x67);
|
||||
|
||||
#endif /* _RISCV_KERNEL_PROBES_SIMULATE_INSN_H */
|
|
@ -0,0 +1,186 @@
|
|||
// SPDX-License-Identifier: GPL-2.0-only
|
||||
|
||||
#include <linux/highmem.h>
|
||||
#include <linux/ptrace.h>
|
||||
#include <linux/uprobes.h>
|
||||
|
||||
#include "decode-insn.h"
|
||||
|
||||
#define UPROBE_TRAP_NR UINT_MAX
|
||||
|
||||
bool is_swbp_insn(uprobe_opcode_t *insn)
|
||||
{
|
||||
#ifdef CONFIG_RISCV_ISA_C
|
||||
return (*insn & 0xffff) == UPROBE_SWBP_INSN;
|
||||
#else
|
||||
return *insn == UPROBE_SWBP_INSN;
|
||||
#endif
|
||||
}
|
||||
|
||||
unsigned long uprobe_get_swbp_addr(struct pt_regs *regs)
|
||||
{
|
||||
return instruction_pointer(regs);
|
||||
}
|
||||
|
||||
int arch_uprobe_analyze_insn(struct arch_uprobe *auprobe, struct mm_struct *mm,
|
||||
unsigned long addr)
|
||||
{
|
||||
probe_opcode_t opcode;
|
||||
|
||||
opcode = *(probe_opcode_t *)(&auprobe->insn[0]);
|
||||
|
||||
auprobe->insn_size = GET_INSN_LENGTH(opcode);
|
||||
|
||||
switch (riscv_probe_decode_insn(&opcode, &auprobe->api)) {
|
||||
case INSN_REJECTED:
|
||||
return -EINVAL;
|
||||
|
||||
case INSN_GOOD_NO_SLOT:
|
||||
auprobe->simulate = true;
|
||||
break;
|
||||
|
||||
case INSN_GOOD:
|
||||
auprobe->simulate = false;
|
||||
break;
|
||||
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int arch_uprobe_pre_xol(struct arch_uprobe *auprobe, struct pt_regs *regs)
|
||||
{
|
||||
struct uprobe_task *utask = current->utask;
|
||||
|
||||
utask->autask.saved_cause = current->thread.bad_cause;
|
||||
current->thread.bad_cause = UPROBE_TRAP_NR;
|
||||
|
||||
instruction_pointer_set(regs, utask->xol_vaddr);
|
||||
|
||||
regs->status &= ~SR_SPIE;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int arch_uprobe_post_xol(struct arch_uprobe *auprobe, struct pt_regs *regs)
|
||||
{
|
||||
struct uprobe_task *utask = current->utask;
|
||||
|
||||
WARN_ON_ONCE(current->thread.bad_cause != UPROBE_TRAP_NR);
|
||||
|
||||
instruction_pointer_set(regs, utask->vaddr + auprobe->insn_size);
|
||||
|
||||
regs->status |= SR_SPIE;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
bool arch_uprobe_xol_was_trapped(struct task_struct *t)
|
||||
{
|
||||
if (t->thread.bad_cause != UPROBE_TRAP_NR)
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool arch_uprobe_skip_sstep(struct arch_uprobe *auprobe, struct pt_regs *regs)
|
||||
{
|
||||
probe_opcode_t insn;
|
||||
unsigned long addr;
|
||||
|
||||
if (!auprobe->simulate)
|
||||
return false;
|
||||
|
||||
insn = *(probe_opcode_t *)(&auprobe->insn[0]);
|
||||
addr = instruction_pointer(regs);
|
||||
|
||||
if (auprobe->api.handler)
|
||||
auprobe->api.handler(insn, addr, regs);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void arch_uprobe_abort_xol(struct arch_uprobe *auprobe, struct pt_regs *regs)
|
||||
{
|
||||
struct uprobe_task *utask = current->utask;
|
||||
|
||||
/*
|
||||
* Task has received a fatal signal, so reset back to probbed
|
||||
* address.
|
||||
*/
|
||||
instruction_pointer_set(regs, utask->vaddr);
|
||||
|
||||
regs->status &= ~SR_SPIE;
|
||||
}
|
||||
|
||||
bool arch_uretprobe_is_alive(struct return_instance *ret, enum rp_check ctx,
|
||||
struct pt_regs *regs)
|
||||
{
|
||||
if (ctx == RP_CHECK_CHAIN_CALL)
|
||||
return regs->sp <= ret->stack;
|
||||
else
|
||||
return regs->sp < ret->stack;
|
||||
}
|
||||
|
||||
unsigned long
|
||||
arch_uretprobe_hijack_return_addr(unsigned long trampoline_vaddr,
|
||||
struct pt_regs *regs)
|
||||
{
|
||||
unsigned long ra;
|
||||
|
||||
ra = regs->ra;
|
||||
|
||||
regs->ra = trampoline_vaddr;
|
||||
|
||||
return ra;
|
||||
}
|
||||
|
||||
int arch_uprobe_exception_notify(struct notifier_block *self,
|
||||
unsigned long val, void *data)
|
||||
{
|
||||
return NOTIFY_DONE;
|
||||
}
|
||||
|
||||
bool uprobe_breakpoint_handler(struct pt_regs *regs)
|
||||
{
|
||||
if (uprobe_pre_sstep_notifier(regs))
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool uprobe_single_step_handler(struct pt_regs *regs)
|
||||
{
|
||||
if (uprobe_post_sstep_notifier(regs))
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void arch_uprobe_copy_ixol(struct page *page, unsigned long vaddr,
|
||||
void *src, unsigned long len)
|
||||
{
|
||||
/* Initialize the slot */
|
||||
void *kaddr = kmap_atomic(page);
|
||||
void *dst = kaddr + (vaddr & ~PAGE_MASK);
|
||||
|
||||
memcpy(dst, src, len);
|
||||
|
||||
/* Add ebreak behind opcode to simulate singlestep */
|
||||
if (vaddr) {
|
||||
dst += GET_INSN_LENGTH(*(probe_opcode_t *)src);
|
||||
*(uprobe_opcode_t *)dst = __BUG_INSN_32;
|
||||
}
|
||||
|
||||
kunmap_atomic(kaddr);
|
||||
|
||||
/*
|
||||
* We probably need flush_icache_user_page() but it needs vma.
|
||||
* This should work on most of architectures by default. If
|
||||
* architecture needs to do something different it can define
|
||||
* its own version of the function.
|
||||
*/
|
||||
flush_dcache_page(page);
|
||||
}
|
|
@ -18,13 +18,14 @@
|
|||
#include <asm/unistd.h>
|
||||
#include <asm/processor.h>
|
||||
#include <asm/csr.h>
|
||||
#include <asm/stacktrace.h>
|
||||
#include <asm/string.h>
|
||||
#include <asm/switch_to.h>
|
||||
#include <asm/thread_info.h>
|
||||
|
||||
register unsigned long gp_in_global __asm__("gp");
|
||||
|
||||
#ifdef CONFIG_STACKPROTECTOR
|
||||
#if defined(CONFIG_STACKPROTECTOR) && !defined(CONFIG_STACKPROTECTOR_PER_TASK)
|
||||
#include <linux/stackprotector.h>
|
||||
unsigned long __stack_chk_guard __read_mostly;
|
||||
EXPORT_SYMBOL(__stack_chk_guard);
|
||||
|
@ -39,11 +40,16 @@ void arch_cpu_idle(void)
|
|||
raw_local_irq_enable();
|
||||
}
|
||||
|
||||
void show_regs(struct pt_regs *regs)
|
||||
void __show_regs(struct pt_regs *regs)
|
||||
{
|
||||
show_regs_print_info(KERN_DEFAULT);
|
||||
|
||||
pr_cont("epc: " REG_FMT " ra : " REG_FMT " sp : " REG_FMT "\n",
|
||||
if (!user_mode(regs)) {
|
||||
pr_cont("epc : %pS\n", (void *)regs->epc);
|
||||
pr_cont(" ra : %pS\n", (void *)regs->ra);
|
||||
}
|
||||
|
||||
pr_cont("epc : " REG_FMT " ra : " REG_FMT " sp : " REG_FMT "\n",
|
||||
regs->epc, regs->ra, regs->sp);
|
||||
pr_cont(" gp : " REG_FMT " tp : " REG_FMT " t0 : " REG_FMT "\n",
|
||||
regs->gp, regs->tp, regs->t0);
|
||||
|
@ -69,6 +75,12 @@ void show_regs(struct pt_regs *regs)
|
|||
pr_cont("status: " REG_FMT " badaddr: " REG_FMT " cause: " REG_FMT "\n",
|
||||
regs->status, regs->badaddr, regs->cause);
|
||||
}
|
||||
void show_regs(struct pt_regs *regs)
|
||||
{
|
||||
__show_regs(regs);
|
||||
if (!user_mode(regs))
|
||||
dump_backtrace(regs, NULL, KERN_DEFAULT);
|
||||
}
|
||||
|
||||
void start_thread(struct pt_regs *regs, unsigned long pc,
|
||||
unsigned long sp)
|
||||
|
|
|
@ -114,6 +114,105 @@ const struct user_regset_view *task_user_regset_view(struct task_struct *task)
|
|||
return &riscv_user_native_view;
|
||||
}
|
||||
|
||||
struct pt_regs_offset {
|
||||
const char *name;
|
||||
int offset;
|
||||
};
|
||||
|
||||
#define REG_OFFSET_NAME(r) {.name = #r, .offset = offsetof(struct pt_regs, r)}
|
||||
#define REG_OFFSET_END {.name = NULL, .offset = 0}
|
||||
|
||||
static const struct pt_regs_offset regoffset_table[] = {
|
||||
REG_OFFSET_NAME(epc),
|
||||
REG_OFFSET_NAME(ra),
|
||||
REG_OFFSET_NAME(sp),
|
||||
REG_OFFSET_NAME(gp),
|
||||
REG_OFFSET_NAME(tp),
|
||||
REG_OFFSET_NAME(t0),
|
||||
REG_OFFSET_NAME(t1),
|
||||
REG_OFFSET_NAME(t2),
|
||||
REG_OFFSET_NAME(s0),
|
||||
REG_OFFSET_NAME(s1),
|
||||
REG_OFFSET_NAME(a0),
|
||||
REG_OFFSET_NAME(a1),
|
||||
REG_OFFSET_NAME(a2),
|
||||
REG_OFFSET_NAME(a3),
|
||||
REG_OFFSET_NAME(a4),
|
||||
REG_OFFSET_NAME(a5),
|
||||
REG_OFFSET_NAME(a6),
|
||||
REG_OFFSET_NAME(a7),
|
||||
REG_OFFSET_NAME(s2),
|
||||
REG_OFFSET_NAME(s3),
|
||||
REG_OFFSET_NAME(s4),
|
||||
REG_OFFSET_NAME(s5),
|
||||
REG_OFFSET_NAME(s6),
|
||||
REG_OFFSET_NAME(s7),
|
||||
REG_OFFSET_NAME(s8),
|
||||
REG_OFFSET_NAME(s9),
|
||||
REG_OFFSET_NAME(s10),
|
||||
REG_OFFSET_NAME(s11),
|
||||
REG_OFFSET_NAME(t3),
|
||||
REG_OFFSET_NAME(t4),
|
||||
REG_OFFSET_NAME(t5),
|
||||
REG_OFFSET_NAME(t6),
|
||||
REG_OFFSET_NAME(status),
|
||||
REG_OFFSET_NAME(badaddr),
|
||||
REG_OFFSET_NAME(cause),
|
||||
REG_OFFSET_NAME(orig_a0),
|
||||
REG_OFFSET_END,
|
||||
};
|
||||
|
||||
/**
|
||||
* regs_query_register_offset() - query register offset from its name
|
||||
* @name: the name of a register
|
||||
*
|
||||
* regs_query_register_offset() returns the offset of a register in struct
|
||||
* pt_regs from its name. If the name is invalid, this returns -EINVAL;
|
||||
*/
|
||||
int regs_query_register_offset(const char *name)
|
||||
{
|
||||
const struct pt_regs_offset *roff;
|
||||
|
||||
for (roff = regoffset_table; roff->name != NULL; roff++)
|
||||
if (!strcmp(roff->name, name))
|
||||
return roff->offset;
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/**
|
||||
* regs_within_kernel_stack() - check the address in the stack
|
||||
* @regs: pt_regs which contains kernel stack pointer.
|
||||
* @addr: address which is checked.
|
||||
*
|
||||
* regs_within_kernel_stack() checks @addr is within the kernel stack page(s).
|
||||
* If @addr is within the kernel stack, it returns true. If not, returns false.
|
||||
*/
|
||||
static bool regs_within_kernel_stack(struct pt_regs *regs, unsigned long addr)
|
||||
{
|
||||
return (addr & ~(THREAD_SIZE - 1)) ==
|
||||
(kernel_stack_pointer(regs) & ~(THREAD_SIZE - 1));
|
||||
}
|
||||
|
||||
/**
|
||||
* regs_get_kernel_stack_nth() - get Nth entry of the stack
|
||||
* @regs: pt_regs which contains kernel stack pointer.
|
||||
* @n: stack entry number.
|
||||
*
|
||||
* regs_get_kernel_stack_nth() returns @n th entry of the kernel stack which
|
||||
* is specified by @regs. If the @n th entry is NOT in the kernel stack,
|
||||
* this returns 0.
|
||||
*/
|
||||
unsigned long regs_get_kernel_stack_nth(struct pt_regs *regs, unsigned int n)
|
||||
{
|
||||
unsigned long *addr = (unsigned long *)kernel_stack_pointer(regs);
|
||||
|
||||
addr += n;
|
||||
if (regs_within_kernel_stack(regs, (unsigned long)addr))
|
||||
return *addr;
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
|
||||
void ptrace_disable(struct task_struct *child)
|
||||
{
|
||||
clear_tsk_thread_flag(child, TIF_SYSCALL_TRACE);
|
||||
|
|
|
@ -351,7 +351,7 @@ static int __sbi_rfence_v02(int fid, const unsigned long *hart_mask,
|
|||
* sbi_set_timer() - Program the timer for next timer event.
|
||||
* @stime_value: The value after which next timer event should fire.
|
||||
*
|
||||
* Return: None
|
||||
* Return: None.
|
||||
*/
|
||||
void sbi_set_timer(uint64_t stime_value)
|
||||
{
|
||||
|
@ -362,11 +362,11 @@ void sbi_set_timer(uint64_t stime_value)
|
|||
* sbi_send_ipi() - Send an IPI to any hart.
|
||||
* @hart_mask: A cpu mask containing all the target harts.
|
||||
*
|
||||
* Return: None
|
||||
* Return: 0 on success, appropriate linux error code otherwise.
|
||||
*/
|
||||
void sbi_send_ipi(const unsigned long *hart_mask)
|
||||
int sbi_send_ipi(const unsigned long *hart_mask)
|
||||
{
|
||||
__sbi_send_ipi(hart_mask);
|
||||
return __sbi_send_ipi(hart_mask);
|
||||
}
|
||||
EXPORT_SYMBOL(sbi_send_ipi);
|
||||
|
||||
|
@ -374,12 +374,12 @@ EXPORT_SYMBOL(sbi_send_ipi);
|
|||
* sbi_remote_fence_i() - Execute FENCE.I instruction on given remote harts.
|
||||
* @hart_mask: A cpu mask containing all the target harts.
|
||||
*
|
||||
* Return: None
|
||||
* Return: 0 on success, appropriate linux error code otherwise.
|
||||
*/
|
||||
void sbi_remote_fence_i(const unsigned long *hart_mask)
|
||||
int sbi_remote_fence_i(const unsigned long *hart_mask)
|
||||
{
|
||||
__sbi_rfence(SBI_EXT_RFENCE_REMOTE_FENCE_I,
|
||||
hart_mask, 0, 0, 0, 0);
|
||||
return __sbi_rfence(SBI_EXT_RFENCE_REMOTE_FENCE_I,
|
||||
hart_mask, 0, 0, 0, 0);
|
||||
}
|
||||
EXPORT_SYMBOL(sbi_remote_fence_i);
|
||||
|
||||
|
@ -390,14 +390,14 @@ EXPORT_SYMBOL(sbi_remote_fence_i);
|
|||
* @start: Start of the virtual address
|
||||
* @size: Total size of the virtual address range.
|
||||
*
|
||||
* Return: None
|
||||
* Return: 0 on success, appropriate linux error code otherwise.
|
||||
*/
|
||||
void sbi_remote_sfence_vma(const unsigned long *hart_mask,
|
||||
int sbi_remote_sfence_vma(const unsigned long *hart_mask,
|
||||
unsigned long start,
|
||||
unsigned long size)
|
||||
{
|
||||
__sbi_rfence(SBI_EXT_RFENCE_REMOTE_SFENCE_VMA,
|
||||
hart_mask, start, size, 0, 0);
|
||||
return __sbi_rfence(SBI_EXT_RFENCE_REMOTE_SFENCE_VMA,
|
||||
hart_mask, start, size, 0, 0);
|
||||
}
|
||||
EXPORT_SYMBOL(sbi_remote_sfence_vma);
|
||||
|
||||
|
@ -410,15 +410,15 @@ EXPORT_SYMBOL(sbi_remote_sfence_vma);
|
|||
* @size: Total size of the virtual address range.
|
||||
* @asid: The value of address space identifier (ASID).
|
||||
*
|
||||
* Return: None
|
||||
* Return: 0 on success, appropriate linux error code otherwise.
|
||||
*/
|
||||
void sbi_remote_sfence_vma_asid(const unsigned long *hart_mask,
|
||||
int sbi_remote_sfence_vma_asid(const unsigned long *hart_mask,
|
||||
unsigned long start,
|
||||
unsigned long size,
|
||||
unsigned long asid)
|
||||
{
|
||||
__sbi_rfence(SBI_EXT_RFENCE_REMOTE_SFENCE_VMA_ASID,
|
||||
hart_mask, start, size, asid, 0);
|
||||
return __sbi_rfence(SBI_EXT_RFENCE_REMOTE_SFENCE_VMA_ASID,
|
||||
hart_mask, start, size, asid, 0);
|
||||
}
|
||||
EXPORT_SYMBOL(sbi_remote_sfence_vma_asid);
|
||||
|
||||
|
@ -560,7 +560,7 @@ static struct riscv_ipi_ops sbi_ipi_ops = {
|
|||
.ipi_inject = sbi_send_cpumask_ipi
|
||||
};
|
||||
|
||||
int __init sbi_init(void)
|
||||
void __init sbi_init(void)
|
||||
{
|
||||
int ret;
|
||||
|
||||
|
@ -600,6 +600,4 @@ int __init sbi_init(void)
|
|||
}
|
||||
|
||||
riscv_set_ipi_ops(&sbi_ipi_ops);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -216,8 +216,15 @@ static void __init init_resources(void)
|
|||
static void __init parse_dtb(void)
|
||||
{
|
||||
/* Early scan of device tree from init memory */
|
||||
if (early_init_dt_scan(dtb_early_va))
|
||||
if (early_init_dt_scan(dtb_early_va)) {
|
||||
const char *name = of_flat_dt_get_machine_name();
|
||||
|
||||
if (name) {
|
||||
pr_info("Machine model: %s\n", name);
|
||||
dump_stack_set_arch_desc("%s (DT)", name);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
pr_err("No DTB passed to the kernel\n");
|
||||
#ifdef CONFIG_CMDLINE_FORCE
|
||||
|
@ -252,9 +259,9 @@ void __init setup_arch(char **cmdline_p)
|
|||
else
|
||||
pr_err("No DTB found in kernel mappings\n");
|
||||
#endif
|
||||
misc_mem_init();
|
||||
|
||||
if (IS_ENABLED(CONFIG_RISCV_SBI))
|
||||
sbi_init();
|
||||
sbi_init();
|
||||
|
||||
if (IS_ENABLED(CONFIG_STRICT_KERNEL_RWX))
|
||||
protect_kernel_text_data();
|
||||
|
@ -275,13 +282,19 @@ void __init setup_arch(char **cmdline_p)
|
|||
|
||||
static int __init topology_init(void)
|
||||
{
|
||||
int i;
|
||||
int i, ret;
|
||||
|
||||
for_each_online_node(i)
|
||||
register_one_node(i);
|
||||
|
||||
for_each_possible_cpu(i) {
|
||||
struct cpu *cpu = &per_cpu(cpu_devices, i);
|
||||
|
||||
cpu->hotpluggable = cpu_has_hotplug(i);
|
||||
register_cpu(cpu, i);
|
||||
ret = register_cpu(cpu, i);
|
||||
if (unlikely(ret))
|
||||
pr_warn("Warning: %s: register_cpu %d failed (%d)\n",
|
||||
__func__, i, ret);
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
|
|
@ -309,6 +309,9 @@ static void do_signal(struct pt_regs *regs)
|
|||
asmlinkage __visible void do_notify_resume(struct pt_regs *regs,
|
||||
unsigned long thread_info_flags)
|
||||
{
|
||||
if (thread_info_flags & _TIF_UPROBE)
|
||||
uprobe_notify_resume(regs);
|
||||
|
||||
/* Handle pending signal delivery */
|
||||
if (thread_info_flags & (_TIF_SIGPENDING | _TIF_NOTIFY_SIGNAL))
|
||||
do_signal(regs);
|
||||
|
|
|
@ -27,6 +27,7 @@
|
|||
#include <asm/cpu_ops.h>
|
||||
#include <asm/irq.h>
|
||||
#include <asm/mmu_context.h>
|
||||
#include <asm/numa.h>
|
||||
#include <asm/tlbflush.h>
|
||||
#include <asm/sections.h>
|
||||
#include <asm/sbi.h>
|
||||
|
@ -45,13 +46,18 @@ void __init smp_prepare_cpus(unsigned int max_cpus)
|
|||
{
|
||||
int cpuid;
|
||||
int ret;
|
||||
unsigned int curr_cpuid;
|
||||
|
||||
curr_cpuid = smp_processor_id();
|
||||
numa_store_cpu_info(curr_cpuid);
|
||||
numa_add_cpu(curr_cpuid);
|
||||
|
||||
/* This covers non-smp usecase mandated by "nosmp" option */
|
||||
if (max_cpus == 0)
|
||||
return;
|
||||
|
||||
for_each_possible_cpu(cpuid) {
|
||||
if (cpuid == smp_processor_id())
|
||||
if (cpuid == curr_cpuid)
|
||||
continue;
|
||||
if (cpu_ops[cpuid]->cpu_prepare) {
|
||||
ret = cpu_ops[cpuid]->cpu_prepare(cpuid);
|
||||
|
@ -59,6 +65,7 @@ void __init smp_prepare_cpus(unsigned int max_cpus)
|
|||
continue;
|
||||
}
|
||||
set_cpu_present(cpuid, true);
|
||||
numa_store_cpu_info(cpuid);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -79,6 +86,7 @@ void __init setup_smp(void)
|
|||
if (hart == cpuid_to_hartid_map(0)) {
|
||||
BUG_ON(found_boot_cpu);
|
||||
found_boot_cpu = 1;
|
||||
early_map_cpu_to_node(0, of_node_to_nid(dn));
|
||||
continue;
|
||||
}
|
||||
if (cpuid >= NR_CPUS) {
|
||||
|
@ -88,6 +96,7 @@ void __init setup_smp(void)
|
|||
}
|
||||
|
||||
cpuid_to_hartid_map(cpuid) = hart;
|
||||
early_map_cpu_to_node(cpuid, of_node_to_nid(dn));
|
||||
cpuid++;
|
||||
}
|
||||
|
||||
|
@ -153,6 +162,7 @@ asmlinkage __visible void smp_callin(void)
|
|||
current->active_mm = mm;
|
||||
|
||||
notify_cpu_starting(curr_cpuid);
|
||||
numa_add_cpu(curr_cpuid);
|
||||
update_siblings_masks(curr_cpuid);
|
||||
set_cpu_online(curr_cpuid, 1);
|
||||
|
||||
|
|
|
@ -26,30 +26,3 @@ void __init soc_early_init(void)
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
static bool soc_builtin_dtb_match(unsigned long vendor_id,
|
||||
unsigned long arch_id, unsigned long imp_id,
|
||||
const struct soc_builtin_dtb *entry)
|
||||
{
|
||||
return entry->vendor_id == vendor_id &&
|
||||
entry->arch_id == arch_id &&
|
||||
entry->imp_id == imp_id;
|
||||
}
|
||||
|
||||
void * __init soc_lookup_builtin_dtb(void)
|
||||
{
|
||||
unsigned long vendor_id, arch_id, imp_id;
|
||||
const struct soc_builtin_dtb *s;
|
||||
|
||||
__asm__ ("csrr %0, mvendorid" : "=r"(vendor_id));
|
||||
__asm__ ("csrr %0, marchid" : "=r"(arch_id));
|
||||
__asm__ ("csrr %0, mimpid" : "=r"(imp_id));
|
||||
|
||||
for (s = (void *)&__soc_builtin_dtb_table_start;
|
||||
(void *)s < (void *)&__soc_builtin_dtb_table_end; s++) {
|
||||
if (soc_builtin_dtb_match(vendor_id, arch_id, imp_id, s))
|
||||
return s->dtb_func();
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
|
|
@ -53,9 +53,15 @@ void notrace walk_stackframe(struct task_struct *task, struct pt_regs *regs,
|
|||
/* Unwind stack frame */
|
||||
frame = (struct stackframe *)fp - 1;
|
||||
sp = fp;
|
||||
fp = frame->fp;
|
||||
pc = ftrace_graph_ret_addr(current, NULL, frame->ra,
|
||||
(unsigned long *)(fp - 8));
|
||||
if (regs && (regs->epc == pc) && (frame->fp & 0x7)) {
|
||||
fp = frame->ra;
|
||||
pc = regs->ra;
|
||||
} else {
|
||||
fp = frame->fp;
|
||||
pc = ftrace_graph_ret_addr(current, NULL, frame->ra,
|
||||
(unsigned long *)(fp - 8));
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -100,10 +106,16 @@ static bool print_trace_address(void *arg, unsigned long pc)
|
|||
return true;
|
||||
}
|
||||
|
||||
void dump_backtrace(struct pt_regs *regs, struct task_struct *task,
|
||||
const char *loglvl)
|
||||
{
|
||||
pr_cont("%sCall Trace:\n", loglvl);
|
||||
walk_stackframe(task, regs, print_trace_address, (void *)loglvl);
|
||||
}
|
||||
|
||||
void show_stack(struct task_struct *task, unsigned long *sp, const char *loglvl)
|
||||
{
|
||||
pr_cont("Call Trace:\n");
|
||||
walk_stackframe(task, NULL, print_trace_address, (void *)loglvl);
|
||||
dump_backtrace(NULL, task, loglvl);
|
||||
}
|
||||
|
||||
static bool save_wchan(void *arg, unsigned long pc)
|
||||
|
|
|
@ -12,10 +12,12 @@
|
|||
#include <linux/signal.h>
|
||||
#include <linux/kdebug.h>
|
||||
#include <linux/uaccess.h>
|
||||
#include <linux/kprobes.h>
|
||||
#include <linux/mm.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/irq.h>
|
||||
|
||||
#include <asm/bug.h>
|
||||
#include <asm/processor.h>
|
||||
#include <asm/ptrace.h>
|
||||
#include <asm/csr.h>
|
||||
|
@ -66,7 +68,7 @@ void do_trap(struct pt_regs *regs, int signo, int code, unsigned long addr)
|
|||
tsk->comm, task_pid_nr(tsk), signo, code, addr);
|
||||
print_vma_addr(KERN_CONT " in ", instruction_pointer(regs));
|
||||
pr_cont("\n");
|
||||
show_regs(regs);
|
||||
__show_regs(regs);
|
||||
}
|
||||
|
||||
force_sig_fault(signo, code, (void __user *)addr);
|
||||
|
@ -75,6 +77,8 @@ void do_trap(struct pt_regs *regs, int signo, int code, unsigned long addr)
|
|||
static void do_trap_error(struct pt_regs *regs, int signo, int code,
|
||||
unsigned long addr, const char *str)
|
||||
{
|
||||
current->thread.bad_cause = regs->cause;
|
||||
|
||||
if (user_mode(regs)) {
|
||||
do_trap(regs, signo, code, addr);
|
||||
} else {
|
||||
|
@ -145,6 +149,22 @@ static inline unsigned long get_break_insn_length(unsigned long pc)
|
|||
|
||||
asmlinkage __visible void do_trap_break(struct pt_regs *regs)
|
||||
{
|
||||
#ifdef CONFIG_KPROBES
|
||||
if (kprobe_single_step_handler(regs))
|
||||
return;
|
||||
|
||||
if (kprobe_breakpoint_handler(regs))
|
||||
return;
|
||||
#endif
|
||||
#ifdef CONFIG_UPROBES
|
||||
if (uprobe_single_step_handler(regs))
|
||||
return;
|
||||
|
||||
if (uprobe_breakpoint_handler(regs))
|
||||
return;
|
||||
#endif
|
||||
current->thread.bad_cause = regs->cause;
|
||||
|
||||
if (user_mode(regs))
|
||||
force_sig_fault(SIGTRAP, TRAP_BRKPT, (void __user *)regs->epc);
|
||||
#ifdef CONFIG_KGDB
|
||||
|
|
|
@ -32,9 +32,10 @@ CPPFLAGS_vdso.lds += -P -C -U$(ARCH)
|
|||
# Disable -pg to prevent insert call site
|
||||
CFLAGS_REMOVE_vgettimeofday.o = $(CC_FLAGS_FTRACE) -Os
|
||||
|
||||
# Disable gcov profiling for VDSO code
|
||||
# Disable profiling and instrumentation for VDSO code
|
||||
GCOV_PROFILE := n
|
||||
KCOV_INSTRUMENT := n
|
||||
KASAN_SANITIZE := n
|
||||
|
||||
# Force dependency
|
||||
$(obj)/vdso.o: $(obj)/vdso.so
|
||||
|
|
|
@ -5,3 +5,5 @@ lib-y += memset.o
|
|||
lib-y += memmove.o
|
||||
lib-$(CONFIG_MMU) += uaccess.o
|
||||
lib-$(CONFIG_64BIT) += tishift.o
|
||||
|
||||
obj-$(CONFIG_FUNCTION_ERROR_INJECTION) += error-inject.o
|
||||
|
|
|
@ -0,0 +1,10 @@
|
|||
// SPDX-License-Identifier: GPL-2.0
|
||||
|
||||
#include <linux/error-injection.h>
|
||||
#include <linux/kprobes.h>
|
||||
|
||||
void override_function_with_return(struct pt_regs *regs)
|
||||
{
|
||||
instruction_pointer_set(regs, regs->ra);
|
||||
}
|
||||
NOKPROBE_SYMBOL(override_function_with_return);
|
|
@ -2,7 +2,8 @@
|
|||
|
||||
CFLAGS_init.o := -mcmodel=medany
|
||||
ifdef CONFIG_FTRACE
|
||||
CFLAGS_REMOVE_init.o = -pg
|
||||
CFLAGS_REMOVE_init.o = $(CC_FLAGS_FTRACE)
|
||||
CFLAGS_REMOVE_cacheflush.o = $(CC_FLAGS_FTRACE)
|
||||
endif
|
||||
|
||||
KCOV_INSTRUMENT_init.o := n
|
||||
|
|
|
@ -2,13 +2,273 @@
|
|||
/*
|
||||
* Copyright (C) 2012 Regents of the University of California
|
||||
* Copyright (C) 2017 SiFive
|
||||
* Copyright (C) 2021 Western Digital Corporation or its affiliates.
|
||||
*/
|
||||
|
||||
#include <linux/bitops.h>
|
||||
#include <linux/cpumask.h>
|
||||
#include <linux/mm.h>
|
||||
#include <linux/percpu.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/spinlock.h>
|
||||
#include <linux/static_key.h>
|
||||
#include <asm/tlbflush.h>
|
||||
#include <asm/cacheflush.h>
|
||||
#include <asm/mmu_context.h>
|
||||
|
||||
#ifdef CONFIG_MMU
|
||||
|
||||
static DEFINE_STATIC_KEY_FALSE(use_asid_allocator);
|
||||
|
||||
static unsigned long asid_bits;
|
||||
static unsigned long num_asids;
|
||||
static unsigned long asid_mask;
|
||||
|
||||
static atomic_long_t current_version;
|
||||
|
||||
static DEFINE_RAW_SPINLOCK(context_lock);
|
||||
static cpumask_t context_tlb_flush_pending;
|
||||
static unsigned long *context_asid_map;
|
||||
|
||||
static DEFINE_PER_CPU(atomic_long_t, active_context);
|
||||
static DEFINE_PER_CPU(unsigned long, reserved_context);
|
||||
|
||||
static bool check_update_reserved_context(unsigned long cntx,
|
||||
unsigned long newcntx)
|
||||
{
|
||||
int cpu;
|
||||
bool hit = false;
|
||||
|
||||
/*
|
||||
* Iterate over the set of reserved CONTEXT looking for a match.
|
||||
* If we find one, then we can update our mm to use new CONTEXT
|
||||
* (i.e. the same CONTEXT in the current_version) but we can't
|
||||
* exit the loop early, since we need to ensure that all copies
|
||||
* of the old CONTEXT are updated to reflect the mm. Failure to do
|
||||
* so could result in us missing the reserved CONTEXT in a future
|
||||
* version.
|
||||
*/
|
||||
for_each_possible_cpu(cpu) {
|
||||
if (per_cpu(reserved_context, cpu) == cntx) {
|
||||
hit = true;
|
||||
per_cpu(reserved_context, cpu) = newcntx;
|
||||
}
|
||||
}
|
||||
|
||||
return hit;
|
||||
}
|
||||
|
||||
static void __flush_context(void)
|
||||
{
|
||||
int i;
|
||||
unsigned long cntx;
|
||||
|
||||
/* Must be called with context_lock held */
|
||||
lockdep_assert_held(&context_lock);
|
||||
|
||||
/* Update the list of reserved ASIDs and the ASID bitmap. */
|
||||
bitmap_clear(context_asid_map, 0, num_asids);
|
||||
|
||||
/* Mark already active ASIDs as used */
|
||||
for_each_possible_cpu(i) {
|
||||
cntx = atomic_long_xchg_relaxed(&per_cpu(active_context, i), 0);
|
||||
/*
|
||||
* If this CPU has already been through a rollover, but
|
||||
* hasn't run another task in the meantime, we must preserve
|
||||
* its reserved CONTEXT, as this is the only trace we have of
|
||||
* the process it is still running.
|
||||
*/
|
||||
if (cntx == 0)
|
||||
cntx = per_cpu(reserved_context, i);
|
||||
|
||||
__set_bit(cntx & asid_mask, context_asid_map);
|
||||
per_cpu(reserved_context, i) = cntx;
|
||||
}
|
||||
|
||||
/* Mark ASID #0 as used because it is used at boot-time */
|
||||
__set_bit(0, context_asid_map);
|
||||
|
||||
/* Queue a TLB invalidation for each CPU on next context-switch */
|
||||
cpumask_setall(&context_tlb_flush_pending);
|
||||
}
|
||||
|
||||
static unsigned long __new_context(struct mm_struct *mm)
|
||||
{
|
||||
static u32 cur_idx = 1;
|
||||
unsigned long cntx = atomic_long_read(&mm->context.id);
|
||||
unsigned long asid, ver = atomic_long_read(¤t_version);
|
||||
|
||||
/* Must be called with context_lock held */
|
||||
lockdep_assert_held(&context_lock);
|
||||
|
||||
if (cntx != 0) {
|
||||
unsigned long newcntx = ver | (cntx & asid_mask);
|
||||
|
||||
/*
|
||||
* If our current CONTEXT was active during a rollover, we
|
||||
* can continue to use it and this was just a false alarm.
|
||||
*/
|
||||
if (check_update_reserved_context(cntx, newcntx))
|
||||
return newcntx;
|
||||
|
||||
/*
|
||||
* We had a valid CONTEXT in a previous life, so try to
|
||||
* re-use it if possible.
|
||||
*/
|
||||
if (!__test_and_set_bit(cntx & asid_mask, context_asid_map))
|
||||
return newcntx;
|
||||
}
|
||||
|
||||
/*
|
||||
* Allocate a free ASID. If we can't find one then increment
|
||||
* current_version and flush all ASIDs.
|
||||
*/
|
||||
asid = find_next_zero_bit(context_asid_map, num_asids, cur_idx);
|
||||
if (asid != num_asids)
|
||||
goto set_asid;
|
||||
|
||||
/* We're out of ASIDs, so increment current_version */
|
||||
ver = atomic_long_add_return_relaxed(num_asids, ¤t_version);
|
||||
|
||||
/* Flush everything */
|
||||
__flush_context();
|
||||
|
||||
/* We have more ASIDs than CPUs, so this will always succeed */
|
||||
asid = find_next_zero_bit(context_asid_map, num_asids, 1);
|
||||
|
||||
set_asid:
|
||||
__set_bit(asid, context_asid_map);
|
||||
cur_idx = asid;
|
||||
return asid | ver;
|
||||
}
|
||||
|
||||
static void set_mm_asid(struct mm_struct *mm, unsigned int cpu)
|
||||
{
|
||||
unsigned long flags;
|
||||
bool need_flush_tlb = false;
|
||||
unsigned long cntx, old_active_cntx;
|
||||
|
||||
cntx = atomic_long_read(&mm->context.id);
|
||||
|
||||
/*
|
||||
* If our active_context is non-zero and the context matches the
|
||||
* current_version, then we update the active_context entry with a
|
||||
* relaxed cmpxchg.
|
||||
*
|
||||
* Following is how we handle racing with a concurrent rollover:
|
||||
*
|
||||
* - We get a zero back from the cmpxchg and end up waiting on the
|
||||
* lock. Taking the lock synchronises with the rollover and so
|
||||
* we are forced to see the updated verion.
|
||||
*
|
||||
* - We get a valid context back from the cmpxchg then we continue
|
||||
* using old ASID because __flush_context() would have marked ASID
|
||||
* of active_context as used and next context switch we will
|
||||
* allocate new context.
|
||||
*/
|
||||
old_active_cntx = atomic_long_read(&per_cpu(active_context, cpu));
|
||||
if (old_active_cntx &&
|
||||
((cntx & ~asid_mask) == atomic_long_read(¤t_version)) &&
|
||||
atomic_long_cmpxchg_relaxed(&per_cpu(active_context, cpu),
|
||||
old_active_cntx, cntx))
|
||||
goto switch_mm_fast;
|
||||
|
||||
raw_spin_lock_irqsave(&context_lock, flags);
|
||||
|
||||
/* Check that our ASID belongs to the current_version. */
|
||||
cntx = atomic_long_read(&mm->context.id);
|
||||
if ((cntx & ~asid_mask) != atomic_long_read(¤t_version)) {
|
||||
cntx = __new_context(mm);
|
||||
atomic_long_set(&mm->context.id, cntx);
|
||||
}
|
||||
|
||||
if (cpumask_test_and_clear_cpu(cpu, &context_tlb_flush_pending))
|
||||
need_flush_tlb = true;
|
||||
|
||||
atomic_long_set(&per_cpu(active_context, cpu), cntx);
|
||||
|
||||
raw_spin_unlock_irqrestore(&context_lock, flags);
|
||||
|
||||
switch_mm_fast:
|
||||
csr_write(CSR_SATP, virt_to_pfn(mm->pgd) |
|
||||
((cntx & asid_mask) << SATP_ASID_SHIFT) |
|
||||
SATP_MODE);
|
||||
|
||||
if (need_flush_tlb)
|
||||
local_flush_tlb_all();
|
||||
}
|
||||
|
||||
static void set_mm_noasid(struct mm_struct *mm)
|
||||
{
|
||||
/* Switch the page table and blindly nuke entire local TLB */
|
||||
csr_write(CSR_SATP, virt_to_pfn(mm->pgd) | SATP_MODE);
|
||||
local_flush_tlb_all();
|
||||
}
|
||||
|
||||
static inline void set_mm(struct mm_struct *mm, unsigned int cpu)
|
||||
{
|
||||
if (static_branch_unlikely(&use_asid_allocator))
|
||||
set_mm_asid(mm, cpu);
|
||||
else
|
||||
set_mm_noasid(mm);
|
||||
}
|
||||
|
||||
static int asids_init(void)
|
||||
{
|
||||
unsigned long old;
|
||||
|
||||
/* Figure-out number of ASID bits in HW */
|
||||
old = csr_read(CSR_SATP);
|
||||
asid_bits = old | (SATP_ASID_MASK << SATP_ASID_SHIFT);
|
||||
csr_write(CSR_SATP, asid_bits);
|
||||
asid_bits = (csr_read(CSR_SATP) >> SATP_ASID_SHIFT) & SATP_ASID_MASK;
|
||||
asid_bits = fls_long(asid_bits);
|
||||
csr_write(CSR_SATP, old);
|
||||
|
||||
/*
|
||||
* In the process of determining number of ASID bits (above)
|
||||
* we polluted the TLB of current HART so let's do TLB flushed
|
||||
* to remove unwanted TLB enteries.
|
||||
*/
|
||||
local_flush_tlb_all();
|
||||
|
||||
/* Pre-compute ASID details */
|
||||
num_asids = 1 << asid_bits;
|
||||
asid_mask = num_asids - 1;
|
||||
|
||||
/*
|
||||
* Use ASID allocator only if number of HW ASIDs are
|
||||
* at-least twice more than CPUs
|
||||
*/
|
||||
if (num_asids > (2 * num_possible_cpus())) {
|
||||
atomic_long_set(¤t_version, num_asids);
|
||||
|
||||
context_asid_map = kcalloc(BITS_TO_LONGS(num_asids),
|
||||
sizeof(*context_asid_map), GFP_KERNEL);
|
||||
if (!context_asid_map)
|
||||
panic("Failed to allocate bitmap for %lu ASIDs\n",
|
||||
num_asids);
|
||||
|
||||
__set_bit(0, context_asid_map);
|
||||
|
||||
static_branch_enable(&use_asid_allocator);
|
||||
|
||||
pr_info("ASID allocator using %lu bits (%lu entries)\n",
|
||||
asid_bits, num_asids);
|
||||
} else {
|
||||
pr_info("ASID allocator disabled\n");
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
early_initcall(asids_init);
|
||||
#else
|
||||
static inline void set_mm(struct mm_struct *mm, unsigned int cpu)
|
||||
{
|
||||
/* Nothing to do here when there is no MMU */
|
||||
}
|
||||
#endif
|
||||
|
||||
/*
|
||||
* When necessary, performs a deferred icache flush for the given MM context,
|
||||
* on the local CPU. RISC-V has no direct mechanism for instruction cache
|
||||
|
@ -58,10 +318,7 @@ void switch_mm(struct mm_struct *prev, struct mm_struct *next,
|
|||
cpumask_clear_cpu(cpu, mm_cpumask(prev));
|
||||
cpumask_set_cpu(cpu, mm_cpumask(next));
|
||||
|
||||
#ifdef CONFIG_MMU
|
||||
csr_write(CSR_SATP, virt_to_pfn(next->pgd) | SATP_MODE);
|
||||
local_flush_tlb_all();
|
||||
#endif
|
||||
set_mm(next, cpu);
|
||||
|
||||
flush_icache_deferred(next);
|
||||
}
|
||||
|
|
|
@ -13,14 +13,30 @@
|
|||
#include <linux/perf_event.h>
|
||||
#include <linux/signal.h>
|
||||
#include <linux/uaccess.h>
|
||||
#include <linux/kprobes.h>
|
||||
|
||||
#include <asm/ptrace.h>
|
||||
#include <asm/tlbflush.h>
|
||||
|
||||
#include "../kernel/head.h"
|
||||
|
||||
static void die_kernel_fault(const char *msg, unsigned long addr,
|
||||
struct pt_regs *regs)
|
||||
{
|
||||
bust_spinlocks(1);
|
||||
|
||||
pr_alert("Unable to handle kernel %s at virtual address " REG_FMT "\n", msg,
|
||||
addr);
|
||||
|
||||
bust_spinlocks(0);
|
||||
die(regs, "Oops");
|
||||
do_exit(SIGKILL);
|
||||
}
|
||||
|
||||
static inline void no_context(struct pt_regs *regs, unsigned long addr)
|
||||
{
|
||||
const char *msg;
|
||||
|
||||
/* Are we prepared to handle this kernel fault? */
|
||||
if (fixup_exception(regs))
|
||||
return;
|
||||
|
@ -29,12 +45,8 @@ static inline void no_context(struct pt_regs *regs, unsigned long addr)
|
|||
* Oops. The kernel tried to access some bad page. We'll have to
|
||||
* terminate things with extreme prejudice.
|
||||
*/
|
||||
bust_spinlocks(1);
|
||||
pr_alert("Unable to handle kernel %s at virtual address " REG_FMT "\n",
|
||||
(addr < PAGE_SIZE) ? "NULL pointer dereference" :
|
||||
"paging request", addr);
|
||||
die(regs, "Oops");
|
||||
do_exit(SIGKILL);
|
||||
msg = (addr < PAGE_SIZE) ? "NULL pointer dereference" : "paging request";
|
||||
die_kernel_fault(msg, addr, regs);
|
||||
}
|
||||
|
||||
static inline void mm_fault_error(struct pt_regs *regs, unsigned long addr, vm_fault_t fault)
|
||||
|
@ -202,6 +214,9 @@ asmlinkage void do_page_fault(struct pt_regs *regs)
|
|||
tsk = current;
|
||||
mm = tsk->mm;
|
||||
|
||||
if (kprobe_page_fault(regs, cause))
|
||||
return;
|
||||
|
||||
/*
|
||||
* Fault-in kernel-space virtual memory on-demand.
|
||||
* The 'reference' page table is init_mm.pgd.
|
||||
|
@ -225,6 +240,7 @@ asmlinkage void do_page_fault(struct pt_regs *regs)
|
|||
* in an atomic region, then we must not take the fault.
|
||||
*/
|
||||
if (unlikely(faulthandler_disabled() || !mm)) {
|
||||
tsk->thread.bad_cause = cause;
|
||||
no_context(regs, addr);
|
||||
return;
|
||||
}
|
||||
|
@ -232,6 +248,11 @@ asmlinkage void do_page_fault(struct pt_regs *regs)
|
|||
if (user_mode(regs))
|
||||
flags |= FAULT_FLAG_USER;
|
||||
|
||||
if (!user_mode(regs) && addr < TASK_SIZE &&
|
||||
unlikely(!(regs->status & SR_SUM)))
|
||||
die_kernel_fault("access to user memory without uaccess routines",
|
||||
addr, regs);
|
||||
|
||||
perf_sw_event(PERF_COUNT_SW_PAGE_FAULTS, 1, regs, addr);
|
||||
|
||||
if (cause == EXC_STORE_PAGE_FAULT)
|
||||
|
@ -242,16 +263,19 @@ retry:
|
|||
mmap_read_lock(mm);
|
||||
vma = find_vma(mm, addr);
|
||||
if (unlikely(!vma)) {
|
||||
tsk->thread.bad_cause = cause;
|
||||
bad_area(regs, mm, code, addr);
|
||||
return;
|
||||
}
|
||||
if (likely(vma->vm_start <= addr))
|
||||
goto good_area;
|
||||
if (unlikely(!(vma->vm_flags & VM_GROWSDOWN))) {
|
||||
tsk->thread.bad_cause = cause;
|
||||
bad_area(regs, mm, code, addr);
|
||||
return;
|
||||
}
|
||||
if (unlikely(expand_stack(vma, addr))) {
|
||||
tsk->thread.bad_cause = cause;
|
||||
bad_area(regs, mm, code, addr);
|
||||
return;
|
||||
}
|
||||
|
@ -264,6 +288,7 @@ good_area:
|
|||
code = SEGV_ACCERR;
|
||||
|
||||
if (unlikely(access_error(cause, vma))) {
|
||||
tsk->thread.bad_cause = cause;
|
||||
bad_area(regs, mm, code, addr);
|
||||
return;
|
||||
}
|
||||
|
@ -297,6 +322,7 @@ good_area:
|
|||
mmap_read_unlock(mm);
|
||||
|
||||
if (unlikely(fault & VM_FAULT_ERROR)) {
|
||||
tsk->thread.bad_cause = cause;
|
||||
mm_fault_error(regs, addr, fault);
|
||||
return;
|
||||
}
|
||||
|
|
|
@ -21,6 +21,7 @@
|
|||
#include <asm/soc.h>
|
||||
#include <asm/io.h>
|
||||
#include <asm/ptdump.h>
|
||||
#include <asm/numa.h>
|
||||
|
||||
#include "../kernel/head.h"
|
||||
|
||||
|
@ -105,55 +106,6 @@ void __init mem_init(void)
|
|||
print_vm_layout();
|
||||
}
|
||||
|
||||
#ifdef CONFIG_BLK_DEV_INITRD
|
||||
static void __init setup_initrd(void)
|
||||
{
|
||||
phys_addr_t start;
|
||||
unsigned long size;
|
||||
|
||||
/* Ignore the virtul address computed during device tree parsing */
|
||||
initrd_start = initrd_end = 0;
|
||||
|
||||
if (!phys_initrd_size)
|
||||
return;
|
||||
/*
|
||||
* Round the memory region to page boundaries as per free_initrd_mem()
|
||||
* This allows us to detect whether the pages overlapping the initrd
|
||||
* are in use, but more importantly, reserves the entire set of pages
|
||||
* as we don't want these pages allocated for other purposes.
|
||||
*/
|
||||
start = round_down(phys_initrd_start, PAGE_SIZE);
|
||||
size = phys_initrd_size + (phys_initrd_start - start);
|
||||
size = round_up(size, PAGE_SIZE);
|
||||
|
||||
if (!memblock_is_region_memory(start, size)) {
|
||||
pr_err("INITRD: 0x%08llx+0x%08lx is not a memory region",
|
||||
(u64)start, size);
|
||||
goto disable;
|
||||
}
|
||||
|
||||
if (memblock_is_region_reserved(start, size)) {
|
||||
pr_err("INITRD: 0x%08llx+0x%08lx overlaps in-use memory region\n",
|
||||
(u64)start, size);
|
||||
goto disable;
|
||||
}
|
||||
|
||||
memblock_reserve(start, size);
|
||||
/* Now convert initrd to virtual addresses */
|
||||
initrd_start = (unsigned long)__va(phys_initrd_start);
|
||||
initrd_end = initrd_start + phys_initrd_size;
|
||||
initrd_below_start_ok = 1;
|
||||
|
||||
pr_info("Initial ramdisk at: 0x%p (%lu bytes)\n",
|
||||
(void *)(initrd_start), size);
|
||||
return;
|
||||
disable:
|
||||
pr_cont(" - disabling initrd\n");
|
||||
initrd_start = 0;
|
||||
initrd_end = 0;
|
||||
}
|
||||
#endif /* CONFIG_BLK_DEV_INITRD */
|
||||
|
||||
void __init setup_bootmem(void)
|
||||
{
|
||||
phys_addr_t mem_start = 0;
|
||||
|
@ -198,20 +150,19 @@ void __init setup_bootmem(void)
|
|||
dma32_phys_limit = min(4UL * SZ_1G, (unsigned long)PFN_PHYS(max_low_pfn));
|
||||
set_max_mapnr(max_low_pfn - ARCH_PFN_OFFSET);
|
||||
|
||||
#ifdef CONFIG_BLK_DEV_INITRD
|
||||
setup_initrd();
|
||||
#endif /* CONFIG_BLK_DEV_INITRD */
|
||||
|
||||
reserve_initrd_mem();
|
||||
/*
|
||||
* Avoid using early_init_fdt_reserve_self() since __pa() does
|
||||
* If DTB is built in, no need to reserve its memblock.
|
||||
* Otherwise, do reserve it but avoid using
|
||||
* early_init_fdt_reserve_self() since __pa() does
|
||||
* not work for DTB pointers that are fixmap addresses
|
||||
*/
|
||||
memblock_reserve(dtb_early_pa, fdt_totalsize(dtb_early_va));
|
||||
if (!IS_ENABLED(CONFIG_BUILTIN_DTB))
|
||||
memblock_reserve(dtb_early_pa, fdt_totalsize(dtb_early_va));
|
||||
|
||||
early_init_fdt_scan_reserved_mem();
|
||||
dma_contiguous_reserve(dma32_phys_limit);
|
||||
memblock_allow_resize();
|
||||
memblock_dump_all();
|
||||
}
|
||||
|
||||
#ifdef CONFIG_MMU
|
||||
|
@ -226,8 +177,6 @@ pgd_t swapper_pg_dir[PTRS_PER_PGD] __page_aligned_bss;
|
|||
pgd_t trampoline_pg_dir[PTRS_PER_PGD] __page_aligned_bss;
|
||||
pte_t fixmap_pte[PTRS_PER_PTE] __page_aligned_bss;
|
||||
|
||||
#define MAX_EARLY_MAPPING_SIZE SZ_128M
|
||||
|
||||
pgd_t early_pg_dir[PTRS_PER_PGD] __initdata __aligned(PAGE_SIZE);
|
||||
|
||||
void __set_fixmap(enum fixed_addresses idx, phys_addr_t phys, pgprot_t prot)
|
||||
|
@ -302,13 +251,7 @@ static void __init create_pte_mapping(pte_t *ptep,
|
|||
|
||||
pmd_t trampoline_pmd[PTRS_PER_PMD] __page_aligned_bss;
|
||||
pmd_t fixmap_pmd[PTRS_PER_PMD] __page_aligned_bss;
|
||||
|
||||
#if MAX_EARLY_MAPPING_SIZE < PGDIR_SIZE
|
||||
#define NUM_EARLY_PMDS 1UL
|
||||
#else
|
||||
#define NUM_EARLY_PMDS (1UL + MAX_EARLY_MAPPING_SIZE / PGDIR_SIZE)
|
||||
#endif
|
||||
pmd_t early_pmd[PTRS_PER_PMD * NUM_EARLY_PMDS] __initdata __aligned(PAGE_SIZE);
|
||||
pmd_t early_pmd[PTRS_PER_PMD] __initdata __aligned(PAGE_SIZE);
|
||||
pmd_t early_dtb_pmd[PTRS_PER_PMD] __initdata __aligned(PAGE_SIZE);
|
||||
|
||||
static pmd_t *__init get_pmd_virt_early(phys_addr_t pa)
|
||||
|
@ -330,11 +273,9 @@ static pmd_t *get_pmd_virt_late(phys_addr_t pa)
|
|||
|
||||
static phys_addr_t __init alloc_pmd_early(uintptr_t va)
|
||||
{
|
||||
uintptr_t pmd_num;
|
||||
BUG_ON((va - PAGE_OFFSET) >> PGDIR_SHIFT);
|
||||
|
||||
pmd_num = (va - PAGE_OFFSET) >> PGDIR_SHIFT;
|
||||
BUG_ON(pmd_num >= NUM_EARLY_PMDS);
|
||||
return (uintptr_t)&early_pmd[pmd_num * PTRS_PER_PMD];
|
||||
return (uintptr_t)early_pmd;
|
||||
}
|
||||
|
||||
static phys_addr_t __init alloc_pmd_fixmap(uintptr_t va)
|
||||
|
@ -452,7 +393,7 @@ asmlinkage void __init setup_vm(uintptr_t dtb_pa)
|
|||
uintptr_t va, pa, end_va;
|
||||
uintptr_t load_pa = (uintptr_t)(&_start);
|
||||
uintptr_t load_sz = (uintptr_t)(&_end) - load_pa;
|
||||
uintptr_t map_size = best_map_size(load_pa, MAX_EARLY_MAPPING_SIZE);
|
||||
uintptr_t map_size;
|
||||
#ifndef __PAGETABLE_PMD_FOLDED
|
||||
pmd_t fix_bmap_spmd, fix_bmap_epmd;
|
||||
#endif
|
||||
|
@ -464,12 +405,11 @@ asmlinkage void __init setup_vm(uintptr_t dtb_pa)
|
|||
* Enforce boot alignment requirements of RV32 and
|
||||
* RV64 by only allowing PMD or PGD mappings.
|
||||
*/
|
||||
BUG_ON(map_size == PAGE_SIZE);
|
||||
map_size = PMD_SIZE;
|
||||
|
||||
/* Sanity check alignment and size */
|
||||
BUG_ON((PAGE_OFFSET % PGDIR_SIZE) != 0);
|
||||
BUG_ON((load_pa % map_size) != 0);
|
||||
BUG_ON(load_sz > MAX_EARLY_MAPPING_SIZE);
|
||||
|
||||
pt_ops.alloc_pte = alloc_pte_early;
|
||||
pt_ops.get_pte_virt = get_pte_virt_early;
|
||||
|
@ -511,6 +451,7 @@ asmlinkage void __init setup_vm(uintptr_t dtb_pa)
|
|||
/* Setup early PMD for DTB */
|
||||
create_pgd_mapping(early_pg_dir, DTB_EARLY_BASE_VA,
|
||||
(uintptr_t)early_dtb_pmd, PGDIR_SIZE, PAGE_TABLE);
|
||||
#ifndef CONFIG_BUILTIN_DTB
|
||||
/* Create two consecutive PMD mappings for FDT early scan */
|
||||
pa = dtb_pa & ~(PMD_SIZE - 1);
|
||||
create_pmd_mapping(early_dtb_pmd, DTB_EARLY_BASE_VA,
|
||||
|
@ -518,7 +459,11 @@ asmlinkage void __init setup_vm(uintptr_t dtb_pa)
|
|||
create_pmd_mapping(early_dtb_pmd, DTB_EARLY_BASE_VA + PMD_SIZE,
|
||||
pa + PMD_SIZE, PMD_SIZE, PAGE_KERNEL);
|
||||
dtb_early_va = (void *)DTB_EARLY_BASE_VA + (dtb_pa & (PMD_SIZE - 1));
|
||||
#else /* CONFIG_BUILTIN_DTB */
|
||||
dtb_early_va = __va(dtb_pa);
|
||||
#endif /* CONFIG_BUILTIN_DTB */
|
||||
#else
|
||||
#ifndef CONFIG_BUILTIN_DTB
|
||||
/* Create two consecutive PGD mappings for FDT early scan */
|
||||
pa = dtb_pa & ~(PGDIR_SIZE - 1);
|
||||
create_pgd_mapping(early_pg_dir, DTB_EARLY_BASE_VA,
|
||||
|
@ -526,6 +471,9 @@ asmlinkage void __init setup_vm(uintptr_t dtb_pa)
|
|||
create_pgd_mapping(early_pg_dir, DTB_EARLY_BASE_VA + PGDIR_SIZE,
|
||||
pa + PGDIR_SIZE, PGDIR_SIZE, PAGE_KERNEL);
|
||||
dtb_early_va = (void *)DTB_EARLY_BASE_VA + (dtb_pa & (PGDIR_SIZE - 1));
|
||||
#else /* CONFIG_BUILTIN_DTB */
|
||||
dtb_early_va = __va(dtb_pa);
|
||||
#endif /* CONFIG_BUILTIN_DTB */
|
||||
#endif
|
||||
dtb_early_pa = dtb_pa;
|
||||
|
||||
|
@ -616,15 +564,7 @@ static void __init setup_vm_final(void)
|
|||
#else
|
||||
asmlinkage void __init setup_vm(uintptr_t dtb_pa)
|
||||
{
|
||||
#ifdef CONFIG_BUILTIN_DTB
|
||||
dtb_early_va = soc_lookup_builtin_dtb();
|
||||
if (!dtb_early_va) {
|
||||
/* Fallback to first available DTS */
|
||||
dtb_early_va = (void *) __dtb_start;
|
||||
}
|
||||
#else
|
||||
dtb_early_va = (void *)dtb_pa;
|
||||
#endif
|
||||
dtb_early_pa = dtb_pa;
|
||||
}
|
||||
|
||||
|
@ -665,9 +605,15 @@ void mark_rodata_ro(void)
|
|||
void __init paging_init(void)
|
||||
{
|
||||
setup_vm_final();
|
||||
sparse_init();
|
||||
setup_zero_page();
|
||||
}
|
||||
|
||||
void __init misc_mem_init(void)
|
||||
{
|
||||
arch_numa_init();
|
||||
sparse_init();
|
||||
zone_sizes_init();
|
||||
memblock_dump_all();
|
||||
}
|
||||
|
||||
#ifdef CONFIG_SPARSEMEM_VMEMMAP
|
||||
|
|
|
@ -9,6 +9,19 @@
|
|||
#include <linux/pgtable.h>
|
||||
#include <asm/tlbflush.h>
|
||||
#include <asm/fixmap.h>
|
||||
#include <asm/pgalloc.h>
|
||||
|
||||
static __init void *early_alloc(size_t size, int node)
|
||||
{
|
||||
void *ptr = memblock_alloc_try_nid(size, size,
|
||||
__pa(MAX_DMA_ADDRESS), MEMBLOCK_ALLOC_ACCESSIBLE, node);
|
||||
|
||||
if (!ptr)
|
||||
panic("%pS: Failed to allocate %zu bytes align=%zx nid=%d from=%llx\n",
|
||||
__func__, size, size, node, (u64)__pa(MAX_DMA_ADDRESS));
|
||||
|
||||
return ptr;
|
||||
}
|
||||
|
||||
extern pgd_t early_pg_dir[PTRS_PER_PGD];
|
||||
asmlinkage void __init kasan_early_init(void)
|
||||
|
@ -47,40 +60,133 @@ asmlinkage void __init kasan_early_init(void)
|
|||
local_flush_tlb_all();
|
||||
}
|
||||
|
||||
static void __init populate(void *start, void *end)
|
||||
static void kasan_populate_pte(pmd_t *pmd, unsigned long vaddr, unsigned long end)
|
||||
{
|
||||
phys_addr_t phys_addr;
|
||||
pte_t *ptep, *base_pte;
|
||||
|
||||
if (pmd_none(*pmd))
|
||||
base_pte = memblock_alloc(PTRS_PER_PTE * sizeof(pte_t), PAGE_SIZE);
|
||||
else
|
||||
base_pte = (pte_t *)pmd_page_vaddr(*pmd);
|
||||
|
||||
ptep = base_pte + pte_index(vaddr);
|
||||
|
||||
do {
|
||||
if (pte_none(*ptep)) {
|
||||
phys_addr = memblock_phys_alloc(PAGE_SIZE, PAGE_SIZE);
|
||||
set_pte(ptep, pfn_pte(PFN_DOWN(phys_addr), PAGE_KERNEL));
|
||||
}
|
||||
} while (ptep++, vaddr += PAGE_SIZE, vaddr != end);
|
||||
|
||||
set_pmd(pmd, pfn_pmd(PFN_DOWN(__pa(base_pte)), PAGE_TABLE));
|
||||
}
|
||||
|
||||
static void kasan_populate_pmd(pgd_t *pgd, unsigned long vaddr, unsigned long end)
|
||||
{
|
||||
phys_addr_t phys_addr;
|
||||
pmd_t *pmdp, *base_pmd;
|
||||
unsigned long next;
|
||||
|
||||
base_pmd = (pmd_t *)pgd_page_vaddr(*pgd);
|
||||
if (base_pmd == lm_alias(kasan_early_shadow_pmd))
|
||||
base_pmd = memblock_alloc(PTRS_PER_PMD * sizeof(pmd_t), PAGE_SIZE);
|
||||
|
||||
pmdp = base_pmd + pmd_index(vaddr);
|
||||
|
||||
do {
|
||||
next = pmd_addr_end(vaddr, end);
|
||||
|
||||
if (pmd_none(*pmdp) && IS_ALIGNED(vaddr, PMD_SIZE) && (next - vaddr) >= PMD_SIZE) {
|
||||
phys_addr = memblock_phys_alloc(PMD_SIZE, PMD_SIZE);
|
||||
if (phys_addr) {
|
||||
set_pmd(pmdp, pfn_pmd(PFN_DOWN(phys_addr), PAGE_KERNEL));
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
kasan_populate_pte(pmdp, vaddr, next);
|
||||
} while (pmdp++, vaddr = next, vaddr != end);
|
||||
|
||||
/*
|
||||
* Wait for the whole PGD to be populated before setting the PGD in
|
||||
* the page table, otherwise, if we did set the PGD before populating
|
||||
* it entirely, memblock could allocate a page at a physical address
|
||||
* where KASAN is not populated yet and then we'd get a page fault.
|
||||
*/
|
||||
set_pgd(pgd, pfn_pgd(PFN_DOWN(__pa(base_pmd)), PAGE_TABLE));
|
||||
}
|
||||
|
||||
static void kasan_populate_pgd(unsigned long vaddr, unsigned long end)
|
||||
{
|
||||
phys_addr_t phys_addr;
|
||||
pgd_t *pgdp = pgd_offset_k(vaddr);
|
||||
unsigned long next;
|
||||
|
||||
do {
|
||||
next = pgd_addr_end(vaddr, end);
|
||||
|
||||
/*
|
||||
* pgdp can't be none since kasan_early_init initialized all KASAN
|
||||
* shadow region with kasan_early_shadow_pmd: if this is stillthe case,
|
||||
* that means we can try to allocate a hugepage as a replacement.
|
||||
*/
|
||||
if (pgd_page_vaddr(*pgdp) == (unsigned long)lm_alias(kasan_early_shadow_pmd) &&
|
||||
IS_ALIGNED(vaddr, PGDIR_SIZE) && (next - vaddr) >= PGDIR_SIZE) {
|
||||
phys_addr = memblock_phys_alloc(PGDIR_SIZE, PGDIR_SIZE);
|
||||
if (phys_addr) {
|
||||
set_pgd(pgdp, pfn_pgd(PFN_DOWN(phys_addr), PAGE_KERNEL));
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
kasan_populate_pmd(pgdp, vaddr, next);
|
||||
} while (pgdp++, vaddr = next, vaddr != end);
|
||||
}
|
||||
|
||||
static void __init kasan_populate(void *start, void *end)
|
||||
{
|
||||
unsigned long i, offset;
|
||||
unsigned long vaddr = (unsigned long)start & PAGE_MASK;
|
||||
unsigned long vend = PAGE_ALIGN((unsigned long)end);
|
||||
unsigned long n_pages = (vend - vaddr) / PAGE_SIZE;
|
||||
unsigned long n_ptes =
|
||||
((n_pages + PTRS_PER_PTE) & -PTRS_PER_PTE) / PTRS_PER_PTE;
|
||||
unsigned long n_pmds =
|
||||
((n_ptes + PTRS_PER_PMD) & -PTRS_PER_PMD) / PTRS_PER_PMD;
|
||||
|
||||
pte_t *pte =
|
||||
memblock_alloc(n_ptes * PTRS_PER_PTE * sizeof(pte_t), PAGE_SIZE);
|
||||
pmd_t *pmd =
|
||||
memblock_alloc(n_pmds * PTRS_PER_PMD * sizeof(pmd_t), PAGE_SIZE);
|
||||
pgd_t *pgd = pgd_offset_k(vaddr);
|
||||
|
||||
for (i = 0; i < n_pages; i++) {
|
||||
phys_addr_t phys = memblock_phys_alloc(PAGE_SIZE, PAGE_SIZE);
|
||||
set_pte(&pte[i], pfn_pte(PHYS_PFN(phys), PAGE_KERNEL));
|
||||
}
|
||||
|
||||
for (i = 0, offset = 0; i < n_ptes; i++, offset += PTRS_PER_PTE)
|
||||
set_pmd(&pmd[i],
|
||||
pfn_pmd(PFN_DOWN(__pa(&pte[offset])),
|
||||
__pgprot(_PAGE_TABLE)));
|
||||
|
||||
for (i = 0, offset = 0; i < n_pmds; i++, offset += PTRS_PER_PMD)
|
||||
set_pgd(&pgd[i],
|
||||
pfn_pgd(PFN_DOWN(__pa(&pmd[offset])),
|
||||
__pgprot(_PAGE_TABLE)));
|
||||
kasan_populate_pgd(vaddr, vend);
|
||||
|
||||
local_flush_tlb_all();
|
||||
memset(start, 0, end - start);
|
||||
memset(start, KASAN_SHADOW_INIT, end - start);
|
||||
}
|
||||
|
||||
void __init kasan_shallow_populate(void *start, void *end)
|
||||
{
|
||||
unsigned long vaddr = (unsigned long)start & PAGE_MASK;
|
||||
unsigned long vend = PAGE_ALIGN((unsigned long)end);
|
||||
unsigned long pfn;
|
||||
int index;
|
||||
void *p;
|
||||
pud_t *pud_dir, *pud_k;
|
||||
pgd_t *pgd_dir, *pgd_k;
|
||||
p4d_t *p4d_dir, *p4d_k;
|
||||
|
||||
while (vaddr < vend) {
|
||||
index = pgd_index(vaddr);
|
||||
pfn = csr_read(CSR_SATP) & SATP_PPN;
|
||||
pgd_dir = (pgd_t *)pfn_to_virt(pfn) + index;
|
||||
pgd_k = init_mm.pgd + index;
|
||||
pgd_dir = pgd_offset_k(vaddr);
|
||||
set_pgd(pgd_dir, *pgd_k);
|
||||
|
||||
p4d_dir = p4d_offset(pgd_dir, vaddr);
|
||||
p4d_k = p4d_offset(pgd_k, vaddr);
|
||||
|
||||
vaddr = (vaddr + PUD_SIZE) & PUD_MASK;
|
||||
pud_dir = pud_offset(p4d_dir, vaddr);
|
||||
pud_k = pud_offset(p4d_k, vaddr);
|
||||
|
||||
if (pud_present(*pud_dir)) {
|
||||
p = early_alloc(PAGE_SIZE, NUMA_NO_NODE);
|
||||
pud_populate(&init_mm, pud_dir, p);
|
||||
}
|
||||
vaddr += PAGE_SIZE;
|
||||
}
|
||||
}
|
||||
|
||||
void __init kasan_init(void)
|
||||
|
@ -90,7 +196,15 @@ void __init kasan_init(void)
|
|||
|
||||
kasan_populate_early_shadow((void *)KASAN_SHADOW_START,
|
||||
(void *)kasan_mem_to_shadow((void *)
|
||||
VMALLOC_END));
|
||||
VMEMMAP_END));
|
||||
if (IS_ENABLED(CONFIG_KASAN_VMALLOC))
|
||||
kasan_shallow_populate(
|
||||
(void *)kasan_mem_to_shadow((void *)VMALLOC_START),
|
||||
(void *)kasan_mem_to_shadow((void *)VMALLOC_END));
|
||||
else
|
||||
kasan_populate_early_shadow(
|
||||
(void *)kasan_mem_to_shadow((void *)VMALLOC_START),
|
||||
(void *)kasan_mem_to_shadow((void *)VMALLOC_END));
|
||||
|
||||
for_each_mem_range(i, &_start, &_end) {
|
||||
void *start = (void *)__va(_start);
|
||||
|
@ -99,7 +213,7 @@ void __init kasan_init(void)
|
|||
if (start >= end)
|
||||
break;
|
||||
|
||||
populate(kasan_mem_to_shadow(start), kasan_mem_to_shadow(end));
|
||||
kasan_populate(kasan_mem_to_shadow(start), kasan_mem_to_shadow(end));
|
||||
};
|
||||
|
||||
for (i = 0; i < PTRS_PER_PTE; i++)
|
||||
|
@ -108,6 +222,6 @@ void __init kasan_init(void)
|
|||
__pgprot(_PAGE_PRESENT | _PAGE_READ |
|
||||
_PAGE_ACCESSED)));
|
||||
|
||||
memset(kasan_early_shadow_page, 0, PAGE_SIZE);
|
||||
memset(kasan_early_shadow_page, KASAN_SHADOW_INIT, PAGE_SIZE);
|
||||
init_task.kasan_depth = 0;
|
||||
}
|
||||
|
|
|
@ -213,4 +213,10 @@ config GENERIC_ARCH_TOPOLOGY
|
|||
appropriate scaling, sysfs interface for reading capacity values at
|
||||
runtime.
|
||||
|
||||
config GENERIC_ARCH_NUMA
|
||||
bool
|
||||
help
|
||||
Enable support for generic NUMA implementation. Currently, RISC-V
|
||||
and ARM64 use it.
|
||||
|
||||
endmenu
|
||||
|
|
|
@ -24,6 +24,7 @@ obj-$(CONFIG_PINCTRL) += pinctrl.o
|
|||
obj-$(CONFIG_DEV_COREDUMP) += devcoredump.o
|
||||
obj-$(CONFIG_GENERIC_MSI_IRQ_DOMAIN) += platform-msi.o
|
||||
obj-$(CONFIG_GENERIC_ARCH_TOPOLOGY) += arch_topology.o
|
||||
obj-$(CONFIG_GENERIC_ARCH_NUMA) += arch_numa.o
|
||||
|
||||
obj-y += test/
|
||||
|
||||
|
|
|
@ -13,7 +13,6 @@
|
|||
#include <linux/module.h>
|
||||
#include <linux/of.h>
|
||||
|
||||
#include <asm/acpi.h>
|
||||
#include <asm/sections.h>
|
||||
|
||||
struct pglist_data *node_data[MAX_NUMNODES] __read_mostly;
|
||||
|
@ -356,11 +355,12 @@ static int __init numa_register_nodes(void)
|
|||
/* Check that valid nid is set to memblks */
|
||||
for_each_mem_region(mblk) {
|
||||
int mblk_nid = memblock_get_region_node(mblk);
|
||||
phys_addr_t start = mblk->base;
|
||||
phys_addr_t end = mblk->base + mblk->size - 1;
|
||||
|
||||
if (mblk_nid == NUMA_NO_NODE || mblk_nid >= MAX_NUMNODES) {
|
||||
pr_warn("Warning: invalid memblk node %d [mem %#010Lx-%#010Lx]\n",
|
||||
mblk_nid, mblk->base,
|
||||
mblk->base + mblk->size - 1);
|
||||
pr_warn("Warning: invalid memblk node %d [mem %pap-%pap]\n",
|
||||
mblk_nid, &start, &end);
|
||||
return -EINVAL;
|
||||
}
|
||||
}
|
||||
|
@ -428,14 +428,14 @@ out_free_distance:
|
|||
static int __init dummy_numa_init(void)
|
||||
{
|
||||
phys_addr_t start = memblock_start_of_DRAM();
|
||||
phys_addr_t end = memblock_end_of_DRAM();
|
||||
phys_addr_t end = memblock_end_of_DRAM() - 1;
|
||||
int ret;
|
||||
|
||||
if (numa_off)
|
||||
pr_info("NUMA disabled\n"); /* Forced off on command line. */
|
||||
pr_info("Faking a node at [mem %#018Lx-%#018Lx]\n", start, end - 1);
|
||||
pr_info("Faking a node at [mem %pap-%pap]\n", &start, &end);
|
||||
|
||||
ret = numa_add_memblk(0, start, end);
|
||||
ret = numa_add_memblk(0, start, end + 1);
|
||||
if (ret) {
|
||||
pr_err("NUMA init failed\n");
|
||||
return ret;
|
||||
|
@ -445,16 +445,36 @@ static int __init dummy_numa_init(void)
|
|||
return 0;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_ACPI_NUMA
|
||||
static int __init arch_acpi_numa_init(void)
|
||||
{
|
||||
int ret;
|
||||
|
||||
ret = acpi_numa_init();
|
||||
if (ret) {
|
||||
pr_info("Failed to initialise from firmware\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
return srat_disabled() ? -EINVAL : 0;
|
||||
}
|
||||
#else
|
||||
static int __init arch_acpi_numa_init(void)
|
||||
{
|
||||
return -EOPNOTSUPP;
|
||||
}
|
||||
#endif
|
||||
|
||||
/**
|
||||
* arm64_numa_init() - Initialize NUMA
|
||||
* arch_numa_init() - Initialize NUMA
|
||||
*
|
||||
* Try each configured NUMA initialization method until one succeeds. The
|
||||
* last fallback is dummy single node config encompassing whole memory.
|
||||
*/
|
||||
void __init arm64_numa_init(void)
|
||||
void __init arch_numa_init(void)
|
||||
{
|
||||
if (!numa_off) {
|
||||
if (!acpi_disabled && !numa_init(arm64_acpi_numa_init))
|
||||
if (!acpi_disabled && !numa_init(arch_acpi_numa_init))
|
||||
return;
|
||||
if (acpi_disabled && !numa_init(of_numa_init))
|
||||
return;
|
|
@ -369,6 +369,13 @@ config COMMON_CLK_FIXED_MMIO
|
|||
help
|
||||
Support for Memory Mapped IO Fixed clocks
|
||||
|
||||
config COMMON_CLK_K210
|
||||
bool "Clock driver for the Canaan Kendryte K210 SoC"
|
||||
depends on OF && RISCV && SOC_CANAAN
|
||||
default SOC_CANAAN
|
||||
help
|
||||
Support for the Canaan Kendryte K210 RISC-V SoC clocks.
|
||||
|
||||
source "drivers/clk/actions/Kconfig"
|
||||
source "drivers/clk/analogbits/Kconfig"
|
||||
source "drivers/clk/baikal-t1/Kconfig"
|
||||
|
|
|
@ -36,6 +36,7 @@ obj-$(CONFIG_COMMON_CLK_ASPEED) += clk-aspeed.o
|
|||
obj-$(CONFIG_MACH_ASPEED_G6) += clk-ast2600.o
|
||||
obj-$(CONFIG_ARCH_HIGHBANK) += clk-highbank.o
|
||||
obj-$(CONFIG_CLK_HSDK) += clk-hsdk-pll.o
|
||||
obj-$(CONFIG_COMMON_CLK_K210) += clk-k210.o
|
||||
obj-$(CONFIG_COMMON_CLK_LOCHNAGAR) += clk-lochnagar.o
|
||||
obj-$(CONFIG_COMMON_CLK_MAX77686) += clk-max77686.o
|
||||
obj-$(CONFIG_COMMON_CLK_MAX9485) += clk-max9485.o
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -370,6 +370,19 @@ config PINCTRL_MICROCHIP_SGPIO
|
|||
connect control signals from SFP modules and to act as an
|
||||
LED controller.
|
||||
|
||||
config PINCTRL_K210
|
||||
bool "Pinctrl driver for the Canaan Kendryte K210 SoC"
|
||||
depends on RISCV && SOC_CANAAN && OF
|
||||
select GENERIC_PINMUX_FUNCTIONS
|
||||
select GENERIC_PINCONF
|
||||
select GPIOLIB
|
||||
select OF_GPIO
|
||||
select REGMAP_MMIO
|
||||
default SOC_CANAAN
|
||||
help
|
||||
Add support for the Canaan Kendryte K210 RISC-V SOC Field
|
||||
Programmable IO Array (FPIOA) controller.
|
||||
|
||||
source "drivers/pinctrl/actions/Kconfig"
|
||||
source "drivers/pinctrl/aspeed/Kconfig"
|
||||
source "drivers/pinctrl/bcm/Kconfig"
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue