[Top][All Lists]
[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 = {
- Re: [Qemu-devel] [PATCH] Add more devices for MIPS system emulation,
Thiemo Seufer <=