tree: drop last paragraph of GPL copyright header
[coreboot.git] / src / arch / arm64 / armv8 / secmon / smc.c
blob6fa6294933a4a4582d086aa80340463b60afb930
1 /*
2 * This file is part of the coreboot project.
4 * Copyright 2014 Google Inc.
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; version 2 of the License.
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
16 #include <string.h>
17 #include <stdlib.h>
18 #include <arch/cpu.h>
19 #include <arch/smc.h>
20 #include <arch/exception.h>
21 #include <arch/lib_helpers.h>
22 #include <console/console.h>
24 enum {
25 /* SMC called from AARCH32 */
26 EC_SMC_AARCH32 = 0x13,
27 /* SMC called from AARCH64 */
28 EC_SMC_AARCH64 = 0x17,
30 SMC_NUM_RANGES = 8,
33 struct smc_range {
34 uint32_t func_begin;
35 uint32_t func_end;
36 int (*handler)(struct smc_call *);
39 struct smc_ranges {
40 size_t used;
41 struct smc_range handlers[SMC_NUM_RANGES];
44 static struct smc_ranges smc_functions;
46 static struct smc_range *smc_handler_by_function(uint32_t fid)
48 int i;
50 for (i = 0; i < smc_functions.used; i++) {
51 struct smc_range *r = &smc_functions.handlers[i];
53 if (fid >= r->func_begin && fid <= r->func_end)
54 return r;
57 return NULL;
60 int smc_register_range(uint32_t min, uint32_t max, int (*h)(struct smc_call *))
62 struct smc_range *r;
64 if (smc_functions.used == SMC_NUM_RANGES)
65 return -1;
67 if (min > max)
68 return -1;
70 /* This check isn't exhaustive but it's fairly quick. */
71 if (smc_handler_by_function(min) || smc_handler_by_function(max))
72 return -1;
74 r = &smc_functions.handlers[smc_functions.used];
75 r->func_begin = min;
76 r->func_end = max;
77 r->handler = h;
78 smc_functions.used++;
80 return 0;
83 static int smc_cleanup(struct exc_state *state, struct smc_call *smc, int ret)
85 memcpy(&state->regs.x, &smc->results, sizeof(smc->results));
87 return ret;
90 static int smc_return_with_error(struct exc_state *state, struct smc_call *smc)
92 smc32_return(smc, SMC_UNKNOWN_FUNC);
93 return smc_cleanup(state, smc, EXC_RET_HANDLED);
96 static int smc_handler(struct exc_state *state, uint64_t vector_id)
98 struct smc_call smc_storage;
99 struct smc_call *smc = &smc_storage;
100 uint32_t exception_class;
101 uint32_t esr;
102 struct smc_range *r;
104 memcpy(&smc->args, &state->regs.x, sizeof(smc->args));
105 memcpy(&smc->results, &state->regs.x, sizeof(smc->results));
107 esr = raw_read_esr_el3();
108 exception_class = (esr >> 26) & 0x3f;
110 /* No support for SMC calls from AARCH32 */
111 if (exception_class == EC_SMC_AARCH32)
112 return smc_return_with_error(state, smc);
114 /* Check to ensure this is an SMC from AARCH64. */
115 if (exception_class != EC_SMC_AARCH64)
116 return EXC_RET_IGNORED;
118 /* Ensure immediate value is 0. */
119 if ((esr & 0xffff) != 0)
120 return smc_return_with_error(state, smc);
122 r = smc_handler_by_function(smc_function_id(smc));
124 if (r != NULL) {
125 if (!r->handler(smc))
126 return smc_cleanup(state, smc, EXC_RET_HANDLED);
129 return smc_return_with_error(state, smc);
132 /* SMC calls can be generated by 32-bit or 64-bit code. */
133 static struct exception_handler smc_handler64 = {
134 .handler = &smc_handler,
137 static struct exception_handler smc_handler32 = {
138 .handler = &smc_handler,
141 static void enable_smc(void *arg)
143 uint32_t scr;
145 /* Enable SMC */
146 scr = raw_read_scr_el3();
147 scr &= ~(SCR_SMC_MASK);
148 scr |= SCR_SMC_ENABLE;
149 raw_write_scr_el3(scr);
152 void smc_init(void)
154 struct cpu_action action = {
155 .run = enable_smc,
158 arch_run_on_all_cpus_async(&action);
160 /* Register SMC handlers. */
161 exception_handler_register(EXC_VID_LOW64_SYNC, &smc_handler64);
162 exception_handler_register(EXC_VID_LOW32_SYNC, &smc_handler32);