blob: fd6f4fbc9304c326063ff143d18f02033ea5f5fa [file] [log] [blame]
Tom Rini10e47792018-05-06 17:58:06 -04001// SPDX-License-Identifier: GPL-2.0+
Alexey Brodkinb628c012014-02-04 12:56:15 +04002/*
3 * Copyright (C) 2013-2014 Synopsys, Inc. All rights reserved.
Alexey Brodkinb628c012014-02-04 12:56:15 +04004 */
5
6#include <common.h>
7#include <elf.h>
Simon Glass0f2af882020-05-10 11:40:05 -06008#include <log.h>
Shiji Yangbb112342023-08-03 09:47:16 +08009#include <asm/sections.h>
Simon Glass3ba929a2020-10-30 21:38:53 -060010#include <asm/global_data.h>
Alexey Brodkin2f78eec2016-08-03 20:44:39 +030011
Alexey Brodkinb628c012014-02-04 12:56:15 +040012DECLARE_GLOBAL_DATA_PTR;
13
Alexey Brodkin913e9f02015-02-24 19:40:36 +030014int copy_uboot_to_ram(void)
15{
Shiji Yangeff11fa2023-08-03 09:47:17 +080016 size_t len = (size_t)__image_copy_end - (size_t)__image_copy_start;
Alexey Brodkin913e9f02015-02-24 19:40:36 +030017
Alexey Brodkinc157ab92015-12-16 19:24:10 +030018 if (gd->flags & GD_FLG_SKIP_RELOC)
19 return 0;
20
Shiji Yangeff11fa2023-08-03 09:47:17 +080021 memcpy((void *)gd->relocaddr, (void *)__image_copy_start, len);
Alexey Brodkin913e9f02015-02-24 19:40:36 +030022
23 return 0;
24}
25
26int clear_bss(void)
27{
Shiji Yangeff11fa2023-08-03 09:47:17 +080028 ulong dst_addr = (ulong)__bss_start + gd->reloc_off;
29 size_t len = (size_t)__bss_end - (size_t)__bss_start;
Alexey Brodkin913e9f02015-02-24 19:40:36 +030030
31 memset((void *)dst_addr, 0x00, len);
32
33 return 0;
34}
35
Alexey Brodkinb628c012014-02-04 12:56:15 +040036/*
37 * Base functionality is taken from x86 version with added ARC-specifics
38 */
39int do_elf_reloc_fixups(void)
40{
Shiji Yangeff11fa2023-08-03 09:47:17 +080041 Elf32_Rela *re_src = (Elf32_Rela *)__rel_dyn_start;
42 Elf32_Rela *re_end = (Elf32_Rela *)__rel_dyn_end;
Alexey Brodkinb628c012014-02-04 12:56:15 +040043
Alexey Brodkinc157ab92015-12-16 19:24:10 +030044 if (gd->flags & GD_FLG_SKIP_RELOC)
45 return 0;
46
Alexey Brodkin03478122016-08-03 20:45:22 +030047 debug("Section .rela.dyn is located at %08x-%08x\n",
48 (unsigned int)re_src, (unsigned int)re_end);
49
Alexey Brodkinf711e542018-05-29 18:09:55 +030050 Elf32_Addr *offset_ptr_rom;
Alexey Brodkinb628c012014-02-04 12:56:15 +040051 Elf32_Addr *offset_ptr_ram;
52
53 do {
54 /* Get the location from the relocation entry */
55 offset_ptr_rom = (Elf32_Addr *)re_src->r_offset;
56
57 /* Check that the location of the relocation is in .text */
Shiji Yangeff11fa2023-08-03 09:47:17 +080058 if (offset_ptr_rom >= (Elf32_Addr *)__image_copy_start &&
59 offset_ptr_rom < (Elf32_Addr *)__image_copy_end) {
Alexey Brodkinf711e542018-05-29 18:09:55 +030060 unsigned int val, do_swap = 0;
Alexey Brodkinb628c012014-02-04 12:56:15 +040061 /* Switch to the in-RAM version */
62 offset_ptr_ram = (Elf32_Addr *)((ulong)offset_ptr_rom +
63 gd->reloc_off);
64
Alexey Brodkinf711e542018-05-29 18:09:55 +030065#ifdef __LITTLE_ENDIAN__
66 /* If location in ".text" section swap value */
Shiji Yangeff11fa2023-08-03 09:47:17 +080067 if (((u32)offset_ptr_rom >= (u32)__text_start &&
68 (u32)offset_ptr_rom <= (u32)__text_end)
Alexey Brodkinf711e542018-05-29 18:09:55 +030069#if defined(__ARC700__) || defined(__ARC600__)
Shiji Yangeff11fa2023-08-03 09:47:17 +080070 || ((u32)offset_ptr_rom >= (u32)__ivt_start &&
71 (u32)offset_ptr_rom <= (u32)__ivt_end)
Alexey Brodkinf711e542018-05-29 18:09:55 +030072#endif
73 )
74 do_swap = 1;
75#endif
76
77 debug("Patching value @ %08x (relocated to %08x)%s\n",
Alexey Brodkin03478122016-08-03 20:45:22 +030078 (unsigned int)offset_ptr_rom,
Alexey Brodkinf711e542018-05-29 18:09:55 +030079 (unsigned int)offset_ptr_ram,
80 do_swap ? ", middle-endian encoded" : "");
Alexey Brodkin03478122016-08-03 20:45:22 +030081
Alexey Brodkinb628c012014-02-04 12:56:15 +040082 /*
83 * Use "memcpy" because target location might be
84 * 16-bit aligned on ARC so we may need to read
85 * byte-by-byte. On attempt to read entire word by
86 * CPU throws an exception
87 */
88 memcpy(&val, offset_ptr_ram, sizeof(int));
89
Alexey Brodkinf711e542018-05-29 18:09:55 +030090 if (do_swap)
Alexey Brodkinb628c012014-02-04 12:56:15 +040091 val = (val << 16) | (val >> 16);
92
Alexey Brodkinb4ee1392014-12-26 19:36:30 +030093 /* Check that the target points into executable */
Shiji Yangeff11fa2023-08-03 09:47:17 +080094 if (val < (unsigned int)__image_copy_start ||
95 val > (unsigned int)__image_copy_end) {
Alexey Brodkinf711e542018-05-29 18:09:55 +030096 /* TODO: Use panic() instead of debug()
97 *
98 * For some reason GCC might generate
99 * fake relocation even for LD/SC of constant
100 * inderectly. See an example below:
101 * ----------------------->8--------------------
102 * static int setup_mon_len(void)
103 * {
Shiji Yangeff11fa2023-08-03 09:47:17 +0800104 * gd->mon_len = (ulong)__bss_end - CONFIG_SYS_MONITOR_BASE;
Alexey Brodkinf711e542018-05-29 18:09:55 +0300105 * return 0;
106 * }
107 * ----------------------->8--------------------
108 *
109 * And that's what we get in the binary:
110 * ----------------------->8--------------------
111 * 10005cb4 <setup_mon_len>:
112 * 10005cb4: 193c 3f80 0003 2f80 st 0x32f80,[r25,60]
113 * 10005cb8: R_ARC_RELATIVE *ABS*-0x10000000
114 * 10005cbc: 7fe0 j_s.d [blink]
115 * 10005cbe: 700c mov_s r0,0
116 * ----------------------->8--------------------
117 */
118 debug("Relocation target %08x points outside of image\n",
119 val);
Alexey Brodkinb628c012014-02-04 12:56:15 +0400120 }
Alexey Brodkinb628c012014-02-04 12:56:15 +0400121
Alexey Brodkinf711e542018-05-29 18:09:55 +0300122 val += gd->reloc_off;
123
124 if (do_swap)
125 val = (val << 16) | (val >> 16);
126
127 memcpy(offset_ptr_ram, &val, sizeof(int));
128 }
Alexey Brodkinb628c012014-02-04 12:56:15 +0400129 } while (++re_src < re_end);
130
131 return 0;
132}