diff options
author | Anton Altaparmakov <aia21@cantab.net> | 2005-06-23 06:26:22 -0400 |
---|---|---|
committer | Anton Altaparmakov <aia21@cantab.net> | 2005-06-23 06:26:22 -0400 |
commit | 3357d4c75f1fb67e7304998c4ad4e9a9fed66fa4 (patch) | |
tree | ceba46966a5a1112a05d257d8ecb25ae5eee95e0 /arch/arm/kernel/traps.c | |
parent | 364f6c717deef4a3ac4982e670fa9846b43cd060 (diff) | |
parent | ee98689be1b054897ff17655008c3048fe88be94 (diff) |
Automatic merge with /usr/src/ntfs-2.6.git.
Diffstat (limited to 'arch/arm/kernel/traps.c')
-rw-r--r-- | arch/arm/kernel/traps.c | 58 |
1 files changed, 58 insertions, 0 deletions
diff --git a/arch/arm/kernel/traps.c b/arch/arm/kernel/traps.c index 14df16b983f4..2fb0a4cfb37a 100644 --- a/arch/arm/kernel/traps.c +++ b/arch/arm/kernel/traps.c | |||
@@ -30,6 +30,7 @@ | |||
30 | #include <asm/traps.h> | 30 | #include <asm/traps.h> |
31 | 31 | ||
32 | #include "ptrace.h" | 32 | #include "ptrace.h" |
33 | #include "signal.h" | ||
33 | 34 | ||
34 | const char *processor_modes[]= | 35 | const char *processor_modes[]= |
35 | { "USER_26", "FIQ_26" , "IRQ_26" , "SVC_26" , "UK4_26" , "UK5_26" , "UK6_26" , "UK7_26" , | 36 | { "USER_26", "FIQ_26" , "IRQ_26" , "SVC_26" , "UK4_26" , "UK5_26" , "UK6_26" , "UK7_26" , |
@@ -464,6 +465,55 @@ asmlinkage int arm_syscall(int no, struct pt_regs *regs) | |||
464 | #endif | 465 | #endif |
465 | return 0; | 466 | return 0; |
466 | 467 | ||
468 | #ifdef CONFIG_NEEDS_SYSCALL_FOR_CMPXCHG | ||
469 | /* | ||
470 | * Atomically store r1 in *r2 if *r2 is equal to r0 for user space. | ||
471 | * Return zero in r0 if *MEM was changed or non-zero if no exchange | ||
472 | * happened. Also set the user C flag accordingly. | ||
473 | * If access permissions have to be fixed up then non-zero is | ||
474 | * returned and the operation has to be re-attempted. | ||
475 | * | ||
476 | * *NOTE*: This is a ghost syscall private to the kernel. Only the | ||
477 | * __kuser_cmpxchg code in entry-armv.S should be aware of its | ||
478 | * existence. Don't ever use this from user code. | ||
479 | */ | ||
480 | case 0xfff0: | ||
481 | { | ||
482 | extern void do_DataAbort(unsigned long addr, unsigned int fsr, | ||
483 | struct pt_regs *regs); | ||
484 | unsigned long val; | ||
485 | unsigned long addr = regs->ARM_r2; | ||
486 | struct mm_struct *mm = current->mm; | ||
487 | pgd_t *pgd; pmd_t *pmd; pte_t *pte; | ||
488 | |||
489 | regs->ARM_cpsr &= ~PSR_C_BIT; | ||
490 | spin_lock(&mm->page_table_lock); | ||
491 | pgd = pgd_offset(mm, addr); | ||
492 | if (!pgd_present(*pgd)) | ||
493 | goto bad_access; | ||
494 | pmd = pmd_offset(pgd, addr); | ||
495 | if (!pmd_present(*pmd)) | ||
496 | goto bad_access; | ||
497 | pte = pte_offset_map(pmd, addr); | ||
498 | if (!pte_present(*pte) || !pte_write(*pte)) | ||
499 | goto bad_access; | ||
500 | val = *(unsigned long *)addr; | ||
501 | val -= regs->ARM_r0; | ||
502 | if (val == 0) { | ||
503 | *(unsigned long *)addr = regs->ARM_r1; | ||
504 | regs->ARM_cpsr |= PSR_C_BIT; | ||
505 | } | ||
506 | spin_unlock(&mm->page_table_lock); | ||
507 | return val; | ||
508 | |||
509 | bad_access: | ||
510 | spin_unlock(&mm->page_table_lock); | ||
511 | /* simulate a read access fault */ | ||
512 | do_DataAbort(addr, 15 + (1 << 11), regs); | ||
513 | return -1; | ||
514 | } | ||
515 | #endif | ||
516 | |||
467 | default: | 517 | default: |
468 | /* Calls 9f00xx..9f07ff are defined to return -ENOSYS | 518 | /* Calls 9f00xx..9f07ff are defined to return -ENOSYS |
469 | if not implemented, rather than raising SIGILL. This | 519 | if not implemented, rather than raising SIGILL. This |
@@ -634,6 +684,14 @@ void __init trap_init(void) | |||
634 | memcpy((void *)0xffff0000, __vectors_start, __vectors_end - __vectors_start); | 684 | memcpy((void *)0xffff0000, __vectors_start, __vectors_end - __vectors_start); |
635 | memcpy((void *)0xffff0200, __stubs_start, __stubs_end - __stubs_start); | 685 | memcpy((void *)0xffff0200, __stubs_start, __stubs_end - __stubs_start); |
636 | memcpy((void *)0xffff1000 - kuser_sz, __kuser_helper_start, kuser_sz); | 686 | memcpy((void *)0xffff1000 - kuser_sz, __kuser_helper_start, kuser_sz); |
687 | |||
688 | /* | ||
689 | * Copy signal return handlers into the vector page, and | ||
690 | * set sigreturn to be a pointer to these. | ||
691 | */ | ||
692 | memcpy((void *)KERN_SIGRETURN_CODE, sigreturn_codes, | ||
693 | sizeof(sigreturn_codes)); | ||
694 | |||
637 | flush_icache_range(0xffff0000, 0xffff0000 + PAGE_SIZE); | 695 | flush_icache_range(0xffff0000, 0xffff0000 + PAGE_SIZE); |
638 | modify_domain(DOMAIN_USER, DOMAIN_CLIENT); | 696 | modify_domain(DOMAIN_USER, DOMAIN_CLIENT); |
639 | } | 697 | } |