[Spice-commits] 25 commits - configure hw/i386 hw/net hw/ppc hw/s390x hw/timer pc-bios/README pc-bios/s390-ccw pc-bios/s390-ccw.img pc-bios/slof.bin roms/SLOF target-ppc/cpu.h target-ppc/mmu_helper.c target-ppc/translate.c target-ppc/translate_init.c

Gerd Hoffmann kraxel at kemper.freedesktop.org
Mon May 6 23:45:44 PDT 2013


 configure                   |    9 +
 hw/i386/kvmvapic.c          |    6 +
 hw/net/spapr_llan.c         |    2 
 hw/ppc/e500.c               |   31 ++++-
 hw/ppc/prep.c               |   36 ++++--
 hw/ppc/spapr_iommu.c        |   14 +-
 hw/s390x/ipl.c              |   38 ++++--
 hw/timer/imx_timer.c        |  262 +++++++++++++++++++++++++++++++++-----------
 pc-bios/README              |    4 
 pc-bios/s390-ccw.img        |binary
 pc-bios/s390-ccw/main.c     |   24 +++-
 pc-bios/s390-ccw/start.S    |    2 
 pc-bios/slof.bin            |binary
 roms/SLOF                   |    2 
 target-ppc/cpu.h            |    3 
 target-ppc/mmu_helper.c     |    4 
 target-ppc/translate.c      |   32 ++---
 target-ppc/translate_init.c |    4 
 18 files changed, 353 insertions(+), 120 deletions(-)

New commits:
commit b5803aa3583e82e5133f7621121bc15ee694f4a1
Merge: fe677fd 0c1cd0a
Author: Anthony Liguori <aliguori at us.ibm.com>
Date:   Mon May 6 15:45:08 2013 -0500

    Merge remote-tracking branch 'qemu-kvm/uq/master' into staging
    
    # By Marcelo Tosatti
    # Via Gleb Natapov
    * qemu-kvm/uq/master:
      kvmvapic: add ioport read accessor
    
    Message-id: cover.1367844188.git.gleb at redhat.com
    Signed-off-by: Anthony Liguori <aliguori at us.ibm.com>

commit fe677fd1b3fde96110898fde5101bea4cfe6e063
Merge: e0ff466 2ddef42
Author: Aurelien Jarno <aurelien at aurel32.net>
Date:   Mon May 6 19:56:27 2013 +0200

    Merge branch 's390-for-upstream' of git://github.com/agraf/qemu
    
    * 's390-for-upstream' of git://github.com/agraf/qemu:
      s390: update s390-ccw.img
      S390: BIOS boot from given device
      S390: Add virtio-blk boot
      S390: Merging s390_ipl_cpu and s390_ipl_reset
      S390: BIOS create link to src folder for .img file
      S390: BIOS check for file

commit 2ddef429d14136a0156a75b1d77b72cb3bdad18f
Author: Alexander Graf <agraf at suse.de>
Date:   Wed May 1 04:50:05 2013 +0200

    s390: update s390-ccw.img
    
    Now that we have boot device selection support, update the firmware
    blob accordingly.
    
    Signed-off-by: Alexander Graf <agraf at suse.de>

diff --git a/pc-bios/s390-ccw.img b/pc-bios/s390-ccw.img
index 149cf70..1b2a11e 100644
Binary files a/pc-bios/s390-ccw.img and b/pc-bios/s390-ccw.img differ
commit ff151f4ec977c38266b79ebfbb6e8689f2121d4f
Author: Dominik Dingel <dingel at linux.vnet.ibm.com>
Date:   Tue Apr 30 07:15:58 2013 +0000

    S390: BIOS boot from given device
    
    Use the passed device, if there is no device, use the first applicable device.
    
    Signed-off-by: Dominik Dingel <dingel at linux.vnet.ibm.com>
    Signed-off-by: Alexander Graf <agraf at suse.de>

diff --git a/pc-bios/s390-ccw/main.c b/pc-bios/s390-ccw/main.c
index fd40fa5..1665c57 100644
--- a/pc-bios/s390-ccw/main.c
+++ b/pc-bios/s390-ccw/main.c
@@ -12,6 +12,7 @@
 
 struct subchannel_id blk_schid;
 char stack[PAGE_SIZE * 8] __attribute__((__aligned__(PAGE_SIZE)));
+uint64_t boot_value;
 
 void virtio_panic(const char *string)
 {
@@ -20,15 +21,22 @@ void virtio_panic(const char *string)
     while (1) { }
 }
 
-static void virtio_setup(void)
+static void virtio_setup(uint64_t dev_info)
 {
     struct schib schib;
     int i;
     int r;
     bool found = false;
-
+    bool check_devno = false;
+    uint16_t dev_no = -1;
     blk_schid.one = 1;
 
+    if (dev_info != -1) {
+        check_devno = true;
+        dev_no = dev_info & 0xffff;
+        debug_print_int("device no. ", dev_no);
+    }
+
     for (i = 0; i < 0x10000; i++) {
         blk_schid.sch_no = i;
         r = stsch_err(blk_schid, &schib);
@@ -36,9 +44,11 @@ static void virtio_setup(void)
             break;
         }
         if (schib.pmcw.dnv) {
-            if (virtio_is_blk(blk_schid)) {
-                found = true;
-                break;
+            if (!check_devno || (schib.pmcw.dev == dev_no)) {
+                if (virtio_is_blk(blk_schid)) {
+                    found = true;
+                    break;
+                }
             }
         }
     }
@@ -53,7 +63,9 @@ static void virtio_setup(void)
 int main(void)
 {
     sclp_setup();
-    virtio_setup();
+    debug_print_int("boot reg[7] ", boot_value);
+    virtio_setup(boot_value);
+
     if (zipl_load() < 0)
         sclp_print("Failed to load OS from hard disk\n");
     disabled_wait();
diff --git a/pc-bios/s390-ccw/start.S b/pc-bios/s390-ccw/start.S
index 09deee7..5d5df0d 100644
--- a/pc-bios/s390-ccw/start.S
+++ b/pc-bios/s390-ccw/start.S
@@ -14,6 +14,8 @@
 _start:
 
 larl	%r15, stack + 0x8000    /* Set up stack */
+larl    %r6, boot_value
+stg     %r7, 0(%r6)     /* save the boot_value before any function calls */
 j	main                    /* And call C */
 
 /*
commit ba1509c0a99ad4c852c22cbd46d244ec7dc90402
Author: Dominik Dingel <dingel at linux.vnet.ibm.com>
Date:   Tue Apr 30 07:15:57 2013 +0000

    S390: Add virtio-blk boot
    
    If no kernel IPL entry is specified, boot the bios and pass if available
    device information for the first boot device (as given by the boot index).
    
    The provided information will be used in the next commit from the BIOS.
    
    Signed-off-by: Dominik Dingel <dingel at linux.vnet.ibm.com>
    Signed-off-by: Alexander Graf <agraf at suse.de>

diff --git a/hw/s390x/ipl.c b/hw/s390x/ipl.c
index d14c548..0aeb003 100644
--- a/hw/s390x/ipl.c
+++ b/hw/s390x/ipl.c
@@ -16,6 +16,8 @@
 #include "elf.h"
 #include "hw/loader.h"
 #include "hw/sysbus.h"
+#include "hw/s390x/virtio-ccw.h"
+#include "hw/s390x/css.h"
 
 #define KERN_IMAGE_START                0x010000UL
 #define KERN_PARM_AREA                  0x010480UL
@@ -150,6 +152,22 @@ static void s390_ipl_reset(DeviceState *dev)
 
     env->psw.addr = ipl->start_addr;
     env->psw.mask = IPL_PSW_MASK;
+
+    if (!ipl->kernel) {
+        /* booting firmware, tell what device to boot from */
+        DeviceState *dev_st = get_boot_device(0);
+        VirtioCcwDevice *ccw_dev = (VirtioCcwDevice *) object_dynamic_cast(
+                OBJECT(&(dev_st->parent_obj)), "virtio-blk-ccw");
+
+        if (ccw_dev) {
+            env->regs[7] = ccw_dev->sch->cssid << 24 |
+                           ccw_dev->sch->ssid << 16 |
+                           ccw_dev->sch->devno;
+        } else {
+            env->regs[7] = -1;
+        }
+    }
+
     s390_add_running_cpu(cpu);
 }
 
