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