qemu/pc-bios/s390-ccw/sclp-ascii.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 "s390-ccw.h"
  12#include "sclp.h"
  13
  14static char _sccb[PAGE_SIZE] __attribute__((__aligned__(4096)));
  15
  16/* Perform service call. Return 0 on success, non-zero otherwise. */
  17static int sclp_service_call(unsigned int command, void *sccb)
  18{
  19        int cc;
  20
  21        asm volatile(
  22                "       .insn   rre,0xb2200000,%1,%2\n"  /* servc %1,%2 */
  23                "       ipm     %0\n"
  24                "       srl     %0,28"
  25                : "=&d" (cc) : "d" (command), "a" (__pa(sccb))
  26                : "cc", "memory");
  27        if (cc == 3)
  28                return -EIO;
  29        if (cc == 2)
  30                return -EBUSY;
  31        return 0;
  32}
  33
  34static void sclp_set_write_mask(void)
  35{
  36    WriteEventMask *sccb = (void *)_sccb;
  37
  38    sccb->h.length = sizeof(WriteEventMask);
  39    sccb->mask_length = sizeof(unsigned int);
  40    sccb->receive_mask = SCLP_EVENT_MASK_MSG_ASCII;
  41    sccb->cp_receive_mask = SCLP_EVENT_MASK_MSG_ASCII;
  42    sccb->send_mask = SCLP_EVENT_MASK_MSG_ASCII;
  43    sccb->cp_send_mask = SCLP_EVENT_MASK_MSG_ASCII;
  44
  45    sclp_service_call(SCLP_CMD_WRITE_EVENT_MASK, sccb);
  46}
  47
  48void sclp_setup(void)
  49{
  50    sclp_set_write_mask();
  51}
  52
  53static int _strlen(const char *str)
  54{
  55    int i;
  56    for (i = 0; *str; i++)
  57        str++;
  58    return i;
  59}
  60
  61static void _memcpy(char *dest, const char *src, int len)
  62{
  63    int i;
  64    for (i = 0; i < len; i++)
  65        dest[i] = src[i];
  66}
  67
  68void sclp_print(const char *str)
  69{
  70    int len = _strlen(str);
  71    WriteEventData *sccb = (void *)_sccb;
  72
  73    sccb->h.length = sizeof(WriteEventData) + len;
  74    sccb->h.function_code = SCLP_FC_NORMAL_WRITE;
  75    sccb->ebh.length = sizeof(EventBufferHeader) + len;
  76    sccb->ebh.type = SCLP_EVENT_ASCII_CONSOLE_DATA;
  77    sccb->ebh.flags = 0;
  78    _memcpy(sccb->data, str, len);
  79
  80    sclp_service_call(SCLP_CMD_WRITE_EVENT_DATA, sccb);
  81}
  82