root / hw / spapr_vty.c @ ad2d30f7
History | View | Annotate | Download (4.1 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 | 4040ab72 | David Gibson | /* FIXME: should check the qemu_chr_write() return value */
|
54 | 4040ab72 | David Gibson | qemu_chr_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 | 4040ab72 | David Gibson | qemu_chr_add_handlers(dev->chardev, vty_can_receive, |
62 | 4040ab72 | David Gibson | vty_receive, NULL, dev);
|
63 | 4040ab72 | David Gibson | |
64 | 4040ab72 | David Gibson | return 0; |
65 | 4040ab72 | David Gibson | } |
66 | 4040ab72 | David Gibson | |
67 | 4040ab72 | David Gibson | static target_ulong h_put_term_char(CPUState *env, sPAPREnvironment *spapr,
|
68 | 4040ab72 | David Gibson | target_ulong opcode, target_ulong *args) |
69 | 4040ab72 | David Gibson | { |
70 | 4040ab72 | David Gibson | target_ulong reg = args[0];
|
71 | 4040ab72 | David Gibson | target_ulong len = args[1];
|
72 | 4040ab72 | David Gibson | target_ulong char0_7 = args[2];
|
73 | 4040ab72 | David Gibson | target_ulong char8_15 = args[3];
|
74 | 4040ab72 | David Gibson | VIOsPAPRDevice *sdev = spapr_vio_find_by_reg(spapr->vio_bus, reg); |
75 | 4040ab72 | David Gibson | uint8_t buf[16];
|
76 | 4040ab72 | David Gibson | |
77 | 4040ab72 | David Gibson | if (!sdev) {
|
78 | 4040ab72 | David Gibson | return H_PARAMETER;
|
79 | 4040ab72 | David Gibson | } |
80 | 4040ab72 | David Gibson | |
81 | 4040ab72 | David Gibson | if (len > 16) { |
82 | 4040ab72 | David Gibson | return H_PARAMETER;
|
83 | 4040ab72 | David Gibson | } |
84 | 4040ab72 | David Gibson | |
85 | 4040ab72 | David Gibson | *((uint64_t *)buf) = cpu_to_be64(char0_7); |
86 | 4040ab72 | David Gibson | *((uint64_t *)buf + 1) = cpu_to_be64(char8_15);
|
87 | 4040ab72 | David Gibson | |
88 | 4040ab72 | David Gibson | vty_putchars(sdev, buf, len); |
89 | 4040ab72 | David Gibson | |
90 | 4040ab72 | David Gibson | return H_SUCCESS;
|
91 | 4040ab72 | David Gibson | } |
92 | 4040ab72 | David Gibson | |
93 | 4040ab72 | David Gibson | static target_ulong h_get_term_char(CPUState *env, sPAPREnvironment *spapr,
|
94 | 4040ab72 | David Gibson | target_ulong opcode, target_ulong *args) |
95 | 4040ab72 | David Gibson | { |
96 | 4040ab72 | David Gibson | target_ulong reg = args[0];
|
97 | 4040ab72 | David Gibson | target_ulong *len = args + 0;
|
98 | 4040ab72 | David Gibson | target_ulong *char0_7 = args + 1;
|
99 | 4040ab72 | David Gibson | target_ulong *char8_15 = args + 2;
|
100 | 4040ab72 | David Gibson | VIOsPAPRDevice *sdev = spapr_vio_find_by_reg(spapr->vio_bus, reg); |
101 | 4040ab72 | David Gibson | uint8_t buf[16];
|
102 | 4040ab72 | David Gibson | |
103 | 4040ab72 | David Gibson | if (!sdev) {
|
104 | 4040ab72 | David Gibson | return H_PARAMETER;
|
105 | 4040ab72 | David Gibson | } |
106 | 4040ab72 | David Gibson | |
107 | 4040ab72 | David Gibson | *len = vty_getchars(sdev, buf, sizeof(buf));
|
108 | 4040ab72 | David Gibson | if (*len < 16) { |
109 | 4040ab72 | David Gibson | memset(buf + *len, 0, 16 - *len); |
110 | 4040ab72 | David Gibson | } |
111 | 4040ab72 | David Gibson | |
112 | 4040ab72 | David Gibson | *char0_7 = be64_to_cpu(*((uint64_t *)buf)); |
113 | 4040ab72 | David Gibson | *char8_15 = be64_to_cpu(*((uint64_t *)buf + 1));
|
114 | 4040ab72 | David Gibson | |
115 | 4040ab72 | David Gibson | return H_SUCCESS;
|
116 | 4040ab72 | David Gibson | } |
117 | 4040ab72 | David Gibson | |
118 | 4040ab72 | David Gibson | void spapr_vty_create(VIOsPAPRBus *bus,
|
119 | 0201e2da | David Gibson | uint32_t reg, CharDriverState *chardev, |
120 | 0201e2da | David Gibson | qemu_irq qirq, uint32_t vio_irq_num) |
121 | 4040ab72 | David Gibson | { |
122 | 4040ab72 | David Gibson | DeviceState *dev; |
123 | 0201e2da | David Gibson | VIOsPAPRDevice *sdev; |
124 | 4040ab72 | David Gibson | |
125 | 4040ab72 | David Gibson | dev = qdev_create(&bus->bus, "spapr-vty");
|
126 | 4040ab72 | David Gibson | qdev_prop_set_uint32(dev, "reg", reg);
|
127 | 4040ab72 | David Gibson | qdev_prop_set_chr(dev, "chardev", chardev);
|
128 | 4040ab72 | David Gibson | qdev_init_nofail(dev); |
129 | 0201e2da | David Gibson | sdev = (VIOsPAPRDevice *)dev; |
130 | 0201e2da | David Gibson | sdev->qirq = qirq; |
131 | 0201e2da | David Gibson | sdev->vio_irq_num = vio_irq_num; |
132 | 4040ab72 | David Gibson | } |
133 | 4040ab72 | David Gibson | |
134 | 4040ab72 | David Gibson | static void vty_hcalls(VIOsPAPRBus *bus) |
135 | 4040ab72 | David Gibson | { |
136 | 4040ab72 | David Gibson | spapr_register_hypercall(H_PUT_TERM_CHAR, h_put_term_char); |
137 | 4040ab72 | David Gibson | spapr_register_hypercall(H_GET_TERM_CHAR, h_get_term_char); |
138 | 4040ab72 | David Gibson | } |
139 | 4040ab72 | David Gibson | |
140 | 4040ab72 | David Gibson | static VIOsPAPRDeviceInfo spapr_vty = {
|
141 | 4040ab72 | David Gibson | .init = spapr_vty_init, |
142 | 4040ab72 | David Gibson | .dt_name = "vty",
|
143 | 4040ab72 | David Gibson | .dt_type = "serial",
|
144 | 4040ab72 | David Gibson | .dt_compatible = "hvterm1",
|
145 | 4040ab72 | David Gibson | .hcalls = vty_hcalls, |
146 | 4040ab72 | David Gibson | .qdev.name = "spapr-vty",
|
147 | 4040ab72 | David Gibson | .qdev.size = sizeof(VIOsPAPRVTYDevice),
|
148 | 4040ab72 | David Gibson | .qdev.props = (Property[]) { |
149 | 4040ab72 | David Gibson | DEFINE_PROP_UINT32("reg", VIOsPAPRDevice, reg, 0), |
150 | 4040ab72 | David Gibson | DEFINE_PROP_CHR("chardev", VIOsPAPRVTYDevice, chardev),
|
151 | 4040ab72 | David Gibson | DEFINE_PROP_END_OF_LIST(), |
152 | 4040ab72 | David Gibson | }, |
153 | 4040ab72 | David Gibson | }; |
154 | 4040ab72 | David Gibson | |
155 | 4040ab72 | David Gibson | static void spapr_vty_register(void) |
156 | 4040ab72 | David Gibson | { |
157 | 4040ab72 | David Gibson | spapr_vio_bus_register_withprop(&spapr_vty); |
158 | 4040ab72 | David Gibson | } |
159 | 4040ab72 | David Gibson | device_init(spapr_vty_register); |