* Re: Saving to 32 bits of GPRs in signal context
From: Benjamin Herrenschmidt @ 2007-05-30 11:23 UTC (permalink / raw)
To: Felix Domke; +Cc: linuxppc-dev list
In-Reply-To: <465C9F04.4070202@elitedvb.net>
> Anyway, please don't. It is *not* portable.
What are you talking about ? Really, I mean, I'm not sure I understand
what you mean :-)
> Or can you guarantee that no CPU ever will implement a.) only a 64bit
> subset or b.) other instructions using the same encoding as the 64bit
> insn you will use for testing?
Well, the idea is that we do expose via AT_HWCAP that the ppc64 insn set
is supported. I reckon we might just strip that bit for 32 bits
processes if they can't do 64 bits insn, no need to even get another
one.
> I still remember the pain of trying to tell that ffmpeg that my CPU
> can't do real altivec, even when it implements some parts of it without
> SIGILLing (which ffmpeg used for testing).
Yeah well, ffmpeg is crap, news at 11... there are ways to test wether
you have altivec or not (and more than one) but it looks like most
ffmpeg packages around don't care.
> And: What will happen if you manage to run your code under an operating
> system which doesn't even save the upper bits at all on interrupts? You
> can't check for that with SIGILL.
What are you talking about ? (bis) :-)
> Having a decent way (like aux/glibc) would also solve the problem with
> "incompatible CPUs", which you mentioned.
Ugh ?
Ben.
^ permalink raw reply
* Re: Porting "prep" from ppc to powerpc.
From: Benjamin Herrenschmidt @ 2007-05-30 11:19 UTC (permalink / raw)
To: Rob Landley; +Cc: linuxppc-dev
In-Reply-To: <200705291702.55060.rob@landley.net>
On Tue, 2007-05-29 at 17:02 -0400, Rob Landley wrote:
> I know just enough about Open
> Firmware to really dislike it,
You need to learn more or fix your taste :-)
Ben.
^ permalink raw reply
* Re: [PATCH 5/5] Set IDE in ULI1575 to not native mode.
From: Benjamin Herrenschmidt @ 2007-05-30 11:18 UTC (permalink / raw)
To: Kumar Gala; +Cc: linuxppc-dev, paulus
In-Reply-To: <A5691757-8218-489B-B809-DE44F81EA5C8@kernel.crashing.org>
On Tue, 2007-05-29 at 15:50 -0500, Kumar Gala wrote:
>
> > Set IDE in ULI1575 to not 100% native mode, which forces
> > the IDE driver to probe the irq itself.
> >
> > Signed-off-by: Zhang Wei <wei.zhang@freescale.com>
>
> What causes this to be needed?
Yeah, that looks dodgy. Native mode should generally work better
Ben.
^ permalink raw reply
* Re: Fix problems with Holly's DT representation of ethernet PHYs
From: Benjamin Herrenschmidt @ 2007-05-30 11:17 UTC (permalink / raw)
To: Josh Boyer
Cc: linuxppc-dev list, Alexandre Bounine, Paul Mackerras,
David Gibson
In-Reply-To: <1180466979.3360.69.camel@zod.rchland.ibm.com>
On Tue, 2007-05-29 at 14:29 -0500, Josh Boyer wrote:
>
> *shrug* Either way works for me.
>
> We're adding these compatible properties to DTS files and the drivers
> at
> the same time. Unless (until?) there are firmwares for these boards
> that start specifying something else in a real device tree, it really
> doesn't matter much. Not that there's anything wrong with your
> reasoning. Just seems like we're trying really hard to define
> something
> "correctly" when we control what's on both sides :).
>
I do think Segher is right there... compatible 109 and then 108
Ben.
^ permalink raw reply
* RE: [PATCH 2/5] Add uli1575 pci-bridge sector to MPC8641HPCN dts file.
From: Benjamin Herrenschmidt @ 2007-05-30 11:07 UTC (permalink / raw)
To: Zhang Wei-r63237; +Cc: linuxppc-dev list, Paul Mackerras
In-Reply-To: <46B96294322F7D458F9648B60E15112C3075B9@zch01exm26.fsl.freescale.net>
On Wed, 2007-05-30 at 18:02 +0800, Zhang Wei-r63237 wrote:
> Hi,
>
> > > + uli1575: uli1575@100 {
> >
> > is this the right address?
>
> '@100' of here, I make up the address by get from bus 1, device 0,
> function 0.
> Such as below '@200' means bus 2, device 0, function0.
It's PCI ? The unit address is well defined then, check the PCI bindings
to OF
Ben.
^ permalink raw reply
* [PATCH 2.6.22-rc3] ehea: Fixed multi queue RX bug
From: Thomas Klein @ 2007-05-30 10:39 UTC (permalink / raw)
To: Jeff Garzik
Cc: Thomas Klein, Jan-Bernd Themann, netdev, linux-kernel,
Christoph Raisch, Stefan Roscher, linux-ppc, Marcus Eder
Must access the respective queue's dummy netdev instead of the port's netdev.
Signed-off-by: Thomas Klein <tklein@de.ibm.com>
---
diff --git a/drivers/net/ehea/ehea.h b/drivers/net/ehea/ehea.h
index 602872d..e85a933 100644
--- a/drivers/net/ehea/ehea.h
+++ b/drivers/net/ehea/ehea.h
@@ -39,7 +39,7 @@
#include <asm/io.h>
#define DRV_NAME "ehea"
-#define DRV_VERSION "EHEA_0058"
+#define DRV_VERSION "EHEA_0061"
#define EHEA_MSG_DEFAULT (NETIF_MSG_LINK | NETIF_MSG_TIMER \
| NETIF_MSG_RX_ERR | NETIF_MSG_TX_ERR)
diff --git a/drivers/net/ehea/ehea_main.c b/drivers/net/ehea/ehea_main.c
index f6e0cb1..152bb20 100644
--- a/drivers/net/ehea/ehea_main.c
+++ b/drivers/net/ehea/ehea_main.c
@@ -428,7 +428,7 @@ static struct ehea_cqe *ehea_proc_rwqes(struct net_device *dev,
}
skb_copy_to_linear_data(skb, ((char*)cqe) + 64,
cqe->num_bytes_transfered - 4);
- ehea_fill_skb(dev, skb, cqe);
+ ehea_fill_skb(port->netdev, skb, cqe);
} else if (rq == 2) { /* RQ2 */
skb = get_skb_by_index(skb_arr_rq2,
skb_arr_rq2_len, cqe);
^ permalink raw reply related
* Re: [PATCH] [POWERPC] Fix viodasd geometry calculations.
From: Christoph Hellwig @ 2007-05-30 10:21 UTC (permalink / raw)
To: Stephen Rothwell; +Cc: ppc-dev, paulus, Christoph Hellwig
In-Reply-To: <20070529160654.8e12e507.sfr@canb.auug.org.au>
On Tue, May 29, 2007 at 04:06:54PM +1000, Stephen Rothwell wrote:
> Commit a885c8c4316e1c1d2d2c8755da3f3d14f852528d that introduced the
> getgeo block device method changed the fallback number of sectors and
> introduced a bug into the fallback cylinder number calculation.
Looking at the patch I can confirm that it introduced this abitrary
changes and your patch reverts it to the original.
ACK.
>
> Thanks to Rusty Russell for noticing this.
>
> Signed-off-by: Stephen Rothwell <sfr@canb.auug.org.au>
> ---
> drivers/block/viodasd.c | 4 ++--
> 1 files changed, 2 insertions(+), 2 deletions(-)
>
> Paul, this is not too urgent as in most (all) cases the fallbacks will
> not be taken.
>
> --
> Cheers,
> Stephen Rothwell sfr@canb.auug.org.au
>
> diff --git a/drivers/block/viodasd.c b/drivers/block/viodasd.c
> index 68592c3..dae3991 100644
> --- a/drivers/block/viodasd.c
> +++ b/drivers/block/viodasd.c
> @@ -252,10 +252,10 @@ static int viodasd_getgeo(struct block_device *bdev, struct hd_geometry *geo)
> struct gendisk *disk = bdev->bd_disk;
> struct viodasd_device *d = disk->private_data;
>
> - geo->sectors = d->sectors ? d->sectors : 0;
> + geo->sectors = d->sectors ? d->sectors : 32;
> geo->heads = d->tracks ? d->tracks : 64;
> geo->cylinders = d->cylinders ? d->cylinders :
> - get_capacity(disk) / (geo->cylinders * geo->heads);
> + get_capacity(disk) / (geo->sectors * geo->heads);
>
> return 0;
> }
> --
> 1.5.1.4
---end quoted text---
^ permalink raw reply
* Re: [PATCH 2/5] Add uli1575 pci-bridge sector to MPC8641HPCN dts file.
From: Segher Boessenkool @ 2007-05-30 10:18 UTC (permalink / raw)
To: Zhang Wei-r63237; +Cc: linuxppc-dev list, Paul Mackerras
In-Reply-To: <46B96294322F7D458F9648B60E15112C3075B9@zch01exm26.fsl.freescale.net>
>>> + uli1575: uli1575@100 {
>>
>> is this the right address?
>
> '@100' of here, I make up the address by get from bus 1, device 0,
> function 0.
> Such as below '@200' means bus 2, device 0, function0.
That is not how PCI unit addresses are encoded. There are
two forms: bla@D and bla@D,F where D and F are device# and
function# respectively. The bus# is implicit from the
parent node.
You have the "reg" property wrong, too (but differently).
Segher
^ permalink raw reply
* Re: [patch 6/7] ps3: ROM Storage Driver
From: Christoph Hellwig @ 2007-05-30 10:13 UTC (permalink / raw)
To: Geert Uytterhoeven
Cc: linuxppc-dev, Christoph Hellwig, linux-scsi, linux-kernel
In-Reply-To: <Pine.LNX.4.62.0705291308280.7698@pademelon.sonytel.be>
On Tue, May 29, 2007 at 01:11:41PM +0200, Geert Uytterhoeven wrote:
> > This looks very inefficient. Just set sg_tablesize of your driver
> > to 1 to avoid getting mutiple segments.
>
> The disadvantage of setting sg_tablesize = 1 is that the driver will get small
> requests (PAGE_SIZE) most of the time, which is very bad for performance.
If you set .clustering = 1 in your host template you will frequently
get larger requests.
For any sane hypervisor or hardware the copy should be worth
than that. Then again a sane hardware or hypervisor would support
SG requests..
^ permalink raw reply
* Re: [PATCH] remove geometry support from ps3 storage driver
From: Christoph Hellwig @ 2007-05-30 10:12 UTC (permalink / raw)
To: Geert Uytterhoeven; +Cc: linuxppc-dev, Olaf Hering, Christoph Hellwig
In-Reply-To: <Pine.LNX.4.62.0705291114340.7698@pademelon.sonytel.be>
On Tue, May 29, 2007 at 11:15:14AM +0200, Geert Uytterhoeven wrote:
> On Mon, 21 May 2007, Christoph Hellwig wrote:
> > On Mon, May 21, 2007 at 02:53:11PM +0200, Olaf Hering wrote:
> > > The old ps3_storage driver did not support DOS geometry, so there is no
> > > point to start adding code for it.
> >
> > That's not quite true. sd applies some heuristics and has a default
> > geometry if there is no ->bios_param method. Then again this whole
> > gemetry thing really only makes sense on x86.
>
> Would it make sense to have a default implementation in block/ioctl.c?
Maybe. Someone would have to look all over block drivers if there is
something common enough to be considered default. Also some drivers
that never ran on x86 never supported it so they'd need a new method
that always returns an error. I'm not sure whether it'll be worth it
in the end.
^ permalink raw reply
* Re: Saving to 32 bits of GPRs in signal context
From: Christoph Hellwig @ 2007-05-30 10:04 UTC (permalink / raw)
To: Becky Bruce
Cc: linuxppc-dev list, Steve Munroe, Ulrich Weigand, Paul Mackerras,
Anton Blanchard
In-Reply-To: <77D9DB04-FAD3-48EF-9159-5EA92BB366E5@freescale.com>
On Tue, May 29, 2007 at 02:04:02PM -0500, Becky Bruce wrote:
> I think that's exactly what Kumar's talking about. The assumption
> that all 64-bit Power processors will use those upper bits in some
> meaningful way is not valid. Also, ld and std do not architecturally
> "just work" on BookE implementations running in 32b mode. Those
> instructions are part of the 64-bit category in 2.03, and may illop
> on BookE processors running in 32b mode.
Then Bens suggest mode will only work on the sane IBM processors and
not the braindead freescale ones. Wouldn't be the first time.
^ permalink raw reply
* RE: [PATCH 2/5] Add uli1575 pci-bridge sector to MPC8641HPCN dts file.
From: Zhang Wei-r63237 @ 2007-05-30 10:02 UTC (permalink / raw)
To: Kumar Gala; +Cc: linuxppc-dev list, Paul Mackerras
In-Reply-To: <17B6534B-3C1C-433D-8875-1C2255E79D98@kernel.crashing.org>
Hi,=20
> > + uli1575: uli1575@100 {
>=20
> is this the right address?
'@100' of here, I make up the address by get from bus 1, device 0,
function 0.
Such as below '@200' means bus 2, device 0, function0.
^ permalink raw reply
* Re: [patch 6/7] ps3: ROM Storage Driver
From: Christoph Hellwig @ 2007-05-30 10:01 UTC (permalink / raw)
To: Geert Uytterhoeven
Cc: linuxppc-dev, Christoph Hellwig, linux-scsi, linux-kernel
In-Reply-To: <Pine.LNX.4.62.0705291818560.7698@pademelon.sonytel.be>
On Tue, May 29, 2007 at 06:21:36PM +0200, Geert Uytterhoeven wrote:
> On Tue, 29 May 2007, Christoph Hellwig wrote:
> > > +/*
> > > + * copy data from device into scatter/gather buffer
> > > + */
> > > +static int fill_from_dev_buffer(struct scsi_cmnd *cmd, const void *buf,
> > > + int buflen)
> > > +{
> > > + int k, req_len, act_len, len, active;
> > > + void *kaddr;
> > > + struct scatterlist *sgpnt;
> > > +
> > > + if (!cmd->request_bufflen)
> > > + return 0;
> > > +
> > > + if (!cmd->request_buffer)
> > > + return DID_ERROR << 16;
> > > +
> > > + if (cmd->sc_data_direction != DMA_BIDIRECTIONAL &&
> > > + cmd->sc_data_direction != DMA_FROM_DEVICE)
> > > + return DID_ERROR << 16;
> > > +
> > > + if (!cmd->use_sg) {
> > > + req_len = cmd->request_bufflen;
> > > + act_len = min(req_len, buflen);
> > > + memcpy(cmd->request_buffer, buf, act_len);
> > > + cmd->resid = req_len - act_len;
> > > + return 0;
> > > + }
> >
> > This is never true anymore.
>
> Just to be sure: all four if-cases or only the last one?
That's just in reference to the last one. The checks above could
be condensed a little more aswell, but I'll comment on further in
the second round of review, in the hope that the command submission
path is a lot more streamline by then already.
^ permalink raw reply
* [RFC/PATCH x/x] ... bad numbering
From: Benjamin Herrenschmidt @ 2007-05-30 8:06 UTC (permalink / raw)
To: linuxppc-dev; +Cc: ulrich.weigand, Paul Mackerras, Anton Blanchard
In-Reply-To: <20070530071729.7E636DE05B@ozlabs.org>
Sorry for the split in 2 series, mistake on my side, it's actually one
serie of 10 patches.
Ben.
^ permalink raw reply
* [RFC/PATCH 4/4] powerpc: Make syscall restart code more common
From: Benjamin Herrenschmidt @ 2007-05-30 8:05 UTC (permalink / raw)
To: linuxppc-dev; +Cc: ulrich.weigand, Paul Mackerras, Anton Blanchard
This patch moves the code in signal_32.c and signal_64.c for handling
syscall restart into a common signal-common.h file and converge around
a single implementation that is based on the 32 bits one, using trap, ccr
and r3 rather than the special "result" field for deciding what to do.
The "result" field is now pretty much deprecated. We still set it for
the sake of whatever might rely on it in userland but we no longer use
it's content.
This, along with a previous patch that enables ptracers to write to
"trap" and "orig_r3" should allow gdb to properly handle syscall
restarting.
There is only one common function for now and it's small enough so
having it inline is fine. However, there is probably room for more
merging of _32.c and _64.c in which case we'll probably want to
have a common .c file and avoid inlines.
Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
---
arch/powerpc/kernel/signal-common.h | 66 ++++++++++++++++++++++++++++++++++++
arch/powerpc/kernel/signal_32.c | 28 ++-------------
arch/powerpc/kernel/signal_64.c | 59 +++-----------------------------
3 files changed, 77 insertions(+), 76 deletions(-)
Index: linux-cell/arch/powerpc/kernel/signal-common.h
===================================================================
--- /dev/null 1970-01-01 00:00:00.000000000 +0000
+++ linux-cell/arch/powerpc/kernel/signal-common.h 2007-05-30 16:47:12.000000000 +1000
@@ -0,0 +1,66 @@
+/*
+ * Copyright (c) 2007 Benjamin Herrenschmidt, IBM Coproration
+ * Extracted from signal_32.c and signal_64.c
+ *
+ * This file is subject to the terms and conditions of the GNU General
+ * Public License. See the file README.legal in the main directory of
+ * this archive for more details.
+ */
+
+#ifndef _POWERPC_SIGNAL_COMMON_H
+#define _POWERPC_SIGNAL_COMMON_H
+
+static inline void check_syscall_restart(struct pt_regs *regs,
+ struct k_sigaction *ka,
+ int has_handler)
+{
+ unsigned long ret = regs->gpr[3];
+ int restart = 1;
+
+ /* syscall ? */
+ if (TRAP(regs) != 0x0C00)
+ return;
+
+ /* error signalled ? */
+ if (!(regs->ccr & 0x10000000))
+ return;
+
+ switch (ret) {
+ case ERESTART_RESTARTBLOCK:
+ case ERESTARTNOHAND:
+ /* ERESTARTNOHAND means that the syscall should only be
+ * restarted if there was no handler for the signal, and since
+ * we only get here if there is a handler, we dont restart.
+ */
+ restart = !has_handler;
+ break;
+ case ERESTARTSYS:
+ /* ERESTARTSYS means to restart the syscall if there is no
+ * handler or the handler was registered with SA_RESTART
+ */
+ restart = !has_handler || (ka->sa.sa_flags & SA_RESTART) != 0;
+ break;
+ case ERESTARTNOINTR:
+ /* ERESTARTNOINTR means that the syscall should be
+ * called again after the signal handler returns.
+ */
+ break;
+ default:
+ return;
+ }
+ if (restart) {
+ if (ret == ERESTART_RESTARTBLOCK)
+ regs->gpr[0] = __NR_restart_syscall;
+ else
+ regs->gpr[3] = regs->orig_gpr3;
+ regs->nip -= 4;
+ regs->result = 0;
+ } else {
+ regs->result = -EINTR;
+ regs->gpr[3] = EINTR;
+ regs->ccr |= 0x10000000;
+ }
+}
+
+
+#endif /* _POWERPC_SIGNAL_COMMON_H */
Index: linux-cell/arch/powerpc/kernel/signal_32.c
===================================================================
--- linux-cell.orig/arch/powerpc/kernel/signal_32.c 2007-05-30 16:45:57.000000000 +1000
+++ linux-cell/arch/powerpc/kernel/signal_32.c 2007-05-30 16:47:16.000000000 +1000
@@ -51,6 +51,8 @@
#include <asm/pgtable.h>
#endif
+#include "signal-common.h"
+
#undef DEBUG_SIG
#define _BLOCKABLE (~(sigmask(SIGKILL) | sigmask(SIGSTOP)))
@@ -1156,30 +1158,8 @@ int do_signal(sigset_t *oldset, struct p
#ifdef CONFIG_PPC32
no_signal:
#endif
- if (TRAP(regs) == 0x0C00 /* System Call! */
- && regs->ccr & 0x10000000 /* error signalled */
- && ((ret = regs->gpr[3]) == ERESTARTSYS
- || ret == ERESTARTNOHAND || ret == ERESTARTNOINTR
- || ret == ERESTART_RESTARTBLOCK)) {
-
- if (signr > 0
- && (ret == ERESTARTNOHAND || ret == ERESTART_RESTARTBLOCK
- || (ret == ERESTARTSYS
- && !(ka.sa.sa_flags & SA_RESTART)))) {
- /* make the system call return an EINTR error */
- regs->result = -EINTR;
- regs->gpr[3] = EINTR;
- /* note that the cr0.SO bit is already set */
- } else {
- regs->nip -= 4; /* Back up & retry system call */
- regs->result = 0;
- regs->trap = 0;
- if (ret == ERESTART_RESTARTBLOCK)
- regs->gpr[0] = __NR_restart_syscall;
- else
- regs->gpr[3] = regs->orig_gpr3;
- }
- }
+ /* Is there any syscall restart business here ? */
+ check_syscall_restart(regs, &ka, signr > 0);
if (signr == 0) {
/* No signal to deliver -- put the saved sigmask back */
Index: linux-cell/arch/powerpc/kernel/signal_64.c
===================================================================
--- linux-cell.orig/arch/powerpc/kernel/signal_64.c 2007-05-30 16:45:57.000000000 +1000
+++ linux-cell/arch/powerpc/kernel/signal_64.c 2007-05-30 16:47:12.000000000 +1000
@@ -34,6 +34,8 @@
#include <asm/syscalls.h>
#include <asm/vdso.h>
+#include "signal-common.h"
+
#define DEBUG_SIG 0
#define _BLOCKABLE (~(sigmask(SIGKILL) | sigmask(SIGSTOP)))
@@ -463,41 +465,6 @@ static int handle_signal(unsigned long s
return ret;
}
-static inline void syscall_restart(struct pt_regs *regs, struct k_sigaction *ka)
-{
- switch ((int)regs->result) {
- case -ERESTART_RESTARTBLOCK:
- case -ERESTARTNOHAND:
- /* ERESTARTNOHAND means that the syscall should only be
- * restarted if there was no handler for the signal, and since
- * we only get here if there is a handler, we dont restart.
- */
- regs->result = -EINTR;
- regs->gpr[3] = EINTR;
- regs->ccr |= 0x10000000;
- break;
- case -ERESTARTSYS:
- /* ERESTARTSYS means to restart the syscall if there is no
- * handler or the handler was registered with SA_RESTART
- */
- if (!(ka->sa.sa_flags & SA_RESTART)) {
- regs->result = -EINTR;
- regs->gpr[3] = EINTR;
- regs->ccr |= 0x10000000;
- break;
- }
- /* fallthrough */
- case -ERESTARTNOINTR:
- /* ERESTARTNOINTR means that the syscall should be
- * called again after the signal handler returns.
- */
- regs->gpr[3] = regs->orig_gpr3;
- regs->nip -= 4;
- regs->result = 0;
- break;
- }
-}
-
/*
* Note that 'init' is a special process: it doesn't get signals it doesn't
* want to handle. Thus you cannot kill init even with a SIGKILL even by
@@ -522,13 +489,13 @@ int do_signal(sigset_t *oldset, struct p
oldset = ¤t->blocked;
signr = get_signal_to_deliver(&info, &ka, regs, NULL);
+
+ /* Is there any syscall restart business here ? */
+ check_syscall_restart(regs, &ka, signr > 0);
+
if (signr > 0) {
int ret;
- /* Whee! Actually deliver the signal. */
- if (TRAP(regs) == 0x0C00)
- syscall_restart(regs, &ka);
-
/*
* Reenable the DABR before delivering the signal to
* user space. The DABR will have been cleared if it
@@ -537,6 +504,7 @@ int do_signal(sigset_t *oldset, struct p
if (current->thread.dabr)
set_dabr(current->thread.dabr);
+ /* Whee! Actually deliver the signal. */
ret = handle_signal(signr, &ka, &info, oldset, regs);
/* If a signal was successfully delivered, the saved sigmask is in
@@ -547,19 +515,6 @@ int do_signal(sigset_t *oldset, struct p
return ret;
}
- if (TRAP(regs) == 0x0C00) { /* System Call! */
- if ((int)regs->result == -ERESTARTNOHAND ||
- (int)regs->result == -ERESTARTSYS ||
- (int)regs->result == -ERESTARTNOINTR) {
- regs->gpr[3] = regs->orig_gpr3;
- regs->nip -= 4; /* Back up & retry system call */
- regs->result = 0;
- } else if ((int)regs->result == -ERESTART_RESTARTBLOCK) {
- regs->gpr[0] = __NR_restart_syscall;
- regs->nip -= 4;
- regs->result = 0;
- }
- }
/* No signal to deliver -- put the saved sigmask back */
if (test_thread_flag(TIF_RESTORE_SIGMASK)) {
clear_thread_flag(TIF_RESTORE_SIGMASK);
^ permalink raw reply
* [RFC/PATCH 3/4] powerpc: Always apply DABR changes on context switches
From: Benjamin Herrenschmidt @ 2007-05-30 8:05 UTC (permalink / raw)
To: linuxppc-dev; +Cc: ulrich.weigand, Paul Mackerras, Anton Blanchard
This patch removes the #ifdef CONFIG_PPC64 around setting the DABR.
The actual setting of the SPR inside of the set_dabr() function is dependant
on CONFIG_PPC64 || CONFIG_6xx but you can always provide a ppc_md hook to
override that. We should improve support for different HW breakpoints
facilities but this is a first step.
Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
---
arch/powerpc/kernel/process.c | 14 +++++++-------
1 file changed, 7 insertions(+), 7 deletions(-)
Index: linux-cell/arch/powerpc/kernel/process.c
===================================================================
--- linux-cell.orig/arch/powerpc/kernel/process.c 2007-05-30 16:22:10.000000000 +1000
+++ linux-cell/arch/powerpc/kernel/process.c 2007-05-30 16:28:08.000000000 +1000
@@ -219,22 +219,26 @@ void discard_lazy_cpu_state(void)
}
#endif /* CONFIG_SMP */
-#ifdef CONFIG_PPC_MERGE /* XXX for now */
int set_dabr(unsigned long dabr)
{
+#ifdef CONFIG_PPC_MERGE /* XXX for now */
if (ppc_md.set_dabr)
return ppc_md.set_dabr(dabr);
+#endif
+ /* XXX should we have a CPU_FTR_HAS_DABR ? */
+#if defined(CONFIG_PPC64) || defined(CONFIG_6xx)
mtspr(SPRN_DABR, dabr);
+#endif
return 0;
}
-#endif
#ifdef CONFIG_PPC64
DEFINE_PER_CPU(struct cpu_usage, cpu_usage_array);
-static DEFINE_PER_CPU(unsigned long, current_dabr);
#endif
+static DEFINE_PER_CPU(unsigned long, current_dabr);
+
struct task_struct *__switch_to(struct task_struct *prev,
struct task_struct *new)
{
@@ -299,12 +303,10 @@ struct task_struct *__switch_to(struct t
#endif /* CONFIG_SMP */
-#ifdef CONFIG_PPC64 /* for now */
if (unlikely(__get_cpu_var(current_dabr) != new->thread.dabr)) {
set_dabr(new->thread.dabr);
__get_cpu_var(current_dabr) = new->thread.dabr;
}
-#endif /* CONFIG_PPC64 */
new_thread = &new->thread;
old_thread = ¤t->thread;
@@ -473,12 +475,10 @@ void flush_thread(void)
discard_lazy_cpu_state();
-#ifdef CONFIG_PPC64 /* for now */
if (current->thread.dabr) {
current->thread.dabr = 0;
set_dabr(0);
}
-#endif
}
void
^ permalink raw reply
* [RFC/PATCH 2/4] powerpc: ptrace can set DABR on both 32 and 64 bits
From: Benjamin Herrenschmidt @ 2007-05-30 8:05 UTC (permalink / raw)
To: linuxppc-dev; +Cc: ulrich.weigand, Paul Mackerras, Anton Blanchard
Allow ptrace to set dabr in the thread structure for both 32 and 64 bits,
though only 64 bits actually uses that field, it's actually defined in both.
Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
---
arch/powerpc/kernel/ptrace.c | 4 ----
1 file changed, 4 deletions(-)
Index: linux-cell/arch/powerpc/kernel/ptrace.c
===================================================================
--- linux-cell.orig/arch/powerpc/kernel/ptrace.c 2007-05-30 16:21:12.000000000 +1000
+++ linux-cell/arch/powerpc/kernel/ptrace.c 2007-05-30 16:21:22.000000000 +1000
@@ -286,7 +286,6 @@ static void clear_single_step(struct tas
clear_tsk_thread_flag(task, TIF_SINGLESTEP);
}
-#ifdef CONFIG_PPC64
static int ptrace_set_debugreg(struct task_struct *task, unsigned long addr,
unsigned long data)
{
@@ -305,7 +304,6 @@ static int ptrace_set_debugreg(struct ta
task->thread.dabr = data;
return 0;
}
-#endif
/*
* Called by kernel/ptrace.c when detaching..
@@ -503,7 +501,6 @@ long arch_ptrace(struct task_struct *chi
break;
}
-#ifdef CONFIG_PPC64
case PTRACE_GET_DEBUGREG: {
ret = -EINVAL;
/* We only support one DABR and no IABRS at the moment */
@@ -517,7 +514,6 @@ long arch_ptrace(struct task_struct *chi
case PTRACE_SET_DEBUGREG:
ret = ptrace_set_debugreg(child, addr, data);
break;
-#endif
case PTRACE_DETACH:
ret = ptrace_detach(child, data);
^ permalink raw reply
* [RFC/PATCH 1/4] powerpc: ptrace shouldn't touch FP exec mode
From: Benjamin Herrenschmidt @ 2007-05-30 8:05 UTC (permalink / raw)
To: linuxppc-dev; +Cc: ulrich.weigand, Paul Mackerras, Anton Blanchard
One of the gratuituous difference between 32 and 64 bits ptrace is wether
you can whack the MSR:FE0 and FE1 bits from ptrace. This patch forbids it
unconditionally. In addition, 64 bits kernels used to return the exec mode
in the MSR on reads but not 32 bits. This patch makes it return those bits
on both.
Finally, since ptrace-ppc32.h and ptrace-ppc64.h are mostly empty now, and
since the previous patch made ptrace32.c no longer need the MSR_DEBUGCHANGE
definition, we just remove those 2 files and move back the remaining bits
to ptrace.c (they were short lived heh ?)
Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
---
arch/powerpc/kernel/ptrace-ppc32.h | 35 -------------------------
arch/powerpc/kernel/ptrace-ppc64.h | 51 -------------------------------------
arch/powerpc/kernel/ptrace.c | 45 ++++++++++++++++++++++++++++----
arch/powerpc/kernel/ptrace32.c | 2 -
4 files changed, 39 insertions(+), 94 deletions(-)
Index: linux-cell/arch/powerpc/kernel/ptrace-ppc32.h
===================================================================
--- linux-cell.orig/arch/powerpc/kernel/ptrace-ppc32.h 2007-05-30 16:15:25.000000000 +1000
+++ /dev/null 1970-01-01 00:00:00.000000000 +0000
@@ -1,35 +0,0 @@
-/*
- * Copyright (c) 2007 Benjamin Herrenschmidt, IBM Coproration
- * Extracted from ptrace.c and ptrace32.c
- *
- * This file is subject to the terms and conditions of the GNU General
- * Public License. See the file README.legal in the main directory of
- * this archive for more details.
- */
-
-#ifndef _POWERPC_PTRACE_PPC32_H
-#define _POWERPC_PTRACE_PPC32_H
-
-/*
- * Set of msr bits that gdb can change on behalf of a process.
- */
-#if defined(CONFIG_40x) || defined(CONFIG_BOOKE)
-#define MSR_DEBUGCHANGE 0
-#else
-#define MSR_DEBUGCHANGE (MSR_SE | MSR_BE)
-#endif
-
-/*
- * Max register writeable via put_reg
- */
-#define PT_MAX_PUT_REG PT_MQ
-
-/*
- * Munging of MSR on return from get_regs
- *
- * Nothing to do on ppc32
- */
-#define PT_MUNGE_MSR(msr, task) (msr)
-
-
-#endif /* _POWERPC_PTRACE_PPC32_H */
Index: linux-cell/arch/powerpc/kernel/ptrace-ppc64.h
===================================================================
--- linux-cell.orig/arch/powerpc/kernel/ptrace-ppc64.h 2007-05-30 16:15:25.000000000 +1000
+++ /dev/null 1970-01-01 00:00:00.000000000 +0000
@@ -1,51 +0,0 @@
-/*
- * Copyright (c) 2002 Stephen Rothwell, IBM Coproration
- * Extracted from ptrace.c and ptrace32.c
- *
- * This file is subject to the terms and conditions of the GNU General
- * Public License. See the file README.legal in the main directory of
- * this archive for more details.
- */
-
-#ifndef _POWERPC_PTRACE_PPC64_H
-#define _POWERPC_PTRACE_PPC64_H
-
-/*
- * Set of msr bits that gdb can change on behalf of a process.
- */
-#define MSR_DEBUGCHANGE (MSR_FE0 | MSR_SE | MSR_BE | MSR_FE1)
-
-/*
- * Max register writeable via put_reg
- */
-#define PT_MAX_PUT_REG PT_CCR
-
-/*
- * Munging of MSR on return from get_regs
- *
- * Put the correct FP bits in, they might be wrong as a result
- * of our lazy FP restore.
- */
-
-#define PT_MUNGE_MSR(msr, task) ({ (msr) | (task)->thread.fpexc_mode; })
-
-static inline int ptrace_set_debugreg(struct task_struct *task,
- unsigned long addr, unsigned long data)
-{
- /* We only support one DABR and no IABRS at the moment */
- if (addr > 0)
- return -EINVAL;
-
- /* The bottom 3 bits are flags */
- if ((data & ~0x7UL) >= TASK_SIZE)
- return -EIO;
-
- /* Ensure translation is on */
- if (data && !(data & DABR_TRANSLATION))
- return -EIO;
-
- task->thread.dabr = data;
- return 0;
-}
-
-#endif /* _POWERPC_PTRACE_PPC64_H */
Index: linux-cell/arch/powerpc/kernel/ptrace.c
===================================================================
--- linux-cell.orig/arch/powerpc/kernel/ptrace.c 2007-05-30 16:15:39.000000000 +1000
+++ linux-cell/arch/powerpc/kernel/ptrace.c 2007-05-30 16:29:06.000000000 +1000
@@ -35,16 +35,28 @@
#include <asm/pgtable.h>
#include <asm/system.h>
-#ifdef CONFIG_PPC64
-#include "ptrace-ppc64.h"
+/*
+ * does not yet catch signals sent when the child dies.
+ * in exit.c or in signal.c.
+ */
+
+/*
+ * Set of msr bits that gdb can change on behalf of a process.
+ */
+#if defined(CONFIG_40x) || defined(CONFIG_BOOKE)
+#define MSR_DEBUGCHANGE 0
#else
-#include "ptrace-ppc32.h"
+#define MSR_DEBUGCHANGE (MSR_SE | MSR_BE)
#endif
/*
- * does not yet catch signals sent when the child dies.
- * in exit.c or in signal.c.
+ * Max register writeable via put_reg
*/
+#ifdef CONFIG_PPC32
+#define PT_MAX_PUT_REG PT_MQ
+#else
+#define PT_MAX_PUT_REG PT_CCR
+#endif
/*
* Get contents of register REGNO in task TASK.
@@ -58,7 +70,7 @@ unsigned long ptrace_get_reg(struct task
if (regno == PT_MSR) {
tmp = ((unsigned long *)task->thread.regs)[PT_MSR];
- return PT_MUNGE_MSR(tmp, task);
+ return tmp | task->thread.fpexc_mode;
}
if (regno < (sizeof(struct pt_regs) / sizeof(unsigned long)))
@@ -274,6 +286,27 @@ static void clear_single_step(struct tas
clear_tsk_thread_flag(task, TIF_SINGLESTEP);
}
+#ifdef CONFIG_PPC64
+static int ptrace_set_debugreg(struct task_struct *task, unsigned long addr,
+ unsigned long data)
+{
+ /* We only support one DABR and no IABRS at the moment */
+ if (addr > 0)
+ return -EINVAL;
+
+ /* The bottom 3 bits are flags */
+ if ((data & ~0x7UL) >= TASK_SIZE)
+ return -EIO;
+
+ /* Ensure translation is on */
+ if (data && !(data & DABR_TRANSLATION))
+ return -EIO;
+
+ task->thread.dabr = data;
+ return 0;
+}
+#endif
+
/*
* Called by kernel/ptrace.c when detaching..
*
Index: linux-cell/arch/powerpc/kernel/ptrace32.c
===================================================================
--- linux-cell.orig/arch/powerpc/kernel/ptrace32.c 2007-05-30 16:15:39.000000000 +1000
+++ linux-cell/arch/powerpc/kernel/ptrace32.c 2007-05-30 16:15:40.000000000 +1000
@@ -33,8 +33,6 @@
#include <asm/pgtable.h>
#include <asm/system.h>
-#include "ptrace-ppc64.h"
-
/*
* does not yet catch signals sent when the child dies.
* in exit.c or in signal.c.
^ permalink raw reply
* Re: Saving to 32 bits of GPRs in signal context
From: Hiroyuki Machida @ 2007-05-30 7:34 UTC (permalink / raw)
To: Steve Munroe; +Cc: linuxppc-dev list
In-Reply-To: <OFB4FD81AE.95147932-ON862572EA.007EAB56-862572EA.007FDB77@us.ibm.com>
Hi Steve,
2007/5/30, Steve Munroe <sjmunroe@us.ibm.com>:
>
> Benjamin Herrenschmidt <benh@kernel.crashing.org> wrote on 05/29/2007
> 04:44:15 PM:
:
:
> > >
> > > Also if you want to debug this code (see long long variables correctly
> from
> > > GDB or even see the upper 32-bits of GPRs) you will need an ABI change
> so
> > > that GDB/DWARF knows what to do.
As already mentioned, ABI (calling convetion and relocations) wont't change,
so there's no exteion to DWARF required, I think. Do you have any concern ?
> >
> > I personally don't care about gdb seeing those or anything like that,
> > those would be strictly local asm optimisations, at least that's my
> > point of view on the matter.
> >
> Well others do. If gcc supports code gen for this they will expect GDB
> support.
Even now, gcc -m32 -mpowerpc64 produces 64 bit insns.
I've cheked with gcc version 4.1.1 20070105 (Red Hat 4.1.1-51).
But in most case, developers would use these options to some
specific files which are critical to performance.
I think GDB support is not critical, but would be expected.
---
Hiroyuki Machida
^ permalink raw reply
* [RFC/PATCH 6/6] powerpc: Allow ptrace write to pt_regs trap and orig_r3
From: Benjamin Herrenschmidt @ 2007-05-30 7:17 UTC (permalink / raw)
To: linuxppc-dev; +Cc: ulrich.weigand, Paul Mackerras, Anton Blanchard
This patch allows a ptracer to write to the "trap" and "orig_r3" words
of the pt_regs.
This, along with a subsequent patch to the signal restart code, should
enable gdb to properly handle syscall restarting after executing a separate
function (at least when there's no restart block).
This patch also removes ptrace32.c code toying directly with the registers
and makes it use the ptrace_get/put_reg() accessors for everything so that
the logic for checking what is permitted is in only one place.
Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
---
arch/powerpc/kernel/ptrace.c | 9 ++++++---
arch/powerpc/kernel/ptrace32.c | 28 +++++++++++++++-------------
2 files changed, 21 insertions(+), 16 deletions(-)
Index: linux-cell/arch/powerpc/kernel/ptrace.c
===================================================================
--- linux-cell.orig/arch/powerpc/kernel/ptrace.c 2007-05-30 16:02:55.000000000 +1000
+++ linux-cell/arch/powerpc/kernel/ptrace.c 2007-05-30 16:03:01.000000000 +1000
@@ -75,10 +75,15 @@ int ptrace_put_reg(struct task_struct *t
if (task->thread.regs == NULL)
return -EIO;
- if (regno <= PT_MAX_PUT_REG) {
+ 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;
((unsigned long *)task->thread.regs)[regno] = data;
return 0;
}
@@ -409,8 +414,6 @@ long arch_ptrace(struct task_struct *chi
break;
CHECK_FULL_REGS(child->thread.regs);
- if (index == PT_ORIG_R3)
- break;
if (index < PT_FPR0) {
ret = ptrace_put_reg(child, index, data);
} else {
Index: linux-cell/arch/powerpc/kernel/ptrace32.c
===================================================================
--- linux-cell.orig/arch/powerpc/kernel/ptrace32.c 2007-05-30 16:02:55.000000000 +1000
+++ linux-cell/arch/powerpc/kernel/ptrace32.c 2007-05-30 16:03:01.000000000 +1000
@@ -206,7 +206,9 @@ long compat_sys_ptrace(int request, int
else
part = 0; /* want the 1st half of the register (left-most). */
- /* Validate the input - check to see if address is on the wrong boundary or beyond the end of the user area */
+ /* Validate the input - check to see if address is on the wrong boundary
+ * or beyond the end of the user area
+ */
if ((addr & 3) || numReg > PT_FPSCR)
break;
@@ -270,8 +272,6 @@ long compat_sys_ptrace(int request, int
if ((addr & 3) || (index > PT_FPSCR32))
break;
- if (index == PT_ORIG_R3)
- break;
if (index < PT_FPR0) {
ret = ptrace_put_reg(child, index, data);
} else {
@@ -297,29 +297,31 @@ long compat_sys_ptrace(int request, int
case PPC_PTRACE_POKEUSR_3264: {
u32 index;
u32 numReg;
+ u32 orig;
ret = -EIO;
/* Determine which register the user wants */
index = (u64)addr >> 2;
numReg = index / 2;
+
/*
* Validate the input - check to see if address is on the
* wrong boundary or beyond the end of the user area
*/
if ((addr & 3) || (numReg > PT_FPSCR))
break;
- /* Insure it is a register we let them change */
- if ((numReg == PT_ORIG_R3)
- || ((numReg > PT_CCR) && (numReg < PT_FPR0)))
- break;
- if (numReg >= PT_FPR0) {
+ if (numReg < PT_FPR0) {
+ unsigned long freg = ptrace_get_reg(child, numReg);
+ if (index % 2)
+ freg = (freg & ~0xfffffffful) | data & 0xfffffffful;
+ else
+ freg = (freg & 0xfffffffful) | (data << 32);
+ ret = ptrace_put_reg(child, numReg, freg);
+ } else {
flush_fp_to_thread(child);
+ ((unsigned int *)child->thread.regs)[index] = data;
+ ret = 0;
}
- if (numReg == PT_MSR)
- data = (data & MSR_DEBUGCHANGE)
- | (child->thread.regs->msr & ~MSR_DEBUGCHANGE);
- ((u32*)child->thread.regs)[index] = data;
- ret = 0;
break;
}
^ permalink raw reply
* [RFC/PATCH 5/6] powerpc: remove some useless ifdef's in ptrace
From: Benjamin Herrenschmidt @ 2007-05-30 7:17 UTC (permalink / raw)
To: linuxppc-dev; +Cc: ulrich.weigand, Paul Mackerras, Anton Blanchard
CHECK_FULL_REGS() exist on both 32 and 64 bits, so there's no need
to make it conditional on CONFIG_PPC32
Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
---
arch/powerpc/kernel/ptrace.c | 4 ----
1 file changed, 4 deletions(-)
Index: linux-cell/arch/powerpc/kernel/ptrace.c
===================================================================
--- linux-cell.orig/arch/powerpc/kernel/ptrace.c 2007-05-30 16:02:55.000000000 +1000
+++ linux-cell/arch/powerpc/kernel/ptrace.c 2007-05-30 16:02:55.000000000 +1000
@@ -371,9 +371,7 @@ long arch_ptrace(struct task_struct *chi
#endif
break;
-#ifdef CONFIG_PPC32
CHECK_FULL_REGS(child->thread.regs);
-#endif
if (index < PT_FPR0) {
tmp = ptrace_get_reg(child, (int) index);
} else {
@@ -410,9 +408,7 @@ long arch_ptrace(struct task_struct *chi
#endif
break;
-#ifdef CONFIG_PPC32
CHECK_FULL_REGS(child->thread.regs);
-#endif
if (index == PT_ORIG_R3)
break;
if (index < PT_FPR0) {
^ permalink raw reply
* [RFC/PATCH 4/6] powerpc: uninline common ptrace bits
From: Benjamin Herrenschmidt @ 2007-05-30 7:17 UTC (permalink / raw)
To: linuxppc-dev; +Cc: ulrich.weigand, Paul Mackerras, Anton Blanchard
This folds back the ptrace-common.h bits back into ptrace.c and removes
that file. The FSL SPE bits from ptrace-ppc32.h are folded back in as
well.
Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
---
arch/powerpc/kernel/ptrace-common.h | 177 ---------------------------
arch/powerpc/kernel/ptrace-ppc32.h | 65 ----------
arch/powerpc/kernel/ptrace.c | 233 +++++++++++++++++++++++++++++++++++-
arch/powerpc/kernel/ptrace32.c | 11 -
include/asm-powerpc/ptrace.h | 5
5 files changed, 237 insertions(+), 254 deletions(-)
Index: linux-cell/arch/powerpc/kernel/ptrace-common.h
===================================================================
--- linux-cell.orig/arch/powerpc/kernel/ptrace-common.h 2007-05-30 15:50:42.000000000 +1000
+++ /dev/null 1970-01-01 00:00:00.000000000 +0000
@@ -1,177 +0,0 @@
-/*
- * Copyright (c) 2002 Stephen Rothwell, IBM Coproration
- * Copyright (c) 2007 Benjamin Herrenschmidt, IBM Coproration
- * Extracted from ptrace.c and ptrace32.c
- *
- * This file is subject to the terms and conditions of the GNU General
- * Public License. See the file README.legal in the main directory of
- * this archive for more details.
- */
-
-#ifndef _POWERPC_PTRACE_COMMON_H
-#define _POWERPC_PTRACE_COMMON_H
-
-/*
- * Get contents of register REGNO in task TASK.
- */
-static inline unsigned long 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 PT_MUNGE_MSR(tmp, task);
- }
-
- if (regno < (sizeof(struct pt_regs) / sizeof(unsigned long)))
- return ((unsigned long *)task->thread.regs)[regno];
-
- return -EIO;
-}
-
-/*
- * Write contents of register REGNO in task TASK.
- */
-static inline int put_reg(struct task_struct *task, int regno,
- unsigned long data)
-{
- if (task->thread.regs == NULL)
- return -EIO;
-
- if (regno <= PT_MAX_PUT_REG) {
- if (regno == PT_MSR)
- data = (data & MSR_DEBUGCHANGE)
- | (task->thread.regs->msr & ~MSR_DEBUGCHANGE);
- ((unsigned long *)task->thread.regs)[regno] = data;
- return 0;
- }
- return -EIO;
-}
-
-
-static inline 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)))
- return -EFAULT;
- return 0;
-}
-
-static inline 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)))
- return -EFAULT;
- return 0;
-}
-
-
-#ifdef CONFIG_ALTIVEC
-/*
- * Get/set all the altivec registers vr0..vr31, vscr, vrsave, in one go.
- * The transfer totals 34 quadword. Quadwords 0-31 contain the
- * corresponding vector registers. Quadword 32 contains the vscr as the
- * last word (offset 12) within that quadword. Quadword 33 contains the
- * vrsave as the first word (offset 0) within the quadword.
- *
- * This definition of the VMX state is compatible with the current PPC32
- * ptrace interface. This allows signal handling and ptrace to use the
- * same structures. This also simplifies the implementation of a bi-arch
- * (combined (32- and 64-bit) gdb.
- */
-
-/*
- * Get contents of AltiVec register state in task TASK
- */
-static inline 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))
- return -EFAULT;
- data += (regsize / sizeof(unsigned long));
-
- /* copy VRSAVE */
- if (put_user(task->thread.vrsave, (u32 __user *)data))
- return -EFAULT;
-
- return 0;
-}
-
-/*
- * Write contents of AltiVec register state into task TASK.
- */
-static inline 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))
- return -EFAULT;
-
- return 0;
-}
-#endif /* CONFIG_ALTIVEC */
-
-static inline void set_single_step(struct task_struct *task)
-{
- struct pt_regs *regs = task->thread.regs;
-
- if (regs != NULL) {
-#if defined(CONFIG_40x) || defined(CONFIG_BOOKE)
- task->thread.dbcr0 = DBCR0_IDM | DBCR0_IC;
- regs->msr |= MSR_DE;
-#else
- regs->msr |= MSR_SE;
-#endif
- }
- set_tsk_thread_flag(task, TIF_SINGLESTEP);
-}
-
-static inline void clear_single_step(struct task_struct *task)
-{
- struct pt_regs *regs = task->thread.regs;
-
- if (regs != NULL) {
-#if defined(CONFIG_40x) || defined(CONFIG_BOOKE)
- task->thread.dbcr0 = 0;
- regs->msr &= ~MSR_DE;
-#else
- regs->msr &= ~MSR_SE;
-#endif
- }
- clear_tsk_thread_flag(task, TIF_SINGLESTEP);
-}
-
-#endif /* _POWERPC_PTRACE_COMMON_H */
Index: linux-cell/arch/powerpc/kernel/ptrace-ppc32.h
===================================================================
--- linux-cell.orig/arch/powerpc/kernel/ptrace-ppc32.h 2007-05-30 15:50:42.000000000 +1000
+++ linux-cell/arch/powerpc/kernel/ptrace-ppc32.h 2007-05-30 15:51:01.000000000 +1000
@@ -32,69 +32,4 @@
#define PT_MUNGE_MSR(msr, task) (msr)
-#ifdef CONFIG_SPE
-
-/*
- * For get_evrregs/set_evrregs functions 'data' has the following layout:
- *
- * struct {
- * u32 evr[32];
- * u64 acc;
- * u32 spefscr;
- * }
- */
-
-/*
- * Get contents of SPE register state in task TASK.
- */
-static inline int get_evrregs(unsigned long *data, struct task_struct *task)
-{
- int i;
-
- if (!access_ok(VERIFY_WRITE, data, 35 * sizeof(unsigned long)))
- return -EFAULT;
-
- /* copy SPEFSCR */
- if (__put_user(task->thread.spefscr, &data[34]))
- return -EFAULT;
-
- /* copy SPE registers EVR[0] .. EVR[31] */
- for (i = 0; i < 32; i++, data++)
- if (__put_user(task->thread.evr[i], data))
- return -EFAULT;
-
- /* copy ACC */
- if (__put_user64(task->thread.acc, (unsigned long long *)data))
- return -EFAULT;
-
- return 0;
-}
-
-/*
- * Write contents of SPE register state into task TASK.
- */
-static inline int set_evrregs(struct task_struct *task, unsigned long *data)
-{
- int i;
-
- if (!access_ok(VERIFY_READ, data, 35 * sizeof(unsigned long)))
- return -EFAULT;
-
- /* copy SPEFSCR */
- if (__get_user(task->thread.spefscr, &data[34]))
- return -EFAULT;
-
- /* 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))
- return -EFAULT;
-
- return 0;
-}
-#endif /* CONFIG_SPE */
-
-
#endif /* _POWERPC_PTRACE_PPC32_H */
Index: linux-cell/arch/powerpc/kernel/ptrace.c
===================================================================
--- linux-cell.orig/arch/powerpc/kernel/ptrace.c 2007-05-30 15:50:42.000000000 +1000
+++ linux-cell/arch/powerpc/kernel/ptrace.c 2007-05-30 15:51:34.000000000 +1000
@@ -41,14 +41,235 @@
#include "ptrace-ppc32.h"
#endif
-#include "ptrace-common.h"
-
/*
* does not yet catch signals sent when the child dies.
* in exit.c or in signal.c.
*/
/*
+ * 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 PT_MUNGE_MSR(tmp, task);
+ }
+
+ if (regno < (sizeof(struct pt_regs) / sizeof(unsigned long)))
+ return ((unsigned long *)task->thread.regs)[regno];
+
+ return -EIO;
+}
+
+/*
+ * Write contents of register REGNO in task TASK.
+ */
+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) {
+ if (regno == PT_MSR)
+ data = (data & MSR_DEBUGCHANGE)
+ | (task->thread.regs->msr & ~MSR_DEBUGCHANGE);
+ ((unsigned long *)task->thread.regs)[regno] = data;
+ return 0;
+ }
+ return -EIO;
+}
+
+
+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)))
+ return -EFAULT;
+ return 0;
+}
+
+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)))
+ return -EFAULT;
+ return 0;
+}
+
+
+#ifdef CONFIG_ALTIVEC
+/*
+ * Get/set all the altivec registers vr0..vr31, vscr, vrsave, in one go.
+ * The transfer totals 34 quadword. Quadwords 0-31 contain the
+ * corresponding vector registers. Quadword 32 contains the vscr as the
+ * last word (offset 12) within that quadword. Quadword 33 contains the
+ * vrsave as the first word (offset 0) within the quadword.
+ *
+ * This definition of the VMX state is compatible with the current PPC32
+ * ptrace interface. This allows signal handling and ptrace to use the
+ * same structures. This also simplifies the implementation of a bi-arch
+ * (combined (32- and 64-bit) gdb.
+ */
+
+/*
+ * 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))
+ return -EFAULT;
+ data += (regsize / sizeof(unsigned long));
+
+ /* copy VRSAVE */
+ if (put_user(task->thread.vrsave, (u32 __user *)data))
+ return -EFAULT;
+
+ return 0;
+}
+
+/*
+ * Write contents of AltiVec register state into task 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))
+ return -EFAULT;
+
+ return 0;
+}
+#endif /* CONFIG_ALTIVEC */
+
+#ifdef CONFIG_SPE
+
+/*
+ * For get_evrregs/set_evrregs functions 'data' has the following layout:
+ *
+ * struct {
+ * u32 evr[32];
+ * u64 acc;
+ * u32 spefscr;
+ * }
+ */
+
+/*
+ * Get contents of SPE register state in task TASK.
+ */
+static int get_evrregs(unsigned long *data, struct task_struct *task)
+{
+ int i;
+
+ if (!access_ok(VERIFY_WRITE, data, 35 * sizeof(unsigned long)))
+ return -EFAULT;
+
+ /* copy SPEFSCR */
+ if (__put_user(task->thread.spefscr, &data[34]))
+ return -EFAULT;
+
+ /* copy SPE registers EVR[0] .. EVR[31] */
+ for (i = 0; i < 32; i++, data++)
+ if (__put_user(task->thread.evr[i], data))
+ return -EFAULT;
+
+ /* copy ACC */
+ if (__put_user64(task->thread.acc, (unsigned long long *)data))
+ return -EFAULT;
+
+ return 0;
+}
+
+/*
+ * Write contents of SPE register state into task TASK.
+ */
+static int set_evrregs(struct task_struct *task, unsigned long *data)
+{
+ int i;
+
+ if (!access_ok(VERIFY_READ, data, 35 * sizeof(unsigned long)))
+ return -EFAULT;
+
+ /* copy SPEFSCR */
+ if (__get_user(task->thread.spefscr, &data[34]))
+ return -EFAULT;
+
+ /* 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))
+ return -EFAULT;
+
+ return 0;
+}
+#endif /* CONFIG_SPE */
+
+
+static void set_single_step(struct task_struct *task)
+{
+ struct pt_regs *regs = task->thread.regs;
+
+ if (regs != NULL) {
+#if defined(CONFIG_40x) || defined(CONFIG_BOOKE)
+ task->thread.dbcr0 = DBCR0_IDM | DBCR0_IC;
+ regs->msr |= MSR_DE;
+#else
+ regs->msr |= MSR_SE;
+#endif
+ }
+ set_tsk_thread_flag(task, TIF_SINGLESTEP);
+}
+
+static void clear_single_step(struct task_struct *task)
+{
+ struct pt_regs *regs = task->thread.regs;
+
+ if (regs != NULL) {
+#if defined(CONFIG_40x) || defined(CONFIG_BOOKE)
+ task->thread.dbcr0 = 0;
+ regs->msr &= ~MSR_DE;
+#else
+ regs->msr &= ~MSR_SE;
+#endif
+ }
+ clear_tsk_thread_flag(task, TIF_SINGLESTEP);
+}
+
+/*
* Called by kernel/ptrace.c when detaching..
*
* Make sure single step bits etc are not set.
@@ -154,7 +375,7 @@ long arch_ptrace(struct task_struct *chi
CHECK_FULL_REGS(child->thread.regs);
#endif
if (index < PT_FPR0) {
- tmp = get_reg(child, (int) index);
+ tmp = ptrace_get_reg(child, (int) index);
} else {
flush_fp_to_thread(child);
tmp = ((unsigned long *)child->thread.fpr)[index - PT_FPR0];
@@ -195,7 +416,7 @@ long arch_ptrace(struct task_struct *chi
if (index == PT_ORIG_R3)
break;
if (index < PT_FPR0) {
- ret = put_reg(child, index, data);
+ ret = ptrace_put_reg(child, index, data);
} else {
flush_fp_to_thread(child);
((unsigned long *)child->thread.fpr)[index - PT_FPR0] = data;
@@ -282,7 +503,7 @@ long arch_ptrace(struct task_struct *chi
}
ret = 0;
for (ui = 0; ui < PT_REGS_COUNT; ui ++) {
- ret |= __put_user(get_reg(child, ui),
+ ret |= __put_user(ptrace_get_reg(child, ui),
(unsigned long __user *) data);
data += sizeof(long);
}
@@ -305,7 +526,7 @@ long arch_ptrace(struct task_struct *chi
ret = __get_user(tmp, (unsigned long __user *) data);
if (ret)
break;
- put_reg(child, ui, tmp);
+ ptrace_put_reg(child, ui, tmp);
data += sizeof(long);
}
break;
Index: linux-cell/arch/powerpc/kernel/ptrace32.c
===================================================================
--- linux-cell.orig/arch/powerpc/kernel/ptrace32.c 2007-05-30 15:50:42.000000000 +1000
+++ linux-cell/arch/powerpc/kernel/ptrace32.c 2007-05-30 15:51:39.000000000 +1000
@@ -34,7 +34,6 @@
#include <asm/system.h>
#include "ptrace-ppc64.h"
-#include "ptrace-common.h"
/*
* does not yet catch signals sent when the child dies.
@@ -168,7 +167,7 @@ long compat_sys_ptrace(int request, int
break;
if (index < PT_FPR0) {
- tmp = get_reg(child, index);
+ tmp = ptrace_get_reg(child, index);
} else {
flush_fp_to_thread(child);
/*
@@ -215,7 +214,7 @@ long compat_sys_ptrace(int request, int
flush_fp_to_thread(child);
tmp = ((unsigned long int *)child->thread.fpr)[numReg - PT_FPR0];
} else { /* register within PT_REGS struct */
- tmp = get_reg(child, numReg);
+ tmp = ptrace_get_reg(child, numReg);
}
reg32bits = ((u32*)&tmp)[part];
ret = put_user(reg32bits, (u32 __user *)data);
@@ -274,7 +273,7 @@ long compat_sys_ptrace(int request, int
if (index == PT_ORIG_R3)
break;
if (index < PT_FPR0) {
- ret = put_reg(child, index, data);
+ ret = ptrace_put_reg(child, index, data);
} else {
flush_fp_to_thread(child);
/*
@@ -346,7 +345,7 @@ long compat_sys_ptrace(int request, int
}
ret = 0;
for (ui = 0; ui < PT_REGS_COUNT; ui ++) {
- ret |= __put_user(get_reg(child, ui),
+ ret |= __put_user(ptrace_get_reg(child, ui),
(unsigned int __user *) data);
data += sizeof(int);
}
@@ -366,7 +365,7 @@ long compat_sys_ptrace(int request, int
ret = __get_user(tmp, (unsigned int __user *) data);
if (ret)
break;
- put_reg(child, ui, tmp);
+ ptrace_put_reg(child, ui, tmp);
data += sizeof(int);
}
break;
Index: linux-cell/include/asm-powerpc/ptrace.h
===================================================================
--- linux-cell.orig/include/asm-powerpc/ptrace.h 2007-05-30 15:50:42.000000000 +1000
+++ linux-cell/include/asm-powerpc/ptrace.h 2007-05-30 15:51:19.000000000 +1000
@@ -92,6 +92,11 @@ extern unsigned long profile_pc(struct p
set_thread_flag(TIF_NOERROR); \
} while(0)
+struct task_struct;
+extern unsigned long ptrace_get_reg(struct task_struct *task, int regno);
+extern int ptrace_put_reg(struct task_struct *task, int regno,
+ unsigned long data);
+
/*
* We use the least-significant bit of the trap field to indicate
* whether we have saved the full set of registers, or only a
^ permalink raw reply
* [RFC/PATCH 3/6] powerpc: ptrace updates & new better requests
From: Benjamin Herrenschmidt @ 2007-05-30 7:17 UTC (permalink / raw)
To: linuxppc-dev; +Cc: ulrich.weigand, Paul Mackerras, Anton Blanchard
The powerpc ptrace interface is dodgy at best. We have defined our
"own" versions of GETREGS/SETREGS/GETFPREGS/SETFPREGS that strangely
take arguments in reverse order from other archs (in addition to having
different request numbers) and have subtle issue, like not accessing
all of the registers in their respective categories.
This patch moves the implementation of those to a separate function
in order to facilitate their deprecation in the future, and provides
new ptrace requests that mirror the x86 and sparc ones and use the
same numbers:
PTRACE_GETREGS : returns an entire pt_regs (the whole thing,
not only the 32 GPRs, though that doesn't
include the FPRs etc... There's a compat version
for 32 bits that returns a 32 bits compatible
pt_regs (44 uints)
PTRACE_SETREGS : sets an entire pt_regs (the whole thing,
not only the 32 GPRs, though that doesn't
include the FPRs etc... Some registers cannot be
written to and will just be dropped, this is the
same as with POKEUSR, that is anything above MQ
on 32 bits and CCR on 64 bits. There is a compat
version as well.
PTRACE_GETFPREGS : returns all the FP registers -including- the FPSCR
that is 33 doubles (regardless of 32/64 bits)
PTRACE_SETFPREGS : sets all the FP registers -including- the FPSCR
that is 33 doubles (regardless of 32/64 bits)
And two that only exist on 64 bits kernels:
PTRACE_GETREGS64 : Same as PTRACE_GETREGS, except there is no compat
function, a 32 bits process will obtain the full 64
bits registers
PTRACE_SETREGS64 : Same as PTRACE_SETREGS, except there is no compat
function, a 32 bits process will set the full 64
bits registers
The two later ones makes things easier to have a 32 bits debugger on a
64 bits program (or on a 32 bits program that uses the full 64 bits of
the GPRs, which is possible though has issues that will be fixed in a
later patch).
Finally, while at it, the patch removes a whole bunch of code duplication
between ptrace32.c and ptrace.c, in large part by having the former call
into the later for all requests that don't need any special "compat"
treatment.
Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
---
arch/powerpc/kernel/ptrace-common.h | 23 ++++
arch/powerpc/kernel/ptrace.c | 148 +++++++++++++++++---------
arch/powerpc/kernel/ptrace32.c | 204 +++++++++++++++---------------------
include/asm-powerpc/ptrace.h | 17 ++-
4 files changed, 222 insertions(+), 170 deletions(-)
Index: linux-cell/arch/powerpc/kernel/ptrace.c
===================================================================
--- linux-cell.orig/arch/powerpc/kernel/ptrace.c 2007-05-30 14:40:54.000000000 +1000
+++ linux-cell/arch/powerpc/kernel/ptrace.c 2007-05-30 16:02:52.000000000 +1000
@@ -59,6 +59,62 @@ void ptrace_disable(struct task_struct *
clear_single_step(child);
}
+/*
+ * Here are the old "legacy" powerpc specific getregs/setregs ptrace calls,
+ * we mark them as obsolete now, they will be removed in a future version
+ */
+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;
+
+ 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;
+
+ 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;
+ }
+
+ }
+ return ret;
+}
+
long arch_ptrace(struct task_struct *child, long request, long addr, long data)
{
int ret = -EPERM;
@@ -214,71 +270,58 @@ long arch_ptrace(struct task_struct *chi
ret = ptrace_detach(child, data);
break;
- 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;
-
- for (i = 0; i < 32; i++) {
- ret = put_user(*reg, tmp);
- if (ret)
- break;
- reg++;
- tmp++;
+#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;
+ }
+ ret = 0;
+ for (ui = 0; ui < PT_REGS_COUNT; ui ++) {
+ ret |= __put_user(get_reg(child, ui),
+ (unsigned long __user *) data);
+ data += sizeof(long);
}
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;
-
- for (i = 0; i < 32; i++) {
- ret = get_user(*reg, tmp);
+#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;
+ }
+ ret = 0;
+ for (ui = 0; ui < PT_REGS_COUNT; ui ++) {
+ ret = __get_user(tmp, (unsigned long __user *) data);
if (ret)
break;
- reg++;
- tmp++;
+ put_reg(child, ui, tmp);
+ data += sizeof(long);
}
break;
}
-#ifdef CONFIG_PPC64
- case PPC_PTRACE_GETFPREGS: { /* Get FPRs 0 - 31. */
- int i;
- unsigned long *reg = &((unsigned long *)child->thread.fpr)[0];
- unsigned long __user *tmp = (unsigned long __user *)addr;
-
+ case PTRACE_GETFPREGS: { /* Get the child FPU state (FPR0...31 + FPSCR) */
flush_fp_to_thread(child);
-
- for (i = 0; i < 32; i++) {
- ret = put_user(*reg, tmp);
- if (ret)
- break;
- reg++;
- tmp++;
- }
+ ret = get_fpregs((void __user *)data, child, 1);
break;
}
- case PPC_PTRACE_SETFPREGS: { /* Get FPRs 0 - 31. */
- int i;
- unsigned long *reg = &((unsigned long *)child->thread.fpr)[0];
- unsigned long __user *tmp = (unsigned long __user *)addr;
-
+ case PTRACE_SETFPREGS: { /* Set the child FPU state (FPR0...31 + FPSCR) */
flush_fp_to_thread(child);
-
- for (i = 0; i < 32; i++) {
- ret = get_user(*reg, tmp);
- if (ret)
- break;
- reg++;
- tmp++;
- }
+ ret = set_fpregs((void __user *)data, child, 1);
break;
}
-#endif /* CONFIG_PPC64 */
#ifdef CONFIG_ALTIVEC
case PTRACE_GETVRREGS:
@@ -311,11 +354,18 @@ long arch_ptrace(struct task_struct *chi
break;
#endif
+ /* Old reverse args ptrace callss */
+ case PPC_PTRACE_GETREGS: /* Get GPRs 0 - 31. */
+ case PPC_PTRACE_SETREGS: /* Set GPRs 0 - 31. */
+ case PPC_PTRACE_GETFPREGS: /* Get FPRs 0 - 31. */
+ case PPC_PTRACE_SETFPREGS: /* Get FPRs 0 - 31. */
+ ret = arch_ptrace_old(child, request, addr, data);
+ break;
+
default:
ret = ptrace_request(child, request, addr, data);
break;
}
-
return ret;
}
Index: linux-cell/include/asm-powerpc/ptrace.h
===================================================================
--- linux-cell.orig/include/asm-powerpc/ptrace.h 2007-05-30 14:26:01.000000000 +1000
+++ linux-cell/include/asm-powerpc/ptrace.h 2007-05-30 16:02:52.000000000 +1000
@@ -158,9 +158,7 @@ do { \
#define PT_NIP 32
#define PT_MSR 33
-#ifdef __KERNEL__
#define PT_ORIG_R3 34
-#endif
#define PT_CTR 35
#define PT_LNK 36
#define PT_XER 37
@@ -169,11 +167,12 @@ do { \
#define PT_MQ 39
#else
#define PT_SOFTE 39
+#endif
#define PT_TRAP 40
#define PT_DAR 41
#define PT_DSISR 42
#define PT_RESULT 43
-#endif
+#define PT_REGS_COUNT 44
#define PT_FPR0 48 /* each FP reg occupies 2 slots in this space */
@@ -229,7 +228,17 @@ do { \
#define PTRACE_GET_DEBUGREG 25
#define PTRACE_SET_DEBUGREG 26
-/* Additional PTRACE requests implemented on PowerPC. */
+/* (new) PTRACE requests using the same numbers as x86 and the same
+ * argument ordering. Additionally, they support more registers too
+ */
+#define PTRACE_GETREGS 12
+#define PTRACE_SETREGS 13
+#define PTRACE_GETFPREGS 14
+#define PTRACE_SETFPREGS 15
+#define PTRACE_GETREGS64 22
+#define PTRACE_SETREGS64 23
+
+/* (old) PTRACE requests with inverted arguments */
#define PPC_PTRACE_GETREGS 0x99 /* Get GPRs 0 - 31 */
#define PPC_PTRACE_SETREGS 0x98 /* Set GPRs 0 - 31 */
#define PPC_PTRACE_GETFPREGS 0x97 /* Get FPRs 0 - 31 */
Index: linux-cell/arch/powerpc/kernel/ptrace-common.h
===================================================================
--- linux-cell.orig/arch/powerpc/kernel/ptrace-common.h 2007-05-30 14:40:54.000000000 +1000
+++ linux-cell/arch/powerpc/kernel/ptrace-common.h 2007-05-30 16:02:52.000000000 +1000
@@ -52,6 +52,29 @@ static inline int put_reg(struct task_st
}
+static inline 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)))
+ return -EFAULT;
+ return 0;
+}
+
+static inline 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)))
+ return -EFAULT;
+ return 0;
+}
+
+
#ifdef CONFIG_ALTIVEC
/*
* Get/set all the altivec registers vr0..vr31, vscr, vrsave, in one go.
Index: linux-cell/arch/powerpc/kernel/ptrace32.c
===================================================================
--- linux-cell.orig/arch/powerpc/kernel/ptrace32.c 2007-05-30 14:40:54.000000000 +1000
+++ linux-cell/arch/powerpc/kernel/ptrace32.c 2007-05-30 16:02:52.000000000 +1000
@@ -41,6 +41,50 @@
* in exit.c or in signal.c.
*/
+/*
+ * Here are the old "legacy" powerpc specific getregs/setregs ptrace calls,
+ * we mark them as obsolete now, they will be removed in a future version
+ */
+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;
+
+ 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;
+
+ for (i = 0; i < 32; i++) {
+ ret = get_user(*reg, tmp);
+ if (ret)
+ break;
+ reg++;
+ tmp++;
+ }
+ break;
+ }
+
+ }
+ return ret;
+}
+
long compat_sys_ptrace(int request, int pid, unsigned long addr,
unsigned long data)
{
@@ -280,52 +324,6 @@ long compat_sys_ptrace(int request, int
break;
}
- case PTRACE_SYSCALL: /* continue and stop at next (return from) syscall */
- case PTRACE_CONT: { /* restart after signal. */
- ret = -EIO;
- if (!valid_signal(data))
- break;
- if (request == PTRACE_SYSCALL)
- set_tsk_thread_flag(child, TIF_SYSCALL_TRACE);
- else
- clear_tsk_thread_flag(child, TIF_SYSCALL_TRACE);
- child->exit_code = data;
- /* make sure the single step bit is not set. */
- clear_single_step(child);
- wake_up_process(child);
- ret = 0;
- break;
- }
-
- /*
- * make the child exit. Best I can do is send it a sigkill.
- * perhaps it should be put in the status that it wants to
- * exit.
- */
- case PTRACE_KILL: {
- ret = 0;
- if (child->exit_state == EXIT_ZOMBIE) /* already dead */
- break;
- child->exit_code = SIGKILL;
- /* make sure the single step bit is not set. */
- clear_single_step(child);
- wake_up_process(child);
- break;
- }
-
- case PTRACE_SINGLESTEP: { /* set the trap flag. */
- ret = -EIO;
- if (!valid_signal(data))
- break;
- clear_tsk_thread_flag(child, TIF_SYSCALL_TRACE);
- set_single_step(child);
- child->exit_code = data;
- /* give it a chance to run. */
- wake_up_process(child);
- ret = 0;
- break;
- }
-
case PTRACE_GET_DEBUGREG: {
ret = -EINVAL;
/* We only support one DABR and no IABRS at the moment */
@@ -335,95 +333,67 @@ long compat_sys_ptrace(int request, int
break;
}
- case PTRACE_SET_DEBUGREG:
- ret = ptrace_set_debugreg(child, addr, data);
- break;
-
- case PTRACE_DETACH:
- ret = ptrace_detach(child, data);
+ case PTRACE_GETEVENTMSG:
+ ret = put_user(child->ptrace_message, (unsigned int __user *) data);
break;
- 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;
-
- for (i = 0; i < 32; i++) {
- ret = put_user(*reg, tmp);
- if (ret)
- break;
- reg++;
- tmp++;
+ 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;
}
- 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;
-
- for (i = 0; i < 32; i++) {
- ret = get_user(*reg, tmp);
- if (ret)
- break;
- reg++;
- tmp++;
+ ret = 0;
+ for (ui = 0; ui < PT_REGS_COUNT; ui ++) {
+ ret |= __put_user(get_reg(child, ui),
+ (unsigned int __user *) data);
+ data += sizeof(int);
}
break;
}
- case PPC_PTRACE_GETFPREGS: { /* Get FPRs 0 - 31. */
- int i;
- unsigned long *reg = &((unsigned long *)child->thread.fpr)[0];
- unsigned int __user *tmp = (unsigned int __user *)addr;
-
- flush_fp_to_thread(child);
-
- for (i = 0; i < 32; i++) {
- ret = put_user(*reg, tmp);
- if (ret)
- break;
- reg++;
- tmp++;
+ 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;
}
- break;
- }
-
- case PPC_PTRACE_SETFPREGS: { /* Get FPRs 0 - 31. */
- int i;
- unsigned long *reg = &((unsigned long *)child->thread.fpr)[0];
- unsigned int __user *tmp = (unsigned int __user *)addr;
-
- flush_fp_to_thread(child);
-
- for (i = 0; i < 32; i++) {
- ret = get_user(*reg, tmp);
+ ret = 0;
+ for (ui = 0; ui < PT_REGS_COUNT; ui ++) {
+ ret = __get_user(tmp, (unsigned int __user *) data);
if (ret)
break;
- reg++;
- tmp++;
+ put_reg(child, ui, tmp);
+ data += sizeof(int);
}
break;
}
- case PTRACE_GETEVENTMSG:
- ret = put_user(child->ptrace_message, (unsigned int __user *) data);
- break;
-
-#ifdef CONFIG_ALTIVEC
+ case PTRACE_GETFPREGS:
+ case PTRACE_SETFPREGS:
case PTRACE_GETVRREGS:
- /* Get the child altivec register state. */
- flush_altivec_to_thread(child);
- ret = get_vrregs((unsigned long __user *)data, child);
+ case PTRACE_SETVRREGS:
+ case PTRACE_GETREGS64:
+ case PTRACE_SETREGS64:
+ case PPC_PTRACE_GETFPREGS:
+ case PPC_PTRACE_SETFPREGS:
+ case PTRACE_KILL:
+ case PTRACE_SINGLESTEP:
+ case PTRACE_DETACH:
+ case PTRACE_SET_DEBUGREG:
+ case PTRACE_SYSCALL:
+ case PTRACE_CONT:
+ ret = arch_ptrace(child, request, addr, data);
break;
- case PTRACE_SETVRREGS:
- /* Set the child altivec register state. */
- flush_altivec_to_thread(child);
- ret = set_vrregs(child, (unsigned long __user *)data);
+ /* Old reverse args ptrace callss */
+ case PPC_PTRACE_GETREGS: /* Get GPRs 0 - 31. */
+ case PPC_PTRACE_SETREGS: /* Set GPRs 0 - 31. */
+ ret = compat_ptrace_old(child, request, addr, data);
break;
-#endif
default:
ret = ptrace_request(child, request, addr, data);
^ permalink raw reply
* [RFC/PATCH 2/6] powerpc: ptrace cleanups
From: Benjamin Herrenschmidt @ 2007-05-30 7:17 UTC (permalink / raw)
To: linuxppc-dev; +Cc: ulrich.weigand, Paul Mackerras, Anton Blanchard
The powerpc ptrace code has some weirdness, like a ptrace-common.h file that
is actually ppc64 only and some of the 32 bits code ifdef'ed inside ptrace.c.
There are also separate implementations for things like get/set_vrregs for
32 and 64 bits which is totally unnecessary.
This patch cleans that up a bit by having a ptrace-common.h which contains
really common code (and makes a lot more code common), and ptrace-ppc32.h and
ptrace-ppc64.h files that contain the few remaining different bits.
Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
---
arch/powerpc/kernel/ptrace-common.h | 89 +++++++---------
arch/powerpc/kernel/ptrace-ppc32.h | 100 ++++++++++++++++++
arch/powerpc/kernel/ptrace-ppc64.h | 51 +++++++++
arch/powerpc/kernel/ptrace.c | 198 ------------------------------------
arch/powerpc/kernel/ptrace32.c | 1
5 files changed, 197 insertions(+), 242 deletions(-)
Index: linux-cell/arch/powerpc/kernel/ptrace-common.h
===================================================================
--- linux-cell.orig/arch/powerpc/kernel/ptrace-common.h 2007-05-29 13:05:55.000000000 +1000
+++ linux-cell/arch/powerpc/kernel/ptrace-common.h 2007-05-29 16:22:00.000000000 +1000
@@ -1,5 +1,6 @@
/*
* Copyright (c) 2002 Stephen Rothwell, IBM Coproration
+ * Copyright (c) 2007 Benjamin Herrenschmidt, IBM Coproration
* Extracted from ptrace.c and ptrace32.c
*
* This file is subject to the terms and conditions of the GNU General
@@ -7,15 +8,8 @@
* this archive for more details.
*/
-#ifndef _PPC64_PTRACE_COMMON_H
-#define _PPC64_PTRACE_COMMON_H
-
-#include <asm/system.h>
-
-/*
- * Set of msr bits that gdb can change on behalf of a process.
- */
-#define MSR_DEBUGCHANGE (MSR_FE0 | MSR_SE | MSR_BE | MSR_FE1)
+#ifndef _POWERPC_PTRACE_COMMON_H
+#define _POWERPC_PTRACE_COMMON_H
/*
* Get contents of register REGNO in task TASK.
@@ -24,18 +18,18 @@ static inline unsigned long get_reg(stru
{
unsigned long tmp = 0;
- /*
- * Put the correct FP bits in, they might be wrong as a result
- * of our lazy FP restore.
- */
+ if (task->thread.regs == NULL)
+ return -EIO;
+
if (regno == PT_MSR) {
tmp = ((unsigned long *)task->thread.regs)[PT_MSR];
- tmp |= task->thread.fpexc_mode;
- } else if (regno < (sizeof(struct pt_regs) / sizeof(unsigned long))) {
- tmp = ((unsigned long *)task->thread.regs)[regno];
+ return PT_MUNGE_MSR(tmp, task);
}
- return tmp;
+ if (regno < (sizeof(struct pt_regs) / sizeof(unsigned long)))
+ return ((unsigned long *)task->thread.regs)[regno];
+
+ return -EIO;
}
/*
@@ -44,7 +38,10 @@ static inline unsigned long get_reg(stru
static inline int put_reg(struct task_struct *task, int regno,
unsigned long data)
{
- if (regno < PT_SOFTE) {
+ if (task->thread.regs == NULL)
+ return -EIO;
+
+ if (regno <= PT_MAX_PUT_REG) {
if (regno == PT_MSR)
data = (data & MSR_DEBUGCHANGE)
| (task->thread.regs->msr & ~MSR_DEBUGCHANGE);
@@ -54,21 +51,6 @@ static inline int put_reg(struct task_st
return -EIO;
}
-static inline void set_single_step(struct task_struct *task)
-{
- struct pt_regs *regs = task->thread.regs;
- if (regs != NULL)
- regs->msr |= MSR_SE;
- set_tsk_thread_flag(task, TIF_SINGLESTEP);
-}
-
-static inline void clear_single_step(struct task_struct *task)
-{
- struct pt_regs *regs = task->thread.regs;
- if (regs != NULL)
- regs->msr &= ~MSR_SE;
- clear_tsk_thread_flag(task, TIF_SINGLESTEP);
-}
#ifdef CONFIG_ALTIVEC
/*
@@ -137,25 +119,36 @@ static inline int set_vrregs(struct task
return 0;
}
-#endif
+#endif /* CONFIG_ALTIVEC */
-static inline int ptrace_set_debugreg(struct task_struct *task,
- unsigned long addr, unsigned long data)
+static inline void set_single_step(struct task_struct *task)
{
- /* We only support one DABR and no IABRS at the moment */
- if (addr > 0)
- return -EINVAL;
+ struct pt_regs *regs = task->thread.regs;
- /* The bottom 3 bits are flags */
- if ((data & ~0x7UL) >= TASK_SIZE)
- return -EIO;
+ if (regs != NULL) {
+#if defined(CONFIG_40x) || defined(CONFIG_BOOKE)
+ task->thread.dbcr0 = DBCR0_IDM | DBCR0_IC;
+ regs->msr |= MSR_DE;
+#else
+ regs->msr |= MSR_SE;
+#endif
+ }
+ set_tsk_thread_flag(task, TIF_SINGLESTEP);
+}
- /* Ensure translation is on */
- if (data && !(data & DABR_TRANSLATION))
- return -EIO;
+static inline void clear_single_step(struct task_struct *task)
+{
+ struct pt_regs *regs = task->thread.regs;
- task->thread.dabr = data;
- return 0;
+ if (regs != NULL) {
+#if defined(CONFIG_40x) || defined(CONFIG_BOOKE)
+ task->thread.dbcr0 = 0;
+ regs->msr &= ~MSR_DE;
+#else
+ regs->msr &= ~MSR_SE;
+#endif
+ }
+ clear_tsk_thread_flag(task, TIF_SINGLESTEP);
}
-#endif /* _PPC64_PTRACE_COMMON_H */
+#endif /* _POWERPC_PTRACE_COMMON_H */
Index: linux-cell/arch/powerpc/kernel/ptrace-ppc32.h
===================================================================
--- /dev/null 1970-01-01 00:00:00.000000000 +0000
+++ linux-cell/arch/powerpc/kernel/ptrace-ppc32.h 2007-05-29 13:05:58.000000000 +1000
@@ -0,0 +1,100 @@
+/*
+ * Copyright (c) 2007 Benjamin Herrenschmidt, IBM Coproration
+ * Extracted from ptrace.c and ptrace32.c
+ *
+ * This file is subject to the terms and conditions of the GNU General
+ * Public License. See the file README.legal in the main directory of
+ * this archive for more details.
+ */
+
+#ifndef _POWERPC_PTRACE_PPC32_H
+#define _POWERPC_PTRACE_PPC32_H
+
+/*
+ * Set of msr bits that gdb can change on behalf of a process.
+ */
+#if defined(CONFIG_40x) || defined(CONFIG_BOOKE)
+#define MSR_DEBUGCHANGE 0
+#else
+#define MSR_DEBUGCHANGE (MSR_SE | MSR_BE)
+#endif
+
+/*
+ * Max register writeable via put_reg
+ */
+#define PT_MAX_PUT_REG PT_MQ
+
+/*
+ * Munging of MSR on return from get_regs
+ *
+ * Nothing to do on ppc32
+ */
+#define PT_MUNGE_MSR(msr, task) (msr)
+
+
+#ifdef CONFIG_SPE
+
+/*
+ * For get_evrregs/set_evrregs functions 'data' has the following layout:
+ *
+ * struct {
+ * u32 evr[32];
+ * u64 acc;
+ * u32 spefscr;
+ * }
+ */
+
+/*
+ * Get contents of SPE register state in task TASK.
+ */
+static inline int get_evrregs(unsigned long *data, struct task_struct *task)
+{
+ int i;
+
+ if (!access_ok(VERIFY_WRITE, data, 35 * sizeof(unsigned long)))
+ return -EFAULT;
+
+ /* copy SPEFSCR */
+ if (__put_user(task->thread.spefscr, &data[34]))
+ return -EFAULT;
+
+ /* copy SPE registers EVR[0] .. EVR[31] */
+ for (i = 0; i < 32; i++, data++)
+ if (__put_user(task->thread.evr[i], data))
+ return -EFAULT;
+
+ /* copy ACC */
+ if (__put_user64(task->thread.acc, (unsigned long long *)data))
+ return -EFAULT;
+
+ return 0;
+}
+
+/*
+ * Write contents of SPE register state into task TASK.
+ */
+static inline int set_evrregs(struct task_struct *task, unsigned long *data)
+{
+ int i;
+
+ if (!access_ok(VERIFY_READ, data, 35 * sizeof(unsigned long)))
+ return -EFAULT;
+
+ /* copy SPEFSCR */
+ if (__get_user(task->thread.spefscr, &data[34]))
+ return -EFAULT;
+
+ /* 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))
+ return -EFAULT;
+
+ return 0;
+}
+#endif /* CONFIG_SPE */
+
+
+#endif /* _POWERPC_PTRACE_PPC32_H */
Index: linux-cell/arch/powerpc/kernel/ptrace-ppc64.h
===================================================================
--- /dev/null 1970-01-01 00:00:00.000000000 +0000
+++ linux-cell/arch/powerpc/kernel/ptrace-ppc64.h 2007-05-29 13:05:58.000000000 +1000
@@ -0,0 +1,51 @@
+/*
+ * Copyright (c) 2002 Stephen Rothwell, IBM Coproration
+ * Extracted from ptrace.c and ptrace32.c
+ *
+ * This file is subject to the terms and conditions of the GNU General
+ * Public License. See the file README.legal in the main directory of
+ * this archive for more details.
+ */
+
+#ifndef _POWERPC_PTRACE_PPC64_H
+#define _POWERPC_PTRACE_PPC64_H
+
+/*
+ * Set of msr bits that gdb can change on behalf of a process.
+ */
+#define MSR_DEBUGCHANGE (MSR_FE0 | MSR_SE | MSR_BE | MSR_FE1)
+
+/*
+ * Max register writeable via put_reg
+ */
+#define PT_MAX_PUT_REG PT_CCR
+
+/*
+ * Munging of MSR on return from get_regs
+ *
+ * Put the correct FP bits in, they might be wrong as a result
+ * of our lazy FP restore.
+ */
+
+#define PT_MUNGE_MSR(msr, task) ({ (msr) | (task)->thread.fpexc_mode; })
+
+static inline int ptrace_set_debugreg(struct task_struct *task,
+ unsigned long addr, unsigned long data)
+{
+ /* We only support one DABR and no IABRS at the moment */
+ if (addr > 0)
+ return -EINVAL;
+
+ /* The bottom 3 bits are flags */
+ if ((data & ~0x7UL) >= TASK_SIZE)
+ return -EIO;
+
+ /* Ensure translation is on */
+ if (data && !(data & DABR_TRANSLATION))
+ return -EIO;
+
+ task->thread.dabr = data;
+ return 0;
+}
+
+#endif /* _POWERPC_PTRACE_PPC64_H */
Index: linux-cell/arch/powerpc/kernel/ptrace.c
===================================================================
--- linux-cell.orig/arch/powerpc/kernel/ptrace.c 2007-05-29 13:05:55.000000000 +1000
+++ linux-cell/arch/powerpc/kernel/ptrace.c 2007-05-29 16:21:50.000000000 +1000
@@ -36,208 +36,18 @@
#include <asm/system.h>
#ifdef CONFIG_PPC64
-#include "ptrace-common.h"
-#endif
-
-#ifdef CONFIG_PPC32
-/*
- * Set of msr bits that gdb can change on behalf of a process.
- */
-#if defined(CONFIG_40x) || defined(CONFIG_BOOKE)
-#define MSR_DEBUGCHANGE 0
+#include "ptrace-ppc64.h"
#else
-#define MSR_DEBUGCHANGE (MSR_SE | MSR_BE)
+#include "ptrace-ppc32.h"
#endif
-#endif /* CONFIG_PPC32 */
+
+#include "ptrace-common.h"
/*
* does not yet catch signals sent when the child dies.
* in exit.c or in signal.c.
*/
-#ifdef CONFIG_PPC32
-/*
- * Get contents of register REGNO in task TASK.
- */
-static inline unsigned long get_reg(struct task_struct *task, int regno)
-{
- if (regno < sizeof(struct pt_regs) / sizeof(unsigned long)
- && task->thread.regs != NULL)
- return ((unsigned long *)task->thread.regs)[regno];
- return (0);
-}
-
-/*
- * Write contents of register REGNO in task TASK.
- */
-static inline int put_reg(struct task_struct *task, int regno,
- unsigned long data)
-{
- if (regno <= PT_MQ && task->thread.regs != NULL) {
- if (regno == PT_MSR)
- data = (data & MSR_DEBUGCHANGE)
- | (task->thread.regs->msr & ~MSR_DEBUGCHANGE);
- ((unsigned long *)task->thread.regs)[regno] = data;
- return 0;
- }
- return -EIO;
-}
-
-#ifdef CONFIG_ALTIVEC
-/*
- * Get contents of AltiVec register state in task TASK
- */
-static inline int get_vrregs(unsigned long __user *data, struct task_struct *task)
-{
- int i, j;
-
- if (!access_ok(VERIFY_WRITE, data, 133 * sizeof(unsigned long)))
- return -EFAULT;
-
- /* copy AltiVec registers VR[0] .. VR[31] */
- for (i = 0; i < 32; i++)
- for (j = 0; j < 4; j++, data++)
- if (__put_user(task->thread.vr[i].u[j], data))
- return -EFAULT;
-
- /* copy VSCR */
- for (i = 0; i < 4; i++, data++)
- if (__put_user(task->thread.vscr.u[i], data))
- return -EFAULT;
-
- /* copy VRSAVE */
- if (__put_user(task->thread.vrsave, data))
- return -EFAULT;
-
- return 0;
-}
-
-/*
- * Write contents of AltiVec register state into task TASK.
- */
-static inline int set_vrregs(struct task_struct *task, unsigned long __user *data)
-{
- int i, j;
-
- if (!access_ok(VERIFY_READ, data, 133 * sizeof(unsigned long)))
- return -EFAULT;
-
- /* copy AltiVec registers VR[0] .. VR[31] */
- for (i = 0; i < 32; i++)
- for (j = 0; j < 4; j++, data++)
- if (__get_user(task->thread.vr[i].u[j], data))
- return -EFAULT;
-
- /* copy VSCR */
- for (i = 0; i < 4; i++, data++)
- if (__get_user(task->thread.vscr.u[i], data))
- return -EFAULT;
-
- /* copy VRSAVE */
- if (__get_user(task->thread.vrsave, data))
- return -EFAULT;
-
- return 0;
-}
-#endif
-
-#ifdef CONFIG_SPE
-
-/*
- * For get_evrregs/set_evrregs functions 'data' has the following layout:
- *
- * struct {
- * u32 evr[32];
- * u64 acc;
- * u32 spefscr;
- * }
- */
-
-/*
- * Get contents of SPE register state in task TASK.
- */
-static inline int get_evrregs(unsigned long *data, struct task_struct *task)
-{
- int i;
-
- if (!access_ok(VERIFY_WRITE, data, 35 * sizeof(unsigned long)))
- return -EFAULT;
-
- /* copy SPEFSCR */
- if (__put_user(task->thread.spefscr, &data[34]))
- return -EFAULT;
-
- /* copy SPE registers EVR[0] .. EVR[31] */
- for (i = 0; i < 32; i++, data++)
- if (__put_user(task->thread.evr[i], data))
- return -EFAULT;
-
- /* copy ACC */
- if (__put_user64(task->thread.acc, (unsigned long long *)data))
- return -EFAULT;
-
- return 0;
-}
-
-/*
- * Write contents of SPE register state into task TASK.
- */
-static inline int set_evrregs(struct task_struct *task, unsigned long *data)
-{
- int i;
-
- if (!access_ok(VERIFY_READ, data, 35 * sizeof(unsigned long)))
- return -EFAULT;
-
- /* copy SPEFSCR */
- if (__get_user(task->thread.spefscr, &data[34]))
- return -EFAULT;
-
- /* 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))
- return -EFAULT;
-
- return 0;
-}
-#endif /* CONFIG_SPE */
-
-static inline void
-set_single_step(struct task_struct *task)
-{
- struct pt_regs *regs = task->thread.regs;
-
- if (regs != NULL) {
-#if defined(CONFIG_40x) || defined(CONFIG_BOOKE)
- task->thread.dbcr0 = DBCR0_IDM | DBCR0_IC;
- regs->msr |= MSR_DE;
-#else
- regs->msr |= MSR_SE;
-#endif
- }
- set_tsk_thread_flag(task, TIF_SINGLESTEP);
-}
-
-static inline void
-clear_single_step(struct task_struct *task)
-{
- struct pt_regs *regs = task->thread.regs;
-
- if (regs != NULL) {
-#if defined(CONFIG_40x) || defined(CONFIG_BOOKE)
- task->thread.dbcr0 = 0;
- regs->msr &= ~MSR_DE;
-#else
- regs->msr &= ~MSR_SE;
-#endif
- }
- clear_tsk_thread_flag(task, TIF_SINGLESTEP);
-}
-#endif /* CONFIG_PPC32 */
-
/*
* Called by kernel/ptrace.c when detaching..
*
Index: linux-cell/arch/powerpc/kernel/ptrace32.c
===================================================================
--- linux-cell.orig/arch/powerpc/kernel/ptrace32.c 2007-05-29 13:05:55.000000000 +1000
+++ linux-cell/arch/powerpc/kernel/ptrace32.c 2007-05-29 16:21:50.000000000 +1000
@@ -33,6 +33,7 @@
#include <asm/pgtable.h>
#include <asm/system.h>
+#include "ptrace-ppc64.h"
#include "ptrace-common.h"
/*
_______________________________________________
Linuxppc-dev mailing list
Linuxppc-dev@ozlabs.org
https://ozlabs.org/mailman/listinfo/linuxppc-dev
^ permalink raw reply
* [RFC/PATCH 1/6] powerpc: Disable broken PPC_PTRACE_GETFPREGS on 32 bits
From: Benjamin Herrenschmidt @ 2007-05-30 7:17 UTC (permalink / raw)
To: linuxppc-dev; +Cc: ulrich.weigand, Paul Mackerras, Anton Blanchard
The handling of PPC_PTRACE_GETFPREGS is broken on 32 bits kernel,
it will only return half of the registers. Since that call didn't
initially exist for 32 bits kernel (added recently), rather than
fixing it, let's just remove it.
Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
---
arch/powerpc/kernel/ptrace.c | 2 ++
1 file changed, 2 insertions(+)
Index: linux-cell/arch/powerpc/kernel/ptrace.c
===================================================================
--- linux-cell.orig/arch/powerpc/kernel/ptrace.c 2007-05-29 11:34:20.000000000 +1000
+++ linux-cell/arch/powerpc/kernel/ptrace.c 2007-05-29 11:34:35.000000000 +1000
@@ -434,6 +434,7 @@ long arch_ptrace(struct task_struct *chi
break;
}
+#ifdef CONFIG_PPC64
case PPC_PTRACE_GETFPREGS: { /* Get FPRs 0 - 31. */
int i;
unsigned long *reg = &((unsigned long *)child->thread.fpr)[0];
@@ -467,6 +468,7 @@ long arch_ptrace(struct task_struct *chi
}
break;
}
+#endif /* CONFIG_PPC64 */
#ifdef CONFIG_ALTIVEC
case PTRACE_GETVRREGS:
^ permalink raw reply
page: next (older) | prev (newer) | latest
- recent:[subjects (threaded)|topics (new)|topics (active)]
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox