diff options
Diffstat (limited to 'common')
-rw-r--r-- | common/aarch64/early_exceptions.S | 171 | ||||
-rw-r--r-- | common/bl_common.c | 432 | ||||
-rw-r--r-- | common/debug.c | 102 | ||||
-rw-r--r-- | common/fip.c | 248 | ||||
-rw-r--r-- | common/memtest.c | 369 |
5 files changed, 1322 insertions, 0 deletions
diff --git a/common/aarch64/early_exceptions.S b/common/aarch64/early_exceptions.S new file mode 100644 index 0000000..90f5421 --- /dev/null +++ b/common/aarch64/early_exceptions.S @@ -0,0 +1,171 @@ +/* + * Copyright (c) 2013-2014, ARM Limited and Contributors. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * Neither the name of ARM nor the names of its contributors may be used + * to endorse or promote products derived from this software without specific + * prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#include <asm_macros.S> +#include <runtime_svc.h> + + .globl early_exceptions + + .section .vectors, "ax"; .align 11 + + /* ----------------------------------------------------- + * Very simple stackless exception handlers used by BL2 + * and BL3-1 bootloader stages. BL3-1 uses them before + * stacks are setup. BL2 uses them throughout. + * ----------------------------------------------------- + */ + .align 7 +early_exceptions: + /* ----------------------------------------------------- + * Current EL with SP0 : 0x0 - 0x180 + * ----------------------------------------------------- + */ +SynchronousExceptionSP0: + mov x0, #SYNC_EXCEPTION_SP_EL0 + bl plat_report_exception + b SynchronousExceptionSP0 + check_vector_size SynchronousExceptionSP0 + + .align 7 +IrqSP0: + mov x0, #IRQ_SP_EL0 + bl plat_report_exception + b IrqSP0 + check_vector_size IrqSP0 + + .align 7 +FiqSP0: + mov x0, #FIQ_SP_EL0 + bl plat_report_exception + b FiqSP0 + check_vector_size FiqSP0 + + .align 7 +SErrorSP0: + mov x0, #SERROR_SP_EL0 + bl plat_report_exception + b SErrorSP0 + check_vector_size SErrorSP0 + + /* ----------------------------------------------------- + * Current EL with SPx: 0x200 - 0x380 + * ----------------------------------------------------- + */ + .align 7 +SynchronousExceptionSPx: + mov x0, #SYNC_EXCEPTION_SP_ELX + bl plat_report_exception + b SynchronousExceptionSPx + check_vector_size SynchronousExceptionSPx + + .align 7 +IrqSPx: + mov x0, #IRQ_SP_ELX + bl plat_report_exception + b IrqSPx + check_vector_size IrqSPx + + .align 7 +FiqSPx: + mov x0, #FIQ_SP_ELX + bl plat_report_exception + b FiqSPx + check_vector_size FiqSPx + + .align 7 +SErrorSPx: + mov x0, #SERROR_SP_ELX + bl plat_report_exception + b SErrorSPx + check_vector_size SErrorSPx + + /* ----------------------------------------------------- + * Lower EL using AArch64 : 0x400 - 0x580 + * ----------------------------------------------------- + */ + .align 7 +SynchronousExceptionA64: + mov x0, #SYNC_EXCEPTION_AARCH64 + bl plat_report_exception + b SynchronousExceptionA64 + check_vector_size SynchronousExceptionA64 + + .align 7 +IrqA64: + mov x0, #IRQ_AARCH64 + bl plat_report_exception + b IrqA64 + check_vector_size IrqA64 + + .align 7 +FiqA64: + mov x0, #FIQ_AARCH64 + bl plat_report_exception + b FiqA64 + check_vector_size FiqA64 + + .align 7 +SErrorA64: + mov x0, #SERROR_AARCH64 + bl plat_report_exception + b SErrorA64 + check_vector_size SErrorA64 + + /* ----------------------------------------------------- + * Lower EL using AArch32 : 0x0 - 0x180 + * ----------------------------------------------------- + */ + .align 7 +SynchronousExceptionA32: + mov x0, #SYNC_EXCEPTION_AARCH32 + bl plat_report_exception + b SynchronousExceptionA32 + check_vector_size SynchronousExceptionA32 + + .align 7 +IrqA32: + mov x0, #IRQ_AARCH32 + bl plat_report_exception + b IrqA32 + check_vector_size IrqA32 + + .align 7 +FiqA32: + mov x0, #FIQ_AARCH32 + bl plat_report_exception + b FiqA32 + check_vector_size FiqA32 + + .align 7 +SErrorA32: + mov x0, #SERROR_AARCH32 + bl plat_report_exception + b SErrorA32 + check_vector_size SErrorA32 diff --git a/common/bl_common.c b/common/bl_common.c new file mode 100644 index 0000000..f0d32d0 --- /dev/null +++ b/common/bl_common.c @@ -0,0 +1,432 @@ +/* + * Copyright (c) 2013-2014, ARM Limited and Contributors. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * Neither the name of ARM nor the names of its contributors may be used + * to endorse or promote products derived from this software without specific + * prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#include <arch.h> +#include <arch_helpers.h> +#include <assert.h> +#include <bl_common.h> +#include <debug.h> +#include <io_storage.h> +#include <platform.h> +#include <errno.h> +#include <stdio.h> +#include <stdint.h> +#include <string.h> + +unsigned long page_align(unsigned long value, unsigned dir) +{ + unsigned long page_size = 1 << FOUR_KB_SHIFT; + + /* Round up the limit to the next page boundary */ + if (value & (page_size - 1)) { + value &= ~(page_size - 1); + if (dir == UP) + value += page_size; + } + + return value; +} + +static inline unsigned int is_page_aligned (unsigned long addr) { + const unsigned long page_size = 1 << FOUR_KB_SHIFT; + + return (addr & (page_size - 1)) == 0; +} + +void change_security_state(unsigned int target_security_state) +{ + unsigned long scr = read_scr(); + + if (target_security_state == SECURE) + scr &= ~SCR_NS_BIT; + else if (target_security_state == NON_SECURE) + scr |= SCR_NS_BIT; + else + assert(0); + + write_scr(scr); +} + + +/******************************************************************************* + * The next function has a weak definition. Platform specific code can override + * it if it wishes to. + ******************************************************************************/ +#pragma weak init_bl2_mem_layout + +/******************************************************************************* + * Function that takes a memory layout into which BL2 has been either top or + * bottom loaded along with the address where BL2 has been loaded in it. Using + * this information, it populates bl2_mem_layout to tell BL2 how much memory + * it has access to and how much is available for use. + ******************************************************************************/ +void init_bl2_mem_layout(meminfo_t *bl1_mem_layout, + meminfo_t *bl2_mem_layout, + unsigned int load_type, + unsigned long bl2_base) +{ + unsigned tmp; + + if (load_type == BOT_LOAD) { + bl2_mem_layout->total_base = bl2_base; + tmp = bl1_mem_layout->free_base - bl2_base; + bl2_mem_layout->total_size = bl1_mem_layout->free_size + tmp; + + } else { + bl2_mem_layout->total_base = bl1_mem_layout->free_base; + tmp = bl1_mem_layout->total_base + bl1_mem_layout->total_size; + bl2_mem_layout->total_size = tmp - bl1_mem_layout->free_base; + } + + bl2_mem_layout->free_base = bl1_mem_layout->free_base; + bl2_mem_layout->free_size = bl1_mem_layout->free_size; + bl2_mem_layout->attr = load_type; + + flush_dcache_range((unsigned long) bl2_mem_layout, sizeof(meminfo_t)); + return; +} + +static void dump_load_info(unsigned long image_load_addr, + unsigned long image_size, + const meminfo_t *mem_layout) +{ +#if 0 + printf("Trying to load image at address 0x%lx, size = 0x%lx\r\n", + image_load_addr, image_size); + printf("Current memory layout:\r\n"); + printf(" total region = [0x%lx, 0x%lx]\r\n", mem_layout->total_base, + mem_layout->total_base + mem_layout->total_size); + printf(" free region = [0x%lx, 0x%lx]\r\n", mem_layout->free_base, + mem_layout->free_base + mem_layout->free_size); +#endif +} + +/* Generic function to return the size of an image */ +unsigned long image_size(const char *image_name) +{ + uintptr_t dev_handle; + uintptr_t image_handle; + uintptr_t image_spec; + size_t image_size = 0; + int io_result = IO_FAIL; + + assert(image_name != NULL); + + /* Obtain a reference to the image by querying the platform layer */ + io_result = plat_get_image_source(image_name, &dev_handle, &image_spec); + if (io_result != IO_SUCCESS) { + WARN("Failed to obtain reference to image '%s' (%i)\n", + image_name, io_result); + return 0; + } + + /* Attempt to access the image */ + io_result = io_open(dev_handle, image_spec, &image_handle); + if (io_result != IO_SUCCESS) { + WARN("Failed to access image '%s' (%i)\n", + image_name, io_result); + return 0; + } + + /* Find the size of the image */ + io_result = io_size(image_handle, &image_size); + if ((io_result != IO_SUCCESS) || (image_size == 0)) { + WARN("Failed to determine the size of the image '%s' file (%i)\n", + image_name, io_result); + } + io_result = io_close(image_handle); + /* Ignore improbable/unrecoverable error in 'close' */ + + /* TODO: Consider maintaining open device connection from this + * bootloader stage + */ + io_result = io_dev_close(dev_handle); + /* Ignore improbable/unrecoverable error in 'dev_close' */ + + return image_size; +} +/******************************************************************************* + * Generic function to load an image into the trusted RAM, + * given a name, extents of free memory & whether the image should be loaded at + * the bottom or top of the free memory. It updates the memory layout if the + * load is successful. It also updates the image information and the entry point + * information in the params passed. The caller might pass a NULL pointer for + * the entry point if it is not interested in this information, e.g. because + * the image just needs to be loaded in memory but won't ever be executed. + ******************************************************************************/ +int load_image(meminfo_t *mem_layout, + const char *image_name, + unsigned int load_type, + unsigned long fixed_addr, + image_info_t *image_data, + entry_point_info_t *entry_point_info) +{ + uintptr_t dev_handle; + uintptr_t image_handle; + uintptr_t image_spec; + unsigned long temp_image_base = 0; + unsigned long image_base = 0; + long offset = 0; + size_t image_size = 0; + size_t bytes_read = 0; + int io_result = IO_FAIL; + + assert(mem_layout != NULL); + assert(image_name != NULL); + assert(image_data->h.version >= VERSION_1); + + /* Obtain a reference to the image by querying the platform layer */ + io_result = plat_get_image_source(image_name, &dev_handle, &image_spec); + if (io_result != IO_SUCCESS) { + WARN("Failed to obtain reference to image '%s' (%i)\n", + image_name, io_result); + return io_result; + } + + /* Attempt to access the image */ + io_result = io_open(dev_handle, image_spec, &image_handle); + if (io_result != IO_SUCCESS) { + WARN("Failed to access image '%s' (%i)\n", + image_name, io_result); + return io_result; + } + + /* Find the size of the image */ + io_result = io_size(image_handle, &image_size); + if ((io_result != IO_SUCCESS) || (image_size == 0)) { + WARN("Failed to determine the size of the image '%s' file (%i)\n", + image_name, io_result); + goto exit; + } + + /* See if we have enough space */ + if (image_size > mem_layout->free_size) { + WARN("Cannot load '%s' file: Not enough space.\n", + image_name); + dump_load_info(0, image_size, mem_layout); + goto exit; + } + + switch (load_type) { + + case TOP_LOAD: + + /* Load the image in the top of free memory */ + temp_image_base = mem_layout->free_base + mem_layout->free_size; + temp_image_base -= image_size; + + /* Page align base address and check whether the image still fits */ + image_base = page_align(temp_image_base, DOWN); + assert(image_base <= temp_image_base); + + if (image_base < mem_layout->free_base) { + WARN("Cannot load '%s' file: Not enough space.\n", + image_name); + dump_load_info(image_base, image_size, mem_layout); + io_result = -ENOMEM; + goto exit; + } + + /* Calculate the amount of extra memory used due to alignment */ + offset = temp_image_base - image_base; + + break; + + case BOT_LOAD: + + /* Load the BL2 image in the bottom of free memory */ + temp_image_base = mem_layout->free_base; + image_base = page_align(temp_image_base, UP); + assert(image_base >= temp_image_base); + + /* Page align base address and check whether the image still fits */ + if (image_base + image_size > + mem_layout->free_base + mem_layout->free_size) { + WARN("Cannot load '%s' file: Not enough space.\n", + image_name); + dump_load_info(image_base, image_size, mem_layout); + io_result = -ENOMEM; + goto exit; + } + + /* Calculate the amount of extra memory used due to alignment */ + offset = image_base - temp_image_base; + + break; + + default: + assert(0); + + } + + /* + * Some images must be loaded at a fixed address, not a dynamic one. + * + * This has been implemented as a hack on top of the existing dynamic + * loading mechanism, for the time being. If the 'fixed_addr' function + * argument is different from zero, then it will force the load address. + * So we still have this principle of top/bottom loading but the code + * determining the load address is bypassed and the load address is + * forced to the fixed one. + * + * This can result in quite a lot of wasted space because we still use + * 1 sole meminfo structure to represent the extents of free memory, + * where we should use some sort of linked list. + * + * E.g. we want to load BL2 at address 0x04020000, the resulting memory + * layout should look as follows: + * ------------ 0x04040000 + * | | <- Free space (1) + * |----------| + * | BL2 | + * |----------| 0x04020000 + * | | <- Free space (2) + * |----------| + * | BL1 | + * ------------ 0x04000000 + * + * But in the current hacky implementation, we'll need to specify + * whether BL2 is loaded at the top or bottom of the free memory. + * E.g. if BL2 is considered as top-loaded, the meminfo structure + * will give the following view of the memory, hiding the chunk of + * free memory above BL2: + * ------------ 0x04040000 + * | | + * | | + * | BL2 | + * |----------| 0x04020000 + * | | <- Free space (2) + * |----------| + * | BL1 | + * ------------ 0x04000000 + */ + if (fixed_addr != 0) { + /* Load the image at the given address. */ + image_base = fixed_addr; + + /* Check whether the image fits. */ + if ((image_base < mem_layout->free_base) || + (image_base + image_size > + mem_layout->free_base + mem_layout->free_size)) { + WARN("Cannot load '%s' file: Not enough space.\n", + image_name); + dump_load_info(image_base, image_size, mem_layout); + io_result = -ENOMEM; + goto exit; + } + + /* Check whether the fixed load address is page-aligned. */ + if (!is_page_aligned(image_base)) { + WARN("Cannot load '%s' file at unaligned address 0x%lx\n", + image_name, fixed_addr); + io_result = -ENOMEM; + goto exit; + } + + /* + * Calculate the amount of extra memory used due to fixed + * loading. + */ + if (load_type == TOP_LOAD) { + unsigned long max_addr, space_used; + /* + * ------------ max_addr + * | /wasted/ | | offset + * |..........|.............................. + * | image | | image_flen + * |----------| fixed_addr + * | | + * | | + * ------------ total_base + */ + max_addr = mem_layout->total_base + mem_layout->total_size; + /* + * Compute the amount of memory used by the image. + * Corresponds to all space above the image load + * address. + */ + space_used = max_addr - fixed_addr; + /* + * Calculate the amount of wasted memory within the + * amount of memory used by the image. + */ + offset = space_used - image_size; + } else /* BOT_LOAD */ + /* + * ------------ + * | | + * | | + * |----------| + * | image | + * |..........| fixed_addr + * | /wasted/ | | offset + * ------------ total_base + */ + offset = fixed_addr - mem_layout->total_base; + } + + /* We have enough space so load the image now */ + /* TODO: Consider whether to try to recover/retry a partially successful read */ + io_result = io_read(image_handle, image_base, image_size, &bytes_read); + if ((io_result != IO_SUCCESS) || (bytes_read < image_size)) { + WARN("Failed to load '%s' file (%i)\n", image_name, io_result); + goto exit; + } + + image_data->image_base = image_base; + image_data->image_size = image_size; + + if (entry_point_info != NULL) + entry_point_info->pc = image_base; + + /* + * File has been successfully loaded. Update the free memory + * data structure & flush the contents of the TZRAM so that + * the next EL can see it. + */ + /* Update the memory contents */ + flush_dcache_range(image_base, image_size); + + mem_layout->free_size -= image_size + offset; + + /* Update the base of free memory since its moved up */ + if (load_type == BOT_LOAD) + mem_layout->free_base += offset + image_size; + +exit: + io_close(image_handle); + /* Ignore improbable/unrecoverable error in 'close' */ + + /* TODO: Consider maintaining open device connection from this bootloader stage */ + io_dev_close(dev_handle); + /* Ignore improbable/unrecoverable error in 'dev_close' */ + + return io_result; +}
\ No newline at end of file diff --git a/common/debug.c b/common/debug.c new file mode 100644 index 0000000..4657d55 --- /dev/null +++ b/common/debug.c @@ -0,0 +1,102 @@ +/* + * Copyright (c) 2014, ARM Limited and Contributors. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * Neither the name of ARM nor the names of its contributors may be used + * to endorse or promote products derived from this software without specific + * prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ +#include <serial.h> +#include <debug.h> +#include <stdio.h> + +/****************************************************************** +* This function is invoked from assembler error handling routines and +* prints out the string and the value in 64 bit hex format. These +* are passed to the function as input parameters. +********************************************************************/ +void print_string_value(char *s, unsigned long *mem) +{ + unsigned char i, temp; + unsigned long val; + + while (*s) { + i = 16; + while (*s) + serial_putc(*s++); + + s++; + + serial_putc('\t'); + serial_putc(':'); + serial_putc('0'); + serial_putc('x'); + + val = *mem++; + + while (i--) { + temp = (val >> (i << 2)) & 0xf; + if (temp < 0xa) + serial_putc('0' + temp); + else + serial_putc('A' + (temp - 0xa)); + } + serial_putc('\n'); + } +} + +/*********************************************************** + * The common implementation of do_panic for all BL stages + ***********************************************************/ + +#if DEBUG +void __dead2 do_panic(const char *file, int line) +{ + serial_puts("PANIC in file: "); + serial_puts(file); + serial_puts(" line: "); + serial_put_dec(line); + serial_puts("\n"); + while (1) + ; +} +#else +void __dead2 do_panic(void) +{ + unsigned long pc_reg; + __asm__ volatile("mov %0, x30\n" + : "=r" (pc_reg) : ); + + /* x30 reports the next eligible instruction whereas we want the + * place where panic() is invoked. Hence decrement by 4. + */ + //printf("PANIC in PC location 0x%016X\n", pc_reg - 0x4); + serial_puts("PANIC in PC location 0x"); + serial_put_hex(pc_reg - 0x4, 64); + serial_puts("\n"); + while (1) + ; + +} +#endif diff --git a/common/fip.c b/common/fip.c new file mode 100644 index 0000000..cdc579a --- /dev/null +++ b/common/fip.c @@ -0,0 +1,248 @@ + +/* + * arch/arm/cpu/armv8/common/firmware/common/fip.c + * + * Copyright (C) 2015 Amlogic, Inc. All rights reserved. + * + * 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., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +*/ + +#include <arch.h> +#include <arch_helpers.h> +#include <fip.h> +#include <storage.h> +#include <string.h> +#include <platform.h> +#include <platform_def.h> +#include <stdio.h> +#include <asm/arch/cpu_config.h> +#include <storage.h> +#include <sha2.h> +#include <mailbox.h> +#include <asm/arch/romboot.h> +#include <cache.h> +#include <fip.h> +#include <asm/arch/watchdog.h> +#include <timer.h> +#include <io.h> + +static int aml_check(unsigned long pBufferSRC,unsigned long pBufferDST,unsigned int nLength,unsigned int nAESFlag); + +void bl2_load_image(void){ + /* dump ddr data when function enabled and flag set */ + dump_ddr_data(); + + //meminfo_t *bl2_tzram_layout; + bl31_params_t *bl2_to_bl31_params; + entry_point_info_t *bl31_ep_info; + //meminfo_t bl33_mem_info; + unsigned int * pCHK = (unsigned int *)FM_FIP_HEADER_LOAD_ADDR; + unsigned int nAESFlag = 1; + unsigned int nBL3XLoadAddr = readl(0xc8100228); + nBL3XLoadAddr = readl(0xc8100228); + int nSecFlag = nBL3XLoadAddr & (1<<4); + /*load fip header*/ + aml_fip_header_t *fip_header; + fip_header = (aml_fip_header_t *)(uint64_t)FM_FIP_HEADER_LOAD_ADDR; +#if defined(CONFIG_AML_SECURE_UBOOT) + extern void platform_stack_set_bl2 (unsigned long); + platform_stack_set_bl2(BL2_SEC_BOOT_SP_BASE); +#endif + storage_load(BL2_SIZE, (uint64_t)fip_header, sizeof(aml_fip_header_t), "fip header"); + memcpy((void*)FM_FIP_BL3X_TEMP_LOAD_ADDR,(void*)FM_FIP_HEADER_LOAD_ADDR,sizeof(aml_fip_header_t)); + if (TOC_HEADER_NAME == *pCHK && TOC_HEADER_SERIAL_NUMBER == *(pCHK+1)) + { + nAESFlag = 0; + } + + aml_check(FM_FIP_BL3X_TEMP_LOAD_ADDR,FM_FIP_HEADER_LOAD_ADDR,sizeof(aml_fip_header_t),nAESFlag); + + /*load and process bl30*/ + image_info_t bl30_image_info; + entry_point_info_t bl30_ep_info; + nBL3XLoadAddr = nSecFlag ? FM_FIP_BL3X_TEMP_LOAD_ADDR : FM_BL30_LOAD_ADDR; + storage_load(BL2_SIZE + (fip_header->bl30_entry.offset),nBL3XLoadAddr, (fip_header->bl30_entry.size), "bl30"); + parse_blx(&bl30_image_info, &bl30_ep_info,nBL3XLoadAddr, FM_BL30_LOAD_ADDR, (fip_header->bl30_entry.size),nAESFlag); + /*process bl30*/ + process_bl30x(&bl30_image_info, &bl30_ep_info, "bl30"); + +#if (NEED_BL301) + /*load and process bl301*/ + image_info_t bl301_image_info; + entry_point_info_t bl301_ep_info; + nBL3XLoadAddr = nSecFlag ? FM_FIP_BL3X_TEMP_LOAD_ADDR : FM_BL301_LOAD_ADDR; + storage_load(BL2_SIZE + (fip_header->bl301_entry.offset),nBL3XLoadAddr, (fip_header->bl301_entry.size), "bl301"); + parse_blx(&bl301_image_info, &bl301_ep_info, nBL3XLoadAddr ,FM_BL301_LOAD_ADDR, (fip_header->bl301_entry.size),nAESFlag); + /*process bl301*/ + process_bl30x(&bl301_image_info, &bl301_ep_info, "bl301"); +#endif + + /*load and process bl31*/ + bl2_to_bl31_params = bl2_plat_get_bl31_params(); + bl31_ep_info = bl2_plat_get_bl31_ep_info(); + /* Set the X0 parameter to bl31 */ + bl31_ep_info->args.arg0 = (unsigned long)bl2_to_bl31_params; + nBL3XLoadAddr = nSecFlag ? FM_FIP_BL3X_TEMP_LOAD_ADDR : FM_BL31_LOAD_ADDR; + storage_load(BL2_SIZE + (fip_header->bl31_entry.offset), nBL3XLoadAddr, (fip_header->bl31_entry.size), "bl31"); + parse_blx(bl2_to_bl31_params->bl31_image_info, bl31_ep_info,nBL3XLoadAddr, FM_BL31_LOAD_ADDR, (fip_header->bl31_entry.size),nAESFlag); + bl2_plat_set_bl31_ep_info(bl2_to_bl31_params->bl31_image_info, bl31_ep_info); + +#if (NEED_BL32) + /* + * Load the BL32 image if there's one. It is upto to platform + * to specify where BL32 should be loaded if it exists. It + * could create space in the secure sram or point to a + * completely different memory. + * + * If a platform does not want to attempt to load BL3-2 image + * it must leave NEED_BL32=0 + */ + meminfo_t bl32_mem_info; + bl2_plat_get_bl32_meminfo(&bl32_mem_info); + nBL3XLoadAddr = nSecFlag ? FM_FIP_BL3X_TEMP_LOAD_ADDR : FM_BL32_LOAD_ADDR; + storage_load(BL2_SIZE + fip_header->bl32_entry.offset, nBL3XLoadAddr , fip_header->bl32_entry.size, "bl32"); + parse_blx(bl2_to_bl31_params->bl32_image_info, bl2_to_bl31_params->bl32_ep_info, + nBL3XLoadAddr, FM_BL32_LOAD_ADDR, fip_header->bl32_entry.size,nAESFlag); + bl2_plat_set_bl32_ep_info(bl2_to_bl31_params->bl32_image_info, bl2_to_bl31_params->bl32_ep_info); +#endif /* NEED_BL32 */ + + /*load and process bl33*/ + nBL3XLoadAddr = nSecFlag ? FM_FIP_BL3X_TEMP_LOAD_ADDR : FM_BL33_LOAD_ADDR; + storage_load(BL2_SIZE + fip_header->bl33_entry.offset,nBL3XLoadAddr, fip_header->bl33_entry.size, "bl33"); + parse_blx(bl2_to_bl31_params->bl33_image_info, bl2_to_bl31_params->bl33_ep_info, + nBL3XLoadAddr, FM_BL33_LOAD_ADDR, fip_header->bl33_entry.size,nAESFlag); + //bl2_plat_get_bl33_meminfo(&bl33_mem_info); + bl2_plat_set_bl33_ep_info(bl2_to_bl31_params->bl33_image_info, bl2_to_bl31_params->bl33_ep_info); + + /* Flush the params to be passed to memory */ + bl2_plat_flush_bl31_params(); + + /*disable mmu and dcache, flush dcache, then enter next firmware*/ + disable_mmu_el1(); + watchdog_disable(); + /* + * Run BL31 via an SMC to BL1. Information on how to pass control to + * the BL32 (if present) and BL33 software images will be passed to + * BL31 as an argument. + */ + + smc(RUN_IMAGE, (unsigned long)bl31_ep_info, 0, 0, 0, 0, 0, 0); + +/* + typedef unsigned long (*FUNC_TPL)(void ); + unsigned long bl33_entry = FM_BL33_LOAD_ADDR; + serial_puts("bl33 entry: 0x"); + serial_put_hex(bl33_entry, 32); + serial_puts("\n"); + FUNC_TPL func_tpl=(FUNC_TPL)bl33_entry; + func_tpl(); +*/ +} + +static int aml_check(unsigned long pBufferSRC,unsigned long pBufferDST,unsigned int nLength,unsigned int nAESFlag) +{ + int nReturn = aml_data_check(pBufferSRC,pBufferDST,nLength,nAESFlag); + if (nReturn) + { + //printf("aml log : SIG CHK : %d for address 0x%08X\n",nReturn,pBufferSRC); + serial_puts("aml log : SIG CHK : "); + serial_put_dec(nReturn); + serial_puts(" for address 0x"); + serial_put_hex(pBufferSRC, 32); + serial_puts("\n"); + //while(1); + check_handler(); + } + + return nReturn; +} + +/*blx header parse function*/ +void parse_blx(image_info_t *image_data, + entry_point_info_t *entry_point_info, + unsigned int src, + unsigned int dst, + unsigned int length, + unsigned int nAESFlag) +{ + image_data->image_base = dst; + image_data->image_size = length; + if (entry_point_info != NULL) + entry_point_info->pc = dst; + + aml_check(src,dst,length,nAESFlag); +} + +/*process bl30x, transfer to m3, etc..*/ +void process_bl30x(image_info_t *image_data, + entry_point_info_t *entry_point_info, const char * name) +{ + //serial_puts("start sha2\n"); + uint8_t _sha2[32] = {0}; + sha2((const uint8_t *)image_data->image_base, + image_data->image_size, + _sha2, + 0); /*0 means sha256, else means sha224*/ + +#if 0 + serial_puts(name); + serial_puts(" sha2:"); + int print_loop = 0; + for (print_loop=0; print_loop<32; print_loop++) { + if (0 == (print_loop % 16)) + serial_puts("\n"); + serial_put_hex(_sha2[print_loop], 8); + serial_puts(" "); + } + serial_puts("\n"); +#endif + + send_bl30x(image_data->image_base, image_data->image_size, \ + _sha2, sizeof(_sha2), name); + return; +} + +void bl2_to_romcode(uintptr_t entry) +{ + bl31_params_t *bl2_to_bl31_params; + entry_point_info_t *bl31_ep_info; + + bl2_to_bl31_params = bl2_plat_get_bl31_params(); + bl31_ep_info = bl2_plat_get_bl31_ep_info(); + /* Set the X0 parameter to bl31 */ + bl31_ep_info->args.arg0 = (unsigned long)bl2_to_bl31_params; + + bl31_ep_info->pc = entry; + SET_SECURITY_STATE(bl31_ep_info->h.attr, SECURE); + bl31_ep_info->spsr = SPSR_64(MODE_EL3, MODE_SP_ELX, + (DAIF_FIQ_BIT | DAIF_IRQ_BIT | DAIF_DBG_BIT)); + + watchdog_disable(); + disable_mmu_el1(); + + bl31_ep_info->args.arg0 = 0; + smc(RUN_IMAGE, (unsigned long)bl31_ep_info, 0, 0, 0, 0, 0, 0); +} + +void check_handler(void) { + if (BOOT_DEVICE_USB == get_boot_device()) { + serial_puts("USB mode!\n"); + bl2_to_romcode(USB_BL2_RETURN_ROM_ADDR); + } + else{ + serial_puts("reset...\n"); + reset_system(); + } +} diff --git a/common/memtest.c b/common/memtest.c new file mode 100644 index 0000000..e7bdb6b --- /dev/null +++ b/common/memtest.c @@ -0,0 +1,369 @@ +/********************************************************************** + * + * Filename: memtest.c + * + * Description: General-purpose memory testing functions. + * + * Notes: This software can be easily ported to systems with + * different data bus widths by redefining 'unsigned int'. + * + * + * Copyright (c) 1998 by Michael Barr. This software is placed into + * the public domain and may be used for any purpose. However, this + * notice must not be changed or removed and no warranty is either + * expressed or implied by its publication or distribution. + **********************************************************************/ + +#define MEM_TEST_DEBUG 0 + +#include <stdio.h> + +/********************************************************************** + * + * Function: memTestDataBus() + * + * Description: Test the data bus wiring in a memory region by + * performing a walking 1's test at a fixed address + * within that region. The address (and hence the + * memory region) is selected by the caller. + * + * Notes: + * + * Returns: 0 if the test succeeds. + * A non-zero result is the first pattern that failed. + * + **********************************************************************/ +unsigned int +memTestDataBus(volatile unsigned int * address) +{ + unsigned int pattern; + unsigned int data; + unsigned int ret = 0; + /* + * Perform a walking 1's test at the given address. + */ + for (pattern = 1; pattern != 0; pattern <<= 1) + { + /* + * Write the test pattern. + */ + *address = pattern; + data = *address; + /* + * Read it back (immediately is okay for this test). + */ + if (data != pattern) + { +#if (MEM_TEST_DEBUG) + //printf(" memTestDataBus - write: 0x%8x, read back: 0x%8x\n", pattern, data); + serial_puts(" memTestDataBus - write: 0x"); + serial_put_hex(pattern, 32); + serial_puts(", read back: 0x"); + serial_put_hex(data, 32); + serial_puts("\n"); + ret = 1; +#else + return (pattern); +#endif + } + } + return (ret); +} /* memTestDataBus() */ + + +/********************************************************************** + * + * Function: memTestAddressBus() + * + * Description: Test the address bus wiring in a memory region by + * performing a walking 1's test on the relevant bits + * of the address and checking for aliasing. This test + * will find single-bit address failures such as stuck + * -high, stuck-low, and shorted pins. The base address + * and size of the region are selected by the caller. + * + * Notes: For best results, the selected base address should + * have enough LSB 0's to guarantee single address bit + * changes. For example, to test a 64-Kbyte region, + * select a base address on a 64-Kbyte boundary. Also, + * select the region size as a power-of-two--if at all + * possible. + * + * Returns: NULL if the test succeeds. + * A non-zero result is the first address at which an + * aliasing problem was uncovered. By examining the + * contents of memory, it may be possible to gather + * additional information about the problem. + * + **********************************************************************/ +unsigned int +memTestAddressBus(volatile unsigned int * baseAddress, unsigned int nBytes) +{ + unsigned int addressMask = (nBytes/sizeof(unsigned int) - 1); + unsigned int offset; + unsigned int testOffset; + + unsigned int pattern = (unsigned int) 0xAAAAAAAA; + unsigned int antipattern = (unsigned int) 0x55555555; + + unsigned int data1, data2; + + /* align the mask address */ + unsigned int temp_i=1, temp_j=0; + temp_j = addressMask; + do { + temp_i=(temp_i<<1); + temp_j=(temp_j>>1); + }while((temp_j)); + addressMask=((temp_i)-1); + + unsigned int ret = 0; + + /* + * Write the default pattern at each of the power-of-two offsets. + */ + for (offset = 1; (offset & addressMask) != 0; offset <<= 1) + { + baseAddress[offset] = pattern; + } + + /* + * Check for address bits stuck high. + */ + testOffset = 0; + baseAddress[testOffset] = antipattern; + + for (offset = 1; (offset & addressMask) != 0; offset <<= 1) + { + data1 = baseAddress[offset]; + data2 = baseAddress[offset]; + if (data1 != data2) + { +#if (MEM_TEST_DEBUG) + //printf(" memTestAddressBus - read twice different[offset]: 0x%8x-0x%8x\n", data1, data2); + serial_puts(" memTestAddressBus - read twice different[offset]: 0x"); + serial_put_hex(data1, 32); + serial_puts("-0x"); + serial_put_hex(data2, 32); + serial_puts("\n"); +#endif + ret = 1; + } + if (data1 != pattern) + { +#if (MEM_TEST_DEBUG) + /*printf(" memTestAddressBus - write[0x%8x]: 0x%8x, read[0x%8x]: 0x%8x\n", \ + offset, pattern, offset, data1); + */ + serial_puts(" memTestAddressBus - write[0x"); + serial_put_hex(offset, 32); + serial_puts("]: 0x"); + serial_put_hex(pattern, 32); + serial_puts(", read[0x"); + serial_put_hex(offset, 32); + serial_puts("]: 0x"); + serial_put_hex(data1, 32); + serial_puts("\n"); + ret = 1; +#else + return ((unsigned int)(unsigned long) &baseAddress[offset]); +#endif + } + } + + baseAddress[testOffset] = pattern; + + /* + * Check for address bits stuck low or shorted. + */ + for (testOffset = 1; (testOffset & addressMask) != 0; testOffset <<= 1) + { + baseAddress[testOffset] = antipattern; + + if (baseAddress[0] != pattern) + { +#if (MEM_TEST_DEBUG) + /*printf(" memTestAddressBus2 - write baseAddress[0x%8x]: 0x%8x, read baseAddress[0]: 0x%8x\n", \ + testOffset, antipattern, baseAddress[0]); + */ + serial_puts(" memTestAddressBus2 - write baseAddress[0x"); + serial_put_hex(testOffset, 32); + serial_puts("]: 0x"); + serial_put_hex(antipattern, 32); + serial_puts(", read baseAddress[0]: 0x"); + serial_put_hex(baseAddress[0], 32); + serial_puts("\n"); + ret = 1; +#else + return ((unsigned int)(unsigned long) &baseAddress[testOffset]); +#endif + } + + for (offset = 1; (offset & addressMask) != 0; offset <<= 1) + { + data1 = baseAddress[offset]; + if ((data1 != pattern) && (offset != testOffset)) + { +#if (MEM_TEST_DEBUG) + /*printf(" memTestAddressBus3 - write baseAddress[0x%8x]: 0x%8x, read baseAddress[0x%8x]: 0x%8x\n", \ + testOffset, antipattern, testOffset, data1); + */ + serial_puts(" memTestAddressBus3 - write baseAddress[0x"); + serial_put_hex(testOffset, 32); + serial_puts("]: 0x"); + serial_put_hex(antipattern, 32); + serial_puts(", read baseAddress[0x"); + serial_put_hex(testOffset, 32); + serial_puts("]: 0x"); + serial_put_hex(data1, 32); + serial_puts("\n"); + ret = 1; +#else + return ((unsigned int)(unsigned long) &baseAddress[testOffset]); +#endif + } + } + + baseAddress[testOffset] = pattern; + } + return (ret); +} /* memTestAddressBus() */ + + +/********************************************************************** + * + * Function: memTestDevice() + * + * Description: Test the integrity of a physical memory device by + * performing an increment/decrement test over the + * entire region. In the process every storage bit + * in the device is tested as a zero and a one. The + * base address and the size of the region are + * selected by the caller. + * + * Notes: + * + * Returns: NULL if the test succeeds. + * + * A non-zero result is the first address at which an + * incorrect value was read back. By examining the + * contents of memory, it may be possible to gather + * additional information about the problem. + * + **********************************************************************/ +/*#define AML_DEBUG_ROM*/ +#if MEM_TEST_DEVICE +unsigned int +memTestDevice(volatile unsigned int * baseAddress, unsigned int nBytes) +{ + + unsigned int offset; + unsigned int nWords = nBytes / sizeof(unsigned int); + unsigned int ret = 0; + unsigned int data; + unsigned int pattern; + unsigned int antipattern; + serial_puts("\nTotal Size 0x"); + serial_put_hex(nBytes, 32); + serial_puts("\n"); + + /* + * Fill memory with a known pattern. + */ + for (pattern = 1, offset = 0; offset < nWords; pattern++, offset++) + { + baseAddress[offset] = pattern; +#ifdef AML_DEBUG_ROM + if ((offset&0x3ffff) == 0) + { + serial_puts("\r0x"); + serial_put_hex(offset<<2, 32); + } +#endif + + } + serial_puts("\n"); + + /* + * Check each location and invert it for the second pass. + */ + for (pattern = 1, offset = 0; offset < nWords; pattern++, offset++) + { + data = baseAddress[offset]; + if ( data!= pattern) + { +#if (MEM_TEST_DEBUG) + /*printf(" memTestDevice - write baseAddress[0x%8x]: 0x%8x, read baseAddress[0x%8x]: 0x%8x\n", \ + offset, pattern, offset, data); + */ + serial_puts(" memTestDevice - write baseAddress[0x"); + serial_put_hex(offset, 32); + serial_puts("]: 0x"); + serial_put_hex(pattern, 32); + serial_puts(", read baseAddress[0x"); + serial_put_hex(offset, 32); + serial_puts("]: 0x"); + serial_put_hex(data, 32); + serial_puts("\n"); + ret = 1; +#else + return ((unsigned int)(unsigned long) &baseAddress[offset]); +#endif + } + + antipattern = ~pattern; + baseAddress[offset] = antipattern; +#ifdef AML_DEBUG_ROM + if ((offset&0x3ffff) == 0) + { + serial_puts("\r0x"); + serial_put_hex((offset<<2), 32); + } +#endif + + } + serial_puts("\n"); + + /* + * Check each location for the inverted pattern and zero it. + */ + for (pattern = 1, offset = 0; offset < nWords; pattern++, offset++) + { + antipattern = ~pattern; + data = baseAddress[offset]; + if (data != antipattern) + { +#if (MEM_TEST_DEBUG) + /*printf(" memTestDevice2 - write baseAddress[0x%8x]: 0x%8x, read baseAddress[0x%8x]: 0x%8x\n", \ + offset, antipattern, offset, data); + */ + serial_puts(" memTestDevice2 - write baseAddress[0x"); + serial_put_hex(offset, 32); + serial_puts("]: 0x"); + serial_put_hex(pattern, 32); + serial_puts(", read baseAddress[0x"); + serial_put_hex(offset, 32); + serial_puts("]: 0x"); + serial_put_hex(data, 32); + serial_puts("\n"); + ret = 1; +#else + return ((unsigned int)(unsigned long) &baseAddress[offset]); +#endif + } +#ifdef AML_DEBUG_ROM + if ((offset&0x3ffff) == 0) + { + serial_puts("\r0x"); + serial_put_hex((offset<<2), 32); + } +#endif + + } +#undef AML_DEBUG_ROM + serial_puts("\n"); + + return (ret); +} /* memTestDevice() */ +#endif// #if MEM_TEST_DEVICE + |