Path: blob/master/tools/testing/selftests/kvm/lib/elf.c
38235 views
// SPDX-License-Identifier: GPL-2.0-only1/*2* tools/testing/selftests/kvm/lib/elf.c3*4* Copyright (C) 2018, Google LLC.5*/67#include "test_util.h"89#include <bits/endian.h>10#include <linux/elf.h>1112#include "kvm_util.h"1314static void elfhdr_get(const char *filename, Elf64_Ehdr *hdrp)15{16off_t offset_rv;1718/* Open the ELF file. */19int fd;20fd = open(filename, O_RDONLY);21TEST_ASSERT(fd >= 0, "Failed to open ELF file,\n"22" filename: %s\n"23" rv: %i errno: %i", filename, fd, errno);2425/* Read in and validate ELF Identification Record.26* The ELF Identification record is the first 16 (EI_NIDENT) bytes27* of the ELF header, which is at the beginning of the ELF file.28* For now it is only safe to read the first EI_NIDENT bytes. Once29* read and validated, the value of e_ehsize can be used to determine30* the real size of the ELF header.31*/32unsigned char ident[EI_NIDENT];33test_read(fd, ident, sizeof(ident));34TEST_ASSERT((ident[EI_MAG0] == ELFMAG0) && (ident[EI_MAG1] == ELFMAG1)35&& (ident[EI_MAG2] == ELFMAG2) && (ident[EI_MAG3] == ELFMAG3),36"ELF MAGIC Mismatch,\n"37" filename: %s\n"38" ident[EI_MAG0 - EI_MAG3]: %02x %02x %02x %02x\n"39" Expected: %02x %02x %02x %02x",40filename,41ident[EI_MAG0], ident[EI_MAG1], ident[EI_MAG2], ident[EI_MAG3],42ELFMAG0, ELFMAG1, ELFMAG2, ELFMAG3);43TEST_ASSERT(ident[EI_CLASS] == ELFCLASS64,44"Current implementation only able to handle ELFCLASS64,\n"45" filename: %s\n"46" ident[EI_CLASS]: %02x\n"47" expected: %02x",48filename,49ident[EI_CLASS], ELFCLASS64);50TEST_ASSERT(((BYTE_ORDER == LITTLE_ENDIAN)51&& (ident[EI_DATA] == ELFDATA2LSB))52|| ((BYTE_ORDER == BIG_ENDIAN)53&& (ident[EI_DATA] == ELFDATA2MSB)), "Current "54"implementation only able to handle\n"55"cases where the host and ELF file endianness\n"56"is the same:\n"57" host BYTE_ORDER: %u\n"58" host LITTLE_ENDIAN: %u\n"59" host BIG_ENDIAN: %u\n"60" ident[EI_DATA]: %u\n"61" ELFDATA2LSB: %u\n"62" ELFDATA2MSB: %u",63BYTE_ORDER, LITTLE_ENDIAN, BIG_ENDIAN,64ident[EI_DATA], ELFDATA2LSB, ELFDATA2MSB);65TEST_ASSERT(ident[EI_VERSION] == EV_CURRENT,66"Current implementation only able to handle current "67"ELF version,\n"68" filename: %s\n"69" ident[EI_VERSION]: %02x\n"70" expected: %02x",71filename, ident[EI_VERSION], EV_CURRENT);7273/* Read in the ELF header.74* With the ELF Identification portion of the ELF header75* validated, especially that the value at EI_VERSION is76* as expected, it is now safe to read the entire ELF header.77*/78offset_rv = lseek(fd, 0, SEEK_SET);79TEST_ASSERT(offset_rv == 0, "Seek to ELF header failed,\n"80" rv: %zi expected: %i", offset_rv, 0);81test_read(fd, hdrp, sizeof(*hdrp));82TEST_ASSERT(hdrp->e_phentsize == sizeof(Elf64_Phdr),83"Unexpected physical header size,\n"84" hdrp->e_phentsize: %x\n"85" expected: %zx",86hdrp->e_phentsize, sizeof(Elf64_Phdr));87TEST_ASSERT(hdrp->e_shentsize == sizeof(Elf64_Shdr),88"Unexpected section header size,\n"89" hdrp->e_shentsize: %x\n"90" expected: %zx",91hdrp->e_shentsize, sizeof(Elf64_Shdr));92close(fd);93}9495/* VM ELF Load96*97* Input Args:98* filename - Path to ELF file99*100* Output Args: None101*102* Input/Output Args:103* vm - Pointer to opaque type that describes the VM.104*105* Return: None, TEST_ASSERT failures for all error conditions106*107* Loads the program image of the ELF file specified by filename,108* into the virtual address space of the VM pointed to by vm. On entry109* the VM needs to not be using any of the virtual address space used110* by the image and it needs to have sufficient available physical pages, to111* back the virtual pages used to load the image.112*/113void kvm_vm_elf_load(struct kvm_vm *vm, const char *filename)114{115off_t offset, offset_rv;116Elf64_Ehdr hdr;117118/* Open the ELF file. */119int fd;120fd = open(filename, O_RDONLY);121TEST_ASSERT(fd >= 0, "Failed to open ELF file,\n"122" filename: %s\n"123" rv: %i errno: %i", filename, fd, errno);124125/* Read in the ELF header. */126elfhdr_get(filename, &hdr);127128/* For each program header.129* The following ELF header members specify the location130* and size of the program headers:131*132* e_phoff - File offset to start of program headers133* e_phentsize - Size of each program header134* e_phnum - Number of program header entries135*/136for (unsigned int n1 = 0; n1 < hdr.e_phnum; n1++) {137/* Seek to the beginning of the program header. */138offset = hdr.e_phoff + (n1 * hdr.e_phentsize);139offset_rv = lseek(fd, offset, SEEK_SET);140TEST_ASSERT(offset_rv == offset,141"Failed to seek to beginning of program header %u,\n"142" filename: %s\n"143" rv: %jd errno: %i",144n1, filename, (intmax_t) offset_rv, errno);145146/* Read in the program header. */147Elf64_Phdr phdr;148test_read(fd, &phdr, sizeof(phdr));149150/* Skip if this header doesn't describe a loadable segment. */151if (phdr.p_type != PT_LOAD)152continue;153154/* Allocate memory for this segment within the VM. */155TEST_ASSERT(phdr.p_memsz > 0, "Unexpected loadable segment "156"memsize of 0,\n"157" phdr index: %u p_memsz: 0x%" PRIx64,158n1, (uint64_t) phdr.p_memsz);159vm_vaddr_t seg_vstart = align_down(phdr.p_vaddr, vm->page_size);160vm_vaddr_t seg_vend = phdr.p_vaddr + phdr.p_memsz - 1;161seg_vend |= vm->page_size - 1;162size_t seg_size = seg_vend - seg_vstart + 1;163164vm_vaddr_t vaddr = __vm_vaddr_alloc(vm, seg_size, seg_vstart,165MEM_REGION_CODE);166TEST_ASSERT(vaddr == seg_vstart, "Unable to allocate "167"virtual memory for segment at requested min addr,\n"168" segment idx: %u\n"169" seg_vstart: 0x%lx\n"170" vaddr: 0x%lx",171n1, seg_vstart, vaddr);172memset(addr_gva2hva(vm, vaddr), 0, seg_size);173/* TODO(lhuemill): Set permissions of each memory segment174* based on the least-significant 3 bits of phdr.p_flags.175*/176177/* Load portion of initial state that is contained within178* the ELF file.179*/180if (phdr.p_filesz) {181offset_rv = lseek(fd, phdr.p_offset, SEEK_SET);182TEST_ASSERT(offset_rv == phdr.p_offset,183"Seek to program segment offset failed,\n"184" program header idx: %u errno: %i\n"185" offset_rv: 0x%jx\n"186" expected: 0x%jx",187n1, errno, (intmax_t) offset_rv,188(intmax_t) phdr.p_offset);189test_read(fd, addr_gva2hva(vm, phdr.p_vaddr),190phdr.p_filesz);191}192}193close(fd);194}195196197