1
2
3
4
5
6
7
8
9#include "test_util.h"
10
11#include <bits/endian.h>
12#include <linux/elf.h>
13
14#include "kvm_util.h"
15#include "kvm_util_internal.h"
16
17static void elfhdr_get(const char *filename, Elf64_Ehdr *hdrp)
18{
19 off_t offset_rv;
20
21
22 int fd;
23 fd = open(filename, O_RDONLY);
24 TEST_ASSERT(fd >= 0, "Failed to open ELF file,\n"
25 " filename: %s\n"
26 " rv: %i errno: %i", filename, fd, errno);
27
28
29
30
31
32
33
34
35 unsigned char ident[EI_NIDENT];
36 test_read(fd, ident, sizeof(ident));
37 TEST_ASSERT((ident[EI_MAG0] == ELFMAG0) && (ident[EI_MAG1] == ELFMAG1)
38 && (ident[EI_MAG2] == ELFMAG2) && (ident[EI_MAG3] == ELFMAG3),
39 "ELF MAGIC Mismatch,\n"
40 " filename: %s\n"
41 " ident[EI_MAG0 - EI_MAG3]: %02x %02x %02x %02x\n"
42 " Expected: %02x %02x %02x %02x",
43 filename,
44 ident[EI_MAG0], ident[EI_MAG1], ident[EI_MAG2], ident[EI_MAG3],
45 ELFMAG0, ELFMAG1, ELFMAG2, ELFMAG3);
46 TEST_ASSERT(ident[EI_CLASS] == ELFCLASS64,
47 "Current implementation only able to handle ELFCLASS64,\n"
48 " filename: %s\n"
49 " ident[EI_CLASS]: %02x\n"
50 " expected: %02x",
51 filename,
52 ident[EI_CLASS], ELFCLASS64);
53 TEST_ASSERT(((BYTE_ORDER == LITTLE_ENDIAN)
54 && (ident[EI_DATA] == ELFDATA2LSB))
55 || ((BYTE_ORDER == BIG_ENDIAN)
56 && (ident[EI_DATA] == ELFDATA2MSB)), "Current "
57 "implementation only able to handle\n"
58 "cases where the host and ELF file endianness\n"
59 "is the same:\n"
60 " host BYTE_ORDER: %u\n"
61 " host LITTLE_ENDIAN: %u\n"
62 " host BIG_ENDIAN: %u\n"
63 " ident[EI_DATA]: %u\n"
64 " ELFDATA2LSB: %u\n"
65 " ELFDATA2MSB: %u",
66 BYTE_ORDER, LITTLE_ENDIAN, BIG_ENDIAN,
67 ident[EI_DATA], ELFDATA2LSB, ELFDATA2MSB);
68 TEST_ASSERT(ident[EI_VERSION] == EV_CURRENT,
69 "Current implementation only able to handle current "
70 "ELF version,\n"
71 " filename: %s\n"
72 " ident[EI_VERSION]: %02x\n"
73 " expected: %02x",
74 filename, ident[EI_VERSION], EV_CURRENT);
75
76
77
78
79
80
81 offset_rv = lseek(fd, 0, SEEK_SET);
82 TEST_ASSERT(offset_rv == 0, "Seek to ELF header failed,\n"
83 " rv: %zi expected: %i", offset_rv, 0);
84 test_read(fd, hdrp, sizeof(*hdrp));
85 TEST_ASSERT(hdrp->e_phentsize == sizeof(Elf64_Phdr),
86 "Unexpected physical header size,\n"
87 " hdrp->e_phentsize: %x\n"
88 " expected: %zx",
89 hdrp->e_phentsize, sizeof(Elf64_Phdr));
90 TEST_ASSERT(hdrp->e_shentsize == sizeof(Elf64_Shdr),
91 "Unexpected section header size,\n"
92 " hdrp->e_shentsize: %x\n"
93 " expected: %zx",
94 hdrp->e_shentsize, sizeof(Elf64_Shdr));
95}
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115void kvm_vm_elf_load(struct kvm_vm *vm, const char *filename,
116 uint32_t data_memslot, uint32_t pgd_memslot)
117{
118 off_t offset, offset_rv;
119 Elf64_Ehdr hdr;
120
121
122 int fd;
123 fd = open(filename, O_RDONLY);
124 TEST_ASSERT(fd >= 0, "Failed to open ELF file,\n"
125 " filename: %s\n"
126 " rv: %i errno: %i", filename, fd, errno);
127
128
129 elfhdr_get(filename, &hdr);
130
131
132
133
134
135
136
137
138
139 for (unsigned int n1 = 0; n1 < hdr.e_phnum; n1++) {
140
141 offset = hdr.e_phoff + (n1 * hdr.e_phentsize);
142 offset_rv = lseek(fd, offset, SEEK_SET);
143 TEST_ASSERT(offset_rv == offset,
144 "Failed to seek to begining of program header %u,\n"
145 " filename: %s\n"
146 " rv: %jd errno: %i",
147 n1, filename, (intmax_t) offset_rv, errno);
148
149
150 Elf64_Phdr phdr;
151 test_read(fd, &phdr, sizeof(phdr));
152
153
154 if (phdr.p_type != PT_LOAD)
155 continue;
156
157
158 TEST_ASSERT(phdr.p_memsz > 0, "Unexpected loadable segment "
159 "memsize of 0,\n"
160 " phdr index: %u p_memsz: 0x%" PRIx64,
161 n1, (uint64_t) phdr.p_memsz);
162 vm_vaddr_t seg_vstart = phdr.p_vaddr;
163 seg_vstart &= ~(vm_vaddr_t)(vm->page_size - 1);
164 vm_vaddr_t seg_vend = phdr.p_vaddr + phdr.p_memsz - 1;
165 seg_vend |= vm->page_size - 1;
166 size_t seg_size = seg_vend - seg_vstart + 1;
167
168 vm_vaddr_t vaddr = vm_vaddr_alloc(vm, seg_size, seg_vstart,
169 data_memslot, pgd_memslot);
170 TEST_ASSERT(vaddr == seg_vstart, "Unable to allocate "
171 "virtual memory for segment at requested min addr,\n"
172 " segment idx: %u\n"
173 " seg_vstart: 0x%lx\n"
174 " vaddr: 0x%lx",
175 n1, seg_vstart, vaddr);
176 memset(addr_gva2hva(vm, vaddr), 0, seg_size);
177
178
179
180
181
182
183
184 if (phdr.p_filesz) {
185 offset_rv = lseek(fd, phdr.p_offset, SEEK_SET);
186 TEST_ASSERT(offset_rv == phdr.p_offset,
187 "Seek to program segment offset failed,\n"
188 " program header idx: %u errno: %i\n"
189 " offset_rv: 0x%jx\n"
190 " expected: 0x%jx\n",
191 n1, errno, (intmax_t) offset_rv,
192 (intmax_t) phdr.p_offset);
193 test_read(fd, addr_gva2hva(vm, phdr.p_vaddr),
194 phdr.p_filesz);
195 }
196 }
197}
198