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:
Linus Torvalds 2021-02-26 10:28:35 -08:00
commit 8b83369ddc
121 changed files with 7605 additions and 1040 deletions

View File

@ -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:

View File

@ -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:

View File

@ -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>;
};
};

View File

@ -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)>;
};
};

View File

@ -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.

View File

@ -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>;
};

View File

@ -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
...

View File

@ -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:

View File

@ -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:

View File

@ -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

View File

@ -20,6 +20,7 @@ properties:
- enum:
- sifive,fu540-c000-uart
- sifive,fu740-c000-uart
- canaan,k210-uarths
- const: sifive,uart0
description:

View File

@ -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:

View File

@ -24,6 +24,9 @@ properties:
interrupts:
maxItems: 1
resets:
maxItems: 1
clocks:
minItems: 1
items:

View File

@ -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)

View File

@ -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

View File

@ -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 */

View File

@ -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;
}

View File

@ -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

View File

@ -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.
*/

View File

@ -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"

View File

@ -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

View File

@ -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

View File

@ -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))

View File

@ -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

View File

@ -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;
};
};

View File

@ -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>;
};
};
};
};

View File

@ -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";
};

View File

@ -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;
};
};

View File

@ -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;
};
};

View File

@ -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;
};
};

View File

@ -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;
};
};

View File

@ -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))

View File

@ -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";
};

View File

@ -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>;
};
};
};

View File

@ -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

View File

@ -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 = &eth0;
};
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";
};
};
};

View File

@ -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;
};
};
&eth0 {
status = "okay";
phy-mode = "gmii";
phy-handle = <&phy0>;
phy0: ethernet-phy@0 {
reg = <0>;
};
};
&pwm0 {
status = "okay";
};
&pwm1 {
status = "okay";
};
&gpio {
status = "okay";
};

View File

@ -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

View File

@ -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

View File

@ -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);

View File

@ -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 */

View File

@ -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)))

View File

@ -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 */

View File

@ -12,6 +12,8 @@
typedef struct {
#ifndef CONFIG_MMU
unsigned long end_brk;
#else
atomic_long_t id;
#endif
void *vdso;
#ifdef CONFIG_SMP

View File

@ -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 */

View File

@ -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 */

View File

@ -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 */

View File

@ -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)

View File

@ -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 */

View File

@ -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

View File

@ -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 */

View File

@ -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 { \

View File

@ -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 */

View File

@ -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 */

View File

@ -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

View File

@ -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

View File

@ -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 */

View File

@ -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 */

View File

@ -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 | \

View File

@ -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 */

View File

@ -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

View File

@ -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);

View File

@ -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 */

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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)
{

View File

@ -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)

View File

@ -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;
}

View File

@ -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 */

View File

@ -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;
}

View File

@ -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;
}

View File

@ -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)

View File

@ -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;
}

View File

@ -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 */

View File

@ -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);
}

View File

@ -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)

View File

@ -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);

View File

@ -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;
}

View File

@ -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;

View File

@ -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);

View File

@ -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);

View File

@ -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;
}

View File

@ -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)

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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);

View File

@ -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

View File

@ -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(&current_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, &current_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(&current_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(&current_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(&current_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);
}

View File

@ -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;
}

View File

@ -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

View File

@ -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;
}

View File

@ -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

View File

@ -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/

View File

@ -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;

View File

@ -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"

View File

@ -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

1007
drivers/clk/clk-k210.c Normal file

File diff suppressed because it is too large Load Diff

View File

@ -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