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