The Design and Implementation of the FreeBSD Operating System, Second Edition
Now available: The Design and Implementation of the FreeBSD Operating System (Second Edition)


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]

FreeBSD/Linux Kernel Cross Reference
sys/riscv/riscv/elf_machdep.c

Version: -  FREEBSD  -  FREEBSD-13-STABLE  -  FREEBSD-13-0  -  FREEBSD-12-STABLE  -  FREEBSD-12-0  -  FREEBSD-11-STABLE  -  FREEBSD-11-0  -  FREEBSD-10-STABLE  -  FREEBSD-10-0  -  FREEBSD-9-STABLE  -  FREEBSD-9-0  -  FREEBSD-8-STABLE  -  FREEBSD-8-0  -  FREEBSD-7-STABLE  -  FREEBSD-7-0  -  FREEBSD-6-STABLE  -  FREEBSD-6-0  -  FREEBSD-5-STABLE  -  FREEBSD-5-0  -  FREEBSD-4-STABLE  -  FREEBSD-3-STABLE  -  FREEBSD22  -  l41  -  OPENBSD  -  linux-2.6  -  MK84  -  PLAN9  -  xnu-8792 
SearchContext: -  none  -  3  -  10 

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

Cache object: bf612d9f9d990c8ab6cbeb7a328a6749


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]


This page is part of the FreeBSD/Linux Linux Kernel Cross-Reference, and was automatically generated using a modified version of the LXR engine.