ppc 7.0 queue:
* Exception and TLB fixes for the 405 CPU (Fabiano and Cedric) * spapr fixes (Alexey and Daniel) * PowerNV PHB3/4 fixes (Frederic and Daniel) * PowerNV XIVE improvements (Cedric) * 603 CPUs fixes (Christophe) * Book-E exception fixes (Vitaly) * Misc compile issues (Philippe and Fabiano) * Exception model rework for the BookS CPUs (Fabiano) * Exception model rework for the 74xx CPUs (Fabiano) * Removal of 602 CPUs -----BEGIN PGP SIGNATURE----- iQIzBAABCAAdFiEEoPZlSPBIlev+awtgUaNDx8/77KEFAmH2zf8ACgkQUaNDx8/7 7KFRpw//XIf99FI9/2LkovsEQIrQ8CooRfOO/4u37tU0W9uxANGrHjx47sANYcwD T45pH44++CjJwvEdwZmLEVicfvGzRVarZct3RofH0oqpYQVSdJNN4azmBHkhFBxN 1ygdppilu/6UVLRyqtiSykv2aoG5KNhLLoxR7Y2SHapnxs4Nnk5dn0QJcc7N/EpN RZ4a3dP+L4MWyZ3rZ0Yy3MXumaC+Sh6b9lxxZUBVNrPWR38zew3iFLy7A9kqCDfi FG/MSdIjctgF31ZKc91OxNwQDok3ByNrPLVTWhsNmNAdTqHEEmG58oDZAdDUo0Yg dzqmiUXglvWe4O54giLCBhDgF9EbWgsg2Bwu46w3+yugnTFAF6ESnngDXeu09zjW qlqNe2xajgY7tWCuJi/OGoPq14S7lzfIki5wSO1fWiHZR9qlfYWP7E5gYVtRYtaZ JG/+gcRoQSPfWP0LY/qazuQPtB8ha5pFwTWQlAATeHl3nfEqQAZmEuLUAdmtTaZx Pm5fEH12tnolLgf3DIAh247CZR4m5gl3MpQEhJzyCYJBEtbQfQv403BvyBIm8qDj BER/gBiscTQMKSnzoZ8ooKMqcIfnCvGtY8E6hn4uvRcAJ1Uz5DGRylQ6ySzy/JJt plW5XuKoBWfWYsQxe9PSoPtMXbCwEd4aQEbBR5e6akBJSrrtP0U= =qP5f -----END PGP SIGNATURE----- Merge remote-tracking branch 'remotes/legoater/tags/pull-ppc-20220130' into staging ppc 7.0 queue: * Exception and TLB fixes for the 405 CPU (Fabiano and Cedric) * spapr fixes (Alexey and Daniel) * PowerNV PHB3/4 fixes (Frederic and Daniel) * PowerNV XIVE improvements (Cedric) * 603 CPUs fixes (Christophe) * Book-E exception fixes (Vitaly) * Misc compile issues (Philippe and Fabiano) * Exception model rework for the BookS CPUs (Fabiano) * Exception model rework for the 74xx CPUs (Fabiano) * Removal of 602 CPUs # gpg: Signature made Sun 30 Jan 2022 17:42:23 GMT # gpg: using RSA key A0F66548F04895EBFE6B0B6051A343C7CFFBECA1 # gpg: Good signature from "Cédric Le Goater <clg@kaod.org>" [undefined] # gpg: WARNING: This key is not certified with a trusted signature! # gpg: There is no indication that the signature belongs to the owner. # Primary key fingerprint: A0F6 6548 F048 95EB FE6B 0B60 51A3 43C7 CFFB ECA1 * remotes/legoater/tags/pull-ppc-20220130: (41 commits) target/ppc: Remove support for the PowerPC 602 CPU target/ppc: 74xx: Set SRRs directly in exception code target/ppc: 74xx: System Reset interrupt cleanup target/ppc: 74xx: System Call exception cleanup target/ppc: 74xx: Program exception cleanup target/ppc: 74xx: External interrupt cleanup target/ppc: 74xx: Machine Check exception cleanup target/ppc: Simplify powerpc_excp_74xx target/ppc: Introduce powerpc_excp_74xx target/ppc: books: Program exception cleanup target/ppc: books: External interrupt cleanup target/ppc: books: Machine Check exception cleanup target/ppc: Simplify powerpc_excp_books target/ppc: Introduce powerpc_excp_books target/ppc: 405: Watchdog timer exception cleanup target/ppc: 405: Program exception cleanup target/ppc: 405: Instruction storage interrupt cleanup target/ppc: 405: Data Storage exception cleanup target/ppc: 405: Debug exception cleanup target/ppc: 405: Alignment exception cleanup ... Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
This commit is contained in:
commit
804b30d25f
@ -172,7 +172,12 @@ static uint64_t pnv_xive_vst_addr_indirect(PnvXive *xive, uint32_t type,
|
|||||||
|
|
||||||
/* Get the page size of the indirect table. */
|
/* Get the page size of the indirect table. */
|
||||||
vsd_addr = vsd & VSD_ADDRESS_MASK;
|
vsd_addr = vsd & VSD_ADDRESS_MASK;
|
||||||
ldq_be_dma(&address_space_memory, vsd_addr, &vsd, MEMTXATTRS_UNSPECIFIED);
|
if (ldq_be_dma(&address_space_memory, vsd_addr, &vsd,
|
||||||
|
MEMTXATTRS_UNSPECIFIED)) {
|
||||||
|
xive_error(xive, "VST: failed to access %s entry %x @0x%" PRIx64,
|
||||||
|
info->name, idx, vsd_addr);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
if (!(vsd & VSD_ADDRESS_MASK)) {
|
if (!(vsd & VSD_ADDRESS_MASK)) {
|
||||||
#ifdef XIVE_DEBUG
|
#ifdef XIVE_DEBUG
|
||||||
@ -195,8 +200,12 @@ static uint64_t pnv_xive_vst_addr_indirect(PnvXive *xive, uint32_t type,
|
|||||||
/* Load the VSD we are looking for, if not already done */
|
/* Load the VSD we are looking for, if not already done */
|
||||||
if (vsd_idx) {
|
if (vsd_idx) {
|
||||||
vsd_addr = vsd_addr + vsd_idx * XIVE_VSD_SIZE;
|
vsd_addr = vsd_addr + vsd_idx * XIVE_VSD_SIZE;
|
||||||
ldq_be_dma(&address_space_memory, vsd_addr, &vsd,
|
if (ldq_be_dma(&address_space_memory, vsd_addr, &vsd,
|
||||||
MEMTXATTRS_UNSPECIFIED);
|
MEMTXATTRS_UNSPECIFIED)) {
|
||||||
|
xive_error(xive, "VST: failed to access %s entry %x @0x%"
|
||||||
|
PRIx64, info->name, vsd_idx, vsd_addr);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
if (!(vsd & VSD_ADDRESS_MASK)) {
|
if (!(vsd & VSD_ADDRESS_MASK)) {
|
||||||
#ifdef XIVE_DEBUG
|
#ifdef XIVE_DEBUG
|
||||||
@ -543,7 +552,12 @@ static uint64_t pnv_xive_vst_per_subpage(PnvXive *xive, uint32_t type)
|
|||||||
|
|
||||||
/* Get the page size of the indirect table. */
|
/* Get the page size of the indirect table. */
|
||||||
vsd_addr = vsd & VSD_ADDRESS_MASK;
|
vsd_addr = vsd & VSD_ADDRESS_MASK;
|
||||||
ldq_be_dma(&address_space_memory, vsd_addr, &vsd, MEMTXATTRS_UNSPECIFIED);
|
if (ldq_be_dma(&address_space_memory, vsd_addr, &vsd,
|
||||||
|
MEMTXATTRS_UNSPECIFIED)) {
|
||||||
|
xive_error(xive, "VST: failed to access %s entry @0x%" PRIx64,
|
||||||
|
info->name, vsd_addr);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
if (!(vsd & VSD_ADDRESS_MASK)) {
|
if (!(vsd & VSD_ADDRESS_MASK)) {
|
||||||
#ifdef XIVE_DEBUG
|
#ifdef XIVE_DEBUG
|
||||||
|
@ -792,7 +792,9 @@ static void pnv_phb3_translate_tve(PnvPhb3DMASpace *ds, hwaddr addr,
|
|||||||
sh = tbl_shift * lev + tce_shift;
|
sh = tbl_shift * lev + tce_shift;
|
||||||
|
|
||||||
/* TODO: Multi-level untested */
|
/* TODO: Multi-level untested */
|
||||||
while ((lev--) >= 0) {
|
do {
|
||||||
|
lev--;
|
||||||
|
|
||||||
/* Grab the TCE address */
|
/* Grab the TCE address */
|
||||||
taddr = base | (((addr >> sh) & ((1ul << tbl_shift) - 1)) << 3);
|
taddr = base | (((addr >> sh) & ((1ul << tbl_shift) - 1)) << 3);
|
||||||
if (dma_memory_read(&address_space_memory, taddr, &tce,
|
if (dma_memory_read(&address_space_memory, taddr, &tce,
|
||||||
@ -813,21 +815,22 @@ static void pnv_phb3_translate_tve(PnvPhb3DMASpace *ds, hwaddr addr,
|
|||||||
}
|
}
|
||||||
sh -= tbl_shift;
|
sh -= tbl_shift;
|
||||||
base = tce & ~0xfffull;
|
base = tce & ~0xfffull;
|
||||||
}
|
} while (lev >= 0);
|
||||||
|
|
||||||
/* We exit the loop with TCE being the final TCE */
|
/* We exit the loop with TCE being the final TCE */
|
||||||
tce_mask = ~((1ull << tce_shift) - 1);
|
|
||||||
tlb->iova = addr & tce_mask;
|
|
||||||
tlb->translated_addr = tce & tce_mask;
|
|
||||||
tlb->addr_mask = ~tce_mask;
|
|
||||||
tlb->perm = tce & 3;
|
|
||||||
if ((is_write & !(tce & 2)) || ((!is_write) && !(tce & 1))) {
|
if ((is_write & !(tce & 2)) || ((!is_write) && !(tce & 1))) {
|
||||||
phb3_error(phb, "TCE access fault at 0x%"PRIx64, taddr);
|
phb3_error(phb, "TCE access fault at 0x%"PRIx64, taddr);
|
||||||
phb3_error(phb, " xlate %"PRIx64":%c TVE=%"PRIx64, addr,
|
phb3_error(phb, " xlate %"PRIx64":%c TVE=%"PRIx64, addr,
|
||||||
is_write ? 'W' : 'R', tve);
|
is_write ? 'W' : 'R', tve);
|
||||||
phb3_error(phb, " tta=%"PRIx64" lev=%d tts=%d tps=%d",
|
phb3_error(phb, " tta=%"PRIx64" lev=%d tts=%d tps=%d",
|
||||||
tta, lev, tts, tps);
|
tta, lev, tts, tps);
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
tce_mask = ~((1ull << tce_shift) - 1);
|
||||||
|
tlb->iova = addr & tce_mask;
|
||||||
|
tlb->translated_addr = tce & tce_mask;
|
||||||
|
tlb->addr_mask = ~tce_mask;
|
||||||
|
tlb->perm = tce & 3;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1267,7 +1267,9 @@ static void pnv_phb4_translate_tve(PnvPhb4DMASpace *ds, hwaddr addr,
|
|||||||
/* TODO: Limit to support IO page sizes */
|
/* TODO: Limit to support IO page sizes */
|
||||||
|
|
||||||
/* TODO: Multi-level untested */
|
/* TODO: Multi-level untested */
|
||||||
while ((lev--) >= 0) {
|
do {
|
||||||
|
lev--;
|
||||||
|
|
||||||
/* Grab the TCE address */
|
/* Grab the TCE address */
|
||||||
taddr = base | (((addr >> sh) & ((1ul << tbl_shift) - 1)) << 3);
|
taddr = base | (((addr >> sh) & ((1ul << tbl_shift) - 1)) << 3);
|
||||||
if (dma_memory_read(&address_space_memory, taddr, &tce,
|
if (dma_memory_read(&address_space_memory, taddr, &tce,
|
||||||
@ -1288,21 +1290,22 @@ static void pnv_phb4_translate_tve(PnvPhb4DMASpace *ds, hwaddr addr,
|
|||||||
}
|
}
|
||||||
sh -= tbl_shift;
|
sh -= tbl_shift;
|
||||||
base = tce & ~0xfffull;
|
base = tce & ~0xfffull;
|
||||||
}
|
} while (lev >= 0);
|
||||||
|
|
||||||
/* We exit the loop with TCE being the final TCE */
|
/* We exit the loop with TCE being the final TCE */
|
||||||
tce_mask = ~((1ull << tce_shift) - 1);
|
|
||||||
tlb->iova = addr & tce_mask;
|
|
||||||
tlb->translated_addr = tce & tce_mask;
|
|
||||||
tlb->addr_mask = ~tce_mask;
|
|
||||||
tlb->perm = tce & 3;
|
|
||||||
if ((is_write & !(tce & 2)) || ((!is_write) && !(tce & 1))) {
|
if ((is_write & !(tce & 2)) || ((!is_write) && !(tce & 1))) {
|
||||||
phb_error(ds->phb, "TCE access fault at 0x%"PRIx64, taddr);
|
phb_error(ds->phb, "TCE access fault at 0x%"PRIx64, taddr);
|
||||||
phb_error(ds->phb, " xlate %"PRIx64":%c TVE=%"PRIx64, addr,
|
phb_error(ds->phb, " xlate %"PRIx64":%c TVE=%"PRIx64, addr,
|
||||||
is_write ? 'W' : 'R', tve);
|
is_write ? 'W' : 'R', tve);
|
||||||
phb_error(ds->phb, " tta=%"PRIx64" lev=%d tts=%d tps=%d",
|
phb_error(ds->phb, " tta=%"PRIx64" lev=%d tts=%d tps=%d",
|
||||||
tta, lev, tts, tps);
|
tta, lev, tts, tps);
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
tce_mask = ~((1ull << tce_shift) - 1);
|
||||||
|
tlb->iova = addr & tce_mask;
|
||||||
|
tlb->translated_addr = tce & tce_mask;
|
||||||
|
tlb->addr_mask = ~tce_mask;
|
||||||
|
tlb->perm = tce & 3;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -3053,7 +3053,7 @@ static char *spapr_get_fw_dev_path(FWPathProvider *p, BusState *bus,
|
|||||||
VHostSCSICommon *vsc = CAST(VHostSCSICommon, dev, TYPE_VHOST_SCSI_COMMON);
|
VHostSCSICommon *vsc = CAST(VHostSCSICommon, dev, TYPE_VHOST_SCSI_COMMON);
|
||||||
PCIDevice *pcidev = CAST(PCIDevice, dev, TYPE_PCI_DEVICE);
|
PCIDevice *pcidev = CAST(PCIDevice, dev, TYPE_PCI_DEVICE);
|
||||||
|
|
||||||
if (d) {
|
if (d && bus) {
|
||||||
void *spapr = CAST(void, bus->parent, "spapr-vscsi");
|
void *spapr = CAST(void, bus->parent, "spapr-vscsi");
|
||||||
VirtIOSCSI *virtio = CAST(VirtIOSCSI, bus->parent, TYPE_VIRTIO_SCSI);
|
VirtIOSCSI *virtio = CAST(VirtIOSCSI, bus->parent, TYPE_VIRTIO_SCSI);
|
||||||
USBDevice *usb = CAST(USBDevice, bus->parent, TYPE_USB_DEVICE);
|
USBDevice *usb = CAST(USBDevice, bus->parent, TYPE_USB_DEVICE);
|
||||||
|
@ -37,6 +37,11 @@ static void spapr_reset_vcpu(PowerPCCPU *cpu)
|
|||||||
|
|
||||||
cpu_reset(cs);
|
cpu_reset(cs);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* "PowerPC Processor binding to IEEE 1275" defines the initial MSR state
|
||||||
|
* as 32bit (MSR_SF=0) in "8.2.1. Initial Register Values".
|
||||||
|
*/
|
||||||
|
env->msr &= ~(1ULL << MSR_SF);
|
||||||
env->spr[SPR_HIOR] = 0;
|
env->spr[SPR_HIOR] = 0;
|
||||||
|
|
||||||
lpcr = env->spr[SPR_LPCR];
|
lpcr = env->spr[SPR_LPCR];
|
||||||
|
@ -88,8 +88,6 @@ void spapr_vof_reset(SpaprMachineState *spapr, void *fdt, Error **errp)
|
|||||||
spapr_cpu_set_entry_state(first_ppc_cpu, SPAPR_ENTRY_POINT,
|
spapr_cpu_set_entry_state(first_ppc_cpu, SPAPR_ENTRY_POINT,
|
||||||
stack_ptr, spapr->initrd_base,
|
stack_ptr, spapr->initrd_base,
|
||||||
spapr->initrd_size);
|
spapr->initrd_size);
|
||||||
/* VOF is 32bit BE so enforce MSR here */
|
|
||||||
first_ppc_cpu->env.msr &= ~((1ULL << MSR_SF) | (1ULL << MSR_LE));
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* At this point the expected allocation map is:
|
* At this point the expected allocation map is:
|
||||||
|
@ -16,7 +16,6 @@
|
|||||||
#include "qemu/units.h"
|
#include "qemu/units.h"
|
||||||
#include "qemu/log.h"
|
#include "qemu/log.h"
|
||||||
#include "qapi/error.h"
|
#include "qapi/error.h"
|
||||||
#include "exec/ram_addr.h"
|
|
||||||
#include "exec/address-spaces.h"
|
#include "exec/address-spaces.h"
|
||||||
#include "hw/ppc/vof.h"
|
#include "hw/ppc/vof.h"
|
||||||
#include "hw/ppc/fdt.h"
|
#include "hw/ppc/fdt.h"
|
||||||
|
@ -6,6 +6,11 @@
|
|||||||
#ifndef HW_VOF_H
|
#ifndef HW_VOF_H
|
||||||
#define HW_VOF_H
|
#define HW_VOF_H
|
||||||
|
|
||||||
|
#include "qom/object.h"
|
||||||
|
#include "exec/address-spaces.h"
|
||||||
|
#include "exec/memory.h"
|
||||||
|
#include "cpu.h"
|
||||||
|
|
||||||
typedef struct Vof {
|
typedef struct Vof {
|
||||||
uint64_t top_addr; /* copied from rma_size */
|
uint64_t top_addr; /* copied from rma_size */
|
||||||
GArray *claimed; /* array of SpaprOfClaimed */
|
GArray *claimed; /* array of SpaprOfClaimed */
|
||||||
|
@ -428,8 +428,6 @@
|
|||||||
"PowerPC 601v1")
|
"PowerPC 601v1")
|
||||||
POWERPC_DEF("601_v2", CPU_POWERPC_601_v2, 601v,
|
POWERPC_DEF("601_v2", CPU_POWERPC_601_v2, 601v,
|
||||||
"PowerPC 601v2")
|
"PowerPC 601v2")
|
||||||
POWERPC_DEF("602", CPU_POWERPC_602, 602,
|
|
||||||
"PowerPC 602")
|
|
||||||
POWERPC_DEF("603", CPU_POWERPC_603, 603,
|
POWERPC_DEF("603", CPU_POWERPC_603, 603,
|
||||||
"PowerPC 603")
|
"PowerPC 603")
|
||||||
POWERPC_DEF("603e_v1.1", CPU_POWERPC_603E_v11, 603E,
|
POWERPC_DEF("603e_v1.1", CPU_POWERPC_603E_v11, 603E,
|
||||||
|
@ -208,7 +208,6 @@ enum {
|
|||||||
CPU_POWERPC_601_v0 = 0x00010001,
|
CPU_POWERPC_601_v0 = 0x00010001,
|
||||||
CPU_POWERPC_601_v1 = 0x00010001,
|
CPU_POWERPC_601_v1 = 0x00010001,
|
||||||
CPU_POWERPC_601_v2 = 0x00010002,
|
CPU_POWERPC_601_v2 = 0x00010002,
|
||||||
CPU_POWERPC_602 = 0x00050100,
|
|
||||||
CPU_POWERPC_603 = 0x00030100,
|
CPU_POWERPC_603 = 0x00030100,
|
||||||
CPU_POWERPC_603E_v11 = 0x00060101,
|
CPU_POWERPC_603E_v11 = 0x00060101,
|
||||||
CPU_POWERPC_603E_v12 = 0x00060102,
|
CPU_POWERPC_603E_v12 = 0x00060102,
|
||||||
|
@ -321,12 +321,11 @@ typedef enum {
|
|||||||
#define MSR_UCLE 26 /* User-mode cache lock enable for BookE */
|
#define MSR_UCLE 26 /* User-mode cache lock enable for BookE */
|
||||||
#define MSR_VR 25 /* altivec available x hflags */
|
#define MSR_VR 25 /* altivec available x hflags */
|
||||||
#define MSR_SPE 25 /* SPE enable for BookE x hflags */
|
#define MSR_SPE 25 /* SPE enable for BookE x hflags */
|
||||||
#define MSR_AP 23 /* Access privilege state on 602 hflags */
|
|
||||||
#define MSR_VSX 23 /* Vector Scalar Extension (ISA 2.06 and later) x hflags */
|
#define MSR_VSX 23 /* Vector Scalar Extension (ISA 2.06 and later) x hflags */
|
||||||
#define MSR_SA 22 /* Supervisor access mode on 602 hflags */
|
|
||||||
#define MSR_S 22 /* Secure state */
|
#define MSR_S 22 /* Secure state */
|
||||||
#define MSR_KEY 19 /* key bit on 603e */
|
#define MSR_KEY 19 /* key bit on 603e */
|
||||||
#define MSR_POW 18 /* Power management */
|
#define MSR_POW 18 /* Power management */
|
||||||
|
#define MSR_WE 18 /* Wait State Enable on 405 */
|
||||||
#define MSR_TGPR 17 /* TGPR usage on 602/603 x */
|
#define MSR_TGPR 17 /* TGPR usage on 602/603 x */
|
||||||
#define MSR_CE 17 /* Critical interrupt enable on embedded PowerPC x */
|
#define MSR_CE 17 /* Critical interrupt enable on embedded PowerPC x */
|
||||||
#define MSR_ILE 16 /* Interrupt little-endian mode */
|
#define MSR_ILE 16 /* Interrupt little-endian mode */
|
||||||
@ -476,9 +475,7 @@ typedef enum {
|
|||||||
#define msr_ucle ((env->msr >> MSR_UCLE) & 1)
|
#define msr_ucle ((env->msr >> MSR_UCLE) & 1)
|
||||||
#define msr_vr ((env->msr >> MSR_VR) & 1)
|
#define msr_vr ((env->msr >> MSR_VR) & 1)
|
||||||
#define msr_spe ((env->msr >> MSR_SPE) & 1)
|
#define msr_spe ((env->msr >> MSR_SPE) & 1)
|
||||||
#define msr_ap ((env->msr >> MSR_AP) & 1)
|
|
||||||
#define msr_vsx ((env->msr >> MSR_VSX) & 1)
|
#define msr_vsx ((env->msr >> MSR_VSX) & 1)
|
||||||
#define msr_sa ((env->msr >> MSR_SA) & 1)
|
|
||||||
#define msr_key ((env->msr >> MSR_KEY) & 1)
|
#define msr_key ((env->msr >> MSR_KEY) & 1)
|
||||||
#define msr_pow ((env->msr >> MSR_POW) & 1)
|
#define msr_pow ((env->msr >> MSR_POW) & 1)
|
||||||
#define msr_tgpr ((env->msr >> MSR_TGPR) & 1)
|
#define msr_tgpr ((env->msr >> MSR_TGPR) & 1)
|
||||||
@ -2141,8 +2138,6 @@ enum {
|
|||||||
PPC_MFTB = 0x0000000000000200ULL,
|
PPC_MFTB = 0x0000000000000200ULL,
|
||||||
|
|
||||||
/* Fixed-point unit extensions */
|
/* Fixed-point unit extensions */
|
||||||
/* PowerPC 602 specific */
|
|
||||||
PPC_602_SPEC = 0x0000000000000400ULL,
|
|
||||||
/* isel instruction */
|
/* isel instruction */
|
||||||
PPC_ISEL = 0x0000000000000800ULL,
|
PPC_ISEL = 0x0000000000000800ULL,
|
||||||
/* popcntb instruction */
|
/* popcntb instruction */
|
||||||
@ -2244,7 +2239,7 @@ enum {
|
|||||||
#define PPC_TCG_INSNS (PPC_INSNS_BASE | PPC_POWER | PPC_POWER2 \
|
#define PPC_TCG_INSNS (PPC_INSNS_BASE | PPC_POWER | PPC_POWER2 \
|
||||||
| PPC_POWER_RTC | PPC_POWER_BR | PPC_64B \
|
| PPC_POWER_RTC | PPC_POWER_BR | PPC_64B \
|
||||||
| PPC_64BX | PPC_64H | PPC_WAIT | PPC_MFTB \
|
| PPC_64BX | PPC_64H | PPC_WAIT | PPC_MFTB \
|
||||||
| PPC_602_SPEC | PPC_ISEL | PPC_POPCNTB \
|
| PPC_ISEL | PPC_POPCNTB \
|
||||||
| PPC_STRING | PPC_FLOAT | PPC_FLOAT_EXT \
|
| PPC_STRING | PPC_FLOAT | PPC_FLOAT_EXT \
|
||||||
| PPC_FLOAT_FSQRT | PPC_FLOAT_FRES \
|
| PPC_FLOAT_FSQRT | PPC_FLOAT_FRES \
|
||||||
| PPC_FLOAT_FRSQRTE | PPC_FLOAT_FRSQRTES \
|
| PPC_FLOAT_FRSQRTE | PPC_FLOAT_FRSQRTES \
|
||||||
|
@ -749,54 +749,6 @@ static void register_G2_sprs(CPUPPCState *env)
|
|||||||
0x00000000);
|
0x00000000);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* SPR specific to PowerPC 602 implementation */
|
|
||||||
static void register_602_sprs(CPUPPCState *env)
|
|
||||||
{
|
|
||||||
/* ESA registers */
|
|
||||||
/* XXX : not implemented */
|
|
||||||
spr_register(env, SPR_SER, "SER",
|
|
||||||
SPR_NOACCESS, SPR_NOACCESS,
|
|
||||||
&spr_read_generic, &spr_write_generic,
|
|
||||||
0x00000000);
|
|
||||||
/* XXX : not implemented */
|
|
||||||
spr_register(env, SPR_SEBR, "SEBR",
|
|
||||||
SPR_NOACCESS, SPR_NOACCESS,
|
|
||||||
&spr_read_generic, &spr_write_generic,
|
|
||||||
0x00000000);
|
|
||||||
/* XXX : not implemented */
|
|
||||||
spr_register(env, SPR_ESASRR, "ESASRR",
|
|
||||||
SPR_NOACCESS, SPR_NOACCESS,
|
|
||||||
&spr_read_generic, &spr_write_generic,
|
|
||||||
0x00000000);
|
|
||||||
/* Floating point status */
|
|
||||||
/* XXX : not implemented */
|
|
||||||
spr_register(env, SPR_SP, "SP",
|
|
||||||
SPR_NOACCESS, SPR_NOACCESS,
|
|
||||||
&spr_read_generic, &spr_write_generic,
|
|
||||||
0x00000000);
|
|
||||||
/* XXX : not implemented */
|
|
||||||
spr_register(env, SPR_LT, "LT",
|
|
||||||
SPR_NOACCESS, SPR_NOACCESS,
|
|
||||||
&spr_read_generic, &spr_write_generic,
|
|
||||||
0x00000000);
|
|
||||||
/* Watchdog timer */
|
|
||||||
/* XXX : not implemented */
|
|
||||||
spr_register(env, SPR_TCR, "TCR",
|
|
||||||
SPR_NOACCESS, SPR_NOACCESS,
|
|
||||||
&spr_read_generic, &spr_write_generic,
|
|
||||||
0x00000000);
|
|
||||||
/* Interrupt base */
|
|
||||||
spr_register(env, SPR_IBR, "IBR",
|
|
||||||
SPR_NOACCESS, SPR_NOACCESS,
|
|
||||||
&spr_read_generic, &spr_write_generic,
|
|
||||||
0x00000000);
|
|
||||||
/* XXX : not implemented */
|
|
||||||
spr_register(env, SPR_IABR, "IABR",
|
|
||||||
SPR_NOACCESS, SPR_NOACCESS,
|
|
||||||
&spr_read_generic, &spr_write_generic,
|
|
||||||
0x00000000);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* SPR specific to PowerPC 601 implementation */
|
/* SPR specific to PowerPC 601 implementation */
|
||||||
static void register_601_sprs(CPUPPCState *env)
|
static void register_601_sprs(CPUPPCState *env)
|
||||||
{
|
{
|
||||||
@ -2128,33 +2080,6 @@ static void init_excp_601(CPUPPCState *env)
|
|||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
static void init_excp_602(CPUPPCState *env)
|
|
||||||
{
|
|
||||||
#if !defined(CONFIG_USER_ONLY)
|
|
||||||
/* XXX: exception prefix has a special behavior on 602 */
|
|
||||||
env->excp_vectors[POWERPC_EXCP_RESET] = 0x00000100;
|
|
||||||
env->excp_vectors[POWERPC_EXCP_MCHECK] = 0x00000200;
|
|
||||||
env->excp_vectors[POWERPC_EXCP_DSI] = 0x00000300;
|
|
||||||
env->excp_vectors[POWERPC_EXCP_ISI] = 0x00000400;
|
|
||||||
env->excp_vectors[POWERPC_EXCP_EXTERNAL] = 0x00000500;
|
|
||||||
env->excp_vectors[POWERPC_EXCP_ALIGN] = 0x00000600;
|
|
||||||
env->excp_vectors[POWERPC_EXCP_PROGRAM] = 0x00000700;
|
|
||||||
env->excp_vectors[POWERPC_EXCP_FPU] = 0x00000800;
|
|
||||||
env->excp_vectors[POWERPC_EXCP_DECR] = 0x00000900;
|
|
||||||
env->excp_vectors[POWERPC_EXCP_SYSCALL] = 0x00000C00;
|
|
||||||
env->excp_vectors[POWERPC_EXCP_TRACE] = 0x00000D00;
|
|
||||||
env->excp_vectors[POWERPC_EXCP_IFTLB] = 0x00001000;
|
|
||||||
env->excp_vectors[POWERPC_EXCP_DLTLB] = 0x00001100;
|
|
||||||
env->excp_vectors[POWERPC_EXCP_DSTLB] = 0x00001200;
|
|
||||||
env->excp_vectors[POWERPC_EXCP_IABR] = 0x00001300;
|
|
||||||
env->excp_vectors[POWERPC_EXCP_SMI] = 0x00001400;
|
|
||||||
env->excp_vectors[POWERPC_EXCP_WDT] = 0x00001500;
|
|
||||||
env->excp_vectors[POWERPC_EXCP_EMUL] = 0x00001600;
|
|
||||||
/* Hardware reset vector */
|
|
||||||
env->hreset_vector = 0x00000100UL;
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
static void init_excp_603(CPUPPCState *env)
|
static void init_excp_603(CPUPPCState *env)
|
||||||
{
|
{
|
||||||
#if !defined(CONFIG_USER_ONLY)
|
#if !defined(CONFIG_USER_ONLY)
|
||||||
@ -2535,11 +2460,12 @@ POWERPC_FAMILY(405)(ObjectClass *oc, void *data)
|
|||||||
PPC_MEM_SYNC | PPC_MEM_EIEIO |
|
PPC_MEM_SYNC | PPC_MEM_EIEIO |
|
||||||
PPC_40x_TLB | PPC_MEM_TLBIA | PPC_MEM_TLBSYNC |
|
PPC_40x_TLB | PPC_MEM_TLBIA | PPC_MEM_TLBSYNC |
|
||||||
PPC_4xx_COMMON | PPC_405_MAC | PPC_40x_EXCP;
|
PPC_4xx_COMMON | PPC_405_MAC | PPC_40x_EXCP;
|
||||||
pcc->msr_mask = (1ull << MSR_POW) |
|
pcc->msr_mask = (1ull << MSR_WE) |
|
||||||
(1ull << MSR_CE) |
|
(1ull << MSR_CE) |
|
||||||
(1ull << MSR_EE) |
|
(1ull << MSR_EE) |
|
||||||
(1ull << MSR_PR) |
|
(1ull << MSR_PR) |
|
||||||
(1ull << MSR_FP) |
|
(1ull << MSR_FP) |
|
||||||
|
(1ull << MSR_ME) |
|
||||||
(1ull << MSR_DWE) |
|
(1ull << MSR_DWE) |
|
||||||
(1ull << MSR_DE) |
|
(1ull << MSR_DE) |
|
||||||
(1ull << MSR_IR) |
|
(1ull << MSR_IR) |
|
||||||
@ -4080,76 +4006,6 @@ POWERPC_FAMILY(601v)(ObjectClass *oc, void *data)
|
|||||||
pcc->flags = POWERPC_FLAG_SE | POWERPC_FLAG_RTC_CLK | POWERPC_FLAG_HID0_LE;
|
pcc->flags = POWERPC_FLAG_SE | POWERPC_FLAG_RTC_CLK | POWERPC_FLAG_HID0_LE;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void init_proc_602(CPUPPCState *env)
|
|
||||||
{
|
|
||||||
register_ne_601_sprs(env);
|
|
||||||
register_sdr1_sprs(env);
|
|
||||||
register_602_sprs(env);
|
|
||||||
/* Time base */
|
|
||||||
register_tbl(env);
|
|
||||||
/* hardware implementation registers */
|
|
||||||
/* XXX : not implemented */
|
|
||||||
spr_register(env, SPR_HID0, "HID0",
|
|
||||||
SPR_NOACCESS, SPR_NOACCESS,
|
|
||||||
&spr_read_generic, &spr_write_generic,
|
|
||||||
0x00000000);
|
|
||||||
/* XXX : not implemented */
|
|
||||||
spr_register(env, SPR_HID1, "HID1",
|
|
||||||
SPR_NOACCESS, SPR_NOACCESS,
|
|
||||||
&spr_read_generic, &spr_write_generic,
|
|
||||||
0x00000000);
|
|
||||||
/* Memory management */
|
|
||||||
register_low_BATs(env);
|
|
||||||
register_6xx_7xx_soft_tlb(env, 64, 2);
|
|
||||||
init_excp_602(env);
|
|
||||||
env->dcache_line_size = 32;
|
|
||||||
env->icache_line_size = 32;
|
|
||||||
/* Allocate hardware IRQ controller */
|
|
||||||
ppc6xx_irq_init(env_archcpu(env));
|
|
||||||
}
|
|
||||||
|
|
||||||
POWERPC_FAMILY(602)(ObjectClass *oc, void *data)
|
|
||||||
{
|
|
||||||
DeviceClass *dc = DEVICE_CLASS(oc);
|
|
||||||
PowerPCCPUClass *pcc = POWERPC_CPU_CLASS(oc);
|
|
||||||
|
|
||||||
dc->desc = "PowerPC 602";
|
|
||||||
pcc->init_proc = init_proc_602;
|
|
||||||
pcc->check_pow = check_pow_hid0;
|
|
||||||
pcc->insns_flags = PPC_INSNS_BASE | PPC_STRING | PPC_MFTB |
|
|
||||||
PPC_FLOAT | PPC_FLOAT_FSEL | PPC_FLOAT_FRES |
|
|
||||||
PPC_FLOAT_FRSQRTE | PPC_FLOAT_STFIWX |
|
|
||||||
PPC_CACHE | PPC_CACHE_ICBI | PPC_CACHE_DCBZ |
|
|
||||||
PPC_MEM_SYNC | PPC_MEM_EIEIO |
|
|
||||||
PPC_MEM_TLBIE | PPC_6xx_TLB | PPC_MEM_TLBSYNC |
|
|
||||||
PPC_SEGMENT | PPC_602_SPEC;
|
|
||||||
pcc->msr_mask = (1ull << MSR_VSX) |
|
|
||||||
(1ull << MSR_SA) |
|
|
||||||
(1ull << MSR_POW) |
|
|
||||||
(1ull << MSR_TGPR) |
|
|
||||||
(1ull << MSR_ILE) |
|
|
||||||
(1ull << MSR_EE) |
|
|
||||||
(1ull << MSR_PR) |
|
|
||||||
(1ull << MSR_FP) |
|
|
||||||
(1ull << MSR_ME) |
|
|
||||||
(1ull << MSR_FE0) |
|
|
||||||
(1ull << MSR_SE) |
|
|
||||||
(1ull << MSR_DE) |
|
|
||||||
(1ull << MSR_FE1) |
|
|
||||||
(1ull << MSR_EP) |
|
|
||||||
(1ull << MSR_IR) |
|
|
||||||
(1ull << MSR_DR) |
|
|
||||||
(1ull << MSR_RI) |
|
|
||||||
(1ull << MSR_LE);
|
|
||||||
/* XXX: 602 MMU is quite specific. Should add a special case */
|
|
||||||
pcc->mmu_model = POWERPC_MMU_SOFT_6xx;
|
|
||||||
pcc->excp_model = POWERPC_EXCP_602;
|
|
||||||
pcc->bus_model = PPC_FLAGS_INPUT_6xx;
|
|
||||||
pcc->bfd_mach = bfd_mach_ppc_602;
|
|
||||||
pcc->flags = POWERPC_FLAG_TGPR | POWERPC_FLAG_SE |
|
|
||||||
POWERPC_FLAG_BE | POWERPC_FLAG_BUS_CLK;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void init_proc_603(CPUPPCState *env)
|
static void init_proc_603(CPUPPCState *env)
|
||||||
{
|
{
|
||||||
register_ne_601_sprs(env);
|
register_ne_601_sprs(env);
|
||||||
@ -8270,8 +8126,6 @@ static void ppc_cpu_reset(DeviceState *dev)
|
|||||||
|
|
||||||
msr = (target_ulong)0;
|
msr = (target_ulong)0;
|
||||||
msr |= (target_ulong)MSR_HVB;
|
msr |= (target_ulong)MSR_HVB;
|
||||||
msr |= (target_ulong)0 << MSR_AP; /* TO BE CHECKED */
|
|
||||||
msr |= (target_ulong)0 << MSR_SA; /* TO BE CHECKED */
|
|
||||||
msr |= (target_ulong)1 << MSR_EP;
|
msr |= (target_ulong)1 << MSR_EP;
|
||||||
#if defined(DO_SINGLE_STEP) && 0
|
#if defined(DO_SINGLE_STEP) && 0
|
||||||
/* Single step trace mode */
|
/* Single step trace mode */
|
||||||
|
@ -392,6 +392,660 @@ static void powerpc_set_excp_state(PowerPCCPU *cpu,
|
|||||||
check_tlb_flush(env, false);
|
check_tlb_flush(env, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void powerpc_excp_40x(PowerPCCPU *cpu, int excp)
|
||||||
|
{
|
||||||
|
CPUState *cs = CPU(cpu);
|
||||||
|
CPUPPCState *env = &cpu->env;
|
||||||
|
target_ulong msr, new_msr, vector;
|
||||||
|
int srr0, srr1;
|
||||||
|
|
||||||
|
if (excp <= POWERPC_EXCP_NONE || excp >= POWERPC_EXCP_NB) {
|
||||||
|
cpu_abort(cs, "Invalid PowerPC exception %d. Aborting\n", excp);
|
||||||
|
}
|
||||||
|
|
||||||
|
qemu_log_mask(CPU_LOG_INT, "Raise exception at " TARGET_FMT_lx
|
||||||
|
" => %s (%d) error=%02x\n", env->nip, powerpc_excp_name(excp),
|
||||||
|
excp, env->error_code);
|
||||||
|
|
||||||
|
/* new srr1 value excluding must-be-zero bits */
|
||||||
|
msr = env->msr & ~0x783f0000ULL;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* new interrupt handler msr preserves existing ME unless
|
||||||
|
* explicitly overriden.
|
||||||
|
*/
|
||||||
|
new_msr = env->msr & (((target_ulong)1 << MSR_ME));
|
||||||
|
|
||||||
|
/* target registers */
|
||||||
|
srr0 = SPR_SRR0;
|
||||||
|
srr1 = SPR_SRR1;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Hypervisor emulation assistance interrupt only exists on server
|
||||||
|
* arch 2.05 server or later.
|
||||||
|
*/
|
||||||
|
if (excp == POWERPC_EXCP_HV_EMU) {
|
||||||
|
excp = POWERPC_EXCP_PROGRAM;
|
||||||
|
}
|
||||||
|
|
||||||
|
vector = env->excp_vectors[excp];
|
||||||
|
if (vector == (target_ulong)-1ULL) {
|
||||||
|
cpu_abort(cs, "Raised an exception without defined vector %d\n",
|
||||||
|
excp);
|
||||||
|
}
|
||||||
|
|
||||||
|
vector |= env->excp_prefix;
|
||||||
|
|
||||||
|
switch (excp) {
|
||||||
|
case POWERPC_EXCP_CRITICAL: /* Critical input */
|
||||||
|
srr0 = SPR_40x_SRR2;
|
||||||
|
srr1 = SPR_40x_SRR3;
|
||||||
|
break;
|
||||||
|
case POWERPC_EXCP_MCHECK: /* Machine check exception */
|
||||||
|
if (msr_me == 0) {
|
||||||
|
/*
|
||||||
|
* Machine check exception is not enabled. Enter
|
||||||
|
* checkstop state.
|
||||||
|
*/
|
||||||
|
fprintf(stderr, "Machine check while not allowed. "
|
||||||
|
"Entering checkstop state\n");
|
||||||
|
if (qemu_log_separate()) {
|
||||||
|
qemu_log("Machine check while not allowed. "
|
||||||
|
"Entering checkstop state\n");
|
||||||
|
}
|
||||||
|
cs->halted = 1;
|
||||||
|
cpu_interrupt_exittb(cs);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* machine check exceptions don't have ME set */
|
||||||
|
new_msr &= ~((target_ulong)1 << MSR_ME);
|
||||||
|
|
||||||
|
srr0 = SPR_40x_SRR2;
|
||||||
|
srr1 = SPR_40x_SRR3;
|
||||||
|
break;
|
||||||
|
case POWERPC_EXCP_DSI: /* Data storage exception */
|
||||||
|
trace_ppc_excp_dsi(env->spr[SPR_40x_ESR], env->spr[SPR_40x_DEAR]);
|
||||||
|
break;
|
||||||
|
case POWERPC_EXCP_ISI: /* Instruction storage exception */
|
||||||
|
trace_ppc_excp_isi(msr, env->nip);
|
||||||
|
break;
|
||||||
|
case POWERPC_EXCP_EXTERNAL: /* External input */
|
||||||
|
break;
|
||||||
|
case POWERPC_EXCP_ALIGN: /* Alignment exception */
|
||||||
|
break;
|
||||||
|
case POWERPC_EXCP_PROGRAM: /* Program exception */
|
||||||
|
switch (env->error_code & ~0xF) {
|
||||||
|
case POWERPC_EXCP_FP:
|
||||||
|
if ((msr_fe0 == 0 && msr_fe1 == 0) || msr_fp == 0) {
|
||||||
|
trace_ppc_excp_fp_ignore();
|
||||||
|
cs->exception_index = POWERPC_EXCP_NONE;
|
||||||
|
env->error_code = 0;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
env->spr[SPR_40x_ESR] = ESR_FP;
|
||||||
|
break;
|
||||||
|
case POWERPC_EXCP_INVAL:
|
||||||
|
trace_ppc_excp_inval(env->nip);
|
||||||
|
env->spr[SPR_40x_ESR] = ESR_PIL;
|
||||||
|
break;
|
||||||
|
case POWERPC_EXCP_PRIV:
|
||||||
|
env->spr[SPR_40x_ESR] = ESR_PPR;
|
||||||
|
break;
|
||||||
|
case POWERPC_EXCP_TRAP:
|
||||||
|
env->spr[SPR_40x_ESR] = ESR_PTR;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
cpu_abort(cs, "Invalid program exception %d. Aborting\n",
|
||||||
|
env->error_code);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case POWERPC_EXCP_SYSCALL: /* System call exception */
|
||||||
|
dump_syscall(env);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* We need to correct the NIP which in this case is supposed
|
||||||
|
* to point to the next instruction
|
||||||
|
*/
|
||||||
|
env->nip += 4;
|
||||||
|
break;
|
||||||
|
case POWERPC_EXCP_FIT: /* Fixed-interval timer interrupt */
|
||||||
|
trace_ppc_excp_print("FIT");
|
||||||
|
break;
|
||||||
|
case POWERPC_EXCP_WDT: /* Watchdog timer interrupt */
|
||||||
|
trace_ppc_excp_print("WDT");
|
||||||
|
break;
|
||||||
|
case POWERPC_EXCP_DTLB: /* Data TLB error */
|
||||||
|
case POWERPC_EXCP_ITLB: /* Instruction TLB error */
|
||||||
|
break;
|
||||||
|
case POWERPC_EXCP_PIT: /* Programmable interval timer interrupt */
|
||||||
|
trace_ppc_excp_print("PIT");
|
||||||
|
break;
|
||||||
|
case POWERPC_EXCP_DEBUG: /* Debug interrupt */
|
||||||
|
cpu_abort(cs, "%s exception not implemented\n",
|
||||||
|
powerpc_excp_name(excp));
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
cpu_abort(cs, "Invalid PowerPC exception %d. Aborting\n", excp);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Sanity check */
|
||||||
|
if (!(env->msr_mask & MSR_HVB)) {
|
||||||
|
if (new_msr & MSR_HVB) {
|
||||||
|
cpu_abort(cs, "Trying to deliver HV exception (MSR) %d with "
|
||||||
|
"no HV support\n", excp);
|
||||||
|
}
|
||||||
|
if (srr0 == SPR_HSRR0) {
|
||||||
|
cpu_abort(cs, "Trying to deliver HV exception (HSRR) %d with "
|
||||||
|
"no HV support\n", excp);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Save PC */
|
||||||
|
env->spr[srr0] = env->nip;
|
||||||
|
|
||||||
|
/* Save MSR */
|
||||||
|
env->spr[srr1] = msr;
|
||||||
|
|
||||||
|
powerpc_set_excp_state(cpu, vector, new_msr);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void powerpc_excp_74xx(PowerPCCPU *cpu, int excp)
|
||||||
|
{
|
||||||
|
CPUState *cs = CPU(cpu);
|
||||||
|
CPUPPCState *env = &cpu->env;
|
||||||
|
target_ulong msr, new_msr, vector;
|
||||||
|
|
||||||
|
if (excp <= POWERPC_EXCP_NONE || excp >= POWERPC_EXCP_NB) {
|
||||||
|
cpu_abort(cs, "Invalid PowerPC exception %d. Aborting\n", excp);
|
||||||
|
}
|
||||||
|
|
||||||
|
qemu_log_mask(CPU_LOG_INT, "Raise exception at " TARGET_FMT_lx
|
||||||
|
" => %s (%d) error=%02x\n", env->nip, powerpc_excp_name(excp),
|
||||||
|
excp, env->error_code);
|
||||||
|
|
||||||
|
/* new srr1 value excluding must-be-zero bits */
|
||||||
|
msr = env->msr & ~0x783f0000ULL;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* new interrupt handler msr preserves existing ME unless
|
||||||
|
* explicitly overriden
|
||||||
|
*/
|
||||||
|
new_msr = env->msr & ((target_ulong)1 << MSR_ME);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Hypervisor emulation assistance interrupt only exists on server
|
||||||
|
* arch 2.05 server or later.
|
||||||
|
*/
|
||||||
|
if (excp == POWERPC_EXCP_HV_EMU) {
|
||||||
|
excp = POWERPC_EXCP_PROGRAM;
|
||||||
|
}
|
||||||
|
|
||||||
|
vector = env->excp_vectors[excp];
|
||||||
|
if (vector == (target_ulong)-1ULL) {
|
||||||
|
cpu_abort(cs, "Raised an exception without defined vector %d\n",
|
||||||
|
excp);
|
||||||
|
}
|
||||||
|
|
||||||
|
vector |= env->excp_prefix;
|
||||||
|
|
||||||
|
switch (excp) {
|
||||||
|
case POWERPC_EXCP_MCHECK: /* Machine check exception */
|
||||||
|
if (msr_me == 0) {
|
||||||
|
/*
|
||||||
|
* Machine check exception is not enabled. Enter
|
||||||
|
* checkstop state.
|
||||||
|
*/
|
||||||
|
fprintf(stderr, "Machine check while not allowed. "
|
||||||
|
"Entering checkstop state\n");
|
||||||
|
if (qemu_log_separate()) {
|
||||||
|
qemu_log("Machine check while not allowed. "
|
||||||
|
"Entering checkstop state\n");
|
||||||
|
}
|
||||||
|
cs->halted = 1;
|
||||||
|
cpu_interrupt_exittb(cs);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* machine check exceptions don't have ME set */
|
||||||
|
new_msr &= ~((target_ulong)1 << MSR_ME);
|
||||||
|
|
||||||
|
break;
|
||||||
|
case POWERPC_EXCP_DSI: /* Data storage exception */
|
||||||
|
trace_ppc_excp_dsi(env->spr[SPR_DSISR], env->spr[SPR_DAR]);
|
||||||
|
break;
|
||||||
|
case POWERPC_EXCP_ISI: /* Instruction storage exception */
|
||||||
|
trace_ppc_excp_isi(msr, env->nip);
|
||||||
|
msr |= env->error_code;
|
||||||
|
break;
|
||||||
|
case POWERPC_EXCP_EXTERNAL: /* External input */
|
||||||
|
break;
|
||||||
|
case POWERPC_EXCP_ALIGN: /* Alignment exception */
|
||||||
|
/* Get rS/rD and rA from faulting opcode */
|
||||||
|
/*
|
||||||
|
* Note: the opcode fields will not be set properly for a
|
||||||
|
* direct store load/store, but nobody cares as nobody
|
||||||
|
* actually uses direct store segments.
|
||||||
|
*/
|
||||||
|
env->spr[SPR_DSISR] |= (env->error_code & 0x03FF0000) >> 16;
|
||||||
|
break;
|
||||||
|
case POWERPC_EXCP_PROGRAM: /* Program exception */
|
||||||
|
switch (env->error_code & ~0xF) {
|
||||||
|
case POWERPC_EXCP_FP:
|
||||||
|
if ((msr_fe0 == 0 && msr_fe1 == 0) || msr_fp == 0) {
|
||||||
|
trace_ppc_excp_fp_ignore();
|
||||||
|
cs->exception_index = POWERPC_EXCP_NONE;
|
||||||
|
env->error_code = 0;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* FP exceptions always have NIP pointing to the faulting
|
||||||
|
* instruction, so always use store_next and claim we are
|
||||||
|
* precise in the MSR.
|
||||||
|
*/
|
||||||
|
msr |= 0x00100000;
|
||||||
|
break;
|
||||||
|
case POWERPC_EXCP_INVAL:
|
||||||
|
trace_ppc_excp_inval(env->nip);
|
||||||
|
msr |= 0x00080000;
|
||||||
|
break;
|
||||||
|
case POWERPC_EXCP_PRIV:
|
||||||
|
msr |= 0x00040000;
|
||||||
|
break;
|
||||||
|
case POWERPC_EXCP_TRAP:
|
||||||
|
msr |= 0x00020000;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
/* Should never occur */
|
||||||
|
cpu_abort(cs, "Invalid program exception %d. Aborting\n",
|
||||||
|
env->error_code);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case POWERPC_EXCP_SYSCALL: /* System call exception */
|
||||||
|
{
|
||||||
|
int lev = env->error_code;
|
||||||
|
|
||||||
|
if ((lev == 1) && cpu->vhyp) {
|
||||||
|
dump_hcall(env);
|
||||||
|
} else {
|
||||||
|
dump_syscall(env);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* We need to correct the NIP which in this case is supposed
|
||||||
|
* to point to the next instruction
|
||||||
|
*/
|
||||||
|
env->nip += 4;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* The Virtual Open Firmware (VOF) relies on the 'sc 1'
|
||||||
|
* instruction to communicate with QEMU. The pegasos2 machine
|
||||||
|
* uses VOF and the 74xx CPUs, so although the 74xx don't have
|
||||||
|
* HV mode, we need to keep hypercall support.
|
||||||
|
*/
|
||||||
|
if ((lev == 1) && cpu->vhyp) {
|
||||||
|
PPCVirtualHypervisorClass *vhc =
|
||||||
|
PPC_VIRTUAL_HYPERVISOR_GET_CLASS(cpu->vhyp);
|
||||||
|
vhc->hypercall(cpu->vhyp, cpu);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case POWERPC_EXCP_FPU: /* Floating-point unavailable exception */
|
||||||
|
case POWERPC_EXCP_DECR: /* Decrementer exception */
|
||||||
|
break;
|
||||||
|
case POWERPC_EXCP_RESET: /* System reset exception */
|
||||||
|
if (msr_pow) {
|
||||||
|
cpu_abort(cs, "Trying to deliver power-saving system reset "
|
||||||
|
"exception %d with no HV support\n", excp);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case POWERPC_EXCP_TRACE: /* Trace exception */
|
||||||
|
break;
|
||||||
|
case POWERPC_EXCP_VPU: /* Vector unavailable exception */
|
||||||
|
break;
|
||||||
|
case POWERPC_EXCP_IABR: /* Instruction address breakpoint */
|
||||||
|
case POWERPC_EXCP_SMI: /* System management interrupt */
|
||||||
|
case POWERPC_EXCP_THERM: /* Thermal interrupt */
|
||||||
|
case POWERPC_EXCP_PERFM: /* Embedded performance monitor interrupt */
|
||||||
|
case POWERPC_EXCP_VPUA: /* Vector assist exception */
|
||||||
|
cpu_abort(cs, "%s exception not implemented\n",
|
||||||
|
powerpc_excp_name(excp));
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
cpu_abort(cs, "Invalid PowerPC exception %d. Aborting\n", excp);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Sanity check */
|
||||||
|
if (!(env->msr_mask & MSR_HVB)) {
|
||||||
|
if (new_msr & MSR_HVB) {
|
||||||
|
cpu_abort(cs, "Trying to deliver HV exception (MSR) %d with "
|
||||||
|
"no HV support\n", excp);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Sort out endianness of interrupt, this differs depending on the
|
||||||
|
* CPU, the HV mode, etc...
|
||||||
|
*/
|
||||||
|
if (ppc_interrupts_little_endian(cpu, !!(new_msr & MSR_HVB))) {
|
||||||
|
new_msr |= (target_ulong)1 << MSR_LE;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Save PC */
|
||||||
|
env->spr[SPR_SRR0] = env->nip;
|
||||||
|
|
||||||
|
/* Save MSR */
|
||||||
|
env->spr[SPR_SRR1] = msr;
|
||||||
|
|
||||||
|
powerpc_set_excp_state(cpu, vector, new_msr);
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef TARGET_PPC64
|
||||||
|
static void powerpc_excp_books(PowerPCCPU *cpu, int excp)
|
||||||
|
{
|
||||||
|
CPUState *cs = CPU(cpu);
|
||||||
|
CPUPPCState *env = &cpu->env;
|
||||||
|
int excp_model = env->excp_model;
|
||||||
|
target_ulong msr, new_msr, vector;
|
||||||
|
int srr0, srr1, lev = -1;
|
||||||
|
|
||||||
|
if (excp <= POWERPC_EXCP_NONE || excp >= POWERPC_EXCP_NB) {
|
||||||
|
cpu_abort(cs, "Invalid PowerPC exception %d. Aborting\n", excp);
|
||||||
|
}
|
||||||
|
|
||||||
|
qemu_log_mask(CPU_LOG_INT, "Raise exception at " TARGET_FMT_lx
|
||||||
|
" => %s (%d) error=%02x\n", env->nip, powerpc_excp_name(excp),
|
||||||
|
excp, env->error_code);
|
||||||
|
|
||||||
|
/* new srr1 value excluding must-be-zero bits */
|
||||||
|
msr = env->msr & ~0x783f0000ULL;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* new interrupt handler msr preserves existing HV and ME unless
|
||||||
|
* explicitly overriden
|
||||||
|
*/
|
||||||
|
new_msr = env->msr & (((target_ulong)1 << MSR_ME) | MSR_HVB);
|
||||||
|
|
||||||
|
/* target registers */
|
||||||
|
srr0 = SPR_SRR0;
|
||||||
|
srr1 = SPR_SRR1;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* check for special resume at 0x100 from doze/nap/sleep/winkle on
|
||||||
|
* P7/P8/P9
|
||||||
|
*/
|
||||||
|
if (env->resume_as_sreset) {
|
||||||
|
excp = powerpc_reset_wakeup(cs, env, excp, &msr);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* We don't want to generate a Hypervisor Emulation Assistance
|
||||||
|
* Interrupt if we don't have HVB in msr_mask (PAPR mode).
|
||||||
|
*/
|
||||||
|
if (excp == POWERPC_EXCP_HV_EMU && !(env->msr_mask & MSR_HVB)) {
|
||||||
|
excp = POWERPC_EXCP_PROGRAM;
|
||||||
|
}
|
||||||
|
|
||||||
|
vector = env->excp_vectors[excp];
|
||||||
|
if (vector == (target_ulong)-1ULL) {
|
||||||
|
cpu_abort(cs, "Raised an exception without defined vector %d\n",
|
||||||
|
excp);
|
||||||
|
}
|
||||||
|
|
||||||
|
vector |= env->excp_prefix;
|
||||||
|
|
||||||
|
switch (excp) {
|
||||||
|
case POWERPC_EXCP_MCHECK: /* Machine check exception */
|
||||||
|
if (msr_me == 0) {
|
||||||
|
/*
|
||||||
|
* Machine check exception is not enabled. Enter
|
||||||
|
* checkstop state.
|
||||||
|
*/
|
||||||
|
fprintf(stderr, "Machine check while not allowed. "
|
||||||
|
"Entering checkstop state\n");
|
||||||
|
if (qemu_log_separate()) {
|
||||||
|
qemu_log("Machine check while not allowed. "
|
||||||
|
"Entering checkstop state\n");
|
||||||
|
}
|
||||||
|
cs->halted = 1;
|
||||||
|
cpu_interrupt_exittb(cs);
|
||||||
|
}
|
||||||
|
if (env->msr_mask & MSR_HVB) {
|
||||||
|
/*
|
||||||
|
* ISA specifies HV, but can be delivered to guest with HV
|
||||||
|
* clear (e.g., see FWNMI in PAPR).
|
||||||
|
*/
|
||||||
|
new_msr |= (target_ulong)MSR_HVB;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* machine check exceptions don't have ME set */
|
||||||
|
new_msr &= ~((target_ulong)1 << MSR_ME);
|
||||||
|
|
||||||
|
break;
|
||||||
|
case POWERPC_EXCP_DSI: /* Data storage exception */
|
||||||
|
trace_ppc_excp_dsi(env->spr[SPR_DSISR], env->spr[SPR_DAR]);
|
||||||
|
break;
|
||||||
|
case POWERPC_EXCP_ISI: /* Instruction storage exception */
|
||||||
|
trace_ppc_excp_isi(msr, env->nip);
|
||||||
|
msr |= env->error_code;
|
||||||
|
break;
|
||||||
|
case POWERPC_EXCP_EXTERNAL: /* External input */
|
||||||
|
{
|
||||||
|
bool lpes0;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* LPES0 is only taken into consideration if we support HV
|
||||||
|
* mode for this CPU.
|
||||||
|
*/
|
||||||
|
if (!env->has_hv_mode) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
lpes0 = !!(env->spr[SPR_LPCR] & LPCR_LPES0);
|
||||||
|
|
||||||
|
if (!lpes0) {
|
||||||
|
new_msr |= (target_ulong)MSR_HVB;
|
||||||
|
new_msr |= env->msr & ((target_ulong)1 << MSR_RI);
|
||||||
|
srr0 = SPR_HSRR0;
|
||||||
|
srr1 = SPR_HSRR1;
|
||||||
|
}
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case POWERPC_EXCP_ALIGN: /* Alignment exception */
|
||||||
|
/* Get rS/rD and rA from faulting opcode */
|
||||||
|
/*
|
||||||
|
* Note: the opcode fields will not be set properly for a
|
||||||
|
* direct store load/store, but nobody cares as nobody
|
||||||
|
* actually uses direct store segments.
|
||||||
|
*/
|
||||||
|
env->spr[SPR_DSISR] |= (env->error_code & 0x03FF0000) >> 16;
|
||||||
|
break;
|
||||||
|
case POWERPC_EXCP_PROGRAM: /* Program exception */
|
||||||
|
switch (env->error_code & ~0xF) {
|
||||||
|
case POWERPC_EXCP_FP:
|
||||||
|
if ((msr_fe0 == 0 && msr_fe1 == 0) || msr_fp == 0) {
|
||||||
|
trace_ppc_excp_fp_ignore();
|
||||||
|
cs->exception_index = POWERPC_EXCP_NONE;
|
||||||
|
env->error_code = 0;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* FP exceptions always have NIP pointing to the faulting
|
||||||
|
* instruction, so always use store_next and claim we are
|
||||||
|
* precise in the MSR.
|
||||||
|
*/
|
||||||
|
msr |= 0x00100000;
|
||||||
|
break;
|
||||||
|
case POWERPC_EXCP_INVAL:
|
||||||
|
trace_ppc_excp_inval(env->nip);
|
||||||
|
msr |= 0x00080000;
|
||||||
|
break;
|
||||||
|
case POWERPC_EXCP_PRIV:
|
||||||
|
msr |= 0x00040000;
|
||||||
|
break;
|
||||||
|
case POWERPC_EXCP_TRAP:
|
||||||
|
msr |= 0x00020000;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
/* Should never occur */
|
||||||
|
cpu_abort(cs, "Invalid program exception %d. Aborting\n",
|
||||||
|
env->error_code);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case POWERPC_EXCP_SYSCALL: /* System call exception */
|
||||||
|
lev = env->error_code;
|
||||||
|
|
||||||
|
if ((lev == 1) && cpu->vhyp) {
|
||||||
|
dump_hcall(env);
|
||||||
|
} else {
|
||||||
|
dump_syscall(env);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* We need to correct the NIP which in this case is supposed
|
||||||
|
* to point to the next instruction
|
||||||
|
*/
|
||||||
|
env->nip += 4;
|
||||||
|
|
||||||
|
/* "PAPR mode" built-in hypercall emulation */
|
||||||
|
if ((lev == 1) && cpu->vhyp) {
|
||||||
|
PPCVirtualHypervisorClass *vhc =
|
||||||
|
PPC_VIRTUAL_HYPERVISOR_GET_CLASS(cpu->vhyp);
|
||||||
|
vhc->hypercall(cpu->vhyp, cpu);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (lev == 1) {
|
||||||
|
new_msr |= (target_ulong)MSR_HVB;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case POWERPC_EXCP_SYSCALL_VECTORED: /* scv exception */
|
||||||
|
lev = env->error_code;
|
||||||
|
dump_syscall(env);
|
||||||
|
env->nip += 4;
|
||||||
|
new_msr |= env->msr & ((target_ulong)1 << MSR_EE);
|
||||||
|
new_msr |= env->msr & ((target_ulong)1 << MSR_RI);
|
||||||
|
|
||||||
|
vector += lev * 0x20;
|
||||||
|
|
||||||
|
env->lr = env->nip;
|
||||||
|
env->ctr = msr;
|
||||||
|
break;
|
||||||
|
case POWERPC_EXCP_FPU: /* Floating-point unavailable exception */
|
||||||
|
case POWERPC_EXCP_DECR: /* Decrementer exception */
|
||||||
|
break;
|
||||||
|
case POWERPC_EXCP_RESET: /* System reset exception */
|
||||||
|
/* A power-saving exception sets ME, otherwise it is unchanged */
|
||||||
|
if (msr_pow) {
|
||||||
|
/* indicate that we resumed from power save mode */
|
||||||
|
msr |= 0x10000;
|
||||||
|
new_msr |= ((target_ulong)1 << MSR_ME);
|
||||||
|
}
|
||||||
|
if (env->msr_mask & MSR_HVB) {
|
||||||
|
/*
|
||||||
|
* ISA specifies HV, but can be delivered to guest with HV
|
||||||
|
* clear (e.g., see FWNMI in PAPR, NMI injection in QEMU).
|
||||||
|
*/
|
||||||
|
new_msr |= (target_ulong)MSR_HVB;
|
||||||
|
} else {
|
||||||
|
if (msr_pow) {
|
||||||
|
cpu_abort(cs, "Trying to deliver power-saving system reset "
|
||||||
|
"exception %d with no HV support\n", excp);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case POWERPC_EXCP_DSEG: /* Data segment exception */
|
||||||
|
case POWERPC_EXCP_ISEG: /* Instruction segment exception */
|
||||||
|
case POWERPC_EXCP_TRACE: /* Trace exception */
|
||||||
|
break;
|
||||||
|
case POWERPC_EXCP_HISI: /* Hypervisor instruction storage exception */
|
||||||
|
msr |= env->error_code;
|
||||||
|
/* fall through */
|
||||||
|
case POWERPC_EXCP_HDECR: /* Hypervisor decrementer exception */
|
||||||
|
case POWERPC_EXCP_HDSI: /* Hypervisor data storage exception */
|
||||||
|
case POWERPC_EXCP_SDOOR_HV: /* Hypervisor Doorbell interrupt */
|
||||||
|
case POWERPC_EXCP_HV_EMU:
|
||||||
|
case POWERPC_EXCP_HVIRT: /* Hypervisor virtualization */
|
||||||
|
srr0 = SPR_HSRR0;
|
||||||
|
srr1 = SPR_HSRR1;
|
||||||
|
new_msr |= (target_ulong)MSR_HVB;
|
||||||
|
new_msr |= env->msr & ((target_ulong)1 << MSR_RI);
|
||||||
|
break;
|
||||||
|
case POWERPC_EXCP_VPU: /* Vector unavailable exception */
|
||||||
|
case POWERPC_EXCP_VSXU: /* VSX unavailable exception */
|
||||||
|
case POWERPC_EXCP_FU: /* Facility unavailable exception */
|
||||||
|
env->spr[SPR_FSCR] |= ((target_ulong)env->error_code << 56);
|
||||||
|
break;
|
||||||
|
case POWERPC_EXCP_HV_FU: /* Hypervisor Facility Unavailable Exception */
|
||||||
|
env->spr[SPR_HFSCR] |= ((target_ulong)env->error_code << FSCR_IC_POS);
|
||||||
|
srr0 = SPR_HSRR0;
|
||||||
|
srr1 = SPR_HSRR1;
|
||||||
|
new_msr |= (target_ulong)MSR_HVB;
|
||||||
|
new_msr |= env->msr & ((target_ulong)1 << MSR_RI);
|
||||||
|
break;
|
||||||
|
case POWERPC_EXCP_THERM: /* Thermal interrupt */
|
||||||
|
case POWERPC_EXCP_PERFM: /* Embedded performance monitor interrupt */
|
||||||
|
case POWERPC_EXCP_VPUA: /* Vector assist exception */
|
||||||
|
case POWERPC_EXCP_MAINT: /* Maintenance exception */
|
||||||
|
case POWERPC_EXCP_SDOOR: /* Doorbell interrupt */
|
||||||
|
case POWERPC_EXCP_HV_MAINT: /* Hypervisor Maintenance exception */
|
||||||
|
cpu_abort(cs, "%s exception not implemented\n",
|
||||||
|
powerpc_excp_name(excp));
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
cpu_abort(cs, "Invalid PowerPC exception %d. Aborting\n", excp);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Sanity check */
|
||||||
|
if (!(env->msr_mask & MSR_HVB)) {
|
||||||
|
if (new_msr & MSR_HVB) {
|
||||||
|
cpu_abort(cs, "Trying to deliver HV exception (MSR) %d with "
|
||||||
|
"no HV support\n", excp);
|
||||||
|
}
|
||||||
|
if (srr0 == SPR_HSRR0) {
|
||||||
|
cpu_abort(cs, "Trying to deliver HV exception (HSRR) %d with "
|
||||||
|
"no HV support\n", excp);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Sort out endianness of interrupt, this differs depending on the
|
||||||
|
* CPU, the HV mode, etc...
|
||||||
|
*/
|
||||||
|
if (ppc_interrupts_little_endian(cpu, !!(new_msr & MSR_HVB))) {
|
||||||
|
new_msr |= (target_ulong)1 << MSR_LE;
|
||||||
|
}
|
||||||
|
|
||||||
|
new_msr |= (target_ulong)1 << MSR_SF;
|
||||||
|
|
||||||
|
if (excp != POWERPC_EXCP_SYSCALL_VECTORED) {
|
||||||
|
/* Save PC */
|
||||||
|
env->spr[srr0] = env->nip;
|
||||||
|
|
||||||
|
/* Save MSR */
|
||||||
|
env->spr[srr1] = msr;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* This can update new_msr and vector if AIL applies */
|
||||||
|
ppc_excp_apply_ail(cpu, excp_model, excp, msr, &new_msr, &vector);
|
||||||
|
|
||||||
|
powerpc_set_excp_state(cpu, vector, new_msr);
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
static inline void powerpc_excp_books(PowerPCCPU *cpu, int excp)
|
||||||
|
{
|
||||||
|
g_assert_not_reached();
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Note that this function should be greatly optimized when called
|
* Note that this function should be greatly optimized when called
|
||||||
* with a constant excp, from ppc_hw_interrupt
|
* with a constant excp, from ppc_hw_interrupt
|
||||||
@ -768,7 +1422,6 @@ static inline void powerpc_excp_legacy(PowerPCCPU *cpu, int excp)
|
|||||||
case POWERPC_EXCP_DLTLB: /* Data load TLB miss */
|
case POWERPC_EXCP_DLTLB: /* Data load TLB miss */
|
||||||
case POWERPC_EXCP_DSTLB: /* Data store TLB miss */
|
case POWERPC_EXCP_DSTLB: /* Data store TLB miss */
|
||||||
switch (excp_model) {
|
switch (excp_model) {
|
||||||
case POWERPC_EXCP_602:
|
|
||||||
case POWERPC_EXCP_603:
|
case POWERPC_EXCP_603:
|
||||||
case POWERPC_EXCP_G2:
|
case POWERPC_EXCP_G2:
|
||||||
/* Swap temporary saved registers with GPRs */
|
/* Swap temporary saved registers with GPRs */
|
||||||
@ -872,6 +1525,19 @@ static void powerpc_excp(PowerPCCPU *cpu, int excp)
|
|||||||
CPUPPCState *env = &cpu->env;
|
CPUPPCState *env = &cpu->env;
|
||||||
|
|
||||||
switch (env->excp_model) {
|
switch (env->excp_model) {
|
||||||
|
case POWERPC_EXCP_40x:
|
||||||
|
powerpc_excp_40x(cpu, excp);
|
||||||
|
break;
|
||||||
|
case POWERPC_EXCP_74xx:
|
||||||
|
powerpc_excp_74xx(cpu, excp);
|
||||||
|
break;
|
||||||
|
case POWERPC_EXCP_970:
|
||||||
|
case POWERPC_EXCP_POWER7:
|
||||||
|
case POWERPC_EXCP_POWER8:
|
||||||
|
case POWERPC_EXCP_POWER9:
|
||||||
|
case POWERPC_EXCP_POWER10:
|
||||||
|
powerpc_excp_books(cpu, excp);
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
powerpc_excp_legacy(cpu, excp);
|
powerpc_excp_legacy(cpu, excp);
|
||||||
}
|
}
|
||||||
@ -1155,7 +1821,6 @@ void helper_pminsn(CPUPPCState *env, powerpc_pm_insn_t insn)
|
|||||||
(env->spr[SPR_PSSCR] & PSSCR_EC);
|
(env->spr[SPR_PSSCR] & PSSCR_EC);
|
||||||
}
|
}
|
||||||
#endif /* defined(TARGET_PPC64) */
|
#endif /* defined(TARGET_PPC64) */
|
||||||
#endif /* CONFIG_TCG */
|
|
||||||
|
|
||||||
static void do_rfi(CPUPPCState *env, target_ulong nip, target_ulong msr)
|
static void do_rfi(CPUPPCState *env, target_ulong nip, target_ulong msr)
|
||||||
{
|
{
|
||||||
@ -1164,6 +1829,10 @@ static void do_rfi(CPUPPCState *env, target_ulong nip, target_ulong msr)
|
|||||||
/* MSR:POW cannot be set by any form of rfi */
|
/* MSR:POW cannot be set by any form of rfi */
|
||||||
msr &= ~(1ULL << MSR_POW);
|
msr &= ~(1ULL << MSR_POW);
|
||||||
|
|
||||||
|
/* MSR:TGPR cannot be set by any form of rfi */
|
||||||
|
if (env->flags & POWERPC_FLAG_TGPR)
|
||||||
|
msr &= ~(1ULL << MSR_TGPR);
|
||||||
|
|
||||||
#if defined(TARGET_PPC64)
|
#if defined(TARGET_PPC64)
|
||||||
/* Switching to 32-bit ? Crop the nip */
|
/* Switching to 32-bit ? Crop the nip */
|
||||||
if (!msr_is_64bit(env, msr)) {
|
if (!msr_is_64bit(env, msr)) {
|
||||||
@ -1188,7 +1857,6 @@ static void do_rfi(CPUPPCState *env, target_ulong nip, target_ulong msr)
|
|||||||
check_tlb_flush(env, false);
|
check_tlb_flush(env, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef CONFIG_TCG
|
|
||||||
void helper_rfi(CPUPPCState *env)
|
void helper_rfi(CPUPPCState *env)
|
||||||
{
|
{
|
||||||
do_rfi(env, env->spr[SPR_SRR0], env->spr[SPR_SRR1] & 0xfffffffful);
|
do_rfi(env, env->spr[SPR_SRR0], env->spr[SPR_SRR1] & 0xfffffffful);
|
||||||
|
@ -646,7 +646,6 @@ DEF_HELPER_FLAGS_2(slbieg, TCG_CALL_NO_RWG, void, env, tl)
|
|||||||
DEF_HELPER_FLAGS_2(load_sr, TCG_CALL_NO_RWG, tl, env, tl)
|
DEF_HELPER_FLAGS_2(load_sr, TCG_CALL_NO_RWG, tl, env, tl)
|
||||||
DEF_HELPER_FLAGS_3(store_sr, TCG_CALL_NO_RWG, void, env, tl, tl)
|
DEF_HELPER_FLAGS_3(store_sr, TCG_CALL_NO_RWG, void, env, tl, tl)
|
||||||
|
|
||||||
DEF_HELPER_FLAGS_1(602_mfrom, TCG_CALL_NO_RWG_SE, tl, tl)
|
|
||||||
DEF_HELPER_1(msgsnd, void, tl)
|
DEF_HELPER_1(msgsnd, void, tl)
|
||||||
DEF_HELPER_2(msgclr, void, env, tl)
|
DEF_HELPER_2(msgclr, void, env, tl)
|
||||||
DEF_HELPER_1(book3s_msgsnd, void, tl)
|
DEF_HELPER_1(book3s_msgsnd, void, tl)
|
||||||
@ -707,6 +706,7 @@ DEF_HELPER_FLAGS_1(load_40x_pit, TCG_CALL_NO_RWG, tl, env)
|
|||||||
DEF_HELPER_FLAGS_2(store_40x_pit, TCG_CALL_NO_RWG, void, env, tl)
|
DEF_HELPER_FLAGS_2(store_40x_pit, TCG_CALL_NO_RWG, void, env, tl)
|
||||||
DEF_HELPER_FLAGS_2(store_40x_tcr, TCG_CALL_NO_RWG, void, env, tl)
|
DEF_HELPER_FLAGS_2(store_40x_tcr, TCG_CALL_NO_RWG, void, env, tl)
|
||||||
DEF_HELPER_FLAGS_2(store_40x_tsr, TCG_CALL_NO_RWG, void, env, tl)
|
DEF_HELPER_FLAGS_2(store_40x_tsr, TCG_CALL_NO_RWG, void, env, tl)
|
||||||
|
DEF_HELPER_2(store_40x_pid, void, env, tl)
|
||||||
DEF_HELPER_2(store_40x_dbcr0, void, env, tl)
|
DEF_HELPER_2(store_40x_dbcr0, void, env, tl)
|
||||||
DEF_HELPER_2(store_40x_sler, void, env, tl)
|
DEF_HELPER_2(store_40x_sler, void, env, tl)
|
||||||
DEF_HELPER_FLAGS_2(store_booke_tcr, TCG_CALL_NO_RWG, void, env, tl)
|
DEF_HELPER_FLAGS_2(store_booke_tcr, TCG_CALL_NO_RWG, void, env, tl)
|
||||||
|
@ -156,7 +156,8 @@ static uint32_t hreg_compute_hflags_value(CPUPPCState *env)
|
|||||||
*/
|
*/
|
||||||
unsigned immu_idx, dmmu_idx;
|
unsigned immu_idx, dmmu_idx;
|
||||||
dmmu_idx = msr & (1 << MSR_PR) ? 0 : 1;
|
dmmu_idx = msr & (1 << MSR_PR) ? 0 : 1;
|
||||||
if (env->mmu_model & POWERPC_MMU_BOOKE) {
|
if (env->mmu_model == POWERPC_MMU_BOOKE ||
|
||||||
|
env->mmu_model == POWERPC_MMU_BOOKE206) {
|
||||||
dmmu_idx |= msr & (1 << MSR_GS) ? 4 : 0;
|
dmmu_idx |= msr & (1 << MSR_GS) ? 4 : 0;
|
||||||
immu_idx = dmmu_idx;
|
immu_idx = dmmu_idx;
|
||||||
immu_idx |= msr & (1 << MSR_IS) ? 2 : 0;
|
immu_idx |= msr & (1 << MSR_IS) ? 2 : 0;
|
||||||
@ -201,7 +202,11 @@ void cpu_get_tb_cpu_state(CPUPPCState *env, target_ulong *pc,
|
|||||||
|
|
||||||
void cpu_interrupt_exittb(CPUState *cs)
|
void cpu_interrupt_exittb(CPUState *cs)
|
||||||
{
|
{
|
||||||
if (!kvm_enabled()) {
|
/*
|
||||||
|
* We don't need to worry about translation blocks
|
||||||
|
* when running with KVM.
|
||||||
|
*/
|
||||||
|
if (kvm_enabled()) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -233,7 +238,8 @@ int hreg_store_msr(CPUPPCState *env, target_ulong value, int alter_hv)
|
|||||||
((value >> MSR_DR) & 1) != msr_dr) {
|
((value >> MSR_DR) & 1) != msr_dr) {
|
||||||
cpu_interrupt_exittb(cs);
|
cpu_interrupt_exittb(cs);
|
||||||
}
|
}
|
||||||
if ((env->mmu_model & POWERPC_MMU_BOOKE) &&
|
if ((env->mmu_model == POWERPC_MMU_BOOKE ||
|
||||||
|
env->mmu_model == POWERPC_MMU_BOOKE206) &&
|
||||||
((value >> MSR_GS) & 1) != msr_gs) {
|
((value >> MSR_GS) & 1) != msr_gs) {
|
||||||
cpu_interrupt_exittb(cs);
|
cpu_interrupt_exittb(cs);
|
||||||
}
|
}
|
||||||
|
@ -488,27 +488,6 @@ target_ulong helper_divso(CPUPPCState *env, target_ulong arg1,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/*****************************************************************************/
|
|
||||||
/* 602 specific instructions */
|
|
||||||
/* mfrom is the most crazy instruction ever seen, imho ! */
|
|
||||||
/* Real implementation uses a ROM table. Do the same */
|
|
||||||
/*
|
|
||||||
* Extremely decomposed:
|
|
||||||
* -arg / 256
|
|
||||||
* return 256 * log10(10 + 1.0) + 0.5
|
|
||||||
*/
|
|
||||||
#if !defined(CONFIG_USER_ONLY)
|
|
||||||
target_ulong helper_602_mfrom(target_ulong arg)
|
|
||||||
{
|
|
||||||
if (likely(arg < 602)) {
|
|
||||||
#include "mfrom_table.c.inc"
|
|
||||||
return mfrom_ROM_table[arg];
|
|
||||||
} else {
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/*****************************************************************************/
|
/*****************************************************************************/
|
||||||
/* Altivec extension helpers */
|
/* Altivec extension helpers */
|
||||||
#if defined(HOST_WORDS_BIGENDIAN)
|
#if defined(HOST_WORDS_BIGENDIAN)
|
||||||
|
@ -1,78 +0,0 @@
|
|||||||
static const uint8_t mfrom_ROM_table[602] = {
|
|
||||||
77, 77, 76, 76, 75, 75, 74, 74,
|
|
||||||
73, 73, 72, 72, 71, 71, 70, 70,
|
|
||||||
69, 69, 68, 68, 68, 67, 67, 66,
|
|
||||||
66, 65, 65, 64, 64, 64, 63, 63,
|
|
||||||
62, 62, 61, 61, 61, 60, 60, 59,
|
|
||||||
59, 58, 58, 58, 57, 57, 56, 56,
|
|
||||||
56, 55, 55, 54, 54, 54, 53, 53,
|
|
||||||
53, 52, 52, 51, 51, 51, 50, 50,
|
|
||||||
50, 49, 49, 49, 48, 48, 47, 47,
|
|
||||||
47, 46, 46, 46, 45, 45, 45, 44,
|
|
||||||
44, 44, 43, 43, 43, 42, 42, 42,
|
|
||||||
42, 41, 41, 41, 40, 40, 40, 39,
|
|
||||||
39, 39, 39, 38, 38, 38, 37, 37,
|
|
||||||
37, 37, 36, 36, 36, 35, 35, 35,
|
|
||||||
35, 34, 34, 34, 34, 33, 33, 33,
|
|
||||||
33, 32, 32, 32, 32, 31, 31, 31,
|
|
||||||
31, 30, 30, 30, 30, 29, 29, 29,
|
|
||||||
29, 28, 28, 28, 28, 28, 27, 27,
|
|
||||||
27, 27, 26, 26, 26, 26, 26, 25,
|
|
||||||
25, 25, 25, 25, 24, 24, 24, 24,
|
|
||||||
24, 23, 23, 23, 23, 23, 23, 22,
|
|
||||||
22, 22, 22, 22, 21, 21, 21, 21,
|
|
||||||
21, 21, 20, 20, 20, 20, 20, 20,
|
|
||||||
19, 19, 19, 19, 19, 19, 19, 18,
|
|
||||||
18, 18, 18, 18, 18, 17, 17, 17,
|
|
||||||
17, 17, 17, 17, 16, 16, 16, 16,
|
|
||||||
16, 16, 16, 16, 15, 15, 15, 15,
|
|
||||||
15, 15, 15, 15, 14, 14, 14, 14,
|
|
||||||
14, 14, 14, 14, 13, 13, 13, 13,
|
|
||||||
13, 13, 13, 13, 13, 12, 12, 12,
|
|
||||||
12, 12, 12, 12, 12, 12, 12, 11,
|
|
||||||
11, 11, 11, 11, 11, 11, 11, 11,
|
|
||||||
11, 11, 10, 10, 10, 10, 10, 10,
|
|
||||||
10, 10, 10, 10, 10, 9, 9, 9,
|
|
||||||
9, 9, 9, 9, 9, 9, 9, 9,
|
|
||||||
9, 9, 8, 8, 8, 8, 8, 8,
|
|
||||||
8, 8, 8, 8, 8, 8, 8, 8,
|
|
||||||
7, 7, 7, 7, 7, 7, 7, 7,
|
|
||||||
7, 7, 7, 7, 7, 7, 7, 7,
|
|
||||||
7, 6, 6, 6, 6, 6, 6, 6,
|
|
||||||
6, 6, 6, 6, 6, 6, 6, 6,
|
|
||||||
6, 6, 6, 6, 5, 5, 5, 5,
|
|
||||||
5, 5, 5, 5, 5, 5, 5, 5,
|
|
||||||
5, 5, 5, 5, 5, 5, 5, 5,
|
|
||||||
5, 5, 5, 4, 4, 4, 4, 4,
|
|
||||||
4, 4, 4, 4, 4, 4, 4, 4,
|
|
||||||
4, 4, 4, 4, 4, 4, 4, 4,
|
|
||||||
4, 4, 4, 4, 4, 4, 4, 3,
|
|
||||||
3, 3, 3, 3, 3, 3, 3, 3,
|
|
||||||
3, 3, 3, 3, 3, 3, 3, 3,
|
|
||||||
3, 3, 3, 3, 3, 3, 3, 3,
|
|
||||||
3, 3, 3, 3, 3, 3, 3, 3,
|
|
||||||
3, 3, 3, 3, 3, 2, 2, 2,
|
|
||||||
2, 2, 2, 2, 2, 2, 2, 2,
|
|
||||||
2, 2, 2, 2, 2, 2, 2, 2,
|
|
||||||
2, 2, 2, 2, 2, 2, 2, 2,
|
|
||||||
2, 2, 2, 2, 2, 2, 2, 2,
|
|
||||||
2, 2, 2, 2, 2, 2, 2, 2,
|
|
||||||
2, 2, 2, 2, 2, 2, 2, 2,
|
|
||||||
2, 2, 2, 2, 2, 2, 1, 1,
|
|
||||||
1, 1, 1, 1, 1, 1, 1, 1,
|
|
||||||
1, 1, 1, 1, 1, 1, 1, 1,
|
|
||||||
1, 1, 1, 1, 1, 1, 1, 1,
|
|
||||||
1, 1, 1, 1, 1, 1, 1, 1,
|
|
||||||
1, 1, 1, 1, 1, 1, 1, 1,
|
|
||||||
1, 1, 1, 1, 1, 1, 1, 1,
|
|
||||||
1, 1, 1, 1, 1, 1, 1, 1,
|
|
||||||
1, 1, 1, 1, 1, 1, 1, 1,
|
|
||||||
1, 1, 1, 1, 1, 1, 1, 1,
|
|
||||||
1, 1, 1, 1, 1, 1, 1, 1,
|
|
||||||
1, 1, 1, 1, 1, 1, 1, 1,
|
|
||||||
1, 1, 1, 1, 1, 1, 1, 1,
|
|
||||||
1, 1, 1, 1, 1, 1, 1, 1,
|
|
||||||
1, 1, 1, 1, 1, 1, 1, 1,
|
|
||||||
1, 1, 1, 1, 1, 1, 1, 1,
|
|
||||||
1, 0,
|
|
||||||
};
|
|
@ -1,34 +0,0 @@
|
|||||||
#define _GNU_SOURCE
|
|
||||||
#include "qemu/osdep.h"
|
|
||||||
#include <math.h>
|
|
||||||
|
|
||||||
int main(void)
|
|
||||||
{
|
|
||||||
double d;
|
|
||||||
uint8_t n;
|
|
||||||
int i;
|
|
||||||
|
|
||||||
printf("static const uint8_t mfrom_ROM_table[602] =\n{\n ");
|
|
||||||
for (i = 0; i < 602; i++) {
|
|
||||||
/*
|
|
||||||
* Extremely decomposed:
|
|
||||||
* -T0 / 256
|
|
||||||
* T0 = 256 * log10(10 + 1.0) + 0.5
|
|
||||||
*/
|
|
||||||
d = -i;
|
|
||||||
d /= 256.0;
|
|
||||||
d = exp10(d);
|
|
||||||
d += 1.0;
|
|
||||||
d = log10(d);
|
|
||||||
d *= 256;
|
|
||||||
d += 0.5;
|
|
||||||
n = d;
|
|
||||||
printf("%3d, ", n);
|
|
||||||
if ((i & 7) == 7) {
|
|
||||||
printf("\n ");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
printf("\n};\n");
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
@ -1367,22 +1367,34 @@ static bool ppc_jumbo_xlate(PowerPCCPU *cpu, vaddr eaddr,
|
|||||||
case -2:
|
case -2:
|
||||||
/* Access rights violation */
|
/* Access rights violation */
|
||||||
cs->exception_index = POWERPC_EXCP_ISI;
|
cs->exception_index = POWERPC_EXCP_ISI;
|
||||||
env->error_code = 0x08000000;
|
if ((env->mmu_model == POWERPC_MMU_BOOKE) ||
|
||||||
|
(env->mmu_model == POWERPC_MMU_BOOKE206)) {
|
||||||
|
env->error_code = 0;
|
||||||
|
} else {
|
||||||
|
env->error_code = 0x08000000;
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
case -3:
|
case -3:
|
||||||
/* No execute protection violation */
|
/* No execute protection violation */
|
||||||
if ((env->mmu_model == POWERPC_MMU_BOOKE) ||
|
if ((env->mmu_model == POWERPC_MMU_BOOKE) ||
|
||||||
(env->mmu_model == POWERPC_MMU_BOOKE206)) {
|
(env->mmu_model == POWERPC_MMU_BOOKE206)) {
|
||||||
env->spr[SPR_BOOKE_ESR] = 0x00000000;
|
env->spr[SPR_BOOKE_ESR] = 0x00000000;
|
||||||
|
env->error_code = 0;
|
||||||
|
} else {
|
||||||
|
env->error_code = 0x10000000;
|
||||||
}
|
}
|
||||||
cs->exception_index = POWERPC_EXCP_ISI;
|
cs->exception_index = POWERPC_EXCP_ISI;
|
||||||
env->error_code = 0x10000000;
|
|
||||||
break;
|
break;
|
||||||
case -4:
|
case -4:
|
||||||
/* Direct store exception */
|
/* Direct store exception */
|
||||||
/* No code fetch is allowed in direct-store areas */
|
/* No code fetch is allowed in direct-store areas */
|
||||||
cs->exception_index = POWERPC_EXCP_ISI;
|
cs->exception_index = POWERPC_EXCP_ISI;
|
||||||
env->error_code = 0x10000000;
|
if ((env->mmu_model == POWERPC_MMU_BOOKE) ||
|
||||||
|
(env->mmu_model == POWERPC_MMU_BOOKE206)) {
|
||||||
|
env->error_code = 0;
|
||||||
|
} else {
|
||||||
|
env->error_code = 0x10000000;
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
@ -664,6 +664,14 @@ static inline int booke_page_size_to_tlb(target_ulong page_size)
|
|||||||
#define PPC4XX_TLBLO_ATTR_MASK 0x000000FF
|
#define PPC4XX_TLBLO_ATTR_MASK 0x000000FF
|
||||||
#define PPC4XX_TLBLO_RPN_MASK 0xFFFFFC00
|
#define PPC4XX_TLBLO_RPN_MASK 0xFFFFFC00
|
||||||
|
|
||||||
|
void helper_store_40x_pid(CPUPPCState *env, target_ulong val)
|
||||||
|
{
|
||||||
|
if (env->spr[SPR_40x_PID] != val) {
|
||||||
|
env->spr[SPR_40x_PID] = val;
|
||||||
|
env->tlb_need_flush |= TLB_NEED_LOCAL_FLUSH;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
target_ulong helper_4xx_tlbre_hi(CPUPPCState *env, target_ulong entry)
|
target_ulong helper_4xx_tlbre_hi(CPUPPCState *env, target_ulong entry)
|
||||||
{
|
{
|
||||||
ppcemb_tlb_t *tlb;
|
ppcemb_tlb_t *tlb;
|
||||||
@ -681,7 +689,7 @@ target_ulong helper_4xx_tlbre_hi(CPUPPCState *env, target_ulong entry)
|
|||||||
size = PPC4XX_TLBHI_SIZE_DEFAULT;
|
size = PPC4XX_TLBHI_SIZE_DEFAULT;
|
||||||
}
|
}
|
||||||
ret |= size << PPC4XX_TLBHI_SIZE_SHIFT;
|
ret |= size << PPC4XX_TLBHI_SIZE_SHIFT;
|
||||||
env->spr[SPR_40x_PID] = tlb->PID;
|
helper_store_40x_pid(env, tlb->PID);
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -794,6 +802,8 @@ void helper_4xx_tlbwe_lo(CPUPPCState *env, target_ulong entry,
|
|||||||
tlb->prot & PAGE_WRITE ? 'w' : '-',
|
tlb->prot & PAGE_WRITE ? 'w' : '-',
|
||||||
tlb->prot & PAGE_EXEC ? 'x' : '-',
|
tlb->prot & PAGE_EXEC ? 'x' : '-',
|
||||||
tlb->prot & PAGE_VALID ? 'v' : '-', (int)tlb->PID);
|
tlb->prot & PAGE_VALID ? 'v' : '-', (int)tlb->PID);
|
||||||
|
|
||||||
|
env->tlb_need_flush |= TLB_NEED_LOCAL_FLUSH;
|
||||||
}
|
}
|
||||||
|
|
||||||
target_ulong helper_4xx_tlbsx(CPUPPCState *env, target_ulong address)
|
target_ulong helper_4xx_tlbsx(CPUPPCState *env, target_ulong address)
|
||||||
|
@ -894,7 +894,7 @@ void spr_write_40x_pid(DisasContext *ctx, int sprn, int gprn)
|
|||||||
{
|
{
|
||||||
TCGv t0 = tcg_temp_new();
|
TCGv t0 = tcg_temp_new();
|
||||||
tcg_gen_andi_tl(t0, cpu_gpr[gprn], 0xFF);
|
tcg_gen_andi_tl(t0, cpu_gpr[gprn], 0xFF);
|
||||||
gen_store_spr(SPR_40x_PID, t0);
|
gen_helper_store_40x_pid(cpu_env, t0);
|
||||||
tcg_temp_free(t0);
|
tcg_temp_free(t0);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -6272,33 +6272,6 @@ static void gen_srq(DisasContext *ctx)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* PowerPC 602 specific instructions */
|
|
||||||
|
|
||||||
/* dsa */
|
|
||||||
static void gen_dsa(DisasContext *ctx)
|
|
||||||
{
|
|
||||||
/* XXX: TODO */
|
|
||||||
gen_inval_exception(ctx, POWERPC_EXCP_INVAL_INVAL);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* esa */
|
|
||||||
static void gen_esa(DisasContext *ctx)
|
|
||||||
{
|
|
||||||
/* XXX: TODO */
|
|
||||||
gen_inval_exception(ctx, POWERPC_EXCP_INVAL_INVAL);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* mfrom */
|
|
||||||
static void gen_mfrom(DisasContext *ctx)
|
|
||||||
{
|
|
||||||
#if defined(CONFIG_USER_ONLY)
|
|
||||||
GEN_PRIV;
|
|
||||||
#else
|
|
||||||
CHK_SV;
|
|
||||||
gen_helper_602_mfrom(cpu_gpr[rD(ctx->opcode)], cpu_gpr[rA(ctx->opcode)]);
|
|
||||||
#endif /* defined(CONFIG_USER_ONLY) */
|
|
||||||
}
|
|
||||||
|
|
||||||
/* 602 - 603 - G2 TLB management */
|
/* 602 - 603 - G2 TLB management */
|
||||||
|
|
||||||
/* tlbld */
|
/* tlbld */
|
||||||
@ -7779,9 +7752,6 @@ GEN_HANDLER(sriq, 0x1F, 0x18, 0x15, 0x00000000, PPC_POWER_BR),
|
|||||||
GEN_HANDLER(srliq, 0x1F, 0x18, 0x17, 0x00000000, PPC_POWER_BR),
|
GEN_HANDLER(srliq, 0x1F, 0x18, 0x17, 0x00000000, PPC_POWER_BR),
|
||||||
GEN_HANDLER(srlq, 0x1F, 0x18, 0x16, 0x00000000, PPC_POWER_BR),
|
GEN_HANDLER(srlq, 0x1F, 0x18, 0x16, 0x00000000, PPC_POWER_BR),
|
||||||
GEN_HANDLER(srq, 0x1F, 0x18, 0x14, 0x00000000, PPC_POWER_BR),
|
GEN_HANDLER(srq, 0x1F, 0x18, 0x14, 0x00000000, PPC_POWER_BR),
|
||||||
GEN_HANDLER(dsa, 0x1F, 0x14, 0x13, 0x03FFF801, PPC_602_SPEC),
|
|
||||||
GEN_HANDLER(esa, 0x1F, 0x14, 0x12, 0x03FFF801, PPC_602_SPEC),
|
|
||||||
GEN_HANDLER(mfrom, 0x1F, 0x09, 0x08, 0x03E0F801, PPC_602_SPEC),
|
|
||||||
GEN_HANDLER2(tlbld_6xx, "tlbld", 0x1F, 0x12, 0x1E, 0x03FF0001, PPC_6xx_TLB),
|
GEN_HANDLER2(tlbld_6xx, "tlbld", 0x1F, 0x12, 0x1E, 0x03FF0001, PPC_6xx_TLB),
|
||||||
GEN_HANDLER2(tlbli_6xx, "tlbli", 0x1F, 0x12, 0x1F, 0x03FF0001, PPC_6xx_TLB),
|
GEN_HANDLER2(tlbli_6xx, "tlbli", 0x1F, 0x12, 0x1F, 0x03FF0001, PPC_6xx_TLB),
|
||||||
GEN_HANDLER(clf, 0x1F, 0x16, 0x03, 0x03E00000, PPC_POWER),
|
GEN_HANDLER(clf, 0x1F, 0x16, 0x03, 0x03E00000, PPC_POWER),
|
||||||
|
Loading…
Reference in New Issue
Block a user