| /* |
| * Copyright (c) 2018 MediaTek Inc. |
| * |
| * Permission is hereby granted, free of charge, to any person obtaining |
| * a copy of this software and associated documentation files |
| * (the "Software"), to deal in the Software without restriction, |
| * including without limitation the rights to use, copy, modify, merge, |
| * publish, distribute, sublicense, and/or sell copies of the Software, |
| * and to permit persons to whom the Software is furnished to do so, |
| * subject to the following conditions: |
| * |
| * The above copyright notice and this permission notice shall be |
| * included in all copies or substantial portions of the Software. |
| * |
| * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, |
| * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF |
| * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. |
| * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY |
| * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, |
| * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE |
| * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. |
| */ |
| #include <assert.h> |
| #include <boot_mode.h> |
| #include <errno.h> |
| #include <kernel/vm.h> |
| #include <lib/mempool.h> |
| #include <libfdt.h> |
| #include <platform.h> |
| #include <platform/platform_blx.h> |
| #include <stdbool.h> |
| #include <string.h> |
| #include <trace.h> |
| |
| #include "blx_common.h" |
| #include "blxboot_ab.h" |
| #include "blxboot_plat.h" |
| |
| #define LOCAL_TRACE 0 |
| |
| struct bl2boot { |
| struct blxboot commonboot; |
| |
| /* keep image data pointer for quick reference */ |
| struct image_load_data *bl33imgdata; |
| struct image_load_data *bootimgdata; |
| struct image_load_data *dtboimgdata; |
| struct image_load_data *tzimgdata; |
| struct image_load_data *vpdimgdata; |
| }; |
| |
| enum { |
| ARM32_TO_ARM32, |
| ARM32_TO_ARM64, |
| ARM64_TO_ARM32, |
| ARM64_TO_ARM64, |
| }; |
| |
| static bool is_arch_arm64(void) |
| { |
| #if ARCH_ARM64 |
| return true; |
| #else |
| return false; |
| #endif |
| } |
| |
| static bool is_enabled_builtin_bl33(void) |
| { |
| #if ENABLE_BUILTIN_BL33 |
| return true; |
| #else |
| return false; |
| #endif |
| } |
| |
| static void update_builtin_bl33(struct blxboot *obj) |
| { |
| struct bl2boot *bl2obj = (struct bl2boot *)obj; |
| struct image_load_data *bl33imgdata; |
| uint32_t *bl33; |
| |
| if (bl2obj == NULL) |
| return; |
| |
| bl33imgdata = bl2obj->bl33imgdata; |
| bl33 = (uint32_t *)paddr_to_kvaddr(bl33imgdata->kernel_entry); |
| |
| bl33[12] = (ulong)(bl2obj->bootimgdata->dtb_load); |
| bl33[14] = (unsigned)0; |
| bl33[16] = (unsigned)0; |
| bl33[18] = (unsigned)0; |
| bl33[20] = (ulong)(bl2obj->bootimgdata->kernel_entry); |
| bl33[21] = (ulong)0; |
| bl33[22] = (unsigned)MACH_TYPE; |
| } |
| |
| static int arm_exec_mode_transition(void) |
| { |
| #if ARCH_ARM64 |
| /*Assume BL31 is aarch64 in case BL2 is aarch64. No handling BL2 of aarch64 |
| and BL33 of aarch32. */ |
| return ARM64_TO_ARM64; |
| #else |
| #if BL2_BOOT_NEXT_64BITS |
| return ARM32_TO_ARM64; |
| #else |
| return ARM32_TO_ARM32; |
| #endif |
| #endif |
| } |
| |
| void mtk_sip(ulong smc_fid, ulong tz_ep, ulong bl33_addr, ulong boot_reason) |
| { |
| jump_func_type jump_func = (jump_func_type)tz_ep; |
| (*jump_func)(bl33_addr, boot_reason, 0UL, 0UL); |
| } |
| |
| static void exitfn_smc64_to_next64(ulong smc_fid, ulong tz_ep, |
| ulong bl33_addr, ulong unused0) |
| { |
| __asm__ volatile("smc #0\n\t"); |
| } |
| |
| static void exitfn_jump32(ulong unused0, ulong tz_ep, |
| ulong bl33_addr, ulong boot_arg) |
| { |
| jump_func_type jump_fn = (jump_func_type)tz_ep; |
| (*jump_fn)(bl33_addr, boot_arg, 0, 0); |
| } |
| |
| __WEAK void platform_set_aarch64_reset_vector(ulong vector) |
| { |
| /* implementation in platform, or panic. */ |
| PANIC_UNIMPLEMENTED; |
| } |
| |
| static void exitfn_warmreset32_to_next64(ulong unused0, ulong tz_ep, |
| ulong bl33_addr, ulong boot_arg) |
| { |
| /* set aarch64 reset vector */ |
| platform_set_aarch64_reset_vector(tz_ep); |
| |
| /* warm reset to aarch64 */ |
| #if ARCH_ARM |
| uint32_t tmpr; |
| |
| __asm__ volatile( |
| "mrc p15, 0, %0, c12, c0, 2\n\t" |
| "orr %0, %0, #1\n\t" |
| "mcr p15, 0, %0, c12, c0, 2\n\t" |
| "mrc p15, 0, %0, c12, c0, 2\n\t" |
| "orr %0, %0, #2\n\t" |
| "mcr p15, 0, %0, c12, c0, 2\n\t" |
| "mov r0, %2\n\t" |
| "mov r1, %3\n\t" |
| "dsb sy\n\t" |
| "isb sy\n\t" |
| "wfi\n\t" |
| : "=r" (tmpr) |
| : "0" (tmpr), "r" (bl33_addr), "r" (boot_arg) |
| ); |
| #endif |
| } |
| |
| static void notify(struct blxboot *obj, struct imageinfo_t *img) |
| { |
| struct image_load_data *imgdata = img->imgdata; |
| struct bl2boot *bl2obj = (struct bl2boot *)obj; |
| |
| LTRACEF("%s: %s\n", __func__, imgdata->part_name); |
| switch (img->type) { |
| case IMGTYPE_TZ: |
| bl2obj->tzimgdata = imgdata; |
| break; |
| case IMGTYPE_BL33: |
| case IMGTYPE_BUILTIN_BL33: |
| bl2obj->bl33imgdata = imgdata; |
| break; |
| case IMGTYPE_KERNEL: |
| bl2obj->bootimgdata = imgdata; |
| break; |
| case IMGTYPE_DTBO: |
| bl2obj->dtboimgdata = imgdata; |
| break; |
| case IMGTYPE_VPD: |
| bl2obj->vpdimgdata = imgdata; |
| break; |
| case IMGTYPE_SCPSYS: |
| plat_start_scpsys(); |
| LTRACEF("start scpsys@%llx\n", current_time_hires()); |
| break; |
| default: |
| break; |
| } |
| } |
| |
| static void fixup_image(struct blxboot *obj, void *fdt_dtb) |
| { |
| if (is_enabled_builtin_bl33()) |
| update_builtin_bl33(obj); |
| } |
| |
| static void setup_boot_param(struct blxboot *obj, struct boot_param *prm) |
| { |
| struct bl2boot *bl2obj = (struct bl2boot *)obj; |
| uint32_t boot_mode; |
| |
| prm->arg0 = MTK_SIP_KERNEL_BOOT_AARCH64; /* only for 64bits BL2 */ |
| prm->arg1 = bl2obj->tzimgdata->kernel_entry; /* next entry point */ |
| prm->arg2 = bl2obj->bl33imgdata->kernel_entry; /* next boot param */ |
| /* pass bootargs from bl2 to bl33 */ |
| extern void *bl2_set_boot_args(uint32_t boot_mode) __attribute__((weak)); |
| boot_mode = obj->bootcfg.boot_mode; |
| prm->arg3 = bl2_set_boot_args ? |
| (ulong)kvaddr_to_paddr(bl2_set_boot_args(boot_mode)) : 0; |
| } |
| |
| static int init(void) |
| { |
| int rc; |
| |
| rc = check_ab_boot(); |
| if ((rc == 0) || (rc == -ENOTSUP)) |
| return 0; |
| |
| return rc; |
| } |
| |
| static void get_overlay_image(struct blxboot *obj, void **fdt_dtb, |
| void **dtbo, void **vpd) |
| { |
| struct bl2boot *bl2obj = (struct bl2boot *)obj; |
| |
| assert(obj); |
| |
| *fdt_dtb = NULL; |
| *dtbo = NULL; |
| *vpd = NULL; |
| if (!is_enabled_builtin_bl33()) |
| return; |
| |
| if (bl2obj->bootimgdata) |
| *fdt_dtb = (void *)bl2obj->bootimgdata->dtb_load; |
| |
| if (bl2obj->dtboimgdata) |
| *dtbo = (void *)bl2obj->dtboimgdata->dtb_load; |
| |
| if (bl2obj->vpdimgdata) |
| *vpd = (void *)bl2obj->vpdimgdata->dtb_load; |
| } |
| |
| struct blxboot *blxboot_create(void) |
| { |
| struct bl2boot *bl2obj; |
| struct blxboot *blxobj; |
| struct blxOps *ops; |
| struct blxCfg *cfg; |
| |
| bl2obj = mempool_alloc(sizeof(struct bl2boot), MEMPOOL_ANY); |
| if (!bl2obj) |
| return NULL; |
| |
| memset(bl2obj, 0, sizeof(struct bl2boot)); |
| |
| blxobj = (struct blxboot *)bl2obj; |
| |
| cfg = &blxobj->bootcfg; |
| cfg->boot_mode = NORMAL_BOOT; |
| cfg->ab_suffix = NULL; |
| |
| ops = &blxobj->ops; |
| ops->init = init; |
| ops->notify = notify; |
| ops->fixup_image = fixup_image; |
| ops->setup_boot_param = setup_boot_param; |
| ops->get_overlay_image = get_overlay_image; |
| |
| switch (arm_exec_mode_transition()) { |
| case ARM32_TO_ARM32: |
| ops->exit = exitfn_jump32; |
| break; |
| case ARM32_TO_ARM64: |
| ops->exit = exitfn_warmreset32_to_next64; |
| break; |
| case ARM64_TO_ARM32: |
| ops->exit = NULL; /* assert to stop here? */ |
| break; |
| case ARM64_TO_ARM64: |
| ops->exit = exitfn_smc64_to_next64; |
| break; |
| } |
| |
| return (struct blxboot *)bl2obj; |
| } |