qemu-devel
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: [Qemu-devel] [PATCH] Add more devices for MIPS system emulation


From: Thiemo Seufer
Subject: Re: [Qemu-devel] [PATCH] Add more devices for MIPS system emulation
Date: Mon, 6 Mar 2006 14:50:44 +0000
User-agent: Mutt/1.5.11+cvs20060126

On Thu, Feb 23, 2006 at 09:44:20PM +0000, Paul Brook wrote:
> > > > That's the current state since there is no real mips firmware, but Qemu
> > > > should also be able to boot from an image. E.g. Linux/MIPS on
> > > > DECstations uses MSDOS disklabels.
> > >
> > > I don't see how providing a fake an x86 boot sector would help this.
> > > Presumably the DECstation firmware just knows how to load an image from
> > > disk.
> >
> > It loads a block sector list from the bootsector which points to
> > the second stage bootloader.
> 
> The existing linux.bin definitely won't do what you want then.
> 
> In any case until the MIPS emulation can emulate a DECstation and we have a 
> corresponding BIOS that we can distribute, your patch just breaks diskless 
> MIPS emulation for no apparent benefit.

I updated the patch to allow for that again, and added an ELF loader on
top to avoid hardcoded kernel load addresses/entry points. This is also
useful for stand-alone programs. The ramdisk and command line addresses
are still hardcoded.


Thiemo


Index: qemu-work/Makefile.target
===================================================================
--- qemu-work.orig/Makefile.target      2006-02-21 16:41:47.000000000 +0000
+++ qemu-work/Makefile.target   2006-03-06 02:03:38.000000000 +0000
@@ -333,8 +333,11 @@
 DEFINES += -DHAS_AUDIO
 endif
 ifeq ($(TARGET_ARCH), mips)
-VL_OBJS+= mips_r4k.o dma.o vga.o serial.o i8254.o i8259.o
-#VL_OBJS+= #ide.o pckbd.o fdc.o m48t59.o
+VL_OBJS+= ide.o pckbd.o ps2.o vga.o $(SOUND_HW) dma.o $(AUDIODRV)
+VL_OBJS+= mc146818rtc.o serial.o i8259.o i8254.o mips_r4k.o
+VL_OBJS+= mixeng.o
+#VL_OBJS+= #fdc.o
+DEFINES += -DHAS_AUDIO
 endif
 ifeq ($(TARGET_BASE_ARCH), sparc)
 ifeq ($(TARGET_ARCH), sparc64)
Index: qemu-work/hw/mips_r4k.c
===================================================================
--- qemu-work.orig/hw/mips_r4k.c        2006-02-21 16:40:03.000000000 +0000
+++ qemu-work/hw/mips_r4k.c     2006-03-06 02:07:18.000000000 +0000
@@ -1,12 +1,13 @@
 #include "vl.h"
 
 #define BIOS_FILENAME "mips_bios.bin"
-//#define BIOS_FILENAME "system.bin"
-#define KERNEL_LOAD_ADDR 0x80010000
+#define LINUX_BOOT_FILENAME "linux_boot.bin"
+
 #define INITRD_LOAD_ADDR 0x80800000
 
 extern FILE *logfile;
 
+static RTCState *rtc_state;
 static PITState *pit;
 
 static void pic_irq_request(void *opaque, int level)
@@ -101,6 +102,136 @@
     cpu_mips_update_count(env, 1, 0);
 }
 
