root / hw / spapr_vty.c @ 03a6b667
History | View | Annotate | Download (5.7 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 | a307d594 | Alexey Kardashevskiy | qemu_irq_pulse(spapr_vio_qirq(&dev->sdev)); |
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 | e2684c0b | Andreas Färber | static target_ulong h_put_term_char(CPUPPCState *env, sPAPREnvironment *spapr,
|
74 | 4040ab72 | David Gibson | target_ulong opcode, target_ulong *args) |
75 | 4040ab72 | David Gibson | { |
76 | 4040ab72 | David Gibson | target_ulong reg = args[0];
|
77 | 4040ab72 | David Gibson | target_ulong len = args[1];
|
78 | 4040ab72 | David Gibson | target_ulong char0_7 = args[2];
|
79 | 4040ab72 | David Gibson | target_ulong char8_15 = args[3];
|
80 | 3feef8ad | David Gibson | VIOsPAPRDevice *sdev; |
81 | 4040ab72 | David Gibson | uint8_t buf[16];
|
82 | 4040ab72 | David Gibson | |
83 | 3feef8ad | David Gibson | sdev = vty_lookup(spapr, reg); |
84 | 4040ab72 | David Gibson | if (!sdev) {
|
85 | 4040ab72 | David Gibson | return H_PARAMETER;
|
86 | 4040ab72 | David Gibson | } |
87 | 4040ab72 | David Gibson | |
88 | 4040ab72 | David Gibson | if (len > 16) { |
89 | 4040ab72 | David Gibson | return H_PARAMETER;
|
90 | 4040ab72 | David Gibson | } |
91 | 4040ab72 | David Gibson | |
92 | 4040ab72 | David Gibson | *((uint64_t *)buf) = cpu_to_be64(char0_7); |
93 | 4040ab72 | David Gibson | *((uint64_t *)buf + 1) = cpu_to_be64(char8_15);
|
94 | 4040ab72 | David Gibson | |
95 | 4040ab72 | David Gibson | vty_putchars(sdev, buf, len); |
96 | 4040ab72 | David Gibson | |
97 | 4040ab72 | David Gibson | return H_SUCCESS;
|
98 | 4040ab72 | David Gibson | } |
99 | 4040ab72 | David Gibson | |
100 | e2684c0b | Andreas Färber | static target_ulong h_get_term_char(CPUPPCState *env, sPAPREnvironment *spapr,
|
101 | 4040ab72 | David Gibson | target_ulong opcode, target_ulong *args) |
102 | 4040ab72 | David Gibson | { |
103 | 4040ab72 | David Gibson | target_ulong reg = args[0];
|
104 | 4040ab72 | David Gibson | target_ulong *len = args + 0;
|
105 | 4040ab72 | David Gibson | target_ulong *char0_7 = args + 1;
|
106 | 4040ab72 | David Gibson | target_ulong *char8_15 = args + 2;
|
107 | 3feef8ad | David Gibson | VIOsPAPRDevice *sdev; |
108 | 4040ab72 | David Gibson | uint8_t buf[16];
|
109 | 4040ab72 | David Gibson | |
110 | 3feef8ad | David Gibson | sdev = vty_lookup(spapr, reg); |
111 | 4040ab72 | David Gibson | if (!sdev) {
|
112 | 4040ab72 | David Gibson | return H_PARAMETER;
|
113 | 4040ab72 | David Gibson | } |
114 | 4040ab72 | David Gibson | |
115 | 4040ab72 | David Gibson | *len = vty_getchars(sdev, buf, sizeof(buf));
|
116 | 4040ab72 | David Gibson | if (*len < 16) { |
117 | 4040ab72 | David Gibson | memset(buf + *len, 0, 16 - *len); |
118 | 4040ab72 | David Gibson | } |
119 | 4040ab72 | David Gibson | |
120 | 4040ab72 | David Gibson | *char0_7 = be64_to_cpu(*((uint64_t *)buf)); |
121 | 4040ab72 | David Gibson | *char8_15 = be64_to_cpu(*((uint64_t *)buf + 1));
|
122 | 4040ab72 | David Gibson | |
123 | 4040ab72 | David Gibson | return H_SUCCESS;
|
124 | 4040ab72 | David Gibson | } |
125 | 4040ab72 | David Gibson | |
126 | d601fac4 | David Gibson | void spapr_vty_create(VIOsPAPRBus *bus, CharDriverState *chardev)
|
127 | 4040ab72 | David Gibson | { |
128 | 4040ab72 | David Gibson | DeviceState *dev; |
129 | 4040ab72 | David Gibson | |
130 | 4040ab72 | David Gibson | dev = qdev_create(&bus->bus, "spapr-vty");
|
131 | 4040ab72 | David Gibson | qdev_prop_set_chr(dev, "chardev", chardev);
|
132 | 4040ab72 | David Gibson | qdev_init_nofail(dev); |
133 | 4040ab72 | David Gibson | } |
134 | 4040ab72 | David Gibson | |
135 | 3954d33a | Anthony Liguori | static Property spapr_vty_properties[] = {
|
136 | ad0ebb91 | David Gibson | DEFINE_SPAPR_PROPERTIES(VIOsPAPRVTYDevice, sdev), |
137 | 3954d33a | Anthony Liguori | DEFINE_PROP_CHR("chardev", VIOsPAPRVTYDevice, chardev),
|
138 | 3954d33a | Anthony Liguori | DEFINE_PROP_END_OF_LIST(), |
139 | 3954d33a | Anthony Liguori | }; |
140 | 3954d33a | Anthony Liguori | |
141 | 3954d33a | Anthony Liguori | static void spapr_vty_class_init(ObjectClass *klass, void *data) |
142 | 3954d33a | Anthony Liguori | { |
143 | 39bffca2 | Anthony Liguori | DeviceClass *dc = DEVICE_CLASS(klass); |
144 | 3954d33a | Anthony Liguori | VIOsPAPRDeviceClass *k = VIO_SPAPR_DEVICE_CLASS(klass); |
145 | 3954d33a | Anthony Liguori | |
146 | 3954d33a | Anthony Liguori | k->init = spapr_vty_init; |
147 | 3954d33a | Anthony Liguori | k->dt_name = "vty";
|
148 | 3954d33a | Anthony Liguori | k->dt_type = "serial";
|
149 | 3954d33a | Anthony Liguori | k->dt_compatible = "hvterm1";
|
150 | 39bffca2 | Anthony Liguori | dc->props = spapr_vty_properties; |
151 | 3954d33a | Anthony Liguori | } |
152 | 3954d33a | Anthony Liguori | |
153 | 39bffca2 | Anthony Liguori | static TypeInfo spapr_vty_info = {
|
154 | 39bffca2 | Anthony Liguori | .name = "spapr-vty",
|
155 | 39bffca2 | Anthony Liguori | .parent = TYPE_VIO_SPAPR_DEVICE, |
156 | 39bffca2 | Anthony Liguori | .instance_size = sizeof(VIOsPAPRVTYDevice),
|
157 | 39bffca2 | Anthony Liguori | .class_init = spapr_vty_class_init, |
158 | 4040ab72 | David Gibson | }; |
159 | 4040ab72 | David Gibson | |
160 | 68f3a94c | David Gibson | VIOsPAPRDevice *spapr_vty_get_default(VIOsPAPRBus *bus) |
161 | 98331f8a | David Gibson | { |
162 | 98331f8a | David Gibson | VIOsPAPRDevice *sdev, *selected; |
163 | 0866aca1 | Anthony Liguori | BusChild *kid; |
164 | 98331f8a | David Gibson | |
165 | 98331f8a | David Gibson | /*
|
166 | 98331f8a | David Gibson | * To avoid the console bouncing around we want one VTY to be
|
167 | 98331f8a | David Gibson | * the "default". We haven't really got anything to go on, so
|
168 | 98331f8a | David Gibson | * arbitrarily choose the one with the lowest reg value.
|
169 | 98331f8a | David Gibson | */
|
170 | 98331f8a | David Gibson | |
171 | 98331f8a | David Gibson | selected = NULL;
|
172 | 0866aca1 | Anthony Liguori | QTAILQ_FOREACH(kid, &bus->bus.children, sibling) { |
173 | 0866aca1 | Anthony Liguori | DeviceState *iter = kid->child; |
174 | 0866aca1 | Anthony Liguori | |
175 | 98331f8a | David Gibson | /* Only look at VTY devices */
|
176 | 3954d33a | Anthony Liguori | if (!object_dynamic_cast(OBJECT(iter), "spapr-vty")) { |
177 | 98331f8a | David Gibson | continue;
|
178 | 98331f8a | David Gibson | } |
179 | 98331f8a | David Gibson | |
180 | 98331f8a | David Gibson | sdev = DO_UPCAST(VIOsPAPRDevice, qdev, iter); |
181 | 98331f8a | David Gibson | |
182 | 98331f8a | David Gibson | /* First VTY we've found, so it is selected for now */
|
183 | 98331f8a | David Gibson | if (!selected) {
|
184 | 98331f8a | David Gibson | selected = sdev; |
185 | 98331f8a | David Gibson | continue;
|
186 | 98331f8a | David Gibson | } |
187 | 98331f8a | David Gibson | |
188 | 98331f8a | David Gibson | /* Choose VTY with lowest reg value */
|
189 | 98331f8a | David Gibson | if (sdev->reg < selected->reg) {
|
190 | 98331f8a | David Gibson | selected = sdev; |
191 | 98331f8a | David Gibson | } |
192 | 98331f8a | David Gibson | } |
193 | 98331f8a | David Gibson | |
194 | 98331f8a | David Gibson | return selected;
|
195 | 98331f8a | David Gibson | } |
196 | 98331f8a | David Gibson | |
197 | 5f2e2ba2 | David Gibson | VIOsPAPRDevice *vty_lookup(sPAPREnvironment *spapr, target_ulong reg) |
198 | 3feef8ad | David Gibson | { |
199 | 3feef8ad | David Gibson | VIOsPAPRDevice *sdev; |
200 | 3feef8ad | David Gibson | |
201 | 3feef8ad | David Gibson | sdev = spapr_vio_find_by_reg(spapr->vio_bus, reg); |
202 | 3feef8ad | David Gibson | if (!sdev && reg == 0) { |
203 | 3feef8ad | David Gibson | /* Hack for kernel early debug, which always specifies reg==0.
|
204 | 98331f8a | David Gibson | * We search all VIO devices, and grab the vty with the lowest
|
205 | 98331f8a | David Gibson | * reg. This attempts to mimic existing PowerVM behaviour
|
206 | 3feef8ad | David Gibson | * (early debug does work there, despite having no vty with
|
207 | 3feef8ad | David Gibson | * reg==0. */
|
208 | 98331f8a | David Gibson | return spapr_vty_get_default(spapr->vio_bus);
|
209 | 3feef8ad | David Gibson | } |
210 | 3feef8ad | David Gibson | |
211 | 3feef8ad | David Gibson | return sdev;
|
212 | 3feef8ad | David Gibson | } |
213 | 3feef8ad | David Gibson | |
214 | 83f7d43a | Andreas Färber | static void spapr_vty_register_types(void) |
215 | 4040ab72 | David Gibson | { |
216 | 1fc02533 | David Gibson | spapr_register_hypercall(H_PUT_TERM_CHAR, h_put_term_char); |
217 | 1fc02533 | David Gibson | spapr_register_hypercall(H_GET_TERM_CHAR, h_get_term_char); |
218 | 39bffca2 | Anthony Liguori | type_register_static(&spapr_vty_info); |
219 | 4040ab72 | David Gibson | } |
220 | 83f7d43a | Andreas Färber | |
221 | 83f7d43a | Andreas Färber | type_init(spapr_vty_register_types) |