| /* |
| * Copyright (C) 2012,2013 - ARM Ltd |
| * Author: Marc Zyngier <marc.zyngier@arm.com> |
| * |
| * This program is free software; you can redistribute it and/or modify |
| * it under the terms of the GNU General Public License version 2 as |
| * published by the Free Software Foundation. |
| * |
| * This program is distributed in the hope that it will be useful, |
| * but WITHOUT ANY WARRANTY; without even the implied warranty of |
| * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
| * GNU General Public License for more details. |
| * |
| * You should have received a copy of the GNU General Public License |
| * along with this program. If not, see <http://www.gnu.org/licenses/>. |
| */ |
| |
| #include <linux/linkage.h> |
| #include <linux/irqchip/arm-gic.h> |
| |
| #include <asm/assembler.h> |
| #include <asm/memory.h> |
| #include <asm/asm-offsets.h> |
| #include <asm/kvm.h> |
| #include <asm/kvm_asm.h> |
| #include <asm/kvm_arm.h> |
| #include <asm/kvm_mmu.h> |
| |
| .text |
| .pushsection .hyp.text, "ax" |
| |
| /* |
| * Save the VGIC CPU state into memory |
| * x0: Register pointing to VCPU struct |
| * Do not corrupt x1!!! |
| */ |
| ENTRY(__save_vgic_v2_state) |
| __save_vgic_v2_state: |
| /* Get VGIC VCTRL base into x2 */ |
| ldr x2, [x0, #VCPU_KVM] |
| kern_hyp_va x2 |
| ldr x2, [x2, #KVM_VGIC_VCTRL] |
| kern_hyp_va x2 |
| cbz x2, 2f // disabled |
| |
| /* Compute the address of struct vgic_cpu */ |
| add x3, x0, #VCPU_VGIC_CPU |
| |
| /* Save all interesting registers */ |
| ldr w4, [x2, #GICH_HCR] |
| ldr w5, [x2, #GICH_VMCR] |
| ldr w6, [x2, #GICH_MISR] |
| ldr w7, [x2, #GICH_EISR0] |
| ldr w8, [x2, #GICH_EISR1] |
| ldr w9, [x2, #GICH_ELRSR0] |
| ldr w10, [x2, #GICH_ELRSR1] |
| ldr w11, [x2, #GICH_APR] |
| CPU_BE( rev w4, w4 ) |
| CPU_BE( rev w5, w5 ) |
| CPU_BE( rev w6, w6 ) |
| CPU_BE( rev w7, w7 ) |
| CPU_BE( rev w8, w8 ) |
| CPU_BE( rev w9, w9 ) |
| CPU_BE( rev w10, w10 ) |
| CPU_BE( rev w11, w11 ) |
| |
| str w4, [x3, #VGIC_V2_CPU_HCR] |
| str w5, [x3, #VGIC_V2_CPU_VMCR] |
| str w6, [x3, #VGIC_V2_CPU_MISR] |
| CPU_LE( str w7, [x3, #VGIC_V2_CPU_EISR] ) |
| CPU_LE( str w8, [x3, #(VGIC_V2_CPU_EISR + 4)] ) |
| CPU_LE( str w9, [x3, #VGIC_V2_CPU_ELRSR] ) |
| CPU_LE( str w10, [x3, #(VGIC_V2_CPU_ELRSR + 4)] ) |
| CPU_BE( str w7, [x3, #(VGIC_V2_CPU_EISR + 4)] ) |
| CPU_BE( str w8, [x3, #VGIC_V2_CPU_EISR] ) |
| CPU_BE( str w9, [x3, #(VGIC_V2_CPU_ELRSR + 4)] ) |
| CPU_BE( str w10, [x3, #VGIC_V2_CPU_ELRSR] ) |
| str w11, [x3, #VGIC_V2_CPU_APR] |
| |
| /* Clear GICH_HCR */ |
| str wzr, [x2, #GICH_HCR] |
| |
| /* Save list registers */ |
| add x2, x2, #GICH_LR0 |
| ldr w4, [x3, #VGIC_CPU_NR_LR] |
| add x3, x3, #VGIC_V2_CPU_LR |
| 1: ldr w5, [x2], #4 |
| CPU_BE( rev w5, w5 ) |
| str w5, [x3], #4 |
| sub w4, w4, #1 |
| cbnz w4, 1b |
| 2: |
| ret |
| ENDPROC(__save_vgic_v2_state) |
| |
| /* |
| * Restore the VGIC CPU state from memory |
| * x0: Register pointing to VCPU struct |
| */ |
| ENTRY(__restore_vgic_v2_state) |
| __restore_vgic_v2_state: |
| /* Get VGIC VCTRL base into x2 */ |
| ldr x2, [x0, #VCPU_KVM] |
| kern_hyp_va x2 |
| ldr x2, [x2, #KVM_VGIC_VCTRL] |
| kern_hyp_va x2 |
| cbz x2, 2f // disabled |
| |
| /* Compute the address of struct vgic_cpu */ |
| add x3, x0, #VCPU_VGIC_CPU |
| |
| /* We only restore a minimal set of registers */ |
| ldr w4, [x3, #VGIC_V2_CPU_HCR] |
| ldr w5, [x3, #VGIC_V2_CPU_VMCR] |
| ldr w6, [x3, #VGIC_V2_CPU_APR] |
| CPU_BE( rev w4, w4 ) |
| CPU_BE( rev w5, w5 ) |
| CPU_BE( rev w6, w6 ) |
| |
| str w4, [x2, #GICH_HCR] |
| str w5, [x2, #GICH_VMCR] |
| str w6, [x2, #GICH_APR] |
| |
| /* Restore list registers */ |
| add x2, x2, #GICH_LR0 |
| ldr w4, [x3, #VGIC_CPU_NR_LR] |
| add x3, x3, #VGIC_V2_CPU_LR |
| 1: ldr w5, [x3], #4 |
| CPU_BE( rev w5, w5 ) |
| str w5, [x2], #4 |
| sub w4, w4, #1 |
| cbnz w4, 1b |
| 2: |
| ret |
| ENDPROC(__restore_vgic_v2_state) |
| |
| .popsection |