RISC-V Patches for the 5.8 Merge Window, Part 1
* 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. I may have a second part, but I wanted to get this out earlier rather than later as they've been ready to go for a while now. -----BEGIN PGP SIGNATURE----- iQJHBAABCgAxFiEEKzw3R0RoQ7JKlDp6LhMZ81+7GIkFAl7YRtMTHHBhbG1lckBk YWJiZWx0LmNvbQAKCRAuExnzX7sYif+oD/4kaoQqmiw0VvyFjBlPT/TC7OPbaoXO 5WBegSEAl+oOq+fUtjHomzn6HaTW2cPNexsqC/KuGP1/QL0OQ23T5O18LaCmrGMd CvELeAcvu6G4kbRuHwF0U16hBI2A1xIYVUJ8qmbuHPpEwVel3AsP2RIjQ+bOvm7g fVTIrlzl1s1eTsOXdOJb3sFZtISHb7o3lHZmcplDva3N13x8E0FrjuoJhHv0f2mj kcmZcy3sr8luAkwAJmbqmdPuwYTlteMnucXdCUv/kG2SaPkBwU5TS+MN7No2ylXH v4vxjkuSyJ1db72pla6uUB/cYD+mh2YI4tjjvH93s3k4I/GZMCrqivXZW2QtxBdt na++GxK8e4FrBG+VCCCQvx2mqugpMFMDnZDt36N2BqwjOtEzO3W8GqjrKCovXtQf farlgAiuFNVcoo7VFdpNZE+N5elQa0GWf57csCqqMNN4J8JLaOgyS7ByozJ9b9/A 1x4g7kQANnMvYiYAeV+C2YfBcK6x8gHEPlWio1QZqirW5la34VUEWa18+rQeSRMz DArKPauCR1GuYZZVUkkDI8cXj0Gs5fTXsYmn+WsIpjFHnDYeYVe6Ocmczxyb3o3O lQwm7+drHlSmMvgrOlWJMrIUbdiomgelDU/iD4PiZzKozC52yKDS6A5gzoG6uZSM UleeAIeVG/TDCw== =keTq -----END PGP SIGNATURE----- Merge tag 'riscv-for-linus-5.8-mw0' of git://git.kernel.org/pub/scm/linux/kernel/git/riscv/linux 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
This commit is contained in:
commit
435faf5c21
@ -1,3 +1,4 @@
|
||||
# SPDX-License-Identifier: GPL-2.0-only
|
||||
|
||||
obj-y += kernel/ mm/ net/
|
||||
obj-$(CONFIG_BUILTIN_DTB) += boot/dts/
|
||||
|
@ -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"
|
||||
|
@ -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
|
||||
|
@ -1,3 +1,5 @@
|
||||
# SPDX-License-Identifier: GPL-2.0
|
||||
subdir-y += sifive
|
||||
subdir-y += kendryte
|
||||
|
||||
obj-$(CONFIG_BUILTIN_DTB) := $(addsuffix /, $(subdir-y))
|
||||
|
@ -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))
|
||||
|
@ -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
|
||||
|
15
arch/riscv/include/asm/cacheinfo.h
Normal file
15
arch/riscv/include/asm/cacheinfo.h
Normal file
@ -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 */
|
117
arch/riscv/include/asm/gdb_xml.h
Normal file
117
arch/riscv/include/asm/gdb_xml.h
Normal file
@ -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
|
12
arch/riscv/include/asm/kdebug.h
Normal file
12
arch/riscv/include/asm/kdebug.h
Normal file
@ -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
|
112
arch/riscv/include/asm/kgdb.h
Normal file
112
arch/riscv/include/asm/kgdb.h
Normal file
@ -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
|
219
arch/riscv/include/asm/parse_asm.h
Normal file
219
arch/riscv/include/asm/parse_asm.h
Normal file
@ -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); })
|
@ -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 */
|
||||
|
@ -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
|
||||
|
@ -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:
|
||||
|
@ -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,
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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
|
||||
|
390
arch/riscv/kernel/kgdb.c
Normal file
390
arch/riscv/kernel/kgdb.c
Normal file
@ -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
|
@ -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);
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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 :
|
||||
{
|
||||
|
@ -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)
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
|
Loading…
Reference in New Issue
Block a user