qemu

FORK: QEMU emulator
git clone https://git.neptards.moe/neptards/qemu.git
Log | Files | Refs | Submodules | LICENSE

sclp.c (3750B)


      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 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 
     61 void sclp_setup(void)
     62 {
     63     sclp_set_write_mask(0, SCLP_EVENT_MASK_MSG_ASCII);
     64 }
     65 
     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 
    104 void sclp_print(const char *str)
    105 {
    106     write(1, str, strlen(str));
    107 }
    108 
    109 void sclp_get_loadparm_ascii(char *loadparm)
    110 {
    111 
    112     ReadInfo *sccb = (void *)_sccb;
    113 
    114     memset((char *)_sccb, 0, sizeof(ReadInfo));
    115     sccb->h.length = SCCB_SIZE;
    116     if (!sclp_service_call(SCLP_CMDW_READ_SCP_INFO, sccb)) {
    117         ebcdic_to_ascii((char *) sccb->loadparm, loadparm, LOADPARM_LEN);
    118     }
    119 }
    120 
    121 int sclp_read(char *str, size_t count)
    122 {
    123     ReadEventData *sccb = (void *)_sccb;
    124     char *buf = (char *)(&sccb->ebh) + 7;
    125 
    126     /* If count exceeds max buffer size, then restrict it to the max size */
    127     if (count > SCCB_SIZE - 8) {
    128         count = SCCB_SIZE - 8;
    129     }
    130 
    131     sccb->h.length = SCCB_SIZE;
    132     sccb->h.function_code = SCLP_UNCONDITIONAL_READ;
    133 
    134     sclp_service_call(SCLP_CMD_READ_EVENT_DATA, sccb);
    135     memcpy(str, buf, count);
    136 
    137     return sccb->ebh.length - 7;
    138 }