From 74287114c98ecb969b7ce4b5c959da8a8a431d0f Mon Sep 17 00:00:00 2001 From: ths Date: Sun, 1 Apr 2007 17:56:37 +0000 Subject: Improved initrd support for mips. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2574 c046a42c-6fe2-441c-8c8c-71466251a162 --- hw/arm_boot.c | 2 +- hw/mips_malta.c | 47 +++++++++++++++++++++++++++++++---------------- hw/mips_r4k.c | 27 ++++++++++++++++++++------- hw/sun4m.c | 4 ++-- hw/sun4u.c | 4 ++-- 5 files changed, 56 insertions(+), 28 deletions(-) (limited to 'hw') diff --git a/hw/arm_boot.c b/hw/arm_boot.c index dfc00db28a..095b0bb79f 100644 --- a/hw/arm_boot.c +++ b/hw/arm_boot.c @@ -101,7 +101,7 @@ void arm_load_kernel(CPUState *env, int ram_size, const char *kernel_filename, qemu_register_reset(main_cpu_reset, env); } /* Assume that raw images are linux kernels, and ELF images are not. */ - kernel_size = load_elf(kernel_filename, 0, &elf_entry); + kernel_size = load_elf(kernel_filename, 0, &elf_entry, NULL, NULL); entry = elf_entry; if (kernel_size < 0) { kernel_size = load_uboot(kernel_filename, &entry, &is_linux); diff --git a/hw/mips_malta.c b/hw/mips_malta.c index e4b43bea99..0ba3359ef4 100644 --- a/hw/mips_malta.c +++ b/hw/mips_malta.c @@ -31,13 +31,13 @@ #endif #ifdef TARGET_MIPS64 -#define INITRD_LOAD_ADDR (int64_t)0x80800000 +#define PHYS_TO_VIRT(x) ((x) | ~0x7fffffffULL) #else -#define INITRD_LOAD_ADDR (int32_t)0x80800000 +#define PHYS_TO_VIRT(x) ((x) | ~0x7fffffffU) #endif -#define ENVP_ADDR (int32_t)0x80002000 -#define VIRT_TO_PHYS_ADDEND (-((int64_t)(int32_t)0x80000000)) +#define ENVP_ADDR (int32_t)0x80002000 +#define VIRT_TO_PHYS_ADDEND (-((int64_t)(int32_t)0x80000000)) #define ENVP_NB_ENTRIES 16 #define ENVP_ENTRY_SIZE 256 @@ -536,7 +536,7 @@ static void network_init (PCIBus *pci_bus) a3 - RAM size in bytes */ -static void write_bootloader (CPUState *env, unsigned long bios_offset, int64_t kernel_addr) +static void write_bootloader (CPUState *env, unsigned long bios_offset, int64_t kernel_entry) { uint32_t *p; @@ -555,8 +555,8 @@ static void write_bootloader (CPUState *env, unsigned long bios_offset, int64_t stl_raw(p++, 0x34c60000 | ((ENVP_ADDR + 8) & 0xffff)); /* ori a2, a2, low(ENVP_ADDR + 8) */ stl_raw(p++, 0x3c070000 | (env->ram_size >> 16)); /* lui a3, high(env->ram_size) */ stl_raw(p++, 0x34e70000 | (env->ram_size & 0xffff)); /* ori a3, a3, low(env->ram_size) */ - stl_raw(p++, 0x3c1f0000 | ((kernel_addr >> 16) & 0xffff)); /* lui ra, high(kernel_addr) */; - stl_raw(p++, 0x37ff0000 | (kernel_addr & 0xffff)); /* ori ra, ra, low(kernel_addr) */ + stl_raw(p++, 0x3c1f0000 | ((kernel_entry >> 16) & 0xffff)); /* lui ra, high(kernel_entry) */ + stl_raw(p++, 0x37ff0000 | (kernel_entry & 0xffff)); /* ori ra, ra, low(kernel_entry) */ stl_raw(p++, 0x03e00008); /* jr ra */ stl_raw(p++, 0x00000000); /* nop */ } @@ -592,11 +592,13 @@ static void prom_set(int index, const char *string, ...) /* Kernel */ static int64_t load_kernel (CPUState *env) { - int64_t kernel_addr = 0; + int64_t kernel_entry, kernel_low, kernel_high; int index = 0; long initrd_size; + ram_addr_t initrd_offset; - if (load_elf(env->kernel_filename, VIRT_TO_PHYS_ADDEND, &kernel_addr) < 0) { + if (load_elf(env->kernel_filename, VIRT_TO_PHYS_ADDEND, + &kernel_entry, &kernel_low, &kernel_high) < 0) { fprintf(stderr, "qemu: could not load kernel '%s'\n", env->kernel_filename); exit(1); @@ -604,9 +606,20 @@ static int64_t load_kernel (CPUState *env) /* load initrd */ initrd_size = 0; + initrd_offset = 0; if (env->initrd_filename) { - initrd_size = load_image(env->initrd_filename, - phys_ram_base + INITRD_LOAD_ADDR + VIRT_TO_PHYS_ADDEND); + initrd_size = get_image_size (env->initrd_filename); + if (initrd_size > 0) { + initrd_offset = (kernel_high + ~TARGET_PAGE_MASK) & TARGET_PAGE_MASK; + if (initrd_offset + initrd_size > env->ram_size) { + fprintf(stderr, + "qemu: memory too small for initial ram disk '%s'\n", + env->initrd_filename); + exit(1); + } + initrd_size = load_image(env->initrd_filename, + phys_ram_base + initrd_offset); + } if (initrd_size == (target_ulong) -1) { fprintf(stderr, "qemu: could not load initial ram disk '%s'\n", env->initrd_filename); @@ -617,7 +630,9 @@ static int64_t load_kernel (CPUState *env) /* Store command line. */ prom_set(index++, env->kernel_filename); if (initrd_size > 0) - prom_set(index++, "rd_start=0x" TARGET_FMT_lx " rd_size=%li %s", INITRD_LOAD_ADDR, initrd_size, env->kernel_cmdline); + prom_set(index++, "rd_start=0x" TARGET_FMT_lx " rd_size=%li %s", + PHYS_TO_VIRT(initrd_offset), initrd_size, + env->kernel_cmdline); else prom_set(index++, env->kernel_cmdline); @@ -628,7 +643,7 @@ static int64_t load_kernel (CPUState *env) prom_set(index++, "38400n8r"); prom_set(index++, NULL); - return kernel_addr; + return kernel_entry; } static void main_cpu_reset(void *opaque) @@ -651,7 +666,7 @@ void mips_malta_init (int ram_size, int vga_ram_size, int boot_device, { char buf[1024]; unsigned long bios_offset; - int64_t kernel_addr; + int64_t kernel_entry; PCIBus *pci_bus; CPUState *env; RTCState *rtc_state; @@ -693,8 +708,8 @@ void mips_malta_init (int ram_size, int vga_ram_size, int boot_device, env->kernel_filename = kernel_filename; env->kernel_cmdline = kernel_cmdline; env->initrd_filename = initrd_filename; - kernel_addr = load_kernel(env); - write_bootloader(env, bios_offset, kernel_addr); + kernel_entry = load_kernel(env); + write_bootloader(env, bios_offset, kernel_entry); } else { snprintf(buf, sizeof(buf), "%s/%s", bios_dir, BIOS_FILENAME); ret = load_image(buf, phys_ram_base + bios_offset); diff --git a/hw/mips_r4k.c b/hw/mips_r4k.c index 487983e462..8fbddf3c34 100644 --- a/hw/mips_r4k.c +++ b/hw/mips_r4k.c @@ -16,9 +16,9 @@ #endif #ifdef TARGET_MIPS64 -#define INITRD_LOAD_ADDR (int64_t)(int32_t)0x80800000 +#define PHYS_TO_VIRT(x) ((x) | ~0x7fffffffULL) #else -#define INITRD_LOAD_ADDR (int32_t)0x80800000 +#define PHYS_TO_VIRT(x) ((x) | ~0x7fffffffU) #endif #define VIRT_TO_PHYS_ADDEND (-((int64_t)(int32_t)0x80000000)) @@ -73,10 +73,12 @@ void load_kernel (CPUState *env, int ram_size, const char *kernel_filename, const char *kernel_cmdline, const char *initrd_filename) { - int64_t entry = 0; + int64_t entry, kernel_low, kernel_high; long kernel_size, initrd_size; + ram_addr_t initrd_offset; - kernel_size = load_elf(kernel_filename, VIRT_TO_PHYS_ADDEND, &entry); + kernel_size = load_elf(kernel_filename, VIRT_TO_PHYS_ADDEND, + &entry, &kernel_low, &kernel_high); if (kernel_size >= 0) { if ((entry & ~0x7fffffffULL) == 0x80000000) entry = (int32_t)entry; @@ -89,9 +91,20 @@ void load_kernel (CPUState *env, int ram_size, const char *kernel_filename, /* load initrd */ initrd_size = 0; + initrd_offset = 0; if (initrd_filename) { - initrd_size = load_image(initrd_filename, - phys_ram_base + INITRD_LOAD_ADDR + VIRT_TO_PHYS_ADDEND); + initrd_size = get_image_size (initrd_filename); + if (initrd_size > 0) { + initrd_offset = (kernel_high + ~TARGET_PAGE_MASK) & TARGET_PAGE_MASK; + if (initrd_offset + initrd_size > ram_size) { + 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 == (target_ulong) -1) { fprintf(stderr, "qemu: could not load initial ram disk '%s'\n", initrd_filename); @@ -104,7 +117,7 @@ void load_kernel (CPUState *env, int ram_size, const char *kernel_filename, int ret; ret = sprintf(phys_ram_base + (16 << 20) - 256, "rd_start=0x" TARGET_FMT_lx " rd_size=%li ", - INITRD_LOAD_ADDR, + PHYS_TO_VIRT((uint32_t)initrd_offset), initrd_size); strcpy (phys_ram_base + (16 << 20) - 256 + ret, kernel_cmdline); } diff --git a/hw/sun4m.c b/hw/sun4m.c index a23baee173..ee34c1b5bc 100644 --- a/hw/sun4m.c +++ b/hw/sun4m.c @@ -295,7 +295,7 @@ static void sun4m_load_kernel(long vram_size, int ram_size, int boot_device, prom_offset | IO_MEM_ROM); snprintf(buf, sizeof(buf), "%s/%s", bios_dir, PROM_FILENAME); - ret = load_elf(buf, 0, NULL); + ret = load_elf(buf, 0, NULL, NULL, NULL); if (ret < 0) { fprintf(stderr, "qemu: could not load prom '%s'\n", buf); @@ -304,7 +304,7 @@ static void sun4m_load_kernel(long vram_size, int ram_size, int boot_device, kernel_size = 0; if (linux_boot) { - kernel_size = load_elf(kernel_filename, -0xf0000000, NULL); + kernel_size = load_elf(kernel_filename, -0xf0000000, NULL, NULL, NULL); if (kernel_size < 0) kernel_size = load_aout(kernel_filename, phys_ram_base + KERNEL_LOAD_ADDR); if (kernel_size < 0) diff --git a/hw/sun4u.c b/hw/sun4u.c index 906695690f..e536c48ea2 100644 --- a/hw/sun4u.c +++ b/hw/sun4u.c @@ -292,7 +292,7 @@ static void sun4u_init(int ram_size, int vga_ram_size, int boot_device, prom_offset | IO_MEM_ROM); snprintf(buf, sizeof(buf), "%s/%s", bios_dir, PROM_FILENAME); - ret = load_elf(buf, 0, NULL); + ret = load_elf(buf, 0, NULL, NULL, NULL); if (ret < 0) { fprintf(stderr, "qemu: could not load prom '%s'\n", buf); @@ -303,7 +303,7 @@ static void sun4u_init(int ram_size, int vga_ram_size, int boot_device, initrd_size = 0; if (linux_boot) { /* XXX: put correct offset */ - kernel_size = load_elf(kernel_filename, 0, NULL); + kernel_size = load_elf(kernel_filename, 0, NULL, NULL, NULL); if (kernel_size < 0) kernel_size = load_aout(kernel_filename, phys_ram_base + KERNEL_LOAD_ADDR); if (kernel_size < 0) -- cgit v1.2.3