+#define REG_EQUIPMENT_BYTE          0x14
+#define REG_IBM_CENTURY_BYTE        0x32
+#define REG_IBM_PS2_CENTURY_BYTE    0x37
+
+static inline int to_bcd(RTCState *s, int a)
+{
+    return ((a / 10) << 4) | (a % 10);
+}
+
+static void cmos_init(int ram_size, int boot_device, BlockDriverState 
**hd_table)
+{
+    RTCState *s = rtc_state;
+    int val;
+    time_t ti;
+    struct tm *tm;
+
+    /* set the CMOS date */
+    time(&ti);
+    if (rtc_utc)
+        tm = gmtime(&ti);
+    else
+        tm = localtime(&ti);
+    rtc_set_date(s, tm);
+
+    val = to_bcd(s, (tm->tm_year / 100) + 19);
+    rtc_set_memory(s, REG_IBM_CENTURY_BYTE, val);
+    rtc_set_memory(s, REG_IBM_PS2_CENTURY_BYTE, val);
+}
+
+
+#include "disas.h"
+
+#define ELF_CLASS   ELFCLASS32
+#ifdef TARGET_WORDS_BIGENDIAN
+# define ELF_DATA    ELFDATA2MSB
+#else
+# define ELF_DATA    ELFDATA2LSB
+#endif
+#define ELF_ARCH    EM_MIPS
+
+#include "elf.h"
+
+#ifndef BSWAP_NEEDED
+#define bswap_ehdr32(e) do { } while (0)
+#define bswap_phdr32(e) do { } while (0)
+#define bswap_shdr32(e) do { } while (0)
+#define bswap_sym32(e) do { } while (0)
+#endif
+
+#define SZ             32
+#define elf_word        uint32_t
+#define bswapSZs       bswap32s
+#include "elf_ops.h"
+
+static int load_mips_kernel_elf(const char *filename, elf_word *entry)
+{
+    struct elf32_hdr ehdr;
+    int retval, fd, i;
+    Elf32_Half machine;
+
+    fd = open(filename, O_RDONLY | O_BINARY);
+    if (fd < 0)
+       goto error;
+
+    retval = read(fd, &ehdr, sizeof(ehdr));
+    if (retval < 0)
+       goto error;
+
+    if (ehdr.e_ident[0] != 0x7f || ehdr.e_ident[1] != 'E'
+       || ehdr.e_ident[2] != 'L' || ehdr.e_ident[3] != 'F')
+       goto error;
+    machine = tswap16(ehdr.e_machine);
+    if (machine == EM_MIPS) {
+       struct elf32_phdr phdr;
+
+       bswap_ehdr32(&ehdr);
+
+       *entry = ehdr.e_entry;
+       retval = lseek(fd, ehdr.e_phoff, SEEK_SET);
+       if (retval < 0)
+           goto error;
+
+       for (i = 0; i < ehdr.e_phnum; i++) {
+           retval = read(fd, &phdr, sizeof(phdr));
+           if (retval < 0)
+               goto error;
+           bswap_phdr32(&phdr);
+           if (phdr.p_type == PT_LOAD) {
+               uint8_t *addr;
+               size_t sz = phdr.p_filesz;
+
+               if (phdr.p_vaddr < 0x80000000
+                   || phdr.p_memsz > 0x20000000
+                   || (phdr.p_vaddr < 0xa0000000 && (phdr.p_vaddr + 
phdr.p_memsz) >= 0xa0000000)
+                   || (phdr.p_vaddr < 0xc0000000 && (phdr.p_vaddr + 
phdr.p_memsz) >= 0xc0000000))
+                   goto error;
+               addr = (uint8_t *)(phys_ram_base + (phdr.p_vaddr & 0x1fffffff));
+               retval = lseek(fd, phdr.p_offset, SEEK_SET);
+               if (retval < 0)
+                   goto error;
+               while (sz) {
+                   retval = read(fd, addr, sz);
+                   switch (retval) {
+                   case -1:
+                       goto error;
+                   case 0: /* EOF */
+                       if (sz)
+                           goto error;
+                       break;
+                   default:
+                       if (sz < retval)
+                           goto error;
+                       sz -= retval;
+                       retval = 0;
+                       break;
+                   }
+               }
+           }
+       }
+       load_symbols32(&ehdr, fd);
+    }
+
+    close(fd);
+    return retval;
+ error:
+    close(fd);
+    return -1;
+}
+
+
 static void io_writeb (void *opaque, target_phys_addr_t addr, uint32_t value)
 {
 #if 0
@@ -183,84 +314,101 @@
     &io_readl,
 };
 
