* sort the PowerPC target object files

* make PowerPC NVRAM accessors generic to be able to use a MacIO NVRAM
  instead of the M48T59 one
* split PowerMac targets code:
 - move all PowerMac related definitions and prototypes into hw/ppc_mac.h
 - add hw/mac_dbdma.c, hw/mac_nvram.c and macio.c
   which implements shared PowerMac devices
 - define the g3bw machine in a new hw/ppc_oldworld.c file
* Fix the g3bw target:
 - fix the Grackle host PCI device
 - connect the Heathrow PIC to the PowerPC 6xx bus pins


git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3475 c046a42c-6fe2-441c-8c8c-71466251a162
This commit is contained in:
j_mayer 2007-10-28 23:42:18 +00:00
parent 897b4c6c4e
commit 3cbee15b9a
13 changed files with 914 additions and 518 deletions

View file

@ -469,13 +469,20 @@ VL_OBJS+= usb-uhci.o smbus_eeprom.o vmmouse.o vmport.o vmware_vga.o
CPPFLAGS += -DHAS_AUDIO -DHAS_AUDIO_CHOICE
endif
ifeq ($(TARGET_BASE_ARCH), ppc)
VL_OBJS+= ppc.o ide.o pckbd.o ps2.o vga.o $(SOUND_HW) dma.o $(AUDIODRV)
VL_OBJS+= mc146818rtc.o serial.o i8259.o i8254.o fdc.o m48t59.o pflash_cfi02.o
VL_OBJS+= ppc_prep.o ppc_chrp.o cuda.o adb.o openpic.o heathrow_pic.o
VL_OBJS+= grackle_pci.o prep_pci.o unin_pci.o
# PowerPC 4xx boards
VL_OBJS+= ppc4xx_devs.o ppc405_uc.o ppc405_boards.o
CPPFLAGS += -DHAS_AUDIO -DHAS_AUDIO_CHOICE
# shared objects
VL_OBJS+= ppc.o ide.o vga.o $(SOUND_HW) dma.o openpic.o $(AUDIODRV)
# PREP target
VL_OBJS+= pckbd.o ps2.o serial.o i8259.o i8254.o fdc.o m48t59.o mc146818rtc.o
VL_OBJS+= prep_pci.o ppc_prep.o
# Mac shared devices
VL_OBJS+= macio.o cuda.o adb.o mac_nvram.o mac_dbdma.o
# OldWorld PowerMac
VL_OBJS+= heathrow_pic.o grackle_pci.o ppc_oldworld.o
# NewWorld PowerMac
VL_OBJS+= unin_pci.o ppc_chrp.o
# PowerPC 4xx boards
VL_OBJS+= pflash_cfi02.o ppc4xx_devs.o ppc405_uc.o ppc405_boards.o
endif
ifeq ($(TARGET_BASE_ARCH), mips)
VL_OBJS+= mips_r4k.o mips_malta.o mips_pica61.o mips_mipssim.o

View file

@ -1,7 +1,8 @@
/*
* QEMU CUDA support
* QEMU PowerMac CUDA device support
*
* Copyright (c) 2004 Fabrice Bellard
* Copyright (c) 2004-2007 Fabrice Bellard
* Copyright (c) 2007 Jocelyn Mayer
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
@ -22,6 +23,7 @@
* THE SOFTWARE.
*/
#include "vl.h"
#include "ppc_mac.h"
/* XXX: implement all timer modes */
@ -634,10 +636,9 @@ static CPUReadMemoryFunc *cuda_read[] = {
&cuda_readl,
};
int cuda_init(qemu_irq irq)
void cuda_init (int *cuda_mem_index, qemu_irq irq)
{
CUDAState *s = &cuda_state;
int cuda_mem_index;
s->irq = irq;
@ -653,6 +654,5 @@ int cuda_init(qemu_irq irq)
set_counter(s, &s->timers[1], 0xffff);
s->adb_poll_timer = qemu_new_timer(vm_clock, cuda_adb_poll, s);
cuda_mem_index = cpu_register_io_memory(0, cuda_read, cuda_write, s);
return cuda_mem_index;
*cuda_mem_index = cpu_register_io_memory(0, cuda_read, cuda_write, s);
}

View file

@ -1,7 +1,8 @@
/*
* QEMU Grackle (heathrow PPC) PCI host
* QEMU Grackle PCI host (heathrow OldWorld PowerMac)
*
* Copyright (c) 2006 Fabrice Bellard
* Copyright (c) 2006-2007 Fabrice Bellard
* Copyright (c) 2007 Jocelyn Mayer
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
@ -23,6 +24,7 @@
*/
#include "vl.h"
#include "ppc_mac.h"
typedef target_phys_addr_t pci_addr_t;
#include "pci_host.h"
@ -82,7 +84,7 @@ static int pci_grackle_map_irq(PCIDevice *pci_dev, int irq_num)
static void pci_grackle_set_irq(qemu_irq *pic, int irq_num, int level)
{
qemu_set_irq(pic[irq_num + 8], level);
qemu_set_irq(pic[irq_num + 0x15], level);
}
PCIBus *pci_grackle_init(uint32_t base, qemu_irq *pic)
@ -93,7 +95,7 @@ PCIBus *pci_grackle_init(uint32_t base, qemu_irq *pic)
s = qemu_mallocz(sizeof(GrackleState));
s->bus = pci_register_bus(pci_grackle_set_irq, pci_grackle_map_irq,
pic, 0, 0);
pic, 0, 4);
pci_mem_config = cpu_register_io_memory(0, pci_grackle_config_read,
pci_grackle_config_write, s);

View file

@ -1,7 +1,8 @@
/*
* Heathrow PIC support (standard PowerMac PIC)
* Heathrow PIC support (OldWorld PowerMac)
*
* Copyright (c) 2005 Fabrice Bellard
* Copyright (c) 2005-2007 Fabrice Bellard
* Copyright (c) 2007 Jocelyn Mayer
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
@ -22,6 +23,7 @@
* THE SOFTWARE.
*/
#include "vl.h"
#include "ppc_mac.h"
//#define DEBUG
@ -34,6 +36,7 @@ typedef struct HeathrowPIC {
typedef struct HeathrowPICS {
HeathrowPIC pics[2];
qemu_irq *irqs;
} HeathrowPICS;
static inline int check_irq(HeathrowPIC *pic)
@ -45,9 +48,9 @@ static inline int check_irq(HeathrowPIC *pic)
static void heathrow_pic_update(HeathrowPICS *s)
{
if (check_irq(&s->pics[0]) || check_irq(&s->pics[1])) {
cpu_interrupt(first_cpu, CPU_INTERRUPT_HARD);
qemu_irq_raise(s->irqs[0]);
} else {
cpu_reset_interrupt(first_cpu, CPU_INTERRUPT_HARD);
qemu_irq_lower(s->irqs[0]);
}
}
@ -57,12 +60,13 @@ static void pic_writel (void *opaque, target_phys_addr_t addr, uint32_t value)
HeathrowPIC *pic;
unsigned int n;
#ifdef TARGET_WORDS_BIGENDIAN
value = bswap32(value);
#ifdef DEBUG
printf("pic_writel: %08x: %08x\n",
addr, value);
#endif
n = ((addr & 0xfff) - 0x10) >> 4;
#ifdef DEBUG
printf("pic_writel: " PADDRX " %u: %08x\n", addr, n, value);
#endif
if (n >= 2)
return;
pic = &s->pics[n];
@ -110,10 +114,11 @@ static uint32_t pic_readl (void *opaque, target_phys_addr_t addr)
}
}
#ifdef DEBUG
printf("pic_readl: %08x: %08x\n",
addr, value);
printf("pic_readl: " PADDRX " %u: %08x\n", addr, n, value);
#endif
#ifdef TARGET_WORDS_BIGENDIAN
value = bswap32(value);
#endif
return value;
}
@ -156,13 +161,17 @@ static void heathrow_pic_set_irq(void *opaque, int num, int level)
heathrow_pic_update(s);
}
qemu_irq *heathrow_pic_init(int *pmem_index)
qemu_irq *heathrow_pic_init(int *pmem_index,
int nb_cpus, qemu_irq **irqs)
{
HeathrowPICS *s;
s = qemu_mallocz(sizeof(HeathrowPICS));
s->pics[0].level_triggered = 0;
s->pics[1].level_triggered = 0x1ff00000;
/* only 1 CPU */
s->irqs = irqs[0];
*pmem_index = cpu_register_io_memory(0, pic_read, pic_write, s);
return qemu_allocate_irqs(heathrow_pic_set_irq, s, 64);
}