commit 2c4c71ee3a904bd07141c6499e5834818e6757f1
Author: Dominik Dingel <dingel at linux.vnet.ibm.com>
Date:   Tue Apr 30 07:15:56 2013 +0000

    S390: Merging s390_ipl_cpu and s390_ipl_reset
    
    There is no use in have this splitted in two functions.
    
    Signed-off-by: Dominik Dingel <dingel at linux.vnet.ibm.com>
    Signed-off-by: Alexander Graf <agraf at suse.de>

diff --git a/hw/s390x/ipl.c b/hw/s390x/ipl.c
index cc3cd23..d14c548 100644
--- a/hw/s390x/ipl.c
+++ b/hw/s390x/ipl.c
@@ -57,16 +57,6 @@ typedef struct S390IPLState {
 } S390IPLState;
 
 
-static void s390_ipl_cpu(uint64_t pswaddr)
-{
-    S390CPU *cpu = S390_CPU(qemu_get_cpu(0));
-    CPUS390XState *env = &cpu->env;
-
-    env->psw.addr = pswaddr;
-    env->psw.mask = IPL_PSW_MASK;
-    s390_add_running_cpu(cpu);
-}
-
 static int s390_ipl_init(SysBusDevice *dev)
 {
     S390IPLState *ipl = S390_IPL(dev);
@@ -155,8 +145,12 @@ static Property s390_ipl_properties[] = {
 static void s390_ipl_reset(DeviceState *dev)
 {
     S390IPLState *ipl = S390_IPL(dev);
+    S390CPU *cpu = S390_CPU(qemu_get_cpu(0));
+    CPUS390XState *env = &cpu->env;
 
-    s390_ipl_cpu(ipl->start_addr);
+    env->psw.addr = ipl->start_addr;
+    env->psw.mask = IPL_PSW_MASK;
+    s390_add_running_cpu(cpu);
 }
 
 static void s390_ipl_class_init(ObjectClass *klass, void *data)
commit e89e33e12e4185fa056a5d7ae6d2e8e7f5400a20
Author: Dominik Dingel <dingel at linux.vnet.ibm.com>
Date:   Mon Apr 29 04:52:06 2013 +0000

    S390: BIOS create link to src folder for .img file
    
    For *.img files, there will be a link created directly to the src folder,
    like for all other blobs.
    
    Signed-off-by: Dominik Dingel <dingel at linux.vnet.ibm.com>
    Signed-off-by: Alexander Graf <agraf at suse.de>

diff --git a/configure b/configure
index a9ff4ad..9439f1c 100755
--- a/configure
+++ b/configure
@@ -4518,6 +4518,7 @@ for bios_file in \
     $source_path/pc-bios/*.aml \
     $source_path/pc-bios/*.rom \
     $source_path/pc-bios/*.dtb \
+    $source_path/pc-bios/*.img \
     $source_path/pc-bios/openbios-* \
     $source_path/pc-bios/palcode-*
 do
commit 1f7de853306499b83e627a09b15281fd6d566a51
Author: Dominik Dingel <dingel at linux.vnet.ibm.com>
Date:   Mon Apr 29 04:52:05 2013 +0000

    S390: BIOS check for file
    
    Add a check if the BIOS blob exists before trying to load.
    
    Signed-off-by: Dominik Dingel <dingel at linux.vnet.ibm.com>
    Signed-off-by: Alexander Graf <agraf at suse.de>

diff --git a/hw/s390x/ipl.c b/hw/s390x/ipl.c
index ace5ff5..cc3cd23 100644
--- a/hw/s390x/ipl.c
+++ b/hw/s390x/ipl.c
@@ -82,6 +82,10 @@ static int s390_ipl_init(SysBusDevice *dev)
         }
 
         bios_filename = qemu_find_file(QEMU_FILE_TYPE_BIOS, bios_name);
+        if (bios_filename == NULL) {
+            hw_error("could not find stage1 bootloader\n");
+        }
+
         bios_size = load_elf(bios_filename, NULL, NULL, &ipl->start_addr, NULL,
                              NULL, 1, ELF_MACHINE, 0);
         if (bios_size == -1UL) {
commit e0ff466c86bfb3b865865431bf8aa67287691917
Author: Alexey Kardashevskiy <aik at ozlabs.ru>
Date:   Thu May 2 20:22:03 2013 +0000

    spapr_llan: fix device reenabling
    
    Normally, the "tap" device is polled by QEMU if a guest NIC can
    receive packets. If a guest NIC is stopped during transfer (rmmod or
    ifdown), it may still have packets in a queue which have to be send
    to the guest before QEMU enables polling of a "tap" interface via
    tap_update_fd_handler().
    
    However the spapr_llan device was missing the qemu_flush_queued_packets()
    call so the tap_send_completed() callback was never called and therefore
    "tap" interface polling was not enabled ever.
    
    The patch fixes this problem.
    
    Signed-off-by: Alexey Kardashevskiy <aik at ozlabs.ru>
    Signed-off-by: Alexander Graf <agraf at suse.de>

diff --git a/hw/net/spapr_llan.c b/hw/net/spapr_llan.c
index 3150add..03a09f2 100644
--- a/hw/net/spapr_llan.c
+++ b/hw/net/spapr_llan.c
@@ -336,6 +336,8 @@ static target_ulong h_register_logical_lan(PowerPCCPU *cpu,
     spapr_vio_dma_set(sdev, VLAN_BD_ADDR(rec_queue), 0, VLAN_BD_LEN(rec_queue));
 
     dev->isopen = 1;
+    qemu_flush_queued_packets(qemu_get_queue(dev->nic));
+
     return H_SUCCESS;
 }
 
commit 43d03f299a017186e00f47c5b10f732492d496a6
Author: Tiejun Chen <tiejun.chen at windriver.com>
Date:   Wed May 1 15:22:59 2013 +0000

    PPC: e500: correct params->ram_size with ram_size
    
    We should sync params->ram_size after we fixup memory size on
    a alignment boundary. Otherwise Guest would exceed the actual
    memory region.
    
    Signed-off-by: Tiejun Chen <tiejun.chen at windriver.com>
    Signed-off-by: Alexander Graf <agraf at suse.de>

diff --git a/hw/ppc/e500.c b/hw/ppc/e500.c
index 2d474e5..c9ae512 100644
--- a/hw/ppc/e500.c
+++ b/hw/ppc/e500.c
@@ -547,6 +547,7 @@ void ppce500_init(PPCE500Params *params)
 
     /* Fixup Memory size on a alignment boundary */
     ram_size &= ~(RAM_SIZES_ALIGN - 1);
+    params->ram_size = ram_size;
 
     /* Register Memory */
     memory_region_init_ram(ram, "mpc8544ds.ram", ram_size);
commit 04559d5210860ea5853db09c75ea8ff2f8843e16
Author: Anton Blanchard <anton at samba.org>
Date:   Wed May 1 00:44:51 2013 +0000

    target-ppc: Add read and write of PPR SPR
    
    Recent Linux kernels save and restore the PPR across exceptions
    so we need to handle it.
    
    Signed-off-by: Anton Blanchard <anton at au1.ibm.com>
    Signed-off-by: Alexander Graf <agraf at suse.de>

diff --git a/target-ppc/translate_init.c b/target-ppc/translate_init.c
index 6feb62a..021a31e 100644
--- a/target-ppc/translate_init.c
+++ b/target-ppc/translate_init.c
@@ -7010,6 +7010,10 @@ static void init_proc_POWER7 (CPUPPCState *env)
                  &spr_read_generic, &spr_write_generic,
                  &spr_read_generic, &spr_write_generic,
                  0x00000000);
+    spr_register(env, SPR_PPR, "PPR",
+                 &spr_read_generic, &spr_write_generic,
+                 &spr_read_generic, &spr_write_generic,
+                 0x00000000);
 #if !defined(CONFIG_USER_ONLY)
     env->slb_nr = 32;
 #endif
commit c05541ee191107eb35093fb693e4ec038e60d2c0
Author: Anton Blanchard <anton at samba.org>
Date:   Wed May 1 00:43:59 2013 +0000

    target-ppc: Fix invalid SPR read/write warnings
    
    Invalid and privileged SPR warnings currently print the wrong
    address. While fixing that, also make it clear that we are
    printing both the decimal and hexadecimal SPR number.
    
    Before:
    
      Trying to read invalid spr 896 380 at 0000000000000714
    
    After:
    
      Trying to read invalid spr 896 (0x380) at 0000000000000710
    
    Signed-off-by: Anton Blanchard <anton at au1.ibm.com>
    Signed-off-by: Alexander Graf <agraf at suse.de>

diff --git a/target-ppc/translate.c b/target-ppc/translate.c
index 1a84653..0886f4d 100644
--- a/target-ppc/translate.c
+++ b/target-ppc/translate.c
@@ -4005,19 +4005,19 @@ static inline void gen_op_mfspr(DisasContext *ctx)
              * allowing userland application to read the PVR
              */
             if (sprn != SPR_PVR) {
-                qemu_log("Trying to read privileged spr %d %03x at "
-                         TARGET_FMT_lx "\n", sprn, sprn, ctx->nip);
-                printf("Trying to read privileged spr %d %03x at "
-                       TARGET_FMT_lx "\n", sprn, sprn, ctx->nip);
+                qemu_log("Trying to read privileged spr %d (0x%03x) at "
+                         TARGET_FMT_lx "\n", sprn, sprn, ctx->nip - 4);
+                printf("Trying to read privileged spr %d (0x%03x) at "
+                       TARGET_FMT_lx "\n", sprn, sprn, ctx->nip - 4);
             }
             gen_inval_exception(ctx, POWERPC_EXCP_PRIV_REG);
         }
     } else {
         /* Not defined */
-        qemu_log("Trying to read invalid spr %d %03x at "
-                    TARGET_FMT_lx "\n", sprn, sprn, ctx->nip);
-        printf("Trying to read invalid spr %d %03x at " TARGET_FMT_lx "\n",
-               sprn, sprn, ctx->nip);
+        qemu_log("Trying to read invalid spr %d (0x%03x) at "
+                 TARGET_FMT_lx "\n", sprn, sprn, ctx->nip - 4);
+        printf("Trying to read invalid spr %d (0x%03x) at "
+               TARGET_FMT_lx "\n", sprn, sprn, ctx->nip - 4);
         gen_inval_exception(ctx, POWERPC_EXCP_INVAL_SPR);
     }
 }
