#endif
#include <qipl.h>
+#include <string.h>
extern QemuIplParameters qipl;
extern IplParameterBlock iplb __attribute__((__aligned__(PAGE_SIZE)));
+extern bool have_iplb;
#define S390_IPL_TYPE_FCP 0x00
#define S390_IPL_TYPE_CCW 0x02
return manage_iplb(iplb, false);
}
+/*
+ * The IPL started on the device, but failed in some way. If the IPLB chain
+ * still has more devices left to try, use the next device in order.
+ */
+static inline bool load_next_iplb(void)
+{
+ IplParameterBlock *next_iplb;
+
+ if (qipl.chain_len < 1) {
+ return false;
+ }
+
+ qipl.index++;
+ next_iplb = (IplParameterBlock *) qipl.next_iplb;
+ memcpy(&iplb, next_iplb, sizeof(IplParameterBlock));
+
+ qipl.chain_len--;
+ qipl.next_iplb = qipl.next_iplb + sizeof(IplParameterBlock);
+
+ return true;
+}
+
#endif /* IPLB_H */
static char loadparm_str[LOADPARM_LEN + 1];
QemuIplParameters qipl;
IplParameterBlock iplb __attribute__((__aligned__(PAGE_SIZE)));
-static bool have_iplb;
+bool have_iplb;
static uint16_t cutype;
LowCore *lowcore; /* Yes, this *is* a pointer to address 0 */
}
}
+static void copy_qipl(void)
+{
+ QemuIplParameters *early_qipl = (QemuIplParameters *)QIPL_ADDRESS;
+ memcpy(&qipl, early_qipl, sizeof(QemuIplParameters));
+}
+
unsigned int get_loadparm_index(void)
{
return atoi(loadparm_str);
/* If loadparm was set to any other value, then do not enable menu */
if (memcmp(loadparm_str, LOADPARM_EMPTY, LOADPARM_LEN) != 0) {
+ menu_set_parms(qipl.qipl_flags & ~BOOT_MENU_FLAG_MASK, 0);
return;
}
static void boot_setup(void)
{
char lpmsg[] = "LOADPARM=[________]\n";
- have_iplb = store_iplb(&iplb);
if (memcmp(iplb.loadparm, NO_LOADPARM, LOADPARM_LEN) != 0) {
ebcdic_to_ascii((char *) iplb.loadparm, loadparm_str, LOADPARM_LEN);
sclp_get_loadparm_ascii(loadparm_str);
}
+ if (have_iplb) {
+ menu_setup();
+ }
+
memcpy(lpmsg + 10, loadparm_str, 8);
puts(lpmsg);
switch (iplb.pbt) {
case S390_IPL_TYPE_CCW:
+ vdev->scsi_device_selected = false;
debug_print_int("device no. ", iplb.ccw.devno);
blk_schid.ssid = iplb.ccw.ssid & 0x3;
debug_print_int("ssid ", blk_schid.ssid);
static int virtio_setup(void)
{
VDev *vdev = virtio_get_device();
- QemuIplParameters *early_qipl = (QemuIplParameters *)QIPL_ADDRESS;
int ret;
- memcpy(&qipl, early_qipl, sizeof(QemuIplParameters));
-
- if (have_iplb) {
- menu_setup();
- }
-
switch (vdev->senseid.cu_model) {
case VIRTIO_ID_NET:
puts("Network boot device detected");
dasd_ipl(blk_schid, cutype);
break;
case CU_TYPE_VIRTIO:
- if (virtio_setup()) {
- return; /* Only returns in case of errors */
+ if (virtio_setup() == 0) {
+ zipl_load();
}
- zipl_load();
break;
default:
printf("Attempting to boot from unexpected device type 0x%X\n", cutype);
void main(void)
{
+ copy_qipl();
sclp_setup();
css_setup();
- boot_setup();
- if (have_iplb && find_boot_device()) {
- ipl_boot_device();
- } else {
+ have_iplb = store_iplb(&iplb);
+ if (!have_iplb) {
probe_boot_device();
}
- panic("Failed to IPL. Halting...");
+ while (have_iplb) {
+ boot_setup();
+ if (have_iplb && find_boot_device()) {
+ ipl_boot_device();
+ }
+ have_iplb = load_next_iplb();
+ }
+
+ panic("No suitable device for IPL. Halting...");
+
}