All of lore.kernel.org
 help / color / mirror / Atom feed
* [Qemu-devel] [PATCH 0/6] PPC: Add FSL (e500) MMU emulation v3
@ 2011-05-02 15:03 Alexander Graf
  2011-05-02 15:03 ` [Qemu-devel] [PATCH 1/6] PPC: Make MPC8544DS obey -cpu switch Alexander Graf
                   ` (6 more replies)
  0 siblings, 7 replies; 15+ messages in thread
From: Alexander Graf @ 2011-05-02 15:03 UTC (permalink / raw)
  To: QEMU-devel Developers; +Cc: Scott Wood, Edgar E. Iglesias, Liu Yu, Blue Swirl

In a global effort to get rid of KVM-only targets, this is the next
important piece of the puzzle: e500 emulation :).

We had support for running an e500 KVM guest for a while now, but the
code could not be tested without a real e500 machine, because it required
KVM to work. This patchset adds emulation for the e500 MMU, enabling
anyone to use the MPC8544DS emulation.

v1 -> v2:

  - fix linux-user build
  - optimize tlb invalidate & search

v2 -> v3:

  - add qdev patch (enables -drive if=virtio)
  - fix mpc initial tlb size comment
  - enable cpu reset

Alexander Graf (6):
  PPC: Make MPC8544DS obey -cpu switch
  PPC: Make MPC8544DS emulation work w/o KVM
  PPC: Add GS MSR definition
  PPC: Add another 64 bits to instruction feature mask
  PPC: Implement e500 (FSL) MMU
  PPC: Qdev'ify e500 pci

 hw/ppce500_mpc8544ds.c      |   92 ++++++++--
 hw/ppce500_pci.c            |  112 ++++++++----
 target-ppc/cpu.h            |  220 ++++++++++++++++++++++-
 target-ppc/helper.c         |  233 +++++++++++++++++++-----
 target-ppc/helper.h         |    5 +
 target-ppc/op_helper.c      |  418 +++++++++++++++++++++++++++++++++++++++++++
 target-ppc/translate.c      |  116 +++++++++++-
 target-ppc/translate_init.c |  246 ++++++++++++++++++--------
 8 files changed, 1253 insertions(+), 189 deletions(-)

^ permalink raw reply	[flat|nested] 15+ messages in thread

* [Qemu-devel] [PATCH 1/6] PPC: Make MPC8544DS obey -cpu switch
  2011-05-02 15:03 [Qemu-devel] [PATCH 0/6] PPC: Add FSL (e500) MMU emulation v3 Alexander Graf
@ 2011-05-02 15:03 ` Alexander Graf
  2011-05-02 15:03 ` [Qemu-devel] [PATCH 2/6] PPC: Make MPC8544DS emulation work w/o KVM Alexander Graf
                   ` (5 subsequent siblings)
  6 siblings, 0 replies; 15+ messages in thread
From: Alexander Graf @ 2011-05-02 15:03 UTC (permalink / raw)
  To: QEMU-devel Developers; +Cc: Scott Wood, Edgar E. Iglesias, Liu Yu, Blue Swirl

The MPC8544DS board emulation code ignored the user defined -cpu switch.
This patch enables it to only provide a sane default, not force an e500v2
CPU inside.

Signed-off-by: Alexander Graf <agraf@suse.de>
---
 hw/ppce500_mpc8544ds.c |    6 +++++-
 1 files changed, 5 insertions(+), 1 deletions(-)

diff --git a/hw/ppce500_mpc8544ds.c b/hw/ppce500_mpc8544ds.c
index e111dda..1b8a1c4 100644
--- a/hw/ppce500_mpc8544ds.c
+++ b/hw/ppce500_mpc8544ds.c
@@ -178,7 +178,11 @@ static void mpc8544ds_init(ram_addr_t ram_size,
     qemu_irq *irqs, *mpic, *pci_irqs;
 
     /* Setup CPU */
-    env = cpu_ppc_init("e500v2_v30");
+    if (cpu_model == NULL) {
+        cpu_model = "e500v2_v30";
+    }
+
+    env = cpu_ppc_init(cpu_model);
     if (!env) {
         fprintf(stderr, "Unable to initialize CPU!\n");
         exit(1);
-- 
1.6.0.2

^ permalink raw reply related	[flat|nested] 15+ messages in thread

* [Qemu-devel] [PATCH 2/6] PPC: Make MPC8544DS emulation work w/o KVM
  2011-05-02 15:03 [Qemu-devel] [PATCH 0/6] PPC: Add FSL (e500) MMU emulation v3 Alexander Graf
  2011-05-02 15:03 ` [Qemu-devel] [PATCH 1/6] PPC: Make MPC8544DS obey -cpu switch Alexander Graf
@ 2011-05-02 15:03 ` Alexander Graf
  2011-05-02 15:03 ` [Qemu-devel] [PATCH 3/6] PPC: Add GS MSR definition Alexander Graf
                   ` (4 subsequent siblings)
  6 siblings, 0 replies; 15+ messages in thread
From: Alexander Graf @ 2011-05-02 15:03 UTC (permalink / raw)
  To: QEMU-devel Developers; +Cc: Scott Wood, Edgar E. Iglesias, Liu Yu, Blue Swirl

The MPC8544DS board emulation was only used with KVM so far, so some
parts of the code didn't provide proper values for non-KVM execution.

This patch makes the machine work without KVM enabled. To actually use
this, you also need proper e500v2 MMU emulation.

Signed-off-by: Alexander Graf <agraf@suse.de>

---

v2 -> v3:

  - fix mpc initial tlb size comment
  - enable cpu reset
---
 hw/ppce500_mpc8544ds.c |   86 +++++++++++++++++++++++++++++++++++++++--------
 1 files changed, 71 insertions(+), 15 deletions(-)

diff --git a/hw/ppce500_mpc8544ds.c b/hw/ppce500_mpc8544ds.c
index 1b8a1c4..44d6440 100644
--- a/hw/ppce500_mpc8544ds.c
+++ b/hw/ppce500_mpc8544ds.c
@@ -28,6 +28,7 @@
 #include "kvm_ppc.h"
 #include "device_tree.h"
 #include "openpic.h"
+#include "ppc.h"
 #include "ppce500.h"
 #include "loader.h"
 #include "elf.h"
@@ -50,6 +51,12 @@
 #define MPC8544_PCI_IO             0xE1000000
 #define MPC8544_PCI_IOLEN          0x10000
 
+static struct boot_info
+{
+    uint32_t dt_base;
+    uint32_t entry;
+} boot_info;
+
 #ifdef CONFIG_FDT
 static int mpc8544_copy_soc_cell(void *fdt, const char *node, const char *prop)
 {
@@ -82,7 +89,7 @@ static int mpc8544_load_device_tree(target_phys_addr_t addr,
 {
     int ret = -1;
 #ifdef CONFIG_FDT
-    uint32_t mem_reg_property[] = {0, ramsize};
+    uint32_t mem_reg_property[] = {0, cpu_to_be32(ramsize)};
     char *filename;
     int fdt_size;
     void *fdt;
@@ -103,15 +110,19 @@ static int mpc8544_load_device_tree(target_phys_addr_t addr,
     if (ret < 0)
         fprintf(stderr, "couldn't set /memory/reg\n");
 
-    ret = qemu_devtree_setprop_cell(fdt, "/chosen", "linux,initrd-start",
-                                    initrd_base);
-    if (ret < 0)
-        fprintf(stderr, "couldn't set /chosen/linux,initrd-start\n");
+    if (initrd_size) {
+        ret = qemu_devtree_setprop_cell(fdt, "/chosen", "linux,initrd-start",
+                                        initrd_base);
+        if (ret < 0) {
+            fprintf(stderr, "couldn't set /chosen/linux,initrd-start\n");
+        }
 
-    ret = qemu_devtree_setprop_cell(fdt, "/chosen", "linux,initrd-end",
-                                    (initrd_base + initrd_size));
-    if (ret < 0)
-        fprintf(stderr, "couldn't set /chosen/linux,initrd-end\n");
+        ret = qemu_devtree_setprop_cell(fdt, "/chosen", "linux,initrd-end",
+                                        (initrd_base + initrd_size));
+        if (ret < 0) {
+            fprintf(stderr, "couldn't set /chosen/linux,initrd-end\n");
+        }
+    }
 
     ret = qemu_devtree_setprop_string(fdt, "/chosen", "bootargs",
                                       kernel_cmdline);
@@ -145,6 +156,13 @@ static int mpc8544_load_device_tree(target_phys_addr_t addr,
 
         mpc8544_copy_soc_cell(fdt, buf, "clock-frequency");
         mpc8544_copy_soc_cell(fdt, buf, "timebase-frequency");
+    } else {
+        const uint32_t freq = 400000000;
+
+        qemu_devtree_setprop_cell(fdt, "/cpus/PowerPC,8544@0",
+                                  "clock-frequency", freq);
+        qemu_devtree_setprop_cell(fdt, "/cpus/PowerPC,8544@0",
+                                  "timebase-frequency", freq);
     }
 
     ret = rom_add_blob_fixed(BINARY_DEVICE_TREE_FILE, fdt, fdt_size, addr);
@@ -156,6 +174,35 @@ out:
     return ret;
 }
 
+/* Create -kernel TLB entries for BookE, linearly spanning 256MB.  */
+static void mmubooke_create_initial_mapping(CPUState *env,
+                                     target_ulong va,
+                                     target_phys_addr_t pa)
+{
+    ppcemb_tlb_t *tlb = &env->tlb[512].tlbe;
+
+    tlb->attr = 0;
+    tlb->prot = PAGE_VALID | ((PAGE_READ | PAGE_WRITE | PAGE_EXEC) << 4);
+    tlb->size = 256 * 1024 * 1024;
+    tlb->EPN = va & TARGET_PAGE_MASK;
+    tlb->RPN = pa & TARGET_PAGE_MASK;
+    tlb->PID = 0;
+}
+
+static void mpc8544ds_cpu_reset(void *opaque)
+{
+    CPUState *env = opaque;
+    struct boot_info *bi = env->load_info;
+
+    cpu_reset(env);
+
+    /* Set initial guest state. */
+    env->gpr[1] = (16<<20) - 8;
+    env->gpr[3] = bi->dt_base;
+    env->nip = bi->entry;
+    mmubooke_create_initial_mapping(env, 0, 0);
+}
+
 static void mpc8544ds_init(ram_addr_t ram_size,
                          const char *boot_device,
                          const char *kernel_filename,
@@ -188,6 +235,13 @@ static void mpc8544ds_init(ram_addr_t ram_size,
         exit(1);
     }
 
+    /* XXX register timer? */
+    ppc_emb_timers_init(env, 400000000, PPC_INTERRUPT_DECR);
+    ppc_dcr_init(env, NULL, NULL);
+
+    /* Register reset handler */
+    qemu_register_reset(mpc8544ds_cpu_reset, env);
+
     /* Fixup Memory size on a alignment boundary */
     ram_size &= ~(RAM_SIZES_ALIGN - 1);
 
@@ -265,6 +319,9 @@ static void mpc8544ds_init(ram_addr_t ram_size,
 
     /* If we're loading a kernel directly, we must load the device tree too. */
     if (kernel_filename) {
+#ifndef CONFIG_FDT
+        cpu_abort(env, "Compiled without FDT support - can't load kernel\n");
+#endif
         dt_base = (kernel_size + DTC_LOAD_PAD) & ~DTC_PAD_MASK;
         if (mpc8544_load_device_tree(dt_base, ram_size,
                     initrd_base, initrd_size, kernel_cmdline) < 0) {
@@ -272,15 +329,14 @@ static void mpc8544ds_init(ram_addr_t ram_size,
             exit(1);
         }
 
-        /* Set initial guest state. */
-        env->gpr[1] = (16<<20) - 8;
-        env->gpr[3] = dt_base;
-        env->nip = entry;
-        /* XXX we currently depend on KVM to create some initial TLB entries. */
+        boot_info.entry = entry;
+        boot_info.dt_base = dt_base;
     }
+    env->load_info = &boot_info;
 
-    if (kvm_enabled())
+    if (kvm_enabled()) {
         kvmppc_init();
+    }
 
     return;
 }
-- 
1.6.0.2

^ permalink raw reply related	[flat|nested] 15+ messages in thread

* [Qemu-devel] [PATCH 3/6] PPC: Add GS MSR definition
  2011-05-02 15:03 [Qemu-devel] [PATCH 0/6] PPC: Add FSL (e500) MMU emulation v3 Alexander Graf
  2011-05-02 15:03 ` [Qemu-devel] [PATCH 1/6] PPC: Make MPC8544DS obey -cpu switch Alexander Graf
  2011-05-02 15:03 ` [Qemu-devel] [PATCH 2/6] PPC: Make MPC8544DS emulation work w/o KVM Alexander Graf
@ 2011-05-02 15:03 ` Alexander Graf
  2011-05-02 15:03 ` [Qemu-devel] [PATCH 4/6] PPC: Add another 64 bits to instruction feature mask Alexander Graf
                   ` (3 subsequent siblings)
  6 siblings, 0 replies; 15+ messages in thread
From: Alexander Graf @ 2011-05-02 15:03 UTC (permalink / raw)
  To: QEMU-devel Developers; +Cc: Scott Wood, Edgar E. Iglesias, Liu Yu, Blue Swirl

The BookE specification defines MSR bit 28 as Guest State. Add it
to the list of MSR macros.

Signed-off-by: Alexander Graf <agraf@suse.de>
---
 target-ppc/cpu.h |    2 ++
 1 files changed, 2 insertions(+), 0 deletions(-)

