/*-1* SPDX-License-Identifier: BSD-2-Clause2*3* Copyright (C) 2017 Alexandru Elisei <[email protected]>4* Copyright (c) 2021 Andrew Turner5*6* This software was developed by Alexandru Elisei under sponsorship7* from the FreeBSD Foundation.8*9* Redistribution and use in source and binary forms, with or without10* modification, are permitted provided that the following conditions11* are met:12* 1. Redistributions of source code must retain the above copyright13* notice, this list of conditions and the following disclaimer.14* 2. Redistributions in binary form must reproduce the above copyright15* notice, this list of conditions and the following disclaimer in the16* documentation and/or other materials provided with the distribution.17*18* THIS SOFTWARE IS PROVIDED BY AUTHOR AND CONTRIBUTORS ``AS IS'' AND19* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE20* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE21* ARE DISCLAIMED. IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE22* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL23* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS24* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)25* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT26* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY27* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF28* SUCH DAMAGE.29*/303132#include <sys/elf_common.h>33#include <machine/asm.h>34#include <machine/hypervisor.h>3536#include "assym.inc"37#include "hyp.h"3839.macro save_host_registers40/* TODO: Only store callee saved registers */41sub sp, sp, #(32 * 8)42str x30, [sp, #(30 * 8)]43stp x28, x29, [sp, #(28 * 8)]44stp x26, x27, [sp, #(26 * 8)]45stp x24, x25, [sp, #(24 * 8)]46stp x22, x23, [sp, #(22 * 8)]47stp x20, x21, [sp, #(20 * 8)]48stp x18, x19, [sp, #(18 * 8)]49stp x16, x17, [sp, #(16 * 8)]50stp x14, x15, [sp, #(14 * 8)]51stp x12, x13, [sp, #(12 * 8)]52stp x10, x11, [sp, #(10 * 8)]53stp x8, x9, [sp, #(8 * 8)]54stp x6, x7, [sp, #(6 * 8)]55stp x4, x5, [sp, #(4 * 8)]56stp x2, x3, [sp, #(2 * 8)]57stp x0, x1, [sp, #(0 * 8)]58.endm5960.macro restore_host_registers61/* TODO: Only restore callee saved registers */62ldp x0, x1, [sp, #(0 * 8)]63ldp x2, x3, [sp, #(2 * 8)]64ldp x4, x5, [sp, #(4 * 8)]65ldp x6, x7, [sp, #(6 * 8)]66ldp x8, x9, [sp, #(8 * 8)]67ldp x10, x11, [sp, #(10 * 8)]68ldp x12, x13, [sp, #(12 * 8)]69ldp x14, x15, [sp, #(14 * 8)]70ldp x16, x17, [sp, #(16 * 8)]71ldp x18, x19, [sp, #(18 * 8)]72ldp x20, x21, [sp, #(20 * 8)]73ldp x22, x23, [sp, #(22 * 8)]74ldp x24, x25, [sp, #(24 * 8)]75ldp x26, x27, [sp, #(26 * 8)]76ldp x28, x29, [sp, #(28 * 8)]77ldr x30, [sp, #(30 * 8)]78add sp, sp, #(32 * 8)79.endm8081.macro save_guest_registers82/* Back up x0 so we can use it as a temporary register */83stp x0, x1, [sp, #-(2 * 8)]!8485/* Restore the hypctx pointer */86mrs x0, tpidr_el28788stp x2, x3, [x0, #(TF_X + 2 * 8)]89stp x4, x5, [x0, #(TF_X + 4 * 8)]90stp x6, x7, [x0, #(TF_X + 6 * 8)]91stp x8, x9, [x0, #(TF_X + 8 * 8)]92stp x10, x11, [x0, #(TF_X + 10 * 8)]93stp x12, x13, [x0, #(TF_X + 12 * 8)]94stp x14, x15, [x0, #(TF_X + 14 * 8)]95stp x16, x17, [x0, #(TF_X + 16 * 8)]96stp x18, x19, [x0, #(TF_X + 18 * 8)]97stp x20, x21, [x0, #(TF_X + 20 * 8)]98stp x22, x23, [x0, #(TF_X + 22 * 8)]99stp x24, x25, [x0, #(TF_X + 24 * 8)]100stp x26, x27, [x0, #(TF_X + 26 * 8)]101stp x28, x29, [x0, #(TF_X + 28 * 8)]102103str lr, [x0, #(TF_LR)]104105/* Restore the saved x0 & x1 and save them */106ldp x2, x3, [sp], #(2 * 8)107stp x2, x3, [x0, #(TF_X + 0 * 8)]108.endm109110.macro restore_guest_registers111/*112* Copy the guest x0 and x1 to the stack so we can restore them113* after loading the other registers.114*/115ldp x2, x3, [x0, #(TF_X + 0 * 8)]116stp x2, x3, [sp, #-(2 * 8)]!117118ldr lr, [x0, #(TF_LR)]119120ldp x28, x29, [x0, #(TF_X + 28 * 8)]121ldp x26, x27, [x0, #(TF_X + 26 * 8)]122ldp x24, x25, [x0, #(TF_X + 24 * 8)]123ldp x22, x23, [x0, #(TF_X + 22 * 8)]124ldp x20, x21, [x0, #(TF_X + 20 * 8)]125ldp x18, x19, [x0, #(TF_X + 18 * 8)]126ldp x16, x17, [x0, #(TF_X + 16 * 8)]127ldp x14, x15, [x0, #(TF_X + 14 * 8)]128ldp x12, x13, [x0, #(TF_X + 12 * 8)]129ldp x10, x11, [x0, #(TF_X + 10 * 8)]130ldp x8, x9, [x0, #(TF_X + 8 * 8)]131ldp x6, x7, [x0, #(TF_X + 6 * 8)]132ldp x4, x5, [x0, #(TF_X + 4 * 8)]133ldp x2, x3, [x0, #(TF_X + 2 * 8)]134135ldp x0, x1, [sp], #(2 * 8)136.endm137138.macro vempty139.align 71401: b 1b141.endm142143.macro vector name144.align 7145b handle_\name146.endm147148.text149.align 11150hyp_vectors:151vempty /* Synchronous EL2t */152vempty /* IRQ EL2t */153vempty /* FIQ EL2t */154vempty /* Error EL2t */155156vector el2_el2h_sync /* Synchronous EL2h */157vector el2_el2h_irq /* IRQ EL2h */158vector el2_el2h_fiq /* FIQ EL2h */159vector el2_el2h_error /* Error EL2h */160161vector el2_el1_sync64 /* Synchronous 64-bit EL1 */162vector el2_el1_irq64 /* IRQ 64-bit EL1 */163vector el2_el1_fiq64 /* FIQ 64-bit EL1 */164vector el2_el1_error64 /* Error 64-bit EL1 */165166vempty /* Synchronous 32-bit EL1 */167vempty /* IRQ 32-bit EL1 */168vempty /* FIQ 32-bit EL1 */169vempty /* Error 32-bit EL1 */170171.macro do_world_switch_to_host172save_guest_registers173restore_host_registers174175/* Restore host VTTBR */176mov x9, #VTTBR_HOST177msr vttbr_el2, x9178179#ifdef VMM_VHE180msr vbar_el1, x1181#endif182.endm183184185.macro handle_el2_excp type186#ifndef VMM_VHE187/* Save registers before modifying so we can restore them */188str x9, [sp, #-16]!189190/* Test if the exception happened when the host was running */191mrs x9, vttbr_el2192cmp x9, #VTTBR_HOST193beq 1f194195/* We got the exception while the guest was running */196ldr x9, [sp], #16197#endif /* !VMM_VHE */198do_world_switch_to_host199mov x0, \type200ret201202#ifndef VMM_VHE2031:204/* We got the exception while the host was running */205ldr x9, [sp], #16206mov x0, \type207ERET208#endif /* !VMM_VHE */209.endm210211212LENTRY(handle_el2_el2h_sync)213handle_el2_excp #EXCP_TYPE_EL2_SYNC214LEND(handle_el2_el2h_sync)215216LENTRY(handle_el2_el2h_irq)217handle_el2_excp #EXCP_TYPE_EL2_IRQ218LEND(handle_el2_el2h_irq)219220LENTRY(handle_el2_el2h_fiq)221handle_el2_excp #EXCP_TYPE_EL2_FIQ222LEND(handle_el2_el2h_fiq)223224LENTRY(handle_el2_el2h_error)225handle_el2_excp #EXCP_TYPE_EL2_ERROR226LEND(handle_el2_el2h_error)227228229LENTRY(handle_el2_el1_sync64)230#ifndef VMM_VHE231/* Save registers before modifying so we can restore them */232str x9, [sp, #-16]!233234/* Check for host hypervisor call */235mrs x9, vttbr_el2236cmp x9, #VTTBR_HOST237ldr x9, [sp], #16 /* Restore the temp register */238bne 1f239240/*241* Called from the host242*/243244/* Check if this is a cleanup call and handle in a controlled state */245cmp x0, #(HYP_CLEANUP)246b.eq vmm_cleanup247248str lr, [sp, #-16]!249bl vmm_hyp_enter250ldr lr, [sp], #16251ERET2522531:254#endif255/* Guest exception taken to EL2 */256do_world_switch_to_host257mov x0, #EXCP_TYPE_EL1_SYNC258ret259LEND(handle_el2_el1_sync64)260261/*262* We only trap IRQ, FIQ and SError exceptions when a guest is running. Do a263* world switch to host to handle these exceptions.264*/265266LENTRY(handle_el2_el1_irq64)267do_world_switch_to_host268str x9, [sp, #-16]!269mrs x9, ich_misr_el2270cmp x9, xzr271beq 1f272mov x0, #EXCP_TYPE_MAINT_IRQ273b 2f2741:275mov x0, #EXCP_TYPE_EL1_IRQ2762:277ldr x9, [sp], #16278ret279LEND(handle_el2_el1_irq64)280281LENTRY(handle_el2_el1_fiq64)282do_world_switch_to_host283mov x0, #EXCP_TYPE_EL1_FIQ284ret285LEND(handle_el2_el1_fiq64)286287LENTRY(handle_el2_el1_error64)288do_world_switch_to_host289mov x0, #EXCP_TYPE_EL1_ERROR290ret291LEND(handle_el2_el1_error64)292293294/*295* Usage:296* uint64_t vmm_do_call_guest(struct hypctx *hypctx)297*298* Expecting:299* x0 - hypctx address300*/301ENTRY(VMM_HYP_FUNC(do_call_guest))302#ifdef VMM_VHE303mrs x1, vbar_el1304adrp x2, hyp_vectors305add x2, x2, :lo12:hyp_vectors306msr vbar_el1, x2307isb308#endif309310/* Save hypctx address */311msr tpidr_el2, x0312313save_host_registers314restore_guest_registers315316/* Enter guest */317ERET318END(VMM_HYP_FUNC(do_call_guest))319320GNU_PROPERTY_AARCH64_FEATURE_1_NOTE(GNU_PROPERTY_AARCH64_FEATURE_1_VAL)321322323