Explorar o código

Merge tag 'arm64-fixes' of git://git.kernel.org/pub/scm/linux/kernel/git/cmarinas/linux-aarch64

Pull arm64 fixes from Catalin Marinas:
 "Main changes:
   - AArch64 Linux compilation fixes following 3.7-rc1 changes
     (MODULES_USE_ELF_RELA, update_vsyscall() prototype)
   - Unnecessary register setting in start_thread() (thanks to Al Viro)
   - ptrace fixes"

* tag 'arm64-fixes' of git://git.kernel.org/pub/scm/linux/kernel/git/cmarinas/linux-aarch64:
  arm64: fix alignment padding in assembly code
  arm64: ptrace: use HW_BREAKPOINT_EMPTY type for disabled breakpoints
  arm64: ptrace: make structure padding explicit for debug registers
  arm64: No need to set the x0-x2 registers in start_thread()
  arm64: Ignore memory blocks below PHYS_OFFSET
  arm64: Fix the update_vsyscall() prototype
  arm64: Select MODULES_USE_ELF_RELA
  arm64: Remove duplicate inclusion of mmu_context.h in smp.c
Linus Torvalds %!s(int64=12) %!d(string=hai) anos
pai
achega
198190a188

+ 1 - 0
arch/arm64/Kconfig

@@ -22,6 +22,7 @@ config ARM64
 	select HAVE_PERF_EVENTS
 	select HAVE_SPARSE_IRQ
 	select IRQ_DOMAIN
+	select MODULES_USE_ELF_RELA
 	select NO_BOOTMEM
 	select OF
 	select OF_EARLY_FLATTREE

+ 0 - 1
arch/arm64/include/asm/Kbuild

@@ -18,7 +18,6 @@ generic-y += ipcbuf.h
 generic-y += irq_regs.h
 generic-y += kdebug.h
 generic-y += kmap_types.h
-generic-y += linkage.h
 generic-y += local.h
 generic-y += local64.h
 generic-y += mman.h

+ 7 - 0
arch/arm64/include/asm/linkage.h

@@ -0,0 +1,7 @@
+#ifndef __ASM_LINKAGE_H
+#define __ASM_LINKAGE_H
+
+#define __ALIGN		.align 4
+#define __ALIGN_STR	".align 4"
+
+#endif

+ 0 - 10
arch/arm64/include/asm/processor.h

@@ -92,30 +92,20 @@ static inline void start_thread_common(struct pt_regs *regs, unsigned long pc)
 static inline void start_thread(struct pt_regs *regs, unsigned long pc,
 				unsigned long sp)
 {
-	unsigned long *stack = (unsigned long *)sp;
-
 	start_thread_common(regs, pc);
 	regs->pstate = PSR_MODE_EL0t;
 	regs->sp = sp;
-	regs->regs[2] = stack[2];	/* x2 (envp) */
-	regs->regs[1] = stack[1];	/* x1 (argv) */
-	regs->regs[0] = stack[0];	/* x0 (argc) */
 }
 
 #ifdef CONFIG_COMPAT
 static inline void compat_start_thread(struct pt_regs *regs, unsigned long pc,
 				       unsigned long sp)
 {
-	unsigned int *stack = (unsigned int *)sp;
-
 	start_thread_common(regs, pc);
 	regs->pstate = COMPAT_PSR_MODE_USR;
 	if (pc & 1)
 		regs->pstate |= COMPAT_PSR_T_BIT;
 	regs->compat_sp = sp;
-	regs->regs[2] = stack[2];	/* x2 (envp) */
-	regs->regs[1] = stack[1];	/* x1 (argv) */
-	regs->regs[0] = stack[0];	/* x0 (argc) */
 }
 #endif
 

+ 2 - 1
arch/arm64/include/uapi/asm/ptrace.h

