ppc patch queue 2021-05-04

Here's the first ppc pull request for qemu-6.1.  It has a wide variety
 of stuff accumulated during the 6.0 freeze.  Highlights are:
 
  * Multi-phase reset cleanups for PAPR
  * Preliminary cleanups towards allowing !CONFIG_TCG for the ppc target
  * Cleanup of AIL logic and extension to POWER10
  * Further improvements to handling of hot unplug failures on PAPR
  * Allow much larger numbers of CPU on pseries
  * Support for the H_SCM_HEALTH hypercall
  * Add support for the Pegasos II board
  * Substantial cleanup to hflag handling
  * Assorted minor fixes and cleanups
 -----BEGIN PGP SIGNATURE-----
 
 iQIzBAABCAAdFiEEdfRlhq5hpmzETofcbDjKyiDZs5IFAmCQ4ScACgkQbDjKyiDZ
 s5KmNhAAsICdDqeu/jm1uhRCr0DDT/Wa6KE1xlglQ53ybWb5Hm2ae0Uwzti5ZWkt
 T9yryObX++wiugbU5Dlx9eXTiJIPgTbDoBV1wfOa3a1BAxSEES1t70jwuwAXXBpX
 mgU++SurQB70IB7vVvyXDi2Z592qGvMiKXqT0sdkfoexPHzAL0+KkQPyJZLeFchM
 Ap/zRHAodXf9SuWAl+LwLXeb350jivXYXBWNcFRrBbOGpbVT0AJMYrk/TEa2ZIpi
 SvbzAWuW+9mX0EOmk7JK5JfkT41cGNdcBcwd0bt4xyvUpmkXLaTMFDLVHj3HWSUn
 PFA4RB3uKXyTfISVtWdxJBbFOzMpchI6lEiRJHCS+KuY7UsACqV1T/y54ATOUauC
 ycLc9APgRaStdNPxfDl+xeFfoVb/f0mQsNwcmY1tv7z+3qE/trY9bMyrbgaebBFn
 /TAkmPvXfwtAREnx8xF/57poarWUkvupGTQkANNosdFokpExmrLj8T0sKv90hh5Y
 vkGf5zP4pYGN1Rs8qhOdHu+IjhVJvUl/L3LZYWcoMI6E61D8rGRc0Dkacx7gcja+
 sluFi5Yh2fQn55y6LTi3049cB1wMd6wly0214F11RKoBswguiGuaqJmL4sNDO/s4
 IcMCy5mg6C0jNZA5kHcdWmqsVzD2+XwP5J29n/LedlmgXoHYF+M=
 =N0qr
 -----END PGP SIGNATURE-----

Merge remote-tracking branch 'remotes/dg-gitlab/tags/ppc-for-6.1-20210504' into staging

ppc patch queue 2021-05-04

Here's the first ppc pull request for qemu-6.1.  It has a wide variety
of stuff accumulated during the 6.0 freeze.  Highlights are:

 * Multi-phase reset cleanups for PAPR
 * Preliminary cleanups towards allowing !CONFIG_TCG for the ppc target
 * Cleanup of AIL logic and extension to POWER10
 * Further improvements to handling of hot unplug failures on PAPR
 * Allow much larger numbers of CPU on pseries
 * Support for the H_SCM_HEALTH hypercall
 * Add support for the Pegasos II board
 * Substantial cleanup to hflag handling
 * Assorted minor fixes and cleanups

# gpg: Signature made Tue 04 May 2021 06:52:39 BST
# gpg:                using RSA key 75F46586AE61A66CC44E87DC6C38CACA20D9B392
# gpg: Good signature from "David Gibson <david@gibson.dropbear.id.au>" [full]
# gpg:                 aka "David Gibson (Red Hat) <dgibson@redhat.com>" [full]
# gpg:                 aka "David Gibson (ozlabs.org) <dgibson@ozlabs.org>" [full]
# gpg:                 aka "David Gibson (kernel.org) <dwg@kernel.org>" [unknown]
# Primary key fingerprint: 75F4 6586 AE61 A66C C44E  87DC 6C38 CACA 20D9 B392

* remotes/dg-gitlab/tags/ppc-for-6.1-20210504: (46 commits)
  hw/ppc/pnv_psi: Use device_cold_reset() instead of device_legacy_reset()
  hw/ppc/spapr_vio: Reset TCE table object with device_cold_reset()
  hw/intc/spapr_xive: Use device_cold_reset() instead of device_legacy_reset()
  target/ppc: removed VSCR from SPR registration
  target/ppc: Reduce the size of ppc_spr_t
  target/ppc: Clean up _spr_register et al
  target/ppc: Add POWER10 exception model
  target/ppc: rework AIL logic in interrupt delivery
  target/ppc: move opcode table logic to translate.c
  target/ppc: code motion from translate_init.c.inc to gdbstub.c
  spapr_drc.c: handle hotunplug errors in drc_unisolate_logical()
  spapr.h: increase FDT_MAX_SIZE
  spapr.c: do not use MachineClass::max_cpus to limit CPUs
  ppc: Rename current DAWR macros and variables
  target/ppc: POWER10 supports scv
  target/ppc: Fix POWER9 radix guest HV interrupt AIL behaviour
  docs/system: ppc: Add documentation for ppce500 machine
  roms/u-boot: Bump ppce500 u-boot to v2021.04 to fix broken pci support
  roms/Makefile: Update ppce500 u-boot build directory name
  ppc/spapr: Add support for implement support for H_SCM_HEALTH
  ...

Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
This commit is contained in:
Peter Maydell 2021-05-05 20:29:14 +01:00
commit d90f154867
48 changed files with 4020 additions and 1208 deletions

View File

@ -1366,6 +1366,16 @@ F: pc-bios/canyonlands.dt[sb]
F: pc-bios/u-boot-sam460ex-20100605.bin
F: roms/u-boot-sam460ex
pegasos2
M: BALATON Zoltan <balaton@eik.bme.hu>
R: David Gibson <david@gibson.dropbear.id.au>
L: qemu-ppc@nongnu.org
S: Maintained
F: hw/ppc/pegasos2.c
F: hw/pci-host/mv64361.c
F: hw/pci-host/mv643xx.h
F: include/hw/pci-host/mv64361.h
RISC-V Machines
---------------
OpenTitan

View File

@ -14,5 +14,7 @@ CONFIG_SAM460EX=y
CONFIG_MAC_OLDWORLD=y
CONFIG_MAC_NEWWORLD=y
CONFIG_PEGASOS2=n
# For PReP
CONFIG_PREP=y

156
docs/system/ppc/ppce500.rst Normal file
View File

@ -0,0 +1,156 @@
ppce500 generic platform (``ppce500``)
======================================
QEMU for PPC supports a special ``ppce500`` machine designed for emulation and
virtualization purposes.
Supported devices
-----------------
The ``ppce500`` machine supports the following devices:
* PowerPC e500 series core (e500v2/e500mc/e5500/e6500)
* Configuration, Control, and Status Register (CCSR)
* Multicore Programmable Interrupt Controller (MPIC) with MSI support
* 1 16550A UART device
* 1 Freescale MPC8xxx I2C controller
* 1 Pericom pt7c4338 RTC via I2C
* 1 Freescale MPC8xxx GPIO controller
* Power-off functionality via one GPIO pin
* 1 Freescale MPC8xxx PCI host controller
* VirtIO devices via PCI bus
Hardware configuration information
----------------------------------
The ``ppce500`` machine automatically generates a device tree blob ("dtb")
which it passes to the guest, if there is no ``-dtb`` option. This provides
information about the addresses, interrupt lines and other configuration of
the various devices in the system.
If users want to provide their own DTB, they can use the ``-dtb`` option.
These DTBs should have the following requirements:
* The number of subnodes under /cpus node should match QEMU's ``-smp`` option
* The /memory reg size should match QEMUs selected ram_size via ``-m``
Both ``qemu-system-ppc`` and ``qemu-system-ppc64`` provide emulation for the
following 32-bit PowerPC CPUs:
* e500v2
* e500mc
Additionally ``qemu-system-ppc64`` provides support for the following 64-bit
PowerPC CPUs:
* e5500
* e6500
The CPU type can be specified via the ``-cpu`` command line. If not specified,
it creates a machine with e500v2 core. The following example shows an e6500
based machine creation:
.. code-block:: bash
$ qemu-system-ppc64 -nographic -M ppce500 -cpu e6500
Boot options
------------
The ``ppce500`` machine can start using the standard -kernel functionality
for loading a payload like an OS kernel (e.g.: Linux), or U-Boot firmware.
When -bios is omitted, the default pc-bios/u-boot.e500 firmware image is used
as the BIOS. QEMU follows below truth table to select which payload to execute:
===== ========== =======
-bios -kernel payload
===== ========== =======
N N u-boot
N Y kernel
Y don't care u-boot
===== ========== =======
When both -bios and -kernel are present, QEMU loads U-Boot and U-Boot in turns
automatically loads the kernel image specified by the -kernel parameter via
U-Boot's built-in "bootm" command, hence a legacy uImage format is required in
such senario.
Running Linux kernel
--------------------
Linux mainline v5.11 release is tested at the time of writing. To build a
Linux mainline kernel that can be booted by the ``ppce500`` machine in
64-bit mode, simply configure the kernel using the defconfig configuration:
.. code-block:: bash
$ export ARCH=powerpc
$ export CROSS_COMPILE=powerpc-linux-
$ make corenet64_smp_defconfig
$ make menuconfig
then manually select the following configuration:
Platform support > Freescale Book-E Machine Type > QEMU generic e500 platform
To boot the newly built Linux kernel in QEMU with the ``ppce500`` machine:
.. code-block:: bash
$ qemu-system-ppc64 -M ppce500 -cpu e5500 -smp 4 -m 2G \
-display none -serial stdio \
-kernel vmlinux \
-initrd /path/to/rootfs.cpio \
-append "root=/dev/ram"
To build a Linux mainline kernel that can be booted by the ``ppce500`` machine
in 32-bit mode, use the same 64-bit configuration steps except the defconfig
file should use corenet32_smp_defconfig.
To boot the 32-bit Linux kernel:
.. code-block:: bash
$ qemu-system-ppc{64|32} -M ppce500 -cpu e500mc -smp 4 -m 2G \
-display none -serial stdio \
-kernel vmlinux \
-initrd /path/to/rootfs.cpio \
-append "root=/dev/ram"
Running U-Boot
--------------
U-Boot mainline v2021.04 release is tested at the time of writing. To build a
U-Boot mainline bootloader that can be booted by the ``ppce500`` machine, use
the qemu-ppce500_defconfig with similar commands as described above for Linux:
.. code-block:: bash
$ export CROSS_COMPILE=powerpc-linux-
$ make qemu-ppce500_defconfig
You will get u-boot file in the build tree.
When U-Boot boots, you will notice the following if using with ``-cpu e6500``:
.. code-block:: none
CPU: Unknown, Version: 0.0, (0x00000000)
Core: e6500, Version: 2.0, (0x80400020)
This is because we only specified a core name to QEMU and it does not have a
meaningful SVR value which represents an actual SoC that integrates such core.
You can specify a real world SoC device that QEMU has built-in support but all
these SoCs are e500v2 based MPC85xx series, hence you cannot test anything
built for P4080 (e500mc), P5020 (e5500) and T2080 (e6500).
By default a VirtIO standard PCI networking device is connected as an ethernet
interface at PCI address 0.1.0, but we can switch that to an e1000 NIC by:
.. code-block:: bash
$ qemu-system-ppc -M ppce500 -smp 4 -m 2G \
-display none -serial stdio \
-bios u-boot \
-nic tap,ifname=tap0,script=no,downscript=no,model=e1000

View File

@ -20,5 +20,6 @@ help``.
ppc/embedded
ppc/powermac
ppc/powernv
ppc/ppce500
ppc/prep
ppc/pseries

View File

