qemu-devel.nongnu.org archive mirror
 help / color / mirror / Atom feed
From: Jens Freimann <jfrei@linux.vnet.ibm.com>
To: Christian Borntraeger <borntraeger@de.ibm.com>,
	Alexander Graf <agraf@suse.de>,
	Cornelia Huck <cornelia.huck@de.ibm.com>
Cc: "Eugene (jno) Dvurechenski" <jno@linux.vnet.ibm.com>,
	Jens Freimann <jfrei@linux.vnet.ibm.com>,
	qemu-devel@nongnu.org
Subject: [Qemu-devel] [PATCH 08/10] pc-bios/s390-ccw: IPL from CDL-formatted ECKD DASD
Date: Thu, 26 Jun 2014 16:30:07 +0200	[thread overview]
Message-ID: <1403793009-54176-9-git-send-email-jfrei@linux.vnet.ibm.com> (raw)
In-Reply-To: <1403793009-54176-1-git-send-email-jfrei@linux.vnet.ibm.com>

From: "Eugene (jno) Dvurechenski" <jno@linux.vnet.ibm.com>

Add code that allows us to start from ECKD DASD using the z/OS
compatible disk layout (CDL), which is the most common format for ECKD
DASD.

Signed-off-by: Eugene (jno) Dvurechenski <jno@linux.vnet.ibm.com>
Signed-off-by: Jens Freimann <jfrei@linux.vnet.ibm.com>
---
 pc-bios/s390-ccw/bootmap.c | 168 +++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 168 insertions(+)

