Merge drm/drm-fixes into drm-misc-fixes
[sfrench/cifs-2.6.git] / tools / testing / selftests / kvm / lib / elf.c
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 }
94
95 /* VM ELF Load
96  *
97  * Input Args:
98  *   filename - Path to ELF file
99  *
100  * Output Args: None
101  *
102  * Input/Output Args:
103  *   vm - Pointer to opaque type that describes the VM.
104  *
105  * Return: None, TEST_ASSERT failures for all error conditions
106  *
107  * Loads the program image of the ELF file specified by filename,
108  * into the virtual address space of the VM pointed to by vm.  On entry
109  * the VM needs to not be using any of the virtual address space used
110  * by the image and it needs to have sufficient available physical pages, to
111  * back the virtual pages used to load the image.
112  */
113 void kvm_vm_elf_load(struct kvm_vm *vm, const char *filename)
114 {
115         off_t offset, offset_rv;
116         Elf64_Ehdr hdr;
117
118         /* Open the ELF file. */
119         int fd;
120         fd = open(filename, O_RDONLY);
121         TEST_ASSERT(fd >= 0, "Failed to open ELF file,\n"
122                 "  filename: %s\n"
123                 "  rv: %i errno: %i", filename, fd, errno);
124
125         /* Read in the ELF header. */
126         elfhdr_get(filename, &hdr);
127
128         /* For each program header.
129          * The following ELF header members specify the location
130          * and size of the program headers:
131          *
132          *   e_phoff - File offset to start of program headers
133          *   e_phentsize - Size of each program header
134          *   e_phnum - Number of program header entries
135          */
136         for (unsigned int n1 = 0; n1 < hdr.e_phnum; n1++) {
137                 /* Seek to the beginning of the program header. */
138                 offset = hdr.e_phoff + (n1 * hdr.e_phentsize);
139                 offset_rv = lseek(fd, offset, SEEK_SET);
140                 TEST_ASSERT(offset_rv == offset,
141                         "Failed to seek to begining of program header %u,\n"
142                         "  filename: %s\n"
143                         "  rv: %jd errno: %i",
144                         n1, filename, (intmax_t) offset_rv, errno);
145
146                 /* Read in the program header. */
147                 Elf64_Phdr phdr;
148                 test_read(fd, &phdr, sizeof(phdr));
149
150                 /* Skip if this header doesn't describe a loadable segment. */
151                 if (phdr.p_type != PT_LOAD)
152                         continue;
153
154                 /* Allocate memory for this segment within the VM. */
155                 TEST_ASSERT(phdr.p_memsz > 0, "Unexpected loadable segment "
156                         "memsize of 0,\n"
157                         "  phdr index: %u p_memsz: 0x%" PRIx64,
158                         n1, (uint64_t) phdr.p_memsz);
159                 vm_vaddr_t seg_vstart = align_down(phdr.p_vaddr, vm->page_size);
160                 vm_vaddr_t seg_vend = phdr.p_vaddr + phdr.p_memsz - 1;
161                 seg_vend |= vm->page_size - 1;
162                 size_t seg_size = seg_vend - seg_vstart + 1;
163
164                 vm_vaddr_t vaddr = vm_vaddr_alloc(vm, seg_size, seg_vstart);
165                 TEST_ASSERT(vaddr == seg_vstart, "Unable to allocate "
166                         "virtual memory for segment at requested min addr,\n"
167                         "  segment idx: %u\n"
168                         "  seg_vstart: 0x%lx\n"
169                         "  vaddr: 0x%lx",
170                         n1, seg_vstart, vaddr);
171                 memset(addr_gva2hva(vm, vaddr), 0, seg_size);
172                 /* TODO(lhuemill): Set permissions of each memory segment
173                  * based on the least-significant 3 bits of phdr.p_flags.
174                  */
175
176                 /* Load portion of initial state that is contained within
177                  * the ELF file.
178                  */
179                 if (phdr.p_filesz) {
180                         offset_rv = lseek(fd, phdr.p_offset, SEEK_SET);
181                         TEST_ASSERT(offset_rv == phdr.p_offset,
182                                 "Seek to program segment offset failed,\n"
183                                 "  program header idx: %u errno: %i\n"
184                                 "  offset_rv: 0x%jx\n"
185                                 "  expected: 0x%jx\n",
186                                 n1, errno, (intmax_t) offset_rv,
187                                 (intmax_t) phdr.p_offset);
188                         test_read(fd, addr_gva2hva(vm, phdr.p_vaddr),
189                                 phdr.p_filesz);
190                 }
191         }
192 }