diff options
author | test <test@test.(none)> | 2013-07-02 17:51:55 +0900 |
---|---|---|
committer | test <test@test.(none)> | 2013-07-02 17:51:55 +0900 |
commit | 6d7ee3e0d990b38cfe087fe1a179fda8d4b5e289 (patch) | |
tree | c7f1213af278e23ed05d50d65103c687ad7d43e5 /pc-bios | |
parent | c9d7a82ff83a1a21c843c072c3e13aa365ff6c51 (diff) | |
parent | 295d81c62414a63c625fa2e78175573d4b3f5ba4 (diff) | |
download | qemu-6d7ee3e0d990b38cfe087fe1a179fda8d4b5e289.tar.gz qemu-6d7ee3e0d990b38cfe087fe1a179fda8d4b5e289.tar.bz2 qemu-6d7ee3e0d990b38cfe087fe1a179fda8d4b5e289.zip |
Merge 'qemu 1.5.1' into tizen_qemu_1.5.1
Conflicts:
Makefile
arch_init.h
block/raw-win32.c
blockdev.c
configure
console.h
cpu-defs.h
cpu-exec.c
cpus.c
default-configs/arm-softmmu.mak
exec-all.h
exec.c
fpu/softfloat.h
hw/9pfs/virtio-9p-device.c
hw/Makefile.objs
hw/acpi_piix4.c
hw/apic_common.c
hw/arm/Makefile.objs
hw/exynos4210.c
hw/exynos4210.h
hw/exynos4210_fimd.c
hw/exynos4210_gic.c
hw/exynos4210_uart.c
hw/pc.c
hw/pc_sysfw.c
hw/pci-hotplug.c
hw/pci.c
hw/pci.h
hw/pl050.c
hw/ps2.c
hw/qdev-properties.c
hw/qdev.c
hw/qdev.h
hw/vga-pci.c
hw/vga-pci.h
hw/vga_int.h
hw/virtio-balloon.c
hw/virtio-balloon.h
hw/virtio-blk.c
hw/virtio-blk.h
hw/virtio-net.c
hw/virtio-net.h
hw/virtio-pci.c
hw/virtio-pci.h
hw/virtio-serial-bus.c
hw/virtio-serial.h
hw/virtio.c
hw/virtio.h
input.c
kvm.h
main-loop.c
main-loop.h
os-win32.c
oslib-posix.c
oslib-win32.c
qemu-char.c
qemu-options.hx
qemu-sockets.c
softmmu_defs.h
softmmu_template.h
sysemu.h
tcg/i386/tcg-target.c
tcg/tcg.c
tcg/tcg.h
vl.c
Diffstat (limited to 'pc-bios')
-rw-r--r-- | pc-bios/README | 8 | ||||
-rw-r--r-- | pc-bios/acpi-dsdt.aml | bin | 0 -> 4521 bytes | |||
-rw-r--r-- | pc-bios/bios.bin | bin | 131072 -> 131072 bytes | |||
-rw-r--r-- | pc-bios/efi-e1000.rom | bin | 0 -> 173568 bytes | |||
-rw-r--r-- | pc-bios/efi-eepro100.rom | bin | 0 -> 174592 bytes | |||
-rw-r--r-- | pc-bios/efi-ne2k_pci.rom | bin | 0 -> 173056 bytes | |||
-rw-r--r-- | pc-bios/efi-pcnet.rom | bin | 0 -> 173056 bytes | |||
-rw-r--r-- | pc-bios/efi-rtl8139.rom | bin | 0 -> 176640 bytes | |||
-rw-r--r-- | pc-bios/efi-virtio.rom | bin | 0 -> 171008 bytes | |||
-rw-r--r-- | pc-bios/multiboot.bin | bin | 1024 -> 1024 bytes | |||
-rw-r--r-- | pc-bios/openbios-ppc | bin | 729908 -> 733972 bytes | |||
-rw-r--r-- | pc-bios/openbios-sparc32 | bin | 381764 -> 381764 bytes | |||
-rw-r--r-- | pc-bios/openbios-sparc64 | bin | 1598648 -> 1598648 bytes | |||
-rw-r--r-- | pc-bios/optionrom/multiboot.S | 7 | ||||
-rw-r--r-- | pc-bios/optionrom/optionrom.h | 2 | ||||
-rw-r--r-- | pc-bios/q35-acpi-dsdt.aml | bin | 0 -> 7458 bytes | |||
-rw-r--r-- | pc-bios/s390-ccw.img | bin | 0 -> 9432 bytes | |||
-rw-r--r-- | pc-bios/s390-ccw/Makefile | 26 | ||||
-rw-r--r-- | pc-bios/s390-ccw/bootmap.c | 235 | ||||
-rw-r--r-- | pc-bios/s390-ccw/cio.h | 322 | ||||
-rw-r--r-- | pc-bios/s390-ccw/main.c | 73 | ||||
-rw-r--r-- | pc-bios/s390-ccw/s390-ccw.h | 134 | ||||
-rw-r--r-- | pc-bios/s390-ccw/sclp-ascii.c | 81 | ||||
-rw-r--r-- | pc-bios/s390-ccw/sclp.h | 107 | ||||
-rw-r--r-- | pc-bios/s390-ccw/start.S | 33 | ||||
-rw-r--r-- | pc-bios/s390-ccw/virtio.c | 298 | ||||
-rw-r--r-- | pc-bios/s390-ccw/virtio.h | 163 | ||||
-rw-r--r-- | pc-bios/slof.bin | bin | 878640 -> 909720 bytes |
28 files changed, 1484 insertions, 5 deletions
diff --git a/pc-bios/README b/pc-bios/README index 303713099e..030d92a049 100644 --- a/pc-bios/README +++ b/pc-bios/README @@ -11,13 +11,13 @@ firmware implementation. The goal is to implement a 100% IEEE 1275-1994 (referred to as Open Firmware) compliant firmware. The included images for PowerPC (for 32 and 64 bit PPC CPUs), - Sparc32 and Sparc64 are built from OpenBIOS SVN revision - 1063. + Sparc32 and Sparc64 are built from OpenBIOS 1.1 release (SVN + revision 1136). - SLOF (Slimline Open Firmware) is a free IEEE 1275 Open Firmware implementation for certain IBM POWER hardware. The sources are at - https://github.com/dgibson/SLOF, and the image currently in qemu is - built from git tag qemu-slof-20120731. + https://github.com/aik/SLOF, and the image currently in qemu is + built from git tag qemu-slof-20130430. - sgabios (the Serial Graphics Adapter option ROM) provides a means for legacy x86 software to communicate with an attached serial console as diff --git a/pc-bios/acpi-dsdt.aml b/pc-bios/acpi-dsdt.aml Binary files differnew file mode 100644 index 0000000000..75dfd1e310 --- /dev/null +++ b/pc-bios/acpi-dsdt.aml diff --git a/pc-bios/bios.bin b/pc-bios/bios.bin Binary files differindex eac67cb05a..c2a19b8930 100644 --- a/pc-bios/bios.bin +++ b/pc-bios/bios.bin diff --git a/pc-bios/efi-e1000.rom b/pc-bios/efi-e1000.rom Binary files differnew file mode 100644 index 0000000000..21b880afc2 --- /dev/null +++ b/pc-bios/efi-e1000.rom diff --git a/pc-bios/efi-eepro100.rom b/pc-bios/efi-eepro100.rom Binary files differnew file mode 100644 index 0000000000..1799c38a83 --- /dev/null +++ b/pc-bios/efi-eepro100.rom diff --git a/pc-bios/efi-ne2k_pci.rom b/pc-bios/efi-ne2k_pci.rom Binary files differnew file mode 100644 index 0000000000..5d1b38b9a2 --- /dev/null +++ b/pc-bios/efi-ne2k_pci.rom diff --git a/pc-bios/efi-pcnet.rom b/pc-bios/efi-pcnet.rom Binary files differnew file mode 100644 index 0000000000..79fa7a9b1d --- /dev/null +++ b/pc-bios/efi-pcnet.rom diff --git a/pc-bios/efi-rtl8139.rom b/pc-bios/efi-rtl8139.rom Binary files differnew file mode 100644 index 0000000000..0b78f1a386 --- /dev/null +++ b/pc-bios/efi-rtl8139.rom diff --git a/pc-bios/efi-virtio.rom b/pc-bios/efi-virtio.rom Binary files differnew file mode 100644 index 0000000000..e6b2bf7242 --- /dev/null +++ b/pc-bios/efi-virtio.rom diff --git a/pc-bios/multiboot.bin b/pc-bios/multiboot.bin Binary files differindex f74a6e142f..7b3c1745a4 100644 --- a/pc-bios/multiboot.bin +++ b/pc-bios/multiboot.bin diff --git a/pc-bios/openbios-ppc b/pc-bios/openbios-ppc Binary files differindex 5311eca691..77eb55dce8 100644 --- a/pc-bios/openbios-ppc +++ b/pc-bios/openbios-ppc diff --git a/pc-bios/openbios-sparc32 b/pc-bios/openbios-sparc32 Binary files differindex 6bd8e45d86..c5ba6ae6d1 100644 --- a/pc-bios/openbios-sparc32 +++ b/pc-bios/openbios-sparc32 diff --git a/pc-bios/openbios-sparc64 b/pc-bios/openbios-sparc64 Binary files differindex 7c06fcc5aa..c4aaa05173 100644 --- a/pc-bios/openbios-sparc64 +++ b/pc-bios/openbios-sparc64 diff --git a/pc-bios/optionrom/multiboot.S b/pc-bios/optionrom/multiboot.S index f08222a3c6..003bcfb49f 100644 --- a/pc-bios/optionrom/multiboot.S +++ b/pc-bios/optionrom/multiboot.S @@ -75,6 +75,13 @@ run_multiboot: shr $4, %eax mov %ax, %fs + /* Account for the EBDA in the multiboot structure's e801 + * map. + */ + int $0x12 + cwtl + movl %eax, %fs:4 + /* ES = mmap_addr */ mov %fs:48, %eax shr $4, %eax diff --git a/pc-bios/optionrom/optionrom.h b/pc-bios/optionrom/optionrom.h index 3daf7da495..ce436085d9 100644 --- a/pc-bios/optionrom/optionrom.h +++ b/pc-bios/optionrom/optionrom.h @@ -20,7 +20,7 @@ #define NO_QEMU_PROTOS -#include "../../hw/fw_cfg.h" +#include "../../include/hw/nvram/fw_cfg.h" #define BIOS_CFG_IOPORT_CFG 0x510 #define BIOS_CFG_IOPORT_DATA 0x511 diff --git a/pc-bios/q35-acpi-dsdt.aml b/pc-bios/q35-acpi-dsdt.aml Binary files differnew file mode 100644 index 0000000000..cf7b085762 --- /dev/null +++ b/pc-bios/q35-acpi-dsdt.aml diff --git a/pc-bios/s390-ccw.img b/pc-bios/s390-ccw.img Binary files differnew file mode 100644 index 0000000000..1b2a11e728 --- /dev/null +++ b/pc-bios/s390-ccw.img diff --git a/pc-bios/s390-ccw/Makefile b/pc-bios/s390-ccw/Makefile new file mode 100644 index 0000000000..ad55a14a14 --- /dev/null +++ b/pc-bios/s390-ccw/Makefile @@ -0,0 +1,26 @@ +all: build-all +# Dummy command so that make thinks it has done something + @true + +include ../../config-host.mak +include $(SRC_PATH)/rules.mak + +$(call set-vpath, $(SRC_PATH)/pc-bios/s390-ccw) + +.PHONY : all clean build-all + +OBJECTS=main.o bootmap.o sclp-ascii.o virtio.o start.o +CFLAGS += -fno-stack-protector +# XXX find a more clever to locate the bootloader +LDFLAGS += -Wl,-Ttext,0x7e00000,-Tbss,0x7f00000 -nostdlib + +build-all: s390-ccw.img + +s390-ccw.elf: $(OBJECTS) + $(call quiet-command,$(CC) $(LDFLAGS) -o $@ $(OBJECTS)," Building $(TARGET_DIR)$@") + +s390-ccw.img: s390-ccw.elf + $(call quiet-command,strip $< -o $@," Stripping $(TARGET_DIR)$@") + +clean: + rm -f *.o *.d *.img *.elf *~ diff --git a/pc-bios/s390-ccw/bootmap.c b/pc-bios/s390-ccw/bootmap.c new file mode 100644 index 0000000000..53a460df84 --- /dev/null +++ b/pc-bios/s390-ccw/bootmap.c @@ -0,0 +1,235 @@ +/* + * QEMU S390 bootmap interpreter + * + * Copyright (c) 2009 Alexander Graf <agraf@suse.de> + * + * This work is licensed under the terms of the GNU GPL, version 2 or (at + * your option) any later version. See the COPYING file in the top-level + * directory. + */ + +#include "s390-ccw.h" + +// #define DEBUG_FALLBACK + +#ifdef DEBUG_FALLBACK +#define dputs(txt) \ + do { sclp_print("zipl: " txt); } while (0) +#else +#define dputs(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 ZIPL_COMP_HEADER_IPL 0x00 +#define ZIPL_COMP_HEADER_DUMP 0x01 + +#define ZIPL_COMP_ENTRY_LOAD 0x02 +#define ZIPL_COMP_ENTRY_EXEC 0x01 + +/* Scratch space */ +static uint8_t sec[SECTOR_SIZE] __attribute__((__aligned__(SECTOR_SIZE))); + +/* Check for ZIPL magic. Returns 0 if not matched. */ +static int zipl_magic(uint8_t *ptr) +{ + uint32_t *p = (void*)ptr; + uint32_t *z = (void*)ZIPL_MAGIC; + + if (*p != *z) { + debug_print_int("invalid magic", *p); + virtio_panic("invalid magic"); + } + + return 1; +} + +static int zipl_load_segment(struct component_entry *entry) +{ + const int max_entries = (SECTOR_SIZE / sizeof(struct scsi_blockptr)); + struct scsi_blockptr *bprs = (void*)sec; + uint64_t blockno; + long address; + int i; + + blockno = entry->data.blockno; + address = entry->load_address; + + debug_print_int("loading segment at block", blockno); + debug_print_int("addr", address); + + do { + if (virtio_read(blockno, (uint8_t *)bprs)) { + debug_print_int("failed reading bprs at", blockno); + goto fail; + } + + for (i = 0;; i++) { + u64 *cur_desc = (void*)&bprs[i]; + + blockno = bprs[i].blockno; + if (!blockno) + break; + + /* we need the updated blockno for the next indirect entry in the + chain, but don't want to advance address */ + if (i == (max_entries - 1)) + break; + + address = virtio_load_direct(cur_desc[0], cur_desc[1], 0, + (void*)address); + if (address == -1) + goto fail; + } + } while (blockno); + + return 0; + +fail: + sclp_print("failed loading segment\n"); + return -1; +} + +/* Run a zipl program */ +static int zipl_run(struct scsi_blockptr *pte) +{ + struct component_header *header; + struct component_entry *entry; + void (*ipl)(void); + uint8_t tmp_sec[SECTOR_SIZE]; + + virtio_read(pte->blockno, tmp_sec); + header = (struct component_header *)tmp_sec; + + if (!zipl_magic(tmp_sec)) { + goto fail; + } + + if (header->type != ZIPL_COMP_HEADER_IPL) { + goto fail; + } + + dputs("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(entry) < 0) { + goto fail; + } + + entry++; + + if ((uint8_t*)(&entry[1]) > (tmp_sec + SECTOR_SIZE)) { + goto fail; + } + } + + if (entry->component_type != ZIPL_COMP_ENTRY_EXEC) { + goto fail; + } + + /* Ensure the guest output starts fresh */ + sclp_print("\n"); + + /* And run the OS! */ + ipl = (void*)(entry->load_address & 0x7fffffff); + debug_print_addr("set IPL addr to", ipl); + /* should not return */ + ipl(); + + return 0; + +fail: + sclp_print("failed running zipl\n"); + return -1; +} + +int zipl_load(void) +{ + struct mbr *mbr = (void*)sec; + uint8_t *ns, *ns_end; + int program_table_entries = 0; + int pte_len = sizeof(struct scsi_blockptr); + struct scsi_blockptr *prog_table_entry; + const char *error = ""; + + /* Grab the MBR */ + virtio_read(0, (void*)mbr); + + dputs("checking magic\n"); + + if (!zipl_magic(mbr->magic)) { + error = "zipl_magic 1"; + goto fail; + } + + debug_print_int("program table", mbr->blockptr.blockno); + + /* Parse the program table */ + if (virtio_read(mbr->blockptr.blockno, sec)) { + error = "virtio_read"; + goto fail; + } + + if (!zipl_magic(sec)) { + error = "zipl_magic 2"; + 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++; + } + + debug_print_int("program table entries", 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(prog_table_entry); + +fail: + sclp_print("failed loading zipl: "); + sclp_print(error); + sclp_print("\n"); + return -1; +} diff --git a/pc-bios/s390-ccw/cio.h b/pc-bios/s390-ccw/cio.h new file mode 100644 index 0000000000..cb5815accd --- /dev/null +++ b/pc-bios/s390-ccw/cio.h @@ -0,0 +1,322 @@ +/* + * Channel IO definitions + * + * Copyright (c) 2013 Alexander Graf <agraf@suse.de> + * + * Inspired by various s390 headers in Linux 3.9. + * + * This work is licensed under the terms of the GNU GPL, version 2 or (at + * your option) any later version. See the COPYING file in the top-level + * directory. + */ + +#ifndef CIO_H +#define CIO_H + +/* + * path management control word + */ +struct pmcw { + __u32 intparm; /* interruption parameter */ + __u32 qf : 1; /* qdio facility */ + __u32 w : 1; + __u32 isc : 3; /* interruption sublass */ + __u32 res5 : 3; /* reserved zeros */ + __u32 ena : 1; /* enabled */ + __u32 lm : 2; /* limit mode */ + __u32 mme : 2; /* measurement-mode enable */ + __u32 mp : 1; /* multipath mode */ + __u32 tf : 1; /* timing facility */ + __u32 dnv : 1; /* device number valid */ + __u32 dev : 16; /* device number */ + __u8 lpm; /* logical path mask */ + __u8 pnom; /* path not operational mask */ + __u8 lpum; /* last path used mask */ + __u8 pim; /* path installed mask */ + __u16 mbi; /* measurement-block index */ + __u8 pom; /* path operational mask */ + __u8 pam; /* path available mask */ + __u8 chpid[8]; /* CHPID 0-7 (if available) */ + __u32 unused1 : 8; /* reserved zeros */ + __u32 st : 3; /* subchannel type */ + __u32 unused2 : 18; /* reserved zeros */ + __u32 mbfc : 1; /* measurement block format control */ + __u32 xmwme : 1; /* extended measurement word mode enable */ + __u32 csense : 1; /* concurrent sense; can be enabled ...*/ + /* ... per MSCH, however, if facility */ + /* ... is not installed, this results */ + /* ... in an operand exception. */ +} __attribute__ ((packed)); + +/* Target SCHIB configuration. */ +struct schib_config { + __u64 mba; + __u32 intparm; + __u16 mbi; + __u32 isc:3; + __u32 ena:1; + __u32 mme:2; + __u32 mp:1; + __u32 csense:1; + __u32 mbfc:1; +} __attribute__ ((packed)); + +struct scsw { + __u16 flags; + __u16 ctrl; + __u32 cpa; + __u8 dstat; + __u8 cstat; + __u16 count; +} __attribute__ ((packed)); + +#define SCSW_FCTL_CLEAR_FUNC 0x1000 +#define SCSW_FCTL_HALT_FUNC 0x2000 +#define SCSW_FCTL_START_FUNC 0x4000 + +/* + * subchannel information block + */ +struct schib { + struct pmcw pmcw; /* path management control word */ + struct scsw scsw; /* subchannel status word */ + __u64 mba; /* measurement block address */ + __u8 mda[4]; /* model dependent area */ +} __attribute__ ((packed,aligned(4))); + +struct subchannel_id { + __u32 cssid : 8; + __u32 : 4; + __u32 m : 1; + __u32 ssid : 2; + __u32 one : 1; + __u32 sch_no : 16; +} __attribute__ ((packed, aligned(4))); + +/* + * TPI info structure + */ +struct tpi_info { + struct subchannel_id schid; + __u32 intparm; /* interruption parameter */ + __u32 adapter_IO : 1; + __u32 reserved2 : 1; + __u32 isc : 3; + __u32 reserved3 : 12; + __u32 int_type : 3; + __u32 reserved4 : 12; +} __attribute__ ((packed)); + +/* channel command word (type 1) */ +struct ccw1 { + __u8 cmd_code; + __u8 flags; + __u16 count; + __u32 cda; +} __attribute__ ((packed)); + +#define CCW_FLAG_DC 0x80 +#define CCW_FLAG_CC 0x40 +#define CCW_FLAG_SLI 0x20 +#define CCW_FLAG_SKIP 0x10 +#define CCW_FLAG_PCI 0x08 +#define CCW_FLAG_IDA 0x04 +#define CCW_FLAG_SUSPEND 0x02 + +#define CCW_CMD_NOOP 0x03 +#define CCW_CMD_BASIC_SENSE 0x04 +#define CCW_CMD_TIC 0x08 +#define CCW_CMD_SENSE_ID 0xe4 + +#define CCW_CMD_SET_VQ 0x13 +#define CCW_CMD_VDEV_RESET 0x33 +#define CCW_CMD_READ_FEAT 0x12 +#define CCW_CMD_WRITE_FEAT 0x11 +#define CCW_CMD_READ_CONF 0x22 +#define CCW_CMD_WRITE_CONF 0x21 +#define CCW_CMD_WRITE_STATUS 0x31 +#define CCW_CMD_SET_IND 0x43 +#define CCW_CMD_SET_CONF_IND 0x53 +#define CCW_CMD_READ_VQ_CONF 0x32 + +/* + * Command-mode operation request block + */ +struct cmd_orb { + __u32 intparm; /* interruption parameter */ + __u32 key:4; /* flags, like key, suspend control, etc. */ + __u32 spnd:1; /* suspend control */ + __u32 res1:1; /* reserved */ + __u32 mod:1; /* modification control */ + __u32 sync:1; /* synchronize control */ + __u32 fmt:1; /* format control */ + __u32 pfch:1; /* prefetch control */ + __u32 isic:1; /* initial-status-interruption control */ + __u32 alcc:1; /* address-limit-checking control */ + __u32 ssic:1; /* suppress-suspended-interr. control */ + __u32 res2:1; /* reserved */ + __u32 c64:1; /* IDAW/QDIO 64 bit control */ + __u32 i2k:1; /* IDAW 2/4kB block size control */ + __u32 lpm:8; /* logical path mask */ + __u32 ils:1; /* incorrect length */ + __u32 zero:6; /* reserved zeros */ + __u32 orbx:1; /* ORB extension control */ + __u32 cpa; /* channel program address */ +} __attribute__ ((packed, aligned(4))); + +struct ciw { + __u8 type; + __u8 command; + __u16 count; +}; + +/* + * sense-id response buffer layout + */ +struct senseid { + /* common part */ + __u8 reserved; /* always 0x'FF' */ + __u16 cu_type; /* control unit type */ + __u8 cu_model; /* control unit model */ + __u16 dev_type; /* device type */ + __u8 dev_model; /* device model */ + __u8 unused; /* padding byte */ + /* extended part */ + struct ciw ciw[62]; +} __attribute__ ((packed, aligned(4))); + +/* interruption response block */ +struct irb { + struct scsw scsw; + __u32 esw[5]; + __u32 ecw[8]; + __u32 emw[8]; +} __attribute__ ((packed, aligned(4))); + +/* + * Some S390 specific IO instructions as inline + */ + +static inline int stsch_err(struct subchannel_id schid, struct schib *addr) +{ + register struct subchannel_id reg1 asm ("1") = schid; + int ccode = -EIO; + + asm volatile( + " stsch 0(%3)\n" + "0: ipm %0\n" + " srl %0,28\n" + "1:\n" + : "+d" (ccode), "=m" (*addr) + : "d" (reg1), "a" (addr) + : "cc"); + return ccode; +} + +static inline int msch(struct subchannel_id schid, struct schib *addr) +{ + register struct subchannel_id reg1 asm ("1") = schid; + int ccode; + + asm volatile( + " msch 0(%2)\n" + " ipm %0\n" + " srl %0,28" + : "=d" (ccode) + : "d" (reg1), "a" (addr), "m" (*addr) + : "cc"); + return ccode; +} + +static inline int msch_err(struct subchannel_id schid, struct schib *addr) +{ + register struct subchannel_id reg1 asm ("1") = schid; + int ccode = -EIO; + + asm volatile( + " msch 0(%2)\n" + "0: ipm %0\n" + " srl %0,28\n" + "1:\n" + : "+d" (ccode) + : "d" (reg1), "a" (addr), "m" (*addr) + : "cc"); + return ccode; +} + +static inline int tsch(struct subchannel_id schid, struct irb *addr) +{ + register struct subchannel_id reg1 asm ("1") = schid; + int ccode; + + asm volatile( + " tsch 0(%3)\n" + " ipm %0\n" + " srl %0,28" + : "=d" (ccode), "=m" (*addr) + : "d" (reg1), "a" (addr) + : "cc"); + return ccode; +} + +static inline int ssch(struct subchannel_id schid, struct cmd_orb *addr) +{ + register struct subchannel_id reg1 asm("1") = schid; + int ccode = -EIO; + + asm volatile( + " ssch 0(%2)\n" + "0: ipm %0\n" + " srl %0,28\n" + "1:\n" + : "+d" (ccode) + : "d" (reg1), "a" (addr), "m" (*addr) + : "cc", "memory"); + return ccode; +} + +static inline int csch(struct subchannel_id schid) +{ + register struct subchannel_id reg1 asm("1") = schid; + int ccode; + + asm volatile( + " csch\n" + " ipm %0\n" + " srl %0,28" + : "=d" (ccode) + : "d" (reg1) + : "cc"); + return ccode; +} + +static inline int tpi(struct tpi_info *addr) +{ + int ccode; + + asm volatile( + " tpi 0(%2)\n" + " ipm %0\n" + " srl %0,28" + : "=d" (ccode), "=m" (*addr) + : "a" (addr) + : "cc"); + return ccode; +} + +static inline int chsc(void *chsc_area) +{ + typedef struct { char _[4096]; } addr_type; + int cc; + + asm volatile( + " .insn rre,0xb25f0000,%2,0\n" + " ipm %0\n" + " srl %0,28\n" + : "=d" (cc), "=m" (*(addr_type *) chsc_area) + : "d" (chsc_area), "m" (*(addr_type *) chsc_area) + : "cc"); + return cc; +} + +#endif /* CIO_H */ diff --git a/pc-bios/s390-ccw/main.c b/pc-bios/s390-ccw/main.c new file mode 100644 index 0000000000..1665c57225 --- /dev/null +++ b/pc-bios/s390-ccw/main.c @@ -0,0 +1,73 @@ +/* + * S390 virtio-ccw loading program + * + * Copyright (c) 2013 Alexander Graf <agraf@suse.de> + * + * This work is licensed under the terms of the GNU GPL, version 2 or (at + * your option) any later version. See the COPYING file in the top-level + * directory. + */ + +#include "s390-ccw.h" + +struct subchannel_id blk_schid; +char stack[PAGE_SIZE * 8] __attribute__((__aligned__(PAGE_SIZE))); +uint64_t boot_value; + +void virtio_panic(const char *string) +{ + sclp_print(string); + disabled_wait(); + while (1) { } +} + +static void virtio_setup(uint64_t dev_info) +{ + struct schib schib; + int i; + int r; + bool found = false; + bool check_devno = false; + uint16_t dev_no = -1; + blk_schid.one = 1; + + if (dev_info != -1) { + check_devno = true; + dev_no = dev_info & 0xffff; + debug_print_int("device no. ", dev_no); + } + + for (i = 0; i < 0x10000; i++) { + blk_schid.sch_no = i; + r = stsch_err(blk_schid, &schib); + if (r == 3) { + break; + } + if (schib.pmcw.dnv) { + if (!check_devno || (schib.pmcw.dev == dev_no)) { + if (virtio_is_blk(blk_schid)) { + found = true; + break; + } + } + } + } + + if (!found) { + virtio_panic("No virtio-blk device found!\n"); + } + + virtio_setup_block(blk_schid); +} + +int main(void) +{ + sclp_setup(); + debug_print_int("boot reg[7] ", boot_value); + virtio_setup(boot_value); + + if (zipl_load() < 0) + sclp_print("Failed to load OS from hard disk\n"); + disabled_wait(); + while (1) { } +} diff --git a/pc-bios/s390-ccw/s390-ccw.h b/pc-bios/s390-ccw/s390-ccw.h new file mode 100644 index 0000000000..8241b0af05 --- /dev/null +++ b/pc-bios/s390-ccw/s390-ccw.h @@ -0,0 +1,134 @@ +/* + * S390 CCW boot loader + * + * Copyright (c) 2013 Alexander Graf <agraf@suse.de> + * + * This work is licensed under the terms of the GNU GPL, version 2 or (at + * your option) any later version. See the COPYING file in the top-level + * directory. + */ + +#ifndef S390_CCW_H +#define S390_CCW_H + +/* #define DEBUG */ + +typedef unsigned char u8; +typedef unsigned short u16; +typedef unsigned int u32; +typedef unsigned long long u64; +typedef unsigned long ulong; +typedef long size_t; +typedef int bool; +typedef unsigned char uint8_t; +typedef unsigned short uint16_t; +typedef unsigned int uint32_t; +typedef unsigned long long uint64_t; +typedef unsigned char __u8; +typedef unsigned short __u16; +typedef unsigned int __u32; +typedef unsigned long long __u64; + +#define true 1 +#define false 0 +#define PAGE_SIZE 4096 + +#ifndef EIO +#define EIO 1 +#endif +#ifndef EBUSY +#define EBUSY 2 +#endif +#ifndef NULL +#define NULL 0 +#endif + +#include "cio.h" + +/* start.s */ +void disabled_wait(void); + +/* main.c */ +void virtio_panic(const char *string); + +/* sclp-ascii.c */ +void sclp_print(const char *string); +void sclp_setup(void); + +/* virtio.c */ +unsigned long virtio_load_direct(ulong rec_list1, ulong rec_list2, + ulong subchan_id, void *load_addr); +bool virtio_is_blk(struct subchannel_id schid); +void virtio_setup_block(struct subchannel_id schid); +int virtio_read(ulong sector, void *load_addr); + +/* bootmap.c */ +int zipl_load(void); + +static inline void *memset(void *s, int c, size_t n) +{ + int i; + unsigned char *p = s; + + for (i = 0; i < n; i++) { + p[i] = c; + } + + return s; +} + +static inline void fill_hex(char *out, unsigned char val) +{ + const char hex[] = "0123456789abcdef"; + + out[0] = hex[(val >> 4) & 0xf]; + out[1] = hex[val & 0xf]; +} + +static inline void print_int(const char *desc, u64 addr) +{ + unsigned char *addr_c = (unsigned char*)&addr; + char out[] = ": 0xffffffffffffffff\n"; + unsigned int i; + + for (i = 0; i < sizeof(addr); i++) { + fill_hex(&out[4 + (i*2)], addr_c[i]); + } + + sclp_print(desc); + sclp_print(out); +} + +static inline void debug_print_int(const char *desc, u64 addr) +{ +#ifdef DEBUG + print_int(desc, addr); +#endif +} + +static inline void debug_print_addr(const char *desc, void *p) +{ +#ifdef DEBUG + debug_print_int(desc, (unsigned int)(unsigned long)p); +#endif +} + +/*********************************************** + * Hypercall functions * + ***********************************************/ + +#define KVM_S390_VIRTIO_NOTIFY 0 +#define KVM_S390_VIRTIO_RESET 1 +#define KVM_S390_VIRTIO_SET_STATUS 2 +#define KVM_S390_VIRTIO_CCW_NOTIFY 3 + +static inline void yield(void) +{ + asm volatile ("diag 0,0,0x44" + : : + : "memory", "cc"); +} + +#define SECTOR_SIZE 512 + +#endif /* S390_CCW_H */ diff --git a/pc-bios/s390-ccw/sclp-ascii.c b/pc-bios/s390-ccw/sclp-ascii.c new file mode 100644 index 0000000000..1c93937104 --- /dev/null +++ b/pc-bios/s390-ccw/sclp-ascii.c @@ -0,0 +1,81 @@ +/* + * SCLP ASCII access driver + * + * Copyright (c) 2013 Alexander Graf <agraf@suse.de> + * + * This work is licensed under the terms of the GNU GPL, version 2 or (at + * your option) any later version. See the COPYING file in the top-level + * directory. + */ + +#include "s390-ccw.h" +#include "sclp.h" + +static char _sccb[PAGE_SIZE] __attribute__((__aligned__(4096))); + +/* Perform service call. Return 0 on success, non-zero otherwise. */ +static int sclp_service_call(unsigned int command, void *sccb) +{ + int cc; + + asm volatile( + " .insn rre,0xb2200000,%1,%2\n" /* servc %1,%2 */ + " ipm %0\n" + " srl %0,28" + : "=&d" (cc) : "d" (command), "a" (__pa(sccb)) + : "cc", "memory"); + if (cc == 3) + return -EIO; + if (cc == 2) + return -EBUSY; + return 0; +} + +static void sclp_set_write_mask(void) +{ + WriteEventMask *sccb = (void*)_sccb; + + sccb->h.length = sizeof(WriteEventMask); + sccb->mask_length = sizeof(unsigned int); + sccb->receive_mask = SCLP_EVENT_MASK_MSG_ASCII; + sccb->cp_receive_mask = SCLP_EVENT_MASK_MSG_ASCII; + sccb->send_mask = SCLP_EVENT_MASK_MSG_ASCII; + sccb->cp_send_mask = SCLP_EVENT_MASK_MSG_ASCII; + + sclp_service_call(SCLP_CMD_WRITE_EVENT_MASK, sccb); +} + +void sclp_setup(void) +{ + sclp_set_write_mask(); +} + +static int _strlen(const char *str) +{ + int i; + for (i = 0; *str; i++) + str++; + return i; +} + +static void _memcpy(char *dest, const char *src, int len) +{ + int i; + for (i = 0; i < len; i++) + dest[i] = src[i]; +} + +void sclp_print(const char *str) +{ + int len = _strlen(str); + WriteEventData *sccb = (void*)_sccb; + + sccb->h.length = sizeof(WriteEventData) + len; + sccb->h.function_code = SCLP_FC_NORMAL_WRITE; + sccb->ebh.length = sizeof(EventBufferHeader) + len; + sccb->ebh.type = SCLP_EVENT_ASCII_CONSOLE_DATA; + sccb->ebh.flags = 0; + _memcpy(sccb->data, str, len); + + sclp_service_call(SCLP_CMD_WRITE_EVENT_DATA, sccb); +} diff --git a/pc-bios/s390-ccw/sclp.h b/pc-bios/s390-ccw/sclp.h new file mode 100644 index 0000000000..3cbfb78930 --- /dev/null +++ b/pc-bios/s390-ccw/sclp.h @@ -0,0 +1,107 @@ +/* + * SCLP ASCII access driver + * + * Copyright (c) 2013 Alexander Graf <agraf@suse.de> + * + * This work is licensed under the terms of the GNU GPL, version 2 or (at + * your option) any later version. See the COPYING file in the top-level + * directory. + */ + +#ifndef SCLP_H +#define SCLP_H + +/* SCLP command codes */ +#define SCLP_CMDW_READ_SCP_INFO 0x00020001 +#define SCLP_CMDW_READ_SCP_INFO_FORCED 0x00120001 +#define SCLP_CMD_READ_EVENT_DATA 0x00770005 +#define SCLP_CMD_WRITE_EVENT_DATA 0x00760005 +#define SCLP_CMD_READ_EVENT_DATA 0x00770005 +#define SCLP_CMD_WRITE_EVENT_DATA 0x00760005 +#define SCLP_CMD_WRITE_EVENT_MASK 0x00780005 + +/* SCLP response codes */ +#define SCLP_RC_NORMAL_READ_COMPLETION 0x0010 +#define SCLP_RC_NORMAL_COMPLETION 0x0020 +#define SCLP_RC_INVALID_SCLP_COMMAND 0x01f0 +#define SCLP_RC_CONTAINED_EQUIPMENT_CHECK 0x0340 +#define SCLP_RC_INSUFFICIENT_SCCB_LENGTH 0x0300 +#define SCLP_RC_INVALID_FUNCTION 0x40f0 +#define SCLP_RC_NO_EVENT_BUFFERS_STORED 0x60f0 +#define SCLP_RC_INVALID_SELECTION_MASK 0x70f0 +#define SCLP_RC_INCONSISTENT_LENGTHS 0x72f0 +#define SCLP_RC_EVENT_BUFFER_SYNTAX_ERROR 0x73f0 +#define SCLP_RC_INVALID_MASK_LENGTH 0x74f0 + +/* Service Call Control Block (SCCB) and its elements */ + +#define SCCB_SIZE 4096 + +#define SCLP_VARIABLE_LENGTH_RESPONSE 0x80 +#define SCLP_EVENT_BUFFER_ACCEPTED 0x80 + +#define SCLP_FC_NORMAL_WRITE 0 + +typedef struct SCCBHeader { + uint16_t length; + uint8_t function_code; + uint8_t control_mask[3]; + uint16_t response_code; +} __attribute__((packed)) SCCBHeader; + +#define SCCB_DATA_LEN (SCCB_SIZE - sizeof(SCCBHeader)) + +typedef struct ReadInfo { + SCCBHeader h; + uint16_t rnmax; + uint8_t rnsize; +} __attribute__((packed)) ReadInfo; + +typedef struct SCCB { + SCCBHeader h; + char data[SCCB_DATA_LEN]; + } __attribute__((packed)) SCCB; + +/* SCLP event types */ +#define SCLP_EVENT_ASCII_CONSOLE_DATA 0x1a +#define SCLP_EVENT_SIGNAL_QUIESCE 0x1d + +/* SCLP event masks */ +#define SCLP_EVENT_MASK_SIGNAL_QUIESCE 0x00000008 +#define SCLP_EVENT_MASK_MSG_ASCII 0x00000040 + +#define SCLP_UNCONDITIONAL_READ 0x00 +#define SCLP_SELECTIVE_READ 0x01 + +typedef struct WriteEventMask { + SCCBHeader h; + uint16_t _reserved; + uint16_t mask_length; + uint32_t cp_receive_mask; + uint32_t cp_send_mask; + uint32_t send_mask; + uint32_t receive_mask; +} __attribute__((packed)) WriteEventMask; + +typedef struct EventBufferHeader { + uint16_t length; + uint8_t type; + uint8_t flags; + uint16_t _reserved; +} __attribute__((packed)) EventBufferHeader; + +typedef struct WriteEventData { + SCCBHeader h; + EventBufferHeader ebh; + char data[0]; +} __attribute__((packed)) WriteEventData; + +typedef struct ReadEventData { + SCCBHeader h; + EventBufferHeader ebh; + uint32_t mask; +} __attribute__((packed)) ReadEventData; + +#define __pa(x) (x) + +#endif /* SCLP_H */ diff --git a/pc-bios/s390-ccw/start.S b/pc-bios/s390-ccw/start.S new file mode 100644 index 0000000000..5d5df0d616 --- /dev/null +++ b/pc-bios/s390-ccw/start.S @@ -0,0 +1,33 @@ +/* + * First stage boot loader for virtio devices. The compiled output goes + * into the pc-bios directory of qemu. + * + * Copyright (c) 2013 Alexander Graf <agraf@suse.de> + * Copyright 2013 IBM Corp. + * + * This work is licensed under the terms of the GNU GPL, version 2 or (at + * your option) any later version. See the COPYING file in the top-level + * directory. + */ + + .globl _start +_start: + +larl %r15, stack + 0x8000 /* Set up stack */ +larl %r6, boot_value +stg %r7, 0(%r6) /* save the boot_value before any function calls */ +j main /* And call C */ + +/* + * void disabled_wait(void) + * + * stops the current guest cpu. + */ + .globl disabled_wait +disabled_wait: + larl %r1,disabled_wait_psw + lpswe 0(%r1) + + .align 8 +disabled_wait_psw: + .quad 0x0002000180000000,0x0000000000000000 diff --git a/pc-bios/s390-ccw/virtio.c b/pc-bios/s390-ccw/virtio.c new file mode 100644 index 0000000000..5b9e1dc107 --- /dev/null +++ b/pc-bios/s390-ccw/virtio.c @@ -0,0 +1,298 @@ +/* + * Virtio driver bits + * + * Copyright (c) 2013 Alexander Graf <agraf@suse.de> + * + * This work is licensed under the terms of the GNU GPL, version 2 or (at + * your option) any later version. See the COPYING file in the top-level + * directory. + */ + +#include "s390-ccw.h" +#include "virtio.h" + +struct vring block; + +static long kvm_hypercall(unsigned long nr, unsigned long param1, + unsigned long param2) +{ + register ulong r_nr asm("1") = nr; + register ulong r_param1 asm("2") = param1; + register ulong r_param2 asm("3") = param2; + register long retval asm("2"); + + asm volatile ("diag 2,4,0x500" + : "=d" (retval) + : "d" (r_nr), "0" (r_param1), "r"(r_param2) + : "memory", "cc"); + + return retval; +} + +static void virtio_notify(struct subchannel_id schid) +{ + kvm_hypercall(KVM_S390_VIRTIO_CCW_NOTIFY, *(u32*)&schid, 0); +} + +/*********************************************** + * Virtio functions * + ***********************************************/ + +static int drain_irqs(struct subchannel_id schid) +{ + struct irb irb = {}; + int r = 0; + + while (1) { + /* FIXME: make use of TPI, for that enable subchannel and isc */ + if (tsch(schid, &irb)) { + /* Might want to differentiate error codes later on. */ + if (irb.scsw.cstat) { + r = -EIO; + } else if (irb.scsw.dstat != 0xc) { + r = -EIO; + } + return r; + } + } +} + +static int run_ccw(struct subchannel_id schid, int cmd, void *ptr, int len) +{ + struct ccw1 ccw = {}; + struct cmd_orb orb = {}; + struct schib schib; + int r; + + /* start command processing */ + stsch_err(schid, &schib); + schib.scsw.ctrl = SCSW_FCTL_START_FUNC; + msch(schid, &schib); + + /* start subchannel command */ + orb.fmt = 1; + orb.cpa = (u32)(long)&ccw; + orb.lpm = 0x80; + + ccw.cmd_code = cmd; + ccw.cda = (long)ptr; + ccw.count = len; + + r = ssch(schid, &orb); + /* + * XXX Wait until device is done processing the CCW. For now we can + * assume that a simple tsch will have finished the CCW processing, + * but the architecture allows for asynchronous operation + */ + if (!r) { + r = drain_irqs(schid); + } + return r; +} + +static void virtio_set_status(struct subchannel_id schid, + unsigned long dev_addr) +{ + unsigned char status = dev_addr; + if (run_ccw(schid, CCW_CMD_WRITE_STATUS, &status, sizeof(status))) { + virtio_panic("Could not write status to host!\n"); + } +} + +static void virtio_reset(struct subchannel_id schid) +{ + run_ccw(schid, CCW_CMD_VDEV_RESET, NULL, 0); +} + +static void vring_init(struct vring *vr, unsigned int num, void *p, + unsigned long align) +{ + debug_print_addr("init p", p); + vr->num = num; + vr->desc = p; + vr->avail = p + num*sizeof(struct vring_desc); + vr->used = (void *)(((unsigned long)&vr->avail->ring[num] + align-1) + & ~(align - 1)); + + /* We're running with interrupts off anyways, so don't bother */ + vr->used->flags = VRING_USED_F_NO_NOTIFY; + + debug_print_addr("init vr", vr); +} + +static void vring_notify(struct subchannel_id schid) +{ + virtio_notify(schid); +} + +static void vring_send_buf(struct vring *vr, void *p, int len, int flags) +{ + /* For follow-up chains we need to keep the first entry point */ + if (!(flags & VRING_HIDDEN_IS_CHAIN)) { + vr->avail->ring[vr->avail->idx % vr->num] = vr->next_idx; + } + + vr->desc[vr->next_idx].addr = (ulong)p; + vr->desc[vr->next_idx].len = len; + vr->desc[vr->next_idx].flags = flags & ~VRING_HIDDEN_IS_CHAIN; + vr->desc[vr->next_idx].next = vr->next_idx; + vr->desc[vr->next_idx].next++; + vr->next_idx++; + + /* Chains only have a single ID */ + if (!(flags & VRING_DESC_F_NEXT)) { + vr->avail->idx++; + } + + vr->used->idx = vr->next_idx; +} + +static u64 get_clock(void) +{ + u64 r; + + asm volatile("stck %0" : "=Q" (r) : : "cc"); + return r; +} + +static ulong get_second(void) +{ + return (get_clock() >> 12) / 1000000; +} + +/* + * Wait for the host to reply. + * + * timeout is in seconds if > 0. + * + * Returns 0 on success, 1 on timeout. + */ +static int vring_wait_reply(struct vring *vr, int timeout) +{ + ulong target_second = get_second() + timeout; + struct subchannel_id schid = vr->schid; + int r = 0; + + while (vr->used->idx == vr->next_idx) { + vring_notify(schid); + if (timeout && (get_second() >= target_second)) { + r = 1; + break; + } + yield(); + } + + vr->next_idx = 0; + vr->desc[0].len = 0; + vr->desc[0].flags = 0; + + return r; +} + +/*********************************************** + * Virtio block * + ***********************************************/ + +static int virtio_read_many(ulong sector, void *load_addr, int sec_num) +{ + struct virtio_blk_outhdr out_hdr; + u8 status; + int r; + + /* Tell the host we want to read */ + out_hdr.type = VIRTIO_BLK_T_IN; + out_hdr.ioprio = 99; + out_hdr.sector = sector; + + vring_send_buf(&block, &out_hdr, sizeof(out_hdr), VRING_DESC_F_NEXT); + + /* This is where we want to receive data */ + vring_send_buf(&block, load_addr, SECTOR_SIZE * sec_num, + VRING_DESC_F_WRITE | VRING_HIDDEN_IS_CHAIN | + VRING_DESC_F_NEXT); + + /* status field */ + vring_send_buf(&block, &status, sizeof(u8), VRING_DESC_F_WRITE | + VRING_HIDDEN_IS_CHAIN); + + /* Now we can tell the host to read */ + vring_wait_reply(&block, 0); + + r = drain_irqs(block.schid); + if (r) { + /* Well, whatever status is supposed to contain... */ + status = 1; + } + return status; +} + +unsigned long virtio_load_direct(ulong rec_list1, ulong rec_list2, + ulong subchan_id, void *load_addr) +{ + u8 status; + int sec = rec_list1; + int sec_num = (((rec_list2 >> 32)+ 1) & 0xffff); + int sec_len = rec_list2 >> 48; + ulong addr = (ulong)load_addr; + + if (sec_len != SECTOR_SIZE) { + return -1; + } + + sclp_print("."); + status = virtio_read_many(sec, (void*)addr, sec_num); + if (status) { + virtio_panic("I/O Error"); + } + addr += sec_num * SECTOR_SIZE; + + return addr; +} + +int virtio_read(ulong sector, void *load_addr) +{ + return virtio_read_many(sector, load_addr, 1); +} + +void virtio_setup_block(struct subchannel_id schid) +{ + struct vq_info_block info; + struct vq_config_block config = {}; + + virtio_reset(schid); + + config.index = 0; + if (run_ccw(schid, CCW_CMD_READ_VQ_CONF, &config, sizeof(config))) { + virtio_panic("Could not get block device configuration\n"); + } + vring_init(&block, config.num, (void*)(100 * 1024 * 1024), + KVM_S390_VIRTIO_RING_ALIGN); + + info.queue = (100ULL * 1024ULL* 1024ULL); + info.align = KVM_S390_VIRTIO_RING_ALIGN; + info.index = 0; + info.num = config.num; + block.schid = schid; + + if (!run_ccw(schid, CCW_CMD_SET_VQ, &info, sizeof(info))) { + virtio_set_status(schid, VIRTIO_CONFIG_S_DRIVER_OK); + } +} + +bool virtio_is_blk(struct subchannel_id schid) +{ + int r; + struct senseid senseid = {}; + + /* run sense id command */ + r = run_ccw(schid, CCW_CMD_SENSE_ID, &senseid, sizeof(senseid)); + if (r) { + return false; + } + if ((senseid.cu_type != 0x3832) || (senseid.cu_model != VIRTIO_ID_BLOCK)) { + return false; + } + + return true; +} + diff --git a/pc-bios/s390-ccw/virtio.h b/pc-bios/s390-ccw/virtio.h new file mode 100644 index 0000000000..86fdd579b4 --- /dev/null +++ b/pc-bios/s390-ccw/virtio.h @@ -0,0 +1,163 @@ +/* + * Virtio driver bits + * + * Copyright (c) 2013 Alexander Graf <agraf@suse.de> + * + * This work is licensed under the terms of the GNU GPL, version 2 or (at + * your option) any later version. See the COPYING file in the top-level + * directory. + */ + +#ifndef VIRTIO_H +#define VIRTIO_H + +#include "s390-ccw.h" + +/* Status byte for guest to report progress, and synchronize features. */ +/* We have seen device and processed generic fields (VIRTIO_CONFIG_F_VIRTIO) */ +#define VIRTIO_CONFIG_S_ACKNOWLEDGE 1 +/* We have found a driver for the device. */ +#define VIRTIO_CONFIG_S_DRIVER 2 +/* Driver has used its parts of the config, and is happy */ +#define VIRTIO_CONFIG_S_DRIVER_OK 4 +/* We've given up on this device. */ +#define VIRTIO_CONFIG_S_FAILED 0x80 + +enum virtio_dev_type { + VIRTIO_ID_NET = 1, + VIRTIO_ID_BLOCK = 2, + VIRTIO_ID_CONSOLE = 3, + VIRTIO_ID_BALLOON = 5, +}; + +struct virtio_dev_header { + enum virtio_dev_type type : 8; + u8 num_vq; + u8 feature_len; + u8 config_len; + u8 status; + u8 vqconfig[]; +} __attribute__((packed)); + +struct virtio_vqconfig { + u64 token; + u64 address; + u16 num; + u8 pad[6]; +} __attribute__((packed)); + +struct vq_info_block { + u64 queue; + u32 align; + u16 index; + u16 num; +} __attribute__((packed)); + +struct vq_config_block { + u16 index; + u16 num; +} __attribute__((packed)); + +struct virtio_dev { + struct virtio_dev_header *header; + struct virtio_vqconfig *vqconfig; + char *host_features; + char *guest_features; + char *config; +}; + +#define KVM_S390_VIRTIO_RING_ALIGN 4096 + +#define VRING_USED_F_NO_NOTIFY 1 + +/* This marks a buffer as continuing via the next field. */ +#define VRING_DESC_F_NEXT 1 +/* This marks a buffer as write-only (otherwise read-only). */ +#define VRING_DESC_F_WRITE 2 +/* This means the buffer contains a list of buffer descriptors. */ +#define VRING_DESC_F_INDIRECT 4 + +/* Internal flag to mark follow-up segments as such */ +#define VRING_HIDDEN_IS_CHAIN 256 + +/* Virtio ring descriptors: 16 bytes. These can chain together via "next". */ +struct vring_desc { + /* Address (guest-physical). */ + u64 addr; + /* Length. */ + u32 len; + /* The flags as indicated above. */ + u16 flags; + /* We chain unused descriptors via this, too */ + u16 next; +} __attribute__((packed)); + +struct vring_avail { + u16 flags; + u16 idx; + u16 ring[]; +} __attribute__((packed)); + +/* u32 is used here for ids for padding reasons. */ +struct vring_used_elem { + /* Index of start of used descriptor chain. */ + u32 id; + /* Total length of the descriptor chain which was used (written to) */ + u32 len; +} __attribute__((packed)); + +struct vring_used { + u16 flags; + u16 idx; + struct vring_used_elem ring[]; +} __attribute__((packed)); + +struct vring { + unsigned int num; + int next_idx; + struct vring_desc *desc; + struct vring_avail *avail; + struct vring_used *used; + struct subchannel_id schid; +}; + + +/*********************************************** + * Virtio block * + ***********************************************/ + +/* + * Command types + * + * Usage is a bit tricky as some bits are used as flags and some are not. + * + * Rules: + * VIRTIO_BLK_T_OUT may be combined with VIRTIO_BLK_T_SCSI_CMD or + * VIRTIO_BLK_T_BARRIER. VIRTIO_BLK_T_FLUSH is a command of its own + * and may not be combined with any of the other flags. + */ + +/* These two define direction. */ +#define VIRTIO_BLK_T_IN 0 +#define VIRTIO_BLK_T_OUT 1 + +/* This bit says it's a scsi command, not an actual read or write. */ +#define VIRTIO_BLK_T_SCSI_CMD 2 + +/* Cache flush command */ +#define VIRTIO_BLK_T_FLUSH 4 + +/* Barrier before this op. */ +#define VIRTIO_BLK_T_BARRIER 0x80000000 + +/* This is the first element of the read scatter-gather list. */ +struct virtio_blk_outhdr { + /* VIRTIO_BLK_T* */ + u32 type; + /* io priority. */ + u32 ioprio; + /* Sector (ie. 512 byte offset) */ + u64 sector; +}; + +#endif /* VIRTIO_H */ diff --git a/pc-bios/slof.bin b/pc-bios/slof.bin Binary files differindex 84ba6b83f3..092e58a46e 100644 --- a/pc-bios/slof.bin +++ b/pc-bios/slof.bin |