1bdc37934SDmitry Chagin /*- 2bdc37934SDmitry Chagin * Copyright (c) 2013 Dmitry Chagin 3bdc37934SDmitry Chagin * All rights reserved. 4bdc37934SDmitry Chagin * 5bdc37934SDmitry Chagin * Redistribution and use in source and binary forms, with or without 6bdc37934SDmitry Chagin * modification, are permitted provided that the following conditions 7bdc37934SDmitry Chagin * are met: 8bdc37934SDmitry Chagin * 1. Redistributions of source code must retain the above copyright 9bdc37934SDmitry Chagin * notice, this list of conditions and the following disclaimer 10bdc37934SDmitry Chagin * in this position and unchanged. 11bdc37934SDmitry Chagin * 2. Redistributions in binary form must reproduce the above copyright 12bdc37934SDmitry Chagin * notice, this list of conditions and the following disclaimer in the 13bdc37934SDmitry Chagin * documentation and/or other materials provided with the distribution. 14bdc37934SDmitry Chagin * 15bdc37934SDmitry Chagin * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 16bdc37934SDmitry Chagin * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 17bdc37934SDmitry Chagin * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 18bdc37934SDmitry Chagin * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 19bdc37934SDmitry Chagin * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 20bdc37934SDmitry Chagin * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 21bdc37934SDmitry Chagin * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 22bdc37934SDmitry Chagin * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 23bdc37934SDmitry Chagin * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 24bdc37934SDmitry Chagin * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 25bdc37934SDmitry Chagin */ 26bdc37934SDmitry Chagin 27bdc37934SDmitry Chagin #include <sys/cdefs.h> 28bdc37934SDmitry Chagin __FBSDID("$FreeBSD$"); 29bdc37934SDmitry Chagin 30bdc37934SDmitry Chagin #include "opt_compat.h" 31bdc37934SDmitry Chagin 3236204c30SDmitry Chagin #if defined(__i386__) || (defined(__amd64__) && defined(COMPAT_LINUX32)) 33bdc37934SDmitry Chagin #define __ELF_WORD_SIZE 32 3436204c30SDmitry Chagin #else 3536204c30SDmitry Chagin #define __ELF_WORD_SIZE 64 3636204c30SDmitry Chagin #endif 37bdc37934SDmitry Chagin 38bdc37934SDmitry Chagin #include <sys/param.h> 39bdc37934SDmitry Chagin #include <sys/systm.h> 40bdc37934SDmitry Chagin #include <sys/elf.h> 41bdc37934SDmitry Chagin #include <sys/kernel.h> 42bdc37934SDmitry Chagin #include <sys/lock.h> 43bdc37934SDmitry Chagin #include <sys/rwlock.h> 44bdc37934SDmitry Chagin #include <sys/queue.h> 45bdc37934SDmitry Chagin #include <sys/sysent.h> 46bdc37934SDmitry Chagin 47bdc37934SDmitry Chagin #include <vm/vm.h> 48bdc37934SDmitry Chagin #include <vm/vm_param.h> 49bdc37934SDmitry Chagin #include <vm/pmap.h> 50bdc37934SDmitry Chagin #include <vm/vm_extern.h> 51bdc37934SDmitry Chagin #include <vm/vm_kern.h> 52bdc37934SDmitry Chagin #include <vm/vm_map.h> 53bdc37934SDmitry Chagin #include <vm/vm_object.h> 54bdc37934SDmitry Chagin #include <vm/vm_page.h> 55bdc37934SDmitry Chagin #include <vm/vm_pager.h> 56bdc37934SDmitry Chagin 57bdc37934SDmitry Chagin #include <compat/linux/linux_vdso.h> 58bdc37934SDmitry Chagin 59bdc37934SDmitry Chagin SLIST_HEAD(, linux_vdso_sym) __elfN(linux_vdso_syms) = 60bdc37934SDmitry Chagin SLIST_HEAD_INITIALIZER(__elfN(linux_vdso_syms)); 61bdc37934SDmitry Chagin 62bdc37934SDmitry Chagin static int __elfN(symtabindex); 63bdc37934SDmitry Chagin static int __elfN(symstrindex); 64bdc37934SDmitry Chagin 65bdc37934SDmitry Chagin static void 66bdc37934SDmitry Chagin __elfN(linux_vdso_lookup)(Elf_Ehdr *, struct linux_vdso_sym *); 67bdc37934SDmitry Chagin 68bdc37934SDmitry Chagin void 69bdc37934SDmitry Chagin __elfN(linux_vdso_sym_init)(struct linux_vdso_sym *s) 70bdc37934SDmitry Chagin { 71bdc37934SDmitry Chagin 72bdc37934SDmitry Chagin SLIST_INSERT_HEAD(&__elfN(linux_vdso_syms), s, sym); 73bdc37934SDmitry Chagin } 74bdc37934SDmitry Chagin 75bdc37934SDmitry Chagin vm_object_t 76bdc37934SDmitry Chagin __elfN(linux_shared_page_init)(char **mapping) 77bdc37934SDmitry Chagin { 78bdc37934SDmitry Chagin vm_page_t m; 79bdc37934SDmitry Chagin vm_object_t obj; 80bdc37934SDmitry Chagin vm_offset_t addr; 81bdc37934SDmitry Chagin 82bdc37934SDmitry Chagin obj = vm_pager_allocate(OBJT_PHYS, 0, PAGE_SIZE, 83bdc37934SDmitry Chagin VM_PROT_DEFAULT, 0, NULL); 84bdc37934SDmitry Chagin VM_OBJECT_WLOCK(obj); 854504268aSJeff Roberson m = vm_page_grab(obj, 0, VM_ALLOC_ZERO); 86bdc37934SDmitry Chagin VM_OBJECT_WUNLOCK(obj); 874504268aSJeff Roberson vm_page_valid(m); 884504268aSJeff Roberson vm_page_xunbusy(m); 89bdc37934SDmitry Chagin addr = kva_alloc(PAGE_SIZE); 90bdc37934SDmitry Chagin pmap_qenter(addr, &m, 1); 91bdc37934SDmitry Chagin *mapping = (char *)addr; 92bdc37934SDmitry Chagin return (obj); 93bdc37934SDmitry Chagin } 94bdc37934SDmitry Chagin 95bdc37934SDmitry Chagin void 96*0fc8a796SMark Johnston __elfN(linux_shared_page_fini)(vm_object_t obj, void *mapping) 97bdc37934SDmitry Chagin { 98*0fc8a796SMark Johnston vm_offset_t va; 99bdc37934SDmitry Chagin 100*0fc8a796SMark Johnston va = (vm_offset_t)mapping; 101*0fc8a796SMark Johnston pmap_qremove(va, 1); 102*0fc8a796SMark Johnston kva_free(va, PAGE_SIZE); 103bdc37934SDmitry Chagin vm_object_deallocate(obj); 104bdc37934SDmitry Chagin } 105bdc37934SDmitry Chagin 106bdc37934SDmitry Chagin void 107bdc37934SDmitry Chagin __elfN(linux_vdso_fixup)(struct sysentvec *sv) 108bdc37934SDmitry Chagin { 109bdc37934SDmitry Chagin Elf_Ehdr *ehdr; 110bdc37934SDmitry Chagin Elf_Shdr *shdr; 111bdc37934SDmitry Chagin int i; 112bdc37934SDmitry Chagin 113bdc37934SDmitry Chagin ehdr = (Elf_Ehdr *) sv->sv_sigcode; 114bdc37934SDmitry Chagin 115bdc37934SDmitry Chagin if (!IS_ELF(*ehdr) || 116bdc37934SDmitry Chagin ehdr->e_ident[EI_CLASS] != ELF_TARG_CLASS || 117bdc37934SDmitry Chagin ehdr->e_ident[EI_DATA] != ELF_TARG_DATA || 118bdc37934SDmitry Chagin ehdr->e_ident[EI_VERSION] != EV_CURRENT || 119bdc37934SDmitry Chagin ehdr->e_shoff == 0 || 120bdc37934SDmitry Chagin ehdr->e_shentsize != sizeof(Elf_Shdr)) 121bdc37934SDmitry Chagin panic("Linux invalid vdso header.\n"); 122bdc37934SDmitry Chagin 123bdc37934SDmitry Chagin if (ehdr->e_type != ET_DYN) 124bdc37934SDmitry Chagin panic("Linux invalid vdso header.\n"); 125bdc37934SDmitry Chagin 126bdc37934SDmitry Chagin shdr = (Elf_Shdr *) ((caddr_t)ehdr + ehdr->e_shoff); 127bdc37934SDmitry Chagin 128bdc37934SDmitry Chagin __elfN(symtabindex) = -1; 129bdc37934SDmitry Chagin __elfN(symstrindex) = -1; 130bdc37934SDmitry Chagin for (i = 0; i < ehdr->e_shnum; i++) { 131bdc37934SDmitry Chagin if (shdr[i].sh_size == 0) 132bdc37934SDmitry Chagin continue; 133bdc37934SDmitry Chagin if (shdr[i].sh_type == SHT_DYNSYM) { 134bdc37934SDmitry Chagin __elfN(symtabindex) = i; 135bdc37934SDmitry Chagin __elfN(symstrindex) = shdr[i].sh_link; 136bdc37934SDmitry Chagin } 137bdc37934SDmitry Chagin } 138bdc37934SDmitry Chagin 139bdc37934SDmitry Chagin if (__elfN(symtabindex) == -1 || __elfN(symstrindex) == -1) 140bdc37934SDmitry Chagin panic("Linux invalid vdso header.\n"); 141bdc37934SDmitry Chagin 142bdc37934SDmitry Chagin ehdr->e_ident[EI_OSABI] = ELFOSABI_LINUX; 143bdc37934SDmitry Chagin } 144bdc37934SDmitry Chagin 145bdc37934SDmitry Chagin void 146c151945cSDmitry Chagin __elfN(linux_vdso_reloc)(struct sysentvec *sv) 147bdc37934SDmitry Chagin { 148bdc37934SDmitry Chagin struct linux_vdso_sym *lsym; 149bdc37934SDmitry Chagin Elf_Ehdr *ehdr; 150bdc37934SDmitry Chagin Elf_Phdr *phdr; 151bdc37934SDmitry Chagin Elf_Shdr *shdr; 152bdc37934SDmitry Chagin Elf_Dyn *dyn; 153bdc37934SDmitry Chagin Elf_Sym *sym; 1545bb676adSDmitry Chagin int i, j, symcnt; 155bdc37934SDmitry Chagin 156bdc37934SDmitry Chagin ehdr = (Elf_Ehdr *) sv->sv_sigcode; 157bdc37934SDmitry Chagin 158bdc37934SDmitry Chagin /* Adjust our so relative to the sigcode_base */ 159c151945cSDmitry Chagin if (sv->sv_shared_page_base != 0) { 160c151945cSDmitry Chagin ehdr->e_entry += sv->sv_shared_page_base; 161bdc37934SDmitry Chagin phdr = (Elf_Phdr *)((caddr_t)ehdr + ehdr->e_phoff); 162bdc37934SDmitry Chagin 163bdc37934SDmitry Chagin /* phdrs */ 164bdc37934SDmitry Chagin for (i = 0; i < ehdr->e_phnum; i++) { 165c151945cSDmitry Chagin phdr[i].p_vaddr += sv->sv_shared_page_base; 166bdc37934SDmitry Chagin if (phdr[i].p_type != PT_DYNAMIC) 167bdc37934SDmitry Chagin continue; 168bdc37934SDmitry Chagin dyn = (Elf_Dyn *)((caddr_t)ehdr + phdr[i].p_offset); 169bdc37934SDmitry Chagin for(; dyn->d_tag != DT_NULL; dyn++) { 170bdc37934SDmitry Chagin switch (dyn->d_tag) { 171bdc37934SDmitry Chagin case DT_PLTGOT: 172bdc37934SDmitry Chagin case DT_HASH: 173bdc37934SDmitry Chagin case DT_STRTAB: 174bdc37934SDmitry Chagin case DT_SYMTAB: 175bdc37934SDmitry Chagin case DT_RELA: 176bdc37934SDmitry Chagin case DT_INIT: 177bdc37934SDmitry Chagin case DT_FINI: 178bdc37934SDmitry Chagin case DT_REL: 179bdc37934SDmitry Chagin case DT_DEBUG: 180bdc37934SDmitry Chagin case DT_JMPREL: 181bdc37934SDmitry Chagin case DT_VERSYM: 182bdc37934SDmitry Chagin case DT_VERDEF: 183bdc37934SDmitry Chagin case DT_VERNEED: 184bdc37934SDmitry Chagin case DT_ADDRRNGLO ... DT_ADDRRNGHI: 185c151945cSDmitry Chagin dyn->d_un.d_ptr += sv->sv_shared_page_base; 186bdc37934SDmitry Chagin break; 187bdc37934SDmitry Chagin case DT_ENCODING ... DT_LOOS-1: 188bdc37934SDmitry Chagin case DT_LOOS ... DT_HIOS: 189bdc37934SDmitry Chagin if (dyn->d_tag >= DT_ENCODING && 190bdc37934SDmitry Chagin (dyn->d_tag & 1) == 0) 191c151945cSDmitry Chagin dyn->d_un.d_ptr += sv->sv_shared_page_base; 192bdc37934SDmitry Chagin break; 193bdc37934SDmitry Chagin default: 194bdc37934SDmitry Chagin break; 195bdc37934SDmitry Chagin } 196bdc37934SDmitry Chagin } 197bdc37934SDmitry Chagin } 198bdc37934SDmitry Chagin 199bdc37934SDmitry Chagin /* sections */ 200bdc37934SDmitry Chagin shdr = (Elf_Shdr *)((caddr_t)ehdr + ehdr->e_shoff); 201bdc37934SDmitry Chagin for(i = 0; i < ehdr->e_shnum; i++) { 202bdc37934SDmitry Chagin if (!(shdr[i].sh_flags & SHF_ALLOC)) 203bdc37934SDmitry Chagin continue; 204c151945cSDmitry Chagin shdr[i].sh_addr += sv->sv_shared_page_base; 205bdc37934SDmitry Chagin if (shdr[i].sh_type != SHT_SYMTAB && 206bdc37934SDmitry Chagin shdr[i].sh_type != SHT_DYNSYM) 207bdc37934SDmitry Chagin continue; 208bdc37934SDmitry Chagin 209bdc37934SDmitry Chagin sym = (Elf_Sym *)((caddr_t)ehdr + shdr[i].sh_offset); 210bdc37934SDmitry Chagin symcnt = shdr[i].sh_size / sizeof(*sym); 211bdc37934SDmitry Chagin 2125bb676adSDmitry Chagin for(j = 0; j < symcnt; j++, sym++) { 213bdc37934SDmitry Chagin if (sym->st_shndx == SHN_UNDEF || 214bdc37934SDmitry Chagin sym->st_shndx == SHN_ABS) 215bdc37934SDmitry Chagin continue; 216c151945cSDmitry Chagin sym->st_value += sv->sv_shared_page_base; 217bdc37934SDmitry Chagin } 218bdc37934SDmitry Chagin } 219bdc37934SDmitry Chagin } 220bdc37934SDmitry Chagin 221bdc37934SDmitry Chagin SLIST_FOREACH(lsym, &__elfN(linux_vdso_syms), sym) 222bdc37934SDmitry Chagin __elfN(linux_vdso_lookup)(ehdr, lsym); 223bdc37934SDmitry Chagin } 224bdc37934SDmitry Chagin 225bdc37934SDmitry Chagin static void 226bdc37934SDmitry Chagin __elfN(linux_vdso_lookup)(Elf_Ehdr *ehdr, struct linux_vdso_sym *vsym) 227bdc37934SDmitry Chagin { 228bdc37934SDmitry Chagin vm_offset_t strtab, symname; 229bdc37934SDmitry Chagin uint32_t symcnt; 230bdc37934SDmitry Chagin Elf_Shdr *shdr; 231bdc37934SDmitry Chagin int i; 232bdc37934SDmitry Chagin 233bdc37934SDmitry Chagin shdr = (Elf_Shdr *) ((caddr_t)ehdr + ehdr->e_shoff); 234bdc37934SDmitry Chagin 235bdc37934SDmitry Chagin strtab = (vm_offset_t)((caddr_t)ehdr + 236bdc37934SDmitry Chagin shdr[__elfN(symstrindex)].sh_offset); 237bdc37934SDmitry Chagin Elf_Sym *sym = (Elf_Sym *)((caddr_t)ehdr + 238bdc37934SDmitry Chagin shdr[__elfN(symtabindex)].sh_offset); 239bdc37934SDmitry Chagin symcnt = shdr[__elfN(symtabindex)].sh_size / sizeof(*sym); 240bdc37934SDmitry Chagin 241bdc37934SDmitry Chagin for (i = 0; i < symcnt; ++i, ++sym) { 242bdc37934SDmitry Chagin symname = strtab + sym->st_name; 243bdc37934SDmitry Chagin if (strncmp(vsym->symname, (char *)symname, vsym->size) == 0) { 244bdc37934SDmitry Chagin *vsym->ptr = (uintptr_t)sym->st_value; 245bdc37934SDmitry Chagin break; 246bdc37934SDmitry Chagin } 247bdc37934SDmitry Chagin } 248bdc37934SDmitry Chagin } 249