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