xref: /netbsd-src/sys/arch/arm/arm/smccc.c (revision 53b02e147d4ed531c0d2a5ca9b3e8026ba3e99b5)
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