1355961Sdim// SPDX-License-Identifier: GPL-2.0 2355961Sdim/* 3355961Sdim * (C) Copyright 2022 Advanced Micro Devices, Inc 4355961Sdim * Michal Simek <michal.simek@amd.com> 5355961Sdim */ 6355961Sdim 7355961Sdim#include <elf.h> 8355961Sdim#include <log.h> 9355961Sdim#include <linux/types.h> 10355961Sdim 11355961Sdim#define R_MICROBLAZE_NONE 0 12355961Sdim#define R_MICROBLAZE_32 1 13355961Sdim#define R_MICROBLAZE_REL 16 14355961Sdim#define R_MICROBLAZE_GLOB_DAT 18 15355961Sdim 16355961Sdim/** 17355961Sdim * mb_fix_rela - update relocation to new address 18355961Sdim * @reloc_addr: new relocation address 19355961Sdim * @verbose: enable version messages 20355961Sdim * @rela_start: rela section start 21355961Sdim * @rela_end: rela section end 22355961Sdim * @dyn_start: dynamic section start 23355961Sdim * @origin_addr: address where u-boot starts(doesn't need to be CONFIG_TEXT_BASE) 24355961Sdim */ 25355961Sdimvoid mb_fix_rela(u32 reloc_addr, u32 verbose, u32 rela_start, 26355961Sdim u32 rela_end, u32 dyn_start, u32 origin_addr) 27355961Sdim{ 28355961Sdim u32 num, type, mask, i, reloc_off; 29355961Sdim 30355961Sdim /* 31355961Sdim * Return in case u-boot.elf is used directly. 32355961Sdim * Skip it when u-boot.bin is loaded to different address than 33355961Sdim * CONFIG_TEXT_BASE. In this case relocation is necessary to run. 34355961Sdim */ 35355961Sdim if (reloc_addr == CONFIG_TEXT_BASE) { 36355961Sdim debug_cond(verbose, 37355961Sdim "Relocation address is the same - skip relocation\n"); 38355961Sdim return; 39355961Sdim } 40355961Sdim 41355961Sdim reloc_off = reloc_addr - origin_addr; 42355961Sdim 43355961Sdim debug_cond(verbose, "Relocation address:\t0x%08x\n", reloc_addr); 44355961Sdim debug_cond(verbose, "Relocation offset:\t0x%08x\n", reloc_off); 45355961Sdim debug_cond(verbose, "Origin address:\t0x%08x\n", origin_addr); 46355961Sdim debug_cond(verbose, "Rela start:\t0x%08x\n", rela_start); 47355961Sdim debug_cond(verbose, "Rela end:\t0x%08x\n", rela_end); 48355961Sdim debug_cond(verbose, "Dynsym start:\t0x%08x\n", dyn_start); 49355961Sdim 50355961Sdim num = (rela_end - rela_start) / sizeof(Elf32_Rela); 51355961Sdim 52355961Sdim debug_cond(verbose, "Number of entries:\t%u\n", num); 53355961Sdim 54355961Sdim for (i = 0; i < num; i++) { 55355961Sdim Elf32_Rela *rela; 56355961Sdim u32 temp; 57355961Sdim 58355961Sdim rela = (Elf32_Rela *)(rela_start + sizeof(Elf32_Rela) * i); 59355961Sdim 60355961Sdim mask = 0xffULL; /* would be different on 32-bit */ 61355961Sdim type = rela->r_info & mask; 62355961Sdim 63355961Sdim debug_cond(verbose, "\nRela possition:\t%d/0x%x\n", 64355961Sdim i, (u32)rela); 65355961Sdim 66355961Sdim switch (type) { 67355961Sdim case R_MICROBLAZE_REL: 68355961Sdim temp = *(u32 *)rela->r_offset; 69355961Sdim 70360784Sdim debug_cond(verbose, "Type:\tREL\n"); 71355961Sdim debug_cond(verbose, "Rela r_offset:\t\t0x%x\n", rela->r_offset); 72355961Sdim debug_cond(verbose, "Rela r_info:\t\t0x%x\n", rela->r_info); 73355961Sdim debug_cond(verbose, "Rela r_addend:\t\t0x%x\n", rela->r_addend); 74355961Sdim debug_cond(verbose, "Value at r_offset:\t0x%x\n", temp); 75355961Sdim 76355961Sdim rela->r_offset += reloc_off; 77355961Sdim rela->r_addend += reloc_off; 78355961Sdim 79355961Sdim temp = *(u32 *)rela->r_offset; 80355961Sdim temp += reloc_off; 81355961Sdim *(u32 *)rela->r_offset = temp; 82355961Sdim 83355961Sdim debug_cond(verbose, "New:Rela r_offset:\t0x%x\n", rela->r_offset); 84355961Sdim debug_cond(verbose, "New:Rela r_addend:\t0x%x\n", rela->r_addend); 85355961Sdim debug_cond(verbose, "New:Value at r_offset:\t0x%x\n", temp); 86355961Sdim break; 87355961Sdim case R_MICROBLAZE_32: 88355961Sdim 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} 113