18c2ecf20Sopenharmony_ci/* SPDX-License-Identifier: GPL-2.0-only */ 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * Copyright (C) 2012,2013 - ARM Ltd 48c2ecf20Sopenharmony_ci * Author: Marc Zyngier <marc.zyngier@arm.com> 58c2ecf20Sopenharmony_ci */ 68c2ecf20Sopenharmony_ci 78c2ecf20Sopenharmony_ci#include <linux/arm-smccc.h> 88c2ecf20Sopenharmony_ci#include <linux/linkage.h> 98c2ecf20Sopenharmony_ci 108c2ecf20Sopenharmony_ci#include <asm/alternative.h> 118c2ecf20Sopenharmony_ci#include <asm/assembler.h> 128c2ecf20Sopenharmony_ci#include <asm/kvm_arm.h> 138c2ecf20Sopenharmony_ci#include <asm/kvm_asm.h> 148c2ecf20Sopenharmony_ci#include <asm/kvm_mmu.h> 158c2ecf20Sopenharmony_ci#include <asm/pgtable-hwdef.h> 168c2ecf20Sopenharmony_ci#include <asm/sysreg.h> 178c2ecf20Sopenharmony_ci#include <asm/virt.h> 188c2ecf20Sopenharmony_ci 198c2ecf20Sopenharmony_ci .text 208c2ecf20Sopenharmony_ci .pushsection .hyp.idmap.text, "ax" 218c2ecf20Sopenharmony_ci 228c2ecf20Sopenharmony_ci .align 11 238c2ecf20Sopenharmony_ci 248c2ecf20Sopenharmony_ciSYM_CODE_START(__kvm_hyp_init) 258c2ecf20Sopenharmony_ci ventry __invalid // Synchronous EL2t 268c2ecf20Sopenharmony_ci ventry __invalid // IRQ EL2t 278c2ecf20Sopenharmony_ci ventry __invalid // FIQ EL2t 288c2ecf20Sopenharmony_ci ventry __invalid // Error EL2t 298c2ecf20Sopenharmony_ci 308c2ecf20Sopenharmony_ci ventry __invalid // Synchronous EL2h 318c2ecf20Sopenharmony_ci ventry __invalid // IRQ EL2h 328c2ecf20Sopenharmony_ci ventry __invalid // FIQ EL2h 338c2ecf20Sopenharmony_ci ventry __invalid // Error EL2h 348c2ecf20Sopenharmony_ci 358c2ecf20Sopenharmony_ci ventry __do_hyp_init // Synchronous 64-bit EL1 368c2ecf20Sopenharmony_ci ventry __invalid // IRQ 64-bit EL1 378c2ecf20Sopenharmony_ci ventry __invalid // FIQ 64-bit EL1 388c2ecf20Sopenharmony_ci ventry __invalid // Error 64-bit EL1 398c2ecf20Sopenharmony_ci 408c2ecf20Sopenharmony_ci ventry __invalid // Synchronous 32-bit EL1 418c2ecf20Sopenharmony_ci ventry __invalid // IRQ 32-bit EL1 428c2ecf20Sopenharmony_ci ventry __invalid // FIQ 32-bit EL1 438c2ecf20Sopenharmony_ci ventry __invalid // Error 32-bit EL1 448c2ecf20Sopenharmony_ci 458c2ecf20Sopenharmony_ci__invalid: 468c2ecf20Sopenharmony_ci b . 478c2ecf20Sopenharmony_ci 488c2ecf20Sopenharmony_ci /* 498c2ecf20Sopenharmony_ci * x0: SMCCC function ID 508c2ecf20Sopenharmony_ci * x1: HYP pgd 518c2ecf20Sopenharmony_ci * x2: per-CPU offset 528c2ecf20Sopenharmony_ci * x3: HYP stack 538c2ecf20Sopenharmony_ci * x4: HYP vectors 548c2ecf20Sopenharmony_ci */ 558c2ecf20Sopenharmony_ci__do_hyp_init: 568c2ecf20Sopenharmony_ci /* Check for a stub HVC call */ 578c2ecf20Sopenharmony_ci cmp x0, #HVC_STUB_HCALL_NR 588c2ecf20Sopenharmony_ci b.lo __kvm_handle_stub_hvc 598c2ecf20Sopenharmony_ci 608c2ecf20Sopenharmony_ci // We only actively check bits [24:31], and everything 618c2ecf20Sopenharmony_ci // else has to be zero, which we check at build time. 628c2ecf20Sopenharmony_ci#if (KVM_HOST_SMCCC_FUNC(__kvm_hyp_init) & 0xFFFFFFFF00FFFFFF) 638c2ecf20Sopenharmony_ci#error Unexpected __KVM_HOST_SMCCC_FUNC___kvm_hyp_init value 648c2ecf20Sopenharmony_ci#endif 658c2ecf20Sopenharmony_ci 668c2ecf20Sopenharmony_ci ror x0, x0, #24 678c2ecf20Sopenharmony_ci eor x0, x0, #((KVM_HOST_SMCCC_FUNC(__kvm_hyp_init) >> 24) & 0xF) 688c2ecf20Sopenharmony_ci ror x0, x0, #4 698c2ecf20Sopenharmony_ci eor x0, x0, #((KVM_HOST_SMCCC_FUNC(__kvm_hyp_init) >> 28) & 0xF) 708c2ecf20Sopenharmony_ci cbz x0, 1f 718c2ecf20Sopenharmony_ci mov x0, #SMCCC_RET_NOT_SUPPORTED 728c2ecf20Sopenharmony_ci eret 738c2ecf20Sopenharmony_ci 748c2ecf20Sopenharmony_ci1: 758c2ecf20Sopenharmony_ci /* Set tpidr_el2 for use by HYP to free a register */ 768c2ecf20Sopenharmony_ci msr tpidr_el2, x2 778c2ecf20Sopenharmony_ci 788c2ecf20Sopenharmony_ci phys_to_ttbr x0, x1 798c2ecf20Sopenharmony_cialternative_if ARM64_HAS_CNP 808c2ecf20Sopenharmony_ci orr x0, x0, #TTBR_CNP_BIT 818c2ecf20Sopenharmony_cialternative_else_nop_endif 828c2ecf20Sopenharmony_ci msr ttbr0_el2, x0 838c2ecf20Sopenharmony_ci 848c2ecf20Sopenharmony_ci mrs x0, tcr_el1 858c2ecf20Sopenharmony_ci mov_q x1, TCR_EL2_MASK 868c2ecf20Sopenharmony_ci and x0, x0, x1 878c2ecf20Sopenharmony_ci mov x1, #TCR_EL2_RES1 888c2ecf20Sopenharmony_ci orr x0, x0, x1 898c2ecf20Sopenharmony_ci 908c2ecf20Sopenharmony_ci /* 918c2ecf20Sopenharmony_ci * The ID map may be configured to use an extended virtual address 928c2ecf20Sopenharmony_ci * range. This is only the case if system RAM is out of range for the 938c2ecf20Sopenharmony_ci * currently configured page size and VA_BITS, in which case we will 948c2ecf20Sopenharmony_ci * also need the extended virtual range for the HYP ID map, or we won't 958c2ecf20Sopenharmony_ci * be able to enable the EL2 MMU. 968c2ecf20Sopenharmony_ci * 978c2ecf20Sopenharmony_ci * However, at EL2, there is only one TTBR register, and we can't switch 988c2ecf20Sopenharmony_ci * between translation tables *and* update TCR_EL2.T0SZ at the same 998c2ecf20Sopenharmony_ci * time. Bottom line: we need to use the extended range with *both* our 1008c2ecf20Sopenharmony_ci * translation tables. 1018c2ecf20Sopenharmony_ci * 1028c2ecf20Sopenharmony_ci * So use the same T0SZ value we use for the ID map. 1038c2ecf20Sopenharmony_ci */ 1048c2ecf20Sopenharmony_ci ldr_l x1, idmap_t0sz 1058c2ecf20Sopenharmony_ci bfi x0, x1, TCR_T0SZ_OFFSET, TCR_TxSZ_WIDTH 1068c2ecf20Sopenharmony_ci 1078c2ecf20Sopenharmony_ci /* 1088c2ecf20Sopenharmony_ci * Set the PS bits in TCR_EL2. 1098c2ecf20Sopenharmony_ci */ 1108c2ecf20Sopenharmony_ci tcr_compute_pa_size x0, #TCR_EL2_PS_SHIFT, x1, x2 1118c2ecf20Sopenharmony_ci 1128c2ecf20Sopenharmony_ci msr tcr_el2, x0 1138c2ecf20Sopenharmony_ci 1148c2ecf20Sopenharmony_ci mrs x0, mair_el1 1158c2ecf20Sopenharmony_ci msr mair_el2, x0 1168c2ecf20Sopenharmony_ci isb 1178c2ecf20Sopenharmony_ci 1188c2ecf20Sopenharmony_ci /* Invalidate the stale TLBs from Bootloader */ 1198c2ecf20Sopenharmony_ci tlbi alle2 1208c2ecf20Sopenharmony_ci dsb sy 1218c2ecf20Sopenharmony_ci 1228c2ecf20Sopenharmony_ci /* 1238c2ecf20Sopenharmony_ci * Preserve all the RES1 bits while setting the default flags, 1248c2ecf20Sopenharmony_ci * as well as the EE bit on BE. Drop the A flag since the compiler 1258c2ecf20Sopenharmony_ci * is allowed to generate unaligned accesses. 1268c2ecf20Sopenharmony_ci */ 1278c2ecf20Sopenharmony_ci mov_q x0, (SCTLR_EL2_RES1 | (SCTLR_ELx_FLAGS & ~SCTLR_ELx_A)) 1288c2ecf20Sopenharmony_ciCPU_BE( orr x0, x0, #SCTLR_ELx_EE) 1298c2ecf20Sopenharmony_cialternative_if ARM64_HAS_ADDRESS_AUTH 1308c2ecf20Sopenharmony_ci mov_q x1, (SCTLR_ELx_ENIA | SCTLR_ELx_ENIB | \ 1318c2ecf20Sopenharmony_ci SCTLR_ELx_ENDA | SCTLR_ELx_ENDB) 1328c2ecf20Sopenharmony_ci orr x0, x0, x1 1338c2ecf20Sopenharmony_cialternative_else_nop_endif 1348c2ecf20Sopenharmony_ci msr sctlr_el2, x0 1358c2ecf20Sopenharmony_ci isb 1368c2ecf20Sopenharmony_ci 1378c2ecf20Sopenharmony_ci /* Set the stack and new vectors */ 1388c2ecf20Sopenharmony_ci mov sp, x3 1398c2ecf20Sopenharmony_ci msr vbar_el2, x4 1408c2ecf20Sopenharmony_ci 1418c2ecf20Sopenharmony_ci /* Hello, World! */ 1428c2ecf20Sopenharmony_ci mov x0, #SMCCC_RET_SUCCESS 1438c2ecf20Sopenharmony_ci eret 1448c2ecf20Sopenharmony_ciSYM_CODE_END(__kvm_hyp_init) 1458c2ecf20Sopenharmony_ci 1468c2ecf20Sopenharmony_ciSYM_CODE_START(__kvm_handle_stub_hvc) 1478c2ecf20Sopenharmony_ci cmp x0, #HVC_SOFT_RESTART 1488c2ecf20Sopenharmony_ci b.ne 1f 1498c2ecf20Sopenharmony_ci 1508c2ecf20Sopenharmony_ci /* This is where we're about to jump, staying at EL2 */ 1518c2ecf20Sopenharmony_ci msr elr_el2, x1 1528c2ecf20Sopenharmony_ci mov x0, #(PSR_F_BIT | PSR_I_BIT | PSR_A_BIT | PSR_D_BIT | PSR_MODE_EL2h) 1538c2ecf20Sopenharmony_ci msr spsr_el2, x0 1548c2ecf20Sopenharmony_ci 1558c2ecf20Sopenharmony_ci /* Shuffle the arguments, and don't come back */ 1568c2ecf20Sopenharmony_ci mov x0, x2 1578c2ecf20Sopenharmony_ci mov x1, x3 1588c2ecf20Sopenharmony_ci mov x2, x4 1598c2ecf20Sopenharmony_ci b reset 1608c2ecf20Sopenharmony_ci 1618c2ecf20Sopenharmony_ci1: cmp x0, #HVC_RESET_VECTORS 1628c2ecf20Sopenharmony_ci b.ne 1f 1638c2ecf20Sopenharmony_ci 1648c2ecf20Sopenharmony_ci /* 1658c2ecf20Sopenharmony_ci * Set the HVC_RESET_VECTORS return code before entering the common 1668c2ecf20Sopenharmony_ci * path so that we do not clobber x0-x2 in case we are coming via 1678c2ecf20Sopenharmony_ci * HVC_SOFT_RESTART. 1688c2ecf20Sopenharmony_ci */ 1698c2ecf20Sopenharmony_ci mov x0, xzr 1708c2ecf20Sopenharmony_cireset: 1718c2ecf20Sopenharmony_ci /* Reset kvm back to the hyp stub. */ 1728c2ecf20Sopenharmony_ci mrs x5, sctlr_el2 1738c2ecf20Sopenharmony_ci mov_q x6, SCTLR_ELx_FLAGS 1748c2ecf20Sopenharmony_ci bic x5, x5, x6 // Clear SCTL_M and etc 1758c2ecf20Sopenharmony_ci pre_disable_mmu_workaround 1768c2ecf20Sopenharmony_ci msr sctlr_el2, x5 1778c2ecf20Sopenharmony_ci isb 1788c2ecf20Sopenharmony_ci 1798c2ecf20Sopenharmony_ci /* Install stub vectors */ 1808c2ecf20Sopenharmony_ci adr_l x5, __hyp_stub_vectors 1818c2ecf20Sopenharmony_ci msr vbar_el2, x5 1828c2ecf20Sopenharmony_ci eret 1838c2ecf20Sopenharmony_ci 1848c2ecf20Sopenharmony_ci1: /* Bad stub call */ 1858c2ecf20Sopenharmony_ci mov_q x0, HVC_STUB_ERR 1868c2ecf20Sopenharmony_ci eret 1878c2ecf20Sopenharmony_ci 1888c2ecf20Sopenharmony_ciSYM_CODE_END(__kvm_handle_stub_hvc) 1898c2ecf20Sopenharmony_ci 1908c2ecf20Sopenharmony_ci .popsection 191