/* multiboot_loader.c - boot multiboot 1 or 2 OS image */ /* * GRUB -- GRand Unified Bootloader * Copyright (C) 2007,2008 Free Software Foundation, Inc. * * GRUB is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * GRUB is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with GRUB. If not, see . */ #include #include #include #include #include #include #include #include #include #include #include grub_dl_t my_mod; /* This tracks which version of multiboot to use when using * the module command. By default use multiboot version 1. * values: * 1 - Multiboot version 1 * 2 - Multiboot version 2 */ static unsigned int module_version_status = 1; static int find_multi_boot1_header (grub_file_t file) { struct multiboot_header *header; char buffer[MULTIBOOT_SEARCH]; int found_status = 0; grub_ssize_t len; len = grub_file_read (file, buffer, MULTIBOOT_SEARCH); if (len < 32) return found_status; /* Look for the multiboot header in the buffer. The header should be at least 12 bytes and aligned on a 4-byte boundary. */ for (header = (struct multiboot_header *) buffer; ((char *) header <= buffer + len - 12) || (header = 0); header = (struct multiboot_header *) ((char *) header + 4)) { if (header->magic == MULTIBOOT_HEADER_MAGIC && !(header->magic + header->flags + header->checksum)) { found_status = 1; break; } } return found_status; } static int find_multi_boot2_header (grub_file_t file) { struct multiboot_header *header; char buffer[MULTIBOOT_SEARCH]; int found_status = 0; grub_ssize_t len; len = grub_file_read (file, buffer, MULTIBOOT_SEARCH); if (len < 32) return found_status; /* Look for the multiboot header in the buffer. The header should be at least 8 bytes and aligned on a 8-byte boundary. */ for (header = (struct multiboot_header *) buffer; ((char *) header <= buffer + len - 8) || (header = 0); header = (struct multiboot_header *) ((char *) header + 8)) { if (header->magic == MULTIBOOT2_HEADER_MAGIC) { found_status = 1; break; } } return found_status; } static grub_err_t grub_cmd_multiboot_loader (grub_command_t cmd __attribute__ ((unused)), int argc, char *argv[]) { grub_file_t file = 0; int header_multi_ver_found = 0; grub_dl_ref (my_mod); if (argc == 0) { grub_error (GRUB_ERR_BAD_ARGUMENT, "no kernel specified"); goto fail; } file = grub_gzfile_open (argv[0], 1); if (! file) { grub_error (GRUB_ERR_BAD_ARGUMENT, "couldn't open file"); goto fail; } /* find which header is in the file */ if (find_multi_boot1_header (file)) header_multi_ver_found = 1; else if (find_multi_boot2_header (file)) header_multi_ver_found = 2; else { grub_error (GRUB_ERR_BAD_OS, "multiboot header not found"); goto fail; } /* close file before calling functions */ if (file) grub_file_close (file); /* Launch multi boot with header */ /* XXX Find a better way to identify this. This is for i386-pc */ #if defined(GRUB_MACHINE_PCBIOS) || defined(GRUB_MACHINE_COREBOOT) || \ defined(GRUB_MACHINE_QEMU) if (header_multi_ver_found == 1) { grub_dprintf ("multiboot_loader", "Launching multiboot 1 grub_multiboot() function\n"); grub_multiboot (argc, argv); module_version_status = 1; } #endif if (header_multi_ver_found == 0 || header_multi_ver_found == 2) { grub_dprintf ("multiboot_loader", "Launching multiboot 2 grub_multiboot2() function\n"); grub_multiboot2 (argc, argv); module_version_status = 2; } return grub_errno; fail: if (file) grub_file_close (file); grub_dl_unref (my_mod); return grub_errno; } static grub_err_t grub_cmd_module_loader (grub_command_t cmd __attribute__ ((unused)), int argc, char *argv[]) { #if defined(GRUB_MACHINE_PCBIOS) || defined(GRUB_MACHINE_COREBOOT) || \ defined(GRUB_MACHINE_QEMU) if (module_version_status == 1) { grub_dprintf("multiboot_loader", "Launching multiboot 1 grub_module() function\n"); grub_module (argc, argv); } #endif if (module_version_status == 2) { grub_dprintf("multiboot_loader", "Launching multiboot 2 grub_module2() function\n"); grub_module2 (argc, argv); } return grub_errno; } static grub_command_t cmd_multiboot, cmd_module; GRUB_MOD_INIT(multiboot) { cmd_multiboot = grub_register_command ("multiboot", grub_cmd_multiboot_loader, 0, "Load a multiboot kernel."); cmd_module = grub_register_command ("module", grub_cmd_module_loader, 0, "Load a multiboot module."); my_mod = mod; } GRUB_MOD_FINI(multiboot) { grub_unregister_command (cmd_multiboot); grub_unregister_command (cmd_module); }