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

Submitted by Alexander Graf on May 7, 2011, 11 p.m.

Details

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

Commit Message

Alexander Graf May 7, 2011, 11 p.m.
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(-)

Comments

Blue Swirl May 8, 2011, 10:08 a.m.
On Sun, May 8, 2011 at 2:00 AM, Alexander Graf <agraf@suse.de> wrote:
> 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;

I don't think there is a need to use static state here.

> +
>  #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
>
>
>
Alexander Graf May 8, 2011, 1:42 p.m.
Am 08.05.2011 um 12:08 schrieb Blue Swirl <blauwirbel@gmail.com>:

> On Sun, May 8, 2011 at 2:00 AM, Alexander Graf <agraf@suse.de> wrote:
>> 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;
> 
> I don't think there is a need to use static state here.

I just modeled it the same as Edgar's code :)

> 

Alex

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