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 lowcore->subchannel_id = blk_schid.sch_id; 40 lowcore->subchannel_nr = blk_schid.sch_no; 41 lowcore->io_int_parm = 0; 42 } 43 44 void write_iplb_location(void) 45 { 46 if (cutype == CU_TYPE_VIRTIO && virtio_get_device_type() != VIRTIO_ID_NET) { 47 lowcore->ptr_iplb = ptr2u32(&iplb); 48 } 49 } 50 51 unsigned int get_loadparm_index(void) 52 { 53 return atoui(loadparm_str); 54 } 55 56 static int is_dev_possibly_bootable(int dev_no, int sch_no) 57 { 58 bool is_virtio; 59 Schib schib; 60 int r; 61 62 blk_schid.sch_no = sch_no; 63 r = stsch_err(blk_schid, &schib); 64 if (r == 3 || r == -EIO) { 65 return -ENODEV; 66 } 67 if (!schib.pmcw.dnv) { 68 return false; 69 } 70 71 enable_subchannel(blk_schid); 72 cutype = cu_type(blk_schid); 73 74 /* 75 * Note: we always have to run virtio_is_supported() here to make 76 * sure that the vdev.senseid data gets pre-initialized correctly 77 */ 78 is_virtio = virtio_is_supported(blk_schid); 79 80 /* No specific devno given, just return whether the device is possibly bootable */ 81 if (dev_no < 0) { 82 switch (cutype) { 83 case CU_TYPE_VIRTIO: 84 if (is_virtio) { 85 /* 86 * Skip net devices since no IPLB is created and therefore 87 * no network bootloader has been loaded 88 */ 89 if (virtio_get_device_type() != VIRTIO_ID_NET) { 90 return true; 91 } 92 } 93 return false; 94 case CU_TYPE_DASD_3990: 95 case CU_TYPE_DASD_2107: 96 return true; 97 default: 98 return false; 99 } 100 } 101 102 /* Caller asked for a specific devno */ 103 if (schib.pmcw.dev == dev_no) { 104 return true; 105 } 106 107 return false; 108 } 109 110 /* 111 * Find the subchannel connected to the given device (dev_no) and fill in the 112 * subchannel information block (schib) with the connected subchannel's info. 113 * NOTE: The global variable blk_schid is updated to contain the subchannel 114 * information. 115 * 116 * If the caller gives dev_no=-1 then the user did not specify a boot device. 117 * In this case we'll just use the first potentially bootable device we find. 118 */ 119 static bool find_subch(int dev_no) 120 { 121 int i, r; 122 123 for (i = 0; i < 0x10000; i++) { 124 r = is_dev_possibly_bootable(dev_no, i); 125 if (r < 0) { 126 break; 127 } 128 if (r == true) { 129 return true; 130 } 131 } 132 133 return false; 134 } 135 136 static void menu_setup(void) 137 { 138 if (memcmp(loadparm_str, LOADPARM_PROMPT, LOADPARM_LEN) == 0) { 139 menu_set_parms(QIPL_FLAG_BM_OPTS_CMD, 0); 140 return; 141 } 142 143 /* If loadparm was set to any other value, then do not enable menu */ 144 if (memcmp(loadparm_str, LOADPARM_EMPTY, LOADPARM_LEN) != 0) { 145 return; 146 } 147 148 switch (iplb.pbt) { 149 case S390_IPL_TYPE_CCW: 150 case S390_IPL_TYPE_QEMU_SCSI: 151 menu_set_parms(qipl.qipl_flags & BOOT_MENU_FLAG_MASK, 152 qipl.boot_menu_timeout); 153 return; 154 } 155 } 156 157 /* 158 * Initialize the channel I/O subsystem so we can talk to our ipl/boot device. 159 */ 160 static void css_setup(void) 161 { 162 /* 163 * Unconditionally enable mss support. In every sane configuration this 164 * will succeed; and even if it doesn't, stsch_err() can handle it. 165 */ 166 enable_mss_facility(); 167 } 168 169 /* 170 * Collect various pieces of information from the hypervisor/hardware that 171 * we'll use to determine exactly how we'll boot. 172 */ 173 static void boot_setup(void) 174 { 175 char lpmsg[] = "LOADPARM=[________]\n"; 176 177 sclp_get_loadparm_ascii(loadparm_str); 178 memcpy(lpmsg + 10, loadparm_str, 8); 179 sclp_print(lpmsg); 180 181 /* 182 * Clear out any potential S390EP magic (see jump_to_low_kernel()), 183 * so we don't taint our decision-making process during a reboot. 184 */ 185 memset((char *)S390EP, 0, 6); 186 187 have_iplb = store_iplb(&iplb); 188 } 189 190 static void find_boot_device(void) 191 { 192 VDev *vdev = virtio_get_device(); 193 bool found; 194 195 switch (iplb.pbt) { 196 case S390_IPL_TYPE_CCW: 197 debug_print_int("device no. ", iplb.ccw.devno); 198 blk_schid.ssid = iplb.ccw.ssid & 0x3; 199 debug_print_int("ssid ", blk_schid.ssid); 200 found = find_subch(iplb.ccw.devno); 201 break; 202 case S390_IPL_TYPE_QEMU_SCSI: 203 vdev->scsi_device_selected = true; 204 vdev->selected_scsi_device.channel = iplb.scsi.channel; 205 vdev->selected_scsi_device.target = iplb.scsi.target; 206 vdev->selected_scsi_device.lun = iplb.scsi.lun; 207 blk_schid.ssid = iplb.scsi.ssid & 0x3; 208 found = find_subch(iplb.scsi.devno); 209 break; 210 default: 211 panic("List-directed IPL not supported yet!\n"); 212 } 213 214 IPL_assert(found, "Boot device not found\n"); 215 } 216 217 static int virtio_setup(void) 218 { 219 VDev *vdev = virtio_get_device(); 220 QemuIplParameters *early_qipl = (QemuIplParameters *)QIPL_ADDRESS; 221 222 memcpy(&qipl, early_qipl, sizeof(QemuIplParameters)); 223 224 if (have_iplb) { 225 menu_setup(); 226 } 227 228 if (virtio_get_device_type() == VIRTIO_ID_NET) { 229 sclp_print("Network boot device detected\n"); 230 vdev->netboot_start_addr = qipl.netboot_start_addr; 231 } else { 232 int ret = virtio_blk_setup_device(blk_schid); 233 if (ret) { 234 return ret; 235 } 236 IPL_assert(virtio_ipl_disk_is_valid(), "No valid IPL device detected"); 237 } 238 239 return 0; 240 } 241 242 static void ipl_boot_device(void) 243 { 244 switch (cutype) { 245 case CU_TYPE_DASD_3990: 246 case CU_TYPE_DASD_2107: 247 dasd_ipl(blk_schid, cutype); /* no return */ 248 break; 249 case CU_TYPE_VIRTIO: 250 if (virtio_setup() == 0) { 251 zipl_load(); /* Only returns in case of errors */ 252 } 253 break; 254 default: 255 print_int("Attempting to boot from unexpected device type", cutype); 256 panic("\nBoot failed.\n"); 257 } 258 } 259 260 /* 261 * No boot device has been specified, so we have to scan through the 262 * channels to find one. 263 */ 264 static void probe_boot_device(void) 265 { 266 int ssid, sch_no, ret; 267 268 for (ssid = 0; ssid < 0x3; ssid++) { 269 blk_schid.ssid = ssid; 270 for (sch_no = 0; sch_no < 0x10000; sch_no++) { 271 ret = is_dev_possibly_bootable(-1, sch_no); 272 if (ret < 0) { 273 break; 274 } 275 if (ret == true) { 276 ipl_boot_device(); /* Only returns if unsuccessful */ 277 } 278 } 279 } 280 281 sclp_print("Could not find a suitable boot device (none specified)\n"); 282 } 283 284 int main(void) 285 { 286 sclp_setup(); 287 css_setup(); 288 boot_setup(); 289 if (have_iplb) { 290 find_boot_device(); 291 ipl_boot_device(); 292 } else { 293 probe_boot_device(); 294 } 295 296 panic("Failed to load OS from hard disk\n"); 297 return 0; /* make compiler happy */ 298 } 299