qemu/pc-bios/s390-ccw/sclp.c
<<
>>
Prefs
   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
  15long write(int fd, const void *str, size_t len);
  16
  17static char _sccb[PAGE_SIZE] __attribute__((__aligned__(4096)));
  18
  19const 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. */
  31static 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
  49void 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
  61void sclp_setup(void)
  62{
  63    sclp_set_write_mask(0, SCLP_EVENT_MASK_MSG_ASCII);
  64}
  65
  66long 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
 104void sclp_print(const char *str)
 105{
 106    write(1, str, strlen(str));
 107}
 108
 109void 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
 121int 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}
 139