Re: [Qemu-devel] [qemu-s390x] [Bug 1753437] [NEW] qemu/pc-bios/s390-ccw/libc.c:82: bad test ?

2018-03-05 Thread Collin L. Walling

On 03/05/2018 09:53 AM, Thomas Huth wrote:

On 05.03.2018 12:22, Christian Borntraeger wrote:

Adding qemu-s390x.

On 03/05/2018 11:31 AM, dcb wrote:

Public bug reported:

qemu/pc-bios/s390-ccw/libc.c:82]: (style) Unsigned variable 'num_idx'
can't be negative so it is unnecessary to test it.

Source code is


 while (num_idx >= 0) {

but

 size_t num_idx = 1; /* account for NUL */

So there is no escape from the while loop.

Actually we're defining size_t like this in the s390-ccw bios:

typedef long   size_t;

So the while loop is not endless.

But yes, this is ugly, we should fix the function and re-define size_t
to be unsigned instead...

  Thomas


Agreed.

--
- Collin L Walling




[Qemu-devel] [PATCH v2] s390/ipl: only print boot menu error if -boot menu=on was specified

2018-02-27 Thread Collin L. Walling
It is possible that certain QEMU configurations may not
create an IPLB (such as when -kernel is provided). In
this case, a misleading error message will be printed
stating that the "boot menu is not supported for this
device type".

To amend this, only print this message iff boot menu=on
was provided on the commandline. Otherwise, return silently.

While we're at it, remove trailing periods from error
messages.

Signed-off-by: Collin L. Walling <wall...@linux.vnet.ibm.com>
---
 hw/s390x/ipl.c | 10 ++
 1 file changed, 6 insertions(+), 4 deletions(-)

diff --git a/hw/s390x/ipl.c b/hw/s390x/ipl.c
index 798e99a..d7fb33f 100644
--- a/hw/s390x/ipl.c
+++ b/hw/s390x/ipl.c
@@ -234,7 +234,7 @@ static void s390_ipl_set_boot_menu(S390IPLState *ipl)
 if (!get_boot_device(0)) {
 if (boot_menu) {
 error_report("boot menu requires a bootindex to be specified for "
- "the IPL device.");
+ "the IPL device");
 }
 return;
 }
@@ -250,7 +250,9 @@ static void s390_ipl_set_boot_menu(S390IPLState *ipl)
 case S390_IPL_TYPE_QEMU_SCSI:
 break;
 default:
-error_report("boot menu is not supported for this device type.");
+if (boot_menu) {
+error_report("boot menu is not supported for this device type");
+}
 return;
 }
 
@@ -263,13 +265,13 @@ static void s390_ipl_set_boot_menu(S390IPLState *ipl)
 tmp = qemu_opt_get(opts, "splash-time");
 
 if (tmp && qemu_strtoul(tmp, NULL, 10, _time)) {
-error_report("splash-time is invalid, forcing it to 0.");
+error_report("splash-time is invalid, forcing it to 0");
 *timeout = 0;
 return;
 }
 
 if (splash_time > 0x) {
-error_report("splash-time is too large, forcing it to max value.");
+error_report("splash-time is too large, forcing it to max value");
 *timeout = 0x;
 return;
 }
-- 
2.7.4




Re: [Qemu-devel] [PATCH] s390-ccw: only print boot menu error if -boot menu=on was specified

2018-02-27 Thread Collin L. Walling

On 02/27/2018 02:18 PM, Cornelia Huck wrote:

On Tue, 27 Feb 2018 10:19:20 -0500
"Collin L. Walling" <wall...@linux.vnet.ibm.com> wrote:

Nit: make the prefix s390x/ipl:, as this is not directly in the bios.


It is possible that certain QEMU configurations may not
create an IPLB (such as when -kernel is provided). In
this case, a misleading error message will be printed
stating that the "boot menu is not supported for this
device type".

To amend this, only print this message iff boot menu=on
was provided on the commandline. Otherwise, return silently.

Signed-off-by: Collin L. Walling <wall...@linux.vnet.ibm.com>
---
  hw/s390x/ipl.c | 4 +++-
  1 file changed, 3 insertions(+), 1 deletion(-)

diff --git a/hw/s390x/ipl.c b/hw/s390x/ipl.c
index 798e99a..c4addb5 100644
--- a/hw/s390x/ipl.c
+++ b/hw/s390x/ipl.c
@@ -250,7 +250,9 @@ static void s390_ipl_set_boot_menu(S390IPLState *ipl)
  case S390_IPL_TYPE_QEMU_SCSI:
  break;
  default:
-error_report("boot menu is not supported for this device type.");
+if (boot_menu) {
+error_report("boot menu is not supported for this device type.");
+}
  return;
  }
  

This change makes sense and works as I'd expect (although the message
is still slightly odd in the -kernel case, but I can't think of
anything better.)

Will you also do a followup removing the trailing punctuation? :)


You got it!

--
- Collin L Walling




[Qemu-devel] [PATCH] s390-ccw: only print boot menu error if -boot menu=on was specified

2018-02-27 Thread Collin L. Walling
It is possible that certain QEMU configurations may not
create an IPLB (such as when -kernel is provided). In
this case, a misleading error message will be printed
stating that the "boot menu is not supported for this
device type".

To amend this, only print this message iff boot menu=on
was provided on the commandline. Otherwise, return silently.

Signed-off-by: Collin L. Walling <wall...@linux.vnet.ibm.com>
---
 hw/s390x/ipl.c | 4 +++-
 1 file changed, 3 insertions(+), 1 deletion(-)

diff --git a/hw/s390x/ipl.c b/hw/s390x/ipl.c
index 798e99a..c4addb5 100644
--- a/hw/s390x/ipl.c
+++ b/hw/s390x/ipl.c
@@ -250,7 +250,9 @@ static void s390_ipl_set_boot_menu(S390IPLState *ipl)
 case S390_IPL_TYPE_QEMU_SCSI:
 break;
 default:
-error_report("boot menu is not supported for this device type.");
+if (boot_menu) {
+error_report("boot menu is not supported for this device type.");
+}
 return;
 }
 
-- 
2.7.4




Re: [Qemu-devel] [qemu-s390x] [PULL-for-s390x 06/14] s390-ccw: parse and set boot menu options

2018-02-27 Thread Collin L. Walling

On 02/27/2018 04:22 AM, Thomas Huth wrote:

On 27.02.2018 10:12, Cornelia Huck wrote:

On Mon, 26 Feb 2018 14:44:45 -0500
"Collin L. Walling" <wall...@linux.vnet.ibm.com> wrote:


On 02/26/2018 02:29 PM, Collin L. Walling wrote:

On 02/26/2018 01:48 PM, Cornelia Huck wrote:

On Mon, 26 Feb 2018 11:42:29 +0100
Thomas Huth <th...@redhat.com> wrote:

[...]

+    switch (ipl->iplb.pbt) {
+    case S390_IPL_TYPE_CCW:
+    break;
+    default:
+    error_report("boot menu is not supported for this device
type.");

If I specify both a bootindex for a device and a -kernel parameter, I
get this error message. Looks a tad odd, but not sure how to avoid it.

Hmm... perhaps an additional check if no IPLB, then skip trying to set
any boot menu data?

[...]

How shall we proceed? I'd be willing to pull this now and then apply
fixups on top, or we can have a respin. Thomas?

Since this is about a change in hw/s390x/ and not about
pc-bios/s390-ccw/ (i.e. no need to rebuild the firmware binaries for
this), I think I'd rather prefer a fix-up patch on top instead of a re-spin.

  Thomas


I'll get right on it and post to the qemu lists.

--
- Collin L Walling




Re: [Qemu-devel] [qemu-s390x] [PULL-for-s390x 06/14] s390-ccw: parse and set boot menu options

2018-02-26 Thread Collin L. Walling

On 02/26/2018 02:29 PM, Collin L. Walling wrote:

On 02/26/2018 01:48 PM, Cornelia Huck wrote:

On Mon, 26 Feb 2018 11:42:29 +0100
Thomas Huth <th...@redhat.com> wrote:

[...]


  3 files changed, 66 insertions(+), 4 deletions(-)
+static void s390_ipl_set_boot_menu(S390IPLState *ipl)
+{
+    QemuOptsList *plist = qemu_find_opts("boot-opts");
+    QemuOpts *opts = QTAILQ_FIRST(>head);
+    uint8_t *flags = >qipl.qipl_flags;
+    uint32_t *timeout = >qipl.boot_menu_timeout;
+    const char *tmp;
+    unsigned long splash_time = 0;
+
+    if (!get_boot_device(0)) {
+    if (boot_menu) {
+    error_report("boot menu requires a bootindex to be 
specified for "

+ "the IPL device.");
+    }
+    return;
+    }
+
+    switch (ipl->iplb.pbt) {
+    case S390_IPL_TYPE_CCW:
+    break;
+    default:
+    error_report("boot menu is not supported for this device 
type.");

If I specify both a bootindex for a device and a -kernel parameter, I
get this error message. Looks a tad odd, but not sure how to avoid it.


Hmm... perhaps an additional check if no IPLB, then skip trying to set
any boot menu data?


[...]




Something like:

    if (!ipl->iplb.len) {
    return;
    }

placed just below the if (!get_boot_device(0)) chunk fixed it for me.If 
no IPLB was set,
then the IPLB fields should just all be zeros.  Why not just check if 
the length is 0 to

determine that we did not set an IPLB at all?

also:

    if (!ipl->iplb.len) {
        if (boot_menu) {
            error_report("boot menu requires an IPLB to function");
        }
    return;
    }

if you think an error message is needed (use a better message, mine is 
not helpful but I
just wanted to demonstrate that the if (boot_menu) check should be 
nested first).


Thanks for reporting this.  Seems to be a few cases that I missed on my end.

--
- Collin L Walling



Re: [Qemu-devel] [qemu-s390x] [PULL-for-s390x 06/14] s390-ccw: parse and set boot menu options

2018-02-26 Thread Collin L. Walling

On 02/26/2018 01:48 PM, Cornelia Huck wrote:

On Mon, 26 Feb 2018 11:42:29 +0100
Thomas Huth <th...@redhat.com> wrote:


From: "Collin L. Walling" <wall...@linux.vnet.ibm.com>

Set boot menu options for an s390 guest and store them in
the iplb. These options are set via the QEMU command line
option:

 -boot menu=on|off[,splash-time=X]

or via the libvirt domain xml:

 
   
 

Where X represents some positive integer representing
milliseconds.

Any value set for loadparm will override all boot menu options.
If loadparm=PROMPT, then the menu will be enabled without a
timeout.

Signed-off-by: Collin L. Walling <wall...@linux.vnet.ibm.com>
Reviewed-by: Janosch Frank <fran...@linux.vnet.ibm.com>
Reviewed-by: Thomas Huth <th...@redhat.com>
Signed-off-by: Thomas Huth <th...@redhat.com>
---
  hw/s390x/ipl.c  | 52 +
  hw/s390x/ipl.h  |  9 +++--
  pc-bios/s390-ccw/iplb.h |  9 +++--

Updating the header, but it is not consumed in the bios?


  3 files changed, 66 insertions(+), 4 deletions(-)
+static void s390_ipl_set_boot_menu(S390IPLState *ipl)
+{
+QemuOptsList *plist = qemu_find_opts("boot-opts");
+QemuOpts *opts = QTAILQ_FIRST(>head);
+uint8_t *flags = >qipl.qipl_flags;
+uint32_t *timeout = >qipl.boot_menu_timeout;
+const char *tmp;
+unsigned long splash_time = 0;
+
+if (!get_boot_device(0)) {
+if (boot_menu) {
+error_report("boot menu requires a bootindex to be specified for "
+ "the IPL device.");
+}
+return;
+}
+
+switch (ipl->iplb.pbt) {
+case S390_IPL_TYPE_CCW:
+break;
+default:
+error_report("boot menu is not supported for this device type.");

If I specify both a bootindex for a device and a -kernel parameter, I
get this error message. Looks a tad odd, but not sure how to avoid it.


Hmm... perhaps an additional check if no IPLB, then skip trying to set
any boot menu data?


[...]



--
- Collin L Walling




Re: [Qemu-devel] [PATCH v9 05/13] s390-ccw: move auxiliary IPL data to separate location

2018-02-23 Thread Collin L. Walling

On 02/23/2018 11:03 AM, Thomas Huth wrote:

On 23.02.2018 16:43, Collin L. Walling wrote:

The s390-ccw firmware needs some information in support of the
boot process which is not available on the native machine.
Examples are the netboot firmware load address and now the
boot menu parameters.

While storing that data in unused fields of the IPL parameter block
works, that approach could create problems if the parameter block
definition should change in the future. Because then a guest could
overwrite these fields using the set IPLB diagnose.

In fact the data in question is of more global nature and not really
tied to an IPL device, so separating it is rather logical.

This commit introduces a new structure to hold firmware relevant
IPL parameters set by QEMU. The data is stored at location 204 (dec)
and can contain up to 7 32-bit words. This area is available to
programming in the z/Architecture Principles of Operation and
can thus safely be used by the firmware until the IPL has completed.

Signed-off-by: Viktor Mihajlovski <mihaj...@linux.vnet.ibm.com>
Signed-off-by: Collin L. Walling <wall...@linux.vnet.ibm.com>
Reviewed-by: Thomas Huth <th...@redhat.com>
---
  hw/s390x/ipl.c  | 18 +-
  hw/s390x/ipl.h  | 25 +++--
  pc-bios/s390-ccw/iplb.h | 18 --
  pc-bios/s390-ccw/main.c |  6 +-
  4 files changed, 61 insertions(+), 6 deletions(-)

diff --git a/hw/s390x/ipl.c b/hw/s390x/ipl.c
index 0d06fc1..79f5a58 100644
--- a/hw/s390x/ipl.c
+++ b/hw/s390x/ipl.c
@@ -399,6 +399,21 @@ void s390_reipl_request(void)
  qemu_system_reset_request(SHUTDOWN_CAUSE_GUEST_RESET);
  }
  
+static void s390_ipl_prepare_qipl(S390CPU *cpu)

+{
+S390IPLState *ipl = get_ipl_device();
+uint8_t *addr;
+uint64_t len = 4096;
+
+addr = cpu_physical_memory_map(cpu->env.psa, , 1);
+if (!addr || len < QIPL_ADDRESS + sizeof(QemuIplParameters)) {
+error_report("Cannot set QEMU IPL parameters");
+return;
+}
+memcpy(addr + QIPL_ADDRESS, >qipl, sizeof(QemuIplParameters));
+cpu_physical_memory_unmap(addr, len, 1, len);
+}
+
  void s390_ipl_prepare_cpu(S390CPU *cpu)
  {
  S390IPLState *ipl = get_ipl_device();
@@ -418,8 +433,9 @@ void s390_ipl_prepare_cpu(S390CPU *cpu)
  error_report_err(err);
  vm_stop(RUN_STATE_INTERNAL_ERROR);
  }
-ipl->iplb.ccw.netboot_start_addr = cpu_to_be64(ipl->start_addr);
+ipl->qipl.netboot_start_addr = cpu_to_be64(ipl->start_addr);
  }
+s390_ipl_prepare_qipl(cpu);
  }
  
  static void s390_ipl_reset(DeviceState *dev)

diff --git a/hw/s390x/ipl.h b/hw/s390x/ipl.h
index 8a705e0..08926a3 100644
--- a/hw/s390x/ipl.h
+++ b/hw/s390x/ipl.h
@@ -16,8 +16,7 @@
  #include "cpu.h"
  
  struct IplBlockCcw {

-uint64_t netboot_start_addr;
-uint8_t  reserved0[77];
+uint8_t  reserved0[85];
  uint8_t  ssid;
  uint16_t devno;
  uint8_t  vm_flags;
@@ -90,6 +89,27 @@ void s390_ipl_prepare_cpu(S390CPU *cpu);
  IplParameterBlock *s390_ipl_get_iplb(void);
  void s390_reipl_request(void);
  
+#define QIPL_ADDRESS  0xcc

+
+/*
+ * The QEMU IPL Parameters will be stored at absolute address
+ * 204 (0xcc) which means it is 32-bit word aligned but not
+ * double-word aligned.
+ * Placement of data fields in this area must account for
+ * their alignment needs. E.g., netboot_start_address must
+ * have an offset of n * 8 bytes within the struct in order

Please replace "n * 8" with "4 + n * 8" in your tree. I can fix it up
manually again, but in case we need a v10 ...

  Thomas

Fixed just in case (along with the missing break for 13/13). Thank you 
for reminding me.


--
- Collin L Walling




[Qemu-devel] [PATCH v9 09/13] s390-ccw: print zipl boot menu

2018-02-23 Thread Collin L. Walling
When the boot menu options are present and the guest's
disk has been configured by the zipl tool, then the user
will be presented with an interactive boot menu with
labeled entries. An example of what the menu might look
like:

zIPL v1.37.1-build-20170714 interactive boot menu.

0. default (linux-4.13.0)

  1. linux-4.13.0
  2. performance
  3. kvm

Signed-off-by: Collin L. Walling <wall...@linux.vnet.ibm.com>
Reviewed-by: Thomas Huth <th...@redhat.com>
---
 pc-bios/s390-ccw/menu.c | 33 -
 1 file changed, 32 insertions(+), 1 deletion(-)

diff --git a/pc-bios/s390-ccw/menu.c b/pc-bios/s390-ccw/menu.c
index c1d242f..730d44e 100644
--- a/pc-bios/s390-ccw/menu.c
+++ b/pc-bios/s390-ccw/menu.c
@@ -15,11 +15,42 @@
 static uint8_t flag;
 static uint64_t timeout;
 
-int menu_get_zipl_boot_index(const char *menu_data)
+static int get_boot_index(int entries)
 {
 return 0; /* implemented next patch */
 }
 
+static void zipl_println(const char *data, size_t len)
+{
+char buf[len + 2];
+
+ebcdic_to_ascii(data, buf, len);
+buf[len] = '\n';
+buf[len + 1] = '\0';
+
+sclp_print(buf);
+}
+
+int menu_get_zipl_boot_index(const char *menu_data)
+{
+size_t len;
+int entries;
+
+/* Print and count all menu items, including the banner */
+for (entries = 0; *menu_data; entries++) {
+len = strlen(menu_data);
+zipl_println(menu_data, len);
+menu_data += len + 1;
+
+if (entries < 2) {
+sclp_print("\n");
+}
+}
+
+sclp_print("\n");
+return get_boot_index(entries - 1); /* subtract 1 to exclude banner */
+}
+
 void menu_set_parms(uint8_t boot_menu_flag, uint32_t boot_menu_timeout)
 {
 flag = boot_menu_flag;
-- 
2.7.4




[Qemu-devel] [PATCH v9 12/13] s390-ccw: use zipl values when no boot menu options are present

2018-02-23 Thread Collin L. Walling
If no boot menu options are present, then flag the boot menu to
use the zipl options that were set in the zipl configuration file
(and stored on disk by zipl). These options are found at some
offset prior to the start of the zipl boot menu banner. The zipl
timeout value is limited to a 16-bit unsigned integer and stored
as seconds, so we take care to convert it to milliseconds in order
to conform to the rest of the boot menu functionality. This is
limited to CCW devices.

For reference, the zipl configuration file uses the following
fields in the menu section:

  prompt=1  enable the boot menu
  timeout=X set the timeout to X seconds

To explicitly disregard any boot menu options, then menu=off or
 must be specified.

Signed-off-by: Collin L. Walling <wall...@linux.vnet.ibm.com>
Reviewed-by: Thomas Huth <th...@redhat.com>
---
 hw/s390x/ipl.c  |  5 +
 hw/s390x/ipl.h  |  1 +
 pc-bios/s390-ccw/iplb.h |  1 +
 pc-bios/s390-ccw/main.c |  3 ++-
 pc-bios/s390-ccw/menu.c | 16 +++-
 5 files changed, 24 insertions(+), 2 deletions(-)

diff --git a/hw/s390x/ipl.c b/hw/s390x/ipl.c
index ee2039d..c12e460 100644
--- a/hw/s390x/ipl.c
+++ b/hw/s390x/ipl.c
@@ -241,6 +241,11 @@ static void s390_ipl_set_boot_menu(S390IPLState *ipl)
 
 switch (ipl->iplb.pbt) {
 case S390_IPL_TYPE_CCW:
+/* In the absence of -boot menu, use zipl parameters */
+if (!qemu_opt_get(opts, "menu")) {
+*flags |= QIPL_FLAG_BM_OPTS_ZIPL;
+return;
+}
 break;
 default:
 error_report("boot menu is not supported for this device type.");
diff --git a/hw/s390x/ipl.h b/hw/s390x/ipl.h
index 3a37924..1a8adc2 100644
--- a/hw/s390x/ipl.h
+++ b/hw/s390x/ipl.h
@@ -93,6 +93,7 @@ void s390_reipl_request(void);
 
 /* Boot Menu flags */
 #define QIPL_FLAG_BM_OPTS_CMD   0x80
+#define QIPL_FLAG_BM_OPTS_ZIPL  0x40
 
 /*
  * The QEMU IPL Parameters will be stored at absolute address
diff --git a/pc-bios/s390-ccw/iplb.h b/pc-bios/s390-ccw/iplb.h
index 832bb94..7dfce4f 100644
--- a/pc-bios/s390-ccw/iplb.h
+++ b/pc-bios/s390-ccw/iplb.h
@@ -76,6 +76,7 @@ extern IplParameterBlock iplb 
__attribute__((__aligned__(PAGE_SIZE)));
 
 /* Boot Menu flags */
 #define QIPL_FLAG_BM_OPTS_CMD   0x80
+#define QIPL_FLAG_BM_OPTS_ZIPL  0x40
 
 /*
  * This definition must be kept in sync with the defininition
diff --git a/pc-bios/s390-ccw/main.c b/pc-bios/s390-ccw/main.c
index 32ed70e..a7473b0 100644
--- a/pc-bios/s390-ccw/main.c
+++ b/pc-bios/s390-ccw/main.c
@@ -20,6 +20,7 @@ QemuIplParameters qipl;
 
 #define LOADPARM_PROMPT "PROMPT  "
 #define LOADPARM_EMPTY  ""
+#define BOOT_MENU_FLAG_MASK (QIPL_FLAG_BM_OPTS_CMD | QIPL_FLAG_BM_OPTS_ZIPL)
 
 /*
  * Priniciples of Operations (SA22-7832-09) chapter 17 requires that
@@ -91,7 +92,7 @@ static void menu_setup(void)
 
 switch (iplb.pbt) {
 case S390_IPL_TYPE_CCW:
-menu_set_parms(qipl.qipl_flags & QIPL_FLAG_BM_OPTS_CMD,
+menu_set_parms(qipl.qipl_flags & BOOT_MENU_FLAG_MASK,
qipl.boot_menu_timeout);
 return;
 }
diff --git a/pc-bios/s390-ccw/menu.c b/pc-bios/s390-ccw/menu.c
index 8d55869..ee56939 100644
--- a/pc-bios/s390-ccw/menu.c
+++ b/pc-bios/s390-ccw/menu.c
@@ -18,6 +18,10 @@
 #define KEYCODE_BACKSP '\177'
 #define KEYCODE_ENTER  '\r'
 
+/* Offsets from zipl fields to zipl banner start */
+#define ZIPL_TIMEOUT_OFFSET 138
+#define ZIPL_FLAG_OFFSET140
+
 #define TOD_CLOCK_MILLISECOND   0x3e8000
 
 #define LOW_CORE_EXTERNAL_INT_ADDR   0x86
@@ -187,6 +191,16 @@ int menu_get_zipl_boot_index(const char *menu_data)
 {
 size_t len;
 int entries;
+uint16_t zipl_flag = *(uint16_t *)(menu_data - ZIPL_FLAG_OFFSET);
+uint16_t zipl_timeout = *(uint16_t *)(menu_data - ZIPL_TIMEOUT_OFFSET);
+
+if (flag == QIPL_FLAG_BM_OPTS_ZIPL) {
+if (!zipl_flag) {
+return 0; /* Boot default */
+}
+/* zipl stores timeout as seconds */
+timeout = zipl_timeout * 1000;
+}
 
 /* Print and count all menu items, including the banner */
 for (entries = 0; *menu_data; entries++) {
@@ -211,5 +225,5 @@ void menu_set_parms(uint8_t boot_menu_flag, uint32_t 
boot_menu_timeout)
 
 bool menu_is_enabled_zipl(void)
 {
-return flag & QIPL_FLAG_BM_OPTS_CMD;
+return flag & (QIPL_FLAG_BM_OPTS_CMD | QIPL_FLAG_BM_OPTS_ZIPL);
 }
-- 
2.7.4




[Qemu-devel] [PATCH v9 13/13] s390-ccw: interactive boot menu for scsi

2018-02-23 Thread Collin L. Walling
Interactive boot menu for scsi. This follows a similar procedure
as the interactive menu for eckd dasd. An example follows:

s390x Enumerated Boot Menu.

3 entries detected. Select from index 0 to 2.

Signed-off-by: Collin L. Walling <wall...@linux.vnet.ibm.com>
Reviewed-by: Thomas Huth <th...@redhat.com>
---
 hw/s390x/ipl.c  |  1 +
 pc-bios/s390-ccw/bootmap.c  |  4 
 pc-bios/s390-ccw/main.c |  1 +
 pc-bios/s390-ccw/menu.c | 20 
 pc-bios/s390-ccw/s390-ccw.h |  2 ++
 5 files changed, 28 insertions(+)

diff --git a/hw/s390x/ipl.c b/hw/s390x/ipl.c
index c12e460..edbec90 100644
--- a/hw/s390x/ipl.c
+++ b/hw/s390x/ipl.c
@@ -246,6 +246,7 @@ static void s390_ipl_set_boot_menu(S390IPLState *ipl)
 *flags |= QIPL_FLAG_BM_OPTS_ZIPL;
 return;
 }
+case S390_IPL_TYPE_QEMU_SCSI:
 break;
 default:
 error_report("boot menu is not supported for this device type.");
diff --git a/pc-bios/s390-ccw/bootmap.c b/pc-bios/s390-ccw/bootmap.c
index ae93b55..29bfd8c 100644
--- a/pc-bios/s390-ccw/bootmap.c
+++ b/pc-bios/s390-ccw/bootmap.c
@@ -568,6 +568,10 @@ static void ipl_scsi(void)
 debug_print_int("program table entries", program_table_entries);
 IPL_assert(program_table_entries != 0, "Empty Program Table");
 
+if (menu_is_enabled_enum()) {
+loadparm = menu_get_enum_boot_index(program_table_entries);
+}
+
 debug_print_int("loadparm", loadparm);
 IPL_assert(loadparm <= MAX_TABLE_ENTRIES, "loadparm value greater than"
" maximum number of boot entries allowed");
diff --git a/pc-bios/s390-ccw/main.c b/pc-bios/s390-ccw/main.c
index a7473b0..9d9f8cf 100644
--- a/pc-bios/s390-ccw/main.c
+++ b/pc-bios/s390-ccw/main.c
@@ -92,6 +92,7 @@ static void menu_setup(void)
 
 switch (iplb.pbt) {
 case S390_IPL_TYPE_CCW:
+case S390_IPL_TYPE_QEMU_SCSI:
 menu_set_parms(qipl.qipl_flags & BOOT_MENU_FLAG_MASK,
qipl.boot_menu_timeout);
 return;
diff --git a/pc-bios/s390-ccw/menu.c b/pc-bios/s390-ccw/menu.c
index ee56939..96eec81 100644
--- a/pc-bios/s390-ccw/menu.c
+++ b/pc-bios/s390-ccw/menu.c
@@ -217,6 +217,21 @@ int menu_get_zipl_boot_index(const char *menu_data)
 return get_boot_index(entries - 1); /* subtract 1 to exclude banner */
 }
 
+
+int menu_get_enum_boot_index(int entries)
+{
+char tmp[4];
+
+sclp_print("s390x Enumerated Boot Menu.\n\n");
+
+sclp_print(uitoa(entries, tmp, sizeof(tmp)));
+sclp_print(" entries detected. Select from boot index 0 to ");
+sclp_print(uitoa(entries - 1, tmp, sizeof(tmp)));
+sclp_print(".\n\n");
+
+return get_boot_index(entries);
+}
+
 void menu_set_parms(uint8_t boot_menu_flag, uint32_t boot_menu_timeout)
 {
 flag = boot_menu_flag;
@@ -227,3 +242,8 @@ bool menu_is_enabled_zipl(void)
 {
 return flag & (QIPL_FLAG_BM_OPTS_CMD | QIPL_FLAG_BM_OPTS_ZIPL);
 }
+
+bool menu_is_enabled_enum(void)
+{
+return flag & QIPL_FLAG_BM_OPTS_CMD;
+}
diff --git a/pc-bios/s390-ccw/s390-ccw.h b/pc-bios/s390-ccw/s390-ccw.h
index c4ddf9f..fd18da2 100644
--- a/pc-bios/s390-ccw/s390-ccw.h
+++ b/pc-bios/s390-ccw/s390-ccw.h
@@ -91,6 +91,8 @@ void zipl_load(void);
 void menu_set_parms(uint8_t boot_menu_flag, uint32_t boot_menu_timeout);
 int menu_get_zipl_boot_index(const char *menu_data);
 bool menu_is_enabled_zipl(void);
+int menu_get_enum_boot_index(int entries);
+bool menu_is_enabled_enum(void);
 
 static inline void fill_hex(char *out, unsigned char val)
 {
-- 
2.7.4




[Qemu-devel] [PATCH v9 07/13] s390-ccw: set up interactive boot menu parameters

2018-02-23 Thread Collin L. Walling
Reads boot menu flag and timeout values from the iplb and
sets the respective fields for the menu.

Signed-off-by: Collin L. Walling <wall...@linux.vnet.ibm.com>
Reviewed-by: Thomas Huth <th...@redhat.com>
---
 pc-bios/s390-ccw/Makefile   |  2 +-
 pc-bios/s390-ccw/main.c | 24 
 pc-bios/s390-ccw/menu.c | 22 ++
 pc-bios/s390-ccw/s390-ccw.h |  3 +++
 4 files changed, 50 insertions(+), 1 deletion(-)
 create mode 100644 pc-bios/s390-ccw/menu.c

diff --git a/pc-bios/s390-ccw/Makefile b/pc-bios/s390-ccw/Makefile
index 9f7904f..1712c2d 100644
--- a/pc-bios/s390-ccw/Makefile
+++ b/pc-bios/s390-ccw/Makefile
@@ -9,7 +9,7 @@ $(call set-vpath, $(SRC_PATH)/pc-bios/s390-ccw)
 
 .PHONY : all clean build-all
 
-OBJECTS = start.o main.o bootmap.o sclp.o virtio.o virtio-scsi.o 
virtio-blkdev.o libc.o
+OBJECTS = start.o main.o bootmap.o sclp.o virtio.o virtio-scsi.o 
virtio-blkdev.o libc.o menu.o
 QEMU_CFLAGS := $(filter -W%, $(QEMU_CFLAGS))
 QEMU_CFLAGS += -ffreestanding -fno-delete-null-pointer-checks -msoft-float
 QEMU_CFLAGS += -march=z900 -fPIE -fno-strict-aliasing
diff --git a/pc-bios/s390-ccw/main.c b/pc-bios/s390-ccw/main.c
index e41b264..32ed70e 100644
--- a/pc-bios/s390-ccw/main.c
+++ b/pc-bios/s390-ccw/main.c
@@ -18,6 +18,9 @@ IplParameterBlock iplb 
__attribute__((__aligned__(PAGE_SIZE)));
 static char loadparm[8] = { 0, 0, 0, 0, 0, 0, 0, 0 };
 QemuIplParameters qipl;
 
+#define LOADPARM_PROMPT "PROMPT  "
+#define LOADPARM_EMPTY  ""
+
 /*
  * Priniciples of Operations (SA22-7832-09) chapter 17 requires that
  * a subsystem-identification is at 184-187 and bytes 188-191 are zero
@@ -74,6 +77,26 @@ static bool find_dev(Schib *schib, int dev_no)
 return false;
 }
 
+static void menu_setup(void)
+{
+if (memcmp(loadparm, LOADPARM_PROMPT, 8) == 0) {
+menu_set_parms(QIPL_FLAG_BM_OPTS_CMD, 0);
+return;
+}
+
+/* If loadparm was set to any other value, then do not enable menu */
+if (memcmp(loadparm, LOADPARM_EMPTY, 8) != 0) {
+return;
+}
+
+switch (iplb.pbt) {
+case S390_IPL_TYPE_CCW:
+menu_set_parms(qipl.qipl_flags & QIPL_FLAG_BM_OPTS_CMD,
+   qipl.boot_menu_timeout);
+return;
+}
+}
+
 static void virtio_setup(void)
 {
 Schib schib;
@@ -117,6 +140,7 @@ static void virtio_setup(void)
 default:
 panic("List-directed IPL not supported yet!\n");
 }
+menu_setup();
 } else {
 for (ssid = 0; ssid < 0x3; ssid++) {
 blk_schid.ssid = ssid;
diff --git a/pc-bios/s390-ccw/menu.c b/pc-bios/s390-ccw/menu.c
new file mode 100644
index 000..1ce33dd
--- /dev/null
+++ b/pc-bios/s390-ccw/menu.c
@@ -0,0 +1,22 @@
+/*
+ * QEMU S390 Interactive Boot Menu
+ *
+ * Copyright 2018 IBM Corp.
+ * Author: Collin L. Walling <wall...@linux.vnet.ibm.com>
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2 or (at
+ * your option) any later version. See the COPYING file in the top-level
+ * directory.
+ */
+
+#include "libc.h"
+#include "s390-ccw.h"
+
+static uint8_t flag;
+static uint64_t timeout;
+
+void menu_set_parms(uint8_t boot_menu_flag, uint32_t boot_menu_timeout)
+{
+flag = boot_menu_flag;
+timeout = boot_menu_timeout;
+}
diff --git a/pc-bios/s390-ccw/s390-ccw.h b/pc-bios/s390-ccw/s390-ccw.h
index 25d4d21..6cfd4b2 100644
--- a/pc-bios/s390-ccw/s390-ccw.h
+++ b/pc-bios/s390-ccw/s390-ccw.h
@@ -84,6 +84,9 @@ ulong get_second(void);
 /* bootmap.c */
 void zipl_load(void);
 
+/* menu.c */
+void menu_set_parms(uint8_t boot_menu_flag, uint32_t boot_menu_timeout);
+
 static inline void fill_hex(char *out, unsigned char val)
 {
 const char hex[] = "0123456789abcdef";
-- 
2.7.4




[Qemu-devel] [PATCH v9 10/13] s390-ccw: read user input for boot index via the SCLP console

2018-02-23 Thread Collin L. Walling
Implements an sclp_read function to capture input from the
console and a wrapper function that handles parsing certain
characters and adding input to a buffer. The input is checked
for any erroneous values and is handled appropriately.

A prompt will persist until input is entered or the timeout
expires (if one was set). Example:

  Please choose (default will boot in 10 seconds):

Correct input will boot the respective boot index. If the
user's input is empty, 0, or if the timeout expires, then
the default zipl entry will be chosen. If the input is
within the range of available boot entries, then the
selection will be booted. Any erroneous input will cancel
the timeout and re-prompt the user.

Signed-off-by: Collin L. Walling <wall...@linux.vnet.ibm.com>
Reviewed-by: Thomas Huth <th...@redhat.com>
---
 pc-bios/s390-ccw/menu.c | 149 +++-
 pc-bios/s390-ccw/s390-ccw.h |   2 +
 pc-bios/s390-ccw/sclp.c |  19 ++
 pc-bios/s390-ccw/virtio.c   |   2 +-
 4 files changed, 170 insertions(+), 2 deletions(-)

diff --git a/pc-bios/s390-ccw/menu.c b/pc-bios/s390-ccw/menu.c
index 730d44e..b99ff03 100644
--- a/pc-bios/s390-ccw/menu.c
+++ b/pc-bios/s390-ccw/menu.c
@@ -12,12 +12,159 @@
 #include "libc.h"
 #include "s390-ccw.h"
 
+#define KEYCODE_NO_INP '\0'
+#define KEYCODE_ESCAPE '\033'
+#define KEYCODE_BACKSP '\177'
+#define KEYCODE_ENTER  '\r'
+
+#define TOD_CLOCK_MILLISECOND   0x3e8000
+
+#define LOW_CORE_EXTERNAL_INT_ADDR   0x86
+#define CLOCK_COMPARATOR_INT 0X1004
+
 static uint8_t flag;
 static uint64_t timeout;
 
+static inline void enable_clock_int(void)
+{
+uint64_t tmp = 0;
+
+asm volatile(
+"stctg  0,0,%0\n"
+"oi 6+%0, 0x8\n"
+"lctlg  0,0,%0"
+: : "Q" (tmp) : "memory"
+);
+}
+
+static inline void disable_clock_int(void)
+{
+uint64_t tmp = 0;
+
+asm volatile(
+"stctg  0,0,%0\n"
+"ni 6+%0, 0xf7\n"
+"lctlg  0,0,%0"
+: : "Q" (tmp) : "memory"
+);
+}
+
+static inline void set_clock_comparator(uint64_t time)
+{
+asm volatile("sckc %0" : : "Q" (time));
+}
+
+static inline bool check_clock_int(void)
+{
+uint16_t *code = (uint16_t *)LOW_CORE_EXTERNAL_INT_ADDR;
+
+consume_sclp_int();
+
+return *code == CLOCK_COMPARATOR_INT;
+}
+
+static int read_prompt(char *buf, size_t len)
+{
+char inp[2] = {};
+uint8_t idx = 0;
+uint64_t time;
+
+if (timeout) {
+time = get_clock() + timeout * TOD_CLOCK_MILLISECOND;
+set_clock_comparator(time);
+enable_clock_int();
+timeout = 0;
+}
+
+while (!check_clock_int()) {
+
+sclp_read(inp, 1); /* Process only one character at a time */
+
+switch (inp[0]) {
+case KEYCODE_NO_INP:
+case KEYCODE_ESCAPE:
+continue;
+case KEYCODE_BACKSP:
+if (idx > 0) {
+buf[--idx] = 0;
+sclp_print("\b \b");
+}
+continue;
+case KEYCODE_ENTER:
+disable_clock_int();
+return idx;
+default:
+/* Echo input and add to buffer */
+if (idx < len) {
+buf[idx++] = inp[0];
+sclp_print(inp);
+}
+}
+}
+
+disable_clock_int();
+*buf = 0;
+
+return 0;
+}
+
+static int get_index(void)
+{
+char buf[11];
+int len;
+int i;
+
+memset(buf, 0, sizeof(buf));
+
+len = read_prompt(buf, sizeof(buf) - 1);
+
+/* If no input, boot default */
+if (len == 0) {
+return 0;
+}
+
+/* Check for erroneous input */
+for (i = 0; i < len; i++) {
+if (!isdigit(buf[i])) {
+return -1;
+}
+}
+
+return atoui(buf);
+}
+
+static void boot_menu_prompt(bool retry)
+{
+char tmp[11];
+
+if (retry) {
+sclp_print("\nError: undefined configuration"
+   "\nPlease choose:\n");
+} else if (timeout > 0) {
+sclp_print("Please choose (default will boot in ");
+sclp_print(uitoa(timeout / 1000, tmp, sizeof(tmp)));
+sclp_print(" seconds):\n");
+} else {
+sclp_print("Please choose:\n");
+}
+}
+
 static int get_boot_index(int entries)
 {
-return 0; /* implemented next patch */
+int boot_index;
+bool retry = false;
+char tmp[5];
+
+do {
+boot_menu_prompt(retry);
+boot_index = get_index();
+retry = true;
+} while (boot_index < 0 || boot_index >= entries);
+
+sclp_print("\nBooting entry #");
+sclp_print(uitoa(boot_index, tmp, sizeof(tmp)));
+
+return boot_index;
 }
 
 static void zipl_println(const char *data, size_t len)
diff --git a/

[Qemu-devel] [PATCH v9 06/13] s390-ccw: parse and set boot menu options

2018-02-23 Thread Collin L. Walling
Set boot menu options for an s390 guest and store them in
the iplb. These options are set via the QEMU command line
option:

-boot menu=on|off[,splash-time=X]

or via the libvirt domain xml:


  


Where X represents some positive integer representing
milliseconds.

Any value set for loadparm will override all boot menu options.
If loadparm=PROMPT, then the menu will be enabled without a
timeout.

Signed-off-by: Collin L. Walling <wall...@linux.vnet.ibm.com>
Reviewed-by: Janosch Frank <fran...@linux.vnet.ibm.com>
Reviewed-by: Thomas Huth <th...@redhat.com>
---
 hw/s390x/ipl.c  | 52 +
 hw/s390x/ipl.h  |  9 +++--
 pc-bios/s390-ccw/iplb.h |  9 +++--
 3 files changed, 66 insertions(+), 4 deletions(-)

diff --git a/hw/s390x/ipl.c b/hw/s390x/ipl.c
index 79f5a58..ee2039d 100644
--- a/hw/s390x/ipl.c
+++ b/hw/s390x/ipl.c
@@ -23,6 +23,9 @@
 #include "hw/s390x/ebcdic.h"
 #include "ipl.h"
 #include "qemu/error-report.h"
+#include "qemu/config-file.h"
+#include "qemu/cutils.h"
+#include "qemu/option.h"
 
 #define KERN_IMAGE_START0x01UL
 #define KERN_PARM_AREA  0x010480UL
@@ -219,6 +222,54 @@ static Property s390_ipl_properties[] = {
 DEFINE_PROP_END_OF_LIST(),
 };
 
+static void s390_ipl_set_boot_menu(S390IPLState *ipl)
+{
+QemuOptsList *plist = qemu_find_opts("boot-opts");
+QemuOpts *opts = QTAILQ_FIRST(>head);
+uint8_t *flags = >qipl.qipl_flags;
+uint32_t *timeout = >qipl.boot_menu_timeout;
+const char *tmp;
+unsigned long splash_time = 0;
+
+if (!get_boot_device(0)) {
+if (boot_menu) {
+error_report("boot menu requires a bootindex to be specified for "
+ "the IPL device.");
+}
+return;
+}
+
+switch (ipl->iplb.pbt) {
+case S390_IPL_TYPE_CCW:
+break;
+default:
+error_report("boot menu is not supported for this device type.");
+return;
+}
+
+if (!boot_menu) {
+return;
+}
+
+*flags |= QIPL_FLAG_BM_OPTS_CMD;
+
+tmp = qemu_opt_get(opts, "splash-time");
+
+if (tmp && qemu_strtoul(tmp, NULL, 10, _time)) {
+error_report("splash-time is invalid, forcing it to 0.");
+*timeout = 0;
+return;
+}
+
+if (splash_time > 0x) {
+error_report("splash-time is too large, forcing it to max value.");
+*timeout = 0x;
+return;
+}
+
+*timeout = cpu_to_be32(splash_time);
+}
+
 static bool s390_gen_initial_iplb(S390IPLState *ipl)
 {
 DeviceState *dev_st;
@@ -435,6 +486,7 @@ void s390_ipl_prepare_cpu(S390CPU *cpu)
 }
 ipl->qipl.netboot_start_addr = cpu_to_be64(ipl->start_addr);
 }
+s390_ipl_set_boot_menu(ipl);
 s390_ipl_prepare_qipl(cpu);
 }
 
diff --git a/hw/s390x/ipl.h b/hw/s390x/ipl.h
index 08926a3..3a37924 100644
--- a/hw/s390x/ipl.h
+++ b/hw/s390x/ipl.h
@@ -91,6 +91,9 @@ void s390_reipl_request(void);
 
 #define QIPL_ADDRESS  0xcc
 
+/* Boot Menu flags */
+#define QIPL_FLAG_BM_OPTS_CMD   0x80
+
 /*
  * The QEMU IPL Parameters will be stored at absolute address
  * 204 (0xcc) which means it is 32-bit word aligned but not
@@ -104,9 +107,11 @@ void s390_reipl_request(void);
  * in pc-bios/s390-ccw/iplb.h.
  */
 struct QemuIplParameters {
-uint8_t  reserved1[4];
+uint8_t  qipl_flags;
+uint8_t  reserved1[3];
 uint64_t netboot_start_addr;
-uint8_t  reserved2[16];
+uint32_t boot_menu_timeout;
+uint8_t  reserved2[12];
 } QEMU_PACKED;
 typedef struct QemuIplParameters QemuIplParameters;
 
diff --git a/pc-bios/s390-ccw/iplb.h b/pc-bios/s390-ccw/iplb.h
index 31d2934..832bb94 100644
--- a/pc-bios/s390-ccw/iplb.h
+++ b/pc-bios/s390-ccw/iplb.h
@@ -74,14 +74,19 @@ extern IplParameterBlock iplb 
__attribute__((__aligned__(PAGE_SIZE)));
 
 #define QIPL_ADDRESS  0xcc
 
+/* Boot Menu flags */
+#define QIPL_FLAG_BM_OPTS_CMD   0x80
+
 /*
  * This definition must be kept in sync with the defininition
  * in hw/s390x/ipl.h
  */
 struct QemuIplParameters {
-uint8_t  reserved1[4];
+uint8_t  qipl_flags;
+uint8_t  reserved1[3];
 uint64_t netboot_start_addr;
-uint8_t  reserved2[16];
+uint32_t boot_menu_timeout;
+uint8_t  reserved2[12];
 } __attribute__ ((packed));
 typedef struct QemuIplParameters QemuIplParameters;
 
-- 
2.7.4




[Qemu-devel] [PATCH v9 11/13] s390-ccw: set cp_receive mask only when needed and consume pending service irqs

2018-02-23 Thread Collin L. Walling
It is possible while waiting for multiple types of external
interrupts that we might have pending irqs remaining between
irq consumption and irq-type disabling. Those interrupts
could potentially propagate to the guest after IPL completes
and cause unwanted behavior.

As it is today, the SCLP will only recognize write events that
are enabled by the control program's send and receive masks. To
limit the window for, and prevent further irqs from, ASCII
console events (specifically keystrokes), we should only enable
the control program's receive mask when we need it.

While we're at it, remove assignment of the (non control program)
send and receive masks, as those are actually set by the SCLP.

Signed-off-by: Collin L. Walling <wall...@linux.vnet.ibm.com>
Reviewed-by: Thomas Huth <th...@redhat.com>
---
 pc-bios/s390-ccw/menu.c |  5 +
 pc-bios/s390-ccw/s390-ccw.h |  1 +
 pc-bios/s390-ccw/sclp.c | 10 --
 3 files changed, 10 insertions(+), 6 deletions(-)

diff --git a/pc-bios/s390-ccw/menu.c b/pc-bios/s390-ccw/menu.c
index b99ff03..8d55869 100644
--- a/pc-bios/s390-ccw/menu.c
+++ b/pc-bios/s390-ccw/menu.c
@@ -11,6 +11,7 @@
 
 #include "libc.h"
 #include "s390-ccw.h"
+#include "sclp.h"
 
 #define KEYCODE_NO_INP '\0'
 #define KEYCODE_ESCAPE '\033'
@@ -116,8 +117,12 @@ static int get_index(void)
 
 memset(buf, 0, sizeof(buf));
 
+sclp_set_write_mask(SCLP_EVENT_MASK_MSG_ASCII, SCLP_EVENT_MASK_MSG_ASCII);
+
 len = read_prompt(buf, sizeof(buf) - 1);
 
+sclp_set_write_mask(0, SCLP_EVENT_MASK_MSG_ASCII);
+
 /* If no input, boot default */
 if (len == 0) {
 return 0;
diff --git a/pc-bios/s390-ccw/s390-ccw.h b/pc-bios/s390-ccw/s390-ccw.h
index aeba8b0..c4ddf9f 100644
--- a/pc-bios/s390-ccw/s390-ccw.h
+++ b/pc-bios/s390-ccw/s390-ccw.h
@@ -69,6 +69,7 @@ unsigned int get_loadparm_index(void);
 
 /* sclp.c */
 void sclp_print(const char *string);
+void sclp_set_write_mask(uint32_t receive_mask, uint32_t send_mask);
 void sclp_setup(void);
 void sclp_get_loadparm_ascii(char *loadparm);
 int sclp_read(char *str, size_t count);
diff --git a/pc-bios/s390-ccw/sclp.c b/pc-bios/s390-ccw/sclp.c
index a2f25eb..3836cb4 100644
--- a/pc-bios/s390-ccw/sclp.c
+++ b/pc-bios/s390-ccw/sclp.c
@@ -46,23 +46,21 @@ static int sclp_service_call(unsigned int command, void 
*sccb)
 return 0;
 }
 
-static void sclp_set_write_mask(void)
+void sclp_set_write_mask(uint32_t receive_mask, uint32_t send_mask)
 {
 WriteEventMask *sccb = (void *)_sccb;
 
 sccb->h.length = sizeof(WriteEventMask);
 sccb->mask_length = sizeof(unsigned int);
-sccb->receive_mask = SCLP_EVENT_MASK_MSG_ASCII;
-sccb->cp_receive_mask = SCLP_EVENT_MASK_MSG_ASCII;
-sccb->send_mask = SCLP_EVENT_MASK_MSG_ASCII;
-sccb->cp_send_mask = SCLP_EVENT_MASK_MSG_ASCII;
+sccb->cp_receive_mask = receive_mask;
+sccb->cp_send_mask = send_mask;
 
 sclp_service_call(SCLP_CMD_WRITE_EVENT_MASK, sccb);
 }
 
 void sclp_setup(void)
 {
-sclp_set_write_mask();
+sclp_set_write_mask(0, SCLP_EVENT_MASK_MSG_ASCII);
 }
 
 long write(int fd, const void *str, size_t len)
-- 
2.7.4




[Qemu-devel] [PATCH v9 01/13] s390-ccw: refactor boot map table code

2018-02-23 Thread Collin L. Walling
Some ECKD bootmap code was using structs designed for SCSI.
Even though this works, it confuses readability. Add a new
BootMapTable struct to assist with readability in bootmap
entry code. Also:

- replace ScsiMbr in ECKD code with appropriate structs
- fix read_block messages to reflect BootMapTable
- fixup ipl_scsi to use BootMapTable (referred to as Program Table)
- defined value for maximum table entries

Signed-off-by: Collin L. Walling <wall...@linux.vnet.ibm.com>
Reviewed-by: Thomas Huth <th...@redhat.com>
---
 pc-bios/s390-ccw/bootmap.c | 60 +-
 pc-bios/s390-ccw/bootmap.h | 11 -
 2 files changed, 37 insertions(+), 34 deletions(-)

diff --git a/pc-bios/s390-ccw/bootmap.c b/pc-bios/s390-ccw/bootmap.c
index 67a6123..a4eaf24 100644
--- a/pc-bios/s390-ccw/bootmap.c
+++ b/pc-bios/s390-ccw/bootmap.c
@@ -182,24 +182,24 @@ static block_number_t load_eckd_segments(block_number_t 
blk, uint64_t *address)
 return block_nr;
 }
 
-static void run_eckd_boot_script(block_number_t mbr_block_nr)
+static void run_eckd_boot_script(block_number_t bmt_block_nr)
 {
 int i;
 unsigned int loadparm = get_loadparm_index();
 block_number_t block_nr;
 uint64_t address;
-ScsiMbr *bte = (void *)sec; /* Eckd bootmap table entry */
+BootMapTable *bmt = (void *)sec;
 BootMapScript *bms = (void *)sec;
 
 debug_print_int("loadparm", loadparm);
-IPL_assert(loadparm < 31, "loadparm value greater than"
+IPL_assert(loadparm <= MAX_TABLE_ENTRIES, "loadparm value greater than"
" maximum number of boot entries allowed");
 
 memset(sec, FREE_SPACE_FILLER, sizeof(sec));
-read_block(mbr_block_nr, sec, "Cannot read MBR");
+read_block(bmt_block_nr, sec, "Cannot read Boot Map Table");
 
-block_nr = eckd_block_num((void *)&(bte->blockptr[loadparm]));
-IPL_assert(block_nr != -1, "No Boot Map");
+block_nr = eckd_block_num(>entry[loadparm]);
+IPL_assert(block_nr != -1, "Cannot find Boot Map Table Entry");
 
 memset(sec, FREE_SPACE_FILLER, sizeof(sec));
 read_block(block_nr, sec, "Cannot read Boot Map Script");
@@ -223,7 +223,7 @@ static void ipl_eckd_cdl(void)
 XEckdMbr *mbr;
 Ipl2 *ipl2 = (void *)sec;
 IplVolumeLabel *vlbl = (void *)sec;
-block_number_t block_nr;
+block_number_t bmt_block_nr;
 
 /* we have just read the block #0 and recognized it as "IPL1" */
 sclp_print("CDL\n");
@@ -238,8 +238,8 @@ static void ipl_eckd_cdl(void)
 IPL_assert(mbr->dev_type == DEV_TYPE_ECKD,
"Non-ECKD device type in zIPL section of IPL2 record.");
 
-/* save pointer to Boot Script */
-block_nr = eckd_block_num((void *)&(mbr->blockptr));
+/* save pointer to Boot Map Table */
+bmt_block_nr = eckd_block_num(>blockptr);
 
 memset(sec, FREE_SPACE_FILLER, sizeof(sec));
 read_block(2, vlbl, "Cannot read Volume Label at block 2");
@@ -249,7 +249,7 @@ static void ipl_eckd_cdl(void)
"Invalid magic of volser block");
 print_volser(vlbl->f.volser);
 
-run_eckd_boot_script(block_nr);
+run_eckd_boot_script(bmt_block_nr);
 /* no return */
 }
 
@@ -280,7 +280,7 @@ static void print_eckd_ldl_msg(ECKD_IPL_mode_t mode)
 
 static void ipl_eckd_ldl(ECKD_IPL_mode_t mode)
 {
-block_number_t block_nr;
+block_number_t bmt_block_nr;
 BootInfo *bip = (void *)(sec + 0x70); /* BootInfo is MBR for LDL */
 
 if (mode != ECKD_LDL_UNLABELED) {
@@ -299,8 +299,10 @@ static void ipl_eckd_ldl(ECKD_IPL_mode_t mode)
 }
 verify_boot_info(bip);
 
-block_nr = eckd_block_num((void *)&(bip->bp.ipl.bm_ptr.eckd.bptr));
-run_eckd_boot_script(block_nr);
+/* save pointer to Boot Map Table */
+bmt_block_nr = eckd_block_num((void *)>bp.ipl.bm_ptr.eckd.bptr);
+
+run_eckd_boot_script(bmt_block_nr);
 /* no return */
 }
 
@@ -325,7 +327,7 @@ static void print_eckd_msg(void)
 
 static void ipl_eckd(void)
 {
-ScsiMbr *mbr = (void *)sec;
+XEckdMbr *mbr = (void *)sec;
 LDL_VTOC *vlbl = (void *)sec;
 
 print_eckd_msg();
@@ -449,10 +451,8 @@ static void zipl_run(ScsiBlockPtr *pte)
 static void ipl_scsi(void)
 {
 ScsiMbr *mbr = (void *)sec;
-uint8_t *ns, *ns_end;
 int program_table_entries = 0;
-const int pte_len = sizeof(ScsiBlockPtr);
-ScsiBlockPtr *prog_table_entry = NULL;
+BootMapTable *prog_table = (void *)sec;
 unsigned int loadparm = get_loadparm_index();
 
 /* Grab the MBR */
@@ -467,34 +467,28 @@ static void ipl_scsi(void)
 debug_print_int("MBR Version", mbr->version_id);
 IPL_check(mbr->version_id == 1,
   "Unknown MBR layout version, assuming version 1");
-debug_print_int("program table", mbr->blockptr[0].blockno);
-I

[Qemu-devel] [PATCH v9 08/13] s390-ccw: read stage2 boot loader data to find menu

2018-02-23 Thread Collin L. Walling
Read the stage2 boot loader data block-by-block. We scan the
current block for the string "zIPL" to detect the start of the
boot menu banner. We then load the adjacent blocks (previous
block and next block) to account for the possibility of menu
data spanning multiple blocks.

Signed-off-by: Collin L. Walling <wall...@linux.vnet.ibm.com>
Reviewed-by: Thomas Huth <th...@redhat.com>
---
 pc-bios/s390-ccw/bootmap.c  | 94 ++---
 pc-bios/s390-ccw/bootmap.h  | 23 ++-
 pc-bios/s390-ccw/menu.c | 10 +
 pc-bios/s390-ccw/s390-ccw.h |  2 +
 4 files changed, 122 insertions(+), 7 deletions(-)

diff --git a/pc-bios/s390-ccw/bootmap.c b/pc-bios/s390-ccw/bootmap.c
index 092fb35..ae93b55 100644
--- a/pc-bios/s390-ccw/bootmap.c
+++ b/pc-bios/s390-ccw/bootmap.c
@@ -83,6 +83,10 @@ static void jump_to_IPL_code(uint64_t address)
 
 static unsigned char _bprs[8*1024]; /* guessed "max" ECKD sector size */
 static const int max_bprs_entries = sizeof(_bprs) / sizeof(ExtEckdBlockPtr);
+static uint8_t _s2[MAX_SECTOR_SIZE * 3] 
__attribute__((__aligned__(PAGE_SIZE)));
+static void *s2_prev_blk = _s2;
+static void *s2_cur_blk = _s2 + MAX_SECTOR_SIZE;
+static void *s2_next_blk = _s2 + MAX_SECTOR_SIZE * 2;
 
 static inline void verify_boot_info(BootInfo *bip)
 {
@@ -182,7 +186,77 @@ static block_number_t load_eckd_segments(block_number_t 
blk, uint64_t *address)
 return block_nr;
 }
 
-static void run_eckd_boot_script(block_number_t bmt_block_nr)
+static bool find_zipl_boot_menu_banner(int *offset)
+{
+int i;
+
+/* Menu banner starts with "zIPL" */
+for (i = 0; i < virtio_get_block_size() - 4; i++) {
+if (magic_match(s2_cur_blk + i, ZIPL_MAGIC_EBCDIC)) {
+*offset = i;
+return true;
+}
+}
+
+return false;
+}
+
+static int eckd_get_boot_menu_index(block_number_t s1b_block_nr)
+{
+block_number_t cur_block_nr;
+block_number_t prev_block_nr = 0;
+block_number_t next_block_nr = 0;
+EckdStage1b *s1b = (void *)sec;
+int banner_offset;
+int i;
+
+/* Get Stage1b data */
+memset(sec, FREE_SPACE_FILLER, sizeof(sec));
+read_block(s1b_block_nr, s1b, "Cannot read stage1b boot loader");
+
+memset(_s2, FREE_SPACE_FILLER, sizeof(_s2));
+
+/* Get Stage2 data */
+for (i = 0; i < STAGE2_BLK_CNT_MAX; i++) {
+cur_block_nr = eckd_block_num(>seek[i].chs);
+
+if (!cur_block_nr) {
+break;
+}
+
+read_block(cur_block_nr, s2_cur_blk, "Cannot read stage2 boot loader");
+
+if (find_zipl_boot_menu_banner(_offset)) {
+/*
+ * Load the adjacent blocks to account for the
+ * possibility of menu data spanning multiple blocks.
+ */
+if (prev_block_nr) {
+read_block(prev_block_nr, s2_prev_blk,
+   "Cannot read stage2 boot loader");
+}
+
+if (i + 1 < STAGE2_BLK_CNT_MAX) {
+next_block_nr = eckd_block_num(>seek[i + 1].chs);
+}
+
+if (next_block_nr) {
+read_block(next_block_nr, s2_next_blk,
+   "Cannot read stage2 boot loader");
+}
+
+return menu_get_zipl_boot_index(s2_cur_blk + banner_offset);
+}
+
+prev_block_nr = cur_block_nr;
+}
+
+sclp_print("No zipl boot menu data found. Booting default entry.");
+return 0;
+}
+
+static void run_eckd_boot_script(block_number_t bmt_block_nr,
+ block_number_t s1b_block_nr)
 {
 int i;
 unsigned int loadparm = get_loadparm_index();
@@ -191,6 +265,10 @@ static void run_eckd_boot_script(block_number_t 
bmt_block_nr)
 BootMapTable *bmt = (void *)sec;
 BootMapScript *bms = (void *)sec;
 
+if (menu_is_enabled_zipl()) {
+loadparm = eckd_get_boot_menu_index(s1b_block_nr);
+}
+
 debug_print_int("loadparm", loadparm);
 IPL_assert(loadparm <= MAX_TABLE_ENTRIES, "loadparm value greater than"
" maximum number of boot entries allowed");
@@ -223,7 +301,7 @@ static void ipl_eckd_cdl(void)
 XEckdMbr *mbr;
 EckdCdlIpl2 *ipl2 = (void *)sec;
 IplVolumeLabel *vlbl = (void *)sec;
-block_number_t bmt_block_nr;
+block_number_t bmt_block_nr, s1b_block_nr;
 
 /* we have just read the block #0 and recognized it as "IPL1" */
 sclp_print("CDL\n");
@@ -241,6 +319,9 @@ static void ipl_eckd_cdl(void)
 /* save pointer to Boot Map Table */
 bmt_block_nr = eckd_block_num(>blockptr.xeckd.bptr.chs);
 
+/* save pointer to Stage1b Data */
+s1b_block_nr = eckd_block_num(>stage1.seek[0].chs);
+
 memset(sec, FREE_SPACE_FILLER, sizeof(sec));
 read_block(2, vlbl, "Cannot read Volume Label at block 2");

[Qemu-devel] [PATCH v9 05/13] s390-ccw: move auxiliary IPL data to separate location

2018-02-23 Thread Collin L. Walling
The s390-ccw firmware needs some information in support of the
boot process which is not available on the native machine.
Examples are the netboot firmware load address and now the
boot menu parameters.

While storing that data in unused fields of the IPL parameter block
works, that approach could create problems if the parameter block
definition should change in the future. Because then a guest could
overwrite these fields using the set IPLB diagnose.

In fact the data in question is of more global nature and not really
tied to an IPL device, so separating it is rather logical.

This commit introduces a new structure to hold firmware relevant
IPL parameters set by QEMU. The data is stored at location 204 (dec)
and can contain up to 7 32-bit words. This area is available to
programming in the z/Architecture Principles of Operation and
can thus safely be used by the firmware until the IPL has completed.

Signed-off-by: Viktor Mihajlovski <mihaj...@linux.vnet.ibm.com>
Signed-off-by: Collin L. Walling <wall...@linux.vnet.ibm.com>
Reviewed-by: Thomas Huth <th...@redhat.com>
---
 hw/s390x/ipl.c  | 18 +-
 hw/s390x/ipl.h  | 25 +++--
 pc-bios/s390-ccw/iplb.h | 18 --
 pc-bios/s390-ccw/main.c |  6 +-
 4 files changed, 61 insertions(+), 6 deletions(-)

diff --git a/hw/s390x/ipl.c b/hw/s390x/ipl.c
index 0d06fc1..79f5a58 100644
--- a/hw/s390x/ipl.c
+++ b/hw/s390x/ipl.c
@@ -399,6 +399,21 @@ void s390_reipl_request(void)
 qemu_system_reset_request(SHUTDOWN_CAUSE_GUEST_RESET);
 }
 
+static void s390_ipl_prepare_qipl(S390CPU *cpu)
+{
+S390IPLState *ipl = get_ipl_device();
+uint8_t *addr;
+uint64_t len = 4096;
+
+addr = cpu_physical_memory_map(cpu->env.psa, , 1);
+if (!addr || len < QIPL_ADDRESS + sizeof(QemuIplParameters)) {
+error_report("Cannot set QEMU IPL parameters");
+return;
+}
+memcpy(addr + QIPL_ADDRESS, >qipl, sizeof(QemuIplParameters));
+cpu_physical_memory_unmap(addr, len, 1, len);
+}
+
 void s390_ipl_prepare_cpu(S390CPU *cpu)
 {
 S390IPLState *ipl = get_ipl_device();
@@ -418,8 +433,9 @@ void s390_ipl_prepare_cpu(S390CPU *cpu)
 error_report_err(err);
 vm_stop(RUN_STATE_INTERNAL_ERROR);
 }
-ipl->iplb.ccw.netboot_start_addr = cpu_to_be64(ipl->start_addr);
+ipl->qipl.netboot_start_addr = cpu_to_be64(ipl->start_addr);
 }
+s390_ipl_prepare_qipl(cpu);
 }
 
 static void s390_ipl_reset(DeviceState *dev)
diff --git a/hw/s390x/ipl.h b/hw/s390x/ipl.h
index 8a705e0..08926a3 100644
--- a/hw/s390x/ipl.h
+++ b/hw/s390x/ipl.h
@@ -16,8 +16,7 @@
 #include "cpu.h"
 
 struct IplBlockCcw {
-uint64_t netboot_start_addr;
-uint8_t  reserved0[77];
+uint8_t  reserved0[85];
 uint8_t  ssid;
 uint16_t devno;
 uint8_t  vm_flags;
@@ -90,6 +89,27 @@ void s390_ipl_prepare_cpu(S390CPU *cpu);
 IplParameterBlock *s390_ipl_get_iplb(void);
 void s390_reipl_request(void);
 
+#define QIPL_ADDRESS  0xcc
+
+/*
+ * The QEMU IPL Parameters will be stored at absolute address
+ * 204 (0xcc) which means it is 32-bit word aligned but not
+ * double-word aligned.
+ * Placement of data fields in this area must account for
+ * their alignment needs. E.g., netboot_start_address must
+ * have an offset of n * 8 bytes within the struct in order
+ * to keep it double-word aligned.
+ * The total size of the struct must never exceed 28 bytes.
+ * This definition must be kept in sync with the defininition
+ * in pc-bios/s390-ccw/iplb.h.
+ */
+struct QemuIplParameters {
+uint8_t  reserved1[4];
+uint64_t netboot_start_addr;
+uint8_t  reserved2[16];
+} QEMU_PACKED;
+typedef struct QemuIplParameters QemuIplParameters;
+
 #define TYPE_S390_IPL "s390-ipl"
 #define S390_IPL(obj) OBJECT_CHECK(S390IPLState, (obj), TYPE_S390_IPL)
 
@@ -105,6 +125,7 @@ struct S390IPLState {
 bool iplb_valid;
 bool reipl_requested;
 bool netboot;
+QemuIplParameters qipl;
 
 /*< public >*/
 char *kernel;
diff --git a/pc-bios/s390-ccw/iplb.h b/pc-bios/s390-ccw/iplb.h
index 890aed9..31d2934 100644
--- a/pc-bios/s390-ccw/iplb.h
+++ b/pc-bios/s390-ccw/iplb.h
@@ -13,8 +13,7 @@
 #define IPLB_H
 
 struct IplBlockCcw {
-uint64_t netboot_start_addr;
-uint8_t  reserved0[77];
+uint8_t  reserved0[85];
 uint8_t  ssid;
 uint16_t devno;
 uint8_t  vm_flags;
@@ -73,6 +72,21 @@ typedef struct IplParameterBlock IplParameterBlock;
 
 extern IplParameterBlock iplb __attribute__((__aligned__(PAGE_SIZE)));
 
+#define QIPL_ADDRESS  0xcc
+
+/*
+ * This definition must be kept in sync with the defininition
+ * in hw/s390x/ipl.h
+ */
+struct QemuIplParameters {
+uint8_t  reserved1[4];
+uint64_t netboot_start_addr;
+uint8_t  reserved2[16];
+} __attribute__ ((packed));
+typedef struct QemuIplParameters QemuIplParameters;
+
+extern QemuIplParameters qipl;

[Qemu-devel] [PATCH v9 00/13] Interactive Boot Menu for DASD and SCSI Guests on s390x

2018-02-23 Thread Collin L. Walling
--- [v9] ---

 - only set boot menu opts if a bootindex was specified on cmd

 - Menus for guests with an IPL device that chooses to use the SCSI scheme are
   only enabled explicitly for -boot menu=on options (i.e. it will appropriately
   and cleanly ignore the zipl flag)

--- [Summary] ---

These patches implement a boot menu for ECKD DASD and SCSI guests on s390x. 
The menu will only appear if the disk has been configured for IPL with the 
zIPL tool and with the following QEMU command line options:

-boot menu=on[,splash-time=X] and/or -machine loadparm='prompt'

The following must be specified for the device to be IPL'd from:

-device ...,bootindex=1

or via the following libvirt domain xml:


  


or


  ...
  


Where X is some positive integer representing time in milliseconds.

 must be specified for the device to be IPL'd from

A loadparm other than 'prompt' will disable the menu and just boot 
the specified entry.

If no boot options are specified, we will attempt to use the values
provided by zipl (ECKD DASD only).

Collin L. Walling (13):
  s390-ccw: refactor boot map table code
  s390-ccw: refactor eckd_block_num to use CHS
  s390-ccw: refactor IPL structs
  s390-ccw: update libc
  s390-ccw: move auxiliary IPL data to separate location
  s390-ccw: parse and set boot menu options
  s390-ccw: set up interactive boot menu parameters
  s390-ccw: read stage2 boot loader data to find menu
  s390-ccw: print zipl boot menu
  s390-ccw: read user input for boot index via the SCLP console
  s390-ccw: set cp_receive mask only when needed and consume pending
service irqs
  s390-ccw: use zipl values when no boot menu options are present
  s390-ccw: interactive boot menu for scsi

 hw/s390x/ipl.c  |  76 +-
 hw/s390x/ipl.h  |  31 +-
 pc-bios/s390-ccw/Makefile   |   2 +-
 pc-bios/s390-ccw/bootmap.c  | 184 +++-
 pc-bios/s390-ccw/bootmap.h  |  91 ++--
 pc-bios/s390-ccw/iplb.h |  24 -
 pc-bios/s390-ccw/libc.c |  88 
 pc-bios/s390-ccw/libc.h |  37 ++-
 pc-bios/s390-ccw/main.c |  49 ++---
 pc-bios/s390-ccw/menu.c | 249 
 pc-bios/s390-ccw/s390-ccw.h |  10 ++
 pc-bios/s390-ccw/sclp.c |  39 ---
 pc-bios/s390-ccw/virtio.c   |   2 +-
 13 files changed, 756 insertions(+), 126 deletions(-)
 create mode 100644 pc-bios/s390-ccw/libc.c
 create mode 100644 pc-bios/s390-ccw/menu.c

-- 
2.7.4




[Qemu-devel] [PATCH v9 04/13] s390-ccw: update libc

2018-02-23 Thread Collin L. Walling
Moved:
  memcmp from bootmap.h to libc.h (renamed from _memcmp)
  strlen from sclp.c to libc.h (renamed from _strlen)

Added C standard functions:
  isdigit

Added non C-standard function:
  uitoa
  atoui

Signed-off-by: Collin L. Walling <wall...@linux.vnet.ibm.com>
Acked-by: Christian Borntraeger <borntrae...@de.ibm.com>
Reviewed-by: Janosch Frank <fran...@linux.vnet.ibm.com>
Reviewed-by: Thomas Huth <th...@redhat.com>
---
 pc-bios/s390-ccw/Makefile  |  2 +-
 pc-bios/s390-ccw/bootmap.c |  4 +--
 pc-bios/s390-ccw/bootmap.h | 16 +
 pc-bios/s390-ccw/libc.c| 88 ++
 pc-bios/s390-ccw/libc.h| 37 +--
 pc-bios/s390-ccw/main.c| 17 +
 pc-bios/s390-ccw/sclp.c| 10 +-
 7 files changed, 129 insertions(+), 45 deletions(-)
 create mode 100644 pc-bios/s390-ccw/libc.c

diff --git a/pc-bios/s390-ccw/Makefile b/pc-bios/s390-ccw/Makefile
index 6d0c2ee..9f7904f 100644
--- a/pc-bios/s390-ccw/Makefile
+++ b/pc-bios/s390-ccw/Makefile
@@ -9,7 +9,7 @@ $(call set-vpath, $(SRC_PATH)/pc-bios/s390-ccw)
 
 .PHONY : all clean build-all
 
-OBJECTS = start.o main.o bootmap.o sclp.o virtio.o virtio-scsi.o 
virtio-blkdev.o
+OBJECTS = start.o main.o bootmap.o sclp.o virtio.o virtio-scsi.o 
virtio-blkdev.o libc.o
 QEMU_CFLAGS := $(filter -W%, $(QEMU_CFLAGS))
 QEMU_CFLAGS += -ffreestanding -fno-delete-null-pointer-checks -msoft-float
 QEMU_CFLAGS += -march=z900 -fPIE -fno-strict-aliasing
diff --git a/pc-bios/s390-ccw/bootmap.c b/pc-bios/s390-ccw/bootmap.c
index a94638d..092fb35 100644
--- a/pc-bios/s390-ccw/bootmap.c
+++ b/pc-bios/s390-ccw/bootmap.c
@@ -506,7 +506,7 @@ static bool is_iso_bc_entry_compatible(IsoBcSection *s)
 "Failed to read image sector 0");
 
 /* Checking bytes 8 - 32 for S390 Linux magic */
-return !_memcmp(magic_sec + 8, linux_s390_magic, 24);
+return !memcmp(magic_sec + 8, linux_s390_magic, 24);
 }
 
 /* Location of the current sector of the directory */
@@ -635,7 +635,7 @@ static uint32_t find_iso_bc(void)
 if (vd->type == VOL_DESC_TYPE_BOOT) {
 IsoVdElTorito *et = >vd.boot;
 
-if (!_memcmp(>el_torito[0], el_torito_magic, 32)) {
+if (!memcmp(>el_torito[0], el_torito_magic, 32)) {
 return bswap32(et->bc_offset);
 }
 }
diff --git a/pc-bios/s390-ccw/bootmap.h b/pc-bios/s390-ccw/bootmap.h
index 4bd95cd..4cf7e1e 100644
--- a/pc-bios/s390-ccw/bootmap.h
+++ b/pc-bios/s390-ccw/bootmap.h
@@ -328,20 +328,6 @@ static inline bool magic_match(const void *data, const 
void *magic)
 return *((uint32_t *)data) == *((uint32_t *)magic);
 }
 
-static inline int _memcmp(const void *s1, const void *s2, size_t n)
-{
-int i;
-const uint8_t *p1 = s1, *p2 = s2;
-
-for (i = 0; i < n; i++) {
-if (p1[i] != p2[i]) {
-return p1[i] > p2[i] ? 1 : -1;
-}
-}
-
-return 0;
-}
-
 static inline uint32_t iso_733_to_u32(uint64_t x)
 {
 return (uint32_t)x;
@@ -434,7 +420,7 @@ const uint8_t vol_desc_magic[] = "CD001";
 
 static inline bool is_iso_vd_valid(IsoVolDesc *vd)
 {
-return !_memcmp(>ident[0], vol_desc_magic, 5) &&
+return !memcmp(>ident[0], vol_desc_magic, 5) &&
vd->version == 0x1 &&
vd->type <= VOL_DESC_TYPE_PARTITION;
 }
diff --git a/pc-bios/s390-ccw/libc.c b/pc-bios/s390-ccw/libc.c
new file mode 100644
index 000..38ea77d
--- /dev/null
+++ b/pc-bios/s390-ccw/libc.c
@@ -0,0 +1,88 @@
+/*
+ * libc-style definitions and functions
+ *
+ * Copyright 2018 IBM Corp.
+ * Author(s): Collin L. Walling <wall...@linux.vnet.ibm.com>
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ */
+
+#include "libc.h"
+#include "s390-ccw.h"
+
+/**
+ * atoui:
+ * @str: the string to be converted.
+ *
+ * Given a string @str, convert it to an integer. Leading spaces are
+ * ignored. Any other non-numerical value will terminate the conversion
+ * and return 0. This function only handles numbers between 0 and
+ * UINT64_MAX inclusive.
+ *
+ * Returns: an integer converted from the string @str, or the number 0
+ * if an error occurred.
+ */
+uint64_t atoui(const char *str)
+{
+int val = 0;
+
+if (!str || !str[0]) {
+return 0;
+}
+
+while (*str == ' ') {
+str++;
+}
+
+while (*str) {
+if (!isdigit(*str)) {
+break;
+}
+val = val * 10 + *str - '0';
+str++;
+}
+
+return val;
+}
+
+/**
+ * uitoa:
+ * @num: an integer (base 10) to be converted.
+ * @str: a pointer to a string to store the conversion.
+ * @len: the length of the passed string.
+ *
+ * Given an in

[Qemu-devel] [PATCH v9 03/13] s390-ccw: refactor IPL structs

2018-02-23 Thread Collin L. Walling
ECKD DASDs have different IPL structures for CDL and LDL
formats. The current Ipl1 and Ipl2 structs follow the CDL
format, so we prepend "EckdCdl" to them. Boot info for LDL
has been moved to a new struct: EckdLdlIpl1.

Signed-off-by: Collin L. Walling <wall...@linux.vnet.ibm.com>
Acked-by: Janosch Frank <fran...@linux.vnet.ibm.com>
Reviewed-by: Thomas Huth <th...@redhat.com>
---
 pc-bios/s390-ccw/bootmap.c | 12 ++--
 pc-bios/s390-ccw/bootmap.h | 37 +
 2 files changed, 27 insertions(+), 22 deletions(-)

diff --git a/pc-bios/s390-ccw/bootmap.c b/pc-bios/s390-ccw/bootmap.c
index 9534f56..a94638d 100644
--- a/pc-bios/s390-ccw/bootmap.c
+++ b/pc-bios/s390-ccw/bootmap.c
@@ -221,7 +221,7 @@ static void run_eckd_boot_script(block_number_t 
bmt_block_nr)
 static void ipl_eckd_cdl(void)
 {
 XEckdMbr *mbr;
-Ipl2 *ipl2 = (void *)sec;
+EckdCdlIpl2 *ipl2 = (void *)sec;
 IplVolumeLabel *vlbl = (void *)sec;
 block_number_t bmt_block_nr;
 
@@ -231,7 +231,7 @@ static void ipl_eckd_cdl(void)
 memset(sec, FREE_SPACE_FILLER, sizeof(sec));
 read_block(1, ipl2, "Cannot read IPL2 record at block 1");
 
-mbr = >u.x.mbr;
+mbr = >mbr;
 IPL_assert(magic_match(mbr, ZIPL_MAGIC), "No zIPL section in IPL2 
record.");
 IPL_assert(block_size_ok(mbr->blockptr.xeckd.bptr.size),
"Bad block size in zIPL section of IPL2 record.");
@@ -281,7 +281,7 @@ static void print_eckd_ldl_msg(ECKD_IPL_mode_t mode)
 static void ipl_eckd_ldl(ECKD_IPL_mode_t mode)
 {
 block_number_t bmt_block_nr;
-BootInfo *bip = (void *)(sec + 0x70); /* BootInfo is MBR for LDL */
+EckdLdlIpl1 *ipl1 = (void *)sec;
 
 if (mode != ECKD_LDL_UNLABELED) {
 print_eckd_ldl_msg(mode);
@@ -292,15 +292,15 @@ static void ipl_eckd_ldl(ECKD_IPL_mode_t mode)
 memset(sec, FREE_SPACE_FILLER, sizeof(sec));
 read_block(0, sec, "Cannot read block 0 to grab boot info.");
 if (mode == ECKD_LDL_UNLABELED) {
-if (!magic_match(bip->magic, ZIPL_MAGIC)) {
+if (!magic_match(ipl1->bip.magic, ZIPL_MAGIC)) {
 return; /* not applicable layout */
 }
 sclp_print("unlabeled LDL.\n");
 }
-verify_boot_info(bip);
+verify_boot_info(>bip);
 
 /* save pointer to Boot Map Table */
-bmt_block_nr = eckd_block_num(>bp.ipl.bm_ptr.eckd.bptr.chs);
+bmt_block_nr = eckd_block_num(>bip.bp.ipl.bm_ptr.eckd.bptr.chs);
 
 run_eckd_boot_script(bmt_block_nr);
 /* no return */
diff --git a/pc-bios/s390-ccw/bootmap.h b/pc-bios/s390-ccw/bootmap.h
index b361084..4bd95cd 100644
--- a/pc-bios/s390-ccw/bootmap.h
+++ b/pc-bios/s390-ccw/bootmap.h
@@ -239,22 +239,27 @@ typedef struct BootInfo {  /* @ 0x70, record #0   
 */
 } bp;
 } __attribute__ ((packed)) BootInfo; /* see also XEckdMbr   */
 
-typedef struct Ipl1 {
-unsigned char key[4]; /* == "IPL1" */
-unsigned char data[24];
-} __attribute__((packed)) Ipl1;
-
-typedef struct Ipl2 {
-unsigned char key[4]; /* == "IPL2" */
-union {
-unsigned char data[144];
-struct {
-unsigned char reserved1[92-4];
-XEckdMbr mbr;
-unsigned char reserved2[144-(92-4)-sizeof(XEckdMbr)];
-} x;
-} u;
-} __attribute__((packed)) Ipl2;
+/*
+ * Structs for IPL
+ */
+#define STAGE2_BLK_CNT_MAX  24 /* Stage 1b can load up to 24 blocks */
+
+typedef struct EckdCdlIpl1 {
+uint8_t key[4]; /* == "IPL1" */
+uint8_t data[24];
+} __attribute__((packed)) EckdCdlIpl1;
+
+typedef struct EckdCdlIpl2 {
+uint8_t key[4]; /* == "IPL2" */
+uint8_t reserved0[88];
+XEckdMbr mbr;
+uint8_t reserved[24];
+} __attribute__((packed)) EckdCdlIpl2;
+
+typedef struct EckdLdlIpl1 {
+uint8_t reserved[112];
+BootInfo bip; /* BootInfo is MBR for LDL */
+} __attribute__((packed)) EckdLdlIpl1;
 
 typedef struct IplVolumeLabel {
 unsigned char key[4]; /* == "VOL1" */
-- 
2.7.4




[Qemu-devel] [PATCH v9 02/13] s390-ccw: refactor eckd_block_num to use CHS

2018-02-23 Thread Collin L. Walling
Add new cylinder/head/sector struct. Use it to calculate
eckd block numbers instead of a BootMapPointer (which used
eckd chs anyway).

Signed-off-by: Collin L. Walling <wall...@linux.vnet.ibm.com>
Reviewed-by: Thomas Huth <th...@redhat.com>
---
 pc-bios/s390-ccw/bootmap.c | 28 ++--
 pc-bios/s390-ccw/bootmap.h |  8 ++--
 2 files changed, 20 insertions(+), 16 deletions(-)

diff --git a/pc-bios/s390-ccw/bootmap.c b/pc-bios/s390-ccw/bootmap.c
index a4eaf24..9534f56 100644
--- a/pc-bios/s390-ccw/bootmap.c
+++ b/pc-bios/s390-ccw/bootmap.c
@@ -95,32 +95,32 @@ static inline void verify_boot_info(BootInfo *bip)
"Bad block size in zIPL section of the 1st record.");
 }
 
-static block_number_t eckd_block_num(BootMapPointer *p)
+static block_number_t eckd_block_num(EckdCHS *chs)
 {
 const uint64_t sectors = virtio_get_sectors();
 const uint64_t heads = virtio_get_heads();
-const uint64_t cylinder = p->eckd.cylinder
-+ ((p->eckd.head & 0xfff0) << 12);
-const uint64_t head = p->eckd.head & 0x000f;
+const uint64_t cylinder = chs->cylinder
++ ((chs->head & 0xfff0) << 12);
+const uint64_t head = chs->head & 0x000f;
 const block_number_t block = sectors * heads * cylinder
+ sectors * head
-   + p->eckd.sector
+   + chs->sector
- 1; /* block nr starts with zero */
 return block;
 }
 
 static bool eckd_valid_address(BootMapPointer *p)
 {
-const uint64_t head = p->eckd.head & 0x000f;
+const uint64_t head = p->eckd.chs.head & 0x000f;
 
 if (head >= virtio_get_heads()
-||  p->eckd.sector > virtio_get_sectors()
-||  p->eckd.sector <= 0) {
+||  p->eckd.chs.sector > virtio_get_sectors()
+||  p->eckd.chs.sector <= 0) {
 return false;
 }
 
 if (!virtio_guessed_disk_nature() &&
-eckd_block_num(p) >= virtio_get_blocks()) {
+eckd_block_num(>eckd.chs) >= virtio_get_blocks()) {
 return false;
 }
 
@@ -140,7 +140,7 @@ static block_number_t load_eckd_segments(block_number_t 
blk, uint64_t *address)
 do {
 more_data = false;
 for (j = 0;; j++) {
-block_nr = eckd_block_num((void *)&(bprs[j].xeckd));
+block_nr = eckd_block_num([j].xeckd.bptr.chs);
 if (is_null_block_number(block_nr)) { /* end of chunk */
 break;
 }
@@ -198,7 +198,7 @@ static void run_eckd_boot_script(block_number_t 
bmt_block_nr)
 memset(sec, FREE_SPACE_FILLER, sizeof(sec));
 read_block(bmt_block_nr, sec, "Cannot read Boot Map Table");
 
-block_nr = eckd_block_num(>entry[loadparm]);
+block_nr = eckd_block_num(>entry[loadparm].xeckd.bptr.chs);
 IPL_assert(block_nr != -1, "Cannot find Boot Map Table Entry");
 
 memset(sec, FREE_SPACE_FILLER, sizeof(sec));
@@ -206,7 +206,7 @@ static void run_eckd_boot_script(block_number_t 
bmt_block_nr)
 
 for (i = 0; bms->entry[i].type == BOOT_SCRIPT_LOAD; i++) {
 address = bms->entry[i].address.load_address;
-block_nr = eckd_block_num(&(bms->entry[i].blkptr));
+block_nr = eckd_block_num(>entry[i].blkptr.xeckd.bptr.chs);
 
 do {
 block_nr = load_eckd_segments(block_nr, );
@@ -239,7 +239,7 @@ static void ipl_eckd_cdl(void)
"Non-ECKD device type in zIPL section of IPL2 record.");
 
 /* save pointer to Boot Map Table */
-bmt_block_nr = eckd_block_num(>blockptr);
+bmt_block_nr = eckd_block_num(>blockptr.xeckd.bptr.chs);
 
 memset(sec, FREE_SPACE_FILLER, sizeof(sec));
 read_block(2, vlbl, "Cannot read Volume Label at block 2");
@@ -300,7 +300,7 @@ static void ipl_eckd_ldl(ECKD_IPL_mode_t mode)
 verify_boot_info(bip);
 
 /* save pointer to Boot Map Table */
-bmt_block_nr = eckd_block_num((void *)>bp.ipl.bm_ptr.eckd.bptr);
+bmt_block_nr = eckd_block_num(>bp.ipl.bm_ptr.eckd.bptr.chs);
 
 run_eckd_boot_script(bmt_block_nr);
 /* no return */
diff --git a/pc-bios/s390-ccw/bootmap.h b/pc-bios/s390-ccw/bootmap.h
index 486c0f3..b361084 100644
--- a/pc-bios/s390-ccw/bootmap.h
+++ b/pc-bios/s390-ccw/bootmap.h
@@ -32,10 +32,14 @@ typedef struct FbaBlockPtr {
 uint16_t blockct;
 } __attribute__ ((packed)) FbaBlockPtr;
 
-typedef struct EckdBlockPtr {
-uint16_t cylinder; /* cylinder/head/sector is an address of the block */
+typedef struct EckdCHS {
+uint16_t cylinder;
 uint16_t head;
 uint8_t sector;
+} __attribute__ ((packed)) EckdCHS;
+
+typedef struct EckdBlockPtr {
+EckdCHS chs; /* cylinder/head/sector is an address of the block */
 uint16_t size;
 uint8_t count; /* (size_in_blocks-1);
 * it's 0 for TablePtr, ScriptPtr, and SectionPtr */
-- 
2.7.4




Re: [Qemu-devel] [PATCH v8 00/13] Interactive Boot Menu for DASD and SCSI Guests on s390x

2018-02-23 Thread Collin L. Walling

On 02/23/2018 08:33 AM, Thomas Huth wrote:

On 23.02.2018 12:50, Viktor Mihajlovski wrote:

On 23.02.2018 11:17, Thomas Huth wrote:

On 23.02.2018 09:53, Christian Borntraeger wrote:

Hmmm, on my ubuntu 16.04 guest, I get the boot menu with no timeout even if I 
do not
specify loadparm or boot menu:

qemu-kvm -drive file=/var/lib/libvirt/qemu/image.zhyp140,if=none,id=d1 -device 
virtio-blk-ccw,drive=d1,bootindex=1

I can reproduce this now, too. FWIW: It only happens with
virtio-blk-ccw, not with virtio-scsi-ccw (that's why I did not notice it
first). Collin, can you reproduce this, too?

  Thomas
The idea is to support the zipl boot menu on ECKD disks (which have a timeout 
by themselves)

even without switching the boot menu on. This is to have the same behavior as 
one would see
on LPAR or z/VM.
The issue is that the boot code tries to interpret the program table of SCSI 
bootmaps as if
a boot menu has been specified.

Ok, thanks for the explanation, makes sense now.

Collin, could you please spin a v9 with the required changes included?

  Thanks,
   Thomas


I see.  I overlooked that we could treat a SCSI device as a CCW device.  
The proposed change makes sense.

I'll respin 9 and reply to this chain.

--
- Collin L Walling




Re: [Qemu-devel] [qemu-s390x] [PATCH v8 00/13] Interactive Boot Menu for DASD and SCSI Guests on s390x

2018-02-23 Thread Collin L. Walling

On 02/23/2018 09:57 AM, Collin L. Walling wrote:

On 02/23/2018 05:11 AM, Christian Borntraeger wrote:


On 02/23/2018 11:07 AM, Thomas Huth wrote:

On 22.02.2018 20:40, Collin L. Walling wrote:

On 02/22/2018 11:45 AM, Collin L. Walling wrote:

On 02/22/2018 10:44 AM, Christian Borntraeger wrote:

On 02/22/2018 04:40 PM, Collin L. Walling wrote:

On 02/22/2018 07:23 AM, Viktor Mihajlovski wrote:

On 22.02.2018 12:51, Christian Borntraeger wrote:

Series
Acked-by: Christian Borntraeger <borntrae...@de.ibm.com>

Thanks!!!


menu on scsi and dasd bootmaps tested successfully.

There is one thing that we might want to fix (can be an addon
patch since this is a non-customer
scenario (no libvirt)).

If you start QEMU manually without a bootindex, the -boot menu=on
is ignored
if no drive has a bootindex.

For example:

-drive file=/dev/dasda,if=none,id=d1 -device
virtio-blk-ccw,drive=d1,bootindex=1 -boot menu=on
does work

-drive file=/dev/dasda -boot menu=on
does not

instead it prints:
qemu-system-s390x: boot menu is not supported for this device 
type.


and the boots up the default entry.


That should indeed be a separate patch, as it would move logic
currently
in the BIOS up to QEMU (find the first defined virtio disk and
select it
as boot disk).
In fact it's more complicated than that, because it would have to
properly account for -boot order=[acdn] and produce the respective
IPLB.
While it makes sense, I wouldn't rush that in but rather change 
the
error message to indicate that -device bootindex is needed to 
activate

the menu, at least for the time being.
[...]


I can look into it.  Theoretically, the easier fix should just
involve parsing all
of the -device commands and looking for a "bootindex=1" field. The
Qemu options
code already handles a bulk of this work, so it's just a matter of
putting it all
together.

Shall I whip something up and post what I have as a reply to this
email chain?

In fact, it should already be there.

static bool s390_gen_initial_iplb(S390IPLState *ipl)
{
  DeviceState *dev_st;

  dev_st = get_boot_device(0);

--> if this returns 0 we have no bootindex statement anywhere and 
the

BIOS will IPL the default
disk.



Makes sense.  I'm working on making this patch look as clean as
possible. The fact that no boot menu
options present means we fallback to using zipl values for CCW being
tied into the switch statement
is making things a bit tricky. Just have to think the logic through a
bit.  Will get back to you once
I have something good.

This should do the trick (this can also be squished painlessly into 
6/13

if desired)

Patch looks fine to me. I can either take it directly like this, or in
case you have to respin (depends on the problem that Christian reported
with the Ubuntu guest), I'm also fine if you squash it into an earlier
patch instead.
FWIW, my problem (a menu happens even without -boot menu=on or 
loadparm) also

happens with other guests (e.g. fedora).


Is this on guests using DASD?  If so, a boot menu will appear if the 
appropriate zipl configuration
values are set (even if no -boot menu or loadparm).  Patch 12/13 goes 
into more detail.


Is this not wanted behavior?


Just noticed other email chain -- ignore me.

--
- Collin L Walling




Re: [Qemu-devel] [qemu-s390x] [PATCH v8 00/13] Interactive Boot Menu for DASD and SCSI Guests on s390x

2018-02-23 Thread Collin L. Walling

On 02/23/2018 05:11 AM, Christian Borntraeger wrote:


On 02/23/2018 11:07 AM, Thomas Huth wrote:

On 22.02.2018 20:40, Collin L. Walling wrote:

On 02/22/2018 11:45 AM, Collin L. Walling wrote:

On 02/22/2018 10:44 AM, Christian Borntraeger wrote:

On 02/22/2018 04:40 PM, Collin L. Walling wrote:

On 02/22/2018 07:23 AM, Viktor Mihajlovski wrote:

On 22.02.2018 12:51, Christian Borntraeger wrote:

Series
Acked-by: Christian Borntraeger <borntrae...@de.ibm.com>

Thanks!!!


menu on scsi and dasd bootmaps tested successfully.

There is one thing that we might want to fix (can be an addon
patch since this is a non-customer
scenario (no libvirt)).

If you start QEMU manually without a bootindex, the -boot menu=on
is ignored
if no drive has a bootindex.

For example:

-drive file=/dev/dasda,if=none,id=d1 -device
virtio-blk-ccw,drive=d1,bootindex=1 -boot menu=on
does work

-drive file=/dev/dasda -boot menu=on
does not

instead it prints:
qemu-system-s390x: boot menu is not supported for this device type.

and the boots up the default entry.


That should indeed be a separate patch, as it would move logic
currently
in the BIOS up to QEMU (find the first defined virtio disk and
select it
as boot disk).
In fact it's more complicated than that, because it would have to
properly account for -boot order=[acdn] and produce the respective
IPLB.
While it makes sense, I wouldn't rush that in but rather change the
error message to indicate that -device bootindex is needed to activate
the menu, at least for the time being.
[...]


I can look into it.  Theoretically, the easier fix should just
involve parsing all
of the -device commands and looking for a "bootindex=1" field. The
Qemu options
code already handles a bulk of this work, so it's just a matter of
putting it all
together.

Shall I whip something up and post what I have as a reply to this
email chain?

In fact, it should already be there.

static bool s390_gen_initial_iplb(S390IPLState *ipl)
{
  DeviceState *dev_st;

  dev_st = get_boot_device(0);

--> if this returns 0 we have no bootindex statement anywhere and the
BIOS will IPL the default
disk.



Makes sense.  I'm working on making this patch look as clean as
possible. The fact that no boot menu
options present means we fallback to using zipl values for CCW being
tied into the switch statement
is making things a bit tricky. Just have to think the logic through a
bit.  Will get back to you once
I have something good.


This should do the trick (this can also be squished painlessly into 6/13
if desired)

Patch looks fine to me. I can either take it directly like this, or in
case you have to respin (depends on the problem that Christian reported
with the Ubuntu guest), I'm also fine if you squash it into an earlier
patch instead.

FWIW, my problem (a menu happens even without -boot menu=on or loadparm) also
happens with other guests (e.g. fedora).


Is this on guests using DASD?  If so, a boot menu will appear if the 
appropriate zipl configuration
values are set (even if no -boot menu or loadparm).  Patch 12/13 goes 
into more detail.


Is this not wanted behavior?

--
- Collin L Walling




Re: [Qemu-devel] [qemu-s390x] [PATCH v8 00/13] Interactive Boot Menu for DASD and SCSI Guests on s390x

2018-02-22 Thread Collin L. Walling

On 02/22/2018 11:45 AM, Collin L. Walling wrote:

On 02/22/2018 10:44 AM, Christian Borntraeger wrote:


On 02/22/2018 04:40 PM, Collin L. Walling wrote:

On 02/22/2018 07:23 AM, Viktor Mihajlovski wrote:

On 22.02.2018 12:51, Christian Borntraeger wrote:

Series
Acked-by: Christian Borntraeger <borntrae...@de.ibm.com>

Thanks!!!



menu on scsi and dasd bootmaps tested successfully.

There is one thing that we might want to fix (can be an addon 
patch since this is a non-customer

scenario (no libvirt)).

If you start QEMU manually without a bootindex, the -boot menu=on 
is ignored

if no drive has a bootindex.

For example:

-drive file=/dev/dasda,if=none,id=d1 -device 
virtio-blk-ccw,drive=d1,bootindex=1 -boot menu=on

does work

-drive file=/dev/dasda -boot menu=on
does not

instead it prints:
qemu-system-s390x: boot menu is not supported for this device type.

and the boots up the default entry.

That should indeed be a separate patch, as it would move logic 
currently
in the BIOS up to QEMU (find the first defined virtio disk and 
select it

as boot disk).
In fact it's more complicated than that, because it would have to
properly account for -boot order=[acdn] and produce the respective 
IPLB.

While it makes sense, I wouldn't rush that in but rather change the
error message to indicate that -device bootindex is needed to activate
the menu, at least for the time being.
[...]

I can look into it.  Theoretically, the easier fix should just 
involve parsing all
of the -device commands and looking for a "bootindex=1" field. The 
Qemu options
code already handles a bulk of this work, so it's just a matter of 
putting it all

together.

Shall I whip something up and post what I have as a reply to this 
email chain?

In fact, it should already be there.

static bool s390_gen_initial_iplb(S390IPLState *ipl)
{
 DeviceState *dev_st;

 dev_st = get_boot_device(0);

--> if this returns 0 we have no bootindex statement anywhere and the 
BIOS will IPL the default

disk.


Makes sense.  I'm working on making this patch look as clean as 
possible. The fact that no boot menu
options present means we fallback to using zipl values for CCW being 
tied into the switch statement
is making things a bit tricky. Just have to think the logic through a 
bit.  Will get back to you once

I have something good.

This should do the trick (this can also be squished painlessly into 6/13 
if desired):


From dea9f22429cb3e4ccc81980974adc9f55ead87bf Mon Sep 17 00:00:00 2001
From: "Collin L. Walling" <wall...@linux.vnet.ibm.com>
Date: Thu, 22 Feb 2018 14:26:14 -0500
Subject: [PATCH] s390-ccw: set boot menu options iff a bootindex was 
provided


The boot menu options should be set iff a device was specified
with bootindex=1, otherwise an error message will appear claiming
that the boot menu is not available for a particular device type.
This can be misleading.

To amend this, only set the boot menu options when

    -device ...,bootindex=1

is provded on the command line for a valid IPL device. The absence
of a bootindex provided with -boot menu=on will display an error
message, and -boot menu=off (or absence of -boot options) will
return silently.

Signed-off-by: Collin L. Walling <wall...@linux.vnet.ibm.com>
---
 hw/s390x/ipl.c | 8 
 1 file changed, 8 insertions(+)

diff --git a/hw/s390x/ipl.c b/hw/s390x/ipl.c
index 566248e..edbec90 100644
--- a/hw/s390x/ipl.c
+++ b/hw/s390x/ipl.c
@@ -231,6 +231,14 @@ static void s390_ipl_set_boot_menu(S390IPLState *ipl)
 const char *tmp;
 unsigned long splash_time = 0;

+    if (!get_boot_device(0)) {
+    if (boot_menu) {
+    error_report("boot menu requires a bootindex to be 
specified for "

+ "the IPL device.");
+    }
+    return;
+    }
+
 switch (ipl->iplb.pbt) {
 case S390_IPL_TYPE_CCW:
 /* In the absence of -boot menu, use zipl parameters */
--
2.7.4

--
- Collin L Walling




Re: [Qemu-devel] [qemu-s390x] [PATCH v8 00/13] Interactive Boot Menu for DASD and SCSI Guests on s390x

2018-02-22 Thread Collin L. Walling

On 02/22/2018 10:44 AM, Christian Borntraeger wrote:


On 02/22/2018 04:40 PM, Collin L. Walling wrote:

On 02/22/2018 07:23 AM, Viktor Mihajlovski wrote:

On 22.02.2018 12:51, Christian Borntraeger wrote:

Series
Acked-by: Christian Borntraeger <borntrae...@de.ibm.com>

Thanks!!!



menu on scsi and dasd bootmaps tested successfully.

There is one thing that we might want to fix (can be an addon patch since this 
is a non-customer
scenario (no libvirt)).

If you start QEMU manually without a bootindex, the -boot menu=on is ignored
if no drive has a bootindex.

For example:

-drive file=/dev/dasda,if=none,id=d1 -device 
virtio-blk-ccw,drive=d1,bootindex=1 -boot menu=on
does work

-drive file=/dev/dasda -boot menu=on
does not

instead it prints:
qemu-system-s390x: boot menu is not supported for this device type.

and the boots up the default entry.


That should indeed be a separate patch, as it would move logic currently
in the BIOS up to QEMU (find the first defined virtio disk and select it
as boot disk).
In fact it's more complicated than that, because it would have to
properly account for -boot order=[acdn] and produce the respective IPLB.
While it makes sense, I wouldn't rush that in but rather change the
error message to indicate that -device bootindex is needed to activate
the menu, at least for the time being.
[...]


I can look into it.  Theoretically, the easier fix should just involve parsing 
all
of the -device commands and looking for a "bootindex=1" field. The Qemu options
code already handles a bulk of this work, so it's just a matter of putting it 
all
together.

Shall I whip something up and post what I have as a reply to this email chain?

In fact, it should already be there.

static bool s390_gen_initial_iplb(S390IPLState *ipl)
{
 DeviceState *dev_st;

 dev_st = get_boot_device(0);

--> if this returns 0 we have no bootindex statement anywhere and the BIOS will 
IPL the default
disk.


Makes sense.  I'm working on making this patch look as clean as 
possible. The fact that no boot menu
options present means we fallback to using zipl values for CCW being 
tied into the switch statement
is making things a bit tricky. Just have to think the logic through a 
bit.  Will get back to you once

I have something good.

--
- Collin L Walling




Re: [Qemu-devel] [qemu-s390x] [PATCH v8 00/13] Interactive Boot Menu for DASD and SCSI Guests on s390x

2018-02-22 Thread Collin L. Walling

On 02/22/2018 07:23 AM, Viktor Mihajlovski wrote:

On 22.02.2018 12:51, Christian Borntraeger wrote:

Series
Acked-by: Christian Borntraeger <borntrae...@de.ibm.com>


Thanks!!!




menu on scsi and dasd bootmaps tested successfully.

There is one thing that we might want to fix (can be an addon patch since this 
is a non-customer
scenario (no libvirt)).

If you start QEMU manually without a bootindex, the -boot menu=on is ignored
if no drive has a bootindex.

For example:

-drive file=/dev/dasda,if=none,id=d1 -device 
virtio-blk-ccw,drive=d1,bootindex=1 -boot menu=on
does work

-drive file=/dev/dasda -boot menu=on
does not

instead it prints:
qemu-system-s390x: boot menu is not supported for this device type.

and the boots up the default entry.


That should indeed be a separate patch, as it would move logic currently
in the BIOS up to QEMU (find the first defined virtio disk and select it
as boot disk).
In fact it's more complicated than that, because it would have to
properly account for -boot order=[acdn] and produce the respective IPLB.
While it makes sense, I wouldn't rush that in but rather change the
error message to indicate that -device bootindex is needed to activate
the menu, at least for the time being.
[...]

I can look into it.  Theoretically, the easier fix should just involve 
parsing all
of the -device commands and looking for a "bootindex=1" field. The Qemu 
options
code already handles a bulk of this work, so it's just a matter of 
putting it all

together.

Shall I whip something up and post what I have as a reply to this email 
chain?


--
- Collin L Walling




[Qemu-devel] [PATCH v8 11/13] s390-ccw: set cp_receive mask only when needed and consume pending service irqs

2018-02-21 Thread Collin L. Walling
It is possible while waiting for multiple types of external
interrupts that we might have pending irqs remaining between
irq consumption and irq-type disabling. Those interrupts
could potentially propagate to the guest after IPL completes
and cause unwanted behavior.

As it is today, the SCLP will only recognize write events that
are enabled by the control program's send and receive masks. To
limit the window for, and prevent further irqs from, ASCII
console events (specifically keystrokes), we should only enable
the control program's receive mask when we need it.

While we're at it, remove assignment of the (non control program)
send and receive masks, as those are actually set by the SCLP.

Signed-off-by: Collin L. Walling <wall...@linux.vnet.ibm.com>
---
 pc-bios/s390-ccw/menu.c |  5 +
 pc-bios/s390-ccw/s390-ccw.h |  1 +
 pc-bios/s390-ccw/sclp.c | 10 --
 3 files changed, 10 insertions(+), 6 deletions(-)

diff --git a/pc-bios/s390-ccw/menu.c b/pc-bios/s390-ccw/menu.c
index 01b120d..4f84bfe 100644
--- a/pc-bios/s390-ccw/menu.c
+++ b/pc-bios/s390-ccw/menu.c
@@ -11,6 +11,7 @@
 
 #include "libc.h"
 #include "s390-ccw.h"
+#include "sclp.h"
 
 #define KEYCODE_NO_INP '\0'
 #define KEYCODE_ESCAPE '\033'
@@ -116,8 +117,12 @@ static int get_index(void)
 
 memset(buf, 0, sizeof(buf));
 
+sclp_set_write_mask(SCLP_EVENT_MASK_MSG_ASCII, SCLP_EVENT_MASK_MSG_ASCII);
+
 len = read_prompt(buf, sizeof(buf) - 1);
 
+sclp_set_write_mask(0, SCLP_EVENT_MASK_MSG_ASCII);
+
 /* If no input, boot default */
 if (len == 0) {
 return 0;
diff --git a/pc-bios/s390-ccw/s390-ccw.h b/pc-bios/s390-ccw/s390-ccw.h
index f7c12bf..56b0c2a 100644
--- a/pc-bios/s390-ccw/s390-ccw.h
+++ b/pc-bios/s390-ccw/s390-ccw.h
@@ -69,6 +69,7 @@ unsigned int get_loadparm_index(void);
 
 /* sclp.c */
 void sclp_print(const char *string);
+void sclp_set_write_mask(uint32_t receive_mask, uint32_t send_mask);
 void sclp_setup(void);
 void sclp_get_loadparm_ascii(char *loadparm);
 int sclp_read(char *str, size_t count);
diff --git a/pc-bios/s390-ccw/sclp.c b/pc-bios/s390-ccw/sclp.c
index a2f25eb..3836cb4 100644
--- a/pc-bios/s390-ccw/sclp.c
+++ b/pc-bios/s390-ccw/sclp.c
@@ -46,23 +46,21 @@ static int sclp_service_call(unsigned int command, void 
*sccb)
 return 0;
 }
 
-static void sclp_set_write_mask(void)
+void sclp_set_write_mask(uint32_t receive_mask, uint32_t send_mask)
 {
 WriteEventMask *sccb = (void *)_sccb;
 
 sccb->h.length = sizeof(WriteEventMask);
 sccb->mask_length = sizeof(unsigned int);
-sccb->receive_mask = SCLP_EVENT_MASK_MSG_ASCII;
-sccb->cp_receive_mask = SCLP_EVENT_MASK_MSG_ASCII;
-sccb->send_mask = SCLP_EVENT_MASK_MSG_ASCII;
-sccb->cp_send_mask = SCLP_EVENT_MASK_MSG_ASCII;
+sccb->cp_receive_mask = receive_mask;
+sccb->cp_send_mask = send_mask;
 
 sclp_service_call(SCLP_CMD_WRITE_EVENT_MASK, sccb);
 }
 
 void sclp_setup(void)
 {
-sclp_set_write_mask();
+sclp_set_write_mask(0, SCLP_EVENT_MASK_MSG_ASCII);
 }
 
 long write(int fd, const void *str, size_t len)
-- 
2.7.4




[Qemu-devel] [PATCH v8 06/13] s390-ccw: parse and set boot menu options

2018-02-21 Thread Collin L. Walling
Set boot menu options for an s390 guest and store them in
the iplb. These options are set via the QEMU command line
option:

-boot menu=on|off[,splash-time=X]

or via the libvirt domain xml:


  


Where X represents some positive integer representing
milliseconds.

Any value set for loadparm will override all boot menu options.
If loadparm=PROMPT, then the menu will be enabled without a
timeout.

Signed-off-by: Collin L. Walling <wall...@linux.vnet.ibm.com>
Reviewed-by: Janosch Frank <fran...@linux.vnet.ibm.com>
---
 hw/s390x/ipl.c  | 44 
 hw/s390x/ipl.h  |  9 +++--
 pc-bios/s390-ccw/iplb.h |  9 +++--
 3 files changed, 58 insertions(+), 4 deletions(-)

diff --git a/hw/s390x/ipl.c b/hw/s390x/ipl.c
index 79f5a58..a176c4a 100644
--- a/hw/s390x/ipl.c
+++ b/hw/s390x/ipl.c
@@ -23,6 +23,9 @@
 #include "hw/s390x/ebcdic.h"
 #include "ipl.h"
 #include "qemu/error-report.h"
+#include "qemu/config-file.h"
+#include "qemu/cutils.h"
+#include "qemu/option.h"
 
 #define KERN_IMAGE_START0x01UL
 #define KERN_PARM_AREA  0x010480UL
@@ -219,6 +222,46 @@ static Property s390_ipl_properties[] = {
 DEFINE_PROP_END_OF_LIST(),
 };
 
+static void s390_ipl_set_boot_menu(S390IPLState *ipl)
+{
+QemuOptsList *plist = qemu_find_opts("boot-opts");
+QemuOpts *opts = QTAILQ_FIRST(>head);
+uint8_t *flags = >qipl.qipl_flags;
+uint32_t *timeout = >qipl.boot_menu_timeout;
+const char *tmp;
+unsigned long splash_time = 0;
+
+switch (ipl->iplb.pbt) {
+case S390_IPL_TYPE_CCW:
+break;
+default:
+error_report("boot menu is not supported for this device type.");
+return;
+}
+
+if (!boot_menu) {
+return;
+}
+
+*flags |= QIPL_FLAG_BM_OPTS_CMD;
+
+tmp = qemu_opt_get(opts, "splash-time");
+
+if (tmp && qemu_strtoul(tmp, NULL, 10, _time)) {
+error_report("splash-time is invalid, forcing it to 0.");
+*timeout = 0;
+return;
+}
+
+if (splash_time > 0x) {
+error_report("splash-time is too large, forcing it to max value.");
+*timeout = 0x;
+return;
+}
+
+*timeout = cpu_to_be32(splash_time);
+}
+
 static bool s390_gen_initial_iplb(S390IPLState *ipl)
 {
 DeviceState *dev_st;
@@ -435,6 +478,7 @@ void s390_ipl_prepare_cpu(S390CPU *cpu)
 }
 ipl->qipl.netboot_start_addr = cpu_to_be64(ipl->start_addr);
 }
+s390_ipl_set_boot_menu(ipl);
 s390_ipl_prepare_qipl(cpu);
 }
 
diff --git a/hw/s390x/ipl.h b/hw/s390x/ipl.h
index 08926a3..3a37924 100644
--- a/hw/s390x/ipl.h
+++ b/hw/s390x/ipl.h
@@ -91,6 +91,9 @@ void s390_reipl_request(void);
 
 #define QIPL_ADDRESS  0xcc
 
+/* Boot Menu flags */
+#define QIPL_FLAG_BM_OPTS_CMD   0x80
+
 /*
  * The QEMU IPL Parameters will be stored at absolute address
  * 204 (0xcc) which means it is 32-bit word aligned but not
@@ -104,9 +107,11 @@ void s390_reipl_request(void);
  * in pc-bios/s390-ccw/iplb.h.
  */
 struct QemuIplParameters {
-uint8_t  reserved1[4];
+uint8_t  qipl_flags;
+uint8_t  reserved1[3];
 uint64_t netboot_start_addr;
-uint8_t  reserved2[16];
+uint32_t boot_menu_timeout;
+uint8_t  reserved2[12];
 } QEMU_PACKED;
 typedef struct QemuIplParameters QemuIplParameters;
 
diff --git a/pc-bios/s390-ccw/iplb.h b/pc-bios/s390-ccw/iplb.h
index 31d2934..832bb94 100644
--- a/pc-bios/s390-ccw/iplb.h
+++ b/pc-bios/s390-ccw/iplb.h
@@ -74,14 +74,19 @@ extern IplParameterBlock iplb 
__attribute__((__aligned__(PAGE_SIZE)));
 
 #define QIPL_ADDRESS  0xcc
 
+/* Boot Menu flags */
+#define QIPL_FLAG_BM_OPTS_CMD   0x80
+
 /*
  * This definition must be kept in sync with the defininition
  * in hw/s390x/ipl.h
  */
 struct QemuIplParameters {
-uint8_t  reserved1[4];
+uint8_t  qipl_flags;
+uint8_t  reserved1[3];
 uint64_t netboot_start_addr;
-uint8_t  reserved2[16];
+uint32_t boot_menu_timeout;
+uint8_t  reserved2[12];
 } __attribute__ ((packed));
 typedef struct QemuIplParameters QemuIplParameters;
 
-- 
2.7.4




[Qemu-devel] [PATCH v8 05/13] s390-ccw: move auxiliary IPL data to separate location

2018-02-21 Thread Collin L. Walling
The s390-ccw firmware needs some information in support of the
boot process which is not available on the native machine.
Examples are the netboot firmware load address and now the
boot menu parameters.

While storing that data in unused fields of the IPL parameter block
works, that approach could create problems if the parameter block
definition should change in the future. Because then a guest could
overwrite these fields using the set IPLB diagnose.

In fact the data in question is of more global nature and not really
tied to an IPL device, so separating it is rather logical.

This commit introduces a new structure to hold firmware relevant
IPL parameters set by QEMU. The data is stored at location 204 (dec)
and can contain up to 7 32-bit words. This area is available to
programming in the z/Architecture Principles of Operation and
can thus safely be used by the firmware until the IPL has completed.

Signed-off-by: Viktor Mihajlovski <mihaj...@linux.vnet.ibm.com>
Signed-off-by: Collin L. Walling <wall...@linux.vnet.ibm.com>
---
 hw/s390x/ipl.c  | 18 +-
 hw/s390x/ipl.h  | 25 +++--
 pc-bios/s390-ccw/iplb.h | 18 --
 pc-bios/s390-ccw/main.c |  6 +-
 4 files changed, 61 insertions(+), 6 deletions(-)

diff --git a/hw/s390x/ipl.c b/hw/s390x/ipl.c
index 0d06fc1..79f5a58 100644
--- a/hw/s390x/ipl.c
+++ b/hw/s390x/ipl.c
@@ -399,6 +399,21 @@ void s390_reipl_request(void)
 qemu_system_reset_request(SHUTDOWN_CAUSE_GUEST_RESET);
 }
 
+static void s390_ipl_prepare_qipl(S390CPU *cpu)
+{
+S390IPLState *ipl = get_ipl_device();
+uint8_t *addr;
+uint64_t len = 4096;
+
+addr = cpu_physical_memory_map(cpu->env.psa, , 1);
+if (!addr || len < QIPL_ADDRESS + sizeof(QemuIplParameters)) {
+error_report("Cannot set QEMU IPL parameters");
+return;
+}
+memcpy(addr + QIPL_ADDRESS, >qipl, sizeof(QemuIplParameters));
+cpu_physical_memory_unmap(addr, len, 1, len);
+}
+
 void s390_ipl_prepare_cpu(S390CPU *cpu)
 {
 S390IPLState *ipl = get_ipl_device();
@@ -418,8 +433,9 @@ void s390_ipl_prepare_cpu(S390CPU *cpu)
 error_report_err(err);
 vm_stop(RUN_STATE_INTERNAL_ERROR);
 }
-ipl->iplb.ccw.netboot_start_addr = cpu_to_be64(ipl->start_addr);
+ipl->qipl.netboot_start_addr = cpu_to_be64(ipl->start_addr);
 }
+s390_ipl_prepare_qipl(cpu);
 }
 
 static void s390_ipl_reset(DeviceState *dev)
diff --git a/hw/s390x/ipl.h b/hw/s390x/ipl.h
index 8a705e0..08926a3 100644
--- a/hw/s390x/ipl.h
+++ b/hw/s390x/ipl.h
@@ -16,8 +16,7 @@
 #include "cpu.h"
 
 struct IplBlockCcw {
-uint64_t netboot_start_addr;
-uint8_t  reserved0[77];
+uint8_t  reserved0[85];
 uint8_t  ssid;
 uint16_t devno;
 uint8_t  vm_flags;
@@ -90,6 +89,27 @@ void s390_ipl_prepare_cpu(S390CPU *cpu);
 IplParameterBlock *s390_ipl_get_iplb(void);
 void s390_reipl_request(void);
 
+#define QIPL_ADDRESS  0xcc
+
+/*
+ * The QEMU IPL Parameters will be stored at absolute address
+ * 204 (0xcc) which means it is 32-bit word aligned but not
+ * double-word aligned.
+ * Placement of data fields in this area must account for
+ * their alignment needs. E.g., netboot_start_address must
+ * have an offset of n * 8 bytes within the struct in order
+ * to keep it double-word aligned.
+ * The total size of the struct must never exceed 28 bytes.
+ * This definition must be kept in sync with the defininition
+ * in pc-bios/s390-ccw/iplb.h.
+ */
+struct QemuIplParameters {
+uint8_t  reserved1[4];
+uint64_t netboot_start_addr;
+uint8_t  reserved2[16];
+} QEMU_PACKED;
+typedef struct QemuIplParameters QemuIplParameters;
+
 #define TYPE_S390_IPL "s390-ipl"
 #define S390_IPL(obj) OBJECT_CHECK(S390IPLState, (obj), TYPE_S390_IPL)
 
@@ -105,6 +125,7 @@ struct S390IPLState {
 bool iplb_valid;
 bool reipl_requested;
 bool netboot;
+QemuIplParameters qipl;
 
 /*< public >*/
 char *kernel;
diff --git a/pc-bios/s390-ccw/iplb.h b/pc-bios/s390-ccw/iplb.h
index 890aed9..31d2934 100644
--- a/pc-bios/s390-ccw/iplb.h
+++ b/pc-bios/s390-ccw/iplb.h
@@ -13,8 +13,7 @@
 #define IPLB_H
 
 struct IplBlockCcw {
-uint64_t netboot_start_addr;
-uint8_t  reserved0[77];
+uint8_t  reserved0[85];
 uint8_t  ssid;
 uint16_t devno;
 uint8_t  vm_flags;
@@ -73,6 +72,21 @@ typedef struct IplParameterBlock IplParameterBlock;
 
 extern IplParameterBlock iplb __attribute__((__aligned__(PAGE_SIZE)));
 
+#define QIPL_ADDRESS  0xcc
+
+/*
+ * This definition must be kept in sync with the defininition
+ * in hw/s390x/ipl.h
+ */
+struct QemuIplParameters {
+uint8_t  reserved1[4];
+uint64_t netboot_start_addr;
+uint8_t  reserved2[16];
+} __attribute__ ((packed));
+typedef struct QemuIplParameters QemuIplParameters;
+
+extern QemuIplParameters qipl;
+
 #define S390_IPL_TYPE_FCP 0x00
 #define S390_IPL_TYPE_CCW 0x02
 #def

[Qemu-devel] [PATCH v8 12/13] s390-ccw: use zipl values when no boot menu options are present

2018-02-21 Thread Collin L. Walling
If no boot menu options are present, then flag the boot menu to
use the zipl options that were set in the zipl configuration file
(and stored on disk by zipl). These options are found at some
offset prior to the start of the zipl boot menu banner. The zipl
timeout value is limited to a 16-bit unsigned integer and stored
as seconds, so we take care to convert it to milliseconds in order
to conform to the rest of the boot menu functionality. This is
limited to CCW devices.

For reference, the zipl configuration file uses the following
fields in the menu section:

  prompt=1  enable the boot menu
  timeout=X set the timeout to X seconds

To explicitly disregard any boot menu options, then menu=off or
 must be specified.

Signed-off-by: Collin L. Walling <wall...@linux.vnet.ibm.com>
---
 hw/s390x/ipl.c  |  5 +
 hw/s390x/ipl.h  |  1 +
 pc-bios/s390-ccw/iplb.h |  1 +
 pc-bios/s390-ccw/main.c |  3 ++-
 pc-bios/s390-ccw/menu.c | 14 ++
 5 files changed, 23 insertions(+), 1 deletion(-)

diff --git a/hw/s390x/ipl.c b/hw/s390x/ipl.c
index a176c4a..a0f4f40 100644
--- a/hw/s390x/ipl.c
+++ b/hw/s390x/ipl.c
@@ -233,6 +233,11 @@ static void s390_ipl_set_boot_menu(S390IPLState *ipl)
 
 switch (ipl->iplb.pbt) {
 case S390_IPL_TYPE_CCW:
+/* In the absence of -boot menu, use zipl parameters */
+if (!qemu_opt_get(opts, "menu")) {
+*flags |= QIPL_FLAG_BM_OPTS_ZIPL;
+return;
+}
 break;
 default:
 error_report("boot menu is not supported for this device type.");
diff --git a/hw/s390x/ipl.h b/hw/s390x/ipl.h
index 3a37924..1a8adc2 100644
--- a/hw/s390x/ipl.h
+++ b/hw/s390x/ipl.h
@@ -93,6 +93,7 @@ void s390_reipl_request(void);
 
 /* Boot Menu flags */
 #define QIPL_FLAG_BM_OPTS_CMD   0x80
+#define QIPL_FLAG_BM_OPTS_ZIPL  0x40
 
 /*
  * The QEMU IPL Parameters will be stored at absolute address
diff --git a/pc-bios/s390-ccw/iplb.h b/pc-bios/s390-ccw/iplb.h
index 832bb94..7dfce4f 100644
--- a/pc-bios/s390-ccw/iplb.h
+++ b/pc-bios/s390-ccw/iplb.h
@@ -76,6 +76,7 @@ extern IplParameterBlock iplb 
__attribute__((__aligned__(PAGE_SIZE)));
 
 /* Boot Menu flags */
 #define QIPL_FLAG_BM_OPTS_CMD   0x80
+#define QIPL_FLAG_BM_OPTS_ZIPL  0x40
 
 /*
  * This definition must be kept in sync with the defininition
diff --git a/pc-bios/s390-ccw/main.c b/pc-bios/s390-ccw/main.c
index 32ed70e..a7473b0 100644
--- a/pc-bios/s390-ccw/main.c
+++ b/pc-bios/s390-ccw/main.c
@@ -20,6 +20,7 @@ QemuIplParameters qipl;
 
 #define LOADPARM_PROMPT "PROMPT  "
 #define LOADPARM_EMPTY  ""
+#define BOOT_MENU_FLAG_MASK (QIPL_FLAG_BM_OPTS_CMD | QIPL_FLAG_BM_OPTS_ZIPL)
 
 /*
  * Priniciples of Operations (SA22-7832-09) chapter 17 requires that
@@ -91,7 +92,7 @@ static void menu_setup(void)
 
 switch (iplb.pbt) {
 case S390_IPL_TYPE_CCW:
-menu_set_parms(qipl.qipl_flags & QIPL_FLAG_BM_OPTS_CMD,
+menu_set_parms(qipl.qipl_flags & BOOT_MENU_FLAG_MASK,
qipl.boot_menu_timeout);
 return;
 }
diff --git a/pc-bios/s390-ccw/menu.c b/pc-bios/s390-ccw/menu.c
index 4f84bfe..4fc328d 100644
--- a/pc-bios/s390-ccw/menu.c
+++ b/pc-bios/s390-ccw/menu.c
@@ -18,6 +18,10 @@
 #define KEYCODE_BACKSP '\177'
 #define KEYCODE_ENTER  '\r'
 
+/* Offsets from zipl fields to zipl banner start */
+#define ZIPL_TIMEOUT_OFFSET 138
+#define ZIPL_FLAG_OFFSET140
+
 #define TOD_CLOCK_MILLISECOND   0x3e8000
 
 #define LOW_CORE_EXTERNAL_INT_ADDR   0x86
@@ -187,6 +191,16 @@ int menu_get_zipl_boot_index(const char *menu_data)
 {
 size_t len;
 int entries;
+uint16_t zipl_flag = *(uint16_t *)(menu_data - ZIPL_FLAG_OFFSET);
+uint16_t zipl_timeout = *(uint16_t *)(menu_data - ZIPL_TIMEOUT_OFFSET);
+
+if (flag == QIPL_FLAG_BM_OPTS_ZIPL) {
+if (!zipl_flag) {
+return 0; /* Boot default */
+}
+/* zipl stores timeout as seconds */
+timeout = zipl_timeout * 1000;
+}
 
 /* Print and count all menu items, including the banner */
 for (entries = 0; *menu_data; entries++) {
-- 
2.7.4




[Qemu-devel] [PATCH v8 00/13] Interactive Boot Menu for DASD and SCSI Guests on s390x

2018-02-21 Thread Collin L. Walling
Due to the introduction of the QemuIplParameter block and taking some time to
revist some areas, a few chunks of code have been reworked to better align with
those changes. I also think the reworkings improve readability. The same 
functionality is still there, the code just looks a little different (and 
hopefully looks better).

--- [v8] ---

The tl;dr:

cleaned up some early patches based on review, threw zipl boot option code
into its own patch, refactored s390_ipl_set_boot_menu to reflect latest
changes.

The "pls explain":

* cleaned up "s390-ccw: refactor boot map table code"

- removed void ptr casting in a couple of spots

* cleaned up "s390-ccw: set cp_receive mask..." patch

- setting the mask consumes a service interrupt, so there is no need 
for 
  a followup sclp_print

* fixed uitoa based on feedback from v7

* fixed alignment concerns in QemuIplParameters and renamed flags field

- reasoning: necessary; better readability

- s/boot_menu_flags/qipl_flags so this field can be (potentially) used 
for 
  other purposes in the future

- when setting the boot menu parms in the bios, we take care to mask out
  the appropriate qipl_flags for boot menu specific flags

- boot menu flags defines are renamed to be prefixed with "QIPL_FLAG_"

- also updated comment above this struct

* cleaned up "s390-ccw: read user input..." patch

- defines for low core external interrupt code addr and 
  clock comparator interrupt code

- take care to make sure buf remains null terminated when passed to 
read_prompt

* [NEW PATCH] "s390-ccw: use zipl values when no boot menu options are 
present"

- reasoning: better readability; further explanation of feature

- *nothing new added to this patch series here*

- zipl options flag setting and parsing *moved to* this patch

- this attempts to better explain how these fields are used and how 
they get
  parsed

- the commit message gives details on how to set these fields in the 
zipl
  configuration file

- the zipl options are only set for CCW type IPL devices (since no 
  other devices actually support it)

* refactored s390_ipl_set_boot_menu

- reasoning: better readability

- the idea is that we should take care to appropriately set the boot 
menu
  flags for each IPL device type from the beginning. We should not set
  certain flags for devices that cannot support certain features (eg 
SCSI 
  does not support zipl menus, so we should never set the use_zipl_opts 
flag
  for SCSI) 

- since there are no longer boot menu fields specific to each IPL type,
  the switch statement is simply used to detect if the IPL device type
  is capable of a boot menu

- since zipl flags are only set for CCW type IPL devices, I reworked 
  the logic and removed some indentation

* s/menu_check_flags/menu_is_enabled

- reasoning: better readability

- no parameters

- "if menu is enabled" reads better than "if these specific flag bits 
are set"

* removed menu.h

- reasoning: file not needed; less to maintain

- introduction of qipl and better understanding of zipl options led to 
  this decision. by the end of these changes, this file ended up 
  housing 4 function declarations and no longer seemed necessary

- all menu related function declarations are in s390-ccw.h

- boot menu flags are defined in iplb.h (which aligns with 
hw/s390x/ipl.h)

--- [Summary] ---

These patches implement a boot menu for ECKD DASD and SCSI guests on s390x. 
The menu will only appear if the disk has been configured for IPL with the 
zIPL tool and with the following QEMU command line options:

-boot menu=on[,splash-time=X] and/or -machine loadparm='prompt'

The following must be specified for the device to be IPL'd from:

-device ...,bootindex=1

or via the following libvirt domain xml:


  


or


  ...
  


Where X is some positive integer representing time in milliseconds.

 must be specified for the device to be IPL'd from

A loadparm other than 'prompt' will disable the menu and just boot 
the specified entry.

If no boot options are specified, we will attempt to use the values
provided by zipl (ECKD DASD only).

Collin L. Walling (13):
  s390-ccw: refactor boot map table code
  s390-ccw: refactor eckd_block_num to use CHS
  s390-ccw: refactor IPL structs
  s390-ccw: update libc
  s390-ccw: move auxiliary IPL data to separate location
  s390-ccw: parse and set boot menu options
  s390-ccw: set up interactive boot menu parameters
  s390-ccw: read stage2 boot loader data to find menu
  s390-c

[Qemu-devel] [PATCH v8 09/13] s390-ccw: print zipl boot menu

2018-02-21 Thread Collin L. Walling
When the boot menu options are present and the guest's
disk has been configured by the zipl tool, then the user
will be presented with an interactive boot menu with
labeled entries. An example of what the menu might look
like:

zIPL v1.37.1-build-20170714 interactive boot menu.

0. default (linux-4.13.0)

  1. linux-4.13.0
  2. performance
  3. kvm

Signed-off-by: Collin L. Walling <wall...@linux.vnet.ibm.com>
Reviewed-by: Thomas Huth <th...@redhat.com>
---
 pc-bios/s390-ccw/menu.c | 33 -
 1 file changed, 32 insertions(+), 1 deletion(-)

diff --git a/pc-bios/s390-ccw/menu.c b/pc-bios/s390-ccw/menu.c
index ba886be..8f50e55 100644
--- a/pc-bios/s390-ccw/menu.c
+++ b/pc-bios/s390-ccw/menu.c
@@ -15,11 +15,42 @@
 static uint8_t flag;
 static uint64_t timeout;
 
-int menu_get_zipl_boot_index(const char *menu_data)
+static int get_boot_index(int entries)
 {
 return 0; /* implemented next patch */
 }
 
+static void zipl_println(const char *data, size_t len)
+{
+char buf[len + 2];
+
+ebcdic_to_ascii(data, buf, len);
+buf[len] = '\n';
+buf[len + 1] = '\0';
+
+sclp_print(buf);
+}
+
+int menu_get_zipl_boot_index(const char *menu_data)
+{
+size_t len;
+int entries;
+
+/* Print and count all menu items, including the banner */
+for (entries = 0; *menu_data; entries++) {
+len = strlen(menu_data);
+zipl_println(menu_data, len);
+menu_data += len + 1;
+
+if (entries < 2) {
+sclp_print("\n");
+}
+}
+
+sclp_print("\n");
+return get_boot_index(entries - 1); /* subtract 1 to exclude banner */
+}
+
 void menu_set_parms(uint8_t boot_menu_flag, uint32_t boot_menu_timeout)
 {
 flag = boot_menu_flag;
-- 
2.7.4




[Qemu-devel] [PATCH v8 01/13] s390-ccw: refactor boot map table code

2018-02-21 Thread Collin L. Walling
Some ECKD bootmap code was using structs designed for SCSI.
Even though this works, it confuses readability. Add a new
BootMapTable struct to assist with readability in bootmap
entry code. Also:

- replace ScsiMbr in ECKD code with appropriate structs
- fix read_block messages to reflect BootMapTable
- fixup ipl_scsi to use BootMapTable (referred to as Program Table)
- defined value for maximum table entries

Signed-off-by: Collin L. Walling <wall...@linux.vnet.ibm.com>
Reviewed-by: Thomas Huth <th...@redhat.com>
---
 pc-bios/s390-ccw/bootmap.c | 60 +-
 pc-bios/s390-ccw/bootmap.h | 11 -
 2 files changed, 37 insertions(+), 34 deletions(-)

diff --git a/pc-bios/s390-ccw/bootmap.c b/pc-bios/s390-ccw/bootmap.c
index 67a6123..a4eaf24 100644
--- a/pc-bios/s390-ccw/bootmap.c
+++ b/pc-bios/s390-ccw/bootmap.c
@@ -182,24 +182,24 @@ static block_number_t load_eckd_segments(block_number_t 
blk, uint64_t *address)
 return block_nr;
 }
 
-static void run_eckd_boot_script(block_number_t mbr_block_nr)
+static void run_eckd_boot_script(block_number_t bmt_block_nr)
 {
 int i;
 unsigned int loadparm = get_loadparm_index();
 block_number_t block_nr;
 uint64_t address;
-ScsiMbr *bte = (void *)sec; /* Eckd bootmap table entry */
+BootMapTable *bmt = (void *)sec;
 BootMapScript *bms = (void *)sec;
 
 debug_print_int("loadparm", loadparm);
-IPL_assert(loadparm < 31, "loadparm value greater than"
+IPL_assert(loadparm <= MAX_TABLE_ENTRIES, "loadparm value greater than"
" maximum number of boot entries allowed");
 
 memset(sec, FREE_SPACE_FILLER, sizeof(sec));
-read_block(mbr_block_nr, sec, "Cannot read MBR");
+read_block(bmt_block_nr, sec, "Cannot read Boot Map Table");
 
-block_nr = eckd_block_num((void *)&(bte->blockptr[loadparm]));
-IPL_assert(block_nr != -1, "No Boot Map");
+block_nr = eckd_block_num(>entry[loadparm]);
+IPL_assert(block_nr != -1, "Cannot find Boot Map Table Entry");
 
 memset(sec, FREE_SPACE_FILLER, sizeof(sec));
 read_block(block_nr, sec, "Cannot read Boot Map Script");
@@ -223,7 +223,7 @@ static void ipl_eckd_cdl(void)
 XEckdMbr *mbr;
 Ipl2 *ipl2 = (void *)sec;
 IplVolumeLabel *vlbl = (void *)sec;
-block_number_t block_nr;
+block_number_t bmt_block_nr;
 
 /* we have just read the block #0 and recognized it as "IPL1" */
 sclp_print("CDL\n");
@@ -238,8 +238,8 @@ static void ipl_eckd_cdl(void)
 IPL_assert(mbr->dev_type == DEV_TYPE_ECKD,
"Non-ECKD device type in zIPL section of IPL2 record.");
 
-/* save pointer to Boot Script */
-block_nr = eckd_block_num((void *)&(mbr->blockptr));
+/* save pointer to Boot Map Table */
+bmt_block_nr = eckd_block_num(>blockptr);
 
 memset(sec, FREE_SPACE_FILLER, sizeof(sec));
 read_block(2, vlbl, "Cannot read Volume Label at block 2");
@@ -249,7 +249,7 @@ static void ipl_eckd_cdl(void)
"Invalid magic of volser block");
 print_volser(vlbl->f.volser);
 
-run_eckd_boot_script(block_nr);
+run_eckd_boot_script(bmt_block_nr);
 /* no return */
 }
 
@@ -280,7 +280,7 @@ static void print_eckd_ldl_msg(ECKD_IPL_mode_t mode)
 
 static void ipl_eckd_ldl(ECKD_IPL_mode_t mode)
 {
-block_number_t block_nr;
+block_number_t bmt_block_nr;
 BootInfo *bip = (void *)(sec + 0x70); /* BootInfo is MBR for LDL */
 
 if (mode != ECKD_LDL_UNLABELED) {
@@ -299,8 +299,10 @@ static void ipl_eckd_ldl(ECKD_IPL_mode_t mode)
 }
 verify_boot_info(bip);
 
-block_nr = eckd_block_num((void *)&(bip->bp.ipl.bm_ptr.eckd.bptr));
-run_eckd_boot_script(block_nr);
+/* save pointer to Boot Map Table */
+bmt_block_nr = eckd_block_num((void *)>bp.ipl.bm_ptr.eckd.bptr);
+
+run_eckd_boot_script(bmt_block_nr);
 /* no return */
 }
 
@@ -325,7 +327,7 @@ static void print_eckd_msg(void)
 
 static void ipl_eckd(void)
 {
-ScsiMbr *mbr = (void *)sec;
+XEckdMbr *mbr = (void *)sec;
 LDL_VTOC *vlbl = (void *)sec;
 
 print_eckd_msg();
@@ -449,10 +451,8 @@ static void zipl_run(ScsiBlockPtr *pte)
 static void ipl_scsi(void)
 {
 ScsiMbr *mbr = (void *)sec;
-uint8_t *ns, *ns_end;
 int program_table_entries = 0;
-const int pte_len = sizeof(ScsiBlockPtr);
-ScsiBlockPtr *prog_table_entry = NULL;
+BootMapTable *prog_table = (void *)sec;
 unsigned int loadparm = get_loadparm_index();
 
 /* Grab the MBR */
@@ -467,34 +467,28 @@ static void ipl_scsi(void)
 debug_print_int("MBR Version", mbr->version_id);
 IPL_check(mbr->version_id == 1,
   "Unknown MBR layout version, assuming version 1");
-debug_print_int("program table", mbr->blockptr[0].blockno);
-I

[Qemu-devel] [PATCH v8 13/13] s390-ccw: interactive boot menu for scsi

2018-02-21 Thread Collin L. Walling
Interactive boot menu for scsi. This follows a similar procedure
as the interactive menu for eckd dasd. An example follows:

s390x Enumerated Boot Menu.

3 entries detected. Select from index 0 to 2.

Signed-off-by: Collin L. Walling <wall...@linux.vnet.ibm.com>
Reviewed-by: Thomas Huth <th...@redhat.com>
---
 hw/s390x/ipl.c  |  1 +
 pc-bios/s390-ccw/bootmap.c  |  4 
 pc-bios/s390-ccw/main.c |  1 +
 pc-bios/s390-ccw/menu.c | 14 ++
 pc-bios/s390-ccw/s390-ccw.h |  1 +
 5 files changed, 21 insertions(+)

diff --git a/hw/s390x/ipl.c b/hw/s390x/ipl.c
index a0f4f40..566248e 100644
--- a/hw/s390x/ipl.c
+++ b/hw/s390x/ipl.c
@@ -238,6 +238,7 @@ static void s390_ipl_set_boot_menu(S390IPLState *ipl)
 *flags |= QIPL_FLAG_BM_OPTS_ZIPL;
 return;
 }
+case S390_IPL_TYPE_QEMU_SCSI:
 break;
 default:
 error_report("boot menu is not supported for this device type.");
diff --git a/pc-bios/s390-ccw/bootmap.c b/pc-bios/s390-ccw/bootmap.c
index 2701ae6..81dbd4a 100644
--- a/pc-bios/s390-ccw/bootmap.c
+++ b/pc-bios/s390-ccw/bootmap.c
@@ -568,6 +568,10 @@ static void ipl_scsi(void)
 debug_print_int("program table entries", program_table_entries);
 IPL_assert(program_table_entries != 0, "Empty Program Table");
 
+if (menu_is_enabled()) {
+loadparm = menu_get_enum_boot_index(program_table_entries);
+}
+
 debug_print_int("loadparm", loadparm);
 IPL_assert(loadparm <= MAX_TABLE_ENTRIES, "loadparm value greater than"
" maximum number of boot entries allowed");
diff --git a/pc-bios/s390-ccw/main.c b/pc-bios/s390-ccw/main.c
index a7473b0..9d9f8cf 100644
--- a/pc-bios/s390-ccw/main.c
+++ b/pc-bios/s390-ccw/main.c
@@ -92,6 +92,7 @@ static void menu_setup(void)
 
 switch (iplb.pbt) {
 case S390_IPL_TYPE_CCW:
+case S390_IPL_TYPE_QEMU_SCSI:
 menu_set_parms(qipl.qipl_flags & BOOT_MENU_FLAG_MASK,
qipl.boot_menu_timeout);
 return;
diff --git a/pc-bios/s390-ccw/menu.c b/pc-bios/s390-ccw/menu.c
index 4fc328d..16b5310 100644
--- a/pc-bios/s390-ccw/menu.c
+++ b/pc-bios/s390-ccw/menu.c
@@ -217,6 +217,20 @@ int menu_get_zipl_boot_index(const char *menu_data)
 return get_boot_index(entries - 1); /* subtract 1 to exclude banner */
 }
 
+int menu_get_enum_boot_index(int entries)
+{
+char tmp[4];
+
+sclp_print("s390x Enumerated Boot Menu.\n\n");
+
+sclp_print(uitoa(entries, tmp, sizeof(tmp)));
+sclp_print(" entries detected. Select from boot index 0 to ");
+sclp_print(uitoa(entries - 1, tmp, sizeof(tmp)));
+sclp_print(".\n\n");
+
+return get_boot_index(entries);
+}
+
 void menu_set_parms(uint8_t boot_menu_flag, uint32_t boot_menu_timeout)
 {
 flag = boot_menu_flag;
diff --git a/pc-bios/s390-ccw/s390-ccw.h b/pc-bios/s390-ccw/s390-ccw.h
index 56b0c2a..cfcaf3c 100644
--- a/pc-bios/s390-ccw/s390-ccw.h
+++ b/pc-bios/s390-ccw/s390-ccw.h
@@ -91,6 +91,7 @@ void zipl_load(void);
 void menu_set_parms(uint8_t boot_menu_flag, uint32_t boot_menu_timeout);
 bool menu_is_enabled(void);
 int menu_get_zipl_boot_index(const char *menu_data);
+int menu_get_enum_boot_index(int entries);
 
 static inline void fill_hex(char *out, unsigned char val)
 {
-- 
2.7.4




[Qemu-devel] [PATCH v8 08/13] s390-ccw: read stage2 boot loader data to find menu

2018-02-21 Thread Collin L. Walling
Read the stage2 boot loader data block-by-block. We scan the
current block for the string "zIPL" to detect the start of the
boot menu banner. We then load the adjacent blocks (previous
block and next block) to account for the possibility of menu
data spanning multiple blocks.

Signed-off-by: Collin L. Walling <wall...@linux.vnet.ibm.com>
Reviewed-by: Thomas Huth <th...@redhat.com>
---
 pc-bios/s390-ccw/bootmap.c  | 94 ++---
 pc-bios/s390-ccw/bootmap.h  | 23 ++-
 pc-bios/s390-ccw/menu.c |  5 +++
 pc-bios/s390-ccw/s390-ccw.h |  1 +
 4 files changed, 116 insertions(+), 7 deletions(-)

diff --git a/pc-bios/s390-ccw/bootmap.c b/pc-bios/s390-ccw/bootmap.c
index 092fb35..2701ae6 100644
--- a/pc-bios/s390-ccw/bootmap.c
+++ b/pc-bios/s390-ccw/bootmap.c
@@ -83,6 +83,10 @@ static void jump_to_IPL_code(uint64_t address)
 
 static unsigned char _bprs[8*1024]; /* guessed "max" ECKD sector size */
 static const int max_bprs_entries = sizeof(_bprs) / sizeof(ExtEckdBlockPtr);
+static uint8_t _s2[MAX_SECTOR_SIZE * 3] 
__attribute__((__aligned__(PAGE_SIZE)));
+static void *s2_prev_blk = _s2;
+static void *s2_cur_blk = _s2 + MAX_SECTOR_SIZE;
+static void *s2_next_blk = _s2 + MAX_SECTOR_SIZE * 2;
 
 static inline void verify_boot_info(BootInfo *bip)
 {
@@ -182,7 +186,77 @@ static block_number_t load_eckd_segments(block_number_t 
blk, uint64_t *address)
 return block_nr;
 }
 
-static void run_eckd_boot_script(block_number_t bmt_block_nr)
+static bool find_zipl_boot_menu_banner(int *offset)
+{
+int i;
+
+/* Menu banner starts with "zIPL" */
+for (i = 0; i < virtio_get_block_size() - 4; i++) {
+if (magic_match(s2_cur_blk + i, ZIPL_MAGIC_EBCDIC)) {
+*offset = i;
+return true;
+}
+}
+
+return false;
+}
+
+static int eckd_get_boot_menu_index(block_number_t s1b_block_nr)
+{
+block_number_t cur_block_nr;
+block_number_t prev_block_nr = 0;
+block_number_t next_block_nr = 0;
+EckdStage1b *s1b = (void *)sec;
+int banner_offset;
+int i;
+
+/* Get Stage1b data */
+memset(sec, FREE_SPACE_FILLER, sizeof(sec));
+read_block(s1b_block_nr, s1b, "Cannot read stage1b boot loader");
+
+memset(_s2, FREE_SPACE_FILLER, sizeof(_s2));
+
+/* Get Stage2 data */
+for (i = 0; i < STAGE2_BLK_CNT_MAX; i++) {
+cur_block_nr = eckd_block_num(>seek[i].chs);
+
+if (!cur_block_nr) {
+break;
+}
+
+read_block(cur_block_nr, s2_cur_blk, "Cannot read stage2 boot loader");
+
+if (find_zipl_boot_menu_banner(_offset)) {
+/*
+ * Load the adjacent blocks to account for the
+ * possibility of menu data spanning multiple blocks.
+ */
+if (prev_block_nr) {
+read_block(prev_block_nr, s2_prev_blk,
+   "Cannot read stage2 boot loader");
+}
+
+if (i + 1 < STAGE2_BLK_CNT_MAX) {
+next_block_nr = eckd_block_num(>seek[i + 1].chs);
+}
+
+if (next_block_nr) {
+read_block(next_block_nr, s2_next_blk,
+   "Cannot read stage2 boot loader");
+}
+
+return menu_get_zipl_boot_index(s2_cur_blk + banner_offset);
+}
+
+prev_block_nr = cur_block_nr;
+}
+
+sclp_print("No zipl boot menu data found. Booting default entry.");
+return 0;
+}
+
+static void run_eckd_boot_script(block_number_t bmt_block_nr,
+ block_number_t s1b_block_nr)
 {
 int i;
 unsigned int loadparm = get_loadparm_index();
@@ -191,6 +265,10 @@ static void run_eckd_boot_script(block_number_t 
bmt_block_nr)
 BootMapTable *bmt = (void *)sec;
 BootMapScript *bms = (void *)sec;
 
+if (menu_is_enabled()) {
+loadparm = eckd_get_boot_menu_index(s1b_block_nr);
+}
+
 debug_print_int("loadparm", loadparm);
 IPL_assert(loadparm <= MAX_TABLE_ENTRIES, "loadparm value greater than"
" maximum number of boot entries allowed");
@@ -223,7 +301,7 @@ static void ipl_eckd_cdl(void)
 XEckdMbr *mbr;
 EckdCdlIpl2 *ipl2 = (void *)sec;
 IplVolumeLabel *vlbl = (void *)sec;
-block_number_t bmt_block_nr;
+block_number_t bmt_block_nr, s1b_block_nr;
 
 /* we have just read the block #0 and recognized it as "IPL1" */
 sclp_print("CDL\n");
@@ -241,6 +319,9 @@ static void ipl_eckd_cdl(void)
 /* save pointer to Boot Map Table */
 bmt_block_nr = eckd_block_num(>blockptr.xeckd.bptr.chs);
 
+/* save pointer to Stage1b Data */
+s1b_block_nr = eckd_block_num(>stage1.seek[0].chs);
+
 memset(sec, FREE_SPACE_FILLER, sizeof(sec));
 read_block(2, vlbl, "Cannot read Volume Label at block 2");
 IPL_

[Qemu-devel] [PATCH v8 07/13] s390-ccw: set up interactive boot menu parameters

2018-02-21 Thread Collin L. Walling
Reads boot menu flag and timeout values from the iplb and
sets the respective fields for the menu.

Signed-off-by: Collin L. Walling <wall...@linux.vnet.ibm.com>
Reviewed-by: Thomas Huth <th...@redhat.com>
---
 pc-bios/s390-ccw/Makefile   |  2 +-
 pc-bios/s390-ccw/main.c | 24 
 pc-bios/s390-ccw/menu.c | 27 +++
 pc-bios/s390-ccw/s390-ccw.h |  4 
 4 files changed, 56 insertions(+), 1 deletion(-)
 create mode 100644 pc-bios/s390-ccw/menu.c

diff --git a/pc-bios/s390-ccw/Makefile b/pc-bios/s390-ccw/Makefile
index 9f7904f..1712c2d 100644
--- a/pc-bios/s390-ccw/Makefile
+++ b/pc-bios/s390-ccw/Makefile
@@ -9,7 +9,7 @@ $(call set-vpath, $(SRC_PATH)/pc-bios/s390-ccw)
 
 .PHONY : all clean build-all
 
-OBJECTS = start.o main.o bootmap.o sclp.o virtio.o virtio-scsi.o 
virtio-blkdev.o libc.o
+OBJECTS = start.o main.o bootmap.o sclp.o virtio.o virtio-scsi.o 
virtio-blkdev.o libc.o menu.o
 QEMU_CFLAGS := $(filter -W%, $(QEMU_CFLAGS))
 QEMU_CFLAGS += -ffreestanding -fno-delete-null-pointer-checks -msoft-float
 QEMU_CFLAGS += -march=z900 -fPIE -fno-strict-aliasing
diff --git a/pc-bios/s390-ccw/main.c b/pc-bios/s390-ccw/main.c
index e41b264..32ed70e 100644
--- a/pc-bios/s390-ccw/main.c
+++ b/pc-bios/s390-ccw/main.c
@@ -18,6 +18,9 @@ IplParameterBlock iplb 
__attribute__((__aligned__(PAGE_SIZE)));
 static char loadparm[8] = { 0, 0, 0, 0, 0, 0, 0, 0 };
 QemuIplParameters qipl;
 
+#define LOADPARM_PROMPT "PROMPT  "
+#define LOADPARM_EMPTY  ""
+
 /*
  * Priniciples of Operations (SA22-7832-09) chapter 17 requires that
  * a subsystem-identification is at 184-187 and bytes 188-191 are zero
@@ -74,6 +77,26 @@ static bool find_dev(Schib *schib, int dev_no)
 return false;
 }
 
+static void menu_setup(void)
+{
+if (memcmp(loadparm, LOADPARM_PROMPT, 8) == 0) {
+menu_set_parms(QIPL_FLAG_BM_OPTS_CMD, 0);
+return;
+}
+
+/* If loadparm was set to any other value, then do not enable menu */
+if (memcmp(loadparm, LOADPARM_EMPTY, 8) != 0) {
+return;
+}
+
+switch (iplb.pbt) {
+case S390_IPL_TYPE_CCW:
+menu_set_parms(qipl.qipl_flags & QIPL_FLAG_BM_OPTS_CMD,
+   qipl.boot_menu_timeout);
+return;
+}
+}
+
 static void virtio_setup(void)
 {
 Schib schib;
@@ -117,6 +140,7 @@ static void virtio_setup(void)
 default:
 panic("List-directed IPL not supported yet!\n");
 }
+menu_setup();
 } else {
 for (ssid = 0; ssid < 0x3; ssid++) {
 blk_schid.ssid = ssid;
diff --git a/pc-bios/s390-ccw/menu.c b/pc-bios/s390-ccw/menu.c
new file mode 100644
index 000..03d91ea
--- /dev/null
+++ b/pc-bios/s390-ccw/menu.c
@@ -0,0 +1,27 @@
+/*
+ * QEMU S390 Interactive Boot Menu
+ *
+ * Copyright 2018 IBM Corp.
+ * Author: Collin L. Walling <wall...@linux.vnet.ibm.com>
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2 or (at
+ * your option) any later version. See the COPYING file in the top-level
+ * directory.
+ */
+
+#include "libc.h"
+#include "s390-ccw.h"
+
+static uint8_t flag;
+static uint64_t timeout;
+
+void menu_set_parms(uint8_t boot_menu_flag, uint32_t boot_menu_timeout)
+{
+flag = boot_menu_flag;
+timeout = boot_menu_timeout;
+}
+
+bool menu_is_enabled(void)
+{
+return flag;
+}
diff --git a/pc-bios/s390-ccw/s390-ccw.h b/pc-bios/s390-ccw/s390-ccw.h
index 25d4d21..09cc840 100644
--- a/pc-bios/s390-ccw/s390-ccw.h
+++ b/pc-bios/s390-ccw/s390-ccw.h
@@ -84,6 +84,10 @@ ulong get_second(void);
 /* bootmap.c */
 void zipl_load(void);
 
+/* menu.c */
+void menu_set_parms(uint8_t boot_menu_flag, uint32_t boot_menu_timeout);
+bool menu_is_enabled(void);
+
 static inline void fill_hex(char *out, unsigned char val)
 {
 const char hex[] = "0123456789abcdef";
-- 
2.7.4




[Qemu-devel] [PATCH v8 03/13] s390-ccw: refactor IPL structs

2018-02-21 Thread Collin L. Walling
ECKD DASDs have different IPL structures for CDL and LDL
formats. The current Ipl1 and Ipl2 structs follow the CDL
format, so we prepend "EckdCdl" to them. Boot info for LDL
has been moved to a new struct: EckdLdlIpl1.

Signed-off-by: Collin L. Walling <wall...@linux.vnet.ibm.com>
Acked-by: Janosch Frank <fran...@linux.vnet.ibm.com>
Reviewed-by: Thomas Huth <th...@redhat.com>
---
 pc-bios/s390-ccw/bootmap.c | 12 ++--
 pc-bios/s390-ccw/bootmap.h | 37 +
 2 files changed, 27 insertions(+), 22 deletions(-)

diff --git a/pc-bios/s390-ccw/bootmap.c b/pc-bios/s390-ccw/bootmap.c
index 9534f56..a94638d 100644
--- a/pc-bios/s390-ccw/bootmap.c
+++ b/pc-bios/s390-ccw/bootmap.c
@@ -221,7 +221,7 @@ static void run_eckd_boot_script(block_number_t 
bmt_block_nr)
 static void ipl_eckd_cdl(void)
 {
 XEckdMbr *mbr;
-Ipl2 *ipl2 = (void *)sec;
+EckdCdlIpl2 *ipl2 = (void *)sec;
 IplVolumeLabel *vlbl = (void *)sec;
 block_number_t bmt_block_nr;
 
@@ -231,7 +231,7 @@ static void ipl_eckd_cdl(void)
 memset(sec, FREE_SPACE_FILLER, sizeof(sec));
 read_block(1, ipl2, "Cannot read IPL2 record at block 1");
 
-mbr = >u.x.mbr;
+mbr = >mbr;
 IPL_assert(magic_match(mbr, ZIPL_MAGIC), "No zIPL section in IPL2 
record.");
 IPL_assert(block_size_ok(mbr->blockptr.xeckd.bptr.size),
"Bad block size in zIPL section of IPL2 record.");
@@ -281,7 +281,7 @@ static void print_eckd_ldl_msg(ECKD_IPL_mode_t mode)
 static void ipl_eckd_ldl(ECKD_IPL_mode_t mode)
 {
 block_number_t bmt_block_nr;
-BootInfo *bip = (void *)(sec + 0x70); /* BootInfo is MBR for LDL */
+EckdLdlIpl1 *ipl1 = (void *)sec;
 
 if (mode != ECKD_LDL_UNLABELED) {
 print_eckd_ldl_msg(mode);
@@ -292,15 +292,15 @@ static void ipl_eckd_ldl(ECKD_IPL_mode_t mode)
 memset(sec, FREE_SPACE_FILLER, sizeof(sec));
 read_block(0, sec, "Cannot read block 0 to grab boot info.");
 if (mode == ECKD_LDL_UNLABELED) {
-if (!magic_match(bip->magic, ZIPL_MAGIC)) {
+if (!magic_match(ipl1->bip.magic, ZIPL_MAGIC)) {
 return; /* not applicable layout */
 }
 sclp_print("unlabeled LDL.\n");
 }
-verify_boot_info(bip);
+verify_boot_info(>bip);
 
 /* save pointer to Boot Map Table */
-bmt_block_nr = eckd_block_num(>bp.ipl.bm_ptr.eckd.bptr.chs);
+bmt_block_nr = eckd_block_num(>bip.bp.ipl.bm_ptr.eckd.bptr.chs);
 
 run_eckd_boot_script(bmt_block_nr);
 /* no return */
diff --git a/pc-bios/s390-ccw/bootmap.h b/pc-bios/s390-ccw/bootmap.h
index b361084..4bd95cd 100644
--- a/pc-bios/s390-ccw/bootmap.h
+++ b/pc-bios/s390-ccw/bootmap.h
@@ -239,22 +239,27 @@ typedef struct BootInfo {  /* @ 0x70, record #0   
 */
 } bp;
 } __attribute__ ((packed)) BootInfo; /* see also XEckdMbr   */
 
-typedef struct Ipl1 {
-unsigned char key[4]; /* == "IPL1" */
-unsigned char data[24];
-} __attribute__((packed)) Ipl1;
-
-typedef struct Ipl2 {
-unsigned char key[4]; /* == "IPL2" */
-union {
-unsigned char data[144];
-struct {
-unsigned char reserved1[92-4];
-XEckdMbr mbr;
-unsigned char reserved2[144-(92-4)-sizeof(XEckdMbr)];
-} x;
-} u;
-} __attribute__((packed)) Ipl2;
+/*
+ * Structs for IPL
+ */
+#define STAGE2_BLK_CNT_MAX  24 /* Stage 1b can load up to 24 blocks */
+
+typedef struct EckdCdlIpl1 {
+uint8_t key[4]; /* == "IPL1" */
+uint8_t data[24];
+} __attribute__((packed)) EckdCdlIpl1;
+
+typedef struct EckdCdlIpl2 {
+uint8_t key[4]; /* == "IPL2" */
+uint8_t reserved0[88];
+XEckdMbr mbr;
+uint8_t reserved[24];
+} __attribute__((packed)) EckdCdlIpl2;
+
+typedef struct EckdLdlIpl1 {
+uint8_t reserved[112];
+BootInfo bip; /* BootInfo is MBR for LDL */
+} __attribute__((packed)) EckdLdlIpl1;
 
 typedef struct IplVolumeLabel {
 unsigned char key[4]; /* == "VOL1" */
-- 
2.7.4




[Qemu-devel] [PATCH v8 04/13] s390-ccw: update libc

2018-02-21 Thread Collin L. Walling
Moved:
  memcmp from bootmap.h to libc.h (renamed from _memcmp)
  strlen from sclp.c to libc.h (renamed from _strlen)

Added C standard functions:
  isdigit

Added non C-standard function:
  uitoa
  atoui

Signed-off-by: Collin L. Walling <wall...@linux.vnet.ibm.com>
Acked-by: Christian Borntraeger <borntrae...@de.ibm.com>
Reviewed-by: Janosch Frank <fran...@linux.vnet.ibm.com>
---
 pc-bios/s390-ccw/Makefile  |  2 +-
 pc-bios/s390-ccw/bootmap.c |  4 +--
 pc-bios/s390-ccw/bootmap.h | 16 +
 pc-bios/s390-ccw/libc.c| 88 ++
 pc-bios/s390-ccw/libc.h| 37 +--
 pc-bios/s390-ccw/main.c| 17 +
 pc-bios/s390-ccw/sclp.c| 10 +-
 7 files changed, 129 insertions(+), 45 deletions(-)
 create mode 100644 pc-bios/s390-ccw/libc.c

diff --git a/pc-bios/s390-ccw/Makefile b/pc-bios/s390-ccw/Makefile
index 6d0c2ee..9f7904f 100644
--- a/pc-bios/s390-ccw/Makefile
+++ b/pc-bios/s390-ccw/Makefile
@@ -9,7 +9,7 @@ $(call set-vpath, $(SRC_PATH)/pc-bios/s390-ccw)
 
 .PHONY : all clean build-all
 
-OBJECTS = start.o main.o bootmap.o sclp.o virtio.o virtio-scsi.o 
virtio-blkdev.o
+OBJECTS = start.o main.o bootmap.o sclp.o virtio.o virtio-scsi.o 
virtio-blkdev.o libc.o
 QEMU_CFLAGS := $(filter -W%, $(QEMU_CFLAGS))
 QEMU_CFLAGS += -ffreestanding -fno-delete-null-pointer-checks -msoft-float
 QEMU_CFLAGS += -march=z900 -fPIE -fno-strict-aliasing
diff --git a/pc-bios/s390-ccw/bootmap.c b/pc-bios/s390-ccw/bootmap.c
index a94638d..092fb35 100644
--- a/pc-bios/s390-ccw/bootmap.c
+++ b/pc-bios/s390-ccw/bootmap.c
@@ -506,7 +506,7 @@ static bool is_iso_bc_entry_compatible(IsoBcSection *s)
 "Failed to read image sector 0");
 
 /* Checking bytes 8 - 32 for S390 Linux magic */
-return !_memcmp(magic_sec + 8, linux_s390_magic, 24);
+return !memcmp(magic_sec + 8, linux_s390_magic, 24);
 }
 
 /* Location of the current sector of the directory */
@@ -635,7 +635,7 @@ static uint32_t find_iso_bc(void)
 if (vd->type == VOL_DESC_TYPE_BOOT) {
 IsoVdElTorito *et = >vd.boot;
 
-if (!_memcmp(>el_torito[0], el_torito_magic, 32)) {
+if (!memcmp(>el_torito[0], el_torito_magic, 32)) {
 return bswap32(et->bc_offset);
 }
 }
diff --git a/pc-bios/s390-ccw/bootmap.h b/pc-bios/s390-ccw/bootmap.h
index 4bd95cd..4cf7e1e 100644
--- a/pc-bios/s390-ccw/bootmap.h
+++ b/pc-bios/s390-ccw/bootmap.h
@@ -328,20 +328,6 @@ static inline bool magic_match(const void *data, const 
void *magic)
 return *((uint32_t *)data) == *((uint32_t *)magic);
 }
 
-static inline int _memcmp(const void *s1, const void *s2, size_t n)
-{
-int i;
-const uint8_t *p1 = s1, *p2 = s2;
-
-for (i = 0; i < n; i++) {
-if (p1[i] != p2[i]) {
-return p1[i] > p2[i] ? 1 : -1;
-}
-}
-
-return 0;
-}
-
 static inline uint32_t iso_733_to_u32(uint64_t x)
 {
 return (uint32_t)x;
@@ -434,7 +420,7 @@ const uint8_t vol_desc_magic[] = "CD001";
 
 static inline bool is_iso_vd_valid(IsoVolDesc *vd)
 {
-return !_memcmp(>ident[0], vol_desc_magic, 5) &&
+return !memcmp(>ident[0], vol_desc_magic, 5) &&
vd->version == 0x1 &&
vd->type <= VOL_DESC_TYPE_PARTITION;
 }
diff --git a/pc-bios/s390-ccw/libc.c b/pc-bios/s390-ccw/libc.c
new file mode 100644
index 000..38ea77d
--- /dev/null
+++ b/pc-bios/s390-ccw/libc.c
@@ -0,0 +1,88 @@
+/*
+ * libc-style definitions and functions
+ *
+ * Copyright 2018 IBM Corp.
+ * Author(s): Collin L. Walling <wall...@linux.vnet.ibm.com>
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ */
+
+#include "libc.h"
+#include "s390-ccw.h"
+
+/**
+ * atoui:
+ * @str: the string to be converted.
+ *
+ * Given a string @str, convert it to an integer. Leading spaces are
+ * ignored. Any other non-numerical value will terminate the conversion
+ * and return 0. This function only handles numbers between 0 and
+ * UINT64_MAX inclusive.
+ *
+ * Returns: an integer converted from the string @str, or the number 0
+ * if an error occurred.
+ */
+uint64_t atoui(const char *str)
+{
+int val = 0;
+
+if (!str || !str[0]) {
+return 0;
+}
+
+while (*str == ' ') {
+str++;
+}
+
+while (*str) {
+if (!isdigit(*str)) {
+break;
+}
+val = val * 10 + *str - '0';
+str++;
+}
+
+return val;
+}
+
+/**
+ * uitoa:
+ * @num: an integer (base 10) to be converted.
+ * @str: a pointer to a string to store the conversion.
+ * @len: the length of the passed string.
+ *
+ * Given an integer @num, convert it to a string. The string @str must be

[Qemu-devel] [PATCH v8 02/13] s390-ccw: refactor eckd_block_num to use CHS

2018-02-21 Thread Collin L. Walling
Add new cylinder/head/sector struct. Use it to calculate
eckd block numbers instead of a BootMapPointer (which used
eckd chs anyway).

Signed-off-by: Collin L. Walling <wall...@linux.vnet.ibm.com>
Reviewed-by: Thomas Huth <th...@redhat.com>
---
 pc-bios/s390-ccw/bootmap.c | 28 ++--
 pc-bios/s390-ccw/bootmap.h |  8 ++--
 2 files changed, 20 insertions(+), 16 deletions(-)

diff --git a/pc-bios/s390-ccw/bootmap.c b/pc-bios/s390-ccw/bootmap.c
index a4eaf24..9534f56 100644
--- a/pc-bios/s390-ccw/bootmap.c
+++ b/pc-bios/s390-ccw/bootmap.c
@@ -95,32 +95,32 @@ static inline void verify_boot_info(BootInfo *bip)
"Bad block size in zIPL section of the 1st record.");
 }
 
-static block_number_t eckd_block_num(BootMapPointer *p)
+static block_number_t eckd_block_num(EckdCHS *chs)
 {
 const uint64_t sectors = virtio_get_sectors();
 const uint64_t heads = virtio_get_heads();
-const uint64_t cylinder = p->eckd.cylinder
-+ ((p->eckd.head & 0xfff0) << 12);
-const uint64_t head = p->eckd.head & 0x000f;
+const uint64_t cylinder = chs->cylinder
++ ((chs->head & 0xfff0) << 12);
+const uint64_t head = chs->head & 0x000f;
 const block_number_t block = sectors * heads * cylinder
+ sectors * head
-   + p->eckd.sector
+   + chs->sector
- 1; /* block nr starts with zero */
 return block;
 }
 
 static bool eckd_valid_address(BootMapPointer *p)
 {
-const uint64_t head = p->eckd.head & 0x000f;
+const uint64_t head = p->eckd.chs.head & 0x000f;
 
 if (head >= virtio_get_heads()
-||  p->eckd.sector > virtio_get_sectors()
-||  p->eckd.sector <= 0) {
+||  p->eckd.chs.sector > virtio_get_sectors()
+||  p->eckd.chs.sector <= 0) {
 return false;
 }
 
 if (!virtio_guessed_disk_nature() &&
-eckd_block_num(p) >= virtio_get_blocks()) {
+eckd_block_num(>eckd.chs) >= virtio_get_blocks()) {
 return false;
 }
 
@@ -140,7 +140,7 @@ static block_number_t load_eckd_segments(block_number_t 
blk, uint64_t *address)
 do {
 more_data = false;
 for (j = 0;; j++) {
-block_nr = eckd_block_num((void *)&(bprs[j].xeckd));
+block_nr = eckd_block_num([j].xeckd.bptr.chs);
 if (is_null_block_number(block_nr)) { /* end of chunk */
 break;
 }
@@ -198,7 +198,7 @@ static void run_eckd_boot_script(block_number_t 
bmt_block_nr)
 memset(sec, FREE_SPACE_FILLER, sizeof(sec));
 read_block(bmt_block_nr, sec, "Cannot read Boot Map Table");
 
-block_nr = eckd_block_num(>entry[loadparm]);
+block_nr = eckd_block_num(>entry[loadparm].xeckd.bptr.chs);
 IPL_assert(block_nr != -1, "Cannot find Boot Map Table Entry");
 
 memset(sec, FREE_SPACE_FILLER, sizeof(sec));
@@ -206,7 +206,7 @@ static void run_eckd_boot_script(block_number_t 
bmt_block_nr)
 
 for (i = 0; bms->entry[i].type == BOOT_SCRIPT_LOAD; i++) {
 address = bms->entry[i].address.load_address;
-block_nr = eckd_block_num(&(bms->entry[i].blkptr));
+block_nr = eckd_block_num(>entry[i].blkptr.xeckd.bptr.chs);
 
 do {
 block_nr = load_eckd_segments(block_nr, );
@@ -239,7 +239,7 @@ static void ipl_eckd_cdl(void)
"Non-ECKD device type in zIPL section of IPL2 record.");
 
 /* save pointer to Boot Map Table */
-bmt_block_nr = eckd_block_num(>blockptr);
+bmt_block_nr = eckd_block_num(>blockptr.xeckd.bptr.chs);
 
 memset(sec, FREE_SPACE_FILLER, sizeof(sec));
 read_block(2, vlbl, "Cannot read Volume Label at block 2");
@@ -300,7 +300,7 @@ static void ipl_eckd_ldl(ECKD_IPL_mode_t mode)
 verify_boot_info(bip);
 
 /* save pointer to Boot Map Table */
-bmt_block_nr = eckd_block_num((void *)>bp.ipl.bm_ptr.eckd.bptr);
+bmt_block_nr = eckd_block_num(>bp.ipl.bm_ptr.eckd.bptr.chs);
 
 run_eckd_boot_script(bmt_block_nr);
 /* no return */
diff --git a/pc-bios/s390-ccw/bootmap.h b/pc-bios/s390-ccw/bootmap.h
index 486c0f3..b361084 100644
--- a/pc-bios/s390-ccw/bootmap.h
+++ b/pc-bios/s390-ccw/bootmap.h
@@ -32,10 +32,14 @@ typedef struct FbaBlockPtr {
 uint16_t blockct;
 } __attribute__ ((packed)) FbaBlockPtr;
 
-typedef struct EckdBlockPtr {
-uint16_t cylinder; /* cylinder/head/sector is an address of the block */
+typedef struct EckdCHS {
+uint16_t cylinder;
 uint16_t head;
 uint8_t sector;
+} __attribute__ ((packed)) EckdCHS;
+
+typedef struct EckdBlockPtr {
+EckdCHS chs; /* cylinder/head/sector is an address of the block */
 uint16_t size;
 uint8_t count; /* (size_in_blocks-1);
 * it's 0 for TablePtr, ScriptPtr, and SectionPtr */
-- 
2.7.4




[Qemu-devel] [PATCH v8 10/13] s390-ccw: read user input for boot index via the SCLP console

2018-02-21 Thread Collin L. Walling
Implements an sclp_read function to capture input from the
console and a wrapper function that handles parsing certain
characters and adding input to a buffer. The input is checked
for any erroneous values and is handled appropriately.

A prompt will persist until input is entered or the timeout
expires (if one was set). Example:

  Please choose (default will boot in 10 seconds):

Correct input will boot the respective boot index. If the
user's input is empty, 0, or if the timeout expires, then
the default zipl entry will be chosen. If the input is
within the range of available boot entries, then the
selection will be booted. Any erroneous input will cancel
the timeout and re-prompt the user.

Signed-off-by: Collin L. Walling <wall...@linux.vnet.ibm.com>
Reviewed-by: Thomas Huth <th...@redhat.com>
---
 pc-bios/s390-ccw/menu.c | 149 +++-
 pc-bios/s390-ccw/s390-ccw.h |   2 +
 pc-bios/s390-ccw/sclp.c |  19 ++
 pc-bios/s390-ccw/virtio.c   |   2 +-
 4 files changed, 170 insertions(+), 2 deletions(-)

diff --git a/pc-bios/s390-ccw/menu.c b/pc-bios/s390-ccw/menu.c
index 8f50e55..01b120d 100644
--- a/pc-bios/s390-ccw/menu.c
+++ b/pc-bios/s390-ccw/menu.c
@@ -12,12 +12,159 @@
 #include "libc.h"
 #include "s390-ccw.h"
 
+#define KEYCODE_NO_INP '\0'
+#define KEYCODE_ESCAPE '\033'
+#define KEYCODE_BACKSP '\177'
+#define KEYCODE_ENTER  '\r'
+
+#define TOD_CLOCK_MILLISECOND   0x3e8000
+
+#define LOW_CORE_EXTERNAL_INT_ADDR   0x86
+#define CLOCK_COMPARATOR_INT 0X1004
+
 static uint8_t flag;
 static uint64_t timeout;
 
+static inline void enable_clock_int(void)
+{
+uint64_t tmp = 0;
+
+asm volatile(
+"stctg  0,0,%0\n"
+"oi 6+%0, 0x8\n"
+"lctlg  0,0,%0"
+: : "Q" (tmp) : "memory"
+);
+}
+
+static inline void disable_clock_int(void)
+{
+uint64_t tmp = 0;
+
+asm volatile(
+"stctg  0,0,%0\n"
+"ni 6+%0, 0xf7\n"
+"lctlg  0,0,%0"
+: : "Q" (tmp) : "memory"
+);
+}
+
+static inline void set_clock_comparator(uint64_t time)
+{
+asm volatile("sckc %0" : : "Q" (time));
+}
+
+static inline bool check_clock_int(void)
+{
+uint16_t *code = (uint16_t *)LOW_CORE_EXTERNAL_INT_ADDR;
+
+consume_sclp_int();
+
+return *code == CLOCK_COMPARATOR_INT;
+}
+
+static int read_prompt(char *buf, size_t len)
+{
+char inp[2] = {};
+uint8_t idx = 0;
+uint64_t time;
+
+if (timeout) {
+time = get_clock() + timeout * TOD_CLOCK_MILLISECOND;
+set_clock_comparator(time);
+enable_clock_int();
+timeout = 0;
+}
+
+while (!check_clock_int()) {
+
+sclp_read(inp, 1); /* Process only one character at a time */
+
+switch (inp[0]) {
+case KEYCODE_NO_INP:
+case KEYCODE_ESCAPE:
+continue;
+case KEYCODE_BACKSP:
+if (idx > 0) {
+buf[--idx] = 0;
+sclp_print("\b \b");
+}
+continue;
+case KEYCODE_ENTER:
+disable_clock_int();
+return idx;
+default:
+/* Echo input and add to buffer */
+if (idx < len) {
+buf[idx++] = inp[0];
+sclp_print(inp);
+}
+}
+}
+
+disable_clock_int();
+*buf = 0;
+
+return 0;
+}
+
+static int get_index(void)
+{
+char buf[11];
+int len;
+int i;
+
+memset(buf, 0, sizeof(buf));
+
+len = read_prompt(buf, sizeof(buf) - 1);
+
+/* If no input, boot default */
+if (len == 0) {
+return 0;
+}
+
+/* Check for erroneous input */
+for (i = 0; i < len; i++) {
+if (!isdigit(buf[i])) {
+return -1;
+}
+}
+
+return atoui(buf);
+}
+
+static void boot_menu_prompt(bool retry)
+{
+char tmp[11];
+
+if (retry) {
+sclp_print("\nError: undefined configuration"
+   "\nPlease choose:\n");
+} else if (timeout > 0) {
+sclp_print("Please choose (default will boot in ");
+sclp_print(uitoa(timeout / 1000, tmp, sizeof(tmp)));
+sclp_print(" seconds):\n");
+} else {
+sclp_print("Please choose:\n");
+}
+}
+
 static int get_boot_index(int entries)
 {
-return 0; /* implemented next patch */
+int boot_index;
+bool retry = false;
+char tmp[5];
+
+do {
+boot_menu_prompt(retry);
+boot_index = get_index();
+retry = true;
+} while (boot_index < 0 || boot_index >= entries);
+
+sclp_print("\nBooting entry #");
+sclp_print(uitoa(boot_index, tmp, sizeof(tmp)));
+
+return boot_index;
 }
 
 static void zipl_println(const char *data, size_t len)
diff --git a/

Re: [Qemu-devel] [PATCH v7 06/12] s390-ccw: parse and set boot menu options

2018-02-19 Thread Collin L. Walling

On 02/19/2018 10:52 AM, Viktor Mihajlovski wrote:

On 16.02.2018 23:07, Collin L. Walling wrote:
[...]

diff --git a/hw/s390x/ipl.h b/hw/s390x/ipl.h
index 74469b1..f632c59 100644
--- a/hw/s390x/ipl.h
+++ b/hw/s390x/ipl.h
@@ -60,6 +60,9 @@ typedef struct IplBlockQemuScsi IplBlockQemuScsi;

  #define QIPL_ADDRESS  0xcc

+#define BOOT_MENU_FLAG_CMD_OPTS  0x80
+#define BOOT_MENU_FLAG_ZIPL_OPTS 0x40
+
  /*
   * The QEMU IPL Parameters will be stored 32-bit word aligned.
   * Placement of data fields in this area must account for
@@ -67,9 +70,11 @@ typedef struct IplBlockQemuScsi IplBlockQemuScsi;
   * The entire structure must not be larger than 28 bytes.
   */
  struct QemuIplParameters {
-uint8_t  reserved1[4];
+uint8_t  boot_menu_flags;
+uint8_t  reserved1[3];
+uint32_t boot_menu_timeout;
  uint64_t netboot_start_addr;
-uint8_t  reserved2[16];
+uint8_t  reserved2[12];
  } QEMU_PACKED;Since this has to be touched anyway to re-establish proper 
alignment, I

could also imagine to define the struct as
   struct QemuIplParameters {
   struct {
   uint32_t flags:8;
   uint32_t timeout:24;
   } QEMU_PACKED boot_menu;
   uint64_t netboot_start_addr;
   uint8_t  reserved2[16];
   } QEMU_PACKED;
would allow to keep the boot menu stuff together without creating
unnecessary holes.
It would allow for a timeout value of more than 4 hours. The code to set
the boot menu would have to be adapted though to properly deal with the
bitfields.


I'm currently trying to wrap my brain aroundendian conversion with bit 
fields.
I'll investigate the best way to handle this in the mean time, but we 
could also

consider the following:

If neighboring related fields is important, how about moving the fields 
below netboot?


struct QemuIplParameters {
    uint8_t  reserved1[4];
    uint64_t netboot_start_addr;
    uint32_t boot_menu_timeout;
    uint8_t  boot_menu_flags;
    uint8_t  reserved2[11];
  } QEMU_PACKED;


If we're concerned about space, we could retreat to timeout as a 16-bit 
field

(and also bring back the ms -> seconds conversion business)

struct QemuIplParameters {
    uint8_t  boot_menu_flags;
    uint8_t  reserved;
    uint16_t boot_menu_timeout;
    uint64_t netboot_start_addr;
    uint8_t  reserved2[16];
  } QEMU_PACKED;


  typedef struct QemuIplParameters QemuIplParameters;

diff --git a/pc-bios/s390-ccw/iplb.h b/pc-bios/s390-ccw/iplb.h
index a23237e..0e39aa0 100644
--- a/pc-bios/s390-ccw/iplb.h
+++ b/pc-bios/s390-ccw/iplb.h
@@ -81,9 +81,11 @@ extern IplParameterBlock iplb 
__attribute__((__aligned__(PAGE_SIZE)));
   * The entire structure must not be larger than 28 bytes.
   */
  struct QemuIplParameters {
-uint8_t  reserved1[4];
+uint8_t  boot_menu_flags;
+uint8_t  reserved1[3];
+uint32_t boot_menu_timeout;
  uint64_t netboot_start_addr;
-uint8_t  reserved2[16];
+uint8_t  reserved2[12];
  } __attribute__ ((packed));
  typedef struct QemuIplParameters QemuIplParameters;


same here.




--
- Collin L Walling




Re: [Qemu-devel] [qemu-s390x] [PATCH v7 04/12] s390-ccw: update libc

2018-02-19 Thread Collin L. Walling

On 02/19/2018 11:19 AM, Collin L. Walling wrote:

On 02/19/2018 11:00 AM, Thomas Huth wrote:

On 19.02.2018 16:40, Collin L. Walling wrote:

On 02/17/2018 02:48 AM, Thomas Huth wrote:

On 16.02.2018 23:07, Collin L. Walling wrote:
[...]

+/**
+ * uitoa:
+ * @num: an integer (base 10) to be converted.
+ * @str: a pointer to a string to store the conversion.
+ * @len: the length of the passed string.
+ *
+ * Given an integer @num, convert it to a string. The string @str
must be
+ * allocated beforehand. The resulting string will be null
terminated and
+ * returned. This function only handles numbers between 0 and
UINT64_MAX
+ * inclusive.
+ *
+ * Returns: the string @str of the converted integer @num
+ */
+char *uitoa(uint64_t num, char *str, size_t len)
+{
+    size_t num_idx = 0;
+    uint64_t tmp = num;
+
+    IPL_assert(str != NULL, "uitoa: no space allocated to store
string");
+
+    /* Get index to ones place */
+    while ((tmp /= 10) != 0) {
+    num_idx++;
+    }
+
+    /* Check if we have enough space for num and null */
+    IPL_assert(len > num_idx, "uitoa: array too small for 
conversion");

Well, in v5 of this patch you've had "len >= num_idx + 1" where we
agreed that it was wrong. Now you have "len > num_idx" which is pretty
much the same. WTF?
I still think you need "len > num_idx + 1" here to properly take the
trailing NUL-byte into account properly. Please fix it!

   Thomas

You're correct, and my apologies for not correcting the true problem 
here:
I messed up the value of num_idx.  It is off by one, but 
initializing the
value to 1 instead of 0 should fix this. I must've accounted for 
this in

my test file but forgot to update it in the actual source code.

Are you sure that initializing it to 1 is right? Unless you also change
the final while loop in this function, this will put the character into
the wrong location ("str[num_idx] = num % 10 + '0';"). Imagine a number
that only consists of one digit ... the digit will be placed in str[1]
which sounds wrong to me...?

  Thomas

There's that, which we can solve by decrementing num_idx at the start 
of the loop.
We also have to change the line str[num_idx + 1] = '\0'; to no longer 
add 1.

It all boils down to "which way reads better", which I often struggle and
bounce back-and-forth with (way) too much...

Maybe I should also rename num_idx to just "idx" and let the comments 
explain

everything?


How is this for a compromise?

    - start num_idx at 1, provide comment as for why
    - change while loop comment to explain we are "counting the 
_indices_ _of_ _num_"
    - str[num_idx] is assigned \0, and we also decrement num_idx in one 
line

    - in conversion loop, post decrement num_idx as it is used

char *uitoa(int num, char *str, int len)
{
  int num_idx = 1; /* account for NULL */
  int tmp = num;

  assert(str != NULL, "uitoa: no space allocated to store string");

  /* Count indices of num */
  while ((tmp /= 10) != 0)
    num_idx++;

  /* Check if we have enough space for num and null */
  assert(len > num_idx, "uitoa: array too small for conversion");

  str[num_idx--] = '\0';

  /* Convert int to string */
  while (num_idx >= 0) {
    str[num_idx--] = num % 10 + '0';
    num /= 10;
  }

  return str;
}


--
- Collin L Walling




Re: [Qemu-devel] [qemu-s390x] [PATCH v7 04/12] s390-ccw: update libc

2018-02-19 Thread Collin L. Walling

On 02/19/2018 11:00 AM, Thomas Huth wrote:

On 19.02.2018 16:40, Collin L. Walling wrote:

On 02/17/2018 02:48 AM, Thomas Huth wrote:

On 16.02.2018 23:07, Collin L. Walling wrote:
[...]

+/**
+ * uitoa:
+ * @num: an integer (base 10) to be converted.
+ * @str: a pointer to a string to store the conversion.
+ * @len: the length of the passed string.
+ *
+ * Given an integer @num, convert it to a string. The string @str
must be
+ * allocated beforehand. The resulting string will be null
terminated and
+ * returned. This function only handles numbers between 0 and
UINT64_MAX
+ * inclusive.
+ *
+ * Returns: the string @str of the converted integer @num
+ */
+char *uitoa(uint64_t num, char *str, size_t len)
+{
+    size_t num_idx = 0;
+    uint64_t tmp = num;
+
+    IPL_assert(str != NULL, "uitoa: no space allocated to store
string");
+
+    /* Get index to ones place */
+    while ((tmp /= 10) != 0) {
+    num_idx++;
+    }
+
+    /* Check if we have enough space for num and null */
+    IPL_assert(len > num_idx, "uitoa: array too small for conversion");

Well, in v5 of this patch you've had "len >= num_idx + 1" where we
agreed that it was wrong. Now you have "len > num_idx" which is pretty
much the same. WTF?
I still think you need "len > num_idx + 1" here to properly take the
trailing NUL-byte into account properly. Please fix it!

   Thomas


You're correct, and my apologies for not correcting the true problem here:
I messed up the value of num_idx.  It is off by one, but initializing the
value to 1 instead of 0 should fix this. I must've accounted for this in
my test file but forgot to update it in the actual source code.

Are you sure that initializing it to 1 is right? Unless you also change
the final while loop in this function, this will put the character into
the wrong location ("str[num_idx] = num % 10 + '0';"). Imagine a number
that only consists of one digit ... the digit will be placed in str[1]
which sounds wrong to me...?

  Thomas

There's that, which we can solve by decrementing num_idx at the start of 
the loop.

We also have to change the line str[num_idx + 1] = '\0'; to no longer add 1.
It all boils down to "which way reads better", which I often struggle and
bounce back-and-forth with (way) too much...

Maybe I should also rename num_idx to just "idx" and let the comments 
explain

everything?

--
- Collin L Walling




Re: [Qemu-devel] [PATCH v7 11/12] s390-ccw: set cp_receive mask only when needed and consume pending service irqs

2018-02-19 Thread Collin L. Walling

On 02/19/2018 09:17 AM, Christian Borntraeger wrote:


On 02/19/2018 03:15 PM, Christian Borntraeger wrote:


On 02/16/2018 11:07 PM, Collin L. Walling wrote:

It is possible while waiting for multiple types of external
interrupts that we might have pending irqs remaining between
irq consumption and irq-type disabling. Those interrupts
could potentially propagate to the guest after IPL completes
and cause unwanted behavior.

As it is today, the SCLP will only recognize write events that
are enabled by the control program's send and receive masks. To
limit the window for, and prevent further irqs from, ASCII
console events (specifically keystrokes), we should only enable
the control program's receive mask when we need it.

As an additional measure, once we've disabled/cleared the control
program's receive mask, we will print an empty string in order
to consume any pending service interrupt.

Signed-off-by: Collin L. Walling <wall...@linux.vnet.ibm.com>

This should work some comments below:


---
  pc-bios/s390-ccw/menu.c |  5 +
  pc-bios/s390-ccw/s390-ccw.h |  1 +
  pc-bios/s390-ccw/sclp.c | 10 --
  3 files changed, 10 insertions(+), 6 deletions(-)

diff --git a/pc-bios/s390-ccw/menu.c b/pc-bios/s390-ccw/menu.c
index 9601043..14410a8 100644
--- a/pc-bios/s390-ccw/menu.c
+++ b/pc-bios/s390-ccw/menu.c
@@ -11,6 +11,7 @@

  #include "menu.h"
  #include "s390-ccw.h"
+#include "sclp.h"

  #define KEYCODE_NO_INP '\0'
  #define KEYCODE_ESCAPE '\033'
@@ -117,8 +118,12 @@ static int get_index(void)

  memset(buf, 0, sizeof(buf));

+sclp_set_write_mask(SCLP_EVENT_MASK_MSG_ASCII, SCLP_EVENT_MASK_MSG_ASCII);
  len = read_prompt(buf, sizeof(buf));

+sclp_set_write_mask(0, SCLP_EVENT_MASK_MSG_ASCII);
+sclp_print(""); /* Clear any pending service int */
+

Why cant you use consume_sclp_int from start.S and not do any printing?
Shouldnt sclp_set_write_mask always make an interrupt pending?

In fact sclp_set_write_mask should already call consume_sclp_int. Have you seen 
spurious
interrupts?


Correct.  We don't need that print there.  Setting the mask kills two 
birds with one stone.


--
- Collin L Walling




Re: [Qemu-devel] [PATCH v7 11/12] s390-ccw: set cp_receive mask only when needed and consume pending service irqs

2018-02-19 Thread Collin L. Walling

On 02/19/2018 09:15 AM, Christian Borntraeger wrote:


On 02/16/2018 11:07 PM, Collin L. Walling wrote:

It is possible while waiting for multiple types of external
interrupts that we might have pending irqs remaining between
irq consumption and irq-type disabling. Those interrupts
could potentially propagate to the guest after IPL completes
and cause unwanted behavior.

As it is today, the SCLP will only recognize write events that
are enabled by the control program's send and receive masks. To
limit the window for, and prevent further irqs from, ASCII
console events (specifically keystrokes), we should only enable
the control program's receive mask when we need it.

As an additional measure, once we've disabled/cleared the control
program's receive mask, we will print an empty string in order
to consume any pending service interrupt.

Signed-off-by: Collin L. Walling <wall...@linux.vnet.ibm.com>

This should work some comments below:


---
  pc-bios/s390-ccw/menu.c |  5 +
  pc-bios/s390-ccw/s390-ccw.h |  1 +
  pc-bios/s390-ccw/sclp.c | 10 --
  3 files changed, 10 insertions(+), 6 deletions(-)

diff --git a/pc-bios/s390-ccw/menu.c b/pc-bios/s390-ccw/menu.c
index 9601043..14410a8 100644
--- a/pc-bios/s390-ccw/menu.c
+++ b/pc-bios/s390-ccw/menu.c
@@ -11,6 +11,7 @@

  #include "menu.h"
  #include "s390-ccw.h"
+#include "sclp.h"

  #define KEYCODE_NO_INP '\0'
  #define KEYCODE_ESCAPE '\033'
@@ -117,8 +118,12 @@ static int get_index(void)

  memset(buf, 0, sizeof(buf));

+sclp_set_write_mask(SCLP_EVENT_MASK_MSG_ASCII, SCLP_EVENT_MASK_MSG_ASCII);
  len = read_prompt(buf, sizeof(buf));

+sclp_set_write_mask(0, SCLP_EVENT_MASK_MSG_ASCII);
+sclp_print(""); /* Clear any pending service int */
+

Why cant you use consume_sclp_int from start.S and not do any printing?
Shouldnt sclp_set_write_mask always make an interrupt pending?


You're correct.  Setting the mask should solve the issue without
the need for a print.





  /* If no input, boot default */
  if (len == 0) {
  return 0;
diff --git a/pc-bios/s390-ccw/s390-ccw.h b/pc-bios/s390-ccw/s390-ccw.h
index a7e6253..ebdcf86 100644
--- a/pc-bios/s390-ccw/s390-ccw.h
+++ b/pc-bios/s390-ccw/s390-ccw.h
@@ -69,6 +69,7 @@ unsigned int get_loadparm_index(void);

  /* sclp.c */
  void sclp_print(const char *string);
+void sclp_set_write_mask(uint32_t receive_mask, uint32_t send_mask);
  void sclp_setup(void);
  void sclp_get_loadparm_ascii(char *loadparm);
  int sclp_read(char *str, size_t count);
diff --git a/pc-bios/s390-ccw/sclp.c b/pc-bios/s390-ccw/sclp.c
index a2f25eb..3836cb4 100644
--- a/pc-bios/s390-ccw/sclp.c
+++ b/pc-bios/s390-ccw/sclp.c
@@ -46,23 +46,21 @@ static int sclp_service_call(unsigned int command, void 
*sccb)
  return 0;
  }

-static void sclp_set_write_mask(void)
+void sclp_set_write_mask(uint32_t receive_mask, uint32_t send_mask)
  {
  WriteEventMask *sccb = (void *)_sccb;

  sccb->h.length = sizeof(WriteEventMask);
  sccb->mask_length = sizeof(unsigned int);
-sccb->receive_mask = SCLP_EVENT_MASK_MSG_ASCII;
-sccb->cp_receive_mask = SCLP_EVENT_MASK_MSG_ASCII;
-sccb->send_mask = SCLP_EVENT_MASK_MSG_ASCII;
-sccb->cp_send_mask = SCLP_EVENT_MASK_MSG_ASCII;
+sccb->cp_receive_mask = receive_mask;
+sccb->cp_send_mask = send_mask;

Isnt this also fixing another issue. write event mask only takes the
control program (the guest) values and the sclp mask are being returned.


Correct. I'll briefly describe this change in the commit message as well.




  sclp_service_call(SCLP_CMD_WRITE_EVENT_MASK, sccb);
  }

  void sclp_setup(void)
  {
-sclp_set_write_mask();
+sclp_set_write_mask(0, SCLP_EVENT_MASK_MSG_ASCII);
  }

  long write(int fd, const void *str, size_t len)






--
- Collin L Walling




Re: [Qemu-devel] [qemu-s390x] [PATCH v7 04/12] s390-ccw: update libc

2018-02-19 Thread Collin L. Walling

On 02/17/2018 02:48 AM, Thomas Huth wrote:

On 16.02.2018 23:07, Collin L. Walling wrote:
[...]

+/**
+ * uitoa:
+ * @num: an integer (base 10) to be converted.
+ * @str: a pointer to a string to store the conversion.
+ * @len: the length of the passed string.
+ *
+ * Given an integer @num, convert it to a string. The string @str must be
+ * allocated beforehand. The resulting string will be null terminated and
+ * returned. This function only handles numbers between 0 and UINT64_MAX
+ * inclusive.
+ *
+ * Returns: the string @str of the converted integer @num
+ */
+char *uitoa(uint64_t num, char *str, size_t len)
+{
+size_t num_idx = 0;
+uint64_t tmp = num;
+
+IPL_assert(str != NULL, "uitoa: no space allocated to store string");
+
+/* Get index to ones place */
+while ((tmp /= 10) != 0) {
+num_idx++;
+}
+
+/* Check if we have enough space for num and null */
+IPL_assert(len > num_idx, "uitoa: array too small for conversion");

Well, in v5 of this patch you've had "len >= num_idx + 1" where we
agreed that it was wrong. Now you have "len > num_idx" which is pretty
much the same. WTF?
I still think you need "len > num_idx + 1" here to properly take the
trailing NUL-byte into account properly. Please fix it!

  Thomas


You're correct, and my apologies for not correcting the true problem here:
I messed up the value of num_idx.  It is off by one, but initializing the
value to 1 instead of 0 should fix this. I must've accounted for this in
my test file but forgot to update it in the actual source code.

I think the assertion make more sense as len > num_idx, if num_idx were
actually correct. Sorry for this mess...



--
- Collin L Walling




[Qemu-devel] [PATCH v7 08/12] s390-ccw: read stage2 boot loader data to find menu

2018-02-16 Thread Collin L. Walling
Read the stage2 boot loader data block-by-block. We scan the
current block for the string "zIPL" to detect the start of the
boot menu banner. We then load the adjacent blocks (previous
block and next block) to account for the possibility of menu
data spanning multiple blocks.

Signed-off-by: Collin L. Walling <wall...@linux.vnet.ibm.com>
Reviewed-by: Thomas Huth <th...@redhat.com>
---
 pc-bios/s390-ccw/bootmap.c | 94 +++---
 pc-bios/s390-ccw/bootmap.h | 23 +++-
 pc-bios/s390-ccw/menu.c|  5 +++
 pc-bios/s390-ccw/menu.h|  1 +
 4 files changed, 116 insertions(+), 7 deletions(-)

diff --git a/pc-bios/s390-ccw/bootmap.c b/pc-bios/s390-ccw/bootmap.c
index 092fb35..4c6ccf3 100644
--- a/pc-bios/s390-ccw/bootmap.c
+++ b/pc-bios/s390-ccw/bootmap.c
@@ -13,6 +13,7 @@
 #include "bootmap.h"
 #include "virtio.h"
 #include "bswap.h"
+#include "menu.h"
 
 #ifdef DEBUG
 /* #define DEBUG_FALLBACK */
@@ -83,6 +84,10 @@ static void jump_to_IPL_code(uint64_t address)
 
 static unsigned char _bprs[8*1024]; /* guessed "max" ECKD sector size */
 static const int max_bprs_entries = sizeof(_bprs) / sizeof(ExtEckdBlockPtr);
+static uint8_t _s2[MAX_SECTOR_SIZE * 3] 
__attribute__((__aligned__(PAGE_SIZE)));
+static void *s2_prev_blk = _s2;
+static void *s2_cur_blk = _s2 + MAX_SECTOR_SIZE;
+static void *s2_next_blk = _s2 + MAX_SECTOR_SIZE * 2;
 
 static inline void verify_boot_info(BootInfo *bip)
 {
@@ -182,7 +187,76 @@ static block_number_t load_eckd_segments(block_number_t 
blk, uint64_t *address)
 return block_nr;
 }
 
-static void run_eckd_boot_script(block_number_t bmt_block_nr)
+static bool find_zipl_boot_menu_banner(int *offset)
+{
+int i;
+
+/* Menu banner starts with "zIPL" */
+for (i = 0; i < virtio_get_block_size() - 4; i++) {
+if (magic_match(s2_cur_blk + i, ZIPL_MAGIC_EBCDIC)) {
+*offset = i;
+return true;
+}
+}
+
+return false;
+}
+
+static int eckd_get_boot_menu_index(block_number_t s1b_block_nr)
+{
+block_number_t cur_block_nr;
+block_number_t prev_block_nr = 0;
+block_number_t next_block_nr = 0;
+EckdStage1b *s1b = (void *)sec;
+int offset;
+int i;
+
+/* Get Stage1b data */
+memset(sec, FREE_SPACE_FILLER, sizeof(sec));
+read_block(s1b_block_nr, s1b, "Cannot read stage1b boot loader");
+
+memset(_s2, FREE_SPACE_FILLER, sizeof(_s2));
+
+/* Get Stage2 data */
+for (i = 0; i < STAGE2_BLK_CNT_MAX; i++) {
+cur_block_nr = eckd_block_num(>seek[i].chs);
+
+if (!cur_block_nr) {
+break;
+}
+
+read_block(cur_block_nr, s2_cur_blk, "Cannot read stage2 boot loader");
+
+if (find_zipl_boot_menu_banner()) {
+/* Load the adjacent blocks to account for the
+ * possibility of menu data spanning multiple blocks.
+ */
+if (prev_block_nr) {
+read_block(prev_block_nr, s2_prev_blk,
+   "Cannot read stage2 boot loader");
+}
+
+if (i + 1 < STAGE2_BLK_CNT_MAX) {
+next_block_nr = eckd_block_num(>seek[i + 1].chs);
+}
+
+if (next_block_nr) {
+read_block(next_block_nr, s2_next_blk,
+   "Cannot read stage2 boot loader");
+}
+
+return menu_get_zipl_boot_index(s2_cur_blk, offset);
+}
+
+prev_block_nr = cur_block_nr;
+}
+
+sclp_print("No zipl boot menu data found. Booting default entry.");
+return 0;
+}
+
+static void run_eckd_boot_script(block_number_t bmt_block_nr,
+ block_number_t s1b_block_nr)
 {
 int i;
 unsigned int loadparm = get_loadparm_index();
@@ -191,6 +265,10 @@ static void run_eckd_boot_script(block_number_t 
bmt_block_nr)
 BootMapTable *bmt = (void *)sec;
 BootMapScript *bms = (void *)sec;
 
+if (menu_check_flags(BOOT_MENU_FLAG_CMD_OPTS | BOOT_MENU_FLAG_ZIPL_OPTS)) {
+loadparm = eckd_get_boot_menu_index(s1b_block_nr);
+}
+
 debug_print_int("loadparm", loadparm);
 IPL_assert(loadparm <= MAX_TABLE_ENTRIES, "loadparm value greater than"
" maximum number of boot entries allowed");
@@ -223,7 +301,7 @@ static void ipl_eckd_cdl(void)
 XEckdMbr *mbr;
 EckdCdlIpl2 *ipl2 = (void *)sec;
 IplVolumeLabel *vlbl = (void *)sec;
-block_number_t bmt_block_nr;
+block_number_t bmt_block_nr, s1b_block_nr;
 
 /* we have just read the block #0 and recognized it as "IPL1" */
 sclp_print("CDL\n");
@@ -241,6 +319,9 @@ static void ipl_eckd_cdl(void)
 /* save pointer to Boot Map Table */
 bmt_block_nr = eckd_block_num(>blockptr.xeckd.bptr.chs);
 
+/* save pointer to Stage1b Data */
+  

[Qemu-devel] [PATCH v7 09/12] s390-ccw: print zipl boot menu

2018-02-16 Thread Collin L. Walling
When the boot menu options are present and the guest's
disk has been configured by the zipl tool, then the user
will be presented with an interactive boot menu with
labeled entries. An example of what the menu might look
like:

zIPL v1.37.1-build-20170714 interactive boot menu.

  0. default (linux-4.13.0)

  1. linux-4.13.0
  2. performance
  3. kvm

Signed-off-by: Collin L. Walling <wall...@linux.vnet.ibm.com>
Reviewed-by: Thomas Huth <th...@redhat.com>
---
 pc-bios/s390-ccw/menu.c | 49 -
 1 file changed, 48 insertions(+), 1 deletion(-)

diff --git a/pc-bios/s390-ccw/menu.c b/pc-bios/s390-ccw/menu.c
index 5790e0c..9631ac0 100644
--- a/pc-bios/s390-ccw/menu.c
+++ b/pc-bios/s390-ccw/menu.c
@@ -10,13 +10,60 @@
  */
 
 #include "menu.h"
+#include "s390-ccw.h"
+
+/* Offsets from zipl fields to zipl banner start */
+#define ZIPL_TIMEOUT_OFFSET 138
+#define ZIPL_FLAG_OFFSET140
 
 static uint8_t flags;
 static uint64_t timeout;
 
+static int get_boot_index(int entries)
+{
+return 0; /* Implemented next patch */
+}
+
+static void zipl_println(const char *data, size_t len)
+{
+char buf[len + 2];
+
+ebcdic_to_ascii(data, buf, len);
+buf[len] = '\n';
+buf[len + 1] = '\0';
+
+sclp_print(buf);
+}
+
 int menu_get_zipl_boot_index(const void *stage2, int offset)
 {
-return 0; /* implemented next patch */
+const char *data = stage2 + offset;
+uint16_t zipl_flag = *(uint16_t *)(data - ZIPL_FLAG_OFFSET);
+uint16_t zipl_timeout = *(uint16_t *)(data - ZIPL_TIMEOUT_OFFSET);
+size_t len;
+int ct;
+
+if (flags & BOOT_MENU_FLAG_ZIPL_OPTS) {
+if (!zipl_flag) {
+return 0; /* Boot default */
+}
+timeout = zipl_timeout * 1000;
+}
+
+/* Print and count all menu items, including the banner */
+for (ct = 0; *data; ct++) {
+len = strlen(data);
+zipl_println(data, len);
+data += len + 1;
+
+if (ct < 2) {
+sclp_print("\n");
+}
+}
+
+sclp_print("\n");
+
+return get_boot_index(ct - 1);
 }
 
 void menu_set_parms(uint8_t boot_menu_flag, uint32_t boot_menu_timeout)
-- 
2.7.4




[Qemu-devel] [PATCH v7 10/12] s390-ccw: read user input for boot index via the SCLP console

2018-02-16 Thread Collin L. Walling
Implements an sclp_read function to capture input from the
console and a wrapper function that handles parsing certain
characters and adding input to a buffer. The input is checked
for any erroneous values and is handled appropriately.

A prompt will persist until input is entered or the timeout
expires (if one was set). Example:

Please choose (default will boot in 10 seconds):

Correct input will boot the respective boot index. If the
user's input is empty, 0, or if the timeout expires, then
the default zipl entry will be chosen. If the input is
within the range of available boot entries, then the
selection will be booted. Any erroneous input will cancel
the timeout and re-prompt the user.

Signed-off-by: Collin L. Walling <wall...@linux.vnet.ibm.com>
Reviewed-by: Thomas Huth <th...@redhat.com>
---
 pc-bios/s390-ccw/menu.c | 146 +++-
 pc-bios/s390-ccw/s390-ccw.h |   2 +
 pc-bios/s390-ccw/sclp.c |  19 ++
 pc-bios/s390-ccw/virtio.c   |   2 +-
 4 files changed, 167 insertions(+), 2 deletions(-)

diff --git a/pc-bios/s390-ccw/menu.c b/pc-bios/s390-ccw/menu.c
index 9631ac0..9601043 100644
--- a/pc-bios/s390-ccw/menu.c
+++ b/pc-bios/s390-ccw/menu.c
@@ -12,16 +12,160 @@
 #include "menu.h"
 #include "s390-ccw.h"
 
+#define KEYCODE_NO_INP '\0'
+#define KEYCODE_ESCAPE '\033'
+#define KEYCODE_BACKSP '\177'
+#define KEYCODE_ENTER  '\r'
+
 /* Offsets from zipl fields to zipl banner start */
 #define ZIPL_TIMEOUT_OFFSET 138
 #define ZIPL_FLAG_OFFSET140
 
+#define TOD_CLOCK_MILLISECOND   0x3e8000
+
 static uint8_t flags;
 static uint64_t timeout;
 
+static inline void enable_clock_int(void)
+{
+uint64_t tmp = 0;
+
+asm volatile(
+"stctg  0,0,%0\n"
+"oi 6+%0, 0x8\n"
+"lctlg  0,0,%0"
+: : "Q" (tmp) : "memory"
+);
+}
+
+static inline void disable_clock_int(void)
+{
+uint64_t tmp = 0;
+
+asm volatile(
+"stctg  0,0,%0\n"
+"ni 6+%0, 0xf7\n"
+"lctlg  0,0,%0"
+: : "Q" (tmp) : "memory"
+);
+}
+
+static inline void set_clock_comparator(uint64_t time)
+{
+asm volatile("sckc %0" : : "Q" (time));
+}
+
+static inline bool check_clock_int(void)
+{
+uint16_t *code = (uint16_t *)0x86; /* low-core external interrupt code */
+
+consume_sclp_int();
+
+return *code == 0x1004;
+}
+
+static int read_prompt(char *buf, size_t len)
+{
+char inp[2] = {};
+uint8_t idx = 0;
+uint64_t time;
+
+if (timeout) {
+time = get_clock() + timeout * TOD_CLOCK_MILLISECOND;
+set_clock_comparator(time);
+enable_clock_int();
+timeout = 0;
+}
+
+while (!check_clock_int()) {
+
+sclp_read(inp, 1); /* Process only one character at a time */
+
+switch (inp[0]) {
+case KEYCODE_NO_INP:
+case KEYCODE_ESCAPE:
+continue;
+case KEYCODE_BACKSP:
+if (idx > 0) {
+buf[--idx] = 0;
+sclp_print("\b \b");
+}
+continue;
+case KEYCODE_ENTER:
+disable_clock_int();
+return idx;
+default:
+/* Echo input and add to buffer */
+if (idx < len) {
+buf[idx++] = inp[0];
+sclp_print(inp);
+}
+}
+}
+
+disable_clock_int();
+*buf = 0;
+
+return 0;
+}
+
+static int get_index(void)
+{
+char buf[10];
+int len;
+int i;
+
+memset(buf, 0, sizeof(buf));
+
+len = read_prompt(buf, sizeof(buf));
+
+/* If no input, boot default */
+if (len == 0) {
+return 0;
+}
+
+/* Check for erroneous input */
+for (i = 0; i < len; i++) {
+if (!isdigit(buf[i])) {
+return -1;
+}
+}
+
+return atoui(buf);
+}
+
+static void boot_menu_prompt(bool retry)
+{
+char tmp[6];
+
+if (retry) {
+sclp_print("\nError: undefined configuration"
+   "\nPlease choose:\n");
+} else if (timeout > 0) {
+sclp_print("Please choose (default will boot in ");
+sclp_print(uitoa(timeout / 1000, tmp, sizeof(tmp)));
+sclp_print(" seconds):\n");
+} else {
+sclp_print("Please choose:\n");
+}
+}
+
 static int get_boot_index(int entries)
 {
-return 0; /* Implemented next patch */
+int boot_index;
+bool retry = false;
+char tmp[5];
+
+do {
+boot_menu_prompt(retry);
+boot_index = get_index();
+retry = true;
+} while (boot_index < 0 || boot_index >= entries);
+
+sclp_print("\nBooting entry #");
+sclp_print(uitoa(boot_index, tmp, sizeof(tmp)));
+
+return boot_index;
 }
 
 static void zipl_println(const char *d

[Qemu-devel] [PATCH v7 11/12] s390-ccw: set cp_receive mask only when needed and consume pending service irqs

2018-02-16 Thread Collin L. Walling
It is possible while waiting for multiple types of external
interrupts that we might have pending irqs remaining between
irq consumption and irq-type disabling. Those interrupts
could potentially propagate to the guest after IPL completes
and cause unwanted behavior.

As it is today, the SCLP will only recognize write events that
are enabled by the control program's send and receive masks. To
limit the window for, and prevent further irqs from, ASCII
console events (specifically keystrokes), we should only enable
the control program's receive mask when we need it.

As an additional measure, once we've disabled/cleared the control
program's receive mask, we will print an empty string in order
to consume any pending service interrupt.

Signed-off-by: Collin L. Walling <wall...@linux.vnet.ibm.com>
---
 pc-bios/s390-ccw/menu.c |  5 +
 pc-bios/s390-ccw/s390-ccw.h |  1 +
 pc-bios/s390-ccw/sclp.c | 10 --
 3 files changed, 10 insertions(+), 6 deletions(-)

diff --git a/pc-bios/s390-ccw/menu.c b/pc-bios/s390-ccw/menu.c
index 9601043..14410a8 100644
--- a/pc-bios/s390-ccw/menu.c
+++ b/pc-bios/s390-ccw/menu.c
@@ -11,6 +11,7 @@
 
 #include "menu.h"
 #include "s390-ccw.h"
+#include "sclp.h"
 
 #define KEYCODE_NO_INP '\0'
 #define KEYCODE_ESCAPE '\033'
@@ -117,8 +118,12 @@ static int get_index(void)
 
 memset(buf, 0, sizeof(buf));
 
+sclp_set_write_mask(SCLP_EVENT_MASK_MSG_ASCII, SCLP_EVENT_MASK_MSG_ASCII);
 len = read_prompt(buf, sizeof(buf));
 
+sclp_set_write_mask(0, SCLP_EVENT_MASK_MSG_ASCII);
+sclp_print(""); /* Clear any pending service int */
+
 /* If no input, boot default */
 if (len == 0) {
 return 0;
diff --git a/pc-bios/s390-ccw/s390-ccw.h b/pc-bios/s390-ccw/s390-ccw.h
index a7e6253..ebdcf86 100644
--- a/pc-bios/s390-ccw/s390-ccw.h
+++ b/pc-bios/s390-ccw/s390-ccw.h
@@ -69,6 +69,7 @@ unsigned int get_loadparm_index(void);
 
 /* sclp.c */
 void sclp_print(const char *string);
+void sclp_set_write_mask(uint32_t receive_mask, uint32_t send_mask);
 void sclp_setup(void);
 void sclp_get_loadparm_ascii(char *loadparm);
 int sclp_read(char *str, size_t count);
diff --git a/pc-bios/s390-ccw/sclp.c b/pc-bios/s390-ccw/sclp.c
index a2f25eb..3836cb4 100644
--- a/pc-bios/s390-ccw/sclp.c
+++ b/pc-bios/s390-ccw/sclp.c
@@ -46,23 +46,21 @@ static int sclp_service_call(unsigned int command, void 
*sccb)
 return 0;
 }
 
-static void sclp_set_write_mask(void)
+void sclp_set_write_mask(uint32_t receive_mask, uint32_t send_mask)
 {
 WriteEventMask *sccb = (void *)_sccb;
 
 sccb->h.length = sizeof(WriteEventMask);
 sccb->mask_length = sizeof(unsigned int);
-sccb->receive_mask = SCLP_EVENT_MASK_MSG_ASCII;
-sccb->cp_receive_mask = SCLP_EVENT_MASK_MSG_ASCII;
-sccb->send_mask = SCLP_EVENT_MASK_MSG_ASCII;
-sccb->cp_send_mask = SCLP_EVENT_MASK_MSG_ASCII;
+sccb->cp_receive_mask = receive_mask;
+sccb->cp_send_mask = send_mask;
 
 sclp_service_call(SCLP_CMD_WRITE_EVENT_MASK, sccb);
 }
 
 void sclp_setup(void)
 {
-sclp_set_write_mask();
+sclp_set_write_mask(0, SCLP_EVENT_MASK_MSG_ASCII);
 }
 
 long write(int fd, const void *str, size_t len)
-- 
2.7.4




[Qemu-devel] [PATCH v7 04/12] s390-ccw: update libc

2018-02-16 Thread Collin L. Walling
Moved:
  memcmp from bootmap.h to libc.h (renamed from _memcmp)
  strlen from sclp.c to libc.h (renamed from _strlen)

Added C standard functions:
  isdigit

Added non C-standard function:
  uitoa
  atoui

Signed-off-by: Collin L. Walling <wall...@linux.vnet.ibm.com>
Acked-by: Christian Borntraeger <borntrae...@de.ibm.com>
Reviewed-by: Janosch Frank <fran...@linux.vnet.ibm.com>
---
 pc-bios/s390-ccw/Makefile  |  2 +-
 pc-bios/s390-ccw/bootmap.c |  4 +--
 pc-bios/s390-ccw/bootmap.h | 16 +
 pc-bios/s390-ccw/libc.c| 89 ++
 pc-bios/s390-ccw/libc.h| 37 +--
 pc-bios/s390-ccw/main.c| 17 +
 pc-bios/s390-ccw/sclp.c| 10 +-
 7 files changed, 130 insertions(+), 45 deletions(-)
 create mode 100644 pc-bios/s390-ccw/libc.c

diff --git a/pc-bios/s390-ccw/Makefile b/pc-bios/s390-ccw/Makefile
index 6d0c2ee..9f7904f 100644
--- a/pc-bios/s390-ccw/Makefile
+++ b/pc-bios/s390-ccw/Makefile
@@ -9,7 +9,7 @@ $(call set-vpath, $(SRC_PATH)/pc-bios/s390-ccw)
 
 .PHONY : all clean build-all
 
-OBJECTS = start.o main.o bootmap.o sclp.o virtio.o virtio-scsi.o 
virtio-blkdev.o
+OBJECTS = start.o main.o bootmap.o sclp.o virtio.o virtio-scsi.o 
virtio-blkdev.o libc.o
 QEMU_CFLAGS := $(filter -W%, $(QEMU_CFLAGS))
 QEMU_CFLAGS += -ffreestanding -fno-delete-null-pointer-checks -msoft-float
 QEMU_CFLAGS += -march=z900 -fPIE -fno-strict-aliasing
diff --git a/pc-bios/s390-ccw/bootmap.c b/pc-bios/s390-ccw/bootmap.c
index a94638d..092fb35 100644
--- a/pc-bios/s390-ccw/bootmap.c
+++ b/pc-bios/s390-ccw/bootmap.c
@@ -506,7 +506,7 @@ static bool is_iso_bc_entry_compatible(IsoBcSection *s)
 "Failed to read image sector 0");
 
 /* Checking bytes 8 - 32 for S390 Linux magic */
-return !_memcmp(magic_sec + 8, linux_s390_magic, 24);
+return !memcmp(magic_sec + 8, linux_s390_magic, 24);
 }
 
 /* Location of the current sector of the directory */
@@ -635,7 +635,7 @@ static uint32_t find_iso_bc(void)
 if (vd->type == VOL_DESC_TYPE_BOOT) {
 IsoVdElTorito *et = >vd.boot;
 
-if (!_memcmp(>el_torito[0], el_torito_magic, 32)) {
+if (!memcmp(>el_torito[0], el_torito_magic, 32)) {
 return bswap32(et->bc_offset);
 }
 }
diff --git a/pc-bios/s390-ccw/bootmap.h b/pc-bios/s390-ccw/bootmap.h
index 4bd95cd..4cf7e1e 100644
--- a/pc-bios/s390-ccw/bootmap.h
+++ b/pc-bios/s390-ccw/bootmap.h
@@ -328,20 +328,6 @@ static inline bool magic_match(const void *data, const 
void *magic)
 return *((uint32_t *)data) == *((uint32_t *)magic);
 }
 
-static inline int _memcmp(const void *s1, const void *s2, size_t n)
-{
-int i;
-const uint8_t *p1 = s1, *p2 = s2;
-
-for (i = 0; i < n; i++) {
-if (p1[i] != p2[i]) {
-return p1[i] > p2[i] ? 1 : -1;
-}
-}
-
-return 0;
-}
-
 static inline uint32_t iso_733_to_u32(uint64_t x)
 {
 return (uint32_t)x;
@@ -434,7 +420,7 @@ const uint8_t vol_desc_magic[] = "CD001";
 
 static inline bool is_iso_vd_valid(IsoVolDesc *vd)
 {
-return !_memcmp(>ident[0], vol_desc_magic, 5) &&
+return !memcmp(>ident[0], vol_desc_magic, 5) &&
vd->version == 0x1 &&
vd->type <= VOL_DESC_TYPE_PARTITION;
 }
diff --git a/pc-bios/s390-ccw/libc.c b/pc-bios/s390-ccw/libc.c
new file mode 100644
index 000..a144388
--- /dev/null
+++ b/pc-bios/s390-ccw/libc.c
@@ -0,0 +1,89 @@
+/*
+ * libc-style definitions and functions
+ *
+ * Copyright 2018 IBM Corp.
+ * Author(s): Collin L. Walling <wall...@linux.vnet.ibm.com>
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ */
+
+#include "libc.h"
+#include "s390-ccw.h"
+
+/**
+ * atoui:
+ * @str: the string to be converted.
+ *
+ * Given a string @str, convert it to an integer. Leading spaces are
+ * ignored. Any other non-numerical value will terminate the conversion
+ * and return 0. This function only handles numbers between 0 and
+ * UINT64_MAX inclusive.
+ *
+ * Returns: an integer converted from the string @str, or the number 0
+ * if an error occurred.
+ */
+uint64_t atoui(const char *str)
+{
+int val = 0;
+
+if (!str || !str[0]) {
+return 0;
+}
+
+while (*str == ' ') {
+str++;
+}
+
+while (*str) {
+if (!isdigit(*str)) {
+break;
+}
+val = val * 10 + *str - '0';
+str++;
+}
+
+return val;
+}
+
+/**
+ * uitoa:
+ * @num: an integer (base 10) to be converted.
+ * @str: a pointer to a string to store the conversion.
+ * @len: the length of the passed string.
+ *
+ * Given an integer @num, convert it to a string. The string @str must be

[Qemu-devel] [PATCH v7 07/12] s390-ccw: set up interactive boot menu parameters

2018-02-16 Thread Collin L. Walling
Reads boot menu flag and timeout values from the iplb and
sets the respective fields for the menu.

Signed-off-by: Collin L. Walling <wall...@linux.vnet.ibm.com>
Reviewed-by: Thomas Huth <th...@redhat.com>
---
 pc-bios/s390-ccw/Makefile |  2 +-
 pc-bios/s390-ccw/main.c   | 24 
 pc-bios/s390-ccw/menu.c   | 26 ++
 pc-bios/s390-ccw/menu.h   | 23 +++
 4 files changed, 74 insertions(+), 1 deletion(-)
 create mode 100644 pc-bios/s390-ccw/menu.c
 create mode 100644 pc-bios/s390-ccw/menu.h

diff --git a/pc-bios/s390-ccw/Makefile b/pc-bios/s390-ccw/Makefile
index 9f7904f..1712c2d 100644
--- a/pc-bios/s390-ccw/Makefile
+++ b/pc-bios/s390-ccw/Makefile
@@ -9,7 +9,7 @@ $(call set-vpath, $(SRC_PATH)/pc-bios/s390-ccw)
 
 .PHONY : all clean build-all
 
-OBJECTS = start.o main.o bootmap.o sclp.o virtio.o virtio-scsi.o 
virtio-blkdev.o libc.o
+OBJECTS = start.o main.o bootmap.o sclp.o virtio.o virtio-scsi.o 
virtio-blkdev.o libc.o menu.o
 QEMU_CFLAGS := $(filter -W%, $(QEMU_CFLAGS))
 QEMU_CFLAGS += -ffreestanding -fno-delete-null-pointer-checks -msoft-float
 QEMU_CFLAGS += -march=z900 -fPIE -fno-strict-aliasing
diff --git a/pc-bios/s390-ccw/main.c b/pc-bios/s390-ccw/main.c
index e41b264..c643a6b 100644
--- a/pc-bios/s390-ccw/main.c
+++ b/pc-bios/s390-ccw/main.c
@@ -11,6 +11,7 @@
 #include "libc.h"
 #include "s390-ccw.h"
 #include "virtio.h"
+#include "menu.h"
 
 char stack[PAGE_SIZE * 8] __attribute__((__aligned__(PAGE_SIZE)));
 static SubChannelId blk_schid = { .one = 1 };
@@ -18,6 +19,9 @@ IplParameterBlock iplb 
__attribute__((__aligned__(PAGE_SIZE)));
 static char loadparm[8] = { 0, 0, 0, 0, 0, 0, 0, 0 };
 QemuIplParameters qipl;
 
+#define LOADPARM_PROMPT "PROMPT  "
+#define LOADPARM_EMPTY  ""
+
 /*
  * Priniciples of Operations (SA22-7832-09) chapter 17 requires that
  * a subsystem-identification is at 184-187 and bytes 188-191 are zero
@@ -74,6 +78,25 @@ static bool find_dev(Schib *schib, int dev_no)
 return false;
 }
 
+static void menu_setup(void)
+{
+if (memcmp(loadparm, LOADPARM_PROMPT, 8) == 0) {
+menu_set_parms(BOOT_MENU_FLAG_CMD_OPTS, 0);
+return;
+}
+
+/* If loadparm was set to any other value, then do not enable menu */
+if (memcmp(loadparm, LOADPARM_EMPTY, 8) != 0) {
+return;
+}
+
+switch (iplb.pbt) {
+case S390_IPL_TYPE_CCW:
+menu_set_parms(qipl.boot_menu_flags, qipl.boot_menu_timeout);
+return;
+}
+}
+
 static void virtio_setup(void)
 {
 Schib schib;
@@ -117,6 +140,7 @@ static void virtio_setup(void)
 default:
 panic("List-directed IPL not supported yet!\n");
 }
+menu_setup();
 } else {
 for (ssid = 0; ssid < 0x3; ssid++) {
 blk_schid.ssid = ssid;
diff --git a/pc-bios/s390-ccw/menu.c b/pc-bios/s390-ccw/menu.c
new file mode 100644
index 000..3056cfc
--- /dev/null
+++ b/pc-bios/s390-ccw/menu.c
@@ -0,0 +1,26 @@
+/*
+ * QEMU S390 Interactive Boot Menu
+ *
+ * Copyright 2018 IBM Corp.
+ * Author: Collin L. Walling <wall...@linux.vnet.ibm.com>
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2 or (at
+ * your option) any later version. See the COPYING file in the top-level
+ * directory.
+ */
+
+#include "menu.h"
+
+static uint8_t flags;
+static uint64_t timeout;
+
+void menu_set_parms(uint8_t boot_menu_flag, uint32_t boot_menu_timeout)
+{
+flags = boot_menu_flag;
+timeout = boot_menu_timeout;
+}
+
+int menu_check_flags(uint8_t check_flags)
+{
+return flags & check_flags;
+}
diff --git a/pc-bios/s390-ccw/menu.h b/pc-bios/s390-ccw/menu.h
new file mode 100644
index 000..7df4114
--- /dev/null
+++ b/pc-bios/s390-ccw/menu.h
@@ -0,0 +1,23 @@
+/*
+ * QEMU S390 Interactive Boot Menu
+ *
+ * Copyright 2018 IBM Corp.
+ * Author: Collin L. Walling <wall...@linux.vnet.ibm.com>
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2 or (at
+ * your option) any later version. See the COPYING file in the top-level
+ * directory.
+ */
+
+#ifndef MENU_H
+#define MENU_H
+
+#include "libc.h"
+
+#define BOOT_MENU_FLAG_CMD_OPTS  0x80
+#define BOOT_MENU_FLAG_ZIPL_OPTS 0x40
+
+void menu_set_parms(uint8_t boot_menu_flags, uint32_t boot_menu_timeout);
+bool menu_check_flags(uint8_t check_flags);
+
+#endif /* MENU_H */
-- 
2.7.4




[Qemu-devel] [PATCH v7 12/12] s390-ccw: interactive boot menu for scsi

2018-02-16 Thread Collin L. Walling
Interactive boot menu for scsi. This follows a similar procedure
as the interactive menu for eckd dasd. An example follows:

s390x Enumerated Boot Menu.

3 entries detected. Select from index 0 to 2.

Signed-off-by: Collin L. Walling <wall...@linux.vnet.ibm.com>
Reviewed-by: Thomas Huth <th...@redhat.com>
---
 pc-bios/s390-ccw/bootmap.c |  4 
 pc-bios/s390-ccw/main.c|  1 +
 pc-bios/s390-ccw/menu.c| 14 ++
 pc-bios/s390-ccw/menu.h|  1 +
 4 files changed, 20 insertions(+)

diff --git a/pc-bios/s390-ccw/bootmap.c b/pc-bios/s390-ccw/bootmap.c
index 4c6ccf3..05d3308 100644
--- a/pc-bios/s390-ccw/bootmap.c
+++ b/pc-bios/s390-ccw/bootmap.c
@@ -568,6 +568,10 @@ static void ipl_scsi(void)
 debug_print_int("program table entries", program_table_entries);
 IPL_assert(program_table_entries != 0, "Empty Program Table");
 
+if (menu_check_flags(BOOT_MENU_FLAG_CMD_OPTS)) {
+loadparm = menu_get_enum_boot_index(program_table_entries);
+}
+
 debug_print_int("loadparm", loadparm);
 IPL_assert(loadparm <= MAX_TABLE_ENTRIES, "loadparm value greater than"
" maximum number of boot entries allowed");
diff --git a/pc-bios/s390-ccw/main.c b/pc-bios/s390-ccw/main.c
index c643a6b..2226871 100644
--- a/pc-bios/s390-ccw/main.c
+++ b/pc-bios/s390-ccw/main.c
@@ -92,6 +92,7 @@ static void menu_setup(void)
 
 switch (iplb.pbt) {
 case S390_IPL_TYPE_CCW:
+case S390_IPL_TYPE_QEMU_SCSI:
 menu_set_parms(qipl.boot_menu_flags, qipl.boot_menu_timeout);
 return;
 }
diff --git a/pc-bios/s390-ccw/menu.c b/pc-bios/s390-ccw/menu.c
index 14410a8..d104327 100644
--- a/pc-bios/s390-ccw/menu.c
+++ b/pc-bios/s390-ccw/menu.c
@@ -215,6 +215,20 @@ int menu_get_zipl_boot_index(const void *stage2, int 
offset)
 return get_boot_index(ct - 1);
 }
 
+int menu_get_enum_boot_index(int entries)
+{
+char tmp[4];
+
+sclp_print("s390x Enumerated Boot Menu.\n\n");
+
+sclp_print(uitoa(entries, tmp, sizeof(tmp)));
+sclp_print(" entries detected. Select from boot index 0 to ");
+sclp_print(uitoa(entries - 1, tmp, sizeof(tmp)));
+sclp_print(".\n\n");
+
+return get_boot_index(entries);
+}
+
 void menu_set_parms(uint8_t boot_menu_flag, uint32_t boot_menu_timeout)
 {
 flags = boot_menu_flag;
diff --git a/pc-bios/s390-ccw/menu.h b/pc-bios/s390-ccw/menu.h
index c603de3..790516c 100644
--- a/pc-bios/s390-ccw/menu.h
+++ b/pc-bios/s390-ccw/menu.h
@@ -18,6 +18,7 @@
 #define BOOT_MENU_FLAG_ZIPL_OPTS 0x40
 
 int menu_get_zipl_boot_index(const void *stage2, int offset);
+int menu_get_enum_boot_index(int entries);
 void menu_set_parms(uint8_t boot_menu_flags, uint32_t boot_menu_timeout);
 bool menu_check_flags(uint8_t check_flags);
 
-- 
2.7.4




[Qemu-devel] [PATCH v7 05/12] s390-ccw: move auxiliary IPL data to separate location

2018-02-16 Thread Collin L. Walling
The s390-ccw firmware needs some information in support of the
boot process which is not available on the native machine.
Examples are the netboot firmware load address and now the
boot menu parameters.

While storing that data in unused fields of the IPL parameter block
works, that approach could create problems if the parameter block
definition should change in the future. Because then a guest could
overwrite these fields using the set IPLB diagnose.

In fact the data in question is of more global nature and not really
tied to an IPL device, so separating it is rather logical.

This commit introduces a new structure to hold firmware relevant
IPL parameters set by QEMU. The data is stored at location 204 (dec)
and can contain up to 7 32-bit words. This area is available to
programming in the z/Architecture Principles of Operation and
can thus safely be used by the firmware until the IPL has completed.

Signed-off-by: Viktor Mihajlovski <mihaj...@linux.vnet.ibm.com>
Signed-off-by: Collin L. Walling <wall...@linux.vnet.ibm.com>
---
 hw/s390x/ipl.c  | 19 ++-
 hw/s390x/ipl.h  | 19 +--
 pc-bios/s390-ccw/iplb.h | 20 ++--
 pc-bios/s390-ccw/main.c |  6 +-
 4 files changed, 58 insertions(+), 6 deletions(-)

diff --git a/hw/s390x/ipl.c b/hw/s390x/ipl.c
index 0d06fc1..31565ce 100644
--- a/hw/s390x/ipl.c
+++ b/hw/s390x/ipl.c
@@ -399,6 +399,21 @@ void s390_reipl_request(void)
 qemu_system_reset_request(SHUTDOWN_CAUSE_GUEST_RESET);
 }
 
+static void s390_ipl_prepare_qipl(S390CPU *cpu)
+{
+S390IPLState *ipl = get_ipl_device();
+uint8_t *addr;
+uint64_t len = 4096;
+
+addr = cpu_physical_memory_map(cpu->env.psa, , 1);
+if (!addr || len < QIPL_ADDRESS + sizeof(QemuIplParameters)) {
+error_report("Cannot set QEMU IPL parameters");
+return;
+}
+memcpy(addr + QIPL_ADDRESS, >iplb.qipl, sizeof(QemuIplParameters));
+cpu_physical_memory_unmap(addr, len, 1, len);
+}
+
 void s390_ipl_prepare_cpu(S390CPU *cpu)
 {
 S390IPLState *ipl = get_ipl_device();
@@ -418,8 +433,10 @@ void s390_ipl_prepare_cpu(S390CPU *cpu)
 error_report_err(err);
 vm_stop(RUN_STATE_INTERNAL_ERROR);
 }
-ipl->iplb.ccw.netboot_start_addr = cpu_to_be64(ipl->start_addr);
+ipl->iplb.qipl.netboot_start_addr = cpu_to_be64(ipl->start_addr);
 }
+s390_ipl_prepare_qipl(cpu);
+
 }
 
 static void s390_ipl_reset(DeviceState *dev)
diff --git a/hw/s390x/ipl.h b/hw/s390x/ipl.h
index 8a705e0..74469b1 100644
--- a/hw/s390x/ipl.h
+++ b/hw/s390x/ipl.h
@@ -16,8 +16,7 @@
 #include "cpu.h"
 
 struct IplBlockCcw {
-uint64_t netboot_start_addr;
-uint8_t  reserved0[77];
+uint8_t  reserved0[85];
 uint8_t  ssid;
 uint16_t devno;
 uint8_t  vm_flags;
@@ -59,6 +58,21 @@ typedef struct IplBlockQemuScsi IplBlockQemuScsi;
 
 #define DIAG308_FLAGS_LP_VALID 0x80
 
+#define QIPL_ADDRESS  0xcc
+
+/*
+ * The QEMU IPL Parameters will be stored 32-bit word aligned.
+ * Placement of data fields in this area must account for
+ * their alignment needs.
+ * The entire structure must not be larger than 28 bytes.
+ */
+struct QemuIplParameters {
+uint8_t  reserved1[4];
+uint64_t netboot_start_addr;
+uint8_t  reserved2[16];
+} QEMU_PACKED;
+typedef struct QemuIplParameters QemuIplParameters;
+
 union IplParameterBlock {
 struct {
 uint32_t len;
@@ -74,6 +88,7 @@ union IplParameterBlock {
 IplBlockFcp fcp;
 IplBlockQemuScsi scsi;
 };
+QemuIplParameters qipl;
 } QEMU_PACKED;
 struct {
 uint8_t  reserved1[110];
diff --git a/pc-bios/s390-ccw/iplb.h b/pc-bios/s390-ccw/iplb.h
index 890aed9..a23237e 100644
--- a/pc-bios/s390-ccw/iplb.h
+++ b/pc-bios/s390-ccw/iplb.h
@@ -13,8 +13,7 @@
 #define IPLB_H
 
 struct IplBlockCcw {
-uint64_t netboot_start_addr;
-uint8_t  reserved0[77];
+uint8_t  reserved0[85];
 uint8_t  ssid;
 uint16_t devno;
 uint8_t  vm_flags;
@@ -73,6 +72,23 @@ typedef struct IplParameterBlock IplParameterBlock;
 
 extern IplParameterBlock iplb __attribute__((__aligned__(PAGE_SIZE)));
 
+#define QIPL_ADDRESS  0xcc
+
+/*
+ * The QEMU IPL Parameters will be stored 32-bit word aligned.
+ * Placement of data fields in this area must account for
+ * their alignment needs.
+ * The entire structure must not be larger than 28 bytes.
+ */
+struct QemuIplParameters {
+uint8_t  reserved1[4];
+uint64_t netboot_start_addr;
+uint8_t  reserved2[16];
+} __attribute__ ((packed));
+typedef struct QemuIplParameters QemuIplParameters;
+
+extern QemuIplParameters qipl;
+
 #define S390_IPL_TYPE_FCP 0x00
 #define S390_IPL_TYPE_CCW 0x02
 #define S390_IPL_TYPE_QEMU_SCSI 0xff
diff --git a/pc-bios/s390-ccw/main.c b/pc-bios/s390-ccw/main.c
index e857ce4..e41b264 100644
--- a/pc-bios/s390-ccw/main.c
+++ b/pc-bios/s390-ccw/main.c
@@ -16,6 +16,7 @@ char stack

[Qemu-devel] [PATCH v7 01/12] s390-ccw: refactor boot map table code

2018-02-16 Thread Collin L. Walling
Some ECKD bootmap code was using structs designed for SCSI.
Even though this works, it confuses readability. Add a new
BootMapTable struct to assist with readability in bootmap
entry code. Also:

- replace ScsiMbr in ECKD code with appropriate structs
- fix read_block messages to reflect BootMapTable
- fixup ipl_scsi to use BootMapTable (referred to as Program Table)
- defined value for maximum table entries

Signed-off-by: Collin L. Walling <wall...@linux.vnet.ibm.com>
---
 pc-bios/s390-ccw/bootmap.c | 60 +-
 pc-bios/s390-ccw/bootmap.h | 11 -
 2 files changed, 37 insertions(+), 34 deletions(-)

diff --git a/pc-bios/s390-ccw/bootmap.c b/pc-bios/s390-ccw/bootmap.c
index 67a6123..286de40 100644
--- a/pc-bios/s390-ccw/bootmap.c
+++ b/pc-bios/s390-ccw/bootmap.c
@@ -182,24 +182,24 @@ static block_number_t load_eckd_segments(block_number_t 
blk, uint64_t *address)
 return block_nr;
 }
 
-static void run_eckd_boot_script(block_number_t mbr_block_nr)
+static void run_eckd_boot_script(block_number_t bmt_block_nr)
 {
 int i;
 unsigned int loadparm = get_loadparm_index();
 block_number_t block_nr;
 uint64_t address;
-ScsiMbr *bte = (void *)sec; /* Eckd bootmap table entry */
+BootMapTable *bmt = (void *)sec;
 BootMapScript *bms = (void *)sec;
 
 debug_print_int("loadparm", loadparm);
-IPL_assert(loadparm < 31, "loadparm value greater than"
+IPL_assert(loadparm <= MAX_TABLE_ENTRIES, "loadparm value greater than"
" maximum number of boot entries allowed");
 
 memset(sec, FREE_SPACE_FILLER, sizeof(sec));
-read_block(mbr_block_nr, sec, "Cannot read MBR");
+read_block(bmt_block_nr, sec, "Cannot read Boot Map Table");
 
-block_nr = eckd_block_num((void *)&(bte->blockptr[loadparm]));
-IPL_assert(block_nr != -1, "No Boot Map");
+block_nr = eckd_block_num((void *)>entry[loadparm]);
+IPL_assert(block_nr != -1, "Cannot find Boot Map Table Entry");
 
 memset(sec, FREE_SPACE_FILLER, sizeof(sec));
 read_block(block_nr, sec, "Cannot read Boot Map Script");
@@ -223,7 +223,7 @@ static void ipl_eckd_cdl(void)
 XEckdMbr *mbr;
 Ipl2 *ipl2 = (void *)sec;
 IplVolumeLabel *vlbl = (void *)sec;
-block_number_t block_nr;
+block_number_t bmt_block_nr;
 
 /* we have just read the block #0 and recognized it as "IPL1" */
 sclp_print("CDL\n");
@@ -238,8 +238,8 @@ static void ipl_eckd_cdl(void)
 IPL_assert(mbr->dev_type == DEV_TYPE_ECKD,
"Non-ECKD device type in zIPL section of IPL2 record.");
 
-/* save pointer to Boot Script */
-block_nr = eckd_block_num((void *)&(mbr->blockptr));
+/* save pointer to Boot Map Table */
+bmt_block_nr = eckd_block_num((void *)>blockptr);
 
 memset(sec, FREE_SPACE_FILLER, sizeof(sec));
 read_block(2, vlbl, "Cannot read Volume Label at block 2");
@@ -249,7 +249,7 @@ static void ipl_eckd_cdl(void)
"Invalid magic of volser block");
 print_volser(vlbl->f.volser);
 
-run_eckd_boot_script(block_nr);
+run_eckd_boot_script(bmt_block_nr);
 /* no return */
 }
 
@@ -280,7 +280,7 @@ static void print_eckd_ldl_msg(ECKD_IPL_mode_t mode)
 
 static void ipl_eckd_ldl(ECKD_IPL_mode_t mode)
 {
-block_number_t block_nr;
+block_number_t bmt_block_nr;
 BootInfo *bip = (void *)(sec + 0x70); /* BootInfo is MBR for LDL */
 
 if (mode != ECKD_LDL_UNLABELED) {
@@ -299,8 +299,10 @@ static void ipl_eckd_ldl(ECKD_IPL_mode_t mode)
 }
 verify_boot_info(bip);
 
-block_nr = eckd_block_num((void *)&(bip->bp.ipl.bm_ptr.eckd.bptr));
-run_eckd_boot_script(block_nr);
+/* save pointer to Boot Map Table */
+bmt_block_nr = eckd_block_num((void *)>bp.ipl.bm_ptr.eckd.bptr);
+
+run_eckd_boot_script(bmt_block_nr);
 /* no return */
 }
 
@@ -325,7 +327,7 @@ static void print_eckd_msg(void)
 
 static void ipl_eckd(void)
 {
-ScsiMbr *mbr = (void *)sec;
+XEckdMbr *mbr = (void *)sec;
 LDL_VTOC *vlbl = (void *)sec;
 
 print_eckd_msg();
@@ -449,10 +451,8 @@ static void zipl_run(ScsiBlockPtr *pte)
 static void ipl_scsi(void)
 {
 ScsiMbr *mbr = (void *)sec;
-uint8_t *ns, *ns_end;
 int program_table_entries = 0;
-const int pte_len = sizeof(ScsiBlockPtr);
-ScsiBlockPtr *prog_table_entry = NULL;
+BootMapTable *prog_table = (void *)sec;
 unsigned int loadparm = get_loadparm_index();
 
 /* Grab the MBR */
@@ -467,34 +467,28 @@ static void ipl_scsi(void)
 debug_print_int("MBR Version", mbr->version_id);
 IPL_check(mbr->version_id == 1,
   "Unknown MBR layout version, assuming version 1");
-debug_print_int("program table", mbr->blockptr[0].blockno);
-IPL_assert(mbr->bloc

[Qemu-devel] [PATCH v7 06/12] s390-ccw: parse and set boot menu options

2018-02-16 Thread Collin L. Walling
Set boot menu options for an s390 guest and store them in
the iplb. These options are set via the QEMU command line
option:

-boot menu=on|off[,splash-time=X]

or via the libvirt domain xml:


  


Where X represents some positive integer representing
milliseconds.

Any value set for loadparm will override all boot menu options.
If loadparm=PROMPT, then the menu will be enabled without a
timeout.

The absence of any boot options on the command line will flag
to later use the zipl boot loader values.

Signed-off-by: Collin L. Walling <wall...@linux.vnet.ibm.com>
Reviewed-by: Janosch Frank <fran...@linux.vnet.ibm.com>
Reviewed-by: Thomas Huth <th...@redhat.com>
---
 hw/s390x/ipl.c  | 48 
 hw/s390x/ipl.h  |  9 +++--
 pc-bios/s390-ccw/iplb.h |  6 --
 3 files changed, 59 insertions(+), 4 deletions(-)

diff --git a/hw/s390x/ipl.c b/hw/s390x/ipl.c
index 31565ce..c8109f5 100644
--- a/hw/s390x/ipl.c
+++ b/hw/s390x/ipl.c
@@ -23,6 +23,9 @@
 #include "hw/s390x/ebcdic.h"
 #include "ipl.h"
 #include "qemu/error-report.h"
+#include "qemu/config-file.h"
+#include "qemu/cutils.h"
+#include "qemu/option.h"
 
 #define KERN_IMAGE_START0x01UL
 #define KERN_PARM_AREA  0x010480UL
@@ -219,6 +222,50 @@ static Property s390_ipl_properties[] = {
 DEFINE_PROP_END_OF_LIST(),
 };
 
+static void s390_ipl_set_boot_menu(IplParameterBlock *iplb)
+{
+QemuOptsList *plist = qemu_find_opts("boot-opts");
+QemuOpts *opts = QTAILQ_FIRST(>head);
+uint8_t *flags;
+uint32_t *timeout;
+const char *tmp;
+unsigned long splash_time = 0;
+
+switch (iplb->pbt) {
+case S390_IPL_TYPE_CCW:
+case S390_IPL_TYPE_QEMU_SCSI:
+flags = >qipl.boot_menu_flags;
+timeout = >qipl.boot_menu_timeout;
+break;
+default:
+error_report("boot menu is not supported for this device type.");
+return;
+}
+
+/* In the absence of -boot menu, use zipl parameters */
+if (!qemu_opt_get(opts, "menu")) {
+*flags = BOOT_MENU_FLAG_ZIPL_OPTS;
+} else if (boot_menu) {
+*flags = BOOT_MENU_FLAG_CMD_OPTS;
+
+tmp = qemu_opt_get(opts, "splash-time");
+
+if (tmp && qemu_strtoul(tmp, NULL, 10, _time)) {
+error_report("splash-time is invalid, forcing it to 0.");
+splash_time = 0;
+return;
+}
+
+if (splash_time > 0x) {
+error_report("splash-time is too large, forcing it to max value.");
+splash_time = 0x;
+return;
+}
+
+*timeout = cpu_to_be32(splash_time);
+}
+}
+
 static bool s390_gen_initial_iplb(S390IPLState *ipl)
 {
 DeviceState *dev_st;
@@ -435,6 +482,7 @@ void s390_ipl_prepare_cpu(S390CPU *cpu)
 }
 ipl->iplb.qipl.netboot_start_addr = cpu_to_be64(ipl->start_addr);
 }
+s390_ipl_set_boot_menu(>iplb);
 s390_ipl_prepare_qipl(cpu);
 
 }
diff --git a/hw/s390x/ipl.h b/hw/s390x/ipl.h
index 74469b1..f632c59 100644
--- a/hw/s390x/ipl.h
+++ b/hw/s390x/ipl.h
@@ -60,6 +60,9 @@ typedef struct IplBlockQemuScsi IplBlockQemuScsi;
 
 #define QIPL_ADDRESS  0xcc
 
+#define BOOT_MENU_FLAG_CMD_OPTS  0x80
+#define BOOT_MENU_FLAG_ZIPL_OPTS 0x40
+
 /*
  * The QEMU IPL Parameters will be stored 32-bit word aligned.
  * Placement of data fields in this area must account for
@@ -67,9 +70,11 @@ typedef struct IplBlockQemuScsi IplBlockQemuScsi;
  * The entire structure must not be larger than 28 bytes.
  */
 struct QemuIplParameters {
-uint8_t  reserved1[4];
+uint8_t  boot_menu_flags;
+uint8_t  reserved1[3];
+uint32_t boot_menu_timeout;
 uint64_t netboot_start_addr;
-uint8_t  reserved2[16];
+uint8_t  reserved2[12];
 } QEMU_PACKED;
 typedef struct QemuIplParameters QemuIplParameters;
 
diff --git a/pc-bios/s390-ccw/iplb.h b/pc-bios/s390-ccw/iplb.h
index a23237e..0e39aa0 100644
--- a/pc-bios/s390-ccw/iplb.h
+++ b/pc-bios/s390-ccw/iplb.h
@@ -81,9 +81,11 @@ extern IplParameterBlock iplb 
__attribute__((__aligned__(PAGE_SIZE)));
  * The entire structure must not be larger than 28 bytes.
  */
 struct QemuIplParameters {
-uint8_t  reserved1[4];
+uint8_t  boot_menu_flags;
+uint8_t  reserved1[3];
+uint32_t boot_menu_timeout;
 uint64_t netboot_start_addr;
-uint8_t  reserved2[16];
+uint8_t  reserved2[12];
 } __attribute__ ((packed));
 typedef struct QemuIplParameters QemuIplParameters;
 
-- 
2.7.4




[Qemu-devel] [PATCH v7 03/12] s390-ccw: refactor IPL structs

2018-02-16 Thread Collin L. Walling
ECKD DASDs have different IPL structures for CDL and LDL
formats. The current Ipl1 and Ipl2 structs follow the CDL
format, so we prepend "EckdCdl" to them. Boot info for LDL
has been moved to a new struct: EckdLdlIpl1.

Signed-off-by: Collin L. Walling <wall...@linux.vnet.ibm.com>
Acked-by: Janosch Frank <fran...@linux.vnet.ibm.com>
Reviewed-by: Thomas Huth <th...@redhat.com>
---
 pc-bios/s390-ccw/bootmap.c | 12 ++--
 pc-bios/s390-ccw/bootmap.h | 37 +
 2 files changed, 27 insertions(+), 22 deletions(-)

diff --git a/pc-bios/s390-ccw/bootmap.c b/pc-bios/s390-ccw/bootmap.c
index 9534f56..a94638d 100644
--- a/pc-bios/s390-ccw/bootmap.c
+++ b/pc-bios/s390-ccw/bootmap.c
@@ -221,7 +221,7 @@ static void run_eckd_boot_script(block_number_t 
bmt_block_nr)
 static void ipl_eckd_cdl(void)
 {
 XEckdMbr *mbr;
-Ipl2 *ipl2 = (void *)sec;
+EckdCdlIpl2 *ipl2 = (void *)sec;
 IplVolumeLabel *vlbl = (void *)sec;
 block_number_t bmt_block_nr;
 
@@ -231,7 +231,7 @@ static void ipl_eckd_cdl(void)
 memset(sec, FREE_SPACE_FILLER, sizeof(sec));
 read_block(1, ipl2, "Cannot read IPL2 record at block 1");
 
-mbr = >u.x.mbr;
+mbr = >mbr;
 IPL_assert(magic_match(mbr, ZIPL_MAGIC), "No zIPL section in IPL2 
record.");
 IPL_assert(block_size_ok(mbr->blockptr.xeckd.bptr.size),
"Bad block size in zIPL section of IPL2 record.");
@@ -281,7 +281,7 @@ static void print_eckd_ldl_msg(ECKD_IPL_mode_t mode)
 static void ipl_eckd_ldl(ECKD_IPL_mode_t mode)
 {
 block_number_t bmt_block_nr;
-BootInfo *bip = (void *)(sec + 0x70); /* BootInfo is MBR for LDL */
+EckdLdlIpl1 *ipl1 = (void *)sec;
 
 if (mode != ECKD_LDL_UNLABELED) {
 print_eckd_ldl_msg(mode);
@@ -292,15 +292,15 @@ static void ipl_eckd_ldl(ECKD_IPL_mode_t mode)
 memset(sec, FREE_SPACE_FILLER, sizeof(sec));
 read_block(0, sec, "Cannot read block 0 to grab boot info.");
 if (mode == ECKD_LDL_UNLABELED) {
-if (!magic_match(bip->magic, ZIPL_MAGIC)) {
+if (!magic_match(ipl1->bip.magic, ZIPL_MAGIC)) {
 return; /* not applicable layout */
 }
 sclp_print("unlabeled LDL.\n");
 }
-verify_boot_info(bip);
+verify_boot_info(>bip);
 
 /* save pointer to Boot Map Table */
-bmt_block_nr = eckd_block_num(>bp.ipl.bm_ptr.eckd.bptr.chs);
+bmt_block_nr = eckd_block_num(>bip.bp.ipl.bm_ptr.eckd.bptr.chs);
 
 run_eckd_boot_script(bmt_block_nr);
 /* no return */
diff --git a/pc-bios/s390-ccw/bootmap.h b/pc-bios/s390-ccw/bootmap.h
index b361084..4bd95cd 100644
--- a/pc-bios/s390-ccw/bootmap.h
+++ b/pc-bios/s390-ccw/bootmap.h
@@ -239,22 +239,27 @@ typedef struct BootInfo {  /* @ 0x70, record #0   
 */
 } bp;
 } __attribute__ ((packed)) BootInfo; /* see also XEckdMbr   */
 
-typedef struct Ipl1 {
-unsigned char key[4]; /* == "IPL1" */
-unsigned char data[24];
-} __attribute__((packed)) Ipl1;
-
-typedef struct Ipl2 {
-unsigned char key[4]; /* == "IPL2" */
-union {
-unsigned char data[144];
-struct {
-unsigned char reserved1[92-4];
-XEckdMbr mbr;
-unsigned char reserved2[144-(92-4)-sizeof(XEckdMbr)];
-} x;
-} u;
-} __attribute__((packed)) Ipl2;
+/*
+ * Structs for IPL
+ */
+#define STAGE2_BLK_CNT_MAX  24 /* Stage 1b can load up to 24 blocks */
+
+typedef struct EckdCdlIpl1 {
+uint8_t key[4]; /* == "IPL1" */
+uint8_t data[24];
+} __attribute__((packed)) EckdCdlIpl1;
+
+typedef struct EckdCdlIpl2 {
+uint8_t key[4]; /* == "IPL2" */
+uint8_t reserved0[88];
+XEckdMbr mbr;
+uint8_t reserved[24];
+} __attribute__((packed)) EckdCdlIpl2;
+
+typedef struct EckdLdlIpl1 {
+uint8_t reserved[112];
+BootInfo bip; /* BootInfo is MBR for LDL */
+} __attribute__((packed)) EckdLdlIpl1;
 
 typedef struct IplVolumeLabel {
 unsigned char key[4]; /* == "VOL1" */
-- 
2.7.4




[Qemu-devel] [PATCH v7 02/12] s390-ccw: refactor eckd_block_num to use CHS

2018-02-16 Thread Collin L. Walling
Add new cylinder/head/sector struct. Use it to calculate
eckd block numbers instead of a BootMapPointer (which used
eckd chs anyway).

Signed-off-by: Collin L. Walling <wall...@linux.vnet.ibm.com>
Reviewed-by: Thomas Huth <th...@redhat.com>
---
 pc-bios/s390-ccw/bootmap.c | 28 ++--
 pc-bios/s390-ccw/bootmap.h |  8 ++--
 2 files changed, 20 insertions(+), 16 deletions(-)

diff --git a/pc-bios/s390-ccw/bootmap.c b/pc-bios/s390-ccw/bootmap.c
index 286de40..9534f56 100644
--- a/pc-bios/s390-ccw/bootmap.c
+++ b/pc-bios/s390-ccw/bootmap.c
@@ -95,32 +95,32 @@ static inline void verify_boot_info(BootInfo *bip)
"Bad block size in zIPL section of the 1st record.");
 }
 
-static block_number_t eckd_block_num(BootMapPointer *p)
+static block_number_t eckd_block_num(EckdCHS *chs)
 {
 const uint64_t sectors = virtio_get_sectors();
 const uint64_t heads = virtio_get_heads();
-const uint64_t cylinder = p->eckd.cylinder
-+ ((p->eckd.head & 0xfff0) << 12);
-const uint64_t head = p->eckd.head & 0x000f;
+const uint64_t cylinder = chs->cylinder
++ ((chs->head & 0xfff0) << 12);
+const uint64_t head = chs->head & 0x000f;
 const block_number_t block = sectors * heads * cylinder
+ sectors * head
-   + p->eckd.sector
+   + chs->sector
- 1; /* block nr starts with zero */
 return block;
 }
 
 static bool eckd_valid_address(BootMapPointer *p)
 {
-const uint64_t head = p->eckd.head & 0x000f;
+const uint64_t head = p->eckd.chs.head & 0x000f;
 
 if (head >= virtio_get_heads()
-||  p->eckd.sector > virtio_get_sectors()
-||  p->eckd.sector <= 0) {
+||  p->eckd.chs.sector > virtio_get_sectors()
+||  p->eckd.chs.sector <= 0) {
 return false;
 }
 
 if (!virtio_guessed_disk_nature() &&
-eckd_block_num(p) >= virtio_get_blocks()) {
+eckd_block_num(>eckd.chs) >= virtio_get_blocks()) {
 return false;
 }
 
@@ -140,7 +140,7 @@ static block_number_t load_eckd_segments(block_number_t 
blk, uint64_t *address)
 do {
 more_data = false;
 for (j = 0;; j++) {
-block_nr = eckd_block_num((void *)&(bprs[j].xeckd));
+block_nr = eckd_block_num([j].xeckd.bptr.chs);
 if (is_null_block_number(block_nr)) { /* end of chunk */
 break;
 }
@@ -198,7 +198,7 @@ static void run_eckd_boot_script(block_number_t 
bmt_block_nr)
 memset(sec, FREE_SPACE_FILLER, sizeof(sec));
 read_block(bmt_block_nr, sec, "Cannot read Boot Map Table");
 
-block_nr = eckd_block_num((void *)>entry[loadparm]);
+block_nr = eckd_block_num(>entry[loadparm].xeckd.bptr.chs);
 IPL_assert(block_nr != -1, "Cannot find Boot Map Table Entry");
 
 memset(sec, FREE_SPACE_FILLER, sizeof(sec));
@@ -206,7 +206,7 @@ static void run_eckd_boot_script(block_number_t 
bmt_block_nr)
 
 for (i = 0; bms->entry[i].type == BOOT_SCRIPT_LOAD; i++) {
 address = bms->entry[i].address.load_address;
-block_nr = eckd_block_num(&(bms->entry[i].blkptr));
+block_nr = eckd_block_num(>entry[i].blkptr.xeckd.bptr.chs);
 
 do {
 block_nr = load_eckd_segments(block_nr, );
@@ -239,7 +239,7 @@ static void ipl_eckd_cdl(void)
"Non-ECKD device type in zIPL section of IPL2 record.");
 
 /* save pointer to Boot Map Table */
-bmt_block_nr = eckd_block_num((void *)>blockptr);
+bmt_block_nr = eckd_block_num(>blockptr.xeckd.bptr.chs);
 
 memset(sec, FREE_SPACE_FILLER, sizeof(sec));
 read_block(2, vlbl, "Cannot read Volume Label at block 2");
@@ -300,7 +300,7 @@ static void ipl_eckd_ldl(ECKD_IPL_mode_t mode)
 verify_boot_info(bip);
 
 /* save pointer to Boot Map Table */
-bmt_block_nr = eckd_block_num((void *)>bp.ipl.bm_ptr.eckd.bptr);
+bmt_block_nr = eckd_block_num(>bp.ipl.bm_ptr.eckd.bptr.chs);
 
 run_eckd_boot_script(bmt_block_nr);
 /* no return */
diff --git a/pc-bios/s390-ccw/bootmap.h b/pc-bios/s390-ccw/bootmap.h
index 486c0f3..b361084 100644
--- a/pc-bios/s390-ccw/bootmap.h
+++ b/pc-bios/s390-ccw/bootmap.h
@@ -32,10 +32,14 @@ typedef struct FbaBlockPtr {
 uint16_t blockct;
 } __attribute__ ((packed)) FbaBlockPtr;
 
-typedef struct EckdBlockPtr {
-uint16_t cylinder; /* cylinder/head/sector is an address of the block */
+typedef struct EckdCHS {
+uint16_t cylinder;
 uint16_t head;
 uint8_t sector;
+} __attribute__ ((packed)) EckdCHS;
+
+typedef struct EckdBlockPtr {
+EckdCHS chs; /* cylinder/head/sector is an address of the block */
 uint16_t size;
 uint8_t count; /* (size_in_blocks-1);
 * it's 0 for TablePtr, ScriptPtr, and SectionPtr */
-- 
2.7.4




[Qemu-devel] [PATCH v7 00/12] Interactive Boot Menu for DASD and SCSI Guests on s390x

2018-02-16 Thread Collin L. Walling
Sorry for posting this version so close to the previous posting. The requested
changes are getting smaller and smaller and I'm hoping to get these patches
satisfactory soon.

--- [v7] ---

 - fixed alignment mistake in QemuIplParameters
- also added comment explaining this

 - fixed rebasing error with _strlen and _memcmp

 - dropped reserved2 field in ScsiMbr

 - r-b's and signoffs aded where suggested

--- [v6] ---

 - cleaned up libc.c

 - expanded timeout field in QemuIPLB from 2 bytes to 4 bytes
- we can now store the timeout value from command line as ms

 - sclp_set_write_mask now accepts two parameters:
- receive_mask
- send_mask

 - the write mask for receive is only set when we need it (reading user inp)
and cleared when we no longer need it (no longer reading user inp)

 - pending irq code cleaned up

 - bootmap code for scsi fixed up -- it has the same limitations as DASD,
so I added some similar checks in ipl_scsi

--- [Summary] ---

These patches implement a boot menu for ECKD DASD and SCSI guests on s390x. 
The menu will only appear if the disk has been configured for IPL with the 
zIPL tool and with the following QEMU command line options:

-boot menu=on[,splash-time=X] and/or -machine loadparm='prompt'

The following must be specified for the device to be IPL'd from:

-device ...,bootindex=1

or via the following libvirt domain xml:


  


or


  ...
  


Where X is some positive integer representing time in milliseconds.

 must be specified for the device to be IPL'd from

A loadparm other than 'prompt' will disable the menu and just boot 
the specified entry.

If no boot options are specified, we will attempt to use the values
provided by zipl (ECKD DASD only).


Collin L. Walling (12):
  s390-ccw: refactor boot map table code
  s390-ccw: refactor eckd_block_num to use CHS
  s390-ccw: refactor IPL structs
  s390-ccw: update libc
  s390-ccw: move auxiliary IPL data to separate location
  s390-ccw: parse and set boot menu options
  s390-ccw: set up interactive boot menu parameters
  s390-ccw: read stage2 boot loader data to find menu
  s390-ccw: print zipl boot menu
  s390-ccw: read user input for boot index via the SCLP console
  s390-ccw: set cp_receive mask only when needed and consume pending
service irqs
  s390-ccw: interactive boot menu for scsi

 hw/s390x/ipl.c  |  67 +++-
 hw/s390x/ipl.h  |  24 -
 pc-bios/s390-ccw/Makefile   |   2 +-
 pc-bios/s390-ccw/bootmap.c  | 184 +++--
 pc-bios/s390-ccw/bootmap.h  |  91 ++---
 pc-bios/s390-ccw/iplb.h |  22 +++-
 pc-bios/s390-ccw/libc.c |  89 
 pc-bios/s390-ccw/libc.h |  37 ++-
 pc-bios/s390-ccw/main.c |  48 +
 pc-bios/s390-ccw/menu.c | 241 
 pc-bios/s390-ccw/menu.h |  25 +
 pc-bios/s390-ccw/s390-ccw.h |   3 +
 pc-bios/s390-ccw/sclp.c |  39 ---
 pc-bios/s390-ccw/virtio.c   |   2 +-
 14 files changed, 748 insertions(+), 126 deletions(-)
 create mode 100644 pc-bios/s390-ccw/libc.c
 create mode 100644 pc-bios/s390-ccw/menu.c
 create mode 100644 pc-bios/s390-ccw/menu.h

-- 
2.7.4




Re: [Qemu-devel] [qemu-s390x] [PATCH v6 06/12] s390-ccw: parse and set boot menu options

2018-02-16 Thread Collin L. Walling

On 02/16/2018 11:36 AM, Viktor Mihajlovski wrote:

On 16.02.2018 17:20, Thomas Huth wrote:
[...]

diff --git a/hw/s390x/ipl.h b/hw/s390x/ipl.h
index cab8a97..7c3cab8 100644
--- a/hw/s390x/ipl.h
+++ b/hw/s390x/ipl.h
@@ -60,10 +60,15 @@ typedef struct IplBlockQemuScsi IplBlockQemuScsi;
  
  #define QIPL_ADDRESS  0xcc
  
+#define BOOT_MENU_FLAG_CMD_OPTS  0x80

+#define BOOT_MENU_FLAG_ZIPL_OPTS 0x40
+
  struct QemuIplParameters {
-uint8_t  reserved1[4];
+uint8_t  boot_menu_flags;
+uint8_t  reserved1;
+uint32_t boot_menu_timeout;
  uint64_t netboot_start_addr;

The netboot_start_addr field is now never aligned anymore, neither on
the host side, nor in guest memory. Not a big problem since the struct
is declared with "QEMU_PACKED", but still ... it's always nicer to try
to align fields to their natural boundaries. So maybe move
boot_menu_flags and reserved1 after netboot_start_addr ?


Good catch ... we probably should document the alignment needs and state
that the ipl parameters starts on a word boundary (and that the block
may not be larger than 28 bytes) in a comment block.


How does this sound?

/* word aligned and cannot exceed 28 bytes */



-uint8_t  reserved2[16];
+uint8_t  reserved2[14];
  } QEMU_PACKED;
  typedef struct QemuIplParameters QemuIplParameters;

  Thomas






--
- Collin L Walling




Re: [Qemu-devel] [qemu-s390x] [PATCH v6 06/12] s390-ccw: parse and set boot menu options

2018-02-16 Thread Collin L. Walling

On 02/16/2018 11:20 AM, Thomas Huth wrote:

On 15.02.2018 23:54, Collin L. Walling wrote:

Set boot menu options for an s390 guest and store them in
the iplb. These options are set via the QEMU command line
option:

 -boot menu=on|off[,splash-time=X]

or via the libvirt domain xml:

 
   
 

Where X represents some positive integer representing
milliseconds.

Any value set for loadparm will override all boot menu options.
If loadparm=PROMPT, then the menu will be enabled without a
timeout.

The absence of any boot options on the command line will flag
to later use the zipl boot loader values.

Signed-off-by: Collin L. Walling <wall...@linux.vnet.ibm.com>
Reviewed-by: Janosch Frank <fran...@linux.vnet.ibm.com>
Reviewed-by: Thomas Huth <th...@redhat.com>
---
  hw/s390x/ipl.c  | 48 
  hw/s390x/ipl.h  |  9 +++--
  pc-bios/s390-ccw/iplb.h |  6 --
  3 files changed, 59 insertions(+), 4 deletions(-)

[]

diff --git a/hw/s390x/ipl.h b/hw/s390x/ipl.h
index cab8a97..7c3cab8 100644
--- a/hw/s390x/ipl.h
+++ b/hw/s390x/ipl.h
@@ -60,10 +60,15 @@ typedef struct IplBlockQemuScsi IplBlockQemuScsi;
  
  #define QIPL_ADDRESS  0xcc
  
+#define BOOT_MENU_FLAG_CMD_OPTS  0x80

+#define BOOT_MENU_FLAG_ZIPL_OPTS 0x40
+
  struct QemuIplParameters {
-uint8_t  reserved1[4];
+uint8_t  boot_menu_flags;
+uint8_t  reserved1;
+uint32_t boot_menu_timeout;
  uint64_t netboot_start_addr;

The netboot_start_addr field is now never aligned anymore, neither on
the host side, nor in guest memory. Not a big problem since the struct
is declared with "QEMU_PACKED", but still ... it's always nicer to try
to align fields to their natural boundaries. So maybe move
boot_menu_flags and reserved1 after netboot_start_addr ?


Makes sense. Will fixup.




-uint8_t  reserved2[16];
+uint8_t  reserved2[14];
  } QEMU_PACKED;
  typedef struct QemuIplParameters QemuIplParameters;

  Thomas




--
- Collin L Walling




Re: [Qemu-devel] [qemu-s390x] [PATCH v6 04/12] s390-ccw: update libc

2018-02-16 Thread Collin L. Walling

On 02/16/2018 11:05 AM, Thomas Huth wrote:

On 15.02.2018 23:54, Collin L. Walling wrote:

Moved:
   memcmp from bootmap.h to libc.h (renamed from _memcmp)
   strlen from sclp.c to libc.h (renamed from _strlen)

What happened to the renames of _strlen to strlen and _memcmp to memcmp?
The hunks now seem to be missing from this patch? Or do I miss something?

  Thomas


Oh shoot... yeah, the _* functions didn't seem to get removed...
sorry about that. Odd rebasing failure on my end :(





Added C standard functions:
   isdigit

Added non C-standard function:
   uitoa
   atoui

Signed-off-by: Collin L. Walling <wall...@linux.vnet.ibm.com>
Acked-by: Christian Borntraeger <borntrae...@de.ibm.com>
Reviewed-by: Janosch Frank <fran...@linux.vnet.ibm.com>
---
  pc-bios/s390-ccw/Makefile |  2 +-
  pc-bios/s390-ccw/libc.c   | 89 +++
  pc-bios/s390-ccw/libc.h   | 37 ++--
  pc-bios/s390-ccw/main.c   | 17 +
  4 files changed, 126 insertions(+), 19 deletions(-)
  create mode 100644 pc-bios/s390-ccw/libc.c

diff --git a/pc-bios/s390-ccw/Makefile b/pc-bios/s390-ccw/Makefile
index 6d0c2ee..9f7904f 100644
--- a/pc-bios/s390-ccw/Makefile
+++ b/pc-bios/s390-ccw/Makefile
@@ -9,7 +9,7 @@ $(call set-vpath, $(SRC_PATH)/pc-bios/s390-ccw)
  
  .PHONY : all clean build-all
  
-OBJECTS = start.o main.o bootmap.o sclp.o virtio.o virtio-scsi.o virtio-blkdev.o

+OBJECTS = start.o main.o bootmap.o sclp.o virtio.o virtio-scsi.o 
virtio-blkdev.o libc.o
  QEMU_CFLAGS := $(filter -W%, $(QEMU_CFLAGS))
  QEMU_CFLAGS += -ffreestanding -fno-delete-null-pointer-checks -msoft-float
  QEMU_CFLAGS += -march=z900 -fPIE -fno-strict-aliasing
diff --git a/pc-bios/s390-ccw/libc.c b/pc-bios/s390-ccw/libc.c
new file mode 100644
index 000..a144388
--- /dev/null
+++ b/pc-bios/s390-ccw/libc.c
@@ -0,0 +1,89 @@
+/*
+ * libc-style definitions and functions
+ *
+ * Copyright 2018 IBM Corp.
+ * Author(s): Collin L. Walling <wall...@linux.vnet.ibm.com>
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ */
+
+#include "libc.h"
+#include "s390-ccw.h"
+
+/**
+ * atoui:
+ * @str: the string to be converted.
+ *
+ * Given a string @str, convert it to an integer. Leading spaces are
+ * ignored. Any other non-numerical value will terminate the conversion
+ * and return 0. This function only handles numbers between 0 and
+ * UINT64_MAX inclusive.
+ *
+ * Returns: an integer converted from the string @str, or the number 0
+ * if an error occurred.
+ */
+uint64_t atoui(const char *str)
+{
+int val = 0;
+
+if (!str || !str[0]) {
+return 0;
+}
+
+while (*str == ' ') {
+str++;
+}
+
+while (*str) {
+if (!isdigit(*str)) {
+break;
+}
+val = val * 10 + *str - '0';
+str++;
+}
+
+return val;
+}
+
+/**
+ * uitoa:
+ * @num: an integer (base 10) to be converted.
+ * @str: a pointer to a string to store the conversion.
+ * @len: the length of the passed string.
+ *
+ * Given an integer @num, convert it to a string. The string @str must be
+ * allocated beforehand. The resulting string will be null terminated and
+ * returned. This function only handles numbers between 0 and UINT64_MAX
+ * inclusive.
+ *
+ * Returns: the string @str of the converted integer @num
+ */
+char *uitoa(uint64_t num, char *str, size_t len)
+{
+size_t num_idx = 0;
+uint64_t tmp = num;
+
+IPL_assert(str != NULL, "uitoa: no space allocated to store string");
+
+/* Get index to ones place */
+while ((tmp /= 10) != 0) {
+num_idx++;
+}
+
+/* Check if we have enough space for num and null */
+IPL_assert(len > num_idx, "uitoa: array too small for conversion");
+
+str[num_idx + 1] = '\0';
+
+/* Convert int to string */
+while (num_idx >= 0) {
+str[num_idx] = num % 10 + '0';
+num /= 10;
+num_idx--;
+}
+
+return str;
+}
diff --git a/pc-bios/s390-ccw/libc.h b/pc-bios/s390-ccw/libc.h
index 0142ea8..63ece70 100644
--- a/pc-bios/s390-ccw/libc.h
+++ b/pc-bios/s390-ccw/libc.h
@@ -1,6 +1,8 @@
  /*
   * libc-style definitions and functions
   *
+ * Copyright (c) 2013 Alexander Graf <ag...@suse.de>
+ *
   * This code is free software; you can redistribute it and/or modify it
   * under the terms of the GNU General Public License as published by the
   * Free Software Foundation; either version 2 of the License, or (at your
@@ -19,7 +21,7 @@ typedef unsigned long long uint64_t;
  
  static inline void *memset(void *s, int c, size_t n)

  {
-int i;
+size_t i;
  unsigned char *p = s;
  
  for (i = 0; i < n; i++) {

@@ -33,7 +35,7 @@ static inline void *memcpy(void *s1, const void *s2, si

Re: [Qemu-devel] [PATCH v6 10/12] s390-ccw: read user input for boot index via the SCLP console

2018-02-16 Thread Collin L. Walling

On 02/16/2018 10:03 AM, David Hildenbrand wrote:

On 15.02.2018 23:54, Collin L. Walling wrote:

[...]
+
  static int get_boot_index(int entries)
  {
-return 0; /* Implemented next patch */
+int boot_index;
+bool retry = false;
+char tmp[5];
+
+do {
+boot_menu_prompt(retry);
+boot_index = get_index();
+retry = true;
+} while (boot_index < 0 || boot_index >= entries);
+

Can you add a comment like

/*
  * We might still have pending SERVICE interrupts. Print something to
  * definitely clear it.
  */


I handle clearing the pending int in the next patch.

[...]

--
- Collin L Walling




Re: [Qemu-devel] [qemu-s390x] [PATCH v6 01/12] s390-ccw: refactor boot map table code

2018-02-16 Thread Collin L. Walling

On 02/16/2018 07:19 AM, Viktor Mihajlovski wrote:

On 16.02.2018 11:42, Thomas Huth wrote:

On 15.02.2018 23:54, Collin L. Walling wrote:

Some ECKD bootmap code was using structs designed for SCSI.
Even though this works, it confuses readability. Add a new
BootMapTable struct to assist with readability in bootmap
entry code. Also:

- replace ScsiMbr in ECKD code with appropriate structs
- fix read_block messages to reflect BootMapTable
- fixup ipl_scsi to use BootMapTable (referred to as Program Table)
- defined value for maximum table entries

Signed-off-by: Collin L. Walling <wall...@linux.vnet.ibm.com>
---
  pc-bios/s390-ccw/bootmap.c | 60 +-
  pc-bios/s390-ccw/bootmap.h | 14 +--
  2 files changed, 39 insertions(+), 35 deletions(-)

[...]

diff --git a/pc-bios/s390-ccw/bootmap.h b/pc-bios/s390-ccw/bootmap.h
index cf99a4c..850b655 100644
--- a/pc-bios/s390-ccw/bootmap.h
+++ b/pc-bios/s390-ccw/bootmap.h
@@ -53,6 +53,15 @@ typedef union BootMapPointer {
  ExtEckdBlockPtr xeckd;
  } __attribute__ ((packed)) BootMapPointer;
  
+#define MAX_TABLE_ENTRIES  30

+
+/* aka Program Table */
+typedef struct BootMapTable {
+uint8_t magic[4];
+uint8_t reserved[12];
+BootMapPointer entry[];
+} __attribute__ ((packed)) BootMapTable;
+
  typedef struct ComponentEntry {
  ScsiBlockPtr data;
  uint8_t pad[7];
@@ -69,8 +78,9 @@ typedef struct ComponentHeader {
  typedef struct ScsiMbr {
  uint8_t magic[4];
  uint32_t version_id;
-uint8_t reserved[8];
-ScsiBlockPtr blockptr[];
+uint8_t reserved1[8];
+ScsiBlockPtr pt;   /* block pointer to program table */
+uint8_t reserved2[120];

Did you want to pad the struct to 512 bytes here? If so, I think that
should have been "uint32_t" instead of "uint8_t" or "480" instead of "120" ?


Should probably be uint8_t[480] then to stay in style with other
reserved field definitions.


The idea was to mimic the Scsi MBR struct defined in zipl.  It has
reserved space for what would appear to be for 5 more ScsiBlockPtrs
(which are not used in zipl) and a boot_info struct (which we don't need
in QEMU).

Alternatively, I can just omit the reserved2 field. I placed it there
for "completeness" but it is not at all necessary.


  } __attribute__ ((packed)) ScsiMbr;
  
  #define ZIPL_MAGIC  "zIPL"



  Thomas






--
- Collin L Walling




[Qemu-devel] [PATCH v6 11/12] s390-ccw: set cp_receive mask only when needed and consume pending service irqs

2018-02-15 Thread Collin L. Walling
It is possible while waiting for multiple types of external
interrupts that we might have pending irqs remaining between
irq consumption and irq-type disabling. Those interrupts
could potentially propagate to the guest after IPL completes
and cause unwanted behavior.

As it is today, the SCLP will only recognize write events that
are enabled by the control program's send and receive masks. To
limit the window for, and prevent further irqs from, ASCII
console events (specifically keystrokes), we should only enable
the control program's receive mask when we need it.

As an additional measure, once we've disabled/cleared the control
program's receive mask, we will print an empty string in order
to consume any pending service interrupt.

Signed-off-by: Collin L. Walling <wall...@linux.vnet.ibm.com>
---
 pc-bios/s390-ccw/menu.c |  5 +
 pc-bios/s390-ccw/s390-ccw.h |  1 +
 pc-bios/s390-ccw/sclp.c | 10 --
 3 files changed, 10 insertions(+), 6 deletions(-)

diff --git a/pc-bios/s390-ccw/menu.c b/pc-bios/s390-ccw/menu.c
index 9601043..14410a8 100644
--- a/pc-bios/s390-ccw/menu.c
+++ b/pc-bios/s390-ccw/menu.c
@@ -11,6 +11,7 @@
 
 #include "menu.h"
 #include "s390-ccw.h"
+#include "sclp.h"
 
 #define KEYCODE_NO_INP '\0'
 #define KEYCODE_ESCAPE '\033'
@@ -117,8 +118,12 @@ static int get_index(void)
 
 memset(buf, 0, sizeof(buf));
 
+sclp_set_write_mask(SCLP_EVENT_MASK_MSG_ASCII, SCLP_EVENT_MASK_MSG_ASCII);
 len = read_prompt(buf, sizeof(buf));
 
+sclp_set_write_mask(0, SCLP_EVENT_MASK_MSG_ASCII);
+sclp_print(""); /* Clear any pending service int */
+
 /* If no input, boot default */
 if (len == 0) {
 return 0;
diff --git a/pc-bios/s390-ccw/s390-ccw.h b/pc-bios/s390-ccw/s390-ccw.h
index a7e6253..ebdcf86 100644
--- a/pc-bios/s390-ccw/s390-ccw.h
+++ b/pc-bios/s390-ccw/s390-ccw.h
@@ -69,6 +69,7 @@ unsigned int get_loadparm_index(void);
 
 /* sclp.c */
 void sclp_print(const char *string);
+void sclp_set_write_mask(uint32_t receive_mask, uint32_t send_mask);
 void sclp_setup(void);
 void sclp_get_loadparm_ascii(char *loadparm);
 int sclp_read(char *str, size_t count);
diff --git a/pc-bios/s390-ccw/sclp.c b/pc-bios/s390-ccw/sclp.c
index abce139..21076f8 100644
--- a/pc-bios/s390-ccw/sclp.c
+++ b/pc-bios/s390-ccw/sclp.c
@@ -46,23 +46,21 @@ static int sclp_service_call(unsigned int command, void 
*sccb)
 return 0;
 }
 
-static void sclp_set_write_mask(void)
+void sclp_set_write_mask(uint32_t receive_mask, uint32_t send_mask)
 {
 WriteEventMask *sccb = (void *)_sccb;
 
 sccb->h.length = sizeof(WriteEventMask);
 sccb->mask_length = sizeof(unsigned int);
-sccb->receive_mask = SCLP_EVENT_MASK_MSG_ASCII;
-sccb->cp_receive_mask = SCLP_EVENT_MASK_MSG_ASCII;
-sccb->send_mask = SCLP_EVENT_MASK_MSG_ASCII;
-sccb->cp_send_mask = SCLP_EVENT_MASK_MSG_ASCII;
+sccb->cp_receive_mask = receive_mask;
+sccb->cp_send_mask = send_mask;
 
 sclp_service_call(SCLP_CMD_WRITE_EVENT_MASK, sccb);
 }
 
 void sclp_setup(void)
 {
-sclp_set_write_mask();
+sclp_set_write_mask(0, SCLP_EVENT_MASK_MSG_ASCII);
 }
 
 static int _strlen(const char *str)
-- 
2.7.4




[Qemu-devel] [PATCH v6 08/12] s390-ccw: read stage2 boot loader data to find menu

2018-02-15 Thread Collin L. Walling
Read the stage2 boot loader data block-by-block. We scan the
current block for the string "zIPL" to detect the start of the
boot menu banner. We then load the adjacent blocks (previous
block and next block) to account for the possibility of menu
data spanning multiple blocks.

Signed-off-by: Collin L. Walling <wall...@linux.vnet.ibm.com>
Reviewed-by: Thomas Huth <th...@redhat.com>
---
 pc-bios/s390-ccw/bootmap.c | 94 +++---
 pc-bios/s390-ccw/bootmap.h | 23 +++-
 pc-bios/s390-ccw/menu.c|  5 +++
 pc-bios/s390-ccw/menu.h|  1 +
 4 files changed, 116 insertions(+), 7 deletions(-)

diff --git a/pc-bios/s390-ccw/bootmap.c b/pc-bios/s390-ccw/bootmap.c
index a94638d..5358301 100644
--- a/pc-bios/s390-ccw/bootmap.c
+++ b/pc-bios/s390-ccw/bootmap.c
@@ -13,6 +13,7 @@
 #include "bootmap.h"
 #include "virtio.h"
 #include "bswap.h"
+#include "menu.h"
 
 #ifdef DEBUG
 /* #define DEBUG_FALLBACK */
@@ -83,6 +84,10 @@ static void jump_to_IPL_code(uint64_t address)
 
 static unsigned char _bprs[8*1024]; /* guessed "max" ECKD sector size */
 static const int max_bprs_entries = sizeof(_bprs) / sizeof(ExtEckdBlockPtr);
+static uint8_t _s2[MAX_SECTOR_SIZE * 3] 
__attribute__((__aligned__(PAGE_SIZE)));
+static void *s2_prev_blk = _s2;
+static void *s2_cur_blk = _s2 + MAX_SECTOR_SIZE;
+static void *s2_next_blk = _s2 + MAX_SECTOR_SIZE * 2;
 
 static inline void verify_boot_info(BootInfo *bip)
 {
@@ -182,7 +187,76 @@ static block_number_t load_eckd_segments(block_number_t 
blk, uint64_t *address)
 return block_nr;
 }
 
-static void run_eckd_boot_script(block_number_t bmt_block_nr)
+static bool find_zipl_boot_menu_banner(int *offset)
+{
+int i;
+
+/* Menu banner starts with "zIPL" */
+for (i = 0; i < virtio_get_block_size() - 4; i++) {
+if (magic_match(s2_cur_blk + i, ZIPL_MAGIC_EBCDIC)) {
+*offset = i;
+return true;
+}
+}
+
+return false;
+}
+
+static int eckd_get_boot_menu_index(block_number_t s1b_block_nr)
+{
+block_number_t cur_block_nr;
+block_number_t prev_block_nr = 0;
+block_number_t next_block_nr = 0;
+EckdStage1b *s1b = (void *)sec;
+int offset;
+int i;
+
+/* Get Stage1b data */
+memset(sec, FREE_SPACE_FILLER, sizeof(sec));
+read_block(s1b_block_nr, s1b, "Cannot read stage1b boot loader");
+
+memset(_s2, FREE_SPACE_FILLER, sizeof(_s2));
+
+/* Get Stage2 data */
+for (i = 0; i < STAGE2_BLK_CNT_MAX; i++) {
+cur_block_nr = eckd_block_num(>seek[i].chs);
+
+if (!cur_block_nr) {
+break;
+}
+
+read_block(cur_block_nr, s2_cur_blk, "Cannot read stage2 boot loader");
+
+if (find_zipl_boot_menu_banner()) {
+/* Load the adjacent blocks to account for the
+ * possibility of menu data spanning multiple blocks.
+ */
+if (prev_block_nr) {
+read_block(prev_block_nr, s2_prev_blk,
+   "Cannot read stage2 boot loader");
+}
+
+if (i + 1 < STAGE2_BLK_CNT_MAX) {
+next_block_nr = eckd_block_num(>seek[i + 1].chs);
+}
+
+if (next_block_nr) {
+read_block(next_block_nr, s2_next_blk,
+   "Cannot read stage2 boot loader");
+}
+
+return menu_get_zipl_boot_index(s2_cur_blk, offset);
+}
+
+prev_block_nr = cur_block_nr;
+}
+
+sclp_print("No zipl boot menu data found. Booting default entry.");
+return 0;
+}
+
+static void run_eckd_boot_script(block_number_t bmt_block_nr,
+ block_number_t s1b_block_nr)
 {
 int i;
 unsigned int loadparm = get_loadparm_index();
@@ -191,6 +265,10 @@ static void run_eckd_boot_script(block_number_t 
bmt_block_nr)
 BootMapTable *bmt = (void *)sec;
 BootMapScript *bms = (void *)sec;
 
+if (menu_check_flags(BOOT_MENU_FLAG_CMD_OPTS | BOOT_MENU_FLAG_ZIPL_OPTS)) {
+loadparm = eckd_get_boot_menu_index(s1b_block_nr);
+}
+
 debug_print_int("loadparm", loadparm);
 IPL_assert(loadparm <= MAX_TABLE_ENTRIES, "loadparm value greater than"
" maximum number of boot entries allowed");
@@ -223,7 +301,7 @@ static void ipl_eckd_cdl(void)
 XEckdMbr *mbr;
 EckdCdlIpl2 *ipl2 = (void *)sec;
 IplVolumeLabel *vlbl = (void *)sec;
-block_number_t bmt_block_nr;
+block_number_t bmt_block_nr, s1b_block_nr;
 
 /* we have just read the block #0 and recognized it as "IPL1" */
 sclp_print("CDL\n");
@@ -241,6 +319,9 @@ static void ipl_eckd_cdl(void)
 /* save pointer to Boot Map Table */
 bmt_block_nr = eckd_block_num(>blockptr.xeckd.bptr.chs);
 
+/* save pointer to Stage1b Data */
+  

[Qemu-devel] [PATCH v6 02/12] s390-ccw: refactor eckd_block_num to use CHS

2018-02-15 Thread Collin L. Walling
Add new cylinder/head/sector struct. Use it to calculate
eckd block numbers instead of a BootMapPointer (which used
eckd chs anyway).

Signed-off-by: Collin L. Walling <wall...@linux.vnet.ibm.com>
---
 pc-bios/s390-ccw/bootmap.c | 28 ++--
 pc-bios/s390-ccw/bootmap.h |  8 ++--
 2 files changed, 20 insertions(+), 16 deletions(-)

diff --git a/pc-bios/s390-ccw/bootmap.c b/pc-bios/s390-ccw/bootmap.c
index 286de40..9534f56 100644
--- a/pc-bios/s390-ccw/bootmap.c
+++ b/pc-bios/s390-ccw/bootmap.c
@@ -95,32 +95,32 @@ static inline void verify_boot_info(BootInfo *bip)
"Bad block size in zIPL section of the 1st record.");
 }
 
-static block_number_t eckd_block_num(BootMapPointer *p)
+static block_number_t eckd_block_num(EckdCHS *chs)
 {
 const uint64_t sectors = virtio_get_sectors();
 const uint64_t heads = virtio_get_heads();
-const uint64_t cylinder = p->eckd.cylinder
-+ ((p->eckd.head & 0xfff0) << 12);
-const uint64_t head = p->eckd.head & 0x000f;
+const uint64_t cylinder = chs->cylinder
++ ((chs->head & 0xfff0) << 12);
+const uint64_t head = chs->head & 0x000f;
 const block_number_t block = sectors * heads * cylinder
+ sectors * head
-   + p->eckd.sector
+   + chs->sector
- 1; /* block nr starts with zero */
 return block;
 }
 
 static bool eckd_valid_address(BootMapPointer *p)
 {
-const uint64_t head = p->eckd.head & 0x000f;
+const uint64_t head = p->eckd.chs.head & 0x000f;
 
 if (head >= virtio_get_heads()
-||  p->eckd.sector > virtio_get_sectors()
-||  p->eckd.sector <= 0) {
+||  p->eckd.chs.sector > virtio_get_sectors()
+||  p->eckd.chs.sector <= 0) {
 return false;
 }
 
 if (!virtio_guessed_disk_nature() &&
-eckd_block_num(p) >= virtio_get_blocks()) {
+eckd_block_num(>eckd.chs) >= virtio_get_blocks()) {
 return false;
 }
 
@@ -140,7 +140,7 @@ static block_number_t load_eckd_segments(block_number_t 
blk, uint64_t *address)
 do {
 more_data = false;
 for (j = 0;; j++) {
-block_nr = eckd_block_num((void *)&(bprs[j].xeckd));
+block_nr = eckd_block_num([j].xeckd.bptr.chs);
 if (is_null_block_number(block_nr)) { /* end of chunk */
 break;
 }
@@ -198,7 +198,7 @@ static void run_eckd_boot_script(block_number_t 
bmt_block_nr)
 memset(sec, FREE_SPACE_FILLER, sizeof(sec));
 read_block(bmt_block_nr, sec, "Cannot read Boot Map Table");
 
-block_nr = eckd_block_num((void *)>entry[loadparm]);
+block_nr = eckd_block_num(>entry[loadparm].xeckd.bptr.chs);
 IPL_assert(block_nr != -1, "Cannot find Boot Map Table Entry");
 
 memset(sec, FREE_SPACE_FILLER, sizeof(sec));
@@ -206,7 +206,7 @@ static void run_eckd_boot_script(block_number_t 
bmt_block_nr)
 
 for (i = 0; bms->entry[i].type == BOOT_SCRIPT_LOAD; i++) {
 address = bms->entry[i].address.load_address;
-block_nr = eckd_block_num(&(bms->entry[i].blkptr));
+block_nr = eckd_block_num(>entry[i].blkptr.xeckd.bptr.chs);
 
 do {
 block_nr = load_eckd_segments(block_nr, );
@@ -239,7 +239,7 @@ static void ipl_eckd_cdl(void)
"Non-ECKD device type in zIPL section of IPL2 record.");
 
 /* save pointer to Boot Map Table */
-bmt_block_nr = eckd_block_num((void *)>blockptr);
+bmt_block_nr = eckd_block_num(>blockptr.xeckd.bptr.chs);
 
 memset(sec, FREE_SPACE_FILLER, sizeof(sec));
 read_block(2, vlbl, "Cannot read Volume Label at block 2");
@@ -300,7 +300,7 @@ static void ipl_eckd_ldl(ECKD_IPL_mode_t mode)
 verify_boot_info(bip);
 
 /* save pointer to Boot Map Table */
-bmt_block_nr = eckd_block_num((void *)>bp.ipl.bm_ptr.eckd.bptr);
+bmt_block_nr = eckd_block_num(>bp.ipl.bm_ptr.eckd.bptr.chs);
 
 run_eckd_boot_script(bmt_block_nr);
 /* no return */
diff --git a/pc-bios/s390-ccw/bootmap.h b/pc-bios/s390-ccw/bootmap.h
index 850b655..7a13c9b 100644
--- a/pc-bios/s390-ccw/bootmap.h
+++ b/pc-bios/s390-ccw/bootmap.h
@@ -32,10 +32,14 @@ typedef struct FbaBlockPtr {
 uint16_t blockct;
 } __attribute__ ((packed)) FbaBlockPtr;
 
-typedef struct EckdBlockPtr {
-uint16_t cylinder; /* cylinder/head/sector is an address of the block */
+typedef struct EckdCHS {
+uint16_t cylinder;
 uint16_t head;
 uint8_t sector;
+} __attribute__ ((packed)) EckdCHS;
+
+typedef struct EckdBlockPtr {
+EckdCHS chs; /* cylinder/head/sector is an address of the block */
 uint16_t size;
 uint8_t count; /* (size_in_blocks-1);
 * it's 0 for TablePtr, ScriptPtr, and SectionPtr */
-- 
2.7.4




[Qemu-devel] [PATCH v6 12/12] s390-ccw: interactive boot menu for scsi

2018-02-15 Thread Collin L. Walling
Interactive boot menu for scsi. This follows a similar procedure
as the interactive menu for eckd dasd. An example follows:

s390x Enumerated Boot Menu.

3 entries detected. Select from index 0 to 2.

Signed-off-by: Collin L. Walling <wall...@linux.vnet.ibm.com>
Reviewed-by: Thomas Huth <th...@redhat.com>
---
 pc-bios/s390-ccw/bootmap.c |  4 
 pc-bios/s390-ccw/main.c|  1 +
 pc-bios/s390-ccw/menu.c| 14 ++
 pc-bios/s390-ccw/menu.h|  1 +
 4 files changed, 20 insertions(+)

diff --git a/pc-bios/s390-ccw/bootmap.c b/pc-bios/s390-ccw/bootmap.c
index 5358301..a75550f 100644
--- a/pc-bios/s390-ccw/bootmap.c
+++ b/pc-bios/s390-ccw/bootmap.c
@@ -568,6 +568,10 @@ static void ipl_scsi(void)
 debug_print_int("program table entries", program_table_entries);
 IPL_assert(program_table_entries != 0, "Empty Program Table");
 
+if (menu_check_flags(BOOT_MENU_FLAG_CMD_OPTS)) {
+loadparm = menu_get_enum_boot_index(program_table_entries);
+}
+
 debug_print_int("loadparm", loadparm);
 IPL_assert(loadparm <= MAX_TABLE_ENTRIES, "loadparm value greater than"
" maximum number of boot entries allowed");
diff --git a/pc-bios/s390-ccw/main.c b/pc-bios/s390-ccw/main.c
index c643a6b..2226871 100644
--- a/pc-bios/s390-ccw/main.c
+++ b/pc-bios/s390-ccw/main.c
@@ -92,6 +92,7 @@ static void menu_setup(void)
 
 switch (iplb.pbt) {
 case S390_IPL_TYPE_CCW:
+case S390_IPL_TYPE_QEMU_SCSI:
 menu_set_parms(qipl.boot_menu_flags, qipl.boot_menu_timeout);
 return;
 }
diff --git a/pc-bios/s390-ccw/menu.c b/pc-bios/s390-ccw/menu.c
index 14410a8..d104327 100644
--- a/pc-bios/s390-ccw/menu.c
+++ b/pc-bios/s390-ccw/menu.c
@@ -215,6 +215,20 @@ int menu_get_zipl_boot_index(const void *stage2, int 
offset)
 return get_boot_index(ct - 1);
 }
 
+int menu_get_enum_boot_index(int entries)
+{
+char tmp[4];
+
+sclp_print("s390x Enumerated Boot Menu.\n\n");
+
+sclp_print(uitoa(entries, tmp, sizeof(tmp)));
+sclp_print(" entries detected. Select from boot index 0 to ");
+sclp_print(uitoa(entries - 1, tmp, sizeof(tmp)));
+sclp_print(".\n\n");
+
+return get_boot_index(entries);
+}
+
 void menu_set_parms(uint8_t boot_menu_flag, uint32_t boot_menu_timeout)
 {
 flags = boot_menu_flag;
diff --git a/pc-bios/s390-ccw/menu.h b/pc-bios/s390-ccw/menu.h
index c603de3..790516c 100644
--- a/pc-bios/s390-ccw/menu.h
+++ b/pc-bios/s390-ccw/menu.h
@@ -18,6 +18,7 @@
 #define BOOT_MENU_FLAG_ZIPL_OPTS 0x40
 
 int menu_get_zipl_boot_index(const void *stage2, int offset);
+int menu_get_enum_boot_index(int entries);
 void menu_set_parms(uint8_t boot_menu_flags, uint32_t boot_menu_timeout);
 bool menu_check_flags(uint8_t check_flags);
 
-- 
2.7.4




[Qemu-devel] [PATCH v6 00/12] Interactive Boot Menu for DASD and SCSI Guests on s390x

2018-02-15 Thread Collin L. Walling
--- [v6] ---

 - cleaned up libc.c

 - expanded timeout field in QemuIPLB from 2 bytes to 4 bytes
- we can now store the timeout value from command line as ms

 - sclp_set_write_mask now accepts two parameters:
- receive_mask
- send_mask

 - the write mask for receive is only set when we need it (reading user inp)
and cleared when we no longer need it (no longer reading user inp)

 - pending irq code cleaned up

 - bootmap code for scsi fixed up -- it has the same limitations as DASD,
so I added some similar checks in ipl_scsi

--- [Summary] ---

These patches implement a boot menu for ECKD DASD and SCSI guests on s390x. 
The menu will only appear if the disk has been configured for IPL with the 
zIPL tool and with the following QEMU command line options:

-boot menu=on[,splash-time=X] and/or -machine loadparm='prompt'

The following must be specified for the device to be IPL'd from:

-device ...,bootindex=1

or via the following libvirt domain xml:


  


or


  ...
  


Where X is some positive integer representing time in milliseconds.

 must be specified for the device to be IPL'd from

A loadparm other than 'prompt' will disable the menu and just boot 
the specified entry.

If no boot options are specified, we will attempt to use the values
provided by zipl (ECKD DASD only).

Collin L. Walling (12):
  s390-ccw: refactor boot map table code
  s390-ccw: refactor eckd_block_num to use CHS
  s390-ccw: refactor IPL structs
  s390-ccw: update libc
  s390-ccw: move auxiliary IPL data to separate location
  s390-ccw: parse and set boot menu options
  s390-ccw: set up interactive boot menu parameters
  s390-ccw: read stage2 boot loader data to find menu
  s390-ccw: print zipl boot menu
  s390-ccw: read user input for boot index via the SCLP console
  s390-ccw: set cp_receive mask only when needed and consume pending
service irqs
  s390-ccw: interactive boot menu for scsi

 hw/s390x/ipl.c  |  67 +++-
 hw/s390x/ipl.h  |  18 +++-
 pc-bios/s390-ccw/Makefile   |   2 +-
 pc-bios/s390-ccw/bootmap.c  | 180 -
 pc-bios/s390-ccw/bootmap.h  |  78 ++
 pc-bios/s390-ccw/iplb.h |  16 ++-
 pc-bios/s390-ccw/libc.c |  89 
 pc-bios/s390-ccw/libc.h |  37 ++-
 pc-bios/s390-ccw/main.c |  48 +
 pc-bios/s390-ccw/menu.c | 241 
 pc-bios/s390-ccw/menu.h |  25 +
 pc-bios/s390-ccw/s390-ccw.h |   3 +
 pc-bios/s390-ccw/sclp.c |  29 --
 pc-bios/s390-ccw/virtio.c   |   2 +-
 14 files changed, 734 insertions(+), 101 deletions(-)
 create mode 100644 pc-bios/s390-ccw/libc.c
 create mode 100644 pc-bios/s390-ccw/menu.c
 create mode 100644 pc-bios/s390-ccw/menu.h

-- 
2.7.4




[Qemu-devel] [PATCH v6 06/12] s390-ccw: parse and set boot menu options

2018-02-15 Thread Collin L. Walling
Set boot menu options for an s390 guest and store them in
the iplb. These options are set via the QEMU command line
option:

-boot menu=on|off[,splash-time=X]

or via the libvirt domain xml:


  


Where X represents some positive integer representing
milliseconds.

Any value set for loadparm will override all boot menu options.
If loadparm=PROMPT, then the menu will be enabled without a
timeout.

The absence of any boot options on the command line will flag
to later use the zipl boot loader values.

Signed-off-by: Collin L. Walling <wall...@linux.vnet.ibm.com>
Reviewed-by: Janosch Frank <fran...@linux.vnet.ibm.com>
Reviewed-by: Thomas Huth <th...@redhat.com>
---
 hw/s390x/ipl.c  | 48 
 hw/s390x/ipl.h  |  9 +++--
 pc-bios/s390-ccw/iplb.h |  6 --
 3 files changed, 59 insertions(+), 4 deletions(-)

diff --git a/hw/s390x/ipl.c b/hw/s390x/ipl.c
index 31565ce..c8109f5 100644
--- a/hw/s390x/ipl.c
+++ b/hw/s390x/ipl.c
@@ -23,6 +23,9 @@
 #include "hw/s390x/ebcdic.h"
 #include "ipl.h"
 #include "qemu/error-report.h"
+#include "qemu/config-file.h"
+#include "qemu/cutils.h"
+#include "qemu/option.h"
 
 #define KERN_IMAGE_START0x01UL
 #define KERN_PARM_AREA  0x010480UL
@@ -219,6 +222,50 @@ static Property s390_ipl_properties[] = {
 DEFINE_PROP_END_OF_LIST(),
 };
 
+static void s390_ipl_set_boot_menu(IplParameterBlock *iplb)
+{
+QemuOptsList *plist = qemu_find_opts("boot-opts");
+QemuOpts *opts = QTAILQ_FIRST(>head);
+uint8_t *flags;
+uint32_t *timeout;
+const char *tmp;
+unsigned long splash_time = 0;
+
+switch (iplb->pbt) {
+case S390_IPL_TYPE_CCW:
+case S390_IPL_TYPE_QEMU_SCSI:
+flags = >qipl.boot_menu_flags;
+timeout = >qipl.boot_menu_timeout;
+break;
+default:
+error_report("boot menu is not supported for this device type.");
+return;
+}
+
+/* In the absence of -boot menu, use zipl parameters */
+if (!qemu_opt_get(opts, "menu")) {
+*flags = BOOT_MENU_FLAG_ZIPL_OPTS;
+} else if (boot_menu) {
+*flags = BOOT_MENU_FLAG_CMD_OPTS;
+
+tmp = qemu_opt_get(opts, "splash-time");
+
+if (tmp && qemu_strtoul(tmp, NULL, 10, _time)) {
+error_report("splash-time is invalid, forcing it to 0.");
+splash_time = 0;
+return;
+}
+
+if (splash_time > 0x) {
+error_report("splash-time is too large, forcing it to max value.");
+splash_time = 0x;
+return;
+}
+
+*timeout = cpu_to_be32(splash_time);
+}
+}
+
 static bool s390_gen_initial_iplb(S390IPLState *ipl)
 {
 DeviceState *dev_st;
@@ -435,6 +482,7 @@ void s390_ipl_prepare_cpu(S390CPU *cpu)
 }
 ipl->iplb.qipl.netboot_start_addr = cpu_to_be64(ipl->start_addr);
 }
+s390_ipl_set_boot_menu(>iplb);
 s390_ipl_prepare_qipl(cpu);
 
 }
diff --git a/hw/s390x/ipl.h b/hw/s390x/ipl.h
index cab8a97..7c3cab8 100644
--- a/hw/s390x/ipl.h
+++ b/hw/s390x/ipl.h
@@ -60,10 +60,15 @@ typedef struct IplBlockQemuScsi IplBlockQemuScsi;
 
 #define QIPL_ADDRESS  0xcc
 
+#define BOOT_MENU_FLAG_CMD_OPTS  0x80
+#define BOOT_MENU_FLAG_ZIPL_OPTS 0x40
+
 struct QemuIplParameters {
-uint8_t  reserved1[4];
+uint8_t  boot_menu_flags;
+uint8_t  reserved1;
+uint32_t boot_menu_timeout;
 uint64_t netboot_start_addr;
-uint8_t  reserved2[16];
+uint8_t  reserved2[14];
 } QEMU_PACKED;
 typedef struct QemuIplParameters QemuIplParameters;
 
diff --git a/pc-bios/s390-ccw/iplb.h b/pc-bios/s390-ccw/iplb.h
index 1266884..e8e442d 100644
--- a/pc-bios/s390-ccw/iplb.h
+++ b/pc-bios/s390-ccw/iplb.h
@@ -75,9 +75,11 @@ extern IplParameterBlock iplb 
__attribute__((__aligned__(PAGE_SIZE)));
 #define QIPL_ADDRESS  0xcc
 
 struct QemuIplParameters {
-uint8_t  reserved1[4];
+uint8_t  boot_menu_flags;
+uint8_t  reserved1;
+uint32_t boot_menu_timeout;
 uint64_t netboot_start_addr;
-uint8_t  reserved2[16];
+uint8_t  reserved2[14];
 } __attribute__ ((packed));
 typedef struct QemuIplParameters QemuIplParameters;
 
-- 
2.7.4




[Qemu-devel] [PATCH v6 07/12] s390-ccw: set up interactive boot menu parameters

2018-02-15 Thread Collin L. Walling
Reads boot menu flag and timeout values from the iplb and
sets the respective fields for the menu.

Signed-off-by: Collin L. Walling <wall...@linux.vnet.ibm.com>
Reviewed-by: Thomas Huth <th...@redhat.com>
---
 pc-bios/s390-ccw/Makefile |  2 +-
 pc-bios/s390-ccw/main.c   | 24 
 pc-bios/s390-ccw/menu.c   | 26 ++
 pc-bios/s390-ccw/menu.h   | 23 +++
 4 files changed, 74 insertions(+), 1 deletion(-)
 create mode 100644 pc-bios/s390-ccw/menu.c
 create mode 100644 pc-bios/s390-ccw/menu.h

diff --git a/pc-bios/s390-ccw/Makefile b/pc-bios/s390-ccw/Makefile
index 9f7904f..1712c2d 100644
--- a/pc-bios/s390-ccw/Makefile
+++ b/pc-bios/s390-ccw/Makefile
@@ -9,7 +9,7 @@ $(call set-vpath, $(SRC_PATH)/pc-bios/s390-ccw)
 
 .PHONY : all clean build-all
 
-OBJECTS = start.o main.o bootmap.o sclp.o virtio.o virtio-scsi.o 
virtio-blkdev.o libc.o
+OBJECTS = start.o main.o bootmap.o sclp.o virtio.o virtio-scsi.o 
virtio-blkdev.o libc.o menu.o
 QEMU_CFLAGS := $(filter -W%, $(QEMU_CFLAGS))
 QEMU_CFLAGS += -ffreestanding -fno-delete-null-pointer-checks -msoft-float
 QEMU_CFLAGS += -march=z900 -fPIE -fno-strict-aliasing
diff --git a/pc-bios/s390-ccw/main.c b/pc-bios/s390-ccw/main.c
index e41b264..c643a6b 100644
--- a/pc-bios/s390-ccw/main.c
+++ b/pc-bios/s390-ccw/main.c
@@ -11,6 +11,7 @@
 #include "libc.h"
 #include "s390-ccw.h"
 #include "virtio.h"
+#include "menu.h"
 
 char stack[PAGE_SIZE * 8] __attribute__((__aligned__(PAGE_SIZE)));
 static SubChannelId blk_schid = { .one = 1 };
@@ -18,6 +19,9 @@ IplParameterBlock iplb 
__attribute__((__aligned__(PAGE_SIZE)));
 static char loadparm[8] = { 0, 0, 0, 0, 0, 0, 0, 0 };
 QemuIplParameters qipl;
 
+#define LOADPARM_PROMPT "PROMPT  "
+#define LOADPARM_EMPTY  ""
+
 /*
  * Priniciples of Operations (SA22-7832-09) chapter 17 requires that
  * a subsystem-identification is at 184-187 and bytes 188-191 are zero
@@ -74,6 +78,25 @@ static bool find_dev(Schib *schib, int dev_no)
 return false;
 }
 
+static void menu_setup(void)
+{
+if (memcmp(loadparm, LOADPARM_PROMPT, 8) == 0) {
+menu_set_parms(BOOT_MENU_FLAG_CMD_OPTS, 0);
+return;
+}
+
+/* If loadparm was set to any other value, then do not enable menu */
+if (memcmp(loadparm, LOADPARM_EMPTY, 8) != 0) {
+return;
+}
+
+switch (iplb.pbt) {
+case S390_IPL_TYPE_CCW:
+menu_set_parms(qipl.boot_menu_flags, qipl.boot_menu_timeout);
+return;
+}
+}
+
 static void virtio_setup(void)
 {
 Schib schib;
@@ -117,6 +140,7 @@ static void virtio_setup(void)
 default:
 panic("List-directed IPL not supported yet!\n");
 }
+menu_setup();
 } else {
 for (ssid = 0; ssid < 0x3; ssid++) {
 blk_schid.ssid = ssid;
diff --git a/pc-bios/s390-ccw/menu.c b/pc-bios/s390-ccw/menu.c
new file mode 100644
index 000..3056cfc
--- /dev/null
+++ b/pc-bios/s390-ccw/menu.c
@@ -0,0 +1,26 @@
+/*
+ * QEMU S390 Interactive Boot Menu
+ *
+ * Copyright 2018 IBM Corp.
+ * Author: Collin L. Walling <wall...@linux.vnet.ibm.com>
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2 or (at
+ * your option) any later version. See the COPYING file in the top-level
+ * directory.
+ */
+
+#include "menu.h"
+
+static uint8_t flags;
+static uint64_t timeout;
+
+void menu_set_parms(uint8_t boot_menu_flag, uint32_t boot_menu_timeout)
+{
+flags = boot_menu_flag;
+timeout = boot_menu_timeout;
+}
+
+int menu_check_flags(uint8_t check_flags)
+{
+return flags & check_flags;
+}
diff --git a/pc-bios/s390-ccw/menu.h b/pc-bios/s390-ccw/menu.h
new file mode 100644
index 000..7df4114
--- /dev/null
+++ b/pc-bios/s390-ccw/menu.h
@@ -0,0 +1,23 @@
+/*
+ * QEMU S390 Interactive Boot Menu
+ *
+ * Copyright 2018 IBM Corp.
+ * Author: Collin L. Walling <wall...@linux.vnet.ibm.com>
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2 or (at
+ * your option) any later version. See the COPYING file in the top-level
+ * directory.
+ */
+
+#ifndef MENU_H
+#define MENU_H
+
+#include "libc.h"
+
+#define BOOT_MENU_FLAG_CMD_OPTS  0x80
+#define BOOT_MENU_FLAG_ZIPL_OPTS 0x40
+
+void menu_set_parms(uint8_t boot_menu_flags, uint32_t boot_menu_timeout);
+bool menu_check_flags(uint8_t check_flags);
+
+#endif /* MENU_H */
-- 
2.7.4




[Qemu-devel] [PATCH v6 10/12] s390-ccw: read user input for boot index via the SCLP console

2018-02-15 Thread Collin L. Walling
Implements an sclp_read function to capture input from the
console and a wrapper function that handles parsing certain
characters and adding input to a buffer. The input is checked
for any erroneous values and is handled appropriately.

A prompt will persist until input is entered or the timeout
expires (if one was set). Example:

Please choose (default will boot in 10 seconds):

Correct input will boot the respective boot index. If the
user's input is empty, 0, or if the timeout expires, then
the default zipl entry will be chosen. If the input is
within the range of available boot entries, then the
selection will be booted. Any erroneous input will cancel
the timeout and re-prompt the user.

Signed-off-by: Collin L. Walling <wall...@linux.vnet.ibm.com>
Reviewed-by: Thomas Huth <th...@redhat.com>
---
 pc-bios/s390-ccw/menu.c | 146 +++-
 pc-bios/s390-ccw/s390-ccw.h |   2 +
 pc-bios/s390-ccw/sclp.c |  19 ++
 pc-bios/s390-ccw/virtio.c   |   2 +-
 4 files changed, 167 insertions(+), 2 deletions(-)

diff --git a/pc-bios/s390-ccw/menu.c b/pc-bios/s390-ccw/menu.c
index 9631ac0..9601043 100644
--- a/pc-bios/s390-ccw/menu.c
+++ b/pc-bios/s390-ccw/menu.c
@@ -12,16 +12,160 @@
 #include "menu.h"
 #include "s390-ccw.h"
 
+#define KEYCODE_NO_INP '\0'
+#define KEYCODE_ESCAPE '\033'
+#define KEYCODE_BACKSP '\177'
+#define KEYCODE_ENTER  '\r'
+
 /* Offsets from zipl fields to zipl banner start */
 #define ZIPL_TIMEOUT_OFFSET 138
 #define ZIPL_FLAG_OFFSET140
 
+#define TOD_CLOCK_MILLISECOND   0x3e8000
+
 static uint8_t flags;
 static uint64_t timeout;
 
+static inline void enable_clock_int(void)
+{
+uint64_t tmp = 0;
+
+asm volatile(
+"stctg  0,0,%0\n"
+"oi 6+%0, 0x8\n"
+"lctlg  0,0,%0"
+: : "Q" (tmp) : "memory"
+);
+}
+
+static inline void disable_clock_int(void)
+{
+uint64_t tmp = 0;
+
+asm volatile(
+"stctg  0,0,%0\n"
+"ni 6+%0, 0xf7\n"
+"lctlg  0,0,%0"
+: : "Q" (tmp) : "memory"
+);
+}
+
+static inline void set_clock_comparator(uint64_t time)
+{
+asm volatile("sckc %0" : : "Q" (time));
+}
+
+static inline bool check_clock_int(void)
+{
+uint16_t *code = (uint16_t *)0x86; /* low-core external interrupt code */
+
+consume_sclp_int();
+
+return *code == 0x1004;
+}
+
+static int read_prompt(char *buf, size_t len)
+{
+char inp[2] = {};
+uint8_t idx = 0;
+uint64_t time;
+
+if (timeout) {
+time = get_clock() + timeout * TOD_CLOCK_MILLISECOND;
+set_clock_comparator(time);
+enable_clock_int();
+timeout = 0;
+}
+
+while (!check_clock_int()) {
+
+sclp_read(inp, 1); /* Process only one character at a time */
+
+switch (inp[0]) {
+case KEYCODE_NO_INP:
+case KEYCODE_ESCAPE:
+continue;
+case KEYCODE_BACKSP:
+if (idx > 0) {
+buf[--idx] = 0;
+sclp_print("\b \b");
+}
+continue;
+case KEYCODE_ENTER:
+disable_clock_int();
+return idx;
+default:
+/* Echo input and add to buffer */
+if (idx < len) {
+buf[idx++] = inp[0];
+sclp_print(inp);
+}
+}
+}
+
+disable_clock_int();
+*buf = 0;
+
+return 0;
+}
+
+static int get_index(void)
+{
+char buf[10];
+int len;
+int i;
+
+memset(buf, 0, sizeof(buf));
+
+len = read_prompt(buf, sizeof(buf));
+
+/* If no input, boot default */
+if (len == 0) {
+return 0;
+}
+
+/* Check for erroneous input */
+for (i = 0; i < len; i++) {
+if (!isdigit(buf[i])) {
+return -1;
+}
+}
+
+return atoui(buf);
+}
+
+static void boot_menu_prompt(bool retry)
+{
+char tmp[6];
+
+if (retry) {
+sclp_print("\nError: undefined configuration"
+   "\nPlease choose:\n");
+} else if (timeout > 0) {
+sclp_print("Please choose (default will boot in ");
+sclp_print(uitoa(timeout / 1000, tmp, sizeof(tmp)));
+sclp_print(" seconds):\n");
+} else {
+sclp_print("Please choose:\n");
+}
+}
+
 static int get_boot_index(int entries)
 {
-return 0; /* Implemented next patch */
+int boot_index;
+bool retry = false;
+char tmp[5];
+
+do {
+boot_menu_prompt(retry);
+boot_index = get_index();
+retry = true;
+} while (boot_index < 0 || boot_index >= entries);
+
+sclp_print("\nBooting entry #");
+sclp_print(uitoa(boot_index, tmp, sizeof(tmp)));
+
+return boot_index;
 }
 
 static void zipl_println(const char *d

[Qemu-devel] [PATCH v6 09/12] s390-ccw: print zipl boot menu

2018-02-15 Thread Collin L. Walling
When the boot menu options are present and the guest's
disk has been configured by the zipl tool, then the user
will be presented with an interactive boot menu with
labeled entries. An example of what the menu might look
like:

zIPL v1.37.1-build-20170714 interactive boot menu.

  0. default (linux-4.13.0)

  1. linux-4.13.0
  2. performance
  3. kvm

Signed-off-by: Collin L. Walling <wall...@linux.vnet.ibm.com>
Reviewed-by: Thomas Huth <th...@redhat.com>
---
 pc-bios/s390-ccw/menu.c | 49 -
 1 file changed, 48 insertions(+), 1 deletion(-)

diff --git a/pc-bios/s390-ccw/menu.c b/pc-bios/s390-ccw/menu.c
index 5790e0c..9631ac0 100644
--- a/pc-bios/s390-ccw/menu.c
+++ b/pc-bios/s390-ccw/menu.c
@@ -10,13 +10,60 @@
  */
 
 #include "menu.h"
+#include "s390-ccw.h"
+
+/* Offsets from zipl fields to zipl banner start */
+#define ZIPL_TIMEOUT_OFFSET 138
+#define ZIPL_FLAG_OFFSET140
 
 static uint8_t flags;
 static uint64_t timeout;
 
+static int get_boot_index(int entries)
+{
+return 0; /* Implemented next patch */
+}
+
+static void zipl_println(const char *data, size_t len)
+{
+char buf[len + 2];
+
+ebcdic_to_ascii(data, buf, len);
+buf[len] = '\n';
+buf[len + 1] = '\0';
+
+sclp_print(buf);
+}
+
 int menu_get_zipl_boot_index(const void *stage2, int offset)
 {
-return 0; /* implemented next patch */
+const char *data = stage2 + offset;
+uint16_t zipl_flag = *(uint16_t *)(data - ZIPL_FLAG_OFFSET);
+uint16_t zipl_timeout = *(uint16_t *)(data - ZIPL_TIMEOUT_OFFSET);
+size_t len;
+int ct;
+
+if (flags & BOOT_MENU_FLAG_ZIPL_OPTS) {
+if (!zipl_flag) {
+return 0; /* Boot default */
+}
+timeout = zipl_timeout * 1000;
+}
+
+/* Print and count all menu items, including the banner */
+for (ct = 0; *data; ct++) {
+len = strlen(data);
+zipl_println(data, len);
+data += len + 1;
+
+if (ct < 2) {
+sclp_print("\n");
+}
+}
+
+sclp_print("\n");
+
+return get_boot_index(ct - 1);
 }
 
 void menu_set_parms(uint8_t boot_menu_flag, uint32_t boot_menu_timeout)
-- 
2.7.4




[Qemu-devel] [PATCH v6 03/12] s390-ccw: refactor IPL structs

2018-02-15 Thread Collin L. Walling
ECKD DASDs have different IPL structures for CDL and LDL
formats. The current Ipl1 and Ipl2 structs follow the CDL
format, so we prepend "EckdCdl" to them. Boot info for LDL
has been moved to a new struct: EckdLdlIpl1.

Signed-off-by: Collin L. Walling <wall...@linux.vnet.ibm.com>
Acked-by: Janosch Frank <fran...@linux.vnet.ibm.com>
Reviewed-by: Thomas Huth <th...@redhat.com>
---
 pc-bios/s390-ccw/bootmap.c | 12 ++--
 pc-bios/s390-ccw/bootmap.h | 37 +
 2 files changed, 27 insertions(+), 22 deletions(-)

diff --git a/pc-bios/s390-ccw/bootmap.c b/pc-bios/s390-ccw/bootmap.c
index 9534f56..a94638d 100644
--- a/pc-bios/s390-ccw/bootmap.c
+++ b/pc-bios/s390-ccw/bootmap.c
@@ -221,7 +221,7 @@ static void run_eckd_boot_script(block_number_t 
bmt_block_nr)
 static void ipl_eckd_cdl(void)
 {
 XEckdMbr *mbr;
-Ipl2 *ipl2 = (void *)sec;
+EckdCdlIpl2 *ipl2 = (void *)sec;
 IplVolumeLabel *vlbl = (void *)sec;
 block_number_t bmt_block_nr;
 
@@ -231,7 +231,7 @@ static void ipl_eckd_cdl(void)
 memset(sec, FREE_SPACE_FILLER, sizeof(sec));
 read_block(1, ipl2, "Cannot read IPL2 record at block 1");
 
-mbr = >u.x.mbr;
+mbr = >mbr;
 IPL_assert(magic_match(mbr, ZIPL_MAGIC), "No zIPL section in IPL2 
record.");
 IPL_assert(block_size_ok(mbr->blockptr.xeckd.bptr.size),
"Bad block size in zIPL section of IPL2 record.");
@@ -281,7 +281,7 @@ static void print_eckd_ldl_msg(ECKD_IPL_mode_t mode)
 static void ipl_eckd_ldl(ECKD_IPL_mode_t mode)
 {
 block_number_t bmt_block_nr;
-BootInfo *bip = (void *)(sec + 0x70); /* BootInfo is MBR for LDL */
+EckdLdlIpl1 *ipl1 = (void *)sec;
 
 if (mode != ECKD_LDL_UNLABELED) {
 print_eckd_ldl_msg(mode);
@@ -292,15 +292,15 @@ static void ipl_eckd_ldl(ECKD_IPL_mode_t mode)
 memset(sec, FREE_SPACE_FILLER, sizeof(sec));
 read_block(0, sec, "Cannot read block 0 to grab boot info.");
 if (mode == ECKD_LDL_UNLABELED) {
-if (!magic_match(bip->magic, ZIPL_MAGIC)) {
+if (!magic_match(ipl1->bip.magic, ZIPL_MAGIC)) {
 return; /* not applicable layout */
 }
 sclp_print("unlabeled LDL.\n");
 }
-verify_boot_info(bip);
+verify_boot_info(>bip);
 
 /* save pointer to Boot Map Table */
-bmt_block_nr = eckd_block_num(>bp.ipl.bm_ptr.eckd.bptr.chs);
+bmt_block_nr = eckd_block_num(>bip.bp.ipl.bm_ptr.eckd.bptr.chs);
 
 run_eckd_boot_script(bmt_block_nr);
 /* no return */
diff --git a/pc-bios/s390-ccw/bootmap.h b/pc-bios/s390-ccw/bootmap.h
index 7a13c9b..1ddc08f 100644
--- a/pc-bios/s390-ccw/bootmap.h
+++ b/pc-bios/s390-ccw/bootmap.h
@@ -240,22 +240,27 @@ typedef struct BootInfo {  /* @ 0x70, record #0   
 */
 } bp;
 } __attribute__ ((packed)) BootInfo; /* see also XEckdMbr   */
 
-typedef struct Ipl1 {
-unsigned char key[4]; /* == "IPL1" */
-unsigned char data[24];
-} __attribute__((packed)) Ipl1;
-
-typedef struct Ipl2 {
-unsigned char key[4]; /* == "IPL2" */
-union {
-unsigned char data[144];
-struct {
-unsigned char reserved1[92-4];
-XEckdMbr mbr;
-unsigned char reserved2[144-(92-4)-sizeof(XEckdMbr)];
-} x;
-} u;
-} __attribute__((packed)) Ipl2;
+/*
+ * Structs for IPL
+ */
+#define STAGE2_BLK_CNT_MAX  24 /* Stage 1b can load up to 24 blocks */
+
+typedef struct EckdCdlIpl1 {
+uint8_t key[4]; /* == "IPL1" */
+uint8_t data[24];
+} __attribute__((packed)) EckdCdlIpl1;
+
+typedef struct EckdCdlIpl2 {
+uint8_t key[4]; /* == "IPL2" */
+uint8_t reserved0[88];
+XEckdMbr mbr;
+uint8_t reserved[24];
+} __attribute__((packed)) EckdCdlIpl2;
+
+typedef struct EckdLdlIpl1 {
+uint8_t reserved[112];
+BootInfo bip; /* BootInfo is MBR for LDL */
+} __attribute__((packed)) EckdLdlIpl1;
 
 typedef struct IplVolumeLabel {
 unsigned char key[4]; /* == "VOL1" */
-- 
2.7.4




[Qemu-devel] [PATCH v6 05/12] s390-ccw: move auxiliary IPL data to separate location

2018-02-15 Thread Collin L. Walling
The s390-ccw firmware needs some information in support of the
boot process which is not available on the native machine.
Examples are the netboot firmware load address and now the
boot menu parameters.

While storing that data in unused fields of the IPL parameter block
works, that approach could create problems if the parameter block
definition should change in the future. Because then a guest could
overwrite these fields using the set IPLB diagnose.

In fact the data in question is of more global nature and not really
tied to an IPL device, so separating it is rather logical.

This commit introduces a new structure to hold firmware relevant
IPL parameters set by QEMU. The data is stored at location 204 (dec)
and can contain up to 7 32-bit words. This area is available to
programming in the z/Architecture Principles of Operation and
can thus safely be used by the firmware until the IPL has completed.

Signed-off-by: Viktor Mihajlovski 
---
 hw/s390x/ipl.c  | 19 ++-
 hw/s390x/ipl.h  | 13 +++--
 pc-bios/s390-ccw/iplb.h | 14 --
 pc-bios/s390-ccw/main.c |  6 +-
 4 files changed, 46 insertions(+), 6 deletions(-)

diff --git a/hw/s390x/ipl.c b/hw/s390x/ipl.c
index 0d06fc1..31565ce 100644
--- a/hw/s390x/ipl.c
+++ b/hw/s390x/ipl.c
@@ -399,6 +399,21 @@ void s390_reipl_request(void)
 qemu_system_reset_request(SHUTDOWN_CAUSE_GUEST_RESET);
 }
 
+static void s390_ipl_prepare_qipl(S390CPU *cpu)
+{
+S390IPLState *ipl = get_ipl_device();
+uint8_t *addr;
+uint64_t len = 4096;
+
+addr = cpu_physical_memory_map(cpu->env.psa, , 1);
+if (!addr || len < QIPL_ADDRESS + sizeof(QemuIplParameters)) {
+error_report("Cannot set QEMU IPL parameters");
+return;
+}
+memcpy(addr + QIPL_ADDRESS, >iplb.qipl, sizeof(QemuIplParameters));
+cpu_physical_memory_unmap(addr, len, 1, len);
+}
+
 void s390_ipl_prepare_cpu(S390CPU *cpu)
 {
 S390IPLState *ipl = get_ipl_device();
@@ -418,8 +433,10 @@ void s390_ipl_prepare_cpu(S390CPU *cpu)
 error_report_err(err);
 vm_stop(RUN_STATE_INTERNAL_ERROR);
 }
-ipl->iplb.ccw.netboot_start_addr = cpu_to_be64(ipl->start_addr);
+ipl->iplb.qipl.netboot_start_addr = cpu_to_be64(ipl->start_addr);
 }
+s390_ipl_prepare_qipl(cpu);
+
 }
 
 static void s390_ipl_reset(DeviceState *dev)
diff --git a/hw/s390x/ipl.h b/hw/s390x/ipl.h
index 8a705e0..cab8a97 100644
--- a/hw/s390x/ipl.h
+++ b/hw/s390x/ipl.h
@@ -16,8 +16,7 @@
 #include "cpu.h"
 
 struct IplBlockCcw {
-uint64_t netboot_start_addr;
-uint8_t  reserved0[77];
+uint8_t  reserved0[85];
 uint8_t  ssid;
 uint16_t devno;
 uint8_t  vm_flags;
@@ -59,6 +58,15 @@ typedef struct IplBlockQemuScsi IplBlockQemuScsi;
 
 #define DIAG308_FLAGS_LP_VALID 0x80
 
+#define QIPL_ADDRESS  0xcc
+
+struct QemuIplParameters {
+uint8_t  reserved1[4];
+uint64_t netboot_start_addr;
+uint8_t  reserved2[16];
+} QEMU_PACKED;
+typedef struct QemuIplParameters QemuIplParameters;
+
 union IplParameterBlock {
 struct {
 uint32_t len;
@@ -74,6 +82,7 @@ union IplParameterBlock {
 IplBlockFcp fcp;
 IplBlockQemuScsi scsi;
 };
+QemuIplParameters qipl;
 } QEMU_PACKED;
 struct {
 uint8_t  reserved1[110];
diff --git a/pc-bios/s390-ccw/iplb.h b/pc-bios/s390-ccw/iplb.h
index 890aed9..1266884 100644
--- a/pc-bios/s390-ccw/iplb.h
+++ b/pc-bios/s390-ccw/iplb.h
@@ -13,8 +13,7 @@
 #define IPLB_H
 
 struct IplBlockCcw {
-uint64_t netboot_start_addr;
-uint8_t  reserved0[77];
+uint8_t  reserved0[85];
 uint8_t  ssid;
 uint16_t devno;
 uint8_t  vm_flags;
@@ -73,6 +72,17 @@ typedef struct IplParameterBlock IplParameterBlock;
 
 extern IplParameterBlock iplb __attribute__((__aligned__(PAGE_SIZE)));
 
+#define QIPL_ADDRESS  0xcc
+
+struct QemuIplParameters {
+uint8_t  reserved1[4];
+uint64_t netboot_start_addr;
+uint8_t  reserved2[16];
+} __attribute__ ((packed));
+typedef struct QemuIplParameters QemuIplParameters;
+
+extern QemuIplParameters qipl;
+
 #define S390_IPL_TYPE_FCP 0x00
 #define S390_IPL_TYPE_CCW 0x02
 #define S390_IPL_TYPE_QEMU_SCSI 0xff
diff --git a/pc-bios/s390-ccw/main.c b/pc-bios/s390-ccw/main.c
index e857ce4..e41b264 100644
--- a/pc-bios/s390-ccw/main.c
+++ b/pc-bios/s390-ccw/main.c
@@ -16,6 +16,7 @@ char stack[PAGE_SIZE * 8] 
__attribute__((__aligned__(PAGE_SIZE)));
 static SubChannelId blk_schid = { .one = 1 };
 IplParameterBlock iplb __attribute__((__aligned__(PAGE_SIZE)));
 static char loadparm[8] = { 0, 0, 0, 0, 0, 0, 0, 0 };
+QemuIplParameters qipl;
 
 /*
  * Priniciples of Operations (SA22-7832-09) chapter 17 requires that
@@ -81,6 +82,7 @@ static void virtio_setup(void)
 uint16_t dev_no;
 char ldp[] = "LOADPARM=[]\n";
 VDev *vdev = virtio_get_device();
+QemuIplParameters *early_qipl = (QemuIplParameters *)QIPL_ADDRESS;
 
 /*
  * We 

[Qemu-devel] [PATCH v6 01/12] s390-ccw: refactor boot map table code

2018-02-15 Thread Collin L. Walling
Some ECKD bootmap code was using structs designed for SCSI.
Even though this works, it confuses readability. Add a new
BootMapTable struct to assist with readability in bootmap
entry code. Also:

- replace ScsiMbr in ECKD code with appropriate structs
- fix read_block messages to reflect BootMapTable
- fixup ipl_scsi to use BootMapTable (referred to as Program Table)
- defined value for maximum table entries

Signed-off-by: Collin L. Walling <wall...@linux.vnet.ibm.com>
---
 pc-bios/s390-ccw/bootmap.c | 60 +-
 pc-bios/s390-ccw/bootmap.h | 14 +--
 2 files changed, 39 insertions(+), 35 deletions(-)

diff --git a/pc-bios/s390-ccw/bootmap.c b/pc-bios/s390-ccw/bootmap.c
index 67a6123..286de40 100644
--- a/pc-bios/s390-ccw/bootmap.c
+++ b/pc-bios/s390-ccw/bootmap.c
@@ -182,24 +182,24 @@ static block_number_t load_eckd_segments(block_number_t 
blk, uint64_t *address)
 return block_nr;
 }
 
-static void run_eckd_boot_script(block_number_t mbr_block_nr)
+static void run_eckd_boot_script(block_number_t bmt_block_nr)
 {
 int i;
 unsigned int loadparm = get_loadparm_index();
 block_number_t block_nr;
 uint64_t address;
-ScsiMbr *bte = (void *)sec; /* Eckd bootmap table entry */
+BootMapTable *bmt = (void *)sec;
 BootMapScript *bms = (void *)sec;
 
 debug_print_int("loadparm", loadparm);
-IPL_assert(loadparm < 31, "loadparm value greater than"
+IPL_assert(loadparm <= MAX_TABLE_ENTRIES, "loadparm value greater than"
" maximum number of boot entries allowed");
 
 memset(sec, FREE_SPACE_FILLER, sizeof(sec));
-read_block(mbr_block_nr, sec, "Cannot read MBR");
+read_block(bmt_block_nr, sec, "Cannot read Boot Map Table");
 
-block_nr = eckd_block_num((void *)&(bte->blockptr[loadparm]));
-IPL_assert(block_nr != -1, "No Boot Map");
+block_nr = eckd_block_num((void *)>entry[loadparm]);
+IPL_assert(block_nr != -1, "Cannot find Boot Map Table Entry");
 
 memset(sec, FREE_SPACE_FILLER, sizeof(sec));
 read_block(block_nr, sec, "Cannot read Boot Map Script");
@@ -223,7 +223,7 @@ static void ipl_eckd_cdl(void)
 XEckdMbr *mbr;
 Ipl2 *ipl2 = (void *)sec;
 IplVolumeLabel *vlbl = (void *)sec;
-block_number_t block_nr;
+block_number_t bmt_block_nr;
 
 /* we have just read the block #0 and recognized it as "IPL1" */
 sclp_print("CDL\n");
@@ -238,8 +238,8 @@ static void ipl_eckd_cdl(void)
 IPL_assert(mbr->dev_type == DEV_TYPE_ECKD,
"Non-ECKD device type in zIPL section of IPL2 record.");
 
-/* save pointer to Boot Script */
-block_nr = eckd_block_num((void *)&(mbr->blockptr));
+/* save pointer to Boot Map Table */
+bmt_block_nr = eckd_block_num((void *)>blockptr);
 
 memset(sec, FREE_SPACE_FILLER, sizeof(sec));
 read_block(2, vlbl, "Cannot read Volume Label at block 2");
@@ -249,7 +249,7 @@ static void ipl_eckd_cdl(void)
"Invalid magic of volser block");
 print_volser(vlbl->f.volser);
 
-run_eckd_boot_script(block_nr);
+run_eckd_boot_script(bmt_block_nr);
 /* no return */
 }
 
@@ -280,7 +280,7 @@ static void print_eckd_ldl_msg(ECKD_IPL_mode_t mode)
 
 static void ipl_eckd_ldl(ECKD_IPL_mode_t mode)
 {
-block_number_t block_nr;
+block_number_t bmt_block_nr;
 BootInfo *bip = (void *)(sec + 0x70); /* BootInfo is MBR for LDL */
 
 if (mode != ECKD_LDL_UNLABELED) {
@@ -299,8 +299,10 @@ static void ipl_eckd_ldl(ECKD_IPL_mode_t mode)
 }
 verify_boot_info(bip);
 
-block_nr = eckd_block_num((void *)&(bip->bp.ipl.bm_ptr.eckd.bptr));
-run_eckd_boot_script(block_nr);
+/* save pointer to Boot Map Table */
+bmt_block_nr = eckd_block_num((void *)>bp.ipl.bm_ptr.eckd.bptr);
+
+run_eckd_boot_script(bmt_block_nr);
 /* no return */
 }
 
@@ -325,7 +327,7 @@ static void print_eckd_msg(void)
 
 static void ipl_eckd(void)
 {
-ScsiMbr *mbr = (void *)sec;
+XEckdMbr *mbr = (void *)sec;
 LDL_VTOC *vlbl = (void *)sec;
 
 print_eckd_msg();
@@ -449,10 +451,8 @@ static void zipl_run(ScsiBlockPtr *pte)
 static void ipl_scsi(void)
 {
 ScsiMbr *mbr = (void *)sec;
-uint8_t *ns, *ns_end;
 int program_table_entries = 0;
-const int pte_len = sizeof(ScsiBlockPtr);
-ScsiBlockPtr *prog_table_entry = NULL;
+BootMapTable *prog_table = (void *)sec;
 unsigned int loadparm = get_loadparm_index();
 
 /* Grab the MBR */
@@ -467,34 +467,28 @@ static void ipl_scsi(void)
 debug_print_int("MBR Version", mbr->version_id);
 IPL_check(mbr->version_id == 1,
   "Unknown MBR layout version, assuming version 1");
-debug_print_int("program table", mbr->blockptr[0].blockno);
-IPL_assert(mbr->bloc

[Qemu-devel] [PATCH v6 04/12] s390-ccw: update libc

2018-02-15 Thread Collin L. Walling
Moved:
  memcmp from bootmap.h to libc.h (renamed from _memcmp)
  strlen from sclp.c to libc.h (renamed from _strlen)

Added C standard functions:
  isdigit

Added non C-standard function:
  uitoa
  atoui

Signed-off-by: Collin L. Walling <wall...@linux.vnet.ibm.com>
Acked-by: Christian Borntraeger <borntrae...@de.ibm.com>
Reviewed-by: Janosch Frank <fran...@linux.vnet.ibm.com>
---
 pc-bios/s390-ccw/Makefile |  2 +-
 pc-bios/s390-ccw/libc.c   | 89 +++
 pc-bios/s390-ccw/libc.h   | 37 ++--
 pc-bios/s390-ccw/main.c   | 17 +
 4 files changed, 126 insertions(+), 19 deletions(-)
 create mode 100644 pc-bios/s390-ccw/libc.c

diff --git a/pc-bios/s390-ccw/Makefile b/pc-bios/s390-ccw/Makefile
index 6d0c2ee..9f7904f 100644
--- a/pc-bios/s390-ccw/Makefile
+++ b/pc-bios/s390-ccw/Makefile
@@ -9,7 +9,7 @@ $(call set-vpath, $(SRC_PATH)/pc-bios/s390-ccw)
 
 .PHONY : all clean build-all
 
-OBJECTS = start.o main.o bootmap.o sclp.o virtio.o virtio-scsi.o 
virtio-blkdev.o
+OBJECTS = start.o main.o bootmap.o sclp.o virtio.o virtio-scsi.o 
virtio-blkdev.o libc.o
 QEMU_CFLAGS := $(filter -W%, $(QEMU_CFLAGS))
 QEMU_CFLAGS += -ffreestanding -fno-delete-null-pointer-checks -msoft-float
 QEMU_CFLAGS += -march=z900 -fPIE -fno-strict-aliasing
diff --git a/pc-bios/s390-ccw/libc.c b/pc-bios/s390-ccw/libc.c
new file mode 100644
index 000..a144388
--- /dev/null
+++ b/pc-bios/s390-ccw/libc.c
@@ -0,0 +1,89 @@
+/*
+ * libc-style definitions and functions
+ *
+ * Copyright 2018 IBM Corp.
+ * Author(s): Collin L. Walling <wall...@linux.vnet.ibm.com>
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ */
+
+#include "libc.h"
+#include "s390-ccw.h"
+
+/**
+ * atoui:
+ * @str: the string to be converted.
+ *
+ * Given a string @str, convert it to an integer. Leading spaces are
+ * ignored. Any other non-numerical value will terminate the conversion
+ * and return 0. This function only handles numbers between 0 and
+ * UINT64_MAX inclusive.
+ *
+ * Returns: an integer converted from the string @str, or the number 0
+ * if an error occurred.
+ */
+uint64_t atoui(const char *str)
+{
+int val = 0;
+
+if (!str || !str[0]) {
+return 0;
+}
+
+while (*str == ' ') {
+str++;
+}
+
+while (*str) {
+if (!isdigit(*str)) {
+break;
+}
+val = val * 10 + *str - '0';
+str++;
+}
+
+return val;
+}
+
+/**
+ * uitoa:
+ * @num: an integer (base 10) to be converted.
+ * @str: a pointer to a string to store the conversion.
+ * @len: the length of the passed string.
+ *
+ * Given an integer @num, convert it to a string. The string @str must be
+ * allocated beforehand. The resulting string will be null terminated and
+ * returned. This function only handles numbers between 0 and UINT64_MAX
+ * inclusive.
+ *
+ * Returns: the string @str of the converted integer @num
+ */
+char *uitoa(uint64_t num, char *str, size_t len)
+{
+size_t num_idx = 0;
+uint64_t tmp = num;
+
+IPL_assert(str != NULL, "uitoa: no space allocated to store string");
+
+/* Get index to ones place */
+while ((tmp /= 10) != 0) {
+num_idx++;
+}
+
+/* Check if we have enough space for num and null */
+IPL_assert(len > num_idx, "uitoa: array too small for conversion");
+
+str[num_idx + 1] = '\0';
+
+/* Convert int to string */
+while (num_idx >= 0) {
+str[num_idx] = num % 10 + '0';
+num /= 10;
+num_idx--;
+}
+
+return str;
+}
diff --git a/pc-bios/s390-ccw/libc.h b/pc-bios/s390-ccw/libc.h
index 0142ea8..63ece70 100644
--- a/pc-bios/s390-ccw/libc.h
+++ b/pc-bios/s390-ccw/libc.h
@@ -1,6 +1,8 @@
 /*
  * libc-style definitions and functions
  *
+ * Copyright (c) 2013 Alexander Graf <ag...@suse.de>
+ *
  * This code is free software; you can redistribute it and/or modify it
  * under the terms of the GNU General Public License as published by the
  * Free Software Foundation; either version 2 of the License, or (at your
@@ -19,7 +21,7 @@ typedef unsigned long long uint64_t;
 
 static inline void *memset(void *s, int c, size_t n)
 {
-int i;
+size_t i;
 unsigned char *p = s;
 
 for (i = 0; i < n; i++) {
@@ -33,7 +35,7 @@ static inline void *memcpy(void *s1, const void *s2, size_t n)
 {
 uint8_t *dest = s1;
 const uint8_t *src = s2;
-int i;
+size_t i;
 
 for (i = 0; i < n; i++) {
 dest[i] = src[i];
@@ -42,4 +44,35 @@ static inline void *memcpy(void *s1, const void *s2, size_t 
n)
 return s1;
 }
 
+static inline int memcmp(const void *s1, const void *s2, size_t n)
+{
+size_t i;
+const uint8_t *p1 = s1, *p2 = s2;
+
+for (i = 0; i <

Re: [Qemu-devel] [qemu-s390x] [PATCH v5 11/12] s390-ccw: clear pending irqs

2018-02-15 Thread Collin L. Walling

On 02/15/2018 02:04 AM, Thomas Huth wrote:

On 14.02.2018 16:33, Collin L. Walling wrote:

On 02/14/2018 05:57 AM, David Hildenbrand wrote:

[...]

1. CKC interrupts can be cleared by resetting the CKC
2. SCLP interrupts can be cleared only via delivery (apart from CPU
reset)

So if you have CKC and SCLP pending at the same time, you get the CKC
delivered first and the SCLP remains pending.

Now, the easiest way to clear that (if you don't know if any is
pending!) is to simply print a string. Then you know that you have
exactly one SCLP interrupt pending.

So simply printing a string after potentially reading should be
sufficient to clear the SCLP interrupt deterministically :)

Perhaps it is due to my lack of understanding of how irqs are queued,
but is it
possible that we could still end up with service interrupts pending in
the SCLP?
Specifically if we're still accepting external interrupts from
keystrokes but we
aren't reading anything from the SCLP.

Let's say we have 1 service signal pending and we go to print something.
This
executes the sclp service call instruction and generates a new service
signal.
The SCLP would consume one of the service interrupts and write to the
console.
We still have 1 interrupt pending that we need to deal with.

That 1 pending interrupt could have been generated at any time we're still
listening to activity from the keyboard.

There is no "queue" or something like this for service interrupts.
Either one service interrupt is pending, or it is not. Have a look at
arch/s390/kvm/interrupt.c in the Linux kernel sources and search for the
functions __deliver_service() and __inject_service() for example.


In my next update to this patch, I setup the control program receive
mask in
the SCLP only when we need to get input from the user and then clear the
mask
when we're done. Doing so will make it so we generate an interrupt from
keystrokes ONLY when the mask is set. No external interrupts from
keystrokes
will be generated when the cp_receive mask is NOT set.

After I clear the cp_receive mask, we consume any leftover interrupts by
calling consume_sclp_int (I also fixup the patch to make sure we only end
irq-clearing on a ckc interrupt -- oops).

Not sure whether you really have to deal with the ckc here again to get
rid of pending service interrupts... David's idea to simply print out
something to clear the pending service interrupt sounds easier to me.

  Thomas



Ah, I understand the problem now. We can't have a multiple irqs of the 
*same* *type*
pending at the same time, but we /can/ have multiple irqs of *different* 
*types* pending

at the same time (i.e. a ckc and service signal).

Thanks for clearing this up for me.  I was over thinking the problem and 
I agree that

a print would be the easiest solution. :)

--
- Collin L Walling




Re: [Qemu-devel] [qemu-s390x] [PATCH v5 06/12] s390-ccw: parse and set boot menu options

2018-02-14 Thread Collin L. Walling
I'm beginning to like the usage of splash-time to represent a timeout 
for the boot menu
less and less.  It is really meant for how long a _splash_ _image_ 
should appear during boot.


I'd like to suggest adding a new boot option "menu-timeout".  An 
alternative would be
documenting in qemu-options.hx that s390 treats "splash-time" as the 
menu-timeout.


Thoughts?

On 02/05/2018 03:57 PM, Collin L. Walling wrote:

Set boot menu options for an s390 guest and store them in
the iplb. These options are set via the QEMU command line
option:

 -boot menu=on|off[,splash-time=X]

or via the libvirt domain xml:

 
   
 

Where X represents some positive integer representing
milliseconds.

Any value set for loadparm will override all boot menu options.
If loadparm=PROMPT, then the menu will be enabled without a
timeout.

The absence of any boot options on the command line will flag
to later use the zipl boot loader values.

Signed-off-by: Collin L. Walling <wall...@linux.vnet.ibm.com>
Reviewed-by: Janosch Frank <fran...@linux.vnet.ibm.com>
Reviewed-by: Thomas Huth <th...@redhat.com>
---
[...]

+static void s390_ipl_set_boot_menu(IplParameterBlock *iplb)
+{
+QemuOptsList *plist = qemu_find_opts("boot-opts");
+QemuOpts *opts = QTAILQ_FIRST(>head);
+uint8_t *flags;
+uint16_t *timeout;
+const char *tmp;
+unsigned long result = 0;
+
+switch (iplb->pbt) {
+case S390_IPL_TYPE_CCW:
+case S390_IPL_TYPE_QEMU_SCSI:
+flags = >qipl.boot_menu_flags;
+timeout = >qipl.boot_menu_timeout;
+break;
+default:
+error_report("boot menu is not supported for this device type.");
+return;
+}
+
+/* In the absence of -boot menu, use zipl parameters */
+if (!qemu_opt_get(opts, "menu")) {
+*flags = BOOT_MENU_FLAG_ZIPL_OPTS;
+} else if (boot_menu) {
+*flags = BOOT_MENU_FLAG_CMD_OPTS;
+
+tmp = qemu_opt_get(opts, "splash-time");
+
+if (tmp && qemu_strtoul(tmp, NULL, 10, )) {
+error_report("splash-time value is invalid, forcing it to 0.");
+*timeout = 0;
+return;
+}
+
+result = (result + 500) / 1000; /* Round and convert to seconds */
+
+if (result > 0x) {
+error_report("splash-time value is greater than 65535000,"
+ " forcing it to 65535000.");
+        *timeout = 0x;
+return;
+}
+
+*timeout = cpu_to_be16(result);
+}
+}
+
[...]



--
- Collin L Walling




Re: [Qemu-devel] [qemu-s390x] [PATCH v5 11/12] s390-ccw: clear pending irqs

2018-02-14 Thread Collin L. Walling

On 02/14/2018 05:57 AM, David Hildenbrand wrote:

On 05.02.2018 21:57, Collin L. Walling wrote:

It is possible while waiting for multiple types of external
interrupts that we might have pending irqs remaining between
irq consumption and irq disabling. Those interrupts could
propagate to the guest after IPL completes and cause unwanted
behavior.

To avoid this, we clear the write event mask to prevent further
service interrupts from ASCII events and then consume all pending
irqs for a miniscule duration. Once finished, we reset the write
event mask and resume business as usual.

Signed-off-by: Collin L. Walling <wall...@linux.vnet.ibm.com>
---
  pc-bios/s390-ccw/menu.c | 16 
  pc-bios/s390-ccw/sclp.c | 12 
  2 files changed, 28 insertions(+)

diff --git a/pc-bios/s390-ccw/menu.c b/pc-bios/s390-ccw/menu.c
index 85d285f..971f6b6 100644
--- a/pc-bios/s390-ccw/menu.c
+++ b/pc-bios/s390-ccw/menu.c
@@ -64,6 +64,20 @@ static inline bool check_clock_int(void)
  return *code == 0x1004;
  }
  
+static void clear_pending_irqs(void)

+{
+uint64_t time = 50 * TOD_CLOCK_SECOND / 0x3e8;
+
+sclp_clear_write_mask();
+
+set_clock_comparator(get_clock() + time);
+enable_clock_int();
+consume_sclp_int();
+disable_clock_int();
+
+sclp_setup(); /* re-enable write mask */
+}
+
  static int read_prompt(char *buf, size_t len)
  {
  char inp[2] = {};
@@ -165,6 +179,8 @@ static int get_boot_index(int entries)
  sclp_print("\nBooting entry #");
  sclp_print(itostr(boot_index, tmp, sizeof(tmp)));
  
+clear_pending_irqs();

+
  return boot_index;
  }
  
diff --git a/pc-bios/s390-ccw/sclp.c b/pc-bios/s390-ccw/sclp.c

index 5902d5b..025eb2d 100644
--- a/pc-bios/s390-ccw/sclp.c
+++ b/pc-bios/s390-ccw/sclp.c
@@ -46,6 +46,18 @@ static int sclp_service_call(unsigned int command, void 
*sccb)
  return 0;
  }
  
+void sclp_clear_write_mask(void)

+{
+WriteEventMask *sccb = (void *)_sccb;
+
+sccb->h.length = sizeof(WriteEventMask);
+sccb->mask_length = sizeof(unsigned int);
+sccb->cp_receive_mask = 0;
+sccb->cp_send_mask = 0;
+
+sclp_service_call(SCLP_CMD_WRITE_EVENT_MASK, sccb);
+}
+
  static void sclp_set_write_mask(void)
  {
  WriteEventMask *sccb = (void *)_sccb;


1. CKC interrupts can be cleared by resetting the CKC
2. SCLP interrupts can be cleared only via delivery (apart from CPU reset)

So if you have CKC and SCLP pending at the same time, you get the CKC
delivered first and the SCLP remains pending.

Now, the easiest way to clear that (if you don't know if any is
pending!) is to simply print a string. Then you know that you have
exactly one SCLP interrupt pending.

So simply printing a string after potentially reading should be
sufficient to clear the SCLP interrupt deterministically :)




Perhaps it is due to my lack of understanding of how irqs are queued, 
but is it
possible that we could still end up with service interrupts pending in 
the SCLP?
Specifically if we're still accepting external interrupts from 
keystrokes but we

aren't reading anything from the SCLP.

Let's say we have 1 service signal pending and we go to print something. 
This
executes the sclp service call instruction and generates a new service 
signal.
The SCLP would consume one of the service interrupts and write to the 
console.

We still have 1 interrupt pending that we need to deal with.

That 1 pending interrupt could have been generated at any time we're still
listening to activity from the keyboard.

In my next update to this patch, I setup the control program receive mask in
the SCLP only when we need to get input from the user and then clear the 
mask

when we're done. Doing so will make it so we generate an interrupt from
keystrokes ONLY when the mask is set. No external interrupts from 
keystrokes

will be generated when the cp_receive mask is NOT set.

After I clear the cp_receive mask, we consume any leftover interrupts by
calling consume_sclp_int (I also fixup the patch to make sure we only end
irq-clearing on a ckc interrupt -- oops).

Am I at least in the ballpark regarding the problem this patch aims to 
solve?


--
- Collin L Walling




Re: [Qemu-devel] [qemu-s390x] [PATCH v5 05/12] s390-ccw: move auxiliary IPL data to separate location

2018-02-14 Thread Collin L. Walling

On 02/06/2018 05:13 AM, Viktor Mihajlovski wrote:

On 06.02.2018 10:23, Thomas Huth wrote:

On 05.02.2018 21:57, Collin L. Walling wrote:
[...]

diff --git a/pc-bios/s390-ccw/main.c b/pc-bios/s390-ccw/main.c
index e857ce4..825a1a3 100644
--- a/pc-bios/s390-ccw/main.c
+++ b/pc-bios/s390-ccw/main.c
@@ -16,6 +16,7 @@ char stack[PAGE_SIZE * 8] 
__attribute__((__aligned__(PAGE_SIZE)));
  static SubChannelId blk_schid = { .one = 1 };
  IplParameterBlock iplb __attribute__((__aligned__(PAGE_SIZE)));
  static char loadparm[8] = { 0, 0, 0, 0, 0, 0, 0, 0 };
+QemuIplParameters qipl;
  
  /*

   * Priniciples of Operations (SA22-7832-09) chapter 17 requires that
@@ -81,6 +82,7 @@ static void virtio_setup(void)
  uint16_t dev_no;
  char ldp[] = "LOADPARM=[]\n";
  VDev *vdev = virtio_get_device();
+QemuIplParameters *early_qipl = (QemuIplParameters *)204;

Could you please introduce a proper #define for that magic 204 value
(and use it in s390_ipl_prepare_qipl, too)? ... so that it is later
easier to grep for this.


Hm ... I was following the pattern established in
write_subsystem_identification(). Christian, what is your opinion?


Any updates on this?  Last change I need to make before the next post.

--
- Collin L Walling




Re: [Qemu-devel] [qemu-s390x] [PATCH v5 04/12] s390-ccw: update libc

2018-02-06 Thread Collin L. Walling

On 02/06/2018 01:14 AM, Thomas Huth wrote:

On 05.02.2018 21:57, Collin L. Walling wrote:

Moved:
   memcmp from bootmap.h to libc.h (renamed from _memcmp)
   strlen from sclp.c to libc.h (renamed from _strlen)

Added C standard functions:
   isdigit

Added non C-standard function:
   itostr
   atoui

Signed-off-by: Collin L. Walling <wall...@linux.vnet.ibm.com>
Acked-by: Christian Borntraeger <borntrae...@de.ibm.com>
Reviewed-by: Janosch Frank <fran...@linux.vnet.ibm.com>
---

[...]

+/**
+ * itostr:
+ * @num: an integer (base 10) to be converted.
+ * @str: a pointer to a string to store the conversion.
+ * @len: the length of the passed string.
+ *
+ * Given an integer @num, convert it to a string. The string @str must be
+ * allocated beforehand. The resulting string will be null terminated and
+ * returned. This function only handles numbers between 0 and UINT64_MAX
+ * inclusive.
+ *
+ * Returns: the string @str of the converted integer @num; NULL if @str
+ * is NULL or if there is not enough space allocated.
+ */
+char *itostr(uint64_t num, char *str, size_t len)

Nitpicking: You renamed atoi to atoui, so maybe this should now rather
be uitostr or uitoa now?


Was thinking the same right after I hit submit.





+{
+size_t num_idx = 0;
+uint64_t tmp = num;
+
+IPL_assert(num >= 0, "itostr: cannot convert negative values");

(already mentioned by patchew)


+IPL_assert(str != NULL, "itostr: no space allocated to store string");
+
+/* Get index to ones place */
+while ((tmp /= 10) != 0) {
+num_idx++;
+}
+
+/* Check if we have enough space for num and null */
+IPL_assert(len >= num_idx + 1, "itostr: array too small for conversion");

Should that rather be "len > num_idx + 1" instead?


Yes -- thank you.  That's what I get for trying to copy-paste old 
conditionals

into an assert.





+str[num_idx + 1] = '\0';
+
+/* Convert int to string */
+while (num_idx >= 0) {
+str[num_idx] = num % 10 + '0';
+num /= 10;
+        num_idx--;
+}
+
+return str;
+}

  Thomas




--
- Collin L Walling




Re: [Qemu-devel] [qemu-s390x] [PATCH v5 05/12] s390-ccw: move auxiliary IPL data to separate location

2018-02-06 Thread Collin L. Walling

On 02/06/2018 05:13 AM, Viktor Mihajlovski wrote:

On 06.02.2018 10:23, Thomas Huth wrote:

On 05.02.2018 21:57, Collin L. Walling wrote:
[...]

diff --git a/hw/s390x/ipl.c b/hw/s390x/ipl.c
index 0d06fc1..3e3c3b8 100644
--- a/hw/s390x/ipl.c
+++ b/hw/s390x/ipl.c
@@ -399,6 +399,20 @@ void s390_reipl_request(void)
  qemu_system_reset_request(SHUTDOWN_CAUSE_GUEST_RESET);
  }
  
+static void s390_ipl_prepare_qipl(S390CPU *cpu)

+{
+S390IPLState *ipl = get_ipl_device();
+uint8_t *addr;
+uint64_t len = 4096;
+
+addr = cpu_physical_memory_map(cpu->env.psa, , 1);
+if (!addr || len < 204 + sizeof(QemuIplParameters)) {
+error_report("Cannot set QEMU IPL parameters");

I think you should return or exit() here. Otherwise the memcpy below
accesses an illegal memory range.Right, I have noticed and fixed that on my 
private branch, but forgot to

update the patch. Collin, could you squash in a
 return;


Can do.

[...]


--
- Collin L Walling




Re: [Qemu-devel] [qemu-s390x] [PATCH v5 01/12] s390-ccw: refactor boot map table code

2018-02-06 Thread Collin L. Walling

On 02/06/2018 12:52 AM, Thomas Huth wrote:

On 05.02.2018 21:57, Collin L. Walling wrote:

- replace ScsiMbr in ECKD code with BootMapTable
- fix read_block messages to reflect BMT
- reduce ipl_scsi code with BMT struct

Signed-off-by: Collin L. Walling <wall...@linux.vnet.ibm.com>
---

[...]

@@ -449,10 +451,8 @@ static void zipl_run(ScsiBlockPtr *pte)
  static void ipl_scsi(void)
  {
  ScsiMbr *mbr = (void *)sec;
-uint8_t *ns, *ns_end;
  int program_table_entries = 0;
-const int pte_len = sizeof(ScsiBlockPtr);
-ScsiBlockPtr *prog_table_entry = NULL;
+BootMapTable *bmt = (void *)sec;
  unsigned int loadparm = get_loadparm_index();
  
  /* Grab the MBR */

@@ -467,34 +467,23 @@ static void ipl_scsi(void)
  debug_print_int("MBR Version", mbr->version_id);
  IPL_check(mbr->version_id == 1,
"Unknown MBR layout version, assuming version 1");
-debug_print_int("program table", mbr->blockptr[0].blockno);
-IPL_assert(mbr->blockptr[0].blockno, "No Program Table");
+debug_print_int("program table", mbr->bmt.blockno);
+IPL_assert(mbr->bmt.blockno, "No Program Table");
  
  /* Parse the program table */

-read_block(mbr->blockptr[0].blockno, sec,
-   "Error reading Program Table");
+read_block(mbr->bmt.blockno, sec, "Error reading Program Table");
  
  IPL_assert(magic_match(sec, ZIPL_MAGIC), "No zIPL magic in PT");
  
  debug_print_int("loadparm index", loadparm);

-ns_end = sec + virtio_get_block_size();
-for (ns = (sec + pte_len); (ns + pte_len) < ns_end; ns += pte_len) {
-prog_table_entry = (ScsiBlockPtr *)ns;
-if (!prog_table_entry->blockno) {
-break;
-}
  
+while (bmt->bte[program_table_entries].scsi.blockno) {

  program_table_entries++;

I think it might make sense to somehow limit this loop like it was done
for the original for-loop, so that in case the sector only contains
non-zero garbage you do not loop here forever.


It should be easy enough to implement a loop condition like it was before
without getting too messy.

I'll also dig into the docs (or more likely through the zipl code) and see
if there exists a limit on the number of program entires for SCSI.





-if (program_table_entries == loadparm + 1) {
-break; /* selected entry found */
-}
  }
  
  debug_print_int("program table entries", program_table_entries);
  
-IPL_assert(program_table_entries != 0, "Empty Program Table");

Don't want to keep the IPL_assert now that you've kept the
program_table_entries variable?



True.  I'll re-add the assertion.





-zipl_run(prog_table_entry); /* no return */
+zipl_run(>bte[loadparm].scsi); /* no return */
  }

  Thomas




--
- Collin L Walling




Re: [Qemu-devel] [qemu-s390x] [PATCH v5 11/12] s390-ccw: clear pending irqs

2018-02-06 Thread Collin L. Walling

On 02/06/2018 05:07 AM, Thomas Huth wrote:

On 05.02.2018 21:57, Collin L. Walling wrote:

It is possible while waiting for multiple types of external
interrupts that we might have pending irqs remaining between
irq consumption and irq disabling. Those interrupts could
propagate to the guest after IPL completes and cause unwanted
behavior.

To avoid this, we clear the write event mask to prevent further
service interrupts from ASCII events and then consume all pending
irqs for a miniscule duration. Once finished, we reset the write
event mask and resume business as usual.

Signed-off-by: Collin L. Walling <wall...@linux.vnet.ibm.com>
---
  pc-bios/s390-ccw/menu.c | 16 
  pc-bios/s390-ccw/sclp.c | 12 
  2 files changed, 28 insertions(+)

diff --git a/pc-bios/s390-ccw/menu.c b/pc-bios/s390-ccw/menu.c
index 85d285f..971f6b6 100644
--- a/pc-bios/s390-ccw/menu.c
+++ b/pc-bios/s390-ccw/menu.c
@@ -64,6 +64,20 @@ static inline bool check_clock_int(void)
  return *code == 0x1004;
  }
  
+static void clear_pending_irqs(void)

+{
+uint64_t time = 50 * TOD_CLOCK_SECOND / 0x3e8;

s/0x3e8/1000/ please.



Agreed.





+sclp_clear_write_mask();
+
+set_clock_comparator(get_clock() + time);
+enable_clock_int();
+consume_sclp_int();
+disable_clock_int();
+
+sclp_setup(); /* re-enable write mask */
+}

I'm pretty much confused by this code. First, isn't there a small chance
that there is a clock int between consume_sclp_int() and
disable_clock_int() (if consume_sclp_int() has consumed an SCLP
interrupt instead of a clock interrupt) ?



By clearing the write mask, we can no longer send nor receive ASCII events
(such as prints or keystrokes). Therefore we will not have any service
interrupts originating from keystrokes.

Theoretically, the only interrupt we should be waiting for in this case
is from the clock.



Second, if you finally enable the SCLP write mask again, doesn't that
mean that there could be interrupts pending again afterwards?



Yes.  When the write mask is re-enabled for cp_receive mask, we can still
get pending service interrupts originating from keystrokes (or other 
external,

ASCII related interruptions). Hopefully the user does not fall asleep
and smack their head on the keyboard during the IPL process. (joking)

Ideally (as it was suggested in a previous review), we should refactor
the consume_sclp_int so we can manually enable / disable service interrupts,
but I think this is a good first step, no?

We also might be able to get away with just not setting the receive mask at
all when we re-enable the write mask. That will prevent any interrupts from
keystrokes.




  Thomas




--
- Collin L Walling




Re: [Qemu-devel] [qemu-s390x] [PATCH v5 00/12]Interactive Boot Menu for DASD and SCSI Guests on s390x

2018-02-05 Thread Collin L. Walling
This was silly.  Last minute change on my end.  Consider the assertion 
removed.


On 02/05/2018 04:20 PM, no-re...@patchew.org wrote:


/var/tmp/patchew-tester-tmp-k5bn7h1w/src/pc-bios/s390-ccw/libc.c: In function 
‘itostr’:
/var/tmp/patchew-tester-tmp-k5bn7h1w/src/pc-bios/s390-ccw/libc.c:70:20: error: 
comparison of unsigned expression >= 0 is always true [-Werror=type-limits]
  IPL_assert(num >= 0, "itostr: cannot convert negative values");
 ^~



--
- Collin L Walling




[Qemu-devel] [PATCH v5 12/12] s390-ccw: interactive boot menu for scsi

2018-02-05 Thread Collin L. Walling
Interactive boot menu for scsi. This follows a similar procedure
as the interactive menu for eckd dasd. An example follows:

s390x Enumerated Boot Menu.

3 entries detected. Select from index 0 to 2.

Signed-off-by: Collin L. Walling <wall...@linux.vnet.ibm.com>
Reviewed-by: Thomas Huth <th...@redhat.com>
---
 pc-bios/s390-ccw/bootmap.c |  4 
 pc-bios/s390-ccw/main.c|  1 +
 pc-bios/s390-ccw/menu.c| 14 ++
 pc-bios/s390-ccw/menu.h|  1 +
 4 files changed, 20 insertions(+)

diff --git a/pc-bios/s390-ccw/bootmap.c b/pc-bios/s390-ccw/bootmap.c
index adbef41..13b2936 100644
--- a/pc-bios/s390-ccw/bootmap.c
+++ b/pc-bios/s390-ccw/bootmap.c
@@ -567,6 +567,10 @@ static void ipl_scsi(void)
 
 debug_print_int("program table entries", program_table_entries);
 
+if (menu_check_flags(BOOT_MENU_FLAG_CMD_OPTS)) {
+loadparm = menu_get_enum_boot_index(program_table_entries);
+}
+
 zipl_run(>bte[loadparm].scsi); /* no return */
 }
 
diff --git a/pc-bios/s390-ccw/main.c b/pc-bios/s390-ccw/main.c
index 76d58cc..3548cd4 100644
--- a/pc-bios/s390-ccw/main.c
+++ b/pc-bios/s390-ccw/main.c
@@ -92,6 +92,7 @@ static void menu_setup(void)
 
 switch (iplb.pbt) {
 case S390_IPL_TYPE_CCW:
+case S390_IPL_TYPE_QEMU_SCSI:
 menu_set_parms(qipl.boot_menu_flags, qipl.boot_menu_timeout);
 return;
 }
diff --git a/pc-bios/s390-ccw/menu.c b/pc-bios/s390-ccw/menu.c
index 971f6b6..41a59e3 100644
--- a/pc-bios/s390-ccw/menu.c
+++ b/pc-bios/s390-ccw/menu.c
@@ -226,6 +226,20 @@ int menu_get_zipl_boot_index(const void *stage2, int 
offset)
 return get_boot_index(ct - 1);
 }
 
+int menu_get_enum_boot_index(int entries)
+{
+char tmp[4];
+
+sclp_print("s390x Enumerated Boot Menu.\n\n");
+
+sclp_print(itostr(entries, tmp, sizeof(tmp)));
+sclp_print(" entries detected. Select from boot index 0 to ");
+sclp_print(itostr(entries - 1, tmp, sizeof(tmp)));
+sclp_print(".\n\n");
+
+return get_boot_index(entries);
+}
+
 void menu_set_parms(uint8_t boot_menu_flag, uint16_t boot_menu_timeout)
 {
 flags = boot_menu_flag;
diff --git a/pc-bios/s390-ccw/menu.h b/pc-bios/s390-ccw/menu.h
index e8e042f..c08e4cf 100644
--- a/pc-bios/s390-ccw/menu.h
+++ b/pc-bios/s390-ccw/menu.h
@@ -18,6 +18,7 @@
 #define BOOT_MENU_FLAG_ZIPL_OPTS 0x40
 
 int menu_get_zipl_boot_index(const void *stage2, int offset);
+int menu_get_enum_boot_index(int entries);
 void menu_set_parms(uint8_t boot_menu_flags, uint16_t boot_menu_timeout);
 bool menu_check_flags(uint8_t check_flags);
 
-- 
2.7.4




[Qemu-devel] [PATCH v5 10/12] s390-ccw: read user input for boot index via the SCLP console

2018-02-05 Thread Collin L. Walling
Implements an sclp_read function to capture input from the
console and a wrapper function that handles parsing certain
characters and adding input to a buffer. The input is checked
for any erroneous values and is handled appropriately.

A prompt will persist until input is entered or the timeout
expires (if one was set). Example:

Please choose (default will boot in 10 seconds):

Correct input will boot the respective boot index. If the
user's input is empty, 0, or if the timeout expires, then
the default zipl entry will be chosen. If the input is
within the range of available boot entries, then the
selection will be booted. Any erroneous input will cancel
the timeout and re-prompt the user.

Signed-off-by: Collin L. Walling <wall...@linux.vnet.ibm.com>
Reviewed-by: Thomas Huth <th...@redhat.com>
---
 pc-bios/s390-ccw/menu.c | 150 +++-
 pc-bios/s390-ccw/s390-ccw.h |   3 +
 pc-bios/s390-ccw/sclp.c |  19 ++
 pc-bios/s390-ccw/virtio.c   |   2 +-
 4 files changed, 170 insertions(+), 4 deletions(-)

diff --git a/pc-bios/s390-ccw/menu.c b/pc-bios/s390-ccw/menu.c
index e9e283f..85d285f 100644
--- a/pc-bios/s390-ccw/menu.c
+++ b/pc-bios/s390-ccw/menu.c
@@ -12,16 +12,160 @@
 #include "menu.h"
 #include "s390-ccw.h"
 
-static uint8_t flags;
-static uint64_t timeout;
+#define KEYCODE_NO_INP '\0'
+#define KEYCODE_ESCAPE '\033'
+#define KEYCODE_BACKSP '\177'
+#define KEYCODE_ENTER  '\r'
 
 /* Offsets from zipl fields to zipl banner start */
 #define ZIPL_TIMEOUT_OFFSET 138
 #define ZIPL_FLAG_OFFSET140
 
+#define TOD_CLOCK_SECOND  0xf424
+
+static uint8_t flags;
+static uint64_t timeout;
+
+static inline void enable_clock_int(void)
+{
+uint64_t tmp = 0;
+
+asm volatile(
+"stctg  0,0,%0\n"
+"oi 6+%0, 0x8\n"
+"lctlg  0,0,%0"
+: : "Q" (tmp) : "memory"
+);
+}
+
+static inline void disable_clock_int(void)
+{
+uint64_t tmp = 0;
+
+asm volatile(
+"stctg  0,0,%0\n"
+"ni 6+%0, 0xf7\n"
+"lctlg  0,0,%0"
+: : "Q" (tmp) : "memory"
+);
+}
+
+static inline void set_clock_comparator(uint64_t time)
+{
+asm volatile("sckc %0" : : "Q" (time));
+}
+
+static inline bool check_clock_int(void)
+{
+uint16_t *code = (uint16_t *)0x86; /* low-core external interrupt code */
+
+consume_sclp_int();
+
+return *code == 0x1004;
+}
+
+static int read_prompt(char *buf, size_t len)
+{
+char inp[2] = {};
+uint8_t idx = 0;
+uint64_t time;
+
+if (timeout) {
+time = get_clock() + timeout * TOD_CLOCK_SECOND;
+set_clock_comparator(time);
+enable_clock_int();
+timeout = 0;
+}
+
+while (!check_clock_int()) {
+
+sclp_read(inp, 1); /* Process only one character at a time */
+
+switch (inp[0]) {
+case KEYCODE_NO_INP:
+case KEYCODE_ESCAPE:
+continue;
+case KEYCODE_BACKSP:
+if (idx > 0) {
+buf[--idx] = 0;
+sclp_print("\b \b");
+}
+continue;
+case KEYCODE_ENTER:
+disable_clock_int();
+return idx;
+default:
+/* Echo input and add to buffer */
+if (idx < len) {
+buf[idx++] = inp[0];
+sclp_print(inp);
+}
+}
+}
+
+disable_clock_int();
+*buf = 0;
+
+return 0;
+}
+
+static int get_index(void)
+{
+char buf[10];
+int len;
+int i;
+
+memset(buf, 0, sizeof(buf));
+
+len = read_prompt(buf, sizeof(buf));
+
+/* If no input, boot default */
+if (len == 0) {
+return 0;
+}
+
+/* Check for erroneous input */
+for (i = 0; i < len; i++) {
+if (!isdigit(buf[i])) {
+return -1;
+}
+}
+
+return atoui(buf);
+}
+
+static void boot_menu_prompt(bool retry)
+{
+char tmp[6];
+
+if (retry) {
+sclp_print("\nError: undefined configuration"
+   "\nPlease choose:\n");
+} else if (timeout > 0) {
+sclp_print("Please choose (default will boot in ");
+sclp_print(itostr(timeout, tmp, sizeof(tmp)));
+sclp_print(" seconds):\n");
+} else {
+sclp_print("Please choose:\n");
+}
+}
+
 static int get_boot_index(int entries)
 {
-return 0; /* Implemented next patch */
+int boot_index;
+bool retry = false;
+char tmp[5];
+
+do {
+boot_menu_prompt(retry);
+boot_index = get_index();
+retry = true;
+} while (boot_index < 0 || boot_index >= entries);
+
+sclp_print("\nBooting entry #");
+sclp_print(itostr(boot_index, tmp, sizeof(tmp)));
+
+return boot_index;
 }
 

[Qemu-devel] [PATCH v5 08/12] s390-ccw: read stage2 boot loader data to find menu

2018-02-05 Thread Collin L. Walling
Read the stage2 boot loader data block-by-block. We scan the
current block for the string "zIPL" to detect the start of the
boot menu banner. We then load the adjacent blocks (previous
block and next block) to account for the possibility of menu
data spanning multiple blocks.

Signed-off-by: Collin L. Walling <wall...@linux.vnet.ibm.com>
Reviewed-by: Thomas Huth <th...@redhat.com>
---
 pc-bios/s390-ccw/bootmap.c | 94 +++---
 pc-bios/s390-ccw/bootmap.h | 23 +++-
 pc-bios/s390-ccw/menu.c|  5 +++
 pc-bios/s390-ccw/menu.h|  1 +
 4 files changed, 116 insertions(+), 7 deletions(-)

diff --git a/pc-bios/s390-ccw/bootmap.c b/pc-bios/s390-ccw/bootmap.c
index e3cbb09b..adbef41 100644
--- a/pc-bios/s390-ccw/bootmap.c
+++ b/pc-bios/s390-ccw/bootmap.c
@@ -13,6 +13,7 @@
 #include "bootmap.h"
 #include "virtio.h"
 #include "bswap.h"
+#include "menu.h"
 
 #ifdef DEBUG
 /* #define DEBUG_FALLBACK */
@@ -83,6 +84,10 @@ static void jump_to_IPL_code(uint64_t address)
 
 static unsigned char _bprs[8*1024]; /* guessed "max" ECKD sector size */
 static const int max_bprs_entries = sizeof(_bprs) / sizeof(ExtEckdBlockPtr);
+static uint8_t _s2[MAX_SECTOR_SIZE * 3] 
__attribute__((__aligned__(PAGE_SIZE)));
+static void *s2_prev_blk = _s2;
+static void *s2_cur_blk = _s2 + MAX_SECTOR_SIZE;
+static void *s2_next_blk = _s2 + MAX_SECTOR_SIZE * 2;
 
 static inline void verify_boot_info(BootInfo *bip)
 {
@@ -182,7 +187,76 @@ static block_number_t load_eckd_segments(block_number_t 
blk, uint64_t *address)
 return block_nr;
 }
 
-static void run_eckd_boot_script(block_number_t bmt_block_nr)
+static bool find_zipl_boot_menu_banner(int *offset)
+{
+int i;
+
+/* Menu banner starts with "zIPL" */
+for (i = 0; i < virtio_get_block_size() - 4; i++) {
+if (magic_match(s2_cur_blk + i, ZIPL_MAGIC_EBCDIC)) {
+*offset = i;
+return true;
+}
+}
+
+return false;
+}
+
+static int eckd_get_boot_menu_index(block_number_t s1b_block_nr)
+{
+block_number_t cur_block_nr;
+block_number_t prev_block_nr = 0;
+block_number_t next_block_nr = 0;
+EckdStage1b *s1b = (void *)sec;
+int offset;
+int i;
+
+/* Get Stage1b data */
+memset(sec, FREE_SPACE_FILLER, sizeof(sec));
+read_block(s1b_block_nr, s1b, "Cannot read stage1b boot loader");
+
+memset(_s2, FREE_SPACE_FILLER, sizeof(_s2));
+
+/* Get Stage2 data */
+for (i = 0; i < STAGE2_BLK_CNT_MAX; i++) {
+cur_block_nr = eckd_block_num(>seek[i].chs);
+
+if (!cur_block_nr) {
+break;
+}
+
+read_block(cur_block_nr, s2_cur_blk, "Cannot read stage2 boot loader");
+
+if (find_zipl_boot_menu_banner()) {
+/* Load the adjacent blocks to account for the
+ * possibility of menu data spanning multiple blocks.
+ */
+if (prev_block_nr) {
+read_block(prev_block_nr, s2_prev_blk,
+   "Cannot read stage2 boot loader");
+}
+
+if (i + 1 < STAGE2_BLK_CNT_MAX) {
+next_block_nr = eckd_block_num(>seek[i + 1].chs);
+}
+
+if (next_block_nr) {
+read_block(next_block_nr, s2_next_blk,
+   "Cannot read stage2 boot loader");
+}
+
+return menu_get_zipl_boot_index(s2_cur_blk, offset);
+}
+
+prev_block_nr = cur_block_nr;
+}
+
+sclp_print("No zipl boot menu data found. Booting default entry.");
+return 0;
+}
+
+static void run_eckd_boot_script(block_number_t bmt_block_nr,
+ block_number_t s1b_block_nr)
 {
 int i;
 unsigned int loadparm = get_loadparm_index();
@@ -191,6 +265,10 @@ static void run_eckd_boot_script(block_number_t 
bmt_block_nr)
 BootMapTable *bmt = (void *)sec;
 BootMapScript *bms = (void *)sec;
 
+if (menu_check_flags(BOOT_MENU_FLAG_CMD_OPTS | BOOT_MENU_FLAG_ZIPL_OPTS)) {
+loadparm = eckd_get_boot_menu_index(s1b_block_nr);
+}
+
 debug_print_int("loadparm", loadparm);
 IPL_assert(loadparm < 31, "loadparm value greater than"
" maximum number of boot entries allowed");
@@ -223,7 +301,7 @@ static void ipl_eckd_cdl(void)
 XEckdMbr *mbr;
 EckdCdlIpl2 *ipl2 = (void *)sec;
 IplVolumeLabel *vlbl = (void *)sec;
-block_number_t bmt_block_nr;
+block_number_t bmt_block_nr, s1b_block_nr;
 
 /* we have just read the block #0 and recognized it as "IPL1" */
 sclp_print("CDL\n");
@@ -241,6 +319,9 @@ static void ipl_eckd_cdl(void)
 /* save pointer to Boot Map Table */
 bmt_block_nr = eckd_block_num(>blockptr.xeckd.bptr.chs);
 
+/* save pointer to Stage1b Data */
+s1b_block_nr = 

[Qemu-devel] [PATCH v5 11/12] s390-ccw: clear pending irqs

2018-02-05 Thread Collin L. Walling
It is possible while waiting for multiple types of external
interrupts that we might have pending irqs remaining between
irq consumption and irq disabling. Those interrupts could
propagate to the guest after IPL completes and cause unwanted
behavior.

To avoid this, we clear the write event mask to prevent further
service interrupts from ASCII events and then consume all pending
irqs for a miniscule duration. Once finished, we reset the write
event mask and resume business as usual.

Signed-off-by: Collin L. Walling <wall...@linux.vnet.ibm.com>
---
 pc-bios/s390-ccw/menu.c | 16 
 pc-bios/s390-ccw/sclp.c | 12 
 2 files changed, 28 insertions(+)

diff --git a/pc-bios/s390-ccw/menu.c b/pc-bios/s390-ccw/menu.c
index 85d285f..971f6b6 100644
--- a/pc-bios/s390-ccw/menu.c
+++ b/pc-bios/s390-ccw/menu.c
@@ -64,6 +64,20 @@ static inline bool check_clock_int(void)
 return *code == 0x1004;
 }
 
+static void clear_pending_irqs(void)
+{
+uint64_t time = 50 * TOD_CLOCK_SECOND / 0x3e8;
+
+sclp_clear_write_mask();
+
+set_clock_comparator(get_clock() + time);
+enable_clock_int();
+consume_sclp_int();
+disable_clock_int();
+
+sclp_setup(); /* re-enable write mask */
+}
+
 static int read_prompt(char *buf, size_t len)
 {
 char inp[2] = {};
@@ -165,6 +179,8 @@ static int get_boot_index(int entries)
 sclp_print("\nBooting entry #");
 sclp_print(itostr(boot_index, tmp, sizeof(tmp)));
 
+clear_pending_irqs();
+
 return boot_index;
 }
 
diff --git a/pc-bios/s390-ccw/sclp.c b/pc-bios/s390-ccw/sclp.c
index 5902d5b..025eb2d 100644
--- a/pc-bios/s390-ccw/sclp.c
+++ b/pc-bios/s390-ccw/sclp.c
@@ -46,6 +46,18 @@ static int sclp_service_call(unsigned int command, void 
*sccb)
 return 0;
 }
 
+void sclp_clear_write_mask(void)
+{
+WriteEventMask *sccb = (void *)_sccb;
+
+sccb->h.length = sizeof(WriteEventMask);
+sccb->mask_length = sizeof(unsigned int);
+sccb->cp_receive_mask = 0;
+sccb->cp_send_mask = 0;
+
+sclp_service_call(SCLP_CMD_WRITE_EVENT_MASK, sccb);
+}
+
 static void sclp_set_write_mask(void)
 {
 WriteEventMask *sccb = (void *)_sccb;
-- 
2.7.4




[Qemu-devel] [PATCH v5 01/12] s390-ccw: refactor boot map table code

2018-02-05 Thread Collin L. Walling
- replace ScsiMbr in ECKD code with BootMapTable
- fix read_block messages to reflect BMT
- reduce ipl_scsi code with BMT struct

Signed-off-by: Collin L. Walling <wall...@linux.vnet.ibm.com>
---
 pc-bios/s390-ccw/bootmap.c | 53 ++
 pc-bios/s390-ccw/bootmap.h |  9 +++-
 2 files changed, 29 insertions(+), 33 deletions(-)

diff --git a/pc-bios/s390-ccw/bootmap.c b/pc-bios/s390-ccw/bootmap.c
index 67a6123..8ee9056 100644
--- a/pc-bios/s390-ccw/bootmap.c
+++ b/pc-bios/s390-ccw/bootmap.c
@@ -182,13 +182,13 @@ static block_number_t load_eckd_segments(block_number_t 
blk, uint64_t *address)
 return block_nr;
 }
 
-static void run_eckd_boot_script(block_number_t mbr_block_nr)
+static void run_eckd_boot_script(block_number_t bmt_block_nr)
 {
 int i;
 unsigned int loadparm = get_loadparm_index();
 block_number_t block_nr;
 uint64_t address;
-ScsiMbr *bte = (void *)sec; /* Eckd bootmap table entry */
+BootMapTable *bmt = (void *)sec;
 BootMapScript *bms = (void *)sec;
 
 debug_print_int("loadparm", loadparm);
@@ -196,10 +196,10 @@ static void run_eckd_boot_script(block_number_t 
mbr_block_nr)
" maximum number of boot entries allowed");
 
 memset(sec, FREE_SPACE_FILLER, sizeof(sec));
-read_block(mbr_block_nr, sec, "Cannot read MBR");
+read_block(bmt_block_nr, sec, "Cannot read Boot Map Table");
 
-block_nr = eckd_block_num((void *)&(bte->blockptr[loadparm]));
-IPL_assert(block_nr != -1, "No Boot Map");
+block_nr = eckd_block_num((void *)>bte[loadparm]);
+IPL_assert(block_nr != -1, "Cannot find Boot Map Table Entry");
 
 memset(sec, FREE_SPACE_FILLER, sizeof(sec));
 read_block(block_nr, sec, "Cannot read Boot Map Script");
@@ -223,7 +223,7 @@ static void ipl_eckd_cdl(void)
 XEckdMbr *mbr;
 Ipl2 *ipl2 = (void *)sec;
 IplVolumeLabel *vlbl = (void *)sec;
-block_number_t block_nr;
+block_number_t bmt_block_nr;
 
 /* we have just read the block #0 and recognized it as "IPL1" */
 sclp_print("CDL\n");
@@ -238,8 +238,8 @@ static void ipl_eckd_cdl(void)
 IPL_assert(mbr->dev_type == DEV_TYPE_ECKD,
"Non-ECKD device type in zIPL section of IPL2 record.");
 
-/* save pointer to Boot Script */
-block_nr = eckd_block_num((void *)&(mbr->blockptr));
+/* save pointer to Boot Map Table */
+bmt_block_nr = eckd_block_num((void *)>blockptr);
 
 memset(sec, FREE_SPACE_FILLER, sizeof(sec));
 read_block(2, vlbl, "Cannot read Volume Label at block 2");
@@ -249,7 +249,7 @@ static void ipl_eckd_cdl(void)
"Invalid magic of volser block");
 print_volser(vlbl->f.volser);
 
-run_eckd_boot_script(block_nr);
+run_eckd_boot_script(bmt_block_nr);
 /* no return */
 }
 
@@ -280,7 +280,7 @@ static void print_eckd_ldl_msg(ECKD_IPL_mode_t mode)
 
 static void ipl_eckd_ldl(ECKD_IPL_mode_t mode)
 {
-block_number_t block_nr;
+block_number_t bmt_block_nr;
 BootInfo *bip = (void *)(sec + 0x70); /* BootInfo is MBR for LDL */
 
 if (mode != ECKD_LDL_UNLABELED) {
@@ -299,8 +299,10 @@ static void ipl_eckd_ldl(ECKD_IPL_mode_t mode)
 }
 verify_boot_info(bip);
 
-block_nr = eckd_block_num((void *)&(bip->bp.ipl.bm_ptr.eckd.bptr));
-run_eckd_boot_script(block_nr);
+/* save pointer to Boot Map Table */
+bmt_block_nr = eckd_block_num((void *)>bp.ipl.bm_ptr.eckd.bptr);
+
+run_eckd_boot_script(bmt_block_nr);
 /* no return */
 }
 
@@ -325,7 +327,7 @@ static void print_eckd_msg(void)
 
 static void ipl_eckd(void)
 {
-ScsiMbr *mbr = (void *)sec;
+XEckdMbr *mbr = (void *)sec;
 LDL_VTOC *vlbl = (void *)sec;
 
 print_eckd_msg();
@@ -449,10 +451,8 @@ static void zipl_run(ScsiBlockPtr *pte)
 static void ipl_scsi(void)
 {
 ScsiMbr *mbr = (void *)sec;
-uint8_t *ns, *ns_end;
 int program_table_entries = 0;
-const int pte_len = sizeof(ScsiBlockPtr);
-ScsiBlockPtr *prog_table_entry = NULL;
+BootMapTable *bmt = (void *)sec;
 unsigned int loadparm = get_loadparm_index();
 
 /* Grab the MBR */
@@ -467,34 +467,23 @@ static void ipl_scsi(void)
 debug_print_int("MBR Version", mbr->version_id);
 IPL_check(mbr->version_id == 1,
   "Unknown MBR layout version, assuming version 1");
-debug_print_int("program table", mbr->blockptr[0].blockno);
-IPL_assert(mbr->blockptr[0].blockno, "No Program Table");
+debug_print_int("program table", mbr->bmt.blockno);
+IPL_assert(mbr->bmt.blockno, "No Program Table");
 
 /* Parse the program table */
-read_block(mbr->blockptr[0].blockno, sec,
-   "Error reading Program Table");
+read_block(mbr->bmt.blockno, sec, &quo

[Qemu-devel] [PATCH v5 04/12] s390-ccw: update libc

2018-02-05 Thread Collin L. Walling
Moved:
  memcmp from bootmap.h to libc.h (renamed from _memcmp)
  strlen from sclp.c to libc.h (renamed from _strlen)

Added C standard functions:
  isdigit

Added non C-standard function:
  itostr
  atoui

Signed-off-by: Collin L. Walling <wall...@linux.vnet.ibm.com>
Acked-by: Christian Borntraeger <borntrae...@de.ibm.com>
Reviewed-by: Janosch Frank <fran...@linux.vnet.ibm.com>
---
 pc-bios/s390-ccw/Makefile  |  2 +-
 pc-bios/s390-ccw/bootmap.c |  4 +-
 pc-bios/s390-ccw/bootmap.h | 16 +---
 pc-bios/s390-ccw/libc.c| 91 ++
 pc-bios/s390-ccw/libc.h| 35 +-
 pc-bios/s390-ccw/main.c| 17 +
 pc-bios/s390-ccw/sclp.c| 10 +
 7 files changed, 131 insertions(+), 44 deletions(-)
 create mode 100644 pc-bios/s390-ccw/libc.c

diff --git a/pc-bios/s390-ccw/Makefile b/pc-bios/s390-ccw/Makefile
index 6d0c2ee..9f7904f 100644
--- a/pc-bios/s390-ccw/Makefile
+++ b/pc-bios/s390-ccw/Makefile
@@ -9,7 +9,7 @@ $(call set-vpath, $(SRC_PATH)/pc-bios/s390-ccw)
 
 .PHONY : all clean build-all
 
-OBJECTS = start.o main.o bootmap.o sclp.o virtio.o virtio-scsi.o 
virtio-blkdev.o
+OBJECTS = start.o main.o bootmap.o sclp.o virtio.o virtio-scsi.o 
virtio-blkdev.o libc.o
 QEMU_CFLAGS := $(filter -W%, $(QEMU_CFLAGS))
 QEMU_CFLAGS += -ffreestanding -fno-delete-null-pointer-checks -msoft-float
 QEMU_CFLAGS += -march=z900 -fPIE -fno-strict-aliasing
diff --git a/pc-bios/s390-ccw/bootmap.c b/pc-bios/s390-ccw/bootmap.c
index c97f136..e3cbb09b 100644
--- a/pc-bios/s390-ccw/bootmap.c
+++ b/pc-bios/s390-ccw/bootmap.c
@@ -501,7 +501,7 @@ static bool is_iso_bc_entry_compatible(IsoBcSection *s)
 "Failed to read image sector 0");
 
 /* Checking bytes 8 - 32 for S390 Linux magic */
-return !_memcmp(magic_sec + 8, linux_s390_magic, 24);
+return !memcmp(magic_sec + 8, linux_s390_magic, 24);
 }
 
 /* Location of the current sector of the directory */
@@ -630,7 +630,7 @@ static uint32_t find_iso_bc(void)
 if (vd->type == VOL_DESC_TYPE_BOOT) {
 IsoVdElTorito *et = >vd.boot;
 
-if (!_memcmp(>el_torito[0], el_torito_magic, 32)) {
+if (!memcmp(>el_torito[0], el_torito_magic, 32)) {
 return bswap32(et->bc_offset);
 }
 }
diff --git a/pc-bios/s390-ccw/bootmap.h b/pc-bios/s390-ccw/bootmap.h
index cfe9ddd..b0a135c 100644
--- a/pc-bios/s390-ccw/bootmap.h
+++ b/pc-bios/s390-ccw/bootmap.h
@@ -326,20 +326,6 @@ static inline bool magic_match(const void *data, const 
void *magic)
 return *((uint32_t *)data) == *((uint32_t *)magic);
 }
 
-static inline int _memcmp(const void *s1, const void *s2, size_t n)
-{
-int i;
-const uint8_t *p1 = s1, *p2 = s2;
-
-for (i = 0; i < n; i++) {
-if (p1[i] != p2[i]) {
-return p1[i] > p2[i] ? 1 : -1;
-}
-}
-
-return 0;
-}
-
 static inline uint32_t iso_733_to_u32(uint64_t x)
 {
 return (uint32_t)x;
@@ -432,7 +418,7 @@ const uint8_t vol_desc_magic[] = "CD001";
 
 static inline bool is_iso_vd_valid(IsoVolDesc *vd)
 {
-return !_memcmp(>ident[0], vol_desc_magic, 5) &&
+return !memcmp(>ident[0], vol_desc_magic, 5) &&
vd->version == 0x1 &&
vd->type <= VOL_DESC_TYPE_PARTITION;
 }
diff --git a/pc-bios/s390-ccw/libc.c b/pc-bios/s390-ccw/libc.c
new file mode 100644
index 000..e6f434b
--- /dev/null
+++ b/pc-bios/s390-ccw/libc.c
@@ -0,0 +1,91 @@
+/*
+ * libc-style definitions and functions
+ *
+ * Copyright 2018 IBM Corp.
+ * Author(s): Collin L. Walling <wall...@linux.vnet.ibm.com>
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ */
+
+#include "libc.h"
+#include "s390-ccw.h"
+
+/**
+ * atoui:
+ * @str: the string to be converted.
+ *
+ * Given a string @str, convert it to an integer. Leading spaces are
+ * ignored. Any other non-numerical value will terminate the conversion
+ * and return 0. This function only handles numbers between 0 and
+ * UINT64_MAX inclusive.
+ *
+ * Returns: an integer converted from the string @str, or the number 0
+ * if an error occurred.
+ */
+uint64_t atoui(const char *str)
+{
+int val = 0;
+
+if (!str || !str[0]) {
+return 0;
+}
+
+while (*str == ' ') {
+str++;
+}
+
+while (*str) {
+if (!isdigit(*str)) {
+break;
+}
+val = val * 10 + *str - '0';
+str++;
+}
+
+return val;
+}
+
+/**
+ * itostr:
+ * @num: an integer (base 10) to be converted.
+ * @str: a pointer to a string to store the conversion.
+ * @len: the length of the passed string.
+ *
+ * Given an integer @num, convert it to a string. The string @str must be

[Qemu-devel] [PATCH v5 07/12] s390-ccw: set up interactive boot menu parameters

2018-02-05 Thread Collin L. Walling
Reads boot menu flag and timeout values from the iplb and
sets the respective fields for the menu.

Signed-off-by: Collin L. Walling <wall...@linux.vnet.ibm.com>
Reviewed-by: Thomas Huth <th...@redhat.com>
---
 pc-bios/s390-ccw/Makefile |  2 +-
 pc-bios/s390-ccw/main.c   | 24 
 pc-bios/s390-ccw/menu.c   | 26 ++
 pc-bios/s390-ccw/menu.h   | 23 +++
 4 files changed, 74 insertions(+), 1 deletion(-)
 create mode 100644 pc-bios/s390-ccw/menu.c
 create mode 100644 pc-bios/s390-ccw/menu.h

diff --git a/pc-bios/s390-ccw/Makefile b/pc-bios/s390-ccw/Makefile
index 9f7904f..1712c2d 100644
--- a/pc-bios/s390-ccw/Makefile
+++ b/pc-bios/s390-ccw/Makefile
@@ -9,7 +9,7 @@ $(call set-vpath, $(SRC_PATH)/pc-bios/s390-ccw)
 
 .PHONY : all clean build-all
 
-OBJECTS = start.o main.o bootmap.o sclp.o virtio.o virtio-scsi.o 
virtio-blkdev.o libc.o
+OBJECTS = start.o main.o bootmap.o sclp.o virtio.o virtio-scsi.o 
virtio-blkdev.o libc.o menu.o
 QEMU_CFLAGS := $(filter -W%, $(QEMU_CFLAGS))
 QEMU_CFLAGS += -ffreestanding -fno-delete-null-pointer-checks -msoft-float
 QEMU_CFLAGS += -march=z900 -fPIE -fno-strict-aliasing
diff --git a/pc-bios/s390-ccw/main.c b/pc-bios/s390-ccw/main.c
index 825a1a3..76d58cc 100644
--- a/pc-bios/s390-ccw/main.c
+++ b/pc-bios/s390-ccw/main.c
@@ -11,6 +11,7 @@
 #include "libc.h"
 #include "s390-ccw.h"
 #include "virtio.h"
+#include "menu.h"
 
 char stack[PAGE_SIZE * 8] __attribute__((__aligned__(PAGE_SIZE)));
 static SubChannelId blk_schid = { .one = 1 };
@@ -18,6 +19,9 @@ IplParameterBlock iplb 
__attribute__((__aligned__(PAGE_SIZE)));
 static char loadparm[8] = { 0, 0, 0, 0, 0, 0, 0, 0 };
 QemuIplParameters qipl;
 
+#define LOADPARM_PROMPT "PROMPT  "
+#define LOADPARM_EMPTY  ""
+
 /*
  * Priniciples of Operations (SA22-7832-09) chapter 17 requires that
  * a subsystem-identification is at 184-187 and bytes 188-191 are zero
@@ -74,6 +78,25 @@ static bool find_dev(Schib *schib, int dev_no)
 return false;
 }
 
+static void menu_setup(void)
+{
+if (memcmp(loadparm, LOADPARM_PROMPT, 8) == 0) {
+menu_set_parms(BOOT_MENU_FLAG_CMD_OPTS, 0);
+return;
+}
+
+/* If loadparm was set to any other value, then do not enable menu */
+if (memcmp(loadparm, LOADPARM_EMPTY, 8) != 0) {
+return;
+}
+
+switch (iplb.pbt) {
+case S390_IPL_TYPE_CCW:
+menu_set_parms(qipl.boot_menu_flags, qipl.boot_menu_timeout);
+return;
+}
+}
+
 static void virtio_setup(void)
 {
 Schib schib;
@@ -117,6 +140,7 @@ static void virtio_setup(void)
 default:
 panic("List-directed IPL not supported yet!\n");
 }
+menu_setup();
 } else {
 for (ssid = 0; ssid < 0x3; ssid++) {
 blk_schid.ssid = ssid;
diff --git a/pc-bios/s390-ccw/menu.c b/pc-bios/s390-ccw/menu.c
new file mode 100644
index 000..e87aec6
--- /dev/null
+++ b/pc-bios/s390-ccw/menu.c
@@ -0,0 +1,26 @@
+/*
+ * QEMU S390 Interactive Boot Menu
+ *
+ * Copyright 2018 IBM Corp.
+ * Author: Collin L. Walling <wall...@linux.vnet.ibm.com>
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2 or (at
+ * your option) any later version. See the COPYING file in the top-level
+ * directory.
+ */
+
+#include "menu.h"
+
+static uint8_t flags;
+static uint64_t timeout;
+
+void menu_set_parms(uint8_t boot_menu_flag, uint16_t boot_menu_timeout)
+{
+flags = boot_menu_flag;
+timeout = boot_menu_timeout;
+}
+
+int menu_check_flags(uint8_t check_flags)
+{
+return flags & check_flags;
+}
diff --git a/pc-bios/s390-ccw/menu.h b/pc-bios/s390-ccw/menu.h
new file mode 100644
index 000..6ff9a0e
--- /dev/null
+++ b/pc-bios/s390-ccw/menu.h
@@ -0,0 +1,23 @@
+/*
+ * QEMU S390 Interactive Boot Menu
+ *
+ * Copyright 2018 IBM Corp.
+ * Author: Collin L. Walling <wall...@linux.vnet.ibm.com>
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2 or (at
+ * your option) any later version. See the COPYING file in the top-level
+ * directory.
+ */
+
+#ifndef MENU_H
+#define MENU_H
+
+#include "libc.h"
+
+#define BOOT_MENU_FLAG_CMD_OPTS  0x80
+#define BOOT_MENU_FLAG_ZIPL_OPTS 0x40
+
+void menu_set_parms(uint8_t boot_menu_flags, uint16_t boot_menu_timeout);
+bool menu_check_flags(uint8_t check_flags);
+
+#endif /* MENU_H */
-- 
2.7.4




[Qemu-devel] [PATCH v5 09/12] s390-ccw: print zipl boot menu

2018-02-05 Thread Collin L. Walling
When the boot menu options are present and the guest's
disk has been configured by the zipl tool, then the user
will be presented with an interactive boot menu with
labeled entries. An example of what the menu might look
like:

zIPL v1.37.1-build-20170714 interactive boot menu.

  0. default (linux-4.13.0)

  1. linux-4.13.0
  2. performance
  3. kvm

Signed-off-by: Collin L. Walling <wall...@linux.vnet.ibm.com>
Reviewed-by: Thomas Huth <th...@redhat.com>
---
 pc-bios/s390-ccw/menu.c | 49 -
 1 file changed, 48 insertions(+), 1 deletion(-)

diff --git a/pc-bios/s390-ccw/menu.c b/pc-bios/s390-ccw/menu.c
index 4ba2684..e9e283f 100644
--- a/pc-bios/s390-ccw/menu.c
+++ b/pc-bios/s390-ccw/menu.c
@@ -10,13 +10,60 @@
  */
 
 #include "menu.h"
+#include "s390-ccw.h"
 
 static uint8_t flags;
 static uint64_t timeout;
 
+/* Offsets from zipl fields to zipl banner start */
+#define ZIPL_TIMEOUT_OFFSET 138
+#define ZIPL_FLAG_OFFSET140
+
+static int get_boot_index(int entries)
+{
+return 0; /* Implemented next patch */
+}
+
+static void zipl_println(const char *data, size_t len)
+{
+char buf[len + 2];
+
+ebcdic_to_ascii(data, buf, len);
+buf[len] = '\n';
+buf[len + 1] = '\0';
+
+sclp_print(buf);
+}
+
 int menu_get_zipl_boot_index(const void *stage2, int offset)
 {
-return 0; /* implemented next patch */
+const char *data = stage2 + offset;
+uint16_t zipl_flag = *(uint16_t *)(data - ZIPL_FLAG_OFFSET);
+uint16_t zipl_timeout = *(uint16_t *)(data - ZIPL_TIMEOUT_OFFSET);
+size_t len;
+int ct;
+
+if (flags & BOOT_MENU_FLAG_ZIPL_OPTS) {
+if (!zipl_flag) {
+return 0; /* Boot default */
+}
+timeout = zipl_timeout;
+}
+
+/* Print and count all menu items, including the banner */
+for (ct = 0; *data; ct++) {
+len = strlen(data);
+zipl_println(data, len);
+data += len + 1;
+
+if (ct < 2) {
+sclp_print("\n");
+}
+}
+
+sclp_print("\n");
+
+return get_boot_index(ct - 1);
 }
 
 void menu_set_parms(uint8_t boot_menu_flag, uint16_t boot_menu_timeout)
-- 
2.7.4




[Qemu-devel] [PATCH v5 02/12] s390-ccw: refactor eckd_block_num to use CHS

2018-02-05 Thread Collin L. Walling
Add new cylinder/head/sector struct. Use it to calculate
eckd block numbers instead of a BootMapPointer (which used
eckd chs anyway).

Signed-off-by: Collin L. Walling <wall...@linux.vnet.ibm.com>
---
 pc-bios/s390-ccw/bootmap.c | 28 ++--
 pc-bios/s390-ccw/bootmap.h |  8 ++--
 2 files changed, 20 insertions(+), 16 deletions(-)

diff --git a/pc-bios/s390-ccw/bootmap.c b/pc-bios/s390-ccw/bootmap.c
index 8ee9056..9b9696e 100644
--- a/pc-bios/s390-ccw/bootmap.c
+++ b/pc-bios/s390-ccw/bootmap.c
@@ -95,32 +95,32 @@ static inline void verify_boot_info(BootInfo *bip)
"Bad block size in zIPL section of the 1st record.");
 }
 
-static block_number_t eckd_block_num(BootMapPointer *p)
+static block_number_t eckd_block_num(EckdCHS *chs)
 {
 const uint64_t sectors = virtio_get_sectors();
 const uint64_t heads = virtio_get_heads();
-const uint64_t cylinder = p->eckd.cylinder
-+ ((p->eckd.head & 0xfff0) << 12);
-const uint64_t head = p->eckd.head & 0x000f;
+const uint64_t cylinder = chs->cylinder
++ ((chs->head & 0xfff0) << 12);
+const uint64_t head = chs->head & 0x000f;
 const block_number_t block = sectors * heads * cylinder
+ sectors * head
-   + p->eckd.sector
+   + chs->sector
- 1; /* block nr starts with zero */
 return block;
 }
 
 static bool eckd_valid_address(BootMapPointer *p)
 {
-const uint64_t head = p->eckd.head & 0x000f;
+const uint64_t head = p->eckd.chs.head & 0x000f;
 
 if (head >= virtio_get_heads()
-||  p->eckd.sector > virtio_get_sectors()
-||  p->eckd.sector <= 0) {
+||  p->eckd.chs.sector > virtio_get_sectors()
+||  p->eckd.chs.sector <= 0) {
 return false;
 }
 
 if (!virtio_guessed_disk_nature() &&
-eckd_block_num(p) >= virtio_get_blocks()) {
+eckd_block_num(>eckd.chs) >= virtio_get_blocks()) {
 return false;
 }
 
@@ -140,7 +140,7 @@ static block_number_t load_eckd_segments(block_number_t 
blk, uint64_t *address)
 do {
 more_data = false;
 for (j = 0;; j++) {
-block_nr = eckd_block_num((void *)&(bprs[j].xeckd));
+block_nr = eckd_block_num([j].xeckd.bptr.chs);
 if (is_null_block_number(block_nr)) { /* end of chunk */
 break;
 }
@@ -198,7 +198,7 @@ static void run_eckd_boot_script(block_number_t 
bmt_block_nr)
 memset(sec, FREE_SPACE_FILLER, sizeof(sec));
 read_block(bmt_block_nr, sec, "Cannot read Boot Map Table");
 
-block_nr = eckd_block_num((void *)>bte[loadparm]);
+block_nr = eckd_block_num(>bte[loadparm].xeckd.bptr.chs);
 IPL_assert(block_nr != -1, "Cannot find Boot Map Table Entry");
 
 memset(sec, FREE_SPACE_FILLER, sizeof(sec));
@@ -206,7 +206,7 @@ static void run_eckd_boot_script(block_number_t 
bmt_block_nr)
 
 for (i = 0; bms->entry[i].type == BOOT_SCRIPT_LOAD; i++) {
 address = bms->entry[i].address.load_address;
-block_nr = eckd_block_num(&(bms->entry[i].blkptr));
+block_nr = eckd_block_num(>entry[i].blkptr.xeckd.bptr.chs);
 
 do {
 block_nr = load_eckd_segments(block_nr, );
@@ -239,7 +239,7 @@ static void ipl_eckd_cdl(void)
"Non-ECKD device type in zIPL section of IPL2 record.");
 
 /* save pointer to Boot Map Table */
-bmt_block_nr = eckd_block_num((void *)>blockptr);
+bmt_block_nr = eckd_block_num(>blockptr.xeckd.bptr.chs);
 
 memset(sec, FREE_SPACE_FILLER, sizeof(sec));
 read_block(2, vlbl, "Cannot read Volume Label at block 2");
@@ -300,7 +300,7 @@ static void ipl_eckd_ldl(ECKD_IPL_mode_t mode)
 verify_boot_info(bip);
 
 /* save pointer to Boot Map Table */
-bmt_block_nr = eckd_block_num((void *)>bp.ipl.bm_ptr.eckd.bptr);
+bmt_block_nr = eckd_block_num(>bp.ipl.bm_ptr.eckd.bptr.chs);
 
 run_eckd_boot_script(bmt_block_nr);
 /* no return */
diff --git a/pc-bios/s390-ccw/bootmap.h b/pc-bios/s390-ccw/bootmap.h
index 77d56db..260ac2a 100644
--- a/pc-bios/s390-ccw/bootmap.h
+++ b/pc-bios/s390-ccw/bootmap.h
@@ -32,10 +32,14 @@ typedef struct FbaBlockPtr {
 uint16_t blockct;
 } __attribute__ ((packed)) FbaBlockPtr;
 
-typedef struct EckdBlockPtr {
-uint16_t cylinder; /* cylinder/head/sector is an address of the block */
+typedef struct EckdCHS {
+uint16_t cylinder;
 uint16_t head;
 uint8_t sector;
+} __attribute__ ((packed)) EckdCHS;
+
+typedef struct EckdBlockPtr {
+EckdCHS chs; /* cylinder/head/sector is an address of the block */
 uint16_t size;
 uint8_t count; /* (size_in_blocks-1);
 * it's 0 for TablePtr, ScriptPtr, and SectionPtr */
-- 
2.7.4




[Qemu-devel] [PATCH v5 06/12] s390-ccw: parse and set boot menu options

2018-02-05 Thread Collin L. Walling
Set boot menu options for an s390 guest and store them in
the iplb. These options are set via the QEMU command line
option:

-boot menu=on|off[,splash-time=X]

or via the libvirt domain xml:


  


Where X represents some positive integer representing
milliseconds.

Any value set for loadparm will override all boot menu options.
If loadparm=PROMPT, then the menu will be enabled without a
timeout.

The absence of any boot options on the command line will flag
to later use the zipl boot loader values.

Signed-off-by: Collin L. Walling <wall...@linux.vnet.ibm.com>
Reviewed-by: Janosch Frank <fran...@linux.vnet.ibm.com>
Reviewed-by: Thomas Huth <th...@redhat.com>
---
 hw/s390x/ipl.c  | 52 +
 hw/s390x/ipl.h  |  7 ++-
 pc-bios/s390-ccw/iplb.h |  4 +++-
 3 files changed, 61 insertions(+), 2 deletions(-)

diff --git a/hw/s390x/ipl.c b/hw/s390x/ipl.c
index 3e3c3b8..227dccb 100644
--- a/hw/s390x/ipl.c
+++ b/hw/s390x/ipl.c
@@ -23,6 +23,8 @@
 #include "hw/s390x/ebcdic.h"
 #include "ipl.h"
 #include "qemu/error-report.h"
+#include "qemu/config-file.h"
+#include "qemu/cutils.h"
 
 #define KERN_IMAGE_START0x01UL
 #define KERN_PARM_AREA  0x010480UL
@@ -219,6 +221,53 @@ static Property s390_ipl_properties[] = {
 DEFINE_PROP_END_OF_LIST(),
 };
 
+static void s390_ipl_set_boot_menu(IplParameterBlock *iplb)
+{
+QemuOptsList *plist = qemu_find_opts("boot-opts");
+QemuOpts *opts = QTAILQ_FIRST(>head);
+uint8_t *flags;
+uint16_t *timeout;
+const char *tmp;
+unsigned long result = 0;
+
+switch (iplb->pbt) {
+case S390_IPL_TYPE_CCW:
+case S390_IPL_TYPE_QEMU_SCSI:
+flags = >qipl.boot_menu_flags;
+timeout = >qipl.boot_menu_timeout;
+break;
+default:
+error_report("boot menu is not supported for this device type.");
+return;
+}
+
+/* In the absence of -boot menu, use zipl parameters */
+if (!qemu_opt_get(opts, "menu")) {
+*flags = BOOT_MENU_FLAG_ZIPL_OPTS;
+} else if (boot_menu) {
+*flags = BOOT_MENU_FLAG_CMD_OPTS;
+
+tmp = qemu_opt_get(opts, "splash-time");
+
+if (tmp && qemu_strtoul(tmp, NULL, 10, )) {
+error_report("splash-time value is invalid, forcing it to 0.");
+*timeout = 0;
+return;
+}
+
+result = (result + 500) / 1000; /* Round and convert to seconds */
+
+if (result > 0x) {
+error_report("splash-time value is greater than 65535000,"
+ " forcing it to 65535000.");
+*timeout = 0x;
+return;
+}
+
+*timeout = cpu_to_be16(result);
+}
+}
+
 static bool s390_gen_initial_iplb(S390IPLState *ipl)
 {
 DeviceState *dev_st;
@@ -273,6 +322,9 @@ static bool s390_gen_initial_iplb(S390IPLState *ipl)
 if (!s390_ipl_set_loadparm(ipl->iplb.loadparm)) {
 ipl->iplb.flags |= DIAG308_FLAGS_LP_VALID;
 }
+
+s390_ipl_set_boot_menu(>iplb);
+
 return true;
 }
 
diff --git a/hw/s390x/ipl.h b/hw/s390x/ipl.h
index 68dcaf8..90c0ed3 100644
--- a/hw/s390x/ipl.h
+++ b/hw/s390x/ipl.h
@@ -58,8 +58,13 @@ typedef struct IplBlockQemuScsi IplBlockQemuScsi;
 
 #define DIAG308_FLAGS_LP_VALID 0x80
 
+#define BOOT_MENU_FLAG_CMD_OPTS  0x80
+#define BOOT_MENU_FLAG_ZIPL_OPTS 0x40
+
 struct QemuIplParameters {
-uint8_t  reserved1[4];
+uint8_t  boot_menu_flags;
+uint8_t  reserved1;
+uint16_t boot_menu_timeout;
 uint64_t netboot_start_addr;
 uint8_t  reserved2[16];
 } QEMU_PACKED;
diff --git a/pc-bios/s390-ccw/iplb.h b/pc-bios/s390-ccw/iplb.h
index 12f6e40..0bbc1ac 100644
--- a/pc-bios/s390-ccw/iplb.h
+++ b/pc-bios/s390-ccw/iplb.h
@@ -73,7 +73,9 @@ typedef struct IplParameterBlock IplParameterBlock;
 extern IplParameterBlock iplb __attribute__((__aligned__(PAGE_SIZE)));
 
 struct QemuIplParameters {
-uint8_t  reserved1[4];
+uint8_t  boot_menu_flags;
+uint8_t  reserved1;
+uint16_t boot_menu_timeout;
 uint64_t netboot_start_addr;
 uint8_t  reserved2[16];
 } __attribute__ ((packed));
-- 
2.7.4




[Qemu-devel] [PATCH v5 03/12] s390-ccw: refactor IPL structs

2018-02-05 Thread Collin L. Walling
ECKD DASDs have different IPL structures for CDL and LDL
formats. The current Ipl1 and Ipl2 structs follow the CDL
format, so we prepend "EckdCdl" to them. Boot info for LDL
has been moved to a new struct: EckdLdlIpl1.

Signed-off-by: Collin L. Walling <wall...@linux.vnet.ibm.com>
Acked-by: Janosch Frank <fran...@linux.vnet.ibm.com>
Reviewed-by: Thomas Huth <th...@redhat.com>
---
 pc-bios/s390-ccw/bootmap.c | 12 ++--
 pc-bios/s390-ccw/bootmap.h | 37 +
 2 files changed, 27 insertions(+), 22 deletions(-)

diff --git a/pc-bios/s390-ccw/bootmap.c b/pc-bios/s390-ccw/bootmap.c
index 9b9696e..c97f136 100644
--- a/pc-bios/s390-ccw/bootmap.c
+++ b/pc-bios/s390-ccw/bootmap.c
@@ -221,7 +221,7 @@ static void run_eckd_boot_script(block_number_t 
bmt_block_nr)
 static void ipl_eckd_cdl(void)
 {
 XEckdMbr *mbr;
-Ipl2 *ipl2 = (void *)sec;
+EckdCdlIpl2 *ipl2 = (void *)sec;
 IplVolumeLabel *vlbl = (void *)sec;
 block_number_t bmt_block_nr;
 
@@ -231,7 +231,7 @@ static void ipl_eckd_cdl(void)
 memset(sec, FREE_SPACE_FILLER, sizeof(sec));
 read_block(1, ipl2, "Cannot read IPL2 record at block 1");
 
-mbr = >u.x.mbr;
+mbr = >mbr;
 IPL_assert(magic_match(mbr, ZIPL_MAGIC), "No zIPL section in IPL2 
record.");
 IPL_assert(block_size_ok(mbr->blockptr.xeckd.bptr.size),
"Bad block size in zIPL section of IPL2 record.");
@@ -281,7 +281,7 @@ static void print_eckd_ldl_msg(ECKD_IPL_mode_t mode)
 static void ipl_eckd_ldl(ECKD_IPL_mode_t mode)
 {
 block_number_t bmt_block_nr;
-BootInfo *bip = (void *)(sec + 0x70); /* BootInfo is MBR for LDL */
+EckdLdlIpl1 *ipl1 = (void *)sec;
 
 if (mode != ECKD_LDL_UNLABELED) {
 print_eckd_ldl_msg(mode);
@@ -292,15 +292,15 @@ static void ipl_eckd_ldl(ECKD_IPL_mode_t mode)
 memset(sec, FREE_SPACE_FILLER, sizeof(sec));
 read_block(0, sec, "Cannot read block 0 to grab boot info.");
 if (mode == ECKD_LDL_UNLABELED) {
-if (!magic_match(bip->magic, ZIPL_MAGIC)) {
+if (!magic_match(ipl1->bip.magic, ZIPL_MAGIC)) {
 return; /* not applicable layout */
 }
 sclp_print("unlabeled LDL.\n");
 }
-verify_boot_info(bip);
+verify_boot_info(>bip);
 
 /* save pointer to Boot Map Table */
-bmt_block_nr = eckd_block_num(>bp.ipl.bm_ptr.eckd.bptr.chs);
+bmt_block_nr = eckd_block_num(>bip.bp.ipl.bm_ptr.eckd.bptr.chs);
 
 run_eckd_boot_script(bmt_block_nr);
 /* no return */
diff --git a/pc-bios/s390-ccw/bootmap.h b/pc-bios/s390-ccw/bootmap.h
index 260ac2a..cfe9ddd 100644
--- a/pc-bios/s390-ccw/bootmap.h
+++ b/pc-bios/s390-ccw/bootmap.h
@@ -237,22 +237,27 @@ typedef struct BootInfo {  /* @ 0x70, record #0   
 */
 } bp;
 } __attribute__ ((packed)) BootInfo; /* see also XEckdMbr   */
 
-typedef struct Ipl1 {
-unsigned char key[4]; /* == "IPL1" */
-unsigned char data[24];
-} __attribute__((packed)) Ipl1;
-
-typedef struct Ipl2 {
-unsigned char key[4]; /* == "IPL2" */
-union {
-unsigned char data[144];
-struct {
-unsigned char reserved1[92-4];
-XEckdMbr mbr;
-unsigned char reserved2[144-(92-4)-sizeof(XEckdMbr)];
-} x;
-} u;
-} __attribute__((packed)) Ipl2;
+/*
+ * Structs for IPL
+ */
+#define STAGE2_BLK_CNT_MAX  24 /* Stage 1b can load up to 24 blocks */
+
+typedef struct EckdCdlIpl1 {
+uint8_t key[4]; /* == "IPL1" */
+uint8_t data[24];
+} __attribute__((packed)) EckdCdlIpl1;
+
+typedef struct EckdCdlIpl2 {
+uint8_t key[4]; /* == "IPL2" */
+uint8_t reserved0[88];
+XEckdMbr mbr;
+uint8_t reserved[24];
+} __attribute__((packed)) EckdCdlIpl2;
+
+typedef struct EckdLdlIpl1 {
+uint8_t reserved[112];
+BootInfo bip; /* BootInfo is MBR for LDL */
+} __attribute__((packed)) EckdLdlIpl1;
 
 typedef struct IplVolumeLabel {
 unsigned char key[4]; /* == "VOL1" */
-- 
2.7.4




[Qemu-devel] [PATCH v5 05/12] s390-ccw: move auxiliary IPL data to separate location

2018-02-05 Thread Collin L. Walling
The s390-ccw firmware needs some information in support of the
boot process which is not available on the native machine.
Examples are the netboot firmware load address and now the
boot menu parameters.

While storing that data in unused fields of the IPL parameter block
works, that approach could create problems if the parameter block
definition should change in the future. Because then a guest could
overwrite these fields using the set IPLB diagnose.

In fact the data in question is of more global nature and not really
tied to an IPL device, so separating it is rather logical.

This commit introduces a new structure to hold firmware relevant
IPL parameters set by QEMU. The data is stored at location 204 (dec)
and can contain up to 7 32-bit words. This area is available to
programming in the z/Architecture Principles of Operation and
can thus safely be used by the firmware until the IPL has completed.

Signed-off-by: Viktor Mihajlovski 
---
 hw/s390x/ipl.c  | 18 +-
 hw/s390x/ipl.h  | 11 +--
 pc-bios/s390-ccw/iplb.h | 12 ++--
 pc-bios/s390-ccw/main.c |  6 +-
 4 files changed, 41 insertions(+), 6 deletions(-)

diff --git a/hw/s390x/ipl.c b/hw/s390x/ipl.c
index 0d06fc1..3e3c3b8 100644
--- a/hw/s390x/ipl.c
+++ b/hw/s390x/ipl.c
@@ -399,6 +399,20 @@ void s390_reipl_request(void)
 qemu_system_reset_request(SHUTDOWN_CAUSE_GUEST_RESET);
 }
 
+static void s390_ipl_prepare_qipl(S390CPU *cpu)
+{
+S390IPLState *ipl = get_ipl_device();
+uint8_t *addr;
+uint64_t len = 4096;
+
+addr = cpu_physical_memory_map(cpu->env.psa, , 1);
+if (!addr || len < 204 + sizeof(QemuIplParameters)) {
+error_report("Cannot set QEMU IPL parameters");
+}
+memcpy(addr + 204, >iplb.qipl, sizeof(QemuIplParameters));
+cpu_physical_memory_unmap(addr, len, 1, len);
+}
+
 void s390_ipl_prepare_cpu(S390CPU *cpu)
 {
 S390IPLState *ipl = get_ipl_device();
@@ -418,8 +432,10 @@ void s390_ipl_prepare_cpu(S390CPU *cpu)
 error_report_err(err);
 vm_stop(RUN_STATE_INTERNAL_ERROR);
 }
-ipl->iplb.ccw.netboot_start_addr = cpu_to_be64(ipl->start_addr);
+ipl->iplb.qipl.netboot_start_addr = cpu_to_be64(ipl->start_addr);
 }
+s390_ipl_prepare_qipl(cpu);
+
 }
 
 static void s390_ipl_reset(DeviceState *dev)
diff --git a/hw/s390x/ipl.h b/hw/s390x/ipl.h
index 8a705e0..68dcaf8 100644
--- a/hw/s390x/ipl.h
+++ b/hw/s390x/ipl.h
@@ -16,8 +16,7 @@
 #include "cpu.h"
 
 struct IplBlockCcw {
-uint64_t netboot_start_addr;
-uint8_t  reserved0[77];
+uint8_t  reserved0[85];
 uint8_t  ssid;
 uint16_t devno;
 uint8_t  vm_flags;
@@ -59,6 +58,13 @@ typedef struct IplBlockQemuScsi IplBlockQemuScsi;
 
 #define DIAG308_FLAGS_LP_VALID 0x80
 
+struct QemuIplParameters {
+uint8_t  reserved1[4];
+uint64_t netboot_start_addr;
+uint8_t  reserved2[16];
+} QEMU_PACKED;
+typedef struct QemuIplParameters QemuIplParameters;
+
 union IplParameterBlock {
 struct {
 uint32_t len;
@@ -74,6 +80,7 @@ union IplParameterBlock {
 IplBlockFcp fcp;
 IplBlockQemuScsi scsi;
 };
+QemuIplParameters qipl;
 } QEMU_PACKED;
 struct {
 uint8_t  reserved1[110];
diff --git a/pc-bios/s390-ccw/iplb.h b/pc-bios/s390-ccw/iplb.h
index 890aed9..12f6e40 100644
--- a/pc-bios/s390-ccw/iplb.h
+++ b/pc-bios/s390-ccw/iplb.h
@@ -13,8 +13,7 @@
 #define IPLB_H
 
 struct IplBlockCcw {
-uint64_t netboot_start_addr;
-uint8_t  reserved0[77];
+uint8_t  reserved0[85];
 uint8_t  ssid;
 uint16_t devno;
 uint8_t  vm_flags;
@@ -73,6 +72,15 @@ typedef struct IplParameterBlock IplParameterBlock;
 
 extern IplParameterBlock iplb __attribute__((__aligned__(PAGE_SIZE)));
 
+struct QemuIplParameters {
+uint8_t  reserved1[4];
+uint64_t netboot_start_addr;
+uint8_t  reserved2[16];
+} __attribute__ ((packed));
+typedef struct QemuIplParameters QemuIplParameters;
+
+extern QemuIplParameters qipl;
+
 #define S390_IPL_TYPE_FCP 0x00
 #define S390_IPL_TYPE_CCW 0x02
 #define S390_IPL_TYPE_QEMU_SCSI 0xff
diff --git a/pc-bios/s390-ccw/main.c b/pc-bios/s390-ccw/main.c
index e857ce4..825a1a3 100644
--- a/pc-bios/s390-ccw/main.c
+++ b/pc-bios/s390-ccw/main.c
@@ -16,6 +16,7 @@ char stack[PAGE_SIZE * 8] 
__attribute__((__aligned__(PAGE_SIZE)));
 static SubChannelId blk_schid = { .one = 1 };
 IplParameterBlock iplb __attribute__((__aligned__(PAGE_SIZE)));
 static char loadparm[8] = { 0, 0, 0, 0, 0, 0, 0, 0 };
+QemuIplParameters qipl;
 
 /*
  * Priniciples of Operations (SA22-7832-09) chapter 17 requires that
@@ -81,6 +82,7 @@ static void virtio_setup(void)
 uint16_t dev_no;
 char ldp[] = "LOADPARM=[]\n";
 VDev *vdev = virtio_get_device();
+QemuIplParameters *early_qipl = (QemuIplParameters *)204;
 
 /*
  * We unconditionally enable mss support. In every sane configuration,
@@ -93,6 +95,8 @@ static void 

  1   2   >