xref: /openbmc/qemu/pc-bios/s390-ccw/sclp.c (revision e17e57e862faf6e1f372385c18dcf6d3fd31158e)
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 <string.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. */
sclp_service_call(unsigned int command,void * sccb)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  
sclp_set_write_mask(uint32_t receive_mask,uint32_t send_mask)49  void sclp_set_write_mask(uint32_t receive_mask, uint32_t send_mask)
50  {
51      WriteEventMask *sccb = (void *)_sccb;
52  
53      sccb->h.length = sizeof(WriteEventMask);
54      sccb->mask_length = sizeof(unsigned int);
55      sccb->cp_receive_mask = receive_mask;
56      sccb->cp_send_mask = send_mask;
57  
58      sclp_service_call(SCLP_CMD_WRITE_EVENT_MASK, sccb);
59  }
60  
sclp_setup(void)61  void sclp_setup(void)
62  {
63      sclp_set_write_mask(0, SCLP_EVENT_MASK_MSG_ASCII);
64  }
65  
write(int fd,const void * str,size_t len)66  long write(int fd, const void *str, size_t len)
67  {
68      WriteEventData *sccb = (void *)_sccb;
69      const char *p = str;
70      size_t data_len = 0;
71      size_t i;
72  
73      if (fd != 1 && fd != 2) {
74          return -EIO;
75      }
76  
77      for (i = 0; i < len; i++) {
78          if ((data_len + 1) >= SCCB_DATA_LEN) {
79              /* We would overflow the sccb buffer, abort early */
80              len = i;
81              break;
82          }
83  
84          if (*p == '\n') {
85              /* Terminal emulators might need \r\n, so generate it */
86              sccb->data[data_len++] = '\r';
87          }
88  
89          sccb->data[data_len++] = *p;
90          p++;
91      }
92  
93      sccb->h.length = sizeof(WriteEventData) + data_len;
94      sccb->h.function_code = SCLP_FC_NORMAL_WRITE;
95      sccb->ebh.length = sizeof(EventBufferHeader) + data_len;
96      sccb->ebh.type = SCLP_EVENT_ASCII_CONSOLE_DATA;
97      sccb->ebh.flags = 0;
98  
99      sclp_service_call(SCLP_CMD_WRITE_EVENT_DATA, sccb);
100  
101      return len;
102  }
103  
sclp_get_loadparm_ascii(char * loadparm)104  void sclp_get_loadparm_ascii(char *loadparm)
105  {
106  
107      ReadInfo *sccb = (void *)_sccb;
108  
109      memset((char *)_sccb, 0, sizeof(ReadInfo));
110      sccb->h.length = SCCB_SIZE;
111      if (!sclp_service_call(SCLP_CMDW_READ_SCP_INFO, sccb)) {
112          ebcdic_to_ascii((char *) sccb->loadparm, loadparm, LOADPARM_LEN);
113      }
114  }
115  
sclp_read(char * str,size_t count)116  int sclp_read(char *str, size_t count)
117  {
118      ReadEventData *sccb = (void *)_sccb;
119      char *buf = (char *)(&sccb->ebh) + 7;
120  
121      /* If count exceeds max buffer size, then restrict it to the max size */
122      if (count > SCCB_SIZE - 8) {
123          count = SCCB_SIZE - 8;
124      }
125  
126      sccb->h.length = SCCB_SIZE;
127      sccb->h.function_code = SCLP_UNCONDITIONAL_READ;
128  
129      sclp_service_call(SCLP_CMD_READ_EVENT_DATA, sccb);
130      memcpy(str, buf, count);
131  
132      return sccb->ebh.length - 7;
133  }
134