diff options
author | Andrea Bastoni <bastoni@cs.unc.edu> | 2010-05-30 19:16:45 -0400 |
---|---|---|
committer | Andrea Bastoni <bastoni@cs.unc.edu> | 2010-05-30 19:16:45 -0400 |
commit | ada47b5fe13d89735805b566185f4885f5a3f750 (patch) | |
tree | 644b88f8a71896307d71438e9b3af49126ffb22b /arch/blackfin/kernel/process.c | |
parent | 43e98717ad40a4ae64545b5ba047c7b86aa44f4f (diff) | |
parent | 3280f21d43ee541f97f8cda5792150d2dbec20d5 (diff) |
Merge branch 'wip-2.6.34' into old-private-masterarchived-private-master
Diffstat (limited to 'arch/blackfin/kernel/process.c')
-rw-r--r-- | arch/blackfin/kernel/process.c | 109 |
1 files changed, 75 insertions, 34 deletions
diff --git a/arch/blackfin/kernel/process.c b/arch/blackfin/kernel/process.c index 5cc7e2e9e415..93ec07da2e51 100644 --- a/arch/blackfin/kernel/process.c +++ b/arch/blackfin/kernel/process.c | |||
@@ -11,6 +11,7 @@ | |||
11 | #include <linux/unistd.h> | 11 | #include <linux/unistd.h> |
12 | #include <linux/user.h> | 12 | #include <linux/user.h> |
13 | #include <linux/uaccess.h> | 13 | #include <linux/uaccess.h> |
14 | #include <linux/slab.h> | ||
14 | #include <linux/sched.h> | 15 | #include <linux/sched.h> |
15 | #include <linux/tick.h> | 16 | #include <linux/tick.h> |
16 | #include <linux/fs.h> | 17 | #include <linux/fs.h> |
@@ -98,13 +99,6 @@ void cpu_idle(void) | |||
98 | } | 99 | } |
99 | } | 100 | } |
100 | 101 | ||
101 | /* Fill in the fpu structure for a core dump. */ | ||
102 | |||
103 | int dump_fpu(struct pt_regs *regs, elf_fpregset_t * fpregs) | ||
104 | { | ||
105 | return 1; | ||
106 | } | ||
107 | |||
108 | /* | 102 | /* |
109 | * This gets run with P1 containing the | 103 | * This gets run with P1 containing the |
110 | * function to call, and R1 containing | 104 | * function to call, and R1 containing |
@@ -215,22 +209,18 @@ copy_thread(unsigned long clone_flags, | |||
215 | /* | 209 | /* |
216 | * sys_execve() executes a new program. | 210 | * sys_execve() executes a new program. |
217 | */ | 211 | */ |
218 | |||
219 | asmlinkage int sys_execve(char __user *name, char __user * __user *argv, char __user * __user *envp) | 212 | asmlinkage int sys_execve(char __user *name, char __user * __user *argv, char __user * __user *envp) |
220 | { | 213 | { |
221 | int error; | 214 | int error; |
222 | char *filename; | 215 | char *filename; |
223 | struct pt_regs *regs = (struct pt_regs *)((&name) + 6); | 216 | struct pt_regs *regs = (struct pt_regs *)((&name) + 6); |
224 | 217 | ||
225 | lock_kernel(); | ||
226 | filename = getname(name); | 218 | filename = getname(name); |
227 | error = PTR_ERR(filename); | 219 | error = PTR_ERR(filename); |
228 | if (IS_ERR(filename)) | 220 | if (IS_ERR(filename)) |
229 | goto out; | 221 | return error; |
230 | error = do_execve(filename, argv, envp, regs); | 222 | error = do_execve(filename, argv, envp, regs); |
231 | putname(filename); | 223 | putname(filename); |
232 | out: | ||
233 | unlock_kernel(); | ||
234 | return error; | 224 | return error; |
235 | } | 225 | } |
236 | 226 | ||
@@ -262,9 +252,12 @@ void finish_atomic_sections (struct pt_regs *regs) | |||
262 | int __user *up0 = (int __user *)regs->p0; | 252 | int __user *up0 = (int __user *)regs->p0; |
263 | 253 | ||
264 | switch (regs->pc) { | 254 | switch (regs->pc) { |
255 | default: | ||
256 | /* not in middle of an atomic step, so resume like normal */ | ||
257 | return; | ||
258 | |||
265 | case ATOMIC_XCHG32 + 2: | 259 | case ATOMIC_XCHG32 + 2: |
266 | put_user(regs->r1, up0); | 260 | put_user(regs->r1, up0); |
267 | regs->pc = ATOMIC_XCHG32 + 4; | ||
268 | break; | 261 | break; |
269 | 262 | ||
270 | case ATOMIC_CAS32 + 2: | 263 | case ATOMIC_CAS32 + 2: |
@@ -272,7 +265,6 @@ void finish_atomic_sections (struct pt_regs *regs) | |||
272 | if (regs->r0 == regs->r1) | 265 | if (regs->r0 == regs->r1) |
273 | case ATOMIC_CAS32 + 6: | 266 | case ATOMIC_CAS32 + 6: |
274 | put_user(regs->r2, up0); | 267 | put_user(regs->r2, up0); |
275 | regs->pc = ATOMIC_CAS32 + 8; | ||
276 | break; | 268 | break; |
277 | 269 | ||
278 | case ATOMIC_ADD32 + 2: | 270 | case ATOMIC_ADD32 + 2: |
@@ -280,7 +272,6 @@ void finish_atomic_sections (struct pt_regs *regs) | |||
280 | /* fall through */ | 272 | /* fall through */ |
281 | case ATOMIC_ADD32 + 4: | 273 | case ATOMIC_ADD32 + 4: |
282 | put_user(regs->r0, up0); | 274 | put_user(regs->r0, up0); |
283 | regs->pc = ATOMIC_ADD32 + 6; | ||
284 | break; | 275 | break; |
285 | 276 | ||
286 | case ATOMIC_SUB32 + 2: | 277 | case ATOMIC_SUB32 + 2: |
@@ -288,7 +279,6 @@ void finish_atomic_sections (struct pt_regs *regs) | |||
288 | /* fall through */ | 279 | /* fall through */ |
289 | case ATOMIC_SUB32 + 4: | 280 | case ATOMIC_SUB32 + 4: |
290 | put_user(regs->r0, up0); | 281 | put_user(regs->r0, up0); |
291 | regs->pc = ATOMIC_SUB32 + 6; | ||
292 | break; | 282 | break; |
293 | 283 | ||
294 | case ATOMIC_IOR32 + 2: | 284 | case ATOMIC_IOR32 + 2: |
@@ -296,7 +286,6 @@ void finish_atomic_sections (struct pt_regs *regs) | |||
296 | /* fall through */ | 286 | /* fall through */ |
297 | case ATOMIC_IOR32 + 4: | 287 | case ATOMIC_IOR32 + 4: |
298 | put_user(regs->r0, up0); | 288 | put_user(regs->r0, up0); |
299 | regs->pc = ATOMIC_IOR32 + 6; | ||
300 | break; | 289 | break; |
301 | 290 | ||
302 | case ATOMIC_AND32 + 2: | 291 | case ATOMIC_AND32 + 2: |
@@ -304,7 +293,6 @@ void finish_atomic_sections (struct pt_regs *regs) | |||
304 | /* fall through */ | 293 | /* fall through */ |
305 | case ATOMIC_AND32 + 4: | 294 | case ATOMIC_AND32 + 4: |
306 | put_user(regs->r0, up0); | 295 | put_user(regs->r0, up0); |
307 | regs->pc = ATOMIC_AND32 + 6; | ||
308 | break; | 296 | break; |
309 | 297 | ||
310 | case ATOMIC_XOR32 + 2: | 298 | case ATOMIC_XOR32 + 2: |
@@ -312,9 +300,15 @@ void finish_atomic_sections (struct pt_regs *regs) | |||
312 | /* fall through */ | 300 | /* fall through */ |
313 | case ATOMIC_XOR32 + 4: | 301 | case ATOMIC_XOR32 + 4: |
314 | put_user(regs->r0, up0); | 302 | put_user(regs->r0, up0); |
315 | regs->pc = ATOMIC_XOR32 + 6; | ||
316 | break; | 303 | break; |
317 | } | 304 | } |
305 | |||
306 | /* | ||
307 | * We've finished the atomic section, and the only thing left for | ||
308 | * userspace is to do a RTS, so we might as well handle that too | ||
309 | * since we need to update the PC anyways. | ||
310 | */ | ||
311 | regs->pc = regs->rets; | ||
318 | } | 312 | } |
319 | 313 | ||
320 | static inline | 314 | static inline |
@@ -336,12 +330,58 @@ int in_mem_const(unsigned long addr, unsigned long size, | |||
336 | { | 330 | { |
337 | return in_mem_const_off(addr, size, 0, const_addr, const_size); | 331 | return in_mem_const_off(addr, size, 0, const_addr, const_size); |
338 | } | 332 | } |
339 | #define IN_ASYNC(bnum, bctlnum) \ | 333 | #define ASYNC_ENABLED(bnum, bctlnum) \ |
340 | ({ \ | 334 | ({ \ |
341 | (bfin_read_EBIU_AMGCTL() & 0xe) < ((bnum + 1) << 1) ? -EFAULT : \ | 335 | (bfin_read_EBIU_AMGCTL() & 0xe) < ((bnum + 1) << 1) ? 0 : \ |
342 | bfin_read_EBIU_AMBCTL##bctlnum() & B##bnum##RDYEN ? -EFAULT : \ | 336 | bfin_read_EBIU_AMBCTL##bctlnum() & B##bnum##RDYEN ? 0 : \ |
343 | BFIN_MEM_ACCESS_CORE; \ | 337 | 1; \ |
344 | }) | 338 | }) |
339 | /* | ||
340 | * We can't read EBIU banks that aren't enabled or we end up hanging | ||
341 | * on the access to the async space. Make sure we validate accesses | ||
342 | * that cross async banks too. | ||
343 | * 0 - found, but unusable | ||
344 | * 1 - found & usable | ||
345 | * 2 - not found | ||
346 | */ | ||
347 | static | ||
348 | int in_async(unsigned long addr, unsigned long size) | ||
349 | { | ||
350 | if (addr >= ASYNC_BANK0_BASE && addr < ASYNC_BANK0_BASE + ASYNC_BANK0_SIZE) { | ||
351 | if (!ASYNC_ENABLED(0, 0)) | ||
352 | return 0; | ||
353 | if (addr + size <= ASYNC_BANK0_BASE + ASYNC_BANK0_SIZE) | ||
354 | return 1; | ||
355 | size -= ASYNC_BANK0_BASE + ASYNC_BANK0_SIZE - addr; | ||
356 | addr = ASYNC_BANK0_BASE + ASYNC_BANK0_SIZE; | ||
357 | } | ||
358 | if (addr >= ASYNC_BANK1_BASE && addr < ASYNC_BANK1_BASE + ASYNC_BANK1_SIZE) { | ||
359 | if (!ASYNC_ENABLED(1, 0)) | ||
360 | return 0; | ||
361 | if (addr + size <= ASYNC_BANK1_BASE + ASYNC_BANK1_SIZE) | ||
362 | return 1; | ||
363 | size -= ASYNC_BANK1_BASE + ASYNC_BANK1_SIZE - addr; | ||
364 | addr = ASYNC_BANK1_BASE + ASYNC_BANK1_SIZE; | ||
365 | } | ||
366 | if (addr >= ASYNC_BANK2_BASE && addr < ASYNC_BANK2_BASE + ASYNC_BANK2_SIZE) { | ||
367 | if (!ASYNC_ENABLED(2, 1)) | ||
368 | return 0; | ||
369 | if (addr + size <= ASYNC_BANK2_BASE + ASYNC_BANK2_SIZE) | ||
370 | return 1; | ||
371 | size -= ASYNC_BANK2_BASE + ASYNC_BANK2_SIZE - addr; | ||
372 | addr = ASYNC_BANK2_BASE + ASYNC_BANK2_SIZE; | ||
373 | } | ||
374 | if (addr >= ASYNC_BANK3_BASE && addr < ASYNC_BANK3_BASE + ASYNC_BANK3_SIZE) { | ||
375 | if (ASYNC_ENABLED(3, 1)) | ||
376 | return 0; | ||
377 | if (addr + size <= ASYNC_BANK3_BASE + ASYNC_BANK3_SIZE) | ||
378 | return 1; | ||
379 | return 0; | ||
380 | } | ||
381 | |||
382 | /* not within async bounds */ | ||
383 | return 2; | ||
384 | } | ||
345 | 385 | ||
346 | int bfin_mem_access_type(unsigned long addr, unsigned long size) | 386 | int bfin_mem_access_type(unsigned long addr, unsigned long size) |
347 | { | 387 | { |
@@ -378,17 +418,11 @@ int bfin_mem_access_type(unsigned long addr, unsigned long size) | |||
378 | if (addr >= SYSMMR_BASE) | 418 | if (addr >= SYSMMR_BASE) |
379 | return BFIN_MEM_ACCESS_CORE_ONLY; | 419 | return BFIN_MEM_ACCESS_CORE_ONLY; |
380 | 420 | ||
381 | /* We can't read EBIU banks that aren't enabled or we end up hanging | 421 | switch (in_async(addr, size)) { |
382 | * on the access to the async space. | 422 | case 0: return -EFAULT; |
383 | */ | 423 | case 1: return BFIN_MEM_ACCESS_CORE; |
384 | if (in_mem_const(addr, size, ASYNC_BANK0_BASE, ASYNC_BANK0_SIZE)) | 424 | case 2: /* fall through */; |
385 | return IN_ASYNC(0, 0); | 425 | } |
386 | if (in_mem_const(addr, size, ASYNC_BANK1_BASE, ASYNC_BANK1_SIZE)) | ||
387 | return IN_ASYNC(1, 0); | ||
388 | if (in_mem_const(addr, size, ASYNC_BANK2_BASE, ASYNC_BANK2_SIZE)) | ||
389 | return IN_ASYNC(2, 1); | ||
390 | if (in_mem_const(addr, size, ASYNC_BANK3_BASE, ASYNC_BANK3_SIZE)) | ||
391 | return IN_ASYNC(3, 1); | ||
392 | 426 | ||
393 | if (in_mem_const(addr, size, BOOT_ROM_START, BOOT_ROM_LENGTH)) | 427 | if (in_mem_const(addr, size, BOOT_ROM_START, BOOT_ROM_LENGTH)) |
394 | return BFIN_MEM_ACCESS_CORE; | 428 | return BFIN_MEM_ACCESS_CORE; |
@@ -405,6 +439,8 @@ __attribute__((l1_text)) | |||
405 | /* Return 1 if access to memory range is OK, 0 otherwise */ | 439 | /* Return 1 if access to memory range is OK, 0 otherwise */ |
406 | int _access_ok(unsigned long addr, unsigned long size) | 440 | int _access_ok(unsigned long addr, unsigned long size) |
407 | { | 441 | { |
442 | int aret; | ||
443 | |||
408 | if (size == 0) | 444 | if (size == 0) |
409 | return 1; | 445 | return 1; |
410 | /* Check that things do not wrap around */ | 446 | /* Check that things do not wrap around */ |
@@ -454,6 +490,11 @@ int _access_ok(unsigned long addr, unsigned long size) | |||
454 | if (in_mem_const(addr, size, COREB_L1_DATA_B_START, COREB_L1_DATA_B_LENGTH)) | 490 | if (in_mem_const(addr, size, COREB_L1_DATA_B_START, COREB_L1_DATA_B_LENGTH)) |
455 | return 1; | 491 | return 1; |
456 | #endif | 492 | #endif |
493 | |||
494 | aret = in_async(addr, size); | ||
495 | if (aret < 2) | ||
496 | return aret; | ||
497 | |||
457 | if (in_mem_const_off(addr, size, _ebss_l2 - _stext_l2, L2_START, L2_LENGTH)) | 498 | if (in_mem_const_off(addr, size, _ebss_l2 - _stext_l2, L2_START, L2_LENGTH)) |
458 | return 1; | 499 | return 1; |
459 | 500 | ||