18c2ecf20Sopenharmony_ci/* SPDX-License-Identifier: GPL-2.0 */ 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * uClinux flat-format executables 48c2ecf20Sopenharmony_ci * 58c2ecf20Sopenharmony_ci * Copyright (C) 2005 John Williams <jwilliams@itee.uq.edu.au> 68c2ecf20Sopenharmony_ci */ 78c2ecf20Sopenharmony_ci 88c2ecf20Sopenharmony_ci#ifndef _ASM_MICROBLAZE_FLAT_H 98c2ecf20Sopenharmony_ci#define _ASM_MICROBLAZE_FLAT_H 108c2ecf20Sopenharmony_ci 118c2ecf20Sopenharmony_ci#include <asm/unaligned.h> 128c2ecf20Sopenharmony_ci 138c2ecf20Sopenharmony_ci/* 148c2ecf20Sopenharmony_ci * Microblaze works a little differently from other arches, because 158c2ecf20Sopenharmony_ci * of the MICROBLAZE_64 reloc type. Here, a 32 bit address is split 168c2ecf20Sopenharmony_ci * over two instructions, an 'imm' instruction which provides the top 178c2ecf20Sopenharmony_ci * 16 bits, then the instruction "proper" which provides the low 16 188c2ecf20Sopenharmony_ci * bits. 198c2ecf20Sopenharmony_ci */ 208c2ecf20Sopenharmony_ci 218c2ecf20Sopenharmony_ci/* 228c2ecf20Sopenharmony_ci * Crack open a symbol reference and extract the address to be 238c2ecf20Sopenharmony_ci * relocated. rp is a potentially unaligned pointer to the 248c2ecf20Sopenharmony_ci * reference 258c2ecf20Sopenharmony_ci */ 268c2ecf20Sopenharmony_ci 278c2ecf20Sopenharmony_cistatic inline int flat_get_addr_from_rp(u32 __user *rp, u32 relval, u32 flags, 288c2ecf20Sopenharmony_ci u32 *addr) 298c2ecf20Sopenharmony_ci{ 308c2ecf20Sopenharmony_ci u32 *p = (__force u32 *)rp; 318c2ecf20Sopenharmony_ci 328c2ecf20Sopenharmony_ci /* Is it a split 64/32 reference? */ 338c2ecf20Sopenharmony_ci if (relval & 0x80000000) { 348c2ecf20Sopenharmony_ci /* Grab the two halves of the reference */ 358c2ecf20Sopenharmony_ci u32 val_hi, val_lo; 368c2ecf20Sopenharmony_ci 378c2ecf20Sopenharmony_ci val_hi = get_unaligned(p); 388c2ecf20Sopenharmony_ci val_lo = get_unaligned(p+1); 398c2ecf20Sopenharmony_ci 408c2ecf20Sopenharmony_ci /* Crack the address out */ 418c2ecf20Sopenharmony_ci *addr = ((val_hi & 0xffff) << 16) + (val_lo & 0xffff); 428c2ecf20Sopenharmony_ci } else { 438c2ecf20Sopenharmony_ci /* Get the address straight out */ 448c2ecf20Sopenharmony_ci *addr = get_unaligned(p); 458c2ecf20Sopenharmony_ci } 468c2ecf20Sopenharmony_ci 478c2ecf20Sopenharmony_ci return 0; 488c2ecf20Sopenharmony_ci} 498c2ecf20Sopenharmony_ci 508c2ecf20Sopenharmony_ci/* 518c2ecf20Sopenharmony_ci * Insert an address into the symbol reference at rp. rp is potentially 528c2ecf20Sopenharmony_ci * unaligned. 538c2ecf20Sopenharmony_ci */ 548c2ecf20Sopenharmony_ci 558c2ecf20Sopenharmony_cistatic inline int 568c2ecf20Sopenharmony_ciflat_put_addr_at_rp(u32 __user *rp, u32 addr, u32 relval) 578c2ecf20Sopenharmony_ci{ 588c2ecf20Sopenharmony_ci u32 *p = (__force u32 *)rp; 598c2ecf20Sopenharmony_ci /* Is this a split 64/32 reloc? */ 608c2ecf20Sopenharmony_ci if (relval & 0x80000000) { 618c2ecf20Sopenharmony_ci /* Get the two "halves" */ 628c2ecf20Sopenharmony_ci unsigned long val_hi = get_unaligned(p); 638c2ecf20Sopenharmony_ci unsigned long val_lo = get_unaligned(p + 1); 648c2ecf20Sopenharmony_ci 658c2ecf20Sopenharmony_ci /* insert the address */ 668c2ecf20Sopenharmony_ci val_hi = (val_hi & 0xffff0000) | addr >> 16; 678c2ecf20Sopenharmony_ci val_lo = (val_lo & 0xffff0000) | (addr & 0xffff); 688c2ecf20Sopenharmony_ci 698c2ecf20Sopenharmony_ci /* store the two halves back into memory */ 708c2ecf20Sopenharmony_ci put_unaligned(val_hi, p); 718c2ecf20Sopenharmony_ci put_unaligned(val_lo, p+1); 728c2ecf20Sopenharmony_ci } else { 738c2ecf20Sopenharmony_ci /* Put it straight in, no messing around */ 748c2ecf20Sopenharmony_ci put_unaligned(addr, p); 758c2ecf20Sopenharmony_ci } 768c2ecf20Sopenharmony_ci return 0; 778c2ecf20Sopenharmony_ci} 788c2ecf20Sopenharmony_ci 798c2ecf20Sopenharmony_ci#define flat_get_relocate_addr(rel) (rel & 0x7fffffff) 808c2ecf20Sopenharmony_ci 818c2ecf20Sopenharmony_ci#endif /* _ASM_MICROBLAZE_FLAT_H */ 82