79
hw/mac_dbdma.c Normal file
View file

@ -0,0 +1,79 @@
/*
* PowerMac descriptor-based DMA emulation
*
* Copyright (c) 2005-2007 Fabrice Bellard
* Copyright (c) 2007 Jocelyn Mayer
*
* 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"
#include "ppc_mac.h"
/* DBDMA: currently no op - should suffice right now */
static void dbdma_writeb (void *opaque,
target_phys_addr_t addr, uint32_t value)
{
printf("%s: 0x" PADDRX " <= 0x%08x\n", __func__, addr, value);
}
static void dbdma_writew (void *opaque,
target_phys_addr_t addr, uint32_t value)
{
}
static void dbdma_writel (void *opaque,
target_phys_addr_t addr, uint32_t value)
{
}
static uint32_t dbdma_readb (void *opaque, target_phys_addr_t addr)
{
printf("%s: 0x" PADDRX " => 0x00000000\n", __func__, addr);
return 0;
}
static uint32_t dbdma_readw (void *opaque, target_phys_addr_t addr)
{
return 0;
}
static uint32_t dbdma_readl (void *opaque, target_phys_addr_t addr)
{
return 0;
}
static CPUWriteMemoryFunc *dbdma_write[] = {
&dbdma_writeb,
&dbdma_writew,
&dbdma_writel,
};
static CPUReadMemoryFunc *dbdma_read[] = {
&dbdma_readb,
&dbdma_readw,
&dbdma_readl,
};
void dbdma_init (int *dbdma_mem_index)
{
*dbdma_mem_index = cpu_register_io_memory(0, dbdma_read, dbdma_write, NULL);
}

123
hw/mac_nvram.c Normal file
View file

@ -0,0 +1,123 @@
/*
* PowerMac NVRAM emulation
*
* Copyright (c) 2005-2007 Fabrice Bellard
* Copyright (c) 2007 Jocelyn Mayer
*
* 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"
#include "ppc_mac.h"
struct MacIONVRAMState {
uint8_t data[0x2000];
};
/* Direct access to NVRAM */
uint32_t macio_nvram_read (void *opaque, uint32_t addr)
{
MacIONVRAMState *s = opaque;
uint32_t ret;
// printf("%s: %p addr %04x\n", __func__, s, addr);
if (addr < 0x2000)
ret = s->data[addr];
else
ret = -1;
return ret;
}
void macio_nvram_write (void *opaque, uint32_t addr, uint32_t val)
{
MacIONVRAMState *s = opaque;
// printf("%s: %p addr %04x val %02x\n", __func__, s, addr, val);
if (addr < 0x2000)
s->data[addr] = val;
}
/* macio style NVRAM device */
static void macio_nvram_writeb (void *opaque,
target_phys_addr_t addr, uint32_t value)
{
MacIONVRAMState *s = opaque;
addr = (addr >> 4) & 0x1fff;
s->data[addr] = value;
// printf("macio_nvram_writeb %04x = %02x\n", addr, value);
}
static uint32_t macio_nvram_readb (void *opaque, target_phys_addr_t addr)
{
MacIONVRAMState *s = opaque;
uint32_t value;
addr = (addr >> 4) & 0x1fff;
value = s->data[addr];
// printf("macio_nvram_readb %04x = %02x\n", addr, value);
return value;
}
static CPUWriteMemoryFunc *nvram_write[] = {
&macio_nvram_writeb,
&macio_nvram_writeb,
&macio_nvram_writeb,
};
static CPUReadMemoryFunc *nvram_read[] = {
&macio_nvram_readb,
&macio_nvram_readb,
&macio_nvram_readb,
};
MacIONVRAMState *macio_nvram_init (int *mem_index)
{
MacIONVRAMState *s;
s = qemu_mallocz(sizeof(MacIONVRAMState));
if (!s)
return NULL;
*mem_index = cpu_register_io_memory(0, nvram_read, nvram_write, s);
return s;
}
static uint8_t nvram_chksum (const uint8_t *buf, int n)
{
int sum, i;
sum = 0;
for(i = 0; i < n; i++)
sum += buf[i];
return (sum & 0xff) + (sum >> 8);
}
/* set a free Mac OS NVRAM partition */
void pmac_format_nvram_partition (MacIONVRAMState *nvr, int len)
{
uint8_t *buf;
char partition_name[12] = "wwwwwwwwwwww";
buf = nvr->data;
buf[0] = 0x7f; /* free partition magic */
buf[1] = 0; /* checksum */
buf[2] = len >> 8;
buf[3] = len;
memcpy(buf + 4, partition_name, 12);
buf[1] = nvram_chksum(buf, 16);
}

116
hw/macio.c Normal file
View file

@ -0,0 +1,116 @@
/*
* PowerMac MacIO device emulation
*
* Copyright (c) 2005-2007 Fabrice Bellard
* Copyright (c) 2007 Jocelyn Mayer
*
* 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"
#include "ppc_mac.h"
typedef struct macio_state_t macio_state_t;
struct macio_state_t {
int is_oldworld;
int pic_mem_index;
int dbdma_mem_index;
int cuda_mem_index;
int nvram_mem_index;
int nb_ide;
int ide_mem_index[4];
};
static void macio_map (PCIDevice *pci_dev, int region_num,
uint32_t addr, uint32_t size, int type)
{
macio_state_t *macio_state;
int i;
macio_state = (macio_state_t *)(pci_dev + 1);
if (macio_state->pic_mem_index >= 0) {
if (macio_state->is_oldworld) {
/* Heathrow PIC */
cpu_register_physical_memory(addr + 0x00000, 0x1000,
macio_state->pic_mem_index);
} else {
/* OpenPIC */
cpu_register_physical_memory(addr + 0x40000, 0x40000,
macio_state->pic_mem_index);
}
}
if (macio_state->dbdma_mem_index >= 0) {
cpu_register_physical_memory(addr + 0x08000, 0x1000,
macio_state->dbdma_mem_index);
}
if (macio_state->cuda_mem_index >= 0) {
cpu_register_physical_memory(addr + 0x16000, 0x2000,
macio_state->cuda_mem_index);
}
for (i = 0; i < macio_state->nb_ide; i++) {
if (macio_state->ide_mem_index[i] >= 0) {
cpu_register_physical_memory(addr + 0x1f000 + (i * 0x1000), 0x1000,
macio_state->ide_mem_index[i]);
}
}
if (macio_state->nvram_mem_index >= 0) {
cpu_register_physical_memory(addr + 0x60000, 0x20000,
macio_state->nvram_mem_index);
}
}
void macio_init (PCIBus *bus, int device_id, int is_oldworld, int pic_mem_index,
int dbdma_mem_index, int cuda_mem_index, int nvram_mem_index,
int nb_ide, int *ide_mem_index)
{
PCIDevice *d;
macio_state_t *macio_state;
int i;
d = pci_register_device(bus, "macio",
sizeof(PCIDevice) + sizeof(macio_state_t),
-1, NULL, NULL);
macio_state = (macio_state_t *)(d + 1);
macio_state->is_oldworld = is_oldworld;
macio_state->pic_mem_index = pic_mem_index;
macio_state->dbdma_mem_index = dbdma_mem_index;
macio_state->cuda_mem_index = cuda_mem_index;
macio_state->nvram_mem_index = nvram_mem_index;
if (nb_ide > 4)
nb_ide = 4;
macio_state->nb_ide = nb_ide;
for (i = 0; i < nb_ide; i++)
macio_state->ide_mem_index[i] = ide_mem_index[i];
for (; i < 4; i++)
macio_state->ide_mem_index[i] = -1;
/* Note: this code is strongly inspirated from the corresponding code
in PearPC */
d->config[0x00] = 0x6b; // vendor_id
d->config[0x01] = 0x10;
d->config[0x02] = device_id;
d->config[0x03] = device_id >> 8;
d->config[0x0a] = 0x00; // class_sub = pci2pci
d->config[0x0b] = 0xff; // class_base = bridge
d->config[0x0e] = 0x00; // header_type
d->config[0x3d] = 0x01; // interrupt on pin 1
pci_register_io_region(d, 0, 0x80000,
PCI_ADDRESS_SPACE_MEM, macio_map);
}