+static const int ide_iobase[2] = { 0x1f0, 0x170 };
+static const int ide_iobase2[2] = { 0x3f6, 0x376 };
+static const int ide_irq[2] = { 14, 15 };
+
 void mips_r4k_init (int ram_size, int vga_ram_size, int boot_device,
                     DisplayState *ds, const char **fd_filename, int snapshot,
                     const char *kernel_filename, const char *kernel_cmdline,
                     const char *initrd_filename)
 {
     char buf[1024];
-    target_ulong kernel_base, kernel_size, initrd_base, initrd_size;
+    elf_word entry = 0;
     unsigned long bios_offset;
     int io_memory;
-    int linux_boot;
     int ret;
     CPUState *env;
-
-    printf("%s: start\n", __func__);
-    linux_boot = (kernel_filename != NULL);
+    int i;
 
     env = cpu_init();
     register_savevm("cpu", 0, 3, cpu_save, cpu_load, env);
 
     /* allocate RAM */
     cpu_register_physical_memory(0, ram_size, IO_MEM_RAM);
+
+    /* Try to load a BIOS image. If this fails, we continue regardless,
+       but initialize the hardware ourselves. When a kernel gets
+       preloaded we also initialize the hardware, since the BIOS wasn't
+       run. */
     bios_offset = ram_size + vga_ram_size;
     snprintf(buf, sizeof(buf), "%s/%s", bios_dir, BIOS_FILENAME);
     printf("%s: load BIOS '%s' size %d\n", __func__, buf, BIOS_SIZE);
     ret = load_image(buf, phys_ram_base + bios_offset);
-    if (ret != BIOS_SIZE) {
-        fprintf(stderr, "qemu: could not load MIPS bios '%s'\n", buf);
-        exit(1);
+    if (ret == BIOS_SIZE) {
+       cpu_register_physical_memory((uint32_t)(0x1fc00000),
+                                    BIOS_SIZE, bios_offset | IO_MEM_ROM);
+       env->PC = 0xBFC00000;
+       if (!kernel_filename)
+           return;
+    } else {
+       /* not fatal */
+        fprintf(stderr, "qemu: Warning, could not load MIPS bios '%s'\n",
+               buf);
     }
-    cpu_register_physical_memory((uint32_t)(0x1fc00000),
-                                 BIOS_SIZE, bios_offset | IO_MEM_ROM);
-#if 0
-    memcpy(phys_ram_base + 0x10000, phys_ram_base + bios_offset, BIOS_SIZE);
-    env->PC = 0x80010004;
-#else
-    env->PC = 0xBFC00004;
-#endif
-    if (linux_boot) {
-        kernel_base = KERNEL_LOAD_ADDR;
-        /* now we can load the kernel */
-        kernel_size = load_image(kernel_filename,
-                                phys_ram_base + (kernel_base - 0x80000000));
-        if (kernel_size == (target_ulong) -1) {
+
+    if (kernel_filename) {
+       /* Prepare the bootsector if a disk image was specified via -hda. */
+       if (bs_table[0]) {
+           uint8_t bootsect[512];
+           uint8_t old_bootsect[512];
+
+           snprintf(buf, sizeof(buf), "%s/%s", bios_dir, LINUX_BOOT_FILENAME);
+           ret = load_image(buf, bootsect);
+           if (ret != sizeof(bootsect)) {
+               fprintf(stderr, "qemu: could not load linux boot sector '%s'\n",
+                       buf);
+               exit(1);
+           }
+
+           if (bdrv_read(bs_table[0], 0, old_bootsect, 1) >= 0) {
+               /* copy the MSDOS partition table */
+               memcpy(bootsect + 0x1be, old_bootsect + 0x1be, 0x40);
+           }
+
+           bdrv_set_boot_sector(bs_table[0], bootsect, sizeof(bootsect));
+       }
+
+       if (load_mips_kernel_elf(kernel_filename, &entry)) {
             fprintf(stderr, "qemu: could not load kernel '%s'\n", 
                     kernel_filename);
             exit(1);
-        }
+       }
+       env->PC = entry;
+
         /* load initrd */
         if (initrd_filename) {
-            initrd_base = INITRD_LOAD_ADDR;
-            initrd_size = load_image(initrd_filename,
-                                     phys_ram_base + initrd_base);
-            if (initrd_size == (target_ulong) -1) {
+            if (load_image(initrd_filename, phys_ram_base + INITRD_LOAD_ADDR)
+               == (target_ulong) -1) {
                 fprintf(stderr, "qemu: could not load initial ram disk 
'%s'\n", 
                         initrd_filename);
                 exit(1);
             }
-        } else {
-            initrd_base = 0;
-            initrd_size = 0;
         }
-        env->PC = KERNEL_LOAD_ADDR;
+
        /* Store command line.  */
         strcpy (phys_ram_base + (16 << 20) - 256, kernel_cmdline);
         /* FIXME: little endian support */
         *(int *)(phys_ram_base + (16 << 20) - 260) = tswap32 (0x12345678);
         *(int *)(phys_ram_base + (16 << 20) - 264) = tswap32 (ram_size);
-    } else {
-        kernel_base = 0;
-        kernel_size = 0;
-        initrd_base = 0;
-        initrd_size = 0;
     }
 
     /* Init internal devices */
     cpu_mips_clock_init(env);
     cpu_mips_irqctrl_init();
 
+    rtc_state = rtc_init(0x70, 8);
+
     /* Register 64 KB of ISA IO space at 0x14000000 */
     io_memory = cpu_register_io_memory(0, io_read, io_write, NULL);
     cpu_register_physical_memory(0x14000000, 0x00010000, io_memory);
@@ -268,6 +416,7 @@
 
     isa_pic = pic_init(pic_irq_request, env);
     pit = pit_init(0x40, 0);
+
     serial_init(&pic_set_irq_new, isa_pic, 0x3f8, 4, serial_hds[0]);
     vga_initialize(NULL, ds, phys_ram_base + ram_size, ram_size, 
                    vga_ram_size, 0, 0);
@@ -281,6 +430,16 @@
             exit (1);
         }
     }
+
+    for(i = 0; i < 2; i++)
+        isa_ide_init(ide_iobase[i], ide_iobase2[i], ide_irq[i],
+                     bs_table[2 * i], bs_table[2 * i + 1]);
+
+    kbd_init();
+    DMA_init(1);
+
+    cmos_init(ram_size, boot_device, bs_table);
+
 }
 
 QEMUMachine mips_machine = {




reply via email to

[Prev in Thread] Current Thread [Next in Thread]