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 #include "kvm_util_internal.h"
15
elfhdr_get(const char * filename,Elf64_Ehdr * hdrp)16 static void elfhdr_get(const char *filename, Elf64_Ehdr *hdrp)
17 {
18 off_t offset_rv;
19
20 /* Open the ELF file. */
21 int fd;
22 fd = open(filename, O_RDONLY);
23 TEST_ASSERT(fd >= 0, "Failed to open ELF file,\n"
24 " filename: %s\n"
25 " rv: %i errno: %i", filename, fd, errno);
26
27 /* Read in and validate ELF Identification Record.
28 * The ELF Identification record is the first 16 (EI_NIDENT) bytes
29 * of the ELF header, which is at the beginning of the ELF file.
30 * For now it is only safe to read the first EI_NIDENT bytes. Once
31 * read and validated, the value of e_ehsize can be used to determine
32 * the real size of the ELF header.
33 */
34 unsigned char ident[EI_NIDENT];
35 test_read(fd, ident, sizeof(ident));
36 TEST_ASSERT((ident[EI_MAG0] == ELFMAG0) && (ident[EI_MAG1] == ELFMAG1)
37 && (ident[EI_MAG2] == ELFMAG2) && (ident[EI_MAG3] == ELFMAG3),
38 "ELF MAGIC Mismatch,\n"
39 " filename: %s\n"
40 " ident[EI_MAG0 - EI_MAG3]: %02x %02x %02x %02x\n"
41 " Expected: %02x %02x %02x %02x",
42 filename,
43 ident[EI_MAG0], ident[EI_MAG1], ident[EI_MAG2], ident[EI_MAG3],
44 ELFMAG0, ELFMAG1, ELFMAG2, ELFMAG3);
45 TEST_ASSERT(ident[EI_CLASS] == ELFCLASS64,
46 "Current implementation only able to handle ELFCLASS64,\n"
47 " filename: %s\n"
48 " ident[EI_CLASS]: %02x\n"
49 " expected: %02x",
50 filename,
51 ident[EI_CLASS], ELFCLASS64);
52 TEST_ASSERT(((BYTE_ORDER == LITTLE_ENDIAN)
53 && (ident[EI_DATA] == ELFDATA2LSB))
54 || ((BYTE_ORDER == BIG_ENDIAN)
55 && (ident[EI_DATA] == ELFDATA2MSB)), "Current "
56 "implementation only able to handle\n"
57 "cases where the host and ELF file endianness\n"
58 "is the same:\n"
59 " host BYTE_ORDER: %u\n"
60 " host LITTLE_ENDIAN: %u\n"
61 " host BIG_ENDIAN: %u\n"
62 " ident[EI_DATA]: %u\n"
63 " ELFDATA2LSB: %u\n"
64 " ELFDATA2MSB: %u",
65 BYTE_ORDER, LITTLE_ENDIAN, BIG_ENDIAN,
66 ident[EI_DATA], ELFDATA2LSB, ELFDATA2MSB);
67 TEST_ASSERT(ident[EI_VERSION] == EV_CURRENT,
68 "Current implementation only able to handle current "
69 "ELF version,\n"
70 " filename: %s\n"
71 " ident[EI_VERSION]: %02x\n"
72 " expected: %02x",
73 filename, ident[EI_VERSION], EV_CURRENT);
74
75 /* Read in the ELF header.
76 * With the ELF Identification portion of the ELF header
77 * validated, especially that the value at EI_VERSION is
78 * as expected, it is now safe to read the entire ELF header.
79 */
80 offset_rv = lseek(fd, 0, SEEK_SET);
81 TEST_ASSERT(offset_rv == 0, "Seek to ELF header failed,\n"
82 " rv: %zi expected: %i", offset_rv, 0);
83 test_read(fd, hdrp, sizeof(*hdrp));
84 TEST_ASSERT(hdrp->e_phentsize == sizeof(Elf64_Phdr),
85 "Unexpected physical header size,\n"
86 " hdrp->e_phentsize: %x\n"
87 " expected: %zx",
88 hdrp->e_phentsize, sizeof(Elf64_Phdr));
89 TEST_ASSERT(hdrp->e_shentsize == sizeof(Elf64_Shdr),
90 "Unexpected section header size,\n"
91 " hdrp->e_shentsize: %x\n"
92 " expected: %zx",
93 hdrp->e_shentsize, sizeof(Elf64_Shdr));
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 */
kvm_vm_elf_load(struct kvm_vm * vm,const char * filename)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 begining 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 = phdr.p_vaddr;
161 seg_vstart &= ~(vm_vaddr_t)(vm->page_size - 1);
162 vm_vaddr_t seg_vend = phdr.p_vaddr + phdr.p_memsz - 1;
163 seg_vend |= vm->page_size - 1;
164 size_t seg_size = seg_vend - seg_vstart + 1;
165
166 vm_vaddr_t vaddr = vm_vaddr_alloc(vm, seg_size, seg_vstart);
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 }
195