ppc patch queue for 2016-05-31

Here's another ppc patch queue.  This batch is all preliminaries
 towards two significant features:
 
 1) Full hypervisor-mode support for POWER8
     Patches 1-8 start fixing various bugs with TCG's handling of
     hypervisor mode
 
 2) CPU hotplug support
     Patches 9-12 make some preliminary fixes towards implementing CPU
     hotplug on ppc64 (and other non-x86 platforms).  These patches are
     actually to generic code, not ppc, but are included here with
     Paolo's ACK.
 -----BEGIN PGP SIGNATURE-----
 Version: GnuPG v1
 
 iQIcBAABAgAGBQJXTN1QAAoJEGw4ysog2bOSM4kP/2TKm/wkGo3nsGm7vG0CArs+
 JVIlTWI9Le7Cq5ijCkTwV9gjeG2CYz+Us2PCh2ZAoHpXgZtP7px2HRcDv07SbCnt
 SaCwCS+EGf3ZO9baQrzG0zfe8XrlJF+XXTejD2zWtOZw7sZ/4OPWF9KdcZbjWqFp
 PzJuXrpYOAaIyXyEPJSZFpHY+AC9NIblqHlUrKntPLLOYbqQBYP4IMxsUmOgu2IX
 rFK/5A8t20BJN0lbmx8JNKh0voorFpHY/hhaH/1T7rKxsRkKMh3VbYSxD6EYs3Uc
 nZ4ufQQW6C4CEFta3YHNwoClcsQUbnZQh3Ra+gKo9bXvqDzasVpq/mBgl3BDjGeG
 LQPSA6sfmEA8lqtRikVdgSgdXDnwy5YXJLVmIXeAIG1KHa6eRuUxC3o+ScOkcH3A
 ynLglCEBl9slsG9/yYkDcFW2u0t/txTBUvaxMfOQomAejrGjOLGZqnSWMd2UC4Gt
 KQRP+b7igkXC7+bfrpBPWKyYGvOOCukESw3OV90hLBIzOthI1dI5hO0Gj61C/nlI
 NXMRbx0qTztgj3tfSTTs6e9Ke8PEKnyXqgol0+t9Yxntlz28f2alTubUoyv/vZjx
 8J1IOlNms3PnO26TxUVBu7/KaCGCM25eTQgllbTx8rhaqin3wAH3dRc1RTlWWhwJ
 SgADl+MWf8sa7DkcxnZa
 =vAIf
 -----END PGP SIGNATURE-----

Merge remote-tracking branch 'remotes/dgibson/tags/ppc-for-2.7-20160531' into staging

ppc patch queue for 2016-05-31

Here's another ppc patch queue.  This batch is all preliminaries
towards two significant features:

1) Full hypervisor-mode support for POWER8
    Patches 1-8 start fixing various bugs with TCG's handling of
    hypervisor mode

2) CPU hotplug support
    Patches 9-12 make some preliminary fixes towards implementing CPU
    hotplug on ppc64 (and other non-x86 platforms).  These patches are
    actually to generic code, not ppc, but are included here with
    Paolo's ACK.

# gpg: Signature made Tue 31 May 2016 01:39:44 BST using RSA key ID 20D9B392
# gpg: Good signature from "David Gibson <david@gibson.dropbear.id.au>"
# gpg:                 aka "David Gibson (Red Hat) <dgibson@redhat.com>"
# gpg:                 aka "David Gibson (ozlabs.org) <dgibson@ozlabs.org>"
# gpg: WARNING: This key is not certified with sufficiently trusted signatures!
# gpg:          It is not certain that the signature belongs to the owner.
# Primary key fingerprint: 75F4 6586 AE61 A66C C44E  87DC 6C38 CACA 20D9 B392

* remotes/dgibson/tags/ppc-for-2.7-20160531:
  cpu: Add a sync version of cpu_remove()
  cpu: Reclaim vCPU objects
  exec: Do vmstate unregistration from cpu_exec_exit()
  exec: Remove cpu from cpus list during cpu_exec_exit()
  ppc: Add PPC_64H instruction flag to POWER7 and POWER8
  ppc: Get out of emulation on SMT "OR" ops
  ppc: Fix sign extension issue in mtmsr(d) emulation
  ppc: Change 'invalid' bit mask of tlbiel and tlbie
  ppc: tlbie, tlbia and tlbisync are HV only
  ppc: Do some batching of TCG tlb flushes
  ppc: Use split I/D mmu modes to avoid flushes on interrupts
  ppc: Remove MMU_MODEn_SUFFIX definitions

Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
This commit is contained in:
Peter Maydell 2016-05-31 10:37:21 +01:00
commit 500acc9c41
16 changed files with 337 additions and 65 deletions

51
cpus.c
View File

