All of lore.kernel.org
 help / color / mirror / Atom feed
* [Qemu-devel] [PATCH 00/15] target-s390x: add Program-Event Recording feature
@ 2015-06-12 22:45 Aurelien Jarno
  2015-06-12 22:45 ` [Qemu-devel] [PATCH 01/15] softmmu: provide tlb_vaddr_to_host function for user mode Aurelien Jarno
                   ` (15 more replies)
  0 siblings, 16 replies; 20+ messages in thread
From: Aurelien Jarno @ 2015-06-12 22:45 UTC (permalink / raw)
  To: qemu-devel; +Cc: Alexander Graf, Aurelien Jarno, Richard Henderson

This patch set adds support for the Program-Event Recording (PER)
feature. It implements all the PER functionalities except the
following ones:
- zero-address-detection event (part of the zero-address-detection
  facility)
- transaction-end event (we don't implement transactional memory)

There are also a few limitations to the storage-alteration event, as it
doesn't support per ASC enablement, nor it doesn't correctly provide the
ASC used for a storage event in the PER AI field.

With this patch set, it's possible to fully use GDB in a s390x guest,
including stepping, breakpoints and watchpoints.


Aurelien Jarno (15):
  softmmu: provide tlb_vaddr_to_host function for user mode
  target-s390x: function to adjust the length wrt page boundary
  target-s390x: mvc_fast_memset: access memory through softmmu
  target-s390x: mvc_fast_memmove: access memory through softmmu
  target-s390x: add PER related constants
  target-s390x: add get_per_atmid function
  target-s390x: add get_per_in_range function
  target-s390x: basic PER event handling
  target-s390x: PER successful-branching event support
  target-s390x: PER instruction-fetch event support
  translate-all: fix watchpoints if retranslation not possible
  target-s390x: PER storage-alteration event support
  target-s390x: PER store-using-real-address event support
  target-s390x: PER instruction-fetch nullification event support
  target-s390x: PER: add Breaking-Event-Address register

 include/exec/cpu_ldst.h    |   8 +-
 target-s390x/cpu-qom.h     |   1 +
 target-s390x/cpu.c         |   7 ++
 target-s390x/cpu.h         |  55 +++++++++++--
 target-s390x/helper.c      | 130 +++++++++++++++++++++++++-----
 target-s390x/helper.h      |   3 +
 target-s390x/mem_helper.c  | 193 +++++++++++++++++++++++----------------------
 target-s390x/misc_helper.c |  46 +++++++++++
 target-s390x/translate.c   |  82 ++++++++++++++++++-
 translate-all.c            |  20 +++--
 10 files changed, 420 insertions(+), 125 deletions(-)

-- 
2.1.4

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

* [Qemu-devel] [PATCH 01/15] softmmu: provide tlb_vaddr_to_host function for user mode
  2015-06-12 22:45 [Qemu-devel] [PATCH 00/15] target-s390x: add Program-Event Recording feature Aurelien Jarno
@ 2015-06-12 22:45 ` Aurelien Jarno
  2015-06-12 22:45 ` [Qemu-devel] [PATCH 02/15] target-s390x: function to adjust the length wrt page boundary Aurelien Jarno
                   ` (14 subsequent siblings)
  15 siblings, 0 replies; 20+ messages in thread
From: Aurelien Jarno @ 2015-06-12 22:45 UTC (permalink / raw)
  To: qemu-devel; +Cc: Alexander Graf, Aurelien Jarno, Richard Henderson

To avoid to many #ifdef in target code, provide a tlb_vaddr_to_host for
both user and softmmu modes. In the first case the function always
succeed and just call the g2h function.

Signed-off-by: Aurelien Jarno <aurelien@aurel32.net>
---
 include/exec/cpu_ldst.h | 8 ++++++--
 1 file changed, 6 insertions(+), 2 deletions(-)

diff --git a/include/exec/cpu_ldst.h b/include/exec/cpu_ldst.h
index 0ec398c..1239c60 100644
--- a/include/exec/cpu_ldst.h
+++ b/include/exec/cpu_ldst.h
@@ -399,6 +399,8 @@ uint64_t helper_ldq_cmmu(CPUArchState *env, target_ulong addr, int mmu_idx);
 #undef MEMSUFFIX
 #undef SOFTMMU_CODE_ACCESS
 
+#endif /* defined(CONFIG_USER_ONLY) */
+
 /**
  * tlb_vaddr_to_host:
  * @env: CPUArchState
@@ -417,6 +419,9 @@ uint64_t helper_ldq_cmmu(CPUArchState *env, target_ulong addr, int mmu_idx);
 static inline void *tlb_vaddr_to_host(CPUArchState *env, target_ulong addr,
                                       int access_type, int mmu_idx)
 {
+#if defined(CONFIG_USER_ONLY)
+    return g2h(vaddr);
+#else
     int index = (addr >> TARGET_PAGE_BITS) & (CPU_TLB_SIZE - 1);
     CPUTLBEntry *tlbentry = &env->tlb_table[mmu_idx][index];
     target_ulong tlb_addr;
@@ -449,8 +454,7 @@ static inline void *tlb_vaddr_to_host(CPUArchState *env, target_ulong addr,
 
     haddr = addr + env->tlb_table[mmu_idx][index].addend;
     return (void *)haddr;
-}
-
 #endif /* defined(CONFIG_USER_ONLY) */
+}
 
 #endif /* CPU_LDST_H */
-- 
2.1.4

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

* [Qemu-devel] [PATCH 02/15] target-s390x: function to adjust the length wrt page boundary
  2015-06-12 22:45 [Qemu-devel] [PATCH 00/15] target-s390x: add Program-Event Recording feature Aurelien Jarno
  2015-06-12 22:45 ` [Qemu-devel] [PATCH 01/15] softmmu: provide tlb_vaddr_to_host function for user mode Aurelien Jarno
@ 2015-06-12 22:45 ` Aurelien Jarno
  2015-06-12 22:45 ` [Qemu-devel] [PATCH 03/15] target-s390x: mvc_fast_memset: access memory through softmmu Aurelien Jarno
                   ` (13 subsequent siblings)
  15 siblings, 0 replies; 20+ messages in thread
From: Aurelien Jarno @ 2015-06-12 22:45 UTC (permalink / raw)
  To: qemu-devel; +Cc: Alexander Graf, Aurelien Jarno, Richard Henderson

This patch adds a function to adjust the length of a transfer so that
it doesn't cross a page boundary in softmmu mode. It does nothing in
user mode.

Cc: Alexander Graf <agraf@suse.de>
Cc: Richard Henderson <rth@twiddle.net>
Signed-off-by: Aurelien Jarno <aurelien@aurel32.net>
---
 target-s390x/mem_helper.c | 11 +++++++++++
 1 file changed, 11 insertions(+)

diff --git a/target-s390x/mem_helper.c b/target-s390x/mem_helper.c
index b4e5d44..b8d3a5f 100644
--- a/target-s390x/mem_helper.c
+++ b/target-s390x/mem_helper.c
@@ -54,6 +54,17 @@ void tlb_fill(CPUState *cs, target_ulong addr, int is_write, int mmu_idx,
 #define HELPER_LOG(x...)
 #endif
 
+/* Reduce the length so that addr + len doesn't cross a page boundary.  */
+static inline uint64_t adj_len_to_page(uint64_t len, uint64_t addr)
+{
+#ifndef CONFIG_USER_ONLY
+    if ((addr & ~TARGET_PAGE_MASK) + len - 1 >= TARGET_PAGE_SIZE) {
+        return -addr & ~TARGET_PAGE_MASK;
+    }
+#endif
+    return len;
+}
+
 #ifndef CONFIG_USER_ONLY
 static void mvc_fast_memset(CPUS390XState *env, uint32_t l, uint64_t dest,
                             uint8_t byte)
-- 
2.1.4

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

* [Qemu-devel] [PATCH 03/15] target-s390x: mvc_fast_memset: access memory through softmmu
  2015-06-12 22:45 [Qemu-devel] [PATCH 00/15] target-s390x: add Program-Event Recording feature Aurelien Jarno
  2015-06-12 22:45 ` [Qemu-devel] [PATCH 01/15] softmmu: provide tlb_vaddr_to_host function for user mode Aurelien Jarno
  2015-06-12 22:45 ` [Qemu-devel] [PATCH 02/15] target-s390x: function to adjust the length wrt page boundary Aurelien Jarno
@ 2015-06-12 22:45 ` Aurelien Jarno
  2015-06-12 22:45 ` [Qemu-devel] [PATCH 04/15] target-s390x: mvc_fast_memmove: " Aurelien Jarno
                   ` (12 subsequent siblings)
  15 siblings, 0 replies; 20+ messages in thread
From: Aurelien Jarno @ 2015-06-12 22:45 UTC (permalink / raw)
  To: qemu-devel; +Cc: Alexander Graf, Aurelien Jarno, Richard Henderson

mvc_fast_memset is bypassing the softmmu functions, getting the
physical address using the mmu_translate function and accessing the
corresponding physical memory. This prevents watchpoints to work
correctly.

Instead use the tlb_vaddr_to_host function to get the host address
corresponding to the guest address through the softmmu code and fallback
to the byte level code in case the corresponding address is not in the
QEMU TLB or being examined through a watchpoint. As a bonus it works
even for area crossing pages by splitting the are into chunks contained
in a single page, bringing some performances improvements.

At the same time change the name of the function to fast_memset as it's
not specific to mvc and use the same argument order as the C memset
function.

Cc: Alexander Graf <agraf@suse.de>
Cc: Richard Henderson <rth@twiddle.net>
Signed-off-by: Aurelien Jarno <aurelien@aurel32.net>
---
 target-s390x/mem_helper.c | 73 +++++++++++++++++++++--------------------------
 1 file changed, 32 insertions(+), 41 deletions(-)

diff --git a/target-s390x/mem_helper.c b/target-s390x/mem_helper.c
index b8d3a5f..947359b 100644
--- a/target-s390x/mem_helper.c
+++ b/target-s390x/mem_helper.c
@@ -65,30 +65,30 @@ static inline uint64_t adj_len_to_page(uint64_t len, uint64_t addr)
     return len;
 }
 
