mirror of https://github.com/xemu-project/xemu.git
* Check validity of the address in the SET PREFIX instruction
* Fix booting from devices that use 4k sectors, but are not like DASDs * Re-evaluate pending interrupts after EXECUTE of certain instructions -----BEGIN PGP SIGNATURE----- iQJFBAABCAAvFiEEJ7iIR+7gJQEY8+q5LtnXdP5wLbUFAmLGhkURHHRodXRoQHJl ZGhhdC5jb20ACgkQLtnXdP5wLbU76Q//Y4mEXxWZDpJTg7tL5SZP+UzBVttnCifv 6q+2I0keOUs6wFhPq8TzBqkazT9wlv51cNrY2Q3fU9I3dpDeRbAXZR34UD4kw5an Q+ZQcebuGSKLjzMrIb1DLAieq8OmZR5FvDUu16BbeJr6GIQIE80lMRfWh9j30UfW tlxkXr15BnyPx6m0rSGwzkZD2vgfj5zSUrDtYJcUsfypIA9OOBMA7yNGNlO+d94V UZiKgNQtAoBNm4hZh2M86nsUtem+WpMTZQnDnCpMLYvFV/u9jRQBFSR+Ay41hcEN WYuLK61rkjc9gPWSjeNNT28x8RMvFJU4YNn1UDiMRSzrigxeui6MOW3SI/h3y6tI 94yXmXV2IuDMibvOjK07nkDaEItqPxfj6zuM2xW1Nc+l8Sk12korFBpk/AZiD0Jo R3u36efci3zNqDRDJvhGUv8sGcv0mwO7Agq1Bm3h5941gYwzQKILHCShL7DPzvQa h+K1MsT7vWfh5++unkGUrN/Zd9CazEylbDuWtywK8lgQcTGDO/9rab8GeXfH/5es Tp0RGJwxmalgrAHZPK9lqgpQaGw92ct2G5odvc82EXQhgccnN9mh54BHPfdKs95E JZVrXtZH3Gtgl5MGZ+yJevWSc9h1iRnRF4a7QC3UlVBjA/9yAWzQUAnNGZOamE/s F+pi89oWLn8= =UsTi -----END PGP SIGNATURE----- Merge tag 'pull-request-2022-07-07' of https://gitlab.com/thuth/qemu into staging * Check validity of the address in the SET PREFIX instruction * Fix booting from devices that use 4k sectors, but are not like DASDs * Re-evaluate pending interrupts after EXECUTE of certain instructions # -----BEGIN PGP SIGNATURE----- # # iQJFBAABCAAvFiEEJ7iIR+7gJQEY8+q5LtnXdP5wLbUFAmLGhkURHHRodXRoQHJl # ZGhhdC5jb20ACgkQLtnXdP5wLbU76Q//Y4mEXxWZDpJTg7tL5SZP+UzBVttnCifv # 6q+2I0keOUs6wFhPq8TzBqkazT9wlv51cNrY2Q3fU9I3dpDeRbAXZR34UD4kw5an # Q+ZQcebuGSKLjzMrIb1DLAieq8OmZR5FvDUu16BbeJr6GIQIE80lMRfWh9j30UfW # tlxkXr15BnyPx6m0rSGwzkZD2vgfj5zSUrDtYJcUsfypIA9OOBMA7yNGNlO+d94V # UZiKgNQtAoBNm4hZh2M86nsUtem+WpMTZQnDnCpMLYvFV/u9jRQBFSR+Ay41hcEN # WYuLK61rkjc9gPWSjeNNT28x8RMvFJU4YNn1UDiMRSzrigxeui6MOW3SI/h3y6tI # 94yXmXV2IuDMibvOjK07nkDaEItqPxfj6zuM2xW1Nc+l8Sk12korFBpk/AZiD0Jo # R3u36efci3zNqDRDJvhGUv8sGcv0mwO7Agq1Bm3h5941gYwzQKILHCShL7DPzvQa # h+K1MsT7vWfh5++unkGUrN/Zd9CazEylbDuWtywK8lgQcTGDO/9rab8GeXfH/5es # Tp0RGJwxmalgrAHZPK9lqgpQaGw92ct2G5odvc82EXQhgccnN9mh54BHPfdKs95E # JZVrXtZH3Gtgl5MGZ+yJevWSc9h1iRnRF4a7QC3UlVBjA/9yAWzQUAnNGZOamE/s # F+pi89oWLn8= # =UsTi # -----END PGP SIGNATURE----- # gpg: Signature made Thu 07 Jul 2022 12:37:49 PM +0530 # gpg: using RSA key 27B88847EEE0250118F3EAB92ED9D774FE702DB5 # gpg: issuer "thuth@redhat.com" # gpg: Good signature from "Thomas Huth <th.huth@gmx.de>" [undefined] # gpg: aka "Thomas Huth <thuth@redhat.com>" [undefined] # gpg: aka "Thomas Huth <th.huth@posteo.de>" [unknown] # gpg: aka "Thomas Huth <huth@tuxfamily.org>" [undefined] # gpg: WARNING: This key is not certified with a trusted signature! # gpg: There is no indication that the signature belongs to the owner. # Primary key fingerprint: 27B8 8847 EEE0 2501 18F3 EAB9 2ED9 D774 FE70 2DB5 * tag 'pull-request-2022-07-07' of https://gitlab.com/thuth/qemu: target/s390x: Exit tb after executing ex_value target/s390x: Remove DISAS_PC_STALE_NOCHAIN target/s390x: Remove DISAS_PC_STALE target/s390x: Remove DISAS_GOTO_TB pc-bios/s390-ccw: Update the s390-ccw bios binaries with the virtio-blk fixes pc-bios/s390-ccw/netboot.mak: Ignore Clang's warnings about GNU extensions pc-bios/s390-ccw/virtio: Remove "extern" keyword from prototypes pc-bios/s390-ccw/virtio-blkdev: Request the right feature bits pc-bios/s390-ccw: Split virtio-scsi code from virtio_blk_setup_device() pc-bios/s390-ccw/virtio: Beautify the code for reading virtqueue configuration pc-bios/s390-ccw/virtio: Read device config after feature negotiation pc-bios/s390-ccw/virtio: Set missing status bits while initializing pc-bios/s390-ccw/virtio-blkdev: Remove virtio_assume_scsi() pc-bios/s390-ccw/virtio-blkdev: Simplify/fix virtio_ipl_disk_is_valid() pc-bios/s390-ccw/bootmap: Improve the guessing logic in zipl_load_vblk() pc-bios/s390-ccw/virtio: Introduce a macro for the DASD block size pc-bios/s390-ccw: Add a proper prototype for main() target/s390x/tcg: SPX: check validity of new prefix Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
This commit is contained in:
commit
212267df2b
Binary file not shown.
|
@ -780,18 +780,37 @@ static void ipl_iso_el_torito(void)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Detect whether we're trying to boot from an .ISO image.
|
||||||
|
* These always have a signature string "CD001" at offset 0x8001.
|
||||||
|
*/
|
||||||
|
static bool has_iso_signature(void)
|
||||||
|
{
|
||||||
|
int blksize = virtio_get_block_size();
|
||||||
|
|
||||||
|
if (!blksize || virtio_read(0x8000 / blksize, sec)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return !memcmp("CD001", &sec[1], 5);
|
||||||
|
}
|
||||||
|
|
||||||
/***********************************************************************
|
/***********************************************************************
|
||||||
* Bus specific IPL sequences
|
* Bus specific IPL sequences
|
||||||
*/
|
*/
|
||||||
|
|
||||||
static void zipl_load_vblk(void)
|
static void zipl_load_vblk(void)
|
||||||
{
|
{
|
||||||
if (virtio_guessed_disk_nature()) {
|
int blksize = virtio_get_block_size();
|
||||||
virtio_assume_iso9660();
|
|
||||||
}
|
|
||||||
ipl_iso_el_torito();
|
|
||||||
|
|
||||||
if (virtio_guessed_disk_nature()) {
|
if (blksize == VIRTIO_ISO_BLOCK_SIZE || has_iso_signature()) {
|
||||||
|
if (blksize != VIRTIO_ISO_BLOCK_SIZE) {
|
||||||
|
virtio_assume_iso9660();
|
||||||
|
}
|
||||||
|
ipl_iso_el_torito();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (blksize != VIRTIO_DASD_DEFAULT_BLOCK_SIZE) {
|
||||||
sclp_print("Using guessed DASD geometry.\n");
|
sclp_print("Using guessed DASD geometry.\n");
|
||||||
virtio_assume_eckd();
|
virtio_assume_eckd();
|
||||||
}
|
}
|
||||||
|
|
|
@ -14,6 +14,7 @@
|
||||||
#include "s390-ccw.h"
|
#include "s390-ccw.h"
|
||||||
#include "cio.h"
|
#include "cio.h"
|
||||||
#include "virtio.h"
|
#include "virtio.h"
|
||||||
|
#include "virtio-scsi.h"
|
||||||
#include "dasd-ipl.h"
|
#include "dasd-ipl.h"
|
||||||
|
|
||||||
char stack[PAGE_SIZE * 8] __attribute__((__aligned__(PAGE_SIZE)));
|
char stack[PAGE_SIZE * 8] __attribute__((__aligned__(PAGE_SIZE)));
|
||||||
|
@ -218,6 +219,7 @@ static int virtio_setup(void)
|
||||||
{
|
{
|
||||||
VDev *vdev = virtio_get_device();
|
VDev *vdev = virtio_get_device();
|
||||||
QemuIplParameters *early_qipl = (QemuIplParameters *)QIPL_ADDRESS;
|
QemuIplParameters *early_qipl = (QemuIplParameters *)QIPL_ADDRESS;
|
||||||
|
int ret;
|
||||||
|
|
||||||
memcpy(&qipl, early_qipl, sizeof(QemuIplParameters));
|
memcpy(&qipl, early_qipl, sizeof(QemuIplParameters));
|
||||||
|
|
||||||
|
@ -225,18 +227,26 @@ static int virtio_setup(void)
|
||||||
menu_setup();
|
menu_setup();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (virtio_get_device_type() == VIRTIO_ID_NET) {
|
switch (vdev->senseid.cu_model) {
|
||||||
|
case VIRTIO_ID_NET:
|
||||||
sclp_print("Network boot device detected\n");
|
sclp_print("Network boot device detected\n");
|
||||||
vdev->netboot_start_addr = qipl.netboot_start_addr;
|
vdev->netboot_start_addr = qipl.netboot_start_addr;
|
||||||
} else {
|
return 0;
|
||||||
int ret = virtio_blk_setup_device(blk_schid);
|
case VIRTIO_ID_BLOCK:
|
||||||
if (ret) {
|
ret = virtio_blk_setup_device(blk_schid);
|
||||||
return ret;
|
break;
|
||||||
}
|
case VIRTIO_ID_SCSI:
|
||||||
|
ret = virtio_scsi_setup_device(blk_schid);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
panic("\n! No IPL device available !\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!ret) {
|
||||||
IPL_assert(virtio_ipl_disk_is_valid(), "No valid IPL device detected");
|
IPL_assert(virtio_ipl_disk_is_valid(), "No valid IPL device detected");
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void ipl_boot_device(void)
|
static void ipl_boot_device(void)
|
||||||
|
@ -281,7 +291,7 @@ static void probe_boot_device(void)
|
||||||
sclp_print("Could not find a suitable boot device (none specified)\n");
|
sclp_print("Could not find a suitable boot device (none specified)\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
int main(void)
|
void main(void)
|
||||||
{
|
{
|
||||||
sclp_setup();
|
sclp_setup();
|
||||||
css_setup();
|
css_setup();
|
||||||
|
@ -294,5 +304,4 @@ int main(void)
|
||||||
}
|
}
|
||||||
|
|
||||||
panic("Failed to load OS from hard disk\n");
|
panic("Failed to load OS from hard disk\n");
|
||||||
return 0; /* make compiler happy */
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -16,9 +16,12 @@ s390-netboot.elf: $(NETOBJS) libnet.a libc.a
|
||||||
s390-netboot.img: s390-netboot.elf
|
s390-netboot.img: s390-netboot.elf
|
||||||
$(call quiet-command,$(STRIP) --strip-unneeded $< -o $@,"STRIP","$(TARGET_DIR)$@")
|
$(call quiet-command,$(STRIP) --strip-unneeded $< -o $@,"STRIP","$(TARGET_DIR)$@")
|
||||||
|
|
||||||
|
# SLOF is GCC-only, so ignore warnings about GNU extensions with Clang here
|
||||||
|
NO_GNU_WARN := $(call cc-option,-Werror $(QEMU_CFLAGS),-Wno-gnu)
|
||||||
|
|
||||||
# libc files:
|
# libc files:
|
||||||
|
|
||||||
LIBC_CFLAGS = $(QEMU_CFLAGS) $(CFLAGS) $(LIBC_INC) $(LIBNET_INC) \
|
LIBC_CFLAGS = $(QEMU_CFLAGS) $(CFLAGS) $(NO_GNU_WARN) $(LIBC_INC) $(LIBNET_INC) \
|
||||||
-MMD -MP -MT $@ -MF $(@:%.o=%.d)
|
-MMD -MP -MT $@ -MF $(@:%.o=%.d)
|
||||||
|
|
||||||
CTYPE_OBJS = isdigit.o isxdigit.o toupper.o
|
CTYPE_OBJS = isdigit.o isxdigit.o toupper.o
|
||||||
|
@ -52,7 +55,7 @@ libc.a: $(LIBCOBJS)
|
||||||
|
|
||||||
LIBNETOBJS := args.o dhcp.o dns.o icmpv6.o ipv6.o tcp.o udp.o bootp.o \
|
LIBNETOBJS := args.o dhcp.o dns.o icmpv6.o ipv6.o tcp.o udp.o bootp.o \
|
||||||
dhcpv6.o ethernet.o ipv4.o ndp.o tftp.o pxelinux.o
|
dhcpv6.o ethernet.o ipv4.o ndp.o tftp.o pxelinux.o
|
||||||
LIBNETCFLAGS = $(QEMU_CFLAGS) $(CFLAGS) $(LIBC_INC) $(LIBNET_INC) \
|
LIBNETCFLAGS = $(QEMU_CFLAGS) $(CFLAGS) $(NO_GNU_WARN) $(LIBC_INC) $(LIBNET_INC) \
|
||||||
-DDHCPARCH=0x1F -MMD -MP -MT $@ -MF $(@:%.o=%.d)
|
-DDHCPARCH=0x1F -MMD -MP -MT $@ -MF $(@:%.o=%.d)
|
||||||
|
|
||||||
%.o : $(SLOF_DIR)/lib/libnet/%.c
|
%.o : $(SLOF_DIR)/lib/libnet/%.c
|
||||||
|
|
|
@ -57,6 +57,7 @@ void write_subsystem_identification(void);
|
||||||
void write_iplb_location(void);
|
void write_iplb_location(void);
|
||||||
extern char stack[PAGE_SIZE * 8] __attribute__((__aligned__(PAGE_SIZE)));
|
extern char stack[PAGE_SIZE * 8] __attribute__((__aligned__(PAGE_SIZE)));
|
||||||
unsigned int get_loadparm_index(void);
|
unsigned int get_loadparm_index(void);
|
||||||
|
void main(void);
|
||||||
|
|
||||||
/* sclp.c */
|
/* sclp.c */
|
||||||
void sclp_print(const char *string);
|
void sclp_print(const char *string);
|
||||||
|
|
|
@ -13,6 +13,9 @@
|
||||||
#include "virtio.h"
|
#include "virtio.h"
|
||||||
#include "virtio-scsi.h"
|
#include "virtio-scsi.h"
|
||||||
|
|
||||||
|
#define VIRTIO_BLK_F_GEOMETRY (1 << 4)
|
||||||
|
#define VIRTIO_BLK_F_BLK_SIZE (1 << 6)
|
||||||
|
|
||||||
static int virtio_blk_read_many(VDev *vdev, ulong sector, void *load_addr,
|
static int virtio_blk_read_many(VDev *vdev, ulong sector, void *load_addr,
|
||||||
int sec_num)
|
int sec_num)
|
||||||
{
|
{
|
||||||
|
@ -112,23 +115,6 @@ VirtioGDN virtio_guessed_disk_nature(void)
|
||||||
return virtio_get_device()->guessed_disk_nature;
|
return virtio_get_device()->guessed_disk_nature;
|
||||||
}
|
}
|
||||||
|
|
||||||
void virtio_assume_scsi(void)
|
|
||||||
{
|
|
||||||
VDev *vdev = virtio_get_device();
|
|
||||||
|
|
||||||
switch (vdev->senseid.cu_model) {
|
|
||||||
case VIRTIO_ID_BLOCK:
|
|
||||||
vdev->guessed_disk_nature = VIRTIO_GDN_SCSI;
|
|
||||||
vdev->config.blk.blk_size = VIRTIO_SCSI_BLOCK_SIZE;
|
|
||||||
vdev->config.blk.physical_block_exp = 0;
|
|
||||||
vdev->blk_factor = 1;
|
|
||||||
break;
|
|
||||||
case VIRTIO_ID_SCSI:
|
|
||||||
vdev->scsi_block_size = VIRTIO_SCSI_BLOCK_SIZE;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void virtio_assume_iso9660(void)
|
void virtio_assume_iso9660(void)
|
||||||
{
|
{
|
||||||
VDev *vdev = virtio_get_device();
|
VDev *vdev = virtio_get_device();
|
||||||
|
@ -155,7 +141,7 @@ void virtio_assume_eckd(void)
|
||||||
vdev->config.blk.physical_block_exp = 0;
|
vdev->config.blk.physical_block_exp = 0;
|
||||||
switch (vdev->senseid.cu_model) {
|
switch (vdev->senseid.cu_model) {
|
||||||
case VIRTIO_ID_BLOCK:
|
case VIRTIO_ID_BLOCK:
|
||||||
vdev->config.blk.blk_size = 4096;
|
vdev->config.blk.blk_size = VIRTIO_DASD_DEFAULT_BLOCK_SIZE;
|
||||||
break;
|
break;
|
||||||
case VIRTIO_ID_SCSI:
|
case VIRTIO_ID_SCSI:
|
||||||
vdev->config.blk.blk_size = vdev->scsi_block_size;
|
vdev->config.blk.blk_size = vdev->scsi_block_size;
|
||||||
|
@ -166,46 +152,19 @@ void virtio_assume_eckd(void)
|
||||||
virtio_eckd_sectors_for_block_size(vdev->config.blk.blk_size);
|
virtio_eckd_sectors_for_block_size(vdev->config.blk.blk_size);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool virtio_disk_is_scsi(void)
|
|
||||||
{
|
|
||||||
VDev *vdev = virtio_get_device();
|
|
||||||
|
|
||||||
if (vdev->guessed_disk_nature == VIRTIO_GDN_SCSI) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
switch (vdev->senseid.cu_model) {
|
|
||||||
case VIRTIO_ID_BLOCK:
|
|
||||||
return (vdev->config.blk.geometry.heads == 255)
|
|
||||||
&& (vdev->config.blk.geometry.sectors == 63)
|
|
||||||
&& (virtio_get_block_size() == VIRTIO_SCSI_BLOCK_SIZE);
|
|
||||||
case VIRTIO_ID_SCSI:
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool virtio_disk_is_eckd(void)
|
|
||||||
{
|
|
||||||
VDev *vdev = virtio_get_device();
|
|
||||||
const int block_size = virtio_get_block_size();
|
|
||||||
|
|
||||||
if (vdev->guessed_disk_nature == VIRTIO_GDN_DASD) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
switch (vdev->senseid.cu_model) {
|
|
||||||
case VIRTIO_ID_BLOCK:
|
|
||||||
return (vdev->config.blk.geometry.heads == 15)
|
|
||||||
&& (vdev->config.blk.geometry.sectors ==
|
|
||||||
virtio_eckd_sectors_for_block_size(block_size));
|
|
||||||
case VIRTIO_ID_SCSI:
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool virtio_ipl_disk_is_valid(void)
|
bool virtio_ipl_disk_is_valid(void)
|
||||||
{
|
{
|
||||||
return virtio_disk_is_scsi() || virtio_disk_is_eckd();
|
int blksize = virtio_get_block_size();
|
||||||
|
VDev *vdev = virtio_get_device();
|
||||||
|
|
||||||
|
if (vdev->guessed_disk_nature == VIRTIO_GDN_SCSI ||
|
||||||
|
vdev->guessed_disk_nature == VIRTIO_GDN_DASD) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return (vdev->senseid.cu_model == VIRTIO_ID_BLOCK ||
|
||||||
|
vdev->senseid.cu_model == VIRTIO_ID_SCSI) &&
|
||||||
|
blksize >= 512 && blksize <= 4096;
|
||||||
}
|
}
|
||||||
|
|
||||||
int virtio_get_block_size(void)
|
int virtio_get_block_size(void)
|
||||||
|
@ -266,34 +225,12 @@ uint64_t virtio_get_blocks(void)
|
||||||
int virtio_blk_setup_device(SubChannelId schid)
|
int virtio_blk_setup_device(SubChannelId schid)
|
||||||
{
|
{
|
||||||
VDev *vdev = virtio_get_device();
|
VDev *vdev = virtio_get_device();
|
||||||
int ret = 0;
|
|
||||||
|
|
||||||
|
vdev->guest_features[0] = VIRTIO_BLK_F_GEOMETRY | VIRTIO_BLK_F_BLK_SIZE;
|
||||||
vdev->schid = schid;
|
vdev->schid = schid;
|
||||||
virtio_setup_ccw(vdev);
|
virtio_setup_ccw(vdev);
|
||||||
|
|
||||||
switch (vdev->senseid.cu_model) {
|
sclp_print("Using virtio-blk.\n");
|
||||||
case VIRTIO_ID_BLOCK:
|
|
||||||
sclp_print("Using virtio-blk.\n");
|
|
||||||
if (!virtio_ipl_disk_is_valid()) {
|
|
||||||
/* make sure all getters but blocksize return 0 for
|
|
||||||
* invalid IPL disk
|
|
||||||
*/
|
|
||||||
memset(&vdev->config.blk, 0, sizeof(vdev->config.blk));
|
|
||||||
virtio_assume_scsi();
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case VIRTIO_ID_SCSI:
|
|
||||||
IPL_assert(vdev->config.scsi.sense_size == VIRTIO_SCSI_SENSE_SIZE,
|
|
||||||
"Config: sense size mismatch");
|
|
||||||
IPL_assert(vdev->config.scsi.cdb_size == VIRTIO_SCSI_CDB_SIZE,
|
|
||||||
"Config: CDB size mismatch");
|
|
||||||
|
|
||||||
sclp_print("Using virtio-scsi.\n");
|
return 0;
|
||||||
ret = virtio_scsi_setup(vdev);
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
panic("\n! No IPL device available !\n");
|
|
||||||
}
|
|
||||||
|
|
||||||
return ret;
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -329,7 +329,7 @@ static void scsi_parse_capacity_report(void *data,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
int virtio_scsi_setup(VDev *vdev)
|
static int virtio_scsi_setup(VDev *vdev)
|
||||||
{
|
{
|
||||||
int retry_test_unit_ready = 3;
|
int retry_test_unit_ready = 3;
|
||||||
uint8_t data[256];
|
uint8_t data[256];
|
||||||
|
@ -430,3 +430,20 @@ int virtio_scsi_setup(VDev *vdev)
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int virtio_scsi_setup_device(SubChannelId schid)
|
||||||
|
{
|
||||||
|
VDev *vdev = virtio_get_device();
|
||||||
|
|
||||||
|
vdev->schid = schid;
|
||||||
|
virtio_setup_ccw(vdev);
|
||||||
|
|
||||||
|
IPL_assert(vdev->config.scsi.sense_size == VIRTIO_SCSI_SENSE_SIZE,
|
||||||
|
"Config: sense size mismatch");
|
||||||
|
IPL_assert(vdev->config.scsi.cdb_size == VIRTIO_SCSI_CDB_SIZE,
|
||||||
|
"Config: CDB size mismatch");
|
||||||
|
|
||||||
|
sclp_print("Using virtio-scsi.\n");
|
||||||
|
|
||||||
|
return virtio_scsi_setup(vdev);
|
||||||
|
}
|
||||||
|
|
|
@ -67,8 +67,8 @@ static inline bool virtio_scsi_response_ok(const VirtioScsiCmdResp *r)
|
||||||
return r->response == VIRTIO_SCSI_S_OK && r->status == CDB_STATUS_GOOD;
|
return r->response == VIRTIO_SCSI_S_OK && r->status == CDB_STATUS_GOOD;
|
||||||
}
|
}
|
||||||
|
|
||||||
int virtio_scsi_setup(VDev *vdev);
|
|
||||||
int virtio_scsi_read_many(VDev *vdev,
|
int virtio_scsi_read_many(VDev *vdev,
|
||||||
ulong sector, void *load_addr, int sec_num);
|
ulong sector, void *load_addr, int sec_num);
|
||||||
|
int virtio_scsi_setup_device(SubChannelId schid);
|
||||||
|
|
||||||
#endif /* VIRTIO_SCSI_H */
|
#endif /* VIRTIO_SCSI_H */
|
||||||
|
|
|
@ -220,7 +220,7 @@ int virtio_run(VDev *vdev, int vqid, VirtioCmd *cmd)
|
||||||
void virtio_setup_ccw(VDev *vdev)
|
void virtio_setup_ccw(VDev *vdev)
|
||||||
{
|
{
|
||||||
int i, rc, cfg_size = 0;
|
int i, rc, cfg_size = 0;
|
||||||
unsigned char status = VIRTIO_CONFIG_S_DRIVER_OK;
|
uint8_t status;
|
||||||
struct VirtioFeatureDesc {
|
struct VirtioFeatureDesc {
|
||||||
uint32_t features;
|
uint32_t features;
|
||||||
uint8_t index;
|
uint8_t index;
|
||||||
|
@ -234,6 +234,10 @@ void virtio_setup_ccw(VDev *vdev)
|
||||||
|
|
||||||
run_ccw(vdev, CCW_CMD_VDEV_RESET, NULL, 0, false);
|
run_ccw(vdev, CCW_CMD_VDEV_RESET, NULL, 0, false);
|
||||||
|
|
||||||
|
status = VIRTIO_CONFIG_S_ACKNOWLEDGE;
|
||||||
|
rc = run_ccw(vdev, CCW_CMD_WRITE_STATUS, &status, sizeof(status), false);
|
||||||
|
IPL_assert(rc == 0, "Could not write ACKNOWLEDGE status to host");
|
||||||
|
|
||||||
switch (vdev->senseid.cu_model) {
|
switch (vdev->senseid.cu_model) {
|
||||||
case VIRTIO_ID_NET:
|
case VIRTIO_ID_NET:
|
||||||
vdev->nr_vqs = 2;
|
vdev->nr_vqs = 2;
|
||||||
|
@ -253,9 +257,10 @@ void virtio_setup_ccw(VDev *vdev)
|
||||||
default:
|
default:
|
||||||
panic("Unsupported virtio device\n");
|
panic("Unsupported virtio device\n");
|
||||||
}
|
}
|
||||||
IPL_assert(
|
|
||||||
run_ccw(vdev, CCW_CMD_READ_CONF, &vdev->config, cfg_size, false) == 0,
|
status |= VIRTIO_CONFIG_S_DRIVER;
|
||||||
"Could not get block device configuration");
|
rc = run_ccw(vdev, CCW_CMD_WRITE_STATUS, &status, sizeof(status), false);
|
||||||
|
IPL_assert(rc == 0, "Could not write DRIVER status to host");
|
||||||
|
|
||||||
/* Feature negotiation */
|
/* Feature negotiation */
|
||||||
for (i = 0; i < ARRAY_SIZE(vdev->guest_features); i++) {
|
for (i = 0; i < ARRAY_SIZE(vdev->guest_features); i++) {
|
||||||
|
@ -269,6 +274,9 @@ void virtio_setup_ccw(VDev *vdev)
|
||||||
IPL_assert(rc == 0, "Could not set features bits");
|
IPL_assert(rc == 0, "Could not set features bits");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
rc = run_ccw(vdev, CCW_CMD_READ_CONF, &vdev->config, cfg_size, false);
|
||||||
|
IPL_assert(rc == 0, "Could not get virtio device configuration");
|
||||||
|
|
||||||
for (i = 0; i < vdev->nr_vqs; i++) {
|
for (i = 0; i < vdev->nr_vqs; i++) {
|
||||||
VqInfo info = {
|
VqInfo info = {
|
||||||
.queue = (unsigned long long) ring_area + (i * VIRTIO_RING_SIZE),
|
.queue = (unsigned long long) ring_area + (i * VIRTIO_RING_SIZE),
|
||||||
|
@ -281,9 +289,8 @@ void virtio_setup_ccw(VDev *vdev)
|
||||||
.num = 0,
|
.num = 0,
|
||||||
};
|
};
|
||||||
|
|
||||||
IPL_assert(
|
rc = run_ccw(vdev, CCW_CMD_READ_VQ_CONF, &config, sizeof(config), false);
|
||||||
run_ccw(vdev, CCW_CMD_READ_VQ_CONF, &config, sizeof(config), false) == 0,
|
IPL_assert(rc == 0, "Could not get virtio device VQ configuration");
|
||||||
"Could not get block device VQ configuration");
|
|
||||||
info.num = config.num;
|
info.num = config.num;
|
||||||
vring_init(&vdev->vrings[i], &info);
|
vring_init(&vdev->vrings[i], &info);
|
||||||
vdev->vrings[i].schid = vdev->schid;
|
vdev->vrings[i].schid = vdev->schid;
|
||||||
|
@ -291,9 +298,10 @@ void virtio_setup_ccw(VDev *vdev)
|
||||||
run_ccw(vdev, CCW_CMD_SET_VQ, &info, sizeof(info), false) == 0,
|
run_ccw(vdev, CCW_CMD_SET_VQ, &info, sizeof(info), false) == 0,
|
||||||
"Cannot set VQ info");
|
"Cannot set VQ info");
|
||||||
}
|
}
|
||||||
IPL_assert(
|
|
||||||
run_ccw(vdev, CCW_CMD_WRITE_STATUS, &status, sizeof(status), false) == 0,
|
status |= VIRTIO_CONFIG_S_DRIVER_OK;
|
||||||
"Could not write status to host");
|
rc = run_ccw(vdev, CCW_CMD_WRITE_STATUS, &status, sizeof(status), false);
|
||||||
|
IPL_assert(rc == 0, "Could not write DRIVER_OK status to host");
|
||||||
}
|
}
|
||||||
|
|
||||||
bool virtio_is_supported(SubChannelId schid)
|
bool virtio_is_supported(SubChannelId schid)
|
||||||
|
|
|
@ -182,22 +182,20 @@ enum guessed_disk_nature_type {
|
||||||
typedef enum guessed_disk_nature_type VirtioGDN;
|
typedef enum guessed_disk_nature_type VirtioGDN;
|
||||||
|
|
||||||
VirtioGDN virtio_guessed_disk_nature(void);
|
VirtioGDN virtio_guessed_disk_nature(void);
|
||||||
void virtio_assume_scsi(void);
|
|
||||||
void virtio_assume_eckd(void);
|
void virtio_assume_eckd(void);
|
||||||
void virtio_assume_iso9660(void);
|
void virtio_assume_iso9660(void);
|
||||||
|
|
||||||
extern bool virtio_disk_is_scsi(void);
|
bool virtio_ipl_disk_is_valid(void);
|
||||||
extern bool virtio_disk_is_eckd(void);
|
int virtio_get_block_size(void);
|
||||||
extern bool virtio_ipl_disk_is_valid(void);
|
uint8_t virtio_get_heads(void);
|
||||||
extern int virtio_get_block_size(void);
|
uint8_t virtio_get_sectors(void);
|
||||||
extern uint8_t virtio_get_heads(void);
|
uint64_t virtio_get_blocks(void);
|
||||||
extern uint8_t virtio_get_sectors(void);
|
int virtio_read_many(ulong sector, void *load_addr, int sec_num);
|
||||||
extern uint64_t virtio_get_blocks(void);
|
|
||||||
extern int virtio_read_many(ulong sector, void *load_addr, int sec_num);
|
|
||||||
|
|
||||||
#define VIRTIO_SECTOR_SIZE 512
|
#define VIRTIO_SECTOR_SIZE 512
|
||||||
#define VIRTIO_ISO_BLOCK_SIZE 2048
|
#define VIRTIO_ISO_BLOCK_SIZE 2048
|
||||||
#define VIRTIO_SCSI_BLOCK_SIZE 512
|
#define VIRTIO_SCSI_BLOCK_SIZE 512
|
||||||
|
#define VIRTIO_DASD_DEFAULT_BLOCK_SIZE 4096
|
||||||
|
|
||||||
static inline ulong virtio_sector_adjust(ulong sector)
|
static inline ulong virtio_sector_adjust(ulong sector)
|
||||||
{
|
{
|
||||||
|
|
Binary file not shown.
|
@ -158,6 +158,13 @@ void HELPER(spx)(CPUS390XState *env, uint64_t a1)
|
||||||
if (prefix == old_prefix) {
|
if (prefix == old_prefix) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
/*
|
||||||
|
* Since prefix got aligned to 8k and memory increments are a multiple of
|
||||||
|
* 8k checking the first page is sufficient
|
||||||
|
*/
|
||||||
|
if (!mmu_absolute_addr_valid(prefix, true)) {
|
||||||
|
tcg_s390_program_interrupt(env, PGM_ADDRESSING, GETPC());
|
||||||
|
}
|
||||||
|
|
||||||
env->psa = prefix;
|
env->psa = prefix;
|
||||||
HELPER_LOG("prefix: %#x\n", prefix);
|
HELPER_LOG("prefix: %#x\n", prefix);
|
||||||
|
|
|
@ -149,6 +149,7 @@ struct DisasContext {
|
||||||
uint64_t pc_tmp;
|
uint64_t pc_tmp;
|
||||||
uint32_t ilen;
|
uint32_t ilen;
|
||||||
enum cc_op cc_op;
|
enum cc_op cc_op;
|
||||||
|
bool exit_to_mainloop;
|
||||||
};
|
};
|
||||||
|
|
||||||
/* Information carried about a condition to be evaluated. */
|
/* Information carried about a condition to be evaluated. */
|
||||||
|
@ -1123,19 +1124,9 @@ typedef struct {
|
||||||
exiting the TB. */
|
exiting the TB. */
|
||||||
#define DISAS_PC_UPDATED DISAS_TARGET_0
|
#define DISAS_PC_UPDATED DISAS_TARGET_0
|
||||||
|
|
||||||
/* We have emitted one or more goto_tb. No fixup required. */
|
|
||||||
#define DISAS_GOTO_TB DISAS_TARGET_1
|
|
||||||
|
|
||||||
/* We have updated the PC and CC values. */
|
/* We have updated the PC and CC values. */
|
||||||
#define DISAS_PC_CC_UPDATED DISAS_TARGET_2
|
#define DISAS_PC_CC_UPDATED DISAS_TARGET_2
|
||||||
|
|
||||||
/* We are exiting the TB, but have neither emitted a goto_tb, nor
|
|
||||||
updated the PC for the next instruction to be executed. */
|
|
||||||
#define DISAS_PC_STALE DISAS_TARGET_3
|
|
||||||
|
|
||||||
/* We are exiting the TB to the main loop. */
|
|
||||||
#define DISAS_PC_STALE_NOCHAIN DISAS_TARGET_4
|
|
||||||
|
|
||||||
|
|
||||||
/* Instruction flags */
|
/* Instruction flags */
|
||||||
#define IF_AFP1 0x0001 /* r1 is a fp reg for HFP/FPS instructions */
|
#define IF_AFP1 0x0001 /* r1 is a fp reg for HFP/FPS instructions */
|
||||||
|
@ -1189,7 +1180,7 @@ static DisasJumpType help_goto_direct(DisasContext *s, uint64_t dest)
|
||||||
tcg_gen_goto_tb(0);
|
tcg_gen_goto_tb(0);
|
||||||
tcg_gen_movi_i64(psw_addr, dest);
|
tcg_gen_movi_i64(psw_addr, dest);
|
||||||
tcg_gen_exit_tb(s->base.tb, 0);
|
tcg_gen_exit_tb(s->base.tb, 0);
|
||||||
return DISAS_GOTO_TB;
|
return DISAS_NORETURN;
|
||||||
} else {
|
} else {
|
||||||
tcg_gen_movi_i64(psw_addr, dest);
|
tcg_gen_movi_i64(psw_addr, dest);
|
||||||
per_branch(s, false);
|
per_branch(s, false);
|
||||||
|
@ -1258,7 +1249,7 @@ static DisasJumpType help_branch(DisasContext *s, DisasCompare *c,
|
||||||
tcg_gen_movi_i64(psw_addr, dest);
|
tcg_gen_movi_i64(psw_addr, dest);
|
||||||
tcg_gen_exit_tb(s->base.tb, 1);
|
tcg_gen_exit_tb(s->base.tb, 1);
|
||||||
|
|
||||||
ret = DISAS_GOTO_TB;
|
ret = DISAS_NORETURN;
|
||||||
} else {
|
} else {
|
||||||
/* Fallthru can use goto_tb, but taken branch cannot. */
|
/* Fallthru can use goto_tb, but taken branch cannot. */
|
||||||
/* Store taken branch destination before the brcond. This
|
/* Store taken branch destination before the brcond. This
|
||||||
|
@ -3029,7 +3020,8 @@ static DisasJumpType op_lctl(DisasContext *s, DisasOps *o)
|
||||||
tcg_temp_free_i32(r1);
|
tcg_temp_free_i32(r1);
|
||||||
tcg_temp_free_i32(r3);
|
tcg_temp_free_i32(r3);
|
||||||
/* Exit to main loop to reevaluate s390_cpu_exec_interrupt. */
|
/* Exit to main loop to reevaluate s390_cpu_exec_interrupt. */
|
||||||
return DISAS_PC_STALE_NOCHAIN;
|
s->exit_to_mainloop = true;
|
||||||
|
return DISAS_TOO_MANY;
|
||||||
}
|
}
|
||||||
|
|
||||||
static DisasJumpType op_lctlg(DisasContext *s, DisasOps *o)
|
static DisasJumpType op_lctlg(DisasContext *s, DisasOps *o)
|
||||||
|
@ -3040,7 +3032,8 @@ static DisasJumpType op_lctlg(DisasContext *s, DisasOps *o)
|
||||||
tcg_temp_free_i32(r1);
|
tcg_temp_free_i32(r1);
|
||||||
tcg_temp_free_i32(r3);
|
tcg_temp_free_i32(r3);
|
||||||
/* Exit to main loop to reevaluate s390_cpu_exec_interrupt. */
|
/* Exit to main loop to reevaluate s390_cpu_exec_interrupt. */
|
||||||
return DISAS_PC_STALE_NOCHAIN;
|
s->exit_to_mainloop = true;
|
||||||
|
return DISAS_TOO_MANY;
|
||||||
}
|
}
|
||||||
|
|
||||||
static DisasJumpType op_lra(DisasContext *s, DisasOps *o)
|
static DisasJumpType op_lra(DisasContext *s, DisasOps *o)
|
||||||
|
@ -3996,7 +3989,7 @@ static DisasJumpType op_sacf(DisasContext *s, DisasOps *o)
|
||||||
{
|
{
|
||||||
gen_helper_sacf(cpu_env, o->in2);
|
gen_helper_sacf(cpu_env, o->in2);
|
||||||
/* Addressing mode has changed, so end the block. */
|
/* Addressing mode has changed, so end the block. */
|
||||||
return DISAS_PC_STALE;
|
return DISAS_TOO_MANY;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
@ -4032,7 +4025,7 @@ static DisasJumpType op_sam(DisasContext *s, DisasOps *o)
|
||||||
tcg_temp_free_i64(tsam);
|
tcg_temp_free_i64(tsam);
|
||||||
|
|
||||||
/* Always exit the TB, since we (may have) changed execution mode. */
|
/* Always exit the TB, since we (may have) changed execution mode. */
|
||||||
return DISAS_PC_STALE;
|
return DISAS_TOO_MANY;
|
||||||
}
|
}
|
||||||
|
|
||||||
static DisasJumpType op_sar(DisasContext *s, DisasOps *o)
|
static DisasJumpType op_sar(DisasContext *s, DisasOps *o)
|
||||||
|
@ -4290,7 +4283,8 @@ static DisasJumpType op_ssm(DisasContext *s, DisasOps *o)
|
||||||
{
|
{
|
||||||
tcg_gen_deposit_i64(psw_mask, psw_mask, o->in2, 56, 8);
|
tcg_gen_deposit_i64(psw_mask, psw_mask, o->in2, 56, 8);
|
||||||
/* Exit to main loop to reevaluate s390_cpu_exec_interrupt. */
|
/* Exit to main loop to reevaluate s390_cpu_exec_interrupt. */
|
||||||
return DISAS_PC_STALE_NOCHAIN;
|
s->exit_to_mainloop = true;
|
||||||
|
return DISAS_TOO_MANY;
|
||||||
}
|
}
|
||||||
|
|
||||||
static DisasJumpType op_stap(DisasContext *s, DisasOps *o)
|
static DisasJumpType op_stap(DisasContext *s, DisasOps *o)
|
||||||
|
@ -4555,7 +4549,8 @@ static DisasJumpType op_stnosm(DisasContext *s, DisasOps *o)
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Exit to main loop to reevaluate s390_cpu_exec_interrupt. */
|
/* Exit to main loop to reevaluate s390_cpu_exec_interrupt. */
|
||||||
return DISAS_PC_STALE_NOCHAIN;
|
s->exit_to_mainloop = true;
|
||||||
|
return DISAS_TOO_MANY;
|
||||||
}
|
}
|
||||||
|
|
||||||
static DisasJumpType op_stura(DisasContext *s, DisasOps *o)
|
static DisasJumpType op_stura(DisasContext *s, DisasOps *o)
|
||||||
|
@ -6565,13 +6560,13 @@ static DisasJumpType translate_one(CPUS390XState *env, DisasContext *s)
|
||||||
|
|
||||||
/* io should be the last instruction in tb when icount is enabled */
|
/* io should be the last instruction in tb when icount is enabled */
|
||||||
if (unlikely(icount && ret == DISAS_NEXT)) {
|
if (unlikely(icount && ret == DISAS_NEXT)) {
|
||||||
ret = DISAS_PC_STALE;
|
ret = DISAS_TOO_MANY;
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifndef CONFIG_USER_ONLY
|
#ifndef CONFIG_USER_ONLY
|
||||||
if (s->base.tb->flags & FLAG_MASK_PER) {
|
if (s->base.tb->flags & FLAG_MASK_PER) {
|
||||||
/* An exception might be triggered, save PSW if not already done. */
|
/* An exception might be triggered, save PSW if not already done. */
|
||||||
if (ret == DISAS_NEXT || ret == DISAS_PC_STALE) {
|
if (ret == DISAS_NEXT || ret == DISAS_TOO_MANY) {
|
||||||
tcg_gen_movi_i64(psw_addr, s->pc_tmp);
|
tcg_gen_movi_i64(psw_addr, s->pc_tmp);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -6598,6 +6593,7 @@ static void s390x_tr_init_disas_context(DisasContextBase *dcbase, CPUState *cs)
|
||||||
|
|
||||||
dc->cc_op = CC_OP_DYNAMIC;
|
dc->cc_op = CC_OP_DYNAMIC;
|
||||||
dc->ex_value = dc->base.tb->cs_base;
|
dc->ex_value = dc->base.tb->cs_base;
|
||||||
|
dc->exit_to_mainloop = (dc->base.tb->flags & FLAG_MASK_PER) || dc->ex_value;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void s390x_tr_tb_start(DisasContextBase *db, CPUState *cs)
|
static void s390x_tr_tb_start(DisasContextBase *db, CPUState *cs)
|
||||||
|
@ -6634,12 +6630,9 @@ static void s390x_tr_tb_stop(DisasContextBase *dcbase, CPUState *cs)
|
||||||
DisasContext *dc = container_of(dcbase, DisasContext, base);
|
DisasContext *dc = container_of(dcbase, DisasContext, base);
|
||||||
|
|
||||||
switch (dc->base.is_jmp) {
|
switch (dc->base.is_jmp) {
|
||||||
case DISAS_GOTO_TB:
|
|
||||||
case DISAS_NORETURN:
|
case DISAS_NORETURN:
|
||||||
break;
|
break;
|
||||||
case DISAS_TOO_MANY:
|
case DISAS_TOO_MANY:
|
||||||
case DISAS_PC_STALE:
|
|
||||||
case DISAS_PC_STALE_NOCHAIN:
|
|
||||||
update_psw_addr(dc);
|
update_psw_addr(dc);
|
||||||
/* FALLTHRU */
|
/* FALLTHRU */
|
||||||
case DISAS_PC_UPDATED:
|
case DISAS_PC_UPDATED:
|
||||||
|
@ -6649,8 +6642,7 @@ static void s390x_tr_tb_stop(DisasContextBase *dcbase, CPUState *cs)
|
||||||
/* FALLTHRU */
|
/* FALLTHRU */
|
||||||
case DISAS_PC_CC_UPDATED:
|
case DISAS_PC_CC_UPDATED:
|
||||||
/* Exit the TB, either by raising a debug exception or by return. */
|
/* Exit the TB, either by raising a debug exception or by return. */
|
||||||
if ((dc->base.tb->flags & FLAG_MASK_PER) ||
|
if (dc->exit_to_mainloop) {
|
||||||
dc->base.is_jmp == DISAS_PC_STALE_NOCHAIN) {
|
|
||||||
tcg_gen_exit_tb(NULL, 0);
|
tcg_gen_exit_tb(NULL, 0);
|
||||||
} else {
|
} else {
|
||||||
tcg_gen_lookup_and_goto_ptr();
|
tcg_gen_lookup_and_goto_ptr();
|
||||||
|
|
Loading…
Reference in New Issue