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