From de7d812d05f3075096a3e37222f4e1876ae25e6c Mon Sep 17 00:00:00 2001 From: Stephen Rothwell Date: Tue, 5 Feb 2008 14:15:12 +1100 Subject: [POWERPC] iSeries: Fix section mismatch in viodsasd WARNING: vmlinux.o(.text+0x3017c): Section mismatch in reference from the function .vio_create_viodasd() to the function .devinit.text:.vio_register_device_node() Signed-off-by: Stephen Rothwell Signed-off-by: Paul Mackerras --- arch/powerpc/kernel/vio.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'arch/powerpc/kernel') diff --git a/arch/powerpc/kernel/vio.c b/arch/powerpc/kernel/vio.c index f0bad7070fb..f98867252ee 100644 --- a/arch/powerpc/kernel/vio.c +++ b/arch/powerpc/kernel/vio.c @@ -176,7 +176,7 @@ static void __devinit vio_dev_release(struct device *dev) * Returns a pointer to the created vio_dev or NULL if node has * NULL device_type or compatible fields. */ -struct vio_dev * __devinit vio_register_device_node(struct device_node *of_node) +struct vio_dev *vio_register_device_node(struct device_node *of_node) { struct vio_dev *viodev; const unsigned int *unit_address; -- cgit v1.2.3-18-g5258 From ad7f71674ad7c3c4467e48f6ab9e85516dae2720 Mon Sep 17 00:00:00 2001 From: Tony Breeds Date: Tue, 5 Feb 2008 16:16:48 +1100 Subject: [POWERPC] Use a sensible default for clock_getres() in the VDSO This ensures that the syscall and the (fast) vdso versions of clock_getres() will return the same resolution. Signed-off-by: Tony Breeds Signed-off-by: Paul Mackerras --- arch/powerpc/kernel/asm-offsets.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'arch/powerpc/kernel') diff --git a/arch/powerpc/kernel/asm-offsets.c b/arch/powerpc/kernel/asm-offsets.c index ed083feaf6f..e6e49289f78 100644 --- a/arch/powerpc/kernel/asm-offsets.c +++ b/arch/powerpc/kernel/asm-offsets.c @@ -22,6 +22,7 @@ #include #include #include +#include #ifdef CONFIG_PPC64 #include #include @@ -312,7 +313,7 @@ int main(void) DEFINE(CLOCK_REALTIME, CLOCK_REALTIME); DEFINE(CLOCK_MONOTONIC, CLOCK_MONOTONIC); DEFINE(NSEC_PER_SEC, NSEC_PER_SEC); - DEFINE(CLOCK_REALTIME_RES, TICK_NSEC); + DEFINE(CLOCK_REALTIME_RES, (KTIME_MONOTONIC_RES).tv64); #ifdef CONFIG_BUG DEFINE(BUG_ENTRY_SIZE, sizeof(struct bug_entry)); -- cgit v1.2.3-18-g5258 From f5903ede0015db5b53458092b6ae2af074fa49d4 Mon Sep 17 00:00:00 2001 From: Michael Ellerman Date: Tue, 5 Feb 2008 23:01:50 +1100 Subject: [POWERPC] Fix legacy serial search for opb bus ports The patch to legacy_serial.c (1a7507c7da2df6856e085e0fbb0c9ea8c12ac4e, Reduce code duplication in legacy_serial, add UART parent types) changed the semantics for opb ports from type = "opb" || compatible = "ibm,opb" to type = "opb" && compatible = "ibm,opb". The result is serial ports on our QS21s (Cell blades) don't get found, and for some reason the machine doesn't boot at all - possibly it's panicking due to lack of a console? The fix is to add two entries to the of_device_id table, one that looks for type = "opb" and the other compatible = "ibm,opb". Signed-off-by: Michael Ellerman Acked-by: Paul Gortmaker Acked-by: Benjamin Herrenschmidt Signed-off-by: Paul Mackerras --- arch/powerpc/kernel/legacy_serial.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'arch/powerpc/kernel') diff --git a/arch/powerpc/kernel/legacy_serial.c b/arch/powerpc/kernel/legacy_serial.c index 76b862bd1fe..61dd17449dd 100644 --- a/arch/powerpc/kernel/legacy_serial.c +++ b/arch/powerpc/kernel/legacy_serial.c @@ -36,7 +36,8 @@ static struct legacy_serial_info { static struct __initdata of_device_id parents[] = { {.type = "soc",}, {.type = "tsi-bridge",}, - {.type = "opb", .compatible = "ibm,opb",}, + {.type = "opb", }, + {.compatible = "ibm,opb",}, {.compatible = "simple-bus",}, {.compatible = "wrs,epld-localbus",}, }; -- cgit v1.2.3-18-g5258 From 39aef685af431c032ffd2763ec8782b13c32520c Mon Sep 17 00:00:00 2001 From: Andy Fleming Date: Mon, 4 Feb 2008 18:27:55 -0600 Subject: [POWERPC] Made FSL Book-E PMC support more generic Some of the more recent e300 cores have the same performance monitor implementation as the e500. e300 isn't book-e, so the name isn't really appropriate. In preparation for e300 support, rename a bunch of fsl_booke things to say fsl_emb (Freescale Embedded Performance Monitors). Signed-off-by: Andy Fleming Signed-off-by: Kumar Gala --- arch/powerpc/kernel/cputable.c | 4 ++-- arch/powerpc/kernel/pmc.c | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) (limited to 'arch/powerpc/kernel') diff --git a/arch/powerpc/kernel/cputable.c b/arch/powerpc/kernel/cputable.c index a4c2771b5e6..98a1c9e6b9f 100644 --- a/arch/powerpc/kernel/cputable.c +++ b/arch/powerpc/kernel/cputable.c @@ -1435,7 +1435,7 @@ static struct cpu_spec __initdata cpu_specs[] = { .dcache_bsize = 32, .num_pmcs = 4, .oprofile_cpu_type = "ppc/e500", - .oprofile_type = PPC_OPROFILE_BOOKE, + .oprofile_type = PPC_OPROFILE_FSL_EMB, .machine_check = machine_check_e500, .platform = "ppc8540", }, @@ -1453,7 +1453,7 @@ static struct cpu_spec __initdata cpu_specs[] = { .dcache_bsize = 32, .num_pmcs = 4, .oprofile_cpu_type = "ppc/e500", - .oprofile_type = PPC_OPROFILE_BOOKE, + .oprofile_type = PPC_OPROFILE_FSL_EMB, .machine_check = machine_check_e500, .platform = "ppc8548", }, diff --git a/arch/powerpc/kernel/pmc.c b/arch/powerpc/kernel/pmc.c index ea04e0ab3f2..0516e2d3e02 100644 --- a/arch/powerpc/kernel/pmc.c +++ b/arch/powerpc/kernel/pmc.c @@ -26,7 +26,7 @@ static void dummy_perf(struct pt_regs *regs) { -#if defined(CONFIG_FSL_BOOKE) && !defined(CONFIG_E200) +#if defined(CONFIG_FSL_EMB_PERFMON) mtpmr(PMRN_PMGC0, mfpmr(PMRN_PMGC0) & ~PMGC0_PMIE); #elif defined(CONFIG_PPC64) || defined(CONFIG_6xx) if (cur_cpu_spec->pmc_type == PPC_PMC_IBM) -- cgit v1.2.3-18-g5258 From 1347a2c1eb61fce8b5085801761c7b63f9e7ba8b Mon Sep 17 00:00:00 2001 From: Andy Fleming Date: Mon, 4 Feb 2008 18:28:07 -0600 Subject: [POWERPC} Add oprofile support for e300 The e300 c3 and c4 variants support hardware performance monitor counters which are identical to those found in the e500. Signed-off-by: Andy Fleming Signed-off-by: Kumar Gala --- arch/powerpc/kernel/cputable.c | 6 ++++++ 1 file changed, 6 insertions(+) (limited to 'arch/powerpc/kernel') diff --git a/arch/powerpc/kernel/cputable.c b/arch/powerpc/kernel/cputable.c index 98a1c9e6b9f..2a8f5cc5184 100644 --- a/arch/powerpc/kernel/cputable.c +++ b/arch/powerpc/kernel/cputable.c @@ -959,6 +959,9 @@ static struct cpu_spec __initdata cpu_specs[] = { .icache_bsize = 32, .dcache_bsize = 32, .cpu_setup = __setup_cpu_603, + .num_pmcs = 4, + .oprofile_cpu_type = "ppc/e300", + .oprofile_type = PPC_OPROFILE_FSL_EMB, .platform = "ppc603", }, { /* e300c4 (e300c1, plus one IU) */ @@ -971,6 +974,9 @@ static struct cpu_spec __initdata cpu_specs[] = { .dcache_bsize = 32, .cpu_setup = __setup_cpu_603, .machine_check = machine_check_generic, + .num_pmcs = 4, + .oprofile_cpu_type = "ppc/e300", + .oprofile_type = PPC_OPROFILE_FSL_EMB, .platform = "ppc603", }, { /* default match, we assume split I/D cache & TB (non-601)... */ -- cgit v1.2.3-18-g5258 From 7dbb922cea70897dd0e76c6cf8a300b061ca2531 Mon Sep 17 00:00:00 2001 From: Olof Johansson Date: Thu, 31 Jan 2008 14:34:47 +1100 Subject: [POWERPC] Fix compilation for CONFIG_DEBUGGER=n and CONFIG_KEXEC=y Looks like "[POWERPC] kdump shutdown hook support" broke builds when CONFIG_DEBUGGER=n and CONFIG_KEXEC=y, such as in g5_defconfig: arch/powerpc/kernel/crash.c: In function 'default_machine_crash_shutdown': arch/powerpc/kernel/crash.c:388: error: '__debugger_fault_handler' undeclared (first use in this function) arch/powerpc/kernel/crash.c:388: error: (Each undeclared identifier is reported only once arch/powerpc/kernel/crash.c:388: error: for each function it appears in.) Move the debugger hooks to under CONFIG_DEBUGGER || CONFIG_KEXEC, since that's when the crash code is enabled. (I should have caught this with my build-script pre-merge, my bad. :( ) Signed-off-by: Olof Johansson Signed-off-by: Paul Mackerras --- arch/powerpc/kernel/traps.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'arch/powerpc/kernel') diff --git a/arch/powerpc/kernel/traps.c b/arch/powerpc/kernel/traps.c index 848a20475db..4b5b7ff4f78 100644 --- a/arch/powerpc/kernel/traps.c +++ b/arch/powerpc/kernel/traps.c @@ -54,7 +54,7 @@ #endif #include -#ifdef CONFIG_DEBUGGER +#if defined(CONFIG_DEBUGGER) || defined(CONFIG_KEXEC) int (*__debugger)(struct pt_regs *regs); int (*__debugger_ipi)(struct pt_regs *regs); int (*__debugger_bpt)(struct pt_regs *regs); -- cgit v1.2.3-18-g5258 From f65255e8d51ecbc6c9eef20d39e0377d19b658ca Mon Sep 17 00:00:00 2001 From: Roland McGrath Date: Thu, 20 Dec 2007 03:57:34 -0800 Subject: [POWERPC] Use user_regset accessors for FP regs This implements user_regset-style accessors for the powerpc FPU data, and rewrites the existing ptrace code in terms of those calls. Signed-off-by: Roland McGrath Signed-off-by: Paul Mackerras --- arch/powerpc/kernel/ptrace.c | 37 +++++++++++++++++++++++++++++++------ 1 file changed, 31 insertions(+), 6 deletions(-) (limited to 'arch/powerpc/kernel') diff --git a/arch/powerpc/kernel/ptrace.c b/arch/powerpc/kernel/ptrace.c index 8b056d2295c..f1ce6464925 100644 --- a/arch/powerpc/kernel/ptrace.c +++ b/arch/powerpc/kernel/ptrace.c @@ -21,6 +21,7 @@ #include #include #include +#include #include #include #include @@ -103,24 +104,48 @@ int ptrace_put_reg(struct task_struct *task, int regno, unsigned long data) } +static int fpr_get(struct task_struct *target, const struct user_regset *regset, + unsigned int pos, unsigned int count, + void *kbuf, void __user *ubuf) +{ + flush_fp_to_thread(target); + + BUILD_BUG_ON(offsetof(struct thread_struct, fpscr) != + offsetof(struct thread_struct, fpr[32])); + + return user_regset_copyout(&pos, &count, &kbuf, &ubuf, + &target->thread.fpr, 0, -1); +} + +static int fpr_set(struct task_struct *target, const struct user_regset *regset, + unsigned int pos, unsigned int count, + const void *kbuf, const void __user *ubuf) +{ + flush_fp_to_thread(target); + + BUILD_BUG_ON(offsetof(struct thread_struct, fpscr) != + offsetof(struct thread_struct, fpr[32])); + + return user_regset_copyin(&pos, &count, &kbuf, &ubuf, + &target->thread.fpr, 0, -1); +} + static int get_fpregs(void __user *data, struct task_struct *task, int has_fpscr) { unsigned int count = has_fpscr ? 33 : 32; - - if (copy_to_user(data, task->thread.fpr, count * sizeof(double))) + if (!access_ok(VERIFY_WRITE, data, count * sizeof(double))) return -EFAULT; - return 0; + return fpr_get(task, NULL, 0, count * sizeof(double), NULL, data); } static int set_fpregs(void __user *data, struct task_struct *task, int has_fpscr) { unsigned int count = has_fpscr ? 33 : 32; - - if (copy_from_user(task->thread.fpr, data, count * sizeof(double))) + if (!access_ok(VERIFY_READ, data, count * sizeof(double))) return -EFAULT; - return 0; + return fpr_set(task, NULL, 0, count * sizeof(double), NULL, data); } -- cgit v1.2.3-18-g5258 From 3caf06c6e0656b25f694e3d414191cedcecf76ce Mon Sep 17 00:00:00 2001 From: Roland McGrath Date: Thu, 20 Dec 2007 03:57:39 -0800 Subject: [POWERPC] Use user_regset accessors for altivec regs This implements user_regset-style accessors for the powerpc Altivec data, and rewrites the existing ptrace code in terms of those calls. Signed-off-by: Roland McGrath Signed-off-by: Paul Mackerras --- arch/powerpc/kernel/ptrace.c | 112 ++++++++++++++++++++++++++++++------------- 1 file changed, 78 insertions(+), 34 deletions(-) (limited to 'arch/powerpc/kernel') diff --git a/arch/powerpc/kernel/ptrace.c b/arch/powerpc/kernel/ptrace.c index f1ce6464925..7cdf35a7c83 100644 --- a/arch/powerpc/kernel/ptrace.c +++ b/arch/powerpc/kernel/ptrace.c @@ -22,6 +22,7 @@ #include #include #include +#include #include #include #include @@ -163,30 +164,87 @@ static int set_fpregs(void __user *data, struct task_struct *task, * (combined (32- and 64-bit) gdb. */ +static int vr_active(struct task_struct *target, + const struct user_regset *regset) +{ + flush_altivec_to_thread(target); + return target->thread.used_vr ? regset->n : 0; +} + +static int vr_get(struct task_struct *target, const struct user_regset *regset, + unsigned int pos, unsigned int count, + void *kbuf, void __user *ubuf) +{ + int ret; + + flush_altivec_to_thread(target); + + BUILD_BUG_ON(offsetof(struct thread_struct, vscr) != + offsetof(struct thread_struct, vr[32])); + + ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf, + &target->thread.vr, 0, + 33 * sizeof(vector128)); + if (!ret) { + /* + * Copy out only the low-order word of vrsave. + */ + union { + elf_vrreg_t reg; + u32 word; + } vrsave; + memset(&vrsave, 0, sizeof(vrsave)); + vrsave.word = target->thread.vrsave; + ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf, &vrsave, + 33 * sizeof(vector128), -1); + } + + return ret; +} + +static int vr_set(struct task_struct *target, const struct user_regset *regset, + unsigned int pos, unsigned int count, + const void *kbuf, const void __user *ubuf) +{ + int ret; + + flush_altivec_to_thread(target); + + BUILD_BUG_ON(offsetof(struct thread_struct, vscr) != + offsetof(struct thread_struct, vr[32])); + + ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf, + &target->thread.vr, 0, 33 * sizeof(vector128)); + if (!ret && count > 0) { + /* + * We use only the first word of vrsave. + */ + union { + elf_vrreg_t reg; + u32 word; + } vrsave; + memset(&vrsave, 0, sizeof(vrsave)); + vrsave.word = target->thread.vrsave; + ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf, &vrsave, + 33 * sizeof(vector128), -1); + if (!ret) + target->thread.vrsave = vrsave.word; + } + + return ret; +} + /* * Get contents of AltiVec register state in task TASK */ static int get_vrregs(unsigned long __user *data, struct task_struct *task) { - unsigned long regsize; - - /* copy AltiVec registers VR[0] .. VR[31] */ - regsize = 32 * sizeof(vector128); - if (copy_to_user(data, task->thread.vr, regsize)) - return -EFAULT; - data += (regsize / sizeof(unsigned long)); - - /* copy VSCR */ - regsize = 1 * sizeof(vector128); - if (copy_to_user(data, &task->thread.vscr, regsize)) + if (!access_ok(VERIFY_WRITE, data, + 33 * sizeof(vector128) + sizeof(u32))) return -EFAULT; - data += (regsize / sizeof(unsigned long)); - /* copy VRSAVE */ - if (put_user(task->thread.vrsave, (u32 __user *)data)) - return -EFAULT; - - return 0; + return vr_get(task, NULL, 0, 33 * sizeof(vector128) + sizeof(u32), + NULL, data); } /* @@ -194,25 +252,11 @@ static int get_vrregs(unsigned long __user *data, struct task_struct *task) */ static int set_vrregs(struct task_struct *task, unsigned long __user *data) { - unsigned long regsize; - - /* copy AltiVec registers VR[0] .. VR[31] */ - regsize = 32 * sizeof(vector128); - if (copy_from_user(task->thread.vr, data, regsize)) - return -EFAULT; - data += (regsize / sizeof(unsigned long)); - - /* copy VSCR */ - regsize = 1 * sizeof(vector128); - if (copy_from_user(&task->thread.vscr, data, regsize)) - return -EFAULT; - data += (regsize / sizeof(unsigned long)); - - /* copy VRSAVE */ - if (get_user(task->thread.vrsave, (u32 __user *)data)) + if (!access_ok(VERIFY_READ, data, 33 * sizeof(vector128) + sizeof(u32))) return -EFAULT; - return 0; + return vr_set(task, NULL, 0, 33 * sizeof(vector128) + sizeof(u32), + NULL, data); } #endif /* CONFIG_ALTIVEC */ -- cgit v1.2.3-18-g5258 From a4e4b175b6028ebfb2217e0ca1fa0487dc73ccc4 Mon Sep 17 00:00:00 2001 From: Roland McGrath Date: Thu, 20 Dec 2007 03:57:48 -0800 Subject: [POWERPC] Use user_regset accessors for SPE regs This implements user_regset-style accessors for the powerpc SPE data, and rewrites the existing ptrace code in terms of those calls. Signed-off-by: Roland McGrath Signed-off-by: Paul Mackerras --- arch/powerpc/kernel/ptrace.c | 90 ++++++++++++++++++++++++++++---------------- 1 file changed, 57 insertions(+), 33 deletions(-) (limited to 'arch/powerpc/kernel') diff --git a/arch/powerpc/kernel/ptrace.c b/arch/powerpc/kernel/ptrace.c index 7cdf35a7c83..8c25b003365 100644 --- a/arch/powerpc/kernel/ptrace.c +++ b/arch/powerpc/kernel/ptrace.c @@ -272,55 +272,79 @@ static int set_vrregs(struct task_struct *task, unsigned long __user *data) * } */ -/* - * Get contents of SPE register state in task TASK. - */ -static int get_evrregs(unsigned long *data, struct task_struct *task) +static int evr_active(struct task_struct *target, + const struct user_regset *regset) { - int i; + flush_spe_to_thread(target); + return target->thread.used_spe ? regset->n : 0; +} - if (!access_ok(VERIFY_WRITE, data, 35 * sizeof(unsigned long))) - return -EFAULT; +static int evr_get(struct task_struct *target, const struct user_regset *regset, + unsigned int pos, unsigned int count, + void *kbuf, void __user *ubuf) +{ + int ret; - /* copy SPEFSCR */ - if (__put_user(task->thread.spefscr, &data[34])) - return -EFAULT; + flush_spe_to_thread(target); - /* copy SPE registers EVR[0] .. EVR[31] */ - for (i = 0; i < 32; i++, data++) - if (__put_user(task->thread.evr[i], data)) - return -EFAULT; + ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf, + &target->thread.evr, + 0, sizeof(target->thread.evr)); - /* copy ACC */ - if (__put_user64(task->thread.acc, (unsigned long long *)data)) - return -EFAULT; + BUILD_BUG_ON(offsetof(struct thread_struct, acc) + sizeof(u64) != + offsetof(struct thread_struct, spefscr)); - return 0; + if (!ret) + ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf, + &target->thread.acc, + sizeof(target->thread.evr), -1); + + return ret; +} + +static int evr_set(struct task_struct *target, const struct user_regset *regset, + unsigned int pos, unsigned int count, + const void *kbuf, const void __user *ubuf) +{ + int ret; + + flush_spe_to_thread(target); + + ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf, + &target->thread.evr, + 0, sizeof(target->thread.evr)); + + BUILD_BUG_ON(offsetof(struct thread_struct, acc) + sizeof(u64) != + offsetof(struct thread_struct, spefscr)); + + if (!ret) + ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf, + &target->thread.acc, + sizeof(target->thread.evr), -1); + + return ret; } /* - * Write contents of SPE register state into task TASK. + * Get contents of SPE register state in task TASK. */ -static int set_evrregs(struct task_struct *task, unsigned long *data) +static int get_evrregs(unsigned long __user *data, struct task_struct *task) { - int i; - - if (!access_ok(VERIFY_READ, data, 35 * sizeof(unsigned long))) + if (!access_ok(VERIFY_WRITE, data, 35 * sizeof(u32))) return -EFAULT; - /* copy SPEFSCR */ - if (__get_user(task->thread.spefscr, &data[34])) - return -EFAULT; + return evr_get(task, NULL, 0, 35 * sizeof(u32), NULL, data); +} - /* copy SPE registers EVR[0] .. EVR[31] */ - for (i = 0; i < 32; i++, data++) - if (__get_user(task->thread.evr[i], data)) - return -EFAULT; - /* copy ACC */ - if (__get_user64(task->thread.acc, (unsigned long long*)data)) +/* + * Write contents of SPE register state into task TASK. + */ +static int set_evrregs(struct task_struct *task, unsigned long *data) +{ + if (!access_ok(VERIFY_READ, data, 35 * sizeof(u32))) return -EFAULT; - return 0; + return evr_set(task, NULL, 0, 35 * sizeof(u32), NULL, data); } #endif /* CONFIG_SPE */ -- cgit v1.2.3-18-g5258 From 26f7713020129e556e494fd36b2db1e651e33ba3 Mon Sep 17 00:00:00 2001 From: Roland McGrath Date: Thu, 20 Dec 2007 03:57:51 -0800 Subject: [POWERPC] ptrace accessors for special regs MSR and TRAP This isolates the ptrace code for the special-case registers msr and trap from the ptrace-layout dispatch code. This should inline away completely. It cleanly separates the low-level machine magic that has to be done for deep reasons, from the superficial details of the ptrace interface. Signed-off-by: Roland McGrath Signed-off-by: Paul Mackerras --- arch/powerpc/kernel/ptrace.c | 45 +++++++++++++++++++++++++++++--------------- 1 file changed, 30 insertions(+), 15 deletions(-) (limited to 'arch/powerpc/kernel') diff --git a/arch/powerpc/kernel/ptrace.c b/arch/powerpc/kernel/ptrace.c index 8c25b003365..4edc1186f6a 100644 --- a/arch/powerpc/kernel/ptrace.c +++ b/arch/powerpc/kernel/ptrace.c @@ -60,20 +60,38 @@ #define PT_MAX_PUT_REG PT_CCR #endif +static unsigned long get_user_msr(struct task_struct *task) +{ + return task->thread.regs->msr | task->thread.fpexc_mode; +} + +static int set_user_msr(struct task_struct *task, unsigned long msr) +{ + task->thread.regs->msr &= ~MSR_DEBUGCHANGE; + task->thread.regs->msr |= msr & MSR_DEBUGCHANGE; + return 0; +} + +/* + * We prevent mucking around with the reserved area of trap + * which are used internally by the kernel. + */ +static int set_user_trap(struct task_struct *task, unsigned long trap) +{ + task->thread.regs->trap = trap & 0xfff0; + return 0; +} + /* * Get contents of register REGNO in task TASK. */ unsigned long ptrace_get_reg(struct task_struct *task, int regno) { - unsigned long tmp = 0; - if (task->thread.regs == NULL) return -EIO; - if (regno == PT_MSR) { - tmp = ((unsigned long *)task->thread.regs)[PT_MSR]; - return tmp | task->thread.fpexc_mode; - } + if (regno == PT_MSR) + return get_user_msr(task); if (regno < (sizeof(struct pt_regs) / sizeof(unsigned long))) return ((unsigned long *)task->thread.regs)[regno]; @@ -89,15 +107,12 @@ int ptrace_put_reg(struct task_struct *task, int regno, unsigned long data) if (task->thread.regs == NULL) return -EIO; - if (regno <= PT_MAX_PUT_REG || regno == PT_TRAP) { - if (regno == PT_MSR) - data = (data & MSR_DEBUGCHANGE) - | (task->thread.regs->msr & ~MSR_DEBUGCHANGE); - /* We prevent mucking around with the reserved area of trap - * which are used internally by the kernel - */ - if (regno == PT_TRAP) - data &= 0xfff0; + if (regno == PT_MSR) + return set_user_msr(task, data); + if (regno == PT_TRAP) + return set_user_trap(task, data); + + if (regno <= PT_MAX_PUT_REG) { ((unsigned long *)task->thread.regs)[regno] = data; return 0; } -- cgit v1.2.3-18-g5258 From 44dd3f50d3848e332b49e83a142b39b960ec962e Mon Sep 17 00:00:00 2001 From: Roland McGrath Date: Thu, 20 Dec 2007 03:57:55 -0800 Subject: [POWERPC] Use user_regset accessors for GPRs This implements user_regset-style accessors for the powerpc general registers. In the future these functions will be the only place that needs to understand the user_regset layout (core dump format) and how it maps to the internal representation of user thread state. Signed-off-by: Roland McGrath Signed-off-by: Paul Mackerras --- arch/powerpc/kernel/ptrace.c | 91 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 91 insertions(+) (limited to 'arch/powerpc/kernel') diff --git a/arch/powerpc/kernel/ptrace.c b/arch/powerpc/kernel/ptrace.c index 4edc1186f6a..d9b952faee7 100644 --- a/arch/powerpc/kernel/ptrace.c +++ b/arch/powerpc/kernel/ptrace.c @@ -119,6 +119,97 @@ int ptrace_put_reg(struct task_struct *task, int regno, unsigned long data) return -EIO; } +static int gpr_get(struct task_struct *target, const struct user_regset *regset, + unsigned int pos, unsigned int count, + void *kbuf, void __user *ubuf) +{ + int ret; + + if (target->thread.regs == NULL) + return -EIO; + + CHECK_FULL_REGS(target->thread.regs); + + ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf, + target->thread.regs, + 0, offsetof(struct pt_regs, msr)); + if (!ret) { + unsigned long msr = get_user_msr(target); + ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf, &msr, + offsetof(struct pt_regs, msr), + offsetof(struct pt_regs, msr) + + sizeof(msr)); + } + + BUILD_BUG_ON(offsetof(struct pt_regs, orig_gpr3) != + offsetof(struct pt_regs, msr) + sizeof(long)); + + if (!ret) + ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf, + &target->thread.regs->orig_gpr3, + offsetof(struct pt_regs, orig_gpr3), + sizeof(struct pt_regs)); + if (!ret) + ret = user_regset_copyout_zero(&pos, &count, &kbuf, &ubuf, + sizeof(struct pt_regs), -1); + + return ret; +} + +static int gpr_set(struct task_struct *target, const struct user_regset *regset, + unsigned int pos, unsigned int count, + const void *kbuf, const void __user *ubuf) +{ + unsigned long reg; + int ret; + + if (target->thread.regs == NULL) + return -EIO; + + CHECK_FULL_REGS(target->thread.regs); + + ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf, + target->thread.regs, + 0, PT_MSR * sizeof(reg)); + + if (!ret && count > 0) { + ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf, ®, + PT_MSR * sizeof(reg), + (PT_MSR + 1) * sizeof(reg)); + if (!ret) + ret = set_user_msr(target, reg); + } + + BUILD_BUG_ON(offsetof(struct pt_regs, orig_gpr3) != + offsetof(struct pt_regs, msr) + sizeof(long)); + + if (!ret) + ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf, + &target->thread.regs->orig_gpr3, + PT_ORIG_R3 * sizeof(reg), + (PT_MAX_PUT_REG + 1) * sizeof(reg)); + + if (PT_MAX_PUT_REG + 1 < PT_TRAP && !ret) + ret = user_regset_copyin_ignore( + &pos, &count, &kbuf, &ubuf, + (PT_MAX_PUT_REG + 1) * sizeof(reg), + PT_TRAP * sizeof(reg)); + + if (!ret && count > 0) { + ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf, ®, + PT_TRAP * sizeof(reg), + (PT_TRAP + 1) * sizeof(reg)); + if (!ret) + ret = set_user_trap(target, reg); + } + + if (!ret) + ret = user_regset_copyin_ignore( + &pos, &count, &kbuf, &ubuf, + (PT_TRAP + 1) * sizeof(reg), -1); + + return ret; +} static int fpr_get(struct task_struct *target, const struct user_regset *regset, unsigned int pos, unsigned int count, -- cgit v1.2.3-18-g5258 From 80fdf4709497a276a826c9d8426ef1effc8f8e33 Mon Sep 17 00:00:00 2001 From: Roland McGrath Date: Thu, 20 Dec 2007 03:58:00 -0800 Subject: [POWERPC] Add user_regset_view definitions This provides the task_user_regset_view entry point and support for all the native-mode (64 on CONFIG_PPC64, 32 on CONFIG_PPC32) thread register state. This will enable generic machine-independent code to access user-mode threads' registers for debugging and dumping. Signed-off-by: Roland McGrath Signed-off-by: Paul Mackerras --- arch/powerpc/kernel/Makefile | 2 ++ arch/powerpc/kernel/ptrace.c | 52 ++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 54 insertions(+) (limited to 'arch/powerpc/kernel') diff --git a/arch/powerpc/kernel/Makefile b/arch/powerpc/kernel/Makefile index 58dbfeff9b4..ac07112b65d 100644 --- a/arch/powerpc/kernel/Makefile +++ b/arch/powerpc/kernel/Makefile @@ -2,6 +2,8 @@ # Makefile for the linux kernel. # +CFLAGS_ptrace.o += -DUTS_MACHINE='"$(UTS_MACHINE)"' + ifeq ($(CONFIG_PPC64),y) CFLAGS_prom_init.o += -mno-minimal-toc endif diff --git a/arch/powerpc/kernel/ptrace.c b/arch/powerpc/kernel/ptrace.c index d9b952faee7..eb00274e84b 100644 --- a/arch/powerpc/kernel/ptrace.c +++ b/arch/powerpc/kernel/ptrace.c @@ -455,6 +455,58 @@ static int set_evrregs(struct task_struct *task, unsigned long *data) #endif /* CONFIG_SPE */ +/* + * These are our native regset flavors. + */ +enum powerpc_regset { + REGSET_GPR, + REGSET_FPR, +#ifdef CONFIG_ALTIVEC + REGSET_VMX, +#endif +#ifdef CONFIG_SPE + REGSET_SPE, +#endif +}; + +static const struct user_regset native_regsets[] = { + [REGSET_GPR] = { + .core_note_type = NT_PRSTATUS, .n = ELF_NGREG, + .size = sizeof(long), .align = sizeof(long), + .get = gpr_get, .set = gpr_set + }, + [REGSET_FPR] = { + .core_note_type = NT_PRFPREG, .n = ELF_NFPREG, + .size = sizeof(double), .align = sizeof(double), + .get = fpr_get, .set = fpr_set + }, +#ifdef CONFIG_ALTIVEC + [REGSET_VMX] = { + .core_note_type = NT_PPC_VMX, .n = 34, + .size = sizeof(vector128), .align = sizeof(vector128), + .active = vr_active, .get = vr_get, .set = vr_set + }, +#endif +#ifdef CONFIG_SPE + [REGSET_SPE] = { + .n = 35, + .size = sizeof(u32), .align = sizeof(u32), + .active = evr_active, .get = evr_get, .set = evr_set + }, +#endif +}; + +static const struct user_regset_view user_ppc_native_view = { + .name = UTS_MACHINE, .e_machine = ELF_ARCH, .ei_osabi = ELF_OSABI, + .regsets = native_regsets, .n = ARRAY_SIZE(native_regsets) +}; + +const struct user_regset_view *task_user_regset_view(struct task_struct *task) +{ + return &user_ppc_native_view; +} + + void user_enable_single_step(struct task_struct *task) { struct pt_regs *regs = task->thread.regs; -- cgit v1.2.3-18-g5258 From fa8f5cb0c980e9fe3e04bc937fbd13417b52c046 Mon Sep 17 00:00:00 2001 From: Roland McGrath Date: Thu, 20 Dec 2007 03:58:08 -0800 Subject: [POWERPC] Add user_regset compat support This extends task_user_regset_view CONFIG_PPC64 with support for the 32-bit view of register state, compatible with what a CONFIG_PPC32 kernel provides. This will enable generic machine-independent code to access user-mode threads' registers for debugging and dumping. Signed-off-by: Roland McGrath Signed-off-by: Paul Mackerras --- arch/powerpc/kernel/ptrace.c | 162 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 162 insertions(+) (limited to 'arch/powerpc/kernel') diff --git a/arch/powerpc/kernel/ptrace.c b/arch/powerpc/kernel/ptrace.c index eb00274e84b..60de9ee3701 100644 --- a/arch/powerpc/kernel/ptrace.c +++ b/arch/powerpc/kernel/ptrace.c @@ -501,8 +501,170 @@ static const struct user_regset_view user_ppc_native_view = { .regsets = native_regsets, .n = ARRAY_SIZE(native_regsets) }; +#ifdef CONFIG_PPC64 +#include + +static int gpr32_get(struct task_struct *target, + const struct user_regset *regset, + unsigned int pos, unsigned int count, + void *kbuf, void __user *ubuf) +{ + const unsigned long *regs = &target->thread.regs->gpr[0]; + compat_ulong_t *k = kbuf; + compat_ulong_t __user *u = ubuf; + compat_ulong_t reg; + + if (target->thread.regs == NULL) + return -EIO; + + CHECK_FULL_REGS(target->thread.regs); + + pos /= sizeof(reg); + count /= sizeof(reg); + + if (kbuf) + for (; count > 0 && pos < PT_MSR; --count) + *k++ = regs[pos++]; + else + for (; count > 0 && pos < PT_MSR; --count) + if (__put_user((compat_ulong_t) regs[pos++], u++)) + return -EFAULT; + + if (count > 0 && pos == PT_MSR) { + reg = get_user_msr(target); + if (kbuf) + *k++ = reg; + else if (__put_user(reg, u++)) + return -EFAULT; + ++pos; + --count; + } + + if (kbuf) + for (; count > 0 && pos < PT_REGS_COUNT; --count) + *k++ = regs[pos++]; + else + for (; count > 0 && pos < PT_REGS_COUNT; --count) + if (__put_user((compat_ulong_t) regs[pos++], u++)) + return -EFAULT; + + kbuf = k; + ubuf = u; + pos *= sizeof(reg); + count *= sizeof(reg); + return user_regset_copyout_zero(&pos, &count, &kbuf, &ubuf, + PT_REGS_COUNT * sizeof(reg), -1); +} + +static int gpr32_set(struct task_struct *target, + const struct user_regset *regset, + unsigned int pos, unsigned int count, + const void *kbuf, const void __user *ubuf) +{ + unsigned long *regs = &target->thread.regs->gpr[0]; + const compat_ulong_t *k = kbuf; + const compat_ulong_t __user *u = ubuf; + compat_ulong_t reg; + + if (target->thread.regs == NULL) + return -EIO; + + CHECK_FULL_REGS(target->thread.regs); + + pos /= sizeof(reg); + count /= sizeof(reg); + + if (kbuf) + for (; count > 0 && pos < PT_MSR; --count) + regs[pos++] = *k++; + else + for (; count > 0 && pos < PT_MSR; --count) { + if (__get_user(reg, u++)) + return -EFAULT; + regs[pos++] = reg; + } + + + if (count > 0 && pos == PT_MSR) { + if (kbuf) + reg = *k++; + else if (__get_user(reg, u++)) + return -EFAULT; + set_user_msr(target, reg); + ++pos; + --count; + } + + if (kbuf) + for (; count > 0 && pos <= PT_MAX_PUT_REG; --count) + regs[pos++] = *k++; + else + for (; count > 0 && pos <= PT_MAX_PUT_REG; --count) { + if (__get_user(reg, u++)) + return -EFAULT; + regs[pos++] = reg; + } + + if (count > 0 && pos == PT_TRAP) { + if (kbuf) + reg = *k++; + else if (__get_user(reg, u++)) + return -EFAULT; + set_user_trap(target, reg); + ++pos; + --count; + } + + kbuf = k; + ubuf = u; + pos *= sizeof(reg); + count *= sizeof(reg); + return user_regset_copyin_ignore(&pos, &count, &kbuf, &ubuf, + (PT_TRAP + 1) * sizeof(reg), -1); +} + +/* + * These are the regset flavors matching the CONFIG_PPC32 native set. + */ +static const struct user_regset compat_regsets[] = { + [REGSET_GPR] = { + .core_note_type = NT_PRSTATUS, .n = ELF_NGREG, + .size = sizeof(compat_long_t), .align = sizeof(compat_long_t), + .get = gpr32_get, .set = gpr32_set + }, + [REGSET_FPR] = { + .core_note_type = NT_PRFPREG, .n = ELF_NFPREG, + .size = sizeof(double), .align = sizeof(double), + .get = fpr_get, .set = fpr_set + }, +#ifdef CONFIG_ALTIVEC + [REGSET_VMX] = { + .core_note_type = NT_PPC_VMX, .n = 34, + .size = sizeof(vector128), .align = sizeof(vector128), + .active = vr_active, .get = vr_get, .set = vr_set + }, +#endif +#ifdef CONFIG_SPE + [REGSET_SPE] = { + .n = 35, + .size = sizeof(u32), .align = sizeof(u32), + .active = evr_active, .get = evr_get, .set = evr_set + }, +#endif +}; + +static const struct user_regset_view user_ppc_compat_view = { + .name = "ppc", .e_machine = EM_PPC, .ei_osabi = ELF_OSABI, + .regsets = compat_regsets, .n = ARRAY_SIZE(compat_regsets) +}; +#endif /* CONFIG_PPC64 */ + const struct user_regset_view *task_user_regset_view(struct task_struct *task) { +#ifdef CONFIG_PPC64 + if (test_tsk_thread_flag(task, TIF_32BIT)) + return &user_ppc_compat_view; +#endif return &user_ppc_native_view; } -- cgit v1.2.3-18-g5258 From 01e31dbabc020bf82e7e5359c031a550daafb8ff Mon Sep 17 00:00:00 2001 From: Roland McGrath Date: Wed, 2 Jan 2008 17:03:11 -0800 Subject: [POWERPC] Switch to generic compat_binfmt_elf code This switches the CONFIG_PPC64 support for 32-bit ELF to use the generic fs/compat_binfmt_elf.c implementation instead of our own binfmt_elf32.c. Since so much is the same between 32/64, there is only one macro we have to define to make the generic support work out of the box. Signed-off-by: Roland McGrath Signed-off-by: Paul Mackerras --- arch/powerpc/kernel/Makefile | 2 +- arch/powerpc/kernel/binfmt_elf32.c | 69 -------------------------------------- 2 files changed, 1 insertion(+), 70 deletions(-) delete mode 100644 arch/powerpc/kernel/binfmt_elf32.c (limited to 'arch/powerpc/kernel') diff --git a/arch/powerpc/kernel/Makefile b/arch/powerpc/kernel/Makefile index ac07112b65d..0662ae46f72 100644 --- a/arch/powerpc/kernel/Makefile +++ b/arch/powerpc/kernel/Makefile @@ -17,7 +17,7 @@ obj-y := semaphore.o cputable.o ptrace.o syscalls.o \ init_task.o process.o systbl.o idle.o \ signal.o obj-y += vdso32/ -obj-$(CONFIG_PPC64) += setup_64.o binfmt_elf32.o sys_ppc32.o \ +obj-$(CONFIG_PPC64) += setup_64.o sys_ppc32.o \ signal_64.o ptrace32.o \ paca.o cpu_setup_ppc970.o \ cpu_setup_pa6t.o \ diff --git a/arch/powerpc/kernel/binfmt_elf32.c b/arch/powerpc/kernel/binfmt_elf32.c deleted file mode 100644 index 1d45d7782d4..00000000000 --- a/arch/powerpc/kernel/binfmt_elf32.c +++ /dev/null @@ -1,69 +0,0 @@ -/* - * binfmt_elf32.c: Support 32-bit PPC ELF binaries on Power3 and followons. - * based on the SPARC64 version. - * Copyright (C) 1995, 1996, 1997, 1998 David S. Miller (davem@redhat.com) - * Copyright (C) 1995, 1996, 1997, 1998 Jakub Jelinek (jj@ultra.linux.cz) - * - * Copyright (C) 2000,2001 Ken Aaker (kdaaker@rchland.vnet.ibm.com), IBM Corp - * Copyright (C) 2001 Anton Blanchard (anton@au.ibm.com), IBM - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version - * 2 of the License, or (at your option) any later version. - */ - -#include -#include -#include -#include - -#undef ELF_ARCH -#undef ELF_CLASS -#define ELF_CLASS ELFCLASS32 -#define ELF_ARCH EM_PPC - -#undef elfhdr -#undef elf_phdr -#undef elf_note -#undef elf_addr_t -#define elfhdr elf32_hdr -#define elf_phdr elf32_phdr -#define elf_note elf32_note -#define elf_addr_t Elf32_Off - -#define elf_prstatus compat_elf_prstatus -#define elf_prpsinfo compat_elf_prpsinfo - -#define elf_core_copy_regs compat_elf_core_copy_regs -static inline void compat_elf_core_copy_regs(compat_elf_gregset_t *elf_regs, - struct pt_regs *regs) -{ - PPC_ELF_CORE_COPY_REGS((*elf_regs), regs); -} - -#define elf_core_copy_task_regs compat_elf_core_copy_task_regs -static int compat_elf_core_copy_task_regs(struct task_struct *tsk, - compat_elf_gregset_t *elf_regs) -{ - struct pt_regs *regs = tsk->thread.regs; - if (regs) - compat_elf_core_copy_regs(elf_regs, regs); - return 1; -} - -#include - -#undef cputime_to_timeval -#define cputime_to_timeval cputime_to_compat_timeval -static __inline__ void -cputime_to_compat_timeval(const cputime_t cputime, struct compat_timeval *value) -{ - unsigned long jiffies = cputime_to_jiffies(cputime); - value->tv_usec = (jiffies % HZ) * (1000000L / HZ); - value->tv_sec = jiffies / HZ; -} - -#define init_elf_binfmt init_elf32_binfmt - -#include "../../../fs/binfmt_elf.c" -- cgit v1.2.3-18-g5258 From c391cd0093a2c86a6d1bc256198caad29fff0f60 Mon Sep 17 00:00:00 2001 From: Roland McGrath Date: Thu, 20 Dec 2007 03:58:36 -0800 Subject: [POWERPC] Use regset code for PTRACE_*REGS* requests This replaces all the code for powerpc PTRACE_*REGS* requests with simple calls to copy_regset_from_user and copy_regset_to_user. All the ptrace formats are either the whole corresponding user_regset format (core dump format) or a leading subset of it, so we can get rid of all the remaining embedded knowledge of both those layouts and of the internal data structures they correspond to. Only the user_regset accessors need to implement that. Signed-off-by: Roland McGrath Signed-off-by: Paul Mackerras --- arch/powerpc/kernel/ptrace.c | 234 +++++++++++-------------------------------- 1 file changed, 59 insertions(+), 175 deletions(-) (limited to 'arch/powerpc/kernel') diff --git a/arch/powerpc/kernel/ptrace.c b/arch/powerpc/kernel/ptrace.c index 60de9ee3701..2c1ee2cf941 100644 --- a/arch/powerpc/kernel/ptrace.c +++ b/arch/powerpc/kernel/ptrace.c @@ -237,24 +237,6 @@ static int fpr_set(struct task_struct *target, const struct user_regset *regset, &target->thread.fpr, 0, -1); } -static int get_fpregs(void __user *data, struct task_struct *task, - int has_fpscr) -{ - unsigned int count = has_fpscr ? 33 : 32; - if (!access_ok(VERIFY_WRITE, data, count * sizeof(double))) - return -EFAULT; - return fpr_get(task, NULL, 0, count * sizeof(double), NULL, data); -} - -static int set_fpregs(void __user *data, struct task_struct *task, - int has_fpscr) -{ - unsigned int count = has_fpscr ? 33 : 32; - if (!access_ok(VERIFY_READ, data, count * sizeof(double))) - return -EFAULT; - return fpr_set(task, NULL, 0, count * sizeof(double), NULL, data); -} - #ifdef CONFIG_ALTIVEC /* @@ -339,31 +321,6 @@ static int vr_set(struct task_struct *target, const struct user_regset *regset, return ret; } - -/* - * Get contents of AltiVec register state in task TASK - */ -static int get_vrregs(unsigned long __user *data, struct task_struct *task) -{ - if (!access_ok(VERIFY_WRITE, data, - 33 * sizeof(vector128) + sizeof(u32))) - return -EFAULT; - - return vr_get(task, NULL, 0, 33 * sizeof(vector128) + sizeof(u32), - NULL, data); -} - -/* - * Write contents of AltiVec register state into task TASK. - */ -static int set_vrregs(struct task_struct *task, unsigned long __user *data) -{ - if (!access_ok(VERIFY_READ, data, 33 * sizeof(vector128) + sizeof(u32))) - return -EFAULT; - - return vr_set(task, NULL, 0, 33 * sizeof(vector128) + sizeof(u32), - NULL, data); -} #endif /* CONFIG_ALTIVEC */ #ifdef CONFIG_SPE @@ -430,28 +387,6 @@ static int evr_set(struct task_struct *target, const struct user_regset *regset, return ret; } - -/* - * Get contents of SPE register state in task TASK. - */ -static int get_evrregs(unsigned long __user *data, struct task_struct *task) -{ - if (!access_ok(VERIFY_WRITE, data, 35 * sizeof(u32))) - return -EFAULT; - - return evr_get(task, NULL, 0, 35 * sizeof(u32), NULL, data); -} - -/* - * Write contents of SPE register state into task TASK. - */ -static int set_evrregs(struct task_struct *task, unsigned long *data) -{ - if (!access_ok(VERIFY_READ, data, 35 * sizeof(u32))) - return -EFAULT; - - return evr_set(task, NULL, 0, 35 * sizeof(u32), NULL, data); -} #endif /* CONFIG_SPE */ @@ -736,55 +671,29 @@ void ptrace_disable(struct task_struct *child) static long arch_ptrace_old(struct task_struct *child, long request, long addr, long data) { - int ret = -EPERM; - - switch(request) { - case PPC_PTRACE_GETREGS: { /* Get GPRs 0 - 31. */ - int i; - unsigned long *reg = &((unsigned long *)child->thread.regs)[0]; - unsigned long __user *tmp = (unsigned long __user *)addr; - - CHECK_FULL_REGS(child->thread.regs); - for (i = 0; i < 32; i++) { - ret = put_user(*reg, tmp); - if (ret) - break; - reg++; - tmp++; - } - break; - } - - case PPC_PTRACE_SETREGS: { /* Set GPRs 0 - 31. */ - int i; - unsigned long *reg = &((unsigned long *)child->thread.regs)[0]; - unsigned long __user *tmp = (unsigned long __user *)addr; - - CHECK_FULL_REGS(child->thread.regs); - for (i = 0; i < 32; i++) { - ret = get_user(*reg, tmp); - if (ret) - break; - reg++; - tmp++; - } - break; - } - - case PPC_PTRACE_GETFPREGS: { /* Get FPRs 0 - 31. */ - flush_fp_to_thread(child); - ret = get_fpregs((void __user *)addr, child, 0); - break; - } - - case PPC_PTRACE_SETFPREGS: { /* Get FPRs 0 - 31. */ - flush_fp_to_thread(child); - ret = set_fpregs((void __user *)addr, child, 0); - break; + switch (request) { + case PPC_PTRACE_GETREGS: /* Get GPRs 0 - 31. */ + return copy_regset_to_user(child, &user_ppc_native_view, + REGSET_GPR, 0, 32 * sizeof(long), + (void __user *) data); + + case PPC_PTRACE_SETREGS: /* Set GPRs 0 - 31. */ + return copy_regset_from_user(child, &user_ppc_native_view, + REGSET_GPR, 0, 32 * sizeof(long), + (const void __user *) data); + + case PPC_PTRACE_GETFPREGS: /* Get FPRs 0 - 31. */ + return copy_regset_to_user(child, &user_ppc_native_view, + REGSET_FPR, 0, 32 * sizeof(double), + (void __user *) data); + + case PPC_PTRACE_SETFPREGS: /* Set FPRs 0 - 31. */ + return copy_regset_from_user(child, &user_ppc_native_view, + REGSET_FPR, 0, 32 * sizeof(double), + (const void __user *) data); } - } - return ret; + return -EPERM; } long arch_ptrace(struct task_struct *child, long request, long addr, long data) @@ -875,85 +784,60 @@ long arch_ptrace(struct task_struct *child, long request, long addr, long data) #ifdef CONFIG_PPC64 case PTRACE_GETREGS64: #endif - case PTRACE_GETREGS: { /* Get all pt_regs from the child. */ - int ui; - if (!access_ok(VERIFY_WRITE, (void __user *)data, - sizeof(struct pt_regs))) { - ret = -EIO; - break; - } - CHECK_FULL_REGS(child->thread.regs); - ret = 0; - for (ui = 0; ui < PT_REGS_COUNT; ui ++) { - ret |= __put_user(ptrace_get_reg(child, ui), - (unsigned long __user *) data); - data += sizeof(long); - } - break; - } + case PTRACE_GETREGS: /* Get all pt_regs from the child. */ + return copy_regset_to_user(child, &user_ppc_native_view, + REGSET_GPR, + 0, sizeof(struct pt_regs), + (void __user *) data); #ifdef CONFIG_PPC64 case PTRACE_SETREGS64: #endif - case PTRACE_SETREGS: { /* Set all gp regs in the child. */ - unsigned long tmp; - int ui; - if (!access_ok(VERIFY_READ, (void __user *)data, - sizeof(struct pt_regs))) { - ret = -EIO; - break; - } - CHECK_FULL_REGS(child->thread.regs); - ret = 0; - for (ui = 0; ui < PT_REGS_COUNT; ui ++) { - ret = __get_user(tmp, (unsigned long __user *) data); - if (ret) - break; - ptrace_put_reg(child, ui, tmp); - data += sizeof(long); - } - break; - } - - case PTRACE_GETFPREGS: { /* Get the child FPU state (FPR0...31 + FPSCR) */ - flush_fp_to_thread(child); - ret = get_fpregs((void __user *)data, child, 1); - break; - } - - case PTRACE_SETFPREGS: { /* Set the child FPU state (FPR0...31 + FPSCR) */ - flush_fp_to_thread(child); - ret = set_fpregs((void __user *)data, child, 1); - break; - } + case PTRACE_SETREGS: /* Set all gp regs in the child. */ + return copy_regset_from_user(child, &user_ppc_native_view, + REGSET_GPR, + 0, sizeof(struct pt_regs), + (const void __user *) data); + + case PTRACE_GETFPREGS: /* Get the child FPU state (FPR0...31 + FPSCR) */ + return copy_regset_to_user(child, &user_ppc_native_view, + REGSET_FPR, + 0, sizeof(elf_fpregset_t), + (void __user *) data); + + case PTRACE_SETFPREGS: /* Set the child FPU state (FPR0...31 + FPSCR) */ + return copy_regset_from_user(child, &user_ppc_native_view, + REGSET_FPR, + 0, sizeof(elf_fpregset_t), + (const void __user *) data); #ifdef CONFIG_ALTIVEC case PTRACE_GETVRREGS: - /* Get the child altivec register state. */ - flush_altivec_to_thread(child); - ret = get_vrregs((unsigned long __user *)data, child); - break; + return copy_regset_to_user(child, &user_ppc_native_view, + REGSET_VMX, + 0, (33 * sizeof(vector128) + + sizeof(u32)), + (void __user *) data); case PTRACE_SETVRREGS: - /* Set the child altivec register state. */ - flush_altivec_to_thread(child); - ret = set_vrregs(child, (unsigned long __user *)data); - break; + return copy_regset_from_user(child, &user_ppc_native_view, + REGSET_VMX, + 0, (33 * sizeof(vector128) + + sizeof(u32)), + (const void __user *) data); #endif #ifdef CONFIG_SPE case PTRACE_GETEVRREGS: /* Get the child spe register state. */ - flush_spe_to_thread(child); - ret = get_evrregs((unsigned long __user *)data, child); - break; + return copy_regset_to_user(child, &user_ppc_native_view, + REGSET_SPE, 0, 35 * sizeof(u32), + (void __user *) data); case PTRACE_SETEVRREGS: /* Set the child spe register state. */ - /* this is to clear the MSR_SPE bit to force a reload - * of register state from memory */ - flush_spe_to_thread(child); - ret = set_evrregs(child, (unsigned long __user *)data); - break; + return copy_regset_from_user(child, &user_ppc_native_view, + REGSET_SPE, 0, 35 * sizeof(u32), + (const void __user *) data); #endif /* Old reverse args ptrace callss */ -- cgit v1.2.3-18-g5258 From c034243504b8396c4293abdc63aa3fc336a7d870 Mon Sep 17 00:00:00 2001 From: Roland McGrath Date: Thu, 20 Dec 2007 03:58:40 -0800 Subject: [POWERPC] Use generic ptrace peekdata/pokedata Now that ptrace_request handles these, we can drop some more boilerplate. Signed-off-by: Roland McGrath Signed-off-by: Paul Mackerras --- arch/powerpc/kernel/ptrace.c | 12 ------------ 1 file changed, 12 deletions(-) (limited to 'arch/powerpc/kernel') diff --git a/arch/powerpc/kernel/ptrace.c b/arch/powerpc/kernel/ptrace.c index 2c1ee2cf941..7571c2e2d99 100644 --- a/arch/powerpc/kernel/ptrace.c +++ b/arch/powerpc/kernel/ptrace.c @@ -701,12 +701,6 @@ long arch_ptrace(struct task_struct *child, long request, long addr, long data) int ret = -EPERM; switch (request) { - /* when I and D space are separate, these will need to be fixed. */ - case PTRACE_PEEKTEXT: /* read word at location addr. */ - case PTRACE_PEEKDATA: - ret = generic_ptrace_peekdata(child, addr, data); - break; - /* read the word at location addr in the USER area. */ case PTRACE_PEEKUSR: { unsigned long index, tmp; @@ -734,12 +728,6 @@ long arch_ptrace(struct task_struct *child, long request, long addr, long data) break; } - /* If I and D space are separate, this will have to be fixed. */ - case PTRACE_POKETEXT: /* write the word at location addr. */ - case PTRACE_POKEDATA: - ret = generic_ptrace_pokedata(child, addr, data); - break; - /* write the word at location addr in the USER area */ case PTRACE_POKEUSR: { unsigned long index; -- cgit v1.2.3-18-g5258 From 1d48d71c06172c0853e04c334456e64cc006e208 Mon Sep 17 00:00:00 2001 From: Roland McGrath Date: Thu, 20 Dec 2007 03:58:49 -0800 Subject: [POWERPC] Use generic compat_ptrace_request This removes some duplicated code by calling the new generic compat_ptrace_request from powerpc's compat_sys_ptrace. Signed-off-by: Roland McGrath Signed-off-by: Paul Mackerras --- arch/powerpc/kernel/ptrace32.c | 34 ++-------------------------------- 1 file changed, 2 insertions(+), 32 deletions(-) (limited to 'arch/powerpc/kernel') diff --git a/arch/powerpc/kernel/ptrace32.c b/arch/powerpc/kernel/ptrace32.c index fea6206ff90..6612304e11e 100644 --- a/arch/powerpc/kernel/ptrace32.c +++ b/arch/powerpc/kernel/ptrace32.c @@ -27,6 +27,7 @@ #include #include #include +#include #include #include @@ -112,20 +113,6 @@ long compat_sys_ptrace(int request, int pid, unsigned long addr, goto out_tsk; switch (request) { - /* when I and D space are separate, these will need to be fixed. */ - case PTRACE_PEEKTEXT: /* read word at location addr. */ - case PTRACE_PEEKDATA: { - unsigned int tmp; - int copied; - - copied = access_process_vm(child, addr, &tmp, sizeof(tmp), 0); - ret = -EIO; - if (copied != sizeof(tmp)) - break; - ret = put_user(tmp, (u32 __user *)data); - break; - } - /* * Read 4 bytes of the other process' storage * data is a pointer specifying where the user wants the @@ -225,19 +212,6 @@ long compat_sys_ptrace(int request, int pid, unsigned long addr, break; } - /* If I and D space are separate, this will have to be fixed. */ - case PTRACE_POKETEXT: /* write the word at location addr. */ - case PTRACE_POKEDATA: { - unsigned int tmp; - tmp = data; - ret = 0; - if (access_process_vm(child, addr, &tmp, sizeof(tmp), 1) - == sizeof(tmp)) - break; - ret = -EIO; - break; - } - /* * Write 4 bytes into the other process' storage * data is the 4 bytes that the user wants written @@ -337,10 +311,6 @@ long compat_sys_ptrace(int request, int pid, unsigned long addr, break; } - case PTRACE_GETEVENTMSG: - ret = put_user(child->ptrace_message, (unsigned int __user *) data); - break; - case PTRACE_GETREGS: { /* Get all pt_regs from the child. */ int ui; if (!access_ok(VERIFY_WRITE, (void __user *)data, @@ -402,7 +372,7 @@ long compat_sys_ptrace(int request, int pid, unsigned long addr, break; default: - ret = ptrace_request(child, request, addr, data); + ret = compat_ptrace_request(child, request, addr, data); break; } out_tsk: -- cgit v1.2.3-18-g5258 From 81e695c026eeda9a97e412fa4f458e5cab2f6c85 Mon Sep 17 00:00:00 2001 From: Roland McGrath Date: Thu, 20 Dec 2007 03:58:55 -0800 Subject: [POWERPC] Use generic compat_sys_ptrace This replaces powerpc's compat_sys_ptrace with a compat_arch_ptrace and enables the new generic definition of compat_sys_ptrace instead. Signed-off-by: Roland McGrath Signed-off-by: Paul Mackerras --- arch/powerpc/kernel/ptrace32.c | 33 +++++---------------------------- 1 file changed, 5 insertions(+), 28 deletions(-) (limited to 'arch/powerpc/kernel') diff --git a/arch/powerpc/kernel/ptrace32.c b/arch/powerpc/kernel/ptrace32.c index 6612304e11e..0f6eea086a2 100644 --- a/arch/powerpc/kernel/ptrace32.c +++ b/arch/powerpc/kernel/ptrace32.c @@ -85,33 +85,13 @@ static long compat_ptrace_old(struct task_struct *child, long request, return ret; } -long compat_sys_ptrace(int request, int pid, unsigned long addr, - unsigned long data) +long compat_arch_ptrace(struct task_struct *child, compat_long_t request, + compat_ulong_t caddr, compat_ulong_t cdata) { - struct task_struct *child; + unsigned long addr = caddr; + unsigned long data = cdata; int ret; - lock_kernel(); - if (request == PTRACE_TRACEME) { - ret = ptrace_traceme(); - goto out; - } - - child = ptrace_get_task_struct(pid); - if (IS_ERR(child)) { - ret = PTR_ERR(child); - goto out; - } - - if (request == PTRACE_ATTACH) { - ret = ptrace_attach(child); - goto out_tsk; - } - - ret = ptrace_check_attach(child, request == PTRACE_KILL); - if (ret < 0) - goto out_tsk; - switch (request) { /* * Read 4 bytes of the other process' storage @@ -375,9 +355,6 @@ long compat_sys_ptrace(int request, int pid, unsigned long addr, ret = compat_ptrace_request(child, request, addr, data); break; } -out_tsk: - put_task_struct(child); -out: - unlock_kernel(); + return ret; } -- cgit v1.2.3-18-g5258 From 0deef2c7ab9dcf82f6ad26fc2fca358cd56c9cb9 Mon Sep 17 00:00:00 2001 From: Roland McGrath Date: Thu, 20 Dec 2007 03:59:04 -0800 Subject: [POWERPC] Use regset code for compat PTRACE_*REGS* calls This cleans up the 32-bit ptrace syscall support to use user_regset calls to get at the register data for PTRACE_*REGS* calls. Signed-off-by: Roland McGrath Signed-off-by: Paul Mackerras --- arch/powerpc/kernel/ptrace32.c | 96 +++++++++++------------------------------- 1 file changed, 25 insertions(+), 71 deletions(-) (limited to 'arch/powerpc/kernel') diff --git a/arch/powerpc/kernel/ptrace32.c b/arch/powerpc/kernel/ptrace32.c index 0f6eea086a2..4c1de6af4c0 100644 --- a/arch/powerpc/kernel/ptrace32.c +++ b/arch/powerpc/kernel/ptrace32.c @@ -24,6 +24,7 @@ #include #include #include +#include #include #include #include @@ -46,43 +47,21 @@ static long compat_ptrace_old(struct task_struct *child, long request, long addr, long data) { - int ret = -EPERM; - - switch(request) { - case PPC_PTRACE_GETREGS: { /* Get GPRs 0 - 31. */ - int i; - unsigned long *reg = &((unsigned long *)child->thread.regs)[0]; - unsigned int __user *tmp = (unsigned int __user *)addr; - - CHECK_FULL_REGS(child->thread.regs); - for (i = 0; i < 32; i++) { - ret = put_user(*reg, tmp); - if (ret) - break; - reg++; - tmp++; - } - break; - } - - case PPC_PTRACE_SETREGS: { /* Set GPRs 0 - 31. */ - int i; - unsigned long *reg = &((unsigned long *)child->thread.regs)[0]; - unsigned int __user *tmp = (unsigned int __user *)addr; - - CHECK_FULL_REGS(child->thread.regs); - for (i = 0; i < 32; i++) { - ret = get_user(*reg, tmp); - if (ret) - break; - reg++; - tmp++; - } - break; + switch (request) { + case PPC_PTRACE_GETREGS: /* Get GPRs 0 - 31. */ + return copy_regset_to_user(child, + task_user_regset_view(current), 0, + 0, 32 * sizeof(compat_long_t), + compat_ptr(data)); + + case PPC_PTRACE_SETREGS: /* Set GPRs 0 - 31. */ + return copy_regset_from_user(child, + task_user_regset_view(current), 0, + 0, 32 * sizeof(compat_long_t), + compat_ptr(data)); } - } - return ret; + return -EPERM; } long compat_arch_ptrace(struct task_struct *child, compat_long_t request, @@ -291,42 +270,17 @@ long compat_arch_ptrace(struct task_struct *child, compat_long_t request, break; } - case PTRACE_GETREGS: { /* Get all pt_regs from the child. */ - int ui; - if (!access_ok(VERIFY_WRITE, (void __user *)data, - PT_REGS_COUNT * sizeof(int))) { - ret = -EIO; - break; - } - CHECK_FULL_REGS(child->thread.regs); - ret = 0; - for (ui = 0; ui < PT_REGS_COUNT; ui ++) { - ret |= __put_user(ptrace_get_reg(child, ui), - (unsigned int __user *) data); - data += sizeof(int); - } - break; - } - - case PTRACE_SETREGS: { /* Set all gp regs in the child. */ - unsigned long tmp; - int ui; - if (!access_ok(VERIFY_READ, (void __user *)data, - PT_REGS_COUNT * sizeof(int))) { - ret = -EIO; - break; - } - CHECK_FULL_REGS(child->thread.regs); - ret = 0; - for (ui = 0; ui < PT_REGS_COUNT; ui ++) { - ret = __get_user(tmp, (unsigned int __user *) data); - if (ret) - break; - ptrace_put_reg(child, ui, tmp); - data += sizeof(int); - } - break; - } + case PTRACE_GETREGS: /* Get all pt_regs from the child. */ + return copy_regset_to_user( + child, task_user_regset_view(current), 0, + 0, PT_REGS_COUNT * sizeof(compat_long_t), + compat_ptr(data)); + + case PTRACE_SETREGS: /* Set all gp regs in the child. */ + return copy_regset_from_user( + child, task_user_regset_view(current), 0, + 0, PT_REGS_COUNT * sizeof(compat_long_t), + compat_ptr(data)); case PTRACE_GETFPREGS: case PTRACE_SETFPREGS: -- cgit v1.2.3-18-g5258 From 24f1a849614ba1805e26a05da7cc8c6bd67490ea Mon Sep 17 00:00:00 2001 From: Roland McGrath Date: Wed, 2 Jan 2008 17:05:48 -0800 Subject: [POWERPC] Add SPE registers to core dumps This makes the SPE register data appear in ELF core dumps, using the new n_type value NT_PPC_SPE (0x101). This new note type is not used by any consumers of core files yet, but support can be added. I don't even have any hardware with SPE capabilities, so I've never seen such a note. But this demonstrates how simple it is to export register information in core dumps when the user_regset style is used for the low-level code. Signed-off-by: Roland McGrath Signed-off-by: Paul Mackerras --- arch/powerpc/kernel/ptrace.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'arch/powerpc/kernel') diff --git a/arch/powerpc/kernel/ptrace.c b/arch/powerpc/kernel/ptrace.c index 7571c2e2d99..7673e986573 100644 --- a/arch/powerpc/kernel/ptrace.c +++ b/arch/powerpc/kernel/ptrace.c @@ -581,7 +581,7 @@ static const struct user_regset compat_regsets[] = { #endif #ifdef CONFIG_SPE [REGSET_SPE] = { - .n = 35, + .core_note_type = NT_PPC_SPE, .n = 35, .size = sizeof(u32), .align = sizeof(u32), .active = evr_active, .get = evr_get, .set = evr_set }, -- cgit v1.2.3-18-g5258