From 69e28c05d0ea310f73854cde9e60300e8c822f21 Mon Sep 17 00:00:00 2001 From: Du Yilong Date: Fri, 21 Oct 2022 15:46:23 +0800 Subject: [PATCH 01/27] sw64: kvm: add qemu fw_cfg device support in sysfs Sunway inclusion category: feature bugzilla: https://gitee.com/openeuler/kernel/issues/I645LQ -------------------------------- Signed-off-by: Du Yilong Reviewed-by: He Sheng Signed-off-by: Gu Zitao --- drivers/firmware/Kconfig | 2 +- drivers/firmware/qemu_fw_cfg.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/firmware/Kconfig b/drivers/firmware/Kconfig index c08968c5ddf8..a34d4bfb27fe 100644 --- a/drivers/firmware/Kconfig +++ b/drivers/firmware/Kconfig @@ -186,7 +186,7 @@ config RASPBERRYPI_FIRMWARE config FW_CFG_SYSFS tristate "QEMU fw_cfg device support in sysfs" - depends on SYSFS && (ARM || ARM64 || PARISC || PPC_PMAC || SPARC || X86) + depends on SYSFS && (ARM || ARM64 || PARISC || PPC_PMAC || SPARC || X86 || SW64) depends on HAS_IOPORT_MAP default n help diff --git a/drivers/firmware/qemu_fw_cfg.c b/drivers/firmware/qemu_fw_cfg.c index f08e056ed0ae..80c416b78766 100644 --- a/drivers/firmware/qemu_fw_cfg.c +++ b/drivers/firmware/qemu_fw_cfg.c @@ -211,7 +211,7 @@ static void fw_cfg_io_cleanup(void) /* arch-specific ctrl & data register offsets are not available in ACPI, DT */ #if !(defined(FW_CFG_CTRL_OFF) && defined(FW_CFG_DATA_OFF)) -# if (defined(CONFIG_ARM) || defined(CONFIG_ARM64)) +# if (defined(CONFIG_ARM) || defined(CONFIG_ARM64) || defined(CONFIG_SW64)) # define FW_CFG_CTRL_OFF 0x08 # define FW_CFG_DATA_OFF 0x00 # define FW_CFG_DMA_OFF 0x10 -- Gitee From 209c44c883335cb6b579da2dda6a61bf33d5b8c2 Mon Sep 17 00:00:00 2001 From: Du Yilong Date: Fri, 21 Oct 2022 15:40:07 +0800 Subject: [PATCH 02/27] sw64: kvm: add qemu fw_cfg device to chip_vt.dts Sunway inclusion category: feature bugzilla: https://gitee.com/openeuler/kernel/issues/I645LQ -------------------------------- Signed-off-by: Du Yilong Reviewed-by: He Sheng Signed-off-by: Gu Zitao --- arch/sw_64/boot/dts/chip_vt.dts | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/arch/sw_64/boot/dts/chip_vt.dts b/arch/sw_64/boot/dts/chip_vt.dts index abad29dee97e..f26285367f98 100644 --- a/arch/sw_64/boot/dts/chip_vt.dts +++ b/arch/sw_64/boot/dts/chip_vt.dts @@ -46,5 +46,10 @@ misc: misc0@8036 { clock-frequency = <24000000>; status = "okay"; }; + fw_cfg: fw_cfg@8049 { + dma-coherent; + reg = <0x8049 0x20000000 0x0 0x18>; + compatible = "qemu,fw-cfg-mmio"; + }; }; }; -- Gitee From afba9e1ac4c44e8c890cc2c61ae6aee9e9acdd90 Mon Sep 17 00:00:00 2001 From: He Sheng Date: Fri, 21 Oct 2022 15:13:08 +0800 Subject: [PATCH 03/27] sw64: make struct cpuinfo_sw64 cache line aligned Sunway inclusion category: feature bugzilla: https://gitee.com/openeuler/kernel/issues/I645MA -------------------------------- This will avoid false sharing between different CPUs. Signed-off-by: He Sheng Reviewed-by: Cui Wei Signed-off-by: Gu Zitao --- arch/sw_64/include/asm/hw_init.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/sw_64/include/asm/hw_init.h b/arch/sw_64/include/asm/hw_init.h index 1fd7ed18c3f0..24de8977e2a7 100644 --- a/arch/sw_64/include/asm/hw_init.h +++ b/arch/sw_64/include/asm/hw_init.h @@ -24,7 +24,7 @@ struct cpuinfo_sw64 { struct cache_desc dcache; /* Primary D or combined I/D cache */ struct cache_desc scache; /* Secondary cache */ struct cache_desc tcache; /* Tertiary/split secondary cache */ -} __attribute__((aligned(64))); +} __aligned(SMP_CACHE_BYTES); struct cpu_desc_t { __u8 model; -- Gitee From 8be350d10ffce4f03b37cbcc3bd11d4bdf3fc6f9 Mon Sep 17 00:00:00 2001 From: He Sheng Date: Fri, 21 Oct 2022 15:46:33 +0800 Subject: [PATCH 04/27] sw64: track last vpn in struct cpuinfo_sw64 Sunway inclusion category: feature bugzilla: https://gitee.com/openeuler/kernel/issues/I645MA -------------------------------- The sw64_kvm_last_vpn[] suffers from false sharing, so remove it and track last vpn in struct cpuinfo_sw64. Signed-off-by: He Sheng Reviewed-by: Cui Wei Signed-off-by: Gu Zitao --- arch/sw_64/include/asm/hw_init.h | 1 + arch/sw_64/kvm/kvm-sw64.c | 11 +++++------ 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/arch/sw_64/include/asm/hw_init.h b/arch/sw_64/include/asm/hw_init.h index 24de8977e2a7..1426892c83b4 100644 --- a/arch/sw_64/include/asm/hw_init.h +++ b/arch/sw_64/include/asm/hw_init.h @@ -19,6 +19,7 @@ struct cache_desc { struct cpuinfo_sw64 { unsigned long last_asid; + unsigned long last_vpn; unsigned long ipi_count; struct cache_desc icache; /* Primary I-cache */ struct cache_desc dcache; /* Primary D or combined I/D cache */ diff --git a/arch/sw_64/kvm/kvm-sw64.c b/arch/sw_64/kvm/kvm-sw64.c index ffcfdee58a48..eb29583c1967 100644 --- a/arch/sw_64/kvm/kvm-sw64.c +++ b/arch/sw_64/kvm/kvm-sw64.c @@ -23,11 +23,10 @@ #include "vmem.c" bool set_msi_flag; -unsigned long sw64_kvm_last_vpn[NR_CPUS]; #if defined(CONFIG_DEBUG_FS) && defined(CONFIG_NUMA) extern bool bind_vcpu_enabled; #endif -#define cpu_last_vpn(cpuid) sw64_kvm_last_vpn[cpuid] +#define last_vpn(cpu) (cpu_data[cpu].last_vpn) #ifdef CONFIG_SUBARCH_C3B #define WIDTH_HARDWARE_VPN 8 @@ -84,14 +83,14 @@ static u64 get_vpcr(u64 hpa_base, u64 mem_size, u64 vpn) static unsigned long __get_new_vpn_context(struct kvm_vcpu *vcpu, long cpu) { - unsigned long vpn = cpu_last_vpn(cpu); + unsigned long vpn = last_vpn(cpu); unsigned long next = vpn + 1; if ((vpn & HARDWARE_VPN_MASK) >= HARDWARE_VPN_MASK) { tbia(); next = (vpn & ~HARDWARE_VPN_MASK) + VPN_FIRST_VERSION + 1; /* bypass 0 */ } - cpu_last_vpn(cpu) = next; + last_vpn(cpu) = next; return next; } @@ -101,7 +100,7 @@ static void sw64_kvm_switch_vpn(struct kvm_vcpu *vcpu) unsigned long vpnc; long cpu = smp_processor_id(); - vpn = cpu_last_vpn(cpu); + vpn = last_vpn(cpu); vpnc = vcpu->arch.vpnc[cpu]; if ((vpnc ^ vpn) & ~HARDWARE_VPN_MASK) { @@ -897,7 +896,7 @@ static int __init kvm_sw64_init(void) return ret; for (i = 0; i < NR_CPUS; i++) - sw64_kvm_last_vpn[i] = VPN_FIRST_VERSION; + last_vpn(i) = VPN_FIRST_VERSION; ret = kvm_init(NULL, sizeof(struct kvm_vcpu), 0, THIS_MODULE); if (ret) { -- Gitee From 5bf798dc8e8492127189cb5b7debdf5681f24919 Mon Sep 17 00:00:00 2001 From: He Sheng Date: Sat, 22 Oct 2022 14:25:09 +0800 Subject: [PATCH 05/27] sw64: always restore MATCH configuration after scheduling Sunway inclusion category: feature bugzilla: https://gitee.com/openeuler/kernel/issues/I645N4 -------------------------------- On SW64, MATCH configuration is a part of task context which should be switched after scheduling. If not, current task may trap because of the MATCH configuration of previous task, which is unexpected. Signed-off-by: He Sheng Reviewed-by: Cui Wei Signed-off-by: Gu Zitao --- arch/sw_64/kernel/ptrace.c | 3 --- 1 file changed, 3 deletions(-) diff --git a/arch/sw_64/kernel/ptrace.c b/arch/sw_64/kernel/ptrace.c index e98679d10fae..10afa6936357 100644 --- a/arch/sw_64/kernel/ptrace.c +++ b/arch/sw_64/kernel/ptrace.c @@ -435,9 +435,6 @@ void restore_da_match_after_sched(void) unsigned long dc_ctl; struct pcb_struct *pcb = &task_thread_info(current)->pcb; - if (!(pcb->da_match || pcb->da_mask || pcb->dv_match || pcb->dv_mask || pcb->dc_ctl)) - return; - printk("Restroe MATCH status, pid: %d\n", current->pid); rwcsr(WCSR, CSR_DA_MATCH, 0); rwcsr(WCSR, CSR_DA_MASK, pcb->da_mask); rwcsr(WCSR, CSR_DA_MATCH, pcb->da_match); -- Gitee From 6c9e44c5275345eebaad93106a9474174541b649 Mon Sep 17 00:00:00 2001 From: Mao Minkai Date: Mon, 24 Oct 2022 09:01:31 +0800 Subject: [PATCH 06/27] sw64: fix compile error when CONFIG_DEBUG_PER_CPU_MAPS=y Sunway inclusion category: feature bugzilla: https://gitee.com/openeuler/kernel/issues/I56QAM -------------------------------- Signed-off-by: Mao Minkai Reviewed-by: He Sheng Signed-off-by: Gu Zitao --- arch/sw_64/kvm/kvm-sw64.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/sw_64/kvm/kvm-sw64.c b/arch/sw_64/kvm/kvm-sw64.c index eb29583c1967..be5218234adf 100644 --- a/arch/sw_64/kvm/kvm-sw64.c +++ b/arch/sw_64/kvm/kvm-sw64.c @@ -614,7 +614,7 @@ int kvm_arch_vcpu_ioctl_run(struct kvm_vcpu *vcpu) end = vcpu->kvm->arch.host_phys_addr + vcpu->kvm->arch.size; nid = pfn_to_nid(PHYS_PFN(vcpu->kvm->arch.host_phys_addr)); if (pfn_to_nid(PHYS_PFN(end)) == nid) - set_cpus_allowed_ptr(vcpu->arch.tsk, node_to_cpumask_map[nid]); + set_cpus_allowed_ptr(vcpu->arch.tsk, cpumask_of_node(nid)); } #endif #else /* !CONFIG_KVM_MEMHOTPLUG */ -- Gitee From 048c5b1d53a2f76a5b4da4e928dbaccd5627e2af Mon Sep 17 00:00:00 2001 From: He Sheng Date: Tue, 25 Oct 2022 14:03:35 +0800 Subject: [PATCH 07/27] Revert "sw64: clean up unused single step support in kernel" Sunway inclusion category: feature bugzilla: https://gitee.com/openeuler/kernel/issues/I56OLG -------------------------------- This reverts commit a11aeaf7596912b10867b64306a167dc4a1282f0. lldb depends on PTRACE_SINGLESTEP, so revert the code to keep compatibility. Signed-off-by: He Sheng Reviewed-by: Cui Wei Signed-off-by: Gu Zitao --- arch/sw_64/include/asm/ptrace.h | 1 + arch/sw_64/include/asm/thread_info.h | 3 + arch/sw_64/kernel/proto.h | 4 + arch/sw_64/kernel/ptrace.c | 111 ++++++++++++++++++++++++++- arch/sw_64/kernel/signal.c | 16 ++++ 5 files changed, 133 insertions(+), 2 deletions(-) diff --git a/arch/sw_64/include/asm/ptrace.h b/arch/sw_64/include/asm/ptrace.h index 5f6cd305f95e..efc93e731b2a 100644 --- a/arch/sw_64/include/asm/ptrace.h +++ b/arch/sw_64/include/asm/ptrace.h @@ -49,6 +49,7 @@ struct pt_regs { unsigned long r18; }; +#define arch_has_single_step() (1) #define user_mode(regs) (((regs)->ps & 8) != 0) #define instruction_pointer(regs) ((regs)->pc) #define profile_pc(regs) instruction_pointer(regs) diff --git a/arch/sw_64/include/asm/thread_info.h b/arch/sw_64/include/asm/thread_info.h index 31740003d0b2..7cdafaec62e4 100644 --- a/arch/sw_64/include/asm/thread_info.h +++ b/arch/sw_64/include/asm/thread_info.h @@ -34,6 +34,9 @@ struct thread_info { int preempt_count; /* 0 => preemptible, <0 => BUG */ unsigned int status; /* thread-synchronous flags */ + int bpt_nsaved; + unsigned long bpt_addr[2]; /* breakpoint handling */ + unsigned int bpt_insn[2]; #ifdef CONFIG_DYNAMIC_FTRACE unsigned long dyn_ftrace_addr; #endif diff --git a/arch/sw_64/kernel/proto.h b/arch/sw_64/kernel/proto.h index f908263f925a..7b2564f47a9d 100644 --- a/arch/sw_64/kernel/proto.h +++ b/arch/sw_64/kernel/proto.h @@ -7,6 +7,10 @@ #include #include +/* ptrace.c */ +extern int ptrace_set_bpt(struct task_struct *child); +extern int ptrace_cancel_bpt(struct task_struct *child); + /* traps.c */ extern void show_regs(struct pt_regs *regs); extern void die(char *str, struct pt_regs *regs, long err); diff --git a/arch/sw_64/kernel/ptrace.c b/arch/sw_64/kernel/ptrace.c index 10afa6936357..2ca8d5804537 100644 --- a/arch/sw_64/kernel/ptrace.c +++ b/arch/sw_64/kernel/ptrace.c @@ -144,12 +144,119 @@ put_reg(struct task_struct *task, unsigned long regno, unsigned long data) return 0; } +static inline int +read_int(struct task_struct *task, unsigned long addr, int *data) +{ + int copied = access_process_vm(task, addr, data, sizeof(int), FOLL_FORCE); + + return (copied == sizeof(int)) ? 0 : -EIO; +} + +static inline int +write_int(struct task_struct *task, unsigned long addr, int data) +{ + int copied = access_process_vm(task, addr, &data, sizeof(int), + FOLL_FORCE | FOLL_WRITE); + return (copied == sizeof(int)) ? 0 : -EIO; +} + +/* + * Set breakpoint. + */ +int +ptrace_set_bpt(struct task_struct *child) +{ + int displ, i, res, reg_b, nsaved = 0; + unsigned int insn, op_code; + unsigned long pc; + + pc = get_reg(child, PC); + res = read_int(child, pc, (int *)&insn); + if (res < 0) + return res; + + op_code = insn >> 26; + /* br bsr beq bne blt ble bgt bge blbc blbs fbeq fbne fblt fble fbgt fbge */ + if ((1UL << op_code) & 0x3fff000000000030UL) { + /* + * It's a branch: instead of trying to figure out + * whether the branch will be taken or not, we'll put + * a breakpoint at either location. This is simpler, + * more reliable, and probably not a whole lot slower + * than the alternative approach of emulating the + * branch (emulation can be tricky for fp branches). + */ + displ = ((s32)(insn << 11)) >> 9; + task_thread_info(child)->bpt_addr[nsaved++] = pc + 4; + if (displ) /* guard against unoptimized code */ + task_thread_info(child)->bpt_addr[nsaved++] + = pc + 4 + displ; + /*call ret jmp*/ + } else if (op_code >= 0x1 && op_code <= 0x3) { + reg_b = (insn >> 16) & 0x1f; + task_thread_info(child)->bpt_addr[nsaved++] = get_reg(child, reg_b); + } else { + task_thread_info(child)->bpt_addr[nsaved++] = pc + 4; + } + + /* install breakpoints: */ + for (i = 0; i < nsaved; ++i) { + res = read_int(child, task_thread_info(child)->bpt_addr[i], + (int *)&insn); + if (res < 0) + return res; + task_thread_info(child)->bpt_insn[i] = insn; + res = write_int(child, task_thread_info(child)->bpt_addr[i], + BREAKINST); + if (res < 0) + return res; + } + task_thread_info(child)->bpt_nsaved = nsaved; + return 0; +} + /* - * Called by ptrace_detach + * Ensure no single-step breakpoint is pending. Returns non-zero + * value if child was being single-stepped. + */ +int +ptrace_cancel_bpt(struct task_struct *child) +{ + int i, nsaved = task_thread_info(child)->bpt_nsaved; + + task_thread_info(child)->bpt_nsaved = 0; + + if (nsaved > 2) { + printk("%s: bogus nsaved: %d!\n", __func__, nsaved); + nsaved = 2; + } + + for (i = 0; i < nsaved; ++i) { + write_int(child, task_thread_info(child)->bpt_addr[i], + task_thread_info(child)->bpt_insn[i]); + } + return (nsaved != 0); +} + +void user_enable_single_step(struct task_struct *child) +{ + /* Mark single stepping. */ + task_thread_info(child)->bpt_nsaved = -1; +} + +void user_disable_single_step(struct task_struct *child) +{ + ptrace_cancel_bpt(child); +} + +/* + * Called by kernel/ptrace.c when detaching.. + * + * Make sure the single step bit is not set. */ void ptrace_disable(struct task_struct *child) { - /**/ + user_disable_single_step(child); } static int gpr_get(struct task_struct *target, diff --git a/arch/sw_64/kernel/signal.c b/arch/sw_64/kernel/signal.c index b80cf0e56224..3a5757b234c6 100644 --- a/arch/sw_64/kernel/signal.c +++ b/arch/sw_64/kernel/signal.c @@ -163,6 +163,11 @@ do_sigreturn(struct sigcontext __user *sc) if (restore_sigcontext(sc, regs)) goto give_sigsegv; + /* Send SIGTRAP if we're single-stepping: */ + if (ptrace_cancel_bpt(current)) { + force_sig_fault(SIGTRAP, TRAP_BRKPT, + (void __user *)regs->pc, 0); + } return; give_sigsegv: @@ -189,6 +194,11 @@ do_rt_sigreturn(struct rt_sigframe __user *frame) if (restore_altstack(&frame->uc.uc_stack)) goto give_sigsegv; + /* Send SIGTRAP if we're single-stepping: */ + if (ptrace_cancel_bpt(current)) { + force_sig_fault(SIGTRAP, TRAP_BRKPT, + (void __user *)regs->pc, 0); + } return; give_sigsegv: @@ -362,15 +372,19 @@ syscall_restart(unsigned long r0, unsigned long r19, static void do_signal(struct pt_regs *regs, unsigned long r0, unsigned long r19) { + unsigned long single_stepping = ptrace_cancel_bpt(current); struct ksignal ksig; /* This lets the debugger run, ... */ if (get_signal(&ksig)) { + /* ... so re-check the single stepping. */ + single_stepping |= ptrace_cancel_bpt(current); /* Whee! Actually deliver the signal. */ if (r0) syscall_restart(r0, r19, regs, &ksig.ka); handle_signal(&ksig, regs); } else { + single_stepping |= ptrace_cancel_bpt(current); if (r0) { switch (regs->r0) { case ERESTARTNOHAND: @@ -390,6 +404,8 @@ do_signal(struct pt_regs *regs, unsigned long r0, unsigned long r19) } restore_saved_sigmask(); } + if (single_stepping) + ptrace_set_bpt(current); /* re-set breakpoint */ } void -- Gitee From c6b10d92003852305d90eeace9b16c2b26735da3 Mon Sep 17 00:00:00 2001 From: Mao Minkai Date: Wed, 26 Oct 2022 14:12:14 +0800 Subject: [PATCH 08/27] sw64: remove unused boot syncronization code Sunway inclusion category: feature bugzilla: https://gitee.com/openeuler/kernel/issues/I56OLG -------------------------------- There's no need to do syncronization between boot core and secondary core during smp booting on SW64. Remove the redundant code. Signed-off-by: Mao Minkai Reviewed-by: He Sheng Signed-off-by: Gu Zitao --- arch/sw_64/kernel/smp.c | 62 +---------------------------------------- 1 file changed, 1 insertion(+), 61 deletions(-) diff --git a/arch/sw_64/kernel/smp.c b/arch/sw_64/kernel/smp.c index ecf276e9e364..79dc334c3375 100644 --- a/arch/sw_64/kernel/smp.c +++ b/arch/sw_64/kernel/smp.c @@ -50,31 +50,12 @@ enum ipi_message_type { IPI_CPU_STOP, }; -/* Set to a secondary's cpuid when it comes online. */ -static int smp_secondary_alive; - int smp_num_cpus = 1; /* Number that came online. */ EXPORT_SYMBOL(smp_num_cpus); #define send_sleep_interrupt(cpu) send_ipi((cpu), II_SLEEP) #define send_wakeup_interrupt(cpu) send_ipi((cpu), II_WAKE) - -static void __init wait_boot_cpu_to_stop(int cpuid) -{ - unsigned long stop = jiffies + 10*HZ; - - while (time_before(jiffies, stop)) { - if (!smp_secondary_alive) - return; - barrier(); - } - - printk("%s: FAILED on CPU %d, hanging now\n", __func__, cpuid); - for (;;) - barrier(); -} - void __weak enable_chip_int(void) { } /* @@ -122,16 +103,6 @@ void smp_callin(void) /* Must have completely accurate bogos. */ local_irq_enable(); - /* Wait boot CPU to stop with irq enabled before running - * calibrate_delay. - */ - wait_boot_cpu_to_stop(cpuid); - mb(); - - /* Allow master to continue only after we written loops_per_jiffy. */ - wmb(); - smp_secondary_alive = 1; - DBGS("%s: commencing CPU %d (RCID: %d)current %p active_mm %p\n", __func__, cpuid, cpu_to_rcid(cpuid), current, current->active_mm); @@ -191,40 +162,9 @@ static int secondary_cpu_start(int cpuid, struct task_struct *idle) */ static int smp_boot_one_cpu(int cpuid, struct task_struct *idle) { - unsigned long timeout; - - /* Signal the secondary to wait a moment. */ - smp_secondary_alive = -1; - per_cpu(cpu_state, cpuid) = CPU_UP_PREPARE; - /* Whirrr, whirrr, whirrrrrrrrr... */ - if (secondary_cpu_start(cpuid, idle)) - return -1; - - /* Notify the secondary CPU it can run calibrate_delay. */ - mb(); - smp_secondary_alive = 0; - - /* We've been acked by the console; wait one second for - * the task to start up for real. - */ - timeout = jiffies + 1*HZ; - while (time_before(jiffies, timeout)) { - if (smp_secondary_alive == 1) - goto alive; - udelay(10); - barrier(); - } - - /* We failed to boot the CPU. */ - - pr_err("SMP: Processor %d is stuck.\n", cpuid); - return -1; - -alive: - /* Another "Red Snapper". */ - return 0; + return secondary_cpu_start(cpuid, idle); } static void __init process_nr_cpu_ids(void) -- Gitee From 084f52c3044b6a1c0d12deb764542bc9de6a886f Mon Sep 17 00:00:00 2001 From: Mao Minkai Date: Wed, 26 Oct 2022 14:12:14 +0800 Subject: [PATCH 09/27] sw64: improve stack trace Sunway inclusion category: feature bugzilla: https://gitee.com/openeuler/kernel/issues/I645NW -------------------------------- Process ra directly if call stack has not been setup yet so we won't miss the previous function. Signed-off-by: Mao Minkai Reviewed-by: He Sheng Signed-off-by: Gu Zitao --- arch/sw_64/kernel/stacktrace.c | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/arch/sw_64/kernel/stacktrace.c b/arch/sw_64/kernel/stacktrace.c index 7b5ddc78bd6d..70c142b11b92 100644 --- a/arch/sw_64/kernel/stacktrace.c +++ b/arch/sw_64/kernel/stacktrace.c @@ -69,8 +69,18 @@ void walk_stackframe(struct task_struct *tsk, struct pt_regs *regs, struct stackframe frame; if (regs) { + unsigned long offset; pc = regs->pc; fp = regs->r15; + if (kallsyms_lookup_size_offset(pc, NULL, &offset) + && offset < 16) { + /* call stack has not been setup + * store pc first then loop from ra + */ + if (fn(pc, data)) + return; + pc = regs->r26; + } } else if (tsk == current || tsk == NULL) { fp = (unsigned long)__builtin_frame_address(0); pc = (unsigned long)walk_stackframe; -- Gitee From 50d6b5a9fdb6a62661075badae6646767756d88c Mon Sep 17 00:00:00 2001 From: Min Fanlei Date: Wed, 26 Oct 2022 09:03:49 +0800 Subject: [PATCH 10/27] sw64: kvm: fix guest longtime offset of VCPU Sunway inclusion category: feature bugzilla: https://gitee.com/openeuler/kernel/issues/I645O8 -------------------------------- Other VCPUs have to sync longtime offset with VCPU0 to ensure the consistency of clock source, and this will avoid RCU CPU stalls in guest live migration. Signed-off-by: Min Fanlei Reviewed-by: He Sheng Signed-off-by: Gu Zitao --- arch/sw_64/kvm/kvm-sw64.c | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/arch/sw_64/kvm/kvm-sw64.c b/arch/sw_64/kvm/kvm-sw64.c index be5218234adf..c5a16d1c350b 100644 --- a/arch/sw_64/kvm/kvm-sw64.c +++ b/arch/sw_64/kvm/kvm-sw64.c @@ -23,6 +23,8 @@ #include "vmem.c" bool set_msi_flag; +static unsigned long longtime_offset; + #if defined(CONFIG_DEBUG_FS) && defined(CONFIG_NUMA) extern bool bind_vcpu_enabled; #endif @@ -726,10 +728,13 @@ long kvm_arch_vcpu_ioctl(struct file *filp, vcpu->arch.vcb.vpcr = get_vpcr(vcpu->kvm->arch.host_phys_addr, vcpu->kvm->arch.size, 0); - result = sw64_io_read(0, LONG_TIME); - /* synchronize the longtime of source and destination */ - vcpu->arch.vcb.guest_longtime_offset = vcpu->arch.vcb.guest_longtime - result; + if (vcpu->arch.vcb.whami == 0) { + result = sw64_io_read(0, LONG_TIME); + vcpu->arch.vcb.guest_longtime_offset = vcpu->arch.vcb.guest_longtime - result; + longtime_offset = vcpu->arch.vcb.guest_longtime_offset; + } else + vcpu->arch.vcb.guest_longtime_offset = longtime_offset; set_timer(vcpu, 200000000); vcpu->arch.vcb.migration_mark = 0; -- Gitee From 1379061f890dddbe0449d0a94036a916c09cd222 Mon Sep 17 00:00:00 2001 From: Mao Minkai Date: Wed, 26 Oct 2022 14:12:14 +0800 Subject: [PATCH 11/27] sw64: fix topology setup Sunway inclusion category: feature bugzilla: https://gitee.com/openeuler/kernel/issues/I645OO -------------------------------- Fix thread id in topology. Rename some variables and reorganize some code to improve readability. Signed-off-by: Mao Minkai Reviewed-by: He Sheng Signed-off-by: Gu Zitao --- arch/sw_64/include/asm/topology.h | 6 +-- arch/sw_64/kernel/topology.c | 70 +++++++++++++------------------ 2 files changed, 31 insertions(+), 45 deletions(-) diff --git a/arch/sw_64/include/asm/topology.h b/arch/sw_64/include/asm/topology.h index f8242d00290b..c39ca5b4beb7 100644 --- a/arch/sw_64/include/asm/topology.h +++ b/arch/sw_64/include/asm/topology.h @@ -8,9 +8,9 @@ #include #include -#define THREAD_ID_SHIFT 5 -#define THREAD_ID_MASK 1 -#define CORE_ID_MASK ((1 << THREAD_ID_SHIFT) - 1) +#define THREAD_ID_SHIFT 5 /* thread_id is removed from rcid */ +#define THREAD_ID_MASK 0 /* set mask to 0 */ +#define CORE_ID_MASK ((1 << THREAD_ID_SHIFT) - 1) extern struct cpu_topology cpu_topology[NR_CPUS]; diff --git a/arch/sw_64/kernel/topology.c b/arch/sw_64/kernel/topology.c index 964d6a83d901..6bad8e13b8c9 100644 --- a/arch/sw_64/kernel/topology.c +++ b/arch/sw_64/kernel/topology.c @@ -18,67 +18,53 @@ EXPORT_SYMBOL_GPL(cpu_topology); const struct cpumask *cpu_coregroup_mask(int cpu) { - const cpumask_t *core_mask = cpumask_of_node(cpu_to_node(cpu)); - - /* Find the smaller of NUMA, core or LLC siblings */ - if (cpumask_subset(&cpu_topology[cpu].core_sibling, core_mask)) { - /* not numa in package, lets use the package siblings */ - core_mask = &cpu_topology[cpu].core_sibling; - } - if (cpu_topology[cpu].llc_id != -1) { - if (cpumask_subset(&cpu_topology[cpu].llc_sibling, core_mask)) - core_mask = &cpu_topology[cpu].llc_sibling; - } - - return core_mask; + return topology_llc_cpumask(cpu); } -static void update_siblings_masks(int cpuid) +static void update_siblings_masks(int cpu) { - struct cpu_topology *cpu_topo, *cpuid_topo = &cpu_topology[cpuid]; - int cpu; + struct cpu_topology *cpu_topo = &cpu_topology[cpu]; + int sib; /* update core and thread sibling masks */ - for_each_online_cpu(cpu) { - cpu_topo = &cpu_topology[cpu]; + for_each_online_cpu(sib) { + struct cpu_topology *sib_topo = &cpu_topology[sib]; - if (cpuid_topo->llc_id == cpu_topo->llc_id) { - cpumask_set_cpu(cpu, &cpuid_topo->llc_sibling); - cpumask_set_cpu(cpuid, &cpu_topo->llc_sibling); + if (cpu_topo->llc_id == sib_topo->llc_id) { + cpumask_set_cpu(cpu, &sib_topo->llc_sibling); + cpumask_set_cpu(sib, &cpu_topo->llc_sibling); } - if (cpuid_topo->package_id != cpu_topo->package_id) - continue; - - cpumask_set_cpu(cpuid, &cpu_topo->core_sibling); - cpumask_set_cpu(cpu, &cpuid_topo->core_sibling); - - if (cpuid_topo->core_id != cpu_topo->core_id) - continue; + if (cpu_topo->package_id == sib_topo->package_id) { + cpumask_set_cpu(cpu, &sib_topo->core_sibling); + cpumask_set_cpu(sib, &cpu_topo->core_sibling); + } - cpumask_set_cpu(cpuid, &cpu_topo->thread_sibling); - cpumask_set_cpu(cpu, &cpuid_topo->thread_sibling); + if (cpu_topo->core_id == sib_topo->core_id) { + cpumask_set_cpu(cpu, &sib_topo->thread_sibling); + cpumask_set_cpu(sib, &cpu_topo->thread_sibling); + } } } -void store_cpu_topology(int cpuid) +void store_cpu_topology(int cpu) { - struct cpu_topology *cpuid_topo = &cpu_topology[cpuid]; + struct cpu_topology *cpu_topo = &cpu_topology[cpu]; - if (cpuid_topo->package_id != -1) + if (cpu_topo->package_id != -1) goto topology_populated; - cpuid_topo->core_id = cpu_to_rcid(cpuid) & CORE_ID_MASK; - cpuid_topo->package_id = rcid_to_package(cpu_to_rcid(cpuid)); - cpuid_topo->llc_id = rcid_to_package(cpuid); - cpuid_topo->thread_id = (cpu_to_rcid(cpuid) >> THREAD_ID_SHIFT) & THREAD_ID_MASK; + cpu_topo->package_id = rcid_to_package(cpu_to_rcid(cpu)); + cpu_topo->core_id = cpu_to_rcid(cpu) & CORE_ID_MASK; + cpu_topo->thread_id = (cpu_to_rcid(cpu) >> THREAD_ID_SHIFT) & THREAD_ID_MASK; + cpu_topo->llc_id = rcid_to_package(cpu_to_rcid(cpu)); - pr_debug("CPU%u: socket %d core %d thread %d\n", - cpuid, cpuid_topo->package_id, cpuid_topo->core_id, - cpuid_topo->thread_id); + pr_debug("CPU%u: socket %d core %d thread %d llc %d\n", + cpu, cpu_topo->package_id, cpu_topo->core_id, + cpu_topo->thread_id, cpu_topo->llc_id); topology_populated: - update_siblings_masks(cpuid); + update_siblings_masks(cpu); } static void clear_cpu_topology(int cpu) -- Gitee From ad275981eba4127e8e29b3537b479c89d0782d68 Mon Sep 17 00:00:00 2001 From: He Sheng Date: Wed, 26 Oct 2022 15:56:28 +0800 Subject: [PATCH 12/27] sw64: fix recordmcount and dynamic ftrace Sunway inclusion category: feature bugzilla: https://gitee.com/openeuler/kernel/issues/I645P4 -------------------------------- SW64 mcount call site has 5 instructions as follows: 0: 00 00 bb ff ldih $r29,0($r27) 0: GPDISP .text+0x4 4: 00 00 bd fb ldi $r29,0($r29) 8: 00 00 9d ff ldih $r28,0($r29) 8: ELF_LITERAL_GOT *ABS* c: 00 00 9d 8f ldl $r28,0($r29) c: ELF_LITERAL _mcount 10: 00 00 9c 07 call $r28,($r28) 10: HINT _mcount It shows that there are 2 _mcount symbols, so recordmcount has to set the second one as fake and filter it, then do the necessary offset adjustment. The first two instructions are aimed at loading global pointer(ldgp), because _mcount is global symbol and global symbols must be accessed through gp due to the design of GCC on sw64. For functions that access global symbols, the ldgp instructions are necessary for both _mcount call and other symbols. However, there is no way to tell whether a function access global symbols, so it has to always reserve the ldgp instructions for dynamic function tracer even when tracing is disabled. This has a negative impact on performance. With it, to disable tracing(ftrace_make_nop), the last 3 instructions in position are replaced with 3 NOP instructions at once. To enable tracing(ftrace_make_call), they are replaced with: nop ldl $28, TI_FTRACE_ADDR($8) call $28, ($28), 1 Signed-off-by: He Sheng Reviewed-by: Cui Wei Signed-off-by: Gu Zitao --- arch/sw_64/include/asm/ftrace.h | 5 ++-- arch/sw_64/include/asm/insn.h | 1 + arch/sw_64/kernel/entry-ftrace.S | 10 +++---- arch/sw_64/kernel/ftrace.c | 50 ++++++++++---------------------- scripts/recordmcount.c | 37 ++++++++++++++++------- 5 files changed, 49 insertions(+), 54 deletions(-) diff --git a/arch/sw_64/include/asm/ftrace.h b/arch/sw_64/include/asm/ftrace.h index ea82224e5826..61933103dcd4 100644 --- a/arch/sw_64/include/asm/ftrace.h +++ b/arch/sw_64/include/asm/ftrace.h @@ -10,13 +10,14 @@ */ #ifndef _ASM_SW64_FTRACE_H #define _ASM_SW64_FTRACE_H -#include #define MCOUNT_ADDR ((unsigned long)_mcount) -#define MCOUNT_INSN_SIZE SW64_INSN_SIZE +#define MCOUNT_INSN_SIZE 20 /* 5 * SW64_INSN_SIZE */ +#define MCOUNT_LDGP_SIZE 8 /* 2 * SW64_INSN_SIZE */ #ifndef __ASSEMBLY__ #include +#include extern void _mcount(unsigned long); diff --git a/arch/sw_64/include/asm/insn.h b/arch/sw_64/include/asm/insn.h index ec0efae3aed0..437cb48d1e93 100644 --- a/arch/sw_64/include/asm/insn.h +++ b/arch/sw_64/include/asm/insn.h @@ -43,6 +43,7 @@ enum { #define SW64_INSN_SYS_CALL 0x02000000 #define SW64_INSN_BR 0x10000000 +#define SW64_NOP (0x43ff075f) #define SW64_BIS(a, b, c) (SW64_INSN_BIS | ___SW64_RA(a) | ___SW64_RB(b) | ___SW64_SIMP_RC(c)) #define SW64_CALL(a, b, disp) (SW64_INSN_CALL | ___SW64_RA(a) | ___SW64_RB(b) | ___SW64_ST_DISP(disp)) #define SW64_SYS_CALL(func) (SW64_INSN_SYS_CALL | ___SW64_SYSCALL_FUNC(func)) diff --git a/arch/sw_64/kernel/entry-ftrace.S b/arch/sw_64/kernel/entry-ftrace.S index 223dd5fc0808..07bdf5a6e35a 100644 --- a/arch/sw_64/kernel/entry-ftrace.S +++ b/arch/sw_64/kernel/entry-ftrace.S @@ -10,6 +10,7 @@ * */ #include +#include .text .set noat @@ -60,8 +61,7 @@ ftrace_caller: br $27, 2f 2: ldgp $29, 0($27) - bis $28, $31, $16 - subl $16, 8, $16 + subl $28, MCOUNT_INSN_SIZE, $16 bis $26, $31, $17 ldi $4, current_tracer @@ -97,8 +97,7 @@ _mcount: cmpeq $4, $5, $6 bne $6, skip_ftrace - bis $28, $31, $16 - subl $16, 8, $16 + subl $28, MCOUNT_INSN_SIZE, $16 bis $26, $31, $17 call $26, ($27), 1 @@ -164,8 +163,7 @@ ftrace_graph_caller: memb /* need memb, otherwise it'll go wrong */ RESTORE_GRAPH_ARGS addl $sp, 0x18, $16 - bis $28, $31, $17 - subl $17, 8, $17 + subl $28, MCOUNT_INSN_SIZE, $17 bis $15, $31, $18 /* parent's fp */ call $26, ($27) /* prepare_ftrace_return() */ diff --git a/arch/sw_64/kernel/ftrace.c b/arch/sw_64/kernel/ftrace.c index 42efca28d386..cf1524c15f15 100644 --- a/arch/sw_64/kernel/ftrace.c +++ b/arch/sw_64/kernel/ftrace.c @@ -19,17 +19,9 @@ EXPORT_SYMBOL(_mcount); #ifdef CONFIG_DYNAMIC_FTRACE -unsigned long current_tracer = (unsigned long)ftrace_stub; +#define TI_FTRACE_ADDR (offsetof(struct thread_info, dyn_ftrace_addr)) -/* - * Replace two instruction, which may be a branch or NOP. - */ -static int ftrace_modify_double_code(unsigned long pc, u64 new) -{ - if (sw64_insn_double_write((void *)pc, new)) - return -EPERM; - return 0; -} +unsigned long current_tracer = (unsigned long)ftrace_stub; /* * Replace a single instruction, which may be a branch or NOP. @@ -47,17 +39,13 @@ static int ftrace_modify_code(unsigned long pc, u32 new) int ftrace_update_ftrace_func(ftrace_func_t func) { unsigned long pc; - int ret; u32 new; current_tracer = (unsigned long)func; - pc = (unsigned long)&ftrace_call; + new = SW64_CALL(R26, R27, 1); - new = sw64_insn_call(R26, R27); - if (ftrace_modify_code(pc, new)) - return ret; - return 0; + return ftrace_modify_code(pc, new); } /* @@ -65,19 +53,16 @@ int ftrace_update_ftrace_func(ftrace_func_t func) */ int ftrace_make_call(struct dyn_ftrace *rec, unsigned long addr) { - unsigned long pc = rec->ip; - u32 new; - int ret; + unsigned int insn[3]; + unsigned long pc = rec->ip + MCOUNT_LDGP_SIZE; + insn[0] = SW64_NOP; /* ldl r28,(ftrace_addr_offset)(r8) */ - new = (0x23U << 26) | (28U << 21) | (8U << 16) | offsetof(struct thread_info, dyn_ftrace_addr); - if (ftrace_modify_code(pc, new)) - return ret; - pc = pc + 4; - new = sw64_insn_call(R28, R28); - if (ftrace_modify_code(pc, new)) - return ret; - return 0; + insn[1] = (0x23U << 26) | (28U << 21) | (8U << 16) | TI_FTRACE_ADDR; + insn[2] = SW64_CALL(R28, R28, 1); + + /* replace the 3 mcount instructions at once */ + return copy_to_kernel_nofault((void *)pc, insn, 3 * SW64_INSN_SIZE); } /* @@ -86,15 +71,10 @@ int ftrace_make_call(struct dyn_ftrace *rec, unsigned long addr) int ftrace_make_nop(struct module *mod, struct dyn_ftrace *rec, unsigned long addr) { - unsigned long pc = rec->ip; - unsigned long insn; - int ret; - - insn = sw64_insn_nop(); - insn = (insn << 32) | insn; - ret = ftrace_modify_double_code(pc, insn); - return ret; + unsigned long pc = rec->ip + MCOUNT_LDGP_SIZE; + unsigned int insn[3] = {SW64_NOP, SW64_NOP, SW64_NOP}; + return copy_to_kernel_nofault((void *)pc, insn, 3 * SW64_INSN_SIZE); } void arch_ftrace_update_code(int command) diff --git a/scripts/recordmcount.c b/scripts/recordmcount.c index 84ea65aec015..f7cf4fd36898 100644 --- a/scripts/recordmcount.c +++ b/scripts/recordmcount.c @@ -40,8 +40,8 @@ #ifndef EM_SW64 #define EM_SW64 0x9916 -#define R_SW_64_NONE 0 -#define R_SW_64_REFQUAD 2 /* Direct 64 bit */ +#define R_SW64_NONE 0 +#define R_SW64_REFQUAD 2 /* Direct 64 bit */ #endif #define R_ARM_PC24 1 @@ -320,8 +320,9 @@ static int make_nop_arm64(void *map, size_t const offset) return 0; } -static unsigned char ideal_nop4_sw_64[4] = {0x5f, 0x07, 0xff, 0x43}; -static int make_nop_sw_64(void *map, size_t const offset) +static unsigned char ideal_nop4_sw64[4] = {0x5f, 0x07, 0xff, 0x43}; + +static int make_nop_sw64(void *map, size_t const offset) { /* Convert to nop */ ulseek(offset, SEEK_SET); @@ -456,6 +457,21 @@ static int arm64_is_fake_mcount(Elf64_Rel const *rp) return ELF64_R_TYPE(w8(rp->r_info)) != R_AARCH64_CALL26; } +#define SW64_FAKEMCOUNT_OFFSET 4 + +static int sw64_is_fake_mcount(Elf64_Rel const *rp) +{ + static Elf64_Addr old_r_offset = ~(Elf64_Addr)0; + Elf64_Addr current_r_offset = _w(rp->r_offset); + int is_fake; + + is_fake = (old_r_offset != ~(Elf64_Addr)0) && + (current_r_offset - old_r_offset == SW64_FAKEMCOUNT_OFFSET); + old_r_offset = current_r_offset; + + return is_fake; +} + /* 64-bit EM_MIPS has weird ELF64_Rela.r_info. * http://techpubs.sgi.com/library/manuals/4000/007-4658-001/pdf/007-4658-001.pdf * We interpret Table 29 Relocation Operation (Elf64_Rel, Elf64_Rela) [p.40] @@ -572,10 +588,12 @@ static int do_file(char const *const fname) is_fake_mcount64 = arm64_is_fake_mcount; break; case EM_SW64: - reltype = R_SW_64_REFQUAD; - make_nop = make_nop_sw_64; - rel_type_nop = R_SW_64_NONE; - ideal_nop = ideal_nop4_sw_64; + reltype = R_SW64_REFQUAD; + make_nop = make_nop_sw64; + rel_type_nop = R_SW64_NONE; + ideal_nop = ideal_nop4_sw64; + mcount_adjust_64 = -12; + is_fake_mcount64 = sw64_is_fake_mcount; break; case EM_IA_64: reltype = R_IA64_IMM64; break; case EM_MIPS: /* reltype: e_class */ break; @@ -631,9 +649,6 @@ static int do_file(char const *const fname) Elf64_r_info = MIPS64_r_info; is_fake_mcount64 = MIPS64_is_fake_mcount; } - if (w2(ghdr->e_machine) == EM_SW64) - is_fake_mcount64 = MIPS64_is_fake_mcount; - if (do64(ghdr, fname, reltype) < 0) goto out; break; -- Gitee From 19945ae59bc56ebf2be10a440695cacf31fc3391 Mon Sep 17 00:00:00 2001 From: Dai Xin Date: Tue, 1 Nov 2022 17:07:27 +0000 Subject: [PATCH 13/27] sw64: acpi: fix compilation dependency when CONFIG_PCI=n Sunway inclusion category: feature bugzilla: https://gitee.com/openeuler/kernel/issues/I56OLG -------------------------------- Signed-off-by: Dai Xin Reviewed-by: He Sheng Signed-off-by: Gu Zitao --- drivers/hwmon/sw64_pvt.c | 1 + drivers/irqchip/irq-sw64-intc-v2.c | 4 ++++ 2 files changed, 5 insertions(+) diff --git a/drivers/hwmon/sw64_pvt.c b/drivers/hwmon/sw64_pvt.c index 9e292a90af38..29098bc1f645 100644 --- a/drivers/hwmon/sw64_pvt.c +++ b/drivers/hwmon/sw64_pvt.c @@ -11,6 +11,7 @@ #include #include #include +#include #include #define PVT_VSYS 0 diff --git a/drivers/irqchip/irq-sw64-intc-v2.c b/drivers/irqchip/irq-sw64-intc-v2.c index 8640c4aa9506..070c12ede959 100644 --- a/drivers/irqchip/irq-sw64-intc-v2.c +++ b/drivers/irqchip/irq-sw64-intc-v2.c @@ -34,6 +34,7 @@ static const struct irq_domain_ops sw64_intc_domain_ops = { .map = sw64_intc_domain_map, }; +#ifdef CONFIG_ACPI static int __init intc_parse_madt(union acpi_subtable_headers *header, const unsigned long end) @@ -91,7 +92,9 @@ static int __init intc_init(void) } subsys_initcall(intc_init); +#endif +#ifdef CONFIG_OF static struct irq_domain *root_domain; static int __init @@ -143,3 +146,4 @@ init_onchip_vt_IRQ(struct device_node *intc, struct device_node *parent) } IRQCHIP_DECLARE(sw64_vt_intc, "sw64,sw6_irq_vt_controller", init_onchip_vt_IRQ); +#endif -- Gitee From 4c655b2b486e760187251bb7a80564202fe1a2c5 Mon Sep 17 00:00:00 2001 From: Gu Zitao Date: Wed, 2 Nov 2022 14:18:00 +0800 Subject: [PATCH 14/27] sw64: add basic livepatch support on SW64 Sunway inclusion category: feature bugzilla: https://gitee.com/openeuler/kernel/issues/I645PM -------------------------------- This patch adds livepatch support on SW64. It requires support from DYNAMIC_FTRACE_WITH_REGS option. Livepatch is handled by a special ftrace handler ftrace_regs_caller(). The livepatch handler modifies the regs->r28 so as to make ftrace_regs_caller() return to the new patched function. Signed-off-by: Gu Zitao Reviewed-by: He Sheng Signed-off-by: Gu Zitao --- arch/sw_64/Kconfig | 5 ++ arch/sw_64/include/asm/ftrace.h | 2 + arch/sw_64/include/asm/livepatch.h | 22 +++++++ arch/sw_64/include/asm/thread_info.h | 4 ++ arch/sw_64/kernel/entry-ftrace.S | 94 ++++++++++++++++++++++++++++ arch/sw_64/kernel/ftrace.c | 33 +++++++++- arch/sw_64/kernel/stacktrace.c | 8 +++ 7 files changed, 165 insertions(+), 3 deletions(-) create mode 100644 arch/sw_64/include/asm/livepatch.h diff --git a/arch/sw_64/Kconfig b/arch/sw_64/Kconfig index b37a4f4e093e..47dc877c03f3 100644 --- a/arch/sw_64/Kconfig +++ b/arch/sw_64/Kconfig @@ -70,6 +70,7 @@ config SW64 select HAVE_C_RECORDMCOUNT select HAVE_DEBUG_BUGVERBOSE select HAVE_DYNAMIC_FTRACE + select HAVE_DYNAMIC_FTRACE_WITH_REGS select HAVE_EBPF_JIT select HAVE_FAST_GUP select HAVE_FTRACE_MCOUNT_RECORD @@ -78,6 +79,7 @@ config SW64 select HAVE_IDE select HAVE_KPROBES select HAVE_KRETPROBES + select HAVE_LIVEPATCH if HAVE_DYNAMIC_FTRACE_WITH_REGS select HAVE_MEMBLOCK select HAVE_MEMBLOCK_NODE_MAP select HAVE_MOD_ARCH_SPECIFIC @@ -88,6 +90,7 @@ config SW64 select HAVE_PERF_REGS select HAVE_PERF_USER_STACK_DUMP select HAVE_REGS_AND_STACK_ACCESS_API + select HAVE_RELIABLE_STACKTRACE if STACKTRACE select HAVE_SYSCALL_TRACEPOINTS select IRQ_FORCED_THREADING select MEMORY_HOTPLUG_SPARSE if MEMORY_HOTPLUG @@ -651,6 +654,8 @@ config ARCH_SPARSEMEM_ENABLE depends on SMP select SPARSEMEM_VMEMMAP_ENABLE +source "kernel/livepatch/Kconfig" + config NUMA bool "NUMA Support" depends on SMP && !FLATMEM diff --git a/arch/sw_64/include/asm/ftrace.h b/arch/sw_64/include/asm/ftrace.h index 61933103dcd4..d211b8ce1d18 100644 --- a/arch/sw_64/include/asm/ftrace.h +++ b/arch/sw_64/include/asm/ftrace.h @@ -15,6 +15,8 @@ #define MCOUNT_INSN_SIZE 20 /* 5 * SW64_INSN_SIZE */ #define MCOUNT_LDGP_SIZE 8 /* 2 * SW64_INSN_SIZE */ +#define ARCH_SUPPORTS_FTRACE_OPS 1 + #ifndef __ASSEMBLY__ #include #include diff --git a/arch/sw_64/include/asm/livepatch.h b/arch/sw_64/include/asm/livepatch.h new file mode 100644 index 000000000000..f93c2131113b --- /dev/null +++ b/arch/sw_64/include/asm/livepatch.h @@ -0,0 +1,22 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * livepatch.h - sw64-specific Kernel Live Patching Core + */ + +#ifndef _ASM_SW64_LIVEPATCH_H +#define _ASM_SW64_LIVEPATCH_H + +#include + +static inline int klp_check_compiler_support(void) +{ + return 0; +} + +static inline void klp_arch_set_pc(struct pt_regs *regs, unsigned long ip) +{ + regs->r27 = ip; + regs->r28 = ip; +} + +#endif /* _ASM_SW64_LIVEPATCH_H */ diff --git a/arch/sw_64/include/asm/thread_info.h b/arch/sw_64/include/asm/thread_info.h index 7cdafaec62e4..c9637d32e1be 100644 --- a/arch/sw_64/include/asm/thread_info.h +++ b/arch/sw_64/include/asm/thread_info.h @@ -39,6 +39,9 @@ struct thread_info { unsigned int bpt_insn[2]; #ifdef CONFIG_DYNAMIC_FTRACE unsigned long dyn_ftrace_addr; +#ifdef CONFIG_DYNAMIC_FTRACE_WITH_REGS + unsigned long dyn_ftrace_regs_addr; +#endif #endif }; @@ -84,6 +87,7 @@ register struct thread_info *__current_thread_info __asm__("$8"); #define TIF_NEED_RESCHED 3 /* rescheduling necessary */ #define TIF_SYSCALL_AUDIT 4 /* syscall audit active */ #define TIF_UPROBE 5 /* uprobe breakpoint or singlestep */ +#define TIF_PATCH_PENDING 6 /* pending live patching update */ #define TIF_DIE_IF_KERNEL 9 /* dik recursion lock */ #define TIF_SYSCALL_TRACEPOINT 10 #define TIF_SECCOMP 11 /* secure computing */ diff --git a/arch/sw_64/kernel/entry-ftrace.S b/arch/sw_64/kernel/entry-ftrace.S index 07bdf5a6e35a..1b8896d1f631 100644 --- a/arch/sw_64/kernel/entry-ftrace.S +++ b/arch/sw_64/kernel/entry-ftrace.S @@ -10,6 +10,7 @@ * */ #include +#include #include .text @@ -45,6 +46,72 @@ addl $sp, FTRACE_SP_OFF, $sp .endm + .macro SAVE_PT_REGS + ldi $sp, -PT_REGS_SIZE($sp) + stl $0, PT_REGS_R0($sp) + stl $1, PT_REGS_R1($sp) + stl $2, PT_REGS_R2($sp) + stl $3, PT_REGS_R3($sp) + stl $4, PT_REGS_R4($sp) + stl $5, PT_REGS_R5($sp) + stl $6, PT_REGS_R6($sp) + stl $7, PT_REGS_R7($sp) + stl $8, PT_REGS_R8($sp) + stl $9, PT_REGS_R9($sp) + stl $10, PT_REGS_R10($sp) + stl $11, PT_REGS_R11($sp) + stl $12, PT_REGS_R12($sp) + stl $13, PT_REGS_R13($sp) + stl $14, PT_REGS_R14($sp) + stl $15, PT_REGS_R15($sp) + stl $16, PT_REGS_R16($sp) + stl $17, PT_REGS_R17($sp) + stl $18, PT_REGS_R18($sp) + stl $19, PT_REGS_R19($sp) + stl $20, PT_REGS_R20($sp) + stl $21, PT_REGS_R21($sp) + stl $22, PT_REGS_R22($sp) + stl $23, PT_REGS_R23($sp) + stl $24, PT_REGS_R24($sp) + stl $25, PT_REGS_R25($sp) + stl $26, PT_REGS_R26($sp) + stl $27, PT_REGS_R27($sp) + stl $28, PT_REGS_R28($sp) + .endm + + .macro RESTORE_PT_REGS + ldl $0, PT_REGS_R0($sp) + ldl $1, PT_REGS_R1($sp) + ldl $2, PT_REGS_R2($sp) + ldl $3, PT_REGS_R3($sp) + ldl $4, PT_REGS_R4($sp) + ldl $5, PT_REGS_R5($sp) + ldl $6, PT_REGS_R6($sp) + ldl $7, PT_REGS_R7($sp) + ldl $8, PT_REGS_R8($sp) + ldl $9, PT_REGS_R9($sp) + ldl $10, PT_REGS_R10($sp) + ldl $11, PT_REGS_R11($sp) + ldl $12, PT_REGS_R12($sp) + ldl $13, PT_REGS_R13($sp) + ldl $14, PT_REGS_R14($sp) + ldl $15, PT_REGS_R15($sp) + ldl $16, PT_REGS_R16($sp) + ldl $17, PT_REGS_R17($sp) + ldl $18, PT_REGS_R18($sp) + ldl $19, PT_REGS_R19($sp) + ldl $20, PT_REGS_R20($sp) + ldl $21, PT_REGS_R21($sp) + ldl $22, PT_REGS_R22($sp) + ldl $23, PT_REGS_R23($sp) + ldl $24, PT_REGS_R24($sp) + ldl $25, PT_REGS_R25($sp) + ldl $26, PT_REGS_R26($sp) + ldl $27, PT_REGS_R27($sp) + ldl $28, PT_REGS_R28($sp) + ldi $sp, PT_REGS_SIZE($sp) + .endm + #ifdef CONFIG_DYNAMIC_FTRACE .global _mcount .ent _mcount @@ -122,6 +189,33 @@ skip_ftrace: #endif /* CONFIG_DYNAMIC_FTRACE */ +#ifdef CONFIG_DYNAMIC_FTRACE_WITH_REGS + .global ftrace_regs_caller + .ent ftrace_regs_caller +ftrace_regs_caller: + SAVE_PT_REGS + + br $27, 2f +2: ldgp $29, 0($27) + + subl $28, MCOUNT_INSN_SIZE, $16 + bis $26, $31, $17 + ldi $4, function_trace_op + ldl $18, 0($4) + mov $sp, $19 + + ldi $4, current_tracer + ldl $27, 0($4) + + .global ftrace_regs_call +ftrace_regs_call: + nop + + RESTORE_PT_REGS + ret $31, ($28), 1 + .end ftrace_regs_caller +#endif /* CONFIG_DYNAMIC_FTRACE_WITH_REGS */ + .global ftrace_stub .ent ftrace_stub ftrace_stub: diff --git a/arch/sw_64/kernel/ftrace.c b/arch/sw_64/kernel/ftrace.c index cf1524c15f15..a2784feaf150 100644 --- a/arch/sw_64/kernel/ftrace.c +++ b/arch/sw_64/kernel/ftrace.c @@ -20,6 +20,8 @@ EXPORT_SYMBOL(_mcount); #ifdef CONFIG_DYNAMIC_FTRACE #define TI_FTRACE_ADDR (offsetof(struct thread_info, dyn_ftrace_addr)) +#define TI_FTRACE_REGS_ADDR \ + (offsetof(struct thread_info, dyn_ftrace_regs_addr)) unsigned long current_tracer = (unsigned long)ftrace_stub; @@ -40,12 +42,20 @@ int ftrace_update_ftrace_func(ftrace_func_t func) { unsigned long pc; u32 new; + int ret; current_tracer = (unsigned long)func; pc = (unsigned long)&ftrace_call; new = SW64_CALL(R26, R27, 1); + ret = ftrace_modify_code(pc, new); - return ftrace_modify_code(pc, new); + if (!ret) { + pc = (unsigned long)&ftrace_regs_call; + new = SW64_CALL(R26, R27, 1); + ret = ftrace_modify_code(pc, new); + } + + return ret; } /* @@ -55,10 +65,16 @@ int ftrace_make_call(struct dyn_ftrace *rec, unsigned long addr) { unsigned int insn[3]; unsigned long pc = rec->ip + MCOUNT_LDGP_SIZE; + unsigned long offset; + + if (addr == FTRACE_ADDR) + offset = TI_FTRACE_ADDR; + else + offset = TI_FTRACE_REGS_ADDR; insn[0] = SW64_NOP; /* ldl r28,(ftrace_addr_offset)(r8) */ - insn[1] = (0x23U << 26) | (28U << 21) | (8U << 16) | TI_FTRACE_ADDR; + insn[1] = (0x23U << 26) | (28U << 21) | (8U << 16) | offset; insn[2] = SW64_CALL(R28, R28, 1); /* replace the 3 mcount instructions at once */ @@ -82,14 +98,25 @@ void arch_ftrace_update_code(int command) ftrace_modify_all_code(command); } -/*tracer_addr must be same with syscall_ftrace*/ int __init ftrace_dyn_arch_init(void) { init_thread_info.dyn_ftrace_addr = FTRACE_ADDR; + +#ifdef CONFIG_DYNAMIC_FTRACE_WITH_REGS + init_thread_info.dyn_ftrace_regs_addr = FTRACE_REGS_ADDR; +#endif return 0; } #endif /* CONFIG_DYNAMIC_FTRACE */ +#ifdef CONFIG_DYNAMIC_FTRACE_WITH_REGS +int ftrace_modify_call(struct dyn_ftrace *rec, unsigned long old_addr, + unsigned long addr) +{ + return 0; +} +#endif + #ifdef CONFIG_FUNCTION_GRAPH_TRACER /* * function_graph tracer expects ftrace_return_to_handler() to be called diff --git a/arch/sw_64/kernel/stacktrace.c b/arch/sw_64/kernel/stacktrace.c index 70c142b11b92..71c0e5b7b3e0 100644 --- a/arch/sw_64/kernel/stacktrace.c +++ b/arch/sw_64/kernel/stacktrace.c @@ -222,3 +222,11 @@ unsigned long get_wchan(struct task_struct *tsk) return pc; } + +#ifdef CONFIG_HAVE_RELIABLE_STACKTRACE +int save_stack_trace_tsk_reliable(struct task_struct *tsk, + struct stack_trace *trace) +{ + return 0; +} +#endif -- Gitee From 057bcf8c9cfdc7dc469750831a8ad5c56d3b2350 Mon Sep 17 00:00:00 2001 From: Mao Minkai Date: Mon, 7 Nov 2022 14:11:47 +0800 Subject: [PATCH 15/27] sw64: bpf: improve BPF_CALL address check Sunway inclusion category: feature bugzilla: https://gitee.com/openeuler/kernel/issues/I645QF -------------------------------- Improve BPF_CALL address check by using macros to support different address spaces. Signed-off-by: Mao Minkai Reviewed-by: He Sheng Signed-off-by: Gu Zitao --- arch/sw_64/net/bpf_jit_comp.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/arch/sw_64/net/bpf_jit_comp.c b/arch/sw_64/net/bpf_jit_comp.c index 2c238c33e574..47e805569154 100644 --- a/arch/sw_64/net/bpf_jit_comp.c +++ b/arch/sw_64/net/bpf_jit_comp.c @@ -1182,9 +1182,9 @@ static int build_insn(const struct bpf_insn *insn, struct jit_ctx *ctx) case BPF_JMP | BPF_CALL: func = (u64)__bpf_call_base + imm; - if ((func & 0xffffffffe0000000UL) != 0xffffffff80000000UL) + if ((func & ~(KERNEL_IMAGE_SIZE - 1)) != __START_KERNEL_map) /* calling bpf program, switch to vmalloc addr */ - func = (func & 0xffffffff) | 0xfffff00000000000UL; + func = (func & U32_MAX) | VMALLOC_START; emit_sw64_ldu64(SW64_BPF_REG_PV, func, ctx); emit(SW64_BPF_CALL(SW64_BPF_REG_RA, SW64_BPF_REG_PV), ctx); break; -- Gitee From 479d48674c021e7522dc7b811ee1fc8f197a8af1 Mon Sep 17 00:00:00 2001 From: Mao Minkai Date: Mon, 7 Nov 2022 14:28:45 +0800 Subject: [PATCH 16/27] sw64: fix memmap_range_valid() Sunway inclusion category: bugfix bugzilla: https://gitee.com/openeuler/kernel/issues/I645QZ -------------------------------- Fix memmap_range_valid() so users can reserve memory successfully even part of the requested space extends beyond end of memory. Signed-off-by: Mao Minkai Reviewed-by: He Sheng Signed-off-by: Gu Zitao --- arch/sw_64/kernel/setup.c | 39 ++++++++++++++++++--------------------- 1 file changed, 18 insertions(+), 21 deletions(-) diff --git a/arch/sw_64/kernel/setup.c b/arch/sw_64/kernel/setup.c index d4c97741616f..5ec55554caf6 100644 --- a/arch/sw_64/kernel/setup.c +++ b/arch/sw_64/kernel/setup.c @@ -336,12 +336,15 @@ static void * __init move_initrd(unsigned long mem_limit) } #endif -static int __init memmap_range_valid(phys_addr_t base, phys_addr_t size) +static bool __init memmap_range_valid(phys_addr_t base, phys_addr_t *size) { - if ((base + size) <= memblock_end_of_DRAM()) - return true; - else + if (base > memblock_end_of_DRAM()) return false; + + if ((base + *size) > memblock_end_of_DRAM()) + *size = memblock_end_of_DRAM() - base; + + return true; } void __init process_memmap(void) @@ -359,8 +362,8 @@ void __init process_memmap(void) size = memmap_map[i].size; switch (memmap_map[i].type) { case memmap_reserved: - if (!memmap_range_valid(base, size)) { - pr_err("reserved memmap region [mem %#018llx-%#018llx] extends beyond end of memory (%#018llx)\n", + if (!memmap_range_valid(base, &size)) { + pr_err("reserved memmap region [mem %#018llx-%#018llx] beyond end of memory (%#018llx)\n", base, base + size - 1, memblock_end_of_DRAM()); } else { pr_info("reserved memmap region [mem %#018llx-%#018llx]\n", @@ -375,8 +378,8 @@ void __init process_memmap(void) } break; case memmap_pci: - if (!memmap_range_valid(base, size)) { - pr_info("pci memmap region [mem %#018llx-%#018llx] extends beyond end of memory (%#018llx)\n", + if (!memmap_range_valid(base, &size)) { + pr_err("pci memmap region [mem %#018llx-%#018llx] beyond end of memory (%#018llx)\n", base, base + size - 1, memblock_end_of_DRAM()); } else { pr_info("pci memmap region [mem %#018llx-%#018llx]\n", @@ -388,29 +391,23 @@ void __init process_memmap(void) } break; case memmap_initrd: - if (!memmap_range_valid(base, size)) { + if ((base + size) > memblock_end_of_DRAM()) { phys_addr_t old_base = base; base = (unsigned long) move_initrd(memblock_end_of_DRAM()); if (!base) { pr_err("initrd memmap region [mem %#018llx-%#018llx] extends beyond end of memory (%#018llx)\n", old_base, old_base + size - 1, memblock_end_of_DRAM()); + break; } else { memmap_map[i].addr = base; - pr_info("initrd memmap region [mem %#018llx-%#018llx]\n", - base, base + size - 1); - ret = memblock_reserve(base, size); - if (ret) - pr_err("reserve memmap region [mem %#018llx-%#018llx] failed\n", - base, base + size - 1); } - } else { - pr_info("initrd memmap region [mem %#018llx-%#018llx]\n", base, base + size - 1); - ret = memblock_reserve(base, size); - if (ret) - pr_err("reserve memmap region [mem %#018llx-%#018llx] failed\n", - base, base + size - 1); } + pr_info("initrd memmap region [mem %#018llx-%#018llx]\n", base, base + size - 1); + ret = memblock_reserve(base, size); + if (ret) + pr_err("reserve memmap region [mem %#018llx-%#018llx] failed\n", + base, base + size - 1); break; case memmap_kvm: case memmap_crashkernel: -- Gitee From 8be9fdf9552faa75753c1ef63451a39876bbffdb Mon Sep 17 00:00:00 2001 From: Gu Zitao Date: Mon, 7 Nov 2022 14:17:32 +0800 Subject: [PATCH 17/27] sw64: mark sched_clock() as notrace Sunway inclusion category: bugfix bugzilla: https://gitee.com/openeuler/kernel/issues/I645RC -------------------------------- sched_clock() of SW64 has no notrace mark like the generic declaration and it will cause kernel crash in ftrace selftests. Add notrace to fix it. Signed-off-by: Gu Zitao Reviewed-by: He Sheng Signed-off-by: Gu Zitao --- arch/sw_64/kernel/time.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/sw_64/kernel/time.c b/arch/sw_64/kernel/time.c index 32690e78849b..8be7a11df51d 100644 --- a/arch/sw_64/kernel/time.c +++ b/arch/sw_64/kernel/time.c @@ -143,7 +143,7 @@ void __init sw64_sched_clock_init(void) sched_clock_register(sched_clock_read, BITS_PER_LONG, get_cpu_freq() >> sc_shift); } #else -unsigned long long sched_clock(void) +unsigned long long notrace sched_clock(void) { if (static_branch_likely(&use_tc_as_sched_clock)) return ((rdtc() - sc_start + __this_cpu_read(tc_offset)) >> sc_shift) * sc_multi; -- Gitee From 83af590138bc79dfee8df8d2ec46c2bce510c5d5 Mon Sep 17 00:00:00 2001 From: Gu Zitao Date: Thu, 10 Nov 2022 08:44:07 +0800 Subject: [PATCH 18/27] sw64: ftrace: fix ARCH_SUPPORTS_FTRACE_OPS support Sunway inclusion category: bugfix bugzilla: https://gitee.com/openeuler/kernel/issues/I645RV -------------------------------- ARCH_SUPPORTS_FTRACE_OPS support was introduced with livepatch, but it didn't pass function_trace_op to tracer in ftrace_caller, and kernel will crash in ftrace func_profiler test. To fix this problem, pass function_trace_op to tracer as the 3rd argument. Signed-off-by: Gu Zitao Reviewed-by: He Sheng Signed-off-by: Gu Zitao --- arch/sw_64/kernel/entry-ftrace.S | 1 + 1 file changed, 1 insertion(+) diff --git a/arch/sw_64/kernel/entry-ftrace.S b/arch/sw_64/kernel/entry-ftrace.S index 1b8896d1f631..6e659bff5775 100644 --- a/arch/sw_64/kernel/entry-ftrace.S +++ b/arch/sw_64/kernel/entry-ftrace.S @@ -130,6 +130,7 @@ ftrace_caller: subl $28, MCOUNT_INSN_SIZE, $16 bis $26, $31, $17 + ldl $18, function_trace_op ldi $4, current_tracer ldl $27, 0($4) -- Gitee From 380566df0b6d22383cbd1c9c6daf5fbeeb262549 Mon Sep 17 00:00:00 2001 From: He Sheng Date: Mon, 7 Nov 2022 16:59:45 +0800 Subject: [PATCH 19/27] sw64: generate call instruction with disp 0 Sunway inclusion category: feature bugzilla: https://gitee.com/openeuler/kernel/issues/I645S9 -------------------------------- The disp is jump hint and target is PC+4*SEXT(disp[15:0]). Signed-off-by: He Sheng Reviewed-by: Cui Wei Signed-off-by: Gu Zitao --- arch/sw_64/kernel/ftrace.c | 6 +++--- arch/sw_64/kernel/insn.c | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/arch/sw_64/kernel/ftrace.c b/arch/sw_64/kernel/ftrace.c index a2784feaf150..4bd89c709ad5 100644 --- a/arch/sw_64/kernel/ftrace.c +++ b/arch/sw_64/kernel/ftrace.c @@ -46,12 +46,12 @@ int ftrace_update_ftrace_func(ftrace_func_t func) current_tracer = (unsigned long)func; pc = (unsigned long)&ftrace_call; - new = SW64_CALL(R26, R27, 1); + new = SW64_CALL(R26, R27, 0); ret = ftrace_modify_code(pc, new); if (!ret) { pc = (unsigned long)&ftrace_regs_call; - new = SW64_CALL(R26, R27, 1); + new = SW64_CALL(R26, R27, 0); ret = ftrace_modify_code(pc, new); } @@ -75,7 +75,7 @@ int ftrace_make_call(struct dyn_ftrace *rec, unsigned long addr) insn[0] = SW64_NOP; /* ldl r28,(ftrace_addr_offset)(r8) */ insn[1] = (0x23U << 26) | (28U << 21) | (8U << 16) | offset; - insn[2] = SW64_CALL(R28, R28, 1); + insn[2] = SW64_CALL(R28, R28, 0); /* replace the 3 mcount instructions at once */ return copy_to_kernel_nofault((void *)pc, insn, 3 * SW64_INSN_SIZE); diff --git a/arch/sw_64/kernel/insn.c b/arch/sw_64/kernel/insn.c index e8dd41b6b7c4..281578e1bfc0 100644 --- a/arch/sw_64/kernel/insn.c +++ b/arch/sw_64/kernel/insn.c @@ -84,7 +84,7 @@ unsigned int __kprobes sw64_insn_nop(void) unsigned int __kprobes sw64_insn_call(unsigned int ra, unsigned int rb) { - return SW64_CALL(ra, rb, 1); + return SW64_CALL(ra, rb, 0); } unsigned int __kprobes sw64_insn_sys_call(unsigned int num) -- Gitee From 4a1bc3498955d37aaa6ca7f5d17daeffb74128ae Mon Sep 17 00:00:00 2001 From: He Sheng Date: Mon, 7 Nov 2022 17:12:03 +0800 Subject: [PATCH 20/27] sw64: ftrace: fix function graph tracing support Sunway inclusion category: feature bugzilla: https://gitee.com/openeuler/kernel/issues/I645S9 -------------------------------- Rewrite ftrace_graph_caller to support function graph tracing for ftrace_regs_caller, ftrace_caller and _mcount. To enable function graph tracing, the nop instruction at ftrace_graph_call is replaced with "call $26, ($27)" instruction. To disable tracing, replace the nop instruction back. Signed-off-by: He Sheng Reviewed-by: Cui Wei Signed-off-by: Gu Zitao --- arch/sw_64/kernel/entry-ftrace.S | 230 ++++++++++++++++++------------- arch/sw_64/kernel/ftrace.c | 10 +- 2 files changed, 135 insertions(+), 105 deletions(-) diff --git a/arch/sw_64/kernel/entry-ftrace.S b/arch/sw_64/kernel/entry-ftrace.S index 6e659bff5775..26bcc71b9db1 100644 --- a/arch/sw_64/kernel/entry-ftrace.S +++ b/arch/sw_64/kernel/entry-ftrace.S @@ -24,7 +24,9 @@ stl $17, 0x8($sp) stl $18, 0x10($sp) stl $26, 0x18($sp) - stl $27, 0x20($sp) +#ifdef CONFIG_FUNCTION_GRAPH_TRACER + stl $9, 0x20($sp) +#endif stl $28, 0x28($sp) stl $29, 0x30($sp) stl $19, 0x38($sp) @@ -37,7 +39,9 @@ ldl $17, 0x8($sp) ldl $18, 0x10($sp) ldl $26, 0x18($sp) - ldl $27, 0x20($sp) +#ifdef CONFIG_FUNCTION_GRAPH_TRACER + ldl $9, 0x20($sp) +#endif ldl $28, 0x28($sp) ldl $29, 0x30($sp) ldl $19, 0x38($sp) @@ -46,6 +50,14 @@ addl $sp, FTRACE_SP_OFF, $sp .endm + .macro RESTORE_GRAPH_ARGS + ldi $16, 0x18($sp) /* &ra */ + bis $31, $9, $17 /* pc */ + #ifdef HAVE_FUNCTION_GRAPH_FP_TEST + bis $31, $15, $18 /* fp */ + #endif + .endm + .macro SAVE_PT_REGS ldi $sp, -PT_REGS_SIZE($sp) stl $0, PT_REGS_R0($sp) @@ -112,6 +124,84 @@ ldi $sp, PT_REGS_SIZE($sp) .endm + .macro RESTORE_GRAPH_REG_ARGS + ldi $16, PT_REGS_R26($sp) + bis $31, $9, $17 +#ifdef HAVE_FUNCTION_GRAPH_FP_TEST + bis $31, $15, $18 +#endif + .endm + + /* save return value regs*/ + .macro save_return_regs + subl $sp, 0x8, $sp + stl $0, 0x0($sp) + .endm + + /* restore return value regs*/ + .macro restore_return_regs + ldl $0, 0x0($sp) + addl $sp, 0x8, $sp + .endm + + +#ifdef CONFIG_FUNCTION_GRAPH_TRACER +/* + * void ftrace_graph_caller(void) + * + * Called from ftrace_caller() or ftrace_regs_caller() when function_graph + * tracer is selected. + * This function prepare_ftrace_return() fakes ra's value on the call + * stack in order to intercept instrumented function's return path and + * run return_to_handler() later on its exit. + */ + +ENTRY(ftrace_graph_caller) + ldgp $29, 0($27) + ldi $sp, -16($sp) + stl $26, 0($sp) + stl $15, 8($sp) + bis $31, $sp, $15 + + ldi $27, prepare_ftrace_return +ftrace_graph_call: + .global ftrace_graph_call + /* + * Calling ftrace_enable/disable_ftrace_graph_caller would overwrite + * the nop below. + */ + nop /* nop, or call prepare_ftrace_return() */ + + ldl $26, 0($sp) + ldl $15, 8($sp) + ldi $sp, 16($sp) + ret $31, ($26), 1 +ENDPROC(ftrace_graph_caller) + +/* + * void return_to_handler(void) + * + * Run ftrace_return_to_handler() before going back to parent. + * @fp is checked against the value passed by ftrace_graph_caller() + * only when HAVE_FUNCTION_GRAPH_FP_TEST is enabled. + * + * It is run by "ret" instruction which does not modify $27, so it + * has to recaculate $27 before ldgp. + */ +ENTRY(return_to_handler) + br $27, 1f +1: ldgp $29, 0($27) + save_return_regs + bis $31, $15, $16 /* parent's fp */ + ldi $27, ftrace_return_to_handler + call $26, ($27) + bis $31, $0, $26 + restore_return_regs + ret $31, ($26), 1 +END(return_to_handler) + +#endif + #ifdef CONFIG_DYNAMIC_FTRACE .global _mcount .ent _mcount @@ -124,27 +214,31 @@ _mcount: .ent ftrace_caller ftrace_caller: mcount_enter - - br $27, 2f -2: ldgp $29, 0($27) + br $27, 1f +1: ldgp $29, 0($27) subl $28, MCOUNT_INSN_SIZE, $16 bis $26, $31, $17 ldl $18, function_trace_op +#ifdef CONFIG_FUNCTION_GRAPH_TRACER + /* + * the graph tracer (specifically, prepare_ftrace_return) needs these + * arguments but for now the function tracer occupies the regs, so we + * save them in callee-saved regs to recover later. + */ + bis $31, $16, $9 +#endif ldi $4, current_tracer ldl $27, 0($4) .global ftrace_call -ftrace_call: /* tracer(pc, lr); call 26, 27 , 1 */ +ftrace_call: /* tracer(pc, ra); */ nop #ifdef CONFIG_FUNCTION_GRAPH_TRACER - ldi $27, prepare_ftrace_return /* prepare_ftrace_return(&lr, pc, fp) */ - .global ftrace_graph_call -ftrace_graph_call: /* ftrace_graph_caller(); */ - nop /* If enabled, this will be replaced */ - /* "br ftrace_graph_caller" */ + RESTORE_GRAPH_ARGS + call ftrace_graph_caller #endif mcount_end ret $31, ($28), 1 @@ -155,36 +249,34 @@ ftrace_graph_call: /* ftrace_graph_caller(); */ .ent _mcount _mcount: mcount_enter - br $27, 1f 1: ldgp $29, 0($27) - ldi $4, ftrace_trace_function - ldl $27, 0($4) - ldi $5, ftrace_stub - cmpeq $4, $5, $6 + ldl $27, ftrace_trace_function // if (ftrace_trace_function + ldi $5, ftrace_stub // != ftrace_stub) + cmpeq $27, $5, $6 // bne $6, skip_ftrace - subl $28, MCOUNT_INSN_SIZE, $16 - bis $26, $31, $17 - call $26, ($27), 1 + subl $28, MCOUNT_INSN_SIZE, $16 // function's pc +#ifdef CONFIG_FUNCTION_GRAPH_TRACER + bis $31, $16, $9 +#endif + bis $26, $31, $17 // function's ra (parent's pc) + call $26, ($27) // (*ftrace_trace_function)(pc, ra); skip_ftrace: #ifdef CONFIG_FUNCTION_GRAPH_TRACER - ldi $4, ftrace_graph_return - ldl $4, 0($4) - ldi $5, ftrace_stub + ldl $4, ftrace_graph_return // if ((ftrace_graph_return + cmpeq $4, $5, $6 // != ftrace_stub) + beq $6, 2f + ldl $4, ftrace_graph_entry // || (ftrace_graph_entry + ldi $5, ftrace_graph_entry_stub // != ftrace_graph_entry_stub)) cmpeq $4, $5, $6 - beq $6, ftrace_graph_caller - - - ldi $4, ftrace_graph_entry - ldl $4, 0($4) - ldi $5, ftrace_graph_entry_stub - cmpeq $4, $5, $6 - beq $6, ftrace_graph_caller + bne $6, 3f +2: RESTORE_GRAPH_ARGS + call ftrace_graph_caller // ftrace_graph_caller(); #endif - mcount_end +3: mcount_end ret $31, ($28), 1 .end _mcount @@ -195,9 +287,8 @@ skip_ftrace: .ent ftrace_regs_caller ftrace_regs_caller: SAVE_PT_REGS - - br $27, 2f -2: ldgp $29, 0($27) + br $27, 1f +1: ldgp $29, 0($27) subl $28, MCOUNT_INSN_SIZE, $16 bis $26, $31, $17 @@ -205,6 +296,9 @@ ftrace_regs_caller: ldl $18, 0($4) mov $sp, $19 +#ifdef CONFIG_FUNCTION_GRAPH_TRACER + bis $31, $16, $9 +#endif ldi $4, current_tracer ldl $27, 0($4) @@ -212,6 +306,10 @@ ftrace_regs_caller: ftrace_regs_call: nop +#ifdef CONFIG_FUNCTION_GRAPH_TRACER + RESTORE_GRAPH_REG_ARGS + call ftrace_graph_caller +#endif RESTORE_PT_REGS ret $31, ($28), 1 .end ftrace_regs_caller @@ -222,67 +320,3 @@ ftrace_regs_call: ftrace_stub: ret $31, ($26), 1 .end ftrace_stub - - -#ifdef CONFIG_FUNCTION_GRAPH_TRACER - .macro RESTORE_GRAPH_ARGS - ldl $26, 0x18($sp) - ldl $28, 0x28($sp) - .endm - - /* save return value regs*/ - .macro save_return_regs - subl $sp, 0x8, $sp - stl $0, 0x0($sp) - .endm - - /* restore return value regs*/ - .macro restore_return_regs - ldl $0, 0x0($sp) - addl $sp, 0x8, $sp - .endm - - -/* - * void ftrace_graph_caller(void) - * - * Called from _mcount() or ftrace_caller() when function_graph tracer is - * selected. - * This function w/ prepare_ftrace_return() fakes link register's value on - * the call stack in order to intercept instrumented function's return path - * and run return_to_handler() later on its exit. - */ - .global ftrace_graph_caller - .ent ftrace_graph_caller -ftrace_graph_caller: - memb /* need memb, otherwise it'll go wrong */ - RESTORE_GRAPH_ARGS - addl $sp, 0x18, $16 - subl $28, MCOUNT_INSN_SIZE, $17 - bis $15, $31, $18 /* parent's fp */ - - call $26, ($27) /* prepare_ftrace_return() */ - - mcount_end - ret $31, ($28), 1 - .end ftrace_graph_caller - -/* - * void return_to_handler(void) - * - * Run ftrace_return_to_handler() before going back to parent. - * @fp is checked against the value passed by ftrace_graph_caller() - * only when HAVE_FUNCTION_GRAPH_FP_TEST is enabled. - */ -ENTRY(return_to_handler) - save_return_regs - br $27, 3f -3: ldgp $29, 0($27) - ldi $27, ftrace_return_to_handler - call $26, ($27) - bis $0, $31, $26 - restore_return_regs - ret $31, ($26), 1 -END(return_to_handler) - -#endif diff --git a/arch/sw_64/kernel/ftrace.c b/arch/sw_64/kernel/ftrace.c index 4bd89c709ad5..3d99f723dced 100644 --- a/arch/sw_64/kernel/ftrace.c +++ b/arch/sw_64/kernel/ftrace.c @@ -154,15 +154,11 @@ void prepare_ftrace_return(unsigned long *parent, unsigned long self_addr, static int ftrace_modify_graph_caller(bool enable) { unsigned long pc = (unsigned long)&ftrace_graph_call; - u32 branch, nop; - - branch = sw64_insn_br(R31, pc, (unsigned long)ftrace_graph_caller); - nop = sw64_insn_nop(); + u32 new = SW64_NOP; if (enable) - return ftrace_modify_code(pc, branch); - else - return ftrace_modify_code(pc, nop); + new = SW64_CALL(R26, R27, 0); + return ftrace_modify_code(pc, new); } int ftrace_enable_ftrace_graph_caller(void) -- Gitee From eee5d5872886372dd61c3f41f1040fa59b9432f1 Mon Sep 17 00:00:00 2001 From: He Sheng Date: Mon, 14 Nov 2022 11:30:16 +0800 Subject: [PATCH 21/27] sw64: fix argument type of __sw64_vcpu_run() Sunway inclusion category: feature bugzilla: https://gitee.com/openeuler/kernel/issues/I56OLG -------------------------------- The first argument of __sw64_vcpu_run() is physical address of guest vcb, and it's not `struct vcpucb *`. Signed-off-by: He Sheng Reviewed-by: Cui Wei Signed-off-by: Gu Zitao --- arch/sw_64/kvm/entry.S | 9 +++++---- arch/sw_64/kvm/kvm-sw64.c | 5 +++-- 2 files changed, 8 insertions(+), 6 deletions(-) diff --git a/arch/sw_64/kvm/entry.S b/arch/sw_64/kvm/entry.S index 0c02b68ee7d0..a331709320ca 100644 --- a/arch/sw_64/kvm/entry.S +++ b/arch/sw_64/kvm/entry.S @@ -11,8 +11,12 @@ .set noat +/* + * r16: physical address of guest kvm_vcpu.arch.vcb + * r17: pointer to guest kvm_vcpu.arch.kvm_regs + * r18: pointer to hcall args + */ ENTRY(__sw64_vcpu_run) - /* save host fpregs */ ldl $1, TI_TASK($8) rfpcr $f0 @@ -27,9 +31,6 @@ ENTRY(__sw64_vcpu_run) vstd $f9, TASK_THREAD_F9($1) ldi sp, -VCPU_RET_SIZE(sp) - /* r16 = guest kvm_vcpu_arch.vcb struct pointer */ - /* r17 = guest kvm_vcpu_arch.kvm_regs struct pointer */ - /* r18 = hcall args */ /* save host pt_regs to current kernel stack */ ldi sp, -PT_REGS_SIZE(sp) stl $9, PT_REGS_R9(sp) diff --git a/arch/sw_64/kvm/kvm-sw64.c b/arch/sw_64/kvm/kvm-sw64.c index c5a16d1c350b..6d34bc843167 100644 --- a/arch/sw_64/kvm/kvm-sw64.c +++ b/arch/sw_64/kvm/kvm-sw64.c @@ -68,7 +68,8 @@ int kvm_set_msi(struct kvm_kernel_irq_routing_entry *e, struct kvm *kvm, int irq return vcpu_interrupt_line(vcpu, irq, true); } -extern int __sw64_vcpu_run(struct vcpucb *vcb, struct kvm_regs *regs, struct hcall_args *args); +extern int __sw64_vcpu_run(unsigned long vcb_pa, + struct kvm_regs *regs, struct hcall_args *args); #ifdef CONFIG_KVM_MEMHOTPLUG static u64 get_vpcr_memhp(u64 seg_base, u64 vpn) @@ -674,7 +675,7 @@ int kvm_arch_vcpu_ioctl_run(struct kvm_vcpu *vcpu) trace_kvm_sw64_entry(vcpu->vcpu_id, vcpu->arch.regs.pc); vcpu->mode = IN_GUEST_MODE; - ret = __sw64_vcpu_run((struct vcpucb *)__phys_addr((unsigned long)vcb), &(vcpu->arch.regs), &hargs); + ret = __sw64_vcpu_run(__pa(vcb), &(vcpu->arch.regs), &hargs); /* Back from guest */ vcpu->mode = OUTSIDE_GUEST_MODE; -- Gitee From a6cb5b28f2ffd958e9ed5c27a023334223dda4bf Mon Sep 17 00:00:00 2001 From: Cui Mingrui Date: Tue, 22 Nov 2022 16:46:42 +0800 Subject: [PATCH 22/27] sw64: add basic NVDIMM support Sunway inclusion category: feature bugzilla: https://gitee.com/openeuler/kernel/issues/I56OLG -------------------------------- This patch introduces basic NVDIMM support for sw64: - Select ARCH_HAS_PMEM_API, ARCH_HAS_UACCESS_FLUSHCACHE and ARCH_HAS_ZONE_DEVICE in Kconfig. - Take bit 22 of pte as _PAGE_DEVMAP to support DAX. - Add some necessary functions for memory copy and cache flush. Signed-off-by: Cui Mingrui Reviewed-by: He Sheng Signed-off-by: Gu Zitao --- arch/sw_64/Kconfig | 4 +++ arch/sw_64/include/asm/pgtable.h | 45 +++++++++++++++++++++++++++++ arch/sw_64/include/asm/string.h | 5 ++++ arch/sw_64/include/asm/uaccess.h | 15 ++++++++++ arch/sw_64/lib/Makefile | 2 ++ arch/sw_64/lib/uaccess_flushcache.c | 42 +++++++++++++++++++++++++++ 6 files changed, 113 insertions(+) create mode 100644 arch/sw_64/lib/uaccess_flushcache.c diff --git a/arch/sw_64/Kconfig b/arch/sw_64/Kconfig index 47dc877c03f3..47a191e27aab 100644 --- a/arch/sw_64/Kconfig +++ b/arch/sw_64/Kconfig @@ -6,8 +6,12 @@ config SW64 select ACPI_REDUCED_HARDWARE_ONLY select ARCH_HAS_ELF_RANDOMIZE select ARCH_HAS_PHYS_TO_DMA + select ARCH_HAS_PMEM_API + select ARCH_HAS_PTE_DEVMAP select ARCH_HAS_PTE_SPECIAL select ARCH_HAS_SG_CHAIN + select ARCH_HAS_UACCESS_FLUSHCACHE + select ARCH_HAS_ZONE_DEVICE select ARCH_HAVE_NMI_SAFE_CMPXCHG select ARCH_INLINE_READ_LOCK select ARCH_INLINE_READ_LOCK_BH diff --git a/arch/sw_64/include/asm/pgtable.h b/arch/sw_64/include/asm/pgtable.h index b451bc94e737..0c312f8c1bd7 100644 --- a/arch/sw_64/include/asm/pgtable.h +++ b/arch/sw_64/include/asm/pgtable.h @@ -13,6 +13,7 @@ * in (currently 8192). */ #include +#include #include #include /* For TASK_SIZE */ @@ -103,6 +104,7 @@ static inline void set_pmd_at(struct mm_struct *mm, unsigned long addr, #define _PAGE_BIT_FOW 2 /* bit of _PAGE_FOW */ #define _PAGE_SPLITTING 0x200000 /* For Transparent Huge Page */ #define _PAGE_BIT_SPLITTING 21 /* bit of _PAGE_SPLITTING */ +#define _PAGE_BIT_DEVMAP 22 /* bit of _PAGE_DEVMAP */ /* * NOTE! The "accessed" bit isn't necessarily exact: it can be kept exactly @@ -234,6 +236,7 @@ static inline unsigned long pmd_page_vaddr(pmd_t pmd) */ #define page_to_pa(page) (page_to_pfn(page) << PAGE_SHIFT) +#define pud_pfn(pud) (pud_val(pud) >> _PFN_SHIFT) #define pmd_pfn(pmd) (pmd_val(pmd) >> _PFN_SHIFT) #define pte_pfn(pte) (pte_val(pte) >> _PFN_SHIFT) @@ -487,6 +490,12 @@ static inline pte_t pte_mkspecial(pte_t pte) return pte; } +static inline pte_t pte_mkdevmap(pte_t pte) +{ + pte_val(pte) |= _PAGE_SPECIAL; + return pte; +} + #ifdef CONFIG_NUMA_BALANCING /* * See the comment in include/asm-generic/pgtable.h @@ -524,8 +533,44 @@ static inline int has_transparent_hugepage(void) { return 1; } + +#ifdef CONFIG_ARCH_HAS_PTE_DEVMAP +#define _PAGE_DEVMAP (_AT(u64, 1) << _PAGE_BIT_DEVMAP) +static inline int pte_devmap(pte_t a) +{ + return (pte_val(a) & _PAGE_DEVMAP) == _PAGE_DEVMAP; +} + +static inline int pmd_devmap(pmd_t pmd) +{ + return !!(pmd_val(pmd) & _PAGE_DEVMAP); +} + +#ifdef CONFIG_HAVE_ARCH_TRANSPARENT_HUGEPAGE_PUD +static inline int pud_devmap(pud_t pud) +{ + return !!(pud_val(pud) & _PAGE_DEVMAP); +} +#else +static inline int pud_devmap(pud_t pud) +{ + return 0; +} +#endif + +static inline int pgd_devmap(pgd_t pgd) +{ + return 0; +} +#endif #endif /* CONFIG_TRANSPARENT_HUGEPAGE */ +static inline pmd_t pmd_mkdevmap(pmd_t pmd) +{ + pmd_val(pmd) |= _PAGE_DEVMAP; + return pmd; +} + #define __HAVE_ARCH_PMDP_GET_AND_CLEAR static inline pmd_t pmdp_get_and_clear(struct mm_struct *mm, unsigned long addr, pmd_t *pmdp) diff --git a/arch/sw_64/include/asm/string.h b/arch/sw_64/include/asm/string.h index 4f4a4687d8d0..c7bda9aed4e8 100644 --- a/arch/sw_64/include/asm/string.h +++ b/arch/sw_64/include/asm/string.h @@ -45,6 +45,11 @@ extern void *__memsetw(void *dest, unsigned short c, size_t count); ? __constant_c_memset((s), 0x0001000100010001UL * (unsigned short)(c), (n)) \ : __memsetw((s), (c), (n))) +#ifdef CONFIG_ARCH_HAS_UACCESS_FLUSHCACHE +#define __HAVE_ARCH_MEMCPY_FLUSHCACHE +void memcpy_flushcache(void *dst, const void *src, size_t cnt); +#endif + #endif /* __KERNEL__ */ #endif /* _ASM_SW64_STRING_H */ diff --git a/arch/sw_64/include/asm/uaccess.h b/arch/sw_64/include/asm/uaccess.h index 730121aad184..49d0b4c11c74 100644 --- a/arch/sw_64/include/asm/uaccess.h +++ b/arch/sw_64/include/asm/uaccess.h @@ -311,5 +311,20 @@ extern long strncpy_from_user(char *dest, const char __user *src, long count); extern __must_check long strlen_user(const char __user *str); extern __must_check long strnlen_user(const char __user *str, long n); +#ifdef CONFIG_ARCH_HAS_UACCESS_FLUSHCACHE +struct page; +void memcpy_page_flushcache(char *to, struct page *page, size_t offset, + size_t len); +extern unsigned long __must_check __copy_user_flushcache(void *to, + const void __user *from, unsigned long n); + +static inline int +__copy_from_user_flushcache(void *dst, const void __user *src, unsigned size) +{ + kasan_check_write(dst, size); + return __copy_user_flushcache(dst, src, size); +} +#endif + #include #endif /* _ASM_SW64_UACCESS_H */ diff --git a/arch/sw_64/lib/Makefile b/arch/sw_64/lib/Makefile index e4727dce3655..e6455bb51139 100644 --- a/arch/sw_64/lib/Makefile +++ b/arch/sw_64/lib/Makefile @@ -35,6 +35,8 @@ lib-memcpy-$(CONFIG_DEEP_MEMCPY) := deep-memcpy.o lib-memset-y := memset.o lib-memset-$(CONFIG_DEEP_MEMSET) := deep-memset.o +lib-$(CONFIG_ARCH_HAS_UACCESS_FLUSHCACHE) += uaccess_flushcache.o + lib-y += $(lib-clear_page-y) $(lib-clear_user-y) $(lib-copy_page-y) $(lib-copy_user-y) $(lib-memcpy-y) $(lib-memset-y) obj-y = iomap.o diff --git a/arch/sw_64/lib/uaccess_flushcache.c b/arch/sw_64/lib/uaccess_flushcache.c new file mode 100644 index 000000000000..353d5ac15248 --- /dev/null +++ b/arch/sw_64/lib/uaccess_flushcache.c @@ -0,0 +1,42 @@ +// SPDX-License-Identifier: GPL-2.0 + +#include +#include +#include +#include + +void memcpy_flushcache(void *dst, const void *src, size_t cnt) +{ + memcpy(dst, src, cnt); + flush_cache_all(); +} +EXPORT_SYMBOL_GPL(memcpy_flushcache); + +void memcpy_page_flushcache(char *to, struct page *page, size_t offset, + size_t len) +{ + memcpy_flushcache(to, page_address(page) + offset, len); +} + +unsigned long __copy_user_flushcache(void *to, const void __user *from, + unsigned long n) +{ + unsigned long rc = __copy_from_user(to, from, n); + + flush_cache_all(); + return rc; +} + +#ifdef CONFIG_ARCH_HAS_PMEM_API +void arch_wb_cache_pmem(void *addr, size_t size) +{ + flush_cache_all(); +} +EXPORT_SYMBOL_GPL(arch_wb_cache_pmem); + +void arch_invalidate_pmem(void *addr, size_t size) +{ + flush_cache_all(); +} +EXPORT_SYMBOL_GPL(arch_invalidate_pmem); +#endif -- Gitee From b20b8f9b728797b27b0531b49755a0985a0a33fc Mon Sep 17 00:00:00 2001 From: Lu Feifei Date: Tue, 22 Nov 2022 17:40:39 +0800 Subject: [PATCH 23/27] sw64: kvm: support debugging guest kernel via gdb Sunway inclusion category: feature bugzilla: https://gitee.com/openeuler/kernel/issues/I56WV8 -------------------------------- To support qemu-gdb, this patch adds a new exit type EXIT_DEBUG to handle exits for breakpoint debugging. Signed-off-by: Lu Feifei Reviewed-by: He Sheng Signed-off-by: Gu Zitao --- arch/sw_64/include/asm/kvm_asm.h | 4 +++- arch/sw_64/kvm/handle_exit.c | 4 ++++ arch/sw_64/kvm/kvm-sw64.c | 5 +++-- 3 files changed, 10 insertions(+), 3 deletions(-) diff --git a/arch/sw_64/include/asm/kvm_asm.h b/arch/sw_64/include/asm/kvm_asm.h index 841bfa1dd0aa..30d3ccbabff0 100644 --- a/arch/sw_64/include/asm/kvm_asm.h +++ b/arch/sw_64/include/asm/kvm_asm.h @@ -12,6 +12,7 @@ #define SW64_KVM_EXIT_IPI 14 #define SW64_KVM_EXIT_RESTART 17 #define SW64_KVM_EXIT_FATAL_ERROR 22 +#define SW64_KVM_EXIT_DEBUG 24 #ifdef CONFIG_KVM_MEMHOTPLUG #define SW64_KVM_EXIT_MEMHOTPLUG 23 @@ -26,6 +27,7 @@ {14, "IPI" }, \ {17, "RESTART" }, \ {22, "FATAL_ERROR" }, \ - {23, "MEMHOTPLUG" } + {23, "MEMHOTPLUG" }, \ + {24, "DEBUG" } #endif /* _ASM_SW64_KVM_ASM_H */ diff --git a/arch/sw_64/kvm/handle_exit.c b/arch/sw_64/kvm/handle_exit.c index 52f40a4c5803..8304ebfcd5c6 100644 --- a/arch/sw_64/kvm/handle_exit.c +++ b/arch/sw_64/kvm/handle_exit.c @@ -43,6 +43,10 @@ int handle_exit(struct kvm_vcpu *vcpu, struct kvm_run *run, case SW64_KVM_EXIT_IPI: vcpu_send_ipi(vcpu, hargs->arg0); return 1; + case SW64_KVM_EXIT_DEBUG: + vcpu->run->exit_reason = KVM_EXIT_DEBUG; + vcpu->run->debug.arch.epc = vcpu->arch.regs.pc; + return 0; #ifdef CONFIG_KVM_MEMHOTPLUG case SW64_KVM_EXIT_MEMHOTPLUG: vcpu_mem_hotplug(vcpu, hargs->arg0); diff --git a/arch/sw_64/kvm/kvm-sw64.c b/arch/sw_64/kvm/kvm-sw64.c index 6d34bc843167..0f0fa9b586cc 100644 --- a/arch/sw_64/kvm/kvm-sw64.c +++ b/arch/sw_64/kvm/kvm-sw64.c @@ -562,9 +562,10 @@ int kvm_arch_vcpu_ioctl_get_regs(struct kvm_vcpu *vcpu, struct kvm_regs *regs) return 0; } -int kvm_arch_vcpu_ioctl_set_guest_debug(struct kvm_vcpu *vcpu, struct kvm_guest_debug *dbg) +int kvm_arch_vcpu_ioctl_set_guest_debug(struct kvm_vcpu *vcpu, + struct kvm_guest_debug *dbg) { - return -ENOIOCTLCMD; + return 0; } void _debug_printk_vcpu(struct kvm_vcpu *vcpu) -- Gitee From 0f56df14a9df1f5d0b4ef2303ae643df8be0407f Mon Sep 17 00:00:00 2001 From: He Chuyue Date: Tue, 22 Nov 2022 13:45:42 +0800 Subject: [PATCH 24/27] sw64: fix VM_DATA_DEFAULT_FLAGS Sunway inclusion category: feature bugzilla: https://gitee.com/openeuler/kernel/issues/I645T3 -------------------------------- SW64 is designed to be have non-executable data by default. However, VM_EXEC was set in VM_DATA_DEFAULT_FLAGS, which makes stack executable and increases security risk. In particular, it causes some tests to fail. Redefine VM_DATA_DEFAULT_FLAGS with VM_DATA_FLAGS_NON_EXEC to fix this problem. Signed-off-by: He Chuyue Reviewed-by: He Sheng Signed-off-by: Gu Zitao --- arch/sw_64/include/asm/page.h | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/arch/sw_64/include/asm/page.h b/arch/sw_64/include/asm/page.h index dc6a89c37231..1ba34f4f5077 100644 --- a/arch/sw_64/include/asm/page.h +++ b/arch/sw_64/include/asm/page.h @@ -57,8 +57,7 @@ extern unsigned long __phys_addr(unsigned long); #define pfn_valid(pfn) ((pfn) < max_mapnr) #endif /* CONFIG_FLATMEM */ -#define VM_DATA_DEFAULT_FLAGS (VM_READ | VM_WRITE | VM_EXEC | \ - VM_MAYREAD | VM_MAYWRITE | VM_MAYEXEC) +#define VM_DATA_DEFAULT_FLAGS VM_DATA_FLAGS_NON_EXEC #include #include #endif -- Gitee From b1554ee3026fdec535169ab7a3c83dc713038865 Mon Sep 17 00:00:00 2001 From: Mao Minkai Date: Wed, 23 Nov 2022 15:30:00 +0800 Subject: [PATCH 25/27] sw64: optimize single float load store instruction emulation Sunway inclusion category: feature bugzilla: https://gitee.com/openeuler/kernel/issues/I56OLG -------------------------------- Use instructions instead of manual calculation to move data between integer register and floating point register to improve performance. Signed-off-by: Mao Minkai Reviewed-by: He Sheng Signed-off-by: Gu Zitao --- arch/sw_64/kernel/traps.c | 42 ++------------------------------------- 1 file changed, 2 insertions(+), 40 deletions(-) diff --git a/arch/sw_64/kernel/traps.c b/arch/sw_64/kernel/traps.c index b26a0e369ed9..5d13eeb71d60 100644 --- a/arch/sw_64/kernel/traps.c +++ b/arch/sw_64/kernel/traps.c @@ -506,44 +506,6 @@ do_entUna(void *va, unsigned long opcode, unsigned long reg, die("Unhandled unaligned exception", regs, error); } -/* - * Convert an s-floating point value in memory format to the - * corresponding value in register format. The exponent - * needs to be remapped to preserve non-finite values - * (infinities, not-a-numbers, denormals). - */ -static inline unsigned long -s_mem_to_reg(unsigned long s_mem) -{ - unsigned long frac = (s_mem >> 0) & 0x7fffff; - unsigned long sign = (s_mem >> 31) & 0x1; - unsigned long exp_msb = (s_mem >> 30) & 0x1; - unsigned long exp_low = (s_mem >> 23) & 0x7f; - unsigned long exp; - - exp = (exp_msb << 10) | exp_low; /* common case */ - if (exp_msb) { - if (exp_low == 0x7f) - exp = 0x7ff; - } else { - if (exp_low == 0x00) - exp = 0x000; - else - exp |= (0x7 << 7); - } - return (sign << 63) | (exp << 52) | (frac << 29); -} - -/* - * Convert an s-floating point value in register format to the - * corresponding value in memory format. - */ -static inline unsigned long -s_reg_to_mem(unsigned long s_reg) -{ - return ((s_reg >> 62) << 30) | ((s_reg << 5) >> 34); -} - /* * Handle user-level unaligned fault. Handling user-level unaligned * faults is *extremely* slow and produces nasty messages. A user @@ -1271,7 +1233,7 @@ do_entUnaUser(void __user *va, unsigned long opcode, : "r"(va), "0"(0)); if (error) goto give_sigsegv; - sw64_write_fp_reg(reg, s_mem_to_reg((int)(tmp1 | tmp2))); + sw64_write_fp_reg_s(reg, tmp1 | tmp2); return; case 0x27: /* fldd */ @@ -1360,7 +1322,7 @@ do_entUnaUser(void __user *va, unsigned long opcode, return; case 0x2e: /* fsts*/ - fake_reg = s_reg_to_mem(sw64_read_fp_reg(reg)); + fake_reg = sw64_read_fp_reg_s(reg); /* FALLTHRU */ case 0x2a: /* stw with stb*/ -- Gitee From 0bf6e0a20279d827ff772af60ae6c79a43effe1d Mon Sep 17 00:00:00 2001 From: Gu Zitao Date: Wed, 16 Nov 2022 09:03:48 +0800 Subject: [PATCH 26/27] sw64: add support for KPROBES_ON_FTRACE Sunway inclusion category: feature bugzilla: https://gitee.com/openeuler/kernel/issues/I645TO -------------------------------- This patch adds support for KPROBES_ON_FTRACE on SW64, and it allows kprobes to be placed on ftrace _mcount() call sites. However, kprobe_ftrace_handler() makes ftrace_regs_caller() return to the instruction after _mcount() call site. Then if the function accesses global symbol with an address caculated based on gp($29), it'll access a wrong address because gp has been changed in ftrace_regs_caller(). To fix it, gp has to be saved and restored in ftrace_regs_caller(). With this patch, ftrace/kprobe selftests return passed. Signed-off-by: Gu Zitao Reviewed-by: He Sheng Signed-off-by: Gu Zitao --- arch/sw_64/Kconfig | 1 + arch/sw_64/include/asm/kprobes.h | 5 +++ arch/sw_64/kernel/entry-ftrace.S | 2 + arch/sw_64/kernel/kprobes/Makefile | 2 +- arch/sw_64/kernel/kprobes/kprobes-ftrace.c | 48 ++++++++++++++++++++++ 5 files changed, 57 insertions(+), 1 deletion(-) create mode 100644 arch/sw_64/kernel/kprobes/kprobes-ftrace.c diff --git a/arch/sw_64/Kconfig b/arch/sw_64/Kconfig index 47a191e27aab..832e7a7a02e0 100644 --- a/arch/sw_64/Kconfig +++ b/arch/sw_64/Kconfig @@ -82,6 +82,7 @@ config SW64 select HAVE_FUNCTION_TRACER select HAVE_IDE select HAVE_KPROBES + select HAVE_KPROBES_ON_FTRACE select HAVE_KRETPROBES select HAVE_LIVEPATCH if HAVE_DYNAMIC_FTRACE_WITH_REGS select HAVE_MEMBLOCK diff --git a/arch/sw_64/include/asm/kprobes.h b/arch/sw_64/include/asm/kprobes.h index 6b7e4548a8bd..0c7be8109ed2 100644 --- a/arch/sw_64/include/asm/kprobes.h +++ b/arch/sw_64/include/asm/kprobes.h @@ -45,6 +45,11 @@ void arch_remove_kprobe(struct kprobe *p); struct arch_specific_insn { /* copy of the original instruction */ kprobe_opcode_t *insn; + /* + * Set in kprobes code, initially to 0. If the instruction can be + * eumulated, this is set to 1, if not, to -1. + */ + int boostable; }; struct prev_kprobe { diff --git a/arch/sw_64/kernel/entry-ftrace.S b/arch/sw_64/kernel/entry-ftrace.S index 26bcc71b9db1..53125495f4e5 100644 --- a/arch/sw_64/kernel/entry-ftrace.S +++ b/arch/sw_64/kernel/entry-ftrace.S @@ -89,6 +89,7 @@ stl $26, PT_REGS_R26($sp) stl $27, PT_REGS_R27($sp) stl $28, PT_REGS_R28($sp) + stl $29, PT_REGS_GP($sp) .endm .macro RESTORE_PT_REGS @@ -121,6 +122,7 @@ ldl $26, PT_REGS_R26($sp) ldl $27, PT_REGS_R27($sp) ldl $28, PT_REGS_R28($sp) + ldl $29, PT_REGS_GP($sp) ldi $sp, PT_REGS_SIZE($sp) .endm diff --git a/arch/sw_64/kernel/kprobes/Makefile b/arch/sw_64/kernel/kprobes/Makefile index b3b1d849a63a..110ba2bf7752 100644 --- a/arch/sw_64/kernel/kprobes/Makefile +++ b/arch/sw_64/kernel/kprobes/Makefile @@ -1,3 +1,3 @@ # SPDX-License-Identifier: GPL-2.0 obj-$(CONFIG_KPROBES) += kprobes.o decode-insn.o -obj-$(CONFIG_KPROBES_ON_FTRACE) += ftrace.o +obj-$(CONFIG_KPROBES_ON_FTRACE) += kprobes-ftrace.o diff --git a/arch/sw_64/kernel/kprobes/kprobes-ftrace.c b/arch/sw_64/kernel/kprobes/kprobes-ftrace.c new file mode 100644 index 000000000000..69fd38135cad --- /dev/null +++ b/arch/sw_64/kernel/kprobes/kprobes-ftrace.c @@ -0,0 +1,48 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Dynamic Ftrace based Kprobes Optimization + */ + +#include +#include +#include +#include +#include + +/* Ftrace callback handler for kprobes */ +void kprobe_ftrace_handler(unsigned long ip, unsigned long parent_ip, + struct ftrace_ops *ops, struct pt_regs *regs) +{ + struct kprobe *p; + struct kprobe_ctlblk *kcb; + + p = get_kprobe((kprobe_opcode_t *)ip); + if (unlikely(!p) || kprobe_disabled(p)) + return; + + kcb = get_kprobe_ctlblk(); + if (kprobe_running()) { + kprobes_inc_nmissed_count(p); + } else { + regs->r28 -= MCOUNT_INSN_SIZE; + + __this_cpu_write(current_kprobe, p); + kcb->kprobe_status = KPROBE_HIT_ACTIVE; + if (!p->pre_handler || !p->pre_handler(p, regs)) { + regs->r28 += MCOUNT_INSN_SIZE; + if (unlikely(p->post_handler)) { + kcb->kprobe_status = KPROBE_HIT_SSDONE; + p->post_handler(p, regs, 0); + } + } + __this_cpu_write(current_kprobe, NULL); + } +} +NOKPROBE_SYMBOL(kprobe_ftrace_handler); + +int arch_prepare_kprobe_ftrace(struct kprobe *p) +{ + p->ainsn.insn = NULL; + p->ainsn.boostable = -1; + return 0; +} -- Gitee From 989461bc91fca3bdf169d779c5b3bc7cb379f9a8 Mon Sep 17 00:00:00 2001 From: Gu Zitao Date: Wed, 16 Nov 2022 09:16:10 +0800 Subject: [PATCH 27/27] sw64: fix kernel_stack_pointer Sunway inclusion category: bugfix bugzilla: https://gitee.com/openeuler/kernel/issues/I645TO -------------------------------- Signed-off-by: Gu Zitao Reviewed-by: He Sheng Signed-off-by: Gu Zitao --- arch/sw_64/include/asm/ptrace.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/sw_64/include/asm/ptrace.h b/arch/sw_64/include/asm/ptrace.h index efc93e731b2a..4db8b61fc093 100644 --- a/arch/sw_64/include/asm/ptrace.h +++ b/arch/sw_64/include/asm/ptrace.h @@ -55,7 +55,7 @@ struct pt_regs { #define profile_pc(regs) instruction_pointer(regs) #define current_user_stack_pointer() rdusp() #define user_stack_pointer(regs) rdusp() -#define kernel_stack_pointer(regs) (((regs->ps) >> 4) & (TASK_SIZE - 1)) +#define kernel_stack_pointer(regs) ((unsigned long)((regs) + 1)) #define instruction_pointer_set(regs, val) ((regs)->pc = val) -- Gitee