xref: /openbmc/qemu/pc-bios/s390-ccw/sclp.c (revision ff5dbf1bc3b81248f4f1c253b586491bc8daeda5)
19a22473cSFarhan Ali /*
29a22473cSFarhan Ali  * SCLP ASCII access driver
39a22473cSFarhan Ali  *
49a22473cSFarhan Ali  * Copyright (c) 2013 Alexander Graf <agraf@suse.de>
59a22473cSFarhan Ali  *
69a22473cSFarhan Ali  * This work is licensed under the terms of the GNU GPL, version 2 or (at
79a22473cSFarhan Ali  * your option) any later version. See the COPYING file in the top-level
89a22473cSFarhan Ali  * directory.
99a22473cSFarhan Ali  */
109a22473cSFarhan Ali 
1190806fecSThomas Huth #include "libc.h"
129a22473cSFarhan Ali #include "s390-ccw.h"
139a22473cSFarhan Ali #include "sclp.h"
149a22473cSFarhan Ali 
153639f93fSThomas Huth long write(int fd, const void *str, size_t len);
163639f93fSThomas Huth 
179a22473cSFarhan Ali static char _sccb[PAGE_SIZE] __attribute__((__aligned__(4096)));
189a22473cSFarhan Ali 
19af3bb73aSThomas Huth const unsigned char ebc2asc[256] =
20af3bb73aSThomas Huth       /* 0123456789abcdef0123456789abcdef */
21af3bb73aSThomas Huth         "................................" /* 1F */
22af3bb73aSThomas Huth         "................................" /* 3F */
23af3bb73aSThomas Huth         " ...........<(+|&.........!$*);." /* 5F first.chr.here.is.real.space */
24af3bb73aSThomas Huth         "-/.........,%_>?.........`:#@'=\""/* 7F */
25af3bb73aSThomas Huth         ".abcdefghi.......jklmnopqr......" /* 9F */
26af3bb73aSThomas Huth         "..stuvwxyz......................" /* BF */
27af3bb73aSThomas Huth         ".ABCDEFGHI.......JKLMNOPQR......" /* DF */
28af3bb73aSThomas Huth         "..STUVWXYZ......0123456789......";/* FF */
29af3bb73aSThomas Huth 
309a22473cSFarhan Ali /* Perform service call. Return 0 on success, non-zero otherwise. */
319a22473cSFarhan Ali static int sclp_service_call(unsigned int command, void *sccb)
329a22473cSFarhan Ali {
339a22473cSFarhan Ali         int cc;
349a22473cSFarhan Ali 
359a22473cSFarhan Ali         asm volatile(
369a22473cSFarhan Ali                 "       .insn   rre,0xb2200000,%1,%2\n"  /* servc %1,%2 */
379a22473cSFarhan Ali                 "       ipm     %0\n"
389a22473cSFarhan Ali                 "       srl     %0,28"
399a22473cSFarhan Ali                 : "=&d" (cc) : "d" (command), "a" (__pa(sccb))
409a22473cSFarhan Ali                 : "cc", "memory");
419a22473cSFarhan Ali         consume_sclp_int();
429a22473cSFarhan Ali         if (cc == 3)
439a22473cSFarhan Ali                 return -EIO;
449a22473cSFarhan Ali         if (cc == 2)
459a22473cSFarhan Ali                 return -EBUSY;
469a22473cSFarhan Ali         return 0;
479a22473cSFarhan Ali }
489a22473cSFarhan Ali 
499a22473cSFarhan Ali static void sclp_set_write_mask(void)
509a22473cSFarhan Ali {
519a22473cSFarhan Ali     WriteEventMask *sccb = (void *)_sccb;
529a22473cSFarhan Ali 
539a22473cSFarhan Ali     sccb->h.length = sizeof(WriteEventMask);
549a22473cSFarhan Ali     sccb->mask_length = sizeof(unsigned int);
559a22473cSFarhan Ali     sccb->receive_mask = SCLP_EVENT_MASK_MSG_ASCII;
569a22473cSFarhan Ali     sccb->cp_receive_mask = SCLP_EVENT_MASK_MSG_ASCII;
579a22473cSFarhan Ali     sccb->send_mask = SCLP_EVENT_MASK_MSG_ASCII;
589a22473cSFarhan Ali     sccb->cp_send_mask = SCLP_EVENT_MASK_MSG_ASCII;
599a22473cSFarhan Ali 
609a22473cSFarhan Ali     sclp_service_call(SCLP_CMD_WRITE_EVENT_MASK, sccb);
619a22473cSFarhan Ali }
629a22473cSFarhan Ali 
639a22473cSFarhan Ali void sclp_setup(void)
649a22473cSFarhan Ali {
659a22473cSFarhan Ali     sclp_set_write_mask();
669a22473cSFarhan Ali }
679a22473cSFarhan Ali 
683639f93fSThomas Huth long write(int fd, const void *str, size_t len)
699a22473cSFarhan Ali {
709a22473cSFarhan Ali     WriteEventData *sccb = (void *)_sccb;
717618c0aeSCollin L. Walling     const char *p = str;
727618c0aeSCollin L. Walling     size_t data_len = 0;
737618c0aeSCollin L. Walling     size_t i;
749a22473cSFarhan Ali 
753639f93fSThomas Huth     if (fd != 1 && fd != 2) {
763639f93fSThomas Huth         return -EIO;
773639f93fSThomas Huth     }
783639f93fSThomas Huth 
797618c0aeSCollin L. Walling     for (i = 0; i < len; i++) {
807618c0aeSCollin L. Walling         if ((data_len + 1) >= SCCB_DATA_LEN) {
817618c0aeSCollin L. Walling             /* We would overflow the sccb buffer, abort early */
827618c0aeSCollin L. Walling             len = i;
837618c0aeSCollin L. Walling             break;
847618c0aeSCollin L. Walling         }
857618c0aeSCollin L. Walling 
867618c0aeSCollin L. Walling         if (*p == '\n') {
877618c0aeSCollin L. Walling             /* Terminal emulators might need \r\n, so generate it */
887618c0aeSCollin L. Walling             sccb->data[data_len++] = '\r';
897618c0aeSCollin L. Walling         }
907618c0aeSCollin L. Walling 
917618c0aeSCollin L. Walling         sccb->data[data_len++] = *p;
927618c0aeSCollin L. Walling         p++;
937618c0aeSCollin L. Walling     }
947618c0aeSCollin L. Walling 
957618c0aeSCollin L. Walling     sccb->h.length = sizeof(WriteEventData) + data_len;
969a22473cSFarhan Ali     sccb->h.function_code = SCLP_FC_NORMAL_WRITE;
977618c0aeSCollin L. Walling     sccb->ebh.length = sizeof(EventBufferHeader) + data_len;
989a22473cSFarhan Ali     sccb->ebh.type = SCLP_EVENT_ASCII_CONSOLE_DATA;
999a22473cSFarhan Ali     sccb->ebh.flags = 0;
1009a22473cSFarhan Ali 
1019a22473cSFarhan Ali     sclp_service_call(SCLP_CMD_WRITE_EVENT_DATA, sccb);
1023639f93fSThomas Huth 
1033639f93fSThomas Huth     return len;
1043639f93fSThomas Huth }
1053639f93fSThomas Huth 
1063639f93fSThomas Huth void sclp_print(const char *str)
1073639f93fSThomas Huth {
108fc0e2087SCollin L. Walling     write(1, str, strlen(str));
1099a22473cSFarhan Ali }
1109a22473cSFarhan Ali 
1119a22473cSFarhan Ali void sclp_get_loadparm_ascii(char *loadparm)
1129a22473cSFarhan Ali {
1139a22473cSFarhan Ali 
1149a22473cSFarhan Ali     ReadInfo *sccb = (void *)_sccb;
1159a22473cSFarhan Ali 
1169a22473cSFarhan Ali     memset((char *)_sccb, 0, sizeof(ReadInfo));
1179a22473cSFarhan Ali     sccb->h.length = sizeof(ReadInfo);
1189a22473cSFarhan Ali     if (!sclp_service_call(SCLP_CMDW_READ_SCP_INFO, sccb)) {
1199a22473cSFarhan Ali         ebcdic_to_ascii((char *) sccb->loadparm, loadparm, 8);
1209a22473cSFarhan Ali     }
1219a22473cSFarhan Ali }
122*ff5dbf1bSCollin L. Walling 
123*ff5dbf1bSCollin L. Walling int sclp_read(char *str, size_t count)
124*ff5dbf1bSCollin L. Walling {
125*ff5dbf1bSCollin L. Walling     ReadEventData *sccb = (void *)_sccb;
126*ff5dbf1bSCollin L. Walling     char *buf = (char *)(&sccb->ebh) + 7;
127*ff5dbf1bSCollin L. Walling 
128*ff5dbf1bSCollin L. Walling     /* If count exceeds max buffer size, then restrict it to the max size */
129*ff5dbf1bSCollin L. Walling     if (count > SCCB_SIZE - 8) {
130*ff5dbf1bSCollin L. Walling         count = SCCB_SIZE - 8;
131*ff5dbf1bSCollin L. Walling     }
132*ff5dbf1bSCollin L. Walling 
133*ff5dbf1bSCollin L. Walling     sccb->h.length = SCCB_SIZE;
134*ff5dbf1bSCollin L. Walling     sccb->h.function_code = SCLP_UNCONDITIONAL_READ;
135*ff5dbf1bSCollin L. Walling 
136*ff5dbf1bSCollin L. Walling     sclp_service_call(SCLP_CMD_READ_EVENT_DATA, sccb);
137*ff5dbf1bSCollin L. Walling     memcpy(str, buf, count);
138*ff5dbf1bSCollin L. Walling 
139*ff5dbf1bSCollin L. Walling     return sccb->ebh.length - 7;
140*ff5dbf1bSCollin L. Walling }
141