1 /* $NetBSD: smccc.c,v 1.4 2023/11/07 13:31:26 rin 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.4 2023/11/07 13:31:26 rin 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 # if defined(__clang__) 40 #define SMCCC_ARCH_ATTRIBUTE __attribute__ ((target("armv7ve"))) 41 # else /* gcc */ 42 #define SMCCC_ARCH_ATTRIBUTE __attribute__ ((target("arch=armv7ve"))) 43 # endif 44 #else 45 #define SMCCC_ARCH_ATTRIBUTE 46 #endif 47 48 /* Minimum supported PSCI version for SMCCC discovery */ 49 #define PSCI_VERSION_1_0 0x10000 50 51 /* Retrieve the implemented version of the SMC Calling Convention. */ 52 #define SMCCC_VERSION 0x80000000 53 54 /* True if SMCCC is detected. */ 55 static bool smccc_present; 56 57 /* SMCCC conduit (SMC or HVC) */ 58 static enum psci_conduit smccc_conduit = PSCI_CONDUIT_NONE; 59 60 /* 61 * smccc_probe -- 62 * 63 * Returns true if SMCCC is supported by platform firmware. 64 */ 65 bool 66 smccc_probe(void) 67 { 68 if (cold && !smccc_present) { 69 if (!psci_available() || psci_version() < PSCI_VERSION_1_0) { 70 return false; 71 } 72 73 smccc_present = psci_features(SMCCC_VERSION) == PSCI_SUCCESS; 74 if (smccc_present) { 75 smccc_conduit = psci_conduit(); 76 77 aprint_debug("SMCCC: Version %#x (%s)\n", 78 smccc_version(), 79 smccc_conduit == PSCI_CONDUIT_SMC ? "SMC" : "HVC"); 80 } 81 } 82 return smccc_present; 83 } 84 85 /* 86 * smccc_version -- 87 * 88 * Return the implemented SMCCC version, or a negative error code on failure. 89 */ 90 int 91 smccc_version(void) 92 { 93 return smccc_call(SMCCC_VERSION, 0, 0, 0, 0, 94 NULL, NULL, NULL, NULL); 95 } 96 97 /* 98 * smccc_call -- 99 * 100 * Generic call interface for SMC/HVC calls. 101 */ 102 SMCCC_ARCH_ATTRIBUTE int 103 smccc_call(uint32_t fid, 104 register_t arg1, register_t arg2, register_t arg3, register_t arg4, 105 register_t *res0, register_t *res1, register_t *res2, register_t *res3) 106 { 107 register_t args[5] = { fid, arg1, arg2, arg3, arg4 }; 108 109 register register_t r0 asm ("r0"); 110 register register_t r1 asm ("r1"); 111 register register_t r2 asm ("r2"); 112 register register_t r3 asm ("r3"); 113 register register_t r4 asm ("r4"); 114 115 if (!smccc_present) { 116 return SMCCC_NOT_SUPPORTED; 117 } 118 119 KASSERT(smccc_conduit != PSCI_CONDUIT_NONE); 120 121 r0 = args[0]; 122 r1 = args[1]; 123 r2 = args[2]; 124 r3 = args[3]; 125 r4 = args[4]; 126 127 if (smccc_conduit == PSCI_CONDUIT_SMC) { 128 asm volatile ("smc #0" : 129 "=r" (r0), "=r" (r1), "=r" (r2), "=r" (r3) : 130 "r" (r0), "r" (r1), "r" (r2), "r" (r3), "r" (r4) : 131 "memory"); 132 } else { 133 asm volatile ("hvc #0" : 134 "=r" (r0), "=r" (r1), "=r" (r2), "=r" (r3) : 135 "r" (r0), "r" (r1), "r" (r2), "r" (r3), "r" (r4) : 136 "memory"); 137 } 138 139 if (res0) { 140 *res0 = r0; 141 } 142 if (res1) { 143 *res1 = r1; 144 } 145 if (res2) { 146 *res2 = r2; 147 } 148 if (res3) { 149 *res3 = r3; 150 } 151 152 return r0; 153 } 154