debuggers.hg

view extras/mini-os/console/xencons_ring.c @ 19811:11d8ca329b54

minios: support secondary guest consoles.

Signed-off-by: Stefano Stabellini <stefano.stabellini@eu.citrix.com>
author Keir Fraser <keir.fraser@citrix.com>
date Wed Jun 17 07:22:18 2009 +0100 (2009-06-17)
parents 5c38568d90df
children bc9f7c6ac695
line source
1 #include <types.h>
2 #include <wait.h>
3 #include <mm.h>
4 #include <hypervisor.h>
5 #include <events.h>
6 #include <os.h>
7 #include <lib.h>
8 #include <xenbus.h>
9 #include <xen/io/console.h>
10 #include <xen/io/protocols.h>
11 #include <xen/io/ring.h>
12 #include <xmalloc.h>
13 #include <gnttab.h>
15 DECLARE_WAIT_QUEUE_HEAD(console_queue);
17 static inline void notify_daemon(struct consfront_dev *dev)
18 {
19 /* Use evtchn: this is called early, before irq is set up. */
20 if (!dev)
21 notify_remote_via_evtchn(start_info.console.domU.evtchn);
22 else
23 notify_remote_via_evtchn(dev->evtchn);
24 }
26 static inline struct xencons_interface *xencons_interface(void)
27 {
28 return mfn_to_virt(start_info.console.domU.mfn);
29 }
31 int xencons_ring_send_no_notify(struct consfront_dev *dev, const char *data, unsigned len)
32 {
33 int sent = 0;
34 struct xencons_interface *intf;
35 XENCONS_RING_IDX cons, prod;
37 if (!dev)
38 intf = xencons_interface();
39 else
40 intf = dev->ring;
42 cons = intf->out_cons;
43 prod = intf->out_prod;
44 mb();
45 BUG_ON((prod - cons) > sizeof(intf->out));
47 while ((sent < len) && ((prod - cons) < sizeof(intf->out)))
48 intf->out[MASK_XENCONS_IDX(prod++, intf->out)] = data[sent++];
50 wmb();
51 intf->out_prod = prod;
53 return sent;
54 }
56 int xencons_ring_send(struct consfront_dev *dev, const char *data, unsigned len)
57 {
58 int sent;
60 sent = xencons_ring_send_no_notify(dev, data, len);
61 notify_daemon(dev);
63 return sent;
64 }
68 static void handle_input(evtchn_port_t port, struct pt_regs *regs, void *data)
69 {
70 #ifdef HAVE_LIBC
71 struct consfront_dev *dev = (struct consfront_dev *) data;
72 int fd = dev ? dev->fd : -1;
74 if (fd != -1)
75 files[fd].read = 1;
77 wake_up(&console_queue);
78 #else
79 struct xencons_interface *intf = xencons_interface();
80 XENCONS_RING_IDX cons, prod;
82 cons = intf->in_cons;
83 prod = intf->in_prod;
84 mb();
85 BUG_ON((prod - cons) > sizeof(intf->in));
87 while (cons != prod) {
88 xencons_rx(intf->in+MASK_XENCONS_IDX(cons,intf->in), 1, regs);
89 cons++;
90 }
92 mb();
93 intf->in_cons = cons;
95 notify_daemon(dev);
97 xencons_tx();
98 #endif
99 }
101 #ifdef HAVE_LIBC
102 int xencons_ring_avail(struct consfront_dev *dev)
103 {
104 struct xencons_interface *intf;
105 XENCONS_RING_IDX cons, prod;
107 if (!dev)
108 intf = xencons_interface();
109 else
110 intf = dev->ring;
112 cons = intf->in_cons;
113 prod = intf->in_prod;
114 mb();
115 BUG_ON((prod - cons) > sizeof(intf->in));
117 return prod - cons;
118 }
120 int xencons_ring_recv(struct consfront_dev *dev, char *data, unsigned len)
121 {
122 struct xencons_interface *intf;
123 XENCONS_RING_IDX cons, prod;
124 unsigned filled = 0;
126 if (!dev)
127 intf = xencons_interface();
128 else
129 intf = dev->ring;
131 cons = intf->in_cons;
132 prod = intf->in_prod;
133 mb();
134 BUG_ON((prod - cons) > sizeof(intf->in));
136 while (filled < len && cons + filled != prod) {
137 data[filled] = *(intf->in + MASK_XENCONS_IDX(cons + filled, intf->in));
138 filled++;
139 }
141 mb();
142 intf->in_cons = cons + filled;
144 notify_daemon(dev);
146 return filled;
147 }
148 #endif
150 struct consfront_dev *xencons_ring_init(void)
151 {
152 int err;
153 struct consfront_dev *dev;
155 if (!start_info.console.domU.evtchn)
156 return 0;
158 dev = malloc(sizeof(struct consfront_dev));
159 memset(dev, 0, sizeof(struct consfront_dev));
160 dev->nodename = "device/console";
161 dev->dom = 0;
162 dev->backend = 0;
163 dev->ring_ref = 0;
165 #ifdef HAVE_LIBC
166 dev->fd = -1;
167 #endif
168 dev->evtchn = start_info.console.domU.evtchn;
169 dev->ring = (struct xencons_interface *) mfn_to_virt(start_info.console.domU.mfn);
171 err = bind_evtchn(dev->evtchn, handle_input, dev);
172 if (err <= 0) {
173 printk("XEN console request chn bind failed %i\n", err);
174 free(dev);
175 return NULL;
176 }
177 unmask_evtchn(dev->evtchn);
179 /* In case we have in-flight data after save/restore... */
180 notify_daemon(dev);
182 return dev;
183 }
185 void free_consfront(struct consfront_dev *dev)
186 {
187 mask_evtchn(dev->evtchn);
189 free(dev->backend);
191 gnttab_end_access(dev->ring_ref);
192 free_page(dev->ring);
194 unbind_evtchn(dev->evtchn);
196 free(dev->nodename);
197 free(dev);
198 }
200 struct consfront_dev *init_consfront(char *_nodename)
201 {
202 xenbus_transaction_t xbt;
203 char* err;
204 char* message=NULL;
205 int retry=0;
206 char* msg;
207 char nodename[256];
208 char path[256];
209 static int consfrontends = 1;
210 struct consfront_dev *dev;
211 int res;
213 if (!_nodename)
214 snprintf(nodename, sizeof(nodename), "device/console/%d", consfrontends);
215 else
216 strncpy(nodename, _nodename, sizeof(nodename));
218 printk("******************* CONSFRONT for %s **********\n\n\n", nodename);
220 consfrontends++;
221 dev = malloc(sizeof(*dev));
222 memset(dev, 0, sizeof(*dev));
223 dev->nodename = strdup(nodename);
224 #ifdef HAVE_LIBC
225 dev->fd = -1;
226 #endif
228 snprintf(path, sizeof(path), "%s/backend-id", nodename);
229 if ((res = xenbus_read_integer(path)) < 0)
230 return NULL;
231 else
232 dev->dom = res;
233 evtchn_alloc_unbound(dev->dom, handle_input, dev, &dev->evtchn);
235 dev->ring = (struct xencons_interface *) alloc_page();
236 memset(dev->ring, 0, PAGE_SIZE);
237 dev->ring_ref = gnttab_grant_access(dev->dom, virt_to_mfn(dev->ring), 0);
239 dev->events = NULL;
241 again:
242 err = xenbus_transaction_start(&xbt);
243 if (err) {
244 printk("starting transaction\n");
245 }
247 err = xenbus_printf(xbt, nodename, "ring-ref","%u",
248 dev->ring_ref);
249 if (err) {
250 message = "writing ring-ref";
251 goto abort_transaction;
252 }
253 err = xenbus_printf(xbt, nodename,
254 "port", "%u", dev->evtchn);
255 if (err) {
256 message = "writing event-channel";
257 goto abort_transaction;
258 }
259 err = xenbus_printf(xbt, nodename,
260 "protocol", "%s", XEN_IO_PROTO_ABI_NATIVE);
261 if (err) {
262 message = "writing protocol";
263 goto abort_transaction;
264 }
266 err = xenbus_printf(xbt, nodename, "type", "%s", "ioemu");
267 if (err) {
268 message = "writing type";
269 goto abort_transaction;
270 }
272 snprintf(path, sizeof(path), "%s/state", nodename);
273 err = xenbus_switch_state(xbt, path, XenbusStateConnected);
274 if (err) {
275 message = "switching state";
276 goto abort_transaction;
277 }
280 err = xenbus_transaction_end(xbt, 0, &retry);
281 if (retry) {
282 goto again;
283 printk("completing transaction\n");
284 }
286 goto done;
288 abort_transaction:
289 xenbus_transaction_end(xbt, 1, &retry);
290 goto error;
292 done:
294 snprintf(path, sizeof(path), "%s/backend", nodename);
295 msg = xenbus_read(XBT_NIL, path, &dev->backend);
296 if (msg) {
297 printk("Error %s when reading the backend path %s\n", msg, path);
298 goto error;
299 }
301 printk("backend at %s\n", dev->backend);
303 {
304 XenbusState state;
305 char path[strlen(dev->backend) + 1 + 19 + 1];
306 snprintf(path, sizeof(path), "%s/state", dev->backend);
308 xenbus_watch_path_token(XBT_NIL, path, path, &dev->events);
309 msg = NULL;
310 state = xenbus_read_integer(path);
311 while (msg == NULL && state < XenbusStateConnected)
312 msg = xenbus_wait_for_state_change(path, &state, &dev->events);
313 if (msg != NULL || state != XenbusStateConnected) {
314 printk("backend not available, state=%d\n", state);
315 xenbus_unwatch_path(XBT_NIL, path);
316 goto error;
317 }
318 }
319 unmask_evtchn(dev->evtchn);
321 printk("**************************\n");
323 return dev;
325 error:
326 free_consfront(dev);
327 return NULL;
328 }
330 void xencons_resume(void)
331 {
332 (void)xencons_ring_init();
333 }