[2/7] PPC: Make MPC8544DS emulation work w/o KVM

Submitted by Alexander Graf on May 6, 2011, noon

Details

Message ID 1304683237-26177-3-git-send-email-agraf@suse.de
State New
Headers show

Commit Message

Alexander Graf May 6, 2011, noon
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(-)

Patch hide | download patch | download mbox

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;
 }