1f651b525SAndrew Turner /*-
2f651b525SAndrew Turner * SPDX-License-Identifier: BSD-2-Clause
3f651b525SAndrew Turner *
4f651b525SAndrew Turner * Copyright (c) 2018 Andrew Turner
5f651b525SAndrew Turner *
6f651b525SAndrew Turner * This software was developed by SRI International and the University of
7f651b525SAndrew Turner * Cambridge Computer Laboratory under DARPA/AFRL contract FA8750-10-C-0237
8f651b525SAndrew Turner * ("CTSRD"), as part of the DARPA CRASH research programme.
9f651b525SAndrew Turner *
10f651b525SAndrew Turner * Redistribution and use in source and binary forms, with or without
11f651b525SAndrew Turner * modification, are permitted provided that the following conditions
12f651b525SAndrew Turner * are met:
13f651b525SAndrew Turner * 1. Redistributions of source code must retain the above copyright
14f651b525SAndrew Turner * notice, this list of conditions and the following disclaimer.
15f651b525SAndrew Turner * 2. Redistributions in binary form must reproduce the above copyright
16f651b525SAndrew Turner * notice, this list of conditions and the following disclaimer in the
17f651b525SAndrew Turner * documentation and/or other materials provided with the distribution.
18f651b525SAndrew Turner *
19f651b525SAndrew Turner * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
20f651b525SAndrew Turner * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21f651b525SAndrew Turner * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22f651b525SAndrew Turner * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
23f651b525SAndrew Turner * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24f651b525SAndrew Turner * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
25f651b525SAndrew Turner * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
26f651b525SAndrew Turner * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
27f651b525SAndrew Turner * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
28f651b525SAndrew Turner * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
29f651b525SAndrew Turner * SUCH DAMAGE.
30f651b525SAndrew Turner */
31f651b525SAndrew Turner
32f651b525SAndrew Turner #include "opt_acpi.h"
33f651b525SAndrew Turner #include "opt_platform.h"
34f651b525SAndrew Turner
35f651b525SAndrew Turner #include <sys/param.h>
36f651b525SAndrew Turner #include <sys/systm.h>
37*3e19edcaSAndrew Turner #include <sys/bus.h>
38f651b525SAndrew Turner #include <sys/kernel.h>
39*3e19edcaSAndrew Turner #include <sys/module.h>
40f651b525SAndrew Turner
41f651b525SAndrew Turner #include <dev/psci/psci.h>
42f651b525SAndrew Turner #include <dev/psci/smccc.h>
43f651b525SAndrew Turner
44f651b525SAndrew Turner #define SMCCC_VERSION_1_0 0x10000
45f651b525SAndrew Turner
46f651b525SAndrew Turner /* Assume 1.0 until we detect a later version */
478a723e2bSAndrew Turner static uint32_t smccc_version;
48f651b525SAndrew Turner
490600af1fSAndrew Turner void
smccc_init(void)500600af1fSAndrew Turner smccc_init(void)
51f651b525SAndrew Turner {
52f651b525SAndrew Turner int32_t features;
53f651b525SAndrew Turner uint32_t ret;
54f651b525SAndrew Turner
558a723e2bSAndrew Turner smccc_version = SMCCC_VERSION_1_0;
56f651b525SAndrew Turner features = psci_features(SMCCC_VERSION);
57f651b525SAndrew Turner if (features != PSCI_RETVAL_NOT_SUPPORTED) {
58f651b525SAndrew Turner ret = psci_call(SMCCC_VERSION, 0, 0, 0);
59f651b525SAndrew Turner /* This should always be the case as we checked it above */
60f651b525SAndrew Turner if (ret > 0)
61f651b525SAndrew Turner smccc_version = ret;
62f651b525SAndrew Turner }
63f651b525SAndrew Turner
64f651b525SAndrew Turner if (bootverbose) {
65f651b525SAndrew Turner printf("Found SMCCC version %u.%u\n",
66f651b525SAndrew Turner SMCCC_VERSION_MAJOR(smccc_version),
67f651b525SAndrew Turner SMCCC_VERSION_MINOR(smccc_version));
68f651b525SAndrew Turner }
69f651b525SAndrew Turner }
700600af1fSAndrew Turner
71*3e19edcaSAndrew Turner static int
smccc_probe(device_t dev)72*3e19edcaSAndrew Turner smccc_probe(device_t dev)
73*3e19edcaSAndrew Turner {
74*3e19edcaSAndrew Turner int32_t version;
75*3e19edcaSAndrew Turner
76*3e19edcaSAndrew Turner /*
77*3e19edcaSAndrew Turner * If the version is not implemented then we treat it as SMCCC 1.0
78*3e19edcaSAndrew Turner */
79*3e19edcaSAndrew Turner if (psci_features(SMCCC_VERSION) == PSCI_RETVAL_NOT_SUPPORTED ||
80*3e19edcaSAndrew Turner (version = arm_smccc_invoke(SMCCC_VERSION, NULL)) <= 0) {
81*3e19edcaSAndrew Turner device_set_desc(dev, "ARM SMCCC v1.0");
82*3e19edcaSAndrew Turner return (0);
83*3e19edcaSAndrew Turner }
84*3e19edcaSAndrew Turner
85*3e19edcaSAndrew Turner device_set_descf(dev, "ARM SMCCC v%d.%d", SMCCC_VERSION_MAJOR(version),
86*3e19edcaSAndrew Turner SMCCC_VERSION_MINOR(version));
87*3e19edcaSAndrew Turner
88*3e19edcaSAndrew Turner return (0);
89*3e19edcaSAndrew Turner }
90*3e19edcaSAndrew Turner
91*3e19edcaSAndrew Turner static int
smccc_attach(device_t dev)92*3e19edcaSAndrew Turner smccc_attach(device_t dev)
93*3e19edcaSAndrew Turner {
94*3e19edcaSAndrew Turner return (bus_generic_attach(dev));
95*3e19edcaSAndrew Turner }
96*3e19edcaSAndrew Turner
970600af1fSAndrew Turner uint32_t
smccc_get_version(void)980600af1fSAndrew Turner smccc_get_version(void)
990600af1fSAndrew Turner {
1008a723e2bSAndrew Turner MPASS(smccc_version != 0);
1010600af1fSAndrew Turner return (smccc_version);
1020600af1fSAndrew Turner }
103f651b525SAndrew Turner
104f651b525SAndrew Turner int32_t
smccc_arch_features(uint32_t smccc_func_id)105f651b525SAndrew Turner smccc_arch_features(uint32_t smccc_func_id)
106f651b525SAndrew Turner {
107f651b525SAndrew Turner
1088a723e2bSAndrew Turner MPASS(smccc_version != 0);
109f651b525SAndrew Turner if (smccc_version == SMCCC_VERSION_1_0)
110f651b525SAndrew Turner return (PSCI_RETVAL_NOT_SUPPORTED);
111f651b525SAndrew Turner
112b9cd72b0SAndrew Turner return (arm_smccc_invoke(SMCCC_ARCH_FEATURES, smccc_func_id, NULL));
113f651b525SAndrew Turner }
114f651b525SAndrew Turner
115f651b525SAndrew Turner /*
116f651b525SAndrew Turner * The SMCCC handler for Spectre variant 2: Branch target injection.
117f651b525SAndrew Turner * (CVE-2017-5715)
118f651b525SAndrew Turner */
119f651b525SAndrew Turner int
smccc_arch_workaround_1(void)120f651b525SAndrew Turner smccc_arch_workaround_1(void)
121f651b525SAndrew Turner {
122f651b525SAndrew Turner
1238a723e2bSAndrew Turner MPASS(smccc_version != 0);
124f651b525SAndrew Turner KASSERT(smccc_version != SMCCC_VERSION_1_0,
125f651b525SAndrew Turner ("SMCCC arch workaround 1 called with an invalid SMCCC interface"));
126b9cd72b0SAndrew Turner return (arm_smccc_invoke(SMCCC_ARCH_WORKAROUND_1, NULL));
127f651b525SAndrew Turner }
1280594061eSAndrew Turner
1290594061eSAndrew Turner int
smccc_arch_workaround_2(int enable)130100a6d19SAndrew Turner smccc_arch_workaround_2(int enable)
1310594061eSAndrew Turner {
1320594061eSAndrew Turner
1338a723e2bSAndrew Turner MPASS(smccc_version != 0);
1340594061eSAndrew Turner KASSERT(smccc_version != SMCCC_VERSION_1_0,
1350594061eSAndrew Turner ("SMCCC arch workaround 2 called with an invalid SMCCC interface"));
136b9cd72b0SAndrew Turner return (arm_smccc_invoke(SMCCC_ARCH_WORKAROUND_2, enable, NULL));
1370594061eSAndrew Turner }
138*3e19edcaSAndrew Turner
139*3e19edcaSAndrew Turner static device_method_t smccc_methods[] = {
140*3e19edcaSAndrew Turner DEVMETHOD(device_probe, smccc_probe),
141*3e19edcaSAndrew Turner DEVMETHOD(device_attach, smccc_attach),
142*3e19edcaSAndrew Turner
143*3e19edcaSAndrew Turner DEVMETHOD(bus_add_child, bus_generic_add_child),
144*3e19edcaSAndrew Turner
145*3e19edcaSAndrew Turner DEVMETHOD_END
146*3e19edcaSAndrew Turner };
147*3e19edcaSAndrew Turner
148*3e19edcaSAndrew Turner static driver_t smccc_driver = {
149*3e19edcaSAndrew Turner "smccc",
150*3e19edcaSAndrew Turner smccc_methods,
151*3e19edcaSAndrew Turner 0,
152*3e19edcaSAndrew Turner };
153*3e19edcaSAndrew Turner
154*3e19edcaSAndrew Turner EARLY_DRIVER_MODULE(smccc, psci, smccc_driver, 0, 0,
155*3e19edcaSAndrew Turner BUS_PASS_CPU + BUS_PASS_ORDER_FIRST);
156