blob: 95b6d5150c7871da779d38896d6b2e2e866c434f [file] [log] [blame]
Tom Rini83d290c2018-05-06 17:58:06 -04001// SPDX-License-Identifier: GPL-2.0+
Alexey Brodkin22723822014-02-04 12:56:15 +04002/*
3 * Copyright (C) 2013-2014 Synopsys, Inc. All rights reserved.
Alexey Brodkin22723822014-02-04 12:56:15 +04004 */
5
Alexey Brodkin22723822014-02-04 12:56:15 +04006#include <elf.h>
Simon Glassf7ae49f2020-05-10 11:40:05 -06007#include <log.h>
Shiji Yang506df9d2023-08-03 09:47:16 +08008#include <asm/sections.h>
Simon Glass401d1c42020-10-30 21:38:53 -06009#include <asm/global_data.h>
Alexey Brodkin9bef24d2016-08-03 20:44:39 +030010
Alexey Brodkin22723822014-02-04 12:56:15 +040011DECLARE_GLOBAL_DATA_PTR;
12
Alexey Brodkin3fb80162015-02-24 19:40:36 +030013int copy_uboot_to_ram(void)
14{
Shiji Yangccea96f2023-08-03 09:47:17 +080015 size_t len = (size_t)__image_copy_end - (size_t)__image_copy_start;
Alexey Brodkin3fb80162015-02-24 19:40:36 +030016
Alexey Brodkin264d2982015-12-16 19:24:10 +030017 if (gd->flags & GD_FLG_SKIP_RELOC)
18 return 0;
19
Shiji Yangccea96f2023-08-03 09:47:17 +080020 memcpy((void *)gd->relocaddr, (void *)__image_copy_start, len);
Alexey Brodkin3fb80162015-02-24 19:40:36 +030021
22 return 0;
23}
24
25int clear_bss(void)
26{
Shiji Yangccea96f2023-08-03 09:47:17 +080027 ulong dst_addr = (ulong)__bss_start + gd->reloc_off;
28 size_t len = (size_t)__bss_end - (size_t)__bss_start;
Alexey Brodkin3fb80162015-02-24 19:40:36 +030029
30 memset((void *)dst_addr, 0x00, len);
31
32 return 0;
33}
34
Alexey Brodkin22723822014-02-04 12:56:15 +040035/*
36 * Base functionality is taken from x86 version with added ARC-specifics
37 */
38int do_elf_reloc_fixups(void)
39{
Shiji Yangccea96f2023-08-03 09:47:17 +080040 Elf32_Rela *re_src = (Elf32_Rela *)__rel_dyn_start;
41 Elf32_Rela *re_end = (Elf32_Rela *)__rel_dyn_end;
Alexey Brodkin22723822014-02-04 12:56:15 +040042
Alexey Brodkin264d2982015-12-16 19:24:10 +030043 if (gd->flags & GD_FLG_SKIP_RELOC)
44 return 0;
45
Alexey Brodkinffffcd12016-08-03 20:45:22 +030046 debug("Section .rela.dyn is located at %08x-%08x\n",
47 (unsigned int)re_src, (unsigned int)re_end);
48
Alexey Brodkince307122018-05-29 18:09:55 +030049 Elf32_Addr *offset_ptr_rom;
Alexey Brodkin22723822014-02-04 12:56:15 +040050 Elf32_Addr *offset_ptr_ram;
51
52 do {
53 /* Get the location from the relocation entry */
54 offset_ptr_rom = (Elf32_Addr *)re_src->r_offset;
55
56 /* Check that the location of the relocation is in .text */
Shiji Yangccea96f2023-08-03 09:47:17 +080057 if (offset_ptr_rom >= (Elf32_Addr *)__image_copy_start &&
58 offset_ptr_rom < (Elf32_Addr *)__image_copy_end) {
Alexey Brodkince307122018-05-29 18:09:55 +030059 unsigned int val, do_swap = 0;
Alexey Brodkin22723822014-02-04 12:56:15 +040060 /* Switch to the in-RAM version */
61 offset_ptr_ram = (Elf32_Addr *)((ulong)offset_ptr_rom +
62 gd->reloc_off);
63
Alexey Brodkince307122018-05-29 18:09:55 +030064#ifdef __LITTLE_ENDIAN__
65 /* If location in ".text" section swap value */
Shiji Yangccea96f2023-08-03 09:47:17 +080066 if (((u32)offset_ptr_rom >= (u32)__text_start &&
67 (u32)offset_ptr_rom <= (u32)__text_end)
Alexey Brodkince307122018-05-29 18:09:55 +030068#if defined(__ARC700__) || defined(__ARC600__)
Shiji Yangccea96f2023-08-03 09:47:17 +080069 || ((u32)offset_ptr_rom >= (u32)__ivt_start &&
70 (u32)offset_ptr_rom <= (u32)__ivt_end)
Alexey Brodkince307122018-05-29 18:09:55 +030071#endif
72 )
73 do_swap = 1;
74#endif
75
76 debug("Patching value @ %08x (relocated to %08x)%s\n",
Alexey Brodkinffffcd12016-08-03 20:45:22 +030077 (unsigned int)offset_ptr_rom,
Alexey Brodkince307122018-05-29 18:09:55 +030078 (unsigned int)offset_ptr_ram,
79 do_swap ? ", middle-endian encoded" : "");
Alexey Brodkinffffcd12016-08-03 20:45:22 +030080
Alexey Brodkin22723822014-02-04 12:56:15 +040081 /*
82 * Use "memcpy" because target location might be
83 * 16-bit aligned on ARC so we may need to read
84 * byte-by-byte. On attempt to read entire word by
85 * CPU throws an exception
86 */
87 memcpy(&val, offset_ptr_ram, sizeof(int));
88
Alexey Brodkince307122018-05-29 18:09:55 +030089 if (do_swap)
Alexey Brodkin22723822014-02-04 12:56:15 +040090 val = (val << 16) | (val >> 16);
91
Alexey Brodkin1c91a3d2014-12-26 19:36:30 +030092 /* Check that the target points into executable */
Shiji Yangccea96f2023-08-03 09:47:17 +080093 if (val < (unsigned int)__image_copy_start ||
94 val > (unsigned int)__image_copy_end) {
Alexey Brodkince307122018-05-29 18:09:55 +030095 /* TODO: Use panic() instead of debug()
96 *
97 * For some reason GCC might generate
98 * fake relocation even for LD/SC of constant
99 * inderectly. See an example below:
100 * ----------------------->8--------------------
101 * static int setup_mon_len(void)
102 * {
Shiji Yangccea96f2023-08-03 09:47:17 +0800103 * gd->mon_len = (ulong)__bss_end - CONFIG_SYS_MONITOR_BASE;
Alexey Brodkince307122018-05-29 18:09:55 +0300104 * return 0;
105 * }
106 * ----------------------->8--------------------
107 *
108 * And that's what we get in the binary:
109 * ----------------------->8--------------------
110 * 10005cb4 <setup_mon_len>:
111 * 10005cb4: 193c 3f80 0003 2f80 st 0x32f80,[r25,60]
112 * 10005cb8: R_ARC_RELATIVE *ABS*-0x10000000
113 * 10005cbc: 7fe0 j_s.d [blink]
114 * 10005cbe: 700c mov_s r0,0
115 * ----------------------->8--------------------
116 */
117 debug("Relocation target %08x points outside of image\n",
118 val);
Alexey Brodkin22723822014-02-04 12:56:15 +0400119 }
Alexey Brodkin22723822014-02-04 12:56:15 +0400120
Alexey Brodkince307122018-05-29 18:09:55 +0300121 val += gd->reloc_off;
122
123 if (do_swap)
124 val = (val << 16) | (val >> 16);
125
126 memcpy(offset_ptr_ram, &val, sizeof(int));
127 }
Alexey Brodkin22723822014-02-04 12:56:15 +0400128 } while (++re_src < re_end);
129
130 return 0;
131}