Commit a80274c31bd94f7a345934d2544075a6d183ebac
1 parent
0aeaa8ce
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
Showing
1 changed file
with
26 additions
and
3 deletions
hw/pc.c
| ... | ... | @@ -32,9 +32,11 @@ |
| 32 | 32 | #define LINUX_BOOT_FILENAME "linux_boot.bin" |
| 33 | 33 | |
| 34 | 34 | #define KERNEL_LOAD_ADDR 0x00100000 |
| 35 | -#define INITRD_LOAD_ADDR 0x00600000 | |
| 35 | +#define MAX_INITRD_LOAD_ADDR 0x38000000 | |
| 36 | 36 | #define KERNEL_PARAMS_ADDR 0x00090000 |
| 37 | 37 | #define KERNEL_CMDLINE_ADDR 0x00099000 |
| 38 | +/* Leave a chunk of memory at the top of RAM for the BIOS ACPI tables. */ | |
| 39 | +#define ACPI_DATA_SIZE 0x10000 | |
| 38 | 40 | |
| 39 | 41 | static fdctrl_t *floppy_controller; |
| 40 | 42 | static RTCState *rtc_state; |
| ... | ... | @@ -452,6 +454,7 @@ static void pc_init1(int ram_size, int vga_ram_size, int boot_device, |
| 452 | 454 | char buf[1024]; |
| 453 | 455 | int ret, linux_boot, initrd_size, i; |
| 454 | 456 | ram_addr_t ram_addr, vga_ram_addr, bios_offset, vga_bios_offset; |
| 457 | + ram_addr_t initrd_offset; | |
| 455 | 458 | int bios_size, isa_bios_size, vga_bios_size; |
| 456 | 459 | PCIBus *pci_bus; |
| 457 | 460 | int piix3_devfn = -1; |
| ... | ... | @@ -599,8 +602,28 @@ static void pc_init1(int ram_size, int vga_ram_size, int boot_device, |
| 599 | 602 | |
| 600 | 603 | /* load initrd */ |
| 601 | 604 | initrd_size = 0; |
| 605 | + initrd_offset = 0; | |
| 602 | 606 | if (initrd_filename) { |
| 603 | - initrd_size = load_image(initrd_filename, phys_ram_base + INITRD_LOAD_ADDR); | |
| 607 | + initrd_size = get_image_size (initrd_filename); | |
| 608 | + if (initrd_size > 0) { | |
| 609 | + initrd_offset = (ram_size - initrd_size) & TARGET_PAGE_MASK; | |
| 610 | + /* Leave space for BIOS ACPI tables. */ | |
| 611 | + initrd_offset -= ACPI_DATA_SIZE; | |
| 612 | + /* Avoid the last 64k to avoid 2.2.x kernel bugs. */ | |
| 613 | + initrd_offset -= 0x10000; | |
| 614 | + if (initrd_offset > MAX_INITRD_LOAD_ADDR) | |
| 615 | + initrd_offset = MAX_INITRD_LOAD_ADDR; | |
| 616 | + | |
| 617 | + if (initrd_size > ram_size | |
| 618 | + || initrd_offset < KERNEL_LOAD_ADDR + ret) { | |
| 619 | + fprintf(stderr, | |
| 620 | + "qemu: memory too small for initial ram disk '%s'\n", | |
| 621 | + initrd_filename); | |
| 622 | + exit(1); | |
| 623 | + } | |
| 624 | + initrd_size = load_image(initrd_filename, | |
| 625 | + phys_ram_base + initrd_offset); | |
| 626 | + } | |
| 604 | 627 | if (initrd_size < 0) { |
| 605 | 628 | fprintf(stderr, "qemu: could not load initial ram disk '%s'\n", |
| 606 | 629 | initrd_filename); |
| ... | ... | @@ -608,7 +631,7 @@ static void pc_init1(int ram_size, int vga_ram_size, int boot_device, |
| 608 | 631 | } |
| 609 | 632 | } |
| 610 | 633 | if (initrd_size > 0) { |
| 611 | - stl_raw(phys_ram_base + KERNEL_PARAMS_ADDR + 0x218, INITRD_LOAD_ADDR); | |
| 634 | + stl_raw(phys_ram_base + KERNEL_PARAMS_ADDR + 0x218, initrd_offset); | |
| 612 | 635 | stl_raw(phys_ram_base + KERNEL_PARAMS_ADDR + 0x21c, initrd_size); |
| 613 | 636 | } |
| 614 | 637 | pstrcpy(phys_ram_base + KERNEL_CMDLINE_ADDR, 4096, | ... | ... |