diff options
Diffstat (limited to 'arch/blackfin/kernel/process.c')
-rw-r--r-- | arch/blackfin/kernel/process.c | 174 |
1 files changed, 144 insertions, 30 deletions
diff --git a/arch/blackfin/kernel/process.c b/arch/blackfin/kernel/process.c index 30d0843ed701..9da36bab7ccb 100644 --- a/arch/blackfin/kernel/process.c +++ b/arch/blackfin/kernel/process.c | |||
@@ -160,6 +160,29 @@ pid_t kernel_thread(int (*fn) (void *), void *arg, unsigned long flags) | |||
160 | } | 160 | } |
161 | EXPORT_SYMBOL(kernel_thread); | 161 | EXPORT_SYMBOL(kernel_thread); |
162 | 162 | ||
163 | /* | ||
164 | * Do necessary setup to start up a newly executed thread. | ||
165 | * | ||
166 | * pass the data segment into user programs if it exists, | ||
167 | * it can't hurt anything as far as I can tell | ||
168 | */ | ||
169 | void start_thread(struct pt_regs *regs, unsigned long new_ip, unsigned long new_sp) | ||
170 | { | ||
171 | set_fs(USER_DS); | ||
172 | regs->pc = new_ip; | ||
173 | if (current->mm) | ||
174 | regs->p5 = current->mm->start_data; | ||
175 | #ifdef CONFIG_SMP | ||
176 | task_thread_info(current)->l1_task_info.stack_start = | ||
177 | (void *)current->mm->context.stack_start; | ||
178 | task_thread_info(current)->l1_task_info.lowest_sp = (void *)new_sp; | ||
179 | memcpy(L1_SCRATCH_TASK_INFO, &task_thread_info(current)->l1_task_info, | ||
180 | sizeof(*L1_SCRATCH_TASK_INFO)); | ||
181 | #endif | ||
182 | wrusp(new_sp); | ||
183 | } | ||
184 | EXPORT_SYMBOL_GPL(start_thread); | ||
185 | |||
163 | void flush_thread(void) | 186 | void flush_thread(void) |
164 | { | 187 | { |
165 | } | 188 | } |
@@ -321,6 +344,87 @@ void finish_atomic_sections (struct pt_regs *regs) | |||
321 | } | 344 | } |
322 | } | 345 | } |
323 | 346 | ||
347 | static inline | ||
348 | int in_mem(unsigned long addr, unsigned long size, | ||
349 | unsigned long start, unsigned long end) | ||
350 | { | ||
351 | return addr >= start && addr + size <= end; | ||
352 | } | ||
353 | static inline | ||
354 | int in_mem_const_off(unsigned long addr, unsigned long size, unsigned long off, | ||
355 | unsigned long const_addr, unsigned long const_size) | ||
356 | { | ||
357 | return const_size && | ||
358 | in_mem(addr, size, const_addr + off, const_addr + const_size); | ||
359 | } | ||
360 | static inline | ||
361 | int in_mem_const(unsigned long addr, unsigned long size, | ||
362 | unsigned long const_addr, unsigned long const_size) | ||
363 | { | ||
364 | return in_mem_const_off(addr, size, 0, const_addr, const_size); | ||
365 | } | ||
366 | #define IN_ASYNC(bnum, bctlnum) \ | ||
367 | ({ \ | ||
368 | (bfin_read_EBIU_AMGCTL() & 0xe) < ((bnum + 1) << 1) ? -EFAULT : \ | ||
369 | bfin_read_EBIU_AMBCTL##bctlnum() & B##bnum##RDYEN ? -EFAULT : \ | ||
370 | BFIN_MEM_ACCESS_CORE; \ | ||
371 | }) | ||
372 | |||
373 | int bfin_mem_access_type(unsigned long addr, unsigned long size) | ||
374 | { | ||
375 | int cpu = raw_smp_processor_id(); | ||
376 | |||
377 | /* Check that things do not wrap around */ | ||
378 | if (addr > ULONG_MAX - size) | ||
379 | return -EFAULT; | ||
380 | |||
381 | if (in_mem(addr, size, FIXED_CODE_START, physical_mem_end)) | ||
382 | return BFIN_MEM_ACCESS_CORE; | ||
383 | |||
384 | if (in_mem_const(addr, size, L1_CODE_START, L1_CODE_LENGTH)) | ||
385 | return cpu == 0 ? BFIN_MEM_ACCESS_ITEST : BFIN_MEM_ACCESS_IDMA; | ||
386 | if (in_mem_const(addr, size, L1_SCRATCH_START, L1_SCRATCH_LENGTH)) | ||
387 | return cpu == 0 ? BFIN_MEM_ACCESS_CORE_ONLY : -EFAULT; | ||
388 | if (in_mem_const(addr, size, L1_DATA_A_START, L1_DATA_A_LENGTH)) | ||
389 | return cpu == 0 ? BFIN_MEM_ACCESS_CORE : BFIN_MEM_ACCESS_IDMA; | ||
390 | if (in_mem_const(addr, size, L1_DATA_B_START, L1_DATA_B_LENGTH)) | ||
391 | return cpu == 0 ? BFIN_MEM_ACCESS_CORE : BFIN_MEM_ACCESS_IDMA; | ||
392 | #ifdef COREB_L1_CODE_START | ||
393 | if (in_mem_const(addr, size, COREB_L1_CODE_START, COREB_L1_CODE_LENGTH)) | ||
394 | return cpu == 1 ? BFIN_MEM_ACCESS_ITEST : BFIN_MEM_ACCESS_IDMA; | ||
395 | if (in_mem_const(addr, size, COREB_L1_SCRATCH_START, L1_SCRATCH_LENGTH)) | ||
396 | return cpu == 1 ? BFIN_MEM_ACCESS_CORE_ONLY : -EFAULT; | ||
397 | if (in_mem_const(addr, size, COREB_L1_DATA_A_START, COREB_L1_DATA_A_LENGTH)) | ||
398 | return cpu == 1 ? BFIN_MEM_ACCESS_CORE : BFIN_MEM_ACCESS_IDMA; | ||
399 | if (in_mem_const(addr, size, COREB_L1_DATA_B_START, COREB_L1_DATA_B_LENGTH)) | ||
400 | return cpu == 1 ? BFIN_MEM_ACCESS_CORE : BFIN_MEM_ACCESS_IDMA; | ||
401 | #endif | ||
402 | if (in_mem_const(addr, size, L2_START, L2_LENGTH)) | ||
403 | return BFIN_MEM_ACCESS_CORE; | ||
404 | |||
405 | if (addr >= SYSMMR_BASE) | ||
406 | return BFIN_MEM_ACCESS_CORE_ONLY; | ||
407 | |||
408 | /* We can't read EBIU banks that aren't enabled or we end up hanging | ||
409 | * on the access to the async space. | ||
410 | */ | ||
411 | if (in_mem_const(addr, size, ASYNC_BANK0_BASE, ASYNC_BANK0_SIZE)) | ||
412 | return IN_ASYNC(0, 0); | ||
413 | if (in_mem_const(addr, size, ASYNC_BANK1_BASE, ASYNC_BANK1_SIZE)) | ||
414 | return IN_ASYNC(1, 0); | ||
415 | if (in_mem_const(addr, size, ASYNC_BANK2_BASE, ASYNC_BANK2_SIZE)) | ||
416 | return IN_ASYNC(2, 1); | ||
417 | if (in_mem_const(addr, size, ASYNC_BANK3_BASE, ASYNC_BANK3_SIZE)) | ||
418 | return IN_ASYNC(3, 1); | ||
419 | |||
420 | if (in_mem_const(addr, size, BOOT_ROM_START, BOOT_ROM_LENGTH)) | ||
421 | return BFIN_MEM_ACCESS_CORE; | ||
422 | if (in_mem_const(addr, size, L1_ROM_START, L1_ROM_LENGTH)) | ||
423 | return BFIN_MEM_ACCESS_DMA; | ||
424 | |||
425 | return -EFAULT; | ||
426 | } | ||
427 | |||
324 | #if defined(CONFIG_ACCESS_CHECK) | 428 | #if defined(CONFIG_ACCESS_CHECK) |
325 | #ifdef CONFIG_ACCESS_OK_L1 | 429 | #ifdef CONFIG_ACCESS_OK_L1 |
326 | __attribute__((l1_text)) | 430 | __attribute__((l1_text)) |
@@ -330,51 +434,61 @@ int _access_ok(unsigned long addr, unsigned long size) | |||
330 | { | 434 | { |
331 | if (size == 0) | 435 | if (size == 0) |
332 | return 1; | 436 | return 1; |
333 | if (addr > (addr + size)) | 437 | /* Check that things do not wrap around */ |
438 | if (addr > ULONG_MAX - size) | ||
334 | return 0; | 439 | return 0; |
335 | if (segment_eq(get_fs(), KERNEL_DS)) | 440 | if (segment_eq(get_fs(), KERNEL_DS)) |
336 | return 1; | 441 | return 1; |
337 | #ifdef CONFIG_MTD_UCLINUX | 442 | #ifdef CONFIG_MTD_UCLINUX |
338 | if (addr >= memory_start && (addr + size) <= memory_end) | 443 | if (1) |
339 | return 1; | 444 | #else |
340 | if (addr >= memory_mtd_end && (addr + size) <= physical_mem_end) | 445 | if (0) |
446 | #endif | ||
447 | { | ||
448 | if (in_mem(addr, size, memory_start, memory_end)) | ||
449 | return 1; | ||
450 | if (in_mem(addr, size, memory_mtd_end, physical_mem_end)) | ||
451 | return 1; | ||
452 | # ifndef CONFIG_ROMFS_ON_MTD | ||
453 | if (0) | ||
454 | # endif | ||
455 | /* For XIP, allow user space to use pointers within the ROMFS. */ | ||
456 | if (in_mem(addr, size, memory_mtd_start, memory_mtd_end)) | ||
457 | return 1; | ||
458 | } else { | ||
459 | if (in_mem(addr, size, memory_start, physical_mem_end)) | ||
460 | return 1; | ||
461 | } | ||
462 | |||
463 | if (in_mem(addr, size, (unsigned long)__init_begin, (unsigned long)__init_end)) | ||
341 | return 1; | 464 | return 1; |
342 | 465 | ||
343 | #ifdef CONFIG_ROMFS_ON_MTD | 466 | if (in_mem_const(addr, size, L1_CODE_START, L1_CODE_LENGTH)) |
344 | /* For XIP, allow user space to use pointers within the ROMFS. */ | ||
345 | if (addr >= memory_mtd_start && (addr + size) <= memory_mtd_end) | ||
346 | return 1; | 467 | return 1; |
347 | #endif | 468 | if (in_mem_const_off(addr, size, _etext_l1 - _stext_l1, L1_CODE_START, L1_CODE_LENGTH)) |
348 | #else | ||
349 | if (addr >= memory_start && (addr + size) <= physical_mem_end) | ||
350 | return 1; | 469 | return 1; |
351 | #endif | 470 | if (in_mem_const_off(addr, size, _ebss_l1 - _sdata_l1, L1_DATA_A_START, L1_DATA_A_LENGTH)) |
352 | if (addr >= (unsigned long)__init_begin && | ||
353 | addr + size <= (unsigned long)__init_end) | ||
354 | return 1; | 471 | return 1; |
355 | if (addr >= get_l1_scratch_start() | 472 | if (in_mem_const_off(addr, size, _ebss_b_l1 - _sdata_b_l1, L1_DATA_B_START, L1_DATA_B_LENGTH)) |
356 | && addr + size <= get_l1_scratch_start() + L1_SCRATCH_LENGTH) | ||
357 | return 1; | 473 | return 1; |
358 | #if L1_CODE_LENGTH != 0 | 474 | #ifdef COREB_L1_CODE_START |
359 | if (addr >= get_l1_code_start() + (_etext_l1 - _stext_l1) | 475 | if (in_mem_const(addr, size, COREB_L1_CODE_START, COREB_L1_CODE_LENGTH)) |
360 | && addr + size <= get_l1_code_start() + L1_CODE_LENGTH) | ||
361 | return 1; | 476 | return 1; |
362 | #endif | 477 | if (in_mem_const(addr, size, COREB_L1_SCRATCH_START, L1_SCRATCH_LENGTH)) |
363 | #if L1_DATA_A_LENGTH != 0 | ||
364 | if (addr >= get_l1_data_a_start() + (_ebss_l1 - _sdata_l1) | ||
365 | && addr + size <= get_l1_data_a_start() + L1_DATA_A_LENGTH) | ||
366 | return 1; | 478 | return 1; |
367 | #endif | 479 | if (in_mem_const(addr, size, COREB_L1_DATA_A_START, COREB_L1_DATA_A_LENGTH)) |
368 | #if L1_DATA_B_LENGTH != 0 | ||
369 | if (addr >= get_l1_data_b_start() + (_ebss_b_l1 - _sdata_b_l1) | ||
370 | && addr + size <= get_l1_data_b_start() + L1_DATA_B_LENGTH) | ||
371 | return 1; | 480 | return 1; |
372 | #endif | 481 | if (in_mem_const(addr, size, COREB_L1_DATA_B_START, COREB_L1_DATA_B_LENGTH)) |
373 | #if L2_LENGTH != 0 | ||
374 | if (addr >= L2_START + (_ebss_l2 - _stext_l2) | ||
375 | && addr + size <= L2_START + L2_LENGTH) | ||
376 | return 1; | 482 | return 1; |
377 | #endif | 483 | #endif |
484 | if (in_mem_const_off(addr, size, _ebss_l2 - _stext_l2, L2_START, L2_LENGTH)) | ||
485 | return 1; | ||
486 | |||
487 | if (in_mem_const(addr, size, BOOT_ROM_START, BOOT_ROM_LENGTH)) | ||
488 | return 1; | ||
489 | if (in_mem_const(addr, size, L1_ROM_START, L1_ROM_LENGTH)) | ||
490 | return 1; | ||
491 | |||
378 | return 0; | 492 | return 0; |
379 | } | 493 | } |
380 | EXPORT_SYMBOL(_access_ok); | 494 | EXPORT_SYMBOL(_access_ok); |