95fa1af854
The LOADPARM value is fetched from SCP Read Info, but it's applied only at the phase of bootmap interpretation. So let's read the LOARPARM value and store it. Also provide a parsing function to detect numbers in the LOADPARM which can be used during bootmap interpretation. Remove a stray whitespace. Initial patch from Eugene (jno) Dvurechenski. Signed-off-by: Eugene (jno) Dvurechenski <jno@linux.vnet.ibm.com> Signed-off-by: Farhan Ali <alifm@linux.vnet.ibm.com> Signed-off-by: Cornelia Huck <cornelia.huck@de.ibm.com>
173 lines
4.6 KiB
C
173 lines
4.6 KiB
C
/*
|
|
* 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"
|
|
#include "virtio.h"
|
|
|
|
char stack[PAGE_SIZE * 8] __attribute__((__aligned__(PAGE_SIZE)));
|
|
static SubChannelId blk_schid = { .one = 1 };
|
|
IplParameterBlock iplb __attribute__((__aligned__(PAGE_SIZE)));
|
|
static char loadparm[8] = { 0, 0, 0, 0, 0, 0, 0, 0 };
|
|
|
|
const unsigned char ebc2asc[256] =
|
|
/* 0123456789abcdef0123456789abcdef */
|
|
"................................" /* 1F */
|
|
"................................" /* 3F */
|
|
" ...........<(+|&.........!$*);." /* 5F first.chr.here.is.real.space */
|
|
"-/.........,%_>?.........`:#@'=\""/* 7F */
|
|
".abcdefghi.......jklmnopqr......" /* 9F */
|
|
"..stuvwxyz......................" /* BF */
|
|
".ABCDEFGHI.......JKLMNOPQR......" /* DF */
|
|
"..STUVWXYZ......0123456789......";/* FF */
|
|
|
|
/*
|
|
* Priniciples of Operations (SA22-7832-09) chapter 17 requires that
|
|
* a subsystem-identification is at 184-187 and bytes 188-191 are zero
|
|
* after list-directed-IPL and ccw-IPL.
|
|
*/
|
|
void write_subsystem_identification(void)
|
|
{
|
|
SubChannelId *schid = (SubChannelId *) 184;
|
|
uint32_t *zeroes = (uint32_t *) 188;
|
|
|
|
*schid = blk_schid;
|
|
*zeroes = 0;
|
|
}
|
|
|
|
void panic(const char *string)
|
|
{
|
|
sclp_print(string);
|
|
disabled_wait();
|
|
while (1) { }
|
|
}
|
|
|
|
unsigned int get_loadparm_index(void)
|
|
{
|
|
const char *lp = loadparm;
|
|
int i;
|
|
unsigned int idx = 0;
|
|
|
|
for (i = 0; i < 8; i++) {
|
|
char c = lp[i];
|
|
|
|
if (c < '0' || c > '9') {
|
|
break;
|
|
}
|
|
|
|
idx *= 10;
|
|
idx += c - '0';
|
|
}
|
|
|
|
return idx;
|
|
}
|
|
|
|
static bool find_dev(Schib *schib, int dev_no)
|
|
{
|
|
int i, r;
|
|
|
|
for (i = 0; i < 0x10000; i++) {
|
|
blk_schid.sch_no = i;
|
|
r = stsch_err(blk_schid, schib);
|
|
if ((r == 3) || (r == -EIO)) {
|
|
break;
|
|
}
|
|
if (!schib->pmcw.dnv) {
|
|
continue;
|
|
}
|
|
if (!virtio_is_supported(blk_schid)) {
|
|
continue;
|
|
}
|
|
/* Skip net devices since no IPLB is created and therefore no
|
|
* no network bootloader has been loaded
|
|
*/
|
|
if (virtio_get_device_type() == VIRTIO_ID_NET && dev_no < 0) {
|
|
continue;
|
|
}
|
|
if ((dev_no < 0) || (schib->pmcw.dev == dev_no)) {
|
|
return true;
|
|
}
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
static void virtio_setup(void)
|
|
{
|
|
Schib schib;
|
|
int ssid;
|
|
bool found = false;
|
|
uint16_t dev_no;
|
|
char ldp[] = "LOADPARM=[________]\n";
|
|
VDev *vdev = virtio_get_device();
|
|
|
|
/*
|
|
* We unconditionally enable mss support. In every sane configuration,
|
|
* this will succeed; and even if it doesn't, stsch_err() can deal
|
|
* with the consequences.
|
|
*/
|
|
enable_mss_facility();
|
|
|
|
sclp_get_loadparm_ascii(loadparm);
|
|
memcpy(ldp + 10, loadparm, 8);
|
|
sclp_print(ldp);
|
|
|
|
if (store_iplb(&iplb)) {
|
|
switch (iplb.pbt) {
|
|
case S390_IPL_TYPE_CCW:
|
|
dev_no = iplb.ccw.devno;
|
|
debug_print_int("device no. ", dev_no);
|
|
blk_schid.ssid = iplb.ccw.ssid & 0x3;
|
|
debug_print_int("ssid ", blk_schid.ssid);
|
|
found = find_dev(&schib, dev_no);
|
|
break;
|
|
case S390_IPL_TYPE_QEMU_SCSI:
|
|
vdev->scsi_device_selected = true;
|
|
vdev->selected_scsi_device.channel = iplb.scsi.channel;
|
|
vdev->selected_scsi_device.target = iplb.scsi.target;
|
|
vdev->selected_scsi_device.lun = iplb.scsi.lun;
|
|
blk_schid.ssid = iplb.scsi.ssid & 0x3;
|
|
found = find_dev(&schib, iplb.scsi.devno);
|
|
break;
|
|
default:
|
|
panic("List-directed IPL not supported yet!\n");
|
|
}
|
|
} else {
|
|
for (ssid = 0; ssid < 0x3; ssid++) {
|
|
blk_schid.ssid = ssid;
|
|
found = find_dev(&schib, -1);
|
|
if (found) {
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
IPL_assert(found, "No virtio device found");
|
|
|
|
if (virtio_get_device_type() == VIRTIO_ID_NET) {
|
|
sclp_print("Network boot device detected\n");
|
|
vdev->netboot_start_addr = iplb.ccw.netboot_start_addr;
|
|
} else {
|
|
virtio_setup_device(blk_schid);
|
|
|
|
IPL_assert(virtio_ipl_disk_is_valid(), "No valid IPL device detected");
|
|
}
|
|
}
|
|
|
|
int main(void)
|
|
{
|
|
sclp_setup();
|
|
virtio_setup();
|
|
|
|
zipl_load(); /* no return */
|
|
|
|
panic("Failed to load OS from hard disk\n");
|
|
return 0; /* make compiler happy */
|
|
}
|