From patchwork Fri Feb 16 22:07:55 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: "Collin L. Walling" X-Patchwork-Id: 10225843 Return-Path: Received: from mail.wl.linuxfoundation.org (pdx-wl-mail.web.codeaurora.org [172.30.200.125]) by pdx-korg-patchwork.web.codeaurora.org (Postfix) with ESMTP id 36874603EE for ; Fri, 16 Feb 2018 22:21:35 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 1A3DD28450 for ; Fri, 16 Feb 2018 22:21:35 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id 0F2B629660; Fri, 16 Feb 2018 22:21:35 +0000 (UTC) X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on pdx-wl-mail.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-6.9 required=2.0 tests=BAYES_00,RCVD_IN_DNSWL_HI autolearn=ham version=3.3.1 Received: from lists.gnu.org (lists.gnu.org [208.118.235.17]) (using TLSv1 with cipher AES256-SHA (256/256 bits)) (No client certificate requested) by mail.wl.linuxfoundation.org (Postfix) with ESMTPS id 5815E28450 for ; Fri, 16 Feb 2018 22:21:34 +0000 (UTC) Received: from localhost ([::1]:38709 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1emoNp-0001WZ-EM for patchwork-qemu-devel@patchwork.kernel.org; Fri, 16 Feb 2018 17:21:33 -0500 Received: from eggs.gnu.org ([2001:4830:134:3::10]:43489) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1emoB4-00071S-3k for qemu-devel@nongnu.org; Fri, 16 Feb 2018 17:08:25 -0500 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1emoAz-0005QS-2J for qemu-devel@nongnu.org; Fri, 16 Feb 2018 17:08:22 -0500 Received: from mx0a-001b2d01.pphosted.com ([148.163.156.1]:47686) by eggs.gnu.org with esmtps (TLS1.0:RSA_AES_256_CBC_SHA1:32) (Exim 4.71) (envelope-from ) id 1emoAy-0005Pp-Px for qemu-devel@nongnu.org; Fri, 16 Feb 2018 17:08:16 -0500 Received: from pps.filterd (m0098394.ppops.net [127.0.0.1]) by mx0a-001b2d01.pphosted.com (8.16.0.22/8.16.0.22) with SMTP id w1GM83fc058701 for ; Fri, 16 Feb 2018 17:08:15 -0500 Received: from e13.ny.us.ibm.com (e13.ny.us.ibm.com [129.33.205.203]) by mx0a-001b2d01.pphosted.com with ESMTP id 2g62xgjrqv-1 (version=TLSv1.2 cipher=AES256-SHA bits=256 verify=NOT) for ; Fri, 16 Feb 2018 17:08:14 -0500 Received: from localhost by e13.ny.us.ibm.com with IBM ESMTP SMTP Gateway: Authorized Use Only! Violators will be prosecuted for from ; Fri, 16 Feb 2018 17:08:13 -0500 Received: from b01cxnp22036.gho.pok.ibm.com (9.57.198.26) by e13.ny.us.ibm.com (146.89.104.200) with IBM ESMTP SMTP Gateway: Authorized Use Only! Violators will be prosecuted; Fri, 16 Feb 2018 17:08:10 -0500 Received: from b01ledav006.gho.pok.ibm.com (b01ledav006.gho.pok.ibm.com [9.57.199.111]) by b01cxnp22036.gho.pok.ibm.com (8.14.9/8.14.9/NCO v10.0) with ESMTP id w1GM89ij56819770; Fri, 16 Feb 2018 22:08:09 GMT Received: from b01ledav006.gho.pok.ibm.com (unknown [127.0.0.1]) by IMSVA (Postfix) with ESMTP id E418CAC046; Fri, 16 Feb 2018 17:09:17 -0500 (EST) Received: from collin-ThinkPad-W541.pok.ibm.com (unknown [9.56.58.109]) by b01ledav006.gho.pok.ibm.com (Postfix) with ESMTP id CC213AC043; Fri, 16 Feb 2018 17:09:17 -0500 (EST) From: "Collin L. Walling" To: qemu-s390x@nongnu.org, qemu-devel@nongnu.org Date: Fri, 16 Feb 2018 17:07:55 -0500 X-Mailer: git-send-email 2.7.4 In-Reply-To: <1518818879-18608-1-git-send-email-walling@linux.vnet.ibm.com> References: <1518818879-18608-1-git-send-email-walling@linux.vnet.ibm.com> X-TM-AS-GCONF: 00 x-cbid: 18021622-0008-0000-0000-000002D5B4B1 X-IBM-SpamModules-Scores: X-IBM-SpamModules-Versions: BY=3.00008545; HX=3.00000241; KW=3.00000007; PH=3.00000004; SC=3.00000254; SDB=6.00990741; UDB=6.00503179; IPR=6.00770087; MB=3.00019594; MTD=3.00000008; XFM=3.00000015; UTC=2018-02-16 22:08:12 X-IBM-AV-DETECTION: SAVI=unused REMOTE=unused XFE=unused x-cbparentid: 18021622-0009-0000-0000-00003849A1DF Message-Id: <1518818879-18608-9-git-send-email-walling@linux.vnet.ibm.com> X-Proofpoint-Virus-Version: vendor=fsecure engine=2.50.10432:, , definitions=2018-02-16_08:, , signatures=0 X-Proofpoint-Spam-Details: rule=outbound_notspam policy=outbound score=0 priorityscore=1501 malwarescore=0 suspectscore=2 phishscore=0 bulkscore=0 spamscore=0 clxscore=1015 lowpriorityscore=0 impostorscore=0 adultscore=0 classifier=spam adjust=0 reason=mlx scancount=1 engine=8.0.1-1709140000 definitions=main-1802160254 X-detected-operating-system: by eggs.gnu.org: GNU/Linux 3.x [generic] [fuzzy] X-Received-From: 148.163.156.1 Subject: [Qemu-devel] [PATCH v7 08/12] s390-ccw: read stage2 boot loader data to find menu X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.21 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: frankja@linux.vnet.ibm.com, thuth@redhat.com, cohuck@redhat.com, david@redhat.com, alifm@linux.vnet.ibm.com, mihajlov@linux.vnet.ibm.com, borntraeger@de.ibm.com Errors-To: qemu-devel-bounces+patchwork-qemu-devel=patchwork.kernel.org@nongnu.org Sender: "Qemu-devel" X-Virus-Scanned: ClamAV using ClamSMTP 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 Reviewed-by: Thomas Huth --- 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(&s1b->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(&s1b->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(&mbr->blockptr.xeckd.bptr.chs); + /* save pointer to Stage1b Data */ + s1b_block_nr = eckd_block_num(&ipl2->stage1.seek[0].chs); + memset(sec, FREE_SPACE_FILLER, sizeof(sec)); read_block(2, vlbl, "Cannot read Volume Label at block 2"); IPL_assert(magic_match(vlbl->key, VOL1_MAGIC), @@ -249,7 +330,7 @@ static void ipl_eckd_cdl(void) "Invalid magic of volser block"); print_volser(vlbl->f.volser); - run_eckd_boot_script(bmt_block_nr); + run_eckd_boot_script(bmt_block_nr, s1b_block_nr); /* no return */ } @@ -280,7 +361,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; + block_number_t bmt_block_nr, s1b_block_nr; EckdLdlIpl1 *ipl1 = (void *)sec; if (mode != ECKD_LDL_UNLABELED) { @@ -302,7 +383,10 @@ static void ipl_eckd_ldl(ECKD_IPL_mode_t mode) /* save pointer to Boot Map Table */ bmt_block_nr = eckd_block_num(&ipl1->bip.bp.ipl.bm_ptr.eckd.bptr.chs); - run_eckd_boot_script(bmt_block_nr); + /* save pointer to Stage1b Data */ + s1b_block_nr = eckd_block_num(&ipl1->stage1.seek[0].chs); + + run_eckd_boot_script(bmt_block_nr, s1b_block_nr); /* no return */ } diff --git a/pc-bios/s390-ccw/bootmap.h b/pc-bios/s390-ccw/bootmap.h index 4cf7e1e..c636626 100644 --- a/pc-bios/s390-ccw/bootmap.h +++ b/pc-bios/s390-ccw/bootmap.h @@ -87,6 +87,7 @@ typedef struct ScsiMbr { } __attribute__ ((packed)) ScsiMbr; #define ZIPL_MAGIC "zIPL" +#define ZIPL_MAGIC_EBCDIC "\xa9\xc9\xd7\xd3" #define IPL1_MAGIC "\xc9\xd7\xd3\xf1" /* == "IPL1" in EBCDIC */ #define IPL2_MAGIC "\xc9\xd7\xd3\xf2" /* == "IPL2" in EBCDIC */ #define VOL1_MAGIC "\xe5\xd6\xd3\xf1" /* == "VOL1" in EBCDIC */ @@ -249,15 +250,33 @@ typedef struct EckdCdlIpl1 { uint8_t data[24]; } __attribute__((packed)) EckdCdlIpl1; +typedef struct EckdSeekArg { + uint16_t pad; + EckdCHS chs; + uint8_t pad2; +} __attribute__ ((packed)) EckdSeekArg; + +typedef struct EckdStage1b { + uint8_t reserved[32 * STAGE2_BLK_CNT_MAX]; + struct EckdSeekArg seek[STAGE2_BLK_CNT_MAX]; + uint8_t unused[64]; +} __attribute__ ((packed)) EckdStage1b; + +typedef struct EckdStage1 { + uint8_t reserved[72]; + struct EckdSeekArg seek[2]; +} __attribute__ ((packed)) EckdStage1; + typedef struct EckdCdlIpl2 { uint8_t key[4]; /* == "IPL2" */ - uint8_t reserved0[88]; + struct EckdStage1 stage1; XEckdMbr mbr; uint8_t reserved[24]; } __attribute__((packed)) EckdCdlIpl2; typedef struct EckdLdlIpl1 { - uint8_t reserved[112]; + uint8_t reserved[24]; + struct EckdStage1 stage1; BootInfo bip; /* BootInfo is MBR for LDL */ } __attribute__((packed)) EckdLdlIpl1; diff --git a/pc-bios/s390-ccw/menu.c b/pc-bios/s390-ccw/menu.c index 3056cfc..5790e0c 100644 --- a/pc-bios/s390-ccw/menu.c +++ b/pc-bios/s390-ccw/menu.c @@ -14,6 +14,11 @@ static uint8_t flags; static uint64_t timeout; +int menu_get_zipl_boot_index(const void *stage2, int offset) +{ + return 0; /* implemented next patch */ +} + 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 7df4114..c603de3 100644 --- a/pc-bios/s390-ccw/menu.h +++ b/pc-bios/s390-ccw/menu.h @@ -17,6 +17,7 @@ #define BOOT_MENU_FLAG_CMD_OPTS 0x80 #define BOOT_MENU_FLAG_ZIPL_OPTS 0x40 +int menu_get_zipl_boot_index(const void *stage2, int offset); void menu_set_parms(uint8_t boot_menu_flags, uint32_t boot_menu_timeout); bool menu_check_flags(uint8_t check_flags);