static grub_err_t grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)), int argc, char *argv[]) { grub_file_t file = 0; struct linux_kernel_header lh; grub_ssize_t len, start, filelen; void *kernel = NULL; grub_dl_ref (my_mod); if (argc == 0) { grub_error (GRUB_ERR_BAD_ARGUMENT, N_("filename expected")); goto fail; } file = grub_file_open (argv[0]); if (! file) goto fail; filelen = grub_file_size (file); kernel = grub_malloc(filelen); if (!kernel) { grub_error (GRUB_ERR_OUT_OF_MEMORY, N_("cannot allocate kernel buffer")); goto fail; } if (grub_file_read (file, kernel, filelen) != filelen) { grub_error (GRUB_ERR_FILE_READ_ERROR, N_("Can't read kernel %s"), argv[0]); goto fail; } grub_tpm_measure (kernel, filelen, GRUB_KERNEL_PCR); if (! grub_linuxefi_secure_validate (kernel, filelen)) { grub_error (GRUB_ERR_INVALID_COMMAND, N_("%s has invalid signature"), argv[0]); grub_free (kernel); goto fail; } params = grub_efi_allocate_pages_max (0x3fffffff, BYTES_TO_PAGES(16384)); if (! params) { grub_error (GRUB_ERR_OUT_OF_MEMORY, "cannot allocate kernel parameters"); goto fail; } grub_memset (params, 0, 16384); grub_memcpy (&lh, kernel, sizeof (lh)); if (lh.boot_flag != grub_cpu_to_le16 (0xaa55)) { grub_error (GRUB_ERR_BAD_OS, N_("invalid magic number")); goto fail; } if (lh.setup_sects > GRUB_LINUX_MAX_SETUP_SECTS) { grub_error (GRUB_ERR_BAD_OS, N_("too many setup sectors")); goto fail; } if (lh.version < grub_cpu_to_le16 (0x020b)) { grub_error (GRUB_ERR_BAD_OS, N_("kernel too old")); goto fail; } if (!lh.handover_offset) { grub_error (GRUB_ERR_BAD_OS, N_("kernel doesn't support EFI handover")); goto fail; } linux_cmdline = grub_efi_allocate_pages_max(0x3fffffff, BYTES_TO_PAGES(lh.cmdline_size + 1)); if (!linux_cmdline) { grub_error (GRUB_ERR_OUT_OF_MEMORY, N_("can't allocate cmdline")); goto fail; } grub_memcpy (linux_cmdline, LINUX_IMAGE, sizeof (LINUX_IMAGE)); grub_create_loader_cmdline (argc, argv, linux_cmdline + sizeof (LINUX_IMAGE) - 1, lh.cmdline_size - (sizeof (LINUX_IMAGE) - 1)); grub_pass_verity_hash(&lh, linux_cmdline); lh.cmd_line_ptr = (grub_uint32_t)(grub_uint64_t)linux_cmdline; handover_offset = lh.handover_offset; start = (lh.setup_sects + 1) * 512; len = grub_file_size(file) - start; kernel_mem = grub_efi_allocate_pages(lh.pref_address, BYTES_TO_PAGES(lh.init_size)); if (!kernel_mem) kernel_mem = grub_efi_allocate_pages_max(0x3fffffff, BYTES_TO_PAGES(lh.init_size)); if (!kernel_mem) { grub_error (GRUB_ERR_OUT_OF_MEMORY, N_("can't allocate kernel")); goto fail; } grub_memcpy (kernel_mem, (char *)kernel + start, len); grub_loader_set (grub_linuxefi_boot, grub_linuxefi_unload, 0); loaded=1; lh.code32_start = (grub_uint32_t)(grub_uint64_t) kernel_mem; grub_memcpy (params, &lh, 2 * 512); params->type_of_loader = 0x21; fail: if (file) grub_file_close (file); if (kernel) grub_free (kernel); if (grub_errno != GRUB_ERR_NONE) { grub_dl_unref (my_mod); loaded = 0; } if (linux_cmdline && !loaded) grub_efi_free_pages((grub_efi_physical_address_t)linux_cmdline, BYTES_TO_PAGES(lh.cmdline_size + 1)); if (kernel_mem && !loaded) grub_efi_free_pages((grub_efi_physical_address_t)kernel_mem, BYTES_TO_PAGES(kernel_size)); if (params && !loaded) grub_efi_free_pages((grub_efi_physical_address_t)params, BYTES_TO_PAGES(16384)); return grub_errno; }
static grub_err_t grub_cmd_initrd (grub_command_t cmd __attribute__ ((unused)), int argc, char *argv[]) { grub_file_t *files = 0; int i, nfiles = 0; grub_size_t size = 0; grub_uint8_t *ptr; if (argc == 0) { grub_error (GRUB_ERR_BAD_ARGUMENT, N_("filename expected")); goto fail; } if (!loaded) { grub_error (GRUB_ERR_BAD_ARGUMENT, N_("you need to load the kernel first")); goto fail; } files = grub_zalloc (argc * sizeof (files[0])); if (!files) goto fail; for (i = 0; i < argc; i++) { grub_file_filter_disable_compression (); files[i] = grub_file_open (argv[i]); if (! files[i]) goto fail; nfiles++; size += ALIGN_UP (grub_file_size (files[i]), 4); } initrd_mem = grub_efi_allocate_pages_max (0x3fffffff, BYTES_TO_PAGES(size)); if (!initrd_mem) { grub_error (GRUB_ERR_OUT_OF_MEMORY, N_("can't allocate initrd")); goto fail; } params->ramdisk_size = size; params->ramdisk_image = (grub_uint32_t)(grub_uint64_t) initrd_mem; ptr = initrd_mem; for (i = 0; i < nfiles; i++) { grub_ssize_t cursize = grub_file_size (files[i]); if (grub_file_read (files[i], ptr, cursize) != cursize) { if (!grub_errno) grub_error (GRUB_ERR_FILE_READ_ERROR, N_("premature end of file %s"), argv[i]); goto fail; } grub_tpm_measure (ptr, cursize, GRUB_INITRD_PCR); ptr += cursize; grub_memset (ptr, 0, ALIGN_UP_OVERHEAD (cursize, 4)); ptr += ALIGN_UP_OVERHEAD (cursize, 4); } params->ramdisk_size = size; fail: for (i = 0; i < nfiles; i++) grub_file_close (files[i]); grub_free (files); if (initrd_mem && grub_errno) grub_efi_free_pages((grub_efi_physical_address_t)initrd_mem, BYTES_TO_PAGES(size)); return grub_errno; }
static grub_err_t grub_cmd_module (grub_command_t cmd __attribute__ ((unused)), int argc, char *argv[]) { grub_file_t file = 0; grub_ssize_t size; void *module = NULL; grub_addr_t target; grub_err_t err; int nounzip = 0; grub_uint64_t lowest_addr = 0; if (argc == 0) return grub_error (GRUB_ERR_BAD_ARGUMENT, N_("filename expected")); if (grub_strcmp (argv[0], "--nounzip") == 0) { argv++; argc--; nounzip = 1; } if (argc == 0) return grub_error (GRUB_ERR_BAD_ARGUMENT, N_("filename expected")); if (!grub_multiboot_relocator) return grub_error (GRUB_ERR_BAD_ARGUMENT, N_("you need to load the kernel first")); if (nounzip) grub_file_filter_disable_compression (); file = grub_file_open (argv[0]); if (! file) return grub_errno; #ifndef GRUB_USE_MULTIBOOT2 lowest_addr = 0x100000; if (grub_multiboot_quirks & GRUB_MULTIBOOT_QUIRK_MODULES_AFTER_KERNEL) lowest_addr = ALIGN_UP (highest_load + 1048576, 4096); #endif size = grub_file_size (file); if (size) { grub_relocator_chunk_t ch; err = grub_relocator_alloc_chunk_align (grub_multiboot_relocator, &ch, lowest_addr, (0xffffffff - size) + 1, size, MULTIBOOT_MOD_ALIGN, GRUB_RELOCATOR_PREFERENCE_NONE, 1); if (err) { grub_file_close (file); return err; } module = get_virtual_current_address (ch); target = get_physical_target_address (ch); } else { module = 0; target = 0; } err = grub_multiboot_add_module (target, size, argc - 1, argv + 1); if (err) { grub_file_close (file); return err; } if (size && grub_file_read (file, module, size) != size) { grub_file_close (file); if (!grub_errno) grub_error (GRUB_ERR_FILE_READ_ERROR, N_("premature end of file %s"), argv[0]); return grub_errno; } grub_file_close (file); grub_tpm_measure (module, size, GRUB_BINARY_PCR, "grub_multiboot", argv[0]); return GRUB_ERR_NONE; }
grub_err_t grub_multiboot_load (grub_file_t file, const char *filename) { grub_properly_aligned_t *buffer; grub_ssize_t len; struct multiboot_header *header; grub_err_t err; struct multiboot_header_tag *tag; struct multiboot_header_tag_address *addr_tag = NULL; int entry_specified = 0; grub_addr_t entry = 0; grub_uint32_t console_required = 0; struct multiboot_header_tag_framebuffer *fbtag = NULL; int accepted_consoles = GRUB_MULTIBOOT_CONSOLE_EGA_TEXT; buffer = grub_malloc (MULTIBOOT_SEARCH); if (!buffer) return grub_errno; len = grub_file_read (file, buffer, MULTIBOOT_SEARCH); if (len < 32) { grub_free (buffer); return grub_error (GRUB_ERR_BAD_OS, N_("premature end of file %s"), filename); } COMPILE_TIME_ASSERT (MULTIBOOT_HEADER_ALIGN % 4 == 0); grub_tpm_measure ((unsigned char *)buffer, len, GRUB_BINARY_PCR, "grub_multiboot", filename); header = find_header (buffer, len); if (header == 0) { grub_free (buffer); return grub_error (GRUB_ERR_BAD_ARGUMENT, "no multiboot header found"); } COMPILE_TIME_ASSERT (MULTIBOOT_TAG_ALIGN % 4 == 0); keep_bs = 0; for (tag = (struct multiboot_header_tag *) (header + 1); tag->type != MULTIBOOT_TAG_TYPE_END; tag = (struct multiboot_header_tag *) ((grub_uint32_t *) tag + ALIGN_UP (tag->size, MULTIBOOT_TAG_ALIGN) / 4)) switch (tag->type) { case MULTIBOOT_HEADER_TAG_INFORMATION_REQUEST: { unsigned i; struct multiboot_header_tag_information_request *request_tag = (struct multiboot_header_tag_information_request *) tag; if (request_tag->flags & MULTIBOOT_HEADER_TAG_OPTIONAL) break; for (i = 0; i < (request_tag->size - sizeof (*request_tag)) / sizeof (request_tag->requests[0]); i++) switch (request_tag->requests[i]) { case MULTIBOOT_TAG_TYPE_END: case MULTIBOOT_TAG_TYPE_CMDLINE: case MULTIBOOT_TAG_TYPE_BOOT_LOADER_NAME: case MULTIBOOT_TAG_TYPE_MODULE: case MULTIBOOT_TAG_TYPE_BASIC_MEMINFO: case MULTIBOOT_TAG_TYPE_BOOTDEV: case MULTIBOOT_TAG_TYPE_MMAP: case MULTIBOOT_TAG_TYPE_FRAMEBUFFER: case MULTIBOOT_TAG_TYPE_VBE: case MULTIBOOT_TAG_TYPE_ELF_SECTIONS: case MULTIBOOT_TAG_TYPE_APM: case MULTIBOOT_TAG_TYPE_EFI32: case MULTIBOOT_TAG_TYPE_EFI64: case MULTIBOOT_TAG_TYPE_ACPI_OLD: case MULTIBOOT_TAG_TYPE_ACPI_NEW: case MULTIBOOT_TAG_TYPE_NETWORK: case MULTIBOOT_TAG_TYPE_EFI_MMAP: case MULTIBOOT_TAG_TYPE_EFI_BS: break; default: grub_free (buffer); return grub_error (GRUB_ERR_UNKNOWN_OS, "unsupported information tag: 0x%x", request_tag->requests[i]); } break; } case MULTIBOOT_HEADER_TAG_ADDRESS: addr_tag = (struct multiboot_header_tag_address *) tag; break; case MULTIBOOT_HEADER_TAG_ENTRY_ADDRESS: entry_specified = 1; entry = ((struct multiboot_header_tag_entry_address *) tag)->entry_addr; break; case MULTIBOOT_HEADER_TAG_CONSOLE_FLAGS: if (!(((struct multiboot_header_tag_console_flags *) tag)->console_flags & MULTIBOOT_CONSOLE_FLAGS_EGA_TEXT_SUPPORTED)) accepted_consoles &= ~GRUB_MULTIBOOT_CONSOLE_EGA_TEXT; if (((struct multiboot_header_tag_console_flags *) tag)->console_flags & MULTIBOOT_CONSOLE_FLAGS_CONSOLE_REQUIRED) console_required = 1; break; case MULTIBOOT_HEADER_TAG_FRAMEBUFFER: fbtag = (struct multiboot_header_tag_framebuffer *) tag; accepted_consoles |= GRUB_MULTIBOOT_CONSOLE_FRAMEBUFFER; break; /* GRUB always page-aligns modules. */ case MULTIBOOT_HEADER_TAG_MODULE_ALIGN: break; case MULTIBOOT_HEADER_TAG_EFI_BS: keep_bs = 1; break; default: if (! (tag->flags & MULTIBOOT_HEADER_TAG_OPTIONAL)) { grub_free (buffer); return grub_error (GRUB_ERR_UNKNOWN_OS, "unsupported tag: 0x%x", tag->type); } break; } if (addr_tag && !entry_specified) { grub_free (buffer); return grub_error (GRUB_ERR_UNKNOWN_OS, "load address tag without entry address tag"); } if (addr_tag) { grub_uint64_t load_addr = (addr_tag->load_addr + 1) ? addr_tag->load_addr : (addr_tag->header_addr - ((char *) header - (char *) buffer)); int offset = ((char *) header - (char *) buffer - (addr_tag->header_addr - load_addr)); int load_size = ((addr_tag->load_end_addr == 0) ? file->size - offset : addr_tag->load_end_addr - addr_tag->load_addr); grub_size_t code_size; void *source; grub_relocator_chunk_t ch; if (addr_tag->bss_end_addr) code_size = (addr_tag->bss_end_addr - load_addr); else code_size = load_size; err = grub_relocator_alloc_chunk_addr (grub_multiboot_relocator, &ch, load_addr, code_size); if (err) { grub_dprintf ("multiboot_loader", "Error loading aout kludge\n"); grub_free (buffer); return err; } source = get_virtual_current_address (ch); if ((grub_file_seek (file, offset)) == (grub_off_t) -1) { grub_free (buffer); return grub_errno; } grub_file_read (file, source, load_size); if (grub_errno) { grub_free (buffer); return grub_errno; } if (addr_tag->bss_end_addr) grub_memset ((grub_uint8_t *) source + load_size, 0, addr_tag->bss_end_addr - load_addr - load_size); } else { err = grub_multiboot_load_elf (file, filename, buffer); if (err) { grub_free (buffer); return err; } } if (entry_specified) grub_multiboot_payload_eip = entry; if (fbtag) err = grub_multiboot_set_console (GRUB_MULTIBOOT_CONSOLE_FRAMEBUFFER, accepted_consoles, fbtag->width, fbtag->height, fbtag->depth, console_required); else err = grub_multiboot_set_console (GRUB_MULTIBOOT_CONSOLE_EGA_TEXT, accepted_consoles, 0, 0, 0, console_required); return err; }
grub_err_t grub_multiboot_load (grub_file_t file, const char *filename) { char *buffer; grub_ssize_t len; struct multiboot_header *header; grub_err_t err; buffer = grub_malloc (MULTIBOOT_SEARCH); if (!buffer) return grub_errno; len = grub_file_read (file, buffer, MULTIBOOT_SEARCH); if (len < 32) { grub_free (buffer); if (!grub_errno) grub_error (GRUB_ERR_BAD_OS, N_("premature end of file %s"), filename); return grub_errno; } grub_tpm_measure((unsigned char*)buffer, len, GRUB_KERNEL_PCR, filename); header = find_header (buffer, len); if (header == 0) { grub_free (buffer); return grub_error (GRUB_ERR_BAD_ARGUMENT, "no multiboot header found"); } if (header->flags & UNSUPPORTED_FLAGS) { grub_free (buffer); return grub_error (GRUB_ERR_UNKNOWN_OS, "unsupported flag: 0x%x", header->flags); } err = load_kernel (file, filename, buffer, header); if (err) { grub_free (buffer); return err; } if (header->flags & MULTIBOOT_VIDEO_MODE) { switch (header->mode_type) { case 1: err = grub_multiboot_set_console (GRUB_MULTIBOOT_CONSOLE_EGA_TEXT, GRUB_MULTIBOOT_CONSOLE_EGA_TEXT | GRUB_MULTIBOOT_CONSOLE_FRAMEBUFFER, 0, 0, 0, 0); break; case 0: err = grub_multiboot_set_console (GRUB_MULTIBOOT_CONSOLE_FRAMEBUFFER, GRUB_MULTIBOOT_CONSOLE_EGA_TEXT | GRUB_MULTIBOOT_CONSOLE_FRAMEBUFFER, header->width, header->height, header->depth, 0); break; default: err = grub_error (GRUB_ERR_BAD_OS, "unsupported graphical mode type %d", header->mode_type); break; } } else err = grub_multiboot_set_console (GRUB_MULTIBOOT_CONSOLE_EGA_TEXT, GRUB_MULTIBOOT_CONSOLE_EGA_TEXT, 0, 0, 0, 0); return err; }