diff --git a/target-ppc/cpu.h b/target-ppc/cpu.h
index 04b1259..fd599fc 100644
--- a/target-ppc/cpu.h
+++ b/target-ppc/cpu.h
@@ -420,6 +420,7 @@ struct ppc_slb_t {
 #define MSR_CM   31 /* Computation mode for BookE                     hflags */
 #define MSR_ICM  30 /* Interrupt computation mode for BookE                  */
 #define MSR_THV  29 /* hypervisor state for 32 bits PowerPC           hflags */
+#define MSR_GS   28 /* guest state for BookE                                 */
 #define MSR_UCLE 26 /* User-mode cache lock enable for BookE                 */
 #define MSR_VR   25 /* altivec available                            x hflags */
 #define MSR_SPE  25 /* SPE enable for BookE                         x hflags */
@@ -457,6 +458,7 @@ struct ppc_slb_t {
 #define msr_cm   ((env->msr >> MSR_CM)   & 1)
 #define msr_icm  ((env->msr >> MSR_ICM)  & 1)
 #define msr_thv  ((env->msr >> MSR_THV)  & 1)
+#define msr_gs   ((env->msr >> MSR_GS)   & 1)
 #define msr_ucle ((env->msr >> MSR_UCLE) & 1)
 #define msr_vr   ((env->msr >> MSR_VR)   & 1)
 #define msr_spe  ((env->msr >> MSR_SPE)  & 1)
-- 
1.6.0.2

^ permalink raw reply related	[flat|nested] 15+ messages in thread

* [Qemu-devel] [PATCH 4/6] PPC: Add another 64 bits to instruction feature mask
  2011-05-02 15:03 [Qemu-devel] [PATCH 0/6] PPC: Add FSL (e500) MMU emulation v3 Alexander Graf
                   ` (2 preceding siblings ...)
  2011-05-02 15:03 ` [Qemu-devel] [PATCH 3/6] PPC: Add GS MSR definition Alexander Graf
@ 2011-05-02 15:03 ` Alexander Graf
  2011-05-02 15:03 ` [Qemu-devel] [PATCH 5/6] PPC: Implement e500 (FSL) MMU Alexander Graf
                   ` (2 subsequent siblings)
  6 siblings, 0 replies; 15+ messages in thread
From: Alexander Graf @ 2011-05-02 15:03 UTC (permalink / raw)
  To: QEMU-devel Developers; +Cc: Scott Wood, Edgar E. Iglesias, Liu Yu, Blue Swirl

To enable quick runtime detection of instruction groups to the currently
selected CPU emulation, we have a feature mask of what exactly the respective
instruction supports.

This feature mask is 64 bits long and we just successfully exceeded those 64
bits. To add more features, we need to think of something.

The easiest solution that came to my mind was to simply add another 64 bits
that we can also match on. Since the comparison is only done on start of the
qemu process to generate an internal opcode calling table, we should be fine
on any performance penalties here.

Signed-off-by: Alexander Graf <agraf@suse.de>
---
 target-ppc/cpu.h            |    1 +
 target-ppc/translate.c      |   25 +++++++--
 target-ppc/translate_init.c |  123 +++++++++++++++++++++++++++++++------------
 3 files changed, 110 insertions(+), 39 deletions(-)

diff --git a/target-ppc/cpu.h b/target-ppc/cpu.h
index fd599fc..b8d9049 100644
--- a/target-ppc/cpu.h
+++ b/target-ppc/cpu.h
@@ -722,6 +722,7 @@ struct CPUPPCState {
     int bfd_mach;
     uint32_t flags;
     uint64_t insns_flags;
+    uint64_t insns_flags2;
 
 #if defined(TARGET_PPC64) && !defined(CONFIG_USER_ONLY)
     target_phys_addr_t vpa;
diff --git a/target-ppc/translate.c b/target-ppc/translate.c
index a943dbc..9076df0 100644
--- a/target-ppc/translate.c
+++ b/target-ppc/translate.c
@@ -200,6 +200,8 @@ struct opc_handler_t {
     uint32_t inval;
     /* instruction type */
     uint64_t type;
+    /* extended instruction type */
+    uint64_t type2;
     /* handler */
     void (*handler)(DisasContext *ctx);
 #if defined(DO_PPC_STATISTICS) || defined(PPC_DUMP_CPU)
@@ -313,10 +315,16 @@ static inline void gen_sync_exception(DisasContext *ctx)
 }
 
 #define GEN_HANDLER(name, opc1, opc2, opc3, inval, type)                      \
-GEN_OPCODE(name, opc1, opc2, opc3, inval, type)
+GEN_OPCODE(name, opc1, opc2, opc3, inval, type, PPC_NONE)
+
+#define GEN_HANDLER_E(name, opc1, opc2, opc3, inval, type, type2)             \
+GEN_OPCODE(name, opc1, opc2, opc3, inval, type, type2)
 
 #define GEN_HANDLER2(name, onam, opc1, opc2, opc3, inval, type)               \
-GEN_OPCODE2(name, onam, opc1, opc2, opc3, inval, type)
+GEN_OPCODE2(name, onam, opc1, opc2, opc3, inval, type, PPC_NONE)
+
+#define GEN_HANDLER2_E(name, onam, opc1, opc2, opc3, inval, type, type2)      \
+GEN_OPCODE2(name, onam, opc1, opc2, opc3, inval, type, type2)
 
 typedef struct opcode_t {
     unsigned char opc1, opc2, opc3;
@@ -456,7 +464,7 @@ static inline target_ulong MASK(uint32_t start, uint32_t end)
 /* PowerPC instructions table                                                */
 
 #if defined(DO_PPC_STATISTICS)
-#define GEN_OPCODE(name, op1, op2, op3, invl, _typ)                           \
+#define GEN_OPCODE(name, op1, op2, op3, invl, _typ, _typ2)                    \
 {                                                                             \
     .opc1 = op1,                                                              \
     .opc2 = op2,                                                              \
@@ -465,12 +473,13 @@ static inline target_ulong MASK(uint32_t start, uint32_t end)
     .handler = {                                                              \
         .inval   = invl,                                                      \
         .type = _typ,                                                         \
+        .type2 = _typ2,                                                       \
         .handler = &gen_##name,                                               \
         .oname = stringify(name),                                             \
     },                                                                        \
     .oname = stringify(name),                                                 \
 }
-#define GEN_OPCODE2(name, onam, op1, op2, op3, invl, _typ)                    \
+#define GEN_OPCODE2(name, onam, op1, op2, op3, invl, _typ, _typ2)             \
 {                                                                             \
     .opc1 = op1,                                                              \
     .opc2 = op2,                                                              \
@@ -479,13 +488,14 @@ static inline target_ulong MASK(uint32_t start, uint32_t end)
     .handler = {                                                              \
         .inval   = invl,                                                      \
         .type = _typ,                                                         \
+        .type2 = _typ2,                                                       \
         .handler = &gen_##name,                                               \
         .oname = onam,                                                        \
     },                                                                        \
     .oname = onam,                                                            \
 }
 #else
-#define GEN_OPCODE(name, op1, op2, op3, invl, _typ)                           \
+#define GEN_OPCODE(name, op1, op2, op3, invl, _typ, _typ2)                    \
 {                                                                             \
     .opc1 = op1,                                                              \
     .opc2 = op2,                                                              \
@@ -494,11 +504,12 @@ static inline target_ulong MASK(uint32_t start, uint32_t end)
     .handler = {                                                              \
         .inval   = invl,                                                      \
         .type = _typ,                                                         \
+        .type2 = _typ2,                                                       \
         .handler = &gen_##name,                                               \
     },                                                                        \
     .oname = stringify(name),                                                 \
 }
-#define GEN_OPCODE2(name, onam, op1, op2, op3, invl, _typ)                    \
+#define GEN_OPCODE2(name, onam, op1, op2, op3, invl, _typ, _typ2)             \
 {                                                                             \
     .opc1 = op1,                                                              \
     .opc2 = op2,                                                              \
@@ -507,6 +518,7 @@ static inline target_ulong MASK(uint32_t start, uint32_t end)
     .handler = {                                                              \
         .inval   = invl,                                                      \
         .type = _typ,                                                         \
+        .type2 = _typ2,                                                       \
         .handler = &gen_##name,                                               \
     },                                                                        \
     .oname = onam,                                                            \
@@ -533,6 +545,7 @@ static void gen_invalid(DisasContext *ctx)
 static opc_handler_t invalid_handler = {
     .inval   = 0xFFFFFFFF,
     .type    = PPC_NONE,
+    .type2   = PPC_NONE,
     .handler = gen_invalid,
 };
 
diff --git a/target-ppc/translate_init.c b/target-ppc/translate_init.c
index e2a83c5..aec0e13 100644
--- a/target-ppc/translate_init.c
+++ b/target-ppc/translate_init.c
@@ -37,6 +37,7 @@ struct ppc_def_t {
     uint32_t pvr;
     uint32_t svr;
     uint64_t insns_flags;
+    uint64_t insns_flags2;
     uint64_t msr_mask;
     powerpc_mmu_t   mmu_model;
     powerpc_excp_t  excp_model;
@@ -3201,6 +3202,7 @@ static int check_pow_hid0_74xx (CPUPPCState *env)
                               PPC_CACHE_DCBZ |                                \
                               PPC_MEM_SYNC | PPC_MEM_EIEIO |                  \
                               PPC_4xx_COMMON | PPC_40x_EXCP)
+#define POWERPC_INSNS2_401   (PPC_NONE)
 #define POWERPC_MSRM_401     (0x00000000000FD201ULL)
 #define POWERPC_MMU_401      (POWERPC_MMU_REAL)
 #define POWERPC_EXCP_401     (POWERPC_EXCP_40x)
@@ -3230,6 +3232,7 @@ static void init_proc_401 (CPUPPCState *env)
                               PPC_MEM_SYNC | PPC_MEM_EIEIO |                  \
                               PPC_40x_TLB | PPC_MEM_TLBIA | PPC_MEM_TLBSYNC | \
                               PPC_4xx_COMMON | PPC_40x_EXCP)
+#define POWERPC_INSNS2_401x2 (PPC_NONE)
 #define POWERPC_MSRM_401x2   (0x00000000001FD231ULL)
 #define POWERPC_MMU_401x2    (POWERPC_MMU_SOFT_4xx_Z)
 #define POWERPC_EXCP_401x2   (POWERPC_EXCP_40x)
@@ -3266,6 +3269,7 @@ static void init_proc_401x2 (CPUPPCState *env)
                               PPC_MEM_SYNC | PPC_MEM_EIEIO |                  \
                               PPC_40x_TLB | PPC_MEM_TLBIA | PPC_MEM_TLBSYNC | \
                               PPC_4xx_COMMON | PPC_40x_EXCP)
+#define POWERPC_INSNS2_401x3 (PPC_NONE)
 #define POWERPC_MSRM_401x3   (0x00000000001FD631ULL)
 #define POWERPC_MMU_401x3    (POWERPC_MMU_SOFT_4xx_Z)
 #define POWERPC_EXCP_401x3   (POWERPC_EXCP_40x)
@@ -3298,6 +3302,7 @@ static void init_proc_401x3 (CPUPPCState *env)
                               PPC_MEM_SYNC | PPC_MEM_EIEIO |                  \
                               PPC_40x_TLB | PPC_MEM_TLBIA | PPC_MEM_TLBSYNC | \
                               PPC_4xx_COMMON | PPC_40x_EXCP)
+#define POWERPC_INSNS2_IOP480 (PPC_NONE)
 #define POWERPC_MSRM_IOP480  (0x00000000001FD231ULL)
 #define POWERPC_MMU_IOP480   (POWERPC_MMU_SOFT_4xx_Z)
 #define POWERPC_EXCP_IOP480  (POWERPC_EXCP_40x)
@@ -3333,6 +3338,7 @@ static void init_proc_IOP480 (CPUPPCState *env)
                               PPC_CACHE_DCBZ |                                \
                               PPC_MEM_SYNC | PPC_MEM_EIEIO |                  \
                               PPC_4xx_COMMON | PPC_40x_EXCP)
+#define POWERPC_INSNS2_403   (PPC_NONE)
 #define POWERPC_MSRM_403     (0x000000000007D00DULL)
 #define POWERPC_MMU_403      (POWERPC_MMU_REAL)
 #define POWERPC_EXCP_403     (POWERPC_EXCP_40x)
@@ -3363,6 +3369,7 @@ static void init_proc_403 (CPUPPCState *env)
                               PPC_MEM_SYNC | PPC_MEM_EIEIO |                  \
                               PPC_40x_TLB | PPC_MEM_TLBIA | PPC_MEM_TLBSYNC | \
                               PPC_4xx_COMMON | PPC_40x_EXCP)
+#define POWERPC_INSNS2_403GCX (PPC_NONE)
 #define POWERPC_MSRM_403GCX  (0x000000000007D00DULL)
 #define POWERPC_MMU_403GCX   (POWERPC_MMU_SOFT_4xx_Z)
 #define POWERPC_EXCP_403GCX  (POWERPC_EXCP_40x)
@@ -3411,6 +3418,7 @@ static void init_proc_403GCX (CPUPPCState *env)
                               PPC_MEM_SYNC | PPC_MEM_EIEIO |                  \
                               PPC_40x_TLB | PPC_MEM_TLBIA | PPC_MEM_TLBSYNC | \
                               PPC_4xx_COMMON | PPC_405_MAC | PPC_40x_EXCP)
+#define POWERPC_INSNS2_405   (PPC_NONE)
 #define POWERPC_MSRM_405     (0x000000000006E630ULL)
 #define POWERPC_MMU_405      (POWERPC_MMU_SOFT_4xx)
 #define POWERPC_EXCP_405     (POWERPC_EXCP_40x)
@@ -3458,6 +3466,7 @@ static void init_proc_405 (CPUPPCState *env)
                               PPC_MEM_TLBSYNC | PPC_MFTB |                    \
                               PPC_BOOKE | PPC_4xx_COMMON | PPC_405_MAC |      \
                               PPC_440_SPEC)
+#define POWERPC_INSNS2_440EP (PPC_NONE)
 #define POWERPC_MSRM_440EP   (0x000000000006D630ULL)
 #define POWERPC_MMU_440EP    (POWERPC_MMU_BOOKE)
 #define POWERPC_EXCP_440EP   (POWERPC_EXCP_BOOKE)
@@ -3538,6 +3547,7 @@ static void init_proc_440EP (CPUPPCState *env)
                               PPC_MEM_TLBSYNC | PPC_TLBIVA | PPC_MFTB |       \
                               PPC_BOOKE | PPC_4xx_COMMON | PPC_405_MAC |      \
                               PPC_440_SPEC)
+#define POWERPC_INSNS2_440GP (PPC_NONE)
 #define POWERPC_MSRM_440GP   (0x000000000006FF30ULL)
 #define POWERPC_MMU_440GP    (POWERPC_MMU_BOOKE)
 #define POWERPC_EXCP_440GP   (POWERPC_EXCP_BOOKE)
@@ -3600,6 +3610,7 @@ static void init_proc_440GP (CPUPPCState *env)
                               PPC_MEM_TLBSYNC | PPC_MFTB |                    \
                               PPC_BOOKE | PPC_4xx_COMMON | PPC_405_MAC |      \
                               PPC_440_SPEC)
+#define POWERPC_INSNS2_440x4 (PPC_NONE)
 #define POWERPC_MSRM_440x4   (0x000000000006FF30ULL)
 #define POWERPC_MMU_440x4    (POWERPC_MMU_BOOKE)
 #define POWERPC_EXCP_440x4   (POWERPC_EXCP_BOOKE)
@@ -3662,6 +3673,7 @@ static void init_proc_440x4 (CPUPPCState *env)
                               PPC_MEM_TLBSYNC | PPC_MFTB |                    \
                               PPC_BOOKE | PPC_4xx_COMMON | PPC_405_MAC |      \
                               PPC_440_SPEC)
+#define POWERPC_INSNS2_440x5 (PPC_NONE)
 #define POWERPC_MSRM_440x5   (0x000000000006FF30ULL)
 #define POWERPC_MMU_440x5    (POWERPC_MMU_BOOKE)
 #define POWERPC_EXCP_440x5   (POWERPC_EXCP_BOOKE)
@@ -3742,6 +3754,7 @@ static void init_proc_440x5 (CPUPPCState *env)
                               PPC_MEM_TLBSYNC | PPC_TLBIVA |                  \
                               PPC_BOOKE | PPC_4xx_COMMON | PPC_405_MAC |      \
                               PPC_440_SPEC)
+#define POWERPC_INSNS2_460   (PPC_NONE)
 #define POWERPC_MSRM_460     (0x000000000006FF30ULL)
 #define POWERPC_MMU_460      (POWERPC_MMU_BOOKE)
 #define POWERPC_EXCP_460     (POWERPC_EXCP_BOOKE)
@@ -3831,6 +3844,7 @@ static void init_proc_460 (CPUPPCState *env)
                               PPC_MEM_TLBSYNC | PPC_TLBIVA |                  \
                               PPC_BOOKE | PPC_4xx_COMMON | PPC_405_MAC |      \
                               PPC_440_SPEC)
+#define POWERPC_INSNS2_460F  (PPC_NONE)
 #define POWERPC_MSRM_460     (0x000000000006FF30ULL)
 #define POWERPC_MMU_460F     (POWERPC_MMU_BOOKE)
 #define POWERPC_EXCP_460F    (POWERPC_EXCP_BOOKE)
@@ -3913,6 +3927,7 @@ static void init_proc_460F (CPUPPCState *env)
                               PPC_MEM_EIEIO | PPC_MEM_SYNC |                  \
                               PPC_CACHE_ICBI | PPC_FLOAT | PPC_FLOAT_STFIWX | \
                               PPC_MFTB)
+#define POWERPC_INSNS2_MPC5xx (PPC_NONE)
 #define POWERPC_MSRM_MPC5xx  (0x000000000001FF43ULL)
 #define POWERPC_MMU_MPC5xx   (POWERPC_MMU_REAL)
 #define POWERPC_EXCP_MPC5xx  (POWERPC_EXCP_603)
@@ -3939,6 +3954,7 @@ static void init_proc_MPC5xx (CPUPPCState *env)
 #define POWERPC_INSNS_MPC8xx (PPC_INSNS_BASE | PPC_STRING  |                  \
                               PPC_MEM_EIEIO | PPC_MEM_SYNC |                  \
                               PPC_CACHE_ICBI | PPC_MFTB)
+#define POWERPC_INSNS2_MPC8xx (PPC_NONE)
 #define POWERPC_MSRM_MPC8xx  (0x000000000001F673ULL)
 #define POWERPC_MMU_MPC8xx   (POWERPC_MMU_MPC8xx)
 #define POWERPC_EXCP_MPC8xx  (POWERPC_EXCP_603)
@@ -3970,6 +3986,7 @@ static void init_proc_MPC8xx (CPUPPCState *env)
                               PPC_MEM_SYNC | PPC_MEM_EIEIO |                  \
                               PPC_MEM_TLBIE | PPC_MEM_TLBSYNC | PPC_6xx_TLB | \
                               PPC_SEGMENT | PPC_EXTERN)
+#define POWERPC_INSNS2_G2    (PPC_NONE)
 #define POWERPC_MSRM_G2      (0x000000000006FFF2ULL)
 #define POWERPC_MMU_G2       (POWERPC_MMU_SOFT_6xx)
 //#define POWERPC_EXCP_G2      (POWERPC_EXCP_G2)
@@ -4027,6 +4044,7 @@ static void init_proc_G2 (CPUPPCState *env)
                               PPC_MEM_SYNC | PPC_MEM_EIEIO |                  \
                               PPC_MEM_TLBIE | PPC_MEM_TLBSYNC | PPC_6xx_TLB | \
                               PPC_SEGMENT | PPC_EXTERN)
+#define POWERPC_INSNS2_G2LE  (PPC_NONE)
 #define POWERPC_MSRM_G2LE    (0x000000000007FFF3ULL)
 #define POWERPC_MMU_G2LE     (POWERPC_MMU_SOFT_6xx)
 #define POWERPC_EXCP_G2LE    (POWERPC_EXCP_G2)
@@ -4093,6 +4111,7 @@ static void init_proc_G2LE (CPUPPCState *env)
                               PPC_CACHE_DCBZ | PPC_CACHE_DCBA |               \
                               PPC_MEM_TLBSYNC | PPC_TLBIVAX |                 \
                               PPC_BOOKE)
+#define POWERPC_INSNS2_e200  (PPC_NONE)
 #define POWERPC_MSRM_e200    (0x000000000606FF30ULL)
 #define POWERPC_MMU_e200     (POWERPC_MMU_BOOKE_FSL)
 #define POWERPC_EXCP_e200    (POWERPC_EXCP_BOOKE)
@@ -4213,6 +4232,7 @@ static void init_proc_e200 (CPUPPCState *env)
                               PPC_MEM_SYNC | PPC_MEM_EIEIO |                  \
                               PPC_MEM_TLBIE | PPC_MEM_TLBSYNC | PPC_6xx_TLB | \
                               PPC_SEGMENT | PPC_EXTERN)
+#define POWERPC_INSNS2_e300  (PPC_NONE)
 #define POWERPC_MSRM_e300    (0x000000000007FFF3ULL)
 #define POWERPC_MMU_e300     (POWERPC_MMU_SOFT_6xx)
 #define POWERPC_EXCP_e300    (POWERPC_EXCP_603)
@@ -4264,6 +4284,7 @@ static void init_proc_e300 (CPUPPCState *env)
                                 PPC_CACHE_DCBZ | PPC_CACHE_DCBA |       \
                                 PPC_MEM_TLBSYNC | PPC_TLBIVAX |         \
                                 PPC_BOOKE)
+#define POWERPC_INSNS2_e500v1  (PPC_NONE)
 #define POWERPC_MSRM_e500v1    (0x000000000606FF30ULL)
 #define POWERPC_MMU_e500v1     (POWERPC_MMU_BOOKE_FSL)
 #define POWERPC_EXCP_e500v1    (POWERPC_EXCP_BOOKE)
@@ -4283,6 +4304,7 @@ static void init_proc_e300 (CPUPPCState *env)
                                 PPC_CACHE_DCBZ | PPC_CACHE_DCBA |       \
                                 PPC_MEM_TLBSYNC | PPC_TLBIVAX |         \
                                 PPC_BOOKE)
+#define POWERPC_INSNS2_e500v2  (PPC_NONE)
 #define POWERPC_MSRM_e500v2    (0x000000000606FF30ULL)
 #define POWERPC_MMU_e500v2     (POWERPC_MMU_BOOKE_FSL)
 #define POWERPC_EXCP_e500v2    (POWERPC_EXCP_BOOKE)
@@ -4414,6 +4436,7 @@ static void init_proc_e500 (CPUPPCState *env)
                               PPC_CACHE | PPC_CACHE_ICBI | PPC_CACHE_DCBZ |   \
                               PPC_MEM_SYNC | PPC_MEM_EIEIO | PPC_MEM_TLBIE |  \
                               PPC_SEGMENT | PPC_EXTERN)
+#define POWERPC_INSNS2_601   (PPC_NONE)
 #define POWERPC_MSRM_601     (0x000000000000FD70ULL)
 #define POWERPC_MSRR_601     (0x0000000000001040ULL)
 //#define POWERPC_MMU_601      (POWERPC_MMU_601)
@@ -4466,6 +4489,7 @@ static void init_proc_601 (CPUPPCState *env)
                               PPC_CACHE | PPC_CACHE_ICBI | PPC_CACHE_DCBZ |   \
                               PPC_MEM_SYNC | PPC_MEM_EIEIO | PPC_MEM_TLBIE |  \
                               PPC_SEGMENT | PPC_EXTERN)
+#define POWERPC_INSNS2_601v  (PPC_NONE)
 #define POWERPC_MSRM_601v    (0x000000000000FD70ULL)
 #define POWERPC_MSRR_601v    (0x0000000000001040ULL)
 #define POWERPC_MMU_601v     (POWERPC_MMU_601)
@@ -4493,6 +4517,7 @@ static void init_proc_601v (CPUPPCState *env)
                               PPC_MEM_SYNC | PPC_MEM_EIEIO |                  \
                               PPC_MEM_TLBIE | PPC_6xx_TLB | PPC_MEM_TLBSYNC | \
                               PPC_SEGMENT | PPC_602_SPEC)
+#define POWERPC_INSNS2_602   (PPC_NONE)
 #define POWERPC_MSRM_602     (0x0000000000C7FF73ULL)
 /* XXX: 602 MMU is quite specific. Should add a special case */
 #define POWERPC_MMU_602      (POWERPC_MMU_SOFT_6xx)
@@ -4538,6 +4563,7 @@ static void init_proc_602 (CPUPPCState *env)
                               PPC_MEM_SYNC | PPC_MEM_EIEIO |                  \
                               PPC_MEM_TLBIE | PPC_MEM_TLBSYNC | PPC_6xx_TLB | \
                               PPC_SEGMENT | PPC_EXTERN)
+#define POWERPC_INSNS2_603   (PPC_NONE)
 #define POWERPC_MSRM_603     (0x000000000007FF73ULL)
 #define POWERPC_MMU_603      (POWERPC_MMU_SOFT_6xx)
 //#define POWERPC_EXCP_603     (POWERPC_EXCP_603)
@@ -4582,6 +4608,7 @@ static void init_proc_603 (CPUPPCState *env)
                               PPC_MEM_SYNC | PPC_MEM_EIEIO |                  \
                               PPC_MEM_TLBIE | PPC_MEM_TLBSYNC | PPC_6xx_TLB | \
                               PPC_SEGMENT | PPC_EXTERN)
+#define POWERPC_INSNS2_603E  (PPC_NONE)
 #define POWERPC_MSRM_603E    (0x000000000007FF73ULL)
 #define POWERPC_MMU_603E     (POWERPC_MMU_SOFT_6xx)
 //#define POWERPC_EXCP_603E    (POWERPC_EXCP_603E)
@@ -4631,6 +4658,7 @@ static void init_proc_603E (CPUPPCState *env)
                               PPC_MEM_SYNC | PPC_MEM_EIEIO |                  \
                               PPC_MEM_TLBIE | PPC_MEM_TLBSYNC |               \
                               PPC_SEGMENT | PPC_EXTERN)
+#define POWERPC_INSNS2_604   (PPC_NONE)
 #define POWERPC_MSRM_604     (0x000000000005FF77ULL)
 #define POWERPC_MMU_604      (POWERPC_MMU_32B)
 //#define POWERPC_EXCP_604     (POWERPC_EXCP_604)
@@ -4669,6 +4697,7 @@ static void init_proc_604 (CPUPPCState *env)
                               PPC_MEM_SYNC | PPC_MEM_EIEIO |                  \
                               PPC_MEM_TLBIE | PPC_MEM_TLBSYNC |               \
                               PPC_SEGMENT | PPC_EXTERN)
+#define POWERPC_INSNS2_604E  (PPC_NONE)
 #define POWERPC_MSRM_604E    (0x000000000005FF77ULL)
 #define POWERPC_MMU_604E     (POWERPC_MMU_32B)
 #define POWERPC_EXCP_604E    (POWERPC_EXCP_604)
@@ -4727,6 +4756,7 @@ static void init_proc_604E (CPUPPCState *env)
                               PPC_MEM_SYNC | PPC_MEM_EIEIO |                  \
                               PPC_MEM_TLBIE | PPC_MEM_TLBSYNC |               \
                               PPC_SEGMENT | PPC_EXTERN)
+#define POWERPC_INSNS2_740   (PPC_NONE)
 #define POWERPC_MSRM_740     (0x000000000005FF77ULL)
 #define POWERPC_MMU_740      (POWERPC_MMU_32B)
 #define POWERPC_EXCP_740     (POWERPC_EXCP_7x0)
@@ -4772,6 +4802,7 @@ static void init_proc_740 (CPUPPCState *env)
                               PPC_MEM_SYNC | PPC_MEM_EIEIO |                  \
                               PPC_MEM_TLBIE | PPC_MEM_TLBSYNC |               \
                               PPC_SEGMENT | PPC_EXTERN)
+#define POWERPC_INSNS2_750   (PPC_NONE)
 #define POWERPC_MSRM_750     (0x000000000005FF77ULL)
 #define POWERPC_MMU_750      (POWERPC_MMU_32B)
 #define POWERPC_EXCP_750     (POWERPC_EXCP_7x0)
@@ -4863,6 +4894,7 @@ static void init_proc_750 (CPUPPCState *env)
                               PPC_MEM_SYNC | PPC_MEM_EIEIO |                  \
                               PPC_MEM_TLBIE | PPC_MEM_TLBSYNC |               \
                               PPC_SEGMENT | PPC_EXTERN)
+#define POWERPC_INSNS2_750cl (PPC_NONE)
 #define POWERPC_MSRM_750cl   (0x000000000005FF77ULL)
 #define POWERPC_MMU_750cl    (POWERPC_MMU_32B)
 #define POWERPC_EXCP_750cl   (POWERPC_EXCP_7x0)
@@ -5001,6 +5033,7 @@ static void init_proc_750cl (CPUPPCState *env)
                               PPC_MEM_SYNC | PPC_MEM_EIEIO |                  \
                               PPC_MEM_TLBIE | PPC_MEM_TLBSYNC |               \
                               PPC_SEGMENT | PPC_EXTERN)
+#define POWERPC_INSNS2_750cx (PPC_NONE)
 #define POWERPC_MSRM_750cx   (0x000000000005FF77ULL)
 #define POWERPC_MMU_750cx    (POWERPC_MMU_32B)
 #define POWERPC_EXCP_750cx   (POWERPC_EXCP_7x0)
@@ -5058,6 +5091,7 @@ static void init_proc_750cx (CPUPPCState *env)
                               PPC_MEM_SYNC | PPC_MEM_EIEIO |                  \
                               PPC_MEM_TLBIE | PPC_MEM_TLBSYNC |               \
                               PPC_SEGMENT  | PPC_EXTERN)
+#define POWERPC_INSNS2_750fx (PPC_NONE)
 #define POWERPC_MSRM_750fx   (0x000000000005FF77ULL)
 #define POWERPC_MMU_750fx    (POWERPC_MMU_32B)
 #define POWERPC_EXCP_750fx   (POWERPC_EXCP_7x0)
@@ -5120,6 +5154,7 @@ static void init_proc_750fx (CPUPPCState *env)
                               PPC_MEM_SYNC | PPC_MEM_EIEIO |                  \
                               PPC_MEM_TLBIE | PPC_MEM_TLBSYNC |               \
                               PPC_SEGMENT  | PPC_EXTERN)
+#define POWERPC_INSNS2_750gx (PPC_NONE)
 #define POWERPC_MSRM_750gx   (0x000000000005FF77ULL)
 #define POWERPC_MMU_750gx    (POWERPC_MMU_32B)
 #define POWERPC_EXCP_750gx   (POWERPC_EXCP_7x0)
@@ -5182,6 +5217,7 @@ static void init_proc_750gx (CPUPPCState *env)
                               PPC_MEM_SYNC | PPC_MEM_EIEIO |                  \
                               PPC_MEM_TLBIE | PPC_MEM_TLBSYNC | PPC_6xx_TLB | \
                               PPC_SEGMENT | PPC_EXTERN)
+#define POWERPC_INSNS2_745   (PPC_NONE)
 #define POWERPC_MSRM_745     (0x000000000005FF77ULL)
 #define POWERPC_MMU_745      (POWERPC_MMU_SOFT_6xx)
 #define POWERPC_EXCP_745     (POWERPC_EXCP_7x5)
@@ -5235,6 +5271,7 @@ static void init_proc_745 (CPUPPCState *env)
                               PPC_MEM_SYNC | PPC_MEM_EIEIO |                  \
                               PPC_MEM_TLBIE | PPC_MEM_TLBSYNC | PPC_6xx_TLB | \
                               PPC_SEGMENT | PPC_EXTERN)
+#define POWERPC_INSNS2_755   (PPC_NONE)
 #define POWERPC_MSRM_755     (0x000000000005FF77ULL)
 #define POWERPC_MMU_755      (POWERPC_MMU_SOFT_6xx)
 #define POWERPC_EXCP_755     (POWERPC_EXCP_7x5)
@@ -5303,6 +5340,7 @@ static void init_proc_755 (CPUPPCState *env)
                               PPC_MEM_TLBIA |                                 \
                               PPC_SEGMENT | PPC_EXTERN |                      \
                               PPC_ALTIVEC)
+#define POWERPC_INSNS2_7400  (PPC_NONE)
 #define POWERPC_MSRM_7400    (0x000000000205FF77ULL)
 #define POWERPC_MMU_7400     (POWERPC_MMU_32B)
 #define POWERPC_EXCP_7400    (POWERPC_EXCP_74xx)
@@ -5355,6 +5393,7 @@ static void init_proc_7400 (CPUPPCState *env)
                               PPC_MEM_TLBIA |                                 \
                               PPC_SEGMENT | PPC_EXTERN |                      \
                               PPC_ALTIVEC)
+#define POWERPC_INSNS2_7410  (PPC_NONE)
 #define POWERPC_MSRM_7410    (0x000000000205FF77ULL)
 #define POWERPC_MMU_7410     (POWERPC_MMU_32B)
 #define POWERPC_EXCP_7410    (POWERPC_EXCP_74xx)
@@ -5413,6 +5452,7 @@ static void init_proc_7410 (CPUPPCState *env)
                               PPC_MEM_TLBIA | PPC_74xx_TLB |                  \
                               PPC_SEGMENT | PPC_EXTERN |                      \
                               PPC_ALTIVEC)
+#define POWERPC_INSNS2_7440  (PPC_NONE)
 #define POWERPC_MSRM_7440    (0x000000000205FF77ULL)
 #define POWERPC_MMU_7440     (POWERPC_MMU_SOFT_74xx)
 #define POWERPC_EXCP_7440    (POWERPC_EXCP_74xx)
@@ -5498,6 +5538,7 @@ static void init_proc_7440 (CPUPPCState *env)
                               PPC_MEM_TLBIA | PPC_74xx_TLB |                  \
                               PPC_SEGMENT | PPC_EXTERN |                      \
                               PPC_ALTIVEC)
+#define POWERPC_INSNS2_7450  (PPC_NONE)
 #define POWERPC_MSRM_7450    (0x000000000205FF77ULL)
 #define POWERPC_MMU_7450     (POWERPC_MMU_SOFT_74xx)
 #define POWERPC_EXCP_7450    (POWERPC_EXCP_74xx)
@@ -5609,6 +5650,7 @@ static void init_proc_7450 (CPUPPCState *env)
                               PPC_MEM_TLBIA | PPC_74xx_TLB |                  \
                               PPC_SEGMENT | PPC_EXTERN |                      \
                               PPC_ALTIVEC)
+#define POWERPC_INSNS2_7445  (PPC_NONE)
 #define POWERPC_MSRM_7445    (0x000000000205FF77ULL)
 #define POWERPC_MMU_7445     (POWERPC_MMU_SOFT_74xx)
 #define POWERPC_EXCP_7445    (POWERPC_EXCP_74xx)
@@ -5723,6 +5765,7 @@ static void init_proc_7445 (CPUPPCState *env)
                               PPC_MEM_TLBIA | PPC_74xx_TLB |                  \
                               PPC_SEGMENT | PPC_EXTERN |                      \
                               PPC_ALTIVEC)
+#define POWERPC_INSNS2_7455  (PPC_NONE)
 #define POWERPC_MSRM_7455    (0x000000000205FF77ULL)
 #define POWERPC_MMU_7455     (POWERPC_MMU_SOFT_74xx)
 #define POWERPC_EXCP_7455    (POWERPC_EXCP_74xx)
@@ -5839,6 +5882,7 @@ static void init_proc_7455 (CPUPPCState *env)
                               PPC_MEM_TLBIA | PPC_74xx_TLB |                  \
                               PPC_SEGMENT | PPC_EXTERN |                      \
                               PPC_ALTIVEC)
+#define POWERPC_INSNS2_7457  (PPC_NONE)
 #define POWERPC_MSRM_7457    (0x000000000205FF77ULL)
 #define POWERPC_MMU_7457     (POWERPC_MMU_SOFT_74xx)
 #define POWERPC_EXCP_7457    (POWERPC_EXCP_74xx)
@@ -5978,6 +6022,7 @@ static void init_proc_7457 (CPUPPCState *env)
                               PPC_MEM_TLBIE | PPC_MEM_TLBSYNC |               \
                               PPC_64B | PPC_ALTIVEC |                         \
                               PPC_SEGMENT_64B | PPC_SLBI)
+#define POWERPC_INSNS2_970   (PPC_NONE)
 #define POWERPC_MSRM_970     (0x900000000204FF36ULL)
 #define POWERPC_MMU_970      (POWERPC_MMU_64B)
 //#define POWERPC_EXCP_970     (POWERPC_EXCP_970)
@@ -6073,6 +6118,7 @@ static void init_proc_970 (CPUPPCState *env)
                               PPC_MEM_TLBIE | PPC_MEM_TLBSYNC |               \
                               PPC_64B | PPC_ALTIVEC |                         \
                               PPC_SEGMENT_64B | PPC_SLBI)
+#define POWERPC_INSNS2_970FX (PPC_NONE)
 #define POWERPC_MSRM_970FX   (0x800000000204FF36ULL)
 #define POWERPC_MMU_970FX    (POWERPC_MMU_64B)
 #define POWERPC_EXCP_970FX   (POWERPC_EXCP_970)
@@ -6174,6 +6220,7 @@ static void init_proc_970FX (CPUPPCState *env)
                               PPC_MEM_TLBIE | PPC_MEM_TLBSYNC |               \
                               PPC_64B | PPC_ALTIVEC |                         \
                               PPC_SEGMENT_64B | PPC_SLBI)
+#define POWERPC_INSNS2_970GX (PPC_NONE)
 #define POWERPC_MSRM_970GX   (0x800000000204FF36ULL)
 #define POWERPC_MMU_970GX    (POWERPC_MMU_64B)
 #define POWERPC_EXCP_970GX   (POWERPC_EXCP_970)
@@ -6263,6 +6310,7 @@ static void init_proc_970GX (CPUPPCState *env)
                               PPC_MEM_TLBIE | PPC_MEM_TLBSYNC |               \
                               PPC_64B | PPC_ALTIVEC |                         \
                               PPC_SEGMENT_64B | PPC_SLBI)
+#define POWERPC_INSNS2_970MP (PPC_NONE)
 #define POWERPC_MSRM_970MP   (0x900000000204FF36ULL)
 #define POWERPC_MMU_970MP    (POWERPC_MMU_64B)
 #define POWERPC_EXCP_970MP   (POWERPC_EXCP_970)
@@ -6354,6 +6402,7 @@ static void init_proc_970MP (CPUPPCState *env)
                               PPC_64B | PPC_ALTIVEC |                         \
                               PPC_SEGMENT_64B | PPC_SLBI |                    \
                               PPC_POPCNTB | PPC_POPCNTWD)
+#define POWERPC_INSNS2_POWER7 (PPC_NONE)
 #define POWERPC_MSRM_POWER7   (0x800000000204FF36ULL)
 #define POWERPC_MMU_POWER7    (POWERPC_MMU_2_06)
 #define POWERPC_EXCP_POWER7   (POWERPC_EXCP_POWER7)
@@ -6424,6 +6473,7 @@ static void init_proc_POWER7 (CPUPPCState *env)
                               PPC_MEM_TLBIE | PPC_MEM_TLBSYNC |               \
                               PPC_SEGMENT | PPC_EXTERN |                      \
                               PPC_64B | PPC_SLBI)
+#define POWERPC_INSNS2_620   (PPC_NONE)
 #define POWERPC_MSRM_620     (0x800000000005FF77ULL)
 //#define POWERPC_MMU_620      (POWERPC_MMU_620)
 #define POWERPC_EXCP_620     (POWERPC_EXCP_970)
@@ -6459,6 +6509,7 @@ static void init_proc_620 (CPUPPCState *env)
 /* Default 32 bits PowerPC target will be 604 */
 #define CPU_POWERPC_PPC32     CPU_POWERPC_604
 #define POWERPC_INSNS_PPC32   POWERPC_INSNS_604
+#define POWERPC_INSNS2_PPC32  POWERPC_INSNS2_604
 #define POWERPC_MSRM_PPC32    POWERPC_MSRM_604
 #define POWERPC_MMU_PPC32     POWERPC_MMU_604
 #define POWERPC_EXCP_PPC32    POWERPC_EXCP_604
@@ -6471,6 +6522,7 @@ static void init_proc_620 (CPUPPCState *env)
 /* Default 64 bits PowerPC target will be 970 FX */
 #define CPU_POWERPC_PPC64     CPU_POWERPC_970FX
 #define POWERPC_INSNS_PPC64   POWERPC_INSNS_970FX
+#define POWERPC_INSNS2_PPC64  POWERPC_INSNS2_970FX
 #define POWERPC_MSRM_PPC64    POWERPC_MSRM_970FX
 #define POWERPC_MMU_PPC64     POWERPC_MMU_970FX
 #define POWERPC_EXCP_PPC64    POWERPC_EXCP_970FX
@@ -6482,27 +6534,29 @@ static void init_proc_620 (CPUPPCState *env)
 
 /* Default PowerPC target will be PowerPC 32 */
 #if defined (TARGET_PPC64) && 0 // XXX: TODO
-#define CPU_POWERPC_DEFAULT   CPU_POWERPC_PPC64
-#define POWERPC_INSNS_DEFAULT POWERPC_INSNS_PPC64
-#define POWERPC_MSRM_DEFAULT  POWERPC_MSRM_PPC64
-#define POWERPC_MMU_DEFAULT   POWERPC_MMU_PPC64
-#define POWERPC_EXCP_DEFAULT  POWERPC_EXCP_PPC64
-#define POWERPC_INPUT_DEFAULT POWERPC_INPUT_PPC64
-#define POWERPC_BFDM_DEFAULT  POWERPC_BFDM_PPC64
-#define POWERPC_FLAG_DEFAULT  POWERPC_FLAG_PPC64
-#define check_pow_DEFAULT     check_pow_PPC64
-#define init_proc_DEFAULT     init_proc_PPC64
+#define CPU_POWERPC_DEFAULT    CPU_POWERPC_PPC64
+#define POWERPC_INSNS_DEFAULT  POWERPC_INSNS_PPC64
+#define POWERPC_INSNS2_DEFAULT POWERPC_INSNS_PPC64
+#define POWERPC_MSRM_DEFAULT   POWERPC_MSRM_PPC64
+#define POWERPC_MMU_DEFAULT    POWERPC_MMU_PPC64
+#define POWERPC_EXCP_DEFAULT   POWERPC_EXCP_PPC64
+#define POWERPC_INPUT_DEFAULT  POWERPC_INPUT_PPC64
+#define POWERPC_BFDM_DEFAULT   POWERPC_BFDM_PPC64
+#define POWERPC_FLAG_DEFAULT   POWERPC_FLAG_PPC64
+#define check_pow_DEFAULT      check_pow_PPC64
+#define init_proc_DEFAULT      init_proc_PPC64
 #else
-#define CPU_POWERPC_DEFAULT   CPU_POWERPC_PPC32
-#define POWERPC_INSNS_DEFAULT POWERPC_INSNS_PPC32
-#define POWERPC_MSRM_DEFAULT  POWERPC_MSRM_PPC32
-#define POWERPC_MMU_DEFAULT   POWERPC_MMU_PPC32
-#define POWERPC_EXCP_DEFAULT  POWERPC_EXCP_PPC32
-#define POWERPC_INPUT_DEFAULT POWERPC_INPUT_PPC32
-#define POWERPC_BFDM_DEFAULT  POWERPC_BFDM_PPC32
-#define POWERPC_FLAG_DEFAULT  POWERPC_FLAG_PPC32
-#define check_pow_DEFAULT     check_pow_PPC32
-#define init_proc_DEFAULT     init_proc_PPC32
+#define CPU_POWERPC_DEFAULT    CPU_POWERPC_PPC32
+#define POWERPC_INSNS_DEFAULT  POWERPC_INSNS_PPC32
+#define POWERPC_INSNS2_DEFAULT POWERPC_INSNS_PPC32
+#define POWERPC_MSRM_DEFAULT   POWERPC_MSRM_PPC32
+#define POWERPC_MMU_DEFAULT    POWERPC_MMU_PPC32
+#define POWERPC_EXCP_DEFAULT   POWERPC_EXCP_PPC32
+#define POWERPC_INPUT_DEFAULT  POWERPC_INPUT_PPC32
+#define POWERPC_BFDM_DEFAULT   POWERPC_BFDM_PPC32
+#define POWERPC_FLAG_DEFAULT   POWERPC_FLAG_PPC32
+#define check_pow_DEFAULT      check_pow_PPC32
+#define init_proc_DEFAULT      init_proc_PPC32
 #endif
 
 /*****************************************************************************/
@@ -7351,18 +7405,19 @@ enum {
 /* PowerPC CPU definitions                                                   */
 #define POWERPC_DEF_SVR(_name, _pvr, _svr, _type)                             \
     {                                                                         \
-        .name        = _name,                                                 \
-        .pvr         = _pvr,                                                  \
-        .svr         = _svr,                                                  \
-        .insns_flags = glue(POWERPC_INSNS_,_type),                            \
-        .msr_mask    = glue(POWERPC_MSRM_,_type),                             \
-        .mmu_model   = glue(POWERPC_MMU_,_type),                              \
-        .excp_model  = glue(POWERPC_EXCP_,_type),                             \
-        .bus_model   = glue(POWERPC_INPUT_,_type),                            \
-        .bfd_mach    = glue(POWERPC_BFDM_,_type),                             \
-        .flags       = glue(POWERPC_FLAG_,_type),                             \
-        .init_proc   = &glue(init_proc_,_type),                               \
-        .check_pow   = &glue(check_pow_,_type),                               \
+        .name         = _name,                                                \
+        .pvr          = _pvr,                                                 \
+        .svr          = _svr,                                                 \
+        .insns_flags  = glue(POWERPC_INSNS_,_type),                           \
+        .insns_flags2 = glue(POWERPC_INSNS2_,_type),                          \
+        .msr_mask     = glue(POWERPC_MSRM_,_type),                            \
+        .mmu_model    = glue(POWERPC_MMU_,_type),                             \
+        .excp_model   = glue(POWERPC_EXCP_,_type),                            \
+        .bus_model    = glue(POWERPC_INPUT_,_type),                           \
+        .bfd_mach     = glue(POWERPC_BFDM_,_type),                            \
+        .flags        = glue(POWERPC_FLAG_,_type),                            \
+        .init_proc    = &glue(init_proc_,_type),                              \
+        .check_pow    = &glue(check_pow_,_type),                              \
     }
 #define POWERPC_DEF(_name, _pvr, _type)                                       \
 POWERPC_DEF_SVR(_name, _pvr, POWERPC_SVR_NONE, _type)
@@ -9437,7 +9492,8 @@ static int create_ppc_opcodes (CPUPPCState *env, const ppc_def_t *def)
 
     fill_new_table(env->opcodes, 0x40);
     for (opc = opcodes; opc < &opcodes[ARRAY_SIZE(opcodes)]; opc++) {
-        if ((opc->handler.type & def->insns_flags) != 0) {
+        if (((opc->handler.type & def->insns_flags) != 0) ||
+            ((opc->handler.type2 & def->insns_flags2) != 0)) {
             if (register_insn(env->opcodes, opc) < 0) {
                 printf("*** ERROR initializing PowerPC instruction "
                        "0x%02x 0x%02x 0x%02x\n", opc->opc1, opc->opc2,
@@ -9650,6 +9706,7 @@ int cpu_ppc_register_internal (CPUPPCState *env, const ppc_def_t *def)
     env->excp_model = def->excp_model;
     env->bus_model = def->bus_model;
     env->insns_flags = def->insns_flags;
+    env->insns_flags2 = def->insns_flags2;
     env->flags = def->flags;
     env->bfd_mach = def->bfd_mach;
     env->check_pow = def->check_pow;
-- 
1.6.0.2

^ permalink raw reply related	[flat|nested] 15+ messages in thread

* [Qemu-devel] [PATCH 5/6] PPC: Implement e500 (FSL) MMU
  2011-05-02 15:03 [Qemu-devel] [PATCH 0/6] PPC: Add FSL (e500) MMU emulation v3 Alexander Graf
                   ` (3 preceding siblings ...)
  2011-05-02 15:03 ` [Qemu-devel] [PATCH 4/6] PPC: Add another 64 bits to instruction feature mask Alexander Graf
@ 2011-05-02 15:03 ` Alexander Graf
  2011-05-03 19:25   ` Scott Wood
  2011-05-02 15:03 ` [Qemu-devel] [PATCH 6/6] PPC: Qdev'ify e500 pci Alexander Graf
  2011-05-04 19:09 ` [Qemu-devel] [PATCH 0/6] PPC: Add FSL (e500) MMU emulation v3 Blue Swirl
  6 siblings, 1 reply; 15+ messages in thread
From: Alexander Graf @ 2011-05-02 15:03 UTC (permalink / raw)
  To: QEMU-devel Developers; +Cc: Scott Wood, Edgar E. Iglesias, Liu Yu, Blue Swirl

Most of the code to support e500 style MMUs is already in place, but
we're missing on some of the special TLB0-TLB1 handling code and slightly
different TLB modification.

This patch adds support for the FSL style MMU.

Signed-off-by: Alexander Graf <agraf@suse.de>

---

v1 -> v2:

  - fix linux-user build
  - optimize tlb invalidate & search
---
 target-ppc/cpu.h            |  217 ++++++++++++++++++++++-
 target-ppc/helper.c         |  233 +++++++++++++++++++-----
 target-ppc/helper.h         |    5 +
 target-ppc/op_helper.c      |  418 +++++++++++++++++++++++++++++++++++++++++++
 target-ppc/translate.c      |   91 +++++++++-
 target-ppc/translate_init.c |  127 +++++++++-----
 6 files changed, 994 insertions(+), 97 deletions(-)

diff --git a/target-ppc/cpu.h b/target-ppc/cpu.h
index b8d9049..785ae53 100644
--- a/target-ppc/cpu.h
+++ b/target-ppc/cpu.h
@@ -608,6 +608,215 @@ enum {
 #define vscr_sat	(((env->vscr) >> VSCR_SAT)	& 0x1)
 
 /*****************************************************************************/
+/* BookE e500 MMU registers */
+
+#define MAS0_NV_SHIFT      0
+#define MAS0_NV_MASK       (0xfff << MAS0_NV_SHIFT)
+
+#define MAS0_WQ_SHIFT      12
+#define MAS0_WQ_MASK       (3 << MAS0_WQ_SHIFT)
+/* Write TLB entry regardless of reservation */
+#define MAS0_WQ_ALWAYS     (0 << MAS0_WQ_SHIFT)
+/* Write TLB entry only already in use */
+#define MAS0_WQ_COND       (1 << MAS0_WQ_SHIFT)
+/* Clear TLB entry */
+#define MAS0_WQ_CLR_RSRV   (2 << MAS0_WQ_SHIFT)
+
+#define MAS0_HES_SHIFT     14
+#define MAS0_HES           (1 << MAS0_HES_SHIFT)
+
+#define MAS0_ESEL_SHIFT    16
+#define MAS0_ESEL_MASK     (0xfff << MAS0_ESEL_SHIFT)
+
+#define MAS0_TLBSEL_SHIFT  28
+#define MAS0_TLBSEL_MASK   (3 << MAS0_TLBSEL_SHIFT)
+#define MAS0_TLBSEL_TLB0   (0 << MAS0_TLBSEL_SHIFT)
+#define MAS0_TLBSEL_TLB1   (1 << MAS0_TLBSEL_SHIFT)
+#define MAS0_TLBSEL_TLB2   (2 << MAS0_TLBSEL_SHIFT)
+#define MAS0_TLBSEL_TLB3   (3 << MAS0_TLBSEL_SHIFT)
+
+#define MAS0_ATSEL_SHIFT   31
+#define MAS0_ATSEL         (1 << MAS0_ATSEL_SHIFT)
+#define MAS0_ATSEL_TLB     0
+#define MAS0_ATSEL_LRAT    MAS0_ATSEL
+
+#define MAS1_TSIZE_SHIFT   8
+#define MAS1_TSIZE_MASK    (0xf << MAS1_TSIZE_SHIFT)
+
+#define MAS1_TS_SHIFT      12
+#define MAS1_TS            (1 << MAS1_TS_SHIFT)
+
+#define MAS1_IND_SHIFT     13
+#define MAS1_IND           (1 << MAS1_IND_SHIFT)
+
+#define MAS1_TID_SHIFT     16
+#define MAS1_TID_MASK      (0x3fff << MAS1_TID_SHIFT)
+
+#define MAS1_IPROT_SHIFT   30
+#define MAS1_IPROT         (1 << MAS1_IPROT_SHIFT)
+
+#define MAS1_VALID_SHIFT   31
+#define MAS1_VALID         0x80000000
+
+#define MAS2_EPN_SHIFT     12
+#define MAS2_EPN_MASK      (0xfffff << MAS2_EPN_SHIFT)
+
+#define MAS2_ACM_SHIFT     6
+#define MAS2_ACM           (1 << MAS2_ACM_SHIFT)
+
+#define MAS2_VLE_SHIFT     5
+#define MAS2_VLE           (1 << MAS2_VLE_SHIFT)
+
+#define MAS2_W_SHIFT       4
+#define MAS2_W             (1 << MAS2_W_SHIFT)
+
+#define MAS2_I_SHIFT       3
+#define MAS2_I             (1 << MAS2_I_SHIFT)
+
+#define MAS2_M_SHIFT       2
+#define MAS2_M             (1 << MAS2_M_SHIFT)
+
+#define MAS2_G_SHIFT       1
+#define MAS2_G             (1 << MAS2_G_SHIFT)
+
+#define MAS2_E_SHIFT       0
+#define MAS2_E             (1 << MAS2_E_SHIFT)
+
+#define MAS3_RPN_SHIFT     12
+#define MAS3_RPN_MASK      (0xfffff << MAS3_RPN_SHIFT)
+
+#define MAS3_U0                 0x00000200
+#define MAS3_U1                 0x00000100
+#define MAS3_U2                 0x00000080
+#define MAS3_U3                 0x00000040
+#define MAS3_UX                 0x00000020
+#define MAS3_SX                 0x00000010
+#define MAS3_UW                 0x00000008
+#define MAS3_SW                 0x00000004
+#define MAS3_UR                 0x00000002
+#define MAS3_SR                 0x00000001
+#define MAS3_SPSIZE_SHIFT       1
+#define MAS3_SPSIZE_MASK        (0x3e << MAS3_SPSIZE_SHIFT)
+
+#define MAS4_TLBSELD_SHIFT      MAS0_TLBSEL_SHIFT
+#define MAS4_TLBSELD_MASK       MAS0_TLBSEL_MASK
+#define MAS4_TIDSELD_MASK       0x00030000
+#define MAS4_TIDSELD_PID0       0x00000000
+#define MAS4_TIDSELD_PID1       0x00010000
+#define MAS4_TIDSELD_PID2       0x00020000
+#define MAS4_TIDSELD_PIDZ       0x00030000
+#define MAS4_INDD               0x00008000      /* Default IND */
+#define MAS4_TSIZED_SHIFT       MAS1_TSIZE_SHIFT
+#define MAS4_TSIZED_MASK        MAS1_TSIZE_MASK
+#define MAS4_ACMD               0x00000040
+#define MAS4_VLED               0x00000020
+#define MAS4_WD                 0x00000010
+#define MAS4_ID                 0x00000008
+#define MAS4_MD                 0x00000004
+#define MAS4_GD                 0x00000002
+#define MAS4_ED                 0x00000001
+#define MAS4_WIMGED_MASK        0x0000001f      /* Default WIMGE */
+#define MAS4_WIMGED_SHIFT       0
+
+#define MAS5_SGS                0x80000000
+#define MAS5_SLPID_MASK         0x00000fff
+
+#define MAS6_SPID0              0x3fff0000
+#define MAS6_SPID1              0x00007ffe
+#define MAS6_ISIZE(x)           MAS1_TSIZE(x)
+#define MAS6_SAS                0x00000001
+#define MAS6_SPID               MAS6_SPID0
+#define MAS6_SIND               0x00000002      /* Indirect page */
+#define MAS6_SIND_SHIFT         1
+#define MAS6_SPID_MASK          0x3fff0000
+#define MAS6_SPID_SHIFT         16
+#define MAS6_ISIZE_MASK         0x00000f80
+#define MAS6_ISIZE_SHIFT        7
+
+#define MAS7_RPN                0xffffffff
+
+#define MAS8_TGS                0x80000000
+#define MAS8_VF                 0x40000000
+#define MAS8_TLBPID             0x00000fff
+
+/* Bit definitions for MMUCFG */
+#define MMUCFG_MAVN     0x00000003      /* MMU Architecture Version Number */
+#define MMUCFG_MAVN_V1  0x00000000      /* v1.0 */
+#define MMUCFG_MAVN_V2  0x00000001      /* v2.0 */
+#define MMUCFG_NTLBS    0x0000000c      /* Number of TLBs */
+#define MMUCFG_PIDSIZE  0x000007c0      /* PID Reg Size */
+#define MMUCFG_TWC      0x00008000      /* TLB Write Conditional (v2.0) */
+#define MMUCFG_LRAT     0x00010000      /* LRAT Supported (v2.0) */
+#define MMUCFG_RASIZE   0x00fe0000      /* Real Addr Size */
+#define MMUCFG_LPIDSIZE 0x0f000000      /* LPID Reg Size */
+
+/* Bit definitions for MMUCSR0 */
+#define MMUCSR0_TLB1FI  0x00000002      /* TLB1 Flash invalidate */
+#define MMUCSR0_TLB0FI  0x00000004      /* TLB0 Flash invalidate */
+#define MMUCSR0_TLB2FI  0x00000040      /* TLB2 Flash invalidate */
+#define MMUCSR0_TLB3FI  0x00000020      /* TLB3 Flash invalidate */
+#define MMUCSR0_TLBFI   (MMUCSR0_TLB0FI | MMUCSR0_TLB1FI | \
+                         MMUCSR0_TLB2FI | MMUCSR0_TLB3FI)
+#define MMUCSR0_TLB0PS  0x00000780      /* TLB0 Page Size */
+#define MMUCSR0_TLB1PS  0x00007800      /* TLB1 Page Size */
+#define MMUCSR0_TLB2PS  0x00078000      /* TLB2 Page Size */
+#define MMUCSR0_TLB3PS  0x00780000      /* TLB3 Page Size */
+
+/* TLBnCFG encoding */
+#define TLBnCFG_N_ENTRY         0x00000fff      /* number of entries */
+#define TLBnCFG_HES             0x00002000      /* HW select supported */
+#define TLBnCFG_AVAIL           0x00004000      /* variable page size */
+#define TLBnCFG_IPROT           0x00008000      /* IPROT supported */
+#define TLBnCFG_GTWE            0x00010000      /* Guest can write */
+#define TLBnCFG_IND             0x00020000      /* IND entries supported */
+#define TLBnCFG_PT              0x00040000      /* Can load from page table */
+#define TLBnCFG_MINSIZE         0x00f00000      /* Minimum Page Size (v1.0) */
+#define TLBnCFG_MINSIZE_SHIFT   20
+#define TLBnCFG_MAXSIZE         0x000f0000      /* Maximum Page Size (v1.0) */
+#define TLBnCFG_MAXSIZE_SHIFT   16
+#define TLBnCFG_ASSOC           0xff000000      /* Associativity */
+#define TLBnCFG_ASSOC_SHIFT     24
+
+/* TLBnPS encoding */
+#define TLBnPS_4K               0x00000004
+#define TLBnPS_8K               0x00000008
+#define TLBnPS_16K              0x00000010
+#define TLBnPS_32K              0x00000020
+#define TLBnPS_64K              0x00000040
+#define TLBnPS_128K             0x00000080
+#define TLBnPS_256K             0x00000100
+#define TLBnPS_512K             0x00000200
+#define TLBnPS_1M               0x00000400
+#define TLBnPS_2M               0x00000800
+#define TLBnPS_4M               0x00001000
+#define TLBnPS_8M               0x00002000
+#define TLBnPS_16M              0x00004000
+#define TLBnPS_32M              0x00008000
+#define TLBnPS_64M              0x00010000
+#define TLBnPS_128M             0x00020000
+#define TLBnPS_256M             0x00040000
+#define TLBnPS_512M             0x00080000
+#define TLBnPS_1G               0x00100000
+#define TLBnPS_2G               0x00200000
+#define TLBnPS_4G               0x00400000
+#define TLBnPS_8G               0x00800000
+#define TLBnPS_16G              0x01000000
+#define TLBnPS_32G              0x02000000
+#define TLBnPS_64G              0x04000000
+#define TLBnPS_128G             0x08000000
+#define TLBnPS_256G             0x10000000
+
+/* tlbilx action encoding */
+#define TLBILX_T_ALL                    0
+#define TLBILX_T_TID                    1
+#define TLBILX_T_FULLMATCH              3
+#define TLBILX_T_CLASS0                 4
+#define TLBILX_T_CLASS1                 5
+#define TLBILX_T_CLASS2                 6
+#define TLBILX_T_CLASS3                 7
+
+
+/*****************************************************************************/
 /* The whole PowerPC CPU context */
 #define NB_MMU_MODES 3
 
@@ -678,8 +887,9 @@ struct CPUPPCState {
     int nb_BATs;
     target_ulong DBAT[2][8];
     target_ulong IBAT[2][8];
-    /* PowerPC TLB registers (for 4xx and 60x software driven TLBs) */
+    /* PowerPC TLB registers (for 4xx, e500 and 60x software driven TLBs) */
     int nb_tlb;      /* Total number of TLB                                  */
+    int nb_tlbs[4];  /* Number of respective TLB entries (e500)              */
     int tlb_per_way; /* Speed-up helper: used to avoid divisions at run time */
     int nb_ways;     /* Number of ways in the TLB set                        */
     int last_way;    /* Last used way used to allocate TLB in a LRU way      */
@@ -1546,6 +1756,11 @@ enum {
     PPC_DCRUX          = 0x4000000000000000ULL,
     /* popcntw and popcntd instructions                                      */
     PPC_POPCNTWD       = 0x8000000000000000ULL,
+
+    /* extended type values */
+
+    /* BookE FSL (e500) PowerPC specification                                */
+    PPC2_BOOKE_FSL     = 0x0000000000000001ULL,
 };
 
 /*****************************************************************************/
diff --git a/target-ppc/helper.c b/target-ppc/helper.c
index 5e4030b..261c1a9 100644
--- a/target-ppc/helper.c
+++ b/target-ppc/helper.c
@@ -1153,48 +1153,144 @@ void store_40x_sler (CPUPPCState *env, uint32_t val)
     env->spr[SPR_405_SLER] = val;
 }
 
+static inline int mmubooke_check_tlb (CPUState *env, ppcemb_tlb_t *tlb,
+                                      target_phys_addr_t *raddr, int *prot,
+                                      target_ulong address, int rw,
+                                      int access_type, int i)
+{
+    int ret, _prot;
+
+    if (ppcemb_tlb_check(env, tlb, raddr, address,
+                         env->spr[SPR_BOOKE_PID],
+                         !env->nb_pids, i) >= 0) {
+        goto found_tlb;
+    }
+
+    if ((env->nb_pids > 1) && env->spr[SPR_BOOKE_PID1] &&
+        ppcemb_tlb_check(env, tlb, raddr, address,
+                         env->spr[SPR_BOOKE_PID1], 0, i) >= 0) {
+        goto found_tlb;
+    }
+
+    if ((env->nb_pids > 2) && env->spr[SPR_BOOKE_PID2] &&
+        ppcemb_tlb_check(env, tlb, raddr, address,
+                         env->spr[SPR_BOOKE_PID2], 0, i) >= 0) {
+        goto found_tlb;
+    }
+
+    return -1;
+
+found_tlb:
+
+    if (msr_pr != 0) {
+        _prot = tlb->prot & 0xF;
+    } else {
+        _prot = (tlb->prot >> 4) & 0xF;
+    }
+
+    /* Check the address space */
+    if (access_type == ACCESS_CODE) {
+        if (msr_ir != (tlb->attr & 1)) {
+            return -1;
+        }
+
+        *prot = _prot;
+        if (_prot & PAGE_EXEC) {
+            return 0;
+        }
+
+        ret = -3;
+    } else {
+        if (msr_dr != (tlb->attr & 1)) {
+            return -1;
+        }
+
+        *prot = _prot;
+        if ((!rw && _prot & PAGE_READ) || (rw && (_prot & PAGE_WRITE))) {
+            return 0;
+        }
+
+        ret = -2;
+    }
+
+    return ret;
+}
+
 static int mmubooke_get_physical_address (CPUState *env, mmu_ctx_t *ctx,
                                           target_ulong address, int rw,
                                           int access_type)
 {
     ppcemb_tlb_t *tlb;
     target_phys_addr_t raddr;
-    int i, prot, ret;
+    int i, ret;
 
     ret = -1;
     raddr = (target_phys_addr_t)-1ULL;
     for (i = 0; i < env->nb_tlb; i++) {
         tlb = &env->tlb[i].tlbe;
-        if (ppcemb_tlb_check(env, tlb, &raddr, address,
-                             env->spr[SPR_BOOKE_PID], 1, i) < 0)
-            continue;
-        if (msr_pr != 0)
-            prot = tlb->prot & 0xF;
-        else
-            prot = (tlb->prot >> 4) & 0xF;
-        /* Check the address space */
-        if (access_type == ACCESS_CODE) {
-            if (msr_ir != (tlb->attr & 1))
-                continue;
-            ctx->prot = prot;
-            if (prot & PAGE_EXEC) {
-                ret = 0;
-                break;
-            }
-            ret = -3;
-        } else {
-            if (msr_dr != (tlb->attr & 1))
-                continue;
-            ctx->prot = prot;
-            if ((!rw && prot & PAGE_READ) || (rw && (prot & PAGE_WRITE))) {
-                ret = 0;
-                break;
-            }
-            ret = -2;
+        ret = mmubooke_check_tlb(env, tlb, &raddr, &ctx->prot, address, rw,
+                                 access_type, i);
+        if (!ret) {
+            break;
+        }
+    }
+
+    if (ret >= 0) {
+        ctx->raddr = raddr;
+        LOG_SWTLB("%s: access granted " TARGET_FMT_lx " => " TARGET_FMT_plx
+                  " %d %d\n", __func__, address, ctx->raddr, ctx->prot,
+                  ret);
+    } else {
+        LOG_SWTLB("%s: access refused " TARGET_FMT_lx " => " TARGET_FMT_plx
+                  " %d %d\n", __func__, address, raddr, ctx->prot, ret);
+    }
+
+    return ret;
+}
+
+static int mmue500_get_physical_address (CPUState *env, mmu_ctx_t *ctx,
+                                         target_ulong address, int rw,
+                                         int access_type)
+{
+    ppcemb_tlb_t *tlb;
+    target_phys_addr_t raddr;
+    int i, ret;
+    uint32_t ea = (address >> MAS2_EPN_SHIFT) & 0x7f;
+
+    ret = -1;
+    raddr = (target_phys_addr_t)-1ULL;
+
+    /* check TLB1 - hits often because the kernel is here */
+    for (i = env->nb_tlbs[0]; i < env->nb_tlb; i++) {
+        tlb = &env->tlb[i].tlbe;
+        ret = mmubooke_check_tlb(env, tlb, &raddr, &ctx->prot, address, rw,
+                                 access_type, i);
+        if (!ret) {
+            goto found_tlb;
         }
     }
-    if (ret >= 0)
+
+    /* check possible TLB0 entries */
+    for (i = 0; i < env->nb_ways; i++) {
+        tlb = &env->tlb[ea | (i << 7)].tlbe;
+        ret = mmubooke_check_tlb(env, tlb, &raddr, &ctx->prot, address, rw,
+                                 access_type, i);
+        if (!ret) {
+            goto found_tlb;
+        }
+    }
+
+found_tlb:
+
+    if (ret >= 0) {
         ctx->raddr = raddr;
+        LOG_SWTLB("%s: access granted " TARGET_FMT_lx " => " TARGET_FMT_plx
+                  " %d %d\n", __func__, address, ctx->raddr, ctx->prot,
+                  ret);
+    } else {
+        LOG_SWTLB("%s: access refused " TARGET_FMT_lx " => " TARGET_FMT_plx
+                  " %d %d\n", __func__, address, raddr, ctx->prot, ret);
+    }
 
     return ret;
 }
@@ -1255,8 +1351,7 @@ static inline int check_physical(CPUState *env, mmu_ctx_t *ctx,
         cpu_abort(env, "MPC8xx MMU model is not implemented\n");
         break;
     case POWERPC_MMU_BOOKE_FSL:
-        /* XXX: TODO */
-        cpu_abort(env, "BookE FSL MMU model not implemented\n");
+        cpu_abort(env, "BookE FSL MMU model doesn't have physical real mode\n");
         break;
     default:
         cpu_abort(env, "Unknown or invalid MMU model\n");
@@ -1281,6 +1376,9 @@ int get_physical_address (CPUState *env, mmu_ctx_t *ctx, target_ulong eaddr,
                IS and DS bits only affect the address space.  */
             ret = mmubooke_get_physical_address(env, ctx, eaddr,
                                                 rw, access_type);
+        } else if (env->mmu_model == POWERPC_MMU_BOOKE_FSL) {
+            ret = mmue500_get_physical_address(env, ctx, eaddr, rw,
+                                               access_type);
         } else {
             /* No address translation.  */
             ret = check_physical(env, ctx, eaddr, rw);
@@ -1314,14 +1412,14 @@ int get_physical_address (CPUState *env, mmu_ctx_t *ctx, target_ulong eaddr,
             ret = mmubooke_get_physical_address(env, ctx, eaddr,
                                                 rw, access_type);
             break;
+        case POWERPC_MMU_BOOKE_FSL:
+            ret = mmue500_get_physical_address(env, ctx, eaddr, rw,
+                                               access_type);
+            break;
         case POWERPC_MMU_MPC8xx:
             /* XXX: TODO */
             cpu_abort(env, "MPC8xx MMU model is not implemented\n");
             break;
-        case POWERPC_MMU_BOOKE_FSL:
-            /* XXX: TODO */
-            cpu_abort(env, "BookE FSL MMU model not implemented\n");
-            return -1;
         case POWERPC_MMU_REAL:
             cpu_abort(env, "PowerPC in real mode do not do any translation\n");
             return -1;
@@ -1348,6 +1446,44 @@ target_phys_addr_t cpu_get_phys_page_debug (CPUState *env, target_ulong addr)
     return ctx.raddr & TARGET_PAGE_MASK;
 }
 
+static void e500_update_mas_tlb_miss(CPUState *env, target_ulong address,
+                                     int rw)
+{
+    env->spr[SPR_BOOKE_MAS0] = env->spr[SPR_BOOKE_MAS4] & MAS4_TLBSELD_MASK;
+    env->spr[SPR_BOOKE_MAS1] = env->spr[SPR_BOOKE_MAS4] & MAS4_TSIZED_MASK;
+    env->spr[SPR_BOOKE_MAS2] = env->spr[SPR_BOOKE_MAS4] & MAS4_WIMGED_MASK;
+    env->spr[SPR_BOOKE_MAS6] = 0;
+
+    /* AS */
+    if (((rw == 2) && msr_ir) || ((rw != 2) && msr_dr)) {
+        env->spr[SPR_BOOKE_MAS1] |= MAS1_TS;
+        env->spr[SPR_BOOKE_MAS6] |= MAS6_SAS;
+    }
+
+    env->spr[SPR_BOOKE_MAS1] |= MAS1_VALID;
+    env->spr[SPR_BOOKE_MAS2] |= address & MAS2_EPN_MASK;
+
+    switch (env->spr[SPR_BOOKE_MAS4] & MAS4_TIDSELD_PIDZ) {
+    case MAS4_TIDSELD_PID0:
+        env->spr[SPR_BOOKE_MAS1] |= env->spr[SPR_BOOKE_PID] << MAS1_TID_SHIFT;
+        break;
+    case MAS4_TIDSELD_PID1:
+        env->spr[SPR_BOOKE_MAS1] |= env->spr[SPR_BOOKE_PID1] << MAS1_TID_SHIFT;
+        break;
+    case MAS4_TIDSELD_PID2:
+        env->spr[SPR_BOOKE_MAS1] |= env->spr[SPR_BOOKE_PID2] << MAS1_TID_SHIFT;
+        break;
+    }
+
+    env->spr[SPR_BOOKE_MAS6] |= env->spr[SPR_BOOKE_PID] << 16;
+
+    /* next victim logic */
+    env->spr[SPR_BOOKE_MAS0] |= env->last_way << MAS0_ESEL_SHIFT;
+    env->last_way++;
+    env->last_way &= 3;
+    env->spr[SPR_BOOKE_MAS0] |= env->last_way << MAS0_NV_SHIFT;
+}
+
 /* Perform address translation */
 int cpu_ppc_handle_mmu_fault (CPUState *env, target_ulong address, int rw,
                               int mmu_idx, int is_softmmu)
@@ -1403,15 +1539,14 @@ int cpu_ppc_handle_mmu_fault (CPUState *env, target_ulong address, int rw,
                     env->exception_index = POWERPC_EXCP_ISI;
                     env->error_code = 0x40000000;
                     break;
+                case POWERPC_MMU_BOOKE_FSL:
+                    e500_update_mas_tlb_miss(env, address, rw);
+                    /* fall through */
                 case POWERPC_MMU_BOOKE:
                     env->exception_index = POWERPC_EXCP_ITLB;
                     env->error_code = 0;
                     env->spr[SPR_BOOKE_DEAR] = address;
                     return -1;
-                case POWERPC_MMU_BOOKE_FSL:
-                    /* XXX: TODO */
-                    cpu_abort(env, "BookE FSL MMU model is not implemented\n");
-                    return -1;
                 case POWERPC_MMU_MPC8xx:
                     /* XXX: TODO */
                     cpu_abort(env, "MPC8xx MMU model is not implemented\n");
@@ -1432,7 +1567,8 @@ int cpu_ppc_handle_mmu_fault (CPUState *env, target_ulong address, int rw,
                 break;
             case -3:
                 /* No execute protection violation */
-                if (env->mmu_model == POWERPC_MMU_BOOKE) {
+                if ((env->mmu_model == POWERPC_MMU_BOOKE) ||
+                    (env->mmu_model == POWERPC_MMU_BOOKE_FSL)) {
                     env->spr[SPR_BOOKE_ESR] = 0x00000000;
                 }
                 env->exception_index = POWERPC_EXCP_ISI;
@@ -1522,16 +1658,15 @@ int cpu_ppc_handle_mmu_fault (CPUState *env, target_ulong address, int rw,
                     /* XXX: TODO */
                     cpu_abort(env, "MPC8xx MMU model is not implemented\n");
                     break;
+                case POWERPC_MMU_BOOKE_FSL:
+                    e500_update_mas_tlb_miss(env, address, rw);
+                    /* fall through */
                 case POWERPC_MMU_BOOKE:
                     env->exception_index = POWERPC_EXCP_DTLB;
                     env->error_code = 0;
                     env->spr[SPR_BOOKE_DEAR] = address;
                     env->spr[SPR_BOOKE_ESR] = rw ? 1 << ESR_ST : 0;
                     return -1;
-                case POWERPC_MMU_BOOKE_FSL:
-                    /* XXX: TODO */
-                    cpu_abort(env, "BookE FSL MMU model is not implemented\n");
-                    return -1;
                 case POWERPC_MMU_REAL:
                     cpu_abort(env, "PowerPC in real mode should never raise "
                               "any MMU exceptions\n");
@@ -1551,7 +1686,8 @@ int cpu_ppc_handle_mmu_fault (CPUState *env, target_ulong address, int rw,
                     if (rw) {
                         env->spr[SPR_40x_ESR] |= 0x00800000;
                     }
-                } else if (env->mmu_model == POWERPC_MMU_BOOKE) {
+                } else if ((env->mmu_model == POWERPC_MMU_BOOKE) ||
+                           (env->mmu_model == POWERPC_MMU_BOOKE_FSL)) {
                     env->spr[SPR_BOOKE_DEAR] = address;
                     env->spr[SPR_BOOKE_ESR] = rw ? 1 << ESR_ST : 0;
                 } else {
@@ -1820,12 +1956,8 @@ void ppc_tlb_invalidate_all (CPUPPCState *env)
         cpu_abort(env, "MPC8xx MMU model is not implemented\n");
         break;
     case POWERPC_MMU_BOOKE:
-        tlb_flush(env, 1);
-        break;
     case POWERPC_MMU_BOOKE_FSL:
-        /* XXX: TODO */
-        if (!kvm_enabled())
-            cpu_abort(env, "BookE MMU model is not implemented\n");
+        tlb_flush(env, 1);
         break;
     case POWERPC_MMU_32B:
     case POWERPC_MMU_601:
@@ -2589,7 +2721,8 @@ static inline void powerpc_excp(CPUState *env, int excp_model, int excp)
     env->exception_index = POWERPC_EXCP_NONE;
     env->error_code = 0;
 
-    if (env->mmu_model == POWERPC_MMU_BOOKE) {
+    if ((env->mmu_model == POWERPC_MMU_BOOKE) ||
+        (env->mmu_model == POWERPC_MMU_BOOKE_FSL)) {
         /* XXX: The BookE changes address space when switching modes,
                 we should probably implement that as different MMU indexes,
                 but for the moment we do it the slow way and flush all.  */
diff --git a/target-ppc/helper.h b/target-ppc/helper.h
index 7c02be9..7839aad 100644
--- a/target-ppc/helper.h
+++ b/target-ppc/helper.h
@@ -334,6 +334,11 @@ DEF_HELPER_1(4xx_tlbsx, tl, tl)
 DEF_HELPER_2(440_tlbre, tl, i32, tl)
 DEF_HELPER_3(440_tlbwe, void, i32, tl, tl)
 DEF_HELPER_1(440_tlbsx, tl, tl)
+DEF_HELPER_0(e500_tlbre, void)
+DEF_HELPER_0(e500_tlbwe, void)
+DEF_HELPER_2(e500_tlbsx, void, tl, tl)
+DEF_HELPER_1(e500_tlbivax, void, tl)
+DEF_HELPER_1(e500_tlbflush, void, i32)
 DEF_HELPER_1(6xx_tlbd, void, tl)
 DEF_HELPER_1(6xx_tlbi, void, tl)
 DEF_HELPER_1(74xx_tlbd, void, tl)
diff --git a/target-ppc/op_helper.c b/target-ppc/op_helper.c
index d5db484..3c0b061 100644
--- a/target-ppc/op_helper.c
+++ b/target-ppc/op_helper.c
@@ -4206,4 +4206,422 @@ target_ulong helper_440_tlbsx (target_ulong address)
     return ppcemb_tlb_search(env, address, env->spr[SPR_440_MMUCR] & 0xFF);
 }
 
+/* PowerPC e500 TLB management */
+
+static inline int e500_tlb_num(CPUState *env, ppcemb_tlb_t *tlb)
+{
+    ulong tlbel = (ulong)tlb;
+    ulong tlbl = (ulong)env->tlb;
+
+    return (tlbel - tlbl) / sizeof(env->tlb[0]);
+}
+
+static inline ppcemb_tlb_t *e500_cur_tlb(CPUState *env)
+{
+    uint32_t tlbncfg = 0;
+    int esel = (env->spr[SPR_BOOKE_MAS0] & MAS0_ESEL_MASK) >> MAS0_ESEL_SHIFT;
+    int ea = (env->spr[SPR_BOOKE_MAS2] & MAS2_EPN_MASK) >> MAS2_EPN_SHIFT;
+    int tlb;
+    int r;
+
+    tlb = (env->spr[SPR_BOOKE_MAS0] & MAS0_TLBSEL_MASK) >> MAS0_TLBSEL_SHIFT;
+    tlbncfg = env->spr[SPR_BOOKE_TLB0CFG + tlb];
+
+    if ((tlbncfg & TLBnCFG_HES) && (env->spr[SPR_BOOKE_MAS0] & MAS0_HES)) {
+        cpu_abort(env, "we don't support HES yet\n");
+    }
+
+    if (tlb == 1) {
+        r = env->nb_tlbs[0] + (esel % env->nb_tlbs[1]);
+    } else {
+        esel &= env->nb_ways - 1;
+        esel <<= 7;
+        ea &= 0x7f;
+        r = (esel | ea) % env->nb_tlbs[0];
+    }
+
+    return &env->tlb[r].tlbe;
+}
+
+static const target_phys_addr_t e500_tlb_sizes[] = {
+    0,
+    4 * 1024,
+    16 * 1024,
+    64 * 1024,
+    256 * 1024,
+    1024 * 1024,
+    4 * 1024 * 1024,
+    16 * 1024 * 1024,
+    64 * 1024 * 1024,
+    256 * 1024 * 1024,
+    1024 * 1024 * 1024,
+    (target_phys_addr_t)(4ULL * 1024ULL * 1024ULL * 1024ULL),
+};
+
+static inline target_phys_addr_t e500_tlb_to_page_size(int size)
+{
+    target_phys_addr_t r;
+
+    if (size > 11) {
+        /* should not happen */
+        r = 1024 * 1024 * 1024;
+    } else {
+        r = e500_tlb_sizes[size];
+    }
+
+    return r;
+}
+
+static inline target_phys_addr_t e500_page_size_to_tlb(uint64_t size)
+{
+    int i;
+    target_phys_addr_t r = 0;
+
+    for (i = 0; i < ARRAY_SIZE(e500_tlb_sizes); i++) {
+        if (e500_tlb_sizes[i] == size) {
+            r = i;
+            break;
+        }
+    }
+
+    return r;
+}
+
+void helper_e500_tlbwe(void)
+{
+    uint32_t tlbncfg;
+    ppcemb_tlb_t *tlb;
+    target_phys_addr_t rpn;
+
+    switch (env->spr[SPR_BOOKE_MAS0] & MAS0_WQ_MASK) {
+    case MAS0_WQ_ALWAYS:
+        /* good to go, write that entry */
+        break;
+    case MAS0_WQ_COND:
+        /* XXX check if reserved */
+        if (0) {
+            return;
+        }
+        break;
+    case MAS0_WQ_CLR_RSRV:
+        /* XXX clear entry */
+        return;
+    default:
+        /* no idea what to do */
+        return;
+    }
+
+    if (((env->spr[SPR_BOOKE_MAS0] & MAS0_ATSEL) == MAS0_ATSEL_LRAT) &&
+         !msr_gs) {
+        /* XXX we don't support direct LRAT setting yet */
+        fprintf(stderr, "cpu: don't support LRAT setting yet\n");
+        return;
+    }
+
+    switch (env->spr[SPR_BOOKE_MAS0] & MAS0_TLBSEL_MASK) {
+    case MAS0_TLBSEL_TLB0:
+        tlbncfg = env->spr[SPR_BOOKE_TLB0CFG];
+        break;
+    case MAS0_TLBSEL_TLB1:
+        tlbncfg = env->spr[SPR_BOOKE_TLB1CFG];
+        break;
+    case MAS0_TLBSEL_TLB2:
+        tlbncfg = env->spr[SPR_BOOKE_TLB2CFG];
+        break;
+    case MAS0_TLBSEL_TLB3:
+        tlbncfg = env->spr[SPR_BOOKE_TLB3CFG];
+        break;
+    }
+
+    tlb = e500_cur_tlb(env);
+
+    /* XXX check for IPROT */
+
+    if (msr_gs) {
+        cpu_abort(env, "missing HV implementation\n");
+    } else {
+        rpn = ((uint64_t)env->spr[SPR_BOOKE_MAS7] << 32) |
+              (env->spr[SPR_BOOKE_MAS3] & 0xfffff000);
+    }
+    tlb->RPN = rpn;
+
+    tlb->PID = (env->spr[SPR_BOOKE_MAS1] & MAS1_TID_MASK) >> MAS1_TID_SHIFT;
+    tlb->size = e500_tlb_to_page_size((env->spr[SPR_BOOKE_MAS1]
+                      & MAS1_TSIZE_MASK) >> MAS1_TSIZE_SHIFT);
+    tlb->EPN = (uint32_t)(env->spr[SPR_BOOKE_MAS2] & MAS2_EPN_MASK);
+    tlb->attr = env->spr[SPR_BOOKE_MAS2] & (MAS2_ACM | MAS2_VLE | MAS2_W |
+                                            MAS2_I | MAS2_M | MAS2_G | MAS2_E)
+                << 1;
+    tlb->attr |= env->spr[SPR_BOOKE_MAS1] & MAS1_IPROT;
+    tlb->attr |= (env->spr[SPR_BOOKE_MAS3] &
+                  ((MAS3_U0 | MAS3_U1 | MAS3_U2 | MAS3_U3)) << 8);
+    if (env->spr[SPR_BOOKE_MAS1] & MAS1_TS) {
+        tlb->attr |= 1;
+    }
+
+    tlb->prot = 0;
+
+    if (env->spr[SPR_BOOKE_MAS1] & MAS1_VALID) {
+        tlb->prot |= PAGE_VALID;
+    }
+    if (env->spr[SPR_BOOKE_MAS3] & MAS3_UX) {
+        tlb->prot |= PAGE_EXEC;
+    }
+    if (env->spr[SPR_BOOKE_MAS3] & MAS3_SX) {
+        tlb->prot |= PAGE_EXEC << 4;
+    }
+    if (env->spr[SPR_BOOKE_MAS3] & MAS3_UW) {
+        tlb->prot |= PAGE_WRITE;
+    }
+    if (env->spr[SPR_BOOKE_MAS3] & MAS3_SW) {
+        tlb->prot |= PAGE_WRITE << 4;
+    }
+    if (env->spr[SPR_BOOKE_MAS3] & MAS3_UR) {
+        tlb->prot |= PAGE_READ;
+    }
+    if (env->spr[SPR_BOOKE_MAS3] & MAS3_SR) {
+        tlb->prot |= PAGE_READ << 4;
+    }
+
+    if (tlb->size == TARGET_PAGE_SIZE) {
+        tlb_flush_page(env, tlb->EPN);
+    } else {
+        tlb_flush(env, 1);
+    }
+}
+
+static inline void e500_tlb_to_mas(CPUState *env, ppcemb_tlb_t *tlb, int i)
+{
+    env->spr[SPR_BOOKE_MAS0] = 0;
+    env->spr[SPR_BOOKE_MAS1] = MAS1_VALID;
+    env->spr[SPR_BOOKE_MAS2] = 0;
+
+    if (i >= env->nb_tlbs[0]) {
+        env->spr[SPR_BOOKE_MAS0] |= MAS0_TLBSEL_TLB1;
+        env->spr[SPR_BOOKE_MAS0] |= (i - env->nb_tlbs[0]) << MAS0_ESEL_SHIFT;
+    } else {
+        env->spr[SPR_BOOKE_MAS0] |= MAS0_TLBSEL_TLB0;
+        env->spr[SPR_BOOKE_MAS0] |= (i >> 7) << MAS0_ESEL_SHIFT;
+    }
+
+    env->spr[SPR_BOOKE_MAS7] = (uint64_t)tlb->RPN >> 32;
+    env->spr[SPR_BOOKE_MAS3] = tlb->RPN;
+    env->spr[SPR_BOOKE_MAS1] |= tlb->PID << MAS1_TID_SHIFT;
+    env->spr[SPR_BOOKE_MAS1] |= e500_page_size_to_tlb(tlb->size)
+                                << MAS1_TSIZE_SHIFT;
+    env->spr[SPR_BOOKE_MAS1] |= tlb->attr & MAS1_IPROT;
+    if (tlb->attr & 1) {
+        env->spr[SPR_BOOKE_MAS1] |= MAS1_TS;
+    }
+
+    env->spr[SPR_BOOKE_MAS2] = tlb->EPN;
+    env->spr[SPR_BOOKE_MAS2] |= (tlb->attr >> 1) &
+        (MAS2_ACM | MAS2_VLE | MAS2_W | MAS2_I | MAS2_M | MAS2_G | MAS2_E);
+
+    if (tlb->prot & PAGE_EXEC) {
+        env->spr[SPR_BOOKE_MAS3] |= MAS3_UX;
+    }
+    if (tlb->prot & (PAGE_EXEC << 4)) {
+        env->spr[SPR_BOOKE_MAS3] |= MAS3_SX;
+    }
+    if (tlb->prot & PAGE_WRITE) {
+        env->spr[SPR_BOOKE_MAS3] |= MAS3_UW;
+    }
+    if (tlb->prot & (PAGE_WRITE << 4)) {
+        env->spr[SPR_BOOKE_MAS3] |= MAS3_SW;
+    }
+    if (tlb->prot & PAGE_READ) {
+        env->spr[SPR_BOOKE_MAS3] |= MAS3_UR;
+    }
+    if (tlb->prot & (PAGE_READ << 4)) {
+        env->spr[SPR_BOOKE_MAS3] |= MAS3_SR;
+    }
+
+    env->spr[SPR_BOOKE_MAS0] |= env->last_way << MAS0_NV_SHIFT;
+}
+
+void helper_e500_tlbre(void)
+{
+    ppcemb_tlb_t *tlb = NULL;
+
+    tlb = e500_cur_tlb(env);
+    e500_tlb_to_mas(env, tlb, e500_tlb_num(env, tlb));
+}
+
+/* Generic TLB check function for embedded PowerPC implementations */
+static inline int ppcemb_tlb_check(CPUState *env, ppcemb_tlb_t *tlb,
+                                   target_phys_addr_t *raddrp,
+                                   target_ulong address, uint32_t pid, int ext,
+                                   int i)
+{
+    target_ulong mask;
+
+    /* Check valid flag */
+    if (!(tlb->prot & PAGE_VALID)) {
+        return -1;
+    }
+    mask = ~(tlb->size - 1);
+
+    /* Check PID */
+    if (tlb->PID != 0 && tlb->PID != pid) {
+        return -1;
+    }
+    /* Check effective address */
+    if ((address & mask) != tlb->EPN) {
+        return -1;
+    }
+    *raddrp = (tlb->RPN & mask) | (address & ~mask);
+#if (TARGET_PHYS_ADDR_BITS >= 36)
+    if (ext) {
+        /* Extend the physical address to 36 bits */
+        *raddrp |= (target_phys_addr_t)(tlb->RPN & 0xF) << 32;
+    }
+#endif
+
+    return 0;
+}
+
+void helper_e500_tlbsx(target_ulong address_hi, target_ulong address_lo)
+{
+    ppcemb_tlb_t *tlb = NULL;
+    int i;
+    target_phys_addr_t raddr;
+    uint32_t spid, sas;
+    uint32_t ea = (address_lo >> MAS2_EPN_SHIFT) & 0x7f;
+
+    spid = (env->spr[SPR_BOOKE_MAS6] & MAS6_SPID_MASK) >> MAS6_SPID_SHIFT;
+    sas = env->spr[SPR_BOOKE_MAS6] & MAS6_SAS;
+
+    /* check possible TLB0 entries */
+    for (i = 0; i < env->nb_ways; i++) {
+        tlb = &env->tlb[ea | (i << 7)].tlbe;
+
+        if (ppcemb_tlb_check(env, tlb, &raddr, address_lo, spid, 0, i) < 0) {
+            continue;
+        }
+
+        if (sas != (tlb->attr & MAS6_SAS)) {
+            continue;
+        }
+
+        e500_tlb_to_mas(env, tlb, ea | (i << 7));
+        return;
+    }
+
+    /* check TLB1 */
+    for (i = env->nb_tlbs[0]; i < (env->nb_tlbs[0] + env->nb_tlbs[1]); i++) {
+        tlb = &env->tlb[i].tlbe;
+
+        if (ppcemb_tlb_check(env, tlb, &raddr, address_lo, spid, 0, i) < 0) {
+            continue;
+        }
+
+        if (sas != (tlb->attr & MAS6_SAS)) {
+            continue;
+        }
+
+        e500_tlb_to_mas(env, tlb, i);
+        return;
+    }
+
+    /* no entry found, fill with defaults */
+    env->spr[SPR_BOOKE_MAS0] = env->spr[SPR_BOOKE_MAS4] & MAS4_TLBSELD_MASK;
+    env->spr[SPR_BOOKE_MAS1] = env->spr[SPR_BOOKE_MAS4] & MAS4_TSIZED_MASK;
+    env->spr[SPR_BOOKE_MAS2] = env->spr[SPR_BOOKE_MAS4] & MAS4_WIMGED_MASK;
+
+    if (env->spr[SPR_BOOKE_MAS6] & MAS6_SAS) {
+        env->spr[SPR_BOOKE_MAS1] |= MAS1_TS;
+    }
+
+    env->spr[SPR_BOOKE_MAS1] |= (env->spr[SPR_BOOKE_MAS6] >> 16)
+                                << MAS1_TID_SHIFT;
+
+    /* next victim logic */
+    env->spr[SPR_BOOKE_MAS0] |= env->last_way << MAS0_ESEL_SHIFT;
+    env->last_way++;
+    env->last_way &= 3;
+    env->spr[SPR_BOOKE_MAS0] |= env->last_way << MAS0_NV_SHIFT;
+}
+
+static inline void e500_invalidate_ea_tlb0(CPUState *env, uint32_t ea)
+{
+    int i;
+    ppcemb_tlb_t *tlb;
+
+    ea &= 0x7f;
+
+    /* check only possible TLB0 entries */
+    for (i = 0; i < env->nb_ways; i++) {
+        tlb = &env->tlb[ea | (i << 7)].tlbe;
+        if (tlb->EPN == ea) {
+            tlb->prot = 0;
+        }
+    }
+}
+
+static inline void e500_invalidate_ea_tlb1(CPUState *env, uint32_t ea)
+{
+    int i;
+
+    for (i = env->nb_tlbs[0]; i < (env->nb_tlbs[0] + env->nb_tlbs[1]); i++) {
+        ppcemb_tlb_t *tlb = &env->tlb[i].tlbe;
+        if ((tlb->EPN == (ea & ~(tlb->size - 1))) &&
+            !(tlb->attr & MAS1_IPROT)) {
+            tlb->prot = 0;
+        }
+    }
+}
+
+void helper_e500_tlbivax(target_ulong address)
+{
+    uint32_t ea = address >> MAS2_EPN_SHIFT;
+
+    if (address & 0x4) {
+        /* flush all entries */
+        if (address & 0x8) {
+            /* flush all of TLB1 */
+            helper_e500_tlbflush(2);
+        } else {
+            /* flush all of TLB0 */
+            helper_e500_tlbflush(4);
+        }
+        return;
+    }
+
+    if (address & 0x8) {
+        /* flush TLB1 entries */
+        e500_invalidate_ea_tlb1(env, ea);
+        tlb_flush(env, 1);
+    } else {
+        /* flush TLB0 entries */
+        e500_invalidate_ea_tlb0(env, ea);
+        tlb_flush_page(env, address & MAS2_EPN_MASK);
+    }
+}
+
+void helper_e500_tlbflush(uint32_t type)
+{
+    int i;
+
+    if (type & 4) {
+        /* flush tlb0 */
+        for (i = 0; i < env->nb_tlbs[0]; i++) {
+            ppcemb_tlb_t *tlb = &env->tlb[i].tlbe;
+            tlb->prot = 0;
+        }
+    }
+
+    if (type & 2) {
+        /* flush tlb1 */
+        for (i = env->nb_tlbs[0]; i < env->nb_tlb; i++) {
+            ppcemb_tlb_t *tlb = &env->tlb[i].tlbe;
+            if (!(tlb->attr & MAS1_IPROT)) {
+                tlb->prot = 0;
+            }
+        }
+    }
+
+    tlb_flush(env, 1);
+}
+
 #endif /* !CONFIG_USER_ONLY */
diff --git a/target-ppc/translate.c b/target-ppc/translate.c
index 9076df0..629d019 100644
--- a/target-ppc/translate.c
+++ b/target-ppc/translate.c
@@ -5987,6 +5987,78 @@ static void gen_tlbwe_440(DisasContext *ctx)
 #endif
 }
 
+/* TLB management - PowerPC e500 implementation */
+
+/* tlbre */
+static void gen_tlbre_e500(DisasContext *ctx)
+{
+#if defined(CONFIG_USER_ONLY)
+    gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC);
+#else
+    if (unlikely(!ctx->mem_idx)) {
+        gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC);
+        return;
+    }
+
+    gen_helper_e500_tlbre();
+#endif
+}
+
+/* tlbsx - tlbsx. */
+static void gen_tlbsx_e500(DisasContext *ctx)
+{
+#if defined(CONFIG_USER_ONLY)
+    gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC);
+#else
+    TCGv t0;
+    if (unlikely(!ctx->mem_idx)) {
+        gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC);
+        return;
+    }
+
+    if (rA(ctx->opcode)) {
+        t0 = cpu_gpr[rD(ctx->opcode)];
+    } else {
+        t0 = tcg_const_tl(0);
+    }
+
+    gen_helper_e500_tlbsx(t0, cpu_gpr[rB(ctx->opcode)]);
+#endif
+}
+
+/* tlbwe */
+static void gen_tlbwe_e500(DisasContext *ctx)
+{
+#if defined(CONFIG_USER_ONLY)
+    gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC);
+#else
+    if (unlikely(!ctx->mem_idx)) {
+        gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC);
+        return;
+    }
+    gen_helper_e500_tlbwe();
+#endif
+}
+
+static void gen_tlbivax_e500(DisasContext *ctx)
+{
+#if defined(CONFIG_USER_ONLY)
+    gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC);
+#else
+    TCGv t0;
+    if (unlikely(!ctx->mem_idx)) {
+        gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC);
+        return;
+    }
+
+    t0 = tcg_temp_new();
+    gen_addr_reg_index(ctx, t0);
+
+    gen_helper_e500_tlbivax(t0);
+#endif
+}
+
+
 /* wrtee */
 static void gen_wrtee(DisasContext *ctx)
 {
@@ -8433,7 +8505,7 @@ GEN_HANDLER2(icbt_40x, "icbt", 0x1F, 0x06, 0x08, 0x03E00001, PPC_40x_ICBT),
 GEN_HANDLER(iccci, 0x1F, 0x06, 0x1E, 0x00000001, PPC_4xx_COMMON),
 GEN_HANDLER(icread, 0x1F, 0x06, 0x1F, 0x03E00001, PPC_4xx_COMMON),
 GEN_HANDLER2(rfci_40x, "rfci", 0x13, 0x13, 0x01, 0x03FF8001, PPC_40x_EXCP),
-GEN_HANDLER(rfci, 0x13, 0x13, 0x01, 0x03FF8001, PPC_BOOKE),
+GEN_HANDLER_E(rfci, 0x13, 0x13, 0x01, 0x03FF8001, PPC_BOOKE, PPC2_BOOKE_FSL),
 GEN_HANDLER(rfdi, 0x13, 0x07, 0x01, 0x03FF8001, PPC_RFDI),
 GEN_HANDLER(rfmci, 0x13, 0x06, 0x01, 0x03FF8001, PPC_RFMCI),
 GEN_HANDLER2(tlbre_40x, "tlbre", 0x1F, 0x12, 0x1D, 0x00000001, PPC_40x_TLB),
@@ -8442,12 +8514,23 @@ GEN_HANDLER2(tlbwe_40x, "tlbwe", 0x1F, 0x12, 0x1E, 0x00000001, PPC_40x_TLB),
 GEN_HANDLER2(tlbre_440, "tlbre", 0x1F, 0x12, 0x1D, 0x00000001, PPC_BOOKE),
 GEN_HANDLER2(tlbsx_440, "tlbsx", 0x1F, 0x12, 0x1C, 0x00000000, PPC_BOOKE),
 GEN_HANDLER2(tlbwe_440, "tlbwe", 0x1F, 0x12, 0x1E, 0x00000001, PPC_BOOKE),
+GEN_HANDLER2_E(tlbre_e500, "tlbre", 0x1F, 0x12, 0x1D, 0x00000001,
+               PPC_NONE, PPC2_BOOKE_FSL),
+GEN_HANDLER2_E(tlbsx_e500, "tlbsx", 0x1F, 0x12, 0x1C, 0x00000000,
+               PPC_NONE, PPC2_BOOKE_FSL),
+GEN_HANDLER2_E(tlbwe_e500, "tlbwe", 0x1F, 0x12, 0x1E, 0x00000001,
+               PPC_NONE, PPC2_BOOKE_FSL),
+GEN_HANDLER2_E(tlbivax_e500, "tlbivax", 0x1F, 0x12, 0x18, 0x00000001,
+               PPC_NONE, PPC2_BOOKE_FSL),
 GEN_HANDLER(wrtee, 0x1F, 0x03, 0x04, 0x000FFC01, PPC_WRTEE),
 GEN_HANDLER(wrteei, 0x1F, 0x03, 0x05, 0x000E7C01, PPC_WRTEE),
 GEN_HANDLER(dlmzb, 0x1F, 0x0E, 0x02, 0x00000000, PPC_440_SPEC),
-GEN_HANDLER(mbar, 0x1F, 0x16, 0x1a, 0x001FF801, PPC_BOOKE),
-GEN_HANDLER(msync, 0x1F, 0x16, 0x12, 0x03FFF801, PPC_BOOKE),
-GEN_HANDLER2(icbt_440, "icbt", 0x1F, 0x16, 0x00, 0x03E00001, PPC_BOOKE),
+GEN_HANDLER_E(mbar, 0x1F, 0x16, 0x1a, 0x001FF801,
+              PPC_BOOKE, PPC2_BOOKE_FSL),
+GEN_HANDLER_E(msync, 0x1F, 0x16, 0x12, 0x03FFF801,
+              PPC_BOOKE, PPC2_BOOKE_FSL),
+GEN_HANDLER2_E(icbt_440, "icbt", 0x1F, 0x16, 0x00, 0x03E00001,
+               PPC_BOOKE, PPC2_BOOKE_FSL),
 GEN_HANDLER(lvsl, 0x1f, 0x06, 0x00, 0x00000001, PPC_ALTIVEC),
 GEN_HANDLER(lvsr, 0x1f, 0x06, 0x01, 0x00000001, PPC_ALTIVEC),
 GEN_HANDLER(mfvscr, 0x04, 0x2, 0x18, 0x001ff800, PPC_ALTIVEC),
diff --git a/target-ppc/translate_init.c b/target-ppc/translate_init.c
index aec0e13..2d7afa2 100644
--- a/target-ppc/translate_init.c
+++ b/target-ppc/translate_init.c
@@ -1355,6 +1355,31 @@ static void gen_74xx_soft_tlb (CPUPPCState *env, int nb_tlbs, int nb_ways)
 #endif
 }
 
+#if !defined(CONFIG_USER_ONLY)
+static void spr_write_e500_l1csr0 (void *opaque, int sprn, int gprn)
+{
+    TCGv t0 = tcg_temp_new();
+
+    tcg_gen_andi_tl(t0, cpu_gpr[gprn], ~256);
+    gen_store_spr(sprn, t0);
+    tcg_temp_free(t0);
+}
+
+static void spr_write_e500_mmucsr0 (void *opaque, int sprn, int gprn)
+{
+    TCGv t0 = tcg_const_i32(sprn);
+    gen_helper_e500_tlbflush(t0);
+    tcg_temp_free(t0);
+}
+
+static void spr_write_booke_pid (void *opaque, int sprn, int gprn)
+{
+    gen_store_spr(sprn, cpu_gpr[gprn]);
+    /* switching context, so need to flush tlb */
+    gen_helper_tlbia();
+}
+#endif
+
 static void gen_spr_usprgh (CPUPPCState *env)
 {
     spr_register(env, SPR_USPRG4, "USPRG4",
@@ -1494,7 +1519,7 @@ static void gen_spr_BookE (CPUPPCState *env, uint64_t ivor_mask)
     }
     spr_register(env, SPR_BOOKE_PID, "PID",
                  SPR_NOACCESS, SPR_NOACCESS,
-                 &spr_read_generic, &spr_write_generic,
+                 &spr_read_generic, &spr_write_booke_pid,
                  0x00000000);
     spr_register(env, SPR_BOOKE_TCR, "TCR",
                  SPR_NOACCESS, SPR_NOACCESS,
@@ -1536,8 +1561,19 @@ static void gen_spr_BookE (CPUPPCState *env, uint64_t ivor_mask)
                  0x00000000);
 }
 
+static inline uint32_t gen_tlbncfg(uint32_t assoc, uint32_t minsize,
+                                   uint32_t maxsize, uint32_t flags,
+                                   uint32_t nentries)
+{
+    return (assoc << TLBnCFG_ASSOC_SHIFT) |
+           (minsize << TLBnCFG_MINSIZE_SHIFT) |
+           (maxsize << TLBnCFG_MAXSIZE_SHIFT) |
+           flags | nentries;
+}
+
 /* FSL storage control registers */
-static void gen_spr_BookE_FSL (CPUPPCState *env, uint32_t mas_mask)
+static void gen_spr_BookE_FSL(CPUPPCState *env, uint32_t mas_mask,
+                              uint32_t *tlbncfg)
 {
 #if !defined(CONFIG_USER_ONLY)
     const char *mas_names[8] = {
@@ -1563,14 +1599,14 @@ static void gen_spr_BookE_FSL (CPUPPCState *env, uint32_t mas_mask)
         /* XXX : not implemented */
         spr_register(env, SPR_BOOKE_PID1, "PID1",
                      SPR_NOACCESS, SPR_NOACCESS,
-                     &spr_read_generic, &spr_write_generic,
+                     &spr_read_generic, &spr_write_booke_pid,
                      0x00000000);
     }
     if (env->nb_pids > 2) {
         /* XXX : not implemented */
         spr_register(env, SPR_BOOKE_PID2, "PID2",
                      SPR_NOACCESS, SPR_NOACCESS,
-                     &spr_read_generic, &spr_write_generic,
+                     &spr_read_generic, &spr_write_booke_pid,
                      0x00000000);
     }
     /* XXX : not implemented */
@@ -1578,45 +1614,38 @@ static void gen_spr_BookE_FSL (CPUPPCState *env, uint32_t mas_mask)
                  SPR_NOACCESS, SPR_NOACCESS,
                  &spr_read_generic, SPR_NOACCESS,
                  0x00000000); /* TOFIX */
-    /* XXX : not implemented */
-    spr_register(env, SPR_MMUCSR0, "MMUCSR0",
-                 SPR_NOACCESS, SPR_NOACCESS,
-                 &spr_read_generic, &spr_write_generic,
-                 0x00000000); /* TOFIX */
     switch (env->nb_ways) {
     case 4:
-        /* XXX : not implemented */
         spr_register(env, SPR_BOOKE_TLB3CFG, "TLB3CFG",
                      SPR_NOACCESS, SPR_NOACCESS,
                      &spr_read_generic, SPR_NOACCESS,
-                     0x00000000); /* TOFIX */
+                     tlbncfg[3]);
         /* Fallthru */
     case 3:
-        /* XXX : not implemented */
         spr_register(env, SPR_BOOKE_TLB2CFG, "TLB2CFG",
                      SPR_NOACCESS, SPR_NOACCESS,
                      &spr_read_generic, SPR_NOACCESS,
-                     0x00000000); /* TOFIX */
+                     tlbncfg[2]);
         /* Fallthru */
     case 2:
-        /* XXX : not implemented */
         spr_register(env, SPR_BOOKE_TLB1CFG, "TLB1CFG",
                      SPR_NOACCESS, SPR_NOACCESS,
                      &spr_read_generic, SPR_NOACCESS,
-                     0x00000000); /* TOFIX */
+                     tlbncfg[1]);
         /* Fallthru */
     case 1:
-        /* XXX : not implemented */
         spr_register(env, SPR_BOOKE_TLB0CFG, "TLB0CFG",
                      SPR_NOACCESS, SPR_NOACCESS,
                      &spr_read_generic, SPR_NOACCESS,
-                     0x00000000); /* TOFIX */
+                     tlbncfg[0]);
         /* Fallthru */
     case 0:
     default:
         break;
     }
 #endif
+
+    gen_spr_usprgh(env);
 }
 
 /* SPR specific to PowerPC 440 implementation */
@@ -4134,7 +4163,7 @@ static void init_proc_e200 (CPUPPCState *env)
                  &spr_read_spefscr, &spr_write_spefscr,
                  0x00000000);
     /* Memory management */
-    gen_spr_BookE_FSL(env, 0x0000005D);
+    gen_spr_BookE_FSL(env, 0x0000005D, NULL);
     /* XXX : not implemented */
     spr_register(env, SPR_HID0, "HID0",
                  SPR_NOACCESS, SPR_NOACCESS,
@@ -4205,6 +4234,11 @@ static void init_proc_e200 (CPUPPCState *env)
                  SPR_NOACCESS, SPR_NOACCESS,
                  &spr_read_generic, &spr_write_generic,
                  0x00000000);
+    /* XXX : not implemented */
+    spr_register(env, SPR_MMUCSR0, "MMUCSR0",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_generic,
+                 0x00000000); /* TOFIX */
     spr_register(env, SPR_BOOKE_DSRR0, "DSRR0",
                  SPR_NOACCESS, SPR_NOACCESS,
                  &spr_read_generic, &spr_write_generic,
@@ -4282,9 +4316,8 @@ static void init_proc_e300 (CPUPPCState *env)
                                 PPC_WRTEE | PPC_RFDI |                  \
                                 PPC_CACHE | PPC_CACHE_LOCK | PPC_CACHE_ICBI | \
                                 PPC_CACHE_DCBZ | PPC_CACHE_DCBA |       \
-                                PPC_MEM_TLBSYNC | PPC_TLBIVAX |         \
-                                PPC_BOOKE)
-#define POWERPC_INSNS2_e500v1  (PPC_NONE)
+                                PPC_MEM_TLBSYNC | PPC_TLBIVAX)
+#define POWERPC_INSNS2_e500v1  (PPC2_BOOKE_FSL)
 #define POWERPC_MSRM_e500v1    (0x000000000606FF30ULL)
 #define POWERPC_MMU_e500v1     (POWERPC_MMU_BOOKE_FSL)
 #define POWERPC_EXCP_e500v1    (POWERPC_EXCP_BOOKE)
@@ -4302,9 +4335,8 @@ static void init_proc_e300 (CPUPPCState *env)
                                 PPC_WRTEE | PPC_RFDI |                  \
                                 PPC_CACHE | PPC_CACHE_LOCK | PPC_CACHE_ICBI | \
                                 PPC_CACHE_DCBZ | PPC_CACHE_DCBA |       \
-                                PPC_MEM_TLBSYNC | PPC_TLBIVAX |         \
-                                PPC_BOOKE)
-#define POWERPC_INSNS2_e500v2  (PPC_NONE)
+                                PPC_MEM_TLBSYNC | PPC_TLBIVAX)
+#define POWERPC_INSNS2_e500v2  (PPC2_BOOKE_FSL)
 #define POWERPC_MSRM_e500v2    (0x000000000606FF30ULL)
 #define POWERPC_MMU_e500v2     (POWERPC_MMU_BOOKE_FSL)
 #define POWERPC_EXCP_e500v2    (POWERPC_EXCP_BOOKE)
@@ -4318,9 +4350,16 @@ static void init_proc_e300 (CPUPPCState *env)
 
 static void init_proc_e500 (CPUPPCState *env)
 {
+    uint32_t tlbncfg[2];
+
     /* Time base */
     gen_tbl(env);
-    gen_spr_BookE(env, 0x0000000F0000FD7FULL);
+    /*
+     * XXX The e500 doesn't implement IVOR7 and IVOR9, but doesn't
+     *     complain when accessing them.
+     * gen_spr_BookE(env, 0x0000000F0000FD7FULL);
+     */
+    gen_spr_BookE(env, 0x0000000F0000FFFFULL);
     /* Processor identification */
     spr_register(env, SPR_BOOKE_PIR, "PIR",
                  SPR_NOACCESS, SPR_NOACCESS,
@@ -4334,8 +4373,23 @@ static void init_proc_e500 (CPUPPCState *env)
     /* Memory management */
 #if !defined(CONFIG_USER_ONLY)
     env->nb_pids = 3;
+    env->nb_ways = 2;
+    env->id_tlbs = 0;
+    if ((env->spr[SPR_PVR] & 0x00010000)) {
+        /* e500v2 */
+        env->nb_tlbs[0] = 512;
+        tlbncfg[0] = gen_tlbncfg(4, 1, 1, 0, env->nb_tlbs[0]);
+        tlbncfg[1] = gen_tlbncfg(16, 1, 12, TLBnCFG_AVAIL | TLBnCFG_IPROT, 16);
+    } else {
+        /* e500v1 */
+        env->nb_tlbs[0] = 256;
+        tlbncfg[0] = gen_tlbncfg(2, 1, 1, 0, env->nb_tlbs[0]);
+        tlbncfg[1] = gen_tlbncfg(16, 1, 9, TLBnCFG_AVAIL | TLBnCFG_IPROT, 16);
+    }
+    env->nb_tlbs[1] = 16;
+    env->nb_tlb = env->nb_tlbs[0] + env->nb_tlbs[1];
 #endif
-    gen_spr_BookE_FSL(env, 0x0000005F);
+    gen_spr_BookE_FSL(env, 0x000000DF, tlbncfg);
     /* XXX : not implemented */
     spr_register(env, SPR_HID0, "HID0",
                  SPR_NOACCESS, SPR_NOACCESS,
@@ -4384,23 +4438,13 @@ static void init_proc_e500 (CPUPPCState *env)
     /* XXX : not implemented */
     spr_register(env, SPR_Exxx_L1CSR0, "L1CSR0",
                  SPR_NOACCESS, SPR_NOACCESS,
-                 &spr_read_generic, &spr_write_generic,
+                 &spr_read_generic, &spr_write_e500_l1csr0,
                  0x00000000);
     /* XXX : not implemented */
     spr_register(env, SPR_Exxx_L1CSR1, "L1CSR1",
                  SPR_NOACCESS, SPR_NOACCESS,
                  &spr_read_generic, &spr_write_generic,
                  0x00000000);
-    /* XXX : not implemented */
-    spr_register(env, SPR_BOOKE_TLB0CFG, "TLB0CFG",
-                 SPR_NOACCESS, SPR_NOACCESS,
-                 &spr_read_generic, &spr_write_generic,
-                 0x00000000);
-    /* XXX : not implemented */
-    spr_register(env, SPR_BOOKE_TLB1CFG, "TLB1CFG",
-                 SPR_NOACCESS, SPR_NOACCESS,
-                 &spr_read_generic, &spr_write_generic,
-                 0x00000000);
     spr_register(env, SPR_BOOKE_MCSRR0, "MCSRR0",
                  SPR_NOACCESS, SPR_NOACCESS,
                  &spr_read_generic, &spr_write_generic,
@@ -4409,11 +4453,10 @@ static void init_proc_e500 (CPUPPCState *env)
                  SPR_NOACCESS, SPR_NOACCESS,
                  &spr_read_generic, &spr_write_generic,
                  0x00000000);
-#if !defined(CONFIG_USER_ONLY)
-    env->nb_tlb = 64;
-    env->nb_ways = 1;
-    env->id_tlbs = 0;
-#endif
+    spr_register(env, SPR_MMUCSR0, "MMUCSR0",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_e500_mmucsr0,
+                 0x00000000);
     init_excp_e200(env);
     env->dcache_line_size = 32;
     env->icache_line_size = 32;
-- 
1.6.0.2

^ permalink raw reply related	[flat|nested] 15+ messages in thread

* [Qemu-devel] [PATCH 6/6] PPC: Qdev'ify e500 pci
  2011-05-02 15:03 [Qemu-devel] [PATCH 0/6] PPC: Add FSL (e500) MMU emulation v3 Alexander Graf
                   ` (4 preceding siblings ...)
  2011-05-02 15:03 ` [Qemu-devel] [PATCH 5/6] PPC: Implement e500 (FSL) MMU Alexander Graf
@ 2011-05-02 15:03 ` Alexander Graf
  2011-05-04 19:08   ` Blue Swirl
  2011-05-04 19:09 ` [Qemu-devel] [PATCH 0/6] PPC: Add FSL (e500) MMU emulation v3 Blue Swirl
  6 siblings, 1 reply; 15+ messages in thread
From: Alexander Graf @ 2011-05-02 15:03 UTC (permalink / raw)
  To: QEMU-devel Developers; +Cc: Scott Wood, Edgar E. Iglesias, Liu Yu, Blue Swirl

The e500 PCI controller isn't qdev'ified yet. This leads to severe issues
when running with -drive.

To be able to use a virtio disk with an e500 VM, let's convert the PCI
controller over to qdev.

Signed-off-by: Alexander Graf <agraf@suse.de>

---

v2 -> v3:

  - rebase to current code base
  - fix endian issue
  - use sysbus helpers
---
 hw/ppce500_pci.c |  112 +++++++++++++++++++++++++++++++++++-------------------
 1 files changed, 73 insertions(+), 39 deletions(-)

diff --git a/hw/ppce500_pci.c b/hw/ppce500_pci.c
index 83a20e4..88bc759 100644
--- a/hw/ppce500_pci.c
+++ b/hw/ppce500_pci.c
@@ -73,11 +73,11 @@ struct pci_inbound {
 };
 
 struct PPCE500PCIState {
+    PCIHostState pci_state;
     struct pci_outbound pob[PPCE500_PCI_NR_POBS];
     struct pci_inbound pib[PPCE500_PCI_NR_PIBS];
     uint32_t gasket_time;
-    PCIHostState pci_state;
-    PCIDevice *pci_dev;
+    uint64_t base_addr;
 };
 
 typedef struct PPCE500PCIState PPCE500PCIState;
@@ -250,7 +250,6 @@ static const VMStateDescription vmstate_ppce500_pci = {
     .minimum_version_id = 1,
     .minimum_version_id_old = 1,
     .fields      = (VMStateField[]) {
-        VMSTATE_PCI_DEVICE_POINTER(pci_dev, PPCE500PCIState),
         VMSTATE_STRUCT_ARRAY(pob, PPCE500PCIState, PPCE500_PCI_NR_POBS, 1,
                              vmstate_pci_outbound, struct pci_outbound),
         VMSTATE_STRUCT_ARRAY(pib, PPCE500PCIState, PPCE500_PCI_NR_PIBS, 1,
@@ -262,58 +261,93 @@ static const VMStateDescription vmstate_ppce500_pci = {
 
 PCIBus *ppce500_pci_init(qemu_irq pci_irqs[4], target_phys_addr_t registers)
 {
-    PPCE500PCIState *controller;
+    DeviceState *dev;
+    PCIBus *b;
+    PCIHostState *h;
+    PPCE500PCIState *s;
     PCIDevice *d;
-    int index;
     static int ppce500_pci_id;
+    SysBusDevice *sb;
+
+    dev = qdev_create(NULL, "e500-pcihost");
+    sb = sysbus_from_qdev(dev);
+    h = FROM_SYSBUS(PCIHostState, sb);
+    s = DO_UPCAST(PPCE500PCIState, pci_state, h);
+
+    b = pci_register_bus(&s->pci_state.busdev.qdev, NULL, mpc85xx_pci_set_irq,
+                         mpc85xx_pci_map_irq, pci_irqs, PCI_DEVFN(0x11, 0), 4);
 
-    controller = qemu_mallocz(sizeof(PPCE500PCIState));
+    s->pci_state.bus = b;
+    qdev_init_nofail(dev);
+    d = pci_create_simple(b, 0, "e500-host-bridge");
 
-    controller->pci_state.bus = pci_register_bus(NULL, "pci",
-                                                 mpc85xx_pci_set_irq,
-                                                 mpc85xx_pci_map_irq,
-                                                 pci_irqs, PCI_DEVFN(0x11, 0),
-                                                 4);
-    d = pci_register_device(controller->pci_state.bus,
-                            "host bridge", sizeof(PCIDevice),
-                            0, NULL, NULL);
+    sysbus_mmio_map(sb, 0, registers + PCIE500_CFGADDR);
+    sysbus_mmio_map(sb, 1, registers + PCIE500_CFGDATA);
+    sysbus_mmio_map(sb, 2, registers + PCIE500_REG_BASE);
 
-    pci_config_set_vendor_id(d->config, PCI_VENDOR_ID_FREESCALE);
-    pci_config_set_device_id(d->config, PCI_DEVICE_ID_MPC8533E);
-    pci_config_set_class(d->config, PCI_CLASS_PROCESSOR_POWERPC);
+    /* XXX load/save code not tested. */
+    vmstate_register(&d->qdev, ppce500_pci_id++, &vmstate_ppce500_pci, s);
+
+    return b;
+}
+
+static int e500_pcihost_initfn(SysBusDevice *dev)
+{
+    PCIHostState *h;
+    PPCE500PCIState *s;
+    /* XXX qdev var */
+    int index;
 
-    controller->pci_dev = d;
+    h = FROM_SYSBUS(PCIHostState, sysbus_from_qdev(dev));
+    s = DO_UPCAST(PPCE500PCIState, pci_state, h);
 
     /* CFGADDR */
-    index = pci_host_conf_register_mmio(&controller->pci_state,
-                                        DEVICE_BIG_ENDIAN);
+    index = pci_host_conf_register_mmio(&s->pci_state, DEVICE_BIG_ENDIAN);
     if (index < 0)
-        goto free;
-    cpu_register_physical_memory(registers + PCIE500_CFGADDR, 4, index);
+        return -1;
+    sysbus_init_mmio(dev, 4, index);
 
     /* CFGDATA */
-    index = pci_host_data_register_mmio(&controller->pci_state,
-                                        DEVICE_BIG_ENDIAN);
+    index = pci_host_data_register_mmio(&s->pci_state, DEVICE_LITTLE_ENDIAN);
     if (index < 0)
-        goto free;
-    cpu_register_physical_memory(registers + PCIE500_CFGDATA, 4, index);
+        return -1;
+    sysbus_init_mmio(dev, 4, index);
 
     index = cpu_register_io_memory(e500_pci_reg_read,
-                                   e500_pci_reg_write, controller,
-                                   DEVICE_NATIVE_ENDIAN);
+                                   e500_pci_reg_write, s, DEVICE_BIG_ENDIAN);
     if (index < 0)
-        goto free;
-    cpu_register_physical_memory(registers + PCIE500_REG_BASE,
-                                   PCIE500_REG_SIZE, index);
+        return -1;
+    sysbus_init_mmio(dev, PCIE500_REG_SIZE, index);
+    return 0;
+}
 
-    /* XXX load/save code not tested. */
-    vmstate_register(&d->qdev, ppce500_pci_id++, &vmstate_ppce500_pci,
-                     controller);
+static int e500_host_bridge_initfn(PCIDevice *dev)
+{
+    pci_config_set_vendor_id(dev->config, PCI_VENDOR_ID_FREESCALE);
+    pci_config_set_device_id(dev->config, PCI_DEVICE_ID_MPC8533E);
+    pci_config_set_class(dev->config, PCI_CLASS_PROCESSOR_POWERPC);
+
+    return 0;
+}
 
-    return controller->pci_state.bus;
+static PCIDeviceInfo e500_host_bridge_info = {
+    .qdev.name    = "e500-host-bridge",
+    .qdev.desc    = "Host bridge",
+    .qdev.size    = sizeof(PCIDevice),
+    .qdev.no_user = 1,
+    .init         = e500_host_bridge_initfn,
+};
 
-free:
-    printf("%s error\n", __func__);
-    qemu_free(controller);
-    return NULL;
+static SysBusDeviceInfo e500_pcihost_info = {
+    .init         = e500_pcihost_initfn,
+    .qdev.name    = "e500-pcihost",
+    .qdev.size    = sizeof(PPCE500PCIState),
+    .qdev.no_user = 1,
+};
+
+static void e500_pci_register(void)
+{
+    sysbus_register_withprop(&e500_pcihost_info);
+    pci_qdev_register(&e500_host_bridge_info);
 }
+device_init(e500_pci_register);
-- 
1.6.0.2

^ permalink raw reply related	[flat|nested] 15+ messages in thread

* Re: [Qemu-devel] [PATCH 5/6] PPC: Implement e500 (FSL) MMU
  2011-05-02 15:03 ` [Qemu-devel] [PATCH 5/6] PPC: Implement e500 (FSL) MMU Alexander Graf
@ 2011-05-03 19:25   ` Scott Wood
  2011-05-06 10:01     ` Alexander Graf
  0 siblings, 1 reply; 15+ messages in thread
From: Scott Wood @ 2011-05-03 19:25 UTC (permalink / raw)
  To: Alexander Graf
  Cc: Blue Swirl, Edgar E. Iglesias, Liu Yu, QEMU-devel Developers

On Mon, 2 May 2011 17:03:21 +0200
Alexander Graf <agraf@suse.de> wrote:

> Most of the code to support e500 style MMUs is already in place, but
> we're missing on some of the special TLB0-TLB1 handling code and slightly
> different TLB modification.
> 
> This patch adds support for the FSL style MMU.
> 
> Signed-off-by: Alexander Graf <agraf@suse.de>

You beat me to (part of) it... :-)

How is this going to interact with the KVM MMU API, where it was suggested
that qemu use that representation as its native structure?  Should we just
change the representation at that point, for both types of booke mmu (so 4xx
would be represented with MAS registers internally, even though a
different interface is exposed to the guest)?

> @@ -678,8 +887,9 @@ struct CPUPPCState {
>      int nb_BATs;
>      target_ulong DBAT[2][8];
>      target_ulong IBAT[2][8];
> -    /* PowerPC TLB registers (for 4xx and 60x software driven TLBs) */
> +    /* PowerPC TLB registers (for 4xx, e500 and 60x software driven TLBs) */
>      int nb_tlb;      /* Total number of TLB                                  */
> +    int nb_tlbs[4];  /* Number of respective TLB entries (e500)              */

Looks like "number of tlbs", not "number of tlb entries"... Was less
confusing when there was only one tlb array.

> diff --git a/target-ppc/helper.c b/target-ppc/helper.c
> index 5e4030b..261c1a9 100644
> --- a/target-ppc/helper.c
> +++ b/target-ppc/helper.c
> @@ -1153,48 +1153,144 @@ void store_40x_sler (CPUPPCState *env, uint32_t val)
>      env->spr[SPR_405_SLER] = val;
>  }
>  
> +static inline int mmubooke_check_tlb (CPUState *env, ppcemb_tlb_t *tlb,
> +                                      target_phys_addr_t *raddr, int *prot,
> +                                      target_ulong address, int rw,
> +                                      int access_type, int i)
> +{
> +    int ret, _prot;
> +
> +    if (ppcemb_tlb_check(env, tlb, raddr, address,
> +                         env->spr[SPR_BOOKE_PID],
> +                         !env->nb_pids, i) >= 0) {
> +        goto found_tlb;
> +    }
> +
> +    if ((env->nb_pids > 1) && env->spr[SPR_BOOKE_PID1] &&
> +        ppcemb_tlb_check(env, tlb, raddr, address,
> +                         env->spr[SPR_BOOKE_PID1], 0, i) >= 0) {
> +        goto found_tlb;
> +    }
> +
> +    if ((env->nb_pids > 2) && env->spr[SPR_BOOKE_PID2] &&
> +        ppcemb_tlb_check(env, tlb, raddr, address,
> +                         env->spr[SPR_BOOKE_PID2], 0, i) >= 0) {
> +        goto found_tlb;
> +    }

Maybe PID1/PID2 should be moved into ppcemb_tlb_check, and eliminate the
nb_pids checks by putting zero in PID1/PID2 on chips that don't have it?
I'm assuming this is performance sensitive for non-KVM.

> +static int mmue500_get_physical_address (CPUState *env, mmu_ctx_t *ctx,
> +                                         target_ulong address, int rw,
> +                                         int access_type)
> +{
> +    ppcemb_tlb_t *tlb;
> +    target_phys_addr_t raddr;
> +    int i, ret;
> +    uint32_t ea = (address >> MAS2_EPN_SHIFT) & 0x7f;
> +
> +    ret = -1;
> +    raddr = (target_phys_addr_t)-1ULL;
> +
> +    /* check TLB1 - hits often because the kernel is here */

I'd optimize for userspace instead -- that's where the real work is more
likely to happen.  Plus, compare what's likely to be 5-6 iterations before
finding the entry for a kernel large-page entry if we check TLB0 first,
versus 17+ iterations (65+ on e500mc) for finding a TLB0 entry if TLB1 is
checked first -- based on Linux's TLB1 usage patterns.

> +    for (i = env->nb_tlbs[0]; i < env->nb_tlb; i++) {
> +        tlb = &env->tlb[i].tlbe;
> +        ret = mmubooke_check_tlb(env, tlb, &raddr, &ctx->prot, address, rw,
> +                                 access_type, i);
> +        if (!ret) {
> +            goto found_tlb;
>          }
>      }
> -    if (ret >= 0)
> +
> +    /* check possible TLB0 entries */
> +    for (i = 0; i < env->nb_ways; i++) {
> +        tlb = &env->tlb[ea | (i << 7)].tlbe;

Do we have to hardcode 7 (and 0x7f) here?

And if possible I'd rearrange the tlb so that ways within a set are
contiguous.  Better for cache utilization, and is what the KVM MMU API will
want.

> @@ -1348,6 +1446,44 @@ target_phys_addr_t cpu_get_phys_page_debug (CPUState *env, target_ulong addr)
>      return ctx.raddr & TARGET_PAGE_MASK;
>  }
>  
> +static void e500_update_mas_tlb_miss(CPUState *env, target_ulong address,
> +                                     int rw)
> +{
> +    env->spr[SPR_BOOKE_MAS0] = env->spr[SPR_BOOKE_MAS4] & MAS4_TLBSELD_MASK;
> +    env->spr[SPR_BOOKE_MAS1] = env->spr[SPR_BOOKE_MAS4] & MAS4_TSIZED_MASK;
> +    env->spr[SPR_BOOKE_MAS2] = env->spr[SPR_BOOKE_MAS4] & MAS4_WIMGED_MASK;
> +    env->spr[SPR_BOOKE_MAS6] = 0;
> +
> +    /* AS */
> +    if (((rw == 2) && msr_ir) || ((rw != 2) && msr_dr)) {
> +        env->spr[SPR_BOOKE_MAS1] |= MAS1_TS;
> +        env->spr[SPR_BOOKE_MAS6] |= MAS6_SAS;
> +    }
> +
> +    env->spr[SPR_BOOKE_MAS1] |= MAS1_VALID;
> +    env->spr[SPR_BOOKE_MAS2] |= address & MAS2_EPN_MASK;
> +
> +    switch (env->spr[SPR_BOOKE_MAS4] & MAS4_TIDSELD_PIDZ) {
> +    case MAS4_TIDSELD_PID0:
> +        env->spr[SPR_BOOKE_MAS1] |= env->spr[SPR_BOOKE_PID] << MAS1_TID_SHIFT;
> +        break;
> +    case MAS4_TIDSELD_PID1:
> +        env->spr[SPR_BOOKE_MAS1] |= env->spr[SPR_BOOKE_PID1] << MAS1_TID_SHIFT;
> +        break;
> +    case MAS4_TIDSELD_PID2:
> +        env->spr[SPR_BOOKE_MAS1] |= env->spr[SPR_BOOKE_PID2] << MAS1_TID_SHIFT;
> +        break;
> +    }
> +
> +    env->spr[SPR_BOOKE_MAS6] |= env->spr[SPR_BOOKE_PID] << 16;
> +
> +    /* next victim logic */
> +    env->spr[SPR_BOOKE_MAS0] |= env->last_way << MAS0_ESEL_SHIFT;
> +    env->last_way++;
> +    env->last_way &= 3;
> +    env->spr[SPR_BOOKE_MAS0] |= env->last_way << MAS0_NV_SHIFT;
> +}

MAS3/7 should be zeroed according to the architecture.

Better victim selection would check for empty ways, and perhaps keep
last_way on a per-set basis.

> @@ -1820,12 +1956,8 @@ void ppc_tlb_invalidate_all (CPUPPCState *env)
>          cpu_abort(env, "MPC8xx MMU model is not implemented\n");
>          break;
>      case POWERPC_MMU_BOOKE:
> -        tlb_flush(env, 1);
> -        break;
>      case POWERPC_MMU_BOOKE_FSL:
> -        /* XXX: TODO */
> -        if (!kvm_enabled())
> -            cpu_abort(env, "BookE MMU model is not implemented\n");
> +        tlb_flush(env, 1);
>          break;
>      case POWERPC_MMU_32B:
>      case POWERPC_MMU_601:

This flushes env->tlb_table, but don't we still need to clear out env->tlb?

> diff --git a/target-ppc/op_helper.c b/target-ppc/op_helper.c
> index d5db484..3c0b061 100644
> --- a/target-ppc/op_helper.c
> +++ b/target-ppc/op_helper.c
> @@ -4206,4 +4206,422 @@ target_ulong helper_440_tlbsx (target_ulong address)
>      return ppcemb_tlb_search(env, address, env->spr[SPR_440_MMUCR] & 0xFF);
>  }
>  
> +/* PowerPC e500 TLB management */
> +
> +static inline int e500_tlb_num(CPUState *env, ppcemb_tlb_t *tlb)
> +{
> +    ulong tlbel = (ulong)tlb;
> +    ulong tlbl = (ulong)env->tlb;
> +
> +    return (tlbel - tlbl) / sizeof(env->tlb[0]);
> +}
> +
> +static inline ppcemb_tlb_t *e500_cur_tlb(CPUState *env)

This is a bit big to be inlined -  let the compiler decide such things.

> +{
> +    uint32_t tlbncfg = 0;
> +    int esel = (env->spr[SPR_BOOKE_MAS0] & MAS0_ESEL_MASK) >> MAS0_ESEL_SHIFT;
> +    int ea = (env->spr[SPR_BOOKE_MAS2] & MAS2_EPN_MASK) >> MAS2_EPN_SHIFT;
> +    int tlb;
> +    int r;
> +
> +    tlb = (env->spr[SPR_BOOKE_MAS0] & MAS0_TLBSEL_MASK) >> MAS0_TLBSEL_SHIFT;
> +    tlbncfg = env->spr[SPR_BOOKE_TLB0CFG + tlb];
> +
> +    if ((tlbncfg & TLBnCFG_HES) && (env->spr[SPR_BOOKE_MAS0] & MAS0_HES)) {
> +        cpu_abort(env, "we don't support HES yet\n");
> +    }
> +
> +    if (tlb == 1) {
> +        r = env->nb_tlbs[0] + (esel % env->nb_tlbs[1]);

Ouch, division by non-constant.

There's no need for it anyway; esel >= env_nb_tlbs[1] is undefined
behavior.  Just crop the value arbitrarily (or error out, if possible) to
avoid dereferencing a bad array index.

> +    } else {
> +        esel &= env->nb_ways - 1;
> +        esel <<= 7;
> +        ea &= 0x7f;
> +        r = (esel | ea) % env->nb_tlbs[0];

More unnecessary division -- use "& (env->nb_tlbs[0] - 1)", or variable-ize
the 7 and 0x7f so that we know that we won't produce an out-of-bounds value.

> +static const target_phys_addr_t e500_tlb_sizes[] = {
> +    0,
> +    4 * 1024,
> +    16 * 1024,
> +    64 * 1024,
> +    256 * 1024,
> +    1024 * 1024,
> +    4 * 1024 * 1024,
> +    16 * 1024 * 1024,
> +    64 * 1024 * 1024,
> +    256 * 1024 * 1024,
> +    1024 * 1024 * 1024,
> +    (target_phys_addr_t)(4ULL * 1024ULL * 1024ULL * 1024ULL),
> +};

FWIW, power-of-2 page sizes are architected, and may appear in future
e500-family chips.  The TSIZE field is extended by one bit on the right
(previously reserved and should-be-zero).

> +static inline target_phys_addr_t e500_tlb_to_page_size(int size)

unsigned int

> +{
> +    target_phys_addr_t r;
> +
> +    if (size > 11) {

if (size >= ARRAY_SIZE(e500_tlb_sizes)) {

> +        /* should not happen */
> +        r = 1024 * 1024 * 1024;

Error message?

+    switch (env->spr[SPR_BOOKE_MAS0] & MAS0_WQ_MASK) {
+    case MAS0_WQ_ALWAYS:
+        /* good to go, write that entry */
+        break;
+    case MAS0_WQ_COND:
+        /* XXX check if reserved */
+        if (0) {
+            return;
+        }
+        break;
+    case MAS0_WQ_CLR_RSRV:
+        /* XXX clear entry */
+        return;
+    default:
+        /* no idea what to do */
+        return;
+    }

If the plan is to support such things, might want a more generic name than
"e500" -- we're really talking about isa 2.06 book3e.  The first chip that
implements this stuff will probably not be from Freescale, much less
called "e500". :-)

> +    if (msr_gs) {
> +        cpu_abort(env, "missing HV implementation\n");

What's the policy on aborting versus error-message versus no-op if the
guest invokes undefined/unimplemented behavior?

> +    } else {
> +        rpn = ((uint64_t)env->spr[SPR_BOOKE_MAS7] << 32) |
> +              (env->spr[SPR_BOOKE_MAS3] & 0xfffff000);
> +    }

Not sure why this is in an else-branch versus msr_gs.

> +    tlb->RPN = rpn;
> +
> +    tlb->PID = (env->spr[SPR_BOOKE_MAS1] & MAS1_TID_MASK) >> MAS1_TID_SHIFT;
> +    tlb->size = e500_tlb_to_page_size((env->spr[SPR_BOOKE_MAS1]
> +                      & MAS1_TSIZE_MASK) >> MAS1_TSIZE_SHIFT);

e500 manuals document that tsize is ignored in tlb0.

> +    tlb->EPN = (uint32_t)(env->spr[SPR_BOOKE_MAS2] & MAS2_EPN_MASK);
> +    tlb->attr = env->spr[SPR_BOOKE_MAS2] & (MAS2_ACM | MAS2_VLE | MAS2_W |
> +                                            MAS2_I | MAS2_M | MAS2_G | MAS2_E)
> +                << 1;
> +    tlb->attr |= env->spr[SPR_BOOKE_MAS1] & MAS1_IPROT;
> +    tlb->attr |= (env->spr[SPR_BOOKE_MAS3] &
> +                  ((MAS3_U0 | MAS3_U1 | MAS3_U2 | MAS3_U3)) << 8);

Might be nice to #define the encoding of these bits into attr/etc, versus
magic shifts (though it's moot if we're going to switch to a MAS-based
representation).

> +    if (tlb->size == TARGET_PAGE_SIZE) {
> +        tlb_flush_page(env, tlb->EPN);
> +    } else {
> +        tlb_flush(env, 1);
> +    }

Need to check whether the previous entry was a large page needing a full
flush.

> +void helper_e500_tlbre(void)
> +{
> +    ppcemb_tlb_t *tlb = NULL;
> +
> +    tlb = e500_cur_tlb(env);
> +    e500_tlb_to_mas(env, tlb, e500_tlb_num(env, tlb));
> +}
> +
> +/* Generic TLB check function for embedded PowerPC implementations */
> +static inline int ppcemb_tlb_check(CPUState *env, ppcemb_tlb_t *tlb,
> +                                   target_phys_addr_t *raddrp,
> +                                   target_ulong address, uint32_t pid, int ext,
> +                                   int i)

Why is this both here and in helper.c?

> +void helper_e500_tlbsx(target_ulong address_hi, target_ulong address_lo)
> +{
> +    ppcemb_tlb_t *tlb = NULL;
> +    int i;
> +    target_phys_addr_t raddr;
> +    uint32_t spid, sas;
> +    uint32_t ea = (address_lo >> MAS2_EPN_SHIFT) & 0x7f;
> +
> +    spid = (env->spr[SPR_BOOKE_MAS6] & MAS6_SPID_MASK) >> MAS6_SPID_SHIFT;
> +    sas = env->spr[SPR_BOOKE_MAS6] & MAS6_SAS;
> +
> +    /* check possible TLB0 entries */
> +    for (i = 0; i < env->nb_ways; i++) {
> +        tlb = &env->tlb[ea | (i << 7)].tlbe;
> +
> +        if (ppcemb_tlb_check(env, tlb, &raddr, address_lo, spid, 0, i) < 0) {
> +            continue;
> +        }
> +
> +        if (sas != (tlb->attr & MAS6_SAS)) {
> +            continue;
> +        }
> +
> +        e500_tlb_to_mas(env, tlb, ea | (i << 7));
> +        return;
> +    }
> +
> +    /* check TLB1 */
> +    for (i = env->nb_tlbs[0]; i < (env->nb_tlbs[0] + env->nb_tlbs[1]); i++) {
> +        tlb = &env->tlb[i].tlbe;
> +
> +        if (ppcemb_tlb_check(env, tlb, &raddr, address_lo, spid, 0, i) < 0) {
> +            continue;
> +        }
> +
> +        if (sas != (tlb->attr & MAS6_SAS)) {
> +            continue;
> +        }
> +
> +        e500_tlb_to_mas(env, tlb, i);
> +        return;
> +    }

This has a lot of overlap with mmue500_get_physical_address()...

> +
> +    /* no entry found, fill with defaults */
> +    env->spr[SPR_BOOKE_MAS0] = env->spr[SPR_BOOKE_MAS4] & MAS4_TLBSELD_MASK;
> +    env->spr[SPR_BOOKE_MAS1] = env->spr[SPR_BOOKE_MAS4] & MAS4_TSIZED_MASK;
> +    env->spr[SPR_BOOKE_MAS2] = env->spr[SPR_BOOKE_MAS4] & MAS4_WIMGED_MASK;
> +
> +    if (env->spr[SPR_BOOKE_MAS6] & MAS6_SAS) {
> +        env->spr[SPR_BOOKE_MAS1] |= MAS1_TS;
> +    }
> +
> +    env->spr[SPR_BOOKE_MAS1] |= (env->spr[SPR_BOOKE_MAS6] >> 16)
> +                                << MAS1_TID_SHIFT;
> +
> +    /* next victim logic */
> +    env->spr[SPR_BOOKE_MAS0] |= env->last_way << MAS0_ESEL_SHIFT;
> +    env->last_way++;
> +    env->last_way &= 3;
> +    env->spr[SPR_BOOKE_MAS0] |= env->last_way << MAS0_NV_SHIFT;

...and this with e500_update_mas_tlb_miss().

> @@ -8433,7 +8505,7 @@ GEN_HANDLER2(icbt_40x, "icbt", 0x1F, 0x06, 0x08, 0x03E00001, PPC_40x_ICBT),
>  GEN_HANDLER(iccci, 0x1F, 0x06, 0x1E, 0x00000001, PPC_4xx_COMMON),
>  GEN_HANDLER(icread, 0x1F, 0x06, 0x1F, 0x03E00001, PPC_4xx_COMMON),
>  GEN_HANDLER2(rfci_40x, "rfci", 0x13, 0x13, 0x01, 0x03FF8001, PPC_40x_EXCP),
> -GEN_HANDLER(rfci, 0x13, 0x13, 0x01, 0x03FF8001, PPC_BOOKE),
> +GEN_HANDLER_E(rfci, 0x13, 0x13, 0x01, 0x03FF8001, PPC_BOOKE, PPC2_BOOKE_FSL),

What is PPC2_BOOKE_FSL supposed to indicate?

rfci is basic booke.  It's in the 440.

> +GEN_HANDLER2_E(icbt_440, "icbt", 0x1F, 0x16, 0x00, 0x03E00001,
> +               PPC_BOOKE, PPC2_BOOKE_FSL),

"icbt_440" is FSL-specific? :-)

> +static void spr_write_booke_pid (void *opaque, int sprn, int gprn)
> +{
> +    gen_store_spr(sprn, cpu_gpr[gprn]);
> +    /* switching context, so need to flush tlb */
> +    gen_helper_tlbia();
> +}

Well, we want to flush the non-guest-visible TLB that doesn't understand
PIDs -- but I'd expect "tlbia" to flush the architected TLB.  8xx, at
least, has both tlbia and an architected TLB.

Plus, we need ppc_tlb_invalidate_all() to clear the architected TLB, unless
we call something different on reset.

> @@ -1578,45 +1614,38 @@ static void gen_spr_BookE_FSL (CPUPPCState *env, uint32_t mas_mask)
>                   SPR_NOACCESS, SPR_NOACCESS,
>                   &spr_read_generic, SPR_NOACCESS,
>                   0x00000000); /* TOFIX */
> -    /* XXX : not implemented */
> -    spr_register(env, SPR_MMUCSR0, "MMUCSR0",
> -                 SPR_NOACCESS, SPR_NOACCESS,
> -                 &spr_read_generic, &spr_write_generic,
> -                 0x00000000); /* TOFIX */
>      switch (env->nb_ways) {
>      case 4:
> -        /* XXX : not implemented */
>          spr_register(env, SPR_BOOKE_TLB3CFG, "TLB3CFG",
>                       SPR_NOACCESS, SPR_NOACCESS,
>                       &spr_read_generic, SPR_NOACCESS,
> -                     0x00000000); /* TOFIX */
> +                     tlbncfg[3]);
>          /* Fallthru */
>      case 3:
> -        /* XXX : not implemented */
>          spr_register(env, SPR_BOOKE_TLB2CFG, "TLB2CFG",
>                       SPR_NOACCESS, SPR_NOACCESS,
>                       &spr_read_generic, SPR_NOACCESS,
> -                     0x00000000); /* TOFIX */
> +                     tlbncfg[2]);
>          /* Fallthru */

In some places you use nb_ways as the associativity of TLB0.  But here it
seems to be the number of TLB arrays?

> @@ -4334,8 +4373,23 @@ static void init_proc_e500 (CPUPPCState *env)
>      /* Memory management */
>  #if !defined(CONFIG_USER_ONLY)
>      env->nb_pids = 3;
> +    env->nb_ways = 2;
> +    env->id_tlbs = 0;
> +    if ((env->spr[SPR_PVR] & 0x00010000)) {
> +        /* e500v2 */
> +        env->nb_tlbs[0] = 512;
> +        tlbncfg[0] = gen_tlbncfg(4, 1, 1, 0, env->nb_tlbs[0]);
> +        tlbncfg[1] = gen_tlbncfg(16, 1, 12, TLBnCFG_AVAIL | TLBnCFG_IPROT, 16);
> +    } else {
> +        /* e500v1 */
> +        env->nb_tlbs[0] = 256;
> +        tlbncfg[0] = gen_tlbncfg(2, 1, 1, 0, env->nb_tlbs[0]);
> +        tlbncfg[1] = gen_tlbncfg(16, 1, 9, TLBnCFG_AVAIL | TLBnCFG_IPROT, 16);
> +    }

It would be nice to be more precise with PVR testing, and complain if an
unrecognized PVR is used (e.g. e500mc).

-Scott

^ permalink raw reply	[flat|nested] 15+ messages in thread

* Re: [Qemu-devel] [PATCH 6/6] PPC: Qdev'ify e500 pci
  2011-05-02 15:03 ` [Qemu-devel] [PATCH 6/6] PPC: Qdev'ify e500 pci Alexander Graf
@ 2011-05-04 19:08   ` Blue Swirl
  2011-05-05 10:43     ` Alexander Graf
  0 siblings, 1 reply; 15+ messages in thread
From: Blue Swirl @ 2011-05-04 19:08 UTC (permalink / raw)
  To: Alexander Graf
  Cc: Scott Wood, Edgar E. Iglesias, Liu Yu, QEMU-devel Developers

On Mon, May 2, 2011 at 6:03 PM, Alexander Graf <agraf@suse.de> wrote:
> The e500 PCI controller isn't qdev'ified yet. This leads to severe issues
> when running with -drive.
>
> To be able to use a virtio disk with an e500 VM, let's convert the PCI
> controller over to qdev.
>
> Signed-off-by: Alexander Graf <agraf@suse.de>
>
> ---
>
> v2 -> v3:
>
>  - rebase to current code base
>  - fix endian issue
>  - use sysbus helpers
> ---
>  hw/ppce500_pci.c |  112 +++++++++++++++++++++++++++++++++++-------------------
>  1 files changed, 73 insertions(+), 39 deletions(-)
>
> diff --git a/hw/ppce500_pci.c b/hw/ppce500_pci.c
> index 83a20e4..88bc759 100644
> --- a/hw/ppce500_pci.c
> +++ b/hw/ppce500_pci.c
> @@ -73,11 +73,11 @@ struct pci_inbound {
>  };
>
>  struct PPCE500PCIState {
> +    PCIHostState pci_state;
>     struct pci_outbound pob[PPCE500_PCI_NR_POBS];
>     struct pci_inbound pib[PPCE500_PCI_NR_PIBS];
>     uint32_t gasket_time;
> -    PCIHostState pci_state;
> -    PCIDevice *pci_dev;
> +    uint64_t base_addr;

This does not seem to be used. Also devices shouldn't care about their
base addresses.

^ permalink raw reply	[flat|nested] 15+ messages in thread

* Re: [Qemu-devel] [PATCH 0/6] PPC: Add FSL (e500) MMU emulation v3
  2011-05-02 15:03 [Qemu-devel] [PATCH 0/6] PPC: Add FSL (e500) MMU emulation v3 Alexander Graf
                   ` (5 preceding siblings ...)
  2011-05-02 15:03 ` [Qemu-devel] [PATCH 6/6] PPC: Qdev'ify e500 pci Alexander Graf
@ 2011-05-04 19:09 ` Blue Swirl
  6 siblings, 0 replies; 15+ messages in thread
From: Blue Swirl @ 2011-05-04 19:09 UTC (permalink / raw)
  To: Alexander Graf
  Cc: Scott Wood, Edgar E. Iglesias, Liu Yu, QEMU-devel Developers

On Mon, May 2, 2011 at 6:03 PM, Alexander Graf <agraf@suse.de> wrote:
> In a global effort to get rid of KVM-only targets, this is the next
> important piece of the puzzle: e500 emulation :).
>
> We had support for running an e500 KVM guest for a while now, but the
> code could not be tested without a real e500 machine, because it required
> KVM to work. This patchset adds emulation for the e500 MMU, enabling
> anyone to use the MPC8544DS emulation.

I had some comments to 6/6, otherwise all look fine to me.

^ permalink raw reply	[flat|nested] 15+ messages in thread

* Re: [Qemu-devel] [PATCH 6/6] PPC: Qdev'ify e500 pci
  2011-05-04 19:08   ` Blue Swirl
@ 2011-05-05 10:43     ` Alexander Graf
  0 siblings, 0 replies; 15+ messages in thread
From: Alexander Graf @ 2011-05-05 10:43 UTC (permalink / raw)
  To: Blue Swirl; +Cc: Scott Wood, Edgar E. Iglesias, Liu Yu, QEMU-devel Developers


On 04.05.2011, at 21:08, Blue Swirl wrote:

> On Mon, May 2, 2011 at 6:03 PM, Alexander Graf <agraf@suse.de> wrote:
>> The e500 PCI controller isn't qdev'ified yet. This leads to severe issues
>> when running with -drive.
>> 
>> To be able to use a virtio disk with an e500 VM, let's convert the PCI
>> controller over to qdev.
>> 
>> Signed-off-by: Alexander Graf <agraf@suse.de>
>> 
>> ---
>> 
>> v2 -> v3:
>> 
>>  - rebase to current code base
>>  - fix endian issue
>>  - use sysbus helpers
>> ---
>>  hw/ppce500_pci.c |  112 +++++++++++++++++++++++++++++++++++-------------------
>>  1 files changed, 73 insertions(+), 39 deletions(-)
>> 
>> diff --git a/hw/ppce500_pci.c b/hw/ppce500_pci.c
>> index 83a20e4..88bc759 100644
>> --- a/hw/ppce500_pci.c
>> +++ b/hw/ppce500_pci.c
>> @@ -73,11 +73,11 @@ struct pci_inbound {
>>  };
>> 
>>  struct PPCE500PCIState {
>> +    PCIHostState pci_state;
>>     struct pci_outbound pob[PPCE500_PCI_NR_POBS];
>>     struct pci_inbound pib[PPCE500_PCI_NR_PIBS];
>>     uint32_t gasket_time;
>> -    PCIHostState pci_state;
>> -    PCIDevice *pci_dev;
>> +    uint64_t base_addr;
> 
> This does not seem to be used. Also devices shouldn't care about their
> base addresses.

Oops - must have missed that one :). Thanks!


Alex

^ permalink raw reply	[flat|nested] 15+ messages in thread

* Re: [Qemu-devel] [PATCH 5/6] PPC: Implement e500 (FSL) MMU
  2011-05-03 19:25   ` Scott Wood
@ 2011-05-06 10:01     ` Alexander Graf
  2011-05-06 17:40       ` Scott Wood
  0 siblings, 1 reply; 15+ messages in thread
From: Alexander Graf @ 2011-05-06 10:01 UTC (permalink / raw)
  To: Scott Wood; +Cc: Blue Swirl, Edgar E. Iglesias, Liu Yu, QEMU-devel Developers


On 03.05.2011, at 21:25, Scott Wood wrote:

> On Mon, 2 May 2011 17:03:21 +0200
> Alexander Graf <agraf@suse.de> wrote:
> 
>> Most of the code to support e500 style MMUs is already in place, but
>> we're missing on some of the special TLB0-TLB1 handling code and slightly
>> different TLB modification.
>> 
>> This patch adds support for the FSL style MMU.
>> 
>> Signed-off-by: Alexander Graf <agraf@suse.de>
> 
> You beat me to (part of) it... :-)
> 
> How is this going to interact with the KVM MMU API, where it was suggested
> that qemu use that representation as its native structure?  Should we just
> change the representation at that point, for both types of booke mmu (so 4xx
> would be represented with MAS registers internally, even though a
> different interface is exposed to the guest)?

Ugh - I completely forgot about that one. I guess we'll just have to redo the internal TLB resolution code at that point, yes. I somehow prefer to work my way from working solution to working solution though, so I don't think I'll move it over to a MAS based approach just yet.

> 
>> @@ -678,8 +887,9 @@ struct CPUPPCState {
>>     int nb_BATs;
>>     target_ulong DBAT[2][8];
>>     target_ulong IBAT[2][8];
>> -    /* PowerPC TLB registers (for 4xx and 60x software driven TLBs) */
>> +    /* PowerPC TLB registers (for 4xx, e500 and 60x software driven TLBs) */
>>     int nb_tlb;      /* Total number of TLB                                  */
>> +    int nb_tlbs[4];  /* Number of respective TLB entries (e500)              */
> 
> Looks like "number of tlbs", not "number of tlb entries"... Was less
> confusing when there was only one tlb array.

I certainly agree, but this way I don't have to change non-e500 code :). I actually started off creating a new TLB struct with 4 entries (the 4 TLBs allowed by the 2.06 spec), but quickly gave up as it's a _lot_ of code using these O_o.

Either way, it's all different now anyways :).

>> diff --git a/target-ppc/helper.c b/target-ppc/helper.c
>> index 5e4030b..261c1a9 100644
>> --- a/target-ppc/helper.c
>> +++ b/target-ppc/helper.c
>> @@ -1153,48 +1153,144 @@ void store_40x_sler (CPUPPCState *env, uint32_t val)
>>     env->spr[SPR_405_SLER] = val;
>> }
>> 
>> +static inline int mmubooke_check_tlb (CPUState *env, ppcemb_tlb_t *tlb,
>> +                                      target_phys_addr_t *raddr, int *prot,
>> +                                      target_ulong address, int rw,
>> +                                      int access_type, int i)
>> +{
>> +    int ret, _prot;
>> +
>> +    if (ppcemb_tlb_check(env, tlb, raddr, address,
>> +                         env->spr[SPR_BOOKE_PID],
>> +                         !env->nb_pids, i) >= 0) {
>> +        goto found_tlb;
>> +    }
>> +
>> +    if ((env->nb_pids > 1) && env->spr[SPR_BOOKE_PID1] &&
>> +        ppcemb_tlb_check(env, tlb, raddr, address,
>> +                         env->spr[SPR_BOOKE_PID1], 0, i) >= 0) {
>> +        goto found_tlb;
>> +    }
>> +
>> +    if ((env->nb_pids > 2) && env->spr[SPR_BOOKE_PID2] &&
>> +        ppcemb_tlb_check(env, tlb, raddr, address,
>> +                         env->spr[SPR_BOOKE_PID2], 0, i) >= 0) {
>> +        goto found_tlb;
>> +    }
> 
> Maybe PID1/PID2 should be moved into ppcemb_tlb_check, and eliminate the
> nb_pids checks by putting zero in PID1/PID2 on chips that don't have it?
> I'm assuming this is performance sensitive for non-KVM.

PID1/PID2 are already 0 on chips that don't have them, so we could eliminate the check on nb_pids, yup. The small branch here really isn't too bad on performance though, so it's more of a readability thing than performance. We're currently killing performance anyways by flushing qemu's internal TLB on every MSR_IR/DR switch.

> 
>> +static int mmue500_get_physical_address (CPUState *env, mmu_ctx_t *ctx,
>> +                                         target_ulong address, int rw,
>> +                                         int access_type)
>> +{
>> +    ppcemb_tlb_t *tlb;
>> +    target_phys_addr_t raddr;
>> +    int i, ret;
>> +    uint32_t ea = (address >> MAS2_EPN_SHIFT) & 0x7f;
>> +
>> +    ret = -1;
>> +    raddr = (target_phys_addr_t)-1ULL;
>> +
>> +    /* check TLB1 - hits often because the kernel is here */
> 
> I'd optimize for userspace instead -- that's where the real work is more
> likely to happen.  Plus, compare what's likely to be 5-6 iterations before
> finding the entry for a kernel large-page entry if we check TLB0 first,
> versus 17+ iterations (65+ on e500mc) for finding a TLB0 entry if TLB1 is
> checked first -- based on Linux's TLB1 usage patterns.

Good point!

> 
>> +    for (i = env->nb_tlbs[0]; i < env->nb_tlb; i++) {
>> +        tlb = &env->tlb[i].tlbe;
>> +        ret = mmubooke_check_tlb(env, tlb, &raddr, &ctx->prot, address, rw,
>> +                                 access_type, i);
>> +        if (!ret) {
>> +            goto found_tlb;
>>         }
>>     }
>> -    if (ret >= 0)
>> +
>> +    /* check possible TLB0 entries */
>> +    for (i = 0; i < env->nb_ways; i++) {
>> +        tlb = &env->tlb[ea | (i << 7)].tlbe;
> 
> Do we have to hardcode 7 (and 0x7f) here?

I'm not sure - the spec isn't exactly obvious on this part. How do I find out the mask from TLBnCFG? But then again I could just take (nb_tlbs[n] - (1 << nb_ways[n])) - 1. I'll give that a try :).

> And if possible I'd rearrange the tlb so that ways within a set are
> contiguous.  Better for cache utilization, and is what the KVM MMU API will
> want.

Ok.

> 
>> @@ -1348,6 +1446,44 @@ target_phys_addr_t cpu_get_phys_page_debug (CPUState *env, target_ulong addr)
>>     return ctx.raddr & TARGET_PAGE_MASK;
>> }
>> 
>> +static void e500_update_mas_tlb_miss(CPUState *env, target_ulong address,
>> +                                     int rw)
>> +{
>> +    env->spr[SPR_BOOKE_MAS0] = env->spr[SPR_BOOKE_MAS4] & MAS4_TLBSELD_MASK;
>> +    env->spr[SPR_BOOKE_MAS1] = env->spr[SPR_BOOKE_MAS4] & MAS4_TSIZED_MASK;
>> +    env->spr[SPR_BOOKE_MAS2] = env->spr[SPR_BOOKE_MAS4] & MAS4_WIMGED_MASK;
>> +    env->spr[SPR_BOOKE_MAS6] = 0;
>> +
>> +    /* AS */
>> +    if (((rw == 2) && msr_ir) || ((rw != 2) && msr_dr)) {
>> +        env->spr[SPR_BOOKE_MAS1] |= MAS1_TS;
>> +        env->spr[SPR_BOOKE_MAS6] |= MAS6_SAS;
>> +    }
>> +
>> +    env->spr[SPR_BOOKE_MAS1] |= MAS1_VALID;
>> +    env->spr[SPR_BOOKE_MAS2] |= address & MAS2_EPN_MASK;
>> +
>> +    switch (env->spr[SPR_BOOKE_MAS4] & MAS4_TIDSELD_PIDZ) {
>> +    case MAS4_TIDSELD_PID0:
>> +        env->spr[SPR_BOOKE_MAS1] |= env->spr[SPR_BOOKE_PID] << MAS1_TID_SHIFT;
>> +        break;
>> +    case MAS4_TIDSELD_PID1:
>> +        env->spr[SPR_BOOKE_MAS1] |= env->spr[SPR_BOOKE_PID1] << MAS1_TID_SHIFT;
>> +        break;
>> +    case MAS4_TIDSELD_PID2:
>> +        env->spr[SPR_BOOKE_MAS1] |= env->spr[SPR_BOOKE_PID2] << MAS1_TID_SHIFT;
>> +        break;
>> +    }
>> +
>> +    env->spr[SPR_BOOKE_MAS6] |= env->spr[SPR_BOOKE_PID] << 16;
>> +
>> +    /* next victim logic */
>> +    env->spr[SPR_BOOKE_MAS0] |= env->last_way << MAS0_ESEL_SHIFT;
>> +    env->last_way++;
>> +    env->last_way &= 3;
>> +    env->spr[SPR_BOOKE_MAS0] |= env->last_way << MAS0_NV_SHIFT;
>> +}
> 
> MAS3/7 should be zeroed according to the architecture.

Ah, missed that one :)

> Better victim selection would check for empty ways, and perhaps keep
> last_way on a per-set basis.

Does the hardware do this?

> 
>> @@ -1820,12 +1956,8 @@ void ppc_tlb_invalidate_all (CPUPPCState *env)
>>         cpu_abort(env, "MPC8xx MMU model is not implemented\n");
>>         break;
>>     case POWERPC_MMU_BOOKE:
>> -        tlb_flush(env, 1);
>> -        break;
>>     case POWERPC_MMU_BOOKE_FSL:
>> -        /* XXX: TODO */
>> -        if (!kvm_enabled())
>> -            cpu_abort(env, "BookE MMU model is not implemented\n");
>> +        tlb_flush(env, 1);
>>         break;
>>     case POWERPC_MMU_32B:
>>     case POWERPC_MMU_601:
> 
> This flushes env->tlb_table, but don't we still need to clear out env->tlb?

I guess so, yes. That would break my PID -> tlb_flush patch though. Hrm. This way we don't reset the TLB on reset. I'll fix it up :).

> 
>> diff --git a/target-ppc/op_helper.c b/target-ppc/op_helper.c
>> index d5db484..3c0b061 100644
>> --- a/target-ppc/op_helper.c
>> +++ b/target-ppc/op_helper.c
>> @@ -4206,4 +4206,422 @@ target_ulong helper_440_tlbsx (target_ulong address)
>>     return ppcemb_tlb_search(env, address, env->spr[SPR_440_MMUCR] & 0xFF);
>> }
>> 
>> +/* PowerPC e500 TLB management */
>> +
>> +static inline int e500_tlb_num(CPUState *env, ppcemb_tlb_t *tlb)
>> +{
>> +    ulong tlbel = (ulong)tlb;
>> +    ulong tlbl = (ulong)env->tlb;
>> +
>> +    return (tlbel - tlbl) / sizeof(env->tlb[0]);
>> +}
>> +
>> +static inline ppcemb_tlb_t *e500_cur_tlb(CPUState *env)
> 
> This is a bit big to be inlined -  let the compiler decide such things.

*shrug* ok :).

> 
>> +{
>> +    uint32_t tlbncfg = 0;
>> +    int esel = (env->spr[SPR_BOOKE_MAS0] & MAS0_ESEL_MASK) >> MAS0_ESEL_SHIFT;
>> +    int ea = (env->spr[SPR_BOOKE_MAS2] & MAS2_EPN_MASK) >> MAS2_EPN_SHIFT;
>> +    int tlb;
>> +    int r;
>> +
>> +    tlb = (env->spr[SPR_BOOKE_MAS0] & MAS0_TLBSEL_MASK) >> MAS0_TLBSEL_SHIFT;
>> +    tlbncfg = env->spr[SPR_BOOKE_TLB0CFG + tlb];
>> +
>> +    if ((tlbncfg & TLBnCFG_HES) && (env->spr[SPR_BOOKE_MAS0] & MAS0_HES)) {
>> +        cpu_abort(env, "we don't support HES yet\n");
>> +    }
>> +
>> +    if (tlb == 1) {
>> +        r = env->nb_tlbs[0] + (esel % env->nb_tlbs[1]);
> 
> Ouch, division by non-constant.
> 
> There's no need for it anyway; esel >= env_nb_tlbs[1] is undefined
> behavior.  Just crop the value arbitrarily (or error out, if possible) to
> avoid dereferencing a bad array index.

I just rewrote all of this anyways, getting rid of the division along the way.

> 
>> +    } else {
>> +        esel &= env->nb_ways - 1;
>> +        esel <<= 7;
>> +        ea &= 0x7f;
>> +        r = (esel | ea) % env->nb_tlbs[0];
> 
> More unnecessary division -- use "& (env->nb_tlbs[0] - 1)", or variable-ize
> the 7 and 0x7f so that we know that we won't produce an out-of-bounds value.
> 
>> +static const target_phys_addr_t e500_tlb_sizes[] = {
>> +    0,
>> +    4 * 1024,
>> +    16 * 1024,
>> +    64 * 1024,
>> +    256 * 1024,
>> +    1024 * 1024,
>> +    4 * 1024 * 1024,
>> +    16 * 1024 * 1024,
>> +    64 * 1024 * 1024,
>> +    256 * 1024 * 1024,
>> +    1024 * 1024 * 1024,
>> +    (target_phys_addr_t)(4ULL * 1024ULL * 1024ULL * 1024ULL),
>> +};
> 
> FWIW, power-of-2 page sizes are architected, and may appear in future
> e500-family chips.  The TSIZE field is extended by one bit on the right
> (previously reserved and should-be-zero).

Yeah, I've seen that mentioned as MAV 2.0 or so change. This is the exact list of supported page sizes for an e500v2 though. Should we just support all of the possible one and ignore the chip's deficiencies?

> 
>> +static inline target_phys_addr_t e500_tlb_to_page_size(int size)
> 
> unsigned int

Why?

> 
>> +{
>> +    target_phys_addr_t r;
>> +
>> +    if (size > 11) {
> 
> if (size >= ARRAY_SIZE(e500_tlb_sizes)) {
> 
>> +        /* should not happen */
>> +        r = 1024 * 1024 * 1024;
> 
> Error message?
> 
> +    switch (env->spr[SPR_BOOKE_MAS0] & MAS0_WQ_MASK) {
> +    case MAS0_WQ_ALWAYS:
> +        /* good to go, write that entry */
> +        break;
> +    case MAS0_WQ_COND:
> +        /* XXX check if reserved */
> +        if (0) {
> +            return;
> +        }
> +        break;
> +    case MAS0_WQ_CLR_RSRV:
> +        /* XXX clear entry */
> +        return;
> +    default:
> +        /* no idea what to do */
> +        return;
> +    }
> 
> If the plan is to support such things, might want a more generic name than
> "e500" -- we're really talking about isa 2.06 book3e.  The first chip that
> implements this stuff will probably not be from Freescale, much less
> called "e500". :-)

Good point :). I'll rename it booke206.

> 
>> +    if (msr_gs) {
>> +        cpu_abort(env, "missing HV implementation\n");
> 
> What's the policy on aborting versus error-message versus no-op if the
> guest invokes undefined/unimplemented behavior?

The less likely a failure is, the more I find aborting/error-message useful. For KVM, we want to keep the abort cases very very very low. For TCG, I prefer to see when something goes wrong.

So general rule of thumb:

  Guest user space should never be able to kill the VM
  Guest kernel can kill the VM anyways, so it can also do so by issuing unimplemented things
  If the VM would work just fine without the unimplemented thing, don't abort

> 
>> +    } else {
>> +        rpn = ((uint64_t)env->spr[SPR_BOOKE_MAS7] << 32) |
>> +              (env->spr[SPR_BOOKE_MAS3] & 0xfffff000);
>> +    }
> 
> Not sure why this is in an else-branch versus msr_gs.

Because that's what the spec says:

if category E.HV.LRAT supported & (MSRGS=1) & (MAS1V=1) then
  rpn <- translate_logical_to_real(MAS7RPNU || MAS3RPNL, MAS8TLPID)
else if MAS7 implemented then
  rpn <- MAS7RPNU || MAS3RPNL
else rpn <- 320 || MAS3RPNL

> 
>> +    tlb->RPN = rpn;
>> +
>> +    tlb->PID = (env->spr[SPR_BOOKE_MAS1] & MAS1_TID_MASK) >> MAS1_TID_SHIFT;
>> +    tlb->size = e500_tlb_to_page_size((env->spr[SPR_BOOKE_MAS1]
>> +                      & MAS1_TSIZE_MASK) >> MAS1_TSIZE_SHIFT);
> 
> e500 manuals document that tsize is ignored in tlb0.

Yup, thanks :).

> 
>> +    tlb->EPN = (uint32_t)(env->spr[SPR_BOOKE_MAS2] & MAS2_EPN_MASK);
>> +    tlb->attr = env->spr[SPR_BOOKE_MAS2] & (MAS2_ACM | MAS2_VLE | MAS2_W |
>> +                                            MAS2_I | MAS2_M | MAS2_G | MAS2_E)
>> +                << 1;
>> +    tlb->attr |= env->spr[SPR_BOOKE_MAS1] & MAS1_IPROT;
>> +    tlb->attr |= (env->spr[SPR_BOOKE_MAS3] &
>> +                  ((MAS3_U0 | MAS3_U1 | MAS3_U2 | MAS3_U3)) << 8);
> 
> Might be nice to #define the encoding of these bits into attr/etc, versus
> magic shifts (though it's moot if we're going to switch to a MAS-based
> representation).

Yeah, this will be moot once we switch. No need to worry about it now.

> 
>> +    if (tlb->size == TARGET_PAGE_SIZE) {
>> +        tlb_flush_page(env, tlb->EPN);
>> +    } else {
>> +        tlb_flush(env, 1);
>> +    }
> 
> Need to check whether the previous entry was a large page needing a full
> flush.

Right, not the current one.

> 
>> +void helper_e500_tlbre(void)
>> +{
>> +    ppcemb_tlb_t *tlb = NULL;
>> +
>> +    tlb = e500_cur_tlb(env);
>> +    e500_tlb_to_mas(env, tlb, e500_tlb_num(env, tlb));
>> +}
>> +
>> +/* Generic TLB check function for embedded PowerPC implementations */
>> +static inline int ppcemb_tlb_check(CPUState *env, ppcemb_tlb_t *tlb,
>> +                                   target_phys_addr_t *raddrp,
>> +                                   target_ulong address, uint32_t pid, int ext,
>> +                                   int i)
> 
> Why is this both here and in helper.c?

Removed this version and exported the helper.c one.

> 
>> +void helper_e500_tlbsx(target_ulong address_hi, target_ulong address_lo)
>> +{
>> +    ppcemb_tlb_t *tlb = NULL;
>> +    int i;
>> +    target_phys_addr_t raddr;
>> +    uint32_t spid, sas;
>> +    uint32_t ea = (address_lo >> MAS2_EPN_SHIFT) & 0x7f;
>> +
>> +    spid = (env->spr[SPR_BOOKE_MAS6] & MAS6_SPID_MASK) >> MAS6_SPID_SHIFT;
>> +    sas = env->spr[SPR_BOOKE_MAS6] & MAS6_SAS;
>> +
>> +    /* check possible TLB0 entries */
>> +    for (i = 0; i < env->nb_ways; i++) {
>> +        tlb = &env->tlb[ea | (i << 7)].tlbe;
>> +
>> +        if (ppcemb_tlb_check(env, tlb, &raddr, address_lo, spid, 0, i) < 0) {
>> +            continue;
>> +        }
>> +
>> +        if (sas != (tlb->attr & MAS6_SAS)) {
>> +            continue;
>> +        }
>> +
>> +        e500_tlb_to_mas(env, tlb, ea | (i << 7));
>> +        return;
>> +    }
>> +
>> +    /* check TLB1 */
>> +    for (i = env->nb_tlbs[0]; i < (env->nb_tlbs[0] + env->nb_tlbs[1]); i++) {
>> +        tlb = &env->tlb[i].tlbe;
>> +
>> +        if (ppcemb_tlb_check(env, tlb, &raddr, address_lo, spid, 0, i) < 0) {
>> +            continue;
>> +        }
>> +
>> +        if (sas != (tlb->attr & MAS6_SAS)) {
>> +            continue;
>> +        }
>> +
>> +        e500_tlb_to_mas(env, tlb, i);
>> +        return;
>> +    }
> 
> This has a lot of overlap with mmue500_get_physical_address()...

It doesn't look as bad now :).

> 
>> +
>> +    /* no entry found, fill with defaults */
>> +    env->spr[SPR_BOOKE_MAS0] = env->spr[SPR_BOOKE_MAS4] & MAS4_TLBSELD_MASK;
>> +    env->spr[SPR_BOOKE_MAS1] = env->spr[SPR_BOOKE_MAS4] & MAS4_TSIZED_MASK;
>> +    env->spr[SPR_BOOKE_MAS2] = env->spr[SPR_BOOKE_MAS4] & MAS4_WIMGED_MASK;
>> +
>> +    if (env->spr[SPR_BOOKE_MAS6] & MAS6_SAS) {
>> +        env->spr[SPR_BOOKE_MAS1] |= MAS1_TS;
>> +    }
>> +
>> +    env->spr[SPR_BOOKE_MAS1] |= (env->spr[SPR_BOOKE_MAS6] >> 16)
>> +                                << MAS1_TID_SHIFT;
>> +
>> +    /* next victim logic */
>> +    env->spr[SPR_BOOKE_MAS0] |= env->last_way << MAS0_ESEL_SHIFT;
>> +    env->last_way++;
>> +    env->last_way &= 3;
>> +    env->spr[SPR_BOOKE_MAS0] |= env->last_way << MAS0_NV_SHIFT;
> 
> ...and this with e500_update_mas_tlb_miss().

Yes, I need to think of a good way to generalize NV still. It isn't defined that there's only a single NV available in the architecture either...

> 
>> @@ -8433,7 +8505,7 @@ GEN_HANDLER2(icbt_40x, "icbt", 0x1F, 0x06, 0x08, 0x03E00001, PPC_40x_ICBT),
>> GEN_HANDLER(iccci, 0x1F, 0x06, 0x1E, 0x00000001, PPC_4xx_COMMON),
>> GEN_HANDLER(icread, 0x1F, 0x06, 0x1F, 0x03E00001, PPC_4xx_COMMON),
>> GEN_HANDLER2(rfci_40x, "rfci", 0x13, 0x13, 0x01, 0x03FF8001, PPC_40x_EXCP),
>> -GEN_HANDLER(rfci, 0x13, 0x13, 0x01, 0x03FF8001, PPC_BOOKE),
>> +GEN_HANDLER_E(rfci, 0x13, 0x13, 0x01, 0x03FF8001, PPC_BOOKE, PPC2_BOOKE_FSL),
> 
> What is PPC2_BOOKE_FSL supposed to indicate?
> 
> rfci is basic booke.  It's in the 440.

It's also in e500, right? The flags there are a mask. Basically it means "this opcode is available on PPC_BOOKE and PPC2_BOOKE_FSL capable CPUs".

> 
>> +GEN_HANDLER2_E(icbt_440, "icbt", 0x1F, 0x16, 0x00, 0x03E00001,
>> +               PPC_BOOKE, PPC2_BOOKE_FSL),
> 
> "icbt_440" is FSL-specific? :-)

No, it's available on both :).

> 
>> +static void spr_write_booke_pid (void *opaque, int sprn, int gprn)
>> +{
>> +    gen_store_spr(sprn, cpu_gpr[gprn]);
>> +    /* switching context, so need to flush tlb */
>> +    gen_helper_tlbia();
>> +}
> 
> Well, we want to flush the non-guest-visible TLB that doesn't understand
> PIDs -- but I'd expect "tlbia" to flush the architected TLB.  8xx, at
> least, has both tlbia and an architected TLB.
> 
> Plus, we need ppc_tlb_invalidate_all() to clear the architected TLB, unless
> we call something different on reset.

Yep, changed all that into its own op_helper call that simply does tlb_flush(). If this should ever be more than a toy we should probably investigate on how to add tags to qemu's tlb, so we don't constantly flush it.

> 
>> @@ -1578,45 +1614,38 @@ static void gen_spr_BookE_FSL (CPUPPCState *env, uint32_t mas_mask)
>>                  SPR_NOACCESS, SPR_NOACCESS,
>>                  &spr_read_generic, SPR_NOACCESS,
>>                  0x00000000); /* TOFIX */
>> -    /* XXX : not implemented */
>> -    spr_register(env, SPR_MMUCSR0, "MMUCSR0",
>> -                 SPR_NOACCESS, SPR_NOACCESS,
>> -                 &spr_read_generic, &spr_write_generic,
>> -                 0x00000000); /* TOFIX */
>>     switch (env->nb_ways) {
>>     case 4:
>> -        /* XXX : not implemented */
>>         spr_register(env, SPR_BOOKE_TLB3CFG, "TLB3CFG",
>>                      SPR_NOACCESS, SPR_NOACCESS,
>>                      &spr_read_generic, SPR_NOACCESS,
>> -                     0x00000000); /* TOFIX */
>> +                     tlbncfg[3]);
>>         /* Fallthru */
>>     case 3:
>> -        /* XXX : not implemented */
>>         spr_register(env, SPR_BOOKE_TLB2CFG, "TLB2CFG",
>>                      SPR_NOACCESS, SPR_NOACCESS,
>>                      &spr_read_generic, SPR_NOACCESS,
>> -                     0x00000000); /* TOFIX */
>> +                     tlbncfg[2]);
>>         /* Fallthru */
> 
> In some places you use nb_ways as the associativity of TLB0.  But here it
> seems to be the number of TLB arrays?

It's always the number of TLB arrays. It's gone in v4 though :).

> 
>> @@ -4334,8 +4373,23 @@ static void init_proc_e500 (CPUPPCState *env)
>>     /* Memory management */
>> #if !defined(CONFIG_USER_ONLY)
>>     env->nb_pids = 3;
>> +    env->nb_ways = 2;
>> +    env->id_tlbs = 0;
>> +    if ((env->spr[SPR_PVR] & 0x00010000)) {
>> +        /* e500v2 */
>> +        env->nb_tlbs[0] = 512;
>> +        tlbncfg[0] = gen_tlbncfg(4, 1, 1, 0, env->nb_tlbs[0]);
>> +        tlbncfg[1] = gen_tlbncfg(16, 1, 12, TLBnCFG_AVAIL | TLBnCFG_IPROT, 16);
>> +    } else {
>> +        /* e500v1 */
>> +        env->nb_tlbs[0] = 256;
>> +        tlbncfg[0] = gen_tlbncfg(2, 1, 1, 0, env->nb_tlbs[0]);
>> +        tlbncfg[1] = gen_tlbncfg(16, 1, 9, TLBnCFG_AVAIL | TLBnCFG_IPROT, 16);
>> +    }
> 
> It would be nice to be more precise with PVR testing, and complain if an
> unrecognized PVR is used (e.g. e500mc).

Alright, done.


Alex

^ permalink raw reply	[flat|nested] 15+ messages in thread

* Re: [Qemu-devel] [PATCH 5/6] PPC: Implement e500 (FSL) MMU
  2011-05-06 10:01     ` Alexander Graf
@ 2011-05-06 17:40       ` Scott Wood
  2011-05-06 18:33         ` Alexander Graf
  0 siblings, 1 reply; 15+ messages in thread
From: Scott Wood @ 2011-05-06 17:40 UTC (permalink / raw)
  To: Alexander Graf
  Cc: Blue Swirl, Edgar E. Iglesias, Liu Yu, QEMU-devel Developers

On Fri, 6 May 2011 12:01:11 +0200
Alexander Graf <agraf@suse.de> wrote:

> >> +    for (i = env->nb_tlbs[0]; i < env->nb_tlb; i++) {
> >> +        tlb = &env->tlb[i].tlbe;
> >> +        ret = mmubooke_check_tlb(env, tlb, &raddr, &ctx->prot, address, rw,
> >> +                                 access_type, i);
> >> +        if (!ret) {
> >> +            goto found_tlb;
> >>         }
> >>     }
> >> -    if (ret >= 0)
> >> +
> >> +    /* check possible TLB0 entries */
> >> +    for (i = 0; i < env->nb_ways; i++) {
> >> +        tlb = &env->tlb[ea | (i << 7)].tlbe;
> > 
> > Do we have to hardcode 7 (and 0x7f) here?
> 
> I'm not sure - the spec isn't exactly obvious on this part. How do I find out the mask from TLBnCFG?

I don't think the ISA specifies the hash at all.  The implementation manual
should specify it.  I think 7 bits is correct on all e500-family chips so
far, but it's really a function of the TLB geometry.  It may be desireable
in some situations for qemu to create a larger TLB than hardware actually
has, to reduce the TLB misses that the guest has to handle.

> > Better victim selection would check for empty ways, and perhaps keep
> > last_way on a per-set basis.
> 
> Does the hardware do this?

Hmm, I thought it did, but checking the docs it seems to be similar to
what you implemented.  I guess I was thinking of the I/D-cache victim
selection.

> >> +static const target_phys_addr_t e500_tlb_sizes[] = {
> >> +    0,
> >> +    4 * 1024,
> >> +    16 * 1024,
> >> +    64 * 1024,
> >> +    256 * 1024,
> >> +    1024 * 1024,
> >> +    4 * 1024 * 1024,
> >> +    16 * 1024 * 1024,
> >> +    64 * 1024 * 1024,
> >> +    256 * 1024 * 1024,
> >> +    1024 * 1024 * 1024,
> >> +    (target_phys_addr_t)(4ULL * 1024ULL * 1024ULL * 1024ULL),
> >> +};
> > 
> > FWIW, power-of-2 page sizes are architected, and may appear in future
> > e500-family chips.  The TSIZE field is extended by one bit on the right
> > (previously reserved and should-be-zero).
> 
> Yeah, I've seen that mentioned as MAV 2.0 or so change. This is the exact list of supported page sizes for an e500v2 though. Should we just support all of the possible one and ignore the chip's deficiencies?

I'd say just support all of them -- it's undefined behavior if a MAV 1.0
guest sets that low bit, so this is as valid an implementation as any. :-)

> >> +static inline target_phys_addr_t e500_tlb_to_page_size(int size)
> > 
> > unsigned int
> 
> Why?

So you don't have to check size < 0.

> >> +    } else {
> >> +        rpn = ((uint64_t)env->spr[SPR_BOOKE_MAS7] << 32) |
> >> +              (env->spr[SPR_BOOKE_MAS3] & 0xfffff000);
> >> +    }
> > 
> > Not sure why this is in an else-branch versus msr_gs.
> 
> Because that's what the spec says:
> 
> if category E.HV.LRAT supported & (MSRGS=1) & (MAS1V=1) then
>   rpn <- translate_logical_to_real(MAS7RPNU || MAS3RPNL, MAS8TLPID)
> else if MAS7 implemented then
>   rpn <- MAS7RPNU || MAS3RPNL
> else rpn <- 320 || MAS3RPNL

Sorry, I was thinking of MAS8[TGS], not MSR[GS].

> Yes, I need to think of a good way to generalize NV still. It isn't defined that there's only a single NV available in the architecture either...

Architecturally, the NV algorithm is implementation-defined.

> >> @@ -8433,7 +8505,7 @@ GEN_HANDLER2(icbt_40x, "icbt", 0x1F, 0x06, 0x08, 0x03E00001, PPC_40x_ICBT),
> >> GEN_HANDLER(iccci, 0x1F, 0x06, 0x1E, 0x00000001, PPC_4xx_COMMON),
> >> GEN_HANDLER(icread, 0x1F, 0x06, 0x1F, 0x03E00001, PPC_4xx_COMMON),
> >> GEN_HANDLER2(rfci_40x, "rfci", 0x13, 0x13, 0x01, 0x03FF8001, PPC_40x_EXCP),
> >> -GEN_HANDLER(rfci, 0x13, 0x13, 0x01, 0x03FF8001, PPC_BOOKE),
> >> +GEN_HANDLER_E(rfci, 0x13, 0x13, 0x01, 0x03FF8001, PPC_BOOKE, PPC2_BOOKE_FSL),
> > 
> > What is PPC2_BOOKE_FSL supposed to indicate?
> > 
> > rfci is basic booke.  It's in the 440.
> 
> It's also in e500, right?

Yes.

> The flags there are a mask. Basically it means "this opcode is available
> on PPC_BOOKE and PPC2_BOOKE_FSL capable CPUs".

OK, it looked like it was being limited to only FSL.  I missed that
PPC_BOOKE and PPC2_BOOKE_FSL are the same "kind" of flags despite being in
different words.  Does PPC_BOOKE not refer to things that are common to all
booke?  Why do the individual implementations of booke need to be listed?

-Scott

^ permalink raw reply	[flat|nested] 15+ messages in thread

* Re: [Qemu-devel] [PATCH 5/6] PPC: Implement e500 (FSL) MMU
  2011-05-06 17:40       ` Scott Wood
@ 2011-05-06 18:33         ` Alexander Graf
  2011-05-06 18:40           ` Scott Wood
  0 siblings, 1 reply; 15+ messages in thread
From: Alexander Graf @ 2011-05-06 18:33 UTC (permalink / raw)
  To: Scott Wood; +Cc: Blue Swirl, Edgar E. Iglesias, Liu Yu, QEMU-devel Developers


On 06.05.2011, at 19:40, Scott Wood wrote:

> On Fri, 6 May 2011 12:01:11 +0200
> Alexander Graf <agraf@suse.de> wrote:
> 
>>>> +    for (i = env->nb_tlbs[0]; i < env->nb_tlb; i++) {
>>>> +        tlb = &env->tlb[i].tlbe;
>>>> +        ret = mmubooke_check_tlb(env, tlb, &raddr, &ctx->prot, address, rw,
>>>> +                                 access_type, i);
>>>> +        if (!ret) {
>>>> +            goto found_tlb;
>>>>        }
>>>>    }
>>>> -    if (ret >= 0)
>>>> +
>>>> +    /* check possible TLB0 entries */
>>>> +    for (i = 0; i < env->nb_ways; i++) {
>>>> +        tlb = &env->tlb[ea | (i << 7)].tlbe;
>>> 
>>> Do we have to hardcode 7 (and 0x7f) here?
>> 
>> I'm not sure - the spec isn't exactly obvious on this part. How do I find out the mask from TLBnCFG?
> 
> I don't think the ISA specifies the hash at all.  The implementation manual
> should specify it.  I think 7 bits is correct on all e500-family chips so
> far, but it's really a function of the TLB geometry.  It may be desireable
> in some situations for qemu to create a larger TLB than hardware actually
> has, to reduce the TLB misses that the guest has to handle.

Yup, changed that one :).

> 
>>> Better victim selection would check for empty ways, and perhaps keep
>>> last_way on a per-set basis.
>> 
>> Does the hardware do this?
> 
> Hmm, I thought it did, but checking the docs it seems to be similar to
> what you implemented.  I guess I was thinking of the I/D-cache victim
> selection.
> 
>>>> +static const target_phys_addr_t e500_tlb_sizes[] = {
>>>> +    0,
>>>> +    4 * 1024,
>>>> +    16 * 1024,
>>>> +    64 * 1024,
>>>> +    256 * 1024,
>>>> +    1024 * 1024,
>>>> +    4 * 1024 * 1024,
>>>> +    16 * 1024 * 1024,
>>>> +    64 * 1024 * 1024,
>>>> +    256 * 1024 * 1024,
>>>> +    1024 * 1024 * 1024,
>>>> +    (target_phys_addr_t)(4ULL * 1024ULL * 1024ULL * 1024ULL),
>>>> +};
>>> 
>>> FWIW, power-of-2 page sizes are architected, and may appear in future
>>> e500-family chips.  The TSIZE field is extended by one bit on the right
>>> (previously reserved and should-be-zero).
>> 
>> Yeah, I've seen that mentioned as MAV 2.0 or so change. This is the exact list of supported page sizes for an e500v2 though. Should we just support all of the possible one and ignore the chip's deficiencies?
> 
> I'd say just support all of them -- it's undefined behavior if a MAV 1.0
> guest sets that low bit, so this is as valid an implementation as any. :-)

I have a nice algorithm for MAV 1.0 now - when 2.0 comes along we can check again and see what fits.

> 
>>>> +static inline target_phys_addr_t e500_tlb_to_page_size(int size)
>>> 
>>> unsigned int
>> 
>> Why?
> 
> So you don't have to check size < 0.

Ah, I see. That one's moot by now since we don't look up things in an array anymore.

> 
>>>> +    } else {
>>>> +        rpn = ((uint64_t)env->spr[SPR_BOOKE_MAS7] << 32) |
>>>> +              (env->spr[SPR_BOOKE_MAS3] & 0xfffff000);
>>>> +    }
>>> 
>>> Not sure why this is in an else-branch versus msr_gs.
>> 
>> Because that's what the spec says:
>> 
>> if category E.HV.LRAT supported & (MSRGS=1) & (MAS1V=1) then
>>  rpn <- translate_logical_to_real(MAS7RPNU || MAS3RPNL, MAS8TLPID)
>> else if MAS7 implemented then
>>  rpn <- MAS7RPNU || MAS3RPNL
>> else rpn <- 320 || MAS3RPNL
> 
> Sorry, I was thinking of MAS8[TGS], not MSR[GS].
> 
>> Yes, I need to think of a good way to generalize NV still. It isn't defined that there's only a single NV available in the architecture either...
> 
> Architecturally, the NV algorithm is implementation-defined.

