mirror of
https://github.com/hardkernel/linux.git
synced 2026-03-24 19:40:21 +09:00
Merge tag 'lsk-v4.4-17.08-android' of git://git.linaro.org/kernel/linux-linaro-stable.git
LSK 17.08 v4.4-android * tag 'lsk-v4.4-17.08-android': (451 commits) Linux 4.4.83 pinctrl: samsung: Remove bogus irq_[un]mask from resource management pinctrl: sunxi: add a missing function of A10/A20 pinctrl driver pnfs/blocklayout: require 64-bit sector_t iio: adc: vf610_adc: Fix VALT selection value for REFSEL bits usb:xhci:Add quirk for Certain failing HP keyboard on reset after resume usb: quirks: Add no-lpm quirk for Moshi USB to Ethernet Adapter usb: core: unlink urbs from the tail of the endpoint's urb_list USB: Check for dropped connection before switching to full speed uag: Add US_FL_IGNORE_RESIDUE for Initio Corporation INIC-3069 iio: light: tsl2563: use correct event code iio: accel: bmc150: Always restore device to normal mode after suspend-resume staging:iio:resolver:ad2s1210 fix negative IIO_ANGL_VEL read USB: hcd: Mark secondary HCD as dead if the primary one died usb: musb: fix tx fifo flush handling again USB: serial: pl2303: add new ATEN device id USB: serial: cp210x: add support for Qivicon USB ZigBee dongle USB: serial: option: add D-Link DWM-222 device ID nfs/flexfiles: fix leak of nfs4_ff_ds_version arrays fuse: initialize the flock flag in fuse_file on allocation ...
This commit is contained in:
5
Makefile
5
Makefile
@@ -1,6 +1,6 @@
|
||||
VERSION = 4
|
||||
PATCHLEVEL = 4
|
||||
SUBLEVEL = 77
|
||||
SUBLEVEL = 83
|
||||
EXTRAVERSION =
|
||||
NAME = Blurry Fish Butt
|
||||
|
||||
@@ -636,6 +636,9 @@ include arch/$(SRCARCH)/Makefile
|
||||
KBUILD_CFLAGS += $(call cc-option,-fno-delete-null-pointer-checks,)
|
||||
KBUILD_CFLAGS += $(call cc-disable-warning,maybe-uninitialized,)
|
||||
KBUILD_CFLAGS += $(call cc-disable-warning,frame-address,)
|
||||
KBUILD_CFLAGS += $(call cc-disable-warning, format-truncation)
|
||||
KBUILD_CFLAGS += $(call cc-disable-warning, format-overflow)
|
||||
KBUILD_CFLAGS += $(call cc-disable-warning, int-in-bool-context)
|
||||
|
||||
ifdef CONFIG_CC_OPTIMIZE_FOR_SIZE
|
||||
KBUILD_CFLAGS += -Os
|
||||
|
||||
@@ -17,7 +17,6 @@ CONFIG_AUDIT=y
|
||||
CONFIG_BLK_DEV_INITRD=y
|
||||
CONFIG_CGROUPS=y
|
||||
CONFIG_CGROUP_CPUACCT=y
|
||||
CONFIG_CGROUP_DEBUG=y
|
||||
CONFIG_CGROUP_FREEZER=y
|
||||
CONFIG_CGROUP_SCHED=y
|
||||
CONFIG_DEFAULT_SECURITY_SELINUX=y
|
||||
@@ -140,11 +139,6 @@ CONFIG_PPP_DEFLATE=y
|
||||
CONFIG_PPP_MPPE=y
|
||||
CONFIG_PREEMPT=y
|
||||
CONFIG_PROFILING=y
|
||||
CONFIG_QFMT_V2=y
|
||||
CONFIG_QUOTA=y
|
||||
CONFIG_QUOTACTL=y
|
||||
CONFIG_QUOTA_NETLINK_INTERFACE=y
|
||||
CONFIG_QUOTA_TREE=y
|
||||
CONFIG_RANDOMIZE_BASE=y
|
||||
CONFIG_RTC_CLASS=y
|
||||
CONFIG_RT_GROUP_SCHED=y
|
||||
|
||||
@@ -109,6 +109,11 @@ CONFIG_POWER_SUPPLY=y
|
||||
CONFIG_PSTORE=y
|
||||
CONFIG_PSTORE_CONSOLE=y
|
||||
CONFIG_PSTORE_RAM=y
|
||||
CONFIG_QFMT_V2=y
|
||||
CONFIG_QUOTA=y
|
||||
CONFIG_QUOTACTL=y
|
||||
CONFIG_QUOTA_NETLINK_INTERFACE=y
|
||||
CONFIG_QUOTA_TREE=y
|
||||
CONFIG_SCHEDSTATS=y
|
||||
CONFIG_SMARTJOYPLUS_FF=y
|
||||
CONFIG_SND=y
|
||||
|
||||
@@ -225,8 +225,8 @@ config ARCH_INIT_TASK
|
||||
config ARCH_TASK_STRUCT_ALLOCATOR
|
||||
bool
|
||||
|
||||
# Select if arch has its private alloc_thread_info() function
|
||||
config ARCH_THREAD_INFO_ALLOCATOR
|
||||
# Select if arch has its private alloc_thread_stack() function
|
||||
config ARCH_THREAD_STACK_ALLOCATOR
|
||||
bool
|
||||
|
||||
# Select if arch wants to size task_struct dynamically via arch_task_struct_size:
|
||||
|
||||
@@ -160,7 +160,7 @@ apply_relocate_add(Elf64_Shdr *sechdrs, const char *strtab,
|
||||
|
||||
/* The small sections were sorted to the end of the segment.
|
||||
The following should definitely cover them. */
|
||||
gp = (u64)me->module_core + me->core_size - 0x8000;
|
||||
gp = (u64)me->core_layout.base + me->core_layout.size - 0x8000;
|
||||
got = sechdrs[me->arch.gotsecindex].sh_addr;
|
||||
|
||||
for (i = 0; i < n; i++) {
|
||||
|
||||
@@ -385,8 +385,8 @@ void *unwind_add_table(struct module *module, const void *table_start,
|
||||
return NULL;
|
||||
|
||||
init_unwind_table(table, module->name,
|
||||
module->module_core, module->core_size,
|
||||
module->module_init, module->init_size,
|
||||
module->core_layout.base, module->core_layout.size,
|
||||
module->init_layout.base, module->init_layout.size,
|
||||
table_start, table_size,
|
||||
NULL, 0);
|
||||
|
||||
|
||||
@@ -89,7 +89,7 @@
|
||||
pinctrl-names = "default";
|
||||
pinctrl-0 = <&pca0_pins>;
|
||||
interrupt-parent = <&gpio0>;
|
||||
interrupts = <18 IRQ_TYPE_EDGE_FALLING>;
|
||||
interrupts = <18 IRQ_TYPE_LEVEL_LOW>;
|
||||
gpio-controller;
|
||||
#gpio-cells = <2>;
|
||||
interrupt-controller;
|
||||
@@ -101,7 +101,7 @@
|
||||
compatible = "nxp,pca9555";
|
||||
pinctrl-names = "default";
|
||||
interrupt-parent = <&gpio0>;
|
||||
interrupts = <18 IRQ_TYPE_EDGE_FALLING>;
|
||||
interrupts = <18 IRQ_TYPE_LEVEL_LOW>;
|
||||
gpio-controller;
|
||||
#gpio-cells = <2>;
|
||||
interrupt-controller;
|
||||
|
||||
@@ -697,6 +697,8 @@
|
||||
vmmc_aux-supply = <&vsim>;
|
||||
bus-width = <8>;
|
||||
non-removable;
|
||||
no-sdio;
|
||||
no-sd;
|
||||
};
|
||||
|
||||
&mmc3 {
|
||||
|
||||
@@ -87,9 +87,9 @@ CONFIG_IPV6_TUNNEL=m
|
||||
CONFIG_NETFILTER=y
|
||||
CONFIG_NF_CONNTRACK=m
|
||||
CONFIG_NF_CONNTRACK_EVENTS=y
|
||||
CONFIG_NF_CT_PROTO_DCCP=m
|
||||
CONFIG_NF_CT_PROTO_SCTP=m
|
||||
CONFIG_NF_CT_PROTO_UDPLITE=m
|
||||
CONFIG_NF_CT_PROTO_DCCP=y
|
||||
CONFIG_NF_CT_PROTO_SCTP=y
|
||||
CONFIG_NF_CT_PROTO_UDPLITE=y
|
||||
CONFIG_NF_CONNTRACK_AMANDA=m
|
||||
CONFIG_NF_CONNTRACK_FTP=m
|
||||
CONFIG_NF_CONNTRACK_H323=m
|
||||
|
||||
@@ -112,12 +112,8 @@ int dump_task_regs(struct task_struct *t, elf_gregset_t *elfregs);
|
||||
#define CORE_DUMP_USE_REGSET
|
||||
#define ELF_EXEC_PAGESIZE 4096
|
||||
|
||||
/* This is the location that an ET_DYN program is loaded if exec'ed. Typical
|
||||
use of this is to invoke "./ld.so someprog" to test out a new version of
|
||||
the loader. We need to make sure that it is out of the way of the program
|
||||
that it will "exec", and that there is sufficient room for the brk. */
|
||||
|
||||
#define ELF_ET_DYN_BASE (TASK_SIZE / 3 * 2)
|
||||
/* This is the base location for PIE (ET_DYN with INTERP) loads. */
|
||||
#define ELF_ET_DYN_BASE 0x400000UL
|
||||
|
||||
/* When the program starts, a1 contains a pointer to a function to be
|
||||
registered with atexit, as per the SVR4 ABI. A value of 0 means we
|
||||
|
||||
@@ -54,6 +54,24 @@ static inline void *return_address(unsigned int level)
|
||||
|
||||
#define ftrace_return_address(n) return_address(n)
|
||||
|
||||
#define ARCH_HAS_SYSCALL_MATCH_SYM_NAME
|
||||
|
||||
static inline bool arch_syscall_match_sym_name(const char *sym,
|
||||
const char *name)
|
||||
{
|
||||
if (!strcmp(sym, "sys_mmap2"))
|
||||
sym = "sys_mmap_pgoff";
|
||||
else if (!strcmp(sym, "sys_statfs64_wrapper"))
|
||||
sym = "sys_statfs64";
|
||||
else if (!strcmp(sym, "sys_fstatfs64_wrapper"))
|
||||
sym = "sys_fstatfs64";
|
||||
else if (!strcmp(sym, "sys_arm_fadvise64_64"))
|
||||
sym = "sys_fadvise64_64";
|
||||
|
||||
/* Ignore case since sym may start with "SyS" instead of "sys" */
|
||||
return !strcasecmp(sym, name);
|
||||
}
|
||||
|
||||
#endif /* ifndef __ASSEMBLY__ */
|
||||
|
||||
#endif /* _ASM_ARM_FTRACE */
|
||||
|
||||
@@ -32,7 +32,7 @@ struct plt_entries {
|
||||
|
||||
static bool in_init(const struct module *mod, u32 addr)
|
||||
{
|
||||
return addr - (u32)mod->module_init < mod->init_size;
|
||||
return addr - (u32)mod->init_layout.base < mod->init_layout.size;
|
||||
}
|
||||
|
||||
u32 get_module_plt(struct module *mod, unsigned long loc, Elf32_Addr val)
|
||||
|
||||
@@ -1636,12 +1636,16 @@ static int kvm_test_age_hva_handler(struct kvm *kvm, gpa_t gpa, void *data)
|
||||
|
||||
int kvm_age_hva(struct kvm *kvm, unsigned long start, unsigned long end)
|
||||
{
|
||||
if (!kvm->arch.pgd)
|
||||
return 0;
|
||||
trace_kvm_age_hva(start, end);
|
||||
return handle_hva_to_gpa(kvm, start, end, kvm_age_hva_handler, NULL);
|
||||
}
|
||||
|
||||
int kvm_test_age_hva(struct kvm *kvm, unsigned long hva)
|
||||
{
|
||||
if (!kvm->arch.pgd)
|
||||
return 0;
|
||||
trace_kvm_test_age_hva(hva);
|
||||
return handle_hva_to_gpa(kvm, hva, hva, kvm_test_age_hva_handler, NULL);
|
||||
}
|
||||
|
||||
@@ -102,6 +102,7 @@ config ARM64
|
||||
select SYSCTL_EXCEPTION_TRACE
|
||||
select HAVE_CONTEXT_TRACKING
|
||||
select HAVE_ARM_SMCCC
|
||||
select THREAD_INFO_IN_TASK
|
||||
help
|
||||
ARM 64-bit (AArch64) Linux support.
|
||||
|
||||
|
||||
@@ -26,7 +26,7 @@
|
||||
stdout-path = "serial0:115200n8";
|
||||
};
|
||||
|
||||
memory {
|
||||
memory@0 {
|
||||
device_type = "memory";
|
||||
reg = <0x0 0x0 0x40000000>;
|
||||
};
|
||||
|
||||
@@ -71,7 +71,7 @@
|
||||
<1 10 0xf01>;
|
||||
};
|
||||
|
||||
amba_apu {
|
||||
amba_apu: amba_apu@0 {
|
||||
compatible = "simple-bus";
|
||||
#address-cells = <2>;
|
||||
#size-cells = <1>;
|
||||
@@ -191,7 +191,7 @@
|
||||
};
|
||||
|
||||
i2c0: i2c@ff020000 {
|
||||
compatible = "cdns,i2c-r1p10";
|
||||
compatible = "cdns,i2c-r1p14", "cdns,i2c-r1p10";
|
||||
status = "disabled";
|
||||
interrupt-parent = <&gic>;
|
||||
interrupts = <0 17 4>;
|
||||
@@ -202,7 +202,7 @@
|
||||
};
|
||||
|
||||
i2c1: i2c@ff030000 {
|
||||
compatible = "cdns,i2c-r1p10";
|
||||
compatible = "cdns,i2c-r1p14", "cdns,i2c-r1p10";
|
||||
status = "disabled";
|
||||
interrupt-parent = <&gic>;
|
||||
interrupts = <0 18 4>;
|
||||
|
||||
@@ -223,14 +223,25 @@ lr .req x30 // link register
|
||||
.endm
|
||||
|
||||
/*
|
||||
* @dst: Result of per_cpu(sym, smp_processor_id())
|
||||
* @sym: The name of the per-cpu variable
|
||||
* @reg: Result of per_cpu(sym, smp_processor_id())
|
||||
* @tmp: scratch register
|
||||
*/
|
||||
.macro this_cpu_ptr, sym, reg, tmp
|
||||
adr_l \reg, \sym
|
||||
.macro adr_this_cpu, dst, sym, tmp
|
||||
adr_l \dst, \sym
|
||||
mrs \tmp, tpidr_el1
|
||||
add \reg, \reg, \tmp
|
||||
add \dst, \dst, \tmp
|
||||
.endm
|
||||
|
||||
/*
|
||||
* @dst: Result of READ_ONCE(per_cpu(sym, smp_processor_id()))
|
||||
* @sym: The name of the per-cpu variable
|
||||
* @tmp: scratch register
|
||||
*/
|
||||
.macro ldr_this_cpu dst, sym, tmp
|
||||
adr_l \dst, \sym
|
||||
mrs \tmp, tpidr_el1
|
||||
ldr \dst, [\dst, \tmp]
|
||||
.endm
|
||||
|
||||
/*
|
||||
|
||||
35
arch/arm64/include/asm/current.h
Normal file
35
arch/arm64/include/asm/current.h
Normal file
@@ -0,0 +1,35 @@
|
||||
#ifndef __ASM_CURRENT_H
|
||||
#define __ASM_CURRENT_H
|
||||
|
||||
#include <linux/compiler.h>
|
||||
|
||||
#include <asm/sysreg.h>
|
||||
|
||||
#ifndef __ASSEMBLY__
|
||||
|
||||
#ifdef CONFIG_THREAD_INFO_IN_TASK
|
||||
struct task_struct;
|
||||
|
||||
/*
|
||||
* We don't use read_sysreg() as we want the compiler to cache the value where
|
||||
* possible.
|
||||
*/
|
||||
static __always_inline struct task_struct *get_current(void)
|
||||
{
|
||||
unsigned long sp_el0;
|
||||
|
||||
asm ("mrs %0, sp_el0" : "=r" (sp_el0));
|
||||
|
||||
return (struct task_struct *)sp_el0;
|
||||
}
|
||||
#define current get_current()
|
||||
#else
|
||||
#include <linux/thread_info.h>
|
||||
#define get_current() (current_thread_info()->task)
|
||||
#define current get_current()
|
||||
#endif
|
||||
|
||||
#endif /* __ASSEMBLY__ */
|
||||
|
||||
#endif /* __ASM_CURRENT_H */
|
||||
|
||||
@@ -113,12 +113,11 @@
|
||||
#define ELF_EXEC_PAGESIZE PAGE_SIZE
|
||||
|
||||
/*
|
||||
* This is the location that an ET_DYN program is loaded if exec'ed. Typical
|
||||
* use of this is to invoke "./ld.so someprog" to test out a new version of
|
||||
* the loader. We need to make sure that it is out of the way of the program
|
||||
* that it will "exec", and that there is sufficient room for the brk.
|
||||
* This is the base location for PIE (ET_DYN with INTERP) loads. On
|
||||
* 64-bit, this is raised to 4GB to leave the entire 32-bit address
|
||||
* space open for things that want to use the area for 32-bit pointers.
|
||||
*/
|
||||
#define ELF_ET_DYN_BASE (2 * TASK_SIZE_64 / 3)
|
||||
#define ELF_ET_DYN_BASE 0x100000000UL
|
||||
|
||||
#ifndef __ASSEMBLY__
|
||||
|
||||
@@ -169,7 +168,8 @@ extern int arch_setup_additional_pages(struct linux_binprm *bprm,
|
||||
|
||||
#ifdef CONFIG_COMPAT
|
||||
|
||||
#define COMPAT_ELF_ET_DYN_BASE (2 * TASK_SIZE_32 / 3)
|
||||
/* PIE load location for compat arm. Must match ARM ELF_ET_DYN_BASE. */
|
||||
#define COMPAT_ELF_ET_DYN_BASE 0x000400000UL
|
||||
|
||||
/* AArch32 registers. */
|
||||
#define COMPAT_ELF_NGREG 18
|
||||
|
||||
@@ -22,14 +22,19 @@
|
||||
#define MODULE_ARCH_VERMAGIC "aarch64"
|
||||
|
||||
#ifdef CONFIG_ARM64_MODULE_PLTS
|
||||
struct mod_arch_specific {
|
||||
struct mod_plt_sec {
|
||||
struct elf64_shdr *plt;
|
||||
int plt_num_entries;
|
||||
int plt_max_entries;
|
||||
};
|
||||
|
||||
struct mod_arch_specific {
|
||||
struct mod_plt_sec core;
|
||||
struct mod_plt_sec init;
|
||||
};
|
||||
#endif
|
||||
|
||||
u64 module_emit_plt_entry(struct module *mod, const Elf64_Rela *rela,
|
||||
u64 module_emit_plt_entry(struct module *mod, void *loc, const Elf64_Rela *rela,
|
||||
Elf64_Sym *sym);
|
||||
|
||||
#ifdef CONFIG_RANDOMIZE_BASE
|
||||
|
||||
@@ -16,6 +16,8 @@
|
||||
#ifndef __ASM_PERCPU_H
|
||||
#define __ASM_PERCPU_H
|
||||
|
||||
#include <asm/stack_pointer.h>
|
||||
|
||||
static inline void set_my_cpu_offset(unsigned long off)
|
||||
{
|
||||
asm volatile("msr tpidr_el1, %0" :: "r" (off) : "memory");
|
||||
|
||||
@@ -17,6 +17,8 @@
|
||||
#ifndef __ASM_PERF_EVENT_H
|
||||
#define __ASM_PERF_EVENT_H
|
||||
|
||||
#include <asm/stack_pointer.h>
|
||||
|
||||
#ifdef CONFIG_PERF_EVENTS
|
||||
struct pt_regs;
|
||||
extern unsigned long perf_instruction_pointer(struct pt_regs *regs);
|
||||
|
||||
@@ -29,11 +29,22 @@
|
||||
|
||||
#ifndef __ASSEMBLY__
|
||||
|
||||
#include <asm/percpu.h>
|
||||
|
||||
#include <linux/threads.h>
|
||||
#include <linux/cpumask.h>
|
||||
#include <linux/thread_info.h>
|
||||
|
||||
#define raw_smp_processor_id() (current_thread_info()->cpu)
|
||||
DECLARE_PER_CPU_READ_MOSTLY(int, cpu_number);
|
||||
|
||||
/*
|
||||
* We don't use this_cpu_read(cpu_number) as that has implicit writes to
|
||||
* preempt_count, and associated (compiler) barriers, that we'd like to avoid
|
||||
* the expense of. If we're preemptible, the value can be stale at use anyway.
|
||||
* And we can't use this_cpu_ptr() either, as that winds up recursing back
|
||||
* here under CONFIG_DEBUG_PREEMPT=y.
|
||||
*/
|
||||
#define raw_smp_processor_id() (*raw_cpu_ptr(&cpu_number))
|
||||
|
||||
struct seq_file;
|
||||
|
||||
@@ -73,6 +84,9 @@ asmlinkage void secondary_start_kernel(void);
|
||||
*/
|
||||
struct secondary_data {
|
||||
void *stack;
|
||||
#ifdef CONFIG_THREAD_INFO_IN_TASK
|
||||
struct task_struct *task;
|
||||
#endif
|
||||
long status;
|
||||
};
|
||||
|
||||
|
||||
9
arch/arm64/include/asm/stack_pointer.h
Normal file
9
arch/arm64/include/asm/stack_pointer.h
Normal file
@@ -0,0 +1,9 @@
|
||||
#ifndef __ASM_STACK_POINTER_H
|
||||
#define __ASM_STACK_POINTER_H
|
||||
|
||||
/*
|
||||
* how to get the current stack pointer from C
|
||||
*/
|
||||
register unsigned long current_stack_pointer asm ("sp");
|
||||
|
||||
#endif /* __ASM_STACK_POINTER_H */
|
||||
@@ -1,7 +1,7 @@
|
||||
#ifndef __ASM_SUSPEND_H
|
||||
#define __ASM_SUSPEND_H
|
||||
|
||||
#define NR_CTX_REGS 10
|
||||
#define NR_CTX_REGS 12
|
||||
#define NR_CALLEE_SAVED_REGS 12
|
||||
|
||||
/*
|
||||
|
||||
@@ -36,25 +36,36 @@
|
||||
|
||||
struct task_struct;
|
||||
|
||||
#include <asm/stack_pointer.h>
|
||||
#include <asm/types.h>
|
||||
|
||||
typedef unsigned long mm_segment_t;
|
||||
|
||||
/*
|
||||
* low level task data that entry.S needs immediate access to.
|
||||
* __switch_to() assumes cpu_context follows immediately after cpu_domain.
|
||||
*/
|
||||
struct thread_info {
|
||||
unsigned long flags; /* low level flags */
|
||||
mm_segment_t addr_limit; /* address limit */
|
||||
#ifndef CONFIG_THREAD_INFO_IN_TASK
|
||||
struct task_struct *task; /* main task structure */
|
||||
#endif
|
||||
#ifdef CONFIG_ARM64_SW_TTBR0_PAN
|
||||
u64 ttbr0; /* saved TTBR0_EL1 */
|
||||
#endif
|
||||
int preempt_count; /* 0 => preemptable, <0 => bug */
|
||||
#ifndef CONFIG_THREAD_INFO_IN_TASK
|
||||
int cpu; /* cpu */
|
||||
#endif
|
||||
};
|
||||
|
||||
#ifdef CONFIG_THREAD_INFO_IN_TASK
|
||||
#define INIT_THREAD_INFO(tsk) \
|
||||
{ \
|
||||
.preempt_count = INIT_PREEMPT_COUNT, \
|
||||
.addr_limit = KERNEL_DS, \
|
||||
}
|
||||
#else
|
||||
#define INIT_THREAD_INFO(tsk) \
|
||||
{ \
|
||||
.task = &tsk, \
|
||||
@@ -63,14 +74,6 @@ struct thread_info {
|
||||
.addr_limit = KERNEL_DS, \
|
||||
}
|
||||
|
||||
#define init_thread_info (init_thread_union.thread_info)
|
||||
#define init_stack (init_thread_union.stack)
|
||||
|
||||
/*
|
||||
* how to get the current stack pointer from C
|
||||
*/
|
||||
register unsigned long current_stack_pointer asm ("sp");
|
||||
|
||||
/*
|
||||
* how to get the thread information struct from C
|
||||
*/
|
||||
@@ -88,6 +91,11 @@ static inline struct thread_info *current_thread_info(void)
|
||||
return (struct thread_info *)sp_el0;
|
||||
}
|
||||
|
||||
#define init_thread_info (init_thread_union.thread_info)
|
||||
#endif
|
||||
|
||||
#define init_stack (init_thread_union.stack)
|
||||
|
||||
#define thread_saved_pc(tsk) \
|
||||
((unsigned long)(tsk->thread.cpu_context.pc))
|
||||
#define thread_saved_sp(tsk) \
|
||||
|
||||
@@ -35,11 +35,16 @@ int main(void)
|
||||
{
|
||||
DEFINE(TSK_ACTIVE_MM, offsetof(struct task_struct, active_mm));
|
||||
BLANK();
|
||||
#ifdef CONFIG_THREAD_INFO_IN_TASK
|
||||
DEFINE(TSK_TI_FLAGS, offsetof(struct task_struct, thread_info.flags));
|
||||
DEFINE(TSK_TI_PREEMPT, offsetof(struct task_struct, thread_info.preempt_count));
|
||||
DEFINE(TSK_TI_ADDR_LIMIT, offsetof(struct task_struct, thread_info.addr_limit));
|
||||
DEFINE(TSK_STACK, offsetof(struct task_struct, stack));
|
||||
#else
|
||||
DEFINE(TI_FLAGS, offsetof(struct thread_info, flags));
|
||||
DEFINE(TI_PREEMPT, offsetof(struct thread_info, preempt_count));
|
||||
DEFINE(TI_ADDR_LIMIT, offsetof(struct thread_info, addr_limit));
|
||||
DEFINE(TI_TASK, offsetof(struct thread_info, task));
|
||||
DEFINE(TI_CPU, offsetof(struct thread_info, cpu));
|
||||
#endif
|
||||
#ifdef CONFIG_ARM64_SW_TTBR0_PAN
|
||||
DEFINE(TSK_TI_TTBR0, offsetof(struct thread_info, ttbr0));
|
||||
#endif
|
||||
@@ -126,6 +131,11 @@ int main(void)
|
||||
BLANK();
|
||||
DEFINE(CPU_BOOT_STACK, offsetof(struct secondary_data, stack));
|
||||
BLANK();
|
||||
#ifdef CONFIG_THREAD_INFO_IN_TASK
|
||||
DEFINE(CPU_BOOT_STACK, offsetof(struct secondary_data, stack));
|
||||
DEFINE(CPU_BOOT_TASK, offsetof(struct secondary_data, task));
|
||||
BLANK();
|
||||
#endif
|
||||
#ifdef CONFIG_KVM_ARM_HOST
|
||||
DEFINE(VCPU_CONTEXT, offsetof(struct kvm_vcpu, arch.ctxt));
|
||||
DEFINE(CPU_GP_REGS, offsetof(struct kvm_cpu_context, gp_regs));
|
||||
|
||||
@@ -93,9 +93,14 @@
|
||||
|
||||
.if \el == 0
|
||||
mrs x21, sp_el0
|
||||
#ifdef CONFIG_THREAD_INFO_IN_TASK
|
||||
ldr_this_cpu tsk, __entry_task, x20 // Ensure MDSCR_EL1.SS is clear,
|
||||
ldr x19, [tsk, #TSK_TI_FLAGS] // since we can unmask debug
|
||||
#else
|
||||
mov tsk, sp
|
||||
and tsk, tsk, #~(THREAD_SIZE - 1) // Ensure MDSCR_EL1.SS is clear,
|
||||
ldr x19, [tsk, #TI_FLAGS] // since we can unmask debug
|
||||
#endif
|
||||
disable_step_tsk x19, x20 // exceptions when scheduling.
|
||||
|
||||
mov x29, xzr // fp pointed to user-space
|
||||
@@ -103,10 +108,18 @@
|
||||
add x21, sp, #S_FRAME_SIZE
|
||||
get_thread_info tsk
|
||||
/* Save the task's original addr_limit and set USER_DS (TASK_SIZE_64) */
|
||||
#ifdef CONFIG_THREAD_INFO_IN_TASK
|
||||
ldr x20, [tsk, #TSK_TI_ADDR_LIMIT]
|
||||
#else
|
||||
ldr x20, [tsk, #TI_ADDR_LIMIT]
|
||||
#endif
|
||||
str x20, [sp, #S_ORIG_ADDR_LIMIT]
|
||||
mov x20, #TASK_SIZE_64
|
||||
#ifdef CONFIG_THREAD_INFO_IN_TASK
|
||||
str x20, [tsk, #TSK_TI_ADDR_LIMIT]
|
||||
#else
|
||||
str x20, [tsk, #TI_ADDR_LIMIT]
|
||||
#endif
|
||||
.endif /* \el == 0 */
|
||||
mrs x22, elr_el1
|
||||
mrs x23, spsr_el1
|
||||
@@ -167,7 +180,11 @@ alternative_else_nop_endif
|
||||
.if \el != 0
|
||||
/* Restore the task's original addr_limit. */
|
||||
ldr x20, [sp, #S_ORIG_ADDR_LIMIT]
|
||||
#ifdef CONFIG_THREAD_INFO_IN_TASK
|
||||
str x20, [tsk, #TSK_TI_ADDR_LIMIT]
|
||||
#else
|
||||
str x20, [tsk, #TI_ADDR_LIMIT]
|
||||
#endif
|
||||
.endif
|
||||
|
||||
ldp x21, x22, [sp, #S_PC] // load ELR, SPSR
|
||||
@@ -255,15 +272,22 @@ alternative_endif
|
||||
mov x19, sp // preserve the original sp
|
||||
|
||||
/*
|
||||
* Compare sp with the current thread_info, if the top
|
||||
* ~(THREAD_SIZE - 1) bits match, we are on a task stack, and
|
||||
* should switch to the irq stack.
|
||||
* Compare sp with the base of the task stack.
|
||||
* If the top ~(THREAD_SIZE - 1) bits match, we are on a task stack,
|
||||
* and should switch to the irq stack.
|
||||
*/
|
||||
#ifdef CONFIG_THREAD_INFO_IN_TASK
|
||||
ldr x25, [tsk, TSK_STACK]
|
||||
eor x25, x25, x19
|
||||
and x25, x25, #~(THREAD_SIZE - 1)
|
||||
cbnz x25, 9998f
|
||||
#else
|
||||
and x25, x19, #~(THREAD_SIZE - 1)
|
||||
cmp x25, tsk
|
||||
b.ne 9998f
|
||||
#endif
|
||||
|
||||
this_cpu_ptr irq_stack, x25, x26
|
||||
adr_this_cpu x25, irq_stack, x26
|
||||
mov x26, #IRQ_STACK_START_SP
|
||||
add x26, x25, x26
|
||||
|
||||
@@ -492,9 +516,17 @@ el1_irq:
|
||||
irq_handler
|
||||
|
||||
#ifdef CONFIG_PREEMPT
|
||||
#ifdef CONFIG_THREAD_INFO_IN_TASK
|
||||
ldr w24, [tsk, #TSK_TI_PREEMPT] // get preempt count
|
||||
#else
|
||||
ldr w24, [tsk, #TI_PREEMPT] // get preempt count
|
||||
#endif
|
||||
cbnz w24, 1f // preempt count != 0
|
||||
#ifdef CONFIG_THREAD_INFO_IN_TASK
|
||||
ldr x0, [tsk, #TSK_TI_FLAGS] // get flags
|
||||
#else
|
||||
ldr x0, [tsk, #TI_FLAGS] // get flags
|
||||
#endif
|
||||
tbz x0, #TIF_NEED_RESCHED, 1f // needs rescheduling?
|
||||
bl el1_preempt
|
||||
1:
|
||||
@@ -509,7 +541,11 @@ ENDPROC(el1_irq)
|
||||
el1_preempt:
|
||||
mov x24, lr
|
||||
1: bl preempt_schedule_irq // irq en/disable is done inside
|
||||
#ifdef CONFIG_THREAD_INFO_IN_TASK
|
||||
ldr x0, [tsk, #TSK_TI_FLAGS] // get new tasks TI_FLAGS
|
||||
#else
|
||||
ldr x0, [tsk, #TI_FLAGS] // get new tasks TI_FLAGS
|
||||
#endif
|
||||
tbnz x0, #TIF_NEED_RESCHED, 1b // needs rescheduling?
|
||||
ret x24
|
||||
#endif
|
||||
@@ -729,8 +765,12 @@ ENTRY(cpu_switch_to)
|
||||
ldp x29, x9, [x8], #16
|
||||
ldr lr, [x8]
|
||||
mov sp, x9
|
||||
#ifdef CONFIG_THREAD_INFO_IN_TASK
|
||||
msr sp_el0, x1
|
||||
#else
|
||||
and x9, x9, #~(THREAD_SIZE - 1)
|
||||
msr sp_el0, x9
|
||||
#endif
|
||||
ret
|
||||
ENDPROC(cpu_switch_to)
|
||||
|
||||
@@ -741,7 +781,11 @@ ENDPROC(cpu_switch_to)
|
||||
ret_fast_syscall:
|
||||
disable_irq // disable interrupts
|
||||
str x0, [sp, #S_X0] // returned x0
|
||||
#ifdef CONFIG_THREAD_INFO_IN_TASK
|
||||
ldr x1, [tsk, #TSK_TI_FLAGS] // re-check for syscall tracing
|
||||
#else
|
||||
ldr x1, [tsk, #TI_FLAGS] // re-check for syscall tracing
|
||||
#endif
|
||||
and x2, x1, #_TIF_SYSCALL_WORK
|
||||
cbnz x2, ret_fast_syscall_trace
|
||||
and x2, x1, #_TIF_WORK_MASK
|
||||
@@ -773,7 +817,11 @@ work_resched:
|
||||
*/
|
||||
ret_to_user:
|
||||
disable_irq // disable interrupts
|
||||
#ifdef CONFIG_THREAD_INFO_IN_TASK
|
||||
ldr x1, [tsk, #TSK_TI_FLAGS]
|
||||
#else
|
||||
ldr x1, [tsk, #TI_FLAGS]
|
||||
#endif
|
||||
and x2, x1, #_TIF_WORK_MASK
|
||||
cbnz x2, work_pending
|
||||
enable_step_tsk x1, x2
|
||||
@@ -805,7 +853,11 @@ el0_svc_naked: // compat entry point
|
||||
enable_dbg_and_irq
|
||||
ct_user_exit 1
|
||||
|
||||
#ifdef CONFIG_THREAD_INFO_IN_TASK
|
||||
ldr x16, [tsk, #TSK_TI_FLAGS] // check for syscall hooks
|
||||
#else
|
||||
ldr x16, [tsk, #TI_FLAGS] // check for syscall hooks
|
||||
#endif
|
||||
tst x16, #_TIF_SYSCALL_WORK
|
||||
b.ne __sys_trace
|
||||
cmp scno, sc_nr // check upper syscall limit
|
||||
|
||||
@@ -419,6 +419,7 @@ ENDPROC(__create_page_tables)
|
||||
.set initial_sp, init_thread_union + THREAD_START_SP
|
||||
__primary_switched:
|
||||
mov x28, lr // preserve LR
|
||||
|
||||
adr_l x8, vectors // load VBAR_EL1 with virtual
|
||||
msr vbar_el1, x8 // vector table address
|
||||
isb
|
||||
@@ -431,10 +432,18 @@ __primary_switched:
|
||||
bl __pi_memset
|
||||
dsb ishst // Make zero page visible to PTW
|
||||
|
||||
#ifdef CONFIG_THREAD_INFO_IN_TASK
|
||||
adrp x4, init_thread_union
|
||||
add sp, x4, #THREAD_SIZE
|
||||
adr_l x5, init_task
|
||||
msr sp_el0, x5 // Save thread_info
|
||||
#else
|
||||
adr_l sp, initial_sp, x4
|
||||
mov x4, sp
|
||||
and x4, x4, #~(THREAD_SIZE - 1)
|
||||
msr sp_el0, x4 // Save thread_info
|
||||
#endif
|
||||
|
||||
str_l x21, __fdt_pointer, x5 // Save FDT pointer
|
||||
|
||||
ldr_l x4, kimage_vaddr // Save the offset between
|
||||
@@ -649,12 +658,19 @@ __secondary_switched:
|
||||
adr_l x5, vectors
|
||||
msr vbar_el1, x5
|
||||
isb
|
||||
|
||||
#ifdef CONFIG_THREAD_INFO_IN_TASK
|
||||
adr_l x0, secondary_data
|
||||
ldr x1, [x0, #CPU_BOOT_STACK] // get secondary_data.stack
|
||||
mov sp, x1
|
||||
ldr x2, [x0, #CPU_BOOT_TASK]
|
||||
msr sp_el0, x2
|
||||
#else
|
||||
adr_l x0, secondary_data
|
||||
ldr x0, [x0, #CPU_BOOT_STACK] // get secondary_data.stack
|
||||
mov sp, x0
|
||||
and x0, x0, #~(THREAD_SIZE - 1)
|
||||
msr sp_el0, x0 // save thread_info
|
||||
#endif
|
||||
mov x29, #0
|
||||
b secondary_start_kernel
|
||||
ENDPROC(__secondary_switched)
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (C) 2014-2016 Linaro Ltd. <ard.biesheuvel@linaro.org>
|
||||
* Copyright (C) 2014-2017 Linaro Ltd. <ard.biesheuvel@linaro.org>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
@@ -26,34 +26,20 @@ struct plt_entry {
|
||||
__le32 br; /* br x16 */
|
||||
};
|
||||
|
||||
u64 module_emit_plt_entry(struct module *mod, const Elf64_Rela *rela,
|
||||
static bool in_init(const struct module *mod, void *loc)
|
||||
{
|
||||
return (u64)loc - (u64)mod->init_layout.base < mod->init_layout.size;
|
||||
}
|
||||
|
||||
u64 module_emit_plt_entry(struct module *mod, void *loc, const Elf64_Rela *rela,
|
||||
Elf64_Sym *sym)
|
||||
{
|
||||
struct plt_entry *plt = (struct plt_entry *)mod->arch.plt->sh_addr;
|
||||
int i = mod->arch.plt_num_entries;
|
||||
struct mod_plt_sec *pltsec = !in_init(mod, loc) ? &mod->arch.core :
|
||||
&mod->arch.init;
|
||||
struct plt_entry *plt = (struct plt_entry *)pltsec->plt->sh_addr;
|
||||
int i = pltsec->plt_num_entries;
|
||||
u64 val = sym->st_value + rela->r_addend;
|
||||
|
||||
/*
|
||||
* We only emit PLT entries against undefined (SHN_UNDEF) symbols,
|
||||
* which are listed in the ELF symtab section, but without a type
|
||||
* or a size.
|
||||
* So, similar to how the module loader uses the Elf64_Sym::st_value
|
||||
* field to store the resolved addresses of undefined symbols, let's
|
||||
* borrow the Elf64_Sym::st_size field (whose value is never used by
|
||||
* the module loader, even for symbols that are defined) to record
|
||||
* the address of a symbol's associated PLT entry as we emit it for a
|
||||
* zero addend relocation (which is the only kind we have to deal with
|
||||
* in practice). This allows us to find duplicates without having to
|
||||
* go through the table every time.
|
||||
*/
|
||||
if (rela->r_addend == 0 && sym->st_size != 0) {
|
||||
BUG_ON(sym->st_size < (u64)plt || sym->st_size >= (u64)&plt[i]);
|
||||
return sym->st_size;
|
||||
}
|
||||
|
||||
mod->arch.plt_num_entries++;
|
||||
BUG_ON(mod->arch.plt_num_entries > mod->arch.plt_max_entries);
|
||||
|
||||
/*
|
||||
* MOVK/MOVN/MOVZ opcode:
|
||||
* +--------+------------+--------+-----------+-------------+---------+
|
||||
@@ -72,8 +58,19 @@ u64 module_emit_plt_entry(struct module *mod, const Elf64_Rela *rela,
|
||||
cpu_to_le32(0xd61f0200)
|
||||
};
|
||||
|
||||
if (rela->r_addend == 0)
|
||||
sym->st_size = (u64)&plt[i];
|
||||
/*
|
||||
* Check if the entry we just created is a duplicate. Given that the
|
||||
* relocations are sorted, this will be the last entry we allocated.
|
||||
* (if one exists).
|
||||
*/
|
||||
if (i > 0 &&
|
||||
plt[i].mov0 == plt[i - 1].mov0 &&
|
||||
plt[i].mov1 == plt[i - 1].mov1 &&
|
||||
plt[i].mov2 == plt[i - 1].mov2)
|
||||
return (u64)&plt[i - 1];
|
||||
|
||||
pltsec->plt_num_entries++;
|
||||
BUG_ON(pltsec->plt_num_entries > pltsec->plt_max_entries);
|
||||
|
||||
return (u64)&plt[i];
|
||||
}
|
||||
@@ -104,7 +101,8 @@ static bool duplicate_rel(const Elf64_Rela *rela, int num)
|
||||
return num > 0 && cmp_rela(rela + num, rela + num - 1) == 0;
|
||||
}
|
||||
|
||||
static unsigned int count_plts(Elf64_Sym *syms, Elf64_Rela *rela, int num)
|
||||
static unsigned int count_plts(Elf64_Sym *syms, Elf64_Rela *rela, int num,
|
||||
Elf64_Word dstidx)
|
||||
{
|
||||
unsigned int ret = 0;
|
||||
Elf64_Sym *s;
|
||||
@@ -116,13 +114,17 @@ static unsigned int count_plts(Elf64_Sym *syms, Elf64_Rela *rela, int num)
|
||||
case R_AARCH64_CALL26:
|
||||
/*
|
||||
* We only have to consider branch targets that resolve
|
||||
* to undefined symbols. This is not simply a heuristic,
|
||||
* it is a fundamental limitation, since the PLT itself
|
||||
* is part of the module, and needs to be within 128 MB
|
||||
* as well, so modules can never grow beyond that limit.
|
||||
* to symbols that are defined in a different section.
|
||||
* This is not simply a heuristic, it is a fundamental
|
||||
* limitation, since there is no guaranteed way to emit
|
||||
* PLT entries sufficiently close to the branch if the
|
||||
* section size exceeds the range of a branch
|
||||
* instruction. So ignore relocations against defined
|
||||
* symbols if they live in the same section as the
|
||||
* relocation target.
|
||||
*/
|
||||
s = syms + ELF64_R_SYM(rela[i].r_info);
|
||||
if (s->st_shndx != SHN_UNDEF)
|
||||
if (s->st_shndx == dstidx)
|
||||
break;
|
||||
|
||||
/*
|
||||
@@ -149,7 +151,8 @@ static unsigned int count_plts(Elf64_Sym *syms, Elf64_Rela *rela, int num)
|
||||
int module_frob_arch_sections(Elf_Ehdr *ehdr, Elf_Shdr *sechdrs,
|
||||
char *secstrings, struct module *mod)
|
||||
{
|
||||
unsigned long plt_max_entries = 0;
|
||||
unsigned long core_plts = 0;
|
||||
unsigned long init_plts = 0;
|
||||
Elf64_Sym *syms = NULL;
|
||||
int i;
|
||||
|
||||
@@ -158,14 +161,16 @@ int module_frob_arch_sections(Elf_Ehdr *ehdr, Elf_Shdr *sechdrs,
|
||||
* entries. Record the symtab address as well.
|
||||
*/
|
||||
for (i = 0; i < ehdr->e_shnum; i++) {
|
||||
if (strcmp(".plt", secstrings + sechdrs[i].sh_name) == 0)
|
||||
mod->arch.plt = sechdrs + i;
|
||||
if (!strcmp(secstrings + sechdrs[i].sh_name, ".plt"))
|
||||
mod->arch.core.plt = sechdrs + i;
|
||||
else if (!strcmp(secstrings + sechdrs[i].sh_name, ".init.plt"))
|
||||
mod->arch.init.plt = sechdrs + i;
|
||||
else if (sechdrs[i].sh_type == SHT_SYMTAB)
|
||||
syms = (Elf64_Sym *)sechdrs[i].sh_addr;
|
||||
}
|
||||
|
||||
if (!mod->arch.plt) {
|
||||
pr_err("%s: module PLT section missing\n", mod->name);
|
||||
if (!mod->arch.core.plt || !mod->arch.init.plt) {
|
||||
pr_err("%s: module PLT section(s) missing\n", mod->name);
|
||||
return -ENOEXEC;
|
||||
}
|
||||
if (!syms) {
|
||||
@@ -188,14 +193,27 @@ int module_frob_arch_sections(Elf_Ehdr *ehdr, Elf_Shdr *sechdrs,
|
||||
/* sort by type, symbol index and addend */
|
||||
sort(rels, numrels, sizeof(Elf64_Rela), cmp_rela, NULL);
|
||||
|
||||
plt_max_entries += count_plts(syms, rels, numrels);
|
||||
if (strncmp(secstrings + dstsec->sh_name, ".init", 5) != 0)
|
||||
core_plts += count_plts(syms, rels, numrels,
|
||||
sechdrs[i].sh_info);
|
||||
else
|
||||
init_plts += count_plts(syms, rels, numrels,
|
||||
sechdrs[i].sh_info);
|
||||
}
|
||||
|
||||
mod->arch.plt->sh_type = SHT_NOBITS;
|
||||
mod->arch.plt->sh_flags = SHF_EXECINSTR | SHF_ALLOC;
|
||||
mod->arch.plt->sh_addralign = L1_CACHE_BYTES;
|
||||
mod->arch.plt->sh_size = plt_max_entries * sizeof(struct plt_entry);
|
||||
mod->arch.plt_num_entries = 0;
|
||||
mod->arch.plt_max_entries = plt_max_entries;
|
||||
mod->arch.core.plt->sh_type = SHT_NOBITS;
|
||||
mod->arch.core.plt->sh_flags = SHF_EXECINSTR | SHF_ALLOC;
|
||||
mod->arch.core.plt->sh_addralign = L1_CACHE_BYTES;
|
||||
mod->arch.core.plt->sh_size = (core_plts + 1) * sizeof(struct plt_entry);
|
||||
mod->arch.core.plt_num_entries = 0;
|
||||
mod->arch.core.plt_max_entries = core_plts;
|
||||
|
||||
mod->arch.init.plt->sh_type = SHT_NOBITS;
|
||||
mod->arch.init.plt->sh_flags = SHF_EXECINSTR | SHF_ALLOC;
|
||||
mod->arch.init.plt->sh_addralign = L1_CACHE_BYTES;
|
||||
mod->arch.init.plt->sh_size = (init_plts + 1) * sizeof(struct plt_entry);
|
||||
mod->arch.init.plt_num_entries = 0;
|
||||
mod->arch.init.plt_max_entries = init_plts;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -380,7 +380,7 @@ int apply_relocate_add(Elf64_Shdr *sechdrs,
|
||||
|
||||
if (IS_ENABLED(CONFIG_ARM64_MODULE_PLTS) &&
|
||||
ovf == -ERANGE) {
|
||||
val = module_emit_plt_entry(me, &rel[i], sym);
|
||||
val = module_emit_plt_entry(me, loc, &rel[i], sym);
|
||||
ovf = reloc_insn_imm(RELOC_OP_PREL, loc, val, 2,
|
||||
26, AARCH64_INSN_IMM_26);
|
||||
}
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
SECTIONS {
|
||||
.plt (NOLOAD) : { BYTE(0) }
|
||||
.init.plt (NOLOAD) : { BYTE(0) }
|
||||
}
|
||||
|
||||
@@ -157,10 +157,10 @@ arm_kprobe_decode_insn(kprobe_opcode_t *addr, struct arch_specific_insn *asi)
|
||||
mod = __module_address((unsigned long)addr);
|
||||
if (mod && within_module_init((unsigned long)addr, mod) &&
|
||||
!within_module_init((unsigned long)scan_end, mod))
|
||||
scan_end = (kprobe_opcode_t *)mod->module_init;
|
||||
scan_end = (kprobe_opcode_t *)mod->init_layout.base;
|
||||
else if (mod && within_module_core((unsigned long)addr, mod) &&
|
||||
!within_module_core((unsigned long)scan_end, mod))
|
||||
scan_end = (kprobe_opcode_t *)mod->module_core;
|
||||
scan_end = (kprobe_opcode_t *)mod->core_layout.base;
|
||||
preempt_enable();
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -45,6 +45,9 @@
|
||||
#include <linux/personality.h>
|
||||
#include <linux/notifier.h>
|
||||
#include <trace/events/power.h>
|
||||
#ifdef CONFIG_THREAD_INFO_IN_TASK
|
||||
#include <linux/percpu.h>
|
||||
#endif
|
||||
|
||||
#include <asm/alternative.h>
|
||||
#include <asm/compat.h>
|
||||
@@ -392,6 +395,22 @@ void uao_thread_switch(struct task_struct *next)
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef CONFIG_THREAD_INFO_IN_TASK
|
||||
/*
|
||||
* We store our current task in sp_el0, which is clobbered by userspace. Keep a
|
||||
* shadow copy so that we can restore this upon entry from userspace.
|
||||
*
|
||||
* This is *only* for exception entry from EL0, and is not valid until we
|
||||
* __switch_to() a user task.
|
||||
*/
|
||||
DEFINE_PER_CPU(struct task_struct *, __entry_task);
|
||||
|
||||
static void entry_task_switch(struct task_struct *next)
|
||||
{
|
||||
__this_cpu_write(__entry_task, next);
|
||||
}
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Thread switching.
|
||||
*/
|
||||
@@ -404,6 +423,9 @@ struct task_struct *__switch_to(struct task_struct *prev,
|
||||
tls_thread_switch(next);
|
||||
hw_breakpoint_thread_switch(next);
|
||||
contextidr_thread_switch(next);
|
||||
#ifdef CONFIG_THREAD_INFO_IN_TASK
|
||||
entry_task_switch(next);
|
||||
#endif
|
||||
uao_thread_switch(next);
|
||||
|
||||
/*
|
||||
@@ -421,27 +443,35 @@ struct task_struct *__switch_to(struct task_struct *prev,
|
||||
unsigned long get_wchan(struct task_struct *p)
|
||||
{
|
||||
struct stackframe frame;
|
||||
unsigned long stack_page;
|
||||
unsigned long stack_page, ret = 0;
|
||||
int count = 0;
|
||||
if (!p || p == current || p->state == TASK_RUNNING)
|
||||
return 0;
|
||||
|
||||
stack_page = (unsigned long)try_get_task_stack(p);
|
||||
if (!stack_page)
|
||||
return 0;
|
||||
|
||||
frame.fp = thread_saved_fp(p);
|
||||
frame.sp = thread_saved_sp(p);
|
||||
frame.pc = thread_saved_pc(p);
|
||||
#ifdef CONFIG_FUNCTION_GRAPH_TRACER
|
||||
frame.graph = p->curr_ret_stack;
|
||||
#endif
|
||||
stack_page = (unsigned long)task_stack_page(p);
|
||||
do {
|
||||
if (frame.sp < stack_page ||
|
||||
frame.sp >= stack_page + THREAD_SIZE ||
|
||||
unwind_frame(p, &frame))
|
||||
return 0;
|
||||
if (!in_sched_functions(frame.pc))
|
||||
return frame.pc;
|
||||
goto out;
|
||||
if (!in_sched_functions(frame.pc)) {
|
||||
ret = frame.pc;
|
||||
goto out;
|
||||
}
|
||||
} while (count ++ < 16);
|
||||
return 0;
|
||||
|
||||
out:
|
||||
put_task_stack(p);
|
||||
return ret;
|
||||
}
|
||||
|
||||
unsigned long arch_align_stack(unsigned long sp)
|
||||
|
||||
@@ -12,6 +12,7 @@
|
||||
#include <linux/export.h>
|
||||
#include <linux/ftrace.h>
|
||||
|
||||
#include <asm/stack_pointer.h>
|
||||
#include <asm/stacktrace.h>
|
||||
|
||||
struct return_address_data {
|
||||
|
||||
@@ -353,12 +353,16 @@ void __init setup_arch(char **cmdline_p)
|
||||
|
||||
#ifdef CONFIG_ARM64_SW_TTBR0_PAN
|
||||
/*
|
||||
* Make sure init_thread_info.ttbr0 always generates translation
|
||||
* Make sure thread_info.ttbr0 always generates translation
|
||||
* faults in case uaccess_enable() is inadvertently called by the init
|
||||
* thread.
|
||||
*/
|
||||
#ifdef CONFIG_THREAD_INFO_IN_TASK
|
||||
init_task.thread_info.ttbr0 = virt_to_phys(empty_zero_page);
|
||||
#else
|
||||
init_thread_info.ttbr0 = virt_to_phys(empty_zero_page);
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_VT
|
||||
#if defined(CONFIG_VGA_CONSOLE)
|
||||
|
||||
@@ -125,9 +125,6 @@ ENTRY(_cpu_resume)
|
||||
/* load sp from context */
|
||||
ldr x2, [x0, #CPU_CTX_SP]
|
||||
mov sp, x2
|
||||
/* save thread_info */
|
||||
and x2, x2, #~(THREAD_SIZE - 1)
|
||||
msr sp_el0, x2
|
||||
/*
|
||||
* cpu_do_resume expects x0 to contain context address pointer
|
||||
*/
|
||||
|
||||
@@ -58,6 +58,9 @@
|
||||
#define CREATE_TRACE_POINTS
|
||||
#include <trace/events/ipi.h>
|
||||
|
||||
DEFINE_PER_CPU_READ_MOSTLY(int, cpu_number);
|
||||
EXPORT_PER_CPU_SYMBOL(cpu_number);
|
||||
|
||||
/*
|
||||
* as from 2.5, kernels no longer have an init_tasks structure
|
||||
* so we need some other way of telling a new secondary core
|
||||
@@ -110,6 +113,9 @@ int __cpu_up(unsigned int cpu, struct task_struct *idle)
|
||||
* We need to tell the secondary core where to find its stack and the
|
||||
* page tables.
|
||||
*/
|
||||
#ifdef CONFIG_THREAD_INFO_IN_TASK
|
||||
secondary_data.task = idle;
|
||||
#endif
|
||||
secondary_data.stack = task_stack_page(idle) + THREAD_START_SP;
|
||||
update_cpu_boot_status(CPU_MMU_OFF);
|
||||
__flush_dcache_area(&secondary_data, sizeof(secondary_data));
|
||||
@@ -134,6 +140,9 @@ int __cpu_up(unsigned int cpu, struct task_struct *idle)
|
||||
pr_err("CPU%u: failed to boot: %d\n", cpu, ret);
|
||||
}
|
||||
|
||||
#ifdef CONFIG_THREAD_INFO_IN_TASK
|
||||
secondary_data.task = NULL;
|
||||
#endif
|
||||
secondary_data.stack = NULL;
|
||||
status = READ_ONCE(secondary_data.status);
|
||||
if (ret && status) {
|
||||
@@ -177,7 +186,10 @@ static void smp_store_cpu_info(unsigned int cpuid)
|
||||
asmlinkage void secondary_start_kernel(void)
|
||||
{
|
||||
struct mm_struct *mm = &init_mm;
|
||||
unsigned int cpu = smp_processor_id();
|
||||
unsigned int cpu;
|
||||
|
||||
cpu = task_cpu(current);
|
||||
set_my_cpu_offset(per_cpu_offset(cpu));
|
||||
|
||||
/*
|
||||
* All kernel threads share the same mm context; grab a
|
||||
@@ -186,8 +198,6 @@ asmlinkage void secondary_start_kernel(void)
|
||||
atomic_inc(&mm->mm_count);
|
||||
current->active_mm = mm;
|
||||
|
||||
set_my_cpu_offset(per_cpu_offset(smp_processor_id()));
|
||||
|
||||
/*
|
||||
* TTBR0 is only used for the identity mapping at this stage. Make it
|
||||
* point to zero page to avoid speculatively fetching new entries.
|
||||
@@ -676,6 +686,8 @@ void __init smp_prepare_cpus(unsigned int max_cpus)
|
||||
if (max_cpus == 0)
|
||||
break;
|
||||
|
||||
per_cpu(cpu_number, cpu) = cpu;
|
||||
|
||||
if (cpu == smp_processor_id())
|
||||
continue;
|
||||
|
||||
|
||||
@@ -22,6 +22,7 @@
|
||||
#include <linux/stacktrace.h>
|
||||
|
||||
#include <asm/irq.h>
|
||||
#include <asm/stack_pointer.h>
|
||||
#include <asm/stacktrace.h>
|
||||
|
||||
/*
|
||||
@@ -128,7 +129,6 @@ void notrace walk_stackframe(struct task_struct *tsk, struct stackframe *frame,
|
||||
break;
|
||||
}
|
||||
}
|
||||
EXPORT_SYMBOL(walk_stackframe);
|
||||
|
||||
#ifdef CONFIG_STACKTRACE
|
||||
struct stack_trace_data {
|
||||
@@ -160,6 +160,9 @@ void save_stack_trace_tsk(struct task_struct *tsk, struct stack_trace *trace)
|
||||
struct stack_trace_data data;
|
||||
struct stackframe frame;
|
||||
|
||||
if (!try_get_task_stack(tsk))
|
||||
return;
|
||||
|
||||
data.trace = trace;
|
||||
data.skip = trace->skip;
|
||||
|
||||
@@ -181,6 +184,8 @@ void save_stack_trace_tsk(struct task_struct *tsk, struct stack_trace *trace)
|
||||
walk_stackframe(tsk, &frame, save_trace, &data);
|
||||
if (trace->nr_entries < trace->max_entries)
|
||||
trace->entries[trace->nr_entries++] = ULONG_MAX;
|
||||
|
||||
put_task_stack(tsk);
|
||||
}
|
||||
|
||||
void save_stack_trace(struct stack_trace *trace)
|
||||
|
||||
@@ -44,12 +44,6 @@ void notrace __cpu_suspend_exit(void)
|
||||
*/
|
||||
cpu_uninstall_idmap();
|
||||
|
||||
/*
|
||||
* Restore per-cpu offset before any kernel
|
||||
* subsystem relying on it has a chance to run.
|
||||
*/
|
||||
set_my_cpu_offset(per_cpu_offset(smp_processor_id()));
|
||||
|
||||
/*
|
||||
* Restore HW breakpoint registers to sane values
|
||||
* before debug exceptions are possibly reenabled
|
||||
|
||||
@@ -38,6 +38,7 @@
|
||||
#include <asm/esr.h>
|
||||
#include <asm/insn.h>
|
||||
#include <asm/traps.h>
|
||||
#include <asm/stack_pointer.h>
|
||||
#include <asm/stacktrace.h>
|
||||
#include <asm/exception.h>
|
||||
#include <asm/system_misc.h>
|
||||
@@ -154,6 +155,14 @@ static void dump_backtrace(struct pt_regs *regs, struct task_struct *tsk)
|
||||
if (!tsk)
|
||||
tsk = current;
|
||||
|
||||
pr_debug("%s(regs = %p tsk = %p)\n", __func__, regs, tsk);
|
||||
|
||||
if (!tsk)
|
||||
tsk = current;
|
||||
|
||||
if (!try_get_task_stack(tsk))
|
||||
return;
|
||||
|
||||
/*
|
||||
* Switching between stacks is valid when tracing current and in
|
||||
* non-preemptible context.
|
||||
@@ -219,6 +228,8 @@ static void dump_backtrace(struct pt_regs *regs, struct task_struct *tsk)
|
||||
stack + sizeof(struct pt_regs), false);
|
||||
}
|
||||
}
|
||||
|
||||
put_task_stack(tsk);
|
||||
}
|
||||
|
||||
void show_stack(struct task_struct *tsk, unsigned long *sp)
|
||||
@@ -234,10 +245,9 @@ void show_stack(struct task_struct *tsk, unsigned long *sp)
|
||||
#endif
|
||||
#define S_SMP " SMP"
|
||||
|
||||
static int __die(const char *str, int err, struct thread_info *thread,
|
||||
struct pt_regs *regs)
|
||||
static int __die(const char *str, int err, struct pt_regs *regs)
|
||||
{
|
||||
struct task_struct *tsk = thread->task;
|
||||
struct task_struct *tsk = current;
|
||||
static int die_counter;
|
||||
int ret;
|
||||
|
||||
@@ -252,7 +262,8 @@ static int __die(const char *str, int err, struct thread_info *thread,
|
||||
print_modules();
|
||||
__show_regs(regs);
|
||||
pr_emerg("Process %.*s (pid: %d, stack limit = 0x%p)\n",
|
||||
TASK_COMM_LEN, tsk->comm, task_pid_nr(tsk), thread + 1);
|
||||
TASK_COMM_LEN, tsk->comm, task_pid_nr(tsk),
|
||||
end_of_stack(tsk));
|
||||
|
||||
if (!user_mode(regs) || in_interrupt()) {
|
||||
dump_mem(KERN_EMERG, "Stack: ", regs->sp,
|
||||
@@ -272,7 +283,6 @@ static DEFINE_RAW_SPINLOCK(die_lock);
|
||||
*/
|
||||
void die(const char *str, struct pt_regs *regs, int err)
|
||||
{
|
||||
struct thread_info *thread = current_thread_info();
|
||||
int ret;
|
||||
|
||||
oops_enter();
|
||||
@@ -280,9 +290,9 @@ void die(const char *str, struct pt_regs *regs, int err)
|
||||
raw_spin_lock_irq(&die_lock);
|
||||
console_verbose();
|
||||
bust_spinlocks(1);
|
||||
ret = __die(str, err, thread, regs);
|
||||
ret = __die(str, err, regs);
|
||||
|
||||
if (regs && kexec_should_crash(thread->task))
|
||||
if (regs && kexec_should_crash(current))
|
||||
crash_kexec(regs);
|
||||
|
||||
bust_spinlocks(0);
|
||||
|
||||
@@ -12,3 +12,7 @@ obj-$(CONFIG_KVM_ARM_HOST) += switch.o
|
||||
obj-$(CONFIG_KVM_ARM_HOST) += fpsimd.o
|
||||
obj-$(CONFIG_KVM_ARM_HOST) += tlb.o
|
||||
obj-$(CONFIG_KVM_ARM_HOST) += hyp-entry.o
|
||||
|
||||
GCOV_PROFILE := n
|
||||
KASAN_SANITIZE := n
|
||||
UBSAN_SANITIZE := n
|
||||
|
||||
@@ -88,21 +88,21 @@ void show_pte(struct mm_struct *mm, unsigned long addr)
|
||||
break;
|
||||
|
||||
pud = pud_offset(pgd, addr);
|
||||
printk(", *pud=%016llx", pud_val(*pud));
|
||||
pr_cont(", *pud=%016llx", pud_val(*pud));
|
||||
if (pud_none(*pud) || pud_bad(*pud))
|
||||
break;
|
||||
|
||||
pmd = pmd_offset(pud, addr);
|
||||
printk(", *pmd=%016llx", pmd_val(*pmd));
|
||||
pr_cont(", *pmd=%016llx", pmd_val(*pmd));
|
||||
if (pmd_none(*pmd) || pmd_bad(*pmd))
|
||||
break;
|
||||
|
||||
pte = pte_offset_map(pmd, addr);
|
||||
printk(", *pte=%016llx", pte_val(*pte));
|
||||
pr_cont(", *pte=%016llx", pte_val(*pte));
|
||||
pte_unmap(pte);
|
||||
} while(0);
|
||||
|
||||
printk("\n");
|
||||
pr_cont("\n");
|
||||
}
|
||||
|
||||
#ifdef CONFIG_ARM64_HW_AFDBM
|
||||
|
||||
@@ -70,11 +70,14 @@ ENTRY(cpu_do_suspend)
|
||||
mrs x8, mdscr_el1
|
||||
mrs x9, oslsr_el1
|
||||
mrs x10, sctlr_el1
|
||||
mrs x11, tpidr_el1
|
||||
mrs x12, sp_el0
|
||||
stp x2, x3, [x0]
|
||||
stp x4, xzr, [x0, #16]
|
||||
stp x5, x6, [x0, #32]
|
||||
stp x7, x8, [x0, #48]
|
||||
stp x9, x10, [x0, #64]
|
||||
stp x11, x12, [x0, #80]
|
||||
ret
|
||||
ENDPROC(cpu_do_suspend)
|
||||
|
||||
@@ -90,6 +93,7 @@ ENTRY(cpu_do_resume)
|
||||
ldp x6, x8, [x0, #32]
|
||||
ldp x9, x10, [x0, #48]
|
||||
ldp x11, x12, [x0, #64]
|
||||
ldp x13, x14, [x0, #80]
|
||||
msr tpidr_el0, x2
|
||||
msr tpidrro_el0, x3
|
||||
msr contextidr_el1, x4
|
||||
@@ -112,6 +116,8 @@ ENTRY(cpu_do_resume)
|
||||
msr mdscr_el1, x10
|
||||
|
||||
msr sctlr_el1, x12
|
||||
msr tpidr_el1, x13
|
||||
msr sp_el0, x14
|
||||
/*
|
||||
* Restore oslsr_el1 by writing oslar_el1
|
||||
*/
|
||||
|
||||
@@ -118,9 +118,9 @@ int module_frob_arch_sections(Elf_Ehdr *hdr, Elf_Shdr *sechdrs,
|
||||
* Increase core size to make room for GOT and set start
|
||||
* offset for GOT.
|
||||
*/
|
||||
module->core_size = ALIGN(module->core_size, 4);
|
||||
module->arch.got_offset = module->core_size;
|
||||
module->core_size += module->arch.got_size;
|
||||
module->core_layout.size = ALIGN(module->core_layout.size, 4);
|
||||
module->arch.got_offset = module->core_layout.size;
|
||||
module->core_layout.size += module->arch.got_size;
|
||||
|
||||
return 0;
|
||||
|
||||
@@ -177,7 +177,7 @@ int apply_relocate_add(Elf32_Shdr *sechdrs, const char *strtab,
|
||||
if (!info->got_initialized) {
|
||||
Elf32_Addr *gotent;
|
||||
|
||||
gotent = (module->module_core
|
||||
gotent = (module->core_layout.base
|
||||
+ module->arch.got_offset
|
||||
+ info->got_offset);
|
||||
*gotent = relocation;
|
||||
@@ -255,8 +255,8 @@ int apply_relocate_add(Elf32_Shdr *sechdrs, const char *strtab,
|
||||
*/
|
||||
pr_debug("GOTPC: PC=0x%x, got_offset=0x%lx, core=0x%p\n",
|
||||
relocation, module->arch.got_offset,
|
||||
module->module_core);
|
||||
relocation -= ((unsigned long)module->module_core
|
||||
module->core_layout.base);
|
||||
relocation -= ((unsigned long)module->core_layout.base
|
||||
+ module->arch.got_offset);
|
||||
*location = relocation;
|
||||
break;
|
||||
|
||||
@@ -45,7 +45,7 @@ config IA64
|
||||
select GENERIC_SMP_IDLE_THREAD
|
||||
select ARCH_INIT_TASK
|
||||
select ARCH_TASK_STRUCT_ALLOCATOR
|
||||
select ARCH_THREAD_INFO_ALLOCATOR
|
||||
select ARCH_THREAD_STACK_ALLOCATOR
|
||||
select ARCH_CLOCKSOURCE_DATA
|
||||
select GENERIC_TIME_VSYSCALL_OLD
|
||||
select SYSCTL_ARCH_UNALIGN_NO_WARN
|
||||
|
||||
@@ -48,15 +48,15 @@ struct thread_info {
|
||||
#ifndef ASM_OFFSETS_C
|
||||
/* how to get the thread information struct from C */
|
||||
#define current_thread_info() ((struct thread_info *) ((char *) current + IA64_TASK_SIZE))
|
||||
#define alloc_thread_info_node(tsk, node) \
|
||||
((struct thread_info *) ((char *) (tsk) + IA64_TASK_SIZE))
|
||||
#define alloc_thread_stack_node(tsk, node) \
|
||||
((unsigned long *) ((char *) (tsk) + IA64_TASK_SIZE))
|
||||
#define task_thread_info(tsk) ((struct thread_info *) ((char *) (tsk) + IA64_TASK_SIZE))
|
||||
#else
|
||||
#define current_thread_info() ((struct thread_info *) 0)
|
||||
#define alloc_thread_info_node(tsk, node) ((struct thread_info *) 0)
|
||||
#define alloc_thread_stack_node(tsk, node) ((unsigned long *) 0)
|
||||
#define task_thread_info(tsk) ((struct thread_info *) 0)
|
||||
#endif
|
||||
#define free_thread_info(ti) /* nothing */
|
||||
#define free_thread_stack(ti) /* nothing */
|
||||
#define task_stack_page(tsk) ((void *)(tsk))
|
||||
|
||||
#define __HAVE_THREAD_FUNCTIONS
|
||||
|
||||
@@ -26,6 +26,7 @@ static struct sighand_struct init_sighand = INIT_SIGHAND(init_sighand);
|
||||
* handled. This is done by having a special ".data..init_task" section...
|
||||
*/
|
||||
#define init_thread_info init_task_mem.s.thread_info
|
||||
#define init_stack init_task_mem.stack
|
||||
|
||||
union {
|
||||
struct {
|
||||
|
||||
@@ -486,13 +486,13 @@ module_frob_arch_sections (Elf_Ehdr *ehdr, Elf_Shdr *sechdrs, char *secstrings,
|
||||
static inline int
|
||||
in_init (const struct module *mod, uint64_t addr)
|
||||
{
|
||||
return addr - (uint64_t) mod->module_init < mod->init_size;
|
||||
return addr - (uint64_t) mod->init_layout.base < mod->init_layout.size;
|
||||
}
|
||||
|
||||
static inline int
|
||||
in_core (const struct module *mod, uint64_t addr)
|
||||
{
|
||||
return addr - (uint64_t) mod->module_core < mod->core_size;
|
||||
return addr - (uint64_t) mod->core_layout.base < mod->core_layout.size;
|
||||
}
|
||||
|
||||
static inline int
|
||||
@@ -675,7 +675,7 @@ do_reloc (struct module *mod, uint8_t r_type, Elf64_Sym *sym, uint64_t addend,
|
||||
break;
|
||||
|
||||
case RV_BDREL:
|
||||
val -= (uint64_t) (in_init(mod, val) ? mod->module_init : mod->module_core);
|
||||
val -= (uint64_t) (in_init(mod, val) ? mod->init_layout.base : mod->core_layout.base);
|
||||
break;
|
||||
|
||||
case RV_LTV:
|
||||
@@ -810,15 +810,15 @@ apply_relocate_add (Elf64_Shdr *sechdrs, const char *strtab, unsigned int symind
|
||||
* addresses have been selected...
|
||||
*/
|
||||
uint64_t gp;
|
||||
if (mod->core_size > MAX_LTOFF)
|
||||
if (mod->core_layout.size > MAX_LTOFF)
|
||||
/*
|
||||
* This takes advantage of fact that SHF_ARCH_SMALL gets allocated
|
||||
* at the end of the module.
|
||||
*/
|
||||
gp = mod->core_size - MAX_LTOFF / 2;
|
||||
gp = mod->core_layout.size - MAX_LTOFF / 2;
|
||||
else
|
||||
gp = mod->core_size / 2;
|
||||
gp = (uint64_t) mod->module_core + ((gp + 7) & -8);
|
||||
gp = mod->core_layout.size / 2;
|
||||
gp = (uint64_t) mod->core_layout.base + ((gp + 7) & -8);
|
||||
mod->arch.gp = gp;
|
||||
DEBUGP("%s: placing gp at 0x%lx\n", __func__, gp);
|
||||
}
|
||||
|
||||
@@ -176,8 +176,8 @@ static uint32_t do_plt_call(void *location, Elf32_Addr val,
|
||||
tramp[1] = 0xac000001 | ((val & 0x0000ffff) << 3);
|
||||
|
||||
/* Init, or core PLT? */
|
||||
if (location >= mod->module_core
|
||||
&& location < mod->module_core + mod->core_size)
|
||||
if (location >= mod->core_layout.base
|
||||
&& location < mod->core_layout.base + mod->core_layout.size)
|
||||
entry = (void *)sechdrs[mod->arch.core_plt_section].sh_addr;
|
||||
else
|
||||
entry = (void *)sechdrs[mod->arch.init_plt_section].sh_addr;
|
||||
|
||||
@@ -74,10 +74,7 @@ static inline int compute_return_epc(struct pt_regs *regs)
|
||||
return __microMIPS_compute_return_epc(regs);
|
||||
if (cpu_has_mips16)
|
||||
return __MIPS16e_compute_return_epc(regs);
|
||||
return regs->cp0_epc;
|
||||
}
|
||||
|
||||
if (!delay_slot(regs)) {
|
||||
} else if (!delay_slot(regs)) {
|
||||
regs->cp0_epc += 4;
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -399,7 +399,7 @@ int __MIPS16e_compute_return_epc(struct pt_regs *regs)
|
||||
*
|
||||
* @regs: Pointer to pt_regs
|
||||
* @insn: branch instruction to decode
|
||||
* @returns: -EFAULT on error and forces SIGBUS, and on success
|
||||
* @returns: -EFAULT on error and forces SIGILL, and on success
|
||||
* returns 0 or BRANCH_LIKELY_TAKEN as appropriate after
|
||||
* evaluating the branch.
|
||||
*
|
||||
@@ -431,7 +431,7 @@ int __compute_return_epc_for_insn(struct pt_regs *regs,
|
||||
/* Fall through */
|
||||
case jr_op:
|
||||
if (NO_R6EMU && insn.r_format.func == jr_op)
|
||||
goto sigill_r6;
|
||||
goto sigill_r2r6;
|
||||
regs->cp0_epc = regs->regs[insn.r_format.rs];
|
||||
break;
|
||||
}
|
||||
@@ -446,7 +446,7 @@ int __compute_return_epc_for_insn(struct pt_regs *regs,
|
||||
switch (insn.i_format.rt) {
|
||||
case bltzl_op:
|
||||
if (NO_R6EMU)
|
||||
goto sigill_r6;
|
||||
goto sigill_r2r6;
|
||||
case bltz_op:
|
||||
if ((long)regs->regs[insn.i_format.rs] < 0) {
|
||||
epc = epc + 4 + (insn.i_format.simmediate << 2);
|
||||
@@ -459,7 +459,7 @@ int __compute_return_epc_for_insn(struct pt_regs *regs,
|
||||
|
||||
case bgezl_op:
|
||||
if (NO_R6EMU)
|
||||
goto sigill_r6;
|
||||
goto sigill_r2r6;
|
||||
case bgez_op:
|
||||
if ((long)regs->regs[insn.i_format.rs] >= 0) {
|
||||
epc = epc + 4 + (insn.i_format.simmediate << 2);
|
||||
@@ -473,10 +473,8 @@ int __compute_return_epc_for_insn(struct pt_regs *regs,
|
||||
case bltzal_op:
|
||||
case bltzall_op:
|
||||
if (NO_R6EMU && (insn.i_format.rs ||
|
||||
insn.i_format.rt == bltzall_op)) {
|
||||
ret = -SIGILL;
|
||||
break;
|
||||
}
|
||||
insn.i_format.rt == bltzall_op))
|
||||
goto sigill_r2r6;
|
||||
regs->regs[31] = epc + 8;
|
||||
/*
|
||||
* OK we are here either because we hit a NAL
|
||||
@@ -507,10 +505,8 @@ int __compute_return_epc_for_insn(struct pt_regs *regs,
|
||||
case bgezal_op:
|
||||
case bgezall_op:
|
||||
if (NO_R6EMU && (insn.i_format.rs ||
|
||||
insn.i_format.rt == bgezall_op)) {
|
||||
ret = -SIGILL;
|
||||
break;
|
||||
}
|
||||
insn.i_format.rt == bgezall_op))
|
||||
goto sigill_r2r6;
|
||||
regs->regs[31] = epc + 8;
|
||||
/*
|
||||
* OK we are here either because we hit a BAL
|
||||
@@ -556,6 +552,7 @@ int __compute_return_epc_for_insn(struct pt_regs *regs,
|
||||
/*
|
||||
* These are unconditional and in j_format.
|
||||
*/
|
||||
case jalx_op:
|
||||
case jal_op:
|
||||
regs->regs[31] = regs->cp0_epc + 8;
|
||||
case j_op:
|
||||
@@ -573,7 +570,7 @@ int __compute_return_epc_for_insn(struct pt_regs *regs,
|
||||
*/
|
||||
case beql_op:
|
||||
if (NO_R6EMU)
|
||||
goto sigill_r6;
|
||||
goto sigill_r2r6;
|
||||
case beq_op:
|
||||
if (regs->regs[insn.i_format.rs] ==
|
||||
regs->regs[insn.i_format.rt]) {
|
||||
@@ -587,7 +584,7 @@ int __compute_return_epc_for_insn(struct pt_regs *regs,
|
||||
|
||||
case bnel_op:
|
||||
if (NO_R6EMU)
|
||||
goto sigill_r6;
|
||||
goto sigill_r2r6;
|
||||
case bne_op:
|
||||
if (regs->regs[insn.i_format.rs] !=
|
||||
regs->regs[insn.i_format.rt]) {
|
||||
@@ -601,7 +598,7 @@ int __compute_return_epc_for_insn(struct pt_regs *regs,
|
||||
|
||||
case blezl_op: /* not really i_format */
|
||||
if (!insn.i_format.rt && NO_R6EMU)
|
||||
goto sigill_r6;
|
||||
goto sigill_r2r6;
|
||||
case blez_op:
|
||||
/*
|
||||
* Compact branches for R6 for the
|
||||
@@ -636,7 +633,7 @@ int __compute_return_epc_for_insn(struct pt_regs *regs,
|
||||
|
||||
case bgtzl_op:
|
||||
if (!insn.i_format.rt && NO_R6EMU)
|
||||
goto sigill_r6;
|
||||
goto sigill_r2r6;
|
||||
case bgtz_op:
|
||||
/*
|
||||
* Compact branches for R6 for the
|
||||
@@ -843,11 +840,12 @@ int __compute_return_epc_for_insn(struct pt_regs *regs,
|
||||
return ret;
|
||||
|
||||
sigill_dsp:
|
||||
printk("%s: DSP branch but not DSP ASE - sending SIGBUS.\n", current->comm);
|
||||
force_sig(SIGBUS, current);
|
||||
pr_info("%s: DSP branch but not DSP ASE - sending SIGILL.\n",
|
||||
current->comm);
|
||||
force_sig(SIGILL, current);
|
||||
return -EFAULT;
|
||||
sigill_r6:
|
||||
pr_info("%s: R2 branch but r2-to-r6 emulator is not preset - sending SIGILL.\n",
|
||||
sigill_r2r6:
|
||||
pr_info("%s: R2 branch but r2-to-r6 emulator is not present - sending SIGILL.\n",
|
||||
current->comm);
|
||||
force_sig(SIGILL, current);
|
||||
return -EFAULT;
|
||||
|
||||
@@ -83,7 +83,7 @@ static int show_cpuinfo(struct seq_file *m, void *v)
|
||||
}
|
||||
|
||||
seq_printf(m, "isa\t\t\t:");
|
||||
if (cpu_has_mips_r1)
|
||||
if (cpu_has_mips_1)
|
||||
seq_printf(m, " mips1");
|
||||
if (cpu_has_mips_2)
|
||||
seq_printf(m, "%s", " mips2");
|
||||
|
||||
@@ -927,7 +927,7 @@ asmlinkage void syscall_trace_leave(struct pt_regs *regs)
|
||||
audit_syscall_exit(regs);
|
||||
|
||||
if (unlikely(test_thread_flag(TIF_SYSCALL_TRACEPOINT)))
|
||||
trace_sys_exit(regs, regs->regs[2]);
|
||||
trace_sys_exit(regs, regs_return_value(regs));
|
||||
|
||||
if (test_thread_flag(TIF_SYSCALL_TRACE))
|
||||
tracehook_report_syscall_exit(regs, 0);
|
||||
|
||||
@@ -372,7 +372,7 @@ EXPORT(sys_call_table)
|
||||
PTR sys_writev
|
||||
PTR sys_cacheflush
|
||||
PTR sys_cachectl
|
||||
PTR sys_sysmips
|
||||
PTR __sys_sysmips
|
||||
PTR sys_ni_syscall /* 4150 */
|
||||
PTR sys_getsid
|
||||
PTR sys_fdatasync
|
||||
|
||||
@@ -312,7 +312,7 @@ EXPORT(sys_call_table)
|
||||
PTR sys_sched_getaffinity
|
||||
PTR sys_cacheflush
|
||||
PTR sys_cachectl
|
||||
PTR sys_sysmips
|
||||
PTR __sys_sysmips
|
||||
PTR sys_io_setup /* 5200 */
|
||||
PTR sys_io_destroy
|
||||
PTR sys_io_getevents
|
||||
|
||||
@@ -298,7 +298,7 @@ EXPORT(sysn32_call_table)
|
||||
PTR compat_sys_sched_getaffinity
|
||||
PTR sys_cacheflush
|
||||
PTR sys_cachectl
|
||||
PTR sys_sysmips
|
||||
PTR __sys_sysmips
|
||||
PTR compat_sys_io_setup /* 6200 */
|
||||
PTR sys_io_destroy
|
||||
PTR compat_sys_io_getevents
|
||||
|
||||
@@ -367,7 +367,7 @@ EXPORT(sys32_call_table)
|
||||
PTR compat_sys_writev
|
||||
PTR sys_cacheflush
|
||||
PTR sys_cachectl
|
||||
PTR sys_sysmips
|
||||
PTR __sys_sysmips
|
||||
PTR sys_ni_syscall /* 4150 */
|
||||
PTR sys_getsid
|
||||
PTR sys_fdatasync
|
||||
|
||||
@@ -28,6 +28,7 @@
|
||||
#include <linux/elf.h>
|
||||
|
||||
#include <asm/asm.h>
|
||||
#include <asm/asm-eva.h>
|
||||
#include <asm/branch.h>
|
||||
#include <asm/cachectl.h>
|
||||
#include <asm/cacheflush.h>
|
||||
@@ -138,10 +139,12 @@ static inline int mips_atomic_set(unsigned long addr, unsigned long new)
|
||||
__asm__ __volatile__ (
|
||||
" .set "MIPS_ISA_ARCH_LEVEL" \n"
|
||||
" li %[err], 0 \n"
|
||||
"1: ll %[old], (%[addr]) \n"
|
||||
"1: \n"
|
||||
user_ll("%[old]", "(%[addr])")
|
||||
" move %[tmp], %[new] \n"
|
||||
"2: sc %[tmp], (%[addr]) \n"
|
||||
" bnez %[tmp], 4f \n"
|
||||
"2: \n"
|
||||
user_sc("%[tmp]", "(%[addr])")
|
||||
" beqz %[tmp], 4f \n"
|
||||
"3: \n"
|
||||
" .insn \n"
|
||||
" .subsection 2 \n"
|
||||
@@ -199,6 +202,12 @@ static inline int mips_atomic_set(unsigned long addr, unsigned long new)
|
||||
unreachable();
|
||||
}
|
||||
|
||||
/*
|
||||
* mips_atomic_set() normally returns directly via syscall_exit potentially
|
||||
* clobbering static registers, so be sure to preserve them.
|
||||
*/
|
||||
save_static_function(sys_sysmips);
|
||||
|
||||
SYSCALL_DEFINE3(sysmips, long, cmd, long, arg1, long, arg2)
|
||||
{
|
||||
switch (cmd) {
|
||||
|
||||
@@ -205,11 +205,11 @@ static void layout_sections(struct module *mod, const Elf_Ehdr *hdr,
|
||||
|| s->sh_entsize != ~0UL)
|
||||
continue;
|
||||
s->sh_entsize =
|
||||
get_offset((unsigned long *)&mod->core_size, s);
|
||||
get_offset((unsigned long *)&mod->core_layout.size, s);
|
||||
}
|
||||
|
||||
if (m == 0)
|
||||
mod->core_text_size = mod->core_size;
|
||||
mod->core_layout.text_size = mod->core_layout.size;
|
||||
|
||||
}
|
||||
}
|
||||
@@ -641,7 +641,7 @@ static int vpe_elfload(struct vpe *v)
|
||||
layout_sections(&mod, hdr, sechdrs, secstrings);
|
||||
}
|
||||
|
||||
v->load_addr = alloc_progmem(mod.core_size);
|
||||
v->load_addr = alloc_progmem(mod.core_layout.size);
|
||||
if (!v->load_addr)
|
||||
return -ENOMEM;
|
||||
|
||||
|
||||
@@ -2496,6 +2496,35 @@ dcopuop:
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Emulate FPU instructions.
|
||||
*
|
||||
* If we use FPU hardware, then we have been typically called to handle
|
||||
* an unimplemented operation, such as where an operand is a NaN or
|
||||
* denormalized. In that case exit the emulation loop after a single
|
||||
* iteration so as to let hardware execute any subsequent instructions.
|
||||
*
|
||||
* If we have no FPU hardware or it has been disabled, then continue
|
||||
* emulating floating-point instructions until one of these conditions
|
||||
* has occurred:
|
||||
*
|
||||
* - a non-FPU instruction has been encountered,
|
||||
*
|
||||
* - an attempt to emulate has ended with a signal,
|
||||
*
|
||||
* - the ISA mode has been switched.
|
||||
*
|
||||
* We need to terminate the emulation loop if we got switched to the
|
||||
* MIPS16 mode, whether supported or not, so that we do not attempt
|
||||
* to emulate a MIPS16 instruction as a regular MIPS FPU instruction.
|
||||
* Similarly if we got switched to the microMIPS mode and only the
|
||||
* regular MIPS mode is supported, so that we do not attempt to emulate
|
||||
* a microMIPS instruction as a regular MIPS FPU instruction. Or if
|
||||
* we got switched to the regular MIPS mode and only the microMIPS mode
|
||||
* is supported, so that we do not attempt to emulate a regular MIPS
|
||||
* instruction that should cause an Address Error exception instead.
|
||||
* For simplicity we always terminate upon an ISA mode switch.
|
||||
*/
|
||||
int fpu_emulator_cop1Handler(struct pt_regs *xcp, struct mips_fpu_struct *ctx,
|
||||
int has_fpu, void *__user *fault_addr)
|
||||
{
|
||||
@@ -2581,6 +2610,15 @@ int fpu_emulator_cop1Handler(struct pt_regs *xcp, struct mips_fpu_struct *ctx,
|
||||
break;
|
||||
if (sig)
|
||||
break;
|
||||
/*
|
||||
* We have to check for the ISA bit explicitly here,
|
||||
* because `get_isa16_mode' may return 0 if support
|
||||
* for code compression has been globally disabled,
|
||||
* or otherwise we may produce the wrong signal or
|
||||
* even proceed successfully where we must not.
|
||||
*/
|
||||
if ((xcp->cp0_epc ^ prevepc) & 0x1)
|
||||
break;
|
||||
|
||||
cond_resched();
|
||||
} while (xcp->cp0_epc > prevepc);
|
||||
|
||||
@@ -115,7 +115,7 @@ static inline unsigned long current_stack_pointer(void)
|
||||
}
|
||||
|
||||
#ifndef CONFIG_KGDB
|
||||
void arch_release_thread_info(struct thread_info *ti);
|
||||
void arch_release_thread_stack(unsigned long *stack);
|
||||
#endif
|
||||
#define get_thread_info(ti) get_task_struct((ti)->task)
|
||||
#define put_thread_info(ti) put_task_struct((ti)->task)
|
||||
|
||||
@@ -397,8 +397,9 @@ static bool kgdb_arch_undo_singlestep(struct pt_regs *regs)
|
||||
* single-step state is cleared. At this point the breakpoints should have
|
||||
* been removed by __switch_to().
|
||||
*/
|
||||
void arch_release_thread_info(struct thread_info *ti)
|
||||
void arch_release_thread_stack(unsigned long *stack)
|
||||
{
|
||||
struct thread_info *ti = (void *)stack;
|
||||
if (kgdb_sstep_thread == ti) {
|
||||
kgdb_sstep_thread = NULL;
|
||||
|
||||
|
||||
@@ -38,6 +38,8 @@ SECTIONS
|
||||
/* Read-only sections, merged into text segment: */
|
||||
. = LOAD_BASE ;
|
||||
|
||||
_text = .;
|
||||
|
||||
/* _s_kernel_ro must be page aligned */
|
||||
. = ALIGN(PAGE_SIZE);
|
||||
_s_kernel_ro = .;
|
||||
|
||||
@@ -39,6 +39,8 @@ struct hppa_dma_ops {
|
||||
** flush/purge and allocate "regular" cacheable pages for everything.
|
||||
*/
|
||||
|
||||
#define DMA_ERROR_CODE (~(dma_addr_t)0)
|
||||
|
||||
#ifdef CONFIG_PA11
|
||||
extern struct hppa_dma_ops pcxl_dma_ops;
|
||||
extern struct hppa_dma_ops pcx_dma_ops;
|
||||
@@ -209,12 +211,13 @@ parisc_walk_tree(struct device *dev)
|
||||
break;
|
||||
}
|
||||
}
|
||||
BUG_ON(!dev->platform_data);
|
||||
return dev->platform_data;
|
||||
}
|
||||
|
||||
#define GET_IOC(dev) (HBA_DATA(parisc_walk_tree(dev))->iommu)
|
||||
|
||||
|
||||
#define GET_IOC(dev) ({ \
|
||||
void *__pdata = parisc_walk_tree(dev); \
|
||||
__pdata ? HBA_DATA(__pdata)->iommu : NULL; \
|
||||
})
|
||||
|
||||
#ifdef CONFIG_IOMMU_CCIO
|
||||
struct parisc_device;
|
||||
|
||||
@@ -49,15 +49,26 @@ static inline void load_context(mm_context_t context)
|
||||
mtctl(__space_to_prot(context), 8);
|
||||
}
|
||||
|
||||
static inline void switch_mm(struct mm_struct *prev, struct mm_struct *next, struct task_struct *tsk)
|
||||
static inline void switch_mm_irqs_off(struct mm_struct *prev,
|
||||
struct mm_struct *next, struct task_struct *tsk)
|
||||
{
|
||||
|
||||
if (prev != next) {
|
||||
mtctl(__pa(next->pgd), 25);
|
||||
load_context(next->context);
|
||||
}
|
||||
}
|
||||
|
||||
static inline void switch_mm(struct mm_struct *prev,
|
||||
struct mm_struct *next, struct task_struct *tsk)
|
||||
{
|
||||
unsigned long flags;
|
||||
|
||||
local_irq_save(flags);
|
||||
switch_mm_irqs_off(prev, next, tsk);
|
||||
local_irq_restore(flags);
|
||||
}
|
||||
#define switch_mm_irqs_off switch_mm_irqs_off
|
||||
|
||||
#define deactivate_mm(tsk,mm) do { } while (0)
|
||||
|
||||
static inline void activate_mm(struct mm_struct *prev, struct mm_struct *next)
|
||||
|
||||
@@ -42,9 +42,9 @@
|
||||
* We are not doing SEGREL32 handling correctly. According to the ABI, we
|
||||
* should do a value offset, like this:
|
||||
* if (in_init(me, (void *)val))
|
||||
* val -= (uint32_t)me->module_init;
|
||||
* val -= (uint32_t)me->init_layout.base;
|
||||
* else
|
||||
* val -= (uint32_t)me->module_core;
|
||||
* val -= (uint32_t)me->core_layout.base;
|
||||
* However, SEGREL32 is used only for PARISC unwind entries, and we want
|
||||
* those entries to have an absolute address, and not just an offset.
|
||||
*
|
||||
@@ -100,14 +100,14 @@
|
||||
* or init pieces the location is */
|
||||
static inline int in_init(struct module *me, void *loc)
|
||||
{
|
||||
return (loc >= me->module_init &&
|
||||
loc <= (me->module_init + me->init_size));
|
||||
return (loc >= me->init_layout.base &&
|
||||
loc <= (me->init_layout.base + me->init_layout.size));
|
||||
}
|
||||
|
||||
static inline int in_core(struct module *me, void *loc)
|
||||
{
|
||||
return (loc >= me->module_core &&
|
||||
loc <= (me->module_core + me->core_size));
|
||||
return (loc >= me->core_layout.base &&
|
||||
loc <= (me->core_layout.base + me->core_layout.size));
|
||||
}
|
||||
|
||||
static inline int in_local(struct module *me, void *loc)
|
||||
@@ -367,13 +367,13 @@ int module_frob_arch_sections(CONST Elf_Ehdr *hdr,
|
||||
}
|
||||
|
||||
/* align things a bit */
|
||||
me->core_size = ALIGN(me->core_size, 16);
|
||||
me->arch.got_offset = me->core_size;
|
||||
me->core_size += gots * sizeof(struct got_entry);
|
||||
me->core_layout.size = ALIGN(me->core_layout.size, 16);
|
||||
me->arch.got_offset = me->core_layout.size;
|
||||
me->core_layout.size += gots * sizeof(struct got_entry);
|
||||
|
||||
me->core_size = ALIGN(me->core_size, 16);
|
||||
me->arch.fdesc_offset = me->core_size;
|
||||
me->core_size += fdescs * sizeof(Elf_Fdesc);
|
||||
me->core_layout.size = ALIGN(me->core_layout.size, 16);
|
||||
me->arch.fdesc_offset = me->core_layout.size;
|
||||
me->core_layout.size += fdescs * sizeof(Elf_Fdesc);
|
||||
|
||||
me->arch.got_max = gots;
|
||||
me->arch.fdesc_max = fdescs;
|
||||
@@ -391,7 +391,7 @@ static Elf64_Word get_got(struct module *me, unsigned long value, long addend)
|
||||
|
||||
BUG_ON(value == 0);
|
||||
|
||||
got = me->module_core + me->arch.got_offset;
|
||||
got = me->core_layout.base + me->arch.got_offset;
|
||||
for (i = 0; got[i].addr; i++)
|
||||
if (got[i].addr == value)
|
||||
goto out;
|
||||
@@ -409,7 +409,7 @@ static Elf64_Word get_got(struct module *me, unsigned long value, long addend)
|
||||
#ifdef CONFIG_64BIT
|
||||
static Elf_Addr get_fdesc(struct module *me, unsigned long value)
|
||||
{
|
||||
Elf_Fdesc *fdesc = me->module_core + me->arch.fdesc_offset;
|
||||
Elf_Fdesc *fdesc = me->core_layout.base + me->arch.fdesc_offset;
|
||||
|
||||
if (!value) {
|
||||
printk(KERN_ERR "%s: zero OPD requested!\n", me->name);
|
||||
@@ -427,7 +427,7 @@ static Elf_Addr get_fdesc(struct module *me, unsigned long value)
|
||||
|
||||
/* Create new one */
|
||||
fdesc->addr = value;
|
||||
fdesc->gp = (Elf_Addr)me->module_core + me->arch.got_offset;
|
||||
fdesc->gp = (Elf_Addr)me->core_layout.base + me->arch.got_offset;
|
||||
return (Elf_Addr)fdesc;
|
||||
}
|
||||
#endif /* CONFIG_64BIT */
|
||||
@@ -839,7 +839,7 @@ register_unwind_table(struct module *me,
|
||||
|
||||
table = (unsigned char *)sechdrs[me->arch.unwind_section].sh_addr;
|
||||
end = table + sechdrs[me->arch.unwind_section].sh_size;
|
||||
gp = (Elf_Addr)me->module_core + me->arch.got_offset;
|
||||
gp = (Elf_Addr)me->core_layout.base + me->arch.got_offset;
|
||||
|
||||
DEBUGP("register_unwind_table(), sect = %d at 0x%p - 0x%p (gp=0x%lx)\n",
|
||||
me->arch.unwind_section, table, end, gp);
|
||||
|
||||
@@ -361,7 +361,7 @@
|
||||
ENTRY_SAME(ni_syscall) /* 263: reserved for vserver */
|
||||
ENTRY_SAME(add_key)
|
||||
ENTRY_SAME(request_key) /* 265 */
|
||||
ENTRY_SAME(keyctl)
|
||||
ENTRY_COMP(keyctl)
|
||||
ENTRY_SAME(ioprio_set)
|
||||
ENTRY_SAME(ioprio_get)
|
||||
ENTRY_SAME(inotify_init)
|
||||
|
||||
@@ -298,7 +298,7 @@ bad_area:
|
||||
case 15: /* Data TLB miss fault/Data page fault */
|
||||
/* send SIGSEGV when outside of vma */
|
||||
if (!vma ||
|
||||
address < vma->vm_start || address > vma->vm_end) {
|
||||
address < vma->vm_start || address >= vma->vm_end) {
|
||||
si.si_signo = SIGSEGV;
|
||||
si.si_code = SEGV_MAPERR;
|
||||
break;
|
||||
|
||||
@@ -460,7 +460,7 @@ static __inline__ int atomic64_add_unless(atomic64_t *v, long a, long u)
|
||||
* Atomically increments @v by 1, so long as @v is non-zero.
|
||||
* Returns non-zero if @v was non-zero, and zero otherwise.
|
||||
*/
|
||||
static __inline__ long atomic64_inc_not_zero(atomic64_t *v)
|
||||
static __inline__ int atomic64_inc_not_zero(atomic64_t *v)
|
||||
{
|
||||
long t1, t2;
|
||||
|
||||
@@ -479,7 +479,7 @@ static __inline__ long atomic64_inc_not_zero(atomic64_t *v)
|
||||
: "r" (&v->counter)
|
||||
: "cc", "xer", "memory");
|
||||
|
||||
return t1;
|
||||
return t1 != 0;
|
||||
}
|
||||
|
||||
#endif /* __powerpc64__ */
|
||||
|
||||
@@ -23,12 +23,13 @@
|
||||
#define CORE_DUMP_USE_REGSET
|
||||
#define ELF_EXEC_PAGESIZE PAGE_SIZE
|
||||
|
||||
/* This is the location that an ET_DYN program is loaded if exec'ed. Typical
|
||||
use of this is to invoke "./ld.so someprog" to test out a new version of
|
||||
the loader. We need to make sure that it is out of the way of the program
|
||||
that it will "exec", and that there is sufficient room for the brk. */
|
||||
|
||||
#define ELF_ET_DYN_BASE 0x20000000
|
||||
/*
|
||||
* This is the base location for PIE (ET_DYN with INTERP) loads. On
|
||||
* 64-bit, this is raised to 4GB to leave the entire 32-bit address
|
||||
* space open for things that want to use the area for 32-bit pointers.
|
||||
*/
|
||||
#define ELF_ET_DYN_BASE (is_32bit_task() ? 0x000400000UL : \
|
||||
0x100000000UL)
|
||||
|
||||
#define ELF_CORE_EFLAGS (is_elf2_task() ? 2 : 0)
|
||||
|
||||
|
||||
@@ -1236,7 +1236,7 @@ static inline unsigned long mfvtb (void)
|
||||
" .llong 0\n" \
|
||||
".previous" \
|
||||
: "=r" (rval) \
|
||||
: "i" (CPU_FTR_CELL_TB_BUG), "i" (SPRN_TBRL)); \
|
||||
: "i" (CPU_FTR_CELL_TB_BUG), "i" (SPRN_TBRL) : "cr0"); \
|
||||
rval;})
|
||||
#else
|
||||
#define mftb() ({unsigned long rval; \
|
||||
|
||||
@@ -44,22 +44,8 @@ extern void __init dump_numa_cpu_topology(void);
|
||||
extern int sysfs_add_device_to_node(struct device *dev, int nid);
|
||||
extern void sysfs_remove_device_from_node(struct device *dev, int nid);
|
||||
|
||||
static inline int early_cpu_to_node(int cpu)
|
||||
{
|
||||
int nid;
|
||||
|
||||
nid = numa_cpu_lookup_table[cpu];
|
||||
|
||||
/*
|
||||
* Fall back to node 0 if nid is unset (it should be, except bugs).
|
||||
* This allows callers to safely do NODE_DATA(early_cpu_to_node(cpu)).
|
||||
*/
|
||||
return (nid < 0) ? 0 : nid;
|
||||
}
|
||||
#else
|
||||
|
||||
static inline int early_cpu_to_node(int cpu) { return 0; }
|
||||
|
||||
static inline void dump_numa_cpu_topology(void) {}
|
||||
|
||||
static inline int sysfs_add_device_to_node(struct device *dev, int nid)
|
||||
|
||||
@@ -188,8 +188,8 @@ static uint32_t do_plt_call(void *location,
|
||||
|
||||
pr_debug("Doing plt for call to 0x%x at 0x%x\n", val, (unsigned int)location);
|
||||
/* Init, or core PLT? */
|
||||
if (location >= mod->module_core
|
||||
&& location < mod->module_core + mod->core_size)
|
||||
if (location >= mod->core_layout.base
|
||||
&& location < mod->core_layout.base + mod->core_layout.size)
|
||||
entry = (void *)sechdrs[mod->arch.core_plt_section].sh_addr;
|
||||
else
|
||||
entry = (void *)sechdrs[mod->arch.init_plt_section].sh_addr;
|
||||
@@ -296,7 +296,7 @@ int apply_relocate_add(Elf32_Shdr *sechdrs,
|
||||
}
|
||||
#ifdef CONFIG_DYNAMIC_FTRACE
|
||||
module->arch.tramp =
|
||||
do_plt_call(module->module_core,
|
||||
do_plt_call(module->core_layout.base,
|
||||
(unsigned long)ftrace_caller,
|
||||
sechdrs, module);
|
||||
#endif
|
||||
|
||||
@@ -751,7 +751,7 @@ void __init setup_arch(char **cmdline_p)
|
||||
|
||||
static void * __init pcpu_fc_alloc(unsigned int cpu, size_t size, size_t align)
|
||||
{
|
||||
return __alloc_bootmem_node(NODE_DATA(early_cpu_to_node(cpu)), size, align,
|
||||
return __alloc_bootmem_node(NODE_DATA(cpu_to_node(cpu)), size, align,
|
||||
__pa(MAX_DMA_ADDRESS));
|
||||
}
|
||||
|
||||
@@ -762,7 +762,7 @@ static void __init pcpu_fc_free(void *ptr, size_t size)
|
||||
|
||||
static int pcpu_cpu_distance(unsigned int from, unsigned int to)
|
||||
{
|
||||
if (early_cpu_to_node(from) == early_cpu_to_node(to))
|
||||
if (cpu_to_node(from) == cpu_to_node(to))
|
||||
return LOCAL_DISTANCE;
|
||||
else
|
||||
return REMOTE_DISTANCE;
|
||||
|
||||
@@ -2687,6 +2687,10 @@ static int kvmppc_vcpu_run_hv(struct kvm_run *run, struct kvm_vcpu *vcpu)
|
||||
{
|
||||
int r;
|
||||
int srcu_idx;
|
||||
unsigned long ebb_regs[3] = {}; /* shut up GCC */
|
||||
unsigned long user_tar = 0;
|
||||
unsigned long proc_fscr = 0;
|
||||
unsigned int user_vrsave;
|
||||
|
||||
if (!vcpu->arch.sane) {
|
||||
run->exit_reason = KVM_EXIT_INTERNAL_ERROR;
|
||||
@@ -2707,10 +2711,11 @@ static int kvmppc_vcpu_run_hv(struct kvm_run *run, struct kvm_vcpu *vcpu)
|
||||
run->fail_entry.hardware_entry_failure_reason = 0;
|
||||
return -EINVAL;
|
||||
}
|
||||
/* Enable TM so we can read the TM SPRs */
|
||||
mtmsr(mfmsr() | MSR_TM);
|
||||
current->thread.tm_tfhar = mfspr(SPRN_TFHAR);
|
||||
current->thread.tm_tfiar = mfspr(SPRN_TFIAR);
|
||||
current->thread.tm_texasr = mfspr(SPRN_TEXASR);
|
||||
current->thread.regs->msr &= ~MSR_TM;
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -2736,6 +2741,17 @@ static int kvmppc_vcpu_run_hv(struct kvm_run *run, struct kvm_vcpu *vcpu)
|
||||
flush_fp_to_thread(current);
|
||||
flush_altivec_to_thread(current);
|
||||
flush_vsx_to_thread(current);
|
||||
|
||||
/* Save userspace EBB and other register values */
|
||||
if (cpu_has_feature(CPU_FTR_ARCH_207S)) {
|
||||
ebb_regs[0] = mfspr(SPRN_EBBHR);
|
||||
ebb_regs[1] = mfspr(SPRN_EBBRR);
|
||||
ebb_regs[2] = mfspr(SPRN_BESCR);
|
||||
user_tar = mfspr(SPRN_TAR);
|
||||
proc_fscr = mfspr(SPRN_FSCR);
|
||||
}
|
||||
user_vrsave = mfspr(SPRN_VRSAVE);
|
||||
|
||||
vcpu->arch.wqp = &vcpu->arch.vcore->wq;
|
||||
vcpu->arch.pgdir = current->mm->pgd;
|
||||
vcpu->arch.state = KVMPPC_VCPU_BUSY_IN_HOST;
|
||||
@@ -2757,6 +2773,29 @@ static int kvmppc_vcpu_run_hv(struct kvm_run *run, struct kvm_vcpu *vcpu)
|
||||
}
|
||||
} while (is_kvmppc_resume_guest(r));
|
||||
|
||||
/* Restore userspace EBB and other register values */
|
||||
if (cpu_has_feature(CPU_FTR_ARCH_207S)) {
|
||||
mtspr(SPRN_EBBHR, ebb_regs[0]);
|
||||
mtspr(SPRN_EBBRR, ebb_regs[1]);
|
||||
mtspr(SPRN_BESCR, ebb_regs[2]);
|
||||
mtspr(SPRN_TAR, user_tar);
|
||||
mtspr(SPRN_FSCR, proc_fscr);
|
||||
}
|
||||
mtspr(SPRN_VRSAVE, user_vrsave);
|
||||
|
||||
/*
|
||||
* Since we don't do lazy TM reload, we need to reload
|
||||
* the TM registers here.
|
||||
*/
|
||||
#ifdef CONFIG_PPC_TRANSACTIONAL_MEM
|
||||
if (cpu_has_feature(CPU_FTR_TM) && current->thread.regs &&
|
||||
(current->thread.regs->msr & MSR_TM)) {
|
||||
mtspr(SPRN_TFHAR, current->thread.tm_tfhar);
|
||||
mtspr(SPRN_TFIAR, current->thread.tm_tfiar);
|
||||
mtspr(SPRN_TEXASR, current->thread.tm_texasr);
|
||||
}
|
||||
#endif
|
||||
|
||||
out:
|
||||
vcpu->arch.state = KVMPPC_VCPU_NOTREADY;
|
||||
atomic_dec(&vcpu->kvm->arch.vcpus_running);
|
||||
|
||||
@@ -36,6 +36,13 @@
|
||||
#define NAPPING_CEDE 1
|
||||
#define NAPPING_NOVCPU 2
|
||||
|
||||
/* Stack frame offsets for kvmppc_hv_entry */
|
||||
#define SFS 112
|
||||
#define STACK_SLOT_TRAP (SFS-4)
|
||||
#define STACK_SLOT_CIABR (SFS-16)
|
||||
#define STACK_SLOT_DAWR (SFS-24)
|
||||
#define STACK_SLOT_DAWRX (SFS-32)
|
||||
|
||||
/*
|
||||
* Call kvmppc_hv_entry in real mode.
|
||||
* Must be called with interrupts hard-disabled.
|
||||
@@ -274,10 +281,10 @@ kvm_novcpu_exit:
|
||||
bl kvmhv_accumulate_time
|
||||
#endif
|
||||
13: mr r3, r12
|
||||
stw r12, 112-4(r1)
|
||||
stw r12, STACK_SLOT_TRAP(r1)
|
||||
bl kvmhv_commence_exit
|
||||
nop
|
||||
lwz r12, 112-4(r1)
|
||||
lwz r12, STACK_SLOT_TRAP(r1)
|
||||
b kvmhv_switch_to_host
|
||||
|
||||
/*
|
||||
@@ -489,7 +496,7 @@ kvmppc_hv_entry:
|
||||
*/
|
||||
mflr r0
|
||||
std r0, PPC_LR_STKOFF(r1)
|
||||
stdu r1, -112(r1)
|
||||
stdu r1, -SFS(r1)
|
||||
|
||||
/* Save R1 in the PACA */
|
||||
std r1, HSTATE_HOST_R1(r13)
|
||||
@@ -643,6 +650,16 @@ kvmppc_got_guest:
|
||||
mtspr SPRN_PURR,r7
|
||||
mtspr SPRN_SPURR,r8
|
||||
|
||||
/* Save host values of some registers */
|
||||
BEGIN_FTR_SECTION
|
||||
mfspr r5, SPRN_CIABR
|
||||
mfspr r6, SPRN_DAWR
|
||||
mfspr r7, SPRN_DAWRX
|
||||
std r5, STACK_SLOT_CIABR(r1)
|
||||
std r6, STACK_SLOT_DAWR(r1)
|
||||
std r7, STACK_SLOT_DAWRX(r1)
|
||||
END_FTR_SECTION_IFSET(CPU_FTR_ARCH_207S)
|
||||
|
||||
BEGIN_FTR_SECTION
|
||||
/* Set partition DABR */
|
||||
/* Do this before re-enabling PMU to avoid P7 DABR corruption bug */
|
||||
@@ -1266,8 +1283,7 @@ END_FTR_SECTION_IFCLR(CPU_FTR_ARCH_207S)
|
||||
*/
|
||||
li r0, 0
|
||||
mtspr SPRN_IAMR, r0
|
||||
mtspr SPRN_CIABR, r0
|
||||
mtspr SPRN_DAWRX, r0
|
||||
mtspr SPRN_PSPB, r0
|
||||
mtspr SPRN_TCSCR, r0
|
||||
mtspr SPRN_WORT, r0
|
||||
/* Set MMCRS to 1<<31 to freeze and disable the SPMC counters */
|
||||
@@ -1283,6 +1299,7 @@ END_FTR_SECTION_IFCLR(CPU_FTR_ARCH_207S)
|
||||
std r6,VCPU_UAMOR(r9)
|
||||
li r6,0
|
||||
mtspr SPRN_AMR,r6
|
||||
mtspr SPRN_UAMOR, r6
|
||||
|
||||
/* Switch DSCR back to host value */
|
||||
mfspr r8, SPRN_DSCR
|
||||
@@ -1424,6 +1441,16 @@ END_FTR_SECTION_IFSET(CPU_FTR_ARCH_207S)
|
||||
slbia
|
||||
ptesync
|
||||
|
||||
/* Restore host values of some registers */
|
||||
BEGIN_FTR_SECTION
|
||||
ld r5, STACK_SLOT_CIABR(r1)
|
||||
ld r6, STACK_SLOT_DAWR(r1)
|
||||
ld r7, STACK_SLOT_DAWRX(r1)
|
||||
mtspr SPRN_CIABR, r5
|
||||
mtspr SPRN_DAWR, r6
|
||||
mtspr SPRN_DAWRX, r7
|
||||
END_FTR_SECTION_IFSET(CPU_FTR_ARCH_207S)
|
||||
|
||||
/*
|
||||
* POWER7/POWER8 guest -> host partition switch code.
|
||||
* We don't have to lock against tlbies but we do
|
||||
@@ -1533,8 +1560,8 @@ END_FTR_SECTION_IFSET(CPU_FTR_ARCH_207S)
|
||||
li r0, KVM_GUEST_MODE_NONE
|
||||
stb r0, HSTATE_IN_GUEST(r13)
|
||||
|
||||
ld r0, 112+PPC_LR_STKOFF(r1)
|
||||
addi r1, r1, 112
|
||||
ld r0, SFS+PPC_LR_STKOFF(r1)
|
||||
addi r1, r1, SFS
|
||||
mtlr r0
|
||||
blr
|
||||
|
||||
|
||||
@@ -687,8 +687,10 @@ int __kprobes analyse_instr(struct instruction_op *op, struct pt_regs *regs,
|
||||
case 19:
|
||||
switch ((instr >> 1) & 0x3ff) {
|
||||
case 0: /* mcrf */
|
||||
rd = (instr >> 21) & 0x1c;
|
||||
ra = (instr >> 16) & 0x1c;
|
||||
rd = 7 - ((instr >> 23) & 0x7);
|
||||
ra = 7 - ((instr >> 18) & 0x7);
|
||||
rd *= 4;
|
||||
ra *= 4;
|
||||
val = (regs->ccr >> ra) & 0xf;
|
||||
regs->ccr = (regs->ccr & ~(0xfUL << rd)) | (val << rd);
|
||||
goto instr_done;
|
||||
@@ -967,6 +969,19 @@ int __kprobes analyse_instr(struct instruction_op *op, struct pt_regs *regs,
|
||||
#endif
|
||||
|
||||
case 19: /* mfcr */
|
||||
if ((instr >> 20) & 1) {
|
||||
imm = 0xf0000000UL;
|
||||
for (sh = 0; sh < 8; ++sh) {
|
||||
if (instr & (0x80000 >> sh)) {
|
||||
regs->gpr[rd] = regs->ccr & imm;
|
||||
break;
|
||||
}
|
||||
imm >>= 4;
|
||||
}
|
||||
|
||||
goto instr_done;
|
||||
}
|
||||
|
||||
regs->gpr[rd] = regs->ccr;
|
||||
regs->gpr[rd] &= 0xffffffffUL;
|
||||
goto instr_done;
|
||||
|
||||
@@ -82,7 +82,6 @@ static int pSeries_reconfig_remove_node(struct device_node *np)
|
||||
|
||||
of_detach_node(np);
|
||||
of_node_put(parent);
|
||||
of_node_put(np); /* Must decrement the refcount */
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
@@ -154,14 +154,13 @@ extern unsigned int vdso_enabled;
|
||||
#define CORE_DUMP_USE_REGSET
|
||||
#define ELF_EXEC_PAGESIZE 4096
|
||||
|
||||
/* This is the location that an ET_DYN program is loaded if exec'ed. Typical
|
||||
use of this is to invoke "./ld.so someprog" to test out a new version of
|
||||
the loader. We need to make sure that it is out of the way of the program
|
||||
that it will "exec", and that there is sufficient room for the brk. 64-bit
|
||||
tasks are aligned to 4GB. */
|
||||
#define ELF_ET_DYN_BASE (is_32bit_task() ? \
|
||||
(STACK_TOP / 3 * 2) : \
|
||||
(STACK_TOP / 3 * 2) & ~((1UL << 32) - 1))
|
||||
/*
|
||||
* This is the base location for PIE (ET_DYN with INTERP) loads. On
|
||||
* 64-bit, this is raised to 4GB to leave the entire 32-bit address
|
||||
* space open for things that want to use the area for 32-bit pointers.
|
||||
*/
|
||||
#define ELF_ET_DYN_BASE (is_compat_task() ? 0x000400000UL : \
|
||||
0x100000000UL)
|
||||
|
||||
/* This yields a mask that user programs can use to figure out what
|
||||
instruction set this CPU supports. */
|
||||
|
||||
@@ -64,6 +64,12 @@ static inline void syscall_get_arguments(struct task_struct *task,
|
||||
{
|
||||
unsigned long mask = -1UL;
|
||||
|
||||
/*
|
||||
* No arguments for this syscall, there's nothing to do.
|
||||
*/
|
||||
if (!n)
|
||||
return;
|
||||
|
||||
BUG_ON(i + n > 6);
|
||||
#ifdef CONFIG_COMPAT
|
||||
if (test_tsk_thread_flag(task, TIF_31BIT))
|
||||
|
||||
@@ -159,11 +159,11 @@ int module_frob_arch_sections(Elf_Ehdr *hdr, Elf_Shdr *sechdrs,
|
||||
|
||||
/* Increase core size by size of got & plt and set start
|
||||
offsets for got and plt. */
|
||||
me->core_size = ALIGN(me->core_size, 4);
|
||||
me->arch.got_offset = me->core_size;
|
||||
me->core_size += me->arch.got_size;
|
||||
me->arch.plt_offset = me->core_size;
|
||||
me->core_size += me->arch.plt_size;
|
||||
me->core_layout.size = ALIGN(me->core_layout.size, 4);
|
||||
me->arch.got_offset = me->core_layout.size;
|
||||
me->core_layout.size += me->arch.got_size;
|
||||
me->arch.plt_offset = me->core_layout.size;
|
||||
me->core_layout.size += me->arch.plt_size;
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -279,7 +279,7 @@ static int apply_rela(Elf_Rela *rela, Elf_Addr base, Elf_Sym *symtab,
|
||||
if (info->got_initialized == 0) {
|
||||
Elf_Addr *gotent;
|
||||
|
||||
gotent = me->module_core + me->arch.got_offset +
|
||||
gotent = me->core_layout.base + me->arch.got_offset +
|
||||
info->got_offset;
|
||||
*gotent = val;
|
||||
info->got_initialized = 1;
|
||||
@@ -302,7 +302,7 @@ static int apply_rela(Elf_Rela *rela, Elf_Addr base, Elf_Sym *symtab,
|
||||
rc = apply_rela_bits(loc, val, 0, 64, 0);
|
||||
else if (r_type == R_390_GOTENT ||
|
||||
r_type == R_390_GOTPLTENT) {
|
||||
val += (Elf_Addr) me->module_core - loc;
|
||||
val += (Elf_Addr) me->core_layout.base - loc;
|
||||
rc = apply_rela_bits(loc, val, 1, 32, 1);
|
||||
}
|
||||
break;
|
||||
@@ -315,7 +315,7 @@ static int apply_rela(Elf_Rela *rela, Elf_Addr base, Elf_Sym *symtab,
|
||||
case R_390_PLTOFF64: /* 16 bit offset from GOT to PLT. */
|
||||
if (info->plt_initialized == 0) {
|
||||
unsigned int *ip;
|
||||
ip = me->module_core + me->arch.plt_offset +
|
||||
ip = me->core_layout.base + me->arch.plt_offset +
|
||||
info->plt_offset;
|
||||
ip[0] = 0x0d10e310; /* basr 1,0; lg 1,10(1); br 1 */
|
||||
ip[1] = 0x100a0004;
|
||||
@@ -334,7 +334,7 @@ static int apply_rela(Elf_Rela *rela, Elf_Addr base, Elf_Sym *symtab,
|
||||
val - loc + 0xffffUL < 0x1ffffeUL) ||
|
||||
(r_type == R_390_PLT32DBL &&
|
||||
val - loc + 0xffffffffULL < 0x1fffffffeULL)))
|
||||
val = (Elf_Addr) me->module_core +
|
||||
val = (Elf_Addr) me->core_layout.base +
|
||||
me->arch.plt_offset +
|
||||
info->plt_offset;
|
||||
val += rela->r_addend - loc;
|
||||
@@ -356,7 +356,7 @@ static int apply_rela(Elf_Rela *rela, Elf_Addr base, Elf_Sym *symtab,
|
||||
case R_390_GOTOFF32: /* 32 bit offset to GOT. */
|
||||
case R_390_GOTOFF64: /* 64 bit offset to GOT. */
|
||||
val = val + rela->r_addend -
|
||||
((Elf_Addr) me->module_core + me->arch.got_offset);
|
||||
((Elf_Addr) me->core_layout.base + me->arch.got_offset);
|
||||
if (r_type == R_390_GOTOFF16)
|
||||
rc = apply_rela_bits(loc, val, 0, 16, 0);
|
||||
else if (r_type == R_390_GOTOFF32)
|
||||
@@ -366,7 +366,7 @@ static int apply_rela(Elf_Rela *rela, Elf_Addr base, Elf_Sym *symtab,
|
||||
break;
|
||||
case R_390_GOTPC: /* 32 bit PC relative offset to GOT. */
|
||||
case R_390_GOTPCDBL: /* 32 bit PC rel. off. to GOT shifted by 1. */
|
||||
val = (Elf_Addr) me->module_core + me->arch.got_offset +
|
||||
val = (Elf_Addr) me->core_layout.base + me->arch.got_offset +
|
||||
rela->r_addend - loc;
|
||||
if (r_type == R_390_GOTPC)
|
||||
rc = apply_rela_bits(loc, val, 1, 32, 0);
|
||||
|
||||
@@ -1250,7 +1250,8 @@ static int bpf_jit_prog(struct bpf_jit *jit, struct bpf_prog *fp)
|
||||
insn_count = bpf_jit_insn(jit, fp, i);
|
||||
if (insn_count < 0)
|
||||
return -1;
|
||||
jit->addrs[i + 1] = jit->prg; /* Next instruction address */
|
||||
/* Next instruction address */
|
||||
jit->addrs[i + insn_count] = jit->prg;
|
||||
}
|
||||
bpf_jit_epilogue(jit);
|
||||
|
||||
|
||||
@@ -25,9 +25,11 @@ void destroy_context(struct mm_struct *mm);
|
||||
void __tsb_context_switch(unsigned long pgd_pa,
|
||||
struct tsb_config *tsb_base,
|
||||
struct tsb_config *tsb_huge,
|
||||
unsigned long tsb_descr_pa);
|
||||
unsigned long tsb_descr_pa,
|
||||
unsigned long secondary_ctx);
|
||||
|
||||
static inline void tsb_context_switch(struct mm_struct *mm)
|
||||
static inline void tsb_context_switch_ctx(struct mm_struct *mm,
|
||||
unsigned long ctx)
|
||||
{
|
||||
__tsb_context_switch(__pa(mm->pgd),
|
||||
&mm->context.tsb_block[0],
|
||||
@@ -38,9 +40,12 @@ static inline void tsb_context_switch(struct mm_struct *mm)
|
||||
#else
|
||||
NULL
|
||||
#endif
|
||||
, __pa(&mm->context.tsb_descr[0]));
|
||||
, __pa(&mm->context.tsb_descr[0]),
|
||||
ctx);
|
||||
}
|
||||
|
||||
#define tsb_context_switch(X) tsb_context_switch_ctx(X, 0)
|
||||
|
||||
void tsb_grow(struct mm_struct *mm,
|
||||
unsigned long tsb_index,
|
||||
unsigned long mm_rss);
|
||||
@@ -110,8 +115,7 @@ static inline void switch_mm(struct mm_struct *old_mm, struct mm_struct *mm, str
|
||||
* cpu0 to update it's TSB because at that point the cpu_vm_mask
|
||||
* only had cpu1 set in it.
|
||||
*/
|
||||
load_secondary_context(mm);
|
||||
tsb_context_switch(mm);
|
||||
tsb_context_switch_ctx(mm, CTX_HWBITS(mm->context));
|
||||
|
||||
/* Any time a processor runs a context on an address space
|
||||
* for the first time, we must flush that context out of the
|
||||
|
||||
@@ -54,6 +54,7 @@ extern struct trap_per_cpu trap_block[NR_CPUS];
|
||||
void init_cur_cpu_trap(struct thread_info *);
|
||||
void setup_tba(void);
|
||||
extern int ncpus_probed;
|
||||
extern u64 cpu_mondo_counter[NR_CPUS];
|
||||
|
||||
unsigned long real_hard_smp_processor_id(void);
|
||||
|
||||
|
||||
@@ -617,22 +617,48 @@ retry:
|
||||
}
|
||||
}
|
||||
|
||||
/* Multi-cpu list version. */
|
||||
#define CPU_MONDO_COUNTER(cpuid) (cpu_mondo_counter[cpuid])
|
||||
#define MONDO_USEC_WAIT_MIN 2
|
||||
#define MONDO_USEC_WAIT_MAX 100
|
||||
#define MONDO_RETRY_LIMIT 500000
|
||||
|
||||
/* Multi-cpu list version.
|
||||
*
|
||||
* Deliver xcalls to 'cnt' number of cpus in 'cpu_list'.
|
||||
* Sometimes not all cpus receive the mondo, requiring us to re-send
|
||||
* the mondo until all cpus have received, or cpus are truly stuck
|
||||
* unable to receive mondo, and we timeout.
|
||||
* Occasionally a target cpu strand is borrowed briefly by hypervisor to
|
||||
* perform guest service, such as PCIe error handling. Consider the
|
||||
* service time, 1 second overall wait is reasonable for 1 cpu.
|
||||
* Here two in-between mondo check wait time are defined: 2 usec for
|
||||
* single cpu quick turn around and up to 100usec for large cpu count.
|
||||
* Deliver mondo to large number of cpus could take longer, we adjusts
|
||||
* the retry count as long as target cpus are making forward progress.
|
||||
*/
|
||||
static void hypervisor_xcall_deliver(struct trap_per_cpu *tb, int cnt)
|
||||
{
|
||||
int retries, this_cpu, prev_sent, i, saw_cpu_error;
|
||||
int this_cpu, tot_cpus, prev_sent, i, rem;
|
||||
int usec_wait, retries, tot_retries;
|
||||
u16 first_cpu = 0xffff;
|
||||
unsigned long xc_rcvd = 0;
|
||||
unsigned long status;
|
||||
int ecpuerror_id = 0;
|
||||
int enocpu_id = 0;
|
||||
u16 *cpu_list;
|
||||
u16 cpu;
|
||||
|
||||
this_cpu = smp_processor_id();
|
||||
|
||||
cpu_list = __va(tb->cpu_list_pa);
|
||||
|
||||
saw_cpu_error = 0;
|
||||
retries = 0;
|
||||
usec_wait = cnt * MONDO_USEC_WAIT_MIN;
|
||||
if (usec_wait > MONDO_USEC_WAIT_MAX)
|
||||
usec_wait = MONDO_USEC_WAIT_MAX;
|
||||
retries = tot_retries = 0;
|
||||
tot_cpus = cnt;
|
||||
prev_sent = 0;
|
||||
|
||||
do {
|
||||
int forward_progress, n_sent;
|
||||
int n_sent, mondo_delivered, target_cpu_busy;
|
||||
|
||||
status = sun4v_cpu_mondo_send(cnt,
|
||||
tb->cpu_list_pa,
|
||||
@@ -640,94 +666,113 @@ static void hypervisor_xcall_deliver(struct trap_per_cpu *tb, int cnt)
|
||||
|
||||
/* HV_EOK means all cpus received the xcall, we're done. */
|
||||
if (likely(status == HV_EOK))
|
||||
break;
|
||||
goto xcall_done;
|
||||
|
||||
/* If not these non-fatal errors, panic */
|
||||
if (unlikely((status != HV_EWOULDBLOCK) &&
|
||||
(status != HV_ECPUERROR) &&
|
||||
(status != HV_ENOCPU)))
|
||||
goto fatal_errors;
|
||||
|
||||
/* First, see if we made any forward progress.
|
||||
*
|
||||
* Go through the cpu_list, count the target cpus that have
|
||||
* received our mondo (n_sent), and those that did not (rem).
|
||||
* Re-pack cpu_list with the cpus remain to be retried in the
|
||||
* front - this simplifies tracking the truly stalled cpus.
|
||||
*
|
||||
* The hypervisor indicates successful sends by setting
|
||||
* cpu list entries to the value 0xffff.
|
||||
*
|
||||
* EWOULDBLOCK means some target cpus did not receive the
|
||||
* mondo and retry usually helps.
|
||||
*
|
||||
* ECPUERROR means at least one target cpu is in error state,
|
||||
* it's usually safe to skip the faulty cpu and retry.
|
||||
*
|
||||
* ENOCPU means one of the target cpu doesn't belong to the
|
||||
* domain, perhaps offlined which is unexpected, but not
|
||||
* fatal and it's okay to skip the offlined cpu.
|
||||
*/
|
||||
rem = 0;
|
||||
n_sent = 0;
|
||||
for (i = 0; i < cnt; i++) {
|
||||
if (likely(cpu_list[i] == 0xffff))
|
||||
cpu = cpu_list[i];
|
||||
if (likely(cpu == 0xffff)) {
|
||||
n_sent++;
|
||||
} else if ((status == HV_ECPUERROR) &&
|
||||
(sun4v_cpu_state(cpu) == HV_CPU_STATE_ERROR)) {
|
||||
ecpuerror_id = cpu + 1;
|
||||
} else if (status == HV_ENOCPU && !cpu_online(cpu)) {
|
||||
enocpu_id = cpu + 1;
|
||||
} else {
|
||||
cpu_list[rem++] = cpu;
|
||||
}
|
||||
}
|
||||
|
||||
forward_progress = 0;
|
||||
if (n_sent > prev_sent)
|
||||
forward_progress = 1;
|
||||
/* No cpu remained, we're done. */
|
||||
if (rem == 0)
|
||||
break;
|
||||
|
||||
/* Otherwise, update the cpu count for retry. */
|
||||
cnt = rem;
|
||||
|
||||
/* Record the overall number of mondos received by the
|
||||
* first of the remaining cpus.
|
||||
*/
|
||||
if (first_cpu != cpu_list[0]) {
|
||||
first_cpu = cpu_list[0];
|
||||
xc_rcvd = CPU_MONDO_COUNTER(first_cpu);
|
||||
}
|
||||
|
||||
/* Was any mondo delivered successfully? */
|
||||
mondo_delivered = (n_sent > prev_sent);
|
||||
prev_sent = n_sent;
|
||||
|
||||
/* If we get a HV_ECPUERROR, then one or more of the cpus
|
||||
* in the list are in error state. Use the cpu_state()
|
||||
* hypervisor call to find out which cpus are in error state.
|
||||
/* or, was any target cpu busy processing other mondos? */
|
||||
target_cpu_busy = (xc_rcvd < CPU_MONDO_COUNTER(first_cpu));
|
||||
xc_rcvd = CPU_MONDO_COUNTER(first_cpu);
|
||||
|
||||
/* Retry count is for no progress. If we're making progress,
|
||||
* reset the retry count.
|
||||
*/
|
||||
if (unlikely(status == HV_ECPUERROR)) {
|
||||
for (i = 0; i < cnt; i++) {
|
||||
long err;
|
||||
u16 cpu;
|
||||
|
||||
cpu = cpu_list[i];
|
||||
if (cpu == 0xffff)
|
||||
continue;
|
||||
|
||||
err = sun4v_cpu_state(cpu);
|
||||
if (err == HV_CPU_STATE_ERROR) {
|
||||
saw_cpu_error = (cpu + 1);
|
||||
cpu_list[i] = 0xffff;
|
||||
}
|
||||
}
|
||||
} else if (unlikely(status != HV_EWOULDBLOCK))
|
||||
goto fatal_mondo_error;
|
||||
|
||||
/* Don't bother rewriting the CPU list, just leave the
|
||||
* 0xffff and non-0xffff entries in there and the
|
||||
* hypervisor will do the right thing.
|
||||
*
|
||||
* Only advance timeout state if we didn't make any
|
||||
* forward progress.
|
||||
*/
|
||||
if (unlikely(!forward_progress)) {
|
||||
if (unlikely(++retries > 10000))
|
||||
goto fatal_mondo_timeout;
|
||||
|
||||
/* Delay a little bit to let other cpus catch up
|
||||
* on their cpu mondo queue work.
|
||||
*/
|
||||
udelay(2 * cnt);
|
||||
if (likely(mondo_delivered || target_cpu_busy)) {
|
||||
tot_retries += retries;
|
||||
retries = 0;
|
||||
} else if (unlikely(retries > MONDO_RETRY_LIMIT)) {
|
||||
goto fatal_mondo_timeout;
|
||||
}
|
||||
|
||||
/* Delay a little bit to let other cpus catch up on
|
||||
* their cpu mondo queue work.
|
||||
*/
|
||||
if (!mondo_delivered)
|
||||
udelay(usec_wait);
|
||||
|
||||
retries++;
|
||||
} while (1);
|
||||
|
||||
if (unlikely(saw_cpu_error))
|
||||
goto fatal_mondo_cpu_error;
|
||||
|
||||
xcall_done:
|
||||
if (unlikely(ecpuerror_id > 0)) {
|
||||
pr_crit("CPU[%d]: SUN4V mondo cpu error, target cpu(%d) was in error state\n",
|
||||
this_cpu, ecpuerror_id - 1);
|
||||
} else if (unlikely(enocpu_id > 0)) {
|
||||
pr_crit("CPU[%d]: SUN4V mondo cpu error, target cpu(%d) does not belong to the domain\n",
|
||||
this_cpu, enocpu_id - 1);
|
||||
}
|
||||
return;
|
||||
|
||||
fatal_mondo_cpu_error:
|
||||
printk(KERN_CRIT "CPU[%d]: SUN4V mondo cpu error, some target cpus "
|
||||
"(including %d) were in error state\n",
|
||||
this_cpu, saw_cpu_error - 1);
|
||||
return;
|
||||
fatal_errors:
|
||||
/* fatal errors include bad alignment, etc */
|
||||
pr_crit("CPU[%d]: Args were cnt(%d) cpulist_pa(%lx) mondo_block_pa(%lx)\n",
|
||||
this_cpu, tot_cpus, tb->cpu_list_pa, tb->cpu_mondo_block_pa);
|
||||
panic("Unexpected SUN4V mondo error %lu\n", status);
|
||||
|
||||
fatal_mondo_timeout:
|
||||
printk(KERN_CRIT "CPU[%d]: SUN4V mondo timeout, no forward "
|
||||
" progress after %d retries.\n",
|
||||
this_cpu, retries);
|
||||
goto dump_cpu_list_and_out;
|
||||
|
||||
fatal_mondo_error:
|
||||
printk(KERN_CRIT "CPU[%d]: Unexpected SUN4V mondo error %lu\n",
|
||||
this_cpu, status);
|
||||
printk(KERN_CRIT "CPU[%d]: Args were cnt(%d) cpulist_pa(%lx) "
|
||||
"mondo_block_pa(%lx)\n",
|
||||
this_cpu, cnt, tb->cpu_list_pa, tb->cpu_mondo_block_pa);
|
||||
|
||||
dump_cpu_list_and_out:
|
||||
printk(KERN_CRIT "CPU[%d]: CPU list [ ", this_cpu);
|
||||
for (i = 0; i < cnt; i++)
|
||||
printk("%u ", cpu_list[i]);
|
||||
printk("]\n");
|
||||
/* some cpus being non-responsive to the cpu mondo */
|
||||
pr_crit("CPU[%d]: SUN4V mondo timeout, cpu(%d) made no forward progress after %d retries. Total target cpus(%d).\n",
|
||||
this_cpu, first_cpu, (tot_retries + retries), tot_cpus);
|
||||
panic("SUN4V mondo timeout panic\n");
|
||||
}
|
||||
|
||||
static void (*xcall_deliver_impl)(struct trap_per_cpu *, int);
|
||||
|
||||
@@ -26,6 +26,21 @@ sun4v_cpu_mondo:
|
||||
ldxa [%g0] ASI_SCRATCHPAD, %g4
|
||||
sub %g4, TRAP_PER_CPU_FAULT_INFO, %g4
|
||||
|
||||
/* Get smp_processor_id() into %g3 */
|
||||
sethi %hi(trap_block), %g5
|
||||
or %g5, %lo(trap_block), %g5
|
||||
sub %g4, %g5, %g3
|
||||
srlx %g3, TRAP_BLOCK_SZ_SHIFT, %g3
|
||||
|
||||
/* Increment cpu_mondo_counter[smp_processor_id()] */
|
||||
sethi %hi(cpu_mondo_counter), %g5
|
||||
or %g5, %lo(cpu_mondo_counter), %g5
|
||||
sllx %g3, 3, %g3
|
||||
add %g5, %g3, %g5
|
||||
ldx [%g5], %g3
|
||||
add %g3, 1, %g3
|
||||
stx %g3, [%g5]
|
||||
|
||||
/* Get CPU mondo queue base phys address into %g7. */
|
||||
ldx [%g4 + TRAP_PER_CPU_CPU_MONDO_PA], %g7
|
||||
|
||||
|
||||
@@ -2659,6 +2659,7 @@ void do_getpsr(struct pt_regs *regs)
|
||||
}
|
||||
}
|
||||
|
||||
u64 cpu_mondo_counter[NR_CPUS] = {0};
|
||||
struct trap_per_cpu trap_block[NR_CPUS];
|
||||
EXPORT_SYMBOL(trap_block);
|
||||
|
||||
|
||||
@@ -375,6 +375,7 @@ tsb_flush:
|
||||
* %o1: TSB base config pointer
|
||||
* %o2: TSB huge config pointer, or NULL if none
|
||||
* %o3: Hypervisor TSB descriptor physical address
|
||||
* %o4: Secondary context to load, if non-zero
|
||||
*
|
||||
* We have to run this whole thing with interrupts
|
||||
* disabled so that the current cpu doesn't change
|
||||
@@ -387,6 +388,17 @@ __tsb_context_switch:
|
||||
rdpr %pstate, %g1
|
||||
wrpr %g1, PSTATE_IE, %pstate
|
||||
|
||||
brz,pn %o4, 1f
|
||||
mov SECONDARY_CONTEXT, %o5
|
||||
|
||||
661: stxa %o4, [%o5] ASI_DMMU
|
||||
.section .sun4v_1insn_patch, "ax"
|
||||
.word 661b
|
||||
stxa %o4, [%o5] ASI_MMU
|
||||
.previous
|
||||
flush %g6
|
||||
|
||||
1:
|
||||
TRAP_LOAD_TRAP_BLOCK(%g2, %g3)
|
||||
|
||||
stx %o0, [%g2 + TRAP_PER_CPU_PGD_PADDR]
|
||||
|
||||
@@ -35,6 +35,5 @@ void restore_processor_state(void)
|
||||
{
|
||||
struct mm_struct *mm = current->active_mm;
|
||||
|
||||
load_secondary_context(mm);
|
||||
tsb_context_switch(mm);
|
||||
tsb_context_switch_ctx(mm, CTX_HWBITS(mm->context));
|
||||
}
|
||||
|
||||
@@ -78,7 +78,7 @@ struct thread_info {
|
||||
|
||||
#ifndef __ASSEMBLY__
|
||||
|
||||
void arch_release_thread_info(struct thread_info *info);
|
||||
void arch_release_thread_stack(unsigned long *stack);
|
||||
|
||||
/* How to get the thread information struct from C. */
|
||||
register unsigned long stack_pointer __asm__("sp");
|
||||
|
||||
@@ -73,8 +73,9 @@ void arch_cpu_idle(void)
|
||||
/*
|
||||
* Release a thread_info structure
|
||||
*/
|
||||
void arch_release_thread_info(struct thread_info *info)
|
||||
void arch_release_thread_stack(unsigned long *stack)
|
||||
{
|
||||
struct thread_info *info = (void *)stack;
|
||||
struct single_step_state *step_state = info->step_state;
|
||||
|
||||
if (step_state) {
|
||||
|
||||
@@ -14,6 +14,7 @@
|
||||
|
||||
#include <linux/types.h>
|
||||
#include "ctype.h"
|
||||
#include "string.h"
|
||||
|
||||
int memcmp(const void *s1, const void *s2, size_t len)
|
||||
{
|
||||
|
||||
@@ -18,4 +18,13 @@ int memcmp(const void *s1, const void *s2, size_t len);
|
||||
#define memset(d,c,l) __builtin_memset(d,c,l)
|
||||
#define memcmp __builtin_memcmp
|
||||
|
||||
extern int strcmp(const char *str1, const char *str2);
|
||||
extern int strncmp(const char *cs, const char *ct, size_t count);
|
||||
extern size_t strlen(const char *s);
|
||||
extern char *strstr(const char *s1, const char *s2);
|
||||
extern size_t strnlen(const char *s, size_t maxlen);
|
||||
extern unsigned int atou(const char *s);
|
||||
extern unsigned long long simple_strtoull(const char *cp, char **endp,
|
||||
unsigned int base);
|
||||
|
||||
#endif /* BOOT_STRING_H */
|
||||
|
||||
@@ -201,7 +201,7 @@ asmlinkage void sha1_transform_avx2(u32 *digest, const char *data,
|
||||
|
||||
static bool avx2_usable(void)
|
||||
{
|
||||
if (avx_usable() && boot_cpu_has(X86_FEATURE_AVX2)
|
||||
if (false && avx_usable() && boot_cpu_has(X86_FEATURE_AVX2)
|
||||
&& boot_cpu_has(X86_FEATURE_BMI1)
|
||||
&& boot_cpu_has(X86_FEATURE_BMI2))
|
||||
return true;
|
||||
|
||||
@@ -245,12 +245,13 @@ extern int force_personality32;
|
||||
#define CORE_DUMP_USE_REGSET
|
||||
#define ELF_EXEC_PAGESIZE 4096
|
||||
|
||||
/* This is the location that an ET_DYN program is loaded if exec'ed. Typical
|
||||
use of this is to invoke "./ld.so someprog" to test out a new version of
|
||||
the loader. We need to make sure that it is out of the way of the program
|
||||
that it will "exec", and that there is sufficient room for the brk. */
|
||||
|
||||
#define ELF_ET_DYN_BASE (TASK_SIZE / 3 * 2)
|
||||
/*
|
||||
* This is the base location for PIE (ET_DYN with INTERP) loads. On
|
||||
* 64-bit, this is raised to 4GB to leave the entire 32-bit address
|
||||
* space open for things that want to use the area for 32-bit pointers.
|
||||
*/
|
||||
#define ELF_ET_DYN_BASE (mmap_is_ia32() ? 0x000400000UL : \
|
||||
0x100000000UL)
|
||||
|
||||
/* This yields a mask that user programs can use to figure out what
|
||||
instruction set this CPU supports. This could be done in user space,
|
||||
|
||||
@@ -405,6 +405,8 @@
|
||||
#define MSR_IA32_TSC_ADJUST 0x0000003b
|
||||
#define MSR_IA32_BNDCFGS 0x00000d90
|
||||
|
||||
#define MSR_IA32_BNDCFGS_RSVD 0x00000ffc
|
||||
|
||||
#define MSR_IA32_XSS 0x00000da0
|
||||
|
||||
#define FEATURE_CONTROL_LOCKED (1<<0)
|
||||
|
||||
@@ -43,6 +43,7 @@
|
||||
|
||||
#include <asm/page.h>
|
||||
#include <asm/pgtable.h>
|
||||
#include <asm/smap.h>
|
||||
|
||||
#include <xen/interface/xen.h>
|
||||
#include <xen/interface/sched.h>
|
||||
@@ -213,10 +214,12 @@ privcmd_call(unsigned call,
|
||||
__HYPERCALL_DECLS;
|
||||
__HYPERCALL_5ARG(a1, a2, a3, a4, a5);
|
||||
|
||||
stac();
|
||||
asm volatile("call *%[call]"
|
||||
: __HYPERCALL_5PARAM
|
||||
: [call] "a" (&hypercall_page[call])
|
||||
: __HYPERCALL_CLOBBER5);
|
||||
clac();
|
||||
|
||||
return (long)__res;
|
||||
}
|
||||
|
||||
@@ -328,6 +328,14 @@ static void __init mp_override_legacy_irq(u8 bus_irq, u8 polarity, u8 trigger,
|
||||
int pin;
|
||||
struct mpc_intsrc mp_irq;
|
||||
|
||||
/*
|
||||
* Check bus_irq boundary.
|
||||
*/
|
||||
if (bus_irq >= NR_IRQS_LEGACY) {
|
||||
pr_warn("Invalid bus_irq %u for legacy override\n", bus_irq);
|
||||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
* Convert 'gsi' to 'ioapic.pin'.
|
||||
*/
|
||||
|
||||
@@ -2115,7 +2115,7 @@ static inline void __init check_timer(void)
|
||||
int idx;
|
||||
idx = find_irq_entry(apic1, pin1, mp_INT);
|
||||
if (idx != -1 && irq_trigger(idx))
|
||||
unmask_ioapic_irq(irq_get_chip_data(0));
|
||||
unmask_ioapic_irq(irq_get_irq_data(0));
|
||||
}
|
||||
irq_domain_deactivate_irq(irq_data);
|
||||
irq_domain_activate_irq(irq_data);
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user