1*4882a593Smuzhiyun // SPDX-License-Identifier: GPL-2.0-only
2*4882a593Smuzhiyun /*
3*4882a593Smuzhiyun * tools/testing/selftests/kvm/lib/elf.c
4*4882a593Smuzhiyun *
5*4882a593Smuzhiyun * Copyright (C) 2018, Google LLC.
6*4882a593Smuzhiyun */
7*4882a593Smuzhiyun
8*4882a593Smuzhiyun #include "test_util.h"
9*4882a593Smuzhiyun
10*4882a593Smuzhiyun #include <bits/endian.h>
11*4882a593Smuzhiyun #include <linux/elf.h>
12*4882a593Smuzhiyun
13*4882a593Smuzhiyun #include "kvm_util.h"
14*4882a593Smuzhiyun #include "kvm_util_internal.h"
15*4882a593Smuzhiyun
elfhdr_get(const char * filename,Elf64_Ehdr * hdrp)16*4882a593Smuzhiyun static void elfhdr_get(const char *filename, Elf64_Ehdr *hdrp)
17*4882a593Smuzhiyun {
18*4882a593Smuzhiyun off_t offset_rv;
19*4882a593Smuzhiyun
20*4882a593Smuzhiyun /* Open the ELF file. */
21*4882a593Smuzhiyun int fd;
22*4882a593Smuzhiyun fd = open(filename, O_RDONLY);
23*4882a593Smuzhiyun TEST_ASSERT(fd >= 0, "Failed to open ELF file,\n"
24*4882a593Smuzhiyun " filename: %s\n"
25*4882a593Smuzhiyun " rv: %i errno: %i", filename, fd, errno);
26*4882a593Smuzhiyun
27*4882a593Smuzhiyun /* Read in and validate ELF Identification Record.
28*4882a593Smuzhiyun * The ELF Identification record is the first 16 (EI_NIDENT) bytes
29*4882a593Smuzhiyun * of the ELF header, which is at the beginning of the ELF file.
30*4882a593Smuzhiyun * For now it is only safe to read the first EI_NIDENT bytes. Once
31*4882a593Smuzhiyun * read and validated, the value of e_ehsize can be used to determine
32*4882a593Smuzhiyun * the real size of the ELF header.
33*4882a593Smuzhiyun */
34*4882a593Smuzhiyun unsigned char ident[EI_NIDENT];
35*4882a593Smuzhiyun test_read(fd, ident, sizeof(ident));
36*4882a593Smuzhiyun TEST_ASSERT((ident[EI_MAG0] == ELFMAG0) && (ident[EI_MAG1] == ELFMAG1)
37*4882a593Smuzhiyun && (ident[EI_MAG2] == ELFMAG2) && (ident[EI_MAG3] == ELFMAG3),
38*4882a593Smuzhiyun "ELF MAGIC Mismatch,\n"
39*4882a593Smuzhiyun " filename: %s\n"
40*4882a593Smuzhiyun " ident[EI_MAG0 - EI_MAG3]: %02x %02x %02x %02x\n"
41*4882a593Smuzhiyun " Expected: %02x %02x %02x %02x",
42*4882a593Smuzhiyun filename,
43*4882a593Smuzhiyun ident[EI_MAG0], ident[EI_MAG1], ident[EI_MAG2], ident[EI_MAG3],
44*4882a593Smuzhiyun ELFMAG0, ELFMAG1, ELFMAG2, ELFMAG3);
45*4882a593Smuzhiyun TEST_ASSERT(ident[EI_CLASS] == ELFCLASS64,
46*4882a593Smuzhiyun "Current implementation only able to handle ELFCLASS64,\n"
47*4882a593Smuzhiyun " filename: %s\n"
48*4882a593Smuzhiyun " ident[EI_CLASS]: %02x\n"
49*4882a593Smuzhiyun " expected: %02x",
50*4882a593Smuzhiyun filename,
51*4882a593Smuzhiyun ident[EI_CLASS], ELFCLASS64);
52*4882a593Smuzhiyun TEST_ASSERT(((BYTE_ORDER == LITTLE_ENDIAN)
53*4882a593Smuzhiyun && (ident[EI_DATA] == ELFDATA2LSB))
54*4882a593Smuzhiyun || ((BYTE_ORDER == BIG_ENDIAN)
55*4882a593Smuzhiyun && (ident[EI_DATA] == ELFDATA2MSB)), "Current "
56*4882a593Smuzhiyun "implementation only able to handle\n"
57*4882a593Smuzhiyun "cases where the host and ELF file endianness\n"
58*4882a593Smuzhiyun "is the same:\n"
59*4882a593Smuzhiyun " host BYTE_ORDER: %u\n"
60*4882a593Smuzhiyun " host LITTLE_ENDIAN: %u\n"
61*4882a593Smuzhiyun " host BIG_ENDIAN: %u\n"
62*4882a593Smuzhiyun " ident[EI_DATA]: %u\n"
63*4882a593Smuzhiyun " ELFDATA2LSB: %u\n"
64*4882a593Smuzhiyun " ELFDATA2MSB: %u",
65*4882a593Smuzhiyun BYTE_ORDER, LITTLE_ENDIAN, BIG_ENDIAN,
66*4882a593Smuzhiyun ident[EI_DATA], ELFDATA2LSB, ELFDATA2MSB);
67*4882a593Smuzhiyun TEST_ASSERT(ident[EI_VERSION] == EV_CURRENT,
68*4882a593Smuzhiyun "Current implementation only able to handle current "
69*4882a593Smuzhiyun "ELF version,\n"
70*4882a593Smuzhiyun " filename: %s\n"
71*4882a593Smuzhiyun " ident[EI_VERSION]: %02x\n"
72*4882a593Smuzhiyun " expected: %02x",
73*4882a593Smuzhiyun filename, ident[EI_VERSION], EV_CURRENT);
74*4882a593Smuzhiyun
75*4882a593Smuzhiyun /* Read in the ELF header.
76*4882a593Smuzhiyun * With the ELF Identification portion of the ELF header
77*4882a593Smuzhiyun * validated, especially that the value at EI_VERSION is
78*4882a593Smuzhiyun * as expected, it is now safe to read the entire ELF header.
79*4882a593Smuzhiyun */
80*4882a593Smuzhiyun offset_rv = lseek(fd, 0, SEEK_SET);
81*4882a593Smuzhiyun TEST_ASSERT(offset_rv == 0, "Seek to ELF header failed,\n"
82*4882a593Smuzhiyun " rv: %zi expected: %i", offset_rv, 0);
83*4882a593Smuzhiyun test_read(fd, hdrp, sizeof(*hdrp));
84*4882a593Smuzhiyun TEST_ASSERT(hdrp->e_phentsize == sizeof(Elf64_Phdr),
85*4882a593Smuzhiyun "Unexpected physical header size,\n"
86*4882a593Smuzhiyun " hdrp->e_phentsize: %x\n"
87*4882a593Smuzhiyun " expected: %zx",
88*4882a593Smuzhiyun hdrp->e_phentsize, sizeof(Elf64_Phdr));
89*4882a593Smuzhiyun TEST_ASSERT(hdrp->e_shentsize == sizeof(Elf64_Shdr),
90*4882a593Smuzhiyun "Unexpected section header size,\n"
91*4882a593Smuzhiyun " hdrp->e_shentsize: %x\n"
92*4882a593Smuzhiyun " expected: %zx",
93*4882a593Smuzhiyun hdrp->e_shentsize, sizeof(Elf64_Shdr));
94*4882a593Smuzhiyun }
95*4882a593Smuzhiyun
96*4882a593Smuzhiyun /* VM ELF Load
97*4882a593Smuzhiyun *
98*4882a593Smuzhiyun * Input Args:
99*4882a593Smuzhiyun * filename - Path to ELF file
100*4882a593Smuzhiyun *
101*4882a593Smuzhiyun * Output Args: None
102*4882a593Smuzhiyun *
103*4882a593Smuzhiyun * Input/Output Args:
104*4882a593Smuzhiyun * vm - Pointer to opaque type that describes the VM.
105*4882a593Smuzhiyun *
106*4882a593Smuzhiyun * Return: None, TEST_ASSERT failures for all error conditions
107*4882a593Smuzhiyun *
108*4882a593Smuzhiyun * Loads the program image of the ELF file specified by filename,
109*4882a593Smuzhiyun * into the virtual address space of the VM pointed to by vm. On entry
110*4882a593Smuzhiyun * the VM needs to not be using any of the virtual address space used
111*4882a593Smuzhiyun * by the image and it needs to have sufficient available physical pages, to
112*4882a593Smuzhiyun * back the virtual pages used to load the image.
113*4882a593Smuzhiyun */
kvm_vm_elf_load(struct kvm_vm * vm,const char * filename,uint32_t data_memslot,uint32_t pgd_memslot)114*4882a593Smuzhiyun void kvm_vm_elf_load(struct kvm_vm *vm, const char *filename,
115*4882a593Smuzhiyun uint32_t data_memslot, uint32_t pgd_memslot)
116*4882a593Smuzhiyun {
117*4882a593Smuzhiyun off_t offset, offset_rv;
118*4882a593Smuzhiyun Elf64_Ehdr hdr;
119*4882a593Smuzhiyun
120*4882a593Smuzhiyun /* Open the ELF file. */
121*4882a593Smuzhiyun int fd;
122*4882a593Smuzhiyun fd = open(filename, O_RDONLY);
123*4882a593Smuzhiyun TEST_ASSERT(fd >= 0, "Failed to open ELF file,\n"
124*4882a593Smuzhiyun " filename: %s\n"
125*4882a593Smuzhiyun " rv: %i errno: %i", filename, fd, errno);
126*4882a593Smuzhiyun
127*4882a593Smuzhiyun /* Read in the ELF header. */
128*4882a593Smuzhiyun elfhdr_get(filename, &hdr);
129*4882a593Smuzhiyun
130*4882a593Smuzhiyun /* For each program header.
131*4882a593Smuzhiyun * The following ELF header members specify the location
132*4882a593Smuzhiyun * and size of the program headers:
133*4882a593Smuzhiyun *
134*4882a593Smuzhiyun * e_phoff - File offset to start of program headers
135*4882a593Smuzhiyun * e_phentsize - Size of each program header
136*4882a593Smuzhiyun * e_phnum - Number of program header entries
137*4882a593Smuzhiyun */
138*4882a593Smuzhiyun for (unsigned int n1 = 0; n1 < hdr.e_phnum; n1++) {
139*4882a593Smuzhiyun /* Seek to the beginning of the program header. */
140*4882a593Smuzhiyun offset = hdr.e_phoff + (n1 * hdr.e_phentsize);
141*4882a593Smuzhiyun offset_rv = lseek(fd, offset, SEEK_SET);
142*4882a593Smuzhiyun TEST_ASSERT(offset_rv == offset,
143*4882a593Smuzhiyun "Failed to seek to begining of program header %u,\n"
144*4882a593Smuzhiyun " filename: %s\n"
145*4882a593Smuzhiyun " rv: %jd errno: %i",
146*4882a593Smuzhiyun n1, filename, (intmax_t) offset_rv, errno);
147*4882a593Smuzhiyun
148*4882a593Smuzhiyun /* Read in the program header. */
149*4882a593Smuzhiyun Elf64_Phdr phdr;
150*4882a593Smuzhiyun test_read(fd, &phdr, sizeof(phdr));
151*4882a593Smuzhiyun
152*4882a593Smuzhiyun /* Skip if this header doesn't describe a loadable segment. */
153*4882a593Smuzhiyun if (phdr.p_type != PT_LOAD)
154*4882a593Smuzhiyun continue;
155*4882a593Smuzhiyun
156*4882a593Smuzhiyun /* Allocate memory for this segment within the VM. */
157*4882a593Smuzhiyun TEST_ASSERT(phdr.p_memsz > 0, "Unexpected loadable segment "
158*4882a593Smuzhiyun "memsize of 0,\n"
159*4882a593Smuzhiyun " phdr index: %u p_memsz: 0x%" PRIx64,
160*4882a593Smuzhiyun n1, (uint64_t) phdr.p_memsz);
161*4882a593Smuzhiyun vm_vaddr_t seg_vstart = phdr.p_vaddr;
162*4882a593Smuzhiyun seg_vstart &= ~(vm_vaddr_t)(vm->page_size - 1);
163*4882a593Smuzhiyun vm_vaddr_t seg_vend = phdr.p_vaddr + phdr.p_memsz - 1;
164*4882a593Smuzhiyun seg_vend |= vm->page_size - 1;
165*4882a593Smuzhiyun size_t seg_size = seg_vend - seg_vstart + 1;
166*4882a593Smuzhiyun
167*4882a593Smuzhiyun vm_vaddr_t vaddr = vm_vaddr_alloc(vm, seg_size, seg_vstart,
168*4882a593Smuzhiyun data_memslot, pgd_memslot);
169*4882a593Smuzhiyun TEST_ASSERT(vaddr == seg_vstart, "Unable to allocate "
170*4882a593Smuzhiyun "virtual memory for segment at requested min addr,\n"
171*4882a593Smuzhiyun " segment idx: %u\n"
172*4882a593Smuzhiyun " seg_vstart: 0x%lx\n"
173*4882a593Smuzhiyun " vaddr: 0x%lx",
174*4882a593Smuzhiyun n1, seg_vstart, vaddr);
175*4882a593Smuzhiyun memset(addr_gva2hva(vm, vaddr), 0, seg_size);
176*4882a593Smuzhiyun /* TODO(lhuemill): Set permissions of each memory segment
177*4882a593Smuzhiyun * based on the least-significant 3 bits of phdr.p_flags.
178*4882a593Smuzhiyun */
179*4882a593Smuzhiyun
180*4882a593Smuzhiyun /* Load portion of initial state that is contained within
181*4882a593Smuzhiyun * the ELF file.
182*4882a593Smuzhiyun */
183*4882a593Smuzhiyun if (phdr.p_filesz) {
184*4882a593Smuzhiyun offset_rv = lseek(fd, phdr.p_offset, SEEK_SET);
185*4882a593Smuzhiyun TEST_ASSERT(offset_rv == phdr.p_offset,
186*4882a593Smuzhiyun "Seek to program segment offset failed,\n"
187*4882a593Smuzhiyun " program header idx: %u errno: %i\n"
188*4882a593Smuzhiyun " offset_rv: 0x%jx\n"
189*4882a593Smuzhiyun " expected: 0x%jx\n",
190*4882a593Smuzhiyun n1, errno, (intmax_t) offset_rv,
191*4882a593Smuzhiyun (intmax_t) phdr.p_offset);
192*4882a593Smuzhiyun test_read(fd, addr_gva2hva(vm, phdr.p_vaddr),
193*4882a593Smuzhiyun phdr.p_filesz);
194*4882a593Smuzhiyun }
195*4882a593Smuzhiyun }
196*4882a593Smuzhiyun }
197