Merge tag 'riscv-for-linus-5.8-mw0' of git://git.kernel.org/pub/scm/linux/kernel...
authorLinus Torvalds <torvalds@linux-foundation.org>
Fri, 5 Jun 2020 03:14:18 +0000 (20:14 -0700)
committerLinus Torvalds <torvalds@linux-foundation.org>
Fri, 5 Jun 2020 03:14:18 +0000 (20:14 -0700)
Pull RISC-V updates from Palmer Dabbelt:

 - The remainder of the code necessary to support the Kendryte K210:

     * Support for building device trees into the kernel, as the K210
       doesn't have a bootloader that provides one

     * A K210 device tree and the associated defconfig update

     * Support for skipping PMP initialization on systems that trap on
       PMP accesses rather than treating them as WARL

 - Support for KGDB

 - Improvements to text patching

 - Some cleanups to the SiFive L2 cache driver

* tag 'riscv-for-linus-5.8-mw0' of git://git.kernel.org/pub/scm/linux/kernel/git/riscv/linux:
  soc: sifive: l2 cache: Mark l2_get_priv_group as static
  soc: sifive: l2 cache: Eliminate an unsigned zero compare warning
  riscv: Add support to determine no. of L2 cache way enabled
  riscv: cacheinfo: Implement cache_get_priv_group with a generic ops structure
  riscv: Use text_mutex instead of patch_lock
  riscv: Use NOKPROBE_SYMBOL() instead of __krpobes annotation
  riscv: Remove the 'riscv_' prefix of function name
  riscv: Add SW single-step support for KDB
  riscv: Use the XML target descriptions to report 3 system registers
  riscv: Add KGDB support
  kgdb: Add kgdb_has_hit_break function
  RISC-V: Skip setting up PMPs on traps
  riscv: K210: Update defconfig
  riscv: K210: Add a built-in device tree
  riscv: Allow device trees to be built into the kernel

27 files changed:
arch/riscv/Kbuild
arch/riscv/Kconfig
arch/riscv/Kconfig.socs
arch/riscv/boot/dts/Makefile
arch/riscv/boot/dts/kendryte/Makefile
arch/riscv/configs/nommu_k210_defconfig
arch/riscv/include/asm/cacheinfo.h [new file with mode: 0644]
arch/riscv/include/asm/gdb_xml.h [new file with mode: 0644]
arch/riscv/include/asm/kdebug.h [new file with mode: 0644]
arch/riscv/include/asm/kgdb.h [new file with mode: 0644]
arch/riscv/include/asm/parse_asm.h [new file with mode: 0644]
arch/riscv/include/asm/patch.h
arch/riscv/include/asm/soc.h
arch/riscv/kernel/Makefile
arch/riscv/kernel/cacheinfo.c
arch/riscv/kernel/ftrace.c
arch/riscv/kernel/head.S
arch/riscv/kernel/kgdb.c [new file with mode: 0644]
arch/riscv/kernel/patch.c
arch/riscv/kernel/setup.c
arch/riscv/kernel/soc.c
arch/riscv/kernel/traps.c
arch/riscv/kernel/vmlinux.lds.S
arch/riscv/mm/init.c
drivers/soc/kendryte/k210-sysctl.c
drivers/soc/sifive/sifive_l2_cache.c
kernel/debug/debug_core.c

index d1d0aa7..4614c01 100644 (file)
@@ -1,3 +1,4 @@
 # SPDX-License-Identifier: GPL-2.0-only
 
 obj-y += kernel/ mm/ net/
+obj-$(CONFIG_BUILTIN_DTB) += boot/dts/
index 6841820..c733007 100644 (file)
@@ -68,6 +68,8 @@ config RISCV
        select ARCH_HAS_GCOV_PROFILE_ALL
        select HAVE_COPY_THREAD_TLS
        select HAVE_ARCH_KASAN if MMU && 64BIT
+       select HAVE_ARCH_KGDB
+       select HAVE_ARCH_KGDB_QXFER_PKT
 
 config ARCH_MMAP_RND_BITS_MIN
        default 18 if 64BIT
@@ -381,6 +383,11 @@ endchoice
 
 endmenu
 
+config BUILTIN_DTB
+       def_bool n
+       depends on RISCV_M_MODE
+       depends on OF
+
 menu "Power management options"
 
 source "kernel/power/Kconfig"
index d646332..6c88148 100644 (file)
@@ -24,11 +24,26 @@ config SOC_VIRT
 config SOC_KENDRYTE
        bool "Kendryte K210 SoC"
        depends on !MMU
-       select BUILTIN_DTB
        select SERIAL_SIFIVE if TTY
        select SERIAL_SIFIVE_CONSOLE if TTY
        select SIFIVE_PLIC
        help
          This enables support for Kendryte K210 SoC platform hardware.
 
+config SOC_KENDRYTE_K210_DTB
+       def_bool y
+       depends on SOC_KENDRYTE_K210_DTB_BUILTIN
+
+config SOC_KENDRYTE_K210_DTB_BUILTIN
+       bool "Builtin device tree for the Kendryte K210"
+       depends on SOC_KENDRYTE
+       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.
+         This option should be selected if no bootloader is being used.
+         If unsure, say Y.
+
 endmenu
index 557f0b5..ca1f8cb 100644 (file)
@@ -1,3 +1,5 @@
 # SPDX-License-Identifier: GPL-2.0
 subdir-y += sifive
 subdir-y += kendryte
+
+obj-$(CONFIG_BUILTIN_DTB) := $(addsuffix /, $(subdir-y))
index 815444e..1a88e61 100644 (file)
@@ -1,2 +1,4 @@
 # SPDX-License-Identifier: GPL-2.0
-dtb-$(CONFIG_SOC_KENDRYTE) += k210.dtb
+dtb-$(CONFIG_SOC_KENDRYTE_K210_DTB) += k210.dtb
+
+obj-$(CONFIG_SOC_KENDRYTE_K210_DTB_BUILTIN) += $(addsuffix .o, $(dtb-y))
index 632aa2f..b48138e 100644 (file)
@@ -2,14 +2,12 @@
 CONFIG_LOG_BUF_SHIFT=15
 CONFIG_PRINTK_SAFE_LOG_BUF_SHIFT=12
 CONFIG_BLK_DEV_INITRD=y
-CONFIG_INITRAMFS_SOURCE=""
 CONFIG_INITRAMFS_FORCE=y
 # 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_BOOT_CONFIG is not set
 CONFIG_CC_OPTIMIZE_FOR_SIZE=y
 # CONFIG_SYSFS_SYSCALL is not set
 # CONFIG_FHANDLE is not set
@@ -35,8 +33,6 @@ CONFIG_SMP=y
 CONFIG_NR_CPUS=2
 CONFIG_CMDLINE="earlycon console=ttySIF0"
 CONFIG_CMDLINE_FORCE=y
-CONFIG_USE_BUILTIN_DTB=y
-CONFIG_BUILTIN_DTB_SOURCE="kendryte/k210"
 # CONFIG_BLOCK is not set
 CONFIG_BINFMT_FLAT=y
 # CONFIG_COREDUMP is not set
@@ -49,8 +45,8 @@ CONFIG_DEVTMPFS_MOUNT=y
 # CONFIG_SERIO is not set
 # CONFIG_LEGACY_PTYS is not set
 # CONFIG_LDISC_AUTOLOAD is not set
-# CONFIG_DEVMEM is not set
 # CONFIG_HW_RANDOM is not set
+# CONFIG_DEVMEM is not set
 # CONFIG_HWMON is not set
 # CONFIG_VGA_CONSOLE is not set
 # CONFIG_HID is not set
@@ -62,6 +58,7 @@ CONFIG_DEVTMPFS_MOUNT=y
 CONFIG_LSM="[]"
 CONFIG_PRINTK_TIME=y
 # 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
