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