Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
torvalds
GitHub Repository: torvalds/linux
Path: blob/master/tools/testing/selftests/kvm/lib/elf.c
38235 views
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",
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
197