@@ -4150,18 +4150,18 @@ static void gen_mtspr(DisasContext *ctx)
             (*write_cb)(ctx, sprn, rS(ctx->opcode));
         } else {
             /* Privilege exception */
-            qemu_log("Trying to write privileged spr %d %03x at "
-                     TARGET_FMT_lx "\n", sprn, sprn, ctx->nip);
-            printf("Trying to write privileged spr %d %03x at " TARGET_FMT_lx
-                   "\n", sprn, sprn, ctx->nip);
+            qemu_log("Trying to write privileged spr %d (0x%03x) at "
+                     TARGET_FMT_lx "\n", sprn, sprn, ctx->nip - 4);
+            printf("Trying to write privileged spr %d (0x%03x) at "
+                   TARGET_FMT_lx "\n", sprn, sprn, ctx->nip - 4);
             gen_inval_exception(ctx, POWERPC_EXCP_PRIV_REG);
         }
     } else {
         /* Not defined */
-        qemu_log("Trying to write invalid spr %d %03x at "
-                 TARGET_FMT_lx "\n", sprn, sprn, ctx->nip);
-        printf("Trying to write invalid spr %d %03x at " TARGET_FMT_lx "\n",
-               sprn, sprn, ctx->nip);
+        qemu_log("Trying to write invalid spr %d (0x%03x) at "
+                 TARGET_FMT_lx "\n", sprn, sprn, ctx->nip - 4);
+        printf("Trying to write invalid spr %d (0x%03x) at "
+               TARGET_FMT_lx "\n", sprn, sprn, ctx->nip - 4);
         gen_inval_exception(ctx, POWERPC_EXCP_INVAL_SPR);
     }
 }
commit 126a79300971ab9314925c3ebbbd6c776bebf3f1
Author: Alexander Graf <agraf at suse.de>
Date:   Thu May 2 00:27:51 2013 +0200

    PPC: Add MMU type for 2.06 with AMR but no TB pages
    
    When running -cpu on a POWER7 system with PR KVM, we mask out the 1TB
    MMU capability from the MMU type mask, but not the AMR bit.
    
    This leads to us having a new MMU type that we don't check for in our
    MMU management functions.
    
    Add the new type, so that we don't have to worry about breakage there.
    We're not going to use the TCG MMU management in that case anyway.
    
    The long term fix for this will be to move all these MMU management
    functions to class callbacks.
    
    Signed-off-by: Alexander Graf <agraf at suse.de>