@@ -79,13 +79,14 @@ struct user_fpsimd_state {
 
 struct user_hwdebug_state {
 	__u32		dbg_info;
+	__u32		pad;
 	struct {
 		__u64	addr;
 		__u32	ctrl;
+		__u32	pad;
 	}		dbg_regs[16];
 };
 
-
 #endif /* __ASSEMBLY__ */
 
 #endif /* _UAPI__ASM_PTRACE_H */

+ 51 - 22
arch/arm64/kernel/ptrace.c

@@ -234,28 +234,33 @@ static int ptrace_hbp_fill_attr_ctrl(unsigned int note_type,
 				     struct arch_hw_breakpoint_ctrl ctrl,
 				     struct perf_event_attr *attr)
 {
-	int err, len, type;
+	int err, len, type, disabled = !ctrl.enabled;
 
-	err = arch_bp_generic_fields(ctrl, &len, &type);
-	if (err)
-		return err;
-
-	switch (note_type) {
-	case NT_ARM_HW_BREAK:
-		if ((type & HW_BREAKPOINT_X) != type)
-			return -EINVAL;
-		break;
-	case NT_ARM_HW_WATCH:
-		if ((type & HW_BREAKPOINT_RW) != type)
+	if (disabled) {
+		len = 0;
+		type = HW_BREAKPOINT_EMPTY;
+	} else {
+		err = arch_bp_generic_fields(ctrl, &len, &type);
+		if (err)
+			return err;
+
+		switch (note_type) {
+		case NT_ARM_HW_BREAK:
+			if ((type & HW_BREAKPOINT_X) != type)
+				return -EINVAL;
+			break;
+		case NT_ARM_HW_WATCH:
+			if ((type & HW_BREAKPOINT_RW) != type)
+				return -EINVAL;
+			break;
+		default:
 			return -EINVAL;
-		break;
-	default:
-		return -EINVAL;
+		}
 	}
 
 	attr->bp_len	= len;
 	attr->bp_type	= type;
-	attr->disabled	= !ctrl.enabled;
+	attr->disabled	= disabled;
 
 	return 0;
 }
@@ -372,7 +377,7 @@ static int ptrace_hbp_set_addr(unsigned int note_type,
 
 #define PTRACE_HBP_ADDR_SZ	sizeof(u64)
 #define PTRACE_HBP_CTRL_SZ	sizeof(u32)
-#define PTRACE_HBP_REG_OFF	sizeof(u32)
+#define PTRACE_HBP_PAD_SZ	sizeof(u32)
 
 static int hw_break_get(struct task_struct *target,
 			const struct user_regset *regset,
@@ -380,7 +385,7 @@ static int hw_break_get(struct task_struct *target,
 			void *kbuf, void __user *ubuf)
 {
 	unsigned int note_type = regset->core_note_type;
-	int ret, idx = 0, offset = PTRACE_HBP_REG_OFF, limit;
+	int ret, idx = 0, offset, limit;
 	u32 info, ctrl;
 	u64 addr;
 
@@ -389,11 +394,20 @@ static int hw_break_get(struct task_struct *target,
 	if (ret)
 		return ret;
 
-	ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf, &info, 0, 4);
+	ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf, &info, 0,
+				  sizeof(info));
+	if (ret)
+		return ret;
+
+	/* Pad */
+	offset = offsetof(struct user_hwdebug_state, pad);
+	ret = user_regset_copyout_zero(&pos, &count, &kbuf, &ubuf, offset,
+				       offset + PTRACE_HBP_PAD_SZ);
 	if (ret)
 		return ret;
 
 	/* (address, ctrl) registers */
+	offset = offsetof(struct user_hwdebug_state, dbg_regs);
 	limit = regset->n * regset->size;
 	while (count && offset < limit) {
 		ret = ptrace_hbp_get_addr(note_type, target, idx, &addr);
@@ -413,6 +427,13 @@ static int hw_break_get(struct task_struct *target,
 		if (ret)
 			return ret;
 		offset += PTRACE_HBP_CTRL_SZ;
+
+		ret = user_regset_copyout_zero(&pos, &count, &kbuf, &ubuf,
+					       offset,
+					       offset + PTRACE_HBP_PAD_SZ);
+		if (ret)
+			return ret;
+		offset += PTRACE_HBP_PAD_SZ;
 		idx++;
 	}
 
@@ -425,12 +446,13 @@ static int hw_break_set(struct task_struct *target,
 			const void *kbuf, const void __user *ubuf)
 {
 	unsigned int note_type = regset->core_note_type;
-	int ret, idx = 0, offset = PTRACE_HBP_REG_OFF, limit;
+	int ret, idx = 0, offset, limit;
 	u32 ctrl;
 	u64 addr;
 
-	/* Resource info */
-	ret = user_regset_copyin_ignore(&pos, &count, &kbuf, &ubuf, 0, 4);
+	/* Resource info and pad */
+	offset = offsetof(struct user_hwdebug_state, dbg_regs);
+	ret = user_regset_copyin_ignore(&pos, &count, &kbuf, &ubuf, 0, offset);
 	if (ret)
 		return ret;
 
@@ -454,6 +476,13 @@ static int hw_break_set(struct task_struct *target,
 		if (ret)
 			return ret;
 		offset += PTRACE_HBP_CTRL_SZ;
+
+		ret = user_regset_copyin_ignore(&pos, &count, &kbuf, &ubuf,
+						offset,
+						offset + PTRACE_HBP_PAD_SZ);
+		if (ret)
+			return ret;
+		offset += PTRACE_HBP_PAD_SZ;
 		idx++;
 	}
 

+ 12 - 0
arch/arm64/kernel/setup.c

@@ -170,7 +170,19 @@ static void __init setup_machine_fdt(phys_addr_t dt_phys)
 
 void __init early_init_dt_add_memory_arch(u64 base, u64 size)
 {
+	base &= PAGE_MASK;
 	size &= PAGE_MASK;
+	if (base + size < PHYS_OFFSET) {
+		pr_warning("Ignoring memory block 0x%llx - 0x%llx\n",
+			   base, base + size);
+		return;
+	}
+	if (base < PHYS_OFFSET) {
+		pr_warning("Ignoring memory range 0x%llx - 0x%llx\n",
+			   base, PHYS_OFFSET);
+		size -= PHYS_OFFSET - base;
+		base = PHYS_OFFSET;
+	}
 	memblock_add(base, size);
 }
 

+ 0 - 1
arch/arm64/kernel/smp.c

@@ -46,7 +46,6 @@
 #include <asm/sections.h>
 #include <asm/tlbflush.h>
 #include <asm/ptrace.h>
-#include <asm/mmu_context.h>
 
 /*
  * as from 2.5, kernels no longer have an init_tasks structure

+ 10 - 10
arch/arm64/kernel/vdso.c

@@ -28,6 +28,7 @@
 #include <linux/sched.h>
 #include <linux/signal.h>
 #include <linux/slab.h>
+#include <linux/timekeeper_internal.h>
 #include <linux/vmalloc.h>
 
 #include <asm/cacheflush.h>
@@ -222,11 +223,10 @@ struct vm_area_struct *get_gate_vma(struct mm_struct *mm)
 /*
  * Update the vDSO data page to keep in sync with kernel timekeeping.
  */
-void update_vsyscall(struct timespec *ts, struct timespec *wtm,
-		     struct clocksource *clock, u32 mult)
+void update_vsyscall(struct timekeeper *tk)
 {
 	struct timespec xtime_coarse;
-	u32 use_syscall = strcmp(clock->name, "arch_sys_counter");
+	u32 use_syscall = strcmp(tk->clock->name, "arch_sys_counter");
 
 	++vdso_data->tb_seq_count;
 	smp_wmb();
@@ -237,13 +237,13 @@ void update_vsyscall(struct timespec *ts, struct timespec *wtm,
 	vdso_data->xtime_coarse_nsec		= xtime_coarse.tv_nsec;
 
 	if (!use_syscall) {
-		vdso_data->cs_cycle_last	= clock->cycle_last;
-		vdso_data->xtime_clock_sec	= ts->tv_sec;
-		vdso_data->xtime_clock_nsec	= ts->tv_nsec;
-		vdso_data->cs_mult		= mult;
-		vdso_data->cs_shift		= clock->shift;
-		vdso_data->wtm_clock_sec	= wtm->tv_sec;
-		vdso_data->wtm_clock_nsec	= wtm->tv_nsec;
+		vdso_data->cs_cycle_last	= tk->clock->cycle_last;
+		vdso_data->xtime_clock_sec	= tk->xtime_sec;
+		vdso_data->xtime_clock_nsec	= tk->xtime_nsec >> tk->shift;
+		vdso_data->cs_mult		= tk->mult;
+		vdso_data->cs_shift		= tk->shift;
+		vdso_data->wtm_clock_sec	= tk->wall_to_monotonic.tv_sec;
+		vdso_data->wtm_clock_nsec	= tk->wall_to_monotonic.tv_nsec;
 	}
 
 	smp_wmb();