diff --git a/arch/riscv/include/asm/cacheinfo.h b/arch/riscv/include/asm/cacheinfo.h
new file mode 100644 (file)
index 0000000..5d9662e
--- /dev/null
@@ -0,0 +1,15 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+
+#ifndef _ASM_RISCV_CACHEINFO_H
+#define _ASM_RISCV_CACHEINFO_H
+
+#include <linux/cacheinfo.h>
+
+struct riscv_cacheinfo_ops {
+       const struct attribute_group * (*get_priv_group)(struct cacheinfo
+                                                       *this_leaf);
+};
+
+void riscv_set_cacheinfo_ops(struct riscv_cacheinfo_ops *ops);
+
+#endif /* _ASM_RISCV_CACHEINFO_H */
diff --git a/arch/riscv/include/asm/gdb_xml.h b/arch/riscv/include/asm/gdb_xml.h
new file mode 100644 (file)
index 0000000..041b45f
--- /dev/null
@@ -0,0 +1,117 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
+#ifndef __ASM_GDB_XML_H_
+#define __ASM_GDB_XML_H_
+
+#define kgdb_arch_gdb_stub_feature riscv_gdb_stub_feature
+static const char riscv_gdb_stub_feature[64] =
+                       "PacketSize=800;qXfer:features:read+;";
+
+static const char gdb_xfer_read_target[31] = "qXfer:features:read:target.xml:";
+
+#ifdef CONFIG_64BIT
+static const char gdb_xfer_read_cpuxml[39] =
+                       "qXfer:features:read:riscv-64bit-cpu.xml";
+
+static const char riscv_gdb_stub_target_desc[256] =
+"l<?xml version=\"1.0\"?>"
+"<!DOCTYPE target SYSTEM \"gdb-target.dtd\">"
+"<target>"
+"<xi:include href=\"riscv-64bit-cpu.xml\"/>"
+"</target>";
+
+static const char riscv_gdb_stub_cpuxml[2048] =
+"l<?xml version=\"1.0\"?>"
+"<!DOCTYPE feature SYSTEM \"gdb-target.dtd\">"
+"<feature name=\"org.gnu.gdb.riscv.cpu\">"
+"<reg name=\""DBG_REG_ZERO"\" bitsize=\"64\" type=\"int\" regnum=\"0\"/>"
+"<reg name=\""DBG_REG_RA"\" bitsize=\"64\" type=\"code_ptr\"/>"
+"<reg name=\""DBG_REG_SP"\" bitsize=\"64\" type=\"data_ptr\"/>"
+"<reg name=\""DBG_REG_GP"\" bitsize=\"64\" type=\"data_ptr\"/>"
+"<reg name=\""DBG_REG_TP"\" bitsize=\"64\" type=\"data_ptr\"/>"
+"<reg name=\""DBG_REG_T0"\" bitsize=\"64\" type=\"int\"/>"
+"<reg name=\""DBG_REG_T1"\" bitsize=\"64\" type=\"int\"/>"
+"<reg name=\""DBG_REG_T2"\" bitsize=\"64\" type=\"int\"/>"
+"<reg name=\""DBG_REG_FP"\" bitsize=\"64\" type=\"data_ptr\"/>"
+"<reg name=\""DBG_REG_S1"\" bitsize=\"64\" type=\"int\"/>"
+"<reg name=\""DBG_REG_A0"\" bitsize=\"64\" type=\"int\"/>"
+"<reg name=\""DBG_REG_A1"\" bitsize=\"64\" type=\"int\"/>"
+"<reg name=\""DBG_REG_A2"\" bitsize=\"64\" type=\"int\"/>"
+"<reg name=\""DBG_REG_A3"\" bitsize=\"64\" type=\"int\"/>"
+"<reg name=\""DBG_REG_A4"\" bitsize=\"64\" type=\"int\"/>"
+"<reg name=\""DBG_REG_A5"\" bitsize=\"64\" type=\"int\"/>"
+"<reg name=\""DBG_REG_A6"\" bitsize=\"64\" type=\"int\"/>"
+"<reg name=\""DBG_REG_A7"\" bitsize=\"64\" type=\"int\"/>"
+"<reg name=\""DBG_REG_S2"\" bitsize=\"64\" type=\"int\"/>"
+"<reg name=\""DBG_REG_S3"\" bitsize=\"64\" type=\"int\"/>"
+"<reg name=\""DBG_REG_S4"\" bitsize=\"64\" type=\"int\"/>"
+"<reg name=\""DBG_REG_S5"\" bitsize=\"64\" type=\"int\"/>"
+"<reg name=\""DBG_REG_S6"\" bitsize=\"64\" type=\"int\"/>"
+"<reg name=\""DBG_REG_S7"\" bitsize=\"64\" type=\"int\"/>"
+"<reg name=\""DBG_REG_S8"\" bitsize=\"64\" type=\"int\"/>"
+"<reg name=\""DBG_REG_S9"\" bitsize=\"64\" type=\"int\"/>"
+"<reg name=\""DBG_REG_S10"\" bitsize=\"64\" type=\"int\"/>"
+"<reg name=\""DBG_REG_S11"\" bitsize=\"64\" type=\"int\"/>"
+"<reg name=\""DBG_REG_T3"\" bitsize=\"64\" type=\"int\"/>"
+"<reg name=\""DBG_REG_T4"\" bitsize=\"64\" type=\"int\"/>"
+"<reg name=\""DBG_REG_T5"\" bitsize=\"64\" type=\"int\"/>"
+"<reg name=\""DBG_REG_T6"\" bitsize=\"64\" type=\"int\"/>"
+"<reg name=\""DBG_REG_EPC"\" bitsize=\"64\" type=\"code_ptr\"/>"
+"<reg name=\""DBG_REG_STATUS"\" bitsize=\"64\" type=\"int\"/>"
+"<reg name=\""DBG_REG_BADADDR"\" bitsize=\"64\" type=\"int\"/>"
+"<reg name=\""DBG_REG_CAUSE"\" bitsize=\"64\" type=\"int\"/>"
+"</feature>";
+#else
+static const char gdb_xfer_read_cpuxml[39] =
+                       "qXfer:features:read:riscv-32bit-cpu.xml";
+
+static const char riscv_gdb_stub_target_desc[256] =
+"l<?xml version=\"1.0\"?>"
+"<!DOCTYPE target SYSTEM \"gdb-target.dtd\">"
+"<target>"
+"<xi:include href=\"riscv-32bit-cpu.xml\"/>"
+"</target>";
+
+static const char riscv_gdb_stub_cpuxml[2048] =
+"l<?xml version=\"1.0\"?>"
+"<!DOCTYPE feature SYSTEM \"gdb-target.dtd\">"
+"<feature name=\"org.gnu.gdb.riscv.cpu\">"
+"<reg name=\""DBG_REG_ZERO"\" bitsize=\"32\" type=\"int\" regnum=\"0\"/>"
+"<reg name=\""DBG_REG_RA"\" bitsize=\"32\" type=\"code_ptr\"/>"
+"<reg name=\""DBG_REG_SP"\" bitsize=\"32\" type=\"data_ptr\"/>"
+"<reg name=\""DBG_REG_GP"\" bitsize=\"32\" type=\"data_ptr\"/>"
+"<reg name=\""DBG_REG_TP"\" bitsize=\"32\" type=\"data_ptr\"/>"
+"<reg name=\""DBG_REG_T0"\" bitsize=\"32\" type=\"int\"/>"
+"<reg name=\""DBG_REG_T1"\" bitsize=\"32\" type=\"int\"/>"
+"<reg name=\""DBG_REG_T2"\" bitsize=\"32\" type=\"int\"/>"
+"<reg name=\""DBG_REG_FP"\" bitsize=\"32\" type=\"data_ptr\"/>"
+"<reg name=\""DBG_REG_S1"\" bitsize=\"32\" type=\"int\"/>"
+"<reg name=\""DBG_REG_A0"\" bitsize=\"32\" type=\"int\"/>"
+"<reg name=\""DBG_REG_A1"\" bitsize=\"32\" type=\"int\"/>"
+"<reg name=\""DBG_REG_A2"\" bitsize=\"32\" type=\"int\"/>"
+"<reg name=\""DBG_REG_A3"\" bitsize=\"32\" type=\"int\"/>"
+"<reg name=\""DBG_REG_A4"\" bitsize=\"32\" type=\"int\"/>"
+"<reg name=\""DBG_REG_A5"\" bitsize=\"32\" type=\"int\"/>"
+"<reg name=\""DBG_REG_A6"\" bitsize=\"32\" type=\"int\"/>"
+"<reg name=\""DBG_REG_A7"\" bitsize=\"32\" type=\"int\"/>"
+"<reg name=\""DBG_REG_S2"\" bitsize=\"32\" type=\"int\"/>"
+"<reg name=\""DBG_REG_S3"\" bitsize=\"32\" type=\"int\"/>"
+"<reg name=\""DBG_REG_S4"\" bitsize=\"32\" type=\"int\"/>"
+"<reg name=\""DBG_REG_S5"\" bitsize=\"32\" type=\"int\"/>"
+"<reg name=\""DBG_REG_S6"\" bitsize=\"32\" type=\"int\"/>"
+"<reg name=\""DBG_REG_S7"\" bitsize=\"32\" type=\"int\"/>"
+"<reg name=\""DBG_REG_S8"\" bitsize=\"32\" type=\"int\"/>"
+"<reg name=\""DBG_REG_S9"\" bitsize=\"32\" type=\"int\"/>"
+"<reg name=\""DBG_REG_S10"\" bitsize=\"32\" type=\"int\"/>"
+"<reg name=\""DBG_REG_S11"\" bitsize=\"32\" type=\"int\"/>"
+"<reg name=\""DBG_REG_T3"\" bitsize=\"32\" type=\"int\"/>"
+"<reg name=\""DBG_REG_T4"\" bitsize=\"32\" type=\"int\"/>"
+"<reg name=\""DBG_REG_T5"\" bitsize=\"32\" type=\"int\"/>"
+"<reg name=\""DBG_REG_T6"\" bitsize=\"32\" type=\"int\"/>"
+"<reg name=\""DBG_REG_EPC"\" bitsize=\"32\" type=\"code_ptr\"/>"
+"<reg name=\""DBG_REG_STATUS"\" bitsize=\"32\" type=\"int\"/>"
+"<reg name=\""DBG_REG_BADADDR"\" bitsize=\"32\" type=\"int\"/>"
+"<reg name=\""DBG_REG_CAUSE"\" bitsize=\"32\" type=\"int\"/>"
+"</feature>";
+#endif
+#endif
diff --git a/arch/riscv/include/asm/kdebug.h b/arch/riscv/include/asm/kdebug.h
new file mode 100644 (file)
index 0000000..85ac004
--- /dev/null
@@ -0,0 +1,12 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
+#ifndef _ASM_ARC_KDEBUG_H
+#define _ASM_ARC_KDEBUG_H
+
+enum die_val {
+       DIE_UNUSED,
+       DIE_TRAP,
+       DIE_OOPS
+};
+
+#endif
diff --git a/arch/riscv/include/asm/kgdb.h b/arch/riscv/include/asm/kgdb.h
new file mode 100644 (file)
index 0000000..8177a45
--- /dev/null
@@ -0,0 +1,112 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
+#ifndef __ASM_KGDB_H_
+#define __ASM_KGDB_H_
+
+#ifdef __KERNEL__
+
+#define GDB_SIZEOF_REG sizeof(unsigned long)
+
+#define DBG_MAX_REG_NUM (36)
+#define NUMREGBYTES ((DBG_MAX_REG_NUM) * GDB_SIZEOF_REG)
+#define CACHE_FLUSH_IS_SAFE     1
+#define BUFMAX                  2048
+#ifdef CONFIG_RISCV_ISA_C
+#define BREAK_INSTR_SIZE       2
+#else
+#define BREAK_INSTR_SIZE       4
+#endif
+
+#ifndef        __ASSEMBLY__
+
+extern int kgdb_has_hit_break(unsigned long addr);
+extern unsigned long kgdb_compiled_break;
+
+static inline void arch_kgdb_breakpoint(void)
+{
+       asm(".global kgdb_compiled_break\n"
+           ".option norvc\n"
+           "kgdb_compiled_break: ebreak\n"
+           ".option rvc\n");
+}
+
+#endif /* !__ASSEMBLY__ */
+
+#define DBG_REG_ZERO "zero"
+#define DBG_REG_RA "ra"
+#define DBG_REG_SP "sp"
+#define DBG_REG_GP "gp"
+#define DBG_REG_TP "tp"
+#define DBG_REG_T0 "t0"
+#define DBG_REG_T1 "t1"
+#define DBG_REG_T2 "t2"
+#define DBG_REG_FP "fp"
+#define DBG_REG_S1 "s1"
+#define DBG_REG_A0 "a0"
+#define DBG_REG_A1 "a1"
+#define DBG_REG_A2 "a2"
+#define DBG_REG_A3 "a3"
+#define DBG_REG_A4 "a4"
+#define DBG_REG_A5 "a5"
+#define DBG_REG_A6 "a6"
+#define DBG_REG_A7 "a7"
+#define DBG_REG_S2 "s2"
+#define DBG_REG_S3 "s3"
+#define DBG_REG_S4 "s4"
+#define DBG_REG_S5 "s5"
+#define DBG_REG_S6 "s6"
+#define DBG_REG_S7 "s7"
+#define DBG_REG_S8 "s8"
+#define DBG_REG_S9 "s9"
+#define DBG_REG_S10 "s10"
+#define DBG_REG_S11 "s11"
+#define DBG_REG_T3 "t3"
+#define DBG_REG_T4 "t4"
+#define DBG_REG_T5 "t5"
+#define DBG_REG_T6 "t6"
+#define DBG_REG_EPC "pc"
+#define DBG_REG_STATUS "sstatus"
+#define DBG_REG_BADADDR "stval"
+#define DBG_REG_CAUSE "scause"
+
+#define DBG_REG_ZERO_OFF 0
+#define DBG_REG_RA_OFF 1
+#define DBG_REG_SP_OFF 2
+#define DBG_REG_GP_OFF 3
+#define DBG_REG_TP_OFF 4
+#define DBG_REG_T0_OFF 5
+#define DBG_REG_T1_OFF 6
+#define DBG_REG_T2_OFF 7
+#define DBG_REG_FP_OFF 8
+#define DBG_REG_S1_OFF 9
+#define DBG_REG_A0_OFF 10
+#define DBG_REG_A1_OFF 11
+#define DBG_REG_A2_OFF 12
+#define DBG_REG_A3_OFF 13
+#define DBG_REG_A4_OFF 14
+#define DBG_REG_A5_OFF 15
+#define DBG_REG_A6_OFF 16
+#define DBG_REG_A7_OFF 17
+#define DBG_REG_S2_OFF 18
+#define DBG_REG_S3_OFF 19
+#define DBG_REG_S4_OFF 20
+#define DBG_REG_S5_OFF 21
+#define DBG_REG_S6_OFF 22
+#define DBG_REG_S7_OFF 23
+#define DBG_REG_S8_OFF 24
+#define DBG_REG_S9_OFF 25
+#define DBG_REG_S10_OFF 26
+#define DBG_REG_S11_OFF 27
+#define DBG_REG_T3_OFF 28
+#define DBG_REG_T4_OFF 29
+#define DBG_REG_T5_OFF 30
+#define DBG_REG_T6_OFF 31
+#define DBG_REG_EPC_OFF 32
+#define DBG_REG_STATUS_OFF 33
+#define DBG_REG_BADADDR_OFF 34
+#define DBG_REG_CAUSE_OFF 35
+
+#include <asm/gdb_xml.h>
+
+#endif
+#endif
diff --git a/arch/riscv/include/asm/parse_asm.h b/arch/riscv/include/asm/parse_asm.h
new file mode 100644 (file)
index 0000000..f36368d
--- /dev/null
@@ -0,0 +1,219 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/*
+ * Copyright (C) 2020 SiFive
+ */
+
+#include <linux/bits.h>
+
+/* The bit field of immediate value in I-type instruction */
+#define I_IMM_SIGN_OPOFF       31
+#define I_IMM_11_0_OPOFF       20
+#define I_IMM_SIGN_OFF         12
+#define I_IMM_11_0_OFF         0
+#define I_IMM_11_0_MASK                GENMASK(11, 0)
+
+/* The bit field of immediate value in J-type instruction */
+#define J_IMM_SIGN_OPOFF       31
+#define J_IMM_10_1_OPOFF       21
+#define J_IMM_11_OPOFF         20
+#define J_IMM_19_12_OPOFF      12
+#define J_IMM_SIGN_OFF         20
+#define J_IMM_10_1_OFF         1
+#define J_IMM_11_OFF           11
+#define J_IMM_19_12_OFF                12
+#define J_IMM_10_1_MASK                GENMASK(9, 0)
+#define J_IMM_11_MASK          GENMASK(0, 0)
+#define J_IMM_19_12_MASK       GENMASK(7, 0)
+
+/* The bit field of immediate value in B-type instruction */
+#define B_IMM_SIGN_OPOFF       31
+#define B_IMM_10_5_OPOFF       25
+#define B_IMM_4_1_OPOFF                8
+#define B_IMM_11_OPOFF         7
+#define B_IMM_SIGN_OFF         12
+#define B_IMM_10_5_OFF         5
+#define B_IMM_4_1_OFF          1
+#define B_IMM_11_OFF           11
+#define B_IMM_10_5_MASK                GENMASK(5, 0)
+#define B_IMM_4_1_MASK         GENMASK(3, 0)
+#define B_IMM_11_MASK          GENMASK(0, 0)
+
+/* The register offset in RVG instruction */
+#define RVG_RS1_OPOFF          15
+#define RVG_RS2_OPOFF          20
+#define RVG_RD_OPOFF           7
+
+/* The bit field of immediate value in RVC J instruction */
+#define RVC_J_IMM_SIGN_OPOFF   12
+#define RVC_J_IMM_4_OPOFF      11
+#define RVC_J_IMM_9_8_OPOFF    9
+#define RVC_J_IMM_10_OPOFF     8
+#define RVC_J_IMM_6_OPOFF      7
+#define RVC_J_IMM_7_OPOFF      6
+#define RVC_J_IMM_3_1_OPOFF    3
+#define RVC_J_IMM_5_OPOFF      2
+#define RVC_J_IMM_SIGN_OFF     11
+#define RVC_J_IMM_4_OFF                4
+#define RVC_J_IMM_9_8_OFF      8
+#define RVC_J_IMM_10_OFF       10
+#define RVC_J_IMM_6_OFF                6
+#define RVC_J_IMM_7_OFF                7
+#define RVC_J_IMM_3_1_OFF      1
+#define RVC_J_IMM_5_OFF                5
+#define RVC_J_IMM_4_MASK       GENMASK(0, 0)
+#define RVC_J_IMM_9_8_MASK     GENMASK(1, 0)
+#define RVC_J_IMM_10_MASK      GENMASK(0, 0)
+#define RVC_J_IMM_6_MASK       GENMASK(0, 0)
+#define RVC_J_IMM_7_MASK       GENMASK(0, 0)
+#define RVC_J_IMM_3_1_MASK     GENMASK(2, 0)
+#define RVC_J_IMM_5_MASK       GENMASK(0, 0)
+
+/* The bit field of immediate value in RVC B instruction */
+#define RVC_B_IMM_SIGN_OPOFF   12
+#define RVC_B_IMM_4_3_OPOFF    10
+#define RVC_B_IMM_7_6_OPOFF    5
+#define RVC_B_IMM_2_1_OPOFF    3
+#define RVC_B_IMM_5_OPOFF      2
+#define RVC_B_IMM_SIGN_OFF     8
+#define RVC_B_IMM_4_3_OFF      3
+#define RVC_B_IMM_7_6_OFF      6
+#define RVC_B_IMM_2_1_OFF      1
+#define RVC_B_IMM_5_OFF                5
+#define RVC_B_IMM_4_3_MASK     GENMASK(1, 0)
+#define RVC_B_IMM_7_6_MASK     GENMASK(1, 0)
+#define RVC_B_IMM_2_1_MASK     GENMASK(1, 0)
+#define RVC_B_IMM_5_MASK       GENMASK(0, 0)
+
+/* The register offset in RVC op=C0 instruction */
+#define RVC_C0_RS1_OPOFF       7
+#define RVC_C0_RS2_OPOFF       2
+#define RVC_C0_RD_OPOFF                2
+
+/* The register offset in RVC op=C1 instruction */
+#define RVC_C1_RS1_OPOFF       7
+#define RVC_C1_RS2_OPOFF       2
+#define RVC_C1_RD_OPOFF                7
+
+/* The register offset in RVC op=C2 instruction */
+#define RVC_C2_RS1_OPOFF       7
+#define RVC_C2_RS2_OPOFF       2
+#define RVC_C2_RD_OPOFF                7
+
+/* parts of opcode for RVG*/
+#define OPCODE_BRANCH          0x63
+#define OPCODE_JALR            0x67
+#define OPCODE_JAL             0x6f
+#define OPCODE_SYSTEM          0x73
+
+/* parts of opcode for RVC*/
+#define OPCODE_C_0             0x0
+#define OPCODE_C_1             0x1
+#define OPCODE_C_2             0x2
+
+/* parts of funct3 code for I, M, A extension*/
+#define FUNCT3_JALR            0x0
+#define FUNCT3_BEQ             0x0
+#define FUNCT3_BNE             0x1000
+#define FUNCT3_BLT             0x4000
+#define FUNCT3_BGE             0x5000
+#define FUNCT3_BLTU            0x6000
+#define FUNCT3_BGEU            0x7000
+
+/* parts of funct3 code for C extension*/
+#define FUNCT3_C_BEQZ          0xc000
+#define FUNCT3_C_BNEZ          0xe000
+#define FUNCT3_C_J             0xa000
+#define FUNCT3_C_JAL           0x2000
+#define FUNCT4_C_JR            0x8000
+#define FUNCT4_C_JALR          0xf000
+
+#define FUNCT12_SRET           0x10200000
+
+#define MATCH_JALR             (FUNCT3_JALR | OPCODE_JALR)
+#define MATCH_JAL              (OPCODE_JAL)
+#define MATCH_BEQ              (FUNCT3_BEQ | OPCODE_BRANCH)
+#define MATCH_BNE              (FUNCT3_BNE | OPCODE_BRANCH)
+#define MATCH_BLT              (FUNCT3_BLT | OPCODE_BRANCH)
+#define MATCH_BGE              (FUNCT3_BGE | OPCODE_BRANCH)
+#define MATCH_BLTU             (FUNCT3_BLTU | OPCODE_BRANCH)
+#define MATCH_BGEU             (FUNCT3_BGEU | OPCODE_BRANCH)
+#define MATCH_SRET             (FUNCT12_SRET | OPCODE_SYSTEM)
+#define MATCH_C_BEQZ           (FUNCT3_C_BEQZ | OPCODE_C_1)
+#define MATCH_C_BNEZ           (FUNCT3_C_BNEZ | OPCODE_C_1)
+#define MATCH_C_J              (FUNCT3_C_J | OPCODE_C_1)
+#define MATCH_C_JAL            (FUNCT3_C_JAL | OPCODE_C_1)
+#define MATCH_C_JR             (FUNCT4_C_JR | OPCODE_C_2)
+#define MATCH_C_JALR           (FUNCT4_C_JALR | OPCODE_C_2)
+
+#define MASK_JALR              0x707f
+#define MASK_JAL               0x7f
+#define MASK_C_JALR            0xf07f
+#define MASK_C_JR              0xf07f
+#define MASK_C_JAL             0xe003
+#define MASK_C_J               0xe003
+#define MASK_BEQ               0x707f
+#define MASK_BNE               0x707f
+#define MASK_BLT               0x707f
+#define MASK_BGE               0x707f
+#define MASK_BLTU              0x707f
+#define MASK_BGEU              0x707f
+#define MASK_C_BEQZ            0xe003
+#define MASK_C_BNEZ            0xe003
+#define MASK_SRET              0xffffffff
+
+#define __INSN_LENGTH_MASK     _UL(0x3)
+#define __INSN_LENGTH_GE_32    _UL(0x3)
+#define __INSN_OPCODE_MASK     _UL(0x7F)
+#define __INSN_BRANCH_OPCODE   _UL(OPCODE_BRANCH)
+
+/* Define a series of is_XXX_insn functions to check if the value INSN
+ * is an instance of instruction XXX.
+ */
+#define DECLARE_INSN(INSN_NAME, INSN_MATCH, INSN_MASK) \
+static inline bool is_ ## INSN_NAME ## _insn(long insn) \
+{ \
+       return (insn & (INSN_MASK)) == (INSN_MATCH); \
+}
+
+#define RV_IMM_SIGN(x) (-(((x) >> 31) & 1))
+#define RVC_IMM_SIGN(x) (-(((x) >> 12) & 1))
+#define RV_X(X, s, mask)  (((X) >> (s)) & (mask))
+#define RVC_X(X, s, mask) RV_X(X, s, mask)
+
+#define EXTRACT_JTYPE_IMM(x) \
+       ({typeof(x) x_ = (x); \
+       (RV_X(x_, J_IMM_10_1_OPOFF, J_IMM_10_1_MASK) << J_IMM_10_1_OFF) | \
+       (RV_X(x_, J_IMM_11_OPOFF, J_IMM_11_MASK) << J_IMM_11_OFF) | \
+       (RV_X(x_, J_IMM_19_12_OPOFF, J_IMM_19_12_MASK) << J_IMM_19_12_OFF) | \
+       (RV_IMM_SIGN(x_) << J_IMM_SIGN_OFF); })
+
+#define EXTRACT_ITYPE_IMM(x) \
+       ({typeof(x) x_ = (x); \
+       (RV_X(x_, I_IMM_11_0_OPOFF, I_IMM_11_0_MASK)) | \
+       (RV_IMM_SIGN(x_) << I_IMM_SIGN_OFF); })
+
+#define EXTRACT_BTYPE_IMM(x) \
+       ({typeof(x) x_ = (x); \
+       (RV_X(x_, B_IMM_4_1_OPOFF, B_IMM_4_1_MASK) << B_IMM_4_1_OFF) | \
+       (RV_X(x_, B_IMM_10_5_OPOFF, B_IMM_10_5_MASK) << B_IMM_10_5_OFF) | \
+       (RV_X(x_, B_IMM_11_OPOFF, B_IMM_11_MASK) << B_IMM_11_OFF) | \
+       (RV_IMM_SIGN(x_) << B_IMM_SIGN_OFF); })
+
+#define EXTRACT_RVC_J_IMM(x) \
+       ({typeof(x) x_ = (x); \
+       (RVC_X(x_, RVC_J_IMM_3_1_OPOFF, RVC_J_IMM_3_1_MASK) << RVC_J_IMM_3_1_OFF) | \
+       (RVC_X(x_, RVC_J_IMM_4_OPOFF, RVC_J_IMM_4_MASK) << RVC_J_IMM_4_OFF) | \
+       (RVC_X(x_, RVC_J_IMM_5_OPOFF, RVC_J_IMM_5_MASK) << RVC_J_IMM_5_OFF) | \
+       (RVC_X(x_, RVC_J_IMM_6_OPOFF, RVC_J_IMM_6_MASK) << RVC_J_IMM_6_OFF) | \
+       (RVC_X(x_, RVC_J_IMM_7_OPOFF, RVC_J_IMM_7_MASK) << RVC_J_IMM_7_OFF) | \
+       (RVC_X(x_, RVC_J_IMM_9_8_OPOFF, RVC_J_IMM_9_8_MASK) << RVC_J_IMM_9_8_OFF) | \
+       (RVC_X(x_, RVC_J_IMM_10_OPOFF, RVC_J_IMM_10_MASK) << RVC_J_IMM_10_OFF) | \
+       (RVC_IMM_SIGN(x_) << RVC_J_IMM_SIGN_OFF); })
+
+#define EXTRACT_RVC_B_IMM(x) \
+       ({typeof(x) x_ = (x); \
+       (RVC_X(x_, RVC_B_IMM_2_1_OPOFF, RVC_B_IMM_2_1_MASK) << RVC_B_IMM_2_1_OFF) | \
+       (RVC_X(x_, RVC_B_IMM_4_3_OPOFF, RVC_B_IMM_4_3_MASK) << RVC_B_IMM_4_3_OFF) | \
+       (RVC_X(x_, RVC_B_IMM_5_OPOFF, RVC_B_IMM_5_MASK) << RVC_B_IMM_5_OFF) | \
+       (RVC_X(x_, RVC_B_IMM_7_6_OPOFF, RVC_B_IMM_7_6_MASK) << RVC_B_IMM_7_6_OFF) | \
+       (RVC_IMM_SIGN(x_) << RVC_B_IMM_SIGN_OFF); })
index b5918a6..9a7d734 100644 (file)
@@ -6,7 +6,7 @@
 #ifndef _ASM_RISCV_PATCH_H
 #define _ASM_RISCV_PATCH_H
 