diff --git a/target-ppc/cpu.h b/target-ppc/cpu.h
index 7cacb56..aa1d013 100644
--- a/target-ppc/cpu.h
+++ b/target-ppc/cpu.h
@@ -119,6 +119,9 @@ enum powerpc_mmu_t {
     /* Architecture 2.06 variant                               */
     POWERPC_MMU_2_06       = POWERPC_MMU_64 | POWERPC_MMU_1TSEG
                              | POWERPC_MMU_AMR | 0x00000003,
+    /* Architecture 2.06 "degraded" (no 1T segments)           */
+    POWERPC_MMU_2_06a      = POWERPC_MMU_64 | POWERPC_MMU_AMR
+                             | 0x00000003,
     /* Architecture 2.06 "degraded" (no 1T segments or AMR)    */
     POWERPC_MMU_2_06d      = POWERPC_MMU_64 | 0x00000003,
 #endif /* defined(TARGET_PPC64) */
diff --git a/target-ppc/mmu_helper.c b/target-ppc/mmu_helper.c
index acf0133..68d5415 100644
--- a/target-ppc/mmu_helper.c
+++ b/target-ppc/mmu_helper.c
@@ -1188,6 +1188,7 @@ void dump_mmu(FILE *f, fprintf_function cpu_fprintf, CPUPPCState *env)
 #if defined(TARGET_PPC64)
     case POWERPC_MMU_64B:
     case POWERPC_MMU_2_06:
+    case POWERPC_MMU_2_06a:
     case POWERPC_MMU_2_06d:
         dump_slb(f, cpu_fprintf, env);
         break;
@@ -1324,6 +1325,7 @@ hwaddr cpu_get_phys_page_debug(CPUPPCState *env, target_ulong addr)
 #if defined(TARGET_PPC64)
     case POWERPC_MMU_64B:
     case POWERPC_MMU_2_06:
+    case POWERPC_MMU_2_06a:
     case POWERPC_MMU_2_06d:
         return ppc_hash64_get_phys_page_debug(env, addr);
 #endif
@@ -1815,6 +1817,7 @@ void ppc_tlb_invalidate_all(CPUPPCState *env)
 #if defined(TARGET_PPC64)
     case POWERPC_MMU_64B:
     case POWERPC_MMU_2_06:
+    case POWERPC_MMU_2_06a:
     case POWERPC_MMU_2_06d:
 #endif /* defined(TARGET_PPC64) */
         tlb_flush(env, 1);
@@ -1884,6 +1887,7 @@ void ppc_tlb_invalidate_one(CPUPPCState *env, target_ulong addr)
 #if defined(TARGET_PPC64)
     case POWERPC_MMU_64B:
     case POWERPC_MMU_2_06:
+    case POWERPC_MMU_2_06a:
     case POWERPC_MMU_2_06d:
         /* tlbie invalidate TLBs for all segments */
         /* XXX: given the fact that there are too many segments to invalidate,
commit 4807ab4f36740b64a0dfa30ae90fe2e8a7d96fbb
Author: Alexey Kardashevskiy <aik at ozlabs.ru>
Date:   Tue Apr 30 03:42:23 2013 +0000

    pseries: Update SLOF firmware image
    
    Minor SLOF fixes which are required for libvirtd to function properly:
    * vio-vscsi: vscsi-report-luns can return 0
    * vio-vscsi: added a proper lun parser
    * SLOF: vio-vscsi: fixed bug with reported luns
    
    Signed-off-by: Alexey Kardashevskiy <aik at ozlabs.ru>
    Signed-off-by: Alexander Graf <agraf at suse.de>

diff --git a/pc-bios/README b/pc-bios/README
index 7b4dfed..030d92a 100644
--- a/pc-bios/README
+++ b/pc-bios/README
@@ -16,8 +16,8 @@
 
 - SLOF (Slimline Open Firmware) is a free IEEE 1275 Open Firmware
   implementation for certain IBM POWER hardware.  The sources are at
-  https://github.com/dgibson/SLOF, and the image currently in qemu is
-  built from git tag qemu-slof-20121018.
+  https://github.com/aik/SLOF, and the image currently in qemu is
+  built from git tag qemu-slof-20130430.
 
 - sgabios (the Serial Graphics Adapter option ROM) provides a means for
   legacy x86 software to communicate with an attached serial console as
diff --git a/pc-bios/slof.bin b/pc-bios/slof.bin
index 3410f4f..092e58a 100644
Binary files a/pc-bios/slof.bin and b/pc-bios/slof.bin differ
diff --git a/roms/SLOF b/roms/SLOF
index 0ad10f2..8cfdfc4 160000
--- a/roms/SLOF
+++ b/roms/SLOF
@@ -1 +1 @@
-Subproject commit 0ad10f26c94a86a0c9c3970e53f9a9f6a744055d
+Subproject commit 8cfdfc43f4c4c8c8dfa4b7cf16f7c19c84eee812
commit cefd3cdbdd9fc9a7d5ab324291904074d2aa69a0
Author: Bharat Bhushan <r65777 at freescale.com>
Date:   Mon Apr 29 04:40:56 2013 +0000

    PPC: e500: initialize GPRs as per epapr
    
    ePAPR defines the initial values of cpu registers.
    This patch initialize the GPRs as per ePAPR specification.
    
    This resolves the issue of guest reboot/reset (guest hang on reboot).
    
    Signed-off-by: Bharat Bhushan <bharat.bhushan at freescale.com>
    [agraf: add whitespace line]
    Signed-off-by: Alexander Graf <agraf at suse.de>

diff --git a/hw/ppc/e500.c b/hw/ppc/e500.c
index c1bdb6b..2d474e5 100644
--- a/hw/ppc/e500.c
+++ b/hw/ppc/e500.c
@@ -37,6 +37,7 @@
 #include "qemu/host-utils.h"
 #include "hw/pci-host/ppce500.h"
 
+#define EPAPR_MAGIC                (0x45504150)
 #define BINARY_DEVICE_TREE_FILE    "mpc8544ds.dtb"
 #define UIMAGE_LOAD_BASE           0
 #define DTC_LOAD_PAD               0x1800000
@@ -393,11 +394,10 @@ static inline hwaddr booke206_page_size_to_tlb(uint64_t size)
     return 63 - clz64(size >> 10);
 }
 
-static void mmubooke_create_initial_mapping(CPUPPCState *env)
+static int booke206_initial_map_tsize(CPUPPCState *env)
 {
     struct boot_info *bi = env->load_info;
-    ppcmas_tlb_t *tlb = booke206_get_tlbm(env, 1, 0, 0);
-    hwaddr size, dt_end;
+    hwaddr dt_end;
     int ps;
 
     /* Our initial TLB entry needs to cover everything from 0 to
@@ -408,6 +408,24 @@ static void mmubooke_create_initial_mapping(CPUPPCState *env)
         /* e500v2 can only do even TLB size bits */
         ps++;
     }
+    return ps;
+}
+
+static uint64_t mmubooke_initial_mapsize(CPUPPCState *env)
+{
+    int tsize;
+
+    tsize = booke206_initial_map_tsize(env);
+    return (1ULL << 10 << tsize);
+}
+
+static void mmubooke_create_initial_mapping(CPUPPCState *env)
+{
+    ppcmas_tlb_t *tlb = booke206_get_tlbm(env, 1, 0, 0);
+    hwaddr size;
+    int ps;
+
+    ps = booke206_initial_map_tsize(env);
     size = (ps << MAS1_TSIZE_SHIFT);
     tlb->mas1 = MAS1_VALID | size;
     tlb->mas2 = 0;
@@ -444,6 +462,12 @@ static void ppce500_cpu_reset(void *opaque)
     cs->halted = 0;
     env->gpr[1] = (16<<20) - 8;
     env->gpr[3] = bi->dt_base;
+    env->gpr[4] = 0;
+    env->gpr[5] = 0;
+    env->gpr[6] = EPAPR_MAGIC;
+    env->gpr[7] = mmubooke_initial_mapsize(env);
+    env->gpr[8] = 0;
+    env->gpr[9] = 0;
     env->nip = bi->entry;
     mmubooke_create_initial_mapping(env);
 }
commit b55519a0f29fca0ef7ebc5d87ee4bfa7304dc219
Author: David Gibson <david at gibson.dropbear.id.au>
Date:   Mon Apr 29 18:33:52 2013 +0000

    pseries: Fix debug message for out-of-bounds address in H_PUT_TCE
    
    Due to a brain outage, this message says "out-of-boards" instead of
    "out-of-bounds".
    
    Signed-off-by: David Gibson <david at gibson.dropbear.id.au>
    Signed-off-by: Alexey Kardashevskiy <aik at ozlabs.ru>
    Signed-off-by: Alexander Graf <agraf at suse.de>

