aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/tty
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2012-03-22 22:59:19 -0400
committerLinus Torvalds <torvalds@linux-foundation.org>2012-03-22 23:16:14 -0400
commitd4c6fa73fe984e504d52f3d6bba291fd76fe49f7 (patch)
tree47842ddebb2a48cc1513b36fba18835678e2b94e /drivers/tty
parentaab008db8063364dc3c8ccf4981c21124866b395 (diff)
parent4bc25af79ec54b79266148f8c1b84bb1e7ff2621 (diff)
Merge tag 'stable/for-linus-3.4-tag' of git://git.kernel.org/pub/scm/linux/kernel/git/konrad/xen
Pull xen updates from Konrad Rzeszutek Wilk: "which has three neat features: - PV multiconsole support, so that there can be hvc1, hvc2, etc; This can be used in HVM and in PV mode. - P-state and C-state power management driver that uploads said power management data to the hypervisor. It also inhibits cpufreq scaling drivers to load so that only the hypervisor can make power management decisions - fixing a weird perf bug. There is one thing in the Kconfig that you won't like: "default y if (X86_ACPI_CPUFREQ = y || X86_POWERNOW_K8 = y)" (note, that it all depends on CONFIG_XEN which depends on CONFIG_PARAVIRT which by default is off). I've a fix to convert that boolean expression into "default m" which I am going to post after the cpufreq git pull - as the two patches to make this work depend on a fix in Dave Jones's tree. - Function Level Reset (FLR) support in the Xen PCI backend. Fixes: - Kconfig dependencies for Xen PV keyboard and video - Compile warnings and constify fixes - Change over to use percpu_xxx instead of this_cpu_xxx" Fix up trivial conflicts in drivers/tty/hvc/hvc_xen.c due to changes to a removed commit. * tag 'stable/for-linus-3.4-tag' of git://git.kernel.org/pub/scm/linux/kernel/git/konrad/xen: xen kconfig: relax INPUT_XEN_KBDDEV_FRONTEND deps xen/acpi-processor: C and P-state driver that uploads said data to hypervisor. xen: constify all instances of "struct attribute_group" xen/xenbus: ignore console/0 hvc_xen: introduce HVC_XEN_FRONTEND hvc_xen: implement multiconsole support hvc_xen: support PV on HVM consoles xenbus: don't free other end details too early xen/enlighten: Expose MWAIT and MWAIT_LEAF if hypervisor OKs it. xen/setup/pm/acpi: Remove the call to boot_option_idle_override. xenbus: address compiler warnings xen: use this_cpu_xxx replace percpu_xxx funcs xen/pciback: Support pci_reset_function, aka FLR or D3 support. pci: Introduce __pci_reset_function_locked to be used when holding device_lock. xen: Utilize the restore_msi_irqs hook.
Diffstat (limited to 'drivers/tty')
-rw-r--r--drivers/tty/hvc/Kconfig8
-rw-r--r--drivers/tty/hvc/hvc_xen.c465
2 files changed, 430 insertions, 43 deletions
diff --git a/drivers/tty/hvc/Kconfig b/drivers/tty/hvc/Kconfig
index 48cb8d3d1758..0282a83f51fb 100644
--- a/drivers/tty/hvc/Kconfig
+++ b/drivers/tty/hvc/Kconfig
@@ -66,6 +66,14 @@ config HVC_XEN
66 help 66 help
67 Xen virtual console device driver 67 Xen virtual console device driver
68 68
69config HVC_XEN_FRONTEND
70 bool "Xen Hypervisor Multiple Consoles support"
71 depends on HVC_XEN
72 select XEN_XENBUS_FRONTEND
73 default y
74 help
75 Xen driver for secondary virtual consoles
76
69config HVC_UDBG 77config HVC_UDBG
70 bool "udbg based fake hypervisor console" 78 bool "udbg based fake hypervisor console"
71 depends on PPC && EXPERIMENTAL 79 depends on PPC && EXPERIMENTAL
diff --git a/drivers/tty/hvc/hvc_xen.c b/drivers/tty/hvc/hvc_xen.c
index a1b0a75c3eae..83d5c88e7165 100644
--- a/drivers/tty/hvc/hvc_xen.c
+++ b/drivers/tty/hvc/hvc_xen.c
@@ -23,44 +23,74 @@
23#include <linux/err.h> 23#include <linux/err.h>
24#include <linux/init.h> 24#include <linux/init.h>
25#include <linux/types.h> 25#include <linux/types.h>
26#include <linux/list.h>
26 27
28#include <asm/io.h>
27#include <asm/xen/hypervisor.h> 29#include <asm/xen/hypervisor.h>
28 30
29#include <xen/xen.h> 31#include <xen/xen.h>
32#include <xen/interface/xen.h>
33#include <xen/hvm.h>
34#include <xen/grant_table.h>
30#include <xen/page.h> 35#include <xen/page.h>
31#include <xen/events.h> 36#include <xen/events.h>
32#include <xen/interface/io/console.h> 37#include <xen/interface/io/console.h>
33#include <xen/hvc-console.h> 38#include <xen/hvc-console.h>
39#include <xen/xenbus.h>
34 40
35#include "hvc_console.h" 41#include "hvc_console.h"
36 42
37#define HVC_COOKIE 0x58656e /* "Xen" in hex */ 43#define HVC_COOKIE 0x58656e /* "Xen" in hex */
38 44
39static struct hvc_struct *hvc; 45struct xencons_info {
40static int xencons_irq; 46 struct list_head list;
47 struct xenbus_device *xbdev;
48 struct xencons_interface *intf;
49 unsigned int evtchn;
50 struct hvc_struct *hvc;
51 int irq;
52 int vtermno;
53 grant_ref_t gntref;
54};
55
56static LIST_HEAD(xenconsoles);
57static DEFINE_SPINLOCK(xencons_lock);
41 58
42/* ------------------------------------------------------------------ */ 59/* ------------------------------------------------------------------ */
43 60
44static unsigned long console_pfn = ~0ul; 61static struct xencons_info *vtermno_to_xencons(int vtermno)
62{
63 struct xencons_info *entry, *n, *ret = NULL;
64
65 if (list_empty(&xenconsoles))
66 return NULL;
67
68 list_for_each_entry_safe(entry, n, &xenconsoles, list) {
69 if (entry->vtermno == vtermno) {
70 ret = entry;
71 break;
72 }
73 }
74
75 return ret;
76}
45 77
46static inline struct xencons_interface *xencons_interface(void) 78static inline int xenbus_devid_to_vtermno(int devid)
47{ 79{
48 if (console_pfn == ~0ul) 80 return devid + HVC_COOKIE;
49 return mfn_to_virt(xen_start_info->console.domU.mfn);
50 else
51 return __va(console_pfn << PAGE_SHIFT);
52} 81}
53 82
54static inline void notify_daemon(void) 83static inline void notify_daemon(struct xencons_info *cons)
55{ 84{
56 /* Use evtchn: this is called early, before irq is set up. */ 85 /* Use evtchn: this is called early, before irq is set up. */
57 notify_remote_via_evtchn(xen_start_info->console.domU.evtchn); 86 notify_remote_via_evtchn(cons->evtchn);
58} 87}
59 88
60static int __write_console(const char *data, int len) 89static int __write_console(struct xencons_info *xencons,
90 const char *data, int len)
61{ 91{
62 struct xencons_interface *intf = xencons_interface();
63 XENCONS_RING_IDX cons, prod; 92 XENCONS_RING_IDX cons, prod;
93 struct xencons_interface *intf = xencons->intf;
64 int sent = 0; 94 int sent = 0;
65 95
66 cons = intf->out_cons; 96 cons = intf->out_cons;
@@ -75,13 +105,16 @@ static int __write_console(const char *data, int len)
75 intf->out_prod = prod; 105 intf->out_prod = prod;
76 106
77 if (sent) 107 if (sent)
78 notify_daemon(); 108 notify_daemon(xencons);
79 return sent; 109 return sent;
80} 110}
81 111
82static int domU_write_console(uint32_t vtermno, const char *data, int len) 112static int domU_write_console(uint32_t vtermno, const char *data, int len)
83{ 113{
84 int ret = len; 114 int ret = len;
115 struct xencons_info *cons = vtermno_to_xencons(vtermno);
116 if (cons == NULL)
117 return -EINVAL;
85 118
86 /* 119 /*
87 * Make sure the whole buffer is emitted, polling if 120 * Make sure the whole buffer is emitted, polling if
@@ -90,7 +123,7 @@ static int domU_write_console(uint32_t vtermno, const char *data, int len)
90 * kernel is crippled. 123 * kernel is crippled.
91 */ 124 */
92 while (len) { 125 while (len) {
93 int sent = __write_console(data, len); 126 int sent = __write_console(cons, data, len);
94 127
95 data += sent; 128 data += sent;
96 len -= sent; 129 len -= sent;
@@ -104,9 +137,13 @@ static int domU_write_console(uint32_t vtermno, const char *data, int len)
104 137
105static int domU_read_console(uint32_t vtermno, char *buf, int len) 138static int domU_read_console(uint32_t vtermno, char *buf, int len)
106{ 139{
107 struct xencons_interface *intf = xencons_interface(); 140 struct xencons_interface *intf;
108 XENCONS_RING_IDX cons, prod; 141 XENCONS_RING_IDX cons, prod;
109 int recv = 0; 142 int recv = 0;
143 struct xencons_info *xencons = vtermno_to_xencons(vtermno);
144 if (xencons == NULL)
145 return -EINVAL;
146 intf = xencons->intf;
110 147
111 cons = intf->in_cons; 148 cons = intf->in_cons;
112 prod = intf->in_prod; 149 prod = intf->in_prod;
@@ -119,7 +156,7 @@ static int domU_read_console(uint32_t vtermno, char *buf, int len)
119 mb(); /* read ring before consuming */ 156 mb(); /* read ring before consuming */
120 intf->in_cons = cons; 157 intf->in_cons = cons;
121 158
122 notify_daemon(); 159 notify_daemon(xencons);
123 return recv; 160 return recv;
124} 161}
125 162
@@ -157,68 +194,407 @@ static struct hv_ops dom0_hvc_ops = {
157 .notifier_hangup = notifier_hangup_irq, 194 .notifier_hangup = notifier_hangup_irq,
158}; 195};
159 196
160static int __init xen_hvc_init(void) 197static int xen_hvm_console_init(void)
198{
199 int r;
200 uint64_t v = 0;
201 unsigned long mfn;
202 struct xencons_info *info;
203
204 if (!xen_hvm_domain())
205 return -ENODEV;
206
207 info = vtermno_to_xencons(HVC_COOKIE);
208 if (!info) {
209 info = kzalloc(sizeof(struct xencons_info), GFP_KERNEL | __GFP_ZERO);
210 if (!info)
211 return -ENOMEM;
212 }
213
214 /* already configured */
215 if (info->intf != NULL)
216 return 0;
217
218 r = hvm_get_parameter(HVM_PARAM_CONSOLE_EVTCHN, &v);
219 if (r < 0) {
220 kfree(info);
221 return -ENODEV;
222 }
223 info->evtchn = v;
224 hvm_get_parameter(HVM_PARAM_CONSOLE_PFN, &v);
225 if (r < 0) {
226 kfree(info);
227 return -ENODEV;
228 }
229 mfn = v;
230 info->intf = ioremap(mfn << PAGE_SHIFT, PAGE_SIZE);
231 if (info->intf == NULL) {
232 kfree(info);
233 return -ENODEV;
234 }
235 info->vtermno = HVC_COOKIE;
236
237 spin_lock(&xencons_lock);
238 list_add_tail(&info->list, &xenconsoles);
239 spin_unlock(&xencons_lock);
240
241 return 0;
242}
243
244static int xen_pv_console_init(void)
161{ 245{
162 struct hvc_struct *hp; 246 struct xencons_info *info;
163 struct hv_ops *ops;
164 247
165 if (!xen_pv_domain()) 248 if (!xen_pv_domain())
166 return -ENODEV; 249 return -ENODEV;
167 250
168 if (xen_initial_domain()) { 251 if (!xen_start_info->console.domU.evtchn)
169 ops = &dom0_hvc_ops; 252 return -ENODEV;
170 xencons_irq = bind_virq_to_irq(VIRQ_CONSOLE, 0);
171 } else {
172 if (!xen_start_info->console.domU.evtchn)
173 return -ENODEV;
174 253
175 ops = &domU_hvc_ops; 254 info = vtermno_to_xencons(HVC_COOKIE);
176 xencons_irq = bind_evtchn_to_irq(xen_start_info->console.domU.evtchn); 255 if (!info) {
256 info = kzalloc(sizeof(struct xencons_info), GFP_KERNEL | __GFP_ZERO);
257 if (!info)
258 return -ENOMEM;
177 } 259 }
178 if (xencons_irq < 0)
179 xencons_irq = 0;
180 else
181 irq_set_noprobe(xencons_irq);
182 260
183 hp = hvc_alloc(HVC_COOKIE, xencons_irq, ops, 256); 261 /* already configured */
184 if (IS_ERR(hp)) 262 if (info->intf != NULL)
185 return PTR_ERR(hp); 263 return 0;
264
265 info->evtchn = xen_start_info->console.domU.evtchn;
266 info->intf = mfn_to_virt(xen_start_info->console.domU.mfn);
267 info->vtermno = HVC_COOKIE;
268
269 spin_lock(&xencons_lock);
270 list_add_tail(&info->list, &xenconsoles);
271 spin_unlock(&xencons_lock);
272
273 return 0;
274}
275
276static int xen_initial_domain_console_init(void)
277{
278 struct xencons_info *info;
279
280 if (!xen_initial_domain())
281 return -ENODEV;
282
283 info = vtermno_to_xencons(HVC_COOKIE);
284 if (!info) {
285 info = kzalloc(sizeof(struct xencons_info), GFP_KERNEL | __GFP_ZERO);
286 if (!info)
287 return -ENOMEM;
288 }
186 289
187 hvc = hp; 290 info->irq = bind_virq_to_irq(VIRQ_CONSOLE, 0);
291 info->vtermno = HVC_COOKIE;
188 292
189 console_pfn = mfn_to_pfn(xen_start_info->console.domU.mfn); 293 spin_lock(&xencons_lock);
294 list_add_tail(&info->list, &xenconsoles);
295 spin_unlock(&xencons_lock);
190 296
191 return 0; 297 return 0;
192} 298}
193 299
194void xen_console_resume(void) 300void xen_console_resume(void)
195{ 301{
196 if (xencons_irq) 302 struct xencons_info *info = vtermno_to_xencons(HVC_COOKIE);
197 rebind_evtchn_irq(xen_start_info->console.domU.evtchn, xencons_irq); 303 if (info != NULL && info->irq)
304 rebind_evtchn_irq(info->evtchn, info->irq);
305}
306
307static void xencons_disconnect_backend(struct xencons_info *info)
308{
309 if (info->irq > 0)
310 unbind_from_irqhandler(info->irq, NULL);
311 info->irq = 0;
312 if (info->evtchn > 0)
313 xenbus_free_evtchn(info->xbdev, info->evtchn);
314 info->evtchn = 0;
315 if (info->gntref > 0)
316 gnttab_free_grant_references(info->gntref);
317 info->gntref = 0;
318 if (info->hvc != NULL)
319 hvc_remove(info->hvc);
320 info->hvc = NULL;
321}
322
323static void xencons_free(struct xencons_info *info)
324{
325 free_page((unsigned long)info->intf);
326 info->intf = NULL;
327 info->vtermno = 0;
328 kfree(info);
329}
330
331static int xen_console_remove(struct xencons_info *info)
332{
333 xencons_disconnect_backend(info);
334 spin_lock(&xencons_lock);
335 list_del(&info->list);
336 spin_unlock(&xencons_lock);
337 if (info->xbdev != NULL)
338 xencons_free(info);
339 else {
340 if (xen_hvm_domain())
341 iounmap(info->intf);
342 kfree(info);
343 }
344 return 0;
345}
346
347#ifdef CONFIG_HVC_XEN_FRONTEND
348static struct xenbus_driver xencons_driver;
349
350static int xencons_remove(struct xenbus_device *dev)
351{
352 return xen_console_remove(dev_get_drvdata(&dev->dev));
353}
354
355static int xencons_connect_backend(struct xenbus_device *dev,
356 struct xencons_info *info)
357{
358 int ret, evtchn, devid, ref, irq;
359 struct xenbus_transaction xbt;
360 grant_ref_t gref_head;
361 unsigned long mfn;
362
363 ret = xenbus_alloc_evtchn(dev, &evtchn);
364 if (ret)
365 return ret;
366 info->evtchn = evtchn;
367 irq = bind_evtchn_to_irq(evtchn);
368 if (irq < 0)
369 return irq;
370 info->irq = irq;
371 devid = dev->nodename[strlen(dev->nodename) - 1] - '0';
372 info->hvc = hvc_alloc(xenbus_devid_to_vtermno(devid),
373 irq, &domU_hvc_ops, 256);
374 if (IS_ERR(info->hvc))
375 return PTR_ERR(info->hvc);
376 if (xen_pv_domain())
377 mfn = virt_to_mfn(info->intf);
378 else
379 mfn = __pa(info->intf) >> PAGE_SHIFT;
380 ret = gnttab_alloc_grant_references(1, &gref_head);
381 if (ret < 0)
382 return ret;
383 info->gntref = gref_head;
384 ref = gnttab_claim_grant_reference(&gref_head);
385 if (ref < 0)
386 return ref;
387 gnttab_grant_foreign_access_ref(ref, info->xbdev->otherend_id,
388 mfn, 0);
389
390 again:
391 ret = xenbus_transaction_start(&xbt);
392 if (ret) {
393 xenbus_dev_fatal(dev, ret, "starting transaction");
394 return ret;
395 }
396 ret = xenbus_printf(xbt, dev->nodename, "ring-ref", "%d", ref);
397 if (ret)
398 goto error_xenbus;
399 ret = xenbus_printf(xbt, dev->nodename, "port", "%u",
400 evtchn);
401 if (ret)
402 goto error_xenbus;
403 ret = xenbus_printf(xbt, dev->nodename, "type", "ioemu");
404 if (ret)
405 goto error_xenbus;
406 ret = xenbus_transaction_end(xbt, 0);
407 if (ret) {
408 if (ret == -EAGAIN)
409 goto again;
410 xenbus_dev_fatal(dev, ret, "completing transaction");
411 return ret;
412 }
413
414 xenbus_switch_state(dev, XenbusStateInitialised);
415 return 0;
416
417 error_xenbus:
418 xenbus_transaction_end(xbt, 1);
419 xenbus_dev_fatal(dev, ret, "writing xenstore");
420 return ret;
421}
422
423static int __devinit xencons_probe(struct xenbus_device *dev,
424 const struct xenbus_device_id *id)
425{
426 int ret, devid;
427 struct xencons_info *info;
428
429 devid = dev->nodename[strlen(dev->nodename) - 1] - '0';
430 if (devid == 0)
431 return -ENODEV;
432
433 info = kzalloc(sizeof(struct xencons_info), GFP_KERNEL | __GFP_ZERO);
434 if (!info)
435 goto error_nomem;
436 dev_set_drvdata(&dev->dev, info);
437 info->xbdev = dev;
438 info->vtermno = xenbus_devid_to_vtermno(devid);
439 info->intf = (void *)__get_free_page(GFP_KERNEL | __GFP_ZERO);
440 if (!info->intf)
441 goto error_nomem;
442
443 ret = xencons_connect_backend(dev, info);
444 if (ret < 0)
445 goto error;
446 spin_lock(&xencons_lock);
447 list_add_tail(&info->list, &xenconsoles);
448 spin_unlock(&xencons_lock);
449
450 return 0;
451
452 error_nomem:
453 ret = -ENOMEM;
454 xenbus_dev_fatal(dev, ret, "allocating device memory");
455 error:
456 xencons_disconnect_backend(info);
457 xencons_free(info);
458 return ret;
459}
460
461static int xencons_resume(struct xenbus_device *dev)
462{
463 struct xencons_info *info = dev_get_drvdata(&dev->dev);
464
465 xencons_disconnect_backend(info);
466 memset(info->intf, 0, PAGE_SIZE);
467 return xencons_connect_backend(dev, info);
468}
469
470static void xencons_backend_changed(struct xenbus_device *dev,
471 enum xenbus_state backend_state)
472{
473 switch (backend_state) {
474 case XenbusStateReconfiguring:
475 case XenbusStateReconfigured:
476 case XenbusStateInitialising:
477 case XenbusStateInitialised:
478 case XenbusStateUnknown:
479 case XenbusStateClosed:
480 break;
481
482 case XenbusStateInitWait:
483 break;
484
485 case XenbusStateConnected:
486 xenbus_switch_state(dev, XenbusStateConnected);
487 break;
488
489 case XenbusStateClosing:
490 xenbus_frontend_closed(dev);
491 break;
492 }
493}
494
495static const struct xenbus_device_id xencons_ids[] = {
496 { "console" },
497 { "" }
498};
499
500
501static DEFINE_XENBUS_DRIVER(xencons, "xenconsole",
502 .probe = xencons_probe,
503 .remove = xencons_remove,
504 .resume = xencons_resume,
505 .otherend_changed = xencons_backend_changed,
506);
507#endif /* CONFIG_HVC_XEN_FRONTEND */
508
509static int __init xen_hvc_init(void)
510{
511 int r;
512 struct xencons_info *info;
513 const struct hv_ops *ops;
514
515 if (!xen_domain())
516 return -ENODEV;
517
518 if (xen_initial_domain()) {
519 ops = &dom0_hvc_ops;
520 r = xen_initial_domain_console_init();
521 if (r < 0)
522 return r;
523 info = vtermno_to_xencons(HVC_COOKIE);
524 } else {
525 ops = &domU_hvc_ops;
526 if (xen_hvm_domain())
527 r = xen_hvm_console_init();
528 else
529 r = xen_pv_console_init();
530 if (r < 0)
531 return r;
532
533 info = vtermno_to_xencons(HVC_COOKIE);
534 info->irq = bind_evtchn_to_irq(info->evtchn);
535 }
536 if (info->irq < 0)
537 info->irq = 0; /* NO_IRQ */
538 else
539 irq_set_noprobe(info->irq);
540
541 info->hvc = hvc_alloc(HVC_COOKIE, info->irq, ops, 256);
542 if (IS_ERR(info->hvc)) {
543 r = PTR_ERR(info->hvc);
544 spin_lock(&xencons_lock);
545 list_del(&info->list);
546 spin_unlock(&xencons_lock);
547 if (info->irq)
548 unbind_from_irqhandler(info->irq, NULL);
549 kfree(info);
550 return r;
551 }
552
553 r = 0;
554#ifdef CONFIG_HVC_XEN_FRONTEND
555 r = xenbus_register_frontend(&xencons_driver);
556#endif
557 return r;
198} 558}
199 559
200static void __exit xen_hvc_fini(void) 560static void __exit xen_hvc_fini(void)
201{ 561{
202 if (hvc) 562 struct xencons_info *entry, *next;
203 hvc_remove(hvc); 563
564 if (list_empty(&xenconsoles))
565 return;
566
567 list_for_each_entry_safe(entry, next, &xenconsoles, list) {
568 xen_console_remove(entry);
569 }
204} 570}
205 571
206static int xen_cons_init(void) 572static int xen_cons_init(void)
207{ 573{
208 struct hv_ops *ops; 574 const struct hv_ops *ops;
209 575
210 if (!xen_pv_domain()) 576 if (!xen_domain())
211 return 0; 577 return 0;
212 578
213 if (xen_initial_domain()) 579 if (xen_initial_domain())
214 ops = &dom0_hvc_ops; 580 ops = &dom0_hvc_ops;
215 else 581 else {
582 int r;
216 ops = &domU_hvc_ops; 583 ops = &domU_hvc_ops;
217 584
585 if (xen_hvm_domain())
586 r = xen_hvm_console_init();
587 else
588 r = xen_pv_console_init();
589 if (r < 0)
590 return r;
591 }
592
218 hvc_instantiate(HVC_COOKIE, 0, ops); 593 hvc_instantiate(HVC_COOKIE, 0, ops);
219 return 0; 594 return 0;
220} 595}
221 596
597
222module_init(xen_hvc_init); 598module_init(xen_hvc_init);
223module_exit(xen_hvc_fini); 599module_exit(xen_hvc_fini);
224console_initcall(xen_cons_init); 600console_initcall(xen_cons_init);
@@ -230,6 +606,9 @@ static void xenboot_write_console(struct console *console, const char *string,
230 unsigned int linelen, off = 0; 606 unsigned int linelen, off = 0;
231 const char *pos; 607 const char *pos;
232 608
609 if (!xen_pv_domain())
610 return;
611
233 dom0_write_console(0, string, len); 612 dom0_write_console(0, string, len);
234 613
235 if (xen_initial_domain()) 614 if (xen_initial_domain())