Print this page
10807 loader fails to boot Dell R510 in UEFI mode
Reviewed by: Robert Mustacchi <rm@joyent.com>
Reviewed by: Jerry Jelinek <jerry.jelinek@joyent.com>
Reviewed by: Toomas Soome <tsoome@me.com>
Split |
Close |
Expand all |
Collapse all |
--- old/usr/src/boot/sys/boot/common/multiboot2.c
+++ new/usr/src/boot/sys/boot/common/multiboot2.c
1 1 /*
2 2 * This file and its contents are supplied under the terms of the
3 3 * Common Development and Distribution License ("CDDL"), version 1.0.
↓ open down ↓ |
3 lines elided |
↑ open up ↑ |
4 4 * You may only use this file in accordance with the terms of version
5 5 * 1.0 of the CDDL.
6 6 *
7 7 * A full copy of the text of the CDDL should have accompanied this
8 8 * source. A copy of the CDDL is also available via the Internet at
9 9 * http://www.illumos.org/license/CDDL.
10 10 */
11 11
12 12 /*
13 13 * Copyright 2017 Toomas Soome <tsoome@me.com>
14 + * Copyright 2019, Joyent, Inc.
14 15 */
15 16
16 17 /*
17 18 * This module adds support for loading and booting illumos multiboot2
18 19 * kernel. This code is only built to support the illumos kernel, it does
19 20 * not support xen.
20 21 */
21 22
22 23 #include <sys/cdefs.h>
23 24 #include <sys/stddef.h>
24 25
25 26 #include <sys/param.h>
26 27 #include <sys/exec.h>
27 28 #include <sys/linker.h>
28 29 #include <sys/module.h>
29 30 #include <sys/stdint.h>
30 31 #include <sys/multiboot2.h>
31 32 #include <stand.h>
32 33 #include <stdbool.h>
33 34 #include <machine/elf.h>
34 35 #include "libzfs.h"
35 36
36 37 #include "bootstrap.h"
37 38 #include <sys/consplat.h>
38 39
39 40 #include <machine/metadata.h>
40 41 #include <machine/pc/bios.h>
41 42
42 43 #define SUPPORT_DHCP
43 44 #include <bootp.h>
44 45
45 46 #if !defined(EFI)
46 47 #include "../i386/btx/lib/btxv86.h"
47 48 #include "libi386.h"
48 49 #include "vbe.h"
49 50
50 51 #else
51 52 #include <efi.h>
52 53 #include <efilib.h>
53 54 #include "loader_efi.h"
54 55
55 56 static void (*trampoline)(uint32_t, struct relocator *, uint64_t);
56 57 #endif
57 58
58 59 #include "platform/acfreebsd.h"
59 60 #include "acconfig.h"
60 61 #define ACPI_SYSTEM_XFACE
61 62 #include "actypes.h"
62 63 #include "actbl.h"
63 64
64 65 extern ACPI_TABLE_RSDP *rsdp;
65 66
66 67 /* MB data heap pointer. */
67 68 static vm_offset_t last_addr;
68 69
69 70 static int multiboot2_loadfile(char *, uint64_t, struct preloaded_file **);
70 71 static int multiboot2_exec(struct preloaded_file *);
71 72
72 73 struct file_format multiboot2 = { multiboot2_loadfile, multiboot2_exec };
73 74 static bool keep_bs = false;
74 75 static bool have_framebuffer = false;
75 76 static vm_offset_t load_addr;
76 77 static vm_offset_t entry_addr;
77 78
78 79 /*
79 80 * Validate tags in info request. This function is provided just to
80 81 * recognize the current tag list and only serves as a limited
81 82 * safe guard against possibly corrupt information.
82 83 */
83 84 static bool
84 85 is_info_request_valid(multiboot_header_tag_information_request_t *rtag)
85 86 {
86 87 int i;
87 88
88 89 /*
89 90 * If the tag is optional and we do not support it, we do not
90 91 * have to do anything special, so we skip optional tags.
91 92 */
92 93 if (rtag->mbh_flags & MULTIBOOT_HEADER_TAG_OPTIONAL)
93 94 return (true);
94 95
95 96 for (i = 0; i < (rtag->mbh_size - sizeof (*rtag)) /
96 97 sizeof (rtag->mbh_requests[0]); i++)
97 98 switch (rtag->mbh_requests[i]) {
98 99 case MULTIBOOT_TAG_TYPE_END:
99 100 case MULTIBOOT_TAG_TYPE_CMDLINE:
100 101 case MULTIBOOT_TAG_TYPE_BOOT_LOADER_NAME:
101 102 case MULTIBOOT_TAG_TYPE_MODULE:
102 103 case MULTIBOOT_TAG_TYPE_BASIC_MEMINFO:
103 104 case MULTIBOOT_TAG_TYPE_BOOTDEV:
104 105 case MULTIBOOT_TAG_TYPE_MMAP:
105 106 case MULTIBOOT_TAG_TYPE_FRAMEBUFFER:
106 107 case MULTIBOOT_TAG_TYPE_VBE:
107 108 case MULTIBOOT_TAG_TYPE_ELF_SECTIONS:
108 109 case MULTIBOOT_TAG_TYPE_APM:
109 110 case MULTIBOOT_TAG_TYPE_EFI32:
110 111 case MULTIBOOT_TAG_TYPE_EFI64:
111 112 case MULTIBOOT_TAG_TYPE_ACPI_OLD:
112 113 case MULTIBOOT_TAG_TYPE_ACPI_NEW:
113 114 case MULTIBOOT_TAG_TYPE_NETWORK:
114 115 case MULTIBOOT_TAG_TYPE_EFI_MMAP:
115 116 case MULTIBOOT_TAG_TYPE_EFI_BS:
116 117 case MULTIBOOT_TAG_TYPE_EFI32_IH:
117 118 case MULTIBOOT_TAG_TYPE_EFI64_IH:
118 119 case MULTIBOOT_TAG_TYPE_LOAD_BASE_ADDR:
119 120 break;
120 121 default:
121 122 printf("unsupported information tag: 0x%x\n",
122 123 rtag->mbh_requests[i]);
123 124 return (false);
124 125 }
125 126 return (true);
126 127 }
127 128
128 129 static int
129 130 multiboot2_loadfile(char *filename, uint64_t dest,
130 131 struct preloaded_file **result)
131 132 {
132 133 int fd, error;
133 134 uint32_t i;
134 135 struct stat st;
135 136 caddr_t header_search;
136 137 multiboot2_header_t *header;
137 138 multiboot_header_tag_t *tag;
138 139 multiboot_header_tag_address_t *addr_tag = NULL;
139 140 multiboot_header_tag_entry_address_t *entry_tag = NULL;
140 141 struct preloaded_file *fp;
141 142
142 143 /* This allows to check other file formats from file_formats array. */
143 144 error = EFTYPE;
144 145 if (filename == NULL)
145 146 return (error);
146 147
147 148 /* is kernel already loaded? */
148 149 fp = file_findfile(NULL, NULL);
149 150 if (fp != NULL)
150 151 return (error);
151 152
152 153 if ((fd = open(filename, O_RDONLY)) == -1)
153 154 return (errno);
154 155
155 156 /*
156 157 * Read MULTIBOOT_SEARCH size in order to search for the
157 158 * multiboot magic header.
158 159 */
159 160 header_search = malloc(MULTIBOOT_SEARCH);
160 161 if (header_search == NULL) {
161 162 close(fd);
162 163 return (ENOMEM);
163 164 }
164 165
165 166 if (read(fd, header_search, MULTIBOOT_SEARCH) != MULTIBOOT_SEARCH)
166 167 goto out;
167 168
168 169 header = NULL;
169 170 for (i = 0; i <= (MULTIBOOT_SEARCH - sizeof (multiboot2_header_t));
170 171 i += MULTIBOOT_HEADER_ALIGN) {
171 172 header = (multiboot2_header_t *)(header_search + i);
172 173
173 174 /* Do we have match on magic? */
174 175 if (header->mb2_magic != MULTIBOOT2_HEADER_MAGIC) {
175 176 header = NULL;
176 177 continue;
177 178 }
178 179 /*
179 180 * Validate checksum, the sum of magic + architecture +
180 181 * header_length + checksum must equal 0.
181 182 */
182 183 if (header->mb2_magic + header->mb2_architecture +
183 184 header->mb2_header_length + header->mb2_checksum != 0) {
184 185 header = NULL;
185 186 continue;
186 187 }
187 188 /*
188 189 * Finally, the entire header must fit within MULTIBOOT_SEARCH.
189 190 */
190 191 if (i + header->mb2_header_length > MULTIBOOT_SEARCH) {
191 192 header = NULL;
192 193 continue;
193 194 }
194 195 break;
195 196 }
196 197
197 198 if (header == NULL)
198 199 goto out;
199 200
200 201 have_framebuffer = false;
201 202 for (tag = header->mb2_tags; tag->mbh_type != MULTIBOOT_TAG_TYPE_END;
202 203 tag = (multiboot_header_tag_t *)((uintptr_t)tag +
203 204 roundup2(tag->mbh_size, MULTIBOOT_TAG_ALIGN))) {
204 205 switch (tag->mbh_type) {
205 206 case MULTIBOOT_HEADER_TAG_INFORMATION_REQUEST:
206 207 if (is_info_request_valid((void*)tag) == false)
207 208 goto out;
208 209 break;
209 210 case MULTIBOOT_HEADER_TAG_ADDRESS:
210 211 addr_tag = (multiboot_header_tag_address_t *)tag;
211 212 break;
212 213 case MULTIBOOT_HEADER_TAG_ENTRY_ADDRESS:
213 214 entry_tag =
214 215 (multiboot_header_tag_entry_address_t *)tag;
215 216 break;
216 217 case MULTIBOOT_HEADER_TAG_CONSOLE_FLAGS:
217 218 break;
218 219 case MULTIBOOT_HEADER_TAG_FRAMEBUFFER:
219 220 have_framebuffer = true;
220 221 break;
221 222 case MULTIBOOT_HEADER_TAG_MODULE_ALIGN:
222 223 /* we always align modules */
223 224 break;
224 225 case MULTIBOOT_HEADER_TAG_EFI_BS:
225 226 keep_bs = true;
226 227 break;
227 228 default:
228 229 if (!(tag->mbh_flags & MULTIBOOT_HEADER_TAG_OPTIONAL)) {
229 230 printf("unsupported tag: 0x%x\n",
230 231 tag->mbh_type);
231 232 goto out;
232 233 }
233 234 }
234 235 }
235 236
236 237 /*
237 238 * We must have addr_tag and entry_tag to load a 64-bit kernel.
238 239 * If these tags are missing, we either have a 32-bit kernel, or
239 240 * this is not our kernel at all.
240 241 */
241 242 if (addr_tag != NULL && entry_tag != NULL) {
242 243 fp = file_alloc();
243 244 if (fp == NULL) {
244 245 error = ENOMEM;
245 246 goto out;
246 247 }
247 248 if (lseek(fd, 0, SEEK_SET) == -1) {
248 249 printf("lseek failed\n");
249 250 error = EIO;
250 251 file_discard(fp);
251 252 goto out;
252 253 }
253 254 if (fstat(fd, &st) < 0) {
254 255 printf("fstat failed\n");
255 256 error = EIO;
256 257 file_discard(fp);
257 258 goto out;
258 259 }
259 260
260 261 load_addr = addr_tag->mbh_load_addr;
261 262 entry_addr = entry_tag->mbh_entry_addr;
262 263 fp->f_addr = archsw.arch_loadaddr(LOAD_KERN, filename,
263 264 addr_tag->mbh_load_addr);
264 265 if (fp->f_addr == 0) {
265 266 error = ENOMEM;
266 267 file_discard(fp);
267 268 goto out;
268 269 }
269 270 fp->f_size = archsw.arch_readin(fd, fp->f_addr, st.st_size);
270 271
271 272 if (fp->f_size != st.st_size) {
272 273 printf("error reading: %s", strerror(errno));
273 274 file_discard(fp);
274 275 error = EIO;
275 276 goto out;
276 277 }
277 278
278 279 fp->f_name = strdup(filename);
279 280 fp->f_type = strdup("aout multiboot2 kernel");
280 281 if (fp->f_name == NULL || fp->f_type == NULL) {
281 282 error = ENOMEM;
282 283 file_discard(fp);
283 284 goto out;
284 285 }
285 286
286 287 fp->f_metadata = NULL;
287 288 error = 0;
288 289 } else {
289 290 #if defined(EFI)
290 291 /* 32-bit kernel is not yet supported for EFI */
291 292 printf("32-bit kernel is not supported by UEFI loader\n");
292 293 error = ENOTSUP;
293 294 goto out;
294 295 #endif
295 296 /* elf32_loadfile_raw will fill the attributes in fp. */
296 297 error = elf32_loadfile_raw(filename, dest, &fp, 2);
297 298 if (error != 0) {
298 299 printf("elf32_loadfile_raw failed: %d unable to "
299 300 "load multiboot2 kernel\n", error);
300 301 goto out;
301 302 }
302 303 entry_addr = fp->f_addr;
303 304 /*
304 305 * We want the load_addr to have some legal value,
305 306 * so we set it same as the entry_addr.
306 307 * The distinction is important with UEFI, but not
307 308 * with BIOS version, because BIOS version does not use
308 309 * staging area.
309 310 */
310 311 load_addr = fp->f_addr;
311 312 }
312 313
313 314 setenv("kernelname", fp->f_name, 1);
314 315 #if defined(EFI)
315 316 efi_addsmapdata(fp);
316 317 #else
317 318 bios_addsmapdata(fp);
318 319 #endif
319 320 *result = fp;
320 321 out:
321 322 free(header_search);
322 323 close(fd);
323 324 return (error);
324 325 }
325 326
326 327 /*
327 328 * Search the command line for named property.
328 329 *
329 330 * Return codes:
330 331 * 0 The name is found, we return the data in value and len.
331 332 * ENOENT The name is not found.
332 333 * EINVAL The provided command line is badly formed.
333 334 */
334 335 static int
335 336 find_property_value(const char *cmd, const char *name, const char **value,
336 337 size_t *len)
337 338 {
338 339 const char *namep, *valuep;
339 340 size_t name_len, value_len;
340 341 int quoted;
341 342
342 343 *value = NULL;
343 344 *len = 0;
344 345
345 346 if (cmd == NULL)
346 347 return (ENOENT);
347 348
348 349 while (*cmd != '\0') {
349 350 if (cmd[0] != '-' || cmd[1] != 'B') {
350 351 cmd++;
351 352 continue;
352 353 }
353 354 cmd += 2; /* Skip -B */
354 355 while (cmd[0] == ' ' || cmd[0] == '\t')
355 356 cmd++; /* Skip whitespaces. */
356 357 while (*cmd != '\0' && cmd[0] != ' ' && cmd[0] != '\t') {
357 358 namep = cmd;
358 359 valuep = strchr(cmd, '=');
359 360 if (valuep == NULL)
360 361 break;
361 362 name_len = valuep - namep;
362 363 valuep++;
363 364 value_len = 0;
364 365 quoted = 0;
365 366 for (; ; ++value_len) {
366 367 if (valuep[value_len] == '\0')
367 368 break;
368 369
369 370 /* Is this value quoted? */
370 371 if (value_len == 0 &&
371 372 (valuep[0] == '\'' || valuep[0] == '"')) {
372 373 quoted = valuep[0];
373 374 ++value_len;
374 375 }
375 376
376 377 /*
377 378 * In the quote accept any character,
378 379 * but look for ending quote.
379 380 */
380 381 if (quoted != 0) {
381 382 if (valuep[value_len] == quoted)
382 383 quoted = 0;
383 384 continue;
384 385 }
385 386
386 387 /* A comma or white space ends the value. */
387 388 if (valuep[value_len] == ',' ||
388 389 valuep[value_len] == ' ' ||
389 390 valuep[value_len] == '\t')
390 391 break;
391 392 }
392 393 if (quoted != 0) {
393 394 printf("Missing closing '%c' in \"%s\"\n",
394 395 quoted, valuep);
395 396 return (EINVAL);
396 397 }
397 398 if (value_len != 0) {
398 399 if (strncmp(namep, name, name_len) == 0) {
399 400 *value = valuep;
400 401 *len = value_len;
401 402 return (0);
402 403 }
403 404 }
404 405 cmd = valuep + value_len;
405 406 while (*cmd == ',')
406 407 cmd++;
407 408 }
408 409 }
409 410 return (ENOENT);
410 411 }
411 412
412 413 /*
413 414 * If command line has " -B ", insert property after "-B ", otherwise
414 415 * append to command line.
415 416 */
416 417 static char *
417 418 insert_cmdline(const char *head, const char *prop)
418 419 {
419 420 const char *prop_opt = " -B ";
420 421 char *cmdline, *tail;
421 422 int len = 0;
422 423
423 424 tail = strstr(head, prop_opt);
424 425 if (tail != NULL) {
425 426 ptrdiff_t diff;
426 427 tail += strlen(prop_opt);
427 428 diff = tail - head;
428 429 if (diff >= INT_MAX)
429 430 return (NULL);
430 431 len = (int)diff;
431 432 }
432 433
433 434 if (tail == NULL)
434 435 asprintf(&cmdline, "%s%s%s", head, prop_opt, prop);
435 436 else
436 437 asprintf(&cmdline, "%.*s%s,%s", len, head, prop, tail);
437 438
438 439 return (cmdline);
439 440 }
440 441
441 442 /*
442 443 * Since we have no way to pass the environment to the mb1 kernel other than
443 444 * through arguments, we need to take care of console setup.
444 445 *
445 446 * If the console is in mirror mode, set the kernel console from $os_console.
446 447 * If it's unset, use first item from $console.
447 448 * If $console is "ttyX", also pass $ttyX-mode, since it may have been set by
448 449 * the user.
449 450 *
450 451 * In case of memory allocation errors, just return the original command line
451 452 * so we have a chance of booting.
452 453 *
453 454 * On success, cl will be freed and a new, allocated command line string is
454 455 * returned.
455 456 *
456 457 * For the mb2 kernel, we only set command line console if os_console is set.
457 458 * We can not overwrite console in the environment, as it can disrupt the
458 459 * loader console messages, and we do not want to deal with the os_console
459 460 * in the kernel.
460 461 */
461 462 static char *
462 463 update_cmdline(char *cl, bool mb2)
463 464 {
464 465 char *os_console = getenv("os_console");
465 466 char *ttymode = NULL;
466 467 char mode[10];
467 468 char *tmp;
468 469 const char *prop;
469 470 size_t plen;
470 471 int rv;
471 472
472 473 if (mb2 == true && os_console == NULL)
473 474 return (cl);
474 475
475 476 if (os_console == NULL) {
476 477 tmp = strdup(getenv("console"));
477 478 os_console = strsep(&tmp, ", ");
478 479 } else {
479 480 os_console = strdup(os_console);
480 481 }
481 482
482 483 if (os_console == NULL)
483 484 return (cl);
484 485
485 486 if (mb2 == false && strncmp(os_console, "tty", 3) == 0) {
486 487 snprintf(mode, sizeof (mode), "%s-mode", os_console);
487 488 /*
488 489 * The ttyX-mode variable is set by our serial console
489 490 * driver for ttya-ttyd. However, since the os_console
490 491 * values are not verified, it is possible we get bogus
491 492 * name and no mode variable. If so, we do not set console
492 493 * property and let the kernel use defaults.
493 494 */
494 495 if ((ttymode = getenv(mode)) == NULL)
495 496 return (cl);
496 497 }
497 498
498 499 rv = find_property_value(cl, "console", &prop, &plen);
499 500 if (rv != 0 && rv != ENOENT) {
500 501 free(os_console);
501 502 return (cl);
502 503 }
503 504
504 505 /* If console is set and this is MB2 boot, we are done. */
505 506 if (rv == 0 && mb2 == true) {
506 507 free(os_console);
507 508 return (cl);
508 509 }
509 510
510 511 /* If console is set, do we need to set tty mode? */
511 512 if (rv == 0) {
512 513 const char *ttyp = NULL;
513 514 size_t ttylen;
514 515
515 516 free(os_console);
516 517 os_console = NULL;
517 518 *mode = '\0';
518 519 if (strncmp(prop, "tty", 3) == 0 && plen == 4) {
519 520 strncpy(mode, prop, plen);
520 521 mode[plen] = '\0';
521 522 strncat(mode, "-mode", 5);
522 523 find_property_value(cl, mode, &ttyp, &ttylen);
523 524 }
524 525
525 526 if (*mode != '\0' && ttyp == NULL)
526 527 ttymode = getenv(mode);
527 528 else
528 529 return (cl);
529 530 }
530 531
531 532 /* Build updated command line. */
532 533 if (os_console != NULL) {
533 534 char *propstr;
534 535
535 536 asprintf(&propstr, "console=%s", os_console);
536 537 free(os_console);
537 538 if (propstr == NULL) {
538 539 return (cl);
539 540 }
540 541
541 542 tmp = insert_cmdline(cl, propstr);
542 543 free(propstr);
543 544 if (tmp == NULL)
544 545 return (cl);
545 546
546 547 free(cl);
547 548 cl = tmp;
548 549 }
549 550 if (ttymode != NULL) {
550 551 char *propstr;
551 552
552 553 asprintf(&propstr, "%s=\"%s\"", mode, ttymode);
553 554 if (propstr == NULL)
554 555 return (cl);
555 556
556 557 tmp = insert_cmdline(cl, propstr);
557 558 free(propstr);
558 559 if (tmp == NULL)
559 560 return (cl);
560 561 free(cl);
561 562 cl = tmp;
562 563 }
563 564
564 565 return (cl);
565 566 }
566 567
567 568 /*
568 569 * Build the kernel command line. Shared function between MB1 and MB2.
569 570 *
570 571 * In both cases, if fstype is set and is not zfs, we do not set up
571 572 * zfs-bootfs property. But we set kernel file name and options.
572 573 *
573 574 * For the MB1, we only can pass properties on command line, so
574 575 * we will set console, ttyX-mode (for serial console) and zfs-bootfs.
575 576 *
576 577 * For the MB2, we can pass properties in environment, but if os_console
577 578 * is set in environment, we need to add console property on the kernel
578 579 * command line.
579 580 *
580 581 * The console properties are managed in update_cmdline().
581 582 */
582 583 int
583 584 mb_kernel_cmdline(struct preloaded_file *fp, struct devdesc *rootdev,
584 585 char **line)
585 586 {
586 587 const char *fs = getenv("fstype");
587 588 char *cmdline;
588 589 size_t len;
589 590 bool zfs_root = false;
590 591 bool mb2;
591 592 int rv;
592 593
593 594 /*
594 595 * 64-bit kernel has aout header, 32-bit kernel is elf, and the
595 596 * type strings are different. Lets just search for "multiboot2".
596 597 */
597 598 if (strstr(fp->f_type, "multiboot2") == NULL)
598 599 mb2 = false;
599 600 else
600 601 mb2 = true;
601 602
602 603 if (rootdev->d_dev->dv_type == DEVT_ZFS)
603 604 zfs_root = true;
604 605
605 606 /* If we have fstype set in env, reset zfs_root if needed. */
606 607 if (fs != NULL && strcmp(fs, "zfs") != 0)
607 608 zfs_root = false;
608 609
609 610 /*
610 611 * If we have fstype set on the command line,
611 612 * reset zfs_root if needed.
612 613 */
613 614 rv = find_property_value(fp->f_args, "fstype", &fs, &len);
614 615 if (rv != 0 && rv != ENOENT)
615 616 return (rv);
616 617
617 618 if (fs != NULL && strncmp(fs, "zfs", len) != 0)
618 619 zfs_root = false;
619 620
620 621 /* zfs_bootfs() will set the environment, it must be called. */
621 622 if (zfs_root == true)
622 623 fs = zfs_bootfs(rootdev);
623 624
624 625 if (fp->f_args == NULL)
625 626 cmdline = strdup(fp->f_name);
626 627 else
627 628 asprintf(&cmdline, "%s %s", fp->f_name, fp->f_args);
628 629
629 630 if (cmdline == NULL)
630 631 return (ENOMEM);
631 632
632 633 /* Append zfs-bootfs for MB1 command line. */
633 634 if (mb2 == false && zfs_root == true) {
634 635 char *tmp;
635 636
636 637 tmp = insert_cmdline(cmdline, fs);
637 638 free(cmdline);
638 639 if (tmp == NULL)
639 640 return (ENOMEM);
640 641 cmdline = tmp;
641 642 }
642 643
643 644 *line = update_cmdline(cmdline, mb2);
644 645 return (0);
645 646 }
646 647
647 648 /*
648 649 * Returns allocated virtual address from MB info area.
649 650 */
650 651 static vm_offset_t
651 652 mb_malloc(size_t n)
652 653 {
653 654 vm_offset_t ptr = last_addr;
654 655 last_addr = roundup(last_addr + n, MULTIBOOT_TAG_ALIGN);
655 656 return (ptr);
656 657 }
657 658
658 659 /*
659 660 * Calculate size for module tag list.
660 661 */
661 662 static size_t
662 663 module_size(struct preloaded_file *fp)
663 664 {
664 665 size_t len, size;
665 666 struct preloaded_file *mfp;
666 667
667 668 size = 0;
668 669 for (mfp = fp->f_next; mfp != NULL; mfp = mfp->f_next) {
669 670 len = strlen(mfp->f_name) + 1;
670 671 len += strlen(mfp->f_type) + 5 + 1; /* 5 is for "type=" */
671 672 if (mfp->f_args != NULL)
672 673 len += strlen(mfp->f_args) + 1;
673 674 size += sizeof (multiboot_tag_module_t) + len;
674 675 size = roundup(size, MULTIBOOT_TAG_ALIGN);
675 676 }
676 677 return (size);
677 678 }
678 679
679 680 #if defined(EFI)
680 681 /*
681 682 * Calculate size for UEFI memory map tag.
682 683 */
683 684 static int
684 685 efimemmap_size(void)
685 686 {
686 687 UINTN size, cur_size, desc_size;
687 688 EFI_MEMORY_DESCRIPTOR *mmap;
688 689 EFI_STATUS ret;
689 690
690 691 size = EFI_PAGE_SIZE; /* Start with 4k. */
691 692 while (1) {
692 693 cur_size = size;
693 694 mmap = malloc(cur_size);
694 695 if (mmap == NULL)
695 696 return (0);
696 697 ret = BS->GetMemoryMap(&cur_size, mmap, NULL, &desc_size, NULL);
697 698 free(mmap);
698 699 if (ret == EFI_SUCCESS)
699 700 break;
700 701 if (ret == EFI_BUFFER_TOO_SMALL) {
701 702 if (size < cur_size)
702 703 size = cur_size;
703 704 size += (EFI_PAGE_SIZE);
704 705 } else
705 706 return (0);
706 707 }
707 708
708 709 /* EFI MMAP will grow when we allocate MBI, set some buffer. */
709 710 size += (3 << EFI_PAGE_SHIFT);
710 711 size = roundup(size, desc_size);
711 712 return (sizeof (multiboot_tag_efi_mmap_t) + size);
712 713 }
713 714 #endif
714 715
715 716 /*
716 717 * Calculate size for bios smap tag.
717 718 */
718 719 static size_t
719 720 biossmap_size(struct preloaded_file *fp)
720 721 {
721 722 int num;
722 723 struct file_metadata *md;
723 724
724 725 md = file_findmetadata(fp, MODINFOMD_SMAP);
725 726 if (md == NULL)
726 727 return (0);
727 728
728 729 num = md->md_size / sizeof (struct bios_smap); /* number of entries */
729 730 return (sizeof (multiboot_tag_mmap_t) +
730 731 num * sizeof (multiboot_mmap_entry_t));
731 732 }
732 733
733 734 static size_t
734 735 mbi_size(struct preloaded_file *fp, char *cmdline)
735 736 {
736 737 size_t size;
737 738 #if !defined(EFI)
738 739 extern multiboot_tag_framebuffer_t gfx_fb;
739 740 #endif
740 741
741 742 size = sizeof (uint32_t) * 2; /* first 2 fields from MBI header */
742 743 size += sizeof (multiboot_tag_string_t) + strlen(cmdline) + 1;
743 744 size = roundup2(size, MULTIBOOT_TAG_ALIGN);
744 745 size += sizeof (multiboot_tag_string_t) + strlen(bootprog_info) + 1;
745 746 size = roundup2(size, MULTIBOOT_TAG_ALIGN);
746 747 #if !defined(EFI)
747 748 size += sizeof (multiboot_tag_basic_meminfo_t);
748 749 size = roundup2(size, MULTIBOOT_TAG_ALIGN);
749 750 #endif
750 751 size += module_size(fp);
751 752 size = roundup2(size, MULTIBOOT_TAG_ALIGN);
752 753 #if defined(EFI)
753 754 size += sizeof (multiboot_tag_efi64_t);
754 755 size = roundup2(size, MULTIBOOT_TAG_ALIGN);
755 756 size += efimemmap_size();
756 757 size = roundup2(size, MULTIBOOT_TAG_ALIGN);
757 758
758 759 if (have_framebuffer == true) {
759 760 size += sizeof (multiboot_tag_framebuffer_t);
760 761 size = roundup2(size, MULTIBOOT_TAG_ALIGN);
761 762 }
762 763 #endif
763 764
764 765 size += biossmap_size(fp);
765 766 size = roundup2(size, MULTIBOOT_TAG_ALIGN);
766 767
767 768 #if !defined(EFI)
768 769 if (gfx_fb.framebuffer_common.framebuffer_type ==
769 770 MULTIBOOT_FRAMEBUFFER_TYPE_INDEXED) {
770 771 size += sizeof (struct multiboot_tag_framebuffer_common);
771 772 size += gfx_fb.u.fb1.framebuffer_palette_num_colors *
772 773 sizeof (multiboot_color_t);
773 774 } else {
774 775 size += sizeof (multiboot_tag_framebuffer_t);
775 776 }
776 777 size = roundup2(size, MULTIBOOT_TAG_ALIGN);
777 778
778 779 size += sizeof (multiboot_tag_vbe_t);
779 780 size = roundup2(size, MULTIBOOT_TAG_ALIGN);
780 781 #endif
781 782
782 783 if (bootp_response != NULL) {
783 784 size += sizeof (multiboot_tag_network_t) + bootp_response_size;
784 785 size = roundup2(size, MULTIBOOT_TAG_ALIGN);
785 786 }
786 787
787 788 if (rsdp != NULL) {
788 789 if (rsdp->Revision == 0) {
789 790 size += sizeof (multiboot_tag_old_acpi_t) +
790 791 sizeof (ACPI_RSDP_COMMON);
791 792 } else {
↓ open down ↓ |
768 lines elided |
↑ open up ↑ |
792 793 size += sizeof (multiboot_tag_new_acpi_t) +
793 794 rsdp->Length;
794 795 }
795 796 size = roundup2(size, MULTIBOOT_TAG_ALIGN);
796 797 }
797 798 size += sizeof (multiboot_tag_t);
798 799
799 800 return (size);
800 801 }
801 802
803 +#if defined(EFI)
804 +static bool
805 +overlaps(uintptr_t start1, size_t size1, uintptr_t start2, size_t size2)
806 +{
807 + if (start1 < start2 + size2 &&
808 + start1 + size1 >= start2) {
809 + printf("overlaps: %zx-%zx, %zx-%zx\n",
810 + start1, start1 + size1, start2, start2 + size2);
811 + return (true);
812 + }
813 +
814 + return (false);
815 +}
816 +#endif
817 +
802 818 static int
803 819 multiboot2_exec(struct preloaded_file *fp)
804 820 {
821 + multiboot2_info_header_t *mbi = NULL;
805 822 struct preloaded_file *mfp;
806 - multiboot2_info_header_t *mbi;
807 823 char *cmdline = NULL;
808 824 struct devdesc *rootdev;
809 825 struct file_metadata *md;
810 826 int i, error, num;
811 827 int rootfs = 0;
812 828 size_t size;
813 829 struct bios_smap *smap;
814 830 #if defined(EFI)
815 831 multiboot_tag_module_t *module, *mp;
832 + struct relocator *relocator = NULL;
816 833 EFI_MEMORY_DESCRIPTOR *map;
817 834 UINTN map_size, desc_size;
818 - struct relocator *relocator;
819 835 struct chunk_head *head;
820 836 struct chunk *chunk;
821 837 vm_offset_t tmp;
822 838
823 839 efi_getdev((void **)(&rootdev), NULL, NULL);
840 +
841 + /*
842 + * We need 5 pages for relocation. We'll allocate from the heap: while
843 + * it's possible that our heap got placed low down enough to be in the
844 + * way of where we're going to relocate our kernel, it's hopefully not
845 + * likely.
846 + */
847 + if ((relocator = malloc(EFI_PAGE_SIZE * 5)) == NULL) {
848 + printf("relocator malloc failed!\n");
849 + error = ENOMEM;
850 + goto error;
851 + }
852 +
853 + if (overlaps((uintptr_t)relocator, EFI_PAGE_SIZE * 5,
854 + load_addr, fp->f_size)) {
855 + printf("relocator pages overlap the kernel!\n");
856 + error = EINVAL;
857 + goto error;
858 + }
859 +
824 860 #else
825 861 i386_getdev((void **)(&rootdev), NULL, NULL);
826 862
827 863 if (have_framebuffer == false) {
828 864 /* make sure we have text mode */
829 865 bios_set_text_mode(VGA_TEXT_MODE);
830 866 }
831 867 #endif
832 868
833 - mbi = NULL;
834 869 error = EINVAL;
835 870 if (rootdev == NULL) {
836 871 printf("can't determine root device\n");
837 872 goto error;
838 873 }
839 874
840 875 /*
841 876 * Set the image command line.
842 877 */
843 878 if (fp->f_args == NULL) {
844 879 cmdline = getenv("boot-args");
845 880 if (cmdline != NULL) {
846 881 fp->f_args = strdup(cmdline);
847 882 if (fp->f_args == NULL) {
848 883 error = ENOMEM;
849 884 goto error;
850 885 }
851 886 }
852 887 }
853 888
854 889 error = mb_kernel_cmdline(fp, rootdev, &cmdline);
855 890 if (error != 0)
856 891 goto error;
857 892
858 893 /* mb_kernel_cmdline() updates the environment. */
859 894 build_environment_module();
860 895
861 896 if (have_framebuffer == true) {
862 897 /* Pass the loaded console font for kernel. */
863 898 build_font_module();
864 899 }
865 900
866 901 size = mbi_size(fp, cmdline); /* Get the size for MBI. */
867 902
868 903 /* Set up the base for mb_malloc. */
869 904 i = 0;
870 905 for (mfp = fp; mfp->f_next != NULL; mfp = mfp->f_next)
871 906 i++;
872 907
873 908 #if defined(EFI)
874 909 /* We need space for kernel + MBI + # modules */
875 910 num = (EFI_PAGE_SIZE - offsetof(struct relocator, rel_chunklist)) /
876 911 sizeof (struct chunk);
877 912 if (i + 2 >= num) {
878 913 printf("Too many modules, do not have space for relocator.\n");
879 914 error = ENOMEM;
880 915 goto error;
881 916 }
882 917
883 918 last_addr = efi_loadaddr(LOAD_MEM, &size, mfp->f_addr + mfp->f_size);
884 919 mbi = (multiboot2_info_header_t *)last_addr;
885 920 if (mbi == NULL) {
886 921 error = ENOMEM;
887 922 goto error;
888 923 }
889 924 last_addr = (vm_offset_t)mbi->mbi_tags;
890 925 #else
891 926 /* Start info block from the new page. */
892 927 last_addr = i386_loadaddr(LOAD_MEM, &size, mfp->f_addr + mfp->f_size);
893 928
894 929 /* Do we have space for multiboot info? */
895 930 if (last_addr + size >= memtop_copyin) {
896 931 error = ENOMEM;
897 932 goto error;
898 933 }
899 934
900 935 mbi = (multiboot2_info_header_t *)PTOV(last_addr);
901 936 last_addr = (vm_offset_t)mbi->mbi_tags;
902 937 #endif /* EFI */
903 938
904 939 {
905 940 multiboot_tag_string_t *tag;
906 941 i = sizeof (multiboot_tag_string_t) + strlen(cmdline) + 1;
907 942 tag = (multiboot_tag_string_t *)mb_malloc(i);
908 943
909 944 tag->mb_type = MULTIBOOT_TAG_TYPE_CMDLINE;
910 945 tag->mb_size = i;
911 946 memcpy(tag->mb_string, cmdline, strlen(cmdline) + 1);
912 947 free(cmdline);
913 948 cmdline = NULL;
914 949 }
915 950
916 951 {
917 952 multiboot_tag_string_t *tag;
918 953 i = sizeof (multiboot_tag_string_t) + strlen(bootprog_info) + 1;
919 954 tag = (multiboot_tag_string_t *)mb_malloc(i);
920 955
921 956 tag->mb_type = MULTIBOOT_TAG_TYPE_BOOT_LOADER_NAME;
922 957 tag->mb_size = i;
923 958 memcpy(tag->mb_string, bootprog_info,
924 959 strlen(bootprog_info) + 1);
925 960 }
926 961
927 962 #if !defined(EFI)
928 963 /* Only set in case of BIOS. */
929 964 {
930 965 multiboot_tag_basic_meminfo_t *tag;
931 966 tag = (multiboot_tag_basic_meminfo_t *)
932 967 mb_malloc(sizeof (*tag));
933 968
934 969 tag->mb_type = MULTIBOOT_TAG_TYPE_BASIC_MEMINFO;
935 970 tag->mb_size = sizeof (*tag);
936 971 tag->mb_mem_lower = bios_basemem / 1024;
937 972 tag->mb_mem_upper = bios_extmem / 1024;
938 973 }
939 974 #endif
940 975
941 976 num = 0;
942 977 for (mfp = fp->f_next; mfp != NULL; mfp = mfp->f_next) {
943 978 num++;
944 979 if (mfp->f_type != NULL && strcmp(mfp->f_type, "rootfs") == 0)
945 980 rootfs++;
946 981 }
947 982
948 983 if (num == 0 || rootfs == 0) {
949 984 /* We need at least one module - rootfs. */
950 985 printf("No rootfs module provided, aborting\n");
951 986 error = EINVAL;
952 987 goto error;
953 988 }
954 989
955 990 /*
956 991 * Set the stage for physical memory layout:
957 992 * - We have kernel at load_addr.
958 993 * - Modules are aligned to page boundary.
959 994 * - MBI is aligned to page boundary.
960 995 * - Set the tmp to point to physical address of the first module.
961 996 * - tmp != mfp->f_addr only in case of EFI.
962 997 */
963 998 #if defined(EFI)
964 999 tmp = roundup2(load_addr + fp->f_size + 1, MULTIBOOT_MOD_ALIGN);
965 1000 module = (multiboot_tag_module_t *)last_addr;
966 1001 #endif
967 1002
968 1003 for (mfp = fp->f_next; mfp != NULL; mfp = mfp->f_next) {
969 1004 multiboot_tag_module_t *tag;
970 1005
971 1006 num = strlen(mfp->f_name) + 1;
972 1007 num += strlen(mfp->f_type) + 5 + 1;
973 1008 if (mfp->f_args != NULL) {
974 1009 num += strlen(mfp->f_args) + 1;
975 1010 }
976 1011 cmdline = malloc(num);
977 1012 if (cmdline == NULL) {
978 1013 error = ENOMEM;
979 1014 goto error;
980 1015 }
981 1016
982 1017 if (mfp->f_args != NULL)
983 1018 snprintf(cmdline, num, "%s type=%s %s",
984 1019 mfp->f_name, mfp->f_type, mfp->f_args);
985 1020 else
986 1021 snprintf(cmdline, num, "%s type=%s",
987 1022 mfp->f_name, mfp->f_type);
988 1023
989 1024 tag = (multiboot_tag_module_t *)mb_malloc(sizeof (*tag) + num);
990 1025
991 1026 tag->mb_type = MULTIBOOT_TAG_TYPE_MODULE;
992 1027 tag->mb_size = sizeof (*tag) + num;
993 1028 #if defined(EFI)
994 1029 /*
995 1030 * We can assign module addresses only after BS have been
996 1031 * switched off.
997 1032 */
998 1033 tag->mb_mod_start = 0;
999 1034 tag->mb_mod_end = mfp->f_size;
1000 1035 #else
1001 1036 tag->mb_mod_start = mfp->f_addr;
1002 1037 tag->mb_mod_end = mfp->f_addr + mfp->f_size;
1003 1038 #endif
1004 1039 memcpy(tag->mb_cmdline, cmdline, num);
1005 1040 free(cmdline);
1006 1041 cmdline = NULL;
1007 1042 }
1008 1043
1009 1044 md = file_findmetadata(fp, MODINFOMD_SMAP);
1010 1045 if (md == NULL) {
1011 1046 printf("no memory smap\n");
1012 1047 error = EINVAL;
1013 1048 goto error;
1014 1049 }
1015 1050
1016 1051 smap = (struct bios_smap *)md->md_data;
1017 1052 num = md->md_size / sizeof (struct bios_smap); /* number of entries */
1018 1053
1019 1054 {
1020 1055 multiboot_tag_mmap_t *tag;
1021 1056 multiboot_mmap_entry_t *mmap_entry;
1022 1057
1023 1058 tag = (multiboot_tag_mmap_t *)
1024 1059 mb_malloc(sizeof (*tag) +
1025 1060 num * sizeof (multiboot_mmap_entry_t));
1026 1061
1027 1062 tag->mb_type = MULTIBOOT_TAG_TYPE_MMAP;
1028 1063 tag->mb_size = sizeof (*tag) +
1029 1064 num * sizeof (multiboot_mmap_entry_t);
1030 1065 tag->mb_entry_size = sizeof (multiboot_mmap_entry_t);
1031 1066 tag->mb_entry_version = 0;
1032 1067 mmap_entry = (multiboot_mmap_entry_t *)tag->mb_entries;
1033 1068
1034 1069 for (i = 0; i < num; i++) {
1035 1070 mmap_entry[i].mmap_addr = smap[i].base;
1036 1071 mmap_entry[i].mmap_len = smap[i].length;
1037 1072 mmap_entry[i].mmap_type = smap[i].type;
1038 1073 mmap_entry[i].mmap_reserved = 0;
1039 1074 }
1040 1075 }
1041 1076
1042 1077 if (bootp_response != NULL) {
1043 1078 multiboot_tag_network_t *tag;
1044 1079 tag = (multiboot_tag_network_t *)
1045 1080 mb_malloc(sizeof (*tag) + bootp_response_size);
1046 1081
1047 1082 tag->mb_type = MULTIBOOT_TAG_TYPE_NETWORK;
1048 1083 tag->mb_size = sizeof (*tag) + bootp_response_size;
1049 1084 memcpy(tag->mb_dhcpack, bootp_response, bootp_response_size);
1050 1085 }
1051 1086
1052 1087 #if !defined(EFI)
1053 1088 multiboot_tag_vbe_t *tag;
1054 1089 extern multiboot_tag_vbe_t vbestate;
1055 1090
1056 1091 if (VBE_VALID_MODE(vbestate.vbe_mode)) {
1057 1092 tag = (multiboot_tag_vbe_t *)mb_malloc(sizeof (*tag));
1058 1093 memcpy(tag, &vbestate, sizeof (*tag));
1059 1094 tag->mb_type = MULTIBOOT_TAG_TYPE_VBE;
1060 1095 tag->mb_size = sizeof (*tag);
1061 1096 }
1062 1097 #endif
1063 1098
1064 1099 if (rsdp != NULL) {
1065 1100 multiboot_tag_new_acpi_t *ntag;
1066 1101 multiboot_tag_old_acpi_t *otag;
1067 1102 uint32_t tsize;
1068 1103
1069 1104 if (rsdp->Revision == 0) {
1070 1105 tsize = sizeof (*otag) + sizeof (ACPI_RSDP_COMMON);
1071 1106 otag = (multiboot_tag_old_acpi_t *)mb_malloc(tsize);
1072 1107 otag->mb_type = MULTIBOOT_TAG_TYPE_ACPI_OLD;
1073 1108 otag->mb_size = tsize;
1074 1109 memcpy(otag->mb_rsdp, rsdp, sizeof (ACPI_RSDP_COMMON));
1075 1110 } else {
1076 1111 tsize = sizeof (*ntag) + rsdp->Length;
1077 1112 ntag = (multiboot_tag_new_acpi_t *)mb_malloc(tsize);
1078 1113 ntag->mb_type = MULTIBOOT_TAG_TYPE_ACPI_NEW;
1079 1114 ntag->mb_size = tsize;
1080 1115 memcpy(ntag->mb_rsdp, rsdp, rsdp->Length);
1081 1116 }
1082 1117 }
1083 1118
1084 1119 #if defined(EFI)
1085 1120 #ifdef __LP64__
1086 1121 {
1087 1122 multiboot_tag_efi64_t *tag;
1088 1123 tag = (multiboot_tag_efi64_t *)
1089 1124 mb_malloc(sizeof (*tag));
1090 1125
1091 1126 tag->mb_type = MULTIBOOT_TAG_TYPE_EFI64;
1092 1127 tag->mb_size = sizeof (*tag);
1093 1128 tag->mb_pointer = (uint64_t)(uintptr_t)ST;
1094 1129 }
1095 1130 #else
1096 1131 {
1097 1132 multiboot_tag_efi32_t *tag;
1098 1133 tag = (multiboot_tag_efi32_t *)
1099 1134 mb_malloc(sizeof (*tag));
1100 1135
1101 1136 tag->mb_type = MULTIBOOT_TAG_TYPE_EFI32;
1102 1137 tag->mb_size = sizeof (*tag);
1103 1138 tag->mb_pointer = (uint32_t)ST;
1104 1139 }
1105 1140 #endif /* __LP64__ */
1106 1141 #endif /* EFI */
1107 1142
1108 1143 if (have_framebuffer == true) {
1109 1144 multiboot_tag_framebuffer_t *tag;
1110 1145 extern multiboot_tag_framebuffer_t gfx_fb;
1111 1146 #if defined(EFI)
1112 1147
1113 1148 tag = (multiboot_tag_framebuffer_t *)mb_malloc(sizeof (*tag));
1114 1149 memcpy(tag, &gfx_fb, sizeof (*tag));
1115 1150 tag->framebuffer_common.mb_type =
1116 1151 MULTIBOOT_TAG_TYPE_FRAMEBUFFER;
1117 1152 tag->framebuffer_common.mb_size = sizeof (*tag);
1118 1153 #else
1119 1154 extern multiboot_color_t *cmap;
1120 1155 uint32_t size;
1121 1156
1122 1157 if (gfx_fb.framebuffer_common.framebuffer_type ==
1123 1158 MULTIBOOT_FRAMEBUFFER_TYPE_INDEXED) {
1124 1159 uint16_t nc;
1125 1160 nc = gfx_fb.u.fb1.framebuffer_palette_num_colors;
1126 1161 size = sizeof (struct multiboot_tag_framebuffer_common)
1127 1162 + sizeof (nc)
1128 1163 + nc * sizeof (multiboot_color_t);
1129 1164 } else {
1130 1165 size = sizeof (gfx_fb);
1131 1166 }
1132 1167
1133 1168 tag = (multiboot_tag_framebuffer_t *)mb_malloc(size);
1134 1169 memcpy(tag, &gfx_fb, sizeof (*tag));
1135 1170
1136 1171 tag->framebuffer_common.mb_type =
1137 1172 MULTIBOOT_TAG_TYPE_FRAMEBUFFER;
1138 1173 tag->framebuffer_common.mb_size = size;
1139 1174
1140 1175 if (gfx_fb.framebuffer_common.framebuffer_type ==
1141 1176 MULTIBOOT_FRAMEBUFFER_TYPE_INDEXED) {
1142 1177 memcpy(tag->u.fb1.framebuffer_palette, cmap,
1143 1178 sizeof (multiboot_color_t) *
1144 1179 gfx_fb.u.fb1.framebuffer_palette_num_colors);
1145 1180 }
1146 1181 #endif /* EFI */
1147 1182 }
1148 1183
1149 1184 #if defined(EFI)
1150 1185 /* Leave EFI memmap last as we will also switch off the BS. */
1151 1186 {
1152 1187 multiboot_tag_efi_mmap_t *tag;
1153 1188 UINTN key;
1154 1189 EFI_STATUS status;
1155 1190
1156 1191 tag = (multiboot_tag_efi_mmap_t *)
1157 1192 mb_malloc(sizeof (*tag));
1158 1193
1159 1194 map_size = 0;
1160 1195 status = BS->GetMemoryMap(&map_size,
1161 1196 (EFI_MEMORY_DESCRIPTOR *)tag->mb_efi_mmap, &key,
1162 1197 &desc_size, &tag->mb_descr_vers);
1163 1198 if (status != EFI_BUFFER_TOO_SMALL) {
1164 1199 error = EINVAL;
1165 1200 goto error;
1166 1201 }
1167 1202 status = BS->GetMemoryMap(&map_size,
↓ open down ↓ |
324 lines elided |
↑ open up ↑ |
1168 1203 (EFI_MEMORY_DESCRIPTOR *)tag->mb_efi_mmap, &key,
1169 1204 &desc_size, &tag->mb_descr_vers);
1170 1205 if (EFI_ERROR(status)) {
1171 1206 error = EINVAL;
1172 1207 goto error;
1173 1208 }
1174 1209 tag->mb_type = MULTIBOOT_TAG_TYPE_EFI_MMAP;
1175 1210 tag->mb_size = sizeof (*tag) + map_size;
1176 1211 tag->mb_descr_size = (uint32_t)desc_size;
1177 1212
1178 - /*
1179 - * Find relocater pages. We assume we have free pages
1180 - * below kernel load address.
1181 - * In this version we are using 5 pages:
1182 - * relocator data, trampoline, copy, memmove, stack.
1183 - */
1184 - for (i = 0, map = (EFI_MEMORY_DESCRIPTOR *)tag->mb_efi_mmap;
1185 - i < map_size / desc_size;
1186 - i++, map = NextMemoryDescriptor(map, desc_size)) {
1187 - if (map->PhysicalStart == 0)
1188 - continue;
1189 - if (map->Type != EfiConventionalMemory)
1190 - continue;
1191 - if (map->PhysicalStart < load_addr &&
1192 - map->NumberOfPages > 5)
1193 - break;
1194 - }
1195 - if (map->PhysicalStart == 0)
1196 - panic("Could not find memory for relocater");
1213 + map = (EFI_MEMORY_DESCRIPTOR *)tag->mb_efi_mmap;
1197 1214
1198 1215 if (keep_bs == 0) {
1199 1216 status = BS->ExitBootServices(IH, key);
1200 1217 if (EFI_ERROR(status)) {
1201 1218 printf("Call to ExitBootServices failed\n");
1202 1219 error = EINVAL;
1203 1220 goto error;
1204 1221 }
1205 1222 }
1206 1223
1207 1224 last_addr += map_size;
1208 1225 last_addr = roundup2(last_addr, MULTIBOOT_TAG_ALIGN);
1209 1226 }
1210 1227 #endif /* EFI */
1211 1228
1212 1229 /*
1213 1230 * MB tag list end marker.
1214 1231 */
1215 1232 {
1216 1233 multiboot_tag_t *tag = (multiboot_tag_t *)
1217 1234 mb_malloc(sizeof (*tag));
1218 1235 tag->mb_type = MULTIBOOT_TAG_TYPE_END;
1219 1236 tag->mb_size = sizeof (*tag);
1220 1237 }
1221 1238
1222 1239 mbi->mbi_total_size = last_addr - (vm_offset_t)mbi;
↓ open down ↓ |
16 lines elided |
↑ open up ↑ |
1223 1240 mbi->mbi_reserved = 0;
1224 1241
1225 1242 #if defined(EFI)
1226 1243 /*
1227 1244 * At this point we have load_addr pointing to kernel load
1228 1245 * address, module list in MBI having physical addresses,
1229 1246 * module list in fp having logical addresses and tmp pointing to
1230 1247 * physical address for MBI.
1231 1248 * Now we must move all pieces to place and start the kernel.
1232 1249 */
1233 - relocator = (struct relocator *)(uintptr_t)map->PhysicalStart;
1234 1250 head = &relocator->rel_chunk_head;
1235 1251 STAILQ_INIT(head);
1236 1252
1237 1253 i = 0;
1238 1254 chunk = &relocator->rel_chunklist[i++];
1239 1255 chunk->chunk_vaddr = fp->f_addr;
1240 1256 chunk->chunk_paddr = load_addr;
1241 1257 chunk->chunk_size = fp->f_size;
1242 1258
1243 1259 STAILQ_INSERT_TAIL(head, chunk, chunk_next);
1244 1260
1245 1261 mp = module;
1246 1262 for (mfp = fp->f_next; mfp != NULL; mfp = mfp->f_next) {
1247 1263 chunk = &relocator->rel_chunklist[i++];
1248 1264 chunk->chunk_vaddr = mfp->f_addr;
1249 1265
1250 1266 /*
1251 1267 * fix the mb_mod_start and mb_mod_end.
1252 1268 */
1253 1269 mp->mb_mod_start = efi_physaddr(module, tmp, map,
1254 1270 map_size / desc_size, desc_size, mp->mb_mod_end);
1255 1271 if (mp->mb_mod_start == 0)
1256 1272 panic("Could not find memory for module");
1257 1273
1258 1274 mp->mb_mod_end += mp->mb_mod_start;
1259 1275 chunk->chunk_paddr = mp->mb_mod_start;
1260 1276 chunk->chunk_size = mfp->f_size;
1261 1277 STAILQ_INSERT_TAIL(head, chunk, chunk_next);
1262 1278
1263 1279 mp = (multiboot_tag_module_t *)
1264 1280 roundup2((uintptr_t)mp + mp->mb_size,
1265 1281 MULTIBOOT_TAG_ALIGN);
1266 1282 }
1267 1283 chunk = &relocator->rel_chunklist[i++];
1268 1284 chunk->chunk_vaddr = (EFI_VIRTUAL_ADDRESS)(uintptr_t)mbi;
1269 1285 chunk->chunk_paddr = efi_physaddr(module, tmp, map,
1270 1286 map_size / desc_size, desc_size, mbi->mbi_total_size);
1271 1287 chunk->chunk_size = mbi->mbi_total_size;
1272 1288 STAILQ_INSERT_TAIL(head, chunk, chunk_next);
1273 1289
1274 1290 trampoline = (void *)(uintptr_t)relocator + EFI_PAGE_SIZE;
1275 1291 memmove(trampoline, multiboot_tramp, EFI_PAGE_SIZE);
1276 1292
1277 1293 relocator->rel_copy = (uintptr_t)trampoline + EFI_PAGE_SIZE;
1278 1294 memmove((void *)relocator->rel_copy, efi_copy_finish, EFI_PAGE_SIZE);
1279 1295
1280 1296 relocator->rel_memmove = (uintptr_t)relocator->rel_copy + EFI_PAGE_SIZE;
1281 1297 memmove((void *)relocator->rel_memmove, memmove, EFI_PAGE_SIZE);
1282 1298 relocator->rel_stack = relocator->rel_memmove + EFI_PAGE_SIZE - 8;
↓ open down ↓ |
39 lines elided |
↑ open up ↑ |
1283 1299
1284 1300 trampoline(MULTIBOOT2_BOOTLOADER_MAGIC, relocator, entry_addr);
1285 1301 #else
1286 1302 dev_cleanup();
1287 1303 __exec((void *)VTOP(multiboot_tramp), MULTIBOOT2_BOOTLOADER_MAGIC,
1288 1304 (void *)entry_addr, (void *)VTOP(mbi));
1289 1305 #endif /* EFI */
1290 1306 panic("exec returned");
1291 1307
1292 1308 error:
1293 - if (cmdline != NULL)
1294 - free(cmdline);
1309 + free(cmdline);
1310 +
1295 1311 #if defined(EFI)
1312 + free(relocator);
1313 +
1296 1314 if (mbi != NULL)
1297 1315 efi_free_loadaddr((vm_offset_t)mbi, EFI_SIZE_TO_PAGES(size));
1298 1316 #endif
1317 +
1299 1318 return (error);
1300 1319 }
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX