--- arch/x86/kernel/microcode_intel_early.c | 139 ++++++++++++++++++++------------ arch/x86/kernel/setup.c | 11 ++ include/linux/earlycpio.h | 10 +- lib/earlycpio.c | 104 ++++++++++++++++++----- 4 files changed, 190 insertions(+), 74 deletions(-) Index: linux-2.6/arch/x86/kernel/microcode_intel_early.c =================================================================== --- linux-2.6.orig/arch/x86/kernel/microcode_intel_early.c +++ linux-2.6/arch/x86/kernel/microcode_intel_early.c @@ -20,9 +20,11 @@ #include #include #include + #include #include #include +#include struct microcode_intel __initdata *mc_saved_in_initrd[MAX_UCODE_COUNT]; struct mc_saved_data mc_saved_data; @@ -290,25 +292,93 @@ static int __cpuinit collect_cpu_info_ea return 0; } +#ifdef CONFIG_X86_64 +static void *early_cd_data_p __initdata; +static unsigned long early_cd_data_pa __initdata; +static unsigned long early_cd_size __initdata; + +void __init update_mc_saved_data(unsigned long pa_offset) +{ + int i; + unsigned long addr; + + if (early_cd_data_p) + early_iounmap(early_cd_data_p, early_cd_size); + + if (!mc_saved_data.mc_saved) + return; + + for (i = 0; i< mc_saved_data.mc_saved_count; i++) { + addr = (void *)mc_saved_data.mc_saved[i]- early_cd_data_p; + addr += early_cd_data_pa; + addr += pa_offset; + mc_saved_data.mc_saved[i] = __va(addr); + } +} +static __init void *map(unsigned long addr, unsigned long size) +{ + return early_memremap(addr, size); +} +static __init void unmap(void *p, unsigned long size) +{ + return early_iounmap(p, size); +} + +#else + +void __init update_mc_saved_data(unsigned long pa_offset) +{ + int i; + + if (mc_saved_data.mc_saved) { + mc_saved_data.mc_saved = __va(mc_saved_data.mc_saved); + for (i = 0; i < mc_saved_data.mc_saved_count; i++) + mc_saved_data.mc_saved[i] = + __va(mc_saved_data.mc_saved[i] + pa_offset); + + } + + mc_saved_data.ucode_cpu_info = __va(mc_saved_data.ucode_cpu_info); + if (mc_saved_data.ucode_cpu_info->mc) + mc_saved_data.ucode_cpu_info->mc = + __va(mc_saved_data.ucode_cpu_info->mc); +} + +#endif + static __init enum ucode_state -scan_microcode(unsigned long start, unsigned long end, +scan_microcode(unsigned long start, unsigned long size, struct mc_saved_data *mc_saved_data, struct microcode_intel **mc_saved_in_initrd) { - unsigned int size = end - start + 1; struct cpio_data cd = { 0, 0 }; char ucode_name[] = "kernel/x86/microcode/GenuineIntel.bin"; long offset = 0; + void *p; +#ifdef CONFIG_X86_64 + cd = find_cpio_data_map(ucode_name, (void *)start, size, &offset, + map, unmap, PAGE_SIZE*16); +#else cd = find_cpio_data(ucode_name, (void *)start, size, &offset); +#endif if (!cd.data) return UCODE_ERROR; - return get_matching_model_microcode(0, cd.data, cd.size, mc_saved_data, +#ifdef CONFIG_X86_64 + /* will need to free them later */ + early_cd_data_pa = (unsigned long)cd.data; + early_cd_size = cd.size; + p = early_cd_data_p = early_memremap(early_cd_data_pa, cd.size); +#else + p = cd.data; +#endif + + return get_matching_model_microcode(0, p, cd.size, mc_saved_data, mc_saved_in_initrd, SYSTEM_BOOTING); } -static int __init +static int __cpuinit apply_microcode_early(struct mc_saved_data *mc_saved_data, int cpu) { struct ucode_cpu_info *uci = mc_saved_data->ucode_cpu_info + cpu; @@ -339,32 +409,6 @@ apply_microcode_early(struct mc_saved_da return 0; } -#ifdef CONFIG_X86_32 -static void __init map_mc_saved(struct mc_saved_data *mc_saved_data, - struct microcode_intel **mc_saved_in_initrd) -{ - int i; - - if (mc_saved_data->mc_saved) { - for (i = 0; i < mc_saved_data->mc_saved_count; i++) - mc_saved_data->mc_saved[i] = - __va(mc_saved_data->mc_saved[i]); - - mc_saved_data->mc_saved = __va(mc_saved_data->mc_saved); - } - - if (mc_saved_data->ucode_cpu_info->mc) - mc_saved_data->ucode_cpu_info->mc = - __va(mc_saved_data->ucode_cpu_info->mc); - mc_saved_data->ucode_cpu_info = __va(mc_saved_data->ucode_cpu_info); -} -#else -static inline void __init map_mc_saved(struct mc_saved_data *mc_saved_data, - struct microcode_intel **mc_saved_in_initrd) -{ -} -#endif - void __init save_microcode_in_initrd(struct mc_saved_data *mc_saved_data, struct microcode_intel **mc_saved_in_initrd) { @@ -376,7 +420,7 @@ void __init save_microcode_in_initrd(str static void __init _load_ucode_intel_bsp(struct mc_saved_data *mc_saved_data, struct microcode_intel **mc_saved_in_initrd, - unsigned long initrd_start, unsigned long initrd_end) + unsigned long initrd_start, unsigned long initrd_size) { int cpu = 0; @@ -387,37 +431,34 @@ _load_ucode_intel_bsp(struct mc_saved_da (struct ucode_cpu_info *)__pa(ucode_cpu_info_early); #endif collect_cpu_info_early(mc_saved_data->ucode_cpu_info + cpu); - scan_microcode(initrd_start, initrd_end, mc_saved_data, + scan_microcode(initrd_start, initrd_size, mc_saved_data, mc_saved_in_initrd); load_microcode(mc_saved_data, cpu); apply_microcode_early(mc_saved_data, cpu); - map_mc_saved(mc_saved_data, mc_saved_in_initrd); } void __init load_ucode_intel_bsp(char *real_mode_data) { - u64 ramdisk_image, ramdisk_size, ramdisk_end; - unsigned long initrd_start, initrd_end; - struct boot_params *boot_params; - - boot_params = (struct boot_params *)real_mode_data; - ramdisk_image = boot_params->hdr.ramdisk_image; - ramdisk_size = boot_params->hdr.ramdisk_size; + u64 ramdisk_image, ramdisk_size; #ifdef CONFIG_X86_64 - ramdisk_end = PAGE_ALIGN(ramdisk_image + ramdisk_size); - initrd_start = ramdisk_image + PAGE_OFFSET; - initrd_end = initrd_start + ramdisk_size; + ramdisk_image = boot_params.hdr.ramdisk_image; + ramdisk_size = boot_params.hdr.ramdisk_size; + if (!ramdisk_image || !ramdisk_size) + return; _load_ucode_intel_bsp(&mc_saved_data, mc_saved_in_initrd, - initrd_start, initrd_end); + ramdisk_image, ramdisk_size); #else - ramdisk_end = ramdisk_image + ramdisk_size; - initrd_start = ramdisk_image; - initrd_end = initrd_start + ramdisk_size; + struct boot_params *boot_params = (struct boot_params *)real_mode_data; + + ramdisk_image = boot_params->hdr.ramdisk_image; + ramdisk_size = boot_params->hdr.ramdisk_size; + if (!ramdisk_image || !ramdisk_size) + return; _load_ucode_intel_bsp((struct mc_saved_data *)__pa(&mc_saved_data), - (struct microcode_intel **)__pa(mc_saved_in_initrd), - initrd_start, initrd_end); + (struct microcode_intel **)__pa(mc_saved_in_initrd), + ramdisk_image, ramdisk_size); #endif } Index: linux-2.6/include/linux/earlycpio.h =================================================================== --- linux-2.6.orig/include/linux/earlycpio.h +++ linux-2.6/include/linux/earlycpio.h @@ -11,7 +11,13 @@ struct cpio_data { char name[MAX_CPIO_FILE_NAME]; }; -struct cpio_data find_cpio_data(const char *path, void *data, size_t len, - long *offset); +struct cpio_data find_cpio(const char *path, void *data, size_t len, + long *offset); + +struct cpio_data find_cpio_data_map(const char *path, void *data, size_t len, + long *offset, + void *(*map)(unsigned long, unsigned long), + void (*unmap)(void *, unsigned long), + unsigned long map_size); #endif /* _LINUX_EARLYCPIO_H */ Index: linux-2.6/lib/earlycpio.c =================================================================== --- linux-2.6.orig/lib/earlycpio.c +++ linux-2.6/lib/earlycpio.c @@ -47,6 +47,14 @@ enum cpio_fields { C_NFIELDS }; +static void *map(unsigned long addr, unsigned long size) +{ + return (void *)addr; +} +static void unmap(void *p, unsigned long size) +{ +} + /** * cpio_data find_cpio_data - Search for files in an uncompressed cpio * @path: The directory to search for, including a slash at the end @@ -63,24 +71,40 @@ enum cpio_fields { * the match returned an empty filename string. */ -struct cpio_data __cpuinit find_cpio_data(const char *path, void *data, - size_t len, long *offset) +struct cpio_data __cpuinit find_cpio_data_map(const char *path, void *data, + size_t len, long *offset, + void *(*map)(unsigned long, unsigned long), + void (*unmap)(void *, unsigned long), + unsigned long map_size) { const size_t cpio_header_len = 8*C_NFIELDS - 2; struct cpio_data cd = { NULL, 0, "" }; - const char *p, *dptr, *nptr; + const char *p; unsigned int ch[C_NFIELDS], *chp, v; unsigned char c, x; size_t mypathsize = strlen(path); int i, j; - - p = data; + unsigned long addr, off, limit = map_size; + unsigned long dptr, nptr; + char *p_start; + + addr = (unsigned long)data; + p = p_start = map(addr, map_size); + off = 0; while (len > cpio_header_len) { if (!*p) { /* All cpio headers need to be 4-byte aligned */ - p += 4; + addr += 4; + off += 4; len -= 4; + if (off < limit) + p += 4; + else { + unmap(p_start, map_size); + p = p_start = map(addr, map_size); + off = 0; + } continue; } @@ -90,7 +114,16 @@ struct cpio_data __cpuinit find_cpio_dat v = 0; while (j--) { v <<= 4; - c = *p++; + c = *p; + addr++; + off++; + if (off < limit) + p++; + else { + unmap(p_start, map_size); + p = p_start = map(addr, map_size); + off = 0; + } x = c - '0'; if (x < 10) { @@ -115,31 +148,56 @@ struct cpio_data __cpuinit find_cpio_dat len -= cpio_header_len; - dptr = PTR_ALIGN(p + ch[C_NAMESIZE], 4); - nptr = PTR_ALIGN(dptr + ch[C_FILESIZE], 4); + dptr = ALIGN(addr + ch[C_NAMESIZE], 4); + nptr = ALIGN(dptr + ch[C_FILESIZE], 4); - if (nptr > p + len || dptr < p || nptr < dptr) + if (nptr > addr + len || dptr < addr || nptr < dptr) goto quit; /* Buffer overrun */ if ((ch[C_MODE] & 0170000) == 0100000 && - ch[C_NAMESIZE] >= mypathsize && - !memcmp(p, path, mypathsize)) { - *offset = (long)nptr - (long)data; - if (ch[C_NAMESIZE] - mypathsize >= MAX_CPIO_FILE_NAME) { - pr_warn( - "File %s exceeding MAX_CPIO_FILE_NAME [%d]\n", - p, MAX_CPIO_FILE_NAME); + ch[C_NAMESIZE] >= mypathsize) { + if (off + mypathsize > limit) { + unmap(p_start, map_size); + p = p_start = map(addr, map_size); + off = 0; } - strlcpy(cd.name, p + mypathsize, MAX_CPIO_FILE_NAME); + if(!memcmp(p, path, mypathsize)) { + *offset = (long)nptr - (long)data; + if (ch[C_NAMESIZE] - mypathsize >= MAX_CPIO_FILE_NAME) { + pr_warn( + "File %s exceeding MAX_CPIO_FILE_NAME [%d]\n", + p, MAX_CPIO_FILE_NAME); + } + if (off + mypathsize + MAX_CPIO_FILE_NAME > limit) { + unmap(p_start, map_size); + p = p_start = map(addr, map_size); + off = 0; + } + strlcpy(cd.name, p + mypathsize, MAX_CPIO_FILE_NAME); - cd.data = (void *)dptr; - cd.size = ch[C_FILESIZE]; - return cd; /* Found it! */ + cd.data = (void *)dptr; + cd.size = ch[C_FILESIZE]; + unmap(p_start, map_size); + return cd; /* Found it! */ + } } - len -= (nptr - p); - p = nptr; + len -= (nptr - addr); + if (nptr - addr >= limit) { + addr = nptr; + unmap(p_start, map_size); + p = p_start = map(addr, map_size); + off = 0; + } else + addr = nptr; } quit: + unmap(p_start, map_size); return cd; } + +struct cpio_data __cpuinit find_cpio_data(const char *path, void *data, + size_t len, long *offset) +{ + return find_cpio_data_map(path, data, len, offset, map, unmap, len); +} Index: linux-2.6/arch/x86/kernel/setup.c =================================================================== --- linux-2.6.orig/arch/x86/kernel/setup.c +++ linux-2.6/arch/x86/kernel/setup.c @@ -294,6 +294,14 @@ static void __init reserve_brk(void) #ifdef CONFIG_BLK_DEV_INITRD +#ifdef CONFIG_MICROCODE_INTEL_EARLY +void update_mc_saved_data(unsigned long pa_offset); +#else +static inline void update_mc_saved_data(unsigned long pa_offset) +{ +} +#endif + static u64 __init get_ramdisk_image(void) { u64 ramdisk_image = boot_params.hdr.ramdisk_image; @@ -357,6 +365,8 @@ static void __init relocate_initrd(void) " [mem %#010llx-%#010llx]\n", ramdisk_image, ramdisk_image + ramdisk_size - 1, ramdisk_here, ramdisk_here + ramdisk_size - 1); + + update_mc_saved_data(ramdisk_here - ramdisk_image); } static u64 __init get_mem_size(unsigned long limit_pfn) @@ -414,6 +424,7 @@ static void __init reserve_initrd(void) /* All are mapped, easy case */ initrd_start = ramdisk_image + PAGE_OFFSET; initrd_end = initrd_start + ramdisk_size; + update_mc_saved_data(0); return; }