Merge git://git.kernel.org/pub/scm/linux/kernel/git/cmetcalf/linux-tile
authorLinus Torvalds <torvalds@linux-foundation.org>
Tue, 18 Dec 2012 23:05:30 +0000 (15:05 -0800)
committerLinus Torvalds <torvalds@linux-foundation.org>
Tue, 18 Dec 2012 23:05:30 +0000 (15:05 -0800)
Pull tile updates from Chris Metcalf:
 "These are a smattering of minor changes from Tilera and other folks,
  mostly in the ptrace area."

* git://git.kernel.org/pub/scm/linux/kernel/git/cmetcalf/linux-tile:
  arch/tile: set CORE_DUMP_USE_REGSET on tile
  arch/tile: implement arch_ptrace using user_regset on tile
  arch/tile: implement user_regset interface on tile
  arch/tile: clean up tile-specific PTRACE_SETOPTIONS
  arch/tile: provide PT_FLAGS_COMPAT value in pt_regs
  tile/PCI: use for_each_pci_dev to simplify the code
  tilegx: remove __init from pci fixup hook

arch/tile/include/asm/elf.h
arch/tile/include/asm/ptrace.h
arch/tile/include/uapi/asm/ptrace.h
arch/tile/kernel/pci.c
arch/tile/kernel/pci_gx.c
arch/tile/kernel/ptrace.c

