1 /* boot.c - load and bootstrap a kernel */ 2 /* 3 * GRUB -- GRand Unified Bootloader 4 * Copyright (C) 1999,2000,2001,2002,2003,2004 Free Software Foundation, Inc. 5 * 6 * This program is free software; you can redistribute it and/or modify 7 * it under the terms of the GNU General Public License as published by 8 * the Free Software Foundation; either version 2 of the License, or 9 * (at your option) any later version. 10 * 11 * This program is distributed in the hope that it will be useful, 12 * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 * GNU General Public License for more details. 15 * 16 * You should have received a copy of the GNU General Public License 17 * along with this program; if not, write to the Free Software 18 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 19 */ 20 21 22 #include "shared.h" 23 24 #include "freebsd.h" 25 #include "imgact_aout.h" 26 #include "i386-elf.h" 27 28 static int cur_addr; 29 entry_func entry_addr; 30 static struct mod_list mll[99]; 31 static int linux_mem_size; 32 33 /* 34 * The next two functions, 'load_image' and 'load_module', are the building 35 * blocks of the multiboot loader component. They handle essentially all 36 * of the gory details of loading in a bootable image and the modules. 37 */ 38 39 kernel_t 40 load_image (char *kernel, char *arg, kernel_t suggested_type, 41 unsigned long load_flags) 42 { 43 int len, i, exec_type = 0, align_4k = 1; 44 entry_func real_entry_addr = 0; 45 kernel_t type = KERNEL_TYPE_NONE; 46 unsigned long flags = 0, text_len = 0, data_len = 0, bss_len = 0; 47 char *str = 0, *str2 = 0; 48 struct linux_kernel_header *lh; 49 union 50 { 51 struct multiboot_header *mb; 52 struct exec *aout; 53 Elf32_Ehdr *elf; 54 } 55 pu; 56 /* presuming that MULTIBOOT_SEARCH is large enough to encompass an 57 executable header */ 58 unsigned char buffer[MULTIBOOT_SEARCH]; 59 60 /* sets the header pointer to point to the beginning of the 61 buffer by default */ 62 pu.aout = (struct exec *) buffer; 63 64 if (!grub_open (kernel)) 65 return KERNEL_TYPE_NONE; 66 67 if (!(len = grub_read (buffer, MULTIBOOT_SEARCH)) || len < 32) 68 { 69 grub_close (); 70 71 if (!errnum) 72 errnum = ERR_EXEC_FORMAT; 73 74 return KERNEL_TYPE_NONE; 75 } 76 77 for (i = 0; i < len; i++) 78 { 79 if (MULTIBOOT_FOUND ((int) (buffer + i), len - i)) 80 { 81 flags = ((struct multiboot_header *) (buffer + i))->flags; 82 if (flags & MULTIBOOT_UNSUPPORTED) 83 { 84 grub_close (); 85 errnum = ERR_BOOT_FEATURES; 86 return KERNEL_TYPE_NONE; 87 } 88 type = KERNEL_TYPE_MULTIBOOT; 89 str2 = "Multiboot"; 90 break; 91 } 92 } 93 94 /* Use BUFFER as a linux kernel header, if the image is Linux zImage 95 or bzImage. */ 96 lh = (struct linux_kernel_header *) buffer; 97 98 /* ELF loading supported if multiboot, FreeBSD and NetBSD. */ 99 if ((type == KERNEL_TYPE_MULTIBOOT 100 || pu.elf->e_ident[EI_OSABI] == ELFOSABI_FREEBSD 101 || grub_strcmp (pu.elf->e_ident + EI_BRAND, "FreeBSD") == 0 102 || suggested_type == KERNEL_TYPE_NETBSD) 103 && len > sizeof (Elf32_Ehdr) 104 && BOOTABLE_I386_ELF ((*((Elf32_Ehdr *) buffer)))) 105 { 106 if (type == KERNEL_TYPE_MULTIBOOT) 107 entry_addr = (entry_func) pu.elf->e_entry; 108 else 109 entry_addr = (entry_func) (pu.elf->e_entry & 0xFFFFFF); 110 111 if (entry_addr < (entry_func) 0x100000) 112 errnum = ERR_BELOW_1MB; 113 114 /* don't want to deal with ELF program header at some random 115 place in the file -- this generally won't happen */ 116 if (pu.elf->e_phoff == 0 || pu.elf->e_phnum == 0 117 || ((pu.elf->e_phoff + (pu.elf->e_phentsize * pu.elf->e_phnum)) 118 >= len)) 119 errnum = ERR_EXEC_FORMAT; 120 str = "elf"; 121 122 if (type == KERNEL_TYPE_NONE) 123 { 124 /* At the moment, there is no way to identify a NetBSD ELF 125 kernel, so rely on the suggested type by the user. */ 126 if (suggested_type == KERNEL_TYPE_NETBSD) 127 { 128 str2 = "NetBSD"; 129 type = suggested_type; 130 } 131 else 132 { 133 str2 = "FreeBSD"; 134 type = KERNEL_TYPE_FREEBSD; 135 } 136 } 137 } 138 else if (flags & MULTIBOOT_AOUT_KLUDGE) 139 { 140 pu.mb = (struct multiboot_header *) (buffer + i); 141 entry_addr = (entry_func) pu.mb->entry_addr; 142 cur_addr = pu.mb->load_addr; 143 /* first offset into file */ 144 grub_seek (i - (pu.mb->header_addr - cur_addr)); 145 146 /* If the load end address is zero, load the whole contents. */ 147 if (! pu.mb->load_end_addr) 148 pu.mb->load_end_addr = cur_addr + filemax; 149 150 text_len = pu.mb->load_end_addr - cur_addr; 151 data_len = 0; 152 153 /* If the bss end address is zero, assume that there is no bss area. */ 154 if (! pu.mb->bss_end_addr) 155 pu.mb->bss_end_addr = pu.mb->load_end_addr; 156 157 bss_len = pu.mb->bss_end_addr - pu.mb->load_end_addr; 158 159 if (pu.mb->header_addr < pu.mb->load_addr 160 || pu.mb->load_end_addr <= pu.mb->load_addr 161 || pu.mb->bss_end_addr < pu.mb->load_end_addr 162 || (pu.mb->header_addr - pu.mb->load_addr) > i) 163 errnum = ERR_EXEC_FORMAT; 164 165 if (cur_addr < 0x100000) 166 errnum = ERR_BELOW_1MB; 167 168 pu.aout = (struct exec *) buffer; 169 exec_type = 2; 170 str = "kludge"; 171 } 172 else if (len > sizeof (struct exec) && !N_BADMAG ((*(pu.aout)))) 173 { 174 entry_addr = (entry_func) pu.aout->a_entry; 175 176 if (type == KERNEL_TYPE_NONE) 177 { 178 /* 179 * If it doesn't have a Multiboot header, then presume 180 * it is either a FreeBSD or NetBSD executable. If so, 181 * then use a magic number of normal ordering, ZMAGIC to 182 * determine if it is FreeBSD. 183 * 184 * This is all because freebsd and netbsd seem to require 185 * masking out some address bits... differently for each 186 * one... plus of course we need to know which booting 187 * method to use. 188 */ 189 entry_addr = (entry_func) ((int) entry_addr & 0xFFFFFF); 190 191 if (buffer[0] == 0xb && buffer[1] == 1) 192 { 193 type = KERNEL_TYPE_FREEBSD; 194 cur_addr = (int) entry_addr; 195 str2 = "FreeBSD"; 196 } 197 else 198 { 199 type = KERNEL_TYPE_NETBSD; 200 cur_addr = (int) entry_addr & 0xF00000; 201 if (N_GETMAGIC ((*(pu.aout))) != NMAGIC) 202 align_4k = 0; 203 str2 = "NetBSD"; 204 } 205 } 206 207 /* first offset into file */ 208 grub_seek (N_TXTOFF (*(pu.aout))); 209 text_len = pu.aout->a_text; 210 data_len = pu.aout->a_data; 211 bss_len = pu.aout->a_bss; 212 213 if (cur_addr < 0x100000) 214 errnum = ERR_BELOW_1MB; 215 216 exec_type = 1; 217 str = "a.out"; 218 } 219 else if (lh->boot_flag == BOOTSEC_SIGNATURE 220 && lh->setup_sects <= LINUX_MAX_SETUP_SECTS) 221 { 222 int big_linux = 0; 223 int setup_sects = lh->setup_sects; 224 225 if (lh->header == LINUX_MAGIC_SIGNATURE && lh->version >= 0x0200) 226 { 227 big_linux = (lh->loadflags & LINUX_FLAG_BIG_KERNEL); 228 lh->type_of_loader = LINUX_BOOT_LOADER_TYPE; 229 230 /* Put the real mode part at as a high location as possible. */ 231 linux_data_real_addr 232 = (char *) ((mbi.mem_lower << 10) - LINUX_SETUP_MOVE_SIZE); 233 /* But it must not exceed the traditional area. */ 234 if (linux_data_real_addr > (char *) LINUX_OLD_REAL_MODE_ADDR) 235 linux_data_real_addr = (char *) LINUX_OLD_REAL_MODE_ADDR; 236 237 if (lh->version >= 0x0201) 238 { 239 lh->heap_end_ptr = LINUX_HEAP_END_OFFSET; 240 lh->loadflags |= LINUX_FLAG_CAN_USE_HEAP; 241 } 242 243 if (lh->version >= 0x0202) 244 lh->cmd_line_ptr = linux_data_real_addr + LINUX_CL_OFFSET; 245 else 246 { 247 lh->cl_magic = LINUX_CL_MAGIC; 248 lh->cl_offset = LINUX_CL_OFFSET; 249 lh->setup_move_size = LINUX_SETUP_MOVE_SIZE; 250 } 251 } 252 else 253 { 254 /* Your kernel is quite old... */ 255 lh->cl_magic = LINUX_CL_MAGIC; 256 lh->cl_offset = LINUX_CL_OFFSET; 257 258 setup_sects = LINUX_DEFAULT_SETUP_SECTS; 259 260 linux_data_real_addr = (char *) LINUX_OLD_REAL_MODE_ADDR; 261 } 262 263 /* If SETUP_SECTS is not set, set it to the default (4). */ 264 if (! setup_sects) 265 setup_sects = LINUX_DEFAULT_SETUP_SECTS; 266 267 data_len = setup_sects << 9; 268 text_len = filemax - data_len - SECTOR_SIZE; 269 270 linux_data_tmp_addr = (char *) LINUX_BZIMAGE_ADDR + text_len; 271 272 if (! big_linux 273 && text_len > linux_data_real_addr - (char *) LINUX_ZIMAGE_ADDR) 274 { 275 grub_printf (" linux 'zImage' kernel too big, try 'make bzImage'\n"); 276 errnum = ERR_WONT_FIT; 277 } 278 else if (linux_data_real_addr + LINUX_SETUP_MOVE_SIZE 279 > RAW_ADDR ((char *) (mbi.mem_lower << 10))) 280 errnum = ERR_WONT_FIT; 281 else 282 { 283 grub_printf (" [Linux-%s, setup=0x%x, size=0x%x]\n", 284 (big_linux ? "bzImage" : "zImage"), data_len, text_len); 285 286 /* Video mode selection support. What a mess! */ 287 /* NOTE: Even the word "mess" is not still enough to 288 represent how wrong and bad the Linux video support is, 289 but I don't want to hear complaints from Linux fanatics 290 any more. -okuji */ 291 { 292 char *vga; 293 294 /* Find the substring "vga=". */ 295 vga = grub_strstr (arg, "vga="); 296 if (vga) 297 { 298 char *value = vga + 4; 299 int vid_mode; 300 301 /* Handle special strings. */ 302 if (substring ("normal", value) < 1) 303 vid_mode = LINUX_VID_MODE_NORMAL; 304 else if (substring ("ext", value) < 1) 305 vid_mode = LINUX_VID_MODE_EXTENDED; 306 else if (substring ("ask", value) < 1) 307 vid_mode = LINUX_VID_MODE_ASK; 308 else if (safe_parse_maxint (&value, &vid_mode)) 309 ; 310 else 311 { 312 /* ERRNUM is already set inside the function 313 safe_parse_maxint. */ 314 grub_close (); 315 return KERNEL_TYPE_NONE; 316 } 317 318 lh->vid_mode = vid_mode; 319 } 320 } 321 322 /* Check the mem= option to limit memory used for initrd. */ 323 { 324 char *mem; 325 326 mem = grub_strstr (arg, "mem="); 327 if (mem) 328 { 329 char *value = mem + 4; 330 331 safe_parse_maxint (&value, &linux_mem_size); 332 switch (errnum) 333 { 334 case ERR_NUMBER_OVERFLOW: 335 /* If an overflow occurs, use the maximum address for 336 initrd instead. This is good, because MAXINT is 337 greater than LINUX_INITRD_MAX_ADDRESS. */ 338 linux_mem_size = LINUX_INITRD_MAX_ADDRESS; 339 errnum = ERR_NONE; 340 break; 341 342 case ERR_NONE: 343 { 344 int shift = 0; 345 346 switch (grub_tolower (*value)) 347 { 348 case 'g': 349 shift += 10; 350 case 'm': 351 shift += 10; 352 case 'k': 353 shift += 10; 354 default: 355 break; 356 } 357 358 /* Check an overflow. */ 359 if (linux_mem_size > (MAXINT >> shift)) 360 linux_mem_size = LINUX_INITRD_MAX_ADDRESS; 361 else 362 linux_mem_size <<= shift; 363 } 364 break; 365 366 default: 367 linux_mem_size = 0; 368 errnum = ERR_NONE; 369 break; 370 } 371 } 372 else 373 linux_mem_size = 0; 374 } 375 376 /* It is possible that DATA_LEN + SECTOR_SIZE is greater than 377 MULTIBOOT_SEARCH, so the data may have been read partially. */ 378 if (data_len + SECTOR_SIZE <= MULTIBOOT_SEARCH) 379 grub_memmove (linux_data_tmp_addr, buffer, 380 data_len + SECTOR_SIZE); 381 else 382 { 383 grub_memmove (linux_data_tmp_addr, buffer, MULTIBOOT_SEARCH); 384 grub_read (linux_data_tmp_addr + MULTIBOOT_SEARCH, 385 data_len + SECTOR_SIZE - MULTIBOOT_SEARCH); 386 } 387 388 if (lh->header != LINUX_MAGIC_SIGNATURE || 389 lh->version < 0x0200) 390 /* Clear the heap space. */ 391 grub_memset (linux_data_tmp_addr + ((setup_sects + 1) << 9), 392 0, 393 (64 - setup_sects - 1) << 9); 394 395 /* Copy command-line plus memory hack to staging area. 396 NOTE: Linux has a bug that it doesn't handle multiple spaces 397 between two options and a space after a "mem=" option isn't 398 removed correctly so the arguments to init could be like 399 {"init", "", "", NULL}. This affects some not-very-clever 400 shells. Thus, the code below does a trick to avoid the bug. 401 That is, copy "mem=XXX" to the end of the command-line, and 402 avoid to copy spaces unnecessarily. Hell. */ 403 { 404 char *src = skip_to (0, arg); 405 char *dest = linux_data_tmp_addr + LINUX_CL_OFFSET; 406 407 while (dest < linux_data_tmp_addr + LINUX_CL_END_OFFSET && *src) 408 *(dest++) = *(src++); 409 410 /* Old Linux kernels have problems determining the amount of 411 the available memory. To work around this problem, we add 412 the "mem" option to the kernel command line. This has its 413 own drawbacks because newer kernels can determine the 414 memory map more accurately. Boot protocol 2.03, which 415 appeared in Linux 2.4.18, provides a pointer to the kernel 416 version string, so we could check it. But since kernel 417 2.4.18 and newer are known to detect memory reliably, boot 418 protocol 2.03 already implies that the kernel is new 419 enough. The "mem" option is added if neither of the 420 following conditions is met: 421 1) The "mem" option is already present. 422 2) The "kernel" command is used with "--no-mem-option". 423 3) GNU GRUB is configured not to pass the "mem" option. 424 4) The kernel supports boot protocol 2.03 or newer. */ 425 if (! grub_strstr (arg, "mem=") 426 && ! (load_flags & KERNEL_LOAD_NO_MEM_OPTION) 427 && lh->version < 0x0203 /* kernel version < 2.4.18 */ 428 && dest + 15 < linux_data_tmp_addr + LINUX_CL_END_OFFSET) 429 { 430 *dest++ = ' '; 431 *dest++ = 'm'; 432 *dest++ = 'e'; 433 *dest++ = 'm'; 434 *dest++ = '='; 435 436 dest = convert_to_ascii (dest, 'u', (extended_memory + 0x400)); 437 *dest++ = 'K'; 438 } 439 440 *dest = 0; 441 } 442 443 /* offset into file */ 444 grub_seek (data_len + SECTOR_SIZE); 445 446 cur_addr = (int) linux_data_tmp_addr + LINUX_SETUP_MOVE_SIZE; 447 grub_read ((char *) LINUX_BZIMAGE_ADDR, text_len); 448 449 if (errnum == ERR_NONE) 450 { 451 grub_close (); 452 453 /* Sanity check. */ 454 if (suggested_type != KERNEL_TYPE_NONE 455 && ((big_linux && suggested_type != KERNEL_TYPE_BIG_LINUX) 456 || (! big_linux && suggested_type != KERNEL_TYPE_LINUX))) 457 { 458 errnum = ERR_EXEC_FORMAT; 459 return KERNEL_TYPE_NONE; 460 } 461 462 /* Ugly hack. */ 463 linux_text_len = text_len; 464 465 return big_linux ? KERNEL_TYPE_BIG_LINUX : KERNEL_TYPE_LINUX; 466 } 467 } 468 } 469 else /* no recognizable format */ 470 errnum = ERR_EXEC_FORMAT; 471 472 /* return if error */ 473 if (errnum) 474 { 475 grub_close (); 476 return KERNEL_TYPE_NONE; 477 } 478 479 /* fill the multiboot info structure */ 480 mbi.cmdline = (int) arg; 481 mbi.mods_count = 0; 482 mbi.mods_addr = 0; 483 mbi.boot_device = (current_drive << 24) | current_partition; 484 mbi.flags &= ~(MB_INFO_MODS | MB_INFO_AOUT_SYMS | MB_INFO_ELF_SHDR); 485 mbi.syms.a.tabsize = 0; 486 mbi.syms.a.strsize = 0; 487 mbi.syms.a.addr = 0; 488 mbi.syms.a.pad = 0; 489 490 printf (" [%s-%s", str2, str); 491 492 str = ""; 493 494 if (exec_type) /* can be loaded like a.out */ 495 { 496 if (flags & MULTIBOOT_AOUT_KLUDGE) 497 str = "-and-data"; 498 499 printf (", loadaddr=0x%x, text%s=0x%x", cur_addr, str, text_len); 500 501 /* read text, then read data */ 502 if (grub_read ((char *) RAW_ADDR (cur_addr), text_len) == text_len) 503 { 504 cur_addr += text_len; 505 506 if (!(flags & MULTIBOOT_AOUT_KLUDGE)) 507 { 508 /* we have to align to a 4K boundary */ 509 if (align_4k) 510 cur_addr = (cur_addr + 0xFFF) & 0xFFFFF000; 511 else 512 printf (", C"); 513 514 printf (", data=0x%x", data_len); 515 516 if ((grub_read ((char *) RAW_ADDR (cur_addr), data_len) 517 != data_len) 518 && !errnum) 519 errnum = ERR_EXEC_FORMAT; 520 cur_addr += data_len; 521 } 522 523 if (!errnum) 524 { 525 memset ((char *) RAW_ADDR (cur_addr), 0, bss_len); 526 cur_addr += bss_len; 527 528 printf (", bss=0x%x", bss_len); 529 } 530 } 531 else if (!errnum) 532 errnum = ERR_EXEC_FORMAT; 533 534 if (!errnum && pu.aout->a_syms 535 && pu.aout->a_syms < (filemax - filepos)) 536 { 537 int symtab_err, orig_addr = cur_addr; 538 539 /* we should align to a 4K boundary here for good measure */ 540 if (align_4k) 541 cur_addr = (cur_addr + 0xFFF) & 0xFFFFF000; 542 543 mbi.syms.a.addr = cur_addr; 544 545 *((int *) RAW_ADDR (cur_addr)) = pu.aout->a_syms; 546 cur_addr += sizeof (int); 547 548 printf (", symtab=0x%x", pu.aout->a_syms); 549 550 if (grub_read ((char *) RAW_ADDR (cur_addr), pu.aout->a_syms) 551 == pu.aout->a_syms) 552 { 553 cur_addr += pu.aout->a_syms; 554 mbi.syms.a.tabsize = pu.aout->a_syms; 555 556 if (grub_read ((char *) &i, sizeof (int)) == sizeof (int)) 557 { 558 *((int *) RAW_ADDR (cur_addr)) = i; 559 cur_addr += sizeof (int); 560 561 mbi.syms.a.strsize = i; 562 563 i -= sizeof (int); 564 565 printf (", strtab=0x%x", i); 566 567 symtab_err = (grub_read ((char *) RAW_ADDR (cur_addr), i) 568 != i); 569 cur_addr += i; 570 } 571 else 572 symtab_err = 1; 573 } 574 else 575 symtab_err = 1; 576 577 if (symtab_err) 578 { 579 printf ("(bad)"); 580 cur_addr = orig_addr; 581 mbi.syms.a.tabsize = 0; 582 mbi.syms.a.strsize = 0; 583 mbi.syms.a.addr = 0; 584 } 585 else 586 mbi.flags |= MB_INFO_AOUT_SYMS; 587 } 588 } 589 else 590 /* ELF executable */ 591 { 592 unsigned loaded = 0, memaddr, memsiz, filesiz; 593 Elf32_Phdr *phdr; 594 595 /* reset this to zero for now */ 596 cur_addr = 0; 597 598 /* scan for program segments */ 599 for (i = 0; i < pu.elf->e_phnum; i++) 600 { 601 phdr = (Elf32_Phdr *) 602 (pu.elf->e_phoff + ((int) buffer) 603 + (pu.elf->e_phentsize * i)); 604 if (phdr->p_type == PT_LOAD) 605 { 606 /* offset into file */ 607 grub_seek (phdr->p_offset); 608 filesiz = phdr->p_filesz; 609 610 if (type == KERNEL_TYPE_FREEBSD || type == KERNEL_TYPE_NETBSD) 611 memaddr = RAW_ADDR (phdr->p_paddr & 0xFFFFFF); 612 else 613 memaddr = RAW_ADDR (phdr->p_paddr); 614 615 memsiz = phdr->p_memsz; 616 if (memaddr < RAW_ADDR (0x100000)) 617 errnum = ERR_BELOW_1MB; 618 619 /* If the memory range contains the entry address, get the 620 physical address here. */ 621 if (type == KERNEL_TYPE_MULTIBOOT 622 && (unsigned) entry_addr >= phdr->p_vaddr 623 && (unsigned) entry_addr < phdr->p_vaddr + memsiz) 624 real_entry_addr = (entry_func) ((unsigned) entry_addr 625 + memaddr - phdr->p_vaddr); 626 627 /* make sure we only load what we're supposed to! */ 628 if (filesiz > memsiz) 629 filesiz = memsiz; 630 /* mark memory as used */ 631 if (cur_addr < memaddr + memsiz) 632 cur_addr = memaddr + memsiz; 633 printf (", <0x%x:0x%x:0x%x>", memaddr, filesiz, 634 memsiz - filesiz); 635 /* increment number of segments */ 636 loaded++; 637 638 /* load the segment */ 639 if (memcheck (memaddr, memsiz) 640 && grub_read ((char *) memaddr, filesiz) == filesiz) 641 { 642 if (memsiz > filesiz) 643 memset ((char *) (memaddr + filesiz), 0, memsiz - filesiz); 644 } 645 else 646 break; 647 } 648 } 649 650 if (! errnum) 651 { 652 if (! loaded) 653 errnum = ERR_EXEC_FORMAT; 654 else 655 { 656 /* Load ELF symbols. */ 657 Elf32_Shdr *shdr = NULL; 658 int tab_size, sec_size; 659 int symtab_err = 0; 660 661 mbi.syms.e.num = pu.elf->e_shnum; 662 mbi.syms.e.size = pu.elf->e_shentsize; 663 mbi.syms.e.shndx = pu.elf->e_shstrndx; 664 665 /* We should align to a 4K boundary here for good measure. */ 666 if (align_4k) 667 cur_addr = (cur_addr + 0xFFF) & 0xFFFFF000; 668 669 tab_size = pu.elf->e_shentsize * pu.elf->e_shnum; 670 671 grub_seek (pu.elf->e_shoff); 672 if (grub_read ((char *) RAW_ADDR (cur_addr), tab_size) 673 == tab_size) 674 { 675 mbi.syms.e.addr = cur_addr; 676 shdr = (Elf32_Shdr *) mbi.syms.e.addr; 677 cur_addr += tab_size; 678 679 printf (", shtab=0x%x", cur_addr); 680 681 for (i = 0; i < mbi.syms.e.num; i++) 682 { 683 /* This section is a loaded section, 684 so we don't care. */ 685 if (shdr[i].sh_addr != 0) 686 continue; 687 688 /* This section is empty, so we don't care. */ 689 if (shdr[i].sh_size == 0) 690 continue; 691 692 /* Align the section to a sh_addralign bits boundary. */ 693 cur_addr = ((cur_addr + shdr[i].sh_addralign) & 694 - (int) shdr[i].sh_addralign); 695 696 grub_seek (shdr[i].sh_offset); 697 698 sec_size = shdr[i].sh_size; 699 700 if (! (memcheck (cur_addr, sec_size) 701 && (grub_read ((char *) RAW_ADDR (cur_addr), 702 sec_size) 703 == sec_size))) 704 { 705 symtab_err = 1; 706 break; 707 } 708 709 shdr[i].sh_addr = cur_addr; 710 cur_addr += sec_size; 711 } 712 } 713 else 714 symtab_err = 1; 715 716 if (mbi.syms.e.addr < RAW_ADDR(0x10000)) 717 symtab_err = 1; 718 719 if (symtab_err) 720 { 721 printf ("(bad)"); 722 mbi.syms.e.num = 0; 723 mbi.syms.e.size = 0; 724 mbi.syms.e.addr = 0; 725 mbi.syms.e.shndx = 0; 726 cur_addr = 0; 727 } 728 else 729 mbi.flags |= MB_INFO_ELF_SHDR; 730 } 731 } 732 } 733 734 if (! errnum) 735 { 736 grub_printf (", entry=0x%x]\n", (unsigned) entry_addr); 737 738 /* If the entry address is physically different from that of the ELF 739 header, correct it here. */ 740 if (real_entry_addr) 741 entry_addr = real_entry_addr; 742 } 743 else 744 { 745 putchar ('\n'); 746 type = KERNEL_TYPE_NONE; 747 } 748 749 grub_close (); 750 751 /* Sanity check. */ 752 if (suggested_type != KERNEL_TYPE_NONE && suggested_type != type) 753 { 754 errnum = ERR_EXEC_FORMAT; 755 return KERNEL_TYPE_NONE; 756 } 757 758 return type; 759 } 760 761 int 762 load_module (char *module, char *arg) 763 { 764 int len; 765 766 /* if we are supposed to load on 4K boundaries */ 767 cur_addr = (cur_addr + 0xFFF) & 0xFFFFF000; 768 769 if (!grub_open (module)) 770 return 0; 771 772 len = grub_read ((char *) cur_addr, -1); 773 if (! len) 774 { 775 grub_close (); 776 return 0; 777 } 778 779 printf (" [Multiboot-module @ 0x%x, 0x%x bytes]\n", cur_addr, len); 780 781 /* these two simply need to be set if any modules are loaded at all */ 782 mbi.flags |= MB_INFO_MODS; 783 mbi.mods_addr = (int) mll; 784 785 mll[mbi.mods_count].cmdline = (int) arg; 786 mll[mbi.mods_count].mod_start = cur_addr; 787 cur_addr += len; 788 mll[mbi.mods_count].mod_end = cur_addr; 789 mll[mbi.mods_count].pad = 0; 790 791 /* increment number of modules included */ 792 mbi.mods_count++; 793 794 grub_close (); 795 return 1; 796 } 797 798 int 799 load_initrd (char *initrd) 800 { 801 int len; 802 unsigned long moveto; 803 unsigned long max_addr; 804 struct linux_kernel_header *lh 805 = (struct linux_kernel_header *) (cur_addr - LINUX_SETUP_MOVE_SIZE); 806 807 #ifndef NO_DECOMPRESSION 808 no_decompression = 1; 809 #endif 810 811 if (! grub_open (initrd)) 812 goto fail; 813 814 len = grub_read ((char *) cur_addr, -1); 815 if (! len) 816 { 817 grub_close (); 818 goto fail; 819 } 820 821 if (linux_mem_size) 822 moveto = linux_mem_size; 823 else 824 moveto = (mbi.mem_upper + 0x400) << 10; 825 826 moveto = (moveto - len) & 0xfffff000; 827 max_addr = (lh->header == LINUX_MAGIC_SIGNATURE && lh->version >= 0x0203 828 ? lh->initrd_addr_max : LINUX_INITRD_MAX_ADDRESS); 829 if (moveto + len >= max_addr) 830 moveto = (max_addr - len) & 0xfffff000; 831 832 /* XXX: Linux 2.3.xx has a bug in the memory range check, so avoid 833 the last page. 834 XXX: Linux 2.2.xx has a bug in the memory range check, which is 835 worse than that of Linux 2.3.xx, so avoid the last 64kb. *sigh* */ 836 moveto -= 0x10000; 837 memmove ((void *) RAW_ADDR (moveto), (void *) cur_addr, len); 838 839 printf (" [Linux-initrd @ 0x%x, 0x%x bytes]\n", moveto, len); 840 841 /* FIXME: Should check if the kernel supports INITRD. */ 842 lh->ramdisk_image = RAW_ADDR (moveto); 843 lh->ramdisk_size = len; 844 845 grub_close (); 846 847 fail: 848 849 #ifndef NO_DECOMPRESSION 850 no_decompression = 0; 851 #endif 852 853 return ! errnum; 854 } 855 856 857 #ifdef GRUB_UTIL 858 /* Dummy function to fake the *BSD boot. */ 859 static void 860 bsd_boot_entry (int flags, int bootdev, int sym_start, int sym_end, 861 int mem_upper, int mem_lower) 862 { 863 stop (); 864 } 865 #endif 866 867 868 /* 869 * All "*_boot" commands depend on the images being loaded into memory 870 * correctly, the variables in this file being set up correctly, and 871 * the root partition being set in the 'saved_drive' and 'saved_partition' 872 * variables. 873 */ 874 875 876 void 877 bsd_boot (kernel_t type, int bootdev, char *arg) 878 { 879 char *str; 880 int clval = 0, i; 881 struct bootinfo bi; 882 883 #ifdef GRUB_UTIL 884 entry_addr = (entry_func) bsd_boot_entry; 885 #else 886 stop_floppy (); 887 #endif 888 889 while (*(++arg) && *arg != ' '); 890 str = arg; 891 while (*str) 892 { 893 if (*str == '-') 894 { 895 while (*str && *str != ' ') 896 { 897 if (*str == 'C') 898 clval |= RB_CDROM; 899 if (*str == 'a') 900 clval |= RB_ASKNAME; 901 if (*str == 'b') 902 clval |= RB_HALT; 903 if (*str == 'c') 904 clval |= RB_CONFIG; 905 if (*str == 'd') 906 clval |= RB_KDB; 907 if (*str == 'D') 908 clval |= RB_MULTIPLE; 909 if (*str == 'g') 910 clval |= RB_GDB; 911 if (*str == 'h') 912 clval |= RB_SERIAL; 913 if (*str == 'm') 914 clval |= RB_MUTE; 915 if (*str == 'r') 916 clval |= RB_DFLTROOT; 917 if (*str == 's') 918 clval |= RB_SINGLE; 919 if (*str == 'v') 920 clval |= RB_VERBOSE; 921 str++; 922 } 923 continue; 924 } 925 str++; 926 } 927 928 if (type == KERNEL_TYPE_FREEBSD) 929 { 930 clval |= RB_BOOTINFO; 931 932 bi.bi_version = BOOTINFO_VERSION; 933 934 *arg = 0; 935 while ((--arg) > (char *) MB_CMDLINE_BUF && *arg != '/'); 936 if (*arg == '/') 937 bi.bi_kernelname = arg + 1; 938 else 939 bi.bi_kernelname = 0; 940 941 bi.bi_nfs_diskless = 0; 942 bi.bi_n_bios_used = 0; /* this field is apparently unused */ 943 944 for (i = 0; i < N_BIOS_GEOM; i++) 945 { 946 struct geometry geom; 947 948 /* XXX Should check the return value. */ 949 get_diskinfo (i + 0x80, &geom); 950 /* FIXME: If HEADS or SECTORS is greater than 255, then this will 951 break the geometry information. That is a drawback of BSD 952 but not of GRUB. */ 953 bi.bi_bios_geom[i] = (((geom.cylinders - 1) << 16) 954 + (((geom.heads - 1) & 0xff) << 8) 955 + (geom.sectors & 0xff)); 956 } 957 958 bi.bi_size = sizeof (struct bootinfo); 959 bi.bi_memsizes_valid = 1; 960 bi.bi_bios_dev = saved_drive; 961 bi.bi_basemem = mbi.mem_lower; 962 bi.bi_extmem = extended_memory; 963 964 if (mbi.flags & MB_INFO_AOUT_SYMS) 965 { 966 bi.bi_symtab = mbi.syms.a.addr; 967 bi.bi_esymtab = mbi.syms.a.addr + 4 968 + mbi.syms.a.tabsize + mbi.syms.a.strsize; 969 } 970 #if 0 971 else if (mbi.flags & MB_INFO_ELF_SHDR) 972 { 973 /* FIXME: Should check if a symbol table exists and, if exists, 974 pass the table to BI. */ 975 } 976 #endif 977 else 978 { 979 bi.bi_symtab = 0; 980 bi.bi_esymtab = 0; 981 } 982 983 /* call entry point */ 984 (*entry_addr) (clval, bootdev, 0, 0, 0, ((int) (&bi))); 985 } 986 else 987 { 988 /* 989 * We now pass the various bootstrap parameters to the loaded 990 * image via the argument list. 991 * 992 * This is the official list: 993 * 994 * arg0 = 8 (magic) 995 * arg1 = boot flags 996 * arg2 = boot device 997 * arg3 = start of symbol table (0 if not loaded) 998 * arg4 = end of symbol table (0 if not loaded) 999 * arg5 = transfer address from image 1000 * arg6 = transfer address for next image pointer 1001 * arg7 = conventional memory size (640) 1002 * arg8 = extended memory size (8196) 1003 * 1004 * ...in actuality, we just pass the parameters used by the kernel. 1005 */ 1006 1007 /* call entry point */ 1008 unsigned long end_mark; 1009 1010 if (mbi.flags & MB_INFO_AOUT_SYMS) 1011 end_mark = (mbi.syms.a.addr + 4 1012 + mbi.syms.a.tabsize + mbi.syms.a.strsize); 1013 else 1014 /* FIXME: it should be mbi.syms.e.size. */ 1015 end_mark = 0; 1016 1017 (*entry_addr) (clval, bootdev, 0, end_mark, 1018 extended_memory, mbi.mem_lower); 1019 } 1020 } 1021