From: Alexander Graf <agraf@suse.de>
To: qemu-devel@nongnu.org
Cc: Carsten Otte <cotte@de.ibm.com>, Aurelien Jarno <aurelien@aurel32.net>
Subject: [Qemu-devel] [PATCH 12/13] Add zipl bootloader interpreter
Date: Tue, 24 Nov 2009 18:29:40 +0100 [thread overview]
Message-ID: <1259083781-14642-13-git-send-email-agraf@suse.de> (raw)
In-Reply-To: <1259083781-14642-1-git-send-email-agraf@suse.de>
The default bootloader on S390 is zipl. Because we don't emulate normal S390
hardware we need to write our own parser for the bootloader configuration,
so we can boot off real hard disks.
This patch adds a pretty simple implementation of such an interpreter. It only
supports 512 bytes sector sizes, always boots the default entry and doesn't
work with reboots yet. But it's better than nothing.
Signed-off-by: Alexander Graf <agraf@suse.de>
---
Makefile.target | 2 +-
hw/s390-virtio.c | 11 ++-
hw/s390-zipl.c | 233 ++++++++++++++++++++++++++++++++++++++++++++++++++++
target-s390x/cpu.h | 1 +
4 files changed, 243 insertions(+), 4 deletions(-)
create mode 100644 hw/s390-zipl.c
diff --git a/Makefile.target b/Makefile.target
index d47d879..e147e09 100644
--- a/Makefile.target
+++ b/Makefile.target
@@ -297,7 +297,7 @@ obj-sh4-y += ide/core.o ide/mmio.o
obj-m68k-y = an5206.o mcf5206.o mcf_uart.o mcf_intc.o mcf5208.o mcf_fec.o
obj-m68k-y += m68k-semi.o dummy_m68k.o
-obj-s390x-y = s390-virtio-bus.o s390-virtio.o
+obj-s390x-y = s390-virtio-bus.o s390-virtio.o s390-zipl.o
main.o vl.o: QEMU_CFLAGS+=$(GPROF_CFLAGS)
diff --git a/hw/s390-virtio.c b/hw/s390-virtio.c
index c843e0d..a008c45 100644
--- a/hw/s390-virtio.c
+++ b/hw/s390-virtio.c
@@ -29,6 +29,7 @@
#include "hw/virtio-console.h"
#include "hw/sysbus.h"
#include "kvm.h"
+#include "s390-zipl.h"
#include "hw/s390-virtio-bus.h"
@@ -166,6 +167,7 @@ static void s390_init(ram_addr_t _ram_size,
env->halted = 0;
env->exception_index = 0;
+ cpu_synchronize_state(env);
if (kernel_filename) {
kernel_size = load_image(kernel_filename, qemu_get_ram_ptr(0));
@@ -175,9 +177,7 @@ static void s390_init(ram_addr_t _ram_size,
exit(1);
}
- cpu_synchronize_state(env);
- env->psw.addr = KERN_IMAGE_START;
- env->psw.mask = 0x0000000180000000UL;
+ env->reset_addr = KERN_IMAGE_START;
}
if (initrd_filename) {
@@ -223,7 +223,12 @@ static void s390_init(ram_addr_t _ram_size,
dev = qdev_create((BusState *)s390_bus, "virtio-blk-s390");
qdev_prop_set_drive(dev, "drive", dinfo);
qdev_init_nofail(dev);
+
+ zipl_load(env, dinfo->bdrv);
}
+
+ env->psw.mask = 0x0000000180000000UL;
+ env->psw.addr = env->reset_addr;
}
static QEMUMachine s390_machine = {
diff --git a/hw/s390-zipl.c b/hw/s390-zipl.c
new file mode 100644
index 0000000..44c08c2
--- /dev/null
+++ b/hw/s390-zipl.c
@@ -0,0 +1,233 @@
+/*
+ * QEMU S390 zipl interpreter
+ *
+ * Copyright (c) 2009 Alexander Graf <agraf@suse.de>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "hw.h"
+#include "block.h"
+#include "sysemu.h"
+#include "net.h"
+#include "boards.h"
+#include "monitor.h"
+#include "loader.h"
+#include "elf.h"
+#include "hw/virtio.h"
+#include "hw/virtio-console.h"
+#include "hw/sysbus.h"
+#include "kvm.h"
+#include "s390-zipl.h"
+
+#include "hw/s390-virtio-bus.h"
+
+//#define DEBUG_S390
+
+#ifdef DEBUG_S390
+#define dprintf(fmt, ...) \
+ do { fprintf(stderr, "zipl: " fmt, ## __VA_ARGS__); } while (0)
+#else
+#define dprintf(fmt, ...) \
+ do { } while (0)
+#endif
+
+struct scsi_blockptr {
+ uint64_t blockno;
+ uint16_t size;
+ uint16_t blockct;
+ uint8_t reserved[4];
+} __attribute__ ((packed));
+
+struct component_entry {
+ struct scsi_blockptr data;
+ uint8_t pad[7];
+ uint8_t component_type;
+ uint64_t load_address;
+} __attribute((packed));
+
+struct component_header {
+ uint8_t magic[4];
+ uint8_t type;
+ uint8_t reserved[27];
+} __attribute((packed));
+
+struct mbr {
+ uint8_t magic[4];
+ uint32_t version_id;
+ uint8_t reserved[8];
+ struct scsi_blockptr blockptr;
+} __attribute__ ((packed));
+
+#define ZIPL_MAGIC "zIPL"
+#define SECTOR_SIZE 512
+
+#define ZIPL_COMP_HEADER_IPL 0x00
+#define ZIPL_COMP_HEADER_DUMP 0x01
+
+#define ZIPL_COMP_ENTRY_LOAD 0x02
+#define ZIPL_COMP_ENTRY_EXEC 0x01
+
+/* Check for ZIPL magic. Returns 0 if not matched. */
+static int zipl_magic(uint8_t *ptr)
+{
+ int r;
+
+ r = !memcmp(ptr, ZIPL_MAGIC, 4);
+ if (!r)
+ dprintf("invalid magic: %#hhx %#hhx %#hhx %#hhx\n",
+ ptr[0], ptr[1], ptr[2], ptr[3]);
+
+ return r;
+}
+
+static int zipl_load_segment(BlockDriverState *bdrv,
+ struct component_entry *entry)
+{
+ int max_entries = SECTOR_SIZE / sizeof(struct scsi_blockptr);
+ struct scsi_blockptr bprs[max_entries + 1];
+ uint64_t blockno, address;
+ int i, len;
+ uint8_t *tmp;
+
+ blockno = be64_to_cpu(entry->data.blockno);
+ address = be64_to_cpu(entry->load_address);
+
+ dprintf("loading segment at %#lx : %#lx\n", blockno, address);
+
+ do {
+ if (bdrv_read(bdrv, blockno, (uint8_t *)&bprs, 1) == -1) {
+ dprintf("failed reading bprs at %#lx\n", blockno);
+ goto fail;
+ }
+
+ for (i = 0; i < max_entries; i++) {
+ blockno = be64_to_cpu(bprs[i].blockno);
+ if (!blockno)
+ break;
+
+ len = be16_to_cpu(bprs[i].size) *
+ (be16_to_cpu(bprs[i].blockct) + 1);
+ tmp = qemu_malloc(len);
+ if (bdrv_pread(bdrv, blockno * SECTOR_SIZE, tmp, len) == -1) {
+ dprintf("failed reading %#x b segment at %#lx\n",
+ len, blockno * SECTOR_SIZE);
+ qemu_free(tmp);
+ goto fail;
+ }
+
+ cpu_physical_memory_write(address, tmp, len);
+ qemu_free(tmp);
+ address += len;
+ }
+ } while (blockno);
+
+ return 0;
+
+fail:
+ dprintf("failed loading segment\n");
+ return -1;
+}
+
+/* Run a zipl program */
+static int zipl_run(CPUState *env, BlockDriverState *bdrv, struct scsi_blockptr *pte)
+{
+ struct component_header *header;
+ struct component_entry *entry;
+ uint8_t sec[SECTOR_SIZE];
+
+ bdrv_read(bdrv, be64_to_cpu(pte->blockno), sec, 1);
+ header = (struct component_header *)sec;
+
+ if (!zipl_magic(sec))
+ goto fail;
+
+ if (header->type != ZIPL_COMP_HEADER_IPL)
+ goto fail;
+
+ dprintf("start loading images\n");
+
+ /* Load image(s) into RAM */
+ entry = (struct component_entry *)(&header[1]);
+ while (entry->component_type == ZIPL_COMP_ENTRY_LOAD) {
+ if (zipl_load_segment(bdrv, entry) < 0)
+ goto fail;
+
+ entry++;
+
+ if ((uint8_t*)(&entry[1]) > (sec + SECTOR_SIZE))
+ goto fail;
+ }
+
+ /* And set the reset vector, so we know where to start */
+ if (entry->component_type != ZIPL_COMP_ENTRY_EXEC)
+ goto fail;
+
+ env->reset_addr = be64_to_cpu(entry->load_address) & 0x7fffffff;
+ dprintf("set reset addr to: %#lx\n", env->reset_addr);
+
+ return 0;
+
+fail:
+ dprintf("failed running zipl\n");
+ return -1;
+}
+
+int zipl_load(CPUState *env, BlockDriverState *bdrv)
+{
+ struct mbr mbr;
+ uint8_t sec[SECTOR_SIZE], *ns, *ns_end;
+ int program_table_entries = 0;
+ int pte_len = sizeof(struct scsi_blockptr);
+ struct scsi_blockptr *prog_table_entry;
+
+ /* Grab the MBR */
+
+ if (bdrv_pread(bdrv, 0, &mbr, sizeof(mbr)) == -1)
+ goto fail;
+
+ if (!zipl_magic(mbr.magic))
+ goto fail;
+
+ /* Parse the program table */
+ if (bdrv_read(bdrv, be64_to_cpu(mbr.blockptr.blockno), sec, 1) == -1)
+ goto fail;
+
+ if (!zipl_magic(sec))
+ goto fail;
+
+ ns_end = sec + SECTOR_SIZE;
+ for (ns = (sec + pte_len); (ns + pte_len) < ns_end; ns++) {
+ prog_table_entry = (struct scsi_blockptr *)ns;
+ if (!prog_table_entry->blockno)
+ break;
+
+ program_table_entries++;
+ }
+
+ dprintf("Found %d program table entries\n", program_table_entries);
+
+ if (!program_table_entries)
+ goto fail;
+
+ /* Run the default entry */
+
+ prog_table_entry = (struct scsi_blockptr *)(sec + pte_len);
+
+ return zipl_run(env, bdrv, prog_table_entry);
+
+fail:
+ dprintf("failed loading zipl\n");
+ return -1;
+}
diff --git a/target-s390x/cpu.h b/target-s390x/cpu.h
index a74745c..2e286c7 100644
--- a/target-s390x/cpu.h
+++ b/target-s390x/cpu.h
@@ -63,6 +63,7 @@ typedef struct CPUS390XState {
int cc; /* condition code (0-3) */
uint64_t __excp_addr;
+ uint64_t reset_addr;
CPU_COMMON
} CPUS390XState;
--
1.6.0.2
next prev parent reply other threads:[~2009-11-24 17:29 UTC|newest]
Thread overview: 40+ messages / expand[flat|nested] mbox.gz Atom feed top
2009-11-24 17:29 [Qemu-devel] [PATCH 00/13] S390x KVM support v4 Alexander Graf
2009-11-24 17:29 ` [Qemu-devel] [PATCH 01/13] S/390 CPU fake emulation Alexander Graf
2009-11-24 17:29 ` [Qemu-devel] [PATCH 02/13] S/390 host/target build system support Alexander Graf
2009-11-24 17:29 ` [Qemu-devel] [PATCH 03/13] S/390 fake TCG implementation Alexander Graf
2009-11-24 17:29 ` [Qemu-devel] [PATCH 04/13] Add KVM support for S390x Alexander Graf
2009-11-24 17:29 ` [Qemu-devel] [PATCH 05/13] Allocate physical memory in low virtual address space Alexander Graf
2009-11-24 17:29 ` [Qemu-devel] [PATCH 06/13] Add support for S390x system emulation Alexander Graf
2009-11-25 11:46 ` Paul Brook
2009-11-25 11:47 ` Alexander Graf
2009-11-24 17:29 ` [Qemu-devel] [PATCH 07/13] Add S390x virtio machine bus Alexander Graf
2009-11-24 17:29 ` [Qemu-devel] [PATCH 08/13] Add S390x virtio machine description Alexander Graf
2009-11-24 17:29 ` [Qemu-devel] [PATCH 09/13] S390 GDB stub Alexander Graf
2009-11-24 17:29 ` [Qemu-devel] [PATCH 10/13] Implement early printk in virtio-console Alexander Graf
2009-11-24 18:55 ` Anthony Liguori
2009-11-24 18:56 ` Alexander Graf
2009-11-24 19:25 ` Anthony Liguori
2009-11-24 19:27 ` Alexander Graf
2009-11-24 19:30 ` Anthony Liguori
2009-11-24 19:32 ` Alexander Graf
2009-11-24 19:48 ` Anthony Liguori
2009-11-24 19:58 ` Alexander Graf
2009-11-25 10:00 ` Carsten Otte
2009-11-25 13:14 ` Arnd Bergmann
2009-11-25 13:47 ` Carsten Otte
2009-11-25 9:03 ` Carsten Otte
2009-11-24 17:29 ` [Qemu-devel] [PATCH 11/13] Set default console to virtio on S390x Alexander Graf
2009-11-24 17:29 ` Alexander Graf [this message]
2009-11-24 18:53 ` [Qemu-devel] [PATCH 12/13] Add zipl bootloader interpreter Anthony Liguori
2009-11-24 18:56 ` Alexander Graf
2009-11-24 19:26 ` Anthony Liguori
2009-11-24 19:29 ` Alexander Graf
2009-11-24 20:39 ` Mark Williamson
2009-11-24 21:10 ` Anthony Liguori
2009-11-25 8:35 ` Hannes Reinecke
2009-11-25 8:38 ` Alexander Graf
2009-11-25 10:09 ` Carsten Otte
2009-11-25 10:02 ` Carsten Otte
2009-11-25 9:58 ` Carsten Otte
2009-11-25 8:59 ` Carsten Otte
2009-11-24 17:29 ` [Qemu-devel] [PATCH 13/13] Add S390 maintainer information Alexander Graf
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=1259083781-14642-13-git-send-email-agraf@suse.de \
--to=agraf@suse.de \
--cc=aurelien@aurel32.net \
--cc=cotte@de.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).