Browse Source
information - remove s390x memory hotplug implementation, which is not useable in this form - add boot menu support in the s390-ccw bios - expose s390x guest crash information - fixes and cleaups -----BEGIN PGP SIGNATURE----- iQJGBAABCAAwFiEEw9DWbcNiT/aowBjO3s9rk8bwL68FAlqX+BcSHGNvaHVja0By ZWRoYXQuY29tAAoJEN7Pa5PG8C+vvMMP/0QihBv9AjhvuvD49Fmyr8+g7ARFO15V t2xU/hiiW3WSbKl2afeZ8TB8PhI8vv+IthJs6eUHLJ6+0iQt2MKWGU4voIGvx2Ip 0727GSrOKFN5Db0pYrgvhGuTVpwE5BUKNfBg7nC0JOAuf9piXO8F+tRcCQmfIkT2 oeMrJzzfIRbQGSORfS2igQPdn+sQMf4Lxv3ZxcDFIGuzG/UkoG+DrXeiVJYQMGdv NB/qmj6vUMo0QPZskLAMolfpw9HSllku2BTDOSPsvW5rUVJHDqcqnnWSLUkpuXOJ k1oyf2mDSM3DfSUDxTsB7QLUXmfdGl9noCGrqeILmciuG6fNCAZv7LWG//mUiIXU IkC4VjHoEFN0z3OvPUrL/ZRB4lBJICCSP3MVEuttn774zon+aKEJqpD6qThRkbjv ntMemq8Xw+qEYmB+kGKfsR/cc4RUVRkikX/eBUHun66kP5gjgmfRKWgYtne7G35b LA1BwX2R1FNAmzD1cPdLV8OeRXUfwqS9N+88/LZsY9pGUVSrqXz5YfNBGiQHJyJv pPoDQ0ZZJSjHUKfUIJB9F3za7vmY4iZp4X2xFp780mZbIH1xEE1OnZA4NrZepn5G tagBwQZWMztz9vjqkHV6LuPM4ycK0tAev58Zqi9caNErmOtmVkGiCGbpYhCz7Ckx IyaUFJZ3dxvO =chDT -----END PGP SIGNATURE----- Merge remote-tracking branch 'remotes/cohuck/tags/s390x-20180301-v2' into staging - add query-cpus-fast and deprecate query-cpus, while adding s390 cpu information - remove s390x memory hotplug implementation, which is not useable in this form - add boot menu support in the s390-ccw bios - expose s390x guest crash information - fixes and cleaups # gpg: Signature made Thu 01 Mar 2018 12:54:47 GMT # gpg: using RSA key DECF6B93C6F02FAF # gpg: Good signature from "Cornelia Huck <conny@cornelia-huck.de>" # gpg: aka "Cornelia Huck <huckc@linux.vnet.ibm.com>" # gpg: aka "Cornelia Huck <cornelia.huck@de.ibm.com>" # gpg: aka "Cornelia Huck <cohuck@kernel.org>" # gpg: aka "Cornelia Huck <cohuck@redhat.com>" # Primary key fingerprint: C3D0 D66D C362 4FF6 A8C0 18CE DECF 6B93 C6F0 2FAF * remotes/cohuck/tags/s390x-20180301-v2: (27 commits) s390x/tcg: fix loading 31bit PSWs with the highest bit set s390x: remove s390_get_memslot_count s390x/sclp: remove memory hotplug support s390x/cpumodel: document S390FeatDef.bit not applicable hmp: change hmp_info_cpus to use query-cpus-fast qemu-doc: deprecate query-cpus qmp: add architecture specific cpu data for query-cpus-fast qmp: add query-cpus-fast qmp: expose s390-specific CPU info s390x/tcg: add various alignment checks s390x/tcg: fix disabling/enabling DAT s390/stattrib: Make SaveVMHandlers data static s390x/cpu: expose the guest crash information pc-bios/s390: Rebuild the s390x firmware images with the boot menu changes s390-ccw: interactive boot menu for scsi s390-ccw: use zipl values when no boot menu options are present s390-ccw: set cp_receive mask only when needed and consume pending service irqs s390-ccw: read user input for boot index via the SCLP console s390-ccw: print zipl boot menu s390-ccw: read stage2 boot loader data to find menu ... Signed-off-by: Peter Maydell <peter.maydell@linaro.org>pull/66/merge
40 changed files with 1222 additions and 606 deletions
Binary file not shown.
@ -0,0 +1,88 @@ |
|||
/*
|
|||
* libc-style definitions and functions |
|||
* |
|||
* Copyright 2018 IBM Corp. |
|||
* Author(s): Collin L. Walling <walling@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 = 1; /* account for NUL */ |
|||
uint64_t tmp = num; |
|||
|
|||
IPL_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 NUL */ |
|||
IPL_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; |
|||
} |
|||
@ -0,0 +1,249 @@ |
|||
/*
|
|||
* QEMU S390 Interactive Boot Menu |
|||
* |
|||
* Copyright 2018 IBM Corp. |
|||
* Author: Collin L. Walling <walling@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" |
|||
#include "sclp.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_OFFSET 140 |
|||
|
|||
#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)); |
|||
|
|||
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; |
|||
} |
|||
|
|||
/* 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) |
|||
{ |
|||
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) |
|||
{ |
|||
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; |
|||
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++) { |
|||
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 */ |
|||
} |
|||
|
|||
|
|||
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; |
|||
timeout = boot_menu_timeout; |
|||
} |
|||
|
|||
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; |
|||
} |
|||
Binary file not shown.
Loading…
Reference in new issue