-#ifndef CONFIG_USER_ONLY
-static void mvc_fast_memset(CPUS390XState *env, uint32_t l, uint64_t dest,
-                            uint8_t byte)
+static void fast_memset(CPUS390XState *env, uint64_t dest, uint8_t byte,
+                        uint32_t l)
 {
-    S390CPU *cpu = s390_env_get_cpu(env);
-    hwaddr dest_phys;
-    hwaddr len = l;
-    void *dest_p;
-    uint64_t asc = env->psw.mask & PSW_MASK_ASC;
-    int flags;
-
-    if (mmu_translate(env, dest, 1, asc, &dest_phys, &flags, true)) {
-        cpu_stb_data(env, dest, byte);
-        cpu_abort(CPU(cpu), "should never reach here");
+    int mmu_idx = cpu_mmu_index(env);
+
+    while (l > 0) {
+        void *p = tlb_vaddr_to_host(env, dest, MMU_DATA_STORE, mmu_idx);
+        if (p) {
+            /* Access to the whole page in write mode granted.  */
+            int l_adj = adj_len_to_page(l, dest);
+            memset(p, byte, l_adj);
+            dest += l_adj;
+            l -= l_adj;
+        } else {
+            /* We failed to get access to the whole page. The next write
+               access will likely fill the QEMU TLB for the next iteration.  */
+            cpu_stb_data(env, dest, byte);
+            dest++;
+            l--;
+        }
     }
-    dest_phys |= dest & ~TARGET_PAGE_MASK;
-
-    dest_p = cpu_physical_memory_map(dest_phys, &len, 1);
-
-    memset(dest_p, byte, len);
-
-    cpu_physical_memory_unmap(dest_p, 1, len, len);
 }
 
+#ifndef CONFIG_USER_ONLY
 static void mvc_fast_memmove(CPUS390XState *env, uint32_t l, uint64_t dest,
                              uint64_t src)
 {
@@ -154,19 +154,11 @@ uint32_t HELPER(xc)(CPUS390XState *env, uint32_t l, uint64_t dest,
     HELPER_LOG("%s l %d dest %" PRIx64 " src %" PRIx64 "\n",
                __func__, l, dest, src);
 
-#ifndef CONFIG_USER_ONLY
     /* xor with itself is the same as memset(0) */
-    if ((l > 32) && (src == dest) &&
-        (src & TARGET_PAGE_MASK) == ((src + l) & TARGET_PAGE_MASK)) {
-        mvc_fast_memset(env, l + 1, dest, 0);
-        return 0;
-    }
-#else
     if (src == dest) {
-        memset(g2h(dest), 0, l + 1);
+        fast_memset(env, dest, 0, l + 1);
         return 0;
     }
-#endif
 
     for (i = 0; i <= l; i++) {
         x = cpu_ldub_data(env, dest + i) ^ cpu_ldub_data(env, src + i);
@@ -208,24 +200,23 @@ void HELPER(mvc)(CPUS390XState *env, uint32_t l, uint64_t dest, uint64_t src)
     HELPER_LOG("%s l %d dest %" PRIx64 " src %" PRIx64 "\n",
                __func__, l, dest, src);
 
+    /* mvc with source pointing to the byte after the destination is the
+       same as memset with the first source byte */
+    if (dest == (src + 1)) {
+        fast_memset(env, dest, cpu_ldub_data(env, src), l + 1);
+        return;
+    }
 #ifndef CONFIG_USER_ONLY
     if ((l > 32) &&
         (src & TARGET_PAGE_MASK) == ((src + l) & TARGET_PAGE_MASK) &&
-        (dest & TARGET_PAGE_MASK) == ((dest + l) & TARGET_PAGE_MASK)) {
-        if (dest == (src + 1)) {
-            mvc_fast_memset(env, l + 1, dest, cpu_ldub_data(env, src));
-            return;
-        } else if ((src & TARGET_PAGE_MASK) != (dest & TARGET_PAGE_MASK)) {
-            mvc_fast_memmove(env, l + 1, dest, src);
-            return;
-        }
+        (dest & TARGET_PAGE_MASK) == ((dest + l) & TARGET_PAGE_MASK) &&
+        (src & TARGET_PAGE_MASK) != (dest & TARGET_PAGE_MASK)) {
+        mvc_fast_memmove(env, l + 1, dest, src);
+        return;
     }
 #else
-    if (dest == (src + 1)) {
-        memset(g2h(dest), cpu_ldub_data(env, src), l + 1);
-        return;
     /* mvc and memmove do not behave the same when areas overlap! */
-    } else if ((dest < src) || (src + l < dest)) {
+    if ((dest < src) || (src + l < dest)) {
         memmove(g2h(dest), g2h(src), l + 1);
         return;
     }
-- 
2.1.4

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

* [Qemu-devel] [PATCH 04/15] target-s390x: mvc_fast_memmove: access memory through softmmu
  2015-06-12 22:45 [Qemu-devel] [PATCH 00/15] target-s390x: add Program-Event Recording feature Aurelien Jarno
                   ` (2 preceding siblings ...)
  2015-06-12 22:45 ` [Qemu-devel] [PATCH 03/15] target-s390x: mvc_fast_memset: access memory through softmmu Aurelien Jarno
@ 2015-06-12 22:45 ` Aurelien Jarno
  2015-06-12 22:45 ` [Qemu-devel] [PATCH 05/15] target-s390x: add PER related constants Aurelien Jarno
                   ` (11 subsequent siblings)
  15 siblings, 0 replies; 20+ messages in thread
From: Aurelien Jarno @ 2015-06-12 22:45 UTC (permalink / raw)
  To: qemu-devel; +Cc: Alexander Graf, Aurelien Jarno, Richard Henderson

mvc_fast_memmove is bypassing the softmmu functions, getting the
physical source and destination addresses using the mmu_translate
function and accessing the corresponding physical memory. This
prevents watchpoints to work correctly.

Instead use the tlb_vaddr_to_host function to get the host addresses
corresponding to the guest source and destination addresses through the
softmmu code and fallback to the byte level code in case the
corresponding address are not in the QEMU TLB or being examined through
a watchpoint. As a bonus it works even for area crossing pages by
splitting the are into chunks contained in a single page, bringing some
performances improvements. We can therefore remove the 8-byte
loads/stores method, as it is now quite unlikely to be used.

At the same time change the name of the function to fast_memmove as it's
not specific to mvc and use the same argument order as the C memmove
function.

Cc: Alexander Graf <agraf@suse.de>
Cc: Richard Henderson <rth@twiddle.net>
Signed-off-by: Aurelien Jarno <aurelien@aurel32.net>
---
 target-s390x/mem_helper.c | 84 +++++++++++++++--------------------------------
 1 file changed, 27 insertions(+), 57 deletions(-)

diff --git a/target-s390x/mem_helper.c b/target-s390x/mem_helper.c
index 947359b..6427ee9 100644
--- a/target-s390x/mem_helper.c
+++ b/target-s390x/mem_helper.c
@@ -88,40 +88,33 @@ static void fast_memset(CPUS390XState *env, uint64_t dest, uint8_t byte,
     }
 }
 
-#ifndef CONFIG_USER_ONLY
-static void mvc_fast_memmove(CPUS390XState *env, uint32_t l, uint64_t dest,
-                             uint64_t src)
+static void fast_memmove(CPUS390XState *env, uint64_t dest, uint64_t src,
+                         uint32_t l)
 {
-    S390CPU *cpu = s390_env_get_cpu(env);
-    hwaddr dest_phys;
-    hwaddr src_phys;
-    hwaddr len = l;
-    void *dest_p;
-    void *src_p;
-    uint64_t asc = env->psw.mask & PSW_MASK_ASC;
-    int flags;
-
-    if (mmu_translate(env, dest, 1, asc, &dest_phys, &flags, true)) {
-        cpu_stb_data(env, dest, 0);
-        cpu_abort(CPU(cpu), "should never reach here");
-    }
-    dest_phys |= dest & ~TARGET_PAGE_MASK;
+    int mmu_idx = cpu_mmu_index(env);
 
-    if (mmu_translate(env, src, 0, asc, &src_phys, &flags, true)) {
-        cpu_ldub_data(env, src);
-        cpu_abort(CPU(cpu), "should never reach here");
+    while (l > 0) {
+        void *src_p = tlb_vaddr_to_host(env, src, MMU_DATA_LOAD, mmu_idx);
+        void *dest_p = tlb_vaddr_to_host(env, dest, MMU_DATA_STORE, mmu_idx);
+        if (src_p && dest_p) {
+            /* Access to both whole pages granted.  */
+            int l_adj = adj_len_to_page(l, src);
+            l_adj = adj_len_to_page(l_adj, dest);
+            memmove(dest_p, src_p, l_adj);
+            src += l_adj;
+            dest += l_adj;
+            l -= l_adj;
+        } else {
+            /* We failed to get access to one or both whole pages. The next
+               read or write access will likely fill the QEMU TLB for the
+               next iteration.  */
+            cpu_stb_data(env, dest, cpu_ldub_data(env, src));
+            src++;
+            dest++;
+            l--;
+        }
     }
-    src_phys |= src & ~TARGET_PAGE_MASK;
-
-    dest_p = cpu_physical_memory_map(dest_phys, &len, 1);
-    src_p = cpu_physical_memory_map(src_phys, &len, 0);
-
-    memmove(dest_p, src_p, len);
-
-    cpu_physical_memory_unmap(dest_p, 1, len, len);
-    cpu_physical_memory_unmap(src_p, 0, len, len);
 }
-#endif
 
 /* and on array */
 uint32_t HELPER(nc)(CPUS390XState *env, uint32_t l, uint64_t dest,
@@ -194,8 +187,6 @@ uint32_t HELPER(oc)(CPUS390XState *env, uint32_t l, uint64_t dest,
 void HELPER(mvc)(CPUS390XState *env, uint32_t l, uint64_t dest, uint64_t src)
 {
     int i = 0;
-    int x = 0;
-    uint32_t l_64 = (l + 1) / 8;
 
     HELPER_LOG("%s l %d dest %" PRIx64 " src %" PRIx64 "\n",
                __func__, l, dest, src);
@@ -206,32 +197,15 @@ void HELPER(mvc)(CPUS390XState *env, uint32_t l, uint64_t dest, uint64_t src)
         fast_memset(env, dest, cpu_ldub_data(env, src), l + 1);
         return;
     }
-#ifndef CONFIG_USER_ONLY
-    if ((l > 32) &&
-        (src & TARGET_PAGE_MASK) == ((src + l) & TARGET_PAGE_MASK) &&
-        (dest & TARGET_PAGE_MASK) == ((dest + l) & TARGET_PAGE_MASK) &&
-        (src & TARGET_PAGE_MASK) != (dest & TARGET_PAGE_MASK)) {
-        mvc_fast_memmove(env, l + 1, dest, src);
-        return;
-    }
-#else
+
     /* mvc and memmove do not behave the same when areas overlap! */
     if ((dest < src) || (src + l < dest)) {
-        memmove(g2h(dest), g2h(src), l + 1);
+        fast_memmove(env, dest, src, l + 1);
         return;
     }
-#endif
-
-    /* handle the parts that fit into 8-byte loads/stores */
-    if ((dest + 8 <= src) || (src + 8 <= dest)) {
-        for (i = 0; i < l_64; i++) {
-            cpu_stq_data(env, dest + x, cpu_ldq_data(env, src + x));
-            x += 8;
-        }
-    }
 
     /* slow version with byte accesses which always work */
-    for (i = x; i <= l; i++) {
+    for (i = 0; i <= l; i++) {
         cpu_stb_data(env, dest + i, cpu_ldub_data(env, src + i));
     }
 }
@@ -398,11 +372,7 @@ void HELPER(mvpg)(CPUS390XState *env, uint64_t r0, uint64_t r1, uint64_t r2)
 {
     /* XXX missing r0 handling */
     env->cc_op = 0;
-#ifdef CONFIG_USER_ONLY
-    memmove(g2h(r1), g2h(r2), TARGET_PAGE_SIZE);
-#else
-    mvc_fast_memmove(env, TARGET_PAGE_SIZE, r1, r2);
-#endif
+    fast_memmove(env, r1, r2, TARGET_PAGE_SIZE);
 }
 
 /* string copy (c is string terminator) */
-- 
2.1.4

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

* [Qemu-devel] [PATCH 05/15] target-s390x: add PER related constants
  2015-06-12 22:45 [Qemu-devel] [PATCH 00/15] target-s390x: add Program-Event Recording feature Aurelien Jarno
                   ` (3 preceding siblings ...)
  2015-06-12 22:45 ` [Qemu-devel] [PATCH 04/15] target-s390x: mvc_fast_memmove: " Aurelien Jarno
@ 2015-06-12 22:45 ` Aurelien Jarno
  2015-06-12 22:45 ` [Qemu-devel] [PATCH 06/15] target-s390x: add get_per_atmid function Aurelien Jarno
                   ` (10 subsequent siblings)
  15 siblings, 0 replies; 20+ messages in thread
From: Aurelien Jarno @ 2015-06-12 22:45 UTC (permalink / raw)
  To: qemu-devel; +Cc: Alexander Graf, Aurelien Jarno, Richard Henderson

Cc: Alexander Graf <agraf@suse.de>
Cc: Richard Henderson <rth@twiddle.net>
Signed-off-by: Aurelien Jarno <aurelien@aurel32.net>
---
 target-s390x/cpu.h | 16 ++++++++++++++++
 1 file changed, 16 insertions(+)

diff --git a/target-s390x/cpu.h b/target-s390x/cpu.h
index 584e74b..4ff3f5c 100644
--- a/target-s390x/cpu.h
+++ b/target-s390x/cpu.h
@@ -364,6 +364,22 @@ static inline int get_ilen(uint8_t opc)
     }
 }
 
+/* PER bits from control register 9 */
+#define PER_CR9_EVENT_BRANCH           0x80000000
+#define PER_CR9_EVENT_IFETCH           0x40000000
+#define PER_CR9_EVENT_STORE            0x20000000
+#define PER_CR9_EVENT_STORE_REAL       0x08000000
+#define PER_CR9_EVENT_NULLIFICATION    0x01000000
+#define PER_CR9_CONTROL_BRANCH_ADDRESS 0x00800000
+#define PER_CR9_CONTROL_ALTERATION     0x00200000
+
+/* PER bits from the PER CODE/ATMID/AI in lowcore */
+#define PER_CODE_EVENT_BRANCH          0x8000
+#define PER_CODE_EVENT_IFETCH          0x4000
+#define PER_CODE_EVENT_STORE           0x2000
+#define PER_CODE_EVENT_STORE_REAL      0x0800
+#define PER_CODE_EVENT_NULLIFICATION   0x0100
+
 #ifndef CONFIG_USER_ONLY
 /* In several cases of runtime exceptions, we havn't recorded the true
    instruction length.  Use these codes when raising exceptions in order
-- 
2.1.4

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

* [Qemu-devel] [PATCH 06/15] target-s390x: add get_per_atmid function
  2015-06-12 22:45 [Qemu-devel] [PATCH 00/15] target-s390x: add Program-Event Recording feature Aurelien Jarno
                   ` (4 preceding siblings ...)
  2015-06-12 22:45 ` [Qemu-devel] [PATCH 05/15] target-s390x: add PER related constants Aurelien Jarno
@ 2015-06-12 22:45 ` Aurelien Jarno
  2015-06-12 22:45 ` [Qemu-devel] [PATCH 07/15] target-s390x: add get_per_in_range function Aurelien Jarno
                   ` (9 subsequent siblings)
  15 siblings, 0 replies; 20+ messages in thread
From: Aurelien Jarno @ 2015-06-12 22:45 UTC (permalink / raw)
  To: qemu-devel; +Cc: Alexander Graf, Aurelien Jarno, Richard Henderson

This function returns the ATMID field that is stored in the
per_perc_atmid lowcore entry.

Cc: Alexander Graf <agraf@suse.de>
Cc: Richard Henderson <rth@twiddle.net>
Signed-off-by: Aurelien Jarno <aurelien@aurel32.net>
---
 target-s390x/cpu.h | 12 ++++++++++++
 1 file changed, 12 insertions(+)

diff --git a/target-s390x/cpu.h b/target-s390x/cpu.h
index 4ff3f5c..86ee650 100644
--- a/target-s390x/cpu.h
+++ b/target-s390x/cpu.h
@@ -380,6 +380,18 @@ static inline int get_ilen(uint8_t opc)
 #define PER_CODE_EVENT_STORE_REAL      0x0800
 #define PER_CODE_EVENT_NULLIFICATION   0x0100
 
+/* Compute the ATMID field that is stored in the per_perc_atmid lowcore
+   entry when a PER exception is triggered.  */
+static inline uint8_t get_per_atmid(CPUS390XState *env)
+{
+    return ((env->psw.mask & PSW_MASK_64) ?      (1 << 7) : 0) |
+           (                                     (1 << 6)    ) |
+           ((env->psw.mask & PSW_MASK_32) ?      (1 << 5) : 0) |
+           ((env->psw.mask & PSW_MASK_DAT)?      (1 << 4) : 0) |
+           ((env->psw.mask & PSW_ASC_SECONDARY)? (1 << 3) : 0) |
+           ((env->psw.mask & PSW_ASC_ACCREG)?    (1 << 2) : 0);
+}
+
 #ifndef CONFIG_USER_ONLY
 /* In several cases of runtime exceptions, we havn't recorded the true
    instruction length.  Use these codes when raising exceptions in order
-- 
2.1.4

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

* [Qemu-devel] [PATCH 07/15] target-s390x: add get_per_in_range function
  2015-06-12 22:45 [Qemu-devel] [PATCH 00/15] target-s390x: add Program-Event Recording feature Aurelien Jarno
                   ` (5 preceding siblings ...)
  2015-06-12 22:45 ` [Qemu-devel] [PATCH 06/15] target-s390x: add get_per_atmid function Aurelien Jarno
@ 2015-06-12 22:45 ` Aurelien Jarno
  2015-06-12 22:45 ` [Qemu-devel] [PATCH 08/15] target-s390x: basic PER event handling Aurelien Jarno
                   ` (8 subsequent siblings)
  15 siblings, 0 replies; 20+ messages in thread
From: Aurelien Jarno @ 2015-06-12 22:45 UTC (permalink / raw)
  To: qemu-devel; +Cc: Alexander Graf, Aurelien Jarno, Richard Henderson

This function checks if an address is in between the PER starting
address and the PER ending address, taking care of a possible
address range loop.

Cc: Alexander Graf <agraf@suse.de>
Cc: Richard Henderson <rth@twiddle.net>
Signed-off-by: Aurelien Jarno <aurelien@aurel32.net>
---
 target-s390x/cpu.h | 11 +++++++++++
 1 file changed, 11 insertions(+)

diff --git a/target-s390x/cpu.h b/target-s390x/cpu.h
index 86ee650..da60eba 100644
--- a/target-s390x/cpu.h
+++ b/target-s390x/cpu.h
@@ -392,6 +392,17 @@ static inline uint8_t get_per_atmid(CPUS390XState *env)
            ((env->psw.mask & PSW_ASC_ACCREG)?    (1 << 2) : 0);
 }
 
+/* Check if an address is within the PER starting address and the PER
+   ending address.  The address range might loop.  */
+static inline bool get_per_in_range(CPUS390XState *env, uint64_t addr)
+{
+    if (env->cregs[10] <= env->cregs[11]) {
+        return env->cregs[10] <= addr && addr <= env->cregs[11];
+    } else {
+        return env->cregs[10] <= addr || addr <= env->cregs[11];
+    }
+}
+
 #ifndef CONFIG_USER_ONLY
 /* In several cases of runtime exceptions, we havn't recorded the true
    instruction length.  Use these codes when raising exceptions in order
-- 
2.1.4

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

* [Qemu-devel] [PATCH 08/15] target-s390x: basic PER event handling
  2015-06-12 22:45 [Qemu-devel] [PATCH 00/15] target-s390x: add Program-Event Recording feature Aurelien Jarno
                   ` (6 preceding siblings ...)
  2015-06-12 22:45 ` [Qemu-devel] [PATCH 07/15] target-s390x: add get_per_in_range function Aurelien Jarno
@ 2015-06-12 22:45 ` Aurelien Jarno
  2015-06-12 22:45 ` [Qemu-devel] [PATCH 09/15] target-s390x: PER successful-branching event support Aurelien Jarno
                   ` (7 subsequent siblings)
  15 siblings, 0 replies; 20+ messages in thread
From: Aurelien Jarno @ 2015-06-12 22:45 UTC (permalink / raw)
  To: qemu-devel; +Cc: Alexander Graf, Aurelien Jarno, Richard Henderson

This patch add basic support to generate PER exceptions. It adds two
fields to the cpu structure to record for the PER address and PER
code & ATMID values. When an exception is triggered and a PER event is
pending, the two PER values are copied to the lowcore area.

At the end of an instruction, an helper is checking for a possible
pending PER event and triggers an exception in that case. For that to
work with branches, we need to disable TB chaining when PER is
activated. Fortunately it's already in the TB flags.

Finally in case of a SERVICE CALL exception, we need to trigger the PER
exception immediately after.

Cc: Alexander Graf <agraf@suse.de>
Cc: Richard Henderson <rth@twiddle.net>
Signed-off-by: Aurelien Jarno <aurelien@aurel32.net>
---
 target-s390x/cpu.h         |  3 +++
 target-s390x/helper.c      | 54 ++++++++++++++++++++++++++++++----------------
 target-s390x/helper.h      |  1 +
 target-s390x/misc_helper.c | 15 +++++++++++++
 target-s390x/translate.c   | 18 +++++++++++++++-
 5 files changed, 71 insertions(+), 20 deletions(-)

diff --git a/target-s390x/cpu.h b/target-s390x/cpu.h
index da60eba..19646b9 100644
--- a/target-s390x/cpu.h
+++ b/target-s390x/cpu.h
@@ -111,6 +111,9 @@ typedef struct CPUS390XState {
     uint32_t int_svc_code;
     uint32_t int_svc_ilen;
 
+    uint64_t per_address;
+    uint16_t per_perc_atmid;
+
     uint64_t cregs[16]; /* control registers */
 
     ExtQueue ext_queue[MAX_EXT_QUEUE];
diff --git a/target-s390x/helper.c b/target-s390x/helper.c
index 90d273c..ec847a2 100644
--- a/target-s390x/helper.c
+++ b/target-s390x/helper.c
@@ -250,25 +250,6 @@ void do_restart_interrupt(CPUS390XState *env)
     load_psw(env, mask, addr);
 }
 
-static void do_svc_interrupt(CPUS390XState *env)
-{
-    uint64_t mask, addr;
-    LowCore *lowcore;
-
-    lowcore = cpu_map_lowcore(env);
-
-    lowcore->svc_code = cpu_to_be16(env->int_svc_code);
-    lowcore->svc_ilen = cpu_to_be16(env->int_svc_ilen);
-    lowcore->svc_old_psw.mask = cpu_to_be64(get_psw_mask(env));
-    lowcore->svc_old_psw.addr = cpu_to_be64(env->psw.addr + env->int_svc_ilen);
-    mask = be64_to_cpu(lowcore->svc_new_psw.mask);
-    addr = be64_to_cpu(lowcore->svc_new_psw.addr);
-
-    cpu_unmap_lowcore(lowcore);
-
-    load_psw(env, mask, addr);
-}
-
 static void do_program_interrupt(CPUS390XState *env)
 {
     uint64_t mask, addr;
@@ -292,6 +273,14 @@ static void do_program_interrupt(CPUS390XState *env)
 
     lowcore = cpu_map_lowcore(env);
 
+    /* Signal PER events with the exception.  */
+    if (env->per_perc_atmid) {
+        env->int_pgm_code |= PGM_PER;
+        lowcore->per_address = cpu_to_be64(env->per_address);
+        lowcore->per_perc_atmid = cpu_to_be16(env->per_perc_atmid);
+        env->per_perc_atmid = 0;
+    }
+
     lowcore->pgm_ilen = cpu_to_be16(ilen);
     lowcore->pgm_code = cpu_to_be16(env->int_pgm_code);
     lowcore->program_old_psw.mask = cpu_to_be64(get_psw_mask(env));
@@ -308,6 +297,33 @@ static void do_program_interrupt(CPUS390XState *env)
     load_psw(env, mask, addr);
 }
 
+static void do_svc_interrupt(CPUS390XState *env)
+{
+    uint64_t mask, addr;
+    LowCore *lowcore;
+
+    lowcore = cpu_map_lowcore(env);
+
+    lowcore->svc_code = cpu_to_be16(env->int_svc_code);
+    lowcore->svc_ilen = cpu_to_be16(env->int_svc_ilen);
+    lowcore->svc_old_psw.mask = cpu_to_be64(get_psw_mask(env));
+    lowcore->svc_old_psw.addr = cpu_to_be64(env->psw.addr + env->int_svc_ilen);
+    mask = be64_to_cpu(lowcore->svc_new_psw.mask);
+    addr = be64_to_cpu(lowcore->svc_new_psw.addr);
+
+    cpu_unmap_lowcore(lowcore);
+
+    load_psw(env, mask, addr);
+
+    /* When a PER event is pending, the PER exception has to happen
+       immediately after the SERVICE CALL one.  */
+    if (env->per_perc_atmid) {
+        env->int_pgm_code = PGM_PER;
+        env->int_pgm_ilen = env->int_svc_ilen;
+        do_program_interrupt(env);
+    }
+}
+
 #define VIRTIO_SUBCODE_64 0x0D00
 
 static void do_ext_interrupt(CPUS390XState *env)
diff --git a/target-s390x/helper.h b/target-s390x/helper.h
index 7e048ec..37bd4d7 100644
--- a/target-s390x/helper.h
+++ b/target-s390x/helper.h
@@ -116,4 +116,5 @@ DEF_HELPER_FLAGS_2(lura, TCG_CALL_NO_WG, i64, env, i64)
 DEF_HELPER_FLAGS_2(lurag, TCG_CALL_NO_WG, i64, env, i64)
 DEF_HELPER_FLAGS_3(stura, TCG_CALL_NO_WG, void, env, i64, i64)
 DEF_HELPER_FLAGS_3(sturg, TCG_CALL_NO_WG, void, env, i64, i64)
+DEF_HELPER_1(per_check_exception, void, env)
 #endif
diff --git a/target-s390x/misc_helper.c b/target-s390x/misc_helper.c
index b375ab7..d19ae91 100644
--- a/target-s390x/misc_helper.c
+++ b/target-s390x/misc_helper.c
@@ -494,3 +494,18 @@ uint32_t HELPER(sigp)(CPUS390XState *env, uint64_t order_code, uint32_t r1,
     return cc;
 }
 #endif
+
+#ifndef CONFIG_USER_ONLY
+void HELPER(per_check_exception)(CPUS390XState *env)
+{
+    CPUState *cs = CPU(s390_env_get_cpu(env));
+
+    if (env->per_perc_atmid) {
+        env->int_pgm_code = PGM_PER;
+        env->int_pgm_ilen = get_ilen(cpu_ldub_code(env, env->per_address));
+
+        cs->exception_index = EXCP_PGM;
+        cpu_loop_exit(cs);
+    }
+}
+#endif
diff --git a/target-s390x/translate.c b/target-s390x/translate.c
index 9b87714..ff2c4bb 100644
--- a/target-s390x/translate.c
+++ b/target-s390x/translate.c
@@ -568,7 +568,8 @@ static int use_goto_tb(DisasContext *s, uint64_t dest)
     return (((dest & TARGET_PAGE_MASK) == (s->tb->pc & TARGET_PAGE_MASK)
              || (dest & TARGET_PAGE_MASK) == ((s->pc - 1) & TARGET_PAGE_MASK))
             && !s->singlestep_enabled
-            && !(s->tb->cflags & CF_LAST_IO));
+            && !(s->tb->cflags & CF_LAST_IO)
+            && !(s->tb->flags & FLAG_MASK_PER));
 }
 
 static void account_noninline_branch(DisasContext *s, int cc_op)
