Commit 6f7e9aec authored by Fabrice Bellard's avatar Fabrice Bellard
Browse files

sparc fixes (Blue Swirl)


git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1326 c046a42c-6fe2-441c-8c8c-71466251a162
parent b756921a
Loading
Loading
Loading
Loading
+1 −1
Original line number Diff line number Diff line
@@ -338,7 +338,7 @@ VL_OBJS+= mc146818rtc.o serial.o i8259.o i8254.o fdc.o m48t59.o
VL_OBJS+= ppc_prep.o ppc_chrp.o cuda.o adb.o openpic.o mixeng.o
endif
ifeq ($(TARGET_BASE_ARCH), sparc)
VL_OBJS+= sun4m.o tcx.o lance.o iommu.o m48t08.o magic-load.o slavio_intctl.o slavio_timer.o slavio_serial.o fdc.o
VL_OBJS+= sun4m.o tcx.o lance.o iommu.o m48t08.o magic-load.o slavio_intctl.o slavio_timer.o slavio_serial.o fdc.o esp.o
endif
ifdef CONFIG_GDBSTUB
VL_OBJS+=gdbstub.o 
+0 −1
Original line number Diff line number Diff line
@@ -3,7 +3,6 @@ short term:
- debug option in 'configure' script + disable -fomit-frame-pointer
- Precise VGA timings for old games/demos (malc patch)
- merge PIC spurious interrupt patch
- merge VNC keyboard patch
- merge Solaris patch
- warning for OS/2: must not use 128 MB memory (merge bochs cmos patch ?)
- config file (at least for windows/Mac OS X)

hw/esp.c

0 → 100644
+192 −0
Original line number Diff line number Diff line
/*
 * QEMU ESP emulation
 * 
 * Copyright (c) 2005 Fabrice Bellard
 * 
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 * THE SOFTWARE.
 */
#include "vl.h"

/* debug ESP card */
#define DEBUG_ESP

