1 /* $NetBSD: smccc.c,v 1.3 2021/08/08 13:43:09 jmcneill Exp $ */ 2 3 /*- 4 * Copyright (c) 2021 Jared McNeill <jmcneill@invisible.ca> 5 * All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 1. Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * 2. Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in the 14 * documentation and/or other materials provided with the distribution. 15 * 16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 17 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 18 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 19 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 20 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 21 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 22 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED 23 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 24 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 25 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 26 * SUCH DAMAGE. 27 */ 28 29 #include <sys/cdefs.h> 30 __KERNEL_RCSID(0, "$NetBSD: smccc.c,v 1.3 2021/08/08 13:43:09 jmcneill Exp $"); 31 32 #include <sys/param.h> 33 #include <sys/kernel.h> 34 35 #include <arm/arm/psci.h> 36 #include <arm/arm/smccc.h> 37 38 #if defined(__arm__) 39 #define SMCCC_ARCH_ATTRIBUTE __attribute__ ((target("arch=armv7ve"))) 40 #else 41 #define SMCCC_ARCH_ATTRIBUTE 42 #endif 43 44 /* Minimum supported PSCI version for SMCCC discovery */ 45 #define PSCI_VERSION_1_0 0x10000 46 47 /* Retrieve the implemented version of the SMC Calling Convention. */ 48 #define SMCCC_VERSION 0x80000000 49 50 /* True if SMCCC is detected. */ 51 static bool smccc_present; 52 53 /* SMCCC conduit (SMC or HVC) */ 54 static enum psci_conduit smccc_conduit = PSCI_CONDUIT_NONE; 55 56 /* 57 * smccc_probe -- 58 * 59 * Returns true if SMCCC is supported by platform firmware. 60 */ 61 bool 62 smccc_probe(void) 63 { 64 if (cold && !smccc_present) { 65 if (!psci_available() || psci_version() < PSCI_VERSION_1_0) { 66 return false; 67 } 68 69 smccc_present = psci_features(SMCCC_VERSION) == PSCI_SUCCESS; 70 if (smccc_present) { 71 smccc_conduit = psci_conduit(); 72 73 aprint_debug("SMCCC: Version %#x (%s)\n", 74 smccc_version(), 75 smccc_conduit == PSCI_CONDUIT_SMC ? "SMC" : "HVC"); 76 } 77 } 78 return smccc_present; 79 } 80 81 /* 82 * smccc_version -- 83 * 84 * Return the implemented SMCCC version, or a negative error code on failure. 85 */ 86 int 87 smccc_version(void) 88 { 89 return smccc_call(SMCCC_VERSION, 0, 0, 0, 0, 90 NULL, NULL, NULL, NULL); 91 } 92 93 /* 94 * smccc_call -- 95 * 96 * Generic call interface for SMC/HVC calls. 97 */ 98 SMCCC_ARCH_ATTRIBUTE int 99 smccc_call(uint32_t fid, 100 register_t arg1, register_t arg2, register_t arg3, register_t arg4, 101 register_t *res0, register_t *res1, register_t *res2, register_t *res3) 102 { 103 register_t args[5] = { fid, arg1, arg2, arg3, arg4 }; 104 105 register register_t r0 asm ("r0"); 106 register register_t r1 asm ("r1"); 107 register register_t r2 asm ("r2"); 108 register register_t r3 asm ("r3"); 109 register register_t r4 asm ("r4"); 110 111 if (!smccc_present) { 112 return SMCCC_NOT_SUPPORTED; 113 } 114 115 KASSERT(smccc_conduit != PSCI_CONDUIT_NONE); 116 117 r0 = args[0]; 118 r1 = args[1]; 119 r2 = args[2]; 120 r3 = args[3]; 121 r4 = args[4]; 122 123 if (smccc_conduit == PSCI_CONDUIT_SMC) { 124 asm volatile ("smc #0" : 125 "=r" (r0), "=r" (r1), "=r" (r2), "=r" (r3) : 126 "r" (r0), "r" (r1), "r" (r2), "r" (r3), "r" (r4) : 127 "memory"); 128 } else { 129 asm volatile ("hvc #0" : 130 "=r" (r0), "=r" (r1), "=r" (r2), "=r" (r3) : 131 "r" (r0), "r" (r1), "r" (r2), "r" (r3), "r" (r4) : 132 "memory"); 133 } 134 135 if (res0) { 136 *res0 = r0; 137 } 138 if (res1) { 139 *res1 = r1; 140 } 141 if (res2) { 142 *res2 = r2; 143 } 144 if (res3) { 145 *res3 = r3; 146 } 147 148 return r0; 149 } 150