root / hw / spapr_vty.c @ 0dad6c35
History | View | Annotate | Download (5.8 kB)
1 | 4040ab72 | David Gibson | #include "qdev.h" |
---|---|---|---|
2 | 4040ab72 | David Gibson | #include "qemu-char.h" |
3 | 4040ab72 | David Gibson | #include "hw/spapr.h" |
4 | 4040ab72 | David Gibson | #include "hw/spapr_vio.h" |
5 | 4040ab72 | David Gibson | |
6 | 4040ab72 | David Gibson | #define VTERM_BUFSIZE 16 |
7 | 4040ab72 | David Gibson | |
8 | 4040ab72 | David Gibson | typedef struct VIOsPAPRVTYDevice { |
9 | 4040ab72 | David Gibson | VIOsPAPRDevice sdev; |
10 | 4040ab72 | David Gibson | CharDriverState *chardev; |
11 | 4040ab72 | David Gibson | uint32_t in, out; |
12 | 4040ab72 | David Gibson | uint8_t buf[VTERM_BUFSIZE]; |
13 | 4040ab72 | David Gibson | } VIOsPAPRVTYDevice; |
14 | 4040ab72 | David Gibson | |
15 | 4040ab72 | David Gibson | static int vty_can_receive(void *opaque) |
16 | 4040ab72 | David Gibson | { |
17 | 4040ab72 | David Gibson | VIOsPAPRVTYDevice *dev = (VIOsPAPRVTYDevice *)opaque; |
18 | 4040ab72 | David Gibson | |
19 | 4040ab72 | David Gibson | return (dev->in - dev->out) < VTERM_BUFSIZE;
|
20 | 4040ab72 | David Gibson | } |
21 | 4040ab72 | David Gibson | |
22 | 4040ab72 | David Gibson | static void vty_receive(void *opaque, const uint8_t *buf, int size) |
23 | 4040ab72 | David Gibson | { |
24 | 4040ab72 | David Gibson | VIOsPAPRVTYDevice *dev = (VIOsPAPRVTYDevice *)opaque; |
25 | 4040ab72 | David Gibson | int i;
|
26 | 4040ab72 | David Gibson | |
27 | 0201e2da | David Gibson | if ((dev->in == dev->out) && size) {
|
28 | 0201e2da | David Gibson | /* toggle line to simulate edge interrupt */
|
29 | 0201e2da | David Gibson | qemu_irq_pulse(dev->sdev.qirq); |
30 | 0201e2da | David Gibson | } |
31 | 4040ab72 | David Gibson | for (i = 0; i < size; i++) { |
32 | 4040ab72 | David Gibson | assert((dev->in - dev->out) < VTERM_BUFSIZE); |
33 | 4040ab72 | David Gibson | dev->buf[dev->in++ % VTERM_BUFSIZE] = buf[i]; |
34 | 4040ab72 | David Gibson | } |
35 | 4040ab72 | David Gibson | } |
36 | 4040ab72 | David Gibson | |
37 | 4040ab72 | David Gibson | static int vty_getchars(VIOsPAPRDevice *sdev, uint8_t *buf, int max) |
38 | 4040ab72 | David Gibson | { |
39 | 4040ab72 | David Gibson | VIOsPAPRVTYDevice *dev = (VIOsPAPRVTYDevice *)sdev; |
40 | 4040ab72 | David Gibson | int n = 0; |
41 | 4040ab72 | David Gibson | |
42 | 4040ab72 | David Gibson | while ((n < max) && (dev->out != dev->in)) {
|
43 | 4040ab72 | David Gibson | buf[n++] = dev->buf[dev->out++ % VTERM_BUFSIZE]; |
44 | 4040ab72 | David Gibson | } |
45 | 4040ab72 | David Gibson | |
46 | 4040ab72 | David Gibson | return n;
|
47 | 4040ab72 | David Gibson | } |
48 | 4040ab72 | David Gibson | |
49 | 4040ab72 | David Gibson | void vty_putchars(VIOsPAPRDevice *sdev, uint8_t *buf, int len) |
50 | 4040ab72 | David Gibson | { |
51 | 4040ab72 | David Gibson | VIOsPAPRVTYDevice *dev = (VIOsPAPRVTYDevice *)sdev; |
52 | 4040ab72 | David Gibson | |
53 | 2cc6e0a1 | Anthony Liguori | /* FIXME: should check the qemu_chr_fe_write() return value */
|
54 | 2cc6e0a1 | Anthony Liguori | qemu_chr_fe_write(dev->chardev, buf, len); |
55 | 4040ab72 | David Gibson | } |
56 | 4040ab72 | David Gibson | |
57 | 4040ab72 | David Gibson | static int spapr_vty_init(VIOsPAPRDevice *sdev) |
58 | 4040ab72 | David Gibson | { |
59 | 4040ab72 | David Gibson | VIOsPAPRVTYDevice *dev = (VIOsPAPRVTYDevice *)sdev; |
60 | 4040ab72 | David Gibson | |
61 | 57285302 | Michael Ellerman | if (!dev->chardev) {
|
62 | 57285302 | Michael Ellerman | fprintf(stderr, "spapr-vty: Can't create vty without a chardev!\n");
|
63 | 57285302 | Michael Ellerman | exit(1);
|
64 | 57285302 | Michael Ellerman | } |
65 | 57285302 | Michael Ellerman | |
66 | 4040ab72 | David Gibson | qemu_chr_add_handlers(dev->chardev, vty_can_receive, |
67 | 4040ab72 | David Gibson | vty_receive, NULL, dev);
|
68 | 4040ab72 | David Gibson | |
69 | 4040ab72 | David Gibson | return 0; |
70 | 4040ab72 | David Gibson | } |
71 | 4040ab72 | David Gibson | |
72 | 3feef8ad | David Gibson | /* Forward declaration */
|
73 | 3feef8ad | David Gibson | static VIOsPAPRDevice *vty_lookup(sPAPREnvironment *spapr, target_ulong reg);
|
74 | 3feef8ad | David Gibson | |
75 | 4040ab72 | David Gibson | static target_ulong h_put_term_char(CPUState *env, sPAPREnvironment *spapr,
|
76 | 4040ab72 | David Gibson | target_ulong opcode, target_ulong *args) |
77 | 4040ab72 | David Gibson | { |
78 | 4040ab72 | David Gibson | target_ulong reg = args[0];
|
79 | 4040ab72 | David Gibson | target_ulong len = args[1];
|
80 | 4040ab72 | David Gibson | target_ulong char0_7 = args[2];
|
81 | 4040ab72 | David Gibson | target_ulong char8_15 = args[3];
|
82 | 3feef8ad | David Gibson | VIOsPAPRDevice *sdev; |
83 | 4040ab72 | David Gibson | uint8_t buf[16];
|
84 | 4040ab72 | David Gibson | |
85 | 3feef8ad | David Gibson | sdev = vty_lookup(spapr, reg); |
86 | 4040ab72 | David Gibson | if (!sdev) {
|
87 | 4040ab72 | David Gibson | return H_PARAMETER;
|
88 | 4040ab72 | David Gibson | } |
89 | 4040ab72 | David Gibson | |
90 | 4040ab72 | David Gibson | if (len > 16) { |
91 | 4040ab72 | David Gibson | return H_PARAMETER;
|
92 | 4040ab72 | David Gibson | } |
93 | 4040ab72 | David Gibson | |
94 | 4040ab72 | David Gibson | *((uint64_t *)buf) = cpu_to_be64(char0_7); |
95 | 4040ab72 | David Gibson | *((uint64_t *)buf + 1) = cpu_to_be64(char8_15);
|
96 | 4040ab72 | David Gibson | |
97 | 4040ab72 | David Gibson | vty_putchars(sdev, buf, len); |
98 | 4040ab72 | David Gibson | |
99 | 4040ab72 | David Gibson | return H_SUCCESS;
|
100 | 4040ab72 | David Gibson | } |
101 | 4040ab72 | David Gibson | |
102 | 4040ab72 | David Gibson | static target_ulong h_get_term_char(CPUState *env, sPAPREnvironment *spapr,
|
103 | 4040ab72 | David Gibson | target_ulong opcode, target_ulong *args) |
104 | 4040ab72 | David Gibson | { |
105 | 4040ab72 | David Gibson | target_ulong reg = args[0];
|
106 | 4040ab72 | David Gibson | target_ulong *len = args + 0;
|
107 | 4040ab72 | David Gibson | target_ulong *char0_7 = args + 1;
|
108 | 4040ab72 | David Gibson | target_ulong *char8_15 = args + 2;
|
109 | 3feef8ad | David Gibson | VIOsPAPRDevice *sdev; |
110 | 4040ab72 | David Gibson | uint8_t buf[16];
|
111 | 4040ab72 | David Gibson | |
112 | 3feef8ad | David Gibson | sdev = vty_lookup(spapr, reg); |
113 | 4040ab72 | David Gibson | if (!sdev) {
|
114 | 4040ab72 | David Gibson | return H_PARAMETER;
|
115 | 4040ab72 | David Gibson | } |
116 | 4040ab72 | David Gibson | |
117 | 4040ab72 | David Gibson | *len = vty_getchars(sdev, buf, sizeof(buf));
|
118 | 4040ab72 | David Gibson | if (*len < 16) { |
119 | 4040ab72 | David Gibson | memset(buf + *len, 0, 16 - *len); |
120 | 4040ab72 | David Gibson | } |
121 | 4040ab72 | David Gibson | |
122 | 4040ab72 | David Gibson | *char0_7 = be64_to_cpu(*((uint64_t *)buf)); |
123 | 4040ab72 | David Gibson | *char8_15 = be64_to_cpu(*((uint64_t *)buf + 1));
|
124 | 4040ab72 | David Gibson | |
125 | 4040ab72 | David Gibson | return H_SUCCESS;
|
126 | 4040ab72 | David Gibson | } |
127 | 4040ab72 | David Gibson | |
128 | 277f9acf | Paolo Bonzini | void spapr_vty_create(VIOsPAPRBus *bus, uint32_t reg, CharDriverState *chardev)
|
129 | 4040ab72 | David Gibson | { |
130 | 4040ab72 | David Gibson | DeviceState *dev; |
131 | 4040ab72 | David Gibson | |
132 | 4040ab72 | David Gibson | dev = qdev_create(&bus->bus, "spapr-vty");
|
133 | 4040ab72 | David Gibson | qdev_prop_set_uint32(dev, "reg", reg);
|
134 | 4040ab72 | David Gibson | qdev_prop_set_chr(dev, "chardev", chardev);
|
135 | 4040ab72 | David Gibson | qdev_init_nofail(dev); |
136 | 4040ab72 | David Gibson | } |
137 | 4040ab72 | David Gibson | |
138 | 3954d33a | Anthony Liguori | static Property spapr_vty_properties[] = {
|
139 | 3954d33a | Anthony Liguori | DEFINE_SPAPR_PROPERTIES(VIOsPAPRVTYDevice, sdev, SPAPR_VTY_BASE_ADDRESS, 0),
|
140 | 3954d33a | Anthony Liguori | DEFINE_PROP_CHR("chardev", VIOsPAPRVTYDevice, chardev),
|
141 | 3954d33a | Anthony Liguori | DEFINE_PROP_END_OF_LIST(), |
142 | 3954d33a | Anthony Liguori | }; |
143 | 3954d33a | Anthony Liguori | |
144 | 3954d33a | Anthony Liguori | static void spapr_vty_class_init(ObjectClass *klass, void *data) |
145 | 3954d33a | Anthony Liguori | { |
146 | 39bffca2 | Anthony Liguori | DeviceClass *dc = DEVICE_CLASS(klass); |
147 | 3954d33a | Anthony Liguori | VIOsPAPRDeviceClass *k = VIO_SPAPR_DEVICE_CLASS(klass); |
148 | 3954d33a | Anthony Liguori | |
149 | 3954d33a | Anthony Liguori | k->init = spapr_vty_init; |
150 | 3954d33a | Anthony Liguori | k->dt_name = "vty";
|
151 | 3954d33a | Anthony Liguori | k->dt_type = "serial";
|
152 | 3954d33a | Anthony Liguori | k->dt_compatible = "hvterm1";
|
153 | 39bffca2 | Anthony Liguori | dc->props = spapr_vty_properties; |
154 | 3954d33a | Anthony Liguori | } |
155 | 3954d33a | Anthony Liguori | |
156 | 39bffca2 | Anthony Liguori | static TypeInfo spapr_vty_info = {
|
157 | 39bffca2 | Anthony Liguori | .name = "spapr-vty",
|
158 | 39bffca2 | Anthony Liguori | .parent = TYPE_VIO_SPAPR_DEVICE, |
159 | 39bffca2 | Anthony Liguori | .instance_size = sizeof(VIOsPAPRVTYDevice),
|
160 | 39bffca2 | Anthony Liguori | .class_init = spapr_vty_class_init, |
161 | 4040ab72 | David Gibson | }; |
162 | 4040ab72 | David Gibson | |
163 | 68f3a94c | David Gibson | VIOsPAPRDevice *spapr_vty_get_default(VIOsPAPRBus *bus) |
164 | 98331f8a | David Gibson | { |
165 | 98331f8a | David Gibson | VIOsPAPRDevice *sdev, *selected; |
166 | 98331f8a | David Gibson | DeviceState *iter; |
167 | 98331f8a | David Gibson | |
168 | 98331f8a | David Gibson | /*
|
169 | 98331f8a | David Gibson | * To avoid the console bouncing around we want one VTY to be
|
170 | 98331f8a | David Gibson | * the "default". We haven't really got anything to go on, so
|
171 | 98331f8a | David Gibson | * arbitrarily choose the one with the lowest reg value.
|
172 | 98331f8a | David Gibson | */
|
173 | 98331f8a | David Gibson | |
174 | 98331f8a | David Gibson | selected = NULL;
|
175 | 98331f8a | David Gibson | QTAILQ_FOREACH(iter, &bus->bus.children, sibling) { |
176 | 98331f8a | David Gibson | /* Only look at VTY devices */
|
177 | 3954d33a | Anthony Liguori | if (!object_dynamic_cast(OBJECT(iter), "spapr-vty")) { |
178 | 98331f8a | David Gibson | continue;
|
179 | 98331f8a | David Gibson | } |
180 | 98331f8a | David Gibson | |
181 | 98331f8a | David Gibson | sdev = DO_UPCAST(VIOsPAPRDevice, qdev, iter); |
182 | 98331f8a | David Gibson | |
183 | 98331f8a | David Gibson | /* First VTY we've found, so it is selected for now */
|
184 | 98331f8a | David Gibson | if (!selected) {
|
185 | 98331f8a | David Gibson | selected = sdev; |
186 | 98331f8a | David Gibson | continue;
|
187 | 98331f8a | David Gibson | } |
188 | 98331f8a | David Gibson | |
189 | 98331f8a | David Gibson | /* Choose VTY with lowest reg value */
|
190 | 98331f8a | David Gibson | if (sdev->reg < selected->reg) {
|
191 | 98331f8a | David Gibson | selected = sdev; |
192 | 98331f8a | David Gibson | } |
193 | 98331f8a | David Gibson | } |
194 | 98331f8a | David Gibson | |
195 | 98331f8a | David Gibson | return selected;
|
196 | 98331f8a | David Gibson | } |
197 | 98331f8a | David Gibson | |
198 | 3feef8ad | David Gibson | static VIOsPAPRDevice *vty_lookup(sPAPREnvironment *spapr, target_ulong reg)
|
199 | 3feef8ad | David Gibson | { |
200 | 3feef8ad | David Gibson | VIOsPAPRDevice *sdev; |
201 | 3feef8ad | David Gibson | |
202 | 3feef8ad | David Gibson | sdev = spapr_vio_find_by_reg(spapr->vio_bus, reg); |
203 | 3feef8ad | David Gibson | if (!sdev && reg == 0) { |
204 | 3feef8ad | David Gibson | /* Hack for kernel early debug, which always specifies reg==0.
|
205 | 98331f8a | David Gibson | * We search all VIO devices, and grab the vty with the lowest
|
206 | 98331f8a | David Gibson | * reg. This attempts to mimic existing PowerVM behaviour
|
207 | 3feef8ad | David Gibson | * (early debug does work there, despite having no vty with
|
208 | 3feef8ad | David Gibson | * reg==0. */
|
209 | 98331f8a | David Gibson | return spapr_vty_get_default(spapr->vio_bus);
|
210 | 3feef8ad | David Gibson | } |
211 | 3feef8ad | David Gibson | |
212 | 3feef8ad | David Gibson | return sdev;
|
213 | 3feef8ad | David Gibson | } |
214 | 3feef8ad | David Gibson | |
215 | 4040ab72 | David Gibson | static void spapr_vty_register(void) |
216 | 4040ab72 | David Gibson | { |
217 | 1fc02533 | David Gibson | spapr_register_hypercall(H_PUT_TERM_CHAR, h_put_term_char); |
218 | 1fc02533 | David Gibson | spapr_register_hypercall(H_GET_TERM_CHAR, h_get_term_char); |
219 | 39bffca2 | Anthony Liguori | type_register_static(&spapr_vty_info); |
220 | 4040ab72 | David Gibson | } |
221 | 4040ab72 | David Gibson | device_init(spapr_vty_register); |