~ahs3/+junk/cq-qemu

« back to all changes in this revision

Viewing changes to hw/spapr_vty.c

  • Committer: Al Stone
  • Date: 2012-02-09 01:17:20 UTC
  • Revision ID: albert.stone@canonical.com-20120209011720-tztl7ik3qayz80p4
first commit to bzr for qemu

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
#include "qdev.h"
 
2
#include "qemu-char.h"
 
3
#include "hw/spapr.h"
 
4
#include "hw/spapr_vio.h"
 
5
 
 
6
#define VTERM_BUFSIZE   16
 
7
 
 
8
typedef struct VIOsPAPRVTYDevice {
 
9
    VIOsPAPRDevice sdev;
 
10
    CharDriverState *chardev;
 
11
    uint32_t in, out;
 
12
    uint8_t buf[VTERM_BUFSIZE];
 
13
} VIOsPAPRVTYDevice;
 
14
 
 
15
static int vty_can_receive(void *opaque)
 
16
{
 
17
    VIOsPAPRVTYDevice *dev = (VIOsPAPRVTYDevice *)opaque;
 
18
 
 
19
    return (dev->in - dev->out) < VTERM_BUFSIZE;
 
20
}
 
21
 
 
22
static void vty_receive(void *opaque, const uint8_t *buf, int size)
 
23
{
 
24
    VIOsPAPRVTYDevice *dev = (VIOsPAPRVTYDevice *)opaque;
 
25
    int i;
 
26
 
 
27
    if ((dev->in == dev->out) && size) {
 
28
        /* toggle line to simulate edge interrupt */
 
29
        qemu_irq_pulse(dev->sdev.qirq);
 
30
    }
 
31
    for (i = 0; i < size; i++) {
 
32
        assert((dev->in - dev->out) < VTERM_BUFSIZE);
 
33
        dev->buf[dev->in++ % VTERM_BUFSIZE] = buf[i];
 
34
    }
 
35
}
 
36
 
 
37
static int vty_getchars(VIOsPAPRDevice *sdev, uint8_t *buf, int max)
 
38
{
 
39
    VIOsPAPRVTYDevice *dev = (VIOsPAPRVTYDevice *)sdev;
 
40
    int n = 0;
 
41
 
 
42
    while ((n < max) && (dev->out != dev->in)) {
 
43
        buf[n++] = dev->buf[dev->out++ % VTERM_BUFSIZE];
 
44
    }
 
45
 
 
46
    return n;
 
47
}
 
48
 
 
49
void vty_putchars(VIOsPAPRDevice *sdev, uint8_t *buf, int len)
 
50
{
 
51
    VIOsPAPRVTYDevice *dev = (VIOsPAPRVTYDevice *)sdev;
 
52
 
 
53
    /* FIXME: should check the qemu_chr_fe_write() return value */
 
54
    qemu_chr_fe_write(dev->chardev, buf, len);
 
55
}
 
56
 
 
57
static int spapr_vty_init(VIOsPAPRDevice *sdev)
 
58
{
 
59
    VIOsPAPRVTYDevice *dev = (VIOsPAPRVTYDevice *)sdev;
 
60
 
 
61
    if (!dev->chardev) {
 
62
        fprintf(stderr, "spapr-vty: Can't create vty without a chardev!\n");
 
63
        exit(1);
 
64
    }
 
65
 
 
66
    qemu_chr_add_handlers(dev->chardev, vty_can_receive,
 
67
                          vty_receive, NULL, dev);
 
68
 
 
69
    return 0;
 
70
}
 
71
 
 
72
/* Forward declaration */
 
73
static VIOsPAPRDevice *vty_lookup(sPAPREnvironment *spapr, target_ulong reg);
 
74
 
 
75
static target_ulong h_put_term_char(CPUState *env, sPAPREnvironment *spapr,
 
76
                                    target_ulong opcode, target_ulong *args)
 
77
{
 
78
    target_ulong reg = args[0];
 
79
    target_ulong len = args[1];
 
80
    target_ulong char0_7 = args[2];
 
81
    target_ulong char8_15 = args[3];
 
82
    VIOsPAPRDevice *sdev;
 
83
    uint8_t buf[16];
 
84
 
 
85
    sdev = vty_lookup(spapr, reg);
 
86
    if (!sdev) {
 
87
        return H_PARAMETER;
 
88
    }
 
89
 
 
90
    if (len > 16) {
 
91
        return H_PARAMETER;
 
92
    }
 
93
 
 
94
    *((uint64_t *)buf) = cpu_to_be64(char0_7);
 
95
    *((uint64_t *)buf + 1) = cpu_to_be64(char8_15);
 
96
 
 
97
    vty_putchars(sdev, buf, len);
 
98
 
 
99
    return H_SUCCESS;
 
100
}
 
