The Pedigree Project 0.1
boot-hosted.cc
1/*
2 * Copyright (c) 2008-2014, Pedigree Developers
3 *
4 * Please see the CONTRIB file in the root of the source tree for a full
5 * list of contributors.
6 *
7 * Permission to use, copy, modify, and distribute this software for any
8 * purpose with or without fee is hereby granted, provided that the above
9 * copyright notice and this permission notice appear in all copies.
10 *
11 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
12 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
13 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
14 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
15 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
16 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
17 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
18 */
19
20#include <assert.h>
21#include <errno.h>
22#include <fcntl.h>
23#include <memory.h>
24#include <stdio.h>
25#include <stdlib.h>
26#include <string.h>
27#include <unistd.h>
28
29#include <sys/mman.h>
30#include <sys/stat.h>
31
32#ifndef PEDIGREE_HOSTED_DARWIN
33#include <elf.h>
34#endif
35
36#include "pedigree/kernel/BootstrapInfo.h"
37#include "pedigree/kernel/TargetInfo.h"
38#include "pedigree/kernel/compiler.h"
39#include "pedigree/kernel/processor/hosted/FunctionProfile.h"
40#include "pedigree/kernel/processor/hosted/smoke.h"
41
42extern "C" void _main(BootstrapStruct_t& bs);
43extern "C" {
44HostedSmokeStage g_HostedSmokeStage = HostedSmokeNone;
45}
46static size_t profileDivisor = 1;
47
48size_t hostedSyscallProfileDivisor() {
49 return profileDivisor;
50}
51
52bool hostedSyscallProfileRequested() {
53#if HOSTED_SMOKE_TESTS
54 const char* value = getenv("PEDIGREE_HOSTED_SYSCALL_PROFILE");
55 return value && !strcmp(value, "1");
56#else
57 return false;
58#endif
59}
60
61static void* add_ptr(void* ptr, size_t addend) {
62 uintptr_t ptr_u = (uintptr_t)ptr;
63 ptr_u += addend;
64 return (void*)ptr_u;
65}
66
67extern "C" int main(int argc, char* argv[]) {
68 struct stat st;
69 int r = 0;
70 int s = 0;
71 int initrd = -1;
72 int kernel = -1;
73 int diskimage = -1;
74 void* initrd_mapping = MAP_FAILED;
75#ifndef PEDIGREE_HOSTED_DARWIN
76 void* kernel_mapping = MAP_FAILED;
77#endif
78 void* diskimage_mapping = MAP_FAILED;
79 uintptr_t* module_region = (uintptr_t*)MAP_FAILED;
80 size_t initrd_length = 0;
81#ifndef PEDIGREE_HOSTED_DARWIN
82 size_t kernel_length = 0;
83#endif
84 size_t diskimage_length = 0;
85#ifndef PEDIGREE_HOSTED_DARWIN
86 Elf64_Ehdr* ehdr = 0;
87 Elf64_Shdr* shdrs = 0;
88#endif
89 BootstrapStruct_t bs = {};
90
91 if (hostedSyscallProfileRequested()) {
92 const char* value = getenv("PEDIGREE_HOSTED_PROFILE_DIVISOR");
93 if (value) {
94 char* end = nullptr;
95 const unsigned long divisor = strtoul(value, &end, 10);
96 if (!*value || *end || divisor < 1 || divisor > 100000) {
97 fprintf(stderr, "PEDIGREE_HOSTED_PROFILE_DIVISOR must be between 1 and 100000.\n");
98 goto fail;
99 }
100 profileDivisor = divisor;
101 }
102 }
103
104 if (argc < 2 || argc > 4) {
105 fprintf(stderr,
106 "Usage: kernel initrd "
107 "[diskimage [root|init|command|shutdown]]\n");
108 goto fail;
109 }
110
111#if PEDIGREE_HOSTED_FUNCTION_PROFILE
112 if (!hostedFunctionProfileInitialise()) {
113 goto fail;
114 }
115#endif
116
117 if (argc == 4) {
118 if (!strcmp(argv[3], "root")) {
119 g_HostedSmokeStage = HostedSmokeRoot;
120 } else if (!strcmp(argv[3], "init")) {
121 g_HostedSmokeStage = HostedSmokeInit;
122 } else if (!strcmp(argv[3], "command")) {
123 g_HostedSmokeStage = HostedSmokeCommand;
124 } else if (!strcmp(argv[3], "shutdown")) {
125 g_HostedSmokeStage = HostedSmokeShutdown;
126 } else {
127 fprintf(stderr, "Unknown hosted smoke stage: %s\n", argv[3]);
128 goto fail;
129 }
130 }
131
132 fprintf(stderr, "Hosted runtime: %s; heap: %s\n",
133 HAS_ADDRESS_SANITIZER ? "AddressSanitizer" : "unsanitized",
134 HOSTED_SYSTEM_MALLOC ? "system malloc" : "Pedigree SlamAllocator");
135 fprintf(stderr, "Pedigree is starting...\n");
136
137 // Load initrd into RAM.
138 initrd = open(argv[1], O_RDONLY);
139 if (initrd < 0) {
140 fprintf(stderr, "Can't open initrd: %s\n", strerror(errno));
141 goto fail;
142 }
143
144#ifndef PEDIGREE_HOSTED_DARWIN
145 // ELF hosts expose the kernel's section table through Multiboot metadata.
146 kernel = open(argv[0], O_RDONLY);
147 if (kernel < 0) {
148 fprintf(stderr, "Can't open kernel: %s\n", strerror(errno));
149 goto fail;
150 }
151#endif
152
153 // Map the initrd.
154 r = fstat(initrd, &st);
155 if (r != 0) {
156 fprintf(stderr, "Can't stat initrd: %s\n", strerror(errno));
157 goto fail;
158 }
159 initrd_length = st.st_size;
160 initrd_mapping = mmap(0, initrd_length, PROT_READ, MAP_PRIVATE, initrd, 0);
161 if (initrd_mapping == MAP_FAILED) {
162 fprintf(stderr, "Can't map initrd: %s\n", strerror(errno));
163 goto fail;
164 }
165 fprintf(stderr, "initrd is at %p\n", initrd_mapping);
166
167#ifndef PEDIGREE_HOSTED_DARWIN
168 r = fstat(kernel, &st);
169 if (r != 0) {
170 fprintf(stderr, "Can't stat kernel: %s\n", strerror(errno));
171 goto fail;
172 }
173 kernel_length = st.st_size;
174 kernel_mapping = mmap(0, kernel_length, PROT_READ | PROT_WRITE, MAP_PRIVATE, kernel, 0);
175 if (kernel_mapping == MAP_FAILED) {
176 fprintf(stderr, "Can't map kernel: %s\n", strerror(errno));
177 goto fail;
178 }
179 fprintf(stderr, "kernel is at %p\n", kernel_mapping);
180#endif
181
182 // Make the module locations available to the kernel.
183 module_region = (uintptr_t*)mmap(0, TargetInfo::getPageSize(), PROT_READ | PROT_WRITE,
184 MAP_PRIVATE | MAP_ANON, -1, 0);
185 if (module_region == MAP_FAILED) {
186 fprintf(stderr, "Can't map module information region: %s\n", strerror(errno));
187 goto fail;
188 }
189 fprintf(stderr, "module region is at %p\n", module_region);
190 memset(module_region, 0, TargetInfo::getPageSize());
191
192 // initrd
193 module_region[0] = reinterpret_cast<uintptr_t>(initrd_mapping);
194 module_region[1] = reinterpret_cast<uintptr_t>(initrd_mapping) + initrd_length;
195
196 bs.mods_addr = reinterpret_cast<uintptr_t>(module_region);
197 bs.mods_count = 1;
198
199 if (argc > 2) {
200 diskimage = open(argv[2], O_RDWR);
201 if (diskimage < 0) {
202 fprintf(stderr, "Can't open disk image: %s\n", strerror(errno));
203 goto fail;
204 }
205
206 r = fstat(diskimage, &st);
207 if (r != 0) {
208 fprintf(stderr, "Can't stat disk image: %s\n", strerror(errno));
209 goto fail;
210 }
211
212 diskimage_length = st.st_size;
213 diskimage_mapping = mmap(0, diskimage_length, PROT_READ | PROT_WRITE,
214 MAP_PRIVATE | MAP_NORESERVE, diskimage, 0);
215 if (diskimage_mapping == MAP_FAILED) {
216 fprintf(stderr, "Can't map disk image: %s\n", strerror(errno));
217 goto fail;
218 }
219 fprintf(stderr, "disk image is at %p\n", diskimage_mapping);
220
221 // Add to the multiboot info.
222 bs.mods_count++;
223 module_region[4] = reinterpret_cast<uintptr_t>(diskimage_mapping);
224 module_region[5] = reinterpret_cast<uintptr_t>(diskimage_mapping) + diskimage_length;
225 }
226
227#ifndef PEDIGREE_HOSTED_DARWIN
228 // Load ELF header to add ELF information.
229 ehdr = reinterpret_cast<Elf64_Ehdr*>(kernel_mapping);
230 bs.shndx = ehdr->e_shstrndx;
231 bs.num = ehdr->e_shnum;
232 bs.size = ehdr->e_shentsize;
233 bs.addr = reinterpret_cast<uintptr_t>(kernel_mapping) + ehdr->e_shoff;
234
235 // Fix up section headers with no addresses.
236 shdrs = reinterpret_cast<Elf64_Shdr*>(bs.addr);
237 for (uint32_t i = 1; i < bs.num; ++i) {
238 if (shdrs[i].sh_addr)
239 continue;
240
241 shdrs[i].sh_addr = shdrs[i].sh_offset + reinterpret_cast<uintptr_t>(kernel_mapping);
242 }
243#endif
244
245 fprintf(stderr, "Running main(), with mappings:\n");
246#ifndef PEDIGREE_HOSTED_DARWIN
247 fprintf(stderr, " kernel: %p -> %p\n", kernel_mapping, add_ptr(kernel_mapping, kernel_length));
248#else
249 fprintf(stderr, " kernel: Mach-O process symbols\n");
250#endif
251 fprintf(stderr, " diskimage: %p -> %p\n", diskimage_mapping,
252 add_ptr(diskimage_mapping, diskimage_length));
253 fprintf(stderr, " modules: %p -> %p\n", module_region,
254 add_ptr(module_region, TargetInfo::getPageSize()));
255 fprintf(stderr, " initrd: %p -> %p\n", initrd_mapping, add_ptr(initrd_mapping, initrd_length));
256
257 // Kernel uses flags to know what it can and can't use.
258 bs.flags |= BOOTSTRAP_FLAG_MODULES;
259#ifndef PEDIGREE_HOSTED_DARWIN
260 bs.flags |= BOOTSTRAP_FLAG_ELF;
261#endif
262 _main(bs);
263
264 fprintf(stderr, "main() returned, cleaning up...\n");
265
266 goto cleanup;
267fail:
268 s = 1;
269cleanup:
270 if (module_region != MAP_FAILED)
271 munmap(module_region, TargetInfo::getPageSize());
272 if (diskimage_mapping != MAP_FAILED)
273 munmap(diskimage_mapping, diskimage_length);
274#ifndef PEDIGREE_HOSTED_DARWIN
275 if (kernel_mapping != MAP_FAILED)
276 munmap(kernel_mapping, kernel_length);
277#endif
278 if (initrd_mapping != MAP_FAILED)
279 munmap(initrd_mapping, initrd_length);
280 close(diskimage);
281 if (kernel >= 0)
282 close(kernel);
283 close(initrd);
284 return s;
285}
static constexpr size_t getPageSize() noexcept
Definition TargetInfo.h:40