@@ -5138,6 +5139,21 @@ static ExitStatus translate_one(CPUS390XState *env, DisasContext *s)
         tcg_temp_free_i64(o.addr1);
     }
 
+#ifndef CONFIG_USER_ONLY
+    if (s->tb->flags & FLAG_MASK_PER) {
+        /* An exception might be triggered, save PSW if not already done.  */
+        if (ret == NO_EXIT || ret == EXIT_PC_STALE) {
+            tcg_gen_movi_i64(psw_addr, s->next_pc);
+        }
+
+        /* Save off cc.  */
+        update_cc_op(s);
+
+        /* Call the helper to check for a possible PER exception.  */
+        gen_helper_per_check_exception(cpu_env);
+    }
+#endif
+
     /* Advance to the next instruction.  */
     s->pc = s->next_pc;
     return ret;
-- 
2.1.4

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

* [Qemu-devel] [PATCH 09/15] target-s390x: PER successful-branching event support
  2015-06-12 22:45 [Qemu-devel] [PATCH 00/15] target-s390x: add Program-Event Recording feature Aurelien Jarno
                   ` (7 preceding siblings ...)
  2015-06-12 22:45 ` [Qemu-devel] [PATCH 08/15] target-s390x: basic PER event handling Aurelien Jarno
@ 2015-06-12 22:45 ` Aurelien Jarno
  2015-06-12 22:45 ` [Qemu-devel] [PATCH 10/15] target-s390x: PER instruction-fetch " Aurelien Jarno
                   ` (6 subsequent siblings)
  15 siblings, 0 replies; 20+ messages in thread
From: Aurelien Jarno @ 2015-06-12 22:45 UTC (permalink / raw)
  To: qemu-devel; +Cc: Alexander Graf, Aurelien Jarno, Richard Henderson

For the PER successful-branching event support, we can't rely on any
QEMU infrastucture. We therefore call an helper in all places where
a branch can be taken. We have to pay attention to the branch to next
case, as it's still a taken branch.

We don't need to care about the cases using goto_tb, as we have disabled
them in the previous patch.

Cc: Alexander Graf <agraf@suse.de>
Cc: Richard Henderson <rth@twiddle.net>
Signed-off-by: Aurelien Jarno <aurelien@aurel32.net>
---
 target-s390x/helper.h      |  1 +
 target-s390x/misc_helper.c | 11 +++++++++++
 target-s390x/translate.c   | 39 +++++++++++++++++++++++++++++++++++++++
 3 files changed, 51 insertions(+)

diff --git a/target-s390x/helper.h b/target-s390x/helper.h
index 37bd4d7..8d89cff 100644
--- a/target-s390x/helper.h
+++ b/target-s390x/helper.h
@@ -117,4 +117,5 @@ DEF_HELPER_FLAGS_2(lurag, TCG_CALL_NO_WG, i64, env, i64)
 DEF_HELPER_FLAGS_3(stura, TCG_CALL_NO_WG, void, env, i64, i64)
 DEF_HELPER_FLAGS_3(sturg, TCG_CALL_NO_WG, void, env, i64, i64)
 DEF_HELPER_1(per_check_exception, void, env)
+DEF_HELPER_FLAGS_3(per_branch, TCG_CALL_NO_RWG, void, env, i64, i64)
 #endif
diff --git a/target-s390x/misc_helper.c b/target-s390x/misc_helper.c
index d19ae91..8972929 100644
--- a/target-s390x/misc_helper.c
+++ b/target-s390x/misc_helper.c
@@ -508,4 +508,15 @@ void HELPER(per_check_exception)(CPUS390XState *env)
         cpu_loop_exit(cs);
     }
 }
+
+void HELPER(per_branch)(CPUS390XState *env, uint64_t from, uint64_t to)
+{
+    if ((env->cregs[9] & PER_CR9_EVENT_BRANCH)) {
+        if (!(env->cregs[9] & PER_CR9_CONTROL_BRANCH_ADDRESS)
+            || get_per_in_range(env, to)) {
+            env->per_address = from;
+            env->per_perc_atmid = PER_CODE_EVENT_BRANCH | get_per_atmid(env);
+        }
+    }
+}
 #endif
diff --git a/target-s390x/translate.c b/target-s390x/translate.c
index ff2c4bb..897486c 100644
--- a/target-s390x/translate.c
+++ b/target-s390x/translate.c
@@ -249,6 +249,38 @@ static void update_psw_addr(DisasContext *s)
     tcg_gen_movi_i64(psw_addr, s->pc);
 }
 
+static void per_branch(DisasContext *s, bool to_next)
+{
+#ifndef CONFIG_USER_ONLY
+    if (s->tb->flags & FLAG_MASK_PER) {
+        TCGv_i64 pc = tcg_const_i64(s->pc);
+        TCGv_i64 next_pc = to_next ? tcg_const_i64(s->next_pc) : psw_addr;
+        gen_helper_per_branch(cpu_env, pc, next_pc);
+        if (to_next) {
+            tcg_temp_free_i64(next_pc);
+        }
+        tcg_temp_free_i64(pc);
+    }
+#endif
+}
+
+static void per_branch_cond(DisasContext *s, TCGCond cond,
+                            TCGv_i64 arg1, TCGv_i64 arg2)
+{
+#ifndef CONFIG_USER_ONLY
+    if (s->tb->flags & FLAG_MASK_PER) {
+        TCGLabel *lab = gen_new_label();
+        tcg_gen_brcond_i64(tcg_invert_cond(cond), arg1, arg2, lab);
+
+        TCGv_i64 pc = tcg_const_i64(s->pc);
+        gen_helper_per_branch(cpu_env, pc, psw_addr);
+        tcg_temp_free_i64(pc);
+
+        gen_set_label(lab);
+    }
+#endif
+}
+
 static void update_cc_op(DisasContext *s)
 {
     if (s->cc_op != CC_OP_DYNAMIC && s->cc_op != CC_OP_STATIC) {
@@ -1182,6 +1214,7 @@ static void help_l2_shift(DisasContext *s, DisasFields *f,
 static ExitStatus help_goto_direct(DisasContext *s, uint64_t dest)
 {
     if (dest == s->next_pc) {
+        per_branch(s, true);
         return NO_EXIT;
     }
     if (use_goto_tb(s, dest)) {
@@ -1192,6 +1225,7 @@ static ExitStatus help_goto_direct(DisasContext *s, uint64_t dest)
         return EXIT_GOTO_TB;
     } else {
         tcg_gen_movi_i64(psw_addr, dest);
+        per_branch(s, false);
         return EXIT_PC_UPDATED;
     }
 }
@@ -1211,6 +1245,7 @@ static ExitStatus help_branch(DisasContext *s, DisasCompare *c,
     if (is_imm) {
         if (dest == s->next_pc) {
             /* Branch to next.  */
+            per_branch(s, true);
             ret = NO_EXIT;
             goto egress;
         }
@@ -1226,6 +1261,7 @@ static ExitStatus help_branch(DisasContext *s, DisasCompare *c,
         }
         if (c->cond == TCG_COND_ALWAYS) {
             tcg_gen_mov_i64(psw_addr, cdest);
+            per_branch(s, false);
             ret = EXIT_PC_UPDATED;
             goto egress;
         }
@@ -1296,6 +1332,7 @@ static ExitStatus help_branch(DisasContext *s, DisasCompare *c,
         if (c->is_64) {
             tcg_gen_movcond_i64(c->cond, psw_addr, c->u.s64.a, c->u.s64.b,
                                 cdest, next);
+            per_branch_cond(s, c->cond, c->u.s64.a, c->u.s64.b);
         } else {
             TCGv_i32 t0 = tcg_temp_new_i32();
             TCGv_i64 t1 = tcg_temp_new_i64();
@@ -1304,6 +1341,7 @@ static ExitStatus help_branch(DisasContext *s, DisasCompare *c,
             tcg_gen_extu_i32_i64(t1, t0);
             tcg_temp_free_i32(t0);
             tcg_gen_movcond_i64(TCG_COND_NE, psw_addr, t1, z, cdest, next);
+            per_branch_cond(s, TCG_COND_NE, t1, z);
             tcg_temp_free_i64(t1);
             tcg_temp_free_i64(z);
         }
@@ -1436,6 +1474,7 @@ static ExitStatus op_bas(DisasContext *s, DisasOps *o)
     tcg_gen_movi_i64(o->out, pc_to_link_info(s, s->next_pc));
     if (!TCGV_IS_UNUSED_I64(o->in2)) {
         tcg_gen_mov_i64(psw_addr, o->in2);
+        per_branch(s, false);
         return EXIT_PC_UPDATED;
     } else {
         return NO_EXIT;
-- 
2.1.4

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

* [Qemu-devel] [PATCH 10/15] target-s390x: PER instruction-fetch event support
  2015-06-12 22:45 [Qemu-devel] [PATCH 00/15] target-s390x: add Program-Event Recording feature Aurelien Jarno
                   ` (8 preceding siblings ...)
  2015-06-12 22:45 ` [Qemu-devel] [PATCH 09/15] target-s390x: PER successful-branching event support Aurelien Jarno
@ 2015-06-12 22:45 ` Aurelien Jarno
  2015-06-12 22:45 ` [Qemu-devel] [PATCH 11/15] translate-all: fix watchpoints if retranslation not possible Aurelien Jarno
                   ` (5 subsequent siblings)
  15 siblings, 0 replies; 20+ messages in thread
