Home | History | Annotate | Line # | Download | only in hppa
      1 /*	$NetBSD: kobj_machdep.c,v 1.16 2023/04/28 07:33:56 skrll Exp $	*/
      2 
      3 /*-
      4  * Copyright (c) 2008 The NetBSD Foundation, Inc.
      5  * All rights reserved.
      6  *
      7  * Redistribution and use in source and binary forms, with or without
      8  * modification, are permitted provided that the following conditions
      9  * are met:
     10  * 1. Redistributions of source code must retain the above copyright
     11  *    notice, this list of conditions and the following disclaimer.
     12  * 2. Redistributions in binary form must reproduce the above copyright
     13  *    notice, this list of conditions and the following disclaimer in the
     14  *    documentation and/or other materials provided with the distribution.
     15  *
     16  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
     17  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
     18  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
     19  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
     20  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
     21  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
     22  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
     23  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
     24  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
     25  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
     26  * POSSIBILITY OF SUCH DAMAGE.
     27  */
     28 
     29 /*-
     30  * Copyright 1996-1998 John D. Polstra.
     31  * All rights reserved.
     32  *
     33  * Redistribution and use in source and binary forms, with or without
     34  * modification, are permitted provided that the following conditions
     35  * are met:
     36  * 1. Redistributions of source code must retain the above copyright
     37  *    notice, this list of conditions and the following disclaimer.
     38  * 2. Redistributions in binary form must reproduce the above copyright
     39  *    notice, this list of conditions and the following disclaimer in the
     40  *    documentation and/or other materials provided with the distribution.
     41  *
     42  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
     43  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
     44  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
     45  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
     46  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
     47  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
     48  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
     49  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
     50  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
     51  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     52  */
     53 
     54 #include <sys/cdefs.h>
     55 __KERNEL_RCSID(0, "$NetBSD: kobj_machdep.c,v 1.16 2023/04/28 07:33:56 skrll Exp $");
     56 
     57 #define	ELFSIZE		ARCH_ELFSIZE
     58 
     59 #include <sys/param.h>
     60 #include <sys/systm.h>
     61 #include <sys/kobj.h>
     62 #include <sys/exec.h>
     63 #include <sys/exec_elf.h>
     64 
     65 #include <uvm/uvm_extern.h>
     66 
     67 #include <machine/cpufunc.h>
     68 #include <machine/pmap.h>
     69 
     70 static inline unsigned int
     71 RND(unsigned int x)
     72 {
     73         return ((x + 0x1000) & 0xffffe000);
     74 }
     75 
     76 static inline unsigned int
     77 R(unsigned int x)
     78 {
     79         return (x & 0x000007ff);
     80 }
     81 
     82 static inline unsigned int
     83 L(unsigned int x)
     84 {
     85         return (x & 0xfffff800);
     86 }
     87 
     88 static inline unsigned int
     89 LR(unsigned int x, unsigned int constant)
     90 {
     91         return L(x + RND(constant));
     92 }
     93 
     94 static inline unsigned int
     95 RR(unsigned int x, unsigned int constant)
     96 {
     97         return R(x + RND(constant)) + (constant - RND(constant));
     98 }
     99 
    100 /*
    101  * It is possible for the compiler to emit relocations for unaligned data.
    102  * We handle this situation with these inlines.
    103  */
    104 #define	RELOC_ALIGNED_P(x) \
    105 	(((uintptr_t)(x) & (sizeof(void *) - 1)) == 0)
    106 
    107 static inline Elf_Addr
    108 load_ptr(void *where)
    109 {
    110 	if (__predict_true(RELOC_ALIGNED_P(where)))
    111 		return *(Elf_Addr *)where;
    112 	else {
    113 		Elf_Addr res;
    114 
    115 		(void)memcpy(&res, where, sizeof(res));
    116 		return res;
    117 	}
    118 }
    119 
    120 static inline void
    121 store_ptr(void *where, Elf_Addr val)
    122 {
    123 	if (__predict_true(RELOC_ALIGNED_P(where)))
    124 		*(Elf_Addr *)where = val;
    125 	else
    126 		(void)memcpy(where, &val, sizeof(val));
    127 }
    128 
    129 int
    130 kobj_reloc(kobj_t ko, uintptr_t relocbase, const void *data,
    131     bool isrela, bool local)
    132 {
    133 	Elf_Addr *where;
    134 	Elf_Addr addr, value;
    135 	Elf_Word rtype, symidx;
    136 	const Elf_Rela *rela;
    137 	extern int __data_start;
    138 
    139 	unsigned int GP = (int) &__data_start;
    140 
    141 	if (!isrela) {
    142 		printf("kobj_reloc: only support RELA relocations\n");
    143 		return -1;
    144 	}
    145 
    146 	rela = (const Elf_Rela *)data;
    147 	where = (Elf_Addr *) (relocbase + rela->r_offset);
    148 	value = rela->r_addend;
    149 	rtype = ELF_R_TYPE(rela->r_info);
    150 	symidx = ELF_R_SYM(rela->r_info);
    151 
    152 	const Elf_Sym *sym = kobj_symbol(ko, symidx);
    153 
    154 	if (!local && ELF_ST_BIND(sym->st_info) == STB_LOCAL) {
    155 		return 0;
    156 	}
    157 
    158 	switch (rtype) {
    159 	case R_TYPE(NONE):
    160 		break;
    161 
    162 	case R_TYPE(DIR32):
    163 		/* symbol + addend */
    164 		kobj_sym_lookup(ko, symidx, &addr);
    165 		value += addr;
    166 		break;
    167 
    168 	case R_TYPE(DIR21L):
    169 		/* LR(symbol, addend) */
    170 		kobj_sym_lookup(ko, symidx, &addr);
    171 		value = LR(addr, value);
    172 		break;
    173 
    174 	case R_TYPE(DIR17R):
    175 	case R_TYPE(DIR14R):
    176 		/* RR(symbol, addend) */
    177 		kobj_sym_lookup(ko, symidx, &addr);
    178 		value = RR(addr, value);
    179 		break;
    180 
    181 	case R_TYPE(PCREL32):
    182 	case R_TYPE(PCREL17F):
    183 		/* symbol - PC - 8 + addend */
    184 		kobj_sym_lookup(ko, symidx, &addr);
    185 		value += addr - (Elf_Word)where - 8;
    186 		break;
    187 
    188 	case R_TYPE(DPREL21L):
    189 		/* LR(symbol - GP, addend) */
    190 		kobj_sym_lookup(ko, symidx, &addr);
    191 		value = LR(addr - GP, value);
    192 		break;
    193 
    194 	case R_TYPE(DPREL14R):
    195 		/* RR(symbol - GP, addend) */
    196 		kobj_sym_lookup(ko, symidx, &addr);
    197 		value = RR(addr - GP, value);
    198 		break;
    199 
    200 	case R_TYPE(PLABEL32):
    201 		/* fptr(symbol) */
    202 		kobj_sym_lookup(ko, symidx, &addr);
    203 		value = addr;
    204 		break;
    205 
    206 	case R_TYPE(SEGREL32):
    207 		/* symbol - SB + addend */
    208 		/* XXX SB */
    209 		kobj_sym_lookup(ko, symidx, &addr);
    210 		value += addr;
    211 		break;
    212 
    213 	default:
    214 		printf("%s: unexpected relocation type %d\n", __func__, rtype);
    215 		return -1;
    216 	}
    217 
    218 	switch (rtype) {
    219 	case R_TYPE(DIR32):
    220 	case R_TYPE(PCREL32):
    221 	case R_TYPE(PLABEL32):
    222 	case R_TYPE(SEGREL32):
    223 		store_ptr(where, value);
    224 		break;
    225 
    226 	case R_TYPE(DIR14R):
    227 	case R_TYPE(DPREL14R):
    228 		*where |=
    229 		     (((value >>  0) & 0x1fff) << 1) |
    230 		     (((value >> 13) & 0x1) << 0);
    231 		break;
    232 
    233 	case R_TYPE(DIR17R):
    234 	case R_TYPE(PCREL17F):
    235 		value >>= 2;		/* bottom two bits not needed */
    236 		*where |=
    237 		    (((value & 0x10000) >> 16) << 0) |		/* w */
    238 		    (((value & 0x0f800) >> 11) << 16) |		/* w1 */
    239 		    (((value & 0x00400) >> 10) << 2) |
    240 		    (((value & 0x003ff) << 1) << 2);		/* w2 */
    241 		break;
    242 
    243 	case R_TYPE(DIR21L):
    244 	case R_TYPE(DPREL21L):
    245 		*where |=
    246 		    (((value >> 31) & 0x001) <<  0) |
    247 		    (((value >> 20) & 0x7ff) <<  1) |
    248 		    (((value >> 18) & 0x003) << 14) |
    249 		    (((value >> 13) & 0x01f) << 16) |
    250 		    (((value >> 11) & 0x003) << 12);
    251 		break;
    252 	}
    253 
    254 	return 0;
    255 }
    256 
    257 int
    258 kobj_machdep(kobj_t ko, void *base, size_t size, bool load)
    259 {
    260 
    261 	if (load) {
    262 		fdcache(HPPA_SID_KERNEL, (vaddr_t)base, size);
    263 		ficache(HPPA_SID_KERNEL, (vaddr_t)base, size);
    264 	}
    265 
    266 	return 0;
    267 }
    268