ppc patch queue 2018-03-06

This pull request supersedes ppc-for-2.12-20180302 which had compile
 problems with some gcc versions.  It also contains a few additional
 patches.
 
 Highlights are:
     * New Sam460ex machine type
     * Yet more fixes related to vcpu id allocation for spapr
     * Numerous macio cleanupsr
     * Some enhancements to the Spectre/Meltdown fixes for pseries,
       allowing use of a better mitigation for indirect branch based
       exploits
     * New pseries machine types with Spectre/Meltdown mitigations
       enabled (stop gap until libvirt and management understands the
       machine options)
     * A handful of other fixes
 -----BEGIN PGP SIGNATURE-----
 
 iQIzBAABCAAdFiEEdfRlhq5hpmzETofcbDjKyiDZs5IFAlqeEnwACgkQbDjKyiDZ
 s5JdZw/+PtrngCvXVKQsPkLzL1cZVPqjrKObTeuQMHolmD/hvSD6nk1XfvLnkvyx
 kuixt4ARv9oEUdE7uy2WrbaBt9JDbrLsIrW+iKXlNCdMzn3ka4Bazd9v/fNiir+0
 IAhi4/KdHZiU6v/niXKSWgRzjtPbCDjDy+qCyo4rFv02UhWlCqr5UyTawN/C7iZO
 YsMEM4aSWOycMuY/kxxn1sBsr3O6apfU64nSVu98fESk6fgXCK0o53O1ajEdR960
 r+oJKv/lOJXCg6xto3qXS7UDbgUslhhxXnawNxOwpmthHu9u8EmyGSujF6UsO6t0
 piUc/VHcOP4LoozaNQbSvxhZe+k6jVOhPGsedhkgtAq2NoM4k9Q2+JbNipZqmW1V
 IkzGM5W8zqvhqw1/YzG/fNnRHKNsq/HPfHb6ZR+i0w+OkOROlt3aXvGwDfOXdrIG
 kkj6oGnFomtrnFSGBXn4p7Vz80+HhgykDuuT78Zx1ob2s4+ylgaDKoFippvJBr1Z
 LrJPVacxnsstXw0RFL3i2dKhHkyWwPxtA1wk4oBPOSIIYn87nB/i6tDgM6TO2aXu
 al48nisiVdlbE6raAQPIJC0euHaWgJjXnP4GK4SqnlFpZVEMI6gFt8B/rf8TqZJK
 ADYS1qT0fkq5cVaC981QldonB7ZE3gk1ee907hOPjnEY/q3pCc8=
 =Rtfm
 -----END PGP SIGNATURE-----

Merge remote-tracking branch 'remotes/dgibson/tags/ppc-for-2.12-20180306' into staging

ppc patch queue 2018-03-06

This pull request supersedes ppc-for-2.12-20180302 which had compile
problems with some gcc versions.  It also contains a few additional
patches.

Highlights are:
    * New Sam460ex machine type
    * Yet more fixes related to vcpu id allocation for spapr
    * Numerous macio cleanupsr
    * Some enhancements to the Spectre/Meltdown fixes for pseries,
      allowing use of a better mitigation for indirect branch based
      exploits
    * New pseries machine types with Spectre/Meltdown mitigations
      enabled (stop gap until libvirt and management understands the
      machine options)
    * A handful of other fixes

# gpg: Signature made Tue 06 Mar 2018 04:01:00 GMT
# gpg:                using RSA key 6C38CACA20D9B392
# gpg: Good signature from "David Gibson <david@gibson.dropbear.id.au>"
# gpg:                 aka "David Gibson (Red Hat) <dgibson@redhat.com>"
# gpg:                 aka "David Gibson (ozlabs.org) <dgibson@ozlabs.org>"
# gpg:                 aka "David Gibson (kernel.org) <dwg@kernel.org>"
# Primary key fingerprint: 75F4 6586 AE61 A66C C44E  87DC 6C38 CACA 20D9 B392

* remotes/dgibson/tags/ppc-for-2.12-20180306: (30 commits)
  PowerPC: Add TS bits into msr_mask
  adb: add trace-events for monitoring keyboard/mouse during bus enumeration
  PPC: e500: Fix duplicate kernel load and device tree overlap
  hw/ppc/spapr,e500: Use new property "stdout-path" for boot console
  ppc/spapr-caps: Define the pseries-2.12-sxxm machine type
  ppc/spapr-caps: Convert cap-ibs to custom spapr-cap
  ppc/spapr-caps: Convert cap-sbbc to custom spapr-cap
  ppc/spapr-caps: Convert cap-cfpc to custom spapr-cap
  ppc/spapr-caps: Add support for custom spapr_capabilities
  target/ppc: Check mask when setting cap_ppc_safe_indirect_branch
  macio: remove macio_init() function
  macio: move setting of CUDA timebase frequency to macio_common_realize()
  mac_newworld: use object link to pass OpenPIC object to macio
  openpic: move OpenPIC state and related definitions to openpic.h
  openpic: move KVM-specific declarations into separate openpic_kvm.h file
  mac_oldworld: use object link to pass heathrow PIC object to macio
  macio: move macio related structures and defines into separate macio.h file
  heathrow: change heathrow_pic_init() to return the heathrow device
  heathrow: convert to trace-events
  heathrow: QOMify heathrow PIC
  ...

Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
This commit is contained in:
Peter Maydell 2018-03-06 10:21:35 +00:00
commit e1ee9ee139
37 changed files with 2534 additions and 574 deletions

3
.gitmodules vendored
View File

@ -43,3 +43,6 @@
[submodule "roms/seabios-hppa"] [submodule "roms/seabios-hppa"]
path = roms/seabios-hppa path = roms/seabios-hppa
url = git://github.com/hdeller/seabios-hppa.git url = git://github.com/hdeller/seabios-hppa.git
[submodule "roms/u-boot-sam460ex"]
path = roms/u-boot-sam460ex
url = git://github.com/zbalaton/u-boot-sam460ex

View File

@ -779,12 +779,12 @@ efi-e1000.rom efi-eepro100.rom efi-ne2k_pci.rom \
efi-pcnet.rom efi-rtl8139.rom efi-virtio.rom \ efi-pcnet.rom efi-rtl8139.rom efi-virtio.rom \
efi-e1000e.rom efi-vmxnet3.rom \ efi-e1000e.rom efi-vmxnet3.rom \
qemu-icon.bmp qemu_logo_no_text.svg \ qemu-icon.bmp qemu_logo_no_text.svg \
bamboo.dtb petalogix-s3adsp1800.dtb petalogix-ml605.dtb \ bamboo.dtb canyonlands.dtb petalogix-s3adsp1800.dtb petalogix-ml605.dtb \
multiboot.bin linuxboot.bin linuxboot_dma.bin kvmvapic.bin \ multiboot.bin linuxboot.bin linuxboot_dma.bin kvmvapic.bin \
s390-ccw.img s390-netboot.img \ s390-ccw.img s390-netboot.img \
spapr-rtas.bin slof.bin skiboot.lid \ spapr-rtas.bin slof.bin skiboot.lid \
palcode-clipper \ palcode-clipper \
u-boot.e500 \ u-boot.e500 u-boot-sam460-20100605.bin \
qemu_vga.ndrv \ qemu_vga.ndrv \
hppa-firmware.img hppa-firmware.img
else else

View File

@ -21,6 +21,8 @@ CONFIG_E500=y
CONFIG_OPENPIC_KVM=$(call land,$(CONFIG_E500),$(CONFIG_KVM)) CONFIG_OPENPIC_KVM=$(call land,$(CONFIG_E500),$(CONFIG_KVM))
CONFIG_PLATFORM_BUS=y CONFIG_PLATFORM_BUS=y
CONFIG_ETSEC=y CONFIG_ETSEC=y
# For Sam460ex
CONFIG_USB_EHCI_SYSBUS=y
CONFIG_SM501=y CONFIG_SM501=y
CONFIG_IDE_SII3112=y CONFIG_IDE_SII3112=y
CONFIG_I2C=y CONFIG_I2C=y

View File

@ -15,6 +15,7 @@ CONFIG_PTIMER=y
CONFIG_I8259=y CONFIG_I8259=y
CONFIG_XILINX=y CONFIG_XILINX=y
CONFIG_XILINX_ETHLITE=y CONFIG_XILINX_ETHLITE=y
CONFIG_USB_EHCI_SYSBUS=y
CONFIG_SM501=y CONFIG_SM501=y
CONFIG_IDE_SII3112=y CONFIG_IDE_SII3112=y
CONFIG_I2C=y CONFIG_I2C=y

View File

@ -258,6 +258,7 @@ static int adb_kbd_request(ADBDevice *d, uint8_t *obuf,
case ADB_CMD_CHANGE_ID_AND_ACT: case ADB_CMD_CHANGE_ID_AND_ACT:
case ADB_CMD_CHANGE_ID_AND_ENABLE: case ADB_CMD_CHANGE_ID_AND_ENABLE:
d->devaddr = buf[1] & 0xf; d->devaddr = buf[1] & 0xf;
trace_adb_kbd_request_change_addr(d->devaddr);
break; break;
default: default:
d->devaddr = buf[1] & 0xf; d->devaddr = buf[1] & 0xf;
@ -269,6 +270,9 @@ static int adb_kbd_request(ADBDevice *d, uint8_t *obuf,
if (buf[2] == 1 || buf[2] == 2 || buf[2] == 3) { if (buf[2] == 1 || buf[2] == 2 || buf[2] == 3) {
d->handler = buf[2]; d->handler = buf[2];
} }
trace_adb_kbd_request_change_addr_and_handler(d->devaddr,
d->handler);
break; break;
} }
} }

View File

@ -118,6 +118,7 @@ static int adb_mouse_request(ADBDevice *d, uint8_t *obuf,
s->dx = 0; s->dx = 0;
s->dy = 0; s->dy = 0;
s->dz = 0; s->dz = 0;
trace_adb_mouse_flush();
return 0; return 0;
} }
@ -138,6 +139,7 @@ static int adb_mouse_request(ADBDevice *d, uint8_t *obuf,
case ADB_CMD_CHANGE_ID_AND_ACT: case ADB_CMD_CHANGE_ID_AND_ACT:
case ADB_CMD_CHANGE_ID_AND_ENABLE: case ADB_CMD_CHANGE_ID_AND_ENABLE:
d->devaddr = buf[1] & 0xf; d->devaddr = buf[1] & 0xf;
trace_adb_mouse_request_change_addr(d->devaddr);
break; break;
default: default:
d->devaddr = buf[1] & 0xf; d->devaddr = buf[1] & 0xf;
@ -155,6 +157,9 @@ static int adb_mouse_request(ADBDevice *d, uint8_t *obuf,
if (buf[2] == 1 || buf[2] == 2) { if (buf[2] == 1 || buf[2] == 2) {
d->handler = buf[2]; d->handler = buf[2];
} }
trace_adb_mouse_request_change_addr_and_handler(d->devaddr,
d->handler);
break; break;
} }
} }

View File

@ -4,10 +4,15 @@
adb_kbd_no_key(void) "Ignoring NO_KEY" adb_kbd_no_key(void) "Ignoring NO_KEY"
adb_kbd_writereg(int reg, uint8_t val) "reg %d val 0x%2.2x" adb_kbd_writereg(int reg, uint8_t val) "reg %d val 0x%2.2x"
adb_kbd_readreg(int reg, uint8_t val0, uint8_t val1) "reg %d obuf[0] 0x%2.2x obuf[1] 0x%2.2x" adb_kbd_readreg(int reg, uint8_t val0, uint8_t val1) "reg %d obuf[0] 0x%2.2x obuf[1] 0x%2.2x"
adb_kbd_request_change_addr(int devaddr) "change addr to 0x%x"
adb_kbd_request_change_addr_and_handler(int devaddr, int handler) "change addr and handler to 0x%x, 0x%x"
# hw/input/adb-mouse.c # hw/input/adb-mouse.c
adb_mouse_flush(void) "flush"
adb_mouse_writereg(int reg, uint8_t val) "reg %d val 0x%2.2x" adb_mouse_writereg(int reg, uint8_t val) "reg %d val 0x%2.2x"
adb_mouse_readreg(int reg, uint8_t val0, uint8_t val1) "reg %d obuf[0] 0x%2.2x obuf[1] 0x%2.2x" adb_mouse_readreg(int reg, uint8_t val0, uint8_t val1) "reg %d obuf[0] 0x%2.2x obuf[1] 0x%2.2x"
adb_mouse_request_change_addr(int devaddr) "change addr to 0x%x"
adb_mouse_request_change_addr_and_handler(int devaddr, int handler) "change addr and handler to 0x%x, 0x%x"
# hw/input/ps2.c # hw/input/ps2.c
ps2_put_keycode(void *opaque, int keycode) "%p keycode 0x%02x" ps2_put_keycode(void *opaque, int keycode) "%p keycode 0x%02x"

View File