-int riscv_patch_text_nosync(void *addr, const void *insns, size_t len);
-int riscv_patch_text(void *addr, u32 insn);
+int patch_text_nosync(void *addr, const void *insns, size_t len);
+int patch_text(void *addr, u32 insn);
 
 #endif /* _ASM_RISCV_PATCH_H */
index 7cec196..136a442 100644 (file)
@@ -1,6 +1,7 @@
 /* SPDX-License-Identifier: GPL-2.0-or-later */
 /*
  * Copyright (C) 2020 Western Digital Corporation or its affiliates.
+ * Copyright (C) 2020 Google, Inc
  */
 
 #ifndef _ASM_RISCV_SOC_H
@@ -20,4 +21,42 @@ 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
index d8bbd32..b355cf4 100644 (file)
@@ -51,5 +51,6 @@ ifeq ($(CONFIG_RISCV_SBI), y)
 obj-$(CONFIG_SMP) += cpu_ops_sbi.o
 endif
 obj-$(CONFIG_HOTPLUG_CPU)      += cpu-hotplug.o
+obj-$(CONFIG_KGDB)             += kgdb.o
 
 clean:
index 4c90c07..bd0f122 100644 (file)
@@ -7,6 +7,23 @@
 #include <linux/cpu.h>
 #include <linux/of.h>
 #include <linux/of_device.h>
