More s390x patches, this time boot related:
- LOADPARM machine property, exposed to the guest via SCLP and diagnose 308 - Use LOADPARM in the s390-ccw bios to select a boot entry - Fix a crash in the ipl device code when a virtio-scsi-pci device has been specified -----BEGIN PGP SIGNATURE----- Version: GnuPG v1 iQIcBAABAgAGBQJZCIm2AAoJEN7Pa5PG8C+v/ckP/3doTOMyiYWQZ91MOKk2UP4W paX4+hqEmuy68Jpk6/owk9t3Mzlx2c0xLuDQX7QWuifi3Vk1y5kD1DbRNx14t6oy icqzWh9wSGMT8Suacf44WjFR+V5TDX9DxrB2c/YDSI1UWg6cEJDM6//hZrbkSH+s Ig4O5rpmhpMNycnDYwSAQXCOZgyqDG8pVdVk0H+nWU/1+9uxVNYEnB8yMpCRSB9a IaDU7LNqkMNBRjCYWLCfMn+UNuRV7bB33iaM3KmaDkAu+XuCZTQuT4H3r5bV5Ata UUCmJtfiWUsGJAOaoxbBrNVNWEUW4yZxsjbVceBkYrUHw0xU6ZKCtyA/AhMCDraF yDwxUbHRQ4rmvqfeyyUGZRMErn7WfdXoPjwWzN3/Cj4DSXSpgz/FTlRmap2B3yqK 1u6lyQFyfTvHgvLVvtfPSQSYGPSGA0/qotzE3C1DoUHZAJtpnYtCRW2mlAd/RxWy 5xUfW6W9p+mE2OHI/zEs47pWe8U4uiG7A+jfEzqKSlMe7g8EGDVvoVFmwL6nPwbD xhzZAsiw3yK3YSeVcYN0bsrvvP6PUBLpnumU0u1QlZlSOoTv79KlJQSXksvrsqqr t/fSsXrW+ZUGDuMnK8qr7Fg1gCPmzfA6bo8o5rmWCE+zM2oDln5UMlZy+QhA1J05 HqG+2eHpaCyLCBKZyF9u =fFQl -----END PGP SIGNATURE----- Merge remote-tracking branch 'cohuck/tags/s390x-20170502' into staging More s390x patches, this time boot related: - LOADPARM machine property, exposed to the guest via SCLP and diagnose 308 - Use LOADPARM in the s390-ccw bios to select a boot entry - Fix a crash in the ipl device code when a virtio-scsi-pci device has been specified # gpg: Signature made Tue 02 May 2017 02:29:26 PM BST # gpg: using RSA key 0xDECF6B93C6F02FAF # gpg: Good signature from "Cornelia Huck <conny@cornelia-huck.de>" # gpg: aka "Cornelia Huck <cohuck@kernel.org>" # gpg: aka "Cornelia Huck <cornelia.huck@de.ibm.com>" # gpg: aka "Cornelia Huck <huckc@linux.vnet.ibm.com>" # Primary key fingerprint: C3D0 D66D C362 4FF6 A8C0 18CE DECF 6B93 C6F0 2FAF * cohuck/tags/s390x-20170502: hw/s390x/ipl: Fix crash with virtio-scsi-pci device pc-bios/s390-ccw.img: update image pc-bios/s390-ccw: add boot entry selection to El Torito routine pc-bios/s390-ccw: add boot entry selection for ECKD DASD pc-bios/s390-ccw: provide entry selection on LOADPARM for SCSI disk pc-bios/s390-ccw: provide a function to interpret LOADPARM value pc-bios/s390-ccw: get LOADPARM stored in SCP Read Info pc-bios/s390-ccw: Make ebcdic/ascii conversion public util/qemu-config: Add loadparm to qemu machine_opts hw/s390x/sclp: update LOADPARM in SCP Info hw/s390x/ipl: enable LOADPARM in IPIB for a boot device hw/s390x: provide loadparm property for the machine Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
This commit is contained in:
commit
4f225f343a
|
@ -17,8 +17,10 @@
|
||||||
#include "cpu.h"
|
#include "cpu.h"
|
||||||
#include "elf.h"
|
#include "elf.h"
|
||||||
#include "hw/loader.h"
|
#include "hw/loader.h"
|
||||||
|
#include "hw/boards.h"
|
||||||
#include "hw/s390x/virtio-ccw.h"
|
#include "hw/s390x/virtio-ccw.h"
|
||||||
#include "hw/s390x/css.h"
|
#include "hw/s390x/css.h"
|
||||||
|
#include "hw/s390x/ebcdic.h"
|
||||||
#include "ipl.h"
|
#include "ipl.h"
|
||||||
#include "qemu/error-report.h"
|
#include "qemu/error-report.h"
|
||||||
|
|
||||||
|
@ -243,12 +245,17 @@ static bool s390_gen_initial_iplb(S390IPLState *ipl)
|
||||||
ipl->iplb.pbt = S390_IPL_TYPE_CCW;
|
ipl->iplb.pbt = S390_IPL_TYPE_CCW;
|
||||||
ipl->iplb.ccw.devno = cpu_to_be16(ccw_dev->sch->devno);
|
ipl->iplb.ccw.devno = cpu_to_be16(ccw_dev->sch->devno);
|
||||||
ipl->iplb.ccw.ssid = ccw_dev->sch->ssid & 3;
|
ipl->iplb.ccw.ssid = ccw_dev->sch->ssid & 3;
|
||||||
return true;
|
|
||||||
} else if (sd) {
|
} else if (sd) {
|
||||||
SCSIBus *bus = scsi_bus_from_device(sd);
|
SCSIBus *bus = scsi_bus_from_device(sd);
|
||||||
VirtIOSCSI *vdev = container_of(bus, VirtIOSCSI, bus);
|
VirtIOSCSI *vdev = container_of(bus, VirtIOSCSI, bus);
|
||||||
VirtIOSCSICcw *scsi_ccw = container_of(vdev, VirtIOSCSICcw, vdev);
|
VirtIOSCSICcw *scsi_ccw = container_of(vdev, VirtIOSCSICcw, vdev);
|
||||||
CcwDevice *ccw_dev = CCW_DEVICE(scsi_ccw);
|
CcwDevice *ccw_dev;
|
||||||
|
|
||||||
|
ccw_dev = (CcwDevice *)object_dynamic_cast(OBJECT(scsi_ccw),
|
||||||
|
TYPE_CCW_DEVICE);
|
||||||
|
if (!ccw_dev) { /* It might be a PCI device instead */
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
ipl->iplb.len = cpu_to_be32(S390_IPLB_MIN_QEMU_SCSI_LEN);
|
ipl->iplb.len = cpu_to_be32(S390_IPLB_MIN_QEMU_SCSI_LEN);
|
||||||
ipl->iplb.blk0_len =
|
ipl->iplb.blk0_len =
|
||||||
|
@ -259,13 +266,39 @@ static bool s390_gen_initial_iplb(S390IPLState *ipl)
|
||||||
ipl->iplb.scsi.channel = cpu_to_be16(sd->channel);
|
ipl->iplb.scsi.channel = cpu_to_be16(sd->channel);
|
||||||
ipl->iplb.scsi.devno = cpu_to_be16(ccw_dev->sch->devno);
|
ipl->iplb.scsi.devno = cpu_to_be16(ccw_dev->sch->devno);
|
||||||
ipl->iplb.scsi.ssid = ccw_dev->sch->ssid & 3;
|
ipl->iplb.scsi.ssid = ccw_dev->sch->ssid & 3;
|
||||||
return true;
|
} else {
|
||||||
|
return false; /* unknown device */
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!s390_ipl_set_loadparm(ipl->iplb.loadparm)) {
|
||||||
|
ipl->iplb.flags |= DIAG308_FLAGS_LP_VALID;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int s390_ipl_set_loadparm(uint8_t *loadparm)
|
||||||
|
{
|
||||||
|
MachineState *machine = MACHINE(qdev_get_machine());
|
||||||
|
char *lp = object_property_get_str(OBJECT(machine), "loadparm", NULL);
|
||||||
|
|
||||||
|
if (lp) {
|
||||||
|
int i;
|
||||||
|
|
||||||
|
/* lp is an uppercase string without leading/embedded spaces */
|
||||||
|
for (i = 0; i < 8 && lp[i]; i++) {
|
||||||
|
loadparm[i] = ascii2ebcdic[(uint8_t) lp[i]];
|
||||||
|
}
|
||||||
|
|
||||||
|
g_free(lp);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
static int load_netboot_image(Error **errp)
|
static int load_netboot_image(Error **errp)
|
||||||
{
|
{
|
||||||
S390IPLState *ipl = get_ipl_device();
|
S390IPLState *ipl = get_ipl_device();
|
||||||
|
|
|
@ -57,6 +57,8 @@ struct IplBlockQemuScsi {
|
||||||
} QEMU_PACKED;
|
} QEMU_PACKED;
|
||||||
typedef struct IplBlockQemuScsi IplBlockQemuScsi;
|
typedef struct IplBlockQemuScsi IplBlockQemuScsi;
|
||||||
|
|
||||||
|
#define DIAG308_FLAGS_LP_VALID 0x80
|
||||||
|
|
||||||
union IplParameterBlock {
|
union IplParameterBlock {
|
||||||
struct {
|
struct {
|
||||||
uint32_t len;
|
uint32_t len;
|
||||||
|
@ -82,6 +84,7 @@ union IplParameterBlock {
|
||||||
} QEMU_PACKED;
|
} QEMU_PACKED;
|
||||||
typedef union IplParameterBlock IplParameterBlock;
|
typedef union IplParameterBlock IplParameterBlock;
|
||||||
|
|
||||||
|
int s390_ipl_set_loadparm(uint8_t *loadparm);
|
||||||
void s390_ipl_update_diag308(IplParameterBlock *iplb);
|
void s390_ipl_update_diag308(IplParameterBlock *iplb);
|
||||||
void s390_ipl_prepare_cpu(S390CPU *cpu);
|
void s390_ipl_prepare_cpu(S390CPU *cpu);
|
||||||
IplParameterBlock *s390_ipl_get_iplb(void);
|
IplParameterBlock *s390_ipl_get_iplb(void);
|
||||||
|
|
|
@ -274,6 +274,36 @@ bool cpu_model_allowed(void)
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static char *machine_get_loadparm(Object *obj, Error **errp)
|
||||||
|
{
|
||||||
|
S390CcwMachineState *ms = S390_CCW_MACHINE(obj);
|
||||||
|
|
||||||
|
return g_memdup(ms->loadparm, sizeof(ms->loadparm));
|
||||||
|
}
|
||||||
|
|
||||||
|
static void machine_set_loadparm(Object *obj, const char *val, Error **errp)
|
||||||
|
{
|
||||||
|
S390CcwMachineState *ms = S390_CCW_MACHINE(obj);
|
||||||
|
int i;
|
||||||
|
|
||||||
|
for (i = 0; i < sizeof(ms->loadparm) && val[i]; i++) {
|
||||||
|
uint8_t c = toupper(val[i]); /* mimic HMC */
|
||||||
|
|
||||||
|
if (('A' <= c && c <= 'Z') || ('0' <= c && c <= '9') || (c == '.') ||
|
||||||
|
(c == ' ')) {
|
||||||
|
ms->loadparm[i] = c;
|
||||||
|
} else {
|
||||||
|
error_setg(errp, "LOADPARM: invalid character '%c' (ASCII 0x%02x)",
|
||||||
|
c, c);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (; i < sizeof(ms->loadparm); i++) {
|
||||||
|
ms->loadparm[i] = ' '; /* pad right with spaces */
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
static inline void s390_machine_initfn(Object *obj)
|
static inline void s390_machine_initfn(Object *obj)
|
||||||
{
|
{
|
||||||
object_property_add_bool(obj, "aes-key-wrap",
|
object_property_add_bool(obj, "aes-key-wrap",
|
||||||
|
@ -291,6 +321,13 @@ static inline void s390_machine_initfn(Object *obj)
|
||||||
"enable/disable DEA key wrapping using the CPACF wrapping key",
|
"enable/disable DEA key wrapping using the CPACF wrapping key",
|
||||||
NULL);
|
NULL);
|
||||||
object_property_set_bool(obj, true, "dea-key-wrap", NULL);
|
object_property_set_bool(obj, true, "dea-key-wrap", NULL);
|
||||||
|
object_property_add_str(obj, "loadparm",
|
||||||
|
machine_get_loadparm, machine_set_loadparm, NULL);
|
||||||
|
object_property_set_description(obj, "loadparm",
|
||||||
|
"Up to 8 chars in set of [A-Za-z0-9. ] (lower case chars converted"
|
||||||
|
" to upper case) to pass to machine loader, boot manager,"
|
||||||
|
" and guest kernel",
|
||||||
|
NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
static const TypeInfo ccw_machine_info = {
|
static const TypeInfo ccw_machine_info = {
|
||||||
|
|
|
@ -23,6 +23,7 @@
|
||||||
#include "hw/s390x/sclp.h"
|
#include "hw/s390x/sclp.h"
|
||||||
#include "hw/s390x/event-facility.h"
|
#include "hw/s390x/event-facility.h"
|
||||||
#include "hw/s390x/s390-pci-bus.h"
|
#include "hw/s390x/s390-pci-bus.h"
|
||||||
|
#include "hw/s390x/ipl.h"
|
||||||
|
|
||||||
static inline SCLPDevice *get_sclp_device(void)
|
static inline SCLPDevice *get_sclp_device(void)
|
||||||
{
|
{
|
||||||
|
@ -57,6 +58,7 @@ static void read_SCP_info(SCLPDevice *sclp, SCCB *sccb)
|
||||||
int cpu_count = 0;
|
int cpu_count = 0;
|
||||||
int rnsize, rnmax;
|
int rnsize, rnmax;
|
||||||
int slots = MIN(machine->ram_slots, s390_get_memslot_count(kvm_state));
|
int slots = MIN(machine->ram_slots, s390_get_memslot_count(kvm_state));
|
||||||
|
IplParameterBlock *ipib = s390_ipl_get_iplb();
|
||||||
|
|
||||||
CPU_FOREACH(cpu) {
|
CPU_FOREACH(cpu) {
|
||||||
cpu_count++;
|
cpu_count++;
|
||||||
|
@ -129,6 +131,13 @@ static void read_SCP_info(SCLPDevice *sclp, SCCB *sccb)
|
||||||
read_info->rnmax2 = cpu_to_be64(rnmax);
|
read_info->rnmax2 = cpu_to_be64(rnmax);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (ipib && ipib->flags & DIAG308_FLAGS_LP_VALID) {
|
||||||
|
memcpy(&read_info->loadparm, &ipib->loadparm,
|
||||||
|
sizeof(read_info->loadparm));
|
||||||
|
} else {
|
||||||
|
s390_ipl_set_loadparm(read_info->loadparm);
|
||||||
|
}
|
||||||
|
|
||||||
sccb->h.response_code = cpu_to_be16(SCLP_RC_NORMAL_READ_COMPLETION);
|
sccb->h.response_code = cpu_to_be16(SCLP_RC_NORMAL_READ_COMPLETION);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -28,6 +28,7 @@ typedef struct S390CcwMachineState {
|
||||||
/*< public >*/
|
/*< public >*/
|
||||||
bool aes_key_wrap;
|
bool aes_key_wrap;
|
||||||
bool dea_key_wrap;
|
bool dea_key_wrap;
|
||||||
|
uint8_t loadparm[8];
|
||||||
} S390CcwMachineState;
|
} S390CcwMachineState;
|
||||||
|
|
||||||
typedef struct S390CcwMachineClass {
|
typedef struct S390CcwMachineClass {
|
||||||
|
|
Binary file not shown.
|
@ -9,7 +9,7 @@ $(call set-vpath, $(SRC_PATH)/pc-bios/s390-ccw)
|
||||||
|
|
||||||
.PHONY : all clean build-all
|
.PHONY : all clean build-all
|
||||||
|
|
||||||
OBJECTS = start.o main.o bootmap.o sclp-ascii.o virtio.o virtio-scsi.o
|
OBJECTS = start.o main.o bootmap.o sclp.o virtio.o virtio-scsi.o
|
||||||
QEMU_CFLAGS := $(filter -W%, $(QEMU_CFLAGS))
|
QEMU_CFLAGS := $(filter -W%, $(QEMU_CFLAGS))
|
||||||
QEMU_CFLAGS += -ffreestanding -fno-delete-null-pointer-checks -msoft-float
|
QEMU_CFLAGS += -ffreestanding -fno-delete-null-pointer-checks -msoft-float
|
||||||
QEMU_CFLAGS += -march=z900 -fPIE -fno-strict-aliasing
|
QEMU_CFLAGS += -march=z900 -fPIE -fno-strict-aliasing
|
||||||
|
|
|
@ -183,15 +183,21 @@ static block_number_t load_eckd_segments(block_number_t blk, uint64_t *address)
|
||||||
static void run_eckd_boot_script(block_number_t mbr_block_nr)
|
static void run_eckd_boot_script(block_number_t mbr_block_nr)
|
||||||
{
|
{
|
||||||
int i;
|
int i;
|
||||||
|
unsigned int loadparm = get_loadparm_index();
|
||||||
block_number_t block_nr;
|
block_number_t block_nr;
|
||||||
uint64_t address;
|
uint64_t address;
|
||||||
ScsiMbr *scsi_mbr = (void *)sec;
|
ScsiMbr *bte = (void *)sec; /* Eckd bootmap table entry */
|
||||||
BootMapScript *bms = (void *)sec;
|
BootMapScript *bms = (void *)sec;
|
||||||
|
|
||||||
|
debug_print_int("loadparm", loadparm);
|
||||||
|
IPL_assert(loadparm < 31, "loadparm value greater than"
|
||||||
|
" maximum number of boot entries allowed");
|
||||||
|
|
||||||
memset(sec, FREE_SPACE_FILLER, sizeof(sec));
|
memset(sec, FREE_SPACE_FILLER, sizeof(sec));
|
||||||
read_block(mbr_block_nr, sec, "Cannot read MBR");
|
read_block(mbr_block_nr, sec, "Cannot read MBR");
|
||||||
|
|
||||||
block_nr = eckd_block_num((void *)&(scsi_mbr->blockptr));
|
block_nr = eckd_block_num((void *)&(bte->blockptr[loadparm]));
|
||||||
|
IPL_assert(block_nr != -1, "No Boot Map");
|
||||||
|
|
||||||
memset(sec, FREE_SPACE_FILLER, sizeof(sec));
|
memset(sec, FREE_SPACE_FILLER, sizeof(sec));
|
||||||
read_block(block_nr, sec, "Cannot read Boot Map Script");
|
read_block(block_nr, sec, "Cannot read Boot Map Script");
|
||||||
|
@ -444,7 +450,8 @@ static void ipl_scsi(void)
|
||||||
uint8_t *ns, *ns_end;
|
uint8_t *ns, *ns_end;
|
||||||
int program_table_entries = 0;
|
int program_table_entries = 0;
|
||||||
const int pte_len = sizeof(ScsiBlockPtr);
|
const int pte_len = sizeof(ScsiBlockPtr);
|
||||||
ScsiBlockPtr *prog_table_entry;
|
ScsiBlockPtr *prog_table_entry = NULL;
|
||||||
|
unsigned int loadparm = get_loadparm_index();
|
||||||
|
|
||||||
/* Grab the MBR */
|
/* Grab the MBR */
|
||||||
memset(sec, FREE_SPACE_FILLER, sizeof(sec));
|
memset(sec, FREE_SPACE_FILLER, sizeof(sec));
|
||||||
|
@ -458,15 +465,16 @@ static void ipl_scsi(void)
|
||||||
debug_print_int("MBR Version", mbr->version_id);
|
debug_print_int("MBR Version", mbr->version_id);
|
||||||
IPL_check(mbr->version_id == 1,
|
IPL_check(mbr->version_id == 1,
|
||||||
"Unknown MBR layout version, assuming version 1");
|
"Unknown MBR layout version, assuming version 1");
|
||||||
debug_print_int("program table", mbr->blockptr.blockno);
|
debug_print_int("program table", mbr->blockptr[0].blockno);
|
||||||
IPL_assert(mbr->blockptr.blockno, "No Program Table");
|
IPL_assert(mbr->blockptr[0].blockno, "No Program Table");
|
||||||
|
|
||||||
/* Parse the program table */
|
/* Parse the program table */
|
||||||
read_block(mbr->blockptr.blockno, sec,
|
read_block(mbr->blockptr[0].blockno, sec,
|
||||||
"Error reading Program Table");
|
"Error reading Program Table");
|
||||||
|
|
||||||
IPL_assert(magic_match(sec, ZIPL_MAGIC), "No zIPL magic in PT");
|
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();
|
ns_end = sec + virtio_get_block_size();
|
||||||
for (ns = (sec + pte_len); (ns + pte_len) < ns_end; ns += pte_len) {
|
for (ns = (sec + pte_len); (ns + pte_len) < ns_end; ns += pte_len) {
|
||||||
prog_table_entry = (ScsiBlockPtr *)ns;
|
prog_table_entry = (ScsiBlockPtr *)ns;
|
||||||
|
@ -475,16 +483,15 @@ static void ipl_scsi(void)
|
||||||
}
|
}
|
||||||
|
|
||||||
program_table_entries++;
|
program_table_entries++;
|
||||||
|
if (program_table_entries == loadparm + 1) {
|
||||||
|
break; /* selected entry found */
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
debug_print_int("program table entries", program_table_entries);
|
debug_print_int("program table entries", program_table_entries);
|
||||||
|
|
||||||
IPL_assert(program_table_entries != 0, "Empty Program Table");
|
IPL_assert(program_table_entries != 0, "Empty Program Table");
|
||||||
|
|
||||||
/* Run the default entry */
|
|
||||||
|
|
||||||
prog_table_entry = (ScsiBlockPtr *)(sec + pte_len);
|
|
||||||
|
|
||||||
zipl_run(prog_table_entry); /* no return */
|
zipl_run(prog_table_entry); /* no return */
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -648,6 +655,7 @@ static IsoBcSection *find_iso_bc_entry(void)
|
||||||
IsoBcEntry *e = (IsoBcEntry *)sec;
|
IsoBcEntry *e = (IsoBcEntry *)sec;
|
||||||
uint32_t offset = find_iso_bc();
|
uint32_t offset = find_iso_bc();
|
||||||
int i;
|
int i;
|
||||||
|
unsigned int loadparm = get_loadparm_index();
|
||||||
|
|
||||||
if (!offset) {
|
if (!offset) {
|
||||||
return NULL;
|
return NULL;
|
||||||
|
@ -668,7 +676,11 @@ static IsoBcSection *find_iso_bc_entry(void)
|
||||||
for (i = 1; i < ISO_BC_ENTRY_PER_SECTOR; i++) {
|
for (i = 1; i < ISO_BC_ENTRY_PER_SECTOR; i++) {
|
||||||
if (e[i].id == ISO_BC_BOOTABLE_SECTION) {
|
if (e[i].id == ISO_BC_BOOTABLE_SECTION) {
|
||||||
if (is_iso_bc_entry_compatible(&e[i].body.sect)) {
|
if (is_iso_bc_entry_compatible(&e[i].body.sect)) {
|
||||||
return &e[i].body.sect;
|
if (loadparm <= 1) {
|
||||||
|
/* found, default, or unspecified */
|
||||||
|
return &e[i].body.sect;
|
||||||
|
}
|
||||||
|
loadparm--;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -70,7 +70,7 @@ typedef struct ScsiMbr {
|
||||||
uint8_t magic[4];
|
uint8_t magic[4];
|
||||||
uint32_t version_id;
|
uint32_t version_id;
|
||||||
uint8_t reserved[8];
|
uint8_t reserved[8];
|
||||||
ScsiBlockPtr blockptr;
|
ScsiBlockPtr blockptr[];
|
||||||
} __attribute__ ((packed)) ScsiMbr;
|
} __attribute__ ((packed)) ScsiMbr;
|
||||||
|
|
||||||
#define ZIPL_MAGIC "zIPL"
|
#define ZIPL_MAGIC "zIPL"
|
||||||
|
@ -264,28 +264,6 @@ typedef enum {
|
||||||
|
|
||||||
/* utility code below */
|
/* utility code below */
|
||||||
|
|
||||||
static const unsigned char ebc2asc[256] =
|
|
||||||
/* 0123456789abcdef0123456789abcdef */
|
|
||||||
"................................" /* 1F */
|
|
||||||
"................................" /* 3F */
|
|
||||||
" ...........<(+|&.........!$*);." /* 5F first.chr.here.is.real.space */
|
|
||||||
"-/.........,%_>?.........`:#@'=\""/* 7F */
|
|
||||||
".abcdefghi.......jklmnopqr......" /* 9F */
|
|
||||||
"..stuvwxyz......................" /* BF */
|
|
||||||
".ABCDEFGHI.......JKLMNOPQR......" /* DF */
|
|
||||||
"..STUVWXYZ......0123456789......";/* FF */
|
|
||||||
|
|
||||||
static inline void ebcdic_to_ascii(const char *src,
|
|
||||||
char *dst,
|
|
||||||
unsigned int size)
|
|
||||||
{
|
|
||||||
unsigned int i;
|
|
||||||
for (i = 0; i < size; i++) {
|
|
||||||
unsigned c = src[i];
|
|
||||||
dst[i] = ebc2asc[c];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline void print_volser(const void *volser)
|
static inline void print_volser(const void *volser)
|
||||||
{
|
{
|
||||||
char ascii[8];
|
char ascii[8];
|
||||||
|
|
|
@ -14,6 +14,18 @@
|
||||||
char stack[PAGE_SIZE * 8] __attribute__((__aligned__(PAGE_SIZE)));
|
char stack[PAGE_SIZE * 8] __attribute__((__aligned__(PAGE_SIZE)));
|
||||||
static SubChannelId blk_schid = { .one = 1 };
|
static SubChannelId blk_schid = { .one = 1 };
|
||||||
IplParameterBlock iplb __attribute__((__aligned__(PAGE_SIZE)));
|
IplParameterBlock iplb __attribute__((__aligned__(PAGE_SIZE)));
|
||||||
|
static char loadparm[8] = { 0, 0, 0, 0, 0, 0, 0, 0 };
|
||||||
|
|
||||||
|
const unsigned char ebc2asc[256] =
|
||||||
|
/* 0123456789abcdef0123456789abcdef */
|
||||||
|
"................................" /* 1F */
|
||||||
|
"................................" /* 3F */
|
||||||
|
" ...........<(+|&.........!$*);." /* 5F first.chr.here.is.real.space */
|
||||||
|
"-/.........,%_>?.........`:#@'=\""/* 7F */
|
||||||
|
".abcdefghi.......jklmnopqr......" /* 9F */
|
||||||
|
"..stuvwxyz......................" /* BF */
|
||||||
|
".ABCDEFGHI.......JKLMNOPQR......" /* DF */
|
||||||
|
"..STUVWXYZ......0123456789......";/* FF */
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Priniciples of Operations (SA22-7832-09) chapter 17 requires that
|
* Priniciples of Operations (SA22-7832-09) chapter 17 requires that
|
||||||
|
@ -29,7 +41,6 @@ void write_subsystem_identification(void)
|
||||||
*zeroes = 0;
|
*zeroes = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void panic(const char *string)
|
void panic(const char *string)
|
||||||
{
|
{
|
||||||
sclp_print(string);
|
sclp_print(string);
|
||||||
|
@ -37,6 +48,26 @@ void panic(const char *string)
|
||||||
while (1) { }
|
while (1) { }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
unsigned int get_loadparm_index(void)
|
||||||
|
{
|
||||||
|
const char *lp = loadparm;
|
||||||
|
int i;
|
||||||
|
unsigned int idx = 0;
|
||||||
|
|
||||||
|
for (i = 0; i < 8; i++) {
|
||||||
|
char c = lp[i];
|
||||||
|
|
||||||
|
if (c < '0' || c > '9') {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
idx *= 10;
|
||||||
|
idx += c - '0';
|
||||||
|
}
|
||||||
|
|
||||||
|
return idx;
|
||||||
|
}
|
||||||
|
|
||||||
static bool find_dev(Schib *schib, int dev_no)
|
static bool find_dev(Schib *schib, int dev_no)
|
||||||
{
|
{
|
||||||
int i, r;
|
int i, r;
|
||||||
|
@ -73,6 +104,7 @@ static void virtio_setup(void)
|
||||||
int ssid;
|
int ssid;
|
||||||
bool found = false;
|
bool found = false;
|
||||||
uint16_t dev_no;
|
uint16_t dev_no;
|
||||||
|
char ldp[] = "LOADPARM=[________]\n";
|
||||||
VDev *vdev = virtio_get_device();
|
VDev *vdev = virtio_get_device();
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -82,6 +114,10 @@ static void virtio_setup(void)
|
||||||
*/
|
*/
|
||||||
enable_mss_facility();
|
enable_mss_facility();
|
||||||
|
|
||||||
|
sclp_get_loadparm_ascii(loadparm);
|
||||||
|
memcpy(ldp + 10, loadparm, 8);
|
||||||
|
sclp_print(ldp);
|
||||||
|
|
||||||
if (store_iplb(&iplb)) {
|
if (store_iplb(&iplb)) {
|
||||||
switch (iplb.pbt) {
|
switch (iplb.pbt) {
|
||||||
case S390_IPL_TYPE_CCW:
|
case S390_IPL_TYPE_CCW:
|
||||||
|
|
|
@ -62,10 +62,12 @@ void consume_sclp_int(void);
|
||||||
void panic(const char *string);
|
void panic(const char *string);
|
||||||
void write_subsystem_identification(void);
|
void write_subsystem_identification(void);
|
||||||
extern char stack[PAGE_SIZE * 8] __attribute__((__aligned__(PAGE_SIZE)));
|
extern char stack[PAGE_SIZE * 8] __attribute__((__aligned__(PAGE_SIZE)));
|
||||||
|
unsigned int get_loadparm_index(void);
|
||||||
|
|
||||||
/* sclp-ascii.c */
|
/* sclp.c */
|
||||||
void sclp_print(const char *string);
|
void sclp_print(const char *string);
|
||||||
void sclp_setup(void);
|
void sclp_setup(void);
|
||||||
|
void sclp_get_loadparm_ascii(char *loadparm);
|
||||||
|
|
||||||
/* virtio.c */
|
/* virtio.c */
|
||||||
unsigned long virtio_load_direct(ulong rec_list1, ulong rec_list2,
|
unsigned long virtio_load_direct(ulong rec_list1, ulong rec_list2,
|
||||||
|
@ -189,4 +191,17 @@ static inline void IPL_check(bool term, const char *message)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
extern const unsigned char ebc2asc[256];
|
||||||
|
static inline void ebcdic_to_ascii(const char *src,
|
||||||
|
char *dst,
|
||||||
|
unsigned int size)
|
||||||
|
{
|
||||||
|
unsigned int i;
|
||||||
|
|
||||||
|
for (i = 0; i < size; i++) {
|
||||||
|
unsigned c = src[i];
|
||||||
|
dst[i] = ebc2asc[c];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#endif /* S390_CCW_H */
|
#endif /* S390_CCW_H */
|
||||||
|
|
|
@ -80,3 +80,15 @@ void sclp_print(const char *str)
|
||||||
|
|
||||||
sclp_service_call(SCLP_CMD_WRITE_EVENT_DATA, sccb);
|
sclp_service_call(SCLP_CMD_WRITE_EVENT_DATA, sccb);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void sclp_get_loadparm_ascii(char *loadparm)
|
||||||
|
{
|
||||||
|
|
||||||
|
ReadInfo *sccb = (void *)_sccb;
|
||||||
|
|
||||||
|
memset((char *)_sccb, 0, sizeof(ReadInfo));
|
||||||
|
sccb->h.length = sizeof(ReadInfo);
|
||||||
|
if (!sclp_service_call(SCLP_CMDW_READ_SCP_INFO, sccb)) {
|
||||||
|
ebcdic_to_ascii((char *) sccb->loadparm, loadparm, 8);
|
||||||
|
}
|
||||||
|
}
|
|
@ -55,6 +55,8 @@ typedef struct ReadInfo {
|
||||||
SCCBHeader h;
|
SCCBHeader h;
|
||||||
uint16_t rnmax;
|
uint16_t rnmax;
|
||||||
uint8_t rnsize;
|
uint8_t rnsize;
|
||||||
|
uint8_t reserved[13];
|
||||||
|
uint8_t loadparm[8];
|
||||||
} __attribute__((packed)) ReadInfo;
|
} __attribute__((packed)) ReadInfo;
|
||||||
|
|
||||||
typedef struct SCCB {
|
typedef struct SCCB {
|
||||||
|
|
|
@ -227,6 +227,12 @@ static QemuOptsList machine_opts = {
|
||||||
.name = "dea-key-wrap",
|
.name = "dea-key-wrap",
|
||||||
.type = QEMU_OPT_BOOL,
|
.type = QEMU_OPT_BOOL,
|
||||||
.help = "enable/disable DEA key wrapping using the CPACF wrapping key",
|
.help = "enable/disable DEA key wrapping using the CPACF wrapping key",
|
||||||
|
},{
|
||||||
|
.name = "loadparm",
|
||||||
|
.type = QEMU_OPT_STRING,
|
||||||
|
.help = "Up to 8 chars in set of [A-Za-z0-9. ](lower case chars"
|
||||||
|
" converted to upper case) to pass to machine"
|
||||||
|
" loader, boot manager, and guest kernel",
|
||||||
},
|
},
|
||||||
{ /* End of list */ }
|
{ /* End of list */ }
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue