aboutsummaryrefslogtreecommitdiffstats
path: root/arch/ia64/kernel/fsys.S
diff options
context:
space:
mode:
Diffstat (limited to 'arch/ia64/kernel/fsys.S')
-rw-r--r--arch/ia64/kernel/fsys.S118
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
612END(fsys_bubble_down) 642END(fsys_bubble_down)
613 643
614 .rodata 644 .rodata