xref: /openbmc/linux/tools/testing/selftests/kvm/lib/elf.c (revision bf109933)
17a338472SThomas Gleixner // SPDX-License-Identifier: GPL-2.0-only
26089ae0bSPaolo Bonzini /*
36089ae0bSPaolo Bonzini  * tools/testing/selftests/kvm/lib/elf.c
46089ae0bSPaolo Bonzini  *
56089ae0bSPaolo Bonzini  * Copyright (C) 2018, Google LLC.
66089ae0bSPaolo Bonzini  */
76089ae0bSPaolo Bonzini 
86089ae0bSPaolo Bonzini #include "test_util.h"
96089ae0bSPaolo Bonzini 
106089ae0bSPaolo Bonzini #include <bits/endian.h>
116089ae0bSPaolo Bonzini #include <linux/elf.h>
126089ae0bSPaolo Bonzini 
136089ae0bSPaolo Bonzini #include "kvm_util.h"
146089ae0bSPaolo Bonzini 
elfhdr_get(const char * filename,Elf64_Ehdr * hdrp)156089ae0bSPaolo Bonzini static void elfhdr_get(const char *filename, Elf64_Ehdr *hdrp)
166089ae0bSPaolo Bonzini {
176089ae0bSPaolo Bonzini 	off_t offset_rv;
186089ae0bSPaolo Bonzini 
196089ae0bSPaolo Bonzini 	/* Open the ELF file. */
206089ae0bSPaolo Bonzini 	int fd;
216089ae0bSPaolo Bonzini 	fd = open(filename, O_RDONLY);
226089ae0bSPaolo Bonzini 	TEST_ASSERT(fd >= 0, "Failed to open ELF file,\n"
236089ae0bSPaolo Bonzini 		"  filename: %s\n"
246089ae0bSPaolo Bonzini 		"  rv: %i errno: %i", filename, fd, errno);
256089ae0bSPaolo Bonzini 
266089ae0bSPaolo Bonzini 	/* Read in and validate ELF Identification Record.
276089ae0bSPaolo Bonzini 	 * The ELF Identification record is the first 16 (EI_NIDENT) bytes
286089ae0bSPaolo Bonzini 	 * of the ELF header, which is at the beginning of the ELF file.
296089ae0bSPaolo Bonzini 	 * For now it is only safe to read the first EI_NIDENT bytes.  Once
306089ae0bSPaolo Bonzini 	 * read and validated, the value of e_ehsize can be used to determine
316089ae0bSPaolo Bonzini 	 * the real size of the ELF header.
326089ae0bSPaolo Bonzini 	 */
336089ae0bSPaolo Bonzini 	unsigned char ident[EI_NIDENT];
346089ae0bSPaolo Bonzini 	test_read(fd, ident, sizeof(ident));
356089ae0bSPaolo Bonzini 	TEST_ASSERT((ident[EI_MAG0] == ELFMAG0) && (ident[EI_MAG1] == ELFMAG1)
366089ae0bSPaolo Bonzini 		&& (ident[EI_MAG2] == ELFMAG2) && (ident[EI_MAG3] == ELFMAG3),
376089ae0bSPaolo Bonzini 		"ELF MAGIC Mismatch,\n"
386089ae0bSPaolo Bonzini 		"  filename: %s\n"
396089ae0bSPaolo Bonzini 		"  ident[EI_MAG0 - EI_MAG3]: %02x %02x %02x %02x\n"
406089ae0bSPaolo Bonzini 		"  Expected: %02x %02x %02x %02x",
416089ae0bSPaolo Bonzini 		filename,
426089ae0bSPaolo Bonzini 		ident[EI_MAG0], ident[EI_MAG1], ident[EI_MAG2], ident[EI_MAG3],
436089ae0bSPaolo Bonzini 		ELFMAG0, ELFMAG1, ELFMAG2, ELFMAG3);
446089ae0bSPaolo Bonzini 	TEST_ASSERT(ident[EI_CLASS] == ELFCLASS64,
456089ae0bSPaolo Bonzini 		"Current implementation only able to handle ELFCLASS64,\n"
466089ae0bSPaolo Bonzini 		"  filename: %s\n"
476089ae0bSPaolo Bonzini 		"  ident[EI_CLASS]: %02x\n"
486089ae0bSPaolo Bonzini 		"  expected: %02x",
496089ae0bSPaolo Bonzini 		filename,
506089ae0bSPaolo Bonzini 		ident[EI_CLASS], ELFCLASS64);
516089ae0bSPaolo Bonzini 	TEST_ASSERT(((BYTE_ORDER == LITTLE_ENDIAN)
526089ae0bSPaolo Bonzini 			&& (ident[EI_DATA] == ELFDATA2LSB))
536089ae0bSPaolo Bonzini 		|| ((BYTE_ORDER == BIG_ENDIAN)
546089ae0bSPaolo Bonzini 			&& (ident[EI_DATA] == ELFDATA2MSB)), "Current "
556089ae0bSPaolo Bonzini 		"implementation only able to handle\n"
566089ae0bSPaolo Bonzini 		"cases where the host and ELF file endianness\n"
576089ae0bSPaolo Bonzini 		"is the same:\n"
586089ae0bSPaolo Bonzini 		"  host BYTE_ORDER: %u\n"
596089ae0bSPaolo Bonzini 		"  host LITTLE_ENDIAN: %u\n"
606089ae0bSPaolo Bonzini 		"  host BIG_ENDIAN: %u\n"
616089ae0bSPaolo Bonzini 		"  ident[EI_DATA]: %u\n"
626089ae0bSPaolo Bonzini 		"  ELFDATA2LSB: %u\n"
636089ae0bSPaolo Bonzini 		"  ELFDATA2MSB: %u",
646089ae0bSPaolo Bonzini 		BYTE_ORDER, LITTLE_ENDIAN, BIG_ENDIAN,
656089ae0bSPaolo Bonzini 		ident[EI_DATA], ELFDATA2LSB, ELFDATA2MSB);
666089ae0bSPaolo Bonzini 	TEST_ASSERT(ident[EI_VERSION] == EV_CURRENT,
676089ae0bSPaolo Bonzini 		"Current implementation only able to handle current "
686089ae0bSPaolo Bonzini 		"ELF version,\n"
696089ae0bSPaolo Bonzini 		"  filename: %s\n"
706089ae0bSPaolo Bonzini 		"  ident[EI_VERSION]: %02x\n"
716089ae0bSPaolo Bonzini 		"  expected: %02x",
726089ae0bSPaolo Bonzini 		filename, ident[EI_VERSION], EV_CURRENT);
736089ae0bSPaolo Bonzini 
746089ae0bSPaolo Bonzini 	/* Read in the ELF header.
756089ae0bSPaolo Bonzini 	 * With the ELF Identification portion of the ELF header
766089ae0bSPaolo Bonzini 	 * validated, especially that the value at EI_VERSION is
776089ae0bSPaolo Bonzini 	 * as expected, it is now safe to read the entire ELF header.
786089ae0bSPaolo Bonzini 	 */
796089ae0bSPaolo Bonzini 	offset_rv = lseek(fd, 0, SEEK_SET);
806089ae0bSPaolo Bonzini 	TEST_ASSERT(offset_rv == 0, "Seek to ELF header failed,\n"
816089ae0bSPaolo Bonzini 		"  rv: %zi expected: %i", offset_rv, 0);
826089ae0bSPaolo Bonzini 	test_read(fd, hdrp, sizeof(*hdrp));
836089ae0bSPaolo Bonzini 	TEST_ASSERT(hdrp->e_phentsize == sizeof(Elf64_Phdr),
846089ae0bSPaolo Bonzini 		"Unexpected physical header size,\n"
856089ae0bSPaolo Bonzini 		"  hdrp->e_phentsize: %x\n"
866089ae0bSPaolo Bonzini 		"  expected: %zx",
876089ae0bSPaolo Bonzini 		hdrp->e_phentsize, sizeof(Elf64_Phdr));
886089ae0bSPaolo Bonzini 	TEST_ASSERT(hdrp->e_shentsize == sizeof(Elf64_Shdr),
896089ae0bSPaolo Bonzini 		"Unexpected section header size,\n"
906089ae0bSPaolo Bonzini 		"  hdrp->e_shentsize: %x\n"
916089ae0bSPaolo Bonzini 		"  expected: %zx",
926089ae0bSPaolo Bonzini 		hdrp->e_shentsize, sizeof(Elf64_Shdr));
93*bf109933SReiji Watanabe 	close(fd);
946089ae0bSPaolo Bonzini }
956089ae0bSPaolo Bonzini 
966089ae0bSPaolo Bonzini /* VM ELF Load
976089ae0bSPaolo Bonzini  *
986089ae0bSPaolo Bonzini  * Input Args:
996089ae0bSPaolo Bonzini  *   filename - Path to ELF file
1006089ae0bSPaolo Bonzini  *
1016089ae0bSPaolo Bonzini  * Output Args: None
1026089ae0bSPaolo Bonzini  *
1036089ae0bSPaolo Bonzini  * Input/Output Args:
1046089ae0bSPaolo Bonzini  *   vm - Pointer to opaque type that describes the VM.
1056089ae0bSPaolo Bonzini  *
1066089ae0bSPaolo Bonzini  * Return: None, TEST_ASSERT failures for all error conditions
1076089ae0bSPaolo Bonzini  *
1086089ae0bSPaolo Bonzini  * Loads the program image of the ELF file specified by filename,
1096089ae0bSPaolo Bonzini  * into the virtual address space of the VM pointed to by vm.  On entry
1106089ae0bSPaolo Bonzini  * the VM needs to not be using any of the virtual address space used
1116089ae0bSPaolo Bonzini  * by the image and it needs to have sufficient available physical pages, to
1126089ae0bSPaolo Bonzini  * back the virtual pages used to load the image.
1136089ae0bSPaolo Bonzini  */
kvm_vm_elf_load(struct kvm_vm * vm,const char * filename)1147a4f1a75SSean Christopherson void kvm_vm_elf_load(struct kvm_vm *vm, const char *filename)
1156089ae0bSPaolo Bonzini {
1166089ae0bSPaolo Bonzini 	off_t offset, offset_rv;
1176089ae0bSPaolo Bonzini 	Elf64_Ehdr hdr;
1186089ae0bSPaolo Bonzini 
1196089ae0bSPaolo Bonzini 	/* Open the ELF file. */
1206089ae0bSPaolo Bonzini 	int fd;
1216089ae0bSPaolo Bonzini 	fd = open(filename, O_RDONLY);
1226089ae0bSPaolo Bonzini 	TEST_ASSERT(fd >= 0, "Failed to open ELF file,\n"
1236089ae0bSPaolo Bonzini 		"  filename: %s\n"
1246089ae0bSPaolo Bonzini 		"  rv: %i errno: %i", filename, fd, errno);
1256089ae0bSPaolo Bonzini 
1266089ae0bSPaolo Bonzini 	/* Read in the ELF header. */
1276089ae0bSPaolo Bonzini 	elfhdr_get(filename, &hdr);
1286089ae0bSPaolo Bonzini 
1296089ae0bSPaolo Bonzini 	/* For each program header.
1306089ae0bSPaolo Bonzini 	 * The following ELF header members specify the location
1316089ae0bSPaolo Bonzini 	 * and size of the program headers:
1326089ae0bSPaolo Bonzini 	 *
1336089ae0bSPaolo Bonzini 	 *   e_phoff - File offset to start of program headers
1346089ae0bSPaolo Bonzini 	 *   e_phentsize - Size of each program header
1356089ae0bSPaolo Bonzini 	 *   e_phnum - Number of program header entries
1366089ae0bSPaolo Bonzini 	 */
1376089ae0bSPaolo Bonzini 	for (unsigned int n1 = 0; n1 < hdr.e_phnum; n1++) {
1386089ae0bSPaolo Bonzini 		/* Seek to the beginning of the program header. */
1396089ae0bSPaolo Bonzini 		offset = hdr.e_phoff + (n1 * hdr.e_phentsize);
1406089ae0bSPaolo Bonzini 		offset_rv = lseek(fd, offset, SEEK_SET);
1416089ae0bSPaolo Bonzini 		TEST_ASSERT(offset_rv == offset,
1429a6418daSColin Ian King 			"Failed to seek to beginning of program header %u,\n"
1436089ae0bSPaolo Bonzini 			"  filename: %s\n"
1446089ae0bSPaolo Bonzini 			"  rv: %jd errno: %i",
1456089ae0bSPaolo Bonzini 			n1, filename, (intmax_t) offset_rv, errno);
1466089ae0bSPaolo Bonzini 
1476089ae0bSPaolo Bonzini 		/* Read in the program header. */
1486089ae0bSPaolo Bonzini 		Elf64_Phdr phdr;
1496089ae0bSPaolo Bonzini 		test_read(fd, &phdr, sizeof(phdr));
1506089ae0bSPaolo Bonzini 
1516089ae0bSPaolo Bonzini 		/* Skip if this header doesn't describe a loadable segment. */
1526089ae0bSPaolo Bonzini 		if (phdr.p_type != PT_LOAD)
1536089ae0bSPaolo Bonzini 			continue;
1546089ae0bSPaolo Bonzini 
1556089ae0bSPaolo Bonzini 		/* Allocate memory for this segment within the VM. */
1566089ae0bSPaolo Bonzini 		TEST_ASSERT(phdr.p_memsz > 0, "Unexpected loadable segment "
1576089ae0bSPaolo Bonzini 			"memsize of 0,\n"
1586089ae0bSPaolo Bonzini 			"  phdr index: %u p_memsz: 0x%" PRIx64,
1596089ae0bSPaolo Bonzini 			n1, (uint64_t) phdr.p_memsz);
160c071ff41SSean Christopherson 		vm_vaddr_t seg_vstart = align_down(phdr.p_vaddr, vm->page_size);
1616089ae0bSPaolo Bonzini 		vm_vaddr_t seg_vend = phdr.p_vaddr + phdr.p_memsz - 1;
1626089ae0bSPaolo Bonzini 		seg_vend |= vm->page_size - 1;
1636089ae0bSPaolo Bonzini 		size_t seg_size = seg_vend - seg_vstart + 1;
1646089ae0bSPaolo Bonzini 
1651446e331SRicardo Koller 		vm_vaddr_t vaddr = __vm_vaddr_alloc(vm, seg_size, seg_vstart,
1661446e331SRicardo Koller 						    MEM_REGION_CODE);
1676089ae0bSPaolo Bonzini 		TEST_ASSERT(vaddr == seg_vstart, "Unable to allocate "
1686089ae0bSPaolo Bonzini 			"virtual memory for segment at requested min addr,\n"
1696089ae0bSPaolo Bonzini 			"  segment idx: %u\n"
1706089ae0bSPaolo Bonzini 			"  seg_vstart: 0x%lx\n"
1716089ae0bSPaolo Bonzini 			"  vaddr: 0x%lx",
1726089ae0bSPaolo Bonzini 			n1, seg_vstart, vaddr);
1736089ae0bSPaolo Bonzini 		memset(addr_gva2hva(vm, vaddr), 0, seg_size);
1746089ae0bSPaolo Bonzini 		/* TODO(lhuemill): Set permissions of each memory segment
1756089ae0bSPaolo Bonzini 		 * based on the least-significant 3 bits of phdr.p_flags.
1766089ae0bSPaolo Bonzini 		 */
1776089ae0bSPaolo Bonzini 
1786089ae0bSPaolo Bonzini 		/* Load portion of initial state that is contained within
1796089ae0bSPaolo Bonzini 		 * the ELF file.
1806089ae0bSPaolo Bonzini 		 */
1816089ae0bSPaolo Bonzini 		if (phdr.p_filesz) {
1826089ae0bSPaolo Bonzini 			offset_rv = lseek(fd, phdr.p_offset, SEEK_SET);
1836089ae0bSPaolo Bonzini 			TEST_ASSERT(offset_rv == phdr.p_offset,
1846089ae0bSPaolo Bonzini 				"Seek to program segment offset failed,\n"
1856089ae0bSPaolo Bonzini 				"  program header idx: %u errno: %i\n"
1866089ae0bSPaolo Bonzini 				"  offset_rv: 0x%jx\n"
1876089ae0bSPaolo Bonzini 				"  expected: 0x%jx\n",
1886089ae0bSPaolo Bonzini 				n1, errno, (intmax_t) offset_rv,
1896089ae0bSPaolo Bonzini 				(intmax_t) phdr.p_offset);
1906089ae0bSPaolo Bonzini 			test_read(fd, addr_gva2hva(vm, phdr.p_vaddr),
1916089ae0bSPaolo Bonzini 				phdr.p_filesz);
1926089ae0bSPaolo Bonzini 		}
1936089ae0bSPaolo Bonzini 	}
194*bf109933SReiji Watanabe 	close(fd);
1956089ae0bSPaolo Bonzini }
196