a3b7428d851991c61067fcc052d858c26d5398c0
[platform/kernel/u-boot.git] / arch / arc / lib / relocate.c
1 // SPDX-License-Identifier: GPL-2.0+
2 /*
3  * Copyright (C) 2013-2014 Synopsys, Inc. All rights reserved.
4  */
5
6 #include <common.h>
7 #include <elf.h>
8 #include <asm-generic/sections.h>
9
10 extern ulong __image_copy_start;
11 extern ulong __ivt_end;
12
13 DECLARE_GLOBAL_DATA_PTR;
14
15 int copy_uboot_to_ram(void)
16 {
17         size_t len = (size_t)&__image_copy_end - (size_t)&__image_copy_start;
18
19         if (gd->flags & GD_FLG_SKIP_RELOC)
20                 return 0;
21
22         memcpy((void *)gd->relocaddr, (void *)&__image_copy_start, len);
23
24         return 0;
25 }
26
27 int clear_bss(void)
28 {
29         ulong dst_addr = (ulong)&__bss_start + gd->reloc_off;
30         size_t len = (size_t)&__bss_end - (size_t)&__bss_start;
31
32         memset((void *)dst_addr, 0x00, len);
33
34         return 0;
35 }
36
37 /*
38  * Base functionality is taken from x86 version with added ARC-specifics
39  */
40 int do_elf_reloc_fixups(void)
41 {
42         Elf32_Rela *re_src = (Elf32_Rela *)(&__rel_dyn_start);
43         Elf32_Rela *re_end = (Elf32_Rela *)(&__rel_dyn_end);
44
45         if (gd->flags & GD_FLG_SKIP_RELOC)
46                 return 0;
47
48         debug("Section .rela.dyn is located at %08x-%08x\n",
49               (unsigned int)re_src, (unsigned int)re_end);
50
51         Elf32_Addr *offset_ptr_rom, *last_offset = NULL;
52         Elf32_Addr *offset_ptr_ram;
53
54         do {
55                 /* Get the location from the relocation entry */
56                 offset_ptr_rom = (Elf32_Addr *)re_src->r_offset;
57
58                 /* Check that the location of the relocation is in .text */
59                 if (offset_ptr_rom >= (Elf32_Addr *)&__image_copy_start &&
60                     offset_ptr_rom > last_offset) {
61                         unsigned int val;
62                         /* Switch to the in-RAM version */
63                         offset_ptr_ram = (Elf32_Addr *)((ulong)offset_ptr_rom +
64                                                         gd->reloc_off);
65
66                         debug("Patching value @ %08x (relocated to %08x)\n",
67                               (unsigned int)offset_ptr_rom,
68                               (unsigned int)offset_ptr_ram);
69
70                         /*
71                          * Use "memcpy" because target location might be
72                          * 16-bit aligned on ARC so we may need to read
73                          * byte-by-byte. On attempt to read entire word by
74                          * CPU throws an exception
75                          */
76                         memcpy(&val, offset_ptr_ram, sizeof(int));
77
78 #ifdef __LITTLE_ENDIAN__
79                         /* If location in ".text" section swap value */
80                         if ((unsigned int)offset_ptr_rom <
81                             (unsigned int)&__ivt_end)
82                                 val = (val << 16) | (val >> 16);
83 #endif
84
85                         /* Check that the target points into executable */
86                         if (val >= (unsigned int)&__image_copy_start && val <=
87                             (unsigned int)&__image_copy_end) {
88                                 val += gd->reloc_off;
89 #ifdef __LITTLE_ENDIAN__
90                                 /* If location in ".text" section swap value */
91                                 if ((unsigned int)offset_ptr_rom <
92                                     (unsigned int)&__ivt_end)
93                                         val = (val << 16) | (val >> 16);
94 #endif
95                                 memcpy(offset_ptr_ram, &val, sizeof(int));
96                         }
97                 }
98                 last_offset = offset_ptr_rom;
99
100         } while (++re_src < re_end);
101
102         return 0;
103 }