Meh :).

> 
>>>> @@ -8433,7 +8505,7 @@ GEN_HANDLER2(icbt_40x, "icbt", 0x1F, 0x06, 0x08, 0x03E00001, PPC_40x_ICBT),
>>>> GEN_HANDLER(iccci, 0x1F, 0x06, 0x1E, 0x00000001, PPC_4xx_COMMON),
>>>> GEN_HANDLER(icread, 0x1F, 0x06, 0x1F, 0x03E00001, PPC_4xx_COMMON),
>>>> GEN_HANDLER2(rfci_40x, "rfci", 0x13, 0x13, 0x01, 0x03FF8001, PPC_40x_EXCP),
>>>> -GEN_HANDLER(rfci, 0x13, 0x13, 0x01, 0x03FF8001, PPC_BOOKE),
>>>> +GEN_HANDLER_E(rfci, 0x13, 0x13, 0x01, 0x03FF8001, PPC_BOOKE, PPC2_BOOKE_FSL),
>>> 
>>> What is PPC2_BOOKE_FSL supposed to indicate?
>>> 
>>> rfci is basic booke.  It's in the 440.
>> 
>> It's also in e500, right?
> 
> Yes.
> 
>> The flags there are a mask. Basically it means "this opcode is available
>> on PPC_BOOKE and PPC2_BOOKE_FSL capable CPUs".
> 
> OK, it looked like it was being limited to only FSL.  I missed that
> PPC_BOOKE and PPC2_BOOKE_FSL are the same "kind" of flags despite being in
> different words.  Does PPC_BOOKE not refer to things that are common to all
> booke?  Why do the individual implementations of booke need to be listed?

