root/tools/testing/selftests/kvm/lib/elf.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. elfhdr_get
  2. kvm_vm_elf_load

   1 // SPDX-License-Identifier: GPL-2.0-only
   2 /*
   3  * tools/testing/selftests/kvm/lib/elf.c
   4  *
   5  * Copyright (C) 2018, Google LLC.
   6  */
   7 
   8 #include "test_util.h"
   9 
  10 #include <bits/endian.h>
  11 #include <linux/elf.h>
  12 
  13 #include "kvm_util.h"
  14 #include "kvm_util_internal.h"
  15 
  16 static void elfhdr_get(const char *filename, Elf64_Ehdr *hdrp)
  17 {
  18         off_t offset_rv;
  19 
  20         /* Open the ELF file. */
  21         int fd;
  22         fd = open(filename, O_RDONLY);
  23         TEST_ASSERT(fd >= 0, "Failed to open ELF file,\n"
  24                 "  filename: %s\n"
  25                 "  rv: %i errno: %i", filename, fd, errno);
  26 
  27         /* Read in and validate ELF Identification Record.
  28          * The ELF Identification record is the first 16 (EI_NIDENT) bytes
  29          * of the ELF header, which is at the beginning of the ELF file.
  30          * For now it is only safe to read the first EI_NIDENT bytes.  Once
  31          * read and validated, the value of e_ehsize can be used to determine
  32          * the real size of the ELF header.
  33          */
  34         unsigned char ident[EI_NIDENT];
  35         test_read(fd, ident, sizeof(ident));
  36         TEST_ASSERT((ident[EI_MAG0] == ELFMAG0) && (ident[EI_MAG1] == ELFMAG1)
  37                 && (ident[EI_MAG2] == ELFMAG2) && (ident[EI_MAG3] == ELFMAG3),
  38                 "ELF MAGIC Mismatch,\n"
  39                 "  filename: %s\n"
  40                 "  ident[EI_MAG0 - EI_MAG3]: %02x %02x %02x %02x\n"
  41                 "  Expected: %02x %02x %02x %02x",
  42                 filename,
  43                 ident[EI_MAG0], ident[EI_MAG1], ident[EI_MAG2], ident[EI_MAG3],
  44                 ELFMAG0, ELFMAG1, ELFMAG2, ELFMAG3);
  45         TEST_ASSERT(ident[EI_CLASS] == ELFCLASS64,
  46                 "Current implementation only able to handle ELFCLASS64,\n"
  47                 "  filename: %s\n"
  48                 "  ident[EI_CLASS]: %02x\n"
  49                 "  expected: %02x",
  50                 filename,
  51                 ident[EI_CLASS], ELFCLASS64);
  52         TEST_ASSERT(((BYTE_ORDER == LITTLE_ENDIAN)
  53                         && (ident[EI_DATA] == ELFDATA2LSB))
  54                 || ((BYTE_ORDER == BIG_ENDIAN)
  55                         && (ident[EI_DATA] == ELFDATA2MSB)), "Current "
  56                 "implementation only able to handle\n"
  57                 "cases where the host and ELF file endianness\n"
  58                 "is the same:\n"
  59                 "  host BYTE_ORDER: %u\n"
  60                 "  host LITTLE_ENDIAN: %u\n"
  61                 "  host BIG_ENDIAN: %u\n"
  62                 "  ident[EI_DATA]: %u\n"
  63                 "  ELFDATA2LSB: %u\n"
  64                 "  ELFDATA2MSB: %u",
  65                 BYTE_ORDER, LITTLE_ENDIAN, BIG_ENDIAN,
  66                 ident[EI_DATA], ELFDATA2LSB, ELFDATA2MSB);
  67         TEST_ASSERT(ident[EI_VERSION] == EV_CURRENT,
  68                 "Current implementation only able to handle current "
  69                 "ELF version,\n"
  70                 "  filename: %s\n"
  71                 "  ident[EI_VERSION]: %02x\n"
  72                 "  expected: %02x",
  73                 filename, ident[EI_VERSION], EV_CURRENT);
  74 
  75         /* Read in the ELF header.
  76          * With the ELF Identification portion of the ELF header
  77          * validated, especially that the value at EI_VERSION is
  78          * as expected, it is now safe to read the entire ELF header.
  79          */
  80         offset_rv = lseek(fd, 0, SEEK_SET);
  81         TEST_ASSERT(offset_rv == 0, "Seek to ELF header failed,\n"
  82                 "  rv: %zi expected: %i", offset_rv, 0);
  83         test_read(fd, hdrp, sizeof(*hdrp));
  84         TEST_ASSERT(hdrp->e_phentsize == sizeof(Elf64_Phdr),
  85                 "Unexpected physical header size,\n"
  86                 "  hdrp->e_phentsize: %x\n"
  87                 "  expected: %zx",
  88                 hdrp->e_phentsize, sizeof(Elf64_Phdr));
  89         TEST_ASSERT(hdrp->e_shentsize == sizeof(Elf64_Shdr),
  90                 "Unexpected section header size,\n"
  91                 "  hdrp->e_shentsize: %x\n"
  92                 "  expected: %zx",
  93                 hdrp->e_shentsize, sizeof(Elf64_Shdr));
  94 }
  95 
  96 /* VM ELF Load
  97  *
  98  * Input Args:
  99  *   filename - Path to ELF file
 100  *
 101  * Output Args: None
 102  *
 103  * Input/Output Args:
 104  *   vm - Pointer to opaque type that describes the VM.
 105  *
 106  * Return: None, TEST_ASSERT failures for all error conditions
 107  *
 108  * Loads the program image of the ELF file specified by filename,
 109  * into the virtual address space of the VM pointed to by vm.  On entry
 110  * the VM needs to not be using any of the virtual address space used
 111  * by the image and it needs to have sufficient available physical pages, to
 112  * back the virtual pages used to load the image.
 113  */
 114 void kvm_vm_elf_load(struct kvm_vm *vm, const char *filename,
 115         uint32_t data_memslot, uint32_t pgd_memslot)
 116 {
 117         off_t offset, offset_rv;
 118         Elf64_Ehdr hdr;
 119 
 120         /* Open the ELF file. */
 121         int fd;
 122         fd = open(filename, O_RDONLY);
 123         TEST_ASSERT(fd >= 0, "Failed to open ELF file,\n"
 124                 "  filename: %s\n"
 125                 "  rv: %i errno: %i", filename, fd, errno);
 126 
 127         /* Read in the ELF header. */
 128         elfhdr_get(filename, &hdr);
 129 
 130         /* For each program header.
 131          * The following ELF header members specify the location
 132          * and size of the program headers:
 133          *
 134          *   e_phoff - File offset to start of program headers
 135          *   e_phentsize - Size of each program header
 136          *   e_phnum - Number of program header entries
 137          */
 138         for (unsigned int n1 = 0; n1 < hdr.e_phnum; n1++) {
 139                 /* Seek to the beginning of the program header. */
 140                 offset = hdr.e_phoff + (n1 * hdr.e_phentsize);
 141                 offset_rv = lseek(fd, offset, SEEK_SET);
 142                 TEST_ASSERT(offset_rv == offset,
 143                         "Failed to seek to begining of program header %u,\n"
 144                         "  filename: %s\n"
 145                         "  rv: %jd errno: %i",
 146                         n1, filename, (intmax_t) offset_rv, errno);
 147 
 148                 /* Read in the program header. */
 149                 Elf64_Phdr phdr;
 150                 test_read(fd, &phdr, sizeof(phdr));
 151 
 152                 /* Skip if this header doesn't describe a loadable segment. */
 153                 if (phdr.p_type != PT_LOAD)
 154                         continue;
 155 
 156                 /* Allocate memory for this segment within the VM. */
 157                 TEST_ASSERT(phdr.p_memsz > 0, "Unexpected loadable segment "
 158                         "memsize of 0,\n"
 159                         "  phdr index: %u p_memsz: 0x%" PRIx64,
 160                         n1, (uint64_t) phdr.p_memsz);
 161                 vm_vaddr_t seg_vstart = phdr.p_vaddr;
 162                 seg_vstart &= ~(vm_vaddr_t)(vm->page_size - 1);
 163                 vm_vaddr_t seg_vend = phdr.p_vaddr + phdr.p_memsz - 1;
 164                 seg_vend |= vm->page_size - 1;
 165                 size_t seg_size = seg_vend - seg_vstart + 1;
 166 
 167                 vm_vaddr_t vaddr = vm_vaddr_alloc(vm, seg_size, seg_vstart,
 168                         data_memslot, pgd_memslot);
 169                 TEST_ASSERT(vaddr == seg_vstart, "Unable to allocate "
 170                         "virtual memory for segment at requested min addr,\n"
 171                         "  segment idx: %u\n"
 172                         "  seg_vstart: 0x%lx\n"
 173                         "  vaddr: 0x%lx",
 174                         n1, seg_vstart, vaddr);
 175                 memset(addr_gva2hva(vm, vaddr), 0, seg_size);
 176                 /* TODO(lhuemill): Set permissions of each memory segment
 177                  * based on the least-significant 3 bits of phdr.p_flags.
 178                  */
 179 
 180                 /* Load portion of initial state that is contained within
 181                  * the ELF file.
 182                  */
 183                 if (phdr.p_filesz) {
 184                         offset_rv = lseek(fd, phdr.p_offset, SEEK_SET);
 185                         TEST_ASSERT(offset_rv == phdr.p_offset,
 186                                 "Seek to program segment offset failed,\n"
 187                                 "  program header idx: %u errno: %i\n"
 188                                 "  offset_rv: 0x%jx\n"
 189                                 "  expected: 0x%jx\n",
 190                                 n1, errno, (intmax_t) offset_rv,
 191                                 (intmax_t) phdr.p_offset);
 192                         test_read(fd, addr_gva2hva(vm, phdr.p_vaddr),
 193                                 phdr.p_filesz);
 194                 }
 195         }
 196 }

/* [<][>][^][v][top][bottom][index][help] */