View file

@ -22,7 +22,6 @@
* THE SOFTWARE.
*/
#include "vl.h"
#include "m48t59.h"
//#define PPC_DEBUG_IRQ
//#define PPC_DEBUG_TB
@ -1240,63 +1239,75 @@ void PPC_debug_write (void *opaque, uint32_t addr, uint32_t val)
/*****************************************************************************/
/* NVRAM helpers */
void NVRAM_set_byte (m48t59_t *nvram, uint32_t addr, uint8_t value)
static inline uint32_t nvram_read (nvram_t *nvram, uint32_t addr)
{
m48t59_write(nvram, addr, value);
return (*nvram->read_fn)(nvram->opaque, addr);;
}
uint8_t NVRAM_get_byte (m48t59_t *nvram, uint32_t addr)
static inline void nvram_write (nvram_t *nvram, uint32_t addr, uint32_t val)
{
return m48t59_read(nvram, addr);
(*nvram->write_fn)(nvram->opaque, addr, val);
}
void NVRAM_set_word (m48t59_t *nvram, uint32_t addr, uint16_t value)
void NVRAM_set_byte (nvram_t *nvram, uint32_t addr, uint8_t value)
{
m48t59_write(nvram, addr, value >> 8);
m48t59_write(nvram, addr + 1, value & 0xFF);
nvram_write(nvram, addr, value);
}
uint16_t NVRAM_get_word (m48t59_t *nvram, uint32_t addr)
uint8_t NVRAM_get_byte (nvram_t *nvram, uint32_t addr)
{
return nvram_read(nvram, addr);
}
void NVRAM_set_word (nvram_t *nvram, uint32_t addr, uint16_t value)
{
nvram_write(nvram, addr, value >> 8);
nvram_write(nvram, addr + 1, value & 0xFF);
}
uint16_t NVRAM_get_word (nvram_t *nvram, uint32_t addr)
{
uint16_t tmp;
tmp = m48t59_read(nvram, addr) << 8;
tmp |= m48t59_read(nvram, addr + 1);
tmp = nvram_read(nvram, addr) << 8;
tmp |= nvram_read(nvram, addr + 1);
return tmp;
}
void NVRAM_set_lword (m48t59_t *nvram, uint32_t addr, uint32_t value)
void NVRAM_set_lword (nvram_t *nvram, uint32_t addr, uint32_t value)
{
m48t59_write(nvram, addr, value >> 24);
m48t59_write(nvram, addr + 1, (value >> 16) & 0xFF);
m48t59_write(nvram, addr + 2, (value >> 8) & 0xFF);
m48t59_write(nvram, addr + 3, value & 0xFF);
nvram_write(nvram, addr, value >> 24);
nvram_write(nvram, addr + 1, (value >> 16) & 0xFF);
nvram_write(nvram, addr + 2, (value >> 8) & 0xFF);
nvram_write(nvram, addr + 3, value & 0xFF);
}
uint32_t NVRAM_get_lword (m48t59_t *nvram, uint32_t addr)
uint32_t NVRAM_get_lword (nvram_t *nvram, uint32_t addr)
{
uint32_t tmp;
tmp = m48t59_read(nvram, addr) << 24;
tmp |= m48t59_read(nvram, addr + 1) << 16;
tmp |= m48t59_read(nvram, addr + 2) << 8;
tmp |= m48t59_read(nvram, addr + 3);
tmp = nvram_read(nvram, addr) << 24;
tmp |= nvram_read(nvram, addr + 1) << 16;
tmp |= nvram_read(nvram, addr + 2) << 8;
tmp |= nvram_read(nvram, addr + 3);
return tmp;
}
void NVRAM_set_string (m48t59_t *nvram, uint32_t addr,
void NVRAM_set_string (nvram_t *nvram, uint32_t addr,
const unsigned char *str, uint32_t max)
{
int i;
for (i = 0; i < max && str[i] != '\0'; i++) {
m48t59_write(nvram, addr + i, str[i]);
nvram_write(nvram, addr + i, str[i]);
}
m48t59_write(nvram, addr + max - 1, '\0');
nvram_write(nvram, addr + i, str[i]);
nvram_write(nvram, addr + max - 1, '\0');
}
int NVRAM_get_string (m48t59_t *nvram, uint8_t *dst, uint16_t addr, int max)
int NVRAM_get_string (nvram_t *nvram, uint8_t *dst, uint16_t addr, int max)
{
int i;
@ -1325,7 +1336,7 @@ static uint16_t NVRAM_crc_update (uint16_t prev, uint16_t value)
return tmp;
}
uint16_t NVRAM_compute_crc (m48t59_t *nvram, uint32_t start, uint32_t count)
uint16_t NVRAM_compute_crc (nvram_t *nvram, uint32_t start, uint32_t count)
{
uint32_t i;
uint16_t crc = 0xFFFF;
@ -1345,7 +1356,7 @@ uint16_t NVRAM_compute_crc (m48t59_t *nvram, uint32_t start, uint32_t count)
#define CMDLINE_ADDR 0x017ff000
int PPC_NVRAM_set_params (m48t59_t *nvram, uint16_t NVRAM_size,
int PPC_NVRAM_set_params (nvram_t *nvram, uint16_t NVRAM_size,
const unsigned char *arch,
uint32_t RAM_size, int boot_device,
uint32_t kernel_image, uint32_t kernel_size,
@ -1382,7 +1393,7 @@ int PPC_NVRAM_set_params (m48t59_t *nvram, uint16_t NVRAM_size,
NVRAM_set_word(nvram, 0x56, height);
NVRAM_set_word(nvram, 0x58, depth);
crc = NVRAM_compute_crc(nvram, 0x00, 0xF8);
NVRAM_set_word(nvram, 0xFC, crc);
NVRAM_set_word(nvram, 0xFC, crc);
return 0;
}

View file

@ -1,7 +1,8 @@
/*
* QEMU PPC CHRP/PMAC hardware System Emulator
* QEMU PowerPC CHRP (currently NewWorld PowerMac) hardware System Emulator
*
* Copyright (c) 2004-2007 Fabrice Bellard
* Copyright (c) 2007 Jocelyn Mayer
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
@ -22,171 +23,7 @@
* THE SOFTWARE.
*/
#include "vl.h"
/* SMP is not enabled, for now */
#define MAX_CPUS 1
#define BIOS_FILENAME "ppc_rom.bin"
#define VGABIOS_FILENAME "video.x"
#define NVRAM_SIZE 0x2000
#define KERNEL_LOAD_ADDR 0x01000000
#define INITRD_LOAD_ADDR 0x01800000
/* MacIO devices (mapped inside the MacIO address space): CUDA, DBDMA,
NVRAM */
static int dbdma_mem_index;
static int cuda_mem_index;
static int ide0_mem_index = -1;
static int ide1_mem_index = -1;
static int openpic_mem_index = -1;
static int heathrow_pic_mem_index = -1;
static int macio_nvram_mem_index = -1;
/* DBDMA: currently no op - should suffice right now */
static void dbdma_writeb (void *opaque,
target_phys_addr_t addr, uint32_t value)
{
printf("%s: 0x" PADDRX " <= 0x%08x\n", __func__, addr, value);
}
static void dbdma_writew (void *opaque,
target_phys_addr_t addr, uint32_t value)
{
}
static void dbdma_writel (void *opaque,
target_phys_addr_t addr, uint32_t value)
{
}
static uint32_t dbdma_readb (void *opaque, target_phys_addr_t addr)
{
printf("%s: 0x" PADDRX " => 0x00000000\n", __func__, addr);
return 0;
}
static uint32_t dbdma_readw (void *opaque, target_phys_addr_t addr)
{
return 0;
}
static uint32_t dbdma_readl (void *opaque, target_phys_addr_t addr)
{
return 0;
}
static CPUWriteMemoryFunc *dbdma_write[] = {
&dbdma_writeb,
&dbdma_writew,
&dbdma_writel,
};
static CPUReadMemoryFunc *dbdma_read[] = {
&dbdma_readb,
&dbdma_readw,
&dbdma_readl,
};
/* macio style NVRAM device */
typedef struct MacIONVRAMState {
uint8_t data[0x2000];
} MacIONVRAMState;
static void macio_nvram_writeb (void *opaque,
target_phys_addr_t addr, uint32_t value)
{
MacIONVRAMState *s = opaque;
addr = (addr >> 4) & 0x1fff;
s->data[addr] = value;
// printf("macio_nvram_writeb %04x = %02x\n", addr, value);
}
static uint32_t macio_nvram_readb (void *opaque, target_phys_addr_t addr)
{
MacIONVRAMState *s = opaque;
uint32_t value;
addr = (addr >> 4) & 0x1fff;
value = s->data[addr];
// printf("macio_nvram_readb %04x = %02x\n", addr, value);
return value;
}
static CPUWriteMemoryFunc *macio_nvram_write[] = {
&macio_nvram_writeb,
&macio_nvram_writeb,
&macio_nvram_writeb,
};
static CPUReadMemoryFunc *macio_nvram_read[] = {
&macio_nvram_readb,
&macio_nvram_readb,
&macio_nvram_readb,
};
static MacIONVRAMState *macio_nvram_init (void)
{
MacIONVRAMState *s;
s = qemu_mallocz(sizeof(MacIONVRAMState));
if (!s)
return NULL;
macio_nvram_mem_index = cpu_register_io_memory(0, macio_nvram_read,
macio_nvram_write, s);
return s;
}
static void macio_map (PCIDevice *pci_dev, int region_num,
uint32_t addr, uint32_t size, int type)
{
if (heathrow_pic_mem_index >= 0) {
cpu_register_physical_memory(addr + 0x00000, 0x1000,
heathrow_pic_mem_index);
}
cpu_register_physical_memory(addr + 0x08000, 0x1000, dbdma_mem_index);
cpu_register_physical_memory(addr + 0x16000, 0x2000, cuda_mem_index);
if (ide0_mem_index >= 0)
cpu_register_physical_memory(addr + 0x1f000, 0x1000, ide0_mem_index);
if (ide1_mem_index >= 0)
cpu_register_physical_memory(addr + 0x20000, 0x1000, ide1_mem_index);
if (openpic_mem_index >= 0) {
cpu_register_physical_memory(addr + 0x40000, 0x40000,
openpic_mem_index);
}
if (macio_nvram_mem_index >= 0)
cpu_register_physical_memory(addr + 0x60000, 0x20000,
macio_nvram_mem_index);
}
static void macio_init (PCIBus *bus, int device_id)
{
PCIDevice *d;
d = pci_register_device(bus, "macio", sizeof(PCIDevice),
-1, NULL, NULL);
/* Note: this code is strongly inspirated from the corresponding code
in PearPC */
d->config[0x00] = 0x6b; // vendor_id
d->config[0x01] = 0x10;
d->config[0x02] = device_id;
d->config[0x03] = device_id >> 8;
d->config[0x0a] = 0x00; // class_sub = pci2pci
d->config[0x0b] = 0xff; // class_base = bridge
d->config[0x0e] = 0x00; // header_type
d->config[0x3d] = 0x01; // interrupt on pin 1
dbdma_mem_index = cpu_register_io_memory(0, dbdma_read, dbdma_write, NULL);
pci_register_io_region(d, 0, 0x80000,
PCI_ADDRESS_SPACE_MEM, macio_map);
}
#include "ppc_mac.h"
/* UniN device */
static void unin_writel (void *opaque, target_phys_addr_t addr, uint32_t value)
@ -210,118 +47,34 @@ static CPUReadMemoryFunc *unin_read[] = {
&unin_readl,
};
/* temporary frame buffer OSI calls for the video.x driver. The right
solution is to modify the driver to use VGA PCI I/Os */
/* XXX: to be removed. This is no way related to emulation */
static int vga_osi_call (CPUState *env)
{
static int vga_vbl_enabled;
int linesize;
// printf("osi_call R5=%d\n", env->gpr[5]);
/* same handler as PearPC, coming from the original MOL video
driver. */
switch(env->gpr[5]) {
case 4:
break;
case 28: /* set_vmode */
if (env->gpr[6] != 1 || env->gpr[7] != 0)
env->gpr[3] = 1;
else
env->gpr[3] = 0;
break;
case 29: /* get_vmode_info */
if (env->gpr[6] != 0) {
if (env->gpr[6] != 1 || env->gpr[7] != 0) {
env->gpr[3] = 1;
break;
}
}
env->gpr[3] = 0;
env->gpr[4] = (1 << 16) | 1; /* num_vmodes, cur_vmode */
env->gpr[5] = (1 << 16) | 0; /* num_depths, cur_depth_mode */
env->gpr[6] = (graphic_width << 16) | graphic_height; /* w, h */
env->gpr[7] = 85 << 16; /* refresh rate */
env->gpr[8] = (graphic_depth + 7) & ~7; /* depth (round to byte) */
linesize = ((graphic_depth + 7) >> 3) * graphic_width;
linesize = (linesize + 3) & ~3;
env->gpr[9] = (linesize << 16) | 0; /* row_bytes, offset */
break;
case 31: /* set_video power */
env->gpr[3] = 0;
break;
case 39: /* video_ctrl */
if (env->gpr[6] == 0 || env->gpr[6] == 1)
vga_vbl_enabled = env->gpr[6];
env->gpr[3] = 0;
break;
case 47:
break;
case 59: /* set_color */
/* R6 = index, R7 = RGB */
env->gpr[3] = 0;
break;
case 64: /* get color */
/* R6 = index */
env->gpr[3] = 0;
break;
case 116: /* set hwcursor */
/* R6 = x, R7 = y, R8 = visible, R9 = data */
break;
default:
fprintf(stderr, "unsupported OSI call R5=" REGX "\n", env->gpr[5]);
break;
}
return 1; /* osi_call handled */
}
static uint8_t nvram_chksum (const uint8_t *buf, int n)
{
int sum, i;
sum = 0;
for(i = 0; i < n; i++)
sum += buf[i];
return (sum & 0xff) + (sum >> 8);
}
/* set a free Mac OS NVRAM partition */
void pmac_format_nvram_partition (uint8_t *buf, int len)
{
char partition_name[12] = "wwwwwwwwwwww";
buf[0] = 0x7f; /* free partition magic */
buf[1] = 0; /* checksum */
buf[2] = len >> 8;
buf[3] = len;
memcpy(buf + 4, partition_name, 12);
buf[1] = nvram_chksum(buf, 16);
}
/* PowerPC CHRP hardware initialisation */
static void ppc_chrp_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,
const char *cpu_model,
int is_heathrow)
/* PowerPC Mac99 hardware initialisation */
static void ppc_core99_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,
const char *cpu_model)
{
CPUState *env, *envs[MAX_CPUS];
char buf[1024];
qemu_irq *pic, **openpic_irqs;
m48t59_t *nvram;
int unin_memory;
int linux_boot, i;
unsigned long bios_offset, vga_bios_offset;
uint32_t kernel_base, kernel_size, initrd_base, initrd_size;
ppc_def_t *def;
PCIBus *pci_bus;
const char *arch_name;
nvram_t nvram;
#if 0
MacIONVRAMState *nvr;
int nvram_mem_index;
#endif
m48t59_t *m48t59;
int vga_bios_size, bios_size;
qemu_irq *dummy_irq;
int pic_mem_index, dbdma_mem_index, cuda_mem_index;
int ide_mem_index[2];
linux_boot = (kernel_filename != NULL);
@ -338,7 +91,9 @@ static void ppc_chrp_init (int ram_size, int vga_ram_size, int boot_device,
cpu_ppc_reset(env);
/* Set time-base frequency to 100 Mhz */
cpu_ppc_tb_init(env, 100UL * 1000UL * 1000UL);
#if 0
env->osi_call = vga_osi_call;
#endif
qemu_register_reset(&cpu_ppc_reset, env);
register_savevm("cpu", 0, 3, cpu_save, cpu_load, env);
envs[i] = env;
@ -413,143 +168,91 @@ static void ppc_chrp_init (int ram_size, int vga_ram_size, int boot_device,
initrd_size = 0;
}
if (is_heathrow) {
isa_mem_base = 0x80000000;
isa_mem_base = 0x80000000;
/* Register 2 MB of ISA IO space */
isa_mmio_init(0xfe000000, 0x00200000);
/* Register 8 MB of ISA IO space */
isa_mmio_init(0xf2000000, 0x00800000);
/* init basic PC hardware */
if (PPC_INPUT(env) != PPC_FLAGS_INPUT_6xx) {
cpu_abort(env, "Only 6xx bus is supported on heathrow machine\n");
/* UniN init */
unin_memory = cpu_register_io_memory(0, unin_read, unin_write, NULL);
cpu_register_physical_memory(0xf8000000, 0x00001000, unin_memory);
openpic_irqs = qemu_mallocz(smp_cpus * sizeof(qemu_irq *));
openpic_irqs[0] =
qemu_mallocz(smp_cpus * sizeof(qemu_irq) * OPENPIC_OUTPUT_NB);
for (i = 0; i < smp_cpus; i++) {
/* Mac99 IRQ connection between OpenPIC outputs pins
* and PowerPC input pins
*/
switch (PPC_INPUT(env)) {
case PPC_FLAGS_INPUT_6xx:
openpic_irqs[i] = openpic_irqs[0] + (i * OPENPIC_OUTPUT_NB);
openpic_irqs[i][OPENPIC_OUTPUT_INT] =
((qemu_irq *)env->irq_inputs)[PPC6xx_INPUT_INT];
openpic_irqs[i][OPENPIC_OUTPUT_CINT] =
((qemu_irq *)env->irq_inputs)[PPC6xx_INPUT_INT];
openpic_irqs[i][OPENPIC_OUTPUT_MCK] =
((qemu_irq *)env->irq_inputs)[PPC6xx_INPUT_MCP];
/* Not connected ? */
openpic_irqs[i][OPENPIC_OUTPUT_DEBUG] = NULL;
/* Check this */
openpic_irqs[i][OPENPIC_OUTPUT_RESET] =
((qemu_irq *)env->irq_inputs)[PPC6xx_INPUT_HRESET];
break;
#if defined(TARGET_PPC64)
case PPC_FLAGS_INPUT_970:
openpic_irqs[i] = openpic_irqs[0] + (i * OPENPIC_OUTPUT_NB);
openpic_irqs[i][OPENPIC_OUTPUT_INT] =
((qemu_irq *)env->irq_inputs)[PPC970_INPUT_INT];
openpic_irqs[i][OPENPIC_OUTPUT_CINT] =
((qemu_irq *)env->irq_inputs)[PPC970_INPUT_INT];
openpic_irqs[i][OPENPIC_OUTPUT_MCK] =
((qemu_irq *)env->irq_inputs)[PPC970_INPUT_MCP];
/* Not connected ? */
openpic_irqs[i][OPENPIC_OUTPUT_DEBUG] = NULL;
/* Check this */
openpic_irqs[i][OPENPIC_OUTPUT_RESET] =
((qemu_irq *)env->irq_inputs)[PPC970_INPUT_HRESET];
break;
#endif /* defined(TARGET_PPC64) */
default:
cpu_abort(env, "Bus model not supported on mac99 machine\n");
exit(1);
}
pic = heathrow_pic_init(&heathrow_pic_mem_index);
pci_bus = pci_grackle_init(0xfec00000, pic);
pci_vga_init(pci_bus, ds, phys_ram_base + ram_size,
ram_size, vga_ram_size,
vga_bios_offset, vga_bios_size);
/* XXX: suppress that */
dummy_irq = i8259_init(NULL);
/* XXX: use Mac Serial port */
serial_init(0x3f8, dummy_irq[4], serial_hds[0]);
for(i = 0; i < nb_nics; i++) {
if (!nd_table[i].model)
nd_table[i].model = "ne2k_pci";
pci_nic_init(pci_bus, &nd_table[i], -1);
}
pci_cmd646_ide_init(pci_bus, &bs_table[0], 0);
/* cuda also initialize ADB */
cuda_mem_index = cuda_init(pic[0x12]);
adb_kbd_init(&adb_bus);
adb_mouse_init(&adb_bus);
{
MacIONVRAMState *nvr;
nvr = macio_nvram_init();
pmac_format_nvram_partition(nvr->data, 0x2000);
}
macio_init(pci_bus, 0x0017);
nvram = m48t59_init(dummy_irq[8], 0xFFF04000, 0x0074, NVRAM_SIZE, 59);
arch_name = "HEATHROW";
} else {
isa_mem_base = 0x80000000;
/* Register 8 MB of ISA IO space */
isa_mmio_init(0xf2000000, 0x00800000);
/* UniN init */
unin_memory = cpu_register_io_memory(0, unin_read, unin_write, NULL);
cpu_register_physical_memory(0xf8000000, 0x00001000, unin_memory);
openpic_irqs = qemu_mallocz(smp_cpus * sizeof(qemu_irq *));
openpic_irqs[0] =
qemu_mallocz(smp_cpus * sizeof(qemu_irq) * OPENPIC_OUTPUT_NB);
for (i = 0; i < smp_cpus; i++) {
/* Mac99 IRQ connection between OpenPIC outputs pins
* and PowerPC input pins
*/
switch (PPC_INPUT(env)) {
case PPC_FLAGS_INPUT_6xx:
openpic_irqs[i] = openpic_irqs[0] + (i * OPENPIC_OUTPUT_NB);
openpic_irqs[i][OPENPIC_OUTPUT_INT] =
((qemu_irq *)env->irq_inputs)[PPC6xx_INPUT_INT];
openpic_irqs[i][OPENPIC_OUTPUT_CINT] =
((qemu_irq *)env->irq_inputs)[PPC6xx_INPUT_INT];
openpic_irqs[i][OPENPIC_OUTPUT_MCK] =
((qemu_irq *)env->irq_inputs)[PPC6xx_INPUT_MCP];
/* Not connected ? */
openpic_irqs[i][OPENPIC_OUTPUT_DEBUG] = NULL;
/* Check this */
openpic_irqs[i][OPENPIC_OUTPUT_RESET] =
((qemu_irq *)env->irq_inputs)[PPC6xx_INPUT_HRESET];
break;
#if defined(TARGET_PPC64)
case PPC_FLAGS_INPUT_970:
openpic_irqs[i] = openpic_irqs[0] + (i * OPENPIC_OUTPUT_NB);
openpic_irqs[i][OPENPIC_OUTPUT_INT] =
((qemu_irq *)env->irq_inputs)[PPC970_INPUT_INT];
openpic_irqs[i][OPENPIC_OUTPUT_CINT] =
((qemu_irq *)env->irq_inputs)[PPC970_INPUT_INT];
openpic_irqs[i][OPENPIC_OUTPUT_MCK] =
((qemu_irq *)env->irq_inputs)[PPC970_INPUT_MCP];
/* Not connected ? */
openpic_irqs[i][OPENPIC_OUTPUT_DEBUG] = NULL;
/* Check this */
openpic_irqs[i][OPENPIC_OUTPUT_RESET] =
((qemu_irq *)env->irq_inputs)[PPC970_INPUT_HRESET];
break;
#endif /* defined(TARGET_PPC64) */
default:
cpu_abort(env, "Bus model not supported on mac99 machine\n");
exit(1);
}
}
pic = openpic_init(NULL, &openpic_mem_index, smp_cpus,
openpic_irqs, NULL);
pci_bus = pci_pmac_init(pic);
/* init basic PC hardware */
pci_vga_init(pci_bus, ds, phys_ram_base + ram_size,
ram_size, vga_ram_size,
vga_bios_offset, vga_bios_size);
/* XXX: suppress that */
dummy_irq = i8259_init(NULL);
/* XXX: use Mac Serial port */
serial_init(0x3f8, dummy_irq[4], serial_hds[0]);
for(i = 0; i < nb_nics; i++) {
if (!nd_table[i].model)
nd_table[i].model = "ne2k_pci";
pci_nic_init(pci_bus, &nd_table[i], -1);
}
#if 1
ide0_mem_index = pmac_ide_init(&bs_table[0], pic[0x13]);
ide1_mem_index = pmac_ide_init(&bs_table[2], pic[0x14]);
#else
pci_cmd646_ide_init(pci_bus, &bs_table[0], 0);
#endif
/* cuda also initialize ADB */
cuda_mem_index = cuda_init(pic[0x19]);
adb_kbd_init(&adb_bus);
adb_mouse_init(&adb_bus);
macio_init(pci_bus, 0x0022);
nvram = m48t59_init(dummy_irq[8], 0xFFF04000, 0x0074, NVRAM_SIZE, 59);
arch_name = "MAC99";
}
pic = openpic_init(NULL, &pic_mem_index, smp_cpus, openpic_irqs, NULL);
pci_bus = pci_pmac_init(pic);
/* init basic PC hardware */
pci_vga_init(pci_bus, ds, phys_ram_base + ram_size,
ram_size, vga_ram_size,
vga_bios_offset, vga_bios_size);
/* XXX: suppress that */
dummy_irq = i8259_init(NULL);
/* XXX: use Mac Serial port */
serial_init(0x3f8, dummy_irq[4], serial_hds[0]);
for(i = 0; i < nb_nics; i++) {
if (!nd_table[i].model)
nd_table[i].model = "ne2k_pci";
pci_nic_init(pci_bus, &nd_table[i], -1);
}
#if 1
ide_mem_index[0] = pmac_ide_init(&bs_table[0], pic[0x13]);
ide_mem_index[1] = pmac_ide_init(&bs_table[2], pic[0x14]);
#else
pci_cmd646_ide_init(pci_bus, &bs_table[0], 0);
#endif
/* cuda also initialize ADB */
cuda_init(&cuda_mem_index, pic[0x19]);
adb_kbd_init(&adb_bus);
adb_mouse_init(&adb_bus);
dbdma_init(&dbdma_mem_index);
macio_init(pci_bus, 0x0022, 0, pic_mem_index, dbdma_mem_index,
cuda_mem_index, -1, 2, ide_mem_index);
if (usb_enabled) {
usb_ohci_init_pci(pci_bus, 3, -1);
@ -557,8 +260,21 @@ static void ppc_chrp_init (int ram_size, int vga_ram_size, int boot_device,
if (graphic_depth != 15 && graphic_depth != 32 && graphic_depth != 8)
graphic_depth = 15;
PPC_NVRAM_set_params(nvram, NVRAM_SIZE, arch_name, ram_size, boot_device,
#if 0 /* XXX: this is ugly but needed for now, or OHW won't boot */
/* The NewWorld NVRAM is not located in the MacIO device */
nvr = macio_nvram_init(&nvram_mem_index);
pmac_format_nvram_partition(nvr, 0x2000);
cpu_register_physical_memory(0xFFF04000, 0x20000, nvram_mem_index);
nvram.opaque = nvr;
nvram.read_fn = &macio_nvram_read;
nvram.write_fn = &macio_nvram_write;
#else
m48t59 = m48t59_init(dummy_irq[8], 0xFFF04000, 0x0074, NVRAM_SIZE, 59);
nvram.opaque = m48t59;
nvram.read_fn = &m48t59_read;
nvram.write_fn = &m48t59_write;
#endif
PPC_NVRAM_set_params(&nvram, NVRAM_SIZE, "MAC99", ram_size, boot_device,
kernel_base, kernel_size,
kernel_cmdline,
initrd_base, initrd_size,
@ -569,44 +285,10 @@ static void ppc_chrp_init (int ram_size, int vga_ram_size, int boot_device,
/* Special port to get debug messages from Open-Firmware */
register_ioport_write(0x0F00, 4, 1, &PPC_debug_write, NULL);
}
static void ppc_core99_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,
const char *cpu_model)
{
ppc_chrp_init(ram_size, vga_ram_size, boot_device,
ds, fd_filename, snapshot,
kernel_filename, kernel_cmdline,
initrd_filename, cpu_model, 0);
}
static void ppc_heathrow_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,
const char *cpu_model)
{
ppc_chrp_init(ram_size, vga_ram_size, boot_device,
ds, fd_filename, snapshot,
kernel_filename, kernel_cmdline,
initrd_filename, cpu_model, 1);
}
}
QEMUMachine core99_machine = {
"mac99",
"Mac99 based PowerMAC",
ppc_core99_init,
};
QEMUMachine heathrow_machine = {
"g3bw",
"Heathrow based PowerMAC",
ppc_heathrow_init,
};

70
hw/ppc_mac.h Normal file
View file

@ -0,0 +1,70 @@
/*
* QEMU PowerMac emulation shared definitions and prototypes
*
* Copyright (c) 2004-2007 Fabrice Bellard
* Copyright (c) 2007 Jocelyn Mayer
*
* 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.
*/
#if !defined(__PPC_MAC_H__)
#define __PPC_MAC_H__
/* SMP is not enabled, for now */
#define MAX_CPUS 1
#define BIOS_FILENAME "ppc_rom.bin"
#define VGABIOS_FILENAME "video.x"
#define NVRAM_SIZE 0x2000
#define KERNEL_LOAD_ADDR 0x01000000
#define INITRD_LOAD_ADDR 0x01800000
/* DBDMA */
void dbdma_init (int *dbdma_mem_index);
/* Cuda */
void cuda_init (int *cuda_mem_index, qemu_irq irq);
/* MacIO */
void macio_init (PCIBus *bus, int device_id, int is_oldworld, int pic_mem_index,
int dbdma_mem_index, int cuda_mem_index, int nvram_mem_index,
int nb_ide, int *ide_mem_index);
/* NewWorld PowerMac IDE */
int pmac_ide_init (BlockDriverState **hd_table, qemu_irq irq);
/* Heathrow PIC */
qemu_irq *heathrow_pic_init(int *pmem_index,
int nb_cpus, qemu_irq **irqs);
/* Grackle PCI */
PCIBus *pci_grackle_init(uint32_t base, qemu_irq *pic);
/* UniNorth PCI */
PCIBus *pci_pmac_init(qemu_irq *pic);
/* Mac NVRAM */
typedef struct MacIONVRAMState MacIONVRAMState;
MacIONVRAMState *macio_nvram_init (int *mem_index);
void pmac_format_nvram_partition (MacIONVRAMState *nvr, int len);
uint32_t macio_nvram_read (void *opaque, uint32_t addr);
void macio_nvram_write (void *opaque, uint32_t addr, uint32_t val);
#endif /* !defined(__PPC_MAC_H__) */

298
hw/ppc_oldworld.c Normal file
View file

@ -0,0 +1,298 @@
/*
* QEMU OldWorld PowerMac (currently ~G3 B&W) hardware System Emulator
*
* Copyright (c) 2004-2007 Fabrice Bellard
* Copyright (c) 2007 Jocelyn Mayer
*
* 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"
#include "ppc_mac.h"
/* temporary frame buffer OSI calls for the video.x driver. The right
solution is to modify the driver to use VGA PCI I/Os */
/* XXX: to be removed. This is no way related to emulation */
static int vga_osi_call (CPUState *env)
{
static int vga_vbl_enabled;
int linesize;
// printf("osi_call R5=%d\n", env->gpr[5]);
/* same handler as PearPC, coming from the original MOL video
driver. */
switch(env->gpr[5]) {
case 4:
break;
case 28: /* set_vmode */
if (env->gpr[6] != 1 || env->gpr[7] != 0)
env->gpr[3] = 1;
else
env->gpr[3] = 0;
break;
case 29: /* get_vmode_info */
if (env->gpr[6] != 0) {
if (env->gpr[6] != 1 || env->gpr[7] != 0) {
env->gpr[3] = 1;
break;
}
}
env->gpr[3] = 0;
env->gpr[4] = (1 << 16) | 1; /* num_vmodes, cur_vmode */
env->gpr[5] = (1 << 16) | 0; /* num_depths, cur_depth_mode */
env->gpr[6] = (graphic_width << 16) | graphic_height; /* w, h */
env->gpr[7] = 85 << 16; /* refresh rate */
env->gpr[8] = (graphic_depth + 7) & ~7; /* depth (round to byte) */
linesize = ((graphic_depth + 7) >> 3) * graphic_width;
linesize = (linesize + 3) & ~3;
env->gpr[9] = (linesize << 16) | 0; /* row_bytes, offset */
break;
case 31: /* set_video power */
env->gpr[3] = 0;
break;
case 39: /* video_ctrl */
if (env->gpr[6] == 0 || env->gpr[6] == 1)
vga_vbl_enabled = env->gpr[6];
env->gpr[3] = 0;
break;
case 47:
break;
case 59: /* set_color */
/* R6 = index, R7 = RGB */
env->gpr[3] = 0;
break;
case 64: /* get color */
/* R6 = index */
env->gpr[3] = 0;
break;
case 116: /* set hwcursor */
/* R6 = x, R7 = y, R8 = visible, R9 = data */
break;
default:
fprintf(stderr, "unsupported OSI call R5=" REGX "\n", env->gpr[5]);
break;
}
return 1; /* osi_call handled */
}
static void ppc_heathrow_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,
const char *cpu_model)
{
CPUState *env, *envs[MAX_CPUS];
char buf[1024];
qemu_irq *pic, **heathrow_irqs;
nvram_t nvram;
m48t59_t *m48t59;
int linux_boot, i;
unsigned long bios_offset, vga_bios_offset;
uint32_t kernel_base, kernel_size, initrd_base, initrd_size;
ppc_def_t *def;
PCIBus *pci_bus;
MacIONVRAMState *nvr;
int vga_bios_size, bios_size;
qemu_irq *dummy_irq;
int pic_mem_index, nvram_mem_index, dbdma_mem_index, cuda_mem_index;
linux_boot = (kernel_filename != NULL);
/* init CPUs */
env = cpu_init();
if (cpu_model == NULL)
cpu_model = "default";
ppc_find_by_name(cpu_model, &def);
if (def == NULL) {
cpu_abort(env, "Unable to find PowerPC CPU definition\n");
}
for (i = 0; i < smp_cpus; i++) {
cpu_ppc_register(env, def);
cpu_ppc_reset(env);
/* Set time-base frequency to 100 Mhz */
cpu_ppc_tb_init(env, 100UL * 1000UL * 1000UL);
env->osi_call = vga_osi_call;
qemu_register_reset(&cpu_ppc_reset, env);
register_savevm("cpu", 0, 3, cpu_save, cpu_load, env);
envs[i] = env;
}
/* allocate RAM */
cpu_register_physical_memory(0, ram_size, IO_MEM_RAM);
/* allocate and load BIOS */
bios_offset = ram_size + vga_ram_size;
if (bios_name == NULL)
bios_name = BIOS_FILENAME;
snprintf(buf, sizeof(buf), "%s/%s", bios_dir, bios_name);
bios_size = load_image(buf, phys_ram_base + bios_offset);
if (bios_size < 0 || bios_size > BIOS_SIZE) {
cpu_abort(env, "qemu: could not load PowerPC bios '%s'\n", buf);
exit(1);
}
bios_size = (bios_size + 0xfff) & ~0xfff;
cpu_register_physical_memory((uint32_t)(-bios_size),
bios_size, bios_offset | IO_MEM_ROM);
/* allocate and load VGA BIOS */
vga_bios_offset = bios_offset + bios_size;
snprintf(buf, sizeof(buf), "%s/%s", bios_dir, VGABIOS_FILENAME);
vga_bios_size = load_image(buf, phys_ram_base + vga_bios_offset + 8);
if (vga_bios_size < 0) {
/* if no bios is present, we can still work */
fprintf(stderr, "qemu: warning: could not load VGA bios '%s'\n", buf);
vga_bios_size = 0;
} else {
/* set a specific header (XXX: find real Apple format for NDRV
drivers) */
phys_ram_base[vga_bios_offset] = 'N';
phys_ram_base[vga_bios_offset + 1] = 'D';
phys_ram_base[vga_bios_offset + 2] = 'R';
phys_ram_base[vga_bios_offset + 3] = 'V';
cpu_to_be32w((uint32_t *)(phys_ram_base + vga_bios_offset + 4),
vga_bios_size);
vga_bios_size += 8;
}
vga_bios_size = (vga_bios_size + 0xfff) & ~0xfff;
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);
if (kernel_size < 0) {
cpu_abort(env, "qemu: could not load kernel '%s'\n",
kernel_filename);
exit(1);
}
/* load initrd */
if (initrd_filename) {
initrd_base = INITRD_LOAD_ADDR;
initrd_size = load_image(initrd_filename,
phys_ram_base + initrd_base);
if (initrd_size < 0) {
cpu_abort(env, "qemu: could not load initial ram disk '%s'\n",
initrd_filename);
exit(1);
}
} else {
initrd_base = 0;
initrd_size = 0;
}
boot_device = 'm';
} else {
kernel_base = 0;
kernel_size = 0;
initrd_base = 0;
initrd_size = 0;
}
isa_mem_base = 0x80000000;
/* Register 2 MB of ISA IO space */
isa_mmio_init(0xfe000000, 0x00200000);
/* XXX: we register only 1 output pin for heathrow PIC */
heathrow_irqs = qemu_mallocz(smp_cpus * sizeof(qemu_irq *));
heathrow_irqs[0] =
qemu_mallocz(smp_cpus * sizeof(qemu_irq) * 1);
/* Connect the heathrow PIC outputs to the 6xx bus */
for (i = 0; i < smp_cpus; i++) {
switch (PPC_INPUT(env)) {
case PPC_FLAGS_INPUT_6xx:
heathrow_irqs[i] = heathrow_irqs[0] + (i * 1);
heathrow_irqs[i][0] =
((qemu_irq *)env->irq_inputs)[PPC6xx_INPUT_INT];
break;
default:
cpu_abort(env, "Bus model not supported on OldWorld Mac machine\n");
exit(1);
}
}
/* init basic PC hardware */
if (PPC_INPUT(env) != PPC_FLAGS_INPUT_6xx) {
cpu_abort(env, "Only 6xx bus is supported on heathrow machine\n");
exit(1);
}
pic = heathrow_pic_init(&pic_mem_index, 1, heathrow_irqs);
pci_bus = pci_grackle_init(0xfec00000, pic);
pci_vga_init(pci_bus, ds, phys_ram_base + ram_size,
ram_size, vga_ram_size,
vga_bios_offset, vga_bios_size);
/* XXX: suppress that */
dummy_irq = i8259_init(NULL);
/* XXX: use Mac Serial port */
serial_init(0x3f8, dummy_irq[4], serial_hds[0]);
for(i = 0; i < nb_nics; i++) {
if (!nd_table[i].model)
nd_table[i].model = "ne2k_pci";
pci_nic_init(pci_bus, &nd_table[i], -1);
}
pci_cmd646_ide_init(pci_bus, &bs_table[0], 0);
/* cuda also initialize ADB */
cuda_init(&cuda_mem_index, pic[0x12]);
adb_kbd_init(&adb_bus);
adb_mouse_init(&adb_bus);
nvr = macio_nvram_init(&nvram_mem_index);
pmac_format_nvram_partition(nvr, 0x2000);
dbdma_init(&dbdma_mem_index);
macio_init(pci_bus, 0x0017, 1, pic_mem_index, dbdma_mem_index,
cuda_mem_index, nvram_mem_index, 0, NULL);
if (usb_enabled) {
usb_ohci_init_pci(pci_bus, 3, -1);
}
if (graphic_depth != 15 && graphic_depth != 32 && graphic_depth != 8)
graphic_depth = 15;
m48t59 = m48t59_init(dummy_irq[8], 0xFFF04000, 0x0074, NVRAM_SIZE, 59);
nvram.opaque = m48t59;
nvram.read_fn = &m48t59_read;
nvram.write_fn = &m48t59_write;
PPC_NVRAM_set_params(&nvram, NVRAM_SIZE, "HEATHROW", ram_size, boot_device,
kernel_base, kernel_size,
kernel_cmdline,
initrd_base, initrd_size,
/* XXX: need an option to load a NVRAM image */
0,
graphic_width, graphic_height, graphic_depth);
/* No PCI init: the BIOS will do it */
/* Special port to get debug messages from Open-Firmware */
register_ioport_write(0x0F00, 4, 1, &PPC_debug_write, NULL);
}
QEMUMachine heathrow_machine = {
"g3bw",
"Heathrow based PowerMAC",
ppc_heathrow_init,
};

View file

@ -527,7 +527,8 @@ static void ppc_prep_init (int ram_size, int vga_ram_size, int boot_device,
{
CPUState *env, *envs[MAX_CPUS];
char buf[1024];
m48t59_t *nvram;
nvram_t nvram;
m48t59_t *m48t59;
int PPC_io_memory;
int linux_boot, i, nb_nics1, bios_size;
unsigned long bios_offset;
@ -678,13 +679,16 @@ static void ppc_prep_init (int ram_size, int vga_ram_size, int boot_device,
usb_ohci_init_pci(pci_bus, 3, -1);
}
nvram = m48t59_init(i8259[8], 0, 0x0074, NVRAM_SIZE, 59);
if (nvram == NULL)
m48t59 = m48t59_init(i8259[8], 0, 0x0074, NVRAM_SIZE, 59);
if (m48t59 == NULL)
return;
sysctrl->nvram = nvram;
sysctrl->nvram = m48t59;
/* Initialise NVRAM */
PPC_NVRAM_set_params(nvram, NVRAM_SIZE, "PREP", ram_size, boot_device,
nvram.opaque = m48t59;
nvram.read_fn = &m48t59_read;
nvram.write_fn = &m48t59_write;
PPC_NVRAM_set_params(&nvram, NVRAM_SIZE, "PREP", ram_size, boot_device,
kernel_base, kernel_size,
kernel_cmdline,
initrd_base, initrd_size,

43
vl.h
View file

@ -859,12 +859,6 @@ PCIBus *pci_bridge_init(PCIBus *bus, int devfn, uint32_t id,
/* prep_pci.c */
PCIBus *pci_prep_init(qemu_irq *pic);
/* grackle_pci.c */
PCIBus *pci_grackle_init(uint32_t base, qemu_irq *pic);
/* unin_pci.c */
PCIBus *pci_pmac_init(qemu_irq *pic);
/* apb_pci.c */
PCIBus *pci_apb_init(target_phys_addr_t special_base, target_phys_addr_t mem_base,
qemu_irq *pic);
@ -892,9 +886,6 @@ enum {
qemu_irq *openpic_init (PCIBus *bus, int *pmem_index, int nb_cpus,
qemu_irq **irqs, qemu_irq irq_out);
/* heathrow_pic.c */
qemu_irq *heathrow_pic_init(int *pmem_index);
/* gt64xxx.c */
PCIBus *pci_gt64120_init(qemu_irq *pic);
@ -1004,7 +995,6 @@ void pci_piix3_ide_init(PCIBus *bus, BlockDriverState **hd_table, int devfn,
qemu_irq *pic);
void pci_piix4_ide_init(PCIBus *bus, BlockDriverState **hd_table, int devfn,
qemu_irq *pic);
int pmac_ide_init (BlockDriverState **hd_table, qemu_irq irq);
/* cdrom.c */
int cdrom_read_toc(int nb_sectors, uint8_t *buf, int msf, int start_track);
@ -1242,12 +1232,12 @@ clk_setup_cb ppc_emb_timers_init (CPUState *env, uint32_t freq);
void ppc40x_core_reset (CPUState *env);
void ppc40x_chip_reset (CPUState *env);
void ppc40x_system_reset (CPUState *env);
#endif
void PREP_debug_write (void *opaque, uint32_t addr, uint32_t val);
extern CPUWriteMemoryFunc *PPC_io_write[];
extern CPUReadMemoryFunc *PPC_io_read[];
void PPC_debug_write (void *opaque, uint32_t addr, uint32_t val);
#endif
/* sun4m.c */
extern QEMUMachine ss5_machine, ss10_machine;
@ -1327,20 +1317,28 @@ void cs_init(target_phys_addr_t base, int irq, void *intctl);
extern QEMUMachine sun4u_machine;
/* NVRAM helpers */
typedef uint32_t (*nvram_read_t)(void *private, uint32_t addr);
typedef void (*nvram_write_t)(void *private, uint32_t addr, uint32_t val);
typedef struct nvram_t {
void *opaque;
nvram_read_t read_fn;
nvram_write_t write_fn;
} nvram_t;
#include "hw/m48t59.h"
void NVRAM_set_byte (m48t59_t *nvram, uint32_t addr, uint8_t value);
uint8_t NVRAM_get_byte (m48t59_t *nvram, uint32_t addr);
void NVRAM_set_word (m48t59_t *nvram, uint32_t addr, uint16_t value);
uint16_t NVRAM_get_word (m48t59_t *nvram, uint32_t addr);
void NVRAM_set_lword (m48t59_t *nvram, uint32_t addr, uint32_t value);
uint32_t NVRAM_get_lword (m48t59_t *nvram, uint32_t addr);
void NVRAM_set_string (m48t59_t *nvram, uint32_t addr,
void NVRAM_set_byte (nvram_t *nvram, uint32_t addr, uint8_t value);
uint8_t NVRAM_get_byte (nvram_t *nvram, uint32_t addr);
void NVRAM_set_word (nvram_t *nvram, uint32_t addr, uint16_t value);
uint16_t NVRAM_get_word (nvram_t *nvram, uint32_t addr);
void NVRAM_set_lword (nvram_t *nvram, uint32_t addr, uint32_t value);
uint32_t NVRAM_get_lword (nvram_t *nvram, uint32_t addr);
void NVRAM_set_string (nvram_t *nvram, uint32_t addr,
const unsigned char *str, uint32_t max);
int NVRAM_get_string (m48t59_t *nvram, uint8_t *dst, uint16_t addr, int max);
void NVRAM_set_crc (m48t59_t *nvram, uint32_t addr,
int NVRAM_get_string (nvram_t *nvram, uint8_t *dst, uint16_t addr, int max);
void NVRAM_set_crc (nvram_t *nvram, uint32_t addr,
uint32_t start, uint32_t count);
int PPC_NVRAM_set_params (m48t59_t *nvram, uint16_t NVRAM_size,
int PPC_NVRAM_set_params (nvram_t *nvram, uint16_t NVRAM_size,
const unsigned char *arch,
uint32_t RAM_size, int boot_device,
uint32_t kernel_image, uint32_t kernel_size,
@ -1388,10 +1386,7 @@ ADBDevice *adb_register_device(ADBBusState *s, int devaddr,
void adb_kbd_init(ADBBusState *bus);
void adb_mouse_init(ADBBusState *bus);
/* cuda.c */
extern ADBBusState adb_bus;
int cuda_init(qemu_irq irq);
#include "hw/usb.h"