Well, the PPC_BOOKE flag was also used for the 440 tlb modification opcodes, which are different for 2.06. So I just introduced a new one :). We could of course also introduce yet another flag for 440s and define specific instructions individually, but I don't really see it buying us too much for now.


Alex

^ permalink raw reply	[flat|nested] 15+ messages in thread

* Re: [Qemu-devel] [PATCH 5/6] PPC: Implement e500 (FSL) MMU
  2011-05-06 18:33         ` Alexander Graf
@ 2011-05-06 18:40           ` Scott Wood
  0 siblings, 0 replies; 15+ messages in thread
From: Scott Wood @ 2011-05-06 18:40 UTC (permalink / raw)
  To: Alexander Graf
  Cc: Blue Swirl, Edgar E. Iglesias, Liu Yu, QEMU-devel Developers

On Fri, 6 May 2011 20:33:24 +0200
Alexander Graf <agraf@suse.de> wrote:

> On 06.05.2011, at 19:40, Scott Wood wrote:
> 
> > OK, it looked like it was being limited to only FSL.  I missed that
> > PPC_BOOKE and PPC2_BOOKE_FSL are the same "kind" of flags despite being in
> > different words.  Does PPC_BOOKE not refer to things that are common to all
> > booke?  Why do the individual implementations of booke need to be listed?
> 
> Well, the PPC_BOOKE flag was also used for the 440 tlb modification opcodes, which are different for 2.06. So I just introduced a new one :). We could of course also introduce yet another flag for 440s and define specific instructions individually, but I don't really see it buying us too much for now.

