diff options
Diffstat (limited to 'arch/ia64/kernel/fsys.S')
-rw-r--r-- | arch/ia64/kernel/fsys.S | 118 |
1 files changed, 74 insertions, 44 deletions
diff --git a/arch/ia64/kernel/fsys.S b/arch/ia64/kernel/fsys.S index 57c6556b1e06..d09a5b8a0982 100644 --- a/arch/ia64/kernel/fsys.S +++ b/arch/ia64/kernel/fsys.S | |||
@@ -531,84 +531,114 @@ GLOBAL_ENTRY(fsys_bubble_down) | |||
531 | .altrp b6 | 531 | .altrp b6 |
532 | .body | 532 | .body |
533 | /* | 533 | /* |
534 | * We get here for syscalls that don't have a lightweight handler. For those, we | 534 | * We get here for syscalls that don't have a lightweight |
535 | * need to bubble down into the kernel and that requires setting up a minimal | 535 | * handler. For those, we need to bubble down into the kernel |
536 | * pt_regs structure, and initializing the CPU state more or less as if an | 536 | * and that requires setting up a minimal pt_regs structure, |
537 | * interruption had occurred. To make syscall-restarts work, we setup pt_regs | 537 | * and initializing the CPU state more or less as if an |
538 | * such that cr_iip points to the second instruction in syscall_via_break. | 538 | * interruption had occurred. To make syscall-restarts work, |
539 | * Decrementing the IP hence will restart the syscall via break and not | 539 | * we setup pt_regs such that cr_iip points to the second |
540 | * decrementing IP will return us to the caller, as usual. Note that we preserve | 540 | * instruction in syscall_via_break. Decrementing the IP |
541 | * the value of psr.pp rather than initializing it from dcr.pp. This makes it | 541 | * hence will restart the syscall via break and not |
542 | * possible to distinguish fsyscall execution from other privileged execution. | 542 | * decrementing IP will return us to the caller, as usual. |
543 | * Note that we preserve the value of psr.pp rather than | ||
544 | * initializing it from dcr.pp. This makes it possible to | ||
545 | * distinguish fsyscall execution from other privileged | ||
546 | * execution. | ||
543 | * | 547 | * |
544 | * On entry: | 548 | * On entry: |
545 | * - normal fsyscall handler register usage, except that we also have: | 549 | * - normal fsyscall handler register usage, except |
550 | * that we also have: | ||
546 | * - r18: address of syscall entry point | 551 | * - r18: address of syscall entry point |
547 | * - r21: ar.fpsr | 552 | * - r21: ar.fpsr |
548 | * - r26: ar.pfs | 553 | * - r26: ar.pfs |
549 | * - r27: ar.rsc | 554 | * - r27: ar.rsc |
550 | * - r29: psr | 555 | * - r29: psr |
556 | * | ||
557 | * We used to clear some PSR bits here but that requires slow | ||
558 | * serialization. Fortuntely, that isn't really necessary. | ||
559 | * The rationale is as follows: we used to clear bits | ||
560 | * ~PSR_PRESERVED_BITS in PSR.L. Since | ||
561 | * PSR_PRESERVED_BITS==PSR.{UP,MFL,MFH,PK,DT,PP,SP,RT,IC}, we | ||
562 | * ended up clearing PSR.{BE,AC,I,DFL,DFH,DI,DB,SI,TB}. | ||
563 | * However, | ||
564 | * | ||
565 | * PSR.BE : already is turned off in __kernel_syscall_via_epc() | ||
566 | * PSR.AC : don't care (kernel normally turns PSR.AC on) | ||
567 | * PSR.I : already turned off by the time fsys_bubble_down gets | ||
568 | * invoked | ||
569 | * PSR.DFL: always 0 (kernel never turns it on) | ||
570 | * PSR.DFH: don't care --- kernel never touches f32-f127 on its own | ||
571 | * initiative | ||
572 | * PSR.DI : always 0 (kernel never turns it on) | ||
573 | * PSR.SI : always 0 (kernel never turns it on) | ||
574 | * PSR.DB : don't care --- kernel never enables kernel-level | ||
575 | * breakpoints | ||
576 | * PSR.TB : must be 0 already; if it wasn't zero on entry to | ||
577 | * __kernel_syscall_via_epc, the branch to fsys_bubble_down | ||
578 | * will trigger a taken branch; the taken-trap-handler then | ||
579 | * converts the syscall into a break-based system-call. | ||
551 | */ | 580 | */ |
552 | /* | 581 | /* |
553 | * Reading psr.l gives us only bits 0-31, psr.it, and psr.mc. The rest we have | 582 | * Reading psr.l gives us only bits 0-31, psr.it, and psr.mc. |
554 | * to synthesize. | 583 | * The rest we have to synthesize. |
555 | */ | 584 | */ |
556 | # define PSR_ONE_BITS ((3 << IA64_PSR_CPL0_BIT) | (0x1 << IA64_PSR_RI_BIT) \ | 585 | # define PSR_ONE_BITS ((3 << IA64_PSR_CPL0_BIT) \ |
586 | | (0x1 << IA64_PSR_RI_BIT) \ | ||
557 | | IA64_PSR_BN | IA64_PSR_I) | 587 | | IA64_PSR_BN | IA64_PSR_I) |
558 | 588 | ||
559 | invala | 589 | invala // M0|1 |
560 | movl r14=ia64_ret_from_syscall | 590 | movl r14=ia64_ret_from_syscall // X |
561 | 591 | ||
562 | nop.m 0 | 592 | nop.m 0 |
563 | movl r28=__kernel_syscall_via_break | 593 | movl r28=__kernel_syscall_via_break // X create cr.iip |
564 | ;; | 594 | ;; |
565 | 595 | ||
566 | mov r2=r16 // copy current task addr to addl-addressable register | 596 | mov r2=r16 // A get task addr to addl-addressable register |
567 | adds r16=IA64_TASK_THREAD_ON_USTACK_OFFSET,r16 | 597 | adds r16=IA64_TASK_THREAD_ON_USTACK_OFFSET,r16 // A |
568 | mov r31=pr // save pr (2 cyc) | 598 | mov r31=pr // I0 save pr (2 cyc) |
569 | ;; | 599 | ;; |
570 | st1 [r16]=r0 // clear current->thread.on_ustack flag | 600 | st1 [r16]=r0 // M2|3 clear current->thread.on_ustack flag |
571 | addl r22=IA64_RBS_OFFSET,r2 // compute base of RBS | 601 | addl r22=IA64_RBS_OFFSET,r2 // A compute base of RBS |
572 | add r3=TI_FLAGS+IA64_TASK_SIZE,r2 | 602 | add r3=TI_FLAGS+IA64_TASK_SIZE,r2 // A |
573 | ;; | 603 | ;; |
574 | ld4 r3=[r3] // r2 = current_thread_info()->flags | 604 | ld4 r3=[r3] // M0|1 r3 = current_thread_info()->flags |
575 | lfetch.fault.excl.nt1 [r22] | 605 | lfetch.fault.excl.nt1 [r22] // M0|1 prefetch register backing-store |
576 | nop.i 0 | 606 | nop.i 0 |
577 | ;; | 607 | ;; |
578 | mov ar.rsc=0 // set enforced lazy mode, pl 0, little-endian, loadrs=0 | 608 | mov ar.rsc=0 // M2 set enforced lazy mode, pl 0, LE, loadrs=0 |
579 | nop.m 0 | 609 | nop.m 0 |
580 | nop.i 0 | 610 | nop.i 0 |
581 | ;; | 611 | ;; |
582 | mov r23=ar.bspstore // save ar.bspstore (12 cyc) | 612 | mov r23=ar.bspstore // M2 (12 cyc) save ar.bspstore |
583 | mov.m r24=ar.rnat // read ar.rnat (5 cyc lat) | 613 | mov.m r24=ar.rnat // M2 (5 cyc) read ar.rnat (dual-issues!) |
584 | nop.i 0 | 614 | nop.i 0 |
585 | ;; | 615 | ;; |
586 | mov ar.bspstore=r22 // switch to kernel RBS | 616 | mov ar.bspstore=r22 // M2 (6 cyc) switch to kernel RBS |
587 | movl r8=PSR_ONE_BITS // X | 617 | movl r8=PSR_ONE_BITS // X |
588 | ;; | 618 | ;; |
589 | mov r25=ar.unat // save ar.unat (5 cyc) | 619 | mov r25=ar.unat // M2 (5 cyc) save ar.unat |
590 | mov r19=b6 // save b6 (2 cyc) | 620 | mov r19=b6 // I0 save b6 (2 cyc) |
591 | mov r20=r1 // save caller's gp in r20 | 621 | mov r20=r1 // A save caller's gp in r20 |
592 | ;; | 622 | ;; |
593 | or r29=r8,r29 // construct cr.ipsr value to save | 623 | or r29=r8,r29 // A construct cr.ipsr value to save |
594 | mov b6=r18 // copy syscall entry-point to b6 (7 cyc) | 624 | mov b6=r18 // I0 copy syscall entry-point to b6 (7 cyc) |
595 | addl r1=IA64_STK_OFFSET-IA64_PT_REGS_SIZE,r2 // compute base of memory stack | 625 | addl r1=IA64_STK_OFFSET-IA64_PT_REGS_SIZE,r2 // A compute base of memory stack |
596 | 626 | ||
597 | mov r18=ar.bsp // save (kernel) ar.bsp (12 cyc) | 627 | mov r18=ar.bsp // M2 save (kernel) ar.bsp (12 cyc) |
598 | cmp.ne pKStk,pUStk=r0,r0 // set pKStk <- 0, pUStk <- 1 | 628 | cmp.ne pKStk,pUStk=r0,r0 // A set pKStk <- 0, pUStk <- 1 |
599 | br.call.sptk.many b7=ia64_syscall_setup | 629 | br.call.sptk.many b7=ia64_syscall_setup // B |
600 | ;; | 630 | ;; |
601 | mov ar.rsc=0x3 // set eager mode, pl 0, little-endian, loadrs=0 | 631 | mov ar.rsc=0x3 // M2 set eager mode, pl 0, LE, loadrs=0 |
602 | mov rp=r14 // set the real return addr | 632 | mov rp=r14 // I0 set the real return addr |
603 | nop.i 0 | 633 | nop.i 0 |
604 | ;; | 634 | ;; |
605 | ssm psr.i | 635 | ssm psr.i // M2 we're on kernel stacks now, reenable irqs |
606 | tbit.z p8,p0=r3,TIF_SYSCALL_TRACE | 636 | tbit.z p8,p0=r3,TIF_SYSCALL_TRACE // I0 |
607 | (p10) br.cond.spnt.many ia64_ret_from_syscall // p10==true means out registers are more than 8 | 637 | (p10) br.cond.spnt.many ia64_ret_from_syscall // B return if bad call-frame or r15 is a NaT |
608 | 638 | ||
609 | nop.m 0 | 639 | nop.m 0 |
610 | (p8) br.call.sptk.many b6=b6 // ignore this return addr | 640 | (p8) br.call.sptk.many b6=b6 // B (ignore return address) |
611 | br.cond.spnt ia64_trace_syscall | 641 | br.cond.spnt ia64_trace_syscall // B |
612 | END(fsys_bubble_down) | 642 | END(fsys_bubble_down) |
613 | 643 | ||
614 | .rodata | 644 | .rodata |