sclp_early_core.c 5.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208
  1. /*
  2. * Copyright IBM Corp. 2015
  3. * Author(s): Martin Schwidefsky <schwidefsky@de.ibm.com>
  4. */
  5. #include <linux/kernel.h>
  6. #include <asm/processor.h>
  7. #include <asm/lowcore.h>
  8. #include <asm/ebcdic.h>
  9. #include <asm/irq.h>
  10. #include "sclp.h"
  11. #include "sclp_rw.h"
  12. char sclp_early_sccb[PAGE_SIZE] __aligned(PAGE_SIZE) __section(data);
  13. int sclp_init_state __section(data) = sclp_init_state_uninitialized;
  14. void sclp_early_wait_irq(void)
  15. {
  16. unsigned long psw_mask, addr;
  17. psw_t psw_ext_save, psw_wait;
  18. union ctlreg0 cr0, cr0_new;
  19. __ctl_store(cr0.val, 0, 0);
  20. cr0_new.val = cr0.val & ~CR0_IRQ_SUBCLASS_MASK;
  21. cr0_new.lap = 0;
  22. cr0_new.sssm = 1;
  23. __ctl_load(cr0_new.val, 0, 0);
  24. psw_ext_save = S390_lowcore.external_new_psw;
  25. psw_mask = __extract_psw();
  26. S390_lowcore.external_new_psw.mask = psw_mask;
  27. psw_wait.mask = psw_mask | PSW_MASK_EXT | PSW_MASK_WAIT;
  28. S390_lowcore.ext_int_code = 0;
  29. do {
  30. asm volatile(
  31. " larl %[addr],0f\n"
  32. " stg %[addr],%[psw_wait_addr]\n"
  33. " stg %[addr],%[psw_ext_addr]\n"
  34. " lpswe %[psw_wait]\n"
  35. "0:\n"
  36. : [addr] "=&d" (addr),
  37. [psw_wait_addr] "=Q" (psw_wait.addr),
  38. [psw_ext_addr] "=Q" (S390_lowcore.external_new_psw.addr)
  39. : [psw_wait] "Q" (psw_wait)
  40. : "cc", "memory");
  41. } while (S390_lowcore.ext_int_code != EXT_IRQ_SERVICE_SIG);
  42. S390_lowcore.external_new_psw = psw_ext_save;
  43. __ctl_load(cr0.val, 0, 0);
  44. }
  45. int sclp_early_cmd(sclp_cmdw_t cmd, void *sccb)
  46. {
  47. unsigned long flags;
  48. int rc;
  49. raw_local_irq_save(flags);
  50. rc = sclp_service_call(cmd, sccb);
  51. if (rc)
  52. goto out;
  53. sclp_early_wait_irq();
  54. out:
  55. raw_local_irq_restore(flags);
  56. return rc;
  57. }
  58. struct write_sccb {
  59. struct sccb_header header;
  60. struct msg_buf msg;
  61. } __packed;
  62. /* Output multi-line text using SCLP Message interface. */
  63. static void sclp_early_print_lm(const char *str, unsigned int len)
  64. {
  65. unsigned char *ptr, *end, ch;
  66. unsigned int count, offset;
  67. struct write_sccb *sccb;
  68. struct msg_buf *msg;
  69. struct mdb *mdb;
  70. struct mto *mto;
  71. struct go *go;
  72. sccb = (struct write_sccb *) &sclp_early_sccb;
  73. end = (unsigned char *) sccb + sizeof(sclp_early_sccb) - 1;
  74. memset(sccb, 0, sizeof(*sccb));
  75. ptr = (unsigned char *) &sccb->msg.mdb.mto;
  76. offset = 0;
  77. do {
  78. for (count = sizeof(*mto); offset < len; count++) {
  79. ch = str[offset++];
  80. if ((ch == 0x0a) || (ptr + count > end))
  81. break;
  82. ptr[count] = _ascebc[ch];
  83. }
  84. mto = (struct mto *) ptr;
  85. memset(mto, 0, sizeof(*mto));
  86. mto->length = count;
  87. mto->type = 4;
  88. mto->line_type_flags = LNTPFLGS_ENDTEXT;
  89. ptr += count;
  90. } while ((offset < len) && (ptr + sizeof(*mto) <= end));
  91. len = ptr - (unsigned char *) sccb;
  92. sccb->header.length = len - offsetof(struct write_sccb, header);
  93. msg = &sccb->msg;
  94. msg->header.type = EVTYP_MSG;
  95. msg->header.length = len - offsetof(struct write_sccb, msg.header);
  96. mdb = &msg->mdb;
  97. mdb->header.type = 1;
  98. mdb->header.tag = 0xD4C4C240;
  99. mdb->header.revision_code = 1;
  100. mdb->header.length = len - offsetof(struct write_sccb, msg.mdb.header);
  101. go = &mdb->go;
  102. go->length = sizeof(*go);
  103. go->type = 1;
  104. sclp_early_cmd(SCLP_CMDW_WRITE_EVENT_DATA, sccb);
  105. }
  106. struct vt220_sccb {
  107. struct sccb_header header;
  108. struct {
  109. struct evbuf_header header;
  110. char data[];
  111. } msg;
  112. } __packed;
  113. /* Output multi-line text using SCLP VT220 interface. */
  114. static void sclp_early_print_vt220(const char *str, unsigned int len)
  115. {
  116. struct vt220_sccb *sccb;
  117. sccb = (struct vt220_sccb *) &sclp_early_sccb;
  118. if (sizeof(*sccb) + len >= sizeof(sclp_early_sccb))
  119. len = sizeof(sclp_early_sccb) - sizeof(*sccb);
  120. memset(sccb, 0, sizeof(*sccb));
  121. memcpy(&sccb->msg.data, str, len);
  122. sccb->header.length = sizeof(*sccb) + len;
  123. sccb->msg.header.length = sizeof(sccb->msg) + len;
  124. sccb->msg.header.type = EVTYP_VT220MSG;
  125. sclp_early_cmd(SCLP_CMDW_WRITE_EVENT_DATA, sccb);
  126. }
  127. int sclp_early_set_event_mask(struct init_sccb *sccb,
  128. unsigned long receive_mask,
  129. unsigned long send_mask)
  130. {
  131. memset(sccb, 0, sizeof(*sccb));
  132. sccb->header.length = sizeof(*sccb);
  133. sccb->mask_length = sizeof(sccb_mask_t);
  134. sccb->receive_mask = receive_mask;
  135. sccb->send_mask = send_mask;
  136. if (sclp_early_cmd(SCLP_CMDW_WRITE_EVENT_MASK, sccb))
  137. return -EIO;
  138. if (sccb->header.response_code != 0x20)
  139. return -EIO;
  140. return 0;
  141. }
  142. unsigned int sclp_early_con_check_linemode(struct init_sccb *sccb)
  143. {
  144. if (!(sccb->sclp_send_mask & EVTYP_OPCMD_MASK))
  145. return 0;
  146. if (!(sccb->sclp_receive_mask & (EVTYP_MSG_MASK | EVTYP_PMSGCMD_MASK)))
  147. return 0;
  148. return 1;
  149. }
  150. static int sclp_early_setup(int disable, int *have_linemode, int *have_vt220)
  151. {
  152. unsigned long receive_mask, send_mask;
  153. struct init_sccb *sccb;
  154. int rc;
  155. *have_linemode = *have_vt220 = 0;
  156. sccb = (struct init_sccb *) &sclp_early_sccb;
  157. receive_mask = disable ? 0 : EVTYP_OPCMD_MASK;
  158. send_mask = disable ? 0 : EVTYP_VT220MSG_MASK | EVTYP_MSG_MASK;
  159. rc = sclp_early_set_event_mask(sccb, receive_mask, send_mask);
  160. if (rc)
  161. return rc;
  162. *have_linemode = sclp_early_con_check_linemode(sccb);
  163. *have_vt220 = sccb->send_mask & EVTYP_VT220MSG_MASK;
  164. return rc;
  165. }
  166. /*
  167. * Output one or more lines of text on the SCLP console (VT220 and /
  168. * or line-mode).
  169. */
  170. void __sclp_early_printk(const char *str, unsigned int len)
  171. {
  172. int have_linemode, have_vt220;
  173. if (sclp_init_state != sclp_init_state_uninitialized)
  174. return;
  175. if (sclp_early_setup(0, &have_linemode, &have_vt220) != 0)
  176. return;
  177. if (have_linemode)
  178. sclp_early_print_lm(str, len);
  179. if (have_vt220)
  180. sclp_early_print_vt220(str, len);
  181. sclp_early_setup(1, &have_linemode, &have_vt220);
  182. }
  183. void sclp_early_printk(const char *str)
  184. {
  185. __sclp_early_printk(str, strlen(str));
  186. }