It would help reduce confusion if PPC_BOOKE really meant booke, and not
440. :-)

-Scott

^ permalink raw reply	[flat|nested] 15+ messages in thread

end of thread, other threads:[~2011-05-06 18:42 UTC | newest]

Thread overview: 15+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2011-05-02 15:03 [Qemu-devel] [PATCH 0/6] PPC: Add FSL (e500) MMU emulation v3 Alexander Graf
2011-05-02 15:03 ` [Qemu-devel] [PATCH 1/6] PPC: Make MPC8544DS obey -cpu switch Alexander Graf
2011-05-02 15:03 ` [Qemu-devel] [PATCH 2/6] PPC: Make MPC8544DS emulation work w/o KVM Alexander Graf
2011-05-02 15:03 ` [Qemu-devel] [PATCH 3/6] PPC: Add GS MSR definition Alexander Graf
2011-05-02 15:03 ` [Qemu-devel] [PATCH 4/6] PPC: Add another 64 bits to instruction feature mask Alexander Graf
2011-05-02 15:03 ` [Qemu-devel] [PATCH 5/6] PPC: Implement e500 (FSL) MMU Alexander Graf
2011-05-03 19:25   ` Scott Wood
2011-05-06 10:01     ` Alexander Graf
2011-05-06 17:40       ` Scott Wood
2011-05-06 18:33         ` Alexander Graf
2011-05-06 18:40           ` Scott Wood
2011-05-02 15:03 ` [Qemu-devel] [PATCH 6/6] PPC: Qdev'ify e500 pci Alexander Graf
2011-05-04 19:08   ` Blue Swirl
2011-05-05 10:43     ` Alexander Graf
2011-05-04 19:09 ` [Qemu-devel] [PATCH 0/6] PPC: Add FSL (e500) MMU emulation v3 Blue Swirl

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.