=== modified file 'grub-core/loader/i386/linux.c' --- grub-core/loader/i386/linux.c 2011-03-09 17:38:31 +0000 +++ grub-core/loader/i386/linux.c 2011-03-28 15:44:34 +0000 @@ -994,7 +994,89 @@ return grub_errno; } -static grub_command_t cmd_linux, cmd_initrd; +static grub_err_t +grub_cmd_ucode (grub_command_t cmd __attribute__ ((unused)), + int argc, char *argv[]) +{ + grub_file_t file = 0; + grub_ssize_t size; + grub_addr_t addr_min, addr_max; + grub_err_t err; + struct linux_kernel_header *lh; + grub_relocator_chunk_t ch; + void *ucode_mem; + grub_addr_t ucode_mem_target; + struct setup_data *hdr; + + if (argc == 0) + { + grub_error (GRUB_ERR_BAD_ARGUMENT, "no module specified"); + goto fail; + } + + if (! loaded) + { + grub_error (GRUB_ERR_BAD_ARGUMENT, "you need to load the kernel first"); + goto fail; + } + + grub_file_filter_disable_compression (); + file = grub_file_open (argv[0]); + size = grub_file_size(file); + + lh = (struct linux_kernel_header *) real_mode_mem; + if (grub_le_to_cpu16(lh->version) < 0x0209) + { + grub_printf("%s:%d: header version=0x%x(<0x0209)\n", + __FUNCTION__, __LINE__, lh->version); + goto fail; + } + + addr_max = grub_cpu_to_le32(lh->initrd_addr_max); + if (addr_max > GRUB_LINUX_INITRD_MAX_ADDRESS) + addr_max = GRUB_LINUX_INITRD_MAX_ADDRESS; + addr_max -= 0x10000; + + if ((linux_mem_size != 0) && (linux_mem_size < addr_max)) + addr_max = linux_mem_size; + addr_max = (addr_max - size - sizeof(*hdr)) & ~0xFFF; + addr_min = prot_mode_target; + + grub_printf("microcode addr_min=%p, add_max=%p\n", + (void*)addr_min, (void *)addr_max); + + err = grub_relocator_alloc_chunk_align(relocator, &ch, addr_min, + addr_max, size + sizeof(*hdr), + 0x1000, GRUB_RELOCATOR_PREFERENCE_HIGH); + if (err) return err; + ucode_mem = get_virtual_current_address(ch); + ucode_mem_target = get_physical_target_address(ch); + + if (grub_file_read(file, (unsigned char*)ucode_mem + sizeof(*hdr), size) != size) + { + grub_error (GRUB_ERR_FILE_READ_ERROR, "couldn't read file"); + goto fail; + } + + hdr = (struct setup_data *)ucode_mem; + hdr->type = SETUP_MICROCODE; + hdr->len = size; + hdr->next = 0; + + lh->setup_data = ucode_mem_target; + + grub_printf("%s: header_version=0x%x, ucode_size=%d\n", __FUNCTION__, + grub_le_to_cpu16 (lh->version), size); + + + fail: + if (file) + grub_file_close (file); + + return grub_errno; +} + +static grub_command_t cmd_linux, cmd_initrd, cmd_ucode; GRUB_MOD_INIT(linux) { @@ -1002,6 +1084,8 @@ 0, N_("Load Linux.")); cmd_initrd = grub_register_command ("initrd", grub_cmd_initrd, 0, N_("Load initrd.")); + cmd_ucode = grub_register_command ("microcode", grub_cmd_ucode, + 0, N_("Load microcode.")); my_mod = mod; } @@ -1009,4 +1093,5 @@ { grub_unregister_command (cmd_linux); grub_unregister_command (cmd_initrd); + grub_unregister_command (cmd_ucode); } === modified file 'include/grub/i386/linux.h' --- include/grub/i386/linux.h 2011-01-10 23:02:01 +0000 +++ include/grub/i386/linux.h 2011-03-28 09:41:12 +0000 @@ -87,6 +87,22 @@ GRUB_VIDEO_LINUX_TYPE_SIMPLE = 0x70 /* Linear framebuffer without any additional functions. */ }; +/* setup data types */ +#define SETUP_NONE 0 +#define SETUP_E820_EXT 1 +#define SETUP_DTB 2 +#define SETUP_MICROCODE 3 + +/* extensible setup data list node */ +struct setup_data { + grub_uint64_t next; + grub_uint32_t type; + grub_uint32_t len; + grub_uint8_t data[0]; +} __attribute__ ((packed)); + + + /* For the Linux/i386 boot protocol version 2.03. */ struct linux_kernel_header { @@ -130,6 +146,8 @@ grub_uint16_t pad1; /* Unused */ grub_uint32_t cmd_line_ptr; /* Points to the kernel command line */ grub_uint32_t initrd_addr_max; /* Highest address for initrd */ + grub_uint32_t pad2[8]; + grub_uint64_t setup_data; } __attribute__ ((packed)); /* Boot parameters for Linux based on 2.6.12. This is used by the setup