diff --git a/pc-bios/s390-ccw/bootmap.c b/pc-bios/s390-ccw/bootmap.c
index 992c9aa..6f73ffc 100644
--- a/pc-bios/s390-ccw/bootmap.c
+++ b/pc-bios/s390-ccw/bootmap.c
@@ -74,6 +74,171 @@ static void jump_to_IPL_code(uint64_t address)
 }
 
 /***********************************************************************
+ * IPL an ECKD DASD (CDL or LDL/CMS format)
+ */
+
+static unsigned char _bprs[8*1024]; /* guessed "max" ECKD sector size */
+const int max_bprs_entries = sizeof(_bprs) / sizeof(ExtEckdBlockPtr);
+
+static bool eckd_valid_address(BootMapPointer *p)
+{
+    const uint64_t cylinder = p->eckd.cylinder
+                            + ((p->eckd.head & 0xfff0) << 12);
+    const uint64_t head = p->eckd.head & 0x000f;
+
+    if (head >= virtio_get_heads()
+        ||  p->eckd.sector > virtio_get_sectors()
+        ||  p->eckd.sector <= 0) {
+        return false;
+    }
+
+    if (!virtio_guessed_disk_nature() && cylinder >= virtio_get_cylinders()) {
+        return false;
+    }
+
+    return true;
+}
+
+static block_number_t eckd_block_num(BootMapPointer *p)
+{
+    const uint64_t sectors = virtio_get_sectors();
+    const uint64_t heads = virtio_get_heads();
+    const uint64_t cylinder = p->eckd.cylinder
+                            + ((p->eckd.head & 0xfff0) << 12);
+    const uint64_t head = p->eckd.head & 0x000f;
+    const block_number_t block = sectors * heads * cylinder
+                               + sectors * head
+                               + p->eckd.sector
+                               - 1; /* block nr starts with zero */
+    return block;
+}
+
+static block_number_t load_eckd_segments(block_number_t blk, uint64_t *address)
+{
+    block_number_t block_nr;
+    int j, rc;
+    BootMapPointer *bprs = (void *)_bprs;
+    bool more_data;
+
+    memset(_bprs, FREE_SPACE_FILLER, sizeof(_bprs));
+    read_block(blk, bprs, "BPRS read failed");
+
+    do {
+        more_data = false;
+        for (j = 0;; j++) {
+            block_nr = eckd_block_num((void *)&(bprs[j].xeckd));
+            if (is_null_block_number(block_nr)) { /* end of chunk */
+                break;
+            }
+
+            /* we need the updated blockno for the next indirect entry
+             * in the chain, but don't want to advance address
+             */
+            if (j == (max_bprs_entries - 1)) {
+                break;
+            }
+
+            IPL_assert(block_size_ok(bprs[j].xeckd.bptr.size),
+                       "bad chunk block size");
+            IPL_assert(eckd_valid_address(&bprs[j]), "bad chunk ECKD addr");
+
+            if ((bprs[j].xeckd.bptr.count == 0) && unused_space(&(bprs[j+1]),
+                sizeof(EckdBlockPtr))) {
+                /* This is a "continue" pointer.
+                 * This ptr should be the last one in the current
+                 * script section.
+                 * I.e. the next ptr must point to the unused memory area
+                 */
+                memset(_bprs, FREE_SPACE_FILLER, sizeof(_bprs));
+                read_block(block_nr, bprs, "BPRS continuation read failed");
+                more_data = true;
+                break;
+            }
+
+            /* Load (count+1) blocks of code at (block_nr)
+             * to memory (address).
+             */
+            rc = virtio_read_many(block_nr, (void *)(*address),
+                                  bprs[j].xeckd.bptr.count+1);
+            IPL_assert(rc == 0, "code chunk read failed");
+
+            *address += (bprs[j].xeckd.bptr.count+1) * virtio_get_block_size();
+        }
+    } while (more_data);
+    return block_nr;
+}
+
+static void run_eckd_boot_script(block_number_t mbr_block_nr)
+{
+    int i;
+    block_number_t block_nr;
+    uint64_t address;
+    ScsiMbr *scsi_mbr = (void *)sec;
+    BootMapScript *bms = (void *)sec;
+
+    memset(sec, FREE_SPACE_FILLER, sizeof(sec));
+    read_block(mbr_block_nr, sec, "Cannot read MBR");
+
+    block_nr = eckd_block_num((void *)&(scsi_mbr->blockptr));
+
+    memset(sec, FREE_SPACE_FILLER, sizeof(sec));
+    read_block(block_nr, sec, "Cannot read Boot Map Script");
+
+    for (i = 0; bms->entry[i].type == BOOT_SCRIPT_LOAD; i++) {
+        address = bms->entry[i].address.load_address;
+        block_nr = eckd_block_num(&(bms->entry[i].blkptr));
+
+        do {
+            block_nr = load_eckd_segments(block_nr, &address);
+        } while (block_nr != -1);
+    }
+
+    IPL_assert(bms->entry[i].type == BOOT_SCRIPT_EXEC,
+               "Unknown script entry type");
+    jump_to_IPL_code(bms->entry[i].address.load_address); /* no return */
+}
+
+static void ipl_eckd(void)
+{
+    XEckdMbr *mbr;
+    Ipl2 *ipl2 = (void *)sec;
+    IplVolumeLabel *vlbl = (void *)sec;
+    block_number_t block_nr;
+
+    sclp_print("Using ECKD scheme.\n");
+    if (virtio_guessed_disk_nature()) {
+        sclp_print("Using guessed DASD geometry.\n");
+        virtio_assume_eckd();
+    }
+    /* we have just read the block #0 and recognized it as "IPL1" */
+
+    memset(sec, FREE_SPACE_FILLER, sizeof(sec));
+    read_block(1, ipl2, "Cannot read IPL2 record at block 1");
+    IPL_assert(magic_match(ipl2, IPL2_MAGIC), "No IPL2 record");
+
+    mbr = &ipl2->u.x.mbr;
+    IPL_assert(magic_match(mbr, ZIPL_MAGIC), "No zIPL section in IPL2 record.");
+    IPL_assert(block_size_ok(mbr->blockptr.xeckd.bptr.size),
+               "Bad block size in zIPL section of IPL2 record.");
+    IPL_assert(mbr->dev_type == DEV_TYPE_ECKD,
+               "Non-ECKD device type in zIPL section of IPL2 record.");
+
+    /* save pointer to Boot Script */
+    block_nr = eckd_block_num((void *)&(mbr->blockptr));
+
+    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),
+               "Invalid magic of volume label block");
+    IPL_assert(magic_match(vlbl->f.key, VOL1_MAGIC),
+               "Invalid magic of volser block");
+    print_volser(vlbl->f.volser);
+
+    run_eckd_boot_script(block_nr);
+    /* no return */
+}
+
+/***********************************************************************
  * IPL a SCSI disk
  */
 