#ifdef DEBUG_ESP
#define DPRINTF(fmt, args...) \
do { printf("ESP: " fmt , ##args); } while (0)
#else
#define DPRINTF(fmt, args...)
#endif

#define ESPDMA_REGS 4
#define ESPDMA_MAXADDR (ESPDMA_REGS * 4 - 1)
#define ESP_MAXREG 0x3f

typedef struct ESPState {
    BlockDriverState **bd;
    uint8_t regs[ESP_MAXREG];
    int irq;
    uint32_t espdmaregs[ESPDMA_REGS];
} ESPState;

static void esp_reset(void *opaque)
{
    ESPState *s = opaque;
    memset(s->regs, 0, ESP_MAXREG);
    s->regs[0x0e] = 0x4; // Indicate fas100a
    memset(s->espdmaregs, 0, ESPDMA_REGS * 4);
}

static uint32_t esp_mem_readb(void *opaque, target_phys_addr_t addr)
{
    ESPState *s = opaque;
    uint32_t saddr;

    saddr = (addr & ESP_MAXREG) >> 2;
    switch (saddr) {
    default:
	break;
    }
    DPRINTF("esp: read reg[%d]: 0x%2.2x\n", saddr, s->regs[saddr]);
    return s->regs[saddr];
}

static void esp_mem_writeb(void *opaque, target_phys_addr_t addr, uint32_t val)
{
    ESPState *s = opaque;
    uint32_t saddr;

    saddr = (addr & ESP_MAXREG) >> 2;
    DPRINTF("esp: write reg[%d]: 0x%2.2x -> 0x%2.2x\n", saddr, s->regs[saddr], val);
    switch (saddr) {
    case 3:
	// Command
	switch(val & 0x7f) {
	case 0:
	    DPRINTF("esp: NOP (%2.2x)\n", val);
	    break;
	case 2:
	    DPRINTF("esp: Chip reset (%2.2x)\n", val);
	    esp_reset(s);
	    break;
	case 3:
	    DPRINTF("esp: Bus reset (%2.2x)\n", val);
	    break;
	case 0x1a:
	    DPRINTF("esp: Set ATN (%2.2x)\n", val);
	    break;
	case 0x42:
	    DPRINTF("esp: Select with ATN (%2.2x)\n", val);
	    s->regs[4] = 0x1a; // Status: TCNT | TDONE | CMD
	    s->regs[5] = 0x20; // Intr: Disconnect, nobody there
	    s->regs[6] = 0x4;  // Seq: Cmd done
	    pic_set_irq(s->irq, 1);
	    break;
	}
	break;
    case 4 ... 7:
    case 9 ... 0xf:
	break;
    default:
	s->regs[saddr] = val;
	break;
    }
}

static CPUReadMemoryFunc *esp_mem_read[3] = {
    esp_mem_readb,
    esp_mem_readb,
    esp_mem_readb,
};

static CPUWriteMemoryFunc *esp_mem_write[3] = {
    esp_mem_writeb,
    esp_mem_writeb,
    esp_mem_writeb,
};

static uint32_t espdma_mem_readl(void *opaque, target_phys_addr_t addr)
{
    ESPState *s = opaque;
    uint32_t saddr;

    saddr = (addr & ESPDMA_MAXADDR) >> 2;
    return s->espdmaregs[saddr];
}

static void espdma_mem_writel(void *opaque, target_phys_addr_t addr, uint32_t val)
{
    ESPState *s = opaque;
    uint32_t saddr;

    saddr = (addr & ESPDMA_MAXADDR) >> 2;
    s->espdmaregs[saddr] = val;
}

static CPUReadMemoryFunc *espdma_mem_read[3] = {
    espdma_mem_readl,
    espdma_mem_readl,
    espdma_mem_readl,
};

static CPUWriteMemoryFunc *espdma_mem_write[3] = {
    espdma_mem_writel,
    espdma_mem_writel,
    espdma_mem_writel,
};

static void esp_save(QEMUFile *f, void *opaque)
{
    ESPState *s = opaque;
    
}

static int esp_load(QEMUFile *f, void *opaque, int version_id)
{
    ESPState *s = opaque;
    
    if (version_id != 1)
        return -EINVAL;

    return 0;
}

void esp_init(BlockDriverState **bd, int irq, uint32_t espaddr, uint32_t espdaddr)
{
    ESPState *s;
    int esp_io_memory, espdma_io_memory;

    s = qemu_mallocz(sizeof(ESPState));
    if (!s)
        return;

    s->bd = bd;
    s->irq = irq;

    esp_io_memory = cpu_register_io_memory(0, esp_mem_read, esp_mem_write, s);
    cpu_register_physical_memory(espaddr, ESP_MAXREG*4, esp_io_memory);

    espdma_io_memory = cpu_register_io_memory(0, espdma_mem_read, espdma_mem_write, s);
    cpu_register_physical_memory(espdaddr, 16, espdma_io_memory);

    esp_reset(s);

    register_savevm("esp", espaddr, 1, esp_save, esp_load, s);
    qemu_register_reset(esp_reset, s);
}
+18 −19
Original line number Diff line number Diff line
@@ -94,21 +94,6 @@ typedef struct fdrive_t {
    uint8_t ro;               /* Is read-only           */
} fdrive_t;

#ifdef TARGET_SPARC
/* XXX: suppress those hacks */
#define DMA_read_memory(a,b,c,d)
#define DMA_write_memory(a,b,c,d)
void DMA_register_channel (int nchan,
                           DMA_transfer_handler transfer_handler,
                           void *opaque)
{
}
#define DMA_hold_DREQ(a)
#define DMA_release_DREQ(a)
#define DMA_get_channel_mode(a) (0)
#define DMA_schedule(a)
#endif

static void fd_init (fdrive_t *drv, BlockDriverState *bs)
{
    /* Drive */
@@ -423,6 +408,12 @@ static uint32_t fdctrl_read (void *opaque, uint32_t reg)
    uint32_t retval;

    switch (reg & 0x07) {
#ifdef TARGET_SPARC
    case 0x00:
	// Identify to Linux as S82078B
	retval = fdctrl_read_statusB(fdctrl);
	break;
#endif
    case 0x01:
	retval = fdctrl_read_statusB(fdctrl);
	break;
@@ -577,6 +568,14 @@ static void fdctrl_reset_irq (fdctrl_t *fdctrl)

static void fdctrl_raise_irq (fdctrl_t *fdctrl, uint8_t status)
{
#ifdef TARGET_SPARC
    // Sparc mutation
    if (!fdctrl->dma_en) {
	fdctrl->state &= ~FD_CTRL_BUSY;
	fdctrl->int_status = status;
	return;
    }
#endif
    if (~(fdctrl->state & FD_CTRL_INTR)) {
        pic_set_irq(fdctrl->irq_lvl, 1);
        fdctrl->state |= FD_CTRL_INTR;
@@ -980,11 +979,11 @@ static int fdctrl_transfer_handler (void *opaque, int nchan,
        len = dma_len - fdctrl->data_pos;
        if (len + rel_pos > FD_SECTOR_LEN)
            len = FD_SECTOR_LEN - rel_pos;
        FLOPPY_DPRINTF("copy %d bytes (%d %d %d) %d pos %d %02x %02x "
                       "(%d-0x%08x 0x%08x)\n", len, size, fdctrl->data_pos,
        FLOPPY_DPRINTF("copy %d bytes (%d %d %d) %d pos %d %02x "
                       "(%d-0x%08x 0x%08x)\n", len, dma_len, fdctrl->data_pos,
                       fdctrl->data_len, fdctrl->cur_drv, cur_drv->head,
                       cur_drv->track, cur_drv->sect, fd_sector(cur_drv),
                       fd_sector(cur_drv) * 512, addr);
                       fd_sector(cur_drv) * 512);
        if (fdctrl->data_dir != FD_DIR_WRITE ||
	    len < FD_SECTOR_LEN || rel_pos != 0) {
            /* READ & SCAN commands and realign to a sector for WRITE */
@@ -1045,7 +1044,7 @@ static int fdctrl_transfer_handler (void *opaque, int nchan,
	    FLOPPY_DPRINTF("seek to next sector (%d %02x %02x => %d) (%d)\n",
			   cur_drv->head, cur_drv->track, cur_drv->sect,
			   fd_sector(cur_drv),
			   fdctrl->data_pos - size);
			   fdctrl->data_pos - len);
            /* XXX: cur_drv->sect >= cur_drv->last_sect should be an
               error in fact */
            if (cur_drv->sect >= cur_drv->last_sect ||
+84 −26
Original line number Diff line number Diff line
@@ -36,7 +36,10 @@
// IRQs are not PIL ones, but master interrupt controller register
// bits
#define PHYS_JJ_IOMMU	0x10000000	/* I/O MMU */
#define PHYS_JJ_TCX_FB	0x50800000	/* Start address, frame buffer body */
#define PHYS_JJ_TCX_FB	0x50000000	/* TCX frame buffer */
#define PHYS_JJ_ESPDMA  0x78400000      /* ESP DMA controller */
#define PHYS_JJ_ESP     0x78800000      /* ESP SCSI */
#define PHYS_JJ_ESP_IRQ    18
#define PHYS_JJ_LEDMA   0x78400010      /* Lance DMA controller */
#define PHYS_JJ_LE      0x78C00000      /* Lance ethernet */
#define PHYS_JJ_LE_IRQ     16
@@ -50,7 +53,6 @@
#define PHYS_JJ_MS_KBD_IRQ    14
#define PHYS_JJ_SER	0x71100000	/* Serial */
#define PHYS_JJ_SER_IRQ    15
#define PHYS_JJ_SCSI_IRQ   18
#define PHYS_JJ_FDC	0x71400000	/* Floppy */
#define PHYS_JJ_FLOPPY_IRQ 22

@@ -61,32 +63,86 @@ uint64_t cpu_get_tsc()
    return qemu_get_clock(vm_clock);
}

void DMA_run() {}
int DMA_get_channel_mode (int nchan)
{
    return 0;
}
int DMA_read_memory (int nchan, void *buf, int pos, int size)
{
    return 0;
}
int DMA_write_memory (int nchan, void *buf, int pos, int size)
{
    return 0;
}
void DMA_hold_DREQ (int nchan) {}
void DMA_release_DREQ (int nchan) {}
void DMA_schedule(int nchan) {}
void DMA_run (void) {}
void DMA_init (int high_page_enable) {}
void DMA_register_channel (int nchan,
                           DMA_transfer_handler transfer_handler,
                           void *opaque)
{
}

static void nvram_set_word (m48t08_t *nvram, uint32_t addr, uint16_t value)
{
    m48t08_write(nvram, addr++, (value >> 8) & 0xff);
    m48t08_write(nvram, addr++, value & 0xff);
}

static void nvram_set_lword (m48t08_t *nvram, uint32_t addr, uint32_t value)
{
    m48t08_write(nvram, addr++, value >> 24);
    m48t08_write(nvram, addr++, (value >> 16) & 0xff);
    m48t08_write(nvram, addr++, (value >> 8) & 0xff);
    m48t08_write(nvram, addr++, value & 0xff);
}

static void nvram_set_string (m48t08_t *nvram, uint32_t addr,
                       const unsigned char *str, uint32_t max)
{
    unsigned int i;

    for (i = 0; i < max && str[i] != '\0'; i++) {
        m48t08_write(nvram, addr + i, str[i]);
    }
    m48t08_write(nvram, addr + max - 1, '\0');
}

static m48t08_t *nvram;

static void nvram_init(m48t08_t *nvram, uint8_t *macaddr, const char *cmdline)
extern int nographic;

static void nvram_init(m48t08_t *nvram, uint8_t *macaddr, const char *cmdline,
		       int boot_device, uint32_t RAM_size,
		       uint32_t kernel_size,
		       int width, int height, int depth)
{
    unsigned char tmp = 0;
    int i, j;

    i = 0x40;
    // Try to match PPC NVRAM
    nvram_set_string(nvram, 0x00, "QEMU_BIOS", 16);
    nvram_set_lword(nvram,  0x10, 0x00000001); /* structure v1 */
    // NVRAM_size, arch not applicable
    m48t08_write(nvram, 0x2F, nographic & 0xff);
    nvram_set_lword(nvram,  0x30, RAM_size);
    m48t08_write(nvram, 0x34, boot_device & 0xff);
    nvram_set_lword(nvram,  0x38, KERNEL_LOAD_ADDR);
    nvram_set_lword(nvram,  0x3C, kernel_size);
    if (cmdline) {
	uint32_t cmdline_len;

	strcpy(phys_ram_base + CMDLINE_ADDR, cmdline);
	m48t08_write(nvram, i++, CMDLINE_ADDR >> 24);
	m48t08_write(nvram, i++, (CMDLINE_ADDR >> 16) & 0xff);
	m48t08_write(nvram, i++, (CMDLINE_ADDR >> 8) & 0xff);
	m48t08_write(nvram, i++, CMDLINE_ADDR & 0xff);

	cmdline_len = strlen(cmdline);
	m48t08_write(nvram, i++, cmdline_len >> 24);
	m48t08_write(nvram, i++, (cmdline_len >> 16) & 0xff);
	m48t08_write(nvram, i++, (cmdline_len >> 8) & 0xff);
	m48t08_write(nvram, i++, cmdline_len & 0xff);
	nvram_set_lword(nvram,  0x40, CMDLINE_ADDR);
        nvram_set_lword(nvram,  0x44, strlen(cmdline));
    }
    // initrd_image, initrd_size passed differently
    nvram_set_word(nvram,   0x54, width);
    nvram_set_word(nvram,   0x56, height);
    nvram_set_word(nvram,   0x58, depth);

    // Sun4m specific use
    i = 0x1fd8;
    m48t08_write(nvram, i++, 0x01);
    m48t08_write(nvram, i++, 0x80); /* Sun4m OBP */
@@ -155,7 +211,7 @@ void sun4m_init(int ram_size, int vga_ram_size, int boot_device,
    char buf[1024];
    int ret, linux_boot;
    unsigned int i;
    unsigned long vram_size = 0x100000, prom_offset, initrd_size;
    long vram_size = 0x100000, prom_offset, initrd_size, kernel_size;

    linux_boot = (kernel_filename != NULL);

@@ -164,14 +220,14 @@ void sun4m_init(int ram_size, int vga_ram_size, int boot_device,

    iommu = iommu_init(PHYS_JJ_IOMMU);
    slavio_intctl = slavio_intctl_init(PHYS_JJ_INTR0, PHYS_JJ_INTR_G);
    tcx = tcx_init(ds, PHYS_JJ_TCX_FB, phys_ram_base + ram_size, ram_size, vram_size);
    tcx = tcx_init(ds, PHYS_JJ_TCX_FB, phys_ram_base + ram_size, ram_size, vram_size, graphic_width, graphic_height);
    lance_init(&nd_table[0], PHYS_JJ_LE_IRQ, PHYS_JJ_LE, PHYS_JJ_LEDMA);
    nvram = m48t08_init(PHYS_JJ_EEPROM, PHYS_JJ_EEPROM_SIZE);
    nvram_init(nvram, (uint8_t *)&nd_table[0].macaddr, kernel_cmdline);
    slavio_timer_init(PHYS_JJ_CLOCK, PHYS_JJ_CLOCK_IRQ, PHYS_JJ_CLOCK1, PHYS_JJ_CLOCK1_IRQ);
    slavio_serial_ms_kbd_init(PHYS_JJ_MS_KBD, PHYS_JJ_MS_KBD_IRQ);
    slavio_serial_init(PHYS_JJ_SER, PHYS_JJ_SER_IRQ, serial_hds[0], serial_hds[1]);
    fdctrl_init(PHYS_JJ_FLOPPY_IRQ, 0, 1, PHYS_JJ_FDC, fd_table);
    esp_init(bs_table, PHYS_JJ_ESP_IRQ, PHYS_JJ_ESP, PHYS_JJ_ESPDMA);

    prom_offset = ram_size + vram_size;

@@ -189,13 +245,14 @@ void sun4m_init(int ram_size, int vga_ram_size, int boot_device,
    cpu_register_physical_memory(PROM_ADDR, (ret + TARGET_PAGE_SIZE) & TARGET_PAGE_MASK, 
                                 prom_offset | IO_MEM_ROM);

    kernel_size = 0;
    if (linux_boot) {
        ret = load_elf(kernel_filename, phys_ram_base + KERNEL_LOAD_ADDR);
        if (ret < 0)
	    ret = load_aout(kernel_filename, phys_ram_base + KERNEL_LOAD_ADDR);
	if (ret < 0)
	    ret = load_image(kernel_filename, phys_ram_base + KERNEL_LOAD_ADDR);
        if (ret < 0) {
        kernel_size = load_elf(kernel_filename, phys_ram_base + KERNEL_LOAD_ADDR);
        if (kernel_size < 0)
	    kernel_size = load_aout(kernel_filename, phys_ram_base + KERNEL_LOAD_ADDR);
	if (kernel_size < 0)
	    kernel_size = load_image(kernel_filename, phys_ram_base + KERNEL_LOAD_ADDR);
        if (kernel_size < 0) {
            fprintf(stderr, "qemu: could not load kernel '%s'\n", 
                    kernel_filename);
	    exit(1);
@@ -222,4 +279,5 @@ void sun4m_init(int ram_size, int vga_ram_size, int boot_device,
	    }
        }
    }
    nvram_init(nvram, (uint8_t *)&nd_table[0].macaddr, kernel_cmdline, boot_device, ram_size, kernel_size, graphic_width, graphic_height, graphic_depth);
}
Loading