linux/arch/arm64/kernel/hyp-stub.S
<<
>>
Prefs
   1/*
   2 * Hypervisor stub
   3 *
   4 * Copyright (C) 2012 ARM Ltd.
   5 * Author:      Marc Zyngier <marc.zyngier@arm.com>
   6 *
   7 * This program is free software; you can redistribute it and/or modify
   8 * it under the terms of the GNU General Public License version 2 as
   9 * published by the Free Software Foundation.
  10 *
  11 * This program is distributed in the hope that it will be useful,
  12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
  13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  14 * GNU General Public License for more details.
  15 *
  16 * You should have received a copy of the GNU General Public License
  17 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
  18 */
  19
  20#include <linux/init.h>
  21#include <linux/linkage.h>
  22#include <linux/irqchip/arm-gic-v3.h>
  23
  24#include <asm/assembler.h>
  25#include <asm/kvm_arm.h>
  26#include <asm/kvm_asm.h>
  27#include <asm/ptrace.h>
  28#include <asm/virt.h>
  29
  30        .text
  31        .align 11
  32
  33ENTRY(__hyp_stub_vectors)
  34        ventry  el2_sync_invalid                // Synchronous EL2t
  35        ventry  el2_irq_invalid                 // IRQ EL2t
  36        ventry  el2_fiq_invalid                 // FIQ EL2t
  37        ventry  el2_error_invalid               // Error EL2t
  38
  39        ventry  el2_sync_invalid                // Synchronous EL2h
  40        ventry  el2_irq_invalid                 // IRQ EL2h
  41        ventry  el2_fiq_invalid                 // FIQ EL2h
  42        ventry  el2_error_invalid               // Error EL2h
  43
  44        ventry  el1_sync                        // Synchronous 64-bit EL1
  45        ventry  el1_irq_invalid                 // IRQ 64-bit EL1
  46        ventry  el1_fiq_invalid                 // FIQ 64-bit EL1
  47        ventry  el1_error_invalid               // Error 64-bit EL1
  48
  49        ventry  el1_sync_invalid                // Synchronous 32-bit EL1
  50        ventry  el1_irq_invalid                 // IRQ 32-bit EL1
  51        ventry  el1_fiq_invalid                 // FIQ 32-bit EL1
  52        ventry  el1_error_invalid               // Error 32-bit EL1
  53ENDPROC(__hyp_stub_vectors)
  54
  55        .align 11
  56
  57el1_sync:
  58        cmp     x0, #HVC_SET_VECTORS
  59        b.ne    2f
  60        msr     vbar_el2, x1
  61        b       9f
  62
  632:      cmp     x0, #HVC_SOFT_RESTART
  64        b.ne    3f
  65        mov     x0, x2
  66        mov     x2, x4
  67        mov     x4, x1
  68        mov     x1, x3
  69        br      x4                              // no return
  70
  713:      cmp     x0, #HVC_RESET_VECTORS
  72        beq     9f                              // Nothing to reset!
  73
  74        /* Someone called kvm_call_hyp() against the hyp-stub... */
  75        ldr     x0, =HVC_STUB_ERR
  76        eret
  77
  789:      mov     x0, xzr
  79        eret
  80ENDPROC(el1_sync)
  81
  82.macro invalid_vector   label
  83\label:
  84        b \label
  85ENDPROC(\label)
  86.endm
  87
  88        invalid_vector  el2_sync_invalid
  89        invalid_vector  el2_irq_invalid
  90        invalid_vector  el2_fiq_invalid
  91        invalid_vector  el2_error_invalid
  92        invalid_vector  el1_sync_invalid
  93        invalid_vector  el1_irq_invalid
  94        invalid_vector  el1_fiq_invalid
  95        invalid_vector  el1_error_invalid
  96
  97/*
  98 * __hyp_set_vectors: Call this after boot to set the initial hypervisor
  99 * vectors as part of hypervisor installation.  On an SMP system, this should
 100 * be called on each CPU.
 101 *
 102 * x0 must be the physical address of the new vector table, and must be
 103 * 2KB aligned.
 104 *
 105 * Before calling this, you must check that the stub hypervisor is installed
 106 * everywhere, by waiting for any secondary CPUs to be brought up and then
 107 * checking that is_hyp_mode_available() is true.
 108 *
 109 * If not, there is a pre-existing hypervisor, some CPUs failed to boot, or
 110 * something else went wrong... in such cases, trying to install a new
 111 * hypervisor is unlikely to work as desired.
 112 *
 113 * When you call into your shiny new hypervisor, sp_el2 will contain junk,
 114 * so you will need to set that to something sensible at the new hypervisor's
 115 * initialisation entry point.
 116 */
 117
 118ENTRY(__hyp_set_vectors)
 119        mov     x1, x0
 120        mov     x0, #HVC_SET_VECTORS
 121        hvc     #0
 122        ret
 123ENDPROC(__hyp_set_vectors)
 124
 125ENTRY(__hyp_reset_vectors)
 126        mov     x0, #HVC_RESET_VECTORS
 127        hvc     #0
 128        ret
 129ENDPROC(__hyp_reset_vectors)
 130