@@ -219,6 +384,9 @@ void zipl_load(void)
     if (magic_match(mbr->magic, ZIPL_MAGIC)) {
         ipl_scsi(); /* no return */
     }
+    if (magic_match(mbr->magic, IPL1_MAGIC)) {
+        ipl_eckd(); /* CDL ECKD; no return */
+    }
 
     virtio_panic("\n* invalid MBR magic *\n");
 }
-- 
1.8.5.5

  parent reply	other threads:[~2014-06-26 14:30 UTC|newest]

Thread overview: 19+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2014-06-26 14:29 [Qemu-devel] [PATCH 00/10] pc-bios/s390-ccw: Add DASD IPL support Jens Freimann
2014-06-26 14:30 ` [Qemu-devel] [PATCH 01/10] pc-bios/s390-ccw: make checkpatch happy Jens Freimann
2014-06-26 14:30 ` [Qemu-devel] [PATCH 02/10] pc-bios/s390-ccw: cleanup and enhance bootmap defintions Jens Freimann
2014-06-26 14:30 ` [Qemu-devel] [PATCH 03/10] pc-bios/s390-ccw: handle different sector sizes Jens Freimann
2014-06-26 14:35   ` Alexander Graf
2014-06-26 15:08     ` Eugene "jno" Dvurechenski
2014-06-26 15:10       ` Alexander Graf
2014-06-26 14:30 ` [Qemu-devel] [PATCH 04/10] pc-bios/s390-ccw: add some utility code Jens Freimann
2014-06-26 14:30 ` [Qemu-devel] [PATCH 05/10] pc-bios/s390-ccw: Unify error handling Jens Freimann
2014-06-26 14:30 ` [Qemu-devel] [PATCH 06/10] pc-bios/s390-ccw: Add fill_hex_val func to provide better msgs Jens Freimann
2014-06-26 14:30 ` [Qemu-devel] [PATCH 07/10] pc-bios/s390-ccw: factor out ipl code Jens Freimann
2014-06-26 14:30 ` Jens Freimann [this message]
2014-06-26 14:30 ` [Qemu-devel] [PATCH 09/10] pc-bios/s390-ccw: IPL from LDL/CMS-formatted ECKD DASD Jens Freimann
2014-06-26 14:30 ` [Qemu-devel] [PATCH 10/10] pc-bios/s390-ccw: update binary Jens Freimann
2014-06-26 14:42 ` [Qemu-devel] [PATCH 00/10] pc-bios/s390-ccw: Add DASD IPL support Alexander Graf
2014-06-27  7:53   ` Christian Borntraeger
2014-06-27  9:05     ` Alexander Graf
2014-06-27  9:27       ` Christian Borntraeger
2014-06-27  9:47         ` Cornelia Huck

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=1403793009-54176-9-git-send-email-jfrei@linux.vnet.ibm.com \
    --to=jfrei@linux.vnet.ibm.com \
    --cc=agraf@suse.de \
    --cc=borntraeger@de.ibm.com \
    --cc=cornelia.huck@de.ibm.com \
    --cc=jno@linux.vnet.ibm.com \
    --cc=qemu-devel@nongnu.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).