fix KVM e820 and initrd

Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
diff --git a/include/bios.h b/include/bios.h
index a187a46..4ed3a1a 100644
--- a/include/bios.h
+++ b/include/bios.h
@@ -42,6 +42,7 @@
 extern bool boot_from_cbfs(void *base, size_t sz);
 
 extern uint16_t e820_seg;
+extern uint32_t lowmem;
 
 #define ARRAY_SIZE(x)	(sizeof(x) / sizeof(x[0]))
 
diff --git a/linuxboot.c b/linuxboot.c
index fc8b7fa..7ce07bc 100644
--- a/linuxboot.c
+++ b/linuxboot.c
@@ -64,6 +64,8 @@
 		initrd_max = ldl_p(header+0x22c);
 	else
 		initrd_max = 0x37ffffff;
+	if (initrd_max > lowmem - 1)
+		initrd_max = lowmem - 1;
 
 	if (protocol >= 0x202)
 		stl_p(header+0x228, cmdline_addr);
diff --git a/main.c b/main.c
index a9984e9..dbfe81a 100644
--- a/main.c
+++ b/main.c
@@ -89,12 +89,16 @@
 	set_realmode_int(0x15, bios_int15);
 }
 
+/* Top of memory below 4GB.  */
+uint32_t lowmem;
+
 static void extract_e820(void)
 {
 	int id = fw_cfg_file_id("etc/e820");
 	uint32_t size;
 	int nr_map;
 	struct e820map *e820;
+	int i;
 
 	if (id == -1)
 		panic();
@@ -114,8 +118,13 @@
 	e820->map[3] = (struct e820entry)
 		{ .addr = 0xf0000, .size = 64 * 1024, .type = E820_RESERVED }; /* firmware */
 	fw_cfg_read(&e820->map[4], size);
-	e820->map[4].addr = 1024 * 1024;
-	e820->map[4].size -= 1024 * 1024;
+	for (i = 4; i < e820->nr_map; i++)
+		if (e820->map[i].addr == 0) {
+			lowmem = e820->map[i].size;
+			e820->map[i].addr = 1024 * 1024;
+			e820->map[i].size -= 1024 * 1024;
+			break;
+		}
 
 	e820_seg = ((uintptr_t) e820) >> 4;
 }