]>
Commit | Line | Data |
---|---|---|
83d290c5 | 1 | // SPDX-License-Identifier: GPL-2.0+ |
b156ff09 GR |
2 | /* |
3 | * (C) Copyright 2008-2011 | |
4 | * Graeme Russ, <[email protected]> | |
5 | * | |
6 | * (C) Copyright 2002 | |
7 | * Daniel Engström, Omicron Ceti AB, <[email protected]> | |
8 | * | |
9 | * (C) Copyright 2002 | |
10 | * Wolfgang Denk, DENX Software Engineering, <[email protected]> | |
11 | * | |
12 | * (C) Copyright 2002 | |
13 | * Sysgo Real-Time Solutions, GmbH <www.elinos.com> | |
14 | * Marius Groeger <[email protected]> | |
b156ff09 GR |
15 | */ |
16 | ||
17 | #include <common.h> | |
f7ae49fc | 18 | #include <log.h> |
e47b2d67 | 19 | #include <relocate.h> |
401d1c4f | 20 | #include <asm/global_data.h> |
b156ff09 | 21 | #include <asm/u-boot-x86.h> |
86cfb6bd | 22 | #include <asm/sections.h> |
b156ff09 GR |
23 | #include <elf.h> |
24 | ||
7282d834 SG |
25 | DECLARE_GLOBAL_DATA_PTR; |
26 | ||
a1d57b7a | 27 | int copy_uboot_to_ram(void) |
b156ff09 | 28 | { |
f196bd21 | 29 | size_t len = (uintptr_t)&__data_end - (uintptr_t)&__text_start; |
b156ff09 | 30 | |
981dca69 SG |
31 | if (gd->flags & GD_FLG_SKIP_RELOC) |
32 | return 0; | |
b156ff09 GR |
33 | memcpy((void *)gd->relocaddr, (void *)&__text_start, len); |
34 | ||
35 | return 0; | |
36 | } | |
37 | ||
a1d57b7a | 38 | int clear_bss(void) |
b156ff09 GR |
39 | { |
40 | ulong dst_addr = (ulong)&__bss_start + gd->reloc_off; | |
f196bd21 | 41 | size_t len = (uintptr_t)&__bss_end - (uintptr_t)&__bss_start; |
b156ff09 | 42 | |
981dca69 SG |
43 | if (gd->flags & GD_FLG_SKIP_RELOC) |
44 | return 0; | |
b156ff09 GR |
45 | memset((void *)dst_addr, 0x00, len); |
46 | ||
47 | return 0; | |
48 | } | |
49 | ||
b50b1633 SG |
50 | #if CONFIG_IS_ENABLED(X86_64) |
51 | static void do_elf_reloc_fixups64(unsigned int text_base, uintptr_t size, | |
52 | Elf64_Rela *re_src, Elf64_Rela *re_end) | |
53 | { | |
54 | Elf64_Addr *offset_ptr_rom, *last_offset = NULL; | |
55 | Elf64_Addr *offset_ptr_ram; | |
56 | ||
57 | do { | |
80df194f HS |
58 | unsigned long long type = ELF64_R_TYPE(re_src->r_info); |
59 | ||
60 | if (type != R_X86_64_RELATIVE) { | |
61 | printf("%s: unsupported relocation type 0x%llx " | |
62 | "at %p, ", __func__, type, re_src); | |
63 | printf("offset = 0x%llx\n", re_src->r_offset); | |
64 | continue; | |
65 | } | |
66 | ||
b50b1633 SG |
67 | /* Get the location from the relocation entry */ |
68 | offset_ptr_rom = (Elf64_Addr *)(uintptr_t)re_src->r_offset; | |
69 | ||
70 | /* Check that the location of the relocation is in .text */ | |
71 | if (offset_ptr_rom >= (Elf64_Addr *)(uintptr_t)text_base && | |
72 | offset_ptr_rom > last_offset) { | |
73 | /* Switch to the in-RAM version */ | |
74 | offset_ptr_ram = (Elf64_Addr *)((ulong)offset_ptr_rom + | |
75 | gd->reloc_off); | |
76 | ||
77 | /* Check that the target points into .text */ | |
78 | if (*offset_ptr_ram >= text_base && | |
79 | *offset_ptr_ram <= text_base + size) { | |
80 | *offset_ptr_ram = gd->reloc_off + | |
81 | re_src->r_addend; | |
82 | } else { | |
dee37fc9 | 83 | debug(" %p: %lx: rom reloc %lx, ram %p, value %lx, limit %lX\n", |
b50b1633 SG |
84 | re_src, (ulong)re_src->r_info, |
85 | (ulong)re_src->r_offset, offset_ptr_ram, | |
86 | (ulong)*offset_ptr_ram, text_base + size); | |
87 | } | |
88 | } else { | |
89 | debug(" %p: %lx: rom reloc %lx, last %p\n", re_src, | |
90 | (ulong)re_src->r_info, (ulong)re_src->r_offset, | |
91 | last_offset); | |
92 | } | |
93 | last_offset = offset_ptr_rom; | |
94 | ||
95 | } while (++re_src < re_end); | |
96 | } | |
97 | #else | |
dc7e2133 SG |
98 | static void do_elf_reloc_fixups32(unsigned int text_base, uintptr_t size, |
99 | Elf32_Rel *re_src, Elf32_Rel *re_end) | |
b156ff09 | 100 | { |
62f7970a | 101 | Elf32_Addr *offset_ptr_rom, *last_offset = NULL; |
b156ff09 | 102 | Elf32_Addr *offset_ptr_ram; |
512e581c | 103 | |
b156ff09 | 104 | do { |
80df194f HS |
105 | unsigned int type = ELF32_R_TYPE(re_src->r_info); |
106 | ||
107 | if (type != R_386_RELATIVE) { | |
108 | printf("%s: unsupported relocation type 0x%x " | |
109 | "at %p, ", __func__, type, re_src); | |
110 | printf("offset = 0x%x\n", re_src->r_offset); | |
111 | continue; | |
112 | } | |
113 | ||
b156ff09 | 114 | /* Get the location from the relocation entry */ |
dc7e2133 | 115 | offset_ptr_rom = (Elf32_Addr *)(uintptr_t)re_src->r_offset; |
b156ff09 GR |
116 | |
117 | /* Check that the location of the relocation is in .text */ | |
dc7e2133 | 118 | if (offset_ptr_rom >= (Elf32_Addr *)(uintptr_t)text_base && |
a42bfe02 | 119 | offset_ptr_rom > last_offset) { |
b156ff09 GR |
120 | |
121 | /* Switch to the in-RAM version */ | |
122 | offset_ptr_ram = (Elf32_Addr *)((ulong)offset_ptr_rom + | |
123 | gd->reloc_off); | |
124 | ||
125 | /* Check that the target points into .text */ | |
a42bfe02 SG |
126 | if (*offset_ptr_ram >= text_base && |
127 | *offset_ptr_ram <= text_base + size) { | |
b156ff09 | 128 | *offset_ptr_ram += gd->reloc_off; |
62f7970a | 129 | } else { |
dee37fc9 MY |
130 | debug(" %p: rom reloc %x, ram %p, value %x, limit %lX\n", |
131 | re_src, re_src->r_offset, offset_ptr_ram, | |
132 | *offset_ptr_ram, text_base + size); | |
b156ff09 | 133 | } |
62f7970a SG |
134 | } else { |
135 | debug(" %p: rom reloc %x, last %p\n", re_src, | |
136 | re_src->r_offset, last_offset); | |
b156ff09 | 137 | } |
62f7970a SG |
138 | last_offset = offset_ptr_rom; |
139 | ||
0c392909 | 140 | } while (++re_src < re_end); |
dc7e2133 | 141 | } |
b50b1633 | 142 | #endif |
dc7e2133 SG |
143 | |
144 | /* | |
145 | * This function has more error checking than you might expect. Please see | |
146 | * this commit message for more information: | |
147 | * 62f7970a x86: Add error checking to x86 relocation code | |
148 | */ | |
149 | int do_elf_reloc_fixups(void) | |
150 | { | |
151 | void *re_src = (void *)(&__rel_dyn_start); | |
152 | void *re_end = (void *)(&__rel_dyn_end); | |
153 | uint text_base; | |
154 | ||
155 | /* The size of the region of u-boot that runs out of RAM. */ | |
156 | uintptr_t size = (uintptr_t)&__bss_end - (uintptr_t)&__text_start; | |
157 | ||
158 | if (gd->flags & GD_FLG_SKIP_RELOC) | |
159 | return 0; | |
160 | if (re_src == re_end) | |
161 | panic("No relocation data"); | |
162 | ||
163 | #ifdef CONFIG_SYS_TEXT_BASE | |
164 | text_base = CONFIG_SYS_TEXT_BASE; | |
165 | #else | |
166 | panic("No CONFIG_SYS_TEXT_BASE"); | |
167 | #endif | |
b50b1633 SG |
168 | #if CONFIG_IS_ENABLED(X86_64) |
169 | do_elf_reloc_fixups64(text_base, size, re_src, re_end); | |
170 | #else | |
dc7e2133 | 171 | do_elf_reloc_fixups32(text_base, size, re_src, re_end); |
b50b1633 | 172 | #endif |
b156ff09 GR |
173 | |
174 | return 0; | |
175 | } |