xref: /openbmc/qemu/pc-bios/s390-ccw/sclp.c (revision 406d2aa2)
1 /*
2  * SCLP ASCII access driver
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-ccw.h"
13 #include "sclp.h"
14 
15 long write(int fd, const void *str, size_t len);
16 
17 static char _sccb[PAGE_SIZE] __attribute__((__aligned__(4096)));
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 /* Perform service call. Return 0 on success, non-zero otherwise. */
31 static int sclp_service_call(unsigned int command, void *sccb)
32 {
33         int cc;
34 
35         asm volatile(
36                 "       .insn   rre,0xb2200000,%1,%2\n"  /* servc %1,%2 */
37                 "       ipm     %0\n"
38                 "       srl     %0,28"
39                 : "=&d" (cc) : "d" (command), "a" (__pa(sccb))
40                 : "cc", "memory");
41         consume_sclp_int();
42         if (cc == 3)
43                 return -EIO;
44         if (cc == 2)
45                 return -EBUSY;
46         return 0;
47 }
48 
49 static void sclp_set_write_mask(void)
50 {
51     WriteEventMask *sccb = (void *)_sccb;
52 
53     sccb->h.length = sizeof(WriteEventMask);
54     sccb->mask_length = sizeof(unsigned int);
55     sccb->receive_mask = SCLP_EVENT_MASK_MSG_ASCII;
56     sccb->cp_receive_mask = SCLP_EVENT_MASK_MSG_ASCII;
57     sccb->send_mask = SCLP_EVENT_MASK_MSG_ASCII;
58     sccb->cp_send_mask = SCLP_EVENT_MASK_MSG_ASCII;
59 
60     sclp_service_call(SCLP_CMD_WRITE_EVENT_MASK, sccb);
61 }
62 
63 void sclp_setup(void)
64 {
65     sclp_set_write_mask();
66 }
67 
68 static int _strlen(const char *str)
69 {
70     int i;
71     for (i = 0; *str; i++)
72         str++;
73     return i;
74 }
75 
76 long write(int fd, const void *str, size_t len)
77 {
78     WriteEventData *sccb = (void *)_sccb;
79     const char *p = str;
80     size_t data_len = 0;
81     size_t i;
82 
83     if (fd != 1 && fd != 2) {
84         return -EIO;
85     }
86 
87     for (i = 0; i < len; i++) {
88         if ((data_len + 1) >= SCCB_DATA_LEN) {
89             /* We would overflow the sccb buffer, abort early */
90             len = i;
91             break;
92         }
93 
94         if (*p == '\n') {
95             /* Terminal emulators might need \r\n, so generate it */
96             sccb->data[data_len++] = '\r';
97         }
98 
99         sccb->data[data_len++] = *p;
100         p++;
101     }
102 
103     sccb->h.length = sizeof(WriteEventData) + data_len;
104     sccb->h.function_code = SCLP_FC_NORMAL_WRITE;
105     sccb->ebh.length = sizeof(EventBufferHeader) + data_len;
106     sccb->ebh.type = SCLP_EVENT_ASCII_CONSOLE_DATA;
107     sccb->ebh.flags = 0;
108 
109     sclp_service_call(SCLP_CMD_WRITE_EVENT_DATA, sccb);
110 
111     return len;
112 }
113 
114 void sclp_print(const char *str)
115 {
116     write(1, str, _strlen(str));
117 }
118 
119 void sclp_get_loadparm_ascii(char *loadparm)
120 {
121 
122     ReadInfo *sccb = (void *)_sccb;
123 
124     memset((char *)_sccb, 0, sizeof(ReadInfo));
125     sccb->h.length = sizeof(ReadInfo);
126     if (!sclp_service_call(SCLP_CMDW_READ_SCP_INFO, sccb)) {
127         ebcdic_to_ascii((char *) sccb->loadparm, loadparm, 8);
128     }
129 }
130