/* Copyright(c) 2021 Intel Corporation. All rights reserved. * SPDX-License-Identifier: Apache-2.0 */ #include #include #include #include #include #include #include #include #include #include #include "manifest.h" /* Important note about linkage: * * The C code here, starting from boot_core0(), is running entirely in * IMR memory. The sram banks are not initialized yet and the Zephyr * code is not yet copied there. No use of this memory is legal until * after parse_manifest() returns. This means that all symbols in * this file must be flagged "__imr" or "__imrdata" (or be guaranteed * to inline via ALWAYS_INLINE, normal gcc "inline" is only a hint)! * * There's a similar note with Xtensa register windows: the Zephyr * exception handles for window overflow are not present in IMR. * While on existing systems, we start running with a VECBASE pointing * to ROM handlers (that seem to work), it seems unsafe to rely on * that. It's not possible to hit an overflow until at least four * nested function calls, so this is mostly theoretical. Nonetheless * care should be taken here to make sure the function tree remains * shallow until SRAM initialization is finished. */ /* Various cAVS platform dependencies needed by the bootloader code. * These probably want to migrate to devicetree. */ #define HOST_PAGE_SIZE 4096 #define MANIFEST_SEGMENT_COUNT 3 /* FIXME: Use Kconfig or some other means */ #if !defined(CONFIG_SOC_SERIES_INTEL_ACE) #define RESET_MEMORY_HOLE #endif /* Initial/true entry point. Does nothing but jump to * z_boot_asm_entry (which cannot be here, because it needs to be able * to reference immediates which must link before it) */ __asm__(".pushsection .boot_entry.text, \"ax\" \n\t" ".global rom_entry \n\t" "rom_entry: \n\t" " j z_boot_asm_entry \n\t" ".popsection \n\t"); /* Entry stub. Sets up register windows and stack such that we can * enter C code successfully, and calls boot_core0() */ #define STRINGIFY_MACRO(x) Z_STRINGIFY(x) #define IMRSTACK STRINGIFY_MACRO(IMR_BOOT_LDR_MANIFEST_BASE) __asm__(".section .imr.z_boot_asm_entry, \"x\" \n\t" ".align 4 \n\t" "z_boot_asm_entry: \n\t" " movi a0, 0x4002f \n\t" " wsr a0, PS \n\t" " movi a0, 0 \n\t" " wsr a0, WINDOWBASE \n\t" " movi a0, 1 \n\t" " wsr a0, WINDOWSTART \n\t" " rsync \n\t" " movi a1, " IMRSTACK "\n\t" " call4 boot_core0 \n\t"); static __imr void parse_module(struct sof_man_fw_header *hdr, struct sof_man_module *mod) { int i; uint32_t bias; /* each module has 3 segments */ for (i = 0; i < MANIFEST_SEGMENT_COUNT; i++) { switch (mod->segment[i].flags.r.type) { case SOF_MAN_SEGMENT_TEXT: case SOF_MAN_SEGMENT_DATA: if (mod->segment[i].flags.r.load == 0) { continue; } bias = mod->segment[i].file_offset - SOF_MAN_ELF_TEXT_OFFSET; /* copy from IMR to SRAM */ bmemcpy((void *)mod->segment[i].v_base_addr, (uint8_t *)hdr + bias, mod->segment[i].flags.r.length * HOST_PAGE_SIZE); break; case SOF_MAN_SEGMENT_BSS: /* already bbzero'd by sram init */ break; default: /* ignore */ break; } } } #define MAN_SKIP_ENTRIES 1 /* parse FW manifest and copy modules */ __imr void parse_manifest(void) { struct sof_man_fw_desc *desc = (struct sof_man_fw_desc *)IMR_BOOT_LDR_MANIFEST_BASE; struct sof_man_fw_header *hdr = &desc->header; struct sof_man_module *mod; int i; sys_cache_data_invd_range(hdr, sizeof(*hdr)); /* copy module to SRAM - skip bootloader module */ for (i = MAN_SKIP_ENTRIES; i < hdr->num_module_entries; i++) { mod = desc->man_module + i; sys_cache_data_invd_range(mod, sizeof(*mod)); parse_module(hdr, mod); } } extern void hp_sram_init(uint32_t memory_size); extern void lp_sram_init(void); __imr void boot_core0(void) { cpu_early_init(); #ifdef CONFIG_ADSP_DISABLE_L2CACHE_AT_BOOT ADSP_L2PCFG_REG = 0; #endif #ifdef RESET_MEMORY_HOLE /* reset memory hole */ CAVS_SHIM.l2mecs = 0; #endif hp_sram_init(L2_SRAM_SIZE); lp_sram_init(); parse_manifest(); sys_cache_data_flush_all(); xtensa_vecbase_lock(); /* Zephyr! */ extern FUNC_NORETURN void z_cstart(void); z_cstart(); }