Index: qemu/hw/pc.c
===================================================================
--- qemu.orig/hw/pc.c	2008-04-29 16:07:32.000000000 +0000
+++ qemu/hw/pc.c	2008-05-01 19:27:25.000000000 +0000
@@ -479,7 +479,7 @@
     int setup_size, kernel_size, initrd_size, cmdline_size;
     uint32_t initrd_max;
     uint8_t header[1024];
-    uint8_t *real_addr, *prot_addr, *cmdline_addr, *initrd_addr;
+    target_phys_addr_t real_addr, prot_addr, cmdline_addr, initrd_addr;
     FILE *f, *fi;
 
     /* Align to 16 bytes as a paranoia measure */
@@ -505,19 +505,19 @@
 
     if (protocol < 0x200 || !(header[0x211] & 0x01)) {
 	/* Low kernel */
-	real_addr    = phys_ram_base + 0x90000;
-	cmdline_addr = phys_ram_base + 0x9a000 - cmdline_size;
-	prot_addr    = phys_ram_base + 0x10000;
+	real_addr    = 0x90000;
+	cmdline_addr = 0x9a000 - cmdline_size;
+	prot_addr    = 0x10000;
     } else if (protocol < 0x202) {
 	/* High but ancient kernel */
-	real_addr    = phys_ram_base + 0x90000;
-	cmdline_addr = phys_ram_base + 0x9a000 - cmdline_size;
-	prot_addr    = phys_ram_base + 0x100000;
+	real_addr    = 0x90000;
+	cmdline_addr = 0x9a000 - cmdline_size;
+	prot_addr    = 0x100000;
     } else {
 	/* High and recent kernel */
-	real_addr    = phys_ram_base + 0x10000;
-	cmdline_addr = phys_ram_base + 0x20000;
-	prot_addr    = phys_ram_base + 0x100000;
+	real_addr    = 0x10000;
+	cmdline_addr = 0x20000;
+	prot_addr    = 0x100000;
     }
 
 #if 0
@@ -525,9 +525,9 @@
 	    "qemu: real_addr     = %#zx\n"
 	    "qemu: cmdline_addr  = %#zx\n"
 	    "qemu: prot_addr     = %#zx\n",
-	    real_addr-phys_ram_base,
-	    cmdline_addr-phys_ram_base,
-	    prot_addr-phys_ram_base);
+	    real_addr,
+	    cmdline_addr,
+	    prot_addr);
 #endif
 
     /* highest address for loading the initrd */
@@ -540,10 +540,10 @@
 	initrd_max = ram_size-ACPI_DATA_SIZE-1;
 
     /* kernel command line */
-    pstrcpy((char*)cmdline_addr, 4096, kernel_cmdline);
+    pstrcpy_targphys(cmdline_addr, 4096, kernel_cmdline);
 
     if (protocol >= 0x202) {
-	stl_p(header+0x228, cmdline_addr-phys_ram_base);
+	stl_p(header+0x228, cmdline_addr);
     } else {
 	stw_p(header+0x20, 0xA33F);
 	stw_p(header+0x22, cmdline_addr-real_addr);
@@ -577,24 +577,24 @@
 	}
 
 	initrd_size = get_file_size(fi);
-	initrd_addr = phys_ram_base + ((initrd_max-initrd_size) & ~4095);
+	initrd_addr = ((initrd_max-initrd_size) & ~4095);
 
 	fprintf(stderr, "qemu: loading initrd (%#x bytes) at %#zx\n",
-		initrd_size, initrd_addr-phys_ram_base);
+		initrd_size, initrd_addr);
 
-	if (fread(initrd_addr, 1, initrd_size, fi) != initrd_size) {
+	if (!fread_targphys_ok(initrd_addr, initrd_size, fi)) {
 	    fprintf(stderr, "qemu: read error on initial ram disk '%s'\n",
 		    initrd_filename);
 	    exit(1);
 	}
 	fclose(fi);
 
-	stl_p(header+0x218, initrd_addr-phys_ram_base);
+	stl_p(header+0x218, initrd_addr);
 	stl_p(header+0x21c, initrd_size);
     }
 
     /* store the finalized header and load the rest of the kernel */
