aboutsummaryrefslogtreecommitdiff
path: root/hw/pc.c
diff options
context:
space:
mode:
authorpbrook <pbrook@c046a42c-6fe2-441c-8c8c-71466251a162>2007-03-31 19:41:22 +0000
committerpbrook <pbrook@c046a42c-6fe2-441c-8c8c-71466251a162>2007-03-31 19:41:22 +0000
commita80274c31bd94f7a345934d2544075a6d183ebac (patch)
tree16c01fc70c4193f6398e210ff38e161008b3ef36 /hw/pc.c
parent0aeaa8ce4f441fec211794e4380b1eb0948ac9c1 (diff)
Large kernel initrd fix (initial patch by Daniel Jacobowitz).
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2562 c046a42c-6fe2-441c-8c8c-71466251a162
Diffstat (limited to 'hw/pc.c')
-rw-r--r--hw/pc.c29
1 files changed, 26 insertions, 3 deletions
diff --git a/hw/pc.c b/hw/pc.c
index ba9c2d9473..7a156eb9f1 100644
--- a/hw/pc.c
+++ b/hw/pc.c
@@ -32,9 +32,11 @@
#define LINUX_BOOT_FILENAME "linux_boot.bin"
#define KERNEL_LOAD_ADDR 0x00100000
-#define INITRD_LOAD_ADDR 0x00600000
+#define MAX_INITRD_LOAD_ADDR 0x38000000
#define KERNEL_PARAMS_ADDR 0x00090000
#define KERNEL_CMDLINE_ADDR 0x00099000
+/* Leave a chunk of memory at the top of RAM for the BIOS ACPI tables. */
+#define ACPI_DATA_SIZE 0x10000
static fdctrl_t *floppy_controller;
static RTCState *rtc_state;
@@ -452,6 +454,7 @@ static void pc_init1(int ram_size, int vga_ram_size, int boot_device,
char buf[1024];
int ret, linux_boot, initrd_size, i;
ram_addr_t ram_addr, vga_ram_addr, bios_offset, vga_bios_offset;
+ ram_addr_t initrd_offset;
int bios_size, isa_bios_size, vga_bios_size;
PCIBus *pci_bus;
int piix3_devfn = -1;
@@ -599,8 +602,28 @@ static void pc_init1(int ram_size, int vga_ram_size, int boot_device,
/* load initrd */
initrd_size = 0;
+ initrd_offset = 0;
if (initrd_filename) {
- initrd_size = load_image(initrd_filename, phys_ram_base + INITRD_LOAD_ADDR);
+ initrd_size = get_image_size (initrd_filename);
+ if (initrd_size > 0) {
+ initrd_offset = (ram_size - initrd_size) & TARGET_PAGE_MASK;
+ /* Leave space for BIOS ACPI tables. */
+ initrd_offset -= ACPI_DATA_SIZE;
+ /* Avoid the last 64k to avoid 2.2.x kernel bugs. */
+ initrd_offset -= 0x10000;
+ if (initrd_offset > MAX_INITRD_LOAD_ADDR)
+ initrd_offset = MAX_INITRD_LOAD_ADDR;
+
+ if (initrd_size > ram_size
+ || initrd_offset < KERNEL_LOAD_ADDR + ret) {
+ fprintf(stderr,
+ "qemu: memory too small for initial ram disk '%s'\n",
+ initrd_filename);
+ exit(1);
+ }
+ initrd_size = load_image(initrd_filename,
+ phys_ram_base + initrd_offset);
+ }
if (initrd_size < 0) {
fprintf(stderr, "qemu: could not load initial ram disk '%s'\n",
initrd_filename);
@@ -608,7 +631,7 @@ static void pc_init1(int ram_size, int vga_ram_size, int boot_device,
}
}
if (initrd_size > 0) {
- stl_raw(phys_ram_base + KERNEL_PARAMS_ADDR + 0x218, INITRD_LOAD_ADDR);
+ stl_raw(phys_ram_base + KERNEL_PARAMS_ADDR + 0x218, initrd_offset);
stl_raw(phys_ram_base + KERNEL_PARAMS_ADDR + 0x21c, initrd_size);
}
pstrcpy(phys_ram_base + KERNEL_CMDLINE_ADDR, 4096,