diff options
Diffstat (limited to 'arch/s390/kernel/entry.S')
-rw-r--r-- | arch/s390/kernel/entry.S | 159 |
1 files changed, 88 insertions, 71 deletions
diff --git a/arch/s390/kernel/entry.S b/arch/s390/kernel/entry.S index 3705700ed37..74ee563fe62 100644 --- a/arch/s390/kernel/entry.S +++ b/arch/s390/kernel/entry.S | |||
@@ -2,7 +2,7 @@ | |||
2 | * arch/s390/kernel/entry.S | 2 | * arch/s390/kernel/entry.S |
3 | * S390 low-level entry points. | 3 | * S390 low-level entry points. |
4 | * | 4 | * |
5 | * Copyright (C) IBM Corp. 1999,2006 | 5 | * Copyright (C) IBM Corp. 1999,2012 |
6 | * Author(s): Martin Schwidefsky (schwidefsky@de.ibm.com), | 6 | * Author(s): Martin Schwidefsky (schwidefsky@de.ibm.com), |
7 | * Hartmut Penner (hp@de.ibm.com), | 7 | * Hartmut Penner (hp@de.ibm.com), |
8 | * Denis Joseph Barrow (djbarrow@de.ibm.com,barrow_dj@yahoo.com), | 8 | * Denis Joseph Barrow (djbarrow@de.ibm.com,barrow_dj@yahoo.com), |
@@ -105,14 +105,14 @@ STACK_SIZE = 1 << STACK_SHIFT | |||
105 | 105 | ||
106 | .macro ADD64 high,low,timer | 106 | .macro ADD64 high,low,timer |
107 | al \high,\timer | 107 | al \high,\timer |
108 | al \low,\timer+4 | 108 | al \low,4+\timer |
109 | brc 12,.+8 | 109 | brc 12,.+8 |
110 | ahi \high,1 | 110 | ahi \high,1 |
111 | .endm | 111 | .endm |
112 | 112 | ||
113 | .macro SUB64 high,low,timer | 113 | .macro SUB64 high,low,timer |
114 | sl \high,\timer | 114 | sl \high,\timer |
115 | sl \low,\timer+4 | 115 | sl \low,4+\timer |
116 | brc 3,.+8 | 116 | brc 3,.+8 |
117 | ahi \high,-1 | 117 | ahi \high,-1 |
118 | .endm | 118 | .endm |
@@ -471,7 +471,6 @@ io_tif: | |||
471 | jnz io_work # there is work to do (signals etc.) | 471 | jnz io_work # there is work to do (signals etc.) |
472 | io_restore: | 472 | io_restore: |
473 | mvc __LC_RETURN_PSW(8),__PT_PSW(%r11) | 473 | mvc __LC_RETURN_PSW(8),__PT_PSW(%r11) |
474 | ni __LC_RETURN_PSW+1,0xfd # clean wait state bit | ||
475 | stpt __LC_EXIT_TIMER | 474 | stpt __LC_EXIT_TIMER |
476 | lm %r0,%r15,__PT_R0(%r11) | 475 | lm %r0,%r15,__PT_R0(%r11) |
477 | lpsw __LC_RETURN_PSW | 476 | lpsw __LC_RETURN_PSW |
@@ -606,12 +605,32 @@ ext_skip: | |||
606 | stm %r8,%r9,__PT_PSW(%r11) | 605 | stm %r8,%r9,__PT_PSW(%r11) |
607 | TRACE_IRQS_OFF | 606 | TRACE_IRQS_OFF |
608 | lr %r2,%r11 # pass pointer to pt_regs | 607 | lr %r2,%r11 # pass pointer to pt_regs |
609 | l %r3,__LC_CPU_ADDRESS # get cpu address + interruption code | 608 | l %r3,__LC_EXT_CPU_ADDR # get cpu address + interruption code |
610 | l %r4,__LC_EXT_PARAMS # get external parameters | 609 | l %r4,__LC_EXT_PARAMS # get external parameters |
611 | l %r1,BASED(.Ldo_extint) | 610 | l %r1,BASED(.Ldo_extint) |
612 | basr %r14,%r1 # call do_extint | 611 | basr %r14,%r1 # call do_extint |
613 | j io_return | 612 | j io_return |
614 | 613 | ||
614 | /* | ||
615 | * Load idle PSW. The second "half" of this function is in cleanup_idle. | ||
616 | */ | ||
617 | ENTRY(psw_idle) | ||
618 | st %r4,__SF_EMPTY(%r15) | ||
619 | basr %r1,0 | ||
620 | la %r1,psw_idle_lpsw+4-.(%r1) | ||
621 | st %r1,__SF_EMPTY+4(%r15) | ||
622 | oi __SF_EMPTY+4(%r15),0x80 | ||
623 | la %r1,.Lvtimer_max-psw_idle_lpsw-4(%r1) | ||
624 | stck __IDLE_ENTER(%r2) | ||
625 | ltr %r5,%r5 | ||
626 | stpt __VQ_IDLE_ENTER(%r3) | ||
627 | jz psw_idle_lpsw | ||
628 | spt 0(%r1) | ||
629 | psw_idle_lpsw: | ||
630 | lpsw __SF_EMPTY(%r15) | ||
631 | br %r14 | ||
632 | psw_idle_end: | ||
633 | |||
615 | __critical_end: | 634 | __critical_end: |
616 | 635 | ||
617 | /* | 636 | /* |
@@ -673,7 +692,6 @@ mcck_skip: | |||
673 | TRACE_IRQS_ON | 692 | TRACE_IRQS_ON |
674 | mcck_return: | 693 | mcck_return: |
675 | mvc __LC_RETURN_MCCK_PSW(8),__PT_PSW(%r11) # move return PSW | 694 | mvc __LC_RETURN_MCCK_PSW(8),__PT_PSW(%r11) # move return PSW |
676 | ni __LC_RETURN_MCCK_PSW+1,0xfd # clear wait state bit | ||
677 | tm __LC_RETURN_MCCK_PSW+1,0x01 # returning to user ? | 695 | tm __LC_RETURN_MCCK_PSW+1,0x01 # returning to user ? |
678 | jno 0f | 696 | jno 0f |
679 | lm %r0,%r15,__PT_R0(%r11) | 697 | lm %r0,%r15,__PT_R0(%r11) |
@@ -691,77 +709,30 @@ mcck_panic: | |||
691 | 0: ahi %r15,-(STACK_FRAME_OVERHEAD + __PT_SIZE) | 709 | 0: ahi %r15,-(STACK_FRAME_OVERHEAD + __PT_SIZE) |
692 | j mcck_skip | 710 | j mcck_skip |
693 | 711 | ||
694 | /* | ||
695 | * Restart interruption handler, kick starter for additional CPUs | ||
696 | */ | ||
697 | #ifdef CONFIG_SMP | ||
698 | __CPUINIT | ||
699 | ENTRY(restart_int_handler) | ||
700 | basr %r1,0 | ||
701 | restart_base: | ||
702 | spt restart_vtime-restart_base(%r1) | ||
703 | stck __LC_LAST_UPDATE_CLOCK | ||
704 | mvc __LC_LAST_UPDATE_TIMER(8),restart_vtime-restart_base(%r1) | ||
705 | mvc __LC_EXIT_TIMER(8),restart_vtime-restart_base(%r1) | ||
706 | l %r15,__LC_GPREGS_SAVE_AREA+60 # load ksp | ||
707 | lctl %c0,%c15,__LC_CREGS_SAVE_AREA # get new ctl regs | ||
708 | lam %a0,%a15,__LC_AREGS_SAVE_AREA | ||
709 | lm %r6,%r15,__SF_GPRS(%r15)# load registers from clone | ||
710 | l %r1,__LC_THREAD_INFO | ||
711 | mvc __LC_USER_TIMER(8),__TI_user_timer(%r1) | ||
712 | mvc __LC_SYSTEM_TIMER(8),__TI_system_timer(%r1) | ||
713 | xc __LC_STEAL_TIMER(8),__LC_STEAL_TIMER | ||
714 | ssm __LC_PGM_NEW_PSW # turn dat on, keep irqs off | ||
715 | basr %r14,0 | ||
716 | l %r14,restart_addr-.(%r14) | ||
717 | basr %r14,%r14 # call start_secondary | ||
718 | restart_addr: | ||
719 | .long start_secondary | ||
720 | .align 8 | ||
721 | restart_vtime: | ||
722 | .long 0x7fffffff,0xffffffff | ||
723 | .previous | ||
724 | #else | ||
725 | /* | ||
726 | * If we do not run with SMP enabled, let the new CPU crash ... | ||
727 | */ | ||
728 | ENTRY(restart_int_handler) | ||
729 | basr %r1,0 | ||
730 | restart_base: | ||
731 | lpsw restart_crash-restart_base(%r1) | ||
732 | .align 8 | ||
733 | restart_crash: | ||
734 | .long 0x000a0000,0x00000000 | ||
735 | restart_go: | ||
736 | #endif | ||
737 | |||
738 | # | 712 | # |
739 | # PSW restart interrupt handler | 713 | # PSW restart interrupt handler |
740 | # | 714 | # |
741 | ENTRY(psw_restart_int_handler) | 715 | ENTRY(restart_int_handler) |
742 | st %r15,__LC_SAVE_AREA_RESTART | 716 | st %r15,__LC_SAVE_AREA_RESTART |
743 | basr %r15,0 | 717 | l %r15,__LC_RESTART_STACK |
744 | 0: l %r15,.Lrestart_stack-0b(%r15) # load restart stack | ||
745 | l %r15,0(%r15) | ||
746 | ahi %r15,-__PT_SIZE # create pt_regs on stack | 718 | ahi %r15,-__PT_SIZE # create pt_regs on stack |
719 | xc 0(__PT_SIZE,%r15),0(%r15) | ||
747 | stm %r0,%r14,__PT_R0(%r15) | 720 | stm %r0,%r14,__PT_R0(%r15) |
748 | mvc __PT_R15(4,%r15),__LC_SAVE_AREA_RESTART | 721 | mvc __PT_R15(4,%r15),__LC_SAVE_AREA_RESTART |
749 | mvc __PT_PSW(8,%r15),__LC_RST_OLD_PSW # store restart old psw | 722 | mvc __PT_PSW(8,%r15),__LC_RST_OLD_PSW # store restart old psw |
750 | ahi %r15,-STACK_FRAME_OVERHEAD | 723 | ahi %r15,-STACK_FRAME_OVERHEAD # create stack frame on stack |
751 | xc __SF_BACKCHAIN(4,%r15),__SF_BACKCHAIN(%r15) | 724 | xc 0(STACK_FRAME_OVERHEAD,%r15),0(%r15) |
752 | basr %r14,0 | 725 | lm %r1,%r3,__LC_RESTART_FN # load fn, parm & source cpu |
753 | 1: l %r14,.Ldo_restart-1b(%r14) | 726 | ltr %r3,%r3 # test source cpu address |
754 | basr %r14,%r14 | 727 | jm 1f # negative -> skip source stop |
755 | basr %r14,0 # load disabled wait PSW if | 728 | 0: sigp %r4,%r3,1 # sigp sense to source cpu |
756 | 2: lpsw restart_psw_crash-2b(%r14) # do_restart returns | 729 | brc 10,0b # wait for status stored |
757 | .align 4 | 730 | 1: basr %r14,%r1 # call function |
758 | .Ldo_restart: | 731 | stap __SF_EMPTY(%r15) # store cpu address |
759 | .long do_restart | 732 | lh %r3,__SF_EMPTY(%r15) |
760 | .Lrestart_stack: | 733 | 2: sigp %r4,%r3,5 # sigp stop to current cpu |
761 | .long restart_stack | 734 | brc 2,2b |
762 | .align 8 | 735 | 3: j 3b |
763 | restart_psw_crash: | ||
764 | .long 0x000a0000,0x00000000 + restart_psw_crash | ||
765 | 736 | ||
766 | .section .kprobes.text, "ax" | 737 | .section .kprobes.text, "ax" |
767 | 738 | ||
@@ -795,6 +766,8 @@ cleanup_table: | |||
795 | .long io_tif + 0x80000000 | 766 | .long io_tif + 0x80000000 |
796 | .long io_restore + 0x80000000 | 767 | .long io_restore + 0x80000000 |
797 | .long io_done + 0x80000000 | 768 | .long io_done + 0x80000000 |
769 | .long psw_idle + 0x80000000 | ||
770 | .long psw_idle_end + 0x80000000 | ||
798 | 771 | ||
799 | cleanup_critical: | 772 | cleanup_critical: |
800 | cl %r9,BASED(cleanup_table) # system_call | 773 | cl %r9,BASED(cleanup_table) # system_call |
@@ -813,6 +786,10 @@ cleanup_critical: | |||
813 | jl cleanup_io_tif | 786 | jl cleanup_io_tif |
814 | cl %r9,BASED(cleanup_table+28) # io_done | 787 | cl %r9,BASED(cleanup_table+28) # io_done |
815 | jl cleanup_io_restore | 788 | jl cleanup_io_restore |
789 | cl %r9,BASED(cleanup_table+32) # psw_idle | ||
790 | jl 0f | ||
791 | cl %r9,BASED(cleanup_table+36) # psw_idle_end | ||
792 | jl cleanup_idle | ||
816 | 0: br %r14 | 793 | 0: br %r14 |
817 | 794 | ||
818 | cleanup_system_call: | 795 | cleanup_system_call: |
@@ -896,7 +873,6 @@ cleanup_io_restore: | |||
896 | jhe 0f | 873 | jhe 0f |
897 | l %r9,12(%r11) # get saved r11 pointer to pt_regs | 874 | l %r9,12(%r11) # get saved r11 pointer to pt_regs |
898 | mvc __LC_RETURN_PSW(8),__PT_PSW(%r9) | 875 | mvc __LC_RETURN_PSW(8),__PT_PSW(%r9) |
899 | ni __LC_RETURN_PSW+1,0xfd # clear wait state bit | ||
900 | mvc 0(32,%r11),__PT_R8(%r9) | 876 | mvc 0(32,%r11),__PT_R8(%r9) |
901 | lm %r0,%r7,__PT_R0(%r9) | 877 | lm %r0,%r7,__PT_R0(%r9) |
902 | 0: lm %r8,%r9,__LC_RETURN_PSW | 878 | 0: lm %r8,%r9,__LC_RETURN_PSW |
@@ -904,11 +880,52 @@ cleanup_io_restore: | |||
904 | cleanup_io_restore_insn: | 880 | cleanup_io_restore_insn: |
905 | .long io_done - 4 + 0x80000000 | 881 | .long io_done - 4 + 0x80000000 |
906 | 882 | ||
883 | cleanup_idle: | ||
884 | # copy interrupt clock & cpu timer | ||
885 | mvc __IDLE_EXIT(8,%r2),__LC_INT_CLOCK | ||
886 | mvc __VQ_IDLE_EXIT(8,%r3),__LC_ASYNC_ENTER_TIMER | ||
887 | chi %r11,__LC_SAVE_AREA_ASYNC | ||
888 | je 0f | ||
889 | mvc __IDLE_EXIT(8,%r2),__LC_MCCK_CLOCK | ||
890 | mvc __VQ_IDLE_EXIT(8,%r3),__LC_MCCK_ENTER_TIMER | ||
891 | 0: # check if stck has been executed | ||
892 | cl %r9,BASED(cleanup_idle_insn) | ||
893 | jhe 1f | ||
894 | mvc __IDLE_ENTER(8,%r2),__IDLE_EXIT(%r2) | ||
895 | mvc __VQ_IDLE_ENTER(8,%r3),__VQ_IDLE_EXIT(%r3) | ||
896 | j 2f | ||
897 | 1: # check if the cpu timer has been reprogrammed | ||
898 | ltr %r5,%r5 | ||
899 | jz 2f | ||
900 | spt __VQ_IDLE_ENTER(%r3) | ||
901 | 2: # account system time going idle | ||
902 | lm %r9,%r10,__LC_STEAL_TIMER | ||
903 | ADD64 %r9,%r10,__IDLE_ENTER(%r2) | ||
904 | SUB64 %r9,%r10,__LC_LAST_UPDATE_CLOCK | ||
905 | stm %r9,%r10,__LC_STEAL_TIMER | ||
906 | mvc __LC_LAST_UPDATE_CLOCK(8),__IDLE_EXIT(%r2) | ||
907 | lm %r9,%r10,__LC_SYSTEM_TIMER | ||
908 | ADD64 %r9,%r10,__LC_LAST_UPDATE_TIMER | ||
909 | SUB64 %r9,%r10,__VQ_IDLE_ENTER(%r3) | ||
910 | stm %r9,%r10,__LC_SYSTEM_TIMER | ||
911 | mvc __LC_LAST_UPDATE_TIMER(8),__VQ_IDLE_EXIT(%r3) | ||
912 | # prepare return psw | ||
913 | n %r8,BASED(cleanup_idle_wait) # clear wait state bit | ||
914 | l %r9,24(%r11) # return from psw_idle | ||
915 | br %r14 | ||
916 | cleanup_idle_insn: | ||
917 | .long psw_idle_lpsw + 0x80000000 | ||
918 | cleanup_idle_wait: | ||
919 | .long 0xfffdffff | ||
920 | |||
907 | /* | 921 | /* |
908 | * Integer constants | 922 | * Integer constants |
909 | */ | 923 | */ |
910 | .align 4 | 924 | .align 4 |
911 | .Lnr_syscalls: .long NR_syscalls | 925 | .Lnr_syscalls: |
926 | .long NR_syscalls | ||
927 | .Lvtimer_max: | ||
928 | .quad 0x7fffffffffffffff | ||
912 | 929 | ||
913 | /* | 930 | /* |
914 | * Symbol constants | 931 | * Symbol constants |