s390/ipl: provide uapi header for list directed IPL

The IPL parameter block is used as an interface between Linux and
the machine to query and change the boot device and boot options.
To be able to create IPL parameter block in user space and pass it
as segment to kexec provide an uapi header with proper structure
definitions for the block.

Signed-off-by: Martin Schwidefsky <schwidefsky@de.ibm.com>
This commit is contained in:
Martin Schwidefsky 2019-02-20 14:26:51 +01:00
parent 86c74d869d
commit 5f1207fbe7
5 changed files with 161 additions and 128 deletions

View File

@ -106,12 +106,12 @@ static void append_ipl_block_parm(void)
delim = early_command_line + len; /* '\0' character position */
parm = early_command_line + len + 1; /* append right after '\0' */
switch (ipl_block.hdr.pbt) {
case DIAG308_IPL_TYPE_CCW:
switch (ipl_block.pb0_hdr.pbt) {
case IPL_PBT_CCW:
rc = ipl_block_get_ascii_vmparm(
parm, COMMAND_LINE_SIZE - len - 1, &ipl_block);
break;
case DIAG308_IPL_TYPE_FCP:
case IPL_PBT_FCP:
rc = ipl_block_get_ascii_scpdata(
parm, COMMAND_LINE_SIZE - len - 1, &ipl_block);
break;
@ -238,8 +238,8 @@ void setup_memory_end(void)
{
#ifdef CONFIG_CRASH_DUMP
if (!OLDMEM_BASE && ipl_block_valid &&
ipl_block.hdr.pbt == DIAG308_IPL_TYPE_FCP &&
ipl_block.fcp.opt == DIAG308_IPL_OPT_DUMP) {
ipl_block.pb0_hdr.pbt == IPL_PBT_FCP &&
ipl_block.fcp.opt == IPL_PB0_FCP_OPT_DUMP) {
if (!sclp_early_get_hsa_size(&memory_end) && memory_end)
memory_end_set = 1;
}

View File

@ -12,74 +12,34 @@
#include <asm/types.h>
#include <asm/cio.h>
#include <asm/setup.h>
#include <uapi/asm/ipl.h>
#define NSS_NAME_SIZE 8
struct ipl_parameter_block {
struct ipl_pl_hdr hdr;
union {
struct ipl_pb_hdr pb0_hdr;
struct ipl_pb0_common common;
struct ipl_pb0_fcp fcp;
struct ipl_pb0_ccw ccw;
char raw[PAGE_SIZE - sizeof(struct ipl_pl_hdr)];
};
} __packed __aligned(PAGE_SIZE);
#define IPL_PARM_BLK_FCP_LEN (sizeof(struct ipl_list_hdr) + \
sizeof(struct ipl_block_fcp))
#define NSS_NAME_SIZE 8
#define IPL_PARM_BLK0_FCP_LEN (sizeof(struct ipl_block_fcp) + 16)
#define IPL_PARM_BLK_CCW_LEN (sizeof(struct ipl_list_hdr) + \
sizeof(struct ipl_block_ccw))
#define IPL_PARM_BLK0_CCW_LEN (sizeof(struct ipl_block_ccw) + 16)
#define IPL_BP_FCP_LEN (sizeof(struct ipl_pl_hdr) + \
sizeof(struct ipl_pb0_fcp))
#define IPL_BP0_FCP_LEN (sizeof(struct ipl_pb0_fcp))
#define IPL_BP_CCW_LEN (sizeof(struct ipl_pl_hdr) + \
sizeof(struct ipl_pb0_ccw))
#define IPL_BP0_CCW_LEN (sizeof(struct ipl_pb0_ccw))
#define IPL_MAX_SUPPORTED_VERSION (0)
struct ipl_list_hdr {
u32 len;
u8 reserved1[3];
u8 version;
u32 blk0_len;
u8 pbt;
u8 flags;
u16 reserved2;
u8 loadparm[8];
} __attribute__((packed));
struct ipl_block_fcp {
u8 reserved1[305-1];
u8 opt;
u8 reserved2[3];
u16 reserved3;
u16 devno;
u8 reserved4[4];
u64 wwpn;
u64 lun;
u32 bootprog;
u8 reserved5[12];
u64 br_lba;
u32 scp_data_len;
u8 reserved6[260];
u8 scp_data[];
} __attribute__((packed));
#define DIAG308_VMPARM_SIZE 64
#define DIAG308_SCPDATA_SIZE (PAGE_SIZE - (sizeof(struct ipl_list_hdr) + \
offsetof(struct ipl_block_fcp, scp_data)))
struct ipl_block_ccw {
u8 reserved1[84];
u16 reserved2 : 13;
u8 ssid : 3;
u16 devno;
u8 vm_flags;
u8 reserved3[3];
u32 vm_parm_len;
u8 nss_name[8];
u8 vm_parm[DIAG308_VMPARM_SIZE];
u8 reserved4[8];
} __attribute__((packed));
struct ipl_parameter_block {
struct ipl_list_hdr hdr;
union {
struct ipl_block_fcp fcp;
struct ipl_block_ccw ccw;
char raw[PAGE_SIZE - sizeof(struct ipl_list_hdr)];
};
} __packed __aligned(PAGE_SIZE);
#define DIAG308_VMPARM_SIZE (64)
#define DIAG308_SCPDATA_OFFSET offsetof(struct ipl_parameter_block, \
fcp.scp_data)
#define DIAG308_SCPDATA_SIZE (PAGE_SIZE - DIAG308_SCPDATA_OFFSET)
struct save_area;
struct save_area * __init save_area_alloc(bool is_boot_cpu);
@ -132,25 +92,6 @@ enum diag308_subcode {
DIAG308_STORE = 6,
};
enum diag308_ipl_type {
DIAG308_IPL_TYPE_FCP = 0,
DIAG308_IPL_TYPE_CCW = 2,
};
enum diag308_opt {
DIAG308_IPL_OPT_IPL = 0x10,
DIAG308_IPL_OPT_DUMP = 0x20,
};
enum diag308_flags {
DIAG308_FLAGS_LP_VALID = 0x80,
};
enum diag308_vm_flags {
DIAG308_VM_FLAGS_NSS_VALID = 0x80,
DIAG308_VM_FLAGS_VP_VALID = 0x40,
};
enum diag308_rc {
DIAG308_RC_OK = 0x0001,
DIAG308_RC_NOCONFIG = 0x0102,

View File

@ -0,0 +1,94 @@
/* SPDX-License-Identifier: GPL-2.0 */
#ifndef _ASM_S390_UAPI_IPL_H
#define _ASM_S390_UAPI_IPL_H
#include <linux/types.h>
/* IPL Parameter List header */
struct ipl_pl_hdr {
__u32 len;
__u8 reserved1[3];
__u8 version;
} __packed;
/* IPL Parameter Block header */
struct ipl_pb_hdr {
__u32 len;
__u8 pbt;
} __packed;
/* IPL Parameter Block types */
enum ipl_pbt {
IPL_PBT_FCP = 0,
IPL_PBT_SCP_DATA = 1,
IPL_PBT_CCW = 2,
};
/* IPL Parameter Block 0 with common fields */
struct ipl_pb0_common {
__u32 len;
__u8 pbt;
__u8 flags;
__u8 reserved1[2];
__u8 loadparm[8];
__u8 reserved2[84];
} __packed;
#define IPL_PB0_FLAG_LOADPARM 0x80
/* IPL Parameter Block 0 for FCP */
struct ipl_pb0_fcp {
__u32 len;
__u8 pbt;
__u8 reserved1[3];
__u8 loadparm[8];
__u8 reserved2[304];
__u8 opt;
__u8 reserved3[3];
__u8 cssid;
__u8 reserved4[1];
__u16 devno;
__u8 reserved5[4];
__u64 wwpn;
__u64 lun;
__u32 bootprog;
__u8 reserved6[12];
__u64 br_lba;
__u32 scp_data_len;
__u8 reserved7[260];
__u8 scp_data[];
} __packed;
#define IPL_PB0_FCP_OPT_IPL 0x10
#define IPL_PB0_FCP_OPT_DUMP 0x20
/* IPL Parameter Block 0 for CCW */
struct ipl_pb0_ccw {
__u32 len;
__u8 pbt;
__u8 flags;
__u8 reserved1[2];
__u8 loadparm[8];
__u8 reserved2[84];
__u16 reserved3 : 13;
__u8 ssid : 3;
__u16 devno;
__u8 vm_flags;
__u8 reserved4[3];
__u32 vm_parm_len;
__u8 nss_name[8];
__u8 vm_parm[64];
__u8 reserved5[8];
} __packed;
#define IPL_PB0_CCW_VM_FLAG_NSS 0x80
#define IPL_PB0_CCW_VM_FLAG_VP 0x40
/* IPL Parameter Block 1 for additional SCP data */
struct ipl_pb1_scp_data {
__u32 len;
__u8 pbt;
__u8 scp_data[];
} __packed;
#endif

View File

@ -244,11 +244,11 @@ static __init enum ipl_type get_ipl_type(void)
if (!ipl_block_valid)
return IPL_TYPE_UNKNOWN;
switch (ipl_block.hdr.pbt) {
case DIAG308_IPL_TYPE_CCW:
switch (ipl_block.pb0_hdr.pbt) {
case IPL_PBT_CCW:
return IPL_TYPE_CCW;
case DIAG308_IPL_TYPE_FCP:
if (ipl_block.fcp.opt == DIAG308_IPL_OPT_DUMP)
case IPL_PBT_FCP:
if (ipl_block.fcp.opt == IPL_PB0_FCP_OPT_DUMP)
return IPL_TYPE_FCP_DUMP;
else
return IPL_TYPE_FCP;
@ -272,7 +272,7 @@ static ssize_t ipl_vm_parm_show(struct kobject *kobj,
{
char parm[DIAG308_VMPARM_SIZE + 1] = {};
if (ipl_block_valid && (ipl_block.hdr.pbt == DIAG308_IPL_TYPE_CCW))
if (ipl_block_valid && (ipl_block.pb0_hdr.pbt == IPL_PBT_CCW))
ipl_block_get_ascii_vmparm(parm, sizeof(parm), &ipl_block);
return sprintf(page, "%s\n", parm);
}
@ -495,11 +495,11 @@ static ssize_t reipl_generic_vmparm_store(struct ipl_parameter_block *ipb,
memset(ipb->ccw.vm_parm, 0, DIAG308_VMPARM_SIZE);
ipb->ccw.vm_parm_len = ip_len;
if (ip_len > 0) {
ipb->ccw.vm_flags |= DIAG308_VM_FLAGS_VP_VALID;
ipb->ccw.vm_flags |= IPL_PB0_CCW_VM_FLAG_VP;
memcpy(ipb->ccw.vm_parm, buf, ip_len);
ASCEBC(ipb->ccw.vm_parm, ip_len);
} else {
ipb->ccw.vm_flags &= ~DIAG308_VM_FLAGS_VP_VALID;
ipb->ccw.vm_flags &= ~IPL_PB0_CCW_VM_FLAG_VP;
}
return len;
@ -571,9 +571,9 @@ static ssize_t reipl_fcp_scpdata_write(struct file *filp, struct kobject *kobj,
scpdata_len += padding;
}
reipl_block_fcp->hdr.len = IPL_BP_FCP_LEN + scpdata_len;
reipl_block_fcp->fcp.len = IPL_BP0_FCP_LEN + scpdata_len;
reipl_block_fcp->fcp.scp_data_len = scpdata_len;
reipl_block_fcp->hdr.len = IPL_PARM_BLK_FCP_LEN + scpdata_len;
reipl_block_fcp->hdr.blk0_len = IPL_PARM_BLK0_FCP_LEN + scpdata_len;
return count;
}
@ -600,7 +600,7 @@ DEFINE_IPL_ATTR_RW(reipl_fcp, device, "0.0.%04llx\n", "0.0.%llx\n",
static void reipl_get_ascii_loadparm(char *loadparm,
struct ipl_parameter_block *ibp)
{
memcpy(loadparm, ibp->hdr.loadparm, LOADPARM_LEN);
memcpy(loadparm, ibp->common.loadparm, LOADPARM_LEN);
EBCASC(loadparm, LOADPARM_LEN);
loadparm[LOADPARM_LEN] = 0;
strim(loadparm);
@ -635,11 +635,11 @@ static ssize_t reipl_generic_loadparm_store(struct ipl_parameter_block *ipb,
return -EINVAL;
}
/* initialize loadparm with blanks */
memset(ipb->hdr.loadparm, ' ', LOADPARM_LEN);
memset(ipb->common.loadparm, ' ', LOADPARM_LEN);
/* copy and convert to ebcdic */
memcpy(ipb->hdr.loadparm, buf, lp_len);
ASCEBC(ipb->hdr.loadparm, LOADPARM_LEN);
ipb->hdr.flags |= DIAG308_FLAGS_LP_VALID;
memcpy(ipb->common.loadparm, buf, lp_len);
ASCEBC(ipb->common.loadparm, LOADPARM_LEN);
ipb->common.flags |= IPL_PB0_FLAG_LOADPARM;
return len;
}
@ -769,14 +769,12 @@ static ssize_t reipl_nss_name_store(struct kobject *kobj,
memset(reipl_block_nss->ccw.nss_name, 0x40, NSS_NAME_SIZE);
if (nss_len > 0) {
reipl_block_nss->ccw.vm_flags |=
DIAG308_VM_FLAGS_NSS_VALID;
reipl_block_nss->ccw.vm_flags |= IPL_PB0_CCW_VM_FLAG_NSS;
memcpy(reipl_block_nss->ccw.nss_name, buf, nss_len);
ASCEBC(reipl_block_nss->ccw.nss_name, nss_len);
EBC_TOUPPER(reipl_block_nss->ccw.nss_name, nss_len);
} else {
reipl_block_nss->ccw.vm_flags &=
~DIAG308_VM_FLAGS_NSS_VALID;
reipl_block_nss->ccw.vm_flags &= ~IPL_PB0_CCW_VM_FLAG_NSS;
}
return len;
@ -896,10 +894,10 @@ static void reipl_run(struct shutdown_trigger *trigger)
static void reipl_block_ccw_init(struct ipl_parameter_block *ipb)
{
ipb->hdr.len = IPL_PARM_BLK_CCW_LEN;
ipb->hdr.len = IPL_BP_CCW_LEN;
ipb->hdr.version = IPL_PARM_BLOCK_VERSION;
ipb->hdr.blk0_len = IPL_PARM_BLK0_CCW_LEN;
ipb->hdr.pbt = DIAG308_IPL_TYPE_CCW;
ipb->pb0_hdr.len = IPL_BP0_CCW_LEN;
ipb->pb0_hdr.pbt = IPL_PBT_CCW;
}
static void reipl_block_ccw_fill_parms(struct ipl_parameter_block *ipb)
@ -907,17 +905,17 @@ static void reipl_block_ccw_fill_parms(struct ipl_parameter_block *ipb)
/* LOADPARM */
/* check if read scp info worked and set loadparm */
if (sclp_ipl_info.is_valid)
memcpy(ipb->hdr.loadparm, &sclp_ipl_info.loadparm, LOADPARM_LEN);
memcpy(ipb->ccw.loadparm, &sclp_ipl_info.loadparm, LOADPARM_LEN);
else
/* read scp info failed: set empty loadparm (EBCDIC blanks) */
memset(ipb->hdr.loadparm, 0x40, LOADPARM_LEN);
ipb->hdr.flags = DIAG308_FLAGS_LP_VALID;
memset(ipb->ccw.loadparm, 0x40, LOADPARM_LEN);
ipb->ccw.flags = IPL_PB0_FLAG_LOADPARM;
/* VM PARM */
if (MACHINE_IS_VM && ipl_block_valid &&
(ipl_block.ccw.vm_flags & DIAG308_VM_FLAGS_VP_VALID)) {
(ipl_block.ccw.vm_flags & IPL_PB0_CCW_VM_FLAG_VP)) {
ipb->ccw.vm_flags |= DIAG308_VM_FLAGS_VP_VALID;
ipb->ccw.vm_flags |= IPL_PB0_CCW_VM_FLAG_VP;
ipb->ccw.vm_parm_len = ipl_block.ccw.vm_parm_len;
memcpy(ipb->ccw.vm_parm,
ipl_block.ccw.vm_parm, DIAG308_VMPARM_SIZE);
@ -999,14 +997,14 @@ static int __init reipl_fcp_init(void)
* is invalid in the SCSI IPL parameter block, so take it
* always from sclp_ipl_info.
*/
memcpy(reipl_block_fcp->hdr.loadparm, sclp_ipl_info.loadparm,
memcpy(reipl_block_fcp->fcp.loadparm, sclp_ipl_info.loadparm,
LOADPARM_LEN);
} else {
reipl_block_fcp->hdr.len = IPL_PARM_BLK_FCP_LEN;
reipl_block_fcp->hdr.len = IPL_BP_FCP_LEN;
reipl_block_fcp->hdr.version = IPL_PARM_BLOCK_VERSION;
reipl_block_fcp->hdr.blk0_len = IPL_PARM_BLK0_FCP_LEN;
reipl_block_fcp->hdr.pbt = DIAG308_IPL_TYPE_FCP;
reipl_block_fcp->fcp.opt = DIAG308_IPL_OPT_IPL;
reipl_block_fcp->fcp.len = IPL_BP0_FCP_LEN;
reipl_block_fcp->fcp.pbt = IPL_PBT_FCP;
reipl_block_fcp->fcp.opt = IPL_PB0_FCP_OPT_IPL;
}
reipl_capabilities |= IPL_TYPE_FCP;
return 0;
@ -1024,10 +1022,10 @@ static int __init reipl_type_init(void)
/*
* If we have an OS info reipl block, this will be used
*/
if (reipl_block->hdr.pbt == DIAG308_IPL_TYPE_FCP) {
if (reipl_block->pb0_hdr.pbt == IPL_PBT_FCP) {
memcpy(reipl_block_fcp, reipl_block, size);
reipl_type = IPL_TYPE_FCP;
} else if (reipl_block->hdr.pbt == DIAG308_IPL_TYPE_CCW) {
} else if (reipl_block->pb0_hdr.pbt == IPL_PBT_CCW) {
memcpy(reipl_block_ccw, reipl_block, size);
reipl_type = IPL_TYPE_CCW;
}
@ -1191,10 +1189,10 @@ static int __init dump_ccw_init(void)
free_page((unsigned long)dump_block_ccw);
return rc;
}
dump_block_ccw->hdr.len = IPL_PARM_BLK_CCW_LEN;
dump_block_ccw->hdr.len = IPL_BP_CCW_LEN;
dump_block_ccw->hdr.version = IPL_PARM_BLOCK_VERSION;
dump_block_ccw->hdr.blk0_len = IPL_PARM_BLK0_CCW_LEN;
dump_block_ccw->hdr.pbt = DIAG308_IPL_TYPE_CCW;
dump_block_ccw->ccw.len = IPL_BP0_CCW_LEN;
dump_block_ccw->ccw.pbt = IPL_PBT_CCW;
dump_capabilities |= DUMP_TYPE_CCW;
return 0;
}
@ -1213,11 +1211,11 @@ static int __init dump_fcp_init(void)
free_page((unsigned long)dump_block_fcp);
return rc;
}
dump_block_fcp->hdr.len = IPL_PARM_BLK_FCP_LEN;
dump_block_fcp->hdr.len = IPL_BP_FCP_LEN;
dump_block_fcp->hdr.version = IPL_PARM_BLOCK_VERSION;
dump_block_fcp->hdr.blk0_len = IPL_PARM_BLK0_FCP_LEN;
dump_block_fcp->hdr.pbt = DIAG308_IPL_TYPE_FCP;
dump_block_fcp->fcp.opt = DIAG308_IPL_OPT_DUMP;
dump_block_fcp->fcp.len = IPL_BP0_FCP_LEN;
dump_block_fcp->fcp.pbt = IPL_PBT_FCP;
dump_block_fcp->fcp.opt = IPL_PB0_FCP_OPT_DUMP;
dump_capabilities |= DUMP_TYPE_FCP;
return 0;
}
@ -1576,7 +1574,7 @@ static int __init s390_ipl_init(void)
* READ SCP info provides the correct value.
*/
if (memcmp(sclp_ipl_info.loadparm, str, sizeof(str)) == 0 && ipl_block_valid)
memcpy(sclp_ipl_info.loadparm, ipl_block.hdr.loadparm, LOADPARM_LEN);
memcpy(sclp_ipl_info.loadparm, ipl_block.ccw.loadparm, LOADPARM_LEN);
shutdown_actions_init();
shutdown_triggers_init();
return 0;

View File

@ -11,7 +11,7 @@ size_t ipl_block_get_ascii_vmparm(char *dest, size_t size,
char has_lowercase = 0;
len = 0;
if ((ipb->ccw.vm_flags & DIAG308_VM_FLAGS_VP_VALID) &&
if ((ipb->ccw.vm_flags & IPL_PB0_CCW_VM_FLAG_VP) &&
(ipb->ccw.vm_parm_len > 0)) {
len = min_t(size_t, size - 1, ipb->ccw.vm_parm_len);