Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-only
0002 /*
0003  * tools/testing/selftests/kvm/lib/elf.c
0004  *
0005  * Copyright (C) 2018, Google LLC.
0006  */
0007 
0008 #include "test_util.h"
0009 
0010 #include <bits/endian.h>
0011 #include <linux/elf.h>
0012 
0013 #include "kvm_util.h"
0014 
0015 static void elfhdr_get(const char *filename, Elf64_Ehdr *hdrp)
0016 {
0017     off_t offset_rv;
0018 
0019     /* Open the ELF file. */
0020     int fd;
0021     fd = open(filename, O_RDONLY);
0022     TEST_ASSERT(fd >= 0, "Failed to open ELF file,\n"
0023         "  filename: %s\n"
0024         "  rv: %i errno: %i", filename, fd, errno);
0025 
0026     /* Read in and validate ELF Identification Record.
0027      * The ELF Identification record is the first 16 (EI_NIDENT) bytes
0028      * of the ELF header, which is at the beginning of the ELF file.
0029      * For now it is only safe to read the first EI_NIDENT bytes.  Once
0030      * read and validated, the value of e_ehsize can be used to determine
0031      * the real size of the ELF header.
0032      */
0033     unsigned char ident[EI_NIDENT];
0034     test_read(fd, ident, sizeof(ident));
0035     TEST_ASSERT((ident[EI_MAG0] == ELFMAG0) && (ident[EI_MAG1] == ELFMAG1)
0036         && (ident[EI_MAG2] == ELFMAG2) && (ident[EI_MAG3] == ELFMAG3),
0037         "ELF MAGIC Mismatch,\n"
0038         "  filename: %s\n"
0039         "  ident[EI_MAG0 - EI_MAG3]: %02x %02x %02x %02x\n"
0040         "  Expected: %02x %02x %02x %02x",
0041         filename,
0042         ident[EI_MAG0], ident[EI_MAG1], ident[EI_MAG2], ident[EI_MAG3],
0043         ELFMAG0, ELFMAG1, ELFMAG2, ELFMAG3);
0044     TEST_ASSERT(ident[EI_CLASS] == ELFCLASS64,
0045         "Current implementation only able to handle ELFCLASS64,\n"
0046         "  filename: %s\n"
0047         "  ident[EI_CLASS]: %02x\n"
0048         "  expected: %02x",
0049         filename,
0050         ident[EI_CLASS], ELFCLASS64);
0051     TEST_ASSERT(((BYTE_ORDER == LITTLE_ENDIAN)
0052             && (ident[EI_DATA] == ELFDATA2LSB))
0053         || ((BYTE_ORDER == BIG_ENDIAN)
0054             && (ident[EI_DATA] == ELFDATA2MSB)), "Current "
0055         "implementation only able to handle\n"
0056         "cases where the host and ELF file endianness\n"
0057         "is the same:\n"
0058         "  host BYTE_ORDER: %u\n"
0059         "  host LITTLE_ENDIAN: %u\n"
0060         "  host BIG_ENDIAN: %u\n"
0061         "  ident[EI_DATA]: %u\n"
0062         "  ELFDATA2LSB: %u\n"
0063         "  ELFDATA2MSB: %u",
0064         BYTE_ORDER, LITTLE_ENDIAN, BIG_ENDIAN,
0065         ident[EI_DATA], ELFDATA2LSB, ELFDATA2MSB);
0066     TEST_ASSERT(ident[EI_VERSION] == EV_CURRENT,
0067         "Current implementation only able to handle current "
0068         "ELF version,\n"
0069         "  filename: %s\n"
0070         "  ident[EI_VERSION]: %02x\n"
0071         "  expected: %02x",
0072         filename, ident[EI_VERSION], EV_CURRENT);
0073 
0074     /* Read in the ELF header.
0075      * With the ELF Identification portion of the ELF header
0076      * validated, especially that the value at EI_VERSION is
0077      * as expected, it is now safe to read the entire ELF header.
0078      */
0079     offset_rv = lseek(fd, 0, SEEK_SET);
0080     TEST_ASSERT(offset_rv == 0, "Seek to ELF header failed,\n"
0081         "  rv: %zi expected: %i", offset_rv, 0);
0082     test_read(fd, hdrp, sizeof(*hdrp));
0083     TEST_ASSERT(hdrp->e_phentsize == sizeof(Elf64_Phdr),
0084         "Unexpected physical header size,\n"
0085         "  hdrp->e_phentsize: %x\n"
0086         "  expected: %zx",
0087         hdrp->e_phentsize, sizeof(Elf64_Phdr));
0088     TEST_ASSERT(hdrp->e_shentsize == sizeof(Elf64_Shdr),
0089         "Unexpected section header size,\n"
0090         "  hdrp->e_shentsize: %x\n"
0091         "  expected: %zx",
0092         hdrp->e_shentsize, sizeof(Elf64_Shdr));
0093 }
0094 
0095 /* VM ELF Load
0096  *
0097  * Input Args:
0098  *   filename - Path to ELF file
0099  *
0100  * Output Args: None
0101  *
0102  * Input/Output Args:
0103  *   vm - Pointer to opaque type that describes the VM.
0104  *
0105  * Return: None, TEST_ASSERT failures for all error conditions
0106  *
0107  * Loads the program image of the ELF file specified by filename,
0108  * into the virtual address space of the VM pointed to by vm.  On entry
0109  * the VM needs to not be using any of the virtual address space used
0110  * by the image and it needs to have sufficient available physical pages, to
0111  * back the virtual pages used to load the image.
0112  */
0113 void kvm_vm_elf_load(struct kvm_vm *vm, const char *filename)
0114 {
0115     off_t offset, offset_rv;
0116     Elf64_Ehdr hdr;
0117 
0118     /* Open the ELF file. */
0119     int fd;
0120     fd = open(filename, O_RDONLY);
0121     TEST_ASSERT(fd >= 0, "Failed to open ELF file,\n"
0122         "  filename: %s\n"
0123         "  rv: %i errno: %i", filename, fd, errno);
0124 
0125     /* Read in the ELF header. */
0126     elfhdr_get(filename, &hdr);
0127 
0128     /* For each program header.
0129      * The following ELF header members specify the location
0130      * and size of the program headers:
0131      *
0132      *   e_phoff - File offset to start of program headers
0133      *   e_phentsize - Size of each program header
0134      *   e_phnum - Number of program header entries
0135      */
0136     for (unsigned int n1 = 0; n1 < hdr.e_phnum; n1++) {
0137         /* Seek to the beginning of the program header. */
0138         offset = hdr.e_phoff + (n1 * hdr.e_phentsize);
0139         offset_rv = lseek(fd, offset, SEEK_SET);
0140         TEST_ASSERT(offset_rv == offset,
0141             "Failed to seek to begining of program header %u,\n"
0142             "  filename: %s\n"
0143             "  rv: %jd errno: %i",
0144             n1, filename, (intmax_t) offset_rv, errno);
0145 
0146         /* Read in the program header. */
0147         Elf64_Phdr phdr;
0148         test_read(fd, &phdr, sizeof(phdr));
0149 
0150         /* Skip if this header doesn't describe a loadable segment. */
0151         if (phdr.p_type != PT_LOAD)
0152             continue;
0153 
0154         /* Allocate memory for this segment within the VM. */
0155         TEST_ASSERT(phdr.p_memsz > 0, "Unexpected loadable segment "
0156             "memsize of 0,\n"
0157             "  phdr index: %u p_memsz: 0x%" PRIx64,
0158             n1, (uint64_t) phdr.p_memsz);
0159         vm_vaddr_t seg_vstart = align_down(phdr.p_vaddr, vm->page_size);
0160         vm_vaddr_t seg_vend = phdr.p_vaddr + phdr.p_memsz - 1;
0161         seg_vend |= vm->page_size - 1;
0162         size_t seg_size = seg_vend - seg_vstart + 1;
0163 
0164         vm_vaddr_t vaddr = vm_vaddr_alloc(vm, seg_size, seg_vstart);
0165         TEST_ASSERT(vaddr == seg_vstart, "Unable to allocate "
0166             "virtual memory for segment at requested min addr,\n"
0167             "  segment idx: %u\n"
0168             "  seg_vstart: 0x%lx\n"
0169             "  vaddr: 0x%lx",
0170             n1, seg_vstart, vaddr);
0171         memset(addr_gva2hva(vm, vaddr), 0, seg_size);
0172         /* TODO(lhuemill): Set permissions of each memory segment
0173          * based on the least-significant 3 bits of phdr.p_flags.
0174          */
0175 
0176         /* Load portion of initial state that is contained within
0177          * the ELF file.
0178          */
0179         if (phdr.p_filesz) {
0180             offset_rv = lseek(fd, phdr.p_offset, SEEK_SET);
0181             TEST_ASSERT(offset_rv == phdr.p_offset,
0182                 "Seek to program segment offset failed,\n"
0183                 "  program header idx: %u errno: %i\n"
0184                 "  offset_rv: 0x%jx\n"
0185                 "  expected: 0x%jx\n",
0186                 n1, errno, (intmax_t) offset_rv,
0187                 (intmax_t) phdr.p_offset);
0188             test_read(fd, addr_gva2hva(vm, phdr.p_vaddr),
0189                 phdr.p_filesz);
0190         }
0191     }
0192 }