---
 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 <linux/vmalloc.h>
 #include <linux/mm.h>
 #include <linux/earlycpio.h>
+
 #include <asm/msr.h>
 #include <asm/microcode_intel.h>
 #include <asm/processor.h>
+#include <asm/setup.h>
 
 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;
 	}
 
