diff options
Diffstat (limited to 'arch/s390/kernel/entry64.S')
-rw-r--r-- | arch/s390/kernel/entry64.S | 111 |
1 files changed, 82 insertions, 29 deletions
diff --git a/arch/s390/kernel/entry64.S b/arch/s390/kernel/entry64.S index d61967e2eab0..7a0fd426ca92 100644 --- a/arch/s390/kernel/entry64.S +++ b/arch/s390/kernel/entry64.S | |||
@@ -9,8 +9,8 @@ | |||
9 | * Heiko Carstens <heiko.carstens@de.ibm.com> | 9 | * Heiko Carstens <heiko.carstens@de.ibm.com> |
10 | */ | 10 | */ |
11 | 11 | ||
12 | #include <linux/linkage.h> | ||
13 | #include <linux/init.h> | 12 | #include <linux/init.h> |
13 | #include <linux/linkage.h> | ||
14 | #include <asm/cache.h> | 14 | #include <asm/cache.h> |
15 | #include <asm/errno.h> | 15 | #include <asm/errno.h> |
16 | #include <asm/ptrace.h> | 16 | #include <asm/ptrace.h> |
@@ -56,15 +56,28 @@ _TIF_WORK_INT = (_TIF_SIGPENDING | _TIF_NOTIFY_RESUME | _TIF_NEED_RESCHED | \ | |||
56 | _TIF_MCCK_PENDING) | 56 | _TIF_MCCK_PENDING) |
57 | _TIF_SYSCALL = (_TIF_SYSCALL_TRACE>>8 | _TIF_SYSCALL_AUDIT>>8 | \ | 57 | _TIF_SYSCALL = (_TIF_SYSCALL_TRACE>>8 | _TIF_SYSCALL_AUDIT>>8 | \ |
58 | _TIF_SECCOMP>>8 | _TIF_SYSCALL_TRACEPOINT>>8) | 58 | _TIF_SECCOMP>>8 | _TIF_SYSCALL_TRACEPOINT>>8) |
59 | _TIF_EXIT_SIE = (_TIF_SIGPENDING | _TIF_NEED_RESCHED | _TIF_MCCK_PENDING) | ||
59 | 60 | ||
60 | #define BASED(name) name-system_call(%r13) | 61 | #define BASED(name) name-system_call(%r13) |
61 | 62 | ||
63 | .macro SPP newpp | ||
64 | #if defined(CONFIG_KVM) || defined(CONFIG_KVM_MODULE) | ||
65 | tm __LC_MACHINE_FLAGS+6,0x20 # MACHINE_FLAG_SPP | ||
66 | jz .+8 | ||
67 | .insn s,0xb2800000,\newpp | ||
68 | #endif | ||
69 | .endm | ||
70 | |||
62 | .macro HANDLE_SIE_INTERCEPT | 71 | .macro HANDLE_SIE_INTERCEPT |
63 | #if defined(CONFIG_KVM) || defined(CONFIG_KVM_MODULE) | 72 | #if defined(CONFIG_KVM) || defined(CONFIG_KVM_MODULE) |
64 | lg %r3,__LC_SIE_HOOK | 73 | tm __TI_flags+6(%r12),_TIF_SIE>>8 |
65 | ltgr %r3,%r3 | ||
66 | jz 0f | 74 | jz 0f |
67 | basr %r14,%r3 | 75 | SPP __LC_CMF_HPP # set host id |
76 | clc SP_PSW+8(8,%r15),BASED(.Lsie_loop) | ||
77 | jl 0f | ||
78 | clc SP_PSW+8(8,%r15),BASED(.Lsie_done) | ||
79 | jhe 0f | ||
80 | mvc SP_PSW+8(8,%r15),BASED(.Lsie_loop) | ||
68 | 0: | 81 | 0: |
69 | #endif | 82 | #endif |
70 | .endm | 83 | .endm |
@@ -206,8 +219,7 @@ _TIF_SYSCALL = (_TIF_SYSCALL_TRACE>>8 | _TIF_SYSCALL_AUDIT>>8 | \ | |||
206 | * Returns: | 219 | * Returns: |
207 | * gpr2 = prev | 220 | * gpr2 = prev |
208 | */ | 221 | */ |
209 | .globl __switch_to | 222 | ENTRY(__switch_to) |
210 | __switch_to: | ||
211 | lg %r4,__THREAD_info(%r2) # get thread_info of prev | 223 | lg %r4,__THREAD_info(%r2) # get thread_info of prev |
212 | lg %r5,__THREAD_info(%r3) # get thread_info of next | 224 | lg %r5,__THREAD_info(%r3) # get thread_info of next |
213 | tm __TI_flags+7(%r4),_TIF_MCCK_PENDING # machine check pending? | 225 | tm __TI_flags+7(%r4),_TIF_MCCK_PENDING # machine check pending? |
@@ -232,8 +244,7 @@ __critical_start: | |||
232 | * are executed with interrupts enabled. | 244 | * are executed with interrupts enabled. |
233 | */ | 245 | */ |
234 | 246 | ||
235 | .globl system_call | 247 | ENTRY(system_call) |
236 | system_call: | ||
237 | stpt __LC_SYNC_ENTER_TIMER | 248 | stpt __LC_SYNC_ENTER_TIMER |
238 | sysc_saveall: | 249 | sysc_saveall: |
239 | SAVE_ALL_SVC __LC_SVC_OLD_PSW,__LC_SAVE_AREA | 250 | SAVE_ALL_SVC __LC_SVC_OLD_PSW,__LC_SAVE_AREA |
@@ -395,8 +406,7 @@ sysc_tracenogo: | |||
395 | # | 406 | # |
396 | # a new process exits the kernel with ret_from_fork | 407 | # a new process exits the kernel with ret_from_fork |
397 | # | 408 | # |
398 | .globl ret_from_fork | 409 | ENTRY(ret_from_fork) |
399 | ret_from_fork: | ||
400 | lg %r13,__LC_SVC_NEW_PSW+8 | 410 | lg %r13,__LC_SVC_NEW_PSW+8 |
401 | lg %r12,__LC_THREAD_INFO # load pointer to thread_info struct | 411 | lg %r12,__LC_THREAD_INFO # load pointer to thread_info struct |
402 | tm SP_PSW+1(%r15),0x01 # forking a kernel thread ? | 412 | tm SP_PSW+1(%r15),0x01 # forking a kernel thread ? |
@@ -411,8 +421,7 @@ ret_from_fork: | |||
411 | # kernel_execve function needs to deal with pt_regs that is not | 421 | # kernel_execve function needs to deal with pt_regs that is not |
412 | # at the usual place | 422 | # at the usual place |
413 | # | 423 | # |
414 | .globl kernel_execve | 424 | ENTRY(kernel_execve) |
415 | kernel_execve: | ||
416 | stmg %r12,%r15,96(%r15) | 425 | stmg %r12,%r15,96(%r15) |
417 | lgr %r14,%r15 | 426 | lgr %r14,%r15 |
418 | aghi %r15,-SP_SIZE | 427 | aghi %r15,-SP_SIZE |
@@ -442,8 +451,7 @@ kernel_execve: | |||
442 | * Program check handler routine | 451 | * Program check handler routine |
443 | */ | 452 | */ |
444 | 453 | ||
445 | .globl pgm_check_handler | 454 | ENTRY(pgm_check_handler) |
446 | pgm_check_handler: | ||
447 | /* | 455 | /* |
448 | * First we need to check for a special case: | 456 | * First we need to check for a special case: |
449 | * Single stepping an instruction that disables the PER event mask will | 457 | * Single stepping an instruction that disables the PER event mask will |
@@ -465,6 +473,7 @@ pgm_check_handler: | |||
465 | xc SP_ILC(4,%r15),SP_ILC(%r15) | 473 | xc SP_ILC(4,%r15),SP_ILC(%r15) |
466 | mvc SP_PSW(16,%r15),__LC_PGM_OLD_PSW | 474 | mvc SP_PSW(16,%r15),__LC_PGM_OLD_PSW |
467 | lg %r12,__LC_THREAD_INFO # load pointer to thread_info struct | 475 | lg %r12,__LC_THREAD_INFO # load pointer to thread_info struct |
476 | HANDLE_SIE_INTERCEPT | ||
468 | tm SP_PSW+1(%r15),0x01 # interrupting from user ? | 477 | tm SP_PSW+1(%r15),0x01 # interrupting from user ? |
469 | jz pgm_no_vtime | 478 | jz pgm_no_vtime |
470 | UPDATE_VTIME __LC_EXIT_TIMER,__LC_SYNC_ENTER_TIMER,__LC_USER_TIMER | 479 | UPDATE_VTIME __LC_EXIT_TIMER,__LC_SYNC_ENTER_TIMER,__LC_USER_TIMER |
@@ -472,7 +481,6 @@ pgm_check_handler: | |||
472 | mvc __LC_LAST_UPDATE_TIMER(8),__LC_SYNC_ENTER_TIMER | 481 | mvc __LC_LAST_UPDATE_TIMER(8),__LC_SYNC_ENTER_TIMER |
473 | LAST_BREAK | 482 | LAST_BREAK |
474 | pgm_no_vtime: | 483 | pgm_no_vtime: |
475 | HANDLE_SIE_INTERCEPT | ||
476 | stg %r11,SP_ARGS(%r15) | 484 | stg %r11,SP_ARGS(%r15) |
477 | lgf %r3,__LC_PGM_ILC # load program interruption code | 485 | lgf %r3,__LC_PGM_ILC # load program interruption code |
478 | lg %r4,__LC_TRANS_EXC_CODE | 486 | lg %r4,__LC_TRANS_EXC_CODE |
@@ -507,6 +515,7 @@ pgm_per_std: | |||
507 | CREATE_STACK_FRAME __LC_SAVE_AREA | 515 | CREATE_STACK_FRAME __LC_SAVE_AREA |
508 | mvc SP_PSW(16,%r15),__LC_PGM_OLD_PSW | 516 | mvc SP_PSW(16,%r15),__LC_PGM_OLD_PSW |
509 | lg %r12,__LC_THREAD_INFO # load pointer to thread_info struct | 517 | lg %r12,__LC_THREAD_INFO # load pointer to thread_info struct |
518 | HANDLE_SIE_INTERCEPT | ||
510 | tm SP_PSW+1(%r15),0x01 # interrupting from user ? | 519 | tm SP_PSW+1(%r15),0x01 # interrupting from user ? |
511 | jz pgm_no_vtime2 | 520 | jz pgm_no_vtime2 |
512 | UPDATE_VTIME __LC_EXIT_TIMER,__LC_SYNC_ENTER_TIMER,__LC_USER_TIMER | 521 | UPDATE_VTIME __LC_EXIT_TIMER,__LC_SYNC_ENTER_TIMER,__LC_USER_TIMER |
@@ -514,7 +523,6 @@ pgm_per_std: | |||
514 | mvc __LC_LAST_UPDATE_TIMER(8),__LC_SYNC_ENTER_TIMER | 523 | mvc __LC_LAST_UPDATE_TIMER(8),__LC_SYNC_ENTER_TIMER |
515 | LAST_BREAK | 524 | LAST_BREAK |
516 | pgm_no_vtime2: | 525 | pgm_no_vtime2: |
517 | HANDLE_SIE_INTERCEPT | ||
518 | lg %r1,__TI_task(%r12) | 526 | lg %r1,__TI_task(%r12) |
519 | tm SP_PSW+1(%r15),0x01 # kernel per event ? | 527 | tm SP_PSW+1(%r15),0x01 # kernel per event ? |
520 | jz kernel_per | 528 | jz kernel_per |
@@ -571,14 +579,14 @@ kernel_per: | |||
571 | /* | 579 | /* |
572 | * IO interrupt handler routine | 580 | * IO interrupt handler routine |
573 | */ | 581 | */ |
574 | .globl io_int_handler | 582 | ENTRY(io_int_handler) |
575 | io_int_handler: | ||
576 | stck __LC_INT_CLOCK | 583 | stck __LC_INT_CLOCK |
577 | stpt __LC_ASYNC_ENTER_TIMER | 584 | stpt __LC_ASYNC_ENTER_TIMER |
578 | SAVE_ALL_ASYNC __LC_IO_OLD_PSW,__LC_SAVE_AREA+40 | 585 | SAVE_ALL_ASYNC __LC_IO_OLD_PSW,__LC_SAVE_AREA+40 |
579 | CREATE_STACK_FRAME __LC_SAVE_AREA+40 | 586 | CREATE_STACK_FRAME __LC_SAVE_AREA+40 |
580 | mvc SP_PSW(16,%r15),0(%r12) # move user PSW to stack | 587 | mvc SP_PSW(16,%r15),0(%r12) # move user PSW to stack |
581 | lg %r12,__LC_THREAD_INFO # load pointer to thread_info struct | 588 | lg %r12,__LC_THREAD_INFO # load pointer to thread_info struct |
589 | HANDLE_SIE_INTERCEPT | ||
582 | tm SP_PSW+1(%r15),0x01 # interrupting from user ? | 590 | tm SP_PSW+1(%r15),0x01 # interrupting from user ? |
583 | jz io_no_vtime | 591 | jz io_no_vtime |
584 | UPDATE_VTIME __LC_EXIT_TIMER,__LC_ASYNC_ENTER_TIMER,__LC_USER_TIMER | 592 | UPDATE_VTIME __LC_EXIT_TIMER,__LC_ASYNC_ENTER_TIMER,__LC_USER_TIMER |
@@ -586,7 +594,6 @@ io_int_handler: | |||
586 | mvc __LC_LAST_UPDATE_TIMER(8),__LC_ASYNC_ENTER_TIMER | 594 | mvc __LC_LAST_UPDATE_TIMER(8),__LC_ASYNC_ENTER_TIMER |
587 | LAST_BREAK | 595 | LAST_BREAK |
588 | io_no_vtime: | 596 | io_no_vtime: |
589 | HANDLE_SIE_INTERCEPT | ||
590 | TRACE_IRQS_OFF | 597 | TRACE_IRQS_OFF |
591 | la %r2,SP_PTREGS(%r15) # address of register-save area | 598 | la %r2,SP_PTREGS(%r15) # address of register-save area |
592 | brasl %r14,do_IRQ # call standard irq handler | 599 | brasl %r14,do_IRQ # call standard irq handler |
@@ -706,14 +713,14 @@ io_notify_resume: | |||
706 | /* | 713 | /* |
707 | * External interrupt handler routine | 714 | * External interrupt handler routine |
708 | */ | 715 | */ |
709 | .globl ext_int_handler | 716 | ENTRY(ext_int_handler) |
710 | ext_int_handler: | ||
711 | stck __LC_INT_CLOCK | 717 | stck __LC_INT_CLOCK |
712 | stpt __LC_ASYNC_ENTER_TIMER | 718 | stpt __LC_ASYNC_ENTER_TIMER |
713 | SAVE_ALL_ASYNC __LC_EXT_OLD_PSW,__LC_SAVE_AREA+40 | 719 | SAVE_ALL_ASYNC __LC_EXT_OLD_PSW,__LC_SAVE_AREA+40 |
714 | CREATE_STACK_FRAME __LC_SAVE_AREA+40 | 720 | CREATE_STACK_FRAME __LC_SAVE_AREA+40 |
715 | mvc SP_PSW(16,%r15),0(%r12) # move user PSW to stack | 721 | mvc SP_PSW(16,%r15),0(%r12) # move user PSW to stack |
716 | lg %r12,__LC_THREAD_INFO # load pointer to thread_info struct | 722 | lg %r12,__LC_THREAD_INFO # load pointer to thread_info struct |
723 | HANDLE_SIE_INTERCEPT | ||
717 | tm SP_PSW+1(%r15),0x01 # interrupting from user ? | 724 | tm SP_PSW+1(%r15),0x01 # interrupting from user ? |
718 | jz ext_no_vtime | 725 | jz ext_no_vtime |
719 | UPDATE_VTIME __LC_EXIT_TIMER,__LC_ASYNC_ENTER_TIMER,__LC_USER_TIMER | 726 | UPDATE_VTIME __LC_EXIT_TIMER,__LC_ASYNC_ENTER_TIMER,__LC_USER_TIMER |
@@ -721,7 +728,6 @@ ext_int_handler: | |||
721 | mvc __LC_LAST_UPDATE_TIMER(8),__LC_ASYNC_ENTER_TIMER | 728 | mvc __LC_LAST_UPDATE_TIMER(8),__LC_ASYNC_ENTER_TIMER |
722 | LAST_BREAK | 729 | LAST_BREAK |
723 | ext_no_vtime: | 730 | ext_no_vtime: |
724 | HANDLE_SIE_INTERCEPT | ||
725 | TRACE_IRQS_OFF | 731 | TRACE_IRQS_OFF |
726 | lghi %r1,4096 | 732 | lghi %r1,4096 |
727 | la %r2,SP_PTREGS(%r15) # address of register-save area | 733 | la %r2,SP_PTREGS(%r15) # address of register-save area |
@@ -736,8 +742,7 @@ __critical_end: | |||
736 | /* | 742 | /* |
737 | * Machine check handler routines | 743 | * Machine check handler routines |
738 | */ | 744 | */ |
739 | .globl mcck_int_handler | 745 | ENTRY(mcck_int_handler) |
740 | mcck_int_handler: | ||
741 | stck __LC_MCCK_CLOCK | 746 | stck __LC_MCCK_CLOCK |
742 | la %r1,4095 # revalidate r1 | 747 | la %r1,4095 # revalidate r1 |
743 | spt __LC_CPU_TIMER_SAVE_AREA-4095(%r1) # revalidate cpu timer | 748 | spt __LC_CPU_TIMER_SAVE_AREA-4095(%r1) # revalidate cpu timer |
@@ -785,6 +790,7 @@ mcck_int_main: | |||
785 | lg %r12,__LC_THREAD_INFO # load pointer to thread_info struct | 790 | lg %r12,__LC_THREAD_INFO # load pointer to thread_info struct |
786 | tm __LC_MCCK_CODE+2,0x08 # mwp of old psw valid? | 791 | tm __LC_MCCK_CODE+2,0x08 # mwp of old psw valid? |
787 | jno mcck_no_vtime # no -> no timer update | 792 | jno mcck_no_vtime # no -> no timer update |
793 | HANDLE_SIE_INTERCEPT | ||
788 | tm SP_PSW+1(%r15),0x01 # interrupting from user ? | 794 | tm SP_PSW+1(%r15),0x01 # interrupting from user ? |
789 | jz mcck_no_vtime | 795 | jz mcck_no_vtime |
790 | UPDATE_VTIME __LC_EXIT_TIMER,__LC_MCCK_ENTER_TIMER,__LC_USER_TIMER | 796 | UPDATE_VTIME __LC_EXIT_TIMER,__LC_MCCK_ENTER_TIMER,__LC_USER_TIMER |
@@ -804,7 +810,6 @@ mcck_no_vtime: | |||
804 | stosm __SF_EMPTY(%r15),0x04 # turn dat on | 810 | stosm __SF_EMPTY(%r15),0x04 # turn dat on |
805 | tm __TI_flags+7(%r12),_TIF_MCCK_PENDING | 811 | tm __TI_flags+7(%r12),_TIF_MCCK_PENDING |
806 | jno mcck_return | 812 | jno mcck_return |
807 | HANDLE_SIE_INTERCEPT | ||
808 | TRACE_IRQS_OFF | 813 | TRACE_IRQS_OFF |
809 | brasl %r14,s390_handle_mcck | 814 | brasl %r14,s390_handle_mcck |
810 | TRACE_IRQS_ON | 815 | TRACE_IRQS_ON |
@@ -823,8 +828,7 @@ mcck_done: | |||
823 | */ | 828 | */ |
824 | #ifdef CONFIG_SMP | 829 | #ifdef CONFIG_SMP |
825 | __CPUINIT | 830 | __CPUINIT |
826 | .globl restart_int_handler | 831 | ENTRY(restart_int_handler) |
827 | restart_int_handler: | ||
828 | basr %r1,0 | 832 | basr %r1,0 |
829 | restart_base: | 833 | restart_base: |
830 | spt restart_vtime-restart_base(%r1) | 834 | spt restart_vtime-restart_base(%r1) |
@@ -851,8 +855,7 @@ restart_vtime: | |||
851 | /* | 855 | /* |
852 | * If we do not run with SMP enabled, let the new CPU crash ... | 856 | * If we do not run with SMP enabled, let the new CPU crash ... |
853 | */ | 857 | */ |
854 | .globl restart_int_handler | 858 | ENTRY(restart_int_handler) |
855 | restart_int_handler: | ||
856 | basr %r1,0 | 859 | basr %r1,0 |
857 | restart_base: | 860 | restart_base: |
858 | lpswe restart_crash-restart_base(%r1) | 861 | lpswe restart_crash-restart_base(%r1) |
@@ -1036,6 +1039,56 @@ cleanup_io_restore_insn: | |||
1036 | .Lcritical_end: | 1039 | .Lcritical_end: |
1037 | .quad __critical_end | 1040 | .quad __critical_end |
1038 | 1041 | ||
1042 | #if defined(CONFIG_KVM) || defined(CONFIG_KVM_MODULE) | ||
1043 | /* | ||
1044 | * sie64a calling convention: | ||
1045 | * %r2 pointer to sie control block | ||
1046 | * %r3 guest register save area | ||
1047 | */ | ||
1048 | ENTRY(sie64a) | ||
1049 | stmg %r6,%r14,__SF_GPRS(%r15) # save kernel registers | ||
1050 | stg %r2,__SF_EMPTY(%r15) # save control block pointer | ||
1051 | stg %r3,__SF_EMPTY+8(%r15) # save guest register save area | ||
1052 | lmg %r0,%r13,0(%r3) # load guest gprs 0-13 | ||
1053 | lg %r14,__LC_THREAD_INFO # pointer thread_info struct | ||
1054 | oi __TI_flags+6(%r14),_TIF_SIE>>8 | ||
1055 | sie_loop: | ||
1056 | lg %r14,__LC_THREAD_INFO # pointer thread_info struct | ||
1057 | tm __TI_flags+7(%r14),_TIF_EXIT_SIE | ||
1058 | jnz sie_exit | ||
1059 | lg %r14,__SF_EMPTY(%r15) # get control block pointer | ||
1060 | SPP __SF_EMPTY(%r15) # set guest id | ||
1061 | sie 0(%r14) | ||
1062 | sie_done: | ||
1063 | SPP __LC_CMF_HPP # set host id | ||
1064 | lg %r14,__LC_THREAD_INFO # pointer thread_info struct | ||
1065 | sie_exit: | ||
1066 | ni __TI_flags+6(%r14),255-(_TIF_SIE>>8) | ||
1067 | lg %r14,__SF_EMPTY+8(%r15) # load guest register save area | ||
1068 | stmg %r0,%r13,0(%r14) # save guest gprs 0-13 | ||
1069 | lmg %r6,%r14,__SF_GPRS(%r15) # restore kernel registers | ||
1070 | lghi %r2,0 | ||
1071 | br %r14 | ||
1072 | sie_fault: | ||
1073 | lg %r14,__LC_THREAD_INFO # pointer thread_info struct | ||
1074 | ni __TI_flags+6(%r14),255-(_TIF_SIE>>8) | ||
1075 | lg %r14,__SF_EMPTY+8(%r15) # load guest register save area | ||
1076 | stmg %r0,%r13,0(%r14) # save guest gprs 0-13 | ||
1077 | lmg %r6,%r14,__SF_GPRS(%r15) # restore kernel registers | ||
1078 | lghi %r2,-EFAULT | ||
1079 | br %r14 | ||
1080 | |||
1081 | .align 8 | ||
1082 | .Lsie_loop: | ||
1083 | .quad sie_loop | ||
1084 | .Lsie_done: | ||
1085 | .quad sie_done | ||
1086 | |||
1087 | .section __ex_table,"a" | ||
1088 | .quad sie_loop,sie_fault | ||
1089 | .previous | ||
1090 | #endif | ||
1091 | |||
1039 | .section .rodata, "a" | 1092 | .section .rodata, "a" |
1040 | #define SYSCALL(esa,esame,emu) .long esame | 1093 | #define SYSCALL(esa,esame,emu) .long esame |
1041 | .globl sys_call_table | 1094 | .globl sys_call_table |