developer | 72bccc1 | 2022-06-26 21:50:32 +0800 | [diff] [blame] | 1 | /* |
| 2 | * Copyright (c) 2022, Mediatek Inc. All rights reserved. |
| 3 | * |
| 4 | * SPDX-License-Identifier: BSD-3-Clause |
| 5 | */ |
| 6 | |
| 7 | #include <assert.h> |
| 8 | #include <errno.h> |
| 9 | #include <inttypes.h> |
| 10 | #include <stdint.h> |
| 11 | #include <common/debug.h> |
| 12 | #include <common/runtime_svc.h> |
| 13 | #include <lib/el3_runtime/context_mgmt.h> |
| 14 | |
| 15 | /* Vendors headers */ |
| 16 | #include <cold_boot.h> |
| 17 | #include <lib/mtk_init/mtk_init.h> |
| 18 | #include <mtk_sip_svc.h> |
| 19 | |
| 20 | static struct kernel_info k_info; |
| 21 | static entry_point_info_t bl32_image_ep_info; |
| 22 | static entry_point_info_t bl33_image_ep_info; |
| 23 | static bool el1_is_2nd_bootloader = true; |
| 24 | static struct atf_arg_t atfarg; |
| 25 | |
| 26 | static int init_mtk_bl32_arg(void) |
| 27 | { |
| 28 | struct mtk_bl_param_t *p_mtk_bl_param; |
| 29 | struct atf_arg_t *p_atfarg; |
| 30 | |
| 31 | p_mtk_bl_param = (struct mtk_bl_param_t *) get_mtk_bl31_fw_config(BOOT_ARG_FROM_BL2); |
| 32 | if (p_mtk_bl_param == NULL) { |
| 33 | ERROR("p_mtk_bl_param is NULL!\n"); |
| 34 | return -1; |
| 35 | } |
| 36 | p_atfarg = (struct atf_arg_t *)p_mtk_bl_param->atf_arg_addr; |
| 37 | if (p_atfarg == NULL) { |
| 38 | ERROR("bl32 argument is NULL!\n"); |
| 39 | return -1; |
| 40 | } |
| 41 | memcpy((void *)&atfarg, (void *)p_atfarg, sizeof(struct atf_arg_t)); |
| 42 | return 0; |
| 43 | } |
| 44 | MTK_EARLY_PLAT_INIT(init_mtk_bl32_arg); |
| 45 | |
| 46 | static void save_kernel_info(uint64_t pc, uint64_t r0, uint64_t r1, uint64_t k32_64) |
| 47 | { |
| 48 | k_info.k32_64 = k32_64; |
| 49 | k_info.pc = pc; |
| 50 | |
| 51 | if (k32_64 == LINUX_KERNEL_32) { |
| 52 | /* for 32 bits kernel */ |
| 53 | k_info.r0 = 0; |
| 54 | /* machtype */ |
| 55 | k_info.r1 = r0; |
| 56 | /* tags */ |
| 57 | k_info.r2 = r1; |
| 58 | } else { |
| 59 | /* for 64 bits kernel */ |
| 60 | k_info.r0 = r0; |
| 61 | k_info.r1 = r1; |
| 62 | } |
| 63 | } |
| 64 | |
| 65 | static uint32_t plat_get_spsr_for_bl32_64_entry(void) |
| 66 | { |
| 67 | return SPSR_64(MODE_EL1, MODE_SP_ELX, DISABLE_ALL_EXCEPTIONS); |
| 68 | } |
| 69 | |
| 70 | #if MTK_BL33_IS_64BIT |
| 71 | static uint32_t plat_get_spsr_for_bl33_entry(void) |
| 72 | { |
| 73 | uint32_t spsr; |
| 74 | uint32_t mode; |
| 75 | |
| 76 | mode = MODE_EL1; |
| 77 | spsr = SPSR_64(mode, MODE_SP_ELX, DISABLE_ALL_EXCEPTIONS); |
| 78 | return spsr; |
| 79 | } |
| 80 | #else |
| 81 | static uint32_t plat_get_spsr_for_bl33_entry(void) |
| 82 | { |
| 83 | unsigned int mode; |
| 84 | uint32_t spsr; |
| 85 | unsigned int ee; |
| 86 | unsigned long daif; |
| 87 | |
| 88 | INFO("Secondary bootloader is AArch32\n"); |
| 89 | mode = MODE32_svc; |
| 90 | ee = 0; |
| 91 | /* |
| 92 | * TODO: Choose async. exception bits if HYP mode is not |
| 93 | * implemented according to the values of SCR.{AW, FW} bits |
| 94 | */ |
| 95 | daif = DAIF_ABT_BIT | DAIF_IRQ_BIT | DAIF_FIQ_BIT; |
| 96 | |
| 97 | spsr = SPSR_MODE32(mode, 0, ee, daif); |
| 98 | return spsr; |
| 99 | } |
| 100 | #endif |
| 101 | |
| 102 | static void populate_bl32_image_ep(entry_point_info_t *bl32_ep_instance, |
| 103 | struct mtk_bl_param_t *p_mtk_bl_param) |
| 104 | { |
| 105 | entry_point_info_t *populated_ep_bl32 = bl32_ep_instance; |
| 106 | |
| 107 | if (p_mtk_bl_param == NULL) { |
| 108 | ERROR("p_mtk_bl_param is NULL!\n"); |
| 109 | panic(); |
| 110 | } |
| 111 | SET_SECURITY_STATE(bl32_ep_instance->h.attr, SECURE); |
| 112 | SET_PARAM_HEAD(populated_ep_bl32, |
| 113 | PARAM_EP, |
| 114 | VERSION_1, |
| 115 | populated_ep_bl32->h.attr); |
| 116 | populated_ep_bl32->pc = atfarg.tee_entry; |
| 117 | populated_ep_bl32->spsr = plat_get_spsr_for_bl32_64_entry(); |
| 118 | } |
| 119 | |
| 120 | static void populate_bl33_image_ep(entry_point_info_t *bl33_ep_instance, |
| 121 | struct mtk_bl_param_t *p_mtk_bl_param) |
| 122 | { |
| 123 | entry_point_info_t *populated_ep_bl33 = bl33_ep_instance; |
| 124 | |
| 125 | if (p_mtk_bl_param == NULL) { |
| 126 | ERROR("p_mtk_bl_param is NULL!\n"); |
| 127 | panic(); |
| 128 | } |
| 129 | SET_SECURITY_STATE(bl33_ep_instance->h.attr, NON_SECURE); |
| 130 | SET_PARAM_HEAD(populated_ep_bl33, |
| 131 | PARAM_EP, |
| 132 | VERSION_1, |
| 133 | populated_ep_bl33->h.attr); |
| 134 | populated_ep_bl33->pc = p_mtk_bl_param->bl33_start_addr; |
| 135 | /* standardize 2nd bootloader input argument */ |
| 136 | populated_ep_bl33->args.arg0 = p_mtk_bl_param->bootarg_loc; |
| 137 | /* compatible to old GZ version */ |
| 138 | populated_ep_bl33->args.arg4 = p_mtk_bl_param->bootarg_loc; |
| 139 | populated_ep_bl33->args.arg5 = p_mtk_bl_param->bootarg_size; |
| 140 | populated_ep_bl33->spsr = plat_get_spsr_for_bl33_entry(); |
| 141 | } |
| 142 | |
| 143 | static int populate_bl_images_ep(struct mtk_bl_param_t *p_mtk_bl_param) |
| 144 | { |
| 145 | /* |
| 146 | * Tell BL31 where the non-trusted software image |
| 147 | * is located and the entry state information |
| 148 | */ |
| 149 | populate_bl33_image_ep(&bl33_image_ep_info, p_mtk_bl_param); |
| 150 | populate_bl32_image_ep(&bl32_image_ep_info, p_mtk_bl_param); |
| 151 | return 0; |
| 152 | } |
| 153 | |
| 154 | static int populate_bl_images_ep_init(void) |
| 155 | { |
| 156 | return populate_bl_images_ep(get_mtk_bl31_fw_config(BOOT_ARG_FROM_BL2)); |
| 157 | } |
| 158 | MTK_PLAT_SETUP_0_INIT(populate_bl_images_ep_init); |
| 159 | |
| 160 | static entry_point_info_t *bl31_plat_get_next_kernel64_ep_info(void) |
| 161 | { |
| 162 | entry_point_info_t *next_image_info; |
| 163 | unsigned long el_status; |
| 164 | unsigned int mode; |
| 165 | |
| 166 | el_status = 0; |
| 167 | mode = 0; |
| 168 | |
| 169 | /* Kernel image is always non-secured */ |
| 170 | next_image_info = &bl33_image_ep_info; |
| 171 | |
| 172 | /* Figure out what mode we enter the non-secure world in */ |
| 173 | el_status = read_id_aa64pfr0_el1() >> ID_AA64PFR0_EL2_SHIFT; |
| 174 | el_status &= ID_AA64PFR0_ELX_MASK; |
| 175 | |
| 176 | INFO("Kernel_EL %d\n", el_status?2:1); |
| 177 | if (el_status) { |
| 178 | mode = MODE_EL2; |
| 179 | } else { |
| 180 | mode = MODE_EL1; |
| 181 | } |
| 182 | INFO("Kernel is 64Bit\n"); |
| 183 | next_image_info->spsr = SPSR_64(mode, MODE_SP_ELX, DISABLE_ALL_EXCEPTIONS); |
| 184 | next_image_info->pc = k_info.pc; |
| 185 | next_image_info->args.arg0 = k_info.r0; |
| 186 | next_image_info->args.arg1 = k_info.r1; |
| 187 | |
| 188 | INFO("pc=0x%lx, r0=0x%" PRIx64 ", r1=0x%" PRIx64 "\n", |
| 189 | next_image_info->pc, |
| 190 | next_image_info->args.arg0, |
| 191 | next_image_info->args.arg1); |
| 192 | |
| 193 | SET_SECURITY_STATE(next_image_info->h.attr, NON_SECURE); |
| 194 | |
| 195 | /* None of the images on this platform can have 0x0 as the entrypoint */ |
| 196 | if (next_image_info->pc) { |
| 197 | return next_image_info; |
| 198 | } |
| 199 | |
| 200 | return NULL; |
| 201 | } |
| 202 | |
| 203 | static entry_point_info_t *bl31_plat_get_next_kernel32_ep_info(void) |
| 204 | { |
| 205 | entry_point_info_t *next_image_info; |
| 206 | unsigned int mode; |
| 207 | |
| 208 | mode = 0; |
| 209 | |
| 210 | /* Kernel image is always non-secured */ |
| 211 | next_image_info = &bl33_image_ep_info; |
| 212 | |
| 213 | /* Figure out what mode we enter the non-secure world in */ |
| 214 | mode = MODE32_hyp; |
| 215 | /* |
| 216 | * TODO: Consider the possibility of specifying the SPSR in |
| 217 | * the FIP ToC and allowing the platform to have a say as |
| 218 | * well. |
| 219 | */ |
| 220 | |
| 221 | INFO("Kernel is 32Bit\n"); |
| 222 | next_image_info->spsr = SPSR_MODE32(mode, SPSR_T_ARM, SPSR_E_LITTLE, |
| 223 | (DAIF_FIQ_BIT | DAIF_IRQ_BIT | DAIF_ABT_BIT)); |
| 224 | next_image_info->pc = k_info.pc; |
| 225 | next_image_info->args.arg0 = k_info.r0; |
| 226 | next_image_info->args.arg1 = k_info.r1; |
| 227 | next_image_info->args.arg2 = k_info.r2; |
| 228 | |
| 229 | INFO("pc=0x%lx, r0=0x%" PRIx64 ", r1=0x%" PRIx64 ", r2=0x%" PRIx64 "\n", |
| 230 | next_image_info->pc, |
| 231 | next_image_info->args.arg0, |
| 232 | next_image_info->args.arg1, |
| 233 | next_image_info->args.arg2); |
| 234 | |
| 235 | SET_SECURITY_STATE(next_image_info->h.attr, NON_SECURE); |
| 236 | |
| 237 | /* None of the images on this platform can have 0x0 as the entrypoint */ |
| 238 | if (next_image_info->pc) { |
| 239 | return next_image_info; |
| 240 | } |
| 241 | |
| 242 | return NULL; |
| 243 | } |
| 244 | |
| 245 | static void bl31_prepare_kernel_entry(uint64_t k32_64) |
| 246 | { |
| 247 | entry_point_info_t *next_image_info = NULL; |
| 248 | uint32_t image_type; |
| 249 | |
| 250 | /* Determine which image to execute next */ |
| 251 | image_type = NON_SECURE; /* bl31_get_next_image_type(); */ |
| 252 | |
| 253 | /* Leave 2nd bootloader then jump to kernel */ |
| 254 | el1_is_2nd_bootloader = false; |
| 255 | |
| 256 | /* Program EL3 registers to enable entry into the next EL */ |
| 257 | if (k32_64 == LINUX_KERNEL_32) { |
| 258 | next_image_info = bl31_plat_get_next_kernel32_ep_info(); |
| 259 | } else { |
| 260 | next_image_info = bl31_plat_get_next_kernel64_ep_info(); |
| 261 | } |
| 262 | |
| 263 | assert(next_image_info); |
| 264 | assert(image_type == GET_SECURITY_STATE(next_image_info->h.attr)); |
| 265 | |
| 266 | INFO("BL31: Preparing for EL3 exit to %s world, Kernel\n", |
| 267 | (image_type == SECURE) ? "secure" : "normal"); |
| 268 | INFO("BL31: Next image address = 0x%" PRIx64 "\n", |
| 269 | next_image_info->pc); |
| 270 | INFO("BL31: Next image spsr = 0x%x\n", next_image_info->spsr); |
| 271 | cm_init_my_context(next_image_info); |
| 272 | cm_prepare_el3_exit(image_type); |
| 273 | } |
| 274 | |
| 275 | bool is_el1_2nd_bootloader(void) |
| 276 | { |
| 277 | return el1_is_2nd_bootloader; |
| 278 | } |
| 279 | |
| 280 | /******************************************************************************* |
| 281 | * Return a pointer to the 'entry_point_info' structure of the next image for |
| 282 | * the security state specified. BL33 corresponds to the non-secure image type |
| 283 | * while BL32 corresponds to the secure image type. A NULL pointer is returned |
| 284 | * if the image does not exist. |
| 285 | ******************************************************************************/ |
| 286 | entry_point_info_t *bl31_plat_get_next_image_ep_info(uint32_t type) |
| 287 | { |
| 288 | entry_point_info_t *next_image_info; |
| 289 | |
| 290 | next_image_info = (type == NON_SECURE) ? &bl33_image_ep_info : &bl32_image_ep_info; |
| 291 | |
| 292 | /* None of the images on this platform can have 0x0 as the entrypoint */ |
| 293 | if (next_image_info->pc) { |
| 294 | return next_image_info; |
| 295 | } |
| 296 | return NULL; |
| 297 | } |
| 298 | |
| 299 | u_register_t boot_to_kernel(u_register_t x1, |
| 300 | u_register_t x2, |
| 301 | u_register_t x3, |
| 302 | u_register_t x4, |
| 303 | void *handle, |
| 304 | struct smccc_res *smccc_ret) |
| 305 | { |
| 306 | static uint8_t kernel_boot_once_flag; |
| 307 | |
| 308 | /* only support in booting flow */ |
| 309 | if (kernel_boot_once_flag == 0) { |
| 310 | kernel_boot_once_flag = 1; |
| 311 | |
| 312 | INFO("save kernel info\n"); |
| 313 | save_kernel_info(x1, x2, x3, x4); |
| 314 | bl31_prepare_kernel_entry(x4); |
| 315 | INFO("el3_exit\n"); |
| 316 | /* |
| 317 | * FIXME: no better way so far to prevent from |
| 318 | * SiP root handler wipe x0~x3 if not assign smccc_ret |
| 319 | * return register |
| 320 | */ |
| 321 | smccc_ret->a1 = x3; |
| 322 | |
| 323 | mtk_init_one_level(MTK_INIT_LVL_BL33_DEFER); |
| 324 | |
| 325 | #if MTK_CONSOLE_RUNTIME_DISABLE |
| 326 | INFO("Turn off BL31 console\n"); |
| 327 | mtk_console_core_end(); |
| 328 | #endif |
| 329 | |
| 330 | /* Re-assign as x0 register entering Linux kernel */ |
| 331 | return x2; |
| 332 | } |
| 333 | return 0; |
| 334 | } |
| 335 | /* Register SiP SMC service */ |
| 336 | DECLARE_SMC_HANDLER(MTK_SIP_KERNEL_BOOT, boot_to_kernel); |