]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - sys/riscv/riscv/elf_machdep.c
Stack unwinding robustness fixes for RISC-V.
[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 static const char *riscv_machine_arch(struct proc *p);
62
63 u_long elf_hwcap;
64
65 struct sysentvec elf64_freebsd_sysvec = {
66         .sv_size        = SYS_MAXSYSCALL,
67         .sv_table       = sysent,
68         .sv_transtrap   = NULL,
69         .sv_fixup       = __elfN(freebsd_fixup),
70         .sv_sendsig     = sendsig,
71         .sv_sigcode     = sigcode,
72         .sv_szsigcode   = &szsigcode,
73         .sv_name        = "FreeBSD ELF64",
74         .sv_coredump    = __elfN(coredump),
75         .sv_imgact_try  = NULL,
76         .sv_minsigstksz = MINSIGSTKSZ,
77         .sv_minuser     = VM_MIN_ADDRESS,
78         .sv_maxuser     = VM_MAXUSER_ADDRESS,
79         .sv_usrstack    = USRSTACK,
80         .sv_psstrings   = PS_STRINGS,
81         .sv_stackprot   = VM_PROT_READ | VM_PROT_WRITE,
82         .sv_copyout_auxargs = __elfN(freebsd_copyout_auxargs),
83         .sv_copyout_strings     = exec_copyout_strings,
84         .sv_setregs     = exec_setregs,
85         .sv_fixlimit    = NULL,
86         .sv_maxssiz     = NULL,
87         .sv_flags       = SV_ABI_FREEBSD | SV_LP64 | SV_SHP | SV_ASLR |
88             SV_RNG_SEED_VER,
89         .sv_set_syscall_retval = cpu_set_syscall_retval,
90         .sv_fetch_syscall_args = cpu_fetch_syscall_args,
91         .sv_syscallnames = syscallnames,
92         .sv_shared_page_base = SHAREDPAGE,
93         .sv_shared_page_len = PAGE_SIZE,
94         .sv_schedtail   = NULL,
95         .sv_thread_detach = NULL,
96         .sv_trap        = NULL,
97         .sv_hwcap       = &elf_hwcap,
98         .sv_machine_arch = riscv_machine_arch,
99 };
100 INIT_SYSENTVEC(elf64_sysvec, &elf64_freebsd_sysvec);
101
102 static const char *
103 riscv_machine_arch(struct proc *p)
104 {
105
106         if ((p->p_elf_flags & EF_RISCV_FLOAT_ABI_MASK) ==
107             EF_RISCV_FLOAT_ABI_SOFT)
108                 return (MACHINE_ARCH "sf");
109         return (MACHINE_ARCH);
110 }
111
112 static Elf64_Brandinfo freebsd_brand_info = {
113         .brand          = ELFOSABI_FREEBSD,
114         .machine        = EM_RISCV,
115         .compat_3_brand = "FreeBSD",
116         .emul_path      = NULL,
117         .interp_path    = "/libexec/ld-elf.so.1",
118         .sysvec         = &elf64_freebsd_sysvec,
119         .interp_newpath = NULL,
120         .brand_note     = &elf64_freebsd_brandnote,
121         .flags          = BI_CAN_EXEC_DYN | BI_BRAND_NOTE
122 };
123
124 SYSINIT(elf64, SI_SUB_EXEC, SI_ORDER_FIRST,
125     (sysinit_cfunc_t)elf64_insert_brand_entry, &freebsd_brand_info);
126
127 static bool debug_kld;
128 SYSCTL_BOOL(_debug, OID_AUTO, kld_reloc, CTLFLAG_RW, &debug_kld, 0,
129     "Activate debug prints in elf_reloc_internal()");
130
131 struct type2str_ent {
132         int type;
133         const char *str;
134 };
135
136 void
137 elf64_dump_thread(struct thread *td, void *dst, size_t *off)
138 {
139
140 }
141
142 /*
143  * Following 4 functions are used to manupilate bits on 32bit interger value.
144  * FIXME: I implemetend for ease-to-understand rather than for well-optimized.
145  */
146 static uint32_t
147 gen_bitmask(int msb, int lsb)
148 {
149         uint32_t mask;
150
151         if (msb == sizeof(mask) * 8 - 1)
152                 mask = ~0;
153         else
154                 mask = (1U << (msb + 1)) - 1;
155
156         if (lsb > 0)
157                 mask &= ~((1U << lsb) - 1);
158
159         return (mask);
160 }
161
162 static uint32_t
163 extract_bits(uint32_t x, int msb, int lsb)
164 {
165         uint32_t mask;
166
167         mask = gen_bitmask(msb, lsb);
168
169         x &= mask;
170         x >>= lsb;
171
172         return (x);
173 }
174
175 static uint32_t
176 insert_bits(uint32_t d, uint32_t s, int msb, int lsb)
177 {
178         uint32_t mask;
179
180         mask = gen_bitmask(msb, lsb);
181
182         d &= ~mask;
183
184         s <<= lsb;
185         s &= mask;
186
187         return (d | s);
188 }
189
190 static uint32_t
191 insert_imm(uint32_t insn, uint32_t imm, int imm_msb, int imm_lsb,
192     int insn_lsb)
193 {
194         int insn_msb;
195         uint32_t v;
196
197         v = extract_bits(imm, imm_msb, imm_lsb);
198         insn_msb = (imm_msb - imm_lsb) + insn_lsb;
199
200         return (insert_bits(insn, v, insn_msb, insn_lsb));
201 }
202
203 /*
204  * The RISC-V ISA is designed so that all of immediate values are
205  * sign-extended.
206  * An immediate value is sometimes generated at runtime by adding
207  * 12bit sign integer and 20bit signed integer. This requests 20bit
208  * immediate value to be ajusted if the MSB of the 12bit immediate
209  * value is asserted (sign-extended value is treated as negative value).
210  *
211  * For example, 0x123800 can be calculated by adding upper 20 bit of
212  * 0x124000 and sign-extended 12bit immediate whose bit pattern is
213  * 0x800 as follows:
214  *   0x123800
215  *     = 0x123000 + 0x800
216  *     = (0x123000 + 0x1000) + (-0x1000 + 0x800)
217  *     = (0x123000 + 0x1000) + (0xff...ff800)
218  *     = 0x124000            + sign-extention(0x800)
219  */
220 static uint32_t
221 calc_hi20_imm(uint32_t value)
222 {
223         /*
224          * There is the arithmetical hack that can remove conditional
225          * statement. But I implement it in straightforward way.
226          */
227         if ((value & 0x800) != 0)
228                 value += 0x1000;
229         return (value & ~0xfff);
230 }
231
232 static const struct type2str_ent t2s[] = {
233         { R_RISCV_NONE,         "R_RISCV_NONE"          },
234         { R_RISCV_64,           "R_RISCV_64"            },
235         { R_RISCV_JUMP_SLOT,    "R_RISCV_JUMP_SLOT"     },
236         { R_RISCV_RELATIVE,     "R_RISCV_RELATIVE"      },
237         { R_RISCV_JAL,          "R_RISCV_JAL"           },
238         { R_RISCV_CALL,         "R_RISCV_CALL"          },
239         { R_RISCV_PCREL_HI20,   "R_RISCV_PCREL_HI20"    },
240         { R_RISCV_PCREL_LO12_I, "R_RISCV_PCREL_LO12_I"  },
241         { R_RISCV_PCREL_LO12_S, "R_RISCV_PCREL_LO12_S"  },
242         { R_RISCV_HI20,         "R_RISCV_HI20"          },
243         { R_RISCV_LO12_I,       "R_RISCV_LO12_I"        },
244         { R_RISCV_LO12_S,       "R_RISCV_LO12_S"        },
245 };
246
247 static const char *
248 reloctype_to_str(int type)
249 {
250         int i;
251
252         for (i = 0; i < sizeof(t2s) / sizeof(t2s[0]); ++i) {
253                 if (type == t2s[i].type)
254                         return t2s[i].str;
255         }
256
257         return "*unknown*";
258 }
259
260 bool
261 elf_is_ifunc_reloc(Elf_Size r_info __unused)
262 {
263
264         return (false);
265 }
266
267 /*
268  * Currently kernel loadable module for RISCV is compiled with -fPIC option.
269  * (see also additional CFLAGS definition for RISCV in sys/conf/kmod.mk)
270  * Only R_RISCV_64, R_RISCV_JUMP_SLOT and RISCV_RELATIVE are emitted in
271  * the module. Other relocations will be processed when kernel loadable
272  * modules are built in non-PIC.
273  *
274  * FIXME: only RISCV64 is supported.
275  */
276 static int
277 elf_reloc_internal(linker_file_t lf, Elf_Addr relocbase, const void *data,
278     int type, int local, elf_lookup_fn lookup)
279 {
280         Elf_Size rtype, symidx;
281         const Elf_Rela *rela;
282         Elf_Addr val, addr;
283         Elf64_Addr *where;
284         Elf_Addr addend;
285         uint32_t before32_1;
286         uint32_t before32;
287         uint64_t before64;
288         uint32_t *insn32p;
289         uint32_t imm20;
290         int error;
291
292         switch (type) {
293         case ELF_RELOC_RELA:
294                 rela = (const Elf_Rela *)data;
295                 where = (Elf_Addr *)(relocbase + rela->r_offset);
296                 insn32p = (uint32_t *)where;
297                 addend = rela->r_addend;
298                 rtype = ELF_R_TYPE(rela->r_info);
299                 symidx = ELF_R_SYM(rela->r_info);
300                 break;
301         default:
302                 printf("%s:%d unknown reloc type %d\n",
303                     __FUNCTION__, __LINE__, type);
304                 return (-1);
305         }
306
307         switch (rtype) {
308         case R_RISCV_NONE:
309                 break;
310
311         case R_RISCV_64:
312         case R_RISCV_JUMP_SLOT:
313                 error = lookup(lf, symidx, 1, &addr);
314                 if (error != 0)
315                         return (-1);
316
317                 val = addr;
318                 before64 = *where;
319                 if (*where != val)
320                         *where = val;
321                 if (debug_kld)
322                         printf("%p %c %-24s %016lx -> %016lx\n", where,
323                             (local ? 'l' : 'g'), reloctype_to_str(rtype),
324                             before64, *where);
325                 break;
326
327         case R_RISCV_RELATIVE:
328                 before64 = *where;
329                 *where = elf_relocaddr(lf, relocbase + addend);
330                 if (debug_kld)
331                         printf("%p %c %-24s %016lx -> %016lx\n", where,
332                             (local ? 'l' : 'g'), reloctype_to_str(rtype),
333                             before64, *where);
334                 break;
335
336         case R_RISCV_JAL:
337                 error = lookup(lf, symidx, 1, &addr);
338                 if (error != 0)
339                         return (-1);
340
341                 val = addr - (Elf_Addr)where;
342                 if (val <= -(1UL << 20) || (1UL << 20) <= val) {
343                         printf("kldload: huge offset against R_RISCV_JAL\n");
344                         return (-1);
345                 }
346
347                 before32 = *insn32p;
348                 *insn32p = insert_imm(*insn32p, val, 20, 20, 31);
349                 *insn32p = insert_imm(*insn32p, val, 10,  1, 21);
350                 *insn32p = insert_imm(*insn32p, val, 11, 11, 20);
351                 *insn32p = insert_imm(*insn32p, val, 19, 12, 12);
352                 if (debug_kld)
353                         printf("%p %c %-24s %08x -> %08x\n", where,
354                             (local ? 'l' : 'g'), reloctype_to_str(rtype),
355                             before32, *insn32p);
356                 break;
357
358         case R_RISCV_CALL:
359                 /*
360                  * R_RISCV_CALL relocates 8-byte region that consists
361                  * of the sequence of AUIPC and JALR.
362                  */
363                 /* Calculate and check the pc relative offset. */
364                 error = lookup(lf, symidx, 1, &addr);
365                 if (error != 0)
366                         return (-1);
367
368                 val = addr - (Elf_Addr)where;
369                 if (val <= -(1UL << 32) || (1UL << 32) <= val) {
370                         printf("kldload: huge offset against R_RISCV_CALL\n");
371                         return (-1);
372                 }
373
374                 /* Relocate AUIPC. */
375                 before32 = insn32p[0];
376                 imm20 = calc_hi20_imm(val);
377                 insn32p[0] = insert_imm(insn32p[0], imm20, 31, 12, 12);
378
379                 /* Relocate JALR. */
380                 before32_1 = insn32p[1];
381                 insn32p[1] = insert_imm(insn32p[1], val, 11,  0, 20);
382                 if (debug_kld)
383                         printf("%p %c %-24s %08x %08x -> %08x %08x\n", where,
384                             (local ? 'l' : 'g'), reloctype_to_str(rtype),
385                             before32, insn32p[0], before32_1, insn32p[1]);
386                 break;
387
388         case R_RISCV_PCREL_HI20:
389                 error = lookup(lf, symidx, 1, &addr);
390                 if (error != 0)
391                         return (-1);
392
393                 val = addr - (Elf_Addr)where;
394                 insn32p = (uint32_t *)where;
395                 before32 = *insn32p;
396                 imm20 = calc_hi20_imm(val);
397                 *insn32p = insert_imm(*insn32p, imm20, 31, 12, 12);
398                 if (debug_kld)
399                         printf("%p %c %-24s %08x -> %08x\n", where,
400                             (local ? 'l' : 'g'), reloctype_to_str(rtype),
401                             before32, *insn32p);
402                 break;
403
404         case R_RISCV_PCREL_LO12_I:
405                 error = lookup(lf, symidx, 1, &addr);
406                 if (error != 0)
407                         return (-1);
408
409                 val = addr - (Elf_Addr)where;
410                 insn32p = (uint32_t *)where;
411                 before32 = *insn32p;
412                 *insn32p = insert_imm(*insn32p, addr, 11,  0, 20);
413                 if (debug_kld)
414                         printf("%p %c %-24s %08x -> %08x\n", where,
415                             (local ? 'l' : 'g'), reloctype_to_str(rtype),
416                             before32, *insn32p);
417                 break;
418
419         case R_RISCV_PCREL_LO12_S:
420                 error = lookup(lf, symidx, 1, &addr);
421                 if (error != 0)
422                         return (-1);
423
424                 val = addr - (Elf_Addr)where;
425                 insn32p = (uint32_t *)where;
426                 before32 = *insn32p;
427                 *insn32p = insert_imm(*insn32p, addr, 11,  5, 25);
428                 *insn32p = insert_imm(*insn32p, addr,  4,  0,  7);
429                 if (debug_kld)
430                         printf("%p %c %-24s %08x -> %08x\n", where,
431                             (local ? 'l' : 'g'), reloctype_to_str(rtype),
432                             before32, *insn32p);
433                 break;
434
435         case R_RISCV_HI20:
436                 error = lookup(lf, symidx, 1, &addr);
437                 if (error != 0)
438                         return (-1);
439
440                 val = addr;
441                 insn32p = (uint32_t *)where;
442                 before32 = *insn32p;
443                 imm20 = calc_hi20_imm(val);
444                 *insn32p = insert_imm(*insn32p, imm20, 31, 12, 12);
445                 if (debug_kld)
446                         printf("%p %c %-24s %08x -> %08x\n", where,
447                             (local ? 'l' : 'g'), reloctype_to_str(rtype),
448                             before32, *insn32p);
449                 break;
450
451         case R_RISCV_LO12_I:
452                 error = lookup(lf, symidx, 1, &addr);
453                 if (error != 0)
454                         return (-1);
455
456                 val = addr;
457                 insn32p = (uint32_t *)where;
458                 before32 = *insn32p;
459                 *insn32p = insert_imm(*insn32p, addr, 11,  0, 20);
460                 if (debug_kld)
461                         printf("%p %c %-24s %08x -> %08x\n", where,
462                             (local ? 'l' : 'g'), reloctype_to_str(rtype),
463                             before32, *insn32p);
464                 break;
465
466         case R_RISCV_LO12_S:
467                 error = lookup(lf, symidx, 1, &addr);
468                 if (error != 0)
469                         return (-1);
470
471                 val = addr;
472                 insn32p = (uint32_t *)where;
473                 before32 = *insn32p;
474                 *insn32p = insert_imm(*insn32p, addr, 11,  5, 25);
475                 *insn32p = insert_imm(*insn32p, addr,  4,  0,  7);
476                 if (debug_kld)
477                         printf("%p %c %-24s %08x -> %08x\n", where,
478                             (local ? 'l' : 'g'), reloctype_to_str(rtype),
479                             before32, *insn32p);
480                 break;
481
482         default:
483                 printf("kldload: unexpected relocation type %ld, "
484                     "symbol index %ld\n", rtype, symidx);
485                 return (-1);
486         }
487
488         return (0);
489 }
490
491 int
492 elf_reloc(linker_file_t lf, Elf_Addr relocbase, const void *data, int type,
493     elf_lookup_fn lookup)
494 {
495
496         return (elf_reloc_internal(lf, relocbase, data, type, 0, lookup));
497 }
498
499 int
500 elf_reloc_local(linker_file_t lf, Elf_Addr relocbase, const void *data,
501     int type, elf_lookup_fn lookup)
502 {
503
504         return (elf_reloc_internal(lf, relocbase, data, type, 1, lookup));
505 }
506
507 int
508 elf_cpu_load_file(linker_file_t lf __unused)
509 {
510
511         return (0);
512 }
513
514 int
515 elf_cpu_unload_file(linker_file_t lf __unused)
516 {
517
518         return (0);
519 }
520
521 int
522 elf_cpu_parse_dynamic(caddr_t loadbase __unused, Elf_Dyn *dynamic __unused)
523 {
524
525         return (0);
526 }