aboutsummaryrefslogtreecommitdiffstats
path: root/arch/blackfin/kernel/process.c
diff options
context:
space:
mode:
Diffstat (limited to 'arch/blackfin/kernel/process.c')
-rw-r--r--arch/blackfin/kernel/process.c109
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
103int 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
219asmlinkage int sys_execve(char __user *name, char __user * __user *argv, char __user * __user *envp) 212asmlinkage 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
320static inline 314static 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 */
347static
348int 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
346int bfin_mem_access_type(unsigned long addr, unsigned long size) 386int 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 */
406int _access_ok(unsigned long addr, unsigned long size) 440int _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