101
 
 
102
static target_ulong h_get_term_char(CPUState *env, sPAPREnvironment *spapr,
 
103
                                    target_ulong opcode, target_ulong *args)
 
104
{
 
105
    target_ulong reg = args[0];
 
106
    target_ulong *len = args + 0;
 
107
    target_ulong *char0_7 = args + 1;
 
108
    target_ulong *char8_15 = args + 2;
 
109
    VIOsPAPRDevice *sdev;
 
110
    uint8_t buf[16];
 
111
 
 
112
    sdev = vty_lookup(spapr, reg);
 
113
    if (!sdev) {
 
114
        return H_PARAMETER;
 
115
    }
 
116
 
 
117
    *len = vty_getchars(sdev, buf, sizeof(buf));
 
118
    if (*len < 16) {
 
119
        memset(buf + *len, 0, 16 - *len);
 
120
    }
 
121
 
 
122
    *char0_7 = be64_to_cpu(*((uint64_t *)buf));
 
123
    *char8_15 = be64_to_cpu(*((uint64_t *)buf + 1));
 
124
 
 
125
    return H_SUCCESS;
 
126
}
 
127
 
 
128
void spapr_vty_create(VIOsPAPRBus *bus, uint32_t reg, CharDriverState *chardev)
 
129
{
 
130
    DeviceState *dev;
 
131
 
 
132
    dev = qdev_create(&bus->bus, "spapr-vty");
 
133
    qdev_prop_set_uint32(dev, "reg", reg);
 
134
    qdev_prop_set_chr(dev, "chardev", chardev);
 
135
    qdev_init_nofail(dev);
 
136
}
 
137
 
 
138
static void vty_hcalls(VIOsPAPRBus *bus)
 
139
{
 
140
    spapr_register_hypercall(H_PUT_TERM_CHAR, h_put_term_char);
 
141
    spapr_register_hypercall(H_GET_TERM_CHAR, h_get_term_char);
 
142
}
 
143
 
 
144
static VIOsPAPRDeviceInfo spapr_vty = {
 
145
    .init = spapr_vty_init,
 
146
    .dt_name = "vty",
 
147
    .dt_type = "serial",
 
148
    .dt_compatible = "hvterm1",
 
149
    .hcalls = vty_hcalls,
 
150
    .qdev.name = "spapr-vty",
 
151
    .qdev.size = sizeof(VIOsPAPRVTYDevice),
 
152
    .qdev.props = (Property[]) {
 
153
        DEFINE_SPAPR_PROPERTIES(VIOsPAPRVTYDevice, sdev, SPAPR_VTY_BASE_ADDRESS, 0),
 
154
        DEFINE_PROP_CHR("chardev", VIOsPAPRVTYDevice, chardev),
 
155
        DEFINE_PROP_END_OF_LIST(),
 
156
    },
 
157
};
 
158
 
 
159
static VIOsPAPRDevice *vty_lookup(sPAPREnvironment *spapr, target_ulong reg)
 
160
{
 
161
    VIOsPAPRDevice *sdev;
 
162
 
 
163
    sdev = spapr_vio_find_by_reg(spapr->vio_bus, reg);
 
164
    if (!sdev && reg == 0) {
 
165
        DeviceState *qdev;
 
166
 
 
167
        /* Hack for kernel early debug, which always specifies reg==0.
 
168
         * We search all VIO devices, and grab the first available vty
 
169
         * device.  This attempts to mimic existing PowerVM behaviour
 
170
         * (early debug does work there, despite having no vty with
 
171
         * reg==0. */
 
172
        QTAILQ_FOREACH(qdev, &spapr->vio_bus->bus.children, sibling) {
 
173
            if (qdev->info == &spapr_vty.qdev) {
 
174
                return DO_UPCAST(VIOsPAPRDevice, qdev, qdev);
 
175
            }
 
176
        }
 
177
    }
 
178
 
 
179
    return sdev;
 
180
}
 
181
 
 
182
static void spapr_vty_register(void)
 
183
{
 
184
    spapr_vio_bus_register_withprop(&spapr_vty);
 
185
}
 
186
device_init(spapr_vty_register);