Loading...
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 | // SPDX-License-Identifier: GPL-2.0+ /* * Copyright (C) 2019 Fraunhofer AISEC, * Lukas Auer <lukas.auer@aisec.fraunhofer.de> * * Based on common/spl/spl_atf.c */ #include <cpu_func.h> #include <errno.h> #include <hang.h> #include <image.h> #include <spl.h> #include <asm/global_data.h> #include <asm/smp.h> #include <opensbi.h> #include <linux/libfdt.h> #include <linux/printk.h> #include <mapmem.h> DECLARE_GLOBAL_DATA_PTR; struct fw_dynamic_info opensbi_info; static int spl_opensbi_find_os_node(void *blob, int *uboot_node, int os_type) { int fit_images_node, node; const char *fit_os; fit_images_node = fdt_path_offset(blob, "/fit-images"); if (fit_images_node < 0) return -ENODEV; fdt_for_each_subnode(node, blob, fit_images_node) { fit_os = fdt_getprop(blob, node, FIT_OS_PROP, NULL); if (!fit_os) continue; if (genimg_get_os_id(fit_os) == os_type) { *uboot_node = node; return 0; } } return -ENODEV; } void __noreturn spl_invoke_opensbi(struct spl_image_info *spl_image) { int ret, os_node; ulong os_entry; int os_type; typedef void __noreturn (*opensbi_entry_t)(ulong hartid, ulong dtb, ulong info); opensbi_entry_t opensbi_entry; if (!spl_image->fdt_addr) { pr_err("No device tree specified in SPL image\n"); hang(); } if (!IS_ALIGNED((uintptr_t)spl_image->fdt_addr, 8)) { pr_err("SPL image loaded an improperly-aligned device tree\n"); hang(); } /* * Originally, u-boot-spl will place DTB directly after the kernel, * but the size of the kernel did not include the BSS section, which * means u-boot-spl will place the DTB in the kernel BSS section * causing the DTB to be cleared by kernel BSS initializtion. * Moving DTB in front of the kernel can avoid the error. */ #if CONFIG_IS_ENABLED(LOAD_FIT_OPENSBI_OS_BOOT) && \ CONFIG_VAL(PAYLOAD_ARGS_ADDR) memcpy((void *)CONFIG_SPL_PAYLOAD_ARGS_ADDR, spl_image->fdt_addr, fdt_totalsize(spl_image->fdt_addr)); spl_image->fdt_addr = map_sysmem(CONFIG_SPL_PAYLOAD_ARGS_ADDR, 0); #endif /* * Find next os image in /fit-images * The next os image default is u-boot proper, once enable * OpenSBI OS boot mode, the OS image should be linux. */ if (CONFIG_IS_ENABLED(LOAD_FIT_OPENSBI_OS_BOOT)) os_type = IH_OS_LINUX; else os_type = IH_OS_U_BOOT; ret = spl_opensbi_find_os_node(spl_image->fdt_addr, &os_node, os_type); if (ret) { pr_err("Can't find %s node for opensbi, %d\n", genimg_get_os_name(os_type), ret); hang(); } /* Get U-Boot entry point */ ret = fit_image_get_entry(spl_image->fdt_addr, os_node, &os_entry); if (ret) ret = fit_image_get_load(spl_image->fdt_addr, os_node, &os_entry); /* Prepare opensbi_info object */ opensbi_info.magic = FW_DYNAMIC_INFO_MAGIC_VALUE; opensbi_info.version = FW_DYNAMIC_INFO_VERSION; opensbi_info.next_addr = os_entry; opensbi_info.next_mode = FW_DYNAMIC_INFO_NEXT_MODE_S; opensbi_info.options = CONFIG_SPL_OPENSBI_SCRATCH_OPTIONS; opensbi_info.boot_hart = gd->arch.boot_hart; opensbi_entry = (opensbi_entry_t)spl_image->entry_point; invalidate_icache_all(); #ifdef CONFIG_SPL_SMP /* * Start OpenSBI on all secondary harts and wait for acknowledgment. * * OpenSBI first relocates itself to its link address. This is done by * the main hart. To make sure no hart is still running U-Boot SPL * during relocation, we wait for all secondary harts to acknowledge * the call-function request before entering OpenSBI on the main hart. * Otherwise, code corruption can occur if the link address ranges of * U-Boot SPL and OpenSBI overlap. */ ret = smp_call_function((ulong)spl_image->entry_point, (ulong)spl_image->fdt_addr, (ulong)&opensbi_info, 1); if (ret) hang(); #endif opensbi_entry(gd->arch.boot_hart, (ulong)spl_image->fdt_addr, (ulong)&opensbi_info); } |