blob: e46fe5bdd5d74befb08f6442a0fe8aaf2f532e91 [file] [log] [blame]
Michal Simekf942ebb2022-06-24 14:15:01 +02001// SPDX-License-Identifier: GPL-2.0
2/*
3 * (C) Copyright 2022 Advanced Micro Devices, Inc
4 * Michal Simek <michal.simek@amd.com>
5 */
6
Michal Simekf942ebb2022-06-24 14:15:01 +02007#include <elf.h>
Tom Rinicee346c2023-10-12 19:03:57 -04008#include <log.h>
9#include <linux/types.h>
Michal Simekf942ebb2022-06-24 14:15:01 +020010
11#define R_MICROBLAZE_NONE 0
12#define R_MICROBLAZE_32 1
13#define R_MICROBLAZE_REL 16
14#define R_MICROBLAZE_GLOB_DAT 18
15
16/**
17 * mb_fix_rela - update relocation to new address
18 * @reloc_addr: new relocation address
19 * @verbose: enable version messages
20 * @rela_start: rela section start
21 * @rela_end: rela section end
22 * @dyn_start: dynamic section start
Simon Glass72cc5382022-10-20 18:22:39 -060023 * @origin_addr: address where u-boot starts(doesn't need to be CONFIG_TEXT_BASE)
Michal Simekf942ebb2022-06-24 14:15:01 +020024 */
25void mb_fix_rela(u32 reloc_addr, u32 verbose, u32 rela_start,
26 u32 rela_end, u32 dyn_start, u32 origin_addr)
27{
28 u32 num, type, mask, i, reloc_off;
29
30 /*
31 * Return in case u-boot.elf is used directly.
32 * Skip it when u-boot.bin is loaded to different address than
Simon Glass72cc5382022-10-20 18:22:39 -060033 * CONFIG_TEXT_BASE. In this case relocation is necessary to run.
Michal Simekf942ebb2022-06-24 14:15:01 +020034 */
Simon Glass72cc5382022-10-20 18:22:39 -060035 if (reloc_addr == CONFIG_TEXT_BASE) {
Michal Simekf942ebb2022-06-24 14:15:01 +020036 debug_cond(verbose,
37 "Relocation address is the same - skip relocation\n");
38 return;
39 }
40
41 reloc_off = reloc_addr - origin_addr;
42
43 debug_cond(verbose, "Relocation address:\t0x%08x\n", reloc_addr);
44 debug_cond(verbose, "Relocation offset:\t0x%08x\n", reloc_off);
45 debug_cond(verbose, "Origin address:\t0x%08x\n", origin_addr);
46 debug_cond(verbose, "Rela start:\t0x%08x\n", rela_start);
47 debug_cond(verbose, "Rela end:\t0x%08x\n", rela_end);
48 debug_cond(verbose, "Dynsym start:\t0x%08x\n", dyn_start);
49
50 num = (rela_end - rela_start) / sizeof(Elf32_Rela);
51
52 debug_cond(verbose, "Number of entries:\t%u\n", num);
53
54 for (i = 0; i < num; i++) {
55 Elf32_Rela *rela;
56 u32 temp;
57
58 rela = (Elf32_Rela *)(rela_start + sizeof(Elf32_Rela) * i);
59
60 mask = 0xffULL; /* would be different on 32-bit */
61 type = rela->r_info & mask;
62
63 debug_cond(verbose, "\nRela possition:\t%d/0x%x\n",
64 i, (u32)rela);
65
66 switch (type) {
67 case R_MICROBLAZE_REL:
68 temp = *(u32 *)rela->r_offset;
69
70 debug_cond(verbose, "Type:\tREL\n");
71 debug_cond(verbose, "Rela r_offset:\t\t0x%x\n", rela->r_offset);
72 debug_cond(verbose, "Rela r_info:\t\t0x%x\n", rela->r_info);
73 debug_cond(verbose, "Rela r_addend:\t\t0x%x\n", rela->r_addend);
74 debug_cond(verbose, "Value at r_offset:\t0x%x\n", temp);
75
76 rela->r_offset += reloc_off;
77 rela->r_addend += reloc_off;
78
79 temp = *(u32 *)rela->r_offset;
80 temp += reloc_off;
81 *(u32 *)rela->r_offset = temp;
82
83 debug_cond(verbose, "New:Rela r_offset:\t0x%x\n", rela->r_offset);
84 debug_cond(verbose, "New:Rela r_addend:\t0x%x\n", rela->r_addend);
85 debug_cond(verbose, "New:Value at r_offset:\t0x%x\n", temp);
86 break;
87 case R_MICROBLAZE_32:
88 case R_MICROBLAZE_GLOB_DAT:
89 debug_cond(verbose, "Type:\t(32/GLOB) %u\n", type);
90 debug_cond(verbose, "Rela r_offset:\t\t0x%x\n", rela->r_offset);
91 debug_cond(verbose, "Rela r_info:\t\t0x%x\n", rela->r_info);
92 debug_cond(verbose, "Rela r_addend:\t\t0x%x\n", rela->r_addend);
93 debug_cond(verbose, "Value at r_offset:\t0x%x\n", temp);
94
95 rela->r_offset += reloc_off;
96
97 temp = *(u32 *)rela->r_offset;
98 temp += reloc_off;
99 *(u32 *)rela->r_offset = temp;
100
101 debug_cond(verbose, "New:Rela r_offset:\t0x%x\n", rela->r_offset);
102 debug_cond(verbose, "New:Value at r_offset:\t0x%x\n", temp);
103 break;
104 case R_MICROBLAZE_NONE:
105 debug_cond(verbose, "R_MICROBLAZE_NONE - skip\n");
106 break;
107 default:
108 debug_cond(verbose, "warning: unsupported relocation type %d at %x\n",
109 type, rela->r_offset);
110 }
111 }
112}