Robert Millan wrote: > On Mon, Dec 28, 2009 at 01:07:10PM +0100, Vladimir 'φ-coder/phcoder' > Serbinenko wrote: > >> Robert Millan wrote: >> >>> On Tue, Sep 01, 2009 at 05:37:11PM +0200, Vladimir 'phcoder' Serbinenko >>> wrote: >>> >>> >>>> Hello. I'm implementing video part of multiboot specification. >>>> Currently the only defined interface is for providing VBE info. I >>>> propose following way to set fields if video is non VBE: >>>> vbe_control_info=0xffffffff >>>> When vbe_control_info is set to 0xffffffff all VBE-specific fields are >>>> invalid >>>> vbe_mode set to 0xffff >>>> vbe_interface_seg=0xffff >>>> vbe_interface_off=0xffff >>>> vbe_interface_len=0xff >>>> vbe_mode_info points to structure similar to vbe_mode_info but with >>>> all vbe-specific fields set to zero. Remaining (valid) fields are >>>> (full structur is in include/grub/i386/pc/vbe.h) >>>> >>>> >>> This seems like one of these cases in which legacy gets in the way. Why >>> don't we just replace the legacy structure with something that doesn't need >>> dummy fields? >>> >>> >> Actually it seems like we already define possible dummy fields if >> vbe_interface isn't available. >> > > Yes. That's the case for vbe_interface_* fields. But extending this to > vbe_control_info and vbe_mode_info is backward-incompatible. > > I don't object to backward-incompatible changes, but I would expect that > when we make one, we get the benefit of a clean, legacy-free interface. In > this case we carry on with legacy baggage to archieve half-way backward > compatibility. > > In purely practical terms, all of this only has a minimal effect. GRUB Legacy > didn't implement these extensions, and GRUB 2 hasn't yet, so use of this > feature in loadees isn't widespread. But it has a major impact when it comes > to reputation. If we make incompatible changes in the text, we should be > honest about it. I don't want people to think they can't rely on Multiboot > because its maintainers sometimes stretch the definitions in ways not > permitted by the text. > > Since it's obvious we want to change something (rather than implement > VBE-specific extensions), I propose we start with: > > -If bit 11 in the @samp{flags} is set, the graphics table is available. > +If bit 12 in the @samp{flags} is set, the graphics table is available. > > at this point, we can change anything we like. > > I followed your suggestions. I attach new draft together with drawing of a blue diagonal line in example kernel (it would be way better to make it use it for output but it's intended to just show how to use passed info). I also attach an implementation of multiboot on EFI which uses this draft. Note that this ammendment is nothing EFI-specific and can be used with any linear framebuffer driver. The only reason it's in the same patch is because it was the branch in which I was working on multiboot improvements and haven't yet splitted individual changes yet
-- Regards Vladimir 'φ-coder/phcoder' Serbinenko
=== modified file 'doc/boot.S' --- doc/boot.S 2009-12-24 13:34:49 +0000 +++ doc/boot.S 2010-01-02 17:13:52 +0000 @@ -30,9 +30,9 @@ /* The flags for the Multiboot header. */ #ifdef __ELF__ -# define MULTIBOOT_HEADER_FLAGS 0x00000003 +# define MULTIBOOT_HEADER_FLAGS 0x00000007 #else -# define MULTIBOOT_HEADER_FLAGS 0x00010003 +# define MULTIBOOT_HEADER_FLAGS 0x00010007 #endif .text @@ -64,7 +64,17 @@ .long _end /* entry_addr */ .long multiboot_entry -#endif /* ! __ELF__ */ +#else /* ! __ELF__ */ + .long 0 + .long 0 + .long 0 + .long 0 + .long 0 +#endif /* __ELF__ */ + .long 0 + .long 1024 + .long 768 + .long 32 multiboot_entry: /* Initialize the stack pointer. */ === modified file 'doc/kernel.c' --- doc/kernel.c 2009-12-24 14:25:44 +0000 +++ doc/kernel.c 2010-01-02 17:04:15 +0000 @@ -150,6 +150,87 @@ mmap->len & 0xffffffff, (unsigned) mmap->type); } + + /* Draw diagonal blue line. */ + if (CHECK_FLAG (mbi->flags, 12)) + { + multiboot_uint32_t color; + unsigned i; + void *fb = (void *) (unsigned long) mbi->framebuffer_addr; + + switch (mbi->framebuffer_type) + { + case MULTIBOOT_FRAMEBUFFER_TYPE_INDEXED: + { + unsigned best_distance, distance; + struct multiboot_color *palette; + + palette = (struct multiboot_color *) mbi->framebuffer_palette_addr; + + color = 0; + best_distance = 4*256*256; + + for (i = 0; i < mbi->framebuffer_palette_num_colors; i++) + { + distance = (0xff - palette[i].blue) * (0xff - palette[i].blue) + + palette[i].red * palette[i].red + + palette[i].green * palette[i].green; + if (distance < best_distance) + { + color = i; + best_distance = distance; + } + } + } + break; + + case MULTIBOOT_FRAMEBUFFER_TYPE_RGB: + color = ((1 << mbi->framebuffer_blue_mask_size) - 1) + << mbi->framebuffer_blue_field_position; + break; + + default: + color = 0xffffffff; + break; + } + for (i = 0; i < mbi->framebuffer_width + && i < mbi->framebuffer_height; i++) + { + switch (mbi->framebuffer_bpp) + { + case 8: + { + multiboot_uint8_t *pixel = fb + mbi->framebuffer_pitch * i + i; + *pixel = color; + } + break; + case 15: + case 16: + { + multiboot_uint16_t *pixel + = fb + mbi->framebuffer_pitch * i + 2 * i; + *pixel = color; + } + break; + case 24: + { + multiboot_uint32_t *pixel + = fb + mbi->framebuffer_pitch * i + 3 * i; + *pixel = (color & 0xffffff) | (*pixel & 0xff000000); + } + break; + + case 32: + { + multiboot_uint32_t *pixel + = fb + mbi->framebuffer_pitch * i + 4 * i; + *pixel = color; + } + break; + } + } + } + } /* Clear the screen and initialize VIDEO, XPOS and YPOS. */ === modified file 'doc/multiboot.h' --- doc/multiboot.h 2009-12-24 14:25:44 +0000 +++ doc/multiboot.h 2010-01-02 12:58:41 +0000 @@ -32,7 +32,7 @@ #define MULTIBOOT_BOOTLOADER_MAGIC 0x2BADB002 /* The bits in the required part of flags field we don't support. */ -#define MULTIBOOT_UNSUPPORTED 0x0000fffc +#define MULTIBOOT_UNSUPPORTED 0x0000fff8 /* Alignment of multiboot modules. */ #define MULTIBOOT_MOD_ALIGN 0x00001000 @@ -88,10 +88,12 @@ #define MULTIBOOT_INFO_APM_TABLE 0x00000400 /* Is there video information? */ -#define MULTIBOOT_INFO_VIDEO_INFO 0x00000800 +#define MULTIBOOT_INFO_VBE_INFO 0x00000800 +#define MULTIBOOT_INFO_FRAMEBUFFER_INFO 0x00001000 #ifndef ASM_FILE +typedef unsigned char multiboot_uint8_t; typedef unsigned short multiboot_uint16_t; typedef unsigned int multiboot_uint32_t; typedef unsigned long long multiboot_uint64_t; @@ -190,9 +192,43 @@ multiboot_uint16_t vbe_interface_seg; multiboot_uint16_t vbe_interface_off; multiboot_uint16_t vbe_interface_len; + + multiboot_uint64_t framebuffer_addr; + multiboot_uint32_t framebuffer_pitch; + multiboot_uint32_t framebuffer_width; + multiboot_uint32_t framebuffer_height; + multiboot_uint8_t framebuffer_bpp; + multiboot_uint8_t framebuffer_type; + union + { + struct + { + multiboot_uint32_t framebuffer_palette_addr; + multiboot_uint16_t framebuffer_palette_num_colors; + }; + struct + { + multiboot_uint8_t framebuffer_red_field_position; + multiboot_uint8_t framebuffer_red_mask_size; + multiboot_uint8_t framebuffer_green_field_position; + multiboot_uint8_t framebuffer_green_mask_size; + multiboot_uint8_t framebuffer_blue_field_position; + multiboot_uint8_t framebuffer_blue_mask_size; + }; + }; +}; + +struct multiboot_color +{ + multiboot_uint8_t red; + multiboot_uint8_t green; + multiboot_uint8_t blue; }; typedef struct multiboot_info multiboot_info_t; +#define MULTIBOOT_FRAMEBUFFER_TYPE_INDEXED 0 +#define MULTIBOOT_FRAMEBUFFER_TYPE_RGB 1 + struct multiboot_mmap_entry { multiboot_uint32_t size; === modified file 'doc/multiboot.texi' --- doc/multiboot.texi 2010-01-01 20:02:24 +0000 +++ doc/multiboot.texi 2010-01-02 16:58:33 +0000 @@ -479,7 +479,8 @@ preferred graphics mode. Note that that is only a @emph{recommended} mode by the OS image. If the mode exists, the boot loader should set it, when the user doesn't specify a mode explicitly. Otherwise, the -boot loader should fall back to a similar mode, if available. +boot loader should fall back to a similar mode, if available. Boot loader +may also choose another mode if it sees fit. The meaning of each is as follows: @@ -488,7 +489,9 @@ Contains @samp{0} for linear graphics mode or @samp{1} for EGA-standard text mode. Everything else is reserved for future expansion. Note that the boot loader may set a text mode, even if this -field contains @samp{0}. +field contains @samp{0}. If video adapter doesn't support EGA text mode or +bootloader doesn't know how to initialise this mode it may set video +mode even if field contains @samp{1} @item width Contains the number of the columns. This is specified in pixels in a @@ -635,6 +638,15 @@ 84 | vbe_interface_off | 86 | vbe_interface_len | +-------------------+ +88 | framebuffer_addr | (present if flags[12] is set) +96 | framebuffer_pitch | +100 | framebuffer_width | +104 | framebuffer_height| +108 | framebuffer_bpp | +109 | framebuffer_type | +110-115 | color_info | + +-------------------+ + @end group @end example @@ -911,9 +923,7 @@ @uref{http://www.microsoft.com/hwdev/busbios/amp_12.htm, Advanced Power Management (APM) BIOS Interface Specification}, for more information. -If bit 11 in the @samp{flags} is set, the graphics table is available. -This must only be done if the kernel has indicated in the -...@samp{multiboot Header} that it accepts a graphics mode. +If bit 11 in the @samp{flags} is set, the @sc{vbe} table is available. The fields @samp{vbe_control_info} and @samp{vbe_mode_info} contain the physical addresses of @sc{vbe} control information returned by the @@ -935,6 +945,42 @@ Multiboot boot loaders may simulate @sc{vbe} on n...@sc{vbe} modes, as if they were @sc{vbe} modes. +If bit 12 in the @samp{flags} is set, the @sc{Framebuffer} table is available. + +The field @samp{framebuffer_addr} contains framebuffer physical address. This field is 64-bit wide but bootloader @dfn{should} set it under 4GiB if possible for compatibility with payloads which aren't aware of PAE or amd64. The field @samp{framebuffer_pitch} contains pitch in bytes. The fields @samp{framebuffer_width}, @samp{framebuffer_height} contain framebuffer dimensions in pixels. The field @samp{framebuffer_bpp} contains number of bits per pixel. If @samp{framebuffer_type} is set to 0 it means indexed color. In this case color_info is defined as following: +...@example +...@group + +----------------------------------+ +110 | framebuffer_palette_addr | +114 | framebuffer_palette_num_colors | + +----------------------------------+ +...@end group +...@end example +...@samp{framebuffer_palette_addr} contains address of array of @samp{framebuffer_palette_num_colors} following structures: +...@example +...@group + +-------------+ +0 | red_value | +1 | green_value | +2 | blue_value | + +-------------+ +...@end group +...@end example +If @samp{framebuffer_type} is set to 1 it direct RGB color. Then color_type is defined as following: + +...@example +...@group + +----------------------------------+ +110 | framebuffer_red_field_position | +111 | framebuffer_red_mask_size | +112 | framebuffer_green_field_position | +113 | framebuffer_green_mask_size | +114 | framebuffer_blue_field_position | +115 | framebuffer_blue_mask_size | + +----------------------------------+ +...@end group +...@end example +All further values of @samp{framebuffer_type} are reserved for future expansion @node Examples @chapter Examples
=== added file 'ChangeLog.efiboot' --- ChangeLog.efiboot 1970-01-01 00:00:00 +0000 +++ ChangeLog.efiboot 2010-01-02 01:48:33 +0000 @@ -0,0 +1,19 @@ +2009-11-28 Vladimir Serbinenko <phco...@gmail.com> + + Multiboot support on i386-efi. + + * conf/i386-efi.rmk (pkglib_MODULES): Add multiboot.mod. + (multiboot_mod_SOURCES): New variable. + (multiboot_mod_CFLAGS): Likewise. + (multiboot_mod_LDFLAGS): Likewise. + (multiboot_mod_ASFLAGS): Likewise. + * include/grub/i386/multiboot.h (grub_multiboot_real_boot): Explicitly + declare as regparm (3). + (grub_multiboot2_real_boot): Likewise. + (grub_multiboot_boot): Finish boot services. + (grub_fill_multiboot_mmap): Explicitly parse memory map types. + (grub_multiboot): Declare as noreturn to avoid finishing console. + * loader/multiboot_loader.c (grub_cmd_multiboot_loader): Enable + multiboot1 on i386-efi and disable multiboot2 on this platform. + (grub_cmd_module_loader): Likewise. + === modified file 'conf/i386-coreboot.rmk' --- conf/i386-coreboot.rmk 2009-12-25 22:06:52 +0000 +++ conf/i386-coreboot.rmk 2010-01-02 01:48:37 +0000 @@ -142,6 +142,7 @@ # For multiboot.mod. multiboot_mod_SOURCES = loader/i386/multiboot.c \ + loader/i386/multiboot_mbi.c \ loader/i386/multiboot_helper.S \ loader/i386/pc/multiboot2.c \ loader/multiboot2.c \ === modified file 'conf/i386-efi.rmk' --- conf/i386-efi.rmk 2009-12-25 22:06:52 +0000 +++ conf/i386-efi.rmk 2010-01-02 01:48:37 +0000 @@ -33,7 +33,15 @@ pkglib_MODULES = kernel.img chain.mod appleldr.mod \ linux.mod halt.mod reboot.mod pci.mod lspci.mod \ datetime.mod date.mod datehook.mod loadbios.mod \ - fixvideo.mod mmap.mod acpi.mod + fixvideo.mod mmap.mod acpi.mod multiboot.mod + +# For multiboot.mod. +multiboot_mod_SOURCES = loader/i386/multiboot.c \ + loader/i386/multiboot_mbi.c \ + loader/multiboot_loader.c +multiboot_mod_CFLAGS = $(COMMON_CFLAGS) +multiboot_mod_LDFLAGS = $(COMMON_LDFLAGS) +multiboot_mod_ASFLAGS = $(COMMON_ASFLAGS) # For kernel.img. kernel_img_EXPORTS = no === modified file 'conf/i386-pc.rmk' --- conf/i386-pc.rmk 2009-12-25 22:06:52 +0000 +++ conf/i386-pc.rmk 2010-01-02 01:48:37 +0000 @@ -206,6 +206,7 @@ # For multiboot.mod. multiboot_mod_SOURCES = loader/i386/multiboot.c \ + loader/i386/multiboot_mbi.c \ loader/i386/multiboot_helper.S \ loader/i386/pc/multiboot2.c \ loader/multiboot2.c \ === modified file 'conf/x86_64-efi.rmk' --- conf/x86_64-efi.rmk 2009-12-25 22:06:52 +0000 +++ conf/x86_64-efi.rmk 2010-01-02 01:48:37 +0000 @@ -172,4 +172,13 @@ relocator_mod_ASFLAGS = $(COMMON_ASFLAGS) relocator_mod_LDFLAGS = $(COMMON_LDFLAGS) +# For multiboot.mod. +pkglib_MODULES += multiboot.mod +multiboot_mod_SOURCES = loader/i386/multiboot.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) + include $(srcdir)/conf/common.mk === modified file 'include/grub/i386/multiboot.h' --- include/grub/i386/multiboot.h 2009-12-13 18:37:44 +0000 +++ include/grub/i386/multiboot.h 2010-01-02 01:48:33 +0000 @@ -20,16 +20,23 @@ #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)); + __attribute__ ((noreturn,regparm (3))); extern grub_uint32_t grub_multiboot_payload_eip; extern char *grub_multiboot_payload_orig; extern grub_addr_t grub_multiboot_payload_dest; -extern grub_size_t grub_multiboot_payload_size; +extern grub_size_t grub_multiboot_pure_size; + +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); +void grub_multiboot_free_mbi (void); +grub_err_t grub_multiboot_init_mbi (int argc, char *argv[]); +grub_err_t grub_multiboot_add_module (grub_off_t start, grub_size_t size, + int argc, char *argv[]); +void grub_multiboot_set_bootdev (void); +void grub_multiboot_set_accepts_video (int val); #endif /* ! GRUB_MULTIBOOT_CPU_HEADER */ === modified file 'include/grub/video.h' --- include/grub/video.h 2009-08-14 12:41:58 +0000 +++ include/grub/video.h 2010-01-02 01:48:33 +0000 @@ -234,6 +234,8 @@ }; typedef struct grub_video_adapter *grub_video_adapter_t; +const char *grub_video_get_active_adapter_name (void); + void grub_video_register (grub_video_adapter_t adapter); void grub_video_unregister (grub_video_adapter_t adapter); void grub_video_iterate (int (*hook) (grub_video_adapter_t adapter)); === added file 'include/grub/x86_64/multiboot.h' --- include/grub/x86_64/multiboot.h 1970-01-01 00:00:00 +0000 +++ include/grub/x86_64/multiboot.h 2010-01-02 01:48:33 +0000 @@ -0,0 +1,1 @@ +#include <grub/i386/multiboot.h> === modified file 'include/multiboot.h' --- include/multiboot.h 2009-12-24 14:19:22 +0000 +++ include/multiboot.h 2010-01-02 12:38:41 +0000 @@ -32,7 +32,7 @@ #define MULTIBOOT_BOOTLOADER_MAGIC 0x2BADB002 /* The bits in the required part of flags field we don't support. */ -#define MULTIBOOT_UNSUPPORTED 0x0000fffc +#define MULTIBOOT_UNSUPPORTED 0x0000fff8 /* Alignment of multiboot modules. */ #define MULTIBOOT_MOD_ALIGN 0x00001000 @@ -88,10 +88,12 @@ #define MULTIBOOT_INFO_APM_TABLE 0x00000400 /* Is there video information? */ -#define MULTIBOOT_INFO_VIDEO_INFO 0x00000800 +#define MULTIBOOT_INFO_VBE_INFO 0x00000800 +#define MULTIBOOT_INFO_FRAMEBUFFER_INFO 0x00001000 #ifndef ASM_FILE +typedef unsigned char multiboot_uint8_t; typedef unsigned short multiboot_uint16_t; typedef unsigned int multiboot_uint32_t; typedef unsigned long long multiboot_uint64_t; @@ -190,9 +192,43 @@ multiboot_uint16_t vbe_interface_seg; multiboot_uint16_t vbe_interface_off; multiboot_uint16_t vbe_interface_len; + + multiboot_uint64_t framebuffer_addr; + multiboot_uint32_t framebuffer_pitch; + multiboot_uint32_t framebuffer_width; + multiboot_uint32_t framebuffer_height; + multiboot_uint8_t framebuffer_bpp; + multiboot_uint8_t framebuffer_type; + union + { + struct + { + multiboot_uint32_t framebuffer_palette_addr; + multiboot_uint16_t framebuffer_palette_num_colors; + }; + struct + { + multiboot_uint8_t framebuffer_red_field_position; + multiboot_uint8_t framebuffer_red_mask_size; + multiboot_uint8_t framebuffer_green_field_position; + multiboot_uint8_t framebuffer_green_mask_size; + multiboot_uint8_t framebuffer_blue_field_position; + multiboot_uint8_t framebuffer_blue_mask_size; + }; + }; +}; + +struct multiboot_color +{ + multiboot_uint8_t red; + multiboot_uint8_t green; + multiboot_uint8_t blue; }; typedef struct multiboot_info multiboot_info_t; +#define MULTIBOOT_FRAMEBUFFER_TYPE_INDEXED 0 +#define MULTIBOOT_FRAMEBUFFER_TYPE_RGB 1 + struct multiboot_mmap_entry { multiboot_uint32_t size; === modified file 'loader/i386/multiboot.c' --- loader/i386/multiboot.c 2009-12-25 11:43:20 +0000 +++ loader/i386/multiboot.c 2010-01-02 17:12:40 +0000 @@ -20,7 +20,6 @@ /* * FIXME: The following features from the Multiboot specification still * need to be implemented: - * - VBE support * - symbol table * - drives table * - ROM configuration table @@ -30,8 +29,6 @@ #include <grub/loader.h> #include <grub/machine/loader.h> #include <grub/multiboot.h> -#include <grub/machine/init.h> -#include <grub/machine/memory.h> #include <grub/cpu/multiboot.h> #include <grub/elf.h> #include <grub/aout.h> @@ -42,31 +39,30 @@ #include <grub/misc.h> #include <grub/gzio.h> #include <grub/env.h> -#ifdef GRUB_MACHINE_PCBIOS -#include <grub/machine/biosnum.h> -#include <grub/disk.h> -#include <grub/device.h> -#include <grub/partition.h> -#endif #include <grub/i386/relocator.h> +#include <grub/cpu/multiboot.h> + +#ifdef GRUB_MACHINE_EFI +#include <grub/efi/efi.h> +#endif + extern grub_dl_t my_mod; -static struct multiboot_info *mbi, *mbi_dest; - -static grub_size_t code_size; +static grub_size_t code_size, alloc_mbi; char *grub_multiboot_payload_orig; grub_addr_t grub_multiboot_payload_dest; -grub_size_t grub_multiboot_payload_size; +grub_size_t grub_multiboot_pure_size; grub_uint32_t grub_multiboot_payload_eip; static grub_err_t grub_multiboot_boot (void) { + grub_size_t mbi_size; + grub_err_t err; struct grub_relocator32_state state = { .eax = MULTIBOOT_BOOTLOADER_MAGIC, - .ebx = PTR_TO_UINT32 (mbi_dest), .ecx = 0, .edx = 0, .eip = grub_multiboot_payload_eip, @@ -75,6 +71,29 @@ .esp = 0x7ff00 }; + mbi_size = grub_multiboot_get_mbi_size (); + if (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; + } + + state.ebx = grub_multiboot_payload_dest + grub_multiboot_pure_size; + err = grub_multiboot_make_mbi (grub_multiboot_payload_orig, + grub_multiboot_payload_dest, + grub_multiboot_pure_size, mbi_size); + if (err) + return err; + +#ifdef GRUB_MACHINE_EFI + if (! grub_efi_finish_boot_services ()) + grub_fatal ("cannot exit boot services"); +#endif + grub_relocator32_boot (grub_multiboot_payload_orig, grub_multiboot_payload_dest, state); @@ -86,69 +105,18 @@ static grub_err_t grub_multiboot_unload (void) { - if (mbi) - { - unsigned int i; - for (i = 0; i < mbi->mods_count; i++) - { - grub_free ((void *) - ((struct multiboot_mod_list *) mbi->mods_addr)[i].mod_start); - grub_free ((void *) - ((struct multiboot_mod_list *) mbi->mods_addr)[i].cmdline); - } - grub_free ((void *) mbi->mods_addr); - } + grub_multiboot_free_mbi (); + grub_relocator32_free (grub_multiboot_payload_orig); - mbi = NULL; + alloc_mbi = 0; + grub_multiboot_payload_orig = NULL; grub_dl_unref (my_mod); return GRUB_ERR_NONE; } -/* 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; - - 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 * sizeof (struct multiboot_mmap_entry); -} - -/* Fill previously allocated Multiboot mmap. */ -static void -grub_fill_multiboot_mmap (struct multiboot_mmap_entry *first_entry) -{ - struct multiboot_mmap_entry *mmap_entry = (struct multiboot_mmap_entry *) first_entry; - - 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; - mmap_entry->type = type; - mmap_entry->size = sizeof (struct multiboot_mmap_entry) - sizeof (mmap_entry->size); - mmap_entry++; - - return 0; - } - - grub_mmap_iterate (hook); -} - #define MULTIBOOT_LOAD_ELF64 #include "multiboot_elfxx.c" #undef MULTIBOOT_LOAD_ELF64 @@ -169,58 +137,13 @@ return grub_error (GRUB_ERR_UNKNOWN_OS, "unknown ELF class"); } -static int -grub_multiboot_get_bootdev (grub_uint32_t *bootdev) -{ -#ifdef GRUB_MACHINE_PCBIOS - char *p; - grub_uint32_t biosdev, slice = ~0, part = ~0; - grub_device_t dev; - - biosdev = grub_get_root_biosnumber (); - - dev = grub_device_open (0); - if (dev && dev->disk && dev->disk->partition) - { - - p = dev->disk->partition->partmap->get_name (dev->disk->partition); - if (p) - { - if ((p[0] >= '0') && (p[0] <= '9')) - { - slice = grub_strtoul (p, &p, 0) - 1; - - if ((p) && (p[0] == ',')) - p++; - } - - if ((p[0] >= 'a') && (p[0] <= 'z')) - part = p[0] - 'a'; - } - } - if (dev) - grub_device_close (dev); - - *bootdev = ((biosdev & 0xff) << 24) | ((slice & 0xff) << 16) - | ((part & 0xff) << 8) | 0xff; - return (biosdev != ~0UL); -#else - *bootdev = 0xffffffff; - return 0; -#endif -} - void grub_multiboot (int argc, char *argv[]) { grub_file_t file = 0; - char buffer[MULTIBOOT_SEARCH], *cmdline = 0, *p; + char buffer[MULTIBOOT_SEARCH]; struct multiboot_header *header; - grub_ssize_t len, cmdline_length, boot_loader_name_length; - grub_uint32_t mmap_length; - int i; - int cmdline_argc; - char **cmdline_argv; + grub_ssize_t len; grub_loader_unset (); @@ -271,31 +194,8 @@ grub_relocator32_free (grub_multiboot_payload_orig); grub_multiboot_payload_orig = NULL; - mmap_length = grub_get_multiboot_mmap_len (); - - /* Figure out cmdline length. */ /* Skip filename. */ - cmdline_argc = argc - 1; - cmdline_argv = argv + 1; - - for (i = 0, cmdline_length = 0; i < cmdline_argc; i++) - cmdline_length += grub_strlen (cmdline_argv[i]) + 1; - - if (cmdline_length == 0) - cmdline_length = 1; - - boot_loader_name_length = sizeof(PACKAGE_STRING); - -#define cmdline_addr(x) ((void *) ((x) + code_size)) -#define boot_loader_name_addr(x) \ - ((void *) ((x) + code_size + cmdline_length)) -#define mbi_addr(x) ((void *) ((x) + code_size + cmdline_length + boot_loader_name_length)) -#define mmap_addr(x) ((void *) ((x) + code_size + cmdline_length + boot_loader_name_length + sizeof (struct multiboot_info))) - - grub_multiboot_payload_size = cmdline_length - /* boot_loader_name_length might need to grow for mbi,etc to be aligned (see below) */ - + boot_loader_name_length + 3 - + sizeof (struct multiboot_info) + mmap_length; + grub_multiboot_init_mbi (argc - 1, argv + 1); if (header->flags & MULTIBOOT_AOUT_KLUDGE) { @@ -310,10 +210,11 @@ code_size = load_size; grub_multiboot_payload_dest = header->load_addr; - grub_multiboot_payload_size += code_size; + grub_multiboot_pure_size += code_size; + alloc_mbi = grub_multiboot_get_mbi_size (); grub_multiboot_payload_orig - = grub_relocator32_alloc (grub_multiboot_payload_size); + = grub_relocator32_alloc (grub_multiboot_pure_size + alloc_mbi); if (! grub_multiboot_payload_orig) goto fail; @@ -335,53 +236,37 @@ else if (grub_multiboot_load_elf (file, buffer) != GRUB_ERR_NONE) goto fail; - /* This provides alignment for the MBI, the memory map and the backward relocator. */ - boot_loader_name_length += (0x04 - ((unsigned long) mbi_addr (grub_multiboot_payload_dest) & 0x03)); - - mbi = mbi_addr (grub_multiboot_payload_orig); - mbi_dest = mbi_addr (grub_multiboot_payload_dest); - grub_memset (mbi, 0, sizeof (struct multiboot_info)); - mbi->mmap_length = mmap_length; - - grub_fill_multiboot_mmap (mmap_addr (grub_multiboot_payload_orig)); - - /* FIXME: grub_uint32_t will break for addresses above 4 GiB, but is mandated - by the spec. Is there something we can do about it? */ - mbi->mmap_addr = (grub_uint32_t) mmap_addr (grub_multiboot_payload_dest); - mbi->flags |= MULTIBOOT_INFO_MEM_MAP; - - /* Convert from bytes to kilobytes. */ - mbi->mem_lower = grub_mmap_get_lower () / 1024; - mbi->mem_upper = grub_mmap_get_upper () / 1024; - mbi->flags |= MULTIBOOT_INFO_MEMORY; - - cmdline = p = cmdline_addr (grub_multiboot_payload_orig); - if (! cmdline) - goto fail; - - for (i = 0; i < cmdline_argc; i++) + if (header->flags & MULTIBOOT_VIDEO_MODE) { - p = grub_stpcpy (p, cmdline_argv[i]); - *(p++) = ' '; + switch (header->mode_type) + { + case 1: + grub_env_set ("gfxpayload", "text"); + break; + + case 0: + { + char buf[sizeof ("XXXXXXXXXXxXXXXXXXXXXxXXXXXXXXXX,XXXXXXXXXXxXXXXXXXXXX,auto")]; + if (header->depth && header->width && header->height) + grub_sprintf (buf, "%dx%dx%d,%dx%d,auto", header->width, + header->height, header->depth, header->width, + header->height); + else if (header->width && header->height) + grub_sprintf (buf, "%dx%d,auto", header->width, header->height); + else + grub_sprintf (buf, "auto"); + + grub_env_set ("gfxpayload", buf); + break; + } + } } - /* Remove the space after the last word. */ - if (p != cmdline) - p--; - *p = 0; - - mbi->flags |= MULTIBOOT_INFO_CMDLINE; - mbi->cmdline = (grub_uint32_t) cmdline_addr (grub_multiboot_payload_dest); - - - grub_strcpy (boot_loader_name_addr (grub_multiboot_payload_orig), PACKAGE_STRING); - mbi->flags |= MULTIBOOT_INFO_BOOT_LOADER_NAME; - mbi->boot_loader_name = (grub_uint32_t) boot_loader_name_addr (grub_multiboot_payload_dest); - - if (grub_multiboot_get_bootdev (&mbi->boot_device)) - mbi->flags |= MULTIBOOT_INFO_BOOTDEV; - - grub_loader_set (grub_multiboot_boot, grub_multiboot_unload, 1); + grub_multiboot_set_accepts_video (!!(header->flags & MULTIBOOT_VIDEO_MODE)); + + grub_multiboot_set_bootdev (); + + grub_loader_set (grub_multiboot_boot, grub_multiboot_unload, 0); fail: if (file) @@ -389,22 +274,19 @@ if (grub_errno != GRUB_ERR_NONE) { - grub_free (cmdline); - grub_free (mbi); + grub_relocator32_free (grub_multiboot_payload_orig); grub_dl_unref (my_mod); } } - void grub_module (int argc, char *argv[]) { grub_file_t file = 0; - grub_ssize_t size, len = 0; - char *module = 0, *cmdline = 0, *p; - int i; - int cmdline_argc; - char **cmdline_argv; + grub_ssize_t size; + char *module = 0; + grub_size_t mbi_size; + grub_err_t err; if (argc == 0) { @@ -412,7 +294,7 @@ goto fail; } - if (!mbi) + if (!grub_multiboot_payload_orig) { grub_error (GRUB_ERR_BAD_ARGUMENT, "you need to load the multiboot kernel first"); @@ -424,9 +306,24 @@ goto fail; size = grub_file_size (file); - module = grub_memalign (MULTIBOOT_MOD_ALIGN, size); - if (! module) - goto fail; + mbi_size = grub_multiboot_get_mbi_size (); + + /* Skip module name. */ + err = grub_multiboot_add_module (grub_multiboot_pure_size, size, + argc - 1, argv + 1); + if (err) + goto fail; + + /* Allocate space on relocator for both module and its descriptor. */ + grub_multiboot_payload_orig + = grub_relocator32_realloc (grub_multiboot_payload_orig, + grub_multiboot_pure_size + size); + if (!grub_multiboot_payload_orig) + goto fail; + alloc_mbi = mbi_size; + + module = grub_multiboot_payload_orig + grub_multiboot_pure_size; + grub_multiboot_pure_size += size; if (grub_file_read (file, module, size) != size) { @@ -434,67 +331,8 @@ goto fail; } - /* Skip module name. */ - cmdline_argc = argc - 1; - cmdline_argv = argv + 1; - - for (i = 0; i < cmdline_argc; i++) - len += grub_strlen (cmdline_argv[i]) + 1; - - if (len == 0) - len = 1; - - cmdline = p = grub_malloc (len); - if (! cmdline) - goto fail; - - for (i = 0; i < cmdline_argc; i++) - { - p = grub_stpcpy (p, cmdline_argv[i]); - *(p++) = ' '; - } - - /* Remove the space after the last word. */ - if (p != cmdline) - p--; - *p = '\0'; - - if (mbi->flags & MULTIBOOT_INFO_MODS) - { - struct multiboot_mod_list *modlist = (struct multiboot_mod_list *) mbi->mods_addr; - - modlist = grub_realloc (modlist, (mbi->mods_count + 1) - * sizeof (struct multiboot_mod_list)); - if (! modlist) - goto fail; - mbi->mods_addr = (grub_uint32_t) modlist; - modlist += mbi->mods_count; - modlist->mod_start = (grub_uint32_t) module; - modlist->mod_end = (grub_uint32_t) module + size; - modlist->cmdline = (grub_uint32_t) cmdline; - modlist->pad = 0; - mbi->mods_count++; - } - else - { - struct multiboot_mod_list *modlist = grub_zalloc (sizeof (struct multiboot_mod_list)); - if (! modlist) - goto fail; - modlist->mod_start = (grub_uint32_t) module; - modlist->mod_end = (grub_uint32_t) module + size; - modlist->cmdline = (grub_uint32_t) cmdline; - mbi->mods_count = 1; - mbi->mods_addr = (grub_uint32_t) modlist; - mbi->flags |= MULTIBOOT_INFO_MODS; - } - fail: if (file) grub_file_close (file); - - if (grub_errno != GRUB_ERR_NONE) - { - grub_free (module); - grub_free (cmdline); - } } + === modified file 'loader/i386/multiboot_elfxx.c' --- loader/i386/multiboot_elfxx.c 2009-12-13 18:29:15 +0000 +++ loader/i386/multiboot_elfxx.c 2010-01-02 01:48:33 +0000 @@ -100,10 +100,11 @@ code_size = (phdr(highest_segment)->p_paddr + phdr(highest_segment)->p_memsz) - phdr(lowest_segment)->p_paddr; grub_multiboot_payload_dest = phdr(lowest_segment)->p_paddr; - grub_multiboot_payload_size += code_size; + grub_multiboot_pure_size += code_size; + alloc_mbi = grub_multiboot_get_mbi_size (); grub_multiboot_payload_orig - = grub_relocator32_alloc (grub_multiboot_payload_size); + = grub_relocator32_alloc (grub_multiboot_pure_size + alloc_mbi); if (!grub_multiboot_payload_orig) return grub_errno; === added file 'loader/i386/multiboot_mbi.c' --- loader/i386/multiboot_mbi.c 1970-01-01 00:00:00 +0000 +++ loader/i386/multiboot_mbi.c 2010-01-02 12:12:35 +0000 @@ -0,0 +1,518 @@ +/* + * 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 <http://www.gnu.org/licenses/>. + */ + +#include <grub/machine/memory.h> +#include <grub/memory.h> +#ifdef GRUB_MACHINE_PCBIOS +#include <grub/machine/biosnum.h> +#endif +#include <grub/multiboot.h> +#include <grub/cpu/multiboot.h> +#include <grub/disk.h> +#include <grub/device.h> +#include <grub/partition.h> +#include <grub/mm.h> +#include <grub/misc.h> +#include <grub/i386/pc/vbe.h> +#include <grub/env.h> + +#if defined (GRUB_MACHINE_PCBIOS) || defined (GRUB_MACHINE_COREBOOT) || defined (GRUB_MACHINE_QEMU) +#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_off_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 grub_uint32_t bootdev; +static int bootdev_set; +static int accepts_video; + +void +grub_multiboot_set_accepts_video (int val) +{ + accepts_video = val; +} + +/* 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; + + 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 * sizeof (struct multiboot_mmap_entry); +} + +grub_size_t +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 () + + sizeof (struct grub_vbe_info_block) + + sizeof (struct grub_vbe_mode_info_block) + + 256 * sizeof (struct multiboot_color); +} + +/* Fill previously allocated Multiboot mmap. */ +static void +grub_fill_multiboot_mmap (struct multiboot_mmap_entry *first_entry) +{ + struct multiboot_mmap_entry *mmap_entry = (struct multiboot_mmap_entry *) first_entry; + + 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; + + default: + mmap_entry->type = MULTIBOOT_MEMORY_RESERVED; + break; + } + mmap_entry->size = sizeof (struct multiboot_mmap_entry) - sizeof (mmap_entry->size); + mmap_entry++; + + return 0; + } + + 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); + else + { + char *tmp; + tmp = grub_malloc (grub_strlen (modevar) + + sizeof (DEFAULT_VIDEO_MODE) + 1); + if (! tmp) + return grub_errno; + grub_sprintf (tmp, "%s;" DEFAULT_VIDEO_MODE, modevar); + err = grub_video_set_mode (tmp, 0); + grub_free (tmp); + } + } + else + err = grub_video_set_mode ("text", 0); + + return err; +} + +#if HAS_VBE +static grub_err_t +fill_vbe_info (struct multiboot_info *mbi, grub_uint8_t *ptrorig, + grub_uint32_t ptrdest) +{ + grub_vbe_status_t status; + grub_uint32_t vbe_mode; + void *scratch = (void *) GRUB_MEMORY_MACHINE_SCRATCH_ADDR; + + status = grub_vbe_bios_get_controller_info (scratch); + if (status != GRUB_VBE_STATUS_OK) + return grub_error (GRUB_ERR_IO, "Can't get controller info."); + + mbi->vbe_control_info = ptrdest; + grub_memcpy (ptrorig, scratch, sizeof (struct grub_vbe_info_block)); + ptrorig += sizeof (struct grub_vbe_info_block); + ptrdest += sizeof (struct grub_vbe_info_block); + + status = grub_vbe_bios_get_mode (scratch); + vbe_mode = *(grub_uint32_t *) scratch; + if (status != GRUB_VBE_STATUS_OK) + return grub_error (GRUB_ERR_IO, "Can't get VBE mode."); + mbi->vbe_mode = vbe_mode; + + status = grub_vbe_bios_get_mode_info (vbe_mode, scratch); + if (status != GRUB_VBE_STATUS_OK) + return grub_error (GRUB_ERR_IO, "Can't get mode info."); + mbi->vbe_mode_info = ptrdest; + grub_memcpy (ptrorig, scratch, sizeof (struct grub_vbe_mode_info_block)); + ptrorig += sizeof (struct grub_vbe_mode_info_block); + ptrdest += sizeof (struct grub_vbe_mode_info_block); + + /* FIXME: retrieve those. */ + mbi->vbe_interface_seg = 0; + mbi->vbe_interface_off = 0; + mbi->vbe_interface_len = 0; + + mbi->flags |= MULTIBOOT_INFO_VBE_INFO; + + return GRUB_ERR_NONE; +} +#endif + +static grub_err_t +retrieve_video_parameters (struct multiboot_info *mbi, + grub_uint8_t *ptrorig, grub_uint32_t ptrdest) +{ + grub_err_t err; + struct grub_video_mode_info mode_info; + void *framebuffer; +#if HAS_VBE + int vbe_active; +#endif + struct grub_video_palette_data palette[256]; + + err = set_video_mode (); + if (err) + return err; + + grub_video_get_palette (0, ARRAY_SIZE (palette), palette); + +#if HAS_VBE + { + const char *adapter_name; + adapter_name = grub_video_get_active_adapter_name (); + + vbe_active = ((adapter_name + && grub_strcmp (adapter_name, + "VESA BIOS Extension Video Driver") == 0) + || (HAS_VGA_TEXT && !adapter_name)); + } +#endif + + err = grub_video_get_info_and_fini (&mode_info, &framebuffer); + if (err) + return err; + + mbi->framebuffer_addr = (grub_addr_t) framebuffer; + mbi->framebuffer_pitch = mode_info.pitch; + + mbi->framebuffer_width = mode_info.width; + mbi->framebuffer_height = mode_info.height; + + mbi->framebuffer_bpp = mode_info.bpp; + + if (mode_info.mode_type & GRUB_VIDEO_MODE_TYPE_INDEX_COLOR) + { + struct multiboot_color *mb_palette; + unsigned i; + mbi->framebuffer_type = MULTIBOOT_FRAMEBUFFER_TYPE_INDEXED; + mbi->framebuffer_palette_addr = ptrdest; + mb_palette = (struct multiboot_color *) ptrorig; + for (i = 0; i < ARRAY_SIZE (palette); i++) + { + mb_palette[i].red = palette[i].r; + mb_palette[i].green = palette[i].g; + mb_palette[i].blue = palette[i].b; + } + ptrorig += ARRAY_SIZE (palette) * sizeof (struct multiboot_color); + ptrdest += ARRAY_SIZE (palette) * sizeof (struct multiboot_color); + } + else + { + mbi->framebuffer_type = MULTIBOOT_FRAMEBUFFER_TYPE_RGB; + mbi->framebuffer_red_field_position = mode_info.green_field_pos; + mbi->framebuffer_red_mask_size = mode_info.green_mask_size; + mbi->framebuffer_green_field_position = mode_info.green_field_pos; + mbi->framebuffer_green_mask_size = mode_info.green_mask_size; + mbi->framebuffer_blue_field_position = mode_info.blue_field_pos; + mbi->framebuffer_blue_mask_size = mode_info.blue_mask_size; + + mbi->flags |= MULTIBOOT_INFO_FRAMEBUFFER_INFO; + } + +#if HAS_VBE + if (vbe_active) + fill_vbe_info (mbi, ptrorig, ptrdest); +#endif + + 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 *) orig + buf_off; + grub_uint32_t ptrdest = dest + buf_off; + struct multiboot_info *mbi; + struct multiboot_mod_list *modlist; + unsigned i; + struct module *cur; + grub_size_t mmap_size; + grub_err_t err; + + if (bufsize < grub_multiboot_get_mbi_size ()) + return grub_error (GRUB_ERR_OUT_OF_MEMORY, "mbi buffer is too small"); + + mbi = (struct multiboot_info *) ptrorig; + ptrorig += sizeof (*mbi); + ptrdest += sizeof (*mbi); + grub_memset (mbi, 0, sizeof (*mbi)); + + grub_memcpy (ptrorig, cmdline, cmdline_size); + mbi->flags |= MULTIBOOT_INFO_CMDLINE; + mbi->cmdline = ptrdest; + ptrorig += ALIGN_UP (cmdline_size, 4); + ptrdest += ALIGN_UP (cmdline_size, 4); + + grub_memcpy (ptrorig, PACKAGE_STRING, sizeof(PACKAGE_STRING)); + mbi->flags |= MULTIBOOT_INFO_BOOT_LOADER_NAME; + mbi->boot_loader_name = ptrdest; + ptrorig += ALIGN_UP (sizeof(PACKAGE_STRING), 4); + ptrdest += ALIGN_UP (sizeof(PACKAGE_STRING), 4); + + if (modcnt) + { + mbi->flags |= MULTIBOOT_INFO_MODS; + mbi->mods_addr = ptrdest; + mbi->mods_count = modcnt; + modlist = (struct multiboot_mod_list *) ptrorig; + ptrorig += modcnt * sizeof (struct multiboot_mod_list); + ptrdest += modcnt * sizeof (struct multiboot_mod_list); + + for (i = 0, cur = modules; i < modcnt; i++, cur = cur->next) + { + modlist[i].mod_start = ptrdest + cur->start; + modlist[i].mod_end = modlist[i].mod_start + cur->size; + modlist[i].cmdline = ptrdest; + grub_memcpy (ptrorig, cur->cmdline, cur->cmdline_size); + ptrorig += ALIGN_UP (cur->cmdline_size, 4); + ptrdest += ALIGN_UP (cur->cmdline_size, 4); + } + } + else + { + mbi->mods_addr = 0; + mbi->mods_count = 0; + } + + mmap_size = grub_get_multiboot_mmap_len (); + grub_fill_multiboot_mmap ((struct multiboot_mmap_entry *) ptrorig); + mbi->mmap_length = mmap_size; + mbi->mmap_addr = ptrdest; + mbi->flags |= MULTIBOOT_INFO_MEM_MAP; + ptrorig += mmap_size; + ptrdest += mmap_size; + + /* Convert from bytes to kilobytes. */ + mbi->mem_lower = grub_mmap_get_lower () / 1024; + mbi->mem_upper = grub_mmap_get_upper () / 1024; + mbi->flags |= MULTIBOOT_INFO_MEMORY; + + if (bootdev_set) + { + mbi->boot_device = bootdev; + mbi->flags |= MULTIBOOT_INFO_BOOTDEV; + } + + err = retrieve_video_parameters (mbi, ptrorig, ptrdest); + if (err) + { + grub_print_error (); + grub_errno = GRUB_ERR_NONE; + } + ptrorig += sizeof (struct grub_vbe_info_block); + ptrdest += sizeof (struct grub_vbe_info_block); + ptrorig += sizeof (struct grub_vbe_mode_info_block); + ptrdest += sizeof (struct grub_vbe_mode_info_block); + + 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_off_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, 4); + + 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; + + return GRUB_ERR_NONE; +} + +void +grub_multiboot_set_bootdev (void) +{ + char *p; + grub_uint32_t biosdev, slice = ~0, part = ~0; + grub_device_t dev; + +#ifdef GRUB_MACHINE_PCBIOS + biosdev = grub_get_root_biosnumber (); +#else + biosdev = 0xffffffff; +#endif + + dev = grub_device_open (0); + if (dev && dev->disk && dev->disk->partition) + { + + p = dev->disk->partition->partmap->get_name (dev->disk->partition); + if (p) + { + if ((p[0] >= '0') && (p[0] <= '9')) + { + slice = grub_strtoul (p, &p, 0) - 1; + + if ((p) && (p[0] == ',')) + p++; + } + + if ((p[0] >= 'a') && (p[0] <= 'z')) + part = p[0] - 'a'; + } + } + if (dev) + grub_device_close (dev); + + bootdev = ((biosdev & 0xff) << 24) | ((slice & 0xff) << 16) + | ((part & 0xff) << 8) | 0xff; + bootdev_set = 1; +} === modified file 'loader/i386/pc/xnu.c' --- loader/i386/pc/xnu.c 2009-10-15 12:40:13 +0000 +++ loader/i386/pc/xnu.c 2010-01-02 01:48:33 +0000 @@ -43,7 +43,8 @@ { struct grub_video_mode_info mode_info; int ret; - char *tmp, *modevar; + char *tmp; + const char *modevar; void *framebuffer; grub_err_t err; @@ -55,8 +56,7 @@ tmp = grub_malloc (grub_strlen (modevar) + sizeof (DEFAULT_VIDEO_MODE) + 1); if (! tmp) - return grub_error (GRUB_ERR_OUT_OF_MEMORY, - "couldn't allocate temporary storag"); + return grub_errno; grub_sprintf (tmp, "%s;" DEFAULT_VIDEO_MODE, modevar); err = grub_video_set_mode (tmp, video_hook); grub_free (tmp); === modified file 'loader/multiboot_loader.c' --- loader/multiboot_loader.c 2009-12-26 10:01:33 +0000 +++ loader/multiboot_loader.c 2010-01-02 01:48:37 +0000 @@ -139,7 +139,7 @@ /* 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) + defined(GRUB_MACHINE_QEMU) || defined(GRUB_MACHINE_EFI) if (header_multi_ver_found == 1) { grub_dprintf ("multiboot_loader", @@ -148,6 +148,7 @@ module_version_status = 1; } #endif +#if !defined(GRUB_MACHINE_EFI) if (header_multi_ver_found == 0 || header_multi_ver_found == 2) { grub_dprintf ("multiboot_loader", @@ -155,6 +156,7 @@ grub_multiboot2 (argc, argv); module_version_status = 2; } +#endif return grub_errno; @@ -173,7 +175,7 @@ { #if defined(GRUB_MACHINE_PCBIOS) || defined(GRUB_MACHINE_COREBOOT) || \ - defined(GRUB_MACHINE_QEMU) + defined(GRUB_MACHINE_QEMU) || defined(GRUB_MACHINE_EFI) if (module_version_status == 1) { grub_dprintf("multiboot_loader", @@ -181,13 +183,14 @@ grub_module (argc, argv); } #endif +#if !defined(GRUB_MACHINE_EFI) if (module_version_status == 2) { grub_dprintf("multiboot_loader", "Launching multiboot 2 grub_module2() function\n"); grub_module2 (argc, argv); } - +#endif return grub_errno; } === modified file 'video/video.c' --- video/video.c 2009-12-24 22:53:05 +0000 +++ video/video.c 2010-01-02 01:48:37 +0000 @@ -399,6 +399,15 @@ return grub_video_adapter_active->get_active_render_target (target); } +const char * +grub_video_get_active_adapter_name (void) +{ + if (grub_video_adapter_active) + return grub_video_adapter_active->name; + return NULL; +} + + grub_err_t grub_video_set_mode (const char *modestring, int NESTED_FUNC_ATTR (*hook) (grub_video_adapter_t p,
signature.asc
Description: OpenPGP digital signature
_______________________________________________ Grub-devel mailing list Grub-devel@gnu.org http://lists.gnu.org/mailman/listinfo/grub-devel