diff --git a/hw/ppc/spapr_iommu.c b/hw/ppc/spapr_iommu.c
index c6aa4fe..e1fe941 100644
--- a/hw/ppc/spapr_iommu.c
+++ b/hw/ppc/spapr_iommu.c
@@ -205,7 +205,7 @@ static target_ulong put_tce_emu(sPAPRTCETable *tcet, target_ulong ioba,
     sPAPRTCE *tcep;
 
     if (ioba >= tcet->window_size) {
-        hcall_dprintf("spapr_vio_put_tce on out-of-boards IOBA 0x"
+        hcall_dprintf("spapr_vio_put_tce on out-of-bounds IOBA 0x"
                       TARGET_FMT_lx "\n", ioba);
         return H_PARAMETER;
     }
commit d4261662b67b48e52f747ee1e3c31cf873c5c982
Author: David Gibson <david at gibson.dropbear.id.au>
Date:   Mon Apr 29 18:33:51 2013 +0000

    pseries: Factor out check for out-of-bounds LIOBN
    
    PAPR defines LIOBNs (Logical IO Bus Numbers) to be 32-bit, and we check for
    values that aren't in the code for H_PUT_TCE.  This patch factors the check
    into spapr_tce_find_by_liobn(), which already checks if a 32-bit LIOBN
    actually exists.  This will become more important as future patches add
    other hypercalls which need to look up a LIOBN.
    
    At the same time we fix the typo in the message.
    
    Signed-off-by: David Gibson <david at gibson.dropbear.id.au>
    Signed-off-by: Alexey Kardashevskiy <aik at ozlabs.ru>
    Signed-off-by: Alexander Graf <agraf at suse.de>

diff --git a/hw/ppc/spapr_iommu.c b/hw/ppc/spapr_iommu.c
index d2782cf..c6aa4fe 100644
--- a/hw/ppc/spapr_iommu.c
+++ b/hw/ppc/spapr_iommu.c
@@ -55,6 +55,12 @@ static sPAPRTCETable *spapr_tce_find_by_liobn(uint32_t liobn)
 {
     sPAPRTCETable *tcet;
 
+    if (liobn & 0xFFFFFFFF00000000ULL) {
+        hcall_dprintf("Request for out-of-bounds LIOBN 0x" TARGET_FMT_lx "\n",
+                      liobn);
+        return NULL;
+    }
+
     QLIST_FOREACH(tcet, &spapr_tce_tables, list) {
         if (tcet->liobn == liobn) {
             return tcet;
@@ -218,12 +224,6 @@ static target_ulong h_put_tce(PowerPCCPU *cpu, sPAPREnvironment *spapr,
     target_ulong tce = args[2];
     sPAPRTCETable *tcet = spapr_tce_find_by_liobn(liobn);
 
-    if (liobn & 0xFFFFFFFF00000000ULL) {
-        hcall_dprintf("spapr_vio_put_tce on out-of-boundsw LIOBN "
-                      TARGET_FMT_lx "\n", liobn);
-        return H_PARAMETER;
-    }
-
     ioba &= ~(SPAPR_TCE_PAGE_SIZE - 1);
 
     if (tcet) {
commit 0c1cd0ae2a4faabeb948b9a07ea1696e853de174
Author: Marcelo Tosatti <mtosatti at redhat.com>
Date:   Sun May 5 17:51:49 2013 -0300

    kvmvapic: add ioport read accessor
    
    Necessary since memory region accessor assumes read and write
    methods are registered. Otherwise reading I/O port 0x7e segfaults.
    
    https://bugzilla.redhat.com/show_bug.cgi?id=954306
    
    Signed-off-by: Marcelo Tosatti <mtosatti at redhat.com>
    Reviewed-by: Jan Kiszka <jan.kiszka at siemens.com>
    Signed-off-by: Gleb Natapov <gleb at redhat.com>

diff --git a/hw/i386/kvmvapic.c b/hw/i386/kvmvapic.c
index 5b558aa..655483b 100644
--- a/hw/i386/kvmvapic.c
+++ b/hw/i386/kvmvapic.c
@@ -687,8 +687,14 @@ static void vapic_write(void *opaque, hwaddr addr, uint64_t data,
     }
 }
 
+static uint64_t vapic_read(void *opaque, hwaddr addr, unsigned size)
+{
+    return 0xffffffff;
+}
+
 static const MemoryRegionOps vapic_ops = {
     .write = vapic_write,
+    .read = vapic_read,
     .endianness = DEVICE_NATIVE_ENDIAN,
 };
 
commit 8e515b125d5f7849167dbee6cbe6ef61636607d4
Author: Peter Maydell <peter.maydell at linaro.org>
Date:   Sat May 4 21:57:51 2013 +0100

    configure: Check that "libtool" is not the MacOSX one
    
    The "libtool" binary on MacOSX is not GNU libtool, and doesn't support
    anything like the same set of command line options. Test whether we
    have accidentally picked this up (by looking for whether it handles
    the GNU --version switch), and discard it if so. The fallback machinery
    for the "we don't have a libtool" case will work fine. This fixes a
    failure in "make install" on MacOSX.
    
    Reported-by: Peter Cheung <mcheung63 at hotmail.com>
    Signed-off-by: Peter Maydell <peter.maydell at linaro.org>
    Message-id: 1367701071-6630-1-git-send-email-peter.maydell at linaro.org
    Signed-off-by: Anthony Liguori <aliguori at us.ibm.com>

diff --git a/configure b/configure
index e818e8b..a9ff4ad 100755
--- a/configure
+++ b/configure
@@ -1685,6 +1685,14 @@ if ! has $libtool; then
     libtool=
 fi
 
+# MacOSX ships with a libtool which isn't the GNU one; weed this
+# out by checking whether libtool supports the --version switch
+if test -n "$libtool"; then
+  if ! "$libtool" --version >/dev/null 2>&1; then
+    libtool=
+  fi
+fi
+
 ##########################################
 # Sparse probe
 if test "$sparse" != "no" ; then
commit e4b006b7a5bce59d4f692d5da04eede5f6d0f31c
Merge: 1e65fe5 b6f54b3
Author: Anthony Liguori <aliguori at us.ibm.com>
Date:   Mon May 6 06:49:51 2013 -0500

    Merge remote-tracking branch 'afaerber-or/prep-up' into staging
    
    # By Andreas Färber (1) and others
    # Via Andreas Färber
    * afaerber-or/prep-up:
      prep: Make System I/O port 0092 read/write
      prep: Add ELF support for -bios
      prep: Fix NIP reset value

commit 1e65fe536782132316ddae0a92f3c4e4f563cafb
Merge: 467b346 462566f
Author: Anthony Liguori <aliguori at us.ibm.com>
Date:   Mon May 6 06:47:28 2013 -0500

    Merge remote-tracking branch 'pmaydell/arm-devs.next' into staging
    
    # By Jean-Christophe DUBOIS
    # Via Peter Maydell
    * pmaydell/arm-devs.next:
      i.MX: implement a more correct version of EPIT timer.
    
    Message-id: 1367603215-5120-1-git-send-email-peter.maydell at linaro.org
    Signed-off-by: Anthony Liguori <aliguori at us.ibm.com>

commit b6f54b31e7cfb2e88b76fc6cfc5334a26d1b9e53
Author: Julio Guerra <guerr at julio.in>
Date:   Sun May 5 23:29:48 2013 +0200

    prep: Make System I/O port 0092 read/write
    
    Port 0x0092 is documented as read/write, so for now return the
    endianness state instead of hardcoded 0x00.
    
    Signed-off-by: Julio Guerra <guerr at julio.in>
    [AF: Extracted from larger port 0092 patch]
    Signed-off-by: Andreas Färber <andreas.faerber at web.de>

diff --git a/hw/ppc/prep.c b/hw/ppc/prep.c
index afa62d7..be8a50e 100644
--- a/hw/ppc/prep.c
+++ b/hw/ppc/prep.c
@@ -269,7 +269,7 @@ static uint32_t PREP_io_800_readb (void *opaque, uint32_t addr)
     switch (addr) {
     case 0x0092:
         /* Special port 92 */
-        retval = 0x00;
+        retval = sysctrl->endian << 1;
         break;
     case 0x0800:
         /* Motorola CPU configuration register */
commit 97c42c3c93d58e14960bfd78771ed154a860acf8
Author: Andreas Färber <andreas.faerber at web.de>
Date:   Sat Apr 27 21:23:23 2013 +0200

    prep: Add ELF support for -bios
    
    This prepares for switching from OpenHack'Ware to OpenBIOS.
    
    While touching the error handling code, switch from aborting hw_error()
    to fprintf()+exit() and suppress failing without -bios for qtest.
    
    Acked-by: Alexander Graf <agraf at suse.de>
    Signed-off-by: Andreas Färber <andreas.faerber at web.de>

diff --git a/hw/ppc/prep.c b/hw/ppc/prep.c
index 2ad5b41..afa62d7 100644
--- a/hw/ppc/prep.c
+++ b/hw/ppc/prep.c
@@ -40,7 +40,9 @@
 #include "hw/isa/pc87312.h"
 #include "sysemu/blockdev.h"
 #include "sysemu/arch_init.h"
+#include "sysemu/qtest.h"
 #include "exec/address-spaces.h"
+#include "elf.h"
 
 //#define HARD_DEBUG_PPC_IO
 //#define DEBUG_PPC_IO
@@ -505,18 +507,29 @@ static void ppc_prep_init(QEMUMachineInitArgs *args)
         bios_name = BIOS_FILENAME;
     filename = qemu_find_file(QEMU_FILE_TYPE_BIOS, bios_name);
     if (filename) {
-        bios_size = get_image_size(filename);
+        bios_size = load_elf(filename, NULL, NULL, NULL,
+                             NULL, NULL, 1, ELF_MACHINE, 0);
+        if (bios_size < 0) {
+            bios_size = get_image_size(filename);
+            if (bios_size > 0 && bios_size <= BIOS_SIZE) {
+                hwaddr bios_addr;
+                bios_size = (bios_size + 0xfff) & ~0xfff;
+                bios_addr = (uint32_t)(-bios_size);
+                bios_size = load_image_targphys(filename, bios_addr, bios_size);
+            }
+            if (bios_size > BIOS_SIZE) {
+                fprintf(stderr, "qemu: PReP bios '%s' is too large (0x%x)\n",
+                        bios_name, bios_size);
+                exit(1);
+            }
+        }
     } else {
         bios_size = -1;
     }
-    if (bios_size > 0 && bios_size <= BIOS_SIZE) {
-        hwaddr bios_addr;
-        bios_size = (bios_size + 0xfff) & ~0xfff;
-        bios_addr = (uint32_t)(-bios_size);
-        bios_size = load_image_targphys(filename, bios_addr, bios_size);
-    }
-    if (bios_size < 0 || bios_size > BIOS_SIZE) {
-        hw_error("qemu: could not load PPC PREP bios '%s'\n", bios_name);
+    if (bios_size < 0 && !qtest_enabled()) {
+        fprintf(stderr, "qemu: could not load PPC PReP bios '%s'\n",
+                bios_name);
+        exit(1);
     }
     if (filename) {
         g_free(filename);
commit 88432756ead526d9c321c20f10fafdbe40e5eaba
Author: Fabien Chouteau <chouteau at adacore.com>
Date:   Tue Apr 30 17:07:04 2013 +0200

    prep: Fix NIP reset value
    
    The value was changed by commit 09d9828ace37ead29d510a7e24e63c2f15cd4b1c
    "PPC: fix hreset_vector for 60x, ...".
    
    Change it back for prep machine to unbreak OpenHack'Ware.
    
    Signed-off-by: Fabien Chouteau <chouteau at adacore.com>
    Signed-off-by: Andreas Färber <andreas.faerber at web.de>

diff --git a/hw/ppc/prep.c b/hw/ppc/prep.c
index 59c7da3..2ad5b41 100644
--- a/hw/ppc/prep.c
+++ b/hw/ppc/prep.c
@@ -427,6 +427,9 @@ static void ppc_prep_reset(void *opaque)
     PowerPCCPU *cpu = opaque;
 
     cpu_reset(CPU(cpu));
+
+    /* Reset address */
+    cpu->env.nip = 0xfffffffc;
 }
 
 /* PowerPC PREP hardware initialisation */
commit 462566fc5e3e10a44e212fdbc67b9e4948179b14
Author: Jean-Christophe DUBOIS <jcd at tribudubois.net>
Date:   Fri May 3 18:21:02 2013 +0100

    i.MX: implement a more correct version of EPIT timer.
    
    This patch is providing a complete version of the EPIT timer.
    
    Note, however that the GPT timer in the same file is still not
    complete.
    
    Signed-off-by: Jean-Christophe DUBOIS <jcd at tribudubois.net>
    Message-id: 1365624982-15647-1-git-send-email-jcd at tribudubois.net
    Reviewed-by: Peter Chubb <peter.chubb at nicta.com.au>
    [PMM: wrapped an overly long line]
    Signed-off-by: Peter Maydell <peter.maydell at linaro.org>

diff --git a/hw/timer/imx_timer.c b/hw/timer/imx_timer.c
index 03197e3..7693bb7 100644
--- a/hw/timer/imx_timer.c
+++ b/hw/timer/imx_timer.c
@@ -95,6 +95,10 @@ typedef struct {
     uint32_t sr;
     uint32_t ir;
     uint32_t ocr1;
+    uint32_t ocr2;
+    uint32_t ocr3;
+    uint32_t icr1;
+    uint32_t icr2;
     uint32_t cnt;
 
     uint32_t waiting_rov;
@@ -103,15 +107,19 @@ typedef struct {
 
 static const VMStateDescription vmstate_imx_timerg = {
     .name = "imx-timerg",
-    .version_id = 1,
-    .minimum_version_id = 1,
-    .minimum_version_id_old = 1,
+    .version_id = 2,
+    .minimum_version_id = 2,
+    .minimum_version_id_old = 2,
     .fields      = (VMStateField[]) {
         VMSTATE_UINT32(cr, IMXTimerGState),
         VMSTATE_UINT32(pr, IMXTimerGState),
         VMSTATE_UINT32(sr, IMXTimerGState),
         VMSTATE_UINT32(ir, IMXTimerGState),
         VMSTATE_UINT32(ocr1, IMXTimerGState),
+        VMSTATE_UINT32(ocr2, IMXTimerGState),
+        VMSTATE_UINT32(ocr3, IMXTimerGState),
+        VMSTATE_UINT32(icr1, IMXTimerGState),
+        VMSTATE_UINT32(icr2, IMXTimerGState),
         VMSTATE_UINT32(cnt, IMXTimerGState),
         VMSTATE_UINT32(waiting_rov, IMXTimerGState),
         VMSTATE_PTIMER(timer, IMXTimerGState),
@@ -156,7 +164,6 @@ static void imx_timerg_update(IMXTimerGState *s)
             s->ir & GPT_SR_ROV ? "ROV" : "",
             s->cr & GPT_CR_EN ? "CR_EN" : "Not Enabled");
 
-
     qemu_set_irq(s->irq, (s->cr & GPT_CR_EN) && flags);
 }
 
@@ -221,6 +228,21 @@ static uint64_t imx_timerg_read(void *opaque, hwaddr offset,
         DPRINTF(" ocr1 = %x\n", s->ocr1);
         return s->ocr1;
 
+    case 5: /* Output Compare Register 2 */
+        DPRINTF(" ocr2 = %x\n", s->ocr2);
+        return s->ocr2;
+
+    case 6: /* Output Compare Register 3 */
+        DPRINTF(" ocr3 = %x\n", s->ocr3);
+        return s->ocr3;
+
+    case 7: /* input Capture Register 1 */
+        DPRINTF(" icr1 = %x\n", s->icr1);
+        return s->icr1;
+
+    case 8: /* input Capture Register 2 */
+        DPRINTF(" icr2 = %x\n", s->icr2);
+        return s->icr2;
 
     case 9: /* cnt */
         imx_timerg_update_counts(s);
@@ -230,6 +252,7 @@ static uint64_t imx_timerg_read(void *opaque, hwaddr offset,
 
     IPRINTF("imx_timerg_read: Bad offset %x\n",
             (int)offset >> 2);
+
     return 0;
 }
 
@@ -240,14 +263,20 @@ static void imx_timerg_reset(DeviceState *dev)
     /*
      * Soft reset doesn't touch some bits; hard reset clears them
      */
-    s->cr &= ~(GPT_CR_EN|GPT_CR_DOZEN|GPT_CR_WAITEN|GPT_CR_DBGEN);
+    s->cr &= ~(GPT_CR_EN|GPT_CR_ENMOD|GPT_CR_STOPEN|GPT_CR_DOZEN|
+               GPT_CR_WAITEN|GPT_CR_DBGEN);
     s->sr = 0;
     s->pr = 0;
     s->ir = 0;
     s->cnt = 0;
     s->ocr1 = TIMER_MAX;
+    s->ocr2 = TIMER_MAX;
+    s->ocr3 = TIMER_MAX;
+    s->icr1 = 0;
+    s->icr2 = 0;
     ptimer_stop(s->timer);
     ptimer_set_limit(s->timer, TIMER_MAX, 1);
+    ptimer_set_count(s->timer, TIMER_MAX);
     imx_timerg_set_freq(s);
 }
 
@@ -323,6 +352,8 @@ static void imx_timerg_write(void *opaque, hwaddr offset,
         s->ocr1 = value;
         return;
 
+    case 5: /* OCR2 -- output compare register */
+    case 6: /* OCR3 -- output compare register */
     default:
         IPRINTF("imx_timerg_write: Bad offset %x\n",
                 (int)offset >> 2);
@@ -411,7 +442,7 @@ static int imx_timerg_init(SysBusDevice *dev)
 #define CR_SWR      (1 << 16)
 #define CR_IOVW     (1 << 17)
 #define CR_DBGEN    (1 << 18)
-#define CR_EPIT     (1 << 19)
+#define CR_WAITEN   (1 << 19)
 #define CR_DOZEN    (1 << 20)
 #define CR_STOPEN   (1 << 21)
 #define CR_CLKSRC_SHIFT (24)
@@ -423,24 +454,26 @@ static int imx_timerg_init(SysBusDevice *dev)
  * These are typical.
  */
 static const IMXClk imx_timerp_clocks[] =  {
-    0,        /* disabled */
-    IPG, /* ipg_clk, ~532MHz */
-    IPG, /* ipg_clk_highfreq */
-    CLK_32k,    /* ipg_clk_32k -- ~32kHz */
+    0,        /* 00 disabled */
+    IPG,      /* 01 ipg_clk, ~532MHz */
+    IPG,      /* 10 ipg_clk_highfreq */
+    CLK_32k,  /* 11 ipg_clk_32k -- ~32kHz */
 };
 
 typedef struct {
     SysBusDevice busdev;
-    ptimer_state *timer;
+    ptimer_state *timer_reload;
+    ptimer_state *timer_cmp;
     MemoryRegion iomem;
     DeviceState *ccm;
 
     uint32_t cr;
+    uint32_t sr;
     uint32_t lr;
     uint32_t cmp;
+    uint32_t cnt;
 
     uint32_t freq;
-    int int_level;
     qemu_irq irq;
 } IMXTimerPState;
 
@@ -449,23 +482,63 @@ typedef struct {
  */
 static void imx_timerp_update(IMXTimerPState *s)
 {
-    if (s->int_level && (s->cr & CR_OCIEN)) {
+    if (s->sr && (s->cr & CR_OCIEN)) {
         qemu_irq_raise(s->irq);
     } else {
         qemu_irq_lower(s->irq);
     }
 }
 
+static void set_timerp_freq(IMXTimerPState *s)
+{
+    int clksrc;
+    unsigned prescaler;
+    uint32_t freq;
+
+    clksrc = (s->cr & CR_CLKSRC_MASK) >> CR_CLKSRC_SHIFT;
+    prescaler = 1 + ((s->cr >> CR_PRESCALE_SHIFT) & CR_PRESCALE_MASK);
+    freq = imx_clock_frequency(s->ccm, imx_timerp_clocks[clksrc]) / prescaler;
+
+    s->freq = freq;
+    DPRINTF("Setting ptimer frequency to %u\n", freq);
+
+    if (freq) {
+        ptimer_set_freq(s->timer_reload, freq);
+        ptimer_set_freq(s->timer_cmp, freq);
+    }
+}
+
 static void imx_timerp_reset(DeviceState *dev)
 {
     IMXTimerPState *s = container_of(dev, IMXTimerPState, busdev.qdev);
 
-    s->cr = 0;
+    /*
+     * Soft reset doesn't touch some bits; hard reset clears them
+     */
+    s->cr &= ~(CR_EN|CR_ENMOD|CR_STOPEN|CR_DOZEN|CR_WAITEN|CR_DBGEN);
+    s->sr = 0;
     s->lr = TIMER_MAX;
-    s->int_level = 0;
     s->cmp = 0;
-    ptimer_stop(s->timer);
-    ptimer_set_count(s->timer, TIMER_MAX);
+    s->cnt = 0;
+    /* stop both timers */
+    ptimer_stop(s->timer_cmp);
+    ptimer_stop(s->timer_reload);
+    /* compute new frequency */
+    set_timerp_freq(s);
+    /* init both timers to TIMER_MAX */
+    ptimer_set_limit(s->timer_cmp, TIMER_MAX, 1);
+    ptimer_set_limit(s->timer_reload, TIMER_MAX, 1);
+    if (s->freq && (s->cr & CR_EN)) {
+        /* if the timer is still enabled, restart it */
+        ptimer_run(s->timer_reload, 1);
+    }
+}
+
+static uint32_t imx_timerp_update_counts(IMXTimerPState *s)
+{
+     s->cnt = ptimer_get_count(s->timer_reload);
+
+     return s->cnt;
 }
 
 static uint64_t imx_timerp_read(void *opaque, hwaddr offset,
@@ -480,8 +553,8 @@ static uint64_t imx_timerp_read(void *opaque, hwaddr offset,
         return s->cr;
 
     case 1: /* Status Register */
-        DPRINTF("int_level %x\n", s->int_level);
-        return s->int_level;
+        DPRINTF("sr %x\n", s->sr);
+        return s->sr;
 
     case 2: /* LR - ticks*/
         DPRINTF("lr %x\n", s->lr);
@@ -492,28 +565,29 @@ static uint64_t imx_timerp_read(void *opaque, hwaddr offset,
         return s->cmp;
 
     case 4: /* CNT */
-        return ptimer_get_count(s->timer);
+        imx_timerp_update_counts(s);
+        DPRINTF(" cnt = %x\n", s->cnt);
+        return s->cnt;
     }
+
     IPRINTF("imx_timerp_read: Bad offset %x\n",
             (int)offset >> 2);
     return 0;
 }
 
-static void set_timerp_freq(IMXTimerPState *s)
+static void imx_reload_compare_timer(IMXTimerPState *s)
 {
-    int clksrc;
-    unsigned prescaler;
-    uint32_t freq;
-
-    clksrc = (s->cr & CR_CLKSRC_MASK) >> CR_CLKSRC_SHIFT;
-    prescaler = 1 + ((s->cr >> CR_PRESCALE_SHIFT) & CR_PRESCALE_MASK);
-    freq = imx_clock_frequency(s->ccm, imx_timerp_clocks[clksrc]) / prescaler;
-
-    s->freq = freq;
-    DPRINTF("Setting ptimer frequency to %u\n", freq);
-
-    if (freq) {
-        ptimer_set_freq(s->timer, freq);
+    if ((s->cr & CR_OCIEN) && s->cmp) {
+        /* if the compare feature is on */
+        uint32_t tmp = imx_timerp_update_counts(s);
+        if (tmp > s->cmp) {
+            /* reinit the cmp timer if required */
+            ptimer_set_count(s->timer_cmp, tmp - s->cmp);
+            if ((s->cr & CR_EN)) {
+                /* Restart the cmp timer if required */
+                ptimer_run(s->timer_cmp, 0);
+            }
+        }
     }
 }
 
@@ -526,40 +600,62 @@ static void imx_timerp_write(void *opaque, hwaddr offset,
 
     switch (offset >> 2) {
     case 0: /* CR */
-        if (value & CR_SWR) {
+        s->cr = value & 0x03ffffff;
+        if (s->cr & CR_SWR) {
+            /* handle the reset */
             imx_timerp_reset(&s->busdev.qdev);
-            value &= ~CR_SWR;
+        } else {
+            set_timerp_freq(s);
         }
-        s->cr = value & 0x03ffffff;
-        set_timerp_freq(s);
 
         if (s->freq && (s->cr & CR_EN)) {
-            if (!(s->cr & CR_ENMOD)) {
-                ptimer_set_count(s->timer, s->lr);
+            if (s->cr & CR_ENMOD) {
+                if (s->cr & CR_RLD) {
+                    ptimer_set_limit(s->timer_reload, s->lr, 1);
+                } else {
+                    ptimer_set_limit(s->timer_reload, TIMER_MAX, 1);
+                }
             }
-            ptimer_run(s->timer, 0);
+
+            imx_reload_compare_timer(s);
+
+            ptimer_run(s->timer_reload, 1);
         } else {
-            ptimer_stop(s->timer);
+            /* stop both timers */
+            ptimer_stop(s->timer_reload);
+            ptimer_stop(s->timer_cmp);
         }
         break;
 
     case 1: /* SR - ACK*/
-        s->int_level = 0;
-        imx_timerp_update(s);
+        /* writing 1 to OCIF clear the OCIF bit */
+        if (value & 0x01) {
+            s->sr = 0;
+            imx_timerp_update(s);
+        }
         break;
 
     case 2: /* LR - set ticks */
         s->lr = value;
-        ptimer_set_limit(s->timer, value, !!(s->cr & CR_IOVW));
+
+        if (s->cr & CR_RLD) {
+            /* Also set the limit if the LRD bit is set */
+            /* If IOVW bit is set then set the timer value */
+            ptimer_set_limit(s->timer_reload, s->lr, s->cr & CR_IOVW);
+        } else if (s->cr & CR_IOVW) {
+            /* If IOVW bit is set then set the timer value */
+            ptimer_set_count(s->timer_reload, s->lr);
+        }
+
+        imx_reload_compare_timer(s);
+
         break;
 
     case 3: /* CMP */
         s->cmp = value;
-        if (value) {
-            IPRINTF(
-                "Values for EPIT comparison other than zero not supported\n"
-            );
-        }
+
+        imx_reload_compare_timer(s);
+
         break;
 
     default:
@@ -568,16 +664,50 @@ static void imx_timerp_write(void *opaque, hwaddr offset,
     }
 }
 
-static void imx_timerp_tick(void *opaque)
+static void imx_timerp_reload(void *opaque)
 {
     IMXTimerPState *s = (IMXTimerPState *)opaque;
 
-   DPRINTF("imxp tick\n");
-    if (!(s->cr & CR_RLD)) {
-        ptimer_set_count(s->timer, TIMER_MAX);
+    DPRINTF("imxp reload\n");
+
+    if (!(s->cr & CR_EN)) {
+        return;
+    }
+
+    if (s->cr & CR_RLD) {
+        ptimer_set_limit(s->timer_reload, s->lr, 1);
+    } else {
+        ptimer_set_limit(s->timer_reload, TIMER_MAX, 1);
+    }
+
+    if (s->cr & CR_OCIEN) {
+        /* if compare register is 0 then we handle the interrupt here */
+        if (s->cmp == 0) {
+            s->sr = 1;
+            imx_timerp_update(s);
+        } else if (s->cmp <= s->lr) {
+            /* We should launch the compare register */
+            ptimer_set_count(s->timer_cmp, s->lr - s->cmp);
+            ptimer_run(s->timer_cmp, 0);
+        } else {
+            IPRINTF("imxp reload: s->lr < s->cmp\n");
+        }
+    }
+}
+
+static void imx_timerp_cmp(void *opaque)
+{
+    IMXTimerPState *s = (IMXTimerPState *)opaque;
+
+    DPRINTF("imxp compare\n");
+
+    ptimer_stop(s->timer_cmp);
+
+    /* compare register is not 0 */
+    if (s->cmp) {
+        s->sr = 1;
+        imx_timerp_update(s);
     }
-    s->int_level = 1;
-    imx_timerp_update(s);
 }
 
 void imx_timerp_create(const hwaddr addr,
@@ -600,16 +730,18 @@ static const MemoryRegionOps imx_timerp_ops = {
 
 static const VMStateDescription vmstate_imx_timerp = {
     .name = "imx-timerp",
-    .version_id = 1,
-    .minimum_version_id = 1,
-    .minimum_version_id_old = 1,
+    .version_id = 2,
+    .minimum_version_id = 2,
+    .minimum_version_id_old = 2,
     .fields      = (VMStateField[]) {
         VMSTATE_UINT32(cr, IMXTimerPState),
+        VMSTATE_UINT32(sr, IMXTimerPState),
         VMSTATE_UINT32(lr, IMXTimerPState),
         VMSTATE_UINT32(cmp, IMXTimerPState),
+        VMSTATE_UINT32(cnt, IMXTimerPState),
         VMSTATE_UINT32(freq, IMXTimerPState),
-        VMSTATE_INT32(int_level, IMXTimerPState),
-        VMSTATE_PTIMER(timer, IMXTimerPState),
+        VMSTATE_PTIMER(timer_reload, IMXTimerPState),
+        VMSTATE_PTIMER(timer_cmp, IMXTimerPState),
         VMSTATE_END_OF_LIST()
     }
 };
@@ -620,15 +752,17 @@ static int imx_timerp_init(SysBusDevice *dev)
     QEMUBH *bh;
 
     DPRINTF("imx_timerp_init\n");
-
     sysbus_init_irq(dev, &s->irq);
     memory_region_init_io(&s->iomem, &imx_timerp_ops,
                           s, "imxp-timer",
                           0x00001000);
     sysbus_init_mmio(dev, &s->iomem);
 
-    bh = qemu_bh_new(imx_timerp_tick, s);
-    s->timer = ptimer_init(bh);
+    bh = qemu_bh_new(imx_timerp_reload, s);
+    s->timer_reload = ptimer_init(bh);
+
+    bh = qemu_bh_new(imx_timerp_cmp, s);
+    s->timer_cmp = ptimer_init(bh);
 
     return 0;
 }


More information about the Spice-commits mailing list