+#include <asm/cacheinfo.h>
+
+static struct riscv_cacheinfo_ops *rv_cache_ops;
+
+void riscv_set_cacheinfo_ops(struct riscv_cacheinfo_ops *ops)
+{
+       rv_cache_ops = ops;
+}
+EXPORT_SYMBOL_GPL(riscv_set_cacheinfo_ops);
+
+const struct attribute_group *
+cache_get_priv_group(struct cacheinfo *this_leaf)
+{
+       if (rv_cache_ops && rv_cache_ops->get_priv_group)
+               return rv_cache_ops->get_priv_group(this_leaf);
+       return NULL;
+}
 
 static void ci_leaf_init(struct cacheinfo *this_leaf,
                         struct device_node *node,
index ce69b34..0839661 100644 (file)
@@ -7,10 +7,23 @@
 
 #include <linux/ftrace.h>
 #include <linux/uaccess.h>
+#include <linux/memory.h>
 #include <asm/cacheflush.h>
 #include <asm/patch.h>
 
 #ifdef CONFIG_DYNAMIC_FTRACE
+int ftrace_arch_code_modify_prepare(void) __acquires(&text_mutex)
+{
+       mutex_lock(&text_mutex);
+       return 0;
+}
+
+int ftrace_arch_code_modify_post_process(void) __releases(&text_mutex)
+{
+       mutex_unlock(&text_mutex);
+       return 0;
+}
+
 static int ftrace_check_current_call(unsigned long hook_pos,
                                     unsigned int *expected)
 {
@@ -51,7 +64,7 @@ static int __ftrace_modify_call(unsigned long hook_pos, unsigned long target,
        make_call(hook_pos, target, call);
 
        /* Replace the auipc-jalr pair at once. Return -EPERM on write error. */
-       if (riscv_patch_text_nosync
+       if (patch_text_nosync
            ((void *)hook_pos, enable ? call : nops, MCOUNT_INSN_SIZE))
                return -EPERM;
 
index 98a4064..7ed1b22 100644 (file)
@@ -161,11 +161,20 @@ ENTRY(_start_kernel)
        /* Reset all registers except ra, a0, a1 */
        call reset_regs
 
-       /* Setup a PMP to permit access to all of memory. */
+       /*
+        * Setup a PMP to permit access to all of memory.  Some machines may
+        * not implement PMPs, so we set up a quick trap handler to just skip
+        * touching the PMPs on any trap.
+        */
+       la a0, pmp_done
+       csrw CSR_TVEC, a0
+
        li a0, -1
        csrw CSR_PMPADDR0, a0
        li a0, (PMP_A_NAPOT | PMP_R | PMP_W | PMP_X)
        csrw CSR_PMPCFG0, a0
+.align 2
+pmp_done:
 
        /*
         * The hartid in a0 is expected later on, and we have no firmware
diff --git a/arch/riscv/kernel/kgdb.c b/arch/riscv/kernel/kgdb.c
new file mode 100644 (file)
index 0000000..f16ade8
--- /dev/null
@@ -0,0 +1,390 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Copyright (C) 2020 SiFive
+ */
+
+#include <linux/ptrace.h>
+#include <linux/kdebug.h>
+#include <linux/bug.h>
+#include <linux/kgdb.h>
+#include <linux/irqflags.h>
+#include <linux/string.h>
+#include <asm/cacheflush.h>
+#include <asm/gdb_xml.h>
+#include <asm/parse_asm.h>
+
+enum {
+       NOT_KGDB_BREAK = 0,
+       KGDB_SW_BREAK,
+       KGDB_COMPILED_BREAK,
+       KGDB_SW_SINGLE_STEP
+};
+
+static unsigned long stepped_address;
+static unsigned int stepped_opcode;
+
+#if __riscv_xlen == 32
+/* C.JAL is an RV32C-only instruction */
+DECLARE_INSN(c_jal, MATCH_C_JAL, MASK_C_JAL)
+#else
+#define is_c_jal_insn(opcode) 0
+#endif
+DECLARE_INSN(jalr, MATCH_JALR, MASK_JALR)
+DECLARE_INSN(jal, MATCH_JAL, MASK_JAL)
+DECLARE_INSN(c_jr, MATCH_C_JR, MASK_C_JR)
+DECLARE_INSN(c_jalr, MATCH_C_JALR, MASK_C_JALR)
+DECLARE_INSN(c_j, MATCH_C_J, MASK_C_J)
+DECLARE_INSN(beq, MATCH_BEQ, MASK_BEQ)
+DECLARE_INSN(bne, MATCH_BNE, MASK_BNE)
+DECLARE_INSN(blt, MATCH_BLT, MASK_BLT)
+DECLARE_INSN(bge, MATCH_BGE, MASK_BGE)
+DECLARE_INSN(bltu, MATCH_BLTU, MASK_BLTU)
+DECLARE_INSN(bgeu, MATCH_BGEU, MASK_BGEU)
+DECLARE_INSN(c_beqz, MATCH_C_BEQZ, MASK_C_BEQZ)
+DECLARE_INSN(c_bnez, MATCH_C_BNEZ, MASK_C_BNEZ)
+DECLARE_INSN(sret, MATCH_SRET, MASK_SRET)
+
+int decode_register_index(unsigned long opcode, int offset)
+{
+       return (opcode >> offset) & 0x1F;
+}
+
+int decode_register_index_short(unsigned long opcode, int offset)
+{
+       return ((opcode >> offset) & 0x7) + 8;
+}
+
+/* Calculate the new address for after a step */
+int get_step_address(struct pt_regs *regs, unsigned long *next_addr)
+{
+       unsigned long pc = regs->epc;
+       unsigned long *regs_ptr = (unsigned long *)regs;
+       unsigned int rs1_num, rs2_num;
+       int op_code;
+
+       if (probe_kernel_address((void *)pc, op_code))
+               return -EINVAL;
+       if ((op_code & __INSN_LENGTH_MASK) != __INSN_LENGTH_GE_32) {
+               if (is_c_jalr_insn(op_code) || is_c_jr_insn(op_code)) {
+                       rs1_num = decode_register_index(op_code, RVC_C2_RS1_OPOFF);
+                       *next_addr = regs_ptr[rs1_num];
+               } else if (is_c_j_insn(op_code) || is_c_jal_insn(op_code)) {
+                       *next_addr = EXTRACT_RVC_J_IMM(op_code) + pc;
+               } else if (is_c_beqz_insn(op_code)) {
+                       rs1_num = decode_register_index_short(op_code,
+                                                             RVC_C1_RS1_OPOFF);
+                       if (!rs1_num || regs_ptr[rs1_num] == 0)
+                               *next_addr = EXTRACT_RVC_B_IMM(op_code) + pc;
+                       else
+                               *next_addr = pc + 2;
+               } else if (is_c_bnez_insn(op_code)) {
+                       rs1_num =
+                           decode_register_index_short(op_code, RVC_C1_RS1_OPOFF);
+                       if (rs1_num && regs_ptr[rs1_num] != 0)
+                               *next_addr = EXTRACT_RVC_B_IMM(op_code) + pc;
+                       else
+                               *next_addr = pc + 2;
+               } else {
+                       *next_addr = pc + 2;
+               }
+       } else {
+               if ((op_code & __INSN_OPCODE_MASK) == __INSN_BRANCH_OPCODE) {
+                       bool result = false;
+                       long imm = EXTRACT_BTYPE_IMM(op_code);
+                       unsigned long rs1_val = 0, rs2_val = 0;
+
+                       rs1_num = decode_register_index(op_code, RVG_RS1_OPOFF);
+                       rs2_num = decode_register_index(op_code, RVG_RS2_OPOFF);
+                       if (rs1_num)
+                               rs1_val = regs_ptr[rs1_num];
+                       if (rs2_num)
+                               rs2_val = regs_ptr[rs2_num];
+
+                       if (is_beq_insn(op_code))
+                               result = (rs1_val == rs2_val) ? true : false;
+                       else if (is_bne_insn(op_code))
+                               result = (rs1_val != rs2_val) ? true : false;
+                       else if (is_blt_insn(op_code))
+                               result =
+                                   ((long)rs1_val <
+                                    (long)rs2_val) ? true : false;
+                       else if (is_bge_insn(op_code))
+                               result =
+                                   ((long)rs1_val >=
+                                    (long)rs2_val) ? true : false;
+                       else if (is_bltu_insn(op_code))
+                               result = (rs1_val < rs2_val) ? true : false;
+                       else if (is_bgeu_insn(op_code))
+                               result = (rs1_val >= rs2_val) ? true : false;
+                       if (result)
+                               *next_addr = imm + pc;
+                       else
+                               *next_addr = pc + 4;
+               } else if (is_jal_insn(op_code)) {
+                       *next_addr = EXTRACT_JTYPE_IMM(op_code) + pc;
+               } else if (is_jalr_insn(op_code)) {
+                       rs1_num = decode_register_index(op_code, RVG_RS1_OPOFF);
+                       if (rs1_num)
+                               *next_addr = ((unsigned long *)regs)[rs1_num];
+                       *next_addr += EXTRACT_ITYPE_IMM(op_code);
+               } else if (is_sret_insn(op_code)) {
+                       *next_addr = pc;
+               } else {
+                       *next_addr = pc + 4;
+               }
+       }
+       return 0;
+}
+
+int do_single_step(struct pt_regs *regs)
+{
+       /* Determine where the target instruction will send us to */
+       unsigned long addr = 0;
+       int error = get_step_address(regs, &addr);
+
+       if (error)
+               return error;
+
+       /* Store the op code in the stepped address */
+       error = probe_kernel_address((void *)addr, stepped_opcode);
+       if (error)
+               return error;
+
+       stepped_address = addr;
+
+       /* Replace the op code with the break instruction */
+       error = probe_kernel_write((void *)stepped_address,
+                                  arch_kgdb_ops.gdb_bpt_instr,
+                                  BREAK_INSTR_SIZE);
+       /* Flush and return */
+       if (!error) {
+               flush_icache_range(addr, addr + BREAK_INSTR_SIZE);
+               kgdb_single_step = 1;
+               atomic_set(&kgdb_cpu_doing_single_step,
+                          raw_smp_processor_id());
+       } else {
+               stepped_address = 0;
+               stepped_opcode = 0;
+       }
+       return error;
+}
+
+/* Undo a single step */
+static void undo_single_step(struct pt_regs *regs)
+{
+       if (stepped_opcode != 0) {
+               probe_kernel_write((void *)stepped_address,
+                                  (void *)&stepped_opcode, BREAK_INSTR_SIZE);
+               flush_icache_range(stepped_address,
+                                  stepped_address + BREAK_INSTR_SIZE);
+       }
+       stepped_address = 0;
+       stepped_opcode = 0;
+       kgdb_single_step = 0;
+       atomic_set(&kgdb_cpu_doing_single_step, -1);
+}
+
+struct dbg_reg_def_t dbg_reg_def[DBG_MAX_REG_NUM] = {
+       {DBG_REG_ZERO, GDB_SIZEOF_REG, -1},
+       {DBG_REG_RA, GDB_SIZEOF_REG, offsetof(struct pt_regs, ra)},
+       {DBG_REG_SP, GDB_SIZEOF_REG, offsetof(struct pt_regs, sp)},
+       {DBG_REG_GP, GDB_SIZEOF_REG, offsetof(struct pt_regs, gp)},
+       {DBG_REG_TP, GDB_SIZEOF_REG, offsetof(struct pt_regs, tp)},
+       {DBG_REG_T0, GDB_SIZEOF_REG, offsetof(struct pt_regs, t0)},
+       {DBG_REG_T1, GDB_SIZEOF_REG, offsetof(struct pt_regs, t1)},
+       {DBG_REG_T2, GDB_SIZEOF_REG, offsetof(struct pt_regs, t2)},
+       {DBG_REG_FP, GDB_SIZEOF_REG, offsetof(struct pt_regs, s0)},
+       {DBG_REG_S1, GDB_SIZEOF_REG, offsetof(struct pt_regs, a1)},
+       {DBG_REG_A0, GDB_SIZEOF_REG, offsetof(struct pt_regs, a0)},
+       {DBG_REG_A1, GDB_SIZEOF_REG, offsetof(struct pt_regs, a1)},
+       {DBG_REG_A2, GDB_SIZEOF_REG, offsetof(struct pt_regs, a2)},
+       {DBG_REG_A3, GDB_SIZEOF_REG, offsetof(struct pt_regs, a3)},
+       {DBG_REG_A4, GDB_SIZEOF_REG, offsetof(struct pt_regs, a4)},
+       {DBG_REG_A5, GDB_SIZEOF_REG, offsetof(struct pt_regs, a5)},
+       {DBG_REG_A6, GDB_SIZEOF_REG, offsetof(struct pt_regs, a6)},
+       {DBG_REG_A7, GDB_SIZEOF_REG, offsetof(struct pt_regs, a7)},
+       {DBG_REG_S2, GDB_SIZEOF_REG, offsetof(struct pt_regs, s2)},
+       {DBG_REG_S3, GDB_SIZEOF_REG, offsetof(struct pt_regs, s3)},
+       {DBG_REG_S4, GDB_SIZEOF_REG, offsetof(struct pt_regs, s4)},
+       {DBG_REG_S5, GDB_SIZEOF_REG, offsetof(struct pt_regs, s5)},
+       {DBG_REG_S6, GDB_SIZEOF_REG, offsetof(struct pt_regs, s6)},
+       {DBG_REG_S7, GDB_SIZEOF_REG, offsetof(struct pt_regs, s7)},
+       {DBG_REG_S8, GDB_SIZEOF_REG, offsetof(struct pt_regs, s8)},
+       {DBG_REG_S9, GDB_SIZEOF_REG, offsetof(struct pt_regs, s9)},
+       {DBG_REG_S10, GDB_SIZEOF_REG, offsetof(struct pt_regs, s10)},
+       {DBG_REG_S11, GDB_SIZEOF_REG, offsetof(struct pt_regs, s11)},
+       {DBG_REG_T3, GDB_SIZEOF_REG, offsetof(struct pt_regs, t3)},
+       {DBG_REG_T4, GDB_SIZEOF_REG, offsetof(struct pt_regs, t4)},
+       {DBG_REG_T5, GDB_SIZEOF_REG, offsetof(struct pt_regs, t5)},
+       {DBG_REG_T6, GDB_SIZEOF_REG, offsetof(struct pt_regs, t6)},
+       {DBG_REG_EPC, GDB_SIZEOF_REG, offsetof(struct pt_regs, epc)},
+       {DBG_REG_STATUS, GDB_SIZEOF_REG, offsetof(struct pt_regs, status)},
+       {DBG_REG_BADADDR, GDB_SIZEOF_REG, offsetof(struct pt_regs, badaddr)},
+       {DBG_REG_CAUSE, GDB_SIZEOF_REG, offsetof(struct pt_regs, cause)},
+};
+
+char *dbg_get_reg(int regno, void *mem, struct pt_regs *regs)
+{
+       if (regno >= DBG_MAX_REG_NUM || regno < 0)
+               return NULL;
+
+       if (dbg_reg_def[regno].offset != -1)
+               memcpy(mem, (void *)regs + dbg_reg_def[regno].offset,
+                      dbg_reg_def[regno].size);
+       else
+               memset(mem, 0, dbg_reg_def[regno].size);
+       return dbg_reg_def[regno].name;
+}
+
+int dbg_set_reg(int regno, void *mem, struct pt_regs *regs)
+{
+       if (regno >= DBG_MAX_REG_NUM || regno < 0)
+               return -EINVAL;
+
+       if (dbg_reg_def[regno].offset != -1)
+               memcpy((void *)regs + dbg_reg_def[regno].offset, mem,
+                      dbg_reg_def[regno].size);
+       return 0;
+}
+
+void
+sleeping_thread_to_gdb_regs(unsigned long *gdb_regs, struct task_struct *task)
+{
+       /* Initialize to zero */
+       memset((char *)gdb_regs, 0, NUMREGBYTES);
+
+       gdb_regs[DBG_REG_SP_OFF] = task->thread.sp;
+       gdb_regs[DBG_REG_FP_OFF] = task->thread.s[0];
+       gdb_regs[DBG_REG_S1_OFF] = task->thread.s[1];
+       gdb_regs[DBG_REG_S2_OFF] = task->thread.s[2];
+       gdb_regs[DBG_REG_S3_OFF] = task->thread.s[3];
+       gdb_regs[DBG_REG_S4_OFF] = task->thread.s[4];
+       gdb_regs[DBG_REG_S5_OFF] = task->thread.s[5];
+       gdb_regs[DBG_REG_S6_OFF] = task->thread.s[6];
+       gdb_regs[DBG_REG_S7_OFF] = task->thread.s[7];
+       gdb_regs[DBG_REG_S8_OFF] = task->thread.s[8];
+       gdb_regs[DBG_REG_S9_OFF] = task->thread.s[10];
+       gdb_regs[DBG_REG_S10_OFF] = task->thread.s[11];
+       gdb_regs[DBG_REG_EPC_OFF] = task->thread.ra;
+}
+
+void kgdb_arch_set_pc(struct pt_regs *regs, unsigned long pc)
+{
+       regs->epc = pc;
+}
+
+void kgdb_arch_handle_qxfer_pkt(char *remcom_in_buffer,
+                               char *remcom_out_buffer)
+{
+       if (!strncmp(remcom_in_buffer, gdb_xfer_read_target,
+                    sizeof(gdb_xfer_read_target)))
+               strcpy(remcom_out_buffer, riscv_gdb_stub_target_desc);
+       else if (!strncmp(remcom_in_buffer, gdb_xfer_read_cpuxml,
+                         sizeof(gdb_xfer_read_cpuxml)))
+               strcpy(remcom_out_buffer, riscv_gdb_stub_cpuxml);
+}
+
+static inline void kgdb_arch_update_addr(struct pt_regs *regs,
+                                        char *remcom_in_buffer)
+{
+       unsigned long addr;
+       char *ptr;
+
+       ptr = &remcom_in_buffer[1];
+       if (kgdb_hex2long(&ptr, &addr))
+               regs->epc = addr;
+}
+
+int kgdb_arch_handle_exception(int vector, int signo, int err_code,
+                              char *remcom_in_buffer, char *remcom_out_buffer,
+                              struct pt_regs *regs)
+{
+       int err = 0;
+
+       undo_single_step(regs);
+
+       switch (remcom_in_buffer[0]) {
+       case 'c':
+       case 'D':
+       case 'k':
+               if (remcom_in_buffer[0] == 'c')
+                       kgdb_arch_update_addr(regs, remcom_in_buffer);
+               break;
+       case 's':
+               kgdb_arch_update_addr(regs, remcom_in_buffer);
+               err = do_single_step(regs);
+               break;
+       default:
+               err = -1;
+       }
+       return err;
+}
+
+int kgdb_riscv_kgdbbreak(unsigned long addr)
+{
+       if (stepped_address == addr)
+               return KGDB_SW_SINGLE_STEP;
+       if (atomic_read(&kgdb_setting_breakpoint))
+               if (addr == (unsigned long)&kgdb_compiled_break)
+                       return KGDB_COMPILED_BREAK;
+
+       return kgdb_has_hit_break(addr);
+}
+
+static int kgdb_riscv_notify(struct notifier_block *self, unsigned long cmd,
+                            void *ptr)
+{
+       struct die_args *args = (struct die_args *)ptr;
+       struct pt_regs *regs = args->regs;
+       unsigned long flags;
+       int type;
+
+       if (user_mode(regs))
+               return NOTIFY_DONE;
+
+       type = kgdb_riscv_kgdbbreak(regs->epc);
+       if (type == NOT_KGDB_BREAK && cmd == DIE_TRAP)
+               return NOTIFY_DONE;
+
+       local_irq_save(flags);
+
+       if (kgdb_handle_exception(type == KGDB_SW_SINGLE_STEP ? 0 : 1,
+                                 args->signr, cmd, regs))
+               return NOTIFY_DONE;
+
+       if (type == KGDB_COMPILED_BREAK)
+               regs->epc += 4;
+
+       local_irq_restore(flags);
+
+       return NOTIFY_STOP;
+}
+
+static struct notifier_block kgdb_notifier = {
+       .notifier_call = kgdb_riscv_notify,
+};
+
+int kgdb_arch_init(void)
+{
+       register_die_notifier(&kgdb_notifier);
+
+       return 0;
+}
+
+void kgdb_arch_exit(void)
+{
+       unregister_die_notifier(&kgdb_notifier);
+}
+
+/*
+ * Global data
+ */
+#ifdef CONFIG_RISCV_ISA_C
+const struct kgdb_arch arch_kgdb_ops = {
+       .gdb_bpt_instr = {0x02, 0x90},  /* c.ebreak */
+};
+#else
+const struct kgdb_arch arch_kgdb_ops = {
+       .gdb_bpt_instr = {0x73, 0x00, 0x10, 0x00},      /* ebreak */
+};
+#endif
index 8a4fc65..5805791 100644 (file)
@@ -5,22 +5,21 @@
 
 #include <linux/spinlock.h>
 #include <linux/mm.h>
+#include <linux/memory.h>
 #include <linux/uaccess.h>
 #include <linux/stop_machine.h>
 #include <asm/kprobes.h>
 #include <asm/cacheflush.h>
 #include <asm/fixmap.h>
 
-struct riscv_insn_patch {
+struct patch_insn {
        void *addr;
        u32 insn;
        atomic_t cpu_count;
 };
 
 #ifdef CONFIG_MMU
-static DEFINE_RAW_SPINLOCK(patch_lock);
-
-static void __kprobes *patch_map(void *addr, int fixmap)
+static void *patch_map(void *addr, int fixmap)
 {
        uintptr_t uintaddr = (uintptr_t) addr;
        struct page *page;
@@ -37,20 +36,26 @@ static void __kprobes *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 __kprobes patch_unmap(int fixmap)
+static void patch_unmap(int fixmap)
 {
        clear_fixmap(fixmap);
 }
+NOKPROBE_SYMBOL(patch_unmap);
 
-static int __kprobes riscv_insn_write(void *addr, const void *insn, size_t len)
+static int patch_insn_write(void *addr, const void *insn, size_t len)
 {
        void *waddr = addr;
        bool across_pages = (((uintptr_t) addr & ~PAGE_MASK) + len) > PAGE_SIZE;
-       unsigned long flags = 0;
        int ret;
 
-       raw_spin_lock_irqsave(&patch_lock, flags);
+       /*
+        * Before reaching here, it was expected to lock the text_mutex
+        * already, so we don't need to give another lock here and could
+        * ensure that it was safe between each cores.
+        */
+       lockdep_assert_held(&text_mutex);
 
        if (across_pages)
                patch_map(addr + len, FIX_TEXT_POKE1);
@@ -64,38 +69,39 @@ static int __kprobes riscv_insn_write(void *addr, const void *insn, size_t len)
        if (across_pages)
                patch_unmap(FIX_TEXT_POKE1);
 
-       raw_spin_unlock_irqrestore(&patch_lock, flags);
-
        return ret;
 }
+NOKPROBE_SYMBOL(patch_insn_write);
 #else
-static int __kprobes riscv_insn_write(void *addr, const void *insn, size_t len)
+static int patch_insn_write(void *addr, const void *insn, size_t len)
 {
        return probe_kernel_write(addr, insn, len);
 }
+NOKPROBE_SYMBOL(patch_insn_write);
 #endif /* CONFIG_MMU */
 
-int __kprobes riscv_patch_text_nosync(void *addr, const void *insns, size_t len)
+int patch_text_nosync(void *addr, const void *insns, size_t len)
 {
        u32 *tp = addr;
        int ret;
 
-       ret = riscv_insn_write(tp, insns, len);
+       ret = patch_insn_write(tp, insns, len);
 
        if (!ret)
                flush_icache_range((uintptr_t) tp, (uintptr_t) tp + len);
 
        return ret;
 }
+NOKPROBE_SYMBOL(patch_text_nosync);
 
-static int __kprobes riscv_patch_text_cb(void *data)
+static int patch_text_cb(void *data)
 {
-       struct riscv_insn_patch *patch = data;
+       struct patch_insn *patch = data;
        int ret = 0;
 
        if (atomic_inc_return(&patch->cpu_count) == 1) {
                ret =
-                   riscv_patch_text_nosync(patch->addr, &patch->insn,
+                   patch_text_nosync(patch->addr, &patch->insn,
                                            GET_INSN_LENGTH(patch->insn));
                atomic_inc(&patch->cpu_count);
        } else {
@@ -106,15 +112,17 @@ static int __kprobes riscv_patch_text_cb(void *data)
 
        return ret;
 }
+NOKPROBE_SYMBOL(patch_text_cb);
 
-int __kprobes riscv_patch_text(void *addr, u32 insn)
+int patch_text(void *addr, u32 insn)
 {
-       struct riscv_insn_patch patch = {
+       struct patch_insn patch = {
                .addr = addr,
                .insn = insn,
                .cpu_count = ATOMIC_INIT(0),
        };
 
-       return stop_machine_cpuslocked(riscv_patch_text_cb,
+       return stop_machine_cpuslocked(patch_text_cb,
                                       &patch, cpu_online_mask);
 }
+NOKPROBE_SYMBOL(patch_text);
index 145128a..3e52831 100644 (file)
@@ -75,7 +75,11 @@ void __init setup_arch(char **cmdline_p)
 
        setup_bootmem();
        paging_init();
+#if IS_ENABLED(CONFIG_BUILTIN_DTB)
+       unflatten_and_copy_device_tree();
+#else
        unflatten_device_tree();
+#endif
        clint_init_boot_cpu();
 
 #ifdef CONFIG_SWIOTLB
index 0b3b3dc..1fc8762 100644 (file)
@@ -26,3 +26,30 @@ 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;
+}
index 7f58fa5..5080fdf 100644 (file)
@@ -147,6 +147,11 @@ asmlinkage __visible void do_trap_break(struct pt_regs *regs)
 {
        if (user_mode(regs))
                force_sig_fault(SIGTRAP, TRAP_BRKPT, (void __user *)regs->epc);
+#ifdef CONFIG_KGDB
+       else if (notify_die(DIE_TRAP, "EBREAK", regs, 0, regs->cause, SIGTRAP)
+                                                               == NOTIFY_STOP)
+               return;
+#endif
        else if (report_bug(regs->epc, regs) == BUG_TRAP_TYPE_WARN)
                regs->epc += get_break_insn_length(regs->epc);
        else
index 0339b6b..e6f8016 100644 (file)
@@ -34,6 +34,11 @@ SECTIONS
                KEEP(*(__soc_early_init_table))
                __soc_early_init_table_end = .;
        }
+       __soc_builtin_dtb_table : {
+               __soc_builtin_dtb_table_start = .;
+               KEEP(*(__soc_builtin_dtb_table))
+               __soc_builtin_dtb_table_end = .;
+       }
        /* we have to discard exit text and such at runtime, not link time */
        .exit.text :
        {
index 939159b..3432740 100644 (file)
@@ -17,6 +17,7 @@
 #include <asm/fixmap.h>
 #include <asm/tlbflush.h>
 #include <asm/sections.h>
+#include <asm/soc.h>
 #include <asm/pgtable.h>
 #include <asm/io.h>
 #include <asm/ptdump.h>
@@ -494,7 +495,15 @@ void free_initmem(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
 }
 
 static inline void setup_vm_final(void)
index 4608fbc..7070192 100644 (file)
@@ -246,3 +246,15 @@ static void __init k210_soc_early_init(const void *fdt)
        iounmap(regs);
 }
 SOC_EARLY_INIT_DECLARE(generic_k210, "kendryte,k210", k210_soc_early_init);
+
+#ifdef CONFIG_SOC_KENDRYTE_K210_DTB_BUILTIN
+/*
+ * Generic entry for the default k210.dtb embedded DTB for boards with:
+ *   - Vendor ID: 0x4B5
+ *   - Arch ID: 0xE59889E6A5A04149 (= "Canaan AI" in UTF-8 encoded Chinese)
+ *   - Impl ID:        0x4D41495832303030 (= "MAIX2000")
+ * These values are reported by the SiPEED MAXDUINO, SiPEED MAIX GO and
+ * SiPEED Dan dock boards.
+ */
+SOC_BUILTIN_DTB_DECLARE(k210, 0x4B5, 0xE59889E6A5A04149, 0x4D41495832303030);
+#endif
index a506939..44d7e19 100644 (file)
@@ -9,6 +9,8 @@
 #include <linux/interrupt.h>
 #include <linux/of_irq.h>
 #include <linux/of_address.h>
+#include <linux/device.h>
+#include <asm/cacheinfo.h>
 #include <soc/sifive/sifive_l2_cache.h>
 
 #define SIFIVE_L2_DIRECCFIX_LOW 0x100
@@ -31,6 +33,7 @@
 
 static void __iomem *l2_base;
 static int g_irq[SIFIVE_L2_MAX_ECCINTR];
+static struct riscv_cacheinfo_ops l2_cache_ops;
 
 enum {
        DIR_CORR = 0,
@@ -48,7 +51,7 @@ static ssize_t l2_write(struct file *file, const char __user *data,
 
        if (kstrtouint_from_user(data, count, 0, &val))
                return -EINVAL;
-       if ((val >= 0 && val < 0xFF) || (val >= 0x10000 && val < 0x100FF))
+       if ((val < 0xFF) || (val >= 0x10000 && val < 0x100FF))
                writel(val, l2_base + SIFIVE_L2_ECCINJECTERR);
        else
                return -EINVAL;
@@ -107,6 +110,38 @@ int unregister_sifive_l2_error_notifier(struct notifier_block *nb)
 }
 EXPORT_SYMBOL_GPL(unregister_sifive_l2_error_notifier);
 
+static int l2_largest_wayenabled(void)
+{
+       return readl(l2_base + SIFIVE_L2_WAYENABLE) & 0xFF;
+}
+
+static ssize_t number_of_ways_enabled_show(struct device *dev,
+                                          struct device_attribute *attr,
+                                          char *buf)
+{
+       return sprintf(buf, "%u\n", l2_largest_wayenabled());
+}
+
+static DEVICE_ATTR_RO(number_of_ways_enabled);
+
+static struct attribute *priv_attrs[] = {
+       &dev_attr_number_of_ways_enabled.attr,
+       NULL,
+};
+
+static const struct attribute_group priv_attr_group = {
+       .attrs = priv_attrs,
+};
+
+static const struct attribute_group *l2_get_priv_group(struct cacheinfo *this_leaf)
+{
+       /* We want to use private group for L2 cache only */
+       if (this_leaf->level == 2)
+               return &priv_attr_group;
+       else
+               return NULL;
+}
+
 static irqreturn_t l2_int_handler(int irq, void *device)
 {
        unsigned int add_h, add_l;
@@ -170,6 +205,9 @@ static int __init sifive_l2_init(void)
 
        l2_config_read();
 
+       l2_cache_ops.get_priv_group = l2_get_priv_group;
+       riscv_set_cacheinfo_ops(&l2_cache_ops);
+
 #ifdef CONFIG_DEBUG_FS
        setup_sifive_debug();
 #endif
index ef94e90..c200d49 100644 (file)
@@ -415,6 +415,18 @@ int kgdb_isremovedbreak(unsigned long addr)
        return 0;
 }
 
+int kgdb_has_hit_break(unsigned long addr)
+{
+       int i;
+
+       for (i = 0; i < KGDB_MAX_BREAKPOINTS; i++) {
+               if (kgdb_break[i].state == BP_ACTIVE &&
+                   kgdb_break[i].bpt_addr == addr)
+                       return 1;
+       }
+       return 0;
+}
+
 int dbg_remove_all_break(void)
 {
        int error;