diff options
author | Martin Schwidefsky <schwidefsky@de.ibm.com> | 2013-05-17 08:41:37 -0400 |
---|---|---|
committer | Gleb Natapov <gleb@redhat.com> | 2013-05-21 04:55:26 -0400 |
commit | 7c470539c95630c1f2a10f109e96f249730b75eb (patch) | |
tree | b3d518e9d6d92eb157ace9aa864dd3515c4e216b /arch/s390/kernel/entry64.S | |
parent | 2c70fe4416d5f6d092b20ebf7d7654835e09c109 (diff) |
s390/kvm: avoid automatic sie reentry
Do not automatically restart the sie instruction in entry64.S after an
interrupt, return to the caller with a reason code instead. That allows
to deal with RCU and other conditions in C code.
Signed-off-by: Martin Schwidefsky <schwidefsky@de.ibm.com>
Signed-off-by: Christian Borntraeger <borntraeger@de.ibm.com>
Signed-off-by: Gleb Natapov <gleb@redhat.com>
Diffstat (limited to 'arch/s390/kernel/entry64.S')
-rw-r--r-- | arch/s390/kernel/entry64.S | 76 |
1 files changed, 33 insertions, 43 deletions
diff --git a/arch/s390/kernel/entry64.S b/arch/s390/kernel/entry64.S index c7daeefb9864..51d99acc16fd 100644 --- a/arch/s390/kernel/entry64.S +++ b/arch/s390/kernel/entry64.S | |||
@@ -47,7 +47,6 @@ _TIF_WORK_INT = (_TIF_SIGPENDING | _TIF_NOTIFY_RESUME | _TIF_NEED_RESCHED | \ | |||
47 | _TIF_MCCK_PENDING) | 47 | _TIF_MCCK_PENDING) |
48 | _TIF_TRACE = (_TIF_SYSCALL_TRACE | _TIF_SYSCALL_AUDIT | _TIF_SECCOMP | \ | 48 | _TIF_TRACE = (_TIF_SYSCALL_TRACE | _TIF_SYSCALL_AUDIT | _TIF_SECCOMP | \ |
49 | _TIF_SYSCALL_TRACEPOINT) | 49 | _TIF_SYSCALL_TRACEPOINT) |
50 | _TIF_EXIT_SIE = (_TIF_SIGPENDING | _TIF_NEED_RESCHED | _TIF_MCCK_PENDING) | ||
51 | 50 | ||
52 | #define BASED(name) name-system_call(%r13) | 51 | #define BASED(name) name-system_call(%r13) |
53 | 52 | ||
@@ -81,25 +80,27 @@ _TIF_EXIT_SIE = (_TIF_SIGPENDING | _TIF_NEED_RESCHED | _TIF_MCCK_PENDING) | |||
81 | #endif | 80 | #endif |
82 | .endm | 81 | .endm |
83 | 82 | ||
84 | .macro HANDLE_SIE_INTERCEPT scratch,pgmcheck | 83 | .macro HANDLE_SIE_INTERCEPT scratch,reason |
85 | #if defined(CONFIG_KVM) || defined(CONFIG_KVM_MODULE) | 84 | #if defined(CONFIG_KVM) || defined(CONFIG_KVM_MODULE) |
86 | tmhh %r8,0x0001 # interrupting from user ? | 85 | tmhh %r8,0x0001 # interrupting from user ? |
87 | jnz .+52 | 86 | jnz .+62 |
88 | lgr \scratch,%r9 | 87 | lgr \scratch,%r9 |
89 | slg \scratch,BASED(.Lsie_loop) | 88 | slg \scratch,BASED(.Lsie_critical) |
90 | clg \scratch,BASED(.Lsie_length) | 89 | clg \scratch,BASED(.Lsie_critical_length) |
91 | .if \pgmcheck | 90 | .if \reason==1 |
92 | # Some program interrupts are suppressing (e.g. protection). | 91 | # Some program interrupts are suppressing (e.g. protection). |
93 | # We must also check the instruction after SIE in that case. | 92 | # We must also check the instruction after SIE in that case. |
94 | # do_protection_exception will rewind to rewind_pad | 93 | # do_protection_exception will rewind to rewind_pad |
95 | jh .+32 | 94 | jh .+42 |
96 | .else | 95 | .else |
97 | jhe .+32 | 96 | jhe .+42 |
98 | .endif | 97 | .endif |
99 | lg %r9,BASED(.Lsie_loop) | 98 | lg %r14,__SF_EMPTY(%r15) # get control block pointer |
100 | LPP BASED(.Lhost_id) # set host id | 99 | LPP __SF_EMPTY+16(%r15) # set host id |
101 | lg %r14,__SF_EMPTY(%r15) # get control block pointer | ||
102 | ni __SIE_PROG0C+3(%r14),0xfe # no longer in SIE | 100 | ni __SIE_PROG0C+3(%r14),0xfe # no longer in SIE |
101 | lctlg %c1,%c1,__LC_USER_ASCE # load primary asce | ||
102 | larl %r9,sie_exit # skip forward to sie_exit | ||
103 | mvi __SF_EMPTY+31(%r15),\reason # set exit reason | ||
103 | #endif | 104 | #endif |
104 | .endm | 105 | .endm |
105 | 106 | ||
@@ -452,7 +453,7 @@ ENTRY(io_int_handler) | |||
452 | lg %r12,__LC_THREAD_INFO | 453 | lg %r12,__LC_THREAD_INFO |
453 | larl %r13,system_call | 454 | larl %r13,system_call |
454 | lmg %r8,%r9,__LC_IO_OLD_PSW | 455 | lmg %r8,%r9,__LC_IO_OLD_PSW |
455 | HANDLE_SIE_INTERCEPT %r14,0 | 456 | HANDLE_SIE_INTERCEPT %r14,2 |
456 | SWITCH_ASYNC __LC_SAVE_AREA_ASYNC,__LC_ASYNC_STACK,STACK_SHIFT | 457 | SWITCH_ASYNC __LC_SAVE_AREA_ASYNC,__LC_ASYNC_STACK,STACK_SHIFT |
457 | tmhh %r8,0x0001 # interrupting from user? | 458 | tmhh %r8,0x0001 # interrupting from user? |
458 | jz io_skip | 459 | jz io_skip |
@@ -597,7 +598,7 @@ ENTRY(ext_int_handler) | |||
597 | lg %r12,__LC_THREAD_INFO | 598 | lg %r12,__LC_THREAD_INFO |
598 | larl %r13,system_call | 599 | larl %r13,system_call |
599 | lmg %r8,%r9,__LC_EXT_OLD_PSW | 600 | lmg %r8,%r9,__LC_EXT_OLD_PSW |
600 | HANDLE_SIE_INTERCEPT %r14,0 | 601 | HANDLE_SIE_INTERCEPT %r14,3 |
601 | SWITCH_ASYNC __LC_SAVE_AREA_ASYNC,__LC_ASYNC_STACK,STACK_SHIFT | 602 | SWITCH_ASYNC __LC_SAVE_AREA_ASYNC,__LC_ASYNC_STACK,STACK_SHIFT |
602 | tmhh %r8,0x0001 # interrupting from user ? | 603 | tmhh %r8,0x0001 # interrupting from user ? |
603 | jz ext_skip | 604 | jz ext_skip |
@@ -645,7 +646,7 @@ ENTRY(mcck_int_handler) | |||
645 | lg %r12,__LC_THREAD_INFO | 646 | lg %r12,__LC_THREAD_INFO |
646 | larl %r13,system_call | 647 | larl %r13,system_call |
647 | lmg %r8,%r9,__LC_MCK_OLD_PSW | 648 | lmg %r8,%r9,__LC_MCK_OLD_PSW |
648 | HANDLE_SIE_INTERCEPT %r14,0 | 649 | HANDLE_SIE_INTERCEPT %r14,4 |
649 | tm __LC_MCCK_CODE,0x80 # system damage? | 650 | tm __LC_MCCK_CODE,0x80 # system damage? |
650 | jo mcck_panic # yes -> rest of mcck code invalid | 651 | jo mcck_panic # yes -> rest of mcck code invalid |
651 | lghi %r14,__LC_CPU_TIMER_SAVE_AREA | 652 | lghi %r14,__LC_CPU_TIMER_SAVE_AREA |
@@ -939,19 +940,8 @@ ENTRY(sie64a) | |||
939 | stmg %r6,%r14,__SF_GPRS(%r15) # save kernel registers | 940 | stmg %r6,%r14,__SF_GPRS(%r15) # save kernel registers |
940 | stg %r2,__SF_EMPTY(%r15) # save control block pointer | 941 | stg %r2,__SF_EMPTY(%r15) # save control block pointer |
941 | stg %r3,__SF_EMPTY+8(%r15) # save guest register save area | 942 | stg %r3,__SF_EMPTY+8(%r15) # save guest register save area |
942 | xc __SF_EMPTY+16(8,%r15),__SF_EMPTY+16(%r15) # host id == 0 | 943 | xc __SF_EMPTY+16(16,%r15),__SF_EMPTY+16(%r15) # host id & reason |
943 | lmg %r0,%r13,0(%r3) # load guest gprs 0-13 | 944 | lmg %r0,%r13,0(%r3) # load guest gprs 0-13 |
944 | # some program checks are suppressing. C code (e.g. do_protection_exception) | ||
945 | # will rewind the PSW by the ILC, which is 4 bytes in case of SIE. Other | ||
946 | # instructions in the sie_loop should not cause program interrupts. So | ||
947 | # lets use a nop (47 00 00 00) as a landing pad. | ||
948 | # See also HANDLE_SIE_INTERCEPT | ||
949 | rewind_pad: | ||
950 | nop 0 | ||
951 | sie_loop: | ||
952 | lg %r14,__LC_THREAD_INFO # pointer thread_info struct | ||
953 | tm __TI_flags+7(%r14),_TIF_EXIT_SIE | ||
954 | jnz sie_exit | ||
955 | lg %r14,__LC_GMAP # get gmap pointer | 945 | lg %r14,__LC_GMAP # get gmap pointer |
956 | ltgr %r14,%r14 | 946 | ltgr %r14,%r14 |
957 | jz sie_gmap | 947 | jz sie_gmap |
@@ -966,33 +956,33 @@ sie_gmap: | |||
966 | sie_done: | 956 | sie_done: |
967 | LPP __SF_EMPTY+16(%r15) # set host id | 957 | LPP __SF_EMPTY+16(%r15) # set host id |
968 | ni __SIE_PROG0C+3(%r14),0xfe # no longer in SIE | 958 | ni __SIE_PROG0C+3(%r14),0xfe # no longer in SIE |
969 | lg %r14,__LC_THREAD_INFO # pointer thread_info struct | ||
970 | sie_exit: | ||
971 | lctlg %c1,%c1,__LC_USER_ASCE # load primary asce | 959 | lctlg %c1,%c1,__LC_USER_ASCE # load primary asce |
960 | # some program checks are suppressing. C code (e.g. do_protection_exception) | ||
961 | # will rewind the PSW by the ILC, which is 4 bytes in case of SIE. Other | ||
962 | # instructions beween sie64a and sie_done should not cause program | ||
963 | # interrupts. So lets use a nop (47 00 00 00) as a landing pad. | ||
964 | # See also HANDLE_SIE_INTERCEPT | ||
965 | rewind_pad: | ||
966 | nop 0 | ||
967 | sie_exit: | ||
972 | lg %r14,__SF_EMPTY+8(%r15) # load guest register save area | 968 | lg %r14,__SF_EMPTY+8(%r15) # load guest register save area |
973 | stmg %r0,%r13,0(%r14) # save guest gprs 0-13 | 969 | stmg %r0,%r13,0(%r14) # save guest gprs 0-13 |
974 | lmg %r6,%r14,__SF_GPRS(%r15) # restore kernel registers | 970 | lmg %r6,%r14,__SF_GPRS(%r15) # restore kernel registers |
975 | lghi %r2,0 | 971 | lg %r2,__SF_EMPTY+24(%r15) # return exit reason code |
976 | br %r14 | 972 | br %r14 |
977 | sie_fault: | 973 | sie_fault: |
978 | lctlg %c1,%c1,__LC_USER_ASCE # load primary asce | 974 | lghi %r14,-EFAULT |
979 | lg %r14,__LC_THREAD_INFO # pointer thread_info struct | 975 | stg %r14,__SF_EMPTY+24(%r15) # set exit reason code |
980 | lg %r14,__SF_EMPTY+8(%r15) # load guest register save area | 976 | j sie_exit |
981 | stmg %r0,%r13,0(%r14) # save guest gprs 0-13 | ||
982 | lmg %r6,%r14,__SF_GPRS(%r15) # restore kernel registers | ||
983 | lghi %r2,-EFAULT | ||
984 | br %r14 | ||
985 | 977 | ||
986 | .align 8 | 978 | .align 8 |
987 | .Lsie_loop: | 979 | .Lsie_critical: |
988 | .quad sie_loop | 980 | .quad sie_gmap |
989 | .Lsie_length: | 981 | .Lsie_critical_length: |
990 | .quad sie_done - sie_loop | 982 | .quad sie_done - sie_gmap |
991 | .Lhost_id: | ||
992 | .quad 0 | ||
993 | 983 | ||
994 | EX_TABLE(rewind_pad,sie_fault) | 984 | EX_TABLE(rewind_pad,sie_fault) |
995 | EX_TABLE(sie_loop,sie_fault) | 985 | EX_TABLE(sie_exit,sie_fault) |
996 | #endif | 986 | #endif |
997 | 987 | ||
998 | .section .rodata, "a" | 988 | .section .rodata, "a" |