1 // SPDX-License-Identifier: GPL-2.0 2 /* 3 * Copyright IBM Corp. 2015 4 * Author(s): Martin Schwidefsky <schwidefsky@de.ibm.com> 5 */ 6 7 #include <linux/kernel.h> 8 #include <asm/processor.h> 9 #include <asm/lowcore.h> 10 #include <asm/ebcdic.h> 11 #include <asm/irq.h> 12 #include <asm/sections.h> 13 #include <asm/mem_detect.h> 14 #include "sclp.h" 15 #include "sclp_rw.h" 16 17 static struct read_info_sccb __bootdata(sclp_info_sccb); 18 static int __bootdata(sclp_info_sccb_valid); 19 char *sclp_early_sccb = (char *) EARLY_SCCB_OFFSET; 20 int sclp_init_state = sclp_init_state_uninitialized; 21 /* 22 * Used to keep track of the size of the event masks. Qemu until version 2.11 23 * only supports 4 and needs a workaround. 24 */ 25 bool sclp_mask_compat_mode; 26 27 void sclp_early_wait_irq(void) 28 { 29 unsigned long psw_mask, addr; 30 psw_t psw_ext_save, psw_wait; 31 union ctlreg0 cr0, cr0_new; 32 33 __ctl_store(cr0.val, 0, 0); 34 cr0_new.val = cr0.val & ~CR0_IRQ_SUBCLASS_MASK; 35 cr0_new.lap = 0; 36 cr0_new.sssm = 1; 37 __ctl_load(cr0_new.val, 0, 0); 38 39 psw_ext_save = S390_lowcore.external_new_psw; 40 psw_mask = __extract_psw(); 41 S390_lowcore.external_new_psw.mask = psw_mask; 42 psw_wait.mask = psw_mask | PSW_MASK_EXT | PSW_MASK_WAIT; 43 S390_lowcore.ext_int_code = 0; 44 45 do { 46 asm volatile( 47 " larl %[addr],0f\n" 48 " stg %[addr],%[psw_wait_addr]\n" 49 " stg %[addr],%[psw_ext_addr]\n" 50 " lpswe %[psw_wait]\n" 51 "0:\n" 52 : [addr] "=&d" (addr), 53 [psw_wait_addr] "=Q" (psw_wait.addr), 54 [psw_ext_addr] "=Q" (S390_lowcore.external_new_psw.addr) 55 : [psw_wait] "Q" (psw_wait) 56 : "cc", "memory"); 57 } while (S390_lowcore.ext_int_code != EXT_IRQ_SERVICE_SIG); 58 59 S390_lowcore.external_new_psw = psw_ext_save; 60 __ctl_load(cr0.val, 0, 0); 61 } 62 63 int sclp_early_cmd(sclp_cmdw_t cmd, void *sccb) 64 { 65 unsigned long flags; 66 int rc; 67 68 raw_local_irq_save(flags); 69 rc = sclp_service_call(cmd, sccb); 70 if (rc) 71 goto out; 72 sclp_early_wait_irq(); 73 out: 74 raw_local_irq_restore(flags); 75 return rc; 76 } 77 78 struct write_sccb { 79 struct sccb_header header; 80 struct msg_buf msg; 81 } __packed; 82 83 /* Output multi-line text using SCLP Message interface. */ 84 static void sclp_early_print_lm(const char *str, unsigned int len) 85 { 86 unsigned char *ptr, *end, ch; 87 unsigned int count, offset; 88 struct write_sccb *sccb; 89 struct msg_buf *msg; 90 struct mdb *mdb; 91 struct mto *mto; 92 struct go *go; 93 94 sccb = (struct write_sccb *) sclp_early_sccb; 95 end = (unsigned char *) sccb + EARLY_SCCB_SIZE - 1; 96 memset(sccb, 0, sizeof(*sccb)); 97 ptr = (unsigned char *) &sccb->msg.mdb.mto; 98 offset = 0; 99 do { 100 for (count = sizeof(*mto); offset < len; count++) { 101 ch = str[offset++]; 102 if ((ch == 0x0a) || (ptr + count > end)) 103 break; 104 ptr[count] = _ascebc[ch]; 105 } 106 mto = (struct mto *) ptr; 107 memset(mto, 0, sizeof(*mto)); 108 mto->length = count; 109 mto->type = 4; 110 mto->line_type_flags = LNTPFLGS_ENDTEXT; 111 ptr += count; 112 } while ((offset < len) && (ptr + sizeof(*mto) <= end)); 113 len = ptr - (unsigned char *) sccb; 114 sccb->header.length = len - offsetof(struct write_sccb, header); 115 msg = &sccb->msg; 116 msg->header.type = EVTYP_MSG; 117 msg->header.length = len - offsetof(struct write_sccb, msg.header); 118 mdb = &msg->mdb; 119 mdb->header.type = 1; 120 mdb->header.tag = 0xD4C4C240; 121 mdb->header.revision_code = 1; 122 mdb->header.length = len - offsetof(struct write_sccb, msg.mdb.header); 123 go = &mdb->go; 124 go->length = sizeof(*go); 125 go->type = 1; 126 sclp_early_cmd(SCLP_CMDW_WRITE_EVENT_DATA, sccb); 127 } 128 129 struct vt220_sccb { 130 struct sccb_header header; 131 struct { 132 struct evbuf_header header; 133 char data[]; 134 } msg; 135 } __packed; 136 137 /* Output multi-line text using SCLP VT220 interface. */ 138 static void sclp_early_print_vt220(const char *str, unsigned int len) 139 { 140 struct vt220_sccb *sccb; 141 142 sccb = (struct vt220_sccb *) sclp_early_sccb; 143 if (sizeof(*sccb) + len >= EARLY_SCCB_SIZE) 144 len = EARLY_SCCB_SIZE - sizeof(*sccb); 145 memset(sccb, 0, sizeof(*sccb)); 146 memcpy(&sccb->msg.data, str, len); 147 sccb->header.length = sizeof(*sccb) + len; 148 sccb->msg.header.length = sizeof(sccb->msg) + len; 149 sccb->msg.header.type = EVTYP_VT220MSG; 150 sclp_early_cmd(SCLP_CMDW_WRITE_EVENT_DATA, sccb); 151 } 152 153 int sclp_early_set_event_mask(struct init_sccb *sccb, 154 sccb_mask_t receive_mask, 155 sccb_mask_t send_mask) 156 { 157 retry: 158 memset(sccb, 0, sizeof(*sccb)); 159 sccb->header.length = sizeof(*sccb); 160 if (sclp_mask_compat_mode) 161 sccb->mask_length = SCLP_MASK_SIZE_COMPAT; 162 else 163 sccb->mask_length = sizeof(sccb_mask_t); 164 sccb_set_recv_mask(sccb, receive_mask); 165 sccb_set_send_mask(sccb, send_mask); 166 if (sclp_early_cmd(SCLP_CMDW_WRITE_EVENT_MASK, sccb)) 167 return -EIO; 168 if ((sccb->header.response_code == 0x74f0) && !sclp_mask_compat_mode) { 169 sclp_mask_compat_mode = true; 170 goto retry; 171 } 172 if (sccb->header.response_code != 0x20) 173 return -EIO; 174 return 0; 175 } 176 177 unsigned int sclp_early_con_check_linemode(struct init_sccb *sccb) 178 { 179 if (!(sccb_get_sclp_send_mask(sccb) & EVTYP_OPCMD_MASK)) 180 return 0; 181 if (!(sccb_get_sclp_recv_mask(sccb) & (EVTYP_MSG_MASK | EVTYP_PMSGCMD_MASK))) 182 return 0; 183 return 1; 184 } 185 186 unsigned int sclp_early_con_check_vt220(struct init_sccb *sccb) 187 { 188 if (sccb_get_sclp_send_mask(sccb) & EVTYP_VT220MSG_MASK) 189 return 1; 190 return 0; 191 } 192 193 static int sclp_early_setup(int disable, int *have_linemode, int *have_vt220) 194 { 195 unsigned long receive_mask, send_mask; 196 struct init_sccb *sccb; 197 int rc; 198 199 BUILD_BUG_ON(sizeof(struct init_sccb) > PAGE_SIZE); 200 201 *have_linemode = *have_vt220 = 0; 202 sccb = (struct init_sccb *) sclp_early_sccb; 203 receive_mask = disable ? 0 : EVTYP_OPCMD_MASK; 204 send_mask = disable ? 0 : EVTYP_VT220MSG_MASK | EVTYP_MSG_MASK; 205 rc = sclp_early_set_event_mask(sccb, receive_mask, send_mask); 206 if (rc) 207 return rc; 208 *have_linemode = sclp_early_con_check_linemode(sccb); 209 *have_vt220 = !!(sccb_get_send_mask(sccb) & EVTYP_VT220MSG_MASK); 210 return rc; 211 } 212 213 /* 214 * Output one or more lines of text on the SCLP console (VT220 and / 215 * or line-mode). 216 */ 217 void __sclp_early_printk(const char *str, unsigned int len) 218 { 219 int have_linemode, have_vt220; 220 221 if (sclp_init_state != sclp_init_state_uninitialized) 222 return; 223 if (sclp_early_setup(0, &have_linemode, &have_vt220) != 0) 224 return; 225 if (have_linemode) 226 sclp_early_print_lm(str, len); 227 if (have_vt220) 228 sclp_early_print_vt220(str, len); 229 sclp_early_setup(1, &have_linemode, &have_vt220); 230 } 231 232 void sclp_early_printk(const char *str) 233 { 234 __sclp_early_printk(str, strlen(str)); 235 } 236 237 int __init sclp_early_read_info(void) 238 { 239 int i; 240 struct read_info_sccb *sccb = &sclp_info_sccb; 241 sclp_cmdw_t commands[] = {SCLP_CMDW_READ_SCP_INFO_FORCED, 242 SCLP_CMDW_READ_SCP_INFO}; 243 244 for (i = 0; i < ARRAY_SIZE(commands); i++) { 245 memset(sccb, 0, sizeof(*sccb)); 246 sccb->header.length = sizeof(*sccb); 247 sccb->header.function_code = 0x80; 248 sccb->header.control_mask[2] = 0x80; 249 if (sclp_early_cmd(commands[i], sccb)) 250 break; 251 if (sccb->header.response_code == 0x10) { 252 sclp_info_sccb_valid = 1; 253 return 0; 254 } 255 if (sccb->header.response_code != 0x1f0) 256 break; 257 } 258 return -EIO; 259 } 260 261 int __init sclp_early_get_info(struct read_info_sccb *info) 262 { 263 if (!sclp_info_sccb_valid) 264 return -EIO; 265 266 *info = sclp_info_sccb; 267 return 0; 268 } 269 270 int __init sclp_early_get_memsize(unsigned long *mem) 271 { 272 unsigned long rnmax; 273 unsigned long rnsize; 274 struct read_info_sccb *sccb = &sclp_info_sccb; 275 276 if (!sclp_info_sccb_valid) 277 return -EIO; 278 279 rnmax = sccb->rnmax ? sccb->rnmax : sccb->rnmax2; 280 rnsize = sccb->rnsize ? sccb->rnsize : sccb->rnsize2; 281 rnsize <<= 20; 282 *mem = rnsize * rnmax; 283 return 0; 284 } 285 286 int __init sclp_early_get_hsa_size(unsigned long *hsa_size) 287 { 288 if (!sclp_info_sccb_valid) 289 return -EIO; 290 291 *hsa_size = 0; 292 if (sclp_info_sccb.hsa_size) 293 *hsa_size = (sclp_info_sccb.hsa_size - 1) * PAGE_SIZE; 294 return 0; 295 } 296 297 #define SCLP_STORAGE_INFO_FACILITY 0x0000400000000000UL 298 299 void __weak __init add_mem_detect_block(u64 start, u64 end) {} 300 int __init sclp_early_read_storage_info(void) 301 { 302 struct read_storage_sccb *sccb = (struct read_storage_sccb *)sclp_early_sccb; 303 int rc, id, max_id = 0; 304 unsigned long rn, rzm; 305 sclp_cmdw_t command; 306 u16 sn; 307 308 if (!sclp_info_sccb_valid) 309 return -EIO; 310 311 if (!(sclp_info_sccb.facilities & SCLP_STORAGE_INFO_FACILITY)) 312 return -EOPNOTSUPP; 313 314 rzm = sclp_info_sccb.rnsize ?: sclp_info_sccb.rnsize2; 315 rzm <<= 20; 316 317 for (id = 0; id <= max_id; id++) { 318 memset(sclp_early_sccb, 0, EARLY_SCCB_SIZE); 319 sccb->header.length = EARLY_SCCB_SIZE; 320 command = SCLP_CMDW_READ_STORAGE_INFO | (id << 8); 321 rc = sclp_early_cmd(command, sccb); 322 if (rc) 323 goto fail; 324 325 max_id = sccb->max_id; 326 switch (sccb->header.response_code) { 327 case 0x0010: 328 for (sn = 0; sn < sccb->assigned; sn++) { 329 if (!sccb->entries[sn]) 330 continue; 331 rn = sccb->entries[sn] >> 16; 332 add_mem_detect_block((rn - 1) * rzm, rn * rzm); 333 } 334 break; 335 case 0x0310: 336 case 0x0410: 337 break; 338 default: 339 goto fail; 340 } 341 } 342 343 return 0; 344 fail: 345 mem_detect.count = 0; 346 return -EIO; 347 } 348