diff --git a/arch/sw_64/Kconfig b/arch/sw_64/Kconfig index b37a4f4e093e7675366ee85964c8656cfce294b8..832e7a7a02e0bd4180e581bb25602c85b0e58cd8 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 @@ -70,6 +74,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 @@ -77,7 +82,9 @@ 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 select HAVE_MEMBLOCK_NODE_MAP select HAVE_MOD_ARCH_SPECIFIC @@ -88,6 +95,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 +659,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/boot/dts/chip_vt.dts b/arch/sw_64/boot/dts/chip_vt.dts index abad29dee97e16c4dd062a524908bab604a3351c..f26285367f98c6715f3ff88eacb12496d12e7644 100644 --- a/arch/sw_64/boot/dts/chip_vt.dts +++ b/arch/sw_64/boot/dts/chip_vt.dts @@ -46,5 +46,10 @@ clock-frequency = <24000000>; status = "okay"; }; + fw_cfg: fw_cfg@8049 { + dma-coherent; + reg = <0x8049 0x20000000 0x0 0x18>; + compatible = "qemu,fw-cfg-mmio"; + }; }; }; diff --git a/arch/sw_64/include/asm/ftrace.h b/arch/sw_64/include/asm/ftrace.h index ea82224e582638484dcb6d959eaee448f4e1d55a..d211b8ce1d1832b479e298dcc3f7d448fc287fde 100644 --- a/arch/sw_64/include/asm/ftrace.h +++ b/arch/sw_64/include/asm/ftrace.h @@ -10,13 +10,16 @@ */ #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 */ + +#define ARCH_SUPPORTS_FTRACE_OPS 1 #ifndef __ASSEMBLY__ #include +#include extern void _mcount(unsigned long); diff --git a/arch/sw_64/include/asm/hw_init.h b/arch/sw_64/include/asm/hw_init.h index 1fd7ed18c3f07e5177042eaaaa2a46ddfb97d9bf..1426892c83b4bf189bbf610a9a86e574953ff451 100644 --- a/arch/sw_64/include/asm/hw_init.h +++ b/arch/sw_64/include/asm/hw_init.h @@ -19,12 +19,13 @@ 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 */ 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; diff --git a/arch/sw_64/include/asm/insn.h b/arch/sw_64/include/asm/insn.h index ec0efae3aed0320fafa9175c6155318309acc649..437cb48d1e9306bc46f206b10a1b0fb176a8e65a 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/include/asm/kprobes.h b/arch/sw_64/include/asm/kprobes.h index 6b7e4548a8bd365f17d73bcd468e25e872b56c0e..0c7be8109ed29423cadec91e4f0ffc9d65e7ab0b 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/include/asm/kvm_asm.h b/arch/sw_64/include/asm/kvm_asm.h index 841bfa1dd0aad0c4ac99365b856e9b5f5eda0440..30d3ccbabff05f48338e3b5035288f9ac3ddfcb6 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/include/asm/livepatch.h b/arch/sw_64/include/asm/livepatch.h new file mode 100644 index 0000000000000000000000000000000000000000..f93c2131113bfc13547c25f1c5ff9c61e5e1e607 --- /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/page.h b/arch/sw_64/include/asm/page.h index dc6a89c37231232058ea7c60359108f162f2952c..1ba34f4f507787773f77c0e88fe2166abd87d24c 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 diff --git a/arch/sw_64/include/asm/pgtable.h b/arch/sw_64/include/asm/pgtable.h index b451bc94e7377b7cca2770abb2f3d840cf230a37..0c312f8c1bd79314e1754404c041e50ca9d8e2a3 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/ptrace.h b/arch/sw_64/include/asm/ptrace.h index 5f6cd305f95e6c3fa1c2801e52903eb4a438d470..4db8b61fc09394a487db69a677bd5a552f7d64fb 100644 --- a/arch/sw_64/include/asm/ptrace.h +++ b/arch/sw_64/include/asm/ptrace.h @@ -49,12 +49,13 @@ 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) #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) diff --git a/arch/sw_64/include/asm/string.h b/arch/sw_64/include/asm/string.h index 4f4a4687d8d0a3f1c16d98ee76e711a2aa533ae9..c7bda9aed4e8da60230928889f8a67e58c6eaece 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/thread_info.h b/arch/sw_64/include/asm/thread_info.h index 31740003d0b2d31204dc6ea36a14a7b9c8284595..c9637d32e1bec199f259b858dd7463e3bd83287e 100644 --- a/arch/sw_64/include/asm/thread_info.h +++ b/arch/sw_64/include/asm/thread_info.h @@ -34,8 +34,14 @@ 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; +#ifdef CONFIG_DYNAMIC_FTRACE_WITH_REGS + unsigned long dyn_ftrace_regs_addr; +#endif #endif }; @@ -81,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/include/asm/topology.h b/arch/sw_64/include/asm/topology.h index f8242d00290b8cecef3a59582b69b09756b74cc8..c39ca5b4beb78f1dc65628695e3a0432547a77b3 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/include/asm/uaccess.h b/arch/sw_64/include/asm/uaccess.h index 730121aad1840459b94d01737bfb50848c878246..49d0b4c11c74698ba4e171b3e4b3ab2f3ae23a79 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/kernel/entry-ftrace.S b/arch/sw_64/kernel/entry-ftrace.S index 223dd5fc0808bdef3c26cb90547ffe5c2b6eb38e..53125495f4e54d94870ce6002590bda1c1401afa 100644 --- a/arch/sw_64/kernel/entry-ftrace.S +++ b/arch/sw_64/kernel/entry-ftrace.S @@ -10,6 +10,8 @@ * */ #include +#include +#include .text .set noat @@ -22,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) @@ -35,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) @@ -44,6 +50,160 @@ 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) + 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) + stl $29, PT_REGS_GP($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) + ldl $29, PT_REGS_GP($sp) + 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 @@ -56,27 +216,31 @@ _mcount: .ent ftrace_caller ftrace_caller: mcount_enter + br $27, 1f +1: ldgp $29, 0($27) - 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 + 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 @@ -87,109 +251,74 @@ 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 - bis $28, $31, $16 - subl $16, 8, $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 #endif /* CONFIG_DYNAMIC_FTRACE */ - .global ftrace_stub - .ent ftrace_stub -ftrace_stub: - ret $31, ($26), 1 - .end ftrace_stub +#ifdef CONFIG_DYNAMIC_FTRACE_WITH_REGS + .global ftrace_regs_caller + .ent ftrace_regs_caller +ftrace_regs_caller: + SAVE_PT_REGS + br $27, 1f +1: 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 #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 - bis $28, $31, $17 - subl $17, 8, $17 - bis $15, $31, $18 /* parent's fp */ + bis $31, $16, $9 +#endif + ldi $4, current_tracer + ldl $27, 0($4) - call $26, ($27) /* prepare_ftrace_return() */ + .global ftrace_regs_call +ftrace_regs_call: + nop - mcount_end - ret $31, ($28), 1 - .end ftrace_graph_caller +#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 +#endif /* CONFIG_DYNAMIC_FTRACE_WITH_REGS */ -/* - * 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 + .global ftrace_stub + .ent ftrace_stub +ftrace_stub: ret $31, ($26), 1 -END(return_to_handler) - -#endif + .end ftrace_stub diff --git a/arch/sw_64/kernel/ftrace.c b/arch/sw_64/kernel/ftrace.c index 42efca28d3864c84e625e38c803b88499673c3d4..3d99f723dced5c5455039330f64cb7c4ebdf627f 100644 --- a/arch/sw_64/kernel/ftrace.c +++ b/arch/sw_64/kernel/ftrace.c @@ -19,17 +19,11 @@ 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)) +#define TI_FTRACE_REGS_ADDR \ + (offsetof(struct thread_info, dyn_ftrace_regs_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 +41,21 @@ 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; + int ret; current_tracer = (unsigned long)func; - pc = (unsigned long)&ftrace_call; + new = SW64_CALL(R26, R27, 0); + ret = ftrace_modify_code(pc, new); - new = sw64_insn_call(R26, R27); - if (ftrace_modify_code(pc, new)) - return ret; - return 0; + if (!ret) { + pc = (unsigned long)&ftrace_regs_call; + new = SW64_CALL(R26, R27, 0); + ret = ftrace_modify_code(pc, new); + } + + return ret; } /* @@ -65,19 +63,22 @@ 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; + 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) */ - 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) | offset; + 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); } /* @@ -86,15 +87,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) @@ -102,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 @@ -147,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) diff --git a/arch/sw_64/kernel/insn.c b/arch/sw_64/kernel/insn.c index e8dd41b6b7c420a056c181bcc4e6a6ff8385cbaf..281578e1bfc03b708be124e0e3d28644d811b512 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) diff --git a/arch/sw_64/kernel/kprobes/Makefile b/arch/sw_64/kernel/kprobes/Makefile index b3b1d849a63a9004fb12e4cbeac98fee10c195ef..110ba2bf7752361442022553269447ceb802d465 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 0000000000000000000000000000000000000000..69fd38135cad990d4ef1f579b30194cbb3d8c2ba --- /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; +} diff --git a/arch/sw_64/kernel/proto.h b/arch/sw_64/kernel/proto.h index f908263f925a76c6acee373cf213ccb541bf029b..7b2564f47a9df4612d4cf53174b9cf8f01afca81 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 e98679d10fae16adee87ae65b08a241f55d986a6..2ca8d5804537242fb8a50aad3c391a9146cdd3d4 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, @@ -435,9 +542,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); diff --git a/arch/sw_64/kernel/setup.c b/arch/sw_64/kernel/setup.c index d4c97741616f5018d238a67c55232c437f435738..5ec55554caf63908fdf4df3000f764fb475f8864 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: diff --git a/arch/sw_64/kernel/signal.c b/arch/sw_64/kernel/signal.c index b80cf0e56224485e41e27ffe7ef49c093f559f76..3a5757b234c6d08bcaae7fb41cc6b114014a608f 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 diff --git a/arch/sw_64/kernel/smp.c b/arch/sw_64/kernel/smp.c index ecf276e9e364af3cd44fb496cfab4d0163c8d9c5..79dc334c3375504e370107138d0cb91faf8c960f 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) diff --git a/arch/sw_64/kernel/stacktrace.c b/arch/sw_64/kernel/stacktrace.c index 7b5ddc78bd6d21efd36e70a58f7711ea1ade8e7d..71c0e5b7b3e00bfccc184430a0845f043e23ca6f 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; @@ -212,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 diff --git a/arch/sw_64/kernel/time.c b/arch/sw_64/kernel/time.c index 32690e78849b8fb54afa7ad22f7f3c59bd9a87f4..8be7a11df51d8c4f61a36d9d3c95114aab14148f 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; diff --git a/arch/sw_64/kernel/topology.c b/arch/sw_64/kernel/topology.c index 964d6a83d901e10b7f2e35f0276c6a27c856a05f..6bad8e13b8c9f1fddedb5c80e1e28e0ab7f4d4db 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) diff --git a/arch/sw_64/kernel/traps.c b/arch/sw_64/kernel/traps.c index b26a0e369ed947cb5308cecf025102ff4bc0cb54..5d13eeb71d60dd9a43b54befb84cca1ceb6d38e1 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*/ diff --git a/arch/sw_64/kvm/entry.S b/arch/sw_64/kvm/entry.S index 0c02b68ee7d06a6e5d83d5c0c7c8db5afed6b862..a331709320ca042fa599c750966bff284d0d126b 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/handle_exit.c b/arch/sw_64/kvm/handle_exit.c index 52f40a4c5803bf5980308b18fbfb6459ab42bdec..8304ebfcd5c69ee3d08a3a28a45fa883ef40a607 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 ffcfdee58a4877f527b9ac2f41fa8fb348f71f6d..0f0fa9b586cccbfd00405338fe8f4fbf02b87e41 100644 --- a/arch/sw_64/kvm/kvm-sw64.c +++ b/arch/sw_64/kvm/kvm-sw64.c @@ -23,11 +23,12 @@ #include "vmem.c" bool set_msi_flag; -unsigned long sw64_kvm_last_vpn[NR_CPUS]; +static unsigned long longtime_offset; + #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 @@ -67,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) @@ -84,14 +86,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 +103,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) { @@ -560,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) @@ -615,7 +618,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 */ @@ -673,7 +676,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; @@ -727,10 +730,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; @@ -897,7 +903,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) { diff --git a/arch/sw_64/lib/Makefile b/arch/sw_64/lib/Makefile index e4727dce3655074f5d18e5aeb69f1d34afa37f14..e6455bb5113911fa7c2fb599449aad5ef1391fea 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 0000000000000000000000000000000000000000..353d5ac152481743a47776666ae6132626da5236 --- /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 diff --git a/arch/sw_64/net/bpf_jit_comp.c b/arch/sw_64/net/bpf_jit_comp.c index 2c238c33e5740dcf4241de568644f7826c2a182b..47e8055691544640d6e51c2c9cdc4a599d965753 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; diff --git a/drivers/firmware/Kconfig b/drivers/firmware/Kconfig index c08968c5ddf8c458c35fc1fc5c5c84412aad4bdb..a34d4bfb27fe449b63ab62bcba3e11cb1cd6323e 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 f08e056ed0ae4506db5f6336534b4095ea4cc388..80c416b78766accd6490a92a18e1e7d109213c47 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 diff --git a/drivers/hwmon/sw64_pvt.c b/drivers/hwmon/sw64_pvt.c index 9e292a90af38887bed826284ac64f6b06c1c7e8b..29098bc1f6450cd80cc00a9693c2eb04d5ce5f2a 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 8640c4aa9506c71c0c0f1209171e09e23218c145..070c12ede959baeb1e45feaa2c22676d30c2fbfc 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 diff --git a/scripts/recordmcount.c b/scripts/recordmcount.c index 84ea65aec015e46ee87057b57e26980141a6d007..f7cf4fd36898d38a224d4a5eae65d6b604597a5f 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;