| /* SPDX-License-Identifier: GPL-2.0-only */ |
| /* |
| * s390x assembly macros |
| * |
| * Copyright (c) 2017 Red Hat Inc |
| * Copyright (c) 2020, 2021 IBM Corp. |
| * |
| * Authors: |
| * Janosch Frank <frankja@linux.ibm.com> |
| * Pierre Morel <pmorel@linux.ibm.com> |
| * David Hildenbrand <david@redhat.com> |
| */ |
| #include <asm/asm-offsets.h> |
| /* |
| * Exception handler macro that saves registers on the stack, |
| * allocates stack space and calls the C handler function. Afterwards |
| * we re-load the registers and load the old PSW. |
| */ |
| .macro CALL_INT_HANDLER c_func, old_psw |
| SAVE_REGS_STACK |
| /* Save the stack address in GR2 which is the first function argument */ |
| lgr %r2, %r15 |
| /* Allocate stack space for called C function, as specified in s390 ELF ABI */ |
| slgfi %r15, STACK_FRAME_SIZE |
| /* |
| * Save the address of the interrupt stack into the back chain |
| * of the called function. |
| */ |
| stg %r2, STACK_FRAME_INT_BACKCHAIN(%r15) |
| brasl %r14, \c_func |
| algfi %r15, STACK_FRAME_SIZE |
| RESTORE_REGS_STACK |
| lpswe \old_psw |
| .endm |
| |
| /* Save registers on the stack (r15), so we can have stacked interrupts. */ |
| .macro SAVE_REGS_STACK |
| /* Allocate a full stack frame */ |
| slgfi %r15, STACK_FRAME_INT_SIZE |
| /* Store registers r0 to r14 on the stack */ |
| stmg %r2, %r15, STACK_FRAME_INT_GRS0(%r15) |
| stg %r0, STACK_FRAME_INT_GRS1(%r15) |
| stg %r1, STACK_FRAME_INT_GRS1 + 8(%r15) |
| /* Store the gr15 value before we allocated the new stack */ |
| lgr %r0, %r15 |
| algfi %r0, STACK_FRAME_INT_SIZE |
| stg %r0, 13 * 8 + STACK_FRAME_INT_GRS0(%r15) |
| stg %r0, STACK_FRAME_INT_BACKCHAIN(%r15) |
| /* |
| * Store CR0 and load initial CR0 so AFP is active and we can |
| * access all fprs to save them. |
| */ |
| stctg %c0,%c15,STACK_FRAME_INT_CRS(%r15) |
| larl %r1, initial_cr0 |
| lctlg %c0, %c0, 0(%r1) |
| /* Save fp register on stack: offset to SP is multiple of reg number */ |
| .irp i, 0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15 |
| std \i, \i * 8 + STACK_FRAME_INT_FPRS(%r15) |
| .endr |
| /* Save fpc */ |
| stfpc STACK_FRAME_INT_FPC(%r15) |
| .endm |
| |
| /* Restore the register in reverse order */ |
| .macro RESTORE_REGS_STACK |
| /* Restore fpc */ |
| lfpc STACK_FRAME_INT_FPC(%r15) |
| /* Restore fp register from stack: SP still where it was left */ |
| /* and offset to SP is a multiple of reg number */ |
| .irp i, 0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15 |
| ld \i, \i * 8 + STACK_FRAME_INT_FPRS(%r15) |
| .endr |
| /* Load CR0 back */ |
| lctlg %c0, %c15, STACK_FRAME_INT_CRS(%r15) |
| /* Load the registers from stack */ |
| lg %r0, STACK_FRAME_INT_GRS1(%r15) |
| lg %r1, STACK_FRAME_INT_GRS1 + 8(%r15) |
| lmg %r2, %r15, STACK_FRAME_INT_GRS0(%r15) |
| .endm |