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 "s390-ccw.h" 12 #include "virtio.h" 13 14 char stack[PAGE_SIZE * 8] __attribute__((__aligned__(PAGE_SIZE))); 15 static SubChannelId blk_schid = { .one = 1 }; 16 IplParameterBlock iplb __attribute__((__aligned__(PAGE_SIZE))); 17 static char loadparm[8] = { 0, 0, 0, 0, 0, 0, 0, 0 }; 18 19 const unsigned char ebc2asc[256] = 20 /* 0123456789abcdef0123456789abcdef */ 21 "................................" /* 1F */ 22 "................................" /* 3F */ 23 " ...........<(+|&.........!$*);." /* 5F first.chr.here.is.real.space */ 24 "-/.........,%_>?.........`:#@'=\""/* 7F */ 25 ".abcdefghi.......jklmnopqr......" /* 9F */ 26 "..stuvwxyz......................" /* BF */ 27 ".ABCDEFGHI.......JKLMNOPQR......" /* DF */ 28 "..STUVWXYZ......0123456789......";/* FF */ 29 30 /* 31 * Priniciples 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 const char *lp = loadparm; 54 int i; 55 unsigned int idx = 0; 56 57 for (i = 0; i < 8; i++) { 58 char c = lp[i]; 59 60 if (c < '0' || c > '9') { 61 break; 62 } 63 64 idx *= 10; 65 idx += c - '0'; 66 } 67 68 return idx; 69 } 70 71 static bool find_dev(Schib *schib, int dev_no) 72 { 73 int i, r; 74 75 for (i = 0; i < 0x10000; i++) { 76 blk_schid.sch_no = i; 77 r = stsch_err(blk_schid, schib); 78 if ((r == 3) || (r == -EIO)) { 79 break; 80 } 81 if (!schib->pmcw.dnv) { 82 continue; 83 } 84 if (!virtio_is_supported(blk_schid)) { 85 continue; 86 } 87 /* Skip net devices since no IPLB is created and therefore no 88 * no network bootloader has been loaded 89 */ 90 if (virtio_get_device_type() == VIRTIO_ID_NET && dev_no < 0) { 91 continue; 92 } 93 if ((dev_no < 0) || (schib->pmcw.dev == dev_no)) { 94 return true; 95 } 96 } 97 98 return false; 99 } 100 101 static void virtio_setup(void) 102 { 103 Schib schib; 104 int ssid; 105 bool found = false; 106 uint16_t dev_no; 107 char ldp[] = "LOADPARM=[________]\n"; 108 VDev *vdev = virtio_get_device(); 109 110 /* 111 * We unconditionally enable mss support. In every sane configuration, 112 * this will succeed; and even if it doesn't, stsch_err() can deal 113 * with the consequences. 114 */ 115 enable_mss_facility(); 116 117 sclp_get_loadparm_ascii(loadparm); 118 memcpy(ldp + 10, loadparm, 8); 119 sclp_print(ldp); 120 121 if (store_iplb(&iplb)) { 122 switch (iplb.pbt) { 123 case S390_IPL_TYPE_CCW: 124 dev_no = iplb.ccw.devno; 125 debug_print_int("device no. ", dev_no); 126 blk_schid.ssid = iplb.ccw.ssid & 0x3; 127 debug_print_int("ssid ", blk_schid.ssid); 128 found = find_dev(&schib, dev_no); 129 break; 130 case S390_IPL_TYPE_QEMU_SCSI: 131 vdev->scsi_device_selected = true; 132 vdev->selected_scsi_device.channel = iplb.scsi.channel; 133 vdev->selected_scsi_device.target = iplb.scsi.target; 134 vdev->selected_scsi_device.lun = iplb.scsi.lun; 135 blk_schid.ssid = iplb.scsi.ssid & 0x3; 136 found = find_dev(&schib, iplb.scsi.devno); 137 break; 138 default: 139 panic("List-directed IPL not supported yet!\n"); 140 } 141 } else { 142 for (ssid = 0; ssid < 0x3; ssid++) { 143 blk_schid.ssid = ssid; 144 found = find_dev(&schib, -1); 145 if (found) { 146 break; 147 } 148 } 149 } 150 151 IPL_assert(found, "No virtio device found"); 152 153 if (virtio_get_device_type() == VIRTIO_ID_NET) { 154 sclp_print("Network boot device detected\n"); 155 vdev->netboot_start_addr = iplb.ccw.netboot_start_addr; 156 } else { 157 virtio_setup_device(blk_schid); 158 159 IPL_assert(virtio_ipl_disk_is_valid(), "No valid IPL device detected"); 160 } 161 } 162 163 int main(void) 164 { 165 sclp_setup(); 166 virtio_setup(); 167 168 zipl_load(); /* no return */ 169 170 panic("Failed to load OS from hard disk\n"); 171 return 0; /* make compiler happy */ 172 } 173