@ -972,6 +972,18 @@ void async_run_on_cpu(CPUState *cpu, void (*func)(void *data), void *data)
qemu_cpu_kick(cpu); qemu_cpu_kick(cpu);
} }
static void qemu_kvm_destroy_vcpu(CPUState *cpu)
{
if (kvm_destroy_vcpu(cpu) < 0) {
error_report("kvm_destroy_vcpu failed");
exit(EXIT_FAILURE);
}
}
static void qemu_tcg_destroy_vcpu(CPUState *cpu)
{
}
static void flush_queued_work(CPUState *cpu) static void flush_queued_work(CPUState *cpu)
{ {
struct qemu_work_item *wi; struct qemu_work_item *wi;
@ -1061,7 +1073,7 @@ static void *qemu_kvm_cpu_thread_fn(void *arg)
cpu->created = true; cpu->created = true;
qemu_cond_signal(&qemu_cpu_cond); qemu_cond_signal(&qemu_cpu_cond);
while (1) { do {
if (cpu_can_run(cpu)) { if (cpu_can_run(cpu)) {
r = kvm_cpu_exec(cpu); r = kvm_cpu_exec(cpu);
if (r == EXCP_DEBUG) { if (r == EXCP_DEBUG) {
@ -1069,8 +1081,12 @@ static void *qemu_kvm_cpu_thread_fn(void *arg)
} }
} }
qemu_kvm_wait_io_event(cpu); qemu_kvm_wait_io_event(cpu);
} } while (!cpu->unplug || cpu_can_run(cpu));
qemu_kvm_destroy_vcpu(cpu);
cpu->created = false;
qemu_cond_signal(&qemu_cpu_cond);
qemu_mutex_unlock_iothread();
return NULL; return NULL;
} }
@ -1124,6 +1140,7 @@ static void tcg_exec_all(void);
static void *qemu_tcg_cpu_thread_fn(void *arg) static void *qemu_tcg_cpu_thread_fn(void *arg)
{ {
CPUState *cpu = arg; CPUState *cpu = arg;
CPUState *remove_cpu = NULL;
rcu_register_thread(); rcu_register_thread();
@ -1161,6 +1178,18 @@ static void *qemu_tcg_cpu_thread_fn(void *arg)
} }
} }
qemu_tcg_wait_io_event(QTAILQ_FIRST(&cpus)); qemu_tcg_wait_io_event(QTAILQ_FIRST(&cpus));
CPU_FOREACH(cpu) {
if (cpu->unplug && !cpu_can_run(cpu)) {
remove_cpu = cpu;
break;
}
}
if (remove_cpu) {
qemu_tcg_destroy_vcpu(remove_cpu);
cpu->created = false;
qemu_cond_signal(&qemu_cpu_cond);
remove_cpu = NULL;
}
} }
return NULL; return NULL;
@ -1317,6 +1346,21 @@ void resume_all_vcpus(void)
} }
} }
void cpu_remove(CPUState *cpu)
{
cpu->stop = true;
cpu->unplug = true;
qemu_cpu_kick(cpu);
}
void cpu_remove_sync(CPUState *cpu)
{
cpu_remove(cpu);
while (cpu->created) {
qemu_cond_wait(&qemu_cpu_cond, &qemu_global_mutex);
}
}
/* For temporary buffers for forming a name */ /* For temporary buffers for forming a name */
#define VCPU_THREAD_NAME_SIZE 16 #define VCPU_THREAD_NAME_SIZE 16
@ -1533,6 +1577,9 @@ static void tcg_exec_all(void)
break; break;
} }
} else if (cpu->stop || cpu->stopped) { } else if (cpu->stop || cpu->stopped) {
if (cpu->unplug) {
next_cpu = CPU_NEXT(cpu);
}
break; break;
} }
} }

43
exec.c
View File