index b73e103..ff8a934 100644 (file)
@@ -170,4 +170,6 @@ do { \
 
 #endif /* CONFIG_COMPAT */
 
+#define CORE_DUMP_USE_REGSET
+
 #endif /* _ASM_TILE_ELF_H */
index 1a4fd9a..5ce052e 100644 (file)
@@ -24,8 +24,7 @@ typedef unsigned long pt_reg_t;
 #include <uapi/asm/ptrace.h>
 
 #define PTRACE_O_MASK_TILE     (PTRACE_O_TRACEMIGRATE)
-#define PT_TRACE_MIGRATE       0x00080000
-#define PT_TRACE_MASK_TILE     (PT_TRACE_MIGRATE)
+#define PT_TRACE_MIGRATE       PT_EVENT_FLAG(PTRACE_EVENT_MIGRATE)
 
 /* Flag bits in pt_regs.flags */
 #define PT_FLAGS_DISABLE_IRQ    1  /* on return to kernel, disable irqs */
index c717d0f..7757e19 100644 (file)
@@ -81,8 +81,14 @@ struct pt_regs {
 #define PTRACE_SETFPREGS       15
 
 /* Support TILE-specific ptrace options, with events starting at 16. */
-#define PTRACE_O_TRACEMIGRATE  0x00010000
 #define PTRACE_EVENT_MIGRATE   16
+#define PTRACE_O_TRACEMIGRATE  (1 << PTRACE_EVENT_MIGRATE)
 
+/*
+ * Flag bits in pt_regs.flags that are part of the ptrace API.
+ * We start our numbering higher up to avoid confusion with the
+ * non-ABI kernel-internal values that use the low 16 bits.
+ */
+#define PT_FLAGS_COMPAT                0x10000  /* process is an -m32 compat process */
 
 #endif /* _UAPI_ASM_TILE_PTRACE_H */
index 7598226..aac1cd5 100644 (file)
@@ -245,7 +245,7 @@ static void __devinit fixup_read_and_payload_sizes(void)
        u16 new_values;
 
        /* Scan for the smallest maximum payload size. */
-       while ((dev = pci_get_device(PCI_ANY_ID, PCI_ANY_ID, dev)) != NULL) {
+       for_each_pci_dev(dev) {
                u32 devcap;
                int max_payload;
 
@@ -260,7 +260,7 @@ static void __devinit fixup_read_and_payload_sizes(void)
 
        /* Now, set the max_payload_size for all devices to that value. */
        new_values = (max_read_size << 12) | (smallest_max_payload << 5);
-       while ((dev = pci_get_device(PCI_ANY_ID, PCI_ANY_ID, dev)) != NULL)
+       for_each_pci_dev(dev)
                pcie_capability_clear_and_set_word(dev, PCI_EXP_DEVCTL,
                                PCI_EXP_DEVCTL_PAYLOAD | PCI_EXP_DEVCTL_READRQ,
                                new_values);
index 2ba6d05..94810d4 100644 (file)
@@ -1047,8 +1047,7 @@ int pcibios_enable_device(struct pci_dev *dev, int mask)
 }
 
 /* Called for each device after PCI setup is done. */
-static void __init
-pcibios_fixup_final(struct pci_dev *pdev)
+static void pcibios_fixup_final(struct pci_dev *pdev)
 {
        set_dma_ops(&pdev->dev, gx_pci_dma_map_ops);
        set_dma_offset(&pdev->dev, TILE_PCI_MEM_MAP_BASE_OFFSET);
index e92e405..9835312 100644 (file)
 #include <linux/kprobes.h>
 #include <linux/compat.h>
 #include <linux/uaccess.h>
+#include <linux/regset.h>
+#include <linux/elf.h>
 #include <asm/traps.h>
+#include <arch/chip.h>
 
 void user_enable_single_step(struct task_struct *child)
 {
@@ -45,6 +48,100 @@ void ptrace_disable(struct task_struct *child)
        clear_tsk_thread_flag(child, TIF_SYSCALL_TRACE);
 }
 
+/*
+ * Get registers from task and ready the result for userspace.
+ * Note that we localize the API issues to getregs() and putregs() at
+ * some cost in performance, e.g. we need a full pt_regs copy for
+ * PEEKUSR, and two copies for POKEUSR.  But in general we expect
+ * GETREGS/PUTREGS to be the API of choice anyway.
+ */
+static char *getregs(struct task_struct *child, struct pt_regs *uregs)
+{
+       *uregs = *task_pt_regs(child);
+
+       /* Set up flags ABI bits. */
+       uregs->flags = 0;
+#ifdef CONFIG_COMPAT
+       if (task_thread_info(child)->status & TS_COMPAT)
+               uregs->flags |= PT_FLAGS_COMPAT;
+#endif
+
+       return (char *)uregs;
+}
+
+/* Put registers back to task. */
+static void putregs(struct task_struct *child, struct pt_regs *uregs)
+{
+       struct pt_regs *regs = task_pt_regs(child);
+
+       /* Don't allow overwriting the kernel-internal flags word. */
+       uregs->flags = regs->flags;
+
+       /* Only allow setting the ICS bit in the ex1 word. */
+       uregs->ex1 = PL_ICS_EX1(USER_PL, EX1_ICS(uregs->ex1));
+
+       *regs = *uregs;
+}
+
+enum tile_regset {
+       REGSET_GPR,
+};
+
+static int tile_gpr_get(struct task_struct *target,
+                         const struct user_regset *regset,
+                         unsigned int pos, unsigned int count,
+                         void *kbuf, void __user *ubuf)
+{
+       struct pt_regs regs;
+
+       getregs(target, &regs);
+
+       return user_regset_copyout(&pos, &count, &kbuf, &ubuf, &regs, 0,
+                                  sizeof(regs));
+}
+
+static int tile_gpr_set(struct task_struct *target,
+                         const struct user_regset *regset,
+                         unsigned int pos, unsigned int count,
+                         const void *kbuf, const void __user *ubuf)
+{
+       int ret;
+       struct pt_regs regs;
+
+       ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf, &regs, 0,
+                                sizeof(regs));
+       if (ret)
+               return ret;
+
+       putregs(target, &regs);
+
+       return 0;
+}
+
+static const struct user_regset tile_user_regset[] = {
+       [REGSET_GPR] = {
+               .core_note_type = NT_PRSTATUS,
+               .n = ELF_NGREG,
+               .size = sizeof(elf_greg_t),
+               .align = sizeof(elf_greg_t),
+               .get = tile_gpr_get,
+               .set = tile_gpr_set,
+       },
+};
+
+static const struct user_regset_view tile_user_regset_view = {
+       .name = CHIP_ARCH_NAME,
+       .e_machine = ELF_ARCH,
+       .ei_osabi = ELF_OSABI,
+       .regsets = tile_user_regset,
+       .n = ARRAY_SIZE(tile_user_regset),
+};
+
+const struct user_regset_view *task_user_regset_view(struct task_struct *task)
+{
+       return &tile_user_regset_view;
+}
+
 long arch_ptrace(struct task_struct *child, long request,
                 unsigned long addr, unsigned long data)
 {
@@ -53,14 +150,13 @@ long arch_ptrace(struct task_struct *child, long request,
        long ret = -EIO;
        char *childreg;
        struct pt_regs copyregs;
-       int ex1_offset;
 
        switch (request) {
 
        case PTRACE_PEEKUSR:  /* Read register from pt_regs. */
                if (addr >= PTREGS_SIZE)
                        break;
-               childreg = (char *)task_pt_regs(child) + addr;
+               childreg = getregs(child, &copyregs) + addr;
 #ifdef CONFIG_COMPAT
                if (is_compat_task()) {
                        if (addr & (sizeof(compat_long_t)-1))
@@ -79,17 +175,7 @@ long arch_ptrace(struct task_struct *child, long request,
        case PTRACE_POKEUSR:  /* Write register in pt_regs. */
                if (addr >= PTREGS_SIZE)
                        break;
-               childreg = (char *)task_pt_regs(child) + addr;
-
-               /* Guard against overwrites of the privilege level. */
-               ex1_offset = PTREGS_OFFSET_EX1;
-#if defined(CONFIG_COMPAT) && defined(__BIG_ENDIAN)
-               if (is_compat_task())   /* point at low word */
-                       ex1_offset += sizeof(compat_long_t);
-#endif
-               if (addr == ex1_offset)
-                       data = PL_ICS_EX1(USER_PL, EX1_ICS(data));
-
+               childreg = getregs(child, &copyregs) + addr;
 #ifdef CONFIG_COMPAT
                if (is_compat_task()) {
                        if (addr & (sizeof(compat_long_t)-1))
@@ -102,24 +188,20 @@ long arch_ptrace(struct task_struct *child, long request,
                                break;
                        *(long *)childreg = data;
                }
+               putregs(child, &copyregs);
                ret = 0;
                break;
 
        case PTRACE_GETREGS:  /* Get all registers from the child. */
-               if (copy_to_user(datap, task_pt_regs(child),
-                                sizeof(struct pt_regs)) == 0) {
-                       ret = 0;
-               }
+               ret = copy_regset_to_user(child, &tile_user_regset_view,
+                                         REGSET_GPR, 0,
+                                         sizeof(struct pt_regs), datap);
                break;
 
        case PTRACE_SETREGS:  /* Set all registers in the child. */
-               if (copy_from_user(&copyregs, datap,
-                                  sizeof(struct pt_regs)) == 0) {
-                       copyregs.ex1 =
-                               PL_ICS_EX1(USER_PL, EX1_ICS(copyregs.ex1));
-                       *task_pt_regs(child) = copyregs;
-                       ret = 0;
-               }
+               ret = copy_regset_from_user(child, &tile_user_regset_view,
+                                           REGSET_GPR, 0,
+                                           sizeof(struct pt_regs), datap);
                break;
 
        case PTRACE_GETFPREGS:  /* Get the child FPU state. */
@@ -128,12 +210,16 @@ long arch_ptrace(struct task_struct *child, long request,
 
        case PTRACE_SETOPTIONS:
                /* Support TILE-specific ptrace options. */
-               child->ptrace &= ~PT_TRACE_MASK_TILE;
+               BUILD_BUG_ON(PTRACE_O_MASK_TILE & PTRACE_O_MASK);
                tmp = data & PTRACE_O_MASK_TILE;
                data &= ~PTRACE_O_MASK_TILE;
                ret = ptrace_request(child, request, addr, data);
-               if (tmp & PTRACE_O_TRACEMIGRATE)
-                       child->ptrace |= PT_TRACE_MIGRATE;
+               if (ret == 0) {
+                       unsigned int flags = child->ptrace;
+                       flags &= ~(PTRACE_O_MASK_TILE << PT_OPT_FLAG_SHIFT);
+                       flags |= (tmp << PT_OPT_FLAG_SHIFT);
+                       child->ptrace = flags;
+               }
                break;
 
        default: