Skip to content

Commit

Permalink
Merge remote-tracking branch 'remotes/cohuck/tags/s390x-20160324' int…
Browse files Browse the repository at this point in the history
…o staging

Support for booting from virtio-scsi devices in the s390-ccw bios.

# gpg: Signature made Thu 24 Mar 2016 08:14:21 GMT using RSA key ID C6F02FAF
# gpg: Good signature from "Cornelia Huck <huckc@linux.vnet.ibm.com>"
# gpg:                 aka "Cornelia Huck <cornelia.huck@de.ibm.com>"

* remotes/cohuck/tags/s390x-20160324:
  s390-ccw.img: rebuild image
  pc-bios/s390-ccw: disambiguation of "No zIPL magic" message
  pc-bios/s390-ccw: enhance bootmap detection
  pc-bios/s390-ccw: enable virtio-scsi
  pc-bios/s390-ccw: add virtio-scsi implementation
  pc-bios/s390-ccw: add scsi definitions
  pc-bios/s390-ccw: add simplified virtio call
  pc-bios/s390-ccw: make provisions for different backends
  pc-bios/s390-ccw: add vdev object to store all device details
  pc-bios/s390-ccw: update virtio implementation to allow up to 3 vrings
  pc-bios/s390-ccw: qemuize types
  pc-bios/s390-ccw: add utility functions and "export" some others
  pc-bios/s390-ccw: virtio_panic -> panic
  pc-bios/s390-ccw: add more disk layout checks

Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
  • Loading branch information
pm215 committed Mar 24, 2016
2 parents f18f2e7 + ce11b06 commit b68a801
Show file tree
Hide file tree
Showing 11 changed files with 1,220 additions and 294 deletions.
Binary file modified pc-bios/s390-ccw.img
Binary file not shown.
2 changes: 1 addition & 1 deletion pc-bios/s390-ccw/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ $(call set-vpath, $(SRC_PATH)/pc-bios/s390-ccw)

.PHONY : all clean build-all

OBJECTS = start.o main.o bootmap.o sclp-ascii.o virtio.o
OBJECTS = start.o main.o bootmap.o sclp-ascii.o virtio.o virtio-scsi.o
CFLAGS += -fPIE -fno-stack-protector -ffreestanding -march=z900
CFLAGS += -fno-delete-null-pointer-checks -msoft-float
LDFLAGS += -Wl,-pie -nostdlib
Expand Down
129 changes: 87 additions & 42 deletions pc-bios/s390-ccw/bootmap.c
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,7 @@ static void jump_to_IPL_code(uint64_t address)
asm volatile("lghi 1,1\n\t"
"diag 1,1,0x308\n\t"
: : : "1", "memory");
virtio_panic("\n! IPL returns !\n");
panic("\n! IPL returns !\n");
}

/***********************************************************************
Expand All @@ -84,7 +84,7 @@ static const int max_bprs_entries = sizeof(_bprs) / sizeof(ExtEckdBlockPtr);

static inline void verify_boot_info(BootInfo *bip)
{
IPL_assert(magic_match(bip->magic, ZIPL_MAGIC), "No zIPL magic");
IPL_assert(magic_match(bip->magic, ZIPL_MAGIC), "No zIPL sig in BootInfo");
IPL_assert(bip->version == BOOT_INFO_VERSION, "Wrong zIPL version");
IPL_assert(bip->bp_type == BOOT_INFO_BP_TYPE_IPL, "DASD is not for IPL");
IPL_assert(bip->dev_type == BOOT_INFO_DEV_TYPE_ECKD, "DASD is not ECKD");
Expand Down Expand Up @@ -315,6 +315,40 @@ static void print_eckd_msg(void)
sclp_print(msg);
}

static void ipl_eckd(void)
{
ScsiMbr *mbr = (void *)sec;
LDL_VTOC *vlbl = (void *)sec;

print_eckd_msg();

/* Grab the MBR again */
memset(sec, FREE_SPACE_FILLER, sizeof(sec));
read_block(0, mbr, "Cannot read block 0 on DASD");

if (magic_match(mbr->magic, IPL1_MAGIC)) {
ipl_eckd_cdl(); /* no return */
}

/* LDL/CMS? */
memset(sec, FREE_SPACE_FILLER, sizeof(sec));
read_block(2, vlbl, "Cannot read block 2");

if (magic_match(vlbl->magic, CMS1_MAGIC)) {
ipl_eckd_ldl(ECKD_CMS); /* no return */
}
if (magic_match(vlbl->magic, LNX1_MAGIC)) {
ipl_eckd_ldl(ECKD_LDL); /* no return */
}

ipl_eckd_ldl(ECKD_LDL_UNLABELED); /* it still may return */
/*
* Ok, it is not a LDL by any means.
* It still might be a CDL with zero record keys for IPL1 and IPL2
*/
ipl_eckd_cdl();
}

/***********************************************************************
* IPL a SCSI disk
*/
Expand Down Expand Up @@ -382,7 +416,7 @@ static void zipl_run(ScsiBlockPtr *pte)
read_block(pte->blockno, tmp_sec, "Cannot read header");
header = (ComponentHeader *)tmp_sec;

IPL_assert(magic_match(tmp_sec, ZIPL_MAGIC), "No zIPL magic");
IPL_assert(magic_match(tmp_sec, ZIPL_MAGIC), "No zIPL magic in header");
IPL_assert(header->type == ZIPL_COMP_HEADER_IPL, "Bad header type");

dputs("start loading images\n");
Expand Down Expand Up @@ -412,16 +446,26 @@ static void ipl_scsi(void)
const int pte_len = sizeof(ScsiBlockPtr);
ScsiBlockPtr *prog_table_entry;

/* The 0-th block (MBR) was already read into sec[] */
/* Grab the MBR */
memset(sec, FREE_SPACE_FILLER, sizeof(sec));
read_block(0, mbr, "Cannot read block 0");

if (!magic_match(mbr->magic, ZIPL_MAGIC)) {
return;
}

sclp_print("Using SCSI scheme.\n");
debug_print_int("MBR Version", mbr->version_id);
IPL_check(mbr->version_id == 1,
"Unknown MBR layout version, assuming version 1");
debug_print_int("program table", mbr->blockptr.blockno);
IPL_assert(mbr->blockptr.blockno, "No Program Table");

/* Parse the program table */
read_block(mbr->blockptr.blockno, sec,
"Error reading Program Table");

IPL_assert(magic_match(sec, ZIPL_MAGIC), "No zIPL magic");
IPL_assert(magic_match(sec, ZIPL_MAGIC), "No zIPL magic in PT");

ns_end = sec + virtio_get_block_size();
for (ns = (sec + pte_len); (ns + pte_len) < ns_end; ns += pte_len) {
Expand Down Expand Up @@ -613,7 +657,7 @@ static IsoBcSection *find_iso_bc_entry(void)

if (!is_iso_bc_valid(e)) {
/* The validation entry is mandatory */
virtio_panic("No valid boot catalog found!\n");
panic("No valid boot catalog found!\n");
return NULL;
}

Expand All @@ -629,7 +673,7 @@ static IsoBcSection *find_iso_bc_entry(void)
}
}

virtio_panic("No suitable boot entry found on ISO-9660 media!\n");
panic("No suitable boot entry found on ISO-9660 media!\n");

return NULL;
}
Expand All @@ -645,57 +689,58 @@ static void ipl_iso_el_torito(void)
}

/***********************************************************************
* IPL starts here
* Bus specific IPL sequences
*/

void zipl_load(void)
static void zipl_load_vblk(void)
{
ScsiMbr *mbr = (void *)sec;
LDL_VTOC *vlbl = (void *)sec;

/* Grab the MBR */
memset(sec, FREE_SPACE_FILLER, sizeof(sec));
read_block(0, mbr, "Cannot read block 0");

dputs("checking magic\n");

if (magic_match(mbr->magic, ZIPL_MAGIC)) {
ipl_scsi(); /* no return */
}

/* Check if we can boot as ISO media */
if (virtio_guessed_disk_nature()) {
virtio_assume_iso9660();
}
ipl_iso_el_torito();

/* We have failed to follow the SCSI scheme, so */
if (virtio_guessed_disk_nature()) {
sclp_print("Using guessed DASD geometry.\n");
virtio_assume_eckd();
}
print_eckd_msg();
if (magic_match(mbr->magic, IPL1_MAGIC)) {
ipl_eckd_cdl(); /* no return */
ipl_eckd();
}

static void zipl_load_vscsi(void)
{
if (virtio_get_block_size() == VIRTIO_ISO_BLOCK_SIZE) {
/* Is it an ISO image in non-CD drive? */
ipl_iso_el_torito();
}

/* LDL/CMS? */
memset(sec, FREE_SPACE_FILLER, sizeof(sec));
read_block(2, vlbl, "Cannot read block 2");
sclp_print("Using guessed DASD geometry.\n");
virtio_assume_eckd();
ipl_eckd();
}

if (magic_match(vlbl->magic, CMS1_MAGIC)) {
ipl_eckd_ldl(ECKD_CMS); /* no return */
}
if (magic_match(vlbl->magic, LNX1_MAGIC)) {
ipl_eckd_ldl(ECKD_LDL); /* no return */
/***********************************************************************
* IPL starts here
*/

void zipl_load(void)
{
if (virtio_get_device()->is_cdrom) {
ipl_iso_el_torito();
panic("\n! Cannot IPL this ISO image !\n");
}

ipl_eckd_ldl(ECKD_LDL_UNLABELED); /* it still may return */
/*
* Ok, it is not a LDL by any means.
* It still might be a CDL with zero record keys for IPL1 and IPL2
*/
ipl_eckd_cdl();
ipl_scsi();

switch (virtio_get_device_type()) {
case VIRTIO_ID_BLOCK:
zipl_load_vblk();
break;
case VIRTIO_ID_SCSI:
zipl_load_vscsi();
break;
default:
panic("\n! Unknown IPL device type !\n");
}

virtio_panic("\n* this can never happen *\n");
panic("\n* this can never happen *\n");
}
9 changes: 0 additions & 9 deletions pc-bios/s390-ccw/bootmap.h
Original file line number Diff line number Diff line change
Expand Up @@ -264,15 +264,6 @@ typedef enum {

/* utility code below */

static inline void IPL_assert(bool term, const char *message)
{
if (!term) {
sclp_print("\n! ");
sclp_print(message);
virtio_panic(" !\n"); /* no return */
}
}

static const unsigned char ebc2asc[256] =
/* 0123456789abcdef0123456789abcdef */
"................................" /* 1F */
Expand Down
25 changes: 10 additions & 15 deletions pc-bios/s390-ccw/main.c
Original file line number Diff line number Diff line change
Expand Up @@ -12,9 +12,8 @@
#include "virtio.h"

char stack[PAGE_SIZE * 8] __attribute__((__aligned__(PAGE_SIZE)));
char ring_area[PAGE_SIZE * 8] __attribute__((__aligned__(PAGE_SIZE)));
uint64_t boot_value;
static struct subchannel_id blk_schid = { .one = 1 };
static SubChannelId blk_schid = { .one = 1 };

/*
* Priniciples of Operations (SA22-7832-09) chapter 17 requires that
Expand All @@ -23,22 +22,22 @@ static struct subchannel_id blk_schid = { .one = 1 };
*/
void write_subsystem_identification(void)
{
struct subchannel_id *schid = (struct subchannel_id *) 184;
SubChannelId *schid = (SubChannelId *) 184;
uint32_t *zeroes = (uint32_t *) 188;

*schid = blk_schid;
*zeroes = 0;
}


void virtio_panic(const char *string)
void panic(const char *string)
{
sclp_print(string);
disabled_wait();
while (1) { }
}

static bool find_dev(struct schib *schib, int dev_no)
static bool find_dev(Schib *schib, int dev_no)
{
int i, r;

Expand All @@ -51,7 +50,7 @@ static bool find_dev(struct schib *schib, int dev_no)
if (!schib->pmcw.dnv) {
continue;
}
if (!virtio_is_blk(blk_schid)) {
if (!virtio_is_supported(blk_schid)) {
continue;
}
if ((dev_no < 0) || (schib->pmcw.dev == dev_no)) {
Expand All @@ -64,7 +63,7 @@ static bool find_dev(struct schib *schib, int dev_no)

static void virtio_setup(uint64_t dev_info)
{
struct schib schib;
Schib schib;
int ssid;
bool found = false;
uint16_t dev_no;
Expand Down Expand Up @@ -92,15 +91,11 @@ static void virtio_setup(uint64_t dev_info)
}
}

if (!found) {
virtio_panic("No virtio-blk device found!\n");
}
IPL_assert(found, "No virtio device found");

virtio_setup_block(blk_schid);
virtio_setup_device(blk_schid);

if (!virtio_ipl_disk_is_valid()) {
virtio_panic("No valid hard disk detected.\n");
}
IPL_assert(virtio_ipl_disk_is_valid(), "No valid IPL device detected");
}

int main(void)
Expand All @@ -111,6 +106,6 @@ int main(void)

zipl_load(); /* no return */

virtio_panic("Failed to load OS from hard disk\n");
panic("Failed to load OS from hard disk\n");
return 0; /* make compiler happy */
}
54 changes: 50 additions & 4 deletions pc-bios/s390-ccw/s390-ccw.h
Original file line number Diff line number Diff line change
Expand Up @@ -45,15 +45,22 @@ typedef unsigned long long __u64;

#include "cio.h"

typedef struct irb Irb;
typedef struct ccw1 Ccw1;
typedef struct cmd_orb CmdOrb;
typedef struct schib Schib;
typedef struct chsc_area_sda ChscAreaSda;
typedef struct senseid SenseId;
typedef struct subchannel_id SubChannelId;

/* start.s */
void disabled_wait(void);
void consume_sclp_int(void);

/* main.c */
void virtio_panic(const char *string);
void panic(const char *string);
void write_subsystem_identification(void);
extern char stack[PAGE_SIZE * 8] __attribute__((__aligned__(PAGE_SIZE)));
extern char ring_area[PAGE_SIZE * 8] __attribute__((__aligned__(PAGE_SIZE)));
extern uint64_t boot_value;

/* sclp-ascii.c */
Expand All @@ -63,10 +70,11 @@ 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);
bool virtio_is_supported(SubChannelId schid);
void virtio_setup_device(SubChannelId schid);
int virtio_read(ulong sector, void *load_addr);
int enable_mss_facility(void);
ulong get_second(void);

/* bootmap.c */
void zipl_load(void);
Expand Down Expand Up @@ -143,4 +151,42 @@ static inline void yield(void)

#define MAX_SECTOR_SIZE 4096

static inline void sleep(unsigned int seconds)
{
ulong target = get_second() + seconds;

while (get_second() < target) {
yield();
}
}

static inline void *memcpy(void *s1, const void *s2, size_t n)
{
uint8_t *p1 = s1;
const uint8_t *p2 = s2;

while (n--) {
p1[n] = p2[n];
}
return s1;
}

static inline void IPL_assert(bool term, const char *message)
{
if (!term) {
sclp_print("\n! ");
sclp_print(message);
panic(" !\n"); /* no return */
}
}

static inline void IPL_check(bool term, const char *message)
{
if (!term) {
sclp_print("\n! WARNING: ");
sclp_print(message);
sclp_print(" !\n");
}
}

#endif /* S390_CCW_H */
Loading

0 comments on commit b68a801

Please sign in to comment.