@ -25,78 +25,58 @@
#include "qemu/osdep.h" #include "qemu/osdep.h"
#include "hw/hw.h" #include "hw/hw.h"
#include "hw/ppc/mac.h" #include "hw/ppc/mac.h"
#include "hw/intc/heathrow_pic.h"
#include "trace.h"
/* debug PIC */ static inline int heathrow_check_irq(HeathrowPICState *pic)
//#define DEBUG_PIC
#ifdef DEBUG_PIC
#define PIC_DPRINTF(fmt, ...) \
do { printf("PIC: " fmt , ## __VA_ARGS__); } while (0)
#else
#define PIC_DPRINTF(fmt, ...)
#endif
typedef struct HeathrowPIC {
uint32_t events;
uint32_t mask;
uint32_t levels;
uint32_t level_triggered;
} HeathrowPIC;
typedef struct HeathrowPICS {
MemoryRegion mem;
HeathrowPIC pics[2];
qemu_irq *irqs;
} HeathrowPICS;
static inline int check_irq(HeathrowPIC *pic)
{ {
return (pic->events | (pic->levels & pic->level_triggered)) & pic->mask; return (pic->events | (pic->levels & pic->level_triggered)) & pic->mask;
} }
/* update the CPU irq state */ /* update the CPU irq state */
static void heathrow_pic_update(HeathrowPICS *s) static void heathrow_update_irq(HeathrowState *s)
{ {
if (check_irq(&s->pics[0]) || check_irq(&s->pics[1])) { if (heathrow_check_irq(&s->pics[0]) ||
heathrow_check_irq(&s->pics[1])) {
qemu_irq_raise(s->irqs[0]); qemu_irq_raise(s->irqs[0]);
} else { } else {
qemu_irq_lower(s->irqs[0]); qemu_irq_lower(s->irqs[0]);
} }
} }
static void pic_write(void *opaque, hwaddr addr, static void heathrow_write(void *opaque, hwaddr addr,
uint64_t value, unsigned size) uint64_t value, unsigned size)
{ {
HeathrowPICS *s = opaque; HeathrowState *s = opaque;
HeathrowPIC *pic; HeathrowPICState *pic;
unsigned int n; unsigned int n;
n = ((addr & 0xfff) - 0x10) >> 4; n = ((addr & 0xfff) - 0x10) >> 4;
PIC_DPRINTF("writel: " TARGET_FMT_plx " %u: %08x\n", addr, n, value); trace_heathrow_write(addr, n, value);
if (n >= 2) if (n >= 2)
return; return;
pic = &s->pics[n]; pic = &s->pics[n];
switch(addr & 0xf) { switch(addr & 0xf) {
case 0x04: case 0x04:
pic->mask = value; pic->mask = value;
heathrow_pic_update(s); heathrow_update_irq(s);
break; break;
case 0x08: case 0x08:
/* do not reset level triggered IRQs */ /* do not reset level triggered IRQs */
value &= ~pic->level_triggered; value &= ~pic->level_triggered;
pic->events &= ~value; pic->events &= ~value;
heathrow_pic_update(s); heathrow_update_irq(s);
break; break;
default: default:
break; break;
} }
} }
static uint64_t pic_read(void *opaque, hwaddr addr, static uint64_t heathrow_read(void *opaque, hwaddr addr,
unsigned size) unsigned size)
{ {
HeathrowPICS *s = opaque; HeathrowState *s = opaque;
HeathrowPIC *pic; HeathrowPICState *pic;
unsigned int n; unsigned int n;
uint32_t value; uint32_t value;
@ -120,40 +100,39 @@ static uint64_t pic_read(void *opaque, hwaddr addr,
break; break;
} }
} }
PIC_DPRINTF("readl: " TARGET_FMT_plx " %u: %08x\n", addr, n, value); trace_heathrow_read(addr, n, value);
return value; return value;
} }
static const MemoryRegionOps heathrow_pic_ops = { static const MemoryRegionOps heathrow_ops = {
.read = pic_read, .read = heathrow_read,
.write = pic_write, .write = heathrow_write,
.endianness = DEVICE_LITTLE_ENDIAN, .endianness = DEVICE_LITTLE_ENDIAN,
}; };
static void heathrow_pic_set_irq(void *opaque, int num, int level) static void heathrow_set_irq(void *opaque, int num, int level)
{ {
HeathrowPICS *s = opaque; HeathrowState *s = opaque;
HeathrowPIC *pic; HeathrowPICState *pic;
unsigned int irq_bit; unsigned int irq_bit;
int last_level;
#if defined(DEBUG)
{
static int last_level[64];
if (last_level[num] != level) {
PIC_DPRINTF("set_irq: num=0x%02x level=%d\n", num, level);
last_level[num] = level;
}
}
#endif
pic = &s->pics[1 - (num >> 5)]; pic = &s->pics[1 - (num >> 5)];
irq_bit = 1 << (num & 0x1f); irq_bit = 1 << (num & 0x1f);
last_level = (pic->levels & irq_bit) ? 1 : 0;
if (level) { if (level) {
pic->events |= irq_bit & ~pic->level_triggered; pic->events |= irq_bit & ~pic->level_triggered;
pic->levels |= irq_bit; pic->levels |= irq_bit;
} else { } else {
pic->levels &= ~irq_bit; pic->levels &= ~irq_bit;
} }
heathrow_pic_update(s);
if (last_level != level) {
trace_heathrow_set_irq(num, level);
}
heathrow_update_irq(s);
} }
static const VMStateDescription vmstate_heathrow_pic_one = { static const VMStateDescription vmstate_heathrow_pic_one = {
@ -161,54 +140,81 @@ static const VMStateDescription vmstate_heathrow_pic_one = {
.version_id = 0, .version_id = 0,
.minimum_version_id = 0, .minimum_version_id = 0,
.fields = (VMStateField[]) { .fields = (VMStateField[]) {
VMSTATE_UINT32(events, HeathrowPIC), VMSTATE_UINT32(events, HeathrowPICState),
VMSTATE_UINT32(mask, HeathrowPIC), VMSTATE_UINT32(mask, HeathrowPICState),
VMSTATE_UINT32(levels, HeathrowPIC), VMSTATE_UINT32(levels, HeathrowPICState),
VMSTATE_UINT32(level_triggered, HeathrowPIC), VMSTATE_UINT32(level_triggered, HeathrowPICState),
VMSTATE_END_OF_LIST() VMSTATE_END_OF_LIST()
} }
}; };
static const VMStateDescription vmstate_heathrow_pic = { static const VMStateDescription vmstate_heathrow = {
.name = "heathrow_pic", .name = "heathrow_pic",
.version_id = 1, .version_id = 1,
.minimum_version_id = 1, .minimum_version_id = 1,
.fields = (VMStateField[]) { .fields = (VMStateField[]) {
VMSTATE_STRUCT_ARRAY(pics, HeathrowPICS, 2, 1, VMSTATE_STRUCT_ARRAY(pics, HeathrowState, 2, 1,
vmstate_heathrow_pic_one, HeathrowPIC), vmstate_heathrow_pic_one, HeathrowPICState),
VMSTATE_END_OF_LIST() VMSTATE_END_OF_LIST()
} }
}; };
static void heathrow_pic_reset_one(HeathrowPIC *s) static void heathrow_reset(DeviceState *d)
{ {
memset(s, '\0', sizeof(HeathrowPIC)); HeathrowState *s = HEATHROW(d);
}
static void heathrow_pic_reset(void *opaque)
{
HeathrowPICS *s = opaque;
heathrow_pic_reset_one(&s->pics[0]);
heathrow_pic_reset_one(&s->pics[1]);
s->pics[0].level_triggered = 0; s->pics[0].level_triggered = 0;
s->pics[1].level_triggered = 0x1ff00000; s->pics[1].level_triggered = 0x1ff00000;
} }
qemu_irq *heathrow_pic_init(MemoryRegion **pmem, static void heathrow_init(Object *obj)
int nb_cpus, qemu_irq **irqs)
{ {
HeathrowPICS *s; HeathrowState *s = HEATHROW(obj);
SysBusDevice *sbd = SYS_BUS_DEVICE(obj);
s = g_malloc0(sizeof(HeathrowPICS)); memory_region_init_io(&s->mem, OBJECT(s), &heathrow_ops, s,
"heathrow-pic", 0x1000);
sysbus_init_mmio(sbd, &s->mem);
}
DeviceState *heathrow_pic_init(int nb_cpus, qemu_irq **irqs,
qemu_irq **pic_irqs)
{
DeviceState *d;
HeathrowState *s;
d = qdev_create(NULL, TYPE_HEATHROW);
qdev_init_nofail(d);
s = HEATHROW(d);
/* only 1 CPU */ /* only 1 CPU */
s->irqs = irqs[0]; s->irqs = irqs[0];
memory_region_init_io(&s->mem, NULL, &heathrow_pic_ops, s,
"heathrow-pic", 0x1000);
*pmem = &s->mem;
vmstate_register(NULL, -1, &vmstate_heathrow_pic, s); *pic_irqs = qemu_allocate_irqs(heathrow_set_irq, s, HEATHROW_NUM_IRQS);
qemu_register_reset(heathrow_pic_reset, s);
return qemu_allocate_irqs(heathrow_pic_set_irq, s, 64); return d;
} }
static void heathrow_class_init(ObjectClass *oc, void *data)
{
DeviceClass *dc = DEVICE_CLASS(oc);
dc->reset = heathrow_reset;
dc->vmsd = &vmstate_heathrow;
set_bit(DEVICE_CATEGORY_MISC, dc->categories);
}
static const TypeInfo heathrow_type_info = {
.name = TYPE_HEATHROW,
.parent = TYPE_SYS_BUS_DEVICE,
.instance_size = sizeof(HeathrowState),
.instance_init = heathrow_init,
.class_init = heathrow_class_init,
};
static void heathrow_register_types(void)
{
type_register_static(&heathrow_type_info);
}
type_init(heathrow_register_types)

View File

@ -63,10 +63,6 @@ static int get_current_cpu(void);
} \ } \
} while (0) } while (0)
#define MAX_CPU 32
#define MAX_MSI 8
#define VID 0x03 /* MPIC version ID */
/* OpenPIC capability flags */ /* OpenPIC capability flags */
#define OPENPIC_FLAG_IDR_CRIT (1 << 0) #define OPENPIC_FLAG_IDR_CRIT (1 << 0)
#define OPENPIC_FLAG_ILR (2 << 0) #define OPENPIC_FLAG_ILR (2 << 0)
@ -85,35 +81,6 @@ static int get_current_cpu(void);
#define OPENPIC_CPU_REG_START 0x20000 #define OPENPIC_CPU_REG_START 0x20000
#define OPENPIC_CPU_REG_SIZE 0x100 + ((MAX_CPU - 1) * 0x1000) #define OPENPIC_CPU_REG_SIZE 0x100 + ((MAX_CPU - 1) * 0x1000)
/* Raven */
#define RAVEN_MAX_CPU 2
#define RAVEN_MAX_EXT 48
#define RAVEN_MAX_IRQ 64
#define RAVEN_MAX_TMR OPENPIC_MAX_TMR
#define RAVEN_MAX_IPI OPENPIC_MAX_IPI
/* KeyLargo */
#define KEYLARGO_MAX_CPU 4
#define KEYLARGO_MAX_EXT 64
#define KEYLARGO_MAX_IPI 4
#define KEYLARGO_MAX_IRQ (64 + KEYLARGO_MAX_IPI)
#define KEYLARGO_MAX_TMR 0
#define KEYLARGO_IPI_IRQ (KEYLARGO_MAX_EXT) /* First IPI IRQ */
/* Timers don't exist but this makes the code happy... */
#define KEYLARGO_TMR_IRQ (KEYLARGO_IPI_IRQ + KEYLARGO_MAX_IPI)
/* Interrupt definitions */
#define RAVEN_FE_IRQ (RAVEN_MAX_EXT) /* Internal functional IRQ */
#define RAVEN_ERR_IRQ (RAVEN_MAX_EXT + 1) /* Error IRQ */
#define RAVEN_TMR_IRQ (RAVEN_MAX_EXT + 2) /* First timer IRQ */
#define RAVEN_IPI_IRQ (RAVEN_TMR_IRQ + RAVEN_MAX_TMR) /* First IPI IRQ */
/* First doorbell IRQ */
#define RAVEN_DBL_IRQ (RAVEN_IPI_IRQ + (RAVEN_MAX_CPU * RAVEN_MAX_IPI))
typedef struct FslMpicInfo {
int max_ext;
} FslMpicInfo;
static FslMpicInfo fsl_mpic_20 = { static FslMpicInfo fsl_mpic_20 = {
.max_ext = 12, .max_ext = 12,
}; };
@ -211,55 +178,6 @@ static void openpic_cpu_write_internal(void *opaque, hwaddr addr,
uint32_t val, int idx); uint32_t val, int idx);
static void openpic_reset(DeviceState *d); static void openpic_reset(DeviceState *d);
typedef enum IRQType {
IRQ_TYPE_NORMAL = 0,
IRQ_TYPE_FSLINT, /* FSL internal interrupt -- level only */
IRQ_TYPE_FSLSPECIAL, /* FSL timer/IPI interrupt, edge, no polarity */
} IRQType;
/* Round up to the nearest 64 IRQs so that the queue length
* won't change when moving between 32 and 64 bit hosts.
*/
#define IRQQUEUE_SIZE_BITS ((OPENPIC_MAX_IRQ + 63) & ~63)
typedef struct IRQQueue {
unsigned long *queue;
int32_t queue_size; /* Only used for VMSTATE_BITMAP */
int next;
int priority;
} IRQQueue;
typedef struct IRQSource {
uint32_t ivpr; /* IRQ vector/priority register */
uint32_t idr; /* IRQ destination register */
uint32_t destmask; /* bitmap of CPU destinations */
int last_cpu;
int output; /* IRQ level, e.g. OPENPIC_OUTPUT_INT */
int pending; /* TRUE if IRQ is pending */
IRQType type;
bool level:1; /* level-triggered */
bool nomask:1; /* critical interrupts ignore mask on some FSL MPICs */
} IRQSource;
#define IVPR_MASK_SHIFT 31
#define IVPR_MASK_MASK (1U << IVPR_MASK_SHIFT)
#define IVPR_ACTIVITY_SHIFT 30
#define IVPR_ACTIVITY_MASK (1U << IVPR_ACTIVITY_SHIFT)
#define IVPR_MODE_SHIFT 29
#define IVPR_MODE_MASK (1U << IVPR_MODE_SHIFT)
#define IVPR_POLARITY_SHIFT 23
#define IVPR_POLARITY_MASK (1U << IVPR_POLARITY_SHIFT)
#define IVPR_SENSE_SHIFT 22
#define IVPR_SENSE_MASK (1U << IVPR_SENSE_SHIFT)
#define IVPR_PRIORITY_MASK (0xFU << 16)
#define IVPR_PRIORITY(_ivprr_) ((int)(((_ivprr_) & IVPR_PRIORITY_MASK) >> 16))
#define IVPR_VECTOR(opp, _ivprr_) ((_ivprr_) & (opp)->vector_mask)
/* IDR[EP/CI] are only for FSL MPIC prior to v4.0 */
#define IDR_EP 0x80000000 /* external pin */
#define IDR_CI 0x40000000 /* critical interrupt */
/* Convert between openpic clock ticks and nanosecs. In the hardware the clock /* Convert between openpic clock ticks and nanosecs. In the hardware the clock
frequency is driven by board inputs to the PIC which the PIC would then frequency is driven by board inputs to the PIC which the PIC would then
divide by 4 or 8. For now hard code to 25MZ. divide by 4 or 8. For now hard code to 25MZ.
@ -275,81 +193,6 @@ static inline uint64_t ticks_to_ns(uint64_t ticks)
return ticks * OPENPIC_TIMER_NS_PER_TICK; return ticks * OPENPIC_TIMER_NS_PER_TICK;
} }
typedef struct OpenPICTimer {
uint32_t tccr; /* Global timer current count register */
uint32_t tbcr; /* Global timer base count register */
int n_IRQ;
bool qemu_timer_active; /* Is the qemu_timer is running? */
struct QEMUTimer *qemu_timer;
struct OpenPICState *opp; /* Device timer is part of. */
/* The QEMU_CLOCK_VIRTUAL time (in ns) corresponding to the last
current_count written or read, only defined if qemu_timer_active. */
uint64_t origin_time;
} OpenPICTimer;
typedef struct OpenPICMSI {
uint32_t msir; /* Shared Message Signaled Interrupt Register */
} OpenPICMSI;
typedef struct IRQDest {
int32_t ctpr; /* CPU current task priority */
IRQQueue raised;
IRQQueue servicing;
qemu_irq *irqs;
/* Count of IRQ sources asserting on non-INT outputs */
uint32_t outputs_active[OPENPIC_OUTPUT_NB];
} IRQDest;
#define OPENPIC(obj) OBJECT_CHECK(OpenPICState, (obj), TYPE_OPENPIC)
typedef struct OpenPICState {
/*< private >*/
SysBusDevice parent_obj;
/*< public >*/
MemoryRegion mem;
/* Behavior control */
FslMpicInfo *fsl;
uint32_t model;
uint32_t flags;
uint32_t nb_irqs;
uint32_t vid;
uint32_t vir; /* Vendor identification register */
uint32_t vector_mask;
uint32_t tfrr_reset;
uint32_t ivpr_reset;
uint32_t idr_reset;
uint32_t brr1;
uint32_t mpic_mode_mask;
/* Sub-regions */
MemoryRegion sub_io_mem[6];
/* Global registers */
uint32_t frr; /* Feature reporting register */
uint32_t gcr; /* Global configuration register */
uint32_t pir; /* Processor initialization register */
uint32_t spve; /* Spurious vector register */
uint32_t tfrr; /* Timer frequency reporting register */
/* Source registers */
IRQSource src[OPENPIC_MAX_IRQ];
/* Local registers per output pin */
IRQDest dst[MAX_CPU];
uint32_t nb_cpus;
/* Timer registers */
OpenPICTimer timers[OPENPIC_MAX_TMR];
uint32_t max_tmr;
/* Shared MSI registers */
OpenPICMSI msi[MAX_MSI];
uint32_t max_irq;
uint32_t irq_ipi0;
uint32_t irq_tim0;
uint32_t irq_msi;
} OpenPICState;
static inline void IRQ_setbit(IRQQueue *q, int n_IRQ) static inline void IRQ_setbit(IRQQueue *q, int n_IRQ)
{ {
set_bit(n_IRQ, q->queue); set_bit(n_IRQ, q->queue);

View File

@ -30,6 +30,7 @@
#include "exec/address-spaces.h" #include "exec/address-spaces.h"
#include "hw/hw.h" #include "hw/hw.h"
#include "hw/ppc/openpic.h" #include "hw/ppc/openpic.h"
#include "hw/ppc/openpic_kvm.h"
#include "hw/pci/msi.h" #include "hw/pci/msi.h"
#include "hw/sysbus.h" #include "hw/sysbus.h"
#include "sysemu/kvm.h" #include "sysemu/kvm.h"

View File

@ -186,3 +186,8 @@ nvic_complete_irq(int irq, bool secure) "NVIC complete IRQ %d (secure %d)"
nvic_set_irq_level(int irq, int level) "NVIC external irq %d level set to %d" nvic_set_irq_level(int irq, int level) "NVIC external irq %d level set to %d"
nvic_sysreg_read(uint64_t addr, uint32_t value, unsigned size) "NVIC sysreg read addr 0x%" PRIx64 " data 0x%" PRIx32 " size %u" nvic_sysreg_read(uint64_t addr, uint32_t value, unsigned size) "NVIC sysreg read addr 0x%" PRIx64 " data 0x%" PRIx32 " size %u"
nvic_sysreg_write(uint64_t addr, uint32_t value, unsigned size) "NVIC sysreg write addr 0x%" PRIx64 " data 0x%" PRIx32 " size %u" nvic_sysreg_write(uint64_t addr, uint32_t value, unsigned size) "NVIC sysreg write addr 0x%" PRIx64 " data 0x%" PRIx32 " size %u"
# hw/intc/heathrow_pic.c
heathrow_write(uint64_t addr, unsigned int n, uint64_t value) "0x%"PRIx64" %u: 0x%"PRIx64
heathrow_read(uint64_t addr, unsigned int n, uint64_t value) "0x%"PRIx64" %u: 0x%"PRIx64
heathrow_set_irq(int num, int level) "set_irq: num=0x%02x level=%d"

View File

@ -30,48 +30,11 @@
#include "hw/pci/pci.h" #include "hw/pci/pci.h"
#include "hw/ppc/mac_dbdma.h" #include "hw/ppc/mac_dbdma.h"
#include "hw/char/escc.h" #include "hw/char/escc.h"
#include "hw/misc/macio/macio.h"
#include "hw/intc/heathrow_pic.h"
#define TYPE_MACIO "macio" /* Note: this code is strongly inspirated from the corresponding code
#define MACIO(obj) OBJECT_CHECK(MacIOState, (obj), TYPE_MACIO) * in PearPC */
typedef struct MacIOState
{
/*< private >*/
PCIDevice parent;
/*< public >*/
MemoryRegion bar;
CUDAState cuda;
DBDMAState *dbdma;
MemoryRegion *pic_mem;
MemoryRegion *escc_mem;
uint64_t frequency;
} MacIOState;
#define OLDWORLD_MACIO(obj) \
OBJECT_CHECK(OldWorldMacIOState, (obj), TYPE_OLDWORLD_MACIO)
typedef struct OldWorldMacIOState {
/*< private >*/
MacIOState parent_obj;
/*< public >*/
qemu_irq irqs[5];
MacIONVRAMState nvram;
MACIOIDEState ide[2];
} OldWorldMacIOState;
#define NEWWORLD_MACIO(obj) \
OBJECT_CHECK(NewWorldMacIOState, (obj), TYPE_NEWWORLD_MACIO)
typedef struct NewWorldMacIOState {
/*< private >*/
MacIOState parent_obj;
/*< public >*/
qemu_irq irqs[5];
MACIOIDEState ide[2];
} NewWorldMacIOState;
/* /*
* The mac-io has two interfaces to the ESCC. One is called "escc-legacy", * The mac-io has two interfaces to the ESCC. One is called "escc-legacy",
@ -84,10 +47,12 @@ typedef struct NewWorldMacIOState {
* *
* Reference: ftp://ftp.software.ibm.com/rs6000/technology/spec/chrp/inwork/CHRP_IORef_1.0.pdf * Reference: ftp://ftp.software.ibm.com/rs6000/technology/spec/chrp/inwork/CHRP_IORef_1.0.pdf
*/ */
static void macio_escc_legacy_setup(MacIOState *macio_state) static void macio_escc_legacy_setup(MacIOState *s)
{ {
ESCCState *escc = ESCC(&s->escc);
SysBusDevice *sbd = SYS_BUS_DEVICE(escc);
MemoryRegion *escc_legacy = g_new(MemoryRegion, 1); MemoryRegion *escc_legacy = g_new(MemoryRegion, 1);
MemoryRegion *bar = &macio_state->bar; MemoryRegion *bar = &s->bar;
int i; int i;
static const int maps[] = { static const int maps[] = {
0x00, 0x00, /* Command B */ 0x00, 0x00, /* Command B */
@ -102,25 +67,26 @@ static void macio_escc_legacy_setup(MacIOState *macio_state)
0xb0, 0xb0, /* Detect AB */ 0xb0, 0xb0, /* Detect AB */
}; };
memory_region_init(escc_legacy, OBJECT(macio_state), "escc-legacy", 256); memory_region_init(escc_legacy, OBJECT(s), "escc-legacy", 256);
for (i = 0; i < ARRAY_SIZE(maps); i += 2) { for (i = 0; i < ARRAY_SIZE(maps); i += 2) {
MemoryRegion *port = g_new(MemoryRegion, 1); MemoryRegion *port = g_new(MemoryRegion, 1);
memory_region_init_alias(port, OBJECT(macio_state), "escc-legacy-port", memory_region_init_alias(port, OBJECT(s), "escc-legacy-port",
macio_state->escc_mem, maps[i+1], 0x2); sysbus_mmio_get_region(sbd, 0),
maps[i + 1], 0x2);
memory_region_add_subregion(escc_legacy, maps[i], port); memory_region_add_subregion(escc_legacy, maps[i], port);
} }
memory_region_add_subregion(bar, 0x12000, escc_legacy); memory_region_add_subregion(bar, 0x12000, escc_legacy);
} }
static void macio_bar_setup(MacIOState *macio_state) static void macio_bar_setup(MacIOState *s)
{ {
MemoryRegion *bar = &macio_state->bar; ESCCState *escc = ESCC(&s->escc);
SysBusDevice *sbd = SYS_BUS_DEVICE(escc);
MemoryRegion *bar = &s->bar;
if (macio_state->escc_mem) { memory_region_add_subregion(bar, 0x13000, sysbus_mmio_get_region(sbd, 0));
memory_region_add_subregion(bar, 0x13000, macio_state->escc_mem); macio_escc_legacy_setup(s);
macio_escc_legacy_setup(macio_state);
}
} }
static void macio_common_realize(PCIDevice *d, Error **errp) static void macio_common_realize(PCIDevice *d, Error **errp)
@ -129,15 +95,17 @@ static void macio_common_realize(PCIDevice *d, Error **errp)
SysBusDevice *sysbus_dev; SysBusDevice *sysbus_dev;
Error *err = NULL; Error *err = NULL;
object_property_set_bool(OBJECT(s->dbdma), true, "realized", &err); object_property_set_bool(OBJECT(&s->dbdma), true, "realized", &err);
if (err) { if (err) {
error_propagate(errp, err); error_propagate(errp, err);
return; return;
} }
sysbus_dev = SYS_BUS_DEVICE(s->dbdma); sysbus_dev = SYS_BUS_DEVICE(&s->dbdma);
memory_region_add_subregion(&s->bar, 0x08000, memory_region_add_subregion(&s->bar, 0x08000,
sysbus_mmio_get_region(sysbus_dev, 0)); sysbus_mmio_get_region(sysbus_dev, 0));
qdev_prop_set_uint64(DEVICE(&s->cuda), "timebase-frequency",
s->frequency);
object_property_set_bool(OBJECT(&s->cuda), true, "realized", &err); object_property_set_bool(OBJECT(&s->cuda), true, "realized", &err);
if (err) { if (err) {
error_propagate(errp, err); error_propagate(errp, err);
@ -147,6 +115,12 @@ static void macio_common_realize(PCIDevice *d, Error **errp)
memory_region_add_subregion(&s->bar, 0x16000, memory_region_add_subregion(&s->bar, 0x16000,
sysbus_mmio_get_region(sysbus_dev, 0)); sysbus_mmio_get_region(sysbus_dev, 0));
object_property_set_bool(OBJECT(&s->escc), true, "realized", &err);
if (err) {
error_propagate(errp, err);
return;
}
macio_bar_setup(s); macio_bar_setup(s);
pci_register_bar(d, 0, PCI_BASE_ADDRESS_SPACE_MEMORY, &s->bar); pci_register_bar(d, 0, PCI_BASE_ADDRESS_SPACE_MEMORY, &s->bar);
} }
@ -161,7 +135,7 @@ static void macio_realize_ide(MacIOState *s, MACIOIDEState *ide,
sysbus_connect_irq(sysbus_dev, 0, irq0); sysbus_connect_irq(sysbus_dev, 0, irq0);
sysbus_connect_irq(sysbus_dev, 1, irq1); sysbus_connect_irq(sysbus_dev, 1, irq1);
qdev_prop_set_uint32(DEVICE(ide), "channel", dmaid); qdev_prop_set_uint32(DEVICE(ide), "channel", dmaid);
object_property_set_link(OBJECT(ide), OBJECT(s->dbdma), "dbdma", errp); object_property_set_link(OBJECT(ide), OBJECT(&s->dbdma), "dbdma", errp);
macio_ide_register_dma(ide); macio_ide_register_dma(ide);
object_property_set_bool(OBJECT(ide), true, "realized", errp); object_property_set_bool(OBJECT(ide), true, "realized", errp);
@ -185,6 +159,10 @@ static void macio_oldworld_realize(PCIDevice *d, Error **errp)
sysbus_dev = SYS_BUS_DEVICE(&s->cuda); sysbus_dev = SYS_BUS_DEVICE(&s->cuda);
sysbus_connect_irq(sysbus_dev, 0, os->irqs[cur_irq++]); sysbus_connect_irq(sysbus_dev, 0, os->irqs[cur_irq++]);
sysbus_dev = SYS_BUS_DEVICE(&s->escc);
sysbus_connect_irq(sysbus_dev, 0, os->irqs[cur_irq++]);
sysbus_connect_irq(sysbus_dev, 1, os->irqs[cur_irq++]);
object_property_set_bool(OBJECT(&os->nvram), true, "realized", &err); object_property_set_bool(OBJECT(&os->nvram), true, "realized", &err);
if (err) { if (err) {
error_propagate(errp, err); error_propagate(errp, err);
@ -195,10 +173,10 @@ static void macio_oldworld_realize(PCIDevice *d, Error **errp)
sysbus_mmio_get_region(sysbus_dev, 0)); sysbus_mmio_get_region(sysbus_dev, 0));
pmac_format_nvram_partition(&os->nvram, os->nvram.size); pmac_format_nvram_partition(&os->nvram, os->nvram.size);
if (s->pic_mem) { /* Heathrow PIC */
/* Heathrow PIC */ sysbus_dev = SYS_BUS_DEVICE(os->pic);
memory_region_add_subregion(&s->bar, 0x00000, s->pic_mem); memory_region_add_subregion(&s->bar, 0x0,
} sysbus_mmio_get_region(sysbus_dev, 0));
/* IDE buses */ /* IDE buses */
for (i = 0; i < ARRAY_SIZE(os->ide); i++) { for (i = 0; i < ARRAY_SIZE(os->ide); i++) {
@ -236,6 +214,11 @@ static void macio_oldworld_init(Object *obj)
qdev_init_gpio_out(DEVICE(obj), os->irqs, ARRAY_SIZE(os->irqs)); qdev_init_gpio_out(DEVICE(obj), os->irqs, ARRAY_SIZE(os->irqs));
object_property_add_link(obj, "pic", TYPE_HEATHROW,
(Object **) &os->pic,
qdev_prop_allow_set_link_before_realize,
0, NULL);
object_initialize(&os->nvram, sizeof(os->nvram), TYPE_MACIO_NVRAM); object_initialize(&os->nvram, sizeof(os->nvram), TYPE_MACIO_NVRAM);
dev = DEVICE(&os->nvram); dev = DEVICE(&os->nvram);
qdev_prop_set_uint32(dev, "size", 0x2000); qdev_prop_set_uint32(dev, "size", 0x2000);
@ -297,10 +280,14 @@ static void macio_newworld_realize(PCIDevice *d, Error **errp)
sysbus_dev = SYS_BUS_DEVICE(&s->cuda); sysbus_dev = SYS_BUS_DEVICE(&s->cuda);
sysbus_connect_irq(sysbus_dev, 0, ns->irqs[cur_irq++]); sysbus_connect_irq(sysbus_dev, 0, ns->irqs[cur_irq++]);
if (s->pic_mem) { sysbus_dev = SYS_BUS_DEVICE(&s->escc);
/* OpenPIC */ sysbus_connect_irq(sysbus_dev, 0, ns->irqs[cur_irq++]);
memory_region_add_subregion(&s->bar, 0x40000, s->pic_mem); sysbus_connect_irq(sysbus_dev, 1, ns->irqs[cur_irq++]);
}
/* OpenPIC */
sysbus_dev = SYS_BUS_DEVICE(ns->pic);
memory_region_add_subregion(&s->bar, 0x40000,
sysbus_mmio_get_region(sysbus_dev, 0));
/* IDE buses */ /* IDE buses */
for (i = 0; i < ARRAY_SIZE(ns->ide); i++) { for (i = 0; i < ARRAY_SIZE(ns->ide); i++) {
@ -329,6 +316,11 @@ static void macio_newworld_init(Object *obj)
qdev_init_gpio_out(DEVICE(obj), ns->irqs, ARRAY_SIZE(ns->irqs)); qdev_init_gpio_out(DEVICE(obj), ns->irqs, ARRAY_SIZE(ns->irqs));
object_property_add_link(obj, "pic", TYPE_OPENPIC,
(Object **) &ns->pic,
qdev_prop_allow_set_link_before_realize,
0, NULL);
for (i = 0; i < 2; i++) { for (i = 0; i < 2; i++) {
macio_init_ide(s, &ns->ide[i], sizeof(ns->ide[i]), i); macio_init_ide(s, &ns->ide[i], sizeof(ns->ide[i]), i);
} }
@ -344,8 +336,20 @@ static void macio_instance_init(Object *obj)
qdev_set_parent_bus(DEVICE(&s->cuda), sysbus_get_default()); qdev_set_parent_bus(DEVICE(&s->cuda), sysbus_get_default());
object_property_add_child(obj, "cuda", OBJECT(&s->cuda), NULL); object_property_add_child(obj, "cuda", OBJECT(&s->cuda), NULL);
s->dbdma = MAC_DBDMA(object_new(TYPE_MAC_DBDMA)); object_initialize(&s->dbdma, sizeof(s->dbdma), TYPE_MAC_DBDMA);
object_property_add_child(obj, "dbdma", OBJECT(s->dbdma), NULL); qdev_set_parent_bus(DEVICE(&s->dbdma), sysbus_get_default());
object_property_add_child(obj, "dbdma", OBJECT(&s->dbdma), NULL);
object_initialize(&s->escc, sizeof(s->escc), TYPE_ESCC);
qdev_prop_set_uint32(DEVICE(&s->escc), "disabled", 0);
qdev_prop_set_uint32(DEVICE(&s->escc), "frequency", ESCC_CLOCK);
qdev_prop_set_uint32(DEVICE(&s->escc), "it_shift", 4);
qdev_prop_set_chr(DEVICE(&s->escc), "chrA", serial_hds[0]);
qdev_prop_set_chr(DEVICE(&s->escc), "chrB", serial_hds[1]);
qdev_prop_set_uint32(DEVICE(&s->escc), "chnBtype", escc_serial);
qdev_prop_set_uint32(DEVICE(&s->escc), "chnAtype", escc_serial);
qdev_set_parent_bus(DEVICE(&s->escc), sysbus_get_default());
object_property_add_child(obj, "escc", OBJECT(&s->escc), NULL);
} }
static const VMStateDescription vmstate_macio_oldworld = { static const VMStateDescription vmstate_macio_oldworld = {
@ -441,19 +445,3 @@ static void macio_register_types(void)
} }
type_init(macio_register_types) type_init(macio_register_types)
void macio_init(PCIDevice *d,
MemoryRegion *pic_mem,
MemoryRegion *escc_mem)
{
MacIOState *macio_state = MACIO(d);
macio_state->pic_mem = pic_mem;
macio_state->escc_mem = escc_mem;
/* Note: this code is strongly inspirated from the corresponding code
in PearPC */
qdev_prop_set_uint64(DEVICE(&macio_state->cuda), "timebase-frequency",
macio_state->frequency);
qdev_init_nofail(DEVICE(d));
}

View File

@ -13,7 +13,8 @@ endif
obj-$(CONFIG_PSERIES) += spapr_rtas_ddw.o obj-$(CONFIG_PSERIES) += spapr_rtas_ddw.o
# PowerPC 4xx boards # PowerPC 4xx boards
obj-y += ppc4xx_devs.o ppc405_uc.o obj-y += ppc4xx_devs.o ppc405_uc.o
obj-$(CONFIG_PPC4XX) += ppc4xx_pci.o ppc405_boards.o ppc440_bamboo.o obj-$(CONFIG_PPC4XX) += ppc4xx_pci.o ppc405_boards.o
obj-$(CONFIG_PPC4XX) += ppc440_bamboo.o ppc440_pcix.o ppc440_uc.o sam460ex.o
# PReP # PReP
obj-$(CONFIG_PREP) += prep.o obj-$(CONFIG_PREP) += prep.o
obj-$(CONFIG_PREP) += prep_systemio.o obj-$(CONFIG_PREP) += prep_systemio.o

View File

@ -29,6 +29,7 @@
#include "kvm_ppc.h" #include "kvm_ppc.h"
#include "sysemu/device_tree.h" #include "sysemu/device_tree.h"
#include "hw/ppc/openpic.h" #include "hw/ppc/openpic.h"
#include "hw/ppc/openpic_kvm.h"
#include "hw/ppc/ppc.h" #include "hw/ppc/ppc.h"
#include "hw/loader.h" #include "hw/loader.h"
#include "elf.h" #include "elf.h"
@ -119,7 +120,14 @@ static void dt_serial_create(void *fdt, unsigned long long offset,
qemu_fdt_setprop_string(fdt, "/aliases", alias, ser); qemu_fdt_setprop_string(fdt, "/aliases", alias, ser);
if (defcon) { if (defcon) {
/*
* "linux,stdout-path" and "stdout" properties are deprecated by linux
* kernel. New platforms should only use the "stdout-path" property. Set
* the new property and continue using older property to remain
* compatible with the existing firmware.
*/
qemu_fdt_setprop_string(fdt, "/chosen", "linux,stdout-path", ser); qemu_fdt_setprop_string(fdt, "/chosen", "linux,stdout-path", ser);
qemu_fdt_setprop_string(fdt, "/chosen", "stdout-path", ser);
} }
} }
@ -784,8 +792,10 @@ void ppce500_init(MachineState *machine, PPCE500Params *params)
int initrd_size = 0; int initrd_size = 0;
hwaddr cur_base = 0; hwaddr cur_base = 0;
char *filename; char *filename;
const char *payload_name;
bool kernel_as_payload;
hwaddr bios_entry = 0; hwaddr bios_entry = 0;
target_long bios_size; target_long payload_size;
struct boot_info *boot_info; struct boot_info *boot_info;
int dt_size; int dt_size;
int i; int i;
@ -913,11 +923,6 @@ void ppce500_init(MachineState *machine, PPCE500Params *params)
/* Register spinning region */ /* Register spinning region */
sysbus_create_simple("e500-spin", params->spin_base, NULL); sysbus_create_simple("e500-spin", params->spin_base, NULL);
if (cur_base < (32 * 1024 * 1024)) {
/* u-boot occupies memory up to 32MB, so load blobs above */
cur_base = (32 * 1024 * 1024);
}
if (params->has_mpc8xxx_gpio) { if (params->has_mpc8xxx_gpio) {
qemu_irq poweroff_irq; qemu_irq poweroff_irq;
@ -952,8 +957,61 @@ void ppce500_init(MachineState *machine, PPCE500Params *params)
sysbus_mmio_get_region(s, 0)); sysbus_mmio_get_region(s, 0));
} }
/* Load kernel. */ /*
if (machine->kernel_filename) { * Smart firmware defaults ahead!
*
* We follow the following table to select which payload we execute.
*
* -kernel | -bios | payload
* ---------+-------+---------
* N | Y | u-boot
* N | N | u-boot
* Y | Y | u-boot
* Y | N | kernel
*
* This ensures backwards compatibility with how we used to expose
* -kernel to users but allows them to run through u-boot as well.
*/
kernel_as_payload = false;
if (bios_name == NULL) {
if (machine->kernel_filename) {
payload_name = machine->kernel_filename;
kernel_as_payload = true;
} else {
payload_name = "u-boot.e500";
}
} else {
payload_name = bios_name;
}
filename = qemu_find_file(QEMU_FILE_TYPE_BIOS, payload_name);
payload_size = load_elf(filename, NULL, NULL, &bios_entry, &loadaddr, NULL,
1, PPC_ELF_MACHINE, 0, 0);
if (payload_size < 0) {
/*
* Hrm. No ELF image? Try a uImage, maybe someone is giving us an
* ePAPR compliant kernel
*/
payload_size = load_uimage(filename, &bios_entry, &loadaddr, NULL,
NULL, NULL);
if (payload_size < 0) {
error_report("qemu: could not load firmware '%s'", filename);
exit(1);
}
}
g_free(filename);
if (kernel_as_payload) {
kernel_base = loadaddr;
kernel_size = payload_size;
}
cur_base = loadaddr + payload_size;
/* Load bare kernel only if no bios/u-boot has been provided */
if (machine->kernel_filename && !kernel_as_payload) {
kernel_base = cur_base; kernel_base = cur_base;
kernel_size = load_image_targphys(machine->kernel_filename, kernel_size = load_image_targphys(machine->kernel_filename,
cur_base, cur_base,
@ -967,6 +1025,11 @@ void ppce500_init(MachineState *machine, PPCE500Params *params)
cur_base += kernel_size; cur_base += kernel_size;
} }
if (cur_base < (32 * 1024 * 1024)) {
/* u-boot occupies memory up to 32MB, so load blobs above */
cur_base = (32 * 1024 * 1024);
}
/* Load initrd. */ /* Load initrd. */
if (machine->initrd_filename) { if (machine->initrd_filename) {
initrd_base = (cur_base + INITRD_LOAD_PAD) & ~INITRD_PAD_MASK; initrd_base = (cur_base + INITRD_LOAD_PAD) & ~INITRD_PAD_MASK;
@ -983,47 +1046,16 @@ void ppce500_init(MachineState *machine, PPCE500Params *params)
} }
/* /*
* Smart firmware defaults ahead! * Reserve space for dtb behind the kernel image because Linux has a bug
* * where it can only handle the dtb if it's within the first 64MB of where
* We follow the following table to select which payload we execute. * <kernel> starts. dtb cannot not reach initrd_base because INITRD_LOAD_PAD
* * ensures enough space between kernel and initrd.
* -kernel | -bios | payload
* ---------+-------+---------
* N | Y | u-boot
* N | N | u-boot
* Y | Y | u-boot
* Y | N | kernel
*
* This ensures backwards compatibility with how we used to expose
* -kernel to users but allows them to run through u-boot as well.
*/ */
if (bios_name == NULL) { dt_base = (loadaddr + payload_size + DTC_LOAD_PAD) & ~DTC_PAD_MASK;
if (machine->kernel_filename) { if (dt_base + DTB_MAX_SIZE > ram_size) {
bios_name = machine->kernel_filename; error_report("qemu: not enough memory for device tree");
} else {
bios_name = "u-boot.e500";
}
}
filename = qemu_find_file(QEMU_FILE_TYPE_BIOS, bios_name);
bios_size = load_elf(filename, NULL, NULL, &bios_entry, &loadaddr, NULL,
1, PPC_ELF_MACHINE, 0, 0);
if (bios_size < 0) {
/*
* Hrm. No ELF image? Try a uImage, maybe someone is giving us an
* ePAPR compliant kernel
*/
kernel_size = load_uimage(filename, &bios_entry, &loadaddr, NULL,
NULL, NULL);
if (kernel_size < 0) {
error_report("could not load firmware '%s'", filename);
exit(1); exit(1);
}
} }
g_free(filename);
/* Reserve space for dtb */
dt_base = (loadaddr + bios_size + DTC_LOAD_PAD) & ~DTC_PAD_MASK;
dt_size = ppce500_prep_device_tree(machine, params, dt_base, dt_size = ppce500_prep_device_tree(machine, params, dt_base,
initrd_base, initrd_size, initrd_base, initrd_size,

View File

@ -47,9 +47,6 @@
/* MacIO */ /* MacIO */
#define TYPE_OLDWORLD_MACIO "macio-oldworld"
#define TYPE_NEWWORLD_MACIO "macio-newworld"
#define TYPE_MACIO_IDE "macio-ide" #define TYPE_MACIO_IDE "macio-ide"
#define MACIO_IDE(obj) OBJECT_CHECK(MACIOIDEState, (obj), TYPE_MACIO_IDE) #define MACIO_IDE(obj) OBJECT_CHECK(MACIOIDEState, (obj), TYPE_MACIO_IDE)
@ -76,12 +73,11 @@ void macio_ide_init_drives(MACIOIDEState *ide, DriveInfo **hd_table);
void macio_ide_register_dma(MACIOIDEState *ide); void macio_ide_register_dma(MACIOIDEState *ide);
void macio_init(PCIDevice *dev, void macio_init(PCIDevice *dev,
MemoryRegion *pic_mem, MemoryRegion *pic_mem);
MemoryRegion *escc_mem);
/* Heathrow PIC */ /* Heathrow PIC */
qemu_irq *heathrow_pic_init(MemoryRegion **pmem, DeviceState *heathrow_pic_init(int nb_cpus, qemu_irq **irqs,
int nb_cpus, qemu_irq **irqs); qemu_irq **pic_irqs);
/* Grackle PCI */ /* Grackle PCI */
#define TYPE_GRACKLE_PCI_HOST_BRIDGE "grackle-pcihost" #define TYPE_GRACKLE_PCI_HOST_BRIDGE "grackle-pcihost"

View File

@ -60,6 +60,7 @@
#include "hw/boards.h" #include "hw/boards.h"
#include "hw/nvram/fw_cfg.h" #include "hw/nvram/fw_cfg.h"
#include "hw/char/escc.h" #include "hw/char/escc.h"
#include "hw/misc/macio/macio.h"
#include "hw/ppc/openpic.h" #include "hw/ppc/openpic.h"
#include "hw/ide.h" #include "hw/ide.h"
#include "hw/loader.h" #include "hw/loader.h"
@ -153,20 +154,18 @@ static void ppc_core99_init(MachineState *machine)
hwaddr kernel_base, initrd_base, cmdline_base = 0; hwaddr kernel_base, initrd_base, cmdline_base = 0;
long kernel_size, initrd_size; long kernel_size, initrd_size;
PCIBus *pci_bus; PCIBus *pci_bus;
PCIDevice *macio; NewWorldMacIOState *macio;
MACIOIDEState *macio_ide; MACIOIDEState *macio_ide;
BusState *adb_bus; BusState *adb_bus;
MacIONVRAMState *nvr; MacIONVRAMState *nvr;
int bios_size, ndrv_size; int bios_size, ndrv_size;
uint8_t *ndrv_file; uint8_t *ndrv_file;
MemoryRegion *pic_mem, *escc_mem;
MemoryRegion *escc_bar = g_new(MemoryRegion, 1);
int ppc_boot_device; int ppc_boot_device;
DriveInfo *hd[MAX_IDE_BUS * MAX_IDE_DEVS]; DriveInfo *hd[MAX_IDE_BUS * MAX_IDE_DEVS];
void *fw_cfg; void *fw_cfg;
int machine_arch; int machine_arch;
SysBusDevice *s; SysBusDevice *s;
DeviceState *dev; DeviceState *dev, *pic_dev;
int *token = g_new(int, 1); int *token = g_new(int, 1);
hwaddr nvram_addr = 0xFFF04000; hwaddr nvram_addr = 0xFFF04000;
uint64_t tbfreq; uint64_t tbfreq;
@ -333,11 +332,10 @@ static void ppc_core99_init(MachineState *machine)
pic = g_new0(qemu_irq, 64); pic = g_new0(qemu_irq, 64);
dev = qdev_create(NULL, TYPE_OPENPIC); pic_dev = qdev_create(NULL, TYPE_OPENPIC);
qdev_prop_set_uint32(dev, "model", OPENPIC_MODEL_KEYLARGO); qdev_prop_set_uint32(pic_dev, "model", OPENPIC_MODEL_KEYLARGO);
qdev_init_nofail(dev); qdev_init_nofail(pic_dev);
s = SYS_BUS_DEVICE(dev); s = SYS_BUS_DEVICE(pic_dev);
pic_mem = s->mmio[0].memory;
k = 0; k = 0;
for (i = 0; i < smp_cpus; i++) { for (i = 0; i < smp_cpus; i++) {
for (j = 0; j < OPENPIC_OUTPUT_NB; j++) { for (j = 0; j < OPENPIC_OUTPUT_NB; j++) {
@ -346,7 +344,7 @@ static void ppc_core99_init(MachineState *machine)
} }
for (i = 0; i < 64; i++) { for (i = 0; i < 64; i++) {
pic[i] = qdev_get_gpio_in(dev, i); pic[i] = qdev_get_gpio_in(pic_dev, i);
} }
if (PPC_INPUT(env) == PPC_FLAGS_INPUT_970) { if (PPC_INPUT(env) == PPC_FLAGS_INPUT_970) {
@ -368,36 +366,20 @@ static void ppc_core99_init(MachineState *machine)
tbfreq = TBFREQ; tbfreq = TBFREQ;
} }
/* init basic PC hardware */ /* MacIO */
macio = NEWWORLD_MACIO(pci_create(pci_bus, -1, TYPE_NEWWORLD_MACIO));
dev = qdev_create(NULL, TYPE_ESCC);
qdev_prop_set_uint32(dev, "disabled", 0);
qdev_prop_set_uint32(dev, "frequency", ESCC_CLOCK);
qdev_prop_set_uint32(dev, "it_shift", 4);
qdev_prop_set_chr(dev, "chrA", serial_hds[0]);
qdev_prop_set_chr(dev, "chrB", serial_hds[1]);
qdev_prop_set_uint32(dev, "chnAtype", escc_serial);
qdev_prop_set_uint32(dev, "chnBtype", escc_serial);
qdev_init_nofail(dev);
s = SYS_BUS_DEVICE(dev);
sysbus_connect_irq(s, 0, pic[0x24]);
sysbus_connect_irq(s, 1, pic[0x25]);
escc_mem = &ESCC(s)->mmio;
memory_region_init_alias(escc_bar, NULL, "escc-bar",
escc_mem, 0, memory_region_size(escc_mem));
macio = pci_create(pci_bus, -1, TYPE_NEWWORLD_MACIO);
dev = DEVICE(macio); dev = DEVICE(macio);
qdev_connect_gpio_out(dev, 0, pic[0x19]); /* CUDA */ qdev_connect_gpio_out(dev, 0, pic[0x19]); /* CUDA */
qdev_connect_gpio_out(dev, 1, pic[0x0d]); /* IDE */ qdev_connect_gpio_out(dev, 1, pic[0x24]); /* ESCC-B */
qdev_connect_gpio_out(dev, 2, pic[0x02]); /* IDE DMA */ qdev_connect_gpio_out(dev, 2, pic[0x25]); /* ESCC-A */
qdev_connect_gpio_out(dev, 3, pic[0x0e]); /* IDE */ qdev_connect_gpio_out(dev, 3, pic[0x0d]); /* IDE */
qdev_connect_gpio_out(dev, 4, pic[0x03]); /* IDE DMA */ qdev_connect_gpio_out(dev, 4, pic[0x02]); /* IDE DMA */
qdev_connect_gpio_out(dev, 5, pic[0x0e]); /* IDE */
qdev_connect_gpio_out(dev, 6, pic[0x03]); /* IDE DMA */
qdev_prop_set_uint64(dev, "frequency", tbfreq); qdev_prop_set_uint64(dev, "frequency", tbfreq);
macio_init(macio, pic_mem, escc_bar); object_property_set_link(OBJECT(macio), OBJECT(pic_dev), "pic",
&error_abort);
qdev_init_nofail(dev);
/* We only emulate 2 out of 3 IDE controllers for now */ /* We only emulate 2 out of 3 IDE controllers for now */
ide_drive_get(hd, ARRAY_SIZE(hd)); ide_drive_get(hd, ARRAY_SIZE(hd));

View File

@ -37,6 +37,7 @@
#include "hw/boards.h" #include "hw/boards.h"
#include "hw/nvram/fw_cfg.h" #include "hw/nvram/fw_cfg.h"
#include "hw/char/escc.h" #include "hw/char/escc.h"
#include "hw/misc/macio/macio.h"
#include "hw/ide.h" #include "hw/ide.h"
#include "hw/loader.h" #include "hw/loader.h"
#include "elf.h" #include "elf.h"
@ -92,19 +93,16 @@ static void ppc_heathrow_init(MachineState *machine)
uint32_t kernel_base, initrd_base, cmdline_base = 0; uint32_t kernel_base, initrd_base, cmdline_base = 0;
int32_t kernel_size, initrd_size; int32_t kernel_size, initrd_size;
PCIBus *pci_bus; PCIBus *pci_bus;
PCIDevice *macio; OldWorldMacIOState *macio;
MACIOIDEState *macio_ide; MACIOIDEState *macio_ide;
DeviceState *dev; DeviceState *dev, *pic_dev;
BusState *adb_bus; BusState *adb_bus;
int bios_size, ndrv_size; int bios_size, ndrv_size;
uint8_t *ndrv_file; uint8_t *ndrv_file;
MemoryRegion *pic_mem;
MemoryRegion *escc_mem, *escc_bar = g_new(MemoryRegion, 1);
uint16_t ppc_boot_device; uint16_t ppc_boot_device;
DriveInfo *hd[MAX_IDE_BUS * MAX_IDE_DEVS]; DriveInfo *hd[MAX_IDE_BUS * MAX_IDE_DEVS];
void *fw_cfg; void *fw_cfg;
uint64_t tbfreq; uint64_t tbfreq;
SysBusDevice *s;
linux_boot = (kernel_filename != NULL); linux_boot = (kernel_filename != NULL);
@ -259,46 +257,32 @@ static void ppc_heathrow_init(MachineState *machine)
error_report("Only 6xx bus is supported on heathrow machine"); error_report("Only 6xx bus is supported on heathrow machine");
exit(1); exit(1);
} }
pic = heathrow_pic_init(&pic_mem, 1, heathrow_irqs); pic_dev = heathrow_pic_init(1, heathrow_irqs, &pic);
pci_bus = pci_grackle_init(0xfec00000, pic, pci_bus = pci_grackle_init(0xfec00000, pic,
get_system_memory(), get_system_memory(),
get_system_io()); get_system_io());
pci_vga_init(pci_bus); pci_vga_init(pci_bus);
dev = qdev_create(NULL, TYPE_ESCC); for (i = 0; i < nb_nics; i++) {
qdev_prop_set_uint32(dev, "disabled", 0);
qdev_prop_set_uint32(dev, "frequency", ESCC_CLOCK);
qdev_prop_set_uint32(dev, "it_shift", 4);
qdev_prop_set_chr(dev, "chrA", serial_hds[0]);
qdev_prop_set_chr(dev, "chrB", serial_hds[1]);
qdev_prop_set_uint32(dev, "chnBtype", escc_serial);
qdev_prop_set_uint32(dev, "chnAtype", escc_serial);
qdev_init_nofail(dev);
s = SYS_BUS_DEVICE(dev);
sysbus_connect_irq(s, 0, pic[0x10]);
sysbus_connect_irq(s, 1, pic[0x0f]);
escc_mem = &ESCC(s)->mmio;
memory_region_init_alias(escc_bar, NULL, "escc-bar",
escc_mem, 0, memory_region_size(escc_mem));
for(i = 0; i < nb_nics; i++)
pci_nic_init_nofail(&nd_table[i], pci_bus, "ne2k_pci", NULL); pci_nic_init_nofail(&nd_table[i], pci_bus, "ne2k_pci", NULL);
}
ide_drive_get(hd, ARRAY_SIZE(hd)); ide_drive_get(hd, ARRAY_SIZE(hd));
macio = pci_create(pci_bus, -1, TYPE_OLDWORLD_MACIO); /* MacIO */
macio = OLDWORLD_MACIO(pci_create(pci_bus, -1, TYPE_OLDWORLD_MACIO));
dev = DEVICE(macio); dev = DEVICE(macio);
qdev_connect_gpio_out(dev, 0, pic[0x12]); /* CUDA */ qdev_connect_gpio_out(dev, 0, pic[0x12]); /* CUDA */
qdev_connect_gpio_out(dev, 1, pic[0x0D]); /* IDE-0 */ qdev_connect_gpio_out(dev, 1, pic[0x10]); /* ESCC-B */
qdev_connect_gpio_out(dev, 2, pic[0x02]); /* IDE-0 DMA */ qdev_connect_gpio_out(dev, 2, pic[0x0F]); /* ESCC-A */
qdev_connect_gpio_out(dev, 3, pic[0x0E]); /* IDE-1 */ qdev_connect_gpio_out(dev, 3, pic[0x0D]); /* IDE-0 */
qdev_connect_gpio_out(dev, 4, pic[0x03]); /* IDE-1 DMA */ qdev_connect_gpio_out(dev, 4, pic[0x02]); /* IDE-0 DMA */
qdev_connect_gpio_out(dev, 5, pic[0x0E]); /* IDE-1 */
qdev_connect_gpio_out(dev, 6, pic[0x03]); /* IDE-1 DMA */
qdev_prop_set_uint64(dev, "frequency", tbfreq); qdev_prop_set_uint64(dev, "frequency", tbfreq);
macio_init(macio, pic_mem, escc_bar); object_property_set_link(OBJECT(macio), OBJECT(pic_dev), "pic",
&error_abort);
qdev_init_nofail(dev);
macio_ide = MACIO_IDE(object_resolve_path_component(OBJECT(macio), macio_ide = MACIO_IDE(object_resolve_path_component(OBJECT(macio),
"ide[0]")); "ide[0]"));

528
hw/ppc/ppc440_pcix.c Normal file
View File

@ -0,0 +1,528 @@
/*
* Emulation of the ibm,plb-pcix PCI controller
* This is found in some 440 SoCs e.g. the 460EX.
*
* Copyright (c) 2016-2018 BALATON Zoltan
*
* Derived from ppc4xx_pci.c and pci-host/ppce500.c
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License, version 2, as
* published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, see <http://www.gnu.org/licenses/>.
*/
#include "qemu/osdep.h"
#include "qemu/error-report.h"
#include "hw/hw.h"
#include "hw/ppc/ppc.h"
#include "hw/ppc/ppc4xx.h"
#include "hw/pci/pci.h"
#include "hw/pci/pci_host.h"
#include "exec/address-spaces.h"
#include "trace.h"
struct PLBOutMap {
uint64_t la;
uint64_t pcia;
uint32_t sa;
MemoryRegion mr;
};
struct PLBInMap {
uint64_t sa;
uint64_t la;
MemoryRegion mr;
};
#define TYPE_PPC440_PCIX_HOST_BRIDGE "ppc440-pcix-host"
#define PPC440_PCIX_HOST_BRIDGE(obj) \
OBJECT_CHECK(PPC440PCIXState, (obj), TYPE_PPC440_PCIX_HOST_BRIDGE)
#define PPC440_PCIX_NR_POMS 3
#define PPC440_PCIX_NR_PIMS 3
typedef struct PPC440PCIXState {
PCIHostState parent_obj;
PCIDevice *dev;
struct PLBOutMap pom[PPC440_PCIX_NR_POMS];
struct PLBInMap pim[PPC440_PCIX_NR_PIMS];
uint32_t sts;
qemu_irq irq[PCI_NUM_PINS];
AddressSpace bm_as;
MemoryRegion bm;
MemoryRegion container;
MemoryRegion iomem;
MemoryRegion busmem;
} PPC440PCIXState;
#define PPC440_REG_BASE 0x80000
#define PPC440_REG_SIZE 0xff
#define PCIC0_CFGADDR 0x0
#define PCIC0_CFGDATA 0x4
#define PCIX0_POM0LAL 0x68
#define PCIX0_POM0LAH 0x6c
#define PCIX0_POM0SA 0x70
#define PCIX0_POM0PCIAL 0x74
#define PCIX0_POM0PCIAH 0x78
#define PCIX0_POM1LAL 0x7c
#define PCIX0_POM1LAH 0x80
#define PCIX0_POM1SA 0x84
#define PCIX0_POM1PCIAL 0x88
#define PCIX0_POM1PCIAH 0x8c
#define PCIX0_POM2SA 0x90
#define PCIX0_PIM0SAL 0x98
#define PCIX0_PIM0LAL 0x9c
#define PCIX0_PIM0LAH 0xa0
#define PCIX0_PIM1SA 0xa4
#define PCIX0_PIM1LAL 0xa8
#define PCIX0_PIM1LAH 0xac
#define PCIX0_PIM2SAL 0xb0
#define PCIX0_PIM2LAL 0xb4
#define PCIX0_PIM2LAH 0xb8
#define PCIX0_PIM0SAH 0xf8
#define PCIX0_PIM2SAH 0xfc
#define PCIX0_STS 0xe0
#define PCI_ALL_SIZE (PPC440_REG_BASE + PPC440_REG_SIZE)
static void ppc440_pcix_clear_region(MemoryRegion *parent,
MemoryRegion *mem)
{
if (memory_region_is_mapped(mem)) {
memory_region_del_subregion(parent, mem);
object_unparent(OBJECT(mem));
}
}
/* DMA mapping */
static void ppc440_pcix_update_pim(PPC440PCIXState *s, int idx)
{
MemoryRegion *mem = &s->pim[idx].mr;
char *name;
uint64_t size;
/* Before we modify anything, unmap and destroy the region */
ppc440_pcix_clear_region(&s->bm, mem);
if (!(s->pim[idx].sa & 1)) {
/* Not enabled, nothing to do */
return;
}
name = g_strdup_printf("PCI Inbound Window %d", idx);
size = ~(s->pim[idx].sa & ~7ULL) + 1;
memory_region_init_alias(mem, OBJECT(s), name, get_system_memory(),
s->pim[idx].la, size);
memory_region_add_subregion_overlap(&s->bm, 0, mem, -1);
g_free(name);
trace_ppc440_pcix_update_pim(idx, size, s->pim[idx].la);
}
/* BAR mapping */
static void ppc440_pcix_update_pom(PPC440PCIXState *s, int idx)
{
MemoryRegion *mem = &s->pom[idx].mr;
MemoryRegion *address_space_mem = get_system_memory();
char *name;
uint32_t size;
/* Before we modify anything, unmap and destroy the region */
ppc440_pcix_clear_region(address_space_mem, mem);
if (!(s->pom[idx].sa & 1)) {
/* Not enabled, nothing to do */
return;
}
name = g_strdup_printf("PCI Outbound Window %d", idx);
size = ~(s->pom[idx].sa & 0xfffffffe) + 1;
if (!size) {
size = 0xffffffff;
}
memory_region_init_alias(mem, OBJECT(s), name, &s->busmem,
s->pom[idx].pcia, size);
memory_region_add_subregion(address_space_mem, s->pom[idx].la, mem);
g_free(name);
trace_ppc440_pcix_update_pom(idx, size, s->pom[idx].la, s->pom[idx].pcia);
}
static void ppc440_pcix_reg_write4(void *opaque, hwaddr addr,
uint64_t val, unsigned size)
{
struct PPC440PCIXState *s = opaque;
trace_ppc440_pcix_reg_read(addr, val);
switch (addr) {
case PCI_VENDOR_ID ... PCI_MAX_LAT:
stl_le_p(s->dev->config + addr, val);
break;
case PCIX0_POM0LAL:
s->pom[0].la &= 0xffffffff00000000ULL;
s->pom[0].la |= val;
ppc440_pcix_update_pom(s, 0);
break;
case PCIX0_POM0LAH:
s->pom[0].la &= 0xffffffffULL;
s->pom[0].la |= val << 32;
ppc440_pcix_update_pom(s, 0);
break;
case PCIX0_POM0SA:
s->pom[0].sa = val;
ppc440_pcix_update_pom(s, 0);
break;
case PCIX0_POM0PCIAL:
s->pom[0].pcia &= 0xffffffff00000000ULL;
s->pom[0].pcia |= val;
ppc440_pcix_update_pom(s, 0);
break;
case PCIX0_POM0PCIAH:
s->pom[0].pcia &= 0xffffffffULL;
s->pom[0].pcia |= val << 32;
ppc440_pcix_update_pom(s, 0);
break;
case PCIX0_POM1LAL:
s->pom[1].la &= 0xffffffff00000000ULL;
s->pom[1].la |= val;
ppc440_pcix_update_pom(s, 1);
break;
case PCIX0_POM1LAH:
s->pom[1].la &= 0xffffffffULL;
s->pom[1].la |= val << 32;
ppc440_pcix_update_pom(s, 1);
break;
case PCIX0_POM1SA:
s->pom[1].sa = val;
ppc440_pcix_update_pom(s, 1);
break;
case PCIX0_POM1PCIAL:
s->pom[1].pcia &= 0xffffffff00000000ULL;
s->pom[1].pcia |= val;
ppc440_pcix_update_pom(s, 1);
break;
case PCIX0_POM1PCIAH:
s->pom[1].pcia &= 0xffffffffULL;
s->pom[1].pcia |= val << 32;
ppc440_pcix_update_pom(s, 1);
break;
case PCIX0_POM2SA:
s->pom[2].sa = val;
break;
case PCIX0_PIM0SAL:
s->pim[0].sa &= 0xffffffff00000000ULL;
s->pim[0].sa |= val;
ppc440_pcix_update_pim(s, 0);
break;
case PCIX0_PIM0LAL:
s->pim[0].la &= 0xffffffff00000000ULL;
s->pim[0].la |= val;
ppc440_pcix_update_pim(s, 0);
break;
case PCIX0_PIM0LAH:
s->pim[0].la &= 0xffffffffULL;
s->pim[0].la |= val << 32;
ppc440_pcix_update_pim(s, 0);
break;
case PCIX0_PIM1SA:
s->pim[1].sa = val;
ppc440_pcix_update_pim(s, 1);
break;
case PCIX0_PIM1LAL:
s->pim[1].la &= 0xffffffff00000000ULL;
s->pim[1].la |= val;
ppc440_pcix_update_pim(s, 1);
break;
case PCIX0_PIM1LAH:
s->pim[1].la &= 0xffffffffULL;
s->pim[1].la |= val << 32;
ppc440_pcix_update_pim(s, 1);
break;
case PCIX0_PIM2SAL:
s->pim[2].sa &= 0xffffffff00000000ULL;
s->pim[2].sa = val;
ppc440_pcix_update_pim(s, 2);
break;
case PCIX0_PIM2LAL:
s->pim[2].la &= 0xffffffff00000000ULL;
s->pim[2].la |= val;
ppc440_pcix_update_pim(s, 2);
break;
case PCIX0_PIM2LAH:
s->pim[2].la &= 0xffffffffULL;
s->pim[2].la |= val << 32;
ppc440_pcix_update_pim(s, 2);
break;
case PCIX0_STS:
s->sts = val;
break;
case PCIX0_PIM0SAH:
s->pim[0].sa &= 0xffffffffULL;
s->pim[0].sa |= val << 32;
ppc440_pcix_update_pim(s, 0);
break;
case PCIX0_PIM2SAH:
s->pim[2].sa &= 0xffffffffULL;
s->pim[2].sa |= val << 32;
ppc440_pcix_update_pim(s, 2);
break;
default:
error_report("%s: unhandled PCI internal register 0x%lx", __func__,
(unsigned long)addr);
break;
}
}
static uint64_t ppc440_pcix_reg_read4(void *opaque, hwaddr addr,
unsigned size)
{
struct PPC440PCIXState *s = opaque;
uint32_t val;
switch (addr) {
case PCI_VENDOR_ID ... PCI_MAX_LAT:
val = ldl_le_p(s->dev->config + addr);
break;
case PCIX0_POM0LAL:
val = s->pom[0].la;
break;
case PCIX0_POM0LAH:
val = s->pom[0].la >> 32;
break;
case PCIX0_POM0SA:
val = s->pom[0].sa;
break;
case PCIX0_POM0PCIAL:
val = s->pom[0].pcia;
break;
case PCIX0_POM0PCIAH:
val = s->pom[0].pcia >> 32;
break;
case PCIX0_POM1LAL:
val = s->pom[1].la;
break;
case PCIX0_POM1LAH:
val = s->pom[1].la >> 32;
break;
case PCIX0_POM1SA:
val = s->pom[1].sa;
break;
case PCIX0_POM1PCIAL:
val = s->pom[1].pcia;
break;
case PCIX0_POM1PCIAH:
val = s->pom[1].pcia >> 32;
break;
case PCIX0_POM2SA:
val = s->pom[2].sa;
break;
case PCIX0_PIM0SAL:
val = s->pim[0].sa;
break;
case PCIX0_PIM0LAL:
val = s->pim[0].la;
break;
case PCIX0_PIM0LAH:
val = s->pim[0].la >> 32;
break;
case PCIX0_PIM1SA:
val = s->pim[1].sa;
break;
case PCIX0_PIM1LAL:
val = s->pim[1].la;
break;
case PCIX0_PIM1LAH:
val = s->pim[1].la >> 32;
break;
case PCIX0_PIM2SAL:
val = s->pim[2].sa;
break;
case PCIX0_PIM2LAL:
val = s->pim[2].la;
break;
case PCIX0_PIM2LAH:
val = s->pim[2].la >> 32;
break;
case PCIX0_STS:
val = s->sts;
break;
case PCIX0_PIM0SAH:
val = s->pim[0].sa >> 32;
break;
case PCIX0_PIM2SAH:
val = s->pim[2].sa >> 32;
break;
default:
error_report("%s: invalid PCI internal register 0x%lx", __func__,
(unsigned long)addr);
val = 0;
}
trace_ppc440_pcix_reg_read(addr, val);
return val;
}
static const MemoryRegionOps pci_reg_ops = {
.read = ppc440_pcix_reg_read4,
.write = ppc440_pcix_reg_write4,
.endianness = DEVICE_LITTLE_ENDIAN,
};
static void ppc440_pcix_reset(DeviceState *dev)
{
struct PPC440PCIXState *s = PPC440_PCIX_HOST_BRIDGE(dev);
int i;
for (i = 0; i < PPC440_PCIX_NR_POMS; i++) {
ppc440_pcix_clear_region(get_system_memory(), &s->pom[i].mr);
}
for (i = 0; i < PPC440_PCIX_NR_PIMS; i++) {
ppc440_pcix_clear_region(&s->bm, &s->pim[i].mr);
}
memset(s->pom, 0, sizeof(s->pom));
memset(s->pim, 0, sizeof(s->pim));
for (i = 0; i < PPC440_PCIX_NR_PIMS; i++) {
s->pim[i].sa = 0xffffffff00000000ULL;
}
s->sts = 0;
}
/* All pins from each slot are tied to a single board IRQ.
* This may need further refactoring for other boards. */
static int ppc440_pcix_map_irq(PCIDevice *pci_dev, int irq_num)
{
int slot = pci_dev->devfn >> 3;
trace_ppc440_pcix_map_irq(pci_dev->devfn, irq_num, slot);
return slot - 1;
}
static void ppc440_pcix_set_irq(void *opaque, int irq_num, int level)
{
qemu_irq *pci_irqs = opaque;
trace_ppc440_pcix_set_irq(irq_num);
if (irq_num < 0) {
error_report("%s: PCI irq %d", __func__, irq_num);
return;
}
qemu_set_irq(pci_irqs[irq_num], level);
}
static AddressSpace *ppc440_pcix_set_iommu(PCIBus *b, void *opaque, int devfn)
{
PPC440PCIXState *s = opaque;
return &s->bm_as;
}
/* The default pci_host_data_{read,write} functions in pci/pci_host.c
* deny access to registers without bit 31 set but our clients want
* this to work so we have to override these here */
static void pci_host_data_write(void *opaque, hwaddr addr,
uint64_t val, unsigned len)
{
PCIHostState *s = opaque;
pci_data_write(s->bus, s->config_reg | (addr & 3), val, len);
}
static uint64_t pci_host_data_read(void *opaque,
hwaddr addr, unsigned len)
{
PCIHostState *s = opaque;
uint32_t val;
val = pci_data_read(s->bus, s->config_reg | (addr & 3), len);
return val;
}
const MemoryRegionOps ppc440_pcix_host_data_ops = {
.read = pci_host_data_read,
.write = pci_host_data_write,
.endianness = DEVICE_LITTLE_ENDIAN,
};
static int ppc440_pcix_initfn(SysBusDevice *dev)
{
PPC440PCIXState *s;
PCIHostState *h;
int i;
h = PCI_HOST_BRIDGE(dev);
s = PPC440_PCIX_HOST_BRIDGE(dev);
for (i = 0; i < ARRAY_SIZE(s->irq); i++) {
sysbus_init_irq(dev, &s->irq[i]);
}
memory_region_init(&s->busmem, OBJECT(dev), "pci bus memory", UINT64_MAX);
h->bus = pci_register_root_bus(DEVICE(dev), NULL, ppc440_pcix_set_irq,
ppc440_pcix_map_irq, s->irq, &s->busmem,
get_system_io(), PCI_DEVFN(0, 0), 4, TYPE_PCI_BUS);
s->dev = pci_create_simple(h->bus, PCI_DEVFN(0, 0), "ppc4xx-host-bridge");
memory_region_init(&s->bm, OBJECT(s), "bm-ppc440-pcix", UINT64_MAX);
memory_region_add_subregion(&s->bm, 0x0, &s->busmem);
address_space_init(&s->bm_as, &s->bm, "pci-bm");
pci_setup_iommu(h->bus, ppc440_pcix_set_iommu, s);
memory_region_init(&s->container, OBJECT(s), "pci-container", PCI_ALL_SIZE);
memory_region_init_io(&h->conf_mem, OBJECT(s), &pci_host_conf_le_ops,
h, "pci-conf-idx", 4);
memory_region_init_io(&h->data_mem, OBJECT(s), &ppc440_pcix_host_data_ops,
h, "pci-conf-data", 4);
memory_region_init_io(&s->iomem, OBJECT(s), &pci_reg_ops, s,
"pci.reg", PPC440_REG_SIZE);
memory_region_add_subregion(&s->container, PCIC0_CFGADDR, &h->conf_mem);
memory_region_add_subregion(&s->container, PCIC0_CFGDATA, &h->data_mem);
memory_region_add_subregion(&s->container, PPC440_REG_BASE, &s->iomem);
sysbus_init_mmio(dev, &s->container);
return 0;
}
static void ppc440_pcix_class_init(ObjectClass *klass, void *data)
{
SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
DeviceClass *dc = DEVICE_CLASS(klass);
k->init = ppc440_pcix_initfn;
dc->reset = ppc440_pcix_reset;
}
static const TypeInfo ppc440_pcix_info = {
.name = TYPE_PPC440_PCIX_HOST_BRIDGE,
.parent = TYPE_PCI_HOST_BRIDGE,
.instance_size = sizeof(PPC440PCIXState),
.class_init = ppc440_pcix_class_init,
};
static void ppc440_pcix_register_types(void)
{
type_register_static(&ppc440_pcix_info);
}
type_init(ppc440_pcix_register_types)

View File

@ -1050,6 +1050,9 @@ static void ppc460ex_pcie_realize(DeviceState *dev, Error **errp)
case DCRN_PCIE1_BASE: case DCRN_PCIE1_BASE:
id = 1; id = 1;
break; break;
default:
error_setg(errp, "invalid PCIe DCRN base");
return;
} }
snprintf(buf, sizeof(buf), "pcie%d-io", id); snprintf(buf, sizeof(buf), "pcie%d-io", id);
memory_region_init(&s->iomem, OBJECT(s), buf, UINT64_MAX); memory_region_init(&s->iomem, OBJECT(s), buf, UINT64_MAX);

603
hw/ppc/sam460ex.c Normal file
View File

@ -0,0 +1,603 @@
/*
* QEMU aCube Sam460ex board emulation
*
* Copyright (c) 2012 François Revol
* Copyright (c) 2016-2018 BALATON Zoltan
*
* This file is derived from hw/ppc440_bamboo.c,
* the copyright for that material belongs to the original owners.
*
* This work is licensed under the GNU GPL license version 2 or later.
*
*/
#include "qemu/osdep.h"
#include "qemu-common.h"
#include "qemu/cutils.h"
#include "qemu/error-report.h"
#include "qapi/error.h"
#include "hw/hw.h"
#include "sysemu/blockdev.h"
#include "hw/boards.h"
#include "sysemu/kvm.h"
#include "kvm_ppc.h"
#include "sysemu/device_tree.h"
#include "sysemu/block-backend.h"
#include "hw/loader.h"
#include "elf.h"
#include "exec/address-spaces.h"
#include "exec/memory.h"
#include "hw/ppc/ppc440.h"
#include "hw/ppc/ppc405.h"
#include "hw/block/flash.h"
#include "sysemu/sysemu.h"
#include "sysemu/qtest.h"
#include "hw/sysbus.h"
#include "hw/char/serial.h"
#include "hw/i2c/ppc4xx_i2c.h"
#include "hw/i2c/smbus.h"
#include "hw/usb/hcd-ehci.h"
#define BINARY_DEVICE_TREE_FILE "canyonlands.dtb"
#define UBOOT_FILENAME "u-boot-sam460-20100605.bin"
/* to extract the official U-Boot bin from the updater: */
/* dd bs=1 skip=$(($(stat -c '%s' updater/updater-460) - 0x80000)) \
if=updater/updater-460 of=u-boot-sam460-20100605.bin */
/* from Sam460 U-Boot include/configs/Sam460ex.h */
#define FLASH_BASE 0xfff00000
#define FLASH_BASE_H 0x4
#define FLASH_SIZE (1 << 20)
#define UBOOT_LOAD_BASE 0xfff80000
#define UBOOT_SIZE 0x00080000
#define UBOOT_ENTRY 0xfffffffc
/* from U-Boot */
#define EPAPR_MAGIC (0x45504150)
#define KERNEL_ADDR 0x1000000
#define FDT_ADDR 0x1800000
#define RAMDISK_ADDR 0x1900000
/* Sam460ex IRQ MAP:
IRQ0 = ETH_INT
IRQ1 = FPGA_INT
IRQ2 = PCI_INT (PCIA, PCIB, PCIC, PCIB)
IRQ3 = FPGA_INT2
IRQ11 = RTC_INT
IRQ12 = SM502_INT
*/
#define SDRAM_NR_BANKS 4
/* FIXME: See u-boot.git 8ac41e, also fix in ppc440_uc.c */
static const unsigned int ppc460ex_sdram_bank_sizes[] = {
1024 << 20, 512 << 20, 256 << 20, 128 << 20, 64 << 20, 32 << 20, 0
};
struct boot_info {
uint32_t dt_base;
uint32_t dt_size;
uint32_t entry;
};
/*****************************************************************************/
/* SPD eeprom content from mips_malta.c */
struct _eeprom24c0x_t {
uint8_t tick;
uint8_t address;
uint8_t command;
uint8_t ack;
uint8_t scl;
uint8_t sda;
uint8_t data;
uint8_t contents[256];
};
typedef struct _eeprom24c0x_t eeprom24c0x_t;
static eeprom24c0x_t spd_eeprom = {
.contents = {
/* 00000000: */ 0x80, 0x08, 0xFF, 0x0D, 0x0A, 0xFF, 0x40, 0x00,
/* 00000008: */ 0x04, 0x75, 0x54, 0x00, 0x82, 0x08, 0x00, 0x01,
/* 00000010: */ 0x8F, 0x04, 0x02, 0x01, 0x01, 0x00, 0x00, 0x00,
/* 00000018: */ 0x00, 0x00, 0x00, 0x14, 0x0F, 0x14, 0x2D, 0xFF,
/* 00000020: */ 0x15, 0x08, 0x15, 0x08, 0x00, 0x00, 0x00, 0x00,
/* 00000028: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
/* 00000030: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
/* 00000038: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x12, 0xD0,
/* 00000040: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
/* 00000048: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
/* 00000050: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
/* 00000058: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
/* 00000060: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
/* 00000068: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
/* 00000070: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
/* 00000078: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0xF4,
},
};
static void generate_eeprom_spd(uint8_t *eeprom, ram_addr_t ram_size)
{
enum { SDR = 0x4, DDR1 = 0x7, DDR2 = 0x8 } type;
uint8_t *spd = spd_eeprom.contents;
uint8_t nbanks = 0;
uint16_t density = 0;
int i;
/* work in terms of MB */
ram_size >>= 20;
while ((ram_size >= 4) && (nbanks <= 2)) {
int sz_log2 = MIN(31 - clz32(ram_size), 14);
nbanks++;
density |= 1 << (sz_log2 - 2);
ram_size -= 1 << sz_log2;
}
/* split to 2 banks if possible */
if ((nbanks == 1) && (density > 1)) {
nbanks++;
density >>= 1;
}
if (density & 0xff00) {
density = (density & 0xe0) | ((density >> 8) & 0x1f);
type = DDR2;
} else if (!(density & 0x1f)) {
type = DDR2;
} else {
type = SDR;
}
if (ram_size) {
warn_report("SPD cannot represent final " RAM_ADDR_FMT "MB"
" of SDRAM", ram_size);
}
/* fill in SPD memory information */
spd[2] = type;
spd[5] = nbanks;
spd[31] = density;
/* XXX: this is totally random */
spd[9] = 0x10; /* CAS tcyc */
spd[18] = 0x20; /* CAS bit */
spd[23] = 0x10; /* CAS tcyc */
spd[25] = 0x10; /* CAS tcyc */
/* checksum */
spd[63] = 0;
for (i = 0; i < 63; i++) {
spd[63] += spd[i];
}
/* copy for SMBUS */
memcpy(eeprom, spd, sizeof(spd_eeprom.contents));
}
static void generate_eeprom_serial(uint8_t *eeprom)
{
int i, pos = 0;
uint8_t mac[6] = { 0x00 };
uint8_t sn[5] = { 0x01, 0x23, 0x45, 0x67, 0x89 };
/* version */
eeprom[pos++] = 0x01;
/* count */
eeprom[pos++] = 0x02;
/* MAC address */
eeprom[pos++] = 0x01; /* MAC */
eeprom[pos++] = 0x06; /* length */
memcpy(&eeprom[pos], mac, sizeof(mac));
pos += sizeof(mac);
/* serial number */
eeprom[pos++] = 0x02; /* serial */
eeprom[pos++] = 0x05; /* length */
memcpy(&eeprom[pos], sn, sizeof(sn));
pos += sizeof(sn);
/* checksum */
eeprom[pos] = 0;
for (i = 0; i < pos; i++) {
eeprom[pos] += eeprom[i];
}
}
/*****************************************************************************/
static int sam460ex_load_uboot(void)
{
DriveInfo *dinfo;
BlockBackend *blk = NULL;
hwaddr base = FLASH_BASE | ((hwaddr)FLASH_BASE_H << 32);
long bios_size = FLASH_SIZE;
int fl_sectors;
dinfo = drive_get(IF_PFLASH, 0, 0);
if (dinfo) {
blk = blk_by_legacy_dinfo(dinfo);
bios_size = blk_getlength(blk);
}
fl_sectors = (bios_size + 65535) >> 16;
if (!pflash_cfi01_register(base, NULL, "sam460ex.flash", bios_size,
blk, (64 * 1024), fl_sectors,
1, 0x89, 0x18, 0x0000, 0x0, 1)) {
error_report("qemu: Error registering flash memory.");
/* XXX: return an error instead? */
exit(1);
}
if (!blk) {
/*error_report("No flash image given with the 'pflash' parameter,"
" using default u-boot image");*/
base = UBOOT_LOAD_BASE | ((hwaddr)FLASH_BASE_H << 32);
rom_add_file_fixed(UBOOT_FILENAME, base, -1);
}
return 0;
}
static int sam460ex_load_device_tree(hwaddr addr,
uint32_t ramsize,
hwaddr initrd_base,
hwaddr initrd_size,
const char *kernel_cmdline)
{
int ret = -1;
uint32_t mem_reg_property[] = { 0, 0, cpu_to_be32(ramsize) };
char *filename;
int fdt_size;
void *fdt;
uint32_t tb_freq = 50000000;
uint32_t clock_freq = 50000000;
filename = qemu_find_file(QEMU_FILE_TYPE_BIOS, BINARY_DEVICE_TREE_FILE);
if (!filename) {
goto out;
}
fdt = load_device_tree(filename, &fdt_size);
g_free(filename);
if (fdt == NULL) {
goto out;
}
/* Manipulate device tree in memory. */
ret = qemu_fdt_setprop(fdt, "/memory", "reg", mem_reg_property,
sizeof(mem_reg_property));
if (ret < 0) {
error_report("couldn't set /memory/reg");
}
/* default FDT doesn't have a /chosen node... */
qemu_fdt_add_subnode(fdt, "/chosen");
ret = qemu_fdt_setprop_cell(fdt, "/chosen", "linux,initrd-start",
initrd_base);
if (ret < 0) {
error_report("couldn't set /chosen/linux,initrd-start");
}
ret = qemu_fdt_setprop_cell(fdt, "/chosen", "linux,initrd-end",
(initrd_base + initrd_size));
if (ret < 0) {
error_report("couldn't set /chosen/linux,initrd-end");
}
ret = qemu_fdt_setprop_string(fdt, "/chosen", "bootargs",
kernel_cmdline);
if (ret < 0) {
error_report("couldn't set /chosen/bootargs");
}
/* Copy data from the host device tree into the guest. Since the guest can
* directly access the timebase without host involvement, we must expose
* the correct frequencies. */
if (kvm_enabled()) {
tb_freq = kvmppc_get_tbfreq();
clock_freq = kvmppc_get_clockfreq();
}
qemu_fdt_setprop_cell(fdt, "/cpus/cpu@0", "clock-frequency",
clock_freq);
qemu_fdt_setprop_cell(fdt, "/cpus/cpu@0", "timebase-frequency",
tb_freq);
rom_add_blob_fixed(BINARY_DEVICE_TREE_FILE, fdt, fdt_size, addr);
g_free(fdt);
ret = fdt_size;
out:
return ret;
}
/* Create reset TLB entries for BookE, mapping only the flash memory. */
static void mmubooke_create_initial_mapping_uboot(CPUPPCState *env)
{
ppcemb_tlb_t *tlb = &env->tlb.tlbe[0];
/* on reset the flash is mapped by a shadow TLB,
* but since we don't implement them we need to use
* the same values U-Boot will use to avoid a fault.
*/
tlb->attr = 0;
tlb->prot = PAGE_VALID | ((PAGE_READ | PAGE_WRITE | PAGE_EXEC) << 4);
tlb->size = 0x10000000; /* up to 0xffffffff */
tlb->EPN = 0xf0000000 & TARGET_PAGE_MASK;
tlb->RPN = (0xf0000000 & TARGET_PAGE_MASK) | 0x4;
tlb->PID = 0;
}
/* Create reset TLB entries for BookE, spanning the 32bit addr space. */
static void mmubooke_create_initial_mapping(CPUPPCState *env,
target_ulong va,
hwaddr pa)
{
ppcemb_tlb_t *tlb = &env->tlb.tlbe[0];
tlb->attr = 0;
tlb->prot = PAGE_VALID | ((PAGE_READ | PAGE_WRITE | PAGE_EXEC) << 4);
tlb->size = 1 << 31; /* up to 0x80000000 */
tlb->EPN = va & TARGET_PAGE_MASK;
tlb->RPN = pa & TARGET_PAGE_MASK;
tlb->PID = 0;
}
static void main_cpu_reset(void *opaque)
{
PowerPCCPU *cpu = opaque;
CPUPPCState *env = &cpu->env;
struct boot_info *bi = env->load_info;
cpu_reset(CPU(cpu));
/* either we have a kernel to boot or we jump to U-Boot */
if (bi->entry != UBOOT_ENTRY) {
env->gpr[1] = (16 << 20) - 8;
env->gpr[3] = FDT_ADDR;
env->nip = bi->entry;
/* Create a mapping for the kernel. */
mmubooke_create_initial_mapping(env, 0, 0);
env->gpr[6] = tswap32(EPAPR_MAGIC);
env->gpr[7] = (16 << 20) - 8; /*bi->ima_size;*/
} else {
env->nip = UBOOT_ENTRY;
mmubooke_create_initial_mapping_uboot(env);
}
}
static void sam460ex_init(MachineState *machine)
{
MemoryRegion *address_space_mem = get_system_memory();
MemoryRegion *isa = g_new(MemoryRegion, 1);
MemoryRegion *ram_memories = g_new(MemoryRegion, SDRAM_NR_BANKS);
hwaddr ram_bases[SDRAM_NR_BANKS];
hwaddr ram_sizes[SDRAM_NR_BANKS];
MemoryRegion *l2cache_ram = g_new(MemoryRegion, 1);
qemu_irq *irqs, *uic[4];
PCIBus *pci_bus;
PowerPCCPU *cpu;
CPUPPCState *env;
PPC4xxI2CState *i2c[2];
hwaddr entry = UBOOT_ENTRY;
hwaddr loadaddr = 0;
target_long initrd_size = 0;
DeviceState *dev;
SysBusDevice *sbdev;
int success;
int i;
struct boot_info *boot_info;
const size_t smbus_eeprom_size = 8 * 256;
uint8_t *smbus_eeprom_buf = g_malloc0(smbus_eeprom_size);
cpu = POWERPC_CPU(cpu_create(machine->cpu_type));
env = &cpu->env;
if (env->mmu_model != POWERPC_MMU_BOOKE) {
error_report("Only MMU model BookE is supported by this machine.");
exit(1);
}
#ifdef TARGET_PPCEMB
if (!qtest_enabled()) {
warn_report("qemu-system-ppcemb is deprecated, "
"please use qemu-system-ppc instead.");
}
#endif
qemu_register_reset(main_cpu_reset, cpu);
boot_info = g_malloc0(sizeof(*boot_info));
env->load_info = boot_info;
ppc_booke_timers_init(cpu, 50000000, 0);
ppc_dcr_init(env, NULL, NULL);
/* PLB arbitrer */
ppc4xx_plb_init(env);
/* interrupt controllers */
irqs = g_malloc0(sizeof(*irqs) * PPCUIC_OUTPUT_NB);
irqs[PPCUIC_OUTPUT_INT] = ((qemu_irq *)env->irq_inputs)[PPC40x_INPUT_INT];
irqs[PPCUIC_OUTPUT_CINT] = ((qemu_irq *)env->irq_inputs)[PPC40x_INPUT_CINT];
uic[0] = ppcuic_init(env, irqs, 0xc0, 0, 1);
uic[1] = ppcuic_init(env, &uic[0][30], 0xd0, 0, 1);
uic[2] = ppcuic_init(env, &uic[0][10], 0xe0, 0, 1);
uic[3] = ppcuic_init(env, &uic[0][16], 0xf0, 0, 1);
/* SDRAM controller */
memset(ram_bases, 0, sizeof(ram_bases));
memset(ram_sizes, 0, sizeof(ram_sizes));
/* put all RAM on first bank because board has one slot
* and firmware only checks that */
machine->ram_size = ppc4xx_sdram_adjust(machine->ram_size, 1,
ram_memories, ram_bases, ram_sizes,
ppc460ex_sdram_bank_sizes);
/* FIXME: does 460EX have ECC interrupts? */
ppc440_sdram_init(env, SDRAM_NR_BANKS, ram_memories,
ram_bases, ram_sizes, 1);
/* generate SPD EEPROM data */
for (i = 0; i < SDRAM_NR_BANKS; i++) {
generate_eeprom_spd(&smbus_eeprom_buf[i * 256], ram_sizes[i]);
}
generate_eeprom_serial(&smbus_eeprom_buf[4 * 256]);
generate_eeprom_serial(&smbus_eeprom_buf[6 * 256]);
/* IIC controllers */
dev = sysbus_create_simple(TYPE_PPC4xx_I2C, 0x4ef600700, uic[0][2]);
i2c[0] = PPC4xx_I2C(dev);
object_property_set_bool(OBJECT(dev), true, "realized", NULL);
smbus_eeprom_init(i2c[0]->bus, 8, smbus_eeprom_buf, smbus_eeprom_size);
g_free(smbus_eeprom_buf);
dev = sysbus_create_simple(TYPE_PPC4xx_I2C, 0x4ef600800, uic[0][3]);
i2c[1] = PPC4xx_I2C(dev);
/* External bus controller */
ppc405_ebc_init(env);
/* CPR */
ppc4xx_cpr_init(env);
/* PLB to AHB bridge */
ppc4xx_ahb_init(env);
/* System DCRs */
ppc4xx_sdr_init(env);
/* MAL */
ppc4xx_mal_init(env, 4, 16, &uic[2][3]);
/* 256K of L2 cache as memory */
ppc4xx_l2sram_init(env);
/* FIXME: remove this after fixing l2sram mapping in ppc440_uc.c? */
memory_region_init_ram(l2cache_ram, NULL, "ppc440.l2cache_ram", 256 << 10,
&error_abort);
memory_region_add_subregion(address_space_mem, 0x400000000LL, l2cache_ram);
/* USB */
sysbus_create_simple(TYPE_PPC4xx_EHCI, 0x4bffd0400, uic[2][29]);
dev = qdev_create(NULL, "sysbus-ohci");
qdev_prop_set_string(dev, "masterbus", "usb-bus.0");
qdev_prop_set_uint32(dev, "num-ports", 6);
qdev_init_nofail(dev);
sbdev = SYS_BUS_DEVICE(dev);
sysbus_mmio_map(sbdev, 0, 0x4bffd0000);
sysbus_connect_irq(sbdev, 0, uic[2][30]);
usb_create_simple(usb_bus_find(-1), "usb-kbd");
usb_create_simple(usb_bus_find(-1), "usb-mouse");
/* PCI bus */
ppc460ex_pcie_init(env);
/* FIXME: is this correct? */
dev = sysbus_create_varargs("ppc440-pcix-host", 0xc0ec00000,
uic[1][0], uic[1][20], uic[1][21], uic[1][22],
NULL);
pci_bus = (PCIBus *)qdev_get_child_bus(dev, "pci.0");
if (!pci_bus) {
error_report("couldn't create PCI controller!");
exit(1);
}
memory_region_init_alias(isa, NULL, "isa_mmio", get_system_io(),
0, 0x10000);
memory_region_add_subregion(get_system_memory(), 0xc08000000, isa);
/* PCI devices */
pci_create_simple(pci_bus, PCI_DEVFN(6, 0), "sm501");
/* SoC has a single SATA port but we don't emulate that yet
* However, firmware and usual clients have driver for SiI311x
* so add one for convenience by default */
if (defaults_enabled()) {
pci_create_simple(pci_bus, -1, "sii3112");
}
/* SoC has 4 UARTs
* but board has only one wired and two are present in fdt */
if (serial_hds[0] != NULL) {
serial_mm_init(address_space_mem, 0x4ef600300, 0, uic[1][1],
PPC_SERIAL_MM_BAUDBASE, serial_hds[0],
DEVICE_BIG_ENDIAN);
}
if (serial_hds[1] != NULL) {
serial_mm_init(address_space_mem, 0x4ef600400, 0, uic[0][1],
PPC_SERIAL_MM_BAUDBASE, serial_hds[1],
DEVICE_BIG_ENDIAN);
}
/* Load U-Boot image. */
if (!machine->kernel_filename) {
success = sam460ex_load_uboot();
if (success < 0) {
error_report("qemu: could not load firmware");
exit(1);
}
}
/* Load kernel. */
if (machine->kernel_filename) {
success = load_uimage(machine->kernel_filename, &entry, &loadaddr,
NULL, NULL, NULL);
if (success < 0) {
uint64_t elf_entry, elf_lowaddr;
success = load_elf(machine->kernel_filename, NULL, NULL, &elf_entry,
&elf_lowaddr, NULL, 1, PPC_ELF_MACHINE, 0, 0);
entry = elf_entry;
loadaddr = elf_lowaddr;
}
/* XXX try again as binary */
if (success < 0) {
error_report("qemu: could not load kernel '%s'",
machine->kernel_filename);
exit(1);
}
}
/* Load initrd. */
if (machine->initrd_filename) {
initrd_size = load_image_targphys(machine->initrd_filename,
RAMDISK_ADDR,
machine->ram_size - RAMDISK_ADDR);
if (initrd_size < 0) {
error_report("qemu: could not load ram disk '%s' at %x",
machine->initrd_filename, RAMDISK_ADDR);
exit(1);
}
}
/* If we're loading a kernel directly, we must load the device tree too. */
if (machine->kernel_filename) {
int dt_size;
dt_size = sam460ex_load_device_tree(FDT_ADDR, machine->ram_size,
RAMDISK_ADDR, initrd_size,
machine->kernel_cmdline);
if (dt_size < 0) {
error_report("couldn't load device tree");
exit(1);
}
boot_info->dt_base = FDT_ADDR;
boot_info->dt_size = dt_size;
}
boot_info->entry = entry;
}
static void sam460ex_machine_init(MachineClass *mc)
{
mc->desc = "aCube Sam460ex";
mc->init = sam460ex_init;
mc->default_cpu_type = POWERPC_CPU_TYPE_NAME("460exb");
mc->default_ram_size = 512 * M_BYTE;
}
DEFINE_MACHINE("sam460ex", sam460ex_machine_init)

View File

@ -105,12 +105,14 @@
*/ */
static int spapr_vcpu_id(sPAPRMachineState *spapr, int cpu_index) static int spapr_vcpu_id(sPAPRMachineState *spapr, int cpu_index)
{ {
assert(spapr->vsmt);
return return
(cpu_index / smp_threads) * spapr->vsmt + cpu_index % smp_threads; (cpu_index / smp_threads) * spapr->vsmt + cpu_index % smp_threads;
} }
static bool spapr_is_thread0_in_vcore(sPAPRMachineState *spapr, static bool spapr_is_thread0_in_vcore(sPAPRMachineState *spapr,
PowerPCCPU *cpu) PowerPCCPU *cpu)
{ {
assert(spapr->vsmt);
return spapr_get_vcpu_id(cpu) % spapr->vsmt == 0; return spapr_get_vcpu_id(cpu) % spapr->vsmt == 0;
} }
@ -177,13 +179,13 @@ static void pre_2_10_vmstate_unregister_dummy_icp(int i)
static int xics_max_server_number(sPAPRMachineState *spapr) static int xics_max_server_number(sPAPRMachineState *spapr)
{ {
assert(spapr->vsmt);
return DIV_ROUND_UP(max_cpus * spapr->vsmt, smp_threads); return DIV_ROUND_UP(max_cpus * spapr->vsmt, smp_threads);
} }
static void xics_system_init(MachineState *machine, int nr_irqs, Error **errp) static void xics_system_init(MachineState *machine, int nr_irqs, Error **errp)
{ {
sPAPRMachineState *spapr = SPAPR_MACHINE(machine); sPAPRMachineState *spapr = SPAPR_MACHINE(machine);
sPAPRMachineClass *smc = SPAPR_MACHINE_GET_CLASS(machine);
if (kvm_enabled()) { if (kvm_enabled()) {
if (machine_kernel_irqchip_allowed(machine) && if (machine_kernel_irqchip_allowed(machine) &&
@ -205,17 +207,6 @@ static void xics_system_init(MachineState *machine, int nr_irqs, Error **errp)
return; return;
} }
} }
if (smc->pre_2_10_has_unused_icps) {
int i;
for (i = 0; i < xics_max_server_number(spapr); i++) {
/* Dummy entries get deregistered when real ICPState objects
* are registered during CPU core hotplug.
*/
pre_2_10_vmstate_register_dummy_icp(i);
}
}
} }
static int spapr_fixup_cpu_smt_dt(void *fdt, int offset, PowerPCCPU *cpu, static int spapr_fixup_cpu_smt_dt(void *fdt, int offset, PowerPCCPU *cpu,
@ -1062,7 +1053,14 @@ static void spapr_dt_chosen(sPAPRMachineState *spapr, void *fdt)
} }
if (!spapr->has_graphics && stdout_path) { if (!spapr->has_graphics && stdout_path) {
/*
* "linux,stdout-path" and "stdout" properties are deprecated by linux
* kernel. New platforms should only use the "stdout-path" property. Set
* the new property and continue using older property to remain
* compatible with the existing firmware.
*/
_FDT(fdt_setprop_string(fdt, chosen, "linux,stdout-path", stdout_path)); _FDT(fdt_setprop_string(fdt, chosen, "linux,stdout-path", stdout_path));
_FDT(fdt_setprop_string(fdt, chosen, "stdout-path", stdout_path));
} }
spapr_dt_ov5_platform_support(fdt, chosen); spapr_dt_ov5_platform_support(fdt, chosen);
@ -2232,61 +2230,6 @@ static CPUArchId *spapr_find_cpu_slot(MachineState *ms, uint32_t id, int *idx)
return &ms->possible_cpus->cpus[index]; return &ms->possible_cpus->cpus[index];
} }
static void spapr_init_cpus(sPAPRMachineState *spapr)
{
MachineState *machine = MACHINE(spapr);
MachineClass *mc = MACHINE_GET_CLASS(machine);
const char *type = spapr_get_cpu_core_type(machine->cpu_type);
const CPUArchIdList *possible_cpus;
int boot_cores_nr = smp_cpus / smp_threads;
int i;
possible_cpus = mc->possible_cpu_arch_ids(machine);
if (mc->has_hotpluggable_cpus) {
if (smp_cpus % smp_threads) {
error_report("smp_cpus (%u) must be multiple of threads (%u)",
smp_cpus, smp_threads);
exit(1);
}
if (max_cpus % smp_threads) {
error_report("max_cpus (%u) must be multiple of threads (%u)",
max_cpus, smp_threads);
exit(1);
}
} else {
if (max_cpus != smp_cpus) {
error_report("This machine version does not support CPU hotplug");
exit(1);
}
boot_cores_nr = possible_cpus->len;
}
for (i = 0; i < possible_cpus->len; i++) {
int core_id = i * smp_threads;
if (mc->has_hotpluggable_cpus) {
spapr_dr_connector_new(OBJECT(spapr), TYPE_SPAPR_DRC_CPU,
spapr_vcpu_id(spapr, core_id));
}
if (i < boot_cores_nr) {
Object *core = object_new(type);
int nr_threads = smp_threads;
/* Handle the partially filled core for older machine types */
if ((i + 1) * smp_threads >= smp_cpus) {
nr_threads = smp_cpus - i * smp_threads;
}
object_property_set_int(core, nr_threads, "nr-threads",
&error_fatal);
object_property_set_int(core, core_id, CPU_CORE_PROP_CORE_ID,
&error_fatal);
object_property_set_bool(core, true, "realized", &error_fatal);
}
}
}
static void spapr_set_vsmt_mode(sPAPRMachineState *spapr, Error **errp) static void spapr_set_vsmt_mode(sPAPRMachineState *spapr, Error **errp)
{ {
Error *local_err = NULL; Error *local_err = NULL;
@ -2359,6 +2302,78 @@ out:
error_propagate(errp, local_err); error_propagate(errp, local_err);
} }
static void spapr_init_cpus(sPAPRMachineState *spapr)
{
MachineState *machine = MACHINE(spapr);
MachineClass *mc = MACHINE_GET_CLASS(machine);
sPAPRMachineClass *smc = SPAPR_MACHINE_GET_CLASS(machine);
const char *type = spapr_get_cpu_core_type(machine->cpu_type);
const CPUArchIdList *possible_cpus;
int boot_cores_nr = smp_cpus / smp_threads;
int i;
possible_cpus = mc->possible_cpu_arch_ids(machine);
if (mc->has_hotpluggable_cpus) {
if (smp_cpus % smp_threads) {
error_report("smp_cpus (%u) must be multiple of threads (%u)",
smp_cpus, smp_threads);
exit(1);
}
if (max_cpus % smp_threads) {
error_report("max_cpus (%u) must be multiple of threads (%u)",
max_cpus, smp_threads);
exit(1);
}
} else {
if (max_cpus != smp_cpus) {
error_report("This machine version does not support CPU hotplug");
exit(1);
}
boot_cores_nr = possible_cpus->len;
}
/* VSMT must be set in order to be able to compute VCPU ids, ie to
* call xics_max_server_number() or spapr_vcpu_id().
*/
spapr_set_vsmt_mode(spapr, &error_fatal);
if (smc->pre_2_10_has_unused_icps) {
int i;
for (i = 0; i < xics_max_server_number(spapr); i++) {
/* Dummy entries get deregistered when real ICPState objects
* are registered during CPU core hotplug.
*/
pre_2_10_vmstate_register_dummy_icp(i);
}
}
for (i = 0; i < possible_cpus->len; i++) {
int core_id = i * smp_threads;
if (mc->has_hotpluggable_cpus) {
spapr_dr_connector_new(OBJECT(spapr), TYPE_SPAPR_DRC_CPU,
spapr_vcpu_id(spapr, core_id));
}
if (i < boot_cores_nr) {
Object *core = object_new(type);
int nr_threads = smp_threads;
/* Handle the partially filled core for older machine types */
if ((i + 1) * smp_threads >= smp_cpus) {
nr_threads = smp_cpus - i * smp_threads;
}
object_property_set_int(core, nr_threads, "nr-threads",
&error_fatal);
object_property_set_int(core, core_id, CPU_CORE_PROP_CORE_ID,
&error_fatal);
object_property_set_bool(core, true, "realized", &error_fatal);
}
}
}
/* pSeries LPAR / sPAPR hardware init */ /* pSeries LPAR / sPAPR hardware init */
static void spapr_machine_init(MachineState *machine) static void spapr_machine_init(MachineState *machine)
{ {
@ -2486,8 +2501,6 @@ static void spapr_machine_init(MachineState *machine)
} }
/* init CPUs */ /* init CPUs */
spapr_set_vsmt_mode(spapr, &error_fatal);
spapr_init_cpus(spapr); spapr_init_cpus(spapr);
if (kvm_enabled()) { if (kvm_enabled()) {
@ -3810,13 +3823,7 @@ static void spapr_pic_print_info(InterruptStatsProvider *obj,
int spapr_get_vcpu_id(PowerPCCPU *cpu) int spapr_get_vcpu_id(PowerPCCPU *cpu)
{ {
CPUState *cs = CPU(cpu); return cpu->vcpu_id;
if (kvm_enabled()) {
return kvm_arch_vcpu_id(cs);
} else {
return cs->cpu_index;
}
} }
void spapr_set_vcpu_id(PowerPCCPU *cpu, int cpu_index, Error **errp) void spapr_set_vcpu_id(PowerPCCPU *cpu, int cpu_index, Error **errp)
@ -3983,6 +3990,23 @@ static void spapr_machine_2_12_class_options(MachineClass *mc)
DEFINE_SPAPR_MACHINE(2_12, "2.12", true); DEFINE_SPAPR_MACHINE(2_12, "2.12", true);
static void spapr_machine_2_12_sxxm_instance_options(MachineState *machine)
{
spapr_machine_2_12_instance_options(machine);
}
static void spapr_machine_2_12_sxxm_class_options(MachineClass *mc)
{
sPAPRMachineClass *smc = SPAPR_MACHINE_CLASS(mc);
spapr_machine_2_12_class_options(mc);
smc->default_caps.caps[SPAPR_CAP_CFPC] = SPAPR_CAP_WORKAROUND;
smc->default_caps.caps[SPAPR_CAP_SBBC] = SPAPR_CAP_WORKAROUND;
smc->default_caps.caps[SPAPR_CAP_IBS] = SPAPR_CAP_FIXED_CCD;
}
DEFINE_SPAPR_MACHINE(2_12_sxxm, "2.12-sxxm", false);
/* /*
* pseries-2.11 * pseries-2.11
*/ */

View File

@ -32,6 +32,20 @@
#include "hw/ppc/spapr.h" #include "hw/ppc/spapr.h"
typedef struct sPAPRCapPossible {
int num; /* size of vals array below */
const char *help; /* help text for vals */
/*
* Note:
* - because of the way compatibility is determined vals MUST be ordered
* such that later options are a superset of all preceding options.
* - the order of vals must be preserved, that is their index is important,
* however vals may be added to the end of the list so long as the above
* point is observed
*/
const char *vals[];
} sPAPRCapPossible;
typedef struct sPAPRCapabilityInfo { typedef struct sPAPRCapabilityInfo {
const char *name; const char *name;
const char *description; const char *description;
@ -41,6 +55,8 @@ typedef struct sPAPRCapabilityInfo {
ObjectPropertyAccessor *get; ObjectPropertyAccessor *get;
ObjectPropertyAccessor *set; ObjectPropertyAccessor *set;
const char *type; const char *type;
/* Possible values if this is a custom string type */
sPAPRCapPossible *possible;
/* Make sure the virtual hardware can support this capability */ /* Make sure the virtual hardware can support this capability */
void (*apply)(sPAPRMachineState *spapr, uint8_t val, Error **errp); void (*apply)(sPAPRMachineState *spapr, uint8_t val, Error **errp);
} sPAPRCapabilityInfo; } sPAPRCapabilityInfo;
@ -73,41 +89,34 @@ static void spapr_cap_set_bool(Object *obj, Visitor *v, const char *name,
spapr->eff.caps[cap->index] = value ? SPAPR_CAP_ON : SPAPR_CAP_OFF; spapr->eff.caps[cap->index] = value ? SPAPR_CAP_ON : SPAPR_CAP_OFF;
} }
static void spapr_cap_get_tristate(Object *obj, Visitor *v, const char *name,
void *opaque, Error **errp) static void spapr_cap_get_string(Object *obj, Visitor *v, const char *name,
void *opaque, Error **errp)
{ {
sPAPRCapabilityInfo *cap = opaque; sPAPRCapabilityInfo *cap = opaque;
sPAPRMachineState *spapr = SPAPR_MACHINE(obj); sPAPRMachineState *spapr = SPAPR_MACHINE(obj);
char *val = NULL; char *val = NULL;
uint8_t value = spapr_get_cap(spapr, cap->index); uint8_t value = spapr_get_cap(spapr, cap->index);
switch (value) { if (value >= cap->possible->num) {
case SPAPR_CAP_BROKEN:
val = g_strdup("broken");
break;
case SPAPR_CAP_WORKAROUND:
val = g_strdup("workaround");
break;
case SPAPR_CAP_FIXED:
val = g_strdup("fixed");
break;
default:
error_setg(errp, "Invalid value (%d) for cap-%s", value, cap->name); error_setg(errp, "Invalid value (%d) for cap-%s", value, cap->name);
return; return;
} }
val = g_strdup(cap->possible->vals[value]);
visit_type_str(v, name, &val, errp); visit_type_str(v, name, &val, errp);
g_free(val); g_free(val);
} }
static void spapr_cap_set_tristate(Object *obj, Visitor *v, const char *name, static void spapr_cap_set_string(Object *obj, Visitor *v, const char *name,
void *opaque, Error **errp) void *opaque, Error **errp)
{ {
sPAPRCapabilityInfo *cap = opaque; sPAPRCapabilityInfo *cap = opaque;
sPAPRMachineState *spapr = SPAPR_MACHINE(obj); sPAPRMachineState *spapr = SPAPR_MACHINE(obj);
char *val;
Error *local_err = NULL; Error *local_err = NULL;
uint8_t value; uint8_t i;
char *val;
visit_type_str(v, name, &val, &local_err); visit_type_str(v, name, &val, &local_err);
if (local_err) { if (local_err) {
@ -115,20 +124,20 @@ static void spapr_cap_set_tristate(Object *obj, Visitor *v, const char *name,
return; return;
} }
if (!strcasecmp(val, "broken")) { if (!strcmp(val, "?")) {
value = SPAPR_CAP_BROKEN; error_setg(errp, "%s", cap->possible->help);
} else if (!strcasecmp(val, "workaround")) {
value = SPAPR_CAP_WORKAROUND;
} else if (!strcasecmp(val, "fixed")) {
value = SPAPR_CAP_FIXED;
} else {
error_setg(errp, "Invalid capability mode \"%s\" for cap-%s", val,
cap->name);
goto out; goto out;
} }
for (i = 0; i < cap->possible->num; i++) {
if (!strcasecmp(val, cap->possible->vals[i])) {
spapr->cmd_line_caps[cap->index] = true;
spapr->eff.caps[cap->index] = i;
goto out;
}
}
spapr->cmd_line_caps[cap->index] = true; error_setg(errp, "Invalid capability mode \"%s\" for cap-%s", val,
spapr->eff.caps[cap->index] = value; cap->name);
out: out:
g_free(val); g_free(val);
} }
@ -180,38 +189,77 @@ static void cap_dfp_apply(sPAPRMachineState *spapr, uint8_t val, Error **errp)
} }
} }
sPAPRCapPossible cap_cfpc_possible = {
.num = 3,
.vals = {"broken", "workaround", "fixed"},
.help = "broken - no protection, workaround - workaround available,"
" fixed - fixed in hardware",
};
static void cap_safe_cache_apply(sPAPRMachineState *spapr, uint8_t val, static void cap_safe_cache_apply(sPAPRMachineState *spapr, uint8_t val,
Error **errp) Error **errp)
{ {
uint8_t kvm_val = kvmppc_get_cap_safe_cache();
if (tcg_enabled() && val) { if (tcg_enabled() && val) {
/* TODO - for now only allow broken for TCG */ /* TODO - for now only allow broken for TCG */
error_setg(errp, "Requested safe cache capability level not supported by tcg, try a different value for cap-cfpc"); error_setg(errp,
} else if (kvm_enabled() && (val > kvmppc_get_cap_safe_cache())) { "Requested safe cache capability level not supported by tcg, try a different value for cap-cfpc");
error_setg(errp, "Requested safe cache capability level not supported by kvm, try a different value for cap-cfpc"); } else if (kvm_enabled() && (val > kvm_val)) {
error_setg(errp,
"Requested safe cache capability level not supported by kvm, try cap-cfpc=%s",
cap_cfpc_possible.vals[kvm_val]);
} }
} }
sPAPRCapPossible cap_sbbc_possible = {
.num = 3,
.vals = {"broken", "workaround", "fixed"},
.help = "broken - no protection, workaround - workaround available,"
" fixed - fixed in hardware",
};
static void cap_safe_bounds_check_apply(sPAPRMachineState *spapr, uint8_t val, static void cap_safe_bounds_check_apply(sPAPRMachineState *spapr, uint8_t val,
Error **errp) Error **errp)
{ {
uint8_t kvm_val = kvmppc_get_cap_safe_bounds_check();
if (tcg_enabled() && val) { if (tcg_enabled() && val) {
/* TODO - for now only allow broken for TCG */ /* TODO - for now only allow broken for TCG */
error_setg(errp, "Requested safe bounds check capability level not supported by tcg, try a different value for cap-sbbc"); error_setg(errp,
} else if (kvm_enabled() && (val > kvmppc_get_cap_safe_bounds_check())) { "Requested safe bounds check capability level not supported by tcg, try a different value for cap-sbbc");
error_setg(errp, "Requested safe bounds check capability level not supported by kvm, try a different value for cap-sbbc"); } else if (kvm_enabled() && (val > kvm_val)) {
error_setg(errp,
"Requested safe bounds check capability level not supported by kvm, try cap-sbbc=%s",
cap_sbbc_possible.vals[kvm_val]);
} }
} }
sPAPRCapPossible cap_ibs_possible = {
.num = 4,
/* Note workaround only maintained for compatibility */
.vals = {"broken", "workaround", "fixed-ibs", "fixed-ccd"},
.help = "broken - no protection, fixed-ibs - indirect branch serialisation,"
" fixed-ccd - cache count disabled",
};
static void cap_safe_indirect_branch_apply(sPAPRMachineState *spapr, static void cap_safe_indirect_branch_apply(sPAPRMachineState *spapr,
uint8_t val, Error **errp) uint8_t val, Error **errp)
{ {
uint8_t kvm_val = kvmppc_get_cap_safe_indirect_branch();
if (val == SPAPR_CAP_WORKAROUND) { /* Can only be Broken or Fixed */ if (val == SPAPR_CAP_WORKAROUND) { /* Can only be Broken or Fixed */
error_setg(errp, "Requested safe indirect branch capability level \"workaround\" not valid, try cap-ibs=fixed"); error_setg(errp,
"Requested safe indirect branch capability level \"workaround\" not valid, try cap-ibs=%s",
cap_ibs_possible.vals[kvm_val]);
} else if (tcg_enabled() && val) { } else if (tcg_enabled() && val) {
/* TODO - for now only allow broken for TCG */ /* TODO - for now only allow broken for TCG */
error_setg(errp, "Requested safe indirect branch capability level not supported by tcg, try a different value for cap-ibs"); error_setg(errp,
} else if (kvm_enabled() && (val > kvmppc_get_cap_safe_indirect_branch())) { "Requested safe indirect branch capability level not supported by tcg, try a different value for cap-ibs");
error_setg(errp, "Requested safe indirect branch capability level not supported by kvm, try a different value for cap-ibs"); } else if (kvm_enabled() && val && (val != kvm_val)) {
error_setg(errp,
"Requested safe indirect branch capability level not supported by kvm, try cap-ibs=%s",
cap_ibs_possible.vals[kvm_val]);
} }
} }
@ -249,27 +297,31 @@ sPAPRCapabilityInfo capability_table[SPAPR_CAP_NUM] = {
.name = "cfpc", .name = "cfpc",
.description = "Cache Flush on Privilege Change" VALUE_DESC_TRISTATE, .description = "Cache Flush on Privilege Change" VALUE_DESC_TRISTATE,
.index = SPAPR_CAP_CFPC, .index = SPAPR_CAP_CFPC,
.get = spapr_cap_get_tristate, .get = spapr_cap_get_string,
.set = spapr_cap_set_tristate, .set = spapr_cap_set_string,
.type = "string", .type = "string",
.possible = &cap_cfpc_possible,
.apply = cap_safe_cache_apply, .apply = cap_safe_cache_apply,
}, },
[SPAPR_CAP_SBBC] = { [SPAPR_CAP_SBBC] = {
.name = "sbbc", .name = "sbbc",
.description = "Speculation Barrier Bounds Checking" VALUE_DESC_TRISTATE, .description = "Speculation Barrier Bounds Checking" VALUE_DESC_TRISTATE,
.index = SPAPR_CAP_SBBC, .index = SPAPR_CAP_SBBC,
.get = spapr_cap_get_tristate, .get = spapr_cap_get_string,
.set = spapr_cap_set_tristate, .set = spapr_cap_set_string,
.type = "string", .type = "string",
.possible = &cap_sbbc_possible,
.apply = cap_safe_bounds_check_apply, .apply = cap_safe_bounds_check_apply,
}, },
[SPAPR_CAP_IBS] = { [SPAPR_CAP_IBS] = {
.name = "ibs", .name = "ibs",
.description = "Indirect Branch Serialisation (broken, fixed)", .description =
"Indirect Branch Speculation (broken, fixed-ibs, fixed-ccd)",
.index = SPAPR_CAP_IBS, .index = SPAPR_CAP_IBS,
.get = spapr_cap_get_tristate, .get = spapr_cap_get_string,
.set = spapr_cap_set_tristate, .set = spapr_cap_set_string,
.type = "string", .type = "string",
.possible = &cap_ibs_possible,
.apply = cap_safe_indirect_branch_apply, .apply = cap_safe_indirect_branch_apply,
}, },
}; };
@ -283,15 +335,26 @@ static sPAPRCapabilities default_caps_with_cpu(sPAPRMachineState *spapr,
caps = smc->default_caps; caps = smc->default_caps;
if (!ppc_check_compat(cpu, CPU_POWERPC_LOGICAL_3_00,
0, spapr->max_compat_pvr)) {
caps.caps[SPAPR_CAP_CFPC] = SPAPR_CAP_BROKEN;
}
if (!ppc_check_compat(cpu, CPU_POWERPC_LOGICAL_2_07, if (!ppc_check_compat(cpu, CPU_POWERPC_LOGICAL_2_07,
0, spapr->max_compat_pvr)) { 0, spapr->max_compat_pvr)) {
caps.caps[SPAPR_CAP_HTM] = SPAPR_CAP_OFF; caps.caps[SPAPR_CAP_HTM] = SPAPR_CAP_OFF;
} }
if (!ppc_check_compat(cpu, CPU_POWERPC_LOGICAL_2_06_PLUS,
0, spapr->max_compat_pvr)) {
caps.caps[SPAPR_CAP_SBBC] = SPAPR_CAP_BROKEN;
}
if (!ppc_check_compat(cpu, CPU_POWERPC_LOGICAL_2_06, if (!ppc_check_compat(cpu, CPU_POWERPC_LOGICAL_2_06,
0, spapr->max_compat_pvr)) { 0, spapr->max_compat_pvr)) {
caps.caps[SPAPR_CAP_VSX] = SPAPR_CAP_OFF; caps.caps[SPAPR_CAP_VSX] = SPAPR_CAP_OFF;
caps.caps[SPAPR_CAP_DFP] = SPAPR_CAP_OFF; caps.caps[SPAPR_CAP_DFP] = SPAPR_CAP_OFF;
caps.caps[SPAPR_CAP_IBS] = SPAPR_CAP_BROKEN;
} }
return caps; return caps;

View File

@ -1705,7 +1705,10 @@ static target_ulong h_get_cpu_characteristics(PowerPCCPU *cpu,
} }
switch (safe_indirect_branch) { switch (safe_indirect_branch) {
case SPAPR_CAP_FIXED: case SPAPR_CAP_FIXED_CCD:
characteristics |= H_CPU_CHAR_CACHE_COUNT_DIS;
break;
case SPAPR_CAP_FIXED_IBS:
characteristics |= H_CPU_CHAR_BCCTRL_SERIALISED; characteristics |= H_CPU_CHAR_BCCTRL_SERIALISED;
break; break;
default: /* broken */ default: /* broken */

View File

@ -99,3 +99,11 @@ mac99_uninorth_read(uint64_t addr, uint64_t value) "addr=0x%" PRIx64 " val=0x%"P
# hw/ppc/ppc4xx_pci.c # hw/ppc/ppc4xx_pci.c
ppc4xx_pci_map_irq(int32_t devfn, int irq_num, int slot) "devfn 0x%x irq %d -> %d" ppc4xx_pci_map_irq(int32_t devfn, int irq_num, int slot) "devfn 0x%x irq %d -> %d"
ppc4xx_pci_set_irq(int irq_num) "PCI irq %d" ppc4xx_pci_set_irq(int irq_num) "PCI irq %d"
# hw/ppc/ppc440_pcix.c
ppc440_pcix_map_irq(int32_t devfn, int irq_num, int slot) "devfn 0x%x irq %d -> %d"
ppc440_pcix_set_irq(int irq_num) "PCI irq %d"
ppc440_pcix_update_pim(int idx, uint64_t size, uint64_t la) "Added window %d of size=0x%" PRIx64 " to CPU=0x%" PRIx64
ppc440_pcix_update_pom(int idx, uint32_t size, uint64_t la, uint64_t pcia) "Added window %d of size=0x%x from CPU=0x%" PRIx64 " to PCI=0x%" PRIx64
ppc440_pcix_reg_read(uint64_t addr, uint32_t val) "addr 0x%" PRIx64 " = 0x%" PRIx32
ppc440_pcix_reg_write(uint64_t addr, uint64_t val) "addr 0x%" PRIx64 " = 0x%" PRIx64

View File

@ -0,0 +1,49 @@
/*
* Heathrow PIC support (OldWorld PowerMac)
*
* 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.
*/
#ifndef HEATHROW_H
#define HEATHROW_H
#define TYPE_HEATHROW "heathrow"
#define HEATHROW(obj) OBJECT_CHECK(HeathrowState, (obj), TYPE_HEATHROW)
typedef struct HeathrowPICState {
uint32_t events;
uint32_t mask;
uint32_t levels;
uint32_t level_triggered;
} HeathrowPICState;
typedef struct HeathrowState {
SysBusDevice parent_obj;
MemoryRegion mem;
HeathrowPICState pics[2];
qemu_irq *irqs;
} HeathrowState;
#define HEATHROW_NUM_IRQS 64
#endif /* HEATHROW_H */

View File

@ -0,0 +1,79 @@
/*
* 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.
*/
#ifndef MACIO_H
#define MACIO_H
#include "hw/intc/heathrow_pic.h"
#include "hw/misc/macio/cuda.h"
#include "hw/ppc/mac_dbdma.h"
#include "hw/ppc/openpic.h"
#define TYPE_MACIO "macio"
#define MACIO(obj) OBJECT_CHECK(MacIOState, (obj), TYPE_MACIO)
typedef struct MacIOState {
/*< private >*/
PCIDevice parent;
/*< public >*/
MemoryRegion bar;
CUDAState cuda;
DBDMAState dbdma;
ESCCState escc;
uint64_t frequency;
} MacIOState;
#define TYPE_OLDWORLD_MACIO "macio-oldworld"
#define OLDWORLD_MACIO(obj) \
OBJECT_CHECK(OldWorldMacIOState, (obj), TYPE_OLDWORLD_MACIO)
typedef struct OldWorldMacIOState {
/*< private >*/
MacIOState parent_obj;
/*< public >*/
HeathrowState *pic;
qemu_irq irqs[7];
MacIONVRAMState nvram;
MACIOIDEState ide[2];
} OldWorldMacIOState;
#define TYPE_NEWWORLD_MACIO "macio-newworld"
#define NEWWORLD_MACIO(obj) \
OBJECT_CHECK(NewWorldMacIOState, (obj), TYPE_NEWWORLD_MACIO)
typedef struct NewWorldMacIOState {
/*< private >*/
MacIOState parent_obj;
/*< public >*/
OpenPICState *pic;
qemu_irq irqs[7];
MACIOIDEState ide[2];
} NewWorldMacIOState;
#endif /* MACIO_H */

View File

@ -2,10 +2,13 @@
#define OPENPIC_H #define OPENPIC_H
#include "qemu-common.h" #include "qemu-common.h"
#include "hw/sysbus.h"
#include "hw/qdev-core.h" #include "hw/qdev-core.h"
#include "qom/cpu.h" #include "qom/cpu.h"
#define TYPE_OPENPIC "openpic" #define MAX_CPU 32
#define MAX_MSI 8
#define VID 0x03 /* MPIC version ID */
/* OpenPIC have 5 outputs per CPU connected and one IRQ out single output */ /* OpenPIC have 5 outputs per CPU connected and one IRQ out single output */
enum { enum {
@ -28,7 +31,158 @@ enum {
#define OPENPIC_MAX_IRQ (OPENPIC_MAX_SRC + OPENPIC_MAX_IPI + \ #define OPENPIC_MAX_IRQ (OPENPIC_MAX_SRC + OPENPIC_MAX_IPI + \
OPENPIC_MAX_TMR) OPENPIC_MAX_TMR)
#define TYPE_KVM_OPENPIC "kvm-openpic" /* Raven */
int kvm_openpic_connect_vcpu(DeviceState *d, CPUState *cs); #define RAVEN_MAX_CPU 2
#define RAVEN_MAX_EXT 48
#define RAVEN_MAX_IRQ 64
#define RAVEN_MAX_TMR OPENPIC_MAX_TMR
#define RAVEN_MAX_IPI OPENPIC_MAX_IPI
/* KeyLargo */
#define KEYLARGO_MAX_CPU 4
#define KEYLARGO_MAX_EXT 64
#define KEYLARGO_MAX_IPI 4
#define KEYLARGO_MAX_IRQ (64 + KEYLARGO_MAX_IPI)
#define KEYLARGO_MAX_TMR 0
#define KEYLARGO_IPI_IRQ (KEYLARGO_MAX_EXT) /* First IPI IRQ */
/* Timers don't exist but this makes the code happy... */
#define KEYLARGO_TMR_IRQ (KEYLARGO_IPI_IRQ + KEYLARGO_MAX_IPI)
/* Interrupt definitions */
#define RAVEN_FE_IRQ (RAVEN_MAX_EXT) /* Internal functional IRQ */
#define RAVEN_ERR_IRQ (RAVEN_MAX_EXT + 1) /* Error IRQ */
#define RAVEN_TMR_IRQ (RAVEN_MAX_EXT + 2) /* First timer IRQ */
#define RAVEN_IPI_IRQ (RAVEN_TMR_IRQ + RAVEN_MAX_TMR) /* First IPI IRQ */
/* First doorbell IRQ */
#define RAVEN_DBL_IRQ (RAVEN_IPI_IRQ + (RAVEN_MAX_CPU * RAVEN_MAX_IPI))
typedef struct FslMpicInfo {
int max_ext;
} FslMpicInfo;
typedef enum IRQType {
IRQ_TYPE_NORMAL = 0,
IRQ_TYPE_FSLINT, /* FSL internal interrupt -- level only */
IRQ_TYPE_FSLSPECIAL, /* FSL timer/IPI interrupt, edge, no polarity */
} IRQType;
/* Round up to the nearest 64 IRQs so that the queue length
* won't change when moving between 32 and 64 bit hosts.
*/
#define IRQQUEUE_SIZE_BITS ((OPENPIC_MAX_IRQ + 63) & ~63)
typedef struct IRQQueue {
unsigned long *queue;
int32_t queue_size; /* Only used for VMSTATE_BITMAP */
int next;
int priority;
} IRQQueue;
typedef struct IRQSource {
uint32_t ivpr; /* IRQ vector/priority register */
uint32_t idr; /* IRQ destination register */
uint32_t destmask; /* bitmap of CPU destinations */
int last_cpu;
int output; /* IRQ level, e.g. OPENPIC_OUTPUT_INT */
int pending; /* TRUE if IRQ is pending */
IRQType type;
bool level:1; /* level-triggered */
bool nomask:1; /* critical interrupts ignore mask on some FSL MPICs */
} IRQSource;
#define IVPR_MASK_SHIFT 31
#define IVPR_MASK_MASK (1U << IVPR_MASK_SHIFT)
#define IVPR_ACTIVITY_SHIFT 30
#define IVPR_ACTIVITY_MASK (1U << IVPR_ACTIVITY_SHIFT)
#define IVPR_MODE_SHIFT 29
#define IVPR_MODE_MASK (1U << IVPR_MODE_SHIFT)
#define IVPR_POLARITY_SHIFT 23
#define IVPR_POLARITY_MASK (1U << IVPR_POLARITY_SHIFT)
#define IVPR_SENSE_SHIFT 22
#define IVPR_SENSE_MASK (1U << IVPR_SENSE_SHIFT)
#define IVPR_PRIORITY_MASK (0xFU << 16)
#define IVPR_PRIORITY(_ivprr_) ((int)(((_ivprr_) & IVPR_PRIORITY_MASK) >> 16))
#define IVPR_VECTOR(opp, _ivprr_) ((_ivprr_) & (opp)->vector_mask)
/* IDR[EP/CI] are only for FSL MPIC prior to v4.0 */
#define IDR_EP 0x80000000 /* external pin */
#define IDR_CI 0x40000000 /* critical interrupt */
typedef struct OpenPICTimer {
uint32_t tccr; /* Global timer current count register */
uint32_t tbcr; /* Global timer base count register */
int n_IRQ;
bool qemu_timer_active; /* Is the qemu_timer is running? */
struct QEMUTimer *qemu_timer;
struct OpenPICState *opp; /* Device timer is part of. */
/* The QEMU_CLOCK_VIRTUAL time (in ns) corresponding to the last
current_count written or read, only defined if qemu_timer_active. */
uint64_t origin_time;
} OpenPICTimer;
typedef struct OpenPICMSI {
uint32_t msir; /* Shared Message Signaled Interrupt Register */
} OpenPICMSI;
typedef struct IRQDest {
int32_t ctpr; /* CPU current task priority */
IRQQueue raised;
IRQQueue servicing;
qemu_irq *irqs;
/* Count of IRQ sources asserting on non-INT outputs */
uint32_t outputs_active[OPENPIC_OUTPUT_NB];
} IRQDest;
#define TYPE_OPENPIC "openpic"
#define OPENPIC(obj) OBJECT_CHECK(OpenPICState, (obj), TYPE_OPENPIC)
typedef struct OpenPICState {
/*< private >*/
SysBusDevice parent_obj;
/*< public >*/
MemoryRegion mem;
/* Behavior control */
FslMpicInfo *fsl;
uint32_t model;
uint32_t flags;
uint32_t nb_irqs;
uint32_t vid;
uint32_t vir; /* Vendor identification register */
uint32_t vector_mask;
uint32_t tfrr_reset;
uint32_t ivpr_reset;
uint32_t idr_reset;
uint32_t brr1;
uint32_t mpic_mode_mask;
/* Sub-regions */
MemoryRegion sub_io_mem[6];
/* Global registers */
uint32_t frr; /* Feature reporting register */
uint32_t gcr; /* Global configuration register */
uint32_t pir; /* Processor initialization register */
uint32_t spve; /* Spurious vector register */
uint32_t tfrr; /* Timer frequency reporting register */
/* Source registers */
IRQSource src[OPENPIC_MAX_IRQ];
/* Local registers per output pin */
IRQDest dst[MAX_CPU];
uint32_t nb_cpus;
/* Timer registers */
OpenPICTimer timers[OPENPIC_MAX_TMR];
uint32_t max_tmr;
/* Shared MSI registers */
OpenPICMSI msi[MAX_MSI];
uint32_t max_irq;
uint32_t irq_ipi0;
uint32_t irq_tim0;
uint32_t irq_msi;
} OpenPICState;
#endif /* OPENPIC_H */ #endif /* OPENPIC_H */

View File

@ -0,0 +1,7 @@
#ifndef OPENPIC_KVM_H
#define OPENPIC_KVM_H
#define TYPE_KVM_OPENPIC "kvm-openpic"
int kvm_openpic_connect_vcpu(DeviceState *d, CPUState *cs);
#endif /* OPENPIC_KVM_H */

View File

@ -75,10 +75,12 @@ typedef enum {
/* Bool Caps */ /* Bool Caps */
#define SPAPR_CAP_OFF 0x00 #define SPAPR_CAP_OFF 0x00
#define SPAPR_CAP_ON 0x01 #define SPAPR_CAP_ON 0x01
/* Broken | Workaround | Fixed Caps */ /* Custom Caps */
#define SPAPR_CAP_BROKEN 0x00 #define SPAPR_CAP_BROKEN 0x00
#define SPAPR_CAP_WORKAROUND 0x01 #define SPAPR_CAP_WORKAROUND 0x01
#define SPAPR_CAP_FIXED 0x02 #define SPAPR_CAP_FIXED 0x02
#define SPAPR_CAP_FIXED_IBS 0x02
#define SPAPR_CAP_FIXED_CCD 0x03
typedef struct sPAPRCapabilities sPAPRCapabilities; typedef struct sPAPRCapabilities sPAPRCapabilities;
struct sPAPRCapabilities { struct sPAPRCapabilities {
@ -313,6 +315,7 @@ struct sPAPRMachineState {
#define H_CPU_CHAR_L1D_THREAD_PRIV PPC_BIT(4) #define H_CPU_CHAR_L1D_THREAD_PRIV PPC_BIT(4)
#define H_CPU_CHAR_HON_BRANCH_HINTS PPC_BIT(5) #define H_CPU_CHAR_HON_BRANCH_HINTS PPC_BIT(5)
#define H_CPU_CHAR_THR_RECONF_TRIG PPC_BIT(6) #define H_CPU_CHAR_THR_RECONF_TRIG PPC_BIT(6)
#define H_CPU_CHAR_CACHE_COUNT_DIS PPC_BIT(7)
#define H_CPU_BEHAV_FAVOUR_SECURITY PPC_BIT(0) #define H_CPU_BEHAV_FAVOUR_SECURITY PPC_BIT(0)
#define H_CPU_BEHAV_L1D_FLUSH_PR PPC_BIT(1) #define H_CPU_BEHAV_L1D_FLUSH_PR PPC_BIT(1)
#define H_CPU_BEHAV_BNDS_CHK_SPEC_BAR PPC_BIT(2) #define H_CPU_BEHAV_BNDS_CHK_SPEC_BAR PPC_BIT(2)

BIN
pc-bios/canyonlands.dtb Normal file

Binary file not shown.

566
pc-bios/canyonlands.dts Normal file
View File

@ -0,0 +1,566 @@
/*
* Device Tree Source for AMCC Canyonlands (460EX)
*
* Copyright 2008-2009 DENX Software Engineering, Stefan Roese <sr@denx.de>
*
* This file is licensed under the terms of the GNU General Public
* License version 2. This program is licensed "as is" without
* any warranty of any kind, whether express or implied.
*/
/dts-v1/;
/ {
#address-cells = <2>;
#size-cells = <1>;
model = "amcc,canyonlands";
compatible = "amcc,canyonlands";
dcr-parent = <&{/cpus/cpu@0}>;
aliases {
ethernet0 = &EMAC0;
ethernet1 = &EMAC1;
serial0 = &UART0;
serial1 = &UART1;
};
cpus {
#address-cells = <1>;
#size-cells = <0>;
cpu@0 {
device_type = "cpu";
model = "PowerPC,460EX";
reg = <0x00000000>;
clock-frequency = <0>; /* Filled in by U-Boot */
timebase-frequency = <0>; /* Filled in by U-Boot */
i-cache-line-size = <32>;
d-cache-line-size = <32>;
i-cache-size = <32768>;
d-cache-size = <32768>;
dcr-controller;
dcr-access-method = "native";
next-level-cache = <&L2C0>;
};
};
memory {
device_type = "memory";
reg = <0x00000000 0x00000000 0x00000000>; /* Filled in by U-Boot */
};
UIC0: interrupt-controller0 {
compatible = "ibm,uic-460ex","ibm,uic";
interrupt-controller;
cell-index = <0>;
dcr-reg = <0x0c0 0x009>;
#address-cells = <0>;
#size-cells = <0>;
#interrupt-cells = <2>;
};
UIC1: interrupt-controller1 {
compatible = "ibm,uic-460ex","ibm,uic";
interrupt-controller;
cell-index = <1>;
dcr-reg = <0x0d0 0x009>;
#address-cells = <0>;
#size-cells = <0>;
#interrupt-cells = <2>;
interrupts = <0x1e 0x4 0x1f 0x4>; /* cascade */
interrupt-parent = <&UIC0>;
};
UIC2: interrupt-controller2 {
compatible = "ibm,uic-460ex","ibm,uic";
interrupt-controller;
cell-index = <2>;
dcr-reg = <0x0e0 0x009>;
#address-cells = <0>;
#size-cells = <0>;
#interrupt-cells = <2>;
interrupts = <0xa 0x4 0xb 0x4>; /* cascade */
interrupt-parent = <&UIC0>;
};
UIC3: interrupt-controller3 {
compatible = "ibm,uic-460ex","ibm,uic";
interrupt-controller;
cell-index = <3>;
dcr-reg = <0x0f0 0x009>;
#address-cells = <0>;
#size-cells = <0>;
#interrupt-cells = <2>;
interrupts = <0x10 0x4 0x11 0x4>; /* cascade */
interrupt-parent = <&UIC0>;
};
SDR0: sdr {
compatible = "ibm,sdr-460ex";
dcr-reg = <0x00e 0x002>;
};
CPR0: cpr {
compatible = "ibm,cpr-460ex";
dcr-reg = <0x00c 0x002>;
};
CPM0: cpm {
compatible = "ibm,cpm";
dcr-access-method = "native";
dcr-reg = <0x160 0x003>;
unused-units = <0x00000100>;
idle-doze = <0x02000000>;
standby = <0xfeff791d>;
};
L2C0: l2c {
compatible = "ibm,l2-cache-460ex", "ibm,l2-cache";
dcr-reg = <0x020 0x008 /* Internal SRAM DCR's */
0x030 0x008>; /* L2 cache DCR's */
cache-line-size = <32>; /* 32 bytes */
cache-size = <262144>; /* L2, 256K */
interrupt-parent = <&UIC1>;
interrupts = <11 1>;
};
plb {
compatible = "ibm,plb-460ex", "ibm,plb4";
#address-cells = <2>;
#size-cells = <1>;
ranges;
clock-frequency = <0>; /* Filled in by U-Boot */
SDRAM0: sdram {
compatible = "ibm,sdram-460ex", "ibm,sdram-405gp";
dcr-reg = <0x010 0x002>;
};
CRYPTO: crypto@180000 {
compatible = "amcc,ppc460ex-crypto", "amcc,ppc4xx-crypto";
reg = <4 0x00180000 0x80400>;
interrupt-parent = <&UIC0>;
interrupts = <0x1d 0x4>;
};
HWRNG: hwrng@110000 {
compatible = "amcc,ppc460ex-rng", "ppc4xx-rng";
reg = <4 0x00110000 0x50>;
};
MAL0: mcmal {
compatible = "ibm,mcmal-460ex", "ibm,mcmal2";
dcr-reg = <0x180 0x062>;
num-tx-chans = <2>;
num-rx-chans = <16>;
#address-cells = <0>;
#size-cells = <0>;
interrupt-parent = <&UIC2>;
interrupts = < /*TXEOB*/ 0x6 0x4
/*RXEOB*/ 0x7 0x4
/*SERR*/ 0x3 0x4
/*TXDE*/ 0x4 0x4
/*RXDE*/ 0x5 0x4>;
};
USB0: ehci@bffd0400 {
compatible = "ibm,usb-ehci-460ex", "usb-ehci";
interrupt-parent = <&UIC2>;
interrupts = <0x1d 4>;
reg = <4 0xbffd0400 0x90 4 0xbffd0490 0x70>;
};
USB1: usb@bffd0000 {
compatible = "ohci-le";
reg = <4 0xbffd0000 0x60>;
interrupt-parent = <&UIC2>;
interrupts = <0x1e 4>;
};
USBOTG0: usbotg@bff80000 {
compatible = "amcc,dwc-otg";
reg = <0x4 0xbff80000 0x10000>;
interrupt-parent = <&USBOTG0>;
#interrupt-cells = <1>;
#address-cells = <0>;
#size-cells = <0>;
interrupts = <0x0 0x1 0x2>;
interrupt-map = </* USB-OTG */ 0x0 &UIC2 0x1c 0x4
/* HIGH-POWER */ 0x1 &UIC1 0x1a 0x8
/* DMA */ 0x2 &UIC0 0xc 0x4>;
};
AHBDMA: dma@bffd0800 {
compatible = "snps,dma-spear1340";
reg = <4 0xbffd0800 0x400>;
interrupt-parent = <&UIC3>;
interrupts = <0x5 0x4>;
#dma-cells = <3>;
};
SATA0: sata@bffd1000 {
compatible = "amcc,sata-460ex";
reg = <4 0xbffd1000 0x800>;
interrupt-parent = <&UIC3>;
interrupts = <0x0 0x4>;
dmas = <&AHBDMA 0 1 0>;
dma-names = "sata-dma";
};
POB0: opb {
compatible = "ibm,opb-460ex", "ibm,opb";
#address-cells = <1>;
#size-cells = <1>;
ranges = <0xb0000000 0x00000004 0xb0000000 0x50000000>;
clock-frequency = <0>; /* Filled in by U-Boot */
EBC0: ebc {
compatible = "ibm,ebc-460ex", "ibm,ebc";
dcr-reg = <0x012 0x002>;
#address-cells = <2>;
#size-cells = <1>;
clock-frequency = <0>; /* Filled in by U-Boot */
/* ranges property is supplied by U-Boot */
interrupts = <0x6 0x4>;
interrupt-parent = <&UIC1>;
nor_flash@0,0 {
compatible = "amd,s29gl512n", "cfi-flash";
bank-width = <2>;
reg = <0x00000000 0x00000000 0x04000000>;
#address-cells = <1>;
#size-cells = <1>;
partition@0 {
label = "kernel";
reg = <0x00000000 0x001e0000>;
};
partition@1e0000 {
label = "dtb";
reg = <0x001e0000 0x00020000>;
};
partition@200000 {
label = "ramdisk";
reg = <0x00200000 0x01400000>;
};
partition@1600000 {
label = "jffs2";
reg = <0x01600000 0x00400000>;
};
partition@1a00000 {
label = "user";
reg = <0x01a00000 0x02560000>;
};
partition@3f60000 {
label = "env";
reg = <0x03f60000 0x00040000>;
};
partition@3fa0000 {
label = "u-boot";
reg = <0x03fa0000 0x00060000>;
};
};
cpld@2,0 {
compatible = "amcc,ppc460ex-bcsr";
reg = <2 0x0 0x9>;
};
ndfc@3,0 {
compatible = "ibm,ndfc";
reg = <0x00000003 0x00000000 0x00002000>;
ccr = <0x00001000>;
bank-settings = <0x80002222>;
#address-cells = <1>;
#size-cells = <1>;
nand {
#address-cells = <1>;
#size-cells = <1>;
partition@0 {
label = "u-boot";
reg = <0x00000000 0x00100000>;
};
partition@100000 {
label = "user";
reg = <0x00000000 0x03f00000>;
};
};
};
};
UART0: serial@ef600300 {
device_type = "serial";
compatible = "ns16550";
reg = <0xef600300 0x00000008>;
virtual-reg = <0xef600300>;
clock-frequency = <0>; /* Filled in by U-Boot */
current-speed = <0>; /* Filled in by U-Boot */
interrupt-parent = <&UIC1>;
interrupts = <0x1 0x4>;
};
UART1: serial@ef600400 {
device_type = "serial";
compatible = "ns16550";
reg = <0xef600400 0x00000008>;
virtual-reg = <0xef600400>;
clock-frequency = <0>; /* Filled in by U-Boot */
current-speed = <0>; /* Filled in by U-Boot */
interrupt-parent = <&UIC0>;
interrupts = <0x1 0x4>;
};
IIC0: i2c@ef600700 {
compatible = "ibm,iic-460ex", "ibm,iic";
reg = <0xef600700 0x00000014>;
interrupt-parent = <&UIC0>;
interrupts = <0x2 0x4>;
#address-cells = <1>;
#size-cells = <0>;
rtc@68 {
compatible = "st,m41t80";
reg = <0x68>;
interrupt-parent = <&UIC2>;
interrupts = <0x19 0x8>;
};
sttm@48 {
compatible = "ad,ad7414";
reg = <0x48>;
interrupt-parent = <&UIC1>;
interrupts = <0x14 0x8>;
};
};
IIC1: i2c@ef600800 {
compatible = "ibm,iic-460ex", "ibm,iic";
reg = <0xef600800 0x00000014>;
interrupt-parent = <&UIC0>;
interrupts = <0x3 0x4>;
};
GPIO0: gpio@ef600b00 {
compatible = "ibm,ppc4xx-gpio";
reg = <0xef600b00 0x00000048>;
gpio-controller;
};
ZMII0: emac-zmii@ef600d00 {
compatible = "ibm,zmii-460ex", "ibm,zmii";
reg = <0xef600d00 0x0000000c>;
};
RGMII0: emac-rgmii@ef601500 {
compatible = "ibm,rgmii-460ex", "ibm,rgmii";
reg = <0xef601500 0x00000008>;
has-mdio;
};
TAH0: emac-tah@ef601350 {
compatible = "ibm,tah-460ex", "ibm,tah";
reg = <0xef601350 0x00000030>;
};
TAH1: emac-tah@ef601450 {
compatible = "ibm,tah-460ex", "ibm,tah";
reg = <0xef601450 0x00000030>;
};
EMAC0: ethernet@ef600e00 {
device_type = "network";
compatible = "ibm,emac-460ex", "ibm,emac4sync";
interrupt-parent = <&EMAC0>;
interrupts = <0x0 0x1>;
#interrupt-cells = <1>;
#address-cells = <0>;
#size-cells = <0>;
interrupt-map = </*Status*/ 0x0 &UIC2 0x10 0x4
/*Wake*/ 0x1 &UIC2 0x14 0x4>;
reg = <0xef600e00 0x000000c4>;
local-mac-address = [000000000000]; /* Filled in by U-Boot */
mal-device = <&MAL0>;
mal-tx-channel = <0>;
mal-rx-channel = <0>;
cell-index = <0>;
max-frame-size = <9000>;
rx-fifo-size = <4096>;
tx-fifo-size = <2048>;
rx-fifo-size-gige = <16384>;
phy-mode = "rgmii";
phy-map = <0x00000000>;
rgmii-device = <&RGMII0>;
rgmii-channel = <0>;
tah-device = <&TAH0>;
tah-channel = <0>;
has-inverted-stacr-oc;
has-new-stacr-staopc;
};
EMAC1: ethernet@ef600f00 {
device_type = "network";
compatible = "ibm,emac-460ex", "ibm,emac4sync";
interrupt-parent = <&EMAC1>;
interrupts = <0x0 0x1>;
#interrupt-cells = <1>;
#address-cells = <0>;
#size-cells = <0>;
interrupt-map = </*Status*/ 0x0 &UIC2 0x11 0x4
/*Wake*/ 0x1 &UIC2 0x15 0x4>;
reg = <0xef600f00 0x000000c4>;
local-mac-address = [000000000000]; /* Filled in by U-Boot */
mal-device = <&MAL0>;
mal-tx-channel = <1>;
mal-rx-channel = <8>;
cell-index = <1>;
max-frame-size = <9000>;
rx-fifo-size = <4096>;
tx-fifo-size = <2048>;
rx-fifo-size-gige = <16384>;
phy-mode = "rgmii";
phy-map = <0x00000000>;
rgmii-device = <&RGMII0>;
rgmii-channel = <1>;
tah-device = <&TAH1>;
tah-channel = <1>;
has-inverted-stacr-oc;
has-new-stacr-staopc;
mdio-device = <&EMAC0>;
};
};
PCIX0: pci@c0ec00000 {
device_type = "pci";
#interrupt-cells = <1>;
#size-cells = <2>;
#address-cells = <3>;
compatible = "ibm,plb-pcix-460ex", "ibm,plb-pcix";
primary;
large-inbound-windows;
enable-msi-hole;
reg = <0x0000000c 0x0ec00000 0x00000008 /* Config space access */
0x00000000 0x00000000 0x00000000 /* no IACK cycles */
0x0000000c 0x0ed00000 0x00000004 /* Special cycles */
0x0000000c 0x0ec80000 0x00000100 /* Internal registers */
0x0000000c 0x0ec80100 0x000000fc>; /* Internal messaging registers */
/* Outbound ranges, one memory and one IO,
* later cannot be changed
*/
ranges = <0x02000000 0x00000000 0x80000000 0x0000000d 0x80000000 0x00000000 0x80000000
0x02000000 0x00000000 0x00000000 0x0000000c 0x0ee00000 0x00000000 0x00100000
0x01000000 0x00000000 0x00000000 0x0000000c 0x08000000 0x00000000 0x00010000>;
/* Inbound 2GB range starting at 0 */
dma-ranges = <0x42000000 0x0 0x0 0x0 0x0 0x0 0x80000000>;
/* This drives busses 0 to 0x3f */
bus-range = <0x0 0x3f>;
/* All PCI interrupts are routed to ext IRQ 2 -> UIC1-0 */
interrupt-map-mask = <0x0 0x0 0x0 0x0>;
interrupt-map = < 0x0 0x0 0x0 0x0 &UIC1 0x0 0x8 >;
};
PCIE0: pciex@d00000000 {
device_type = "pci";
#interrupt-cells = <1>;
#size-cells = <2>;
#address-cells = <3>;
compatible = "ibm,plb-pciex-460ex", "ibm,plb-pciex";
primary;
port = <0x0>; /* port number */
reg = <0x0000000d 0x00000000 0x20000000 /* Config space access */
0x0000000c 0x08010000 0x00001000>; /* Registers */
dcr-reg = <0x100 0x020>;
sdr-base = <0x300>;
/* Outbound ranges, one memory and one IO,
* later cannot be changed
*/
ranges = <0x02000000 0x00000000 0x80000000 0x0000000e 0x00000000 0x00000000 0x80000000
0x02000000 0x00000000 0x00000000 0x0000000f 0x00000000 0x00000000 0x00100000
0x01000000 0x00000000 0x00000000 0x0000000f 0x80000000 0x00000000 0x00010000>;
/* Inbound 2GB range starting at 0 */
dma-ranges = <0x42000000 0x0 0x0 0x0 0x0 0x0 0x80000000>;
/* This drives busses 40 to 0x7f */
bus-range = <0x40 0x7f>;
/* Legacy interrupts (note the weird polarity, the bridge seems
* to invert PCIe legacy interrupts).
* We are de-swizzling here because the numbers are actually for
* port of the root complex virtual P2P bridge. But I want
* to avoid putting a node for it in the tree, so the numbers
* below are basically de-swizzled numbers.
* The real slot is on idsel 0, so the swizzling is 1:1
*/
interrupt-map-mask = <0x0 0x0 0x0 0x7>;
interrupt-map = <
0x0 0x0 0x0 0x1 &UIC3 0xc 0x4 /* swizzled int A */
0x0 0x0 0x0 0x2 &UIC3 0xd 0x4 /* swizzled int B */
0x0 0x0 0x0 0x3 &UIC3 0xe 0x4 /* swizzled int C */
0x0 0x0 0x0 0x4 &UIC3 0xf 0x4 /* swizzled int D */>;
};
PCIE1: pciex@d20000000 {
device_type = "pci";
#interrupt-cells = <1>;
#size-cells = <2>;
#address-cells = <3>;
compatible = "ibm,plb-pciex-460ex", "ibm,plb-pciex";
primary;
port = <0x1>; /* port number */
reg = <0x0000000d 0x20000000 0x20000000 /* Config space access */
0x0000000c 0x08011000 0x00001000>; /* Registers */
dcr-reg = <0x120 0x020>;
sdr-base = <0x340>;
/* Outbound ranges, one memory and one IO,
* later cannot be changed
*/
ranges = <0x02000000 0x00000000 0x80000000 0x0000000e 0x80000000 0x00000000 0x80000000
0x02000000 0x00000000 0x00000000 0x0000000f 0x00100000 0x00000000 0x00100000
0x01000000 0x00000000 0x00000000 0x0000000f 0x80010000 0x00000000 0x00010000>;
/* Inbound 2GB range starting at 0 */
dma-ranges = <0x42000000 0x0 0x0 0x0 0x0 0x0 0x80000000>;
/* This drives busses 80 to 0xbf */
bus-range = <0x80 0xbf>;
/* Legacy interrupts (note the weird polarity, the bridge seems
* to invert PCIe legacy interrupts).
* We are de-swizzling here because the numbers are actually for
* port of the root complex virtual P2P bridge. But I want
* to avoid putting a node for it in the tree, so the numbers
* below are basically de-swizzled numbers.
* The real slot is on idsel 0, so the swizzling is 1:1
*/
interrupt-map-mask = <0x0 0x0 0x0 0x7>;
interrupt-map = <
0x0 0x0 0x0 0x1 &UIC3 0x10 0x4 /* swizzled int A */
0x0 0x0 0x0 0x2 &UIC3 0x11 0x4 /* swizzled int B */
0x0 0x0 0x0 0x3 &UIC3 0x12 0x4 /* swizzled int C */
0x0 0x0 0x0 0x4 &UIC3 0x13 0x4 /* swizzled int D */>;
};
MSI: ppc4xx-msi@C10000000 {
compatible = "amcc,ppc4xx-msi", "ppc4xx-msi";
reg = < 0xC 0x10000000 0x100>;
sdr-base = <0x36C>;
msi-data = <0x00000000>;
msi-mask = <0x44440000>;
interrupt-count = <3>;
interrupts = <0 1 2 3>;
interrupt-parent = <&UIC3>;
#interrupt-cells = <1>;
#address-cells = <0>;
#size-cells = <0>;
interrupt-map = <0 &UIC3 0x18 1
1 &UIC3 0x19 1
2 &UIC3 0x1A 1
3 &UIC3 0x1B 1>;
};
};
};

Binary file not shown.

View File

@ -65,6 +65,7 @@ default:
@echo " slof -- update slof.bin" @echo " slof -- update slof.bin"
@echo " skiboot -- update skiboot.lid" @echo " skiboot -- update skiboot.lid"
@echo " u-boot.e500 -- update u-boot.e500" @echo " u-boot.e500 -- update u-boot.e500"
@echo " u-boot.sam460 -- update u-boot.sam460"
bios: build-seabios-config-seabios-128k build-seabios-config-seabios-256k bios: build-seabios-config-seabios-128k build-seabios-config-seabios-256k
cp seabios/builds/seabios-128k/bios.bin ../pc-bios/bios.bin cp seabios/builds/seabios-128k/bios.bin ../pc-bios/bios.bin
@ -147,6 +148,11 @@ u-boot.e500:
$(powerpc_cross_prefix)strip u-boot/build.e500/u-boot -o \ $(powerpc_cross_prefix)strip u-boot/build.e500/u-boot -o \
../pc-bios/u-boot.e500 ../pc-bios/u-boot.e500
u-boot.sam460:
$(MAKE) -C u-boot-sam460ex Sam460ex_config
$(MAKE) -C u-boot-sam460ex CROSS_COMPILE=$(powerpc_cross_prefix)
cp u-boot-sam460ex/u-boot.bin ../pc-bios/u-boot-sam460-20100605.bin
skiboot: skiboot:
$(MAKE) -C skiboot CROSS=$(powerpc64_cross_prefix) $(MAKE) -C skiboot CROSS=$(powerpc64_cross_prefix)
cp skiboot/skiboot.lid ../pc-bios/skiboot.lid cp skiboot/skiboot.lid ../pc-bios/skiboot.lid
@ -160,4 +166,5 @@ clean:
$(MAKE) -C ipxe/src veryclean $(MAKE) -C ipxe/src veryclean
$(MAKE) -C SLOF clean $(MAKE) -C SLOF clean
rm -rf u-boot/build.e500 rm -rf u-boot/build.e500
$(MAKE) -C u-boot-sam460ex distclean
$(MAKE) -C skiboot clean $(MAKE) -C skiboot clean

1
roms/u-boot-sam460ex Submodule

@ -0,0 +1 @@
Subproject commit 119aa277f74a4a2d3f7ab6c9471292308eba14e4

View File

@ -12,7 +12,7 @@
#include "qemu/osdep.h" #include "qemu/osdep.h"
#include "qemu-common.h" #include "qemu-common.h"
#include "cpu.h" #include "cpu.h"
#include "hw/ppc/openpic.h" #include "hw/ppc/openpic_kvm.h"
int kvm_openpic_connect_vcpu(DeviceState *d, CPUState *cs) int kvm_openpic_connect_vcpu(DeviceState *d, CPUState *cs)
{ {

View File

@ -2494,8 +2494,10 @@ static void kvmppc_get_cpu_characteristics(KVMState *s)
cap_ppc_safe_bounds_check = 1; cap_ppc_safe_bounds_check = 1;
} }
/* Parse and set cap_ppc_safe_indirect_branch */ /* Parse and set cap_ppc_safe_indirect_branch */
if (c.character & H_CPU_CHAR_BCCTRL_SERIALISED) { if (c.character & c.character_mask & H_CPU_CHAR_CACHE_COUNT_DIS) {
cap_ppc_safe_indirect_branch = 2; cap_ppc_safe_indirect_branch = SPAPR_CAP_FIXED_CCD;
} else if (c.character & c.character_mask & H_CPU_CHAR_BCCTRL_SERIALISED) {
cap_ppc_safe_indirect_branch = SPAPR_CAP_FIXED_IBS;
} }
} }

View File

@ -8692,6 +8692,8 @@ POWERPC_FAMILY(POWER8)(ObjectClass *oc, void *data)
(1ull << MSR_DR) | (1ull << MSR_DR) |
(1ull << MSR_PMM) | (1ull << MSR_PMM) |
(1ull << MSR_RI) | (1ull << MSR_RI) |
(1ull << MSR_TS0) |
(1ull << MSR_TS1) |
(1ull << MSR_LE); (1ull << MSR_LE);
pcc->mmu_model = POWERPC_MMU_2_07; pcc->mmu_model = POWERPC_MMU_2_07;
#if defined(CONFIG_SOFTMMU) #if defined(CONFIG_SOFTMMU)