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) 2013-2014 Synopsys, Inc. All rights reserved. */ #include <elf.h> #include <log.h> #include <asm/sections.h> #include <asm/global_data.h> DECLARE_GLOBAL_DATA_PTR; int copy_uboot_to_ram(void) { size_t len = (size_t)__image_copy_end - (size_t)__image_copy_start; if (gd->flags & GD_FLG_SKIP_RELOC) return 0; memcpy((void *)gd->relocaddr, (void *)__image_copy_start, len); return 0; } int clear_bss(void) { ulong dst_addr = (ulong)__bss_start + gd->reloc_off; size_t len = (size_t)__bss_end - (size_t)__bss_start; memset((void *)dst_addr, 0x00, len); return 0; } /* * Base functionality is taken from x86 version with added ARC-specifics */ int do_elf_reloc_fixups(void) { Elf32_Rela *re_src = (Elf32_Rela *)__rel_dyn_start; Elf32_Rela *re_end = (Elf32_Rela *)__rel_dyn_end; if (gd->flags & GD_FLG_SKIP_RELOC) return 0; debug("Section .rela.dyn is located at %08x-%08x\n", (unsigned int)re_src, (unsigned int)re_end); Elf32_Addr *offset_ptr_rom; Elf32_Addr *offset_ptr_ram; do { /* Get the location from the relocation entry */ offset_ptr_rom = (Elf32_Addr *)re_src->r_offset; /* Check that the location of the relocation is in .text */ if (offset_ptr_rom >= (Elf32_Addr *)__image_copy_start && offset_ptr_rom < (Elf32_Addr *)__image_copy_end) { unsigned int val, do_swap = 0; /* Switch to the in-RAM version */ offset_ptr_ram = (Elf32_Addr *)((ulong)offset_ptr_rom + gd->reloc_off); #ifdef __LITTLE_ENDIAN__ /* If location in ".text" section swap value */ if (((u32)offset_ptr_rom >= (u32)__text_start && (u32)offset_ptr_rom <= (u32)__text_end) #if defined(__ARC700__) || defined(__ARC600__) || ((u32)offset_ptr_rom >= (u32)__ivt_start && (u32)offset_ptr_rom <= (u32)__ivt_end) #endif ) do_swap = 1; #endif debug("Patching value @ %08x (relocated to %08x)%s\n", (unsigned int)offset_ptr_rom, (unsigned int)offset_ptr_ram, do_swap ? ", middle-endian encoded" : ""); /* * Use "memcpy" because target location might be * 16-bit aligned on ARC so we may need to read * byte-by-byte. On attempt to read entire word by * CPU throws an exception */ memcpy(&val, offset_ptr_ram, sizeof(int)); if (do_swap) val = (val << 16) | (val >> 16); /* Check that the target points into executable */ if (val < (unsigned int)__image_copy_start || val > (unsigned int)__image_copy_end) { /* TODO: Use panic() instead of debug() * * For some reason GCC might generate * fake relocation even for LD/SC of constant * inderectly. See an example below: * ----------------------->8-------------------- * static int setup_mon_len(void) * { * gd->mon_len = (ulong)__bss_end - CONFIG_SYS_MONITOR_BASE; * return 0; * } * ----------------------->8-------------------- * * And that's what we get in the binary: * ----------------------->8-------------------- * 10005cb4 <setup_mon_len>: * 10005cb4: 193c 3f80 0003 2f80 st 0x32f80,[r25,60] * 10005cb8: R_ARC_RELATIVE *ABS*-0x10000000 * 10005cbc: 7fe0 j_s.d [blink] * 10005cbe: 700c mov_s r0,0 * ----------------------->8-------------------- */ debug("Relocation target %08x points outside of image\n", val); } val += gd->reloc_off; if (do_swap) val = (val << 16) | (val >> 16); memcpy(offset_ptr_ram, &val, sizeof(int)); } } while (++re_src < re_end); return 0; } |