1 /* 2 * This file and its contents are supplied under the terms of the 3 * Common Development and Distribution License ("CDDL"), version 1.0. 4 * You may only use this file in accordance with the terms of version 5 * 1.0 of the CDDL. 6 * 7 * A full copy of the text of the CDDL should have accompanied this 8 * source. A copy of the CDDL is also available via the Internet at 9 * http://www.illumos.org/license/CDDL. 10 */ 11 12 /* 13 * Copyright 2017 Toomas Soome <tsoome@me.com> 14 */ 15 16 /* 17 * This module adds support for loading and booting illumos multiboot2 18 * kernel. This code is only built to support the illumos kernel, it does 19 * not support xen. 20 */ 21 #include <sys/cdefs.h> 22 #include <sys/stddef.h> 23 24 #include <sys/param.h> 25 #include <sys/exec.h> 26 #include <sys/linker.h> 27 #include <sys/module.h> 28 #include <sys/stdint.h> 29 #include <sys/multiboot2.h> 30 #include <stand.h> 31 #include <stdbool.h> 32 #include "libzfs.h" 33 34 #include "bootstrap.h" 35 36 #include <machine/metadata.h> 37 #include <machine/pc/bios.h> 38 39 #include "../i386/libi386/libi386.h" 40 #include "../i386/btx/lib/btxv86.h" 41 #include "pxe.h" 42 43 extern BOOTPLAYER bootplayer; /* dhcp info */ 44 extern void multiboot_tramp(); 45 46 #include "platform/acfreebsd.h" 47 #include "acconfig.h" 48 #define ACPI_SYSTEM_XFACE 49 #include "actypes.h" 50 #include "actbl.h" 51 52 extern ACPI_TABLE_RSDP *rsdp; 53 54 /* MB data heap pointer. */ 55 static vm_offset_t last_addr; 56 extern char bootprog_info[]; 57 58 extern int elf32_loadfile_raw(char *filename, u_int64_t dest, 59 struct preloaded_file **result, int multiboot); 60 static int multiboot2_loadfile(char *, u_int64_t, struct preloaded_file **); 61 static int multiboot2_exec(struct preloaded_file *); 62 63 struct file_format multiboot2 = { multiboot2_loadfile, multiboot2_exec }; 64 static bool keep_bs = false; 65 static bool have_framebuffer = false; 66 static vm_offset_t load_addr; 67 static vm_offset_t entry_addr; 68 69 /* 70 * Validate tags in info request. This function is provided just to 71 * recognize the current tag list and only serves as a limited 72 * safe guard against possibly corrupt information. 73 */ 74 static bool 75 is_info_request_valid(multiboot_header_tag_information_request_t *rtag) 76 { 77 int i; 78 79 /* 80 * If the tag is optional and we do not support it, we do not 81 * have to do anything special, so we skip optional tags. 82 */ 83 if (rtag->mbh_flags & MULTIBOOT_HEADER_TAG_OPTIONAL) 84 return (true); 85 86 for (i = 0; i < (rtag->mbh_size - sizeof (*rtag)) / 87 sizeof (rtag->mbh_requests[0]); i++) 88 switch (rtag->mbh_requests[i]) { 89 case MULTIBOOT_TAG_TYPE_END: 90 case MULTIBOOT_TAG_TYPE_CMDLINE: 91 case MULTIBOOT_TAG_TYPE_BOOT_LOADER_NAME: 92 case MULTIBOOT_TAG_TYPE_MODULE: 93 case MULTIBOOT_TAG_TYPE_BASIC_MEMINFO: 94 case MULTIBOOT_TAG_TYPE_BOOTDEV: 95 case MULTIBOOT_TAG_TYPE_MMAP: 96 case MULTIBOOT_TAG_TYPE_FRAMEBUFFER: 97 case MULTIBOOT_TAG_TYPE_VBE: 98 case MULTIBOOT_TAG_TYPE_ELF_SECTIONS: 99 case MULTIBOOT_TAG_TYPE_APM: 100 case MULTIBOOT_TAG_TYPE_EFI32: 101 case MULTIBOOT_TAG_TYPE_EFI64: 102 case MULTIBOOT_TAG_TYPE_ACPI_OLD: 103 case MULTIBOOT_TAG_TYPE_ACPI_NEW: 104 case MULTIBOOT_TAG_TYPE_NETWORK: 105 case MULTIBOOT_TAG_TYPE_EFI_MMAP: 106 case MULTIBOOT_TAG_TYPE_EFI_BS: 107 case MULTIBOOT_TAG_TYPE_EFI32_IH: 108 case MULTIBOOT_TAG_TYPE_EFI64_IH: 109 case MULTIBOOT_TAG_TYPE_LOAD_BASE_ADDR: 110 break; 111 default: 112 printf("unsupported information tag: 0x%x\n", 113 rtag->mbh_requests[i]); 114 return (false); 115 } 116 return (true); 117 } 118 119 static int 120 multiboot2_loadfile(char *filename, u_int64_t dest, 121 struct preloaded_file **result) 122 { 123 int fd, error; 124 uint32_t i; 125 struct stat st; 126 caddr_t header_search; 127 multiboot2_header_t *header; 128 multiboot_header_tag_t *tag; 129 multiboot_header_tag_address_t *addr_tag = NULL; 130 multiboot_header_tag_entry_address_t *entry_tag = NULL; 131 struct preloaded_file *fp; 132 133 /* This allows to check other file formats from file_formats array. */ 134 error = EFTYPE; 135 if (filename == NULL) 136 return (error); 137 138 /* is kernel already loaded? */ 139 fp = file_findfile(NULL, NULL); 140 if (fp != NULL) 141 return (error); 142 143 if ((fd = open(filename, O_RDONLY)) == -1) 144 return (errno); 145 146 /* 147 * Read MULTIBOOT_SEARCH size in order to search for the 148 * multiboot magic header. 149 */ 150 header_search = malloc(MULTIBOOT_SEARCH); 151 if (header_search == NULL) { 152 close(fd); 153 return (ENOMEM); 154 } 155 156 if (read(fd, header_search, MULTIBOOT_SEARCH) != MULTIBOOT_SEARCH) 157 goto out; 158 159 header = NULL; 160 for (i = 0; i <= (MULTIBOOT_SEARCH - sizeof (multiboot2_header_t)); 161 i += MULTIBOOT_HEADER_ALIGN) { 162 header = (multiboot2_header_t *)(header_search + i); 163 164 /* Do we have match on magic? */ 165 if (header->mb2_magic != MULTIBOOT2_HEADER_MAGIC) { 166 header = NULL; 167 continue; 168 } 169 /* 170 * Validate checksum, the sum of magic + architecture + 171 * header_length + checksum must equal 0. 172 */ 173 if (header->mb2_magic + header->mb2_architecture + 174 header->mb2_header_length + header->mb2_checksum != 0) { 175 header = NULL; 176 continue; 177 } 178 /* 179 * Finally, the entire header must fit within MULTIBOOT_SEARCH. 180 */ 181 if (i + header->mb2_header_length > MULTIBOOT_SEARCH) { 182 header = NULL; 183 continue; 184 } 185 break; 186 } 187 188 if (header == NULL) 189 goto out; 190 191 for (tag = header->mb2_tags; tag->mbh_type != MULTIBOOT_TAG_TYPE_END; 192 tag = (multiboot_header_tag_t *)((uintptr_t)tag + 193 roundup2(tag->mbh_size, MULTIBOOT_TAG_ALIGN))) { 194 switch (tag->mbh_type) { 195 case MULTIBOOT_HEADER_TAG_INFORMATION_REQUEST: 196 if (is_info_request_valid((void*)tag) == false) 197 goto out; 198 break; 199 case MULTIBOOT_HEADER_TAG_ADDRESS: 200 addr_tag = (multiboot_header_tag_address_t *)tag; 201 break; 202 case MULTIBOOT_HEADER_TAG_ENTRY_ADDRESS: 203 entry_tag = 204 (multiboot_header_tag_entry_address_t *)tag; 205 break; 206 case MULTIBOOT_HEADER_TAG_CONSOLE_FLAGS: 207 break; 208 case MULTIBOOT_HEADER_TAG_FRAMEBUFFER: 209 have_framebuffer = true; 210 break; 211 case MULTIBOOT_HEADER_TAG_MODULE_ALIGN: 212 /* we always align modules */ 213 break; 214 case MULTIBOOT_HEADER_TAG_EFI_BS: 215 keep_bs = true; 216 break; 217 default: 218 if (!(tag->mbh_flags & MULTIBOOT_HEADER_TAG_OPTIONAL)) { 219 printf("unsupported tag: 0x%x\n", 220 tag->mbh_type); 221 goto out; 222 } 223 } 224 } 225 226 /* 227 * We must have addr_tag and entry_tag to load a 64-bit kernel. 228 * If these tags are missing, we either have a 32-bit kernel, or 229 * this is not our kernel at all. 230 */ 231 if (addr_tag != NULL && entry_tag != NULL) { 232 fp = file_alloc(); 233 if (fp == NULL) { 234 error = ENOMEM; 235 goto out; 236 } 237 if (lseek(fd, 0, SEEK_SET) == -1) { 238 printf("lseek failed\n"); 239 error = EIO; 240 file_discard(fp); 241 goto out; 242 } 243 if (fstat(fd, &st) < 0) { 244 printf("fstat failed\n"); 245 error = EIO; 246 file_discard(fp); 247 goto out; 248 } 249 250 load_addr = addr_tag->mbh_load_addr; 251 entry_addr = entry_tag->mbh_entry_addr; 252 fp->f_addr = archsw.arch_loadaddr(LOAD_KERN, filename, 253 addr_tag->mbh_load_addr); 254 if (fp->f_addr == 0) { 255 error = ENOMEM; 256 file_discard(fp); 257 goto out; 258 } 259 fp->f_size = archsw.arch_readin(fd, fp->f_addr, st.st_size); 260 261 if (fp->f_size != st.st_size) { 262 printf("error reading: %s", strerror(errno)); 263 file_discard(fp); 264 error = EIO; 265 goto out; 266 } 267 268 fp->f_name = strdup(filename); 269 fp->f_type = strdup("aout multiboot2 kernel"); 270 if (fp->f_name == NULL || fp->f_type == NULL) { 271 error = ENOMEM; 272 file_discard(fp); 273 goto out; 274 } 275 276 fp->f_metadata = NULL; 277 error = 0; 278 } else { 279 /* elf32_loadfile_raw will fill the attributes in fp. */ 280 error = elf32_loadfile_raw(filename, dest, &fp, 2); 281 if (error != 0) { 282 printf("elf32_loadfile_raw failed: %d unable to " 283 "load multiboot2 kernel\n", error); 284 goto out; 285 } 286 entry_addr = fp->f_addr; 287 /* 288 * We want the load_addr to have some legal value, 289 * so we set it same as the entry_addr. 290 * The distinction is important with UEFI, but not 291 * with BIOS version, because BIOS version does not use 292 * staging area. 293 */ 294 load_addr = fp->f_addr; 295 } 296 297 setenv("kernelname", fp->f_name, 1); 298 bios_addsmapdata(fp); 299 *result = fp; 300 out: 301 free(header_search); 302 close(fd); 303 return (error); 304 } 305 306 /* 307 * Search the command line for named property. 308 * 309 * Return codes: 310 * 0 The name is found, we return the data in value and len. 311 * ENOENT The name is not found. 312 * EINVAL The provided command line is badly formed. 313 */ 314 static int 315 find_property_value(const char *cmd, const char *name, const char **value, 316 size_t *len) 317 { 318 const char *namep, *valuep; 319 size_t name_len, value_len; 320 int quoted; 321 322 *value = NULL; 323 *len = 0; 324 325 if (cmd == NULL) 326 return (ENOENT); 327 328 while (*cmd != '\0') { 329 if (cmd[0] != '-' || cmd[1] != 'B') { 330 cmd++; 331 continue; 332 } 333 cmd += 2; /* Skip -B */ 334 while (cmd[0] == ' ' || cmd[0] == '\t') 335 cmd++; /* Skip whitespaces. */ 336 while (*cmd != '\0' && cmd[0] != ' ' && cmd[0] != '\t') { 337 namep = cmd; 338 valuep = strchr(cmd, '='); 339 if (valuep == NULL) 340 break; 341 name_len = valuep - namep; 342 valuep++; 343 value_len = 0; 344 quoted = 0; 345 for (; ; ++value_len) { 346 if (valuep[value_len] == '\0') 347 break; 348 349 /* Is this value quoted? */ 350 if (value_len == 0 && 351 (valuep[0] == '\'' || valuep[0] == '"')) { 352 quoted = valuep[0]; 353 ++value_len; 354 } 355 356 /* 357 * In the quote accept any character, 358 * but look for ending quote. 359 */ 360 if (quoted != 0) { 361 if (valuep[value_len] == quoted) 362 quoted = 0; 363 continue; 364 } 365 366 /* A comma or white space ends the value. */ 367 if (valuep[value_len] == ',' || 368 valuep[value_len] == ' ' || 369 valuep[value_len] == '\t') 370 break; 371 } 372 if (quoted != 0) { 373 printf("Missing closing '%c' in \"%s\"\n", 374 quoted, valuep); 375 return (EINVAL); 376 } 377 if (value_len != 0) { 378 if (strncmp(namep, name, name_len) == 0) { 379 *value = valuep; 380 *len = value_len; 381 return (0); 382 } 383 } 384 cmd = valuep + value_len; 385 while (*cmd == ',') 386 cmd++; 387 } 388 } 389 return (ENOENT); 390 } 391 392 /* 393 * If command line has " -B ", insert property after "-B ", otherwise 394 * append to command line. 395 */ 396 static char * 397 insert_cmdline(const char *head, const char *prop) 398 { 399 const char *prop_opt = " -B "; 400 char *cmdline, *tail; 401 int len = 0; 402 403 tail = strstr(head, prop_opt); 404 if (tail != NULL) { 405 ptrdiff_t diff; 406 tail += strlen(prop_opt); 407 diff = tail - head; 408 if (diff >= INT_MAX) 409 return (NULL); 410 len = (int)diff; 411 } 412 413 if (tail == NULL) 414 asprintf(&cmdline, "%s%s%s", head, prop_opt, prop); 415 else 416 asprintf(&cmdline, "%.*s%s,%s", len, head, prop, tail); 417 418 return (cmdline); 419 } 420 421 /* 422 * Since we have no way to pass the environment to the mb1 kernel other than 423 * through arguments, we need to take care of console setup. 424 * 425 * If the console is in mirror mode, set the kernel console from $os_console. 426 * If it's unset, use first item from $console. 427 * If $console is "ttyX", also pass $ttyX-mode, since it may have been set by 428 * the user. 429 * 430 * In case of memory allocation errors, just return the original command line 431 * so we have a chance of booting. 432 * 433 * On success, cl will be freed and a new, allocated command line string is 434 * returned. 435 * 436 * For the mb2 kernel, we only set command line console if os_console is set. 437 * We can not overwrite console in the environment, as it can disrupt the 438 * loader console messages, and we do not want to deal with the os_console 439 * in the kernel. 440 */ 441 static char * 442 update_cmdline(char *cl, bool mb2) 443 { 444 char *os_console = getenv("os_console"); 445 char *ttymode = NULL; 446 char mode[10]; 447 char *tmp; 448 const char *prop; 449 size_t plen; 450 int rv; 451 452 if (mb2 == true && os_console == NULL) 453 return (cl); 454 455 if (os_console == NULL) { 456 tmp = strdup(getenv("console")); 457 os_console = strsep(&tmp, ", "); 458 } else { 459 os_console = strdup(os_console); 460 } 461 462 if (os_console == NULL) 463 return (cl); 464 465 if (mb2 == false && strncmp(os_console, "tty", 3) == 0) { 466 snprintf(mode, sizeof (mode), "%s-mode", os_console); 467 /* 468 * The ttyX-mode variable is set by our serial console 469 * driver for ttya-ttyd. However, since the os_console 470 * values are not verified, it is possible we get bogus 471 * name and no mode variable. If so, we do not set console 472 * property and let the kernel use defaults. 473 */ 474 if ((ttymode = getenv(mode)) == NULL) 475 return (cl); 476 } 477 478 rv = find_property_value(cl, "console", &prop, &plen); 479 if (rv != 0 && rv != ENOENT) { 480 free(os_console); 481 return (cl); 482 } 483 484 /* If console is set and this is MB2 boot, we are done. */ 485 if (rv == 0 && mb2 == true) { 486 free(os_console); 487 return (cl); 488 } 489 490 /* If console is set, do we need to set tty mode? */ 491 if (rv == 0) { 492 const char *ttyp = NULL; 493 size_t ttylen; 494 495 free(os_console); 496 os_console = NULL; 497 *mode = '\0'; 498 if (strncmp(prop, "tty", 3) == 0 && plen == 4) { 499 strncpy(mode, prop, plen); 500 mode[plen] = '\0'; 501 strncat(mode, "-mode", 5); 502 find_property_value(cl, mode, &ttyp, &ttylen); 503 } 504 505 if (*mode != '\0' && ttyp == NULL) 506 ttymode = getenv(mode); 507 else 508 return (cl); 509 } 510 511 /* Build updated command line. */ 512 if (os_console != NULL) { 513 char *propstr; 514 515 asprintf(&propstr, "console=%s", os_console); 516 free(os_console); 517 if (propstr == NULL) { 518 return (cl); 519 } 520 521 tmp = insert_cmdline(cl, propstr); 522 free(propstr); 523 if (tmp == NULL) 524 return (cl); 525 526 free(cl); 527 cl = tmp; 528 } 529 if (ttymode != NULL) { 530 char *propstr; 531 532 asprintf(&propstr, "%s=\"%s\"", mode, ttymode); 533 if (propstr == NULL) 534 return (cl); 535 536 tmp = insert_cmdline(cl, propstr); 537 free(propstr); 538 if (tmp == NULL) 539 return (cl); 540 free(cl); 541 cl = tmp; 542 } 543 544 return (cl); 545 } 546 547 /* 548 * Build the kernel command line. Shared function between MB1 and MB2. 549 * 550 * In both cases, if fstype is set and is not zfs, we do not set up 551 * zfs-bootfs property. But we set kernel file name and options. 552 * 553 * For the MB1, we only can pass properties on command line, so 554 * we will set console, ttyX-mode (for serial console) and zfs-bootfs. 555 * 556 * For the MB2, we can pass properties in environment, but if os_console 557 * is set in environment, we need to add console property on the kernel 558 * command line. 559 * 560 * The console properties are managed in update_cmdline(). 561 */ 562 int 563 mb_kernel_cmdline(struct preloaded_file *fp, struct devdesc *rootdev, 564 char **line) 565 { 566 const char *fs = getenv("fstype"); 567 char *cmdline; 568 size_t len; 569 bool zfs_root = false; 570 bool mb2; 571 int rv; 572 573 /* 574 * 64-bit kernel has aout header, 32-bit kernel is elf, and the 575 * type strings are different. Lets just search for "multiboot2". 576 */ 577 if (strstr(fp->f_type, "multiboot2") == NULL) 578 mb2 = false; 579 else 580 mb2 = true; 581 582 if (rootdev->d_type == DEVT_ZFS) 583 zfs_root = true; 584 585 /* If we have fstype set in env, reset zfs_root if needed. */ 586 if (fs != NULL && strcmp(fs, "zfs") != 0) 587 zfs_root = false; 588 589 /* 590 * If we have fstype set on the command line, 591 * reset zfs_root if needed. 592 */ 593 rv = find_property_value(fp->f_args, "fstype", &fs, &len); 594 if (rv != 0 && rv != ENOENT) 595 return (rv); 596 597 if (fs != NULL && strncmp(fs, "zfs", len) != 0) 598 zfs_root = false; 599 600 /* zfs_bootfs() will set the environment, it must be called. */ 601 if (zfs_root == true) 602 fs = zfs_bootfs(rootdev); 603 604 if (fp->f_args == NULL) 605 cmdline = strdup(fp->f_name); 606 else 607 asprintf(&cmdline, "%s %s", fp->f_name, fp->f_args); 608 609 if (cmdline == NULL) 610 return (ENOMEM); 611 612 /* Append zfs-bootfs for MB1 command line. */ 613 if (mb2 == false && zfs_root == true) { 614 char *tmp; 615 616 tmp = insert_cmdline(cmdline, fs); 617 free(cmdline); 618 if (tmp == NULL) 619 return (ENOMEM); 620 cmdline = tmp; 621 } 622 623 *line = update_cmdline(cmdline, mb2); 624 return (0); 625 } 626 627 /* 628 * Returns allocated virtual address from MB info area. 629 */ 630 static vm_offset_t 631 mb_malloc(size_t n) 632 { 633 vm_offset_t ptr = last_addr; 634 last_addr = roundup(last_addr + n, MULTIBOOT_TAG_ALIGN); 635 return (ptr); 636 } 637 638 /* 639 * Calculate size for module tag list. 640 */ 641 static size_t 642 module_size(struct preloaded_file *fp) 643 { 644 size_t len, size; 645 struct preloaded_file *mfp; 646 647 size = 0; 648 for (mfp = fp->f_next; mfp != NULL; mfp = mfp->f_next) { 649 len = strlen(mfp->f_name) + 1; 650 len += strlen(mfp->f_type) + 5 + 1; /* 5 is for "type=" */ 651 if (mfp->f_args != NULL) 652 len += strlen(mfp->f_args) + 1; 653 size += sizeof (multiboot_tag_module_t) + len; 654 size = roundup(size, MULTIBOOT_TAG_ALIGN); 655 } 656 return (size); 657 } 658 659 /* 660 * Calculate size for bios smap tag. 661 */ 662 static size_t 663 biossmap_size(struct preloaded_file *fp) 664 { 665 int num; 666 struct file_metadata *md; 667 668 md = file_findmetadata(fp, MODINFOMD_SMAP); 669 if (md == NULL) 670 return (0); 671 672 num = md->md_size / sizeof(struct bios_smap); /* number of entries */ 673 return (sizeof (multiboot_tag_mmap_t) + 674 num * sizeof (multiboot_mmap_entry_t)); 675 } 676 677 static size_t 678 mbi_size(struct preloaded_file *fp, char *cmdline) 679 { 680 size_t size; 681 682 size = sizeof (uint32_t) * 2; /* first 2 fields from MBI header */ 683 size += sizeof (multiboot_tag_string_t) + strlen(cmdline) + 1; 684 size = roundup2(size, MULTIBOOT_TAG_ALIGN); 685 size += sizeof (multiboot_tag_string_t) + strlen(bootprog_info) + 1; 686 size = roundup2(size, MULTIBOOT_TAG_ALIGN); 687 size += sizeof (multiboot_tag_basic_meminfo_t); 688 size = roundup2(size, MULTIBOOT_TAG_ALIGN); 689 size += module_size(fp); 690 size = roundup2(size, MULTIBOOT_TAG_ALIGN); 691 size += biossmap_size(fp); 692 size = roundup2(size, MULTIBOOT_TAG_ALIGN); 693 694 if (strstr(getenv("loaddev"), "pxe") != NULL) { 695 size += sizeof(multiboot_tag_network_t) + sizeof (BOOTPLAYER); 696 size = roundup2(size, MULTIBOOT_TAG_ALIGN); 697 } 698 699 if (rsdp != NULL) { 700 if (rsdp->Revision == 0) { 701 size += sizeof (multiboot_tag_old_acpi_t) + 702 sizeof(ACPI_RSDP_COMMON); 703 } else { 704 size += sizeof (multiboot_tag_new_acpi_t) + 705 rsdp->Length; 706 } 707 size = roundup2(size, MULTIBOOT_TAG_ALIGN); 708 } 709 size += sizeof(multiboot_tag_t); 710 711 return (size); 712 } 713 714 static int 715 multiboot2_exec(struct preloaded_file *fp) 716 { 717 struct preloaded_file *mfp; 718 multiboot2_info_header_t *mbi; 719 char *cmdline = NULL; 720 struct devdesc *rootdev; 721 struct file_metadata *md; 722 int i, error, num; 723 int rootfs = 0; 724 size_t size; 725 struct bios_smap *smap; 726 vm_offset_t tmp; 727 i386_getdev((void **)(&rootdev), NULL, NULL); 728 729 error = EINVAL; 730 if (rootdev == NULL) { 731 printf("can't determine root device\n"); 732 goto error; 733 } 734 735 /* 736 * Set the image command line. 737 */ 738 if (fp->f_args == NULL) { 739 cmdline = getenv("boot-args"); 740 if (cmdline != NULL) { 741 fp->f_args = strdup(cmdline); 742 if (fp->f_args == NULL) { 743 error = ENOMEM; 744 goto error; 745 } 746 } 747 } 748 749 error = mb_kernel_cmdline(fp, rootdev, &cmdline); 750 if (error != 0) 751 goto error; 752 753 /* mb_kernel_cmdline() updates the environment. */ 754 build_environment_module(); 755 756 size = mbi_size(fp, cmdline); /* Get the size for MBI. */ 757 758 /* Set up the base for mb_malloc. */ 759 for (mfp = fp; mfp->f_next != NULL; mfp = mfp->f_next); 760 761 /* Start info block from the new page. */ 762 last_addr = roundup(mfp->f_addr + mfp->f_size, MULTIBOOT_MOD_ALIGN); 763 764 /* Do we have space for multiboot info? */ 765 if (last_addr + size >= memtop_copyin) { 766 error = ENOMEM; 767 goto error; 768 } 769 770 mbi = (multiboot2_info_header_t *)PTOV(last_addr); 771 last_addr = (vm_offset_t)mbi->mbi_tags; 772 773 { 774 multiboot_tag_string_t *tag; 775 i = sizeof (multiboot_tag_string_t) + strlen(cmdline) + 1; 776 tag = (multiboot_tag_string_t *) mb_malloc(i); 777 778 tag->mb_type = MULTIBOOT_TAG_TYPE_CMDLINE; 779 tag->mb_size = i; 780 memcpy(tag->mb_string, cmdline, strlen(cmdline) + 1); 781 free(cmdline); 782 cmdline = NULL; 783 } 784 785 { 786 multiboot_tag_string_t *tag; 787 i = sizeof (multiboot_tag_string_t) + strlen(bootprog_info) + 1; 788 tag = (multiboot_tag_string_t *) mb_malloc(i); 789 790 tag->mb_type = MULTIBOOT_TAG_TYPE_BOOT_LOADER_NAME; 791 tag->mb_size = i; 792 memcpy(tag->mb_string, bootprog_info, 793 strlen(bootprog_info) + 1); 794 } 795 796 { 797 multiboot_tag_basic_meminfo_t *tag; 798 tag = (multiboot_tag_basic_meminfo_t *) 799 mb_malloc(sizeof (*tag)); 800 801 tag->mb_type = MULTIBOOT_TAG_TYPE_BASIC_MEMINFO; 802 tag->mb_size = sizeof (*tag); 803 tag->mb_mem_lower = bios_basemem / 1024; 804 tag->mb_mem_upper = bios_extmem / 1024; 805 } 806 807 num = 0; 808 for (mfp = fp->f_next; mfp != NULL; mfp = mfp->f_next) { 809 num++; 810 if (mfp->f_type != NULL && strcmp(mfp->f_type, "rootfs") == 0) 811 rootfs++; 812 } 813 814 if (num == 0 || rootfs == 0) { 815 /* We need at least one module - rootfs. */ 816 printf("No rootfs module provided, aborting\n"); 817 error = EINVAL; 818 goto error; 819 } 820 821 /* 822 * Set the stage for physical memory layout: 823 * - We have kernel at load_addr. 824 * - Modules are aligned to page boundary. 825 * - MBI is aligned to page boundary. 826 * - Set the tmp to point to physical address of the first module. 827 */ 828 tmp = roundup2(load_addr + fp->f_size, MULTIBOOT_MOD_ALIGN); 829 830 for (mfp = fp->f_next; mfp != NULL; mfp = mfp->f_next) { 831 multiboot_tag_module_t *tag; 832 833 num = strlen(mfp->f_name) + 1; 834 num += strlen(mfp->f_type) + 5 + 1; 835 if (mfp->f_args != NULL) { 836 num += strlen(mfp->f_args) + 1; 837 } 838 cmdline = malloc(num); 839 if (cmdline == NULL) { 840 error = ENOMEM; 841 goto error; 842 } 843 844 if (mfp->f_args != NULL) 845 snprintf(cmdline, num, "%s type=%s %s", 846 mfp->f_name, mfp->f_type, mfp->f_args); 847 else 848 snprintf(cmdline, num, "%s type=%s", 849 mfp->f_name, mfp->f_type); 850 851 tag = (multiboot_tag_module_t *)mb_malloc(sizeof (*tag) + num); 852 853 tag->mb_type = MULTIBOOT_TAG_TYPE_MODULE; 854 tag->mb_size = sizeof (*tag) + num; 855 tag->mb_mod_start = tmp; 856 tag->mb_mod_end = tmp + mfp->f_size; 857 tmp = roundup2(tag->mb_mod_end, MULTIBOOT_MOD_ALIGN); 858 memcpy(tag->mb_cmdline, cmdline, num); 859 free(cmdline); 860 cmdline = NULL; 861 } 862 863 md = file_findmetadata(fp, MODINFOMD_SMAP); 864 if (md == NULL) { 865 printf("no memory smap\n"); 866 error = EINVAL; 867 goto error; 868 } 869 870 smap = (struct bios_smap *)md->md_data; 871 num = md->md_size / sizeof(struct bios_smap); /* number of entries */ 872 873 { 874 multiboot_tag_mmap_t *tag; 875 multiboot_mmap_entry_t *mmap_entry; 876 877 tag = (multiboot_tag_mmap_t *) 878 mb_malloc(sizeof (*tag) + 879 num * sizeof (multiboot_mmap_entry_t)); 880 881 tag->mb_type = MULTIBOOT_TAG_TYPE_MMAP; 882 tag->mb_size = sizeof (*tag) + 883 num * sizeof (multiboot_mmap_entry_t); 884 tag->mb_entry_size = sizeof (multiboot_mmap_entry_t); 885 tag->mb_entry_version = 0; 886 mmap_entry = (multiboot_mmap_entry_t *)tag->mb_entries; 887 888 for (i = 0; i < num; i++) { 889 mmap_entry[i].mmap_addr = smap[i].base; 890 mmap_entry[i].mmap_len = smap[i].length; 891 mmap_entry[i].mmap_type = smap[i].type; 892 mmap_entry[i].mmap_reserved = 0; 893 } 894 } 895 896 if (strstr(getenv("loaddev"), "pxe") != NULL) { 897 multiboot_tag_network_t *tag; 898 tag = (multiboot_tag_network_t *) 899 mb_malloc(sizeof(*tag) + sizeof (BOOTPLAYER)); 900 901 tag->mb_type = MULTIBOOT_TAG_TYPE_NETWORK; 902 tag->mb_size = sizeof(*tag) + sizeof (BOOTPLAYER); 903 memcpy(tag->mb_dhcpack, &bootplayer, sizeof (BOOTPLAYER)); 904 } 905 906 if (rsdp != NULL) { 907 multiboot_tag_new_acpi_t *ntag; 908 multiboot_tag_old_acpi_t *otag; 909 uint32_t tsize; 910 911 if (rsdp->Revision == 0) { 912 tsize = sizeof (*otag) + sizeof (ACPI_RSDP_COMMON); 913 otag = (multiboot_tag_old_acpi_t *)mb_malloc(tsize); 914 otag->mb_type = MULTIBOOT_TAG_TYPE_ACPI_OLD; 915 otag->mb_size = tsize; 916 memcpy(otag->mb_rsdp, rsdp, sizeof (ACPI_RSDP_COMMON)); 917 } else { 918 tsize = sizeof (*ntag) + rsdp->Length; 919 ntag = (multiboot_tag_new_acpi_t *)mb_malloc(tsize); 920 ntag->mb_type = MULTIBOOT_TAG_TYPE_ACPI_NEW; 921 ntag->mb_size = tsize; 922 memcpy(ntag->mb_rsdp, rsdp, rsdp->Length); 923 } 924 } 925 926 /* 927 * MB tag list end marker. 928 */ 929 { 930 multiboot_tag_t *tag = (multiboot_tag_t *) 931 mb_malloc(sizeof(*tag)); 932 tag->mb_type = MULTIBOOT_TAG_TYPE_END; 933 tag->mb_size = sizeof(*tag); 934 } 935 936 mbi->mbi_total_size = last_addr - (vm_offset_t)mbi; 937 mbi->mbi_reserved = 0; 938 939 dev_cleanup(); 940 __exec((void *)VTOP(multiboot_tramp), MULTIBOOT2_BOOTLOADER_MAGIC, 941 (void *)entry_addr, (void *)VTOP(mbi)); 942 panic("exec returned"); 943 944 error: 945 if (cmdline != NULL) 946 free(cmdline); 947 return (error); 948 } 949