From: Aurelien Jarno @ 2015-06-12 22:45 UTC (permalink / raw)
  To: qemu-devel; +Cc: Alexander Graf, Aurelien Jarno, Richard Henderson

For the PER instruction-fetch, we can't use the QEMU breakpoint
infrastructure as it triggers for a single address and not a full
address range, and as it actually stop before the instruction and
not before.

We therefore call an helper with the just fetched instruction address,
which check if the address is within the PER address range. If it is
the case, an event is recorded and will be signaled through an
exception.

Note that we implement here the PER-3 behaviour, that is an invalid
opcode is not considered as an instruction fetch. Without PER-3 this
behavious is undefined.

Cc: Alexander Graf <agraf@suse.de>
Cc: Richard Henderson <rth@twiddle.net>
Signed-off-by: Aurelien Jarno <aurelien@aurel32.net>
---
 target-s390x/helper.h      | 1 +
 target-s390x/misc_helper.c | 8 ++++++++
 target-s390x/translate.c   | 8 ++++++++
 3 files changed, 17 insertions(+)

diff --git a/target-s390x/helper.h b/target-s390x/helper.h
index 8d89cff..f789cdf 100644
--- a/target-s390x/helper.h
+++ b/target-s390x/helper.h
@@ -118,4 +118,5 @@ DEF_HELPER_FLAGS_3(stura, TCG_CALL_NO_WG, void, env, i64, i64)
 DEF_HELPER_FLAGS_3(sturg, TCG_CALL_NO_WG, void, env, i64, i64)
 DEF_HELPER_1(per_check_exception, void, env)
 DEF_HELPER_FLAGS_3(per_branch, TCG_CALL_NO_RWG, void, env, i64, i64)
+DEF_HELPER_FLAGS_2(per_ifetch, TCG_CALL_NO_RWG, void, env, i64)
 #endif
diff --git a/target-s390x/misc_helper.c b/target-s390x/misc_helper.c
index 8972929..ca3aabe 100644
--- a/target-s390x/misc_helper.c
+++ b/target-s390x/misc_helper.c
@@ -519,4 +519,12 @@ void HELPER(per_branch)(CPUS390XState *env, uint64_t from, uint64_t to)
         }
     }
 }
+
+void HELPER(per_ifetch)(CPUS390XState *env, uint64_t addr)
+{
+    if ((env->cregs[9] & PER_CR9_EVENT_IFETCH) && get_per_in_range(env, addr)) {
+        env->per_address = addr;
+        env->per_perc_atmid = PER_CODE_EVENT_IFETCH | get_per_atmid(env);
+    }
+}
 #endif
diff --git a/target-s390x/translate.c b/target-s390x/translate.c
index 897486c..98e8224 100644
--- a/target-s390x/translate.c
+++ b/target-s390x/translate.c
@@ -5091,6 +5091,14 @@ static ExitStatus translate_one(CPUS390XState *env, DisasContext *s)
         return EXIT_NORETURN;
     }
 
