diff --git a/genprotimg/src/pv/pv_ipib.c b/genprotimg/src/pv/pv_ipib.c index 152f1d78..60072941 100644 --- a/genprotimg/src/pv/pv_ipib.c +++ b/genprotimg/src/pv/pv_ipib.c @@ -59,7 +59,7 @@ static gint pv_ipib_init(IplParameterBlock *ipib, GSList *comps, ipib_size = MAX(ipl_pl_hdr_size + blk0_len, (uint32_t)PAGE_SIZE); g_assert(pv_ipib_get_size(comps_length) == ipib_size); - pv->pbt = IPL_TYPE_PV; + pv->pbt = IPL_PBT_PV; pv->len = GUINT32_TO_BE(blk0_len); pv->num_comp = GUINT32_TO_BE(comps_length); /* both values will be overwritten during the IPL process by diff --git a/include/boot/ipl.h b/include/boot/ipl.h index 0427420c..c7072cb2 100644 --- a/include/boot/ipl.h +++ b/include/boot/ipl.h @@ -21,10 +21,6 @@ #define IPL_MAX_SUPPORTED_VERSION 0 #define IPL_PARM_BLOCK_VERSION 0x1 -/* IPL Types */ -#define IPL_TYPE_PV 0x5 - - #ifndef __ASSEMBLER__ #include @@ -43,6 +39,16 @@ struct ipl_pb_hdr { uint8_t pbt; } __packed; +/* IPL Parameter Block types */ +enum ipl_pbt { + IPL_PBT_FCP = 0, + IPL_PBT_SCP_DATA = 1, + IPL_PBT_CCW = 2, + IPL_PBT_ECKD = 3, + IPL_PBT_NVME = 4, + IPL_PBT_PV = 5, +}; + /* IPL Parameter Block 0 with common fields */ struct ipl_pb0_common { uint32_t len; diff --git a/zipl/boot/stage2dump.c b/zipl/boot/stage2dump.c index 2815c01a..6b1082e4 100644 --- a/zipl/boot/stage2dump.c +++ b/zipl/boot/stage2dump.c @@ -17,6 +17,8 @@ #include "libc.h" #include "sclp.h" #include "stage2dump.h" +#include "boot/ipl.h" +#include "boot/os_info.h" #define CPU_ADDRESS_MAX 1000 #define MACHINE_HAS_VX machine_has_vx @@ -26,14 +28,6 @@ */ static uint8_t machine_has_vx; -/* - * IPL info in lowcore - */ -struct ipib_info { - unsigned long ipib; - uint32_t ipib_csum; -}; - /* * Tail parameters */ @@ -395,17 +389,41 @@ static void store_status(void) */ static __noreturn void dump_exit(unsigned long code) { - struct ipib_info *ipib_info = (struct ipib_info *)&S390_lowcore.ipib; - uint32_t ipib_len, csum; + struct ipl_parameter_block *ipib = (struct ipl_parameter_block *)S390_lowcore.ipib; + const struct os_info *os_info = (struct os_info *)S390_lowcore.os_info; + const struct os_info_entry *os_info_entry = NULL; + unsigned long os_info_flags = 0; + uint32_t csum; - if (!ipib_info->ipib) + if (!ipib) libc_stop(code); - ipib_len = *((uint32_t *) ipib_info->ipib); - csum = csum_partial((void *) ipib_info->ipib, ipib_len, 0); - if (ipib_info->ipib_csum != csum) + csum = csum_partial(ipib, ipib->hdr.len, 0); + /* Verify ipib checksum against the value stored in lowcore */ + if (csum != S390_lowcore.ipib_checksum) libc_stop(code); - diag308(DIAG308_SET, (void *) ipib_info->ipib); - diag308(DIAG308_LOAD_CLEAR, NULL); + diag308(DIAG308_SET, ipib); + /* + * Check os_info flags entry for REIPL_CLEAR flag and make + * diag308 call with a proper subcode. + * Verify the bit flags field size before accessing it. + */ + if (os_info_check(os_info) == 0) { + os_info_entry = &os_info->entry[OS_INFO_FLAGS_ENTRY]; + if (os_info_entry_is_valid(os_info_entry) && + os_info_entry->size >= OS_INFO_FLAGS_ENTRY_SIZE) + os_info_flags = *((unsigned long *)os_info_entry->addr); + else + printf("Warning: os_info flags entry is missing or corrupted"); + } else { + printf("Warning: os_info is missing or corrupted"); + } + if (os_info_flags & OS_INFO_FLAG_REIPL_CLEAR) + diag308(DIAG308_LOAD_CLEAR, NULL); + /* Use special diag308 subcode for CCW normal ipl */ + if (ipib->pb0_hdr.pbt == IPL_PBT_CCW) + diag308(DIAG308_LOAD_NORMAL_DUMP, NULL); + else + diag308(DIAG308_LOAD_NORMAL, NULL); __builtin_unreachable(); }