@ -1798,7 +1798,7 @@ static target_ulong h_int_reset(PowerPCCPU *cpu,
return H_PARAMETER;
}
device_legacy_reset(DEVICE(xive));
device_cold_reset(DEVICE(xive));
if (spapr_xive_in_kernel(xive)) {
Error *local_err = NULL;

View File

@ -8,6 +8,9 @@
*
* Contributions after 2012-01-13 are licensed under the terms of the
* GNU GPL, version 2 or (at your option) any later version.
*
* VT8231 south bridge support and general clean up to allow it
* Copyright (c) 2018-2020 BALATON Zoltan
*/
#include "qemu/osdep.h"
@ -264,15 +267,80 @@ static const TypeInfo vt8231_pm_info = {
};
typedef struct SuperIOConfig {
uint8_t regs[0x100];
MemoryRegion io;
} SuperIOConfig;
#define TYPE_VIA_SUPERIO "via-superio"
OBJECT_DECLARE_SIMPLE_TYPE(ViaSuperIOState, VIA_SUPERIO)
static void superio_cfg_write(void *opaque, hwaddr addr, uint64_t data,
unsigned size)
struct ViaSuperIOState {
ISASuperIODevice superio;
uint8_t regs[0x100];
const MemoryRegionOps *io_ops;
MemoryRegion io;
};
static inline void via_superio_io_enable(ViaSuperIOState *s, bool enable)
{
SuperIOConfig *sc = opaque;
memory_region_set_enabled(&s->io, enable);
}
static void via_superio_realize(DeviceState *d, Error **errp)
{
ViaSuperIOState *s = VIA_SUPERIO(d);
ISASuperIOClass *ic = ISA_SUPERIO_GET_CLASS(s);
Error *local_err = NULL;
assert(s->io_ops);
ic->parent_realize(d, &local_err);
if (local_err) {
error_propagate(errp, local_err);
return;
}
memory_region_init_io(&s->io, OBJECT(d), s->io_ops, s, "via-superio", 2);
memory_region_set_enabled(&s->io, false);
/* The floppy also uses 0x3f0 and 0x3f1 but this seems to work anyway */
memory_region_add_subregion(isa_address_space_io(ISA_DEVICE(s)), 0x3f0,
&s->io);
}
static uint64_t via_superio_cfg_read(void *opaque, hwaddr addr, unsigned size)
{
ViaSuperIOState *sc = opaque;
uint8_t idx = sc->regs[0];
uint8_t val = sc->regs[idx];
if (addr == 0) {
return idx;
}
if (addr == 1 && idx == 0) {
val = 0; /* reading reg 0 where we store index value */
}
trace_via_superio_read(idx, val);
return val;
}
static void via_superio_class_init(ObjectClass *klass, void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
ISASuperIOClass *sc = ISA_SUPERIO_CLASS(klass);
sc->parent_realize = dc->realize;
dc->realize = via_superio_realize;
}
static const TypeInfo via_superio_info = {
.name = TYPE_VIA_SUPERIO,
.parent = TYPE_ISA_SUPERIO,
.instance_size = sizeof(ViaSuperIOState),
.class_size = sizeof(ISASuperIOClass),
.class_init = via_superio_class_init,
.abstract = true,
};
#define TYPE_VT82C686B_SUPERIO "vt82c686b-superio"
static void vt82c686b_superio_cfg_write(void *opaque, hwaddr addr,
uint64_t data, unsigned size)
{
ViaSuperIOState *sc = opaque;
uint8_t idx = sc->regs[0];
if (addr == 0) { /* config index register */
@ -303,25 +371,9 @@ static void superio_cfg_write(void *opaque, hwaddr addr, uint64_t data,
sc->regs[idx] = data;
}
static uint64_t superio_cfg_read(void *opaque, hwaddr addr, unsigned size)
{
SuperIOConfig *sc = opaque;
uint8_t idx = sc->regs[0];
uint8_t val = sc->regs[idx];
if (addr == 0) {
return idx;
}
if (addr == 1 && idx == 0) {
val = 0; /* reading reg 0 where we store index value */
}
trace_via_superio_read(idx, val);
return val;
}
static const MemoryRegionOps superio_cfg_ops = {
.read = superio_cfg_read,
.write = superio_cfg_write,
static const MemoryRegionOps vt82c686b_superio_cfg_ops = {
.read = via_superio_cfg_read,
.write = vt82c686b_superio_cfg_write,
.endianness = DEVICE_NATIVE_ENDIAN,
.impl = {
.min_access_size = 1,
@ -329,47 +381,215 @@ static const MemoryRegionOps superio_cfg_ops = {
},
};
static void vt82c686b_superio_reset(DeviceState *dev)
{
ViaSuperIOState *s = VIA_SUPERIO(dev);
OBJECT_DECLARE_SIMPLE_TYPE(VT82C686BISAState, VT82C686B_ISA)
memset(s->regs, 0, sizeof(s->regs));
/* Device ID */
vt82c686b_superio_cfg_write(s, 0, 0xe0, 1);
vt82c686b_superio_cfg_write(s, 1, 0x3c, 1);
/* Function select - all disabled */
vt82c686b_superio_cfg_write(s, 0, 0xe2, 1);
vt82c686b_superio_cfg_write(s, 1, 0x03, 1);
/* Floppy ctrl base addr 0x3f0-7 */
vt82c686b_superio_cfg_write(s, 0, 0xe3, 1);
vt82c686b_superio_cfg_write(s, 1, 0xfc, 1);
/* Parallel port base addr 0x378-f */
vt82c686b_superio_cfg_write(s, 0, 0xe6, 1);
vt82c686b_superio_cfg_write(s, 1, 0xde, 1);
/* Serial port 1 base addr 0x3f8-f */
vt82c686b_superio_cfg_write(s, 0, 0xe7, 1);
vt82c686b_superio_cfg_write(s, 1, 0xfe, 1);
/* Serial port 2 base addr 0x2f8-f */
vt82c686b_superio_cfg_write(s, 0, 0xe8, 1);
vt82c686b_superio_cfg_write(s, 1, 0xbe, 1);
struct VT82C686BISAState {
vt82c686b_superio_cfg_write(s, 0, 0, 1);
}
static void vt82c686b_superio_init(Object *obj)
{
VIA_SUPERIO(obj)->io_ops = &vt82c686b_superio_cfg_ops;
}
static void vt82c686b_superio_class_init(ObjectClass *klass, void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
ISASuperIOClass *sc = ISA_SUPERIO_CLASS(klass);
dc->reset = vt82c686b_superio_reset;
sc->serial.count = 2;
sc->parallel.count = 1;
sc->ide.count = 0; /* emulated by via-ide */
sc->floppy.count = 1;
}
static const TypeInfo vt82c686b_superio_info = {
.name = TYPE_VT82C686B_SUPERIO,
.parent = TYPE_VIA_SUPERIO,
.instance_size = sizeof(ViaSuperIOState),
.instance_init = vt82c686b_superio_init,
.class_size = sizeof(ISASuperIOClass),
.class_init = vt82c686b_superio_class_init,
};
#define TYPE_VT8231_SUPERIO "vt8231-superio"
static void vt8231_superio_cfg_write(void *opaque, hwaddr addr,
uint64_t data, unsigned size)
{
ViaSuperIOState *sc = opaque;
uint8_t idx = sc->regs[0];
if (addr == 0) { /* config index register */
sc->regs[0] = data;
return;
}
/* config data register */
trace_via_superio_write(idx, data);
switch (idx) {
case 0x00 ... 0xdf:
case 0xe7 ... 0xef:
case 0xf0 ... 0xf1:
case 0xf5:
case 0xf8:
case 0xfd:
/* ignore write to read only registers */
return;
default:
qemu_log_mask(LOG_UNIMP,
"via_superio_cfg: unimplemented register 0x%x\n", idx);
break;
}
sc->regs[idx] = data;
}
static const MemoryRegionOps vt8231_superio_cfg_ops = {
.read = via_superio_cfg_read,
.write = vt8231_superio_cfg_write,
.endianness = DEVICE_NATIVE_ENDIAN,
.impl = {
.min_access_size = 1,
.max_access_size = 1,
},
};
static void vt8231_superio_reset(DeviceState *dev)
{
ViaSuperIOState *s = VIA_SUPERIO(dev);
memset(s->regs, 0, sizeof(s->regs));
/* Device ID */
s->regs[0xf0] = 0x3c;
/* Device revision */
s->regs[0xf1] = 0x01;
/* Function select - all disabled */
vt8231_superio_cfg_write(s, 0, 0xf2, 1);
vt8231_superio_cfg_write(s, 1, 0x03, 1);
/* Serial port base addr */
vt8231_superio_cfg_write(s, 0, 0xf4, 1);
vt8231_superio_cfg_write(s, 1, 0xfe, 1);
/* Parallel port base addr */
vt8231_superio_cfg_write(s, 0, 0xf6, 1);
vt8231_superio_cfg_write(s, 1, 0xde, 1);
/* Floppy ctrl base addr */
vt8231_superio_cfg_write(s, 0, 0xf7, 1);
vt8231_superio_cfg_write(s, 1, 0xfc, 1);
vt8231_superio_cfg_write(s, 0, 0, 1);
}
static void vt8231_superio_init(Object *obj)
{
VIA_SUPERIO(obj)->io_ops = &vt8231_superio_cfg_ops;
}
static uint16_t vt8231_superio_serial_iobase(ISASuperIODevice *sio,
uint8_t index)
{
return 0x2f8; /* FIXME: This should be settable via registers f2-f4 */
}
static void vt8231_superio_class_init(ObjectClass *klass, void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
ISASuperIOClass *sc = ISA_SUPERIO_CLASS(klass);
dc->reset = vt8231_superio_reset;
sc->serial.count = 1;
sc->serial.get_iobase = vt8231_superio_serial_iobase;
sc->parallel.count = 1;
sc->ide.count = 0; /* emulated by via-ide */
sc->floppy.count = 1;
}
static const TypeInfo vt8231_superio_info = {
.name = TYPE_VT8231_SUPERIO,
.parent = TYPE_VIA_SUPERIO,
.instance_size = sizeof(ViaSuperIOState),
.instance_init = vt8231_superio_init,
.class_size = sizeof(ISASuperIOClass),
.class_init = vt8231_superio_class_init,
};
#define TYPE_VIA_ISA "via-isa"
OBJECT_DECLARE_SIMPLE_TYPE(ViaISAState, VIA_ISA)
struct ViaISAState {
PCIDevice dev;
qemu_irq cpu_intr;
SuperIOConfig superio_cfg;
ViaSuperIOState *via_sio;
};
static const VMStateDescription vmstate_via = {
.name = "via-isa",
.version_id = 1,
.minimum_version_id = 1,
.fields = (VMStateField[]) {
VMSTATE_PCI_DEVICE(dev, ViaISAState),
VMSTATE_END_OF_LIST()
}
};
static const TypeInfo via_isa_info = {
.name = TYPE_VIA_ISA,
.parent = TYPE_PCI_DEVICE,
.instance_size = sizeof(ViaISAState),
.abstract = true,
.interfaces = (InterfaceInfo[]) {
{ INTERFACE_CONVENTIONAL_PCI_DEVICE },
{ },
},
};
static void via_isa_request_i8259_irq(void *opaque, int irq, int level)
{
VT82C686BISAState *s = opaque;
ViaISAState *s = opaque;
qemu_set_irq(s->cpu_intr, level);
}
/* TYPE_VT82C686B_ISA */
static void vt82c686b_write_config(PCIDevice *d, uint32_t addr,
uint32_t val, int len)
{
VT82C686BISAState *s = VT82C686B_ISA(d);
ViaISAState *s = VIA_ISA(d);
trace_via_isa_write(addr, val, len);
pci_default_write_config(d, addr, val, len);
if (addr == 0x85) {
/* BIT(1): enable or disable superio config io ports */
memory_region_set_enabled(&s->superio_cfg.io, val & BIT(1));
via_superio_io_enable(s->via_sio, val & BIT(1));
}
}
static const VMStateDescription vmstate_via = {
.name = "vt82c686b",
.version_id = 1,
.minimum_version_id = 1,
.fields = (VMStateField[]) {
VMSTATE_PCI_DEVICE(dev, VT82C686BISAState),
VMSTATE_END_OF_LIST()
}
};
static void vt82c686b_isa_reset(DeviceState *dev)
{
VT82C686BISAState *s = VT82C686B_ISA(dev);
ViaISAState *s = VIA_ISA(dev);
uint8_t *pci_conf = s->dev.config;
pci_set_long(pci_conf + PCI_CAPABILITY_LIST, 0x000000c0);
@ -385,18 +605,11 @@ static void vt82c686b_isa_reset(DeviceState *dev)
pci_conf[0x5a] = 0x04; /* KBC/RTC Control*/
pci_conf[0x5f] = 0x04;
pci_conf[0x77] = 0x10; /* GPIO Control 1/2/3/4 */
s->superio_cfg.regs[0xe0] = 0x3c; /* Device ID */
s->superio_cfg.regs[0xe2] = 0x03; /* Function select */
s->superio_cfg.regs[0xe3] = 0xfc; /* Floppy ctrl base addr */
s->superio_cfg.regs[0xe6] = 0xde; /* Parallel port base addr */
s->superio_cfg.regs[0xe7] = 0xfe; /* Serial port 1 base addr */
s->superio_cfg.regs[0xe8] = 0xbe; /* Serial port 2 base addr */
}
static void vt82c686b_realize(PCIDevice *d, Error **errp)
{
VT82C686BISAState *s = VT82C686B_ISA(d);
ViaISAState *s = VIA_ISA(d);
DeviceState *dev = DEVICE(d);
ISABus *isa_bus;
qemu_irq *isa_irq;
@ -409,7 +622,8 @@ static void vt82c686b_realize(PCIDevice *d, Error **errp)
isa_bus_irqs(isa_bus, i8259_init(isa_bus, *isa_irq));
i8254_pit_init(isa_bus, 0x40, 0, NULL);
i8257_dma_init(isa_bus, 0);
isa_create_simple(isa_bus, TYPE_VT82C686B_SUPERIO);
s->via_sio = VIA_SUPERIO(isa_create_simple(isa_bus,
TYPE_VT82C686B_SUPERIO));
mc146818_rtc_init(isa_bus, 2000, NULL);
for (i = 0; i < PCI_CONFIG_HEADER_SIZE; i++) {
@ -417,19 +631,9 @@ static void vt82c686b_realize(PCIDevice *d, Error **errp)
d->wmask[i] = 0;
}
}
memory_region_init_io(&s->superio_cfg.io, OBJECT(d), &superio_cfg_ops,
&s->superio_cfg, "superio_cfg", 2);
memory_region_set_enabled(&s->superio_cfg.io, false);
/*
* The floppy also uses 0x3f0 and 0x3f1.
* But we do not emulate a floppy, so just set it here.
*/
memory_region_add_subregion(isa_bus->address_space_io, 0x3f0,
&s->superio_cfg.io);
}
static void via_class_init(ObjectClass *klass, void *data)
static void vt82c686b_class_init(ObjectClass *klass, void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
@ -437,47 +641,101 @@ static void via_class_init(ObjectClass *klass, void *data)
k->realize = vt82c686b_realize;
k->config_write = vt82c686b_write_config;
k->vendor_id = PCI_VENDOR_ID_VIA;
k->device_id = PCI_DEVICE_ID_VIA_ISA_BRIDGE;
k->device_id = PCI_DEVICE_ID_VIA_82C686B_ISA;
k->class_id = PCI_CLASS_BRIDGE_ISA;
k->revision = 0x40;
dc->reset = vt82c686b_isa_reset;
dc->desc = "ISA bridge";
dc->vmsd = &vmstate_via;
/*
* Reason: part of VIA VT82C686 southbridge, needs to be wired up,
* e.g. by mips_fuloong2e_init()
*/
/* Reason: part of VIA VT82C686 southbridge, needs to be wired up */
dc->user_creatable = false;
}
static const TypeInfo via_info = {
static const TypeInfo vt82c686b_isa_info = {
.name = TYPE_VT82C686B_ISA,
.parent = TYPE_PCI_DEVICE,
.instance_size = sizeof(VT82C686BISAState),
.class_init = via_class_init,
.interfaces = (InterfaceInfo[]) {
{ INTERFACE_CONVENTIONAL_PCI_DEVICE },
{ },
},
.parent = TYPE_VIA_ISA,
.instance_size = sizeof(ViaISAState),
.class_init = vt82c686b_class_init,
};
/* TYPE_VT8231_ISA */
static void vt82c686b_superio_class_init(ObjectClass *klass, void *data)
static void vt8231_write_config(PCIDevice *d, uint32_t addr,
uint32_t val, int len)
{
ISASuperIOClass *sc = ISA_SUPERIO_CLASS(klass);
ViaISAState *s = VIA_ISA(d);
sc->serial.count = 2;
sc->parallel.count = 1;
sc->ide.count = 0;
sc->floppy.count = 1;
trace_via_isa_write(addr, val, len);
pci_default_write_config(d, addr, val, len);
if (addr == 0x50) {
/* BIT(2): enable or disable superio config io ports */
via_superio_io_enable(s->via_sio, val & BIT(2));
}
}
static const TypeInfo via_superio_info = {
.name = TYPE_VT82C686B_SUPERIO,
.parent = TYPE_ISA_SUPERIO,
.instance_size = sizeof(ISASuperIODevice),
.class_size = sizeof(ISASuperIOClass),
.class_init = vt82c686b_superio_class_init,
static void vt8231_isa_reset(DeviceState *dev)
{
ViaISAState *s = VIA_ISA(dev);
uint8_t *pci_conf = s->dev.config;
pci_set_long(pci_conf + PCI_CAPABILITY_LIST, 0x000000c0);
pci_set_word(pci_conf + PCI_COMMAND, PCI_COMMAND_IO | PCI_COMMAND_MEMORY |
PCI_COMMAND_MASTER | PCI_COMMAND_SPECIAL);
pci_set_word(pci_conf + PCI_STATUS, PCI_STATUS_DEVSEL_MEDIUM);
pci_conf[0x58] = 0x40; /* Miscellaneous Control 0 */
pci_conf[0x67] = 0x08; /* Fast IR Config */
pci_conf[0x6b] = 0x01; /* Fast IR I/O Base */
}
static void vt8231_realize(PCIDevice *d, Error **errp)
{
ViaISAState *s = VIA_ISA(d);
DeviceState *dev = DEVICE(d);
ISABus *isa_bus;
qemu_irq *isa_irq;
int i;
qdev_init_gpio_out(dev, &s->cpu_intr, 1);
isa_irq = qemu_allocate_irqs(via_isa_request_i8259_irq, s, 1);
isa_bus = isa_bus_new(dev, get_system_memory(), pci_address_space_io(d),
&error_fatal);
isa_bus_irqs(isa_bus, i8259_init(isa_bus, *isa_irq));
i8254_pit_init(isa_bus, 0x40, 0, NULL);
i8257_dma_init(isa_bus, 0);
s->via_sio = VIA_SUPERIO(isa_create_simple(isa_bus, TYPE_VT8231_SUPERIO));
mc146818_rtc_init(isa_bus, 2000, NULL);
for (i = 0; i < PCI_CONFIG_HEADER_SIZE; i++) {
if (i < PCI_COMMAND || i >= PCI_REVISION_ID) {
d->wmask[i] = 0;
}
}
}
static void vt8231_class_init(ObjectClass *klass, void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
k->realize = vt8231_realize;
k->config_write = vt8231_write_config;
k->vendor_id = PCI_VENDOR_ID_VIA;
k->device_id = PCI_DEVICE_ID_VIA_8231_ISA;
k->class_id = PCI_CLASS_BRIDGE_ISA;
k->revision = 0x10;
dc->reset = vt8231_isa_reset;
dc->desc = "ISA bridge";
dc->vmsd = &vmstate_via;
/* Reason: part of VIA VT8231 southbridge, needs to be wired up */
dc->user_creatable = false;
}
static const TypeInfo vt8231_isa_info = {
.name = TYPE_VT8231_ISA,
.parent = TYPE_VIA_ISA,
.instance_size = sizeof(ViaISAState),
.class_init = vt8231_class_init,
};
@ -486,8 +744,12 @@ static void vt82c686b_register_types(void)
type_register_static(&via_pm_info);
type_register_static(&vt82c686b_pm_info);
type_register_static(&vt8231_pm_info);
type_register_static(&via_info);
type_register_static(&via_superio_info);
type_register_static(&vt82c686b_superio_info);
type_register_static(&vt8231_superio_info);
type_register_static(&via_isa_info);
type_register_static(&vt82c686b_isa_info);
type_register_static(&vt8231_isa_info);
}
type_init(vt82c686b_register_types)

View File

@ -72,3 +72,7 @@ config REMOTE_PCIHOST
config SH_PCI
bool
select PCI
config MV64361
bool
select PCI

View File

@ -19,6 +19,8 @@ pci_ss.add(when: 'CONFIG_GRACKLE_PCI', if_true: files('grackle.c'))
pci_ss.add(when: 'CONFIG_UNIN_PCI', if_true: files('uninorth.c'))
# PowerPC E500 boards
pci_ss.add(when: 'CONFIG_PPCE500_PCI', if_true: files('ppce500.c'))
# Pegasos2
pci_ss.add(when: 'CONFIG_MV64361', if_true: files('mv64361.c'))
# ARM devices
pci_ss.add(when: 'CONFIG_VERSATILE_PCI', if_true: files('versatile.c'))

951
hw/pci-host/mv64361.c Normal file
View File

@ -0,0 +1,951 @@
/*
* Marvell Discovery II MV64361 System Controller for
* QEMU PowerPC CHRP (Genesi/bPlan Pegasos II) hardware System Emulator
*
* Copyright (c) 2018-2020 BALATON Zoltan
*
* This work is licensed under the GNU GPL license version 2 or later.
*
*/
#include "qemu/osdep.h"
#include "qemu-common.h"
#include "qemu/units.h"
#include "qapi/error.h"
#include "hw/hw.h"
#include "hw/sysbus.h"
#include "hw/pci/pci.h"
#include "hw/pci/pci_host.h"
#include "hw/irq.h"
#include "hw/intc/i8259.h"
#include "hw/qdev-properties.h"
#include "exec/address-spaces.h"
#include "qemu/log.h"
#include "qemu/error-report.h"
#include "trace.h"
#include "hw/pci-host/mv64361.h"
#include "mv643xx.h"
#define TYPE_MV64361_PCI_BRIDGE "mv64361-pcibridge"
static void mv64361_pcibridge_class_init(ObjectClass *klass, void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
k->vendor_id = PCI_VENDOR_ID_MARVELL;
k->device_id = PCI_DEVICE_ID_MARVELL_MV6436X;
k->class_id = PCI_CLASS_BRIDGE_HOST;
/*
* PCI-facing part of the host bridge,
* not usable without the host-facing part
*/
dc->user_creatable = false;
}
static const TypeInfo mv64361_pcibridge_info = {
.name = TYPE_MV64361_PCI_BRIDGE,
.parent = TYPE_PCI_DEVICE,
.instance_size = sizeof(PCIDevice),
.class_init = mv64361_pcibridge_class_init,
.interfaces = (InterfaceInfo[]) {
{ INTERFACE_CONVENTIONAL_PCI_DEVICE },
{ },
},
};
#define TYPE_MV64361_PCI "mv64361-pcihost"
OBJECT_DECLARE_SIMPLE_TYPE(MV64361PCIState, MV64361_PCI)
struct MV64361PCIState {
PCIHostState parent_obj;
uint8_t index;
MemoryRegion io;
MemoryRegion mem;
qemu_irq irq[PCI_NUM_PINS];
uint32_t io_base;
uint32_t io_size;
uint32_t mem_base[4];
uint32_t mem_size[4];
uint64_t remap[5];
};
static int mv64361_pcihost_map_irq(PCIDevice *pci_dev, int n)
{
return (n + PCI_SLOT(pci_dev->devfn)) % PCI_NUM_PINS;
}
static void mv64361_pcihost_set_irq(void *opaque, int n, int level)
{
MV64361PCIState *s = opaque;
qemu_set_irq(s->irq[n], level);
}
static void mv64361_pcihost_realize(DeviceState *dev, Error **errp)
{
MV64361PCIState *s = MV64361_PCI(dev);
PCIHostState *h = PCI_HOST_BRIDGE(dev);
char *name;
name = g_strdup_printf("pci%d-io", s->index);
memory_region_init(&s->io, OBJECT(dev), name, 0x10000);
g_free(name);
name = g_strdup_printf("pci%d-mem", s->index);
memory_region_init(&s->mem, OBJECT(dev), name, 1ULL << 32);
g_free(name);
name = g_strdup_printf("pci.%d", s->index);
h->bus = pci_register_root_bus(dev, name, mv64361_pcihost_set_irq,
mv64361_pcihost_map_irq, dev,
&s->mem, &s->io, 0, 4, TYPE_PCI_BUS);
g_free(name);
pci_create_simple(h->bus, 0, TYPE_MV64361_PCI_BRIDGE);
}
static Property mv64361_pcihost_props[] = {
DEFINE_PROP_UINT8("index", MV64361PCIState, index, 0),
DEFINE_PROP_END_OF_LIST()
};
static void mv64361_pcihost_class_init(ObjectClass *klass, void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
dc->realize = mv64361_pcihost_realize;
device_class_set_props(dc, mv64361_pcihost_props);
set_bit(DEVICE_CATEGORY_BRIDGE, dc->categories);
}
static const TypeInfo mv64361_pcihost_info = {
.name = TYPE_MV64361_PCI,
.parent = TYPE_PCI_HOST_BRIDGE,
.instance_size = sizeof(MV64361PCIState),
.class_init = mv64361_pcihost_class_init,
};
static void mv64361_pci_register_types(void)
{
type_register_static(&mv64361_pcihost_info);
type_register_static(&mv64361_pcibridge_info);
}
type_init(mv64361_pci_register_types)
OBJECT_DECLARE_SIMPLE_TYPE(MV64361State, MV64361)
struct MV64361State {
SysBusDevice parent_obj;
MemoryRegion regs;
MV64361PCIState pci[2];
MemoryRegion cpu_win[19];
qemu_irq cpu_irq;
/* registers state */
uint32_t cpu_conf;
uint32_t regs_base;
uint32_t base_addr_enable;
uint64_t main_int_cr;
uint64_t cpu0_int_mask;
uint32_t gpp_io;
uint32_t gpp_level;
uint32_t gpp_value;
uint32_t gpp_int_cr;
uint32_t gpp_int_mask;
bool gpp_int_level;
};
enum mv64361_irq_cause {
MV64361_IRQ_DEVERR = 1,
MV64361_IRQ_DMAERR = 2,
MV64361_IRQ_CPUERR = 3,
MV64361_IRQ_IDMA0 = 4,
MV64361_IRQ_IDMA1 = 5,
MV64361_IRQ_IDMA2 = 6,
MV64361_IRQ_IDMA3 = 7,
MV64361_IRQ_TIMER0 = 8,
MV64361_IRQ_TIMER1 = 9,
MV64361_IRQ_TIMER2 = 10,
MV64361_IRQ_TIMER3 = 11,
MV64361_IRQ_PCI0 = 12,
MV64361_IRQ_SRAMERR = 13,
MV64361_IRQ_GBEERR = 14,
MV64361_IRQ_CERR = 15,
MV64361_IRQ_PCI1 = 16,
MV64361_IRQ_DRAMERR = 17,
MV64361_IRQ_WDNMI = 18,
MV64361_IRQ_WDE = 19,
MV64361_IRQ_PCI0IN = 20,
MV64361_IRQ_PCI0OUT = 21,
MV64361_IRQ_PCI1IN = 22,
MV64361_IRQ_PCI1OUT = 23,
MV64361_IRQ_P1_GPP0_7 = 24,
MV64361_IRQ_P1_GPP8_15 = 25,
MV64361_IRQ_P1_GPP16_23 = 26,
MV64361_IRQ_P1_GPP24_31 = 27,
MV64361_IRQ_P1_CPU_DB = 28,
/* 29-31: reserved */
MV64361_IRQ_GBE0 = 32,
MV64361_IRQ_GBE1 = 33,
MV64361_IRQ_GBE2 = 34,
/* 35: reserved */
MV64361_IRQ_SDMA0 = 36,
MV64361_IRQ_TWSI = 37,
MV64361_IRQ_SDMA1 = 38,
MV64361_IRQ_BRG = 39,
MV64361_IRQ_MPSC0 = 40,
MV64361_IRQ_MPSC1 = 41,
MV64361_IRQ_G0RX = 42,
MV64361_IRQ_G0TX = 43,
MV64361_IRQ_G0MISC = 44,
MV64361_IRQ_G1RX = 45,
MV64361_IRQ_G1TX = 46,
MV64361_IRQ_G1MISC = 47,
MV64361_IRQ_G2RX = 48,
MV64361_IRQ_G2TX = 49,
MV64361_IRQ_G2MISC = 50,
/* 51-55: reserved */
MV64361_IRQ_P0_GPP0_7 = 56,
MV64361_IRQ_P0_GPP8_15 = 57,
MV64361_IRQ_P0_GPP16_23 = 58,
MV64361_IRQ_P0_GPP24_31 = 59,
MV64361_IRQ_P0_CPU_DB = 60,
/* 61-63: reserved */
};
PCIBus *mv64361_get_pci_bus(DeviceState *dev, int n)
{
MV64361State *mv = MV64361(dev);
return PCI_HOST_BRIDGE(&mv->pci[n])->bus;
}
static void unmap_region(MemoryRegion *mr)
{
if (memory_region_is_mapped(mr)) {
memory_region_del_subregion(get_system_memory(), mr);
object_unparent(OBJECT(mr));
}
}
static void map_pci_region(MemoryRegion *mr, MemoryRegion *parent,
struct Object *owner, const char *name,
hwaddr poffs, uint64_t size, hwaddr moffs)
{
memory_region_init_alias(mr, owner, name, parent, poffs, size);
memory_region_add_subregion(get_system_memory(), moffs, mr);
trace_mv64361_region_map(name, poffs, size, moffs);
}
static void set_mem_windows(MV64361State *s, uint32_t val)
{
MV64361PCIState *p;
MemoryRegion *mr;
uint32_t mask;
int i;
val &= 0x1fffff;
for (mask = 1, i = 0; i < 21; i++, mask <<= 1) {
if ((val & mask) != (s->base_addr_enable & mask)) {
trace_mv64361_region_enable(!(val & mask) ? "enable" : "disable", i);
/*
* 0-3 are SDRAM chip selects but we map all RAM directly
* 4-7 are device chip selects (not sure what those are)
* 8 is Boot device (ROM) chip select but we map that directly too
*/
if (i == 9) {
p = &s->pci[0];
mr = &s->cpu_win[i];
unmap_region(mr);
if (!(val & mask)) {
map_pci_region(mr, &p->io, OBJECT(s), "pci0-io-win",
p->remap[4], (p->io_size + 1) << 16,
(p->io_base & 0xfffff) << 16);
}
} else if (i == 10) {
p = &s->pci[0];
mr = &s->cpu_win[i];
unmap_region(mr);
if (!(val & mask)) {
map_pci_region(mr, &p->mem, OBJECT(s), "pci0-mem0-win",
p->remap[0], (p->mem_size[0] + 1) << 16,
(p->mem_base[0] & 0xfffff) << 16);
}
} else if (i == 11) {
p = &s->pci[0];
mr = &s->cpu_win[i];
unmap_region(mr);
if (!(val & mask)) {
map_pci_region(mr, &p->mem, OBJECT(s), "pci0-mem1-win",
p->remap[1], (p->mem_size[1] + 1) << 16,
(p->mem_base[1] & 0xfffff) << 16);
}
} else if (i == 12) {
p = &s->pci[0];
mr = &s->cpu_win[i];
unmap_region(mr);
if (!(val & mask)) {
map_pci_region(mr, &p->mem, OBJECT(s), "pci0-mem2-win",
p->remap[2], (p->mem_size[2] + 1) << 16,
(p->mem_base[2] & 0xfffff) << 16);
}
} else if (i == 13) {
p = &s->pci[0];
mr = &s->cpu_win[i];
unmap_region(mr);
if (!(val & mask)) {
map_pci_region(mr, &p->mem, OBJECT(s), "pci0-mem3-win",
p->remap[3], (p->mem_size[3] + 1) << 16,
(p->mem_base[3] & 0xfffff) << 16);
}
} else if (i == 14) {
p = &s->pci[1];
mr = &s->cpu_win[i];
unmap_region(mr);
if (!(val & mask)) {
map_pci_region(mr, &p->io, OBJECT(s), "pci1-io-win",
p->remap[4], (p->io_size + 1) << 16,
(p->io_base & 0xfffff) << 16);
}
} else if (i == 15) {
p = &s->pci[1];
mr = &s->cpu_win[i];
unmap_region(mr);
if (!(val & mask)) {
map_pci_region(mr, &p->mem, OBJECT(s), "pci1-mem0-win",
p->remap[0], (p->mem_size[0] + 1) << 16,
(p->mem_base[0] & 0xfffff) << 16);
}
} else if (i == 16) {
p = &s->pci[1];
mr = &s->cpu_win[i];
unmap_region(mr);
if (!(val & mask)) {
map_pci_region(mr, &p->mem, OBJECT(s), "pci1-mem1-win",
p->remap[1], (p->mem_size[1] + 1) << 16,
(p->mem_base[1] & 0xfffff) << 16);
}
} else if (i == 17) {
p = &s->pci[1];
mr = &s->cpu_win[i];
unmap_region(mr);
if (!(val & mask)) {
map_pci_region(mr, &p->mem, OBJECT(s), "pci1-mem2-win",
p->remap[2], (p->mem_size[2] + 1) << 16,
(p->mem_base[2] & 0xfffff) << 16);
}
} else if (i == 18) {
p = &s->pci[1];
mr = &s->cpu_win[i];
unmap_region(mr);
if (!(val & mask)) {
map_pci_region(mr, &p->mem, OBJECT(s), "pci1-mem3-win",
p->remap[3], (p->mem_size[3] + 1) << 16,
(p->mem_base[3] & 0xfffff) << 16);
}
/* 19 is integrated SRAM */
} else if (i == 20) {
mr = &s->regs;
unmap_region(mr);
if (!(val & mask)) {
memory_region_add_subregion(get_system_memory(),
(s->regs_base & 0xfffff) << 16, mr);
}
}
}
}
s->base_addr_enable = val;
}
static void mv64361_update_irq(void *opaque, int n, int level)
{
MV64361State *s = opaque;
uint64_t val = s->main_int_cr;
if (level) {
val |= BIT_ULL(n);
} else {
val &= ~BIT_ULL(n);
}
if ((s->main_int_cr & s->cpu0_int_mask) != (val & s->cpu0_int_mask)) {
qemu_set_irq(s->cpu_irq, level);
}
s->main_int_cr = val;
}
static uint64_t mv64361_read(void *opaque, hwaddr addr, unsigned int size)
{
MV64361State *s = MV64361(opaque);
uint32_t ret = 0;
switch (addr) {
case MV64340_CPU_CONFIG:
ret = s->cpu_conf;
break;
case MV64340_PCI_0_IO_BASE_ADDR:
ret = s->pci[0].io_base;
break;
case MV64340_PCI_0_IO_SIZE:
ret = s->pci[0].io_size;
break;
case MV64340_PCI_0_IO_ADDR_REMAP:
ret = s->pci[0].remap[4] >> 16;
break;
case MV64340_PCI_0_MEMORY0_BASE_ADDR:
ret = s->pci[0].mem_base[0];
break;
case MV64340_PCI_0_MEMORY0_SIZE:
ret = s->pci[0].mem_size[0];
break;
case MV64340_PCI_0_MEMORY0_LOW_ADDR_REMAP:
ret = (s->pci[0].remap[0] & 0xffff0000) >> 16;
break;
case MV64340_PCI_0_MEMORY0_HIGH_ADDR_REMAP:
ret = s->pci[0].remap[0] >> 32;
break;
case MV64340_PCI_0_MEMORY1_BASE_ADDR:
ret = s->pci[0].mem_base[1];
break;
case MV64340_PCI_0_MEMORY1_SIZE:
ret = s->pci[0].mem_size[1];
break;
case MV64340_PCI_0_MEMORY1_LOW_ADDR_REMAP:
ret = (s->pci[0].remap[1] & 0xffff0000) >> 16;
break;
case MV64340_PCI_0_MEMORY1_HIGH_ADDR_REMAP:
ret = s->pci[0].remap[1] >> 32;
break;
case MV64340_PCI_0_MEMORY2_BASE_ADDR:
ret = s->pci[0].mem_base[2];
break;
case MV64340_PCI_0_MEMORY2_SIZE:
ret = s->pci[0].mem_size[2];
break;
case MV64340_PCI_0_MEMORY2_LOW_ADDR_REMAP:
ret = (s->pci[0].remap[2] & 0xffff0000) >> 16;
break;
case MV64340_PCI_0_MEMORY2_HIGH_ADDR_REMAP:
ret = s->pci[0].remap[2] >> 32;
break;
case MV64340_PCI_0_MEMORY3_BASE_ADDR:
ret = s->pci[0].mem_base[3];
break;
case MV64340_PCI_0_MEMORY3_SIZE:
ret = s->pci[0].mem_size[3];
break;
case MV64340_PCI_0_MEMORY3_LOW_ADDR_REMAP:
ret = (s->pci[0].remap[3] & 0xffff0000) >> 16;
break;
case MV64340_PCI_0_MEMORY3_HIGH_ADDR_REMAP:
ret = s->pci[0].remap[3] >> 32;
break;
case MV64340_PCI_1_IO_BASE_ADDR:
ret = s->pci[1].io_base;
break;
case MV64340_PCI_1_IO_SIZE:
ret = s->pci[1].io_size;
break;
case MV64340_PCI_1_IO_ADDR_REMAP:
ret = s->pci[1].remap[4] >> 16;
break;
case MV64340_PCI_1_MEMORY0_BASE_ADDR:
ret = s->pci[1].mem_base[0];
break;
case MV64340_PCI_1_MEMORY0_SIZE:
ret = s->pci[1].mem_size[0];
break;
case MV64340_PCI_1_MEMORY0_LOW_ADDR_REMAP:
ret = (s->pci[1].remap[0] & 0xffff0000) >> 16;
break;
case MV64340_PCI_1_MEMORY0_HIGH_ADDR_REMAP:
ret = s->pci[1].remap[0] >> 32;
break;
case MV64340_PCI_1_MEMORY1_BASE_ADDR:
ret = s->pci[1].mem_base[1];
break;
case MV64340_PCI_1_MEMORY1_SIZE:
ret = s->pci[1].mem_size[1];
break;
case MV64340_PCI_1_MEMORY1_LOW_ADDR_REMAP:
ret = (s->pci[1].remap[1] & 0xffff0000) >> 16;
break;
case MV64340_PCI_1_MEMORY1_HIGH_ADDR_REMAP:
ret = s->pci[1].remap[1] >> 32;
break;
case MV64340_PCI_1_MEMORY2_BASE_ADDR:
ret = s->pci[1].mem_base[2];
break;
case MV64340_PCI_1_MEMORY2_SIZE:
ret = s->pci[1].mem_size[2];
break;
case MV64340_PCI_1_MEMORY2_LOW_ADDR_REMAP:
ret = (s->pci[1].remap[2] & 0xffff0000) >> 16;
break;
case MV64340_PCI_1_MEMORY2_HIGH_ADDR_REMAP:
ret = s->pci[1].remap[2] >> 32;
break;
case MV64340_PCI_1_MEMORY3_BASE_ADDR:
ret = s->pci[1].mem_base[3];
break;
case MV64340_PCI_1_MEMORY3_SIZE:
ret = s->pci[1].mem_size[3];
break;
case MV64340_PCI_1_MEMORY3_LOW_ADDR_REMAP:
ret = (s->pci[1].remap[3] & 0xffff0000) >> 16;
break;
case MV64340_PCI_1_MEMORY3_HIGH_ADDR_REMAP:
ret = s->pci[1].remap[3] >> 32;
break;
case MV64340_INTERNAL_SPACE_BASE_ADDR:
ret = s->regs_base;
break;
case MV64340_BASE_ADDR_ENABLE:
ret = s->base_addr_enable;
break;
case MV64340_PCI_0_CONFIG_ADDR:
ret = pci_host_conf_le_ops.read(PCI_HOST_BRIDGE(&s->pci[0]), 0, size);
break;
case MV64340_PCI_0_CONFIG_DATA_VIRTUAL_REG ...
MV64340_PCI_0_CONFIG_DATA_VIRTUAL_REG + 3:
ret = pci_host_data_le_ops.read(PCI_HOST_BRIDGE(&s->pci[0]),
addr - MV64340_PCI_0_CONFIG_DATA_VIRTUAL_REG, size);
break;
case MV64340_PCI_1_CONFIG_ADDR:
ret = pci_host_conf_le_ops.read(PCI_HOST_BRIDGE(&s->pci[1]), 0, size);
break;
case MV64340_PCI_1_CONFIG_DATA_VIRTUAL_REG ...
MV64340_PCI_1_CONFIG_DATA_VIRTUAL_REG + 3:
ret = pci_host_data_le_ops.read(PCI_HOST_BRIDGE(&s->pci[1]),
addr - MV64340_PCI_1_CONFIG_DATA_VIRTUAL_REG, size);
break;
case MV64340_PCI_1_INTERRUPT_ACKNOWLEDGE_VIRTUAL_REG:
/* FIXME: Should this be sent via the PCI bus somehow? */
if (s->gpp_int_level && (s->gpp_value & BIT(31))) {
ret = pic_read_irq(isa_pic);
}
break;
case MV64340_MAIN_INTERRUPT_CAUSE_LOW:
ret = s->main_int_cr;
break;
case MV64340_MAIN_INTERRUPT_CAUSE_HIGH:
ret = s->main_int_cr >> 32;
break;
case MV64340_CPU_INTERRUPT0_MASK_LOW:
ret = s->cpu0_int_mask;
break;
case MV64340_CPU_INTERRUPT0_MASK_HIGH:
ret = s->cpu0_int_mask >> 32;
break;
case MV64340_CPU_INTERRUPT0_SELECT_CAUSE:
ret = s->main_int_cr;
if (s->main_int_cr & s->cpu0_int_mask) {
if (!(s->main_int_cr & s->cpu0_int_mask & 0xffffffff)) {
ret = s->main_int_cr >> 32 | BIT(30);
} else if ((s->main_int_cr & s->cpu0_int_mask) >> 32) {
ret |= BIT(31);
}
}
break;
case MV64340_CUNIT_ARBITER_CONTROL_REG:
ret = 0x11ff0000 | (s->gpp_int_level << 10);
break;
case MV64340_GPP_IO_CONTROL:
ret = s->gpp_io;
break;
case MV64340_GPP_LEVEL_CONTROL:
ret = s->gpp_level;
break;
case MV64340_GPP_VALUE:
ret = s->gpp_value;
break;
case MV64340_GPP_VALUE_SET:
case MV64340_GPP_VALUE_CLEAR:
ret = 0;
break;
case MV64340_GPP_INTERRUPT_CAUSE:
ret = s->gpp_int_cr;
break;
case MV64340_GPP_INTERRUPT_MASK0:
case MV64340_GPP_INTERRUPT_MASK1:
ret = s->gpp_int_mask;
break;
default:
qemu_log_mask(LOG_UNIMP, "%s: Unimplemented register read 0x%"
HWADDR_PRIx "\n", __func__, addr);
break;
}
if (addr != MV64340_PCI_1_INTERRUPT_ACKNOWLEDGE_VIRTUAL_REG) {
trace_mv64361_reg_read(addr, ret);
}
return ret;
}
static void warn_swap_bit(uint64_t val)
{
if ((val & 0x3000000ULL) >> 24 != 1) {
qemu_log_mask(LOG_UNIMP, "%s: Data swap not implemented", __func__);
}
}
static void mv64361_set_pci_mem_remap(MV64361State *s, int bus, int idx,
uint64_t val, bool high)
{
if (high) {
s->pci[bus].remap[idx] = val;
} else {
s->pci[bus].remap[idx] &= 0xffffffff00000000ULL;
s->pci[bus].remap[idx] |= (val & 0xffffULL) << 16;
}
}
static void mv64361_write(void *opaque, hwaddr addr, uint64_t val,
unsigned int size)
{
MV64361State *s = MV64361(opaque);
trace_mv64361_reg_write(addr, val);
switch (addr) {
case MV64340_CPU_CONFIG:
s->cpu_conf = val & 0xe4e3bffULL;
s->cpu_conf |= BIT(23);
break;
case MV64340_PCI_0_IO_BASE_ADDR:
s->pci[0].io_base = val & 0x30fffffULL;
warn_swap_bit(val);
if (!(s->cpu_conf & BIT(27))) {
s->pci[0].remap[4] = (val & 0xffffULL) << 16;
}
break;
case MV64340_PCI_0_IO_SIZE:
s->pci[0].io_size = val & 0xffffULL;
break;
case MV64340_PCI_0_IO_ADDR_REMAP:
s->pci[0].remap[4] = (val & 0xffffULL) << 16;
break;
case MV64340_PCI_0_MEMORY0_BASE_ADDR:
s->pci[0].mem_base[0] = val & 0x70fffffULL;
warn_swap_bit(val);
if (!(s->cpu_conf & BIT(27))) {
mv64361_set_pci_mem_remap(s, 0, 0, val, false);
}
break;
case MV64340_PCI_0_MEMORY0_SIZE:
s->pci[0].mem_size[0] = val & 0xffffULL;
break;
case MV64340_PCI_0_MEMORY0_LOW_ADDR_REMAP:
case MV64340_PCI_0_MEMORY0_HIGH_ADDR_REMAP:
mv64361_set_pci_mem_remap(s, 0, 0, val,
(addr == MV64340_PCI_0_MEMORY0_HIGH_ADDR_REMAP));
break;
case MV64340_PCI_0_MEMORY1_BASE_ADDR:
s->pci[0].mem_base[1] = val & 0x70fffffULL;
warn_swap_bit(val);
if (!(s->cpu_conf & BIT(27))) {
mv64361_set_pci_mem_remap(s, 0, 1, val, false);
}
break;
case MV64340_PCI_0_MEMORY1_SIZE:
s->pci[0].mem_size[1] = val & 0xffffULL;
break;
case MV64340_PCI_0_MEMORY1_LOW_ADDR_REMAP:
case MV64340_PCI_0_MEMORY1_HIGH_ADDR_REMAP:
mv64361_set_pci_mem_remap(s, 0, 1, val,
(addr == MV64340_PCI_0_MEMORY1_HIGH_ADDR_REMAP));
break;
case MV64340_PCI_0_MEMORY2_BASE_ADDR:
s->pci[0].mem_base[2] = val & 0x70fffffULL;
warn_swap_bit(val);
if (!(s->cpu_conf & BIT(27))) {
mv64361_set_pci_mem_remap(s, 0, 2, val, false);
}
break;
case MV64340_PCI_0_MEMORY2_SIZE:
s->pci[0].mem_size[2] = val & 0xffffULL;
break;
case MV64340_PCI_0_MEMORY2_LOW_ADDR_REMAP:
case MV64340_PCI_0_MEMORY2_HIGH_ADDR_REMAP:
mv64361_set_pci_mem_remap(s, 0, 2, val,
(addr == MV64340_PCI_0_MEMORY2_HIGH_ADDR_REMAP));
break;
case MV64340_PCI_0_MEMORY3_BASE_ADDR:
s->pci[0].mem_base[3] = val & 0x70fffffULL;
warn_swap_bit(val);
if (!(s->cpu_conf & BIT(27))) {
mv64361_set_pci_mem_remap(s, 0, 3, val, false);
}
break;
case MV64340_PCI_0_MEMORY3_SIZE:
s->pci[0].mem_size[3] = val & 0xffffULL;
break;
case MV64340_PCI_0_MEMORY3_LOW_ADDR_REMAP:
case MV64340_PCI_0_MEMORY3_HIGH_ADDR_REMAP:
mv64361_set_pci_mem_remap(s, 0, 3, val,
(addr == MV64340_PCI_0_MEMORY3_HIGH_ADDR_REMAP));
break;
case MV64340_PCI_1_IO_BASE_ADDR:
s->pci[1].io_base = val & 0x30fffffULL;
warn_swap_bit(val);
break;
if (!(s->cpu_conf & BIT(27))) {
s->pci[1].remap[4] = (val & 0xffffULL) << 16;
}
break;
case MV64340_PCI_1_IO_SIZE:
s->pci[1].io_size = val & 0xffffULL;
break;
case MV64340_PCI_1_MEMORY0_BASE_ADDR:
s->pci[1].mem_base[0] = val & 0x70fffffULL;
warn_swap_bit(val);
if (!(s->cpu_conf & BIT(27))) {
mv64361_set_pci_mem_remap(s, 1, 0, val, false);
}
break;
case MV64340_PCI_1_MEMORY0_SIZE:
s->pci[1].mem_size[0] = val & 0xffffULL;
break;
case MV64340_PCI_1_MEMORY0_LOW_ADDR_REMAP:
case MV64340_PCI_1_MEMORY0_HIGH_ADDR_REMAP:
mv64361_set_pci_mem_remap(s, 1, 0, val,
(addr == MV64340_PCI_1_MEMORY0_HIGH_ADDR_REMAP));
break;
case MV64340_PCI_1_MEMORY1_BASE_ADDR:
s->pci[1].mem_base[1] = val & 0x70fffffULL;
warn_swap_bit(val);
if (!(s->cpu_conf & BIT(27))) {
mv64361_set_pci_mem_remap(s, 1, 1, val, false);
}
break;
case MV64340_PCI_1_MEMORY1_SIZE:
s->pci[1].mem_size[1] = val & 0xffffULL;
break;
case MV64340_PCI_1_MEMORY1_LOW_ADDR_REMAP:
case MV64340_PCI_1_MEMORY1_HIGH_ADDR_REMAP:
mv64361_set_pci_mem_remap(s, 1, 1, val,
(addr == MV64340_PCI_1_MEMORY1_HIGH_ADDR_REMAP));
break;
case MV64340_PCI_1_MEMORY2_BASE_ADDR:
s->pci[1].mem_base[2] = val & 0x70fffffULL;
warn_swap_bit(val);
if (!(s->cpu_conf & BIT(27))) {
mv64361_set_pci_mem_remap(s, 1, 2, val, false);
}
break;
case MV64340_PCI_1_MEMORY2_SIZE:
s->pci[1].mem_size[2] = val & 0xffffULL;
break;
case MV64340_PCI_1_MEMORY2_LOW_ADDR_REMAP:
case MV64340_PCI_1_MEMORY2_HIGH_ADDR_REMAP:
mv64361_set_pci_mem_remap(s, 1, 2, val,
(addr == MV64340_PCI_1_MEMORY2_HIGH_ADDR_REMAP));
break;
case MV64340_PCI_1_MEMORY3_BASE_ADDR:
s->pci[1].mem_base[3] = val & 0x70fffffULL;
warn_swap_bit(val);
if (!(s->cpu_conf & BIT(27))) {
mv64361_set_pci_mem_remap(s, 1, 3, val, false);
}
break;
case MV64340_PCI_1_MEMORY3_SIZE:
s->pci[1].mem_size[3] = val & 0xffffULL;
break;
case MV64340_PCI_1_MEMORY3_LOW_ADDR_REMAP:
case MV64340_PCI_1_MEMORY3_HIGH_ADDR_REMAP:
mv64361_set_pci_mem_remap(s, 1, 3, val,
(addr == MV64340_PCI_1_MEMORY3_HIGH_ADDR_REMAP));
break;
case MV64340_INTERNAL_SPACE_BASE_ADDR:
s->regs_base = val & 0xfffffULL;
break;
case MV64340_BASE_ADDR_ENABLE:
set_mem_windows(s, val);
break;
case MV64340_PCI_0_CONFIG_ADDR:
pci_host_conf_le_ops.write(PCI_HOST_BRIDGE(&s->pci[0]), 0, val, size);
break;
case MV64340_PCI_0_CONFIG_DATA_VIRTUAL_REG ...
MV64340_PCI_0_CONFIG_DATA_VIRTUAL_REG + 3:
pci_host_data_le_ops.write(PCI_HOST_BRIDGE(&s->pci[0]),
addr - MV64340_PCI_0_CONFIG_DATA_VIRTUAL_REG, val, size);
break;
case MV64340_PCI_1_CONFIG_ADDR:
pci_host_conf_le_ops.write(PCI_HOST_BRIDGE(&s->pci[1]), 0, val, size);
break;
case MV64340_PCI_1_CONFIG_DATA_VIRTUAL_REG ...
MV64340_PCI_1_CONFIG_DATA_VIRTUAL_REG + 3:
pci_host_data_le_ops.write(PCI_HOST_BRIDGE(&s->pci[1]),
addr - MV64340_PCI_1_CONFIG_DATA_VIRTUAL_REG, val, size);
break;
case MV64340_CPU_INTERRUPT0_MASK_LOW:
s->cpu0_int_mask &= 0xffffffff00000000ULL;
s->cpu0_int_mask |= val & 0xffffffffULL;
break;
case MV64340_CPU_INTERRUPT0_MASK_HIGH:
s->cpu0_int_mask &= 0xffffffffULL;
s->cpu0_int_mask |= val << 32;
break;
case MV64340_CUNIT_ARBITER_CONTROL_REG:
s->gpp_int_level = !!(val & BIT(10));
break;
case MV64340_GPP_IO_CONTROL:
s->gpp_io = val;
break;
case MV64340_GPP_LEVEL_CONTROL:
s->gpp_level = val;
break;
case MV64340_GPP_VALUE:
s->gpp_value &= ~s->gpp_io;
s->gpp_value |= val & s->gpp_io;
break;
case MV64340_GPP_VALUE_SET:
s->gpp_value |= val & s->gpp_io;
break;
case MV64340_GPP_VALUE_CLEAR:
s->gpp_value &= ~(val & s->gpp_io);
break;
case MV64340_GPP_INTERRUPT_CAUSE:
if (!s->gpp_int_level && val != s->gpp_int_cr) {
int i;
uint32_t ch = s->gpp_int_cr ^ val;
s->gpp_int_cr = val;
for (i = 0; i < 4; i++) {
if ((ch & 0xff << i) && !(val & 0xff << i)) {
mv64361_update_irq(opaque, MV64361_IRQ_P0_GPP0_7 + i, 0);
}
}
} else {
s->gpp_int_cr = val;
}
break;
case MV64340_GPP_INTERRUPT_MASK0:
case MV64340_GPP_INTERRUPT_MASK1:
s->gpp_int_mask = val;
break;
default:
qemu_log_mask(LOG_UNIMP, "%s: Unimplemented register write 0x%"
HWADDR_PRIx " = %"PRIx64"\n", __func__, addr, val);
break;
}
}
static const MemoryRegionOps mv64361_ops = {
.read = mv64361_read,
.write = mv64361_write,
.valid.min_access_size = 1,
.valid.max_access_size = 4,
.endianness = DEVICE_LITTLE_ENDIAN,
};
static void mv64361_gpp_irq(void *opaque, int n, int level)
{
MV64361State *s = opaque;
uint32_t mask = BIT(n);
uint32_t val = s->gpp_value & ~mask;
if (s->gpp_level & mask) {
level = !level;
}
val |= level << n;
if (val > s->gpp_value) {
s->gpp_value = val;
s->gpp_int_cr |= mask;
if (s->gpp_int_mask & mask) {
mv64361_update_irq(opaque, MV64361_IRQ_P0_GPP0_7 + n / 8, 1);
}
} else if (val < s->gpp_value) {
int b = n / 8;
s->gpp_value = val;
if (s->gpp_int_level && !(val & 0xff << b)) {
mv64361_update_irq(opaque, MV64361_IRQ_P0_GPP0_7 + b, 0);
}
}
}
static void mv64361_realize(DeviceState *dev, Error **errp)
{
MV64361State *s = MV64361(dev);
int i;
s->base_addr_enable = 0x1fffff;
memory_region_init_io(&s->regs, OBJECT(s), &mv64361_ops, s,
TYPE_MV64361, 0x10000);
for (i = 0; i < 2; i++) {
g_autofree char *name = g_strdup_printf("pcihost%d", i);
object_initialize_child(OBJECT(dev), name, &s->pci[i],
TYPE_MV64361_PCI);
DeviceState *pci = DEVICE(&s->pci[i]);
qdev_prop_set_uint8(pci, "index", i);
sysbus_realize_and_unref(SYS_BUS_DEVICE(pci), &error_fatal);
}
sysbus_init_irq(SYS_BUS_DEVICE(dev), &s->cpu_irq);
qdev_init_gpio_in_named(dev, mv64361_gpp_irq, "gpp", 32);
/* FIXME: PCI IRQ connections may be board specific */
for (i = 0; i < PCI_NUM_PINS; i++) {
s->pci[1].irq[i] = qdev_get_gpio_in_named(dev, "gpp", 12 + i);
}
}
static void mv64361_reset(DeviceState *dev)
{
MV64361State *s = MV64361(dev);
int i, j;
/*
* These values may be board specific
* Real chip supports init from an eprom but that's not modelled
*/
set_mem_windows(s, 0x1fffff);
s->cpu_conf = 0x28000ff;
s->regs_base = 0x100f100;
s->pci[0].io_base = 0x100f800;
s->pci[0].io_size = 0xff;
s->pci[0].mem_base[0] = 0x100c000;
s->pci[0].mem_size[0] = 0x1fff;
s->pci[0].mem_base[1] = 0x100f900;
s->pci[0].mem_size[1] = 0xff;
s->pci[0].mem_base[2] = 0x100f400;
s->pci[0].mem_size[2] = 0x1ff;
s->pci[0].mem_base[3] = 0x100f600;
s->pci[0].mem_size[3] = 0x1ff;
s->pci[1].io_base = 0x100fe00;
s->pci[1].io_size = 0xff;
s->pci[1].mem_base[0] = 0x1008000;
s->pci[1].mem_size[0] = 0x3fff;
s->pci[1].mem_base[1] = 0x100fd00;
s->pci[1].mem_size[1] = 0xff;
s->pci[1].mem_base[2] = 0x1002600;
s->pci[1].mem_size[2] = 0x1ff;
s->pci[1].mem_base[3] = 0x100ff80;
s->pci[1].mem_size[3] = 0x7f;
for (i = 0; i < 2; i++) {
for (j = 0; j < 4; j++) {
s->pci[i].remap[j] = s->pci[i].mem_base[j] << 16;
}
}
s->pci[0].remap[1] = 0;
s->pci[1].remap[1] = 0;
set_mem_windows(s, 0xfbfff);
}
static void mv64361_class_init(ObjectClass *klass, void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
dc->realize = mv64361_realize;
dc->reset = mv64361_reset;
}
static const TypeInfo mv64361_type_info = {
.name = TYPE_MV64361,
.parent = TYPE_SYS_BUS_DEVICE,
.instance_size = sizeof(MV64361State),
.class_init = mv64361_class_init,
};
static void mv64361_register_types(void)
{
type_register_static(&mv64361_type_info);
}
type_init(mv64361_register_types)

918
hw/pci-host/mv643xx.h Normal file
View File

@ -0,0 +1,918 @@
/*
* mv643xx.h - MV-643XX Internal registers definition file.
*
* Copyright 2002 Momentum Computer, Inc.
* Author: Matthew Dharm <mdharm@momenco.com>
* Copyright 2002 GALILEO TECHNOLOGY, LTD.
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2 of the License, or (at your
* option) any later version.
*/
#ifndef ASM_MV643XX_H
#define ASM_MV643XX_H
/****************************************/
/* Processor Address Space */
/****************************************/
/* DDR SDRAM BAR and size registers */
#define MV64340_CS_0_BASE_ADDR 0x008
#define MV64340_CS_0_SIZE 0x010
#define MV64340_CS_1_BASE_ADDR 0x208
#define MV64340_CS_1_SIZE 0x210
#define MV64340_CS_2_BASE_ADDR 0x018
#define MV64340_CS_2_SIZE 0x020
#define MV64340_CS_3_BASE_ADDR 0x218
#define MV64340_CS_3_SIZE 0x220
/* Devices BAR and size registers */
#define MV64340_DEV_CS0_BASE_ADDR 0x028
#define MV64340_DEV_CS0_SIZE 0x030
#define MV64340_DEV_CS1_BASE_ADDR 0x228
#define MV64340_DEV_CS1_SIZE 0x230
#define MV64340_DEV_CS2_BASE_ADDR 0x248
#define MV64340_DEV_CS2_SIZE 0x250
#define MV64340_DEV_CS3_BASE_ADDR 0x038
#define MV64340_DEV_CS3_SIZE 0x040
#define MV64340_BOOTCS_BASE_ADDR 0x238
#define MV64340_BOOTCS_SIZE 0x240
/* PCI 0 BAR and size registers */
#define MV64340_PCI_0_IO_BASE_ADDR 0x048
#define MV64340_PCI_0_IO_SIZE 0x050
#define MV64340_PCI_0_MEMORY0_BASE_ADDR 0x058
#define MV64340_PCI_0_MEMORY0_SIZE 0x060
#define MV64340_PCI_0_MEMORY1_BASE_ADDR 0x080
#define MV64340_PCI_0_MEMORY1_SIZE 0x088
#define MV64340_PCI_0_MEMORY2_BASE_ADDR 0x258
#define MV64340_PCI_0_MEMORY2_SIZE 0x260
#define MV64340_PCI_0_MEMORY3_BASE_ADDR 0x280
#define MV64340_PCI_0_MEMORY3_SIZE 0x288
/* PCI 1 BAR and size registers */
#define MV64340_PCI_1_IO_BASE_ADDR 0x090
#define MV64340_PCI_1_IO_SIZE 0x098
#define MV64340_PCI_1_MEMORY0_BASE_ADDR 0x0a0
#define MV64340_PCI_1_MEMORY0_SIZE 0x0a8
#define MV64340_PCI_1_MEMORY1_BASE_ADDR 0x0b0
#define MV64340_PCI_1_MEMORY1_SIZE 0x0b8
#define MV64340_PCI_1_MEMORY2_BASE_ADDR 0x2a0
#define MV64340_PCI_1_MEMORY2_SIZE 0x2a8
#define MV64340_PCI_1_MEMORY3_BASE_ADDR 0x2b0
#define MV64340_PCI_1_MEMORY3_SIZE 0x2b8
/* SRAM base address */
#define MV64340_INTEGRATED_SRAM_BASE_ADDR 0x268
/* internal registers space base address */
#define MV64340_INTERNAL_SPACE_BASE_ADDR 0x068
/* Enables the CS , DEV_CS , PCI 0 and PCI 1 windows above */
#define MV64340_BASE_ADDR_ENABLE 0x278
/****************************************/
/* PCI remap registers */
/****************************************/
/* PCI 0 */
#define MV64340_PCI_0_IO_ADDR_REMAP 0x0f0
#define MV64340_PCI_0_MEMORY0_LOW_ADDR_REMAP 0x0f8
#define MV64340_PCI_0_MEMORY0_HIGH_ADDR_REMAP 0x320
#define MV64340_PCI_0_MEMORY1_LOW_ADDR_REMAP 0x100
#define MV64340_PCI_0_MEMORY1_HIGH_ADDR_REMAP 0x328
#define MV64340_PCI_0_MEMORY2_LOW_ADDR_REMAP 0x2f8
#define MV64340_PCI_0_MEMORY2_HIGH_ADDR_REMAP 0x330
#define MV64340_PCI_0_MEMORY3_LOW_ADDR_REMAP 0x300
#define MV64340_PCI_0_MEMORY3_HIGH_ADDR_REMAP 0x338
/* PCI 1 */
#define MV64340_PCI_1_IO_ADDR_REMAP 0x108
#define MV64340_PCI_1_MEMORY0_LOW_ADDR_REMAP 0x110
#define MV64340_PCI_1_MEMORY0_HIGH_ADDR_REMAP 0x340
#define MV64340_PCI_1_MEMORY1_LOW_ADDR_REMAP 0x118
#define MV64340_PCI_1_MEMORY1_HIGH_ADDR_REMAP 0x348
#define MV64340_PCI_1_MEMORY2_LOW_ADDR_REMAP 0x310
#define MV64340_PCI_1_MEMORY2_HIGH_ADDR_REMAP 0x350
#define MV64340_PCI_1_MEMORY3_LOW_ADDR_REMAP 0x318
#define MV64340_PCI_1_MEMORY3_HIGH_ADDR_REMAP 0x358
#define MV64340_CPU_PCI_0_HEADERS_RETARGET_CONTROL 0x3b0
#define MV64340_CPU_PCI_0_HEADERS_RETARGET_BASE 0x3b8
#define MV64340_CPU_PCI_1_HEADERS_RETARGET_CONTROL 0x3c0
#define MV64340_CPU_PCI_1_HEADERS_RETARGET_BASE 0x3c8
#define MV64340_CPU_GE_HEADERS_RETARGET_CONTROL 0x3d0
#define MV64340_CPU_GE_HEADERS_RETARGET_BASE 0x3d8
#define MV64340_CPU_IDMA_HEADERS_RETARGET_CONTROL 0x3e0
#define MV64340_CPU_IDMA_HEADERS_RETARGET_BASE 0x3e8
/****************************************/
/* CPU Control Registers */
/****************************************/
#define MV64340_CPU_CONFIG 0x000
#define MV64340_CPU_MODE 0x120
#define MV64340_CPU_MASTER_CONTROL 0x160
#define MV64340_CPU_CROSS_BAR_CONTROL_LOW 0x150
#define MV64340_CPU_CROSS_BAR_CONTROL_HIGH 0x158
#define MV64340_CPU_CROSS_BAR_TIMEOUT 0x168
/****************************************/
/* SMP RegisterS */
/****************************************/
#define MV64340_SMP_WHO_AM_I 0x200
#define MV64340_SMP_CPU0_DOORBELL 0x214
#define MV64340_SMP_CPU0_DOORBELL_CLEAR 0x21C
#define MV64340_SMP_CPU1_DOORBELL 0x224
#define MV64340_SMP_CPU1_DOORBELL_CLEAR 0x22C
#define MV64340_SMP_CPU0_DOORBELL_MASK 0x234
#define MV64340_SMP_CPU1_DOORBELL_MASK 0x23C
#define MV64340_SMP_SEMAPHOR0 0x244
#define MV64340_SMP_SEMAPHOR1 0x24c
#define MV64340_SMP_SEMAPHOR2 0x254
#define MV64340_SMP_SEMAPHOR3 0x25c
#define MV64340_SMP_SEMAPHOR4 0x264
#define MV64340_SMP_SEMAPHOR5 0x26c
#define MV64340_SMP_SEMAPHOR6 0x274
#define MV64340_SMP_SEMAPHOR7 0x27c
/****************************************/
/* CPU Sync Barrier Register */
/****************************************/
#define MV64340_CPU_0_SYNC_BARRIER_TRIGGER 0x0c0
#define MV64340_CPU_0_SYNC_BARRIER_VIRTUAL 0x0c8
#define MV64340_CPU_1_SYNC_BARRIER_TRIGGER 0x0d0
#define MV64340_CPU_1_SYNC_BARRIER_VIRTUAL 0x0d8
/****************************************/
/* CPU Access Protect */
/****************************************/
#define MV64340_CPU_PROTECT_WINDOW_0_BASE_ADDR 0x180
#define MV64340_CPU_PROTECT_WINDOW_0_SIZE 0x188
#define MV64340_CPU_PROTECT_WINDOW_1_BASE_ADDR 0x190
#define MV64340_CPU_PROTECT_WINDOW_1_SIZE 0x198
#define MV64340_CPU_PROTECT_WINDOW_2_BASE_ADDR 0x1a0
#define MV64340_CPU_PROTECT_WINDOW_2_SIZE 0x1a8
#define MV64340_CPU_PROTECT_WINDOW_3_BASE_ADDR 0x1b0
#define MV64340_CPU_PROTECT_WINDOW_3_SIZE 0x1b8
/****************************************/
/* CPU Error Report */
/****************************************/
#define MV64340_CPU_ERROR_ADDR_LOW 0x070
#define MV64340_CPU_ERROR_ADDR_HIGH 0x078
#define MV64340_CPU_ERROR_DATA_LOW 0x128
#define MV64340_CPU_ERROR_DATA_HIGH 0x130
#define MV64340_CPU_ERROR_PARITY 0x138
#define MV64340_CPU_ERROR_CAUSE 0x140
#define MV64340_CPU_ERROR_MASK 0x148
/****************************************/
/* CPU Interface Debug Registers */
/****************************************/
#define MV64340_PUNIT_SLAVE_DEBUG_LOW 0x360
#define MV64340_PUNIT_SLAVE_DEBUG_HIGH 0x368
#define MV64340_PUNIT_MASTER_DEBUG_LOW 0x370
#define MV64340_PUNIT_MASTER_DEBUG_HIGH 0x378
#define MV64340_PUNIT_MMASK 0x3e4
/****************************************/
/* Integrated SRAM Registers */
/****************************************/
#define MV64340_SRAM_CONFIG 0x380
#define MV64340_SRAM_TEST_MODE 0X3F4
#define MV64340_SRAM_ERROR_CAUSE 0x388
#define MV64340_SRAM_ERROR_ADDR 0x390
#define MV64340_SRAM_ERROR_ADDR_HIGH 0X3F8
#define MV64340_SRAM_ERROR_DATA_LOW 0x398
#define MV64340_SRAM_ERROR_DATA_HIGH 0x3a0
#define MV64340_SRAM_ERROR_DATA_PARITY 0x3a8
/****************************************/
/* SDRAM Configuration */
/****************************************/
#define MV64340_SDRAM_CONFIG 0x1400
#define MV64340_D_UNIT_CONTROL_LOW 0x1404
#define MV64340_D_UNIT_CONTROL_HIGH 0x1424
#define MV64340_SDRAM_TIMING_CONTROL_LOW 0x1408
#define MV64340_SDRAM_TIMING_CONTROL_HIGH 0x140c
#define MV64340_SDRAM_ADDR_CONTROL 0x1410
#define MV64340_SDRAM_OPEN_PAGES_CONTROL 0x1414
#define MV64340_SDRAM_OPERATION 0x1418
#define MV64340_SDRAM_MODE 0x141c
#define MV64340_EXTENDED_DRAM_MODE 0x1420
#define MV64340_SDRAM_CROSS_BAR_CONTROL_LOW 0x1430
#define MV64340_SDRAM_CROSS_BAR_CONTROL_HIGH 0x1434
#define MV64340_SDRAM_CROSS_BAR_TIMEOUT 0x1438
#define MV64340_SDRAM_ADDR_CTRL_PADS_CALIBRATION 0x14c0
#define MV64340_SDRAM_DATA_PADS_CALIBRATION 0x14c4
/****************************************/
/* SDRAM Error Report */
/****************************************/
#define MV64340_SDRAM_ERROR_DATA_LOW 0x1444
#define MV64340_SDRAM_ERROR_DATA_HIGH 0x1440
#define MV64340_SDRAM_ERROR_ADDR 0x1450
#define MV64340_SDRAM_RECEIVED_ECC 0x1448
#define MV64340_SDRAM_CALCULATED_ECC 0x144c
#define MV64340_SDRAM_ECC_CONTROL 0x1454
#define MV64340_SDRAM_ECC_ERROR_COUNTER 0x1458
/******************************************/
/* Controlled Delay Line (CDL) Registers */
/******************************************/
#define MV64340_DFCDL_CONFIG0 0x1480
#define MV64340_DFCDL_CONFIG1 0x1484
#define MV64340_DLL_WRITE 0x1488
#define MV64340_DLL_READ 0x148c
#define MV64340_SRAM_ADDR 0x1490
#define MV64340_SRAM_DATA0 0x1494
#define MV64340_SRAM_DATA1 0x1498
#define MV64340_SRAM_DATA2 0x149c
#define MV64340_DFCL_PROBE 0x14a0
/******************************************/
/* Debug Registers */
/******************************************/
#define MV64340_DUNIT_DEBUG_LOW 0x1460
#define MV64340_DUNIT_DEBUG_HIGH 0x1464
#define MV64340_DUNIT_MMASK 0X1b40
/****************************************/
/* Device Parameters */
/****************************************/
#define MV64340_DEVICE_BANK0_PARAMETERS 0x45c
#define MV64340_DEVICE_BANK1_PARAMETERS 0x460
#define MV64340_DEVICE_BANK2_PARAMETERS 0x464
#define MV64340_DEVICE_BANK3_PARAMETERS 0x468
#define MV64340_DEVICE_BOOT_BANK_PARAMETERS 0x46c
#define MV64340_DEVICE_INTERFACE_CONTROL 0x4c0
#define MV64340_DEVICE_INTERFACE_CROSS_BAR_CONTROL_LOW 0x4c8
#define MV64340_DEVICE_INTERFACE_CROSS_BAR_CONTROL_HIGH 0x4cc
#define MV64340_DEVICE_INTERFACE_CROSS_BAR_TIMEOUT 0x4c4
/****************************************/
/* Device interrupt registers */
/****************************************/
#define MV64340_DEVICE_INTERRUPT_CAUSE 0x4d0
#define MV64340_DEVICE_INTERRUPT_MASK 0x4d4
#define MV64340_DEVICE_ERROR_ADDR 0x4d8
#define MV64340_DEVICE_ERROR_DATA 0x4dc
#define MV64340_DEVICE_ERROR_PARITY 0x4e0
/****************************************/
/* Device debug registers */
/****************************************/
#define MV64340_DEVICE_DEBUG_LOW 0x4e4
#define MV64340_DEVICE_DEBUG_HIGH 0x4e8
#define MV64340_RUNIT_MMASK 0x4f0
/****************************************/
/* PCI Slave Address Decoding registers */
/****************************************/
#define MV64340_PCI_0_CS_0_BANK_SIZE 0xc08
#define MV64340_PCI_1_CS_0_BANK_SIZE 0xc88
#define MV64340_PCI_0_CS_1_BANK_SIZE 0xd08
#define MV64340_PCI_1_CS_1_BANK_SIZE 0xd88
#define MV64340_PCI_0_CS_2_BANK_SIZE 0xc0c
#define MV64340_PCI_1_CS_2_BANK_SIZE 0xc8c
#define MV64340_PCI_0_CS_3_BANK_SIZE 0xd0c
#define MV64340_PCI_1_CS_3_BANK_SIZE 0xd8c
#define MV64340_PCI_0_DEVCS_0_BANK_SIZE 0xc10
#define MV64340_PCI_1_DEVCS_0_BANK_SIZE 0xc90
#define MV64340_PCI_0_DEVCS_1_BANK_SIZE 0xd10
#define MV64340_PCI_1_DEVCS_1_BANK_SIZE 0xd90
#define MV64340_PCI_0_DEVCS_2_BANK_SIZE 0xd18
#define MV64340_PCI_1_DEVCS_2_BANK_SIZE 0xd98
#define MV64340_PCI_0_DEVCS_3_BANK_SIZE 0xc14
#define MV64340_PCI_1_DEVCS_3_BANK_SIZE 0xc94
#define MV64340_PCI_0_DEVCS_BOOT_BANK_SIZE 0xd14
#define MV64340_PCI_1_DEVCS_BOOT_BANK_SIZE 0xd94
#define MV64340_PCI_0_P2P_MEM0_BAR_SIZE 0xd1c
#define MV64340_PCI_1_P2P_MEM0_BAR_SIZE 0xd9c
#define MV64340_PCI_0_P2P_MEM1_BAR_SIZE 0xd20
#define MV64340_PCI_1_P2P_MEM1_BAR_SIZE 0xda0
#define MV64340_PCI_0_P2P_I_O_BAR_SIZE 0xd24
#define MV64340_PCI_1_P2P_I_O_BAR_SIZE 0xda4
#define MV64340_PCI_0_CPU_BAR_SIZE 0xd28
#define MV64340_PCI_1_CPU_BAR_SIZE 0xda8
#define MV64340_PCI_0_INTERNAL_SRAM_BAR_SIZE 0xe00
#define MV64340_PCI_1_INTERNAL_SRAM_BAR_SIZE 0xe80
#define MV64340_PCI_0_EXPANSION_ROM_BAR_SIZE 0xd2c
#define MV64340_PCI_1_EXPANSION_ROM_BAR_SIZE 0xd9c
#define MV64340_PCI_0_BASE_ADDR_REG_ENABLE 0xc3c
#define MV64340_PCI_1_BASE_ADDR_REG_ENABLE 0xcbc
#define MV64340_PCI_0_CS_0_BASE_ADDR_REMAP 0xc48
#define MV64340_PCI_1_CS_0_BASE_ADDR_REMAP 0xcc8
#define MV64340_PCI_0_CS_1_BASE_ADDR_REMAP 0xd48
#define MV64340_PCI_1_CS_1_BASE_ADDR_REMAP 0xdc8
#define MV64340_PCI_0_CS_2_BASE_ADDR_REMAP 0xc4c
#define MV64340_PCI_1_CS_2_BASE_ADDR_REMAP 0xccc
#define MV64340_PCI_0_CS_3_BASE_ADDR_REMAP 0xd4c
#define MV64340_PCI_1_CS_3_BASE_ADDR_REMAP 0xdcc
#define MV64340_PCI_0_CS_0_BASE_HIGH_ADDR_REMAP 0xF04
#define MV64340_PCI_1_CS_0_BASE_HIGH_ADDR_REMAP 0xF84
#define MV64340_PCI_0_CS_1_BASE_HIGH_ADDR_REMAP 0xF08
#define MV64340_PCI_1_CS_1_BASE_HIGH_ADDR_REMAP 0xF88
#define MV64340_PCI_0_CS_2_BASE_HIGH_ADDR_REMAP 0xF0C
#define MV64340_PCI_1_CS_2_BASE_HIGH_ADDR_REMAP 0xF8C
#define MV64340_PCI_0_CS_3_BASE_HIGH_ADDR_REMAP 0xF10
#define MV64340_PCI_1_CS_3_BASE_HIGH_ADDR_REMAP 0xF90
#define MV64340_PCI_0_DEVCS_0_BASE_ADDR_REMAP 0xc50
#define MV64340_PCI_1_DEVCS_0_BASE_ADDR_REMAP 0xcd0
#define MV64340_PCI_0_DEVCS_1_BASE_ADDR_REMAP 0xd50
#define MV64340_PCI_1_DEVCS_1_BASE_ADDR_REMAP 0xdd0
#define MV64340_PCI_0_DEVCS_2_BASE_ADDR_REMAP 0xd58
#define MV64340_PCI_1_DEVCS_2_BASE_ADDR_REMAP 0xdd8
#define MV64340_PCI_0_DEVCS_3_BASE_ADDR_REMAP 0xc54
#define MV64340_PCI_1_DEVCS_3_BASE_ADDR_REMAP 0xcd4
#define MV64340_PCI_0_DEVCS_BOOTCS_BASE_ADDR_REMAP 0xd54
#define MV64340_PCI_1_DEVCS_BOOTCS_BASE_ADDR_REMAP 0xdd4
#define MV64340_PCI_0_P2P_MEM0_BASE_ADDR_REMAP_LOW 0xd5c
#define MV64340_PCI_1_P2P_MEM0_BASE_ADDR_REMAP_LOW 0xddc
#define MV64340_PCI_0_P2P_MEM0_BASE_ADDR_REMAP_HIGH 0xd60
#define MV64340_PCI_1_P2P_MEM0_BASE_ADDR_REMAP_HIGH 0xde0
#define MV64340_PCI_0_P2P_MEM1_BASE_ADDR_REMAP_LOW 0xd64
#define MV64340_PCI_1_P2P_MEM1_BASE_ADDR_REMAP_LOW 0xde4
#define MV64340_PCI_0_P2P_MEM1_BASE_ADDR_REMAP_HIGH 0xd68
#define MV64340_PCI_1_P2P_MEM1_BASE_ADDR_REMAP_HIGH 0xde8
#define MV64340_PCI_0_P2P_I_O_BASE_ADDR_REMAP 0xd6c
#define MV64340_PCI_1_P2P_I_O_BASE_ADDR_REMAP 0xdec
#define MV64340_PCI_0_CPU_BASE_ADDR_REMAP_LOW 0xd70
#define MV64340_PCI_1_CPU_BASE_ADDR_REMAP_LOW 0xdf0
#define MV64340_PCI_0_CPU_BASE_ADDR_REMAP_HIGH 0xd74
#define MV64340_PCI_1_CPU_BASE_ADDR_REMAP_HIGH 0xdf4
#define MV64340_PCI_0_INTEGRATED_SRAM_BASE_ADDR_REMAP 0xf00
#define MV64340_PCI_1_INTEGRATED_SRAM_BASE_ADDR_REMAP 0xf80
#define MV64340_PCI_0_EXPANSION_ROM_BASE_ADDR_REMAP 0xf38
#define MV64340_PCI_1_EXPANSION_ROM_BASE_ADDR_REMAP 0xfb8
#define MV64340_PCI_0_ADDR_DECODE_CONTROL 0xd3c
#define MV64340_PCI_1_ADDR_DECODE_CONTROL 0xdbc
#define MV64340_PCI_0_HEADERS_RETARGET_CONTROL 0xF40
#define MV64340_PCI_1_HEADERS_RETARGET_CONTROL 0xFc0
#define MV64340_PCI_0_HEADERS_RETARGET_BASE 0xF44
#define MV64340_PCI_1_HEADERS_RETARGET_BASE 0xFc4
#define MV64340_PCI_0_HEADERS_RETARGET_HIGH 0xF48
#define MV64340_PCI_1_HEADERS_RETARGET_HIGH 0xFc8
/***********************************/
/* PCI Control Register Map */
/***********************************/
#define MV64340_PCI_0_DLL_STATUS_AND_COMMAND 0x1d20
#define MV64340_PCI_1_DLL_STATUS_AND_COMMAND 0x1da0
#define MV64340_PCI_0_MPP_PADS_DRIVE_CONTROL 0x1d1C
#define MV64340_PCI_1_MPP_PADS_DRIVE_CONTROL 0x1d9C
#define MV64340_PCI_0_COMMAND 0xc00
#define MV64340_PCI_1_COMMAND 0xc80
#define MV64340_PCI_0_MODE 0xd00
#define MV64340_PCI_1_MODE 0xd80
#define MV64340_PCI_0_RETRY 0xc04
#define MV64340_PCI_1_RETRY 0xc84
#define MV64340_PCI_0_READ_BUFFER_DISCARD_TIMER 0xd04
#define MV64340_PCI_1_READ_BUFFER_DISCARD_TIMER 0xd84
#define MV64340_PCI_0_MSI_TRIGGER_TIMER 0xc38
#define MV64340_PCI_1_MSI_TRIGGER_TIMER 0xcb8
#define MV64340_PCI_0_ARBITER_CONTROL 0x1d00
#define MV64340_PCI_1_ARBITER_CONTROL 0x1d80
#define MV64340_PCI_0_CROSS_BAR_CONTROL_LOW 0x1d08
#define MV64340_PCI_1_CROSS_BAR_CONTROL_LOW 0x1d88
#define MV64340_PCI_0_CROSS_BAR_CONTROL_HIGH 0x1d0c
#define MV64340_PCI_1_CROSS_BAR_CONTROL_HIGH 0x1d8c
#define MV64340_PCI_0_CROSS_BAR_TIMEOUT 0x1d04
#define MV64340_PCI_1_CROSS_BAR_TIMEOUT 0x1d84
#define MV64340_PCI_0_SYNC_BARRIER_TRIGGER_REG 0x1D18
#define MV64340_PCI_1_SYNC_BARRIER_TRIGGER_REG 0x1D98
#define MV64340_PCI_0_SYNC_BARRIER_VIRTUAL_REG 0x1d10
#define MV64340_PCI_1_SYNC_BARRIER_VIRTUAL_REG 0x1d90
#define MV64340_PCI_0_P2P_CONFIG 0x1d14
#define MV64340_PCI_1_P2P_CONFIG 0x1d94
#define MV64340_PCI_0_ACCESS_CONTROL_BASE_0_LOW 0x1e00
#define MV64340_PCI_0_ACCESS_CONTROL_BASE_0_HIGH 0x1e04
#define MV64340_PCI_0_ACCESS_CONTROL_SIZE_0 0x1e08
#define MV64340_PCI_0_ACCESS_CONTROL_BASE_1_LOW 0x1e10
#define MV64340_PCI_0_ACCESS_CONTROL_BASE_1_HIGH 0x1e14
#define MV64340_PCI_0_ACCESS_CONTROL_SIZE_1 0x1e18
#define MV64340_PCI_0_ACCESS_CONTROL_BASE_2_LOW 0x1e20
#define MV64340_PCI_0_ACCESS_CONTROL_BASE_2_HIGH 0x1e24
#define MV64340_PCI_0_ACCESS_CONTROL_SIZE_2 0x1e28
#define MV64340_PCI_0_ACCESS_CONTROL_BASE_3_LOW 0x1e30
#define MV64340_PCI_0_ACCESS_CONTROL_BASE_3_HIGH 0x1e34
#define MV64340_PCI_0_ACCESS_CONTROL_SIZE_3 0x1e38
#define MV64340_PCI_0_ACCESS_CONTROL_BASE_4_LOW 0x1e40
#define MV64340_PCI_0_ACCESS_CONTROL_BASE_4_HIGH 0x1e44
#define MV64340_PCI_0_ACCESS_CONTROL_SIZE_4 0x1e48
#define MV64340_PCI_0_ACCESS_CONTROL_BASE_5_LOW 0x1e50
#define MV64340_PCI_0_ACCESS_CONTROL_BASE_5_HIGH 0x1e54
#define MV64340_PCI_0_ACCESS_CONTROL_SIZE_5 0x1e58
#define MV64340_PCI_1_ACCESS_CONTROL_BASE_0_LOW 0x1e80
#define MV64340_PCI_1_ACCESS_CONTROL_BASE_0_HIGH 0x1e84
#define MV64340_PCI_1_ACCESS_CONTROL_SIZE_0 0x1e88
#define MV64340_PCI_1_ACCESS_CONTROL_BASE_1_LOW 0x1e90
#define MV64340_PCI_1_ACCESS_CONTROL_BASE_1_HIGH 0x1e94
#define MV64340_PCI_1_ACCESS_CONTROL_SIZE_1 0x1e98
#define MV64340_PCI_1_ACCESS_CONTROL_BASE_2_LOW 0x1ea0
#define MV64340_PCI_1_ACCESS_CONTROL_BASE_2_HIGH 0x1ea4
#define MV64340_PCI_1_ACCESS_CONTROL_SIZE_2 0x1ea8
#define MV64340_PCI_1_ACCESS_CONTROL_BASE_3_LOW 0x1eb0
#define MV64340_PCI_1_ACCESS_CONTROL_BASE_3_HIGH 0x1eb4
#define MV64340_PCI_1_ACCESS_CONTROL_SIZE_3 0x1eb8
#define MV64340_PCI_1_ACCESS_CONTROL_BASE_4_LOW 0x1ec0
#define MV64340_PCI_1_ACCESS_CONTROL_BASE_4_HIGH 0x1ec4
#define MV64340_PCI_1_ACCESS_CONTROL_SIZE_4 0x1ec8
#define MV64340_PCI_1_ACCESS_CONTROL_BASE_5_LOW 0x1ed0
#define MV64340_PCI_1_ACCESS_CONTROL_BASE_5_HIGH 0x1ed4
#define MV64340_PCI_1_ACCESS_CONTROL_SIZE_5 0x1ed8
/****************************************/
/* PCI Configuration Access Registers */
/****************************************/
#define MV64340_PCI_0_CONFIG_ADDR 0xcf8
#define MV64340_PCI_0_CONFIG_DATA_VIRTUAL_REG 0xcfc
#define MV64340_PCI_1_CONFIG_ADDR 0xc78
#define MV64340_PCI_1_CONFIG_DATA_VIRTUAL_REG 0xc7c
#define MV64340_PCI_0_INTERRUPT_ACKNOWLEDGE_VIRTUAL_REG 0xc34
#define MV64340_PCI_1_INTERRUPT_ACKNOWLEDGE_VIRTUAL_REG 0xcb4
/****************************************/
/* PCI Error Report Registers */
/****************************************/
#define MV64340_PCI_0_SERR_MASK 0xc28
#define MV64340_PCI_1_SERR_MASK 0xca8
#define MV64340_PCI_0_ERROR_ADDR_LOW 0x1d40
#define MV64340_PCI_1_ERROR_ADDR_LOW 0x1dc0
#define MV64340_PCI_0_ERROR_ADDR_HIGH 0x1d44
#define MV64340_PCI_1_ERROR_ADDR_HIGH 0x1dc4
#define MV64340_PCI_0_ERROR_ATTRIBUTE 0x1d48
#define MV64340_PCI_1_ERROR_ATTRIBUTE 0x1dc8
#define MV64340_PCI_0_ERROR_COMMAND 0x1d50
#define MV64340_PCI_1_ERROR_COMMAND 0x1dd0
#define MV64340_PCI_0_ERROR_CAUSE 0x1d58
#define MV64340_PCI_1_ERROR_CAUSE 0x1dd8
#define MV64340_PCI_0_ERROR_MASK 0x1d5c
#define MV64340_PCI_1_ERROR_MASK 0x1ddc
/****************************************/
/* PCI Debug Registers */
/****************************************/
#define MV64340_PCI_0_MMASK 0X1D24
#define MV64340_PCI_1_MMASK 0X1DA4
/*********************************************/
/* PCI Configuration, Function 0, Registers */
/*********************************************/
#define MV64340_PCI_DEVICE_AND_VENDOR_ID 0x000
#define MV64340_PCI_STATUS_AND_COMMAND 0x004
#define MV64340_PCI_CLASS_CODE_AND_REVISION_ID 0x008
#define MV64340_PCI_BIST_HEADER_TYPE_LATENCY_TIMER_CACHE_LINE 0x00C
#define MV64340_PCI_SCS_0_BASE_ADDR_LOW 0x010
#define MV64340_PCI_SCS_0_BASE_ADDR_HIGH 0x014
#define MV64340_PCI_SCS_1_BASE_ADDR_LOW 0x018
#define MV64340_PCI_SCS_1_BASE_ADDR_HIGH 0x01C
#define MV64340_PCI_INTERNAL_REG_MEM_MAPPED_BASE_ADDR_LOW 0x020
#define MV64340_PCI_INTERNAL_REG_MEM_MAPPED_BASE_ADDR_HIGH 0x024
#define MV64340_PCI_SUBSYSTEM_ID_AND_SUBSYSTEM_VENDOR_ID 0x02c
#define MV64340_PCI_EXPANSION_ROM_BASE_ADDR_REG 0x030
#define MV64340_PCI_CAPABILTY_LIST_POINTER 0x034
#define MV64340_PCI_INTERRUPT_PIN_AND_LINE 0x03C
/* capability list */
#define MV64340_PCI_POWER_MANAGEMENT_CAPABILITY 0x040
#define MV64340_PCI_POWER_MANAGEMENT_STATUS_AND_CONTROL 0x044
#define MV64340_PCI_VPD_ADDR 0x048
#define MV64340_PCI_VPD_DATA 0x04c
#define MV64340_PCI_MSI_MESSAGE_CONTROL 0x050
#define MV64340_PCI_MSI_MESSAGE_ADDR 0x054
#define MV64340_PCI_MSI_MESSAGE_UPPER_ADDR 0x058
#define MV64340_PCI_MSI_MESSAGE_DATA 0x05c
#define MV64340_PCI_X_COMMAND 0x060
#define MV64340_PCI_X_STATUS 0x064
#define MV64340_PCI_COMPACT_PCI_HOT_SWAP 0x068
/***********************************************/
/* PCI Configuration, Function 1, Registers */
/***********************************************/
#define MV64340_PCI_SCS_2_BASE_ADDR_LOW 0x110
#define MV64340_PCI_SCS_2_BASE_ADDR_HIGH 0x114
#define MV64340_PCI_SCS_3_BASE_ADDR_LOW 0x118
#define MV64340_PCI_SCS_3_BASE_ADDR_HIGH 0x11c
#define MV64340_PCI_INTERNAL_SRAM_BASE_ADDR_LOW 0x120
#define MV64340_PCI_INTERNAL_SRAM_BASE_ADDR_HIGH 0x124
/***********************************************/
/* PCI Configuration, Function 2, Registers */
/***********************************************/
#define MV64340_PCI_DEVCS_0_BASE_ADDR_LOW 0x210
#define MV64340_PCI_DEVCS_0_BASE_ADDR_HIGH 0x214
#define MV64340_PCI_DEVCS_1_BASE_ADDR_LOW 0x218
#define MV64340_PCI_DEVCS_1_BASE_ADDR_HIGH 0x21c
#define MV64340_PCI_DEVCS_2_BASE_ADDR_LOW 0x220
#define MV64340_PCI_DEVCS_2_BASE_ADDR_HIGH 0x224
/***********************************************/
/* PCI Configuration, Function 3, Registers */
/***********************************************/
#define MV64340_PCI_DEVCS_3_BASE_ADDR_LOW 0x310
#define MV64340_PCI_DEVCS_3_BASE_ADDR_HIGH 0x314
#define MV64340_PCI_BOOT_CS_BASE_ADDR_LOW 0x318
#define MV64340_PCI_BOOT_CS_BASE_ADDR_HIGH 0x31c
#define MV64340_PCI_CPU_BASE_ADDR_LOW 0x220
#define MV64340_PCI_CPU_BASE_ADDR_HIGH 0x224
/***********************************************/
/* PCI Configuration, Function 4, Registers */
/***********************************************/
#define MV64340_PCI_P2P_MEM0_BASE_ADDR_LOW 0x410
#define MV64340_PCI_P2P_MEM0_BASE_ADDR_HIGH 0x414
#define MV64340_PCI_P2P_MEM1_BASE_ADDR_LOW 0x418
#define MV64340_PCI_P2P_MEM1_BASE_ADDR_HIGH 0x41c
#define MV64340_PCI_P2P_I_O_BASE_ADDR 0x420
#define MV64340_PCI_INTERNAL_REGS_I_O_MAPPED_BASE_ADDR 0x424
/****************************************/
/* Messaging Unit Registers (I20) */
/****************************************/
#define MV64340_I2O_INBOUND_MESSAGE_REG0_PCI_0_SIDE 0x010
#define MV64340_I2O_INBOUND_MESSAGE_REG1_PCI_0_SIDE 0x014
#define MV64340_I2O_OUTBOUND_MESSAGE_REG0_PCI_0_SIDE 0x018
#define MV64340_I2O_OUTBOUND_MESSAGE_REG1_PCI_0_SIDE 0x01C
#define MV64340_I2O_INBOUND_DOORBELL_REG_PCI_0_SIDE 0x020
#define MV64340_I2O_INBOUND_INTERRUPT_CAUSE_REG_PCI_0_SIDE 0x024
#define MV64340_I2O_INBOUND_INTERRUPT_MASK_REG_PCI_0_SIDE 0x028
#define MV64340_I2O_OUTBOUND_DOORBELL_REG_PCI_0_SIDE 0x02C
#define MV64340_I2O_OUTBOUND_INTERRUPT_CAUSE_REG_PCI_0_SIDE 0x030
#define MV64340_I2O_OUTBOUND_INTERRUPT_MASK_REG_PCI_0_SIDE 0x034
#define MV64340_I2O_INBOUND_QUEUE_PORT_VIRTUAL_REG_PCI_0_SIDE 0x040
#define MV64340_I2O_OUTBOUND_QUEUE_PORT_VIRTUAL_REG_PCI_0_SIDE 0x044
#define MV64340_I2O_QUEUE_CONTROL_REG_PCI_0_SIDE 0x050
#define MV64340_I2O_QUEUE_BASE_ADDR_REG_PCI_0_SIDE 0x054
#define MV64340_I2O_INBOUND_FREE_HEAD_POINTER_REG_PCI_0_SIDE 0x060
#define MV64340_I2O_INBOUND_FREE_TAIL_POINTER_REG_PCI_0_SIDE 0x064
#define MV64340_I2O_INBOUND_POST_HEAD_POINTER_REG_PCI_0_SIDE 0x068
#define MV64340_I2O_INBOUND_POST_TAIL_POINTER_REG_PCI_0_SIDE 0x06C
#define MV64340_I2O_OUTBOUND_FREE_HEAD_POINTER_REG_PCI_0_SIDE 0x070
#define MV64340_I2O_OUTBOUND_FREE_TAIL_POINTER_REG_PCI_0_SIDE 0x074
#define MV64340_I2O_OUTBOUND_POST_HEAD_POINTER_REG_PCI_0_SIDE 0x0F8
#define MV64340_I2O_OUTBOUND_POST_TAIL_POINTER_REG_PCI_0_SIDE 0x0FC
#define MV64340_I2O_INBOUND_MESSAGE_REG0_PCI_1_SIDE 0x090
#define MV64340_I2O_INBOUND_MESSAGE_REG1_PCI_1_SIDE 0x094
#define MV64340_I2O_OUTBOUND_MESSAGE_REG0_PCI_1_SIDE 0x098
#define MV64340_I2O_OUTBOUND_MESSAGE_REG1_PCI_1_SIDE 0x09C
#define MV64340_I2O_INBOUND_DOORBELL_REG_PCI_1_SIDE 0x0A0
#define MV64340_I2O_INBOUND_INTERRUPT_CAUSE_REG_PCI_1_SIDE 0x0A4
#define MV64340_I2O_INBOUND_INTERRUPT_MASK_REG_PCI_1_SIDE 0x0A8
#define MV64340_I2O_OUTBOUND_DOORBELL_REG_PCI_1_SIDE 0x0AC
#define MV64340_I2O_OUTBOUND_INTERRUPT_CAUSE_REG_PCI_1_SIDE 0x0B0
#define MV64340_I2O_OUTBOUND_INTERRUPT_MASK_REG_PCI_1_SIDE 0x0B4
#define MV64340_I2O_INBOUND_QUEUE_PORT_VIRTUAL_REG_PCI_1_SIDE 0x0C0
#define MV64340_I2O_OUTBOUND_QUEUE_PORT_VIRTUAL_REG_PCI_1_SIDE 0x0C4
#define MV64340_I2O_QUEUE_CONTROL_REG_PCI_1_SIDE 0x0D0
#define MV64340_I2O_QUEUE_BASE_ADDR_REG_PCI_1_SIDE 0x0D4
#define MV64340_I2O_INBOUND_FREE_HEAD_POINTER_REG_PCI_1_SIDE 0x0E0
#define MV64340_I2O_INBOUND_FREE_TAIL_POINTER_REG_PCI_1_SIDE 0x0E4
#define MV64340_I2O_INBOUND_POST_HEAD_POINTER_REG_PCI_1_SIDE 0x0E8
#define MV64340_I2O_INBOUND_POST_TAIL_POINTER_REG_PCI_1_SIDE 0x0EC
#define MV64340_I2O_OUTBOUND_FREE_HEAD_POINTER_REG_PCI_1_SIDE 0x0F0
#define MV64340_I2O_OUTBOUND_FREE_TAIL_POINTER_REG_PCI_1_SIDE 0x0F4
#define MV64340_I2O_OUTBOUND_POST_HEAD_POINTER_REG_PCI_1_SIDE 0x078
#define MV64340_I2O_OUTBOUND_POST_TAIL_POINTER_REG_PCI_1_SIDE 0x07C
#define MV64340_I2O_INBOUND_MESSAGE_REG0_CPU0_SIDE 0x1C10
#define MV64340_I2O_INBOUND_MESSAGE_REG1_CPU0_SIDE 0x1C14
#define MV64340_I2O_OUTBOUND_MESSAGE_REG0_CPU0_SIDE 0x1C18
#define MV64340_I2O_OUTBOUND_MESSAGE_REG1_CPU0_SIDE 0x1C1C
#define MV64340_I2O_INBOUND_DOORBELL_REG_CPU0_SIDE 0x1C20
#define MV64340_I2O_INBOUND_INTERRUPT_CAUSE_REG_CPU0_SIDE 0x1C24
#define MV64340_I2O_INBOUND_INTERRUPT_MASK_REG_CPU0_SIDE 0x1C28
#define MV64340_I2O_OUTBOUND_DOORBELL_REG_CPU0_SIDE 0x1C2C
#define MV64340_I2O_OUTBOUND_INTERRUPT_CAUSE_REG_CPU0_SIDE 0x1C30
#define MV64340_I2O_OUTBOUND_INTERRUPT_MASK_REG_CPU0_SIDE 0x1C34
#define MV64340_I2O_INBOUND_QUEUE_PORT_VIRTUAL_REG_CPU0_SIDE 0x1C40
#define MV64340_I2O_OUTBOUND_QUEUE_PORT_VIRTUAL_REG_CPU0_SIDE 0x1C44
#define MV64340_I2O_QUEUE_CONTROL_REG_CPU0_SIDE 0x1C50
#define MV64340_I2O_QUEUE_BASE_ADDR_REG_CPU0_SIDE 0x1C54
#define MV64340_I2O_INBOUND_FREE_HEAD_POINTER_REG_CPU0_SIDE 0x1C60
#define MV64340_I2O_INBOUND_FREE_TAIL_POINTER_REG_CPU0_SIDE 0x1C64
#define MV64340_I2O_INBOUND_POST_HEAD_POINTER_REG_CPU0_SIDE 0x1C68
#define MV64340_I2O_INBOUND_POST_TAIL_POINTER_REG_CPU0_SIDE 0x1C6C
#define MV64340_I2O_OUTBOUND_FREE_HEAD_POINTER_REG_CPU0_SIDE 0x1C70
#define MV64340_I2O_OUTBOUND_FREE_TAIL_POINTER_REG_CPU0_SIDE 0x1C74
#define MV64340_I2O_OUTBOUND_POST_HEAD_POINTER_REG_CPU0_SIDE 0x1CF8
#define MV64340_I2O_OUTBOUND_POST_TAIL_POINTER_REG_CPU0_SIDE 0x1CFC
#define MV64340_I2O_INBOUND_MESSAGE_REG0_CPU1_SIDE 0x1C90
#define MV64340_I2O_INBOUND_MESSAGE_REG1_CPU1_SIDE 0x1C94
#define MV64340_I2O_OUTBOUND_MESSAGE_REG0_CPU1_SIDE 0x1C98
#define MV64340_I2O_OUTBOUND_MESSAGE_REG1_CPU1_SIDE 0x1C9C
#define MV64340_I2O_INBOUND_DOORBELL_REG_CPU1_SIDE 0x1CA0
#define MV64340_I2O_INBOUND_INTERRUPT_CAUSE_REG_CPU1_SIDE 0x1CA4
#define MV64340_I2O_INBOUND_INTERRUPT_MASK_REG_CPU1_SIDE 0x1CA8
#define MV64340_I2O_OUTBOUND_DOORBELL_REG_CPU1_SIDE 0x1CAC
#define MV64340_I2O_OUTBOUND_INTERRUPT_CAUSE_REG_CPU1_SIDE 0x1CB0
#define MV64340_I2O_OUTBOUND_INTERRUPT_MASK_REG_CPU1_SIDE 0x1CB4
#define MV64340_I2O_INBOUND_QUEUE_PORT_VIRTUAL_REG_CPU1_SIDE 0x1CC0
#define MV64340_I2O_OUTBOUND_QUEUE_PORT_VIRTUAL_REG_CPU1_SIDE 0x1CC4
#define MV64340_I2O_QUEUE_CONTROL_REG_CPU1_SIDE 0x1CD0
#define MV64340_I2O_QUEUE_BASE_ADDR_REG_CPU1_SIDE 0x1CD4
#define MV64340_I2O_INBOUND_FREE_HEAD_POINTER_REG_CPU1_SIDE 0x1CE0
#define MV64340_I2O_INBOUND_FREE_TAIL_POINTER_REG_CPU1_SIDE 0x1CE4
#define MV64340_I2O_INBOUND_POST_HEAD_POINTER_REG_CPU1_SIDE 0x1CE8
#define MV64340_I2O_INBOUND_POST_TAIL_POINTER_REG_CPU1_SIDE 0x1CEC
#define MV64340_I2O_OUTBOUND_FREE_HEAD_POINTER_REG_CPU1_SIDE 0x1CF0
#define MV64340_I2O_OUTBOUND_FREE_TAIL_POINTER_REG_CPU1_SIDE 0x1CF4
#define MV64340_I2O_OUTBOUND_POST_HEAD_POINTER_REG_CPU1_SIDE 0x1C78
#define MV64340_I2O_OUTBOUND_POST_TAIL_POINTER_REG_CPU1_SIDE 0x1C7C
/****************************************/
/* Ethernet Unit Registers */
/****************************************/
/*******************************************/
/* CUNIT Registers */
/*******************************************/
/* Address Decoding Register Map */
#define MV64340_CUNIT_BASE_ADDR_REG0 0xf200
#define MV64340_CUNIT_BASE_ADDR_REG1 0xf208
#define MV64340_CUNIT_BASE_ADDR_REG2 0xf210
#define MV64340_CUNIT_BASE_ADDR_REG3 0xf218
#define MV64340_CUNIT_SIZE0 0xf204
#define MV64340_CUNIT_SIZE1 0xf20c
#define MV64340_CUNIT_SIZE2 0xf214
#define MV64340_CUNIT_SIZE3 0xf21c
#define MV64340_CUNIT_HIGH_ADDR_REMAP_REG0 0xf240
#define MV64340_CUNIT_HIGH_ADDR_REMAP_REG1 0xf244
#define MV64340_CUNIT_BASE_ADDR_ENABLE_REG 0xf250
#define MV64340_MPSC0_ACCESS_PROTECTION_REG 0xf254
#define MV64340_MPSC1_ACCESS_PROTECTION_REG 0xf258
#define MV64340_CUNIT_INTERNAL_SPACE_BASE_ADDR_REG 0xf25C
/* Error Report Registers */
#define MV64340_CUNIT_INTERRUPT_CAUSE_REG 0xf310
#define MV64340_CUNIT_INTERRUPT_MASK_REG 0xf314
#define MV64340_CUNIT_ERROR_ADDR 0xf318
/* Cunit Control Registers */
#define MV64340_CUNIT_ARBITER_CONTROL_REG 0xf300
#define MV64340_CUNIT_CONFIG_REG 0xb40c
#define MV64340_CUNIT_CRROSBAR_TIMEOUT_REG 0xf304
/* Cunit Debug Registers */
#define MV64340_CUNIT_DEBUG_LOW 0xf340
#define MV64340_CUNIT_DEBUG_HIGH 0xf344
#define MV64340_CUNIT_MMASK 0xf380
/* MPSCs Clocks Routing Registers */
#define MV64340_MPSC_ROUTING_REG 0xb400
#define MV64340_MPSC_RX_CLOCK_ROUTING_REG 0xb404
#define MV64340_MPSC_TX_CLOCK_ROUTING_REG 0xb408
/* MPSCs Interrupts Registers */
#define MV64340_MPSC_CAUSE_REG(port) (0xb804 + (port << 3))
#define MV64340_MPSC_MASK_REG(port) (0xb884 + (port << 3))
#define MV64340_MPSC_MAIN_CONFIG_LOW(port) (0x8000 + (port << 12))
#define MV64340_MPSC_MAIN_CONFIG_HIGH(port) (0x8004 + (port << 12))
#define MV64340_MPSC_PROTOCOL_CONFIG(port) (0x8008 + (port << 12))
#define MV64340_MPSC_CHANNEL_REG1(port) (0x800c + (port << 12))
#define MV64340_MPSC_CHANNEL_REG2(port) (0x8010 + (port << 12))
#define MV64340_MPSC_CHANNEL_REG3(port) (0x8014 + (port << 12))
#define MV64340_MPSC_CHANNEL_REG4(port) (0x8018 + (port << 12))
#define MV64340_MPSC_CHANNEL_REG5(port) (0x801c + (port << 12))
#define MV64340_MPSC_CHANNEL_REG6(port) (0x8020 + (port << 12))
#define MV64340_MPSC_CHANNEL_REG7(port) (0x8024 + (port << 12))
#define MV64340_MPSC_CHANNEL_REG8(port) (0x8028 + (port << 12))
#define MV64340_MPSC_CHANNEL_REG9(port) (0x802c + (port << 12))
#define MV64340_MPSC_CHANNEL_REG10(port) (0x8030 + (port << 12))
/* MPSC0 Registers */
/***************************************/
/* SDMA Registers */
/***************************************/
#define MV64340_SDMA_CONFIG_REG(channel) (0x4000 + (channel << 13))
#define MV64340_SDMA_COMMAND_REG(channel) (0x4008 + (channel << 13))
#define MV64340_SDMA_CURRENT_RX_DESCRIPTOR_POINTER(channel) (0x4810 + (channel << 13))
#define MV64340_SDMA_CURRENT_TX_DESCRIPTOR_POINTER(channel) (0x4c10 + (channel << 13))
#define MV64340_SDMA_FIRST_TX_DESCRIPTOR_POINTER(channel) (0x4c14 + (channel << 13))
#define MV64340_SDMA_CAUSE_REG 0xb800
#define MV64340_SDMA_MASK_REG 0xb880
/* BRG Interrupts */
#define MV64340_BRG_CONFIG_REG(brg) (0xb200 + (brg << 3))
#define MV64340_BRG_BAUDE_TUNING_REG(brg) (0xb208 + (brg << 3))
#define MV64340_BRG_CAUSE_REG 0xb834
#define MV64340_BRG_MASK_REG 0xb8b4
/****************************************/
/* DMA Channel Control */
/****************************************/
#define MV64340_DMA_CHANNEL0_CONTROL 0x840
#define MV64340_DMA_CHANNEL0_CONTROL_HIGH 0x880
#define MV64340_DMA_CHANNEL1_CONTROL 0x844
#define MV64340_DMA_CHANNEL1_CONTROL_HIGH 0x884
#define MV64340_DMA_CHANNEL2_CONTROL 0x848
#define MV64340_DMA_CHANNEL2_CONTROL_HIGH 0x888
#define MV64340_DMA_CHANNEL3_CONTROL 0x84C
#define MV64340_DMA_CHANNEL3_CONTROL_HIGH 0x88C
/****************************************/
/* IDMA Registers */
/****************************************/
#define MV64340_DMA_CHANNEL0_BYTE_COUNT 0x800
#define MV64340_DMA_CHANNEL1_BYTE_COUNT 0x804
#define MV64340_DMA_CHANNEL2_BYTE_COUNT 0x808
#define MV64340_DMA_CHANNEL3_BYTE_COUNT 0x80C
#define MV64340_DMA_CHANNEL0_SOURCE_ADDR 0x810
#define MV64340_DMA_CHANNEL1_SOURCE_ADDR 0x814
#define MV64340_DMA_CHANNEL2_SOURCE_ADDR 0x818
#define MV64340_DMA_CHANNEL3_SOURCE_ADDR 0x81c
#define MV64340_DMA_CHANNEL0_DESTINATION_ADDR 0x820
#define MV64340_DMA_CHANNEL1_DESTINATION_ADDR 0x824
#define MV64340_DMA_CHANNEL2_DESTINATION_ADDR 0x828
#define MV64340_DMA_CHANNEL3_DESTINATION_ADDR 0x82C
#define MV64340_DMA_CHANNEL0_NEXT_DESCRIPTOR_POINTER 0x830
#define MV64340_DMA_CHANNEL1_NEXT_DESCRIPTOR_POINTER 0x834
#define MV64340_DMA_CHANNEL2_NEXT_DESCRIPTOR_POINTER 0x838
#define MV64340_DMA_CHANNEL3_NEXT_DESCRIPTOR_POINTER 0x83C
#define MV64340_DMA_CHANNEL0_CURRENT_DESCRIPTOR_POINTER 0x870
#define MV64340_DMA_CHANNEL1_CURRENT_DESCRIPTOR_POINTER 0x874
#define MV64340_DMA_CHANNEL2_CURRENT_DESCRIPTOR_POINTER 0x878
#define MV64340_DMA_CHANNEL3_CURRENT_DESCRIPTOR_POINTER 0x87C
/* IDMA Address Decoding Base Address Registers */
#define MV64340_DMA_BASE_ADDR_REG0 0xa00
#define MV64340_DMA_BASE_ADDR_REG1 0xa08
#define MV64340_DMA_BASE_ADDR_REG2 0xa10
#define MV64340_DMA_BASE_ADDR_REG3 0xa18
#define MV64340_DMA_BASE_ADDR_REG4 0xa20
#define MV64340_DMA_BASE_ADDR_REG5 0xa28
#define MV64340_DMA_BASE_ADDR_REG6 0xa30
#define MV64340_DMA_BASE_ADDR_REG7 0xa38
/* IDMA Address Decoding Size Address Register */
#define MV64340_DMA_SIZE_REG0 0xa04
#define MV64340_DMA_SIZE_REG1 0xa0c
#define MV64340_DMA_SIZE_REG2 0xa14
#define MV64340_DMA_SIZE_REG3 0xa1c
#define MV64340_DMA_SIZE_REG4 0xa24
#define MV64340_DMA_SIZE_REG5 0xa2c
#define MV64340_DMA_SIZE_REG6 0xa34
#define MV64340_DMA_SIZE_REG7 0xa3C
/* IDMA Address Decoding High Address Remap and Access Protection Registers */
#define MV64340_DMA_HIGH_ADDR_REMAP_REG0 0xa60
#define MV64340_DMA_HIGH_ADDR_REMAP_REG1 0xa64
#define MV64340_DMA_HIGH_ADDR_REMAP_REG2 0xa68
#define MV64340_DMA_HIGH_ADDR_REMAP_REG3 0xa6C
#define MV64340_DMA_BASE_ADDR_ENABLE_REG 0xa80
#define MV64340_DMA_CHANNEL0_ACCESS_PROTECTION_REG 0xa70
#define MV64340_DMA_CHANNEL1_ACCESS_PROTECTION_REG 0xa74
#define MV64340_DMA_CHANNEL2_ACCESS_PROTECTION_REG 0xa78
#define MV64340_DMA_CHANNEL3_ACCESS_PROTECTION_REG 0xa7c
#define MV64340_DMA_ARBITER_CONTROL 0x860
#define MV64340_DMA_CROSS_BAR_TIMEOUT 0x8d0
/* IDMA Headers Retarget Registers */
#define MV64340_DMA_HEADERS_RETARGET_CONTROL 0xa84
#define MV64340_DMA_HEADERS_RETARGET_BASE 0xa88
/* IDMA Interrupt Register */
#define MV64340_DMA_INTERRUPT_CAUSE_REG 0x8c0
#define MV64340_DMA_INTERRUPT_CAUSE_MASK 0x8c4
#define MV64340_DMA_ERROR_ADDR 0x8c8
#define MV64340_DMA_ERROR_SELECT 0x8cc
/* IDMA Debug Register ( for internal use ) */
#define MV64340_DMA_DEBUG_LOW 0x8e0
#define MV64340_DMA_DEBUG_HIGH 0x8e4
#define MV64340_DMA_SPARE 0xA8C
/****************************************/
/* Timer_Counter */
/****************************************/
#define MV64340_TIMER_COUNTER0 0x850
#define MV64340_TIMER_COUNTER1 0x854
#define MV64340_TIMER_COUNTER2 0x858
#define MV64340_TIMER_COUNTER3 0x85C
#define MV64340_TIMER_COUNTER_0_3_CONTROL 0x864
#define MV64340_TIMER_COUNTER_0_3_INTERRUPT_CAUSE 0x868
#define MV64340_TIMER_COUNTER_0_3_INTERRUPT_MASK 0x86c
/****************************************/
/* Watchdog registers */
/****************************************/
#define MV64340_WATCHDOG_CONFIG_REG 0xb410
#define MV64340_WATCHDOG_VALUE_REG 0xb414
/****************************************/
/* I2C Registers */
/****************************************/
#define MV64XXX_I2C_OFFSET 0xc000
#define MV64XXX_I2C_REG_BLOCK_SIZE 0x0020
/****************************************/
/* GPP Interface Registers */
/****************************************/
#define MV64340_GPP_IO_CONTROL 0xf100
#define MV64340_GPP_LEVEL_CONTROL 0xf110
#define MV64340_GPP_VALUE 0xf104
#define MV64340_GPP_INTERRUPT_CAUSE 0xf108
#define MV64340_GPP_INTERRUPT_MASK0 0xf10c
#define MV64340_GPP_INTERRUPT_MASK1 0xf114
#define MV64340_GPP_VALUE_SET 0xf118
#define MV64340_GPP_VALUE_CLEAR 0xf11c
/****************************************/
/* Interrupt Controller Registers */
/****************************************/
/****************************************/
/* Interrupts */
/****************************************/
#define MV64340_MAIN_INTERRUPT_CAUSE_LOW 0x004
#define MV64340_MAIN_INTERRUPT_CAUSE_HIGH 0x00c
#define MV64340_CPU_INTERRUPT0_MASK_LOW 0x014
#define MV64340_CPU_INTERRUPT0_MASK_HIGH 0x01c
#define MV64340_CPU_INTERRUPT0_SELECT_CAUSE 0x024
#define MV64340_CPU_INTERRUPT1_MASK_LOW 0x034
#define MV64340_CPU_INTERRUPT1_MASK_HIGH 0x03c
#define MV64340_CPU_INTERRUPT1_SELECT_CAUSE 0x044
#define MV64340_INTERRUPT0_MASK_0_LOW 0x054
#define MV64340_INTERRUPT0_MASK_0_HIGH 0x05c
#define MV64340_INTERRUPT0_SELECT_CAUSE 0x064
#define MV64340_INTERRUPT1_MASK_0_LOW 0x074
#define MV64340_INTERRUPT1_MASK_0_HIGH 0x07c
#define MV64340_INTERRUPT1_SELECT_CAUSE 0x084
/****************************************/
/* MPP Interface Registers */
/****************************************/
#define MV64340_MPP_CONTROL0 0xf000
#define MV64340_MPP_CONTROL1 0xf004
#define MV64340_MPP_CONTROL2 0xf008
#define MV64340_MPP_CONTROL3 0xf00c
/****************************************/
/* Serial Initialization registers */
/****************************************/
#define MV64340_SERIAL_INIT_LAST_DATA 0xf324
#define MV64340_SERIAL_INIT_CONTROL 0xf328
#define MV64340_SERIAL_INIT_STATUS 0xf32c
#endif /* ASM_MV643XX_H */

View File

@ -3,6 +3,12 @@
# grackle.c
grackle_set_irq(int irq_num, int level) "set_irq num %d level %d"
# mv64361.c
mv64361_region_map(const char *name, uint64_t poffs, uint64_t size, uint64_t moffs) "Mapping %s 0x%"PRIx64"+0x%"PRIx64" @ 0x%"PRIx64
mv64361_region_enable(const char *op, int num) "Should %s region %d"
mv64361_reg_read(uint64_t addr, uint32_t val) "0x%"PRIx64" -> 0x%x"
mv64361_reg_write(uint64_t addr, uint64_t val) "0x%"PRIx64" <- 0x%"PRIx64
# sabre.c
sabre_set_request(int irq_num) "request irq %d"
sabre_clear_request(int irq_num) "clear request irq %d"

View File

@ -68,6 +68,15 @@ config SAM460EX
select USB_OHCI
select FDT_PPC
config PEGASOS2
bool
select MV64361
select VT82C686
select IDE_VIA
select SMBUS_EEPROM
# This should come with VT82C686
select ACPI_X86
config PREP
bool
imply PCI_DEVICES

View File

@ -155,6 +155,10 @@ static void ppc_core99_init(MachineState *machine)
}
/* allocate RAM */
if (machine->ram_size > 2 * GiB) {
error_report("RAM size more than 2 GiB is not supported");
exit(1);
}
memory_region_add_subregion(get_system_memory(), 0, machine->ram);
/* allocate and load firmware ROM */

View File

@ -78,5 +78,7 @@ ppc_ss.add(when: 'CONFIG_E500', if_true: files(
))
# PowerPC 440 Xilinx ML507 reference board.
ppc_ss.add(when: 'CONFIG_VIRTEX', if_true: files('virtex_ml507.c'))
# Pegasos2
ppc_ss.add(when: 'CONFIG_PEGASOS2', if_true: files('pegasos2.c'))
hw_arch += {'ppc': ppc_ss}

144
hw/ppc/pegasos2.c Normal file
View File

@ -0,0 +1,144 @@
/*
* QEMU PowerPC CHRP (Genesi/bPlan Pegasos II) hardware System Emulator
*
* Copyright (c) 2018-2020 BALATON Zoltan
*
* This work is licensed under the GNU GPL license version 2 or later.
*
*/
#include "qemu/osdep.h"
#include "qemu-common.h"
#include "qemu/units.h"
#include "qapi/error.h"
#include "hw/hw.h"
#include "hw/ppc/ppc.h"
#include "hw/sysbus.h"
#include "hw/pci/pci_host.h"
#include "hw/irq.h"
#include "hw/pci-host/mv64361.h"
#include "hw/isa/vt82c686.h"
#include "hw/ide/pci.h"
#include "hw/i2c/smbus_eeprom.h"
#include "hw/qdev-properties.h"
#include "sysemu/reset.h"
#include "hw/boards.h"
#include "hw/loader.h"
#include "hw/fw-path-provider.h"
#include "elf.h"
#include "qemu/log.h"
#include "qemu/error-report.h"
#include "sysemu/kvm.h"
#include "kvm_ppc.h"
#include "exec/address-spaces.h"
#include "trace.h"
#include "qemu/datadir.h"
#include "sysemu/device_tree.h"
#define PROM_FILENAME "pegasos2.rom"
#define PROM_ADDR 0xfff00000
#define PROM_SIZE 0x80000
#define BUS_FREQ_HZ 133333333
static void pegasos2_cpu_reset(void *opaque)
{
PowerPCCPU *cpu = opaque;
cpu_reset(CPU(cpu));
cpu->env.spr[SPR_HID1] = 7ULL << 28;
}
static void pegasos2_init(MachineState *machine)
{
PowerPCCPU *cpu = NULL;
MemoryRegion *rom = g_new(MemoryRegion, 1);
DeviceState *mv;
PCIBus *pci_bus;
PCIDevice *dev;
I2CBus *i2c_bus;
const char *fwname = machine->firmware ?: PROM_FILENAME;
char *filename;
int sz;
uint8_t *spd_data;
/* init CPU */
cpu = POWERPC_CPU(cpu_create(machine->cpu_type));
if (PPC_INPUT(&cpu->env) != PPC_FLAGS_INPUT_6xx) {
error_report("Incompatible CPU, only 6xx bus supported");
exit(1);
}
/* Set time-base frequency */
cpu_ppc_tb_init(&cpu->env, BUS_FREQ_HZ / 4);
qemu_register_reset(pegasos2_cpu_reset, cpu);
/* RAM */
memory_region_add_subregion(get_system_memory(), 0, machine->ram);
/* allocate and load firmware */
filename = qemu_find_file(QEMU_FILE_TYPE_BIOS, fwname);
if (!filename) {
error_report("Could not find firmware '%s'", fwname);
exit(1);
}
memory_region_init_rom(rom, NULL, "pegasos2.rom", PROM_SIZE, &error_fatal);
memory_region_add_subregion(get_system_memory(), PROM_ADDR, rom);
sz = load_elf(filename, NULL, NULL, NULL, NULL, NULL, NULL, NULL, 1,
PPC_ELF_MACHINE, 0, 0);
if (sz <= 0) {
sz = load_image_targphys(filename, PROM_ADDR, PROM_SIZE);
}
if (sz <= 0 || sz > PROM_SIZE) {
error_report("Could not load firmware '%s'", filename);
exit(1);
}
g_free(filename);
/* Marvell Discovery II system controller */
mv = DEVICE(sysbus_create_simple(TYPE_MV64361, -1,
((qemu_irq *)cpu->env.irq_inputs)[PPC6xx_INPUT_INT]));
pci_bus = mv64361_get_pci_bus(mv, 1);
/* VIA VT8231 South Bridge (multifunction PCI device) */
/* VT8231 function 0: PCI-to-ISA Bridge */
dev = pci_create_simple_multifunction(pci_bus, PCI_DEVFN(12, 0), true,
TYPE_VT8231_ISA);
qdev_connect_gpio_out(DEVICE(dev), 0,
qdev_get_gpio_in_named(mv, "gpp", 31));
/* VT8231 function 1: IDE Controller */
dev = pci_create_simple(pci_bus, PCI_DEVFN(12, 1), "via-ide");
pci_ide_create_devs(dev);
/* VT8231 function 2-3: USB Ports */
pci_create_simple(pci_bus, PCI_DEVFN(12, 2), "vt82c686b-usb-uhci");
pci_create_simple(pci_bus, PCI_DEVFN(12, 3), "vt82c686b-usb-uhci");
/* VT8231 function 4: Power Management Controller */
dev = pci_create_simple(pci_bus, PCI_DEVFN(12, 4), TYPE_VT8231_PM);
i2c_bus = I2C_BUS(qdev_get_child_bus(DEVICE(dev), "i2c"));
spd_data = spd_data_generate(DDR, machine->ram_size);
smbus_eeprom_init_one(i2c_bus, 0x57, spd_data);
/* VT8231 function 5-6: AC97 Audio & Modem */
pci_create_simple(pci_bus, PCI_DEVFN(12, 5), TYPE_VIA_AC97);
pci_create_simple(pci_bus, PCI_DEVFN(12, 6), TYPE_VIA_MC97);
/* other PC hardware */
pci_vga_init(pci_bus);
}
static void pegasos2_machine(MachineClass *mc)
{
mc->desc = "Genesi/bPlan Pegasos II";
mc->init = pegasos2_init;
mc->block_default_type = IF_IDE;
mc->default_boot_order = "cd";
mc->default_display = "std";
mc->default_cpu_type = POWERPC_CPU_TYPE_NAME("7400_v2.9");
mc->default_ram_id = "pegasos2.ram";
mc->default_ram_size = 512 * MiB;
}
DEFINE_MACHINE("pegasos2", pegasos2_machine)

View File

@ -29,6 +29,7 @@
#include "hw/ppc/pnv_xscom.h"
#include "hw/ppc/xics.h"
#include "hw/qdev-properties.h"
#include "helper_regs.h"
static const char *pnv_core_cpu_typename(PnvCore *pc)
{
@ -55,8 +56,8 @@ static void pnv_core_cpu_reset(PnvCore *pc, PowerPCCPU *cpu)
env->gpr[3] = PNV_FDT_ADDR;
env->nip = 0x10;
env->msr |= MSR_HVB; /* Hypervisor mode */
env->spr[SPR_HRMOR] = pc->hrmor;
hreg_compute_hflags(env);
pcc->intc_reset(pc->chip, cpu);
}

View File

@ -465,7 +465,7 @@ static void pnv_psi_reset(DeviceState *dev)
static void pnv_psi_reset_handler(void *dev)
{
device_legacy_reset(DEVICE(dev));
device_cold_reset(DEVICE(dev));
}
static void pnv_psi_realize(DeviceState *dev, Error **errp)
@ -709,7 +709,7 @@ static void pnv_psi_p9_mmio_write(void *opaque, hwaddr addr,
break;
case PSIHB9_INTERRUPT_CONTROL:
if (val & PSIHB9_IRQ_RESET) {
device_legacy_reset(DEVICE(&psi9->source));
device_cold_reset(DEVICE(&psi9->source));
}
psi->regs[reg] = val;
break;

View File

@ -98,7 +98,7 @@
*
* We load our kernel at 4M, leaving space for SLOF initial image
*/
#define RTAS_MAX_ADDR 0x80000000 /* RTAS must stay below that */
#define FDT_MAX_ADDR 0x80000000 /* FDT must stay below that */
#define FW_MAX_SIZE 0x400000
#define FW_FILE_NAME "slof.bin"
#define FW_OVERHEAD 0x2800000
@ -1615,11 +1615,11 @@ static void spapr_machine_reset(MachineState *machine)
spapr_clear_pending_events(spapr);
/*
* We place the device tree and RTAS just below either the top of the RMA,
* We place the device tree just below either the top of the RMA,
* or just below 2GB, whichever is lower, so that it can be
* processed with 32-bit real mode code if necessary
*/
fdt_addr = MIN(spapr->rma_size, RTAS_MAX_ADDR) - FDT_MAX_SIZE;
fdt_addr = MIN(spapr->rma_size, FDT_MAX_ADDR) - FDT_MAX_SIZE;
fdt = spapr_build_fdt(spapr, true, FDT_MAX_SIZE);
@ -2692,7 +2692,7 @@ static void spapr_machine_init(MachineState *machine)
spapr->rma_size = spapr_rma_size(spapr, &error_fatal);
/* Setup a load limit for the ramdisk leaving room for SLOF and FDT */
load_limit = MIN(spapr->rma_size, RTAS_MAX_ADDR) - FW_OVERHEAD;
load_limit = MIN(spapr->rma_size, FDT_MAX_ADDR) - FW_OVERHEAD;
/*
* VSMT must be set in order to be able to compute VCPU ids, ie to
@ -4485,7 +4485,16 @@ static void spapr_machine_class_init(ObjectClass *oc, void *data)
mc->init = spapr_machine_init;
mc->reset = spapr_machine_reset;
mc->block_default_type = IF_SCSI;
mc->max_cpus = 1024;
/*
* Setting max_cpus to INT32_MAX. Both KVM and TCG max_cpus values
* should be limited by the host capability instead of hardcoded.
* max_cpus for KVM guests will be checked in kvm_init(), and TCG
* guests are welcome to have as many CPUs as the host are capable
* of emulate.
*/
mc->max_cpus = INT32_MAX;
mc->no_parallel = 1;
mc->default_boot_order = "";
mc->default_ram_size = 512 * MiB;

View File

@ -150,9 +150,32 @@ static uint32_t drc_isolate_logical(SpaprDrc *drc)
static uint32_t drc_unisolate_logical(SpaprDrc *drc)
{
SpaprMachineState *spapr = NULL;
switch (drc->state) {
case SPAPR_DRC_STATE_LOGICAL_UNISOLATE:
case SPAPR_DRC_STATE_LOGICAL_CONFIGURED:
/*
* Unisolating a logical DRC that was marked for unplug
* means that the kernel is refusing the removal.
*/
if (drc->unplug_requested && drc->dev) {
if (spapr_drc_type(drc) == SPAPR_DR_CONNECTOR_TYPE_LMB) {
spapr = SPAPR_MACHINE(qdev_get_machine());
spapr_memory_unplug_rollback(spapr, drc->dev);
}
drc->unplug_requested = false;
error_report("Device hotunplug rejected by the guest "
"for device %s", drc->dev->id);
/*
* TODO: send a QAPI DEVICE_UNPLUG_ERROR event when
* it is implemented.
*/
}
return RTAS_OUT_SUCCESS; /* Nothing to do */
case SPAPR_DRC_STATE_LOGICAL_AVAILABLE:
break; /* see below */

View File

@ -1394,7 +1394,13 @@ static target_ulong h_set_mode_resource_addr_trans_mode(PowerPCCPU *cpu,
return H_P4;
}
if (mflags == AIL_RESERVED) {
if (mflags == 1) {
/* AIL=1 is reserved in POWER8/POWER9/POWER10 */
return H_UNSUPPORTED_FLAG;
}
if (mflags == 2 && (pcc->insns_flags2 & PPC2_ISA310)) {
/* AIL=2 is reserved in POWER10 (ISA v3.1) */
return H_UNSUPPORTED_FLAG;
}

View File

@ -31,6 +31,10 @@
#include "qemu/range.h"
#include "hw/ppc/spapr_numa.h"
/* DIMM health bitmap bitmap indicators. Taken from kernel's papr_scm.c */
/* SCM device is unable to persist memory contents */
#define PAPR_PMEM_UNARMED PPC_BIT(0)
bool spapr_nvdimm_validate(HotplugHandler *hotplug_dev, NVDIMMDevice *nvdimm,
uint64_t size, Error **errp)
{
@ -467,6 +471,37 @@ static target_ulong h_scm_unbind_all(PowerPCCPU *cpu, SpaprMachineState *spapr,
return H_SUCCESS;
}
static target_ulong h_scm_health(PowerPCCPU *cpu, SpaprMachineState *spapr,
target_ulong opcode, target_ulong *args)
{
NVDIMMDevice *nvdimm;
uint64_t hbitmap = 0;
uint32_t drc_index = args[0];
SpaprDrc *drc = spapr_drc_by_index(drc_index);
const uint64_t hbitmap_mask = PAPR_PMEM_UNARMED;
/* Ensure that the drc is valid & is valid PMEM dimm and is plugged in */
if (!drc || !drc->dev ||
spapr_drc_type(drc) != SPAPR_DR_CONNECTOR_TYPE_PMEM) {
return H_PARAMETER;
}
nvdimm = NVDIMM(drc->dev);
/* Update if the nvdimm is unarmed and send its status via health bitmaps */
if (object_property_get_bool(OBJECT(nvdimm), NVDIMM_UNARMED_PROP, NULL)) {
hbitmap |= PAPR_PMEM_UNARMED;
}
/* Update the out args with health bitmap/mask */
args[0] = hbitmap;
args[1] = hbitmap_mask;
return H_SUCCESS;
}
static void spapr_scm_register_types(void)
{
/* qemu/scm specific hcalls */
@ -475,6 +510,7 @@ static void spapr_scm_register_types(void)
spapr_register_hypercall(H_SCM_BIND_MEM, h_scm_bind_mem);
spapr_register_hypercall(H_SCM_UNBIND_MEM, h_scm_unbind_mem);
spapr_register_hypercall(H_SCM_UNBIND_ALL, h_scm_unbind_all);
spapr_register_hypercall(H_SCM_HEALTH, h_scm_health);
}
type_init(spapr_scm_register_types)

View File

@ -49,6 +49,7 @@
#include "target/ppc/mmu-hash64.h"
#include "target/ppc/mmu-book3s-v3.h"
#include "migration/blocker.h"
#include "helper_regs.h"
static void rtas_display_character(PowerPCCPU *cpu, SpaprMachineState *spapr,
uint32_t token, uint32_t nargs,
@ -161,6 +162,7 @@ static void rtas_start_cpu(PowerPCCPU *callcpu, SpaprMachineState *spapr,
cpu_synchronize_state(CPU(newcpu));
env->msr = (1ULL << MSR_SF) | (1ULL << MSR_ME);
hreg_compute_hflags(env);
/* Enable Power-saving mode Exit Cause exceptions for the new CPU */
lpcr = env->spr[SPR_LPCR];

View File

@ -310,7 +310,7 @@ int spapr_vio_send_crq(SpaprVioDevice *dev, uint8_t *crq)
static void spapr_vio_quiesce_one(SpaprVioDevice *dev)
{
if (dev->tcet) {
device_legacy_reset(DEVICE(dev->tcet));
device_cold_reset(DEVICE(dev->tcet));
}
free_crq(dev);
}

View File

@ -2,8 +2,8 @@
#define HW_VT82C686_H
#define TYPE_VT82C686B_ISA "vt82c686b-isa"
#define TYPE_VT82C686B_SUPERIO "vt82c686b-superio"
#define TYPE_VT82C686B_PM "vt82c686b-pm"
#define TYPE_VT8231_ISA "vt8231-isa"
#define TYPE_VT8231_PM "vt8231-pm"
#define TYPE_VIA_AC97 "via-ac97"
#define TYPE_VIA_MC97 "via-mc97"

View File

@ -0,0 +1,8 @@
#ifndef MV64361_H
#define MV64361_H
#define TYPE_MV64361 "mv64361"
PCIBus *mv64361_get_pci_bus(DeviceState *dev, int n);
#endif

View File

@ -204,15 +204,17 @@
#define PCI_VENDOR_ID_XILINX 0x10ee
#define PCI_VENDOR_ID_VIA 0x1106
#define PCI_DEVICE_ID_VIA_ISA_BRIDGE 0x0686
#define PCI_DEVICE_ID_VIA_82C686B_ISA 0x0686
#define PCI_DEVICE_ID_VIA_IDE 0x0571
#define PCI_DEVICE_ID_VIA_UHCI 0x3038
#define PCI_DEVICE_ID_VIA_82C686B_PM 0x3057
#define PCI_DEVICE_ID_VIA_AC97 0x3058
#define PCI_DEVICE_ID_VIA_MC97 0x3068
#define PCI_DEVICE_ID_VIA_8231_ISA 0x8231
#define PCI_DEVICE_ID_VIA_8231_PM 0x8235
#define PCI_VENDOR_ID_MARVELL 0x11ab
#define PCI_DEVICE_ID_MARVELL_MV6436X 0x6460
#define PCI_VENDOR_ID_SILICON_MOTION 0x126f
#define PCI_DEVICE_ID_SM501 0x0501

View File

@ -95,7 +95,7 @@ typedef enum {
#define SPAPR_CAP_FIXED_CCD 0x03
#define SPAPR_CAP_FIXED_NA 0x10 /* Lets leave a bit of a gap... */
#define FDT_MAX_SIZE 0x100000
#define FDT_MAX_SIZE 0x200000
/*
* NUMA related macros. MAX_DISTANCE_REF_POINTS was taken
@ -363,7 +363,7 @@ struct SpaprMachineState {
/* Values for 2nd argument to H_SET_MODE */
#define H_SET_MODE_RESOURCE_SET_CIABR 1
#define H_SET_MODE_RESOURCE_SET_DAWR 2
#define H_SET_MODE_RESOURCE_SET_DAWR0 2
#define H_SET_MODE_RESOURCE_ADDR_TRANS_MODE 3
#define H_SET_MODE_RESOURCE_LE 4
@ -538,8 +538,9 @@ struct SpaprMachineState {
#define H_SCM_BIND_MEM 0x3EC
#define H_SCM_UNBIND_MEM 0x3F0
#define H_SCM_UNBIND_ALL 0x3FC
#define H_SCM_HEALTH 0x400
#define MAX_HCALL_OPCODE H_SCM_UNBIND_ALL
#define MAX_HCALL_OPCODE H_SCM_HEALTH
/* The hcalls above are standardized in PAPR and implemented by pHyp
* as well.

View File

@ -492,11 +492,12 @@ void target_cpu_copy_regs(CPUArchState *env, struct target_pt_regs *regs)
#if defined(TARGET_PPC64)
int flag = (env->insns_flags2 & PPC2_BOOKE206) ? MSR_CM : MSR_SF;
#if defined(TARGET_ABI32)
env->msr &= ~((target_ulong)1 << flag);
ppc_store_msr(env, env->msr & ~((target_ulong)1 << flag));
#else
env->msr |= (target_ulong)1 << flag;
ppc_store_msr(env, env->msr | (target_ulong)1 << flag);
#endif
#endif
env->nip = regs->nip;
for(i = 0; i < 32; i++) {
env->gpr[i] = regs->gpr[i];

View File

@ -261,9 +261,6 @@ static void save_user_regs(CPUPPCState *env, struct target_mcontext *frame)
__put_user(avr->u64[PPC_VEC_HI], &vreg->u64[0]);
__put_user(avr->u64[PPC_VEC_LO], &vreg->u64[1]);
}
/* Set MSR_VR in the saved MSR value to indicate that
frame->mc_vregs contains valid data. */
msr |= MSR_VR;
#if defined(TARGET_PPC64)
vrsave = (uint32_t *)&frame->mc_vregs.altivec[33];
/* 64-bit needs to put a pointer to the vectors in the frame */
@ -300,9 +297,6 @@ static void save_user_regs(CPUPPCState *env, struct target_mcontext *frame)
for (i = 0; i < ARRAY_SIZE(env->gprh); i++) {
__put_user(env->gprh[i], &frame->mc_vregs.spe[i]);
}
/* Set MSR_SPE in the saved MSR value to indicate that
frame->mc_vregs contains valid data. */
msr |= MSR_SPE;
__put_user(env->spe_fscr, &frame->mc_vregs.spe[32]);
}
#endif
@ -354,8 +348,10 @@ static void restore_user_regs(CPUPPCState *env,
__get_user(msr, &frame->mc_gregs[TARGET_PT_MSR]);
/* If doing signal return, restore the previous little-endian mode. */
if (sig)
env->msr = (env->msr & ~(1ull << MSR_LE)) | (msr & (1ull << MSR_LE));
if (sig) {
ppc_store_msr(env, ((env->msr & ~(1ull << MSR_LE)) |
(msr & (1ull << MSR_LE))));
}
/* Restore Altivec registers if necessary. */
if (env->insns_flags & PPC_ALTIVEC) {
@ -376,8 +372,6 @@ static void restore_user_regs(CPUPPCState *env,
__get_user(avr->u64[PPC_VEC_HI], &vreg->u64[0]);
__get_user(avr->u64[PPC_VEC_LO], &vreg->u64[1]);
}
/* Set MSR_VEC in the saved MSR value to indicate that
frame->mc_vregs contains valid data. */
#if defined(TARGET_PPC64)
vrsave = (uint32_t *)&v_regs[33];
#else
@ -468,7 +462,7 @@ void setup_frame(int sig, struct target_sigaction *ka,
env->nip = (target_ulong) ka->_sa_handler;
/* Signal handlers are entered in big-endian mode. */
env->msr &= ~(1ull << MSR_LE);
ppc_store_msr(env, env->msr & ~(1ull << MSR_LE));
unlock_user_struct(frame, frame_addr, 1);
return;
@ -563,8 +557,13 @@ void setup_rt_frame(int sig, struct target_sigaction *ka,
env->nip = (target_ulong) ka->_sa_handler;
#endif
#ifdef TARGET_WORDS_BIGENDIAN
/* Signal handlers are entered in big-endian mode. */
env->msr &= ~(1ull << MSR_LE);
ppc_store_msr(env, env->msr & ~(1ull << MSR_LE));
#else
/* Signal handlers are entered in little-endian mode. */
ppc_store_msr(env, env->msr | (1ull << MSR_LE));
#endif
unlock_user_struct(rt_sf, rt_sf_addr, 1);
return;

Binary file not shown.

View File

@ -154,10 +154,10 @@ slof:
cp SLOF/boot_rom.bin ../pc-bios/slof.bin
u-boot.e500:
$(MAKE) -C u-boot O=build.e500 qemu-ppce500_config
$(MAKE) -C u-boot O=build-e500 qemu-ppce500_config
$(MAKE) -C u-boot CROSS_COMPILE=$(powerpc_cross_prefix) \
O=build.e500
$(powerpc_cross_prefix)strip u-boot/build.e500/u-boot -o \
O=build-e500
$(powerpc_cross_prefix)strip u-boot/build-e500/u-boot -o \
../pc-bios/u-boot.e500
u-boot.sam460:
@ -205,7 +205,7 @@ clean:
$(MAKE) -C ipxe/src veryclean
$(MAKE) -C edk2/BaseTools 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) -f Makefile.edk2 clean

@ -1 +1 @@
Subproject commit d3689267f92c5956e09cc7d1baa4700141662bff
Subproject commit b46dd116ce03e235f2a7d4843c6278e1da44b5e1

View File

@ -116,6 +116,8 @@ enum powerpc_excp_t {
POWERPC_EXCP_POWER8,
/* POWER9 exception model */
POWERPC_EXCP_POWER9,
/* POWER10 exception model */
POWERPC_EXCP_POWER10,
};
/*****************************************************************************/

View File

@ -192,17 +192,21 @@ typedef struct ppc_hash_pte64 ppc_hash_pte64_t;
/* SPR access micro-ops generations callbacks */
struct ppc_spr_t {
const char *name;
target_ulong default_value;
#ifndef CONFIG_USER_ONLY
unsigned int gdb_id;
#endif
#ifdef CONFIG_TCG
void (*uea_read)(DisasContext *ctx, int gpr_num, int spr_num);
void (*uea_write)(DisasContext *ctx, int spr_num, int gpr_num);
#if !defined(CONFIG_USER_ONLY)
# ifndef CONFIG_USER_ONLY
void (*oea_read)(DisasContext *ctx, int gpr_num, int spr_num);
void (*oea_write)(DisasContext *ctx, int spr_num, int gpr_num);
void (*hea_read)(DisasContext *ctx, int gpr_num, int spr_num);
void (*hea_write)(DisasContext *ctx, int spr_num, int gpr_num);
unsigned int gdb_id;
# endif
#endif
const char *name;
target_ulong default_value;
#ifdef CONFIG_KVM
/*
* We (ab)use the fact that all the SPRs will have ids for the
@ -322,13 +326,13 @@ typedef struct ppc_v3_pate_t {
#define MSR_PR 14 /* Problem state hflags */
#define MSR_FP 13 /* Floating point available hflags */
#define MSR_ME 12 /* Machine check interrupt enable */
#define MSR_FE0 11 /* Floating point exception mode 0 hflags */
#define MSR_FE0 11 /* Floating point exception mode 0 */
#define MSR_SE 10 /* Single-step trace enable x hflags */
#define MSR_DWE 10 /* Debug wait enable on 405 x */
#define MSR_UBLE 10 /* User BTB lock enable on e500 x */
#define MSR_BE 9 /* Branch trace enable x hflags */
#define MSR_DE 9 /* Debug interrupts enable on embedded PowerPC x */
#define MSR_FE1 8 /* Floating point exception mode 1 hflags */
#define MSR_FE1 8 /* Floating point exception mode 1 */
#define MSR_AL 7 /* AL bit on POWER */
#define MSR_EP 6 /* Exception prefix on 601 */
#define MSR_IR 5 /* Instruction relocate */
@ -354,10 +358,11 @@ typedef struct ppc_v3_pate_t {
#define LPCR_PECE_U_SHIFT (63 - 19)
#define LPCR_PECE_U_MASK (0x7ull << LPCR_PECE_U_SHIFT)
#define LPCR_HVEE PPC_BIT(17) /* Hypervisor Virt Exit Enable */
#define LPCR_RMLS_SHIFT (63 - 37)
#define LPCR_RMLS_SHIFT (63 - 37) /* RMLS (removed in ISA v3.0) */
#define LPCR_RMLS (0xfull << LPCR_RMLS_SHIFT)
#define LPCR_HAIL PPC_BIT(37) /* ISA v3.1 HV AIL=3 equivalent */
#define LPCR_ILE PPC_BIT(38)
#define LPCR_AIL_SHIFT (63 - 40) /* Alternate interrupt location */
#define LPCR_AIL_SHIFT (63 - 40) /* Alternate interrupt location */
#define LPCR_AIL (3ull << LPCR_AIL_SHIFT)
#define LPCR_UPRT PPC_BIT(41) /* Use Process Table */
#define LPCR_EVIRT PPC_BIT(42) /* Enhanced Virtualisation */
@ -581,6 +586,34 @@ enum {
POWERPC_FLAG_TM = 0x00100000,
/* Has SCV (ISA 3.00) */
POWERPC_FLAG_SCV = 0x00200000,
/* Has HID0 for LE bit (601) */
POWERPC_FLAG_HID0_LE = 0x00400000,
};
/*
* Bits for env->hflags.
*
* Most of these bits overlap with corresponding bits in MSR,
* but some come from other sources. Those that do come from
* the MSR are validated in hreg_compute_hflags.
*/
enum {
HFLAGS_LE = 0, /* MSR_LE -- comes from elsewhere on 601 */
HFLAGS_HV = 1, /* computed from MSR_HV and other state */
HFLAGS_64 = 2, /* computed from MSR_CE and MSR_SF */
HFLAGS_GTSE = 3, /* computed from SPR_LPCR[GTSE] */
HFLAGS_DR = 4, /* MSR_DR */
HFLAGS_SPE = 6, /* from MSR_SPE if cpu has SPE; avoid overlap w/ MSR_VR */
HFLAGS_TM = 8, /* computed from MSR_TM */
HFLAGS_BE = 9, /* MSR_BE -- from elsewhere on embedded ppc */
HFLAGS_SE = 10, /* MSR_SE -- from elsewhere on embedded ppc */
HFLAGS_FP = 13, /* MSR_FP */
HFLAGS_PR = 14, /* MSR_PR */
HFLAGS_VSX = 23, /* MSR_VSX if cpu has VSX */
HFLAGS_VR = 25, /* MSR_VR if cpu has VRE */
HFLAGS_IMMU_IDX = 26, /* 26..28 -- the composite immu_idx */
HFLAGS_DMMU_IDX = 29, /* 29..31 -- the composite dmmu_idx */
};
/*****************************************************************************/
@ -1102,11 +1135,9 @@ struct CPUPPCState {
bool resume_as_sreset;
#endif
/* These resources are used only in QEMU core */
target_ulong hflags; /* hflags is MSR & HFLAGS_MASK */
target_ulong hflags_nmsr; /* specific hflags, not coming from MSR */
int immu_idx; /* precomputed MMU index to speed up insn accesses */
int dmmu_idx; /* precomputed MMU index to speed up data accesses */
/* These resources are used only in TCG */
uint32_t hflags;
target_ulong hflags_compat_nmsr; /* for migration compatibility */
/* Power management */
int (*check_pow)(CPUPPCState *env);
@ -1342,7 +1373,11 @@ int ppc_dcr_write(ppc_dcr_t *dcr_env, int dcrn, uint32_t val);
#define MMU_USER_IDX 0
static inline int cpu_mmu_index(CPUPPCState *env, bool ifetch)
{
return ifetch ? env->immu_idx : env->dmmu_idx;
#ifdef CONFIG_USER_ONLY
return MMU_USER_IDX;
#else
return (env->hflags >> (ifetch ? HFLAGS_IMMU_IDX : HFLAGS_DMMU_IDX)) & 7;
#endif
}
/* Compatibility modes */
@ -1459,10 +1494,10 @@ typedef PowerPCCPU ArchCPU;
#define SPR_MPC_BAR (0x09F)
#define SPR_PSPB (0x09F)
#define SPR_DPDES (0x0B0)
#define SPR_DAWR (0x0B4)
#define SPR_DAWR0 (0x0B4)
#define SPR_RPR (0x0BA)
#define SPR_CIABR (0x0BB)
#define SPR_DAWRX (0x0BC)
#define SPR_DAWRX0 (0x0BC)
#define SPR_HFSCR (0x0BE)
#define SPR_VRSAVE (0x100)
#define SPR_USPRG0 (0x100)
@ -2375,14 +2410,6 @@ enum {
HMER_XSCOM_STATUS_MASK = PPC_BITMASK(21, 23),
};
/* Alternate Interrupt Location (AIL) */
enum {
AIL_NONE = 0,
AIL_RESERVED = 1,
AIL_0001_8000 = 2,
AIL_C000_0000_0000_4000 = 3,
};
/*****************************************************************************/
#define is_isa300(ctx) (!!(ctx->insns_flags2 & PPC2_ISA300))
@ -2395,6 +2422,10 @@ void cpu_write_xer(CPUPPCState *env, target_ulong xer);
*/
#define is_book3s_arch2x(ctx) (!!((ctx)->insns_flags & PPC_SEGMENT_64B))
#ifdef CONFIG_DEBUG_TCG
void cpu_get_tb_cpu_state(CPUPPCState *env, target_ulong *pc,
target_ulong *cs_base, uint32_t *flags);
#else
static inline void cpu_get_tb_cpu_state(CPUPPCState *env, target_ulong *pc,
target_ulong *cs_base, uint32_t *flags)
{
@ -2402,6 +2433,7 @@ static inline void cpu_get_tb_cpu_state(CPUPPCState *env, target_ulong *pc,
*cs_base = 0;
*flags = env->hflags;
}
#endif
void QEMU_NORETURN raise_exception(CPUPPCState *env, uint32_t exception);
void QEMU_NORETURN raise_exception_ra(CPUPPCState *env, uint32_t exception,

View File

@ -136,25 +136,157 @@ static int powerpc_reset_wakeup(CPUState *cs, CPUPPCState *env, int excp,
return POWERPC_EXCP_RESET;
}
static uint64_t ppc_excp_vector_offset(CPUState *cs, int ail)
/*
* AIL - Alternate Interrupt Location, a mode that allows interrupts to be
* taken with the MMU on, and which uses an alternate location (e.g., so the
* kernel/hv can map the vectors there with an effective address).
*
* An interrupt is considered to be taken "with AIL" or "AIL applies" if they
* are delivered in this way. AIL requires the LPCR to be set to enable this
* mode, and then a number of conditions have to be true for AIL to apply.
*
* First of all, SRESET, MCE, and HMI are always delivered without AIL, because
* they specifically want to be in real mode (e.g., the MCE might be signaling
* a SLB multi-hit which requires SLB flush before the MMU can be enabled).
*
* After that, behaviour depends on the current MSR[IR], MSR[DR], MSR[HV],
* whether or not the interrupt changes MSR[HV] from 0 to 1, and the current
* radix mode (LPCR[HR]).
*
* POWER8, POWER9 with LPCR[HR]=0
* | LPCR[AIL] | MSR[IR||DR] | MSR[HV] | new MSR[HV] | AIL |
* +-----------+-------------+---------+-------------+-----+
* | a | 00/01/10 | x | x | 0 |
* | a | 11 | 0 | 1 | 0 |
* | a | 11 | 1 | 1 | a |
* | a | 11 | 0 | 0 | a |
* +-------------------------------------------------------+
*
* POWER9 with LPCR[HR]=1
* | LPCR[AIL] | MSR[IR||DR] | MSR[HV] | new MSR[HV] | AIL |
* +-----------+-------------+---------+-------------+-----+
* | a | 00/01/10 | x | x | 0 |
* | a | 11 | x | x | a |
* +-------------------------------------------------------+
*
* The difference with POWER9 being that MSR[HV] 0->1 interrupts can be sent to
* the hypervisor in AIL mode if the guest is radix. This is good for
* performance but allows the guest to influence the AIL of hypervisor
* interrupts using its MSR, and also the hypervisor must disallow guest
* interrupts (MSR[HV] 0->0) from using AIL if the hypervisor does not want to
* use AIL for its MSR[HV] 0->1 interrupts.
*
* POWER10 addresses those issues with a new LPCR[HAIL] bit that is applied to
* interrupts that begin execution with MSR[HV]=1 (so both MSR[HV] 0->1 and
* MSR[HV] 1->1).
*
* HAIL=1 is equivalent to AIL=3, for interrupts delivered with MSR[HV]=1.
*
* POWER10 behaviour is
* | LPCR[AIL] | LPCR[HAIL] | MSR[IR||DR] | MSR[HV] | new MSR[HV] | AIL |
* +-----------+------------+-------------+---------+-------------+-----+
* | a | h | 00/01/10 | 0 | 0 | 0 |
* | a | h | 11 | 0 | 0 | a |
* | a | h | x | 0 | 1 | h |
* | a | h | 00/01/10 | 1 | 1 | 0 |
* | a | h | 11 | 1 | 1 | h |
* +--------------------------------------------------------------------+
*/
static inline void ppc_excp_apply_ail(PowerPCCPU *cpu, int excp_model, int excp,
target_ulong msr,
target_ulong *new_msr,
target_ulong *vector)
{
uint64_t offset = 0;
#if defined(TARGET_PPC64)
CPUPPCState *env = &cpu->env;
bool mmu_all_on = ((msr >> MSR_IR) & 1) && ((msr >> MSR_DR) & 1);
bool hv_escalation = !(msr & MSR_HVB) && (*new_msr & MSR_HVB);
int ail = 0;
switch (ail) {
case AIL_NONE:
break;
case AIL_0001_8000:
offset = 0x18000;
break;
case AIL_C000_0000_0000_4000:
offset = 0xc000000000004000ull;
break;
default:
cpu_abort(cs, "Invalid AIL combination %d\n", ail);
break;
if (excp == POWERPC_EXCP_MCHECK ||
excp == POWERPC_EXCP_RESET ||
excp == POWERPC_EXCP_HV_MAINT) {
/* SRESET, MCE, HMI never apply AIL */
return;
}
return offset;
if (excp_model == POWERPC_EXCP_POWER8 ||
excp_model == POWERPC_EXCP_POWER9) {
if (!mmu_all_on) {
/* AIL only works if MSR[IR] and MSR[DR] are both enabled. */
return;
}
if (hv_escalation && !(env->spr[SPR_LPCR] & LPCR_HR)) {
/*
* AIL does not work if there is a MSR[HV] 0->1 transition and the
* partition is in HPT mode. For radix guests, such interrupts are
* allowed to be delivered to the hypervisor in ail mode.
*/
return;
}
ail = (env->spr[SPR_LPCR] & LPCR_AIL) >> LPCR_AIL_SHIFT;
if (ail == 0) {
return;
}
if (ail == 1) {
/* AIL=1 is reserved, treat it like AIL=0 */
return;
}
} else if (excp_model == POWERPC_EXCP_POWER10) {
if (!mmu_all_on && !hv_escalation) {
/*
* AIL works for HV interrupts even with guest MSR[IR/DR] disabled.
* Guest->guest and HV->HV interrupts do require MMU on.
*/
return;
}
if (*new_msr & MSR_HVB) {
if (!(env->spr[SPR_LPCR] & LPCR_HAIL)) {
/* HV interrupts depend on LPCR[HAIL] */
return;
}
ail = 3; /* HAIL=1 gives AIL=3 behaviour for HV interrupts */
} else {
ail = (env->spr[SPR_LPCR] & LPCR_AIL) >> LPCR_AIL_SHIFT;
}
if (ail == 0) {
return;
}
if (ail == 1 || ail == 2) {
/* AIL=1 and AIL=2 are reserved, treat them like AIL=0 */
return;
}
} else {
/* Other processors do not support AIL */
return;
}
/*
* AIL applies, so the new MSR gets IR and DR set, and an offset applied
* to the new IP.
*/
*new_msr |= (1 << MSR_IR) | (1 << MSR_DR);
if (excp != POWERPC_EXCP_SYSCALL_VECTORED) {
if (ail == 2) {
*vector |= 0x0000000000018000ull;
} else if (ail == 3) {
*vector |= 0xc000000000004000ull;
}
} else {
/*
* scv AIL is a little different. AIL=2 does not change the address,
* only the MSR. AIL=3 replaces the 0x17000 base with 0xc...3000.
*/
if (ail == 3) {
*vector &= ~0x0000000000017000ull; /* Un-apply the base offset */
*vector |= 0xc000000000003000ull; /* Apply scv's AIL=3 offset */
}
}
#endif
}
static inline void powerpc_set_excp_state(PowerPCCPU *cpu,
@ -197,7 +329,7 @@ static inline void powerpc_excp(PowerPCCPU *cpu, int excp_model, int excp)
CPUState *cs = CPU(cpu);
CPUPPCState *env = &cpu->env;
target_ulong msr, new_msr, vector;
int srr0, srr1, asrr0, asrr1, lev = -1, ail;
int srr0, srr1, asrr0, asrr1, lev = -1;
bool lpes0;
qemu_log_mask(CPU_LOG_INT, "Raise exception at " TARGET_FMT_lx
@ -238,25 +370,17 @@ static inline void powerpc_excp(PowerPCCPU *cpu, int excp_model, int excp)
*
* On anything else, we behave as if LPES0 is 1
* (externals don't alter MSR:HV)
*
* AIL is initialized here but can be cleared by
* selected exceptions
*/
#if defined(TARGET_PPC64)
if (excp_model == POWERPC_EXCP_POWER7 ||
excp_model == POWERPC_EXCP_POWER8 ||
excp_model == POWERPC_EXCP_POWER9) {
excp_model == POWERPC_EXCP_POWER9 ||
excp_model == POWERPC_EXCP_POWER10) {
lpes0 = !!(env->spr[SPR_LPCR] & LPCR_LPES0);
if (excp_model != POWERPC_EXCP_POWER7) {
ail = (env->spr[SPR_LPCR] & LPCR_AIL) >> LPCR_AIL_SHIFT;
} else {
ail = 0;
}
} else
#endif /* defined(TARGET_PPC64) */
{
lpes0 = true;
ail = 0;
}
/*
@ -315,7 +439,6 @@ static inline void powerpc_excp(PowerPCCPU *cpu, int excp_model, int excp)
*/
new_msr |= (target_ulong)MSR_HVB;
}
ail = 0;
/* machine check exceptions don't have ME set */
new_msr &= ~((target_ulong)1 << MSR_ME);
@ -519,7 +642,6 @@ static inline void powerpc_excp(PowerPCCPU *cpu, int excp_model, int excp)
"exception %d with no HV support\n", excp);
}
}
ail = 0;
break;
case POWERPC_EXCP_DSEG: /* Data segment exception */
case POWERPC_EXCP_ISEG: /* Instruction segment exception */
@ -773,7 +895,8 @@ static inline void powerpc_excp(PowerPCCPU *cpu, int excp_model, int excp)
} else if (env->spr[SPR_LPCR] & LPCR_ILE) {
new_msr |= (target_ulong)1 << MSR_LE;
}
} else if (excp_model == POWERPC_EXCP_POWER9) {
} else if (excp_model == POWERPC_EXCP_POWER9 ||
excp_model == POWERPC_EXCP_POWER10) {
if (new_msr & MSR_HVB) {
if (env->spr[SPR_HID0] & HID0_POWER9_HILE) {
new_msr |= (target_ulong)1 << MSR_LE;
@ -790,15 +913,6 @@ static inline void powerpc_excp(PowerPCCPU *cpu, int excp_model, int excp)
}
#endif
/*
* AIL only works if there is no HV transition and we are running
* with translations enabled
*/
if (!((msr >> MSR_IR) & 1) || !((msr >> MSR_DR) & 1) ||
((new_msr & MSR_HVB) && !(msr & MSR_HVB))) {
ail = 0;
}
vector = env->excp_vectors[excp];
if (vector == (target_ulong)-1ULL) {
cpu_abort(cs, "Raised an exception without defined vector %d\n",
@ -839,23 +953,8 @@ static inline void powerpc_excp(PowerPCCPU *cpu, int excp_model, int excp)
/* Save MSR */
env->spr[srr1] = msr;
/* Handle AIL */
if (ail) {
new_msr |= (1 << MSR_IR) | (1 << MSR_DR);
vector |= ppc_excp_vector_offset(cs, ail);
}
#if defined(TARGET_PPC64)
} else {
/* scv AIL is a little different */
if (ail) {
new_msr |= (1 << MSR_IR) | (1 << MSR_DR);
}
if (ail == AIL_C000_0000_0000_4000) {
vector |= 0xc000000000003000ull;
} else {
vector |= 0x0000000000017000ull;
}
vector += lev * 0x20;
env->lr = env->nip;
@ -863,6 +962,9 @@ static inline void powerpc_excp(PowerPCCPU *cpu, int excp_model, int excp)
#endif
}
/* This can update new_msr and vector if AIL applies */
ppc_excp_apply_ail(cpu, excp_model, excp, msr, &new_msr, &vector);
powerpc_set_excp_state(cpu, vector, new_msr);
}
@ -1130,6 +1232,15 @@ void helper_store_msr(CPUPPCState *env, target_ulong val)
}
#if defined(TARGET_PPC64)
void helper_scv(CPUPPCState *env, uint32_t lev)
{
if (env->spr[SPR_FSCR] & (1ull << FSCR_SCV)) {
raise_exception_err(env, POWERPC_EXCP_SYSCALL_VECTORED, lev);
} else {
raise_exception_err(env, POWERPC_EXCP_FU, FSCR_IC_SCV);
}
}
void helper_pminsn(CPUPPCState *env, powerpc_pm_insn_t insn)
{
CPUState *cs;

View File

@ -20,6 +20,8 @@
#include "qemu/osdep.h"
#include "cpu.h"
#include "exec/gdbstub.h"
#include "exec/helper-proto.h"
#include "internal.h"
static int ppc_gdb_register_len_apple(int n)
{
@ -387,3 +389,259 @@ const char *ppc_gdb_get_dynamic_xml(CPUState *cs, const char *xml_name)
return NULL;
}
#endif
static bool avr_need_swap(CPUPPCState *env)
{
#ifdef HOST_WORDS_BIGENDIAN
return msr_le;
#else
return !msr_le;
#endif
}
#if !defined(CONFIG_USER_ONLY)
static int gdb_find_spr_idx(CPUPPCState *env, int n)
{
int i;
for (i = 0; i < ARRAY_SIZE(env->spr_cb); i++) {
ppc_spr_t *spr = &env->spr_cb[i];
if (spr->name && spr->gdb_id == n) {
return i;
}
}
return -1;
}
static int gdb_get_spr_reg(CPUPPCState *env, GByteArray *buf, int n)
{
int reg;
int len;
reg = gdb_find_spr_idx(env, n);
if (reg < 0) {
return 0;
}
len = TARGET_LONG_SIZE;
gdb_get_regl(buf, env->spr[reg]);
ppc_maybe_bswap_register(env, gdb_get_reg_ptr(buf, len), len);
return len;
}
static int gdb_set_spr_reg(CPUPPCState *env, uint8_t *mem_buf, int n)
{
int reg;
int len;
reg = gdb_find_spr_idx(env, n);
if (reg < 0) {
return 0;
}
len = TARGET_LONG_SIZE;
ppc_maybe_bswap_register(env, mem_buf, len);
env->spr[reg] = ldn_p(mem_buf, len);
return len;
}
#endif
static int gdb_get_float_reg(CPUPPCState *env, GByteArray *buf, int n)
{
uint8_t *mem_buf;
if (n < 32) {
gdb_get_reg64(buf, *cpu_fpr_ptr(env, n));
mem_buf = gdb_get_reg_ptr(buf, 8);
ppc_maybe_bswap_register(env, mem_buf, 8);
return 8;
}
if (n == 32) {
gdb_get_reg32(buf, env->fpscr);
mem_buf = gdb_get_reg_ptr(buf, 4);
ppc_maybe_bswap_register(env, mem_buf, 4);
return 4;
}
return 0;
}
static int gdb_set_float_reg(CPUPPCState *env, uint8_t *mem_buf, int n)
{
if (n < 32) {
ppc_maybe_bswap_register(env, mem_buf, 8);
*cpu_fpr_ptr(env, n) = ldq_p(mem_buf);
return 8;
}
if (n == 32) {
ppc_maybe_bswap_register(env, mem_buf, 4);
store_fpscr(env, ldl_p(mem_buf), 0xffffffff);
return 4;
}
return 0;
}
static int gdb_get_avr_reg(CPUPPCState *env, GByteArray *buf, int n)
{
uint8_t *mem_buf;
if (n < 32) {
ppc_avr_t *avr = cpu_avr_ptr(env, n);
if (!avr_need_swap(env)) {
gdb_get_reg128(buf, avr->u64[0] , avr->u64[1]);
} else {
gdb_get_reg128(buf, avr->u64[1] , avr->u64[0]);
}
mem_buf = gdb_get_reg_ptr(buf, 16);
ppc_maybe_bswap_register(env, mem_buf, 8);
ppc_maybe_bswap_register(env, mem_buf + 8, 8);
return 16;
}
if (n == 32) {
gdb_get_reg32(buf, helper_mfvscr(env));
mem_buf = gdb_get_reg_ptr(buf, 4);
ppc_maybe_bswap_register(env, mem_buf, 4);
return 4;
}
if (n == 33) {
gdb_get_reg32(buf, (uint32_t)env->spr[SPR_VRSAVE]);
mem_buf = gdb_get_reg_ptr(buf, 4);
ppc_maybe_bswap_register(env, mem_buf, 4);
return 4;
}
return 0;
}
static int gdb_set_avr_reg(CPUPPCState *env, uint8_t *mem_buf, int n)
{
if (n < 32) {
ppc_avr_t *avr = cpu_avr_ptr(env, n);
ppc_maybe_bswap_register(env, mem_buf, 8);
ppc_maybe_bswap_register(env, mem_buf + 8, 8);
if (!avr_need_swap(env)) {
avr->u64[0] = ldq_p(mem_buf);
avr->u64[1] = ldq_p(mem_buf + 8);
} else {
avr->u64[1] = ldq_p(mem_buf);
avr->u64[0] = ldq_p(mem_buf + 8);
}
return 16;
}
if (n == 32) {
ppc_maybe_bswap_register(env, mem_buf, 4);
helper_mtvscr(env, ldl_p(mem_buf));
return 4;
}
if (n == 33) {
ppc_maybe_bswap_register(env, mem_buf, 4);
env->spr[SPR_VRSAVE] = (target_ulong)ldl_p(mem_buf);
return 4;
}
return 0;
}
static int gdb_get_spe_reg(CPUPPCState *env, GByteArray *buf, int n)
{
if (n < 32) {
#if defined(TARGET_PPC64)
gdb_get_reg32(buf, env->gpr[n] >> 32);
ppc_maybe_bswap_register(env, gdb_get_reg_ptr(buf, 4), 4);
#else
gdb_get_reg32(buf, env->gprh[n]);
#endif
return 4;
}
if (n == 32) {
gdb_get_reg64(buf, env->spe_acc);
ppc_maybe_bswap_register(env, gdb_get_reg_ptr(buf, 8), 8);
return 8;
}
if (n == 33) {
gdb_get_reg32(buf, env->spe_fscr);
ppc_maybe_bswap_register(env, gdb_get_reg_ptr(buf, 4), 4);
return 4;
}
return 0;
}
static int gdb_set_spe_reg(CPUPPCState *env, uint8_t *mem_buf, int n)
{
if (n < 32) {
#if defined(TARGET_PPC64)
target_ulong lo = (uint32_t)env->gpr[n];
target_ulong hi;
ppc_maybe_bswap_register(env, mem_buf, 4);
hi = (target_ulong)ldl_p(mem_buf) << 32;
env->gpr[n] = lo | hi;
#else
env->gprh[n] = ldl_p(mem_buf);
#endif
return 4;
}
if (n == 32) {
ppc_maybe_bswap_register(env, mem_buf, 8);
env->spe_acc = ldq_p(mem_buf);
return 8;
}
if (n == 33) {
ppc_maybe_bswap_register(env, mem_buf, 4);
env->spe_fscr = ldl_p(mem_buf);
return 4;
}
return 0;
}
static int gdb_get_vsx_reg(CPUPPCState *env, GByteArray *buf, int n)
{
if (n < 32) {
gdb_get_reg64(buf, *cpu_vsrl_ptr(env, n));
ppc_maybe_bswap_register(env, gdb_get_reg_ptr(buf, 8), 8);
return 8;
}
return 0;
}
static int gdb_set_vsx_reg(CPUPPCState *env, uint8_t *mem_buf, int n)
{
if (n < 32) {
ppc_maybe_bswap_register(env, mem_buf, 8);
*cpu_vsrl_ptr(env, n) = ldq_p(mem_buf);
return 8;
}
return 0;
}
gchar *ppc_gdb_arch_name(CPUState *cs)
{
#if defined(TARGET_PPC64)
return g_strdup("powerpc:common64");
#else
return g_strdup("powerpc:common");
#endif
}
void ppc_gdb_init(CPUState *cs, PowerPCCPUClass *pcc)
{
if (pcc->insns_flags & PPC_FLOAT) {
gdb_register_coprocessor(cs, gdb_get_float_reg, gdb_set_float_reg,
33, "power-fpu.xml", 0);
}
if (pcc->insns_flags & PPC_ALTIVEC) {
gdb_register_coprocessor(cs, gdb_get_avr_reg, gdb_set_avr_reg,
34, "power-altivec.xml", 0);
}
if (pcc->insns_flags & PPC_SPE) {
gdb_register_coprocessor(cs, gdb_get_spe_reg, gdb_set_spe_reg,
34, "power-spe.xml", 0);
}
if (pcc->insns_flags2 & PPC2_VSX) {
gdb_register_coprocessor(cs, gdb_get_vsx_reg, gdb_set_vsx_reg,
32, "power-vsx.xml", 0);
}
#ifndef CONFIG_USER_ONLY
gdb_register_coprocessor(cs, gdb_get_spr_reg, gdb_set_spr_reg,
pcc->gdb_num_sprs, "power-spr.xml", 0);
#endif
}

View File

@ -13,6 +13,7 @@ DEF_HELPER_1(rfci, void, env)
DEF_HELPER_1(rfdi, void, env)
DEF_HELPER_1(rfmci, void, env)
#if defined(TARGET_PPC64)
DEF_HELPER_2(scv, noreturn, env, i32)
DEF_HELPER_2(pminsn, void, env, i32)
DEF_HELPER_1(rfid, void, env)
DEF_HELPER_1(rfscv, void, env)

280
target/ppc/helper_regs.c Normal file
View File

@ -0,0 +1,280 @@
/*
* PowerPC emulation special registers manipulation helpers for qemu.
*
* Copyright (c) 2003-2007 Jocelyn Mayer
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library 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
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, see <http://www.gnu.org/licenses/>.
*/
#include "qemu/osdep.h"
#include "cpu.h"
#include "qemu/main-loop.h"
#include "exec/exec-all.h"
#include "sysemu/kvm.h"
#include "helper_regs.h"
/* Swap temporary saved registers with GPRs */
void hreg_swap_gpr_tgpr(CPUPPCState *env)
{
target_ulong tmp;
tmp = env->gpr[0];
env->gpr[0] = env->tgpr[0];
env->tgpr[0] = tmp;
tmp = env->gpr[1];
env->gpr[1] = env->tgpr[1];
env->tgpr[1] = tmp;
tmp = env->gpr[2];
env->gpr[2] = env->tgpr[2];
env->tgpr[2] = tmp;
tmp = env->gpr[3];
env->gpr[3] = env->tgpr[3];
env->tgpr[3] = tmp;
}
static uint32_t hreg_compute_hflags_value(CPUPPCState *env)
{
target_ulong msr = env->msr;
uint32_t ppc_flags = env->flags;
uint32_t hflags = 0;
uint32_t msr_mask;
/* Some bits come straight across from MSR. */
QEMU_BUILD_BUG_ON(MSR_LE != HFLAGS_LE);
QEMU_BUILD_BUG_ON(MSR_PR != HFLAGS_PR);
QEMU_BUILD_BUG_ON(MSR_DR != HFLAGS_DR);
QEMU_BUILD_BUG_ON(MSR_FP != HFLAGS_FP);
msr_mask = ((1 << MSR_LE) | (1 << MSR_PR) |
(1 << MSR_DR) | (1 << MSR_FP));
if (ppc_flags & POWERPC_FLAG_HID0_LE) {
/*
* Note that MSR_LE is not set in env->msr_mask for this cpu,
* and so will never be set in msr.
*/
uint32_t le = extract32(env->spr[SPR_HID0], 3, 1);
hflags |= le << MSR_LE;
}
if (ppc_flags & POWERPC_FLAG_DE) {
target_ulong dbcr0 = env->spr[SPR_BOOKE_DBCR0];
if (dbcr0 & DBCR0_ICMP) {
hflags |= 1 << HFLAGS_SE;
}
if (dbcr0 & DBCR0_BRT) {
hflags |= 1 << HFLAGS_BE;
}
} else {
if (ppc_flags & POWERPC_FLAG_BE) {
QEMU_BUILD_BUG_ON(MSR_BE != HFLAGS_BE);
msr_mask |= 1 << MSR_BE;
}
if (ppc_flags & POWERPC_FLAG_SE) {
QEMU_BUILD_BUG_ON(MSR_SE != HFLAGS_SE);
msr_mask |= 1 << MSR_SE;
}
}
if (msr_is_64bit(env, msr)) {
hflags |= 1 << HFLAGS_64;
}
if ((ppc_flags & POWERPC_FLAG_SPE) && (msr & (1 << MSR_SPE))) {
hflags |= 1 << HFLAGS_SPE;
}
if (ppc_flags & POWERPC_FLAG_VRE) {
QEMU_BUILD_BUG_ON(MSR_VR != HFLAGS_VR);
msr_mask |= 1 << MSR_VR;
}
if (ppc_flags & POWERPC_FLAG_VSX) {
QEMU_BUILD_BUG_ON(MSR_VSX != HFLAGS_VSX);
msr_mask |= 1 << MSR_VSX;
}
if ((ppc_flags & POWERPC_FLAG_TM) && (msr & (1ull << MSR_TM))) {
hflags |= 1 << HFLAGS_TM;
}
if (env->spr[SPR_LPCR] & LPCR_GTSE) {
hflags |= 1 << HFLAGS_GTSE;
}
#ifndef CONFIG_USER_ONLY
if (!env->has_hv_mode || (msr & (1ull << MSR_HV))) {
hflags |= 1 << HFLAGS_HV;
}
/*
* This is our encoding for server processors. The architecture
* specifies that there is no such thing as userspace with
* translation off, however it appears that MacOS does it and some
* 32-bit CPUs support it. Weird...
*
* 0 = Guest User space virtual mode
* 1 = Guest Kernel space virtual mode
* 2 = Guest User space real mode
* 3 = Guest Kernel space real mode
* 4 = HV User space virtual mode
* 5 = HV Kernel space virtual mode
* 6 = HV User space real mode
* 7 = HV Kernel space real mode
*
* For BookE, we need 8 MMU modes as follow:
*
* 0 = AS 0 HV User space
* 1 = AS 0 HV Kernel space
* 2 = AS 1 HV User space
* 3 = AS 1 HV Kernel space
* 4 = AS 0 Guest User space
* 5 = AS 0 Guest Kernel space
* 6 = AS 1 Guest User space
* 7 = AS 1 Guest Kernel space
*/
unsigned immu_idx, dmmu_idx;
dmmu_idx = msr & (1 << MSR_PR) ? 0 : 1;
if (env->mmu_model & POWERPC_MMU_BOOKE) {
dmmu_idx |= msr & (1 << MSR_GS) ? 4 : 0;
immu_idx = dmmu_idx;
immu_idx |= msr & (1 << MSR_IS) ? 2 : 0;
dmmu_idx |= msr & (1 << MSR_DS) ? 2 : 0;
} else {
dmmu_idx |= msr & (1ull << MSR_HV) ? 4 : 0;
immu_idx = dmmu_idx;
immu_idx |= msr & (1 << MSR_IR) ? 0 : 2;
dmmu_idx |= msr & (1 << MSR_DR) ? 0 : 2;
}
hflags |= immu_idx << HFLAGS_IMMU_IDX;
hflags |= dmmu_idx << HFLAGS_DMMU_IDX;
#endif
return hflags | (msr & msr_mask);
}
void hreg_compute_hflags(CPUPPCState *env)
{
env->hflags = hreg_compute_hflags_value(env);
}
#ifdef CONFIG_DEBUG_TCG
void cpu_get_tb_cpu_state(CPUPPCState *env, target_ulong *pc,
target_ulong *cs_base, uint32_t *flags)
{
uint32_t hflags_current = env->hflags;
uint32_t hflags_rebuilt;
*pc = env->nip;
*cs_base = 0;
*flags = hflags_current;
hflags_rebuilt = hreg_compute_hflags_value(env);
if (unlikely(hflags_current != hflags_rebuilt)) {
cpu_abort(env_cpu(env),
"TCG hflags mismatch (current:0x%08x rebuilt:0x%08x)\n",
hflags_current, hflags_rebuilt);
}
}
#endif
void cpu_interrupt_exittb(CPUState *cs)
{
if (!kvm_enabled()) {
return;
}
if (!qemu_mutex_iothread_locked()) {
qemu_mutex_lock_iothread();
cpu_interrupt(cs, CPU_INTERRUPT_EXITTB);
qemu_mutex_unlock_iothread();
} else {
cpu_interrupt(cs, CPU_INTERRUPT_EXITTB);
}
}
int hreg_store_msr(CPUPPCState *env, target_ulong value, int alter_hv)
{
int excp;
#if !defined(CONFIG_USER_ONLY)
CPUState *cs = env_cpu(env);
#endif
excp = 0;
value &= env->msr_mask;
#if !defined(CONFIG_USER_ONLY)
/* Neither mtmsr nor guest state can alter HV */
if (!alter_hv || !(env->msr & MSR_HVB)) {
value &= ~MSR_HVB;
value |= env->msr & MSR_HVB;
}
if (((value >> MSR_IR) & 1) != msr_ir ||
((value >> MSR_DR) & 1) != msr_dr) {
cpu_interrupt_exittb(cs);
}
if ((env->mmu_model & POWERPC_MMU_BOOKE) &&
((value >> MSR_GS) & 1) != msr_gs) {
cpu_interrupt_exittb(cs);
}
if (unlikely((env->flags & POWERPC_FLAG_TGPR) &&
((value ^ env->msr) & (1 << MSR_TGPR)))) {
/* Swap temporary saved registers with GPRs */
hreg_swap_gpr_tgpr(env);
}
if (unlikely((value >> MSR_EP) & 1) != msr_ep) {
/* Change the exception prefix on PowerPC 601 */
env->excp_prefix = ((value >> MSR_EP) & 1) * 0xFFF00000;
}
/*
* If PR=1 then EE, IR and DR must be 1
*
* Note: We only enforce this on 64-bit server processors.
* It appears that:
* - 32-bit implementations supports PR=1 and EE/DR/IR=0 and MacOS
* exploits it.
* - 64-bit embedded implementations do not need any operation to be
* performed when PR is set.
*/
if (is_book3s_arch2x(env) && ((value >> MSR_PR) & 1)) {
value |= (1 << MSR_EE) | (1 << MSR_DR) | (1 << MSR_IR);
}
#endif
env->msr = value;
hreg_compute_hflags(env);
#if !defined(CONFIG_USER_ONLY)
if (unlikely(msr_pow == 1)) {
if (!env->pending_interrupts && (*env->check_pow)(env)) {
cs->halted = 1;
excp = EXCP_HALTED;
}
}
#endif
return excp;
}
#ifndef CONFIG_USER_ONLY
void check_tlb_flush(CPUPPCState *env, bool global)
{
CPUState *cs = env_cpu(env);
/* Handle global flushes first */
if (global && (env->tlb_need_flush & TLB_NEED_GLOBAL_FLUSH)) {
env->tlb_need_flush &= ~TLB_NEED_GLOBAL_FLUSH;
env->tlb_need_flush &= ~TLB_NEED_LOCAL_FLUSH;
tlb_flush_all_cpus_synced(cs);
return;
}
/* Then handle local ones */
if (env->tlb_need_flush & TLB_NEED_LOCAL_FLUSH) {
env->tlb_need_flush &= ~TLB_NEED_LOCAL_FLUSH;
tlb_flush(cs);
}
}
#endif

View File

@ -20,184 +20,15 @@
#ifndef HELPER_REGS_H
#define HELPER_REGS_H
#include "qemu/main-loop.h"
#include "exec/exec-all.h"
#include "sysemu/kvm.h"
void hreg_swap_gpr_tgpr(CPUPPCState *env);
void hreg_compute_hflags(CPUPPCState *env);
void cpu_interrupt_exittb(CPUState *cs);
int hreg_store_msr(CPUPPCState *env, target_ulong value, int alter_hv);
/* Swap temporary saved registers with GPRs */
static inline void hreg_swap_gpr_tgpr(CPUPPCState *env)
{
target_ulong tmp;
tmp = env->gpr[0];
env->gpr[0] = env->tgpr[0];
env->tgpr[0] = tmp;
tmp = env->gpr[1];
env->gpr[1] = env->tgpr[1];
env->tgpr[1] = tmp;
tmp = env->gpr[2];
env->gpr[2] = env->tgpr[2];
env->tgpr[2] = tmp;
tmp = env->gpr[3];
env->gpr[3] = env->tgpr[3];
env->tgpr[3] = tmp;
}
static inline void hreg_compute_mem_idx(CPUPPCState *env)
{
/*
* This is our encoding for server processors. The architecture
* specifies that there is no such thing as userspace with
* translation off, however it appears that MacOS does it and some
* 32-bit CPUs support it. Weird...
*
* 0 = Guest User space virtual mode
* 1 = Guest Kernel space virtual mode
* 2 = Guest User space real mode
* 3 = Guest Kernel space real mode
* 4 = HV User space virtual mode
* 5 = HV Kernel space virtual mode
* 6 = HV User space real mode
* 7 = HV Kernel space real mode
*
* For BookE, we need 8 MMU modes as follow:
*
* 0 = AS 0 HV User space
* 1 = AS 0 HV Kernel space
* 2 = AS 1 HV User space
* 3 = AS 1 HV Kernel space
* 4 = AS 0 Guest User space
* 5 = AS 0 Guest Kernel space
* 6 = AS 1 Guest User space
* 7 = AS 1 Guest Kernel space
*/
if (env->mmu_model & POWERPC_MMU_BOOKE) {
env->immu_idx = env->dmmu_idx = msr_pr ? 0 : 1;
env->immu_idx += msr_is ? 2 : 0;
env->dmmu_idx += msr_ds ? 2 : 0;
env->immu_idx += msr_gs ? 4 : 0;
env->dmmu_idx += msr_gs ? 4 : 0;
} else {
env->immu_idx = env->dmmu_idx = msr_pr ? 0 : 1;
env->immu_idx += msr_ir ? 0 : 2;
env->dmmu_idx += msr_dr ? 0 : 2;
env->immu_idx += msr_hv ? 4 : 0;
env->dmmu_idx += msr_hv ? 4 : 0;
}
}
static inline void hreg_compute_hflags(CPUPPCState *env)
{
target_ulong hflags_mask;
/* We 'forget' FE0 & FE1: we'll never generate imprecise exceptions */
hflags_mask = (1 << MSR_VR) | (1 << MSR_AP) | (1 << MSR_SA) |
(1 << MSR_PR) | (1 << MSR_FP) | (1 << MSR_SE) | (1 << MSR_BE) |
(1 << MSR_LE) | (1 << MSR_VSX) | (1 << MSR_IR) | (1 << MSR_DR);
hflags_mask |= (1ULL << MSR_CM) | (1ULL << MSR_SF) | MSR_HVB;
hreg_compute_mem_idx(env);
env->hflags = env->msr & hflags_mask;
/* Merge with hflags coming from other registers */
env->hflags |= env->hflags_nmsr;
}
static inline void cpu_interrupt_exittb(CPUState *cs)
{
if (!kvm_enabled()) {
return;
}
if (!qemu_mutex_iothread_locked()) {
qemu_mutex_lock_iothread();
cpu_interrupt(cs, CPU_INTERRUPT_EXITTB);
qemu_mutex_unlock_iothread();
} else {
cpu_interrupt(cs, CPU_INTERRUPT_EXITTB);
}
}
static inline int hreg_store_msr(CPUPPCState *env, target_ulong value,
int alter_hv)
{
int excp;
#if !defined(CONFIG_USER_ONLY)
CPUState *cs = env_cpu(env);
#endif
excp = 0;
value &= env->msr_mask;
#if !defined(CONFIG_USER_ONLY)
/* Neither mtmsr nor guest state can alter HV */
if (!alter_hv || !(env->msr & MSR_HVB)) {
value &= ~MSR_HVB;
value |= env->msr & MSR_HVB;
}
if (((value >> MSR_IR) & 1) != msr_ir ||
((value >> MSR_DR) & 1) != msr_dr) {
cpu_interrupt_exittb(cs);
}
if ((env->mmu_model & POWERPC_MMU_BOOKE) &&
((value >> MSR_GS) & 1) != msr_gs) {
cpu_interrupt_exittb(cs);
}
if (unlikely((env->flags & POWERPC_FLAG_TGPR) &&
((value ^ env->msr) & (1 << MSR_TGPR)))) {
/* Swap temporary saved registers with GPRs */
hreg_swap_gpr_tgpr(env);
}
if (unlikely((value >> MSR_EP) & 1) != msr_ep) {
/* Change the exception prefix on PowerPC 601 */
env->excp_prefix = ((value >> MSR_EP) & 1) * 0xFFF00000;
}
/*
* If PR=1 then EE, IR and DR must be 1
*
* Note: We only enforce this on 64-bit server processors.
* It appears that:
* - 32-bit implementations supports PR=1 and EE/DR/IR=0 and MacOS
* exploits it.
* - 64-bit embedded implementations do not need any operation to be
* performed when PR is set.
*/
if (is_book3s_arch2x(env) && ((value >> MSR_PR) & 1)) {
value |= (1 << MSR_EE) | (1 << MSR_DR) | (1 << MSR_IR);
}
#endif
env->msr = value;
hreg_compute_hflags(env);
#if !defined(CONFIG_USER_ONLY)
if (unlikely(msr_pow == 1)) {
if (!env->pending_interrupts && (*env->check_pow)(env)) {
cs->halted = 1;
excp = EXCP_HALTED;
}
}
#endif
return excp;
}
#if !defined(CONFIG_USER_ONLY)
static inline void check_tlb_flush(CPUPPCState *env, bool global)
{
CPUState *cs = env_cpu(env);
/* Handle global flushes first */
if (global && (env->tlb_need_flush & TLB_NEED_GLOBAL_FLUSH)) {
env->tlb_need_flush &= ~TLB_NEED_GLOBAL_FLUSH;
env->tlb_need_flush &= ~TLB_NEED_LOCAL_FLUSH;
tlb_flush_all_cpus_synced(cs);
return;
}
/* Then handle local ones */
if (env->tlb_need_flush & TLB_NEED_LOCAL_FLUSH) {
env->tlb_need_flush &= ~TLB_NEED_LOCAL_FLUSH;
tlb_flush(cs);
}
}
#else
#ifdef CONFIG_USER_ONLY
static inline void check_tlb_flush(CPUPPCState *env, bool global) { }
#else
void check_tlb_flush(CPUPPCState *env, bool global);
#endif
#endif /* HELPER_REGS_H */

View File

@ -22,6 +22,7 @@
#include "internal.h"
#include "qemu/host-utils.h"
#include "qemu/main-loop.h"
#include "qemu/log.h"
#include "exec/helper-proto.h"
#include "crypto/aes.h"
#include "fpu/softfloat.h"

View File

@ -215,4 +215,17 @@ void helper_compute_fprf_float128(CPUPPCState *env, float128 arg);
void ppc_cpu_do_unaligned_access(CPUState *cs, vaddr addr,
MMUAccessType access_type,
int mmu_idx, uintptr_t retaddr);
/* translate.c */
/* #define PPC_DUMP_CPU */
int ppc_fixup_cpu(PowerPCCPU *cpu);
void create_ppc_opcodes(PowerPCCPU *cpu, Error **errp);
void destroy_ppc_opcodes(PowerPCCPU *cpu);
/* gdbstub.c */
void ppc_gdb_init(CPUState *cs, PowerPCCPUClass *ppc);
gchar *ppc_gdb_arch_name(CPUState *cs);
#endif /* PPC_INTERNAL_H */

View File

@ -10,6 +10,18 @@
#include "kvm_ppc.h"
#include "exec/helper-proto.h"
static void post_load_update_msr(CPUPPCState *env)
{
target_ulong msr = env->msr;
/*
* Invalidate all supported msr bits except MSR_TGPR/MSR_HVB
* before restoring. Note that this recomputes hflags.
*/
env->msr ^= env->msr_mask & ~((1ULL << MSR_TGPR) | MSR_HVB);
ppc_store_msr(env, msr);
}
static int cpu_load_old(QEMUFile *f, void *opaque, int version_id)
{
PowerPCCPU *cpu = opaque;
@ -111,13 +123,12 @@ static int cpu_load_old(QEMUFile *f, void *opaque, int version_id)
qemu_get_betls(f, &env->ivpr_mask);
qemu_get_betls(f, &env->hreset_vector);
qemu_get_betls(f, &env->nip);
qemu_get_betls(f, &env->hflags);
qemu_get_betls(f, &env->hflags_nmsr);
qemu_get_sbetl(f); /* Discard unused hflags */
qemu_get_sbetl(f); /* Discard unused hflags_nmsr */
qemu_get_sbe32(f); /* Discard unused mmu_idx */
qemu_get_sbe32(f); /* Discard unused power_mode */
/* Recompute mmu indices */
hreg_compute_mem_idx(env);
post_load_update_msr(env);
return 0;
}
@ -304,6 +315,10 @@ static int cpu_pre_save(void *opaque)
}
}
/* Retain migration compatibility for pre 6.0 for 601 machines. */
env->hflags_compat_nmsr = (env->flags & POWERPC_FLAG_HID0_LE
? env->hflags & MSR_LE : 0);
return 0;
}
@ -333,7 +348,6 @@ static int cpu_post_load(void *opaque, int version_id)
PowerPCCPU *cpu = opaque;
CPUPPCState *env = &cpu->env;
int i;
target_ulong msr;
/*
* If we're operating in compat mode, we should be ok as long as
@ -407,15 +421,7 @@ static int cpu_post_load(void *opaque, int version_id)
ppc_store_sdr1(env, env->spr[SPR_SDR1]);
}
/*
* Invalidate all supported msr bits except MSR_TGPR/MSR_HVB
* before restoring
*/
msr = env->msr;
env->msr ^= env->msr_mask & ~((1ULL << MSR_TGPR) | MSR_HVB);
ppc_store_msr(env, msr);
hreg_compute_mem_idx(env);
post_load_update_msr(env);
return 0;
}
@ -825,9 +831,8 @@ const VMStateDescription vmstate_ppc_cpu = {
/* Supervisor mode architected state */
VMSTATE_UINTTL(env.msr, PowerPCCPU),
/* Internal state */
VMSTATE_UINTTL(env.hflags_nmsr, PowerPCCPU),
/* FIXME: access_type? */
/* Backward compatible internal state */
VMSTATE_UINTTL(env.hflags_compat_nmsr, PowerPCCPU),
/* Sanity checking */
VMSTATE_UINTTL_TEST(mig_msr_mask, PowerPCCPU, cpu_pre_2_8_migration),

View File

@ -278,7 +278,7 @@ static void dcbz_common(CPUPPCState *env, target_ulong addr,
target_ulong mask, dcbz_size = env->dcache_line_size;
uint32_t i;
void *haddr;
int mmu_idx = epid ? PPC_TLB_EPID_STORE : env->dmmu_idx;
int mmu_idx = epid ? PPC_TLB_EPID_STORE : cpu_mmu_index(env, false);
#if defined(TARGET_PPC64)
/* Check for dcbz vs dcbzl on 970 */

View File

@ -6,6 +6,7 @@ ppc_ss.add(files(
'excp_helper.c',
'fpu_helper.c',
'gdbstub.c',
'helper_regs.c',
'int_helper.c',
'mem_helper.c',
'misc_helper.c',

View File

@ -194,16 +194,14 @@ void helper_store_hid0_601(CPUPPCState *env, target_ulong val)
target_ulong hid0;
hid0 = env->spr[SPR_HID0];
env->spr[SPR_HID0] = (uint32_t)val;
if ((val ^ hid0) & 0x00000008) {
/* Change current endianness */
env->hflags &= ~(1 << MSR_LE);
env->hflags_nmsr &= ~(1 << MSR_LE);
env->hflags_nmsr |= (1 << MSR_LE) & (((val >> 3) & 1) << MSR_LE);
env->hflags |= env->hflags_nmsr;
qemu_log("%s: set endianness to %c => " TARGET_FMT_lx "\n", __func__,
hreg_compute_hflags(env);
qemu_log("%s: set endianness to %c => %08x\n", __func__,
val & 0x8 ? 'l' : 'b', env->hflags);
}
env->spr[SPR_HID0] = (uint32_t)val;
}
void helper_store_403_pbr(CPUPPCState *env, uint32_t num, target_ulong value)
@ -217,6 +215,9 @@ void helper_store_403_pbr(CPUPPCState *env, uint32_t num, target_ulong value)
void helper_store_40x_dbcr0(CPUPPCState *env, target_ulong val)
{
/* Bits 26 & 27 affect single-stepping. */
hreg_compute_hflags(env);
/* Bits 28 & 29 affect reset or shutdown. */
store_40x_dbcr0(env, val);
}

View File

@ -30,6 +30,7 @@
#include "exec/log.h"
#include "hw/hw.h"
#include "mmu-book3s-v3.h"
#include "helper_regs.h"
/* #define DEBUG_SLB */
@ -1125,6 +1126,8 @@ void ppc_store_lpcr(PowerPCCPU *cpu, target_ulong val)
CPUPPCState *env = &cpu->env;
env->spr[SPR_LPCR] = val & pcc->lpcr_mask;
/* The gtse bit affects hflags */
hreg_compute_hflags(env);
}
void helper_store_lpcr(CPUPPCState *env, target_ulong val)

View File

@ -173,7 +173,6 @@ struct DisasContext {
bool vsx_enabled;
bool spe_enabled;
bool tm_enabled;
bool scv_enabled;
bool gtse;
ppc_spr_t *spr_cb; /* Needed to check rights for mfspr/mtspr */
int singlestep_enabled;
@ -4081,15 +4080,16 @@ static void gen_sc(DisasContext *ctx)
#if !defined(CONFIG_USER_ONLY)
static void gen_scv(DisasContext *ctx)
{
uint32_t lev;
uint32_t lev = (ctx->opcode >> 5) & 0x7F;
if (unlikely(!ctx->scv_enabled)) {
gen_exception_err(ctx, POWERPC_EXCP_FU, FSCR_IC_SCV);
return;
/* Set the PC back to the faulting instruction. */
if (ctx->exception == POWERPC_EXCP_NONE) {
gen_update_nip(ctx, ctx->base.pc_next - 4);
}
gen_helper_scv(cpu_env, tcg_constant_i32(lev));
lev = (ctx->opcode >> 5) & 0x7F;
gen_exception_err(ctx, POWERPC_SYSCALL_VECTORED, lev);
/* This need not be exact, just not POWERPC_EXCP_NONE */
ctx->exception = POWERPC_SYSCALL_VECTORED;
}
#endif
#endif
@ -7657,9 +7657,9 @@ void ppc_cpu_dump_state(CPUState *cs, FILE *f, int flags)
env->nip, env->lr, env->ctr, cpu_read_xer(env),
cs->cpu_index);
qemu_fprintf(f, "MSR " TARGET_FMT_lx " HID0 " TARGET_FMT_lx " HF "
TARGET_FMT_lx " iidx %d didx %d\n",
env->msr, env->spr[SPR_HID0],
env->hflags, env->immu_idx, env->dmmu_idx);
"%08x iidx %d didx %d\n",
env->msr, env->spr[SPR_HID0], env->hflags,
cpu_mmu_index(env, true), cpu_mmu_index(env, false));
#if !defined(NO_TIMER_DUMP)
qemu_fprintf(f, "TB %08" PRIu32 " %08" PRIu64
#if !defined(CONFIG_USER_ONLY)
@ -7731,7 +7731,8 @@ void ppc_cpu_dump_state(CPUState *cs, FILE *f, int flags)
#if defined(TARGET_PPC64)
if (env->excp_model == POWERPC_EXCP_POWER7 ||
env->excp_model == POWERPC_EXCP_POWER8 ||
env->excp_model == POWERPC_EXCP_POWER9) {
env->excp_model == POWERPC_EXCP_POWER9 ||
env->excp_model == POWERPC_EXCP_POWER10) {
qemu_fprintf(f, "HSRR0 " TARGET_FMT_lx " HSRR1 " TARGET_FMT_lx "\n",
env->spr[SPR_HSRR0], env->spr[SPR_HSRR1]);
}
@ -7825,6 +7826,400 @@ void ppc_cpu_dump_state(CPUState *cs, FILE *f, int flags)
#undef RFPL
}
/*****************************************************************************/
/* Opcode types */
enum {
PPC_DIRECT = 0, /* Opcode routine */
PPC_INDIRECT = 1, /* Indirect opcode table */
};
#define PPC_OPCODE_MASK 0x3
static inline int is_indirect_opcode(void *handler)
{
return ((uintptr_t)handler & PPC_OPCODE_MASK) == PPC_INDIRECT;
}
static inline opc_handler_t **ind_table(void *handler)
{
return (opc_handler_t **)((uintptr_t)handler & ~PPC_OPCODE_MASK);
}
/* Instruction table creation */
/* Opcodes tables creation */
static void fill_new_table(opc_handler_t **table, int len)
{
int i;
for (i = 0; i < len; i++) {
table[i] = &invalid_handler;
}
}
static int create_new_table(opc_handler_t **table, unsigned char idx)
{
opc_handler_t **tmp;
tmp = g_new(opc_handler_t *, PPC_CPU_INDIRECT_OPCODES_LEN);
fill_new_table(tmp, PPC_CPU_INDIRECT_OPCODES_LEN);
table[idx] = (opc_handler_t *)((uintptr_t)tmp | PPC_INDIRECT);
return 0;
}
static int insert_in_table(opc_handler_t **table, unsigned char idx,
opc_handler_t *handler)
{
if (table[idx] != &invalid_handler) {
return -1;
}
table[idx] = handler;
return 0;
}
static int register_direct_insn(opc_handler_t **ppc_opcodes,
unsigned char idx, opc_handler_t *handler)
{
if (insert_in_table(ppc_opcodes, idx, handler) < 0) {
printf("*** ERROR: opcode %02x already assigned in main "
"opcode table\n", idx);
#if defined(DO_PPC_STATISTICS) || defined(PPC_DUMP_CPU)
printf(" Registered handler '%s' - new handler '%s'\n",
ppc_opcodes[idx]->oname, handler->oname);
#endif
return -1;
}
return 0;
}
static int register_ind_in_table(opc_handler_t **table,
unsigned char idx1, unsigned char idx2,
opc_handler_t *handler)
{
if (table[idx1] == &invalid_handler) {
if (create_new_table(table, idx1) < 0) {
printf("*** ERROR: unable to create indirect table "
"idx=%02x\n", idx1);
return -1;
}
} else {
if (!is_indirect_opcode(table[idx1])) {
printf("*** ERROR: idx %02x already assigned to a direct "
"opcode\n", idx1);
#if defined(DO_PPC_STATISTICS) || defined(PPC_DUMP_CPU)
printf(" Registered handler '%s' - new handler '%s'\n",
ind_table(table[idx1])[idx2]->oname, handler->oname);
#endif
return -1;
}
}
if (handler != NULL &&
insert_in_table(ind_table(table[idx1]), idx2, handler) < 0) {
printf("*** ERROR: opcode %02x already assigned in "
"opcode table %02x\n", idx2, idx1);
#if defined(DO_PPC_STATISTICS) || defined(PPC_DUMP_CPU)
printf(" Registered handler '%s' - new handler '%s'\n",
ind_table(table[idx1])[idx2]->oname, handler->oname);
#endif
return -1;
}
return 0;
}
static int register_ind_insn(opc_handler_t **ppc_opcodes,
unsigned char idx1, unsigned char idx2,
opc_handler_t *handler)
{
return register_ind_in_table(ppc_opcodes, idx1, idx2, handler);
}
static int register_dblind_insn(opc_handler_t **ppc_opcodes,
unsigned char idx1, unsigned char idx2,
unsigned char idx3, opc_handler_t *handler)
{
if (register_ind_in_table(ppc_opcodes, idx1, idx2, NULL) < 0) {
printf("*** ERROR: unable to join indirect table idx "
"[%02x-%02x]\n", idx1, idx2);
return -1;
}
if (register_ind_in_table(ind_table(ppc_opcodes[idx1]), idx2, idx3,
handler) < 0) {
printf("*** ERROR: unable to insert opcode "
"[%02x-%02x-%02x]\n", idx1, idx2, idx3);
return -1;
}
return 0;
}
static int register_trplind_insn(opc_handler_t **ppc_opcodes,
unsigned char idx1, unsigned char idx2,
unsigned char idx3, unsigned char idx4,
opc_handler_t *handler)
{
opc_handler_t **table;
if (register_ind_in_table(ppc_opcodes, idx1, idx2, NULL) < 0) {
printf("*** ERROR: unable to join indirect table idx "
"[%02x-%02x]\n", idx1, idx2);
return -1;
}
table = ind_table(ppc_opcodes[idx1]);
if (register_ind_in_table(table, idx2, idx3, NULL) < 0) {
printf("*** ERROR: unable to join 2nd-level indirect table idx "
"[%02x-%02x-%02x]\n", idx1, idx2, idx3);
return -1;
}
table = ind_table(table[idx2]);
if (register_ind_in_table(table, idx3, idx4, handler) < 0) {
printf("*** ERROR: unable to insert opcode "
"[%02x-%02x-%02x-%02x]\n", idx1, idx2, idx3, idx4);
return -1;
}
return 0;
}
static int register_insn(opc_handler_t **ppc_opcodes, opcode_t *insn)
{
if (insn->opc2 != 0xFF) {
if (insn->opc3 != 0xFF) {
if (insn->opc4 != 0xFF) {
if (register_trplind_insn(ppc_opcodes, insn->opc1, insn->opc2,
insn->opc3, insn->opc4,
&insn->handler) < 0) {
return -1;
}
} else {
if (register_dblind_insn(ppc_opcodes, insn->opc1, insn->opc2,
insn->opc3, &insn->handler) < 0) {
return -1;
}
}
} else {
if (register_ind_insn(ppc_opcodes, insn->opc1,
insn->opc2, &insn->handler) < 0) {
return -1;
}
}
} else {
if (register_direct_insn(ppc_opcodes, insn->opc1, &insn->handler) < 0) {
return -1;
}
}
return 0;
}
static int test_opcode_table(opc_handler_t **table, int len)
{
int i, count, tmp;
for (i = 0, count = 0; i < len; i++) {
/* Consistency fixup */
if (table[i] == NULL) {
table[i] = &invalid_handler;
}
if (table[i] != &invalid_handler) {
if (is_indirect_opcode(table[i])) {
tmp = test_opcode_table(ind_table(table[i]),
PPC_CPU_INDIRECT_OPCODES_LEN);
if (tmp == 0) {
free(table[i]);
table[i] = &invalid_handler;
} else {
count++;
}
} else {
count++;
}
}
}
return count;
}
static void fix_opcode_tables(opc_handler_t **ppc_opcodes)
{
if (test_opcode_table(ppc_opcodes, PPC_CPU_OPCODES_LEN) == 0) {
printf("*** WARNING: no opcode defined !\n");
}
}
/*****************************************************************************/
void create_ppc_opcodes(PowerPCCPU *cpu, Error **errp)
{
PowerPCCPUClass *pcc = POWERPC_CPU_GET_CLASS(cpu);
opcode_t *opc;
fill_new_table(cpu->opcodes, PPC_CPU_OPCODES_LEN);
for (opc = opcodes; opc < &opcodes[ARRAY_SIZE(opcodes)]; opc++) {
if (((opc->handler.type & pcc->insns_flags) != 0) ||
((opc->handler.type2 & pcc->insns_flags2) != 0)) {
if (register_insn(cpu->opcodes, opc) < 0) {
error_setg(errp, "ERROR initializing PowerPC instruction "
"0x%02x 0x%02x 0x%02x", opc->opc1, opc->opc2,
opc->opc3);
return;
}
}
}
fix_opcode_tables(cpu->opcodes);
fflush(stdout);
fflush(stderr);
}
void destroy_ppc_opcodes(PowerPCCPU *cpu)
{
opc_handler_t **table, **table_2;
int i, j, k;
for (i = 0; i < PPC_CPU_OPCODES_LEN; i++) {
if (cpu->opcodes[i] == &invalid_handler) {
continue;
}
if (is_indirect_opcode(cpu->opcodes[i])) {
table = ind_table(cpu->opcodes[i]);
for (j = 0; j < PPC_CPU_INDIRECT_OPCODES_LEN; j++) {
if (table[j] == &invalid_handler) {
continue;
}
if (is_indirect_opcode(table[j])) {
table_2 = ind_table(table[j]);
for (k = 0; k < PPC_CPU_INDIRECT_OPCODES_LEN; k++) {
if (table_2[k] != &invalid_handler &&
is_indirect_opcode(table_2[k])) {
g_free((opc_handler_t *)((uintptr_t)table_2[k] &
~PPC_INDIRECT));
}
}
g_free((opc_handler_t *)((uintptr_t)table[j] &
~PPC_INDIRECT));
}
}
g_free((opc_handler_t *)((uintptr_t)cpu->opcodes[i] &
~PPC_INDIRECT));
}
}
}
#if defined(PPC_DUMP_CPU)
static void dump_ppc_insns(CPUPPCState *env)
{
opc_handler_t **table, *handler;
const char *p, *q;
uint8_t opc1, opc2, opc3, opc4;
printf("Instructions set:\n");
/* opc1 is 6 bits long */
for (opc1 = 0x00; opc1 < PPC_CPU_OPCODES_LEN; opc1++) {
table = env->opcodes;
handler = table[opc1];
if (is_indirect_opcode(handler)) {
/* opc2 is 5 bits long */
for (opc2 = 0; opc2 < PPC_CPU_INDIRECT_OPCODES_LEN; opc2++) {
table = env->opcodes;
handler = env->opcodes[opc1];
table = ind_table(handler);
handler = table[opc2];
if (is_indirect_opcode(handler)) {
table = ind_table(handler);
/* opc3 is 5 bits long */
for (opc3 = 0; opc3 < PPC_CPU_INDIRECT_OPCODES_LEN;
opc3++) {
handler = table[opc3];
if (is_indirect_opcode(handler)) {
table = ind_table(handler);
/* opc4 is 5 bits long */
for (opc4 = 0; opc4 < PPC_CPU_INDIRECT_OPCODES_LEN;
opc4++) {
handler = table[opc4];
if (handler->handler != &gen_invalid) {
printf("INSN: %02x %02x %02x %02x -- "
"(%02d %04d %02d) : %s\n",
opc1, opc2, opc3, opc4,
opc1, (opc3 << 5) | opc2, opc4,
handler->oname);
}
}
} else {
if (handler->handler != &gen_invalid) {
/* Special hack to properly dump SPE insns */
p = strchr(handler->oname, '_');
if (p == NULL) {
printf("INSN: %02x %02x %02x (%02d %04d) : "
"%s\n",
opc1, opc2, opc3, opc1,
(opc3 << 5) | opc2,
handler->oname);
} else {
q = "speundef";
if ((p - handler->oname) != strlen(q)
|| (memcmp(handler->oname, q, strlen(q))
!= 0)) {
/* First instruction */
printf("INSN: %02x %02x %02x"
"(%02d %04d) : %.*s\n",
opc1, opc2 << 1, opc3, opc1,
(opc3 << 6) | (opc2 << 1),
(int)(p - handler->oname),
handler->oname);
}
if (strcmp(p + 1, q) != 0) {
/* Second instruction */
printf("INSN: %02x %02x %02x "
"(%02d %04d) : %s\n", opc1,
(opc2 << 1) | 1, opc3, opc1,
(opc3 << 6) | (opc2 << 1) | 1,
p + 1);
}
}
}
}
}
} else {
if (handler->handler != &gen_invalid) {
printf("INSN: %02x %02x -- (%02d %04d) : %s\n",
opc1, opc2, opc1, opc2, handler->oname);
}
}
}
} else {
if (handler->handler != &gen_invalid) {
printf("INSN: %02x -- -- (%02d ----) : %s\n",
opc1, opc1, handler->oname);
}
}
}
}
#endif
int ppc_fixup_cpu(PowerPCCPU *cpu)
{
CPUPPCState *env = &cpu->env;
/*
* TCG doesn't (yet) emulate some groups of instructions that are
* implemented on some otherwise supported CPUs (e.g. VSX and
* decimal floating point instructions on POWER7). We remove
* unsupported instruction groups from the cpu state's instruction
* masks and hope the guest can cope. For at least the pseries
* machine, the unavailability of these instructions can be
* advertised to the guest via the device tree.
*/
if ((env->insns_flags & ~PPC_TCG_INSNS)
|| (env->insns_flags2 & ~PPC_TCG_INSNS2)) {
warn_report("Disabling some instructions which are not "
"emulated by TCG (0x%" PRIx64 ", 0x%" PRIx64 ")",
env->insns_flags & ~PPC_TCG_INSNS,
env->insns_flags2 & ~PPC_TCG_INSNS2);
}
env->insns_flags &= PPC_TCG_INSNS;
env->insns_flags2 &= PPC_TCG_INSNS2;
return 0;
}
void ppc_cpu_dump_statistics(CPUState *cs, int flags)
{
#if defined(DO_PPC_STATISTICS)
@ -7879,87 +8274,47 @@ static void ppc_tr_init_disas_context(DisasContextBase *dcbase, CPUState *cs)
{
DisasContext *ctx = container_of(dcbase, DisasContext, base);
CPUPPCState *env = cs->env_ptr;
uint32_t hflags = ctx->base.tb->flags;
int bound;
ctx->exception = POWERPC_EXCP_NONE;
ctx->spr_cb = env->spr_cb;
ctx->pr = msr_pr;
ctx->mem_idx = env->dmmu_idx;
ctx->dr = msr_dr;
#if !defined(CONFIG_USER_ONLY)
ctx->hv = msr_hv || !env->has_hv_mode;
#endif
ctx->pr = (hflags >> HFLAGS_PR) & 1;
ctx->mem_idx = (hflags >> HFLAGS_DMMU_IDX) & 7;
ctx->dr = (hflags >> HFLAGS_DR) & 1;
ctx->hv = (hflags >> HFLAGS_HV) & 1;
ctx->insns_flags = env->insns_flags;
ctx->insns_flags2 = env->insns_flags2;
ctx->access_type = -1;
ctx->need_access_type = !mmu_is_64bit(env->mmu_model);
ctx->le_mode = !!(env->hflags & (1 << MSR_LE));
ctx->le_mode = (hflags >> HFLAGS_LE) & 1;
ctx->default_tcg_memop_mask = ctx->le_mode ? MO_LE : MO_BE;
ctx->flags = env->flags;
#if defined(TARGET_PPC64)
ctx->sf_mode = msr_is_64bit(env, env->msr);
ctx->sf_mode = (hflags >> HFLAGS_64) & 1;
ctx->has_cfar = !!(env->flags & POWERPC_FLAG_CFAR);
#endif
ctx->lazy_tlb_flush = env->mmu_model == POWERPC_MMU_32B
|| env->mmu_model == POWERPC_MMU_601
|| env->mmu_model & POWERPC_MMU_64;
ctx->fpu_enabled = !!msr_fp;
if ((env->flags & POWERPC_FLAG_SPE) && msr_spe) {
ctx->spe_enabled = !!msr_spe;
} else {
ctx->spe_enabled = false;
}
if ((env->flags & POWERPC_FLAG_VRE) && msr_vr) {
ctx->altivec_enabled = !!msr_vr;
} else {
ctx->altivec_enabled = false;
}
if ((env->flags & POWERPC_FLAG_VSX) && msr_vsx) {
ctx->vsx_enabled = !!msr_vsx;
} else {
ctx->vsx_enabled = false;
}
if ((env->flags & POWERPC_FLAG_SCV)
&& (env->spr[SPR_FSCR] & (1ull << FSCR_SCV))) {
ctx->scv_enabled = true;
} else {
ctx->scv_enabled = false;
}
#if defined(TARGET_PPC64)
if ((env->flags & POWERPC_FLAG_TM) && msr_tm) {
ctx->tm_enabled = !!msr_tm;
} else {
ctx->tm_enabled = false;
}
#endif
ctx->gtse = !!(env->spr[SPR_LPCR] & LPCR_GTSE);
if ((env->flags & POWERPC_FLAG_SE) && msr_se) {
ctx->singlestep_enabled = CPU_SINGLE_STEP;
} else {
ctx->singlestep_enabled = 0;
}
if ((env->flags & POWERPC_FLAG_BE) && msr_be) {
ctx->singlestep_enabled |= CPU_BRANCH_STEP;
}
if ((env->flags & POWERPC_FLAG_DE) && msr_de) {
ctx->singlestep_enabled = 0;
target_ulong dbcr0 = env->spr[SPR_BOOKE_DBCR0];
if (dbcr0 & DBCR0_ICMP) {
ctx->singlestep_enabled |= CPU_SINGLE_STEP;
}
if (dbcr0 & DBCR0_BRT) {
ctx->singlestep_enabled |= CPU_BRANCH_STEP;
}
ctx->fpu_enabled = (hflags >> HFLAGS_FP) & 1;
ctx->spe_enabled = (hflags >> HFLAGS_SPE) & 1;
ctx->altivec_enabled = (hflags >> HFLAGS_VR) & 1;
ctx->vsx_enabled = (hflags >> HFLAGS_VSX) & 1;
ctx->tm_enabled = (hflags >> HFLAGS_TM) & 1;
ctx->gtse = (hflags >> HFLAGS_GTSE) & 1;
ctx->singlestep_enabled = 0;
if ((hflags >> HFLAGS_SE) & 1) {
ctx->singlestep_enabled |= CPU_SINGLE_STEP;
}
if ((hflags >> HFLAGS_BE) & 1) {
ctx->singlestep_enabled |= CPU_BRANCH_STEP;
}
if (unlikely(ctx->base.singlestep_enabled)) {
ctx->singlestep_enabled |= GDBSTUB_SINGLE_STEP;
}
#if defined(DO_SINGLE_STEP) && 0
/* Single step trace mode */
msr_se = 1;
#endif
bound = -(ctx->base.pc_first | TARGET_PAGE_MASK) / 4;
ctx->base.max_insns = MIN(ctx->base.max_insns, bound);

View File

@ -42,7 +42,6 @@
#include "fpu/softfloat.h"
#include "qapi/qapi-commands-machine-target.h"
/* #define PPC_DUMP_CPU */
/* #define PPC_DEBUG_SPR */
/* #define PPC_DUMP_SPR_ACCESSES */
/* #define USE_APPLE_GDB */
@ -721,104 +720,98 @@ static inline void vscr_init(CPUPPCState *env, uint32_t val)
helper_mtvscr(env, val);
}
#ifdef CONFIG_USER_ONLY
#define spr_register_kvm(env, num, name, uea_read, uea_write, \
oea_read, oea_write, one_reg_id, initial_value) \
_spr_register(env, num, name, uea_read, uea_write, initial_value)
#define spr_register_kvm_hv(env, num, name, uea_read, uea_write, \
oea_read, oea_write, hea_read, hea_write, \
one_reg_id, initial_value) \
_spr_register(env, num, name, uea_read, uea_write, initial_value)
/**
* _spr_register
*
* Register an SPR with all the callbacks required for tcg,
* and the ID number for KVM.
*
* The reason for the conditional compilation is that the tcg functions
* may be compiled out, and the system kvm header may not be available
* for supplying the ID numbers. This is ugly, but the best we can do.
*/
#ifdef CONFIG_TCG
# define USR_ARG(X) X,
# ifdef CONFIG_USER_ONLY
# define SYS_ARG(X)
# else
# define SYS_ARG(X) X,
# endif
#else
#if !defined(CONFIG_KVM)
#define spr_register_kvm(env, num, name, uea_read, uea_write, \
oea_read, oea_write, one_reg_id, initial_value) \
_spr_register(env, num, name, uea_read, uea_write, \
oea_read, oea_write, oea_read, oea_write, initial_value)
#define spr_register_kvm_hv(env, num, name, uea_read, uea_write, \
oea_read, oea_write, hea_read, hea_write, \
one_reg_id, initial_value) \
_spr_register(env, num, name, uea_read, uea_write, \
oea_read, oea_write, hea_read, hea_write, initial_value)
# define USR_ARG(X)
# define SYS_ARG(X)
#endif
#ifdef CONFIG_KVM
# define KVM_ARG(X) X,
#else
#define spr_register_kvm(env, num, name, uea_read, uea_write, \
oea_read, oea_write, one_reg_id, initial_value) \
_spr_register(env, num, name, uea_read, uea_write, \
oea_read, oea_write, oea_read, oea_write, \
one_reg_id, initial_value)
#define spr_register_kvm_hv(env, num, name, uea_read, uea_write, \
oea_read, oea_write, hea_read, hea_write, \
one_reg_id, initial_value) \
_spr_register(env, num, name, uea_read, uea_write, \
oea_read, oea_write, hea_read, hea_write, \
one_reg_id, initial_value)
#endif
# define KVM_ARG(X)
#endif
#define spr_register(env, num, name, uea_read, uea_write, \
oea_read, oea_write, initial_value) \
spr_register_kvm(env, num, name, uea_read, uea_write, \
oea_read, oea_write, 0, initial_value)
typedef void spr_callback(DisasContext *, int, int);
#define spr_register_hv(env, num, name, uea_read, uea_write, \
oea_read, oea_write, hea_read, hea_write, \
initial_value) \
spr_register_kvm_hv(env, num, name, uea_read, uea_write, \
oea_read, oea_write, hea_read, hea_write, \
0, initial_value)
static inline void _spr_register(CPUPPCState *env, int num,
const char *name,
void (*uea_read)(DisasContext *ctx,
int gprn, int sprn),
void (*uea_write)(DisasContext *ctx,
int sprn, int gprn),
#if !defined(CONFIG_USER_ONLY)
void (*oea_read)(DisasContext *ctx,
int gprn, int sprn),
void (*oea_write)(DisasContext *ctx,
int sprn, int gprn),
void (*hea_read)(DisasContext *opaque,
int gprn, int sprn),
void (*hea_write)(DisasContext *opaque,
int sprn, int gprn),
#endif
#if defined(CONFIG_KVM)
uint64_t one_reg_id,
#endif
target_ulong initial_value)
static void _spr_register(CPUPPCState *env, int num, const char *name,
USR_ARG(spr_callback *uea_read)
USR_ARG(spr_callback *uea_write)
SYS_ARG(spr_callback *oea_read)
SYS_ARG(spr_callback *oea_write)
SYS_ARG(spr_callback *hea_read)
SYS_ARG(spr_callback *hea_write)
KVM_ARG(uint64_t one_reg_id)
target_ulong initial_value)
{
ppc_spr_t *spr;
ppc_spr_t *spr = &env->spr_cb[num];
/* No SPR should be registered twice. */
assert(spr->name == NULL);
assert(name != NULL);
spr = &env->spr_cb[num];
if (spr->name != NULL || env->spr[num] != 0x00000000 ||
#if !defined(CONFIG_USER_ONLY)
spr->oea_read != NULL || spr->oea_write != NULL ||
#endif
spr->uea_read != NULL || spr->uea_write != NULL) {
printf("Error: Trying to register SPR %d (%03x) twice !\n", num, num);
exit(1);
}
#if defined(PPC_DEBUG_SPR)
printf("*** register spr %d (%03x) %s val " TARGET_FMT_lx "\n", num, num,
name, initial_value);
#endif
spr->name = name;
spr->default_value = initial_value;
env->spr[num] = initial_value;
#ifdef CONFIG_TCG
spr->uea_read = uea_read;
spr->uea_write = uea_write;
#if !defined(CONFIG_USER_ONLY)
# ifndef CONFIG_USER_ONLY
spr->oea_read = oea_read;
spr->oea_write = oea_write;
spr->hea_read = hea_read;
spr->hea_write = hea_write;
# endif
#endif
#if defined(CONFIG_KVM)
spr->one_reg_id = one_reg_id,
#ifdef CONFIG_KVM
spr->one_reg_id = one_reg_id;
#endif
env->spr[num] = spr->default_value = initial_value;
}
/* spr_register_kvm_hv passes all required arguments. */
#define spr_register_kvm_hv(env, num, name, uea_read, uea_write, \
oea_read, oea_write, hea_read, hea_write, \
one_reg_id, initial_value) \
_spr_register(env, num, name, \
USR_ARG(uea_read) USR_ARG(uea_write) \
SYS_ARG(oea_read) SYS_ARG(oea_write) \
SYS_ARG(hea_read) SYS_ARG(hea_write) \
KVM_ARG(one_reg_id) initial_value)
/* spr_register_kvm duplicates the oea callbacks to the hea callbacks. */
#define spr_register_kvm(env, num, name, uea_read, uea_write, \
oea_read, oea_write, one_reg_id, ival) \
spr_register_kvm_hv(env, num, name, uea_read, uea_write, oea_read, \
oea_write, oea_read, oea_write, one_reg_id, ival)
/* spr_register_hv and spr_register are similar, except there is no kvm id. */
#define spr_register_hv(env, num, name, uea_read, uea_write, \
oea_read, oea_write, hea_read, hea_write, ival) \
spr_register_kvm_hv(env, num, name, uea_read, uea_write, oea_read, \
oea_write, hea_read, hea_write, 0, ival)
#define spr_register(env, num, name, uea_read, uea_write, \
oea_read, oea_write, ival) \
spr_register_kvm(env, num, name, uea_read, uea_write, \
oea_read, oea_write, 0, ival)
/* Generic PowerPC SPRs */
static void gen_spr_generic(CPUPPCState *env)
{
@ -1700,8 +1693,6 @@ static void gen_spr_74xx(CPUPPCState *env)
SPR_NOACCESS, SPR_NOACCESS,
&spr_read_generic, spr_access_nop,
0x00000000);
/* Not strictly an SPR */
vscr_init(env, 0x00010000);
}
static void gen_l3_ctrl(CPUPPCState *env)
@ -3457,7 +3448,7 @@ static void init_excp_POWER9(CPUPPCState *env)
#if !defined(CONFIG_USER_ONLY)
env->excp_vectors[POWERPC_EXCP_HVIRT] = 0x00000EA0;
env->excp_vectors[POWERPC_EXCP_SYSCALL_VECTORED] = 0x00000000;
env->excp_vectors[POWERPC_EXCP_SYSCALL_VECTORED] = 0x00017000;
#endif
}
@ -5441,7 +5432,7 @@ POWERPC_FAMILY(601)(ObjectClass *oc, void *data)
pcc->excp_model = POWERPC_EXCP_601;
pcc->bus_model = PPC_FLAGS_INPUT_6xx;
pcc->bfd_mach = bfd_mach_ppc_601;
pcc->flags = POWERPC_FLAG_SE | POWERPC_FLAG_RTC_CLK;
pcc->flags = POWERPC_FLAG_SE | POWERPC_FLAG_RTC_CLK | POWERPC_FLAG_HID0_LE;
}
#define POWERPC_MSRR_601v (0x0000000000001040ULL)
@ -5485,7 +5476,7 @@ POWERPC_FAMILY(601v)(ObjectClass *oc, void *data)
#endif
pcc->bus_model = PPC_FLAGS_INPUT_6xx;
pcc->bfd_mach = bfd_mach_ppc_601;
pcc->flags = POWERPC_FLAG_SE | POWERPC_FLAG_RTC_CLK;
pcc->flags = POWERPC_FLAG_SE | POWERPC_FLAG_RTC_CLK | POWERPC_FLAG_HID0_LE;
}
static void init_proc_602(CPUPPCState *env)
@ -6625,6 +6616,7 @@ static void init_proc_7400(CPUPPCState *env)
gen_tbl(env);
/* 74xx specific SPR */
gen_spr_74xx(env);
vscr_init(env, 0x00010000);
/* XXX : not implemented */
spr_register(env, SPR_UBAMR, "UBAMR",
&spr_read_ureg, SPR_NOACCESS,
@ -6704,6 +6696,7 @@ static void init_proc_7410(CPUPPCState *env)
gen_tbl(env);
/* 74xx specific SPR */
gen_spr_74xx(env);
vscr_init(env, 0x00010000);
/* XXX : not implemented */
spr_register(env, SPR_UBAMR, "UBAMR",
&spr_read_ureg, SPR_NOACCESS,
@ -6789,6 +6782,7 @@ static void init_proc_7440(CPUPPCState *env)
gen_tbl(env);
/* 74xx specific SPR */
gen_spr_74xx(env);
vscr_init(env, 0x00010000);
/* XXX : not implemented */
spr_register(env, SPR_UBAMR, "UBAMR",
&spr_read_ureg, SPR_NOACCESS,
@ -6897,6 +6891,7 @@ static void init_proc_7450(CPUPPCState *env)
gen_tbl(env);
/* 74xx specific SPR */
gen_spr_74xx(env);
vscr_init(env, 0x00010000);
/* Level 3 cache control */
gen_l3_ctrl(env);
/* L3ITCR1 */
@ -7031,6 +7026,7 @@ static void init_proc_7445(CPUPPCState *env)
gen_tbl(env);
/* 74xx specific SPR */
gen_spr_74xx(env);
vscr_init(env, 0x00010000);
/* LDSTCR */
/* XXX : not implemented */
spr_register(env, SPR_LDSTCR, "LDSTCR",
@ -7168,6 +7164,7 @@ static void init_proc_7455(CPUPPCState *env)
gen_tbl(env);
/* 74xx specific SPR */
gen_spr_74xx(env);
vscr_init(env, 0x00010000);
/* Level 3 cache control */
gen_l3_ctrl(env);
/* LDSTCR */
@ -7307,6 +7304,7 @@ static void init_proc_7457(CPUPPCState *env)
gen_tbl(env);
/* 74xx specific SPR */
gen_spr_74xx(env);
vscr_init(env, 0x00010000);
/* Level 3 cache control */
gen_l3_ctrl(env);
/* L3ITCR1 */
@ -7470,6 +7468,7 @@ static void init_proc_e600(CPUPPCState *env)
gen_tbl(env);
/* 74xx specific SPR */
gen_spr_74xx(env);
vscr_init(env, 0x00010000);
/* XXX : not implemented */
spr_register(env, SPR_UBAMR, "UBAMR",
&spr_read_ureg, SPR_NOACCESS,
@ -7720,11 +7719,6 @@ static void gen_spr_book3s_altivec(CPUPPCState *env)
&spr_read_generic, &spr_write_generic,
KVM_REG_PPC_VRSAVE, 0x00000000);
/*
* Can't find information on what this should be on reset. This
* value is the one used by 74xx processors.
*/
vscr_init(env, 0x00010000);
}
static void gen_spr_book3s_dbg(CPUPPCState *env)
@ -7748,12 +7742,12 @@ static void gen_spr_book3s_dbg(CPUPPCState *env)
static void gen_spr_book3s_207_dbg(CPUPPCState *env)
{
spr_register_kvm_hv(env, SPR_DAWR, "DAWR",
spr_register_kvm_hv(env, SPR_DAWR0, "DAWR0",
SPR_NOACCESS, SPR_NOACCESS,
SPR_NOACCESS, SPR_NOACCESS,
&spr_read_generic, &spr_write_generic,
KVM_REG_PPC_DAWR, 0x00000000);
spr_register_kvm_hv(env, SPR_DAWRX, "DAWRX",
spr_register_kvm_hv(env, SPR_DAWRX0, "DAWRX0",
SPR_NOACCESS, SPR_NOACCESS,
SPR_NOACCESS, SPR_NOACCESS,
&spr_read_generic, &spr_write_generic,
@ -8422,6 +8416,11 @@ static void init_proc_book3s_common(CPUPPCState *env)
gen_spr_book3s_pmu_sup(env);
gen_spr_book3s_pmu_user(env);
gen_spr_book3s_ctrl(env);
/*
* Can't find information on what this should be on reset. This
* value is the one used by 74xx processors.
*/
vscr_init(env, 0x00010000);
}
static void init_proc_970(CPUPPCState *env)
@ -9317,13 +9316,13 @@ POWERPC_FAMILY(POWER10)(ObjectClass *oc, void *data)
pcc->radix_page_info = &POWER10_radix_page_info;
pcc->lrg_decr_bits = 56;
#endif
pcc->excp_model = POWERPC_EXCP_POWER9;
pcc->excp_model = POWERPC_EXCP_POWER10;
pcc->bus_model = PPC_FLAGS_INPUT_POWER9;
pcc->bfd_mach = bfd_mach_ppc64;
pcc->flags = POWERPC_FLAG_VRE | POWERPC_FLAG_SE |
POWERPC_FLAG_BE | POWERPC_FLAG_PMM |
POWERPC_FLAG_BUS_CLK | POWERPC_FLAG_CFAR |
POWERPC_FLAG_VSX | POWERPC_FLAG_TM;
POWERPC_FLAG_VSX | POWERPC_FLAG_TM | POWERPC_FLAG_SCV;
pcc->l1_dcache_size = 0x8000;
pcc->l1_icache_size = 0x8000;
pcc->interrupts_big_endian = ppc_cpu_interrupts_big_endian_lpcr;
@ -9560,590 +9559,6 @@ static void dump_ppc_sprs(CPUPPCState *env)
}
#endif
/*****************************************************************************/
/* Opcode types */
enum {
PPC_DIRECT = 0, /* Opcode routine */
PPC_INDIRECT = 1, /* Indirect opcode table */
};
#define PPC_OPCODE_MASK 0x3
static inline int is_indirect_opcode(void *handler)
{
return ((uintptr_t)handler & PPC_OPCODE_MASK) == PPC_INDIRECT;
}
static inline opc_handler_t **ind_table(void *handler)
{
return (opc_handler_t **)((uintptr_t)handler & ~PPC_OPCODE_MASK);
}
/* Instruction table creation */
/* Opcodes tables creation */
static void fill_new_table(opc_handler_t **table, int len)
{
int i;
for (i = 0; i < len; i++) {
table[i] = &invalid_handler;
}
}
static int create_new_table(opc_handler_t **table, unsigned char idx)
{
opc_handler_t **tmp;
tmp = g_new(opc_handler_t *, PPC_CPU_INDIRECT_OPCODES_LEN);
fill_new_table(tmp, PPC_CPU_INDIRECT_OPCODES_LEN);
table[idx] = (opc_handler_t *)((uintptr_t)tmp | PPC_INDIRECT);
return 0;
}
static int insert_in_table(opc_handler_t **table, unsigned char idx,
opc_handler_t *handler)
{
if (table[idx] != &invalid_handler) {
return -1;
}
table[idx] = handler;
return 0;
}
static int register_direct_insn(opc_handler_t **ppc_opcodes,
unsigned char idx, opc_handler_t *handler)
{
if (insert_in_table(ppc_opcodes, idx, handler) < 0) {
printf("*** ERROR: opcode %02x already assigned in main "
"opcode table\n", idx);
#if defined(DO_PPC_STATISTICS) || defined(PPC_DUMP_CPU)
printf(" Registered handler '%s' - new handler '%s'\n",
ppc_opcodes[idx]->oname, handler->oname);
#endif
return -1;
}
return 0;
}
static int register_ind_in_table(opc_handler_t **table,
unsigned char idx1, unsigned char idx2,
opc_handler_t *handler)
{
if (table[idx1] == &invalid_handler) {
if (create_new_table(table, idx1) < 0) {
printf("*** ERROR: unable to create indirect table "
"idx=%02x\n", idx1);
return -1;
}
} else {
if (!is_indirect_opcode(table[idx1])) {
printf("*** ERROR: idx %02x already assigned to a direct "
"opcode\n", idx1);
#if defined(DO_PPC_STATISTICS) || defined(PPC_DUMP_CPU)
printf(" Registered handler '%s' - new handler '%s'\n",
ind_table(table[idx1])[idx2]->oname, handler->oname);
#endif
return -1;
}
}
if (handler != NULL &&
insert_in_table(ind_table(table[idx1]), idx2, handler) < 0) {
printf("*** ERROR: opcode %02x already assigned in "
"opcode table %02x\n", idx2, idx1);
#if defined(DO_PPC_STATISTICS) || defined(PPC_DUMP_CPU)
printf(" Registered handler '%s' - new handler '%s'\n",
ind_table(table[idx1])[idx2]->oname, handler->oname);
#endif
return -1;
}
return 0;
}
static int register_ind_insn(opc_handler_t **ppc_opcodes,
unsigned char idx1, unsigned char idx2,
opc_handler_t *handler)
{
return register_ind_in_table(ppc_opcodes, idx1, idx2, handler);
}
static int register_dblind_insn(opc_handler_t **ppc_opcodes,
unsigned char idx1, unsigned char idx2,
unsigned char idx3, opc_handler_t *handler)
{
if (register_ind_in_table(ppc_opcodes, idx1, idx2, NULL) < 0) {
printf("*** ERROR: unable to join indirect table idx "
"[%02x-%02x]\n", idx1, idx2);
return -1;
}
if (register_ind_in_table(ind_table(ppc_opcodes[idx1]), idx2, idx3,
handler) < 0) {
printf("*** ERROR: unable to insert opcode "
"[%02x-%02x-%02x]\n", idx1, idx2, idx3);
return -1;
}
return 0;
}
static int register_trplind_insn(opc_handler_t **ppc_opcodes,
unsigned char idx1, unsigned char idx2,
unsigned char idx3, unsigned char idx4,
opc_handler_t *handler)
{
opc_handler_t **table;
if (register_ind_in_table(ppc_opcodes, idx1, idx2, NULL) < 0) {
printf("*** ERROR: unable to join indirect table idx "
"[%02x-%02x]\n", idx1, idx2);
return -1;
}
table = ind_table(ppc_opcodes[idx1]);
if (register_ind_in_table(table, idx2, idx3, NULL) < 0) {
printf("*** ERROR: unable to join 2nd-level indirect table idx "
"[%02x-%02x-%02x]\n", idx1, idx2, idx3);
return -1;
}
table = ind_table(table[idx2]);
if (register_ind_in_table(table, idx3, idx4, handler) < 0) {
printf("*** ERROR: unable to insert opcode "
"[%02x-%02x-%02x-%02x]\n", idx1, idx2, idx3, idx4);
return -1;
}
return 0;
}
static int register_insn(opc_handler_t **ppc_opcodes, opcode_t *insn)
{
if (insn->opc2 != 0xFF) {
if (insn->opc3 != 0xFF) {
if (insn->opc4 != 0xFF) {
if (register_trplind_insn(ppc_opcodes, insn->opc1, insn->opc2,
insn->opc3, insn->opc4,
&insn->handler) < 0) {
return -1;
}
} else {
if (register_dblind_insn(ppc_opcodes, insn->opc1, insn->opc2,
insn->opc3, &insn->handler) < 0) {
return -1;
}
}
} else {
if (register_ind_insn(ppc_opcodes, insn->opc1,
insn->opc2, &insn->handler) < 0) {
return -1;
}
}
} else {
if (register_direct_insn(ppc_opcodes, insn->opc1, &insn->handler) < 0) {
return -1;
}
}
return 0;
}
static int test_opcode_table(opc_handler_t **table, int len)
{
int i, count, tmp;
for (i = 0, count = 0; i < len; i++) {
/* Consistency fixup */
if (table[i] == NULL) {
table[i] = &invalid_handler;
}
if (table[i] != &invalid_handler) {
if (is_indirect_opcode(table[i])) {
tmp = test_opcode_table(ind_table(table[i]),
PPC_CPU_INDIRECT_OPCODES_LEN);
if (tmp == 0) {
free(table[i]);
table[i] = &invalid_handler;
} else {
count++;
}
} else {
count++;
}
}
}
return count;
}
static void fix_opcode_tables(opc_handler_t **ppc_opcodes)
{
if (test_opcode_table(ppc_opcodes, PPC_CPU_OPCODES_LEN) == 0) {
printf("*** WARNING: no opcode defined !\n");
}
}
/*****************************************************************************/
static void create_ppc_opcodes(PowerPCCPU *cpu, Error **errp)
{
PowerPCCPUClass *pcc = POWERPC_CPU_GET_CLASS(cpu);
opcode_t *opc;
fill_new_table(cpu->opcodes, PPC_CPU_OPCODES_LEN);
for (opc = opcodes; opc < &opcodes[ARRAY_SIZE(opcodes)]; opc++) {
if (((opc->handler.type & pcc->insns_flags) != 0) ||
((opc->handler.type2 & pcc->insns_flags2) != 0)) {
if (register_insn(cpu->opcodes, opc) < 0) {
error_setg(errp, "ERROR initializing PowerPC instruction "
"0x%02x 0x%02x 0x%02x", opc->opc1, opc->opc2,
opc->opc3);
return;
}
}
}
fix_opcode_tables(cpu->opcodes);
fflush(stdout);
fflush(stderr);
}
#if defined(PPC_DUMP_CPU)
static void dump_ppc_insns(CPUPPCState *env)
{
opc_handler_t **table, *handler;
const char *p, *q;
uint8_t opc1, opc2, opc3, opc4;
printf("Instructions set:\n");
/* opc1 is 6 bits long */
for (opc1 = 0x00; opc1 < PPC_CPU_OPCODES_LEN; opc1++) {
table = env->opcodes;
handler = table[opc1];
if (is_indirect_opcode(handler)) {
/* opc2 is 5 bits long */
for (opc2 = 0; opc2 < PPC_CPU_INDIRECT_OPCODES_LEN; opc2++) {
table = env->opcodes;
handler = env->opcodes[opc1];
table = ind_table(handler);
handler = table[opc2];
if (is_indirect_opcode(handler)) {
table = ind_table(handler);
/* opc3 is 5 bits long */
for (opc3 = 0; opc3 < PPC_CPU_INDIRECT_OPCODES_LEN;
opc3++) {
handler = table[opc3];
if (is_indirect_opcode(handler)) {
table = ind_table(handler);
/* opc4 is 5 bits long */
for (opc4 = 0; opc4 < PPC_CPU_INDIRECT_OPCODES_LEN;
opc4++) {
handler = table[opc4];
if (handler->handler != &gen_invalid) {
printf("INSN: %02x %02x %02x %02x -- "
"(%02d %04d %02d) : %s\n",
opc1, opc2, opc3, opc4,
opc1, (opc3 << 5) | opc2, opc4,
handler->oname);
}
}
} else {
if (handler->handler != &gen_invalid) {
/* Special hack to properly dump SPE insns */
p = strchr(handler->oname, '_');
if (p == NULL) {
printf("INSN: %02x %02x %02x (%02d %04d) : "
"%s\n",
opc1, opc2, opc3, opc1,
(opc3 << 5) | opc2,
handler->oname);
} else {
q = "speundef";
if ((p - handler->oname) != strlen(q)
|| (memcmp(handler->oname, q, strlen(q))
!= 0)) {
/* First instruction */
printf("INSN: %02x %02x %02x"
"(%02d %04d) : %.*s\n",
opc1, opc2 << 1, opc3, opc1,
(opc3 << 6) | (opc2 << 1),
(int)(p - handler->oname),
handler->oname);
}
if (strcmp(p + 1, q) != 0) {
/* Second instruction */
printf("INSN: %02x %02x %02x "
"(%02d %04d) : %s\n", opc1,
(opc2 << 1) | 1, opc3, opc1,
(opc3 << 6) | (opc2 << 1) | 1,
p + 1);
}
}
}
}
}
} else {
if (handler->handler != &gen_invalid) {
printf("INSN: %02x %02x -- (%02d %04d) : %s\n",
opc1, opc2, opc1, opc2, handler->oname);
}
}
}
} else {
if (handler->handler != &gen_invalid) {
printf("INSN: %02x -- -- (%02d ----) : %s\n",
opc1, opc1, handler->oname);
}
}
}
}
#endif
static bool avr_need_swap(CPUPPCState *env)
{
#ifdef HOST_WORDS_BIGENDIAN
return msr_le;
#else
return !msr_le;
#endif
}
#if !defined(CONFIG_USER_ONLY)
static int gdb_find_spr_idx(CPUPPCState *env, int n)
{
int i;
for (i = 0; i < ARRAY_SIZE(env->spr_cb); i++) {
ppc_spr_t *spr = &env->spr_cb[i];
if (spr->name && spr->gdb_id == n) {
return i;
}
}
return -1;
}
static int gdb_get_spr_reg(CPUPPCState *env, GByteArray *buf, int n)
{
int reg;
int len;
reg = gdb_find_spr_idx(env, n);
if (reg < 0) {
return 0;
}
len = TARGET_LONG_SIZE;
gdb_get_regl(buf, env->spr[reg]);
ppc_maybe_bswap_register(env, gdb_get_reg_ptr(buf, len), len);
return len;
}
static int gdb_set_spr_reg(CPUPPCState *env, uint8_t *mem_buf, int n)
{
int reg;
int len;
reg = gdb_find_spr_idx(env, n);
if (reg < 0) {
return 0;
}
len = TARGET_LONG_SIZE;
ppc_maybe_bswap_register(env, mem_buf, len);
env->spr[reg] = ldn_p(mem_buf, len);
return len;
}
#endif
static int gdb_get_float_reg(CPUPPCState *env, GByteArray *buf, int n)
{
uint8_t *mem_buf;
if (n < 32) {
gdb_get_reg64(buf, *cpu_fpr_ptr(env, n));
mem_buf = gdb_get_reg_ptr(buf, 8);
ppc_maybe_bswap_register(env, mem_buf, 8);
return 8;
}
if (n == 32) {
gdb_get_reg32(buf, env->fpscr);
mem_buf = gdb_get_reg_ptr(buf, 4);
ppc_maybe_bswap_register(env, mem_buf, 4);
return 4;
}
return 0;
}
static int gdb_set_float_reg(CPUPPCState *env, uint8_t *mem_buf, int n)
{
if (n < 32) {
ppc_maybe_bswap_register(env, mem_buf, 8);
*cpu_fpr_ptr(env, n) = ldq_p(mem_buf);
return 8;
}
if (n == 32) {
ppc_maybe_bswap_register(env, mem_buf, 4);
helper_store_fpscr(env, ldl_p(mem_buf), 0xffffffff);
return 4;
}
return 0;
}
static int gdb_get_avr_reg(CPUPPCState *env, GByteArray *buf, int n)
{
uint8_t *mem_buf;
if (n < 32) {
ppc_avr_t *avr = cpu_avr_ptr(env, n);
if (!avr_need_swap(env)) {
gdb_get_reg128(buf, avr->u64[0] , avr->u64[1]);
} else {
gdb_get_reg128(buf, avr->u64[1] , avr->u64[0]);
}
mem_buf = gdb_get_reg_ptr(buf, 16);
ppc_maybe_bswap_register(env, mem_buf, 8);
ppc_maybe_bswap_register(env, mem_buf + 8, 8);
return 16;
}
if (n == 32) {
gdb_get_reg32(buf, helper_mfvscr(env));
mem_buf = gdb_get_reg_ptr(buf, 4);
ppc_maybe_bswap_register(env, mem_buf, 4);
return 4;
}
if (n == 33) {
gdb_get_reg32(buf, (uint32_t)env->spr[SPR_VRSAVE]);
mem_buf = gdb_get_reg_ptr(buf, 4);
ppc_maybe_bswap_register(env, mem_buf, 4);
return 4;
}
return 0;
}
static int gdb_set_avr_reg(CPUPPCState *env, uint8_t *mem_buf, int n)
{
if (n < 32) {
ppc_avr_t *avr = cpu_avr_ptr(env, n);
ppc_maybe_bswap_register(env, mem_buf, 8);
ppc_maybe_bswap_register(env, mem_buf + 8, 8);
if (!avr_need_swap(env)) {
avr->u64[0] = ldq_p(mem_buf);
avr->u64[1] = ldq_p(mem_buf + 8);
} else {
avr->u64[1] = ldq_p(mem_buf);
avr->u64[0] = ldq_p(mem_buf + 8);
}
return 16;
}
if (n == 32) {
ppc_maybe_bswap_register(env, mem_buf, 4);
helper_mtvscr(env, ldl_p(mem_buf));
return 4;
}
if (n == 33) {
ppc_maybe_bswap_register(env, mem_buf, 4);
env->spr[SPR_VRSAVE] = (target_ulong)ldl_p(mem_buf);
return 4;
}
return 0;
}
static int gdb_get_spe_reg(CPUPPCState *env, GByteArray *buf, int n)
{
if (n < 32) {
#if defined(TARGET_PPC64)
gdb_get_reg32(buf, env->gpr[n] >> 32);
ppc_maybe_bswap_register(env, gdb_get_reg_ptr(buf, 4), 4);
#else
gdb_get_reg32(buf, env->gprh[n]);
#endif
return 4;
}
if (n == 32) {
gdb_get_reg64(buf, env->spe_acc);
ppc_maybe_bswap_register(env, gdb_get_reg_ptr(buf, 8), 8);
return 8;
}
if (n == 33) {
gdb_get_reg32(buf, env->spe_fscr);
ppc_maybe_bswap_register(env, gdb_get_reg_ptr(buf, 4), 4);
return 4;
}
return 0;
}
static int gdb_set_spe_reg(CPUPPCState *env, uint8_t *mem_buf, int n)
{
if (n < 32) {
#if defined(TARGET_PPC64)
target_ulong lo = (uint32_t)env->gpr[n];
target_ulong hi;
ppc_maybe_bswap_register(env, mem_buf, 4);
hi = (target_ulong)ldl_p(mem_buf) << 32;
env->gpr[n] = lo | hi;
#else
env->gprh[n] = ldl_p(mem_buf);
#endif
return 4;
}
if (n == 32) {
ppc_maybe_bswap_register(env, mem_buf, 8);
env->spe_acc = ldq_p(mem_buf);
return 8;
}
if (n == 33) {
ppc_maybe_bswap_register(env, mem_buf, 4);
env->spe_fscr = ldl_p(mem_buf);
return 4;
}
return 0;
}
static int gdb_get_vsx_reg(CPUPPCState *env, GByteArray *buf, int n)
{
if (n < 32) {
gdb_get_reg64(buf, *cpu_vsrl_ptr(env, n));
ppc_maybe_bswap_register(env, gdb_get_reg_ptr(buf, 8), 8);
return 8;
}
return 0;
}
static int gdb_set_vsx_reg(CPUPPCState *env, uint8_t *mem_buf, int n)
{
if (n < 32) {
ppc_maybe_bswap_register(env, mem_buf, 8);
*cpu_vsrl_ptr(env, n) = ldq_p(mem_buf);
return 8;
}
return 0;
}
static int ppc_fixup_cpu(PowerPCCPU *cpu)
{
CPUPPCState *env = &cpu->env;
/*
* TCG doesn't (yet) emulate some groups of instructions that are
* implemented on some otherwise supported CPUs (e.g. VSX and
* decimal floating point instructions on POWER7). We remove
* unsupported instruction groups from the cpu state's instruction
* masks and hope the guest can cope. For at least the pseries
* machine, the unavailability of these instructions can be
* advertised to the guest via the device tree.
*/
if ((env->insns_flags & ~PPC_TCG_INSNS)
|| (env->insns_flags2 & ~PPC_TCG_INSNS2)) {
warn_report("Disabling some instructions which are not "
"emulated by TCG (0x%" PRIx64 ", 0x%" PRIx64 ")",
env->insns_flags & ~PPC_TCG_INSNS,
env->insns_flags2 & ~PPC_TCG_INSNS2);
}
env->insns_flags &= PPC_TCG_INSNS;
env->insns_flags2 &= PPC_TCG_INSNS2;
return 0;
}
static void ppc_cpu_realize(DeviceState *dev, Error **errp)
{
CPUState *cs = CPU(dev);
@ -10174,26 +9589,7 @@ static void ppc_cpu_realize(DeviceState *dev, Error **errp)
}
init_ppc_proc(cpu);
if (pcc->insns_flags & PPC_FLOAT) {
gdb_register_coprocessor(cs, gdb_get_float_reg, gdb_set_float_reg,
33, "power-fpu.xml", 0);
}
if (pcc->insns_flags & PPC_ALTIVEC) {
gdb_register_coprocessor(cs, gdb_get_avr_reg, gdb_set_avr_reg,
34, "power-altivec.xml", 0);
}
if (pcc->insns_flags & PPC_SPE) {
gdb_register_coprocessor(cs, gdb_get_spe_reg, gdb_set_spe_reg,
34, "power-spe.xml", 0);
}
if (pcc->insns_flags2 & PPC2_VSX) {
gdb_register_coprocessor(cs, gdb_get_vsx_reg, gdb_set_vsx_reg,
32, "power-vsx.xml", 0);
}
#ifndef CONFIG_USER_ONLY
gdb_register_coprocessor(cs, gdb_get_spr_reg, gdb_set_spr_reg,
pcc->gdb_num_sprs, "power-spr.xml", 0);
#endif
ppc_gdb_init(cs, pcc);
qemu_init_vcpu(cs);
pcc->parent_realize(dev, errp);
@ -10374,40 +9770,12 @@ static void ppc_cpu_unrealize(DeviceState *dev)
{
PowerPCCPU *cpu = POWERPC_CPU(dev);
PowerPCCPUClass *pcc = POWERPC_CPU_GET_CLASS(cpu);
opc_handler_t **table, **table_2;
int i, j, k;
pcc->parent_unrealize(dev);
cpu_remove_sync(CPU(cpu));
for (i = 0; i < PPC_CPU_OPCODES_LEN; i++) {
if (cpu->opcodes[i] == &invalid_handler) {
continue;
}
if (is_indirect_opcode(cpu->opcodes[i])) {
table = ind_table(cpu->opcodes[i]);
for (j = 0; j < PPC_CPU_INDIRECT_OPCODES_LEN; j++) {
if (table[j] == &invalid_handler) {
continue;
}
if (is_indirect_opcode(table[j])) {
table_2 = ind_table(table[j]);
for (k = 0; k < PPC_CPU_INDIRECT_OPCODES_LEN; k++) {
if (table_2[k] != &invalid_handler &&
is_indirect_opcode(table_2[k])) {
g_free((opc_handler_t *)((uintptr_t)table_2[k] &
~PPC_INDIRECT));
}
}
g_free((opc_handler_t *)((uintptr_t)table[j] &
~PPC_INDIRECT));
}
}
g_free((opc_handler_t *)((uintptr_t)cpu->opcodes[i] &
~PPC_INDIRECT));
}
}
destroy_ppc_opcodes(cpu);
}
static gint ppc_cpu_compare_class_pvr(gconstpointer a, gconstpointer b)
@ -10835,15 +10203,6 @@ static bool ppc_pvr_match_default(PowerPCCPUClass *pcc, uint32_t pvr)
return pcc->pvr == pvr;
}
static gchar *ppc_gdb_arch_name(CPUState *cs)
{
#if defined(TARGET_PPC64)
return g_strdup("powerpc:common64");
#else
return g_strdup("powerpc:common");
#endif
}
static void ppc_disas_set_info(CPUState *cs, disassemble_info *info)
{
PowerPCCPU *cpu = POWERPC_CPU(cs);