X-Git-Url: https://git.sur5r.net/?a=blobdiff_plain;ds=sidebyside;f=arch%2Farm%2Flib%2Fbootm.c;h=a7f7c67997691c3b33d49bd6fa676fe6fcdb05b6;hb=1dfdd9ba4e699562a3b282f4fb5efe4c80e6e8c7;hp=1b6e0ace45372417af0b671aac632fce309b12f3;hpb=fb651b10d43be36e7d7e16704c4b5ea1e295587a;p=u-boot diff --git a/arch/arm/lib/bootm.c b/arch/arm/lib/bootm.c index 1b6e0ace45..a7f7c67997 100644 --- a/arch/arm/lib/bootm.c +++ b/arch/arm/lib/bootm.c @@ -9,19 +9,7 @@ * * Copyright (C) 2001 Erik Mouw (J.A.K.Mouw@its.tudelft.nl) * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * SPDX-License-Identifier: GPL-2.0+ */ #include @@ -32,7 +20,14 @@ #include #include #include +#include #include +#include +#include + +#if defined(CONFIG_ARMV7_NONSEC) || defined(CONFIG_ARMV7_VIRT) +#include +#endif DECLARE_GLOBAL_DATA_PTR; @@ -68,9 +63,15 @@ void arch_lmb_reserve(struct lmb *lmb) gd->bd->bi_dram[0].start + gd->bd->bi_dram[0].size - sp); } -static void announce_and_cleanup(void) +/** + * announce_and_cleanup() - Print message and prepare for kernel boot + * + * @fake: non-zero to do everything except actually boot + */ +static void announce_and_cleanup(int fake) { - printf("\nStarting kernel ...\n\n"); + printf("\nStarting kernel ...%s\n\n", fake ? + "(fake run for tracing)" : ""); bootstage_mark_name(BOOTSTAGE_ID_BOOTM_HANDOFF, "start_kernel"); #ifdef CONFIG_BOOTSTAGE_FDT bootstage_fdt_add_report(); @@ -186,6 +187,18 @@ static void setup_end_tag(bd_t *bd) __weak void setup_board_tags(struct tag **in_params) {} +#ifdef CONFIG_ARM64 +static void do_nonsec_virt_switch(void) +{ + smp_kick_all_cpus(); + flush_dcache_all(); /* flush cache before swtiching to EL2 */ + armv8_switch_to_el2(); +#ifdef CONFIG_ARMV8_SWITCH_TO_EL1 + armv8_switch_to_el1(); +#endif +} +#endif + /* Subcommand: PREP */ static void boot_prep_linux(bootm_headers_t *images) { @@ -224,13 +237,53 @@ static void boot_prep_linux(bootm_headers_t *images) } } +#if defined(CONFIG_ARMV7_NONSEC) || defined(CONFIG_ARMV7_VIRT) +static bool boot_nonsec(void) +{ + char *s = getenv("bootm_boot_mode"); +#ifdef CONFIG_ARMV7_BOOT_SEC_DEFAULT + bool nonsec = false; +#else + bool nonsec = true; +#endif + + if (s && !strcmp(s, "sec")) + nonsec = false; + + if (s && !strcmp(s, "nonsec")) + nonsec = true; + + return nonsec; +} +#endif + /* Subcommand: GO */ -static void boot_jump_linux(bootm_headers_t *images) +static void boot_jump_linux(bootm_headers_t *images, int flag) { +#ifdef CONFIG_ARM64 + void (*kernel_entry)(void *fdt_addr, void *res0, void *res1, + void *res2); + int fake = (flag & BOOTM_STATE_OS_FAKE_GO); + + kernel_entry = (void (*)(void *fdt_addr, void *res0, void *res1, + void *res2))images->ep; + + debug("## Transferring control to Linux (at address %lx)...\n", + (ulong) kernel_entry); + bootstage_mark(BOOTSTAGE_ID_RUN_OS); + + announce_and_cleanup(fake); + + if (!fake) { + do_nonsec_virt_switch(); + kernel_entry(images->ft_addr, NULL, NULL, NULL); + } +#else unsigned long machid = gd->bd->bi_arch_number; char *s; void (*kernel_entry)(int zero, int arch, uint params); unsigned long r2; + int fake = (flag & BOOTM_STATE_OS_FAKE_GO); kernel_entry = (void (*)(int, int, uint))images->ep; @@ -243,14 +296,24 @@ static void boot_jump_linux(bootm_headers_t *images) debug("## Transferring control to Linux (at address %08lx)" \ "...\n", (ulong) kernel_entry); bootstage_mark(BOOTSTAGE_ID_RUN_OS); - announce_and_cleanup(); + announce_and_cleanup(fake); if (IMAGE_ENABLE_OF_LIBFDT && images->ft_len) r2 = (unsigned long)images->ft_addr; else r2 = gd->bd->bi_boot_params; - kernel_entry(0, machid, r2); + if (!fake) { +#if defined(CONFIG_ARMV7_NONSEC) || defined(CONFIG_ARMV7_VIRT) + if (boot_nonsec()) { + armv7_init_nonsec(); + secure_ram_addr(_do_nonsec_entry)(kernel_entry, + 0, machid, r2); + } else +#endif + kernel_entry(0, machid, r2); + } +#endif } /* Main Entry point for arm bootm implementation @@ -259,7 +322,8 @@ static void boot_jump_linux(bootm_headers_t *images) * DIFFERENCE: Instead of calling prep and go at the end * they are called if subcommand is equal 0. */ -int do_bootm_linux(int flag, int argc, char *argv[], bootm_headers_t *images) +int do_bootm_linux(int flag, int argc, char * const argv[], + bootm_headers_t *images) { /* No need for those on ARM */ if (flag & BOOTM_STATE_OS_BD_T || flag & BOOTM_STATE_OS_CMDLINE) @@ -270,13 +334,13 @@ int do_bootm_linux(int flag, int argc, char *argv[], bootm_headers_t *images) return 0; } - if (flag & BOOTM_STATE_OS_GO) { - boot_jump_linux(images); + if (flag & (BOOTM_STATE_OS_GO | BOOTM_STATE_OS_FAKE_GO)) { + boot_jump_linux(images, flag); return 0; } boot_prep_linux(images); - boot_jump_linux(images); + boot_jump_linux(images, flag); return 0; } @@ -291,21 +355,46 @@ struct zimage_header { #define LINUX_ARM_ZIMAGE_MAGIC 0x016f2818 -int bootz_setup(void *image, void **start, void **end) +int bootz_setup(ulong image, ulong *start, ulong *end) { - struct zimage_header *zi = (struct zimage_header *)image; + struct zimage_header *zi; + zi = (struct zimage_header *)map_sysmem(image, 0); if (zi->zi_magic != LINUX_ARM_ZIMAGE_MAGIC) { puts("Bad Linux ARM zImage magic!\n"); return 1; } - *start = (void *)zi->zi_start; - *end = (void *)zi->zi_end; + *start = zi->zi_start; + *end = zi->zi_end; - debug("Kernel image @ 0x%08x [ 0x%08x - 0x%08x ]\n", - (uint32_t)image, (uint32_t)*start, (uint32_t)*end); + printf("Kernel image @ %#08lx [ %#08lx - %#08lx ]\n", image, *start, + *end); return 0; } + #endif /* CONFIG_CMD_BOOTZ */ + +#if defined(CONFIG_BOOTM_VXWORKS) +void boot_prep_vxworks(bootm_headers_t *images) +{ +#if defined(CONFIG_OF_LIBFDT) + int off; + + if (images->ft_addr) { + off = fdt_path_offset(images->ft_addr, "/memory"); + if (off < 0) { + if (arch_fixup_fdt(images->ft_addr)) + puts("## WARNING: fixup memory failed!\n"); + } + } +#endif + cleanup_before_linux(); +} +void boot_jump_vxworks(bootm_headers_t *images) +{ + /* ARM VxWorks requires device tree physical address to be passed */ + ((void (*)(void *))images->ep)(images->ft_addr); +} +#endif