@ -57,6 +57,8 @@
#include "exec/ram_addr.h" #include "exec/ram_addr.h"
#include "exec/log.h" #include "exec/log.h"
#include "migration/vmstate.h"
#include "qemu/range.h" #include "qemu/range.h"
#ifndef _WIN32 #ifndef _WIN32
#include "qemu/mmap-alloc.h" #include "qemu/mmap-alloc.h"
@ -612,15 +614,9 @@ static int cpu_get_free_index(Error **errp)
return cpu; return cpu;
} }
void cpu_exec_exit(CPUState *cpu) static void cpu_release_index(CPUState *cpu)
{ {
if (cpu->cpu_index == -1) {
/* cpu_index was never allocated by this @cpu or was already freed. */
return;
}
bitmap_clear(cpu_index_map, cpu->cpu_index, 1); bitmap_clear(cpu_index_map, cpu->cpu_index, 1);
cpu->cpu_index = -1;
} }
#else #else
@ -635,11 +631,42 @@ static int cpu_get_free_index(Error **errp)
return cpu_index; return cpu_index;
} }
void cpu_exec_exit(CPUState *cpu) static void cpu_release_index(CPUState *cpu)
{ {
return;
} }
#endif #endif
void cpu_exec_exit(CPUState *cpu)
{
CPUClass *cc = CPU_GET_CLASS(cpu);
#if defined(CONFIG_USER_ONLY)
cpu_list_lock();
#endif
if (cpu->cpu_index == -1) {
/* cpu_index was never allocated by this @cpu or was already freed. */
#if defined(CONFIG_USER_ONLY)
cpu_list_unlock();
#endif
return;
}
QTAILQ_REMOVE(&cpus, cpu, node);
cpu_release_index(cpu);
cpu->cpu_index = -1;
#if defined(CONFIG_USER_ONLY)
cpu_list_unlock();
#endif
if (cc->vmsd != NULL) {
vmstate_unregister(NULL, cc->vmsd, cpu);
}
if (qdev_get_vmsd(DEVICE(cpu)) == NULL) {
vmstate_unregister(NULL, &vmstate_cpu_common, cpu);
}
}
void cpu_exec_init(CPUState *cpu, Error **errp) void cpu_exec_init(CPUState *cpu, Error **errp)
{ {
CPUClass *cc = CPU_GET_CLASS(cpu); CPUClass *cc = CPU_GET_CLASS(cpu);

View File

@ -186,6 +186,7 @@ static RemoveResult remove_hpte(PowerPCCPU *cpu, target_ulong ptex,
static target_ulong h_remove(PowerPCCPU *cpu, sPAPRMachineState *spapr, static target_ulong h_remove(PowerPCCPU *cpu, sPAPRMachineState *spapr,
target_ulong opcode, target_ulong *args) target_ulong opcode, target_ulong *args)
{ {
CPUPPCState *env = &cpu->env;
target_ulong flags = args[0]; target_ulong flags = args[0];
target_ulong pte_index = args[1]; target_ulong pte_index = args[1];
target_ulong avpn = args[2]; target_ulong avpn = args[2];
@ -196,6 +197,7 @@ static target_ulong h_remove(PowerPCCPU *cpu, sPAPRMachineState *spapr,
switch (ret) { switch (ret) {
case REMOVE_SUCCESS: case REMOVE_SUCCESS:
check_tlb_flush(env);
return H_SUCCESS; return H_SUCCESS;
case REMOVE_NOT_FOUND: case REMOVE_NOT_FOUND:
@ -232,7 +234,9 @@ static target_ulong h_remove(PowerPCCPU *cpu, sPAPRMachineState *spapr,
static target_ulong h_bulk_remove(PowerPCCPU *cpu, sPAPRMachineState *spapr, static target_ulong h_bulk_remove(PowerPCCPU *cpu, sPAPRMachineState *spapr,
target_ulong opcode, target_ulong *args) target_ulong opcode, target_ulong *args)
{ {
CPUPPCState *env = &cpu->env;
int i; int i;
target_ulong rc = H_SUCCESS;
for (i = 0; i < H_BULK_REMOVE_MAX_BATCH; i++) { for (i = 0; i < H_BULK_REMOVE_MAX_BATCH; i++) {
target_ulong *tsh = &args[i*2]; target_ulong *tsh = &args[i*2];
@ -265,14 +269,18 @@ static target_ulong h_bulk_remove(PowerPCCPU *cpu, sPAPRMachineState *spapr,
break; break;
case REMOVE_PARM: case REMOVE_PARM:
return H_PARAMETER; rc = H_PARAMETER;
goto exit;
case REMOVE_HW: case REMOVE_HW:
return H_HARDWARE; rc = H_HARDWARE;
goto exit;
} }
} }
exit:
check_tlb_flush(env);
return H_SUCCESS; return rc;
} }
static target_ulong h_protect(PowerPCCPU *cpu, sPAPRMachineState *spapr, static target_ulong h_protect(PowerPCCPU *cpu, sPAPRMachineState *spapr,

View File

@ -244,6 +244,7 @@ struct qemu_work_item {
* @halted: Nonzero if the CPU is in suspended state. * @halted: Nonzero if the CPU is in suspended state.
* @stop: Indicates a pending stop request. * @stop: Indicates a pending stop request.
* @stopped: Indicates the CPU has been artificially stopped. * @stopped: Indicates the CPU has been artificially stopped.
* @unplug: Indicates a pending CPU unplug request.
* @crash_occurred: Indicates the OS reported a crash (panic) for this CPU * @crash_occurred: Indicates the OS reported a crash (panic) for this CPU
* @tcg_exit_req: Set to force TCG to stop executing linked TBs for this * @tcg_exit_req: Set to force TCG to stop executing linked TBs for this
* CPU and return to its top level loop. * CPU and return to its top level loop.
@ -296,6 +297,7 @@ struct CPUState {
bool created; bool created;
bool stop; bool stop;
bool stopped; bool stopped;
bool unplug;
bool crash_occurred; bool crash_occurred;
bool exit_request; bool exit_request;
bool tb_flushed; bool tb_flushed;
@ -762,6 +764,22 @@ void cpu_exit(CPUState *cpu);
*/ */
void cpu_resume(CPUState *cpu); void cpu_resume(CPUState *cpu);
/**
* cpu_remove:
* @cpu: The CPU to remove.
*
* Requests the CPU to be removed.
*/
void cpu_remove(CPUState *cpu);
/**
* cpu_remove_sync:
* @cpu: The CPU to remove.
*
* Requests the CPU to be removed and waits till it is removed.
*/
void cpu_remove_sync(CPUState *cpu);
/** /**
* qemu_init_vcpu: * qemu_init_vcpu:
* @cpu: The vCPU to initialize. * @cpu: The vCPU to initialize.

View File

@ -216,6 +216,7 @@ int kvm_has_intx_set_mask(void);
int kvm_init_vcpu(CPUState *cpu); int kvm_init_vcpu(CPUState *cpu);
int kvm_cpu_exec(CPUState *cpu); int kvm_cpu_exec(CPUState *cpu);
int kvm_destroy_vcpu(CPUState *cpu);
#ifdef NEED_CPU_H #ifdef NEED_CPU_H
#include "cpu.h" #include "cpu.h"

View File

@ -61,6 +61,12 @@
#define KVM_MSI_HASHTAB_SIZE 256 #define KVM_MSI_HASHTAB_SIZE 256
struct KVMParkedVcpu {
unsigned long vcpu_id;
int kvm_fd;
QLIST_ENTRY(KVMParkedVcpu) node;
};
struct KVMState struct KVMState
{ {
AccelState parent_obj; AccelState parent_obj;
@ -94,6 +100,7 @@ struct KVMState
QTAILQ_HEAD(msi_hashtab, KVMMSIRoute) msi_hashtab[KVM_MSI_HASHTAB_SIZE]; QTAILQ_HEAD(msi_hashtab, KVMMSIRoute) msi_hashtab[KVM_MSI_HASHTAB_SIZE];
#endif #endif
KVMMemoryListener memory_listener; KVMMemoryListener memory_listener;
QLIST_HEAD(, KVMParkedVcpu) kvm_parked_vcpus;
}; };
KVMState *kvm_state; KVMState *kvm_state;
@ -237,6 +244,53 @@ static int kvm_set_user_memory_region(KVMMemoryListener *kml, KVMSlot *slot)
return kvm_vm_ioctl(s, KVM_SET_USER_MEMORY_REGION, &mem); return kvm_vm_ioctl(s, KVM_SET_USER_MEMORY_REGION, &mem);
} }
int kvm_destroy_vcpu(CPUState *cpu)
{
KVMState *s = kvm_state;
long mmap_size;
struct KVMParkedVcpu *vcpu = NULL;
int ret = 0;
DPRINTF("kvm_destroy_vcpu\n");
mmap_size = kvm_ioctl(s, KVM_GET_VCPU_MMAP_SIZE, 0);
if (mmap_size < 0) {
ret = mmap_size;
DPRINTF("KVM_GET_VCPU_MMAP_SIZE failed\n");
goto err;
}
ret = munmap(cpu->kvm_run, mmap_size);
if (ret < 0) {
goto err;
}
vcpu = g_malloc0(sizeof(*vcpu));
vcpu->vcpu_id = kvm_arch_vcpu_id(cpu);
vcpu->kvm_fd = cpu->kvm_fd;
QLIST_INSERT_HEAD(&kvm_state->kvm_parked_vcpus, vcpu, node);
err:
return ret;
}
static int kvm_get_vcpu(KVMState *s, unsigned long vcpu_id)
{
struct KVMParkedVcpu *cpu;
QLIST_FOREACH(cpu, &s->kvm_parked_vcpus, node) {
if (cpu->vcpu_id == vcpu_id) {
int kvm_fd;
QLIST_REMOVE(cpu, node);
kvm_fd = cpu->kvm_fd;
g_free(cpu);
return kvm_fd;
}
}
return kvm_vm_ioctl(s, KVM_CREATE_VCPU, (void *)vcpu_id);
}
int kvm_init_vcpu(CPUState *cpu) int kvm_init_vcpu(CPUState *cpu)
{ {
KVMState *s = kvm_state; KVMState *s = kvm_state;
@ -245,7 +299,7 @@ int kvm_init_vcpu(CPUState *cpu)
DPRINTF("kvm_init_vcpu\n"); DPRINTF("kvm_init_vcpu\n");
ret = kvm_vm_ioctl(s, KVM_CREATE_VCPU, (void *)kvm_arch_vcpu_id(cpu)); ret = kvm_get_vcpu(s, kvm_arch_vcpu_id(cpu));
if (ret < 0) { if (ret < 0) {
DPRINTF("kvm_create_vcpu failed\n"); DPRINTF("kvm_create_vcpu failed\n");
goto err; goto err;
@ -1501,6 +1555,7 @@ static int kvm_init(MachineState *ms)
#ifdef KVM_CAP_SET_GUEST_DEBUG #ifdef KVM_CAP_SET_GUEST_DEBUG
QTAILQ_INIT(&s->kvm_sw_breakpoints); QTAILQ_INIT(&s->kvm_sw_breakpoints);
#endif #endif
QLIST_INIT(&s->kvm_parked_vcpus);
s->vmfd = -1; s->vmfd = -1;
s->fd = qemu_open("/dev/kvm", O_RDWR); s->fd = qemu_open("/dev/kvm", O_RDWR);
if (s->fd == -1) { if (s->fd == -1) {

View File

@ -32,6 +32,11 @@ bool kvm_allowed;
bool kvm_readonly_mem_allowed; bool kvm_readonly_mem_allowed;
bool kvm_ioeventfd_any_length_allowed; bool kvm_ioeventfd_any_length_allowed;
int kvm_destroy_vcpu(CPUState *cpu)
{
return -ENOSYS;
}
int kvm_init_vcpu(CPUState *cpu) int kvm_init_vcpu(CPUState *cpu)
{ {
return -ENOSYS; return -ENOSYS;

View File

@ -359,6 +359,8 @@ struct ppc_slb_t {
#define MSR_EP 6 /* Exception prefix on 601 */ #define MSR_EP 6 /* Exception prefix on 601 */
#define MSR_IR 5 /* Instruction relocate */ #define MSR_IR 5 /* Instruction relocate */
#define MSR_DR 4 /* Data relocate */ #define MSR_DR 4 /* Data relocate */
#define MSR_IS 5 /* Instruction address space (BookE) */
#define MSR_DS 4 /* Data address space (BookE) */
#define MSR_PE 3 /* Protection enable on 403 */ #define MSR_PE 3 /* Protection enable on 403 */
#define MSR_PX 2 /* Protection exclusive on 403 x */ #define MSR_PX 2 /* Protection exclusive on 403 x */
#define MSR_PMM 2 /* Performance monitor mark on POWER x */ #define MSR_PMM 2 /* Performance monitor mark on POWER x */
@ -410,6 +412,8 @@ struct ppc_slb_t {
#define msr_ep ((env->msr >> MSR_EP) & 1) #define msr_ep ((env->msr >> MSR_EP) & 1)
#define msr_ir ((env->msr >> MSR_IR) & 1) #define msr_ir ((env->msr >> MSR_IR) & 1)
#define msr_dr ((env->msr >> MSR_DR) & 1) #define msr_dr ((env->msr >> MSR_DR) & 1)
#define msr_is ((env->msr >> MSR_IS) & 1)
#define msr_ds ((env->msr >> MSR_DS) & 1)
#define msr_pe ((env->msr >> MSR_PE) & 1) #define msr_pe ((env->msr >> MSR_PE) & 1)
#define msr_px ((env->msr >> MSR_PX) & 1) #define msr_px ((env->msr >> MSR_PX) & 1)
#define msr_pmm ((env->msr >> MSR_PMM) & 1) #define msr_pmm ((env->msr >> MSR_PMM) & 1)
@ -889,7 +893,7 @@ struct ppc_segment_page_sizes {
/*****************************************************************************/ /*****************************************************************************/
/* The whole PowerPC CPU context */ /* The whole PowerPC CPU context */
#define NB_MMU_MODES 3 #define NB_MMU_MODES 8
#define PPC_CPU_OPCODES_LEN 0x40 #define PPC_CPU_OPCODES_LEN 0x40
#define PPC_CPU_INDIRECT_OPCODES_LEN 0x20 #define PPC_CPU_INDIRECT_OPCODES_LEN 0x20
@ -954,6 +958,8 @@ struct CPUPPCState {
/* PowerPC 64 SLB area */ /* PowerPC 64 SLB area */
ppc_slb_t slb[MAX_SLB_ENTRIES]; ppc_slb_t slb[MAX_SLB_ENTRIES];
int32_t slb_nr; int32_t slb_nr;
/* tcg TLB needs flush (deferred slb inval instruction typically) */
uint32_t tlb_need_flush;
#endif #endif
/* segment registers */ /* segment registers */
hwaddr htab_base; hwaddr htab_base;
@ -1053,7 +1059,8 @@ struct CPUPPCState {
/* Those resources are used only in QEMU core */ /* Those resources are used only in QEMU core */
target_ulong hflags; /* hflags is a MSR & HFLAGS_MASK */ target_ulong hflags; /* hflags is a MSR & HFLAGS_MASK */
target_ulong hflags_nmsr; /* specific hflags, not coming from MSR */ target_ulong hflags_nmsr; /* specific hflags, not coming from MSR */
int mmu_idx; /* precomputed MMU index to speed up mem accesses */ int immu_idx; /* precomputed MMU index to speed up insn access */
int dmmu_idx; /* precomputed MMU index to speed up data accesses */
/* Power management */ /* Power management */
int (*check_pow)(CPUPPCState *env); int (*check_pow)(CPUPPCState *env);
@ -1242,13 +1249,10 @@ int ppc_dcr_write (ppc_dcr_t *dcr_env, int dcrn, uint32_t val);
#define cpu_list ppc_cpu_list #define cpu_list ppc_cpu_list
/* MMU modes definitions */ /* MMU modes definitions */
#define MMU_MODE0_SUFFIX _user
#define MMU_MODE1_SUFFIX _kernel
#define MMU_MODE2_SUFFIX _hypv
#define MMU_USER_IDX 0 #define MMU_USER_IDX 0
static inline int cpu_mmu_index (CPUPPCState *env, bool ifetch) static inline int cpu_mmu_index (CPUPPCState *env, bool ifetch)
{ {
return env->mmu_idx; return ifetch ? env->immu_idx : env->dmmu_idx;
} }
#include "exec/cpu-all.h" #include "exec/cpu-all.h"

View File

@ -646,9 +646,6 @@ static inline void powerpc_excp(PowerPCCPU *cpu, int excp_model, int excp)
if (env->spr[SPR_LPCR] & LPCR_AIL) { if (env->spr[SPR_LPCR] & LPCR_AIL) {
new_msr |= (1 << MSR_IR) | (1 << MSR_DR); new_msr |= (1 << MSR_IR) | (1 << MSR_DR);
} else if (msr & ((1 << MSR_IR) | (1 << MSR_DR))) {
/* If we disactivated any translation, flush TLBs */
tlb_flush(cs, 1);
} }
#ifdef TARGET_PPC64 #ifdef TARGET_PPC64
@ -722,13 +719,10 @@ static inline void powerpc_excp(PowerPCCPU *cpu, int excp_model, int excp)
cs->exception_index = POWERPC_EXCP_NONE; cs->exception_index = POWERPC_EXCP_NONE;
env->error_code = 0; env->error_code = 0;
if ((env->mmu_model == POWERPC_MMU_BOOKE) || /* Any interrupt is context synchronizing, check if TCG TLB
(env->mmu_model == POWERPC_MMU_BOOKE206)) { * needs a delayed flush on ppc64
/* XXX: The BookE changes address space when switching modes, */
we should probably implement that as different MMU indexes, check_tlb_flush(env);
but for the moment we do it the slow way and flush all. */
tlb_flush(cs, 1);
}
} }
void ppc_cpu_do_interrupt(CPUState *cs) void ppc_cpu_do_interrupt(CPUState *cs)
@ -954,6 +948,9 @@ static inline void do_rfi(CPUPPCState *env, target_ulong nip, target_ulong msr,
* as rfi is always the last insn of a TB * as rfi is always the last insn of a TB
*/ */
cs->interrupt_request |= CPU_INTERRUPT_EXITTB; cs->interrupt_request |= CPU_INTERRUPT_EXITTB;
/* Context synchronizing: check if TCG TLB needs flush */
check_tlb_flush(env);
} }
void helper_rfi(CPUPPCState *env) void helper_rfi(CPUPPCState *env)

View File

@ -16,6 +16,7 @@ DEF_HELPER_1(rfmci, void, env)
DEF_HELPER_1(rfid, void, env) DEF_HELPER_1(rfid, void, env)
DEF_HELPER_1(hrfid, void, env) DEF_HELPER_1(hrfid, void, env)
#endif #endif
DEF_HELPER_1(check_tlb_flush, void, env)
#endif #endif
DEF_HELPER_3(lmw, void, env, tl, i32) DEF_HELPER_3(lmw, void, env, tl, i32)

View File

@ -41,11 +41,50 @@ static inline void hreg_swap_gpr_tgpr(CPUPPCState *env)
static inline void hreg_compute_mem_idx(CPUPPCState *env) static inline void hreg_compute_mem_idx(CPUPPCState *env)
{ {
/* Precompute MMU index */ /* This is our encoding for server processors
if (msr_pr == 0 && msr_hv != 0) { *
env->mmu_idx = 2; * 0 = Guest User space virtual mode
* 1 = Guest Kernel space virtual mode
* 2 = Guest Kernel space real mode
* 3 = HV User space virtual mode
* 4 = HV Kernel space virtual mode
* 5 = HV Kernel space real mode
*
* The combination PR=1 IR&DR=0 is invalid, we will treat
* it as IR=DR=1
*
* For BookE, we need 8 MMU modes as follow:
*
* 0 = AS 0 HV User space
* 1 = AS 0 HV Kernel space
* 2 = AS 1 HV User space
* 3 = AS 1 HV Kernel space
* 4 = AS 0 Guest User space
* 5 = AS 0 Guest Kernel space
* 6 = AS 1 Guest User space
* 7 = AS 1 Guest Kernel space
*/
if (env->mmu_model & POWERPC_MMU_BOOKE) {
env->immu_idx = env->dmmu_idx = msr_pr ? 0 : 1;
env->immu_idx += msr_is ? 2 : 0;
env->dmmu_idx += msr_ds ? 2 : 0;
env->immu_idx += msr_gs ? 4 : 0;
env->dmmu_idx += msr_gs ? 4 : 0;
} else { } else {
env->mmu_idx = 1 - msr_pr; /* First calucalte a base value independent of HV */
if (msr_pr != 0) {
/* User space, ignore IR and DR */
env->immu_idx = env->dmmu_idx = 0;
} else {
/* Kernel, setup a base I/D value */
env->immu_idx = msr_ir ? 1 : 2;
env->dmmu_idx = msr_dr ? 1 : 2;
}
/* Then offset it for HV */
if (msr_hv) {
env->immu_idx += 3;
env->dmmu_idx += 3;
}
} }
} }
@ -82,9 +121,10 @@ static inline int hreg_store_msr(CPUPPCState *env, target_ulong value,
} }
if (((value >> MSR_IR) & 1) != msr_ir || if (((value >> MSR_IR) & 1) != msr_ir ||
((value >> MSR_DR) & 1) != msr_dr) { ((value >> MSR_DR) & 1) != msr_dr) {
/* Flush all tlb when changing translation mode */ cs->interrupt_request |= CPU_INTERRUPT_EXITTB;
tlb_flush(cs, 1); }
excp = POWERPC_EXCP_NONE; if ((env->mmu_model & POWERPC_MMU_BOOKE) &&
((value >> MSR_GS) & 1) != msr_gs) {
cs->interrupt_request |= CPU_INTERRUPT_EXITTB; cs->interrupt_request |= CPU_INTERRUPT_EXITTB;
} }
if (unlikely((env->flags & POWERPC_FLAG_TGPR) && if (unlikely((env->flags & POWERPC_FLAG_TGPR) &&
@ -111,4 +151,17 @@ static inline int hreg_store_msr(CPUPPCState *env, target_ulong value,
return excp; return excp;
} }
#if !defined(CONFIG_USER_ONLY) && defined(TARGET_PPC64)
static inline void check_tlb_flush(CPUPPCState *env)
{
CPUState *cs = CPU(ppc_env_get_cpu(env));
if (env->tlb_need_flush) {
env->tlb_need_flush = 0;
tlb_flush(cs, 1);
}
}
#else
static inline void check_tlb_flush(CPUPPCState *env) { }
#endif
#endif /* !defined(__HELPER_REGS_H__) */ #endif /* !defined(__HELPER_REGS_H__) */

View File

@ -97,9 +97,12 @@ static int cpu_load_old(QEMUFile *f, void *opaque, int version_id)
qemu_get_betls(f, &env->nip); qemu_get_betls(f, &env->nip);
qemu_get_betls(f, &env->hflags); qemu_get_betls(f, &env->hflags);
qemu_get_betls(f, &env->hflags_nmsr); qemu_get_betls(f, &env->hflags_nmsr);
qemu_get_sbe32s(f, &env->mmu_idx); qemu_get_sbe32(f); /* Discard unused mmu_idx */
qemu_get_sbe32(f); /* Discard unused power_mode */ qemu_get_sbe32(f); /* Discard unused power_mode */
/* Recompute mmu indices */
hreg_compute_mem_idx(env);
return 0; return 0;
} }

View File

@ -99,10 +99,8 @@ void dump_slb(FILE *f, fprintf_function cpu_fprintf, PowerPCCPU *cpu)
void helper_slbia(CPUPPCState *env) void helper_slbia(CPUPPCState *env)
{ {
PowerPCCPU *cpu = ppc_env_get_cpu(env); int n;
int n, do_invalidate;
do_invalidate = 0;
/* XXX: Warning: slbia never invalidates the first segment */ /* XXX: Warning: slbia never invalidates the first segment */
for (n = 1; n < env->slb_nr; n++) { for (n = 1; n < env->slb_nr; n++) {
ppc_slb_t *slb = &env->slb[n]; ppc_slb_t *slb = &env->slb[n];
@ -113,12 +111,9 @@ void helper_slbia(CPUPPCState *env)
* and we still don't have a tlb_flush_mask(env, n, mask) * and we still don't have a tlb_flush_mask(env, n, mask)
* in QEMU, we just invalidate all TLBs * in QEMU, we just invalidate all TLBs
*/ */
do_invalidate = 1; env->tlb_need_flush = 1;
} }
} }
if (do_invalidate) {
tlb_flush(CPU(cpu), 1);
}
} }
void helper_slbie(CPUPPCState *env, target_ulong addr) void helper_slbie(CPUPPCState *env, target_ulong addr)
@ -138,7 +133,7 @@ void helper_slbie(CPUPPCState *env, target_ulong addr)
* and we still don't have a tlb_flush_mask(env, n, mask) * and we still don't have a tlb_flush_mask(env, n, mask)
* in QEMU, we just invalidate all TLBs * in QEMU, we just invalidate all TLBs
*/ */
tlb_flush(CPU(cpu), 1); env->tlb_need_flush = 1;
} }
} }

View File

@ -27,6 +27,7 @@
#include "exec/exec-all.h" #include "exec/exec-all.h"
#include "exec/cpu_ldst.h" #include "exec/cpu_ldst.h"
#include "exec/log.h" #include "exec/log.h"
#include "helper_regs.h"
//#define DEBUG_MMU //#define DEBUG_MMU
//#define DEBUG_BATS //#define DEBUG_BATS
@ -1924,6 +1925,7 @@ void ppc_tlb_invalidate_all(CPUPPCState *env)
case POWERPC_MMU_2_06a: case POWERPC_MMU_2_06a:
case POWERPC_MMU_2_07: case POWERPC_MMU_2_07:
case POWERPC_MMU_2_07a: case POWERPC_MMU_2_07a:
env->tlb_need_flush = 0;
#endif /* defined(TARGET_PPC64) */ #endif /* defined(TARGET_PPC64) */
tlb_flush(CPU(cpu), 1); tlb_flush(CPU(cpu), 1);
break; break;
@ -1986,7 +1988,7 @@ void ppc_tlb_invalidate_one(CPUPPCState *env, target_ulong addr)
* and we still don't have a tlb_flush_mask(env, n, mask) in QEMU, * and we still don't have a tlb_flush_mask(env, n, mask) in QEMU,
* we just invalidate all TLBs * we just invalidate all TLBs
*/ */
tlb_flush(CPU(cpu), 1); env->tlb_need_flush = 1;
break; break;
#endif /* defined(TARGET_PPC64) */ #endif /* defined(TARGET_PPC64) */
default: default:
@ -2875,6 +2877,11 @@ void helper_booke206_tlbflush(CPUPPCState *env, target_ulong type)
} }
void helper_check_tlb_flush(CPUPPCState *env)
{
check_tlb_flush(env);
}
/*****************************************************************************/ /*****************************************************************************/
/* try to fill the TLB and return an exception if error. If retaddr is /* try to fill the TLB and return an exception if error. If retaddr is

View File

@ -1392,6 +1392,19 @@ GEN_LOGICAL2(nand, tcg_gen_nand_tl, 0x0E, PPC_INTEGER);
/* nor & nor. */ /* nor & nor. */
GEN_LOGICAL2(nor, tcg_gen_nor_tl, 0x03, PPC_INTEGER); GEN_LOGICAL2(nor, tcg_gen_nor_tl, 0x03, PPC_INTEGER);
#if defined(TARGET_PPC64)
static void gen_pause(DisasContext *ctx)
{
TCGv_i32 t0 = tcg_const_i32(0);
tcg_gen_st_i32(t0, cpu_env,
-offsetof(PowerPCCPU, env) + offsetof(CPUState, halted));
tcg_temp_free_i32(t0);
/* Stop translation, this gives other CPUs a chance to run */
gen_exception_err(ctx, EXCP_HLT, 1);
}
#endif /* defined(TARGET_PPC64) */
/* or & or. */ /* or & or. */
static void gen_or(DisasContext *ctx) static void gen_or(DisasContext *ctx)
{ {
@ -1447,7 +1460,7 @@ static void gen_or(DisasContext *ctx)
} }
break; break;
case 7: case 7:
if (ctx->hv) { if (ctx->hv && !ctx->pr) {
/* Set process priority to very high */ /* Set process priority to very high */
prio = 7; prio = 7;
} }
@ -1464,6 +1477,10 @@ static void gen_or(DisasContext *ctx)
tcg_gen_ori_tl(t0, t0, ((uint64_t)prio) << 50); tcg_gen_ori_tl(t0, t0, ((uint64_t)prio) << 50);
gen_store_spr(SPR_PPR, t0); gen_store_spr(SPR_PPR, t0);
tcg_temp_free(t0); tcg_temp_free(t0);
/* Pause us out of TCG otherwise spin loops with smt_low
* eat too much CPU and the kernel hangs
*/
gen_pause(ctx);
} }
#endif #endif
} }
@ -1489,8 +1506,6 @@ static void gen_ori(DisasContext *ctx)
target_ulong uimm = UIMM(ctx->opcode); target_ulong uimm = UIMM(ctx->opcode);
if (rS(ctx->opcode) == rA(ctx->opcode) && uimm == 0) { if (rS(ctx->opcode) == rA(ctx->opcode) && uimm == 0) {
/* NOP */
/* XXX: should handle special NOPs for POWER series */
return; return;
} }
tcg_gen_ori_tl(cpu_gpr[rA(ctx->opcode)], cpu_gpr[rS(ctx->opcode)], uimm); tcg_gen_ori_tl(cpu_gpr[rA(ctx->opcode)], cpu_gpr[rS(ctx->opcode)], uimm);
@ -3275,9 +3290,32 @@ static void gen_eieio(DisasContext *ctx)
{ {
} }
#if !defined(CONFIG_USER_ONLY) && defined(TARGET_PPC64)
static inline void gen_check_tlb_flush(DisasContext *ctx)
{
TCGv_i32 t = tcg_temp_new_i32();
TCGLabel *l = gen_new_label();
tcg_gen_ld_i32(t, cpu_env, offsetof(CPUPPCState, tlb_need_flush));
tcg_gen_brcondi_i32(TCG_COND_EQ, t, 0, l);
gen_helper_check_tlb_flush(cpu_env);
gen_set_label(l);
tcg_temp_free_i32(t);
}
#else
static inline void gen_check_tlb_flush(DisasContext *ctx) { }
#endif
/* isync */ /* isync */
static void gen_isync(DisasContext *ctx) static void gen_isync(DisasContext *ctx)
{ {
/*
* We need to check for a pending TLB flush. This can only happen in
* kernel mode however so check MSR_PR
*/
if (!ctx->pr) {
gen_check_tlb_flush(ctx);
}
gen_stop_exception(ctx); gen_stop_exception(ctx);
} }
@ -3434,6 +3472,15 @@ STCX(stqcx_, 16);
/* sync */ /* sync */
static void gen_sync(DisasContext *ctx) static void gen_sync(DisasContext *ctx)
{ {
uint32_t l = (ctx->opcode >> 21) & 3;
/*
* For l == 2, it's a ptesync, We need to check for a pending TLB flush.
* This can only happen in kernel mode however so check MSR_PR as well.
*/
if (l == 2 && !ctx->pr) {
gen_check_tlb_flush(ctx);
}
} }
/* wait */ /* wait */
@ -4349,7 +4396,7 @@ static void gen_mtmsrd(DisasContext *ctx)
/* Special form that does not need any synchronisation */ /* Special form that does not need any synchronisation */
TCGv t0 = tcg_temp_new(); TCGv t0 = tcg_temp_new();
tcg_gen_andi_tl(t0, cpu_gpr[rS(ctx->opcode)], (1 << MSR_RI) | (1 << MSR_EE)); tcg_gen_andi_tl(t0, cpu_gpr[rS(ctx->opcode)], (1 << MSR_RI) | (1 << MSR_EE));
tcg_gen_andi_tl(cpu_msr, cpu_msr, ~((1 << MSR_RI) | (1 << MSR_EE))); tcg_gen_andi_tl(cpu_msr, cpu_msr, ~(target_ulong)((1 << MSR_RI) | (1 << MSR_EE)));
tcg_gen_or_tl(cpu_msr, cpu_msr, t0); tcg_gen_or_tl(cpu_msr, cpu_msr, t0);
tcg_temp_free(t0); tcg_temp_free(t0);
} else { } else {
@ -4380,7 +4427,7 @@ static void gen_mtmsr(DisasContext *ctx)
/* Special form that does not need any synchronisation */ /* Special form that does not need any synchronisation */
TCGv t0 = tcg_temp_new(); TCGv t0 = tcg_temp_new();
tcg_gen_andi_tl(t0, cpu_gpr[rS(ctx->opcode)], (1 << MSR_RI) | (1 << MSR_EE)); tcg_gen_andi_tl(t0, cpu_gpr[rS(ctx->opcode)], (1 << MSR_RI) | (1 << MSR_EE));
tcg_gen_andi_tl(cpu_msr, cpu_msr, ~((1 << MSR_RI) | (1 << MSR_EE))); tcg_gen_andi_tl(cpu_msr, cpu_msr, ~(target_ulong)((1 << MSR_RI) | (1 << MSR_EE)));
tcg_gen_or_tl(cpu_msr, cpu_msr, t0); tcg_gen_or_tl(cpu_msr, cpu_msr, t0);
tcg_temp_free(t0); tcg_temp_free(t0);
} else { } else {
@ -4826,7 +4873,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->pr)) { if (unlikely(ctx->pr || !ctx->hv)) {
gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC); gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC);
return; return;
} }
@ -4847,14 +4894,15 @@ 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->pr)) { if (unlikely(ctx->pr || !ctx->hv)) {
gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC); gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC);
return; return;
} }
/* This has no effect: it should ensure that all previous /* tlbsync is a nop for server, ptesync handles delayed tlb flush,
* tlbie have completed * embedded however needs to deal with tlbsync. We don't try to be
* fancy and swallow the overhead of checking for both.
*/ */
gen_stop_exception(ctx); gen_check_tlb_flush(ctx);
#endif #endif
} }
@ -4865,7 +4913,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->pr)) { if (unlikely(ctx->pr || !ctx->hv)) {
gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC); gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC);
return; return;
} }
@ -9913,8 +9961,10 @@ GEN_HANDLER2(slbmfee, "slbmfee", 0x1F, 0x13, 0x1C, 0x001F0001, PPC_SEGMENT_64B),
GEN_HANDLER2(slbmfev, "slbmfev", 0x1F, 0x13, 0x1A, 0x001F0001, PPC_SEGMENT_64B), GEN_HANDLER2(slbmfev, "slbmfev", 0x1F, 0x13, 0x1A, 0x001F0001, PPC_SEGMENT_64B),
#endif #endif
GEN_HANDLER(tlbia, 0x1F, 0x12, 0x0B, 0x03FFFC01, PPC_MEM_TLBIA), GEN_HANDLER(tlbia, 0x1F, 0x12, 0x0B, 0x03FFFC01, PPC_MEM_TLBIA),
GEN_HANDLER(tlbiel, 0x1F, 0x12, 0x08, 0x03FF0001, PPC_MEM_TLBIE), /* XXX Those instructions will need to be handled differently for
GEN_HANDLER(tlbie, 0x1F, 0x12, 0x09, 0x03FF0001, PPC_MEM_TLBIE), * different ISA versions */
GEN_HANDLER(tlbiel, 0x1F, 0x12, 0x08, 0x001F0001, PPC_MEM_TLBIE),
GEN_HANDLER(tlbie, 0x1F, 0x12, 0x09, 0x001F0001, PPC_MEM_TLBIE),
GEN_HANDLER(tlbsync, 0x1F, 0x16, 0x11, 0x03FFF801, PPC_MEM_TLBSYNC), GEN_HANDLER(tlbsync, 0x1F, 0x16, 0x11, 0x03FFF801, PPC_MEM_TLBSYNC),
#if defined(TARGET_PPC64) #if defined(TARGET_PPC64)
GEN_HANDLER(slbia, 0x1F, 0x12, 0x0F, 0x03FFFC01, PPC_SLBI), GEN_HANDLER(slbia, 0x1F, 0x12, 0x0F, 0x03FFFC01, PPC_SLBI),
@ -11220,8 +11270,9 @@ void ppc_cpu_dump_state(CPUState *cs, FILE *f, fprintf_function cpu_fprintf,
env->nip, env->lr, env->ctr, cpu_read_xer(env), env->nip, env->lr, env->ctr, cpu_read_xer(env),
cs->cpu_index); cs->cpu_index);
cpu_fprintf(f, "MSR " TARGET_FMT_lx " HID0 " TARGET_FMT_lx " HF " cpu_fprintf(f, "MSR " TARGET_FMT_lx " HID0 " TARGET_FMT_lx " HF "
TARGET_FMT_lx " idx %d\n", env->msr, env->spr[SPR_HID0], TARGET_FMT_lx " iidx %d didx %d\n",
env->hflags, env->mmu_idx); env->msr, env->spr[SPR_HID0],
env->hflags, env->immu_idx, env->dmmu_idx);
#if !defined(NO_TIMER_DUMP) #if !defined(NO_TIMER_DUMP)
cpu_fprintf(f, "TB %08" PRIu32 " %08" PRIu64 cpu_fprintf(f, "TB %08" PRIu32 " %08" PRIu64
#if !defined(CONFIG_USER_ONLY) #if !defined(CONFIG_USER_ONLY)
@ -11428,7 +11479,7 @@ void gen_intermediate_code(CPUPPCState *env, struct TranslationBlock *tb)
ctx.spr_cb = env->spr_cb; ctx.spr_cb = env->spr_cb;
ctx.pr = msr_pr; ctx.pr = msr_pr;
ctx.hv = !msr_pr && msr_hv; ctx.hv = !msr_pr && msr_hv;
ctx.mem_idx = env->mmu_idx; ctx.mem_idx = env->dmmu_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;
ctx.access_type = -1; ctx.access_type = -1;

View File

@ -8359,7 +8359,7 @@ POWERPC_FAMILY(POWER7)(ObjectClass *oc, void *data)
PPC_CACHE | PPC_CACHE_ICBI | PPC_CACHE_DCBZ | PPC_CACHE | PPC_CACHE_ICBI | PPC_CACHE_DCBZ |
PPC_MEM_SYNC | PPC_MEM_EIEIO | PPC_MEM_SYNC | PPC_MEM_EIEIO |
PPC_MEM_TLBIE | PPC_MEM_TLBSYNC | PPC_MEM_TLBIE | PPC_MEM_TLBSYNC |
PPC_64B | PPC_ALTIVEC | PPC_64B | PPC_64H | PPC_ALTIVEC |
PPC_SEGMENT_64B | PPC_SLBI | PPC_SEGMENT_64B | PPC_SLBI |
PPC_POPCNTB | PPC_POPCNTWD; PPC_POPCNTB | PPC_POPCNTWD;
pcc->insns_flags2 = PPC2_VSX | PPC2_DFP | PPC2_DBRX | PPC2_ISA205 | pcc->insns_flags2 = PPC2_VSX | PPC2_DFP | PPC2_DBRX | PPC2_ISA205 |
@ -8439,7 +8439,7 @@ POWERPC_FAMILY(POWER8)(ObjectClass *oc, void *data)
PPC_CACHE | PPC_CACHE_ICBI | PPC_CACHE_DCBZ | PPC_CACHE | PPC_CACHE_ICBI | PPC_CACHE_DCBZ |
PPC_MEM_SYNC | PPC_MEM_EIEIO | PPC_MEM_SYNC | PPC_MEM_EIEIO |
PPC_MEM_TLBIE | PPC_MEM_TLBSYNC | PPC_MEM_TLBIE | PPC_MEM_TLBSYNC |
PPC_64B | PPC_64BX | PPC_ALTIVEC | PPC_64B | PPC_64H | PPC_64BX | PPC_ALTIVEC |
PPC_SEGMENT_64B | PPC_SLBI | PPC_SEGMENT_64B | PPC_SLBI |
PPC_POPCNTB | PPC_POPCNTWD; PPC_POPCNTB | PPC_POPCNTWD;
pcc->insns_flags2 = PPC2_VSX | PPC2_VSX207 | PPC2_DFP | PPC2_DBRX | pcc->insns_flags2 = PPC2_VSX | PPC2_VSX207 | PPC2_DFP | PPC2_DBRX |