-    memcpy(real_addr, header, 1024);
+    cpu_physical_memory_write(real_addr, header, 1024);
 
     setup_size = header[0x1f1];
     if (setup_size == 0)
@@ -603,8 +603,8 @@
     setup_size = (setup_size+1)*512;
     kernel_size -= setup_size;	/* Size of protected-mode code */
 
-    if (fread(real_addr+1024, 1, setup_size-1024, f) != setup_size-1024 ||
-	fread(prot_addr, 1, kernel_size, f) != kernel_size) {
+    if (!fread_targphys_ok(real_addr+1024, setup_size-1024, f) ||
+	!fread_targphys_ok(prot_addr, kernel_size, f)) {
 	fprintf(stderr, "qemu: read error on kernel '%s'\n",
 		kernel_filename);
 	exit(1);
@@ -612,7 +612,7 @@
     fclose(f);
 
     /* generate bootsector to set up the initial register state */
-    real_seg = (real_addr-phys_ram_base) >> 4;
+    real_seg = real_addr >> 4;
     seg[0] = seg[2] = seg[3] = seg[4] = seg[4] = real_seg;
     seg[1] = real_seg+0x20;	/* CS */
     memset(gpr, 0, sizeof gpr);
@@ -768,7 +768,7 @@
         goto bios_error;
     }
     bios_offset = qemu_ram_alloc(bios_size);
-    ret = load_image(buf, phys_ram_base + bios_offset);
+    ret = load_image_targphys(buf, bios_offset, bios_size);
     if (ret != bios_size) {
     bios_error:
         fprintf(stderr, "qemu: could not load PC BIOS '%s'\n", buf);
@@ -786,7 +786,7 @@
         goto vga_bios_error;
     vga_bios_offset = qemu_ram_alloc(65536);
 
-    ret = load_image(buf, phys_ram_base + vga_bios_offset);
+    ret = load_image_targphys(buf, vga_bios_offset, vga_bios_size);
     if (ret != vga_bios_size) {
     vga_bios_error:
         fprintf(stderr, "qemu: could not load VGA BIOS '%s'\n", buf);
@@ -822,7 +822,7 @@
             if (size > (0x10000 - offset))
                 goto option_rom_error;
             option_rom_offset = qemu_ram_alloc(size);
-            ret = load_image(option_rom[i], phys_ram_base + option_rom_offset);
+            ret = load_image_targphys(option_rom[i], option_rom_offset, size);
             if (ret != size) {
             option_rom_error:
                 fprintf(stderr, "Too many option ROMS\n");
Index: qemu/loader.c
===================================================================
--- qemu.orig/loader.c	2008-03-30 18:07:18.000000000 +0000
+++ qemu/loader.c	2008-05-02 14:03:45.000000000 +0000
@@ -39,6 +39,7 @@
 }
 
 /* return the size or -1 if error */
+/* deprecated, because caller does not specify buffer size! */
 int load_image(const char *filename, uint8_t *addr)
 {
     int fd, size;
@@ -55,6 +56,83 @@
     return size;
 }
 
+/* return the amount read, just like fread.  0 may mean error or eof */
+int fread_targphys(target_phys_addr_t dst_addr, size_t nbytes, FILE *f)
+{
+    unsigned char buf[4096];
+    target_phys_addr_t dst_begin = dst_addr;
+    size_t want, did;
+
+    while (nbytes) {
+	want = nbytes > sizeof(buf) ? sizeof(buf) : nbytes;
+	did = fread(buf, 1, want, f);
+	if (did != want) break;
+
+	cpu_physical_memory_write_rom(dst_addr, buf, did);
+	dst_addr += did;
+	nbytes -= did;
+    }
+    return dst_addr - dst_begin;
+}
+
+/* returns 0 on error, 1 if ok */
+int fread_targphys_ok(target_phys_addr_t dst_addr, size_t nbytes, FILE *f)
+{
+    return fread_targphys(dst_addr, nbytes, f) == nbytes;
+}
+
+/* read()-like version */
+int read_targphys(int fd, target_phys_addr_t dst_addr, size_t nbytes)
+{
+    unsigned char buf[4096];
+    target_phys_addr_t dst_begin = dst_addr;
+    size_t want, did;
+
+    while (nbytes) {
+	want = nbytes > sizeof(buf) ? sizeof(buf) : nbytes;
+	did = read(fd, buf, want);
+	if (did != want) break;
+
+	cpu_physical_memory_write_rom(dst_addr, buf, did);
+	dst_addr += did;
+	nbytes -= did;
+    }
+    return dst_addr - dst_begin;
+}
+
+/* return the size or -1 if error */
+int load_image_targphys(const char *filename,
+			target_phys_addr_t addr, int max_sz)
+{
+    FILE *f;
+    size_t got;
+
+    f = fopen(filename, "rb");
+    if (!f) return -1;
+
+    got = fread_targphys(addr, max_sz, f);
+    if (ferror(f)) { fclose(f); return -1; }
+    fclose(f);
+
+    return got;
+}
+
+void pstrcpy_targphys(target_phys_addr_t dest, int buf_size,
+                      const char *source)
+{
+    static const char nul_byte;
+    const char *nulp;
+
+    if (buf_size <= 0) return;
+    nulp = memchr(source, 0, buf_size);
+    if (nulp) {
+	cpu_physical_memory_write_rom(dest, source, (nulp - source) + 1);
+    } else {
+	cpu_physical_memory_write_rom(dest, source, buf_size - 1);
+	cpu_physical_memory_write_rom(dest, &nul_byte, 1);
+    }
+}
+
 /* A.OUT loader */
 
 struct exec
@@ -105,7 +183,7 @@
      : (_N_SEGMENT_ROUND (_N_TXTENDADDR(x))))
 
 
-int load_aout(const char *filename, uint8_t *addr)
+int load_aout(const char *filename, target_phys_addr_t addr, int max_sz)
 {
     int fd, size, ret;
     struct exec e;
@@ -126,17 +204,21 @@
     case ZMAGIC:
     case QMAGIC:
     case OMAGIC:
+        if (e.a_text + e.a_data > max_sz)
+            goto fail;
 	lseek(fd, N_TXTOFF(e), SEEK_SET);
-	size = read(fd, addr, e.a_text + e.a_data);
+	size = read_targphys(fd, addr, e.a_text + e.a_data);
 	if (size < 0)
 	    goto fail;
 	break;
     case NMAGIC:
+        if (N_DATADDR(e) + e.a_data > max_sz)
+            goto fail;
 	lseek(fd, N_TXTOFF(e), SEEK_SET);
-	size = read(fd, addr, e.a_text);
+	size = read_targphys(fd, addr, e.a_text);
 	if (size < 0)
 	    goto fail;
-	ret = read(fd, addr + N_DATADDR(e), e.a_data);
+	ret = read_targphys(fd, addr + N_DATADDR(e), e.a_data);
 	if (ret < 0)
 	    goto fail;
 	size += ret;
Index: qemu/sysemu.h
===================================================================
--- qemu.orig/sysemu.h	2008-04-29 16:07:34.000000000 +0000
+++ qemu/sysemu.h	2008-05-01 19:40:09.000000000 +0000
@@ -151,11 +151,17 @@
 #ifdef NEED_CPU_H
 /* loader.c */
 int get_image_size(const char *filename);
-int load_image(const char *filename, uint8_t *addr);
+int load_image(const char *filename, uint8_t *addr); /* deprecated */
+int load_image_targphys(const char *filename, target_phys_addr_t, int max_sz);
 int load_elf(const char *filename, int64_t virt_to_phys_addend,
              uint64_t *pentry, uint64_t *lowaddr, uint64_t *highaddr);
-int load_aout(const char *filename, uint8_t *addr);
+int load_aout(const char *filename, target_phys_addr_t addr, int max_sz);
 int load_uboot(const char *filename, target_ulong *ep, int *is_linux);
+
+int fread_targphys(target_phys_addr_t dst_addr, size_t nbytes, FILE *f);
+int fread_targphys_ok(target_phys_addr_t dst_addr, size_t nbytes, FILE *f);
+void pstrcpy_targphys(target_phys_addr_t dest, int buf_size,
+                      const char *source);
 #endif
 
 #ifdef HAS_AUDIO
Index: qemu/hw/sun4m.c
===================================================================
--- qemu.orig/hw/sun4m.c	2008-05-01 19:29:33.000000000 +0000
+++ qemu/hw/sun4m.c	2008-05-02 14:45:38.000000000 +0000
@@ -186,7 +186,7 @@
     header->kernel_image = cpu_to_be64((uint64_t)KERNEL_LOAD_ADDR);
     header->kernel_size = cpu_to_be64((uint64_t)kernel_size);
     if (cmdline) {
-        strcpy(phys_ram_base + CMDLINE_ADDR, cmdline);
+        pstrcpy_targphys(CMDLINE_ADDR, TARGET_PAGE_SIZE, cmdline);
         header->cmdline = cpu_to_be64((uint64_t)CMDLINE_ADDR);
         header->cmdline_size = cpu_to_be64((uint64_t)strlen(cmdline));
     }
@@ -320,7 +320,8 @@
 
 static unsigned long sun4m_load_kernel(const char *kernel_filename,
                                        const char *kernel_cmdline,
-                                       const char *initrd_filename)
+                                       const char *initrd_filename,
+                                       ram_addr_t ram_size)
 {
     int linux_boot;
     unsigned int i;
@@ -333,9 +334,11 @@
         kernel_size = load_elf(kernel_filename, -0xf0000000ULL, NULL, NULL,
                                NULL);
         if (kernel_size < 0)
-            kernel_size = load_aout(kernel_filename, phys_ram_base + KERNEL_LOAD_ADDR);
+            kernel_size = load_aout(kernel_filename, KERNEL_LOAD_ADDR,
+                                    ram_size - KERNEL_LOAD_ADDR);
         if (kernel_size < 0)
-            kernel_size = load_image(kernel_filename, phys_ram_base + KERNEL_LOAD_ADDR);
+            kernel_size = load_image_targphys(kernel_filename, KERNEL_LOAD_ADDR,
+                                    ram_size - KERNEL_LOAD_ADDR);
         if (kernel_size < 0) {
             fprintf(stderr, "qemu: could not load kernel '%s'\n",
                     kernel_filename);
@@ -345,7 +348,9 @@
         /* load initrd */
         initrd_size = 0;
         if (initrd_filename) {
-            initrd_size = load_image(initrd_filename, phys_ram_base + INITRD_LOAD_ADDR);
+            initrd_size = load_image_targphys(initrd_filename, INITRD_LOAD_ADDR,
+                                    ram_size - INITRD_LOAD_ADDR);
+
             if (initrd_size < 0) {
                 fprintf(stderr, "qemu: could not load initial ram disk '%s'\n",
                         initrd_filename);
@@ -354,10 +359,9 @@
         }
         if (initrd_size > 0) {
             for (i = 0; i < 64 * TARGET_PAGE_SIZE; i += TARGET_PAGE_SIZE) {
-                if (ldl_raw(phys_ram_base + KERNEL_LOAD_ADDR + i)
-                    == 0x48647253) { // HdrS
-                    stl_raw(phys_ram_base + KERNEL_LOAD_ADDR + i + 16, INITRD_LOAD_ADDR);
-                    stl_raw(phys_ram_base + KERNEL_LOAD_ADDR + i + 20, initrd_size);
+                if (ldl_phys(KERNEL_LOAD_ADDR + i) == 0x48647253) { // HdrS
+                    stl_phys(KERNEL_LOAD_ADDR + i + 16, INITRD_LOAD_ADDR);
+                    stl_phys(KERNEL_LOAD_ADDR + i + 20, initrd_size);
                     break;
                 }
             }
@@ -434,7 +438,7 @@
     snprintf(buf, sizeof(buf), "%s/%s", bios_dir, bios_name);
     ret = load_elf(buf, hwdef->slavio_base - PROM_VADDR, NULL, NULL, NULL);
     if (ret < 0 || ret > PROM_SIZE_MAX)
-        ret = load_image(buf, phys_ram_base + prom_offset);
+        ret = load_image_targphys(buf, prom_offset, PROM_SIZE_MAX);
     if (ret < 0 || ret > PROM_SIZE_MAX) {
         fprintf(stderr, "qemu: could not load prom '%s'\n",
                 buf);
@@ -451,10 +455,12 @@
                                        hwdef->clock_irq);
 
     if (hwdef->idreg_base != (target_phys_addr_t)-1) {
-        stl_raw(phys_ram_base + prom_offset, 0xfe810103);
+        static const uint32_t idreg_data = 0xfe810103;
 
         cpu_register_physical_memory(hwdef->idreg_base, sizeof(uint32_t),
                                      prom_offset | IO_MEM_ROM);
+        cpu_physical_memory_write_rom(hwdef->idreg_base, (char *)&idreg_data,
+                                      sizeof(uint32_t));
     }
 
     iommu = iommu_init(hwdef->iommu_base, hwdef->iommu_version,
@@ -534,7 +540,7 @@
         cs_init(hwdef->cs_base, hwdef->cs_irq, slavio_intctl);
 
     kernel_size = sun4m_load_kernel(kernel_filename, kernel_cmdline,
-                                    initrd_filename);
+                                    initrd_filename, RAM_size);
 
     nvram_init(nvram, (uint8_t *)&nd_table[0].macaddr, kernel_cmdline,
                boot_device, RAM_size, kernel_size, graphic_width,
@@ -601,7 +607,7 @@
     snprintf(buf, sizeof(buf), "%s/%s", bios_dir, bios_name);
     ret = load_elf(buf, hwdef->slavio_base - PROM_VADDR, NULL, NULL, NULL);
     if (ret < 0 || ret > PROM_SIZE_MAX)
-        ret = load_image(buf, phys_ram_base + prom_offset);
+        ret = load_image_targphys(buf, prom_offset, PROM_SIZE_MAX);
     if (ret < 0 || ret > PROM_SIZE_MAX) {
         fprintf(stderr, "qemu: could not load prom '%s'\n",
                 buf);
@@ -683,7 +689,7 @@
     }
 
     kernel_size = sun4m_load_kernel(kernel_filename, kernel_cmdline,
-                                    initrd_filename);
+                                    initrd_filename, RAM_size);
 
     nvram_init(nvram, (uint8_t *)&nd_table[0].macaddr, kernel_cmdline,
                boot_device, RAM_size, kernel_size, graphic_width,
@@ -1415,7 +1421,7 @@
     snprintf(buf, sizeof(buf), "%s/%s", bios_dir, bios_name);
     ret = load_elf(buf, hwdef->slavio_base - PROM_VADDR, NULL, NULL, NULL);
     if (ret < 0 || ret > PROM_SIZE_MAX)
-        ret = load_image(buf, phys_ram_base + prom_offset);
+        ret = load_image_targphys(buf, prom_offset, PROM_SIZE_MAX);
     if (ret < 0 || ret > PROM_SIZE_MAX) {
         fprintf(stderr, "qemu: could not load prom '%s'\n",
                 buf);
@@ -1485,7 +1491,7 @@
     }
 
     kernel_size = sun4m_load_kernel(kernel_filename, kernel_cmdline,
-                                    initrd_filename);
+                                    initrd_filename, RAM_size);
 
     nvram_init(nvram, (uint8_t *)&nd_table[0].macaddr, kernel_cmdline,
                boot_device, RAM_size, kernel_size, graphic_width,
Index: qemu/hw/sun4u.c
===================================================================
--- qemu.orig/hw/sun4u.c	2008-05-01 19:29:35.000000000 +0000
+++ qemu/hw/sun4u.c	2008-05-02 14:45:50.000000000 +0000
@@ -111,7 +111,7 @@
     header->kernel_image = cpu_to_be64((uint64_t)kernel_image);
     header->kernel_size = cpu_to_be64((uint64_t)kernel_size);
     if (cmdline) {
-        strcpy(phys_ram_base + CMDLINE_ADDR, cmdline);
+        pstrcpy_targphys(CMDLINE_ADDR, TARGET_PAGE_SIZE, cmdline);
         header->cmdline = cpu_to_be64((uint64_t)CMDLINE_ADDR);
         header->cmdline_size = cpu_to_be64((uint64_t)strlen(cmdline));
     }
@@ -294,9 +294,12 @@
         /* XXX: put correct offset */
         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);
+            kernel_size = load_aout(kernel_filename, KERNEL_LOAD_ADDR,
+                                    ram_size - KERNEL_LOAD_ADDR);
         if (kernel_size < 0)
-            kernel_size = load_image(kernel_filename, phys_ram_base + KERNEL_LOAD_ADDR);
+            kernel_size = load_image_targphys(kernel_filename,
+                                              KERNEL_LOAD_ADDR,
+                                              ram_size - KERNEL_LOAD_ADDR);
         if (kernel_size < 0) {
             fprintf(stderr, "qemu: could not load kernel '%s'\n",
                     kernel_filename);
@@ -305,7 +308,9 @@
 
         /* load initrd */
         if (initrd_filename) {
-            initrd_size = load_image(initrd_filename, phys_ram_base + INITRD_LOAD_ADDR);
+            initrd_size = load_image_targphys(initrd_filename,
+                                              INITRD_LOAD_ADDR,
+                                              ram_size - INITRD_LOAD_ADDR);
             if (initrd_size < 0) {
                 fprintf(stderr, "qemu: could not load initial ram disk '%s'\n",
                         initrd_filename);
@@ -313,11 +318,12 @@
             }
         }
         if (initrd_size > 0) {
+            uint32_t temp;
+
             for (i = 0; i < 64 * TARGET_PAGE_SIZE; i += TARGET_PAGE_SIZE) {
-                if (ldl_raw(phys_ram_base + KERNEL_LOAD_ADDR + i)
-                    == 0x48647253) { // HdrS
-                    stl_raw(phys_ram_base + KERNEL_LOAD_ADDR + i + 16, INITRD_LOAD_ADDR);
-                    stl_raw(phys_ram_base + KERNEL_LOAD_ADDR + i + 20, initrd_size);
+                if (ldl_phys(KERNEL_LOAD_ADDR + i) == 0x48647253) { // HdrS
+                    stl_phys(KERNEL_LOAD_ADDR + i + 16, INITRD_LOAD_ADDR);
+                    stl_phys(KERNEL_LOAD_ADDR + i + 20, initrd_size);
                     break;
                 }
             }
Index: qemu/elf_ops.h
===================================================================
--- qemu.orig/elf_ops.h	2008-05-02 13:52:10.000000000 +0000
+++ qemu/elf_ops.h	2008-05-02 13:55:29.000000000 +0000
@@ -147,7 +147,6 @@
     int size, i, total_size;
     elf_word mem_size;
     uint64_t addr, low = 0, high = 0;
-    uint8_t *data = NULL;
 
     if (read(fd, &ehdr, sizeof(ehdr)) != sizeof(ehdr))
         goto fail;
@@ -182,26 +181,19 @@
         ph = &phdr[i];
         if (ph->p_type == PT_LOAD) {
             mem_size = ph->p_memsz;
-            /* XXX: avoid allocating */
-            data = qemu_mallocz(mem_size);
+            addr = ph->p_vaddr + virt_to_phys_addend;
             if (ph->p_filesz > 0) {
                 if (lseek(fd, ph->p_offset, SEEK_SET) < 0)
                     goto fail;
-                if (read(fd, data, ph->p_filesz) != ph->p_filesz)
+                if (read_targphys(fd, addr, ph->p_filesz) != ph->p_filesz)
                     goto fail;
             }
-            addr = ph->p_vaddr + virt_to_phys_addend;
-
-            cpu_physical_memory_write_rom(addr, data, mem_size);
 
             total_size += mem_size;
             if (!low || addr < low)
                 low = addr;
             if (!high || (addr + mem_size) > high)
                 high = addr + mem_size;
-
-            qemu_free(data);
-            data = NULL;
         }
     }
     qemu_free(phdr);
@@ -211,7 +203,6 @@
         *highaddr = (uint64_t)(elf_sword)high;
     return total_size;
  fail:
-    qemu_free(data);
     qemu_free(phdr);
     return -1;
 }
