* [PATCH 0/21] This is my pending series for 2.6.23
@ 2007-06-04 5:15 Benjamin Herrenschmidt
2007-06-04 5:15 ` [PATCH 1/21] unmap_vm_area becomes unmap_kernel_range for the public Benjamin Herrenschmidt
` (21 more replies)
0 siblings, 22 replies; 30+ messages in thread
From: Benjamin Herrenschmidt @ 2007-06-04 5:15 UTC (permalink / raw)
To: linuxppc-dev; +Cc: Paul Mackerras, Christoph Hellwig, cbe-oss-dev
It contains
- My PCI IO allocation rework (the first patch changes generic code
and is in -mm already)
- spufs single step & capabilities support
- my cleanup/merge of the ptrace code
- patches from Christoph Hellwig and myself that fix and merge things
in the signal handling code
I'm still working on saving the top 32 bits of registers on 64 bits
for signals, so that's not included here.
^ permalink raw reply [flat|nested] 30+ messages in thread
* [PATCH 1/21] unmap_vm_area becomes unmap_kernel_range for the public
2007-06-04 5:15 [PATCH 0/21] This is my pending series for 2.6.23 Benjamin Herrenschmidt
@ 2007-06-04 5:15 ` Benjamin Herrenschmidt
2007-06-04 5:15 ` [PATCH 2/21] powerpc: Rewrite IO allocation & mapping on powerpc64 Benjamin Herrenschmidt
` (20 subsequent siblings)
21 siblings, 0 replies; 30+ messages in thread
From: Benjamin Herrenschmidt @ 2007-06-04 5:15 UTC (permalink / raw)
To: linuxppc-dev; +Cc: Paul Mackerras, Christoph Hellwig, cbe-oss-dev
This patch makes unmap_vm_area static and a wrapper around a new
exported unmap_kernel_range that takes an explicit range instead
of a vm_area struct.
This makes it more versatile for code that wants to play with kernel
page tables outside of the standard vmalloc area.
(One example is some rework of the PowerPC PCI IO space mapping
code that depends on that patch and removes some code duplication
and horrible abuse of forged struct vm_struct).
Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
---
This patch is already in -mm
Documentation/cachetlb.txt | 2 +-
arch/powerpc/mm/imalloc.c | 3 ++-
arch/powerpc/mm/pgtable_64.c | 1 -
include/linux/vmalloc.h | 3 ++-
mm/vmalloc.c | 13 +++++++++----
5 files changed, 14 insertions(+), 8 deletions(-)
Index: linux-cell/Documentation/cachetlb.txt
===================================================================
--- linux-cell.orig/Documentation/cachetlb.txt 2007-05-24 14:00:32.000000000 +1000
+++ linux-cell/Documentation/cachetlb.txt 2007-05-24 14:01:31.000000000 +1000
@@ -253,7 +253,7 @@ Here are the routines, one by one:
The first of these two routines is invoked after map_vm_area()
has installed the page table entries. The second is invoked
- before unmap_vm_area() deletes the page table entries.
+ before unmap_kernel_range() deletes the page table entries.
There exists another whole class of cpu cache issues which currently
require a whole different set of interfaces to handle properly.
Index: linux-cell/arch/powerpc/mm/imalloc.c
===================================================================
--- linux-cell.orig/arch/powerpc/mm/imalloc.c 2007-05-24 14:00:32.000000000 +1000
+++ linux-cell/arch/powerpc/mm/imalloc.c 2007-05-24 14:01:31.000000000 +1000
@@ -301,7 +301,8 @@ void im_free(void * addr)
for (p = &imlist ; (tmp = *p) ; p = &tmp->next) {
if (tmp->addr == addr) {
*p = tmp->next;
- unmap_vm_area(tmp);
+ unmap_kernel_range((unsigned long)tmp->addr,
+ tmp->size);
kfree(tmp);
mutex_unlock(&imlist_mutex);
return;
Index: linux-cell/arch/powerpc/mm/pgtable_64.c
===================================================================
--- linux-cell.orig/arch/powerpc/mm/pgtable_64.c 2007-05-24 14:00:32.000000000 +1000
+++ linux-cell/arch/powerpc/mm/pgtable_64.c 2007-05-24 14:01:31.000000000 +1000
@@ -240,7 +240,6 @@ int __ioremap_explicit(phys_addr_t pa, u
/*
* Unmap an IO region and remove it from imalloc'd list.
* Access to IO memory should be serialized by driver.
- * This code is modeled after vmalloc code - unmap_vm_area()
*
* XXX what about calls before mem_init_done (ie python_countermeasures())
*/
Index: linux-cell/include/linux/vmalloc.h
===================================================================
--- linux-cell.orig/include/linux/vmalloc.h 2007-05-24 14:00:32.000000000 +1000
+++ linux-cell/include/linux/vmalloc.h 2007-05-24 14:01:31.000000000 +1000
@@ -65,9 +65,10 @@ extern struct vm_struct *get_vm_area_nod
unsigned long flags, int node,
gfp_t gfp_mask);
extern struct vm_struct *remove_vm_area(void *addr);
+
extern int map_vm_area(struct vm_struct *area, pgprot_t prot,
struct page ***pages);
-extern void unmap_vm_area(struct vm_struct *area);
+extern void unmap_kernel_range(unsigned long addr, unsigned long size);
/*
* Internals. Dont't use..
Index: linux-cell/mm/vmalloc.c
===================================================================
--- linux-cell.orig/mm/vmalloc.c 2007-05-24 14:00:32.000000000 +1000
+++ linux-cell/mm/vmalloc.c 2007-05-24 14:02:03.000000000 +1000
@@ -68,12 +68,12 @@ static inline void vunmap_pud_range(pgd_
} while (pud++, addr = next, addr != end);
}
-void unmap_vm_area(struct vm_struct *area)
+void unmap_kernel_range(unsigned long addr, unsigned long size)
{
pgd_t *pgd;
unsigned long next;
- unsigned long addr = (unsigned long) area->addr;
- unsigned long end = addr + area->size;
+ unsigned long start = addr;
+ unsigned long end = addr + size;
BUG_ON(addr >= end);
pgd = pgd_offset_k(addr);
@@ -84,7 +84,12 @@ void unmap_vm_area(struct vm_struct *are
continue;
vunmap_pud_range(pgd, addr, next);
} while (pgd++, addr = next, addr != end);
- flush_tlb_kernel_range((unsigned long) area->addr, end);
+ flush_tlb_kernel_range(start, end);
+}
+
+static void unmap_vm_area(struct vm_struct *area)
+{
+ unmap_kernel_range((unsigned long)area->addr, area->size);
}
static int vmap_pte_range(pmd_t *pmd, unsigned long addr,
^ permalink raw reply [flat|nested] 30+ messages in thread
* [PATCH 2/21] powerpc: Rewrite IO allocation & mapping on powerpc64
2007-06-04 5:15 [PATCH 0/21] This is my pending series for 2.6.23 Benjamin Herrenschmidt
2007-06-04 5:15 ` [PATCH 1/21] unmap_vm_area becomes unmap_kernel_range for the public Benjamin Herrenschmidt
@ 2007-06-04 5:15 ` Benjamin Herrenschmidt
2007-06-04 5:15 ` [PATCH 3/21] spufs: Add support for SPU single stepping Benjamin Herrenschmidt
` (19 subsequent siblings)
21 siblings, 0 replies; 30+ messages in thread
From: Benjamin Herrenschmidt @ 2007-06-04 5:15 UTC (permalink / raw)
To: linuxppc-dev; +Cc: Paul Mackerras, Christoph Hellwig, cbe-oss-dev
This patch rewrites pretty much from scratch the handling of
MMIO and PIO space allocations on powerpc64. The main goals
are:
- Get rid of imalloc and use more common code where possible
- Simplify the current mess so that PIO space is allocated and
mapped in a single place for PCI bridges
- Handle allocation constraints of PIO for all bridges including
hot plugged ones within the 2GB space reserved for IO ports,
so that devices on hotplugged busses will now work with drivers
that assume IO ports fit in an int.
- Cleanup and separate tracking of the ISA space in the reserved
low 64K of IO space. No ISA -> Nothing mapped there.
The patch is mostly untested ! This is not aimed at 2.6.22 but
rather the next merge window since it's pretty big and we need to
test well the hotplug stuff among others.
I booted a cell blade with IDE on PIO and MMIO and a dual G5 so
far, that's it :-)
With this patch, all allocations are done using the code in
mm/vmalloc.c, though we use the low level __get_vm_area with
explicit start/stop constraints in order to manage separate
areas for vmalloc/vmap, ioremap, and PCI IOs.
This greatly simplifies a lot of things, as you can see in the
diffstat of that patch :-)
A new pair of functions pcibios_map/unmap_io_space() now replace
all of the previous code that used to manipulate PCI IOs space.
The allocation is done at mapping time, which is now called from
scan_phb's, just before the devices are probed (instead of after,
which is by itself a bug fix). The only other caller is the PCI
hotplug code for hot adding PCI-PCI bridges (slots).
imalloc is gone, as is the "sub-allocation" thing, but I do beleive
that hotplug should still work in the sense that the space allocation
is always done by the PHB, but if you unmap a child bus of this PHB
(which seems to be possible), then the code should properly tear
down all the HPTE mappings for that area of the PHB allocated IO space.
I now always reserve the first 64K of IO space for the bridge with
the ISA bus on it. I have moved the code for tracking ISA in a separate
file which should also make it smarter if we ever are capable of
hot unplugging or re-plugging an ISA bridge.
This should have a side effect on platforms like powermac where VGA IOs
will no longer work. This is done on purpose though as they would have
worked semi-randomly before. The idea at this point is to isolate drivers
that might need to access those and fix them by providing a proper
function to obtain an offset to the legacy IOs of a given bus.
Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
---
Applied on top of whatever else I posted today. This version fixes
things here or there and adds more debugging. I no longer tear down
the PTEs when a PCI 2 PCI bridge is unplugged as such mappings might
be smaller than 64K pages on machines with 4K IOs. I flush the hash
table instead (and introduced a new call for that).
arch/powerpc/kernel/Makefile | 2
arch/powerpc/kernel/isa-bridge.c | 271 ++++++++++++++++++++
arch/powerpc/kernel/of_platform.c | 8
arch/powerpc/kernel/pci_64.c | 356 +++++++++------------------
arch/powerpc/kernel/rtas_pci.c | 7
arch/powerpc/mm/Makefile | 3
arch/powerpc/mm/imalloc.c | 314 -----------------------
arch/powerpc/mm/mmu_decl.h | 12
arch/powerpc/mm/pgtable_64.c | 204 +++------------
arch/powerpc/mm/tlb_64.c | 56 ++++
arch/powerpc/platforms/cell/io-workarounds.c | 2
arch/powerpc/platforms/iseries/pci.c | 5
arch/powerpc/platforms/maple/pci.c | 35 --
arch/powerpc/platforms/pasemi/pci.c | 20 -
arch/powerpc/platforms/powermac/pci.c | 32 --
arch/powerpc/platforms/pseries/pci_dlpar.c | 2
arch/powerpc/platforms/pseries/pseries.h | 2
drivers/pci/hotplug/rpadlpar_core.c | 6
include/asm-powerpc/floppy.h | 6
include/asm-powerpc/io.h | 19 -
include/asm-powerpc/pci-bridge.h | 6
include/asm-powerpc/pci.h | 4
include/asm-powerpc/pgtable-ppc64.h | 23 +
include/asm-powerpc/ppc-pci.h | 6
include/asm-powerpc/tlbflush.h | 5
25 files changed, 557 insertions(+), 849 deletions(-)
Index: linux-cell/include/asm-powerpc/pgtable-ppc64.h
===================================================================
--- linux-cell.orig/include/asm-powerpc/pgtable-ppc64.h 2007-05-24 14:00:31.000000000 +1000
+++ linux-cell/include/asm-powerpc/pgtable-ppc64.h 2007-05-24 14:02:09.000000000 +1000
@@ -27,7 +27,7 @@ struct mm_struct;
*/
#define PGTABLE_EADDR_SIZE (PTE_INDEX_SIZE + PMD_INDEX_SIZE + \
PUD_INDEX_SIZE + PGD_INDEX_SIZE + PAGE_SHIFT)
-#define PGTABLE_RANGE (1UL << PGTABLE_EADDR_SIZE)
+#define PGTABLE_RANGE (ASM_CONST(1) << PGTABLE_EADDR_SIZE)
#if TASK_SIZE_USER64 > PGTABLE_RANGE
#error TASK_SIZE_USER64 exceeds pagetable range
@@ -37,19 +37,28 @@ struct mm_struct;
#error TASK_SIZE_USER64 exceeds user VSID range
#endif
+
/*
* Define the address range of the vmalloc VM area.
*/
#define VMALLOC_START ASM_CONST(0xD000000000000000)
-#define VMALLOC_SIZE ASM_CONST(0x80000000000)
+#define VMALLOC_SIZE (PGTABLE_RANGE >> 1)
#define VMALLOC_END (VMALLOC_START + VMALLOC_SIZE)
/*
- * Define the address range of the imalloc VM area.
- */
-#define PHBS_IO_BASE VMALLOC_END
-#define IMALLOC_BASE (PHBS_IO_BASE + 0x80000000ul) /* Reserve 2 gigs for PHBs */
-#define IMALLOC_END (VMALLOC_START + PGTABLE_RANGE)
+ * Define the address ranges for MMIO and IO space :
+ *
+ * ISA_IO_BASE = VMALLOC_END, 64K reserved area
+ * PHB_IO_BASE = ISA_IO_BASE + 64K to ISA_IO_BASE + 2G, PHB IO spaces
+ * IOREMAP_BASE = ISA_IO_BASE + 2G to VMALLOC_START + PGTABLE_RANGE
+ */
+#define FULL_IO_SIZE 0x80000000ul
+#define ISA_IO_BASE (VMALLOC_END)
+#define ISA_IO_END (VMALLOC_END + 0x10000ul)
+#define PHB_IO_BASE (ISA_IO_END)
+#define PHB_IO_END (VMALLOC_END + FULL_IO_SIZE)
+#define IOREMAP_BASE (PHB_IO_END)
+#define IOREMAP_END (VMALLOC_START + PGTABLE_RANGE)
/*
* Region IDs
Index: linux-cell/arch/powerpc/kernel/Makefile
===================================================================
--- linux-cell.orig/arch/powerpc/kernel/Makefile 2007-05-24 14:00:31.000000000 +1000
+++ linux-cell/arch/powerpc/kernel/Makefile 2007-05-24 14:02:09.000000000 +1000
@@ -65,7 +65,7 @@ obj-$(CONFIG_PPC_UDBG_16550) += legacy_s
module-$(CONFIG_PPC64) += module_64.o
obj-$(CONFIG_MODULES) += $(module-y)
-pci64-$(CONFIG_PPC64) += pci_64.o pci_dn.o
+pci64-$(CONFIG_PPC64) += pci_64.o pci_dn.o isa-bridge.o
pci32-$(CONFIG_PPC32) := pci_32.o
obj-$(CONFIG_PCI) += $(pci64-y) $(pci32-y)
obj-$(CONFIG_PCI_MSI) += msi.o
Index: linux-cell/arch/powerpc/kernel/isa-bridge.c
===================================================================
--- /dev/null 1970-01-01 00:00:00.000000000 +0000
+++ linux-cell/arch/powerpc/kernel/isa-bridge.c 2007-05-24 14:02:09.000000000 +1000
@@ -0,0 +1,271 @@
+/*
+ * Routines for tracking a legacy ISA bridge
+ *
+ * Copyrigh 2007 Benjamin Herrenschmidt <benh@kernel.crashing.org>, IBM Corp.
+ *
+ * Some bits and pieces moved over from pci_64.c
+ *
+ * Copyrigh 2003 Anton Blanchard <anton@au.ibm.com>, IBM Corp.
+ *
+ * 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.
+ */
+
+#define DEBUG
+
+#include <linux/kernel.h>
+#include <linux/pci.h>
+#include <linux/string.h>
+#include <linux/init.h>
+#include <linux/mm.h>
+#include <linux/notifier.h>
+
+#include <asm/processor.h>
+#include <asm/io.h>
+#include <asm/prom.h>
+#include <asm/pci-bridge.h>
+#include <asm/machdep.h>
+#include <asm/ppc-pci.h>
+#include <asm/firmware.h>
+
+unsigned long isa_io_base; /* NULL if no ISA bus */
+EXPORT_SYMBOL(isa_io_base);
+
+/* Cached ISA bridge dev. */
+static struct device_node *isa_bridge_devnode;
+struct pci_dev *isa_bridge_pcidev;
+EXPORT_SYMBOL_GPL(isa_bridge_pcidev);
+
+#define ISA_SPACE_MASK 0x1
+#define ISA_SPACE_IO 0x1
+
+static void __devinit pci_process_ISA_OF_ranges(struct device_node *isa_node,
+ unsigned long phb_io_base_phys)
+{
+ /* We should get some saner parsing here and remove these structs */
+ struct pci_address {
+ u32 a_hi;
+ u32 a_mid;
+ u32 a_lo;
+ };
+
+ struct isa_address {
+ u32 a_hi;
+ u32 a_lo;
+ };
+
+ struct isa_range {
+ struct isa_address isa_addr;
+ struct pci_address pci_addr;
+ unsigned int size;
+ };
+
+ const struct isa_range *range;
+ unsigned long pci_addr;
+ unsigned int isa_addr;
+ unsigned int size;
+ int rlen = 0;
+
+ range = of_get_property(isa_node, "ranges", &rlen);
+ if (range == NULL || (rlen < sizeof(struct isa_range)))
+ goto inval_range;
+
+ /* From "ISA Binding to 1275"
+ * The ranges property is laid out as an array of elements,
+ * each of which comprises:
+ * cells 0 - 1: an ISA address
+ * cells 2 - 4: a PCI address
+ * (size depending on dev->n_addr_cells)
+ * cell 5: the size of the range
+ */
+ if ((range->isa_addr.a_hi && ISA_SPACE_MASK) != ISA_SPACE_IO) {
+ range++;
+ rlen -= sizeof(struct isa_range);
+ if (rlen < sizeof(struct isa_range))
+ goto inval_range;
+ }
+ if ((range->isa_addr.a_hi && ISA_SPACE_MASK) != ISA_SPACE_IO)
+ goto inval_range;
+
+ isa_addr = range->isa_addr.a_lo;
+ pci_addr = (unsigned long) range->pci_addr.a_mid << 32 |
+ range->pci_addr.a_lo;
+
+ /* Assume these are both zero. Note: We could fix that and
+ * do a proper parsing instead ... oh well, that will do for
+ * now as nobody uses fancy mappings for ISA bridges
+ */
+ if ((pci_addr != 0) || (isa_addr != 0)) {
+ printk(KERN_ERR "unexpected isa to pci mapping: %s\n",
+ __FUNCTION__);
+ return;
+ }
+
+ /* Align size and make sure it's cropped to 64K */
+ size = PAGE_ALIGN(range->size);
+ if (size > 0x10000)
+ size = 0x10000;
+
+ printk(KERN_ERR "no ISA IO ranges or unexpected isa range,"
+ "mapping 64k\n");
+
+ __ioremap_at(phb_io_base_phys, (void *)ISA_IO_BASE,
+ size, _PAGE_NO_CACHE|_PAGE_GUARDED);
+ return;
+
+inval_range:
+ printk(KERN_ERR "no ISA IO ranges or unexpected isa range,"
+ "mapping 64k\n");
+ __ioremap_at(phb_io_base_phys, (void *)ISA_IO_BASE,
+ 0x10000, _PAGE_NO_CACHE|_PAGE_GUARDED);
+}
+
+
+/**
+ * isa_bridge_find_early - Find and map the ISA IO space early before
+ * main PCI discovery. This is optionally called by
+ * the arch code when adding PCI PHBs to get early
+ * access to ISA IO ports
+ */
+void __init isa_bridge_find_early(struct pci_controller *hose)
+{
+ struct device_node *np, *parent = NULL, *tmp;
+
+ /* If we already have an ISA bridge, bail off */
+ if (isa_bridge_devnode != NULL)
+ return;
+
+ /* For each "isa" node in the system. Note : we do a search by
+ * type and not by name. It might be better to do by name but that's
+ * what the code used to do and I don't want to break too much at
+ * once. We can look into changing that separately
+ */
+ for_each_node_by_type(np, "isa") {
+ /* Look for our hose being a parent */
+ for (parent = of_get_parent(np); parent;) {
+ if (parent == hose->arch_data) {
+ of_node_put(parent);
+ break;
+ }
+ tmp = parent;
+ parent = of_get_parent(parent);
+ of_node_put(tmp);
+ }
+ if (parent != NULL)
+ break;
+ }
+ if (np == NULL)
+ return;
+ isa_bridge_devnode = np;
+
+ /* Now parse the "ranges" property and setup the ISA mapping */
+ pci_process_ISA_OF_ranges(np, hose->io_base_phys);
+
+ /* Set the global ISA io base to indicate we have an ISA bridge */
+ isa_io_base = ISA_IO_BASE;
+
+ pr_debug("ISA bridge (early) is %s\n", np->full_name);
+}
+
+/**
+ * isa_bridge_find_late - Find and map the ISA IO space upon discovery of
+ * a new ISA bridge
+ */
+static void __devinit isa_bridge_find_late(struct pci_dev *pdev,
+ struct device_node *devnode)
+{
+ struct pci_controller *hose = pci_bus_to_host(pdev->bus);
+
+ /* Store ISA device node and PCI device */
+ isa_bridge_devnode = of_node_get(devnode);
+ isa_bridge_pcidev = pdev;
+
+ /* Now parse the "ranges" property and setup the ISA mapping */
+ pci_process_ISA_OF_ranges(devnode, hose->io_base_phys);
+
+ /* Set the global ISA io base to indicate we have an ISA bridge */
+ isa_io_base = ISA_IO_BASE;
+
+ pr_debug("ISA bridge (late) is %s on %s\n",
+ devnode->full_name, pci_name(pdev));
+}
+
+/**
+ * isa_bridge_remove - Remove/unmap an ISA bridge
+ */
+static void isa_bridge_remove(void)
+{
+ pr_debug("ISA bridge removed !\n");
+
+ /* Clear the global ISA io base to indicate that we have no more
+ * ISA bridge. Note that drivers don't quite handle that, though
+ * we should probably do something about it. But do we ever really
+ * have ISA bridges being removed on machines using legacy devices ?
+ */
+ isa_io_base = ISA_IO_BASE;
+
+ /* Clear references to the bridge */
+ of_node_put(isa_bridge_devnode);
+ isa_bridge_devnode = NULL;
+ isa_bridge_pcidev = NULL;
+
+ /* Unmap the ISA area */
+ __iounmap_at((void *)ISA_IO_BASE, 0x10000);
+}
+
+/**
+ * isa_bridge_notify - Get notified of PCI devices addition/removal
+ */
+static int __devinit isa_bridge_notify(struct notifier_block *nb,
+ unsigned long action, void *data)
+{
+ struct device *dev = data;
+ struct pci_dev *pdev = to_pci_dev(dev);
+ struct device_node *devnode = pci_device_to_OF_node(pdev);
+
+ switch(action) {
+ case BUS_NOTIFY_ADD_DEVICE:
+ /* Check if we have an early ISA device, without PCI dev */
+ if (isa_bridge_devnode && isa_bridge_devnode == devnode &&
+ !isa_bridge_pcidev) {
+ pr_debug("ISA bridge PCI attached: %s\n",
+ pci_name(pdev));
+ isa_bridge_pcidev = pdev;
+ }
+
+ /* Check if we have no ISA device, and this happens to be one,
+ * register it as such if it has an OF device
+ */
+ if (!isa_bridge_devnode && devnode && devnode->type &&
+ !strcmp(devnode->type, "isa"))
+ isa_bridge_find_late(pdev, devnode);
+
+ return 0;
+ case BUS_NOTIFY_DEL_DEVICE:
+ /* Check if this our existing ISA device */
+ if (pdev == isa_bridge_pcidev ||
+ (devnode && devnode == isa_bridge_devnode))
+ isa_bridge_remove();
+ return 0;
+ }
+ return 0;
+}
+
+static struct notifier_block isa_bridge_notifier = {
+ .notifier_call = isa_bridge_notify
+};
+
+/**
+ * isa_bridge_init - register to be notified of ISA bridge addition/removal
+ *
+ */
+static int __init isa_bridge_init(void)
+{
+ if (firmware_has_feature(FW_FEATURE_ISERIES))
+ return 0;
+ bus_register_notifier(&pci_bus_type, &isa_bridge_notifier);
+ return 0;
+}
+arch_initcall(isa_bridge_init);
Index: linux-cell/arch/powerpc/kernel/of_platform.c
===================================================================
--- linux-cell.orig/arch/powerpc/kernel/of_platform.c 2007-05-24 14:00:31.000000000 +1000
+++ linux-cell/arch/powerpc/kernel/of_platform.c 2007-05-24 14:02:09.000000000 +1000
@@ -427,14 +427,6 @@ static int __devinit of_pci_phb_probe(st
/* Process "ranges" property */
pci_process_bridge_OF_ranges(phb, dev->node, 0);
- /* Setup IO space. We use the non-dynamic version of that code here,
- * which doesn't quite support unplugging. Next kernel release will
- * have a better fix for this.
- * Note also that we don't do ISA, this will also be fixed with a
- * more massive rework.
- */
- pci_setup_phb_io(phb, 0);
-
/* Init pci_dn data structures */
pci_devs_phb_init_dynamic(phb);
Index: linux-cell/arch/powerpc/kernel/pci_64.c
===================================================================
--- linux-cell.orig/arch/powerpc/kernel/pci_64.c 2007-05-24 14:00:31.000000000 +1000
+++ linux-cell/arch/powerpc/kernel/pci_64.c 2007-05-24 14:02:09.000000000 +1000
@@ -11,7 +11,7 @@
* 2 of the License, or (at your option) any later version.
*/
-#undef DEBUG
+#define DEBUG
#include <linux/kernel.h>
#include <linux/pci.h>
@@ -22,6 +22,7 @@
#include <linux/list.h>
#include <linux/syscalls.h>
#include <linux/irq.h>
+#include <linux/vmalloc.h>
#include <asm/processor.h>
#include <asm/io.h>
@@ -41,35 +42,26 @@
unsigned long pci_probe_only = 1;
int pci_assign_all_buses = 0;
-static int pci_initial_scan_done;
static void fixup_resource(struct resource *res, struct pci_dev *dev);
static void do_bus_setup(struct pci_bus *bus);
-static void phbs_remap_io(void);
/* pci_io_base -- the base address from which io bars are offsets.
* This is the lowest I/O base address (so bar values are always positive),
* and it *must* be the start of ISA space if an ISA bus exists because
- * ISA drivers use hard coded offsets. If no ISA bus exists a dummy
- * page is mapped and isa_io_limit prevents access to it.
+ * ISA drivers use hard coded offsets. If no ISA bus exists nothing
+ * is mapped on the first 64K of IO space
*/
-unsigned long isa_io_base; /* NULL if no ISA bus */
-EXPORT_SYMBOL(isa_io_base);
-unsigned long pci_io_base;
+unsigned long pci_io_base = ISA_IO_BASE;
EXPORT_SYMBOL(pci_io_base);
-void iSeries_pcibios_init(void);
-
LIST_HEAD(hose_list);
static struct dma_mapping_ops *pci_dma_ops;
+/* XXX kill that some day ... */
int global_phb_number; /* Global phb counter */
-/* Cached ISA bridge dev. */
-struct pci_dev *ppc64_isabridge_dev = NULL;
-EXPORT_SYMBOL_GPL(ppc64_isabridge_dev);
-
void set_pci_dma_ops(struct dma_mapping_ops *dma_ops)
{
pci_dma_ops = dma_ops;
@@ -100,7 +92,7 @@ void pcibios_resource_to_bus(struct pci
return;
if (res->flags & IORESOURCE_IO)
- offset = (unsigned long)hose->io_base_virt - pci_io_base;
+ offset = (unsigned long)hose->io_base_virt - _IO_BASE;
if (res->flags & IORESOURCE_MEM)
offset = hose->pci_mem_offset;
@@ -119,7 +111,7 @@ void pcibios_bus_to_resource(struct pci_
return;
if (res->flags & IORESOURCE_IO)
- offset = (unsigned long)hose->io_base_virt - pci_io_base;
+ offset = (unsigned long)hose->io_base_virt - _IO_BASE;
if (res->flags & IORESOURCE_MEM)
offset = hose->pci_mem_offset;
@@ -156,7 +148,7 @@ void pcibios_align_resource(void *data,
if (res->flags & IORESOURCE_IO) {
unsigned long offset = (unsigned long)hose->io_base_virt -
- pci_io_base;
+ _IO_BASE;
/* Make sure we start at our min on all hoses */
if (start - offset < PCIBIOS_MIN_IO)
start = PCIBIOS_MIN_IO + offset;
@@ -535,10 +527,16 @@ void __devinit scan_phb(struct pci_contr
bus->secondary = hose->first_busno;
hose->bus = bus;
+ if (!firmware_has_feature(FW_FEATURE_ISERIES))
+ pcibios_map_io_space(bus);
+
bus->resource[0] = res = &hose->io_resource;
- if (res->flags && request_resource(&ioport_resource, res))
+ if (res->flags && request_resource(&ioport_resource, res)) {
printk(KERN_ERR "Failed to request PCI IO region "
"on PCI domain %04x\n", hose->global_number);
+ DBG("res->start = 0x%016lx, res->end = 0x%016lx\n",
+ res->start, res->end);
+ }
for (i = 0; i < 3; ++i) {
res = &hose->mem_resources[i];
@@ -596,17 +594,6 @@ static int __init pcibios_init(void)
if (ppc_md.pcibios_fixup)
ppc_md.pcibios_fixup();
- /* Cache the location of the ISA bridge (if we have one) */
- ppc64_isabridge_dev = pci_get_class(PCI_CLASS_BRIDGE_ISA << 8, NULL);
- if (ppc64_isabridge_dev != NULL)
- printk(KERN_DEBUG "ISA bridge at %s\n", pci_name(ppc64_isabridge_dev));
-
- if (!firmware_has_feature(FW_FEATURE_ISERIES))
- /* map in PCI I/O space */
- phbs_remap_io();
-
- pci_initial_scan_done = 1;
-
printk(KERN_DEBUG "PCI: Probing PCI hardware done\n");
return 0;
@@ -711,7 +698,7 @@ static struct resource *__pci_mmap_make_
#endif
res_bit = IORESOURCE_MEM;
} else {
- io_offset = (unsigned long)hose->io_base_virt - pci_io_base;
+ io_offset = (unsigned long)hose->io_base_virt - _IO_BASE;
*offset += io_offset;
res_bit = IORESOURCE_IO;
}
@@ -881,76 +868,6 @@ void pcibios_add_platform_entries(struct
device_create_file(&pdev->dev, &dev_attr_devspec);
}
-#define ISA_SPACE_MASK 0x1
-#define ISA_SPACE_IO 0x1
-
-static void __devinit pci_process_ISA_OF_ranges(struct device_node *isa_node,
- unsigned long phb_io_base_phys,
- void __iomem * phb_io_base_virt)
-{
- /* Remove these asap */
-
- struct pci_address {
- u32 a_hi;
- u32 a_mid;
- u32 a_lo;
- };
-
- struct isa_address {
- u32 a_hi;
- u32 a_lo;
- };
-
- struct isa_range {
- struct isa_address isa_addr;
- struct pci_address pci_addr;
- unsigned int size;
- };
-
- const struct isa_range *range;
- unsigned long pci_addr;
- unsigned int isa_addr;
- unsigned int size;
- int rlen = 0;
-
- range = of_get_property(isa_node, "ranges", &rlen);
- if (range == NULL || (rlen < sizeof(struct isa_range))) {
- printk(KERN_ERR "no ISA ranges or unexpected isa range size,"
- "mapping 64k\n");
- __ioremap_explicit(phb_io_base_phys,
- (unsigned long)phb_io_base_virt,
- 0x10000, _PAGE_NO_CACHE | _PAGE_GUARDED);
- return;
- }
-
- /* From "ISA Binding to 1275"
- * The ranges property is laid out as an array of elements,
- * each of which comprises:
- * cells 0 - 1: an ISA address
- * cells 2 - 4: a PCI address
- * (size depending on dev->n_addr_cells)
- * cell 5: the size of the range
- */
- if ((range->isa_addr.a_hi && ISA_SPACE_MASK) == ISA_SPACE_IO) {
- isa_addr = range->isa_addr.a_lo;
- pci_addr = (unsigned long) range->pci_addr.a_mid << 32 |
- range->pci_addr.a_lo;
-
- /* Assume these are both zero */
- if ((pci_addr != 0) || (isa_addr != 0)) {
- printk(KERN_ERR "unexpected isa to pci mapping: %s\n",
- __FUNCTION__);
- return;
- }
-
- size = PAGE_ALIGN(range->size);
-
- __ioremap_explicit(phb_io_base_phys,
- (unsigned long) phb_io_base_virt,
- size, _PAGE_NO_CACHE | _PAGE_GUARDED);
- }
-}
-
void __devinit pci_process_bridge_OF_ranges(struct pci_controller *hose,
struct device_node *dev, int prim)
{
@@ -1045,155 +962,122 @@ void __devinit pci_process_bridge_OF_ran
}
}
-void __devinit pci_setup_phb_io(struct pci_controller *hose, int primary)
+#ifdef CONFIG_HOTPLUG
+
+int pcibios_unmap_io_space(struct pci_bus *bus)
{
- unsigned long size = hose->pci_io_size;
- unsigned long io_virt_offset;
- struct resource *res;
- struct device_node *isa_dn;
+ struct pci_controller *hose;
- if (size == 0)
- return;
+ WARN_ON(bus == NULL);
- hose->io_base_virt = reserve_phb_iospace(size);
- DBG("phb%d io_base_phys 0x%lx io_base_virt 0x%lx\n",
- hose->global_number, hose->io_base_phys,
- (unsigned long) hose->io_base_virt);
-
- if (primary) {
- pci_io_base = (unsigned long)hose->io_base_virt;
- isa_dn = of_find_node_by_type(NULL, "isa");
- if (isa_dn) {
- isa_io_base = pci_io_base;
- pci_process_ISA_OF_ranges(isa_dn, hose->io_base_phys,
- hose->io_base_virt);
- of_node_put(isa_dn);
- }
- }
+ /* If this is not a PHB, we only flush the hash table over
+ * the area mapped by this bridge. We don't play with the PTE
+ * mappings since we might have to deal with sub-page alignemnts
+ * so flushing the hash table is the only sane way to make sure
+ * that no hash entries are covering that removed bridge area
+ * while still allowing other busses overlapping those pages
+ */
+ if (bus->self) {
+ struct resource *res = bus->resource[0];
- io_virt_offset = (unsigned long)hose->io_base_virt - pci_io_base;
- res = &hose->io_resource;
- res->start += io_virt_offset;
- res->end += io_virt_offset;
+ DBG("IO unmapping for PCI-PCI bridge %s\n",
+ pci_name(bus->self));
- /* If this is called after the initial PCI scan, then we need to
- * proceed to IO mappings now
- */
- if (pci_initial_scan_done)
- __ioremap_explicit(hose->io_base_phys,
- (unsigned long)hose->io_base_virt,
- hose->pci_io_size,
- _PAGE_NO_CACHE | _PAGE_GUARDED);
-}
+ __flush_hash_table_range(&init_mm, res->start + _IO_BASE,
+ res->end - res->start + 1);
+ return 0;
+ }
-void __devinit pci_setup_phb_io_dynamic(struct pci_controller *hose,
- int primary)
-{
- unsigned long size = hose->pci_io_size;
- unsigned long io_virt_offset;
- struct resource *res;
+ /* Get the host bridge */
+ hose = pci_bus_to_host(bus);
- if (size == 0)
- return;
+ /* Check if we have IOs allocated */
+ if (hose->io_base_alloc == 0)
+ return 0;
- hose->io_base_virt = __ioremap(hose->io_base_phys, size,
- _PAGE_NO_CACHE | _PAGE_GUARDED);
- DBG("phb%d io_base_phys 0x%lx io_base_virt 0x%lx\n",
- hose->global_number, hose->io_base_phys,
- (unsigned long) hose->io_base_virt);
+ DBG("IO unmapping for PHB %s\n",
+ ((struct device_node *)hose->arch_data)->full_name);
+ DBG(" alloc=0x%p\n", hose->io_base_alloc);
- if (primary)
- pci_io_base = (unsigned long)hose->io_base_virt;
+ /* This is a PHB, we fully unmap the IO area */
+ vunmap(hose->io_base_alloc);
- io_virt_offset = (unsigned long)hose->io_base_virt - pci_io_base;
- res = &hose->io_resource;
- res->start += io_virt_offset;
- res->end += io_virt_offset;
+ return 0;
}
+EXPORT_SYMBOL_GPL(pcibios_unmap_io_space);
+#endif /* CONFIG_HOTPLUG */
-static int get_bus_io_range(struct pci_bus *bus, unsigned long *start_phys,
- unsigned long *start_virt, unsigned long *size)
+int __devinit pcibios_map_io_space(struct pci_bus *bus)
{
- struct pci_controller *hose = pci_bus_to_host(bus);
- struct resource *res;
-
- if (bus->self)
- res = bus->resource[0];
- else
- /* Root Bus */
- res = &hose->io_resource;
-
- if (res->end == 0 && res->start == 0)
- return 1;
+ struct vm_struct *area;
+ unsigned long phys_page;
+ unsigned long size_page;
+ unsigned long io_virt_offset;
+ struct pci_controller *hose;
- *start_virt = pci_io_base + res->start;
- *start_phys = *start_virt + hose->io_base_phys
- - (unsigned long) hose->io_base_virt;
+ WARN_ON(bus == NULL);
- if (res->end > res->start)
- *size = res->end - res->start + 1;
- else {
- printk("%s(): unexpected region 0x%lx->0x%lx\n",
- __FUNCTION__, res->start, res->end);
- return 1;
+ /* If this not a PHB, nothing to do, page tables still exist and
+ * thus HPTEs will be faulted in when needed
+ */
+ if (bus->self) {
+ DBG("IO mapping for PCI-PCI bridge %s\n",
+ pci_name(bus->self));
+ DBG(" virt=0x%016lx...0x%016lx\n",
+ bus->resource[0]->start + _IO_BASE,
+ bus->resource[0]->end + _IO_BASE);
+ return 0;
}
- return 0;
-}
+ /* Get the host bridge */
+ hose = pci_bus_to_host(bus);
+ phys_page = _ALIGN_DOWN(hose->io_base_phys, PAGE_SIZE);
+ size_page = _ALIGN_UP(hose->pci_io_size, PAGE_SIZE);
-int unmap_bus_range(struct pci_bus *bus)
-{
- unsigned long start_phys;
- unsigned long start_virt;
- unsigned long size;
+ /* Make sure IO area address is clear */
+ hose->io_base_alloc = NULL;
- if (!bus) {
- printk(KERN_ERR "%s() expected bus\n", __FUNCTION__);
- return 1;
- }
-
- if (get_bus_io_range(bus, &start_phys, &start_virt, &size))
- return 1;
- if (__iounmap_explicit((void __iomem *) start_virt, size))
- return 1;
-
- return 0;
-}
-EXPORT_SYMBOL(unmap_bus_range);
+ /* If there's no IO to map on that bus, get away too */
+ if (hose->pci_io_size == 0 || hose->io_base_phys == 0)
+ return 0;
-int remap_bus_range(struct pci_bus *bus)
-{
- unsigned long start_phys;
- unsigned long start_virt;
- unsigned long size;
+ /* Let's allocate some IO space for that guy. We don't pass
+ * VM_IOREMAP because we don't care about alignment tricks that
+ * the core does in that case. Maybe we should due to stupid card
+ * with incomplete address decoding but I'd rather not deal with
+ * those outside of the reserved 64K legacy region.
+ */
+ area = __get_vm_area(size_page, 0, PHB_IO_BASE, PHB_IO_END);
+ if (area == NULL)
+ return -ENOMEM;
+ hose->io_base_alloc = area->addr;
+ hose->io_base_virt = (void __iomem *)(area->addr +
+ hose->io_base_phys - phys_page);
+
+ DBG("IO mapping for PHB %s\n",
+ ((struct device_node *)hose->arch_data)->full_name);
+ DBG(" phys=0x%016lx, virt=0x%p (alloc=0x%p)\n",
+ hose->io_base_phys, hose->io_base_virt, hose->io_base_alloc);
+ DBG(" size=0x%016lx (alloc=0x%016lx)\n",
+ hose->pci_io_size, size_page);
+
+ /* Establish the mapping */
+ if (__ioremap_at(phys_page, area->addr, size_page,
+ _PAGE_NO_CACHE | _PAGE_GUARDED) == NULL)
+ return -ENOMEM;
+
+ /* Fixup hose IO resource */
+ io_virt_offset = (unsigned long)hose->io_base_virt - _IO_BASE;
+ hose->io_resource.start += io_virt_offset;
+ hose->io_resource.end += io_virt_offset;
- if (!bus) {
- printk(KERN_ERR "%s() expected bus\n", __FUNCTION__);
- return 1;
- }
-
-
- if (get_bus_io_range(bus, &start_phys, &start_virt, &size))
- return 1;
- if (start_phys == 0)
- return 1;
- printk(KERN_DEBUG "mapping IO %lx -> %lx, size: %lx\n", start_phys, start_virt, size);
- if (__ioremap_explicit(start_phys, start_virt, size,
- _PAGE_NO_CACHE | _PAGE_GUARDED))
- return 1;
+ DBG(" hose->io_resource=0x%016lx...0x%016lx\n",
+ hose->io_resource.start, hose->io_resource.end);
return 0;
}
-EXPORT_SYMBOL(remap_bus_range);
-
-static void phbs_remap_io(void)
-{
- struct pci_controller *hose, *tmp;
-
- list_for_each_entry_safe(hose, tmp, &hose_list, list_node)
- remap_bus_range(hose->bus);
-}
+EXPORT_SYMBOL_GPL(pcibios_map_io_space);
static void __devinit fixup_resource(struct resource *res, struct pci_dev *dev)
{
@@ -1201,8 +1085,7 @@ static void __devinit fixup_resource(str
unsigned long offset;
if (res->flags & IORESOURCE_IO) {
- offset = (unsigned long)hose->io_base_virt - pci_io_base;
-
+ offset = (unsigned long)hose->io_base_virt - _IO_BASE;
res->start += offset;
res->end += offset;
} else if (res->flags & IORESOURCE_MEM) {
@@ -1217,9 +1100,20 @@ void __devinit pcibios_fixup_device_reso
/* Update device resources. */
int i;
- for (i = 0; i < PCI_NUM_RESOURCES; i++)
- if (dev->resource[i].flags)
- fixup_resource(&dev->resource[i], dev);
+ DBG("%s: Fixup resources:\n", pci_name(dev));
+ for (i = 0; i < PCI_NUM_RESOURCES; i++) {
+ struct resource *res = &dev->resource[i];
+ if (!res->flags)
+ continue;
+
+ DBG(" 0x%02x < %08lx:0x%016lx...0x%016lx\n",
+ i, res->flags, res->start, res->end);
+
+ fixup_resource(res, dev);
+
+ DBG(" > %08lx:0x%016lx...0x%016lx\n",
+ res->flags, res->start, res->end);
+ }
}
EXPORT_SYMBOL(pcibios_fixup_device_resources);
@@ -1360,7 +1254,7 @@ void pci_resource_to_user(const struct p
return;
if (rsrc->flags & IORESOURCE_IO)
- offset = (unsigned long)hose->io_base_virt - pci_io_base;
+ offset = (unsigned long)hose->io_base_virt - _IO_BASE;
/* We pass a fully fixed up address to userland for MMIO instead of
* a BAR value because X is lame and expects to be able to use that
@@ -1410,7 +1304,7 @@ unsigned long pci_address_to_pio(phys_ad
if (address >= hose->io_base_phys &&
address < (hose->io_base_phys + hose->pci_io_size)) {
unsigned long base =
- (unsigned long)hose->io_base_virt - pci_io_base;
+ (unsigned long)hose->io_base_virt - _IO_BASE;
return base + (address - hose->io_base_phys);
}
}
Index: linux-cell/arch/powerpc/kernel/rtas_pci.c
===================================================================
--- linux-cell.orig/arch/powerpc/kernel/rtas_pci.c 2007-05-24 14:00:31.000000000 +1000
+++ linux-cell/arch/powerpc/kernel/rtas_pci.c 2007-05-24 14:02:09.000000000 +1000
@@ -278,10 +278,8 @@ void __init find_and_init_phbs(void)
{
struct device_node *node;
struct pci_controller *phb;
- unsigned int index;
struct device_node *root = of_find_node_by_path("/");
- index = 0;
for (node = of_get_next_child(root, NULL);
node != NULL;
node = of_get_next_child(root, node)) {
@@ -295,8 +293,7 @@ void __init find_and_init_phbs(void)
continue;
rtas_setup_phb(phb);
pci_process_bridge_OF_ranges(phb, node, 0);
- pci_setup_phb_io(phb, index == 0);
- index++;
+ isa_bridge_find_early(phb);
}
of_node_put(root);
@@ -335,7 +332,7 @@ int pcibios_remove_root_bus(struct pci_c
return 1;
}
- rc = unmap_bus_range(b);
+ rc = pcibios_unmap_io_space(b);
if (rc) {
printk(KERN_ERR "%s: failed to unmap IO on bus %s\n",
__FUNCTION__, b->name);
Index: linux-cell/arch/powerpc/mm/imalloc.c
===================================================================
--- linux-cell.orig/arch/powerpc/mm/imalloc.c 2007-05-24 14:01:31.000000000 +1000
+++ /dev/null 1970-01-01 00:00:00.000000000 +0000
@@ -1,314 +0,0 @@
-/*
- * c 2001 PPC 64 Team, IBM Corp
- *
- * 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 <linux/slab.h>
-#include <linux/vmalloc.h>
-
-#include <asm/uaccess.h>
-#include <asm/pgalloc.h>
-#include <asm/pgtable.h>
-#include <linux/mutex.h>
-#include <asm/cacheflush.h>
-
-#include "mmu_decl.h"
-
-static DEFINE_MUTEX(imlist_mutex);
-struct vm_struct * imlist = NULL;
-
-static int get_free_im_addr(unsigned long size, unsigned long *im_addr)
-{
- unsigned long addr;
- struct vm_struct **p, *tmp;
-
- addr = ioremap_bot;
- for (p = &imlist; (tmp = *p) ; p = &tmp->next) {
- if (size + addr < (unsigned long) tmp->addr)
- break;
- if ((unsigned long)tmp->addr >= ioremap_bot)
- addr = tmp->size + (unsigned long) tmp->addr;
- if (addr >= IMALLOC_END-size)
- return 1;
- }
- *im_addr = addr;
-
- return 0;
-}
-
-/* Return whether the region described by v_addr and size is a subset
- * of the region described by parent
- */
-static inline int im_region_is_subset(unsigned long v_addr, unsigned long size,
- struct vm_struct *parent)
-{
- return (int) (v_addr >= (unsigned long) parent->addr &&
- v_addr < (unsigned long) parent->addr + parent->size &&
- size < parent->size);
-}
-
-/* Return whether the region described by v_addr and size is a superset
- * of the region described by child
- */
-static int im_region_is_superset(unsigned long v_addr, unsigned long size,
- struct vm_struct *child)
-{
- struct vm_struct parent;
-
- parent.addr = (void *) v_addr;
- parent.size = size;
-
- return im_region_is_subset((unsigned long) child->addr, child->size,
- &parent);
-}
-
-/* Return whether the region described by v_addr and size overlaps
- * the region described by vm. Overlapping regions meet the
- * following conditions:
- * 1) The regions share some part of the address space
- * 2) The regions aren't identical
- * 3) Neither region is a subset of the other
- */
-static int im_region_overlaps(unsigned long v_addr, unsigned long size,
- struct vm_struct *vm)
-{
- if (im_region_is_superset(v_addr, size, vm))
- return 0;
-
- return (v_addr + size > (unsigned long) vm->addr + vm->size &&
- v_addr < (unsigned long) vm->addr + vm->size) ||
- (v_addr < (unsigned long) vm->addr &&
- v_addr + size > (unsigned long) vm->addr);
-}
-
-/* Determine imalloc status of region described by v_addr and size.
- * Can return one of the following:
- * IM_REGION_UNUSED - Entire region is unallocated in imalloc space.
- * IM_REGION_SUBSET - Region is a subset of a region that is already
- * allocated in imalloc space.
- * vm will be assigned to a ptr to the parent region.
- * IM_REGION_EXISTS - Exact region already allocated in imalloc space.
- * vm will be assigned to a ptr to the existing imlist
- * member.
- * IM_REGION_OVERLAPS - Region overlaps an allocated region in imalloc space.
- * IM_REGION_SUPERSET - Region is a superset of a region that is already
- * allocated in imalloc space.
- */
-static int im_region_status(unsigned long v_addr, unsigned long size,
- struct vm_struct **vm)
-{
- struct vm_struct *tmp;
-
- for (tmp = imlist; tmp; tmp = tmp->next)
- if (v_addr < (unsigned long) tmp->addr + tmp->size)
- break;
-
- *vm = NULL;
- if (tmp) {
- if (im_region_overlaps(v_addr, size, tmp))
- return IM_REGION_OVERLAP;
-
- *vm = tmp;
- if (im_region_is_subset(v_addr, size, tmp)) {
- /* Return with tmp pointing to superset */
- return IM_REGION_SUBSET;
- }
- if (im_region_is_superset(v_addr, size, tmp)) {
- /* Return with tmp pointing to first subset */
- return IM_REGION_SUPERSET;
- }
- else if (v_addr == (unsigned long) tmp->addr &&
- size == tmp->size) {
- /* Return with tmp pointing to exact region */
- return IM_REGION_EXISTS;
- }
- }
-
- return IM_REGION_UNUSED;
-}
-
-static struct vm_struct * split_im_region(unsigned long v_addr,
- unsigned long size, struct vm_struct *parent)
-{
- struct vm_struct *vm1 = NULL;
- struct vm_struct *vm2 = NULL;
- struct vm_struct *new_vm = NULL;
-
- vm1 = kmalloc(sizeof(*vm1), GFP_KERNEL);
- if (vm1 == NULL) {
- printk(KERN_ERR "%s() out of memory\n", __FUNCTION__);
- return NULL;
- }
-
- if (v_addr == (unsigned long) parent->addr) {
- /* Use existing parent vm_struct to represent child, allocate
- * new one for the remainder of parent range
- */
- vm1->size = parent->size - size;
- vm1->addr = (void *) (v_addr + size);
- vm1->next = parent->next;
-
- parent->size = size;
- parent->next = vm1;
- new_vm = parent;
- } else if (v_addr + size == (unsigned long) parent->addr +
- parent->size) {
- /* Allocate new vm_struct to represent child, use existing
- * parent one for remainder of parent range
- */
- vm1->size = size;
- vm1->addr = (void *) v_addr;
- vm1->next = parent->next;
- new_vm = vm1;
-
- parent->size -= size;
- parent->next = vm1;
- } else {
- /* Allocate two new vm_structs for the new child and
- * uppermost remainder, and use existing parent one for the
- * lower remainder of parent range
- */
- vm2 = kmalloc(sizeof(*vm2), GFP_KERNEL);
- if (vm2 == NULL) {
- printk(KERN_ERR "%s() out of memory\n", __FUNCTION__);
- kfree(vm1);
- return NULL;
- }
-
- vm1->size = size;
- vm1->addr = (void *) v_addr;
- vm1->next = vm2;
- new_vm = vm1;
-
- vm2->size = ((unsigned long) parent->addr + parent->size) -
- (v_addr + size);
- vm2->addr = (void *) v_addr + size;
- vm2->next = parent->next;
-
- parent->size = v_addr - (unsigned long) parent->addr;
- parent->next = vm1;
- }
-
- return new_vm;
-}
-
-static struct vm_struct * __add_new_im_area(unsigned long req_addr,
- unsigned long size)
-{
- struct vm_struct **p, *tmp, *area;
-
- for (p = &imlist; (tmp = *p) ; p = &tmp->next) {
- if (req_addr + size <= (unsigned long)tmp->addr)
- break;
- }
-
- area = kmalloc(sizeof(*area), GFP_KERNEL);
- if (!area)
- return NULL;
- area->flags = 0;
- area->addr = (void *)req_addr;
- area->size = size;
- area->next = *p;
- *p = area;
-
- return area;
-}
-
-static struct vm_struct * __im_get_area(unsigned long req_addr,
- unsigned long size,
- int criteria)
-{
- struct vm_struct *tmp;
- int status;
-
- status = im_region_status(req_addr, size, &tmp);
- if ((criteria & status) == 0) {
- return NULL;
- }
-
- switch (status) {
- case IM_REGION_UNUSED:
- tmp = __add_new_im_area(req_addr, size);
- break;
- case IM_REGION_SUBSET:
- tmp = split_im_region(req_addr, size, tmp);
- break;
- case IM_REGION_EXISTS:
- /* Return requested region */
- break;
- case IM_REGION_SUPERSET:
- /* Return first existing subset of requested region */
- break;
- default:
- printk(KERN_ERR "%s() unexpected imalloc region status\n",
- __FUNCTION__);
- tmp = NULL;
- }
-
- return tmp;
-}
-
-struct vm_struct * im_get_free_area(unsigned long size)
-{
- struct vm_struct *area;
- unsigned long addr;
-
- mutex_lock(&imlist_mutex);
- if (get_free_im_addr(size, &addr)) {
- printk(KERN_ERR "%s() cannot obtain addr for size 0x%lx\n",
- __FUNCTION__, size);
- area = NULL;
- goto next_im_done;
- }
-
- area = __im_get_area(addr, size, IM_REGION_UNUSED);
- if (area == NULL) {
- printk(KERN_ERR
- "%s() cannot obtain area for addr 0x%lx size 0x%lx\n",
- __FUNCTION__, addr, size);
- }
-next_im_done:
- mutex_unlock(&imlist_mutex);
- return area;
-}
-
-struct vm_struct * im_get_area(unsigned long v_addr, unsigned long size,
- int criteria)
-{
- struct vm_struct *area;
-
- mutex_lock(&imlist_mutex);
- area = __im_get_area(v_addr, size, criteria);
- mutex_unlock(&imlist_mutex);
- return area;
-}
-
-void im_free(void * addr)
-{
- struct vm_struct **p, *tmp;
-
- if (!addr)
- return;
- if ((unsigned long) addr & ~PAGE_MASK) {
- printk(KERN_ERR "Trying to %s bad address (%p)\n", __FUNCTION__, addr);
- return;
- }
- mutex_lock(&imlist_mutex);
- for (p = &imlist ; (tmp = *p) ; p = &tmp->next) {
- if (tmp->addr == addr) {
- *p = tmp->next;
- unmap_kernel_range((unsigned long)tmp->addr,
- tmp->size);
- kfree(tmp);
- mutex_unlock(&imlist_mutex);
- return;
- }
- }
- mutex_unlock(&imlist_mutex);
- printk(KERN_ERR "Trying to %s nonexistent area (%p)\n", __FUNCTION__,
- addr);
-}
Index: linux-cell/arch/powerpc/mm/mmu_decl.h
===================================================================
--- linux-cell.orig/arch/powerpc/mm/mmu_decl.h 2007-05-24 14:00:31.000000000 +1000
+++ linux-cell/arch/powerpc/mm/mmu_decl.h 2007-05-24 14:02:09.000000000 +1000
@@ -90,16 +90,4 @@ static inline void flush_HPTE(unsigned c
else
_tlbie(va);
}
-#else /* CONFIG_PPC64 */
-/* imalloc region types */
-#define IM_REGION_UNUSED 0x1
-#define IM_REGION_SUBSET 0x2
-#define IM_REGION_EXISTS 0x4
-#define IM_REGION_OVERLAP 0x8
-#define IM_REGION_SUPERSET 0x10
-
-extern struct vm_struct * im_get_free_area(unsigned long size);
-extern struct vm_struct * im_get_area(unsigned long v_addr, unsigned long size,
- int region_type);
-extern void im_free(void *addr);
#endif
Index: linux-cell/arch/powerpc/mm/pgtable_64.c
===================================================================
--- linux-cell.orig/arch/powerpc/mm/pgtable_64.c 2007-05-24 14:01:31.000000000 +1000
+++ linux-cell/arch/powerpc/mm/pgtable_64.c 2007-05-24 14:02:09.000000000 +1000
@@ -34,41 +34,27 @@
#include <linux/stddef.h>
#include <linux/vmalloc.h>
#include <linux/init.h>
-#include <linux/delay.h>
-#include <linux/bootmem.h>
-#include <linux/highmem.h>
-#include <linux/idr.h>
-#include <linux/nodemask.h>
-#include <linux/module.h>
#include <asm/pgalloc.h>
#include <asm/page.h>
#include <asm/prom.h>
-#include <asm/lmb.h>
-#include <asm/rtas.h>
#include <asm/io.h>
#include <asm/mmu_context.h>
#include <asm/pgtable.h>
#include <asm/mmu.h>
-#include <asm/uaccess.h>
#include <asm/smp.h>
#include <asm/machdep.h>
#include <asm/tlb.h>
-#include <asm/eeh.h>
#include <asm/processor.h>
-#include <asm/mmzone.h>
#include <asm/cputable.h>
#include <asm/sections.h>
#include <asm/system.h>
-#include <asm/iommu.h>
#include <asm/abs_addr.h>
-#include <asm/vdso.h>
#include <asm/firmware.h>
#include "mmu_decl.h"
-unsigned long ioremap_bot = IMALLOC_BASE;
-static unsigned long phbs_io_bot = PHBS_IO_BASE;
+unsigned long ioremap_bot = IOREMAP_BASE;
/*
* map_io_page currently only called by __ioremap
@@ -102,8 +88,8 @@ static int map_io_page(unsigned long ea,
* entry in the hardware page table.
*
*/
- if (htab_bolt_mapping(ea, ea + PAGE_SIZE, pa, flags,
- mmu_io_psize)) {
+ if (htab_bolt_mapping(ea, (unsigned long)ea + PAGE_SIZE,
+ pa, flags, mmu_io_psize)) {
printk(KERN_ERR "Failed to do bolted mapping IO "
"memory at %016lx !\n", pa);
return -ENOMEM;
@@ -113,8 +99,11 @@ static int map_io_page(unsigned long ea,
}
-static void __iomem * __ioremap_com(phys_addr_t addr, unsigned long pa,
- unsigned long ea, unsigned long size,
+/**
+ * __ioremap_at - Low level function to establish the page tables
+ * for an IO mapping
+ */
+void __iomem * __ioremap_at(phys_addr_t pa, void *ea, unsigned long size,
unsigned long flags)
{
unsigned long i;
@@ -122,17 +111,35 @@ static void __iomem * __ioremap_com(phys
if ((flags & _PAGE_PRESENT) == 0)
flags |= pgprot_val(PAGE_KERNEL);
+ WARN_ON(pa & ~PAGE_MASK);
+ WARN_ON(((unsigned long)ea) & ~PAGE_MASK);
+ WARN_ON(size & ~PAGE_MASK);
+
for (i = 0; i < size; i += PAGE_SIZE)
- if (map_io_page(ea+i, pa+i, flags))
+ if (map_io_page((unsigned long)ea+i, pa+i, flags))
return NULL;
- return (void __iomem *) (ea + (addr & ~PAGE_MASK));
+ return (void __iomem *)ea;
+}
+
+/**
+ * __iounmap_from - Low level function to tear down the page tables
+ * for an IO mapping. This is used for mappings that
+ * are manipulated manually, like partial unmapping of
+ * PCI IOs or ISA space.
+ */
+void __iounmap_at(void *ea, unsigned long size)
+{
+ WARN_ON(((unsigned long)ea) & ~PAGE_MASK);
+ WARN_ON(size & ~PAGE_MASK);
+
+ unmap_kernel_range((unsigned long)ea, size);
}
void __iomem * __ioremap(phys_addr_t addr, unsigned long size,
unsigned long flags)
{
- unsigned long pa, ea;
+ phys_addr_t paligned;
void __iomem *ret;
/*
@@ -144,27 +151,30 @@ void __iomem * __ioremap(phys_addr_t add
* IMALLOC_END
*
*/
- pa = addr & PAGE_MASK;
- size = PAGE_ALIGN(addr + size) - pa;
+ paligned = addr & PAGE_MASK;
+ size = PAGE_ALIGN(addr + size) - paligned;
- if ((size == 0) || (pa == 0))
+ if ((size == 0) || (paligned == 0))
return NULL;
if (mem_init_done) {
struct vm_struct *area;
- area = im_get_free_area(size);
+
+ area = __get_vm_area(size, VM_IOREMAP,
+ ioremap_bot, IOREMAP_END);
if (area == NULL)
return NULL;
- ea = (unsigned long)(area->addr);
- ret = __ioremap_com(addr, pa, ea, size, flags);
+ ret = __ioremap_at(paligned, area->addr, size, flags);
if (!ret)
- im_free(area->addr);
+ vunmap(area->addr);
} else {
- ea = ioremap_bot;
- ret = __ioremap_com(addr, pa, ea, size, flags);
+ ret = __ioremap_at(paligned, (void *)ioremap_bot, size, flags);
if (ret)
ioremap_bot += size;
}
+
+ if (ret)
+ ret += addr & ~PAGE_MASK;
return ret;
}
@@ -187,61 +197,9 @@ void __iomem * ioremap_flags(phys_addr_t
}
-#define IS_PAGE_ALIGNED(_val) ((_val) == ((_val) & PAGE_MASK))
-
-int __ioremap_explicit(phys_addr_t pa, unsigned long ea,
- unsigned long size, unsigned long flags)
-{
- struct vm_struct *area;
- void __iomem *ret;
-
- /* For now, require page-aligned values for pa, ea, and size */
- if (!IS_PAGE_ALIGNED(pa) || !IS_PAGE_ALIGNED(ea) ||
- !IS_PAGE_ALIGNED(size)) {
- printk(KERN_ERR "unaligned value in %s\n", __FUNCTION__);
- return 1;
- }
-
- if (!mem_init_done) {
- /* Two things to consider in this case:
- * 1) No records will be kept (imalloc, etc) that the region
- * has been remapped
- * 2) It won't be easy to iounmap() the region later (because
- * of 1)
- */
- ;
- } else {
- area = im_get_area(ea, size,
- IM_REGION_UNUSED|IM_REGION_SUBSET|IM_REGION_EXISTS);
- if (area == NULL) {
- /* Expected when PHB-dlpar is in play */
- return 1;
- }
- if (ea != (unsigned long) area->addr) {
- printk(KERN_ERR "unexpected addr return from "
- "im_get_area\n");
- return 1;
- }
- }
-
- ret = __ioremap_com(pa, pa, ea, size, flags);
- if (ret == NULL) {
- printk(KERN_ERR "ioremap_explicit() allocation failure !\n");
- return 1;
- }
- if (ret != (void *) ea) {
- printk(KERN_ERR "__ioremap_com() returned unexpected addr\n");
- return 1;
- }
-
- return 0;
-}
-
/*
* Unmap an IO region and remove it from imalloc'd list.
* Access to IO memory should be serialized by driver.
- *
- * XXX what about calls before mem_init_done (ie python_countermeasures())
*/
void __iounmap(volatile void __iomem *token)
{
@@ -250,9 +208,14 @@ void __iounmap(volatile void __iomem *to
if (!mem_init_done)
return;
- addr = (void *) ((unsigned long __force) token & PAGE_MASK);
-
- im_free(addr);
+ addr = (void *) ((unsigned long __force)
+ PCI_FIX_ADDR(token) & PAGE_MASK);
+ if ((unsigned long)addr < ioremap_bot) {
+ printk(KERN_WARNING "Attempt to iounmap early bolted mapping"
+ " at 0x%p\n", addr);
+ return;
+ }
+ vunmap(addr);
}
void iounmap(volatile void __iomem *token)
@@ -263,77 +226,8 @@ void iounmap(volatile void __iomem *toke
__iounmap(token);
}
-static int iounmap_subset_regions(unsigned long addr, unsigned long size)
-{
- struct vm_struct *area;
-
- /* Check whether subsets of this region exist */
- area = im_get_area(addr, size, IM_REGION_SUPERSET);
- if (area == NULL)
- return 1;
-
- while (area) {
- iounmap((void __iomem *) area->addr);
- area = im_get_area(addr, size,
- IM_REGION_SUPERSET);
- }
-
- return 0;
-}
-
-int __iounmap_explicit(volatile void __iomem *start, unsigned long size)
-{
- struct vm_struct *area;
- unsigned long addr;
- int rc;
-
- addr = (unsigned long __force) start & PAGE_MASK;
-
- /* Verify that the region either exists or is a subset of an existing
- * region. In the latter case, split the parent region to create
- * the exact region
- */
- area = im_get_area(addr, size,
- IM_REGION_EXISTS | IM_REGION_SUBSET);
- if (area == NULL) {
- /* Determine whether subset regions exist. If so, unmap */
- rc = iounmap_subset_regions(addr, size);
- if (rc) {
- printk(KERN_ERR
- "%s() cannot unmap nonexistent range 0x%lx\n",
- __FUNCTION__, addr);
- return 1;
- }
- } else {
- iounmap((void __iomem *) area->addr);
- }
- /*
- * FIXME! This can't be right:
- iounmap(area->addr);
- * Maybe it should be "iounmap(area);"
- */
- return 0;
-}
-
EXPORT_SYMBOL(ioremap);
EXPORT_SYMBOL(ioremap_flags);
EXPORT_SYMBOL(__ioremap);
EXPORT_SYMBOL(iounmap);
EXPORT_SYMBOL(__iounmap);
-
-static DEFINE_SPINLOCK(phb_io_lock);
-
-void __iomem * reserve_phb_iospace(unsigned long size)
-{
- void __iomem *virt_addr;
-
- if (phbs_io_bot >= IMALLOC_BASE)
- panic("reserve_phb_iospace(): phb io space overflow\n");
-
- spin_lock(&phb_io_lock);
- virt_addr = (void __iomem *) phbs_io_bot;
- phbs_io_bot += size;
- spin_unlock(&phb_io_lock);
-
- return virt_addr;
-}
Index: linux-cell/arch/powerpc/platforms/maple/pci.c
===================================================================
--- linux-cell.orig/arch/powerpc/platforms/maple/pci.c 2007-05-24 14:00:31.000000000 +1000
+++ linux-cell/arch/powerpc/platforms/maple/pci.c 2007-05-24 14:02:09.000000000 +1000
@@ -519,23 +519,6 @@ void __devinit maple_pci_irq_fixup(struc
DBG(" <- maple_pci_irq_fixup\n");
}
-static void __init maple_fixup_phb_resources(void)
-{
- struct pci_controller *hose, *tmp;
-
- list_for_each_entry_safe(hose, tmp, &hose_list, list_node) {
- unsigned long offset = (unsigned long)hose->io_base_virt - pci_io_base;
-
- hose->io_resource.start += offset;
- hose->io_resource.end += offset;
-
- printk(KERN_INFO "PCI Host %d, io start: %llx; io end: %llx\n",
- hose->global_number,
- (unsigned long long)hose->io_resource.start,
- (unsigned long long)hose->io_resource.end);
- }
-}
-
void __init maple_pci_init(void)
{
struct device_node *np, *root;
@@ -573,24 +556,6 @@ void __init maple_pci_init(void)
if (ht && add_bridge(ht) != 0)
of_node_put(ht);
- /*
- * We need to call pci_setup_phb_io for the HT bridge first
- * so it gets the I/O port numbers starting at 0, and we
- * need to call it for the AGP bridge after that so it gets
- * small positive I/O port numbers.
- */
- if (u3_ht)
- pci_setup_phb_io(u3_ht, 1);
- if (u3_agp)
- pci_setup_phb_io(u3_agp, 0);
- if (u4_pcie)
- pci_setup_phb_io(u4_pcie, 0);
-
- /* Fixup the IO resources on our host bridges as the common code
- * does it only for childs of the host bridges
- */
- maple_fixup_phb_resources();
-
/* Setup the linkage between OF nodes and PHBs */
pci_devs_phb_init();
Index: linux-cell/arch/powerpc/platforms/pasemi/pci.c
===================================================================
--- linux-cell.orig/arch/powerpc/platforms/pasemi/pci.c 2007-05-24 14:00:31.000000000 +1000
+++ linux-cell/arch/powerpc/platforms/pasemi/pci.c 2007-05-24 14:02:09.000000000 +1000
@@ -150,29 +150,11 @@ static int __init add_bridge(struct devi
printk(KERN_INFO "Found PA-PXP PCI host bridge.\n");
/* Interpret the "ranges" property */
- /* This also maps the I/O region and sets isa_io/mem_base */
pci_process_bridge_OF_ranges(hose, dev, 1);
- pci_setup_phb_io(hose, 1);
return 0;
}
-
-static void __init pas_fixup_phb_resources(void)
-{
- struct pci_controller *hose, *tmp;
-
- list_for_each_entry_safe(hose, tmp, &hose_list, list_node) {
- unsigned long offset = (unsigned long)hose->io_base_virt - pci_io_base;
- hose->io_resource.start += offset;
- hose->io_resource.end += offset;
- printk(KERN_INFO "PCI Host %d, io start: %lx; io end: %lx\n",
- hose->global_number,
- hose->io_resource.start, hose->io_resource.end);
- }
-}
-
-
void __init pas_pci_init(void)
{
struct device_node *np, *root;
@@ -190,8 +172,6 @@ void __init pas_pci_init(void)
of_node_put(root);
- pas_fixup_phb_resources();
-
/* Setup the linkage between OF nodes and PHBs */
pci_devs_phb_init();
Index: linux-cell/arch/powerpc/platforms/powermac/pci.c
===================================================================
--- linux-cell.orig/arch/powerpc/platforms/powermac/pci.c 2007-05-24 14:00:31.000000000 +1000
+++ linux-cell/arch/powerpc/platforms/powermac/pci.c 2007-05-24 14:02:09.000000000 +1000
@@ -1006,19 +1006,6 @@ void __devinit pmac_pci_irq_fixup(struct
#endif /* CONFIG_PPC32 */
}
-#ifdef CONFIG_PPC64
-static void __init pmac_fixup_phb_resources(void)
-{
- struct pci_controller *hose, *tmp;
-
- list_for_each_entry_safe(hose, tmp, &hose_list, list_node) {
- printk(KERN_INFO "PCI Host %d, io start: %lx; io end: %lx\n",
- hose->global_number,
- hose->io_resource.start, hose->io_resource.end);
- }
-}
-#endif
-
void __init pmac_pci_init(void)
{
struct device_node *np, *root;
@@ -1053,25 +1040,6 @@ void __init pmac_pci_init(void)
if (ht && add_bridge(ht) != 0)
of_node_put(ht);
- /*
- * We need to call pci_setup_phb_io for the HT bridge first
- * so it gets the I/O port numbers starting at 0, and we
- * need to call it for the AGP bridge after that so it gets
- * small positive I/O port numbers.
- */
- if (u3_ht)
- pci_setup_phb_io(u3_ht, 1);
- if (u3_agp)
- pci_setup_phb_io(u3_agp, 0);
- if (u4_pcie)
- pci_setup_phb_io(u4_pcie, 0);
-
- /*
- * On ppc64, fixup the IO resources on our host bridges as
- * the common code does it only for children of the host bridges
- */
- pmac_fixup_phb_resources();
-
/* Setup the linkage between OF nodes and PHBs */
pci_devs_phb_init();
Index: linux-cell/arch/powerpc/platforms/pseries/pci_dlpar.c
===================================================================
--- linux-cell.orig/arch/powerpc/platforms/pseries/pci_dlpar.c 2007-05-24 14:00:31.000000000 +1000
+++ linux-cell/arch/powerpc/platforms/pseries/pci_dlpar.c 2007-05-24 14:02:09.000000000 +1000
@@ -200,8 +200,6 @@ struct pci_controller * __devinit init_p
rtas_setup_phb(phb);
pci_process_bridge_OF_ranges(phb, dn, 0);
- pci_setup_phb_io_dynamic(phb, primary);
-
pci_devs_phb_init_dynamic(phb);
if (dn->child)
Index: linux-cell/drivers/pci/hotplug/rpadlpar_core.c
===================================================================
--- linux-cell.orig/drivers/pci/hotplug/rpadlpar_core.c 2007-05-24 14:00:31.000000000 +1000
+++ linux-cell/drivers/pci/hotplug/rpadlpar_core.c 2007-05-24 14:02:09.000000000 +1000
@@ -159,8 +159,8 @@ static void dlpar_pci_add_bus(struct dev
/* Claim new bus resources */
pcibios_claim_one_bus(dev->bus);
- /* ioremap() for child bus, which may or may not succeed */
- remap_bus_range(dev->subordinate);
+ /* Map IO space for child bus, which may or may not succeed */
+ pcibios_map_io_space(dev->subordinate);
/* Add new devices to global lists. Register in proc, sysfs. */
pci_bus_add_devices(phb->bus);
@@ -390,7 +390,7 @@ int dlpar_remove_pci_slot(char *drc_name
} else
pcibios_remove_pci_devices(bus);
- if (unmap_bus_range(bus)) {
+ if (pcibios_unmap_io_space(bus)) {
printk(KERN_ERR "%s: failed to unmap bus range\n",
__FUNCTION__);
return -ERANGE;
Index: linux-cell/include/asm-powerpc/pci-bridge.h
===================================================================
--- linux-cell.orig/include/asm-powerpc/pci-bridge.h 2007-05-24 14:00:31.000000000 +1000
+++ linux-cell/include/asm-powerpc/pci-bridge.h 2007-05-24 14:02:09.000000000 +1000
@@ -31,6 +31,7 @@ struct pci_controller {
int last_busno;
void __iomem *io_base_virt;
+ void *io_base_alloc;
resource_size_t io_base_phys;
/* Some machines have a non 1:1 mapping of
@@ -164,6 +165,11 @@ static inline unsigned long pci_address_
}
#endif
+extern void isa_bridge_find_early(struct pci_controller *hose);
+
+extern int pcibios_unmap_io_space(struct pci_bus *bus);
+extern int pcibios_map_io_space(struct pci_bus *bus);
+
/* Return values for ppc_md.pci_probe_mode function */
#define PCI_PROBE_NONE -1 /* Don't look at this bus at all */
#define PCI_PROBE_NORMAL 0 /* Do normal PCI probing */
Index: linux-cell/include/asm-powerpc/pci.h
===================================================================
--- linux-cell.orig/include/asm-powerpc/pci.h 2007-05-24 14:00:31.000000000 +1000
+++ linux-cell/include/asm-powerpc/pci.h 2007-05-24 14:02:09.000000000 +1000
@@ -220,10 +220,6 @@ static inline struct resource *pcibios_s
return root;
}
-extern int unmap_bus_range(struct pci_bus *bus);
-
-extern int remap_bus_range(struct pci_bus *bus);
-
extern void pcibios_fixup_device_resources(struct pci_dev *dev,
struct pci_bus *bus);
Index: linux-cell/include/asm-powerpc/io.h
===================================================================
--- linux-cell.orig/include/asm-powerpc/io.h 2007-05-24 14:00:31.000000000 +1000
+++ linux-cell/include/asm-powerpc/io.h 2007-05-24 14:02:09.000000000 +1000
@@ -607,9 +607,9 @@ static inline void iosync(void)
*
* * iounmap undoes such a mapping and can be hooked
*
- * * __ioremap_explicit (and the pending __iounmap_explicit) are low level
- * functions to create hand-made mappings for use only by the PCI code
- * and cannot currently be hooked.
+ * * __ioremap_at (and the pending __iounmap_at) are low level functions to
+ * create hand-made mappings for use only by the PCI code and cannot
+ * currently be hooked. Must be page aligned.
*
* * __ioremap is the low level implementation used by ioremap and
* ioremap_flags and cannot be hooked (but can be used by a hook on one
@@ -629,12 +629,9 @@ extern void __iomem *__ioremap(phys_addr
unsigned long flags);
extern void __iounmap(volatile void __iomem *addr);
-extern int __ioremap_explicit(phys_addr_t p_addr, unsigned long v_addr,
- unsigned long size, unsigned long flags);
-extern int __iounmap_explicit(volatile void __iomem *start,
- unsigned long size);
-
-extern void __iomem * reserve_phb_iospace(unsigned long size);
+extern void __iomem * __ioremap_at(phys_addr_t pa, void *ea,
+ unsigned long size, unsigned long flags);
+extern void __iounmap_at(void *ea, unsigned long size);
/* Those are more 32 bits only functions */
extern unsigned long iopa(unsigned long addr);
@@ -651,8 +648,8 @@ extern void io_block_mapping(unsigned lo
*/
#define HAVE_ARCH_PIO_SIZE 1
#define PIO_OFFSET 0x00000000UL
-#define PIO_MASK 0x3fffffffUL
-#define PIO_RESERVED 0x40000000UL
+#define PIO_MASK (FULL_IO_SIZE - 1)
+#define PIO_RESERVED (FULL_IO_SIZE)
#define mmio_read16be(addr) readw_be(addr)
#define mmio_read32be(addr) readl_be(addr)
Index: linux-cell/arch/powerpc/mm/Makefile
===================================================================
--- linux-cell.orig/arch/powerpc/mm/Makefile 2007-05-24 14:00:31.000000000 +1000
+++ linux-cell/arch/powerpc/mm/Makefile 2007-05-24 14:02:09.000000000 +1000
@@ -11,8 +11,7 @@ obj-$(CONFIG_PPC32) += init_32.o pgtabl
hash-$(CONFIG_PPC_NATIVE) := hash_native_64.o
obj-$(CONFIG_PPC64) += init_64.o pgtable_64.o mmu_context_64.o \
hash_utils_64.o hash_low_64.o tlb_64.o \
- slb_low.o slb.o stab.o mmap.o imalloc.o \
- $(hash-y)
+ slb_low.o slb.o stab.o mmap.o $(hash-y)
obj-$(CONFIG_PPC_STD_MMU_32) += ppc_mmu_32.o hash_low_32.o tlb_32.o
obj-$(CONFIG_40x) += 4xx_mmu.o
obj-$(CONFIG_44x) += 44x_mmu.o
Index: linux-cell/arch/powerpc/platforms/cell/io-workarounds.c
===================================================================
--- linux-cell.orig/arch/powerpc/platforms/cell/io-workarounds.c 2007-05-24 14:00:31.000000000 +1000
+++ linux-cell/arch/powerpc/platforms/cell/io-workarounds.c 2007-05-24 14:02:09.000000000 +1000
@@ -102,7 +102,7 @@ static void spider_io_flush(const volati
vaddr = (unsigned long)PCI_FIX_ADDR(addr);
/* Check if it's in allowed range for PIO */
- if (vaddr < PHBS_IO_BASE || vaddr >= IMALLOC_BASE)
+ if (vaddr < PHB_IO_BASE || vaddr > PHB_IO_END)
return;
/* Try to find a PTE. If not, clear the paddr, we'll do
Index: linux-cell/include/asm-powerpc/floppy.h
===================================================================
--- linux-cell.orig/include/asm-powerpc/floppy.h 2007-05-24 14:00:31.000000000 +1000
+++ linux-cell/include/asm-powerpc/floppy.h 2007-05-24 14:02:09.000000000 +1000
@@ -29,7 +29,7 @@
#define fd_free_irq() free_irq(FLOPPY_IRQ, NULL);
#include <linux/pci.h>
-#include <asm/ppc-pci.h> /* for ppc64_isabridge_dev */
+#include <asm/ppc-pci.h> /* for isa_bridge_pcidev */
#define fd_dma_setup(addr,size,mode,io) fd_ops->_dma_setup(addr,size,mode,io)
@@ -139,12 +139,12 @@ static int hard_dma_setup(char *addr, un
if (bus_addr
&& (addr != prev_addr || size != prev_size || dir != prev_dir)) {
/* different from last time -- unmap prev */
- pci_unmap_single(ppc64_isabridge_dev, bus_addr, prev_size, prev_dir);
+ pci_unmap_single(isa_bridge_pcidev, bus_addr, prev_size, prev_dir);
bus_addr = 0;
}
if (!bus_addr) /* need to map it */
- bus_addr = pci_map_single(ppc64_isabridge_dev, addr, size, dir);
+ bus_addr = pci_map_single(isa_bridge_pcidev, addr, size, dir);
/* remember this one as prev */
prev_addr = addr;
Index: linux-cell/include/asm-powerpc/ppc-pci.h
===================================================================
--- linux-cell.orig/include/asm-powerpc/ppc-pci.h 2007-05-24 14:00:31.000000000 +1000
+++ linux-cell/include/asm-powerpc/ppc-pci.h 2007-05-24 14:02:09.000000000 +1000
@@ -26,7 +26,7 @@ extern int global_phb_number;
extern void find_and_init_phbs(void);
-extern struct pci_dev *ppc64_isabridge_dev; /* may be NULL if no ISA bus */
+extern struct pci_dev *isa_bridge_pcidev; /* may be NULL if no ISA bus */
/** Bus Unit ID macros; get low and hi 32-bits of the 64-bit BUID */
#define BUID_HI(buid) ((buid) >> 32)
@@ -47,8 +47,8 @@ extern void init_pci_config_tokens (void
extern unsigned long get_phb_buid (struct device_node *);
extern int rtas_setup_phb(struct pci_controller *phb);
-/* From pSeries_pci.h */
-extern void pSeries_final_fixup(void);
+/* From iSeries PCI */
+extern void iSeries_pcibios_init(void);
extern unsigned long pci_probe_only;
Index: linux-cell/arch/powerpc/mm/tlb_64.c
===================================================================
--- linux-cell.orig/arch/powerpc/mm/tlb_64.c 2007-05-24 14:00:31.000000000 +1000
+++ linux-cell/arch/powerpc/mm/tlb_64.c 2007-05-24 14:02:09.000000000 +1000
@@ -239,3 +239,59 @@ void pte_free_finish(void)
pte_free_submit(*batchp);
*batchp = NULL;
}
+
+/**
+ * __flush_hash_table_range - Flush all HPTEs for a given address range
+ * from the hash table (and the TLB). But keeps
+ * the linux PTEs intact.
+ *
+ * @mm : mm_struct of the target address space (generally init_mm)
+ * @start : starting address
+ * @end : ending address (not included in the flush)
+ *
+ * This function is mostly to be used by some IO hotplug code in order
+ * to remove all hash entries from a given address range used to map IO
+ * space on a removed PCI-PCI bidge without tearing down the full mapping
+ * since 64K pages may overlap with other bridges when using 64K pages
+ * with 4K HW pages on IO space.
+ *
+ * Because of that usage pattern, it's only available with CONFIG_HOTPLUG
+ * and is implemented for small size rather than speed.
+ */
+#ifdef CONFIG_HOTPLUG
+
+void __flush_hash_table_range(struct mm_struct *mm, unsigned long start,
+ unsigned long end)
+{
+ unsigned long flags;
+
+ start = _ALIGN_DOWN(start, PAGE_SIZE);
+ end = _ALIGN_UP(end, PAGE_SIZE);
+
+ BUG_ON(!mm->pgd);
+
+ /* Note: Normally, we should only ever use a batch within a
+ * PTE locked section. This violates the rule, but will work
+ * since we don't actually modify the PTEs, we just flush the
+ * hash while leaving the PTEs intact (including their reference
+ * to being hashed). This is not the most performance oriented
+ * way to do things but is fine for our needs here.
+ */
+ local_irq_save(flags);
+ arch_enter_lazy_mmu_mode();
+ for(;start < end; start += PAGE_SIZE) {
+ pte_t *ptep = find_linux_pte(mm->pgd, start);
+ unsigned long pte;
+
+ if (ptep == NULL)
+ continue;
+ pte = pte_val(*ptep);
+ if (!(pte & _PAGE_HASHPTE))
+ continue;
+ hpte_need_flush(mm, start, ptep, pte, 0);
+ }
+ arch_leave_lazy_mmu_mode();
+ local_irq_restore(flags);
+}
+
+#endif /* CONFIG_HOTPLUG */
Index: linux-cell/include/asm-powerpc/tlbflush.h
===================================================================
--- linux-cell.orig/include/asm-powerpc/tlbflush.h 2007-05-24 14:00:31.000000000 +1000
+++ linux-cell/include/asm-powerpc/tlbflush.h 2007-05-24 14:02:09.000000000 +1000
@@ -155,6 +155,11 @@ static inline void flush_tlb_kernel_rang
{
}
+/* Private function for use by PCI IO mapping code */
+extern void __flush_hash_table_range(struct mm_struct *mm, unsigned long start,
+ unsigned long end);
+
+
#endif
/*
Index: linux-cell/arch/powerpc/platforms/iseries/pci.c
===================================================================
--- linux-cell.orig/arch/powerpc/platforms/iseries/pci.c 2007-05-24 14:00:31.000000000 +1000
+++ linux-cell/arch/powerpc/platforms/iseries/pci.c 2007-05-24 14:02:09.000000000 +1000
@@ -742,6 +742,11 @@ void __init iSeries_pcibios_init(void)
/* Install IO hooks */
ppc_pci_io = iseries_pci_io;
+ /* iSeries has no IO space in the common sense, it needs to set
+ * the IO base to 0
+ */
+ pci_io_base = 0;
+
if (root == NULL) {
printk(KERN_CRIT "iSeries_pcibios_init: can't find root "
"of device tree\n");
Index: linux-cell/arch/powerpc/platforms/pseries/pseries.h
===================================================================
--- linux-cell.orig/arch/powerpc/platforms/pseries/pseries.h 2007-05-24 14:00:31.000000000 +1000
+++ linux-cell/arch/powerpc/platforms/pseries/pseries.h 2007-05-24 14:02:09.000000000 +1000
@@ -33,6 +33,8 @@ static inline void setup_kexec_cpu_down_
static inline void setup_kexec_cpu_down_mpic(void) { }
#endif
+extern void pSeries_final_fixup(void);
+
/* Poweron flag used for enabling auto ups restart */
extern unsigned long rtas_poweron_auto;
^ permalink raw reply [flat|nested] 30+ messages in thread
* [PATCH 3/21] spufs: Add support for SPU single stepping
2007-06-04 5:15 [PATCH 0/21] This is my pending series for 2.6.23 Benjamin Herrenschmidt
2007-06-04 5:15 ` [PATCH 1/21] unmap_vm_area becomes unmap_kernel_range for the public Benjamin Herrenschmidt
2007-06-04 5:15 ` [PATCH 2/21] powerpc: Rewrite IO allocation & mapping on powerpc64 Benjamin Herrenschmidt
@ 2007-06-04 5:15 ` Benjamin Herrenschmidt
2007-06-04 13:06 ` Jeremy Kerr
2007-06-04 5:15 ` [PATCH 4/21] spufs: Add a "capabilities" file to spu contexts Benjamin Herrenschmidt
` (18 subsequent siblings)
21 siblings, 1 reply; 30+ messages in thread
From: Benjamin Herrenschmidt @ 2007-06-04 5:15 UTC (permalink / raw)
To: linuxppc-dev; +Cc: Paul Mackerras, Christoph Hellwig, cbe-oss-dev
This patch adds support for SPU single stepping. The single
step bit is set in the SPU when the current process is
being single-stepped via ptrace. The spu then stops and
returns with a specific flag set and the syscall exit code
will generate the SIGTRAP.
Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
---
arch/powerpc/platforms/cell/spufs/run.c | 12 +++++++++++-
1 file changed, 11 insertions(+), 1 deletion(-)
Index: linux-cell/arch/powerpc/platforms/cell/spufs/run.c
===================================================================
--- linux-cell.orig/arch/powerpc/platforms/cell/spufs/run.c 2007-05-25 13:00:31.000000000 +1000
+++ linux-cell/arch/powerpc/platforms/cell/spufs/run.c 2007-05-25 13:14:54.000000000 +1000
@@ -142,8 +142,12 @@ static int spu_run_init(struct spu_conte
runcntl = SPU_RUNCNTL_RUNNABLE;
ctx->ops->runcntl_write(ctx, runcntl);
} else {
+ unsigned long mode = SPU_PRIVCNTL_MODE_NORMAL;
spu_start_tick(ctx);
ctx->ops->npc_write(ctx, *npc);
+ if (test_thread_flag(TIF_SINGLESTEP))
+ mode = SPU_PRIVCNTL_MODE_SINGLE_STEP;
+ out_be64(&ctx->spu->priv2->spu_privcntl_RW, mode);
ctx->ops->runcntl_write(ctx, SPU_RUNCNTL_RUNNABLE);
}
@@ -334,7 +338,8 @@ long spufs_run_spu(struct file *file, st
ret = spu_process_events(ctx);
} while (!ret && !(status & (SPU_STATUS_STOPPED_BY_STOP |
- SPU_STATUS_STOPPED_BY_HALT)));
+ SPU_STATUS_STOPPED_BY_HALT |
+ SPU_STATUS_SINGLE_STEP)));
ctx->ops->master_stop(ctx);
ret = spu_run_fini(ctx, npc, &status);
@@ -344,10 +349,15 @@ out2:
if ((ret == 0) ||
((ret == -ERESTARTSYS) &&
((status & SPU_STATUS_STOPPED_BY_HALT) ||
+ (status & SPU_STATUS_SINGLE_STEP) ||
((status & SPU_STATUS_STOPPED_BY_STOP) &&
(status >> SPU_STOP_STATUS_SHIFT != 0x2104)))))
ret = status;
+ /* Note: we don't need to force_sig SIGTRAP on single-step
+ * since we have TIF_SINGLESTEP set, thus the kernel will do
+ * it upon return from the syscall anyawy
+ */
if ((status & SPU_STATUS_STOPPED_BY_STOP)
&& (status >> SPU_STOP_STATUS_SHIFT) == 0x3fff) {
force_sig(SIGTRAP, current);
^ permalink raw reply [flat|nested] 30+ messages in thread
* [PATCH 4/21] spufs: Add a "capabilities" file to spu contexts
2007-06-04 5:15 [PATCH 0/21] This is my pending series for 2.6.23 Benjamin Herrenschmidt
` (2 preceding siblings ...)
2007-06-04 5:15 ` [PATCH 3/21] spufs: Add support for SPU single stepping Benjamin Herrenschmidt
@ 2007-06-04 5:15 ` Benjamin Herrenschmidt
2007-06-04 13:06 ` Jeremy Kerr
2007-06-04 5:15 ` [PATCH 5/21] powerpc: Disable broken PPC_PTRACE_GETFPREGS on 32 bits Benjamin Herrenschmidt
` (17 subsequent siblings)
21 siblings, 1 reply; 30+ messages in thread
From: Benjamin Herrenschmidt @ 2007-06-04 5:15 UTC (permalink / raw)
To: linuxppc-dev; +Cc: Paul Mackerras, Christoph Hellwig, cbe-oss-dev
This adds a "capabilities" file to spu contexts consisting of a
list of linefeed separated capability names. The current exposed
capabilities are "sched" (the context is scheduleable) and
"step" (the context supports single stepping).
Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
---
This version of that patch includes Christoph Hellwig change to
use seq_file instead of hand-coded macro crap
arch/powerpc/platforms/cell/spufs/file.c | 27 +++++++++++++++++++++++++++
1 file changed, 27 insertions(+)
Index: linux-cell/arch/powerpc/platforms/cell/spufs/file.c
===================================================================
--- linux-cell.orig/arch/powerpc/platforms/cell/spufs/file.c 2007-06-04 13:20:44.000000000 +1000
+++ linux-cell/arch/powerpc/platforms/cell/spufs/file.c 2007-06-04 14:34:50.000000000 +1000
@@ -28,6 +28,7 @@
#include <linux/pagemap.h>
#include <linux/poll.h>
#include <linux/ptrace.h>
+#include <linux/seq_file.h>
#include <asm/io.h>
#include <asm/semaphore.h>
@@ -39,6 +40,7 @@
#define SPUFS_MMAP_4K (PAGE_SIZE == 0x1000)
+
static int
spufs_mem_open(struct inode *inode, struct file *file)
{
@@ -1796,6 +1798,29 @@ static int spufs_info_open(struct inode
return 0;
}
+static int spufs_caps_show(struct seq_file *s, void *private)
+{
+ struct spu_context *ctx = s->private;
+
+ if (!(ctx->flags & SPU_CREATE_NOSCHED))
+ seq_puts(s, "sched\n");
+ if (!(ctx->flags & SPU_CREATE_ISOLATE))
+ seq_puts(s, "step\n");
+ return 0;
+}
+
+static int spufs_caps_open(struct inode *inode, struct file *file)
+{
+ return single_open(file, spufs_caps_show, SPUFS_I(inode)->i_ctx);
+}
+
+static const struct file_operations spufs_caps_fops = {
+ .open = spufs_caps_open,
+ .read = seq_read,
+ .llseek = seq_lseek,
+ .release = single_release,
+};
+
static ssize_t __spufs_mbox_info_read(struct spu_context *ctx,
char __user *buf, size_t len, loff_t *pos)
{
@@ -2014,6 +2039,7 @@ static const struct file_operations spuf
};
struct tree_descr spufs_dir_contents[] = {
+ { "capabilities", &spufs_caps_fops, 0444, },
{ "mem", &spufs_mem_fops, 0666, },
{ "regs", &spufs_regs_fops, 0666, },
{ "mbox", &spufs_mbox_fops, 0444, },
@@ -2049,6 +2075,7 @@ struct tree_descr spufs_dir_contents[] =
};
struct tree_descr spufs_dir_nosched_contents[] = {
+ { "capabilities", &spufs_caps_fops, 0444, },
{ "mem", &spufs_mem_fops, 0666, },
{ "mbox", &spufs_mbox_fops, 0444, },
{ "ibox", &spufs_ibox_fops, 0444, },
^ permalink raw reply [flat|nested] 30+ messages in thread
* [PATCH 5/21] powerpc: Disable broken PPC_PTRACE_GETFPREGS on 32 bits
2007-06-04 5:15 [PATCH 0/21] This is my pending series for 2.6.23 Benjamin Herrenschmidt
` (3 preceding siblings ...)
2007-06-04 5:15 ` [PATCH 4/21] spufs: Add a "capabilities" file to spu contexts Benjamin Herrenschmidt
@ 2007-06-04 5:15 ` Benjamin Herrenschmidt
2007-06-04 5:15 ` [PATCH 6/21] powerpc: ptrace cleanups Benjamin Herrenschmidt
` (16 subsequent siblings)
21 siblings, 0 replies; 30+ messages in thread
From: Benjamin Herrenschmidt @ 2007-06-04 5:15 UTC (permalink / raw)
To: linuxppc-dev; +Cc: Paul Mackerras, Christoph Hellwig, cbe-oss-dev
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 [flat|nested] 30+ messages in thread
* [PATCH 6/21] powerpc: ptrace cleanups
2007-06-04 5:15 [PATCH 0/21] This is my pending series for 2.6.23 Benjamin Herrenschmidt
` (4 preceding siblings ...)
2007-06-04 5:15 ` [PATCH 5/21] powerpc: Disable broken PPC_PTRACE_GETFPREGS on 32 bits Benjamin Herrenschmidt
@ 2007-06-04 5:15 ` Benjamin Herrenschmidt
2007-06-04 5:15 ` [PATCH 7/21] powerpc: ptrace updates & new better requests Benjamin Herrenschmidt
` (15 subsequent siblings)
21 siblings, 0 replies; 30+ messages in thread
From: Benjamin Herrenschmidt @ 2007-06-04 5:15 UTC (permalink / raw)
To: linuxppc-dev; +Cc: Paul Mackerras, Christoph Hellwig, cbe-oss-dev
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 [flat|nested] 30+ messages in thread
* [PATCH 7/21] powerpc: ptrace updates & new better requests
2007-06-04 5:15 [PATCH 0/21] This is my pending series for 2.6.23 Benjamin Herrenschmidt
` (5 preceding siblings ...)
2007-06-04 5:15 ` [PATCH 6/21] powerpc: ptrace cleanups Benjamin Herrenschmidt
@ 2007-06-04 5:15 ` Benjamin Herrenschmidt
2007-06-04 5:15 ` [PATCH 8/21] powerpc: uninline common ptrace bits Benjamin Herrenschmidt
` (14 subsequent siblings)
21 siblings, 0 replies; 30+ messages in thread
From: Benjamin Herrenschmidt @ 2007-06-04 5:15 UTC (permalink / raw)
To: linuxppc-dev; +Cc: Paul Mackerras, Christoph Hellwig, cbe-oss-dev
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 [flat|nested] 30+ messages in thread
* [PATCH 8/21] powerpc: uninline common ptrace bits
2007-06-04 5:15 [PATCH 0/21] This is my pending series for 2.6.23 Benjamin Herrenschmidt
` (6 preceding siblings ...)
2007-06-04 5:15 ` [PATCH 7/21] powerpc: ptrace updates & new better requests Benjamin Herrenschmidt
@ 2007-06-04 5:15 ` Benjamin Herrenschmidt
2007-06-04 5:15 ` [PATCH 9/21] powerpc: remove some useless ifdef's in ptrace Benjamin Herrenschmidt
` (13 subsequent siblings)
21 siblings, 0 replies; 30+ messages in thread
From: Benjamin Herrenschmidt @ 2007-06-04 5:15 UTC (permalink / raw)
To: linuxppc-dev; +Cc: Paul Mackerras, Christoph Hellwig, cbe-oss-dev
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 [flat|nested] 30+ messages in thread
* [PATCH 9/21] powerpc: remove some useless ifdef's in ptrace
2007-06-04 5:15 [PATCH 0/21] This is my pending series for 2.6.23 Benjamin Herrenschmidt
` (7 preceding siblings ...)
2007-06-04 5:15 ` [PATCH 8/21] powerpc: uninline common ptrace bits Benjamin Herrenschmidt
@ 2007-06-04 5:15 ` Benjamin Herrenschmidt
2007-06-04 5:15 ` [PATCH 10/21] powerpc: Allow ptrace write to pt_regs trap and orig_r3 Benjamin Herrenschmidt
` (12 subsequent siblings)
21 siblings, 0 replies; 30+ messages in thread
From: Benjamin Herrenschmidt @ 2007-06-04 5:15 UTC (permalink / raw)
To: linuxppc-dev; +Cc: Paul Mackerras, Christoph Hellwig, cbe-oss-dev
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 [flat|nested] 30+ messages in thread
* [PATCH 10/21] powerpc: Allow ptrace write to pt_regs trap and orig_r3
2007-06-04 5:15 [PATCH 0/21] This is my pending series for 2.6.23 Benjamin Herrenschmidt
` (8 preceding siblings ...)
2007-06-04 5:15 ` [PATCH 9/21] powerpc: remove some useless ifdef's in ptrace Benjamin Herrenschmidt
@ 2007-06-04 5:15 ` Benjamin Herrenschmidt
2007-06-04 5:15 ` [PATCH 11/21] powerpc: ptrace shouldn't touch FP exec mode Benjamin Herrenschmidt
` (11 subsequent siblings)
21 siblings, 0 replies; 30+ messages in thread
From: Benjamin Herrenschmidt @ 2007-06-04 5:15 UTC (permalink / raw)
To: linuxppc-dev; +Cc: Paul Mackerras, Christoph Hellwig, cbe-oss-dev
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 | 27 ++++++++++++++-------------
2 files changed, 20 insertions(+), 16 deletions(-)
Index: linux-cell/arch/powerpc/kernel/ptrace.c
===================================================================
--- linux-cell.orig/arch/powerpc/kernel/ptrace.c 2007-06-04 14:42:13.000000000 +1000
+++ linux-cell/arch/powerpc/kernel/ptrace.c 2007-06-04 14:42:26.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-06-04 14:42:13.000000000 +1000
+++ linux-cell/arch/powerpc/kernel/ptrace32.c 2007-06-04 14:43:22.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 {
@@ -302,24 +302,25 @@ long compat_sys_ptrace(int request, int
/* 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 [flat|nested] 30+ messages in thread
* [PATCH 11/21] powerpc: ptrace shouldn't touch FP exec mode
2007-06-04 5:15 [PATCH 0/21] This is my pending series for 2.6.23 Benjamin Herrenschmidt
` (9 preceding siblings ...)
2007-06-04 5:15 ` [PATCH 10/21] powerpc: Allow ptrace write to pt_regs trap and orig_r3 Benjamin Herrenschmidt
@ 2007-06-04 5:15 ` Benjamin Herrenschmidt
2007-06-04 5:15 ` [PATCH 12/21] powerpc: ptrace can set DABR on both 32 and 64 bits Benjamin Herrenschmidt
` (10 subsequent siblings)
21 siblings, 0 replies; 30+ messages in thread
From: Benjamin Herrenschmidt @ 2007-06-04 5:15 UTC (permalink / raw)
To: linuxppc-dev; +Cc: Paul Mackerras, Christoph Hellwig, cbe-oss-dev
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 [flat|nested] 30+ messages in thread
* [PATCH 12/21] powerpc: ptrace can set DABR on both 32 and 64 bits
2007-06-04 5:15 [PATCH 0/21] This is my pending series for 2.6.23 Benjamin Herrenschmidt
` (10 preceding siblings ...)
2007-06-04 5:15 ` [PATCH 11/21] powerpc: ptrace shouldn't touch FP exec mode Benjamin Herrenschmidt
@ 2007-06-04 5:15 ` Benjamin Herrenschmidt
2007-06-04 5:15 ` [PATCH 13/21] powerpc: Always apply DABR changes on context switches Benjamin Herrenschmidt
` (9 subsequent siblings)
21 siblings, 0 replies; 30+ messages in thread
From: Benjamin Herrenschmidt @ 2007-06-04 5:15 UTC (permalink / raw)
To: linuxppc-dev; +Cc: Paul Mackerras, Christoph Hellwig, cbe-oss-dev
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 [flat|nested] 30+ messages in thread
* [PATCH 13/21] powerpc: Always apply DABR changes on context switches
2007-06-04 5:15 [PATCH 0/21] This is my pending series for 2.6.23 Benjamin Herrenschmidt
` (11 preceding siblings ...)
2007-06-04 5:15 ` [PATCH 12/21] powerpc: ptrace can set DABR on both 32 and 64 bits Benjamin Herrenschmidt
@ 2007-06-04 5:15 ` Benjamin Herrenschmidt
2007-06-04 5:15 ` [PATCH 14/21] powerpc: Make syscall restart code more common Benjamin Herrenschmidt
` (8 subsequent siblings)
21 siblings, 0 replies; 30+ messages in thread
From: Benjamin Herrenschmidt @ 2007-06-04 5:15 UTC (permalink / raw)
To: linuxppc-dev; +Cc: Paul Mackerras, Christoph Hellwig, cbe-oss-dev
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 [flat|nested] 30+ messages in thread
* [PATCH 14/21] powerpc: Make syscall restart code more common
2007-06-04 5:15 [PATCH 0/21] This is my pending series for 2.6.23 Benjamin Herrenschmidt
` (12 preceding siblings ...)
2007-06-04 5:15 ` [PATCH 13/21] powerpc: Always apply DABR changes on context switches Benjamin Herrenschmidt
@ 2007-06-04 5:15 ` Benjamin Herrenschmidt
2007-06-04 7:06 ` Christoph Hellwig
2007-06-04 5:15 ` [PATCH 15/21] powerpc: consolidate sys_sigaltstack Benjamin Herrenschmidt
` (7 subsequent siblings)
21 siblings, 1 reply; 30+ messages in thread
From: Benjamin Herrenschmidt @ 2007-06-04 5:15 UTC (permalink / raw)
To: linuxppc-dev; +Cc: Paul Mackerras, Christoph Hellwig, cbe-oss-dev
This patch moves the code in signal_32.c and signal_64.c for handling
syscall restart into a common signal.c 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.
Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
---
This is basically my initial patch as modified by Christoph Hellwig
(hch, care to send a SOB ? :-)
arch/powerpc/kernel/Makefile | 3 +
arch/powerpc/kernel/signal.c | 64 ++++++++++++++++++++++++++++++++++++++++
arch/powerpc/kernel/signal.h | 16 ++++++++++
arch/powerpc/kernel/signal_32.c | 28 ++---------------
arch/powerpc/kernel/signal_64.c | 59 ++++--------------------------------
5 files changed, 93 insertions(+), 77 deletions(-)
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-06-04 11:45:43.000000000 +1000
@@ -51,6 +51,8 @@
#include <asm/pgtable.h>
#endif
+#include "signal.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-06-04 11:45:43.000000000 +1000
@@ -34,6 +34,8 @@
#include <asm/syscalls.h>
#include <asm/vdso.h>
+#include "signal.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);
Index: linux-cell/arch/powerpc/kernel/Makefile
===================================================================
--- linux-cell.orig/arch/powerpc/kernel/Makefile 2007-06-04 11:16:01.000000000 +1000
+++ linux-cell/arch/powerpc/kernel/Makefile 2007-06-04 11:16:16.000000000 +1000
@@ -12,7 +12,8 @@ endif
obj-y := semaphore.o cputable.o ptrace.o syscalls.o \
irq.o align.o signal_32.o pmc.o vdso.o \
- init_task.o process.o systbl.o idle.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 \
signal_64.o ptrace32.o \
Index: linux-cell/arch/powerpc/kernel/signal.c
===================================================================
--- /dev/null 1970-01-01 00:00:00.000000000 +0000
+++ linux-cell/arch/powerpc/kernel/signal.c 2007-06-04 11:45:50.000000000 +1000
@@ -0,0 +1,64 @@
+/*
+ * Common signal handling code for both 32 and 64 bits
+ *
+ * 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.
+ */
+
+#include <linux/ptrace.h>
+#include <linux/signal.h>
+
+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;
+ }
+}
Index: linux-cell/arch/powerpc/kernel/signal.h
===================================================================
--- /dev/null 1970-01-01 00:00:00.000000000 +0000
+++ linux-cell/arch/powerpc/kernel/signal.h 2007-06-04 11:45:41.000000000 +1000
@@ -0,0 +1,16 @@
+/*
+ * 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_ARCH_SIGNAL_H
+#define _POWERPC_ARCH_SIGNAL_H
+
+extern void check_syscall_restart(struct pt_regs *regs, struct k_sigaction *ka,
+ int has_handler);
+
+#endif /* _POWERPC_ARCH_SIGNAL_H */
^ permalink raw reply [flat|nested] 30+ messages in thread
* [PATCH 15/21] powerpc: consolidate sys_sigaltstack
2007-06-04 5:15 [PATCH 0/21] This is my pending series for 2.6.23 Benjamin Herrenschmidt
` (13 preceding siblings ...)
2007-06-04 5:15 ` [PATCH 14/21] powerpc: Make syscall restart code more common Benjamin Herrenschmidt
@ 2007-06-04 5:15 ` Benjamin Herrenschmidt
2007-06-04 5:15 ` [PATCH 16/21] powerpc: consolidate restore_sigmask Benjamin Herrenschmidt
` (6 subsequent siblings)
21 siblings, 0 replies; 30+ messages in thread
From: Benjamin Herrenschmidt @ 2007-06-04 5:15 UTC (permalink / raw)
To: linuxppc-dev; +Cc: Paul Mackerras, Christoph Hellwig, cbe-oss-dev
From: Christoph Hellwig <hch@lst.de>
sys_sigaltstack is the same on 32bit and 64 and we can consolidate it
to signal.c. The only difference is that the 32bit code uses ints
for the unused register paramaters and 64bit unsigned long. I've
changed it to unsigned long because it's the same width on 32bit.
(I also wonder who came up with this awkward calling convention.. :))
Signed-off-by: Christoph Hellwig <hch@lst.de>
Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
---
arch/powerpc/kernel/signal.c | 7 +++++++
arch/powerpc/kernel/signal_32.c | 8 --------
arch/powerpc/kernel/signal_64.c | 8 --------
include/asm-powerpc/syscalls.h | 7 -------
4 files changed, 7 insertions(+), 23 deletions(-)
Index: linux-cell/arch/powerpc/kernel/signal_32.c
===================================================================
--- linux-cell.orig/arch/powerpc/kernel/signal_32.c 2007-06-04 11:45:43.000000000 +1000
+++ linux-cell/arch/powerpc/kernel/signal_32.c 2007-06-04 11:45:55.000000000 +1000
@@ -253,14 +253,6 @@ long sys_sigsuspend(old_sigset_t mask)
return -ERESTARTNOHAND;
}
-#ifdef CONFIG_PPC32
-long sys_sigaltstack(const stack_t __user *uss, stack_t __user *uoss, int r5,
- int r6, int r7, int r8, struct pt_regs *regs)
-{
- return do_sigaltstack(uss, uoss, regs->gpr[1]);
-}
-#endif
-
long sys_sigaction(int sig, struct old_sigaction __user *act,
struct old_sigaction __user *oact)
{
Index: linux-cell/arch/powerpc/kernel/signal_64.c
===================================================================
--- linux-cell.orig/arch/powerpc/kernel/signal_64.c 2007-06-04 11:45:43.000000000 +1000
+++ linux-cell/arch/powerpc/kernel/signal_64.c 2007-06-04 11:45:55.000000000 +1000
@@ -66,14 +66,6 @@ struct rt_sigframe {
char abigap[288];
} __attribute__ ((aligned (16)));
-long sys_sigaltstack(const stack_t __user *uss, stack_t __user *uoss, unsigned long r5,
- unsigned long r6, unsigned long r7, unsigned long r8,
- struct pt_regs *regs)
-{
- return do_sigaltstack(uss, uoss, regs->gpr[1]);
-}
-
-
/*
* Set up the sigcontext for the signal frame.
*/
Index: linux-cell/include/asm-powerpc/syscalls.h
===================================================================
--- linux-cell.orig/include/asm-powerpc/syscalls.h 2007-06-04 11:45:43.000000000 +1000
+++ linux-cell/include/asm-powerpc/syscalls.h 2007-06-04 11:45:55.000000000 +1000
@@ -43,16 +43,9 @@ asmlinkage long ppc_newuname(struct new_
asmlinkage long sys_rt_sigsuspend(sigset_t __user *unewset,
size_t sigsetsize);
-
-#ifndef __powerpc64__
-asmlinkage long sys_sigaltstack(const stack_t __user *uss,
- stack_t __user *uoss, int r5, int r6, int r7, int r8,
- struct pt_regs *regs);
-#else /* __powerpc64__ */
asmlinkage long sys_sigaltstack(const stack_t __user *uss,
stack_t __user *uoss, unsigned long r5, unsigned long r6,
unsigned long r7, unsigned long r8, struct pt_regs *regs);
-#endif /* __powerpc64__ */
#endif /* __KERNEL__ */
#endif /* __ASM_POWERPC_SYSCALLS_H */
Index: linux-cell/arch/powerpc/kernel/signal.c
===================================================================
--- linux-cell.orig/arch/powerpc/kernel/signal.c 2007-06-04 11:45:50.000000000 +1000
+++ linux-cell/arch/powerpc/kernel/signal.c 2007-06-04 11:45:55.000000000 +1000
@@ -62,3 +62,10 @@ void check_syscall_restart(struct pt_reg
regs->ccr |= 0x10000000;
}
}
+
+long sys_sigaltstack(const stack_t __user *uss, stack_t __user *uoss,
+ unsigned long r5, unsigned long r6, unsigned long r7,
+ unsigned long r8, struct pt_regs *regs)
+{
+ return do_sigaltstack(uss, uoss, regs->gpr[1]);
+}
^ permalink raw reply [flat|nested] 30+ messages in thread
* [PATCH 16/21] powerpc: consolidate restore_sigmask
2007-06-04 5:15 [PATCH 0/21] This is my pending series for 2.6.23 Benjamin Herrenschmidt
` (14 preceding siblings ...)
2007-06-04 5:15 ` [PATCH 15/21] powerpc: consolidate sys_sigaltstack Benjamin Herrenschmidt
@ 2007-06-04 5:15 ` Benjamin Herrenschmidt
2007-06-04 5:15 ` [PATCH 17/21] powerpc: consolidate do_signal Benjamin Herrenschmidt
` (5 subsequent siblings)
21 siblings, 0 replies; 30+ messages in thread
From: Benjamin Herrenschmidt @ 2007-06-04 5:15 UTC (permalink / raw)
To: linuxppc-dev; +Cc: Paul Mackerras, Christoph Hellwig, cbe-oss-dev
From: Christoph Hellwig <hch@lst.de>
restore_sigmask is exactly the same on 32 and 64bit, so move it to
common code. Also move _BLOCKABLE to signal.h to avoid defining it
multiple times.
Signed-off-by: Christoph Hellwig <hch@lst.de>
Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
---
arch/powerpc/kernel/signal.c | 15 +++++++++++++++
arch/powerpc/kernel/signal.h | 3 +++
arch/powerpc/kernel/signal_32.c | 19 -------------------
arch/powerpc/kernel/signal_64.c | 15 ---------------
4 files changed, 18 insertions(+), 34 deletions(-)
Index: linux-cell/arch/powerpc/kernel/signal.c
===================================================================
--- linux-cell.orig/arch/powerpc/kernel/signal.c 2007-06-04 11:45:55.000000000 +1000
+++ linux-cell/arch/powerpc/kernel/signal.c 2007-06-04 11:45:58.000000000 +1000
@@ -12,6 +12,21 @@
#include <linux/ptrace.h>
#include <linux/signal.h>
+#include "signal.h"
+
+
+/*
+ * Restore the user process's signal mask
+ */
+void restore_sigmask(sigset_t *set)
+{
+ sigdelsetmask(set, ~_BLOCKABLE);
+ spin_lock_irq(¤t->sighand->siglock);
+ current->blocked = *set;
+ recalc_sigpending();
+ spin_unlock_irq(¤t->sighand->siglock);
+}
+
void check_syscall_restart(struct pt_regs *regs, struct k_sigaction *ka,
int has_handler)
{
Index: linux-cell/arch/powerpc/kernel/signal.h
===================================================================
--- linux-cell.orig/arch/powerpc/kernel/signal.h 2007-06-04 11:45:41.000000000 +1000
+++ linux-cell/arch/powerpc/kernel/signal.h 2007-06-04 11:45:58.000000000 +1000
@@ -10,6 +10,9 @@
#ifndef _POWERPC_ARCH_SIGNAL_H
#define _POWERPC_ARCH_SIGNAL_H
+#define _BLOCKABLE (~(sigmask(SIGKILL) | sigmask(SIGSTOP)))
+
+extern void restore_sigmask(sigset_t *set);
extern void check_syscall_restart(struct pt_regs *regs, struct k_sigaction *ka,
int has_handler);
Index: linux-cell/arch/powerpc/kernel/signal_32.c
===================================================================
--- linux-cell.orig/arch/powerpc/kernel/signal_32.c 2007-06-04 11:45:55.000000000 +1000
+++ linux-cell/arch/powerpc/kernel/signal_32.c 2007-06-04 11:45:58.000000000 +1000
@@ -55,8 +55,6 @@
#undef DEBUG_SIG
-#define _BLOCKABLE (~(sigmask(SIGKILL) | sigmask(SIGSTOP)))
-
#ifdef CONFIG_PPC64
#define do_signal do_signal32
#define sys_sigsuspend compat_sys_sigsuspend
@@ -697,23 +695,6 @@ int compat_sys_sigaltstack(u32 __new, u3
}
#endif /* CONFIG_PPC64 */
-
-/*
- * Restore the user process's signal mask
- */
-#ifdef CONFIG_PPC64
-extern void restore_sigmask(sigset_t *set);
-#else /* CONFIG_PPC64 */
-static void restore_sigmask(sigset_t *set)
-{
- sigdelsetmask(set, ~_BLOCKABLE);
- spin_lock_irq(¤t->sighand->siglock);
- current->blocked = *set;
- recalc_sigpending();
- spin_unlock_irq(¤t->sighand->siglock);
-}
-#endif
-
/*
* Set up a signal frame for a "real-time" signal handler
* (one which gets siginfo).
Index: linux-cell/arch/powerpc/kernel/signal_64.c
===================================================================
--- linux-cell.orig/arch/powerpc/kernel/signal_64.c 2007-06-04 11:45:55.000000000 +1000
+++ linux-cell/arch/powerpc/kernel/signal_64.c 2007-06-04 11:45:58.000000000 +1000
@@ -38,8 +38,6 @@
#define DEBUG_SIG 0
-#define _BLOCKABLE (~(sigmask(SIGKILL) | sigmask(SIGSTOP)))
-
#define GP_REGS_SIZE min(sizeof(elf_gregset_t), sizeof(struct pt_regs))
#define FP_REGS_SIZE sizeof(elf_fpregset_t)
@@ -243,19 +241,6 @@ static long setup_trampoline(unsigned in
}
/*
- * Restore the user process's signal mask (also used by signal32.c)
- */
-void restore_sigmask(sigset_t *set)
-{
- sigdelsetmask(set, ~_BLOCKABLE);
- spin_lock_irq(¤t->sighand->siglock);
- current->blocked = *set;
- recalc_sigpending();
- spin_unlock_irq(¤t->sighand->siglock);
-}
-
-
-/*
* Handle {get,set,swap}_context operations
*/
int sys_swapcontext(struct ucontext __user *old_ctx,
^ permalink raw reply [flat|nested] 30+ messages in thread
* [PATCH 17/21] powerpc: consolidate do_signal
2007-06-04 5:15 [PATCH 0/21] This is my pending series for 2.6.23 Benjamin Herrenschmidt
` (15 preceding siblings ...)
2007-06-04 5:15 ` [PATCH 16/21] powerpc: consolidate restore_sigmask Benjamin Herrenschmidt
@ 2007-06-04 5:15 ` Benjamin Herrenschmidt
2007-06-04 5:15 ` [PATCH 18/21] powerpc: Remove obsolete freezer bits Benjamin Herrenschmidt
` (4 subsequent siblings)
21 siblings, 0 replies; 30+ messages in thread
From: Benjamin Herrenschmidt @ 2007-06-04 5:15 UTC (permalink / raw)
To: linuxppc-dev; +Cc: Paul Mackerras, Christoph Hellwig, cbe-oss-dev
From: Christoph Hellwig <hch@lst.de>
do_signal has exactly the same behaviour on 32bit and 64bit and 32bit
compat on 64bit for handling 32bit signals. Consolidate all these
into one common function in signal.c. The oly odd left over is
the try_to_free in the 32bit version that no other architecture has
in mainline (only in i386 for some odd SuSE release). We should
probably get rid of it in a separate patch.
Signed-off-by: Christoph Hellwig <hch@lst.de>
Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
---
arch/powerpc/kernel/signal.c | 107 +++++++++++++++++++++++++++++++++++++++-
arch/powerpc/kernel/signal.h | 14 ++++-
arch/powerpc/kernel/signal_32.c | 88 --------------------------------
arch/powerpc/kernel/signal_64.c | 86 --------------------------------
4 files changed, 120 insertions(+), 175 deletions(-)
Index: linux-cell/arch/powerpc/kernel/signal.c
===================================================================
--- linux-cell.orig/arch/powerpc/kernel/signal.c 2007-06-04 11:45:58.000000000 +1000
+++ linux-cell/arch/powerpc/kernel/signal.c 2007-06-04 11:46:18.000000000 +1000
@@ -9,12 +9,26 @@
* this archive for more details.
*/
+#include <linux/freezer.h>
#include <linux/ptrace.h>
#include <linux/signal.h>
#include "signal.h"
+#ifdef CONFIG_PPC64
+static inline int is_32bit_task(void)
+{
+ return test_thread_flag(TIF_32BIT);
+}
+#else
+static inline int is_32bit_task(void)
+{
+ return 1;
+}
+#endif
+
+
/*
* Restore the user process's signal mask
*/
@@ -27,8 +41,8 @@ void restore_sigmask(sigset_t *set)
spin_unlock_irq(¤t->sighand->siglock);
}
-void check_syscall_restart(struct pt_regs *regs, struct k_sigaction *ka,
- int has_handler)
+static void check_syscall_restart(struct pt_regs *regs, struct k_sigaction *ka,
+ int has_handler)
{
unsigned long ret = regs->gpr[3];
int restart = 1;
@@ -78,6 +92,95 @@ void check_syscall_restart(struct pt_reg
}
}
+int do_signal(sigset_t *oldset, struct pt_regs *regs)
+{
+ siginfo_t info;
+ int signr;
+ struct k_sigaction ka;
+ int ret;
+ int is32 = is_32bit_task();
+
+#ifdef CONFIG_PPC32
+ if (try_to_freeze()) {
+ signr = 0;
+ if (!signal_pending(current))
+ goto no_signal;
+ }
+#endif
+
+ if (test_thread_flag(TIF_RESTORE_SIGMASK))
+ oldset = ¤t->saved_sigmask;
+ else if (!oldset)
+ oldset = ¤t->blocked;
+
+ signr = get_signal_to_deliver(&info, &ka, regs, NULL);
+
+#ifdef CONFIG_PPC32
+no_signal:
+#endif
+ /* 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 */
+ if (test_thread_flag(TIF_RESTORE_SIGMASK)) {
+ clear_thread_flag(TIF_RESTORE_SIGMASK);
+ sigprocmask(SIG_SETMASK, ¤t->saved_sigmask, NULL);
+ }
+ return 0; /* no signals delivered */
+ }
+
+#ifdef CONFIG_PPC64
+ /*
+ * Reenable the DABR before delivering the signal to
+ * user space. The DABR will have been cleared if it
+ * triggered inside the kernel.
+ */
+ if (current->thread.dabr)
+ set_dabr(current->thread.dabr);
+#endif
+
+ if (is32) {
+ unsigned int newsp;
+
+ if ((ka.sa.sa_flags & SA_ONSTACK) &&
+ current->sas_ss_size && !on_sig_stack(regs->gpr[1]))
+ newsp = current->sas_ss_sp + current->sas_ss_size;
+ else
+ newsp = regs->gpr[1];
+
+ if (ka.sa.sa_flags & SA_SIGINFO)
+ ret = handle_rt_signal32(signr, &ka, &info, oldset,
+ regs, newsp);
+ else
+ ret = handle_signal32(signr, &ka, &info, oldset,
+ regs, newsp);
+#ifdef CONFIG_PPC64
+ } else {
+ ret = handle_rt_signal64(signr, &ka, &info, oldset, regs);
+#endif
+ }
+
+ if (ret) {
+ spin_lock_irq(¤t->sighand->siglock);
+ sigorsets(¤t->blocked, ¤t->blocked,
+ &ka.sa.sa_mask);
+ if (!(ka.sa.sa_flags & SA_NODEFER))
+ sigaddset(¤t->blocked, signr);
+ recalc_sigpending();
+ spin_unlock_irq(¤t->sighand->siglock);
+
+ /*
+ * A signal was successfully delivered; the saved sigmask is in
+ * its frame, and we can clear the TIF_RESTORE_SIGMASK flag.
+ */
+ if (test_thread_flag(TIF_RESTORE_SIGMASK))
+ clear_thread_flag(TIF_RESTORE_SIGMASK);
+ }
+
+ return ret;
+}
+
long sys_sigaltstack(const stack_t __user *uss, stack_t __user *uoss,
unsigned long r5, unsigned long r6, unsigned long r7,
unsigned long r8, struct pt_regs *regs)
Index: linux-cell/arch/powerpc/kernel/signal.h
===================================================================
--- linux-cell.orig/arch/powerpc/kernel/signal.h 2007-06-04 11:45:58.000000000 +1000
+++ linux-cell/arch/powerpc/kernel/signal.h 2007-06-04 11:46:03.000000000 +1000
@@ -13,7 +13,17 @@
#define _BLOCKABLE (~(sigmask(SIGKILL) | sigmask(SIGSTOP)))
extern void restore_sigmask(sigset_t *set);
-extern void check_syscall_restart(struct pt_regs *regs, struct k_sigaction *ka,
- int has_handler);
+
+extern int handle_signal32(unsigned long sig, struct k_sigaction *ka,
+ siginfo_t *info, sigset_t *oldset,
+ struct pt_regs *regs, unsigned long newsp);
+
+extern int handle_rt_signal32(unsigned long sig, struct k_sigaction *ka,
+ siginfo_t *info, sigset_t *oldset,
+ struct pt_regs *regs, unsigned long newsp);
+
+extern int handle_rt_signal64(int signr, struct k_sigaction *ka,
+ siginfo_t *info, sigset_t *set,
+ struct pt_regs *regs);
#endif /* _POWERPC_ARCH_SIGNAL_H */
Index: linux-cell/arch/powerpc/kernel/signal_32.c
===================================================================
--- linux-cell.orig/arch/powerpc/kernel/signal_32.c 2007-06-04 11:45:58.000000000 +1000
+++ linux-cell/arch/powerpc/kernel/signal_32.c 2007-06-04 11:46:03.000000000 +1000
@@ -56,7 +56,6 @@
#undef DEBUG_SIG
#ifdef CONFIG_PPC64
-#define do_signal do_signal32
#define sys_sigsuspend compat_sys_sigsuspend
#define sys_rt_sigsuspend compat_sys_rt_sigsuspend
#define sys_rt_sigreturn compat_sys_rt_sigreturn
@@ -231,8 +230,6 @@ static inline int restore_general_regs(s
#endif /* CONFIG_PPC64 */
-int do_signal(sigset_t *oldset, struct pt_regs *regs);
-
/*
* Atomically swap in the new signal mask, and wait for a signal.
*/
@@ -699,7 +696,7 @@ int compat_sys_sigaltstack(u32 __new, u3
* Set up a signal frame for a "real-time" signal handler
* (one which gets siginfo).
*/
-static int handle_rt_signal(unsigned long sig, struct k_sigaction *ka,
+int handle_rt_signal32(unsigned long sig, struct k_sigaction *ka,
siginfo_t *info, sigset_t *oldset,
struct pt_regs *regs, unsigned long newsp)
{
@@ -990,7 +987,7 @@ int sys_debug_setcontext(struct ucontext
/*
* OK, we're invoking a handler
*/
-static int handle_signal(unsigned long sig, struct k_sigaction *ka,
+int handle_signal32(unsigned long sig, struct k_sigaction *ka,
siginfo_t *info, sigset_t *oldset, struct pt_regs *regs,
unsigned long newsp)
{
@@ -1101,84 +1098,3 @@ badframe:
force_sig(SIGSEGV, current);
return 0;
}
-
-/*
- * 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
- * mistake.
- */
-int do_signal(sigset_t *oldset, struct pt_regs *regs)
-{
- siginfo_t info;
- struct k_sigaction ka;
- unsigned int newsp;
- int signr, ret;
-
-#ifdef CONFIG_PPC32
- if (try_to_freeze()) {
- signr = 0;
- if (!signal_pending(current))
- goto no_signal;
- }
-#endif
-
- if (test_thread_flag(TIF_RESTORE_SIGMASK))
- oldset = ¤t->saved_sigmask;
- else if (!oldset)
- oldset = ¤t->blocked;
-
- signr = get_signal_to_deliver(&info, &ka, regs, NULL);
-#ifdef CONFIG_PPC32
-no_signal:
-#endif
- /* 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 */
- if (test_thread_flag(TIF_RESTORE_SIGMASK)) {
- clear_thread_flag(TIF_RESTORE_SIGMASK);
- sigprocmask(SIG_SETMASK, ¤t->saved_sigmask, NULL);
- }
- return 0; /* no signals delivered */
- }
-
- if ((ka.sa.sa_flags & SA_ONSTACK) && current->sas_ss_size
- && !on_sig_stack(regs->gpr[1]))
- newsp = current->sas_ss_sp + current->sas_ss_size;
- else
- newsp = regs->gpr[1];
- newsp &= ~0xfUL;
-
-#ifdef CONFIG_PPC64
- /*
- * Reenable the DABR before delivering the signal to
- * user space. The DABR will have been cleared if it
- * triggered inside the kernel.
- */
- if (current->thread.dabr)
- set_dabr(current->thread.dabr);
-#endif
-
- /* Whee! Actually deliver the signal. */
- if (ka.sa.sa_flags & SA_SIGINFO)
- ret = handle_rt_signal(signr, &ka, &info, oldset, regs, newsp);
- else
- ret = handle_signal(signr, &ka, &info, oldset, regs, newsp);
-
- if (ret) {
- spin_lock_irq(¤t->sighand->siglock);
- sigorsets(¤t->blocked, ¤t->blocked,
- &ka.sa.sa_mask);
- if (!(ka.sa.sa_flags & SA_NODEFER))
- sigaddset(¤t->blocked, signr);
- recalc_sigpending();
- spin_unlock_irq(¤t->sighand->siglock);
- /* A signal was successfully delivered; the saved sigmask is in
- its frame, and we can clear the TIF_RESTORE_SIGMASK flag */
- if (test_thread_flag(TIF_RESTORE_SIGMASK))
- clear_thread_flag(TIF_RESTORE_SIGMASK);
- }
-
- return ret;
-}
Index: linux-cell/arch/powerpc/kernel/signal_64.c
===================================================================
--- linux-cell.orig/arch/powerpc/kernel/signal_64.c 2007-06-04 11:45:58.000000000 +1000
+++ linux-cell/arch/powerpc/kernel/signal_64.c 2007-06-04 11:46:03.000000000 +1000
@@ -334,7 +334,7 @@ badframe:
return 0;
}
-static int setup_rt_frame(int signr, struct k_sigaction *ka, siginfo_t *info,
+int handle_rt_signal64(int signr, struct k_sigaction *ka, siginfo_t *info,
sigset_t *set, struct pt_regs *regs)
{
/* Handler is *really* a pointer to the function descriptor for
@@ -417,87 +417,3 @@ badframe:
force_sigsegv(signr, current);
return 0;
}
-
-
-/*
- * OK, we're invoking a handler
- */
-static int handle_signal(unsigned long sig, struct k_sigaction *ka,
- siginfo_t *info, sigset_t *oldset, struct pt_regs *regs)
-{
- int ret;
-
- /* Set up Signal Frame */
- ret = setup_rt_frame(sig, ka, info, oldset, regs);
-
- if (ret) {
- spin_lock_irq(¤t->sighand->siglock);
- sigorsets(¤t->blocked, ¤t->blocked, &ka->sa.sa_mask);
- if (!(ka->sa.sa_flags & SA_NODEFER))
- sigaddset(¤t->blocked,sig);
- recalc_sigpending();
- spin_unlock_irq(¤t->sighand->siglock);
- }
-
- return ret;
-}
-
-/*
- * 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
- * mistake.
- */
-int do_signal(sigset_t *oldset, struct pt_regs *regs)
-{
- siginfo_t info;
- int signr;
- struct k_sigaction ka;
-
- /*
- * If the current thread is 32 bit - invoke the
- * 32 bit signal handling code
- */
- if (test_thread_flag(TIF_32BIT))
- return do_signal32(oldset, regs);
-
- if (test_thread_flag(TIF_RESTORE_SIGMASK))
- oldset = ¤t->saved_sigmask;
- else if (!oldset)
- 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;
-
- /*
- * Reenable the DABR before delivering the signal to
- * user space. The DABR will have been cleared if it
- * triggered inside the kernel.
- */
- 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
- its frame, and we can clear the TIF_RESTORE_SIGMASK flag */
- if (ret && test_thread_flag(TIF_RESTORE_SIGMASK))
- clear_thread_flag(TIF_RESTORE_SIGMASK);
-
- return ret;
- }
-
- /* No signal to deliver -- put the saved sigmask back */
- if (test_thread_flag(TIF_RESTORE_SIGMASK)) {
- clear_thread_flag(TIF_RESTORE_SIGMASK);
- sigprocmask(SIG_SETMASK, ¤t->saved_sigmask, NULL);
- }
-
- return 0;
-}
-EXPORT_SYMBOL(do_signal);
^ permalink raw reply [flat|nested] 30+ messages in thread
* [PATCH 18/21] powerpc: Remove obsolete freezer bits
2007-06-04 5:15 [PATCH 0/21] This is my pending series for 2.6.23 Benjamin Herrenschmidt
` (16 preceding siblings ...)
2007-06-04 5:15 ` [PATCH 17/21] powerpc: consolidate do_signal Benjamin Herrenschmidt
@ 2007-06-04 5:15 ` Benjamin Herrenschmidt
2007-06-04 5:15 ` [PATCH 19/21] powerpc: Merge creation of signal frame Benjamin Herrenschmidt
` (3 subsequent siblings)
21 siblings, 0 replies; 30+ messages in thread
From: Benjamin Herrenschmidt @ 2007-06-04 5:15 UTC (permalink / raw)
To: linuxppc-dev; +Cc: Paul Mackerras, Christoph Hellwig, cbe-oss-dev
The powerpc signal code still had some obsolete freezer bits that
have long been removed from x86 (it's now done in generic code).
Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
---
arch/powerpc/kernel/signal.c | 12 ------------
1 file changed, 12 deletions(-)
Index: linux-cell/arch/powerpc/kernel/signal.c
===================================================================
--- linux-cell.orig/arch/powerpc/kernel/signal.c 2007-06-04 11:44:24.000000000 +1000
+++ linux-cell/arch/powerpc/kernel/signal.c 2007-06-04 11:44:34.000000000 +1000
@@ -9,7 +9,6 @@
* this archive for more details.
*/
-#include <linux/freezer.h>
#include <linux/ptrace.h>
#include <linux/signal.h>
@@ -100,14 +99,6 @@ int do_signal(sigset_t *oldset, struct p
int ret;
int is32 = is_32bit_task();
-#ifdef CONFIG_PPC32
- if (try_to_freeze()) {
- signr = 0;
- if (!signal_pending(current))
- goto no_signal;
- }
-#endif
-
if (test_thread_flag(TIF_RESTORE_SIGMASK))
oldset = ¤t->saved_sigmask;
else if (!oldset)
@@ -115,9 +106,6 @@ int do_signal(sigset_t *oldset, struct p
signr = get_signal_to_deliver(&info, &ka, regs, NULL);
-#ifdef CONFIG_PPC32
-no_signal:
-#endif
/* Is there any syscall restart business here ? */
check_syscall_restart(regs, &ka, signr > 0);
^ permalink raw reply [flat|nested] 30+ messages in thread
* [PATCH 19/21] powerpc: Merge creation of signal frame
2007-06-04 5:15 [PATCH 0/21] This is my pending series for 2.6.23 Benjamin Herrenschmidt
` (17 preceding siblings ...)
2007-06-04 5:15 ` [PATCH 18/21] powerpc: Remove obsolete freezer bits Benjamin Herrenschmidt
@ 2007-06-04 5:15 ` Benjamin Herrenschmidt
2007-06-04 7:22 ` PATCH 19/21] powerpc: Merge creation of signal frame (#2) Benjamin Herrenschmidt
2007-06-04 5:15 ` [PATCH 20/21] powerpc: remove #ifdef around set_dabr in signal code Benjamin Herrenschmidt
` (2 subsequent siblings)
21 siblings, 1 reply; 30+ messages in thread
From: Benjamin Herrenschmidt @ 2007-06-04 5:15 UTC (permalink / raw)
To: linuxppc-dev; +Cc: Paul Mackerras, Christoph Hellwig, cbe-oss-dev
The code for creating signal frames was still duplicated and split
in strange ways between 32 and 64 bits, including the SA_ONSTACK
handling being in do_signal on 32 bits but inside handle_rt_signal
on 64 bits etc...
This moves the 64 bits get_sigframe() to the generic signal.c,
cleans it a bit, moves the access_ok() call done by all callers to
it as well, and adapts/cleanups the 3 different signal handling cases
to use that common function.
Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
---
arch/powerpc/kernel/signal.c | 39 ++++++++++++++++++++++--------
arch/powerpc/kernel/signal.h | 6 +++-
arch/powerpc/kernel/signal_32.c | 52 ++++++++++++++++++----------------------
arch/powerpc/kernel/signal_64.c | 22 ----------------
4 files changed, 58 insertions(+), 61 deletions(-)
Index: linux-cell/arch/powerpc/kernel/signal.c
===================================================================
--- linux-cell.orig/arch/powerpc/kernel/signal.c 2007-06-04 14:06:06.000000000 +1000
+++ linux-cell/arch/powerpc/kernel/signal.c 2007-06-04 14:07:25.000000000 +1000
@@ -11,6 +11,7 @@
#include <linux/ptrace.h>
#include <linux/signal.h>
+#include <asm/uaccess.h>
#include "signal.h"
@@ -27,6 +28,32 @@ static inline int is_32bit_task(void)
}
#endif
+/*
+ * Allocate space for the signal frame
+ */
+void __user * get_sigframe(struct k_sigaction *ka, struct pt_regs *regs,
+ size_t frame_size)
+{
+ unsigned long oldsp, newsp;
+
+ /* Default to using normal stack */
+ oldsp = regs->gpr[1];
+
+ /* Check for alt stack */
+ if ((ka->sa.sa_flags & SA_ONSTACK) &&
+ current->sas_ss_size && !on_sig_stack(regs->gpr[1]))
+ oldsp = (current->sas_ss_sp + current->sas_ss_size);
+
+ /* Get aligned frame */
+ newsp = (oldsp - frame_size) & ~0xFUL;
+
+ /* Check access */
+ if (!access_ok(VERIFY_WRITE, (void __user *)newsp, oldsp - newsp))
+ return NULL;
+
+ return (void __user *)newsp;
+}
+
/*
* Restore the user process's signal mask
@@ -129,20 +156,12 @@ int do_signal(sigset_t *oldset, struct p
#endif
if (is32) {
- unsigned int newsp;
-
- if ((ka.sa.sa_flags & SA_ONSTACK) &&
- current->sas_ss_size && !on_sig_stack(regs->gpr[1]))
- newsp = current->sas_ss_sp + current->sas_ss_size;
- else
- newsp = regs->gpr[1];
-
if (ka.sa.sa_flags & SA_SIGINFO)
ret = handle_rt_signal32(signr, &ka, &info, oldset,
- regs, newsp);
+ regs);
else
ret = handle_signal32(signr, &ka, &info, oldset,
- regs, newsp);
+ regs);
#ifdef CONFIG_PPC64
} else {
ret = handle_rt_signal64(signr, &ka, &info, oldset, regs);
Index: linux-cell/arch/powerpc/kernel/signal.h
===================================================================
--- linux-cell.orig/arch/powerpc/kernel/signal.h 2007-06-04 14:06:06.000000000 +1000
+++ linux-cell/arch/powerpc/kernel/signal.h 2007-06-04 14:07:25.000000000 +1000
@@ -12,15 +12,17 @@
#define _BLOCKABLE (~(sigmask(SIGKILL) | sigmask(SIGSTOP)))
+extern void __user * get_sigframe(struct k_sigaction *ka, struct pt_regs *regs,
+ size_t frame_size);
extern void restore_sigmask(sigset_t *set);
extern int handle_signal32(unsigned long sig, struct k_sigaction *ka,
siginfo_t *info, sigset_t *oldset,
- struct pt_regs *regs, unsigned long newsp);
+ struct pt_regs *regs);
extern int handle_rt_signal32(unsigned long sig, struct k_sigaction *ka,
siginfo_t *info, sigset_t *oldset,
- struct pt_regs *regs, unsigned long newsp);
+ struct pt_regs *regs);
extern int handle_rt_signal64(int signr, struct k_sigaction *ka,
siginfo_t *info, sigset_t *set,
Index: linux-cell/arch/powerpc/kernel/signal_32.c
===================================================================
--- linux-cell.orig/arch/powerpc/kernel/signal_32.c 2007-06-04 14:06:06.000000000 +1000
+++ linux-cell/arch/powerpc/kernel/signal_32.c 2007-06-04 14:07:25.000000000 +1000
@@ -282,14 +282,17 @@ long sys_sigaction(int sig, struct old_s
/*
* When we have signals to deliver, we set up on the
* user stack, going down from the original stack pointer:
- * a sigregs struct
+ * an ABI gap of 56 words
+ * an mcontext struct
* a sigcontext struct
* a gap of __SIGNAL_FRAMESIZE bytes
*
- * Each of these things must be a multiple of 16 bytes in size.
+ * Each of these things must be a multiple of 16 bytes in size. The following
+ * structure represent all of this except the __SIGNAL_FRAMESIZE gap
*
*/
-struct sigregs {
+struct sigframe {
+ struct sigcontext sctx; /* the sigcontext */
struct mcontext mctx; /* all the register values */
/*
* Programs using the rs6000/xcoff abi can save up to 19 gp
@@ -698,21 +701,16 @@ int compat_sys_sigaltstack(u32 __new, u3
*/
int handle_rt_signal32(unsigned long sig, struct k_sigaction *ka,
siginfo_t *info, sigset_t *oldset,
- struct pt_regs *regs, unsigned long newsp)
+ struct pt_regs *regs)
{
struct rt_sigframe __user *rt_sf;
struct mcontext __user *frame;
- unsigned long origsp = newsp;
+ unsigned long newsp = 0;
/* Set up Signal Frame */
/* Put a Real Time Context onto stack */
- newsp -= sizeof(*rt_sf);
- rt_sf = (struct rt_sigframe __user *)newsp;
-
- /* create a stack frame for the caller of the handler */
- newsp -= __SIGNAL_FRAMESIZE + 16;
-
- if (!access_ok(VERIFY_WRITE, (void __user *)newsp, origsp - newsp))
+ rt_sf = get_sigframe(ka, regs, sizeof(*rt_sf));
+ if (unlikely(rt_sf == NULL))
goto badframe;
/* Put the siginfo & fill in most of the ucontext */
@@ -742,8 +740,12 @@ int handle_rt_signal32(unsigned long sig
current->thread.fpscr.val = 0; /* turn off all fp exceptions */
+ /* create a stack frame for the caller of the handler */
+ newsp = (unsigned long)rt_sf - __SIGNAL_FRAMESIZE + 16;
if (put_user(regs->gpr[1], (u32 __user *)newsp))
goto badframe;
+
+ /* Fill registers for signal handler */
regs->gpr[1] = newsp;
regs->gpr[3] = sig;
regs->gpr[4] = (unsigned long) &rt_sf->info;
@@ -988,26 +990,17 @@ int sys_debug_setcontext(struct ucontext
* OK, we're invoking a handler
*/
int handle_signal32(unsigned long sig, struct k_sigaction *ka,
- siginfo_t *info, sigset_t *oldset, struct pt_regs *regs,
- unsigned long newsp)
+ siginfo_t *info, sigset_t *oldset, struct pt_regs *regs)
{
struct sigcontext __user *sc;
- struct sigregs __user *frame;
- unsigned long origsp = newsp;
+ struct sigframe __user *frame;
+ unsigned long newsp = 0;
/* Set up Signal Frame */
- newsp -= sizeof(struct sigregs);
- frame = (struct sigregs __user *) newsp;
-
- /* Put a sigcontext on the stack */
- newsp -= sizeof(*sc);
- sc = (struct sigcontext __user *) newsp;
-
- /* create a stack frame for the caller of the handler */
- newsp -= __SIGNAL_FRAMESIZE;
-
- if (!access_ok(VERIFY_WRITE, (void __user *) newsp, origsp - newsp))
+ frame = get_sigframe(ka, regs, sizeof(*frame));
+ if (unlikely(frame == NULL))
goto badframe;
+ sc = (struct sigcontext __user *) &frame->sctx;
#if _NSIG != 64
#error "Please adjust handle_signal()"
@@ -1019,7 +1012,7 @@ int handle_signal32(unsigned long sig, s
#else
|| __put_user(oldset->sig[1], &sc->_unused[3])
#endif
- || __put_user(to_user_ptr(frame), &sc->regs)
+ || __put_user(to_user_ptr(&frame->mctx), &sc->regs)
|| __put_user(sig, &sc->signal))
goto badframe;
@@ -1035,8 +1028,11 @@ int handle_signal32(unsigned long sig, s
current->thread.fpscr.val = 0; /* turn off all fp exceptions */
+ /* create a stack frame for the caller of the handler */
+ newsp -= __SIGNAL_FRAMESIZE;
if (put_user(regs->gpr[1], (u32 __user *)newsp))
goto badframe;
+
regs->gpr[1] = newsp;
regs->gpr[3] = sig;
regs->gpr[4] = (unsigned long) sc;
Index: linux-cell/arch/powerpc/kernel/signal_64.c
===================================================================
--- linux-cell.orig/arch/powerpc/kernel/signal_64.c 2007-06-04 14:06:06.000000000 +1000
+++ linux-cell/arch/powerpc/kernel/signal_64.c 2007-06-04 14:07:25.000000000 +1000
@@ -196,25 +196,6 @@ static long restore_sigcontext(struct pt
}
/*
- * Allocate space for the signal frame
- */
-static inline void __user * get_sigframe(struct k_sigaction *ka, struct pt_regs *regs,
- size_t frame_size)
-{
- unsigned long newsp;
-
- /* Default to using normal stack */
- newsp = regs->gpr[1];
-
- if ((ka->sa.sa_flags & SA_ONSTACK) && current->sas_ss_size) {
- if (! on_sig_stack(regs->gpr[1]))
- newsp = (current->sas_ss_sp + current->sas_ss_size);
- }
-
- return (void __user *)((newsp - frame_size) & -16ul);
-}
-
-/*
* Setup the trampoline code on the stack
*/
static long setup_trampoline(unsigned int syscall, unsigned int __user *tramp)
@@ -348,8 +329,7 @@ int handle_rt_signal64(int signr, struct
long err = 0;
frame = get_sigframe(ka, regs, sizeof(*frame));
-
- if (!access_ok(VERIFY_WRITE, frame, sizeof(*frame)))
+ if (unlikely(frame == NULL))
goto badframe;
err |= __put_user(&frame->info, &frame->pinfo);
^ permalink raw reply [flat|nested] 30+ messages in thread
* [PATCH 20/21] powerpc: remove #ifdef around set_dabr in signal code
2007-06-04 5:15 [PATCH 0/21] This is my pending series for 2.6.23 Benjamin Herrenschmidt
` (18 preceding siblings ...)
2007-06-04 5:15 ` [PATCH 19/21] powerpc: Merge creation of signal frame Benjamin Herrenschmidt
@ 2007-06-04 5:15 ` Benjamin Herrenschmidt
2007-06-04 5:15 ` [PATCH 21/21] powerpc: Less ifdef's in signal.c/signal.h Benjamin Herrenschmidt
2007-06-04 7:00 ` [PATCH 0/21] This is my pending series for 2.6.23 Benjamin Herrenschmidt
21 siblings, 0 replies; 30+ messages in thread
From: Benjamin Herrenschmidt @ 2007-06-04 5:15 UTC (permalink / raw)
To: linuxppc-dev; +Cc: Paul Mackerras, Christoph Hellwig, cbe-oss-dev
set_dabr() and thread.dabr exist on 32 bits as well nowadays (they
actually may do something even, depending on what CPU you have).
So remove the ifdef
Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
---
arch/powerpc/kernel/signal.c | 2 --
1 file changed, 2 deletions(-)
Index: linux-cell/arch/powerpc/kernel/signal.c
===================================================================
--- linux-cell.orig/arch/powerpc/kernel/signal.c 2007-06-04 13:08:24.000000000 +1000
+++ linux-cell/arch/powerpc/kernel/signal.c 2007-06-04 13:08:30.000000000 +1000
@@ -145,7 +145,6 @@ int do_signal(sigset_t *oldset, struct p
return 0; /* no signals delivered */
}
-#ifdef CONFIG_PPC64
/*
* Reenable the DABR before delivering the signal to
* user space. The DABR will have been cleared if it
@@ -153,7 +152,6 @@ int do_signal(sigset_t *oldset, struct p
*/
if (current->thread.dabr)
set_dabr(current->thread.dabr);
-#endif
if (is32) {
if (ka.sa.sa_flags & SA_SIGINFO)
^ permalink raw reply [flat|nested] 30+ messages in thread
* [PATCH 21/21] powerpc: Less ifdef's in signal.c/signal.h
2007-06-04 5:15 [PATCH 0/21] This is my pending series for 2.6.23 Benjamin Herrenschmidt
` (19 preceding siblings ...)
2007-06-04 5:15 ` [PATCH 20/21] powerpc: remove #ifdef around set_dabr in signal code Benjamin Herrenschmidt
@ 2007-06-04 5:15 ` Benjamin Herrenschmidt
2007-06-04 7:00 ` [PATCH 0/21] This is my pending series for 2.6.23 Benjamin Herrenschmidt
21 siblings, 0 replies; 30+ messages in thread
From: Benjamin Herrenschmidt @ 2007-06-04 5:15 UTC (permalink / raw)
To: linuxppc-dev; +Cc: Paul Mackerras, Christoph Hellwig, cbe-oss-dev
This patch moves things around a little bit in the new common signal.c
and signal.h files to remove the last #ifdef in the middle of the
common do_signal()
Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
---
arch/powerpc/kernel/signal.c | 15 ---------------
arch/powerpc/kernel/signal.h | 24 ++++++++++++++++++++++++
2 files changed, 24 insertions(+), 15 deletions(-)
Index: linux-cell/arch/powerpc/kernel/signal.c
===================================================================
--- linux-cell.orig/arch/powerpc/kernel/signal.c 2007-06-04 13:09:27.000000000 +1000
+++ linux-cell/arch/powerpc/kernel/signal.c 2007-06-04 13:17:50.000000000 +1000
@@ -15,19 +15,6 @@
#include "signal.h"
-
-#ifdef CONFIG_PPC64
-static inline int is_32bit_task(void)
-{
- return test_thread_flag(TIF_32BIT);
-}
-#else
-static inline int is_32bit_task(void)
-{
- return 1;
-}
-#endif
-
/*
* Allocate space for the signal frame
*/
@@ -160,10 +147,8 @@ int do_signal(sigset_t *oldset, struct p
else
ret = handle_signal32(signr, &ka, &info, oldset,
regs);
-#ifdef CONFIG_PPC64
} else {
ret = handle_rt_signal64(signr, &ka, &info, oldset, regs);
-#endif
}
if (ret) {
Index: linux-cell/arch/powerpc/kernel/signal.h
===================================================================
--- linux-cell.orig/arch/powerpc/kernel/signal.h 2007-06-04 13:10:10.000000000 +1000
+++ linux-cell/arch/powerpc/kernel/signal.h 2007-06-04 13:11:03.000000000 +1000
@@ -24,8 +24,32 @@ extern int handle_rt_signal32(unsigned l
siginfo_t *info, sigset_t *oldset,
struct pt_regs *regs);
+
+#ifdef CONFIG_PPC64
+
+static inline int is_32bit_task(void)
+{
+ return test_thread_flag(TIF_32BIT);
+}
+
extern int handle_rt_signal64(int signr, struct k_sigaction *ka,
siginfo_t *info, sigset_t *set,
struct pt_regs *regs);
+#else /* CONFIG_PPC64 */
+
+static inline int is_32bit_task(void)
+{
+ return 1;
+}
+
+static inline int handle_rt_signal64(int signr, struct k_sigaction *ka,
+ siginfo_t *info, sigset_t *set,
+ struct pt_regs *regs)
+{
+ return -EFAULT;
+}
+
+#endif /* !defined(CONFIG_PPC64) */
+
#endif /* _POWERPC_ARCH_SIGNAL_H */
^ permalink raw reply [flat|nested] 30+ messages in thread
* Re: [PATCH 0/21] This is my pending series for 2.6.23
2007-06-04 5:15 [PATCH 0/21] This is my pending series for 2.6.23 Benjamin Herrenschmidt
` (20 preceding siblings ...)
2007-06-04 5:15 ` [PATCH 21/21] powerpc: Less ifdef's in signal.c/signal.h Benjamin Herrenschmidt
@ 2007-06-04 7:00 ` Benjamin Herrenschmidt
2007-06-04 7:21 ` Benjamin Herrenschmidt
21 siblings, 1 reply; 30+ messages in thread
From: Benjamin Herrenschmidt @ 2007-06-04 7:00 UTC (permalink / raw)
To: linuxppc-dev; +Cc: Paul Mackerras, Christoph Hellwig, cbe-oss-dev
On Mon, 2007-06-04 at 14:49 +1000, Benjamin Herrenschmidt wrote:
> It contains
>
> - My PCI IO allocation rework (the first patch changes generic code
> and is in -mm already)
>
> - spufs single step & capabilities support
>
> - my cleanup/merge of the ptrace code
>
> - patches from Christoph Hellwig and myself that fix and merge things
> in the signal handling code
>
> I'm still working on saving the top 32 bits of registers on 64 bits
> for signals, so that's not included here.
And one of the signal changes is causing init to segv on my laptop,
which I'm quite happy to blame on my signal frame allocation change.
(Well, at least with the serie applied up to Christoph 3rd patch, it
still boots). I'll debug that and post an updated patch.
Ben.
^ permalink raw reply [flat|nested] 30+ messages in thread
* Re: [PATCH 14/21] powerpc: Make syscall restart code more common
2007-06-04 5:15 ` [PATCH 14/21] powerpc: Make syscall restart code more common Benjamin Herrenschmidt
@ 2007-06-04 7:06 ` Christoph Hellwig
0 siblings, 0 replies; 30+ messages in thread
From: Christoph Hellwig @ 2007-06-04 7:06 UTC (permalink / raw)
To: Benjamin Herrenschmidt
Cc: linuxppc-dev, Paul Mackerras, Christoph Hellwig, cbe-oss-dev
On Mon, Jun 04, 2007 at 03:15:49PM +1000, Benjamin Herrenschmidt wrote:
> This patch moves the code in signal_32.c and signal_64.c for handling
> syscall restart into a common signal.c 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.
>
> Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
> ---
>
> This is basically my initial patch as modified by Christoph Hellwig
> (hch, care to send a SOB ? :-)
Signed-off-by: Christoph Hellwig <hch@lst.de>
>
>
> arch/powerpc/kernel/Makefile | 3 +
> arch/powerpc/kernel/signal.c | 64 ++++++++++++++++++++++++++++++++++++++++
> arch/powerpc/kernel/signal.h | 16 ++++++++++
> arch/powerpc/kernel/signal_32.c | 28 ++---------------
> arch/powerpc/kernel/signal_64.c | 59 ++++--------------------------------
> 5 files changed, 93 insertions(+), 77 deletions(-)
>
> 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-06-04 11:45:43.000000000 +1000
> @@ -51,6 +51,8 @@
> #include <asm/pgtable.h>
> #endif
>
> +#include "signal.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-06-04 11:45:43.000000000 +1000
> @@ -34,6 +34,8 @@
> #include <asm/syscalls.h>
> #include <asm/vdso.h>
>
> +#include "signal.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);
> Index: linux-cell/arch/powerpc/kernel/Makefile
> ===================================================================
> --- linux-cell.orig/arch/powerpc/kernel/Makefile 2007-06-04 11:16:01.000000000 +1000
> +++ linux-cell/arch/powerpc/kernel/Makefile 2007-06-04 11:16:16.000000000 +1000
> @@ -12,7 +12,8 @@ endif
>
> obj-y := semaphore.o cputable.o ptrace.o syscalls.o \
> irq.o align.o signal_32.o pmc.o vdso.o \
> - init_task.o process.o systbl.o idle.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 \
> signal_64.o ptrace32.o \
> Index: linux-cell/arch/powerpc/kernel/signal.c
> ===================================================================
> --- /dev/null 1970-01-01 00:00:00.000000000 +0000
> +++ linux-cell/arch/powerpc/kernel/signal.c 2007-06-04 11:45:50.000000000 +1000
> @@ -0,0 +1,64 @@
> +/*
> + * Common signal handling code for both 32 and 64 bits
> + *
> + * 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.
> + */
> +
> +#include <linux/ptrace.h>
> +#include <linux/signal.h>
> +
> +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;
> + }
> +}
> Index: linux-cell/arch/powerpc/kernel/signal.h
> ===================================================================
> --- /dev/null 1970-01-01 00:00:00.000000000 +0000
> +++ linux-cell/arch/powerpc/kernel/signal.h 2007-06-04 11:45:41.000000000 +1000
> @@ -0,0 +1,16 @@
> +/*
> + * 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_ARCH_SIGNAL_H
> +#define _POWERPC_ARCH_SIGNAL_H
> +
> +extern void check_syscall_restart(struct pt_regs *regs, struct k_sigaction *ka,
> + int has_handler);
> +
> +#endif /* _POWERPC_ARCH_SIGNAL_H */
---end quoted text---
^ permalink raw reply [flat|nested] 30+ messages in thread
* Re: [PATCH 0/21] This is my pending series for 2.6.23
2007-06-04 7:00 ` [PATCH 0/21] This is my pending series for 2.6.23 Benjamin Herrenschmidt
@ 2007-06-04 7:21 ` Benjamin Herrenschmidt
0 siblings, 0 replies; 30+ messages in thread
From: Benjamin Herrenschmidt @ 2007-06-04 7:21 UTC (permalink / raw)
To: linuxppc-dev; +Cc: Paul Mackerras, Christoph Hellwig, cbe-oss-dev
On Mon, 2007-06-04 at 17:00 +1000, Benjamin Herrenschmidt wrote:
> And one of the signal changes is causing init to segv on my laptop,
> which I'm quite happy to blame on my signal frame allocation change.
> (Well, at least with the serie applied up to Christoph 3rd patch, it
> still boots). I'll debug that and post an updated patch.
Fixed... posting a replacement to patch 19/21 as a reply to the initial
patch email.
Ben.
^ permalink raw reply [flat|nested] 30+ messages in thread
* PATCH 19/21] powerpc: Merge creation of signal frame (#2)
2007-06-04 5:15 ` [PATCH 19/21] powerpc: Merge creation of signal frame Benjamin Herrenschmidt
@ 2007-06-04 7:22 ` Benjamin Herrenschmidt
2007-06-04 8:01 ` Christoph Hellwig
0 siblings, 1 reply; 30+ messages in thread
From: Benjamin Herrenschmidt @ 2007-06-04 7:22 UTC (permalink / raw)
To: linuxppc-dev; +Cc: Paul Mackerras, Christoph Hellwig, cbe-oss-dev
powerpc: Merge creation of signal frame
The code for creating signal frames was still duplicated and split
in strange ways between 32 and 64 bits, including the SA_ONSTACK
handling being in do_signal on 32 bits but inside handle_rt_signal
on 64 bits etc...
This moves the 64 bits get_sigframe() to the generic signal.c,
cleans it a bit, moves the access_ok() call done by all callers to
it as well, and adapts/cleanups the 3 different signal handling cases
to use that common function.
Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
---
This one actually works :-)
Index: linux-cell/arch/powerpc/kernel/signal.c
===================================================================
--- linux-cell.orig/arch/powerpc/kernel/signal.c 2007-06-04 16:58:04.000000000 +1000
+++ linux-cell/arch/powerpc/kernel/signal.c 2007-06-04 17:06:29.000000000 +1000
@@ -11,6 +11,7 @@
#include <linux/ptrace.h>
#include <linux/signal.h>
+#include <asm/uaccess.h>
#include "signal.h"
@@ -27,6 +28,32 @@ static inline int is_32bit_task(void)
}
#endif
+/*
+ * Allocate space for the signal frame
+ */
+void __user * get_sigframe(struct k_sigaction *ka, struct pt_regs *regs,
+ size_t frame_size)
+{
+ unsigned long oldsp, newsp;
+
+ /* Default to using normal stack */
+ oldsp = regs->gpr[1];
+
+ /* Check for alt stack */
+ if ((ka->sa.sa_flags & SA_ONSTACK) &&
+ current->sas_ss_size && !on_sig_stack(oldsp))
+ oldsp = (current->sas_ss_sp + current->sas_ss_size);
+
+ /* Get aligned frame */
+ newsp = (oldsp - frame_size) & ~0xFUL;
+
+ /* Check access */
+ if (!access_ok(VERIFY_WRITE, (void __user *)newsp, oldsp - newsp))
+ return NULL;
+
+ return (void __user *)newsp;
+}
+
/*
* Restore the user process's signal mask
@@ -129,20 +156,12 @@ int do_signal(sigset_t *oldset, struct p
#endif
if (is32) {
- unsigned int newsp;
-
- if ((ka.sa.sa_flags & SA_ONSTACK) &&
- current->sas_ss_size && !on_sig_stack(regs->gpr[1]))
- newsp = current->sas_ss_sp + current->sas_ss_size;
- else
- newsp = regs->gpr[1];
-
if (ka.sa.sa_flags & SA_SIGINFO)
ret = handle_rt_signal32(signr, &ka, &info, oldset,
- regs, newsp);
+ regs);
else
ret = handle_signal32(signr, &ka, &info, oldset,
- regs, newsp);
+ regs);
#ifdef CONFIG_PPC64
} else {
ret = handle_rt_signal64(signr, &ka, &info, oldset, regs);
Index: linux-cell/arch/powerpc/kernel/signal.h
===================================================================
--- linux-cell.orig/arch/powerpc/kernel/signal.h 2007-06-04 16:58:04.000000000 +1000
+++ linux-cell/arch/powerpc/kernel/signal.h 2007-06-04 17:03:20.000000000 +1000
@@ -12,15 +12,17 @@
#define _BLOCKABLE (~(sigmask(SIGKILL) | sigmask(SIGSTOP)))
+extern void __user * get_sigframe(struct k_sigaction *ka, struct pt_regs *regs,
+ size_t frame_size);
extern void restore_sigmask(sigset_t *set);
extern int handle_signal32(unsigned long sig, struct k_sigaction *ka,
siginfo_t *info, sigset_t *oldset,
- struct pt_regs *regs, unsigned long newsp);
+ struct pt_regs *regs);
extern int handle_rt_signal32(unsigned long sig, struct k_sigaction *ka,
siginfo_t *info, sigset_t *oldset,
- struct pt_regs *regs, unsigned long newsp);
+ struct pt_regs *regs);
extern int handle_rt_signal64(int signr, struct k_sigaction *ka,
siginfo_t *info, sigset_t *set,
Index: linux-cell/arch/powerpc/kernel/signal_32.c
===================================================================
--- linux-cell.orig/arch/powerpc/kernel/signal_32.c 2007-06-04 16:58:04.000000000 +1000
+++ linux-cell/arch/powerpc/kernel/signal_32.c 2007-06-04 17:14:20.000000000 +1000
@@ -282,14 +282,17 @@ long sys_sigaction(int sig, struct old_s
/*
* When we have signals to deliver, we set up on the
* user stack, going down from the original stack pointer:
- * a sigregs struct
+ * an ABI gap of 56 words
+ * an mcontext struct
* a sigcontext struct
* a gap of __SIGNAL_FRAMESIZE bytes
*
- * Each of these things must be a multiple of 16 bytes in size.
+ * Each of these things must be a multiple of 16 bytes in size. The following
+ * structure represent all of this except the __SIGNAL_FRAMESIZE gap
*
*/
-struct sigregs {
+struct sigframe {
+ struct sigcontext sctx; /* the sigcontext */
struct mcontext mctx; /* all the register values */
/*
* Programs using the rs6000/xcoff abi can save up to 19 gp
@@ -698,21 +701,16 @@ int compat_sys_sigaltstack(u32 __new, u3
*/
int handle_rt_signal32(unsigned long sig, struct k_sigaction *ka,
siginfo_t *info, sigset_t *oldset,
- struct pt_regs *regs, unsigned long newsp)
+ struct pt_regs *regs)
{
struct rt_sigframe __user *rt_sf;
struct mcontext __user *frame;
- unsigned long origsp = newsp;
+ unsigned long newsp = 0;
/* Set up Signal Frame */
/* Put a Real Time Context onto stack */
- newsp -= sizeof(*rt_sf);
- rt_sf = (struct rt_sigframe __user *)newsp;
-
- /* create a stack frame for the caller of the handler */
- newsp -= __SIGNAL_FRAMESIZE + 16;
-
- if (!access_ok(VERIFY_WRITE, (void __user *)newsp, origsp - newsp))
+ rt_sf = get_sigframe(ka, regs, sizeof(*rt_sf));
+ if (unlikely(rt_sf == NULL))
goto badframe;
/* Put the siginfo & fill in most of the ucontext */
@@ -742,8 +740,12 @@ int handle_rt_signal32(unsigned long sig
current->thread.fpscr.val = 0; /* turn off all fp exceptions */
+ /* create a stack frame for the caller of the handler */
+ newsp = ((unsigned long)rt_sf) - (__SIGNAL_FRAMESIZE + 16);
if (put_user(regs->gpr[1], (u32 __user *)newsp))
goto badframe;
+
+ /* Fill registers for signal handler */
regs->gpr[1] = newsp;
regs->gpr[3] = sig;
regs->gpr[4] = (unsigned long) &rt_sf->info;
@@ -988,26 +990,17 @@ int sys_debug_setcontext(struct ucontext
* OK, we're invoking a handler
*/
int handle_signal32(unsigned long sig, struct k_sigaction *ka,
- siginfo_t *info, sigset_t *oldset, struct pt_regs *regs,
- unsigned long newsp)
+ siginfo_t *info, sigset_t *oldset, struct pt_regs *regs)
{
struct sigcontext __user *sc;
- struct sigregs __user *frame;
- unsigned long origsp = newsp;
+ struct sigframe __user *frame;
+ unsigned long newsp = 0;
/* Set up Signal Frame */
- newsp -= sizeof(struct sigregs);
- frame = (struct sigregs __user *) newsp;
-
- /* Put a sigcontext on the stack */
- newsp -= sizeof(*sc);
- sc = (struct sigcontext __user *) newsp;
-
- /* create a stack frame for the caller of the handler */
- newsp -= __SIGNAL_FRAMESIZE;
-
- if (!access_ok(VERIFY_WRITE, (void __user *) newsp, origsp - newsp))
+ frame = get_sigframe(ka, regs, sizeof(*frame));
+ if (unlikely(frame == NULL))
goto badframe;
+ sc = (struct sigcontext __user *) &frame->sctx;
#if _NSIG != 64
#error "Please adjust handle_signal()"
@@ -1019,7 +1012,7 @@ int handle_signal32(unsigned long sig, s
#else
|| __put_user(oldset->sig[1], &sc->_unused[3])
#endif
- || __put_user(to_user_ptr(frame), &sc->regs)
+ || __put_user(to_user_ptr(&frame->mctx), &sc->regs)
|| __put_user(sig, &sc->signal))
goto badframe;
@@ -1035,8 +1028,11 @@ int handle_signal32(unsigned long sig, s
current->thread.fpscr.val = 0; /* turn off all fp exceptions */
+ /* create a stack frame for the caller of the handler */
+ newsp = ((unsigned long)frame) - __SIGNAL_FRAMESIZE;
if (put_user(regs->gpr[1], (u32 __user *)newsp))
goto badframe;
+
regs->gpr[1] = newsp;
regs->gpr[3] = sig;
regs->gpr[4] = (unsigned long) sc;
Index: linux-cell/arch/powerpc/kernel/signal_64.c
===================================================================
--- linux-cell.orig/arch/powerpc/kernel/signal_64.c 2007-06-04 16:58:04.000000000 +1000
+++ linux-cell/arch/powerpc/kernel/signal_64.c 2007-06-04 17:22:10.000000000 +1000
@@ -196,25 +196,6 @@ static long restore_sigcontext(struct pt
}
/*
- * Allocate space for the signal frame
- */
-static inline void __user * get_sigframe(struct k_sigaction *ka, struct pt_regs *regs,
- size_t frame_size)
-{
- unsigned long newsp;
-
- /* Default to using normal stack */
- newsp = regs->gpr[1];
-
- if ((ka->sa.sa_flags & SA_ONSTACK) && current->sas_ss_size) {
- if (! on_sig_stack(regs->gpr[1]))
- newsp = (current->sas_ss_sp + current->sas_ss_size);
- }
-
- return (void __user *)((newsp - frame_size) & -16ul);
-}
-
-/*
* Setup the trampoline code on the stack
*/
static long setup_trampoline(unsigned int syscall, unsigned int __user *tramp)
@@ -348,8 +329,7 @@ int handle_rt_signal64(int signr, struct
long err = 0;
frame = get_sigframe(ka, regs, sizeof(*frame));
-
- if (!access_ok(VERIFY_WRITE, frame, sizeof(*frame)))
+ if (unlikely(frame == NULL))
goto badframe;
err |= __put_user(&frame->info, &frame->pinfo);
@@ -386,7 +366,7 @@ int handle_rt_signal64(int signr, struct
funct_desc_ptr = (func_descr_t __user *) ka->sa.sa_handler;
/* Allocate a dummy caller frame for the signal handler. */
- newsp = (unsigned long)frame - __SIGNAL_FRAMESIZE;
+ newsp = ((unsigned long)frame) - __SIGNAL_FRAMESIZE;
err |= put_user(regs->gpr[1], (unsigned long __user *)newsp);
/* Set up "regs" so we "return" to the signal handler. */
^ permalink raw reply [flat|nested] 30+ messages in thread
* Re: PATCH 19/21] powerpc: Merge creation of signal frame (#2)
2007-06-04 7:22 ` PATCH 19/21] powerpc: Merge creation of signal frame (#2) Benjamin Herrenschmidt
@ 2007-06-04 8:01 ` Christoph Hellwig
2007-06-04 10:04 ` Benjamin Herrenschmidt
0 siblings, 1 reply; 30+ messages in thread
From: Christoph Hellwig @ 2007-06-04 8:01 UTC (permalink / raw)
To: Benjamin Herrenschmidt
Cc: linuxppc-dev, Paul Mackerras, Christoph Hellwig, cbe-oss-dev
On Mon, Jun 04, 2007 at 05:22:48PM +1000, Benjamin Herrenschmidt wrote:
> +/*
> + * Allocate space for the signal frame
> + */
> +void __user * get_sigframe(struct k_sigaction *ka, struct pt_regs *regs,
> + size_t frame_size)
little style nitpick: no whitespace after the *, please.
> +{
> + unsigned long oldsp, newsp;
> +
> + /* Default to using normal stack */
> + oldsp = regs->gpr[1];
> +
> + /* Check for alt stack */
> + if ((ka->sa.sa_flags & SA_ONSTACK) &&
> + current->sas_ss_size && !on_sig_stack(oldsp))
> + oldsp = (current->sas_ss_sp + current->sas_ss_size);
> +
> + /* Get aligned frame */
> + newsp = (oldsp - frame_size) & ~0xFUL;
> +
> + /* Check access */
> + if (!access_ok(VERIFY_WRITE, (void __user *)newsp, oldsp - newsp))
> + return NULL;
> +
> + return (void __user *)newsp;
> +}
The body also has some odd whitespace problems. I'd also make
newsp a void __user variable to only do the cast once. In the end the
function should looks something like:
void __user *get_sigframe(struct k_sigaction *ka, struct pt_regs *regs,
size_t frame_size)
{
unsigned long oldsp;
void __user *newsp;
/* Check for alt stack */
if ((ka->sa.sa_flags & SA_ONSTACK) &&
current->sas_ss_size && !on_sig_stack(oldsp))
oldsp = (current->sas_ss_sp + current->sas_ss_size);
else
oldsp = regs->gpr[1];
/* Get aligned frame */
newsp = (void __user *)((oldsp - frame_size) & ~0xFUL);
/* Check access */
if (!access_ok(VERIFY_WRITE, newsp, oldsp - newsp))
return NULL;
return newsp;
}
^ permalink raw reply [flat|nested] 30+ messages in thread
* Re: PATCH 19/21] powerpc: Merge creation of signal frame (#2)
2007-06-04 8:01 ` Christoph Hellwig
@ 2007-06-04 10:04 ` Benjamin Herrenschmidt
0 siblings, 0 replies; 30+ messages in thread
From: Benjamin Herrenschmidt @ 2007-06-04 10:04 UTC (permalink / raw)
To: Christoph Hellwig; +Cc: linuxppc-dev, Paul Mackerras, cbe-oss-dev
On Mon, 2007-06-04 at 10:01 +0200, Christoph Hellwig wrote:
> On Mon, Jun 04, 2007 at 05:22:48PM +1000, Benjamin Herrenschmidt wrote:
> > +/*
> > + * Allocate space for the signal frame
> > + */
> > +void __user * get_sigframe(struct k_sigaction *ka, struct pt_regs *regs,
> > + size_t frame_size)
>
> little style nitpick: no whitespace after the *, please.
Heh... just copy pasted what was there :-) I'll rip it out for the next
round :-)
> > +{
> > + unsigned long oldsp, newsp;
> > +
> > + /* Default to using normal stack */
> > + oldsp = regs->gpr[1];
> > +
> > + /* Check for alt stack */
> > + if ((ka->sa.sa_flags & SA_ONSTACK) &&
> > + current->sas_ss_size && !on_sig_stack(oldsp))
> > + oldsp = (current->sas_ss_sp + current->sas_ss_size);
> > +
> > + /* Get aligned frame */
> > + newsp = (oldsp - frame_size) & ~0xFUL;
> > +
> > + /* Check access */
> > + if (!access_ok(VERIFY_WRITE, (void __user *)newsp, oldsp - newsp))
> > + return NULL;
> > +
> > + return (void __user *)newsp;
> > +}
>
> The body also has some odd whitespace problems. I'd also make
> newsp a void __user variable to only do the cast once. In the end the
> function should looks something like:
Makes sense.
Thanks,
Ben.
^ permalink raw reply [flat|nested] 30+ messages in thread
* Re: [PATCH 3/21] spufs: Add support for SPU single stepping
2007-06-04 5:15 ` [PATCH 3/21] spufs: Add support for SPU single stepping Benjamin Herrenschmidt
@ 2007-06-04 13:06 ` Jeremy Kerr
0 siblings, 0 replies; 30+ messages in thread
From: Jeremy Kerr @ 2007-06-04 13:06 UTC (permalink / raw)
To: linuxppc-dev; +Cc: Paul Mackerras, Christoph Hellwig, cbe-oss-dev
> This patch adds support for SPU single stepping. The single
> step bit is set in the SPU when the current process is
> being single-stepped via ptrace. The spu then stops and
> returns with a specific flag set and the syscall exit code
> will generate the SIGTRAP.
Acked-by: Jeremy Kerr <jk@ozlabs.org>
Cheers,
Jeremy
^ permalink raw reply [flat|nested] 30+ messages in thread
* Re: [PATCH 4/21] spufs: Add a "capabilities" file to spu contexts
2007-06-04 5:15 ` [PATCH 4/21] spufs: Add a "capabilities" file to spu contexts Benjamin Herrenschmidt
@ 2007-06-04 13:06 ` Jeremy Kerr
0 siblings, 0 replies; 30+ messages in thread
From: Jeremy Kerr @ 2007-06-04 13:06 UTC (permalink / raw)
To: linuxppc-dev; +Cc: Paul Mackerras, Christoph Hellwig, cbe-oss-dev
Ben,
> This adds a "capabilities" file to spu contexts consisting of a
> list of linefeed separated capability names. The current exposed
> capabilities are "sched" (the context is scheduleable) and
> "step" (the context supports single stepping).
Looks good.
Acked-by: Jeremy Kerr <jk@ozlabs.org>
Jeremy
^ permalink raw reply [flat|nested] 30+ messages in thread
end of thread, other threads:[~2007-06-04 13:06 UTC | newest]
Thread overview: 30+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2007-06-04 5:15 [PATCH 0/21] This is my pending series for 2.6.23 Benjamin Herrenschmidt
2007-06-04 5:15 ` [PATCH 1/21] unmap_vm_area becomes unmap_kernel_range for the public Benjamin Herrenschmidt
2007-06-04 5:15 ` [PATCH 2/21] powerpc: Rewrite IO allocation & mapping on powerpc64 Benjamin Herrenschmidt
2007-06-04 5:15 ` [PATCH 3/21] spufs: Add support for SPU single stepping Benjamin Herrenschmidt
2007-06-04 13:06 ` Jeremy Kerr
2007-06-04 5:15 ` [PATCH 4/21] spufs: Add a "capabilities" file to spu contexts Benjamin Herrenschmidt
2007-06-04 13:06 ` Jeremy Kerr
2007-06-04 5:15 ` [PATCH 5/21] powerpc: Disable broken PPC_PTRACE_GETFPREGS on 32 bits Benjamin Herrenschmidt
2007-06-04 5:15 ` [PATCH 6/21] powerpc: ptrace cleanups Benjamin Herrenschmidt
2007-06-04 5:15 ` [PATCH 7/21] powerpc: ptrace updates & new better requests Benjamin Herrenschmidt
2007-06-04 5:15 ` [PATCH 8/21] powerpc: uninline common ptrace bits Benjamin Herrenschmidt
2007-06-04 5:15 ` [PATCH 9/21] powerpc: remove some useless ifdef's in ptrace Benjamin Herrenschmidt
2007-06-04 5:15 ` [PATCH 10/21] powerpc: Allow ptrace write to pt_regs trap and orig_r3 Benjamin Herrenschmidt
2007-06-04 5:15 ` [PATCH 11/21] powerpc: ptrace shouldn't touch FP exec mode Benjamin Herrenschmidt
2007-06-04 5:15 ` [PATCH 12/21] powerpc: ptrace can set DABR on both 32 and 64 bits Benjamin Herrenschmidt
2007-06-04 5:15 ` [PATCH 13/21] powerpc: Always apply DABR changes on context switches Benjamin Herrenschmidt
2007-06-04 5:15 ` [PATCH 14/21] powerpc: Make syscall restart code more common Benjamin Herrenschmidt
2007-06-04 7:06 ` Christoph Hellwig
2007-06-04 5:15 ` [PATCH 15/21] powerpc: consolidate sys_sigaltstack Benjamin Herrenschmidt
2007-06-04 5:15 ` [PATCH 16/21] powerpc: consolidate restore_sigmask Benjamin Herrenschmidt
2007-06-04 5:15 ` [PATCH 17/21] powerpc: consolidate do_signal Benjamin Herrenschmidt
2007-06-04 5:15 ` [PATCH 18/21] powerpc: Remove obsolete freezer bits Benjamin Herrenschmidt
2007-06-04 5:15 ` [PATCH 19/21] powerpc: Merge creation of signal frame Benjamin Herrenschmidt
2007-06-04 7:22 ` PATCH 19/21] powerpc: Merge creation of signal frame (#2) Benjamin Herrenschmidt
2007-06-04 8:01 ` Christoph Hellwig
2007-06-04 10:04 ` Benjamin Herrenschmidt
2007-06-04 5:15 ` [PATCH 20/21] powerpc: remove #ifdef around set_dabr in signal code Benjamin Herrenschmidt
2007-06-04 5:15 ` [PATCH 21/21] powerpc: Less ifdef's in signal.c/signal.h Benjamin Herrenschmidt
2007-06-04 7:00 ` [PATCH 0/21] This is my pending series for 2.6.23 Benjamin Herrenschmidt
2007-06-04 7:21 ` Benjamin Herrenschmidt
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).