diff --git a/ChangeLog b/ChangeLog index 86c1d6ceb..b15ba47d5 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,43 @@ +2010-03-28 Vladimir Serbinenko + + Multiboot2 tag support + + * conf/i386.rmk (multiboot2_mod_SOURCES): Replace + loader/i386/multiboot_mbi.c with loader/i386/multiboot_mbi2.c. + Remove loader/multiboot_loader.c. + * include/grub/i386/multiboot.h (grub_multiboot_real_boot): Removed. + (grub_multiboot2_real_boot): Likewise. + * include/grub/multiboot.h (grub_multiboot_set_accepts_video): Removed. + (grub_get_multiboot_mmap_count): New proto. + (grub_fill_multiboot_mmap): Likewise. + (grub_multiboot_set_video_mode): Likewise. + (grub_multiboot_set_console): Likewise. + (grub_multiboot_load): Likewise. + (grub_multiboot_load_elf): Likewise. + (GRUB_MULTIBOOT_CONSOLE_EGA_TEXT): New definition. + (GRUB_MULTIBOOT_CONSOLE_FRAMEBUFFER): Likewise. + * include/multiboot.h: Resynced with specification. + * include/multiboot2.h: Resynced with specification. + * loader/i386/multiboot_mbi.c (DEFAULT_VIDEO_MODE): Moved from here... + * loader/i386/multiboot.c (DEFAULT_VIDEO_MODE): ... here. + * loader/i386/multiboot_mbi.c (HAS_VGA_TEXT): Moved from here .. + * include/grub/multiboot.h (GRUB_MACHINE_HAS_VGA_TEXT): ... here. All + users updated. + * loader/i386/multiboot_mbi.c (accepts_video): Moved from here... + * loader/i386/multiboot.c (accepts_video): ... here. All users updated. + * loader/i386/multiboot_mbi.c (grub_multiboot_set_accepts_video): + Removed. + * loader/i386/multiboot_mbi.c (grub_get_multiboot_mmap_len): + Moved from here... + * loader/i386/multiboot.c (grub_get_multiboot_mmap_len): ... here. + * loader/i386/multiboot_mbi.c (grub_fill_multiboot_mmap): + Moved from here... + * loader/i386/multiboot.c (grub_fill_multiboot_mmap): ... here. + * loader/i386/multiboot_mbi.c (set_video_mode): Moved from here... + * loader/i386/multiboot.c (grub_multiboot_set_video_mode): ... here. + All users updated. + * loader/i386/multiboot_mbi2.c: New file. + 2010-03-27 Vladimir Serbinenko Resync with gnulib. diff --git a/conf/i386.rmk b/conf/i386.rmk index 86b6fd795..79a8e430b 100644 --- a/conf/i386.rmk +++ b/conf/i386.rmk @@ -34,16 +34,14 @@ setpci_mod_LDFLAGS = $(COMMON_LDFLAGS) pkglib_MODULES += multiboot.mod multiboot_mod_SOURCES = loader/i386/multiboot.c \ - loader/i386/multiboot_mbi.c \ - loader/multiboot_loader.c + loader/i386/multiboot_mbi.c multiboot_mod_CFLAGS = $(COMMON_CFLAGS) multiboot_mod_LDFLAGS = $(COMMON_LDFLAGS) multiboot_mod_ASFLAGS = $(COMMON_ASFLAGS) pkglib_MODULES += multiboot2.mod multiboot2_mod_SOURCES = loader/i386/multiboot.c \ - loader/i386/multiboot_mbi.c \ - loader/multiboot_loader.c + loader/i386/multiboot_mbi2.c multiboot2_mod_CFLAGS = $(COMMON_CFLAGS) -DGRUB_USE_MULTIBOOT2 multiboot2_mod_LDFLAGS = $(COMMON_LDFLAGS) multiboot2_mod_ASFLAGS = $(COMMON_ASFLAGS) diff --git a/include/grub/i386/multiboot.h b/include/grub/i386/multiboot.h index 584955449..8131e9477 100644 --- a/include/grub/i386/multiboot.h +++ b/include/grub/i386/multiboot.h @@ -19,14 +19,6 @@ #ifndef GRUB_MULTIBOOT_CPU_HEADER #define GRUB_MULTIBOOT_CPU_HEADER 1 -/* The asm part of the multiboot loader. */ -void grub_multiboot_real_boot (grub_addr_t entry, - struct multiboot_info *mbi) - __attribute__ ((noreturn)); -void grub_multiboot2_real_boot (grub_addr_t entry, - struct multiboot_info *mbi) - __attribute__ ((noreturn)); - extern grub_uint32_t grub_multiboot_payload_eip; extern char *grub_multiboot_payload_orig; extern grub_addr_t grub_multiboot_payload_dest; diff --git a/include/grub/multiboot.h b/include/grub/multiboot.h index 665292e33..49d71fa09 100644 --- a/include/grub/multiboot.h +++ b/include/grub/multiboot.h @@ -20,6 +20,8 @@ #ifndef GRUB_MULTIBOOT_HEADER #define GRUB_MULTIBOOT_HEADER 1 +#include + #ifdef GRUB_USE_MULTIBOOT2 #include /* Same thing as far as our loader is concerned. */ @@ -35,8 +37,6 @@ void grub_multiboot (int argc, char *argv[]); void grub_module (int argc, char *argv[]); -void grub_multiboot_set_accepts_video (int val); - grub_size_t grub_multiboot_get_mbi_size (void); grub_err_t grub_multiboot_make_mbi (void *orig, grub_uint32_t dest, grub_off_t buf_off, grub_size_t bufsize); @@ -46,5 +46,29 @@ grub_err_t grub_multiboot_add_module (grub_addr_t start, grub_size_t size, int argc, char *argv[]); void grub_multiboot_set_bootdev (void); +grub_uint32_t grub_get_multiboot_mmap_count (void); +grub_err_t grub_multiboot_set_video_mode (void); + +#if defined (GRUB_MACHINE_PCBIOS) || defined (GRUB_MACHINE_COREBOOT) || defined (GRUB_MACHINE_QEMU) +#include +#define GRUB_MACHINE_HAS_VGA_TEXT 1 +#else +#define GRUB_MACHINE_HAS_VGA_TEXT 0 +#endif + +#define GRUB_MULTIBOOT_CONSOLE_EGA_TEXT 1 +#define GRUB_MULTIBOOT_CONSOLE_FRAMEBUFFER 2 + +grub_err_t +grub_multiboot_set_console (int console_type, int accepted_consoles, + int width, int height, int depth, + int console_required); +grub_err_t +grub_multiboot_load (grub_file_t file); +/* Load ELF32 or ELF64. */ +grub_err_t +grub_multiboot_load_elf (grub_file_t file, void *buffer); +extern grub_size_t grub_multiboot_pure_size; +extern grub_size_t grub_multiboot_alloc_mbi; #endif /* ! GRUB_MULTIBOOT_HEADER */ diff --git a/include/multiboot.h b/include/multiboot.h index c529c5c5f..fda863e85 100644 --- a/include/multiboot.h +++ b/include/multiboot.h @@ -24,6 +24,7 @@ /* How many bytes from the start of the file we search for the header. */ #define MULTIBOOT_SEARCH 8192 +#define MULTIBOOT_HEADER_ALIGN 4 /* The magic field should contain this. */ #define MULTIBOOT_HEADER_MAGIC 0x1BADB002 diff --git a/include/multiboot2.h b/include/multiboot2.h index 1b649d514..59d7c951f 100644 --- a/include/multiboot2.h +++ b/include/multiboot2.h @@ -23,7 +23,8 @@ #define MULTIBOOT_HEADER 1 /* How many bytes from the start of the file we search for the header. */ -#define MULTIBOOT_SEARCH 8192 +#define MULTIBOOT_SEARCH 32768 +#define MULTIBOOT_HEADER_ALIGN 8 /* The magic field should contain this. */ #define MULTIBOOT2_HEADER_MAGIC 0xe85250d6 @@ -51,42 +52,32 @@ /* This flag indicates the use of the address fields in the header. */ #define MULTIBOOT_AOUT_KLUDGE 0x00010000 -/* Flags to be set in the 'flags' member of the multiboot info structure. */ +#define MULTIBOOT_TAG_ALIGN 8 +#define MULTIBOOT_TAG_TYPE_END 0 +#define MULTIBOOT_TAG_TYPE_CMDLINE 1 +#define MULTIBOOT_TAG_TYPE_BOOT_LOADER_NAME 2 +#define MULTIBOOT_TAG_TYPE_MODULE 3 +#define MULTIBOOT_TAG_TYPE_BASIC_MEMINFO 4 +#define MULTIBOOT_TAG_TYPE_BOOTDEV 5 +#define MULTIBOOT_TAG_TYPE_MMAP 6 +#define MULTIBOOT_TAG_TYPE_VBE 7 +#define MULTIBOOT_TAG_TYPE_FRAMEBUFFER 8 +#define MULTIBOOT_TAG_TYPE_ELF_SECTIONS 9 +#define MULTIBOOT_TAG_TYPE_APM 10 -/* is there basic lower/upper memory information? */ -#define MULTIBOOT_INFO_MEMORY 0x00000001 -/* is there a boot device set? */ -#define MULTIBOOT_INFO_BOOTDEV 0x00000002 -/* is the command-line defined? */ -#define MULTIBOOT_INFO_CMDLINE 0x00000004 -/* are there modules to do something with? */ -#define MULTIBOOT_INFO_MODS 0x00000008 +#define MULTIBOOT_HEADER_TAG_END 0 +#define MULTIBOOT_HEADER_TAG_INFORMATION_REQUEST 1 +#define MULTIBOOT_HEADER_TAG_ADDRESS 2 +#define MULTIBOOT_HEADER_TAG_ENTRY_ADDRESS 3 +#define MULTIBOOT_HEADER_TAG_CONSOLE_FLAGS 4 +#define MULTIBOOT_HEADER_TAG_FRAMEBUFFER 5 +#define MULTIBOOT_HEADER_TAG_MODULE_ALIGN 6 -/* These next two are mutually exclusive */ +#define GRUB_MULTIBOOT_ARCHITECTURE_I386 0 +#define MULTIBOOT_HEADER_TAG_OPTIONAL 1 -/* is there a symbol table loaded? */ -#define MULTIBOOT_INFO_AOUT_SYMS 0x00000010 -/* is there an ELF section header table? */ -#define MULTIBOOT_INFO_ELF_SHDR 0X00000020 - -/* is there a full memory map? */ -#define MULTIBOOT_INFO_MEM_MAP 0x00000040 - -/* Is there drive info? */ -#define MULTIBOOT_INFO_DRIVE_INFO 0x00000080 - -/* Is there a config table? */ -#define MULTIBOOT_INFO_CONFIG_TABLE 0x00000100 - -/* Is there a boot loader name? */ -#define MULTIBOOT_INFO_BOOT_LOADER_NAME 0x00000200 - -/* Is there a APM table? */ -#define MULTIBOOT_INFO_APM_TABLE 0x00000400 - -/* Is there video information? */ -#define MULTIBOOT_INFO_VBE_INFO 0x00000800 -#define MULTIBOOT_INFO_FRAMEBUFFER_INFO 0x00001000 +#define MULTIBOOT_CONSOLE_FLAGS_CONSOLE_REQUIRED 1 +#define MULTIBOOT_CONSOLE_FLAGS_EGA_TEXT_SUPPORTED 2 #ifndef ASM_FILE @@ -100,96 +91,175 @@ struct multiboot_header /* Must be MULTIBOOT_MAGIC - see above. */ multiboot_uint32_t magic; - /* Feature flags. */ - multiboot_uint32_t flags; + /* ISA */ + multiboot_uint32_t architecture; + + /* Total header length. */ + multiboot_uint32_t header_length; /* The above fields plus this one must equal 0 mod 2^32. */ multiboot_uint32_t checksum; +}; - /* These are only valid if MULTIBOOT_AOUT_KLUDGE is set. */ +struct multiboot_header_tag +{ + multiboot_uint16_t type; + multiboot_uint16_t flags; + multiboot_uint32_t size; +}; + +struct multiboot_header_tag_information_request +{ + multiboot_uint16_t type; + multiboot_uint16_t flags; + multiboot_uint32_t size; + multiboot_uint32_t requests[0]; +}; + +struct multiboot_header_tag_address +{ + multiboot_uint16_t type; + multiboot_uint16_t flags; + multiboot_uint32_t size; multiboot_uint32_t header_addr; multiboot_uint32_t load_addr; multiboot_uint32_t load_end_addr; multiboot_uint32_t bss_end_addr; - multiboot_uint32_t entry_addr; +}; - /* These are only valid if MULTIBOOT_VIDEO_MODE is set. */ - multiboot_uint32_t mode_type; +struct multiboot_header_tag_entry_address +{ + multiboot_uint16_t type; + multiboot_uint16_t flags; + multiboot_uint32_t size; + multiboot_uint32_t entry_addr; +}; + +struct multiboot_header_tag_console_flags +{ + multiboot_uint16_t type; + multiboot_uint16_t flags; + multiboot_uint32_t size; + multiboot_uint32_t console_flags; +}; + +struct multiboot_header_tag_framebuffer +{ + multiboot_uint16_t type; + multiboot_uint16_t flags; + multiboot_uint32_t size; multiboot_uint32_t width; multiboot_uint32_t height; multiboot_uint32_t depth; }; -/* The symbol table for a.out. */ -struct multiboot_aout_symbol_table +struct multiboot_header_tag_module_align { - multiboot_uint32_t tabsize; - multiboot_uint32_t strsize; - multiboot_uint32_t addr; - multiboot_uint32_t reserved; -}; -typedef struct multiboot_aout_symbol_table multiboot_aout_symbol_table_t; - -/* The section header table for ELF. */ -struct multiboot_elf_section_header_table -{ - multiboot_uint32_t num; + multiboot_uint16_t type; + multiboot_uint16_t flags; multiboot_uint32_t size; - multiboot_uint32_t addr; - multiboot_uint32_t shndx; + multiboot_uint32_t width; + multiboot_uint32_t height; + multiboot_uint32_t depth; }; -typedef struct multiboot_elf_section_header_table multiboot_elf_section_header_table_t; -struct multiboot_info +struct multiboot_color { - /* Multiboot info version number */ - multiboot_uint32_t flags; + multiboot_uint8_t red; + multiboot_uint8_t green; + multiboot_uint8_t blue; +}; - /* Available memory from BIOS */ +struct multiboot_mmap_entry +{ + multiboot_uint64_t addr; + multiboot_uint64_t len; +#define MULTIBOOT_MEMORY_AVAILABLE 1 +#define MULTIBOOT_MEMORY_RESERVED 2 +#define MULTIBOOT_MEMORY_ACPI_RECLAIMABLE 3 +#define MULTIBOOT_MEMORY_NVS 4 + multiboot_uint32_t type; + multiboot_uint32_t zero; +} __attribute__((packed)); +typedef struct multiboot_mmap_entry multiboot_memory_map_t; + +struct multiboot_tag +{ + multiboot_uint32_t type; + multiboot_uint32_t size; +}; + +struct multiboot_tag_string +{ + multiboot_uint32_t type; + multiboot_uint32_t size; + char string[0]; +}; + +struct multiboot_tag_module +{ + multiboot_uint32_t type; + multiboot_uint32_t size; + multiboot_uint32_t mod_start; + multiboot_uint32_t mod_end; + char cmdline[0]; +}; + +struct multiboot_tag_basic_meminfo +{ + multiboot_uint32_t type; + multiboot_uint32_t size; multiboot_uint32_t mem_lower; multiboot_uint32_t mem_upper; +}; - /* "root" partition */ - multiboot_uint32_t boot_device; +struct multiboot_tag_bootdev +{ + multiboot_uint32_t type; + multiboot_uint32_t size; + multiboot_uint32_t biosdev; + multiboot_uint32_t slice; + multiboot_uint32_t part; +}; - /* Kernel command line */ - multiboot_uint32_t cmdline; +struct multiboot_tag_mmap +{ + multiboot_uint32_t type; + multiboot_uint32_t size; + multiboot_uint32_t entry_size; + multiboot_uint32_t entry_version; + struct multiboot_mmap_entry entries[0]; +}; - /* Boot-Module list */ - multiboot_uint32_t mods_count; - multiboot_uint32_t mods_addr; +struct multiboot_vbe_info_block +{ + multiboot_uint8_t external_specification[512]; +}; - union - { - multiboot_aout_symbol_table_t aout_sym; - multiboot_elf_section_header_table_t elf_sec; - } u; +struct multiboot_vbe_mode_info_block +{ + multiboot_uint8_t external_specification[256]; +}; - /* Memory Mapping buffer */ - multiboot_uint32_t mmap_length; - multiboot_uint32_t mmap_addr; +struct multiboot_tag_vbe +{ + multiboot_uint32_t type; + multiboot_uint32_t size; - /* Drive Info buffer */ - multiboot_uint32_t drives_length; - multiboot_uint32_t drives_addr; - - /* ROM configuration table */ - multiboot_uint32_t config_table; - - /* Boot Loader Name */ - multiboot_uint32_t boot_loader_name; - - /* APM table */ - multiboot_uint32_t apm_table; - - /* Video */ - multiboot_uint32_t vbe_control_info; - multiboot_uint32_t vbe_mode_info; multiboot_uint16_t vbe_mode; multiboot_uint16_t vbe_interface_seg; multiboot_uint16_t vbe_interface_off; multiboot_uint16_t vbe_interface_len; + struct multiboot_vbe_info_block vbe_control_info; + struct multiboot_vbe_mode_info_block vbe_mode_info; +}; + +struct multiboot_tag_framebuffer_common +{ + multiboot_uint32_t type; + multiboot_uint32_t size; + multiboot_uint64_t framebuffer_addr; multiboot_uint32_t framebuffer_pitch; multiboot_uint32_t framebuffer_width; @@ -199,12 +269,19 @@ struct multiboot_info #define MULTIBOOT_FRAMEBUFFER_TYPE_RGB 1 #define MULTIBOOT_FRAMEBUFFER_TYPE_EGA_TEXT 2 multiboot_uint8_t framebuffer_type; + multiboot_uint16_t reserved; +}; + +struct multiboot_tag_framebuffer +{ + struct multiboot_tag_framebuffer_common common; + union { struct { - multiboot_uint32_t framebuffer_palette_addr; multiboot_uint16_t framebuffer_palette_num_colors; + struct multiboot_color framebuffer_palette[0]; }; struct { @@ -217,41 +294,31 @@ struct multiboot_info }; }; }; -typedef struct multiboot_info multiboot_info_t; -struct multiboot_color +struct multiboot_tag_elf_sections { - multiboot_uint8_t red; - multiboot_uint8_t green; - multiboot_uint8_t blue; -}; - -struct multiboot_mmap_entry -{ - multiboot_uint32_t size; - multiboot_uint64_t addr; - multiboot_uint64_t len; -#define MULTIBOOT_MEMORY_AVAILABLE 1 -#define MULTIBOOT_MEMORY_RESERVED 2 -#define MULTIBOOT_MEMORY_ACPI_RECLAIMABLE 3 -#define MULTIBOOT_MEMORY_NVS 4 multiboot_uint32_t type; -} __attribute__((packed)); -typedef struct multiboot_mmap_entry multiboot_memory_map_t; - -struct multiboot_mod_list -{ - /* the memory used goes from bytes 'mod_start' to 'mod_end-1' inclusive */ - multiboot_uint32_t mod_start; - multiboot_uint32_t mod_end; - - /* Module command line */ - multiboot_uint32_t cmdline; - - /* padding to take it to 16 bytes (must be zero) */ - multiboot_uint32_t pad; + multiboot_uint32_t size; + multiboot_uint32_t num; + multiboot_uint32_t entsize; + multiboot_uint32_t shndx; + char sections[0]; +}; + +struct multiboot_tag_apm +{ + multiboot_uint32_t type; + multiboot_uint32_t size; + multiboot_uint16_t version; + multiboot_uint16_t cseg; + multiboot_uint32_t offset; + multiboot_uint16_t cseg_16; + multiboot_uint16_t dseg; + multiboot_uint16_t flags; + multiboot_uint16_t cseg_len; + multiboot_uint16_t cseg_16_len; + multiboot_uint16_t dseg_len; }; -typedef struct multiboot_mod_list multiboot_module_t; #endif /* ! ASM_FILE */ diff --git a/loader/i386/multiboot.c b/loader/i386/multiboot.c index fc9588269..99d1cf906 100644 --- a/loader/i386/multiboot.c +++ b/loader/i386/multiboot.c @@ -27,10 +27,8 @@ * - APM table */ -/* The bits in the required part of flags field we don't support. */ -#define UNSUPPORTED_FLAGS 0x0000fff8 - #include +#include #include #include #include @@ -45,18 +43,78 @@ #include #include #include +#include +#include #ifdef GRUB_MACHINE_EFI #include #endif -extern grub_dl_t my_mod; -static grub_size_t code_size, alloc_mbi; +#if defined (GRUB_MACHINE_PCBIOS) || defined (GRUB_MACHINE_COREBOOT) || defined (GRUB_MACHINE_QEMU) +#define DEFAULT_VIDEO_MODE "text" +#else +#define DEFAULT_VIDEO_MODE "auto" +#endif + +grub_size_t grub_multiboot_alloc_mbi; char *grub_multiboot_payload_orig; grub_addr_t grub_multiboot_payload_dest; grub_size_t grub_multiboot_pure_size; grub_uint32_t grub_multiboot_payload_eip; +static int accepts_video; +static int accepts_ega_text; +static int console_required; +static grub_dl_t my_mod; + + +/* Return the length of the Multiboot mmap that will be needed to allocate + our platform's map. */ +grub_uint32_t +grub_get_multiboot_mmap_count (void) +{ + grub_size_t count = 0; + + auto int NESTED_FUNC_ATTR hook (grub_uint64_t, grub_uint64_t, grub_uint32_t); + int NESTED_FUNC_ATTR hook (grub_uint64_t addr __attribute__ ((unused)), + grub_uint64_t size __attribute__ ((unused)), + grub_uint32_t type __attribute__ ((unused))) + { + count++; + return 0; + } + + grub_mmap_iterate (hook); + + return count; +} + +grub_err_t +grub_multiboot_set_video_mode (void) +{ + grub_err_t err; + const char *modevar; + + if (accepts_video || !GRUB_MACHINE_HAS_VGA_TEXT) + { + modevar = grub_env_get ("gfxpayload"); + if (! modevar || *modevar == 0) + err = grub_video_set_mode (DEFAULT_VIDEO_MODE, 0, 0); + else + { + char *tmp; + tmp = grub_xasprintf ("%s;" DEFAULT_VIDEO_MODE, modevar); + if (! tmp) + return grub_errno; + err = grub_video_set_mode (tmp, 0, 0); + grub_free (tmp); + } + } + else + err = grub_video_set_mode ("text", 0, 0); + + return err; +} static grub_err_t grub_multiboot_boot (void) @@ -75,14 +133,14 @@ grub_multiboot_boot (void) }; mbi_size = grub_multiboot_get_mbi_size (); - if (alloc_mbi < mbi_size) + if (grub_multiboot_alloc_mbi < mbi_size) { grub_multiboot_payload_orig = grub_relocator32_realloc (grub_multiboot_payload_orig, grub_multiboot_pure_size + mbi_size); if (!grub_multiboot_payload_orig) return grub_errno; - alloc_mbi = mbi_size; + grub_multiboot_alloc_mbi = mbi_size; } state.ebx = grub_multiboot_payload_dest + grub_multiboot_pure_size; @@ -112,7 +170,7 @@ grub_multiboot_unload (void) grub_relocator32_free (grub_multiboot_payload_orig); - alloc_mbi = 0; + grub_multiboot_alloc_mbi = 0; grub_multiboot_payload_orig = NULL; grub_dl_unref (my_mod); @@ -129,7 +187,7 @@ grub_multiboot_unload (void) #undef MULTIBOOT_LOAD_ELF32 /* Load ELF32 or ELF64. */ -static grub_err_t +grub_err_t grub_multiboot_load_elf (grub_file_t file, void *buffer) { if (grub_multiboot_is_elf32 (buffer)) @@ -140,137 +198,77 @@ grub_multiboot_load_elf (grub_file_t file, void *buffer) return grub_error (GRUB_ERR_UNKNOWN_OS, "unknown ELF class"); } -void -grub_multiboot (int argc, char *argv[]) +grub_err_t +grub_multiboot_set_console (int console_type, int accepted_consoles, + int width, int height, int depth, + int console_req) +{ + console_required = console_req; + if (!(accepted_consoles + & (GRUB_MULTIBOOT_CONSOLE_FRAMEBUFFER + | (GRUB_MACHINE_HAS_VGA_TEXT ? GRUB_MULTIBOOT_CONSOLE_EGA_TEXT : 0)))) + { + if (console_required) + return grub_error (GRUB_ERR_BAD_OS, + "OS requires a console but none is available"); + grub_printf ("WARNING: no console will be available to OS"); + accepts_video = 0; + accepts_ega_text = 0; + return GRUB_ERR_NONE; + } + + if (console_type == GRUB_MULTIBOOT_CONSOLE_FRAMEBUFFER) + { + char *buf; + if (depth && width && height) + buf = grub_xasprintf ("%dx%dx%d,%dx%d,auto", width, + height, depth, width, height); + else if (width && height) + buf = grub_xasprintf ("%dx%d,auto", width, height); + else + buf = grub_strdup ("auto"); + + if (!buf) + return grub_errno; + grub_env_set ("gfxpayload", buf); + grub_free (buf); + } + else + grub_env_set ("gfxpayload", "text"); + + accepts_video = !!(accepted_consoles & GRUB_MULTIBOOT_CONSOLE_FRAMEBUFFER); + accepts_ega_text = !!(accepted_consoles & GRUB_MULTIBOOT_CONSOLE_EGA_TEXT); + return GRUB_ERR_NONE; +} + +static grub_err_t +grub_cmd_multiboot (grub_command_t cmd __attribute__ ((unused)), + int argc, char *argv[]) { grub_file_t file = 0; - char buffer[MULTIBOOT_SEARCH]; - struct multiboot_header *header; - grub_ssize_t len; + grub_err_t err; grub_loader_unset (); if (argc == 0) - { - grub_error (GRUB_ERR_BAD_ARGUMENT, "no kernel specified"); - goto fail; - } + return grub_error (GRUB_ERR_BAD_ARGUMENT, "no kernel specified"); file = grub_gzfile_open (argv[0], 1); if (! file) - { - grub_error (GRUB_ERR_BAD_ARGUMENT, "couldn't open file"); - goto fail; - } + return grub_error (GRUB_ERR_BAD_ARGUMENT, "couldn't open file"); - len = grub_file_read (file, buffer, MULTIBOOT_SEARCH); - if (len < 32) - { - grub_error (GRUB_ERR_BAD_OS, "file too small"); - goto fail; - } - - /* 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)) - break; - } - - if (header == 0) - { - grub_error (GRUB_ERR_BAD_ARGUMENT, "no multiboot header found"); - goto fail; - } - - if (header->flags & UNSUPPORTED_FLAGS) - { - grub_error (GRUB_ERR_UNKNOWN_OS, - "unsupported flag: 0x%x", header->flags); - goto fail; - } - - grub_relocator32_free (grub_multiboot_payload_orig); - grub_multiboot_payload_orig = NULL; + grub_dl_ref (my_mod); /* Skip filename. */ grub_multiboot_init_mbi (argc - 1, argv + 1); - if (header->flags & MULTIBOOT_AOUT_KLUDGE) - { - int offset = ((char *) header - buffer - - (header->header_addr - header->load_addr)); - int load_size = ((header->load_end_addr == 0) ? file->size - offset : - header->load_end_addr - header->load_addr); + grub_relocator32_free (grub_multiboot_payload_orig); + grub_multiboot_payload_orig = NULL; - if (header->bss_end_addr) - code_size = (header->bss_end_addr - header->load_addr); - else - code_size = load_size; - grub_multiboot_payload_dest = header->load_addr; - - grub_multiboot_pure_size += code_size; - - /* Allocate a bit more to avoid relocations in most cases. */ - alloc_mbi = grub_multiboot_get_mbi_size () + 65536; - grub_multiboot_payload_orig - = grub_relocator32_alloc (grub_multiboot_pure_size + alloc_mbi); - - if (! grub_multiboot_payload_orig) - goto fail; - - if ((grub_file_seek (file, offset)) == (grub_off_t) -1) - goto fail; - - grub_file_read (file, (void *) grub_multiboot_payload_orig, load_size); - if (grub_errno) - goto fail; - - if (header->bss_end_addr) - grub_memset ((void *) (grub_multiboot_payload_orig + load_size), 0, - header->bss_end_addr - header->load_addr - load_size); - - grub_multiboot_payload_eip = header->entry_addr; - - } - else if (grub_multiboot_load_elf (file, buffer) != GRUB_ERR_NONE) + err = grub_multiboot_load (file); + if (err) goto fail; - if (header->flags & MULTIBOOT_VIDEO_MODE) - { - switch (header->mode_type) - { - case 1: - grub_env_set ("gfxpayload", "text"); - break; - - case 0: - { - char *buf; - if (header->depth && header->width && header->height) - buf = grub_xasprintf ("%dx%dx%d,%dx%d,auto", header->width, - header->height, header->depth, header->width, - header->height); - else if (header->width && header->height) - buf = grub_xasprintf ("%dx%d,auto", header->width, header->height); - else - buf = grub_strdup ("auto"); - - if (!buf) - goto fail; - grub_env_set ("gfxpayload", buf); - grub_free (buf); - break; - } - } - } - - grub_multiboot_set_accepts_video (!!(header->flags & MULTIBOOT_VIDEO_MODE)); - grub_multiboot_set_bootdev (); grub_loader_set (grub_multiboot_boot, grub_multiboot_unload, 0); @@ -282,12 +280,16 @@ grub_multiboot (int argc, char *argv[]) if (grub_errno != GRUB_ERR_NONE) { grub_relocator32_free (grub_multiboot_payload_orig); + grub_multiboot_free_mbi (); grub_dl_unref (my_mod); } + + return grub_errno; } -void -grub_module (int argc, char *argv[]) +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; @@ -295,40 +297,64 @@ grub_module (int argc, char *argv[]) grub_err_t err; if (argc == 0) - { - grub_error (GRUB_ERR_BAD_ARGUMENT, "no module specified"); - goto fail; - } + return grub_error (GRUB_ERR_BAD_ARGUMENT, "no module specified"); if (!grub_multiboot_payload_orig) - { - grub_error (GRUB_ERR_BAD_ARGUMENT, - "you need to load the multiboot kernel first"); - goto fail; - } + return grub_error (GRUB_ERR_BAD_ARGUMENT, + "you need to load the multiboot kernel first"); file = grub_gzfile_open (argv[0], 1); if (! file) - goto fail; + return grub_errno; size = grub_file_size (file); module = grub_memalign (MULTIBOOT_MOD_ALIGN, size); if (! module) - goto fail; + { + grub_file_close (file); + return grub_errno; + } err = grub_multiboot_add_module ((grub_addr_t) module, size, argc - 1, argv + 1); if (err) - goto fail; + { + grub_file_close (file); + return err; + } if (grub_file_read (file, module, size) != size) { - grub_error (GRUB_ERR_FILE_READ_ERROR, "couldn't read file"); - goto fail; + grub_file_close (file); + return grub_error (GRUB_ERR_FILE_READ_ERROR, "couldn't read file"); } - fail: - if (file) - grub_file_close (file); + grub_file_close (file); + return GRUB_ERR_NONE;; } +static grub_command_t cmd_multiboot, cmd_module; + +GRUB_MOD_INIT(multiboot) +{ + cmd_multiboot = +#ifdef GRUB_USE_MULTIBOOT2 + grub_register_command ("multiboot2", grub_cmd_multiboot, + 0, N_("Load a multiboot 2 kernel.")); +#else + grub_register_command ("multiboot", grub_cmd_multiboot, + 0, N_("Load a multiboot kernel.")); +#endif + + cmd_module = + grub_register_command ("module", grub_cmd_module, + 0, N_("Load a multiboot module.")); + + my_mod = mod; +} + +GRUB_MOD_FINI(multiboot) +{ + grub_unregister_command (cmd_multiboot); + grub_unregister_command (cmd_module); +} diff --git a/loader/i386/multiboot_elfxx.c b/loader/i386/multiboot_elfxx.c index 2e35183a4..05fb2c1c1 100644 --- a/loader/i386/multiboot_elfxx.c +++ b/loader/i386/multiboot_elfxx.c @@ -53,6 +53,7 @@ CONCAT(grub_multiboot_load_elf, XX) (grub_file_t file, void *buffer) char *phdr_base; int lowest_segment = -1, highest_segment = -1; int i; + grub_size_t code_size; if (ehdr->e_ident[EI_CLASS] != ELFCLASSXX) return grub_error (GRUB_ERR_UNKNOWN_OS, "invalid ELF class"); @@ -102,9 +103,9 @@ CONCAT(grub_multiboot_load_elf, XX) (grub_file_t file, void *buffer) grub_multiboot_pure_size += code_size; - alloc_mbi = grub_multiboot_get_mbi_size (); + grub_multiboot_alloc_mbi = grub_multiboot_get_mbi_size () + 65536; grub_multiboot_payload_orig - = grub_relocator32_alloc (grub_multiboot_pure_size + alloc_mbi + 65536); + = grub_relocator32_alloc (grub_multiboot_pure_size + grub_multiboot_alloc_mbi); if (!grub_multiboot_payload_orig) return grub_errno; diff --git a/loader/i386/multiboot_mbi.c b/loader/i386/multiboot_mbi.c index 928677512..2a7c70f96 100644 --- a/loader/i386/multiboot_mbi.c +++ b/loader/i386/multiboot_mbi.c @@ -23,6 +23,7 @@ #endif #include #include +#include #include #include #include @@ -30,15 +31,10 @@ #include #include #include +#include -#if defined (GRUB_MACHINE_PCBIOS) || defined (GRUB_MACHINE_COREBOOT) || defined (GRUB_MACHINE_QEMU) -#include -#define DEFAULT_VIDEO_MODE "text" -#define HAS_VGA_TEXT 1 -#else -#define DEFAULT_VIDEO_MODE "auto" -#define HAS_VGA_TEXT 0 -#endif +/* The bits in the required part of flags field we don't support. */ +#define UNSUPPORTED_FLAGS 0x0000fff8 struct module { @@ -56,33 +52,131 @@ static unsigned modcnt; static char *cmdline = NULL; static grub_uint32_t bootdev; static int bootdev_set; -static int accepts_video; -void -grub_multiboot_set_accepts_video (int val) +grub_err_t +grub_multiboot_load (grub_file_t file) { - accepts_video = val; -} + char *buffer; + grub_ssize_t len; + struct multiboot_header *header; + grub_err_t err; -/* Return the length of the Multiboot mmap that will be needed to allocate - our platform's map. */ -static grub_uint32_t -grub_get_multiboot_mmap_len (void) -{ - grub_size_t count = 0; + buffer = grub_malloc (MULTIBOOT_SEARCH); + if (!buffer) + return grub_errno; - auto int NESTED_FUNC_ATTR hook (grub_uint64_t, grub_uint64_t, grub_uint32_t); - int NESTED_FUNC_ATTR hook (grub_uint64_t addr __attribute__ ((unused)), - grub_uint64_t size __attribute__ ((unused)), - grub_uint32_t type __attribute__ ((unused))) + len = grub_file_read (file, buffer, MULTIBOOT_SEARCH); + if (len < 32) { - count++; - return 0; + grub_free (buffer); + return grub_error (GRUB_ERR_BAD_OS, "file too small"); } - grub_mmap_iterate (hook); + /* 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 + MULTIBOOT_HEADER_ALIGN)) + { + if (header->magic == MULTIBOOT_HEADER_MAGIC + && !(header->magic + header->flags + header->checksum)) + break; + } - return count * sizeof (struct multiboot_mmap_entry); + 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); + } + + if (header->flags & MULTIBOOT_AOUT_KLUDGE) + { + int offset = ((char *) header - buffer - + (header->header_addr - header->load_addr)); + int load_size = ((header->load_end_addr == 0) ? file->size - offset : + header->load_end_addr - header->load_addr); + grub_size_t code_size; + + if (header->bss_end_addr) + code_size = (header->bss_end_addr - header->load_addr); + else + code_size = load_size; + grub_multiboot_payload_dest = header->load_addr; + + grub_multiboot_pure_size += code_size; + + /* Allocate a bit more to avoid relocations in most cases. */ + grub_multiboot_alloc_mbi = grub_multiboot_get_mbi_size () + 65536; + grub_multiboot_payload_orig + = grub_relocator32_alloc (grub_multiboot_pure_size + grub_multiboot_alloc_mbi); + + if (! grub_multiboot_payload_orig) + { + grub_free (buffer); + return grub_errno; + } + + if ((grub_file_seek (file, offset)) == (grub_off_t) -1) + { + grub_free (buffer); + return grub_errno; + } + + grub_file_read (file, (void *) grub_multiboot_payload_orig, load_size); + if (grub_errno) + { + grub_free (buffer); + return grub_errno; + } + + if (header->bss_end_addr) + grub_memset ((void *) (grub_multiboot_payload_orig + load_size), 0, + header->bss_end_addr - header->load_addr - load_size); + + grub_multiboot_payload_eip = header->entry_addr; + + } + else + { + err = grub_multiboot_load_elf (file, buffer); + 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; + } + } + else + err = grub_multiboot_set_console (GRUB_MULTIBOOT_CONSOLE_EGA_TEXT, + GRUB_MULTIBOOT_CONSOLE_EGA_TEXT, + 0, 0, 0, 0); + return err; } grub_size_t @@ -90,7 +184,8 @@ grub_multiboot_get_mbi_size (void) { return sizeof (struct multiboot_info) + ALIGN_UP (cmdline_size, 4) + modcnt * sizeof (struct multiboot_mod_list) + total_modcmd - + ALIGN_UP (sizeof(PACKAGE_STRING), 4) + grub_get_multiboot_mmap_len () + + ALIGN_UP (sizeof(PACKAGE_STRING), 4) + + grub_get_multiboot_mmap_count () * sizeof (struct multiboot_mmap_entry) + 256 * sizeof (struct multiboot_color); } @@ -136,33 +231,6 @@ grub_fill_multiboot_mmap (struct multiboot_mmap_entry *first_entry) grub_mmap_iterate (hook); } -static grub_err_t -set_video_mode (void) -{ - grub_err_t err; - const char *modevar; - - if (accepts_video || !HAS_VGA_TEXT) - { - modevar = grub_env_get ("gfxpayload"); - if (! modevar || *modevar == 0) - err = grub_video_set_mode (DEFAULT_VIDEO_MODE, 0, 0); - else - { - char *tmp; - tmp = grub_xasprintf ("%s;" DEFAULT_VIDEO_MODE, modevar); - if (! tmp) - return grub_errno; - err = grub_video_set_mode (tmp, 0, 0); - grub_free (tmp); - } - } - else - err = grub_video_set_mode ("text", 0, 0); - - return err; -} - static grub_err_t retrieve_video_parameters (struct multiboot_info *mbi, grub_uint8_t *ptrorig, grub_uint32_t ptrdest) @@ -173,7 +241,7 @@ retrieve_video_parameters (struct multiboot_info *mbi, grub_video_driver_id_t driv_id; struct grub_video_palette_data palette[256]; - err = set_video_mode (); + err = grub_multiboot_set_video_mode (); if (err) { grub_print_error (); @@ -293,7 +361,8 @@ grub_multiboot_make_mbi (void *orig, grub_uint32_t dest, grub_off_t buf_off, mbi->mods_count = 0; } - mmap_size = grub_get_multiboot_mmap_len (); + mmap_size = grub_get_multiboot_mmap_count () + * sizeof (struct multiboot_mmap_entry); grub_fill_multiboot_mmap ((struct multiboot_mmap_entry *) ptrorig); mbi->mmap_length = mmap_size; mbi->mmap_addr = ptrdest; @@ -444,6 +513,9 @@ grub_multiboot_set_bootdev (void) biosdev = 0xffffffff; #endif + if (biosdev == 0xffffffff) + return; + dev = grub_device_open (0); if (dev && dev->disk && dev->disk->partition) { diff --git a/loader/i386/multiboot_mbi2.c b/loader/i386/multiboot_mbi2.c new file mode 100644 index 000000000..436cd0901 --- /dev/null +++ b/loader/i386/multiboot_mbi2.c @@ -0,0 +1,694 @@ +/* + * GRUB -- GRand Unified Bootloader + * Copyright (C) 1999,2000,2001,2002,2003,2004,2005,2007,2008,2009 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 +#ifdef GRUB_MACHINE_PCBIOS +#include +#endif +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#if defined (GRUB_MACHINE_PCBIOS) || defined (GRUB_MACHINE_COREBOOT) || defined (GRUB_MACHINE_QEMU) +#include +#define DEFAULT_VIDEO_MODE "text" +#define HAS_VGA_TEXT 1 +#define HAS_VBE 1 +#else +#define DEFAULT_VIDEO_MODE "auto" +#define HAS_VGA_TEXT 0 +#define HAS_VBE 0 +#endif + +struct module +{ + struct module *next; + grub_addr_t start; + grub_size_t size; + char *cmdline; + int cmdline_size; +}; + +struct module *modules, *modules_last; +static grub_size_t cmdline_size; +static grub_size_t total_modcmd; +static unsigned modcnt; +static char *cmdline = NULL; +static int bootdev_set; +static grub_uint32_t biosdev, slice, part; + +grub_err_t +grub_multiboot_load (grub_file_t file) +{ + char *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, "file too small"); + } + + /* 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 + MULTIBOOT_HEADER_ALIGN)) + { + if (header->magic == MULTIBOOT_HEADER_MAGIC + && !(header->magic + header->architecture + + header->header_length + header->checksum)) + break; + } + + if (header == 0) + { + grub_free (buffer); + return grub_error (GRUB_ERR_BAD_ARGUMENT, "no multiboot header found"); + } + + for (tag = (struct multiboot_header_tag *) (header + 1); + tag->type != MULTIBOOT_TAG_TYPE_END; + tag = (struct multiboot_header_tag *) ((char *) tag + tag->size)) + 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: + break; + + case MULTIBOOT_TAG_TYPE_VBE: + case MULTIBOOT_TAG_TYPE_ELF_SECTIONS: + case MULTIBOOT_TAG_TYPE_APM: + 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; + + 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) + { + int offset = ((char *) header - buffer - + (addr_tag->header_addr - addr_tag->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; + + if (addr_tag->bss_end_addr) + code_size = (addr_tag->bss_end_addr - addr_tag->load_addr); + else + code_size = load_size; + grub_multiboot_payload_dest = addr_tag->load_addr; + + grub_multiboot_pure_size += code_size; + + /* Allocate a bit more to avoid relocations in most cases. */ + grub_multiboot_alloc_mbi = grub_multiboot_get_mbi_size () + 65536; + grub_multiboot_payload_orig + = grub_relocator32_alloc (grub_multiboot_pure_size + grub_multiboot_alloc_mbi); + + if (! grub_multiboot_payload_orig) + { + grub_free (buffer); + return grub_errno; + } + + if ((grub_file_seek (file, offset)) == (grub_off_t) -1) + { + grub_free (buffer); + return grub_errno; + } + + grub_file_read (file, (void *) grub_multiboot_payload_orig, load_size); + if (grub_errno) + { + grub_free (buffer); + return grub_errno; + } + + if (addr_tag->bss_end_addr) + grub_memset ((void *) (grub_multiboot_payload_orig + load_size), 0, + addr_tag->bss_end_addr - addr_tag->load_addr - load_size); + } + else + { + err = grub_multiboot_load_elf (file, 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_size_t +grub_multiboot_get_mbi_size (void) +{ + return 2 * sizeof (grub_uint32_t) + sizeof (struct multiboot_tag) + + (sizeof (struct multiboot_tag_string) + + ALIGN_UP (cmdline_size, MULTIBOOT_TAG_ALIGN)) + + (sizeof (struct multiboot_tag_string) + + ALIGN_UP (sizeof (PACKAGE_STRING), MULTIBOOT_TAG_ALIGN)) + + (modcnt * sizeof (struct multiboot_tag_module) + total_modcmd) + + sizeof (struct multiboot_tag_basic_meminfo) + + ALIGN_UP (sizeof (struct multiboot_tag_bootdev), MULTIBOOT_TAG_ALIGN) + + (sizeof (struct multiboot_tag_mmap) + grub_get_multiboot_mmap_count () + * sizeof (struct multiboot_mmap_entry)) + + sizeof (struct multiboot_tag_vbe) + MULTIBOOT_TAG_ALIGN - 1; +} + +/* Fill previously allocated Multiboot mmap. */ +static void +grub_fill_multiboot_mmap (struct multiboot_tag_mmap *tag) +{ + struct multiboot_mmap_entry *mmap_entry = tag->entries; + + auto int NESTED_FUNC_ATTR hook (grub_uint64_t, grub_uint64_t, grub_uint32_t); + int NESTED_FUNC_ATTR hook (grub_uint64_t addr, grub_uint64_t size, grub_uint32_t type) + { + mmap_entry->addr = addr; + mmap_entry->len = size; + switch (type) + { + case GRUB_MACHINE_MEMORY_AVAILABLE: + mmap_entry->type = MULTIBOOT_MEMORY_AVAILABLE; + break; + +#ifdef GRUB_MACHINE_MEMORY_ACPI_RECLAIMABLE + case GRUB_MACHINE_MEMORY_ACPI_RECLAIMABLE: + mmap_entry->type = MULTIBOOT_MEMORY_ACPI_RECLAIMABLE; + break; +#endif + +#ifdef GRUB_MACHINE_MEMORY_NVS + case GRUB_MACHINE_MEMORY_NVS: + mmap_entry->type = MULTIBOOT_MEMORY_NVS; + break; +#endif + + default: + mmap_entry->type = MULTIBOOT_MEMORY_RESERVED; + break; + } + mmap_entry++; + + return 0; + } + + tag->type = MULTIBOOT_TAG_TYPE_MMAP; + tag->size = sizeof (struct multiboot_tag_mmap) + + sizeof (struct multiboot_mmap_entry) * grub_get_multiboot_mmap_count (); + tag->entry_size = sizeof (struct multiboot_mmap_entry); + tag->entry_version = 0; + + grub_mmap_iterate (hook); +} + +static grub_err_t +retrieve_video_parameters (grub_uint8_t **ptrorig) +{ + grub_err_t err; + struct grub_video_mode_info mode_info; + void *framebuffer; + grub_video_driver_id_t driv_id; + struct grub_video_palette_data palette[256]; + struct multiboot_tag_framebuffer *tag + = (struct multiboot_tag_framebuffer *) *ptrorig; + + err = grub_multiboot_set_video_mode (); + if (err) + { + grub_print_error (); + grub_errno = GRUB_ERR_NONE; + } + + grub_video_get_palette (0, ARRAY_SIZE (palette), palette); + + driv_id = grub_video_get_driver_id (); +#if HAS_VGA_TEXT + if (driv_id == GRUB_VIDEO_DRIVER_NONE) + { + struct grub_vbe_mode_info_block vbe_mode_info; + grub_vbe_status_t status; + grub_uint32_t vbe_mode; + void *scratch = (void *) GRUB_MEMORY_MACHINE_SCRATCH_ADDR; + + status = grub_vbe_bios_get_mode (scratch); + vbe_mode = *(grub_uint32_t *) scratch; + if (status != GRUB_VBE_STATUS_OK) + return GRUB_ERR_NONE; + + /* get_mode_info isn't available for mode 3. */ + if (vbe_mode == 3) + { + grub_memset (&vbe_mode_info, 0, + sizeof (struct grub_vbe_mode_info_block)); + vbe_mode_info.memory_model = GRUB_VBE_MEMORY_MODEL_TEXT; + vbe_mode_info.x_resolution = 80; + vbe_mode_info.y_resolution = 25; + } + else + { + status = grub_vbe_bios_get_mode_info (vbe_mode, scratch); + if (status != GRUB_VBE_STATUS_OK) + return GRUB_ERR_NONE; + grub_memcpy (&vbe_mode_info, scratch, + sizeof (struct grub_vbe_mode_info_block)); + } + + if (vbe_mode_info.memory_model == GRUB_VBE_MEMORY_MODEL_TEXT) + { + tag = (struct multiboot_tag_framebuffer *) *ptrorig; + tag->common.type = MULTIBOOT_TAG_TYPE_FRAMEBUFFER; + tag->common.size = 0; + + tag->common.framebuffer_addr = 0xb8000; + + tag->common.framebuffer_pitch = 2 * vbe_mode_info.x_resolution; + tag->common.framebuffer_width = vbe_mode_info.x_resolution; + tag->common.framebuffer_height = vbe_mode_info.y_resolution; + + tag->common.framebuffer_bpp = 16; + + tag->common.framebuffer_type = MULTIBOOT_FRAMEBUFFER_TYPE_EGA_TEXT; + tag->common.size = sizeof (tag->common); + tag->common.reserved = 0; + *ptrorig += ALIGN_UP (tag->common.size, MULTIBOOT_TAG_ALIGN); + } + return GRUB_ERR_NONE; + } +#else + if (driv_id == GRUB_VIDEO_DRIVER_NONE) + return GRUB_ERR_NONE; +#endif + + err = grub_video_get_info_and_fini (&mode_info, &framebuffer); + if (err) + return err; + + tag = (struct multiboot_tag_framebuffer *) *ptrorig; + tag->common.type = MULTIBOOT_TAG_TYPE_FRAMEBUFFER; + tag->common.size = 0; + + tag->common.framebuffer_addr = (grub_addr_t) framebuffer; + tag->common.framebuffer_pitch = mode_info.pitch; + + tag->common.framebuffer_width = mode_info.width; + tag->common.framebuffer_height = mode_info.height; + + tag->common.framebuffer_bpp = mode_info.bpp; + + tag->common.reserved = 0; + + if (mode_info.mode_type & GRUB_VIDEO_MODE_TYPE_INDEX_COLOR) + { + unsigned i; + tag->common.framebuffer_type = MULTIBOOT_FRAMEBUFFER_TYPE_INDEXED; + tag->framebuffer_palette_num_colors = mode_info.number_of_colors; + if (tag->framebuffer_palette_num_colors > ARRAY_SIZE (palette)) + tag->framebuffer_palette_num_colors = ARRAY_SIZE (palette); + tag->common.size = sizeof (struct multiboot_tag_framebuffer_common) + + sizeof (multiboot_uint16_t) + tag->framebuffer_palette_num_colors + * sizeof (struct multiboot_color); + for (i = 0; i < tag->framebuffer_palette_num_colors; i++) + { + tag->framebuffer_palette[i].red = palette[i].r; + tag->framebuffer_palette[i].green = palette[i].g; + tag->framebuffer_palette[i].blue = palette[i].b; + } + } + else + { + tag->common.framebuffer_type = MULTIBOOT_FRAMEBUFFER_TYPE_RGB; + tag->common.framebuffer_type = MULTIBOOT_FRAMEBUFFER_TYPE_RGB; + tag->framebuffer_red_field_position = mode_info.green_field_pos; + tag->framebuffer_red_mask_size = mode_info.green_mask_size; + tag->framebuffer_green_field_position = mode_info.green_field_pos; + tag->framebuffer_green_mask_size = mode_info.green_mask_size; + tag->framebuffer_blue_field_position = mode_info.blue_field_pos; + tag->framebuffer_blue_mask_size = mode_info.blue_mask_size; + + tag->common.size = sizeof (struct multiboot_tag_framebuffer_common) + 6; + } + *ptrorig += ALIGN_UP (tag->common.size, MULTIBOOT_TAG_ALIGN); + + return GRUB_ERR_NONE; +} + +grub_err_t +grub_multiboot_make_mbi (void *orig, grub_uint32_t dest, grub_off_t buf_off, + grub_size_t bufsize) +{ + grub_uint8_t *ptrorig; + grub_uint8_t *mbistart = (grub_uint8_t *) orig + buf_off + + (ALIGN_UP (dest + buf_off, MULTIBOOT_TAG_ALIGN) - (dest + buf_off)); + grub_err_t err; + + if (bufsize < grub_multiboot_get_mbi_size ()) + return grub_error (GRUB_ERR_OUT_OF_MEMORY, "mbi buffer is too small"); + + ptrorig = mbistart + 2 * sizeof (grub_uint32_t); + + { + struct multiboot_tag_string *tag = (struct multiboot_tag_string *) ptrorig; + tag->type = MULTIBOOT_TAG_TYPE_CMDLINE; + tag->size = sizeof (struct multiboot_tag_string) + cmdline_size; + grub_memcpy (tag->string, cmdline, cmdline_size); + ptrorig += ALIGN_UP (tag->size, MULTIBOOT_TAG_ALIGN); + } + + { + struct multiboot_tag_string *tag = (struct multiboot_tag_string *) ptrorig; + tag->type = MULTIBOOT_TAG_TYPE_BOOT_LOADER_NAME; + tag->size = sizeof (struct multiboot_tag_string) + sizeof (PACKAGE_STRING); + grub_memcpy (tag->string, PACKAGE_STRING, sizeof (PACKAGE_STRING)); + ptrorig += ALIGN_UP (tag->size, MULTIBOOT_TAG_ALIGN); + } + + { + unsigned i; + struct module *cur; + + for (i = 0, cur = modules; i < modcnt; i++, cur = cur->next) + { + struct multiboot_tag_module *tag + = (struct multiboot_tag_module *) ptrorig; + tag->type = MULTIBOOT_TAG_TYPE_MODULE; + tag->size = sizeof (struct multiboot_tag_module) + cur->cmdline_size; + tag->mod_start = dest + cur->start; + tag->mod_end = tag->mod_start + cur->size; + grub_memcpy (tag->cmdline, cur->cmdline, cur->cmdline_size); + ptrorig += ALIGN_UP (tag->size, MULTIBOOT_TAG_ALIGN); + } + } + + { + struct multiboot_tag_mmap *tag = (struct multiboot_tag_mmap *) ptrorig; + grub_fill_multiboot_mmap (tag); + ptrorig += ALIGN_UP (tag->size, MULTIBOOT_TAG_ALIGN); + } + + { + struct multiboot_tag_basic_meminfo *tag + = (struct multiboot_tag_basic_meminfo *) ptrorig; + tag->type = MULTIBOOT_TAG_TYPE_BASIC_MEMINFO; + tag->size = sizeof (struct multiboot_tag_basic_meminfo); + + /* Convert from bytes to kilobytes. */ + tag->mem_lower = grub_mmap_get_lower () / 1024; + tag->mem_upper = grub_mmap_get_upper () / 1024; + ptrorig += ALIGN_UP (tag->size, MULTIBOOT_TAG_ALIGN); + } + + if (bootdev_set) + { + struct multiboot_tag_bootdev *tag + = (struct multiboot_tag_bootdev *) ptrorig; + tag->type = MULTIBOOT_TAG_TYPE_BOOTDEV; + tag->size = sizeof (struct multiboot_tag_bootdev); + + tag->biosdev = biosdev; + tag->slice = slice; + tag->part = part; + ptrorig += ALIGN_UP (tag->size, MULTIBOOT_TAG_ALIGN); + } + + { + err = retrieve_video_parameters (&ptrorig); + if (err) + { + grub_print_error (); + grub_errno = GRUB_ERR_NONE; + } + } + + { + struct multiboot_tag *tag = (struct multiboot_tag *) ptrorig; + tag->type = MULTIBOOT_TAG_TYPE_END; + tag->size = sizeof (struct multiboot_tag); + ptrorig += ALIGN_UP (tag->size, MULTIBOOT_TAG_ALIGN); + } + + ((grub_uint32_t *) mbistart)[0] = ptrorig - mbistart; + ((grub_uint32_t *) mbistart)[1] = 0; + + return GRUB_ERR_NONE; +} + +void +grub_multiboot_free_mbi (void) +{ + struct module *cur, *next; + + cmdline_size = 0; + total_modcmd = 0; + modcnt = 0; + grub_free (cmdline); + cmdline = NULL; + bootdev_set = 0; + + for (cur = modules; cur; cur = next) + { + next = cur->next; + grub_free (cur->cmdline); + grub_free (cur); + } + modules = NULL; + modules_last = NULL; +} + +grub_err_t +grub_multiboot_init_mbi (int argc, char *argv[]) +{ + grub_ssize_t len = 0; + char *p; + int i; + + grub_multiboot_free_mbi (); + + for (i = 0; i < argc; i++) + len += grub_strlen (argv[i]) + 1; + if (len == 0) + len = 1; + + cmdline = p = grub_malloc (len); + if (! cmdline) + return grub_errno; + cmdline_size = len; + + for (i = 0; i < argc; i++) + { + p = grub_stpcpy (p, argv[i]); + *(p++) = ' '; + } + + /* Remove the space after the last word. */ + if (p != cmdline) + p--; + *p = '\0'; + + return GRUB_ERR_NONE; +} + +grub_err_t +grub_multiboot_add_module (grub_addr_t start, grub_size_t size, + int argc, char *argv[]) +{ + struct module *newmod; + char *p; + grub_ssize_t len = 0; + int i; + + newmod = grub_malloc (sizeof (*newmod)); + if (!newmod) + return grub_errno; + newmod->start = start; + newmod->size = size; + + for (i = 0; i < argc; i++) + len += grub_strlen (argv[i]) + 1; + + if (len == 0) + len = 1; + + newmod->cmdline = p = grub_malloc (len); + if (! newmod->cmdline) + { + grub_free (newmod); + return grub_errno; + } + newmod->cmdline_size = len; + total_modcmd += ALIGN_UP (len, MULTIBOOT_TAG_ALIGN); + + for (i = 0; i < argc; i++) + { + p = grub_stpcpy (p, argv[i]); + *(p++) = ' '; + } + + /* Remove the space after the last word. */ + if (p != newmod->cmdline) + p--; + *p = '\0'; + + if (modules_last) + modules_last->next = newmod; + else + { + modules = newmod; + modules_last->next = NULL; + } + modules_last = newmod; + + modcnt++; + + return GRUB_ERR_NONE; +} + +void +grub_multiboot_set_bootdev (void) +{ + grub_device_t dev; + + slice = ~0; + part = ~0; + +#ifdef GRUB_MACHINE_PCBIOS + biosdev = grub_get_root_biosnumber (); +#else + biosdev = 0xffffffff; +#endif + + if (biosdev == 0xffffffff) + return; + + dev = grub_device_open (0); + if (dev && dev->disk && dev->disk->partition) + { + if (dev->disk->partition->parent) + { + part = dev->disk->partition->number; + slice = dev->disk->partition->parent->number; + } + else + slice = dev->disk->partition->number; + } + if (dev) + grub_device_close (dev); + + bootdev_set = 1; +} diff --git a/loader/multiboot_loader.c b/loader/multiboot_loader.c deleted file mode 100644 index 6d042fa81..000000000 --- a/loader/multiboot_loader.c +++ /dev/null @@ -1,150 +0,0 @@ -/* multiboot_loader.c - boot multiboot kernel image */ -/* - * GRUB -- GRand Unified Bootloader - * Copyright (C) 2007,2008,2009,2010 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 - -grub_dl_t my_mod; - -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 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 - { - 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 */ - - grub_dprintf ("multiboot_loader", - "Launching multiboot 1 grub_multiboot() function\n"); - grub_multiboot (argc, argv); - - 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[]) -{ - - grub_dprintf("multiboot_loader", - "Launching multiboot 1 grub_module() function\n"); - grub_module (argc, argv); - - return grub_errno; -} - -static grub_command_t cmd_multiboot, cmd_module; - -GRUB_MOD_INIT(multiboot) -{ - cmd_multiboot = -#ifdef GRUB_USE_MULTIBOOT2 - grub_register_command ("multiboot2", grub_cmd_multiboot_loader, - 0, N_("Load a multiboot 2 kernel.")); -#else - grub_register_command ("multiboot", grub_cmd_multiboot_loader, - 0, N_("Load a multiboot kernel.")); -#endif - - cmd_module = - grub_register_command ("module", grub_cmd_module_loader, - 0, N_("Load a multiboot module.")); - - my_mod = mod; -} - -GRUB_MOD_FINI(multiboot) -{ - grub_unregister_command (cmd_multiboot); - grub_unregister_command (cmd_module); -}