xref: /openbmc/linux/tools/testing/selftests/kvm/lib/elf.c (revision 2bad466c)
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 
15 static void elfhdr_get(const char *filename, Elf64_Ehdr *hdrp)
16 {
17 	off_t offset_rv;
18 
19 	/* Open the ELF file. */
20 	int fd;
21 	fd = open(filename, O_RDONLY);
22 	TEST_ASSERT(fd >= 0, "Failed to open ELF file,\n"
23 		"  filename: %s\n"
24 		"  rv: %i errno: %i", filename, fd, errno);
25 
26 	/* Read in and validate ELF Identification Record.
27 	 * The ELF Identification record is the first 16 (EI_NIDENT) bytes
28 	 * of the ELF header, which is at the beginning of the ELF file.
29 	 * For now it is only safe to read the first EI_NIDENT bytes.  Once
30 	 * read and validated, the value of e_ehsize can be used to determine
31 	 * the real size of the ELF header.
32 	 */
33 	unsigned char ident[EI_NIDENT];
34 	test_read(fd, ident, sizeof(ident));
35 	TEST_ASSERT((ident[EI_MAG0] == ELFMAG0) && (ident[EI_MAG1] == ELFMAG1)
36 		&& (ident[EI_MAG2] == ELFMAG2) && (ident[EI_MAG3] == ELFMAG3),
37 		"ELF MAGIC Mismatch,\n"
38 		"  filename: %s\n"
39 		"  ident[EI_MAG0 - EI_MAG3]: %02x %02x %02x %02x\n"
40 		"  Expected: %02x %02x %02x %02x",
41 		filename,
42 		ident[EI_MAG0], ident[EI_MAG1], ident[EI_MAG2], ident[EI_MAG3],
43 		ELFMAG0, ELFMAG1, ELFMAG2, ELFMAG3);
44 	TEST_ASSERT(ident[EI_CLASS] == ELFCLASS64,
45 		"Current implementation only able to handle ELFCLASS64,\n"
46 		"  filename: %s\n"
47 		"  ident[EI_CLASS]: %02x\n"
48 		"  expected: %02x",
49 		filename,
50 		ident[EI_CLASS], ELFCLASS64);
51 	TEST_ASSERT(((BYTE_ORDER == LITTLE_ENDIAN)
52 			&& (ident[EI_DATA] == ELFDATA2LSB))
53 		|| ((BYTE_ORDER == BIG_ENDIAN)
54 			&& (ident[EI_DATA] == ELFDATA2MSB)), "Current "
55 		"implementation only able to handle\n"
56 		"cases where the host and ELF file endianness\n"
57 		"is the same:\n"
58 		"  host BYTE_ORDER: %u\n"
59 		"  host LITTLE_ENDIAN: %u\n"
60 		"  host BIG_ENDIAN: %u\n"
61 		"  ident[EI_DATA]: %u\n"
62 		"  ELFDATA2LSB: %u\n"
63 		"  ELFDATA2MSB: %u",
64 		BYTE_ORDER, LITTLE_ENDIAN, BIG_ENDIAN,
65 		ident[EI_DATA], ELFDATA2LSB, ELFDATA2MSB);
66 	TEST_ASSERT(ident[EI_VERSION] == EV_CURRENT,
67 		"Current implementation only able to handle current "
68 		"ELF version,\n"
69 		"  filename: %s\n"
70 		"  ident[EI_VERSION]: %02x\n"
71 		"  expected: %02x",
72 		filename, ident[EI_VERSION], EV_CURRENT);
73 
74 	/* Read in the ELF header.
75 	 * With the ELF Identification portion of the ELF header
76 	 * validated, especially that the value at EI_VERSION is
77 	 * as expected, it is now safe to read the entire ELF header.
78 	 */
79 	offset_rv = lseek(fd, 0, SEEK_SET);
80 	TEST_ASSERT(offset_rv == 0, "Seek to ELF header failed,\n"
81 		"  rv: %zi expected: %i", offset_rv, 0);
82 	test_read(fd, hdrp, sizeof(*hdrp));
83 	TEST_ASSERT(hdrp->e_phentsize == sizeof(Elf64_Phdr),
84 		"Unexpected physical header size,\n"
85 		"  hdrp->e_phentsize: %x\n"
86 		"  expected: %zx",
87 		hdrp->e_phentsize, sizeof(Elf64_Phdr));
88 	TEST_ASSERT(hdrp->e_shentsize == sizeof(Elf64_Shdr),
89 		"Unexpected section header size,\n"
90 		"  hdrp->e_shentsize: %x\n"
91 		"  expected: %zx",
92 		hdrp->e_shentsize, sizeof(Elf64_Shdr));
93 	close(fd);
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 {
116 	off_t offset, offset_rv;
117 	Elf64_Ehdr hdr;
118 
119 	/* Open the ELF file. */
120 	int fd;
121 	fd = open(filename, O_RDONLY);
122 	TEST_ASSERT(fd >= 0, "Failed to open ELF file,\n"
123 		"  filename: %s\n"
124 		"  rv: %i errno: %i", filename, fd, errno);
125 
126 	/* Read in the ELF header. */
127 	elfhdr_get(filename, &hdr);
128 
129 	/* For each program header.
130 	 * The following ELF header members specify the location
131 	 * and size of the program headers:
132 	 *
133 	 *   e_phoff - File offset to start of program headers
134 	 *   e_phentsize - Size of each program header
135 	 *   e_phnum - Number of program header entries
136 	 */
137 	for (unsigned int n1 = 0; n1 < hdr.e_phnum; n1++) {
138 		/* Seek to the beginning of the program header. */
139 		offset = hdr.e_phoff + (n1 * hdr.e_phentsize);
140 		offset_rv = lseek(fd, offset, SEEK_SET);
141 		TEST_ASSERT(offset_rv == offset,
142 			"Failed to seek to beginning of program header %u,\n"
143 			"  filename: %s\n"
144 			"  rv: %jd errno: %i",
145 			n1, filename, (intmax_t) offset_rv, errno);
146 
147 		/* Read in the program header. */
148 		Elf64_Phdr phdr;
149 		test_read(fd, &phdr, sizeof(phdr));
150 
151 		/* Skip if this header doesn't describe a loadable segment. */
152 		if (phdr.p_type != PT_LOAD)
153 			continue;
154 
155 		/* Allocate memory for this segment within the VM. */
156 		TEST_ASSERT(phdr.p_memsz > 0, "Unexpected loadable segment "
157 			"memsize of 0,\n"
158 			"  phdr index: %u p_memsz: 0x%" PRIx64,
159 			n1, (uint64_t) phdr.p_memsz);
160 		vm_vaddr_t seg_vstart = align_down(phdr.p_vaddr, vm->page_size);
161 		vm_vaddr_t seg_vend = phdr.p_vaddr + phdr.p_memsz - 1;
162 		seg_vend |= vm->page_size - 1;
163 		size_t seg_size = seg_vend - seg_vstart + 1;
164 
165 		vm_vaddr_t vaddr = __vm_vaddr_alloc(vm, seg_size, seg_vstart,
166 						    MEM_REGION_CODE);
167 		TEST_ASSERT(vaddr == seg_vstart, "Unable to allocate "
168 			"virtual memory for segment at requested min addr,\n"
169 			"  segment idx: %u\n"
170 			"  seg_vstart: 0x%lx\n"
171 			"  vaddr: 0x%lx",
172 			n1, seg_vstart, vaddr);
173 		memset(addr_gva2hva(vm, vaddr), 0, seg_size);
174 		/* TODO(lhuemill): Set permissions of each memory segment
175 		 * based on the least-significant 3 bits of phdr.p_flags.
176 		 */
177 
178 		/* Load portion of initial state that is contained within
179 		 * the ELF file.
180 		 */
181 		if (phdr.p_filesz) {
182 			offset_rv = lseek(fd, phdr.p_offset, SEEK_SET);
183 			TEST_ASSERT(offset_rv == phdr.p_offset,
184 				"Seek to program segment offset failed,\n"
185 				"  program header idx: %u errno: %i\n"
186 				"  offset_rv: 0x%jx\n"
187 				"  expected: 0x%jx\n",
188 				n1, errno, (intmax_t) offset_rv,
189 				(intmax_t) phdr.p_offset);
190 			test_read(fd, addr_gva2hva(vm, phdr.p_vaddr),
191 				phdr.p_filesz);
192 		}
193 	}
194 	close(fd);
195 }
196