Patch queue for ppc - 2014-11-04
Fun things for 2.2: - e500 virt machine: power off support (needs 3.19 guests) - e500 virt machine: -device eTSEC support - new framework to allow dynamic spawning of sysbus devices - spapr: enable migration of nvram - new 440x5wDFPU cpu type - Altivec and other random fixes -----BEGIN PGP SIGNATURE----- Version: GnuPG v2.0.19 (GNU/Linux) iQIcBAABAgAGBQJUWVKfAAoJECszeR4D/txguC8QAIjVzZztg83ubBC8Wtb2BwIO pnyiFBtWCGpziOvUILFNQyX1DuxNMUciyzM3RheN6HyW6Z8ON1dVxqGvt2efkoEW 2JEwTDM9jWpbvinWX/oomGSqnazj3p6T+Yd1+6vpUnq7aax0tDvgPxQZZp5xVDBk dHT+X/EbIg1zERK+pKng+f3i9FQSpQR3pnQMCBg3namJaNll+EVwT5r0IdqKfRb2 OTXgdCUMkT3B1SmWAJDJZeZKpoj+o1e3Y4e3LAY9cha4ixlpMb2RCNd36O9wENf/ uZX8UeDdb56JpQy4Eyqk/eaYRpmyaA5XVQJRRrpF+iIWGMi290YQWQvfVKLyEAXl z7dstSQiJ38ZwAVEGASD4X/THvEr9XE03EKzxFLEH0sD7DN4YjMQuPm/BrHTywhB HKPlUu1nvHIbPA+yUePD6pUN2gBGMpYRSJpJkhUQwU9erdlyTx/Jhgg6+KUgl74D 1ub+Xd+/RLwAccvHISq5Sm5fbVi9Ti+SEAmHoYFV44YxspGlABq4FovXfXmpgvpj lC9nO49ZiPGWRD6J3JphQoH0YCoCW/ld7uQjkN4rhRxBNLAIeTGgPq6ikarC3JJl Yg4gPkGqtOr4nJ0XNSdsY5iEPjCoG3p8bYiIrrNMBlTOniDwr9vIo9H3s0nA1QN8 JtFbYPqsSOI2ukazdlzq =X+W0 -----END PGP SIGNATURE----- Merge remote-tracking branch 'remotes/agraf/tags/signed-ppc-for-upstream' into staging Patch queue for ppc - 2014-11-04 Fun things for 2.2: - e500 virt machine: power off support (needs 3.19 guests) - e500 virt machine: -device eTSEC support - new framework to allow dynamic spawning of sysbus devices - spapr: enable migration of nvram - new 440x5wDFPU cpu type - Altivec and other random fixes # gpg: Signature made Tue 04 Nov 2014 22:26:39 GMT using RSA key ID 03FEDC60 # gpg: Good signature from "Alexander Graf <agraf@suse.de>" # gpg: aka "Alexander Graf <alex@csgraf.de>" * remotes/agraf/tags/signed-ppc-for-upstream: (34 commits) spapr: Allow dynamic creation of PHB target-ppc: Fix Altivec Round Opcodes target-ppc: Fix vcmpbfp. Unordered Case target-ppc: Fix Altivec Shifts target-ppc: simplify AES emulation e500: Add support for eTSEC in device tree PPC: e500: Support dynamically spawned sysbus devices sysbus: Add new platform bus helper device sysbus: Expose MMIO enumeration helper sysbus: Expose IRQ enumeration helpers sysbus: Make devices spawnable via -device sysbus: Add dynamic sysbus device search hw/ppc/spapr_pci.c: Avoid functions not in glib 2.12 (g_hash_table_iter_*) ppc: do not look at the MMU index to detect PR/HV mode target-ppc: kvm: Fix memory overflow issue about strncat() spapr_nvram: Enable migration PPC: E500: Hook up power off GPIO to GPIO controller PPC: E500: Instantiate MPC8XXX gpio controller on virt machine PPC: Add MPC8XXX gpio controller target-ppc: Fix an invalid free in opcode table handling code. ... Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
This commit is contained in:
commit
c8d943303d
|
@ -14,3 +14,4 @@ common-obj-$(CONFIG_SOFTMMU) += machine.o
|
||||||
common-obj-$(CONFIG_SOFTMMU) += null-machine.o
|
common-obj-$(CONFIG_SOFTMMU) += null-machine.o
|
||||||
common-obj-$(CONFIG_SOFTMMU) += loader.o
|
common-obj-$(CONFIG_SOFTMMU) += loader.o
|
||||||
common-obj-$(CONFIG_SOFTMMU) += qdev-properties-system.o
|
common-obj-$(CONFIG_SOFTMMU) += qdev-properties-system.o
|
||||||
|
common-obj-$(CONFIG_SOFTMMU) += platform-bus.o
|
||||||
|
|
|
@ -12,6 +12,9 @@
|
||||||
|
|
||||||
#include "hw/boards.h"
|
#include "hw/boards.h"
|
||||||
#include "qapi/visitor.h"
|
#include "qapi/visitor.h"
|
||||||
|
#include "hw/sysbus.h"
|
||||||
|
#include "sysemu/sysemu.h"
|
||||||
|
#include "qemu/error-report.h"
|
||||||
|
|
||||||
static char *machine_get_accel(Object *obj, Error **errp)
|
static char *machine_get_accel(Object *obj, Error **errp)
|
||||||
{
|
{
|
||||||
|
@ -257,8 +260,35 @@ static void machine_set_iommu(Object *obj, bool value, Error **errp)
|
||||||
ms->iommu = value;
|
ms->iommu = value;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int error_on_sysbus_device(SysBusDevice *sbdev, void *opaque)
|
||||||
|
{
|
||||||
|
error_report("Option '-device %s' cannot be handled by this machine",
|
||||||
|
object_class_get_name(object_get_class(OBJECT(sbdev))));
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void machine_init_notify(Notifier *notifier, void *data)
|
||||||
|
{
|
||||||
|
Object *machine = qdev_get_machine();
|
||||||
|
ObjectClass *oc = object_get_class(machine);
|
||||||
|
MachineClass *mc = MACHINE_CLASS(oc);
|
||||||
|
|
||||||
|
if (mc->has_dynamic_sysbus) {
|
||||||
|
/* Our machine can handle dynamic sysbus devices, we're all good */
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Loop through all dynamically created devices and check whether there
|
||||||
|
* are sysbus devices among them. If there are, error out.
|
||||||
|
*/
|
||||||
|
foreach_dynamic_sysbus_device(error_on_sysbus_device, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
static void machine_initfn(Object *obj)
|
static void machine_initfn(Object *obj)
|
||||||
{
|
{
|
||||||
|
MachineState *ms = MACHINE(obj);
|
||||||
|
|
||||||
object_property_add_str(obj, "accel",
|
object_property_add_str(obj, "accel",
|
||||||
machine_get_accel, machine_set_accel, NULL);
|
machine_get_accel, machine_set_accel, NULL);
|
||||||
object_property_add_bool(obj, "kernel-irqchip",
|
object_property_add_bool(obj, "kernel-irqchip",
|
||||||
|
@ -303,6 +333,10 @@ static void machine_initfn(Object *obj)
|
||||||
object_property_add_bool(obj, "iommu",
|
object_property_add_bool(obj, "iommu",
|
||||||
machine_get_iommu,
|
machine_get_iommu,
|
||||||
machine_set_iommu, NULL);
|
machine_set_iommu, NULL);
|
||||||
|
|
||||||
|
/* Register notifier when init is done for sysbus sanity checks */
|
||||||
|
ms->sysbus_notifier.notify = machine_init_notify;
|
||||||
|
qemu_add_machine_init_done_notifier(&ms->sysbus_notifier);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void machine_finalize(Object *obj)
|
static void machine_finalize(Object *obj)
|
||||||
|
|
|
@ -0,0 +1,253 @@
|
||||||
|
/*
|
||||||
|
* Platform Bus device to support dynamic Sysbus devices
|
||||||
|
*
|
||||||
|
* Copyright (C) 2014 Freescale Semiconductor, Inc. All rights reserved.
|
||||||
|
*
|
||||||
|
* Author: Alexander Graf, <agraf@suse.de>
|
||||||
|
*
|
||||||
|
* 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 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 "hw/platform-bus.h"
|
||||||
|
#include "monitor/monitor.h"
|
||||||
|
#include "exec/address-spaces.h"
|
||||||
|
#include "sysemu/sysemu.h"
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Returns the PlatformBus IRQ number for a SysBusDevice irq number or -1 if
|
||||||
|
* the IRQ is not mapped on this Platform bus.
|
||||||
|
*/
|
||||||
|
int platform_bus_get_irqn(PlatformBusDevice *pbus, SysBusDevice *sbdev,
|
||||||
|
int n)
|
||||||
|
{
|
||||||
|
qemu_irq sbirq = sysbus_get_connected_irq(sbdev, n);
|
||||||
|
int i;
|
||||||
|
|
||||||
|
for (i = 0; i < pbus->num_irqs; i++) {
|
||||||
|
if (pbus->irqs[i] == sbirq) {
|
||||||
|
return i;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* IRQ not mapped on platform bus */
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Returns the PlatformBus MMIO region offset for Region n of a SysBusDevice or
|
||||||
|
* -1 if the region is not mapped on this Platform bus.
|
||||||
|
*/
|
||||||
|
hwaddr platform_bus_get_mmio_addr(PlatformBusDevice *pbus, SysBusDevice *sbdev,
|
||||||
|
int n)
|
||||||
|
{
|
||||||
|
MemoryRegion *pbus_mr = &pbus->mmio;
|
||||||
|
MemoryRegion *sbdev_mr = sysbus_mmio_get_region(sbdev, n);
|
||||||
|
Object *pbus_mr_obj = OBJECT(pbus_mr);
|
||||||
|
Object *parent_mr;
|
||||||
|
|
||||||
|
if (!memory_region_is_mapped(sbdev_mr)) {
|
||||||
|
/* Region is not mapped? */
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
parent_mr = object_property_get_link(OBJECT(sbdev_mr), "container", NULL);
|
||||||
|
|
||||||
|
assert(parent_mr);
|
||||||
|
if (parent_mr != pbus_mr_obj) {
|
||||||
|
/* MMIO region is not mapped on platform bus */
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return object_property_get_int(OBJECT(sbdev_mr), "addr", NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int platform_bus_count_irqs(SysBusDevice *sbdev, void *opaque)
|
||||||
|
{
|
||||||
|
PlatformBusDevice *pbus = opaque;
|
||||||
|
qemu_irq sbirq;
|
||||||
|
int n, i;
|
||||||
|
|
||||||
|
for (n = 0; ; n++) {
|
||||||
|
if (!sysbus_has_irq(sbdev, n)) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
sbirq = sysbus_get_connected_irq(sbdev, n);
|
||||||
|
for (i = 0; i < pbus->num_irqs; i++) {
|
||||||
|
if (pbus->irqs[i] == sbirq) {
|
||||||
|
bitmap_set(pbus->used_irqs, i, 1);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Loop through all sysbus devices and look for unassigned IRQ lines as well as
|
||||||
|
* unassociated MMIO regions. Connect them to the platform bus if available.
|
||||||
|
*/
|
||||||
|
static void plaform_bus_refresh_irqs(PlatformBusDevice *pbus)
|
||||||
|
{
|
||||||
|
bitmap_zero(pbus->used_irqs, pbus->num_irqs);
|
||||||
|
foreach_dynamic_sysbus_device(platform_bus_count_irqs, pbus);
|
||||||
|
pbus->done_gathering = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int platform_bus_map_irq(PlatformBusDevice *pbus, SysBusDevice *sbdev,
|
||||||
|
int n)
|
||||||
|
{
|
||||||
|
int max_irqs = pbus->num_irqs;
|
||||||
|
int irqn;
|
||||||
|
|
||||||
|
if (sysbus_is_irq_connected(sbdev, n)) {
|
||||||
|
/* IRQ is already mapped, nothing to do */
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
irqn = find_first_zero_bit(pbus->used_irqs, max_irqs);
|
||||||
|
if (irqn >= max_irqs) {
|
||||||
|
hw_error("Platform Bus: Can not fit IRQ line");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
set_bit(irqn, pbus->used_irqs);
|
||||||
|
sysbus_connect_irq(sbdev, n, pbus->irqs[irqn]);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int platform_bus_map_mmio(PlatformBusDevice *pbus, SysBusDevice *sbdev,
|
||||||
|
int n)
|
||||||
|
{
|
||||||
|
MemoryRegion *sbdev_mr = sysbus_mmio_get_region(sbdev, n);
|
||||||
|
uint64_t size = memory_region_size(sbdev_mr);
|
||||||
|
uint64_t alignment = (1ULL << (63 - clz64(size + size - 1)));
|
||||||
|
uint64_t off;
|
||||||
|
bool found_region = false;
|
||||||
|
|
||||||
|
if (memory_region_is_mapped(sbdev_mr)) {
|
||||||
|
/* Region is already mapped, nothing to do */
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Look for empty space in the MMIO space that is naturally aligned with
|
||||||
|
* the target device's memory region
|
||||||
|
*/
|
||||||
|
for (off = 0; off < pbus->mmio_size; off += alignment) {
|
||||||
|
if (!memory_region_find(&pbus->mmio, off, size).mr) {
|
||||||
|
found_region = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!found_region) {
|
||||||
|
hw_error("Platform Bus: Can not fit MMIO region of size %"PRIx64, size);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Map the device's region into our Platform Bus MMIO space */
|
||||||
|
memory_region_add_subregion(&pbus->mmio, off, sbdev_mr);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* For each sysbus device, look for unassigned IRQ lines as well as
|
||||||
|
* unassociated MMIO regions. Connect them to the platform bus if available.
|
||||||
|
*/
|
||||||
|
static int link_sysbus_device(SysBusDevice *sbdev, void *opaque)
|
||||||
|
{
|
||||||
|
PlatformBusDevice *pbus = opaque;
|
||||||
|
int i;
|
||||||
|
|
||||||
|
for (i = 0; sysbus_has_irq(sbdev, i); i++) {
|
||||||
|
platform_bus_map_irq(pbus, sbdev, i);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (i = 0; sysbus_has_mmio(sbdev, i); i++) {
|
||||||
|
platform_bus_map_mmio(pbus, sbdev, i);
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void platform_bus_init_notify(Notifier *notifier, void *data)
|
||||||
|
{
|
||||||
|
PlatformBusDevice *pb = container_of(notifier, PlatformBusDevice, notifier);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Generate a bitmap of used IRQ lines, as the user might have specified
|
||||||
|
* them on the command line.
|
||||||
|
*/
|
||||||
|
plaform_bus_refresh_irqs(pb);
|
||||||
|
|
||||||
|
foreach_dynamic_sysbus_device(link_sysbus_device, pb);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void platform_bus_realize(DeviceState *dev, Error **errp)
|
||||||
|
{
|
||||||
|
PlatformBusDevice *pbus;
|
||||||
|
SysBusDevice *d;
|
||||||
|
int i;
|
||||||
|
|
||||||
|
d = SYS_BUS_DEVICE(dev);
|
||||||
|
pbus = PLATFORM_BUS_DEVICE(dev);
|
||||||
|
|
||||||
|
memory_region_init(&pbus->mmio, NULL, "platform bus", pbus->mmio_size);
|
||||||
|
sysbus_init_mmio(d, &pbus->mmio);
|
||||||
|
|
||||||
|
pbus->used_irqs = bitmap_new(pbus->num_irqs);
|
||||||
|
pbus->irqs = g_new0(qemu_irq, pbus->num_irqs);
|
||||||
|
for (i = 0; i < pbus->num_irqs; i++) {
|
||||||
|
sysbus_init_irq(d, &pbus->irqs[i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Register notifier that allows us to gather dangling devices once the
|
||||||
|
* machine is completely assembled
|
||||||
|
*/
|
||||||
|
pbus->notifier.notify = platform_bus_init_notify;
|
||||||
|
qemu_add_machine_init_done_notifier(&pbus->notifier);
|
||||||
|
}
|
||||||
|
|
||||||
|
static Property platform_bus_properties[] = {
|
||||||
|
DEFINE_PROP_UINT32("num_irqs", PlatformBusDevice, num_irqs, 0),
|
||||||
|
DEFINE_PROP_UINT32("mmio_size", PlatformBusDevice, mmio_size, 0),
|
||||||
|
DEFINE_PROP_END_OF_LIST()
|
||||||
|
};
|
||||||
|
|
||||||
|
static void platform_bus_class_init(ObjectClass *klass, void *data)
|
||||||
|
{
|
||||||
|
DeviceClass *dc = DEVICE_CLASS(klass);
|
||||||
|
|
||||||
|
dc->realize = platform_bus_realize;
|
||||||
|
dc->props = platform_bus_properties;
|
||||||
|
}
|
||||||
|
|
||||||
|
static const TypeInfo platform_bus_info = {
|
||||||
|
.name = TYPE_PLATFORM_BUS_DEVICE,
|
||||||
|
.parent = TYPE_SYS_BUS_DEVICE,
|
||||||
|
.instance_size = sizeof(PlatformBusDevice),
|
||||||
|
.class_init = platform_bus_class_init,
|
||||||
|
};
|
||||||
|
|
||||||
|
static void platform_bus_register_types(void)
|
||||||
|
{
|
||||||
|
type_register_static(&platform_bus_info);
|
||||||
|
}
|
||||||
|
|
||||||
|
type_init(platform_bus_register_types)
|
|
@ -453,6 +453,17 @@ void qdev_connect_gpio_out_named(DeviceState *dev, const char *name, int n,
|
||||||
g_free(propname);
|
g_free(propname);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
qemu_irq qdev_get_gpio_out_connector(DeviceState *dev, const char *name, int n)
|
||||||
|
{
|
||||||
|
char *propname = g_strdup_printf("%s[%d]",
|
||||||
|
name ? name : "unnamed-gpio-out", n);
|
||||||
|
|
||||||
|
qemu_irq ret = (qemu_irq)object_property_get_link(OBJECT(dev), propname,
|
||||||
|
NULL);
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
/* disconnect a GPIO ouput, returning the disconnected input (if any) */
|
/* disconnect a GPIO ouput, returning the disconnected input (if any) */
|
||||||
|
|
||||||
static qemu_irq qdev_disconnect_gpio_out_named(DeviceState *dev,
|
static qemu_irq qdev_disconnect_gpio_out_named(DeviceState *dev,
|
||||||
|
|
|
@ -24,6 +24,51 @@
|
||||||
static void sysbus_dev_print(Monitor *mon, DeviceState *dev, int indent);
|
static void sysbus_dev_print(Monitor *mon, DeviceState *dev, int indent);
|
||||||
static char *sysbus_get_fw_dev_path(DeviceState *dev);
|
static char *sysbus_get_fw_dev_path(DeviceState *dev);
|
||||||
|
|
||||||
|
typedef struct SysBusFind {
|
||||||
|
void *opaque;
|
||||||
|
FindSysbusDeviceFunc *func;
|
||||||
|
} SysBusFind;
|
||||||
|
|
||||||
|
/* Run func() for every sysbus device, traverse the tree for everything else */
|
||||||
|
static int find_sysbus_device(Object *obj, void *opaque)
|
||||||
|
{
|
||||||
|
SysBusFind *find = opaque;
|
||||||
|
Object *dev;
|
||||||
|
SysBusDevice *sbdev;
|
||||||
|
|
||||||
|
dev = object_dynamic_cast(obj, TYPE_SYS_BUS_DEVICE);
|
||||||
|
sbdev = (SysBusDevice *)dev;
|
||||||
|
|
||||||
|
if (!sbdev) {
|
||||||
|
/* Container, traverse it for children */
|
||||||
|
return object_child_foreach(obj, find_sysbus_device, opaque);
|
||||||
|
}
|
||||||
|
|
||||||
|
find->func(sbdev, find->opaque);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Loop through all dynamically created sysbus devices and call
|
||||||
|
* func() for each instance.
|
||||||
|
*/
|
||||||
|
void foreach_dynamic_sysbus_device(FindSysbusDeviceFunc *func, void *opaque)
|
||||||
|
{
|
||||||
|
Object *container;
|
||||||
|
SysBusFind find = {
|
||||||
|
.func = func,
|
||||||
|
.opaque = opaque,
|
||||||
|
};
|
||||||
|
|
||||||
|
/* Loop through all sysbus devices that were spawened outside the machine */
|
||||||
|
container = container_get(qdev_get_machine(), "/peripheral");
|
||||||
|
find_sysbus_device(container, &find);
|
||||||
|
container = container_get(qdev_get_machine(), "/peripheral-anon");
|
||||||
|
find_sysbus_device(container, &find);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
static void system_bus_class_init(ObjectClass *klass, void *data)
|
static void system_bus_class_init(ObjectClass *klass, void *data)
|
||||||
{
|
{
|
||||||
BusClass *k = BUS_CLASS(klass);
|
BusClass *k = BUS_CLASS(klass);
|
||||||
|
@ -39,11 +84,38 @@ static const TypeInfo system_bus_info = {
|
||||||
.class_init = system_bus_class_init,
|
.class_init = system_bus_class_init,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/* Check whether an IRQ source exists */
|
||||||
|
bool sysbus_has_irq(SysBusDevice *dev, int n)
|
||||||
|
{
|
||||||
|
char *prop = g_strdup_printf("%s[%d]", SYSBUS_DEVICE_GPIO_IRQ, n);
|
||||||
|
ObjectProperty *r;
|
||||||
|
|
||||||
|
r = object_property_find(OBJECT(dev), prop, NULL);
|
||||||
|
return (r != NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool sysbus_is_irq_connected(SysBusDevice *dev, int n)
|
||||||
|
{
|
||||||
|
return !!sysbus_get_connected_irq(dev, n);
|
||||||
|
}
|
||||||
|
|
||||||
|
qemu_irq sysbus_get_connected_irq(SysBusDevice *dev, int n)
|
||||||
|
{
|
||||||
|
DeviceState *d = DEVICE(dev);
|
||||||
|
return qdev_get_gpio_out_connector(d, SYSBUS_DEVICE_GPIO_IRQ, n);
|
||||||
|
}
|
||||||
|
|
||||||
void sysbus_connect_irq(SysBusDevice *dev, int n, qemu_irq irq)
|
void sysbus_connect_irq(SysBusDevice *dev, int n, qemu_irq irq)
|
||||||
{
|
{
|
||||||
qdev_connect_gpio_out_named(DEVICE(dev), SYSBUS_DEVICE_GPIO_IRQ, n, irq);
|
qdev_connect_gpio_out_named(DEVICE(dev), SYSBUS_DEVICE_GPIO_IRQ, n, irq);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Check whether an MMIO region exists */
|
||||||
|
bool sysbus_has_mmio(SysBusDevice *dev, unsigned int n)
|
||||||
|
{
|
||||||
|
return (n < dev->num_mmio);
|
||||||
|
}
|
||||||
|
|
||||||
static void sysbus_mmio_map_common(SysBusDevice *dev, int n, hwaddr addr,
|
static void sysbus_mmio_map_common(SysBusDevice *dev, int n, hwaddr addr,
|
||||||
bool may_overlap, int priority)
|
bool may_overlap, int priority)
|
||||||
{
|
{
|
||||||
|
@ -238,13 +310,6 @@ static void sysbus_device_class_init(ObjectClass *klass, void *data)
|
||||||
DeviceClass *k = DEVICE_CLASS(klass);
|
DeviceClass *k = DEVICE_CLASS(klass);
|
||||||
k->init = sysbus_device_init;
|
k->init = sysbus_device_init;
|
||||||
k->bus_type = TYPE_SYSTEM_BUS;
|
k->bus_type = TYPE_SYSTEM_BUS;
|
||||||
/*
|
|
||||||
* device_add plugs devices into suitable bus. For "real" buses,
|
|
||||||
* that actually connects the device. For sysbus, the connections
|
|
||||||
* need to be made separately, and device_add can't do that. The
|
|
||||||
* device would be left unconnected, and could not possibly work.
|
|
||||||
*/
|
|
||||||
k->cannot_instantiate_with_device_add_yet = true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static const TypeInfo sysbus_device_type_info = {
|
static const TypeInfo sysbus_device_type_info = {
|
||||||
|
|
|
@ -2,5 +2,6 @@ common-obj-$(CONFIG_MAX7310) += max7310.o
|
||||||
common-obj-$(CONFIG_PL061) += pl061.o
|
common-obj-$(CONFIG_PL061) += pl061.o
|
||||||
common-obj-$(CONFIG_PUV3) += puv3_gpio.o
|
common-obj-$(CONFIG_PUV3) += puv3_gpio.o
|
||||||
common-obj-$(CONFIG_ZAURUS) += zaurus.o
|
common-obj-$(CONFIG_ZAURUS) += zaurus.o
|
||||||
|
common-obj-$(CONFIG_E500) += mpc8xxx.o
|
||||||
|
|
||||||
obj-$(CONFIG_OMAP) += omap_gpio.o
|
obj-$(CONFIG_OMAP) += omap_gpio.o
|
||||||
|
|
|
@ -0,0 +1,217 @@
|
||||||
|
/*
|
||||||
|
* GPIO Controller for a lot of Freescale SoCs
|
||||||
|
*
|
||||||
|
* Copyright (C) 2014 Freescale Semiconductor, Inc. All rights reserved.
|
||||||
|
*
|
||||||
|
* Author: Alexander Graf, <agraf@suse.de>
|
||||||
|
*
|
||||||
|
* 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 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 "hw/sysbus.h"
|
||||||
|
|
||||||
|
#define TYPE_MPC8XXX_GPIO "mpc8xxx_gpio"
|
||||||
|
#define MPC8XXX_GPIO(obj) OBJECT_CHECK(MPC8XXXGPIOState, (obj), TYPE_MPC8XXX_GPIO)
|
||||||
|
|
||||||
|
typedef struct MPC8XXXGPIOState {
|
||||||
|
SysBusDevice parent_obj;
|
||||||
|
|
||||||
|
MemoryRegion iomem;
|
||||||
|
qemu_irq irq;
|
||||||
|
qemu_irq out[32];
|
||||||
|
|
||||||
|
uint32_t dir;
|
||||||
|
uint32_t odr;
|
||||||
|
uint32_t dat;
|
||||||
|
uint32_t ier;
|
||||||
|
uint32_t imr;
|
||||||
|
uint32_t icr;
|
||||||
|
} MPC8XXXGPIOState;
|
||||||
|
|
||||||
|
static const VMStateDescription vmstate_mpc8xxx_gpio = {
|
||||||
|
.name = "mpc8xxx_gpio",
|
||||||
|
.version_id = 1,
|
||||||
|
.minimum_version_id = 1,
|
||||||
|
.fields = (VMStateField[]) {
|
||||||
|
VMSTATE_UINT32(dir, MPC8XXXGPIOState),
|
||||||
|
VMSTATE_UINT32(odr, MPC8XXXGPIOState),
|
||||||
|
VMSTATE_UINT32(dat, MPC8XXXGPIOState),
|
||||||
|
VMSTATE_UINT32(ier, MPC8XXXGPIOState),
|
||||||
|
VMSTATE_UINT32(imr, MPC8XXXGPIOState),
|
||||||
|
VMSTATE_UINT32(icr, MPC8XXXGPIOState),
|
||||||
|
VMSTATE_END_OF_LIST()
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
static void mpc8xxx_gpio_update(MPC8XXXGPIOState *s)
|
||||||
|
{
|
||||||
|
qemu_set_irq(s->irq, !!(s->ier & s->imr));
|
||||||
|
}
|
||||||
|
|
||||||
|
static uint64_t mpc8xxx_gpio_read(void *opaque, hwaddr offset,
|
||||||
|
unsigned size)
|
||||||
|
{
|
||||||
|
MPC8XXXGPIOState *s = (MPC8XXXGPIOState *)opaque;
|
||||||
|
|
||||||
|
if (size != 4) {
|
||||||
|
/* All registers are 32bit */
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (offset) {
|
||||||
|
case 0x0: /* Direction */
|
||||||
|
return s->dir;
|
||||||
|
case 0x4: /* Open Drain */
|
||||||
|
return s->odr;
|
||||||
|
case 0x8: /* Data */
|
||||||
|
return s->dat;
|
||||||
|
case 0xC: /* Interrupt Event */
|
||||||
|
return s->ier;
|
||||||
|
case 0x10: /* Interrupt Mask */
|
||||||
|
return s->imr;
|
||||||
|
case 0x14: /* Interrupt Control */
|
||||||
|
return s->icr;
|
||||||
|
default:
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void mpc8xxx_write_data(MPC8XXXGPIOState *s, uint32_t new_data)
|
||||||
|
{
|
||||||
|
uint32_t old_data = s->dat;
|
||||||
|
uint32_t diff = old_data ^ new_data;
|
||||||
|
int i;
|
||||||
|
|
||||||
|
for (i = 0; i < 32; i++) {
|
||||||
|
uint32_t mask = 0x80000000 >> i;
|
||||||
|
if (!(diff & mask)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (s->dir & mask) {
|
||||||
|
/* Output */
|
||||||
|
qemu_set_irq(s->out[i], (new_data & mask) != 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
s->dat = new_data;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void mpc8xxx_gpio_write(void *opaque, hwaddr offset,
|
||||||
|
uint64_t value, unsigned size)
|
||||||
|
{
|
||||||
|
MPC8XXXGPIOState *s = (MPC8XXXGPIOState *)opaque;
|
||||||
|
|
||||||
|
if (size != 4) {
|
||||||
|
/* All registers are 32bit */
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (offset) {
|
||||||
|
case 0x0: /* Direction */
|
||||||
|
s->dir = value;
|
||||||
|
break;
|
||||||
|
case 0x4: /* Open Drain */
|
||||||
|
s->odr = value;
|
||||||
|
break;
|
||||||
|
case 0x8: /* Data */
|
||||||
|
mpc8xxx_write_data(s, value);
|
||||||
|
break;
|
||||||
|
case 0xC: /* Interrupt Event */
|
||||||
|
s->ier &= ~value;
|
||||||
|
break;
|
||||||
|
case 0x10: /* Interrupt Mask */
|
||||||
|
s->imr = value;
|
||||||
|
break;
|
||||||
|
case 0x14: /* Interrupt Control */
|
||||||
|
s->icr = value;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
mpc8xxx_gpio_update(s);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void mpc8xxx_gpio_reset(MPC8XXXGPIOState *s)
|
||||||
|
{
|
||||||
|
s->dir = 0;
|
||||||
|
s->odr = 0;
|
||||||
|
s->dat = 0;
|
||||||
|
s->ier = 0;
|
||||||
|
s->imr = 0;
|
||||||
|
s->icr = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void mpc8xxx_gpio_set_irq(void * opaque, int irq, int level)
|
||||||
|
{
|
||||||
|
MPC8XXXGPIOState *s = (MPC8XXXGPIOState *)opaque;
|
||||||
|
uint32_t mask;
|
||||||
|
|
||||||
|
mask = 0x80000000 >> irq;
|
||||||
|
if ((s->dir & mask) == 0) {
|
||||||
|
uint32_t old_value = s->dat & mask;
|
||||||
|
|
||||||
|
s->dat &= ~mask;
|
||||||
|
if (level)
|
||||||
|
s->dat |= mask;
|
||||||
|
|
||||||
|
if (!(s->icr & irq) || (old_value && !level)) {
|
||||||
|
s->ier |= mask;
|
||||||
|
}
|
||||||
|
|
||||||
|
mpc8xxx_gpio_update(s);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static const MemoryRegionOps mpc8xxx_gpio_ops = {
|
||||||
|
.read = mpc8xxx_gpio_read,
|
||||||
|
.write = mpc8xxx_gpio_write,
|
||||||
|
.endianness = DEVICE_BIG_ENDIAN,
|
||||||
|
};
|
||||||
|
|
||||||
|
static int mpc8xxx_gpio_initfn(SysBusDevice *sbd)
|
||||||
|
{
|
||||||
|
DeviceState *dev = DEVICE(sbd);
|
||||||
|
MPC8XXXGPIOState *s = MPC8XXX_GPIO(dev);
|
||||||
|
|
||||||
|
memory_region_init_io(&s->iomem, OBJECT(s), &mpc8xxx_gpio_ops, s, "mpc8xxx_gpio", 0x1000);
|
||||||
|
sysbus_init_mmio(sbd, &s->iomem);
|
||||||
|
sysbus_init_irq(sbd, &s->irq);
|
||||||
|
qdev_init_gpio_in(dev, mpc8xxx_gpio_set_irq, 32);
|
||||||
|
qdev_init_gpio_out(dev, s->out, 32);
|
||||||
|
mpc8xxx_gpio_reset(s);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void mpc8xxx_gpio_class_init(ObjectClass *klass, void *data)
|
||||||
|
{
|
||||||
|
DeviceClass *dc = DEVICE_CLASS(klass);
|
||||||
|
SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
|
||||||
|
|
||||||
|
k->init = mpc8xxx_gpio_initfn;
|
||||||
|
dc->vmsd = &vmstate_mpc8xxx_gpio;
|
||||||
|
}
|
||||||
|
|
||||||
|
static const TypeInfo mpc8xxx_gpio_info = {
|
||||||
|
.name = TYPE_MPC8XXX_GPIO,
|
||||||
|
.parent = TYPE_SYS_BUS_DEVICE,
|
||||||
|
.instance_size = sizeof(MPC8XXXGPIOState),
|
||||||
|
.class_init = mpc8xxx_gpio_class_init,
|
||||||
|
};
|
||||||
|
|
||||||
|
static void mpc8xxx_gpio_register_types(void)
|
||||||
|
{
|
||||||
|
type_register_static(&mpc8xxx_gpio_info);
|
||||||
|
}
|
||||||
|
|
||||||
|
type_init(mpc8xxx_gpio_register_types)
|
|
@ -45,6 +45,7 @@ typedef struct KVMOpenPICState {
|
||||||
MemoryListener mem_listener;
|
MemoryListener mem_listener;
|
||||||
uint32_t fd;
|
uint32_t fd;
|
||||||
uint32_t model;
|
uint32_t model;
|
||||||
|
hwaddr mapped;
|
||||||
} KVMOpenPICState;
|
} KVMOpenPICState;
|
||||||
|
|
||||||
static void kvm_openpic_set_irq(void *opaque, int n_IRQ, int level)
|
static void kvm_openpic_set_irq(void *opaque, int n_IRQ, int level)
|
||||||
|
@ -128,7 +129,16 @@ static void kvm_openpic_region_add(MemoryListener *listener,
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (opp->mapped) {
|
||||||
|
/*
|
||||||
|
* We can only map the MPIC once. Since we are already mapped,
|
||||||
|
* the best we can do is ignore new maps.
|
||||||
|
*/
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
reg_base = section->offset_within_address_space;
|
reg_base = section->offset_within_address_space;
|
||||||
|
opp->mapped = reg_base;
|
||||||
|
|
||||||
attr.group = KVM_DEV_MPIC_GRP_MISC;
|
attr.group = KVM_DEV_MPIC_GRP_MISC;
|
||||||
attr.attr = KVM_DEV_MPIC_BASE_ADDR;
|
attr.attr = KVM_DEV_MPIC_BASE_ADDR;
|
||||||
|
@ -155,6 +165,15 @@ static void kvm_openpic_region_del(MemoryListener *listener,
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (section->offset_within_address_space != opp->mapped) {
|
||||||
|
/*
|
||||||
|
* We can only map the MPIC once. This mapping was a secondary
|
||||||
|
* one that we couldn't fulfill. Ignore it.
|
||||||
|
*/
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
opp->mapped = 0;
|
||||||
|
|
||||||
attr.group = KVM_DEV_MPIC_GRP_MISC;
|
attr.group = KVM_DEV_MPIC_GRP_MISC;
|
||||||
attr.attr = KVM_DEV_MPIC_BASE_ADDR;
|
attr.attr = KVM_DEV_MPIC_BASE_ADDR;
|
||||||
attr.addr = (uint64_t)(unsigned long)®_base;
|
attr.addr = (uint64_t)(unsigned long)®_base;
|
||||||
|
|
|
@ -52,7 +52,6 @@ static void rtas_nvram_fetch(PowerPCCPU *cpu, sPAPREnvironment *spapr,
|
||||||
{
|
{
|
||||||
sPAPRNVRAM *nvram = spapr->nvram;
|
sPAPRNVRAM *nvram = spapr->nvram;
|
||||||
hwaddr offset, buffer, len;
|
hwaddr offset, buffer, len;
|
||||||
int alen;
|
|
||||||
void *membuf;
|
void *membuf;
|
||||||
|
|
||||||
if ((nargs != 3) || (nret != 2)) {
|
if ((nargs != 3) || (nret != 2)) {
|
||||||
|
@ -77,19 +76,14 @@ static void rtas_nvram_fetch(PowerPCCPU *cpu, sPAPREnvironment *spapr,
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
membuf = cpu_physical_memory_map(buffer, &len, 1);
|
|
||||||
if (nvram->blk) {
|
|
||||||
alen = blk_pread(nvram->blk, offset, membuf, len);
|
|
||||||
} else {
|
|
||||||
assert(nvram->buf);
|
assert(nvram->buf);
|
||||||
|
|
||||||
|
membuf = cpu_physical_memory_map(buffer, &len, 1);
|
||||||
memcpy(membuf, nvram->buf + offset, len);
|
memcpy(membuf, nvram->buf + offset, len);
|
||||||
alen = len;
|
|
||||||
}
|
|
||||||
cpu_physical_memory_unmap(membuf, len, 1, len);
|
cpu_physical_memory_unmap(membuf, len, 1, len);
|
||||||
|
|
||||||
rtas_st(rets, 0, (alen < len) ? RTAS_OUT_HW_ERROR : RTAS_OUT_SUCCESS);
|
rtas_st(rets, 0, RTAS_OUT_SUCCESS);
|
||||||
rtas_st(rets, 1, (alen < 0) ? 0 : alen);
|
rtas_st(rets, 1, len);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void rtas_nvram_store(PowerPCCPU *cpu, sPAPREnvironment *spapr,
|
static void rtas_nvram_store(PowerPCCPU *cpu, sPAPREnvironment *spapr,
|
||||||
|
@ -123,14 +117,15 @@ static void rtas_nvram_store(PowerPCCPU *cpu, sPAPREnvironment *spapr,
|
||||||
}
|
}
|
||||||
|
|
||||||
membuf = cpu_physical_memory_map(buffer, &len, 0);
|
membuf = cpu_physical_memory_map(buffer, &len, 0);
|
||||||
|
|
||||||
|
alen = len;
|
||||||
if (nvram->blk) {
|
if (nvram->blk) {
|
||||||
alen = blk_pwrite(nvram->blk, offset, membuf, len);
|
alen = blk_pwrite(nvram->blk, offset, membuf, len);
|
||||||
} else {
|
|
||||||
assert(nvram->buf);
|
|
||||||
|
|
||||||
memcpy(nvram->buf + offset, membuf, len);
|
|
||||||
alen = len;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
assert(nvram->buf);
|
||||||
|
memcpy(nvram->buf + offset, membuf, len);
|
||||||
|
|
||||||
cpu_physical_memory_unmap(membuf, len, 0, len);
|
cpu_physical_memory_unmap(membuf, len, 0, len);
|
||||||
|
|
||||||
rtas_st(rets, 0, (alen < len) ? RTAS_OUT_HW_ERROR : RTAS_OUT_SUCCESS);
|
rtas_st(rets, 0, (alen < len) ? RTAS_OUT_HW_ERROR : RTAS_OUT_SUCCESS);
|
||||||
|
@ -145,15 +140,24 @@ static int spapr_nvram_init(VIOsPAPRDevice *dev)
|
||||||
nvram->size = blk_getlength(nvram->blk);
|
nvram->size = blk_getlength(nvram->blk);
|
||||||
} else {
|
} else {
|
||||||
nvram->size = DEFAULT_NVRAM_SIZE;
|
nvram->size = DEFAULT_NVRAM_SIZE;
|
||||||
nvram->buf = g_malloc0(nvram->size);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
nvram->buf = g_malloc0(nvram->size);
|
||||||
|
|
||||||
if ((nvram->size < MIN_NVRAM_SIZE) || (nvram->size > MAX_NVRAM_SIZE)) {
|
if ((nvram->size < MIN_NVRAM_SIZE) || (nvram->size > MAX_NVRAM_SIZE)) {
|
||||||
fprintf(stderr, "spapr-nvram must be between %d and %d bytes in size\n",
|
fprintf(stderr, "spapr-nvram must be between %d and %d bytes in size\n",
|
||||||
MIN_NVRAM_SIZE, MAX_NVRAM_SIZE);
|
MIN_NVRAM_SIZE, MAX_NVRAM_SIZE);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (nvram->blk) {
|
||||||
|
int alen = blk_pread(nvram->blk, 0, nvram->buf, nvram->size);
|
||||||
|
|
||||||
|
if (alen != nvram->size) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
spapr_rtas_register(RTAS_NVRAM_FETCH, "nvram-fetch", rtas_nvram_fetch);
|
spapr_rtas_register(RTAS_NVRAM_FETCH, "nvram-fetch", rtas_nvram_fetch);
|
||||||
spapr_rtas_register(RTAS_NVRAM_STORE, "nvram-store", rtas_nvram_store);
|
spapr_rtas_register(RTAS_NVRAM_STORE, "nvram-store", rtas_nvram_store);
|
||||||
|
|
||||||
|
@ -167,6 +171,48 @@ static int spapr_nvram_devnode(VIOsPAPRDevice *dev, void *fdt, int node_off)
|
||||||
return fdt_setprop_cell(fdt, node_off, "#bytes", nvram->size);
|
return fdt_setprop_cell(fdt, node_off, "#bytes", nvram->size);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int spapr_nvram_pre_load(void *opaque)
|
||||||
|
{
|
||||||
|
sPAPRNVRAM *nvram = VIO_SPAPR_NVRAM(opaque);
|
||||||
|
|
||||||
|
g_free(nvram->buf);
|
||||||
|
nvram->buf = NULL;
|
||||||
|
nvram->size = 0;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int spapr_nvram_post_load(void *opaque, int version_id)
|
||||||
|
{
|
||||||
|
sPAPRNVRAM *nvram = VIO_SPAPR_NVRAM(opaque);
|
||||||
|
|
||||||
|
if (nvram->blk) {
|
||||||
|
int alen = blk_pwrite(nvram->blk, 0, nvram->buf, nvram->size);
|
||||||
|
|
||||||
|
if (alen < 0) {
|
||||||
|
return alen;
|
||||||
|
}
|
||||||
|
if (alen != nvram->size) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static const VMStateDescription vmstate_spapr_nvram = {
|
||||||
|
.name = "spapr_nvram",
|
||||||
|
.version_id = 1,
|
||||||
|
.minimum_version_id = 1,
|
||||||
|
.pre_load = spapr_nvram_pre_load,
|
||||||
|
.post_load = spapr_nvram_post_load,
|
||||||
|
.fields = (VMStateField[]) {
|
||||||
|
VMSTATE_UINT32(size, sPAPRNVRAM),
|
||||||
|
VMSTATE_VBUFFER_ALLOC_UINT32(buf, sPAPRNVRAM, 1, NULL, 0, size),
|
||||||
|
VMSTATE_END_OF_LIST()
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
static Property spapr_nvram_properties[] = {
|
static Property spapr_nvram_properties[] = {
|
||||||
DEFINE_SPAPR_PROPERTIES(sPAPRNVRAM, sdev),
|
DEFINE_SPAPR_PROPERTIES(sPAPRNVRAM, sdev),
|
||||||
DEFINE_PROP_DRIVE("drive", sPAPRNVRAM, blk),
|
DEFINE_PROP_DRIVE("drive", sPAPRNVRAM, blk),
|
||||||
|
@ -185,6 +231,7 @@ static void spapr_nvram_class_init(ObjectClass *klass, void *data)
|
||||||
k->dt_compatible = "qemu,spapr-nvram";
|
k->dt_compatible = "qemu,spapr-nvram";
|
||||||
set_bit(DEVICE_CATEGORY_MISC, dc->categories);
|
set_bit(DEVICE_CATEGORY_MISC, dc->categories);
|
||||||
dc->props = spapr_nvram_properties;
|
dc->props = spapr_nvram_properties;
|
||||||
|
dc->vmsd = &vmstate_spapr_nvram;
|
||||||
}
|
}
|
||||||
|
|
||||||
static const TypeInfo spapr_nvram_type_info = {
|
static const TypeInfo spapr_nvram_type_info = {
|
||||||
|
|
|
@ -20,4 +20,4 @@ obj-$(CONFIG_MAC) += mac_newworld.o
|
||||||
obj-$(CONFIG_E500) += e500.o mpc8544ds.o e500plat.o
|
obj-$(CONFIG_E500) += e500.o mpc8544ds.o e500plat.o
|
||||||
obj-$(CONFIG_E500) += mpc8544_guts.o ppce500_spin.o
|
obj-$(CONFIG_E500) += mpc8544_guts.o ppce500_spin.o
|
||||||
# PowerPC 440 Xilinx ML507 reference board.
|
# PowerPC 440 Xilinx ML507 reference board.
|
||||||
obj-y += virtex_ml507.o
|
obj-$(CONFIG_XILINX) += virtex_ml507.o
|
||||||
|
|
199
hw/ppc/e500.c
199
hw/ppc/e500.c
|
@ -36,6 +36,9 @@
|
||||||
#include "exec/address-spaces.h"
|
#include "exec/address-spaces.h"
|
||||||
#include "qemu/host-utils.h"
|
#include "qemu/host-utils.h"
|
||||||
#include "hw/pci-host/ppce500.h"
|
#include "hw/pci-host/ppce500.h"
|
||||||
|
#include "qemu/error-report.h"
|
||||||
|
#include "hw/platform-bus.h"
|
||||||
|
#include "hw/net/fsl_etsec/etsec.h"
|
||||||
|
|
||||||
#define EPAPR_MAGIC (0x45504150)
|
#define EPAPR_MAGIC (0x45504150)
|
||||||
#define BINARY_DEVICE_TREE_FILE "mpc8544ds.dtb"
|
#define BINARY_DEVICE_TREE_FILE "mpc8544ds.dtb"
|
||||||
|
@ -61,6 +64,8 @@
|
||||||
#define MPC8544_PCI_IO 0xE1000000ULL
|
#define MPC8544_PCI_IO 0xE1000000ULL
|
||||||
#define MPC8544_UTIL_OFFSET 0xe0000ULL
|
#define MPC8544_UTIL_OFFSET 0xe0000ULL
|
||||||
#define MPC8544_SPIN_BASE 0xEF000000ULL
|
#define MPC8544_SPIN_BASE 0xEF000000ULL
|
||||||
|
#define MPC8XXX_GPIO_OFFSET 0x000FF000ULL
|
||||||
|
#define MPC8XXX_GPIO_IRQ 43
|
||||||
|
|
||||||
struct boot_info
|
struct boot_info
|
||||||
{
|
{
|
||||||
|
@ -122,6 +127,142 @@ static void dt_serial_create(void *fdt, unsigned long long offset,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void create_dt_mpc8xxx_gpio(void *fdt, const char *soc, const char *mpic)
|
||||||
|
{
|
||||||
|
hwaddr mmio0 = MPC8XXX_GPIO_OFFSET;
|
||||||
|
int irq0 = MPC8XXX_GPIO_IRQ;
|
||||||
|
gchar *node = g_strdup_printf("%s/gpio@%"PRIx64, soc, mmio0);
|
||||||
|
gchar *poweroff = g_strdup_printf("%s/power-off", soc);
|
||||||
|
int gpio_ph;
|
||||||
|
|
||||||
|
qemu_fdt_add_subnode(fdt, node);
|
||||||
|
qemu_fdt_setprop_string(fdt, node, "compatible", "fsl,qoriq-gpio");
|
||||||
|
qemu_fdt_setprop_cells(fdt, node, "reg", mmio0, 0x1000);
|
||||||
|
qemu_fdt_setprop_cells(fdt, node, "interrupts", irq0, 0x2);
|
||||||
|
qemu_fdt_setprop_phandle(fdt, node, "interrupt-parent", mpic);
|
||||||
|
qemu_fdt_setprop_cells(fdt, node, "#gpio-cells", 2);
|
||||||
|
qemu_fdt_setprop(fdt, node, "gpio-controller", NULL, 0);
|
||||||
|
gpio_ph = qemu_fdt_alloc_phandle(fdt);
|
||||||
|
qemu_fdt_setprop_cell(fdt, node, "phandle", gpio_ph);
|
||||||
|
qemu_fdt_setprop_cell(fdt, node, "linux,phandle", gpio_ph);
|
||||||
|
|
||||||
|
/* Power Off Pin */
|
||||||
|
qemu_fdt_add_subnode(fdt, poweroff);
|
||||||
|
qemu_fdt_setprop_string(fdt, poweroff, "compatible", "gpio-poweroff");
|
||||||
|
qemu_fdt_setprop_cells(fdt, poweroff, "gpios", gpio_ph, 0, 0);
|
||||||
|
|
||||||
|
g_free(node);
|
||||||
|
g_free(poweroff);
|
||||||
|
}
|
||||||
|
|
||||||
|
typedef struct PlatformDevtreeData {
|
||||||
|
void *fdt;
|
||||||
|
const char *mpic;
|
||||||
|
int irq_start;
|
||||||
|
const char *node;
|
||||||
|
PlatformBusDevice *pbus;
|
||||||
|
} PlatformDevtreeData;
|
||||||
|
|
||||||
|
static int create_devtree_etsec(SysBusDevice *sbdev, PlatformDevtreeData *data)
|
||||||
|
{
|
||||||
|
eTSEC *etsec = ETSEC_COMMON(sbdev);
|
||||||
|
PlatformBusDevice *pbus = data->pbus;
|
||||||
|
hwaddr mmio0 = platform_bus_get_mmio_addr(pbus, sbdev, 0);
|
||||||
|
int irq0 = platform_bus_get_irqn(pbus, sbdev, 0);
|
||||||
|
int irq1 = platform_bus_get_irqn(pbus, sbdev, 1);
|
||||||
|
int irq2 = platform_bus_get_irqn(pbus, sbdev, 2);
|
||||||
|
gchar *node = g_strdup_printf("/platform/ethernet@%"PRIx64, mmio0);
|
||||||
|
gchar *group = g_strdup_printf("%s/queue-group", node);
|
||||||
|
void *fdt = data->fdt;
|
||||||
|
|
||||||
|
assert((int64_t)mmio0 >= 0);
|
||||||
|
assert(irq0 >= 0);
|
||||||
|
assert(irq1 >= 0);
|
||||||
|
assert(irq2 >= 0);
|
||||||
|
|
||||||
|
qemu_fdt_add_subnode(fdt, node);
|
||||||
|
qemu_fdt_setprop_string(fdt, node, "device_type", "network");
|
||||||
|
qemu_fdt_setprop_string(fdt, node, "compatible", "fsl,etsec2");
|
||||||
|
qemu_fdt_setprop_string(fdt, node, "model", "eTSEC");
|
||||||
|
qemu_fdt_setprop(fdt, node, "local-mac-address", etsec->conf.macaddr.a, 6);
|
||||||
|
qemu_fdt_setprop_cells(fdt, node, "fixed-link", 0, 1, 1000, 0, 0);
|
||||||
|
|
||||||
|
qemu_fdt_add_subnode(fdt, group);
|
||||||
|
qemu_fdt_setprop_cells(fdt, group, "reg", mmio0, 0x1000);
|
||||||
|
qemu_fdt_setprop_cells(fdt, group, "interrupts",
|
||||||
|
data->irq_start + irq0, 0x2,
|
||||||
|
data->irq_start + irq1, 0x2,
|
||||||
|
data->irq_start + irq2, 0x2);
|
||||||
|
|
||||||
|
g_free(node);
|
||||||
|
g_free(group);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int sysbus_device_create_devtree(SysBusDevice *sbdev, void *opaque)
|
||||||
|
{
|
||||||
|
PlatformDevtreeData *data = opaque;
|
||||||
|
bool matched = false;
|
||||||
|
|
||||||
|
if (object_dynamic_cast(OBJECT(sbdev), TYPE_ETSEC_COMMON)) {
|
||||||
|
create_devtree_etsec(sbdev, data);
|
||||||
|
matched = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!matched) {
|
||||||
|
error_report("Device %s is not supported by this machine yet.",
|
||||||
|
qdev_fw_name(DEVICE(sbdev)));
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void platform_bus_create_devtree(PPCE500Params *params, void *fdt,
|
||||||
|
const char *mpic)
|
||||||
|
{
|
||||||
|
gchar *node = g_strdup_printf("/platform@%"PRIx64, params->platform_bus_base);
|
||||||
|
const char platcomp[] = "qemu,platform\0simple-bus";
|
||||||
|
uint64_t addr = params->platform_bus_base;
|
||||||
|
uint64_t size = params->platform_bus_size;
|
||||||
|
int irq_start = params->platform_bus_first_irq;
|
||||||
|
PlatformBusDevice *pbus;
|
||||||
|
DeviceState *dev;
|
||||||
|
|
||||||
|
/* Create a /platform node that we can put all devices into */
|
||||||
|
|
||||||
|
qemu_fdt_add_subnode(fdt, node);
|
||||||
|
qemu_fdt_setprop(fdt, node, "compatible", platcomp, sizeof(platcomp));
|
||||||
|
|
||||||
|
/* Our platform bus region is less than 32bit big, so 1 cell is enough for
|
||||||
|
address and size */
|
||||||
|
qemu_fdt_setprop_cells(fdt, node, "#size-cells", 1);
|
||||||
|
qemu_fdt_setprop_cells(fdt, node, "#address-cells", 1);
|
||||||
|
qemu_fdt_setprop_cells(fdt, node, "ranges", 0, addr >> 32, addr, size);
|
||||||
|
|
||||||
|
qemu_fdt_setprop_phandle(fdt, node, "interrupt-parent", mpic);
|
||||||
|
|
||||||
|
dev = qdev_find_recursive(sysbus_get_default(), TYPE_PLATFORM_BUS_DEVICE);
|
||||||
|
pbus = PLATFORM_BUS_DEVICE(dev);
|
||||||
|
|
||||||
|
/* We can only create dt nodes for dynamic devices when they're ready */
|
||||||
|
if (pbus->done_gathering) {
|
||||||
|
PlatformDevtreeData data = {
|
||||||
|
.fdt = fdt,
|
||||||
|
.mpic = mpic,
|
||||||
|
.irq_start = irq_start,
|
||||||
|
.node = node,
|
||||||
|
.pbus = pbus,
|
||||||
|
};
|
||||||
|
|
||||||
|
/* Loop through all dynamic sysbus devices and create nodes for them */
|
||||||
|
foreach_dynamic_sysbus_device(sysbus_device_create_devtree, &data);
|
||||||
|
}
|
||||||
|
|
||||||
|
g_free(node);
|
||||||
|
}
|
||||||
|
|
||||||
static int ppce500_load_device_tree(MachineState *machine,
|
static int ppce500_load_device_tree(MachineState *machine,
|
||||||
PPCE500Params *params,
|
PPCE500Params *params,
|
||||||
hwaddr addr,
|
hwaddr addr,
|
||||||
|
@ -379,6 +520,14 @@ static int ppce500_load_device_tree(MachineState *machine,
|
||||||
qemu_fdt_setprop_cell(fdt, pci, "#address-cells", 3);
|
qemu_fdt_setprop_cell(fdt, pci, "#address-cells", 3);
|
||||||
qemu_fdt_setprop_string(fdt, "/aliases", "pci0", pci);
|
qemu_fdt_setprop_string(fdt, "/aliases", "pci0", pci);
|
||||||
|
|
||||||
|
if (params->has_mpc8xxx_gpio) {
|
||||||
|
create_dt_mpc8xxx_gpio(fdt, soc, mpic);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (params->has_platform_bus) {
|
||||||
|
platform_bus_create_devtree(params, fdt, mpic);
|
||||||
|
}
|
||||||
|
|
||||||
params->fixup_devtree(params, fdt);
|
params->fixup_devtree(params, fdt);
|
||||||
|
|
||||||
if (toplevel_compat) {
|
if (toplevel_compat) {
|
||||||
|
@ -407,6 +556,7 @@ typedef struct DeviceTreeParams {
|
||||||
hwaddr initrd_size;
|
hwaddr initrd_size;
|
||||||
hwaddr kernel_base;
|
hwaddr kernel_base;
|
||||||
hwaddr kernel_size;
|
hwaddr kernel_size;
|
||||||
|
Notifier notifier;
|
||||||
} DeviceTreeParams;
|
} DeviceTreeParams;
|
||||||
|
|
||||||
static void ppce500_reset_device_tree(void *opaque)
|
static void ppce500_reset_device_tree(void *opaque)
|
||||||
|
@ -417,6 +567,12 @@ static void ppce500_reset_device_tree(void *opaque)
|
||||||
false);
|
false);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void ppce500_init_notify(Notifier *notifier, void *data)
|
||||||
|
{
|
||||||
|
DeviceTreeParams *p = container_of(notifier, DeviceTreeParams, notifier);
|
||||||
|
ppce500_reset_device_tree(p);
|
||||||
|
}
|
||||||
|
|
||||||
static int ppce500_prep_device_tree(MachineState *machine,
|
static int ppce500_prep_device_tree(MachineState *machine,
|
||||||
PPCE500Params *params,
|
PPCE500Params *params,
|
||||||
hwaddr addr,
|
hwaddr addr,
|
||||||
|
@ -435,6 +591,8 @@ static int ppce500_prep_device_tree(MachineState *machine,
|
||||||
p->kernel_size = kernel_size;
|
p->kernel_size = kernel_size;
|
||||||
|
|
||||||
qemu_register_reset(ppce500_reset_device_tree, p);
|
qemu_register_reset(ppce500_reset_device_tree, p);
|
||||||
|
p->notifier.notify = ppce500_init_notify;
|
||||||
|
qemu_add_machine_init_done_notifier(&p->notifier);
|
||||||
|
|
||||||
/* Issue the device tree loader once, so that we get the size of the blob */
|
/* Issue the device tree loader once, so that we get the size of the blob */
|
||||||
return ppce500_load_device_tree(machine, params, addr, initrd_base,
|
return ppce500_load_device_tree(machine, params, addr, initrd_base,
|
||||||
|
@ -618,6 +776,13 @@ static qemu_irq *ppce500_init_mpic(PPCE500Params *params, MemoryRegion *ccsr,
|
||||||
return mpic;
|
return mpic;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void ppce500_power_off(void *opaque, int line, int on)
|
||||||
|
{
|
||||||
|
if (on) {
|
||||||
|
qemu_system_shutdown_request();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void ppce500_init(MachineState *machine, PPCE500Params *params)
|
void ppce500_init(MachineState *machine, PPCE500Params *params)
|
||||||
{
|
{
|
||||||
MemoryRegion *address_space_mem = get_system_memory();
|
MemoryRegion *address_space_mem = get_system_memory();
|
||||||
|
@ -769,6 +934,40 @@ void ppce500_init(MachineState *machine, PPCE500Params *params)
|
||||||
cur_base = (32 * 1024 * 1024);
|
cur_base = (32 * 1024 * 1024);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (params->has_mpc8xxx_gpio) {
|
||||||
|
qemu_irq poweroff_irq;
|
||||||
|
|
||||||
|
dev = qdev_create(NULL, "mpc8xxx_gpio");
|
||||||
|
s = SYS_BUS_DEVICE(dev);
|
||||||
|
qdev_init_nofail(dev);
|
||||||
|
sysbus_connect_irq(s, 0, mpic[MPC8XXX_GPIO_IRQ]);
|
||||||
|
memory_region_add_subregion(ccsr_addr_space, MPC8XXX_GPIO_OFFSET,
|
||||||
|
sysbus_mmio_get_region(s, 0));
|
||||||
|
|
||||||
|
/* Power Off GPIO at Pin 0 */
|
||||||
|
poweroff_irq = qemu_allocate_irq(ppce500_power_off, NULL, 0);
|
||||||
|
qdev_connect_gpio_out(dev, 0, poweroff_irq);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Platform Bus Device */
|
||||||
|
if (params->has_platform_bus) {
|
||||||
|
dev = qdev_create(NULL, TYPE_PLATFORM_BUS_DEVICE);
|
||||||
|
dev->id = TYPE_PLATFORM_BUS_DEVICE;
|
||||||
|
qdev_prop_set_uint32(dev, "num_irqs", params->platform_bus_num_irqs);
|
||||||
|
qdev_prop_set_uint32(dev, "mmio_size", params->platform_bus_size);
|
||||||
|
qdev_init_nofail(dev);
|
||||||
|
s = SYS_BUS_DEVICE(dev);
|
||||||
|
|
||||||
|
for (i = 0; i < params->platform_bus_num_irqs; i++) {
|
||||||
|
int irqn = params->platform_bus_first_irq + i;
|
||||||
|
sysbus_connect_irq(s, i, mpic[irqn]);
|
||||||
|
}
|
||||||
|
|
||||||
|
memory_region_add_subregion(address_space_mem,
|
||||||
|
params->platform_bus_base,
|
||||||
|
sysbus_mmio_get_region(s, 0));
|
||||||
|
}
|
||||||
|
|
||||||
/* Load kernel. */
|
/* Load kernel. */
|
||||||
if (machine->kernel_filename) {
|
if (machine->kernel_filename) {
|
||||||
kernel_base = cur_base;
|
kernel_base = cur_base;
|
||||||
|
|
|
@ -11,6 +11,12 @@ typedef struct PPCE500Params {
|
||||||
void (*fixup_devtree)(struct PPCE500Params *params, void *fdt);
|
void (*fixup_devtree)(struct PPCE500Params *params, void *fdt);
|
||||||
|
|
||||||
int mpic_version;
|
int mpic_version;
|
||||||
|
bool has_mpc8xxx_gpio;
|
||||||
|
bool has_platform_bus;
|
||||||
|
hwaddr platform_bus_base;
|
||||||
|
hwaddr platform_bus_size;
|
||||||
|
int platform_bus_first_irq;
|
||||||
|
int platform_bus_num_irqs;
|
||||||
} PPCE500Params;
|
} PPCE500Params;
|
||||||
|
|
||||||
void ppce500_init(MachineState *machine, PPCE500Params *params);
|
void ppce500_init(MachineState *machine, PPCE500Params *params);
|
||||||
|
|
|
@ -35,6 +35,12 @@ static void e500plat_init(MachineState *machine)
|
||||||
.pci_nr_slots = PCI_SLOT_MAX - 1,
|
.pci_nr_slots = PCI_SLOT_MAX - 1,
|
||||||
.fixup_devtree = e500plat_fixup_devtree,
|
.fixup_devtree = e500plat_fixup_devtree,
|
||||||
.mpic_version = OPENPIC_MODEL_FSL_MPIC_42,
|
.mpic_version = OPENPIC_MODEL_FSL_MPIC_42,
|
||||||
|
.has_mpc8xxx_gpio = true,
|
||||||
|
.has_platform_bus = true,
|
||||||
|
.platform_bus_base = 0xf00000000ULL,
|
||||||
|
.platform_bus_size = (128ULL * 1024 * 1024),
|
||||||
|
.platform_bus_first_irq = 5,
|
||||||
|
.platform_bus_num_irqs = 10,
|
||||||
};
|
};
|
||||||
|
|
||||||
/* Older KVM versions don't support EPR which breaks guests when we announce
|
/* Older KVM versions don't support EPR which breaks guests when we announce
|
||||||
|
@ -51,6 +57,7 @@ static QEMUMachine e500plat_machine = {
|
||||||
.desc = "generic paravirt e500 platform",
|
.desc = "generic paravirt e500 platform",
|
||||||
.init = e500plat_init,
|
.init = e500plat_init,
|
||||||
.max_cpus = 32,
|
.max_cpus = 32,
|
||||||
|
.has_dynamic_sysbus = true,
|
||||||
};
|
};
|
||||||
|
|
||||||
static void e500plat_machine_init(void)
|
static void e500plat_machine_init(void)
|
||||||
|
|
|
@ -92,30 +92,6 @@ typedef struct PPC4xxPCIState PPC4xxPCIState;
|
||||||
|
|
||||||
#define PCI_ALL_SIZE (PCI_REG_BASE + PCI_REG_SIZE)
|
#define PCI_ALL_SIZE (PCI_REG_BASE + PCI_REG_SIZE)
|
||||||
|
|
||||||
static uint64_t pci4xx_cfgaddr_read(void *opaque, hwaddr addr,
|
|
||||||
unsigned size)
|
|
||||||
{
|
|
||||||
PPC4xxPCIState *ppc4xx_pci = opaque;
|
|
||||||
PCIHostState *phb = PCI_HOST_BRIDGE(ppc4xx_pci);
|
|
||||||
|
|
||||||
return phb->config_reg;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void pci4xx_cfgaddr_write(void *opaque, hwaddr addr,
|
|
||||||
uint64_t value, unsigned size)
|
|
||||||
{
|
|
||||||
PPC4xxPCIState *ppc4xx_pci = opaque;
|
|
||||||
PCIHostState *phb = PCI_HOST_BRIDGE(ppc4xx_pci);
|
|
||||||
|
|
||||||
phb->config_reg = value & ~0x3;
|
|
||||||
}
|
|
||||||
|
|
||||||
static const MemoryRegionOps pci4xx_cfgaddr_ops = {
|
|
||||||
.read = pci4xx_cfgaddr_read,
|
|
||||||
.write = pci4xx_cfgaddr_write,
|
|
||||||
.endianness = DEVICE_LITTLE_ENDIAN,
|
|
||||||
};
|
|
||||||
|
|
||||||
static void ppc4xx_pci_reg_write4(void *opaque, hwaddr offset,
|
static void ppc4xx_pci_reg_write4(void *opaque, hwaddr offset,
|
||||||
uint64_t value, unsigned size)
|
uint64_t value, unsigned size)
|
||||||
{
|
{
|
||||||
|
|
|
@ -850,11 +850,31 @@ static void spapr_reset_htab(sPAPREnvironment *spapr)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int find_unknown_sysbus_device(SysBusDevice *sbdev, void *opaque)
|
||||||
|
{
|
||||||
|
bool matched = false;
|
||||||
|
|
||||||
|
if (object_dynamic_cast(OBJECT(sbdev), TYPE_SPAPR_PCI_HOST_BRIDGE)) {
|
||||||
|
matched = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!matched) {
|
||||||
|
error_report("Device %s is not supported by this machine yet.",
|
||||||
|
qdev_fw_name(DEVICE(sbdev)));
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
static void ppc_spapr_reset(void)
|
static void ppc_spapr_reset(void)
|
||||||
{
|
{
|
||||||
PowerPCCPU *first_ppc_cpu;
|
PowerPCCPU *first_ppc_cpu;
|
||||||
uint32_t rtas_limit;
|
uint32_t rtas_limit;
|
||||||
|
|
||||||
|
/* Check for unknown sysbus devices */
|
||||||
|
foreach_dynamic_sysbus_device(find_unknown_sysbus_device, NULL);
|
||||||
|
|
||||||
/* Reset the hash table & recalc the RMA */
|
/* Reset the hash table & recalc the RMA */
|
||||||
spapr_reset_htab(spapr);
|
spapr_reset_htab(spapr);
|
||||||
|
|
||||||
|
@ -1660,9 +1680,6 @@ static void spapr_machine_class_init(ObjectClass *oc, void *data)
|
||||||
FWPathProviderClass *fwc = FW_PATH_PROVIDER_CLASS(oc);
|
FWPathProviderClass *fwc = FW_PATH_PROVIDER_CLASS(oc);
|
||||||
NMIClass *nc = NMI_CLASS(oc);
|
NMIClass *nc = NMI_CLASS(oc);
|
||||||
|
|
||||||
mc->name = "pseries";
|
|
||||||
mc->desc = "pSeries Logical Partition (PAPR compliant)";
|
|
||||||
mc->is_default = 1;
|
|
||||||
mc->init = ppc_spapr_init;
|
mc->init = ppc_spapr_init;
|
||||||
mc->reset = ppc_spapr_reset;
|
mc->reset = ppc_spapr_reset;
|
||||||
mc->block_default_type = IF_SCSI;
|
mc->block_default_type = IF_SCSI;
|
||||||
|
@ -1670,6 +1687,7 @@ static void spapr_machine_class_init(ObjectClass *oc, void *data)
|
||||||
mc->no_parallel = 1;
|
mc->no_parallel = 1;
|
||||||
mc->default_boot_order = NULL;
|
mc->default_boot_order = NULL;
|
||||||
mc->kvm_type = spapr_kvm_type;
|
mc->kvm_type = spapr_kvm_type;
|
||||||
|
mc->has_dynamic_sysbus = true;
|
||||||
|
|
||||||
fwc->get_dev_path = spapr_get_fw_dev_path;
|
fwc->get_dev_path = spapr_get_fw_dev_path;
|
||||||
nc->nmi_monitor_handler = spapr_nmi;
|
nc->nmi_monitor_handler = spapr_nmi;
|
||||||
|
@ -1678,6 +1696,7 @@ static void spapr_machine_class_init(ObjectClass *oc, void *data)
|
||||||
static const TypeInfo spapr_machine_info = {
|
static const TypeInfo spapr_machine_info = {
|
||||||
.name = TYPE_SPAPR_MACHINE,
|
.name = TYPE_SPAPR_MACHINE,
|
||||||
.parent = TYPE_MACHINE,
|
.parent = TYPE_MACHINE,
|
||||||
|
.abstract = true,
|
||||||
.instance_size = sizeof(sPAPRMachineState),
|
.instance_size = sizeof(sPAPRMachineState),
|
||||||
.instance_init = spapr_machine_initfn,
|
.instance_init = spapr_machine_initfn,
|
||||||
.class_init = spapr_machine_class_init,
|
.class_init = spapr_machine_class_init,
|
||||||
|
@ -1698,7 +1717,6 @@ static void spapr_machine_2_1_class_init(ObjectClass *oc, void *data)
|
||||||
|
|
||||||
mc->name = "pseries-2.1";
|
mc->name = "pseries-2.1";
|
||||||
mc->desc = "pSeries Logical Partition (PAPR compliant) v2.1";
|
mc->desc = "pSeries Logical Partition (PAPR compliant) v2.1";
|
||||||
mc->is_default = 0;
|
|
||||||
mc->compat_props = compat_props;
|
mc->compat_props = compat_props;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1708,10 +1726,27 @@ static const TypeInfo spapr_machine_2_1_info = {
|
||||||
.class_init = spapr_machine_2_1_class_init,
|
.class_init = spapr_machine_2_1_class_init,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static void spapr_machine_2_2_class_init(ObjectClass *oc, void *data)
|
||||||
|
{
|
||||||
|
MachineClass *mc = MACHINE_CLASS(oc);
|
||||||
|
|
||||||
|
mc->name = "pseries-2.2";
|
||||||
|
mc->desc = "pSeries Logical Partition (PAPR compliant) v2.2";
|
||||||
|
mc->alias = "pseries";
|
||||||
|
mc->is_default = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static const TypeInfo spapr_machine_2_2_info = {
|
||||||
|
.name = TYPE_SPAPR_MACHINE "2.2",
|
||||||
|
.parent = TYPE_SPAPR_MACHINE,
|
||||||
|
.class_init = spapr_machine_2_2_class_init,
|
||||||
|
};
|
||||||
|
|
||||||
static void spapr_machine_register_types(void)
|
static void spapr_machine_register_types(void)
|
||||||
{
|
{
|
||||||
type_register_static(&spapr_machine_info);
|
type_register_static(&spapr_machine_info);
|
||||||
type_register_static(&spapr_machine_2_1_info);
|
type_register_static(&spapr_machine_2_1_info);
|
||||||
|
type_register_static(&spapr_machine_2_2_info);
|
||||||
}
|
}
|
||||||
|
|
||||||
type_init(spapr_machine_register_types)
|
type_init(spapr_machine_register_types)
|
||||||
|
|
|
@ -704,28 +704,34 @@ static const VMStateDescription vmstate_spapr_pci_msi = {
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static void spapr_pci_fill_msi_devs(gpointer key, gpointer value,
|
||||||
|
gpointer opaque)
|
||||||
|
{
|
||||||
|
sPAPRPHBState *sphb = opaque;
|
||||||
|
|
||||||
|
sphb->msi_devs[sphb->msi_devs_num].key = *(uint32_t *)key;
|
||||||
|
sphb->msi_devs[sphb->msi_devs_num].value = *(spapr_pci_msi *)value;
|
||||||
|
sphb->msi_devs_num++;
|
||||||
|
}
|
||||||
|
|
||||||
static void spapr_pci_pre_save(void *opaque)
|
static void spapr_pci_pre_save(void *opaque)
|
||||||
{
|
{
|
||||||
sPAPRPHBState *sphb = opaque;
|
sPAPRPHBState *sphb = opaque;
|
||||||
GHashTableIter iter;
|
int msi_devs_num;
|
||||||
gpointer key, value;
|
|
||||||
int i;
|
|
||||||
|
|
||||||
if (sphb->msi_devs) {
|
if (sphb->msi_devs) {
|
||||||
g_free(sphb->msi_devs);
|
g_free(sphb->msi_devs);
|
||||||
sphb->msi_devs = NULL;
|
sphb->msi_devs = NULL;
|
||||||
}
|
}
|
||||||
sphb->msi_devs_num = g_hash_table_size(sphb->msi);
|
sphb->msi_devs_num = 0;
|
||||||
if (!sphb->msi_devs_num) {
|
msi_devs_num = g_hash_table_size(sphb->msi);
|
||||||
|
if (!msi_devs_num) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
sphb->msi_devs = g_malloc(sphb->msi_devs_num * sizeof(spapr_pci_msi_mig));
|
sphb->msi_devs = g_malloc(msi_devs_num * sizeof(spapr_pci_msi_mig));
|
||||||
|
|
||||||
g_hash_table_iter_init(&iter, sphb->msi);
|
g_hash_table_foreach(sphb->msi, spapr_pci_fill_msi_devs, sphb);
|
||||||
for (i = 0; g_hash_table_iter_next(&iter, &key, &value); ++i) {
|
assert(sphb->msi_devs_num == msi_devs_num);
|
||||||
sphb->msi_devs[i].key = *(uint32_t *) key;
|
|
||||||
sphb->msi_devs[i].value = *(spapr_pci_msi *) value;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static int spapr_pci_post_load(void *opaque, int version_id)
|
static int spapr_pci_post_load(void *opaque, int version_id)
|
||||||
|
|
|
@ -36,7 +36,8 @@ struct QEMUMachine {
|
||||||
use_sclp:1,
|
use_sclp:1,
|
||||||
no_floppy:1,
|
no_floppy:1,
|
||||||
no_cdrom:1,
|
no_cdrom:1,
|
||||||
no_sdcard:1;
|
no_sdcard:1,
|
||||||
|
has_dynamic_sysbus:1;
|
||||||
int is_default;
|
int is_default;
|
||||||
const char *default_machine_opts;
|
const char *default_machine_opts;
|
||||||
const char *default_boot_order;
|
const char *default_boot_order;
|
||||||
|
@ -97,7 +98,8 @@ struct MachineClass {
|
||||||
use_sclp:1,
|
use_sclp:1,
|
||||||
no_floppy:1,
|
no_floppy:1,
|
||||||
no_cdrom:1,
|
no_cdrom:1,
|
||||||
no_sdcard:1;
|
no_sdcard:1,
|
||||||
|
has_dynamic_sysbus:1;
|
||||||
int is_default;
|
int is_default;
|
||||||
const char *default_machine_opts;
|
const char *default_machine_opts;
|
||||||
const char *default_boot_order;
|
const char *default_boot_order;
|
||||||
|
@ -115,6 +117,8 @@ struct MachineClass {
|
||||||
struct MachineState {
|
struct MachineState {
|
||||||
/*< private >*/
|
/*< private >*/
|
||||||
Object parent_obj;
|
Object parent_obj;
|
||||||
|
Notifier sysbus_notifier;
|
||||||
|
|
||||||
/*< public >*/
|
/*< public >*/
|
||||||
|
|
||||||
char *accel;
|
char *accel;
|
||||||
|
|
|
@ -0,0 +1,57 @@
|
||||||
|
#ifndef HW_PLATFORM_BUS_H
|
||||||
|
#define HW_PLATFORM_BUS_H 1
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Platform Bus device to support dynamic Sysbus devices
|
||||||
|
*
|
||||||
|
* Copyright (C) 2014 Freescale Semiconductor, Inc. All rights reserved.
|
||||||
|
*
|
||||||
|
* Author: Alexander Graf, <agraf@suse.de>
|
||||||
|
*
|
||||||
|
* 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 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 "hw/sysbus.h"
|
||||||
|
|
||||||
|
typedef struct PlatformBusDevice PlatformBusDevice;
|
||||||
|
|
||||||
|
#define TYPE_PLATFORM_BUS_DEVICE "platform-bus-device"
|
||||||
|
#define PLATFORM_BUS_DEVICE(obj) \
|
||||||
|
OBJECT_CHECK(PlatformBusDevice, (obj), TYPE_PLATFORM_BUS_DEVICE)
|
||||||
|
#define PLATFORM_BUS_DEVICE_CLASS(klass) \
|
||||||
|
OBJECT_CLASS_CHECK(PlatformBusDeviceClass, (klass), TYPE_PLATFORM_BUS_DEVICE)
|
||||||
|
#define PLATFORM_BUS_DEVICE_GET_CLASS(obj) \
|
||||||
|
OBJECT_GET_CLASS(PlatformBusDeviceClass, (obj), TYPE_PLATFORM_BUS_DEVICE)
|
||||||
|
|
||||||
|
struct PlatformBusDevice {
|
||||||
|
/*< private >*/
|
||||||
|
SysBusDevice parent_obj;
|
||||||
|
Notifier notifier;
|
||||||
|
bool done_gathering;
|
||||||
|
|
||||||
|
/*< public >*/
|
||||||
|
uint32_t mmio_size;
|
||||||
|
MemoryRegion mmio;
|
||||||
|
|
||||||
|
uint32_t num_irqs;
|
||||||
|
qemu_irq *irqs;
|
||||||
|
unsigned long *used_irqs;
|
||||||
|
};
|
||||||
|
|
||||||
|
int platform_bus_get_irqn(PlatformBusDevice *platform_bus, SysBusDevice *sbdev,
|
||||||
|
int n);
|
||||||
|
hwaddr platform_bus_get_mmio_addr(PlatformBusDevice *pbus, SysBusDevice *sbdev,
|
||||||
|
int n);
|
||||||
|
|
||||||
|
#endif /* !HW_PLATFORM_BUS_H */
|
|
@ -272,6 +272,7 @@ qemu_irq qdev_get_gpio_in_named(DeviceState *dev, const char *name, int n);
|
||||||
void qdev_connect_gpio_out(DeviceState *dev, int n, qemu_irq pin);
|
void qdev_connect_gpio_out(DeviceState *dev, int n, qemu_irq pin);
|
||||||
void qdev_connect_gpio_out_named(DeviceState *dev, const char *name, int n,
|
void qdev_connect_gpio_out_named(DeviceState *dev, const char *name, int n,
|
||||||
qemu_irq pin);
|
qemu_irq pin);
|
||||||
|
qemu_irq qdev_get_gpio_out_connector(DeviceState *dev, const char *name, int n);
|
||||||
qemu_irq qdev_intercept_gpio_out(DeviceState *dev, qemu_irq icpt,
|
qemu_irq qdev_intercept_gpio_out(DeviceState *dev, qemu_irq icpt,
|
||||||
const char *name, int n);
|
const char *name, int n);
|
||||||
|
|
||||||
|
|
|
@ -57,6 +57,8 @@ struct SysBusDevice {
|
||||||
pio_addr_t pio[QDEV_MAX_PIO];
|
pio_addr_t pio[QDEV_MAX_PIO];
|
||||||
};
|
};
|
||||||
|
|
||||||
|
typedef int FindSysbusDeviceFunc(SysBusDevice *sbdev, void *opaque);
|
||||||
|
|
||||||
void sysbus_init_mmio(SysBusDevice *dev, MemoryRegion *memory);
|
void sysbus_init_mmio(SysBusDevice *dev, MemoryRegion *memory);
|
||||||
MemoryRegion *sysbus_mmio_get_region(SysBusDevice *dev, int n);
|
MemoryRegion *sysbus_mmio_get_region(SysBusDevice *dev, int n);
|
||||||
void sysbus_init_irq(SysBusDevice *dev, qemu_irq *p);
|
void sysbus_init_irq(SysBusDevice *dev, qemu_irq *p);
|
||||||
|
@ -64,7 +66,11 @@ void sysbus_pass_irq(SysBusDevice *dev, SysBusDevice *target);
|
||||||
void sysbus_init_ioports(SysBusDevice *dev, pio_addr_t ioport, pio_addr_t size);
|
void sysbus_init_ioports(SysBusDevice *dev, pio_addr_t ioport, pio_addr_t size);
|
||||||
|
|
||||||
|
|
||||||
|
bool sysbus_has_irq(SysBusDevice *dev, int n);
|
||||||
|
bool sysbus_has_mmio(SysBusDevice *dev, unsigned int n);
|
||||||
void sysbus_connect_irq(SysBusDevice *dev, int n, qemu_irq irq);
|
void sysbus_connect_irq(SysBusDevice *dev, int n, qemu_irq irq);
|
||||||
|
bool sysbus_is_irq_connected(SysBusDevice *dev, int n);
|
||||||
|
qemu_irq sysbus_get_connected_irq(SysBusDevice *dev, int n);
|
||||||
void sysbus_mmio_map(SysBusDevice *dev, int n, hwaddr addr);
|
void sysbus_mmio_map(SysBusDevice *dev, int n, hwaddr addr);
|
||||||
void sysbus_mmio_map_overlap(SysBusDevice *dev, int n, hwaddr addr,
|
void sysbus_mmio_map_overlap(SysBusDevice *dev, int n, hwaddr addr,
|
||||||
int priority);
|
int priority);
|
||||||
|
@ -72,6 +78,9 @@ void sysbus_add_io(SysBusDevice *dev, hwaddr addr,
|
||||||
MemoryRegion *mem);
|
MemoryRegion *mem);
|
||||||
MemoryRegion *sysbus_address_space(SysBusDevice *dev);
|
MemoryRegion *sysbus_address_space(SysBusDevice *dev);
|
||||||
|
|
||||||
|
/* Call func for every dynamically created sysbus device in the system */
|
||||||
|
void foreach_dynamic_sysbus_device(FindSysbusDeviceFunc *func, void *opaque);
|
||||||
|
|
||||||
/* Legacy helper function for creating devices. */
|
/* Legacy helper function for creating devices. */
|
||||||
DeviceState *sysbus_create_varargs(const char *name,
|
DeviceState *sysbus_create_varargs(const char *name,
|
||||||
hwaddr addr, ...);
|
hwaddr addr, ...);
|
||||||
|
|
|
@ -2968,7 +2968,7 @@ static target_long monitor_get_ccr (const struct MonitorDef *md, int val)
|
||||||
|
|
||||||
u = 0;
|
u = 0;
|
||||||
for (i = 0; i < 8; i++)
|
for (i = 0; i < 8; i++)
|
||||||
u |= env->crf[i] << (32 - (4 * i));
|
u |= env->crf[i] << (32 - (4 * (i + 1)));
|
||||||
|
|
||||||
return u;
|
return u;
|
||||||
}
|
}
|
||||||
|
|
|
@ -309,6 +309,9 @@
|
||||||
#endif
|
#endif
|
||||||
POWERPC_DEF("440-Xilinx", CPU_POWERPC_440_XILINX, 440x5,
|
POWERPC_DEF("440-Xilinx", CPU_POWERPC_440_XILINX, 440x5,
|
||||||
"PowerPC 440 Xilinx 5")
|
"PowerPC 440 Xilinx 5")
|
||||||
|
|
||||||
|
POWERPC_DEF("440-Xilinx-w-dfpu", CPU_POWERPC_440_XILINX, 440x5wDFPU,
|
||||||
|
"PowerPC 440 Xilinx 5 With a Double Prec. FPU")
|
||||||
#if defined(TODO)
|
#if defined(TODO)
|
||||||
POWERPC_DEF("440A5", CPU_POWERPC_440A5, 440x5,
|
POWERPC_DEF("440A5", CPU_POWERPC_440A5, 440x5,
|
||||||
"PowerPC 440 A5")
|
"PowerPC 440 A5")
|
||||||
|
|
|
@ -925,6 +925,7 @@ struct ppc_segment_page_sizes {
|
||||||
#define NB_MMU_MODES 3
|
#define NB_MMU_MODES 3
|
||||||
|
|
||||||
#define PPC_CPU_OPCODES_LEN 0x40
|
#define PPC_CPU_OPCODES_LEN 0x40
|
||||||
|
#define PPC_CPU_INDIRECT_OPCODES_LEN 0x20
|
||||||
|
|
||||||
struct CPUPPCState {
|
struct CPUPPCState {
|
||||||
/* First are the most commonly used resources
|
/* First are the most commonly used resources
|
||||||
|
@ -2007,13 +2008,16 @@ enum {
|
||||||
PPC2_ALTIVEC_207 = 0x0000000000004000ULL,
|
PPC2_ALTIVEC_207 = 0x0000000000004000ULL,
|
||||||
/* PowerISA 2.07 Book3s specification */
|
/* PowerISA 2.07 Book3s specification */
|
||||||
PPC2_ISA207S = 0x0000000000008000ULL,
|
PPC2_ISA207S = 0x0000000000008000ULL,
|
||||||
|
/* Double precision floating point conversion for signed integer 64 */
|
||||||
|
PPC2_FP_CVT_S64 = 0x0000000000010000ULL,
|
||||||
|
|
||||||
#define PPC_TCG_INSNS2 (PPC2_BOOKE206 | PPC2_VSX | PPC2_PRCNTL | PPC2_DBRX | \
|
#define PPC_TCG_INSNS2 (PPC2_BOOKE206 | PPC2_VSX | PPC2_PRCNTL | PPC2_DBRX | \
|
||||||
PPC2_ISA205 | PPC2_VSX207 | PPC2_PERM_ISA206 | \
|
PPC2_ISA205 | PPC2_VSX207 | PPC2_PERM_ISA206 | \
|
||||||
PPC2_DIVE_ISA206 | PPC2_ATOMIC_ISA206 | \
|
PPC2_DIVE_ISA206 | PPC2_ATOMIC_ISA206 | \
|
||||||
PPC2_FP_CVT_ISA206 | PPC2_FP_TST_ISA206 | \
|
PPC2_FP_CVT_ISA206 | PPC2_FP_TST_ISA206 | \
|
||||||
PPC2_BCTAR_ISA207 | PPC2_LSQ_ISA207 | \
|
PPC2_BCTAR_ISA207 | PPC2_LSQ_ISA207 | \
|
||||||
PPC2_ALTIVEC_207 | PPC2_ISA207S | PPC2_DFP)
|
PPC2_ALTIVEC_207 | PPC2_ISA207S | PPC2_DFP | \
|
||||||
|
PPC2_FP_CVT_S64)
|
||||||
};
|
};
|
||||||
|
|
||||||
/*****************************************************************************/
|
/*****************************************************************************/
|
||||||
|
|
|
@ -649,14 +649,10 @@ FPU_FCTI(fctiw, int32, 0x80000000U)
|
||||||
FPU_FCTI(fctiwz, int32_round_to_zero, 0x80000000U)
|
FPU_FCTI(fctiwz, int32_round_to_zero, 0x80000000U)
|
||||||
FPU_FCTI(fctiwu, uint32, 0x00000000U)
|
FPU_FCTI(fctiwu, uint32, 0x00000000U)
|
||||||
FPU_FCTI(fctiwuz, uint32_round_to_zero, 0x00000000U)
|
FPU_FCTI(fctiwuz, uint32_round_to_zero, 0x00000000U)
|
||||||
#if defined(TARGET_PPC64)
|
|
||||||
FPU_FCTI(fctid, int64, 0x8000000000000000ULL)
|
FPU_FCTI(fctid, int64, 0x8000000000000000ULL)
|
||||||
FPU_FCTI(fctidz, int64_round_to_zero, 0x8000000000000000ULL)
|
FPU_FCTI(fctidz, int64_round_to_zero, 0x8000000000000000ULL)
|
||||||
FPU_FCTI(fctidu, uint64, 0x0000000000000000ULL)
|
FPU_FCTI(fctidu, uint64, 0x0000000000000000ULL)
|
||||||
FPU_FCTI(fctiduz, uint64_round_to_zero, 0x0000000000000000ULL)
|
FPU_FCTI(fctiduz, uint64_round_to_zero, 0x0000000000000000ULL)
|
||||||
#endif
|
|
||||||
|
|
||||||
#if defined(TARGET_PPC64)
|
|
||||||
|
|
||||||
#define FPU_FCFI(op, cvtr, is_single) \
|
#define FPU_FCFI(op, cvtr, is_single) \
|
||||||
uint64_t helper_##op(CPUPPCState *env, uint64_t arg) \
|
uint64_t helper_##op(CPUPPCState *env, uint64_t arg) \
|
||||||
|
@ -678,8 +674,6 @@ FPU_FCFI(fcfids, int64_to_float32, 1)
|
||||||
FPU_FCFI(fcfidu, uint64_to_float64, 0)
|
FPU_FCFI(fcfidu, uint64_to_float64, 0)
|
||||||
FPU_FCFI(fcfidus, uint64_to_float32, 1)
|
FPU_FCFI(fcfidus, uint64_to_float32, 1)
|
||||||
|
|
||||||
#endif
|
|
||||||
|
|
||||||
static inline uint64_t do_fri(CPUPPCState *env, uint64_t arg,
|
static inline uint64_t do_fri(CPUPPCState *env, uint64_t arg,
|
||||||
int rounding_mode)
|
int rounding_mode)
|
||||||
{
|
{
|
||||||
|
|
|
@ -66,7 +66,6 @@ DEF_HELPER_2(fctiw, i64, env, i64)
|
||||||
DEF_HELPER_2(fctiwu, i64, env, i64)
|
DEF_HELPER_2(fctiwu, i64, env, i64)
|
||||||
DEF_HELPER_2(fctiwz, i64, env, i64)
|
DEF_HELPER_2(fctiwz, i64, env, i64)
|
||||||
DEF_HELPER_2(fctiwuz, i64, env, i64)
|
DEF_HELPER_2(fctiwuz, i64, env, i64)
|
||||||
#if defined(TARGET_PPC64)
|
|
||||||
DEF_HELPER_2(fcfid, i64, env, i64)
|
DEF_HELPER_2(fcfid, i64, env, i64)
|
||||||
DEF_HELPER_2(fcfidu, i64, env, i64)
|
DEF_HELPER_2(fcfidu, i64, env, i64)
|
||||||
DEF_HELPER_2(fcfids, i64, env, i64)
|
DEF_HELPER_2(fcfids, i64, env, i64)
|
||||||
|
@ -75,7 +74,6 @@ DEF_HELPER_2(fctid, i64, env, i64)
|
||||||
DEF_HELPER_2(fctidu, i64, env, i64)
|
DEF_HELPER_2(fctidu, i64, env, i64)
|
||||||
DEF_HELPER_2(fctidz, i64, env, i64)
|
DEF_HELPER_2(fctidz, i64, env, i64)
|
||||||
DEF_HELPER_2(fctiduz, i64, env, i64)
|
DEF_HELPER_2(fctiduz, i64, env, i64)
|
||||||
#endif
|
|
||||||
DEF_HELPER_2(frsp, i64, env, i64)
|
DEF_HELPER_2(frsp, i64, env, i64)
|
||||||
DEF_HELPER_2(frin, i64, env, i64)
|
DEF_HELPER_2(frin, i64, env, i64)
|
||||||
DEF_HELPER_2(friz, i64, env, i64)
|
DEF_HELPER_2(friz, i64, env, i64)
|
||||||
|
|
|
@ -708,7 +708,7 @@ static inline void vcmpbfp_internal(CPUPPCState *env, ppc_avr_t *r,
|
||||||
int le_rel = float32_compare_quiet(a->f[i], b->f[i], &env->vec_status);
|
int le_rel = float32_compare_quiet(a->f[i], b->f[i], &env->vec_status);
|
||||||
if (le_rel == float_relation_unordered) {
|
if (le_rel == float_relation_unordered) {
|
||||||
r->u32[i] = 0xc0000000;
|
r->u32[i] = 0xc0000000;
|
||||||
/* ALL_IN does not need to be updated here. */
|
all_in = 1;
|
||||||
} else {
|
} else {
|
||||||
float32 bneg = float32_chs(b->f[i]);
|
float32 bneg = float32_chs(b->f[i]);
|
||||||
int ge_rel = float32_compare_quiet(a->f[i], bneg, &env->vec_status);
|
int ge_rel = float32_compare_quiet(a->f[i], bneg, &env->vec_status);
|
||||||
|
@ -1552,13 +1552,6 @@ void helper_vlogefp(CPUPPCState *env, ppc_avr_t *r, ppc_avr_t *b)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#if defined(HOST_WORDS_BIGENDIAN)
|
|
||||||
#define LEFT 0
|
|
||||||
#define RIGHT 1
|
|
||||||
#else
|
|
||||||
#define LEFT 1
|
|
||||||
#define RIGHT 0
|
|
||||||
#endif
|
|
||||||
/* The specification says that the results are undefined if all of the
|
/* The specification says that the results are undefined if all of the
|
||||||
* shift counts are not identical. We check to make sure that they are
|
* shift counts are not identical. We check to make sure that they are
|
||||||
* to conform to what real hardware appears to do. */
|
* to conform to what real hardware appears to do. */
|
||||||
|
@ -1588,11 +1581,9 @@ void helper_vlogefp(CPUPPCState *env, ppc_avr_t *r, ppc_avr_t *b)
|
||||||
} \
|
} \
|
||||||
} \
|
} \
|
||||||
}
|
}
|
||||||
VSHIFT(l, LEFT)
|
VSHIFT(l, 1)
|
||||||
VSHIFT(r, RIGHT)
|
VSHIFT(r, 0)
|
||||||
#undef VSHIFT
|
#undef VSHIFT
|
||||||
#undef LEFT
|
|
||||||
#undef RIGHT
|
|
||||||
|
|
||||||
#define VSL(suffix, element, mask) \
|
#define VSL(suffix, element, mask) \
|
||||||
void helper_vsl##suffix(ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b) \
|
void helper_vsl##suffix(ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b) \
|
||||||
|
@ -2286,25 +2277,25 @@ uint32_t helper_bcdadd(ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b, uint32_t ps)
|
||||||
if (sgna == sgnb) {
|
if (sgna == sgnb) {
|
||||||
result.u8[BCD_DIG_BYTE(0)] = bcd_preferred_sgn(sgna, ps);
|
result.u8[BCD_DIG_BYTE(0)] = bcd_preferred_sgn(sgna, ps);
|
||||||
zero = bcd_add_mag(&result, a, b, &invalid, &overflow);
|
zero = bcd_add_mag(&result, a, b, &invalid, &overflow);
|
||||||
cr = (sgna > 0) ? 4 : 8;
|
cr = (sgna > 0) ? 1 << CRF_GT : 1 << CRF_LT;
|
||||||
} else if (bcd_cmp_mag(a, b) > 0) {
|
} else if (bcd_cmp_mag(a, b) > 0) {
|
||||||
result.u8[BCD_DIG_BYTE(0)] = bcd_preferred_sgn(sgna, ps);
|
result.u8[BCD_DIG_BYTE(0)] = bcd_preferred_sgn(sgna, ps);
|
||||||
zero = bcd_sub_mag(&result, a, b, &invalid, &overflow);
|
zero = bcd_sub_mag(&result, a, b, &invalid, &overflow);
|
||||||
cr = (sgna > 0) ? 4 : 8;
|
cr = (sgna > 0) ? 1 << CRF_GT : 1 << CRF_LT;
|
||||||
} else {
|
} else {
|
||||||
result.u8[BCD_DIG_BYTE(0)] = bcd_preferred_sgn(sgnb, ps);
|
result.u8[BCD_DIG_BYTE(0)] = bcd_preferred_sgn(sgnb, ps);
|
||||||
zero = bcd_sub_mag(&result, b, a, &invalid, &overflow);
|
zero = bcd_sub_mag(&result, b, a, &invalid, &overflow);
|
||||||
cr = (sgnb > 0) ? 4 : 8;
|
cr = (sgnb > 0) ? 1 << CRF_GT : 1 << CRF_LT;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (unlikely(invalid)) {
|
if (unlikely(invalid)) {
|
||||||
result.u64[HI_IDX] = result.u64[LO_IDX] = -1;
|
result.u64[HI_IDX] = result.u64[LO_IDX] = -1;
|
||||||
cr = 1;
|
cr = 1 << CRF_SO;
|
||||||
} else if (overflow) {
|
} else if (overflow) {
|
||||||
cr |= 1;
|
cr |= 1 << CRF_SO;
|
||||||
} else if (zero) {
|
} else if (zero) {
|
||||||
cr = 2;
|
cr = 1 << CRF_EQ;
|
||||||
}
|
}
|
||||||
|
|
||||||
*r = result;
|
*r = result;
|
||||||
|
@ -2352,7 +2343,7 @@ void helper_vcipherlast(ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b)
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
VECTOR_FOR_INORDER_I(i, u8) {
|
VECTOR_FOR_INORDER_I(i, u8) {
|
||||||
r->AVRB(i) = b->AVRB(i) ^ (AES_Te4[a->AVRB(AES_shifts[i])] & 0xFF);
|
r->AVRB(i) = b->AVRB(i) ^ (AES_sbox[a->AVRB(AES_shifts[i])]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2381,7 +2372,7 @@ void helper_vncipherlast(ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b)
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
VECTOR_FOR_INORDER_I(i, u8) {
|
VECTOR_FOR_INORDER_I(i, u8) {
|
||||||
r->AVRB(i) = b->AVRB(i) ^ (AES_Td4[a->AVRB(AES_ishifts[i])] & 0xFF);
|
r->AVRB(i) = b->AVRB(i) ^ (AES_isbox[a->AVRB(AES_ishifts[i])]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2556,6 +2547,7 @@ target_ulong helper_dlmzb(CPUPPCState *env, target_ulong high,
|
||||||
}
|
}
|
||||||
i++;
|
i++;
|
||||||
}
|
}
|
||||||
|
i = 8;
|
||||||
if (update_Rc) {
|
if (update_Rc) {
|
||||||
env->crf[0] = 0x2;
|
env->crf[0] = 0x2;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1782,7 +1782,7 @@ static int kvmppc_find_cpu_dt(char *buf, int buf_len)
|
||||||
* format) */
|
* format) */
|
||||||
static uint64_t kvmppc_read_int_cpu_dt(const char *propname)
|
static uint64_t kvmppc_read_int_cpu_dt(const char *propname)
|
||||||
{
|
{
|
||||||
char buf[PATH_MAX];
|
char buf[PATH_MAX], *tmp;
|
||||||
union {
|
union {
|
||||||
uint32_t v32;
|
uint32_t v32;
|
||||||
uint64_t v64;
|
uint64_t v64;
|
||||||
|
@ -1794,10 +1794,10 @@ static uint64_t kvmppc_read_int_cpu_dt(const char *propname)
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
strncat(buf, "/", sizeof(buf) - strlen(buf));
|
tmp = g_strdup_printf("%s/%s", buf, propname);
|
||||||
strncat(buf, propname, sizeof(buf) - strlen(buf));
|
|
||||||
|
|
||||||
f = fopen(buf, "rb");
|
f = fopen(tmp, "rb");
|
||||||
|
g_free(tmp);
|
||||||
if (!f) {
|
if (!f) {
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
|
@ -189,6 +189,7 @@ typedef struct DisasContext {
|
||||||
uint32_t opcode;
|
uint32_t opcode;
|
||||||
uint32_t exception;
|
uint32_t exception;
|
||||||
/* Routine used to access memory */
|
/* Routine used to access memory */
|
||||||
|
bool pr, hv;
|
||||||
int mem_idx;
|
int mem_idx;
|
||||||
int access_type;
|
int access_type;
|
||||||
/* Translation flags */
|
/* Translation flags */
|
||||||
|
@ -643,20 +644,6 @@ static opc_handler_t invalid_handler = {
|
||||||
.handler = gen_invalid,
|
.handler = gen_invalid,
|
||||||
};
|
};
|
||||||
|
|
||||||
#if defined(TARGET_PPC64)
|
|
||||||
/* NOTE: as this time, the only use of is_user_mode() is in 64 bit code. And */
|
|
||||||
/* so the function is wrapped in the standard 64-bit ifdef in order to */
|
|
||||||
/* avoid compiler warnings in 32-bit implementations. */
|
|
||||||
static bool is_user_mode(DisasContext *ctx)
|
|
||||||
{
|
|
||||||
#if defined(CONFIG_USER_ONLY)
|
|
||||||
return true;
|
|
||||||
#else
|
|
||||||
return ctx->mem_idx == 0;
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/*** Integer comparison ***/
|
/*** Integer comparison ***/
|
||||||
|
|
||||||
static inline void gen_op_cmp(TCGv arg0, TCGv arg1, int s, int crf)
|
static inline void gen_op_cmp(TCGv arg0, TCGv arg1, int s, int crf)
|
||||||
|
@ -784,7 +771,7 @@ static void gen_isel(DisasContext *ctx)
|
||||||
l1 = gen_new_label();
|
l1 = gen_new_label();
|
||||||
l2 = gen_new_label();
|
l2 = gen_new_label();
|
||||||
|
|
||||||
mask = 1 << (3 - (bi & 0x03));
|
mask = 0x08 >> (bi & 0x03);
|
||||||
t0 = tcg_temp_new_i32();
|
t0 = tcg_temp_new_i32();
|
||||||
tcg_gen_andi_i32(t0, cpu_crf[bi >> 2], mask);
|
tcg_gen_andi_i32(t0, cpu_crf[bi >> 2], mask);
|
||||||
tcg_gen_brcondi_i32(TCG_COND_EQ, t0, 0, l1);
|
tcg_gen_brcondi_i32(TCG_COND_EQ, t0, 0, l1);
|
||||||
|
@ -1456,25 +1443,25 @@ static void gen_or(DisasContext *ctx)
|
||||||
break;
|
break;
|
||||||
#if !defined(CONFIG_USER_ONLY)
|
#if !defined(CONFIG_USER_ONLY)
|
||||||
case 31:
|
case 31:
|
||||||
if (ctx->mem_idx > 0) {
|
if (!ctx->pr) {
|
||||||
/* Set process priority to very low */
|
/* Set process priority to very low */
|
||||||
prio = 1;
|
prio = 1;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case 5:
|
case 5:
|
||||||
if (ctx->mem_idx > 0) {
|
if (!ctx->pr) {
|
||||||
/* Set process priority to medium-hight */
|
/* Set process priority to medium-hight */
|
||||||
prio = 5;
|
prio = 5;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case 3:
|
case 3:
|
||||||
if (ctx->mem_idx > 0) {
|
if (!ctx->pr) {
|
||||||
/* Set process priority to high */
|
/* Set process priority to high */
|
||||||
prio = 6;
|
prio = 6;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case 7:
|
case 7:
|
||||||
if (ctx->mem_idx > 1) {
|
if (ctx->hv) {
|
||||||
/* Set process priority to very high */
|
/* Set process priority to very high */
|
||||||
prio = 7;
|
prio = 7;
|
||||||
}
|
}
|
||||||
|
@ -2287,9 +2274,8 @@ GEN_FLOAT_B(ctiwz, 0x0F, 0x00, 0, PPC_FLOAT);
|
||||||
GEN_FLOAT_B(ctiwuz, 0x0F, 0x04, 0, PPC2_FP_CVT_ISA206);
|
GEN_FLOAT_B(ctiwuz, 0x0F, 0x04, 0, PPC2_FP_CVT_ISA206);
|
||||||
/* frsp */
|
/* frsp */
|
||||||
GEN_FLOAT_B(rsp, 0x0C, 0x00, 1, PPC_FLOAT);
|
GEN_FLOAT_B(rsp, 0x0C, 0x00, 1, PPC_FLOAT);
|
||||||
#if defined(TARGET_PPC64)
|
|
||||||
/* fcfid */
|
/* fcfid */
|
||||||
GEN_FLOAT_B(cfid, 0x0E, 0x1A, 1, PPC_64B);
|
GEN_FLOAT_B(cfid, 0x0E, 0x1A, 1, PPC2_FP_CVT_S64);
|
||||||
/* fcfids */
|
/* fcfids */
|
||||||
GEN_FLOAT_B(cfids, 0x0E, 0x1A, 0, PPC2_FP_CVT_ISA206);
|
GEN_FLOAT_B(cfids, 0x0E, 0x1A, 0, PPC2_FP_CVT_ISA206);
|
||||||
/* fcfidu */
|
/* fcfidu */
|
||||||
|
@ -2297,14 +2283,13 @@ GEN_FLOAT_B(cfidu, 0x0E, 0x1E, 0, PPC2_FP_CVT_ISA206);
|
||||||
/* fcfidus */
|
/* fcfidus */
|
||||||
GEN_FLOAT_B(cfidus, 0x0E, 0x1E, 0, PPC2_FP_CVT_ISA206);
|
GEN_FLOAT_B(cfidus, 0x0E, 0x1E, 0, PPC2_FP_CVT_ISA206);
|
||||||
/* fctid */
|
/* fctid */
|
||||||
GEN_FLOAT_B(ctid, 0x0E, 0x19, 0, PPC_64B);
|
GEN_FLOAT_B(ctid, 0x0E, 0x19, 0, PPC2_FP_CVT_S64);
|
||||||
/* fctidu */
|
/* fctidu */
|
||||||
GEN_FLOAT_B(ctidu, 0x0E, 0x1D, 0, PPC2_FP_CVT_ISA206);
|
GEN_FLOAT_B(ctidu, 0x0E, 0x1D, 0, PPC2_FP_CVT_ISA206);
|
||||||
/* fctidz */
|
/* fctidz */
|
||||||
GEN_FLOAT_B(ctidz, 0x0F, 0x19, 0, PPC_64B);
|
GEN_FLOAT_B(ctidz, 0x0F, 0x19, 0, PPC2_FP_CVT_S64);
|
||||||
/* fctidu */
|
/* fctidu */
|
||||||
GEN_FLOAT_B(ctiduz, 0x0F, 0x1D, 0, PPC2_FP_CVT_ISA206);
|
GEN_FLOAT_B(ctiduz, 0x0F, 0x1D, 0, PPC2_FP_CVT_ISA206);
|
||||||
#endif
|
|
||||||
|
|
||||||
/* frin */
|
/* frin */
|
||||||
GEN_FLOAT_B(rin, 0x08, 0x0C, 1, PPC_FLOAT_EXT);
|
GEN_FLOAT_B(rin, 0x08, 0x0C, 1, PPC_FLOAT_EXT);
|
||||||
|
@ -2903,7 +2888,7 @@ static void gen_lq(DisasContext *ctx)
|
||||||
bool legal_in_user_mode = (ctx->insns_flags2 & PPC2_LSQ_ISA207) != 0;
|
bool legal_in_user_mode = (ctx->insns_flags2 & PPC2_LSQ_ISA207) != 0;
|
||||||
bool le_is_supported = (ctx->insns_flags2 & PPC2_LSQ_ISA207) != 0;
|
bool le_is_supported = (ctx->insns_flags2 & PPC2_LSQ_ISA207) != 0;
|
||||||
|
|
||||||
if (!legal_in_user_mode && is_user_mode(ctx)) {
|
if (!legal_in_user_mode && ctx->pr) {
|
||||||
gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC);
|
gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -3026,7 +3011,7 @@ static void gen_std(DisasContext *ctx)
|
||||||
bool legal_in_user_mode = (ctx->insns_flags2 & PPC2_LSQ_ISA207) != 0;
|
bool legal_in_user_mode = (ctx->insns_flags2 & PPC2_LSQ_ISA207) != 0;
|
||||||
bool le_is_supported = (ctx->insns_flags2 & PPC2_LSQ_ISA207) != 0;
|
bool le_is_supported = (ctx->insns_flags2 & PPC2_LSQ_ISA207) != 0;
|
||||||
|
|
||||||
if (!legal_in_user_mode && is_user_mode(ctx)) {
|
if (!legal_in_user_mode && ctx->pr) {
|
||||||
gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC);
|
gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -3889,7 +3874,7 @@ static inline void gen_bcond(DisasContext *ctx, int type)
|
||||||
if ((bo & 0x10) == 0) {
|
if ((bo & 0x10) == 0) {
|
||||||
/* Test CR */
|
/* Test CR */
|
||||||
uint32_t bi = BI(ctx->opcode);
|
uint32_t bi = BI(ctx->opcode);
|
||||||
uint32_t mask = 1 << (3 - (bi & 0x03));
|
uint32_t mask = 0x08 >> (bi & 0x03);
|
||||||
TCGv_i32 temp = tcg_temp_new_i32();
|
TCGv_i32 temp = tcg_temp_new_i32();
|
||||||
|
|
||||||
if (bo & 0x8) {
|
if (bo & 0x8) {
|
||||||
|
@ -3971,7 +3956,7 @@ static void glue(gen_, name)(DisasContext *ctx)
|
||||||
else \
|
else \
|
||||||
tcg_gen_mov_i32(t1, cpu_crf[crbB(ctx->opcode) >> 2]); \
|
tcg_gen_mov_i32(t1, cpu_crf[crbB(ctx->opcode) >> 2]); \
|
||||||
tcg_op(t0, t0, t1); \
|
tcg_op(t0, t0, t1); \
|
||||||
bitmask = 1 << (3 - (crbD(ctx->opcode) & 0x03)); \
|
bitmask = 0x08 >> (crbD(ctx->opcode) & 0x03); \
|
||||||
tcg_gen_andi_i32(t0, t0, bitmask); \
|
tcg_gen_andi_i32(t0, t0, bitmask); \
|
||||||
tcg_gen_andi_i32(t1, cpu_crf[crbD(ctx->opcode) >> 2], ~bitmask); \
|
tcg_gen_andi_i32(t1, cpu_crf[crbD(ctx->opcode) >> 2], ~bitmask); \
|
||||||
tcg_gen_or_i32(cpu_crf[crbD(ctx->opcode) >> 2], t0, t1); \
|
tcg_gen_or_i32(cpu_crf[crbD(ctx->opcode) >> 2], t0, t1); \
|
||||||
|
@ -4004,14 +3989,14 @@ static void gen_mcrf(DisasContext *ctx)
|
||||||
|
|
||||||
/*** System linkage ***/
|
/*** System linkage ***/
|
||||||
|
|
||||||
/* rfi (mem_idx only) */
|
/* rfi (supervisor only) */
|
||||||
static void gen_rfi(DisasContext *ctx)
|
static void gen_rfi(DisasContext *ctx)
|
||||||
{
|
{
|
||||||
#if defined(CONFIG_USER_ONLY)
|
#if defined(CONFIG_USER_ONLY)
|
||||||
gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC);
|
gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC);
|
||||||
#else
|
#else
|
||||||
/* Restore CPU state */
|
/* Restore CPU state */
|
||||||
if (unlikely(!ctx->mem_idx)) {
|
if (unlikely(ctx->pr)) {
|
||||||
gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC);
|
gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -4028,7 +4013,7 @@ static void gen_rfid(DisasContext *ctx)
|
||||||
gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC);
|
gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC);
|
||||||
#else
|
#else
|
||||||
/* Restore CPU state */
|
/* Restore CPU state */
|
||||||
if (unlikely(!ctx->mem_idx)) {
|
if (unlikely(ctx->pr)) {
|
||||||
gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC);
|
gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -4044,7 +4029,7 @@ static void gen_hrfid(DisasContext *ctx)
|
||||||
gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC);
|
gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC);
|
||||||
#else
|
#else
|
||||||
/* Restore CPU state */
|
/* Restore CPU state */
|
||||||
if (unlikely(ctx->mem_idx <= 1)) {
|
if (unlikely(!ctx->hv)) {
|
||||||
gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC);
|
gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -4213,7 +4198,7 @@ static void gen_mfmsr(DisasContext *ctx)
|
||||||
#if defined(CONFIG_USER_ONLY)
|
#if defined(CONFIG_USER_ONLY)
|
||||||
gen_inval_exception(ctx, POWERPC_EXCP_PRIV_REG);
|
gen_inval_exception(ctx, POWERPC_EXCP_PRIV_REG);
|
||||||
#else
|
#else
|
||||||
if (unlikely(!ctx->mem_idx)) {
|
if (unlikely(ctx->pr)) {
|
||||||
gen_inval_exception(ctx, POWERPC_EXCP_PRIV_REG);
|
gen_inval_exception(ctx, POWERPC_EXCP_PRIV_REG);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -4237,9 +4222,9 @@ static inline void gen_op_mfspr(DisasContext *ctx)
|
||||||
uint32_t sprn = SPR(ctx->opcode);
|
uint32_t sprn = SPR(ctx->opcode);
|
||||||
|
|
||||||
#if !defined(CONFIG_USER_ONLY)
|
#if !defined(CONFIG_USER_ONLY)
|
||||||
if (ctx->mem_idx == 2)
|
if (ctx->hv)
|
||||||
read_cb = ctx->spr_cb[sprn].hea_read;
|
read_cb = ctx->spr_cb[sprn].hea_read;
|
||||||
else if (ctx->mem_idx)
|
else if (!ctx->pr)
|
||||||
read_cb = ctx->spr_cb[sprn].oea_read;
|
read_cb = ctx->spr_cb[sprn].oea_read;
|
||||||
else
|
else
|
||||||
#endif
|
#endif
|
||||||
|
@ -4317,7 +4302,7 @@ static void gen_mtmsrd(DisasContext *ctx)
|
||||||
#if defined(CONFIG_USER_ONLY)
|
#if defined(CONFIG_USER_ONLY)
|
||||||
gen_inval_exception(ctx, POWERPC_EXCP_PRIV_REG);
|
gen_inval_exception(ctx, POWERPC_EXCP_PRIV_REG);
|
||||||
#else
|
#else
|
||||||
if (unlikely(!ctx->mem_idx)) {
|
if (unlikely(ctx->pr)) {
|
||||||
gen_inval_exception(ctx, POWERPC_EXCP_PRIV_REG);
|
gen_inval_exception(ctx, POWERPC_EXCP_PRIV_REG);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -4348,7 +4333,7 @@ static void gen_mtmsr(DisasContext *ctx)
|
||||||
#if defined(CONFIG_USER_ONLY)
|
#if defined(CONFIG_USER_ONLY)
|
||||||
gen_inval_exception(ctx, POWERPC_EXCP_PRIV_REG);
|
gen_inval_exception(ctx, POWERPC_EXCP_PRIV_REG);
|
||||||
#else
|
#else
|
||||||
if (unlikely(!ctx->mem_idx)) {
|
if (unlikely(ctx->pr)) {
|
||||||
gen_inval_exception(ctx, POWERPC_EXCP_PRIV_REG);
|
gen_inval_exception(ctx, POWERPC_EXCP_PRIV_REG);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -4388,9 +4373,9 @@ static void gen_mtspr(DisasContext *ctx)
|
||||||
uint32_t sprn = SPR(ctx->opcode);
|
uint32_t sprn = SPR(ctx->opcode);
|
||||||
|
|
||||||
#if !defined(CONFIG_USER_ONLY)
|
#if !defined(CONFIG_USER_ONLY)
|
||||||
if (ctx->mem_idx == 2)
|
if (ctx->hv)
|
||||||
write_cb = ctx->spr_cb[sprn].hea_write;
|
write_cb = ctx->spr_cb[sprn].hea_write;
|
||||||
else if (ctx->mem_idx)
|
else if (!ctx->pr)
|
||||||
write_cb = ctx->spr_cb[sprn].oea_write;
|
write_cb = ctx->spr_cb[sprn].oea_write;
|
||||||
else
|
else
|
||||||
#endif
|
#endif
|
||||||
|
@ -4437,7 +4422,7 @@ static void gen_dcbi(DisasContext *ctx)
|
||||||
gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC);
|
gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC);
|
||||||
#else
|
#else
|
||||||
TCGv EA, val;
|
TCGv EA, val;
|
||||||
if (unlikely(!ctx->mem_idx)) {
|
if (unlikely(ctx->pr)) {
|
||||||
gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC);
|
gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -4574,7 +4559,7 @@ static void gen_mfsr(DisasContext *ctx)
|
||||||
gen_inval_exception(ctx, POWERPC_EXCP_PRIV_REG);
|
gen_inval_exception(ctx, POWERPC_EXCP_PRIV_REG);
|
||||||
#else
|
#else
|
||||||
TCGv t0;
|
TCGv t0;
|
||||||
if (unlikely(!ctx->mem_idx)) {
|
if (unlikely(ctx->pr)) {
|
||||||
gen_inval_exception(ctx, POWERPC_EXCP_PRIV_REG);
|
gen_inval_exception(ctx, POWERPC_EXCP_PRIV_REG);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -4591,7 +4576,7 @@ static void gen_mfsrin(DisasContext *ctx)
|
||||||
gen_inval_exception(ctx, POWERPC_EXCP_PRIV_REG);
|
gen_inval_exception(ctx, POWERPC_EXCP_PRIV_REG);
|
||||||
#else
|
#else
|
||||||
TCGv t0;
|
TCGv t0;
|
||||||
if (unlikely(!ctx->mem_idx)) {
|
if (unlikely(ctx->pr)) {
|
||||||
gen_inval_exception(ctx, POWERPC_EXCP_PRIV_REG);
|
gen_inval_exception(ctx, POWERPC_EXCP_PRIV_REG);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -4610,7 +4595,7 @@ static void gen_mtsr(DisasContext *ctx)
|
||||||
gen_inval_exception(ctx, POWERPC_EXCP_PRIV_REG);
|
gen_inval_exception(ctx, POWERPC_EXCP_PRIV_REG);
|
||||||
#else
|
#else
|
||||||
TCGv t0;
|
TCGv t0;
|
||||||
if (unlikely(!ctx->mem_idx)) {
|
if (unlikely(ctx->pr)) {
|
||||||
gen_inval_exception(ctx, POWERPC_EXCP_PRIV_REG);
|
gen_inval_exception(ctx, POWERPC_EXCP_PRIV_REG);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -4627,7 +4612,7 @@ static void gen_mtsrin(DisasContext *ctx)
|
||||||
gen_inval_exception(ctx, POWERPC_EXCP_PRIV_REG);
|
gen_inval_exception(ctx, POWERPC_EXCP_PRIV_REG);
|
||||||
#else
|
#else
|
||||||
TCGv t0;
|
TCGv t0;
|
||||||
if (unlikely(!ctx->mem_idx)) {
|
if (unlikely(ctx->pr)) {
|
||||||
gen_inval_exception(ctx, POWERPC_EXCP_PRIV_REG);
|
gen_inval_exception(ctx, POWERPC_EXCP_PRIV_REG);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -4649,7 +4634,7 @@ static void gen_mfsr_64b(DisasContext *ctx)
|
||||||
gen_inval_exception(ctx, POWERPC_EXCP_PRIV_REG);
|
gen_inval_exception(ctx, POWERPC_EXCP_PRIV_REG);
|
||||||
#else
|
#else
|
||||||
TCGv t0;
|
TCGv t0;
|
||||||
if (unlikely(!ctx->mem_idx)) {
|
if (unlikely(ctx->pr)) {
|
||||||
gen_inval_exception(ctx, POWERPC_EXCP_PRIV_REG);
|
gen_inval_exception(ctx, POWERPC_EXCP_PRIV_REG);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -4666,7 +4651,7 @@ static void gen_mfsrin_64b(DisasContext *ctx)
|
||||||
gen_inval_exception(ctx, POWERPC_EXCP_PRIV_REG);
|
gen_inval_exception(ctx, POWERPC_EXCP_PRIV_REG);
|
||||||
#else
|
#else
|
||||||
TCGv t0;
|
TCGv t0;
|
||||||
if (unlikely(!ctx->mem_idx)) {
|
if (unlikely(ctx->pr)) {
|
||||||
gen_inval_exception(ctx, POWERPC_EXCP_PRIV_REG);
|
gen_inval_exception(ctx, POWERPC_EXCP_PRIV_REG);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -4685,7 +4670,7 @@ static void gen_mtsr_64b(DisasContext *ctx)
|
||||||
gen_inval_exception(ctx, POWERPC_EXCP_PRIV_REG);
|
gen_inval_exception(ctx, POWERPC_EXCP_PRIV_REG);
|
||||||
#else
|
#else
|
||||||
TCGv t0;
|
TCGv t0;
|
||||||
if (unlikely(!ctx->mem_idx)) {
|
if (unlikely(ctx->pr)) {
|
||||||
gen_inval_exception(ctx, POWERPC_EXCP_PRIV_REG);
|
gen_inval_exception(ctx, POWERPC_EXCP_PRIV_REG);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -4702,7 +4687,7 @@ static void gen_mtsrin_64b(DisasContext *ctx)
|
||||||
gen_inval_exception(ctx, POWERPC_EXCP_PRIV_REG);
|
gen_inval_exception(ctx, POWERPC_EXCP_PRIV_REG);
|
||||||
#else
|
#else
|
||||||
TCGv t0;
|
TCGv t0;
|
||||||
if (unlikely(!ctx->mem_idx)) {
|
if (unlikely(ctx->pr)) {
|
||||||
gen_inval_exception(ctx, POWERPC_EXCP_PRIV_REG);
|
gen_inval_exception(ctx, POWERPC_EXCP_PRIV_REG);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -4720,7 +4705,7 @@ static void gen_slbmte(DisasContext *ctx)
|
||||||
#if defined(CONFIG_USER_ONLY)
|
#if defined(CONFIG_USER_ONLY)
|
||||||
gen_inval_exception(ctx, POWERPC_EXCP_PRIV_REG);
|
gen_inval_exception(ctx, POWERPC_EXCP_PRIV_REG);
|
||||||
#else
|
#else
|
||||||
if (unlikely(!ctx->mem_idx)) {
|
if (unlikely(ctx->pr)) {
|
||||||
gen_inval_exception(ctx, POWERPC_EXCP_PRIV_REG);
|
gen_inval_exception(ctx, POWERPC_EXCP_PRIV_REG);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -4734,7 +4719,7 @@ static void gen_slbmfee(DisasContext *ctx)
|
||||||
#if defined(CONFIG_USER_ONLY)
|
#if defined(CONFIG_USER_ONLY)
|
||||||
gen_inval_exception(ctx, POWERPC_EXCP_PRIV_REG);
|
gen_inval_exception(ctx, POWERPC_EXCP_PRIV_REG);
|
||||||
#else
|
#else
|
||||||
if (unlikely(!ctx->mem_idx)) {
|
if (unlikely(ctx->pr)) {
|
||||||
gen_inval_exception(ctx, POWERPC_EXCP_PRIV_REG);
|
gen_inval_exception(ctx, POWERPC_EXCP_PRIV_REG);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -4748,7 +4733,7 @@ static void gen_slbmfev(DisasContext *ctx)
|
||||||
#if defined(CONFIG_USER_ONLY)
|
#if defined(CONFIG_USER_ONLY)
|
||||||
gen_inval_exception(ctx, POWERPC_EXCP_PRIV_REG);
|
gen_inval_exception(ctx, POWERPC_EXCP_PRIV_REG);
|
||||||
#else
|
#else
|
||||||
if (unlikely(!ctx->mem_idx)) {
|
if (unlikely(ctx->pr)) {
|
||||||
gen_inval_exception(ctx, POWERPC_EXCP_PRIV_REG);
|
gen_inval_exception(ctx, POWERPC_EXCP_PRIV_REG);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -4759,7 +4744,7 @@ static void gen_slbmfev(DisasContext *ctx)
|
||||||
#endif /* defined(TARGET_PPC64) */
|
#endif /* defined(TARGET_PPC64) */
|
||||||
|
|
||||||
/*** Lookaside buffer management ***/
|
/*** Lookaside buffer management ***/
|
||||||
/* Optional & mem_idx only: */
|
/* Optional & supervisor only: */
|
||||||
|
|
||||||
/* tlbia */
|
/* tlbia */
|
||||||
static void gen_tlbia(DisasContext *ctx)
|
static void gen_tlbia(DisasContext *ctx)
|
||||||
|
@ -4767,7 +4752,7 @@ static void gen_tlbia(DisasContext *ctx)
|
||||||
#if defined(CONFIG_USER_ONLY)
|
#if defined(CONFIG_USER_ONLY)
|
||||||
gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC);
|
gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC);
|
||||||
#else
|
#else
|
||||||
if (unlikely(!ctx->mem_idx)) {
|
if (unlikely(ctx->pr)) {
|
||||||
gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC);
|
gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -4781,7 +4766,7 @@ static void gen_tlbiel(DisasContext *ctx)
|
||||||
#if defined(CONFIG_USER_ONLY)
|
#if defined(CONFIG_USER_ONLY)
|
||||||
gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC);
|
gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC);
|
||||||
#else
|
#else
|
||||||
if (unlikely(!ctx->mem_idx)) {
|
if (unlikely(ctx->pr)) {
|
||||||
gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC);
|
gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -4795,7 +4780,7 @@ static void gen_tlbie(DisasContext *ctx)
|
||||||
#if defined(CONFIG_USER_ONLY)
|
#if defined(CONFIG_USER_ONLY)
|
||||||
gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC);
|
gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC);
|
||||||
#else
|
#else
|
||||||
if (unlikely(!ctx->mem_idx)) {
|
if (unlikely(ctx->pr)) {
|
||||||
gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC);
|
gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -4816,7 +4801,7 @@ static void gen_tlbsync(DisasContext *ctx)
|
||||||
#if defined(CONFIG_USER_ONLY)
|
#if defined(CONFIG_USER_ONLY)
|
||||||
gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC);
|
gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC);
|
||||||
#else
|
#else
|
||||||
if (unlikely(!ctx->mem_idx)) {
|
if (unlikely(ctx->pr)) {
|
||||||
gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC);
|
gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -4834,7 +4819,7 @@ static void gen_slbia(DisasContext *ctx)
|
||||||
#if defined(CONFIG_USER_ONLY)
|
#if defined(CONFIG_USER_ONLY)
|
||||||
gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC);
|
gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC);
|
||||||
#else
|
#else
|
||||||
if (unlikely(!ctx->mem_idx)) {
|
if (unlikely(ctx->pr)) {
|
||||||
gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC);
|
gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -4848,7 +4833,7 @@ static void gen_slbie(DisasContext *ctx)
|
||||||
#if defined(CONFIG_USER_ONLY)
|
#if defined(CONFIG_USER_ONLY)
|
||||||
gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC);
|
gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC);
|
||||||
#else
|
#else
|
||||||
if (unlikely(!ctx->mem_idx)) {
|
if (unlikely(ctx->pr)) {
|
||||||
gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC);
|
gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -5556,7 +5541,7 @@ static void gen_mfrom(DisasContext *ctx)
|
||||||
#if defined(CONFIG_USER_ONLY)
|
#if defined(CONFIG_USER_ONLY)
|
||||||
gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC);
|
gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC);
|
||||||
#else
|
#else
|
||||||
if (unlikely(!ctx->mem_idx)) {
|
if (unlikely(ctx->pr)) {
|
||||||
gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC);
|
gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -5572,7 +5557,7 @@ static void gen_tlbld_6xx(DisasContext *ctx)
|
||||||
#if defined(CONFIG_USER_ONLY)
|
#if defined(CONFIG_USER_ONLY)
|
||||||
gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC);
|
gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC);
|
||||||
#else
|
#else
|
||||||
if (unlikely(!ctx->mem_idx)) {
|
if (unlikely(ctx->pr)) {
|
||||||
gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC);
|
gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -5586,7 +5571,7 @@ static void gen_tlbli_6xx(DisasContext *ctx)
|
||||||
#if defined(CONFIG_USER_ONLY)
|
#if defined(CONFIG_USER_ONLY)
|
||||||
gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC);
|
gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC);
|
||||||
#else
|
#else
|
||||||
if (unlikely(!ctx->mem_idx)) {
|
if (unlikely(ctx->pr)) {
|
||||||
gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC);
|
gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -5602,7 +5587,7 @@ static void gen_tlbld_74xx(DisasContext *ctx)
|
||||||
#if defined(CONFIG_USER_ONLY)
|
#if defined(CONFIG_USER_ONLY)
|
||||||
gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC);
|
gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC);
|
||||||
#else
|
#else
|
||||||
if (unlikely(!ctx->mem_idx)) {
|
if (unlikely(ctx->pr)) {
|
||||||
gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC);
|
gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -5616,7 +5601,7 @@ static void gen_tlbli_74xx(DisasContext *ctx)
|
||||||
#if defined(CONFIG_USER_ONLY)
|
#if defined(CONFIG_USER_ONLY)
|
||||||
gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC);
|
gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC);
|
||||||
#else
|
#else
|
||||||
if (unlikely(!ctx->mem_idx)) {
|
if (unlikely(ctx->pr)) {
|
||||||
gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC);
|
gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -5639,7 +5624,7 @@ static void gen_cli(DisasContext *ctx)
|
||||||
#if defined(CONFIG_USER_ONLY)
|
#if defined(CONFIG_USER_ONLY)
|
||||||
gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC);
|
gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC);
|
||||||
#else
|
#else
|
||||||
if (unlikely(!ctx->mem_idx)) {
|
if (unlikely(ctx->pr)) {
|
||||||
gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC);
|
gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -5660,7 +5645,7 @@ static void gen_mfsri(DisasContext *ctx)
|
||||||
int ra = rA(ctx->opcode);
|
int ra = rA(ctx->opcode);
|
||||||
int rd = rD(ctx->opcode);
|
int rd = rD(ctx->opcode);
|
||||||
TCGv t0;
|
TCGv t0;
|
||||||
if (unlikely(!ctx->mem_idx)) {
|
if (unlikely(ctx->pr)) {
|
||||||
gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC);
|
gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -5681,7 +5666,7 @@ static void gen_rac(DisasContext *ctx)
|
||||||
gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC);
|
gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC);
|
||||||
#else
|
#else
|
||||||
TCGv t0;
|
TCGv t0;
|
||||||
if (unlikely(!ctx->mem_idx)) {
|
if (unlikely(ctx->pr)) {
|
||||||
gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC);
|
gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -5697,7 +5682,7 @@ static void gen_rfsvc(DisasContext *ctx)
|
||||||
#if defined(CONFIG_USER_ONLY)
|
#if defined(CONFIG_USER_ONLY)
|
||||||
gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC);
|
gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC);
|
||||||
#else
|
#else
|
||||||
if (unlikely(!ctx->mem_idx)) {
|
if (unlikely(ctx->pr)) {
|
||||||
gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC);
|
gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -5859,7 +5844,7 @@ static void gen_tlbiva(DisasContext *ctx)
|
||||||
gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC);
|
gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC);
|
||||||
#else
|
#else
|
||||||
TCGv t0;
|
TCGv t0;
|
||||||
if (unlikely(!ctx->mem_idx)) {
|
if (unlikely(ctx->pr)) {
|
||||||
gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC);
|
gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -6092,7 +6077,7 @@ static void gen_mfdcr(DisasContext *ctx)
|
||||||
gen_inval_exception(ctx, POWERPC_EXCP_PRIV_REG);
|
gen_inval_exception(ctx, POWERPC_EXCP_PRIV_REG);
|
||||||
#else
|
#else
|
||||||
TCGv dcrn;
|
TCGv dcrn;
|
||||||
if (unlikely(!ctx->mem_idx)) {
|
if (unlikely(ctx->pr)) {
|
||||||
gen_inval_exception(ctx, POWERPC_EXCP_PRIV_REG);
|
gen_inval_exception(ctx, POWERPC_EXCP_PRIV_REG);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -6111,7 +6096,7 @@ static void gen_mtdcr(DisasContext *ctx)
|
||||||
gen_inval_exception(ctx, POWERPC_EXCP_PRIV_REG);
|
gen_inval_exception(ctx, POWERPC_EXCP_PRIV_REG);
|
||||||
#else
|
#else
|
||||||
TCGv dcrn;
|
TCGv dcrn;
|
||||||
if (unlikely(!ctx->mem_idx)) {
|
if (unlikely(ctx->pr)) {
|
||||||
gen_inval_exception(ctx, POWERPC_EXCP_PRIV_REG);
|
gen_inval_exception(ctx, POWERPC_EXCP_PRIV_REG);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -6130,7 +6115,7 @@ static void gen_mfdcrx(DisasContext *ctx)
|
||||||
#if defined(CONFIG_USER_ONLY)
|
#if defined(CONFIG_USER_ONLY)
|
||||||
gen_inval_exception(ctx, POWERPC_EXCP_PRIV_REG);
|
gen_inval_exception(ctx, POWERPC_EXCP_PRIV_REG);
|
||||||
#else
|
#else
|
||||||
if (unlikely(!ctx->mem_idx)) {
|
if (unlikely(ctx->pr)) {
|
||||||
gen_inval_exception(ctx, POWERPC_EXCP_PRIV_REG);
|
gen_inval_exception(ctx, POWERPC_EXCP_PRIV_REG);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -6149,7 +6134,7 @@ static void gen_mtdcrx(DisasContext *ctx)
|
||||||
#if defined(CONFIG_USER_ONLY)
|
#if defined(CONFIG_USER_ONLY)
|
||||||
gen_inval_exception(ctx, POWERPC_EXCP_PRIV_REG);
|
gen_inval_exception(ctx, POWERPC_EXCP_PRIV_REG);
|
||||||
#else
|
#else
|
||||||
if (unlikely(!ctx->mem_idx)) {
|
if (unlikely(ctx->pr)) {
|
||||||
gen_inval_exception(ctx, POWERPC_EXCP_PRIV_REG);
|
gen_inval_exception(ctx, POWERPC_EXCP_PRIV_REG);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -6187,7 +6172,7 @@ static void gen_dccci(DisasContext *ctx)
|
||||||
#if defined(CONFIG_USER_ONLY)
|
#if defined(CONFIG_USER_ONLY)
|
||||||
gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC);
|
gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC);
|
||||||
#else
|
#else
|
||||||
if (unlikely(!ctx->mem_idx)) {
|
if (unlikely(ctx->pr)) {
|
||||||
gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC);
|
gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -6202,7 +6187,7 @@ static void gen_dcread(DisasContext *ctx)
|
||||||
gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC);
|
gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC);
|
||||||
#else
|
#else
|
||||||
TCGv EA, val;
|
TCGv EA, val;
|
||||||
if (unlikely(!ctx->mem_idx)) {
|
if (unlikely(ctx->pr)) {
|
||||||
gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC);
|
gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -6232,7 +6217,7 @@ static void gen_iccci(DisasContext *ctx)
|
||||||
#if defined(CONFIG_USER_ONLY)
|
#if defined(CONFIG_USER_ONLY)
|
||||||
gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC);
|
gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC);
|
||||||
#else
|
#else
|
||||||
if (unlikely(!ctx->mem_idx)) {
|
if (unlikely(ctx->pr)) {
|
||||||
gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC);
|
gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -6246,7 +6231,7 @@ static void gen_icread(DisasContext *ctx)
|
||||||
#if defined(CONFIG_USER_ONLY)
|
#if defined(CONFIG_USER_ONLY)
|
||||||
gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC);
|
gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC);
|
||||||
#else
|
#else
|
||||||
if (unlikely(!ctx->mem_idx)) {
|
if (unlikely(ctx->pr)) {
|
||||||
gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC);
|
gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -6254,13 +6239,13 @@ static void gen_icread(DisasContext *ctx)
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
/* rfci (mem_idx only) */
|
/* rfci (supervisor only) */
|
||||||
static void gen_rfci_40x(DisasContext *ctx)
|
static void gen_rfci_40x(DisasContext *ctx)
|
||||||
{
|
{
|
||||||
#if defined(CONFIG_USER_ONLY)
|
#if defined(CONFIG_USER_ONLY)
|
||||||
gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC);
|
gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC);
|
||||||
#else
|
#else
|
||||||
if (unlikely(!ctx->mem_idx)) {
|
if (unlikely(ctx->pr)) {
|
||||||
gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC);
|
gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -6275,7 +6260,7 @@ static void gen_rfci(DisasContext *ctx)
|
||||||
#if defined(CONFIG_USER_ONLY)
|
#if defined(CONFIG_USER_ONLY)
|
||||||
gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC);
|
gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC);
|
||||||
#else
|
#else
|
||||||
if (unlikely(!ctx->mem_idx)) {
|
if (unlikely(ctx->pr)) {
|
||||||
gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC);
|
gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -6293,7 +6278,7 @@ static void gen_rfdi(DisasContext *ctx)
|
||||||
#if defined(CONFIG_USER_ONLY)
|
#if defined(CONFIG_USER_ONLY)
|
||||||
gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC);
|
gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC);
|
||||||
#else
|
#else
|
||||||
if (unlikely(!ctx->mem_idx)) {
|
if (unlikely(ctx->pr)) {
|
||||||
gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC);
|
gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -6309,7 +6294,7 @@ static void gen_rfmci(DisasContext *ctx)
|
||||||
#if defined(CONFIG_USER_ONLY)
|
#if defined(CONFIG_USER_ONLY)
|
||||||
gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC);
|
gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC);
|
||||||
#else
|
#else
|
||||||
if (unlikely(!ctx->mem_idx)) {
|
if (unlikely(ctx->pr)) {
|
||||||
gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC);
|
gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -6327,7 +6312,7 @@ static void gen_tlbre_40x(DisasContext *ctx)
|
||||||
#if defined(CONFIG_USER_ONLY)
|
#if defined(CONFIG_USER_ONLY)
|
||||||
gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC);
|
gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC);
|
||||||
#else
|
#else
|
||||||
if (unlikely(!ctx->mem_idx)) {
|
if (unlikely(ctx->pr)) {
|
||||||
gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC);
|
gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -6354,7 +6339,7 @@ static void gen_tlbsx_40x(DisasContext *ctx)
|
||||||
gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC);
|
gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC);
|
||||||
#else
|
#else
|
||||||
TCGv t0;
|
TCGv t0;
|
||||||
if (unlikely(!ctx->mem_idx)) {
|
if (unlikely(ctx->pr)) {
|
||||||
gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC);
|
gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -6378,7 +6363,7 @@ static void gen_tlbwe_40x(DisasContext *ctx)
|
||||||
#if defined(CONFIG_USER_ONLY)
|
#if defined(CONFIG_USER_ONLY)
|
||||||
gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC);
|
gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC);
|
||||||
#else
|
#else
|
||||||
if (unlikely(!ctx->mem_idx)) {
|
if (unlikely(ctx->pr)) {
|
||||||
gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC);
|
gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -6406,7 +6391,7 @@ static void gen_tlbre_440(DisasContext *ctx)
|
||||||
#if defined(CONFIG_USER_ONLY)
|
#if defined(CONFIG_USER_ONLY)
|
||||||
gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC);
|
gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC);
|
||||||
#else
|
#else
|
||||||
if (unlikely(!ctx->mem_idx)) {
|
if (unlikely(ctx->pr)) {
|
||||||
gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC);
|
gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -6435,7 +6420,7 @@ static void gen_tlbsx_440(DisasContext *ctx)
|
||||||
gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC);
|
gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC);
|
||||||
#else
|
#else
|
||||||
TCGv t0;
|
TCGv t0;
|
||||||
if (unlikely(!ctx->mem_idx)) {
|
if (unlikely(ctx->pr)) {
|
||||||
gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC);
|
gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -6459,7 +6444,7 @@ static void gen_tlbwe_440(DisasContext *ctx)
|
||||||
#if defined(CONFIG_USER_ONLY)
|
#if defined(CONFIG_USER_ONLY)
|
||||||
gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC);
|
gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC);
|
||||||
#else
|
#else
|
||||||
if (unlikely(!ctx->mem_idx)) {
|
if (unlikely(ctx->pr)) {
|
||||||
gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC);
|
gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -6489,7 +6474,7 @@ static void gen_tlbre_booke206(DisasContext *ctx)
|
||||||
#if defined(CONFIG_USER_ONLY)
|
#if defined(CONFIG_USER_ONLY)
|
||||||
gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC);
|
gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC);
|
||||||
#else
|
#else
|
||||||
if (unlikely(!ctx->mem_idx)) {
|
if (unlikely(ctx->pr)) {
|
||||||
gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC);
|
gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -6505,7 +6490,7 @@ static void gen_tlbsx_booke206(DisasContext *ctx)
|
||||||
gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC);
|
gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC);
|
||||||
#else
|
#else
|
||||||
TCGv t0;
|
TCGv t0;
|
||||||
if (unlikely(!ctx->mem_idx)) {
|
if (unlikely(ctx->pr)) {
|
||||||
gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC);
|
gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -6529,7 +6514,7 @@ static void gen_tlbwe_booke206(DisasContext *ctx)
|
||||||
#if defined(CONFIG_USER_ONLY)
|
#if defined(CONFIG_USER_ONLY)
|
||||||
gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC);
|
gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC);
|
||||||
#else
|
#else
|
||||||
if (unlikely(!ctx->mem_idx)) {
|
if (unlikely(ctx->pr)) {
|
||||||
gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC);
|
gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -6544,7 +6529,7 @@ static void gen_tlbivax_booke206(DisasContext *ctx)
|
||||||
gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC);
|
gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC);
|
||||||
#else
|
#else
|
||||||
TCGv t0;
|
TCGv t0;
|
||||||
if (unlikely(!ctx->mem_idx)) {
|
if (unlikely(ctx->pr)) {
|
||||||
gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC);
|
gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -6563,7 +6548,7 @@ static void gen_tlbilx_booke206(DisasContext *ctx)
|
||||||
gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC);
|
gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC);
|
||||||
#else
|
#else
|
||||||
TCGv t0;
|
TCGv t0;
|
||||||
if (unlikely(!ctx->mem_idx)) {
|
if (unlikely(ctx->pr)) {
|
||||||
gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC);
|
gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -6598,7 +6583,7 @@ static void gen_wrtee(DisasContext *ctx)
|
||||||
gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC);
|
gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC);
|
||||||
#else
|
#else
|
||||||
TCGv t0;
|
TCGv t0;
|
||||||
if (unlikely(!ctx->mem_idx)) {
|
if (unlikely(ctx->pr)) {
|
||||||
gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC);
|
gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -6620,7 +6605,7 @@ static void gen_wrteei(DisasContext *ctx)
|
||||||
#if defined(CONFIG_USER_ONLY)
|
#if defined(CONFIG_USER_ONLY)
|
||||||
gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC);
|
gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC);
|
||||||
#else
|
#else
|
||||||
if (unlikely(!ctx->mem_idx)) {
|
if (unlikely(ctx->pr)) {
|
||||||
gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC);
|
gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -6673,7 +6658,7 @@ static void gen_msgclr(DisasContext *ctx)
|
||||||
#if defined(CONFIG_USER_ONLY)
|
#if defined(CONFIG_USER_ONLY)
|
||||||
gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC);
|
gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC);
|
||||||
#else
|
#else
|
||||||
if (unlikely(ctx->mem_idx == 0)) {
|
if (unlikely(ctx->pr)) {
|
||||||
gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC);
|
gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -6687,7 +6672,7 @@ static void gen_msgsnd(DisasContext *ctx)
|
||||||
#if defined(CONFIG_USER_ONLY)
|
#if defined(CONFIG_USER_ONLY)
|
||||||
gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC);
|
gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC);
|
||||||
#else
|
#else
|
||||||
if (unlikely(ctx->mem_idx == 0)) {
|
if (unlikely(ctx->pr)) {
|
||||||
gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC);
|
gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -7253,10 +7238,10 @@ GEN_VXFORM_NOA_ENV(vrefp, 5, 4);
|
||||||
GEN_VXFORM_NOA_ENV(vrsqrtefp, 5, 5);
|
GEN_VXFORM_NOA_ENV(vrsqrtefp, 5, 5);
|
||||||
GEN_VXFORM_NOA_ENV(vexptefp, 5, 6);
|
GEN_VXFORM_NOA_ENV(vexptefp, 5, 6);
|
||||||
GEN_VXFORM_NOA_ENV(vlogefp, 5, 7);
|
GEN_VXFORM_NOA_ENV(vlogefp, 5, 7);
|
||||||
GEN_VXFORM_NOA_ENV(vrfim, 5, 8);
|
GEN_VXFORM_NOA_ENV(vrfim, 5, 11);
|
||||||
GEN_VXFORM_NOA_ENV(vrfin, 5, 9);
|
GEN_VXFORM_NOA_ENV(vrfin, 5, 8);
|
||||||
GEN_VXFORM_NOA_ENV(vrfip, 5, 10);
|
GEN_VXFORM_NOA_ENV(vrfip, 5, 10);
|
||||||
GEN_VXFORM_NOA_ENV(vrfiz, 5, 11);
|
GEN_VXFORM_NOA_ENV(vrfiz, 5, 9);
|
||||||
|
|
||||||
#define GEN_VXFORM_SIMM(name, opc2, opc3) \
|
#define GEN_VXFORM_SIMM(name, opc2, opc3) \
|
||||||
static void glue(gen_, name)(DisasContext *ctx) \
|
static void glue(gen_, name)(DisasContext *ctx) \
|
||||||
|
@ -8221,7 +8206,7 @@ static inline TCGv_ptr gen_fprp_ptr(int reg)
|
||||||
}
|
}
|
||||||
|
|
||||||
#if defined(TARGET_PPC64)
|
#if defined(TARGET_PPC64)
|
||||||
static void gen_set_cr6_from_fpscr(DisasContext *ctx)
|
static void gen_set_cr1_from_fpscr(DisasContext *ctx)
|
||||||
{
|
{
|
||||||
TCGv_i32 tmp = tcg_temp_new_i32();
|
TCGv_i32 tmp = tcg_temp_new_i32();
|
||||||
tcg_gen_trunc_tl_i32(tmp, cpu_fpscr);
|
tcg_gen_trunc_tl_i32(tmp, cpu_fpscr);
|
||||||
|
@ -8229,7 +8214,7 @@ static void gen_set_cr6_from_fpscr(DisasContext *ctx)
|
||||||
tcg_temp_free_i32(tmp);
|
tcg_temp_free_i32(tmp);
|
||||||
}
|
}
|
||||||
#else
|
#else
|
||||||
static void gen_set_cr6_from_fpscr(DisasContext *ctx)
|
static void gen_set_cr1_from_fpscr(DisasContext *ctx)
|
||||||
{
|
{
|
||||||
tcg_gen_shri_tl(cpu_crf[1], cpu_fpscr, 28);
|
tcg_gen_shri_tl(cpu_crf[1], cpu_fpscr, 28);
|
||||||
}
|
}
|
||||||
|
@ -8249,7 +8234,7 @@ static void gen_##name(DisasContext *ctx) \
|
||||||
rb = gen_fprp_ptr(rB(ctx->opcode)); \
|
rb = gen_fprp_ptr(rB(ctx->opcode)); \
|
||||||
gen_helper_##name(cpu_env, rd, ra, rb); \
|
gen_helper_##name(cpu_env, rd, ra, rb); \
|
||||||
if (unlikely(Rc(ctx->opcode) != 0)) { \
|
if (unlikely(Rc(ctx->opcode) != 0)) { \
|
||||||
gen_set_cr6_from_fpscr(ctx); \
|
gen_set_cr1_from_fpscr(ctx); \
|
||||||
} \
|
} \
|
||||||
tcg_temp_free_ptr(rd); \
|
tcg_temp_free_ptr(rd); \
|
||||||
tcg_temp_free_ptr(ra); \
|
tcg_temp_free_ptr(ra); \
|
||||||
|
@ -8307,7 +8292,7 @@ static void gen_##name(DisasContext *ctx) \
|
||||||
u32_2 = tcg_const_i32(u32f2(ctx->opcode)); \
|
u32_2 = tcg_const_i32(u32f2(ctx->opcode)); \
|
||||||
gen_helper_##name(cpu_env, rt, rb, u32_1, u32_2); \
|
gen_helper_##name(cpu_env, rt, rb, u32_1, u32_2); \
|
||||||
if (unlikely(Rc(ctx->opcode) != 0)) { \
|
if (unlikely(Rc(ctx->opcode) != 0)) { \
|
||||||
gen_set_cr6_from_fpscr(ctx); \
|
gen_set_cr1_from_fpscr(ctx); \
|
||||||
} \
|
} \
|
||||||
tcg_temp_free_ptr(rt); \
|
tcg_temp_free_ptr(rt); \
|
||||||
tcg_temp_free_ptr(rb); \
|
tcg_temp_free_ptr(rb); \
|
||||||
|
@ -8331,7 +8316,7 @@ static void gen_##name(DisasContext *ctx) \
|
||||||
i32 = tcg_const_i32(i32fld(ctx->opcode)); \
|
i32 = tcg_const_i32(i32fld(ctx->opcode)); \
|
||||||
gen_helper_##name(cpu_env, rt, ra, rb, i32); \
|
gen_helper_##name(cpu_env, rt, ra, rb, i32); \
|
||||||
if (unlikely(Rc(ctx->opcode) != 0)) { \
|
if (unlikely(Rc(ctx->opcode) != 0)) { \
|
||||||
gen_set_cr6_from_fpscr(ctx); \
|
gen_set_cr1_from_fpscr(ctx); \
|
||||||
} \
|
} \
|
||||||
tcg_temp_free_ptr(rt); \
|
tcg_temp_free_ptr(rt); \
|
||||||
tcg_temp_free_ptr(rb); \
|
tcg_temp_free_ptr(rb); \
|
||||||
|
@ -8352,7 +8337,7 @@ static void gen_##name(DisasContext *ctx) \
|
||||||
rb = gen_fprp_ptr(rB(ctx->opcode)); \
|
rb = gen_fprp_ptr(rB(ctx->opcode)); \
|
||||||
gen_helper_##name(cpu_env, rt, rb); \
|
gen_helper_##name(cpu_env, rt, rb); \
|
||||||
if (unlikely(Rc(ctx->opcode) != 0)) { \
|
if (unlikely(Rc(ctx->opcode) != 0)) { \
|
||||||
gen_set_cr6_from_fpscr(ctx); \
|
gen_set_cr1_from_fpscr(ctx); \
|
||||||
} \
|
} \
|
||||||
tcg_temp_free_ptr(rt); \
|
tcg_temp_free_ptr(rt); \
|
||||||
tcg_temp_free_ptr(rb); \
|
tcg_temp_free_ptr(rb); \
|
||||||
|
@ -8373,7 +8358,7 @@ static void gen_##name(DisasContext *ctx) \
|
||||||
i32 = tcg_const_i32(i32fld(ctx->opcode)); \
|
i32 = tcg_const_i32(i32fld(ctx->opcode)); \
|
||||||
gen_helper_##name(cpu_env, rt, rs, i32); \
|
gen_helper_##name(cpu_env, rt, rs, i32); \
|
||||||
if (unlikely(Rc(ctx->opcode) != 0)) { \
|
if (unlikely(Rc(ctx->opcode) != 0)) { \
|
||||||
gen_set_cr6_from_fpscr(ctx); \
|
gen_set_cr1_from_fpscr(ctx); \
|
||||||
} \
|
} \
|
||||||
tcg_temp_free_ptr(rt); \
|
tcg_temp_free_ptr(rt); \
|
||||||
tcg_temp_free_ptr(rs); \
|
tcg_temp_free_ptr(rs); \
|
||||||
|
@ -10091,16 +10076,14 @@ GEN_HANDLER_E(fctiwu, 0x3F, 0x0E, 0x04, 0, PPC_NONE, PPC2_FP_CVT_ISA206),
|
||||||
GEN_FLOAT_B(ctiwz, 0x0F, 0x00, 0, PPC_FLOAT),
|
GEN_FLOAT_B(ctiwz, 0x0F, 0x00, 0, PPC_FLOAT),
|
||||||
GEN_HANDLER_E(fctiwuz, 0x3F, 0x0F, 0x04, 0, PPC_NONE, PPC2_FP_CVT_ISA206),
|
GEN_HANDLER_E(fctiwuz, 0x3F, 0x0F, 0x04, 0, PPC_NONE, PPC2_FP_CVT_ISA206),
|
||||||
GEN_FLOAT_B(rsp, 0x0C, 0x00, 1, PPC_FLOAT),
|
GEN_FLOAT_B(rsp, 0x0C, 0x00, 1, PPC_FLOAT),
|
||||||
#if defined(TARGET_PPC64)
|
GEN_HANDLER_E(fcfid, 0x3F, 0x0E, 0x1A, 0x001F0000, PPC_NONE, PPC2_FP_CVT_S64),
|
||||||
GEN_FLOAT_B(cfid, 0x0E, 0x1A, 1, PPC_64B),
|
|
||||||
GEN_HANDLER_E(fcfids, 0x3B, 0x0E, 0x1A, 0, PPC_NONE, PPC2_FP_CVT_ISA206),
|
GEN_HANDLER_E(fcfids, 0x3B, 0x0E, 0x1A, 0, PPC_NONE, PPC2_FP_CVT_ISA206),
|
||||||
GEN_HANDLER_E(fcfidu, 0x3F, 0x0E, 0x1E, 0, PPC_NONE, PPC2_FP_CVT_ISA206),
|
GEN_HANDLER_E(fcfidu, 0x3F, 0x0E, 0x1E, 0, PPC_NONE, PPC2_FP_CVT_ISA206),
|
||||||
GEN_HANDLER_E(fcfidus, 0x3B, 0x0E, 0x1E, 0, PPC_NONE, PPC2_FP_CVT_ISA206),
|
GEN_HANDLER_E(fcfidus, 0x3B, 0x0E, 0x1E, 0, PPC_NONE, PPC2_FP_CVT_ISA206),
|
||||||
GEN_FLOAT_B(ctid, 0x0E, 0x19, 0, PPC_64B),
|
GEN_HANDLER_E(fctid, 0x3F, 0x0E, 0x19, 0x001F0000, PPC_NONE, PPC2_FP_CVT_S64),
|
||||||
GEN_HANDLER_E(fctidu, 0x3F, 0x0E, 0x1D, 0, PPC_NONE, PPC2_FP_CVT_ISA206),
|
GEN_HANDLER_E(fctidu, 0x3F, 0x0E, 0x1D, 0, PPC_NONE, PPC2_FP_CVT_ISA206),
|
||||||
GEN_FLOAT_B(ctidz, 0x0F, 0x19, 0, PPC_64B),
|
GEN_HANDLER_E(fctidz, 0x3F, 0x0F, 0x19, 0x001F0000, PPC_NONE, PPC2_FP_CVT_S64),
|
||||||
GEN_HANDLER_E(fctiduz, 0x3F, 0x0F, 0x1D, 0, PPC_NONE, PPC2_FP_CVT_ISA206),
|
GEN_HANDLER_E(fctiduz, 0x3F, 0x0F, 0x1D, 0, PPC_NONE, PPC2_FP_CVT_ISA206),
|
||||||
#endif
|
|
||||||
GEN_FLOAT_B(rin, 0x08, 0x0C, 1, PPC_FLOAT_EXT),
|
GEN_FLOAT_B(rin, 0x08, 0x0C, 1, PPC_FLOAT_EXT),
|
||||||
GEN_FLOAT_B(riz, 0x08, 0x0D, 1, PPC_FLOAT_EXT),
|
GEN_FLOAT_B(riz, 0x08, 0x0D, 1, PPC_FLOAT_EXT),
|
||||||
GEN_FLOAT_B(rip, 0x08, 0x0E, 1, PPC_FLOAT_EXT),
|
GEN_FLOAT_B(rip, 0x08, 0x0E, 1, PPC_FLOAT_EXT),
|
||||||
|
@ -10491,10 +10474,10 @@ GEN_VXFORM_NOA(vrefp, 5, 4),
|
||||||
GEN_VXFORM_NOA(vrsqrtefp, 5, 5),
|
GEN_VXFORM_NOA(vrsqrtefp, 5, 5),
|
||||||
GEN_VXFORM_NOA(vexptefp, 5, 6),
|
GEN_VXFORM_NOA(vexptefp, 5, 6),
|
||||||
GEN_VXFORM_NOA(vlogefp, 5, 7),
|
GEN_VXFORM_NOA(vlogefp, 5, 7),
|
||||||
GEN_VXFORM_NOA(vrfim, 5, 8),
|
GEN_VXFORM_NOA(vrfim, 5, 11),
|
||||||
GEN_VXFORM_NOA(vrfin, 5, 9),
|
GEN_VXFORM_NOA(vrfin, 5, 8),
|
||||||
GEN_VXFORM_NOA(vrfip, 5, 10),
|
GEN_VXFORM_NOA(vrfip, 5, 10),
|
||||||
GEN_VXFORM_NOA(vrfiz, 5, 11),
|
GEN_VXFORM_NOA(vrfiz, 5, 9),
|
||||||
|
|
||||||
#undef GEN_VXFORM_UIMM
|
#undef GEN_VXFORM_UIMM
|
||||||
#define GEN_VXFORM_UIMM(name, opc2, opc3) \
|
#define GEN_VXFORM_UIMM(name, opc2, opc3) \
|
||||||
|
@ -11302,6 +11285,8 @@ static inline void gen_intermediate_code_internal(PowerPCCPU *cpu,
|
||||||
ctx.tb = tb;
|
ctx.tb = tb;
|
||||||
ctx.exception = POWERPC_EXCP_NONE;
|
ctx.exception = POWERPC_EXCP_NONE;
|
||||||
ctx.spr_cb = env->spr_cb;
|
ctx.spr_cb = env->spr_cb;
|
||||||
|
ctx.pr = msr_pr;
|
||||||
|
ctx.hv = !msr_pr && msr_hv;
|
||||||
ctx.mem_idx = env->mmu_idx;
|
ctx.mem_idx = env->mmu_idx;
|
||||||
ctx.insns_flags = env->insns_flags;
|
ctx.insns_flags = env->insns_flags;
|
||||||
ctx.insns_flags2 = env->insns_flags2;
|
ctx.insns_flags2 = env->insns_flags2;
|
||||||
|
|
|
@ -2786,7 +2786,7 @@ static void init_excp_BookE (CPUPPCState *env)
|
||||||
env->excp_vectors[POWERPC_EXCP_DTLB] = 0x00000000;
|
env->excp_vectors[POWERPC_EXCP_DTLB] = 0x00000000;
|
||||||
env->excp_vectors[POWERPC_EXCP_ITLB] = 0x00000000;
|
env->excp_vectors[POWERPC_EXCP_ITLB] = 0x00000000;
|
||||||
env->excp_vectors[POWERPC_EXCP_DEBUG] = 0x00000000;
|
env->excp_vectors[POWERPC_EXCP_DEBUG] = 0x00000000;
|
||||||
env->ivor_mask = 0x0000FFE0UL;
|
env->ivor_mask = 0x0000FFF0UL;
|
||||||
env->ivpr_mask = 0xFFFF0000UL;
|
env->ivpr_mask = 0xFFFF0000UL;
|
||||||
/* Hardware reset vector */
|
/* Hardware reset vector */
|
||||||
env->hreset_vector = 0xFFFFFFFCUL;
|
env->hreset_vector = 0xFFFFFFFCUL;
|
||||||
|
@ -3923,6 +3923,44 @@ POWERPC_FAMILY(440x5)(ObjectClass *oc, void *data)
|
||||||
POWERPC_FLAG_DE | POWERPC_FLAG_BUS_CLK;
|
POWERPC_FLAG_DE | POWERPC_FLAG_BUS_CLK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
POWERPC_FAMILY(440x5wDFPU)(ObjectClass *oc, void *data)
|
||||||
|
{
|
||||||
|
DeviceClass *dc = DEVICE_CLASS(oc);
|
||||||
|
PowerPCCPUClass *pcc = POWERPC_CPU_CLASS(oc);
|
||||||
|
|
||||||
|
dc->desc = "PowerPC 440x5 with double precision FPU";
|
||||||
|
pcc->init_proc = init_proc_440x5;
|
||||||
|
pcc->check_pow = check_pow_nocheck;
|
||||||
|
pcc->insns_flags = PPC_INSNS_BASE | PPC_STRING |
|
||||||
|
PPC_FLOAT | PPC_FLOAT_FSQRT |
|
||||||
|
PPC_FLOAT_STFIWX |
|
||||||
|
PPC_DCR | PPC_WRTEE | PPC_RFMCI |
|
||||||
|
PPC_CACHE | PPC_CACHE_ICBI |
|
||||||
|
PPC_CACHE_DCBZ | PPC_CACHE_DCBA |
|
||||||
|
PPC_MEM_TLBSYNC | PPC_MFTB |
|
||||||
|
PPC_BOOKE | PPC_4xx_COMMON | PPC_405_MAC |
|
||||||
|
PPC_440_SPEC;
|
||||||
|
pcc->insns_flags2 = PPC2_FP_CVT_S64;
|
||||||
|
pcc->msr_mask = (1ull << MSR_POW) |
|
||||||
|
(1ull << MSR_CE) |
|
||||||
|
(1ull << MSR_EE) |
|
||||||
|
(1ull << MSR_PR) |
|
||||||
|
(1ull << MSR_FP) |
|
||||||
|
(1ull << MSR_ME) |
|
||||||
|
(1ull << MSR_FE0) |
|
||||||
|
(1ull << MSR_DWE) |
|
||||||
|
(1ull << MSR_DE) |
|
||||||
|
(1ull << MSR_FE1) |
|
||||||
|
(1ull << MSR_IR) |
|
||||||
|
(1ull << MSR_DR);
|
||||||
|
pcc->mmu_model = POWERPC_MMU_BOOKE;
|
||||||
|
pcc->excp_model = POWERPC_EXCP_BOOKE;
|
||||||
|
pcc->bus_model = PPC_FLAGS_INPUT_BookE;
|
||||||
|
pcc->bfd_mach = bfd_mach_ppc_403;
|
||||||
|
pcc->flags = POWERPC_FLAG_CE | POWERPC_FLAG_DWE |
|
||||||
|
POWERPC_FLAG_DE | POWERPC_FLAG_BUS_CLK;
|
||||||
|
}
|
||||||
|
|
||||||
static void init_proc_460 (CPUPPCState *env)
|
static void init_proc_460 (CPUPPCState *env)
|
||||||
{
|
{
|
||||||
/* Time base */
|
/* Time base */
|
||||||
|
@ -5010,7 +5048,8 @@ POWERPC_FAMILY(e5500)(ObjectClass *oc, void *data)
|
||||||
PPC_FLOAT_STFIWX | PPC_WAIT |
|
PPC_FLOAT_STFIWX | PPC_WAIT |
|
||||||
PPC_MEM_TLBSYNC | PPC_TLBIVAX | PPC_MEM_SYNC |
|
PPC_MEM_TLBSYNC | PPC_TLBIVAX | PPC_MEM_SYNC |
|
||||||
PPC_64B | PPC_POPCNTB | PPC_POPCNTWD;
|
PPC_64B | PPC_POPCNTB | PPC_POPCNTWD;
|
||||||
pcc->insns_flags2 = PPC2_BOOKE206 | PPC2_PRCNTL | PPC2_PERM_ISA206;
|
pcc->insns_flags2 = PPC2_BOOKE206 | PPC2_PRCNTL | PPC2_PERM_ISA206 | \
|
||||||
|
PPC2_FP_CVT_S64;
|
||||||
pcc->msr_mask = (1ull << MSR_CM) |
|
pcc->msr_mask = (1ull << MSR_CM) |
|
||||||
(1ull << MSR_GS) |
|
(1ull << MSR_GS) |
|
||||||
(1ull << MSR_UCLE) |
|
(1ull << MSR_UCLE) |
|
||||||
|
@ -7906,6 +7945,7 @@ POWERPC_FAMILY(970)(ObjectClass *oc, void *data)
|
||||||
PPC_MEM_TLBIE | PPC_MEM_TLBSYNC |
|
PPC_MEM_TLBIE | PPC_MEM_TLBSYNC |
|
||||||
PPC_64B | PPC_ALTIVEC |
|
PPC_64B | PPC_ALTIVEC |
|
||||||
PPC_SEGMENT_64B | PPC_SLBI;
|
PPC_SEGMENT_64B | PPC_SLBI;
|
||||||
|
pcc->insns_flags2 = PPC2_FP_CVT_S64;
|
||||||
pcc->msr_mask = (1ull << MSR_SF) |
|
pcc->msr_mask = (1ull << MSR_SF) |
|
||||||
(1ull << MSR_VR) |
|
(1ull << MSR_VR) |
|
||||||
(1ull << MSR_POW) |
|
(1ull << MSR_POW) |
|
||||||
|
@ -7958,6 +7998,7 @@ POWERPC_FAMILY(POWER5P)(ObjectClass *oc, void *data)
|
||||||
PPC_MEM_TLBIE | PPC_MEM_TLBSYNC |
|
PPC_MEM_TLBIE | PPC_MEM_TLBSYNC |
|
||||||
PPC_64B |
|
PPC_64B |
|
||||||
PPC_SEGMENT_64B | PPC_SLBI;
|
PPC_SEGMENT_64B | PPC_SLBI;
|
||||||
|
pcc->insns_flags2 = PPC2_FP_CVT_S64;
|
||||||
pcc->msr_mask = (1ull << MSR_SF) |
|
pcc->msr_mask = (1ull << MSR_SF) |
|
||||||
(1ull << MSR_VR) |
|
(1ull << MSR_VR) |
|
||||||
(1ull << MSR_POW) |
|
(1ull << MSR_POW) |
|
||||||
|
@ -8100,7 +8141,7 @@ POWERPC_FAMILY(POWER7)(ObjectClass *oc, void *data)
|
||||||
pcc->insns_flags2 = PPC2_VSX | PPC2_DFP | PPC2_DBRX | PPC2_ISA205 |
|
pcc->insns_flags2 = PPC2_VSX | PPC2_DFP | PPC2_DBRX | PPC2_ISA205 |
|
||||||
PPC2_PERM_ISA206 | PPC2_DIVE_ISA206 |
|
PPC2_PERM_ISA206 | PPC2_DIVE_ISA206 |
|
||||||
PPC2_ATOMIC_ISA206 | PPC2_FP_CVT_ISA206 |
|
PPC2_ATOMIC_ISA206 | PPC2_FP_CVT_ISA206 |
|
||||||
PPC2_FP_TST_ISA206;
|
PPC2_FP_TST_ISA206 | PPC2_FP_CVT_S64;
|
||||||
pcc->msr_mask = (1ull << MSR_SF) |
|
pcc->msr_mask = (1ull << MSR_SF) |
|
||||||
(1ull << MSR_VR) |
|
(1ull << MSR_VR) |
|
||||||
(1ull << MSR_VSX) |
|
(1ull << MSR_VSX) |
|
||||||
|
@ -8178,7 +8219,7 @@ POWERPC_FAMILY(POWER8)(ObjectClass *oc, void *data)
|
||||||
PPC2_ATOMIC_ISA206 | PPC2_FP_CVT_ISA206 |
|
PPC2_ATOMIC_ISA206 | PPC2_FP_CVT_ISA206 |
|
||||||
PPC2_FP_TST_ISA206 | PPC2_BCTAR_ISA207 |
|
PPC2_FP_TST_ISA206 | PPC2_BCTAR_ISA207 |
|
||||||
PPC2_LSQ_ISA207 | PPC2_ALTIVEC_207 |
|
PPC2_LSQ_ISA207 | PPC2_ALTIVEC_207 |
|
||||||
PPC2_ISA205 | PPC2_ISA207S;
|
PPC2_ISA205 | PPC2_ISA207S | PPC2_FP_CVT_S64;
|
||||||
pcc->msr_mask = (1ull << MSR_SF) |
|
pcc->msr_mask = (1ull << MSR_SF) |
|
||||||
(1ull << MSR_TM) |
|
(1ull << MSR_TM) |
|
||||||
(1ull << MSR_VR) |
|
(1ull << MSR_VR) |
|
||||||
|
@ -8432,14 +8473,16 @@ enum {
|
||||||
PPC_INDIRECT = 1, /* Indirect opcode table */
|
PPC_INDIRECT = 1, /* Indirect opcode table */
|
||||||
};
|
};
|
||||||
|
|
||||||
|
#define PPC_OPCODE_MASK 0x3
|
||||||
|
|
||||||
static inline int is_indirect_opcode (void *handler)
|
static inline int is_indirect_opcode (void *handler)
|
||||||
{
|
{
|
||||||
return ((uintptr_t)handler & 0x03) == PPC_INDIRECT;
|
return ((uintptr_t)handler & PPC_OPCODE_MASK) == PPC_INDIRECT;
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline opc_handler_t **ind_table(void *handler)
|
static inline opc_handler_t **ind_table(void *handler)
|
||||||
{
|
{
|
||||||
return (opc_handler_t **)((uintptr_t)handler & ~3);
|
return (opc_handler_t **)((uintptr_t)handler & ~PPC_OPCODE_MASK);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Instruction table creation */
|
/* Instruction table creation */
|
||||||
|
@ -8456,8 +8499,8 @@ static int create_new_table (opc_handler_t **table, unsigned char idx)
|
||||||
{
|
{
|
||||||
opc_handler_t **tmp;
|
opc_handler_t **tmp;
|
||||||
|
|
||||||
tmp = g_new(opc_handler_t *, 0x20);
|
tmp = g_new(opc_handler_t *, PPC_CPU_INDIRECT_OPCODES_LEN);
|
||||||
fill_new_table(tmp, 0x20);
|
fill_new_table(tmp, PPC_CPU_INDIRECT_OPCODES_LEN);
|
||||||
table[idx] = (opc_handler_t *)((uintptr_t)tmp | PPC_INDIRECT);
|
table[idx] = (opc_handler_t *)((uintptr_t)tmp | PPC_INDIRECT);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -8584,7 +8627,8 @@ static int test_opcode_table (opc_handler_t **table, int len)
|
||||||
table[i] = &invalid_handler;
|
table[i] = &invalid_handler;
|
||||||
if (table[i] != &invalid_handler) {
|
if (table[i] != &invalid_handler) {
|
||||||
if (is_indirect_opcode(table[i])) {
|
if (is_indirect_opcode(table[i])) {
|
||||||
tmp = test_opcode_table(ind_table(table[i]), 0x20);
|
tmp = test_opcode_table(ind_table(table[i]),
|
||||||
|
PPC_CPU_INDIRECT_OPCODES_LEN);
|
||||||
if (tmp == 0) {
|
if (tmp == 0) {
|
||||||
free(table[i]);
|
free(table[i]);
|
||||||
table[i] = &invalid_handler;
|
table[i] = &invalid_handler;
|
||||||
|
@ -8602,7 +8646,7 @@ static int test_opcode_table (opc_handler_t **table, int len)
|
||||||
|
|
||||||
static void fix_opcode_tables (opc_handler_t **ppc_opcodes)
|
static void fix_opcode_tables (opc_handler_t **ppc_opcodes)
|
||||||
{
|
{
|
||||||
if (test_opcode_table(ppc_opcodes, 0x40) == 0)
|
if (test_opcode_table(ppc_opcodes, PPC_CPU_OPCODES_LEN) == 0)
|
||||||
printf("*** WARNING: no opcode defined !\n");
|
printf("*** WARNING: no opcode defined !\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -8613,7 +8657,7 @@ static void create_ppc_opcodes(PowerPCCPU *cpu, Error **errp)
|
||||||
CPUPPCState *env = &cpu->env;
|
CPUPPCState *env = &cpu->env;
|
||||||
opcode_t *opc;
|
opcode_t *opc;
|
||||||
|
|
||||||
fill_new_table(env->opcodes, 0x40);
|
fill_new_table(env->opcodes, PPC_CPU_OPCODES_LEN);
|
||||||
for (opc = opcodes; opc < &opcodes[ARRAY_SIZE(opcodes)]; opc++) {
|
for (opc = opcodes; opc < &opcodes[ARRAY_SIZE(opcodes)]; opc++) {
|
||||||
if (((opc->handler.type & pcc->insns_flags) != 0) ||
|
if (((opc->handler.type & pcc->insns_flags) != 0) ||
|
||||||
((opc->handler.type2 & pcc->insns_flags2) != 0)) {
|
((opc->handler.type2 & pcc->insns_flags2) != 0)) {
|
||||||
|
@ -8639,12 +8683,12 @@ static void dump_ppc_insns (CPUPPCState *env)
|
||||||
|
|
||||||
printf("Instructions set:\n");
|
printf("Instructions set:\n");
|
||||||
/* opc1 is 6 bits long */
|
/* opc1 is 6 bits long */
|
||||||
for (opc1 = 0x00; opc1 < 0x40; opc1++) {
|
for (opc1 = 0x00; opc1 < PPC_CPU_OPCODES_LEN; opc1++) {
|
||||||
table = env->opcodes;
|
table = env->opcodes;
|
||||||
handler = table[opc1];
|
handler = table[opc1];
|
||||||
if (is_indirect_opcode(handler)) {
|
if (is_indirect_opcode(handler)) {
|
||||||
/* opc2 is 5 bits long */
|
/* opc2 is 5 bits long */
|
||||||
for (opc2 = 0; opc2 < 0x20; opc2++) {
|
for (opc2 = 0; opc2 < PPC_CPU_INDIRECT_OPCODES_LEN; opc2++) {
|
||||||
table = env->opcodes;
|
table = env->opcodes;
|
||||||
handler = env->opcodes[opc1];
|
handler = env->opcodes[opc1];
|
||||||
table = ind_table(handler);
|
table = ind_table(handler);
|
||||||
|
@ -8652,7 +8696,8 @@ static void dump_ppc_insns (CPUPPCState *env)
|
||||||
if (is_indirect_opcode(handler)) {
|
if (is_indirect_opcode(handler)) {
|
||||||
table = ind_table(handler);
|
table = ind_table(handler);
|
||||||
/* opc3 is 5 bits long */
|
/* opc3 is 5 bits long */
|
||||||
for (opc3 = 0; opc3 < 0x20; opc3++) {
|
for (opc3 = 0; opc3 < PPC_CPU_INDIRECT_OPCODES_LEN;
|
||||||
|
opc3++) {
|
||||||
handler = table[opc3];
|
handler = table[opc3];
|
||||||
if (handler->handler != &gen_invalid) {
|
if (handler->handler != &gen_invalid) {
|
||||||
/* Special hack to properly dump SPE insns */
|
/* Special hack to properly dump SPE insns */
|
||||||
|
@ -9087,11 +9132,24 @@ static void ppc_cpu_unrealizefn(DeviceState *dev, Error **errp)
|
||||||
{
|
{
|
||||||
PowerPCCPU *cpu = POWERPC_CPU(dev);
|
PowerPCCPU *cpu = POWERPC_CPU(dev);
|
||||||
CPUPPCState *env = &cpu->env;
|
CPUPPCState *env = &cpu->env;
|
||||||
int i;
|
opc_handler_t **table;
|
||||||
|
int i, j;
|
||||||
|
|
||||||
for (i = 0; i < PPC_CPU_OPCODES_LEN; i++) {
|
for (i = 0; i < PPC_CPU_OPCODES_LEN; i++) {
|
||||||
if (env->opcodes[i] != &invalid_handler) {
|
if (env->opcodes[i] == &invalid_handler) {
|
||||||
g_free(env->opcodes[i]);
|
continue;
|
||||||
|
}
|
||||||
|
if (is_indirect_opcode(env->opcodes[i])) {
|
||||||
|
table = ind_table(env->opcodes[i]);
|
||||||
|
for (j = 0; j < PPC_CPU_INDIRECT_OPCODES_LEN; j++) {
|
||||||
|
if (table[j] != &invalid_handler &&
|
||||||
|
is_indirect_opcode(table[j])) {
|
||||||
|
g_free((opc_handler_t *)((uintptr_t)table[j] &
|
||||||
|
~PPC_INDIRECT));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
g_free((opc_handler_t *)((uintptr_t)env->opcodes[i] &
|
||||||
|
~PPC_INDIRECT));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -9137,7 +9195,7 @@ int ppc_set_compat(PowerPCCPU *cpu, uint32_t cpu_version)
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (kvm_enabled() && kvmppc_set_compat(cpu, cpu->max_compat) < 0) {
|
if (kvm_enabled() && kvmppc_set_compat(cpu, cpu->cpu_version) < 0) {
|
||||||
error_report("Unable to set compatibility mode in KVM");
|
error_report("Unable to set compatibility mode in KVM");
|
||||||
ret = -1;
|
ret = -1;
|
||||||
}
|
}
|
||||||
|
|
1
vl.c
1
vl.c
|
@ -1441,6 +1441,7 @@ static void machine_class_init(ObjectClass *oc, void *data)
|
||||||
mc->no_floppy = qm->no_floppy;
|
mc->no_floppy = qm->no_floppy;
|
||||||
mc->no_cdrom = qm->no_cdrom;
|
mc->no_cdrom = qm->no_cdrom;
|
||||||
mc->no_sdcard = qm->no_sdcard;
|
mc->no_sdcard = qm->no_sdcard;
|
||||||
|
mc->has_dynamic_sysbus = qm->has_dynamic_sysbus;
|
||||||
mc->is_default = qm->is_default;
|
mc->is_default = qm->is_default;
|
||||||
mc->default_machine_opts = qm->default_machine_opts;
|
mc->default_machine_opts = qm->default_machine_opts;
|
||||||
mc->default_boot_order = qm->default_boot_order;
|
mc->default_boot_order = qm->default_boot_order;
|
||||||
|
|
Loading…
Reference in New Issue