All of lore.kernel.org
 help / color / mirror / Atom feed
* [Qemu-devel] [PATCH 0/8] s390: SCLP console and misc
@ 2012-06-06 12:05 Jens Freimann
  2012-06-06 12:05 ` [Qemu-devel] [PATCH 1/8] s390: add new define for KVM_CAP_S390_COW Jens Freimann
                   ` (8 more replies)
  0 siblings, 9 replies; 51+ messages in thread
From: Jens Freimann @ 2012-06-06 12:05 UTC (permalink / raw)
  To: Alexander Graf; +Cc: Cornelia Huck, Jens Freimann, Heinz Graalfs, qemu-devel

From: Jens Freimann <jfrei@linux.vnet.ibm.com>

Some patches for s390. The biggest chunk is the SCLP (console) implementation.

Christian Borntraeger (3):
  s390: autodetect map private
  s390: stop target cpu on sigp initial reset
  s390: Cleanup sclp functions

Heinz Graalfs (2):
  s390: sclp event facility and signal quiesce support via
    system_powerdown
  s390: Add SCLP vt220 console support

Jens Freimann (2):
  s390: add new define for KVM_CAP_S390_COW
  s390: make kvm_stat work on s390

Nick Wang (1):
  s390: Fix the storage increment size calculation

 Makefile.target           |    3 +-
 exec.c                    |   54 ++++--
 hw/s390-event-facility.c  |  441 ++++++++++++++++++++++++++++++++++++++++++
 hw/s390-event-facility.h  |   62 ++++++
 hw/s390-sclp.c            |  463 +++++++++++++++++++++++++++++++++++++++++++++
 hw/s390-sclp.h            |  148 +++++++++++++++
 hw/s390-virtio.c          |   17 +-
 kvm.h                     |    9 +
 linux-headers/linux/kvm.h |    1 +
 oslib-posix.c             |    3 +
 scripts/kvm/kvm_stat      |   26 ++-
 sysemu.h                  |    1 +
 target-s390x/cpu.h        |   11 --
 target-s390x/kvm.c        |   12 +-
 target-s390x/op_helper.c  |   48 ++---
 vl.c                      |   41 ++++
 16 files changed, 1283 insertions(+), 57 deletions(-)
 create mode 100644 hw/s390-event-facility.c
 create mode 100644 hw/s390-event-facility.h
 create mode 100644 hw/s390-sclp.c
 create mode 100644 hw/s390-sclp.h

-- 
1.7.10.4

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

* [Qemu-devel] [PATCH 1/8] s390: add new define for KVM_CAP_S390_COW
  2012-06-06 12:05 [Qemu-devel] [PATCH 0/8] s390: SCLP console and misc Jens Freimann
@ 2012-06-06 12:05 ` Jens Freimann
  2012-06-06 12:05 ` [Qemu-devel] [PATCH 2/8] s390: autodetect map private Jens Freimann
                   ` (7 subsequent siblings)
  8 siblings, 0 replies; 51+ messages in thread
From: Jens Freimann @ 2012-06-06 12:05 UTC (permalink / raw)
  To: Alexander Graf
  Cc: Jens Freimann, Heinz Graalfs, qemu-devel, Christian Borntraeger,
	Jens Freimann, Cornelia Huck

From: Jens Freimann <jfrei@linux.vnet.ibm.com>

Add new define for capability KVM_CAP_S390_COW
This patch should be replaced by a current kernel kvm.h header file.

Signed-off-by: Christian Borntraeger <borntraeger@de.ibm.com>
Signed-off-by: Jens Freimann <jfrei@de.ibm.com>
---
 linux-headers/linux/kvm.h |    1 +
 1 file changed, 1 insertion(+)

diff --git a/linux-headers/linux/kvm.h b/linux-headers/linux/kvm.h
index c4426ec..5a9d4e3 100644
--- a/linux-headers/linux/kvm.h
+++ b/linux-headers/linux/kvm.h
@@ -616,6 +616,7 @@ struct kvm_ppc_smmu_info {
 #define KVM_CAP_KVMCLOCK_CTRL 76
 #define KVM_CAP_SIGNAL_MSI 77
 #define KVM_CAP_PPC_GET_SMMU_INFO 78
+#define KVM_CAP_S390_COW 79
 
 #ifdef KVM_CAP_IRQ_ROUTING
 
-- 
1.7.10.4

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

* [Qemu-devel] [PATCH 2/8] s390: autodetect map private
  2012-06-06 12:05 [Qemu-devel] [PATCH 0/8] s390: SCLP console and misc Jens Freimann
  2012-06-06 12:05 ` [Qemu-devel] [PATCH 1/8] s390: add new define for KVM_CAP_S390_COW Jens Freimann
@ 2012-06-06 12:05 ` Jens Freimann
  2012-06-12  9:32   ` Alexander Graf
  2012-06-06 12:05 ` [Qemu-devel] [PATCH 3/8] s390: make kvm_stat work on s390 Jens Freimann
                   ` (6 subsequent siblings)
  8 siblings, 1 reply; 51+ messages in thread
From: Jens Freimann @ 2012-06-06 12:05 UTC (permalink / raw)
  To: Alexander Graf
  Cc: Cornelia Huck, Christian Borntraeger, Jens Freimann,
	Heinz Graalfs, qemu-devel

From: Christian Borntraeger <borntraeger@de.ibm.com>

By default qemu will use MAP_PRIVATE for guest pages. This will write
protect pages and thus break on s390 systems that dont support this feature.
Therefore qemu has a hack to always use MAP_SHARED for s390. But MAP_SHARED
has other problems (no dirty pages tracking, a lot more swap overhead etc.)
Newer systems allow the distinction via KVM_CAP_S390_COW. With this feature
qemu can use the standard qemu alloc if available, otherwise it will use
the old s390 hack.

Signed-off-by: Christian Borntraeger <borntraeger@de.ibm.com>
Signed-off-by: Jens Freimann <jfrei@linux.vnet.ibm.com>
---
 exec.c             |   54 +++++++++++++++++++++++++++++++++++++---------------
 kvm.h              |    9 +++++++++
 oslib-posix.c      |    3 +++
 target-s390x/kvm.c |    6 ++++++
 4 files changed, 57 insertions(+), 15 deletions(-)

diff --git a/exec.c b/exec.c
index a0494c7..8fec680 100644
--- a/exec.c
+++ b/exec.c
@@ -2618,6 +2618,43 @@ void qemu_ram_set_idstr(ram_addr_t addr, const char *name, DeviceState *dev)
     }
 }
 
+/*
+ * lets make sure that we dont have the old s390x limitations regarding
+ * guest mappings
+ */
+static int legacy_s390x_mem_layout(void)
+{
+#if defined(TARGET_S390X)
+    return kvm_has_legacy_s390x_memlayout();
+#else
+    return 0;
+#endif
+}
+
+/*
+ * Legacy layout for s390:
+ * Older S390 KVM requires the topmost vma of the RAM to be
+ * smaller than an system defined value, which is at least 256GB.
+ * Larger systems have larger values. We put the guest between
+ * the end of data segment (system break) and this value. We
+ * use 32GB as a base to have enough room for the system break
+ * to grow. We also have to use MAP parameters that avoid
+ * read-only mapping of guest pages.
+ */
+static void *legacy_s390_alloc(ram_addr_t size)
+{
+    void *mem;
+
+    mem = mmap((void *) 0x800000000ULL, size,
+               PROT_EXEC|PROT_READ|PROT_WRITE,
+               MAP_SHARED | MAP_ANONYMOUS | MAP_FIXED, -1, 0);
+    if (mem == MAP_FAILED) {
+        fprintf(stderr, "Allocating RAM failed\n");
+        abort();
+    }
+    return mem;
+}
+
 ram_addr_t qemu_ram_alloc_from_ptr(ram_addr_t size, void *host,
                                    MemoryRegion *mr)
 {
@@ -2644,26 +2681,13 @@ ram_addr_t qemu_ram_alloc_from_ptr(ram_addr_t size, void *host,
             exit(1);
 #endif
         } else {
-#if defined(TARGET_S390X) && defined(CONFIG_KVM)
-            /* S390 KVM requires the topmost vma of the RAM to be smaller than
-               an system defined value, which is at least 256GB. Larger systems
-               have larger values. We put the guest between the end of data
-               segment (system break) and this value. We use 32GB as a base to
-               have enough room for the system break to grow. */
-            new_block->host = mmap((void*)0x800000000, size,
-                                   PROT_EXEC|PROT_READ|PROT_WRITE,
-                                   MAP_SHARED | MAP_ANONYMOUS | MAP_FIXED, -1, 0);
-            if (new_block->host == MAP_FAILED) {
-                fprintf(stderr, "Allocating RAM failed\n");
-                abort();
-            }
-#else
             if (xen_enabled()) {
                 xen_ram_alloc(new_block->offset, size, mr);
+            } else if (legacy_s390x_mem_layout()) {
+                new_block->host = legacy_s390_alloc(size);
             } else {
                 new_block->host = qemu_vmalloc(size);
             }
-#endif
             qemu_madvise(new_block->host, size, QEMU_MADV_MERGEABLE);
         }
     }
diff --git a/kvm.h b/kvm.h
index 9c7b0ea..ca0557e 100644
--- a/kvm.h
+++ b/kvm.h
@@ -62,6 +62,15 @@ int kvm_has_pit_state2(void);
 int kvm_has_many_ioeventfds(void);
 int kvm_has_gsi_routing(void);
 
+#ifndef CONFIG_KVM 
+static inline int kvm_has_legacy_s390x_memlayout(void)
+{
+    return 0;
+}
+#else
+int kvm_has_legacy_s390x_memlayout(void);
+#endif
+
 int kvm_allows_irq0_override(void);
 
 #ifdef NEED_CPU_H
diff --git a/oslib-posix.c b/oslib-posix.c
index b6a3c7f..93902ac 100644
--- a/oslib-posix.c
+++ b/oslib-posix.c
@@ -41,6 +41,9 @@ extern int daemon(int, int);
       therefore we need special code which handles running on Valgrind. */
 #  define QEMU_VMALLOC_ALIGN (512 * 4096)
 #  define CONFIG_VALGRIND
+#elif defined(__linux__) && defined(__s390x__)
+   /* Use 1 MiB (segment size) alignment so gmap can be used by KVM. */
+#  define QEMU_VMALLOC_ALIGN (256 * 4096)
 #else
 #  define QEMU_VMALLOC_ALIGN getpagesize()
 #endif
diff --git a/target-s390x/kvm.c b/target-s390x/kvm.c
index 90aad61..93a8431 100644
--- a/target-s390x/kvm.c
+++ b/target-s390x/kvm.c
@@ -135,6 +135,12 @@ int kvm_arch_get_registers(CPUS390XState *env)
     return 0;
 }
 
+int kvm_has_legacy_s390x_memlayout(void)
+{
+    return !kvm_check_extension(kvm_state, KVM_CAP_S390_GMAP) ||
+           !kvm_check_extension(kvm_state, KVM_CAP_S390_COW);
+}
+
 int kvm_arch_insert_sw_breakpoint(CPUS390XState *env, struct kvm_sw_breakpoint *bp)
 {
     static const uint8_t diag_501[] = {0x83, 0x24, 0x05, 0x01};
-- 
1.7.10.4

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

* [Qemu-devel] [PATCH 3/8] s390: make kvm_stat work on s390
  2012-06-06 12:05 [Qemu-devel] [PATCH 0/8] s390: SCLP console and misc Jens Freimann
  2012-06-06 12:05 ` [Qemu-devel] [PATCH 1/8] s390: add new define for KVM_CAP_S390_COW Jens Freimann
  2012-06-06 12:05 ` [Qemu-devel] [PATCH 2/8] s390: autodetect map private Jens Freimann
@ 2012-06-06 12:05 ` Jens Freimann
  2012-06-06 12:05 ` [Qemu-devel] [PATCH 4/8] s390: stop target cpu on sigp initial reset Jens Freimann
                   ` (5 subsequent siblings)
  8 siblings, 0 replies; 51+ messages in thread
From: Jens Freimann @ 2012-06-06 12:05 UTC (permalink / raw)
  To: Alexander Graf; +Cc: Cornelia Huck, Jens Freimann, Heinz Graalfs, qemu-devel

From: Jens Freimann <jfrei@linux.vnet.ibm.com>

Add s390_exit_reasons so kvm_stat doesn't crash when called on s390.
Look for 'vendor_id' in /proc/cpuinfo as well, instead of just for
'flags', so we can determine if we run on S390.

Signed-off-by: Jens Freimann <jfrei@linux.vnet.ibm.com>
---
 scripts/kvm/kvm_stat |   26 +++++++++++++++++++++++++-
 1 file changed, 25 insertions(+), 1 deletion(-)

diff --git a/scripts/kvm/kvm_stat b/scripts/kvm/kvm_stat
index 56d2bd7..e8d68f0 100755
--- a/scripts/kvm/kvm_stat
+++ b/scripts/kvm/kvm_stat
@@ -141,15 +141,39 @@ svm_exit_reasons = {
     0x400: 'NPF',
 }
 
+s390_exit_reasons = {
+	0x000: 'UNKNOWN',
+	0x001: 'EXCEPTION',
+	0x002: 'IO',
+	0x003: 'HYPERCALL',
+	0x004: 'DEBUG',
+	0x005: 'HLT',
+	0x006: 'MMIO',
+	0x007: 'IRQ_WINDOW_OPEN',
+	0x008: 'SHUTDOWN',
+	0x009: 'FAIL_ENTRY',
+	0x010: 'INTR',
+	0x011: 'SET_TPR',
+	0x012: 'TPR_ACCESS',
+	0x013: 'S390_SIEIC',
+	0x014: 'S390_RESET',
+	0x015: 'DCR',
+	0x016: 'NMI',
+	0x017: 'INTERNAL_ERROR',
+	0x018: 'OSI',
+	0x019: 'PAPR_HCALL',
+}
+
 vendor_exit_reasons = {
     'vmx': vmx_exit_reasons,
     'svm': svm_exit_reasons,
+    'IBM/S390': s390_exit_reasons,
 }
 
 exit_reasons = None
 
 for line in file('/proc/cpuinfo').readlines():
-    if line.startswith('flags'):
+    if line.startswith('flags') or line.startswith('vendor_id'):
         for flag in line.split():
             if flag in vendor_exit_reasons:
                 exit_reasons = vendor_exit_reasons[flag]
-- 
1.7.10.4

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

* [Qemu-devel] [PATCH 4/8] s390: stop target cpu on sigp initial reset
  2012-06-06 12:05 [Qemu-devel] [PATCH 0/8] s390: SCLP console and misc Jens Freimann
                   ` (2 preceding siblings ...)
  2012-06-06 12:05 ` [Qemu-devel] [PATCH 3/8] s390: make kvm_stat work on s390 Jens Freimann
@ 2012-06-06 12:05 ` Jens Freimann
  2012-06-12  9:42   ` Alexander Graf
  2012-06-06 12:05 ` [Qemu-devel] [PATCH 5/8] s390: Cleanup sclp functions Jens Freimann
                   ` (4 subsequent siblings)
  8 siblings, 1 reply; 51+ messages in thread
From: Jens Freimann @ 2012-06-06 12:05 UTC (permalink / raw)
  To: Alexander Graf
  Cc: Cornelia Huck, Christian Borntraeger, Jens Freimann,
	Heinz Graalfs, qemu-devel

From: Christian Borntraeger <borntraeger@de.ibm.com>

We must not run the target cpu after an initial reset. This makes
system_reset more reliable for smp guests.

Signed-off-by: Christian Borntraeger <borntraeger@de.ibm.com>
---
 target-s390x/kvm.c |    1 +
 1 file changed, 1 insertion(+)

diff --git a/target-s390x/kvm.c b/target-s390x/kvm.c
index 93a8431..73cfd1f 100644
--- a/target-s390x/kvm.c
+++ b/target-s390x/kvm.c
@@ -318,6 +318,7 @@ static int s390_cpu_initial_reset(CPUS390XState *env)
 {
     int i;
 
+    s390_del_running_cpu(env);
     if (kvm_vcpu_ioctl(env, KVM_S390_INITIAL_RESET, NULL) < 0) {
         perror("cannot init reset vcpu");
     }
-- 
1.7.10.4

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

* [Qemu-devel] [PATCH 5/8] s390: Cleanup sclp functions
  2012-06-06 12:05 [Qemu-devel] [PATCH 0/8] s390: SCLP console and misc Jens Freimann
                   ` (3 preceding siblings ...)
  2012-06-06 12:05 ` [Qemu-devel] [PATCH 4/8] s390: stop target cpu on sigp initial reset Jens Freimann
@ 2012-06-06 12:05 ` Jens Freimann
  2012-06-12  9:58   ` Alexander Graf
  2012-06-12 22:38   ` Anthony Liguori
  2012-06-06 12:05 ` [Qemu-devel] [PATCH 6/8] s390: sclp event facility and signal quiesce support via system_powerdown Jens Freimann
                   ` (3 subsequent siblings)
  8 siblings, 2 replies; 51+ messages in thread
From: Jens Freimann @ 2012-06-06 12:05 UTC (permalink / raw)
  To: Alexander Graf
  Cc: Jens Freimann, Heinz Graalfs, qemu-devel, Christian Borntraeger,
	Jens Freimann, Cornelia Huck

From: Christian Borntraeger <borntraeger@de.ibm.com>

The sclp facility on s390 is a hardware that is external to the cpu.
Lets cleanup the definitions and move the functionality into a separate
file under hw/.

Signed-off-by: Christian Borntraeger <borntraeger@de.ibm.com>
Signed-off-by: Jens Freimann <jfrei@de.ibm.com>
---
 Makefile.target          |    2 +-
 hw/s390-sclp.c           |   42 ++++++++++++++++++++++++++++++++++++++++++
 hw/s390-sclp.h           |   34 ++++++++++++++++++++++++++++++++++
 target-s390x/cpu.h       |   11 -----------
 target-s390x/kvm.c       |    5 ++---
 target-s390x/op_helper.c |   39 +++++++++++++++++----------------------
 6 files changed, 96 insertions(+), 37 deletions(-)
 create mode 100644 hw/s390-sclp.c
 create mode 100644 hw/s390-sclp.h

diff --git a/Makefile.target b/Makefile.target
index 1582904..fed2d72 100644
--- a/Makefile.target
+++ b/Makefile.target
@@ -374,7 +374,7 @@ obj-sh4-y += ide/mmio.o
 obj-m68k-y = an5206.o mcf5206.o mcf_uart.o mcf_intc.o mcf5208.o mcf_fec.o
 obj-m68k-y += m68k-semi.o dummy_m68k.o
 
-obj-s390x-y = s390-virtio-bus.o s390-virtio.o
+obj-s390x-y = s390-virtio-bus.o s390-virtio.o s390-sclp.o
 
 obj-alpha-y = mc146818rtc.o
 obj-alpha-y += alpha_pci.o alpha_dp264.o alpha_typhoon.o
diff --git a/hw/s390-sclp.c b/hw/s390-sclp.c
new file mode 100644
index 0000000..c046441
--- /dev/null
+++ b/hw/s390-sclp.c
@@ -0,0 +1,42 @@
+/*
+ * sclp facility
+ * Copyright IBM Corp. 2012
+ * Author: Christian Borntraeger <borntraeger@de.ibm.com>
+ *
+ */
+
+#include "cpu.h"
+#include "kvm.h"
+#include "hw/s390-sclp.h"
+
+int sclp_read_info(CPUS390XState *env, struct sccb *sccb)
+{
+    int shift = 0;
+
+    while ((ram_size >> (20 + shift)) > 65535) {
+        shift++;
+    }
+    sccb->c.read_info.rnmax = cpu_to_be16(ram_size >> (20 + shift));
+    sccb->c.read_info.rnsize = 1 << shift;
+    sccb->h.response_code = cpu_to_be16(0x10);
+
+    return 0;
+}
+
+void sclp_service_interrupt(CPUS390XState *env, uint32_t sccb)
+{
+    if (!sccb) {
+        return;
+    }
+
+    if (kvm_enabled()) {
+#ifdef CONFIG_KVM
+        kvm_s390_interrupt_internal(env, KVM_S390_INT_SERVICE,
+                                    (sccb & ~3), 0, 1);
+#endif
+    } else {
+        env->psw.addr += 4;
+        cpu_inject_ext(env, EXT_SERVICE, (sccb & ~3), 0);
+    }
+}
+
diff --git a/hw/s390-sclp.h b/hw/s390-sclp.h
new file mode 100644
index 0000000..e335b21
--- /dev/null
+++ b/hw/s390-sclp.h
@@ -0,0 +1,34 @@
+#include <stdint.h>
+#include <qemu-common.h>
+
+
+/* SCLP command codes */
+#define SCLP_CMDW_READ_SCP_INFO                 0x00020001
+#define SCLP_CMDW_READ_SCP_INFO_FORCED          0x00120001
+
+/* SCLP response codes */
+#define SCLP_RC_SCCB_RESOURCE_INSUFFICENT       0x07f0
+
+struct sccb_header {
+    uint16_t length;
+#define SCLP_FC_NORMAL_WRITE                    0
+    uint8_t function_code;
+    uint8_t control_mask[3];
+    uint16_t response_code;
+} __attribute__((packed));
+
+struct read_info_sccb {
+    uint16_t rnmax;
+    uint8_t rnsize;
+} __attribute__((packed));
+
+struct sccb {
+    struct sccb_header h;
+    union {
+        struct read_info_sccb read_info;
+        char data[4088];
+    } c;
+ } __attribute__((packed));
+
+int sclp_read_info(CPUS390XState *env, struct sccb *sccb);
+void sclp_service_interrupt(CPUS390XState *env, uint32_t sccb);
diff --git a/target-s390x/cpu.h b/target-s390x/cpu.h
index 2f3f394..d0199d7 100644
--- a/target-s390x/cpu.h
+++ b/target-s390x/cpu.h
@@ -591,17 +591,6 @@ static inline const char *cc_name(int cc_op)
     return cc_names[cc_op];
 }
 
-/* SCLP PV interface defines */
-#define SCLP_CMDW_READ_SCP_INFO         0x00020001
-#define SCLP_CMDW_READ_SCP_INFO_FORCED  0x00120001
-
-#define SCP_LENGTH                      0x00
-#define SCP_FUNCTION_CODE               0x02
-#define SCP_CONTROL_MASK                0x03
-#define SCP_RESPONSE_CODE               0x06
-#define SCP_MEM_CODE                    0x08
-#define SCP_INCREMENT                   0x0a
-
 typedef struct LowCore
 {
     /* prefix area: defined by architecture */
diff --git a/target-s390x/kvm.c b/target-s390x/kvm.c
index 73cfd1f..7a7604b 100644
--- a/target-s390x/kvm.c
+++ b/target-s390x/kvm.c
@@ -60,9 +60,6 @@
 #define SIGP_STORE_STATUS_ADDR          0x0e
 #define SIGP_SET_ARCH                   0x12
 
-#define SCLP_CMDW_READ_SCP_INFO         0x00020001
-#define SCLP_CMDW_READ_SCP_INFO_FORCED  0x00120001
-
 const KVMCapabilityInfo kvm_arch_required_capabilities[] = {
     KVM_CAP_LAST_INFO
 };
@@ -246,6 +243,8 @@ static int kvm_sclp_service_call(CPUS390XState *env, struct kvm_run *run,
     r = sclp_service_call(env, sccb, code);
     if (r) {
         setcc(env, 3);
+    } else {
+        setcc(env, 0);
     }
 
     return 0;
diff --git a/target-s390x/op_helper.c b/target-s390x/op_helper.c
index 7b72473..74bd9ad 100644
--- a/target-s390x/op_helper.c
+++ b/target-s390x/op_helper.c
@@ -31,6 +31,7 @@
 
 #if !defined (CONFIG_USER_ONLY)
 #include "sysemu.h"
+#include "hw/s390-sclp.h"
 #endif
 
 /*****************************************************************************/
@@ -2360,16 +2361,13 @@ static void program_interrupt(CPUS390XState *env, uint32_t code, int ilc)
     }
 }
 
-static void ext_interrupt(CPUS390XState *env, int type, uint32_t param,
-                          uint64_t param64)
-{
-    cpu_inject_ext(env, type, param, param64);
-}
 
 int sclp_service_call(CPUS390XState *env, uint32_t sccb, uint64_t code)
 {
     int r = 0;
-    int shift = 0;
+    struct sccb work_sccb;
+    struct sccb *guest_sccb;
+    target_phys_addr_t sccb_len = sizeof(*guest_sccb);
 
 #ifdef DEBUG_HELPER
     printf("sclp(0x%x, 0x%" PRIx64 ")\n", sccb, code);
@@ -2380,26 +2378,18 @@ int sclp_service_call(CPUS390XState *env, uint32_t sccb, uint64_t code)
         r = -1;
         goto out;
     }
+    /*
+     * we want to work on a private copy of the sccb, to prevent guests
+     * from playing dirty tricks by modifying the memory content after
+     * the host has checked the values
+     */
+    guest_sccb = cpu_physical_memory_map(sccb, &sccb_len, true);
+    memcpy(&work_sccb, guest_sccb, sizeof(*guest_sccb));
 
     switch(code) {
         case SCLP_CMDW_READ_SCP_INFO:
         case SCLP_CMDW_READ_SCP_INFO_FORCED:
-            while ((ram_size >> (20 + shift)) > 65535) {
-                shift++;
-            }
-            stw_phys(sccb + SCP_MEM_CODE, ram_size >> (20 + shift));
-            stb_phys(sccb + SCP_INCREMENT, 1 << shift);
-            stw_phys(sccb + SCP_RESPONSE_CODE, 0x10);
-
-            if (kvm_enabled()) {
-#ifdef CONFIG_KVM
-                kvm_s390_interrupt_internal(env, KVM_S390_INT_SERVICE,
-                                            sccb & ~3, 0, 1);
-#endif
-            } else {
-                env->psw.addr += 4;
-                ext_interrupt(env, EXT_SERVICE, sccb & ~3, 0);
-            }
+            r = sclp_read_info(env, &work_sccb);
             break;
         default:
 #ifdef DEBUG_HELPER
@@ -2408,6 +2398,11 @@ int sclp_service_call(CPUS390XState *env, uint32_t sccb, uint64_t code)
             r = -1;
             break;
     }
+    memcpy(guest_sccb, &work_sccb, work_sccb.h.length);
+    cpu_physical_memory_unmap(guest_sccb, 4096, true, 4096);
+    if (!r) {
+        sclp_service_interrupt(env, sccb);
+    }
 
 out:
     return r;
-- 
1.7.10.4

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

* [Qemu-devel] [PATCH 6/8] s390: sclp event facility and signal quiesce support via system_powerdown
  2012-06-06 12:05 [Qemu-devel] [PATCH 0/8] s390: SCLP console and misc Jens Freimann
                   ` (4 preceding siblings ...)
  2012-06-06 12:05 ` [Qemu-devel] [PATCH 5/8] s390: Cleanup sclp functions Jens Freimann
@ 2012-06-06 12:05 ` Jens Freimann
  2012-06-12 11:38   ` Alexander Graf
  2012-06-06 12:05 ` [Qemu-devel] [PATCH 7/8] s390: Add SCLP vt220 console support Jens Freimann
                   ` (2 subsequent siblings)
  8 siblings, 1 reply; 51+ messages in thread
From: Jens Freimann @ 2012-06-06 12:05 UTC (permalink / raw)
  To: Alexander Graf
  Cc: Jens Freimann, Heinz Graalfs, qemu-devel, Christian Borntraeger,
	Jens Freimann, Cornelia Huck

From: Heinz Graalfs <graalfs@linux.vnet.ibm.com>

This patch implements a subset of the sclp event facility as well
as the signal quiesce event. This allows to gracefully shutdown
a guest by using system_powerdown. This sends a signal quiesce
signal that is interpreted by linux guests as ctrl-alt-del.
In addition the event facility is modeled using the QOM.

Signed-off-by: Heinz Graalfs <graalfs@linux.vnet.ibm.com>
Signed-off-by: Christian Borntraeger <borntraeger@de.ibm.com>
Signed-off-by: Jens Freimann <jfrei@de.ibm.com>
---
 Makefile.target          |    1 +
 hw/s390-event-facility.c |  232 +++++++++++++++++++++++++++++++++++++++++
 hw/s390-event-facility.h |   54 ++++++++++
 hw/s390-sclp.c           |  256 +++++++++++++++++++++++++++++++++++++++++++++-
 hw/s390-sclp.h           |   98 +++++++++++++++++-
 hw/s390-virtio.c         |   11 +-
 target-s390x/op_helper.c |    3 +
 7 files changed, 649 insertions(+), 6 deletions(-)
 create mode 100644 hw/s390-event-facility.c
 create mode 100644 hw/s390-event-facility.h

diff --git a/Makefile.target b/Makefile.target
index fed2d72..f939c3a 100644
--- a/Makefile.target
+++ b/Makefile.target
@@ -375,6 +375,7 @@ obj-m68k-y = an5206.o mcf5206.o mcf_uart.o mcf_intc.o mcf5208.o mcf_fec.o
 obj-m68k-y += m68k-semi.o dummy_m68k.o
 
 obj-s390x-y = s390-virtio-bus.o s390-virtio.o s390-sclp.o
+obj-s390x-y += s390-event-facility.o
 
 obj-alpha-y = mc146818rtc.o
 obj-alpha-y += alpha_pci.o alpha_dp264.o alpha_typhoon.o
diff --git a/hw/s390-event-facility.c b/hw/s390-event-facility.c
new file mode 100644
index 0000000..b8106a6
--- /dev/null
+++ b/hw/s390-event-facility.c
@@ -0,0 +1,232 @@
+/*
+ * SCLP Event Facility
+ *
+ * Copyright IBM Corp. 2007,2012
+ * Author: Heinz Graalfs <graalfs@de.ibm.com>
+ *
+ * This file is licensed under the terms of the GNU General Public License(GPL)
+ */
+
+#include "iov.h"
+#include "monitor.h"
+#include "qemu-queue.h"
+#include "sysbus.h"
+#include "sysemu.h"
+
+#include "s390-sclp.h"
+#include "s390-event-facility.h"
+
+struct SCLPDevice {
+    const char *name;
+    bool vm_running;
+};
+
+struct SCLP {
+    BusState qbus;
+    SCLPEventFacility *event_facility;
+};
+
+struct SCLPEventFacility {
+    SCLPDevice sdev;
+    SCLP sbus;
+    DeviceState *qdev;
+    void *opaque;
+};
+
+typedef struct SCLPConsole {
+    SCLPEvent event;
+    CharDriverState *chr;
+} SCLPConsole;
+
+static void sclpef_bus_dev_print(Monitor *mon, DeviceState *qdev, int indent)
+{
+    SCLPEvent *event = DO_UPCAST(SCLPEvent, dev, qdev);
+
+    monitor_printf(mon, "%*sid %d\n", indent, "", event->id);
+}
+
+static unsigned int send_mask_quiesce(void)
+{
+    return SCLP_EVENT_MASK_SIGNAL_QUIESCE;
+}
+
+static unsigned int receive_mask_quiesce(void)
+{
+    return 0;
+}
+
+static void s390_signal_quiesce(void *opaque, int n, int level)
+{
+    sclp_enable_signal_quiesce();
+    sclp_service_interrupt(opaque, 0);
+}
+
+unsigned int sclpef_send_mask(SCLPDevice *sdev)
+{
+    unsigned int mask;
+    DeviceState *dev;
+    SCLPEventFacility *event_facility;
+    SCLPEventClass *cons;
+
+    event_facility = DO_UPCAST(SCLPEventFacility, sdev, sdev);
+
+    mask = 0;
+
+    QTAILQ_FOREACH(dev, &event_facility->sbus.qbus.children, sibling) {
+        cons = SCLP_EVENT_GET_CLASS((SCLPEvent *) dev);
+        mask |= cons->get_send_mask();
+    }
+    return mask;
+}
+
+unsigned int sclpef_receive_mask(SCLPDevice *sdev)
+{
+    unsigned int mask;
+    DeviceState *dev;
+    SCLPEventClass *cons;
+    SCLPEventFacility *event_facility;
+
+    event_facility = DO_UPCAST(SCLPEventFacility, sdev, sdev);
+
+    mask = 0;
+
+    QTAILQ_FOREACH(dev, &event_facility->sbus.qbus.children, sibling) {
+        cons = SCLP_EVENT_GET_CLASS((SCLPEvent *) dev);
+        mask |= cons->get_receive_mask();
+    }
+    return mask;
+}
+
+static struct BusInfo sclp_bus_info = {
+    .name      = "s390-sclp-bus",
+    .size      = sizeof(SCLPS390Bus),
+    .print_dev = sclpef_bus_dev_print,
+    .props      = (Property[]) {
+        DEFINE_PROP_STRING("name", SCLPEvent, name),
+        DEFINE_PROP_END_OF_LIST()
+    }
+};
+
+static int sclpef_qdev_init(DeviceState *qdev)
+{
+    int rc;
+    SCLPEvent *event = DO_UPCAST(SCLPEvent, dev, qdev);
+    SCLPEventClass *cons = SCLP_EVENT_GET_CLASS(event);
+    SCLP *bus = DO_UPCAST(SCLP, qbus, qdev->parent_bus);
+
+    event->evt_fac = bus->event_facility;
+    rc = cons->init(event);
+
+    return rc;
+}
+
+static int sclpef_qdev_exit(DeviceState *qdev)
+{
+    SCLPEvent *event = DO_UPCAST(SCLPEvent, dev, qdev);
+    SCLPEventClass *cons = SCLP_EVENT_GET_CLASS(event);
+    if (cons->exit) {
+        cons->exit(event);
+    }
+    return 0;
+}
+
+static SCLPDevice *sclpef_common_init(const char *name, size_t struct_size)
+{
+    SCLPDevice *sdev;
+
+    sdev = malloc(struct_size);
+    if (!sdev) {
+        return NULL;
+    }
+    sdev->vm_running = runstate_is_running();
+    sdev->name = name;
+
+    return sdev;
+}
+
+void sclpef_enable_irqs(SCLPDevice *sdev, void *opaque)
+{
+    SCLPEventFacility *event_facility;
+
+    event_facility = DO_UPCAST(SCLPEventFacility, sdev, sdev);
+    qemu_system_powerdown = *qemu_allocate_irqs(s390_signal_quiesce,
+                                                opaque, 1);
+    event_facility->opaque = opaque;
+}
+
+SCLPDevice *sclpef_init_event_facility(DeviceState *dev)
+{
+    DeviceState *quiesce;
+    SCLPDevice *sdev;
+    SCLPEventFacility *event_facility;
+
+    sdev = sclpef_common_init("sclp-event-facility",
+            sizeof(SCLPEventFacility));
+
+    if (!sdev) {
+        return NULL;
+    }
+    event_facility = DO_UPCAST(SCLPEventFacility, sdev, sdev);
+
+    /* Spawn a new sclp-facility */
+    qbus_create_inplace(&event_facility->sbus.qbus, &sclp_bus_info, dev, NULL);
+    event_facility->sbus.qbus.allow_hotplug = 0;
+    event_facility->sbus.event_facility = event_facility;
+    event_facility->qdev = dev;
+    event_facility->opaque = NULL;
+    quiesce = qdev_create(&event_facility->sbus.qbus, "sclpquiesce");
+
+    if (!quiesce) {
+        return NULL;
+    }
+
+    return sdev;
+}
+
+static void sclpef_class_init(ObjectClass *klass, void *data)
+{
+    DeviceClass *dc = DEVICE_CLASS(klass);
+    dc->init = sclpef_qdev_init;
+    dc->bus_info = &sclp_bus_info;
+    dc->exit = sclpef_qdev_exit;
+    dc->unplug = qdev_simple_unplug_cb;
+}
+
+static TypeInfo sclp_event_facility_type_info = {
+    .name = TYPE_SCLP_EVENT,
+    .parent = TYPE_DEVICE,
+    .instance_size = sizeof(SCLPEvent),
+    .class_size = sizeof(SCLPEventClass),
+    .class_init = sclpef_class_init,
+    .abstract = true,
+};
+
+static int sclpquiesce_initfn(SCLPEvent *event)
+{
+    event->id = ID_QUIESCE;
+
+    return 0;
+}
+
+static void sclpef_quiesce_class_init(ObjectClass *klass, void *data)
+{
+    SCLPEventClass *k = SCLP_EVENT_CLASS(klass);
+
+    k->init = sclpquiesce_initfn;
+    k->get_send_mask = send_mask_quiesce;
+    k->get_receive_mask = receive_mask_quiesce;
+}
+
+static TypeInfo sclp_quiesce_info = {
+    .name          = "sclpquiesce",
+    .parent        = TYPE_SCLP_EVENT,
+    .instance_size = sizeof(SCLPEvent),
+    .class_init    = sclpef_quiesce_class_init,
+};
+
+static void sclpef_register_types(void)
+{
+    type_register_static(&sclp_event_facility_type_info);
+    type_register_static(&sclp_quiesce_info);
+}
+type_init(sclpef_register_types)
diff --git a/hw/s390-event-facility.h b/hw/s390-event-facility.h
new file mode 100644
index 0000000..40d4049
--- /dev/null
+++ b/hw/s390-event-facility.h
@@ -0,0 +1,54 @@
+/*
+ * SCLP definitions
+ *
+ * Copyright IBM Corp. 2007,2012
+ * Author: Heinz Graalfs <graalfs@de.ibm.com>
+ *
+ * This file is licensed under the terms of the GNU General Public License(GPL)
+ */
+
+#ifndef _QEMU_SCLP_EVENT_H
+#define _QEMU_SCLP_EVENT_H
+
+#include "qdev.h"
+#include "qemu-common.h"
+
+#define ID_QUIESCE SCLP_EVENT_SIGNAL_QUIESCE
+
+#define TYPE_SCLP_EVENT "s390-sclp-event-type"
+#define SCLP_EVENT(obj) \
+     OBJECT_CHECK(SCLPEvent, (obj), TYPE_SCLP_EVENT)
+#define SCLP_EVENT_CLASS(klass) \
+     OBJECT_CLASS_CHECK(SCLPEventClass, (klass), TYPE_SCLP_EVENT)
+#define SCLP_EVENT_GET_CLASS(obj) \
+     OBJECT_GET_CLASS(SCLPEventClass, (obj), TYPE_SCLP_EVENT)
+
+typedef struct SCLP SCLP;
+typedef struct SCLPEventFacility SCLPEventFacility;
+typedef struct SCLPEvent SCLPEvent;
+typedef struct SCLPDevice SCLPDevice;
+
+typedef struct SCLPEventClass {
+    DeviceClass parent_class;
+    int (*init)(SCLPEvent *event);
+    int (*exit)(SCLPEvent *event);
+    unsigned int (*get_send_mask)(void);
+    unsigned int (*get_receive_mask)(void);
+} SCLPEventClass;
+
+struct SCLPEvent {
+    DeviceState dev;
+    SCLPEventFacility *evt_fac;
+    char *name;
+    uint32_t id;
+};
+
+SCLPDevice *sclpef_init_event_facility(DeviceState *dev);
+
+void sclpef_enable_irqs(SCLPDevice *sdev, void *opaque);
+
+void sclpef_set_masks(void);
+unsigned int sclpef_send_mask(SCLPDevice *sdev);
+unsigned int sclpef_receive_mask(SCLPDevice *sdev);
+
+#endif
diff --git a/hw/s390-sclp.c b/hw/s390-sclp.c
index c046441..683a709 100644
--- a/hw/s390-sclp.c
+++ b/hw/s390-sclp.c
@@ -7,7 +7,20 @@
 
 #include "cpu.h"
 #include "kvm.h"
+#include "hw/sysbus.h"
 #include "hw/s390-sclp.h"
+#include "hw/s390-event-facility.h"
+
+/* Host capabilites */
+static unsigned int sclp_send_mask;
+static unsigned int sclp_receive_mask;
+
+/* Guest capabilities */
+static unsigned int sclp_cp_send_mask;
+static unsigned int sclp_cp_receive_mask;
+
+static int quiesce;
+static int event_pending;
 
 int sclp_read_info(CPUS390XState *env, struct sccb *sccb)
 {
@@ -23,20 +36,257 @@ int sclp_read_info(CPUS390XState *env, struct sccb *sccb)
     return 0;
 }
 
+static int signal_quiesce_event(struct sccb *sccb, int *slen)
+{
+    if (!quiesce) {
+        return 0;
+    }
+
+    if (*slen < sizeof(struct signal_quiesce)) {
+        event_pending = 1;
+        return 0;
+    }
+
+    sccb->c.read.quiesce.h.length = cpu_to_be16(sizeof(struct signal_quiesce));
+    sccb->c.read.quiesce.h.type = SCLP_EVENT_SIGNAL_QUIESCE;
+    sccb->c.read.quiesce.h.flags &= ~SCLP_EVENT_BUFFER_ACCEPTED;
+    /*
+     * system_powerdown does not have a timeout. Fortunately the
+     * timeout value is curently ignored by Linux, anyway
+     */
+    sccb->c.read.quiesce.timeout = cpu_to_be16(0);
+    sccb->c.read.quiesce.unit = cpu_to_be16(0);
+
+    quiesce = 0;
+    *slen -= sizeof(struct signal_quiesce);
+    return 1;
+}
+
+void sclp_enable_signal_quiesce(void)
+{
+    quiesce = 1;
+    event_pending = 1;
+}
+
+static void sclp_set_masks(void)
+{
+    SCLPS390EventFacility *evt_fac;
+
+    if (!sclp_bus) {
+        return;
+    }
+    evt_fac = sclp_bus->event_facility;
+
+    assert(evt_fac);
+
+    sclp_send_mask = sclpef_send_mask(evt_fac->sdev);
+    sclp_receive_mask = sclpef_receive_mask(evt_fac->sdev);
+ }
+
+int sclp_read_event_data(CPUS390XState *env, struct sccb *sccb)
+{
+    unsigned int sclp_active_selection_mask;
+    int slen;
+
+    if (be16_to_cpu(sccb->h.length) != SCCB_SIZE) {
+        sccb->h.response_code = cpu_to_be16(SCLP_RC_INSUFFICIENT_SCCB_LENGTH);
+        goto out;
+    }
+
+    switch (sccb->h.function_code) {
+    case SCLP_UNCONDITIONAL_READ:
+        sclp_active_selection_mask = sclp_cp_receive_mask;
+        break;
+    case SCLP_SELECTIVE_READ:
+        if (!(sclp_cp_receive_mask & be32_to_cpu(sccb->c.read.mask))) {
+            sccb->h.response_code = cpu_to_be16(SCLP_RC_INVALID_SELECTION_MASK);
+            goto out;
+        }
+        sclp_active_selection_mask = be32_to_cpu(sccb->c.read.mask);
+        break;
+    default:
+        sccb->h.response_code = cpu_to_be16(SCLP_RC_INVALID_FUNCTION);
+        goto out;
+    }
+
+    slen = sizeof(sccb->c.data);
+    sccb->h.response_code = cpu_to_be16(SCLP_RC_NO_EVENT_BUFFERS_STORED);
+
+    if (sclp_active_selection_mask & SCLP_EVENT_MASK_SIGNAL_QUIESCE) {
+        if (signal_quiesce_event(sccb, &slen)) {
+            sccb->h.response_code = cpu_to_be16(SCLP_RC_NORMAL_COMPLETION);
+        }
+    }
+
+    if (sccb->h.control_mask[2] & SCLP_VARIABLE_LENGTH_RESPONSE) {
+        sccb->h.control_mask[2] &= ~SCLP_VARIABLE_LENGTH_RESPONSE;
+        sccb->h.length = cpu_to_be16(SCCB_SIZE - slen);
+    }
+
+out:
+    return 0;
+}
+
+int sclp_write_event_mask(CPUS390XState *env, struct sccb *sccb)
+{
+    /* Attention: We assume that Linux uses 4-byte masks, what it actually
+       does. Architecture allows for masks of variable size, though */
+    if (be16_to_cpu(sccb->c.we_mask.mask_length) != 4) {
+        sccb->h.response_code = cpu_to_be16(SCLP_RC_INVALID_MASK_LENGTH);
+        goto out;
+    }
+
+    /* keep track of the guest's capability masks */
+    sclp_cp_send_mask = be32_to_cpu(sccb->c.we_mask.cp_send_mask);
+    sclp_cp_receive_mask = be32_to_cpu(sccb->c.we_mask.cp_receive_mask);
+
+    sclp_set_masks();
+
+    /* return the SCLP's capability masks to the guest */
+    sccb->c.we_mask.send_mask = cpu_to_be32(sclp_send_mask);
+    sccb->c.we_mask.receive_mask = cpu_to_be32(sclp_receive_mask);
+
+    sccb->h.response_code = cpu_to_be32(SCLP_RC_NORMAL_COMPLETION);
+
+out:
+    return 0;
+}
+
 void sclp_service_interrupt(CPUS390XState *env, uint32_t sccb)
 {
-    if (!sccb) {
+    if (!event_pending && !sccb) {
         return;
     }
 
     if (kvm_enabled()) {
 #ifdef CONFIG_KVM
         kvm_s390_interrupt_internal(env, KVM_S390_INT_SERVICE,
-                                    (sccb & ~3), 0, 1);
+                                    (sccb & ~3) + event_pending, 0, 1);
 #endif
     } else {
         env->psw.addr += 4;
-        cpu_inject_ext(env, EXT_SERVICE, (sccb & ~3), 0);
+        cpu_inject_ext(env, EXT_SERVICE, (sccb & ~3) + event_pending, 0);
+    }
+    event_pending = 0;
+}
+
+struct BusInfo s390_sclp_bus_info = {
+    .name       = "s390-sclp",
+    .size       = sizeof(SCLPS390Bus),
+};
+
+SCLPS390Bus *s390_sclp_bus_init(void)
+{
+    SCLPS390Bus *bus;
+    BusState *bus_state;
+    DeviceState *dev;
+
+    dev = qdev_create(NULL, "s390-sclp-bridge");
+    qdev_init_nofail(dev);
+    bus_state = qbus_create(&s390_sclp_bus_info, dev, "s390-sclp-bus");
+    bus = DO_UPCAST(SCLPS390Bus, bus, bus_state);
+
+    bus_state->allow_hotplug = 0;
+
+    return bus;
+}
+
+static int s390_sclp_device_init(SCLPS390EventFacility *dev, SCLPDevice *sdev)
+{
+    dev->sdev = sdev;
+
+    return 0;
+}
+
+static int s390_sclp_init(SCLPS390EventFacility *dev)
+{
+    int rc;
+    SCLPS390Bus *bus;
+    SCLPDevice *sdev;
+
+    bus = DO_UPCAST(SCLPS390Bus, bus, dev->qdev.parent_bus);
+
+    sdev = sclpef_init_event_facility((DeviceState *)dev);
+    if (!sdev) {
+        return -1;
     }
+
+    rc = s390_sclp_device_init(dev, sdev);
+    if (!rc) {
+        bus->event_facility = dev;
+    }
+
+    return rc;
+}
+
+static void s390_sclp_class_init(ObjectClass *klass, void *data)
+{
+    SCLPS390EventFacilityClass *k = SCLP_S390_EVENT_FACILITY_CLASS(klass);
+
+    k->init = s390_sclp_init;
+}
+
+static TypeInfo s390_sclp_event_facility = {
+    .name          = "sclp-event-facility",
+    .parent        = TYPE_SCLP_S390_EVENT_FACILITY,
+    .instance_size = sizeof(SCLPS390EventFacility),
+    .class_init    = s390_sclp_class_init,
+};
+
+static int s390_sclp_busdev_init(DeviceState *dev)
+{
+    SCLPS390EventFacility *_dev = (SCLPS390EventFacility *)dev;
+    SCLPS390EventFacilityClass *evt_fac =
+        SCLP_S390_EVENT_FACILITY_GET_CLASS(dev);
+
+    return evt_fac->init(_dev);
 }
 
+static void sclp_s390_device_class_init(ObjectClass *klass, void *data)
+{
+    DeviceClass *dc = DEVICE_CLASS(klass);
+
+    dc->init = s390_sclp_busdev_init;
+    dc->bus_info = &s390_sclp_bus_info;
+}
+
+static TypeInfo sclp_s390_device_info = {
+    .name = TYPE_SCLP_S390_EVENT_FACILITY,
+    .parent = TYPE_DEVICE,
+    .instance_size = sizeof(SCLPS390EventFacility),
+    .class_init = sclp_s390_device_class_init,
+    .class_size = sizeof(SCLPS390EventFacilityClass),
+    .abstract = true,
+};
+
+/***************** S390 SCLP Bus Bridge Device *******************/
+/* Only required to have the sclp bus as child in the system bus */
+
+static int s390_sclp_bridge_init(SysBusDevice *dev)
+{
+    return 0;
+}
+
+static void s390_sclp_bridge_class_init(ObjectClass *klass, void *data)
+{
+    DeviceClass *dc = DEVICE_CLASS(klass);
+    SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
+
+    k->init = s390_sclp_bridge_init;
+    dc->no_user = 1;
+}
+
+static TypeInfo s390_sclp_bridge_info = {
+    .name          = "s390-sclp-bridge",
+    .parent        = TYPE_SYS_BUS_DEVICE,
+    .instance_size = sizeof(SysBusDevice),
+    .class_init    = s390_sclp_bridge_class_init,
+};
+
+static void s390_sclp_register_types(void)
+{
+    type_register_static(&sclp_s390_device_info);
+    type_register_static(&s390_sclp_event_facility);
+    type_register_static(&s390_sclp_bridge_info);
+}
+type_init(s390_sclp_register_types)
diff --git a/hw/s390-sclp.h b/hw/s390-sclp.h
index e335b21..f61421b 100644
--- a/hw/s390-sclp.h
+++ b/hw/s390-sclp.h
@@ -1,13 +1,69 @@
 #include <stdint.h>
 #include <qemu-common.h>
 
+#include "sysbus.h"
+#include "hw/s390-event-facility.h"
 
 /* SCLP command codes */
 #define SCLP_CMDW_READ_SCP_INFO                 0x00020001
 #define SCLP_CMDW_READ_SCP_INFO_FORCED          0x00120001
+#define SCLP_CMD_WRITE_EVENT_MASK               0x00780005
 
 /* SCLP response codes */
-#define SCLP_RC_SCCB_RESOURCE_INSUFFICENT       0x07f0
+#define SCLP_RC_NORMAL_COMPLETION               0x0020
+#define SCLP_RC_INSUFFICIENT_SCCB_LENGTH        0x0300
+#define SCLP_RC_INVALID_FUNCTION                0x40f0
+#define SCLP_RC_NO_EVENT_BUFFERS_STORED         0x60f0
+#define SCLP_RC_INVALID_SELECTION_MASK          0x70f0
+#define SCLP_RC_INCONSISTENT_LENGTHS            0x72f0
+#define SCLP_RC_EVENT_BUFFER_SYNTAX_ERROR       0x73f0
+#define SCLP_RC_INVALID_MASK_LENGTH             0x74f0
+
+/* SCLP event types */
+#define SCLP_EVENT_SIGNAL_QUIESCE               0x1d
+
+/* SCLP event masks */
+#define SCLP_EVENT_MASK_SIGNAL_QUIESCE          0x00000008
+#define SCLP_EVENT_MASK_MSG                     0x40000000
+
+#define SCLP_UNCONDITIONAL_READ                 0x00
+#define SCLP_SELECTIVE_READ                     0x01
+
+#define SCLP_VARIABLE_LENGTH_RESPONSE           0x80
+
+#define SCCB_SIZE 4096
+
+/* Service Call Control Block (SCCB) and its elements */
+
+struct write_event_mask {
+    uint16_t _reserved;
+    uint16_t mask_length;
+    uint32_t cp_receive_mask;
+    uint32_t cp_send_mask;
+    uint32_t send_mask;
+    uint32_t receive_mask;
+} __attribute__((packed));
+
+struct event_buffer_header {
+    uint16_t length;
+    uint8_t  type;
+#define SCLP_EVENT_BUFFER_ACCEPTED              0x80
+    uint8_t  flags;
+    uint16_t _reserved;
+} __attribute__((packed));
+
+struct signal_quiesce {
+    struct event_buffer_header h;
+    uint16_t timeout;
+    uint8_t unit;
+} __attribute__((packed));
+
+struct read_event_data {
+    union {
+        struct signal_quiesce quiesce;
+        uint32_t mask;
+    };
+} __attribute__((packed));
 
 struct sccb_header {
     uint16_t length;
@@ -22,13 +78,51 @@ struct read_info_sccb {
     uint8_t rnsize;
 } __attribute__((packed));
 
+#define SCCB_DATA_LEN 4088
+
 struct sccb {
     struct sccb_header h;
     union {
         struct read_info_sccb read_info;
-        char data[4088];
+        struct read_event_data read;
+        struct write_event_mask we_mask;
+        char data[SCCB_DATA_LEN];
     } c;
  } __attribute__((packed));
 
+void sclp_enable_signal_quiesce(void);
 int sclp_read_info(CPUS390XState *env, struct sccb *sccb);
+int sclp_read_event_data(CPUS390XState *env, struct sccb *sccb);
+int sclp_write_event_mask(CPUS390XState *env, struct sccb *sccb);
 void sclp_service_interrupt(CPUS390XState *env, uint32_t sccb);
+
+#define TYPE_SCLP_S390_EVENT_FACILITY "s390-sclp-event-facility"
+#define SCLP_S390_EVENT_FACILITY(obj) \
+     OBJECT_CHECK(SCLPS390EventFacility, (obj), TYPE_SCLP_S390_EVENT_FACILITY)
+#define SCLP_S390_EVENT_FACILITY_CLASS(klass) \
+     OBJECT_CLASS_CHECK(SCLPS390EventFacilityClass, (klass), \
+             TYPE_SCLP_S390_EVENT_FACILITY)
+#define SCLP_S390_EVENT_FACILITY_GET_CLASS(obj) \
+     OBJECT_GET_CLASS(SCLPS390EventFacilityClass, (obj), \
+             TYPE_SCLP_S390_EVENT_FACILITY)
+
+typedef struct SCLPS390EventFacility SCLPS390EventFacility;
+
+typedef struct SCLPS390EventFacilityClass {
+    DeviceClass qdev;
+    int (*init)(SCLPS390EventFacility *dev);
+} SCLPS390EventFacilityClass;
+
+struct SCLPS390EventFacility {
+    DeviceState qdev;
+    SCLPDevice *sdev;
+};
+
+typedef struct SCLPS390Bus {
+    BusState bus;
+    SCLPS390EventFacility *event_facility;
+} SCLPS390Bus;
+
+extern SCLPS390Bus *sclp_bus;
+
+SCLPS390Bus *s390_sclp_bus_init(void);
diff --git a/hw/s390-virtio.c b/hw/s390-virtio.c
index c0e19fd..0babf27 100644
--- a/hw/s390-virtio.c
+++ b/hw/s390-virtio.c
@@ -32,6 +32,7 @@
 #include "exec-memory.h"
 
 #include "hw/s390-virtio-bus.h"
+#include "hw/s390-sclp.h"
 
 //#define DEBUG_S390
 
@@ -60,7 +61,9 @@
 
 #define MAX_BLK_DEVS                    10
 
-static VirtIOS390Bus *s390_bus;
+VirtIOS390Bus *s390_bus;
+SCLPS390Bus *sclp_bus;
+
 static CPUS390XState **ipi_states;
 
 CPUS390XState *s390_cpu_addr2state(uint16_t cpu_addr)
@@ -170,6 +173,7 @@ static void s390_init(ram_addr_t my_ram_size,
     target_phys_addr_t virtio_region_len;
     target_phys_addr_t virtio_region_start;
     int i;
+    DeviceState *dev;
 
     /* s390x ram size detection needs a 16bit multiplier + an increment. So
        guests > 64GB can be specified in 2MB steps etc. */
@@ -183,6 +187,7 @@ static void s390_init(ram_addr_t my_ram_size,
 
     /* get a BUS */
     s390_bus = s390_virtio_bus_init(&my_ram_size);
+    sclp_bus = s390_sclp_bus_init();
 
     /* allocate RAM */
     memory_region_init_ram(ram, "s390.ram", my_ram_size);
@@ -325,6 +330,10 @@ static void s390_init(ram_addr_t my_ram_size,
         qdev_prop_set_drive_nofail(dev, "drive", dinfo->bdrv);
         qdev_init_nofail(dev);
     }
+
+    dev = qdev_create((BusState *)sclp_bus, "sclp-event-facility");
+    qdev_init_nofail(dev);
+    sclpef_enable_irqs(sclp_bus->event_facility->sdev, ipi_states[0]);
 }
 
 static QEMUMachine s390_machine = {
diff --git a/target-s390x/op_helper.c b/target-s390x/op_helper.c
index 74bd9ad..3e5eff4 100644
--- a/target-s390x/op_helper.c
+++ b/target-s390x/op_helper.c
@@ -2391,6 +2391,9 @@ int sclp_service_call(CPUS390XState *env, uint32_t sccb, uint64_t code)
         case SCLP_CMDW_READ_SCP_INFO_FORCED:
             r = sclp_read_info(env, &work_sccb);
             break;
+        case SCLP_CMD_WRITE_EVENT_MASK:
+            r = sclp_write_event_mask(env, &work_sccb);
+            break;
         default:
 #ifdef DEBUG_HELPER
             printf("KVM: invalid sclp call 0x%x / 0x%" PRIx64 "x\n", sccb, code);
-- 
1.7.10.4

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

* [Qemu-devel] [PATCH 7/8] s390: Add SCLP vt220 console support
  2012-06-06 12:05 [Qemu-devel] [PATCH 0/8] s390: SCLP console and misc Jens Freimann
                   ` (5 preceding siblings ...)
  2012-06-06 12:05 ` [Qemu-devel] [PATCH 6/8] s390: sclp event facility and signal quiesce support via system_powerdown Jens Freimann
@ 2012-06-06 12:05 ` Jens Freimann
  2012-06-12 11:52   ` Alexander Graf
  2012-06-06 12:05 ` [Qemu-devel] [PATCH 8/8] s390: Fix the storage increment size calculation Jens Freimann
  2012-06-18 12:35 ` [Qemu-devel] [PATCH 0/8] s390: SCLP console and misc Christian Borntraeger
  8 siblings, 1 reply; 51+ messages in thread
From: Jens Freimann @ 2012-06-06 12:05 UTC (permalink / raw)
  To: Alexander Graf; +Cc: Cornelia Huck, Jens Freimann, Heinz Graalfs, qemu-devel

From: Heinz Graalfs <graalfs@linux.vnet.ibm.com>

Adds console support (in vt220 mode).
In order to run qemu exploiting the SCLP's console functionality in vt220 mode
the user has to specify the following console related parameters:

 -chardev stdio,id=charconsole0 -device sclpconsole,chardev=charconsole0,id=console0

Signed-off-by: Heinz Graalfs <graalfs@linux.vnet.ibm.com>
Signed-off-by: Jens Freimann <jfrei@linux.vnet.ibm.com>
---
 hw/s390-event-facility.c |  209 ++++++++++++++++++++++++++++++++++++++++++++++
 hw/s390-event-facility.h |    8 ++
 hw/s390-sclp.c           |  177 ++++++++++++++++++++++++++++++++++++++-
 hw/s390-sclp.h           |   22 ++++-
 sysemu.h                 |    1 +
 target-s390x/op_helper.c |    6 ++
 vl.c                     |   41 +++++++++
 7 files changed, 460 insertions(+), 4 deletions(-)

diff --git a/hw/s390-event-facility.c b/hw/s390-event-facility.c
index b8106a6..cfa5dd4 100644
--- a/hw/s390-event-facility.c
+++ b/hw/s390-event-facility.c
@@ -16,6 +16,11 @@
 #include "s390-sclp.h"
 #include "s390-event-facility.h"
 
+qemu_irq sclp_read_vt220;
+
+static int size_buffer = 4096;
+static char *sclp_console_data_vt220;
+
 struct SCLPDevice {
     const char *name;
     bool vm_running;
@@ -224,9 +229,213 @@ static TypeInfo sclp_quiesce_info = {
     .class_init    = sclpef_quiesce_class_init,
 };
 
+/* ----------- SCLP VT220 console ------------ */
+
+static void s390_signal_read_vt220(void *opaque, int n, int level)
+{
+    sclp_enable_signal_read_vt220();
+    sclp_service_interrupt(opaque, 0);
+}
+
+static void sclpef_set_console(SCLPEvent *event)
+{
+    if (event->id == ID_VT220) {
+        sclp_read_vt220 = *qemu_allocate_irqs(s390_signal_read_vt220,
+            event->evt_fac->opaque, 1);
+    }
+}
+
+void sclpef_write_console_vt220(SCLPDevice *sdev, char *buf)
+{
+    DeviceState *dev;
+    SCLPEventFacility *event_facility;
+    static SCLPEvent *event;
+    static SCLPEventClass *cons;
+
+    event_facility = DO_UPCAST(SCLPEventFacility, sdev, sdev);
+
+    if (!cons) {
+        QTAILQ_FOREACH(dev, &event_facility->sbus.qbus.children, sibling) {
+            event = (SCLPEvent *) dev;
+            if (event->id == ID_VT220) {
+                cons = SCLP_EVENT_GET_CLASS(event);
+                assert(cons->have_data);
+                break;
+            }
+        }
+    }
+    if (cons) {
+        cons->have_data(event, (const uint8_t *)buf, strlen(buf));
+    }
+}
+
+char *sclpef_get_console_data_vt220(SCLPDevice *sdev)
+{
+    DeviceState *dev;
+    SCLPEventFacility *event_facility;
+    SCLPEvent *event = NULL;
+    static SCLPEventClass *cons;
+
+    event_facility = DO_UPCAST(SCLPEventFacility, sdev, sdev);
+
+    if (!cons) {
+        QTAILQ_FOREACH(dev, &event_facility->sbus.qbus.children, sibling) {
+            event = (SCLPEvent *) dev;
+            if (event->id == ID_VT220) {
+                cons = SCLP_EVENT_GET_CLASS(event);
+                assert(cons->get_data);
+                break;
+            }
+        }
+    }
+    if (cons) {
+        return cons->get_data();
+    }
+    return NULL;
+}
+
+static char *console_data_vt220(void)
+{
+    return sclp_console_data_vt220;
+}
+
+static ssize_t flush_buf(SCLPEvent *event, const uint8_t *buf, size_t len)
+{
+    SCLPConsole *scon = DO_UPCAST(SCLPConsole, event, event);
+    ssize_t ret;
+
+    if (!scon->chr) {
+        /* If there's no backend, we can just say we consumed all data. */
+        return len;
+    }
+
+    ret = qemu_chr_fe_write(scon->chr, buf, len);
+
+    if (ret < 0) {
+        /* see virtio-console comments */
+        ret = 0;
+    }
+
+    return ret;
+}
+
+static void guest_open(SCLPEvent *event)
+{
+    SCLPConsole *scon = DO_UPCAST(SCLPConsole, event, event);
+
+    if (!scon->chr) {
+        return;
+    }
+    qemu_chr_fe_open(scon->chr);
+}
+
+static void guest_close(SCLPEvent *event)
+{
+    SCLPConsole *scon = DO_UPCAST(SCLPConsole, event, event);
+
+    if (!scon->chr) {
+        return;
+    }
+    qemu_chr_fe_close(scon->chr);
+}
+
+static int chr_can_read(void *opaque)
+{
+    return 1;
+}
+
+static void chr_read_vt220(void *opaque, const uint8_t *buf, int size)
+{
+    char *offset;
+
+    if (!sclp_console_data_vt220) {
+        size_buffer = 2 * size;
+        sclp_console_data_vt220 = malloc(size_buffer);
+    }
+    if (size_buffer < size + 1) {
+        free(sclp_console_data_vt220);
+        size_buffer = 2 * size;
+        sclp_console_data_vt220 = malloc(size_buffer);
+    }
+    offset = sclp_console_data_vt220;
+    if (offset) {
+        memcpy(offset, buf, size);
+        offset += size;
+        *offset = '\0';
+        qemu_irq_raise(sclp_read_vt220);
+    } else {
+        size_buffer = 0;
+    }
+}
+
+static void chr_event(void *opaque, int event)
+{
+    switch (event) {
+    case CHR_EVENT_OPENED:
+        if (!sclp_console_data_vt220) {
+            sclp_console_data_vt220 = malloc(size_buffer);
+        }
+        break;
+    case CHR_EVENT_CLOSED:
+        break;
+    }
+}
+
+static unsigned int send_mask_vt220(void)
+{
+    return SCLP_EVENT_MASK_MSG_ASCII;
+}
+
+static unsigned int receive_mask_vt220(void)
+{
+    return SCLP_EVENT_MASK_MSG_ASCII;
+}
+
+static int sclpconsole_initfn_vt220(SCLPEvent *event)
+{
+    SCLPConsole *scon = DO_UPCAST(SCLPConsole, event, event);
+
+    event->id = ID_VT220;
+    sclpef_set_console(event);
+    if (scon->chr) {
+        qemu_chr_add_handlers(scon->chr, chr_can_read,
+                chr_read_vt220, chr_event, scon);
+    }
+
+    return 0;
+}
+
+static Property sclpconsole_properties[] = {
+    DEFINE_PROP_CHR("chardev", SCLPConsole, chr),
+    DEFINE_PROP_END_OF_LIST(),
+};
+
+static void sclpconsole_class_init(ObjectClass *klass, void *data)
+{
+    DeviceClass *dc = DEVICE_CLASS(klass);
+    SCLPEventClass *k = SCLP_EVENT_CLASS(klass);
+
+    k->init = sclpconsole_initfn_vt220;
+    k->have_data = flush_buf;
+    k->guest_open = guest_open;
+    k->guest_close = guest_close;
+    k->get_send_mask = send_mask_vt220;
+    k->get_receive_mask = receive_mask_vt220;
+    k->get_data = console_data_vt220;
+    dc->props = sclpconsole_properties;
+}
+
+static TypeInfo sclpconsole_info = {
+    .name          = "sclpconsole",
+    .parent        = TYPE_SCLP_EVENT,
+    .instance_size = sizeof(SCLPConsole),
+    .class_init    = sclpconsole_class_init,
+};
+
 static void sclpef_register_types(void)
 {
     type_register_static(&sclp_event_facility_type_info);
     type_register_static(&sclp_quiesce_info);
+    type_register_static(&sclpconsole_info);
 }
 type_init(sclpef_register_types)
diff --git a/hw/s390-event-facility.h b/hw/s390-event-facility.h
index 40d4049..d6bde7d 100644
--- a/hw/s390-event-facility.h
+++ b/hw/s390-event-facility.h
@@ -14,6 +14,7 @@
 #include "qemu-common.h"
 
 #define ID_QUIESCE SCLP_EVENT_SIGNAL_QUIESCE
+#define ID_VT220   SCLP_EVENT_ASCII_CONSOLE_DATA
 
 #define TYPE_SCLP_EVENT "s390-sclp-event-type"
 #define SCLP_EVENT(obj) \
@@ -34,6 +35,11 @@ typedef struct SCLPEventClass {
     int (*exit)(SCLPEvent *event);
     unsigned int (*get_send_mask)(void);
     unsigned int (*get_receive_mask)(void);
+    void (*guest_open)(SCLPEvent *event);
+    void (*guest_close)(SCLPEvent *event);
+    void (*guest_ready)(SCLPEvent *event);
+    ssize_t (*have_data)(SCLPEvent *event, const uint8_t *buf, size_t len);
+    char *(*get_data)(void);
 } SCLPEventClass;
 
 struct SCLPEvent {
@@ -50,5 +56,7 @@ void sclpef_enable_irqs(SCLPDevice *sdev, void *opaque);
 void sclpef_set_masks(void);
 unsigned int sclpef_send_mask(SCLPDevice *sdev);
 unsigned int sclpef_receive_mask(SCLPDevice *sdev);
+void sclpef_write_console_vt220(SCLPDevice *sdev, char *buf);
+char *sclpef_get_console_data_vt220(SCLPDevice *sdev);
 
 #endif
diff --git a/hw/s390-sclp.c b/hw/s390-sclp.c
index 683a709..8f45773 100644
--- a/hw/s390-sclp.c
+++ b/hw/s390-sclp.c
@@ -11,6 +11,11 @@
 #include "hw/s390-sclp.h"
 #include "hw/s390-event-facility.h"
 
+/* input buffer handling */
+#define INP_BUFFER_SIZE 4096
+static int sclp_curr_buf_size;
+static char *sclp_input_vt220;
+
 /* Host capabilites */
 static unsigned int sclp_send_mask;
 static unsigned int sclp_receive_mask;
@@ -21,6 +26,7 @@ static unsigned int sclp_cp_receive_mask;
 
 static int quiesce;
 static int event_pending;
+static int vt220;
 
 int sclp_read_info(CPUS390XState *env, struct sccb *sccb)
 {
@@ -66,6 +72,7 @@ void sclp_enable_signal_quiesce(void)
 {
     quiesce = 1;
     event_pending = 1;
+    vt220 = 0;
 }
 
 static void sclp_set_masks(void)
@@ -81,7 +88,112 @@ static void sclp_set_masks(void)
 
     sclp_send_mask = sclpef_send_mask(evt_fac->sdev);
     sclp_receive_mask = sclpef_receive_mask(evt_fac->sdev);
- }
+}
+
+static int signal_vt220_event(struct sccb *sccb, int *slen)
+{
+    char *p;
+
+    if (!sclp_input_vt220 || !vt220) {
+        return 0;
+    }
+
+    int l = strlen(sclp_input_vt220);
+
+    if (*slen < sizeof(struct ascii_cons_data_command) + l + 1) {
+        event_pending = 1;
+        return 0;
+    }
+    p = (char *)&sccb->c.read.acd_cmd.data;
+    /* first byte is hex 0 saying an ascii string follows */
+    *p++ = '\0';
+    memmove(p, sclp_input_vt220, l);
+    *sclp_input_vt220 = '\0';
+
+    sccb->c.read.acd_cmd.h.length =
+            cpu_to_be16(sizeof(struct ascii_cons_data_command) + l + 1);
+    sccb->c.read.acd_cmd.h.type = SCLP_EVENT_ASCII_CONSOLE_DATA;
+
+    vt220 = 0;
+    *slen -= sizeof(struct ascii_cons_data_command) + l + 1;
+    return 1;
+}
+
+static char *grow_buffer(int size)
+{
+    char *p = (char *) malloc(size);
+
+    if (!p) {
+        sclp_curr_buf_size = 0;
+        return NULL;
+    }
+    memset(p, '\0', size);
+    sclp_curr_buf_size = size;
+    return p;
+}
+
+static int sclp_write_vt220(struct event_buffer_header *event)
+{
+    int l;
+    char *msg;
+    SCLPS390EventFacility *evt_fac;
+    struct ascii_cons_data_command *ad =
+            (struct ascii_cons_data_command *) event;
+
+    assert(sclp_bus);
+
+    l = event->length - sizeof(struct event_buffer_header);
+    msg = (char *) malloc(l + 1);
+    assert(msg);
+    memset(msg, '\0', l + 1);
+    memmove(msg, ad->data, l);
+
+    evt_fac = sclp_bus->event_facility;
+    sclpef_write_console_vt220(evt_fac->sdev, msg);
+
+    free(msg);
+
+    return SCLP_RC_NORMAL_COMPLETION;
+}
+
+void sclp_enable_signal_read_vt220(void)
+{
+    int len;
+    char *input;
+    SCLPS390EventFacility *evt_fac;
+
+    if (!sclp_bus) {
+        return;
+    }
+    evt_fac = sclp_bus->event_facility;
+
+    assert(evt_fac);
+
+    input = sclpef_get_console_data_vt220(evt_fac->sdev);
+
+    if (!input) {
+        return;
+    }
+
+    vt220 = 1;
+    quiesce = 0;
+    event_pending = 1;
+    len = strlen((char *) input);
+    if (sclp_input_vt220 == NULL) {
+        /* get new buffer */
+        sclp_input_vt220 = grow_buffer(2 * len + 1);
+    } else {
+        if (len >= sclp_curr_buf_size) {
+            /* get larger buffer */
+            char *p = grow_buffer(2 * len + 1);
+            free(sclp_input_vt220);
+            sclp_input_vt220 = p;
+        }
+    }
+    if (sclp_input_vt220) {
+        strcat(sclp_input_vt220, (char *)input);
+    }
+}
 
 int sclp_read_event_data(CPUS390XState *env, struct sccb *sccb)
 {
@@ -99,7 +211,8 @@ int sclp_read_event_data(CPUS390XState *env, struct sccb *sccb)
         break;
     case SCLP_SELECTIVE_READ:
         if (!(sclp_cp_receive_mask & be32_to_cpu(sccb->c.read.mask))) {
-            sccb->h.response_code = cpu_to_be16(SCLP_RC_INVALID_SELECTION_MASK);
+            sccb->h.response_code =
+                    cpu_to_be16(SCLP_RC_INVALID_SELECTION_MASK);
             goto out;
         }
         sclp_active_selection_mask = be32_to_cpu(sccb->c.read.mask);
@@ -117,7 +230,12 @@ int sclp_read_event_data(CPUS390XState *env, struct sccb *sccb)
             sccb->h.response_code = cpu_to_be16(SCLP_RC_NORMAL_COMPLETION);
         }
     }
-
+    if (sclp_active_selection_mask & SCLP_EVENT_MASK_MSG_ASCII) {
+        if (signal_vt220_event(sccb, &slen)) {
+            sccb->h.response_code = cpu_to_be16(SCLP_RC_NORMAL_COMPLETION);
+            sccb->h.length = cpu_to_be16(SCCB_SIZE - slen);
+        }
+    }
     if (sccb->h.control_mask[2] & SCLP_VARIABLE_LENGTH_RESPONSE) {
         sccb->h.control_mask[2] &= ~SCLP_VARIABLE_LENGTH_RESPONSE;
         sccb->h.length = cpu_to_be16(SCCB_SIZE - slen);
@@ -127,6 +245,59 @@ out:
     return 0;
 }
 
+int sclp_write_event_data(CPUS390XState *env, struct sccb *sccb)
+{
+    struct event_buffer_header *event;
+    int slen;
+    unsigned elen = 0;
+
+    if (sccb->h.function_code != SCLP_FC_NORMAL_WRITE) {
+        sccb->h.response_code = cpu_to_be16(SCLP_RC_INVALID_FUNCTION);
+        goto out;
+    }
+    if (be16_to_cpu(sccb->h.length) < 8) {
+        sccb->h.response_code = cpu_to_be16(SCLP_RC_INSUFFICIENT_SCCB_LENGTH);
+        goto out;
+    }
+
+    /* first check the sum of all events */
+    event = &sccb->c.event;
+    for (slen = be16_to_cpu(sccb->h.length) - sizeof(sccb->h);
+         slen > 0; slen -= elen) {
+        elen = be16_to_cpu(event->length);
+        if (elen < sizeof(*event) || elen > slen) {
+            sccb->h.response_code =
+                    cpu_to_be16(SCLP_RC_EVENT_BUFFER_SYNTAX_ERROR);
+            goto out;
+        }
+        event = (void *) event + elen;
+    }
+    if (slen) {
+        sccb->h.response_code = cpu_to_be16(SCLP_RC_INCONSISTENT_LENGTHS);
+        goto out;
+    }
+
+    /* the execute */
+    event = &sccb->c.event;
+    for (slen = be16_to_cpu(sccb->h.length) - sizeof(sccb->h);
+         slen > 0; slen -= elen) {
+        elen = be16_to_cpu(event->length);
+        switch (event->type) {
+        case SCLP_EVENT_ASCII_CONSOLE_DATA:
+            sccb->h.response_code = cpu_to_be16(sclp_write_vt220(event));
+            break;
+        default:
+            sccb->h.response_code = SCLP_RC_INVALID_FUNCTION;
+            break;
+        }
+        event = (void *) event + elen;
+    }
+    sccb->h.response_code = SCLP_RC_NORMAL_COMPLETION;
+
+out:
+    return 0;
+}
+
 int sclp_write_event_mask(CPUS390XState *env, struct sccb *sccb)
 {
     /* Attention: We assume that Linux uses 4-byte masks, what it actually
diff --git a/hw/s390-sclp.h b/hw/s390-sclp.h
index f61421b..c86bca8 100644
--- a/hw/s390-sclp.h
+++ b/hw/s390-sclp.h
@@ -7,6 +7,8 @@
 /* SCLP command codes */
 #define SCLP_CMDW_READ_SCP_INFO                 0x00020001
 #define SCLP_CMDW_READ_SCP_INFO_FORCED          0x00120001
+#define SCLP_CMD_READ_EVENT_DATA                0x00770005
+#define SCLP_CMD_WRITE_EVENT_DATA               0x00760005
 #define SCLP_CMD_WRITE_EVENT_MASK               0x00780005
 
 /* SCLP response codes */
@@ -20,11 +22,12 @@
 #define SCLP_RC_INVALID_MASK_LENGTH             0x74f0
 
 /* SCLP event types */
+#define SCLP_EVENT_ASCII_CONSOLE_DATA           0x1a
 #define SCLP_EVENT_SIGNAL_QUIESCE               0x1d
 
 /* SCLP event masks */
 #define SCLP_EVENT_MASK_SIGNAL_QUIESCE          0x00000008
-#define SCLP_EVENT_MASK_MSG                     0x40000000
+#define SCLP_EVENT_MASK_MSG_ASCII               0x00000040
 
 #define SCLP_UNCONDITIONAL_READ                 0x00
 #define SCLP_SELECTIVE_READ                     0x01
@@ -44,6 +47,13 @@ struct write_event_mask {
     uint32_t receive_mask;
 } __attribute__((packed));
 
+struct mdb_header {
+    uint16_t length;
+    uint16_t type;
+    uint32_t tag;
+    uint32_t revision_code;
+} __attribute__((packed));
+
 struct event_buffer_header {
     uint16_t length;
     uint8_t  type;
@@ -58,9 +68,15 @@ struct signal_quiesce {
     uint8_t unit;
 } __attribute__((packed));
 
+struct ascii_cons_data_command {
+    struct event_buffer_header h;
+    char data[0];
+} __attribute__((packed));
+
 struct read_event_data {
     union {
         struct signal_quiesce quiesce;
+        struct ascii_cons_data_command acd_cmd;
         uint32_t mask;
     };
 } __attribute__((packed));
@@ -84,15 +100,19 @@ struct sccb {
     struct sccb_header h;
     union {
         struct read_info_sccb read_info;
+        struct event_buffer_header event;
         struct read_event_data read;
+        struct ascii_cons_data_command acd_cmd;
         struct write_event_mask we_mask;
         char data[SCCB_DATA_LEN];
     } c;
  } __attribute__((packed));
 
 void sclp_enable_signal_quiesce(void);
+void sclp_enable_signal_read_vt220(void);
 int sclp_read_info(CPUS390XState *env, struct sccb *sccb);
 int sclp_read_event_data(CPUS390XState *env, struct sccb *sccb);
+int sclp_write_event_data(CPUS390XState *env, struct sccb *sccb);
 int sclp_write_event_mask(CPUS390XState *env, struct sccb *sccb);
 void sclp_service_interrupt(CPUS390XState *env, uint32_t sccb);
 
diff --git a/sysemu.h b/sysemu.h
index bc2c788..b4d399c 100644
--- a/sysemu.h
+++ b/sysemu.h
@@ -62,6 +62,7 @@ int qemu_powerdown_requested(void);
 void qemu_system_killed(int signal, pid_t pid);
 void qemu_kill_report(void);
 extern qemu_irq qemu_system_powerdown;
+extern qemu_irq sclp_read_vt220;
 void qemu_system_reset(bool report);
 
 void qemu_add_exit_notifier(Notifier *notify);
diff --git a/target-s390x/op_helper.c b/target-s390x/op_helper.c
index 3e5eff4..4d49472 100644
--- a/target-s390x/op_helper.c
+++ b/target-s390x/op_helper.c
@@ -2391,6 +2391,12 @@ int sclp_service_call(CPUS390XState *env, uint32_t sccb, uint64_t code)
         case SCLP_CMDW_READ_SCP_INFO_FORCED:
             r = sclp_read_info(env, &work_sccb);
             break;
+        case SCLP_CMD_READ_EVENT_DATA:
+            r = sclp_read_event_data(env, &work_sccb);
+            break;
+        case SCLP_CMD_WRITE_EVENT_DATA:
+            r = sclp_write_event_data(env, &work_sccb);
+            break;
         case SCLP_CMD_WRITE_EVENT_MASK:
             r = sclp_write_event_mask(env, &work_sccb);
             break;
diff --git a/vl.c b/vl.c
index 23ab3a3..aba7ab0 100644
--- a/vl.c
+++ b/vl.c
@@ -174,6 +174,7 @@ int main(int argc, char **argv)
 #define DEFAULT_RAM_SIZE 128
 
 #define MAX_VIRTIO_CONSOLES 1
+#define MAX_SCLP_CONSOLES   1
 
 static const char *data_dir;
 const char *bios_name = NULL;
@@ -201,6 +202,7 @@ int no_quit = 0;
 CharDriverState *serial_hds[MAX_SERIAL_PORTS];
 CharDriverState *parallel_hds[MAX_PARALLEL_PORTS];
 CharDriverState *virtcon_hds[MAX_VIRTIO_CONSOLES];
+CharDriverState *sclpcon_hds[MAX_SCLP_CONSOLES];
 int win2k_install_hack = 0;
 int usb_enabled = 0;
 int singlestep = 0;
@@ -274,6 +276,8 @@ static int default_floppy = 1;
 static int default_cdrom = 1;
 static int default_sdcard = 1;
 static int default_vga = 1;
+static int default_sclpcon = 1;
+static int default_loader = 1;
 
 static struct {
     const char *driver;
@@ -295,6 +299,8 @@ static struct {
     { .driver = "isa-cirrus-vga",       .flag = &default_vga       },
     { .driver = "vmware-svga",          .flag = &default_vga       },
     { .driver = "qxl-vga",              .flag = &default_vga       },
+    { .driver = "s390-sclp",            .flag = &default_sclpcon   },
+    { .driver = "s390-ipl",             .flag = &default_loader    },
 };
 
 static void res_free(void)
@@ -1942,6 +1948,7 @@ struct device_config {
         DEV_VIRTCON,   /* -virtioconsole */
         DEV_DEBUGCON,  /* -debugcon */
         DEV_GDB,       /* -gdb, -s */
+        DEV_SCLPCON,   /* sclp console */
     } type;
     const char *cmdline;
     Location loc;
@@ -2058,6 +2065,36 @@ static int virtcon_parse(const char *devname)
     return 0;
 }
 
+static int sclpcon_parse(const char *devname)
+{
+    QemuOptsList *device = qemu_find_opts("device");
+    static int index;
+    char label[32];
+    QemuOpts *dev_opts;
+
+    if (strcmp(devname, "none") == 0)
+        return 0;
+    if (index == MAX_SCLP_CONSOLES) {
+        fprintf(stderr, "qemu: too many sclp consoles\n");
+        exit(1);
+    }
+
+    dev_opts = qemu_opts_create(device, NULL, 0);
+    qemu_opt_set(dev_opts, "driver", "sclpconsole");
+
+    snprintf(label, sizeof(label), "sclpcon%d", index);
+    sclpcon_hds[index] = qemu_chr_new(label, devname, NULL);
+    if (!sclpcon_hds[index]) {
+        fprintf(stderr, "qemu: could not open sclp console '%s': %s\n",
+                devname, strerror(errno));
+        return -1;
+    }
+    qemu_opt_set(dev_opts, "chardev", label);
+
+    index++;
+    return 0;
+}
+
 static int debugcon_parse(const char *devname)
 {   
     QemuOpts *opts;
@@ -3304,6 +3341,8 @@ int main(int argc, char **argv, char **envp)
             add_device_config(DEV_SERIAL, "mon:stdio");
         } else if (default_virtcon && default_monitor) {
             add_device_config(DEV_VIRTCON, "mon:stdio");
+        } else if (default_sclpcon && default_monitor) {
+            add_device_config(DEV_SCLPCON, "mon:stdio");
         } else {
             if (default_serial)
                 add_device_config(DEV_SERIAL, "stdio");
@@ -3491,6 +3530,8 @@ int main(int argc, char **argv, char **envp)
         exit(1);
     if (foreach_device_config(DEV_VIRTCON, virtcon_parse) < 0)
         exit(1);
+    if (foreach_device_config(DEV_SCLPCON, sclpcon_parse) < 0)
+        exit(1);
     if (foreach_device_config(DEV_DEBUGCON, debugcon_parse) < 0)
         exit(1);
 
-- 
1.7.10.4

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

* [Qemu-devel] [PATCH 8/8] s390: Fix the storage increment size calculation
  2012-06-06 12:05 [Qemu-devel] [PATCH 0/8] s390: SCLP console and misc Jens Freimann
                   ` (6 preceding siblings ...)
  2012-06-06 12:05 ` [Qemu-devel] [PATCH 7/8] s390: Add SCLP vt220 console support Jens Freimann
@ 2012-06-06 12:05 ` Jens Freimann
  2012-06-12 11:53   ` Alexander Graf
  2012-06-18 12:35 ` [Qemu-devel] [PATCH 0/8] s390: SCLP console and misc Christian Borntraeger
  8 siblings, 1 reply; 51+ messages in thread
From: Jens Freimann @ 2012-06-06 12:05 UTC (permalink / raw)
  To: Alexander Graf
  Cc: Cornelia Huck, Nick Wang, Jens Freimann, Heinz Graalfs, qemu-devel

From: Nick Wang <jfwang@us.ibm.com>

To comply with the SCLP architecture, the number of storage
increments should be 512 or fewer. The increment size is a
multiple of 1M and is a power of 2.

Signed-off-by: Nick Wang <jfwang@us.ibm.com>
Signed-off-by: Jens Freimann <jfrei@linux.vnet.ibm.com>
---
 hw/s390-sclp.c   |    2 +-
 hw/s390-virtio.c |    6 +++---
 2 files changed, 4 insertions(+), 4 deletions(-)

diff --git a/hw/s390-sclp.c b/hw/s390-sclp.c
index 8f45773..3e91f93 100644
--- a/hw/s390-sclp.c
+++ b/hw/s390-sclp.c
@@ -32,7 +32,7 @@ int sclp_read_info(CPUS390XState *env, struct sccb *sccb)
 {
     int shift = 0;
 
-    while ((ram_size >> (20 + shift)) > 65535) {
+    while ((ram_size >> (20 + shift)) > 512) {
         shift++;
     }
     sccb->c.read_info.rnmax = cpu_to_be16(ram_size >> (20 + shift));
diff --git a/hw/s390-virtio.c b/hw/s390-virtio.c
index 0babf27..9578d15 100644
--- a/hw/s390-virtio.c
+++ b/hw/s390-virtio.c
@@ -175,9 +175,9 @@ static void s390_init(ram_addr_t my_ram_size,
     int i;
     DeviceState *dev;
 
-    /* s390x ram size detection needs a 16bit multiplier + an increment. So
-       guests > 64GB can be specified in 2MB steps etc. */
-    while ((my_ram_size >> (20 + shift)) > 65535) {
+    /* The storage increment size is a multiple of 1M and is a power of 2.
+     * The number of storage increments must be 512 or fewer. */
+    while ((my_ram_size >> (20 + shift)) > 512) {
         shift++;
     }
     my_ram_size = my_ram_size >> (20 + shift) << (20 + shift);
-- 
1.7.10.4

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

* Re: [Qemu-devel] [PATCH 2/8] s390: autodetect map private
  2012-06-06 12:05 ` [Qemu-devel] [PATCH 2/8] s390: autodetect map private Jens Freimann
@ 2012-06-12  9:32   ` Alexander Graf
  2012-06-12 11:20     ` Christian Borntraeger
  0 siblings, 1 reply; 51+ messages in thread
From: Alexander Graf @ 2012-06-12  9:32 UTC (permalink / raw)
  To: Jens Freimann
  Cc: Cornelia Huck, Christian Borntraeger, Jens Freimann,
	Heinz Graalfs, qemu-devel

Jens Freimann wrote:
> From: Christian Borntraeger <borntraeger@de.ibm.com>
>
> By default qemu will use MAP_PRIVATE for guest pages. This will write
> protect pages and thus break on s390 systems that dont support this feature.
> Therefore qemu has a hack to always use MAP_SHARED for s390. But MAP_SHARED
> has other problems (no dirty pages tracking, a lot more swap overhead etc.)
> Newer systems allow the distinction via KVM_CAP_S390_COW. With this feature
> qemu can use the standard qemu alloc if available, otherwise it will use
> the old s390 hack.
>
> Signed-off-by: Christian Borntraeger <borntraeger@de.ibm.com>
> Signed-off-by: Jens Freimann <jfrei@linux.vnet.ibm.com>
> ---
>  exec.c             |   54 +++++++++++++++++++++++++++++++++++++---------------
>  kvm.h              |    9 +++++++++
>  oslib-posix.c      |    3 +++
>  target-s390x/kvm.c |    6 ++++++
>  4 files changed, 57 insertions(+), 15 deletions(-)
>
> diff --git a/exec.c b/exec.c
> index a0494c7..8fec680 100644
> --- a/exec.c
> +++ b/exec.c
> @@ -2618,6 +2618,43 @@ void qemu_ram_set_idstr(ram_addr_t addr, const char *name, DeviceState *dev)
>      }
>  }
>  
> +/*
> + * lets make sure that we dont have the old s390x limitations regarding
> + * guest mappings
> + */
> +static int legacy_s390x_mem_layout(void)
> +{
> +#if defined(TARGET_S390X)
> +    return kvm_has_legacy_s390x_memlayout();
> +#else
> +    return 0;
> +#endif
> +}
> +
> +/*
> + * Legacy layout for s390:
> + * Older S390 KVM requires the topmost vma of the RAM to be
> + * smaller than an system defined value, which is at least 256GB.
> + * Larger systems have larger values. We put the guest between
> + * the end of data segment (system break) and this value. We
> + * use 32GB as a base to have enough room for the system break
> + * to grow. We also have to use MAP parameters that avoid
> + * read-only mapping of guest pages.
> + */
> +static void *legacy_s390_alloc(ram_addr_t size)
> +{
> +    void *mem;
> +
> +    mem = mmap((void *) 0x800000000ULL, size,
> +               PROT_EXEC|PROT_READ|PROT_WRITE,
> +               MAP_SHARED | MAP_ANONYMOUS | MAP_FIXED, -1, 0);
> +    if (mem == MAP_FAILED) {
> +        fprintf(stderr, "Allocating RAM failed\n");
> +        abort();
> +    }
> +    return mem;
> +}
> +
>   

Is there any way we can move the above code to target-s390x? Having the
branch below is already invasive enough for generic code, but we really
don't need all the special s390 quirks to live here.

>  ram_addr_t qemu_ram_alloc_from_ptr(ram_addr_t size, void *host,
>                                     MemoryRegion *mr)
>  {
> @@ -2644,26 +2681,13 @@ ram_addr_t qemu_ram_alloc_from_ptr(ram_addr_t size, void *host,
>              exit(1);
>  #endif
>          } else {
> -#if defined(TARGET_S390X) && defined(CONFIG_KVM)
> -            /* S390 KVM requires the topmost vma of the RAM to be smaller than
> -               an system defined value, which is at least 256GB. Larger systems
> -               have larger values. We put the guest between the end of data
> -               segment (system break) and this value. We use 32GB as a base to
> -               have enough room for the system break to grow. */
> -            new_block->host = mmap((void*)0x800000000, size,
> -                                   PROT_EXEC|PROT_READ|PROT_WRITE,
> -                                   MAP_SHARED | MAP_ANONYMOUS | MAP_FIXED, -1, 0);
> -            if (new_block->host == MAP_FAILED) {
> -                fprintf(stderr, "Allocating RAM failed\n");
> -                abort();
> -            }
> -#else
>              if (xen_enabled()) {
>                  xen_ram_alloc(new_block->offset, size, mr);
>   
#ifdef TARGET_S390X
> +            } else if (legacy_s390x_mem_layout()) {
> +                new_block->host = legacy_s390_alloc(size);
>   
#endif

maybe? That way you could move everything to target-s390x.
>              } else {
>                  new_block->host = qemu_vmalloc(size);
>              }
> -#endif
>              qemu_madvise(new_block->host, size, QEMU_MADV_MERGEABLE);
>          }
>      }
> diff --git a/kvm.h b/kvm.h
> index 9c7b0ea..ca0557e 100644
> --- a/kvm.h
> +++ b/kvm.h
> @@ -62,6 +62,15 @@ int kvm_has_pit_state2(void);
>  int kvm_has_many_ioeventfds(void);
>  int kvm_has_gsi_routing(void);
>  
> +#ifndef CONFIG_KVM 
> +static inline int kvm_has_legacy_s390x_memlayout(void)
>   

An s390 function in generic kvm.h? No way :)

> +{
> +    return 0;
> +}
> +#else
> +int kvm_has_legacy_s390x_memlayout(void);
> +#endif
> +
>  int kvm_allows_irq0_override(void);
>  
>  #ifdef NEED_CPU_H
> diff --git a/oslib-posix.c b/oslib-posix.c
> index b6a3c7f..93902ac 100644
> --- a/oslib-posix.c
> +++ b/oslib-posix.c
> @@ -41,6 +41,9 @@ extern int daemon(int, int);
>        therefore we need special code which handles running on Valgrind. */
>  #  define QEMU_VMALLOC_ALIGN (512 * 4096)
>  #  define CONFIG_VALGRIND
> +#elif defined(__linux__) && defined(__s390x__)
> +   /* Use 1 MiB (segment size) alignment so gmap can be used by KVM. */
> +#  define QEMU_VMALLOC_ALIGN (256 * 4096)
>  #else
>  #  define QEMU_VMALLOC_ALIGN getpagesize()
>  #endif
> diff --git a/target-s390x/kvm.c b/target-s390x/kvm.c
> index 90aad61..93a8431 100644
> --- a/target-s390x/kvm.c
> +++ b/target-s390x/kvm.c
> @@ -135,6 +135,12 @@ int kvm_arch_get_registers(CPUS390XState *env)
>      return 0;
>  }
>  
> +int kvm_has_legacy_s390x_memlayout(void)
> +{
> +    return !kvm_check_extension(kvm_state, KVM_CAP_S390_GMAP) ||
> +           !kvm_check_extension(kvm_state, KVM_CAP_S390_COW);
> +}
> +
>  int kvm_arch_insert_sw_breakpoint(CPUS390XState *env, struct kvm_sw_breakpoint *bp)
>  {
>      static const uint8_t diag_501[] = {0x83, 0x24, 0x05, 0x01};
>   

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

* Re: [Qemu-devel] [PATCH 4/8] s390: stop target cpu on sigp initial reset
  2012-06-06 12:05 ` [Qemu-devel] [PATCH 4/8] s390: stop target cpu on sigp initial reset Jens Freimann
@ 2012-06-12  9:42   ` Alexander Graf
  2012-06-12 10:15     ` Christian Borntraeger
  0 siblings, 1 reply; 51+ messages in thread
From: Alexander Graf @ 2012-06-12  9:42 UTC (permalink / raw)
  To: Jens Freimann
  Cc: Cornelia Huck, Christian Borntraeger, Jens Freimann,
	Heinz Graalfs, qemu-devel

Jens Freimann wrote:
> From: Christian Borntraeger <borntraeger@de.ibm.com>
>
> We must not run the target cpu after an initial reset. This makes
> system_reset more reliable for smp guests.
>   

Why?

Alex

> Signed-off-by: Christian Borntraeger <borntraeger@de.ibm.com>
> ---
>  target-s390x/kvm.c |    1 +
>  1 file changed, 1 insertion(+)
>
> diff --git a/target-s390x/kvm.c b/target-s390x/kvm.c
> index 93a8431..73cfd1f 100644
> --- a/target-s390x/kvm.c
> +++ b/target-s390x/kvm.c
> @@ -318,6 +318,7 @@ static int s390_cpu_initial_reset(CPUS390XState *env)
>  {
>      int i;
>  
> +    s390_del_running_cpu(env);
>      if (kvm_vcpu_ioctl(env, KVM_S390_INITIAL_RESET, NULL) < 0) {
>          perror("cannot init reset vcpu");
>      }
>   

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

* Re: [Qemu-devel] [PATCH 5/8] s390: Cleanup sclp functions
  2012-06-06 12:05 ` [Qemu-devel] [PATCH 5/8] s390: Cleanup sclp functions Jens Freimann
@ 2012-06-12  9:58   ` Alexander Graf
  2012-06-12 10:07     ` Christian Borntraeger
  2012-06-12 12:24     ` Christian Borntraeger
  2012-06-12 22:38   ` Anthony Liguori
  1 sibling, 2 replies; 51+ messages in thread
From: Alexander Graf @ 2012-06-12  9:58 UTC (permalink / raw)
  To: Jens Freimann
  Cc: Heinz Graalfs, qemu-devel, Christian Borntraeger, Jens Freimann,
	Cornelia Huck, Andreas Färber

Jens Freimann wrote:
> From: Christian Borntraeger <borntraeger@de.ibm.com>
>
> The sclp facility on s390 is a hardware that is external to the cpu.
> Lets cleanup the definitions and move the functionality into a separate
> file under hw/.
>   

Phew. I'm not sure this is a great idea. At least not the way the code
is structured now. Andreas, do you have any idea how to get this done
nicely? We'd have to invent our own bus to communicate to the device,
right? And then also actually spawn one.

> Signed-off-by: Christian Borntraeger <borntraeger@de.ibm.com>
> Signed-off-by: Jens Freimann <jfrei@de.ibm.com>
> ---
>  Makefile.target          |    2 +-
>  hw/s390-sclp.c           |   42 ++++++++++++++++++++++++++++++++++++++++++
>  hw/s390-sclp.h           |   34 ++++++++++++++++++++++++++++++++++
>  target-s390x/cpu.h       |   11 -----------
>  target-s390x/kvm.c       |    5 ++---
>  target-s390x/op_helper.c |   39 +++++++++++++++++----------------------
>  6 files changed, 96 insertions(+), 37 deletions(-)
>  create mode 100644 hw/s390-sclp.c
>  create mode 100644 hw/s390-sclp.h
>
> diff --git a/Makefile.target b/Makefile.target
> index 1582904..fed2d72 100644
> --- a/Makefile.target
> +++ b/Makefile.target
> @@ -374,7 +374,7 @@ obj-sh4-y += ide/mmio.o
>  obj-m68k-y = an5206.o mcf5206.o mcf_uart.o mcf_intc.o mcf5208.o mcf_fec.o
>  obj-m68k-y += m68k-semi.o dummy_m68k.o
>  
> -obj-s390x-y = s390-virtio-bus.o s390-virtio.o
> +obj-s390x-y = s390-virtio-bus.o s390-virtio.o s390-sclp.o
>  
>  obj-alpha-y = mc146818rtc.o
>  obj-alpha-y += alpha_pci.o alpha_dp264.o alpha_typhoon.o
> diff --git a/hw/s390-sclp.c b/hw/s390-sclp.c
> new file mode 100644
> index 0000000..c046441
> --- /dev/null
> +++ b/hw/s390-sclp.c
> @@ -0,0 +1,42 @@
> +/*
> + * sclp facility
> + * Copyright IBM Corp. 2012
> + * Author: Christian Borntraeger <borntraeger@de.ibm.com>
> + *
> + */
> +
> +#include "cpu.h"
> +#include "kvm.h"
> +#include "hw/s390-sclp.h"
>   

No need for hw/.

> +
> +int sclp_read_info(CPUS390XState *env, struct sccb *sccb)
> +{
> +    int shift = 0;
> +
> +    while ((ram_size >> (20 + shift)) > 65535) {
> +        shift++;
> +    }
> +    sccb->c.read_info.rnmax = cpu_to_be16(ram_size >> (20 + shift));
> +    sccb->c.read_info.rnsize = 1 << shift;
> +    sccb->h.response_code = cpu_to_be16(0x10);
> +
> +    return 0;
> +}
> +
> +void sclp_service_interrupt(CPUS390XState *env, uint32_t sccb)
> +{
> +    if (!sccb) {
> +        return;
> +    }
> +
> +    if (kvm_enabled()) {
> +#ifdef CONFIG_KVM
>   

You shouldn't know about CONFIG_KVM in hw/. So we have to generalize
this code.

> +        kvm_s390_interrupt_internal(env, KVM_S390_INT_SERVICE,
> +                                    (sccb & ~3), 0, 1);
> +#endif
> +    } else {
> +        env->psw.addr += 4;
> +        cpu_inject_ext(env, EXT_SERVICE, (sccb & ~3), 0);
> +    }
> +}
> +
> diff --git a/hw/s390-sclp.h b/hw/s390-sclp.h
> new file mode 100644
> index 0000000..e335b21
> --- /dev/null
> +++ b/hw/s390-sclp.h
> @@ -0,0 +1,34 @@
> +#include <stdint.h>
> +#include <qemu-common.h>
> +
> +
> +/* SCLP command codes */
> +#define SCLP_CMDW_READ_SCP_INFO                 0x00020001
> +#define SCLP_CMDW_READ_SCP_INFO_FORCED          0x00120001
> +
> +/* SCLP response codes */
> +#define SCLP_RC_SCCB_RESOURCE_INSUFFICENT       0x07f0
> +
> +struct sccb_header {
> +    uint16_t length;
> +#define SCLP_FC_NORMAL_WRITE                    0
>   

Please don't intertwine defines and struct definitions.

> +    uint8_t function_code;
> +    uint8_t control_mask[3];
> +    uint16_t response_code;
> +} __attribute__((packed));
> +
> +struct read_info_sccb {
> +    uint16_t rnmax;
> +    uint8_t rnsize;
> +} __attribute__((packed));
> +
> +struct sccb {
> +    struct sccb_header h;
> +    union {
> +        struct read_info_sccb read_info;
> +        char data[4088];
> +    } c;
> + } __attribute__((packed));
> +
> +int sclp_read_info(CPUS390XState *env, struct sccb *sccb);
> +void sclp_service_interrupt(CPUS390XState *env, uint32_t sccb);
> diff --git a/target-s390x/cpu.h b/target-s390x/cpu.h
> index 2f3f394..d0199d7 100644
> --- a/target-s390x/cpu.h
> +++ b/target-s390x/cpu.h
> @@ -591,17 +591,6 @@ static inline const char *cc_name(int cc_op)
>      return cc_names[cc_op];
>  }
>  
> -/* SCLP PV interface defines */
> -#define SCLP_CMDW_READ_SCP_INFO         0x00020001
> -#define SCLP_CMDW_READ_SCP_INFO_FORCED  0x00120001
> -
> -#define SCP_LENGTH                      0x00
> -#define SCP_FUNCTION_CODE               0x02
> -#define SCP_CONTROL_MASK                0x03
> -#define SCP_RESPONSE_CODE               0x06
> -#define SCP_MEM_CODE                    0x08
> -#define SCP_INCREMENT                   0x0a
> -
>  typedef struct LowCore
>  {
>      /* prefix area: defined by architecture */
> diff --git a/target-s390x/kvm.c b/target-s390x/kvm.c
> index 73cfd1f..7a7604b 100644
> --- a/target-s390x/kvm.c
> +++ b/target-s390x/kvm.c
> @@ -60,9 +60,6 @@
>  #define SIGP_STORE_STATUS_ADDR          0x0e
>  #define SIGP_SET_ARCH                   0x12
>  
> -#define SCLP_CMDW_READ_SCP_INFO         0x00020001
> -#define SCLP_CMDW_READ_SCP_INFO_FORCED  0x00120001
> -
>  const KVMCapabilityInfo kvm_arch_required_capabilities[] = {
>      KVM_CAP_LAST_INFO
>  };
> @@ -246,6 +243,8 @@ static int kvm_sclp_service_call(CPUS390XState *env, struct kvm_run *run,
>      r = sclp_service_call(env, sccb, code);
>      if (r) {
>          setcc(env, 3);
> +    } else {
> +        setcc(env, 0);
>   

This one looks like an actual fix that is not part of the cleanup?

>      }
>  
>      return 0;
> diff --git a/target-s390x/op_helper.c b/target-s390x/op_helper.c
> index 7b72473..74bd9ad 100644
> --- a/target-s390x/op_helper.c
> +++ b/target-s390x/op_helper.c
> @@ -31,6 +31,7 @@
>  
>  #if !defined (CONFIG_USER_ONLY)
>  #include "sysemu.h"
> +#include "hw/s390-sclp.h"
>   

#include in hw/ from target-XXX is a no-go. It means our abstraction
layer is broken.

>  #endif
>  
>  /*****************************************************************************/
> @@ -2360,16 +2361,13 @@ static void program_interrupt(CPUS390XState *env, uint32_t code, int ilc)
>      }
>  }
>  
> -static void ext_interrupt(CPUS390XState *env, int type, uint32_t param,
> -                          uint64_t param64)
> -{
> -    cpu_inject_ext(env, type, param, param64);
> -}
>  
>  int sclp_service_call(CPUS390XState *env, uint32_t sccb, uint64_t code)
>  {
>      int r = 0;
> -    int shift = 0;
> +    struct sccb work_sccb;
> +    struct sccb *guest_sccb;
> +    target_phys_addr_t sccb_len = sizeof(*guest_sccb);
>  
>  #ifdef DEBUG_HELPER
>      printf("sclp(0x%x, 0x%" PRIx64 ")\n", sccb, code);
> @@ -2380,26 +2378,18 @@ int sclp_service_call(CPUS390XState *env, uint32_t sccb, uint64_t code)
>          r = -1;
>          goto out;
>      }
> +    /*
> +     * we want to work on a private copy of the sccb, to prevent guests
> +     * from playing dirty tricks by modifying the memory content after
> +     * the host has checked the values
> +     */
> +    guest_sccb = cpu_physical_memory_map(sccb, &sccb_len, true);
> +    memcpy(&work_sccb, guest_sccb, sizeof(*guest_sccb));
>  
>      switch(code) {
>          case SCLP_CMDW_READ_SCP_INFO:
>          case SCLP_CMDW_READ_SCP_INFO_FORCED:
> -            while ((ram_size >> (20 + shift)) > 65535) {
> -                shift++;
> -            }
> -            stw_phys(sccb + SCP_MEM_CODE, ram_size >> (20 + shift));
> -            stb_phys(sccb + SCP_INCREMENT, 1 << shift);
> -            stw_phys(sccb + SCP_RESPONSE_CODE, 0x10);
> -
> -            if (kvm_enabled()) {
> -#ifdef CONFIG_KVM
> -                kvm_s390_interrupt_internal(env, KVM_S390_INT_SERVICE,
> -                                            sccb & ~3, 0, 1);
> -#endif
> -            } else {
> -                env->psw.addr += 4;
> -                ext_interrupt(env, EXT_SERVICE, sccb & ~3, 0);
> -            }
> +            r = sclp_read_info(env, &work_sccb);
>   

Maybe we should have a list of callbacks that hw/ code can register for?
Like the spapr hcalls.


Alex

>              break;
>          default:
>  #ifdef DEBUG_HELPER
> @@ -2408,6 +2398,11 @@ int sclp_service_call(CPUS390XState *env, uint32_t sccb, uint64_t code)
>              r = -1;
>              break;
>      }
> +    memcpy(guest_sccb, &work_sccb, work_sccb.h.length);
> +    cpu_physical_memory_unmap(guest_sccb, 4096, true, 4096);
> +    if (!r) {
> +        sclp_service_interrupt(env, sccb);
> +    }
>  
>  out:
>      return r;
>   

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

* Re: [Qemu-devel] [PATCH 5/8] s390: Cleanup sclp functions
  2012-06-12  9:58   ` Alexander Graf
@ 2012-06-12 10:07     ` Christian Borntraeger
  2012-06-12 10:09       ` Alexander Graf
  2012-06-12 10:10       ` Alexander Graf
  2012-06-12 12:24     ` Christian Borntraeger
  1 sibling, 2 replies; 51+ messages in thread
From: Christian Borntraeger @ 2012-06-12 10:07 UTC (permalink / raw)
  To: Alexander Graf
  Cc: Jens Freimann, Heinz Graalfs, qemu-devel, Jens Freimann,
	Cornelia Huck, Andreas Färber

On 12/06/12 11:58, Alexander Graf wrote:
> Jens Freimann wrote:
>> From: Christian Borntraeger <borntraeger@de.ibm.com>
>>
>> The sclp facility on s390 is a hardware that is external to the cpu.
>> Lets cleanup the definitions and move the functionality into a separate
>> file under hw/.
>>   
> 
> Phew. I'm not sure this is a great idea. At least not the way the code
> is structured now. Andreas, do you have any idea how to get this done
> nicely? We'd have to invent our own bus to communicate to the device,
> right? And then also actually spawn one.

There are followup patches which add qom etc see patch 6. Can you look at
the end result?

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

* Re: [Qemu-devel] [PATCH 5/8] s390: Cleanup sclp functions
  2012-06-12 10:07     ` Christian Borntraeger
@ 2012-06-12 10:09       ` Alexander Graf
  2012-06-12 10:10       ` Alexander Graf
  1 sibling, 0 replies; 51+ messages in thread
From: Alexander Graf @ 2012-06-12 10:09 UTC (permalink / raw)
  To: Christian Borntraeger
  Cc: Jens Freimann, Heinz Graalfs, qemu-devel, Jens Freimann,
	Cornelia Huck, Andreas Färber



On 12.06.2012, at 12:07, Christian Borntraeger <borntraeger@de.ibm.com> wrote:

> On 12/06/12 11:58, Alexander Graf wrote:
>> Jens Freimann wrote:
>>> From: Christian Borntraeger <borntraeger@de.ibm.com>
>>> 
>>> The sclp facility on s390 is a hardware that is external to the cpu.
>>> Lets cleanup the definitions and move the functionality into a separate
>>> file under hw/.
>>> 
>> 
>> Phew. I'm not sure this is a great idea. At least not the way the code
>> is structured now. Andreas, do you have any idea how to get this done
>> nicely? We'd have to invent our own bus to communicate to the device,
>> right? And then also actually spawn one.
> 
> There are followup patches which add qom etc see patch 6. Can you look at
> the end result?

Yeah, still trying to get my head around them :).

Alex

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

* Re: [Qemu-devel] [PATCH 5/8] s390: Cleanup sclp functions
  2012-06-12 10:07     ` Christian Borntraeger
  2012-06-12 10:09       ` Alexander Graf
@ 2012-06-12 10:10       ` Alexander Graf
  1 sibling, 0 replies; 51+ messages in thread
From: Alexander Graf @ 2012-06-12 10:10 UTC (permalink / raw)
  To: Christian Borntraeger
  Cc: Jens Freimann, Heinz Graalfs, qemu-devel, Jens Freimann,
	Cornelia Huck, Andreas Färber



On 12.06.2012, at 12:07, Christian Borntraeger <borntraeger@de.ibm.com> wrote:

> On 12/06/12 11:58, Alexander Graf wrote:
>> Jens Freimann wrote:
>>> From: Christian Borntraeger <borntraeger@de.ibm.com>
>>> 
>>> The sclp facility on s390 is a hardware that is external to the cpu.
>>> Lets cleanup the definitions and move the functionality into a separate
>>> file under hw/.
>>> 
>> 
>> Phew. I'm not sure this is a great idea. At least not the way the code
>> is structured now. Andreas, do you have any idea how to get this done
>> nicely? We'd have to invent our own bus to communicate to the device,
>> right? And then also actually spawn one.
> 
> There are followup patches which add qom etc see patch 6. Can you look at
> the end result?

Btw, the fact that this is a preparation step for more rework later is a pretty crucial part of the patch description :).

Alex

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

* Re: [Qemu-devel] [PATCH 4/8] s390: stop target cpu on sigp initial reset
  2012-06-12  9:42   ` Alexander Graf
@ 2012-06-12 10:15     ` Christian Borntraeger
  0 siblings, 0 replies; 51+ messages in thread
From: Christian Borntraeger @ 2012-06-12 10:15 UTC (permalink / raw)
  To: Alexander Graf
  Cc: Jens Freimann, Cornelia Huck, Jens Freimann, Heinz Graalfs, qemu-devel

On 12/06/12 11:42, Alexander Graf wrote:
> Jens Freimann wrote:
>> From: Christian Borntraeger <borntraeger@de.ibm.com>
>>
>> We must not run the target cpu after an initial reset. This makes
>> system_reset more reliable for smp guests.
>>   
> 
> Why?

After an initial reset, the cpu is in a state (PSW=0) that causes program check
loops if the cpu thread starts before the cpu is properly set up, iow we might
burn cpu and have the cpu in a state that it is not supposed to be.

Christian

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

* Re: [Qemu-devel] [PATCH 2/8] s390: autodetect map private
  2012-06-12  9:32   ` Alexander Graf
@ 2012-06-12 11:20     ` Christian Borntraeger
  2012-06-12 11:57       ` Alexander Graf
  0 siblings, 1 reply; 51+ messages in thread
From: Christian Borntraeger @ 2012-06-12 11:20 UTC (permalink / raw)
  To: Alexander Graf
  Cc: Jens Freimann, Cornelia Huck, Jens Freimann, Heinz Graalfs, qemu-devel

> Is there any way we can move the above code to target-s390x? Having the
> branch below is already invasive enough for generic code, but we really
> don't need all the special s390 quirks to live here.


Hmm, we have to have a special hook somehow.
What about this approach?

-----------------------

By default qemu will use MAP_PRIVATE for guest pages. This will write
protect pages and thus break on s390 systems that dont support this feature.
Therefore qemu has a hack to always use MAP_SHARED for s390. But MAP_SHARED
has other problems (no dirty pages tracking, a lot more swap overhead etc.)
Newer systems allow the distinction via KVM_CAP_S390_COW. With this feature
qemu can use the standard qemu alloc if available, otherwise it will use
the old s390 hack.

Signed-off-by: Christian Borntraeger <borntraeger@de.ibm.com>
---
 exec.c             |   19 ++++---------------
 kvm.h              |    1 +
 oslib-posix.c      |    3 +++
 target-s390x/kvm.c |   34 ++++++++++++++++++++++++++++++++++
 4 files changed, 42 insertions(+), 15 deletions(-)

diff --git a/exec.c b/exec.c
index a587e7a..9b9b8e1 100644
--- a/exec.c
+++ b/exec.c
@@ -2645,26 +2645,15 @@ ram_addr_t qemu_ram_alloc_from_ptr(ram_addr_t size, void *host,
             exit(1);
 #endif
         } else {
-#if defined(TARGET_S390X) && defined(CONFIG_KVM)
-            /* S390 KVM requires the topmost vma of the RAM to be smaller than
-               an system defined value, which is at least 256GB. Larger systems
-               have larger values. We put the guest between the end of data
-               segment (system break) and this value. We use 32GB as a base to
-               have enough room for the system break to grow. */
-            new_block->host = mmap((void*)0x800000000, size,
-                                   PROT_EXEC|PROT_READ|PROT_WRITE,
-                                   MAP_SHARED | MAP_ANONYMOUS | MAP_FIXED, -1, 0);
-            if (new_block->host == MAP_FAILED) {
-                fprintf(stderr, "Allocating RAM failed\n");
-                abort();
-            }
-#else
             if (xen_enabled()) {
                 xen_ram_alloc(new_block->offset, size, mr);
+#if defined(TARGET_S390X)
+            } else if (kvm_enabled()) {
+                new_block->host = kvm_arch_alloc(size);
+#endif
             } else {
                 new_block->host = qemu_vmalloc(size);
             }
-#endif
             qemu_madvise(new_block->host, size, QEMU_MADV_MERGEABLE);
         }
     }
diff --git a/kvm.h b/kvm.h
index 9c7b0ea..9d50016 100644
--- a/kvm.h
+++ b/kvm.h
@@ -102,6 +102,7 @@ int kvm_vcpu_ioctl(CPUArchState *env, int type, ...);
 
 extern const KVMCapabilityInfo kvm_arch_required_capabilities[];
 
+void *kvm_arch_alloc(ram_addr_t size);
 void kvm_arch_pre_run(CPUArchState *env, struct kvm_run *run);
 void kvm_arch_post_run(CPUArchState *env, struct kvm_run *run);
 
diff --git a/oslib-posix.c b/oslib-posix.c
index b6a3c7f..93902ac 100644
--- a/oslib-posix.c
+++ b/oslib-posix.c
@@ -41,6 +41,9 @@ extern int daemon(int, int);
       therefore we need special code which handles running on Valgrind. */
 #  define QEMU_VMALLOC_ALIGN (512 * 4096)
 #  define CONFIG_VALGRIND
+#elif defined(__linux__) && defined(__s390x__)
+   /* Use 1 MiB (segment size) alignment so gmap can be used by KVM. */
+#  define QEMU_VMALLOC_ALIGN (256 * 4096)
 #else
 #  define QEMU_VMALLOC_ALIGN getpagesize()
 #endif
diff --git a/target-s390x/kvm.c b/target-s390x/kvm.c
index 90aad61..ccf5daa 100644
--- a/target-s390x/kvm.c
+++ b/target-s390x/kvm.c
@@ -135,6 +135,40 @@ int kvm_arch_get_registers(CPUS390XState *env)
     return 0;
 }
 
+/*
+ * Legacy layout for s390:
+ * Older S390 KVM requires the topmost vma of the RAM to be
+ * smaller than an system defined value, which is at least 256GB.
+ * Larger systems have larger values. We put the guest between
+ * the end of data segment (system break) and this value. We
+ * use 32GB as a base to have enough room for the system break
+ * to grow. We also have to use MAP parameters that avoid
+ * read-only mapping of guest pages.
+ */
+static void *legacy_s390_alloc(ram_addr_t size)
+{
+    void *mem;
+
+    mem = mmap((void *) 0x800000000ULL, size,
+               PROT_EXEC|PROT_READ|PROT_WRITE,
+               MAP_SHARED | MAP_ANONYMOUS | MAP_FIXED, -1, 0);
+    if (mem == MAP_FAILED) {
+        fprintf(stderr, "Allocating RAM failed\n");
+        abort();
+    }
+    return mem;
+}
+
+void *kvm_arch_alloc(ram_addr_t size)
+{
+    if (kvm_check_extension(kvm_state, KVM_CAP_S390_GMAP) &&
+        kvm_check_extension(kvm_state, KVM_CAP_S390_COW)) {
+        return qemu_vmalloc(size);
+    } else {
+        return legacy_s390_alloc(size);
+    }
+}
+
 int kvm_arch_insert_sw_breakpoint(CPUS390XState *env, struct kvm_sw_breakpoint *bp)
 {
     static const uint8_t diag_501[] = {0x83, 0x24, 0x05, 0x01};

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

* Re: [Qemu-devel] [PATCH 6/8] s390: sclp event facility and signal quiesce support via system_powerdown
  2012-06-06 12:05 ` [Qemu-devel] [PATCH 6/8] s390: sclp event facility and signal quiesce support via system_powerdown Jens Freimann
@ 2012-06-12 11:38   ` Alexander Graf
  2012-06-13  7:00     ` Heinz Graalfs
  0 siblings, 1 reply; 51+ messages in thread
From: Alexander Graf @ 2012-06-12 11:38 UTC (permalink / raw)
  To: Jens Freimann
  Cc: Heinz Graalfs, qemu-devel, Christian Borntraeger, Jens Freimann,
	Cornelia Huck, Andreas Färber

On 06/06/2012 02:05 PM, Jens Freimann wrote:
> From: Heinz Graalfs<graalfs@linux.vnet.ibm.com>
>
> This patch implements a subset of the sclp event facility as well
> as the signal quiesce event. This allows to gracefully shutdown
> a guest by using system_powerdown. This sends a signal quiesce
> signal that is interpreted by linux guests as ctrl-alt-del.
> In addition the event facility is modeled using the QOM.
>
> Signed-off-by: Heinz Graalfs<graalfs@linux.vnet.ibm.com>
> Signed-off-by: Christian Borntraeger<borntraeger@de.ibm.com>
> Signed-off-by: Jens Freimann<jfrei@de.ibm.com>

Andreas, I'm always getting headaches reviewing qdev and/or qom patches. 
Could you please check this for layering violations?

> ---
>   Makefile.target          |    1 +
>   hw/s390-event-facility.c |  232 +++++++++++++++++++++++++++++++++++++++++
>   hw/s390-event-facility.h |   54 ++++++++++
>   hw/s390-sclp.c           |  256 +++++++++++++++++++++++++++++++++++++++++++++-
>   hw/s390-sclp.h           |   98 +++++++++++++++++-
>   hw/s390-virtio.c         |   11 +-
>   target-s390x/op_helper.c |    3 +
>   7 files changed, 649 insertions(+), 6 deletions(-)
>   create mode 100644 hw/s390-event-facility.c
>   create mode 100644 hw/s390-event-facility.h
>
> diff --git a/Makefile.target b/Makefile.target
> index fed2d72..f939c3a 100644
> --- a/Makefile.target
> +++ b/Makefile.target
> @@ -375,6 +375,7 @@ obj-m68k-y = an5206.o mcf5206.o mcf_uart.o mcf_intc.o mcf5208.o mcf_fec.o
>   obj-m68k-y += m68k-semi.o dummy_m68k.o
>
>   obj-s390x-y = s390-virtio-bus.o s390-virtio.o s390-sclp.o
> +obj-s390x-y += s390-event-facility.o
>
>   obj-alpha-y = mc146818rtc.o
>   obj-alpha-y += alpha_pci.o alpha_dp264.o alpha_typhoon.o
> diff --git a/hw/s390-event-facility.c b/hw/s390-event-facility.c
> new file mode 100644
> index 0000000..b8106a6
> --- /dev/null
> +++ b/hw/s390-event-facility.c
> @@ -0,0 +1,232 @@
> +/*
> + * SCLP Event Facility
> + *
> + * Copyright IBM Corp. 2007,2012
> + * Author: Heinz Graalfs<graalfs@de.ibm.com>
> + *
> + * This file is licensed under the terms of the GNU General Public License(GPL)
> + */
> +
> +#include "iov.h"
> +#include "monitor.h"
> +#include "qemu-queue.h"
> +#include "sysbus.h"
> +#include "sysemu.h"
> +
> +#include "s390-sclp.h"
> +#include "s390-event-facility.h"
> +
> +struct SCLPDevice {
> +    const char *name;
> +    bool vm_running;
> +};
> +
> +struct SCLP {
> +    BusState qbus;
> +    SCLPEventFacility *event_facility;
> +};
> +
> +struct SCLPEventFacility {
> +    SCLPDevice sdev;
> +    SCLP sbus;
> +    DeviceState *qdev;
> +    void *opaque;
> +};
> +
> +typedef struct SCLPConsole {
> +    SCLPEvent event;
> +    CharDriverState *chr;
> +} SCLPConsole;
> +
> +static void sclpef_bus_dev_print(Monitor *mon, DeviceState *qdev, int indent)
> +{
> +    SCLPEvent *event = DO_UPCAST(SCLPEvent, dev, qdev);
> +
> +    monitor_printf(mon, "%*sid %d\n", indent, "", event->id);
> +}
> +
> +static unsigned int send_mask_quiesce(void)
> +{
> +    return SCLP_EVENT_MASK_SIGNAL_QUIESCE;
> +}
> +
> +static unsigned int receive_mask_quiesce(void)
> +{
> +    return 0;
> +}
> +
> +static void s390_signal_quiesce(void *opaque, int n, int level)
> +{
> +    sclp_enable_signal_quiesce();
> +    sclp_service_interrupt(opaque, 0);
> +}
> +
> +unsigned int sclpef_send_mask(SCLPDevice *sdev)
> +{
> +    unsigned int mask;
> +    DeviceState *dev;
> +    SCLPEventFacility *event_facility;
> +    SCLPEventClass *cons;
> +
> +    event_facility = DO_UPCAST(SCLPEventFacility, sdev, sdev);
> +
> +    mask = 0;
> +
> +    QTAILQ_FOREACH(dev,&event_facility->sbus.qbus.children, sibling) {
> +        cons = SCLP_EVENT_GET_CLASS((SCLPEvent *) dev);
> +        mask |= cons->get_send_mask();
> +    }
> +    return mask;
> +}
> +
> +unsigned int sclpef_receive_mask(SCLPDevice *sdev)
> +{
> +    unsigned int mask;
> +    DeviceState *dev;
> +    SCLPEventClass *cons;
> +    SCLPEventFacility *event_facility;
> +
> +    event_facility = DO_UPCAST(SCLPEventFacility, sdev, sdev);
> +
> +    mask = 0;
> +
> +    QTAILQ_FOREACH(dev,&event_facility->sbus.qbus.children, sibling) {
> +        cons = SCLP_EVENT_GET_CLASS((SCLPEvent *) dev);
> +        mask |= cons->get_receive_mask();
> +    }
> +    return mask;
> +}
> +
> +static struct BusInfo sclp_bus_info = {
> +    .name      = "s390-sclp-bus",
> +    .size      = sizeof(SCLPS390Bus),
> +    .print_dev = sclpef_bus_dev_print,
> +    .props      = (Property[]) {
> +        DEFINE_PROP_STRING("name", SCLPEvent, name),
> +        DEFINE_PROP_END_OF_LIST()
> +    }
> +};
> +
> +static int sclpef_qdev_init(DeviceState *qdev)
> +{
> +    int rc;
> +    SCLPEvent *event = DO_UPCAST(SCLPEvent, dev, qdev);
> +    SCLPEventClass *cons = SCLP_EVENT_GET_CLASS(event);
> +    SCLP *bus = DO_UPCAST(SCLP, qbus, qdev->parent_bus);
> +
> +    event->evt_fac = bus->event_facility;
> +    rc = cons->init(event);
> +
> +    return rc;
> +}
> +
> +static int sclpef_qdev_exit(DeviceState *qdev)
> +{
> +    SCLPEvent *event = DO_UPCAST(SCLPEvent, dev, qdev);
> +    SCLPEventClass *cons = SCLP_EVENT_GET_CLASS(event);
> +    if (cons->exit) {
> +        cons->exit(event);
> +    }
> +    return 0;
> +}
> +
> +static SCLPDevice *sclpef_common_init(const char *name, size_t struct_size)
> +{
> +    SCLPDevice *sdev;
> +
> +    sdev = malloc(struct_size);

g_malloc please. I suppose even g_malloc0?

> +    if (!sdev) {
> +        return NULL;
> +    }
> +    sdev->vm_running = runstate_is_running();
> +    sdev->name = name;
> +
> +    return sdev;
> +}
> +
> +void sclpef_enable_irqs(SCLPDevice *sdev, void *opaque)
> +{
> +    SCLPEventFacility *event_facility;
> +
> +    event_facility = DO_UPCAST(SCLPEventFacility, sdev, sdev);
> +    qemu_system_powerdown = *qemu_allocate_irqs(s390_signal_quiesce,
> +                                                opaque, 1);
> +    event_facility->opaque = opaque;
> +}
> +
> +SCLPDevice *sclpef_init_event_facility(DeviceState *dev)
> +{
> +    DeviceState *quiesce;
> +    SCLPDevice *sdev;
> +    SCLPEventFacility *event_facility;
> +
> +    sdev = sclpef_common_init("sclp-event-facility",
> +            sizeof(SCLPEventFacility));
> +
> +    if (!sdev) {
> +        return NULL;
> +    }
> +    event_facility = DO_UPCAST(SCLPEventFacility, sdev, sdev);
> +
> +    /* Spawn a new sclp-facility */
> +    qbus_create_inplace(&event_facility->sbus.qbus,&sclp_bus_info, dev, NULL);
> +    event_facility->sbus.qbus.allow_hotplug = 0;
> +    event_facility->sbus.event_facility = event_facility;
> +    event_facility->qdev = dev;
> +    event_facility->opaque = NULL;
> +    quiesce = qdev_create(&event_facility->sbus.qbus, "sclpquiesce");
> +
> +    if (!quiesce) {
> +        return NULL;
> +    }
> +
> +    return sdev;
> +}
> +
> +static void sclpef_class_init(ObjectClass *klass, void *data)
> +{
> +    DeviceClass *dc = DEVICE_CLASS(klass);
> +    dc->init = sclpef_qdev_init;
> +    dc->bus_info =&sclp_bus_info;
> +    dc->exit = sclpef_qdev_exit;
> +    dc->unplug = qdev_simple_unplug_cb;
> +}
> +
> +static TypeInfo sclp_event_facility_type_info = {
> +    .name = TYPE_SCLP_EVENT,
> +    .parent = TYPE_DEVICE,
> +    .instance_size = sizeof(SCLPEvent),
> +    .class_size = sizeof(SCLPEventClass),
> +    .class_init = sclpef_class_init,
> +    .abstract = true,
> +};
> +
> +static int sclpquiesce_initfn(SCLPEvent *event)
> +{
> +    event->id = ID_QUIESCE;
> +
> +    return 0;
> +}
> +
> +static void sclpef_quiesce_class_init(ObjectClass *klass, void *data)
> +{
> +    SCLPEventClass *k = SCLP_EVENT_CLASS(klass);
> +
> +    k->init = sclpquiesce_initfn;
> +    k->get_send_mask = send_mask_quiesce;
> +    k->get_receive_mask = receive_mask_quiesce;
> +}
> +
> +static TypeInfo sclp_quiesce_info = {
> +    .name          = "sclpquiesce",
> +    .parent        = TYPE_SCLP_EVENT,
> +    .instance_size = sizeof(SCLPEvent),
> +    .class_init    = sclpef_quiesce_class_init,
> +};
> +
> +static void sclpef_register_types(void)
> +{
> +    type_register_static(&sclp_event_facility_type_info);
> +    type_register_static(&sclp_quiesce_info);
> +}
> +type_init(sclpef_register_types)
> diff --git a/hw/s390-event-facility.h b/hw/s390-event-facility.h
> new file mode 100644
> index 0000000..40d4049
> --- /dev/null
> +++ b/hw/s390-event-facility.h
> @@ -0,0 +1,54 @@
> +/*
> + * SCLP definitions
> + *
> + * Copyright IBM Corp. 2007,2012
> + * Author: Heinz Graalfs<graalfs@de.ibm.com>
> + *
> + * This file is licensed under the terms of the GNU General Public License(GPL)
> + */
> +
> +#ifndef _QEMU_SCLP_EVENT_H
> +#define _QEMU_SCLP_EVENT_H
> +
> +#include "qdev.h"
> +#include "qemu-common.h"
> +
> +#define ID_QUIESCE SCLP_EVENT_SIGNAL_QUIESCE
> +
> +#define TYPE_SCLP_EVENT "s390-sclp-event-type"
> +#define SCLP_EVENT(obj) \
> +     OBJECT_CHECK(SCLPEvent, (obj), TYPE_SCLP_EVENT)
> +#define SCLP_EVENT_CLASS(klass) \
> +     OBJECT_CLASS_CHECK(SCLPEventClass, (klass), TYPE_SCLP_EVENT)
> +#define SCLP_EVENT_GET_CLASS(obj) \
> +     OBJECT_GET_CLASS(SCLPEventClass, (obj), TYPE_SCLP_EVENT)
> +
> +typedef struct SCLP SCLP;
> +typedef struct SCLPEventFacility SCLPEventFacility;
> +typedef struct SCLPEvent SCLPEvent;
> +typedef struct SCLPDevice SCLPDevice;
> +
> +typedef struct SCLPEventClass {
> +    DeviceClass parent_class;
> +    int (*init)(SCLPEvent *event);
> +    int (*exit)(SCLPEvent *event);
> +    unsigned int (*get_send_mask)(void);
> +    unsigned int (*get_receive_mask)(void);
> +} SCLPEventClass;
> +
> +struct SCLPEvent {
> +    DeviceState dev;
> +    SCLPEventFacility *evt_fac;
> +    char *name;
> +    uint32_t id;
> +};
> +
> +SCLPDevice *sclpef_init_event_facility(DeviceState *dev);
> +
> +void sclpef_enable_irqs(SCLPDevice *sdev, void *opaque);
> +
> +void sclpef_set_masks(void);
> +unsigned int sclpef_send_mask(SCLPDevice *sdev);
> +unsigned int sclpef_receive_mask(SCLPDevice *sdev);
> +
> +#endif
> diff --git a/hw/s390-sclp.c b/hw/s390-sclp.c
> index c046441..683a709 100644
> --- a/hw/s390-sclp.c
> +++ b/hw/s390-sclp.c
> @@ -7,7 +7,20 @@
>
>   #include "cpu.h"
>   #include "kvm.h"
> +#include "hw/sysbus.h"
>   #include "hw/s390-sclp.h"
> +#include "hw/s390-event-facility.h"
> +
> +/* Host capabilites */
> +static unsigned int sclp_send_mask;
> +static unsigned int sclp_receive_mask;
> +
> +/* Guest capabilities */
> +static unsigned int sclp_cp_send_mask;
> +static unsigned int sclp_cp_receive_mask;
> +
> +static int quiesce;
> +static int event_pending;

Global variables? Bad idea :). These should be properties of your 
quiesce device.

>
>   int sclp_read_info(CPUS390XState *env, struct sccb *sccb)
>   {
> @@ -23,20 +36,257 @@ int sclp_read_info(CPUS390XState *env, struct sccb *sccb)
>       return 0;
>   }
>
> +static int signal_quiesce_event(struct sccb *sccb, int *slen)
> +{
> +    if (!quiesce) {
> +        return 0;
> +    }
> +
> +    if (*slen<  sizeof(struct signal_quiesce)) {
> +        event_pending = 1;
> +        return 0;
> +    }
> +
> +    sccb->c.read.quiesce.h.length = cpu_to_be16(sizeof(struct signal_quiesce));
> +    sccb->c.read.quiesce.h.type = SCLP_EVENT_SIGNAL_QUIESCE;
> +    sccb->c.read.quiesce.h.flags&= ~SCLP_EVENT_BUFFER_ACCEPTED;
> +    /*
> +     * system_powerdown does not have a timeout. Fortunately the
> +     * timeout value is curently ignored by Linux, anyway
> +     */
> +    sccb->c.read.quiesce.timeout = cpu_to_be16(0);
> +    sccb->c.read.quiesce.unit = cpu_to_be16(0);
> +
> +    quiesce = 0;
> +    *slen -= sizeof(struct signal_quiesce);
> +    return 1;
> +}
> +
> +void sclp_enable_signal_quiesce(void)
> +{
> +    quiesce = 1;
> +    event_pending = 1;
> +}
> +
> +static void sclp_set_masks(void)
> +{
> +    SCLPS390EventFacility *evt_fac;
> +
> +    if (!sclp_bus) {
> +        return;
> +    }
> +    evt_fac = sclp_bus->event_facility;
> +
> +    assert(evt_fac);
> +
> +    sclp_send_mask = sclpef_send_mask(evt_fac->sdev);
> +    sclp_receive_mask = sclpef_receive_mask(evt_fac->sdev);
> + }
> +
> +int sclp_read_event_data(CPUS390XState *env, struct sccb *sccb)
> +{
> +    unsigned int sclp_active_selection_mask;
> +    int slen;
> +
> +    if (be16_to_cpu(sccb->h.length) != SCCB_SIZE) {
> +        sccb->h.response_code = cpu_to_be16(SCLP_RC_INSUFFICIENT_SCCB_LENGTH);
> +        goto out;
> +    }
> +
> +    switch (sccb->h.function_code) {
> +    case SCLP_UNCONDITIONAL_READ:
> +        sclp_active_selection_mask = sclp_cp_receive_mask;
> +        break;
> +    case SCLP_SELECTIVE_READ:
> +        if (!(sclp_cp_receive_mask&  be32_to_cpu(sccb->c.read.mask))) {
> +            sccb->h.response_code = cpu_to_be16(SCLP_RC_INVALID_SELECTION_MASK);
> +            goto out;
> +        }
> +        sclp_active_selection_mask = be32_to_cpu(sccb->c.read.mask);
> +        break;
> +    default:
> +        sccb->h.response_code = cpu_to_be16(SCLP_RC_INVALID_FUNCTION);
> +        goto out;
> +    }
> +
> +    slen = sizeof(sccb->c.data);
> +    sccb->h.response_code = cpu_to_be16(SCLP_RC_NO_EVENT_BUFFERS_STORED);
> +
> +    if (sclp_active_selection_mask&  SCLP_EVENT_MASK_SIGNAL_QUIESCE) {
> +        if (signal_quiesce_event(sccb,&slen)) {
> +            sccb->h.response_code = cpu_to_be16(SCLP_RC_NORMAL_COMPLETION);
> +        }
> +    }
> +
> +    if (sccb->h.control_mask[2]&  SCLP_VARIABLE_LENGTH_RESPONSE) {
> +        sccb->h.control_mask[2]&= ~SCLP_VARIABLE_LENGTH_RESPONSE;
> +        sccb->h.length = cpu_to_be16(SCCB_SIZE - slen);
> +    }
> +
> +out:
> +    return 0;
> +}
> +
> +int sclp_write_event_mask(CPUS390XState *env, struct sccb *sccb)
> +{
> +    /* Attention: We assume that Linux uses 4-byte masks, what it actually
> +       does. Architecture allows for masks of variable size, though */
> +    if (be16_to_cpu(sccb->c.we_mask.mask_length) != 4) {
> +        sccb->h.response_code = cpu_to_be16(SCLP_RC_INVALID_MASK_LENGTH);
> +        goto out;
> +    }
> +
> +    /* keep track of the guest's capability masks */
> +    sclp_cp_send_mask = be32_to_cpu(sccb->c.we_mask.cp_send_mask);
> +    sclp_cp_receive_mask = be32_to_cpu(sccb->c.we_mask.cp_receive_mask);
> +
> +    sclp_set_masks();
> +
> +    /* return the SCLP's capability masks to the guest */
> +    sccb->c.we_mask.send_mask = cpu_to_be32(sclp_send_mask);
> +    sccb->c.we_mask.receive_mask = cpu_to_be32(sclp_receive_mask);
> +
> +    sccb->h.response_code = cpu_to_be32(SCLP_RC_NORMAL_COMPLETION);
> +
> +out:
> +    return 0;
> +}
> +
>   void sclp_service_interrupt(CPUS390XState *env, uint32_t sccb)
>   {
> -    if (!sccb) {
> +    if (!event_pending&&  !sccb) {
>           return;
>       }
>
>       if (kvm_enabled()) {
>   #ifdef CONFIG_KVM
>           kvm_s390_interrupt_internal(env, KVM_S390_INT_SERVICE,
> -                                    (sccb&  ~3), 0, 1);
> +                                    (sccb&  ~3) + event_pending, 0, 1);
>   #endif
>       } else {
>           env->psw.addr += 4;
> -        cpu_inject_ext(env, EXT_SERVICE, (sccb&  ~3), 0);
> +        cpu_inject_ext(env, EXT_SERVICE, (sccb&  ~3) + event_pending, 0);
> +    }

Please fix the above piece of code to use the same mechanism regarless 
of TCG or KVM, so that SCLP code doesn't have to be aware of KVM.

> +    event_pending = 0;
> +}
> +
> +struct BusInfo s390_sclp_bus_info = {
> +    .name       = "s390-sclp",
> +    .size       = sizeof(SCLPS390Bus),
> +};
> +
> +SCLPS390Bus *s390_sclp_bus_init(void)
> +{
> +    SCLPS390Bus *bus;
> +    BusState *bus_state;
> +    DeviceState *dev;
> +
> +    dev = qdev_create(NULL, "s390-sclp-bridge");
> +    qdev_init_nofail(dev);
> +    bus_state = qbus_create(&s390_sclp_bus_info, dev, "s390-sclp-bus");
> +    bus = DO_UPCAST(SCLPS390Bus, bus, bus_state);
> +
> +    bus_state->allow_hotplug = 0;
> +
> +    return bus;
> +}
> +
> +static int s390_sclp_device_init(SCLPS390EventFacility *dev, SCLPDevice *sdev)
> +{
> +    dev->sdev = sdev;
> +
> +    return 0;
> +}
> +
> +static int s390_sclp_init(SCLPS390EventFacility *dev)
> +{
> +    int rc;
> +    SCLPS390Bus *bus;
> +    SCLPDevice *sdev;
> +
> +    bus = DO_UPCAST(SCLPS390Bus, bus, dev->qdev.parent_bus);
> +
> +    sdev = sclpef_init_event_facility((DeviceState *)dev);
> +    if (!sdev) {
> +        return -1;
>       }
> +
> +    rc = s390_sclp_device_init(dev, sdev);
> +    if (!rc) {
> +        bus->event_facility = dev;
> +    }
> +
> +    return rc;
> +}
> +
> +static void s390_sclp_class_init(ObjectClass *klass, void *data)
> +{
> +    SCLPS390EventFacilityClass *k = SCLP_S390_EVENT_FACILITY_CLASS(klass);
> +
> +    k->init = s390_sclp_init;
> +}
> +
> +static TypeInfo s390_sclp_event_facility = {
> +    .name          = "sclp-event-facility",
> +    .parent        = TYPE_SCLP_S390_EVENT_FACILITY,
> +    .instance_size = sizeof(SCLPS390EventFacility),
> +    .class_init    = s390_sclp_class_init,
> +};
> +
> +static int s390_sclp_busdev_init(DeviceState *dev)
> +{
> +    SCLPS390EventFacility *_dev = (SCLPS390EventFacility *)dev;
> +    SCLPS390EventFacilityClass *evt_fac =
> +        SCLP_S390_EVENT_FACILITY_GET_CLASS(dev);
> +
> +    return evt_fac->init(_dev);
>   }
>
> +static void sclp_s390_device_class_init(ObjectClass *klass, void *data)
> +{
> +    DeviceClass *dc = DEVICE_CLASS(klass);
> +
> +    dc->init = s390_sclp_busdev_init;
> +    dc->bus_info =&s390_sclp_bus_info;
> +}
> +
> +static TypeInfo sclp_s390_device_info = {
> +    .name = TYPE_SCLP_S390_EVENT_FACILITY,
> +    .parent = TYPE_DEVICE,
> +    .instance_size = sizeof(SCLPS390EventFacility),
> +    .class_init = sclp_s390_device_class_init,
> +    .class_size = sizeof(SCLPS390EventFacilityClass),
> +    .abstract = true,
> +};
> +
> +/***************** S390 SCLP Bus Bridge Device *******************/
> +/* Only required to have the sclp bus as child in the system bus */
> +
> +static int s390_sclp_bridge_init(SysBusDevice *dev)
> +{
> +    return 0;
> +}
> +
> +static void s390_sclp_bridge_class_init(ObjectClass *klass, void *data)
> +{
> +    DeviceClass *dc = DEVICE_CLASS(klass);
> +    SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
> +
> +    k->init = s390_sclp_bridge_init;
> +    dc->no_user = 1;
> +}
> +
> +static TypeInfo s390_sclp_bridge_info = {
> +    .name          = "s390-sclp-bridge",
> +    .parent        = TYPE_SYS_BUS_DEVICE,
> +    .instance_size = sizeof(SysBusDevice),
> +    .class_init    = s390_sclp_bridge_class_init,
> +};
> +
> +static void s390_sclp_register_types(void)
> +{
> +    type_register_static(&sclp_s390_device_info);
> +    type_register_static(&s390_sclp_event_facility);
> +    type_register_static(&s390_sclp_bridge_info);
> +}
> +type_init(s390_sclp_register_types)
> diff --git a/hw/s390-sclp.h b/hw/s390-sclp.h
> index e335b21..f61421b 100644
> --- a/hw/s390-sclp.h
> +++ b/hw/s390-sclp.h
> @@ -1,13 +1,69 @@
>   #include<stdint.h>
>   #include<qemu-common.h>
>
> +#include "sysbus.h"
> +#include "hw/s390-event-facility.h"
>
>   /* SCLP command codes */
>   #define SCLP_CMDW_READ_SCP_INFO                 0x00020001
>   #define SCLP_CMDW_READ_SCP_INFO_FORCED          0x00120001
> +#define SCLP_CMD_WRITE_EVENT_MASK               0x00780005
>
>   /* SCLP response codes */
> -#define SCLP_RC_SCCB_RESOURCE_INSUFFICENT       0x07f0
> +#define SCLP_RC_NORMAL_COMPLETION               0x0020
> +#define SCLP_RC_INSUFFICIENT_SCCB_LENGTH        0x0300
> +#define SCLP_RC_INVALID_FUNCTION                0x40f0
> +#define SCLP_RC_NO_EVENT_BUFFERS_STORED         0x60f0
> +#define SCLP_RC_INVALID_SELECTION_MASK          0x70f0
> +#define SCLP_RC_INCONSISTENT_LENGTHS            0x72f0
> +#define SCLP_RC_EVENT_BUFFER_SYNTAX_ERROR       0x73f0
> +#define SCLP_RC_INVALID_MASK_LENGTH             0x74f0
> +
> +/* SCLP event types */
> +#define SCLP_EVENT_SIGNAL_QUIESCE               0x1d
> +
> +/* SCLP event masks */
> +#define SCLP_EVENT_MASK_SIGNAL_QUIESCE          0x00000008
> +#define SCLP_EVENT_MASK_MSG                     0x40000000
> +
> +#define SCLP_UNCONDITIONAL_READ                 0x00
> +#define SCLP_SELECTIVE_READ                     0x01
> +
> +#define SCLP_VARIABLE_LENGTH_RESPONSE           0x80
> +
> +#define SCCB_SIZE 4096
> +
> +/* Service Call Control Block (SCCB) and its elements */
> +
> +struct write_event_mask {
> +    uint16_t _reserved;
> +    uint16_t mask_length;
> +    uint32_t cp_receive_mask;
> +    uint32_t cp_send_mask;
> +    uint32_t send_mask;
> +    uint32_t receive_mask;
> +} __attribute__((packed));
> +
> +struct event_buffer_header {
> +    uint16_t length;
> +    uint8_t  type;
> +#define SCLP_EVENT_BUFFER_ACCEPTED              0x80
> +    uint8_t  flags;
> +    uint16_t _reserved;
> +} __attribute__((packed));
> +
> +struct signal_quiesce {
> +    struct event_buffer_header h;
> +    uint16_t timeout;
> +    uint8_t unit;
> +} __attribute__((packed));
> +
> +struct read_event_data {
> +    union {
> +        struct signal_quiesce quiesce;
> +        uint32_t mask;
> +    };
> +} __attribute__((packed));
>
>   struct sccb_header {
>       uint16_t length;
> @@ -22,13 +78,51 @@ struct read_info_sccb {
>       uint8_t rnsize;
>   } __attribute__((packed));
>
> +#define SCCB_DATA_LEN 4088
> +
>   struct sccb {
>       struct sccb_header h;
>       union {
>           struct read_info_sccb read_info;
> -        char data[4088];
> +        struct read_event_data read;
> +        struct write_event_mask we_mask;
> +        char data[SCCB_DATA_LEN];
>       } c;
>    } __attribute__((packed));
>
> +void sclp_enable_signal_quiesce(void);
>   int sclp_read_info(CPUS390XState *env, struct sccb *sccb);
> +int sclp_read_event_data(CPUS390XState *env, struct sccb *sccb);
> +int sclp_write_event_mask(CPUS390XState *env, struct sccb *sccb);
>   void sclp_service_interrupt(CPUS390XState *env, uint32_t sccb);
> +
> +#define TYPE_SCLP_S390_EVENT_FACILITY "s390-sclp-event-facility"
> +#define SCLP_S390_EVENT_FACILITY(obj) \
> +     OBJECT_CHECK(SCLPS390EventFacility, (obj), TYPE_SCLP_S390_EVENT_FACILITY)
> +#define SCLP_S390_EVENT_FACILITY_CLASS(klass) \
> +     OBJECT_CLASS_CHECK(SCLPS390EventFacilityClass, (klass), \
> +             TYPE_SCLP_S390_EVENT_FACILITY)
> +#define SCLP_S390_EVENT_FACILITY_GET_CLASS(obj) \
> +     OBJECT_GET_CLASS(SCLPS390EventFacilityClass, (obj), \
> +             TYPE_SCLP_S390_EVENT_FACILITY)
> +
> +typedef struct SCLPS390EventFacility SCLPS390EventFacility;
> +
> +typedef struct SCLPS390EventFacilityClass {
> +    DeviceClass qdev;
> +    int (*init)(SCLPS390EventFacility *dev);
> +} SCLPS390EventFacilityClass;
> +
> +struct SCLPS390EventFacility {
> +    DeviceState qdev;
> +    SCLPDevice *sdev;
> +};
> +
> +typedef struct SCLPS390Bus {
> +    BusState bus;
> +    SCLPS390EventFacility *event_facility;
> +} SCLPS390Bus;
> +
> +extern SCLPS390Bus *sclp_bus;
> +
> +SCLPS390Bus *s390_sclp_bus_init(void);
> diff --git a/hw/s390-virtio.c b/hw/s390-virtio.c
> index c0e19fd..0babf27 100644
> --- a/hw/s390-virtio.c
> +++ b/hw/s390-virtio.c
> @@ -32,6 +32,7 @@
>   #include "exec-memory.h"
>
>   #include "hw/s390-virtio-bus.h"
> +#include "hw/s390-sclp.h"
>
>   //#define DEBUG_S390
>
> @@ -60,7 +61,9 @@
>
>   #define MAX_BLK_DEVS                    10
>
> -static VirtIOS390Bus *s390_bus;
> +VirtIOS390Bus *s390_bus;
> +SCLPS390Bus *sclp_bus;
> +
>   static CPUS390XState **ipi_states;
>
>   CPUS390XState *s390_cpu_addr2state(uint16_t cpu_addr)
> @@ -170,6 +173,7 @@ static void s390_init(ram_addr_t my_ram_size,
>       target_phys_addr_t virtio_region_len;
>       target_phys_addr_t virtio_region_start;
>       int i;
> +    DeviceState *dev;
>
>       /* s390x ram size detection needs a 16bit multiplier + an increment. So
>          guests>  64GB can be specified in 2MB steps etc. */
> @@ -183,6 +187,7 @@ static void s390_init(ram_addr_t my_ram_size,
>
>       /* get a BUS */
>       s390_bus = s390_virtio_bus_init(&my_ram_size);
> +    sclp_bus = s390_sclp_bus_init();
>
>       /* allocate RAM */
>       memory_region_init_ram(ram, "s390.ram", my_ram_size);
> @@ -325,6 +330,10 @@ static void s390_init(ram_addr_t my_ram_size,
>           qdev_prop_set_drive_nofail(dev, "drive", dinfo->bdrv);
>           qdev_init_nofail(dev);
>       }
> +
> +    dev = qdev_create((BusState *)sclp_bus, "sclp-event-facility");
> +    qdev_init_nofail(dev);
> +    sclpef_enable_irqs(sclp_bus->event_facility->sdev, ipi_states[0]);
>   }
>
>   static QEMUMachine s390_machine = {
> diff --git a/target-s390x/op_helper.c b/target-s390x/op_helper.c
> index 74bd9ad..3e5eff4 100644
> --- a/target-s390x/op_helper.c
> +++ b/target-s390x/op_helper.c
> @@ -2391,6 +2391,9 @@ int sclp_service_call(CPUS390XState *env, uint32_t sccb, uint64_t code)
>           case SCLP_CMDW_READ_SCP_INFO_FORCED:
>               r = sclp_read_info(env,&work_sccb);
>               break;
> +        case SCLP_CMD_WRITE_EVENT_MASK:
> +            r = sclp_write_event_mask(env,&work_sccb);
> +            break;
>           default:

I don't understand most of the patch tbh. It does a lot of things at the 
same time, but none of them really thorough. Please split this off into 
separate patches and make them actually do something small, but 
constistently.

Things I saw while looking over this:

   - you create a bus to plug in sclp users. This needs to be separate. 
Don't introduce users of a framework when introducing the framework 
itself, unless really neccessary (or if the patch only becomes 5 lines 
longer)
   - you create objects for the new event parser, but not all the other 
sclp users. There's also no generic distribution mechanism in place
   - the event parser itself uses globals - that's nowhere near object 
oriented :)
   - I don't see the header inclusions i commented on in the last patch 
remedied here, please think your model over. In general, moving sclp to 
hw/ is probably a good idea, but then please do it in a properly 
abstracted way.
   - A lot of the above code could use some comments, so people reading 
it would actually understand what's going on :)

Alex

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

* Re: [Qemu-devel] [PATCH 7/8] s390: Add SCLP vt220 console support
  2012-06-06 12:05 ` [Qemu-devel] [PATCH 7/8] s390: Add SCLP vt220 console support Jens Freimann
@ 2012-06-12 11:52   ` Alexander Graf
  2012-06-13  7:27     ` Heinz Graalfs
  0 siblings, 1 reply; 51+ messages in thread
From: Alexander Graf @ 2012-06-12 11:52 UTC (permalink / raw)
  To: Jens Freimann; +Cc: Cornelia Huck, Jens Freimann, Heinz Graalfs, qemu-devel

On 06/06/2012 02:05 PM, Jens Freimann wrote:
> From: Heinz Graalfs<graalfs@linux.vnet.ibm.com>
>
> Adds console support (in vt220 mode).
> In order to run qemu exploiting the SCLP's console functionality in vt220 mode
> the user has to specify the following console related parameters:
>
>   -chardev stdio,id=charconsole0 -device sclpconsole,chardev=charconsole0,id=console0
>
> Signed-off-by: Heinz Graalfs<graalfs@linux.vnet.ibm.com>
> Signed-off-by: Jens Freimann<jfrei@linux.vnet.ibm.com>
> ---
>   hw/s390-event-facility.c |  209 ++++++++++++++++++++++++++++++++++++++++++++++
>   hw/s390-event-facility.h |    8 ++
>   hw/s390-sclp.c           |  177 ++++++++++++++++++++++++++++++++++++++-
>   hw/s390-sclp.h           |   22 ++++-
>   sysemu.h                 |    1 +
>   target-s390x/op_helper.c |    6 ++
>   vl.c                     |   41 +++++++++
>   7 files changed, 460 insertions(+), 4 deletions(-)
>
> diff --git a/hw/s390-event-facility.c b/hw/s390-event-facility.c
> index b8106a6..cfa5dd4 100644
> --- a/hw/s390-event-facility.c
> +++ b/hw/s390-event-facility.c
> @@ -16,6 +16,11 @@
>   #include "s390-sclp.h"
>   #include "s390-event-facility.h"
>
> +qemu_irq sclp_read_vt220;
> +
> +static int size_buffer = 4096;
> +static char *sclp_console_data_vt220;

Globals?

> +
>   struct SCLPDevice {
>       const char *name;
>       bool vm_running;
> @@ -224,9 +229,213 @@ static TypeInfo sclp_quiesce_info = {
>       .class_init    = sclpef_quiesce_class_init,
>   };
>
> +/* ----------- SCLP VT220 console ------------ */
> +
> +static void s390_signal_read_vt220(void *opaque, int n, int level)
> +{
> +    sclp_enable_signal_read_vt220();
> +    sclp_service_interrupt(opaque, 0);
> +}
> +
> +static void sclpef_set_console(SCLPEvent *event)
> +{
> +    if (event->id == ID_VT220) {
> +        sclp_read_vt220 = *qemu_allocate_irqs(s390_signal_read_vt220,
> +            event->evt_fac->opaque, 1);
> +    }
> +}
> +
> +void sclpef_write_console_vt220(SCLPDevice *sdev, char *buf)
> +{
> +    DeviceState *dev;
> +    SCLPEventFacility *event_facility;
> +    static SCLPEvent *event;
> +    static SCLPEventClass *cons;
> +
> +    event_facility = DO_UPCAST(SCLPEventFacility, sdev, sdev);
> +
> +    if (!cons) {
> +        QTAILQ_FOREACH(dev,&event_facility->sbus.qbus.children, sibling) {
> +            event = (SCLPEvent *) dev;
> +            if (event->id == ID_VT220) {
> +                cons = SCLP_EVENT_GET_CLASS(event);
> +                assert(cons->have_data);
> +                break;
> +            }
> +        }
> +    }

I don't understand the above code. Why do you have to search for 
anything when you're in a call to process a write?

> +    if (cons) {
> +        cons->have_data(event, (const uint8_t *)buf, strlen(buf));
> +    }
> +}
> +
> +char *sclpef_get_console_data_vt220(SCLPDevice *sdev)
> +{
> +    DeviceState *dev;
> +    SCLPEventFacility *event_facility;
> +    SCLPEvent *event = NULL;
> +    static SCLPEventClass *cons;
> +
> +    event_facility = DO_UPCAST(SCLPEventFacility, sdev, sdev);
> +
> +    if (!cons) {
> +        QTAILQ_FOREACH(dev,&event_facility->sbus.qbus.children, sibling) {
> +            event = (SCLPEvent *) dev;
> +            if (event->id == ID_VT220) {
> +                cons = SCLP_EVENT_GET_CLASS(event);
> +                assert(cons->get_data);
> +                break;
> +            }
> +        }
> +    }

See above.

> +    if (cons) {
> +        return cons->get_data();
> +    }
> +    return NULL;
> +}
> +
> +static char *console_data_vt220(void)
> +{
> +    return sclp_console_data_vt220;
> +}
> +
> +static ssize_t flush_buf(SCLPEvent *event, const uint8_t *buf, size_t len)
> +{
> +    SCLPConsole *scon = DO_UPCAST(SCLPConsole, event, event);
> +    ssize_t ret;
> +
> +    if (!scon->chr) {
> +        /* If there's no backend, we can just say we consumed all data. */
> +        return len;
> +    }
> +
> +    ret = qemu_chr_fe_write(scon->chr, buf, len);
> +
> +    if (ret<  0) {
> +        /* see virtio-console comments */
> +        ret = 0;
> +    }
> +
> +    return ret;
> +}
> +
> +static void guest_open(SCLPEvent *event)
> +{
> +    SCLPConsole *scon = DO_UPCAST(SCLPConsole, event, event);
> +
> +    if (!scon->chr) {
> +        return;
> +    }
> +    qemu_chr_fe_open(scon->chr);
> +}
> +
> +static void guest_close(SCLPEvent *event)
> +{
> +    SCLPConsole *scon = DO_UPCAST(SCLPConsole, event, event);
> +
> +    if (!scon->chr) {
> +        return;
> +    }
> +    qemu_chr_fe_close(scon->chr);
> +}
> +
> +static int chr_can_read(void *opaque)
> +{
> +    return 1;
> +}
> +
> +static void chr_read_vt220(void *opaque, const uint8_t *buf, int size)
> +{
> +    char *offset;
> +
> +    if (!sclp_console_data_vt220) {
> +        size_buffer = 2 * size;

Why 2*?

> +        sclp_console_data_vt220 = malloc(size_buffer);

%s/malloc/g_malloc0/g

> +    }
> +    if (size_buffer<  size + 1) {

This could use a comment.

> +        free(sclp_console_data_vt220);
> +        size_buffer = 2 * size;
> +        sclp_console_data_vt220 = malloc(size_buffer);
> +    }
> +    offset = sclp_console_data_vt220;
> +    if (offset) {
> +        memcpy(offset, buf, size);
> +        offset += size;
> +        *offset = '\0';

How do you know you're not out of bounds?

> +        qemu_irq_raise(sclp_read_vt220);
> +    } else {
> +        size_buffer = 0;
> +    }
> +}
> +
> +static void chr_event(void *opaque, int event)
> +{
> +    switch (event) {
> +    case CHR_EVENT_OPENED:
> +        if (!sclp_console_data_vt220) {
> +            sclp_console_data_vt220 = malloc(size_buffer);
> +        }
> +        break;
> +    case CHR_EVENT_CLOSED:
> +        break;
> +    }
> +}
> +
> +static unsigned int send_mask_vt220(void)
> +{
> +    return SCLP_EVENT_MASK_MSG_ASCII;
> +}
> +
> +static unsigned int receive_mask_vt220(void)
> +{
> +    return SCLP_EVENT_MASK_MSG_ASCII;
> +}
> +
> +static int sclpconsole_initfn_vt220(SCLPEvent *event)
> +{
> +    SCLPConsole *scon = DO_UPCAST(SCLPConsole, event, event);
> +
> +    event->id = ID_VT220;
> +    sclpef_set_console(event);
> +    if (scon->chr) {
> +        qemu_chr_add_handlers(scon->chr, chr_can_read,
> +                chr_read_vt220, chr_event, scon);
> +    }
> +
> +    return 0;
> +}
> +
> +static Property sclpconsole_properties[] = {
> +    DEFINE_PROP_CHR("chardev", SCLPConsole, chr),
> +    DEFINE_PROP_END_OF_LIST(),
> +};
> +
> +static void sclpconsole_class_init(ObjectClass *klass, void *data)
> +{
> +    DeviceClass *dc = DEVICE_CLASS(klass);
> +    SCLPEventClass *k = SCLP_EVENT_CLASS(klass);
> +
> +    k->init = sclpconsole_initfn_vt220;
> +    k->have_data = flush_buf;
> +    k->guest_open = guest_open;
> +    k->guest_close = guest_close;
> +    k->get_send_mask = send_mask_vt220;
> +    k->get_receive_mask = receive_mask_vt220;
> +    k->get_data = console_data_vt220;
> +    dc->props = sclpconsole_properties;
> +}
> +
> +static TypeInfo sclpconsole_info = {
> +    .name          = "sclpconsole",
> +    .parent        = TYPE_SCLP_EVENT,
> +    .instance_size = sizeof(SCLPConsole),
> +    .class_init    = sclpconsole_class_init,
> +};
> +
>   static void sclpef_register_types(void)
>   {
>       type_register_static(&sclp_event_facility_type_info);
>       type_register_static(&sclp_quiesce_info);
> +    type_register_static(&sclpconsole_info);
>   }
>   type_init(sclpef_register_types)
> diff --git a/hw/s390-event-facility.h b/hw/s390-event-facility.h
> index 40d4049..d6bde7d 100644
> --- a/hw/s390-event-facility.h
> +++ b/hw/s390-event-facility.h
> @@ -14,6 +14,7 @@
>   #include "qemu-common.h"
>
>   #define ID_QUIESCE SCLP_EVENT_SIGNAL_QUIESCE
> +#define ID_VT220   SCLP_EVENT_ASCII_CONSOLE_DATA
>
>   #define TYPE_SCLP_EVENT "s390-sclp-event-type"
>   #define SCLP_EVENT(obj) \
> @@ -34,6 +35,11 @@ typedef struct SCLPEventClass {
>       int (*exit)(SCLPEvent *event);
>       unsigned int (*get_send_mask)(void);
>       unsigned int (*get_receive_mask)(void);
> +    void (*guest_open)(SCLPEvent *event);
> +    void (*guest_close)(SCLPEvent *event);
> +    void (*guest_ready)(SCLPEvent *event);
> +    ssize_t (*have_data)(SCLPEvent *event, const uint8_t *buf, size_t len);
> +    char *(*get_data)(void);
>   } SCLPEventClass;
>
>   struct SCLPEvent {
> @@ -50,5 +56,7 @@ void sclpef_enable_irqs(SCLPDevice *sdev, void *opaque);
>   void sclpef_set_masks(void);
>   unsigned int sclpef_send_mask(SCLPDevice *sdev);
>   unsigned int sclpef_receive_mask(SCLPDevice *sdev);
> +void sclpef_write_console_vt220(SCLPDevice *sdev, char *buf);
> +char *sclpef_get_console_data_vt220(SCLPDevice *sdev);
>
>   #endif
> diff --git a/hw/s390-sclp.c b/hw/s390-sclp.c
> index 683a709..8f45773 100644
> --- a/hw/s390-sclp.c
> +++ b/hw/s390-sclp.c
> @@ -11,6 +11,11 @@
>   #include "hw/s390-sclp.h"
>   #include "hw/s390-event-facility.h"
>
> +/* input buffer handling */
> +#define INP_BUFFER_SIZE 4096
> +static int sclp_curr_buf_size;
> +static char *sclp_input_vt220;
> +
>   /* Host capabilites */
>   static unsigned int sclp_send_mask;
>   static unsigned int sclp_receive_mask;
> @@ -21,6 +26,7 @@ static unsigned int sclp_cp_receive_mask;
>
>   static int quiesce;
>   static int event_pending;
> +static int vt220;

If anything, this is a machine variable, no? What is this supposed to 
express?

>
>   int sclp_read_info(CPUS390XState *env, struct sccb *sccb)
>   {
> @@ -66,6 +72,7 @@ void sclp_enable_signal_quiesce(void)
>   {
>       quiesce = 1;
>       event_pending = 1;
> +    vt220 = 0;
>   }
>
>   static void sclp_set_masks(void)
> @@ -81,7 +88,112 @@ static void sclp_set_masks(void)
>
>       sclp_send_mask = sclpef_send_mask(evt_fac->sdev);
>       sclp_receive_mask = sclpef_receive_mask(evt_fac->sdev);
> - }
> +}
> +
> +static int signal_vt220_event(struct sccb *sccb, int *slen)
> +{
> +    char *p;
> +
> +    if (!sclp_input_vt220 || !vt220) {
> +        return 0;
> +    }
> +
> +    int l = strlen(sclp_input_vt220);
> +
> +    if (*slen<  sizeof(struct ascii_cons_data_command) + l + 1) {
> +        event_pending = 1;
> +        return 0;
> +    }
> +    p = (char *)&sccb->c.read.acd_cmd.data;
> +    /* first byte is hex 0 saying an ascii string follows */
> +    *p++ = '\0';
> +    memmove(p, sclp_input_vt220, l);
> +    *sclp_input_vt220 = '\0';
> +
> +    sccb->c.read.acd_cmd.h.length =
> +            cpu_to_be16(sizeof(struct ascii_cons_data_command) + l + 1);
> +    sccb->c.read.acd_cmd.h.type = SCLP_EVENT_ASCII_CONSOLE_DATA;
> +
> +    vt220 = 0;
> +    *slen -= sizeof(struct ascii_cons_data_command) + l + 1;
> +    return 1;
> +}
> +
> +static char *grow_buffer(int size)
> +{
> +    char *p = (char *) malloc(size);
> +
> +    if (!p) {
> +        sclp_curr_buf_size = 0;
> +        return NULL;
> +    }
> +    memset(p, '\0', size);
> +    sclp_curr_buf_size = size;
> +    return p;
> +}
> +
> +static int sclp_write_vt220(struct event_buffer_header *event)
> +{
> +    int l;
> +    char *msg;
> +    SCLPS390EventFacility *evt_fac;
> +    struct ascii_cons_data_command *ad =
> +            (struct ascii_cons_data_command *) event;
> +
> +    assert(sclp_bus);
> +
> +    l = event->length - sizeof(struct event_buffer_header);
> +    msg = (char *) malloc(l + 1);
> +    assert(msg);
> +    memset(msg, '\0', l + 1);
> +    memmove(msg, ad->data, l);

Why the copy? Also, for such short lived data, you're probably better 
off using alloca.

> +
> +    evt_fac = sclp_bus->event_facility;
> +    sclpef_write_console_vt220(evt_fac->sdev, msg);
> +
> +    free(msg);
> +
> +    return SCLP_RC_NORMAL_COMPLETION;
> +}
> +
> +void sclp_enable_signal_read_vt220(void)
> +{
> +    int len;
> +    char *input;
> +    SCLPS390EventFacility *evt_fac;
> +
> +    if (!sclp_bus) {
> +        return;
> +    }
> +    evt_fac = sclp_bus->event_facility;
> +
> +    assert(evt_fac);
> +
> +    input = sclpef_get_console_data_vt220(evt_fac->sdev);
> +
> +    if (!input) {
> +        return;
> +    }
> +
> +    vt220 = 1;
> +    quiesce = 0;
> +    event_pending = 1;
> +    len = strlen((char *) input);
> +    if (sclp_input_vt220 == NULL) {
> +        /* get new buffer */
> +        sclp_input_vt220 = grow_buffer(2 * len + 1);
> +    } else {
> +        if (len>= sclp_curr_buf_size) {
> +            /* get larger buffer */
> +            char *p = grow_buffer(2 * len + 1);
> +            free(sclp_input_vt220);
> +            sclp_input_vt220 = p;
> +        }
> +    }
> +    if (sclp_input_vt220) {
> +        strcat(sclp_input_vt220, (char *)input);
> +    }
> +}
>
>   int sclp_read_event_data(CPUS390XState *env, struct sccb *sccb)
>   {
> @@ -99,7 +211,8 @@ int sclp_read_event_data(CPUS390XState *env, struct sccb *sccb)
>           break;
>       case SCLP_SELECTIVE_READ:
>           if (!(sclp_cp_receive_mask&  be32_to_cpu(sccb->c.read.mask))) {
> -            sccb->h.response_code = cpu_to_be16(SCLP_RC_INVALID_SELECTION_MASK);
> +            sccb->h.response_code =
> +                    cpu_to_be16(SCLP_RC_INVALID_SELECTION_MASK);
>               goto out;
>           }
>           sclp_active_selection_mask = be32_to_cpu(sccb->c.read.mask);
> @@ -117,7 +230,12 @@ int sclp_read_event_data(CPUS390XState *env, struct sccb *sccb)
>               sccb->h.response_code = cpu_to_be16(SCLP_RC_NORMAL_COMPLETION);
>           }
>       }
> -
> +    if (sclp_active_selection_mask&  SCLP_EVENT_MASK_MSG_ASCII) {
> +        if (signal_vt220_event(sccb,&slen)) {
> +            sccb->h.response_code = cpu_to_be16(SCLP_RC_NORMAL_COMPLETION);
> +            sccb->h.length = cpu_to_be16(SCCB_SIZE - slen);
> +        }
> +    }
>       if (sccb->h.control_mask[2]&  SCLP_VARIABLE_LENGTH_RESPONSE) {
>           sccb->h.control_mask[2]&= ~SCLP_VARIABLE_LENGTH_RESPONSE;
>           sccb->h.length = cpu_to_be16(SCCB_SIZE - slen);
> @@ -127,6 +245,59 @@ out:
>       return 0;
>   }
>
> +int sclp_write_event_data(CPUS390XState *env, struct sccb *sccb)
> +{
> +    struct event_buffer_header *event;
> +    int slen;
> +    unsigned elen = 0;
> +
> +    if (sccb->h.function_code != SCLP_FC_NORMAL_WRITE) {
> +        sccb->h.response_code = cpu_to_be16(SCLP_RC_INVALID_FUNCTION);
> +        goto out;
> +    }
> +    if (be16_to_cpu(sccb->h.length)<  8) {
> +        sccb->h.response_code = cpu_to_be16(SCLP_RC_INSUFFICIENT_SCCB_LENGTH);
> +        goto out;
> +    }
> +
> +    /* first check the sum of all events */
> +    event =&sccb->c.event;
> +    for (slen = be16_to_cpu(sccb->h.length) - sizeof(sccb->h);
> +         slen>  0; slen -= elen) {
> +        elen = be16_to_cpu(event->length);
> +        if (elen<  sizeof(*event) || elen>  slen) {
> +            sccb->h.response_code =
> +                    cpu_to_be16(SCLP_RC_EVENT_BUFFER_SYNTAX_ERROR);
> +            goto out;
> +        }
> +        event = (void *) event + elen;
> +    }
> +    if (slen) {
> +        sccb->h.response_code = cpu_to_be16(SCLP_RC_INCONSISTENT_LENGTHS);
> +        goto out;
> +    }
> +
> +    /* the execute */
> +    event =&sccb->c.event;
> +    for (slen = be16_to_cpu(sccb->h.length) - sizeof(sccb->h);
> +         slen>  0; slen -= elen) {
> +        elen = be16_to_cpu(event->length);
> +        switch (event->type) {
> +        case SCLP_EVENT_ASCII_CONSOLE_DATA:
> +            sccb->h.response_code = cpu_to_be16(sclp_write_vt220(event));
> +            break;

This also screams for a generic dispatcher.

> +        default:
> +            sccb->h.response_code = SCLP_RC_INVALID_FUNCTION;
> +            break;
> +        }
> +        event = (void *) event + elen;
> +    }
> +    sccb->h.response_code = SCLP_RC_NORMAL_COMPLETION;
> +
> +out:
> +    return 0;
> +}
> +
>   int sclp_write_event_mask(CPUS390XState *env, struct sccb *sccb)
>   {
>       /* Attention: We assume that Linux uses 4-byte masks, what it actually
> diff --git a/hw/s390-sclp.h b/hw/s390-sclp.h
> index f61421b..c86bca8 100644
> --- a/hw/s390-sclp.h
> +++ b/hw/s390-sclp.h
> @@ -7,6 +7,8 @@
>   /* SCLP command codes */
>   #define SCLP_CMDW_READ_SCP_INFO                 0x00020001
>   #define SCLP_CMDW_READ_SCP_INFO_FORCED          0x00120001
> +#define SCLP_CMD_READ_EVENT_DATA                0x00770005
> +#define SCLP_CMD_WRITE_EVENT_DATA               0x00760005
>   #define SCLP_CMD_WRITE_EVENT_MASK               0x00780005
>
>   /* SCLP response codes */
> @@ -20,11 +22,12 @@
>   #define SCLP_RC_INVALID_MASK_LENGTH             0x74f0
>
>   /* SCLP event types */
> +#define SCLP_EVENT_ASCII_CONSOLE_DATA           0x1a
>   #define SCLP_EVENT_SIGNAL_QUIESCE               0x1d
>
>   /* SCLP event masks */
>   #define SCLP_EVENT_MASK_SIGNAL_QUIESCE          0x00000008
> -#define SCLP_EVENT_MASK_MSG                     0x40000000
> +#define SCLP_EVENT_MASK_MSG_ASCII               0x00000040
>
>   #define SCLP_UNCONDITIONAL_READ                 0x00
>   #define SCLP_SELECTIVE_READ                     0x01
> @@ -44,6 +47,13 @@ struct write_event_mask {
>       uint32_t receive_mask;
>   } __attribute__((packed));
>
> +struct mdb_header {
> +    uint16_t length;
> +    uint16_t type;
> +    uint32_t tag;
> +    uint32_t revision_code;
> +} __attribute__((packed));
> +
>   struct event_buffer_header {
>       uint16_t length;
>       uint8_t  type;
> @@ -58,9 +68,15 @@ struct signal_quiesce {
>       uint8_t unit;
>   } __attribute__((packed));
>
> +struct ascii_cons_data_command {
> +    struct event_buffer_header h;
> +    char data[0];
> +} __attribute__((packed));
> +
>   struct read_event_data {
>       union {
>           struct signal_quiesce quiesce;
> +        struct ascii_cons_data_command acd_cmd;
>           uint32_t mask;
>       };
>   } __attribute__((packed));
> @@ -84,15 +100,19 @@ struct sccb {
>       struct sccb_header h;
>       union {
>           struct read_info_sccb read_info;
> +        struct event_buffer_header event;
>           struct read_event_data read;
> +        struct ascii_cons_data_command acd_cmd;
>           struct write_event_mask we_mask;
>           char data[SCCB_DATA_LEN];
>       } c;
>    } __attribute__((packed));
>
>   void sclp_enable_signal_quiesce(void);
> +void sclp_enable_signal_read_vt220(void);
>   int sclp_read_info(CPUS390XState *env, struct sccb *sccb);
>   int sclp_read_event_data(CPUS390XState *env, struct sccb *sccb);
> +int sclp_write_event_data(CPUS390XState *env, struct sccb *sccb);
>   int sclp_write_event_mask(CPUS390XState *env, struct sccb *sccb);
>   void sclp_service_interrupt(CPUS390XState *env, uint32_t sccb);
>
> diff --git a/sysemu.h b/sysemu.h
> index bc2c788..b4d399c 100644
> --- a/sysemu.h
> +++ b/sysemu.h
> @@ -62,6 +62,7 @@ int qemu_powerdown_requested(void);
>   void qemu_system_killed(int signal, pid_t pid);
>   void qemu_kill_report(void);
>   extern qemu_irq qemu_system_powerdown;
> +extern qemu_irq sclp_read_vt220;
>   void qemu_system_reset(bool report);
>
>   void qemu_add_exit_notifier(Notifier *notify);
> diff --git a/target-s390x/op_helper.c b/target-s390x/op_helper.c
> index 3e5eff4..4d49472 100644
> --- a/target-s390x/op_helper.c
> +++ b/target-s390x/op_helper.c
> @@ -2391,6 +2391,12 @@ int sclp_service_call(CPUS390XState *env, uint32_t sccb, uint64_t code)
>           case SCLP_CMDW_READ_SCP_INFO_FORCED:
>               r = sclp_read_info(env,&work_sccb);
>               break;
> +        case SCLP_CMD_READ_EVENT_DATA:
> +            r = sclp_read_event_data(env,&work_sccb);
> +            break;
> +        case SCLP_CMD_WRITE_EVENT_DATA:
> +            r = sclp_write_event_data(env,&work_sccb);
> +            break;
>           case SCLP_CMD_WRITE_EVENT_MASK:
>               r = sclp_write_event_mask(env,&work_sccb);
>               break;
> diff --git a/vl.c b/vl.c
> index 23ab3a3..aba7ab0 100644
> --- a/vl.c
> +++ b/vl.c
> @@ -174,6 +174,7 @@ int main(int argc, char **argv)
>   #define DEFAULT_RAM_SIZE 128
>
>   #define MAX_VIRTIO_CONSOLES 1
> +#define MAX_SCLP_CONSOLES   1
>
>   static const char *data_dir;
>   const char *bios_name = NULL;
> @@ -201,6 +202,7 @@ int no_quit = 0;
>   CharDriverState *serial_hds[MAX_SERIAL_PORTS];
>   CharDriverState *parallel_hds[MAX_PARALLEL_PORTS];
>   CharDriverState *virtcon_hds[MAX_VIRTIO_CONSOLES];
> +CharDriverState *sclpcon_hds[MAX_SCLP_CONSOLES];
>   int win2k_install_hack = 0;
>   int usb_enabled = 0;
>   int singlestep = 0;
> @@ -274,6 +276,8 @@ static int default_floppy = 1;
>   static int default_cdrom = 1;
>   static int default_sdcard = 1;
>   static int default_vga = 1;
> +static int default_sclpcon = 1;
> +static int default_loader = 1;
>
>   static struct {
>       const char *driver;
> @@ -295,6 +299,8 @@ static struct {
>       { .driver = "isa-cirrus-vga",       .flag =&default_vga       },
>       { .driver = "vmware-svga",          .flag =&default_vga       },
>       { .driver = "qxl-vga",              .flag =&default_vga       },
> +    { .driver = "s390-sclp",            .flag =&default_sclpcon   },
> +    { .driver = "s390-ipl",             .flag =&default_loader    },
>   };
>
>   static void res_free(void)
> @@ -1942,6 +1948,7 @@ struct device_config {
>           DEV_VIRTCON,   /* -virtioconsole */
>           DEV_DEBUGCON,  /* -debugcon */
>           DEV_GDB,       /* -gdb, -s */
> +        DEV_SCLPCON,   /* sclp console */
>       } type;
>       const char *cmdline;
>       Location loc;
> @@ -2058,6 +2065,36 @@ static int virtcon_parse(const char *devname)
>       return 0;
>   }
>
> +static int sclpcon_parse(const char *devname)
> +{
> +    QemuOptsList *device = qemu_find_opts("device");
> +    static int index;
> +    char label[32];
> +    QemuOpts *dev_opts;
> +
> +    if (strcmp(devname, "none") == 0)
> +        return 0;

Apart from that part not passing checkpatch, why do we have to 
reimplement this for every char device?


Alex

> +    if (index == MAX_SCLP_CONSOLES) {
> +        fprintf(stderr, "qemu: too many sclp consoles\n");
> +        exit(1);
> +    }
> +
> +    dev_opts = qemu_opts_create(device, NULL, 0);
> +    qemu_opt_set(dev_opts, "driver", "sclpconsole");
> +
> +    snprintf(label, sizeof(label), "sclpcon%d", index);
> +    sclpcon_hds[index] = qemu_chr_new(label, devname, NULL);
> +    if (!sclpcon_hds[index]) {
> +        fprintf(stderr, "qemu: could not open sclp console '%s': %s\n",
> +                devname, strerror(errno));
> +        return -1;
> +    }
> +    qemu_opt_set(dev_opts, "chardev", label);
> +
> +    index++;
> +    return 0;
> +}
> +
>   static int debugcon_parse(const char *devname)
>   {
>       QemuOpts *opts;
> @@ -3304,6 +3341,8 @@ int main(int argc, char **argv, char **envp)
>               add_device_config(DEV_SERIAL, "mon:stdio");
>           } else if (default_virtcon&&  default_monitor) {
>               add_device_config(DEV_VIRTCON, "mon:stdio");
> +        } else if (default_sclpcon&&  default_monitor) {
> +            add_device_config(DEV_SCLPCON, "mon:stdio");
>           } else {
>               if (default_serial)
>                   add_device_config(DEV_SERIAL, "stdio");
> @@ -3491,6 +3530,8 @@ int main(int argc, char **argv, char **envp)
>           exit(1);
>       if (foreach_device_config(DEV_VIRTCON, virtcon_parse)<  0)
>           exit(1);
> +    if (foreach_device_config(DEV_SCLPCON, sclpcon_parse)<  0)
> +        exit(1);
>       if (foreach_device_config(DEV_DEBUGCON, debugcon_parse)<  0)
>           exit(1);
>

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

* Re: [Qemu-devel] [PATCH 8/8] s390: Fix the storage increment size calculation
  2012-06-06 12:05 ` [Qemu-devel] [PATCH 8/8] s390: Fix the storage increment size calculation Jens Freimann
@ 2012-06-12 11:53   ` Alexander Graf
  2012-06-12 14:57     ` Jeng-fang Wang
  0 siblings, 1 reply; 51+ messages in thread
From: Alexander Graf @ 2012-06-12 11:53 UTC (permalink / raw)
  To: Jens Freimann
  Cc: Cornelia Huck, Nick Wang, Jens Freimann, Heinz Graalfs, qemu-devel

On 06/06/2012 02:05 PM, Jens Freimann wrote:
> From: Nick Wang<jfwang@us.ibm.com>
>
> To comply with the SCLP architecture, the number of storage
> increments should be 512 or fewer. The increment size is a
> multiple of 1M and is a power of 2.
>
> Signed-off-by: Nick Wang<jfwang@us.ibm.com>
> Signed-off-by: Jens Freimann<jfrei@linux.vnet.ibm.com>

Any references to documentation for this one? :)


Alex

> ---
>   hw/s390-sclp.c   |    2 +-
>   hw/s390-virtio.c |    6 +++---
>   2 files changed, 4 insertions(+), 4 deletions(-)
>
> diff --git a/hw/s390-sclp.c b/hw/s390-sclp.c
> index 8f45773..3e91f93 100644
> --- a/hw/s390-sclp.c
> +++ b/hw/s390-sclp.c
> @@ -32,7 +32,7 @@ int sclp_read_info(CPUS390XState *env, struct sccb *sccb)
>   {
>       int shift = 0;
>
> -    while ((ram_size>>  (20 + shift))>  65535) {
> +    while ((ram_size>>  (20 + shift))>  512) {
>           shift++;
>       }
>       sccb->c.read_info.rnmax = cpu_to_be16(ram_size>>  (20 + shift));
> diff --git a/hw/s390-virtio.c b/hw/s390-virtio.c
> index 0babf27..9578d15 100644
> --- a/hw/s390-virtio.c
> +++ b/hw/s390-virtio.c
> @@ -175,9 +175,9 @@ static void s390_init(ram_addr_t my_ram_size,
>       int i;
>       DeviceState *dev;
>
> -    /* s390x ram size detection needs a 16bit multiplier + an increment. So
> -       guests>  64GB can be specified in 2MB steps etc. */
> -    while ((my_ram_size>>  (20 + shift))>  65535) {
> +    /* The storage increment size is a multiple of 1M and is a power of 2.
> +     * The number of storage increments must be 512 or fewer. */
> +    while ((my_ram_size>>  (20 + shift))>  512) {
>           shift++;
>       }
>       my_ram_size = my_ram_size>>  (20 + shift)<<  (20 + shift);

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

* Re: [Qemu-devel] [PATCH 2/8] s390: autodetect map private
  2012-06-12 11:20     ` Christian Borntraeger
@ 2012-06-12 11:57       ` Alexander Graf
  2012-06-12 12:02         ` Christian Borntraeger
  0 siblings, 1 reply; 51+ messages in thread
From: Alexander Graf @ 2012-06-12 11:57 UTC (permalink / raw)
  To: Christian Borntraeger
  Cc: Jens Freimann, Cornelia Huck, Jens Freimann, Heinz Graalfs, qemu-devel

On 06/12/2012 01:20 PM, Christian Borntraeger wrote:
>> Is there any way we can move the above code to target-s390x? Having the
>> branch below is already invasive enough for generic code, but we really
>> don't need all the special s390 quirks to live here.
>
> Hmm, we have to have a special hook somehow.
> What about this approach?
>
> -----------------------
>
> By default qemu will use MAP_PRIVATE for guest pages. This will write
> protect pages and thus break on s390 systems that dont support this feature.
> Therefore qemu has a hack to always use MAP_SHARED for s390. But MAP_SHARED
> has other problems (no dirty pages tracking, a lot more swap overhead etc.)
> Newer systems allow the distinction via KVM_CAP_S390_COW. With this feature
> qemu can use the standard qemu alloc if available, otherwise it will use
> the old s390 hack.
>
> Signed-off-by: Christian Borntraeger<borntraeger@de.ibm.com>
> ---
>   exec.c             |   19 ++++---------------
>   kvm.h              |    1 +
>   oslib-posix.c      |    3 +++
>   target-s390x/kvm.c |   34 ++++++++++++++++++++++++++++++++++
>   4 files changed, 42 insertions(+), 15 deletions(-)
>
> diff --git a/exec.c b/exec.c
> index a587e7a..9b9b8e1 100644
> --- a/exec.c
> +++ b/exec.c
> @@ -2645,26 +2645,15 @@ ram_addr_t qemu_ram_alloc_from_ptr(ram_addr_t size, void *host,
>               exit(1);
>   #endif
>           } else {
> -#if defined(TARGET_S390X)&&  defined(CONFIG_KVM)
> -            /* S390 KVM requires the topmost vma of the RAM to be smaller than
> -               an system defined value, which is at least 256GB. Larger systems
> -               have larger values. We put the guest between the end of data
> -               segment (system break) and this value. We use 32GB as a base to
> -               have enough room for the system break to grow. */
> -            new_block->host = mmap((void*)0x800000000, size,
> -                                   PROT_EXEC|PROT_READ|PROT_WRITE,
> -                                   MAP_SHARED | MAP_ANONYMOUS | MAP_FIXED, -1, 0);
> -            if (new_block->host == MAP_FAILED) {
> -                fprintf(stderr, "Allocating RAM failed\n");
> -                abort();
> -            }
> -#else
>               if (xen_enabled()) {
>                   xen_ram_alloc(new_block->offset, size, mr);
> +#if defined(TARGET_S390X)
> +            } else if (kvm_enabled()) {
> +                new_block->host = kvm_arch_alloc(size);

Since it lives in an s390 specific branch, the function name should 
probably be called s390 specific. If we ever need another architecture 
to have a kvm specific ram allocator, we can make it generic when that 
time comes. Until then, let's treat s390 as the oddball it is :).

Apart from that, this approach looks a lot nicer, yes.

Alex

> +#endif
>               } else {
>                   new_block->host = qemu_vmalloc(size);
>               }
> -#endif
>               qemu_madvise(new_block->host, size, QEMU_MADV_MERGEABLE);
>           }
>       }
> diff --git a/kvm.h b/kvm.h
> index 9c7b0ea..9d50016 100644
> --- a/kvm.h
> +++ b/kvm.h
> @@ -102,6 +102,7 @@ int kvm_vcpu_ioctl(CPUArchState *env, int type, ...);
>
>   extern const KVMCapabilityInfo kvm_arch_required_capabilities[];
>
> +void *kvm_arch_alloc(ram_addr_t size);
>   void kvm_arch_pre_run(CPUArchState *env, struct kvm_run *run);
>   void kvm_arch_post_run(CPUArchState *env, struct kvm_run *run);
>
> diff --git a/oslib-posix.c b/oslib-posix.c
> index b6a3c7f..93902ac 100644
> --- a/oslib-posix.c
> +++ b/oslib-posix.c
> @@ -41,6 +41,9 @@ extern int daemon(int, int);
>         therefore we need special code which handles running on Valgrind. */
>   #  define QEMU_VMALLOC_ALIGN (512 * 4096)
>   #  define CONFIG_VALGRIND
> +#elif defined(__linux__)&&  defined(__s390x__)
> +   /* Use 1 MiB (segment size) alignment so gmap can be used by KVM. */
> +#  define QEMU_VMALLOC_ALIGN (256 * 4096)
>   #else
>   #  define QEMU_VMALLOC_ALIGN getpagesize()
>   #endif
> diff --git a/target-s390x/kvm.c b/target-s390x/kvm.c
> index 90aad61..ccf5daa 100644
> --- a/target-s390x/kvm.c
> +++ b/target-s390x/kvm.c
> @@ -135,6 +135,40 @@ int kvm_arch_get_registers(CPUS390XState *env)
>       return 0;
>   }
>
> +/*
> + * Legacy layout for s390:
> + * Older S390 KVM requires the topmost vma of the RAM to be
> + * smaller than an system defined value, which is at least 256GB.
> + * Larger systems have larger values. We put the guest between
> + * the end of data segment (system break) and this value. We
> + * use 32GB as a base to have enough room for the system break
> + * to grow. We also have to use MAP parameters that avoid
> + * read-only mapping of guest pages.
> + */
> +static void *legacy_s390_alloc(ram_addr_t size)
> +{
> +    void *mem;
> +
> +    mem = mmap((void *) 0x800000000ULL, size,
> +               PROT_EXEC|PROT_READ|PROT_WRITE,
> +               MAP_SHARED | MAP_ANONYMOUS | MAP_FIXED, -1, 0);
> +    if (mem == MAP_FAILED) {
> +        fprintf(stderr, "Allocating RAM failed\n");
> +        abort();
> +    }
> +    return mem;
> +}
> +
> +void *kvm_arch_alloc(ram_addr_t size)
> +{
> +    if (kvm_check_extension(kvm_state, KVM_CAP_S390_GMAP)&&
> +        kvm_check_extension(kvm_state, KVM_CAP_S390_COW)) {
> +        return qemu_vmalloc(size);
> +    } else {
> +        return legacy_s390_alloc(size);
> +    }
> +}
> +
>   int kvm_arch_insert_sw_breakpoint(CPUS390XState *env, struct kvm_sw_breakpoint *bp)
>   {
>       static const uint8_t diag_501[] = {0x83, 0x24, 0x05, 0x01};
>

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

* Re: [Qemu-devel] [PATCH 2/8] s390: autodetect map private
  2012-06-12 11:57       ` Alexander Graf
@ 2012-06-12 12:02         ` Christian Borntraeger
  2012-06-12 12:12           ` Alexander Graf
  0 siblings, 1 reply; 51+ messages in thread
From: Christian Borntraeger @ 2012-06-12 12:02 UTC (permalink / raw)
  To: Alexander Graf
  Cc: Jens Freimann, Cornelia Huck, Jens Freimann, Heinz Graalfs, qemu-devel

On 12/06/12 13:57, Alexander Graf wrote:
> Since it lives in an s390 specific branch, the function name should probably be called s390 specific. If we ever need another architecture to have a kvm specific ram allocator, we can make it generic when that time comes. Until then, let's treat s390 as the oddball it is :).
> 
> Apart from that, this approach looks a lot nicer, yes.

But then I have to have a *s390* function declared in kvm.h and your other comment
hits me. You got me in a trap here, heh? ;-)

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

* Re: [Qemu-devel] [PATCH 2/8] s390: autodetect map private
  2012-06-12 12:02         ` Christian Borntraeger
@ 2012-06-12 12:12           ` Alexander Graf
  2012-06-13 10:30             ` Jan Kiszka
  0 siblings, 1 reply; 51+ messages in thread
From: Alexander Graf @ 2012-06-12 12:12 UTC (permalink / raw)
  To: Christian Borntraeger
  Cc: Jens Freimann, Heinz Graalfs, Jan Kiszka, qemu-devel,
	Jens Freimann, Cornelia Huck

On 06/12/2012 02:02 PM, Christian Borntraeger wrote:
> On 12/06/12 13:57, Alexander Graf wrote:
>> Since it lives in an s390 specific branch, the function name should probably be called s390 specific. If we ever need another architecture to have a kvm specific ram allocator, we can make it generic when that time comes. Until then, let's treat s390 as the oddball it is :).
>>
>> Apart from that, this approach looks a lot nicer, yes.
> But then I have to have a *s390* function declared in kvm.h and your other comment
> hits me. You got me in a trap here, heh? ;-)

Ah, I see what you mean. I was thinking of having a 
target-s390x/kvm_s390x.h or so. Then we could add the function 
definition there and have everything nicely contained within 
target-s390x only.

Jan, which approach would you think is cleaner? Make this a generic 
kvm_arch callback or introduce a special kvm_s390x.h header which would 
then have to be explicitly included in exec.c?


Alex

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

* Re: [Qemu-devel] [PATCH 5/8] s390: Cleanup sclp functions
  2012-06-12  9:58   ` Alexander Graf
  2012-06-12 10:07     ` Christian Borntraeger
@ 2012-06-12 12:24     ` Christian Borntraeger
  2012-06-12 12:32       ` Alexander Graf
  1 sibling, 1 reply; 51+ messages in thread
From: Christian Borntraeger @ 2012-06-12 12:24 UTC (permalink / raw)
  To: Alexander Graf
  Cc: Jens Freimann, Heinz Graalfs, qemu-devel, Jens Freimann,
	Cornelia Huck, Andreas Färber

Yes we will re-split the sclp patches.

besides that, some comments:

On 12/06/12 11:58, Alexander Graf wrote:
>> +#include "hw/s390-sclp.h"
>>   
> 
> No need for hw/.

will fix. 


>> +void sclp_service_interrupt(CPUS390XState *env, uint32_t sccb)
>> +{
>> +    if (!sccb) {
>> +        return;
>> +    }
>> +
>> +    if (kvm_enabled()) {
>> +#ifdef CONFIG_KVM
>>   
> 
> You shouldn't know about CONFIG_KVM in hw/. So we have to generalize
> this code.

Ok, Maybe an exported interface for sending interrupts to the guest 
under target-s390/  that hides the kvm/tcg thing.


ice_call(CPUS390XState *env, struct kvm_run *run,
>>      r = sclp_service_call(env, sccb, code);
>>      if (r) {
>>          setcc(env, 3);
>> +    } else {
>> +        setcc(env, 0);
>>   
> 
> This one looks like an actual fix that is not part of the cleanup?

Yes it is. Separate patch?

> 
>>      }
>>  
>>      return 0;
>> diff --git a/target-s390x/op_helper.c b/target-s390x/op_helper.c
>> index 7b72473..74bd9ad 100644
>> --- a/target-s390x/op_helper.c
>> +++ b/target-s390x/op_helper.c
>> @@ -31,6 +31,7 @@
>>  
>>  #if !defined (CONFIG_USER_ONLY)
>>  #include "sysemu.h"
>> +#include "hw/s390-sclp.h"
>>   
> 
> #include in hw/ from target-XXX is a no-go. It means our abstraction
> layer is broken.

Disagree here. The sclp is a processor that helps the CPU and there is a 
tight link. This is similar to a PIC/APIC etc which are also under hw AND
included from target-386/ - among others:

cborntra@br96egxr:/space/qemu$ egrep "include.*hw"  target-*/* | wc -l
39


[...9

>> -            if (kvm_enabled()) {
>> -#ifdef CONFIG_KVM
>> -                kvm_s390_interrupt_internal(env, KVM_S390_INT_SERVICE,
>> -                                            sccb & ~3, 0, 1);
>> -#endif
>> -            } else {
>> -                env->psw.addr += 4;
>> -                ext_interrupt(env, EXT_SERVICE, sccb & ~3, 0);
>> -            }
>> +            r = sclp_read_info(env, &work_sccb);
>>   
> 
> Maybe we should have a list of callbacks that hw/ code can register for?
> Like the spapr hcalls.

We will have a look if thats a way to go.

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

* Re: [Qemu-devel] [PATCH 5/8] s390: Cleanup sclp functions
  2012-06-12 12:24     ` Christian Borntraeger
@ 2012-06-12 12:32       ` Alexander Graf
  2012-06-12 22:41         ` Anthony Liguori
  0 siblings, 1 reply; 51+ messages in thread
From: Alexander Graf @ 2012-06-12 12:32 UTC (permalink / raw)
  To: Christian Borntraeger
  Cc: Jens Freimann, Heinz Graalfs, qemu-devel, Jens Freimann,
	Cornelia Huck, Andreas Färber

On 06/12/2012 02:24 PM, Christian Borntraeger wrote:
> Yes we will re-split the sclp patches.
>
> besides that, some comments:
>
> On 12/06/12 11:58, Alexander Graf wrote:
>>> +#include "hw/s390-sclp.h"
>>>
>> No need for hw/.
> will fix.
>
>
>>> +void sclp_service_interrupt(CPUS390XState *env, uint32_t sccb)
>>> +{
>>> +    if (!sccb) {
>>> +        return;
>>> +    }
>>> +
>>> +    if (kvm_enabled()) {
>>> +#ifdef CONFIG_KVM
>>>
>> You shouldn't know about CONFIG_KVM in hw/. So we have to generalize
>> this code.
> Ok, Maybe an exported interface for sending interrupts to the guest
> under target-s390/  that hides the kvm/tcg thing.

Yeah, or have KVM hook into the tcg interrupt dispatch loop at 
cpu_exec.c:cpu_exec(). Not sure which way is easier.

>
>
> ice_call(CPUS390XState *env, struct kvm_run *run,
>>>       r = sclp_service_call(env, sccb, code);
>>>       if (r) {
>>>           setcc(env, 3);
>>> +    } else {
>>> +        setcc(env, 0);
>>>
>> This one looks like an actual fix that is not part of the cleanup?
> Yes it is. Separate patch?

Yes, please :).

>
>>>       }
>>>
>>>       return 0;
>>> diff --git a/target-s390x/op_helper.c b/target-s390x/op_helper.c
>>> index 7b72473..74bd9ad 100644
>>> --- a/target-s390x/op_helper.c
>>> +++ b/target-s390x/op_helper.c
>>> @@ -31,6 +31,7 @@
>>>
>>>   #if !defined (CONFIG_USER_ONLY)
>>>   #include "sysemu.h"
>>> +#include "hw/s390-sclp.h"
>>>
>> #include in hw/ from target-XXX is a no-go. It means our abstraction
>> layer is broken.
> Disagree here. The sclp is a processor that helps the CPU and there is a
> tight link. This is similar to a PIC/APIC etc which are also under hw AND
> included from target-386/ - among others:

Which is exactly why Anthony is suggesting for years now to pull the 
APIC code into target-i386.

To me, the SCLP interface is similar to PIO, MMIO, SPAPR hypercalls, you 
name it. We can certainly have sclp awareness in target-s390x, but 
please don't just blindly include headers from hw/. Split the few bits 
of information that we need in target-s390x into a separate header 
(clean) or target-s390x/cpu.h (hacky, but ok for now) and rather include 
that from hw/.


Alex

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

* Re: [Qemu-devel] [PATCH 8/8] s390: Fix the storage increment size calculation
  2012-06-12 11:53   ` Alexander Graf
@ 2012-06-12 14:57     ` Jeng-fang Wang
  2012-06-18 13:46       ` Alexander Graf
  0 siblings, 1 reply; 51+ messages in thread
From: Jeng-fang Wang @ 2012-06-12 14:57 UTC (permalink / raw)
  To: Alexander Graf
  Cc: Jens Freimann, Heinz Graalfs, Christian Borntraeger, qemu-devel,
	Jens Freimann, Cornelia Huck


[-- Attachment #1.1: Type: text/plain, Size: 2411 bytes --]


Yes, you can refer to AR10040-03-POK, Service-Call Logical Processor
Architecture for S/390 and z/Architecture, Figure 2-6 Minimum storage
increment and subincrement size.  :)

Nick






From:	Alexander Graf <agraf@suse.de>
To:	Jens Freimann <jfrei@de.ibm.com>
Cc:	Jens Freimann <jfrei@linux.vnet.ibm.com>, Cornelia Huck
            <cornelia.huck@de.ibm.com>, qemu-devel <qemu-devel@nongnu.org>,
            Heinz Graalfs <graalfs@linux.vnet.ibm.com>, Jeng-fang
            Wang/Poughkeepsie/IBM@IBMUS
Date:	06/12/2012 07:53 AM
Subject:	Re: [PATCH 8/8] s390: Fix the storage increment size
            calculation



On 06/06/2012 02:05 PM, Jens Freimann wrote:
> From: Nick Wang<jfwang@us.ibm.com>
>
> To comply with the SCLP architecture, the number of storage
> increments should be 512 or fewer. The increment size is a
> multiple of 1M and is a power of 2.
>
> Signed-off-by: Nick Wang<jfwang@us.ibm.com>
> Signed-off-by: Jens Freimann<jfrei@linux.vnet.ibm.com>

Any references to documentation for this one? :)


Alex

> ---
>   hw/s390-sclp.c   |    2 +-
>   hw/s390-virtio.c |    6 +++---
>   2 files changed, 4 insertions(+), 4 deletions(-)
>
> diff --git a/hw/s390-sclp.c b/hw/s390-sclp.c
> index 8f45773..3e91f93 100644
> --- a/hw/s390-sclp.c
> +++ b/hw/s390-sclp.c
> @@ -32,7 +32,7 @@ int sclp_read_info(CPUS390XState *env, struct sccb
*sccb)
>   {
>       int shift = 0;
>
> -    while ((ram_size>>  (20 + shift))>  65535) {
> +    while ((ram_size>>  (20 + shift))>  512) {
>           shift++;
>       }
>       sccb->c.read_info.rnmax = cpu_to_be16(ram_size>>  (20 + shift));
> diff --git a/hw/s390-virtio.c b/hw/s390-virtio.c
> index 0babf27..9578d15 100644
> --- a/hw/s390-virtio.c
> +++ b/hw/s390-virtio.c
> @@ -175,9 +175,9 @@ static void s390_init(ram_addr_t my_ram_size,
>       int i;
>       DeviceState *dev;
>
> -    /* s390x ram size detection needs a 16bit multiplier + an increment.
So
> -       guests>  64GB can be specified in 2MB steps etc. */
> -    while ((my_ram_size>>  (20 + shift))>  65535) {
> +    /* The storage increment size is a multiple of 1M and is a power of
2.
> +     * The number of storage increments must be 512 or fewer. */
> +    while ((my_ram_size>>  (20 + shift))>  512) {
>           shift++;
>       }
>       my_ram_size = my_ram_size>>  (20 + shift)<<  (20 + shift);


[-- Attachment #1.2: Type: text/html, Size: 4378 bytes --]

[-- Attachment #2: graycol.gif --]
[-- Type: image/gif, Size: 105 bytes --]

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

* Re: [Qemu-devel] [PATCH 5/8] s390: Cleanup sclp functions
  2012-06-06 12:05 ` [Qemu-devel] [PATCH 5/8] s390: Cleanup sclp functions Jens Freimann
  2012-06-12  9:58   ` Alexander Graf
@ 2012-06-12 22:38   ` Anthony Liguori
  1 sibling, 0 replies; 51+ messages in thread
From: Anthony Liguori @ 2012-06-12 22:38 UTC (permalink / raw)
  To: Jens Freimann
  Cc: Heinz Graalfs, Alexander Graf, qemu-devel, Christian Borntraeger,
	Jens Freimann, Cornelia Huck

On 06/06/2012 07:05 AM, Jens Freimann wrote:
> From: Christian Borntraeger<borntraeger@de.ibm.com>
>
> The sclp facility on s390 is a hardware that is external to the cpu.
> Lets cleanup the definitions and move the functionality into a separate
> file under hw/.
>
> Signed-off-by: Christian Borntraeger<borntraeger@de.ibm.com>
> Signed-off-by: Jens Freimann<jfrei@de.ibm.com>
> ---
>   Makefile.target          |    2 +-
>   hw/s390-sclp.c           |   42 ++++++++++++++++++++++++++++++++++++++++++
>   hw/s390-sclp.h           |   34 ++++++++++++++++++++++++++++++++++
>   target-s390x/cpu.h       |   11 -----------
>   target-s390x/kvm.c       |    5 ++---
>   target-s390x/op_helper.c |   39 +++++++++++++++++----------------------
>   6 files changed, 96 insertions(+), 37 deletions(-)
>   create mode 100644 hw/s390-sclp.c
>   create mode 100644 hw/s390-sclp.h
>
> diff --git a/Makefile.target b/Makefile.target
> index 1582904..fed2d72 100644
> --- a/Makefile.target
> +++ b/Makefile.target
> @@ -374,7 +374,7 @@ obj-sh4-y += ide/mmio.o
>   obj-m68k-y = an5206.o mcf5206.o mcf_uart.o mcf_intc.o mcf5208.o mcf_fec.o
>   obj-m68k-y += m68k-semi.o dummy_m68k.o
>
> -obj-s390x-y = s390-virtio-bus.o s390-virtio.o
> +obj-s390x-y = s390-virtio-bus.o s390-virtio.o s390-sclp.o
>
>   obj-alpha-y = mc146818rtc.o
>   obj-alpha-y += alpha_pci.o alpha_dp264.o alpha_typhoon.o
> diff --git a/hw/s390-sclp.c b/hw/s390-sclp.c
> new file mode 100644
> index 0000000..c046441
> --- /dev/null
> +++ b/hw/s390-sclp.c
> @@ -0,0 +1,42 @@
> +/*
> + * sclp facility
> + * Copyright IBM Corp. 2012
> + * Author: Christian Borntraeger<borntraeger@de.ibm.com>
> + *
> + */

Each file needs a license statement.  Take a look at virtio.c for an example.

> +#include "cpu.h"
> +#include "kvm.h"
> +#include "hw/s390-sclp.h"
> +
> +int sclp_read_info(CPUS390XState *env, struct sccb *sccb)
> +{
> +    int shift = 0;
> +
> +    while ((ram_size>>  (20 + shift))>  65535) {
> +        shift++;
> +    }
> +    sccb->c.read_info.rnmax = cpu_to_be16(ram_size>>  (20 + shift));
> +    sccb->c.read_info.rnsize = 1<<  shift;
> +    sccb->h.response_code = cpu_to_be16(0x10);
> +
> +    return 0;
> +}
> +
> +void sclp_service_interrupt(CPUS390XState *env, uint32_t sccb)
> +{
> +    if (!sccb) {
> +        return;
> +    }
> +
> +    if (kvm_enabled()) {
> +#ifdef CONFIG_KVM
> +        kvm_s390_interrupt_internal(env, KVM_S390_INT_SERVICE,
> +                                    (sccb&  ~3), 0, 1);
> +#endif
> +    } else {
> +        env->psw.addr += 4;
> +        cpu_inject_ext(env, EXT_SERVICE, (sccb&  ~3), 0);
> +    }
> +}
> +

As a basic rule, if it's in hw/, it shouldn't interact with CPUState.

If you need to raise an interrupt, you should use a qemu_irq.

I don't know anything about sclp.  Does it use a reasonable calling convention 
where the arguments are within specific registers such that you could pass an 
array of ulongs as inputs and return a ulong as output?

> diff --git a/hw/s390-sclp.h b/hw/s390-sclp.h
> new file mode 100644
> index 0000000..e335b21
> --- /dev/null
> +++ b/hw/s390-sclp.h
> @@ -0,0 +1,34 @@
> +#include<stdint.h>
> +#include<qemu-common.h>


qemu-common.h is not a system header and stdint should not be required.  You 
also need a copyright/license statement.

> +
> +
> +/* SCLP command codes */
> +#define SCLP_CMDW_READ_SCP_INFO                 0x00020001
> +#define SCLP_CMDW_READ_SCP_INFO_FORCED          0x00120001
> +
> +/* SCLP response codes */
> +#define SCLP_RC_SCCB_RESOURCE_INSUFFICENT       0x07f0
> +
> +struct sccb_header {
> +    uint16_t length;
> +#define SCLP_FC_NORMAL_WRITE                    0
> +    uint8_t function_code;
> +    uint8_t control_mask[3];
> +    uint16_t response_code;
> +} __attribute__((packed));

This violates CodingStyle.  The use of packed is always suspicious.  It 
typically indicates you aren't handling endianness correctly.

> +
> +struct read_info_sccb {
> +    uint16_t rnmax;
> +    uint8_t rnsize;
> +} __attribute__((packed));
> +
> +struct sccb {
> +    struct sccb_header h;
> +    union {
> +        struct read_info_sccb read_info;
> +        char data[4088];
> +    } c;
> + } __attribute__((packed));
> +
> +int sclp_read_info(CPUS390XState *env, struct sccb *sccb);
> +void sclp_service_interrupt(CPUS390XState *env, uint32_t sccb);

You have no #ifdef guards on this header...

> diff --git a/target-s390x/cpu.h b/target-s390x/cpu.h
> index 2f3f394..d0199d7 100644
> --- a/target-s390x/cpu.h
> +++ b/target-s390x/cpu.h
> @@ -591,17 +591,6 @@ static inline const char *cc_name(int cc_op)
>       return cc_names[cc_op];
>   }
>
> -/* SCLP PV interface defines */
> -#define SCLP_CMDW_READ_SCP_INFO         0x00020001
> -#define SCLP_CMDW_READ_SCP_INFO_FORCED  0x00120001
> -
> -#define SCP_LENGTH                      0x00
> -#define SCP_FUNCTION_CODE               0x02
> -#define SCP_CONTROL_MASK                0x03
> -#define SCP_RESPONSE_CODE               0x06
> -#define SCP_MEM_CODE                    0x08
> -#define SCP_INCREMENT                   0x0a
> -
>   typedef struct LowCore
>   {
>       /* prefix area: defined by architecture */
> diff --git a/target-s390x/kvm.c b/target-s390x/kvm.c
> index 73cfd1f..7a7604b 100644
> --- a/target-s390x/kvm.c
> +++ b/target-s390x/kvm.c
> @@ -60,9 +60,6 @@
>   #define SIGP_STORE_STATUS_ADDR          0x0e
>   #define SIGP_SET_ARCH                   0x12
>
> -#define SCLP_CMDW_READ_SCP_INFO         0x00020001
> -#define SCLP_CMDW_READ_SCP_INFO_FORCED  0x00120001
> -
>   const KVMCapabilityInfo kvm_arch_required_capabilities[] = {
>       KVM_CAP_LAST_INFO
>   };
> @@ -246,6 +243,8 @@ static int kvm_sclp_service_call(CPUS390XState *env, struct kvm_run *run,
>       r = sclp_service_call(env, sccb, code);
>       if (r) {
>           setcc(env, 3);
> +    } else {
> +        setcc(env, 0);
>       }
>
>       return 0;
> diff --git a/target-s390x/op_helper.c b/target-s390x/op_helper.c
> index 7b72473..74bd9ad 100644
> --- a/target-s390x/op_helper.c
> +++ b/target-s390x/op_helper.c
> @@ -31,6 +31,7 @@
>
>   #if !defined (CONFIG_USER_ONLY)
>   #include "sysemu.h"
> +#include "hw/s390-sclp.h"
>   #endif
>
>   /*****************************************************************************/
> @@ -2360,16 +2361,13 @@ static void program_interrupt(CPUS390XState *env, uint32_t code, int ilc)
>       }
>   }
>
> -static void ext_interrupt(CPUS390XState *env, int type, uint32_t param,
> -                          uint64_t param64)
> -{
> -    cpu_inject_ext(env, type, param, param64);
> -}
>
>   int sclp_service_call(CPUS390XState *env, uint32_t sccb, uint64_t code)
>   {
>       int r = 0;
> -    int shift = 0;
> +    struct sccb work_sccb;
> +    struct sccb *guest_sccb;
> +    target_phys_addr_t sccb_len = sizeof(*guest_sccb);
>
>   #ifdef DEBUG_HELPER
>       printf("sclp(0x%x, 0x%" PRIx64 ")\n", sccb, code);
> @@ -2380,26 +2378,18 @@ int sclp_service_call(CPUS390XState *env, uint32_t sccb, uint64_t code)
>           r = -1;
>           goto out;
>       }
> +    /*
> +     * we want to work on a private copy of the sccb, to prevent guests
> +     * from playing dirty tricks by modifying the memory content after
> +     * the host has checked the values
> +     */
> +    guest_sccb = cpu_physical_memory_map(sccb,&sccb_len, true);
> +    memcpy(&work_sccb, guest_sccb, sizeof(*guest_sccb));

This is definitely wrong.  You should use cpu_physical_mmeory_read()

>
>       switch(code) {
>           case SCLP_CMDW_READ_SCP_INFO:
>           case SCLP_CMDW_READ_SCP_INFO_FORCED:
> -            while ((ram_size>>  (20 + shift))>  65535) {
> -                shift++;
> -            }
> -            stw_phys(sccb + SCP_MEM_CODE, ram_size>>  (20 + shift));
> -            stb_phys(sccb + SCP_INCREMENT, 1<<  shift);
> -            stw_phys(sccb + SCP_RESPONSE_CODE, 0x10);
> -
> -            if (kvm_enabled()) {
> -#ifdef CONFIG_KVM
> -                kvm_s390_interrupt_internal(env, KVM_S390_INT_SERVICE,
> -                                            sccb&  ~3, 0, 1);
> -#endif
> -            } else {
> -                env->psw.addr += 4;
> -                ext_interrupt(env, EXT_SERVICE, sccb&  ~3, 0);
> -            }
> +            r = sclp_read_info(env,&work_sccb);
>               break;
>           default:
>   #ifdef DEBUG_HELPER
> @@ -2408,6 +2398,11 @@ int sclp_service_call(CPUS390XState *env, uint32_t sccb, uint64_t code)
>               r = -1;
>               break;
>       }
> +    memcpy(guest_sccb,&work_sccb, work_sccb.h.length);

And then cpu_physical_memory_write().  Now you are handling endianness correctly 
but I still think it's better to not rely on packed and instead read the 
structure from memory using ldl_phys, etc.

> +    cpu_physical_memory_unmap(guest_sccb, 4096, true, 4096);

It's very odd that you're passing 4096 here...

Regards,

Anthony Liguori

> +    if (!r) {
> +        sclp_service_interrupt(env, sccb);
> +    }
>
>   out:
>       return r;

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

* Re: [Qemu-devel] [PATCH 5/8] s390: Cleanup sclp functions
  2012-06-12 12:32       ` Alexander Graf
@ 2012-06-12 22:41         ` Anthony Liguori
  0 siblings, 0 replies; 51+ messages in thread
From: Anthony Liguori @ 2012-06-12 22:41 UTC (permalink / raw)
  To: Alexander Graf
  Cc: Jens Freimann, Heinz Graalfs, qemu-devel, Christian Borntraeger,
	Jens Freimann, Cornelia Huck, Andreas Färber

On 06/12/2012 07:32 AM, Alexander Graf wrote:
> On 06/12/2012 02:24 PM, Christian Borntraeger wrote:
>> Yes we will re-split the sclp patches.
>>
>> besides that, some comments:
>>
>> On 12/06/12 11:58, Alexander Graf wrote:
>>>> +#include "hw/s390-sclp.h"
>>>>
>>> No need for hw/.
>> will fix.
>>
>>
>>>> +void sclp_service_interrupt(CPUS390XState *env, uint32_t sccb)
>>>> +{
>>>> + if (!sccb) {
>>>> + return;
>>>> + }
>>>> +
>>>> + if (kvm_enabled()) {
>>>> +#ifdef CONFIG_KVM
>>>>
>>> You shouldn't know about CONFIG_KVM in hw/. So we have to generalize
>>> this code.
>> Ok, Maybe an exported interface for sending interrupts to the guest
>> under target-s390/ that hides the kvm/tcg thing.
>
> Yeah, or have KVM hook into the tcg interrupt dispatch loop at
> cpu_exec.c:cpu_exec(). Not sure which way is easier.
>
>>
>>
>> ice_call(CPUS390XState *env, struct kvm_run *run,
>>>> r = sclp_service_call(env, sccb, code);
>>>> if (r) {
>>>> setcc(env, 3);
>>>> + } else {
>>>> + setcc(env, 0);
>>>>
>>> This one looks like an actual fix that is not part of the cleanup?
>> Yes it is. Separate patch?
>
> Yes, please :).
>
>>
>>>> }
>>>>
>>>> return 0;
>>>> diff --git a/target-s390x/op_helper.c b/target-s390x/op_helper.c
>>>> index 7b72473..74bd9ad 100644
>>>> --- a/target-s390x/op_helper.c
>>>> +++ b/target-s390x/op_helper.c
>>>> @@ -31,6 +31,7 @@
>>>>
>>>> #if !defined (CONFIG_USER_ONLY)
>>>> #include "sysemu.h"
>>>> +#include "hw/s390-sclp.h"
>>>>
>>> #include in hw/ from target-XXX is a no-go. It means our abstraction
>>> layer is broken.
>> Disagree here. The sclp is a processor that helps the CPU and there is a
>> tight link. This is similar to a PIC/APIC etc which are also under hw AND
>> included from target-386/ - among others:
>
> Which is exactly why Anthony is suggesting for years now to pull the APIC code
> into target-i386.

Indeed :-)

>
> To me, the SCLP interface is similar to PIO, MMIO, SPAPR hypercalls, you name
> it.

Yeah, the SPAPR hypercalls is a good one I think but I don't know enough about 
SCLP yet.  From what's here, it would be pretty easy to model with qemu_irq I think.

We do that for target-i386 for things like the a20 line which is another case 
where random hardware interacts with the cpu in a far too personal fashion.

Regards,

Anthony Liguori

  We can certainly have sclp awareness in target-s390x, but please don't just
> blindly include headers from hw/. Split the few bits of information that we need
> in target-s390x into a separate header (clean) or target-s390x/cpu.h (hacky, but
> ok for now) and rather include that from hw/.
>
>
> Alex
>
>
>

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

* Re: [Qemu-devel] [PATCH 6/8] s390: sclp event facility and signal quiesce support via system_powerdown
  2012-06-12 11:38   ` Alexander Graf
@ 2012-06-13  7:00     ` Heinz Graalfs
  2012-06-13 13:12       ` Andreas Färber
  0 siblings, 1 reply; 51+ messages in thread
From: Heinz Graalfs @ 2012-06-13  7:00 UTC (permalink / raw)
  To: Alexander Graf
  Cc: Jens Freimann, qemu-devel, Christian Borntraeger, Jens Freimann,
	Cornelia Huck, Andreas Färber

Alex, thanks for the comments,

On Tue, 2012-06-12 at 13:38 +0200, Alexander Graf wrote:
> On 06/06/2012 02:05 PM, Jens Freimann wrote:
> > From: Heinz Graalfs<graalfs@linux.vnet.ibm.com>
> >
> > This patch implements a subset of the sclp event facility as well
> > as the signal quiesce event. This allows to gracefully shutdown
> > a guest by using system_powerdown. This sends a signal quiesce
> > signal that is interpreted by linux guests as ctrl-alt-del.
> > In addition the event facility is modeled using the QOM.
> >
> > Signed-off-by: Heinz Graalfs<graalfs@linux.vnet.ibm.com>
> > Signed-off-by: Christian Borntraeger<borntraeger@de.ibm.com>
> > Signed-off-by: Jens Freimann<jfrei@de.ibm.com>
> 
> Andreas, I'm always getting headaches reviewing qdev and/or qom patches. 
> Could you please check this for layering violations?
> 
> > ---
> >   Makefile.target          |    1 +
> >   hw/s390-event-facility.c |  232 +++++++++++++++++++++++++++++++++++++++++
> >   hw/s390-event-facility.h |   54 ++++++++++
> >   hw/s390-sclp.c           |  256 +++++++++++++++++++++++++++++++++++++++++++++-
> >   hw/s390-sclp.h           |   98 +++++++++++++++++-
> >   hw/s390-virtio.c         |   11 +-
> >   target-s390x/op_helper.c |    3 +
> >   7 files changed, 649 insertions(+), 6 deletions(-)
> >   create mode 100644 hw/s390-event-facility.c
> >   create mode 100644 hw/s390-event-facility.h
> >
> > diff --git a/Makefile.target b/Makefile.target
> > index fed2d72..f939c3a 100644
> > --- a/Makefile.target
> > +++ b/Makefile.target
> > @@ -375,6 +375,7 @@ obj-m68k-y = an5206.o mcf5206.o mcf_uart.o mcf_intc.o mcf5208.o mcf_fec.o
> >   obj-m68k-y += m68k-semi.o dummy_m68k.o
> >
> >   obj-s390x-y = s390-virtio-bus.o s390-virtio.o s390-sclp.o
> > +obj-s390x-y += s390-event-facility.o
> >
> >   obj-alpha-y = mc146818rtc.o
> >   obj-alpha-y += alpha_pci.o alpha_dp264.o alpha_typhoon.o
> > diff --git a/hw/s390-event-facility.c b/hw/s390-event-facility.c
> > new file mode 100644
> > index 0000000..b8106a6
> > --- /dev/null
> > +++ b/hw/s390-event-facility.c
> > @@ -0,0 +1,232 @@
> > +/*
> > + * SCLP Event Facility
> > + *
> > + * Copyright IBM Corp. 2007,2012
> > + * Author: Heinz Graalfs<graalfs@de.ibm.com>
> > + *
> > + * This file is licensed under the terms of the GNU General Public License(GPL)
> > + */
> > +
> > +#include "iov.h"
> > +#include "monitor.h"
> > +#include "qemu-queue.h"
> > +#include "sysbus.h"
> > +#include "sysemu.h"
> > +
> > +#include "s390-sclp.h"
> > +#include "s390-event-facility.h"
> > +
> > +struct SCLPDevice {
> > +    const char *name;
> > +    bool vm_running;
> > +};
> > +
> > +struct SCLP {
> > +    BusState qbus;
> > +    SCLPEventFacility *event_facility;
> > +};
> > +
> > +struct SCLPEventFacility {
> > +    SCLPDevice sdev;
> > +    SCLP sbus;
> > +    DeviceState *qdev;
> > +    void *opaque;
> > +};
> > +
> > +typedef struct SCLPConsole {
> > +    SCLPEvent event;
> > +    CharDriverState *chr;
> > +} SCLPConsole;
> > +
> > +static void sclpef_bus_dev_print(Monitor *mon, DeviceState *qdev, int indent)
> > +{
> > +    SCLPEvent *event = DO_UPCAST(SCLPEvent, dev, qdev);
> > +
> > +    monitor_printf(mon, "%*sid %d\n", indent, "", event->id);
> > +}
> > +
> > +static unsigned int send_mask_quiesce(void)
> > +{
> > +    return SCLP_EVENT_MASK_SIGNAL_QUIESCE;
> > +}
> > +
> > +static unsigned int receive_mask_quiesce(void)
> > +{
> > +    return 0;
> > +}
> > +
> > +static void s390_signal_quiesce(void *opaque, int n, int level)
> > +{
> > +    sclp_enable_signal_quiesce();
> > +    sclp_service_interrupt(opaque, 0);
> > +}
> > +
> > +unsigned int sclpef_send_mask(SCLPDevice *sdev)
> > +{
> > +    unsigned int mask;
> > +    DeviceState *dev;
> > +    SCLPEventFacility *event_facility;
> > +    SCLPEventClass *cons;
> > +
> > +    event_facility = DO_UPCAST(SCLPEventFacility, sdev, sdev);
> > +
> > +    mask = 0;
> > +
> > +    QTAILQ_FOREACH(dev,&event_facility->sbus.qbus.children, sibling) {
> > +        cons = SCLP_EVENT_GET_CLASS((SCLPEvent *) dev);
> > +        mask |= cons->get_send_mask();
> > +    }
> > +    return mask;
> > +}
> > +
> > +unsigned int sclpef_receive_mask(SCLPDevice *sdev)
> > +{
> > +    unsigned int mask;
> > +    DeviceState *dev;
> > +    SCLPEventClass *cons;
> > +    SCLPEventFacility *event_facility;
> > +
> > +    event_facility = DO_UPCAST(SCLPEventFacility, sdev, sdev);
> > +
> > +    mask = 0;
> > +
> > +    QTAILQ_FOREACH(dev,&event_facility->sbus.qbus.children, sibling) {
> > +        cons = SCLP_EVENT_GET_CLASS((SCLPEvent *) dev);
> > +        mask |= cons->get_receive_mask();
> > +    }
> > +    return mask;
> > +}
> > +
> > +static struct BusInfo sclp_bus_info = {
> > +    .name      = "s390-sclp-bus",
> > +    .size      = sizeof(SCLPS390Bus),
> > +    .print_dev = sclpef_bus_dev_print,
> > +    .props      = (Property[]) {
> > +        DEFINE_PROP_STRING("name", SCLPEvent, name),
> > +        DEFINE_PROP_END_OF_LIST()
> > +    }
> > +};
> > +
> > +static int sclpef_qdev_init(DeviceState *qdev)
> > +{
> > +    int rc;
> > +    SCLPEvent *event = DO_UPCAST(SCLPEvent, dev, qdev);
> > +    SCLPEventClass *cons = SCLP_EVENT_GET_CLASS(event);
> > +    SCLP *bus = DO_UPCAST(SCLP, qbus, qdev->parent_bus);
> > +
> > +    event->evt_fac = bus->event_facility;
> > +    rc = cons->init(event);
> > +
> > +    return rc;
> > +}
> > +
> > +static int sclpef_qdev_exit(DeviceState *qdev)
> > +{
> > +    SCLPEvent *event = DO_UPCAST(SCLPEvent, dev, qdev);
> > +    SCLPEventClass *cons = SCLP_EVENT_GET_CLASS(event);
> > +    if (cons->exit) {
> > +        cons->exit(event);
> > +    }
> > +    return 0;
> > +}
> > +
> > +static SCLPDevice *sclpef_common_init(const char *name, size_t struct_size)
> > +{
> > +    SCLPDevice *sdev;
> > +
> > +    sdev = malloc(struct_size);
> 
> g_malloc please. I suppose even g_malloc0?
> 
OK, I will look into this
> > +    if (!sdev) {
> > +        return NULL;
> > +    }
> > +    sdev->vm_running = runstate_is_running();
> > +    sdev->name = name;
> > +
> > +    return sdev;
> > +}
> > +
> > +void sclpef_enable_irqs(SCLPDevice *sdev, void *opaque)
> > +{
> > +    SCLPEventFacility *event_facility;
> > +
> > +    event_facility = DO_UPCAST(SCLPEventFacility, sdev, sdev);
> > +    qemu_system_powerdown = *qemu_allocate_irqs(s390_signal_quiesce,
> > +                                                opaque, 1);
> > +    event_facility->opaque = opaque;
> > +}
> > +
> > +SCLPDevice *sclpef_init_event_facility(DeviceState *dev)
> > +{
> > +    DeviceState *quiesce;
> > +    SCLPDevice *sdev;
> > +    SCLPEventFacility *event_facility;
> > +
> > +    sdev = sclpef_common_init("sclp-event-facility",
> > +            sizeof(SCLPEventFacility));
> > +
> > +    if (!sdev) {
> > +        return NULL;
> > +    }
> > +    event_facility = DO_UPCAST(SCLPEventFacility, sdev, sdev);
> > +
> > +    /* Spawn a new sclp-facility */
> > +    qbus_create_inplace(&event_facility->sbus.qbus,&sclp_bus_info, dev, NULL);
> > +    event_facility->sbus.qbus.allow_hotplug = 0;
> > +    event_facility->sbus.event_facility = event_facility;
> > +    event_facility->qdev = dev;
> > +    event_facility->opaque = NULL;
> > +    quiesce = qdev_create(&event_facility->sbus.qbus, "sclpquiesce");
> > +
> > +    if (!quiesce) {
> > +        return NULL;
> > +    }
> > +
> > +    return sdev;
> > +}
> > +
> > +static void sclpef_class_init(ObjectClass *klass, void *data)
> > +{
> > +    DeviceClass *dc = DEVICE_CLASS(klass);
> > +    dc->init = sclpef_qdev_init;
> > +    dc->bus_info =&sclp_bus_info;
> > +    dc->exit = sclpef_qdev_exit;
> > +    dc->unplug = qdev_simple_unplug_cb;
> > +}
> > +
> > +static TypeInfo sclp_event_facility_type_info = {
> > +    .name = TYPE_SCLP_EVENT,
> > +    .parent = TYPE_DEVICE,
> > +    .instance_size = sizeof(SCLPEvent),
> > +    .class_size = sizeof(SCLPEventClass),
> > +    .class_init = sclpef_class_init,
> > +    .abstract = true,
> > +};
> > +
> > +static int sclpquiesce_initfn(SCLPEvent *event)
> > +{
> > +    event->id = ID_QUIESCE;
> > +
> > +    return 0;
> > +}
> > +
> > +static void sclpef_quiesce_class_init(ObjectClass *klass, void *data)
> > +{
> > +    SCLPEventClass *k = SCLP_EVENT_CLASS(klass);
> > +
> > +    k->init = sclpquiesce_initfn;
> > +    k->get_send_mask = send_mask_quiesce;
> > +    k->get_receive_mask = receive_mask_quiesce;
> > +}
> > +
> > +static TypeInfo sclp_quiesce_info = {
> > +    .name          = "sclpquiesce",
> > +    .parent        = TYPE_SCLP_EVENT,
> > +    .instance_size = sizeof(SCLPEvent),
> > +    .class_init    = sclpef_quiesce_class_init,
> > +};
> > +
> > +static void sclpef_register_types(void)
> > +{
> > +    type_register_static(&sclp_event_facility_type_info);
> > +    type_register_static(&sclp_quiesce_info);
> > +}
> > +type_init(sclpef_register_types)
> > diff --git a/hw/s390-event-facility.h b/hw/s390-event-facility.h
> > new file mode 100644
> > index 0000000..40d4049
> > --- /dev/null
> > +++ b/hw/s390-event-facility.h
> > @@ -0,0 +1,54 @@
> > +/*
> > + * SCLP definitions
> > + *
> > + * Copyright IBM Corp. 2007,2012
> > + * Author: Heinz Graalfs<graalfs@de.ibm.com>
> > + *
> > + * This file is licensed under the terms of the GNU General Public License(GPL)
> > + */
> > +
> > +#ifndef _QEMU_SCLP_EVENT_H
> > +#define _QEMU_SCLP_EVENT_H
> > +
> > +#include "qdev.h"
> > +#include "qemu-common.h"
> > +
> > +#define ID_QUIESCE SCLP_EVENT_SIGNAL_QUIESCE
> > +
> > +#define TYPE_SCLP_EVENT "s390-sclp-event-type"
> > +#define SCLP_EVENT(obj) \
> > +     OBJECT_CHECK(SCLPEvent, (obj), TYPE_SCLP_EVENT)
> > +#define SCLP_EVENT_CLASS(klass) \
> > +     OBJECT_CLASS_CHECK(SCLPEventClass, (klass), TYPE_SCLP_EVENT)
> > +#define SCLP_EVENT_GET_CLASS(obj) \
> > +     OBJECT_GET_CLASS(SCLPEventClass, (obj), TYPE_SCLP_EVENT)
> > +
> > +typedef struct SCLP SCLP;
> > +typedef struct SCLPEventFacility SCLPEventFacility;
> > +typedef struct SCLPEvent SCLPEvent;
> > +typedef struct SCLPDevice SCLPDevice;
> > +
> > +typedef struct SCLPEventClass {
> > +    DeviceClass parent_class;
> > +    int (*init)(SCLPEvent *event);
> > +    int (*exit)(SCLPEvent *event);
> > +    unsigned int (*get_send_mask)(void);
> > +    unsigned int (*get_receive_mask)(void);
> > +} SCLPEventClass;
> > +
> > +struct SCLPEvent {
> > +    DeviceState dev;
> > +    SCLPEventFacility *evt_fac;
> > +    char *name;
> > +    uint32_t id;
> > +};
> > +
> > +SCLPDevice *sclpef_init_event_facility(DeviceState *dev);
> > +
> > +void sclpef_enable_irqs(SCLPDevice *sdev, void *opaque);
> > +
> > +void sclpef_set_masks(void);
> > +unsigned int sclpef_send_mask(SCLPDevice *sdev);
> > +unsigned int sclpef_receive_mask(SCLPDevice *sdev);
> > +
> > +#endif
> > diff --git a/hw/s390-sclp.c b/hw/s390-sclp.c
> > index c046441..683a709 100644
> > --- a/hw/s390-sclp.c
> > +++ b/hw/s390-sclp.c
> > @@ -7,7 +7,20 @@
> >
> >   #include "cpu.h"
> >   #include "kvm.h"
> > +#include "hw/sysbus.h"
> >   #include "hw/s390-sclp.h"
> > +#include "hw/s390-event-facility.h"
> > +
> > +/* Host capabilites */
> > +static unsigned int sclp_send_mask;
> > +static unsigned int sclp_receive_mask;
> > +
> > +/* Guest capabilities */
> > +static unsigned int sclp_cp_send_mask;
> > +static unsigned int sclp_cp_receive_mask;
> > +
> > +static int quiesce;
> > +static int event_pending;
> 
> Global variables? Bad idea :). These should be properties of your 
> quiesce device.
> 
OK, I'll look onto this
> >
> >   int sclp_read_info(CPUS390XState *env, struct sccb *sccb)
> >   {
> > @@ -23,20 +36,257 @@ int sclp_read_info(CPUS390XState *env, struct sccb *sccb)
> >       return 0;
> >   }
> >
> > +static int signal_quiesce_event(struct sccb *sccb, int *slen)
> > +{
> > +    if (!quiesce) {
> > +        return 0;
> > +    }
> > +
> > +    if (*slen<  sizeof(struct signal_quiesce)) {
> > +        event_pending = 1;
> > +        return 0;
> > +    }
> > +
> > +    sccb->c.read.quiesce.h.length = cpu_to_be16(sizeof(struct signal_quiesce));
> > +    sccb->c.read.quiesce.h.type = SCLP_EVENT_SIGNAL_QUIESCE;
> > +    sccb->c.read.quiesce.h.flags&= ~SCLP_EVENT_BUFFER_ACCEPTED;
> > +    /*
> > +     * system_powerdown does not have a timeout. Fortunately the
> > +     * timeout value is curently ignored by Linux, anyway
> > +     */
> > +    sccb->c.read.quiesce.timeout = cpu_to_be16(0);
> > +    sccb->c.read.quiesce.unit = cpu_to_be16(0);
> > +
> > +    quiesce = 0;
> > +    *slen -= sizeof(struct signal_quiesce);
> > +    return 1;
> > +}
> > +
> > +void sclp_enable_signal_quiesce(void)
> > +{
> > +    quiesce = 1;
> > +    event_pending = 1;
> > +}
> > +
> > +static void sclp_set_masks(void)
> > +{
> > +    SCLPS390EventFacility *evt_fac;
> > +
> > +    if (!sclp_bus) {
> > +        return;
> > +    }
> > +    evt_fac = sclp_bus->event_facility;
> > +
> > +    assert(evt_fac);
> > +
> > +    sclp_send_mask = sclpef_send_mask(evt_fac->sdev);
> > +    sclp_receive_mask = sclpef_receive_mask(evt_fac->sdev);
> > + }
> > +
> > +int sclp_read_event_data(CPUS390XState *env, struct sccb *sccb)
> > +{
> > +    unsigned int sclp_active_selection_mask;
> > +    int slen;
> > +
> > +    if (be16_to_cpu(sccb->h.length) != SCCB_SIZE) {
> > +        sccb->h.response_code = cpu_to_be16(SCLP_RC_INSUFFICIENT_SCCB_LENGTH);
> > +        goto out;
> > +    }
> > +
> > +    switch (sccb->h.function_code) {
> > +    case SCLP_UNCONDITIONAL_READ:
> > +        sclp_active_selection_mask = sclp_cp_receive_mask;
> > +        break;
> > +    case SCLP_SELECTIVE_READ:
> > +        if (!(sclp_cp_receive_mask&  be32_to_cpu(sccb->c.read.mask))) {
> > +            sccb->h.response_code = cpu_to_be16(SCLP_RC_INVALID_SELECTION_MASK);
> > +            goto out;
> > +        }
> > +        sclp_active_selection_mask = be32_to_cpu(sccb->c.read.mask);
> > +        break;
> > +    default:
> > +        sccb->h.response_code = cpu_to_be16(SCLP_RC_INVALID_FUNCTION);
> > +        goto out;
> > +    }
> > +
> > +    slen = sizeof(sccb->c.data);
> > +    sccb->h.response_code = cpu_to_be16(SCLP_RC_NO_EVENT_BUFFERS_STORED);
> > +
> > +    if (sclp_active_selection_mask&  SCLP_EVENT_MASK_SIGNAL_QUIESCE) {
> > +        if (signal_quiesce_event(sccb,&slen)) {
> > +            sccb->h.response_code = cpu_to_be16(SCLP_RC_NORMAL_COMPLETION);
> > +        }
> > +    }
> > +
> > +    if (sccb->h.control_mask[2]&  SCLP_VARIABLE_LENGTH_RESPONSE) {
> > +        sccb->h.control_mask[2]&= ~SCLP_VARIABLE_LENGTH_RESPONSE;
> > +        sccb->h.length = cpu_to_be16(SCCB_SIZE - slen);
> > +    }
> > +
> > +out:
> > +    return 0;
> > +}
> > +
> > +int sclp_write_event_mask(CPUS390XState *env, struct sccb *sccb)
> > +{
> > +    /* Attention: We assume that Linux uses 4-byte masks, what it actually
> > +       does. Architecture allows for masks of variable size, though */
> > +    if (be16_to_cpu(sccb->c.we_mask.mask_length) != 4) {
> > +        sccb->h.response_code = cpu_to_be16(SCLP_RC_INVALID_MASK_LENGTH);
> > +        goto out;
> > +    }
> > +
> > +    /* keep track of the guest's capability masks */
> > +    sclp_cp_send_mask = be32_to_cpu(sccb->c.we_mask.cp_send_mask);
> > +    sclp_cp_receive_mask = be32_to_cpu(sccb->c.we_mask.cp_receive_mask);
> > +
> > +    sclp_set_masks();
> > +
> > +    /* return the SCLP's capability masks to the guest */
> > +    sccb->c.we_mask.send_mask = cpu_to_be32(sclp_send_mask);
> > +    sccb->c.we_mask.receive_mask = cpu_to_be32(sclp_receive_mask);
> > +
> > +    sccb->h.response_code = cpu_to_be32(SCLP_RC_NORMAL_COMPLETION);
> > +
> > +out:
> > +    return 0;
> > +}
> > +
> >   void sclp_service_interrupt(CPUS390XState *env, uint32_t sccb)
> >   {
> > -    if (!sccb) {
> > +    if (!event_pending&&  !sccb) {
> >           return;
> >       }
> >
> >       if (kvm_enabled()) {
> >   #ifdef CONFIG_KVM
> >           kvm_s390_interrupt_internal(env, KVM_S390_INT_SERVICE,
> > -                                    (sccb&  ~3), 0, 1);
> > +                                    (sccb&  ~3) + event_pending, 0, 1);
> >   #endif
> >       } else {
> >           env->psw.addr += 4;
> > -        cpu_inject_ext(env, EXT_SERVICE, (sccb&  ~3), 0);
> > +        cpu_inject_ext(env, EXT_SERVICE, (sccb&  ~3) + event_pending, 0);
> > +    }
> 
> Please fix the above piece of code to use the same mechanism regarless 
> of TCG or KVM, so that SCLP code doesn't have to be aware of KVM.
> 
> > +    event_pending = 0;
> > +}
> > +
> > +struct BusInfo s390_sclp_bus_info = {
> > +    .name       = "s390-sclp",
> > +    .size       = sizeof(SCLPS390Bus),
> > +};
> > +
> > +SCLPS390Bus *s390_sclp_bus_init(void)
> > +{
> > +    SCLPS390Bus *bus;
> > +    BusState *bus_state;
> > +    DeviceState *dev;
> > +
> > +    dev = qdev_create(NULL, "s390-sclp-bridge");
> > +    qdev_init_nofail(dev);
> > +    bus_state = qbus_create(&s390_sclp_bus_info, dev, "s390-sclp-bus");
> > +    bus = DO_UPCAST(SCLPS390Bus, bus, bus_state);
> > +
> > +    bus_state->allow_hotplug = 0;
> > +
> > +    return bus;
> > +}
> > +
> > +static int s390_sclp_device_init(SCLPS390EventFacility *dev, SCLPDevice *sdev)
> > +{
> > +    dev->sdev = sdev;
> > +
> > +    return 0;
> > +}
> > +
> > +static int s390_sclp_init(SCLPS390EventFacility *dev)
> > +{
> > +    int rc;
> > +    SCLPS390Bus *bus;
> > +    SCLPDevice *sdev;
> > +
> > +    bus = DO_UPCAST(SCLPS390Bus, bus, dev->qdev.parent_bus);
> > +
> > +    sdev = sclpef_init_event_facility((DeviceState *)dev);
> > +    if (!sdev) {
> > +        return -1;
> >       }
> > +
> > +    rc = s390_sclp_device_init(dev, sdev);
> > +    if (!rc) {
> > +        bus->event_facility = dev;
> > +    }
> > +
> > +    return rc;
> > +}
> > +
> > +static void s390_sclp_class_init(ObjectClass *klass, void *data)
> > +{
> > +    SCLPS390EventFacilityClass *k = SCLP_S390_EVENT_FACILITY_CLASS(klass);
> > +
> > +    k->init = s390_sclp_init;
> > +}
> > +
> > +static TypeInfo s390_sclp_event_facility = {
> > +    .name          = "sclp-event-facility",
> > +    .parent        = TYPE_SCLP_S390_EVENT_FACILITY,
> > +    .instance_size = sizeof(SCLPS390EventFacility),
> > +    .class_init    = s390_sclp_class_init,
> > +};
> > +
> > +static int s390_sclp_busdev_init(DeviceState *dev)
> > +{
> > +    SCLPS390EventFacility *_dev = (SCLPS390EventFacility *)dev;
> > +    SCLPS390EventFacilityClass *evt_fac =
> > +        SCLP_S390_EVENT_FACILITY_GET_CLASS(dev);
> > +
> > +    return evt_fac->init(_dev);
> >   }
> >
> > +static void sclp_s390_device_class_init(ObjectClass *klass, void *data)
> > +{
> > +    DeviceClass *dc = DEVICE_CLASS(klass);
> > +
> > +    dc->init = s390_sclp_busdev_init;
> > +    dc->bus_info =&s390_sclp_bus_info;
> > +}
> > +
> > +static TypeInfo sclp_s390_device_info = {
> > +    .name = TYPE_SCLP_S390_EVENT_FACILITY,
> > +    .parent = TYPE_DEVICE,
> > +    .instance_size = sizeof(SCLPS390EventFacility),
> > +    .class_init = sclp_s390_device_class_init,
> > +    .class_size = sizeof(SCLPS390EventFacilityClass),
> > +    .abstract = true,
> > +};
> > +
> > +/***************** S390 SCLP Bus Bridge Device *******************/
> > +/* Only required to have the sclp bus as child in the system bus */
> > +
> > +static int s390_sclp_bridge_init(SysBusDevice *dev)
> > +{
> > +    return 0;
> > +}
> > +
> > +static void s390_sclp_bridge_class_init(ObjectClass *klass, void *data)
> > +{
> > +    DeviceClass *dc = DEVICE_CLASS(klass);
> > +    SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
> > +
> > +    k->init = s390_sclp_bridge_init;
> > +    dc->no_user = 1;
> > +}
> > +
> > +static TypeInfo s390_sclp_bridge_info = {
> > +    .name          = "s390-sclp-bridge",
> > +    .parent        = TYPE_SYS_BUS_DEVICE,
> > +    .instance_size = sizeof(SysBusDevice),
> > +    .class_init    = s390_sclp_bridge_class_init,
> > +};
> > +
> > +static void s390_sclp_register_types(void)
> > +{
> > +    type_register_static(&sclp_s390_device_info);
> > +    type_register_static(&s390_sclp_event_facility);
> > +    type_register_static(&s390_sclp_bridge_info);
> > +}
> > +type_init(s390_sclp_register_types)
> > diff --git a/hw/s390-sclp.h b/hw/s390-sclp.h
> > index e335b21..f61421b 100644
> > --- a/hw/s390-sclp.h
> > +++ b/hw/s390-sclp.h
> > @@ -1,13 +1,69 @@
> >   #include<stdint.h>
> >   #include<qemu-common.h>
> >
> > +#include "sysbus.h"
> > +#include "hw/s390-event-facility.h"
> >
> >   /* SCLP command codes */
> >   #define SCLP_CMDW_READ_SCP_INFO                 0x00020001
> >   #define SCLP_CMDW_READ_SCP_INFO_FORCED          0x00120001
> > +#define SCLP_CMD_WRITE_EVENT_MASK               0x00780005
> >
> >   /* SCLP response codes */
> > -#define SCLP_RC_SCCB_RESOURCE_INSUFFICENT       0x07f0
> > +#define SCLP_RC_NORMAL_COMPLETION               0x0020
> > +#define SCLP_RC_INSUFFICIENT_SCCB_LENGTH        0x0300
> > +#define SCLP_RC_INVALID_FUNCTION                0x40f0
> > +#define SCLP_RC_NO_EVENT_BUFFERS_STORED         0x60f0
> > +#define SCLP_RC_INVALID_SELECTION_MASK          0x70f0
> > +#define SCLP_RC_INCONSISTENT_LENGTHS            0x72f0
> > +#define SCLP_RC_EVENT_BUFFER_SYNTAX_ERROR       0x73f0
> > +#define SCLP_RC_INVALID_MASK_LENGTH             0x74f0
> > +
> > +/* SCLP event types */
> > +#define SCLP_EVENT_SIGNAL_QUIESCE               0x1d
> > +
> > +/* SCLP event masks */
> > +#define SCLP_EVENT_MASK_SIGNAL_QUIESCE          0x00000008
> > +#define SCLP_EVENT_MASK_MSG                     0x40000000
> > +
> > +#define SCLP_UNCONDITIONAL_READ                 0x00
> > +#define SCLP_SELECTIVE_READ                     0x01
> > +
> > +#define SCLP_VARIABLE_LENGTH_RESPONSE           0x80
> > +
> > +#define SCCB_SIZE 4096
> > +
> > +/* Service Call Control Block (SCCB) and its elements */
> > +
> > +struct write_event_mask {
> > +    uint16_t _reserved;
> > +    uint16_t mask_length;
> > +    uint32_t cp_receive_mask;
> > +    uint32_t cp_send_mask;
> > +    uint32_t send_mask;
> > +    uint32_t receive_mask;
> > +} __attribute__((packed));
> > +
> > +struct event_buffer_header {
> > +    uint16_t length;
> > +    uint8_t  type;
> > +#define SCLP_EVENT_BUFFER_ACCEPTED              0x80
> > +    uint8_t  flags;
> > +    uint16_t _reserved;
> > +} __attribute__((packed));
> > +
> > +struct signal_quiesce {
> > +    struct event_buffer_header h;
> > +    uint16_t timeout;
> > +    uint8_t unit;
> > +} __attribute__((packed));
> > +
> > +struct read_event_data {
> > +    union {
> > +        struct signal_quiesce quiesce;
> > +        uint32_t mask;
> > +    };
> > +} __attribute__((packed));
> >
> >   struct sccb_header {
> >       uint16_t length;
> > @@ -22,13 +78,51 @@ struct read_info_sccb {
> >       uint8_t rnsize;
> >   } __attribute__((packed));
> >
> > +#define SCCB_DATA_LEN 4088
> > +
> >   struct sccb {
> >       struct sccb_header h;
> >       union {
> >           struct read_info_sccb read_info;
> > -        char data[4088];
> > +        struct read_event_data read;
> > +        struct write_event_mask we_mask;
> > +        char data[SCCB_DATA_LEN];
> >       } c;
> >    } __attribute__((packed));
> >
> > +void sclp_enable_signal_quiesce(void);
> >   int sclp_read_info(CPUS390XState *env, struct sccb *sccb);
> > +int sclp_read_event_data(CPUS390XState *env, struct sccb *sccb);
> > +int sclp_write_event_mask(CPUS390XState *env, struct sccb *sccb);
> >   void sclp_service_interrupt(CPUS390XState *env, uint32_t sccb);
> > +
> > +#define TYPE_SCLP_S390_EVENT_FACILITY "s390-sclp-event-facility"
> > +#define SCLP_S390_EVENT_FACILITY(obj) \
> > +     OBJECT_CHECK(SCLPS390EventFacility, (obj), TYPE_SCLP_S390_EVENT_FACILITY)
> > +#define SCLP_S390_EVENT_FACILITY_CLASS(klass) \
> > +     OBJECT_CLASS_CHECK(SCLPS390EventFacilityClass, (klass), \
> > +             TYPE_SCLP_S390_EVENT_FACILITY)
> > +#define SCLP_S390_EVENT_FACILITY_GET_CLASS(obj) \
> > +     OBJECT_GET_CLASS(SCLPS390EventFacilityClass, (obj), \
> > +             TYPE_SCLP_S390_EVENT_FACILITY)
> > +
> > +typedef struct SCLPS390EventFacility SCLPS390EventFacility;
> > +
> > +typedef struct SCLPS390EventFacilityClass {
> > +    DeviceClass qdev;
> > +    int (*init)(SCLPS390EventFacility *dev);
> > +} SCLPS390EventFacilityClass;
> > +
> > +struct SCLPS390EventFacility {
> > +    DeviceState qdev;
> > +    SCLPDevice *sdev;
> > +};
> > +
> > +typedef struct SCLPS390Bus {
> > +    BusState bus;
> > +    SCLPS390EventFacility *event_facility;
> > +} SCLPS390Bus;
> > +
> > +extern SCLPS390Bus *sclp_bus;
> > +
> > +SCLPS390Bus *s390_sclp_bus_init(void);
> > diff --git a/hw/s390-virtio.c b/hw/s390-virtio.c
> > index c0e19fd..0babf27 100644
> > --- a/hw/s390-virtio.c
> > +++ b/hw/s390-virtio.c
> > @@ -32,6 +32,7 @@
> >   #include "exec-memory.h"
> >
> >   #include "hw/s390-virtio-bus.h"
> > +#include "hw/s390-sclp.h"
> >
> >   //#define DEBUG_S390
> >
> > @@ -60,7 +61,9 @@
> >
> >   #define MAX_BLK_DEVS                    10
> >
> > -static VirtIOS390Bus *s390_bus;
> > +VirtIOS390Bus *s390_bus;
> > +SCLPS390Bus *sclp_bus;
> > +
> >   static CPUS390XState **ipi_states;
> >
> >   CPUS390XState *s390_cpu_addr2state(uint16_t cpu_addr)
> > @@ -170,6 +173,7 @@ static void s390_init(ram_addr_t my_ram_size,
> >       target_phys_addr_t virtio_region_len;
> >       target_phys_addr_t virtio_region_start;
> >       int i;
> > +    DeviceState *dev;
> >
> >       /* s390x ram size detection needs a 16bit multiplier + an increment. So
> >          guests>  64GB can be specified in 2MB steps etc. */
> > @@ -183,6 +187,7 @@ static void s390_init(ram_addr_t my_ram_size,
> >
> >       /* get a BUS */
> >       s390_bus = s390_virtio_bus_init(&my_ram_size);
> > +    sclp_bus = s390_sclp_bus_init();
> >
> >       /* allocate RAM */
> >       memory_region_init_ram(ram, "s390.ram", my_ram_size);
> > @@ -325,6 +330,10 @@ static void s390_init(ram_addr_t my_ram_size,
> >           qdev_prop_set_drive_nofail(dev, "drive", dinfo->bdrv);
> >           qdev_init_nofail(dev);
> >       }
> > +
> > +    dev = qdev_create((BusState *)sclp_bus, "sclp-event-facility");
> > +    qdev_init_nofail(dev);
> > +    sclpef_enable_irqs(sclp_bus->event_facility->sdev, ipi_states[0]);
> >   }
> >
> >   static QEMUMachine s390_machine = {
> > diff --git a/target-s390x/op_helper.c b/target-s390x/op_helper.c
> > index 74bd9ad..3e5eff4 100644
> > --- a/target-s390x/op_helper.c
> > +++ b/target-s390x/op_helper.c
> > @@ -2391,6 +2391,9 @@ int sclp_service_call(CPUS390XState *env, uint32_t sccb, uint64_t code)
> >           case SCLP_CMDW_READ_SCP_INFO_FORCED:
> >               r = sclp_read_info(env,&work_sccb);
> >               break;
> > +        case SCLP_CMD_WRITE_EVENT_MASK:
> > +            r = sclp_write_event_mask(env,&work_sccb);
> > +            break;
> >           default:
> 
> I don't understand most of the patch tbh. It does a lot of things at the 
> same time, but none of them really thorough. Please split this off into 
> separate patches and make them actually do something small, but 
> constistently.
> 
> Things I saw while looking over this:
> 
>    - you create a bus to plug in sclp users. This needs to be separate. 
> Don't introduce users of a framework when introducing the framework 
> itself, unless really neccessary (or if the patch only becomes 5 lines 
> longer)
>    - you create objects for the new event parser, but not all the other 
> sclp users. There's also no generic distribution mechanism in place
>    - the event parser itself uses globals - that's nowhere near object 
> oriented :)
>    - I don't see the header inclusions i commented on in the last patch 
> remedied here, please think your model over. In general, moving sclp to 
> hw/ is probably a good idea, but then please do it in a properly 
> abstracted way.
>    - A lot of the above code could use some comments, so people reading 
> it would actually understand what's going on :)
> 
OK
> Alex
> 

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

* Re: [Qemu-devel] [PATCH 7/8] s390: Add SCLP vt220 console support
  2012-06-12 11:52   ` Alexander Graf
@ 2012-06-13  7:27     ` Heinz Graalfs
  2012-06-13  7:53       ` Alexander Graf
  0 siblings, 1 reply; 51+ messages in thread
From: Heinz Graalfs @ 2012-06-13  7:27 UTC (permalink / raw)
  To: Alexander Graf; +Cc: Jens Freimann, Cornelia Huck, Jens Freimann, qemu-devel

On Tue, 2012-06-12 at 13:52 +0200, Alexander Graf wrote:
> On 06/06/2012 02:05 PM, Jens Freimann wrote:
> > From: Heinz Graalfs<graalfs@linux.vnet.ibm.com>
> >
> > Adds console support (in vt220 mode).
> > In order to run qemu exploiting the SCLP's console functionality in vt220 mode
> > the user has to specify the following console related parameters:
> >
> >   -chardev stdio,id=charconsole0 -device sclpconsole,chardev=charconsole0,id=console0
> >
> > Signed-off-by: Heinz Graalfs<graalfs@linux.vnet.ibm.com>
> > Signed-off-by: Jens Freimann<jfrei@linux.vnet.ibm.com>
> > ---
> >   hw/s390-event-facility.c |  209 ++++++++++++++++++++++++++++++++++++++++++++++
> >   hw/s390-event-facility.h |    8 ++
> >   hw/s390-sclp.c           |  177 ++++++++++++++++++++++++++++++++++++++-
> >   hw/s390-sclp.h           |   22 ++++-
> >   sysemu.h                 |    1 +
> >   target-s390x/op_helper.c |    6 ++
> >   vl.c                     |   41 +++++++++
> >   7 files changed, 460 insertions(+), 4 deletions(-)
> >
> > diff --git a/hw/s390-event-facility.c b/hw/s390-event-facility.c
> > index b8106a6..cfa5dd4 100644
> > --- a/hw/s390-event-facility.c
> > +++ b/hw/s390-event-facility.c
> > @@ -16,6 +16,11 @@
> >   #include "s390-sclp.h"
> >   #include "s390-event-facility.h"
> >
> > +qemu_irq sclp_read_vt220;
> > +
> > +static int size_buffer = 4096;
> > +static char *sclp_console_data_vt220;
> 
> Globals?
> 
ok, I'll look into this
> > +
> >   struct SCLPDevice {
> >       const char *name;
> >       bool vm_running;
> > @@ -224,9 +229,213 @@ static TypeInfo sclp_quiesce_info = {
> >       .class_init    = sclpef_quiesce_class_init,
> >   };
> >
> > +/* ----------- SCLP VT220 console ------------ */
> > +
> > +static void s390_signal_read_vt220(void *opaque, int n, int level)
> > +{
> > +    sclp_enable_signal_read_vt220();
> > +    sclp_service_interrupt(opaque, 0);
> > +}
> > +
> > +static void sclpef_set_console(SCLPEvent *event)
> > +{
> > +    if (event->id == ID_VT220) {
> > +        sclp_read_vt220 = *qemu_allocate_irqs(s390_signal_read_vt220,
> > +            event->evt_fac->opaque, 1);
> > +    }
> > +}
> > +
> > +void sclpef_write_console_vt220(SCLPDevice *sdev, char *buf)
> > +{
> > +    DeviceState *dev;
> > +    SCLPEventFacility *event_facility;
> > +    static SCLPEvent *event;
> > +    static SCLPEventClass *cons;
> > +
> > +    event_facility = DO_UPCAST(SCLPEventFacility, sdev, sdev);
> > +
> > +    if (!cons) {
> > +        QTAILQ_FOREACH(dev,&event_facility->sbus.qbus.children, sibling) {
> > +            event = (SCLPEvent *) dev;
> > +            if (event->id == ID_VT220) {
> > +                cons = SCLP_EVENT_GET_CLASS(event);
> > +                assert(cons->have_data);
> > +                break;
> > +            }
> > +        }
> > +    }
> 
> I don't understand the above code. Why do you have to search for 
> anything when you're in a call to process a write?
The loop occurs once to find the console.

OK, I'll add an entry to SCLPEvent structure and use that
(getting rid of the loop).

> 
> > +    if (cons) {
> > +        cons->have_data(event, (const uint8_t *)buf, strlen(buf));
> > +    }
> > +}
> > +
> > +char *sclpef_get_console_data_vt220(SCLPDevice *sdev)
> > +{
> > +    DeviceState *dev;
> > +    SCLPEventFacility *event_facility;
> > +    SCLPEvent *event = NULL;
> > +    static SCLPEventClass *cons;
> > +
> > +    event_facility = DO_UPCAST(SCLPEventFacility, sdev, sdev);
> > +
> > +    if (!cons) {
> > +        QTAILQ_FOREACH(dev,&event_facility->sbus.qbus.children, sibling) {
> > +            event = (SCLPEvent *) dev;
> > +            if (event->id == ID_VT220) {
> > +                cons = SCLP_EVENT_GET_CLASS(event);
> > +                assert(cons->get_data);
> > +                break;
> > +            }
> > +        }
> > +    }
> 
> See above.
> 
The loop occurs once to find the console.

OK, I'll add an entry to SCLPEvent structure and use that
(getting rid of the loop).

> > +    if (cons) {
> > +        return cons->get_data();
> > +    }
> > +    return NULL;
> > +}
> > +
> > +static char *console_data_vt220(void)
> > +{
> > +    return sclp_console_data_vt220;
> > +}
> > +
> > +static ssize_t flush_buf(SCLPEvent *event, const uint8_t *buf, size_t len)
> > +{
> > +    SCLPConsole *scon = DO_UPCAST(SCLPConsole, event, event);
> > +    ssize_t ret;
> > +
> > +    if (!scon->chr) {
> > +        /* If there's no backend, we can just say we consumed all data. */
> > +        return len;
> > +    }
> > +
> > +    ret = qemu_chr_fe_write(scon->chr, buf, len);
> > +
> > +    if (ret<  0) {
> > +        /* see virtio-console comments */
> > +        ret = 0;
> > +    }
> > +
> > +    return ret;
> > +}
> > +
> > +static void guest_open(SCLPEvent *event)
> > +{
> > +    SCLPConsole *scon = DO_UPCAST(SCLPConsole, event, event);
> > +
> > +    if (!scon->chr) {
> > +        return;
> > +    }
> > +    qemu_chr_fe_open(scon->chr);
> > +}
> > +
> > +static void guest_close(SCLPEvent *event)
> > +{
> > +    SCLPConsole *scon = DO_UPCAST(SCLPConsole, event, event);
> > +
> > +    if (!scon->chr) {
> > +        return;
> > +    }
> > +    qemu_chr_fe_close(scon->chr);
> > +}
> > +
> > +static int chr_can_read(void *opaque)
> > +{
> > +    return 1;
> > +}
> > +
> > +static void chr_read_vt220(void *opaque, const uint8_t *buf, int size)
> > +{
> > +    char *offset;
> > +
> > +    if (!sclp_console_data_vt220) {
> > +        size_buffer = 2 * size;
> 
> Why 2*?
> 

OK, will change to exact size plus 1 for trailing 0

> > +        sclp_console_data_vt220 = malloc(size_buffer);
> 
> %s/malloc/g_malloc0/g
> 
OK
> > +    }
> > +    if (size_buffer<  size + 1) {
> 
> This could use a comment.
> 
OK
> > +        free(sclp_console_data_vt220);
> > +        size_buffer = 2 * size;
> > +        sclp_console_data_vt220 = malloc(size_buffer);
> > +    }
> > +    offset = sclp_console_data_vt220;
> > +    if (offset) {
> > +        memcpy(offset, buf, size);
> > +        offset += size;
> > +        *offset = '\0';
> 
> How do you know you're not out of bounds?
> 
OK, size + 1
> > +        qemu_irq_raise(sclp_read_vt220);
> > +    } else {
> > +        size_buffer = 0;
> > +    }
> > +}
> > +
> > +static void chr_event(void *opaque, int event)
> > +{
> > +    switch (event) {
> > +    case CHR_EVENT_OPENED:
> > +        if (!sclp_console_data_vt220) {
> > +            sclp_console_data_vt220 = malloc(size_buffer);
> > +        }
> > +        break;
> > +    case CHR_EVENT_CLOSED:
> > +        break;
> > +    }
> > +}
> > +
> > +static unsigned int send_mask_vt220(void)
> > +{
> > +    return SCLP_EVENT_MASK_MSG_ASCII;
> > +}
> > +
> > +static unsigned int receive_mask_vt220(void)
> > +{
> > +    return SCLP_EVENT_MASK_MSG_ASCII;
> > +}
> > +
> > +static int sclpconsole_initfn_vt220(SCLPEvent *event)
> > +{
> > +    SCLPConsole *scon = DO_UPCAST(SCLPConsole, event, event);
> > +
> > +    event->id = ID_VT220;
> > +    sclpef_set_console(event);
> > +    if (scon->chr) {
> > +        qemu_chr_add_handlers(scon->chr, chr_can_read,
> > +                chr_read_vt220, chr_event, scon);
> > +    }
> > +
> > +    return 0;
> > +}
> > +
> > +static Property sclpconsole_properties[] = {
> > +    DEFINE_PROP_CHR("chardev", SCLPConsole, chr),
> > +    DEFINE_PROP_END_OF_LIST(),
> > +};
> > +
> > +static void sclpconsole_class_init(ObjectClass *klass, void *data)
> > +{
> > +    DeviceClass *dc = DEVICE_CLASS(klass);
> > +    SCLPEventClass *k = SCLP_EVENT_CLASS(klass);
> > +
> > +    k->init = sclpconsole_initfn_vt220;
> > +    k->have_data = flush_buf;
> > +    k->guest_open = guest_open;
> > +    k->guest_close = guest_close;
> > +    k->get_send_mask = send_mask_vt220;
> > +    k->get_receive_mask = receive_mask_vt220;
> > +    k->get_data = console_data_vt220;
> > +    dc->props = sclpconsole_properties;
> > +}
> > +
> > +static TypeInfo sclpconsole_info = {
> > +    .name          = "sclpconsole",
> > +    .parent        = TYPE_SCLP_EVENT,
> > +    .instance_size = sizeof(SCLPConsole),
> > +    .class_init    = sclpconsole_class_init,
> > +};
> > +
> >   static void sclpef_register_types(void)
> >   {
> >       type_register_static(&sclp_event_facility_type_info);
> >       type_register_static(&sclp_quiesce_info);
> > +    type_register_static(&sclpconsole_info);
> >   }
> >   type_init(sclpef_register_types)
> > diff --git a/hw/s390-event-facility.h b/hw/s390-event-facility.h
> > index 40d4049..d6bde7d 100644
> > --- a/hw/s390-event-facility.h
> > +++ b/hw/s390-event-facility.h
> > @@ -14,6 +14,7 @@
> >   #include "qemu-common.h"
> >
> >   #define ID_QUIESCE SCLP_EVENT_SIGNAL_QUIESCE
> > +#define ID_VT220   SCLP_EVENT_ASCII_CONSOLE_DATA
> >
> >   #define TYPE_SCLP_EVENT "s390-sclp-event-type"
> >   #define SCLP_EVENT(obj) \
> > @@ -34,6 +35,11 @@ typedef struct SCLPEventClass {
> >       int (*exit)(SCLPEvent *event);
> >       unsigned int (*get_send_mask)(void);
> >       unsigned int (*get_receive_mask)(void);
> > +    void (*guest_open)(SCLPEvent *event);
> > +    void (*guest_close)(SCLPEvent *event);
> > +    void (*guest_ready)(SCLPEvent *event);
> > +    ssize_t (*have_data)(SCLPEvent *event, const uint8_t *buf, size_t len);
> > +    char *(*get_data)(void);
> >   } SCLPEventClass;
> >
> >   struct SCLPEvent {
> > @@ -50,5 +56,7 @@ void sclpef_enable_irqs(SCLPDevice *sdev, void *opaque);
> >   void sclpef_set_masks(void);
> >   unsigned int sclpef_send_mask(SCLPDevice *sdev);
> >   unsigned int sclpef_receive_mask(SCLPDevice *sdev);
> > +void sclpef_write_console_vt220(SCLPDevice *sdev, char *buf);
> > +char *sclpef_get_console_data_vt220(SCLPDevice *sdev);
> >
> >   #endif
> > diff --git a/hw/s390-sclp.c b/hw/s390-sclp.c
> > index 683a709..8f45773 100644
> > --- a/hw/s390-sclp.c
> > +++ b/hw/s390-sclp.c
> > @@ -11,6 +11,11 @@
> >   #include "hw/s390-sclp.h"
> >   #include "hw/s390-event-facility.h"
> >
> > +/* input buffer handling */
> > +#define INP_BUFFER_SIZE 4096
> > +static int sclp_curr_buf_size;
> > +static char *sclp_input_vt220;
> > +
> >   /* Host capabilites */
> >   static unsigned int sclp_send_mask;
> >   static unsigned int sclp_receive_mask;
> > @@ -21,6 +26,7 @@ static unsigned int sclp_cp_receive_mask;
> >
> >   static int quiesce;
> >   static int event_pending;
> > +static int vt220;
> 
> If anything, this is a machine variable, no? What is this supposed to 
> express?
> 
> >
> >   int sclp_read_info(CPUS390XState *env, struct sccb *sccb)
> >   {
> > @@ -66,6 +72,7 @@ void sclp_enable_signal_quiesce(void)
> >   {
> >       quiesce = 1;
> >       event_pending = 1;
> > +    vt220 = 0;
> >   }
> >
> >   static void sclp_set_masks(void)
> > @@ -81,7 +88,112 @@ static void sclp_set_masks(void)
> >
> >       sclp_send_mask = sclpef_send_mask(evt_fac->sdev);
> >       sclp_receive_mask = sclpef_receive_mask(evt_fac->sdev);
> > - }
> > +}
> > +
> > +static int signal_vt220_event(struct sccb *sccb, int *slen)
> > +{
> > +    char *p;
> > +
> > +    if (!sclp_input_vt220 || !vt220) {
> > +        return 0;
> > +    }
> > +
> > +    int l = strlen(sclp_input_vt220);
> > +
> > +    if (*slen<  sizeof(struct ascii_cons_data_command) + l + 1) {
> > +        event_pending = 1;
> > +        return 0;
> > +    }
> > +    p = (char *)&sccb->c.read.acd_cmd.data;
> > +    /* first byte is hex 0 saying an ascii string follows */
> > +    *p++ = '\0';
> > +    memmove(p, sclp_input_vt220, l);
> > +    *sclp_input_vt220 = '\0';
> > +
> > +    sccb->c.read.acd_cmd.h.length =
> > +            cpu_to_be16(sizeof(struct ascii_cons_data_command) + l + 1);
> > +    sccb->c.read.acd_cmd.h.type = SCLP_EVENT_ASCII_CONSOLE_DATA;
> > +
> > +    vt220 = 0;
> > +    *slen -= sizeof(struct ascii_cons_data_command) + l + 1;
> > +    return 1;
> > +}
> > +
> > +static char *grow_buffer(int size)
> > +{
> > +    char *p = (char *) malloc(size);
> > +
> > +    if (!p) {
> > +        sclp_curr_buf_size = 0;
> > +        return NULL;
> > +    }
> > +    memset(p, '\0', size);
> > +    sclp_curr_buf_size = size;
> > +    return p;
> > +}
> > +
> > +static int sclp_write_vt220(struct event_buffer_header *event)
> > +{
> > +    int l;
> > +    char *msg;
> > +    SCLPS390EventFacility *evt_fac;
> > +    struct ascii_cons_data_command *ad =
> > +            (struct ascii_cons_data_command *) event;
> > +
> > +    assert(sclp_bus);
> > +
> > +    l = event->length - sizeof(struct event_buffer_header);
> > +    msg = (char *) malloc(l + 1);
> > +    assert(msg);
> > +    memset(msg, '\0', l + 1);
> > +    memmove(msg, ad->data, l);
> 
> Why the copy? Also, for such short lived data, you're probably better 
> off using alloca.
> 
OK, I'll look into this
> > +
> > +    evt_fac = sclp_bus->event_facility;
> > +    sclpef_write_console_vt220(evt_fac->sdev, msg);
> > +
> > +    free(msg);
> > +
> > +    return SCLP_RC_NORMAL_COMPLETION;
> > +}
> > +
> > +void sclp_enable_signal_read_vt220(void)
> > +{
> > +    int len;
> > +    char *input;
> > +    SCLPS390EventFacility *evt_fac;
> > +
> > +    if (!sclp_bus) {
> > +        return;
> > +    }
> > +    evt_fac = sclp_bus->event_facility;
> > +
> > +    assert(evt_fac);
> > +
> > +    input = sclpef_get_console_data_vt220(evt_fac->sdev);
> > +
> > +    if (!input) {
> > +        return;
> > +    }
> > +
> > +    vt220 = 1;
> > +    quiesce = 0;
> > +    event_pending = 1;
> > +    len = strlen((char *) input);
> > +    if (sclp_input_vt220 == NULL) {
> > +        /* get new buffer */
> > +        sclp_input_vt220 = grow_buffer(2 * len + 1);
> > +    } else {
> > +        if (len>= sclp_curr_buf_size) {
> > +            /* get larger buffer */
> > +            char *p = grow_buffer(2 * len + 1);
> > +            free(sclp_input_vt220);
> > +            sclp_input_vt220 = p;
> > +        }
> > +    }
> > +    if (sclp_input_vt220) {
> > +        strcat(sclp_input_vt220, (char *)input);
> > +    }
> > +}
> >
> >   int sclp_read_event_data(CPUS390XState *env, struct sccb *sccb)
> >   {
> > @@ -99,7 +211,8 @@ int sclp_read_event_data(CPUS390XState *env, struct sccb *sccb)
> >           break;
> >       case SCLP_SELECTIVE_READ:
> >           if (!(sclp_cp_receive_mask&  be32_to_cpu(sccb->c.read.mask))) {
> > -            sccb->h.response_code = cpu_to_be16(SCLP_RC_INVALID_SELECTION_MASK);
> > +            sccb->h.response_code =
> > +                    cpu_to_be16(SCLP_RC_INVALID_SELECTION_MASK);
> >               goto out;
> >           }
> >           sclp_active_selection_mask = be32_to_cpu(sccb->c.read.mask);
> > @@ -117,7 +230,12 @@ int sclp_read_event_data(CPUS390XState *env, struct sccb *sccb)
> >               sccb->h.response_code = cpu_to_be16(SCLP_RC_NORMAL_COMPLETION);
> >           }
> >       }
> > -
> > +    if (sclp_active_selection_mask&  SCLP_EVENT_MASK_MSG_ASCII) {
> > +        if (signal_vt220_event(sccb,&slen)) {
> > +            sccb->h.response_code = cpu_to_be16(SCLP_RC_NORMAL_COMPLETION);
> > +            sccb->h.length = cpu_to_be16(SCCB_SIZE - slen);
> > +        }
> > +    }
> >       if (sccb->h.control_mask[2]&  SCLP_VARIABLE_LENGTH_RESPONSE) {
> >           sccb->h.control_mask[2]&= ~SCLP_VARIABLE_LENGTH_RESPONSE;
> >           sccb->h.length = cpu_to_be16(SCCB_SIZE - slen);
> > @@ -127,6 +245,59 @@ out:
> >       return 0;
> >   }
> >
> > +int sclp_write_event_data(CPUS390XState *env, struct sccb *sccb)
> > +{
> > +    struct event_buffer_header *event;
> > +    int slen;
> > +    unsigned elen = 0;
> > +
> > +    if (sccb->h.function_code != SCLP_FC_NORMAL_WRITE) {
> > +        sccb->h.response_code = cpu_to_be16(SCLP_RC_INVALID_FUNCTION);
> > +        goto out;
> > +    }
> > +    if (be16_to_cpu(sccb->h.length)<  8) {
> > +        sccb->h.response_code = cpu_to_be16(SCLP_RC_INSUFFICIENT_SCCB_LENGTH);
> > +        goto out;
> > +    }
> > +
> > +    /* first check the sum of all events */
> > +    event =&sccb->c.event;
> > +    for (slen = be16_to_cpu(sccb->h.length) - sizeof(sccb->h);
> > +         slen>  0; slen -= elen) {
> > +        elen = be16_to_cpu(event->length);
> > +        if (elen<  sizeof(*event) || elen>  slen) {
> > +            sccb->h.response_code =
> > +                    cpu_to_be16(SCLP_RC_EVENT_BUFFER_SYNTAX_ERROR);
> > +            goto out;
> > +        }
> > +        event = (void *) event + elen;
> > +    }
> > +    if (slen) {
> > +        sccb->h.response_code = cpu_to_be16(SCLP_RC_INCONSISTENT_LENGTHS);
> > +        goto out;
> > +    }
> > +
> > +    /* the execute */
> > +    event =&sccb->c.event;
> > +    for (slen = be16_to_cpu(sccb->h.length) - sizeof(sccb->h);
> > +         slen>  0; slen -= elen) {
> > +        elen = be16_to_cpu(event->length);
> > +        switch (event->type) {
> > +        case SCLP_EVENT_ASCII_CONSOLE_DATA:
> > +            sccb->h.response_code = cpu_to_be16(sclp_write_vt220(event));
> > +            break;
> 
> This also screams for a generic dispatcher.
> 
> > +        default:
> > +            sccb->h.response_code = SCLP_RC_INVALID_FUNCTION;
> > +            break;
> > +        }
> > +        event = (void *) event + elen;
> > +    }
> > +    sccb->h.response_code = SCLP_RC_NORMAL_COMPLETION;
> > +
> > +out:
> > +    return 0;
> > +}
> > +
> >   int sclp_write_event_mask(CPUS390XState *env, struct sccb *sccb)
> >   {
> >       /* Attention: We assume that Linux uses 4-byte masks, what it actually
> > diff --git a/hw/s390-sclp.h b/hw/s390-sclp.h
> > index f61421b..c86bca8 100644
> > --- a/hw/s390-sclp.h
> > +++ b/hw/s390-sclp.h
> > @@ -7,6 +7,8 @@
> >   /* SCLP command codes */
> >   #define SCLP_CMDW_READ_SCP_INFO                 0x00020001
> >   #define SCLP_CMDW_READ_SCP_INFO_FORCED          0x00120001
> > +#define SCLP_CMD_READ_EVENT_DATA                0x00770005
> > +#define SCLP_CMD_WRITE_EVENT_DATA               0x00760005
> >   #define SCLP_CMD_WRITE_EVENT_MASK               0x00780005
> >
> >   /* SCLP response codes */
> > @@ -20,11 +22,12 @@
> >   #define SCLP_RC_INVALID_MASK_LENGTH             0x74f0
> >
> >   /* SCLP event types */
> > +#define SCLP_EVENT_ASCII_CONSOLE_DATA           0x1a
> >   #define SCLP_EVENT_SIGNAL_QUIESCE               0x1d
> >
> >   /* SCLP event masks */
> >   #define SCLP_EVENT_MASK_SIGNAL_QUIESCE          0x00000008
> > -#define SCLP_EVENT_MASK_MSG                     0x40000000
> > +#define SCLP_EVENT_MASK_MSG_ASCII               0x00000040
> >
> >   #define SCLP_UNCONDITIONAL_READ                 0x00
> >   #define SCLP_SELECTIVE_READ                     0x01
> > @@ -44,6 +47,13 @@ struct write_event_mask {
> >       uint32_t receive_mask;
> >   } __attribute__((packed));
> >
> > +struct mdb_header {
> > +    uint16_t length;
> > +    uint16_t type;
> > +    uint32_t tag;
> > +    uint32_t revision_code;
> > +} __attribute__((packed));
> > +
> >   struct event_buffer_header {
> >       uint16_t length;
> >       uint8_t  type;
> > @@ -58,9 +68,15 @@ struct signal_quiesce {
> >       uint8_t unit;
> >   } __attribute__((packed));
> >
> > +struct ascii_cons_data_command {
> > +    struct event_buffer_header h;
> > +    char data[0];
> > +} __attribute__((packed));
> > +
> >   struct read_event_data {
> >       union {
> >           struct signal_quiesce quiesce;
> > +        struct ascii_cons_data_command acd_cmd;
> >           uint32_t mask;
> >       };
> >   } __attribute__((packed));
> > @@ -84,15 +100,19 @@ struct sccb {
> >       struct sccb_header h;
> >       union {
> >           struct read_info_sccb read_info;
> > +        struct event_buffer_header event;
> >           struct read_event_data read;
> > +        struct ascii_cons_data_command acd_cmd;
> >           struct write_event_mask we_mask;
> >           char data[SCCB_DATA_LEN];
> >       } c;
> >    } __attribute__((packed));
> >
> >   void sclp_enable_signal_quiesce(void);
> > +void sclp_enable_signal_read_vt220(void);
> >   int sclp_read_info(CPUS390XState *env, struct sccb *sccb);
> >   int sclp_read_event_data(CPUS390XState *env, struct sccb *sccb);
> > +int sclp_write_event_data(CPUS390XState *env, struct sccb *sccb);
> >   int sclp_write_event_mask(CPUS390XState *env, struct sccb *sccb);
> >   void sclp_service_interrupt(CPUS390XState *env, uint32_t sccb);
> >
> > diff --git a/sysemu.h b/sysemu.h
> > index bc2c788..b4d399c 100644
> > --- a/sysemu.h
> > +++ b/sysemu.h
> > @@ -62,6 +62,7 @@ int qemu_powerdown_requested(void);
> >   void qemu_system_killed(int signal, pid_t pid);
> >   void qemu_kill_report(void);
> >   extern qemu_irq qemu_system_powerdown;
> > +extern qemu_irq sclp_read_vt220;
> >   void qemu_system_reset(bool report);
> >
> >   void qemu_add_exit_notifier(Notifier *notify);
> > diff --git a/target-s390x/op_helper.c b/target-s390x/op_helper.c
> > index 3e5eff4..4d49472 100644
> > --- a/target-s390x/op_helper.c
> > +++ b/target-s390x/op_helper.c
> > @@ -2391,6 +2391,12 @@ int sclp_service_call(CPUS390XState *env, uint32_t sccb, uint64_t code)
> >           case SCLP_CMDW_READ_SCP_INFO_FORCED:
> >               r = sclp_read_info(env,&work_sccb);
> >               break;
> > +        case SCLP_CMD_READ_EVENT_DATA:
> > +            r = sclp_read_event_data(env,&work_sccb);
> > +            break;
> > +        case SCLP_CMD_WRITE_EVENT_DATA:
> > +            r = sclp_write_event_data(env,&work_sccb);
> > +            break;
> >           case SCLP_CMD_WRITE_EVENT_MASK:
> >               r = sclp_write_event_mask(env,&work_sccb);
> >               break;
> > diff --git a/vl.c b/vl.c
> > index 23ab3a3..aba7ab0 100644
> > --- a/vl.c
> > +++ b/vl.c
> > @@ -174,6 +174,7 @@ int main(int argc, char **argv)
> >   #define DEFAULT_RAM_SIZE 128
> >
> >   #define MAX_VIRTIO_CONSOLES 1
> > +#define MAX_SCLP_CONSOLES   1
> >
> >   static const char *data_dir;
> >   const char *bios_name = NULL;
> > @@ -201,6 +202,7 @@ int no_quit = 0;
> >   CharDriverState *serial_hds[MAX_SERIAL_PORTS];
> >   CharDriverState *parallel_hds[MAX_PARALLEL_PORTS];
> >   CharDriverState *virtcon_hds[MAX_VIRTIO_CONSOLES];
> > +CharDriverState *sclpcon_hds[MAX_SCLP_CONSOLES];
> >   int win2k_install_hack = 0;
> >   int usb_enabled = 0;
> >   int singlestep = 0;
> > @@ -274,6 +276,8 @@ static int default_floppy = 1;
> >   static int default_cdrom = 1;
> >   static int default_sdcard = 1;
> >   static int default_vga = 1;
> > +static int default_sclpcon = 1;
> > +static int default_loader = 1;
> >
> >   static struct {
> >       const char *driver;
> > @@ -295,6 +299,8 @@ static struct {
> >       { .driver = "isa-cirrus-vga",       .flag =&default_vga       },
> >       { .driver = "vmware-svga",          .flag =&default_vga       },
> >       { .driver = "qxl-vga",              .flag =&default_vga       },
> > +    { .driver = "s390-sclp",            .flag =&default_sclpcon   },
> > +    { .driver = "s390-ipl",             .flag =&default_loader    },
> >   };
> >
> >   static void res_free(void)
> > @@ -1942,6 +1948,7 @@ struct device_config {
> >           DEV_VIRTCON,   /* -virtioconsole */
> >           DEV_DEBUGCON,  /* -debugcon */
> >           DEV_GDB,       /* -gdb, -s */
> > +        DEV_SCLPCON,   /* sclp console */
> >       } type;
> >       const char *cmdline;
> >       Location loc;
> > @@ -2058,6 +2065,36 @@ static int virtcon_parse(const char *devname)
> >       return 0;
> >   }
> >
> > +static int sclpcon_parse(const char *devname)
> > +{
> > +    QemuOptsList *device = qemu_find_opts("device");
> > +    static int index;
> > +    char label[32];
> > +    QemuOpts *dev_opts;
> > +
> > +    if (strcmp(devname, "none") == 0)
> > +        return 0;
> 
> Apart from that part not passing checkpatch, why do we have to 
> reimplement this for every char device?
> 
OK, I'll look into this if this is really needed
> 
> Alex
> 
> > +    if (index == MAX_SCLP_CONSOLES) {
> > +        fprintf(stderr, "qemu: too many sclp consoles\n");
> > +        exit(1);
> > +    }
> > +
> > +    dev_opts = qemu_opts_create(device, NULL, 0);
> > +    qemu_opt_set(dev_opts, "driver", "sclpconsole");
> > +
> > +    snprintf(label, sizeof(label), "sclpcon%d", index);
> > +    sclpcon_hds[index] = qemu_chr_new(label, devname, NULL);
> > +    if (!sclpcon_hds[index]) {
> > +        fprintf(stderr, "qemu: could not open sclp console '%s': %s\n",
> > +                devname, strerror(errno));
> > +        return -1;
> > +    }
> > +    qemu_opt_set(dev_opts, "chardev", label);
> > +
> > +    index++;
> > +    return 0;
> > +}
> > +
> >   static int debugcon_parse(const char *devname)
> >   {
> >       QemuOpts *opts;
> > @@ -3304,6 +3341,8 @@ int main(int argc, char **argv, char **envp)
> >               add_device_config(DEV_SERIAL, "mon:stdio");
> >           } else if (default_virtcon&&  default_monitor) {
> >               add_device_config(DEV_VIRTCON, "mon:stdio");
> > +        } else if (default_sclpcon&&  default_monitor) {
> > +            add_device_config(DEV_SCLPCON, "mon:stdio");
> >           } else {
> >               if (default_serial)
> >                   add_device_config(DEV_SERIAL, "stdio");
> > @@ -3491,6 +3530,8 @@ int main(int argc, char **argv, char **envp)
> >           exit(1);
> >       if (foreach_device_config(DEV_VIRTCON, virtcon_parse)<  0)
> >           exit(1);
> > +    if (foreach_device_config(DEV_SCLPCON, sclpcon_parse)<  0)
> > +        exit(1);
> >       if (foreach_device_config(DEV_DEBUGCON, debugcon_parse)<  0)
> >           exit(1);
> >
> 

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

* Re: [Qemu-devel] [PATCH 7/8] s390: Add SCLP vt220 console support
  2012-06-13  7:27     ` Heinz Graalfs
@ 2012-06-13  7:53       ` Alexander Graf
  0 siblings, 0 replies; 51+ messages in thread
From: Alexander Graf @ 2012-06-13  7:53 UTC (permalink / raw)
  To: Heinz Graalfs; +Cc: Jens Freimann, Cornelia Huck, Jens Freimann, qemu-devel

Heinz Graalfs wrote:
> On Tue, 2012-06-12 at 13:52 +0200, Alexander Graf wrote:
>   
>> On 06/06/2012 02:05 PM, Jens Freimann wrote:
>>     
>>> From: Heinz Graalfs<graalfs@linux.vnet.ibm.com>
>>>
>>>       

[...]

>>> +static void chr_read_vt220(void *opaque, const uint8_t *buf, int size)
>>> +{
>>> +    char *offset;
>>> +
>>> +    if (!sclp_console_data_vt220) {
>>> +        size_buffer = 2 * size;
>>>       
>> Why 2*?
>>
>>     
>
> OK, will change to exact size plus 1 for trailing 0
>   

This happens in more than one place btw :).

>
>   
>>> +        free(sclp_console_data_vt220);
>>> +        size_buffer = 2 * size;
>>> +        sclp_console_data_vt220 = malloc(size_buffer);
>>> +    }
>>> +    offset = sclp_console_data_vt220;
>>> +    if (offset) {
>>> +        memcpy(offset, buf, size);
>>> +        offset += size;
>>> +        *offset = '\0';
>>>       
>> How do you know you're not out of bounds?
>>
>>     
> OK, size + 1
>   

I was more thinking of the memcpy(some_variable, ..., n) where you never
check if available_space(some_variable) > n, no?


Alex

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

* Re: [Qemu-devel] [PATCH 2/8] s390: autodetect map private
  2012-06-12 12:12           ` Alexander Graf
@ 2012-06-13 10:30             ` Jan Kiszka
  2012-06-13 10:54               ` Alexander Graf
  0 siblings, 1 reply; 51+ messages in thread
From: Jan Kiszka @ 2012-06-13 10:30 UTC (permalink / raw)
  To: Alexander Graf
  Cc: Jens Freimann, Heinz Graalfs, qemu-devel, Christian Borntraeger,
	Jens Freimann, Cornelia Huck

On 2012-06-12 14:12, Alexander Graf wrote:
> On 06/12/2012 02:02 PM, Christian Borntraeger wrote:
>> On 12/06/12 13:57, Alexander Graf wrote:
>>> Since it lives in an s390 specific branch, the function name should probably be called s390 specific. If we ever need another architecture to have a kvm specific ram allocator, we can make it generic when that time comes. Until then, let's treat s390 as the oddball it is :).
>>>
>>> Apart from that, this approach looks a lot nicer, yes.
>> But then I have to have a *s390* function declared in kvm.h and your other comment
>> hits me. You got me in a trap here, heh? ;-)
> 
> Ah, I see what you mean. I was thinking of having a 
> target-s390x/kvm_s390x.h or so. Then we could add the function 
> definition there and have everything nicely contained within 
> target-s390x only.
> 
> Jan, which approach would you think is cleaner? Make this a generic 
> kvm_arch callback or introduce a special kvm_s390x.h header which would 
> then have to be explicitly included in exec.c?

Maybe somethings like

#ifdef __s390__
    else if (kvm_enabled())
        new_block->host = kvm_arch_vmalloc(size)
#endif

? But I have no definitive opinion yet. I think that

 - the changes to generic code should make clear that it's an s390+kvm
   specialty
 - actual work should be done in target-s390/kvm.c (e.g. avoid
   legacy_s390_alloc)

Jan

-- 
Siemens AG, Corporate Technology, CT T DE IT 1
Corporate Competence Center Embedded Linux

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

* Re: [Qemu-devel] [PATCH 2/8] s390: autodetect map private
  2012-06-13 10:30             ` Jan Kiszka
@ 2012-06-13 10:54               ` Alexander Graf
  2012-06-13 10:58                 ` Jan Kiszka
  0 siblings, 1 reply; 51+ messages in thread
From: Alexander Graf @ 2012-06-13 10:54 UTC (permalink / raw)
  To: Jan Kiszka
  Cc: Jens Freimann, Heinz Graalfs, qemu-devel, Christian Borntraeger,
	Jens Freimann, Cornelia Huck

On 06/13/2012 12:30 PM, Jan Kiszka wrote:
> On 2012-06-12 14:12, Alexander Graf wrote:
>> On 06/12/2012 02:02 PM, Christian Borntraeger wrote:
>>> On 12/06/12 13:57, Alexander Graf wrote:
>>>> Since it lives in an s390 specific branch, the function name should probably be called s390 specific. If we ever need another architecture to have a kvm specific ram allocator, we can make it generic when that time comes. Until then, let's treat s390 as the oddball it is :).
>>>>
>>>> Apart from that, this approach looks a lot nicer, yes.
>>> But then I have to have a *s390* function declared in kvm.h and your other comment
>>> hits me. You got me in a trap here, heh? ;-)
>> Ah, I see what you mean. I was thinking of having a
>> target-s390x/kvm_s390x.h or so. Then we could add the function
>> definition there and have everything nicely contained within
>> target-s390x only.
>>
>> Jan, which approach would you think is cleaner? Make this a generic
>> kvm_arch callback or introduce a special kvm_s390x.h header which would
>> then have to be explicitly included in exec.c?
> Maybe somethings like
>
> #ifdef __s390__
>      else if (kvm_enabled())
>          new_block->host = kvm_arch_vmalloc(size)
> #endif
>
> ? But I have no definitive opinion yet. I think that
>
>   - the changes to generic code should make clear that it's an s390+kvm
>     specialty
>   - actual work should be done in target-s390/kvm.c (e.g. avoid
>     legacy_s390_alloc)

Thinking about this a bit more, how about

} else if (!kvm_arch_vmalloc(size, &new_block->host)) {
<normal code>
}

Then the arch specific code could do the check and the implementation of 
vmalloc, but only has to return -1 if we don't need it and things still 
fall back to the generic code.


Alex

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

* Re: [Qemu-devel] [PATCH 2/8] s390: autodetect map private
  2012-06-13 10:54               ` Alexander Graf
@ 2012-06-13 10:58                 ` Jan Kiszka
  2012-06-13 11:27                   ` Christian Borntraeger
  0 siblings, 1 reply; 51+ messages in thread
From: Jan Kiszka @ 2012-06-13 10:58 UTC (permalink / raw)
  To: Alexander Graf
  Cc: Jens Freimann, Heinz Graalfs, qemu-devel, Christian Borntraeger,
	Jens Freimann, Cornelia Huck

On 2012-06-13 12:54, Alexander Graf wrote:
> On 06/13/2012 12:30 PM, Jan Kiszka wrote:
>> On 2012-06-12 14:12, Alexander Graf wrote:
>>> On 06/12/2012 02:02 PM, Christian Borntraeger wrote:
>>>> On 12/06/12 13:57, Alexander Graf wrote:
>>>>> Since it lives in an s390 specific branch, the function name should probably be called s390 specific. If we ever need another architecture to have a kvm specific ram allocator, we can make it generic when that time comes. Until then, let's treat s390 as the oddball it is :).
>>>>>
>>>>> Apart from that, this approach looks a lot nicer, yes.
>>>> But then I have to have a *s390* function declared in kvm.h and your other comment
>>>> hits me. You got me in a trap here, heh? ;-)
>>> Ah, I see what you mean. I was thinking of having a
>>> target-s390x/kvm_s390x.h or so. Then we could add the function
>>> definition there and have everything nicely contained within
>>> target-s390x only.
>>>
>>> Jan, which approach would you think is cleaner? Make this a generic
>>> kvm_arch callback or introduce a special kvm_s390x.h header which would
>>> then have to be explicitly included in exec.c?
>> Maybe somethings like
>>
>> #ifdef __s390__
>>      else if (kvm_enabled())
>>          new_block->host = kvm_arch_vmalloc(size)
>> #endif
>>
>> ? But I have no definitive opinion yet. I think that
>>
>>   - the changes to generic code should make clear that it's an s390+kvm
>>     specialty
>>   - actual work should be done in target-s390/kvm.c (e.g. avoid
>>     legacy_s390_alloc)
> 
> Thinking about this a bit more, how about
> 
> } else if (!kvm_arch_vmalloc(size, &new_block->host)) {
> <normal code>
> }
> 
> Then the arch specific code could do the check and the implementation of 
> vmalloc, but only has to return -1 if we don't need it and things still 
> fall back to the generic code.

But you would have to walk a while to find out that only s390x on (old)
KVM actually returns success here and does some allocation.

Jan

-- 
Siemens AG, Corporate Technology, CT T DE IT 1
Corporate Competence Center Embedded Linux

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

* Re: [Qemu-devel] [PATCH 2/8] s390: autodetect map private
  2012-06-13 10:58                 ` Jan Kiszka
@ 2012-06-13 11:27                   ` Christian Borntraeger
  2012-06-13 11:41                     ` Jan Kiszka
  0 siblings, 1 reply; 51+ messages in thread
From: Christian Borntraeger @ 2012-06-13 11:27 UTC (permalink / raw)
  To: Jan Kiszka
  Cc: Jens Freimann, Heinz Graalfs, Alexander Graf, qemu-devel,
	Jens Freimann, Cornelia Huck

On 13/06/12 12:58, Jan Kiszka wrote:
>> Thinking about this a bit more, how about
>>
>> } else if (!kvm_arch_vmalloc(size, &new_block->host)) {
>> <normal code>
>> }
>>

I like that. Of course, we have to have a generic kvm_arch_vmalloc implementation
then.

>> Then the arch specific code could do the check and the implementation of 
>> vmalloc, but only has to return -1 if we don't need it and things still 
>> fall back to the generic code.
> 
> But you would have to walk a while to find out that only s390x on (old)
> KVM actually returns success here and does some allocation.


It that such a problem? What about adding a comment then, otherwise we just
use ifdef as a comment, which isnt nice either.

Christian

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

* Re: [Qemu-devel] [PATCH 2/8] s390: autodetect map private
  2012-06-13 11:27                   ` Christian Borntraeger
@ 2012-06-13 11:41                     ` Jan Kiszka
  2012-06-13 12:33                       ` Alexander Graf
  0 siblings, 1 reply; 51+ messages in thread
From: Jan Kiszka @ 2012-06-13 11:41 UTC (permalink / raw)
  To: Christian Borntraeger
  Cc: Jens Freimann, Heinz Graalfs, Alexander Graf, qemu-devel,
	Jens Freimann, Cornelia Huck

On 2012-06-13 13:27, Christian Borntraeger wrote:
> On 13/06/12 12:58, Jan Kiszka wrote:
>>> Thinking about this a bit more, how about
>>>
>>> } else if (!kvm_arch_vmalloc(size, &new_block->host)) {
>>> <normal code>
>>> }
>>>
> 
> I like that. Of course, we have to have a generic kvm_arch_vmalloc implementation
> then.

Then better go for kvm_vmalloc calling kvm_arch_vmalloc (in the s390 case).

However, I do not like the variation of parameters and return value
compared to normal *alloc. Better:

memory = kvm_vmalloc(size);
if (!memory)
	memory = qemu_vmalloc(size);

But more regular (when looking at the Xen block) is guarding the call
with kvm_enabled() and embedding qemu_vmalloc in kvm_vmalloc.

> 
>>> Then the arch specific code could do the check and the implementation of 
>>> vmalloc, but only has to return -1 if we don't need it and things still 
>>> fall back to the generic code.
>>
>> But you would have to walk a while to find out that only s390x on (old)
>> KVM actually returns success here and does some allocation.
> 
> 
> It that such a problem? What about adding a comment then, otherwise we just
> use ifdef as a comment, which isnt nice either.

Any kind of comment is definitely a good idea.

Jan

-- 
Siemens AG, Corporate Technology, CT T DE IT 1
Corporate Competence Center Embedded Linux

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

* Re: [Qemu-devel] [PATCH 2/8] s390: autodetect map private
  2012-06-13 11:41                     ` Jan Kiszka
@ 2012-06-13 12:33                       ` Alexander Graf
  2012-06-13 12:35                         ` Jan Kiszka
  0 siblings, 1 reply; 51+ messages in thread
From: Alexander Graf @ 2012-06-13 12:33 UTC (permalink / raw)
  To: Jan Kiszka
  Cc: Jens Freimann, Heinz Graalfs, qemu-devel, Christian Borntraeger,
	Jens Freimann, Cornelia Huck

On 06/13/2012 01:41 PM, Jan Kiszka wrote:
> On 2012-06-13 13:27, Christian Borntraeger wrote:
>> On 13/06/12 12:58, Jan Kiszka wrote:
>>>> Thinking about this a bit more, how about
>>>>
>>>> } else if (!kvm_arch_vmalloc(size,&new_block->host)) {
>>>> <normal code>
>>>> }
>>>>
>> I like that. Of course, we have to have a generic kvm_arch_vmalloc implementation
>> then.
> Then better go for kvm_vmalloc calling kvm_arch_vmalloc (in the s390 case).
>
> However, I do not like the variation of parameters and return value
> compared to normal *alloc. Better:
>
> memory = kvm_vmalloc(size);
> if (!memory)
> 	memory = qemu_vmalloc(size);
>
> But more regular (when looking at the Xen block) is guarding the call
> with kvm_enabled() and embedding qemu_vmalloc in kvm_vmalloc.

So basically

#ifdef CONFIG_TARGET_S390X
   } else if (kvm_enabled()) {
     memory = kvm_vmalloc();
   } else {
#endif

or a generic

} else if (kvm_enabled()) {
   memory = kvm_vmalloc();
} else {

? Because that one would mean we always duplicate the common 
qemu_vmalloc case. But then again, that one's only a single call, so 
maybe it's ok. Meh - I'll let you decide :).


Alex

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

* Re: [Qemu-devel] [PATCH 2/8] s390: autodetect map private
  2012-06-13 12:33                       ` Alexander Graf
@ 2012-06-13 12:35                         ` Jan Kiszka
  2012-06-15 14:01                           ` [Qemu-devel] Next version of memory allocation fixup Christian Borntraeger
  0 siblings, 1 reply; 51+ messages in thread
From: Jan Kiszka @ 2012-06-13 12:35 UTC (permalink / raw)
  To: Alexander Graf
  Cc: Jens Freimann, Heinz Graalfs, qemu-devel, Christian Borntraeger,
	Jens Freimann, Cornelia Huck

On 2012-06-13 14:33, Alexander Graf wrote:
> On 06/13/2012 01:41 PM, Jan Kiszka wrote:
>> On 2012-06-13 13:27, Christian Borntraeger wrote:
>>> On 13/06/12 12:58, Jan Kiszka wrote:
>>>>> Thinking about this a bit more, how about
>>>>>
>>>>> } else if (!kvm_arch_vmalloc(size,&new_block->host)) {
>>>>> <normal code>
>>>>> }
>>>>>
>>> I like that. Of course, we have to have a generic kvm_arch_vmalloc implementation
>>> then.
>> Then better go for kvm_vmalloc calling kvm_arch_vmalloc (in the s390 case).
>>
>> However, I do not like the variation of parameters and return value
>> compared to normal *alloc. Better:
>>
>> memory = kvm_vmalloc(size);
>> if (!memory)
>> 	memory = qemu_vmalloc(size);
>>
>> But more regular (when looking at the Xen block) is guarding the call
>> with kvm_enabled() and embedding qemu_vmalloc in kvm_vmalloc.
> 
> So basically
> 
> #ifdef CONFIG_TARGET_S390X
>    } else if (kvm_enabled()) {
>      memory = kvm_vmalloc();
>    } else {
> #endif
> 
> or a generic
> 
> } else if (kvm_enabled()) {
>    memory = kvm_vmalloc();
> } else {
> 
> ? Because that one would mean we always duplicate the common 
> qemu_vmalloc case. But then again, that one's only a single call, so 
> maybe it's ok. Meh - I'll let you decide :).

I'm fine with the #ifdef-free version if providing some comment which
arch requires this special path.

Jan

-- 
Siemens AG, Corporate Technology, CT T DE IT 1
Corporate Competence Center Embedded Linux

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

* Re: [Qemu-devel] [PATCH 6/8] s390: sclp event facility and signal quiesce support via system_powerdown
  2012-06-13  7:00     ` Heinz Graalfs
@ 2012-06-13 13:12       ` Andreas Färber
  0 siblings, 0 replies; 51+ messages in thread
From: Andreas Färber @ 2012-06-13 13:12 UTC (permalink / raw)
  To: Heinz Graalfs
  Cc: Jens Freimann, Alexander Graf, qemu-devel, Christian Borntraeger,
	Jens Freimann, Cornelia Huck

Am 13.06.2012 09:00, schrieb Heinz Graalfs:
> Alex, thanks for the comments,
> 
> On Tue, 2012-06-12 at 13:38 +0200, Alexander Graf wrote:
>> On 06/06/2012 02:05 PM, Jens Freimann wrote:
>>> +static SCLPDevice *sclpef_common_init(const char *name, size_t struct_size)
>>> +{
>>> +    SCLPDevice *sdev;
>>> +
>>> +    sdev = malloc(struct_size);
>>
>> g_malloc please. I suppose even g_malloc0?
>>
> OK, I will look into this

Careful: The equivalent of malloc() and a NULL check is g_try_malloc().
g_malloc() aborts on failure to allocate.

The line to draw is whether this only happens at startup or whether this
is called at runtime *and* you are willing to consequently handle the
possible NULL return in all callers.

Regards,
Andreas

-- 
SUSE LINUX Products GmbH, Maxfeldstr. 5, 90409 Nürnberg, Germany
GF: Jeff Hawn, Jennifer Guild, Felix Imendörffer; HRB 16746 AG Nürnberg

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

* [Qemu-devel] Next version of memory allocation fixup
  2012-06-13 12:35                         ` Jan Kiszka
@ 2012-06-15 14:01                           ` Christian Borntraeger
  2012-06-15 14:01                             ` [Qemu-devel] [PatchV2] s390: autodetect map private Christian Borntraeger
  2012-06-15 15:10                             ` [Qemu-devel] One more fix Christian Borntraeger
  0 siblings, 2 replies; 51+ messages in thread
From: Christian Borntraeger @ 2012-06-15 14:01 UTC (permalink / raw)
  To: agraf
  Cc: jfrei, graalfs, jan.kiszka, qemu-devel, Christian Borntraeger,
	cornelia.huck

Jan, Alex,
what about this version? I had two options: ifdef in kvm for
s390 or provide a kvm_arch_vmalloc for every kvm arch. I did choose
the first one.

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

* [Qemu-devel] [PatchV2] s390: autodetect map private
  2012-06-15 14:01                           ` [Qemu-devel] Next version of memory allocation fixup Christian Borntraeger
@ 2012-06-15 14:01                             ` Christian Borntraeger
  2012-06-15 15:10                             ` [Qemu-devel] One more fix Christian Borntraeger
  1 sibling, 0 replies; 51+ messages in thread
From: Christian Borntraeger @ 2012-06-15 14:01 UTC (permalink / raw)
  To: agraf
  Cc: jfrei, graalfs, jan.kiszka, qemu-devel, Christian Borntraeger,
	cornelia.huck

By default qemu will use MAP_PRIVATE for guest pages. This will write
protect pages and thus break on s390 systems that dont support this feature.
Therefore qemu has a hack to always use MAP_SHARED for s390. But MAP_SHARED
has other problems (no dirty pages tracking, a lot more swap overhead etc.)
Newer systems allow the distinction via KVM_CAP_S390_COW. With this feature
qemu can use the standard qemu alloc if available, otherwise it will use
the old s390 hack.

Signed-off-by: Christian Borntraeger <borntraeger@de.ibm.com>
---
 exec.c             |   18 +++---------------
 kvm-all.c          |   13 +++++++++++++
 kvm.h              |    3 +++
 oslib-posix.c      |    3 +++
 target-s390x/kvm.c |   35 +++++++++++++++++++++++++++++++++++
 5 files changed, 57 insertions(+), 15 deletions(-)

diff --git a/exec.c b/exec.c
index 5c9b762..584a484 100644
--- a/exec.c
+++ b/exec.c
@@ -2647,26 +2647,14 @@ ram_addr_t qemu_ram_alloc_from_ptr(ram_addr_t size, void *host,
             exit(1);
 #endif
         } else {
-#if defined(TARGET_S390X) && defined(CONFIG_KVM)
-            /* S390 KVM requires the topmost vma of the RAM to be smaller than
-               an system defined value, which is at least 256GB. Larger systems
-               have larger values. We put the guest between the end of data
-               segment (system break) and this value. We use 32GB as a base to
-               have enough room for the system break to grow. */
-            new_block->host = mmap((void*)0x800000000, size,
-                                   PROT_EXEC|PROT_READ|PROT_WRITE,
-                                   MAP_SHARED | MAP_ANONYMOUS | MAP_FIXED, -1, 0);
-            if (new_block->host == MAP_FAILED) {
-                fprintf(stderr, "Allocating RAM failed\n");
-                abort();
-            }
-#else
             if (xen_enabled()) {
                 xen_ram_alloc(new_block->offset, size, mr);
+            } else if (kvm_enabled()) {
+                /* some s390/kvm configurations have special constraints */
+                new_block->host = kvm_vmalloc(size);
             } else {
                 new_block->host = qemu_vmalloc(size);
             }
-#endif
             qemu_madvise(new_block->host, size, QEMU_MADV_MERGEABLE);
         }
     }
diff --git a/kvm-all.c b/kvm-all.c
index 4ea7d85..0372f7a 100644
--- a/kvm-all.c
+++ b/kvm-all.c
@@ -1653,6 +1653,19 @@ int kvm_allows_irq0_override(void)
     return !kvm_irqchip_in_kernel() || kvm_has_gsi_routing();
 }
 
+void *kvm_vmalloc(ram_addr_t size)
+{
+#ifdef TARGET_S390X
+    void *mem; 
+
+    mem = kvm_arch_vmalloc(size);
+    if (mem) {
+        return mem;
+    }
+#endif
+    return qemu_vmalloc(size);
+}
+
 void kvm_setup_guest_memory(void *start, size_t size)
 {
     if (!kvm_has_sync_mmu()) {
diff --git a/kvm.h b/kvm.h
index 9c7b0ea..c8ebf3d 100644
--- a/kvm.h
+++ b/kvm.h
@@ -60,6 +60,7 @@ int kvm_has_xsave(void);
 int kvm_has_xcrs(void);
 int kvm_has_pit_state2(void);
 int kvm_has_many_ioeventfds(void);
+
 int kvm_has_gsi_routing(void);
 
 int kvm_allows_irq0_override(void);
@@ -70,6 +71,7 @@ int kvm_init_vcpu(CPUArchState *env);
 int kvm_cpu_exec(CPUArchState *env);
 
 #if !defined(CONFIG_USER_ONLY)
+void *kvm_vmalloc(ram_addr_t size);
 void kvm_setup_guest_memory(void *start, size_t size);
 
 int kvm_coalesce_mmio_region(target_phys_addr_t start, ram_addr_t size);
@@ -177,6 +179,7 @@ uint32_t kvm_arch_get_supported_cpuid(KVMState *env, uint32_t function,
 void kvm_cpu_synchronize_state(CPUArchState *env);
 void kvm_cpu_synchronize_post_reset(CPUArchState *env);
 void kvm_cpu_synchronize_post_init(CPUArchState *env);
+void *kvm_arch_vmalloc(ram_addr_t size);
 
 /* generic hooks - to be moved/refactored once there are more users */
 
diff --git a/oslib-posix.c b/oslib-posix.c
index b6a3c7f..93902ac 100644
--- a/oslib-posix.c
+++ b/oslib-posix.c
@@ -41,6 +41,9 @@ extern int daemon(int, int);
       therefore we need special code which handles running on Valgrind. */
 #  define QEMU_VMALLOC_ALIGN (512 * 4096)
 #  define CONFIG_VALGRIND
+#elif defined(__linux__) && defined(__s390x__)
+   /* Use 1 MiB (segment size) alignment so gmap can be used by KVM. */
+#  define QEMU_VMALLOC_ALIGN (256 * 4096)
 #else
 #  define QEMU_VMALLOC_ALIGN getpagesize()
 #endif
diff --git a/target-s390x/kvm.c b/target-s390x/kvm.c
index 5800fd6..4d38820 100644
--- a/target-s390x/kvm.c
+++ b/target-s390x/kvm.c
@@ -135,6 +135,41 @@ int kvm_arch_get_registers(CPUS390XState *env)
     return 0;
 }
 
+/*
+ * Legacy layout for s390:
+ * Older S390 KVM requires the topmost vma of the RAM to be
+ * smaller than an system defined value, which is at least 256GB.
+ * Larger systems have larger values. We put the guest between
+ * the end of data segment (system break) and this value. We
+ * use 32GB as a base to have enough room for the system break
+ * to grow. We also have to use MAP parameters that avoid
+ * read-only mapping of guest pages.
+ */
+static void *legacy_s390_alloc(ram_addr_t size)
+{
+    void *mem;
+
+    mem = mmap((void *) 0x800000000ULL, size,
+               PROT_EXEC|PROT_READ|PROT_WRITE,
+               MAP_SHARED | MAP_ANONYMOUS | MAP_FIXED, -1, 0);
+    if (mem == MAP_FAILED) {
+        fprintf(stderr, "Allocating RAM failed\n");
+        abort();
+    }
+    return mem;
+}
+
+void *kvm_arch_vmalloc(ram_addr_t size)
+{
+    /* Can we use the standard allocation ? */
+    if (kvm_check_extension(kvm_state, KVM_CAP_S390_GMAP) &&
+        kvm_check_extension(kvm_state, KVM_CAP_S390_COW)) {
+        return NULL;
+    } else {
+        return legacy_s390_alloc(size);
+    }
+}
+
 int kvm_arch_insert_sw_breakpoint(CPUS390XState *env, struct kvm_sw_breakpoint *bp)
 {
     static const uint8_t diag_501[] = {0x83, 0x24, 0x05, 0x01};
-- 
1.7.10.4

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

* [Qemu-devel] One more fix
  2012-06-15 14:01                           ` [Qemu-devel] Next version of memory allocation fixup Christian Borntraeger
  2012-06-15 14:01                             ` [Qemu-devel] [PatchV2] s390: autodetect map private Christian Borntraeger
@ 2012-06-15 15:10                             ` Christian Borntraeger
  2012-06-15 15:10                               ` [Qemu-devel] [PATCH v3] s390: autodetect map private Christian Borntraeger
  1 sibling, 1 reply; 51+ messages in thread
From: Christian Borntraeger @ 2012-06-15 15:10 UTC (permalink / raw)
  To: agraf
  Cc: jfrei, graalfs, jan.kiszka, qemu-devel, Christian Borntraeger,
	cornelia.huck

Hmpf,

here is a fixed version that also compiles for config user only...

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

* [Qemu-devel] [PATCH v3] s390: autodetect map private
  2012-06-15 15:10                             ` [Qemu-devel] One more fix Christian Borntraeger
@ 2012-06-15 15:10                               ` Christian Borntraeger
  2012-06-15 17:01                                 ` Jan Kiszka
  2012-06-18 13:44                                 ` Alexander Graf
  0 siblings, 2 replies; 51+ messages in thread
From: Christian Borntraeger @ 2012-06-15 15:10 UTC (permalink / raw)
  To: agraf
  Cc: jfrei, graalfs, jan.kiszka, qemu-devel, Christian Borntraeger,
	Jens Freimann, cornelia.huck

By default qemu will use MAP_PRIVATE for guest pages. This will write
protect pages and thus break on s390 systems that dont support this feature.
Therefore qemu has a hack to always use MAP_SHARED for s390. But MAP_SHARED
has other problems (no dirty pages tracking, a lot more swap overhead etc.)
Newer systems allow the distinction via KVM_CAP_S390_COW. With this feature
qemu can use the standard qemu alloc if available, otherwise it will use
the old s390 hack.

Signed-off-by: Christian Borntraeger <borntraeger@de.ibm.com>
Signed-off-by: Jens Freimann <jfrei@linux.vnet.ibm.com>
---
 exec.c             |   18 +++---------------
 kvm-all.c          |   13 +++++++++++++
 kvm.h              |    2 ++
 oslib-posix.c      |    3 +++
 target-s390x/kvm.c |   35 +++++++++++++++++++++++++++++++++++
 5 files changed, 56 insertions(+), 15 deletions(-)

diff --git a/exec.c b/exec.c
index 5c9b762..584a484 100644
--- a/exec.c
+++ b/exec.c
@@ -2647,26 +2647,14 @@ ram_addr_t qemu_ram_alloc_from_ptr(ram_addr_t size, void *host,
             exit(1);
 #endif
         } else {
-#if defined(TARGET_S390X) && defined(CONFIG_KVM)
-            /* S390 KVM requires the topmost vma of the RAM to be smaller than
-               an system defined value, which is at least 256GB. Larger systems
-               have larger values. We put the guest between the end of data
-               segment (system break) and this value. We use 32GB as a base to
-               have enough room for the system break to grow. */
-            new_block->host = mmap((void*)0x800000000, size,
-                                   PROT_EXEC|PROT_READ|PROT_WRITE,
-                                   MAP_SHARED | MAP_ANONYMOUS | MAP_FIXED, -1, 0);
-            if (new_block->host == MAP_FAILED) {
-                fprintf(stderr, "Allocating RAM failed\n");
-                abort();
-            }
-#else
             if (xen_enabled()) {
                 xen_ram_alloc(new_block->offset, size, mr);
+            } else if (kvm_enabled()) {
+                /* some s390/kvm configurations have special constraints */
+                new_block->host = kvm_vmalloc(size);
             } else {
                 new_block->host = qemu_vmalloc(size);
             }
-#endif
             qemu_madvise(new_block->host, size, QEMU_MADV_MERGEABLE);
         }
     }
diff --git a/kvm-all.c b/kvm-all.c
index 4ea7d85..0372f7a 100644
--- a/kvm-all.c
+++ b/kvm-all.c
@@ -1653,6 +1653,19 @@ int kvm_allows_irq0_override(void)
     return !kvm_irqchip_in_kernel() || kvm_has_gsi_routing();
 }
 
+void *kvm_vmalloc(ram_addr_t size)
+{
+#ifdef TARGET_S390X
+    void *mem;
+
+    mem = kvm_arch_vmalloc(size);
+    if (mem) {
+        return mem;
+    }
+#endif
+    return qemu_vmalloc(size);
+}
+
 void kvm_setup_guest_memory(void *start, size_t size)
 {
     if (!kvm_has_sync_mmu()) {
diff --git a/kvm.h b/kvm.h
index 9c7b0ea..ddc7c53 100644
--- a/kvm.h
+++ b/kvm.h
@@ -70,6 +70,8 @@ int kvm_init_vcpu(CPUArchState *env);
 int kvm_cpu_exec(CPUArchState *env);
 
 #if !defined(CONFIG_USER_ONLY)
+void *kvm_vmalloc(ram_addr_t size);
+void *kvm_arch_vmalloc(ram_addr_t size);
 void kvm_setup_guest_memory(void *start, size_t size);
 
 int kvm_coalesce_mmio_region(target_phys_addr_t start, ram_addr_t size);
diff --git a/oslib-posix.c b/oslib-posix.c
index b6a3c7f..93902ac 100644
--- a/oslib-posix.c
+++ b/oslib-posix.c
@@ -41,6 +41,9 @@ extern int daemon(int, int);
       therefore we need special code which handles running on Valgrind. */
 #  define QEMU_VMALLOC_ALIGN (512 * 4096)
 #  define CONFIG_VALGRIND
+#elif defined(__linux__) && defined(__s390x__)
+   /* Use 1 MiB (segment size) alignment so gmap can be used by KVM. */
+#  define QEMU_VMALLOC_ALIGN (256 * 4096)
 #else
 #  define QEMU_VMALLOC_ALIGN getpagesize()
 #endif
diff --git a/target-s390x/kvm.c b/target-s390x/kvm.c
index 5800fd6..4d38820 100644
--- a/target-s390x/kvm.c
+++ b/target-s390x/kvm.c
@@ -135,6 +135,41 @@ int kvm_arch_get_registers(CPUS390XState *env)
     return 0;
 }
 
+/*
+ * Legacy layout for s390:
+ * Older S390 KVM requires the topmost vma of the RAM to be
+ * smaller than an system defined value, which is at least 256GB.
+ * Larger systems have larger values. We put the guest between
+ * the end of data segment (system break) and this value. We
+ * use 32GB as a base to have enough room for the system break
+ * to grow. We also have to use MAP parameters that avoid
+ * read-only mapping of guest pages.
+ */
+static void *legacy_s390_alloc(ram_addr_t size)
+{
+    void *mem;
+
+    mem = mmap((void *) 0x800000000ULL, size,
+               PROT_EXEC|PROT_READ|PROT_WRITE,
+               MAP_SHARED | MAP_ANONYMOUS | MAP_FIXED, -1, 0);
+    if (mem == MAP_FAILED) {
+        fprintf(stderr, "Allocating RAM failed\n");
+        abort();
+    }
+    return mem;
+}
+
+void *kvm_arch_vmalloc(ram_addr_t size)
+{
+    /* Can we use the standard allocation ? */
+    if (kvm_check_extension(kvm_state, KVM_CAP_S390_GMAP) &&
+        kvm_check_extension(kvm_state, KVM_CAP_S390_COW)) {
+        return NULL;
+    } else {
+        return legacy_s390_alloc(size);
+    }
+}
+
 int kvm_arch_insert_sw_breakpoint(CPUS390XState *env, struct kvm_sw_breakpoint *bp)
 {
     static const uint8_t diag_501[] = {0x83, 0x24, 0x05, 0x01};
-- 
1.7.10.4

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

* Re: [Qemu-devel] [PATCH v3] s390: autodetect map private
  2012-06-15 15:10                               ` [Qemu-devel] [PATCH v3] s390: autodetect map private Christian Borntraeger
@ 2012-06-15 17:01                                 ` Jan Kiszka
  2012-06-18 13:44                                 ` Alexander Graf
  1 sibling, 0 replies; 51+ messages in thread
From: Jan Kiszka @ 2012-06-15 17:01 UTC (permalink / raw)
  To: Christian Borntraeger
  Cc: jfrei, graalfs, agraf, qemu-devel, Jens Freimann, cornelia.huck

On 2012-06-15 17:10, Christian Borntraeger wrote:
> By default qemu will use MAP_PRIVATE for guest pages. This will write
> protect pages and thus break on s390 systems that dont support this feature.
> Therefore qemu has a hack to always use MAP_SHARED for s390. But MAP_SHARED
> has other problems (no dirty pages tracking, a lot more swap overhead etc.)
> Newer systems allow the distinction via KVM_CAP_S390_COW. With this feature
> qemu can use the standard qemu alloc if available, otherwise it will use
> the old s390 hack.
> 
> Signed-off-by: Christian Borntraeger <borntraeger@de.ibm.com>
> Signed-off-by: Jens Freimann <jfrei@linux.vnet.ibm.com>
> ---
>  exec.c             |   18 +++---------------
>  kvm-all.c          |   13 +++++++++++++
>  kvm.h              |    2 ++
>  oslib-posix.c      |    3 +++
>  target-s390x/kvm.c |   35 +++++++++++++++++++++++++++++++++++
>  5 files changed, 56 insertions(+), 15 deletions(-)
> 
> diff --git a/exec.c b/exec.c
> index 5c9b762..584a484 100644
> --- a/exec.c
> +++ b/exec.c
> @@ -2647,26 +2647,14 @@ ram_addr_t qemu_ram_alloc_from_ptr(ram_addr_t size, void *host,
>              exit(1);
>  #endif
>          } else {
> -#if defined(TARGET_S390X) && defined(CONFIG_KVM)
> -            /* S390 KVM requires the topmost vma of the RAM to be smaller than
> -               an system defined value, which is at least 256GB. Larger systems
> -               have larger values. We put the guest between the end of data
> -               segment (system break) and this value. We use 32GB as a base to
> -               have enough room for the system break to grow. */
> -            new_block->host = mmap((void*)0x800000000, size,
> -                                   PROT_EXEC|PROT_READ|PROT_WRITE,
> -                                   MAP_SHARED | MAP_ANONYMOUS | MAP_FIXED, -1, 0);
> -            if (new_block->host == MAP_FAILED) {
> -                fprintf(stderr, "Allocating RAM failed\n");
> -                abort();
> -            }
> -#else
>              if (xen_enabled()) {
>                  xen_ram_alloc(new_block->offset, size, mr);
> +            } else if (kvm_enabled()) {
> +                /* some s390/kvm configurations have special constraints */
> +                new_block->host = kvm_vmalloc(size);
>              } else {
>                  new_block->host = qemu_vmalloc(size);
>              }
> -#endif
>              qemu_madvise(new_block->host, size, QEMU_MADV_MERGEABLE);
>          }
>      }
> diff --git a/kvm-all.c b/kvm-all.c
> index 4ea7d85..0372f7a 100644
> --- a/kvm-all.c
> +++ b/kvm-all.c
> @@ -1653,6 +1653,19 @@ int kvm_allows_irq0_override(void)
>      return !kvm_irqchip_in_kernel() || kvm_has_gsi_routing();
>  }
>  
> +void *kvm_vmalloc(ram_addr_t size)
> +{
> +#ifdef TARGET_S390X
> +    void *mem;
> +
> +    mem = kvm_arch_vmalloc(size);
> +    if (mem) {
> +        return mem;
> +    }
> +#endif
> +    return qemu_vmalloc(size);
> +}
> +
>  void kvm_setup_guest_memory(void *start, size_t size)
>  {
>      if (!kvm_has_sync_mmu()) {
> diff --git a/kvm.h b/kvm.h
> index 9c7b0ea..ddc7c53 100644
> --- a/kvm.h
> +++ b/kvm.h
> @@ -70,6 +70,8 @@ int kvm_init_vcpu(CPUArchState *env);
>  int kvm_cpu_exec(CPUArchState *env);
>  
>  #if !defined(CONFIG_USER_ONLY)
> +void *kvm_vmalloc(ram_addr_t size);
> +void *kvm_arch_vmalloc(ram_addr_t size);
>  void kvm_setup_guest_memory(void *start, size_t size);
>  
>  int kvm_coalesce_mmio_region(target_phys_addr_t start, ram_addr_t size);
> diff --git a/oslib-posix.c b/oslib-posix.c
> index b6a3c7f..93902ac 100644
> --- a/oslib-posix.c
> +++ b/oslib-posix.c
> @@ -41,6 +41,9 @@ extern int daemon(int, int);
>        therefore we need special code which handles running on Valgrind. */
>  #  define QEMU_VMALLOC_ALIGN (512 * 4096)
>  #  define CONFIG_VALGRIND
> +#elif defined(__linux__) && defined(__s390x__)
> +   /* Use 1 MiB (segment size) alignment so gmap can be used by KVM. */
> +#  define QEMU_VMALLOC_ALIGN (256 * 4096)
>  #else
>  #  define QEMU_VMALLOC_ALIGN getpagesize()
>  #endif
> diff --git a/target-s390x/kvm.c b/target-s390x/kvm.c
> index 5800fd6..4d38820 100644
> --- a/target-s390x/kvm.c
> +++ b/target-s390x/kvm.c
> @@ -135,6 +135,41 @@ int kvm_arch_get_registers(CPUS390XState *env)
>      return 0;
>  }
>  
> +/*
> + * Legacy layout for s390:
> + * Older S390 KVM requires the topmost vma of the RAM to be
> + * smaller than an system defined value, which is at least 256GB.
> + * Larger systems have larger values. We put the guest between
> + * the end of data segment (system break) and this value. We
> + * use 32GB as a base to have enough room for the system break
> + * to grow. We also have to use MAP parameters that avoid
> + * read-only mapping of guest pages.
> + */
> +static void *legacy_s390_alloc(ram_addr_t size)
> +{
> +    void *mem;
> +
> +    mem = mmap((void *) 0x800000000ULL, size,
> +               PROT_EXEC|PROT_READ|PROT_WRITE,
> +               MAP_SHARED | MAP_ANONYMOUS | MAP_FIXED, -1, 0);
> +    if (mem == MAP_FAILED) {
> +        fprintf(stderr, "Allocating RAM failed\n");
> +        abort();
> +    }
> +    return mem;
> +}
> +
> +void *kvm_arch_vmalloc(ram_addr_t size)
> +{
> +    /* Can we use the standard allocation ? */
> +    if (kvm_check_extension(kvm_state, KVM_CAP_S390_GMAP) &&
> +        kvm_check_extension(kvm_state, KVM_CAP_S390_COW)) {
> +        return NULL;
> +    } else {
> +        return legacy_s390_alloc(size);
> +    }
> +}
> +
>  int kvm_arch_insert_sw_breakpoint(CPUS390XState *env, struct kvm_sw_breakpoint *bp)
>  {
>      static const uint8_t diag_501[] = {0x83, 0x24, 0x05, 0x01};

Looks good to me.

Jan

-- 
Siemens AG, Corporate Technology, CT T DE IT 1
Corporate Competence Center Embedded Linux

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

* Re: [Qemu-devel] [PATCH 0/8] s390: SCLP console and misc
  2012-06-06 12:05 [Qemu-devel] [PATCH 0/8] s390: SCLP console and misc Jens Freimann
                   ` (7 preceding siblings ...)
  2012-06-06 12:05 ` [Qemu-devel] [PATCH 8/8] s390: Fix the storage increment size calculation Jens Freimann
@ 2012-06-18 12:35 ` Christian Borntraeger
  2012-06-18 13:33   ` Alexander Graf
  8 siblings, 1 reply; 51+ messages in thread
From: Christian Borntraeger @ 2012-06-18 12:35 UTC (permalink / raw)
  To: Alexander Graf
  Cc: Jens Freimann, Cornelia Huck, Jens Freimann, Heinz Graalfs, qemu-devel

Alex,

are you going to pull the non-controversial patches?
We would then send a reworked sclp patch set later on (when 
ready) - and everything that you also want us to rework.

The alternative is to resend the considered good
patches in a separate patch set.

Christian

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

* Re: [Qemu-devel] [PATCH 0/8] s390: SCLP console and misc
  2012-06-18 12:35 ` [Qemu-devel] [PATCH 0/8] s390: SCLP console and misc Christian Borntraeger
@ 2012-06-18 13:33   ` Alexander Graf
  2012-06-18 13:41     ` Christian Borntraeger
  0 siblings, 1 reply; 51+ messages in thread
From: Alexander Graf @ 2012-06-18 13:33 UTC (permalink / raw)
  To: Christian Borntraeger
  Cc: Jens Freimann, Cornelia Huck, Jens Freimann, Heinz Graalfs, qemu-devel


On 18.06.2012, at 14:35, Christian Borntraeger wrote:

> Alex,
> 
> are you going to pull the non-controversial patches?
> We would then send a reworked sclp patch set later on (when 
> ready) - and everything that you also want us to rework.

Yes, sorry. My patch queue currently has the following patches. Please let me know if I did forget any uncontroversial ones :).


Alexander Graf (2):
      s390x: fix s390 virtio aliases
      kvm: Update kernel headers

Christian Borntraeger (1):
      s390: stop target cpu on sigp initial reset

Jens Freimann (1):
      s390: make kvm_stat work on s390


Alex

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

* Re: [Qemu-devel] [PATCH 0/8] s390: SCLP console and misc
  2012-06-18 13:33   ` Alexander Graf
@ 2012-06-18 13:41     ` Christian Borntraeger
  2012-06-18 13:51       ` Alexander Graf
  0 siblings, 1 reply; 51+ messages in thread
From: Christian Borntraeger @ 2012-06-18 13:41 UTC (permalink / raw)
  To: Alexander Graf
  Cc: Jens Freimann, Cornelia Huck, Jens Freimann, Heinz Graalfs, qemu-devel

On 18/06/12 15:33, Alexander Graf wrote:
> 
> On 18.06.2012, at 14:35, Christian Borntraeger wrote:
> 
>> Alex,
>>
>> are you going to pull the non-controversial patches?
>> We would then send a reworked sclp patch set later on (when 
>> ready) - and everything that you also want us to rework.
> 
> Yes, sorry. My patch queue currently has the following patches. Please let me know if I did forget any uncontroversial ones :).

What about 
- the last version of the autodetect map private that was reviewed by Jan?
- s390: Fix the storage increment size calculation?

> 
> 
> Alexander Graf (2):
>       s390x: fix s390 virtio aliases
>       kvm: Update kernel headers
> 
> Christian Borntraeger (1):
>       s390: stop target cpu on sigp initial reset
> 
> Jens Freimann (1):
>       s390: make kvm_stat work on s390
> 
> 
> Alex

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

* Re: [Qemu-devel] [PATCH v3] s390: autodetect map private
  2012-06-15 15:10                               ` [Qemu-devel] [PATCH v3] s390: autodetect map private Christian Borntraeger
  2012-06-15 17:01                                 ` Jan Kiszka
@ 2012-06-18 13:44                                 ` Alexander Graf
  1 sibling, 0 replies; 51+ messages in thread
From: Alexander Graf @ 2012-06-18 13:44 UTC (permalink / raw)
  To: Christian Borntraeger
  Cc: jfrei, graalfs, jan.kiszka, qemu-devel, Jens Freimann, cornelia.huck


On 15.06.2012, at 17:10, Christian Borntraeger wrote:

> By default qemu will use MAP_PRIVATE for guest pages. This will write
> protect pages and thus break on s390 systems that dont support this feature.
> Therefore qemu has a hack to always use MAP_SHARED for s390. But MAP_SHARED
> has other problems (no dirty pages tracking, a lot more swap overhead etc.)
> Newer systems allow the distinction via KVM_CAP_S390_COW. With this feature
> qemu can use the standard qemu alloc if available, otherwise it will use
> the old s390 hack.

Thanks, applied to s390-next.


Alex

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

* Re: [Qemu-devel] [PATCH 8/8] s390: Fix the storage increment size calculation
  2012-06-12 14:57     ` Jeng-fang Wang
@ 2012-06-18 13:46       ` Alexander Graf
  2012-06-18 19:30         ` Christian Borntraeger
  0 siblings, 1 reply; 51+ messages in thread
From: Alexander Graf @ 2012-06-18 13:46 UTC (permalink / raw)
  To: Jeng-fang Wang
  Cc: Jens Freimann, Heinz Graalfs, Christian Borntraeger, qemu-devel,
	Jens Freimann, Cornelia Huck


On 12.06.2012, at 16:57, Jeng-fang Wang wrote:

> Yes, you can refer to AR10040-03-POK, Service-Call Logical Processor Architecture for S/390 and z/Architecture, Figure 2-6 Minimum storage increment and subincrement size.  :)
> 

Is that one publicly available anywhere?


Alex

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

* Re: [Qemu-devel] [PATCH 0/8] s390: SCLP console and misc
  2012-06-18 13:41     ` Christian Borntraeger
@ 2012-06-18 13:51       ` Alexander Graf
  0 siblings, 0 replies; 51+ messages in thread
From: Alexander Graf @ 2012-06-18 13:51 UTC (permalink / raw)
  To: Christian Borntraeger
  Cc: Jens Freimann, Cornelia Huck, Jens Freimann, Heinz Graalfs, qemu-devel


On 18.06.2012, at 15:41, Christian Borntraeger wrote:

> On 18/06/12 15:33, Alexander Graf wrote:
>> 
>> On 18.06.2012, at 14:35, Christian Borntraeger wrote:
>> 
>>> Alex,
>>> 
>>> are you going to pull the non-controversial patches?
>>> We would then send a reworked sclp patch set later on (when 
>>> ready) - and everything that you also want us to rework.
>> 
>> Yes, sorry. My patch queue currently has the following patches. Please let me know if I did forget any uncontroversial ones :).
> 
> What about 
> - the last version of the autodetect map private that was reviewed by Jan?

Yup, applied that one.

> - s390: Fix the storage increment size calculation?

That's not uncontroversial yet. I still need to see some documentation - or blindly trust you guys :(.


Alex

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

* Re: [Qemu-devel] [PATCH 8/8] s390: Fix the storage increment size calculation
  2012-06-18 13:46       ` Alexander Graf
@ 2012-06-18 19:30         ` Christian Borntraeger
  0 siblings, 0 replies; 51+ messages in thread
From: Christian Borntraeger @ 2012-06-18 19:30 UTC (permalink / raw)
  To: Alexander Graf
  Cc: Jens Freimann, Heinz Graalfs, Jeng-fang Wang, qemu-devel,
	Jens Freimann, Cornelia Huck

On 18/06/12 15:46, Alexander Graf wrote:

> Is that one publicly available anywhere?

Unfortunately no. Sorry.

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

end of thread, other threads:[~2012-06-18 19:30 UTC | newest]

Thread overview: 51+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2012-06-06 12:05 [Qemu-devel] [PATCH 0/8] s390: SCLP console and misc Jens Freimann
2012-06-06 12:05 ` [Qemu-devel] [PATCH 1/8] s390: add new define for KVM_CAP_S390_COW Jens Freimann
2012-06-06 12:05 ` [Qemu-devel] [PATCH 2/8] s390: autodetect map private Jens Freimann
2012-06-12  9:32   ` Alexander Graf
2012-06-12 11:20     ` Christian Borntraeger
2012-06-12 11:57       ` Alexander Graf
2012-06-12 12:02         ` Christian Borntraeger
2012-06-12 12:12           ` Alexander Graf
2012-06-13 10:30             ` Jan Kiszka
2012-06-13 10:54               ` Alexander Graf
2012-06-13 10:58                 ` Jan Kiszka
2012-06-13 11:27                   ` Christian Borntraeger
2012-06-13 11:41                     ` Jan Kiszka
2012-06-13 12:33                       ` Alexander Graf
2012-06-13 12:35                         ` Jan Kiszka
2012-06-15 14:01                           ` [Qemu-devel] Next version of memory allocation fixup Christian Borntraeger
2012-06-15 14:01                             ` [Qemu-devel] [PatchV2] s390: autodetect map private Christian Borntraeger
2012-06-15 15:10                             ` [Qemu-devel] One more fix Christian Borntraeger
2012-06-15 15:10                               ` [Qemu-devel] [PATCH v3] s390: autodetect map private Christian Borntraeger
2012-06-15 17:01                                 ` Jan Kiszka
2012-06-18 13:44                                 ` Alexander Graf
2012-06-06 12:05 ` [Qemu-devel] [PATCH 3/8] s390: make kvm_stat work on s390 Jens Freimann
2012-06-06 12:05 ` [Qemu-devel] [PATCH 4/8] s390: stop target cpu on sigp initial reset Jens Freimann
2012-06-12  9:42   ` Alexander Graf
2012-06-12 10:15     ` Christian Borntraeger
2012-06-06 12:05 ` [Qemu-devel] [PATCH 5/8] s390: Cleanup sclp functions Jens Freimann
2012-06-12  9:58   ` Alexander Graf
2012-06-12 10:07     ` Christian Borntraeger
2012-06-12 10:09       ` Alexander Graf
2012-06-12 10:10       ` Alexander Graf
2012-06-12 12:24     ` Christian Borntraeger
2012-06-12 12:32       ` Alexander Graf
2012-06-12 22:41         ` Anthony Liguori
2012-06-12 22:38   ` Anthony Liguori
2012-06-06 12:05 ` [Qemu-devel] [PATCH 6/8] s390: sclp event facility and signal quiesce support via system_powerdown Jens Freimann
2012-06-12 11:38   ` Alexander Graf
2012-06-13  7:00     ` Heinz Graalfs
2012-06-13 13:12       ` Andreas Färber
2012-06-06 12:05 ` [Qemu-devel] [PATCH 7/8] s390: Add SCLP vt220 console support Jens Freimann
2012-06-12 11:52   ` Alexander Graf
2012-06-13  7:27     ` Heinz Graalfs
2012-06-13  7:53       ` Alexander Graf
2012-06-06 12:05 ` [Qemu-devel] [PATCH 8/8] s390: Fix the storage increment size calculation Jens Freimann
2012-06-12 11:53   ` Alexander Graf
2012-06-12 14:57     ` Jeng-fang Wang
2012-06-18 13:46       ` Alexander Graf
2012-06-18 19:30         ` Christian Borntraeger
2012-06-18 12:35 ` [Qemu-devel] [PATCH 0/8] s390: SCLP console and misc Christian Borntraeger
2012-06-18 13:33   ` Alexander Graf
2012-06-18 13:41     ` Christian Borntraeger
2012-06-18 13:51       ` 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.