122723828SAlexey Brodkin /* 222723828SAlexey Brodkin * Copyright (C) 2013-2014 Synopsys, Inc. All rights reserved. 322723828SAlexey Brodkin * 422723828SAlexey Brodkin * SPDX-License-Identifier: GPL-2.0+ 522723828SAlexey Brodkin */ 622723828SAlexey Brodkin 722723828SAlexey Brodkin #include <common.h> 822723828SAlexey Brodkin #include <elf.h> 922723828SAlexey Brodkin #include <asm/sections.h> 1022723828SAlexey Brodkin 1122723828SAlexey Brodkin DECLARE_GLOBAL_DATA_PTR; 1222723828SAlexey Brodkin 1322723828SAlexey Brodkin /* 1422723828SAlexey Brodkin * Base functionality is taken from x86 version with added ARC-specifics 1522723828SAlexey Brodkin */ 1622723828SAlexey Brodkin int do_elf_reloc_fixups(void) 1722723828SAlexey Brodkin { 1822723828SAlexey Brodkin Elf32_Rela *re_src = (Elf32_Rela *)(&__rel_dyn_start); 1922723828SAlexey Brodkin Elf32_Rela *re_end = (Elf32_Rela *)(&__rel_dyn_end); 2022723828SAlexey Brodkin 2122723828SAlexey Brodkin Elf32_Addr *offset_ptr_rom, *last_offset = NULL; 2222723828SAlexey Brodkin Elf32_Addr *offset_ptr_ram; 2322723828SAlexey Brodkin 2422723828SAlexey Brodkin do { 2522723828SAlexey Brodkin /* Get the location from the relocation entry */ 2622723828SAlexey Brodkin offset_ptr_rom = (Elf32_Addr *)re_src->r_offset; 2722723828SAlexey Brodkin 2822723828SAlexey Brodkin /* Check that the location of the relocation is in .text */ 2922723828SAlexey Brodkin if (offset_ptr_rom >= (Elf32_Addr *)CONFIG_SYS_TEXT_BASE && 3022723828SAlexey Brodkin offset_ptr_rom > last_offset) { 3122723828SAlexey Brodkin unsigned int val; 3222723828SAlexey Brodkin /* Switch to the in-RAM version */ 3322723828SAlexey Brodkin offset_ptr_ram = (Elf32_Addr *)((ulong)offset_ptr_rom + 3422723828SAlexey Brodkin gd->reloc_off); 3522723828SAlexey Brodkin 3622723828SAlexey Brodkin /* 3722723828SAlexey Brodkin * Use "memcpy" because target location might be 3822723828SAlexey Brodkin * 16-bit aligned on ARC so we may need to read 3922723828SAlexey Brodkin * byte-by-byte. On attempt to read entire word by 4022723828SAlexey Brodkin * CPU throws an exception 4122723828SAlexey Brodkin */ 4222723828SAlexey Brodkin memcpy(&val, offset_ptr_ram, sizeof(int)); 4322723828SAlexey Brodkin 44*36ae5cd2SAlexey Brodkin #ifdef __LITTLE_ENDIAN__ 4522723828SAlexey Brodkin /* If location in ".text" section swap value */ 4622723828SAlexey Brodkin if ((unsigned int)offset_ptr_rom < 4722723828SAlexey Brodkin (unsigned int)&__text_end) 4822723828SAlexey Brodkin val = (val << 16) | (val >> 16); 49*36ae5cd2SAlexey Brodkin #endif 5022723828SAlexey Brodkin 5122723828SAlexey Brodkin /* Check that the target points into .text */ 5222723828SAlexey Brodkin if (val >= CONFIG_SYS_TEXT_BASE && val <= 5322723828SAlexey Brodkin (unsigned int)&__bss_end) { 5422723828SAlexey Brodkin val += gd->reloc_off; 55*36ae5cd2SAlexey Brodkin #ifdef __LITTLE_ENDIAN__ 5622723828SAlexey Brodkin /* If location in ".text" section swap value */ 5722723828SAlexey Brodkin if ((unsigned int)offset_ptr_rom < 5822723828SAlexey Brodkin (unsigned int)&__text_end) 5922723828SAlexey Brodkin val = (val << 16) | (val >> 16); 60*36ae5cd2SAlexey Brodkin #endif 6122723828SAlexey Brodkin memcpy(offset_ptr_ram, &val, sizeof(int)); 6222723828SAlexey Brodkin } else { 6322723828SAlexey Brodkin debug(" %p: rom reloc %x, ram %p, value %x, limit %x\n", 6422723828SAlexey Brodkin re_src, re_src->r_offset, offset_ptr_ram, 6522723828SAlexey Brodkin val, (unsigned int)&__bss_end); 6622723828SAlexey Brodkin } 6722723828SAlexey Brodkin } else { 6822723828SAlexey Brodkin debug(" %p: rom reloc %x, last %p\n", re_src, 6922723828SAlexey Brodkin re_src->r_offset, last_offset); 7022723828SAlexey Brodkin } 7122723828SAlexey Brodkin last_offset = offset_ptr_rom; 7222723828SAlexey Brodkin 7322723828SAlexey Brodkin } while (++re_src < re_end); 7422723828SAlexey Brodkin 7522723828SAlexey Brodkin return 0; 7622723828SAlexey Brodkin } 77