Statistics
| Branch: | Revision:

root / hw / spapr_vty.c @ 94afdadc

History | View | Annotate | Download (5.5 kB)

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 VIOsPAPRDeviceInfo spapr_vty = {
139
    .init = spapr_vty_init,
140
    .dt_name = "vty",
141
    .dt_type = "serial",
142
    .dt_compatible = "hvterm1",
143
    .qdev.name = "spapr-vty",
144
    .qdev.size = sizeof(VIOsPAPRVTYDevice),
145
    .qdev.props = (Property[]) {
146
        DEFINE_SPAPR_PROPERTIES(VIOsPAPRVTYDevice, sdev, SPAPR_VTY_BASE_ADDRESS, 0),
147
        DEFINE_PROP_CHR("chardev", VIOsPAPRVTYDevice, chardev),
148
        DEFINE_PROP_END_OF_LIST(),
149
    },
150
};
151

    
152
VIOsPAPRDevice *spapr_vty_get_default(VIOsPAPRBus *bus)
153
{
154
    VIOsPAPRDevice *sdev, *selected;
155
    DeviceState *iter;
156

    
157
    /*
158
     * To avoid the console bouncing around we want one VTY to be
159
     * the "default". We haven't really got anything to go on, so
160
     * arbitrarily choose the one with the lowest reg value.
161
     */
162

    
163
    selected = NULL;
164
    QTAILQ_FOREACH(iter, &bus->bus.children, sibling) {
165
        /* Only look at VTY devices */
166
        if (qdev_get_info(iter) != &spapr_vty.qdev) {
167
            continue;
168
        }
169

    
170
        sdev = DO_UPCAST(VIOsPAPRDevice, qdev, iter);
171

    
172
        /* First VTY we've found, so it is selected for now */
173
        if (!selected) {
174
            selected = sdev;
175
            continue;
176
        }
177

    
178
        /* Choose VTY with lowest reg value */
179
        if (sdev->reg < selected->reg) {
180
            selected = sdev;
181
        }
182
    }
183

    
184
    return selected;
185
}
186

    
187
static VIOsPAPRDevice *vty_lookup(sPAPREnvironment *spapr, target_ulong reg)
188
{
189
    VIOsPAPRDevice *sdev;
190

    
191
    sdev = spapr_vio_find_by_reg(spapr->vio_bus, reg);
192
    if (!sdev && reg == 0) {
193
        /* Hack for kernel early debug, which always specifies reg==0.
194
         * We search all VIO devices, and grab the vty with the lowest
195
         * reg.  This attempts to mimic existing PowerVM behaviour
196
         * (early debug does work there, despite having no vty with
197
         * reg==0. */
198
        return spapr_vty_get_default(spapr->vio_bus);
199
    }
200

    
201
    return sdev;
202
}
203

    
204
static void spapr_vty_register(void)
205
{
206
    spapr_vio_bus_register_withprop(&spapr_vty);
207
    spapr_register_hypercall(H_PUT_TERM_CHAR, h_put_term_char);
208
    spapr_register_hypercall(H_GET_TERM_CHAR, h_get_term_char);
209
}
210
device_init(spapr_vty_register);