diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2012-12-18 18:05:30 -0500 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2012-12-18 18:05:30 -0500 |
commit | 5b3040a48bc9b916dc318bde33c9ebd98f00fbeb (patch) | |
tree | 3762a11cb024c1197e07046d60af0b93d3a541ff /arch/tile | |
parent | 31564cbd77baa88405862d4aa0d00893ab1d8cb7 (diff) | |
parent | e6cdebdf5aeccb5cbcf81e5e2764ad28a80f3185 (diff) |
Merge git://git.kernel.org/pub/scm/linux/kernel/git/cmetcalf/linux-tile
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
Diffstat (limited to 'arch/tile')
-rw-r--r-- | arch/tile/include/asm/elf.h | 2 | ||||
-rw-r--r-- | arch/tile/include/asm/ptrace.h | 3 | ||||
-rw-r--r-- | arch/tile/include/uapi/asm/ptrace.h | 8 | ||||
-rw-r--r-- | arch/tile/kernel/pci.c | 4 | ||||
-rw-r--r-- | arch/tile/kernel/pci_gx.c | 3 | ||||
-rw-r--r-- | arch/tile/kernel/ptrace.c | 140 |
6 files changed, 126 insertions, 34 deletions
diff --git a/arch/tile/include/asm/elf.h b/arch/tile/include/asm/elf.h index b73e1039c911..ff8a93408823 100644 --- a/arch/tile/include/asm/elf.h +++ b/arch/tile/include/asm/elf.h | |||
@@ -170,4 +170,6 @@ do { \ | |||
170 | 170 | ||
171 | #endif /* CONFIG_COMPAT */ | 171 | #endif /* CONFIG_COMPAT */ |
172 | 172 | ||
173 | #define CORE_DUMP_USE_REGSET | ||
174 | |||
173 | #endif /* _ASM_TILE_ELF_H */ | 175 | #endif /* _ASM_TILE_ELF_H */ |
diff --git a/arch/tile/include/asm/ptrace.h b/arch/tile/include/asm/ptrace.h index 1a4fd9ab0ee1..5ce052e16b7b 100644 --- a/arch/tile/include/asm/ptrace.h +++ b/arch/tile/include/asm/ptrace.h | |||
@@ -24,8 +24,7 @@ typedef unsigned long pt_reg_t; | |||
24 | #include <uapi/asm/ptrace.h> | 24 | #include <uapi/asm/ptrace.h> |
25 | 25 | ||
26 | #define PTRACE_O_MASK_TILE (PTRACE_O_TRACEMIGRATE) | 26 | #define PTRACE_O_MASK_TILE (PTRACE_O_TRACEMIGRATE) |
27 | #define PT_TRACE_MIGRATE 0x00080000 | 27 | #define PT_TRACE_MIGRATE PT_EVENT_FLAG(PTRACE_EVENT_MIGRATE) |
28 | #define PT_TRACE_MASK_TILE (PT_TRACE_MIGRATE) | ||
29 | 28 | ||
30 | /* Flag bits in pt_regs.flags */ | 29 | /* Flag bits in pt_regs.flags */ |
31 | #define PT_FLAGS_DISABLE_IRQ 1 /* on return to kernel, disable irqs */ | 30 | #define PT_FLAGS_DISABLE_IRQ 1 /* on return to kernel, disable irqs */ |
diff --git a/arch/tile/include/uapi/asm/ptrace.h b/arch/tile/include/uapi/asm/ptrace.h index c717d0fec72e..7757e1985fb6 100644 --- a/arch/tile/include/uapi/asm/ptrace.h +++ b/arch/tile/include/uapi/asm/ptrace.h | |||
@@ -81,8 +81,14 @@ struct pt_regs { | |||
81 | #define PTRACE_SETFPREGS 15 | 81 | #define PTRACE_SETFPREGS 15 |
82 | 82 | ||
83 | /* Support TILE-specific ptrace options, with events starting at 16. */ | 83 | /* Support TILE-specific ptrace options, with events starting at 16. */ |
84 | #define PTRACE_O_TRACEMIGRATE 0x00010000 | ||
85 | #define PTRACE_EVENT_MIGRATE 16 | 84 | #define PTRACE_EVENT_MIGRATE 16 |
85 | #define PTRACE_O_TRACEMIGRATE (1 << PTRACE_EVENT_MIGRATE) | ||
86 | 86 | ||
87 | /* | ||
88 | * Flag bits in pt_regs.flags that are part of the ptrace API. | ||
89 | * We start our numbering higher up to avoid confusion with the | ||
90 | * non-ABI kernel-internal values that use the low 16 bits. | ||
91 | */ | ||
92 | #define PT_FLAGS_COMPAT 0x10000 /* process is an -m32 compat process */ | ||
87 | 93 | ||
88 | #endif /* _UAPI_ASM_TILE_PTRACE_H */ | 94 | #endif /* _UAPI_ASM_TILE_PTRACE_H */ |
diff --git a/arch/tile/kernel/pci.c b/arch/tile/kernel/pci.c index 759822687e8f..aac1cd586966 100644 --- a/arch/tile/kernel/pci.c +++ b/arch/tile/kernel/pci.c | |||
@@ -245,7 +245,7 @@ static void __devinit fixup_read_and_payload_sizes(void) | |||
245 | u16 new_values; | 245 | u16 new_values; |
246 | 246 | ||
247 | /* Scan for the smallest maximum payload size. */ | 247 | /* Scan for the smallest maximum payload size. */ |
248 | while ((dev = pci_get_device(PCI_ANY_ID, PCI_ANY_ID, dev)) != NULL) { | 248 | for_each_pci_dev(dev) { |
249 | u32 devcap; | 249 | u32 devcap; |
250 | int max_payload; | 250 | int max_payload; |
251 | 251 | ||
@@ -260,7 +260,7 @@ static void __devinit fixup_read_and_payload_sizes(void) | |||
260 | 260 | ||
261 | /* Now, set the max_payload_size for all devices to that value. */ | 261 | /* Now, set the max_payload_size for all devices to that value. */ |
262 | new_values = (max_read_size << 12) | (smallest_max_payload << 5); | 262 | new_values = (max_read_size << 12) | (smallest_max_payload << 5); |
263 | while ((dev = pci_get_device(PCI_ANY_ID, PCI_ANY_ID, dev)) != NULL) | 263 | for_each_pci_dev(dev) |
264 | pcie_capability_clear_and_set_word(dev, PCI_EXP_DEVCTL, | 264 | pcie_capability_clear_and_set_word(dev, PCI_EXP_DEVCTL, |
265 | PCI_EXP_DEVCTL_PAYLOAD | PCI_EXP_DEVCTL_READRQ, | 265 | PCI_EXP_DEVCTL_PAYLOAD | PCI_EXP_DEVCTL_READRQ, |
266 | new_values); | 266 | new_values); |
diff --git a/arch/tile/kernel/pci_gx.c b/arch/tile/kernel/pci_gx.c index 2ba6d052f85d..94810d4a6332 100644 --- a/arch/tile/kernel/pci_gx.c +++ b/arch/tile/kernel/pci_gx.c | |||
@@ -1047,8 +1047,7 @@ int pcibios_enable_device(struct pci_dev *dev, int mask) | |||
1047 | } | 1047 | } |
1048 | 1048 | ||
1049 | /* Called for each device after PCI setup is done. */ | 1049 | /* Called for each device after PCI setup is done. */ |
1050 | static void __init | 1050 | static void pcibios_fixup_final(struct pci_dev *pdev) |
1051 | pcibios_fixup_final(struct pci_dev *pdev) | ||
1052 | { | 1051 | { |
1053 | set_dma_ops(&pdev->dev, gx_pci_dma_map_ops); | 1052 | set_dma_ops(&pdev->dev, gx_pci_dma_map_ops); |
1054 | set_dma_offset(&pdev->dev, TILE_PCI_MEM_MAP_BASE_OFFSET); | 1053 | set_dma_offset(&pdev->dev, TILE_PCI_MEM_MAP_BASE_OFFSET); |
diff --git a/arch/tile/kernel/ptrace.c b/arch/tile/kernel/ptrace.c index e92e40527d6d..9835312d5a91 100644 --- a/arch/tile/kernel/ptrace.c +++ b/arch/tile/kernel/ptrace.c | |||
@@ -19,7 +19,10 @@ | |||
19 | #include <linux/kprobes.h> | 19 | #include <linux/kprobes.h> |
20 | #include <linux/compat.h> | 20 | #include <linux/compat.h> |
21 | #include <linux/uaccess.h> | 21 | #include <linux/uaccess.h> |
22 | #include <linux/regset.h> | ||
23 | #include <linux/elf.h> | ||
22 | #include <asm/traps.h> | 24 | #include <asm/traps.h> |
25 | #include <arch/chip.h> | ||
23 | 26 | ||
24 | void user_enable_single_step(struct task_struct *child) | 27 | void user_enable_single_step(struct task_struct *child) |
25 | { | 28 | { |
@@ -45,6 +48,100 @@ void ptrace_disable(struct task_struct *child) | |||
45 | clear_tsk_thread_flag(child, TIF_SYSCALL_TRACE); | 48 | clear_tsk_thread_flag(child, TIF_SYSCALL_TRACE); |
46 | } | 49 | } |
47 | 50 | ||
51 | /* | ||
52 | * Get registers from task and ready the result for userspace. | ||
53 | * Note that we localize the API issues to getregs() and putregs() at | ||
54 | * some cost in performance, e.g. we need a full pt_regs copy for | ||
55 | * PEEKUSR, and two copies for POKEUSR. But in general we expect | ||
56 | * GETREGS/PUTREGS to be the API of choice anyway. | ||
57 | */ | ||
58 | static char *getregs(struct task_struct *child, struct pt_regs *uregs) | ||
59 | { | ||
60 | *uregs = *task_pt_regs(child); | ||
61 | |||
62 | /* Set up flags ABI bits. */ | ||
63 | uregs->flags = 0; | ||
64 | #ifdef CONFIG_COMPAT | ||
65 | if (task_thread_info(child)->status & TS_COMPAT) | ||
66 | uregs->flags |= PT_FLAGS_COMPAT; | ||
67 | #endif | ||
68 | |||
69 | return (char *)uregs; | ||
70 | } | ||
71 | |||
72 | /* Put registers back to task. */ | ||
73 | static void putregs(struct task_struct *child, struct pt_regs *uregs) | ||
74 | { | ||
75 | struct pt_regs *regs = task_pt_regs(child); | ||
76 | |||
77 | /* Don't allow overwriting the kernel-internal flags word. */ | ||
78 | uregs->flags = regs->flags; | ||
79 | |||
80 | /* Only allow setting the ICS bit in the ex1 word. */ | ||
81 | uregs->ex1 = PL_ICS_EX1(USER_PL, EX1_ICS(uregs->ex1)); | ||
82 | |||
83 | *regs = *uregs; | ||
84 | } | ||
85 | |||
86 | enum tile_regset { | ||
87 | REGSET_GPR, | ||
88 | }; | ||
89 | |||
90 | static int tile_gpr_get(struct task_struct *target, | ||
91 | const struct user_regset *regset, | ||
92 | unsigned int pos, unsigned int count, | ||
93 | void *kbuf, void __user *ubuf) | ||
94 | { | ||
95 | struct pt_regs regs; | ||
96 | |||
97 | getregs(target, ®s); | ||
98 | |||
99 | return user_regset_copyout(&pos, &count, &kbuf, &ubuf, ®s, 0, | ||
100 | sizeof(regs)); | ||
101 | } | ||
102 | |||
103 | static int tile_gpr_set(struct task_struct *target, | ||
104 | const struct user_regset *regset, | ||
105 | unsigned int pos, unsigned int count, | ||
106 | const void *kbuf, const void __user *ubuf) | ||
107 | { | ||
108 | int ret; | ||
109 | struct pt_regs regs; | ||
110 | |||
111 | ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf, ®s, 0, | ||
112 | sizeof(regs)); | ||
113 | if (ret) | ||
114 | return ret; | ||
115 | |||
116 | putregs(target, ®s); | ||
117 | |||
118 | return 0; | ||
119 | } | ||
120 | |||
121 | static const struct user_regset tile_user_regset[] = { | ||
122 | [REGSET_GPR] = { | ||
123 | .core_note_type = NT_PRSTATUS, | ||
124 | .n = ELF_NGREG, | ||
125 | .size = sizeof(elf_greg_t), | ||
126 | .align = sizeof(elf_greg_t), | ||
127 | .get = tile_gpr_get, | ||
128 | .set = tile_gpr_set, | ||
129 | }, | ||
130 | }; | ||
131 | |||
132 | static const struct user_regset_view tile_user_regset_view = { | ||
133 | .name = CHIP_ARCH_NAME, | ||
134 | .e_machine = ELF_ARCH, | ||
135 | .ei_osabi = ELF_OSABI, | ||
136 | .regsets = tile_user_regset, | ||
137 | .n = ARRAY_SIZE(tile_user_regset), | ||
138 | }; | ||
139 | |||
140 | const struct user_regset_view *task_user_regset_view(struct task_struct *task) | ||
141 | { | ||
142 | return &tile_user_regset_view; | ||
143 | } | ||
144 | |||
48 | long arch_ptrace(struct task_struct *child, long request, | 145 | long arch_ptrace(struct task_struct *child, long request, |
49 | unsigned long addr, unsigned long data) | 146 | unsigned long addr, unsigned long data) |
50 | { | 147 | { |
@@ -53,14 +150,13 @@ long arch_ptrace(struct task_struct *child, long request, | |||
53 | long ret = -EIO; | 150 | long ret = -EIO; |
54 | char *childreg; | 151 | char *childreg; |
55 | struct pt_regs copyregs; | 152 | struct pt_regs copyregs; |
56 | int ex1_offset; | ||
57 | 153 | ||
58 | switch (request) { | 154 | switch (request) { |
59 | 155 | ||
60 | case PTRACE_PEEKUSR: /* Read register from pt_regs. */ | 156 | case PTRACE_PEEKUSR: /* Read register from pt_regs. */ |
61 | if (addr >= PTREGS_SIZE) | 157 | if (addr >= PTREGS_SIZE) |
62 | break; | 158 | break; |
63 | childreg = (char *)task_pt_regs(child) + addr; | 159 | childreg = getregs(child, ©regs) + addr; |
64 | #ifdef CONFIG_COMPAT | 160 | #ifdef CONFIG_COMPAT |
65 | if (is_compat_task()) { | 161 | if (is_compat_task()) { |
66 | if (addr & (sizeof(compat_long_t)-1)) | 162 | if (addr & (sizeof(compat_long_t)-1)) |
@@ -79,17 +175,7 @@ long arch_ptrace(struct task_struct *child, long request, | |||
79 | case PTRACE_POKEUSR: /* Write register in pt_regs. */ | 175 | case PTRACE_POKEUSR: /* Write register in pt_regs. */ |
80 | if (addr >= PTREGS_SIZE) | 176 | if (addr >= PTREGS_SIZE) |
81 | break; | 177 | break; |
82 | childreg = (char *)task_pt_regs(child) + addr; | 178 | childreg = getregs(child, ©regs) + addr; |
83 | |||
84 | /* Guard against overwrites of the privilege level. */ | ||
85 | ex1_offset = PTREGS_OFFSET_EX1; | ||
86 | #if defined(CONFIG_COMPAT) && defined(__BIG_ENDIAN) | ||
87 | if (is_compat_task()) /* point at low word */ | ||
88 | ex1_offset += sizeof(compat_long_t); | ||
89 | #endif | ||
90 | if (addr == ex1_offset) | ||
91 | data = PL_ICS_EX1(USER_PL, EX1_ICS(data)); | ||
92 | |||
93 | #ifdef CONFIG_COMPAT | 179 | #ifdef CONFIG_COMPAT |
94 | if (is_compat_task()) { | 180 | if (is_compat_task()) { |
95 | if (addr & (sizeof(compat_long_t)-1)) | 181 | if (addr & (sizeof(compat_long_t)-1)) |
@@ -102,24 +188,20 @@ long arch_ptrace(struct task_struct *child, long request, | |||
102 | break; | 188 | break; |
103 | *(long *)childreg = data; | 189 | *(long *)childreg = data; |
104 | } | 190 | } |
191 | putregs(child, ©regs); | ||
105 | ret = 0; | 192 | ret = 0; |
106 | break; | 193 | break; |
107 | 194 | ||
108 | case PTRACE_GETREGS: /* Get all registers from the child. */ | 195 | case PTRACE_GETREGS: /* Get all registers from the child. */ |
109 | if (copy_to_user(datap, task_pt_regs(child), | 196 | ret = copy_regset_to_user(child, &tile_user_regset_view, |
110 | sizeof(struct pt_regs)) == 0) { | 197 | REGSET_GPR, 0, |
111 | ret = 0; | 198 | sizeof(struct pt_regs), datap); |
112 | } | ||
113 | break; | 199 | break; |
114 | 200 | ||
115 | case PTRACE_SETREGS: /* Set all registers in the child. */ | 201 | case PTRACE_SETREGS: /* Set all registers in the child. */ |
116 | if (copy_from_user(©regs, datap, | 202 | ret = copy_regset_from_user(child, &tile_user_regset_view, |
117 | sizeof(struct pt_regs)) == 0) { | 203 | REGSET_GPR, 0, |
118 | copyregs.ex1 = | 204 | sizeof(struct pt_regs), datap); |
119 | PL_ICS_EX1(USER_PL, EX1_ICS(copyregs.ex1)); | ||
120 | *task_pt_regs(child) = copyregs; | ||
121 | ret = 0; | ||
122 | } | ||
123 | break; | 205 | break; |
124 | 206 | ||
125 | case PTRACE_GETFPREGS: /* Get the child FPU state. */ | 207 | case PTRACE_GETFPREGS: /* Get the child FPU state. */ |
@@ -128,12 +210,16 @@ long arch_ptrace(struct task_struct *child, long request, | |||
128 | 210 | ||
129 | case PTRACE_SETOPTIONS: | 211 | case PTRACE_SETOPTIONS: |
130 | /* Support TILE-specific ptrace options. */ | 212 | /* Support TILE-specific ptrace options. */ |
131 | child->ptrace &= ~PT_TRACE_MASK_TILE; | 213 | BUILD_BUG_ON(PTRACE_O_MASK_TILE & PTRACE_O_MASK); |
132 | tmp = data & PTRACE_O_MASK_TILE; | 214 | tmp = data & PTRACE_O_MASK_TILE; |
133 | data &= ~PTRACE_O_MASK_TILE; | 215 | data &= ~PTRACE_O_MASK_TILE; |
134 | ret = ptrace_request(child, request, addr, data); | 216 | ret = ptrace_request(child, request, addr, data); |
135 | if (tmp & PTRACE_O_TRACEMIGRATE) | 217 | if (ret == 0) { |
136 | child->ptrace |= PT_TRACE_MIGRATE; | 218 | unsigned int flags = child->ptrace; |
219 | flags &= ~(PTRACE_O_MASK_TILE << PT_OPT_FLAG_SHIFT); | ||
220 | flags |= (tmp << PT_OPT_FLAG_SHIFT); | ||
221 | child->ptrace = flags; | ||
222 | } | ||
137 | break; | 223 | break; |
138 | 224 | ||
139 | default: | 225 | default: |