]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - sys/riscv/riscv/elf_machdep.c
Merge lldb trunk r351319, resolve conflicts, and update FREEBSD-Xlist.
[FreeBSD/FreeBSD.git] / sys / riscv / riscv / elf_machdep.c
1 /*-
2  * Copyright 1996-1998 John D. Polstra.
3  * Copyright (c) 2015 Ruslan Bukin <br@bsdpad.com>
4  * Copyright (c) 2016 Yukishige Shibata <y-shibat@mtd.biglobe.ne.jp>
5  * All rights reserved.
6  *
7  * Portions of this software were developed by SRI International and the
8  * University of Cambridge Computer Laboratory under DARPA/AFRL contract
9  * FA8750-10-C-0237 ("CTSRD"), as part of the DARPA CRASH research programme.
10  *
11  * Portions of this software were developed by the University of Cambridge
12  * Computer Laboratory as part of the CTSRD Project, with support from the
13  * UK Higher Education Innovation Fund (HEIF).
14  *
15  * Redistribution and use in source and binary forms, with or without
16  * modification, are permitted provided that the following conditions
17  * are met:
18  * 1. Redistributions of source code must retain the above copyright
19  *    notice, this list of conditions and the following disclaimer.
20  * 2. Redistributions in binary form must reproduce the above copyright
21  *    notice, this list of conditions and the following disclaimer in the
22  *    documentation and/or other materials provided with the distribution.
23  *
24  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
25  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
26  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
27  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
28  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
29  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
30  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
31  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
32  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
33  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
34  * SUCH DAMAGE.
35  */
36
37 #include <sys/cdefs.h>
38 __FBSDID("$FreeBSD$");
39
40 #include <sys/param.h>
41 #include <sys/kernel.h>
42 #include <sys/systm.h>
43 #include <sys/exec.h>
44 #include <sys/imgact.h>
45 #include <sys/linker.h>
46 #include <sys/proc.h>
47 #include <sys/sysctl.h>
48 #include <sys/sysent.h>
49 #include <sys/imgact_elf.h>
50 #include <sys/syscall.h>
51 #include <sys/signalvar.h>
52 #include <sys/vnode.h>
53
54 #include <vm/vm.h>
55 #include <vm/pmap.h>
56 #include <vm/vm_param.h>
57
58 #include <machine/elf.h>
59 #include <machine/md_var.h>
60
61 struct sysentvec elf64_freebsd_sysvec = {
62         .sv_size        = SYS_MAXSYSCALL,
63         .sv_table       = sysent,
64         .sv_errsize     = 0,
65         .sv_errtbl      = NULL,
66         .sv_transtrap   = NULL,
67         .sv_fixup       = __elfN(freebsd_fixup),
68         .sv_sendsig     = sendsig,
69         .sv_sigcode     = sigcode,
70         .sv_szsigcode   = &szsigcode,
71         .sv_name        = "FreeBSD ELF64",
72         .sv_coredump    = __elfN(coredump),
73         .sv_imgact_try  = NULL,
74         .sv_minsigstksz = MINSIGSTKSZ,
75         .sv_pagesize    = PAGE_SIZE,
76         .sv_minuser     = VM_MIN_ADDRESS,
77         .sv_maxuser     = VM_MAXUSER_ADDRESS,
78         .sv_usrstack    = USRSTACK,
79         .sv_psstrings   = PS_STRINGS,
80         .sv_stackprot   = VM_PROT_ALL,
81         .sv_copyout_strings     = exec_copyout_strings,
82         .sv_setregs     = exec_setregs,
83         .sv_fixlimit    = NULL,
84         .sv_maxssiz     = NULL,
85         .sv_flags       = SV_ABI_FREEBSD | SV_LP64 | SV_SHP,
86         .sv_set_syscall_retval = cpu_set_syscall_retval,
87         .sv_fetch_syscall_args = cpu_fetch_syscall_args,
88         .sv_syscallnames = syscallnames,
89         .sv_shared_page_base = SHAREDPAGE,
90         .sv_shared_page_len = PAGE_SIZE,
91         .sv_schedtail   = NULL,
92         .sv_thread_detach = NULL,
93         .sv_trap        = NULL,
94 };
95 INIT_SYSENTVEC(elf64_sysvec, &elf64_freebsd_sysvec);
96
97 static Elf64_Brandinfo freebsd_brand_info = {
98         .brand          = ELFOSABI_FREEBSD,
99         .machine        = EM_RISCV,
100         .compat_3_brand = "FreeBSD",
101         .emul_path      = NULL,
102         .interp_path    = "/libexec/ld-elf.so.1",
103         .sysvec         = &elf64_freebsd_sysvec,
104         .interp_newpath = NULL,
105         .brand_note     = &elf64_freebsd_brandnote,
106         .flags          = BI_CAN_EXEC_DYN | BI_BRAND_NOTE
107 };
108
109 SYSINIT(elf64, SI_SUB_EXEC, SI_ORDER_FIRST,
110         (sysinit_cfunc_t) elf64_insert_brand_entry,
111         &freebsd_brand_info);
112
113 static int debug_kld;
114 SYSCTL_INT(_kern, OID_AUTO, debug_kld,
115            CTLFLAG_RW, &debug_kld, 0,
116            "Activate debug prints in elf_reloc_internal()");
117
118 struct type2str_ent {
119         int type;
120         const char *str;
121 };
122
123 void
124 elf64_dump_thread(struct thread *td, void *dst, size_t *off)
125 {
126
127 }
128
129 /*
130  * Following 4 functions are used to manupilate bits on 32bit interger value.
131  * FIXME: I implemetend for ease-to-understand rather than for well-optimized.
132  */
133 static uint32_t
134 gen_bitmask(int msb, int lsb)
135 {
136         uint32_t mask;
137
138         if (msb == sizeof(mask) * 8 - 1)
139                 mask = ~0;
140         else
141                 mask = (1U << (msb + 1)) - 1;
142
143         if (lsb > 0)
144                 mask &= ~((1U << lsb) - 1);
145
146         return (mask);
147 }
148
149 static uint32_t
150 extract_bits(uint32_t x, int msb, int lsb)
151 {
152         uint32_t mask;
153
154         mask = gen_bitmask(msb, lsb);
155
156         x &= mask;
157         x >>= lsb;
158
159         return (x);
160 }
161
162 static uint32_t
163 insert_bits(uint32_t d, uint32_t s, int msb, int lsb)
164 {
165         uint32_t mask;
166
167         mask = gen_bitmask(msb, lsb);
168
169         d &= ~mask;
170
171         s <<= lsb;
172         s &= mask;
173
174         return (d | s);
175 }
176
177 static uint32_t
178 insert_imm(uint32_t insn, uint32_t imm, int imm_msb, int imm_lsb,
179     int insn_lsb)
180 {
181         int insn_msb;
182         uint32_t v;
183
184         v = extract_bits(imm, imm_msb, imm_lsb);
185         insn_msb = (imm_msb - imm_lsb) + insn_lsb;
186
187         return (insert_bits(insn, v, insn_msb, insn_lsb));
188 }
189
190 /*
191  * The RISC-V ISA is designed so that all of immediate values are
192  * sign-extended.
193  * An immediate value is sometimes generated at runtime by adding
194  * 12bit sign integer and 20bit signed integer. This requests 20bit
195  * immediate value to be ajusted if the MSB of the 12bit immediate
196  * value is asserted (sign-extended value is treated as negative value).
197  *
198  * For example, 0x123800 can be calculated by adding upper 20 bit of
199  * 0x124000 and sign-extended 12bit immediate whose bit pattern is
200  * 0x800 as follows:
201  *   0x123800
202  *     = 0x123000 + 0x800
203  *     = (0x123000 + 0x1000) + (-0x1000 + 0x800)
204  *     = (0x123000 + 0x1000) + (0xff...ff800)
205  *     = 0x124000            + sign-extention(0x800)
206  */
207 static uint32_t
208 calc_hi20_imm(uint32_t value)
209 {
210         /*
211          * There is the arithmetical hack that can remove conditional
212          * statement. But I implement it in straightforward way.
213          */
214         if ((value & 0x800) != 0)
215                 value += 0x1000;
216         return (value & ~0xfff);
217 }
218
219 static const struct type2str_ent t2s[] = {
220         { R_RISCV_NONE,         "R_RISCV_NONE"          },
221         { R_RISCV_64,           "R_RISCV_64"            },
222         { R_RISCV_JUMP_SLOT,    "R_RISCV_JUMP_SLOT"     },
223         { R_RISCV_RELATIVE,     "R_RISCV_RELATIVE"      },
224         { R_RISCV_JAL,          "R_RISCV_JAL"           },
225         { R_RISCV_CALL,         "R_RISCV_CALL"          },
226         { R_RISCV_PCREL_HI20,   "R_RISCV_PCREL_HI20"    },
227         { R_RISCV_PCREL_LO12_I, "R_RISCV_PCREL_LO12_I"  },
228         { R_RISCV_PCREL_LO12_S, "R_RISCV_PCREL_LO12_S"  },
229         { R_RISCV_HI20,         "R_RISCV_HI20"          },
230         { R_RISCV_LO12_I,       "R_RISCV_LO12_I"        },
231         { R_RISCV_LO12_S,       "R_RISCV_LO12_S"        },
232 };
233
234 static const char *
235 reloctype_to_str(int type)
236 {
237         int i;
238
239         for (i = 0; i < sizeof(t2s) / sizeof(t2s[0]); ++i) {
240                 if (type == t2s[i].type)
241                         return t2s[i].str;
242         }
243
244         return "*unknown*";
245 }
246
247 bool
248 elf_is_ifunc_reloc(Elf_Size r_info __unused)
249 {
250
251         return (false);
252 }
253
254 /*
255  * Currently kernel loadable module for RISCV is compiled with -fPIC option.
256  * (see also additional CFLAGS definition for RISCV in sys/conf/kmod.mk)
257  * Only R_RISCV_64, R_RISCV_JUMP_SLOT and RISCV_RELATIVE are emitted in
258  * the module. Other relocations will be processed when kernel loadable
259  * modules are built in non-PIC.
260  *
261  * FIXME: only RISCV64 is supported.
262  */
263 static int
264 elf_reloc_internal(linker_file_t lf, Elf_Addr relocbase, const void *data,
265     int type, int local, elf_lookup_fn lookup)
266 {
267         Elf_Size rtype, symidx;
268         const Elf_Rela *rela;
269         Elf_Addr val, addr;
270         Elf64_Addr *where;
271         Elf_Addr addend;
272         uint32_t before32_1;
273         uint32_t before32;
274         uint64_t before64;
275         uint32_t* insn32p;
276         uint32_t imm20;
277         int error;
278
279         switch (type) {
280         case ELF_RELOC_RELA:
281                 rela = (const Elf_Rela *)data;
282                 where = (Elf_Addr *)(relocbase + rela->r_offset);
283                 insn32p = (uint32_t*)where;
284                 addend = rela->r_addend;
285                 rtype = ELF_R_TYPE(rela->r_info);
286                 symidx = ELF_R_SYM(rela->r_info);
287                 break;
288         default:
289                 printf("%s:%d unknown reloc type %d\n",
290                        __FUNCTION__, __LINE__, type);
291                 return -1;
292         }
293
294         switch (rtype) {
295         case R_RISCV_NONE:
296                 break;
297
298         case R_RISCV_64:
299         case R_RISCV_JUMP_SLOT:
300                 error = lookup(lf, symidx, 1, &addr);
301                 if (error != 0)
302                         return -1;
303
304                 val = addr;
305                 before64 = *where;
306                 if (*where != val)
307                         *where = val;
308
309                 if (debug_kld)
310                         printf("%p %c %-24s %016lx -> %016lx\n",
311                                where,
312                                (local? 'l': 'g'),
313                                reloctype_to_str(rtype),
314                                before64, *where);
315                 break;
316
317         case R_RISCV_RELATIVE:
318                 before64 = *where;
319
320                 *where = elf_relocaddr(lf, relocbase + addend);
321
322                 if (debug_kld)
323                         printf("%p %c %-24s %016lx -> %016lx\n",
324                                where,
325                                (local? 'l': 'g'),
326                                reloctype_to_str(rtype),
327                                before64, *where);
328                 break;
329
330         case R_RISCV_JAL:
331                 error = lookup(lf, symidx, 1, &addr);
332                 if (error != 0)
333                         return -1;
334
335                 val = addr - (Elf_Addr)where;
336                 if ((val <= -(1UL << 20) || (1UL << 20) <= val)) {
337                         printf("kldload: huge offset against R_RISCV_JAL\n");
338                         return -1;
339                 }
340
341                 before32 = *insn32p;
342                 *insn32p = insert_imm(*insn32p, val, 20, 20, 31);
343                 *insn32p = insert_imm(*insn32p, val, 10,  1, 21);
344                 *insn32p = insert_imm(*insn32p, val, 11, 11, 20);
345                 *insn32p = insert_imm(*insn32p, val, 19, 12, 12);
346
347                 if (debug_kld)
348                         printf("%p %c %-24s %08x -> %08x\n",
349                                where,
350                                (local? 'l': 'g'),
351                                reloctype_to_str(rtype),
352                                before32, *insn32p);
353                 break;
354
355         case R_RISCV_CALL:
356                 /*
357                  * R_RISCV_CALL relocates 8-byte region that consists
358                  * of the sequence of AUIPC and JALR.
359                  */
360                 /* calculate and check the pc relative offset. */
361                 error = lookup(lf, symidx, 1, &addr);
362                 if (error != 0)
363                         return -1;
364                 val = addr - (Elf_Addr)where;
365                 if ((val <= -(1UL << 32) || (1UL << 32) <= val)) {
366                         printf("kldload: huge offset against R_RISCV_CALL\n");
367                         return -1;
368                 }
369
370                 /* Relocate AUIPC. */
371                 before32 = insn32p[0];
372                 imm20 = calc_hi20_imm(val);
373                 insn32p[0] = insert_imm(insn32p[0], imm20, 31, 12, 12);
374
375                 /* Relocate JALR. */
376                 before32_1 = insn32p[1];
377                 insn32p[1] = insert_imm(insn32p[1], val, 11,  0, 20);
378
379                 if (debug_kld)
380                         printf("%p %c %-24s %08x %08x -> %08x %08x\n",
381                                where,
382                                (local? 'l': 'g'),
383                                reloctype_to_str(rtype),
384                                before32,   insn32p[0],
385                                before32_1, insn32p[1]);
386                 break;
387
388         case R_RISCV_PCREL_HI20:
389                 val = addr - (Elf_Addr)where;
390                 insn32p = (uint32_t*)where;
391                 before32 = *insn32p;
392                 imm20 = calc_hi20_imm(val);
393                 *insn32p = insert_imm(*insn32p, imm20, 31, 12, 12);
394
395                 if (debug_kld)
396                         printf("%p %c %-24s %08x -> %08x\n",
397                                where,
398                                (local? 'l': 'g'),
399                                reloctype_to_str(rtype),
400                                before32, *insn32p);
401                 break;
402
403         case R_RISCV_PCREL_LO12_I:
404                 val = addr - (Elf_Addr)where;
405                 insn32p = (uint32_t*)where;
406                 before32 = *insn32p;
407                 *insn32p = insert_imm(*insn32p, addr, 11,  0, 20);
408
409                 if (debug_kld)
410                         printf("%p %c %-24s %08x -> %08x\n",
411                                where,
412                                (local? 'l': 'g'),
413                                reloctype_to_str(rtype),
414                                before32, *insn32p);
415                 break;
416
417         case R_RISCV_PCREL_LO12_S:
418                 val = addr - (Elf_Addr)where;
419                 insn32p = (uint32_t*)where;
420                 before32 = *insn32p;
421                 *insn32p = insert_imm(*insn32p, addr, 11,  5, 25);
422                 *insn32p = insert_imm(*insn32p, addr,  4,  0,  7);
423                 if (debug_kld)
424                         printf("%p %c %-24s %08x -> %08x\n",
425                                where,
426                                (local? 'l': 'g'),
427                                reloctype_to_str(rtype),
428                                before32, *insn32p);
429                 break;
430
431         case R_RISCV_HI20:
432                 error = lookup(lf, symidx, 1, &addr);
433                 if (error != 0)
434                         return -1;
435
436                 insn32p = (uint32_t*)where;
437                 before32 = *insn32p;
438                 imm20 = calc_hi20_imm(val);
439                 *insn32p = insert_imm(*insn32p, imm20, 31, 12, 12);
440
441                 if (debug_kld)
442                         printf("%p %c %-24s %08x -> %08x\n",
443                                where,
444                                (local? 'l': 'g'),
445                                reloctype_to_str(rtype),
446                                before32, *insn32p);
447                 break;
448
449         case R_RISCV_LO12_I:
450                 error = lookup(lf, symidx, 1, &addr);
451                 if (error != 0)
452                         return -1;
453
454                 val = addr;
455                 insn32p = (uint32_t*)where;
456                 before32 = *insn32p;
457                 *insn32p = insert_imm(*insn32p, addr, 11,  0, 20);
458
459                 if (debug_kld)
460                         printf("%p %c %-24s %08x -> %08x\n",
461                                where,
462                                (local? 'l': 'g'),
463                                reloctype_to_str(rtype),
464                                before32, *insn32p);
465                 break;
466
467         case R_RISCV_LO12_S:
468                 error = lookup(lf, symidx, 1, &addr);
469                 if (error != 0)
470                         return -1;
471
472                 val = addr;
473                 insn32p = (uint32_t*)where;
474                 before32 = *insn32p;
475                 *insn32p = insert_imm(*insn32p, addr, 11,  5, 25);
476                 *insn32p = insert_imm(*insn32p, addr,  4,  0,  7);
477
478                 if (debug_kld)
479                         printf("%p %c %-24s %08x -> %08x\n",
480                                where,
481                                (local? 'l': 'g'),
482                                reloctype_to_str(rtype),
483                                before32, *insn32p);
484                 break;
485
486         default:
487                 printf("kldload: unexpected relocation type %ld\n", rtype);
488                 return (-1);
489         }
490
491         return (0);
492 }
493
494 int
495 elf_reloc(linker_file_t lf, Elf_Addr relocbase, const void *data, int type,
496     elf_lookup_fn lookup)
497 {
498
499         return (elf_reloc_internal(lf, relocbase, data, type, 0, lookup));
500 }
501
502 int
503 elf_reloc_local(linker_file_t lf, Elf_Addr relocbase, const void *data,
504     int type, elf_lookup_fn lookup)
505 {
506
507         return (elf_reloc_internal(lf, relocbase, data, type, 1, lookup));
508 }
509
510 int
511 elf_cpu_load_file(linker_file_t lf __unused)
512 {
513
514         return (0);
515 }
516
517 int
518 elf_cpu_unload_file(linker_file_t lf __unused)
519 {
520
521         return (0);
522 }