+#ifndef CONFIG_USER_ONLY
+    if (s->tb->flags & FLAG_MASK_PER) {
+        TCGv_i64 addr = tcg_const_i64(s->pc);
+        gen_helper_per_ifetch(cpu_env, addr);
+        tcg_temp_free_i64(addr);
+    }
+#endif
+
     /* Check for insn specification exceptions.  */
     if (insn->spec) {
         int spec = insn->spec, excp = 0, r;
-- 
2.1.4

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

* [Qemu-devel] [PATCH 11/15] translate-all: fix watchpoints if retranslation not possible
  2015-06-12 22:45 [Qemu-devel] [PATCH 00/15] target-s390x: add Program-Event Recording feature Aurelien Jarno
                   ` (9 preceding siblings ...)
  2015-06-12 22:45 ` [Qemu-devel] [PATCH 10/15] target-s390x: PER instruction-fetch " Aurelien Jarno
@ 2015-06-12 22:45 ` Aurelien Jarno
  2015-06-12 22:46 ` [Qemu-devel] [PATCH 12/15] target-s390x: PER storage-alteration event support Aurelien Jarno
                   ` (4 subsequent siblings)
  15 siblings, 0 replies; 20+ messages in thread
From: Aurelien Jarno @ 2015-06-12 22:45 UTC (permalink / raw)
  To: qemu-devel; +Cc: Alexander Graf, Aurelien Jarno, Richard Henderson

The tb_check_watchpoint function currently assumes that all memory
access is done either directly through the TCG code or through an
helper which knows its return address. This is obviously wrong as the
helpers use cpu_ldxx/stxx_data functions to access the memory.

Instead of aborting in that case, don't try to retranslate the code, but
assume that the CPU state (and especially the program counter) has been
saved before calling the helper. Then invalidate the TB based on this
address.

Signed-off-by: Aurelien Jarno <aurelien@aurel32.net>
---
 translate-all.c | 20 +++++++++++++++-----
 1 file changed, 15 insertions(+), 5 deletions(-)

diff --git a/translate-all.c b/translate-all.c
index e2e7422..b6b0e1c 100644
--- a/translate-all.c
+++ b/translate-all.c
@@ -1431,12 +1431,22 @@ void tb_check_watchpoint(CPUState *cpu)
     TranslationBlock *tb;
 
     tb = tb_find_pc(cpu->mem_io_pc);
-    if (!tb) {
-        cpu_abort(cpu, "check_watchpoint: could not find TB for pc=%p",
-                  (void *)cpu->mem_io_pc);
+    if (tb) {
+        /* We can use retranslation to find the PC.  */
+        cpu_restore_state_from_tb(cpu, tb, cpu->mem_io_pc);
+        tb_phys_invalidate(tb, -1);
+    } else {
+        /* The exception probably happened in a helper.  The CPU state should
+           have been saved before calling it. Fetch the PC from there.  */
+        CPUArchState *env = cpu->env_ptr;
+        target_ulong pc, cs_base;
+        tb_page_addr_t addr;
+        int flags;
+
+        cpu_get_tb_cpu_state(env, &pc, &cs_base, &flags);
+        addr = get_page_addr_code(env, pc);
+        tb_invalidate_phys_range(addr, addr + 1);
     }
-    cpu_restore_state_from_tb(cpu, tb, cpu->mem_io_pc);
-    tb_phys_invalidate(tb, -1);
 }
 
 #ifndef CONFIG_USER_ONLY
-- 
2.1.4

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

* [Qemu-devel] [PATCH 12/15] target-s390x: PER storage-alteration event support
  2015-06-12 22:45 [Qemu-devel] [PATCH 00/15] target-s390x: add Program-Event Recording feature Aurelien Jarno
                   ` (10 preceding siblings ...)
  2015-06-12 22:45 ` [Qemu-devel] [PATCH 11/15] translate-all: fix watchpoints if retranslation not possible Aurelien Jarno
@ 2015-06-12 22:46 ` Aurelien Jarno
  2015-06-12 22:46 ` [Qemu-devel] [PATCH 13/15] target-s390x: PER store-using-real-address " Aurelien Jarno
                   ` (3 subsequent siblings)
  15 siblings, 0 replies; 20+ messages in thread
From: Aurelien Jarno @ 2015-06-12 22:46 UTC (permalink / raw)
  To: qemu-devel; +Cc: Alexander Graf, Aurelien Jarno, Richard Henderson

For the PER storage-alteration event we can use the QEMU watchpoint
infrastructure. When PER is enabled or PER control register changed we
enable the corresponding watchpoints. When a watchpoint arises we can
save the event. Unfortunately the current code does not provide the
address space used to trigger the watchpoint. For now we assume it comes
from the default ASC.

Cc: Alexander Graf <agraf@suse.de>
Cc: Richard Henderson <rth@twiddle.net>
Signed-off-by: Aurelien Jarno <aurelien@aurel32.net>
---
 target-s390x/cpu-qom.h    |  1 +
 target-s390x/cpu.c        |  1 +
 target-s390x/cpu.h        |  1 +
 target-s390x/helper.c     | 75 +++++++++++++++++++++++++++++++++++++++++++++++
 target-s390x/mem_helper.c | 25 ++++++++++++++--
 5 files changed, 100 insertions(+), 3 deletions(-)

diff --git a/target-s390x/cpu-qom.h b/target-s390x/cpu-qom.h
index 936ae21..491c1b8 100644
--- a/target-s390x/cpu-qom.h
+++ b/target-s390x/cpu-qom.h
@@ -98,5 +98,6 @@ hwaddr s390_cpu_get_phys_addr_debug(CPUState *cpu, vaddr addr);
 int s390_cpu_gdb_read_register(CPUState *cpu, uint8_t *buf, int reg);
 int s390_cpu_gdb_write_register(CPUState *cpu, uint8_t *buf, int reg);
 void s390_cpu_gdb_init(CPUState *cs);
+void s390x_cpu_debug_excp_handler(CPUState *cs);
 
 #endif
diff --git a/target-s390x/cpu.c b/target-s390x/cpu.c
index 7f17823..67579e7 100644
--- a/target-s390x/cpu.c
+++ b/target-s390x/cpu.c
@@ -333,6 +333,7 @@ static void s390_cpu_class_init(ObjectClass *oc, void *data)
     cc->write_elf64_note = s390_cpu_write_elf64_note;
     cc->write_elf64_qemunote = s390_cpu_write_elf64_qemunote;
     cc->cpu_exec_interrupt = s390_cpu_exec_interrupt;
+    cc->debug_excp_handler = s390x_cpu_debug_excp_handler;
 #endif
     cc->gdb_num_core_regs = S390_NUM_CORE_REGS;
     cc->gdb_core_xml_file = "s390x-core64.xml";
diff --git a/target-s390x/cpu.h b/target-s390x/cpu.h
index 19646b9..61cc5b4 100644
--- a/target-s390x/cpu.h
+++ b/target-s390x/cpu.h
@@ -1044,6 +1044,7 @@ int mmu_translate(CPUS390XState *env, target_ulong vaddr, int rw, uint64_t asc,
 int sclp_service_call(CPUS390XState *env, uint64_t sccb, uint32_t code);
 uint32_t calc_cc(CPUS390XState *env, uint32_t cc_op, uint64_t src, uint64_t dst,
                  uint64_t vr);
+void s390_cpu_recompute_watchpoints(CPUState *cs);
 
 int s390_cpu_virt_mem_rw(S390CPU *cpu, vaddr laddr, uint8_t ar, void *hostbuf,
                          int len, bool is_write);
diff --git a/target-s390x/helper.c b/target-s390x/helper.c
index ec847a2..615cccf 100644
--- a/target-s390x/helper.c
+++ b/target-s390x/helper.c
@@ -181,12 +181,18 @@ hwaddr s390_cpu_get_phys_addr_debug(CPUState *cs, vaddr vaddr)
 
 void load_psw(CPUS390XState *env, uint64_t mask, uint64_t addr)
 {
+    uint64_t old_mask = env->psw.mask;
+
     env->psw.addr = addr;
     env->psw.mask = mask;
     if (tcg_enabled()) {
         env->cc_op = (mask >> 44) & 3;
     }
 
+    if ((old_mask ^ mask) & PSW_MASK_PER) {
+        s390_cpu_recompute_watchpoints(CPU(s390_env_get_cpu(env)));
+    }
+
     if (mask & PSW_MASK_WAIT) {
         S390CPU *cpu = s390_env_get_cpu(env);
         if (s390_cpu_halt(cpu) == 0) {
@@ -573,4 +579,73 @@ bool s390_cpu_exec_interrupt(CPUState *cs, int interrupt_request)
     }
     return false;
 }
+
+void s390_cpu_recompute_watchpoints(CPUState *cs)
+{
+    const int wp_flags = BP_CPU | BP_MEM_WRITE | BP_STOP_BEFORE_ACCESS;
+    S390CPU *cpu = S390_CPU(cs);
+    CPUS390XState *env = &cpu->env;
+
+    /* We are called when the watchpoints have changed. First
+       remove them all.  */
+    cpu_watchpoint_remove_all(cs, BP_CPU);
+
+    /* Return if PER is not enabled */
+    if (!(env->psw.mask & PSW_MASK_PER)) {
+        return;
+    }
+
+    /* Return if storage-alteration event is not enabled.  */
+    if (!(env->cregs[9] & PER_CR9_EVENT_STORE)) {
+        return;
+    }
+
+    if (env->cregs[10] == 0 && env->cregs[11] == -1LL) {
+        /* We can't create a watchoint spanning the whole memory range, so
+           split it in two parts.   */
+        cpu_watchpoint_insert(cs, 0, 1ULL << 63, wp_flags, NULL);
+        cpu_watchpoint_insert(cs, 1ULL << 63, 1ULL << 63, wp_flags, NULL);
+    } else if (env->cregs[10] > env->cregs[11]) {
+        /* The address range loops, create two watchpoints.  */
+        cpu_watchpoint_insert(cs, env->cregs[10], -env->cregs[10],
+                              wp_flags, NULL);
+        cpu_watchpoint_insert(cs, 0, env->cregs[11] + 1, wp_flags, NULL);
+
+    } else {
+        /* Default case, create a single watchpoint.  */
+        cpu_watchpoint_insert(cs, env->cregs[10],
+                              env->cregs[11] - env->cregs[10] + 1,
+                              wp_flags, NULL);
+    }
+}
+
+void s390x_cpu_debug_excp_handler(CPUState *cs)
+{
+    S390CPU *cpu = S390_CPU(cs);
+    CPUS390XState *env = &cpu->env;
+    CPUWatchpoint *wp_hit = cs->watchpoint_hit;
+
+    if (wp_hit && wp_hit->flags & BP_CPU) {
+        /* FIXME: When the storage-alteration-space control bit is set,
+           the exception should only be triggered if the memory access
+           is done using an address space with the storage-alteration-event
+           bit set.  We have no way to detect that with the current
+           watchpoint code.  */
+        cs->watchpoint_hit = NULL;
+
+        env->per_address = env->psw.addr;
+        env->per_perc_atmid |= PER_CODE_EVENT_STORE | get_per_atmid(env);
+        /* FIXME: We currently no way to detect the address space used
+           to trigger the watchpoint.  For now just consider it is the
+           current default ASC. This turn to be true except when MVCP
+           and MVCS instrutions are not used.  */
+        env->per_perc_atmid |= env->psw.mask & (PSW_MASK_ASC) >> 46;
+
+        /* Remove all watchpoints to re-execute the code.  A PER exception
+           will be triggered, it will call load_psw which will recompute
+           the watchpoints.  */
+        cpu_watchpoint_remove_all(cs, BP_CPU);
+        cpu_resume_from_signal(cs, NULL);
+    }
+}
 #endif /* CONFIG_USER_ONLY */
diff --git a/target-s390x/mem_helper.c b/target-s390x/mem_helper.c
index 6427ee9..d03f9fd 100644
--- a/target-s390x/mem_helper.c
+++ b/target-s390x/mem_helper.c
@@ -841,11 +841,17 @@ uint32_t HELPER(trt)(CPUS390XState *env, uint32_t len, uint64_t array,
 void HELPER(lctlg)(CPUS390XState *env, uint32_t r1, uint64_t a2, uint32_t r3)
 {
     S390CPU *cpu = s390_env_get_cpu(env);
+    bool PERchanged = false;
     int i;
     uint64_t src = a2;
+    uint64_t val;
 
     for (i = r1;; i = (i + 1) % 16) {
-        env->cregs[i] = cpu_ldq_data(env, src);
+        val = cpu_ldq_data(env, src);
+        if (env->cregs[i] != val && i >= 9 && i <= 11) {
+            PERchanged = true;
+        }
+        env->cregs[i] = val;
         HELPER_LOG("load ctl %d from 0x%" PRIx64 " == 0x%" PRIx64 "\n",
                    i, src, env->cregs[i]);
         src += sizeof(uint64_t);
@@ -855,18 +861,27 @@ void HELPER(lctlg)(CPUS390XState *env, uint32_t r1, uint64_t a2, uint32_t r3)
         }
     }
 
+    if (PERchanged && env->psw.mask & PSW_MASK_PER) {
+        s390_cpu_recompute_watchpoints(CPU(cpu));
+    }
+
     tlb_flush(CPU(cpu), 1);
 }
 
 void HELPER(lctl)(CPUS390XState *env, uint32_t r1, uint64_t a2, uint32_t r3)
 {
     S390CPU *cpu = s390_env_get_cpu(env);
+    bool PERchanged = false;
     int i;
     uint64_t src = a2;
+    uint32_t val;
 
     for (i = r1;; i = (i + 1) % 16) {
-        env->cregs[i] = (env->cregs[i] & 0xFFFFFFFF00000000ULL) |
-            cpu_ldl_data(env, src);
+        val = cpu_ldl_data(env, src);
+        if ((uint32_t)env->cregs[i] != val && i >= 9 && i <= 11) {
+            PERchanged = true;
+        }
+        env->cregs[i] = (env->cregs[i] & 0xFFFFFFFF00000000ULL) | val;
         src += sizeof(uint32_t);
 
         if (i == r3) {
@@ -874,6 +889,10 @@ void HELPER(lctl)(CPUS390XState *env, uint32_t r1, uint64_t a2, uint32_t r3)
         }
     }
 
+    if (PERchanged && env->psw.mask & PSW_MASK_PER) {
+        s390_cpu_recompute_watchpoints(CPU(cpu));
+    }
+
     tlb_flush(CPU(cpu), 1);
 }
 
-- 
2.1.4

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

* [Qemu-devel] [PATCH 13/15] target-s390x: PER store-using-real-address event support
  2015-06-12 22:45 [Qemu-devel] [PATCH 00/15] target-s390x: add Program-Event Recording feature Aurelien Jarno
                   ` (11 preceding siblings ...)
  2015-06-12 22:46 ` [Qemu-devel] [PATCH 12/15] target-s390x: PER storage-alteration event support Aurelien Jarno
@ 2015-06-12 22:46 ` Aurelien Jarno
  2015-06-12 22:46 ` [Qemu-devel] [PATCH 14/15] target-s390x: PER instruction-fetch nullification " Aurelien Jarno
                   ` (2 subsequent siblings)
  15 siblings, 0 replies; 20+ messages in thread
From: Aurelien Jarno @ 2015-06-12 22:46 UTC (permalink / raw)
  To: qemu-devel; +Cc: Alexander Graf, Aurelien Jarno, Richard Henderson

This PER event happens each time the STURA or STURG instructions are
used. As they use helpers, we can just save the event in the PER code
there, if enabled.

Cc: Richard Henderson <rth@twiddle.net>
Cc: Alexander Graf <agraf@suse.de>
Signed-off-by: Aurelien Jarno <aurelien@aurel32.net>
---
 target-s390x/mem_helper.c | 16 ++++++++++++++++
 1 file changed, 16 insertions(+)

diff --git a/target-s390x/mem_helper.c b/target-s390x/mem_helper.c
index d03f9fd..3ccbeb9 100644
--- a/target-s390x/mem_helper.c
+++ b/target-s390x/mem_helper.c
@@ -1105,6 +1105,14 @@ void HELPER(stura)(CPUS390XState *env, uint64_t addr, uint64_t v1)
     CPUState *cs = CPU(s390_env_get_cpu(env));
 
     stl_phys(cs->as, get_address(env, 0, 0, addr), (uint32_t)v1);
+
+    if ((env->psw.mask & PSW_MASK_PER) &&
+        (env->cregs[9] & PER_CR9_EVENT_STORE) &&
+        (env->cregs[9] & PER_CR9_EVENT_STORE_REAL)) {
+        /* PSW is saved just before calling the helper.  */
+        env->per_address = env->psw.addr;
+        env->per_perc_atmid = PER_CODE_EVENT_STORE_REAL | get_per_atmid(env);
+    }
 }
 
 void HELPER(sturg)(CPUS390XState *env, uint64_t addr, uint64_t v1)
@@ -1112,6 +1120,14 @@ void HELPER(sturg)(CPUS390XState *env, uint64_t addr, uint64_t v1)
     CPUState *cs = CPU(s390_env_get_cpu(env));
 
     stq_phys(cs->as, get_address(env, 0, 0, addr), v1);
+
+    if ((env->psw.mask & PSW_MASK_PER) &&
+        (env->cregs[9] & PER_CR9_EVENT_STORE) &&
+        (env->cregs[9] & PER_CR9_EVENT_STORE_REAL)) {
+        /* PSW is saved just before calling the helper.  */
+        env->per_address = env->psw.addr;
+        env->per_perc_atmid = PER_CODE_EVENT_STORE_REAL | get_per_atmid(env);
+    }
 }
 
 /* load real address */
-- 
2.1.4

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

* [Qemu-devel] [PATCH 14/15] target-s390x: PER instruction-fetch nullification event support
  2015-06-12 22:45 [Qemu-devel] [PATCH 00/15] target-s390x: add Program-Event Recording feature Aurelien Jarno
                   ` (12 preceding siblings ...)
  2015-06-12 22:46 ` [Qemu-devel] [PATCH 13/15] target-s390x: PER store-using-real-address " Aurelien Jarno
@ 2015-06-12 22:46 ` Aurelien Jarno
  2015-06-12 22:46 ` [Qemu-devel] [PATCH 15/15] target-s390x: PER: add Breaking-Event-Address register Aurelien Jarno
  2015-06-16 17:55 ` [Qemu-devel] [PATCH 00/15] target-s390x: add Program-Event Recording feature Alexander Graf
  15 siblings, 0 replies; 20+ messages in thread
From: Aurelien Jarno @ 2015-06-12 22:46 UTC (permalink / raw)
  To: qemu-devel; +Cc: Alexander Graf, Aurelien Jarno, Richard Henderson

For the instruction-fetch nullification event, we just reuse the
existing instruction-fetch code and trigger the exception immediately
in that case.

There is no need to save the CPU state in the TCG code as it has been
saved by the previous instruction before calling the per_check_exception
helper.

Cc: Alexander Graf <agraf@suse.de>
Cc: Richard Henderson <rth@twiddle.net>
Signed-off-by: Aurelien Jarno <aurelien@aurel32.net>
---
 target-s390x/misc_helper.c | 12 ++++++++++++
 1 file changed, 12 insertions(+)

diff --git a/target-s390x/misc_helper.c b/target-s390x/misc_helper.c
index ca3aabe..241f82e 100644
--- a/target-s390x/misc_helper.c
+++ b/target-s390x/misc_helper.c
@@ -525,6 +525,18 @@ void HELPER(per_ifetch)(CPUS390XState *env, uint64_t addr)
     if ((env->cregs[9] & PER_CR9_EVENT_IFETCH) && get_per_in_range(env, addr)) {
         env->per_address = addr;
         env->per_perc_atmid = PER_CODE_EVENT_IFETCH | get_per_atmid(env);
+
+        /* If the instruction has to be nullified, trigger the
+           exception immediately. */
+        if (env->cregs[9] & PER_CR9_EVENT_NULLIFICATION) {
+            CPUState *cs = CPU(s390_env_get_cpu(env));
+
+            env->int_pgm_code = PGM_PER;
+            env->int_pgm_ilen = get_ilen(cpu_ldub_code(env, addr));
+
+            cs->exception_index = EXCP_PGM;
+            cpu_loop_exit(cs);
+        }
     }
 }
 #endif
-- 
2.1.4

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

* [Qemu-devel] [PATCH 15/15] target-s390x: PER: add Breaking-Event-Address register
  2015-06-12 22:45 [Qemu-devel] [PATCH 00/15] target-s390x: add Program-Event Recording feature Aurelien Jarno
                   ` (13 preceding siblings ...)
  2015-06-12 22:46 ` [Qemu-devel] [PATCH 14/15] target-s390x: PER instruction-fetch nullification " Aurelien Jarno
@ 2015-06-12 22:46 ` Aurelien Jarno
  2015-06-16 16:44   ` Alexander Graf
  2015-06-16 17:55 ` [Qemu-devel] [PATCH 00/15] target-s390x: add Program-Event Recording feature Alexander Graf
  15 siblings, 1 reply; 20+ messages in thread
From: Aurelien Jarno @ 2015-06-12 22:46 UTC (permalink / raw)
  To: qemu-devel; +Cc: Alexander Graf, Aurelien Jarno, Richard Henderson

This patch adds support for PER Breaking-Event-Address register. Like
real hardware, it save the current PSW address when the PSW address is
changed by an instruction. We have to take care of optimizations QEMU
does, a branch to the next instruction is still a branch.

This register is copied to low core memory when a program exception
happens.

Cc: Richard Henderson <rth@twiddle.net>
Cc: Alexander Graf <agraf@suse.de>
Signed-off-by: Aurelien Jarno <aurelien@aurel32.net>
---
 target-s390x/cpu.c       |  6 ++++++
 target-s390x/cpu.h       | 12 +++++++-----
 target-s390x/helper.c    |  1 +
 target-s390x/translate.c | 29 +++++++++++++++++++++++------
 4 files changed, 37 insertions(+), 11 deletions(-)

diff --git a/target-s390x/cpu.c b/target-s390x/cpu.c
index 67579e7..98d2081 100644
--- a/target-s390x/cpu.c
+++ b/target-s390x/cpu.c
@@ -116,6 +116,9 @@ static void s390_cpu_initial_reset(CPUState *s)
     env->cregs[0] = CR0_RESET;
     env->cregs[14] = CR14_RESET;
 
+    /* architectured initial value for Breaking-Event-Address register */
+    env->gbea = 1;
+
     env->pfault_token = -1UL;
 
     /* tininess for underflow is detected before rounding */
@@ -145,6 +148,9 @@ static void s390_cpu_full_reset(CPUState *s)
     env->cregs[0] = CR0_RESET;
     env->cregs[14] = CR14_RESET;
 
+    /* architectured initial value for Breaking-Event-Address register */
+    env->gbea = 1;
+
     env->pfault_token = -1UL;
 
     /* tininess for underflow is detected before rounding */
diff --git a/target-s390x/cpu.h b/target-s390x/cpu.h
index 61cc5b4..519cef9 100644
--- a/target-s390x/cpu.h
+++ b/target-s390x/cpu.h
@@ -788,14 +788,16 @@ typedef struct LowCore
     uint8_t         pad5[0xf4-0xf0];          /* 0x0f0 */
     uint32_t        external_damage_code;     /* 0x0f4 */
     uint64_t        failing_storage_address;  /* 0x0f8 */
-    uint8_t         pad6[0x120-0x100];        /* 0x100 */
+    uint8_t         pad6[0x110-0x100];        /* 0x100 */
+    uint64_t        per_breaking_event_addr;  /* 0x110 */
+    uint8_t         pad7[0x120-0x118];        /* 0x118 */
     PSW             restart_old_psw;          /* 0x120 */
     PSW             external_old_psw;         /* 0x130 */
     PSW             svc_old_psw;              /* 0x140 */
     PSW             program_old_psw;          /* 0x150 */
     PSW             mcck_old_psw;             /* 0x160 */
     PSW             io_old_psw;               /* 0x170 */
-    uint8_t         pad7[0x1a0-0x180];        /* 0x180 */
+    uint8_t         pad8[0x1a0-0x180];        /* 0x180 */
     PSW             restart_new_psw;          /* 0x1a0 */
     PSW             external_new_psw;         /* 0x1b0 */
     PSW             svc_new_psw;              /* 0x1c0 */
@@ -813,10 +815,10 @@ typedef struct LowCore
     uint64_t        last_update_clock;        /* 0x280 */
     uint64_t        steal_clock;              /* 0x288 */
     PSW             return_mcck_psw;          /* 0x290 */
-    uint8_t         pad8[0xc00-0x2a0];        /* 0x2a0 */
+    uint8_t         pad9[0xc00-0x2a0];        /* 0x2a0 */
     /* System info area */
     uint64_t        save_area[16];            /* 0xc00 */
-    uint8_t         pad9[0xd40-0xc80];        /* 0xc80 */
+    uint8_t         pad10[0xd40-0xc80];       /* 0xc80 */
     uint64_t        kernel_stack;             /* 0xd40 */
     uint64_t        thread_info;              /* 0xd48 */
     uint64_t        async_stack;              /* 0xd50 */
@@ -824,7 +826,7 @@ typedef struct LowCore
     uint64_t        user_asce;                /* 0xd60 */
     uint64_t        panic_stack;              /* 0xd68 */
     uint64_t        user_exec_asce;           /* 0xd70 */
-    uint8_t         pad10[0xdc0-0xd78];       /* 0xd78 */
+    uint8_t         pad11[0xdc0-0xd78];       /* 0xd78 */
 
     /* SMP info area: defined by DJB */
     uint64_t        clock_comparator;         /* 0xdc0 */
diff --git a/target-s390x/helper.c b/target-s390x/helper.c
index 615cccf..d887006 100644
--- a/target-s390x/helper.c
+++ b/target-s390x/helper.c
@@ -293,6 +293,7 @@ static void do_program_interrupt(CPUS390XState *env)
     lowcore->program_old_psw.addr = cpu_to_be64(env->psw.addr);
     mask = be64_to_cpu(lowcore->program_new_psw.mask);
     addr = be64_to_cpu(lowcore->program_new_psw.addr);
+    lowcore->per_breaking_event_addr = cpu_to_be64(env->gbea);
 
     cpu_unmap_lowcore(lowcore);
 
diff --git a/target-s390x/translate.c b/target-s390x/translate.c
index 98e8224..2fde815 100644
--- a/target-s390x/translate.c
+++ b/target-s390x/translate.c
@@ -150,6 +150,7 @@ void s390_cpu_dump_state(CPUState *cs, FILE *f, fprintf_function cpu_fprintf,
 
 static TCGv_i64 psw_addr;
 static TCGv_i64 psw_mask;
+static TCGv_i64 gbea;
 
 static TCGv_i32 cc_op;
 static TCGv_i64 cc_src;
@@ -173,6 +174,9 @@ void s390x_translate_init(void)
     psw_mask = tcg_global_mem_new_i64(TCG_AREG0,
                                       offsetof(CPUS390XState, psw.mask),
                                       "psw_mask");
+    gbea = tcg_global_mem_new_i64(TCG_AREG0,
+                                  offsetof(CPUS390XState, gbea),
+                                  "gbea");
 
     cc_op = tcg_global_mem_new_i32(TCG_AREG0, offsetof(CPUS390XState, cc_op),
                                    "cc_op");
@@ -252,14 +256,14 @@ static void update_psw_addr(DisasContext *s)
 static void per_branch(DisasContext *s, bool to_next)
 {
 #ifndef CONFIG_USER_ONLY
+    tcg_gen_movi_i64(gbea, s->pc);
+
     if (s->tb->flags & FLAG_MASK_PER) {
-        TCGv_i64 pc = tcg_const_i64(s->pc);
         TCGv_i64 next_pc = to_next ? tcg_const_i64(s->next_pc) : psw_addr;
-        gen_helper_per_branch(cpu_env, pc, next_pc);
+        gen_helper_per_branch(cpu_env, gbea, next_pc);
         if (to_next) {
             tcg_temp_free_i64(next_pc);
         }
-        tcg_temp_free_i64(pc);
     }
 #endif
 }
@@ -272,15 +276,23 @@ static void per_branch_cond(DisasContext *s, TCGCond cond,
         TCGLabel *lab = gen_new_label();
         tcg_gen_brcond_i64(tcg_invert_cond(cond), arg1, arg2, lab);
 
-        TCGv_i64 pc = tcg_const_i64(s->pc);
-        gen_helper_per_branch(cpu_env, pc, psw_addr);
-        tcg_temp_free_i64(pc);
+        tcg_gen_movi_i64(gbea, s->pc);
+        gen_helper_per_branch(cpu_env, gbea, psw_addr);
 
         gen_set_label(lab);
+    } else {
+        TCGv_i64 pc = tcg_const_i64(s->pc);
+        tcg_gen_movcond_i64(cond, gbea, arg1, arg2, gbea, pc);
+        tcg_temp_free_i64(pc);
     }
 #endif
 }
 
+static void per_breaking_event(DisasContext *s)
+{
+    tcg_gen_movi_i64(gbea, s->pc);
+}
+
 static void update_cc_op(DisasContext *s)
 {
     if (s->cc_op != CC_OP_DYNAMIC && s->cc_op != CC_OP_STATIC) {
@@ -1219,6 +1231,7 @@ static ExitStatus help_goto_direct(DisasContext *s, uint64_t dest)
     }
     if (use_goto_tb(s, dest)) {
         update_cc_op(s);
+        per_breaking_event(s);
         tcg_gen_goto_tb(0);
         tcg_gen_movi_i64(psw_addr, dest);
         tcg_gen_exit_tb((uintptr_t)s->tb);
@@ -1286,6 +1299,7 @@ static ExitStatus help_branch(DisasContext *s, DisasCompare *c,
 
             /* Branch taken.  */
             gen_set_label(lab);
+            per_breaking_event(s);
             tcg_gen_goto_tb(1);
             tcg_gen_movi_i64(psw_addr, dest);
             tcg_gen_exit_tb((uintptr_t)s->tb + 1);
@@ -1317,6 +1331,7 @@ static ExitStatus help_branch(DisasContext *s, DisasCompare *c,
             if (is_imm) {
                 tcg_gen_movi_i64(psw_addr, dest);
             }
+            per_breaking_event(s);
             ret = EXIT_PC_UPDATED;
         }
     } else {
@@ -2545,6 +2560,7 @@ static ExitStatus op_lpsw(DisasContext *s, DisasOps *o)
     TCGv_i64 t1, t2;
 
     check_privileged(s);
+    per_breaking_event(s);
 
     t1 = tcg_temp_new_i64();
     t2 = tcg_temp_new_i64();
@@ -2564,6 +2580,7 @@ static ExitStatus op_lpswe(DisasContext *s, DisasOps *o)
     TCGv_i64 t1, t2;
 
     check_privileged(s);
+    per_breaking_event(s);
 
     t1 = tcg_temp_new_i64();
     t2 = tcg_temp_new_i64();
-- 
2.1.4

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

* Re: [Qemu-devel] [PATCH 15/15] target-s390x: PER: add Breaking-Event-Address register
  2015-06-12 22:46 ` [Qemu-devel] [PATCH 15/15] target-s390x: PER: add Breaking-Event-Address register Aurelien Jarno
@ 2015-06-16 16:44   ` Alexander Graf
  2015-06-16 17:44     ` Aurelien Jarno
  0 siblings, 1 reply; 20+ messages in thread
From: Alexander Graf @ 2015-06-16 16:44 UTC (permalink / raw)
  To: Aurelien Jarno, qemu-devel; +Cc: Richard Henderson

On 06/13/15 00:46, Aurelien Jarno wrote:
> This patch adds support for PER Breaking-Event-Address register. Like
> real hardware, it save the current PSW address when the PSW address is
> changed by an instruction. We have to take care of optimizations QEMU
> does, a branch to the next instruction is still a branch.
>
> This register is copied to low core memory when a program exception
> happens.
>
> Cc: Richard Henderson <rth@twiddle.net>
> Cc: Alexander Graf <agraf@suse.de>
> Signed-off-by: Aurelien Jarno <aurelien@aurel32.net>
> ---
>   target-s390x/cpu.c       |  6 ++++++
>   target-s390x/cpu.h       | 12 +++++++-----
>   target-s390x/helper.c    |  1 +
>   target-s390x/translate.c | 29 +++++++++++++++++++++++------
>   4 files changed, 37 insertions(+), 11 deletions(-)
>
> diff --git a/target-s390x/cpu.c b/target-s390x/cpu.c
> index 67579e7..98d2081 100644
> --- a/target-s390x/cpu.c
> +++ b/target-s390x/cpu.c
> @@ -116,6 +116,9 @@ static void s390_cpu_initial_reset(CPUState *s)
>       env->cregs[0] = CR0_RESET;
>       env->cregs[14] = CR14_RESET;
>   
> +    /* architectured initial value for Breaking-Event-Address register */
> +    env->gbea = 1;
> +
>       env->pfault_token = -1UL;
>   
>       /* tininess for underflow is detected before rounding */
> @@ -145,6 +148,9 @@ static void s390_cpu_full_reset(CPUState *s)
>       env->cregs[0] = CR0_RESET;
>       env->cregs[14] = CR14_RESET;
>   
> +    /* architectured initial value for Breaking-Event-Address register */
> +    env->gbea = 1;
> +
>       env->pfault_token = -1UL;
>   
>       /* tininess for underflow is detected before rounding */
> diff --git a/target-s390x/cpu.h b/target-s390x/cpu.h
> index 61cc5b4..519cef9 100644
> --- a/target-s390x/cpu.h
> +++ b/target-s390x/cpu.h
> @@ -788,14 +788,16 @@ typedef struct LowCore
>       uint8_t         pad5[0xf4-0xf0];          /* 0x0f0 */
>       uint32_t        external_damage_code;     /* 0x0f4 */
>       uint64_t        failing_storage_address;  /* 0x0f8 */
> -    uint8_t         pad6[0x120-0x100];        /* 0x100 */
> +    uint8_t         pad6[0x110-0x100];        /* 0x100 */
> +    uint64_t        per_breaking_event_addr;  /* 0x110 */
> +    uint8_t         pad7[0x120-0x118];        /* 0x118 */
>       PSW             restart_old_psw;          /* 0x120 */
>       PSW             external_old_psw;         /* 0x130 */
>       PSW             svc_old_psw;              /* 0x140 */
>       PSW             program_old_psw;          /* 0x150 */
>       PSW             mcck_old_psw;             /* 0x160 */
>       PSW             io_old_psw;               /* 0x170 */
> -    uint8_t         pad7[0x1a0-0x180];        /* 0x180 */
> +    uint8_t         pad8[0x1a0-0x180];        /* 0x180 */
>       PSW             restart_new_psw;          /* 0x1a0 */
>       PSW             external_new_psw;         /* 0x1b0 */
>       PSW             svc_new_psw;              /* 0x1c0 */
> @@ -813,10 +815,10 @@ typedef struct LowCore
>       uint64_t        last_update_clock;        /* 0x280 */
>       uint64_t        steal_clock;              /* 0x288 */
>       PSW             return_mcck_psw;          /* 0x290 */
> -    uint8_t         pad8[0xc00-0x2a0];        /* 0x2a0 */
> +    uint8_t         pad9[0xc00-0x2a0];        /* 0x2a0 */
>       /* System info area */
>       uint64_t        save_area[16];            /* 0xc00 */
> -    uint8_t         pad9[0xd40-0xc80];        /* 0xc80 */
> +    uint8_t         pad10[0xd40-0xc80];       /* 0xc80 */
>       uint64_t        kernel_stack;             /* 0xd40 */
>       uint64_t        thread_info;              /* 0xd48 */
>       uint64_t        async_stack;              /* 0xd50 */
> @@ -824,7 +826,7 @@ typedef struct LowCore
>       uint64_t        user_asce;                /* 0xd60 */
>       uint64_t        panic_stack;              /* 0xd68 */
>       uint64_t        user_exec_asce;           /* 0xd70 */
> -    uint8_t         pad10[0xdc0-0xd78];       /* 0xd78 */
> +    uint8_t         pad11[0xdc0-0xd78];       /* 0xd78 */
>   
>       /* SMP info area: defined by DJB */
>       uint64_t        clock_comparator;         /* 0xdc0 */
> diff --git a/target-s390x/helper.c b/target-s390x/helper.c
> index 615cccf..d887006 100644
> --- a/target-s390x/helper.c
> +++ b/target-s390x/helper.c
> @@ -293,6 +293,7 @@ static void do_program_interrupt(CPUS390XState *env)
>       lowcore->program_old_psw.addr = cpu_to_be64(env->psw.addr);
>       mask = be64_to_cpu(lowcore->program_new_psw.mask);
>       addr = be64_to_cpu(lowcore->program_new_psw.addr);
> +    lowcore->per_breaking_event_addr = cpu_to_be64(env->gbea);
>   
>       cpu_unmap_lowcore(lowcore);
>   
> diff --git a/target-s390x/translate.c b/target-s390x/translate.c
> index 98e8224..2fde815 100644
> --- a/target-s390x/translate.c
> +++ b/target-s390x/translate.c
> @@ -150,6 +150,7 @@ void s390_cpu_dump_state(CPUState *cs, FILE *f, fprintf_function cpu_fprintf,
>   
>   static TCGv_i64 psw_addr;
>   static TCGv_i64 psw_mask;
> +static TCGv_i64 gbea;
>   
>   static TCGv_i32 cc_op;
>   static TCGv_i64 cc_src;
> @@ -173,6 +174,9 @@ void s390x_translate_init(void)
>       psw_mask = tcg_global_mem_new_i64(TCG_AREG0,
>                                         offsetof(CPUS390XState, psw.mask),
>                                         "psw_mask");
> +    gbea = tcg_global_mem_new_i64(TCG_AREG0,
> +                                  offsetof(CPUS390XState, gbea),
> +                                  "gbea");
>   
>       cc_op = tcg_global_mem_new_i32(TCG_AREG0, offsetof(CPUS390XState, cc_op),
>                                      "cc_op");
> @@ -252,14 +256,14 @@ static void update_psw_addr(DisasContext *s)
>   static void per_branch(DisasContext *s, bool to_next)
>   {
>   #ifndef CONFIG_USER_ONLY
> +    tcg_gen_movi_i64(gbea, s->pc);

This should probably be a call to per_breaking_event(), no?

Also, is there no flag to control this register? I'd assume it to be 
quite some performance penalty to always store the last branched register.


Alex

> +
>       if (s->tb->flags & FLAG_MASK_PER) {
> -        TCGv_i64 pc = tcg_const_i64(s->pc);
>           TCGv_i64 next_pc = to_next ? tcg_const_i64(s->next_pc) : psw_addr;
> -        gen_helper_per_branch(cpu_env, pc, next_pc);
> +        gen_helper_per_branch(cpu_env, gbea, next_pc);
>           if (to_next) {
>               tcg_temp_free_i64(next_pc);
>           }
> -        tcg_temp_free_i64(pc);
>       }
>   #endif
>   }
> @@ -272,15 +276,23 @@ static void per_branch_cond(DisasContext *s, TCGCond cond,
>           TCGLabel *lab = gen_new_label();
>           tcg_gen_brcond_i64(tcg_invert_cond(cond), arg1, arg2, lab);
>   
> -        TCGv_i64 pc = tcg_const_i64(s->pc);
> -        gen_helper_per_branch(cpu_env, pc, psw_addr);
> -        tcg_temp_free_i64(pc);
> +        tcg_gen_movi_i64(gbea, s->pc);
> +        gen_helper_per_branch(cpu_env, gbea, psw_addr);
>   
>           gen_set_label(lab);
> +    } else {
> +        TCGv_i64 pc = tcg_const_i64(s->pc);
> +        tcg_gen_movcond_i64(cond, gbea, arg1, arg2, gbea, pc);
> +        tcg_temp_free_i64(pc);
>       }
>   #endif
>   }
>   
> +static void per_breaking_event(DisasContext *s)
> +{
> +    tcg_gen_movi_i64(gbea, s->pc);
> +}
> +
>   static void update_cc_op(DisasContext *s)
>   {
>       if (s->cc_op != CC_OP_DYNAMIC && s->cc_op != CC_OP_STATIC) {
> @@ -1219,6 +1231,7 @@ static ExitStatus help_goto_direct(DisasContext *s, uint64_t dest)
>       }
>       if (use_goto_tb(s, dest)) {
>           update_cc_op(s);
> +        per_breaking_event(s);
>           tcg_gen_goto_tb(0);
>           tcg_gen_movi_i64(psw_addr, dest);
>           tcg_gen_exit_tb((uintptr_t)s->tb);
> @@ -1286,6 +1299,7 @@ static ExitStatus help_branch(DisasContext *s, DisasCompare *c,
>   
>               /* Branch taken.  */
>               gen_set_label(lab);
> +            per_breaking_event(s);
>               tcg_gen_goto_tb(1);
>               tcg_gen_movi_i64(psw_addr, dest);
>               tcg_gen_exit_tb((uintptr_t)s->tb + 1);
> @@ -1317,6 +1331,7 @@ static ExitStatus help_branch(DisasContext *s, DisasCompare *c,
>               if (is_imm) {
>                   tcg_gen_movi_i64(psw_addr, dest);
>               }
> +            per_breaking_event(s);
>               ret = EXIT_PC_UPDATED;
>           }
>       } else {
> @@ -2545,6 +2560,7 @@ static ExitStatus op_lpsw(DisasContext *s, DisasOps *o)
>       TCGv_i64 t1, t2;
>   
>       check_privileged(s);
> +    per_breaking_event(s);
>   
>       t1 = tcg_temp_new_i64();
>       t2 = tcg_temp_new_i64();
> @@ -2564,6 +2580,7 @@ static ExitStatus op_lpswe(DisasContext *s, DisasOps *o)
>       TCGv_i64 t1, t2;
>   
>       check_privileged(s);
> +    per_breaking_event(s);
>   
>       t1 = tcg_temp_new_i64();
>       t2 = tcg_temp_new_i64();

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

* Re: [Qemu-devel] [PATCH 15/15] target-s390x: PER: add Breaking-Event-Address register
  2015-06-16 16:44   ` Alexander Graf
@ 2015-06-16 17:44     ` Aurelien Jarno
  2015-06-16 17:50       ` Alexander Graf
  0 siblings, 1 reply; 20+ messages in thread
From: Aurelien Jarno @ 2015-06-16 17:44 UTC (permalink / raw)
  To: Alexander Graf; +Cc: qemu-devel, Richard Henderson

On 2015-06-16 18:44, Alexander Graf wrote:
> On 06/13/15 00:46, Aurelien Jarno wrote:
> >This patch adds support for PER Breaking-Event-Address register. Like
> >real hardware, it save the current PSW address when the PSW address is
> >changed by an instruction. We have to take care of optimizations QEMU
> >does, a branch to the next instruction is still a branch.
> >
> >This register is copied to low core memory when a program exception
> >happens.
> >
> >Cc: Richard Henderson <rth@twiddle.net>
> >Cc: Alexander Graf <agraf@suse.de>
> >Signed-off-by: Aurelien Jarno <aurelien@aurel32.net>
> >---
> >  target-s390x/cpu.c       |  6 ++++++
> >  target-s390x/cpu.h       | 12 +++++++-----
> >  target-s390x/helper.c    |  1 +
> >  target-s390x/translate.c | 29 +++++++++++++++++++++++------
> >  4 files changed, 37 insertions(+), 11 deletions(-)
> >
> >diff --git a/target-s390x/cpu.c b/target-s390x/cpu.c
> >index 67579e7..98d2081 100644
> >--- a/target-s390x/cpu.c
> >+++ b/target-s390x/cpu.c
> >@@ -116,6 +116,9 @@ static void s390_cpu_initial_reset(CPUState *s)
> >      env->cregs[0] = CR0_RESET;
> >      env->cregs[14] = CR14_RESET;
> >+    /* architectured initial value for Breaking-Event-Address register */
> >+    env->gbea = 1;
> >+
> >      env->pfault_token = -1UL;
> >      /* tininess for underflow is detected before rounding */
> >@@ -145,6 +148,9 @@ static void s390_cpu_full_reset(CPUState *s)
> >      env->cregs[0] = CR0_RESET;
> >      env->cregs[14] = CR14_RESET;
> >+    /* architectured initial value for Breaking-Event-Address register */
> >+    env->gbea = 1;
> >+
> >      env->pfault_token = -1UL;
> >      /* tininess for underflow is detected before rounding */
> >diff --git a/target-s390x/cpu.h b/target-s390x/cpu.h
> >index 61cc5b4..519cef9 100644
> >--- a/target-s390x/cpu.h
> >+++ b/target-s390x/cpu.h
> >@@ -788,14 +788,16 @@ typedef struct LowCore
> >      uint8_t         pad5[0xf4-0xf0];          /* 0x0f0 */
> >      uint32_t        external_damage_code;     /* 0x0f4 */
> >      uint64_t        failing_storage_address;  /* 0x0f8 */
> >-    uint8_t         pad6[0x120-0x100];        /* 0x100 */
> >+    uint8_t         pad6[0x110-0x100];        /* 0x100 */
> >+    uint64_t        per_breaking_event_addr;  /* 0x110 */
> >+    uint8_t         pad7[0x120-0x118];        /* 0x118 */
> >      PSW             restart_old_psw;          /* 0x120 */
> >      PSW             external_old_psw;         /* 0x130 */
> >      PSW             svc_old_psw;              /* 0x140 */
> >      PSW             program_old_psw;          /* 0x150 */
> >      PSW             mcck_old_psw;             /* 0x160 */
> >      PSW             io_old_psw;               /* 0x170 */
> >-    uint8_t         pad7[0x1a0-0x180];        /* 0x180 */
> >+    uint8_t         pad8[0x1a0-0x180];        /* 0x180 */
> >      PSW             restart_new_psw;          /* 0x1a0 */
> >      PSW             external_new_psw;         /* 0x1b0 */
> >      PSW             svc_new_psw;              /* 0x1c0 */
> >@@ -813,10 +815,10 @@ typedef struct LowCore
> >      uint64_t        last_update_clock;        /* 0x280 */
> >      uint64_t        steal_clock;              /* 0x288 */
> >      PSW             return_mcck_psw;          /* 0x290 */
> >-    uint8_t         pad8[0xc00-0x2a0];        /* 0x2a0 */
> >+    uint8_t         pad9[0xc00-0x2a0];        /* 0x2a0 */
> >      /* System info area */
> >      uint64_t        save_area[16];            /* 0xc00 */
> >-    uint8_t         pad9[0xd40-0xc80];        /* 0xc80 */
> >+    uint8_t         pad10[0xd40-0xc80];       /* 0xc80 */
> >      uint64_t        kernel_stack;             /* 0xd40 */
> >      uint64_t        thread_info;              /* 0xd48 */
> >      uint64_t        async_stack;              /* 0xd50 */
> >@@ -824,7 +826,7 @@ typedef struct LowCore
> >      uint64_t        user_asce;                /* 0xd60 */
> >      uint64_t        panic_stack;              /* 0xd68 */
> >      uint64_t        user_exec_asce;           /* 0xd70 */
> >-    uint8_t         pad10[0xdc0-0xd78];       /* 0xd78 */
> >+    uint8_t         pad11[0xdc0-0xd78];       /* 0xd78 */
> >      /* SMP info area: defined by DJB */
> >      uint64_t        clock_comparator;         /* 0xdc0 */
> >diff --git a/target-s390x/helper.c b/target-s390x/helper.c
> >index 615cccf..d887006 100644
> >--- a/target-s390x/helper.c
> >+++ b/target-s390x/helper.c
> >@@ -293,6 +293,7 @@ static void do_program_interrupt(CPUS390XState *env)
> >      lowcore->program_old_psw.addr = cpu_to_be64(env->psw.addr);
> >      mask = be64_to_cpu(lowcore->program_new_psw.mask);
> >      addr = be64_to_cpu(lowcore->program_new_psw.addr);
> >+    lowcore->per_breaking_event_addr = cpu_to_be64(env->gbea);
> >      cpu_unmap_lowcore(lowcore);
> >diff --git a/target-s390x/translate.c b/target-s390x/translate.c
> >index 98e8224..2fde815 100644
> >--- a/target-s390x/translate.c
> >+++ b/target-s390x/translate.c
> >@@ -150,6 +150,7 @@ void s390_cpu_dump_state(CPUState *cs, FILE *f, fprintf_function cpu_fprintf,
> >  static TCGv_i64 psw_addr;
> >  static TCGv_i64 psw_mask;
> >+static TCGv_i64 gbea;
> >  static TCGv_i32 cc_op;
> >  static TCGv_i64 cc_src;
> >@@ -173,6 +174,9 @@ void s390x_translate_init(void)
> >      psw_mask = tcg_global_mem_new_i64(TCG_AREG0,
> >                                        offsetof(CPUS390XState, psw.mask),
> >                                        "psw_mask");
> >+    gbea = tcg_global_mem_new_i64(TCG_AREG0,
> >+                                  offsetof(CPUS390XState, gbea),
> >+                                  "gbea");
> >      cc_op = tcg_global_mem_new_i32(TCG_AREG0, offsetof(CPUS390XState, cc_op),
> >                                     "cc_op");
> >@@ -252,14 +256,14 @@ static void update_psw_addr(DisasContext *s)
> >  static void per_branch(DisasContext *s, bool to_next)
> >  {
> >  #ifndef CONFIG_USER_ONLY
> >+    tcg_gen_movi_i64(gbea, s->pc);
> 
> This should probably be a call to per_breaking_event(), no?

Yes, that's possible, but given gbea is reused below instead of
reloading s->pc, I preferred to make the move more explicit.

That said given I have to send a rebased version, I can easily change
that.

> Also, is there no flag to control this register? I'd assume it to be quite
> some performance penalty to always store the last branched register.

No this register is always loaded. This is the value you see in dmesg
when a user program crashes, but you can also get it via GDB. Quite
useful in some cases.

I haven't measured any performance impact, only noise. We are talking
about writing an immediate to a memory location in the env structure
(thus very likely with a cache line already allocated), so it's only
two host instructions more in a TB. That's not a lot given that for
example every TB starts by loading a value from the env structure and
doing a test on it.

Aurelien

-- 
Aurelien Jarno                          GPG: 4096R/1DDD8C9B
aurelien@aurel32.net                 http://www.aurel32.net

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

* Re: [Qemu-devel] [PATCH 15/15] target-s390x: PER: add Breaking-Event-Address register
  2015-06-16 17:44     ` Aurelien Jarno
@ 2015-06-16 17:50       ` Alexander Graf
  0 siblings, 0 replies; 20+ messages in thread
From: Alexander Graf @ 2015-06-16 17:50 UTC (permalink / raw)
  To: Aurelien Jarno; +Cc: qemu-devel, Richard Henderson



On 16.06.15 19:44, Aurelien Jarno wrote:
> On 2015-06-16 18:44, Alexander Graf wrote:
>> On 06/13/15 00:46, Aurelien Jarno wrote:
>>> This patch adds support for PER Breaking-Event-Address register. Like
>>> real hardware, it save the current PSW address when the PSW address is
>>> changed by an instruction. We have to take care of optimizations QEMU
>>> does, a branch to the next instruction is still a branch.
>>>
>>> This register is copied to low core memory when a program exception
>>> happens.
>>>
>>> Cc: Richard Henderson <rth@twiddle.net>
>>> Cc: Alexander Graf <agraf@suse.de>
>>> Signed-off-by: Aurelien Jarno <aurelien@aurel32.net>
>>> ---
>>>  target-s390x/cpu.c       |  6 ++++++
>>>  target-s390x/cpu.h       | 12 +++++++-----
>>>  target-s390x/helper.c    |  1 +
>>>  target-s390x/translate.c | 29 +++++++++++++++++++++++------
>>>  4 files changed, 37 insertions(+), 11 deletions(-)
>>>
>>> diff --git a/target-s390x/cpu.c b/target-s390x/cpu.c
>>> index 67579e7..98d2081 100644
>>> --- a/target-s390x/cpu.c
>>> +++ b/target-s390x/cpu.c
>>> @@ -116,6 +116,9 @@ static void s390_cpu_initial_reset(CPUState *s)
>>>      env->cregs[0] = CR0_RESET;
>>>      env->cregs[14] = CR14_RESET;
>>> +    /* architectured initial value for Breaking-Event-Address register */
>>> +    env->gbea = 1;
>>> +
>>>      env->pfault_token = -1UL;
>>>      /* tininess for underflow is detected before rounding */
>>> @@ -145,6 +148,9 @@ static void s390_cpu_full_reset(CPUState *s)
>>>      env->cregs[0] = CR0_RESET;
>>>      env->cregs[14] = CR14_RESET;
>>> +    /* architectured initial value for Breaking-Event-Address register */
>>> +    env->gbea = 1;
>>> +
>>>      env->pfault_token = -1UL;
>>>      /* tininess for underflow is detected before rounding */
>>> diff --git a/target-s390x/cpu.h b/target-s390x/cpu.h
>>> index 61cc5b4..519cef9 100644
>>> --- a/target-s390x/cpu.h
>>> +++ b/target-s390x/cpu.h
>>> @@ -788,14 +788,16 @@ typedef struct LowCore
>>>      uint8_t         pad5[0xf4-0xf0];          /* 0x0f0 */
>>>      uint32_t        external_damage_code;     /* 0x0f4 */
>>>      uint64_t        failing_storage_address;  /* 0x0f8 */
>>> -    uint8_t         pad6[0x120-0x100];        /* 0x100 */
>>> +    uint8_t         pad6[0x110-0x100];        /* 0x100 */
>>> +    uint64_t        per_breaking_event_addr;  /* 0x110 */
>>> +    uint8_t         pad7[0x120-0x118];        /* 0x118 */
>>>      PSW             restart_old_psw;          /* 0x120 */
>>>      PSW             external_old_psw;         /* 0x130 */
>>>      PSW             svc_old_psw;              /* 0x140 */
>>>      PSW             program_old_psw;          /* 0x150 */
>>>      PSW             mcck_old_psw;             /* 0x160 */
>>>      PSW             io_old_psw;               /* 0x170 */
>>> -    uint8_t         pad7[0x1a0-0x180];        /* 0x180 */
>>> +    uint8_t         pad8[0x1a0-0x180];        /* 0x180 */
>>>      PSW             restart_new_psw;          /* 0x1a0 */
>>>      PSW             external_new_psw;         /* 0x1b0 */
>>>      PSW             svc_new_psw;              /* 0x1c0 */
>>> @@ -813,10 +815,10 @@ typedef struct LowCore
>>>      uint64_t        last_update_clock;        /* 0x280 */
>>>      uint64_t        steal_clock;              /* 0x288 */
>>>      PSW             return_mcck_psw;          /* 0x290 */
>>> -    uint8_t         pad8[0xc00-0x2a0];        /* 0x2a0 */
>>> +    uint8_t         pad9[0xc00-0x2a0];        /* 0x2a0 */
>>>      /* System info area */
>>>      uint64_t        save_area[16];            /* 0xc00 */
>>> -    uint8_t         pad9[0xd40-0xc80];        /* 0xc80 */
>>> +    uint8_t         pad10[0xd40-0xc80];       /* 0xc80 */
>>>      uint64_t        kernel_stack;             /* 0xd40 */
>>>      uint64_t        thread_info;              /* 0xd48 */
>>>      uint64_t        async_stack;              /* 0xd50 */
>>> @@ -824,7 +826,7 @@ typedef struct LowCore
>>>      uint64_t        user_asce;                /* 0xd60 */
>>>      uint64_t        panic_stack;              /* 0xd68 */
>>>      uint64_t        user_exec_asce;           /* 0xd70 */
>>> -    uint8_t         pad10[0xdc0-0xd78];       /* 0xd78 */
>>> +    uint8_t         pad11[0xdc0-0xd78];       /* 0xd78 */
>>>      /* SMP info area: defined by DJB */
>>>      uint64_t        clock_comparator;         /* 0xdc0 */
>>> diff --git a/target-s390x/helper.c b/target-s390x/helper.c
>>> index 615cccf..d887006 100644
>>> --- a/target-s390x/helper.c
>>> +++ b/target-s390x/helper.c
>>> @@ -293,6 +293,7 @@ static void do_program_interrupt(CPUS390XState *env)
>>>      lowcore->program_old_psw.addr = cpu_to_be64(env->psw.addr);
>>>      mask = be64_to_cpu(lowcore->program_new_psw.mask);
>>>      addr = be64_to_cpu(lowcore->program_new_psw.addr);
>>> +    lowcore->per_breaking_event_addr = cpu_to_be64(env->gbea);
>>>      cpu_unmap_lowcore(lowcore);
>>> diff --git a/target-s390x/translate.c b/target-s390x/translate.c
>>> index 98e8224..2fde815 100644
>>> --- a/target-s390x/translate.c
>>> +++ b/target-s390x/translate.c
>>> @@ -150,6 +150,7 @@ void s390_cpu_dump_state(CPUState *cs, FILE *f, fprintf_function cpu_fprintf,
>>>  static TCGv_i64 psw_addr;
>>>  static TCGv_i64 psw_mask;
>>> +static TCGv_i64 gbea;
>>>  static TCGv_i32 cc_op;
>>>  static TCGv_i64 cc_src;
>>> @@ -173,6 +174,9 @@ void s390x_translate_init(void)
>>>      psw_mask = tcg_global_mem_new_i64(TCG_AREG0,
>>>                                        offsetof(CPUS390XState, psw.mask),
>>>                                        "psw_mask");
>>> +    gbea = tcg_global_mem_new_i64(TCG_AREG0,
>>> +                                  offsetof(CPUS390XState, gbea),
>>> +                                  "gbea");
>>>      cc_op = tcg_global_mem_new_i32(TCG_AREG0, offsetof(CPUS390XState, cc_op),
>>>                                     "cc_op");
>>> @@ -252,14 +256,14 @@ static void update_psw_addr(DisasContext *s)
>>>  static void per_branch(DisasContext *s, bool to_next)
>>>  {
>>>  #ifndef CONFIG_USER_ONLY
>>> +    tcg_gen_movi_i64(gbea, s->pc);
>>
>> This should probably be a call to per_breaking_event(), no?
> 
> Yes, that's possible, but given gbea is reused below instead of
> reloading s->pc, I preferred to make the move more explicit.

You're right, it's probably better to be explicit.

> 
> That said given I have to send a rebased version, I can easily change
> that.

No worries.

> 
>> Also, is there no flag to control this register? I'd assume it to be quite
>> some performance penalty to always store the last branched register.
> 
> No this register is always loaded. This is the value you see in dmesg
> when a user program crashes, but you can also get it via GDB. Quite
> useful in some cases.
> 
> I haven't measured any performance impact, only noise. We are talking
> about writing an immediate to a memory location in the env structure
> (thus very likely with a cache line already allocated), so it's only
> two host instructions more in a TB. That's not a lot given that for
> example every TB starts by loading a value from the env structure and
> doing a test on it.

Ok, let's be correct first and then see what we can do if anyone
complains about performance ;)


Alex

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

* Re: [Qemu-devel] [PATCH 00/15] target-s390x: add Program-Event Recording feature
  2015-06-12 22:45 [Qemu-devel] [PATCH 00/15] target-s390x: add Program-Event Recording feature Aurelien Jarno
                   ` (14 preceding siblings ...)
  2015-06-12 22:46 ` [Qemu-devel] [PATCH 15/15] target-s390x: PER: add Breaking-Event-Address register Aurelien Jarno
@ 2015-06-16 17:55 ` Alexander Graf
  15 siblings, 0 replies; 20+ messages in thread
From: Alexander Graf @ 2015-06-16 17:55 UTC (permalink / raw)
  To: Aurelien Jarno, qemu-devel; +Cc: Richard Henderson



On 13.06.15 00:45, Aurelien Jarno wrote:
> This patch set adds support for the Program-Event Recording (PER)
> feature. It implements all the PER functionalities except the
> following ones:
> - zero-address-detection event (part of the zero-address-detection
>   facility)
> - transaction-end event (we don't implement transactional memory)
> 
> There are also a few limitations to the storage-alteration event, as it
> doesn't support per ASC enablement, nor it doesn't correctly provide the
> ASC used for a storage event in the PER AI field.
> 
> With this patch set, it's possible to fully use GDB in a s390x guest,
> including stepping, breakpoints and watchpoints.

Thanks, applied all to s390-next.


Alex

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

end of thread, other threads:[~2015-06-16 17:55 UTC | newest]

Thread overview: 20+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2015-06-12 22:45 [Qemu-devel] [PATCH 00/15] target-s390x: add Program-Event Recording feature Aurelien Jarno
2015-06-12 22:45 ` [Qemu-devel] [PATCH 01/15] softmmu: provide tlb_vaddr_to_host function for user mode Aurelien Jarno
2015-06-12 22:45 ` [Qemu-devel] [PATCH 02/15] target-s390x: function to adjust the length wrt page boundary Aurelien Jarno
2015-06-12 22:45 ` [Qemu-devel] [PATCH 03/15] target-s390x: mvc_fast_memset: access memory through softmmu Aurelien Jarno
2015-06-12 22:45 ` [Qemu-devel] [PATCH 04/15] target-s390x: mvc_fast_memmove: " Aurelien Jarno
2015-06-12 22:45 ` [Qemu-devel] [PATCH 05/15] target-s390x: add PER related constants Aurelien Jarno
2015-06-12 22:45 ` [Qemu-devel] [PATCH 06/15] target-s390x: add get_per_atmid function Aurelien Jarno
2015-06-12 22:45 ` [Qemu-devel] [PATCH 07/15] target-s390x: add get_per_in_range function Aurelien Jarno
2015-06-12 22:45 ` [Qemu-devel] [PATCH 08/15] target-s390x: basic PER event handling Aurelien Jarno
2015-06-12 22:45 ` [Qemu-devel] [PATCH 09/15] target-s390x: PER successful-branching event support Aurelien Jarno
2015-06-12 22:45 ` [Qemu-devel] [PATCH 10/15] target-s390x: PER instruction-fetch " Aurelien Jarno
2015-06-12 22:45 ` [Qemu-devel] [PATCH 11/15] translate-all: fix watchpoints if retranslation not possible Aurelien Jarno
2015-06-12 22:46 ` [Qemu-devel] [PATCH 12/15] target-s390x: PER storage-alteration event support Aurelien Jarno
2015-06-12 22:46 ` [Qemu-devel] [PATCH 13/15] target-s390x: PER store-using-real-address " Aurelien Jarno
2015-06-12 22:46 ` [Qemu-devel] [PATCH 14/15] target-s390x: PER instruction-fetch nullification " Aurelien Jarno
2015-06-12 22:46 ` [Qemu-devel] [PATCH 15/15] target-s390x: PER: add Breaking-Event-Address register Aurelien Jarno
2015-06-16 16:44   ` Alexander Graf
2015-06-16 17:44     ` Aurelien Jarno
2015-06-16 17:50       ` Alexander Graf
2015-06-16 17:55 ` [Qemu-devel] [PATCH 00/15] target-s390x: add Program-Event Recording feature Alexander Graf

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.