1 /* 2 * S390 virtio-ccw loading program 3 * 4 * Copyright (c) 2013 Alexander Graf <agraf@suse.de> 5 * 6 * This work is licensed under the terms of the GNU GPL, version 2 or (at 7 * your option) any later version. See the COPYING file in the top-level 8 * directory. 9 */ 10 11 #include "libc.h" 12 #include "s390-arch.h" 13 #include "s390-ccw.h" 14 #include "cio.h" 15 #include "virtio.h" 16 #include "dasd-ipl.h" 17 18 char stack[PAGE_SIZE * 8] __attribute__((__aligned__(PAGE_SIZE))); 19 static SubChannelId blk_schid = { .one = 1 }; 20 static char loadparm_str[LOADPARM_LEN + 1] = { 0, 0, 0, 0, 0, 0, 0, 0, 0 }; 21 QemuIplParameters qipl; 22 IplParameterBlock iplb __attribute__((__aligned__(PAGE_SIZE))); 23 static bool have_iplb; 24 LowCore const *lowcore; /* Yes, this *is* a pointer to address 0 */ 25 26 #define LOADPARM_PROMPT "PROMPT " 27 #define LOADPARM_EMPTY " " 28 #define BOOT_MENU_FLAG_MASK (QIPL_FLAG_BM_OPTS_CMD | QIPL_FLAG_BM_OPTS_ZIPL) 29 30 /* 31 * Principles of Operations (SA22-7832-09) chapter 17 requires that 32 * a subsystem-identification is at 184-187 and bytes 188-191 are zero 33 * after list-directed-IPL and ccw-IPL. 34 */ 35 void write_subsystem_identification(void) 36 { 37 SubChannelId *schid = (SubChannelId *) 184; 38 uint32_t *zeroes = (uint32_t *) 188; 39 40 *schid = blk_schid; 41 *zeroes = 0; 42 } 43 44 void panic(const char *string) 45 { 46 sclp_print(string); 47 disabled_wait(); 48 while (1) { } 49 } 50 51 unsigned int get_loadparm_index(void) 52 { 53 return atoui(loadparm_str); 54 } 55 56 /* 57 * Find the subchannel connected to the given device (dev_no) and fill in the 58 * subchannel information block (schib) with the connected subchannel's info. 59 * NOTE: The global variable blk_schid is updated to contain the subchannel 60 * information. 61 */ 62 static bool find_subch(int dev_no) 63 { 64 Schib schib; 65 int i, r; 66 67 for (i = 0; i < 0x10000; i++) { 68 blk_schid.sch_no = i; 69 r = stsch_err(blk_schid, &schib); 70 if ((r == 3) || (r == -EIO)) { 71 break; 72 } 73 if (!schib.pmcw.dnv) { 74 continue; 75 } 76 77 /* Skip net devices since no IPLB is created and therefore no 78 * network bootloader has been loaded 79 */ 80 enable_subchannel(blk_schid); 81 if (virtio_is_supported(blk_schid) && 82 virtio_get_device_type() == VIRTIO_ID_NET && dev_no < 0) { 83 continue; 84 } 85 86 if ((dev_no < 0) || (schib.pmcw.dev == dev_no)) { 87 return true; 88 } 89 } 90 91 return false; 92 } 93 94 static void menu_setup(void) 95 { 96 if (memcmp(loadparm_str, LOADPARM_PROMPT, LOADPARM_LEN) == 0) { 97 menu_set_parms(QIPL_FLAG_BM_OPTS_CMD, 0); 98 return; 99 } 100 101 /* If loadparm was set to any other value, then do not enable menu */ 102 if (memcmp(loadparm_str, LOADPARM_EMPTY, LOADPARM_LEN) != 0) { 103 return; 104 } 105 106 switch (iplb.pbt) { 107 case S390_IPL_TYPE_CCW: 108 case S390_IPL_TYPE_QEMU_SCSI: 109 menu_set_parms(qipl.qipl_flags & BOOT_MENU_FLAG_MASK, 110 qipl.boot_menu_timeout); 111 return; 112 } 113 } 114 115 /* 116 * Initialize the channel I/O subsystem so we can talk to our ipl/boot device. 117 */ 118 static void css_setup(void) 119 { 120 /* 121 * Unconditionally enable mss support. In every sane configuration this 122 * will succeed; and even if it doesn't, stsch_err() can handle it. 123 */ 124 enable_mss_facility(); 125 } 126 127 /* 128 * Collect various pieces of information from the hypervisor/hardware that 129 * we'll use to determine exactly how we'll boot. 130 */ 131 static void boot_setup(void) 132 { 133 char lpmsg[] = "LOADPARM=[________]\n"; 134 135 sclp_get_loadparm_ascii(loadparm_str); 136 memcpy(lpmsg + 10, loadparm_str, 8); 137 sclp_print(lpmsg); 138 139 have_iplb = store_iplb(&iplb); 140 } 141 142 static void find_boot_device(void) 143 { 144 VDev *vdev = virtio_get_device(); 145 int ssid; 146 bool found; 147 148 if (!have_iplb) { 149 for (ssid = 0; ssid < 0x3; ssid++) { 150 blk_schid.ssid = ssid; 151 found = find_subch(-1); 152 if (found) { 153 return; 154 } 155 } 156 panic("Could not find a suitable boot device (none specified)\n"); 157 } 158 159 switch (iplb.pbt) { 160 case S390_IPL_TYPE_CCW: 161 debug_print_int("device no. ", iplb.ccw.devno); 162 blk_schid.ssid = iplb.ccw.ssid & 0x3; 163 debug_print_int("ssid ", blk_schid.ssid); 164 found = find_subch(iplb.ccw.devno); 165 break; 166 case S390_IPL_TYPE_QEMU_SCSI: 167 vdev->scsi_device_selected = true; 168 vdev->selected_scsi_device.channel = iplb.scsi.channel; 169 vdev->selected_scsi_device.target = iplb.scsi.target; 170 vdev->selected_scsi_device.lun = iplb.scsi.lun; 171 blk_schid.ssid = iplb.scsi.ssid & 0x3; 172 found = find_subch(iplb.scsi.devno); 173 break; 174 default: 175 panic("List-directed IPL not supported yet!\n"); 176 } 177 178 IPL_assert(found, "Boot device not found\n"); 179 } 180 181 static void virtio_setup(void) 182 { 183 VDev *vdev = virtio_get_device(); 184 QemuIplParameters *early_qipl = (QemuIplParameters *)QIPL_ADDRESS; 185 186 memcpy(&qipl, early_qipl, sizeof(QemuIplParameters)); 187 188 if (have_iplb) { 189 menu_setup(); 190 } 191 192 if (virtio_get_device_type() == VIRTIO_ID_NET) { 193 sclp_print("Network boot device detected\n"); 194 vdev->netboot_start_addr = qipl.netboot_start_addr; 195 } else { 196 virtio_blk_setup_device(blk_schid); 197 IPL_assert(virtio_ipl_disk_is_valid(), "No valid IPL device detected"); 198 } 199 } 200 201 int main(void) 202 { 203 uint16_t cutype; 204 205 sclp_setup(); 206 css_setup(); 207 boot_setup(); 208 find_boot_device(); 209 enable_subchannel(blk_schid); 210 211 cutype = cu_type(blk_schid); 212 switch (cutype) { 213 case CU_TYPE_DASD_3990: 214 case CU_TYPE_DASD_2107: 215 dasd_ipl(blk_schid, cutype); /* no return */ 216 break; 217 case CU_TYPE_VIRTIO: 218 virtio_setup(); 219 zipl_load(); /* no return */ 220 break; 221 default: 222 print_int("Attempting to boot from unexpected device type", cutype); 223 panic(""); 224 } 225 226 panic("Failed to load OS from hard disk\n"); 227 return 0; /* make compiler happy */ 228 } 229