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.
20 #include <arch/exception.h>
21 #include <arch/lib_helpers.h>
22 #include <console/console.h>
25 /* SMC called from AARCH32 */
26 EC_SMC_AARCH32
= 0x13,
27 /* SMC called from AARCH64 */
28 EC_SMC_AARCH64
= 0x17,
36 int (*handler
)(struct smc_call
*);
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
)
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
)
60 int smc_register_range(uint32_t min
, uint32_t max
, int (*h
)(struct smc_call
*))
64 if (smc_functions
.used
== SMC_NUM_RANGES
)
70 /* This check isn't exhaustive but it's fairly quick. */
71 if (smc_handler_by_function(min
) || smc_handler_by_function(max
))
74 r
= &smc_functions
.handlers
[smc_functions
.used
];
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
));
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
;
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
));
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
)
146 scr
= raw_read_scr_el3();
147 scr
&= ~(SCR_SMC_MASK
);
148 scr
|= SCR_SMC_ENABLE
;
149 raw_write_scr_el3(scr
);
154 struct cpu_action action
= {
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
);